Рекомендации по выполнению задания

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

{ ПАРАМЕТРЫ РИСУНКА МОЖНО ИЗМЕНИТЬ В МОДУЛЕ Consts }

uses

Crt,

Graph, { модуль графической библиотеки }

Consts, { модуль с константами }

Types, { модуль описания типов данных }

Mathem1, { модуль математических преобразований }

Draw1, { модуль процедур и функций для рисования }

{ МОДУЛИ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ }

Mathem2, { модуль математических преобразований }

Draw2; { модуль процедур и функций для рисования }

{ Первая математическая функция }

function F1(x:real):real; far; { Дальняя ссылка }

begin

F1:=9*x*x-11;

end;

{ Вторая математическая функция }

function F2(x:real):real; far; { Дальняя ссылка }

begin

F2:=x*x*x+5;

end;

{ **************** Основная часть **************** }

var

M1,M2:TMatMas; { Таблицы математических функций }

Y1min,Y2min, { Минимумы и ... }

Y1max,Y2max, { ... максимумы математических функций }

Ymin,Ymax:real; { Абсолютный минимум и максимум функций }

Kx,Ky:real; { Масштабирующие коэффициенты }

Ms1,Ms2:TScrMas; { "Экранные" таблицы }

Xo,Yo:word; { Координаты "экранного" нуля }

RootMas:TRoot; { Массив точек пересечения }

K:word; { Количество точек пересечения }

Rect:TRect; { Прямоугольник для вывода графика }

begin

{ ********* Подготовка данных для рисования *********** }

with Rect do

begin

Origin.X:=OriginX;

Origin.Y:=OriginY;

Size.X:=Nx;

Size.Y:=Ny;

end;

{ Заполнение таблиц математических функций }

EnterMatMas (M1,Nx,@F1,Xmin,Xmax);

EnterMatMas (M2,Nx,@F2,Xmin,Xmax);

{ Вычисление минимума и максимума математических функций }

Y1min:=Min(M1,Nx); Y1max:=Max(M1,Nx);

Y2min:=Min(M2,Nx); Y2max:=Max(M2,Nx);

Ymin:=Minimum(Y1min,Y2min);

Ymax:=Maximum(Y1max,Y2max);

{ Вычисление масштабирующих коэффициентов }

Kx:=Nx/(Xmax-Xmin);

Ky:=Ny/(Ymax-Ymin);

{ Заполнение "экранных" таблиц }

EnterScrMas(Ms1,M1,Ymin,Ky,Rect);

EnterScrMas(Ms2,M2,Ymin,Ky,Rect);

{ Вычислить координаты "экранного" нуля }

Zero(Xmin,Xmax,Ymin,Ymax,Rect,Kx,Ky,Xo,Yo);

{ Найти точки пересечения }

K:=Solution(Xmin,Xmax,@F1,@F2,RootMas);

{ ********************** Рисование ********************* }

GraphInit;

{ Нарисовать рамку }

Ramka(Rect,Width,Cyan);

{ Рисование граничных значений по углам рамки }

DrawBounds(Xmin,Xmax,Ymin,Ymax,Rect,Red);

{ Рисование координатной сетки }

DrawGridLines(NgrX,NgrY,Rect,DarkGray);

{ Нарисовать оси }

DrawAxis(Rect,Xo,Yo,Red);

{ Нарисовать функции }

DrawFunction(Ms1,Nx,LightGreen);

DrawFunction(Ms2,Nx,Yellow);

{ Вывести координаты точек пересечения }

WriteCoord(RootMas,K,Rect,LightGreen);

ReadKey;

CloseGraph;

end.

Разбиение текста программы на отдельные модули позволяет сделать программу более «читабельной». Пусть даже эти модули очень небольшие.

unit Consts;

interface

const

Nx=440; { Размер графика по оси X }

Ny=480; { Размер графика оси Y }

OriginX=180; OriginY=40; { Левый верхний угол рамки }

Xmin=-2; Xmax=2; { Начальное и конечное значения аргумента }

NgrX=6; NgrY=23; { Количество линий координатной сетки }

Epsilon=0.001; { Точность решения }

R=10; { Количество поддиапазонов }

const

Width=3; { Ширина рамки }

implementation

end.

Модуль используемых типов.

