Глава 24. График линейной функции

Листинг 24.1. Наш код в шаблоне метода для кнопки Graph.

double a_Form3, b_Form3, x_min_Form3, x_max_Form3;

a_Form3 = Convert.ToDouble(textBox1.Text);

b_Form3 = Convert.ToDouble(textBox2.Text);

x_min_Form3 = Convert.ToDouble(textBox3.Text);

x_max_Form3 = Convert.ToDouble(textBox4.Text);

Form5 myForm5 = new Form5();

myForm5.a = a_Form3;

myForm5.b = b_Form3;

myForm5.x_min = x_min_Form3;

myForm5.x_max = x_max_Form3;

myForm5.Show();

Для программной реализации этого алгоритма дважды щелкаем значок timer1 (ниже формы в режиме проектирования). Появляется файл с шаблоном, в который записываем наш следующий код:

//Объявляем булеву переменную myColor со значением false:

bool myColor = false;

private void timer1_Tick(object sender, EventArgs e)

{

//Вводим анимацию:

if (myColor == false)

{

//Выводим красный цвет переключателя:

this.radioButton2.BackColor =

System.Drawing.Color.Red;

//Изменяем значение myColor на противоположное:

myColor = true;

}

else

{

//Выводим белый цвет переключателя:

this.radioButton2.BackColor =

System.Drawing.Color.White;

//Изменяем значение myColor на противоположное:

myColor = false;

}

}

Листинг 24.2. Первая часть кода (выше шаблона pictureBox1_Paint).

//Параметры графика функции y = a*x + b

//в виде глобальных переменных:

public float a, b, x_min, x_max;

float Function_of_graph(float x)

{

float Function;

//Метод y = f(x), график которой будем строить:

Function = a * x + b;

return Function;

}

Листинг 24.3. Вторая часть кода (выше шаблона pictureBox1_Paint).

//Число точек графика:

public int Npoints = 100;

//Величины (в пикселах) O_x_pix и O_y_pix

//для параллельного переноса

//осей "x" и "y" новой системы координат (по сравнению

//со старой системой в верхнем левом углу рамки PictureBox):

public float O_x_pix = 500;

public float O_y_pix = 350;

//Масштабы по осям "x" и "y" (M_x и M_y) для перехода

//от действительных значений к пикселам

//и построения графика в пикселах:

public float M_x = 450;

public float M_y = 300;

Теперь внутрь этого (приведенного выше) шаблона для процедуры pictureBox1_Paint записываем основную часть нашего кода для вывода графика на экран монитора. Перед каждым логическим блоком кода мы даем подробный комментарий, чтобы читатель мог изучить это важный код и мог грамотно внести изменения (в случае необходимости).

Листинг 24.4. Главный код построения графика функции на экране монитора.

//Шаг по оси абсцисс "x" между точками графика:

float step_x = (x_max-x_min)/Npoints;

//Наибольшее абсолютное значение x_max_abs

//из двух концов заданного нами числового интервала

//x_min и x_max:

float x_max_abs = Math.Abs(x_max);

if (x_max_abs < Math.Abs(x_min)) x_max_abs = Math.Abs(x_min);

//Промежуточные локальные переменные:

float x_0, y_0, x_1, y_1, x_0_pix, y_0_pix, x_1_pix, y_1_pix;

//Расчет минимального y_min и максимального y_max

//действительных значений функции:

float y_min, y_max;

//Присваиваем y_min, y_max значение y_0

//для нулевой точки (i=0):

x_0 = x_min; y_0 = Function_of_graph(x_0);

y_min = y_0; y_max = y_0; int i;

//Организовываем цикл по всем точкам, начиная с i=1:

for (i=1; i<=(Npoints-1); i++)

{

x_1 = x_min + i * step_x;

y_1 = Function_of_graph(x_1);

//Расчет минимального и максимального значений функции:

if (y_min > y_1) y_min = y_1;

if (y_max < y_1) y_max = y_1;

}

