014 – Розробка програми рисування графіка функції двох змінних z=f(x, y)

Розробка програми рисування графіку функції двох змінних z=f(x, y)

У даній роботі описано як в окремій формі реалізувати графік функції двох змінних

z = f(x, y)

або іншими словами графік у трьохвимірному просторі (3D).

Як приклад, вибрано функцію

z = sin(x) + cos(y)

Використовуючи даний приклад можна створювати власне програмне забезпечення для рисування графіків для інших функцій двох змінних.


Зміст


Умова задачі

Дано формулу функції двох змінних z = sin(x) + cos(y). Розробити додаток, який рисує графік цієї функції в окремій формі.

Додатково реалізувати поворот графіку вліво, вправо, вверх, вниз. Також потрібно виводити осі X, Y, Z.


Математична постановка задачі

Побудова графіка функції двох змінних є задачею, яка математично розв’язана і використовує відомі формули обчислення.

Графік функції двох змінних z(x, y) будується в паралелепіпеді з розмірами (xx1, xx2), (yy1, yy2), (zz1, zz2).

Для використання повороту системи у 3-вимірному просторі виникає поняття точки (x0, y0, z0), відносно якої відбувається поворот системи.

Також виникає поняття кутів:

  • 02_02_00_013_alfa (альфа) – поворот системи відносно осі OZ;
  • 02_02_00_013_beta (бета) – поворот системи відносно осі OX.

Зсув у точку (x0, y0, z0) з врахуванням повороту на кути 02_02_00_013_alfa та 02_02_00_013_beta описується відомими співвідношеннями

02_02_00_013_formula_01

Після перемноження матриць отримуємо формулу для обчислення:

02_02_00_013_formula_02

 

01_02_00_014_01_

Рис. 1. Зсув і поворот системи координат

Необхідно визначитись, в якій площині монітору будуть лежати вісі координат OX, OY, OZ. Приймаємо, що в площині монітору лежать осі OX та OY. А вісь OZ перпендикулярна екрану.

Координати розраховуваної точки (x, y) притискаються до точки (0, 0) за формулами:

02_02_00_013_formula_03

де A, a – коефіцієнти перспективи, які підбираються експериментально в залежності від функції.


Виконання

1. Запустити Delphi. Створити проект за шаблоном VCL Forms Application

Детальний приклад створення проекту описується тут. Зберегти проект під довільним іменем. У результаті буде створено головну форму програми з іменем Form1. Файл головної форми має ім’я “Unit1.pas“.

 

2. Розробка головної форми Form1

Створити головну форму за зразком, як показано на рисунку 2.

01_02_00_014_02u

Рис. 2. Вигляд форми Form1

На формі розміщується компонент типу TButton, який призначений для виклику обробника події відображення графіку функції. У результаті утворюється об’єкт з іменем Button1.

З допомогою Object Inspector в компоненті Button1 потрібно настроїти властивість Caption в значення «Показати 3D графік…».

 

3. Розробка другорядної форми Form2

Створити форму Form2 як показано на рисунку 3. Ця форма відображатиме графік функції. Приклад створення нової форми описується тут.

Форма Fom2 розміщується у модулі “Unit2.pas”.

01_02_00_014_03_

Рис. 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 – генерується, коли користувач відпускає кнопку мишки після натиску.

01_02_00_014_04_

Рис. 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).

01_02_00_014_05_Рис. 5. Виконання додатку