t3dlib4.cpp
上传用户:husern
上传日期:2018-01-20
资源大小:42486k
文件大小:62k
源码类别:

游戏

开发平台:

Visual C++

  1. // T3DLIB4.CPP - Game Engine Part IV, Basic Math Engine Part I
  2.  
  3. // INCLUDES ///////////////////////////////////////////////////
  4. #define WIN32_LEAN_AND_MEAN  
  5. //#ifndef INITGUID
  6. //#define INITGUID       // you need this or DXGUID.LIB
  7. //#endif
  8. #include <windows.h>   // include important windows stuff
  9. #include <windowsx.h> 
  10. #include <mmsystem.h>
  11. #include <objbase.h>
  12. #include <iostream.h> // include important C/C++ stuff
  13. #include <conio.h>
  14. #include <stdlib.h>
  15. #include <malloc.h>
  16. #include <memory.h>
  17. #include <string.h>
  18. #include <stdarg.h>
  19. #include <stdio.h>
  20. #include <math.h>
  21. #include <io.h>
  22. #include <fcntl.h>
  23. #include <direct.h>
  24. #include <wchar.h>
  25. #include <ddraw.h>      // needed for defs in T3DLIB1.H 
  26. #include "T3DLIB1.H"    // T3DLIB4 is based on some defs in this 
  27. #include "T3DLIB4.H"
  28. // DEFINES ////////////////////////////////////////////////
  29. // TYPES //////////////////////////////////////////////////
  30. // PROTOTYPES /////////////////////////////////////////////
  31. // EXTERNALS /////////////////////////////////////////////
  32. extern HWND main_window_handle;     // access to main window handle in main module
  33. // GLOBALS ////////////////////////////////////////////////
  34. // FUNCTIONS //////////////////////////////////////////////
  35. FIXP16 FIXP16_MUL(FIXP16 fp1, FIXP16 fp2)
  36. {
  37. // this function computes the product fp_prod = fp1*fp2
  38. // using 64 bit math, so as not to loose precission
  39. FIXP16 fp_prod; // return the product
  40. _asm {
  41.      mov eax, fp1      // move into eax fp2
  42.      imul fp2          // multiply fp1*fp2
  43.      shrd eax, edx, 16 // result is in 32:32 format 
  44.                        // residing at edx:eax
  45.                        // shift it into eax alone 16:16
  46.      // result is sitting in eax
  47.      } // end asm
  48. } // end FIXP16_MUL
  49. ///////////////////////////////////////////////////////////////
  50. FIXP16 FIXP16_DIV(FIXP16 fp1, FIXP16 fp2)
  51. {
  52. // this function computes the quotient fp1/fp2 using
  53. // 64 bit math, so as not to loose precision
  54. _asm {
  55.      mov eax, fp1      // move dividend into eax
  56.      cdq               // sign extend it to edx:eax
  57.      shld edx, eax, 16 // now shift 16:16 into position in edx
  58.      sal eax, 16       // and shift eax into position since the
  59.                        // shld didn't move it -- DUMB! uPC
  60.      idiv fp2          // do the divide
  61.      // result is sitting in eax     
  62.      } // end asm
  63. } // end FIXP16_DIV
  64. ///////////////////////////////////////////////////////////////
  65. void FIXP16_Print(FIXP16 fp)
  66. {
  67. // this function prints out a fixed point number
  68. Write_Error("nfp=%f", (float)(fp)/FIXP16_MAG);
  69. } // end FIXP16_Print
  70. ///////////////////////////////////////////////////////////////
  71. void QUAT_Add(QUAT_PTR q1, QUAT_PTR q2, QUAT_PTR qsum)
  72. {
  73. // this function adds two quaternions
  74. qsum->x = q1->x + q2->x;
  75. qsum->y = q1->y + q2->y;
  76. qsum->z = q1->z + q2->z;
  77. qsum->w = q1->w + q2->w;
  78. } // end QUAT_Add
  79. ///////////////////////////////////////////////////////////////
  80.  void QUAT_Sub(QUAT_PTR q1, QUAT_PTR q2, QUAT_PTR qdiff)
  81. {
  82. // this function subtracts two quaternions, q1-q2
  83. qdiff->x = q1->x - q2->x;
  84. qdiff->y = q1->y - q2->y;
  85. qdiff->z = q1->z - q2->z;
  86. qdiff->w = q1->w - q2->w;
  87. } // end QUAT_Sub
  88. ///////////////////////////////////////////////////////////////
  89. void QUAT_Conjugate(QUAT_PTR q, QUAT_PTR qconj)
  90. {
  91. // this function computes the conjugate of a quaternion
  92. qconj->x = -q->x;
  93. qconj->y = -q->y;
  94. qconj->z = -q->z;
  95. qconj->w = q->w;
  96. } // end QUAT_Conjugate
  97. ///////////////////////////////////////////////////////////////
  98. void QUAT_Scale(QUAT_PTR q, float scale, QUAT_PTR qs)
  99. {
  100. // this function scales a quaternion and returns it 
  101. qs->x = scale*q->x;
  102. qs->y = scale*q->y;
  103. qs->z = scale*q->z;
  104. qs->w = scale*q->w;
  105. } // end QUAT_Scale
  106. ///////////////////////////////////////////////////////////////
  107. void QUAT_Scale(QUAT_PTR q, float scale)
  108. {
  109. // this function scales a quaternion in place
  110. q->x*=scale;
  111. q->y*=scale;
  112. q->z*=scale;
  113. q->w*=scale;
  114. } // end QUAT_Scale
  115. //////////////////////////////////////////////////////////////
  116. float QUAT_Norm(QUAT_PTR q)
  117. {
  118. // returns the length or norm of a quaterion
  119. return(sqrtf(q->w*q->w + q->x*q->x + q->y*q->y + q->z*q->z));
  120. } // end QUAT_Norm
  121. //////////////////////////////////////////////////////////////
  122. float QUAT_Norm2(QUAT_PTR q)
  123. {
  124. // returns the length or norm of a quaterion squared
  125. return(q->w*q->w + q->x*q->x + q->y*q->y + q->z*q->z);
  126. } // end QUAT_Norm2
  127. /////////////////////////////////////////////////////////////
  128. void QUAT_Normalize(QUAT_PTR q, QUAT_PTR qn)
  129. {
  130. // this functions normalizes the sent quaternion and 
  131. // returns it
  132. // compute 1/length
  133. float qlength_inv = 1.0/(sqrtf(q->w*q->w + q->x*q->x + q->y*q->y + q->z*q->z));
  134. // now normalize
  135. qn->w=q->w*qlength_inv;
  136. qn->x=q->x*qlength_inv;
  137. qn->y=q->y*qlength_inv;
  138. qn->z=q->z*qlength_inv;
  139. } // end QUAT_Normalize
  140. /////////////////////////////////////////////////////////////
  141. void QUAT_Normalize(QUAT_PTR q)
  142. {
  143. // this functions normalizes the sent quaternion in place
  144. // compute length
  145. float qlength_inv = 1.0/(sqrtf(q->w*q->w + q->x*q->x + q->y*q->y + q->z*q->z));
  146. // now normalize
  147. q->w*=qlength_inv;
  148. q->x*=qlength_inv;
  149. q->y*=qlength_inv;
  150. q->z*=qlength_inv;
  151. } // end QUAT_Normalize
  152. //////////////////////////////////////////////////////////////
  153. void QUAT_Unit_Inverse(QUAT_PTR q, QUAT_PTR qi)
  154. {
  155. // this function computes the inverse of a unit quaternion
  156. // and returns the result
  157. // the inverse of a unit quaternion is the conjugate :)
  158. qi->w =  q->w;
  159. qi->x = -q->x;
  160. qi->y = -q->y;
  161. qi->z = -q->z;
  162. } // end QUAT_Unit_Inverse
  163. //////////////////////////////////////////////////////////////
  164. void QUAT_Unit_Inverse(QUAT_PTR q)
  165. {
  166. // this function computes the inverse of a unit quaternion
  167. // in place
  168. // the inverse of a unit quaternion is the conjugate :)
  169. q->x = -q->x;
  170. q->y = -q->y;
  171. q->z = -q->z;
  172. } // end QUAT_Unit_Inverse
  173. /////////////////////////////////////////////////////////////
  174. void QUAT_Inverse(QUAT_PTR q, QUAT_PTR qi)
  175. {
  176. // this function computes the inverse of a general quaternion
  177. // and returns result
  178. // in general, q-1 = *q/|q|2
  179. // compute norm squared
  180. float norm2_inv = 1.0/(q->w*q->w + q->x*q->x + q->y*q->y + q->z*q->z);
  181. // and plug in
  182. qi->w =  q->w*norm2_inv;
  183. qi->x = -q->x*norm2_inv;
  184. qi->y = -q->y*norm2_inv;
  185. qi->z = -q->z*norm2_inv;
  186. } // end QUAT_Inverse
  187. /////////////////////////////////////////////////////////////
  188. void QUAT_Inverse(QUAT_PTR q)
  189. {
  190. // this function computes the inverse of a general quaternion
  191. // in place
  192. // in general, q-1 = *q/|q|2
  193. // compute norm squared
  194. float norm2_inv = 1.0/(q->w*q->w + q->x*q->x + q->y*q->y + q->z*q->z);
  195. // and plug in
  196. q->w =  q->w*norm2_inv;
  197. q->x = -q->x*norm2_inv;
  198. q->y = -q->y*norm2_inv;
  199. q->z = -q->z*norm2_inv;
  200. } // end QUAT_Inverse
  201. /////////////////////////////////////////////////////////////
  202. void QUAT_Mul(QUAT_PTR q1, QUAT_PTR q2, QUAT_PTR qprod)
  203. {
  204. // this function multiplies two quaternions
  205. // this is the brute force method
  206. //qprod->w = q1->w*q2->w - q1->x*q2->x - q1->y*q2->y - q1->z*q2->z;
  207. //qprod->x = q1->w*q2->x + q1->x*q2->w + q1->y*q2->z - q1->z*q2->y;
  208. //qprod->y = q1->w*q2->y - q1->x*q2->z + q1->y*q2->w - q1->z*q2->x;
  209. //qprod->z = q1->w*q2->z + q1->x*q2->y - q1->y*q2->x + q1->z*q2->w;
  210. // this method was arrived at basically by trying to factor the above
  211. // expression to reduce the # of multiplies
  212. float prd_0 = (q1->z - q1->y) * (q2->y - q2->z);
  213. float prd_1 = (q1->w + q1->x) * (q2->w + q2->x);
  214. float prd_2 = (q1->w - q1->x) * (q2->y + q2->z);
  215. float prd_3 = (q1->y + q1->z) * (q2->w - q2->x);
  216. float prd_4 = (q1->z - q1->x) * (q2->x - q2->y);
  217. float prd_5 = (q1->z + q1->x) * (q2->x + q2->y);
  218. float prd_6 = (q1->w + q1->y) * (q2->w - q2->z);
  219. float prd_7 = (q1->w - q1->y) * (q2->w + q2->z);
  220. float prd_8 = prd_5 + prd_6 + prd_7;
  221. float prd_9 = 0.5 * (prd_4 + prd_8);
  222. // and finally build up the result with the temporary products
  223. qprod->w = prd_0 + prd_9 - prd_5;
  224. qprod->x = prd_1 + prd_9 - prd_8;
  225. qprod->y = prd_2 + prd_9 - prd_7;
  226. qprod->z = prd_3 + prd_9 - prd_6;
  227. } // end QUAT_Mul
  228. ///////////////////////////////////////////////////////////
  229. void QUAT_Triple_Product(QUAT_PTR q1, QUAT_PTR q2, QUAT_PTR q3, 
  230.                          QUAT_PTR qprod)
  231. {
  232. // this function computes q1*q2*q3 in that order and returns 
  233. // the results in qprod
  234. QUAT qtmp;
  235. QUAT_Mul(q1,q2,&qtmp);
  236. QUAT_Mul(&qtmp, q3, qprod);
  237. } // end QUAT_Triple_Product
  238. ///////////////////////////////////////////////////////////
  239. void VECTOR3D_Theta_To_QUAT(QUAT_PTR q, VECTOR3D_PTR v, float theta)
  240. {
  241. // initializes a quaternion based on a 3d direction vector and angle
  242. // note the direction vector must be a unit vector
  243. // and the angle is in rads
  244. float theta_div_2 = (0.5)*theta; // compute theta/2
  245. // compute the quaterion, note this is from chapter 4
  246. // pre-compute to save time
  247. float sinf_theta = sinf(theta_div_2);
  248. q->x = sinf_theta * v->x;
  249. q->y = sinf_theta * v->y;
  250. q->z = sinf_theta * v->z;
  251. q->w = cosf( theta_div_2 );
  252. } // end VECTOR3D_Theta_To_QUAT
  253. ///////////////////////////////////////////////////////////////
  254.  void VECTOR4D_Theta_To_QUAT(QUAT_PTR q, VECTOR4D_PTR v, float theta)
  255. {
  256. // initializes a quaternion based on a 4d direction vector and angle
  257. // note the direction vector must be a unit vector
  258. // and the angle is in rads
  259. float theta_div_2 = (0.5)*theta; // compute theta/2
  260. // compute the quaterion, note this is from chapter 4
  261. // pre-compute to save time
  262. float sinf_theta = sinf(theta_div_2);
  263. q->x = sinf_theta * v->x;
  264. q->y = sinf_theta * v->y;
  265. q->z = sinf_theta * v->z;
  266. q->w = cosf( theta_div_2 );
  267. } // end VECTOR4D_Theta_to_QUAT
  268. ///////////////////////////////////////////////////////////////
  269. void EulerZYX_To_QUAT(QUAT_PTR q, float theta_z, float theta_y, float theta_x)
  270. {
  271. // this function intializes a quaternion based on the zyx
  272. // multiplication order of the angles that are parallel to the
  273. // zyx axis respectively, note there are 11 other possibilities
  274. // this is just one, later we may make a general version of the
  275. // the function
  276. // precompute values
  277. float cos_z_2 = 0.5*cosf(theta_z);
  278. float cos_y_2 = 0.5*cosf(theta_y);
  279. float cos_x_2 = 0.5*cosf(theta_x);
  280. float sin_z_2 = 0.5*sinf(theta_z);
  281. float sin_y_2 = 0.5*sinf(theta_y);
  282. float sin_x_2 = 0.5*sinf(theta_x);
  283. // and now compute quaternion
  284. q->w = cos_z_2*cos_y_2*cos_x_2 + sin_z_2*sin_y_2*sin_x_2;
  285. q->x = cos_z_2*cos_y_2*sin_x_2 - sin_z_2*sin_y_2*cos_x_2;
  286. q->y = cos_z_2*sin_y_2*cos_x_2 + sin_z_2*cos_y_2*sin_x_2;
  287. q->z = sin_z_2*cos_y_2*cos_x_2 - cos_z_2*sin_y_2*sin_x_2;
  288. } // EulerZYX_To_QUAT
  289. ///////////////////////////////////////////////////////////////
  290. void QUAT_To_VECTOR3D_Theta(QUAT_PTR q, VECTOR3D_PTR v, float *theta)
  291. {
  292. // this function converts a unit quaternion into a unit direction
  293. // vector and rotation angle about that vector
  294. // extract theta
  295. *theta = acosf(q->w);
  296. // pre-compute to save time
  297. float sinf_theta_inv = 1.0/sinf(*theta);
  298. // now the vector
  299. v->x    = q->x*sinf_theta_inv;
  300. v->y    = q->y*sinf_theta_inv;
  301. v->z    = q->z*sinf_theta_inv;
  302. // multiply by 2
  303. *theta*=2;
  304. } // end QUAT_To_VECTOR3D_Theta
  305. ////////////////////////////////////////////////////////////
  306. void QUAT_Print(QUAT_PTR q, char *name="q")
  307. {
  308. // this function prints out a quaternion
  309. Write_Error("n%s=%f+[(%f)i + (%f)j + (%f)k]", 
  310.        name, q->w, q->x, q->y, q->z);
  311. } // end QUAT_Print
  312. ///////////////////////////////////////////////////////////
  313. float Fast_Sin(float theta)
  314. {
  315. // this function uses the sin_look[] lookup table, but
  316. // has logic to handle negative angles as well as fractional
  317. // angles via interpolation, use this for a more robust
  318. // sin computation that the blind lookup, but with with
  319. // a slight hit in speed
  320. // convert angle to 0-359
  321. theta = fmodf(theta,360);
  322. // make angle positive
  323. if (theta < 0) theta+=360.0;
  324. // compute floor of theta and fractional part to interpolate
  325. int theta_int    = (int)theta;
  326. float theta_frac = theta - theta_int;
  327. // now compute the value of sin(angle) using the lookup tables
  328. // and interpolating the fractional part, note that if theta_int
  329. // is equal to 359 then theta_int+1=360, but this is fine since the
  330. // table was made with the entries 0-360 inclusive
  331. return(sin_look[theta_int] + 
  332.        theta_frac*(sin_look[theta_int+1] - sin_look[theta_int]));
  333. } // end Fast_Sin
  334. ///////////////////////////////////////////////////////////////
  335. float Fast_Cos(float theta)
  336. {
  337. // this function uses the cos_look[] lookup table, but
  338. // has logic to handle negative angles as well as fractional
  339. // angles via interpolation, use this for a more robust
  340. // cos computation that the blind lookup, but with with
  341. // a slight hit in speed
  342. // convert angle to 0-359
  343. theta = fmodf(theta,360);
  344. // make angle positive
  345. if (theta < 0) theta+=360.0;
  346. // compute floor of theta and fractional part to interpolate
  347. int theta_int    = (int)theta;
  348. float theta_frac = theta - theta_int;
  349. // now compute the value of sin(angle) using the lookup tables
  350. // and interpolating the fractional part, note that if theta_int
  351. // is equal to 359 then theta_int+1=360, but this is fine since the
  352. // table was made with the entries 0-360 inclusive
  353. return(cos_look[theta_int] + 
  354.        theta_frac*(cos_look[theta_int+1] - cos_look[theta_int]));
  355. } // end Fast_Cos
  356. ///////////////////////////////////////////////////////////////
  357. void POLAR2D_To_POINT2D(POLAR2D_PTR polar, POINT2D_PTR rect)
  358. {
  359. // convert polar to rectangular
  360. rect->x = polar->r*cosf(polar->theta);
  361. rect->y = polar->r*sinf(polar->theta);
  362. } // end POLAR2D_To_POINT2D
  363. ////////////////////////////////////////////////////////////////
  364. void POLAR2D_To_RectXY(POLAR2D_PTR polar, float *x, float *y)
  365. {
  366. // convert polar to rectangular
  367. *x = polar->r*cosf(polar->theta);
  368. *y = polar->r*sinf(polar->theta);
  369. } // end POLAR2D_To_RectXY
  370. ///////////////////////////////////////////////////////////////
  371. void POINT2D_To_POLAR2D(POINT2D_PTR rect, POLAR2D_PTR polar)
  372. {
  373. // convert rectangular to polar
  374. polar->r     = sqrtf((rect->x * rect->x) + (rect->y * rect->y));
  375. polar->theta = atanf(rect->y/rect->x);
  376. } // end POINT2D_To_POLAR2D
  377. ////////////////////////////////////////////////////////////
  378. void POINT2D_To_PolarRTh(POINT2D_PTR rect, float *r, float *theta)
  379. {
  380. // convert rectangular to polar
  381. *r=sqrtf((rect->x * rect->x) + (rect->y * rect->y));
  382. *theta = atanf(rect->y/rect->x);
  383. } // end POINT2D_To_PolarRTh
  384. ///////////////////////////////////////////////////////////////
  385.  void CYLINDRICAL3D_To_POINT3D(CYLINDRICAL3D_PTR cyl, POINT3D_PTR rect)
  386. {
  387. // convert cylindrical to rectangular
  388. rect->x = cyl->r*cosf(cyl->theta);
  389. rect->y = cyl->r*sinf(cyl->theta);
  390. rect->z = cyl->z;
  391. } // end CYLINDRICAL3D_To_POINT3D
  392. ////////////////////////////////////////////////////////////////
  393. void CYLINDRICAL3D_To_RectXYZ(CYLINDRICAL3D_PTR cyl,  
  394.                               float *x, float *y, float *z)
  395. {
  396. // convert cylindrical to rectangular
  397. *x = cyl->r*cosf(cyl->theta);
  398. *y = cyl->r*sinf(cyl->theta);
  399. *z = cyl->z;
  400. } // end CYLINDRICAL3D_To_RectXYZ
  401. ///////////////////////////////////////////////////////////////
  402. void POINT3D_To_CYLINDRICAL3D(POINT3D_PTR rect, 
  403.                               CYLINDRICAL3D_PTR cyl)
  404. {
  405. // convert rectangular to cylindrical
  406. cyl->r     = sqrtf((rect->x * rect->x) + (rect->y * rect->y));
  407. cyl->theta = atanf(rect->y/rect->x);
  408. cyl->z     = rect->z;
  409. } // end POINT3D_To_CYLINDRICAL3D
  410. ///////////////////////////////////////////////////////////////
  411. void POINT3D_To_CylindricalRThZ(POINT3D_PTR rect, 
  412.                                        float *r, float *theta, float *z)
  413. {
  414. // convert rectangular to cylindrical
  415. *r     = sqrtf((rect->x * rect->x) + (rect->y * rect->y));
  416. *theta = atanf(rect->y/rect->x);
  417. *z     = rect->z;
  418. } // end POINT3D_To_CylindricalRThZ
  419. ///////////////////////////////////////////////////////////////
  420. void SPHERICAL3D_To_POINT3D(SPHERICAL3D_PTR sph, POINT3D_PTR rect)
  421. {
  422. // convert spherical to rectangular
  423. float r;
  424. // pre-compute r, and z
  425. r       = sph->p*sinf(sph->phi);
  426. rect->z = sph->p*cosf(sph->phi);
  427. // use r to simplify computation of x,y
  428. rect->x = r*cosf(sph->theta);
  429. rect->y = r*sinf(sph->theta);
  430. } // end SPHERICAL3D_To_POINT3D
  431. ////////////////////////////////////////////////////////////////
  432. void SPHERICAL3D_To_RectXYZ(SPHERICAL3D_PTR sph, 
  433.                                    float *x, float *y, float *z)
  434. {
  435. // convert spherical to rectangular
  436. float r;
  437. // pre-compute r, and z
  438. r  = sph->p*sinf(sph->phi);
  439. *z = sph->p*cosf(sph->phi);
  440. // use r to simplify computation of x,y
  441. *x = r*cosf(sph->theta);
  442. *y = r*sinf(sph->theta);
  443. } // end SPHERICAL3D_To_RectXYZ
  444. ///////////////////////////////////////////////////////////
  445. void POINT3D_To_SPHERICAL3D(POINT3D_PTR rect, SPHERICAL3D_PTR sph)
  446. {
  447. // convert rectangular to spherical
  448. sph->p = sqrtf((rect->x*rect->x)+(rect->y*rect->y)+(rect->z*rect->z));
  449. sph->theta = atanf(rect->y/rect->x);
  450. // we need r to compute phi
  451. float r = sph->p*sinf(sph->phi);
  452. sph->phi   = asinf(r/sph->p);
  453. } // end POINT3D_To_CYLINDRICAL3D
  454. ////////////////////////////////////////////////////////////
  455. void POINT3D_To_SphericalPThPh(POINT3D_PTR rect, 
  456.                                       float *p, float *theta, float *phi)
  457. {
  458. // convert rectangular to spherical
  459. *p     = sqrtf((rect->x*rect->x)+(rect->y*rect->y)+(rect->z*rect->z));
  460. *theta = atanf(rect->y/rect->x);
  461. // we need r to compute phi
  462. float r = sqrtf((rect->x * rect->x) + (rect->y * rect->y));
  463. *phi    = asinf(r / (*p));
  464. } // end POINT3D_To_SphericalPThPh
  465. /////////////////////////////////////////////////////////////
  466. void VECTOR2D_Add(VECTOR2D_PTR va, 
  467.                          VECTOR2D_PTR vb, 
  468.                          VECTOR2D_PTR vsum)
  469. {
  470. // this function adds va+vb and return it in vsum
  471. vsum->x = va->x + vb->x;
  472. vsum->y = va->y + vb->y;
  473. } // end VECTOR2D_Add
  474. ////////////////////////////////////////////////////////////
  475. VECTOR2D VECTOR2D_Add(VECTOR2D_PTR va, 
  476.                       VECTOR2D_PTR vb)
  477. {
  478. // this function adds va+vb and returns the result on 
  479. // the stack
  480. VECTOR2D vsum;
  481. vsum.x = va->x + vb->x;
  482. vsum.y = va->y + vb->y;
  483. // return result
  484. return(vsum);
  485. } // end VECTOR2D_Add
  486. ////////////////////////////////////////////////////////////
  487. void VECTOR2D_Sub(VECTOR2D_PTR va, 
  488.                          VECTOR2D_PTR vb, 
  489.                          VECTOR2D_PTR vdiff)
  490. {
  491. // this function subtracts va-vb and return it in vdiff
  492. // the stack
  493. vdiff->x = va->x - vb->x;
  494. vdiff->y = va->y - vb->y;
  495. } // end VECTOR2D_Sub
  496. ////////////////////////////////////////////////////////////
  497. VECTOR2D VECTOR2D_Sub(VECTOR2D_PTR va, 
  498.                       VECTOR2D_PTR vb)
  499. {
  500. // this function subtracts va-vb and returns the result on 
  501. // the stack
  502. VECTOR2D vdiff;
  503. vdiff.x = va->x - vb->x;
  504. vdiff.y = va->y - vb->y;
  505. // return result
  506. return(vdiff);                      
  507. } // end VECTOR2D_Sub
  508. ////////////////////////////////////////////////////////////
  509. void VECTOR2D_Scale(float k, 
  510.                     VECTOR2D_PTR va, 
  511.                     VECTOR2D_PTR vscaled)
  512. {
  513. // this function scales a vector by the constant k,
  514. // leaves the original unchanged, and returns the result
  515. // in vscaled
  516. // multiply each component by scaling factor
  517. vscaled->x = k*va->x;
  518. vscaled->y = k*va->y;
  519. } // end VECTOR2D_Scale
  520. /////////////////////////////////////////////////////////////
  521. void VECTOR2D_Scale(float k, VECTOR2D_PTR va)
  522. {
  523. // this function scales a vector by the constant k,
  524. // by scaling the original
  525. // multiply each component by scaling factor
  526. va->x*=k;
  527. va->y*=k;
  528. } // end VECTOR2D_Scale
  529. //////////////////////////////////////////////////////////////
  530. float VECTOR2D_Dot(VECTOR2D_PTR va, VECTOR2D_PTR vb)
  531. {
  532. // computes the dot product between va and vb
  533. return( (va->x * vb->x) + (va->y * vb->y) );
  534. } // end VECTOR2D_Dot
  535. ///////////////////////////////////////////////////////////////
  536. float VECTOR2D_Length(VECTOR2D_PTR va)
  537. {
  538. // computes the magnitude of a vector, slow
  539. return(sqrtf(va->x*va->x + va->y*va->y));
  540. } // end VECTOR2D_Length
  541. ///////////////////////////////////////////////////////////////
  542. float VECTOR2D_Length_Fast(VECTOR2D_PTR va)
  543. {
  544. // computes the magnitude of a vector using an approximation
  545. // very fast
  546. return( (float)Fast_Distance_2D(va->x, va->y) );
  547. } // end VECTOR2D_Length_Fast
  548. ///////////////////////////////////////////////////////////////
  549. void VECTOR2D_Normalize(VECTOR2D_PTR va)
  550. {
  551. // normalizes the sent vector in place
  552. // compute length
  553. float length = sqrtf(va->x*va->x + va->y*va->y );
  554. // test for zero length vector
  555. // if found return zero vector
  556. if (length < EPSILON_E5) 
  557.    return;
  558. float length_inv = 1/length;
  559. // compute normalized version of vector
  560. va->x = va->x*length_inv;
  561. va->y = va->y*length_inv;
  562. } // end VECTOR2D_Normalize
  563. ///////////////////////////////////////////////////////////////
  564. void VECTOR2D_Normalize(VECTOR2D_PTR va, VECTOR2D_PTR vn)
  565. {
  566. // normalizes the sent vector and returns the result in vn
  567. VECTOR2D_ZERO(vn);
  568. // compute length
  569. float length = (float)sqrtf(va->x*va->x + va->y*va->y );
  570. // test for zero length vector
  571. // if found return zero vector
  572. if (length < EPSILON_E5) 
  573.    return;
  574. float length_inv = 1/length;
  575. // compute normalized version of vector
  576. vn->x = va->x*length_inv;
  577. vn->y = va->y*length_inv;
  578. } // end VECTOR2D_Normalize
  579. ///////////////////////////////////////////////////////////////
  580. void VECTOR2D_Build(VECTOR2D_PTR init,
  581.                     VECTOR2D_PTR term,
  582.                     VECTOR2D_PTR result)
  583. {
  584. // this function creates a vector from two vectors (or points)
  585. //  in 3D space
  586. result->x = term->x - init->x;
  587. result->y = term->y - init->y;
  588. } // end VECTOR2D_Build
  589. ///////////////////////////////////////////////////////////////
  590. float VECTOR2D_CosTh(VECTOR2D_PTR va, VECTOR2D_PTR vb)
  591. {
  592. // this function returns the cosine of the angle between
  593. // two vectors. Note, we could compute the actual angle,
  594. // many many times, in further calcs we will want ultimately
  595. // compute cos of the angle, so why not just leave it!
  596. return(VECTOR2D_Dot(va,vb)/(VECTOR2D_Length(va)*VECTOR2D_Length(vb)));
  597. } // end VECTOR2D_CosTh
  598. //////////////////////////////////////////////////////////////
  599. void VECTOR2D_Print(VECTOR2D_PTR va, char *name="v")
  600. {
  601. // this function prints out a VECTOR2D
  602. Write_Error("n%s=[",name);
  603. for (int index=0; index<2; index++)
  604.     Write_Error("%f, ",va->M[index]);
  605. Write_Error("]");
  606. } // end VECTOR2D_Print
  607. /////////////////////////////////////////////////////////////
  608. void VECTOR3D_Add(VECTOR3D_PTR va, 
  609.                   VECTOR3D_PTR vb, 
  610.                   VECTOR3D_PTR vsum)
  611. {
  612. // this function adds va+vb and return it in vsum
  613. vsum->x = va->x + vb->x;
  614. vsum->y = va->y + vb->y;
  615. vsum->z = va->z + vb->z;
  616. } // end VECTOR3D_Add
  617. ////////////////////////////////////////////////////////////
  618. VECTOR3D VECTOR3D_Add(VECTOR3D_PTR va, 
  619.                       VECTOR3D_PTR vb)
  620. {
  621. // this function adds va+vb and returns the result on 
  622. // the stack
  623. VECTOR3D vsum;
  624. vsum.x = va->x + vb->x;
  625. vsum.y = va->y + vb->y;
  626. vsum.z = va->z + vb->z;
  627. // return result
  628. return(vsum);
  629. } // end VECTOR3D_Add
  630. ////////////////////////////////////////////////////////////
  631. void VECTOR3D_Sub(VECTOR3D_PTR va, 
  632.                   VECTOR3D_PTR vb, 
  633.                   VECTOR3D_PTR vdiff)
  634. {
  635. // this function subtracts va-vb and return it in vdiff
  636. // the stack
  637. vdiff->x = va->x - vb->x;
  638. vdiff->y = va->y - vb->y;
  639. vdiff->z = va->z - vb->z;
  640. } // end VECTOR3D_Sub
  641. ////////////////////////////////////////////////////////////
  642. VECTOR3D VECTOR3D_Sub(VECTOR3D_PTR va, VECTOR3D_PTR vb)
  643. {
  644. // this function subtracts va-vb and returns the result on 
  645. // the stack
  646. VECTOR3D vdiff;
  647. vdiff.x = va->x - vb->x;
  648. vdiff.y = va->y - vb->y;
  649. vdiff.z = va->z - vb->z;
  650. // return result
  651. return(vdiff);                      
  652. } // end VECTOR3D_Sub
  653. ////////////////////////////////////////////////////////////
  654. void VECTOR3D_Scale(float k, VECTOR3D_PTR va)
  655. {
  656. // this function scales a vector by the constant k,
  657. // and modifies the original
  658. // multiply each component by scaling factor
  659. va->x*=k;
  660. va->y*=k;
  661. va->z*=k;
  662. } // end VECTOR3D_Scale
  663. /////////////////////////////////////////////////////////////
  664. void VECTOR3D_Scale(float k, VECTOR3D_PTR va, VECTOR3D_PTR vscaled)
  665. {
  666. // this function scales a vector by the constant k,
  667. // leaves the original unchanged, and returns the result
  668. // in vres as well as on the stack
  669. // multiply each component by scaling factor
  670. vscaled->x = k*va->x;
  671. vscaled->y = k*va->y;
  672. vscaled->z = k*va->z;
  673. } // end VECTOR3D_Scale
  674. //////////////////////////////////////////////////////////////
  675. float VECTOR3D_Dot(VECTOR3D_PTR va, VECTOR3D_PTR vb)
  676. {
  677. // computes the dot product between va and vb
  678. return( (va->x * vb->x) + (va->y * vb->y) + (va->z * vb->z) );
  679. } // end VECTOR3D_DOT
  680. /////////////////////////////////////////////////////////////
  681. void VECTOR3D_Cross(VECTOR3D_PTR va, VECTOR3D_PTR vb, VECTOR3D_PTR vn)
  682. {
  683. // this function computes the cross product between va and vb
  684. // and returns the vector that is perpendicular to each in vn
  685. vn->x =  ( (va->y * vb->z) - (va->z * vb->y) );
  686. vn->y = -( (va->x * vb->z) - (va->z * vb->x) );
  687. vn->z =  ( (va->x * vb->y) - (va->y * vb->x) ); 
  688. } // end VECTOR3D_Cross
  689. /////////////////////////////////////////////////////////////
  690. VECTOR3D VECTOR3D_Cross(VECTOR3D_PTR va, VECTOR3D_PTR vb)
  691. {
  692. // this function computes the cross product between va and vb
  693. // and returns the vector that is perpendicular to each
  694. VECTOR3D vn;
  695. vn.x =  ( (va->y * vb->z) - (va->z * vb->y) );
  696. vn.y = -( (va->x * vb->z) - (va->z * vb->x) );
  697. vn.z =  ( (va->x * vb->y) - (va->y * vb->x) ); 
  698. // return result
  699. return(vn);
  700. } // end VECTOR3D_Cross
  701. //////////////////////////////////////////////////////////////
  702. float VECTOR3D_Length(VECTOR3D_PTR va)
  703. {
  704. // computes the magnitude of a vector, slow
  705. return( (float)sqrtf(va->x*va->x + va->y*va->y + va->z*va->z) );
  706. } // end VECTOR3D_Length
  707. ///////////////////////////////////////////////////////////////
  708. float VECTOR3D_Length_Fast(VECTOR3D_PTR va)
  709. {
  710. // computes the magnitude of a vector using an approximation
  711. // very fast
  712. return( Fast_Distance_3D(va->x, va->y, va->z) );
  713. } // end VECTOR3D_Length_Fast
  714. ///////////////////////////////////////////////////////////////
  715. void VECTOR3D_Normalize(VECTOR3D_PTR va)
  716. {
  717. // normalizes the sent vector in placew
  718. // compute length
  719. float length = sqrtf(va->x*va->x + va->y*va->y + va->z*va->z);
  720. // test for zero length vector
  721. // if found return zero vector
  722. if (length < EPSILON_E5) 
  723.    return;
  724. float length_inv = 1/length;
  725. // compute normalized version of vector
  726. va->x*=length_inv;
  727. va->y*=length_inv;
  728. va->z*=length_inv;
  729. } // end VECTOR3D_Normalize
  730. ///////////////////////////////////////////////////////////////
  731. void VECTOR3D_Normalize(VECTOR3D_PTR va, VECTOR3D_PTR vn)
  732. {
  733. // normalizes the sent vector and returns the result in vn
  734. VECTOR3D_ZERO(vn);
  735. // compute length
  736. float length = VECTOR3D_Length(va);
  737. // test for zero length vector
  738. // if found return zero vector
  739. if (length < EPSILON_E5) 
  740.    return;
  741. float length_inv = 1.0/length;
  742. // compute normalized version of vector
  743. vn->x = va->x*length_inv;
  744. vn->y = va->y*length_inv;
  745. vn->z = va->z*length_inv;
  746. } // end VECTOR3D_Normalize
  747. ///////////////////////////////////////////////////////////////
  748. void VECTOR3D_Build(VECTOR3D_PTR init,VECTOR3D_PTR term,VECTOR3D_PTR result)
  749. {
  750. // this function creates a vector from two vectors (or points)
  751. //  in 3D space
  752. result->x = term->x - init->x;
  753. result->y = term->y - init->y;
  754. result->z = term->z - init->z;
  755. } // end VECTOR3D_Build
  756. /////////////////////////////////////////////////////////////
  757. float VECTOR3D_CosTh(VECTOR3D_PTR va, VECTOR3D_PTR vb)
  758. {
  759. // this function returns the cosine of the angle between
  760. // two vectors. Note, we could compute the actual angle,
  761. // many many times, in further calcs we will want ultimately
  762. // compute cos of the angle, so why not just leave it!
  763. return(VECTOR3D_Dot(va,vb)/(VECTOR3D_Length(va)*VECTOR3D_Length(vb)));
  764. } // end VECTOR3D_CosTh
  765. ///////////////////////////////////////////////////////////////
  766. void VECTOR3D_Print(VECTOR3D_PTR va, char *name="v")
  767. {
  768. // this function prints out a VECTOR3D
  769. Write_Error("n%s=[",name);
  770. for (int index=0; index<3; index++)
  771.     Write_Error("%f, ",va->M[index]);
  772. Write_Error("]");
  773. } // end VECTOR3D_Print
  774. ////////////////////////////////////////////////////////////////
  775. // these are the 4D version of the vector functions, they
  776. // assume that the vectors are 3D with a w, so w is left
  777. // out of all the operations
  778. void VECTOR4D_Build(VECTOR4D_PTR init, VECTOR4D_PTR term, VECTOR4D_PTR result)
  779. {
  780. // build a 4d vector
  781. result->x = term->x - init->x;
  782. result->y = term->y - init->y;
  783. result->z = term->z - init->z;
  784. result->w = 1;
  785. } // end VECTOR4D_Build
  786. ////////////////////////////////////////////////////////////////
  787. void VECTOR4D_Add(VECTOR4D_PTR va, VECTOR4D_PTR vb, VECTOR4D_PTR vsum)
  788. {
  789. // this function adds va+vb and return it in vsum
  790. vsum->x = va->x + vb->x;
  791. vsum->y = va->y + vb->y;
  792. vsum->z = va->z + vb->z;
  793. vsum->w = 1;
  794. } // end VECTOR4D_Add
  795. ////////////////////////////////////////////////////////////
  796. VECTOR4D VECTOR4D_Add(VECTOR4D_PTR va, VECTOR4D_PTR vb)
  797. {
  798. // this function adds va+vb and returns the result on 
  799. // the stack
  800. VECTOR4D vsum;
  801. vsum.x = va->x + vb->x;
  802. vsum.y = va->y + vb->y;
  803. vsum.z = va->z + vb->z;
  804. vsum.w = 1;
  805. // return result
  806. return(vsum);
  807. } // end VECTOR4D_Add
  808. ////////////////////////////////////////////////////////////
  809. void VECTOR4D_Sub(VECTOR4D_PTR va, VECTOR4D_PTR vb, VECTOR4D_PTR vdiff)
  810. {
  811. // this function subtracts va-vb and return it in vdiff
  812. // the stack
  813. vdiff->x = va->x - vb->x;
  814. vdiff->y = va->y - vb->y;
  815. vdiff->z = va->z - vb->z;
  816. vdiff->w = 1;
  817. } // end VECTOR4D_Sub
  818. ////////////////////////////////////////////////////////////
  819. VECTOR4D VECTOR4D_Sub(VECTOR4D_PTR va, VECTOR4D_PTR vb)
  820. {
  821. // this function subtracts va-vb and returns the result on 
  822. // the stack
  823. VECTOR4D vdiff;
  824. vdiff.x = va->x - vb->x;
  825. vdiff.y = va->y - vb->y;
  826. vdiff.z = va->z - vb->z;
  827. vdiff.w = 1;
  828. // return result
  829. return(vdiff);                      
  830. } // end VECTOR4D_Sub
  831. ////////////////////////////////////////////////////////////
  832. void VECTOR4D_Scale(float k, VECTOR4D_PTR va)
  833. {
  834. // this function scales a vector by the constant k,
  835. // in place , note w is left unchanged
  836. // multiply each component by scaling factor
  837. va->x*=k;
  838. va->y*=k;
  839. va->z*=k;
  840. va->w = 1;
  841. } // end VECTOR4D_Scale
  842. /////////////////////////////////////////////////////////////
  843. void VECTOR4D_Scale(float k, VECTOR4D_PTR va, VECTOR4D_PTR vscaled)
  844. {
  845. // this function scales a vector by the constant k,
  846. // leaves the original unchanged, and returns the result
  847. // in vres as well as on the stack
  848. // multiply each component by scaling factor
  849. vscaled->x = k*va->x;
  850. vscaled->y = k*va->y;
  851. vscaled->z = k*va->z;
  852. vscaled->w = 1;
  853. } // end VECTOR4D_Scale
  854. //////////////////////////////////////////////////////////////
  855. float VECTOR4D_Dot(VECTOR4D_PTR va, VECTOR4D_PTR vb)
  856. {
  857. // computes the dot product between va and vb
  858. return( (va->x * vb->x) + (va->y * vb->y) + (va->z * vb->z) );
  859. } // end VECTOR4D_DOT
  860. /////////////////////////////////////////////////////////////
  861. void VECTOR4D_Cross(VECTOR4D_PTR va, 
  862.                     VECTOR4D_PTR vb,
  863.                     VECTOR4D_PTR vn)
  864. {
  865. // this function computes the cross product between va and vb
  866. // and returns the vector that is perpendicular to each in vn
  867. vn->x =  ( (va->y * vb->z) - (va->z * vb->y) );
  868. vn->y = -( (va->x * vb->z) - (va->z * vb->x) );
  869. vn->z =  ( (va->x * vb->y) - (va->y * vb->x) ); 
  870. vn->w = 1;
  871. } // end VECTOR4D_Cross
  872. /////////////////////////////////////////////////////////////
  873. VECTOR4D VECTOR4D_Cross(VECTOR4D_PTR va, VECTOR4D_PTR vb)
  874. {
  875. // this function computes the cross product between va and vb
  876. // and returns the vector that is perpendicular to each
  877. VECTOR4D vn;
  878. vn.x =  ( (va->y * vb->z) - (va->z * vb->y) );
  879. vn.y = -( (va->x * vb->z) - (va->z * vb->x) );
  880. vn.z =  ( (va->x * vb->y) - (va->y * vb->x) ); 
  881. vn.w = 1;
  882. // return result
  883. return(vn);
  884. } // end VECTOR4D_Cross
  885. //////////////////////////////////////////////////////////////
  886. float VECTOR4D_Length(VECTOR4D_PTR va)
  887. {
  888. // computes the magnitude of a vector, slow
  889. return(sqrtf(va->x*va->x + va->y*va->y + va->z*va->z) );
  890. } // end VECTOR4D_Length
  891. ///////////////////////////////////////////////////////////////
  892. float VECTOR4D_Length_Fast(VECTOR4D_PTR va)
  893. {
  894. // computes the magnitude of a vector using an approximation
  895. // very fast
  896. return( Fast_Distance_3D(va->x, va->y, va->z) );
  897. } // end VECTOR4D_Length_Fast
  898. ///////////////////////////////////////////////////////////////
  899. void VECTOR4D_Normalize(VECTOR4D_PTR va)
  900. {
  901. // normalizes the sent vector and returns the result
  902. // compute length
  903. float length = sqrtf(va->x*va->x + va->y*va->y + va->z*va->z);
  904. // test for zero length vector
  905. // if found return zero vector
  906. if (length < EPSILON_E5) 
  907.    return;
  908. float length_inv = 1.0/length;
  909. // compute normalized version of vector
  910. va->x*=length_inv;
  911. va->y*=length_inv;
  912. va->z*=length_inv;
  913. va->w = 1;
  914. } // end VECTOR4D_Normalize
  915. ///////////////////////////////////////////////////////////////
  916. void VECTOR4D_Normalize(VECTOR4D_PTR va, VECTOR4D_PTR vn)
  917. {
  918. // normalizes the sent vector and returns the result in vn
  919. VECTOR4D_ZERO(vn);
  920. // compute length
  921. float length = sqrt(va->x*va->x + va->y*va->y + va->z*va->z);
  922. // test for zero length vector
  923. // if found return zero vector
  924. if (length < EPSILON_E5) 
  925.    return;
  926. float length_inv = 1.0/length;
  927. // compute normalized version of vector
  928. vn->x = va->x*length_inv;
  929. vn->y = va->y*length_inv;
  930. vn->z = va->z*length_inv;
  931. vn->w = 1;
  932. } // end VECTOR4D_Normalize
  933. ///////////////////////////////////////////////////////////////
  934. float VECTOR4D_CosTh(VECTOR4D_PTR va, VECTOR4D_PTR vb)
  935. {
  936. // this function returns the cosine of the angle between
  937. // two vectors. Note, we could compute the actual angle,
  938. // many many times, in further calcs we will want ultimately
  939. // compute cos of the angle, so why not just leave it!
  940. return(VECTOR4D_Dot(va,vb)/(VECTOR4D_Length(va)*VECTOR4D_Length(vb)));
  941. } // end VECTOR4D_CosTh
  942. ////////////////////////////////////////////////////////////
  943. void VECTOR4D_Print(VECTOR4D_PTR va, char *name="v")
  944. {
  945. // this function prints out a VECTOR4D
  946. Write_Error("n%s[",name);
  947. for (int index=0; index<4; index++)
  948.     Write_Error("%f, ",va->M[index]);
  949. Write_Error("]");
  950. } // end VECTOR4D_Print
  951. ////////////////////////////////////////////////////////////////
  952. void Mat_Init_2X2(MATRIX2X2_PTR ma, 
  953.                   float m00, float m01,
  954.                   float m10, float m11)
  955. {
  956. // this function fills a 2x2 matrix with the sent data in 
  957. // row major form
  958. ma->M00 = m00; ma->M01 = m01; 
  959. ma->M10 = m10; ma->M11 = m11; 
  960. } // end Mat_Init_2X2
  961. /////////////////////////////////////////////////////////////////
  962. void Mat_Add_2X2(MATRIX2X2_PTR ma, MATRIX2X2_PTR mb, MATRIX2X2_PTR msum)
  963. {
  964. // this function adds two 2x2 matrices together and stores
  965. // the result in msum
  966. msum->M00 = ma->M00+mb->M00;
  967. msum->M01 = ma->M01+mb->M01;
  968. msum->M10 = ma->M10+mb->M10;
  969. msum->M11 = ma->M11+mb->M11;
  970. } // end Mat_Add_2X2
  971. /////////////////////////////////////////////////////////////////
  972. void Mat_Mul_2X2(MATRIX2X2_PTR ma, MATRIX2X2_PTR mb, MATRIX2X2_PTR mprod)
  973. {
  974. // this function multiplies two 2x2 matrices together and 
  975. // and stores the result in mprod
  976. mprod->M00 = ma->M00*mb->M00 + ma->M01*mb->M10;
  977. mprod->M01 = ma->M00*mb->M01 + ma->M01*mb->M11;
  978. mprod->M10 = ma->M10*mb->M00 + ma->M11*mb->M10;
  979. mprod->M11 = ma->M10*mb->M01 + ma->M11*mb->M11;
  980. } // end Mat_Mul_2X2
  981. /////////////////////////////////////////////////////////////////
  982. int Mat_Inverse_2X2(MATRIX2X2_PTR m, MATRIX2X2_PTR mi)
  983. {
  984. // this function computes the inverse of a 2x2 matrix
  985. // and stores the result in mi
  986. // compute determinate
  987. float det = (m->M00*m->M11 - m->M01*m->M10);
  988. // if determinate is 0 then inverse doesn't exist
  989. if (fabs(det) < EPSILON_E5)
  990.    return(0);
  991. float det_inv = 1.0/det;
  992. // fill in inverse by formula
  993. mi->M00 =  m->M11*det_inv;
  994. mi->M01 = -m->M01*det_inv;
  995. mi->M10 = -m->M10*det_inv;
  996. mi->M11 =  m->M00*det_inv;
  997. // return sucess
  998. return(1);
  999. } // end Mat_Inverse_2X2
  1000. /////////////////////////////////////////////////////////////////
  1001. void Print_Mat_2X2(MATRIX2X2_PTR ma, char *name="M")
  1002. {
  1003. // prints out a 3x3 matrix
  1004. Write_Error("n%s=n",name);
  1005. for (int r=0; r < 2; r++, Write_Error("n"))
  1006.     for (int c=0; c < 2; c++)
  1007.         Write_Error("%f ",ma->M[r][c]);        
  1008. } // end Print_Mat_2X2
  1009. //////////////////////////////////////////////////////////////////
  1010. float Mat_Det_2X2(MATRIX2X2_PTR m)
  1011. {
  1012. // computes the determinate of a 2x2 matrix
  1013. return(m->M00*m->M11 - m->M01*m->M10);
  1014. } // end Mat_Det_2X2
  1015. ///////////////////////////////////////////////////////////////
  1016. int Solve_2X2_System(MATRIX2X2_PTR A, MATRIX1X2_PTR X, MATRIX1X2_PTR B)
  1017. {
  1018. // solves the system AX=B and computes X=A(-1)*B
  1019. // by using cramers rule and determinates
  1020. // step 1: compute determinate of A
  1021. float det_A = Mat_Det_2X2(A);
  1022. // test if det(a) is zero, if so then there is no solution
  1023. if (fabs(det_A) < EPSILON_E5)
  1024.    return(0);
  1025. // step 2: create x,y numerator matrices by taking A and
  1026. // replacing each column of it with B(transpose) and solve
  1027. MATRIX2X2 work_mat; // working matrix
  1028. // solve for x /////////////////
  1029. // copy A into working matrix
  1030. MAT_COPY_2X2(A, &work_mat);
  1031. // swap out column 0 (x column)
  1032. MAT_COLUMN_SWAP_2X2(&work_mat, 0, B);
  1033. // compute determinate of A with B swapped into x column
  1034. float det_ABx = Mat_Det_2X2(&work_mat);
  1035. // now solve for X00
  1036. X->M00 = det_ABx/det_A;
  1037. // solve for y /////////////////
  1038. // copy A into working matrix
  1039. MAT_COPY_2X2(A, &work_mat);
  1040. // swap out column 1 (y column)
  1041. MAT_COLUMN_SWAP_2X2(&work_mat, 1, B);
  1042. // compute determinate of A with B swapped into y column
  1043. float det_ABy = Mat_Det_2X2(&work_mat);
  1044. // now solve for X01
  1045. X->M01 = det_ABy/det_A;
  1046. // return success
  1047. return(1);
  1048. } // end Solve_2X2_System
  1049. ///////////////////////////////////////////////////////////////
  1050. void Mat_Add_3X3(MATRIX3X3_PTR ma, 
  1051.                  MATRIX3X3_PTR mb,
  1052.                  MATRIX3X3_PTR msum)
  1053. {
  1054. // this function adds two 3x3 matrices together and 
  1055. // and stores the result
  1056. for (int row=0; row<3; row++)
  1057.     {
  1058.     for (int col=0; col<3; col++)
  1059.         {
  1060.         // insert resulting row,col element
  1061.         msum->M[row][col] = ma->M[row][col] + mb->M[row][col];
  1062.         } // end for col
  1063.     } // end for row
  1064. } // end Mat_Add_3X3
  1065. ////////////////////////////////////////////////////////////////////
  1066. void Mat_Mul_VECTOR3D_3X3(VECTOR3D_PTR  va, 
  1067.                           MATRIX3X3_PTR mb,
  1068.                           VECTOR3D_PTR  vprod)
  1069. {
  1070. // this function multiplies a VECTOR3D against a 
  1071. // 3x3 matrix - ma*mb and stores the result in mprod
  1072.     for (int col=0; col < 3; col++)
  1073.         {
  1074.         // compute dot product from row of ma 
  1075.         // and column of mb
  1076.         float sum = 0; // used to hold result
  1077.         for (int row=0; row<3; row++)
  1078.              {
  1079.              // add in next product pair
  1080.              sum+=(va->M[row]*mb->M[row][col]);
  1081.              } // end for index
  1082.         // insert resulting col element
  1083.         vprod->M[col] = sum;
  1084.         } // end for col
  1085. } // end Mat_Mul_VECTOR3D_3X3
  1086. ////////////////////////////////////////////////////////////////////
  1087. void Mat_Init_3X3(MATRIX3X3_PTR ma, 
  1088.                   float m00, float m01, float m02,
  1089.                   float m10, float m11, float m12,
  1090.                   float m20, float m21, float m22)
  1091. {
  1092. // this function fills a 3x3 matrix with the sent data in row major form
  1093. ma->M00 = m00; ma->M01 = m01; ma->M02 = m02;
  1094. ma->M10 = m10; ma->M11 = m11; ma->M12 = m12;
  1095. ma->M20 = m20; ma->M21 = m21; ma->M22 = m22;
  1096. } // end Mat_Init_3X3
  1097. /////////////////////////////////////////////////////////////////
  1098.  int Mat_Inverse_3X3(MATRIX3X3_PTR m, MATRIX3X3_PTR mi)
  1099. {
  1100. // this function computes the inverse of a 3x3
  1101. // first compute the determinate to see if there is 
  1102. // an inverse
  1103. float det = m->M00*(m->M11*m->M22 - m->M21*m->M12) - 
  1104.             m->M01*(m->M10*m->M22 - m->M20*m->M12) + 
  1105.             m->M02*(m->M10*m->M21 - m->M20*m->M11);
  1106. if (fabs(det) < EPSILON_E5)
  1107.    return(0);
  1108. // compute inverse to save divides
  1109. float det_inv = 1.0/det;
  1110. // compute inverse using m-1 = adjoint(m)/det(m)
  1111. mi->M00 =  det_inv*(m->M11*m->M22 - m->M21*m->M12);
  1112. mi->M10 = -det_inv*(m->M10*m->M22 - m->M20*m->M12);
  1113. mi->M20 =  det_inv*(m->M10*m->M21 - m->M20*m->M11);
  1114. mi->M01 = -det_inv*(m->M01*m->M22 - m->M21*m->M02);
  1115. mi->M11 =  det_inv*(m->M00*m->M22 - m->M20*m->M02);
  1116. mi->M21 = -det_inv*(m->M00*m->M21 - m->M20*m->M01);
  1117. mi->M02 =  det_inv*(m->M01*m->M12 - m->M11*m->M02);
  1118. mi->M12 = -det_inv*(m->M00*m->M12 - m->M10*m->M02);
  1119. mi->M22 =  det_inv*(m->M00*m->M11 - m->M10*m->M01);
  1120. // return success
  1121. return(1);
  1122. } // end Mat_Inverse_3X3
  1123. /////////////////////////////////////////////////////////////////
  1124. void Print_Mat_3X3(MATRIX3X3_PTR ma, char *name="M")
  1125. {
  1126. // prints out a 3x3 matrix
  1127. Write_Error("n%s=n",name);
  1128. for (int r=0; r < 3; r++, Write_Error("n"))
  1129.     for (int c=0; c < 3; c++)
  1130.         Write_Error("%f ",ma->M[r][c]);        
  1131. } // end Print_Mat_3X3
  1132. /////////////////////////////////////////////////////////////////
  1133. float Mat_Det_3X3(MATRIX3X3_PTR m)
  1134. {
  1135. // computes the determinate of a 3x3 matrix using co-factor
  1136. // expansion
  1137. return(m->M00*(m->M11*m->M22 - m->M21*m->M12) - 
  1138.        m->M01*(m->M10*m->M22 - m->M20*m->M12) + 
  1139.        m->M02*(m->M10*m->M21 - m->M20*m->M11) );
  1140. } // end Mat_Det_3X3
  1141. ///////////////////////////////////////////////////////////////
  1142. int Solve_3X3_System(MATRIX3X3_PTR A, MATRIX1X3_PTR X, MATRIX1X3_PTR B)
  1143. {
  1144. // solves the system AX=B and computes X=A(-1)*B
  1145. // by using cramers rule and determinates
  1146. // step 1: compute determinate of A
  1147. float det_A = Mat_Det_3X3(A);
  1148. // test if det(a) is zero, if so then there is no solution
  1149. if (fabs(det_A) < EPSILON_E5)
  1150.    return(0);
  1151. // step 2: create x,y,z numerator matrices by taking A and
  1152. // replacing each column of it with B(transpose) and solve
  1153. MATRIX3X3 work_mat; // working matrix
  1154. // solve for x /////////////////
  1155. // copy A into working matrix
  1156. MAT_COPY_3X3(A, &work_mat);
  1157. // swap out column 0 (x column)
  1158. MAT_COLUMN_SWAP_3X3(&work_mat, 0, B);
  1159. // compute determinate of A with B swapped into x column
  1160. float det_ABx = Mat_Det_3X3(&work_mat);
  1161. // now solve for X00
  1162. X->M00 = det_ABx/det_A;
  1163. // solve for y /////////////////
  1164. // copy A into working matrix
  1165. MAT_COPY_3X3(A, &work_mat);
  1166. // swap out column 1 (y column)
  1167. MAT_COLUMN_SWAP_3X3(&work_mat, 1, B);
  1168. // compute determinate of A with B swapped into y column
  1169. float det_ABy = Mat_Det_3X3(&work_mat);
  1170. // now solve for X01
  1171. X->M01 = det_ABy/det_A;
  1172. // solve for z /////////////////
  1173. // copy A into working matrix
  1174. MAT_COPY_3X3(A, &work_mat);
  1175. // swap out column 2 (z column)
  1176. MAT_COLUMN_SWAP_3X3(&work_mat, 2, B);
  1177. // compute determinate of A with B swapped into z column
  1178. float det_ABz = Mat_Det_3X3(&work_mat);
  1179. // now solve for X02
  1180. X->M02 = det_ABz/det_A;
  1181. // return success
  1182. return(1);
  1183. } // end Solve_3X3_System
  1184. ///////////////////////////////////////////////////////////////
  1185. void Mat_Add_4X4(MATRIX4X4_PTR ma, 
  1186.                  MATRIX4X4_PTR mb,
  1187.                  MATRIX4X4_PTR msum)
  1188. {
  1189. // this function adds two 4x4 matrices together and 
  1190. // and stores the result
  1191. for (int row=0; row<4; row++)
  1192.     {
  1193.     for (int col=0; col<4; col++)
  1194.         {
  1195.         // insert resulting row,col element
  1196.         msum->M[row][col] = ma->M[row][col] + mb->M[row][col];
  1197.         } // end for col
  1198.     } // end for row
  1199. } // end Mat_Add_4X4
  1200. ///////////////////////////////////////////////////////////////
  1201. void Mat_Mul_4X4(MATRIX4X4_PTR ma, 
  1202.                  MATRIX4X4_PTR mb,
  1203.                  MATRIX4X4_PTR mprod)
  1204. {
  1205. // this function multiplies two 4x4 matrices together and 
  1206. // and stores the result in mprod
  1207. // note later we will take advantage of the fact that we know
  1208. // that w=1 always, and that the last column of a 4x4 is
  1209. // always 0
  1210. for (int row=0; row<4; row++)
  1211.     {
  1212.     for (int col=0; col<4; col++)
  1213.         {
  1214.         // compute dot product from row of ma 
  1215.         // and column of mb
  1216.         float sum = 0; // used to hold result
  1217.         for (int index=0; index<4; index++)
  1218.              {
  1219.              // add in next product pair
  1220.              sum+=(ma->M[row][index]*mb->M[index][col]);
  1221.              } // end for index
  1222.         // insert resulting row,col element
  1223.         mprod->M[row][col] = sum;
  1224.         } // end for col
  1225.     } // end for row
  1226. } // end Mat_Mul_4X4
  1227. ////////////////////////////////////////////////////////////////
  1228. void Mat_Mul_1X4_4X4(MATRIX1X4_PTR ma, 
  1229.                      MATRIX4X4_PTR mb,
  1230.                      MATRIX1X4_PTR mprod)
  1231. {
  1232. // this function multiplies a 1x4 matrix against a 
  1233. // 4x4 matrix - ma*mb and stores the result
  1234. // no tricks or assumptions here, just a straight multiply
  1235.     for (int col=0; col<4; col++)
  1236.         {
  1237.         // compute dot product from row of ma 
  1238.         // and column of mb
  1239.         float sum = 0; // used to hold result
  1240.         for (int row=0; row<4; row++)
  1241.              {
  1242.              // add in next product pair
  1243.              sum+=(ma->M[row] * mb->M[row][col]);
  1244.              } // end for index
  1245.         // insert resulting col element
  1246.         mprod->M[col] = sum;
  1247.         } // end for col
  1248. } // end Mat_Mul_1X4_4X4
  1249. ////////////////////////////////////////////////////////////////////
  1250. void Mat_Mul_VECTOR3D_4X4(VECTOR3D_PTR  va, 
  1251.                           MATRIX4X4_PTR mb,
  1252.                           VECTOR3D_PTR  vprod)
  1253. {
  1254. // this function multiplies a VECTOR3D against a 
  1255. // 4x4 matrix - ma*mb and stores the result in mprod
  1256. // the function assumes that the vector refers to a 
  1257. // 4D homogenous vector, thus the function assumes that
  1258. // w=1 to carry out the multiply, also the function
  1259. // does not carry out the last column multiply since
  1260. // we are assuming w=1, there is no point
  1261.     for (int col=0; col < 3; col++)
  1262.         {
  1263.         // compute dot product from row of ma 
  1264.         // and column of mb
  1265.         float sum = 0; // used to hold result
  1266.         for (int row=0; row<3; row++)
  1267.              {
  1268.              // add in next product pair
  1269.              sum+=(va->M[row]*mb->M[row][col]);
  1270.              } // end for index
  1271.         // add in last element in column or w*mb[3][col]
  1272.         sum+=mb->M[row][col];    
  1273.  
  1274.         // insert resulting col element
  1275.         vprod->M[col] = sum;
  1276.         } // end for col
  1277. } // end Mat_Mul_VECTOR3D_4X4
  1278. ///////////////////////////////////////////////////////////////
  1279. void Mat_Mul_VECTOR3D_4X3(VECTOR3D_PTR  va, 
  1280.                           MATRIX4X3_PTR mb,
  1281.                           VECTOR3D_PTR  vprod)
  1282. {
  1283. // this function multiplies a VECTOR3D against a 
  1284. // 4x3 matrix - ma*mb and stores the result in mprod
  1285. // the function assumes that the vector refers to a 
  1286. // 4D homogenous vector, thus the function assumes that
  1287. // w=1 to carry out the multiply, also the function
  1288. // does not carry out the last column multiply since
  1289. // we are assuming w=1, there is no point
  1290.     for (int col=0; col < 3; col++)
  1291.         {
  1292.         // compute dot product from row of ma 
  1293.         // and column of mb
  1294.         float sum = 0; // used to hold result
  1295.         for (int row=0; row<3; row++)
  1296.              {
  1297.              // add in next product pair
  1298.              sum+=(va->M[row]*mb->M[row][col]);
  1299.              } // end for index
  1300.         // add in last element in column or w*mb[3][col]
  1301.         sum+=mb->M[row][col];    
  1302.  
  1303.         // insert resulting col element
  1304.         vprod->M[col] = sum;
  1305.         } // end for col
  1306. } // end Mat_Mul_VECTOR3D_4X3
  1307. ////////////////////////////////////////////////////////////////////
  1308. void Mat_Mul_VECTOR4D_4X4(VECTOR4D_PTR  va, 
  1309.                           MATRIX4X4_PTR mb,
  1310.                           VECTOR4D_PTR  vprod)
  1311. {
  1312. // this function multiplies a VECTOR4D against a 
  1313. // 4x4 matrix - ma*mb and stores the result in mprod
  1314. // the function makes no assumptions
  1315.     for (int col=0; col < 4; col++)
  1316.         {
  1317.         // compute dot product from row of ma 
  1318.         // and column of mb
  1319.         float sum = 0; // used to hold result
  1320.         for (int row=0; row<4; row++)
  1321.              {
  1322.              // add in next product pair
  1323.              sum+=(va->M[row]*mb->M[row][col]);
  1324.              } // end for index
  1325.         // insert resulting col element
  1326.         vprod->M[col] = sum;
  1327.         } // end for col
  1328. } // end Mat_Mul_VECTOR4D_4X4
  1329. ////////////////////////////////////////////////////////////////////
  1330. void Mat_Mul_VECTOR4D_4X3(VECTOR4D_PTR  va, 
  1331.                           MATRIX4X4_PTR mb,
  1332.                           VECTOR4D_PTR  vprod)
  1333. {
  1334. // this function multiplies a VECTOR4D against a 
  1335. // 4x3 matrix - ma*mb and stores the result in mprod
  1336. // the function assumes that the last column of
  1337. // mb is [0 0 0 1]t , thus w just gets replicated
  1338. // from the vector [x y z w]
  1339.     for (int col=0; col < 3; col++)
  1340.         {
  1341.         // compute dot product from row of ma 
  1342.         // and column of mb
  1343.         float sum = 0; // used to hold result
  1344.         for (int row=0; row<4; row++)
  1345.              {
  1346.              // add in next product pair
  1347.              sum+=(va->M[row]*mb->M[row][col]);
  1348.              } // end for index
  1349.         // insert resulting col element
  1350.         vprod->M[col] = sum;
  1351.         } // end for col
  1352.      // copy back w element
  1353.      vprod->M[3] = va->M[3];
  1354. } // end Mat_Mul_VECTOR4D_4X3
  1355. ///////////////////////////////////////////////////////////////
  1356. void Mat_Init_4X4(MATRIX4X4_PTR ma, 
  1357.                  float m00, float m01, float m02, float m03,
  1358.                  float m10, float m11, float m12, float m13,
  1359.                  float m20, float m21, float m22, float m23,
  1360.                  float m30, float m31, float m32, float m33)
  1361. {
  1362. // this function fills a 4x4 matrix with the sent data in 
  1363. // row major form
  1364. ma->M00 = m00; ma->M01 = m01; ma->M02 = m02; ma->M03 = m03;
  1365. ma->M10 = m10; ma->M11 = m11; ma->M12 = m12; ma->M13 = m13;
  1366. ma->M20 = m20; ma->M21 = m21; ma->M22 = m22; ma->M23 = m23;
  1367. ma->M30 = m30; ma->M31 = m31; ma->M32 = m32; ma->M33 = m33;
  1368. } // end Mat_Init_4X4
  1369. ////////////////////////////////////////////////////////////////
  1370. int Mat_Inverse_4X4(MATRIX4X4_PTR m, MATRIX4X4_PTR mi)
  1371. {
  1372. // computes the inverse of a 4x4, assumes that the last
  1373. // column is [0 0 0 1]t
  1374. float det =  ( m->M00 * ( m->M11 * m->M22 - m->M12 * m->M21 ) -
  1375.                m->M01 * ( m->M10 * m->M22 - m->M12 * m->M20 ) +
  1376.                m->M02 * ( m->M10 * m->M21 - m->M11 * m->M20 ) );
  1377. // test determinate to see if it's 0
  1378. if (fabs(det) < EPSILON_E5)
  1379.    return(0);
  1380. float det_inv  = 1.0f / det;
  1381. mi->M00 =  det_inv * ( m->M11 * m->M22 - m->M12 * m->M21 );
  1382. mi->M01 = -det_inv * ( m->M01 * m->M22 - m->M02 * m->M21 );
  1383. mi->M02 =  det_inv * ( m->M01 * m->M12 - m->M02 * m->M11 );
  1384. mi->M03 = 0.0f; // always 0
  1385. mi->M10 = -det_inv * ( m->M10 * m->M22 - m->M12 * m->M20 );
  1386. mi->M11 =  det_inv * ( m->M00 * m->M22 - m->M02 * m->M20 );
  1387. mi->M12 = -det_inv * ( m->M00 * m->M12 - m->M02 * m->M10 );
  1388. mi->M13 = 0.0f; // always 0
  1389. mi->M20 =  det_inv * ( m->M10 * m->M21 - m->M11 * m->M20 );
  1390. mi->M21 = -det_inv * ( m->M00 * m->M21 - m->M01 * m->M20 );
  1391. mi->M22 =  det_inv * ( m->M00 * m->M11 - m->M01 * m->M10 );
  1392. mi->M23 = 0.0f; // always 0
  1393. mi->M30 = -( m->M30 * mi->M00 + m->M31 * mi->M10 + m->M32 * mi->M20 );
  1394. mi->M31 = -( m->M30 * mi->M01 + m->M31 * mi->M11 + m->M32 * mi->M21 );
  1395. mi->M32 = -( m->M30 * mi->M02 + m->M31 * mi->M12 + m->M32 * mi->M22 );
  1396. mi->M33 = 1.0f; // always 0
  1397. // return success 
  1398. return(1);
  1399. } // end Mat_Inverse_4X4
  1400. /////////////////////////////////////////////////////////////////
  1401. void Print_Mat_4X4(MATRIX4X4_PTR ma, char *name="M")
  1402. {
  1403. // prints out a 4x4 matrix
  1404. Write_Error("n%s=n",name);
  1405. for (int r=0; r < 4; r++, Write_Error("n"))
  1406.     for (int c=0; c < 4; c++)
  1407.         Write_Error("%f ",ma->M[r][c]);        
  1408. } // end Print_Mat_4X4
  1409. /////////////////////////////////////////////////////////////////
  1410. void Init_Parm_Line2D(POINT2D_PTR p_init, 
  1411.                       POINT2D_PTR p_term, PARMLINE2D_PTR p)
  1412. {
  1413. // this initializes a parametric 2d line, note that the function
  1414. // computes v=p_pend - p_init, thus when t=0 the line p=p0+v*t = p0
  1415. // and whne t=1, p=p1, this way the segement is traced out from
  1416. // p0 to p1 via 0<= t <= 1
  1417. // start point
  1418. VECTOR2D_INIT(&(p->p0), p_init);
  1419. // end point
  1420. VECTOR2D_INIT(&(p->p1), p_term);
  1421. // now compute direction vector from p0->p1
  1422. VECTOR2D_Build(p_init, p_term, &(p->v));
  1423. } // end Init_Parm_Line2D
  1424. /////////////////////////////////////////////////////////////////
  1425. void Init_Parm_Line3D(POINT3D_PTR p_init, 
  1426.                       POINT3D_PTR p_term, PARMLINE3D_PTR p)
  1427. {
  1428. // this initializes a parametric 3d line, note that the function
  1429. // computes v=p_pend - p_init, thus when t=0 the line p=p0+v*t = p0
  1430. // and whne t=1, p=p1, this way the segement is traced out from
  1431. // p0 to p1 via 0<= t <= 1
  1432. // start point
  1433. VECTOR3D_INIT(&(p->p0), p_init);
  1434. // end point
  1435. VECTOR3D_INIT(&(p->p1),p_term);
  1436. // now compute direction vector from p0->p1
  1437. VECTOR3D_Build(p_init, p_term, &(p->v));
  1438. } // end Init_Parm_Line3D
  1439. /////////////////////////////////////////////////////////////////
  1440. void Compute_Parm_Line2D(PARMLINE2D_PTR p, float t, POINT2D_PTR pt)
  1441. {
  1442. // this function computes the value of the sent parametric 
  1443. // line at the value of t
  1444. pt->x = p->p0.x + p->v.x*t;
  1445. pt->y = p->p0.y + p->v.y*t;
  1446. } // end Compute_Parm_Line2D
  1447. ///////////////////////////////////////////////////////////////
  1448. void Compute_Parm_Line3D(PARMLINE3D_PTR p, float t, POINT3D_PTR pt)
  1449. {
  1450. // this function computes the value of the sent parametric 
  1451. // line at the value of t
  1452. pt->x = p->p0.x + p->v.x*t;
  1453. pt->y = p->p0.y + p->v.y*t;
  1454. pt->z = p->p0.z + p->v.z*t;
  1455. } // end Compute_Parm_Line3D
  1456. ///////////////////////////////////////////////////////////////////
  1457. int Intersect_Parm_Lines2D(PARMLINE2D_PTR p1, PARMLINE2D_PTR p2, 
  1458.                            float *t1, float *t2)
  1459. {
  1460. // this function computes the interesection of the two parametric 
  1461. // line segments the function returns true if the segments 
  1462. // interesect and sets the values of t1 and t2 to the t values that 
  1463. // the intersection occurs on the lines p1 and p2 respectively, 
  1464. // however, the function may send back t value not in the range [0,1]
  1465. // this means that the segments don't intersect, but the lines that 
  1466. // they represent do, thus a retun of 0 means no intersection, a 
  1467. // 1 means intersection on the segments and a 2 means the lines 
  1468. // intersect, but not necessarily the segments and 3 means that 
  1469. // the lines are the same, thus they intersect everywhere
  1470. // basically we have a system of 2d linear equations, we need
  1471. // to solve for t1, t2 when x,y are both equal (if that's possible)
  1472. // step 1: test for parallel lines, if the direction vectors are 
  1473. // scalar multiples then the lines are parallel and can't possible
  1474. // intersect unless the lines overlap
  1475. float det_p1p2 = (p1->v.x*p2->v.y - p1->v.y*p2->v.x);
  1476. if (fabs(det_p1p2) <= EPSILON_E5)
  1477.    {
  1478.    // at this point, the lines either don't intersect at all
  1479.    // or they are the same lines, in which case they may intersect
  1480.    // at one or many points along the segments, at this point we 
  1481.    // will assume that the lines don't intersect at all, but later
  1482.    // we may need to rewrite this function and take into 
  1483.    // consideration the overlap and singular point exceptions
  1484.    return(PARM_LINE_NO_INTERSECT);
  1485.    } // end if
  1486. // step 2: now compute the t1, t2 values for intersection
  1487. // we have two lines of the form
  1488. // p    = p0    +  v*t, specifically
  1489. // p1   = p10   + v1*t1
  1490. // p1.x = p10.x + v1.x*t1
  1491. // p1.y = p10.y + v1.y*t1
  1492. // p2 = p20 + v2*t2
  1493. // p2   = p20   + v2*t2
  1494. // p2.x = p20.x + v2.x*t2
  1495. // p2.y = p20.y + v2.y*t2
  1496. // solve the system when x1 = x2 and y1 = y2
  1497. // explained in chapter 4
  1498. *t1 = (p2->v.x*(p1->p0.y - p2->p0.y) - p2->v.y*(p1->p0.x - p2->p0.x)) 
  1499.       /det_p1p2;
  1500. *t2 = (p1->v.x*(p1->p0.y - p2->p0.y) - p1->v.y*(p1->p0.x - p2->p0.x))
  1501.       /det_p1p2;
  1502. // test if the lines intersect on the segments
  1503. if ((*t1>=0) && (*t1<=1) && (*t2>=0) && (*t2<=1))
  1504.    return(PARM_LINE_INTERSECT_IN_SEGMENT);
  1505. else
  1506.    return(PARM_LINE_INTERSECT_OUT_SEGMENT);
  1507. } // end Intersect_Parm_Lines2D
  1508. ///////////////////////////////////////////////////////////////
  1509. int Intersect_Parm_Lines2D(PARMLINE2D_PTR p1, PARMLINE2D_PTR p2, POINT2D_PTR pt)
  1510. {
  1511. // this function computes the interesection of the two 
  1512. // parametric line segments the function returns true if 
  1513. // the segments interesect and sets the values of pt to the 
  1514. // intersection point, however, the function may send back a 
  1515. // value not in the range [0,1] on the segments this means 
  1516. // that the segments don't intersect, but the lines that 
  1517. // they represent do, thus a retun of 0 means no intersection, 
  1518. // a 1 means intersection on the segments and a 2 means 
  1519. // the lines intersect, but not necessarily the segments
  1520. // basically we have a system of 2d linear equations, we need
  1521. // to solve for t1, t2 when x,y are both equal (if that's possible)
  1522. // step 1: test for parallel lines, if the direction vectors are 
  1523. // scalar multiples then the lines are parallel and can't possible
  1524. // intersect
  1525. float t1, t2, det_p1p2 = (p1->v.x*p2->v.y - p1->v.y*p2->v.x);
  1526. if (fabs(det_p1p2) <= EPSILON_E5)
  1527.    {
  1528.    // at this point, the lines either don't intersect at all
  1529.    // or they are the same lines, in which case they may intersect
  1530.    // at one or many points along the segments, at this point we 
  1531.    // will assume that the lines don't intersect at all, but later
  1532.    // we may need to rewrite this function and take into 
  1533.    // consideration the overlap and singular point exceptions
  1534.    return(PARM_LINE_NO_INTERSECT);
  1535.    } // end if
  1536. // step 2: now compute the t1, t2 values for intersection
  1537. // we have two lines of the form
  1538. // p    = p0    +  v*t, specifically
  1539. // p1   = p10   + v1*t1
  1540. // p1.x = p10.x + v1.x*t1
  1541. // p1.y = p10.y + v1.y*t1
  1542. // p2 = p20 + v2*t2
  1543. // p2   = p20   + v2*t2
  1544. // p2.x = p20.x + v2.x*t2
  1545. // p2.y = p20.y + v2.y*t2
  1546. // solve the system when x1 = x2 and y1 = y2
  1547. // explained in chapter 4
  1548. t1 = (p2->v.x*(p1->p0.y - p2->p0.y) - p2->v.y*(p1->p0.x - p2->p0.x))
  1549.      /det_p1p2;
  1550. t2 = (p1->v.x*(p1->p0.y - p2->p0.y) - p1->v.y*(p1->p0.x - p2->p0.x))
  1551.      /det_p1p2;
  1552. // now compute point of intersection
  1553. pt->x = p1->p0.x + p1->v.x*t1;
  1554. pt->y = p1->p0.y + p1->v.y*t1;
  1555. // test if the lines intersect on the segments
  1556. if ((t1>=0) && (t1<=1) && (t2>=0) && (t2<=1))
  1557.    return(PARM_LINE_INTERSECT_IN_SEGMENT);
  1558. else
  1559.    return(PARM_LINE_INTERSECT_OUT_SEGMENT);
  1560. } // end Intersect_Parm_Lines2D
  1561. ///////////////////////////////////////////////////////////////
  1562. void PLANE3D_Init(PLANE3D_PTR plane, POINT3D_PTR p0, 
  1563.                   VECTOR3D_PTR normal, int normalize=0)
  1564. {
  1565. // this function initializes a 3d plane
  1566. // copy the point
  1567. POINT3D_COPY(&plane->p0, p0);
  1568. // if normalize is 1 then the normal is made into a unit vector
  1569. if (!normalize)
  1570.    VECTOR3D_COPY(&plane->n, normal);
  1571. else
  1572.    {
  1573.    // make normal into unit vector
  1574.    VECTOR3D_Normalize(normal,&plane->n);
  1575.    } // end else
  1576. } // end PLANE3D_Init
  1577. //////////////////////////////////////////////////////////////
  1578.  float Compute_Point_In_Plane3D(POINT3D_PTR pt, PLANE3D_PTR plane)
  1579. {
  1580. // test if the point in on the plane, in the positive halfspace
  1581. // or negative halfspace
  1582. float hs = plane->n.x*(pt->x - plane->p0.x) + 
  1583.            plane->n.y*(pt->y - plane->p0.y) +
  1584.            plane->n.z*(pt->z - plane->p0.z); 
  1585. // return half space value
  1586. return(hs);
  1587. } // end Compute_Point_In_Plane3D
  1588. ///////////////////////////////////////////////////////////////
  1589. int Intersect_Parm_Line3D_Plane3D(PARMLINE3D_PTR pline, 
  1590.                                          PLANE3D_PTR plane, 
  1591.                                          float *t, POINT3D_PTR pt)
  1592. {
  1593. // this function determines where the sent parametric line 
  1594. // intersects the plane the function will project the line 
  1595. // infinitely in both directions, to compute the intersection, 
  1596. // but the line segment defined by p intersected the plane iff t e [0,1]
  1597. // also the function returns 0 for no intersection, 1 for 
  1598. // intersection of the segment and the plane and 2 for intersection 
  1599. // of the line along the segment and the plane 3, the line lies 
  1600. // in the plane
  1601. // first test of the line and the plane are parallel, if so 
  1602. // then they can't intersect unless the line lies in the plane!
  1603. float plane_dot_line = VECTOR3D_Dot(&pline->v, &plane->n);
  1604. if (fabs(plane_dot_line) <= EPSILON_E5)
  1605.    {
  1606.    // the line and plane are co-planer, does the line lie 
  1607.    // in the plane?
  1608.    if (fabs(Compute_Point_In_Plane3D(&pline->p0, plane)) <= EPSILON_E5)
  1609.       return(PARM_LINE_INTERSECT_EVERYWHERE);
  1610.    else
  1611.       return(PARM_LINE_NO_INTERSECT);
  1612.    } // end if
  1613. // from chapter 4 we know that we can solve for the t where 
  1614. // intersection occurs by
  1615. // a*(x0+vx*t) + b*(y0+vy*t) + c*(z0+vz*t) + d =0
  1616. // t = -(a*x0 + b*y0 + c*z0 + d)/(a*vx + b*vy + c*vz)
  1617. // x0,y0,z0, vx,vy,vz, define the line
  1618. // d = (-a*xp0 - b*yp0 - c*zp0), xp0, yp0, zp0, define the point on the plane 
  1619. *t = -(plane->n.x*pline->p0.x + 
  1620.        plane->n.y*pline->p0.y + 
  1621.        plane->n.z*pline->p0.z -
  1622.        plane->n.x*plane->p0.x - 
  1623.        plane->n.y*plane->p0.y - 
  1624.        plane->n.z*plane->p0.z) / (plane_dot_line);
  1625.    
  1626. // now plug t into the parametric line and solve for x,y,z
  1627. pt->x = pline->p0.x + pline->v.x*(*t);
  1628. pt->y = pline->p0.y + pline->v.y*(*t);
  1629. pt->z = pline->p0.z + pline->v.z*(*t);
  1630. // test interval of t
  1631. if (*t>=0.0 && *t<=1.0)
  1632.    return(PARM_LINE_INTERSECT_IN_SEGMENT );
  1633. else
  1634.    return(PARM_LINE_INTERSECT_OUT_SEGMENT);
  1635. } // end Intersect_Parm_Line3D_Plane3D
  1636. /////////////////////////////////////////////////////////////////