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