Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Компьютерная графика, мультимедиа и игры на Vis...doc
Скачиваний:
3
Добавлен:
01.03.2025
Размер:
1.92 Mб
Скачать

Часть VIII. Методология создания графической системы в двухмерном пространстве Глава 23. Алгоритмы и оглавление графической системы

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

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

bool myColor = false;

private void timer1_Tick(object sender, EventArgs e)

{

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

if (myColor == false)

{

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

this.radioButton2.BackColor = Color.Red;

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

myColor = true;

}

else

{

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

this.radioButton2.BackColor = Color.White;

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

myColor = false;

}

}

В этом коде мы можем устанавливать чередование двух других цветов из списка, который появляется, когда при написании кода мы ставим точку после имени структуры Color. Аналогично можно также дописать код, чтобы сделать анимационными сразу несколько переключателей. Задавая в панели Properties для компонента Timer различные значения свойству Interval (а выше мы задали 1000 миллисекунд или 1 секунду), можно изменять частоту чередования цветов переключателей. Методика приостановки и возобновления анимации приведена выше.

Проверяем, как на данном этапе проектирования действует оглавление системы. Для этого строим (Build, Build Solution) и запускаем программу на выполнение (Debug, Start Without Debugging).

Глава 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;

}

}