{ Updated EGAVGA.SWG on May 26, 1995 } { From: ss8913@u.cc.utah.edu (Scott Stone) Well, here it is. A version of the unit that should calculate stuff properly. :) Also, it uses DOUBLE precision instead of REAL. If it won't work on your system (should, with the coprocessor-emulation directive in there), then just change all the DOUBLEs back to REALs. } Unit Graph3d; {Version 0.02 1/12/95} {Written 1/7/95 by Scott Stone I wrote this because nobody is willing to help a newbie who lacks this info, so go ahead and use it freely - I wouldn't mind a mention in your credits, however! } {Keep in mind, all procedures that require inputs of an angular measurement require the measurement in DEGREES, due to the cosine/sine tables involved} {This version uses DOUBLE precision, hence the new compiler directive. It also fixes the bug that prevents the previous version from working.} Interface {$N+} Var sint,cost : array [0..359] of double; function rd(radians : double) : double; function dr(degrees : double) : double; procedure maketables; Procedure Rotatexy(ra : integer; ox,oy : double; var nx,ny : double); Procedure Rotatexyz(rx,ry,rz : integer; ox,oy,oz : double; var nx,ny,nz : double); Procedure Rotate3X(rx : integer; ox,oy,oz : double; var nx,ny,nz : double); Procedure Rotate3Y(ry : integer; ox,oy,oz : double; var nx,ny,nz : double); Procedure Rotate3Z(rz : integer; ox,oy,oz : double; var nx,ny,nz : double); Procedure C32(ox,oy,oz : double; ep : integer; var nx,ny : integer); function arccos(ca : double) : double; Function A2V(i1,j1,k1,i2,j2,k2 : double) : double; Implementation Function RD (radians : double) : double; {Converts Radians ==>> Degrees} Begin rd:=((180*radians)/pi); End; Function DR (degrees : double) : double; {Converts Degrees =>> Radians} Begin dr:=abs(degrees)*pi/180.0; End; Procedure MakeTables; {Makes Sine/Cosine tables for faster lookups} Var cc : integer; Begin {Defines SINT & COST - used in terms of degrees} for cc:=0 to 359 do begin sint[cc]:=sin(dr(cc)); cost[cc]:=cos(dr(cc)) end; end; Procedure Rotatexy(ra : integer; ox,oy : double; var nx,ny : double); {Rotate a 2-D point about the origin - positive degrees are COUNTERclockwise} {RA=amount to rotate, in degrees. ox,oy = old X,Y. nx,ny = new X,Y} Begin nx:=(ox*(cost[ra]))-(oy*(sint[ra])); ny:=(ox*(sint[ra]))+(oy*(cost[ra])); End; Procedure Rotatexyz(rx,ry,rz : integer; ox,oy,oz : double; var nx,ny,nz : double); {Rotate a 3-D point. rx,ry,rz=amount to rotate about each axis.} {ox,oy,oz = old x,y,z. nx,ny,nz=new x,y,z} Var tx,ty,tz : double; tx1,ty1,tz1 : double; Begin {first rotate about X-axis} tx:=ox; ty:=(oy*(cost[rx]))-(oz*(sint[rx])); tz:=(oy*(sint[rx]))+(oz*(cost[rx])); {now about the Y-axis} tx1:=(tx*(cost[ry]))+(tz*(sint[ry])); ty1:=ty; tz1:=-(tx*(sint[ry]))+(tz*(cost[ry])); {now about the Z-axis} nx:=(tx1*(cost[rz]))-(ty1*(sint[rz])); ny:=(tx1*(sint[rz]))+(ty1*(cost[rz])); nz:=tz1; End; Procedure Rotate3X(rx : integer; ox,oy,oz : double; var nx,ny,nz : double); {Just rotate a 3-D point around X-axis - separates might be faster} Begin if (rx<>0) then {don't do if rx=0 - might save some speed in some cases} begin nx:=ox; ny:=(oy*(cost[rx]))-(oz*(sint[rx])); nz:=(oy*(sint[rx]))+(oz*(cost[rx])) end; End; Procedure Rotate3Y(ry : integer; ox,oy,oz : double; var nx,ny,nz : double); Begin if (ry<>0) then begin nx:=(ox*(cost[ry]))+(oz*(sint[ry])); ny:=oy; nz:=-(ox*(sint[ry]))+(oz*(cost[ry])) end; end; Procedure Rotate3Z(rz : integer; ox,oy,oz : double; var nx,ny,nz : double); Begin if (rz<>0) then begin nx:=(ox*(cost[rz]))-(oy*(sint[rz])); ny:=(ox*(sint[rz]))+(oy*(cost[rz])); nz:=oz end; End; Procedure C32(ox,oy,oz : double; ep : integer; var nx,ny : integer); {Converts 3-D point to 2-D point} {EP = Expansion Factor - useful for 3-D starfields - set to 1 for doubleism} Begin nx:=round((ox*ep)/oz); ny:=round((oy*ep)/oz); {have to round to integers for screen} End; {* Note - Make sure you clip your screen points to fit screen res} function arccos(ca : double) : double; {While compiling this unit, TP7 said that there was no predefined ARCCOS function. There is a pre-defined ARCTAN function, so this procedure finds the ARCCOS in terms of the ARCTAN. This was the hardest part about writing this unit. Isn't math cool? :) BTW - if this doesn't work, let me know. Better yet, let me know and tell me why it doesn't work. } var r,r0,r1 : double; begin r:=sqrt(1-(abs(sqr(ca)))); r0:=r/ca; r1:=arctan(r0); arccos:=r1; end; Function A2V(i1,j1,k1,i2,j2,k2 : double) : double; {Finds angle between two vectors - parameters are vector components} Var theta : double; vm1,vm2 : double; dp : double; ff : double; Begin vm1:=sqrt(abs(sqr(i1))+abs(sqr(j1))+abs(sqr(k1))); vm2:=sqrt(abs(sqr(i2))+abs(sqr(j2))+abs(sqr(k2))); dp:=(i1*i2)+(j1*j2)+(k1*k2); ff:=(dp/(vm1*vm2)); theta:=arccos(ff); a2v:=theta; End; Begin End.