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