unit Types;

interface

uses Consts;

type

TMatMas=array[1..Nx] of real; { Тип математической таблицы }

TScrMas=array[1..Nx] of word; { Тип "экранной" таблицы }

TRealCoord=record x,y:real; end; { Тип координата в действит. числах }

TRoot=array[1..Nx div 10] of TRealCoord; { Тип массив точек пересечения }

TIntCoord=record x,y:word; end; { Тип координата в целых числах }

TRect=record { Координаты прямоугольника }

Origin:TIntCoord; { Левый верхний угол }

Size:TIntCoord; { Размер }

end;

implementation

end.

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

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

unit Mathem1;

interface

uses Types, Consts;

procedure EnterMatMas (

var M : array of real; { Таблица математической функции }

Nx : word; { Количество точек в таблице }

Func : Pointer; { Указатель на математическую функцию }

Xmin,Xmax : real { Начальное и конечное значения аргумента }

);

{ Вычисление точек пересечения }

function Solution(

Xmin,Xmax:real; { Минимум и максимум аргумента }

F1,F2:pointer; { Математические функции }

var RootMas:TRoot): { Массив координат пересечения }

byte; { Количество точек пересечения }

implementation

procedure EnterMatMas(

var M : array of real; { Таблица математической функции }

Nx : word; { Количество точек в таблице }

Func : Pointer; { Указатель на математическую функцию }

Xmin,Xmax : real { Начальное и конечное значения аргумента }

);

type

TFunc = function (x:real):real; { Описание типа функции }

var

F : TFunc; { Математическая функция }

x : real; { Значение аргумента }

dx : real; { Шаг вычисления функции }

i : word; { Счетчик вычисляемых точек }

begin

F:=TFunc(Func); { Сделать ссылку на математическую функцию }

dx:=(Xmax-Xmin)/(Nx-1); { Вычислить шаг вычисления функции }

x:=Xmin; { Начальное значение аргумента }

for i:=0 to Nx-1 do { Цикл заполнения таблицы }

begin

M[i]:=F(x); { занести значение в массив }

x:=x+dx; { следующее значение аргумента }

end;

end;

{ Вычисление точек пересечения }

function Solution(

Xmin,Xmax:real; { Минимум и максимум аргумента }

F1,F2:pointer; { Математические функции }

var RootMas:TRoot): { Массив координат пересечения }

byte; { Количество точек пересечения }

type

TFunc = function (x:real):real; { Описание типа функции }

var

Fu1,Fu2 : TFunc; { Математические функции }

{ Для вычисления точек пересечения задана новая функция,

как разность двух исходных }

function Fu(x:real):real;

begin

Fu:=Fu1(x)-Fu2(x);

end;

{ Определить, есть ли решения в поддиапазоне }

function SubRange (var FirstX, LastX, Step : real) : boolean;

begin

{ Найти поддиапазон, на котором есть решение.

Из условия, что при прохождении через ось X функция меняет знак }

while (Fu(FirstX)*Fu(FirstX+Step)>0)and((FirstX+Step)<=Xmax) do

FirstX := FirstX+Step;

if ((FirstX+Step)<=Xmax)

then

begin

LastX := FirstX+Step;

SubRange := True;

end

else SubRange := False;

end;

{ Вычисление корня }

function Root (FirstX, LastX, NewStep : real) : real;

begin

repeat

{ Вычислить новое значение шага }

NewStep := NewStep/R;

{ Найти новый (уточненный) поддиапазон }

SubRange (FirstX,LastX,NewStep);

{ Определение правой границы поддиапазона }

LastX := FirstX + NewStep;

until abs(NewStep)<=Epsilon/R; { Условие достижения заданной точности }

Root := FirstX; { Возвращение корня }

end;

var

Step : real; { Величина подиапазона }

CurLeft,CurRight:real; { Границы отрезка, на котором есть решение }

k:word; { Номер точки пересечения }

begin

k:=0;

{ Задать функции }

Fu1:=TFunc(F1); Fu2:=TFunc(F2);

{ Вычислить начальный размер поддиапазона }

Step:=(Xmax-Xmin)/R;

{ Поиск решения с левой крайней границы отрезка }

CurLeft := Xmin;

{ Цикл поиска всех решений }