//Т.к. в последней точке i = Npoints

//значение x_1 = x_min + Npoints * step_x

//может отличаться от заданного значения x_max

//(из-за накапливания погрешности в цикле), то проверяем,

//может быть y_min или y_max находится в последней

//точке при точном задании нами значения x_max:

x_1 = x_max; y_1 = Function_of_graph(x_1);

//Проверка минимального и максимального

//значений функции в последней точке:

if (y_min > y_1) y_min = y_1;

if (y_max < y_1) y_max = y_1;

//Наибольшее абсолютное значение функции y_max_abs

//из двух значений y_min и y_max:

float y_max_abs = Math.Abs(y_max);

if (y_max_abs < Math.Abs(y_min)) y_max_abs = Math.Abs(y_min);

//Строим сетку координат:

//Сначала строим ось абсцисс "x" от x = -1 до x = 1:

//Задаем абсциссу последней точки оси абсцисс "x"

//при x = 1:

float x_point_end, x_point_end_pix; x_point_end = 1;

x_point_end_pix = x_point_end * M_x + O_x_pix;

//Выбираем зеленое перо толщиной 2:

Pen greenPen_x = new Pen(Color.Green, 2);

//Задаем координаты двух граничных точек оси:

PointF point1 = new PointF(-1 * M_x + O_x_pix, O_y_pix);

PointF point2 = new PointF(x_point_end_pix, O_y_pix);

//Строим линию через две заданные граничные точки:

e.Graphics.DrawLine(greenPen_x, point1, point2);

//Строим горизонтальные линии сетки координат

//(кроме оси "x"):

//Ширина (размах) графика по оси ординат "y":

float span_y = y_max - y_min;

//Число шагов по всей высоте сетки (по оси "y"):

int N_step_grid_y = 20;

//Шаг сетки в направлении оси "y"

//(высота всей сетки равна 2 единицам):

float step_grid_y, step_grid_y_pix;

//Преобразование типов переменных:

step_grid_y = (float) 2 / N_step_grid_y;

step_grid_y_pix = step_grid_y * M_y;

//Выбираем красное перо толщиной 1:

Pen redPen = new Pen(Color.Red, 1);

//Строим сетку от нулевой линии в одну сторону (вниз):

int j_y; float y1, y1_pix;

for (j_y = 1; j_y<=(N_step_grid_y/2); j_y++)

{

y1 = j_y * step_grid_y;

y1_pix = O_y_pix + j_y * step_grid_y_pix;

//Задаем координаты двух граничных точек линии сетки:

PointF point3 = new PointF(-1 * M_x + O_x_pix, y1_pix);

PointF point4 = new PointF(x_point_end_pix, y1_pix);

//Строим линию через две заданные граничные точки:

e.Graphics.DrawLine(redPen, point3, point4);

}

//Строим сетку от нулевой линии в другую сторону (вверх):

for (j_y = 1; j_y<=(N_step_grid_y / 2); j_y++)

{

y1_pix = O_y_pix - j_y * step_grid_y * M_y;

//Задаем координаты двух граничных точек линии сетки:

PointF point5 = new PointF(-1 * M_x + O_x_pix, y1_pix);

PointF point6 = new PointF(x_point_end_pix, y1_pix);

//Строим прямую линию через две заданные точки:

e.Graphics.DrawLine(redPen, point5, point6);

}

//Строим ось ординат "y" от y= -1 до y = 1:

//Задаем ординату последней точки оси ординат "y" при y = 1:

float y_point_end, y_point_end_pix; y_point_end = 1;

y_point_end_pix = y_point_end * M_y + O_y_pix;

//Выбираем зеленое перо толщиной 2:

Pen greenPen_y = new Pen(Color.Green, 2);

//Задаем координаты двух граничных точек оси:

PointF point7 = new PointF(O_x_pix, -1 * M_y + O_y_pix);

