Как найти координаты числа в паскале

Формулировка задачи:

Здравствуйте! Вот такая вот задача:
Бесконечная прямоугольная таблица заполняется целыми числами, начиная с 1 по диагоналям с чередованием порядка заполнения (см. рисунок).

По заданному числу N определить номер строки и столбца, в котором оно находится при данном заполнении. Номера строк и столбцов считать с 1.

Не могу придумать алгоритм, если хотя бы его предложите, уже будет здорово. Заранее спасибо!)

Код к задаче: «Определить координаты числа в таблице»

textual

Листинг программы

program qq; 
var n,k,x,y,i: longint; 
begin 
readln(n); 
k:=1; 
while n>k do begin 
n:=n-k; 
k:=k+1; 
end; 
if (k mod 2) = 0 then begin 
x:=k; 
y:=1; 
for i:=2 to n do begin 
x:=x-1; 
y:=y+1; 
end; 
end 
else begin 
x:=1; 
y:=k; 
for i:=2 to n do begin 
x:=x+1; 
y:=y-1; 
end; 
end; 
 
writeln(y,' ',x); 
end.

Процедуру SetViewPort  удобно использовать для построения системы координат на экране. Эту систему координат можно в дальнейшем использовать для построения графика функции.

 Построение системы координат с помощью процедуры SetViewPort.



Program Graphika26;
Uses Graph;
Procedure Graphinterface;
Var  gd, gm, error:Integer;
s:String;
Begin
gd:=detect;
s:='';
Initgraph(gd,gm,s);
error:=GraphResult;
if error<>GrOk then
begin
writeln(GraphErrorMsg(Error));
Halt(error)
end
end;
begin
Graphinterface;
setviewport(getmaxx div 2, getmaxy div 2, getmaxx, getmaxy,clipoff);
setcolor(5);
setlinestyle(0,0,3);
line(-300,0,300,0);
line(0,-300,0,300);
line(300,0,270,-10);
line(300,0,270,10);
line(0,-300,-10,-270);
line(0,-300,10,-270);
readln;
closegraph
end.




В строке №19 записываем процедуру SetViewPort, которая строит на экране невидимое окно. Координаты левого верхнего угла этого окна совпадают с серединой экрана (getmaxx div 2, getmaxy div 2). Координаты правого нижнего угла окна совпадают с правым нижним углом всего экрана. На рис. снизу представлено расположение окна (ABCD), построенного с помощью процедуры SetViewPort. Левый верхний угол окна (точка B) имеет координаты (getmaxx div 2, getmaxy div 2) и совпадает с серединой экрана. Правый нижний угол окна имеет координаты (getmaxx, getmaxy) и совпадает с правым нижним углом экрана.

Procedura SetViewPort sistemma koordinat

5-й параметр процедуры SetViewPort имеет значение ClipOff, т.е. элементы изображений, выходящие за пределы окна, не будут отсекаться.

Строка №20 и №21. Устанавливаем цвет, тип и толщину линий.

Строка №22. Рисуем линию. Так как начало координат теперь находится в левом верхнем углу окна (в точке B), нам необходимо использовать отрицательные координаты при построении изображений, находящихся левее либо выше окна ABCD. На рис. снизу показаны линии, построенные с помощью процедуры Line.

Procedura SetViewPort sistemma koordinat.

Линия EF построена с помощью процедуры Line в строке №22.
Линия GH построена с помощью процедуры Line в строке №23.
Так как точка B имеет координаты (0,0), точка E будет иметь координаты (-300,0), точка F – (300,0), точка G – (0,-300), точка H – (300,0). Таким образом, на данном этапе необходимо запомнить, что изображение, находящееся левее, либо выше окна, построенного с помощью процедуры SetViewPort, должно иметь отрицательные координаты.

Строка №24-№27. Строим стрелочки, указывающие направление осей. На рис. снизу линия FJ построена с помощью процедуры Line в строке №24. Точка F имеет координаты (300,0), точка J – (270,-10).

