1 /*******************************************************************************
2 
3    MATHTOOLS.C
4 
5    Author: Peter Loan
6 
7    Date: 8-DEC-88
8 
9    Copyright (c) 1992-5 MusculoGraphics, Inc.
10    All rights reserved.
11    Portions of this source code are copyrighted by MusculoGraphics, Inc.
12 
13    Description: This file contains routines that implement various
14       mathematical tools and functions. Every one operates exclusively
15       on the formal parameter list, and so does not change any external
16       variables or other general model or plot structures.
17 
18    Routines:
19       get_array_length      : gets the length of an integer array
20       mult_4x4matrix_by_vector : multiplies a vector by a matrix
21       mult_4x4matrices      : multiplies two 4x4 matrices
22       transpose_4x4matrix   : transposes a 4x4 matrix
23       cross_vectors         : finds cros product of two vectors
24       normalize_vector      : normalizes a vector
25       calc_function_coefficients : finds coefficients of a function
26       interpolate_function    : given an x, interpolates a cubic to get a y value
27       format_double         : determines appropriate printf format for a number
28       reset_4x4matrix       : sets a 4x4 matrix equal to the identity matrix
29       make_4x4dircos_matrix : makes direction cosine matrix given angle & axis
30 
31 *******************************************************************************/
32 
33 #include "universal.h"
34 #include "functions.h"
35 
36 
37 /*************** DEFINES (for this file only) *********************************/
38 #define LINE_EPSILON 0.00001
39 
40 
41 /*************** STATIC GLOBAL VARIABLES (for this file only) *****************/
42 
43 
44 
45 /*************** EXTERNED VARIABLES (declared in another file) ****************/
46 
47 
48 
49 /*************** PROTOTYPES for STATIC FUNCTIONS (for this file only) *********/
50 static void quat_to_axis_angle_rot(const Quat, dpCoord3D* axis, double* angle);
51 static void matrix_to_quat(double m[][4], Quat);
52 static void make_quaternion(Quat, const double axis[3], double angle);
53 static void quat_to_matrix(const Quat q, double m[][4]);
54 static void rotate_matrix_by_quat(double m[][4], const Quat);
55 
56 
57 /* GET_ARRAY_LENGTH: get the length of an array of ints. The end is
58  * marked by the END_OF_ARRAY constant.
59  */
get_array_length(int list[])60 int get_array_length(int list[])
61 {
62    int i = 0;
63 
64    while (list[i] != END_OF_ARRAY)
65      i++;
66 
67    return i;
68 }
69 
70 
71 /* MULT_4X4MATRIX_BY_VECTOR: this routine premultiplies a 4x4 matrix by
72  * a 1x4 vector. That is, it does vector*mat, not mat*vector.
73  */
74 
mult_4x4matrix_by_vector(double mat[][4],double vector[],double result[])75 void mult_4x4matrix_by_vector(double mat[][4], double vector[], double result[])
76 {
77 
78    result[0] = vector[0]*mat[0][0] + vector[1]*mat[1][0] +
79                vector[2]*mat[2][0] + vector[3]*mat[3][0];
80    result[1] = vector[0]*mat[0][1] + vector[1]*mat[1][1] +
81                vector[2]*mat[2][1] + vector[3]*mat[3][1];
82    result[2] = vector[0]*mat[0][2] + vector[1]*mat[1][2] +
83                vector[2]*mat[2][2] + vector[3]*mat[3][2];
84    result[3] = vector[0]*mat[0][3] + vector[1]*mat[1][3] +
85                vector[2]*mat[2][3] + vector[3]*mat[3][3];
86 
87 }
88 
89 
90 
91 /* MULT_4X4MATRICES: this routine multiplies the two specified 4x4 matrices
92  * in the order: mat1*mat2.
93  */
94 
mult_4x4matrices(double mat1[][4],double mat2[][4],double result[][4])95 void mult_4x4matrices(double mat1[][4], double mat2[][4], double result[][4])
96 {
97 
98    result[0][0] = mat1[0][0]*mat2[0][0] + mat1[0][1]*mat2[1][0] +
99       mat1[0][2]*mat2[2][0] + mat1[0][3]*mat2[3][0];
100 
101    result[0][1] = mat1[0][0]*mat2[0][1] + mat1[0][1]*mat2[1][1] +
102       mat1[0][2]*mat2[2][1] + mat1[0][3]*mat2[3][1];
103 
104    result[0][2] = mat1[0][0]*mat2[0][2] + mat1[0][1]*mat2[1][2] +
105       mat1[0][2]*mat2[2][2] + mat1[0][3]*mat2[3][2];
106 
107    result[0][3] = mat1[0][0]*mat2[0][3] + mat1[0][1]*mat2[1][3] +
108       mat1[0][2]*mat2[2][3] + mat1[0][3]*mat2[3][3];
109 
110 
111    result[1][0] = mat1[1][0]*mat2[0][0] + mat1[1][1]*mat2[1][0] +
112       mat1[1][2]*mat2[2][0] + mat1[1][3]*mat2[3][0];
113 
114    result[1][1] = mat1[1][0]*mat2[0][1] + mat1[1][1]*mat2[1][1] +
115       mat1[1][2]*mat2[2][1] + mat1[1][3]*mat2[3][1];
116 
117    result[1][2] = mat1[1][0]*mat2[0][2] + mat1[1][1]*mat2[1][2] +
118       mat1[1][2]*mat2[2][2] + mat1[1][3]*mat2[3][2];
119 
120    result[1][3] = mat1[1][0]*mat2[0][3] + mat1[1][1]*mat2[1][3] +
121       mat1[1][2]*mat2[2][3] + mat1[1][3]*mat2[3][3];
122 
123 
124    result[2][0] = mat1[2][0]*mat2[0][0] + mat1[2][1]*mat2[1][0] +
125       mat1[2][2]*mat2[2][0] + mat1[2][3]*mat2[3][0];
126 
127    result[2][1] = mat1[2][0]*mat2[0][1] + mat1[2][1]*mat2[1][1] +
128       mat1[2][2]*mat2[2][1] + mat1[2][3]*mat2[3][1];
129 
130    result[2][2] = mat1[2][0]*mat2[0][2] + mat1[2][1]*mat2[1][2] +
131       mat1[2][2]*mat2[2][2] + mat1[2][3]*mat2[3][2];
132 
133    result[2][3] = mat1[2][0]*mat2[0][3] + mat1[2][1]*mat2[1][3] +
134       mat1[2][2]*mat2[2][3] + mat1[2][3]*mat2[3][3];
135 
136 
137    result[3][0] = mat1[3][0]*mat2[0][0] + mat1[3][1]*mat2[1][0] +
138       mat1[3][2]*mat2[2][0] + mat1[3][3]*mat2[3][0];
139 
140    result[3][1] = mat1[3][0]*mat2[0][1] + mat1[3][1]*mat2[1][1] +
141       mat1[3][2]*mat2[2][1] + mat1[3][3]*mat2[3][1];
142 
143    result[3][2] = mat1[3][0]*mat2[0][2] + mat1[3][1]*mat2[1][2] +
144       mat1[3][2]*mat2[2][2] + mat1[3][3]*mat2[3][2];
145 
146    result[3][3] = mat1[3][0]*mat2[0][3] + mat1[3][1]*mat2[1][3] +
147       mat1[3][2]*mat2[2][3] + mat1[3][3]*mat2[3][3];
148 
149 }
150 
151 
152 /* APPEND_4X4MATRIX: multiplies mat1 by mat2 and stores the
153  * result in mat1.
154  */
155 
append_4x4matrix(double mat1[][4],double mat2[][4])156 void append_4x4matrix(double mat1[][4], double mat2[][4])
157 {
158 
159    int i, j;
160    double mat[4][4];
161 
162    mult_4x4matrices(mat1,mat2,mat);
163 
164    for (i=0; i<4; i++)
165       for (j=0; j<4; j++)
166      mat1[i][j] = mat[i][j];
167 
168 }
169 
170 
171 /* TRANSPOSE_4X4MATRIX: this routine transposes a 4x4 matrix */
172 
transpose_4x4matrix(double mat[][4],double mat_transpose[][4])173 void transpose_4x4matrix(double mat[][4], double mat_transpose[][4])
174 {
175 
176    int i, j;
177 
178    for (i=0; i<4; i++)
179       for (j=0; j<4; j++)
180          mat_transpose[j][i] = mat[i][j];
181 
182 }
183 
184 
185 /* MAKE_TRANSLATION_MATRIX: makes a 4x4 matrix with either an X, Y, or Z
186  * translation.
187  */
188 
make_translation_matrix(double mat[][4],int axis,double trans)189 void make_translation_matrix(double mat[][4], int axis, double trans)
190 {
191 
192    reset_4x4matrix(mat);
193 
194    mat[3][axis] = trans;
195 
196 }
197 
198 
199 /* MAKE_SCALE_MATRIX: makes a 4x4 matrix with either an X, Y, or Z
200  * scale.
201  */
202 
make_scale_matrix(double mat[][4],int axis,double scale)203 void make_scale_matrix(double mat[][4], int axis, double scale)
204 {
205 
206    reset_4x4matrix(mat);
207 
208    mat[axis][axis] = scale;
209 
210 }
211 
212 
213 /* CROSS_VECTORS: computes the cross product of two 1x3 vectors */
214 
cross_vectors(double vector1[],double vector2[],double result[])215 void cross_vectors(double vector1[], double vector2[], double result[])
216 {
217 
218    result[0] = vector1[1]*vector2[2] - vector1[2]*vector2[1];
219    result[1] = vector1[2]*vector2[0] - vector1[0]*vector2[2];
220    result[2] = vector1[0]*vector2[1] - vector1[1]*vector2[0];
221 
222 }
223 
224 
225 /* NORMALIZE_VECTOR: normalizes a 1x3 vector. */
normalize_vector(double vector[],double norm_vector[])226 double normalize_vector(double vector[], double norm_vector[])
227 {
228    double magnitude;
229 
230    magnitude = VECTOR_MAGNITUDE(vector);
231 
232    if (magnitude < TINY_NUMBER)
233    {
234       norm_vector[0] = vector[0];
235       norm_vector[1] = vector[1];
236       norm_vector[2] = vector[2];
237    }
238    else
239    {
240       norm_vector[0] = vector[0]/magnitude;
241       norm_vector[1] = vector[1]/magnitude;
242       norm_vector[2] = vector[2]/magnitude;
243    }
244 
245    return magnitude;
246 }
247 
248 
249 /* NORMALIZE_VECTOR: normalizes a 1x3 vector. */
normalize_vector_f(float vector[],float norm_vector[])250 double normalize_vector_f(float vector[], float norm_vector[])
251 {
252    float magnitude;
253 
254    magnitude = VECTOR_MAGNITUDE(vector);
255 
256    if (magnitude < TINY_NUMBER)
257    {
258       norm_vector[0] = vector[0];
259       norm_vector[1] = vector[1];
260       norm_vector[2] = vector[2];
261    }
262    else
263    {
264       norm_vector[0] = vector[0]/magnitude;
265       norm_vector[1] = vector[1]/magnitude;
266       norm_vector[2] = vector[2]/magnitude;
267    }
268 
269    return magnitude;
270 }
271 
272 
273 /* FORMAT_DOUBLE: this routine finds a good format (printf style) for a given
274  * number by checking its magnitude. For example, if the number is greater than
275  * 50, you don't really need to show any decimal places, but if the number is
276  * less than 0.01, you should show several decimal places.
277  */
278 
format_double(double number,char format[])279 void format_double(double number, char format[])
280 {
281 
282    if (number > 50.0)
283       (void)strcpy(format,"%.3lf");
284    else if (number > 10.0)
285       (void)strcpy(format,"%.4lf");
286    else if (number > 1.0)
287       (void)strcpy(format,"%.5lf");
288    else if (number > 0.1)
289       (void)strcpy(format,"%.6lf");
290    else if (number > 0.01)
291       (void)strcpy(format,"%.7lf");
292    else
293       (void)strcpy(format,"%.8lf");
294 
295 }
296 
297 
298 /* RESET_4X4MATRIX: this routine sets a 4x4 matrix equal to the identity matrix */
299 
reset_4x4matrix(double mat[][4])300 void reset_4x4matrix(double mat[][4])
301 {
302 
303    mat[0][1] = mat[0][2] = mat[0][3] = 0.0;
304    mat[1][0] = mat[1][2] = mat[1][3] = 0.0;
305    mat[2][0] = mat[2][1] = mat[2][3] = 0.0;
306    mat[3][0] = mat[3][1] = mat[3][2] = 0.0;
307 
308    mat[0][0] = mat[1][1] = mat[2][2] = mat[3][3] = 1.0;
309 
310 }
311 
312 
313 /* MAKE_4X4DIRCOS_MATRIX: this routine creates a 4x4 direction cosine matrix
314  * given an arbitrarily oriented axis and a rotation angle in degrees.
315  */
316 
make_4x4dircos_matrix(double angle,double axis[],double mat[][4])317 void make_4x4dircos_matrix(double angle, double axis[], double mat[][4])
318 {
319 
320    double rad_angle, cl, sl, omc;
321 
322    reset_4x4matrix(mat);
323    normalize_vector(axis,axis);
324 
325    rad_angle = angle*DTOR;
326 
327    cl = cos(rad_angle);
328    sl = sin(rad_angle);
329    omc = 1.0 - cl;
330 
331    /* the following matrix is taken from Kane's 'Spacecraft Dynamics,' pp 6-7 */
332 
333    mat[0][0] = cl + axis[XX]*axis[XX]*omc;
334    mat[1][0] = -axis[ZZ]*sl + axis[XX]*axis[YY]*omc;
335    mat[2][0] = axis[YY]*sl + axis[ZZ]*axis[XX]*omc;
336    mat[0][1] = axis[ZZ]*sl + axis[XX]*axis[YY]*omc;
337    mat[1][1] = cl + axis[YY]*axis[YY]*omc;
338    mat[2][1] = -axis[XX]*sl + axis[YY]*axis[ZZ]*omc;
339    mat[0][2] = -axis[YY]*sl + axis[ZZ]*axis[XX]*omc;
340    mat[1][2] = axis[XX]*sl + axis[YY]*axis[ZZ]*omc;
341    mat[2][2] = cl + axis[ZZ]*axis[ZZ]*omc;
342 
343 }
344 
345 
346 /* VECTOR_INTERSECTS_POLYHEDRON: This function checks for intersection of a vector
347  * and a polyhedron.
348  */
vector_intersects_polyhedron(double pt[],double vec[],PolyhedronStruct * ph,double inter[])349 SBoolean vector_intersects_polyhedron(double pt[], double vec[], PolyhedronStruct* ph, double inter[])
350 {
351    int i;
352    double pt2[3], t;
353 
354    pt2[0] = pt[0] + vec[0];
355    pt2[1] = pt[1] + vec[1];
356    pt2[2] = pt[2] + vec[2];
357 
358    /* Check to see if the vector intersects any of the polygons in the polyhedron.
359     * intersect_line_plane() is used to get the point of intersection between the
360     * vector and the plane of the polygon, and then this point is checked to see if
361     * it is inside the boundaries of the polygon. Return the first intersection found.
362     */
363    for (i = 0; i < ph->num_polygons; i++)
364    {
365       if (intersect_line_plane(pt, pt2, ph->polygon[i].normal, ph->polygon[i].d, inter, &t) == yes &&
366          point_in_polygon3D(inter, ph, i) == yes)
367       {
368          return yes;
369       }
370    }
371 
372    return no;
373 }
374 
375 
376 /* intersection between a line (pt1,pt2) and plane (plane,d)
377  * will give the intersection point(inter) and where on the line
378  * it is (t). Ratio t should does not have to lie within 0 and 1
379  */
intersect_line_plane(double pt1[],double pt2[],double plane[],double d,double inter[],double * t)380 SBoolean intersect_line_plane(double pt1[], double pt2[],
381                               double plane[], double d, double inter[], double* t)
382 {
383    double dotprod;
384    double vec[3];
385 
386    MAKE_3DVECTOR(pt1,pt2,vec);
387    dotprod = DOT_VECTORS(vec,plane);
388 
389    if (DABS(dotprod) < LINE_EPSILON)
390       return no;
391 
392    *t = (-d - plane[0]*pt1[0] - plane[1]*pt1[1] - plane[2]*pt1[2])/dotprod;
393 
394    inter[0] = pt1[0] + ((*t) * vec[0]);
395    inter[1] = pt1[1] + ((*t) * vec[1]);
396    inter[2] = pt1[2] + ((*t) * vec[2]);
397 
398    return yes;
399 }
400 
401 /* intersection between a line (pt1,pt2) and plane (plane,d)
402 ** will give the intersection point (inter) and where on the line it is (t)
403 ** ratio t should lie within 0 and 1
404 */
intersect_line_plane01(double pt1[],double pt2[],double plane[],double d,double inter[],double * t)405 SBoolean intersect_line_plane01(double pt1[], double pt2[],
406                                 double plane[], double d, double inter[], double* t)
407 {
408    double dotprod;
409    double vec[3];
410 
411    MAKE_3DVECTOR(pt1,pt2,vec);
412    dotprod = DOT_VECTORS(vec,plane);
413 
414    if (DABS(dotprod) < LINE_EPSILON)
415       return no;
416 
417    *t = (-d - plane[0]*pt1[0] - plane[1]*pt1[1] - plane[2]*pt1[2])/dotprod;
418 
419    if ((*t < -LINE_EPSILON) || (*t > 1.0 + LINE_EPSILON))
420       return no;
421 
422    inter[0] = pt1[0] + ((*t) * vec[0]);
423    inter[1] = pt1[1] + ((*t) * vec[1]);
424    inter[2] = pt1[2] + ((*t) * vec[2]);
425 
426    return yes;
427 }
428 
429 /* POINT_IN_POLYGON3D: determines if a 3D point is inside a 3D polygon. The polygon
430  * is the first one in the PolyhedronStruct, and is assumed to be planar.
431  */
432 
point_in_polygon3D(double pt[],PolyhedronStruct * ph,int polygon_index)433 SBoolean point_in_polygon3D(double pt[], PolyhedronStruct* ph, int polygon_index)
434 {
435    int i, j, index, skip_coord;
436    double max_value, polygon[50][2], pt2D[2];
437 
438    /* if the polygon has more than 50 vertices, abort. */
439    if (ph->polygon[polygon_index].num_vertices > 50)
440       return no;
441 
442    /* Project the polygon onto one of the major planes by ignoring one of the
443     * coordinates. Ignore the one most parallel to the plane's normal so that
444     * the area of the projected polygon will be as large as possible.
445     */
446    skip_coord = XX;
447    max_value = DABS(ph->polygon[polygon_index].normal[XX]);
448    if (DABS(ph->polygon[polygon_index].normal[YY]) > max_value)
449    {
450       skip_coord = YY;
451       max_value = DABS(ph->polygon[polygon_index].normal[YY]);
452    }
453    if (DABS(ph->polygon[polygon_index].normal[ZZ]) > max_value)
454       skip_coord = ZZ;
455 
456    /* Copy the vertices into a 2D array, skipping the skip_coord */
457    for (i = 0; i < ph->polygon[polygon_index].num_vertices; i++)
458    {
459       for (j = 0, index = 0; j < 3; j++)
460       {
461          if (j != skip_coord)
462             polygon[i][index++] = ph->vertex[ph->polygon[polygon_index].vertex_index[i]].coord[j];
463       }
464    }
465 
466    /* Copy the 3D point into a 2D point, skipping the skip_coord */
467    for (i = 0, index = 0; i < 3; i++)
468    {
469       if (i != skip_coord)
470          pt2D[index++] = pt[i];
471    }
472 
473    if (point_in_polygon2D(pt2D, polygon, ph->polygon[polygon_index].num_vertices))
474       return yes;
475 
476    return no;
477 }
478 
479 
480 /* POINT_IN_POLYGON2D: determines if a 2D point is inside a 2D polygon. Uses the
481  * "crossings test" taken from:
482  * Haines, Eric, "Point in Polygon Strategies," Graphics Gems IV, ed. Paul Heckbert,
483  * Academic Press, p. 24-46, 1994.
484  * Shoot a test ray along +X axis. The strategy, from MacMartin, is to
485  * compare vertex Y values to the testing point's Y and quickly discard
486  * edges which are entirely to one side of the test ray.
487  *
488  * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
489  * _point_, returns 1 if inside, 0 if outside.
490  */
491 
point_in_polygon2D(double point[],double pgon[][2],int numverts)492 int point_in_polygon2D(double point[], double pgon[][2], int numverts)
493 {
494    register int j, yflag0, yflag1, inside_flag, xflag0 ;
495    register double ty, tx, *vtx0, *vtx1 ;
496 
497    tx = point[XX];
498    ty = point[YY];
499 
500    vtx0 = pgon[numverts-1];
501 
502    /* get test bit for above/below X axis */
503    yflag0 = ( vtx0[YY] >= ty );
504    vtx1 = pgon[0];
505 
506    inside_flag = 0;
507 
508    for (j = numverts+1; --j ;)
509    {
510       yflag1 = ( vtx1[YY] >= ty );
511        /* check if endpoints straddle (are on opposite sides) of X axis
512         * (i.e. the Y's differ); if so, +X ray could intersect this edge.
513         */
514       if (yflag0 != yflag1)
515       {
516          xflag0 = (vtx0[XX] >= tx);
517          /* check if endpoints are on same side of the Y axis (i.e. X's
518           * are the same); if so, it's easy to test if edge hits or misses.
519           */
520          if ( xflag0 == ( vtx1[XX] >= tx ) )
521          {
522             /* if edge's X values both right of the point, must hit */
523             if ( xflag0 )
524                inside_flag = !inside_flag;
525          }
526          else
527          {
528               /* compute intersection of pgon segment with +X ray, note
529                * if >= point's X; if so, the ray hits it.
530                */
531             if ((vtx1[XX] - (vtx1[YY]-ty) * (vtx0[XX]-vtx1[XX])/(vtx0[YY]-vtx1[YY])) >= tx)
532             {
533                inside_flag = !inside_flag;
534             }
535          }
536       }
537 
538       /* move to next pair of vertices, retaining info as possible */
539       yflag0 = yflag1;
540       vtx0 = vtx1;
541       vtx1 += 2;
542    }
543 
544    return inside_flag;
545 }
546 
polygon_ray_inter3d(PolyhedronStruct * newph,int poly_index,double pt[3],int axes)547 int polygon_ray_inter3d(PolyhedronStruct* newph, int poly_index, double pt[3], int axes)
548 {
549 
550    int i,j, num_inter, numpts;
551    double **poly_pts, temppt[3], rotpt[3];
552    PolygonStruct* poly;
553    VertexStruct* v1;
554    double **mat;
555    double amat[3][3];
556 
557    poly = &newph->polygon[poly_index];
558    numpts = poly->num_vertices;
559    poly_pts = (double**)simm_malloc(numpts*sizeof(double*));
560    for (i=0; i<numpts; i++)
561       poly_pts[i] = (double*)simm_malloc(3*sizeof(double));
562 
563    for (i=0; i<numpts; i++)
564    {
565       v1 = &newph->vertex[poly->vertex_index[i]];
566       poly_pts[i][0] = v1->coord[0];
567       poly_pts[i][1] = v1->coord[1];
568       poly_pts[i][2] = v1->coord[2];
569    }
570 
571    mat = (double**)simm_malloc(4*sizeof(double*));
572    mat[0] = (double*)simm_malloc(3*sizeof(double));
573    mat[1] = (double*)simm_malloc(3*sizeof(double));
574    mat[2] = (double*)simm_malloc(3*sizeof(double));
575    make_rotation_matrix(mat,poly->normal);
576 
577    for (i=0; i<3; i++)
578       for (j=0; j<3; j++)
579      amat[i][j] = mat[i][j];
580 
581    for (i=0; i<numpts; i++)
582    {
583       COPY_1X3VECTOR(poly_pts[i],temppt);
584       mult_3x3matrix_by_vector(amat,temppt,poly_pts[i]);
585    }
586    mult_3x3matrix_by_vector(amat,pt,rotpt);
587 
588    num_inter = polygon_ray_inter_jordanstheorem(poly_pts,numpts,rotpt,axes);
589 
590    for (i=0; i<numpts; i++)
591       FREE_IFNOTNULL(poly_pts[i]);
592    FREE_IFNOTNULL(poly_pts);
593 
594    return (num_inter);
595 
596 }
597 
598 
polygon_ray_inter_jordanstheorem(double ** poly_pts,int numpts,double ptray[3],int axes)599 int polygon_ray_inter_jordanstheorem(double** poly_pts, int numpts,
600                      double ptray[3], int axes)
601 {
602 
603    int i, newstate, algstate, otheraxes, numinter = 0;
604    int quit = FALSE;
605    double intermin, inter, t;
606    int count, start, current, last = -1;
607 
608    otheraxes = (axes == 1 ? 0 : 1);
609 
610    for (i=0; i<numpts; i++)
611    {
612       if ((algstate = point_ray_relation(poly_pts[i],ptray,otheraxes)) != ON_RAY)
613      break;
614    }
615 
616    if (algstate == ON_RAY)
617       return (0);
618 
619    /* the vertex is below the ray level */
620    count = 0;
621    if (i == numpts)
622       current = start = 0;
623    else
624       current =  start = i;
625 
626    while (!quit)
627    {
628       count = 0;
629       while (point_ray_relation(poly_pts[current],ptray,otheraxes) == algstate)
630       {
631      last = current;
632      current += 1;
633      if (current == numpts)
634         current = 0;
635      count++;
636      if (count == numpts || current == start)
637      {
638         quit = TRUE;
639         break;
640      }
641       }
642       intermin = 1000000;
643       count =0;
644       while (point_ray_relation(poly_pts[current],ptray,otheraxes) == ON_RAY)
645       {
646      intermin = _MIN(intermin,poly_pts[current][axes]);
647      last = current;
648      current += 1;
649      if (current == numpts)
650         current = 0;
651      count++;
652      if (current == start)
653      {
654         quit = TRUE;
655      }
656       }
657       if ((newstate = point_ray_relation(poly_pts[current],ptray,otheraxes))
658       != algstate)
659       {
660      t = (ptray[otheraxes] - poly_pts[current][otheraxes])/
661             (poly_pts[last][otheraxes] - poly_pts[current][otheraxes]);
662      inter = poly_pts[last][axes] * t + poly_pts[current][axes] * (1.0-t);
663      intermin = _MIN(intermin,inter);
664      if (intermin > ptray[axes] && NOT_EQUAL_WITHIN_TOLERANCE(intermin,ptray[axes],LINE_EPSILON))
665         numinter++;
666       }
667       algstate = newstate;
668    }
669 
670    return (numinter);
671 
672 }
673 
674 /* returns the relation between a ray and a given point
675 ** returns 0,1,2
676 ** 0= on the ray;  1= above ray, 2= below ray
677 ** the pt is either on, above or below the ray
678 */
point_ray_relation(double * pt,double ptray[],int axes)679 int point_ray_relation(double* pt, double ptray[], int axes)
680 {
681 
682    if (EQUAL_WITHIN_TOLERANCE(ptray[axes],pt[axes],LINE_EPSILON))
683       return (ON_RAY);
684    else if (ptray[axes] < pt[axes])
685       return (ABOVE_RAY);
686    else
687       return (BELOW_RAY);
688 
689 }
690 
691 /*****************************************************************************
692 ** DESCRIPTION:
693 **
694 ** prepare a transformation martix to rotate such that Dir is
695 ** parallel to the Z axes. Used to rotate the
696 ** polygons to be XY plane parallel.
697 **
698 **    Algorithm: form a 4 by 4 matrix from Dir as follows:
699 **                |  tx  ty  tz  0 |   A transformation which takes the coord
700 **                |  bx  by  bz  0 |  system into t, b & n as required.
701 ** [X  Y  Z  1] * |  nx  ny  nz  0 |
702 **                |  0   0   0   1 |
703 **   N is exactly Dir, but we got freedom on T & B which must be on
704 **   a plane perpendicular to N and perpendicular between them but thats all!
705 **   T is therefore selected using this (heuristic ?) algorithm:
706 **   Let P be the axis of which the absolute N coefficient is the smallest.
707 **   Let B be (N cross P) and T be (B cross N).
708 **
709 ** PARAMETERS:
710 **   mat:     To place the constructed homogeneous transformation.
711 **   dir:     To derive a transformation such that Dir goes to Z axis.
712 **
713 */
make_rotation_matrix(double ** mat,double normal[])714 void make_rotation_matrix(double** mat, double normal[])
715 {
716   int i,j;
717   double r;
718   double dir_n[3], t[3],b[3],p[3];
719 
720   COPY_1X3VECTOR(normal,dir_n);
721   normalize_vector(dir_n,dir_n);
722   p[0] = 0.0;
723   p[1] = 0.0;
724   p[2] = 0.0;
725 
726   j=0;
727   r = DABS(dir_n[0]);
728   for(i=1; i<3; i++)
729   {
730      if( r > DABS(dir_n[i]))
731      {
732         r = dir_n[i];
733         j = i;
734      }
735   }
736   p[j] = 1.0;   /* set p to the axis with the biggest angle from dirn */
737 
738   cross_vectors(dir_n,p,b);  /* calc the bi-normal*/
739   normalize_vector(b,b);
740   cross_vectors(b,dir_n,t);  /* calc the tangent */
741   normalize_vector(t,t);
742 
743   for(i=0; i<3; i++)
744   {
745       mat[i][0] = t[i];
746       mat[i][1] = b[i];
747       mat[i][2] = dir_n[i];
748   }
749 
750 }
751 
intersect_lines(double p1[],double p2[],double p3[],double p4[],double p_int1[],double * t,double p_int2[],double * s)752 int intersect_lines(double p1[], double p2[], double p3[], double p4[],
753             double p_int1[], double* t, double p_int2[], double* s)
754 {
755 
756    double mag1, mag2, cross_prod[3], denom, vec1[3], vec2[3], mat[3][3];
757 
758    vec1[0] = p2[0] - p1[0];
759    vec1[1] = p2[1] - p1[1];
760    vec1[2] = p2[2] - p1[2];
761    mag1 = normalize_vector(vec1,vec1);
762 
763    vec2[0] = p4[0] - p3[0];
764    vec2[1] = p4[1] - p3[1];
765    vec2[2] = p4[2] - p3[2];
766    mag2 = normalize_vector(vec2,vec2);
767 
768    cross_vectors(vec1,vec2,cross_prod);
769 
770    denom = cross_prod[0]*cross_prod[0] + cross_prod[1]*cross_prod[1]
771       + cross_prod[2]*cross_prod[2];
772 
773    if (EQUAL_WITHIN_ERROR(denom,0.0))
774    {
775       *s = *t = MINMDOUBLE;
776       return (0);
777    }
778 
779    mat[0][0] = p3[0] - p1[0];
780    mat[0][1] = p3[1] - p1[1];
781    mat[0][2] = p3[2] - p1[2];
782    mat[1][0] = vec1[0];
783    mat[1][1] = vec1[1];
784    mat[1][2] = vec1[2];
785    mat[2][0] = cross_prod[0];
786    mat[2][1] = cross_prod[1];
787    mat[2][2] = cross_prod[2];
788 
789    *s = CALC_DETERMINANT(mat) / denom;
790 
791    p_int2[0] = p3[0] + (*s) * (vec2[0]);
792    p_int2[1] = p3[1] + (*s) * (vec2[1]);
793    p_int2[2] = p3[2] + (*s) * (vec2[2]);
794 
795    mat[1][0] = vec2[0];
796    mat[1][1] = vec2[1];
797    mat[1][2] = vec2[2];
798 
799    *t = CALC_DETERMINANT(mat) / denom;
800 
801    p_int1[0] = p1[0] + (*t) * (vec1[0]);
802    p_int1[1] = p1[1] + (*t) * (vec1[1]);
803    p_int1[2] = p1[2] + (*t) * (vec1[2]);
804 
805    (*s) /= mag2;
806    (*t) /= mag1;
807 
808    return (1);
809 
810 }
811 
812 /* Same as intersect_lines(), but this routine does not scale the S and T
813  * parameters to be between 0.0 and 1.0. S ranges from 0.0 to mag2,
814  * and T ranges from 0.0 to mag1.
815  */
816 
intersect_lines_scaled(double p1[],double p2[],double p3[],double p4[],double p_int1[],double * t,double * mag1,double p_int2[],double * s,double * mag2)817 int intersect_lines_scaled(double p1[], double p2[], double p3[], double p4[],
818                double p_int1[], double* t, double* mag1,
819                double p_int2[], double* s, double* mag2)
820 {
821 
822    double cross_prod[3], denom, vec1[3], vec2[3], mat[3][3];
823 
824    vec1[0] = p2[0] - p1[0];
825    vec1[1] = p2[1] - p1[1];
826    vec1[2] = p2[2] - p1[2];
827    *mag1 = normalize_vector(vec1,vec1);
828 
829    vec2[0] = p4[0] - p3[0];
830    vec2[1] = p4[1] - p3[1];
831    vec2[2] = p4[2] - p3[2];
832    *mag2 = normalize_vector(vec2,vec2);
833 
834    cross_vectors(vec1,vec2,cross_prod);
835 
836    denom = cross_prod[0]*cross_prod[0] + cross_prod[1]*cross_prod[1]
837       + cross_prod[2]*cross_prod[2];
838 
839    if (EQUAL_WITHIN_ERROR(denom,0.0))
840    {
841       *s = *t = MINMDOUBLE;
842       return (0);
843    }
844 
845    mat[0][0] = p3[0] - p1[0];
846    mat[0][1] = p3[1] - p1[1];
847    mat[0][2] = p3[2] - p1[2];
848    mat[1][0] = vec1[0];
849    mat[1][1] = vec1[1];
850    mat[1][2] = vec1[2];
851    mat[2][0] = cross_prod[0];
852    mat[2][1] = cross_prod[1];
853    mat[2][2] = cross_prod[2];
854 
855    *s = CALC_DETERMINANT(mat) / denom;
856 
857    p_int2[0] = p3[0] + (*s) * (vec2[0]);
858    p_int2[1] = p3[1] + (*s) * (vec2[1]);
859    p_int2[2] = p3[2] + (*s) * (vec2[2]);
860 
861    mat[1][0] = vec2[0];
862    mat[1][1] = vec2[1];
863    mat[1][2] = vec2[2];
864 
865    *t = CALC_DETERMINANT(mat) / denom;
866 
867    p_int1[0] = p1[0] + (*t) * (vec1[0]);
868    p_int1[1] = p1[1] + (*t) * (vec1[1]);
869    p_int1[2] = p1[2] + (*t) * (vec1[2]);
870 
871    return (1);
872 
873 }
874 
875 
876 /* MULT_3X3MATRIX_BY_VECTOR: this routine premultiplies a 3x3 matrix by
877 ** a 1x3 vector. That is, it does vector*mat, not mat*vector.
878 */
mult_3x3matrix_by_vector(double mat[][3],double vector[],double result[])879 void mult_3x3matrix_by_vector(double mat[][3], double vector[], double result[])
880 {
881 
882    result[0] = vector[0]*mat[0][0] + vector[1]*mat[1][0] +
883                vector[2]*mat[2][0];
884    result[1] = vector[0]*mat[0][1] + vector[1]*mat[1][1] +
885                vector[2]*mat[2][1];
886    result[2] = vector[0]*mat[0][2] + vector[1]*mat[1][2] +
887                vector[2]*mat[2][2];
888 
889 }
890 
891 
make_3x3dircos_matrix(double angle,double axis[],double mat[][3])892 void make_3x3dircos_matrix(double angle, double axis[], double mat[][3])
893 {
894 
895    double rad_angle, cl, sl, omc;
896 
897    reset_3x3matrix(mat);
898 
899    rad_angle = angle*DTOR;
900 
901    cl = cos(rad_angle);
902    sl = sin(rad_angle);
903    omc = 1.0 - cl;
904 
905    /* the following matrix is taken from Kane's 'Spacecraft Dynamics,' pp 6-7 */
906 
907    mat[0][0] = cl + axis[0]*axis[0]*omc;
908    mat[1][0] = -axis[2]*sl + axis[0]*axis[1]*omc;
909    mat[2][0] = axis[1]*sl + axis[2]*axis[0]*omc;
910    mat[0][1] = axis[2]*sl + axis[0]*axis[1]*omc;
911    mat[1][1] = cl + axis[1]*axis[1]*omc;
912    mat[2][1] = -axis[0]*sl + axis[1]*axis[2]*omc;
913    mat[0][2] = -axis[1]*sl + axis[2]*axis[0]*omc;
914    mat[1][2] = axis[0]*sl + axis[1]*axis[2]*omc;
915    mat[2][2] = cl + axis[2]*axis[2]*omc;
916 
917 }
918 
919 
reset_3x3matrix(double matrix[][3])920 void reset_3x3matrix(double matrix[][3])
921 {
922 
923    matrix[0][1] = matrix[0][2] = matrix[1][2] = 0.0;
924    matrix[1][0] = matrix[2][0] = matrix[2][1] = 0.0;
925    matrix[0][0] = matrix[1][1] = matrix[2][2] = 1.0;
926 
927 }
928 
929 
clear_vector(double a[],int n)930 void clear_vector(double a[], int n)
931 {
932 
933    int i;
934 
935    for (i=0; i<n; i++)
936       a[i] = 0.0;
937 
938 }
939 
940 
make_3x3_xrot_matrix(double a,double m[][3])941 void make_3x3_xrot_matrix(double a, double m[][3])
942 {
943 
944    m[0][0] = 1.0;
945    m[0][1] = 0.0;
946    m[0][2] = 0.0;
947 
948    m[1][0] = 0.0;
949    m[1][1] = cos(a);
950    m[1][2] = sin(a);
951 
952    m[2][0] = 0.0;
953    m[2][1] = -sin(a);
954    m[2][2] = cos(a);
955 
956 }
957 
958 
mult_3x3matrices(double mat1[][3],double mat2[][3],double result[][3])959 void mult_3x3matrices(double mat1[][3], double mat2[][3], double result[][3])
960 {
961 
962    result[0][0] = mat1[0][0]*mat2[0][0] + mat1[0][1]*mat2[1][0] +
963       mat1[0][2]*mat2[2][0];
964 
965    result[0][1] = mat1[0][0]*mat2[0][1] + mat1[0][1]*mat2[1][1] +
966       mat1[0][2]*mat2[2][1];
967 
968    result[0][2] = mat1[0][0]*mat2[0][2] + mat1[0][1]*mat2[1][2] +
969       mat1[0][2]*mat2[2][2];
970 
971 
972    result[1][0] = mat1[1][0]*mat2[0][0] + mat1[1][1]*mat2[1][0] +
973       mat1[1][2]*mat2[2][0];
974 
975    result[1][1] = mat1[1][0]*mat2[0][1] + mat1[1][1]*mat2[1][1] +
976       mat1[1][2]*mat2[2][1];
977 
978    result[1][2] = mat1[1][0]*mat2[0][2] + mat1[1][1]*mat2[1][2] +
979       mat1[1][2]*mat2[2][2];
980 
981 
982    result[2][0] = mat1[2][0]*mat2[0][0] + mat1[2][1]*mat2[1][0] +
983       mat1[2][2]*mat2[2][0];
984 
985    result[2][1] = mat1[2][0]*mat2[0][1] + mat1[2][1]*mat2[1][1] +
986       mat1[2][2]*mat2[2][1];
987 
988    result[2][2] = mat1[2][0]*mat2[0][2] + mat1[2][1]*mat2[1][2] +
989       mat1[2][2]*mat2[2][2];
990 
991 }
992 
993 
994 
transpose_3x3matrix(double mat[][3],double mat_transpose[][3])995 void transpose_3x3matrix(double mat[][3], double mat_transpose[][3])
996 {
997 
998    int i, j;
999 
1000    for (i=0; i<3; i++)
1001       for (j=0; j<3; j++)
1002          mat_transpose[j][i] = mat[i][j];
1003 
1004 }
1005 
1006 
copy_3x3matrix(double from[][3],double to[][3])1007 void copy_3x3matrix(double from[][3], double to[][3])
1008 {
1009 
1010    to[0][0] = from[0][0];
1011    to[0][1] = from[0][1];
1012    to[0][2] = from[0][2];
1013    to[1][0] = from[1][0];
1014    to[1][1] = from[1][1];
1015    to[1][2] = from[1][2];
1016    to[2][0] = from[2][0];
1017    to[2][1] = from[2][1];
1018    to[2][2] = from[2][2];
1019 
1020 }
1021 
1022 
mult_3x3_by_vector(double mat[][3],double vec[])1023 void mult_3x3_by_vector(double mat[][3], double vec[])
1024 {
1025 
1026    double result[3];
1027 
1028    result[0] = vec[0]*mat[0][0] + vec[1]*mat[1][0] + vec[2]*mat[2][0];
1029    result[1] = vec[0]*mat[0][1] + vec[1]*mat[1][1] + vec[2]*mat[2][1];
1030    result[2] = vec[0]*mat[0][2] + vec[1]*mat[1][2] + vec[2]*mat[2][2];
1031 
1032    vec[0] = result[0];
1033    vec[1] = result[1];
1034    vec[2] = result[2];
1035 
1036 }
1037 
1038 
find_plane_normal_to_line(PlaneStruct * plane,double pt1[],double pt2[])1039 void find_plane_normal_to_line(PlaneStruct* plane, double pt1[], double pt2[])
1040 {
1041 
1042    double pt3[3];
1043 
1044    MAKE_3DVECTOR(pt1,pt2,pt3);
1045 
1046    normalize_vector(pt3,pt3);
1047 
1048    plane->a = pt3[XX];
1049    plane->b = pt3[YY];
1050    plane->c = pt3[ZZ];
1051 
1052    /* d is the distance along the plane's normal vector from the plane to the
1053     * origin. Thus it is negative when the plane is above the origin, and
1054     * positive when the plane is below the origin.
1055     */
1056 
1057    plane->d = -plane->a*pt1[XX] - plane->b*pt1[YY] - plane->c*pt1[ZZ];
1058 
1059 }
1060 
1061 
compute_angle_between_vectors(double vector1[],double vector2[])1062 double compute_angle_between_vectors(double vector1[], double vector2[])
1063 {
1064 
1065    double normal_vector1[3], normal_vector2[3];
1066 
1067    normalize_vector(vector1,normal_vector1);
1068    normalize_vector(vector2,normal_vector2);
1069 
1070    return (acos(DOT_VECTORS(normal_vector1,normal_vector2)));
1071 
1072 }
1073 
1074 
1075 
project_point_onto_plane(double pt[],PlaneStruct * plane,double projpt[])1076 void project_point_onto_plane(double pt[], PlaneStruct* plane, double projpt[])
1077 {
1078 
1079    double plane_normal[3];
1080    double distance_to_plane;
1081 
1082    plane_normal[XX] = plane->a;
1083    plane_normal[YY] = plane->b;
1084    plane_normal[ZZ] = plane->c;
1085 
1086    normalize_vector(plane_normal,plane_normal);
1087 
1088    /* distance_to_plane is the distance from pt to the plane along the
1089     * plane's normal vector. Thus it is negative when pt is below
1090     * the plane, and positive when pt is above the plane.
1091     */
1092 
1093    distance_to_plane = DOT_VECTORS(pt,plane_normal) + plane->d;
1094 
1095    projpt[XX] = pt[XX] - distance_to_plane*plane_normal[XX];
1096    projpt[YY] = pt[YY] - distance_to_plane*plane_normal[YY];
1097    projpt[ZZ] = pt[ZZ] - distance_to_plane*plane_normal[ZZ];
1098 
1099 }
1100 
1101 
1102 
distancesqr_between_vertices(double vertex1[],double vertex2[])1103 double distancesqr_between_vertices(double vertex1[], double vertex2[])
1104 {
1105 
1106    double vec[3];
1107 
1108    vec[0] = vertex2[0] - vertex1[0];
1109    vec[1] = vertex2[1] - vertex1[1];
1110    vec[2] = vertex2[2] - vertex1[2];
1111 
1112    return vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2];
1113 
1114 }
1115 
1116 
distance_between_vertices(double vertex1[],double vertex2[])1117 double distance_between_vertices(double vertex1[], double vertex2[])
1118 {
1119 
1120    double vec[3];
1121 
1122    vec[0] = vertex2[0] - vertex1[0];
1123    vec[1] = vertex2[1] - vertex1[1];
1124    vec[2] = vertex2[2] - vertex1[2];
1125 
1126    return (sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]));
1127 
1128 }
1129 
1130 
1131 /* Calculates the square of the shortest distance from a point (point)
1132  * to a line (vl, through pl).
1133  */
get_distsqr_point_line(double point[],double pl[],double vl[])1134 double get_distsqr_point_line(double point[], double pl[], double vl[])
1135 {
1136 
1137    double ptemp[3];
1138 
1139    /* find the closest point on line */
1140    get_point_from_point_line(point,pl,vl,ptemp);
1141 
1142    return distancesqr_between_vertices(point,ptemp);
1143 
1144 }
1145 
1146 
1147 /* to calculate the closest 3d point to given 3d line.
1148  * the line is defined as vector(vec) and a point(pt)
1149  * the line has not been normalized to a unit vector
1150  * the value hypo*(cosalpha) of a rt triangle is found out
1151  * to get the closest point
1152  */
get_point_from_point_line(double point[],double pt[],double vec[],double closest_pt[])1153 void get_point_from_point_line(double point[], double pt[], double vec[],
1154                    double closest_pt[])
1155 {
1156 
1157    double v1[3], v2[3];
1158    double t, mag;
1159 
1160    v1[0] = point[0] - pt[0];
1161    v1[1] = point[1] - pt[1];
1162    v1[2] = point[2] - pt[2];
1163 
1164    v2[0] = vec[0];
1165    v2[1] = vec[1];
1166    v2[2] = vec[2];
1167 
1168    mag = normalize_vector(v1,v1);
1169    normalize_vector(v2,v2);
1170    t = DOT_VECTORS(v1,v2) * mag;
1171 
1172    closest_pt[0] = pt[0] + t * v2[0];
1173    closest_pt[1] = pt[1] + t * v2[1];
1174    closest_pt[2] = pt[2] + t * v2[2];
1175 
1176 }
1177 
1178 
1179 /* ------------------------------------------------------------------------
1180    atan3 - like the Standard C Library's atan2(), except returning a result
1181       between 0 and 2pi instead of -pi and pi.
1182 --------------------------------------------------------------------------- */
atan3(double y,double x)1183 double atan3 (double y, double x)
1184 {
1185    double result = atan2(y, x);
1186 
1187    if (result < 0.0)
1188       result += 2 * M_PI;
1189 
1190    return result;
1191 }
1192 
identity_matrix(double m[][4])1193 void identity_matrix(double m[][4])
1194 {
1195    /* set matrix 'm' to the identity matrix */
1196 
1197    m[0][0] = 1.0; m[0][1] = 0.0; m[0][2] = 0.0; m[0][3] = 0.0;
1198    m[1][0] = 0.0; m[1][1] = 1.0; m[1][2] = 0.0; m[1][3] = 0.0;
1199    m[2][0] = 0.0; m[2][1] = 0.0; m[2][2] = 1.0; m[2][3] = 0.0;
1200    m[3][0] = 0.0; m[3][1] = 0.0; m[3][2] = 0.0; m[3][3] = 1.0;
1201 }
1202 
x_rotate_matrix_bodyfixed(double m[][4],double radians)1203 void x_rotate_matrix_bodyfixed(double m[][4], double radians)
1204 {
1205    /* append rotation about local x-axis to matrix 'm' */
1206    Quat q;
1207 
1208    make_quaternion(q, m[0], radians);
1209    rotate_matrix_by_quat(m, q);
1210 }
1211 
y_rotate_matrix_bodyfixed(double m[][4],double radians)1212 void y_rotate_matrix_bodyfixed(double m[][4], double radians)
1213 {
1214    /* append rotation about local y-axis to matrix 'm' */
1215    Quat q;
1216 
1217    make_quaternion(q, m[1], radians);
1218    rotate_matrix_by_quat(m, q);
1219 }
1220 
z_rotate_matrix_bodyfixed(double m[][4],double radians)1221 void z_rotate_matrix_bodyfixed(double m[][4], double radians)
1222 {
1223    /* append rotation about local z-axis to matrix 'm' */
1224    Quat q;
1225 
1226    make_quaternion(q, m[2], radians);
1227    rotate_matrix_by_quat(m, q);
1228 }
1229 
x_rotate_matrix_spacefixed(double m[][4],double radians)1230 void x_rotate_matrix_spacefixed(double m[][4], double radians)
1231 {
1232    /* append rotation about global x-axis to matrix 'm' */
1233     double sinTheta = sin(radians);
1234     double cosTheta = cos(radians);
1235 
1236     double t = m[0][1];
1237     m[0][1] = t * cosTheta - m[0][2] * sinTheta;
1238     m[0][2] = t * sinTheta + m[0][2] * cosTheta;
1239 
1240     t = m[1][1];
1241     m[1][1] = t * cosTheta - m[1][2] * sinTheta;
1242     m[1][2] = t * sinTheta + m[1][2] * cosTheta;
1243 
1244     t = m[2][1];
1245     m[2][1] = t * cosTheta - m[2][2] * sinTheta;
1246     m[2][2] = t * sinTheta + m[2][2] * cosTheta;
1247 
1248     t = m[3][1];
1249     m[3][1] = t * cosTheta - m[3][2] * sinTheta;
1250     m[3][2] = t * sinTheta + m[3][2] * cosTheta;
1251 }
1252 
y_rotate_matrix_spacefixed(double m[][4],double radians)1253 void y_rotate_matrix_spacefixed(double m[][4], double radians)
1254 {
1255    /* append rotation about global y-axis to matrix 'm' */
1256     double sinTheta = sin(radians);
1257     double cosTheta = cos(radians);
1258 
1259     double t = m[0][0];
1260     m[0][0] = t * cosTheta + m[0][2] * sinTheta;
1261     m[0][2] = m[0][2] * cosTheta - t * sinTheta;
1262 
1263     t = m[1][0];
1264     m[1][0] = t * cosTheta + m[1][2] * sinTheta;
1265     m[1][2] = m[1][2] * cosTheta - t * sinTheta;
1266 
1267     t = m[2][0];
1268     m[2][0] = t * cosTheta + m[2][2] * sinTheta;
1269     m[2][2] = m[2][2] * cosTheta - t * sinTheta;
1270 
1271     t = m[3][0];
1272     m[3][0] = t * cosTheta + m[3][2] * sinTheta;
1273     m[3][2] = m[3][2] * cosTheta - t * sinTheta;
1274 }
1275 
z_rotate_matrix_spacefixed(double m[][4],double radians)1276 void z_rotate_matrix_spacefixed(double m[][4], double radians)
1277 {
1278    /* append rotation about global z-axis to matrix 'm' */
1279     double sinTheta = sin(radians);
1280     double cosTheta = cos(radians);
1281 
1282     double t = m[0][0];
1283     m[0][0] = t * cosTheta - m[0][1] * sinTheta;
1284     m[0][1] = t * sinTheta + m[0][1] * cosTheta;
1285 
1286     t = m[1][0];
1287     m[1][0] = t * cosTheta - m[1][1] * sinTheta;
1288     m[1][1] = t * sinTheta + m[1][1] * cosTheta;
1289 
1290     t = m[2][0];
1291     m[2][0] = t * cosTheta - m[2][1] * sinTheta;
1292     m[2][1] = t * sinTheta + m[2][1] * cosTheta;
1293 
1294     t = m[3][0];
1295     m[3][0] = t * cosTheta - m[3][1] * sinTheta;
1296     m[3][1] = t * sinTheta + m[3][1] * cosTheta;
1297 }
1298 
translate_matrix(double m[][4],const double * delta)1299 void translate_matrix(double m[][4], const double* delta)
1300 {
1301    /* append translation 'delta' to matrix 'm' */
1302 
1303    m[0][0] += m[0][3] * delta[0];   m[0][1] += m[0][3] * delta[1];   m[0][2] += m[0][3] * delta[2];
1304    m[1][0] += m[1][3] * delta[0];   m[1][1] += m[1][3] * delta[1];   m[1][2] += m[1][3] * delta[2];
1305    m[2][0] += m[2][3] * delta[0];   m[2][1] += m[2][3] * delta[1];   m[2][2] += m[2][3] * delta[2];
1306    m[3][0] += m[3][3] * delta[0];   m[3][1] += m[3][3] * delta[1];   m[3][2] += m[3][3] * delta[2];
1307 }
1308 
scale_matrix(double m[][4],const double * scaleBy)1309 void scale_matrix (double m[][4], const double* scaleBy)
1310 {
1311    m[0][0] *= scaleBy[XX];   m[0][1] *= scaleBy[YY];   m[0][2] *= scaleBy[ZZ];
1312    m[1][0] *= scaleBy[XX];   m[1][1] *= scaleBy[YY];   m[1][2] *= scaleBy[ZZ];
1313    m[2][0] *= scaleBy[XX];   m[2][1] *= scaleBy[YY];   m[2][2] *= scaleBy[ZZ];
1314    m[3][0] *= scaleBy[XX];   m[3][1] *= scaleBy[YY];   m[3][2] *= scaleBy[ZZ];
1315 }
1316 
append_matrix(DMatrix m,const DMatrix b)1317 void append_matrix(DMatrix m, const DMatrix b)
1318 {
1319    /* append matrix 'b' to matrix 'm' */
1320 
1321    double ta[4][4];
1322 
1323    memcpy(ta, m, 16 * sizeof(double));
1324 
1325    m[0][0] = ta[0][0] * b[0][0] + ta[0][1] * b[1][0] + ta[0][2] * b[2][0] + ta[0][3] * b[3][0];
1326    m[0][1] = ta[0][0] * b[0][1] + ta[0][1] * b[1][1] + ta[0][2] * b[2][1] + ta[0][3] * b[3][1];
1327    m[0][2] = ta[0][0] * b[0][2] + ta[0][1] * b[1][2] + ta[0][2] * b[2][2] + ta[0][3] * b[3][2];
1328    m[0][3] = ta[0][0] * b[0][3] + ta[0][1] * b[1][3] + ta[0][2] * b[2][3] + ta[0][3] * b[3][3];
1329 
1330    m[1][0] = ta[1][0] * b[0][0] + ta[1][1] * b[1][0] + ta[1][2] * b[2][0] + ta[1][3] * b[3][0];
1331    m[1][1] = ta[1][0] * b[0][1] + ta[1][1] * b[1][1] + ta[1][2] * b[2][1] + ta[1][3] * b[3][1];
1332    m[1][2] = ta[1][0] * b[0][2] + ta[1][1] * b[1][2] + ta[1][2] * b[2][2] + ta[1][3] * b[3][2];
1333    m[1][3] = ta[1][0] * b[0][3] + ta[1][1] * b[1][3] + ta[1][2] * b[2][3] + ta[1][3] * b[3][3];
1334 
1335    m[2][0] = ta[2][0] * b[0][0] + ta[2][1] * b[1][0] + ta[2][2] * b[2][0] + ta[2][3] * b[3][0];
1336    m[2][1] = ta[2][0] * b[0][1] + ta[2][1] * b[1][1] + ta[2][2] * b[2][1] + ta[2][3] * b[3][1];
1337    m[2][2] = ta[2][0] * b[0][2] + ta[2][1] * b[1][2] + ta[2][2] * b[2][2] + ta[2][3] * b[3][2];
1338    m[2][3] = ta[2][0] * b[0][3] + ta[2][1] * b[1][3] + ta[2][2] * b[2][3] + ta[2][3] * b[3][3];
1339 
1340    m[3][0] = ta[3][0] * b[0][0] + ta[3][1] * b[1][0] + ta[3][2] * b[2][0] + ta[3][3] * b[3][0];
1341    m[3][1] = ta[3][0] * b[0][1] + ta[3][1] * b[1][1] + ta[3][2] * b[2][1] + ta[3][3] * b[3][1];
1342    m[3][2] = ta[3][0] * b[0][2] + ta[3][1] * b[1][2] + ta[3][2] * b[2][2] + ta[3][3] * b[3][2];
1343    m[3][3] = ta[3][0] * b[0][3] + ta[3][1] * b[1][3] + ta[3][2] * b[2][3] + ta[3][3] * b[3][3];
1344 }
1345 
transform_pt(double m[][4],double * pt)1346 void transform_pt(double m[][4], double* pt)
1347 {
1348    /* apply a matrix transformation to a 3d point */
1349 
1350    double tx = pt[XX] * m[0][0] + pt[YY] * m[1][0] + pt[ZZ] * m[2][0] + m[3][0];
1351    double ty = pt[XX] * m[0][1] + pt[YY] * m[1][1] + pt[ZZ] * m[2][1] + m[3][1];
1352 
1353    pt[ZZ] = pt[XX] * m[0][2] + pt[YY] * m[1][2] + pt[ZZ] * m[2][2] + m[3][2];
1354    pt[XX] = tx;
1355    pt[YY] = ty;
1356 }
1357 
transform_vec(double m[][4],double * vec)1358 void transform_vec(double m[][4], double* vec)
1359 {
1360    /* apply a matrix transformation to a 3d vector */
1361 
1362    double tx = vec[XX] * m[0][0] + vec[YY] * m[1][0] + vec[ZZ] * m[2][0];
1363    double ty = vec[XX] * m[0][1] + vec[YY] * m[1][1] + vec[ZZ] * m[2][1];
1364 
1365    vec[ZZ] = vec[XX] * m[0][2] + vec[YY] * m[1][2] + vec[ZZ] * m[2][2];
1366    vec[XX] = tx;
1367    vec[YY] = ty;
1368 }
1369 
quat_to_axis_angle_rot(const Quat q,dpCoord3D * axis,double * angle)1370 static void quat_to_axis_angle_rot (const Quat q, dpCoord3D* axis, double* angle)
1371 {
1372    double sin_a2;
1373 
1374    axis->xyz[XX] = q[XX];
1375    axis->xyz[YY] = q[YY];
1376    axis->xyz[ZZ] = q[ZZ];
1377 
1378    /* |sin a/2|, w = cos a/2 */
1379    sin_a2 = sqrt(SQR(q[XX]) + SQR(q[YY]) + SQR(q[ZZ]));
1380 
1381    /* 0 <= angle <= PI , because 0 < sin_a2 */
1382    *angle = 2.0 * atan2(sin_a2, q[WW]);
1383 
1384    if (EQUAL_WITHIN_ERROR(0.0,*angle))
1385    {
1386       axis->xyz[XX] = 1.0;
1387       axis->xyz[YY] = 0.0;
1388       axis->xyz[ZZ] = 0.0;
1389    }
1390 }
1391 
matrix_to_quat(double m[][4],Quat q)1392 static void matrix_to_quat (double m[][4], Quat q)
1393 {
1394    double s, trace = m[XX][XX] + m[YY][YY] + m[ZZ][ZZ];
1395 
1396    if (NEAR_GT_OR_EQ(trace, 0.0))
1397    {
1398       s    = sqrt(trace + m[WW][WW]);
1399       q[WW] = s * 0.5;
1400       s    = 0.5 / s;
1401 
1402       q[XX] = (m[YY][ZZ] - m[ZZ][YY]) * s;
1403       q[YY] = (m[ZZ][XX] - m[XX][ZZ]) * s;
1404       q[ZZ] = (m[XX][YY] - m[YY][XX]) * s;
1405    }
1406    else
1407    {
1408       static const int next[] = { YY, ZZ, XX };
1409 
1410       int i = XX, j, k;
1411 
1412       if (m[YY][YY] > m[XX][XX])
1413          i = YY;
1414       if (m[ZZ][ZZ] > m[i][i])
1415          i = ZZ;
1416 
1417       j = next[i];
1418       k = next[j];
1419 
1420       s = sqrt((m[i][i] - (m[j][j] + m[k][k])) + m[WW][WW]);
1421 
1422       q[i] = s * 0.5;
1423       s    = 0.5 / s;
1424 
1425       q[j] = (m[i][j] + m[j][i]) * s;
1426       q[k] = (m[i][k] + m[k][i]) * s;
1427       q[WW] = (m[j][k] - m[k][j]) * s;
1428    }
1429    if (NOT_EQUAL_WITHIN_ERROR(m[WW][WW], 1.0))
1430    {
1431       double scale = 1.0 / sqrt(m[WW][WW]);
1432 
1433       q[XX] *= scale;  q[YY] *= scale;  q[ZZ] *= scale;  q[WW] *= scale;
1434    }
1435 }
1436 
extract_rotation(double m[][4],dpCoord3D * axis,double * angle)1437 void extract_rotation(double m[][4], dpCoord3D* axis, double* angle)
1438 {
1439    /* extract matrix rotation in axis-angle format */
1440 
1441    Quat q;
1442 
1443    matrix_to_quat(m, q);
1444 
1445    quat_to_axis_angle_rot(q, axis, angle);
1446 }
1447 
extract_xyz_rot_spacefixed(double m[][4],double xyz_rot[3])1448 void extract_xyz_rot_spacefixed(double m[][4], double xyz_rot[3])
1449 {
1450    /* NOTE: extracts SPACE-FIXED rotations in x,y,z order.
1451     *  The matrix may have scale factors in it, so it needs to
1452     *  be normalized first.
1453     */
1454    double mat[4][4];
1455 
1456    copy_4x4matrix(m, mat);
1457    normalize_vector(mat[0], mat[0]);
1458    normalize_vector(mat[1], mat[1]);
1459    normalize_vector(mat[2], mat[2]);
1460 
1461    xyz_rot[YY] = asin(-mat[0][2]);
1462 
1463    if (NOT_EQUAL_WITHIN_ERROR(0.0,cos(xyz_rot[YY])))
1464    {
1465       xyz_rot[XX] = atan2(mat[1][2], mat[2][2]);
1466       xyz_rot[ZZ] = atan2(mat[0][1], mat[0][0]);
1467    }
1468    else
1469    {
1470       xyz_rot[XX] = atan2(mat[1][0], mat[1][1]);
1471       xyz_rot[ZZ] = 0.0;
1472    }
1473 }
1474 
extract_xyz_rot_bodyfixed(double m[][4],double xyz_rot[3])1475 void extract_xyz_rot_bodyfixed(double m[][4], double xyz_rot[3])
1476 {
1477    /* NOTE: extracts BODY-FIXED rotations in x,y,z order, which
1478     *  is the same as space-fixed rotations in z,y,x order.
1479     *  The matrix may have scale factors in it, so it needs to
1480     *  be normalized first.
1481     */
1482    double mat1[4][4], mat2[4][4];
1483 
1484 #if 0
1485    // Normalize the columns by transposing so that the
1486    // vectors are contiguous. Then transpose back.
1487    transpose_4x4matrix(m, mat1);
1488    normalize_vector(mat1[0], mat1[0]);
1489    normalize_vector(mat1[1], mat1[1]);
1490    normalize_vector(mat1[2], mat1[2]);
1491    transpose_4x4matrix(mat1, mat2);
1492 #else
1493    copy_4x4matrix(m, mat2);
1494    normalize_vector(mat2[0], mat2[0]);
1495    normalize_vector(mat2[1], mat2[1]);
1496    normalize_vector(mat2[2], mat2[2]);
1497 #endif
1498 
1499    xyz_rot[YY] = asin(mat2[2][0]);
1500 
1501    if (NOT_EQUAL_WITHIN_ERROR(0.0,cos(xyz_rot[YY])))
1502    {
1503       xyz_rot[XX] = atan2(-mat2[2][1], mat2[2][2]);
1504       xyz_rot[ZZ] = atan2(-mat2[1][0], mat2[0][0]);
1505    }
1506    else
1507    {
1508       xyz_rot[XX] = atan2(mat2[0][1], mat2[1][1]);
1509       xyz_rot[ZZ] = 0.0;
1510    }
1511    /* NOTE: a body-fixed sequence of rotations is equivalent to
1512     *  the same sequence of space-fixed rotation in the *opposite*
1513     *  order!!  (see: "Introduction to Robotics, 2nd Ed. by J. Craig,
1514     *  page 49)  -- KMS 2/17/99
1515     */
1516 }
1517 
make_quaternion(Quat q,const double axis[3],double angle)1518 static void make_quaternion(Quat q, const double axis[3], double angle)
1519 {
1520    /* make a quaternion given an axis-angle rotation
1521     * (from java-based vecmath package)
1522     */
1523    double n, halfAngle;
1524 
1525    q[XX] = axis[XX];
1526    q[YY] = axis[YY];
1527    q[ZZ] = axis[ZZ];
1528 
1529    n = sqrt(SQR(q[XX]) + SQR(q[YY]) + SQR(q[ZZ]));
1530 
1531    halfAngle = 0.5 * angle;
1532 
1533    if (NOT_EQUAL_WITHIN_ERROR(n,0.0))
1534    {
1535       double s = sin(halfAngle) / n;
1536 
1537       q[XX] *= s;  q[YY] *= s;  q[ZZ] *= s;
1538 
1539       q[WW] = cos(halfAngle);
1540    }
1541 }
1542 
quat_to_matrix(const Quat q,double m[][4])1543 static void quat_to_matrix (const Quat q, double m[][4])
1544 {
1545    /* make a rotation matrix from a quaternion */
1546 
1547    double Nq = SQR(q[XX]) + SQR(q[YY]) + SQR(q[ZZ]) + SQR(q[WW]);
1548    double s = (Nq > 0.0) ? (2.0 / Nq) : 0.0;
1549 
1550    double xs = q[XX] * s,   ys = q[YY] * s,   zs = q[ZZ] * s;
1551    double wx = q[WW] * xs,  wy = q[WW] * ys,  wz = q[WW] * zs;
1552    double xx = q[XX] * xs,  xy = q[XX] * ys,  xz = q[XX] * zs;
1553    double yy = q[YY] * ys,  yz = q[YY] * zs,  zz = q[ZZ] * zs;
1554 
1555    m[XX][XX] = 1.0 - (yy + zz);  m[XX][YY] = xy + wz;          m[XX][ZZ] = xz - wy;
1556    m[YY][XX] = xy - wz;          m[YY][YY] = 1.0 - (xx + zz);  m[YY][ZZ] = yz + wx;
1557    m[ZZ][XX] = xz + wy;          m[ZZ][YY] = yz - wx;          m[ZZ][ZZ] = 1.0 - (xx + yy);
1558 
1559    m[XX][WW] = m[YY][WW] = m[ZZ][WW] = m[WW][XX] = m[WW][YY] = m[WW][ZZ] = 0.0;
1560    m[WW][WW] = 1.0;
1561 }
1562 
rotate_matrix_by_quat(double m[][4],const Quat q)1563 static void rotate_matrix_by_quat(double m[][4], const Quat q)
1564 {
1565    /* append a quaternion rotation to a matrix */
1566 
1567    double n[4][4];
1568 
1569    quat_to_matrix(q, n);
1570 
1571    append_matrix(m, n);    /* append matrix 'n' onto matrix 'm' */
1572 }
1573 
rotate_matrix_axis_angle(double m[][4],const double * axis,double angle)1574 void rotate_matrix_axis_angle (double m[][4], const double* axis, double angle)
1575 {
1576     Quat q;
1577 
1578     make_quaternion(q, axis, angle);
1579     rotate_matrix_by_quat(m, q);
1580 }
1581 
lerp_pt(double start[3],double end[3],double t,double result[3])1582 void lerp_pt(double start[3], double end[3], double t, double result[3])
1583 {
1584    result[0] = start[0] + t * (end[0] - start[0]);
1585    result[1] = start[1] + t * (end[1] - start[1]);
1586    result[2] = start[2] + t * (end[2] - start[2]);
1587 }
1588 
slerp(const dpCoord3D * axisStart,double angleStart,const dpCoord3D * axisEnd,double angleEnd,double t,dpCoord3D * axisResult,double * angleResult)1589 void slerp(const dpCoord3D* axisStart, double angleStart,
1590            const dpCoord3D* axisEnd,   double angleEnd,
1591            double t,
1592            dpCoord3D* axisResult, double* angleResult)
1593 {
1594    Quat from, to, res;
1595    double to1[4], omega, cosom, sinom, scale0, scale1;
1596 
1597    make_quaternion(from, axisStart->xyz, angleStart);
1598    make_quaternion(to,   axisEnd->xyz,   angleEnd);
1599 
1600    /* calc cosine */
1601    cosom = from[XX] * to[XX] + from[YY] * to[YY] + from[ZZ] * to[ZZ] + from[WW] * to[WW];
1602 
1603    /* adjust signs (if necessary) */
1604    if (cosom < 0.0)
1605    {
1606       cosom = -cosom; to1[0] = - to[XX];
1607       to1[1] = - to[YY];
1608       to1[2] = - to[ZZ];
1609       to1[3] = - to[WW];
1610    }
1611    else
1612    {
1613       to1[0] = to[XX];
1614       to1[1] = to[YY];
1615       to1[2] = to[ZZ];
1616       to1[3] = to[WW];
1617    }
1618 
1619    /* calculate coefficients */
1620    if ((1.0 - cosom) > TINY_NUMBER)
1621    {
1622       /* standard case (slerp) */
1623       omega = acos(cosom);
1624       sinom = sin(omega);
1625       scale0 = sin((1.0 - t) * omega) / sinom;
1626       scale1 = sin(t * omega) / sinom;
1627    }
1628    else
1629    {
1630       /* "from" and "to" quaternions are very close, do a linear interpolation */
1631       scale0 = 1.0 - t;
1632       scale1 = t;
1633    }
1634    /* calculate final values */
1635    res[XX] = scale0 * from[XX] + scale1 * to1[XX];
1636    res[YY] = scale0 * from[YY] + scale1 * to1[YY];
1637    res[ZZ] = scale0 * from[ZZ] + scale1 * to1[ZZ];
1638    res[WW] = scale0 * from[WW] + scale1 * to1[WW];
1639 
1640    quat_to_axis_angle_rot(res, axisResult, angleResult);
1641 }
1642 
find_primary_direction(double vec[])1643 smAxes find_primary_direction(double vec[])
1644 {
1645    double x_abs = ABS(vec[0]);
1646    double y_abs = ABS(vec[1]);
1647    double z_abs = ABS(vec[2]);
1648 
1649    if (x_abs >= y_abs)
1650    {
1651       if (x_abs >= z_abs)
1652       {
1653          if (vec[0] > 0.0)
1654             return smX;
1655          else
1656             return smNegX;
1657       }
1658       else
1659       {
1660          if (vec[2] > 0.0)
1661             return smZ;
1662          else
1663             return smNegZ;
1664       }
1665    }
1666    else
1667    {
1668       if (y_abs >= z_abs)
1669       {
1670          if (vec[1] > 0.0)
1671             return smY;
1672          else
1673             return smNegY;
1674       }
1675       else
1676       {
1677          if (vec[2] > 0.0)
1678             return smZ;
1679          else
1680             return smNegZ;
1681       }
1682    }
1683 }
1684 
1685 
1686 /* COPY_4X4MATRIX: copies a 4x4 matrix */
copy_4x4matrix(double from[][4],double to[][4])1687 void copy_4x4matrix(double from[][4], double to[][4])
1688 {
1689    to[0][0] = from[0][0];
1690    to[0][1] = from[0][1];
1691    to[0][2] = from[0][2];
1692    to[0][3] = from[0][3];
1693    to[1][0] = from[1][0];
1694    to[1][1] = from[1][1];
1695    to[1][2] = from[1][2];
1696    to[1][3] = from[1][3];
1697    to[2][0] = from[2][0];
1698    to[2][1] = from[2][1];
1699    to[2][2] = from[2][2];
1700    to[2][3] = from[2][3];
1701    to[3][0] = from[3][0];
1702    to[3][1] = from[3][1];
1703    to[3][2] = from[3][2];
1704    to[3][3] = from[3][3];
1705 }
1706