Root /ArchiveAbout
()

Графики функций в паскале

Графики функций в паскале

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

Следует сразу заметить, что построение графика функции происходит в два основных этапа: построение системы координат и, собственно, рисование самого графика. Кроме того, процесс создания системы координат тоже разбивается на несколько частей.

Договоримся ещё об одном: систему будем строить с положительными и отрицательными значениями по обеим осям. Поскольку многие используют ещё турбо паскаль, то в конце страницы будет приведены две программы: одна – для PascalABC и PascalABC.Net, другая – для Turbo Pascal и Free Pascal.

Итак, для построения системы координат нам необходимо знать, в каких границах графического окна она будет находиться. Можно было бы опустить этот этап и строить декартову систему так, чтобы она занимала все графическое окно. Но это не очень удобно и просто некрасиво выглядит, когда график функции занимает всю область, не имея свободных полей слева-справа и сверху-снизу. Поэтому, чтобы задать прямоугольник, в котором будет находиться система координат, достаточно знать координаты левого верхнего и правого нижнего его углов.

Граница системы координат в 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.

Координаты точки относительно системы координат и относительно графического окна Pascal

График функции будем строить по точкам, используя процедуру 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.

Итак, запустив программу, вы должны увидеть следующее:

График функции в паскале в Pascal

А теперь программа для тех, у кого нет 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.

Если все сделано правильно, вы должны увидеть такой график функции:

График функции в Turbo Pascal

Вообще, построение графиков – это одно из постейших заданий, с которым может столкнуться программист на практике.

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