Procedura SetViewPort sistemma koordinat..

Procedura SetViewPort sistemma koordinat...

Procedura SetViewPort sistemma koordinat....


Предыдущая статья : Процедура SetViewPort.

Оглавление : Уроки Паскаль. Графика.

Следующая статья : Построение системы координат (продолжение).


На занятии происходит знакомство с логическим типом Boolean в Паскале. Рассматривается алгоритм того, как находится минимальное и максимальное число в Паскале

Содержание:

  • Графика в Паскале
    • Управление цветом
    • Точки, отрезки и ломаные
    • Рисование фигур
    • Функция random для использования окраски
  • Анимация в Паскале

Графика в Паскале

Для работы с графикой в pascal abc используется модуль GraphABC. Для его подключения используется следующий код:

uses GraphABC;
begin
...
end.

Система координат в Паскале соответствует экранной системе координат и выглядит следующим образом:

Система координат в паскале

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

Управление цветом

Для того, чтобы использовать цвет, необходимо применить этот цвет к инструменту перо:


  • SetPenColor(color) — устанавливает цвет пера, задаваемый параметром color;
  • setBrushColor(color) — устанавливает цвет кисти, задаваемый параметром color;
  • либо для палитры RGB: SetPenColor(rgb(0-255, 0-255, 0-255));
  • или использовать для заливки:

  • FloodFill(x,y,color) — заливает область одного цвета цветом color, начиная с точки (x,y).

После чего можно использовать процедуры для рисования геометрических фигур.

Цвета в pascal abc:

clBlack – черный
clPurple – фиолетовый
clWhite – белый
clMaroon – темно-красный
clRed – красный
clNavy – темно-синий
clGreen – зеленый
clBrown – коричневый
clBlue – синий
clSkyBlue – голубой
clYellow – желтый
clCream – кремовый
clAqua – бирюзовый
clOlive – оливковый
clFuchsia – сиреневый
clTeal – сине-зеленый
clGray – темно-серый
clLime – ярко-зеленый
clMoneyGreen – цвет зеленых денег
clLtGray – светло-серый
clDkGray – темно-серый
clMedGray – серый
clSilver – серебряный

Точки, отрезки и ломаные

