A BB4W Compendium

freeman69@gmx.com

IDIC

Object Axes

So far, we've rotated templates of objects around the fixed (Z, X, Y) axes of our 'universe' to orient the objects however we wish. However, there are occasions when we want to rotate an object about its own axes e.g. a plane in flight can roll, pitch and yaw relative to its current orientation.

One solution to this problem is to use vectors:

Once the relevant local axes ('alignment vectors') have been transformed by the rotation vectors, we use the positive z & y alignment vectors to determine the correct angles of rotation (about the fixed Z, X, Y axes) to achieve this new orientation.

I.e. We drag the alignment vectors into a new position, mimicking the act of rotation, and then work out the z, x & y angles needed to rotate the template into the same orientation.

The following program demonstrates this process. Use the mouse to click on the '< >' arrows to rotate the object about its local axes.

10 MODE 9:OFF

20 ORIGIN 640,512

30 *REFRESH OFF

40 DIM nd{(17) xt,yt,zt,xr,yr,zr,x2,y2}:REM Nodes

60 DIM td{(1) np,lp,nc,lc}:REM Net pointers

70 FOR a=0 TO 17

90 NEXT

100 FOR a=0 TO 17

120 NEXT

130 FOR a=0 TO 0

150 NEXT

160 REM Create a unit vector pointing towards a light source

170 lightx=100:lighty=100:lightz=10

180 lm=SQR(lightx^2+lighty^2+lightz^2)

190 lightx/=lm:lighty/=lm:lightz/=lm

200

210 za=0:xa=0:ya=0:REM Object orientation

220

230 REPEAT

240   TIME=0:CLS

250   PRINTTAB(0,0);"Object's Z-axis: < >"

260   PRINTTAB(0,1);"Object's X-axis: < >"

270   PRINTTAB(0,2);"Object's Y-axis: < >"

280

290   MOUSE mx,my,mz

300   mx DIV=32:my DIV=32:dir\$=""

310   IF mx=-2 dir\$="A"

320   IF mx=0 dir\$="C"

330   IF dir\$<>"" AND my>=13 AND my<=15 THEN

340     GCOL 3,4:RECTANGLEFILL mx*32,my*32,-32,32

350     IF mz<>0 THEN

360       CASE my OF

370         WHEN 13 : PROCflybywire("Y",2,dir\$,za,xa,ya)

380         WHEN 14 : PROCflybywire("X",2,dir\$,za,xa,ya)

390         WHEN 15 : PROCflybywire("Z",2,dir\$,za,xa,ya)

400       ENDCASE

410     ENDIF

420   ENDIF

430

440   PROCdraw(0,0,0,-40,za,xa,ya)

450   *REFRESH

460   WAIT 4-TIME

470 UNTIL FALSE

480 END

490

500 DEF PROCflybywire(ax\$,angle,dir\$,RETURN za,RETURN xa,RETURN ya)

510 LOCAL f,a,ca,sa,x,y,z

530 FOR a=0 TO 4:PROCrotzxy(a,0,0,0,za,xa,ya):NEXT

540 CASE ax\$ OF

550   WHEN "Z"

560     IF dir\$="C" THEN

570       nd{(1)}.xr+=f*(nd{(3)}.xr-nd{(1)}.xr)

580       nd{(1)}.yr+=f*(nd{(3)}.yr-nd{(1)}.yr)

590       nd{(1)}.zr+=f*(nd{(3)}.zr-nd{(1)}.zr)

600     ELSE

610       nd{(1)}.xr+=f*(nd{(4)}.xr-nd{(1)}.xr)

620       nd{(1)}.yr+=f*(nd{(4)}.yr-nd{(1)}.yr)

630       nd{(1)}.zr+=f*(nd{(4)}.zr-nd{(1)}.zr)

640     ENDIF

650   WHEN "X"

660     IF dir\$="C" THEN

670       nd{(0)}.xr+=f*(nd{(1)}.xr-nd{(0)}.xr)

680       nd{(0)}.yr+=f*(nd{(1)}.yr-nd{(0)}.yr)

690       nd{(0)}.zr+=f*(nd{(1)}.zr-nd{(0)}.zr)

700     ELSE

710       nd{(0)}.xr+=f*(nd{(2)}.xr-nd{(0)}.xr)

720       nd{(0)}.yr+=f*(nd{(2)}.yr-nd{(0)}.yr)

730       nd{(0)}.zr+=f*(nd{(2)}.zr-nd{(0)}.zr)

740     ENDIF

750   WHEN "Y"

760     IF dir\$="C" THEN

770       nd{(0)}.xr+=f*(nd{(4)}.xr-nd{(0)}.xr)

780       nd{(0)}.yr+=f*(nd{(4)}.yr-nd{(0)}.yr)

790       nd{(0)}.zr+=f*(nd{(4)}.zr-nd{(0)}.zr)

800     ELSE

810       nd{(0)}.xr+=f*(nd{(3)}.xr-nd{(0)}.xr)

820       nd{(0)}.yr+=f*(nd{(3)}.yr-nd{(0)}.yr)

830       nd{(0)}.zr+=f*(nd{(3)}.zr-nd{(0)}.zr)

840     ENDIF

850 ENDCASE

860 ya=FNgetbearing(nd{(0)}.xr,nd{(0)}.zr)

870 REM Unwind 2 main alignment vectors about y-axis

890 z=nd{(0)}.zr*ca+nd{(0)}.xr*sa

900 x=nd{(0)}.xr*ca-nd{(0)}.zr*sa

910 nd{(0)}.zr=z

920 nd{(0)}.xr=x

930 z=nd{(1)}.zr*ca+nd{(1)}.xr*sa