PointF point8 = new PointF(O_x_pix, y_point_end_pix);

//Строим линию через две заданные граничные точки:

e.Graphics.DrawLine(greenPen_y, point7, point8);

//Строим вертикальные линии сетки координат (кроме оси "y"):

//Ширина (размах) графика по оси абсцисс "x":

float span_x = x_max - x_min;

//Число шагов по всей ширине сетки по обе стороны от оси y:

int N_step_grid_x = 20;

//Шаг сетки в направлении оси "x"

//(ширина всей сетки равна 2 единицам):

float step_grid_x = 0.1F, step_grid_x_pix;

step_grid_x_pix = step_grid_x * M_x;

//Выбираем красное перо толщиной 1:

Pen redPen_y = new Pen(Color.Red, 1);

//Строим сетку от нулевой линии в одну сторону (вправо):

int j_x; float x1, x1_pix;

for (j_x = 1; j_x<=(N_step_grid_x / 2); j_x++)

{

x1 = j_x * step_grid_x;

x1_pix = O_x_pix + j_x * step_grid_x_pix;

//Задаем координаты двух граничных точек линии сетки:

PointF point9 = new PointF(x1_pix, -1 * M_y + O_y_pix);

PointF point10 = new PointF(x1_pix, y_point_end_pix);

//Строим линию через две заданные граничные точки:

e.Graphics.DrawLine(greenPen_y, point9, point10);

}

//Строим сетку от нулевой линии в другую сторону (влево):

for (j_x = 1; j_x<=(N_step_grid_x / 2); j_x++)

{

x1 = j_x * step_grid_x;

x1_pix = O_x_pix - j_x * step_grid_x_pix;

//Задаем координаты двух граничных точек линии сетки:

PointF point11 = new PointF(x1_pix, -1 * M_y +

O_y_pix);

PointF point12 = new PointF(x1_pix, y_point_end_pix);

//Строим прямую линию через две заданные точки:

e.Graphics.DrawLine(greenPen_y, point11, point12);

}

//Записываем числа по осям координат:

//Объявляем локальные переменные:

int n; float p1 = 1, p2; string msg;

//Записываем числа по оси "O","+y":

for (n = 0; n<=9; n++)

{

p2 = p1 - n * 0.1F;

msg = "" + p2.ToString() + "";

e.Graphics.DrawString(msg, this.Font, Brushes.Blue,

O_x_pix - 35, O_y_pix - 323 + n * step_grid_y_pix);

}

//Записываем числа по оси "O","-y":

p1 = 0;

for (n = 1; n<=10; n++)

{

p2 = p1 - n * 0.1F;

msg = "" + p2.ToString() + "";

e.Graphics.DrawString(msg, this.Font, Brushes.Blue,

O_x_pix - 40, O_y_pix - 23 + n * step_grid_y_pix);

}

//Записываем числа по оси "O","+x":

p1 = 0;

for (n = 0; n<=10; n++)

{

p2 = p1 + n * 0.1F;

msg = "" + p2.ToString() + "";

e.Graphics.DrawString(msg, this.Font, Brushes.Blue,

O_x_pix - 0 + n * step_grid_x_pix, O_y_pix - 0);

}

//Записываем числа по оси "O","-x":

p1 = 0;

for (n = 1; n<=10; n++)

{

p2 = p1 - n * 0.1F;

msg = "" + p2.ToString() + "";

e.Graphics.DrawString(msg, this.Font, Brushes.Blue,

O_x_pix - 39 - n * step_grid_x_pix, O_y_pix - 0);

}

//Записываем обозначение оси y' = y / y_max:

msg = "y ' = y / | y_max | ;";

e.Graphics.DrawString(msg, this.Font,

Brushes.Blue, O_x_pix - 5, O_y_pix - 333);

//Записываем значение | y_max |:

msg = "| y_max | = " + y_max_abs.ToString() + ";";

