1.4
Javítás a fényerő-problémán
2.2 A
körív pontjai: (r*cos(a), r*sin(a))
A
képernyőn a „normál” koordinátarendszer:
|
A két koordinátarendszer közötti áttérést ráhagyjuk a PontRajzol
eljárásra, amely felhasználja a képernyőre pontot rajzoló Pont utasítást [1]:
Eljárás PontRajzolás(Konstans x,y:Valós):
[globális input: ks, ko]
s:=Kerekít(ks-y); o:=Kerekít(ko+x)[2]
Ha sÎ[0,MaxY] és oÎ[0,MaxX] akkor Pont(o,s)
Eljárás vége.
A feladat:
szakaszt rajzolni (x1,y1)
és (x2,y2) között. Föltehető, hogy x1£x2.
A két
ponton húzható egyenes egyenlete: y=(y2-y1)/(x2-x1)*(x-x1)+y1
A megoldás
lényege:
1. vegyük sorra x
lehetséges (egész) értékeit [x1,x2] között, és
2. rajzoljuk ki az (x,y(x)) pontot!
Eljárás SzakaszRajzolás(Konstans x1,y1,x2,y2:Egész):
Változó
x,y,it:Valós
it:=(y2-y1)/(x2-x1) [iránytangens]
Ciklus x=x1-től
x2-ig [3]
y:=(x-x1)*it+y1;
PontRajzolás(x,y)
Ciklus vége
Eljárás vége.
Problémák:
Pl.: it=0, akkor a
„fénysűrűség”=(N-fénypont)/(N pixelnyi hossz)=1,
it=1, akkor a
„fénysűrűség”=(N-fénypont)/(*(N pixelnyi hossz))=»0,71.
Az alábbiakban először az első két problémára keresünk megoldást.
Válasszuk szét az it£1,
it>1, és x1=x2 eseteket! A 2. esetben cseréljük föl x és y szerepét, a 3. esetben speciálisan
erre az esetre specifikálunk egy eljárást.
Eljárás SzakaszRajzolás(Konstans x1,y1,x2,y2:Egész):
Változó
x,y,it:Valós
Ha x1=x2
akkor
FüggőlegesRajzolás(x1,y1,y2)
különben
it:=(y2-y1)/(x2-x1) [iránytangens]
Ha it£1 akkor
Ciklus x=x1-től
x2-ig
y:=(x-x1)*it+y1;
PontRajzolás(x,y)
Ciklus vége
különben
Ciklus y=y1-től
y2-ig
x:=(y-y1)/it+x1;
PontRajzolás(x,y)
Ciklus vége
Elágazás vége
Elágazás vége
Eljárás vége.
Válasszuk
meg úgy az x-irányú lépésközt, hogy az megfelelő legyen minden esetben (a
függőleges esetet kivéve). Ez elérhető, ha az x-irányú eltérés (hx) és az y-irányú eltérés (hy) maximumával normáljuk a
lépésközöket.
|
Hány lépést (k) kell tenni? x2=x1+k*lx Û k=(x2-x1)/lx Û k=(x2-x1)/(hx/h) Û Hasonlóan (és
nem meglepő módon) ugyanezt kapjuk az y-irányban is. |
Eljárás SzakaszRajzolás(Konstans x1,y1,x2,y2:Egész):
Változó
lx,ly,x,y:Valós
k,hx,hy,h:Egész
hx:=x2-x1; hy:=y2-y1
Ha Abs(hx)>Abs(hy) akkor
h:=Abs(hx) különben h:=Abs(hy)
Ha h=0 akkor
PontRajzolás(x1,y1)
különben
lx:=hx/h [x–irányú lépésköz]
ly:=hy/h [y–irányú lépésköz]
x:=x1; y:=y1;
PontRajzolás(x1,y1)
[kezdőpont]
Ciklus k=1-től h-ig
x:+lx; y:+ly;
PontRajzolás(x,y)
Ciklus vége
Elágazás vége
Eljárás vége.
Ötlet: kiegészíteni további (azonos színű, fényességű) pontokkal a „töréseknél”. (A színezés csak az új pontok kiemelését szolgálja.) |
|
Ami után a probléma „megfordul”: Ui.. ha it=1, akkor h pont helyett h+(h-1) pont
lesz, |
|
Ötlet: kiegészíteni kisebb (számítható) fényerejű pontokkal. |
|
A feladat körívet rajzolni. Vegyük észre, hogy
1.
a kör szimmetriája miatt, ha az(x,y) pont rajta van az íven , akkor az (-x,y), (x,-y),
(-x,-y)pontok is rajta lesznek.
(Sőt további szimmetriatengelyei is vannak, amelyek kihasználhatók!)
2. az (x0,y0) középpontú kör a (0,0) középpontú eltolásával egyszerűen megkapható, amelyet ismét rábízhatunk a PontRajzol eljárásra.
Mivel a körív pontjai kielégítik az y2=r2-x2 egyenletet, kapjuk a kézen fekvő megoldást:
Eljárás KörRajzolás(Konstans r:Egész):
Ciklus x=0-tól r-ig
y:=Egész(Négyzetgyök(r*r-x*x))
PontRajzolás(x,y);
PontRajzolás(-x,y)
PontRajzolás(x,-y);
PontRajzolás(-x,-y)
Ciklus vége
Eljárás vége.
Probléma:
Az ív „meredek” érintőjű részén szakadozik.
Ezen a problémán segíthetünk azzal, hogy „egyenletesen” járjuk be a negyed körívet. Nem x-szerint haladunk, hanem origóból azonos (Da) szögelfordulással haladva:
Eljárás
KörRajzolás(Konstans r:Egész):
Változó
Da,a: Valós
Da:=???
Ciklus a=0-tól p/2-ig Da-asával
x:=r*cos(a); y:=r*sin(a)
PontRajzolás(x,y);
PontRajzolás(-x,y)
PontRajzolás(x,-y);
PontRajzolás(-x,-y)
Ciklus vége
Eljárás vége.
Meggondolandó a Da választása! Ha túl kicsire választjuk, akkor sokszor fogja ugyanazt a pontot kiszínezni, ha meg túl nagyra, akkor meg kimaradnak pontok.
Legyen Da-nyi fordulat az r-sugarú íven kb. 1 pixelnyi! Azaz Da /
(2*p)
= 1 / (2*r*p)
Þ Da = 1 / r
Egy, a görbék rajzolására általánosan alkalmazható ötlet:
1. kiindulás a görbe egy alkalmas kezdőpontjából,
2. válasszunk valamilyen elképzelhető haladási (rajzolási) irányt (balra/jobbra és/vagy fel/le),
3. az irányba eső szomszédos (mondjuk: 5) pontokat vizsgáljuk meg: melyik tér el legkevésbé a görbétől [4]. S arra lépjünk tovább! |
Pl.: oo |
A kör esetén megint csak az első negyedbeli ívét használjuk föl „vezérlőként”.
Eljárás KörRajzolás(Konstans r:Egész): x:=0; y:=r;
rr:=r*r |
|
Megjegyzés:
Az világos, hogy az
algoritmusbeli feltételek –sorrendjükkel együtt– feltételezik, hogy a „vezérlő
szerepű” körív-darab éppen az 1. negyedbe eső negyed körív,
sőt, hogy a rajzolás az (0,r)-től
kezdődik. (Ui.: y³0; és elegendő 5 helyett a rajzon jelzett 3
„próbapont”; a „legkevésbé eltérés”-t
helyettesíthetjük a „a körlapba először
belépés”-sel.)
Észre kell vennünk, hogy az
általános algoritmust csak „e-pontossággal” követi a fenti, ui. elképzelhető,
hogy bár a jobbra lépés lenne a legjobb, mi mégis a „jobbra-le” szomszédot
választjuk, mert ő az első még bennmaradó. Ez a hiba azonban a kör „körségét”
nem befolyásolja, az ívtől való elszakadástól nem kell tartanunk. |
|
[1] ami a TurboGrafikában (Graph unit a Turbo/FreePascal-ban): PutPixel(o,s,pontSzín).
[2] Érdemes eljátszadozni a Kerekít függvény helyett Egészrész-szel.
[3] Ha x1£x2.nem lenne feltehető, akkor a ciklus Sgn(x2-x1)-esével szervezzük
[4] Ez egy jó, nem ritkán nehezen megválaszolható kérdés! Gyakran helyettesítik valami hasonló, de könnyebben megválaszolhatóval.