Компьютерная графика, мультимедиа и игры на Visual C#

         

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


Листинг 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;
      }
}

Содержание раздела