while SubRange(CurLeft,CurRight,Step) do

begin

inc(k);

RootMas[k].X:=Root(CurLeft,CurRight,Step);

RootMas[k].Y:=Fu1(RootMas[k].X);

CurLeft := CurRight;

end;

Solution:=K;

end;

end.

Задание: самостоятельно реализуйте реализацию (implementation) модуля Mathem2. Интерфейсная часть данного модуля имеет вид:

unit Mathem2;

interface

{ Функция вычисления минимума в массиве (таблице) точек }

function Min(

M : array of real; { Таблица математической функции }

N : word { Количество точек в таблице }

):real;

{ Функция вычисления минимума в массиве (таблице) точек }

function Max(

M : array of real; { Таблица математической функции }

N : word { Количество точек в таблице }

):real;

{ Выбор минимального из двух значений }

function Minimum(x,y:real):real;

{ Выбор максимального из двух значений }

function Maximum(x,y:real):real;

{ Процедура заполнения "экранной" таблицы }

procedure EnterScrMas(

var Ms : array of word; { "Экранная" таблица }

Mm : array of real; { Таблица математической функции }

Ymin : real; { Минимум математической функции }

K : real; { Коэффициент масштабирования }

var Rect { Прямоугольник вывода }

);

{ Вычислить координаты "экранного" нуля }

procedure Zero (

Xmin,Xmax,Ymin,Ymax:real; { Математические пределы изменения функций }

var Rect; { "Экранные" пределы изменения функций }

Kx,Ky:real; { Коэффициенты масштабирования }

var Xo,Yo:word); { Координаты "экранного" нуля }

implementation

end.

 

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

{*********** Процедуры и функции для работы с графикой *************}

unit Draw1;

interface

uses Types;

{ Инициализация графики }

procedure GraphInit;

{ Рисование функции по точкам из массива }

procedure DrawFunction(M:array of word;N:word;Color:byte);

{ Рисование рамки }

procedure Ramka(Rect:TRect;Width,Color:word);

implementation

uses Graph,Consts;

{ Инициализация графики }

procedure GraphInit;

var

Driver,Mode:integer;

Res:integer;

begin

Driver:=Detect;

InitGraph(Driver,Mode,'');

Res:=GraphResult;

if Res<>0 then

begin

WriteLn(GraphErrorMsg(Res));

WriteLn('Press <Enter> for exit');

ReadLn;

Halt(1);

end;

end;

{ Рисование функции по точкам из массива }

procedure DrawFunction(M:array of word;N:word;Color:byte);

var

i:word;

begin

SetColor(Color);

MoveTo(OriginX,M[0]);

for i:=1 to N-1 do

begin

LineTo(OriginX+i,M[i]);

{ PutPixel(OriginX+i,M[i],Color);}

end;

end;

{ Рисование рамки }

procedure Ramka(Rect:TRect;Width,Color:word);

var

i,OldColor:byte;

begin

OldColor:=GetColor;

SetColor(Color);

with Rect do

for i:=1 to Width do

Rectangle(Origin.X-i, Origin.Y-i,

Origin.X+Size.X+i, Origin.Y+Size.Y+i);

SetColor(OldColor);

end;

end.

Задание: самостоятельно реализуйте реализацию (implementation) модуля Draw2. Интерфейсная часть данного модуля имеет вид:

{*********** Процедуры и функции для работы с графикой *************}

unit Draw2;

interface

{ Нарисовать оси }

procedure DrawAxis(var Rect;Xo,Yo,Color:word);

{ Рисование граничных значений по углам рамки }

procedure DrawBounds(Xmin,Xmax,Ymin,Ymax:real;var Rect;Color:word);

{ Рисование координатной сетки }

procedure DrawGridLines(NgrX,NgrY:word;var Rect;Color:word);

{ Вывод координат точек пересечения }

procedure WriteCoord(var RootMas;K:word;var Rect;Color:word);

implementation

end.

 

Контрольные вопросы по теме № 8

1. Библиотечные функции графической библиотеки в языке Turbo Pascal.

2. Масштабирование функции для вывода в виде графика.

3. Тип процедура и тип функция. Преобразование типов.

4. Решение нелинейного алгебраического уравнения (метод деления отрезка пополам, метод простых итераций, метод пошаговых приближений).