e.Graphics.DrawString(msg, this.Font,

Brushes.Blue, O_x_pix + 170, O_y_pix - 333);

//Записываем значение y_max:

msg = "y_max = " + y_max.ToString() + ";";

e.Graphics.DrawString(msg, this.Font,

Brushes.Blue, O_x_pix + 380, O_y_pix - 333);

//Записываем значение y_min:

msg = "y_min = " + y_min.ToString() + "";

e.Graphics.DrawString(msg, this.Font,

Brushes.Blue, O_x_pix + 455, O_y_pix - 300);

//Записываем обозначение оси x' = x / | x_max |:

msg = "x ' = x / | x_max |";

e.Graphics.DrawString(msg, this.Font,

Brushes.Blue, O_x_pix + 455, O_y_pix - 30);

//Записываем значение | x_max |:

msg = "| x_max | = " + x_max_abs.ToString() + "";

e.Graphics.DrawString(msg, this.Font,

Brushes.Blue, O_x_pix + 455, O_y_pix + 40);

//Записываем значение x_max:

msg = "x_max = " + x_max.ToString() + "";

e.Graphics.DrawString(msg, this.Font,

Brushes.Blue, O_x_pix + 455, O_y_pix + 90);

//Записываем значение x_min:

msg = "x_min = " + x_min.ToString() + "";

e.Graphics.DrawString(msg, this.Font,

Brushes.Blue, O_x_pix + 455, O_y_pix + 140);

//Построение графика функции y = f(x):

//Координаты нулевой (i=0) точки,

//с которой строится график:

x_0 = x_min; x_0_pix = x_0 / x_max_abs * M_x + O_x_pix;

//Рассчитываем "y" и вводим знак минус,

//чтобы положительное значение "y"

//отложилось вверх по оси "y" (а не вниз):

y_0 = -(Function_of_graph(x_0));

y_0_pix = y_0 / y_max_abs * M_y + O_y_pix;

//Выбираем черное перо толщиной 4:

Pen blackPen = new Pen(Color.Black, 4);

//Организовываем цикл по всем точкам, начиная с i = 1:

for (i = 1; i<=Npoints; i++)

{

//Рассчитываем абсциссу "x" данной i-й точки:

x_1 = x_min + i * step_x;

//Рассчитываем ординату "y" этой i-й точки

//и вводим знак минус, чтобы положительные значения "y"

//откладывались вверх (а не вниз), и чтобы

//строить график традиционно снизу-вверх по оси "y":

y_1 = -(Function_of_graph(x_1));

//Переходим к относительным величинам и пикселам:

x_1_pix = x_1 / x_max_abs * M_x + O_x_pix;

y_1_pix = y_1 / y_max_abs * M_y + O_y_pix;

//Строим отрезок линии графика y = f(x)

//между двумя известными точками:

e.Graphics.DrawLine(blackPen, x_0_pix, y_0_pix,

x_1_pix, y_1_pix);

//Присваиваем предыдущей (i-1)-й точке

//координаты данной i-й точки:

x_0_pix = x_1_pix; y_0_pix = y_1_pix;

//Задаем следующую (i+1)-ю точку:

}

Отметим еще раз, что наши подробные комментарии внутри кода позволят читателю на этом примере понять и изучить основные конструкции и синтаксис языка C#. А также грамотно внести изменения в код, если читатель пожелает модернизировать внешний вид графика для учета своих конкретных требований.

Листинг 24.5. Код для выполнения анимации.

//Объявляем булеву переменную myText со значением false:

bool myText = false;

private void timer1_Tick(object sender, EventArgs e)

{

//Вводим анимацию:

if (myText == false)

{

//Выводим текст:

this.label1.Text =

"Graph 'Straight Line' of function y = a*x + b:";

//Изменяем значение myText на противоположное:

myText = true;

}

else

{

//Удаляем текст:

this.label1.Text = "";

//Изменяем значение myText на противоположное:

myText = false;

}

}


Наши рекомендации