940 x=nd{(1)}.xr*ca-nd{(1)}.zr*sa

950 nd{(1)}.zr=z

960 nd{(1)}.xr=x

970 xa=FNgetbearing(nd{(0)}.yr,nd{(0)}.zr)

980 REM Unwind vertical alignment vectors about x-axis

1000 y=nd{(1)}.yr*ca+nd{(1)}.zr*sa

1010 z=nd{(1)}.zr*ca-nd{(1)}.yr*sa

1020 nd{(1)}.yr=y

1030 nd{(1)}.zr=z

1040 za=FNgetbearing(nd{(1)}.xr,nd{(1)}.yr)

1050 IF ya<>0 ya=360-ya

1060 ENDPROC

1070

1080 DEF FNgetbearing(x,y)

1090 LOCAL a,h

1100 a=0:h=SQR(x*x+y*y)

1110 IF h>0 THEN

1120   IF ABS(x)<ABS(y) THEN

1130     a=DEG(ACS(y/h))

1140   ELSE

1150     a=90-DEG(ACS(ABS(x)/h)):IF y<0 AND a<>180 a=180-a

1160   ENDIF

1170   IF x<0 AND a<>0 a=360-a

1180 ENDIF

1190 =a

1200

1210 DEF PROCdraw(net,x,y,z,za,xa,ya)

1220 LOCAL f,abort,col,a,n1,n2,n3,v1x,v1y,v1z,v2x,v2y,v2z,nx,ny,nz,nm,v

1230 f=1280:abort=FALSE:col=7:GCOL 0,15

1240 FOR a=td{(net)}.np TO td{(net)}.np+td{(net)}.nc-1

1250   PROCrotzxy(a,x,y,z,za,xa,ya):REM Rotate node & add offset

1260   IF nd{(a)}.zr>-1 THEN

1270     abort=TRUE:REM Node behind viewer

1280   ELSE

1290     nd{(a)}.x2=f*nd{(a)}.xr/-nd{(a)}.zr:REM 3D to 2D

1300     nd{(a)}.y2=f*nd{(a)}.yr/-nd{(a)}.zr

1310   ENDIF

1320 NEXT

1330 IF abort ENDPROC

1340 FOR a=td{(net)}.lp TO td{(net)}.lp+td{(net)}.lc-1

1370     WHEN 7

1410       REM Calc two vectors from 3 co-ords (triangle): b-a and c-a

1420       v1x=nd{(n2)}.xr-nd{(n1)}.xr

1430       v1y=nd{(n2)}.yr-nd{(n1)}.yr

1440       v1z=nd{(n2)}.zr-nd{(n1)}.zr

1450       v2x=nd{(n3)}.xr-nd{(n1)}.xr

1460       v2y=nd{(n3)}.yr-nd{(n1)}.yr

1470       v2z=nd{(n3)}.zr-nd{(n1)}.zr

1480       REM Find the 'normal' of a triangle, (cross product of two vectors)

1490       nx=v1y*v2z-v1z*v2y

1500       ny=v1z*v2x-v1x*v2z

1510       nz=v1x*v2y-v1y*v2x

1520       REM Vector towards viewer

1530       v1x=0-nd{(n1)}.xr

1540       v1y=0-nd{(n1)}.yr

1550       v1z=0-nd{(n1)}.zr

1560       REM Triangle faces viewer (normal points towards viewer)?

1570       IF (nx*v1x+ny*v1y+nz*v1z)>0 THEN

1580         nm=SQR(nx^2+ny^2+nz^2)

1590         REM Calc triangle shade from: A.B / |A||B|

1600         v=(nx*lightx+ny*lighty+nz*lightz)/nm

1610         IF v<-1 v=0 ELSE IF v>1 v=255 ELSE v=255-ACS(v)/PI*255

1620         COLOUR 15,v*(col AND 1),v*((col AND 2)/2),v*((col AND 4)/4)

1630         MOVE nd{(n1)}.x2,nd{(n1)}.y2

1640         MOVE nd{(n2)}.x2,nd{(n2)}.y2

1650         PLOT 85,nd{(n3)}.x2,nd{(n3)}.y2

1660       ENDIF

1670   ENDCASE

1680 NEXT

1690 ENDPROC

1700

1710 REM Rotate a node about 3 axes and add any offset

1720 DEF PROCrotzxy(n,x,y,z,za,xa,ya)

1730 LOCAL ca,sa,x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4

1740 x1=nd{(n)}.xt:y1=nd{(n)}.yt:z1=nd{(n)}.zt

1780 nd{(n)}.xr=x4+x:nd{(n)}.yr=y4+y:nd{(n)}.zr=z4+z

1790 ENDPROC

1800

1810 REM Alignment vectors

1820 DATA 0,0,1,0,1,0,0,-1,0,1,0,0,-1,0,0

1830 REM Ship nodes (x,y,z)

1840 DATA 0,4,-8,0,-4,-8,8,0,-4,-8,0,-4,0,0,8,6,4,-8

1850 DATA 6,-4,-8,-6,-4,-8,-6,4,-8,8,0,8,-8,0,8,8,0,-8,-8,0,-8

1860 REM Ship links (type,n1,n2,n3: type 1=colour, 7=triangle)

1870 DATA 1,1,0,0,7,7,12,10,7,12,8,10,7,11,6,9,7,9,5,11,1,7,0,0

1880 DATA 7,0,4,2,7,0,3,4,1,6,0,0,7,4,3,1,7,1,2,4,7,2,1,0,7,1,3,0

1890 DATA 1,1,0,0,7,7,10,12,7,12,10,8,7,9,6,11,7,9,11,5

1900 REM Net pointers

1910 DATA 5,0,13,18