На предыдущих страницах мы рассмотрели процедуры для работы с точками в Паскале, а также познакомились с некоторыми другими процедурами. Теперь пришло время использовать эти знания в построении графиков функций в паскале.
Следует сразу заметить, что построение графика функции происходит в два основных этапа: построение системы координат и, собственно, рисование самого графика. Кроме того, процесс создания системы координат тоже разбивается на несколько частей.
Договоримся ещё об одном: систему будем строить с положительными и отрицательными значениями по обеим осям. Поскольку многие используют ещё турбо паскаль, то в конце страницы будет приведены две программы: одна – для PascalABC и PascalABC.Net, другая – для Turbo Pascal и Free Pascal.
Итак, для построения системы координат нам необходимо знать, в каких границах графического окна она будет находиться. Можно было бы опустить этот этап и строить декартову систему так, чтобы она занимала все графическое окно. Но это не очень удобно и просто некрасиво выглядит, когда график функции занимает всю область, не имея свободных полей слева-справа и сверху-снизу. Поэтому, чтобы задать прямоугольник, в котором будет находиться система координат, достаточно знать координаты левого верхнего и правого нижнего его углов.
Пусть (xLeft; yLeft) – координаты левого верхнего угла декартовой системы координат в графическом окне PascalABC.Net, (xRight; yRight) – соответственно координаты правого нижнего угла. Следующая задача – провести оси координат OX и OY. Будем считать, что нам нужны все четыре четверти координат. В этом случае обе оси будут иметь положительные и отрицательные значения. Чтобы правильно поставить центр координат (x0; y0), необходимо знать границы изменения аргумента x по оси OX и значения функции f по оси OY.
Итак, отложим по оси ОХ числа от a до b с интервалом dx, по оси OY – числа от fmin до fmax с разницей dy; причем обязательные условия: a≤0, b≥0, fmin≤0, fmax≥0. Для правильного отображения засечек на осях необходимо также, чтобы dx было делителем a и b, а dy было делителем fmin и fmax, и эти числа придется выбирать самостоятельно для каждого интервала. Но сначала нам придется познакомиться с таким понятием как масштаб системы координат в графическом окне паскаля. Что такое масштаб?
✎ Масштаб – это величина, или коэффициент, показывающий, сколько пикселей графического окна паскаля приходится на единицу оси системы координат. Например, по оси ОХ нужно расположить числа от -4 до 16 (всего 20 единиц), а ширина графического окна паскаля равна 1000 пикселей; тогда на единицу величины оси ОХ приходится 1000:20=50 пикселей/единицу. Это и есть масштаб по оси ОХ. Чтобы узнать, сколько пикселей содержат n единиц, надо просто умножить n на 50.
График функции будем строить по точкам, используя процедуру SetPixel(x, y, c), где x, y – координаты точки в графическом окне паскаля, c – цвет точки. Для рисования осей координат ОХ и OY воспользуемся процедурой Line(x1, y1, x2, y2), где (x1; y1) – координаты начальной точки, (x2; y2) – координаты конечной.
Последовательность такова: сначала строим систему координат, а после (в самом конце) вычисляем значения функции, вычисляем соответствующие координаты точки в графическом окне и ставим точку (x, y), закрашенную в зеленый цвет. Откройте PascalABC или PascalABC.Net, скопируйте следующий код и запустите программу:
uses
graphABC; //Подключаем графический модуль
const
W = 800; H = 500;//Размеры графического окна
function F(x: real): real;
begin
F := (x + 1) * (x - 2) * (x - 3); //Функция
end;
var
x0, y0, x, y, xLeft, yLeft, xRight, yRight, n: integer;
a, b, fmin, fmax, x1, y1, mx, my, dx, dy, num: real;
i: byte;
s: string;
begin
SetWindowSize(W, H); //Устанавливаем размеры графического окна
//Координаты левой верхней границы системы координат:
xLeft := 50;
yLeft := 50;
//Координаты правой нижней границы системы координат:
xRight := W - 50;
yRight := H - 50;
//интервал по Х; a и b должно нацело делится на dx:
a := -2; b := 6; dx := 0.5;
//Интервал по Y; fmin и fmax должно нацело делится на dy:
fmin := -10; fmax := 20; dy := 2;
//Устанавливаем масштаб:
mx := (xRight - xLeft) / (b - a); //масштаб по Х
my := (yRight - yLeft) / (fmax - fmin); //масштаб по Y
//начало координат:
x0 := trunc(abs(a) * mx) + xLeft;
y0 := yRight - trunc(abs(fmin) * my);
//Рисуем оси координат:
line(xLeft, y0, xRight + 10, y0); //ось ОХ
line(x0, yLeft - 10, x0, yRight); //ось ОY
SetFontSize(12); //Размер шрифта
SetFontColor(clBlue); //Цвет шрифта
TextOut(xRight + 20, y0 - 15, 'X'); //Подписываем ось OX
TextOut(x0 - 10, yLeft - 30, 'Y'); //Подписываем ось OY
SetFontSize(8); //Размер шрифта
SetFontColor(clRed); //Цвет шрифта
{ Засечки по оси OX: }
n := round((b - a) / dx) + 1; //количество засечек по ОХ
for i := 1 to n do
begin
num := a + (i - 1) * dx; //Координата на оси ОХ
x := xLeft + trunc(mx * (num - a)); //Координата num в окне
Line(x, y0 - 3, x, y0 + 3); //рисуем засечки на оси OX
str(Num:0:1, s);
if abs(num) > 1E-15 then //Исключаем 0 на оси OX
TextOut(x - TextWidth(s) div 2, y0 + 10, s)
end;
{ Засечки на оси OY: }
n := round((fmax - fmin) / dy) + 1; //количество засечек по ОY
for i := 1 to n do
begin
num := fMin + (i - 1) * dy; //Координата на оси ОY
y := yRight - trunc(my * (num - fmin));
Line(x0 - 3, y, x0 + 3, y); //рисуем засечки на оси Oy
str(num:0:0, s);
if abs(num) > 1E-15 then //Исключаем 0 на оси OY
TextOut(x0 + 7, y - TextHeight(s) div 2, s)
end;
TextOut(x0 - 10, y0 + 10, '0'); //Нулевая точка
{ График функции строим по точкам: }
x1 := a; //Начальное значение аргумента
while x1 <= b do
begin
y1 := F(x1); //Вычисляем значение функции
x := x0 + round(x1 * mx); //Координата Х в графическом окне
y := y0 - round(y1 * my); //Координата Y в графическом окне
//Если y попадает в границы [yLeft; yRight], то ставим точку:
if (y >= yLeft) and (y <= yRight) then SetPixel(x, y, clGreen);
x1 := x1 + 0.001 //Увеличиваем абсциссу
end
end.
**unit** GraphABC;
: Модуль предоставляет константы, типы, процедуры, функции и классы для рисования в графическом окне**type** real;
: Представляет число двойной точности с плавающей запятой.Размер: 8 байт Количество значащих цифр: 15 - 16 Диапазон значений: -1.8∙10308 .. 1.8∙10308**type** real;
: Представляет число двойной точности с плавающей запятой.Размер: 8 байт Количество значащих цифр: 15 - 16 Диапазон значений: -1.8∙10308 .. 1.8∙10308**type** integer;
: Представляет 32-битовое целое число со знаком.Диапазон значений: -2 147 483 648 .. 2 147 483 647**type** real;
: Представляет число двойной точности с плавающей запятой.Размер: 8 байт Количество значащих цифр: 15 - 16 Диапазон значений: -1.8∙10308 .. 1.8∙10308**type** byte;
: Представляет 8-битовое целое число без знака.Диапазон значений: 0..255**type** string;
: Представляет текст как последовательность знаков Юникода.**procedure** SetWindowSize(w,h: integer);
: Устанавливает размеры клиентской части графического окна в пикселах**function** Trunc(x: real): integer;
: Возвращает целую часть числа x.**function** Abs(x: real): real;
: Возвращает модуль числа x.**function** Trunc(x: real): integer;
: Возвращает целую часть числа x.**function** Abs(x: real): real;
: Возвращает модуль числа x.**procedure** Line(x1,y1,x2,y2: integer);
: Рисует отрезок от точки (x1,y1) до точки (x2,y2)**procedure** Line(x1,y1,x2,y2: integer);
: Рисует отрезок от точки (x1,y1) до точки (x2,y2)**procedure** SetFontSize(size: integer);
: Устанавливает размер текущего шрифта в пунктах**procedure** SetFontColor(c: Color);
: Устанавливает цвет текущего шрифта Цвет:clBlue
- синий**procedure** TextOut(x,y: integer; s: string);
: Выводит строку s в прямоугольник к координатами левого верхнего угла (x,y)**procedure** TextOut(x,y: integer; s: string);
: Выводит строку s в прямоугольник к координатами левого верхнего угла (x,y)**procedure** SetFontSize(size: integer);
: Устанавливает размер текущего шрифта в пунктах**procedure** SetFontColor(c: Color);
: Устанавливает цвет текущего шрифта Цвет:clRed
- красный**function** Round(x: real): integer;
: Возвращает x, округленное до ближайшего целого.**function** Trunc(x: real): integer;
: Возвращает целую часть числа x.**procedure** Line(x1,y1,x2,y2: integer);
: Рисует отрезок от точки (x1,y1) до точки (x2,y2)**function** Abs(x: real): real;
: Возвращает модуль числа x.**procedure** TextOut(x,y: integer; s: string);
: Выводит строку s в прямоугольник к координатами левого верхнего угла (x,y)**function** TextWidth(s: string): integer;
: Возвращает ширину строки s в пикселях при текущих настройках шрифтаA **div** B
- целочисленное деление А на В**function** Round(x: real): integer;
: Возвращает x, округленное до ближайшего целого.**function** Trunc(x: real): integer;
: Возвращает целую часть числа x.**procedure** Line(x1,y1,x2,y2: integer);
: Рисует отрезок от точки (x1,y1) до точки (x2,y2)**function** Abs(x: real): real;
: Возвращает модуль числа x.**procedure** TextOut(x,y: integer; s: string);
: Выводит строку s в прямоугольник к координатами левого верхнего угла (x,y)**function** TextHeight(s: string): integer;
: Возвращает высоту строки s в пикселях при текущих настройках шрифтаA **div** B
- целочисленное деление А на В**procedure** TextOut(x,y: integer; s: string);
: Выводит строку s в прямоугольник к координатами левого верхнего угла (x,y)**function** Round(x: real): integer;
: Возвращает x, округленное до ближайшего целого.**function** Round(x: real): integer;
: Возвращает x, округленное до ближайшего целого.**procedure** SetPixel(x,y: integer; c: Color);
: Закрашивает пиксел с координатами (x,y) цветом c Цвет:clGreen
- зеленый Только не нужно забывать, что в PascalABC цвет имеет тип ColorType, а PascalABC.Net тип цвета Color – это синоним System.Drawing.Color.
Итак, запустив программу, вы должны увидеть следующее:
А теперь программа для тех, у кого нет PascalABC, но есть Turbo Pascal или Free Pascal. Итак, скопируйте нижеприведенный код в блокнот, сохраните в формате .pas и откройте в турбо паскале, потом запустите (ctrl+F9):
uses
Graph; { Подключаем модуль }
function F(x: real): real;
begin
F := (x + 1) * (x - 2) * (x - 3); { Функция }
end;
var
Gd, Gm, x0, y0, x, y, xLeft, yLeft, xRight, yRight, n: integer;
a, b, fmin, fmax, x1, y1, mx, my, dx, dy, num: real;
i: byte;
s: string;
begin
x0 := 0;
Gd := Detect;
InitGraph(Gd, Gm, 'C:\tp7\bgi'); { Инициализируем графический режим }
{ Координаты левой верхней границы системы координат: }
xLeft := 50;
yLeft := 50;
{ Координаты правой нижней границы системы координат: }
xRight := GetMaxX - 50;
yRight := GetMaxY - 50;
{ интервал по Х; a и b должно нацело делится на dx: }
a := -2; b := 6; dx := 0.5;
{ Интервал по Y; fmin и fmax должно нацело делится на dy: }
fmin := -10; fmax := 20; dy := 2;
{ Устанавливаем масштаб: }
mx := (xRight - xLeft) / (b - a); { масштаб по Х }
my := (yRight - yLeft) / (fmax - fmin); { масштаб по Y }
{ начало координат: }
x0 := trunc(abs(a) * mx) + xLeft;
y0 := yRight - trunc(abs(fmin) * my);
{ Рисуем оси координат: }
line(xLeft, y0, xRight + 10, y0); { ось ОХ }
line(x0, yLeft - 10, x0, yRight); { ось ОY }
SetColor(4); { Цвет шрифта }
SetTextStyle(1, 0, 1); { Устанавливаем стиль шрифта: }
OutTextXY(xRight + 20, y0 - 15, 'X'); { Подписываем ось OX }
OutTextXY(x0 - 15, yLeft - 35, 'Y'); { Подписываем ось OY }
SetColor(14); { Цвет шрифта }
{ Засечки по оси OX: }
n := round((b - a) / dx) + 1; { количество засечек по ОХ }
for i := 1 to n do
begin
num := a + (i - 1) * dx; { Координата на оси ОХ }
x := xLeft + trunc(mx * (num - a)); { Координата num в окне }
Line(x, y0 - 3, x, y0 + 3); { рисуем засечки на оси OX }
str(Num:0:1, s);
if abs(num) > 1E-15 then { Исключаем 0 на оси OX }
OutTextXY(x - TextWidth(s) div 2, y0 + 10, s)
end;
{ Засечки на оси OY: }
n := round((fmax - fmin) / dy) + 1; { количество засечек по ОY }
for i := 1 to n do
begin
num := fMin + (i - 1) * dy; { Координата на оси ОY }
y := yRight - trunc(my * (num - fmin));
Line(x0 - 3, y, x0 + 3, y); { рисуем засечки на оси Oy }
str(num:0:0, s);
if abs(num) > 1E-15 then { Исключаем 0 на оси OY }
OutTextXY(x0 + 7, y - TextHeight(s) div 2, s)
end;
OutTextXY(x0 - 10, y0 + 10, '0'); { Нулевая точка }
{ График функции строим по точкам: }
x1 := a; { Начальное значение аргумента }
while x1 <= b do
begin
y1 := F(x1); { Вычисляем значение функции }
x := x0 + round(x1 * mx); { Координата Х в графическом окне }
y := y0 - round(y1 * my); { Координата Y в графическом окне }
{ Если y попадает в границы [yLeft; yRight], то ставим точку: }
if (y >= yLeft) and (y <= yRight) then PutPixel(x, y, 12);
x1 := x1 + 0.001 { Увеличиваем абсциссу }
end;
SetColor(15);
OutTextXY(GetMaxX div 2 - 50, 50, 'y = (x+1)(x-2)(x-3)');
readln
end.
Если все сделано правильно, вы должны увидеть такой график функции:
Вообще, построение графиков – это одно из постейших заданий, с которым может столкнуться программист на практике.
Простейший игровой автомат – это обычная игра, но с использованием функции Random(N), возвращающей случайное число от 0 до N-1. Это значит, что нажимая на кнопки, выбирая разные фишки, бросая кубики, шарики и т.п. каждый раз вы будете получать случайный результат, так как функция Random генерирует случайные числа с привязкой к текущему времени. Также в играх подобного типа обязательное использование таймера для создания плавности перехода. Позже в этом разделе мы напишем небольшие игры и посмотрим, как это работает.