Розробка програми рисування графіку функції двох змінних z=f(x, y)
У даній роботі описано як в окремій формі реалізувати графік функції двох змінних
z = f(x, y)
або іншими словами графік у трьохвимірному просторі (3D).
Як приклад, вибрано функцію
z = sin(x) + cos(y)
Використовуючи даний приклад можна створювати власне програмне забезпечення для рисування графіків для інших функцій двох змінних.
Зміст
- Умова задачі
- Математична постановка задачі
- Виконання
- 1. Запустити Delphi. Створити проект за шаблоном VCL Forms Application
- 2. Розробка головної форми Form1
- 3. Розробка другорядної форми Form2
- 4. Ввід внутрішніх змінних у Form2
- 5. Ввід внутрішніх методів у текст модуля “Unit2.pas”
- 6. Програмування обробників подій кліку на кнопках обертання графіку у формі Form2
- 7. Програмування обробника події активізації форми Form2
- 8. Програмування обробників подій обертання графіку з допомогою мишки
- 9. Програмування події кліку на кнопці «Показати 3D графік…» з форми Form1
- 10. Запуск додатку на виконання
Умова задачі
Дано формулу функції двох змінних z = sin(x) + cos(y). Розробити додаток, який рисує графік цієї функції в окремій формі.
Додатково реалізувати поворот графіку вліво, вправо, вверх, вниз. Також потрібно виводити осі X, Y, Z.
Математична постановка задачі
Побудова графіка функції двох змінних є задачею, яка математично розв’язана і використовує відомі формули обчислення.
Графік функції двох змінних z(x, y) будується в паралелепіпеді з розмірами (xx1, xx2), (yy1, yy2), (zz1, zz2).
Для використання повороту системи у 3-вимірному просторі виникає поняття точки (x0, y0, z0), відносно якої відбувається поворот системи.
Також виникає поняття кутів:
Зсув у точку (x0, y0, z0) з врахуванням повороту на кути та описується відомими співвідношеннями
Після перемноження матриць отримуємо формулу для обчислення:
Рис. 1. Зсув і поворот системи координат
Необхідно визначитись, в якій площині монітору будуть лежати вісі координат OX, OY, OZ. Приймаємо, що в площині монітору лежать осі OX та OY. А вісь OZ перпендикулярна екрану.
Координати розраховуваної точки (x, y) притискаються до точки (0, 0) за формулами:
де A, a – коефіцієнти перспективи, які підбираються експериментально в залежності від функції.
Виконання
1. Запустити Delphi. Створити проект за шаблоном VCL Forms Application
Детальний приклад створення проекту описується тут. Зберегти проект під довільним іменем. У результаті буде створено головну форму програми з іменем Form1. Файл головної форми має ім’я “Unit1.pas“.
2. Розробка головної форми Form1
Створити головну форму за зразком, як показано на рисунку 2.
Рис. 2. Вигляд форми Form1
На формі розміщується компонент типу TButton, який призначений для виклику обробника події відображення графіку функції. У результаті утворюється об’єкт з іменем Button1.
З допомогою Object Inspector в компоненті Button1 потрібно настроїти властивість Caption в значення «Показати 3D графік…».
3. Розробка другорядної форми Form2
Створити форму Form2 як показано на рисунку 3. Ця форма відображатиме графік функції. Приклад створення нової форми описується тут.
Форма Fom2 розміщується у модулі “Unit2.pas”.
Рис. 3. Форма Form2 виведення графіку функції
З палітри Tool Palette на формі розміщуються компоненти наступних типів:
- з вкладки Standard чотири компоненти типу TButton, які представляють стрілки напрямків обертання графіку функції. У результаті утворюється чотири об’єкти-змінні з іменами Button1, Button2, Button3, Button4;
- з вкладки Additional компонент типу TImage, в якому буде відображатись графік функції. Створюється об’єкт з іменем Image1.
З допомогою Object Inspector здійснити налаштування таких компонент:
- у компоненті Button1 властивість Caption = «^»;
- у компоненті Button2 властивість Caption = «v»;
- у компоненті Button3 властивість Caption = «<<»;
- у компоненті Button4 властивість Caption = «>>».
4. Ввід внутрішніх змінних у Form2
Усі внутрішні змінні, що використовуються для організації виведення графіку, розміщуються в формі Form2. Тому, спочатку треба активізувати модуль «Unit2.pas».
У модуль форми Form2 у розділі private вводяться наступні внутрішні змінні:
- xx1, xx2, yy1, yy2 – відповідають координатам точок що відображаються на екрані монітору;
- масиви xx та yy які призначені для виведення площини з 4-х точок. Область визначення функції z = f(x, y) розбивається на прямокутники, на кожному з яких функція екстраполюється з ребрами чотирикутника.
У розділі public вводяться:
- змінні X_min, Y_min, X_max, Y_max дійсного типу, що відповідають реальним координатам паралелепіпеда, в якому виводиться графік функції. Ці змінні заповнюються з основної форми Form1 експериментальним шляхом;
- змінні alfa, beta дійсного типу, які відображають кути спостереження за графіком функції. Заповнюються з основної форми Form1;
- змінні x0, y0, z0 дійсного типу. Відображають величини з основної формули обчислення (див. математичну постановку задачі);
- змінна A дійсного типу є коефіцієнтом перспективи і підбирається експериментально;
- змінна f_show логічного типу, яка використовується для вказування того, що потрібно перемалювати графік у випадку зміни положення одного з кутів alfa чи beta.
Після введення змінних у текст програми, фрагмент класу форми Form2 має вигляд:
type
TForm2 = class(TForm)
...
private
{ Private declarations }
xx1, xx2, yy1, yy2 : integer;
xx, yy : array[0..3] of integer;
public
{ Public declarations }
// Дані, які заповнюються з форми Form1
X_min, Y_min, X_max, Y_max: real;
alfa, beta:real;
x0, y0, z0:real;
A:real;
f_show:boolean;
...
end;
Змінні з розділу public заповнюються з форми Form1.
5. Ввід внутрішніх методів у текст модуля “Unit2.pas”
У текст класу форми Form2 потрібно ввести три додаткові методи:
- процедуру перетворення системи координат і масштабування Zoom_XY;
- функцію func для якої виводиться графік;
- процедуру рисування графіка функції Show_Graphic.
Після введення внутрішніх методів, фрагмент лістингу класу Form2 наступний:
type
TForm2 = class(TForm)
...
private
{ Private declarations }
xx1, xx2, yy1, yy2 : integer;
xx, yy : array[0..3] of integer;
// внутрішні методи
procedure Zoom_XY(x,y,z:real; var xx,yy:integer);
procedure Show_Graphic;
function func(x,y:real):real;
public
{ Public declarations }
// Дані, які заповнюються з форми Form1
X_min, Y_min, X_max, Y_max: real;
alfa, beta:real;
x0, y0, z0:real;
A:real;
f_show:boolean;
end;
...
Лістинг процедури перетворення системи координат наступний:
procedure TForm2.Zoom_XY(x: Real; y: Real; z: Real; var xx: Integer; var yy: Integer);
var
tx, ty, tz:real;
xn, yn, zn:real;
begin
tx := (x-x0)*cos(alfa) - (y-y0)*sin(alfa);
ty := ((x-x0)*sin(alfa) + (y-y0)*cos(alfa)) * cos(beta) - (z-z0)*sin(beta);
tz := ((x-x0)*sin(alfa) + (y-y0)*cos(alfa)) * sin(beta) + (z-z0)*cos(beta);
xn := tx/(tz/A+1);
yn := ty/(tz/A+1);
xx := Trunc(Image1.Width * (xn-X_min)/(X_max-X_min));
yy := Trunc(Image1.Height * (yn-Y_max)/(Y_min-Y_max));
end;
Безпосереднє виведення графіку функції реалізовано в процедурі Show_Graphic. Лістинг процедури Show_Graphic наступний.
procedure TForm2.Show_Graphic;
const
h = 0.1;
h0 = 0;
var
i,j:integer;
canv:TCanvas;
begin
canv := Image1.Canvas; // полотно для рисування
// очищення полотна (канви)
canv.Rectangle(-1,-1, Image1.Width, Image1.Height);
// рисування осей
Zoom_XY(0,0,0,xx1,yy1);
Zoom_XY(1.2,0,0,xx2,yy2);
canv.MoveTo(xx1,yy1);
canv.LineTo(xx2,yy2);
canv.TextOut(xx2+3,yy2,'X');
Zoom_XY(0,0,0,xx1,yy1);
Zoom_XY(0,1.2,0,xx2,yy2);
canv.MoveTo(xx1,yy1);
canv.LineTo(xx2,yy2);
canv.TextOut(xx2+3,yy2,'Y');
Zoom_XY(0,0,0,xx1,yy1);
Zoom_XY(0,0,1.2,xx2,yy2);
canv.MoveTo(xx1,yy1);
canv.LineTo(xx2,yy2);
canv.TextOut(xx2+3,yy2-3,'Z');
// рисування поверхні
for j:=0 to 9 do
for i:=0 to 9 do
begin
Zoom_XY(h0+h*i, h0+h*j, func(h0+h*i, h0+h*j), xx[0], yy[0]);
Zoom_XY(h0+h*i, h+h*j, func(h0+h*i, h+h*j), xx[1], yy[1]);
Zoom_XY(h+h*i, h+h*j, func(h+h*i, h+h*j), xx[2], yy[2]);
Zoom_XY(h+h*i, h0+h*j, func(h+h*i, h0+h*j), xx[3], yy[3]);
canv.Polygon([Point(xx[0], yy[0]), Point(xx[1], yy[1]),
Point(xx[2], yy[2]), Point(xx[3], yy[3])]);
end;
end;
Пояснимо деякі фрагменти коду в процедурі Show_Graphic.
Область визначення функції z = f(x, y) розбивається на прямокутники, на кожному з яких функція екстраполюється з ребрами чотирикутника. Побудова чотирикутників на екрані реалізується з допомогою методу Polygon().
Після очищення канви відбувається рисування осей координат і методом Polygon() виводяться фрагменти поверхні.
При рисуванні поверхні, з процедури Show_Graphic викликається процедура Zoom_XY(), яка здійснює перетворення і масштабування з реальних координат в екранні координати.
Лістинг методу func() наступний.
function TForm2.func(x: Real; y: Real):real;
begin
func := sin(x) + cos(y);
end;
У цьому методі замість рядка
func := sin(x) + cos(y);
можна зробити вставку власної функції.
6. Програмування обробників подій кліку на кнопках обертання графіку у формі Form2
Обертання графіку відбувається в момент, коли користувач робить клік на одній з кнопок розміщених на формі Form2 (компоненти Button1, Button2, Button3, Button4).
Відображення графіку залежить від внутрішніх змінних alfa і beta. Змінна alfa містить кут повороту відносно осі OZ. Змінна beta містить значення кута повороту навколо осі OX.
Тому, в обробниках подій відбувається зміна значень alfa і beta на деяку величину. За бажанням, можна встановити власну величину зміни alfa і beta.
Лістинг обробників подій наведено нижче.
procedure TForm2.Button1Click(Sender: TObject);
begin
beta := beta + 0.1;
Show_Graphic;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
beta := beta - 0.1;
Show_Graphic;
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
alfa := alfa + 0.1;
Show_Graphic;
end;
procedure TForm2.Button4Click(Sender: TObject);
begin
alfa := alfa - 0.1;
Show_Graphic;
end;
7. Програмування обробника події активізації форми Form2
В момент виклику форми Form2 має виводитись графік функції. Тому в обробнику події OnActivate форми Form2 викликається метод Show_Graphic.
procedure TForm2.FormActivate(Sender: TObject);
begin
Show_Graphic;
end;
8. Програмування обробників подій обертання графіку з допомогою мишки
Для здійснення обертання графіку з допомогою мишки потрібно запрограмувати відповідні обробники подій компонента Image1.
Якщо натиснути клавішу миші і утримувати її натиснутою над компонентом Image1 а потім відпустити, то генеруються такі події (рисунок 4):
- OnMouseDown – генерується, коли користувач робить клік мишкою на компоненті Image1;
- OnMouseMove – генерується, коли користувач переміщує мишку над компонентом Image1 (не залежно, чи натиснута одна з кнопок мишки);
- OnMouseUp – генерується, коли користувач відпускає кнопку мишки після натиску.
Рис. 4. Події OnMouseDown, OnMouseMove, OnMouseUp компонента Image1
Переміщення мишки з натиснутою клавішею по компоненту Image1 приводить до зміни кутів alfa і beta. Змінна f_show використовується для вказівки обробнику події OnMouseMove, що потрібно змінити змінні alfa і beta і перемалювати графік.
Лістинги обробників подій OnMouseDown, OnMouseMove та OnMouseUp наведено нижче.
procedure TForm2.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
f_show := true;
end;
procedure TForm2.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
a, b:real;
begin
if f_show then
begin
a := x - Width div 2;
b := y - Height div 2;
if a<>0 then
alfa := arctan(b/a)
else
alfa := Pi/2;
beta := sqrt(sqr(a/10) + sqr(b/10));
Show_Graphic;
end;
end;
procedure TForm2.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
f_show := false;
end;
9. Програмування події кліку на кнопці «Показати 3D графік…» з форми Form1.
При кліку на кнопці Button1 з форми Form1 має виводитись графік функції.
Обробник події кліку на кнопці Button1 має вигляд.
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2.f_show := false;
Form2.x0 := 0;
Form2.y0 := 0;
Form2.z0 := 0;
Form2.A := -8;
Form2.alfa := 10;
Form2.beta := 12;
Form2.X_min := -3;
Form2.X_max := 3;
Form2.Y_min := -3;
Form2.Y_max := 3;
Form2.ShowModal;
end;
Як видно з лістингу, перед викликом форми Form2 формуються значення внутрішніх змінних. Ці значення підбираються експериментально і можуть відрізнятись для кожної функції.
10. Запуск додатку на виконання
Тепер можна запустити додаток на виконання і протестувати його роботу (рисунок 5).