Для отображения точки в паскале используется процедура:

  • SetPixel(x,y,color) — Закрашивает один пиксел с координатами (x,y) цветом color
  • точки в паскале

    uses GraphABC;
    begin
      SetPixel(300,200,clred);
    end.

    Для рисования линии используется:

  • Line(x1,y1,x2,y2) — рисует отрезок с началом в точке (x1,y1) и концом в точке (x2,y2)
  • паскаль линия

    uses GraphABC;
    begin
      SetPenColor(clgreen);
      line(100,50,500,250);
    end.

    Ломаные можно рисовать с помощью процедур MoveTo (x1, y1) и LineTo (x2, y2).
    Процедуры работают в паре: MoveTo передвигает курсор в определенную точку, а процедура LineTo рисует линию с этой точки до точки, определенной параметром данной процедуры.
    ломаные в паскале

    uses GraphABC;
    begin
    ...
    SetPenColor(clblue);
    MoveTo (x1, y1);
    LineTo (x2, y2);
    LineTo (x3, y3);
    LineTo (x4, y4);
    LineTo (x5, y5);
    end.

    Задание 0: При помощи операторов SetPenColor(), LineTo (x2, y2) и MoveTo (x1, y1) нарисовать квадрат и равносторонний треугольник.

    [Название файла: L4_2task0.pas]

    Для установки размеров графического окна используется процедура

  • SetWindowSize(ширина, высота)
  • или, например:

    SetWindowWidth(600);
    SetWindowHeight(400);

    Рисование фигур

    Прямоугольник в Паскале рисуется:

  • Rectangle(x1,y1,x2,y2) — рисует прямоугольник, заданный координатами противоположных вершин (x1,y1) и (x2,y2).
  • прямоугольник в паскале

    uses GraphABC;
    begin
      Rectangle(50,50,200,200);
    end.

    Фигуры с заливкой:

    Фигуры с заливкой

    uses GraphABC;
    begin
      Rectangle(50,50,200,200);
      FloodFill(100,100,clBlue);
    end.

    Треугольник рисуется процедурами:

    Line(x1,y1,x2,y2);
    LineTo(x,y);

    треугольник в паскале

    uses GraphABC;
    begin
      setpenwidth(20);
      setpencolor(clred);
      moveTo(300,100);
      lineTo(500,300);
      lineto(100,300);
      lineto(300,100);
      floodfill(300,200,clgreen);
    end.

    Окружность можно нарисовать с помощью процедуры:

  • Circle(x,y,r) — рисует окружность с центром в точке (x,y) и радиусом r.
  • круг в паскале

    uses GraphABC;
    begin
       Circle(500,200,100);
       FloodFill(500,200,clred);
    end.

    Дуга окружности

  • Arc(x,y,r,a1,a2) — Рисует дугу окружности с центром в точке (x,y) и радиусом r, заключенной между двумя лучами, образующими углы a1 и a2 с осью OX (a1 и a2 – вещественные, задаются в градусах и отсчитываются против часовой стрелки).
  • Дуга окружности

    1
    2
    3
    4
    5
    
    uses GraphABC;
    Begin
    SetPenWidth(10);
    Arc(300,250,150,45,135);
    end.

    Задание 1: «Лягушка»
    задание по теме графика в паскале

    [Название файла: L4_2task1.pas]

    Задание 2: «Корона»
    задание по теме графика в pascal

    [Название файла: L4_2task2.pas]

    Функция random для использования окраски

  • SetPenColor(rgb(random(256), random(256), random(256))); — выбирает случайное число из 256-цветной палитры для красного, зеленого и синего.
  • Задание 3: Нарисовать горизонтальный ряд окружностей радиусом 10 на расстоянии 100 от верхнего края экрана и с такими горизонтальными координатами 50, 80, 110, 140, … , 290.

    * раскрасить круги случайным цветом

    [Название файла: L4_2task3.pas]

    Задание 4: «Круги на воде».
    Нарисуйте пару десятков концентрических окружностей, то есть окружностей разного радиуса, но имеющих общий центр.

    [Название файла: L4_2task4.pas]

    Задание 5:
    Воспроизвести изображение при помощи программы:
    графика паскаль abc.net

    [Название файла: L4_2task5.pas]

    Штриховка

    Нарисовать штриховку на Паскале можно, используя процедуры рисования прямоугольника и линии:
    алгоритм штриховки на паскале

    Программа будет выглядеть следующим образом:

    1_1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    uses graphABC;
    var i, x1, x2, y1, y2, N: integer;
       h, x: real;
    begin   
      x1 := 100; y1 := 100;
      x2 := 300; y2 := 200;
      N := 10;
      Rectangle (x1, y1, x2, y2);
      h := (x2 - x1) / (N + 1);
      x := x1 + h;
      for i:=1 to N do begin
        Line(round(x), y1, round(x), y2);
        x := x + h;
      end;
    end.

    Задание 6:
    Нарисуйте шахматную доску.

    [Название файла: L4_2task6.pas]

    Анимация в Паскале

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

    Пример: Воспроизвести движение круга по горизонтали.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    uses GraphABC;
    var x:integer;
    begin
      x:=40;
    	repeat 
    		SetPenColor(clWhite);
    		Circle(x,100,10);	{Рисуем белую окружность}
    		SetPenColor(clBlack);
    		Circle(x,100,10);	{Рисуем черную окружность}
    		x:=x+1				{Перемещаемся немного направо}
    	until x>600;
    end.

    Задание 7: Выполнить анимацию движения квадрата по следующей траектории:

    [Название файла: L4_2task7.pas]

    • В начало
    • Паскаль
    • Задачник
    • Графика
    • Карта сайта

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

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

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

    Договоримся ещё об одном: систему будем строить с положительными и отрицательными значениями по обеим осям. Поскольку многие используют ещё турбо паскаль, то в конце страницы будет приведены две программы: одна – для 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:tp7bgi'); { Инициализируем графический режим }
      { Координаты левой верхней границы системы координат: }
      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 генерирует случайные числа с привязкой к текущему времени. Также в играх подобного типа обязательное использование таймера для создания плавности перехода. Позже в этом разделе мы напишем небольшие игры и посмотрим, как это работает.

    Система
    координат устройства и мировая система
    координат

    Окно вывода
    Построение
    графиков

    Когда нет
    времени…

    1.
    Система координат устройства и мировая система
    координат

    При работе с компьютерной графикой
    приходится иметь дело с двумя системами
    координат. Первая система – это система
    координат устройства (или экранная система
    координат). Координатами точки в этой системе
    являются номер пиксела в строке
    X и номер строки пикселов Y:

    dev_cs.gif (3373 bytes)

    0 <= X <= Xmax
    0 <= Y <= Ymax

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

    Вторая система координат – так
    называемая мировая или математическая. Она
    представляет собой декартову систему (
    x,
    y
    ), определяемую
    программистом, и является независимой от
    конкретного графического устройства:

    xmin < x < xmax
    ymin < y < ymax


    Параметры, которыми задаются
    диапазоны изменения
    x и y (xmin, ymin,
    xmax, ymax
    ), определяют
    прямоугольную область в математическом
    двумерном пространстве. Эти параметры зависят
    только от конкретной задачи.

    Мировые координаты и координаты
    устройства связаны между собой простыми
    соотношениями:

    (1)

    Формула для “экранной” координаты Y
    несколько отличается от формулы
    для координаты
    X в силу того,
    что в экранной системе координат ось
    OY направлена вниз.

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

    VAR
      xmin, xmax, ymin, ymax : real; { математические координаты
    }

    FUNCTION Xs( x : real ) :
    integer;
    BEGIN
      Xs := round( GetMaxX * (x-xmin)/(xmax-xmin) );
    END;

    FUNCTION
    Ys( y : real ) : integer;
    BEGIN
      Ys := round( GetMaxY * (1-(y-ymin)/(ymax-ymin)) );
    END;

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

    В качестве примера использования
    функций преобразования координат рассмотрим
    следующую задачу. В центре экрана необходимо
    отобразить некоторую область (см. рис.) и точку,
    координаты которой вводятся с
    клавиатуры.

    wpe13.jpg (4414 bytes)

    Предположим для начала, что нам нужно
    просто отобразить на экране оси координат (без
    разметки) и контуры заданной области. Это вполне
    можно сделать работая непосредственно с
    экранными координатами. Допустим, что разрешение
    экрана 640
    х480
    пикселов
    :

    wpe14.jpg (6324 bytes)

    Для построения осей и контура области
    воспользуемся процедурами
    Line и Rectangle:

    { Оси }
    Line(0,240,639,240);
    Line(320,0,320,479);
    { контур }
    Line(220,240,320,240);
    Line(220,240,320,140);
    Line(320,140,320,240);
    Rectangle(320,240,420,340);

    С построением области проблем не
    возникло. Пусть теперь необходимо отобразить на
    экране точку с координатами
    x = 0.6, y
    = -0.8
    . Для того, чтобы
    “поставить” на экране точку нужно вызвать
    процедуру
    PutPixel. Но процедура PutPixel, также как и другие графические
    процедуры, работает только с экранными
    координатами. А какие экранные координаты
    соответствуют точке
    (0.6, -0.8)? Конечно, их можно рассчитать:

    X=320+int((420-320)*0.6)

    Y=240-int((340-240)*(-0.8))

    Подумайте,
    как получены эти формулы?

     Но гораздо удобнее
    в этом случае с
    самого начала
    работать в мировой системе координат. Определим
    ее, например, следующим образом:

    xmin = -2, xmax = 2, ymin = -2, ymax = 2

    Построим контур области работая в
    мировой системе координат, при этом
    воспользуемся определенными ранее функциями
    Xs(x)
    и Ys(y).

    {
    Определяем параметры мировой СК }
    xmin := -2;
    xmax := 2;
    ymin := -2;
    ymax := 2;
    { Работаем в мировой СК }
    Line( Xs(-1), Ys(0), Xs(0), Ys(1) );
    Line( Xs(-1), Ys(0), Xs(0), Ys(0) );
    Line( Xs(0), Ys(1), Xs(0), Ys(0) );
    Rectangle( Xs(0), Ys(0), Xs(1), Ys(-1) );

    Для того чтобы отобразить точку с
    координатами
    x = 0.6, y = -0.8 теперь достаточно написать:

    PutPixel( Xs(0.6),
    Ys(-0.8), White );

    2. Окно
    вывода

    Иногда при построении изображений
    возникает необходимость разделить экран на
    несколько прямоугольных областей (графических
    окон) с тем, чтобы в каждом из окон строить свое
    изображение. В модуле
    GRAPH для этих целей имеется специальная
    процедура
    SetViewPort:

    SetViewPort( X1, Y1, X2,
    Y2 : Integer; ClipMode : Boolean );

    где переменные X1,
    Y1, X2
    и Y2 задают координаты диагонали окна, а
    параметр
    ClipMode определяет
    будет ли отображаться часть изображения
    попавшая за пределы окна или нет. Параметр
    ClipMode
    может принимать два значения.
    Значение
    ClipOn (true) указывает
    на то, что часть изображения попавшая за пределы
    окна не должна выводится на экран, а значение
    ClipOff
    (false)
    указывает на
    возможность вывода изображения попавшего за
    границы окна. После выполнения этой процедуры
    графический экран “сжимается” до размеров окна,
    текущий указатель перемещается левый верхний
    угол окна и туда же перемещается начало
    координат. Если параметр
    ClipMode равен ClipOn, то часть экрана вне окна становится
    недоступной.

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

    SetViewPort( GetMaxX
    div 2, GetMaxY div 2, GetMaxX, GetMaxY, ClipOff );

    то получим систему координат с началом
    в центре экрана. При этом станет “видимой”
    адресация отрицательных координат.

    Работу с графическими окнами можно
    организовать и без использования процедуры
    SetViewPort. Для этого достаточно лишь немного
    модифицировать рассмотренные ранее функции
    преобразования координат.

    Выделим на экране прямоугольную
    область
    с диагональю (XWmin,YWmin)
    – (XWmax,YWmax)
    :

    ww_cs.gif (5054 bytes)

    Совместим с этой областью
    математическую систему координат, заданную
    параметрами
    xmin, ymin, xmax и ymax.
    Формулы преобразования координат в этом случае
    будут иметь следующий вид:

    (2)

    При работе с мировыми координатами и
    использовании данного способа организации
    графических окон, целесообразно включить в
    программу следующий блок описаний:

    CONST
    XWmin : integer = 0; { Переменные, определяющие окно
    вывода }
    YWmin : integer = 0; { по умолчанию – весь экран }
    XWmax : integer = 639;
    YWmax : integer = 479;

    VAR
      xmin, xmax, ymin, ymax : real; { Мировая система координат }

    PROCEDURE SetWorldCoords( x1,
    y1, x2, y2 : real );
    { Процедура назначения мировых координат }
    BEGIN
      xmin := x1; xmax := x2;
      ymin := y1; ymax =: y2
    END;

    PROCEDURE SetWindow( x1, y1, x2,
    y2 : integer );
    { Процедура установки параметров окна вывода }
    BEGIN
      XWmin := x1; XWmax := x2;
      YWmin := y1; YWmax := y2
    END;

    { Функции преобразования
    мировых координат к координатам устройства }

    FUNCTION Xs( x : real ) :
    integer;
    BEGIN
      Xs := XWmin + round( (XWmax-XWmin)* (x-xmin)/(xmax-xmin) )
    END;

    FUNCTION Ys( y : real ) :
    integer;
    BEGIN
      ys := YWmax — round( (YWmax-YWmin)* (y-ymin)/(ymax-ymin) )
    END;

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

    3.
    Построение графиков

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

    Рассмотрим в качестве примера задачу
    построения линейного графика произвольной
    функции
    в заданном диапазоне изменения
    аргумента
    . Исходными данными в этой задаче
    являются: функция, график которой строится,
    диапазоны изменения аргумента
    a и b, и
    количество точек
    N,
    отображаемых на графике (или шаг изменения
    аргумента
    dx). При решения
    поставленной задачи желательно придерживаться
    следующей последовательности действий:


    1. ввод исходных данных;
    2. табулирование функции
      (вычисление значений функции при изменении аргумента от a до b
      с шагом dx);
    3. определение минимального и
      максимального значений функции на заданном
      интервале;
    4. определение мировой системы
      координат;
    5. построение осей координат;
    6. построение графика функции.

    Рассмотрим реализацию некоторых из
    перечисленных действий и оформим их в виде
    отдельных процедур и функций. В основной
    программе опишем следующие константы и
    переменные:

    CONST
      N = 50;

    VAR
      X, Y : array[1..N] of real;

    Константа N задает
    число точек отображаемых на графике. В массивы
    X
    и Y мы
    поместим результаты табулирования функции.

    Кроме этого, будем подразумевать, что в
    программу включено описание:

    • целочисленных переменных XWmin,
      XWmax, YWmin и YWmax, определяющих координаты окна вывода
      (см. выше);
    • вещественных переменных xmin, xmax,
      ymin, ymax, определяющих математическую систему
      координат;
    • процедур SetWindow и SetWorldCoords (см.
      выше);
    • двух функций преобразования
      координат Xs и Ys;
    • целочисленных переменных GrDr и
      GrMd, необходимых для процедуры инициализации
      графики.

    Табулирование функции:

    PROCEDURE
    TablFunc( a, b : real );
    VAR
      i : integer;

    function F( x : real ) : real;
    begin
      F := выражение для функции, график которой
    нужно построить;
    end;

    BEGIN
      for i:=1 to N do begin
        X[i] := a + (b-a)/(N-1)*(i-1);
        Y[i] : F( X[i] );
      end;
    END;

    Определение минимального и
    максимального значений функции:

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

    FUNCTION
    MinY : real;
    VAR i : integer;
    m : real;
    BEGIN
      m := Y[1];
      for i:=2 to N do if Y[i]<m then
    m := Y[i];
      MinY := m
    END;


    FUNCTION
    MaxY : real;
    VAR i : integer;
    m : real;
    BEGIN
      m := Y[1];
      for i:=2 to N do if Y[i]>m then
    m := Y[i];
      MaxY := m
    END;

    Оси координат:
    Основой для построения любых графиков и диаграмм
    является система координат. Ниже приведена
    процедура построения на экране декартовой
    системы координат с изображением осей и
    разметкой по периметру. Процедура имеет два
    параметра nx и ny, которые определяют количество
    штрихов на оси OX и OY, соответственно.

    PROCEDURE
    BuildCoords( nx, ny : Byte );
    VAR
      i : Byte;
      v : real;
      s : string;
    BEGIN
      SetColor( White );
      Rectangle( XWmin, YWmin, XWmax, YWmax ); { область графика }
      Line( Xs(xmin), Ys(0), Xs(xmax), Ys(0) ); { ось ОХ }
      Line( Xs(0), Ys(ymax), Xs(0), Ys(ymin) ); { ось OY }
      SetTextStyle(SmallFont,0,5); { выбор шрифта Small }
      SetTextJustify(CenterText,CenterText); { выравнивание текста }

      { Разметка оси Х }

      for i:=0
    to nx-1 do begin
        v := xmin + (xmax-xmin)/(nx-1)*i; { координата i-го
    штриха }
        Str(v:5:2,s); { преобразование числа в строку
    }
        Line(Xs(v), YWmax, Xs(v), YWmax+5); { черчение i-го
    штриха }
        OutTextXY(Xs(v), YWmax+15, s); { вывод числа }
      end;


      {
    Разметка оси Y }


      for i:=0 to
    ny-1 do begin
        v := ymin + (ymax-ymin)/(ny-1)*i;
        Str(v:5:2,s);
        Line(XWmin, Ys(v), XWmin-5, Ys(v));
        OutTextXY(XWmin-30, Ys(v), s);
      end;
    END;

    Построение графика:

    PROCEDURE Graphic(
    Color : word );
    VAR i : integer;
    BEGIN
      SetColor( Color );
      MoveTo( Xs(X[1]), Ys(Y[1]) );
      Circle( Xs(X[1]), Ys(Y[1]), 2);
      FOR i:=2 TO N DO begin
        LineTo( Xs(X[i]), Ys(Y[i]) );
        Circle( Xs(X[i]), Ys(Y[i]), 2);
      end;
    END;

    Процедура Graphic строит точечно-линейный график по
    точкам, хранящимся в массивах
    X и Y.
    Параметр
    Color
    определяет цвет линии.

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

    PROGRAM
    Graphic_of_Function;
    USES CRT, Graph;
    CONST
      N = 50;
    VAR
      X, Y : array[1..N] of real;
    VAR
      Описание переменных XWmin, XWmax, YWmin, YWmax;
      Описание переменных xmin, xmax, ymin, ymax;
      Описание процедуры SetWorldCoords;
      Описание процедуры SetWindow;
      Описание функции Xs;
      Описание функции Ys;
      Описание процедуры TablFunc;
      Описание функции MinY;
      Описание функции MaxY;
      Описание процедуры BuildCoords;
      Описание процедуры Graphic;
    VAR
      a, b : real;
      GrDr, GrMd : integer;

    BEGIN
      ClrScr;
      Write(‘Введите пределы изменения аргумента [a,
    b]: ’);
      ReadLn(a, b);
      TablFunc( a, b );
      GrDr := detect;
      InitGraph( GrDr, GrMd, ‘C:TP7BGI’ );
      SetWindow( 100, 50, 500, 400 );
      SetWorldCoords( a, MinY, b, MaxY );
      BuildCoords( 5, 5 );
      Graphic( Yellow );
      ReadKey;
      CloseGraph;
    END.

    Эту программу легко изменить с тем, что
    бы она строила график по заданным точкам,
    полученным, например, в результате некоторого
    эксперимента. Собственно говоря, ничего менять
    для этого не нужно. Необходимо написать новую
    процедуру заполнения массивов
    X и Y.
    Напомним, что раньше этим занималась процедура
    TablFunc. Процедура ввода данных может быть
    оформлена следующим образом:

    PROCEDURE
    ReadDATA;
    VAR
      i : integer;


    BEGIN
      WriteLn(‘Введите попарно координаты точек X, Y:
    ’);
      FOR i:=1 TO N DO begin
        Write(i,‘-я точка: ’);
        ReadLn( X[i], Y[i] )
      end
    END;

    После чего в основном блоке программы
    вместо вызова процедуры
    TablFunc нужно поставить вызов процедуры ReadDATA.

    На первый взгляд, рассмотренная выше
    программа построения линейных графиков может
    показаться несколько сложной (хотя это только
    кажущаяся сложность) и перегруженной различными
    процедурами и функциями. Основное достоинство
    рассмотренного подхода и программы в их
    относительной универсальности: какую бы Вы
    функцию не задали, какие бы Вы не ввели пределы
    изменения аргумента, программа обязательно
    построит желаемый график. Причем все изображение
    графика будет точно умещаться в рамках
    отведенного окна. Безусловно за универсальность
    приходится платить, и в данном случае, ценой
    введения разнообразных переменных и
    подпрограмм. Зато используя арсенал этих
    подпрограмм можно с одинаковой легкостью
    построить на экране как один график, так и целых
    десять, каждый из которых будет иметь свои оси
    координат.
    При желании
    описание некоторых подпрограмм (таких, как
    SetWindow,
    SetWorldCoords, Xs, Ys
    ), а также
    переменных
    XWmin, XWmax, YWmin, YWmax, xmin, xmax, ymin и ymax можно
    оформить в виде отдельного модуля. Можно также
    добавить процедуры построения графиков других
    видов. Все это позволит в дальнейшим значительно
    упростить написание программ, предусматривающих
    построение графиков.

    4.
    Когда нет времени…

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

    Для примера рассмотрим простую задачу:

    Камень
    брошен вверх под углом
    к горизонт с
    начальной скоростью
    . Требуется
    построить на экране траектории движения камня
    при разных значениях угла бросания
    .

    Уравнения движения для координат
    камня
    x и y в неподвижной инерциальной системе
    отсчета имеют вид:

    ,

    При заданных значения и максимальная
    высота подъема камня над горизонтом и
    максимальная дальность полета определяются
    соответственно
    :

    ,

    .

    Для построения траектории движения
    камня при заданных значения
    и необходимо, изменяя значение t
    с некоторым шагом , вычислять координаты x и y и
    отображать их на экране. Для того чтобы на экране
    “уместились” все траектории с различными
    значениями угла бросания необходимо сначала
    определить максимальную дальность полета и
    высоту подъема при заданном значении
    . Очевидно, что максимальная
    дальность полета будет равна
      (при ), а максимальная высота подъема    (при ).

    Определим декартову систему координат
    (мировые координаты) относительно которой будем
    строить траектории движения камня:

    xmin = 0,    xmax = ,   ymin = 0,   ymax = .

    С учетом формул (1) экранные координаты
    будут определятся следующими выражениями:

    ,
        ,

    где введены обозначения: и .

    Ниже приведена соответствующая
    программа.

    PROGRAM
    Stone;
    USES CRT, Graph;
    CONST
      g = 9.8;
    VAR
      x, y, t, dt,
      v0, alpha,
      gx, gy : real;
      xs, ys,
      GrDr, GrMd : integer;

    BEGIN
      ClrScr;
      Write(‘Введите начальную скорость камня Vo [м/с]:
    ’);
      ReadLn(v0);
      { Инициализация графического режима }
      GrDr := detect;
      InitGraph(GrDr, GrMd, ‘C:TP7BGI’);
      Line(0, GetMaxY, GetMaxX, GetMaxY ); { ось OX (поверхность
    Земли) }
      { Масштабные множители }
      gx := GetMaxX / ( sqr(v0)/g );
      gy := GetMaxY / ( sqr(v0)/(2*g) );
      { Начальный угол бросания }
      alpha := 10;
      REPEAT
        { Шаг по времени = 1/1000 от времени полета
    }
        dt := (2*v0*sin(alpha*pi/180)/g)/1000;
        t := 0;
        REPEAT
          x := v0*cos(alpha*pi/180)*t;
          y := v0*sin(alpha*pi/180)*t-g*sqr(t)/2;
          { Вычисляем экранные координаты
    и ставим желтую точку }
          xs := round( gx*x );
          ys := GetMaxY — round( gy*y );
          PutPixel( xs, ys, Yellow );
          t := t + dt;
        UNTIL (y<0);
        alpha := alpha + 5; { Увеличиваем угол бросания
    на 5 градусов }
      UNTIL (alpha>90);
      ReadKey;
      CloseGraph;
    END.

    Права на материал принадлежат их авторам
    Вернуться на главную страницу

    Понравилась статья? Поделить с друзьями:
  • Как найти сумму пяти чисел геометрической прогрессии
  • Планировщик пакетов qos windows 10 как найти
  • Как можно найти мошенника по номеру телефона
  • Как найти поезд по номеру электронного билета
  • Как найти в ворде все выделенные слова