Rovinn kivky
Uivatelsk souadn soustava
Jak ji vme, DELPHI pracuje s tzv. svtovmi souadnicemi, kter jsou na pipojenm obrzku vyznaeny mode. Prce v takov soustav je pro uivatele znan nepjemn. Vytvome si proto tzv. uivatelskou souadnou soustavu, kter je vyznaena erven. Dlku osy (interval ) jako i dlku osy (interval ) budeme moci mnit. V obrzku je resp. dlka uivatelsk jednotky na ose resp. ve svtovch souadnicch. Zejm je
; (1)
Souadnice uivatelskho potku O ve svtovch souadnicch jsou pak
; (2)
Je-li pak libovoln bod na kreslic ploe, jeho souadnice
v uivatelsk soustav a jeho souadnice
ve svtov soustav, pak zejm plat
; (3)
Realizujme nyn uivatelskou
souadnou soustavu a vykresleme trojhelnk s danmi vrcholy. Na formul
jsme opt umstili objekt Image, proceduru, kter trojhelnk vykresluje, jsme
nazvali Triangle
a budeme ji aktivovat OnClick.
unit Graph2D;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs,ExtCtrls;
type
TPoint = array [1..2]
of Double;
TForm1 = class(TForm)
Image1: TImage;
procedure Triangle(Sender:TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure Scale(x1,x2,y1,y2:Double);
function XCoor(x:Double):integer;
function YCoor(y:Double):integer;
end;
Vimnte si vak,
e se hlavika tto procedury automaticky zapsala tak jako nov vlastnost typu
TForm. Tmto
zpsobem meme i my sami obohacovat typ TForm
o nov promnn, procedury a funkce, nejlpe do odstavce Public (zde
budou tyto vlastnosti v ppad poteby dostupn i z jinch jednotek).
Nyn se tedy dostvme k ervenmu textu, kter musme dopsat sami a kterm realizujeme uivatelskou souadnou
soustavu.
var Form1
:TForm1;
Unit_X,Unit_Y,x1,x2,y1,y2:Double;
O :TPoint;
implementation
{$R *.DFM}
procedure TForm1.Scale(x1,x2,y1,y2:Double);
begin
Unit_X:= Image1.Width/(x2-x1);
Unit_Y:=Image1.Height/(y2-y1);
O[1]:= -x1*Unit_X;O[2]:=y2*Unit_Y;
end;
function TForm1.XCoor(x:Double):integer;
begin XCoor:=trunc(O[1]+Unit_X*x);end;
function TForm1.YCoor(y:Double):integer;
begin
YCoor:=trunc(O[2]-Unit_Y*y);end;
procedure
TForm1.Triangle(Sender: TObject);
begin
end;
end.
Protoe
budeme chtt pracovat s body v rovin, deklarujeme v sti Interface typ TPoint jako uspodanou dvojici relnch sel (pedefinovali
jsme tedy typ TPoint, kter je v
Pklad 1:
Ve uveden st kdu by samozejm jet trojhelnk nevykreslila. Doplme
jej tak, abychom na vstupu trojhelnk dostali. V eenm pkladu jsou
podobn jako ve uveden ti procedury a funkce doplnny dal:
procedure
PutPixel(X:TPoint;Color:DWord);
procedure
MoveTo(X:TPoint);
procedure
LineTo(X:TPoint;Color:DWord);
procedure
Line(X,Y:TPoint;Color:DWord);
procedure
XAxis(x1,x2,y:Double;Color:DWord);
procedure
YAxis(y1,y2,x:Double;Color:DWord);
Procedury PutPixel, MoveTo a LineTo funguj analogicky, jako metody
obsaen v TCanvas ve standardnm
procedure
TForm1.LineTo(X:TPoint;Color:DWord);
begin
With
Image1.Canvas do
Begin
Pen.Color:=Color;LineTo(XCoor(X[1]),YCoor(X[2]));
end;
end;
V tchto procedurch tedy nen vyuit pstup
do bitmapy pes obrazov dky tak, jak bylo uvedeno v matematickch
podrobnostech pedchoz kapitoly. V dalm textu budeme
prozatm pouvat osmibitov barvy, resp. peddeklarovan konstanty - nap.
slRed, slGreen atd., kter byly popsny v
matematickch podrobnostech pedchoz kapitoly, a vlastn proceduru Line pro
seku, kter je popsna v matematickch podrobnostech tto kapitoly .
Jsou-li k dispozici ve uveden
procedury, pak trojhelnk vykreslme velmi jednodue:
procedure
TForm1.Triangle(Sender: TObject);
var A,B,C:TPoint;
begin
A[1]:=-2;A[2]:=6;
B[1]:= 4;B[2]:=-1; C[1]:= 5;C[2]:=5;
{definice vrchol}
x1:=-4;x2:=7;y1:=-3;y2:=8;
Scale(x1,x2,y1,y2);
{definice uivatelsk kreslic plochy}
Line(A,B,slRed);Line(B,C,slRed);Line(A,C,slRed); {vlastn
konstrukce}
end;
Zde
najdete kompletn zdrojov
kd a zde spustiteln kd
Pklad 2: Pedchoz pklad vylepme o cejchovn
souadnch os, kter obstarvaj procedury
XGauge (x1,x2,y:Double;Color:Byte);
resp. YGauge
(y1,y2,x:Double; Color: Byte). Podle velikosti mtka procedury
zvol vhodnou velikost jednotky na popis, k popisu pipoj vzdlenost
sousednch fous. Funguj nsledujcm zpsobem (jako pklad uveme popis
osy x):
procedure TForm1.XScale(x1,x2,y:Double;Color:DWord);
var AxisUnit :Double;
Text :String;
Lx,Exponent :Integer;
begin
Image1.Canvas.Font.Color:=Color;
AxisUnit:=1E30;Lx:=0;Exponent:=30;
While (x2-x1)/AxisUnit<1 do
begin
AxisUnit:=AxisUnit/10;Exponent:=Exponent-1;
end; {nalezen vhodn velikosti jednotky}
if x1<0
{nalezen
nejmen popisky}
then Repeat Lx:=Lx-1 Until
AxisUnit*(Lx-1)<x1
else Repeat Lx:=Lx+1 Until AxisUnit*(Lx+1)>x1;
With Image1.Canvas do
repeat
MoveTo(XCoor(AxisUnit*Lx),YCoor(y)-3); {cejchovn osy}
LineTo(XCoor(AxisUnit*Lx),YCoor(y)+3);
Str(Lx,Text);TextOut(XCoor(AxisUnit*Lx),YCoor(y)+5,Text);Lx:=Lx+1; {popisky}
until
AxisUnit*Lx>x2;
Str(Exponent,Text); {funkce Str pevd selnou hodnotu na etzec}
Image1.Canvas.TextOut(XCoor(x2)+15,YCoor(y)+5,'*10');
{jednotka
a exponent}
Image1.Canvas.TextOut(XCoor(x2)+35,YCoor(y),Text);
end;
Zde najdete kompletn zdrojov
kd a zde spustiteln kd
Pedchoz pklady neumouj mnit parametry za bhu programu. Tento nedostatek napravme v nsledujcm pkladu.
Pklad 3: K ovldn naeho formule Form1 zalome cel nov formul. V menu File klikneme na New Form. Objev se nm nov formul Form2 spolu s novou jednotkou Unit2. Tomuto formuli zmnme titulek na Control Panel. a umstme na nj ti tlatka, kter vybereme ze strnky Standard vcestrnkov lity. Tmto tlatkm zmnme titulky na Start, Clear Image a Exit. Dle nkolik objekt Static Text, tento typ najdeme v lit Additional, jejich titulky budou Triangle, Scale, dal budou slouit pro popis vrchol - A=, B=, C= a uivatelskch rozmr kreslic plochy x, y. Dle zde umstme Check Box (lita Standard) s titulkem Show Axses, s jeho pomoc bude uivatel vybrat monost zobrazen souadnch os. O tom, zda se souadn osy maj i nemaj zobrazit, rozhoduje vlastnost Checked typu Boolean. Konen pidme potebn poet objekt Edit (opt v lit Standard), do kterch bude uivatel zadvat hodnoty. Zmnme jejich jmna (vlastnost Name v Object Inspectoru) na EditA1, EditA2, , resp EditX1, EditX2, a Text, tak, aby pi sputn programu tato okna obsahovala vchoz parametry. N formul vypad tak, jak vidme na piloenm obrzku. Procedury tkajc se rovinn uivatelsk souadn soustavy jsou v samostatn jednotce - pvodn Unit1 pejmenujeme na Graph2D pomoc File/SaveAs. Do tto jednotky jsme tak umstili objekt typu TImage, kter jsme nazvali Draw2D a vechny konstrukce probhaj v tomto objektu. Nap. procedura pro mazn kreslic plochy kresl pes celou tuto plochu bl obdlnk:
procedure TDraw2D.ClearImage;
begin
with Image1.Canvas do
begin
Pen.Color:=clWhite;Brush.Color:=clWhite;end;
with Image1 do Canvas.Rectangle(0,0,Width-1,Height-1);
end;
V Control Panelu nejdve zadme ten parametr z Edit-oknek, a to procedurou Setting:
Procedure TControl_Panel.Setting;
var Code:Integer;
begin
With
Draw2D do
begin
Val(EditA1.Text,A[1],Code);
Val(EditA2.Text,A[2],Code);
Val(EditY2.Text,y2,Code);
Scale(x1,x2,y1,y2);
end;
end;
Tlatka v Control Panelu spojme pes udlost OnClick poad s procedurami Triangle, ClearImage a Exit:
procedure TControl_Panel.Triangle(Sender: TObject);
begin
With Draw2D do
begin
ClearImage;Setting;
if CheckBox1.Checked then CoorSystem(slRed);
Line(A,B,slBlue);Line(B,C,slBlue);Line(A,C,slBlue);
end;
end;
procedure TControl_Panel.ClearImage(Sender: TObject);
begin Draw2D.ClearImage;end;
procedure TControl_Panel.Exit(Sender: TObject);
begin Halt; end;
V pkladu je navc eeno zadvn vrchol trojhelnka my
Zde najdete kompletn zdrojov
kd a zde spustiteln kd
Kivky
typu
Z hlediska konstrukce se jedn o nejjednodu kivky. Lze je konstruovat jako lomen ry sloen z seek dle pipojenho obrzku:
Pklad 1: Sestrojme proceduru Explicit_Curve, kter sestroj graf funkce (viz pipojen vpis). Nejdve opt sestavme ovldac panel ze znmch komponent (v panelu NumberOfSegments bude uivatel zadvat poet segment, z kterch m bt kivka sestrojena. Stejn jako v pedchoz kapitole sestrojme uivatelskou kreslic plochu, souadn osy a definujeme barvu sestrojovan kivky. Vidme, e funkce je definovna uvnit procedury. Vlastn konstrukce spov v nastaven kroku hx a v postupn konstrukci seek :
Procedure
TControl_Panel.Explicit_Curve(Sender:TObject);
var x,hx:Double;
A,B :TPoint;
function f(x:Double):Double;
begin if x=0 then f:=0
else f:=x+10*x*x*sin(1/x); end;
begin
With Draw2D do {Uivatelsk kreslic plocha}
begin
if CheckBox1.Checked then
begin
{souadn osy a
jejich popis}
XScale(x1,x2,0,clRed); {sestroj stupnici rovnobnou s osou x, resp. y.}
YScale(y1,y2,0,clRed); { Pro uren barvy je pouita standardn konstanta }
end; { kvli snazmu
popisu os pomoc procedury TextOut}
hx:=(x2-x1)/NumberOfSegments;x:=x1;A[1]:=x;A[2]:=f(x);
Repeat {konstrukce kivky jako lomen ry}
B[1]:=x+hx;B[2]:=f(x+hx); Line(A,B,slBlue);A:=B;x:=x+hx
Until x>x2
end;
end;
Zde najdete kompletn zdrojov
kd a zde spustiteln kd
V ppad
kivek bv vhodn posloupnost bod, ktermi kivka prochz, nejdve celou
spotat a teprve potom proloit kivku.
Pklad 2: Pedefinujme metodu PolyLine a funkci z p. 1. sestrojme pomoc tto nov metody. Nae metoda bude pracovat s posloupnost bod, musme tedy nejdve deklarovat nov typ, nejlpe hned za TPoint:
TPoint = array [1..2] of Double;
TArrayOfPoints = array [0..800] of TPoint;
TPoint je tedy jeden bod - uspodan dvojice sel, TArrayOfPoints je posloupnost nejve osmi set bod. Do promnn tohoto typu se budou ukldat body, ktermi m prochzet nae kivka. S nstroji, kter ji mme k dispozici, je jej konstrukce jednoduch:
procedure Draw2D.PolyLine(Q:TArrayOfPoints; n:Word;Color:Byte);
var
i:Word;
begin
MoveTo(Q[1]);
for
i:=1 to n do LineTo(Q[i],Color);
end;
Vimnme si nejdve hlaviky: Q
je posloupnost bod, n definuje poet bod, kter maj bt spojeny, Color
pak barvu, kterou m bt kivka sestrojena. Procedura nejdve umst pero do
prvnho bodu pomoc na metody MoveTo, do nsledujcch pak kresl seky na
metodou LineTo. Samozejm je teba upravit i nai proceduru
Explicit_Curve (uvdm pouze st kdu, kter se od pedchozho pkladu li).
procedure TControl_Panel.Explicit_Curve(Sender:TObject);
var x,hx:Double; Q :TArrayOfPoints; i
:Word;
function f.....
begin
.......
hx:=(x2-x1)/NumberOfSegments;i:=0;x:=x1;
Repeat
Q[i,1]:=x;Q[i,2]:=f(x); {konstrukce kivky jako lomen ry}
x:=x+hx;i:=succ(i);
Until x>x2+hx;
PolyLine(Q,i,Color);
end;
Zde najdete kompletn zdrojov
kd a zde spustiteln kd
Je zde jedna ponkud nepjemn vc: V promnn typu TArrayOfPoints nm pibyl jeden index, kter udv poad bodu v posloupnosti. Ten je teba uvdt vdy jako prvn. Zpis Q [i,2] tedy znamen, e se jedn o druhou souadnici i - tho bodu v posloupnosti Q. Nai metodu PolyLine pouijeme i pi konstrukci kivek zadanch parametricky a polrn. Zde bude ponkud odlin pouze zpsob naplnn pole Q.
Z hlediska uivatele zstv jin nepjemnost vc: z ovldacho panelu nen mon mnit zadn funkce.
V pkladu 3, jeho zdrojov kd je zde a spustiteln kd je zde,
je tento nedostatek odstrann. etezec zadvan do okna EditFunction je vyslovn v jednotce Graph2D_256 funkc Calc(Text:String; ErrorReport:String). V zadvanm etzci je mono zadvat vechny bn funkce vetn cyklometrickch, k oznaen promnnch lze pout x, y, t, k. ErrorReport vrac chybov hlen. Mme-li k dispozici tuto proceduru, odpad zadvn funkce f ve zdrojovm kdu. Promnnou f deklarujeme jako etzec a pkaz A[i,2]:=f(x) nahradme pkazem A[i,2]:=Calc(f, ErrorReport). etzec ErrorReport je pi korektnm vpotu sprvn. Pi chybnm vyhodnocen je vrcen popis chyby, eho je mono vyut k chybovmu hlen a peruen procedury, nap:
A[i,2]:=Calc(f, ErrorReport)
if ErrorReport<>
then begin
ShowMessage(ErrorReport);
exit;
end;
Samotn vyslen etezce (funkce Calc) vak nen jednoduchou zleitost, bezprostedn nesouvis pmo s grafickmi problmy a nebudeme se jm proto podrobnji zabvat.
Dve, ne postoupme dle, je
teba uinit jet jednu poznmku. Barvy zadvme v
procedure TControl_Panel.FormActivate(Sender:TObject);
begin
Draw2D.InitImage(Image1.Width,Image1.Height);
end;
procedure TControl_Panel.Explicit_Curve(Sender:TObject);
var x,hx:Double; Q :TArrayOfPoints; i
:Word;
function f.....
begin
.......
hx:=(x2-x1)/NumberOfSegments;i:=0;x:=x1;
Repeat
Q[i,1]:=x;Q[i,2]:=f(x); {konstrukce kivky jako lomen ry}
x:=x+hx;i:=succ(i);
Until x>x2+hx;
PolyLine(Q,i,Color);
end;
Odkazy na kdy pracujc v True Color reimu budeme uvdt takto:
True Color: zdrojov kd spustiteln kd
Kivky
zadan parametricky a polrn
Konstrukce tchto kivek je velmi podobn, ukeme si ji na konkrtnm pkladu:
Pklad 1: Sestrojte kivku urenou
obecn parametrickmi rovnicemi ; (jedn se o
tzv. Lissajousovy kivky, kter opisuje kyvadlo rozkmitan ve dvou navzjem
kolmch rovinch a amplitudami , a hlovmi
frekvencemi ;). N kol e procedura Param_Curve. Nejprve jsou
deklarovny konstanty t1, t2, kter definuj rozsah parametru. Msto promnnch
x, hx je deklarovn parametr t a jeho krok ht. Na deklaraci parametrickch rovnic
ve zdrojovm kdu musme msto funkce pout proceduru, nebo jako vstup
potebujeme dv promnn - x, y.
procedure TControl_Panel.Param_Curve (Sender:
TObject);
var i:Word;
procedure Lissajous(t:double;var x,y:double);
begin
x:=3*sin(3*t); y:=3*cos(5*t);
end;
begin
With Draw2D do
begin
ClearImage(slWhite); {vyplnn plochy blou barvou}
Scale(x1,x2,y1,y2);
ht:=(t2-t1)/NumberOfSegments;
t:=t1;i:=0;
Repeat
Lissajous(t,Q[i,1],Q[i,2]);
t:=t+ht;i:=succ(i);
Until t>t2+ht;
PolyLine(Q,i,slBlue);
end;
end;
Vstupn parametry od vstupnch je teba v hlavice procedury oddlit klovm slovem var. Nsleduj parametrick rovnice (s konkrtnmi volbami za a, b, j, y). Ve vlastn procedue jsem se omezil opt vhradn na konstrukci kivky. Nejdve je poteba nastavit krok parametru ht a jeho poten hodnotu. V cyklu pak naplujeme pole Q parametrickmi rovnicemi, dokud parametr t krokem ht neprobhne cel interval t1;t2ñ (indexem i potme body v posloupnosti Q). Nakonec kivku vykreslme opt pomoc PolyLine.