Points | Tview | Tuv | Map | DrawScene | ViewScene | Celotna koda programa
//************************************************************* PROCEDURE Points(tp,tr:TSetOfVectors;nn,ss:TVector;var prebod,OK:boolean); //Dolocitev vseh potrebnih tock Tw[i] za izris scene. //nn, ss, tp in tr so podatki premice oz. ravnine, ki jih podamo. const mreza = 7; //stevilo polj, na katere razdelijo vzporednice ravnino var xp,yp,zp,ld,sd,x,y,z,p,delta : double;//prebod, dolzini vektorjev in pomozne sprem. l,m,n,Ar,Br,Cr,Dr : double; //parametri ravnine in premice, r kot ravnina ll : TVector; //vektor l ssk : array[1..4] of TVector; //vektorji na stranicah kvadrata i : integer; rr : array[1..4] of Tvector; //vektorji za izris kvadrata na ravnini BEGIN //Koordinatni sistem (tocke 10..13) Tw[11].x:=R; Tw[12].y:=R; Tw[13].z:=R;
//Koordinate oznat x, y in z koordinatnega sistema (tocke 38..49) Tw[38].x:=Tw[11].x+R/12; Tw[38].y:=0; Tw[38].z:=Tw[11].z+R/12; Tw[39].x:=Tw[11].x-R/12; Tw[39].y:=0; Tw[39].z:=Tw[11].z-R/12; Tw[40].x:=Tw[11].x+R/12; Tw[40].y:=0; Tw[40].z:=Tw[11].z-R/12; Tw[41].x:=Tw[11].x-R/12; Tw[41].y:=0; Tw[41].z:=Tw[11].z+R/12;
Tw[42].x:=0; Tw[42].y:=Tw[12].y-R/12; Tw[42].z:=Tw[12].z+R/12; Tw[43].x:=0; Tw[43].y:=Tw[12].y; Tw[43].z:=Tw[12].z; Tw[44].x:=0; Tw[44].y:=Tw[12].y-R/12; Tw[44].z:=Tw[12].z-R/12; Tw[45].x:=0; Tw[45].y:=Tw[12].y+R/12; Tw[45].z:=Tw[12].z+R/12;
Tw[46].x:=Tw[13].x+R/24; Tw[46].y:=Tw[13].y-R/24; Tw[46].z:=Tw[13].z+R/12; Tw[47].x:=Tw[13].x-R/24; Tw[47].y:=Tw[13].y+R/24; Tw[47].z:=Tw[13].z+R/12; Tw[48].x:=Tw[13].x+R/24; Tw[48].y:=Tw[13].y-R/24; Tw[48].z:=Tw[13].z; Tw[49].x:=Tw[13].x-R/24; Tw[49].y:=Tw[13].y+R/24; Tw[49].z:=Tw[13].z;
//***Dolocitev parametrov premice in ravnine glede na to, kaj podamo (tocke 5..9) //Premica OK:=False; if PMoznost = 1 then //tocka in smerni vektor begin l:=ss.x; m:=ss.y; n:=ss.z; end else //dve tocki begin l:=tp[2].x-tp[1].x; m:=tp[2].y-tp[1].y; n:=tp[2].z-tp[1].z; end; if (l=0)and(m=0)and(n=0) then begin ShowMessage('Premica ne obstaja'); Exit; end; //Ravnina (tocke 1..4) if RMoznost = 1 then //tocka in normala begin Ar:=nn.x; Br:=nn.y; Cr:=nn.z; Dr:=-Ar*tr[1].x-Br*tr[1].y-Cr*tr[1].z; end else //tri tocke begin Ar:=tr[2].y*tr[3].z-tr[2].y*tr[1].z-tr[1].y*tr[3].z-tr[2].z*tr[3].y+tr[2].z*tr[1].y+tr[1].z*tr[3].y; Br:=-tr[3].x*tr[1].z+tr[1].x*tr[3].z-tr[2].x*tr[3].z+tr[2].x*tr[1].z+tr[3].x*tr[2].z-tr[1].x*tr[2].z; Cr:=-tr[3].x*tr[2].y-tr[1].x*tr[3].y+tr[2].x*tr[3].y-tr[2].x*tr[1].y+tr[1].x*tr[2].y+tr[3].x*tr[1].y; Dr:=-tr[1].x*tr[2].y*tr[3].z+tr[1].x*tr[3].y*tr[2].z-tr[2].x*tr[3].y*tr[1].z+tr[3].x*tr[2].y*tr[1].z+tr[2].x*tr[1].y*tr[3].z-tr[3].x*tr[1].y*tr[2].z; end; //***Prebod ravnine in premice - preveri tudi, ce le-ta sploh obstaja if (Ar*l+Br*m+Cr*n)<>0 then //prebod obstaja begin prebod:=True; p:=(Ar*tp[1].x+Br*tp[1].y+Cr*tp[1].z+Dr)/(Ar*l+Br*m+Cr*n); xp:=tp[1].x-l*p; yp:=tp[1].y-m*p; zp:=tp[1].z-n*p; Tw[7].x:=xp; Tw[7].y:=yp; Tw[7].z:=zp; //prebod end else //preboda ni - ravnina in premica sta vzporedni begin prebod:=False; if (Ar=0) and (Br=0) and (Cr=0) then begin ShowMessage('Ravnina ne obstaja'); Exit; end; delta:=(Ar*tp[1].x+Br*tp[1].y+Cr*tp[1].z+Dr)/(Ar*Ar+Br*Br+Cr*Cr); //razdalja med premico in ravnino Tw[8].x:=abs(delta); //sem noter se zapise razdalja med premico in ravnino xp:=tp[1].x-delta*Ar; //prebod je tokrat le navidezen in lezi na ravnini yp:=tp[1].y-delta*Br; zp:=tp[1].z-delta*Cr; Tw[7]:=tp[1]; //sredisce daljice za izris end; OK:=True; //***Tocke kvadratnega obmocja (kvadrata) na ravnini if Cr<>0 then begin x:=xp+1; y:=yp+1; //dolocitev poljubne tocke na ravnini z:=-(Ar*x+Br*y+Dr)/Cr; end else if Br<>0 then begin x:=xp+1; z:=zp+1; y:=-(Ar*x+Cr*z+Dr)/Br; end else begin y:=yp+1; z:=zp+1; x:=-(Br*y+Cr*z+Dr)/Ar; end; ll.x:=x-xp; //vektor od preboda do poljubne tocke ll.y:=y-yp; ll.z:=z-zp; ld:=sqrt(sqr(ll.x)+sqr(ll.y)+sqr(ll.z)); //prva tocka kvadrata rr[1].x:=R/ld*ll.x; rr[1].y:=R/ld*ll.y; rr[1].z:=R/ld*ll.z; Tw[1].x:=xp+rr[1].x; Tw[1].y:=yp+rr[1].y; Tw[1].z:=zp+rr[1].z; //ostale 3 dolocimo s pomocjo vektorskega produkta predhodnega vektorja in normale //Tako dobimo 4 med sebojno pravokotne vektorje, ki lezijo na ravnini od preboda //do ogljisc kvadrata for i:=1 to 3 do begin ll.x:=Br*rr[i].z-Cr*rr[i].y; ll.y:=Cr*rr[i].x-Ar*rr[i].z; ll.z:=Ar*rr[i].y-Br*rr[i].x; ld:=sqrt(sqr(ll.x)+sqr(ll.y)+sqr(ll.z)); rr[i+1].x:=R/ld*ll.x; rr[i+1].y:=R/ld*ll.y; rr[i+1].z:=R/ld*ll.z; Tw[i+1].x:=xp+rr[i+1].x; Tw[i+1].y:=yp+rr[i+1].y; Tw[i+1].z:=zp+rr[i+1].z; end; //***Dolocitev konca in zacetka premice sd:=sqrt(l*l+m*m+n*n); //dolzina smernega vektorja Tw[5].x:=Tw[7].x+2*R*l/sd; //npr. l/sd je x komponenta ENOTSKEGA smernega vektorja Tw[5].y:=Tw[7].y+2*R*m/sd; Tw[5].z:=Tw[7].z+2*R*n/sd; //pri tem vedno velja, da je s usmerjen proti od T[9] proti T[1] Tw[9].x:=Tw[7].x-2*R*l/sd; Tw[9].y:=Tw[7].y-2*R*m/sd; Tw[9].z:=Tw[7].z-2*R*n/sd; //***Vzporednice na ravnini (tocke 14..37) ssk[4].x:=Tw[4].x-Tw[1].x; ssk[4].y:=Tw[4].y-Tw[1].y; ssk[4].z:=Tw[4].z-Tw[1].z; ssk[3].x:=Tw[3].x-Tw[4].x; ssk[3].y:=Tw[3].y-Tw[4].y; ssk[3].z:=Tw[3].z-Tw[4].z; ssk[2].x:=Tw[3].x-Tw[2].x; ssk[2].y:=Tw[3].y-Tw[2].y; ssk[2].z:=Tw[3].z-Tw[2].z; ssk[1].x:=Tw[2].x-Tw[1].x; ssk[1].y:=Tw[2].y-Tw[1].y; ssk[1].z:=Tw[2].z-Tw[1].z; for i:=14 to 19 do begin Tw[i].x:=Tw[1].x+(i-13)*ssk[1].x/mreza; Tw[i].y:=Tw[1].y+(i-13)*ssk[1].y/mreza; Tw[i].z:=Tw[1].z+(i-13)*ssk[1].z/mreza; end; for i:=20 to 25 do begin Tw[i].x:=Tw[2].x+(i-19)*ssk[2].x/mreza; Tw[i].y:=Tw[2].y+(i-19)*ssk[2].y/mreza; Tw[i].z:=Tw[2].z+(i-19)*ssk[2].z/mreza; end; for i:=26 to 31 do begin Tw[i].x:=Tw[1].x+(i-25)*ssk[4].x/mreza; Tw[i].y:=Tw[1].y+(i-25)*ssk[4].y/mreza; Tw[i].z:=Tw[1].z+(i-25)*ssk[4].z/mreza; end; for i:=32 to 37 do begin Tw[i].x:=Tw[4].x+(i-31)*ssk[3].x/mreza; Tw[i].y:=Tw[4].y+(i-31)*ssk[3].y/mreza; Tw[i].z:=Tw[4].z+(i-31)*ssk[3].z/mreza; end; END;//Points
//************************************************************* PROCEDURE Tview(T:TVector;VRP:TCamera; var Tout:TVector); //Pretvorba iz relnega prostora (world koord.) (Tw) na koordinate //kamere (view koord.) (Tv) - glede na pozicijo kamere //Uporabljen je 4-parametricni sistem var x,y,z : double; BEGIN x:=T.x; y:=T.y; z:=T.z; //View koordinate (koordinate glede na kamero) Tout.x:=-x*sin(VRP.theta)+y*cos(VRP.theta); Tout.y:=-x*cos(VRP.theta)*cos(VRP.fi)-y*sin(VRP.theta)*cos(VRP.fi)+z*sin(VRP.fi); Tout.z:=-x*cos(VRP.theta)*sin(VRP.fi)-y*sin(VRP.theta)*sin(VRP.fi)-z*cos(VRP.fi)+VRP.r; END;//Tview
//************************************************************* PROCEDURE Tuv(T:TVector;VRP:TCamera; var Tout:TVector); //Projekcija na proj. ravnino (u,v) - perspektivna projekcija. BEGIN //Koordinate u,v na projecirni ravnini pri perspektivni projekciji Tout.x:=T.x*VRP.d/T.z; Tout.y:=T.y*VRP.d/T.z; Tout.z:=T.z; END;//Tuv
//************************************************************* PROCEDURE Map(T:TVector; var Tout:TVectorInt); //Pretvori koordinate iz projecirne ravnine (u,v) na zaslonske koordinate, glede na izbrano //okno na projecirni ravnini in viewport na zaslonu BEGIN Tout.x:=Round(T.x*factor+W/2); Tout.y:=Round(H/2-T.y*factor*Ratio); END;//Map
//************************************************************* PROCEDURE DrawScene; //Izris scene - izris premice, kvadrata in koord. sistema, torej celotne scene //na podlagi izracunanih in ustrezno transformiranih tock Tw preko Tv v Ts //Tudi dolocitev vidnih in nevidnih delov premice type TInter = record z : double; vis : boolean; end; var i,ip,k : integer; A,B,C : array[1..4] of double; //parametri nosilk daljic, ki tvorijo ravnino Apr,Bpr,Cpr : double; //parametri premice x,y,D,ad,a59,ap : extended; //presek premice in daljice in pomozna sprem. delta,p5,p9 : integer; zpr,zdal : array[1..2] of TInter; P : array[1..2] of TVector; label done;
Function Num(value:double):double; //Uposteva le 4 decimalna mesta Begin Result:=Int(value)+(Int(Frac(value)*10000))/10000; End;//Num
BEGIN With MainForm.Canvas do begin //Koordinatni sistem Pen.Color:=clYellow; for i:=11 to 13 do begin MoveTo(Ts[10].x,Ts[10].y); LineTo(Ts[i].x,Ts[i].y); end;
//Ravnina Pen.Color:=clBlue; MoveTo(Ts[1].x,Ts[1].y); for i:=2 to 4 do LineTo(Ts[i].x,Ts[i].y); LineTo(Ts[1].x,Ts[1].y);
//*****Premica - vidni in nevidni deli se dolocajo na proj. //ravnini in se sele potem pretvorijo na screen k. s proceduro Map!!! Pen.Color:=clRed; //parametri premice in nosilk daljic kvadrata Apr:=Tproj[5].y-Tproj[9].y; Bpr:=Tproj[9].x-Tproj[5].x; Cpr:=Tproj[9].y*Tproj[5].x-Tproj[5].y*Tproj[9].x; A[4]:=Tproj[1].y-Tproj[4].y; B[4]:=Tproj[4].x-Tproj[1].x; C[4]:=Tproj[4].y*Tproj[1].x-Tproj[1].y*Tproj[4].x; for i:=1 to 3 do begin A[i]:=Tproj[i].y-Tproj[i+1].y; B[i]:=Tproj[i+1].x-Tproj[i].x; C[i]:=Tproj[i+1].y*Tproj[i].x-Tproj[i].y*Tproj[i+1].x; end;
//***Prekrivanja premice in kvadrata - izris premice po odsekih ip:=0; //iracun dveh ali nobenega presekov premice z kvadratom na for i:=1 to 4 do //obmocju kvadrata begin D:=Apr*B[i]-A[i]*Bpr; if D<>0 then //obstaja prekrivanje premice in daljice na proj. ravnini begin x:=(Bpr*C[i]-B[i]*Cpr)/D; //izracun preseka y:=(Cpr*A[i]-C[i]*Apr)/D; if i=4 then k:=4 else k:=0; ad:=sqr(Tproj[i].x -Tproj[i+1-k].x)+sqr(Tproj[i].y -Tproj[i+1-k].y); //razdalja i-te daljice kvadrata if ((sqr(x-Tproj[i].x)+sqr(y-Tproj[i].y))<=ad)and((sqr(x-Tproj[i+1-k].x)+sqr(y-Tproj[i+1-k].y))<=ad) then begin //ce je presek na obmocju kvadrata inc(ip); P[ip].x:=x; P[ip].y:=y; //dolocimo zv koordinati premice in daljice //na mestu prekrivanja, na podlagi cesar se doloci ali je premica nad ali pod ravnino //...najprej zv premice if (Tv[5].z=Tv[9].z) then zpr[ip].z:=Tv[5].z else zpr[ip].z:=(Tv[5].y-Tv[5].z*(Tv[5].y-Tv[9].y)/(Tv[5].z-Tv[9].z))/(y/VRP.d-(Tv[5].y-Tv[9].y)/(Tv[5].z-Tv[9].z)); //...in se zv daljice s katero se premica prekriva if i=4 then k:=4 else k:=0; if (Tv[i].z=Tv[i+1-k].z) then zdal[ip].z:=Tv[i].z else zdal[ip].z:=(Tv[i].y-Tv[i].z*(Tv[i].y-Tv[i+1-k].y)/(Tv[i].z-Tv[i+1-k].z))/(y/VRP.d-(Tv[i].y-Tv[i+1-k].y)/(Tv[i].z-Tv[i+1-k].z)); //dolocanje ali je premica na mestu prekrivanja pod ali nad ravnino if num(zpr[ip].z)<=num(zdal[ip].z) then zpr[ip].vis:=True else zpr[ip].vis:=False; if zpr[ip].z<0 then zpr[ip].vis:=False; //Ce presek ne obstaja v smeri, v kateri gledamo end; end; end; MoveTo(Ts[5].x,Ts[5].y); //premik na Ts5 if ip=0 then //ce ni prekrivanja begin Pen.Style:=psSolid; LineTo(Ts[9].x,Ts[9].y); end else begin //ce prekrivanje je if zpr[1].vis and zpr[2].vis then begin //premica je v celoti nad ravnino Pen.Style:=psSolid; LineTo(Ts[9].x,Ts[9].y); end else begin //premica je v celoti pod ravnino ali pa je prebod a59:=sqr(Tproj[9].x-Tproj[5].x)+sqr(Tproj[9].y-Tproj[5].y); //razdalja premice med 5 in 9 ap:=sqr(P[1].x-P[2].x)+sqr(P[1].y-P[2].y); //razdalja med presekoma if ((sqr(Tproj[5].x-P[1].x)+sqr(Tproj[5].y-P[1].y))<ap)and((sqr(Tproj[5].x-P[2].x)+sqr(Tproj[5].y-P[2].y))<ap) then begin //5 lezi med obema presekoma if ((P[1].x-Tproj[5].x)*(Tproj[9].x-Tproj[5].x)+(P[1].y-Tproj[5].y)*(Tproj[9].y-Tproj[5].y))>=0 then p5:=1 else p5:=2; //presek, ki je v smeri proti 9 if p5=1 then p9:=2 else p9:=1; if not(zpr[p5].vis) then Pen.Style:=psSolid else Pen.Style:=psDot; if not(zpr[p5].vis) and not(zpr[p9].vis) then Pen.Style:=psDot; Map(P[p5],Ts[6]); if (sqr(P[p5].x-Tproj[5].x)+sqr(P[p5].y-Tproj[5].y))<a59 then begin //9 je zunaj kvadrata if not(zpr[p5].vis) then begin if not(zpr[p9].vis) then LineTo(Ts[6].x,Ts[6].y) else LineTo(Ts[7].x,Ts[7].y); Pen.Style:=psSolid; LineTo(Ts[9].x,Ts[9].y); end else begin LineTo(Ts[7].x,Ts[7].y); Pen.Style:=psSolid; LineTo(Ts[9].x,Ts[9].y); end; end else //tudi 9 je znotraj kvadrata begin LineTo(Ts[7].x,Ts[7].y); if not(zpr[p5].vis) then begin Pen.Style:=psDot; LineTo(Ts[9].x,Ts[9].y); end else Pen.Style:=psSolid; LineTo(Ts[9].x,Ts[9].y); begin end; end; end else begin //5 lezi zunaj presekov if (sqr(P[1].x-Tproj[5].x)+sqr(P[1].y-Tproj[5].y))<(sqr(P[2].x-Tproj[5].x)+sqr(P[2].y-Tproj[5].y)) then begin //doloci presek najblizje 5 p5:=1; p9:=2 end else begin p5:=2; p9:=1; end; Pen.Style:=psSolid; if ((sqr(P[p5].x-Tproj[5].x)+sqr(P[p5].y-Tproj[5].y))>=a59)or (((Tproj[9].x-Tproj[5].x)*(P[p5].x-Tproj[5].x)+(Tproj[9].y-Tproj[5].y)*(P[p5].y-Tproj[5].y))<0) then begin //ce daljica 5-9 ne prekriva kvadrata LineTo(Ts[9].x,Ts[9].y); end else begin if ((sqr(Tproj[9].x-P[1].x)+sqr(Tproj[9].y-P[1].y))<=ap)and((sqr(Tproj[9].x-P[2].x)+sqr(Tproj[9].y-P[2].y))<=ap) then begin //ce 9 lezi med obema presekoma Map(P[p5],Ts[6]); LineTo(Ts[6].x,Ts[6].y); if not(zpr[p5].vis) then Pen.Style:=psDot else Pen.Style:=psSolid; if not(zpr[p5].vis) and not(zpr[p9].vis) then Pen.Style:=psDot; if not(zpr[p5].vis) then begin if not(zpr[p9].vis) then begin Pen.Style:=psDot; LineTo(Ts[9].x,Ts[9].y); end else begin LineTo(Ts[7].x,Ts[7].y); Pen.Style:=psSolid; LineTo(Ts[9].x,Ts[9].y); end; end else begin LineTo(Ts[7].x,Ts[7].y); Pen.Style:=psDot; LineTo(Ts[9].x,Ts[9].y); end; end else //in ce je tudi 9 zunaj presekov begin Map(P[p5],Ts[6]); LineTo(Ts[6].x,Ts[6].y); if not(zpr[p5].vis) then Pen.Style:=psDot else Pen.Style:=psSolid; LineTo(Ts[7].x,Ts[7].y); Map(P[p9],Ts[6]); if not(zpr[p5].vis) and zpr[p9].vis then begin Pen.Style:=psSolid; LineTo(Ts[9].x,Ts[9].y); end else begin Pen.Style:=psDot; LineTo(Ts[6].x,Ts[6].y); Pen.Style:=psSolid; LineTo(Ts[9].x,Ts[9].y); end; end; end; end; end; end; done:
//Prebod if prebod then begin delta:=Round(R/50*VRP.d/VRP.r*factor); Pen.Style:=psSolid; Pen.Color:=clLime; Brush.Color:=clLime; Ellipse(Ts[7].x-delta,Ts[7].y+delta,Ts[7].x+delta,Ts[7].y-delta); Brush.Color:=clBlack; //nazaj na crno, da ne zapolni crtkane crte z zeleno end;
//Vzporednice na ravnini Pen.Style:=psSolid; Pen.Color:=clBlue; for i:=14 to 19 do begin MoveTo(Ts[i].x,Ts[i].y); LineTo(Ts[i+18].x,Ts[i+18].y); end; for i:=20 to 25 do begin MoveTo(Ts[i].x,Ts[i].y); LineTo(Ts[i+6].x,Ts[i+6].y); end;
//Oznake koordinatnega sistema Pen.Color:=clLime; i:=38; while i<=49 do begin MoveTo(Ts[i].x,Ts[i].y); LineTo(Ts[i+1].x,Ts[i+1].y); i:=i+2; end; MoveTo(Ts[47].x,Ts[47].y); LineTo(Ts[48].x,Ts[48].y); end; END;//DrawScene
//************************************************************* PROCEDURE ViewScene(VRP:TCamera); //Pogled scene na zaslonu var i : integer; BEGIN //Pretvorba vseh tock scene na na k. sistem kamere for i:=1 to 49 do Tview(Tw[i],VRP,Tv[i]); //Projeciranje vseh tock scene na projecirno ravnino, ki je oddaljena za d od kamere for i:=1 to 49 do Tuv(Tv[i],VRP,Tproj[i]); //Pretvorba koordinat iz okna view window v viewport na zaslonu(mapping) for i:=1 to 49 do Map(Tproj[i],Ts[i]); //Izris objektov (k. sistem, ravnina in premica) DrawScene; END;//ViewScene