root/cgm/trunk/geom/AnalyticGeometryTool.cpp

Revision 1040, 189.9 KB (checked in by tautges, 2 years ago)

Version 10.2 of cgm.

  • Property svn:executable set to *
Line 
1//- Class:       AnalyticGeometryTool
2//- Description: This class performs calculations on analytic geometry
3//               (points, lines, arcs, planes, polygons).  Capabilities
4//               include vector and point math, matrix operations,
5//               measurements, intersections and comparison/containment checks.
6//
7//- Owner: Steve Storm, Caterpillar Inc.
8//- Checked by:
9
10
11#include <float.h>
12#include "AnalyticGeometryTool.hpp"
13#include "CubitMessage.hpp"
14#include "CubitBox.hpp"
15#include "CubitPlane.hpp"
16#include "CubitVector.hpp"
17#include "DLIList.hpp"
18#include <math.h>
19#include "CastTo.hpp"
20
21#include <fstream>
22using std::cout;
23using std::endl;
24using std::ofstream;
25using std::ios;
26using std::ostream;
27
28static double AGT_IDENTITY_MTX_4X4[4][4] = { {1.0, 0.0, 0.0, 0.0},
29                                             {0.0, 1.0, 0.0, 0.0},
30                                             {0.0, 0.0, 1.0, 0.0},
31                                             {0.0, 0.0, 0.0, 1.0} };
32
33static double AGT_IDENTITY_MTX_3X3[3][3] = { {1.0, 0.0, 0.0},
34                                             {0.0, 1.0, 0.0},
35                                             {0.0, 0.0, 1.0} };
36
37AnalyticGeometryTool* AnalyticGeometryTool::instance_ = 0;
38
39Point2 operator+ (const Point2& p, const Point2& q)
40{
41    Point2 add;
42    add.x = p.x + q.x;
43    add.y = p.y + q.y;
44    return add;
45}
46
47Point2 operator- (const Point2& p, const Point2& q)
48{
49    Point2 sub;
50    sub.x = p.x - q.x;
51    sub.y = p.y - q.y;
52    return sub;
53}
54
55Point2 operator* (double t, const Point2& p)
56{
57    Point2 prod;
58    prod.x = t*p.x;
59    prod.y = t*p.y;
60    return prod;
61}
62
63Point2 operator* (const Point2& p, double t)
64{
65    Point2 prod;
66    prod.x = t*p.x;
67    prod.y = t*p.y;
68    return prod;
69}
70
71Point2 operator- (const Point2& p)
72{
73    Point2 neg;
74    neg.x = -p.x;
75    neg.y = -p.y;
76    return neg;
77}
78
79inline double AnalyticGeometryTool::Dot (const Point2& p, const Point2& q)
80{
81    return double(p.x*q.x + p.y*q.y);
82}
83
84Point3 operator+ (const Point3& p, const Point3& q)
85{
86    Point3 add;
87    add.x = p.x + q.x;
88    add.y = p.y + q.y;
89    add.z = p.z + q.z;
90    return add;
91}
92
93Point3 operator- (const Point3& p, const Point3& q)
94{
95    Point3 sub;
96    sub.x = p.x - q.x;
97    sub.y = p.y - q.y;
98    sub.z = p.z - q.z;
99    return sub;
100}
101
102Point3 operator* (double t, const Point3& p)
103{
104    Point3 prod;
105    prod.x = t*p.x;
106    prod.y = t*p.y;
107    prod.z = t*p.z;
108    return prod;
109}
110
111Point3 operator* (const Point3& p, double t)
112{
113    Point3 prod;
114    prod.x = t*p.x;
115    prod.y = t*p.y;
116    prod.z = t*p.z;
117    return prod;
118}
119
120Point3 operator- (const Point3& p)
121{
122    Point3 neg;
123    neg.x = -p.x;
124    neg.y = -p.y;
125    neg.z = -p.z;
126    return neg;
127}
128
129// Method: instance
130// provides access to the unique model for this execution.
131// sets up this instance on first access
132AnalyticGeometryTool* AnalyticGeometryTool::instance()
133{
134  if (instance_ == 0) {
135    instance_ = new AnalyticGeometryTool;
136  }
137  return instance_;
138}
139
140AnalyticGeometryTool::AnalyticGeometryTool() 
141{
142   agtEpsilon = 1e-8;
143}
144
145AnalyticGeometryTool::~AnalyticGeometryTool()
146{
147}
148
149//***************************************************************************
150// Double numbers
151//***************************************************************************
152
153
154void AnalyticGeometryTool::round_near_val( double &val )
155{
156   if( dbl_eq( val, 0.0 ) )
157      val = 0.0;
158   else if( dbl_eq( val, 1.0 ) )
159      val  = 1.0;
160   else if( dbl_eq( val, -1.0 ) )
161      val = -1.0;
162}
163
164//***************************************************************************
165// Matrices & Transforms
166//***************************************************************************
167void AnalyticGeometryTool::transform_pnt( double m[4][4], 
168                                         double pin[3],
169                                         double pout[3] )
170{
171    double p[3];  // working buffer
172   
173    // Check if transformation can occur
174    if (!m) {
175       if (pin && pout)
176          copy_pnt(pin, pout);
177       return;
178    }
179   
180    // Perform transformation   
181    p[0] = m[0][0] * pin[0] + m[1][0] * pin[1] + m[2][0] * pin[2] + m[3][0];
182    p[1] = m[0][1] * pin[0] + m[1][1] * pin[1] + m[2][1] * pin[2] + m[3][1];
183    p[2] = m[0][2] * pin[0] + m[1][2] * pin[1] + m[2][2] * pin[2] + m[3][2];
184   
185    // Copy work buffer to out point   
186    copy_pnt(p,pout);
187} 
188
189void AnalyticGeometryTool::transform_vec( double m3[3][3],
190                                         double vin[3],
191                                         double vout[3] )
192{
193   double v[3];    // working buffer
194   
195   // Determine if transformation can occur
196   if (!m3) {     
197      if (vin && vout)
198         copy_vec(vin, vout);
199      return;
200   }
201   
202   // Perform transformation
203   v[0] = m3[0][0] * vin[0] + m3[1][0] * vin[1] + m3[2][0] * vin[2];
204   v[1] = m3[0][1] * vin[0] + m3[1][1] * vin[1] + m3[2][1] * vin[2];
205   v[2] = m3[0][2] * vin[0] + m3[1][2] * vin[1] + m3[2][2] * vin[2];
206   
207   // Copy work buffer to vector out   
208   copy_pnt(v,vout);
209}
210
211void AnalyticGeometryTool::transform_vec( double m4[4][4], 
212                                         double vin[3],
213                                         double vout[3] )
214{
215   double v[3];    // working buffer
216   
217   // Determine if transformation can occur
218   if (!m4) {     
219      if (vin && vout)
220         copy_vec(vin, vout);
221      return;
222   }
223   
224   // Perform transformation
225   
226   v[0] = m4[0][0] * vin[0] + m4[1][0] * vin[1] + m4[2][0] * vin[2];
227   v[1] = m4[0][1] * vin[0] + m4[1][1] * vin[1] + m4[2][1] * vin[2];
228   v[2] = m4[0][2] * vin[0] + m4[1][2] * vin[1] + m4[2][2] * vin[2];
229   
230   // Copy work buffer to vector out   
231   copy_pnt(v,vout);
232}
233
234void AnalyticGeometryTool::transform_line( double rot_mtx[4][4],
235                                           double origin[3], double axis[3] )
236{
237   double end_pnt[3]; // Find arbitrary end point on line
238   next_pnt( origin, axis, 10.0, end_pnt );
239   
240   transform_pnt( rot_mtx, origin, origin );
241   transform_pnt( rot_mtx, end_pnt, end_pnt );
242   
243   axis[0] = end_pnt[0] - origin[0];
244   axis[1] = end_pnt[1] - origin[1];
245   axis[2] = end_pnt[2] - origin[2];
246}
247
248void AnalyticGeometryTool::transform_line( double rot_mtx[4][4],
249                                          CubitVector &origin, CubitVector &axis )
250{
251   CubitVector end_point; // Find arbitrary end point on line
252   origin.next_point( axis, 10.0, end_point );
253   
254   double start_pnt[3], end_pnt[3];
255   copy_pnt( origin, start_pnt );
256   copy_pnt( end_point, end_pnt );
257   
258   transform_pnt( rot_mtx, start_pnt, start_pnt );
259   transform_pnt( rot_mtx, end_pnt, end_pnt );
260   
261   axis.x( end_pnt[0] - start_pnt[0] );
262   axis.y( end_pnt[1] - start_pnt[1] );
263   axis.z( end_pnt[2] - start_pnt[2] );
264   
265   origin.set( start_pnt );
266}
267
268void AnalyticGeometryTool::copy_mtx( double from[3][3],double to[3][3] )
269{   
270   // Determine if identity matrix needed
271   if (!from) // copy in the identity matrix
272      memcpy(to, AGT_IDENTITY_MTX_3X3, sizeof(double)*9); 
273   else // Copy from to to
274      memcpy(to, from, sizeof(double)*9);   
275}
276
277void AnalyticGeometryTool::copy_mtx( double from[4][4], double to[4][4] )
278{   
279   // determine if identity matrix needed
280   if (!from) // copy in the identity matrix
281      memcpy(to, AGT_IDENTITY_MTX_4X4, sizeof(double)*16); 
282   else // copy from to to
283      memcpy(to, from, sizeof(double)*16);   
284}
285
286void AnalyticGeometryTool::copy_mtx( double from[4][4], double to[3][3] )
287{   
288   size_t dbl3;
289   
290   dbl3 = sizeof(double) * 3;
291   
292   // Determine if identity matrix needed
293   if (!from) // Copy in the identity matrix
294      memcpy(to, AGT_IDENTITY_MTX_3X3, sizeof(double)*9); 
295   else { // Copy each upper left element of from to to
296      memcpy(to[0], from[0], dbl3);
297      memcpy(to[1], from[1], dbl3);
298      memcpy(to[2], from[2], dbl3);
299   }   
300}
301
302void AnalyticGeometryTool::copy_mtx(double from[3][3], double to[4][4],
303                                    double* origin )
304{   
305   size_t dbl3;
306   
307   dbl3 = sizeof(double) * 3;
308   
309   // Determine if identity matrix needed
310   if (!from) { // Copy in the identity matrix
311   
312      memcpy(to, AGT_IDENTITY_MTX_4X4, sizeof(double)*16);
313     
314      if (origin)
315         memcpy(to[3], origin, dbl3);
316   }   
317             
318   else { // Copy each upper element of from to to
319     
320      memcpy(to[0], from[0], dbl3);
321      memcpy(to[1], from[1], dbl3);
322      memcpy(to[2], from[2], dbl3);
323     
324      to[0][3] = 0.0;
325      to[1][3] = 0.0;
326      to[2][3] = 0.0;
327      to[3][3] = 1.0;
328     
329      if (origin)
330      {
331         memcpy(to[3], origin, dbl3);
332//         to[3][0] = origin[0];
333//         to[3][1] = origin[1];
334//         to[3][2] = origin[2];
335      }
336      else
337         memcpy(to[3], AGT_IDENTITY_MTX_4X4[3], sizeof(double)*3);
338   } 
339}
340
341void AnalyticGeometryTool::create_rotation_mtx( double theta, double v[3],
342                                               double mtx3x3[3][3] )
343{       
344   double coeff1;
345   double coeff2;
346   double coeff3;
347   double v_unit[3];
348   
349   if (!mtx3x3)
350      return;
351   
352   coeff1 = cos(theta);
353   coeff2 = (1.0l - coeff1);
354   coeff3 = sin(theta);
355   
356   unit_vec(v, v_unit);
357   
358   mtx3x3[0][0] = coeff1 + coeff2 * (v_unit[0] * v_unit[0]);
359   mtx3x3[0][1] = coeff2 * v_unit[1] * v_unit[0] + coeff3 * v_unit[2];
360   mtx3x3[0][2] = coeff2 * v_unit[2] * v_unit[0] - coeff3 * v_unit[1];
361   
362   mtx3x3[1][0] = coeff2 * v_unit[1] * v_unit[0] - coeff3 * v_unit[2];
363   mtx3x3[1][1] = coeff1 + coeff2 * (v_unit[1] * v_unit[1]);
364   mtx3x3[1][2] = coeff2 * v_unit[1] * v_unit[2] + coeff3 * v_unit[0];
365   
366   mtx3x3[2][0] = coeff2 * v_unit[2] * v_unit[0] + coeff3 * v_unit[1];
367   mtx3x3[2][1] = coeff2 * v_unit[2] * v_unit[1] - coeff3 * v_unit[0];
368   mtx3x3[2][2] = coeff1 + coeff2 * (v_unit[2] * v_unit[2]);
369}
370
371void AnalyticGeometryTool::create_rotation_mtx( double theta, double v[3],
372                                               double mtx4x4[4][4] )
373{       
374   double coeff1;
375   double coeff2;
376   double coeff3;
377   double v_unit[3];
378   
379   if (!mtx4x4)
380      return;
381   
382   coeff1 = cos(theta);
383   coeff2 = (1.0l - coeff1);
384   coeff3 = sin(theta);
385
386   unit_vec(v, v_unit);
387   
388   mtx4x4[0][0] = coeff1 + coeff2 * (v_unit[0] * v_unit[0]);
389   mtx4x4[0][1] = coeff2 * v_unit[1] * v_unit[0] + coeff3 * v_unit[2];
390   mtx4x4[0][2] = coeff2 * v_unit[2] * v_unit[0] - coeff3 * v_unit[1];
391   
392   mtx4x4[1][0] = coeff2 * v_unit[1] * v_unit[0] - coeff3 * v_unit[2];
393   mtx4x4[1][1] = coeff1 + coeff2 * (v_unit[1] * v_unit[1]);
394   mtx4x4[1][2] = coeff2 * v_unit[1] * v_unit[2] + coeff3 * v_unit[0];
395   
396   mtx4x4[2][0] = coeff2 * v_unit[2] * v_unit[0] + coeff3 * v_unit[1];
397   mtx4x4[2][1] = coeff2 * v_unit[2] * v_unit[1] - coeff3 * v_unit[0];
398   mtx4x4[2][2] = coeff1 + coeff2 * (v_unit[2] * v_unit[2]);
399   
400   mtx4x4[0][3] = 0.0;
401   mtx4x4[1][3] = 0.0;
402   mtx4x4[2][3] = 0.0;
403   mtx4x4[3][3] = 1.0;
404   mtx4x4[3][0] = 0.0;
405   mtx4x4[3][1] = 0.0;
406   mtx4x4[3][2] = 0.0; 
407}
408
409void AnalyticGeometryTool::add_origin_to_rotation_mtx( double rot_mtx[4][4], 
410                                                      double origin[3] )
411{ 
412   double tmp_mtx[4][4];
413
414   // Translate to origin
415   double t[4][4]; 
416   memcpy(t, AGT_IDENTITY_MTX_4X4, sizeof(double)*16);
417   //PRINT_INFO( "Rotation matrix, before origin: \n" );
418   //print_mtx( rot_mtx );
419   t[3][0]=-origin[0]; t[3][1]=-origin[1]; t[3][2]=-origin[2];
420   mult_mtx( t, rot_mtx, tmp_mtx );
421   
422   //PRINT_INFO( "Origin times rotation: \n" );
423   //print_mtx( tmp_mtx );
424   
425   // Translate back
426   t[3][0]=origin[0]; t[3][1]=origin[1]; t[3][2]=origin[2];
427   mult_mtx( tmp_mtx, t, rot_mtx );
428   
429   //PRINT_INFO( "Rotation x -origin: \n" );
430   //print_mtx( rot_mtx );
431}
432
433void AnalyticGeometryTool::identity_mtx( double mtx3x3[3][3] )
434{ 
435   memcpy(mtx3x3, AGT_IDENTITY_MTX_3X3, sizeof(double)*9);
436}
437
438void AnalyticGeometryTool::identity_mtx( double mtx4x4[4][4] )
439{ 
440   memcpy(mtx4x4, AGT_IDENTITY_MTX_4X4, sizeof(double)*16);
441}
442
443void AnalyticGeometryTool::mtx_to_angs( double mtx3x3[3][3],
444                                       double &ax, double &ay,
445                                       double &az )
446{   
447//   METHOD:
448//   o Rotate x-vector onto xz plane
449//   o  Check xp dotted into y 
450//   o   If xp dot y is zero  ==> az = 0 (x-vector already in xz plane)
451//   o   Otherwise, compute rotation of vector into xz plane to acquire *az     
452//   o    Use atan2 (on x-vector) to get *az
453//   o    Rotate the system about z
454//   o Use atan2 function (on x-vector in xz plane) to determine *ay
455//   o Rotate the system about y     
456//   o Compute ax using y-vector
457//   o Resultant angles are negated (to reverse above procedure)
458 
459   double x[3];                    // x-axis vector
460   double y[3];                    // y-axis vector
461   double z[3];                    // z-axis vector
462   double ar[3][3];                // Rotation matrix
463   double sinr,cosr;               // Used for atan2 function
464   double work_sys[3][3];          // Temporary holder for system
465   double *xp = work_sys[0];       // x-axis vector of system: x-primed
466   double *yp = work_sys[1];       // y-axis vector of system: y-primed
467   
468   x[0] = 1.0; x[1] = 0.0; x[2] = 0.0;
469   y[0] = 0.0; y[1] = 1.0; y[2] = 0.0;
470   z[0] = 0.0; z[1] = 0.0; z[2] = 1.0;
471   
472   if (!mtx3x3)
473      return;
474   
475   // Copy matrix over to work csys
476   copy_mtx(mtx3x3,work_sys);
477     
478   // Check xp dotted into y
479   //   If xp dot y is zero  ==> az = 0
480   
481   // Otherwise, compute rotation of vector into xz plane to acquire *az
482   
483   if (dbl_eq(dot_vec(xp,y), 0.0))
484     
485      az = 0.0;
486         
487   else {
488     
489      /*
490      Compute *az - rotate xp to xz-plane about z-axis         
491               y    xp                                           
492               |  /                                             
493               | /  negative angle about z (negative of atan2)   
494                -----x              (use RH rule about z)       
495                 \                                               
496                  \ positive angle about z (negative of atan2)         
497                   xp                                           
498      */
499         
500      sinr = dot_vec(xp,y);
501      cosr = dot_vec(xp,x);
502      az = - atan2(sinr, cosr);
503     
504      // Rotate the system about z
505      create_rotation_mtx(az,z,ar);
506      rotate_system(ar,work_sys,work_sys);
507     
508   }
509   
510      /*
511      Compute *ay - rotate xp to x-axis about y-axis           
512              z    xp                                           
513              |  /                                             
514              | /  positive angle about y (positive of atan2)   
515               -----x     (use RH rule about y)                 
516                \                                               
517                 \ negative angle about y (positive of atan2)   
518                  xp                                           
519      */
520   
521   sinr = dot_vec(xp,z);
522   cosr = dot_vec(xp,x);
523   ay = atan2(sinr, cosr);
524   
525   // Rotate the system about y       
526   create_rotation_mtx(ay,y,ar);     
527   rotate_system(ar,work_sys,work_sys);
528 
529   /*
530      Compute *ax - rotate yp to y-axis about x-axis           
531              z    yp                                           
532              |  /                                             
533              | /  negative angle about x (negative of atan2)   
534               -----y     (use RH rule about x)                 
535                \                                               
536                 \ positive angle about x (negative of atan2)   
537                  yp                                           
538   */
539   
540   sinr = dot_vec(yp,z);
541   cosr = dot_vec(yp,y);
542   ax = atan2(sinr,cosr);     // Negative of negative - see below
543   
544   // Negate above angles for rotation of the system back to original
545   az = -(az);
546   ay = -(ay);
547   
548   // Make sure near zero angles are actually zero
549   if (dbl_eq(ax, 0.0))
550      ax = 0.0;
551   
552   if (dbl_eq(ay, 0.0))
553      ay = 0.0;   
554}
555
556void AnalyticGeometryTool::mtx_to_angs( double mtx4x4[4][4],
557                                       double &ax, double &ay,
558                                       double &az )
559{   
560   double work_sys[3][3];
561
562   if(!mtx4x4)
563      return;
564
565   copy_mtx(mtx4x4,work_sys);
566   mtx_to_angs( work_sys, ax, ay, az );
567}
568
569void AnalyticGeometryTool::rotate_system( double mtx[3][3], 
570                                         double sys_in[3][3],
571                                         double sys_out[3][3] )
572{
573   double sys_tmp[3][3];
574   double *p_sys_tmp;
575   
576   // Check to see if rotating in place
577   if (sys_in == sys_out) {
578      copy_mtx( sys_in, sys_tmp );
579      p_sys_tmp = (double *)sys_tmp; 
580   }
581   else 
582      // Have sys_tmp point at outgoing memory location
583      p_sys_tmp = (double *)sys_out;
584   
585   
586   // X-vector
587   p_sys_tmp[0] =   mtx[0][0] * sys_in[0][0]
588                  + mtx[1][0] * sys_in[0][1]
589                  + mtx[2][0] * sys_in[0][2];
590   p_sys_tmp[1] =   mtx[0][1] * sys_in[0][0]
591                  + mtx[1][1] * sys_in[0][1]
592                  + mtx[2][1] * sys_in[0][2];
593   p_sys_tmp[2] =   mtx[0][2] * sys_in[0][0]
594                  + mtx[1][2] * sys_in[0][1]
595                  + mtx[2][2] * sys_in[0][2];   
596   
597   // Y-vector
598   p_sys_tmp[3] =   mtx[0][0] * sys_in[1][0]
599                  + mtx[1][0] * sys_in[1][1]
600                  + mtx[2][0] * sys_in[1][2];
601   p_sys_tmp[4] =   mtx[0][1] * sys_in[1][0]
602                  + mtx[1][1] * sys_in[1][1]
603                  + mtx[2][1] * sys_in[1][2];
604   p_sys_tmp[5] =   mtx[0][2] * sys_in[1][0]
605                  + mtx[1][2] * sys_in[1][1]
606                  + mtx[2][2] * sys_in[1][2];
607   
608   // Z-vector
609   p_sys_tmp[6] =   mtx[0][0] * sys_in[2][0]
610                  + mtx[1][0] * sys_in[2][1]
611                  + mtx[2][0] * sys_in[2][2];
612   p_sys_tmp[7] =   mtx[0][1] * sys_in[2][0]
613                  + mtx[1][1] * sys_in[2][1]
614                  + mtx[2][1] * sys_in[2][2];
615   p_sys_tmp[8] =   mtx[0][2] * sys_in[2][0]
616                  + mtx[1][2] * sys_in[2][1]
617                  + mtx[2][2] * sys_in[2][2];
618   
619    // Copy sys_tmp to sys_out if rotating in place
620   if (sys_in == sys_out) {
621      memcpy(sys_out, sys_tmp, sizeof(double)*9); 
622   }
623}
624
625void AnalyticGeometryTool::rotate_system( double mtx[4][4], 
626                                         double sys_in[4][4],
627                                         double sys_out[4][4] )
628{
629   double sys_tmp[4][4];
630   double* p_sys_tmp;
631   
632   // Check to see if rotating in place
633   if (sys_in == sys_out) {
634      copy_mtx( sys_in, sys_tmp );
635      p_sys_tmp = (double *)sys_tmp; 
636   }
637   else 
638      // Have p_sys_tmp point at outgoing memory location
639      p_sys_tmp = (double *)sys_out;
640   
641   
642   // X-vector
643   p_sys_tmp[0] =   mtx[0][0] * sys_in[0][0]
644                  + mtx[1][0] * sys_in[0][1]
645                  + mtx[2][0] * sys_in[0][2];
646   p_sys_tmp[1] =   mtx[0][1] * sys_in[0][0]
647                  + mtx[1][1] * sys_in[0][1]
648                  + mtx[2][1] * sys_in[0][2];
649   p_sys_tmp[2] =   mtx[0][2] * sys_in[0][0]
650                  + mtx[1][2] * sys_in[0][1]
651                  + mtx[2][2] * sys_in[0][2];   
652   
653   // Y-vector
654   p_sys_tmp[4] =   mtx[0][0] * sys_in[1][0]
655                  + mtx[1][0] * sys_in[1][1]
656                  + mtx[2][0] * sys_in[1][2];
657   p_sys_tmp[5] =   mtx[0][1] * sys_in[1][0]
658                  + mtx[1][1] * sys_in[1][1]
659                  + mtx[2][1] * sys_in[1][2];
660   p_sys_tmp[6] =   mtx[0][2] * sys_in[1][0]
661                  + mtx[1][2] * sys_in[1][1]
662                  + mtx[2][2] * sys_in[1][2];
663   
664   // Z-vector
665   p_sys_tmp[8] =   mtx[0][0] * sys_in[2][0]
666                  + mtx[1][0] * sys_in[2][1]
667                  + mtx[2][0] * sys_in[2][2];
668   p_sys_tmp[9] =   mtx[0][1] * sys_in[2][0]
669                  + mtx[1][1] * sys_in[2][1]
670                  + mtx[2][1] * sys_in[2][2];
671   p_sys_tmp[10] =  mtx[0][2] * sys_in[2][0]
672                  + mtx[1][2] * sys_in[2][1]
673                  + mtx[2][2] * sys_in[2][2];
674   
675   // Maintain the origin
676   p_sys_tmp[3] = sys_in[0][3];
677   p_sys_tmp[7] = sys_in[1][3];
678   p_sys_tmp[11] = sys_in[2][3];
679   p_sys_tmp[15] = sys_in[3][3];   
680   p_sys_tmp[12] = sys_in[3][0];
681   p_sys_tmp[13] = sys_in[3][1];   
682   p_sys_tmp[14] = sys_in[3][2];   
683   
684    // Copy sys_tmp to sys_out if rotating in place
685   if (sys_in == sys_out) {
686      memcpy(sys_out, sys_tmp, sizeof(double)*16);
687   }
688}
689
690double AnalyticGeometryTool::det_mtx( double m[3][3] ) 
691{
692   double determinant;
693   
694   if (!m)
695      return (0.0);
696   
697   determinant = m[0][0]*(m[1][1]*m[2][2]-m[1][2]*m[2][1])
698               + m[0][1]*(m[1][2]*m[2][0]-m[1][0]*m[2][2])
699               + m[0][2]*(m[1][0]*m[2][1]-m[1][1]*m[2][0]);
700   
701   return (determinant);
702} 
703
704void AnalyticGeometryTool::mult_mtx( double a[3][3],double b[3][3], 
705                                    double d[3][3] ) 
706{       
707   double c[3][3];    // working buffer
708     
709   if( a != 0 && b != 0 ) {   // a & b are valid
710           
711      c[0][0] = (  a[0][0] * b[0][0] + a[0][1] * b[1][0] 
712                 + a[0][2] * b[2][0]);
713      c[1][0] = (  a[1][0] * b[0][0] + a[1][1] * b[1][0] 
714                 + a[1][2] * b[2][0]);
715      c[2][0] = (  a[2][0] * b[0][0] + a[2][1] * b[1][0] 
716                 + a[2][2] * b[2][0]);
717     
718      c[0][1] = (  a[0][0] * b[0][1] + a[0][1] * b[1][1] 
719                 + a[0][2] * b[2][1]);
720      c[1][1] = (  a[1][0] * b[0][1] + a[1][1] * b[1][1] 
721                 + a[1][2] * b[2][1]);
722      c[2][1] = (  a[2][0] * b[0][1] + a[2][1] * b[1][1] 
723                 + a[2][2] * b[2][1]);
724     
725      c[0][2] = (  a[0][0] * b[0][2] + a[0][1] * b[1][2] 
726                 + a[0][2] * b[2][2]);
727      c[1][2] = (  a[1][0] * b[0][2] + a[1][1] * b[1][2]
728                 + a[1][2] * b[2][2]);
729      c[2][2] = (  a[2][0] * b[0][2] + a[2][1] * b[1][2]
730                 + a[2][2] * b[2][2]);
731     
732      copy_mtx(c, d);
733     
734   }
735   else if (a) {                 // b equals 0     
736      copy_mtx(a, d);   
737   }
738   else if (b) {                  // a equals 0
739      copy_mtx(b, d);   
740   }
741   else {                         // a & b equal 0
742     
743      copy_mtx(AGT_IDENTITY_MTX_3X3, d);         
744   }
745}
746
747void AnalyticGeometryTool::mult_mtx( double a[4][4], 
748                                    double b[4][4],
749                                    double d[4][4] ) 
750{       
751   double c[4][4];    // working buffer
752     
753   if( a != 0 && b != 0 ) {   // a & b are valid
754           
755      c[0][0] = (  a[0][0] * b[0][0] + a[0][1] * b[1][0] 
756                 + a[0][2] * b[2][0] + a[0][3] * b[3][0]);
757      c[1][0] = (  a[1][0] * b[0][0] + a[1][1] * b[1][0] 
758                 + a[1][2] * b[2][0] + a[1][3] * b[3][0]);
759      c[2][0] = (  a[2][0] * b[0][0] + a[2][1] * b[1][0] 
760                 + a[2][2] * b[2][0] + a[2][3] * b[3][0]);
761      c[3][0] = (  a[3][0] * b[0][0] + a[3][1] * b[1][0] 
762                 + a[3][2] * b[2][0] + a[3][3] * b[3][0]);
763     
764      c[0][1] = (  a[0][0] * b[0][1] + a[0][1] * b[1][1] 
765                 + a[0][2] * b[2][1] + a[0][3] * b[3][1]);
766      c[1][1] = (  a[1][0] * b[0][1] + a[1][1] * b[1][1] 
767                 + a[1][2] * b[2][1] + a[1][3] * b[3][1]);
768      c[2][1] = (  a[2][0] * b[0][1] + a[2][1] * b[1][1] 
769                 + a[2][2] * b[2][1] + a[2][3] * b[3][1]);
770      c[3][1] = (  a[3][0] * b[0][1] + a[3][1] * b[1][1] 
771                 + a[3][2] * b[2][1] + a[3][3] * b[3][1]);
772     
773      c[0][2] = (  a[0][0] * b[0][2] + a[0][1] * b[1][2] 
774                 + a[0][2] * b[2][2] + a[0][3] * b[3][2]);
775      c[1][2] = (  a[1][0] * b[0][2] + a[1][1] * b[1][2]
776                 + a[1][2] * b[2][2] + a[1][3] * b[3][2]);
777      c[2][2] = (  a[2][0] * b[0][2] + a[2][1] * b[1][2]
778                 + a[2][2] * b[2][2] + a[2][3] * b[3][2]);
779      c[3][2] = (  a[3][0] * b[0][2] + a[3][1] * b[1][2]
780                 + a[3][2] * b[2][2] + a[3][3] * b[3][2]);
781     
782      c[0][3] = (  a[0][0] * b[0][3] + a[0][1] * b[1][3]
783                 + a[0][2] * b[2][3] + a[0][3] * b[3][3]);
784      c[1][3] = (  a[1][0] * b[0][3] + a[1][1] * b[1][3]
785                 + a[1][2] * b[2][3] + a[1][3] * b[3][3]);
786      c[2][3] = (  a[2][0] * b[0][3] + a[2][1] * b[1][3]
787                 + a[2][2] * b[2][3] + a[2][3] * b[3][3]);
788      c[3][3] = (  a[3][0] * b[0][3] + a[3][1] * b[1][3]
789                 + a[3][2] * b[2][3] + a[3][3] * b[3][3]);
790     
791      copy_mtx(c, d);           
792   }
793   else if (a) {                 // b equals 0     
794      copy_mtx(a, d);   
795   }
796   else if (b) {                  // a equals 0
797      copy_mtx(b, d);   
798   }
799   else {                         // a & b equal 0
800     
801      copy_mtx(AGT_IDENTITY_MTX_4X4, d);         
802   }
803}
804
805CubitStatus AnalyticGeometryTool::inv_mtx_adj( double mtx[3][3],
806                                              double inv_mtx[3][3] )
807{
808   int i,i1,i2,j,j1,j2;
809   double work_mtx[3][3];
810   double determinant;
811   
812   // Check for null input
813   if (!mtx) {
814      copy_mtx(AGT_IDENTITY_MTX_3X3, inv_mtx);
815      return CUBIT_SUCCESS;
816   }     
817   
818   // Calculate determinant
819   determinant = det_mtx(mtx);
820   
821   // Check for singularity
822   if (dbl_eq(determinant,0.0))
823      return CUBIT_FAILURE;
824   
825   // Get work matrix (allow inverting in place)
826   copy_mtx(mtx, work_mtx);
827   
828   // Inverse is adjoint matrix divided by determinant
829   for (i=1; i<4; i++) {
830     
831      i1 = (i % 3) + 1;  i2 = (i1 % 3) + 1;
832     
833      for (j=1; j<4; j++) {
834         
835         j1 = (j % 3) + 1;  j2 = (j1 % 3) + 1;
836         
837         inv_mtx[j-1][i-1] = (work_mtx[i1-1][j1-1]*work_mtx[i2-1][j2-1] - 
838            work_mtx[i1-1][j2-1]*work_mtx[i2-1][j1-1]) 
839            / determinant;
840         
841      }
842   }
843   return CUBIT_SUCCESS;
844}
845
846CubitStatus AnalyticGeometryTool::inv_trans_mtx( double transf[4][4], 
847                                                double inv_transf[4][4] )
848{
849   double scale_sq;
850   double inv_sq_scale;
851   double tmp_transf[4][4]; // For temporary storage of incoming matrix
852   double *p_tmp_transf = NULL;
853
854   // If input transform is 0 set output to identity matrix
855   if (!transf) {
856      copy_mtx( AGT_IDENTITY_MTX_4X4, inv_transf );
857      return CUBIT_SUCCESS;
858   }
859   
860   // Obtain the matrix scale
861   scale_sq = transf[0][0]*transf[0][0] + transf[0][1]*transf[0][1] +
862              transf[0][2]*transf[0][2];
863   
864   // Check for singular matrix
865   if (scale_sq < (.000000001 * .000000001))
866      return CUBIT_FAILURE;
867   
868   // Need the inverse scale squared
869   inv_sq_scale = 1.0 / scale_sq;   
870   
871   // Check to see if inverting in place
872   if (transf == inv_transf) {
873      copy_mtx( transf, tmp_transf );
874      p_tmp_transf = (double *)tmp_transf;
875   }
876   else
877      p_tmp_transf = (double *)transf;
878   
879   // The X vector
880   inv_transf[0][0] = p_tmp_transf[0] * inv_sq_scale;
881   inv_transf[1][0] = p_tmp_transf[1] * inv_sq_scale;
882   inv_transf[2][0] = p_tmp_transf[2] * inv_sq_scale;
883   
884   // The Y vector
885   inv_transf[0][1] = p_tmp_transf[4] * inv_sq_scale;
886   inv_transf[1][1] = p_tmp_transf[5] * inv_sq_scale;
887   inv_transf[2][1] = p_tmp_transf[6] * inv_sq_scale;
888   
889   // The Z vector
890   inv_transf[0][2] = p_tmp_transf[8] * inv_sq_scale;
891   inv_transf[1][2] = p_tmp_transf[9] * inv_sq_scale;
892   inv_transf[2][2] = p_tmp_transf[10] * inv_sq_scale;
893   
894   // Column 4
895   inv_transf[0][3] = 0.0;
896   inv_transf[1][3] = 0.0;
897   inv_transf[2][3] = 0.0;
898   
899   // The X origin
900   inv_transf[3][0] = -inv_sq_scale * (  p_tmp_transf[0] * p_tmp_transf[12]
901                                       + p_tmp_transf[1] * p_tmp_transf[13]
902                                       + p_tmp_transf[2] * p_tmp_transf[14]);
903   
904   // The Y origin
905   inv_transf[3][1] = -inv_sq_scale * (  p_tmp_transf[4] * p_tmp_transf[12]
906                                       + p_tmp_transf[5] * p_tmp_transf[13]
907                                       + p_tmp_transf[6] * p_tmp_transf[14]);
908   
909   // The Z origin
910   inv_transf[3][2] = -inv_sq_scale * (  p_tmp_transf[8] * p_tmp_transf[12]
911                                       + p_tmp_transf[9] * p_tmp_transf[13]
912                                       + p_tmp_transf[10] * p_tmp_transf[14]);
913   
914   // This is always one
915   inv_transf[3][3] = 1.0;
916   
917   return CUBIT_SUCCESS;
918}
919
920void AnalyticGeometryTool::vecs_to_mtx( double xvec[3], 
921                                       double yvec[3],
922                                       double zvec[3],
923                                       double matrix[3][3] )
924{     
925   if (xvec) 
926      copy_pnt(xvec, matrix[0]);
927   else
928      copy_pnt(AGT_IDENTITY_MTX_3X3[0], matrix[0]);
929   
930   if (yvec)
931      copy_pnt(yvec, matrix[1]);
932   else
933      copy_pnt(AGT_IDENTITY_MTX_3X3[1], matrix[1]);
934   
935   if (zvec)
936      copy_pnt(zvec, matrix[2]);
937   else
938      copy_pnt(AGT_IDENTITY_MTX_3X3[2], matrix[2]);
939}   
940
941void AnalyticGeometryTool::vecs_to_mtx( double xvec[3], 
942                                       double yvec[3],
943                                       double zvec[3], 
944                                       double origin[3],
945                                       double matrix[4][4] )
946{     
947   if (xvec) 
948      copy_pnt(xvec, matrix[0]);
949   else
950      copy_pnt(AGT_IDENTITY_MTX_3X3[0], matrix[0]);
951   
952   if (yvec)
953      copy_pnt(yvec, matrix[1]);
954   else
955      copy_pnt(AGT_IDENTITY_MTX_3X3[1], matrix[1]);
956   
957   if (zvec)
958      copy_pnt(zvec, matrix[2]);
959   else
960      copy_pnt(AGT_IDENTITY_MTX_3X3[2], matrix[2]);
961   
962   if( origin )
963      copy_pnt(origin, matrix[3]);
964   else
965   {
966      matrix[3][0] = 0.0;
967      matrix[3][1] = 0.0;
968      matrix[3][2] = 0.0;
969   }
970
971   matrix[0][3] = 0.0;
972   matrix[1][3] = 0.0;
973   matrix[2][3] = 0.0;
974   matrix[3][3] = 1.0;   
975}
976
977void AnalyticGeometryTool::print_mtx( double mtx[3][3] )
978{
979   PRINT_INFO( "%f %f %f\n", mtx[0][0], mtx[0][1], mtx[0][2] );
980   PRINT_INFO( "%f %f %f\n", mtx[1][0], mtx[1][1], mtx[1][2] );
981   PRINT_INFO( "%f %f %f\n", mtx[2][0], mtx[2][1], mtx[2][2] );
982}
983
984void AnalyticGeometryTool::print_mtx( double mtx[4][4] )
985{
986   PRINT_INFO( "%f %f %f %f\n", mtx[0][0], mtx[0][1], mtx[0][2], mtx[0][3] );
987   PRINT_INFO( "%f %f %f %f\n", mtx[1][0], mtx[1][1], mtx[1][2], mtx[1][3] );
988   PRINT_INFO( "%f %f %f %f\n", mtx[2][0], mtx[2][1], mtx[2][2], mtx[2][3] );
989   PRINT_INFO( "%f %f %f %f\n", mtx[3][0], mtx[3][1], mtx[3][2], mtx[3][3] );
990}
991
992//***************************************************************************
993// 3D Points
994//***************************************************************************
995void AnalyticGeometryTool::copy_pnt( double pnt_in[3], double pnt_out[3] )
996{   
997   if (pnt_in == pnt_out)
998      return;
999   
1000   if (pnt_out == NULL)
1001      return;
1002   
1003   if (pnt_in == NULL) {
1004      pnt_out[0] = 0.0;
1005      pnt_out[1] = 0.0;
1006      pnt_out[2] = 0.0;
1007      return;
1008   }
1009   
1010   // Simply copy first point into second point   
1011   memcpy(pnt_out, pnt_in, sizeof(double)*3);
1012}
1013
1014void AnalyticGeometryTool::copy_pnt( double pnt_in[3], CubitVector &cubit_vec )
1015{
1016   cubit_vec.set( pnt_in );
1017}
1018   
1019void AnalyticGeometryTool::copy_pnt( CubitVector &cubit_vec, double pnt_out[3] )
1020{
1021   pnt_out[0] = cubit_vec.x();
1022   pnt_out[1] = cubit_vec.y();
1023   pnt_out[2] = cubit_vec.z();
1024}
1025
1026
1027CubitBoolean AnalyticGeometryTool::pnt_eq( double pnt1[3],double pnt2[3] )
1028{
1029   double x = pnt2[0] - pnt1[0];  // difference in the x direction
1030   double y = pnt2[1] - pnt1[1];  // difference in the y direction
1031   double z = pnt2[2] - pnt1[2];  // difference in the z direction
1032 
1033   return (dbl_eq(sqrt(x*x + y*y + z*z), 0.0));
1034}
1035
1036
1037CubitStatus AnalyticGeometryTool::mirror_pnt( double pnt[3], 
1038                                             double pln_orig[3],
1039                                             double pln_norm[3],
1040                                             double m_pnt[3])
1041{
1042   double int_pnt[3],
1043      vec[3];
1044   
1045   // Find intersection of point and plane
1046   if (int_pnt_pln(pnt, pln_orig, pln_norm, int_pnt)) {
1047      // If intersection is on the plane, return
1048      copy_pnt(pnt, m_pnt);
1049      return CUBIT_FAILURE;
1050   }
1051   
1052   // Find vector from pnt to int_pnt
1053   get_vec(pnt, int_pnt, vec);
1054   
1055   // Traverse twice the length of vec in vec direction
1056   m_pnt[0] = pnt[0] + 2.0 * vec[0];
1057   m_pnt[1] = pnt[1] + 2.0 * vec[1];
1058   m_pnt[2] = pnt[2] + 2.0 * vec[2];
1059   
1060   return CUBIT_SUCCESS;   
1061}
1062
1063
1064CubitStatus AnalyticGeometryTool::next_pnt( double str_pnt[3], 
1065                                           double vec_dir[3], 
1066                                           double len,
1067                                           double new_pnt[3])
1068{       
1069   double uv[3];  // unit vector representation of vector direction
1070   
1071   // unitize specified direction
1072   if (!unit_vec(vec_dir,uv)) {
1073      copy_pnt(str_pnt, new_pnt);
1074      return CUBIT_FAILURE;
1075   }
1076   
1077   // determine next point in space
1078   
1079   new_pnt[0] = str_pnt[0] + (len * uv[0]);     
1080   new_pnt[1] = str_pnt[1] + (len * uv[1]);     
1081   new_pnt[2] = str_pnt[2] + (len * uv[2]); 
1082   
1083   return CUBIT_SUCCESS;
1084}
1085
1086
1087//***************************************************************************
1088// 3D Vectors
1089//***************************************************************************
1090CubitStatus AnalyticGeometryTool::unit_vec( double vin[3], double vout[3] )
1091{
1092   double rmag; // holds magnitude of vector
1093     
1094   // Calculate vector magnitude
1095   rmag = sqrt(vin[0]*vin[0] + vin[1]*vin[1] + vin[2]*vin[2]);
1096   
1097   // check if vector has a magnitude - catch division by zero
1098   
1099   if (dbl_eq(rmag, 0.0)) {
1100      if (vin != vout)
1101         copy_pnt(vin, vout);
1102      return CUBIT_FAILURE;
1103   }
1104   
1105   // divide each element of the vector by the magnitude
1106     
1107   vout[0] = vin[0] / rmag;
1108   vout[1] = vin[1] / rmag;
1109   vout[2] = vin[2] / rmag;
1110     
1111   return CUBIT_SUCCESS;
1112}
1113
1114double AnalyticGeometryTool::dot_vec( double uval[3], double vval[3] )
1115{
1116   double dot_val;
1117   
1118   // perform dot calculation = v[0]*u[0] + v[1]*u[1] + v[1]*u[1]
1119           
1120   dot_val = uval[0]*vval[0] + uval[1]*vval[1] + uval[2]*vval[2];
1121     
1122   return(dot_val);   
1123}
1124
1125void AnalyticGeometryTool::cross_vec( double uval[3], double vval[3],
1126                                     double cross[3] )
1127{     
1128   // determine cross product of the two vectors
1129   
1130   cross[0] = uval[1] * vval[2] - uval[2] * vval[1];
1131   cross[1] = uval[2] * vval[0] - uval[0] * vval[2];
1132   cross[2] = uval[0] * vval[1] - uval[1] * vval[0];   
1133}
1134
1135void AnalyticGeometryTool::cross_vec_unit( double uval[3], double vval[3],
1136                                          double cross[3] )
1137{     
1138   // determine cross product of the two vectors
1139   cross_vec(uval,vval,cross);
1140   
1141   // convert to unit vector
1142   unit_vec(cross,cross);
1143}
1144
1145void AnalyticGeometryTool::orth_vecs( double uvect[3], double vvect[3], 
1146                                     double wvect[3] )
1147{
1148   double x[3];
1149   unsigned short i = 0;
1150   unsigned short imin = 3;
1151   double rmin = 1.0E20;
1152   unsigned short iperm1[3];
1153   unsigned short iperm2[3];
1154   unsigned short cont_flag = 1;
1155   double vec[3];
1156   
1157   // Initialize perm flags
1158   iperm1[0] = 1; iperm1[1] = 2; iperm1[2] = 0;
1159   iperm2[0] = 2; iperm2[1] = 0; iperm2[2] = 1;
1160   
1161   // unitize vector
1162   
1163   unit_vec(uvect,vec);
1164   
1165   while (i<3 && cont_flag ) {
1166      if (dbl_eq(vec[i], 0.0)) {
1167         vvect[i] = 1.0;
1168         vvect[iperm1[i]] = 0.0;
1169         vvect[iperm2[i]] = 0.0;
1170         cont_flag = 0;
1171      }
1172     
1173      if (fabs(vec[i]) < rmin) {
1174         imin = i;
1175         rmin = fabs(vec[i]);
1176      }
1177      ++i;
1178   }
1179   
1180   if (cont_flag) {
1181      x[imin] = 1.0;
1182      x[iperm1[imin]] = 0.0;
1183      x[iperm2[imin]] = 0.0;
1184     
1185      // determine cross product
1186      cross_vec_unit(vec,x,vvect);
1187   }
1188   
1189   // cross vector to determine last orthogonal vector
1190   cross_vec(vvect,vec,wvect);
1191}
1192
1193double AnalyticGeometryTool::mag_vec( double vec[3] )
1194{
1195   return (sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]));
1196}
1197
1198CubitStatus AnalyticGeometryTool::get_vec ( double str_pnt[3], 
1199                                           double stp_pnt[3],
1200                                           double vector_out[3] )
1201{ 
1202   // Make sure we can create a vector
1203   if (pnt_eq(str_pnt, stp_pnt)) {
1204      vector_out[0] = 0.0;
1205      vector_out[1] = 0.0;
1206      vector_out[2] = 0.0;
1207      return CUBIT_FAILURE;
1208   }
1209   
1210   // determine vector by subtracting starting point from stopping point
1211   
1212  vector_out[0] = stp_pnt[0] - str_pnt[0];
1213  vector_out[1] = stp_pnt[1] - str_pnt[1];
1214  vector_out[2] = stp_pnt[2] - str_pnt[2]; 
1215 
1216  return CUBIT_SUCCESS;
1217}
1218
1219CubitStatus AnalyticGeometryTool::get_vec_unit( double str_pnt[3], 
1220                                               double stp_pnt[3],
1221                                               double uv_out[3] )
1222{
1223  // determine vector between points
1224   if (!get_vec(str_pnt,stp_pnt,uv_out))
1225      return CUBIT_FAILURE;
1226 
1227  // unitize vector
1228  if (!unit_vec(uv_out,uv_out))
1229     return CUBIT_FAILURE;
1230     
1231  return CUBIT_SUCCESS; 
1232}
1233
1234void AnalyticGeometryTool::mult_vecxconst( double constant,
1235                                          double vec[3],
1236                                          double vec_out[3] )
1237{
1238   // multiply each element of the vector by the constant
1239   vec_out[0] = constant * vec[0];
1240   vec_out[1] = constant * vec[1];
1241   vec_out[2] = constant * vec[2];   
1242}
1243
1244
1245void AnalyticGeometryTool::reverse_vec( double vin[3],double vout[3] )
1246{
1247   // Multiply the vector components by a -1.0   
1248   mult_vecxconst(-1.0, vin, vout);     
1249}
1250
1251double AnalyticGeometryTool::angle_vec_vec( double v1[3],double v2[3] )
1252{   
1253  double denom, dot, cosang, sinang, acrsb, angle;
1254  double crossed_vec[3];
1255     
1256  // For accuracy, use cosine for large angles, sine for small angles
1257  denom = sqrt((v1[0]*v1[0] + v1[1]*v1[1] + v1[2]*v1[2])
1258              *(v2[0]*v2[0] + v2[1]*v2[1] + v2[2]*v2[2]));
1259 
1260  // Check for a zero length vector
1261  if (dbl_eq(denom, 0.0))
1262     return (0.0);
1263 
1264  dot = dot_vec(v1, v2);
1265 
1266  cosang = dot/denom;
1267 
1268  if (1.0 - fabs(cosang) < 0.01) {
1269     cross_vec(v1, v2, crossed_vec);
1270     acrsb = mag_vec(crossed_vec);
1271     sinang = acrsb/denom;
1272     if (cosang > 0.0) 
1273        angle = asin(sinang);
1274     else 
1275        angle = AGT_PI - asin(sinang);
1276  }
1277  else 
1278     angle = acos(cosang);
1279 
1280  return (angle); 
1281}
1282
1283//***************************************************************************
1284// Distances
1285//***************************************************************************
1286double AnalyticGeometryTool::dist_pnt_pnt( double pnt1[3], double pnt2[3] )
1287{ 
1288  double x = pnt2[0] - pnt1[0];  // difference in the x direction
1289  double y = pnt2[1] - pnt1[1];  // difference in the y direction
1290  double z = pnt2[2] - pnt1[2];  // difference in the z direction
1291 
1292  // return the distance   
1293  return(sqrt(x*x + y*y + z*z));
1294}
1295
1296
1297
1298double AnalyticGeometryTool::dist_pln_pln( double pln_1_orig[3],
1299                                          double pln_1_norm[3], 
1300                                          double pln_2_orig[3],
1301                                          double pln_2_norm[3],
1302                                          AgtSide *side,
1303                                          AgtOrientation *orien,
1304                                          unsigned short *status )   
1305{
1306   double distance;
1307   double int_pnt[3];
1308   double vec[3];
1309   
1310   // Check to see if planes are parallel
1311   if (is_vec_par(pln_1_norm, pln_2_norm)) {   
1312     
1313      // Set successful status
1314      if (status)
1315         *status = 1;
1316     
1317      // Calculate perpendicular line plane intersection on plane_2 from
1318      // pln_1_origin
1319      int_ln_pln(pln_1_orig, pln_1_norm, pln_2_orig, pln_2_norm, 
1320                 int_pnt);
1321     
1322      // Find distance between pln_1_origin and this intersection pnt
1323      distance = dist_pnt_pnt(pln_1_orig, int_pnt);
1324     
1325      // Get side if required
1326      if (side) {
1327         
1328         if (dbl_eq(distance, 0.0))
1329           
1330            *side = AGT_ON_PLANE;
1331         
1332         else {
1333           
1334            // Get vector to intersection point
1335            get_vec(pln_1_orig, int_pnt, vec);
1336           
1337            // Compare angles
1338            if (dbl_eq(angle_vec_vec(vec, pln_1_norm), 0.0))
1339               *side = AGT_POS_SIDE;
1340            else
1341               *side = AGT_NEG_SIDE;
1342           
1343         }
1344      }
1345     
1346      // Get orientation if required
1347      if (orien) {
1348         
1349         // Compare surface normals
1350         if (dbl_eq(angle_vec_vec(pln_1_norm, pln_2_norm), 0.0))
1351            *orien = AGT_SAME_DIR;
1352         else
1353            *orien = AGT_OPP_DIR;
1354      }     
1355     
1356   }
1357   
1358   else {
1359     
1360      if (status)
1361         *status = 0;
1362     
1363      if (side)
1364         *side = AGT_CROSS;
1365     
1366      distance = 0.0;
1367     
1368   }
1369   
1370   return (distance);
1371}
1372
1373
1374
1375//***************************************************************************
1376// Intersections
1377//***************************************************************************
1378CubitStatus AnalyticGeometryTool::int_ln_pln( double ln_orig[3],
1379                                             double ln_vec[3],
1380                                             double pln_orig[3],
1381                                             double pln_norm[3],
1382                                             double int_pnt[3] )
1383{   
1384   double denom;
1385   double t;
1386   
1387   // Set parametric eqns of line equal to parametric eqn of plane & solve
1388   // for t
1389   denom = pln_norm[0]*ln_vec[0] + pln_norm[1]*ln_vec[1] + 
1390           pln_norm[2]*ln_vec[2];
1391   
1392   if (dbl_eq(denom, 0.0))
1393      return CUBIT_FAILURE;
1394   
1395   t = (pln_norm[0]*(pln_orig[0]-ln_orig[0]) + 
1396      pln_norm[1]*(pln_orig[1]-ln_orig[1]) + 
1397      pln_norm[2]*(pln_orig[2]-ln_orig[2]))/denom;
1398   
1399   // Substitute t back into equations of line to get xyz
1400   int_pnt[0] = ln_orig[0] + ln_vec[0]*t;
1401   int_pnt[1] = ln_orig[1] + ln_vec[1]*t;
1402   int_pnt[2] = ln_orig[2] + ln_vec[2]*t;
1403     
1404   return CUBIT_SUCCESS;   
1405}
1406
1407int AnalyticGeometryTool::int_ln_ln( double p1[3], double v1[3],
1408                                    double p2[3], double v2[3], 
1409                                    double int_pnt1[3], double int_pnt2[3] )
1410{   
1411   double norm[3];
1412   double pln1_norm[3];
1413   double pln2_norm[3];
1414   
1415   // Cross the two vectors to get a normal vector
1416   cross_vec(v1, v2, norm);
1417   
1418   if (dbl_eq(mag_vec(norm), 0.0))
1419      return 0;
1420   
1421   // Cross v2 & normal to get normal to plane 2
1422   cross_vec(v2, norm, pln2_norm);
1423   
1424   // Find intersection of pln2_norm and vector 1 - this is int_pnt1
1425   int_ln_pln(p1, v1, p2, pln2_norm, int_pnt1);
1426   
1427   // Cross v1 & normal to get normal to plane 1
1428   cross_vec(v1, norm, pln1_norm);
1429   
1430   // Find intersection of pln2_norm and vector 1 - this is int_pnt2
1431   int_ln_pln(p2, v2, p1, pln1_norm, int_pnt2);
1432
1433   // Check to see if the intersection points are the same & return
1434   if (pnt_eq(int_pnt1, int_pnt2)) 
1435      return 1;
1436   else
1437      return 2;   
1438}
1439
1440
1441int AnalyticGeometryTool::int_pnt_pln( double pnt[3],
1442                                      double pln_orig[3], 
1443                                      double pln_norm[3], 
1444                                      double pln_int[3] )   
1445{
1446   // Calculate line plane intersection w/plane normal as line vector
1447   int_ln_pln(pnt, pln_norm, pln_orig, pln_norm, pln_int);
1448   
1449   // Check to see if point is on the plane
1450   if (pnt_eq(pln_int, pnt))
1451      return 1;
1452   else
1453      return 0; 
1454}
1455
1456
1457
1458//***************************************************************************
1459// Comparison/Containment Tests
1460//***************************************************************************
1461CubitBoolean AnalyticGeometryTool::is_vec_par( double vec_1[3],
1462                                              double vec_2[3] )
1463{   
1464   double cross[3];
1465   
1466   // Get cross product & see if its magnitude is zero
1467   cross_vec(vec_1, vec_2, cross);
1468   
1469   if (dbl_eq(mag_vec(cross), 0.0))
1470      return CUBIT_TRUE;
1471   else
1472      return CUBIT_FALSE;
1473}
1474
1475CubitBoolean AnalyticGeometryTool::is_vec_perp( double vec_1[3],double vec_2[3])
1476{ 
1477   // Check angle between vectors
1478   if (dbl_eq(angle_vec_vec(vec_1, vec_2), AGT_PI_DIV_2))
1479      return CUBIT_TRUE;
1480   else
1481      return CUBIT_FALSE;   
1482}
1483
1484CubitBoolean AnalyticGeometryTool::is_vecs_same_dir( double vec_1[3], 
1485                                                     double vec_2[3] )
1486{         
1487   // Check to see if angle between vectors can be considered zero   
1488   if (dbl_eq(angle_vec_vec(vec_1, vec_2), 0.0))
1489      return CUBIT_TRUE;
1490   else
1491      return CUBIT_FALSE;   
1492}
1493
1494
1495CubitBoolean AnalyticGeometryTool::is_pnt_on_ln( double pnt[3],
1496                                                double ln_orig[3],
1497                                                double ln_vec[3] )
1498{ 
1499   double vec[3];
1500   
1501   // Compare pnt and line origin
1502   if (pnt_eq(pnt, ln_orig))
1503      return CUBIT_TRUE;   
1504   
1505   // Get a vector from line origin to the point     
1506   get_vec(ln_orig, pnt, vec);
1507   
1508   // If this vector is parallel with line vector, point is on the line
1509   if (is_vec_par(vec, ln_vec))
1510      return CUBIT_TRUE;
1511   else
1512      return CUBIT_FALSE;
1513}
1514
1515CubitBoolean AnalyticGeometryTool::is_pnt_on_ln_seg( double pnt[3],
1516                                                    double end1[3],
1517                                                    double end2[3] )
1518{ 
1519//   METHOD:
1520//    o Use parametric equations of line
1521//   
1522//         x = x1 + t(x2 - x1)
1523//         y = y1 + t(y2 - y1)
1524//         z = z1 + t(z2 - z1)
1525//       
1526//    o Note:  two other method's were considered:
1527//       1) Comparing sum of distance of point to both end points to the
1528//          line length.
1529//       2) Checking to see if area of a triangle with the vertices is zero
1530//       
1531//     Using parametric equations is more efficient in many cases.
1532  double t1 = 0.0,
1533    t2 = 0.0,
1534    t3 = 0.0,
1535    neg_range,
1536    pos_range;
1537 
1538  unsigned short flg1 = 0,
1539    flg2 = 0,
1540    flg3 = 0;
1541 
1542  neg_range = 0.0 - agtEpsilon;
1543  pos_range = 1.0 + agtEpsilon;
1544 
1545  if (fabs(end2[0] - end1[0]) < agtEpsilon)
1546  {
1547    if (fabs(pnt[0] - end1[0]) < agtEpsilon)
1548      flg1 = 1;
1549    else
1550      return CUBIT_FALSE;
1551  }
1552  else
1553  {
1554    t1 = (pnt[0] - end1[0])/(end2[0] - end1[0]);
1555   
1556    if (t1<neg_range || t1>pos_range)
1557      return CUBIT_FALSE;
1558  }
1559 
1560  if (fabs(end2[1] - end1[1]) < agtEpsilon)
1561  {
1562    if (fabs(pnt[1] - end1[1]) < agtEpsilon)
1563      flg2 = 1;
1564    else
1565      return CUBIT_FALSE;
1566  }
1567  else
1568  {
1569    t2 = (pnt[1] - end1[1])/(end2[1] - end1[1]);
1570   
1571    if (t2<neg_range || t2>pos_range)
1572      return CUBIT_FALSE;
1573  }
1574   
1575  if (fabs(end2[2] - end1[2]) < agtEpsilon)
1576  {
1577    if (fabs(pnt[2] - end1[2]) < agtEpsilon)
1578      flg3 = 1;
1579    else
1580      return CUBIT_FALSE;
1581  }
1582  else
1583  {
1584    t3 = (pnt[2] - end1[2])/(end2[2] - end1[2]);
1585   
1586    if (t3<neg_range || t3>pos_range)
1587      return CUBIT_FALSE;
1588  }
1589 
1590    // If any 2 flags are 1, point is on the line,
1591    // otherwise, check remaining T's for equality
1592 
1593  if (flg1)
1594  {
1595      // Here, flg1 = 1
1596   
1597    if (flg2)
1598    {
1599        // Here, flg1 = 1
1600        // Here, flg2 = 1
1601      return CUBIT_TRUE;
1602    }
1603    else
1604    {
1605        // Here, flg1 = 1
1606        // Here, flg2 = 0
1607     
1608      if (flg3)
1609          // Here, flg1 = 1
1610          // Here, flg2 = 0
1611          // Here, flg3 = 1
1612        return CUBIT_TRUE;
1613      else
1614      {
1615          // Here, flg1 = 1
1616          // Here, flg2 = 0
1617          // Here, flg3 = 0
1618        if (dbl_eq(t2, t3))
1619          return CUBIT_TRUE;
1620        else
1621          return CUBIT_FALSE;
1622      }
1623    }
1624  }
1625  else
1626  {
1627      // Here, flg1 = 0
1628    if (flg2)
1629    {
1630        // Here, flg1 = 0
1631        // Here, flg2 = 1
1632      if (flg3)
1633        return CUBIT_TRUE;
1634          // Here, flg1 = 0
1635          // Here, flg2 = 1
1636          // Here, flg3 = 1
1637      else
1638      {
1639          // Here, flg1 = 0
1640          // Here, flg2 = 1
1641          // Here, flg3 = 0
1642        if (dbl_eq(t1, t3))
1643          return CUBIT_TRUE;
1644        else
1645          return CUBIT_FALSE;
1646      }
1647    }
1648    else
1649    {
1650        // Here, flg1 = 0
1651        // Here, flg2 = 0
1652      if (flg3)
1653      {
1654          // Here, flg1 = 0
1655          // Here, flg2 = 0
1656          // Here, flg3 = 1
1657        if (dbl_eq(t1, t2))
1658          return CUBIT_TRUE;
1659        else
1660          return CUBIT_FALSE;
1661      }
1662      else
1663      {
1664          // Here, flg1 = 0
1665          // Here, flg2 = 0
1666          // Here, flg3 = 0
1667        if (dbl_eq(t1, t2) && dbl_eq(t1, t3))
1668          return CUBIT_TRUE;
1669        else
1670          return CUBIT_FALSE;
1671      }
1672    }
1673  }
1674 
1675    // This would be a programmer's error if we got to this point
1676//  return CUBIT_FALSE;
1677}
1678
1679CubitBoolean AnalyticGeometryTool::is_pnt_on_pln( double pnt[3],
1680                                                 double pln_orig[3],
1681                                                 double pln_norm[3] )
1682{ 
1683   double result;
1684   
1685   // See if point satisfies parametric equation of plane
1686   
1687   result = pln_norm[0] * (pnt[0] - pln_orig[0]) +
1688            pln_norm[1] * (pnt[1] - pln_orig[1]) +
1689            pln_norm[2] * (pnt[2] - pln_orig[2]);
1690   
1691   if (dbl_eq(result, 0.0))
1692      return CUBIT_TRUE;
1693   else
1694      return CUBIT_FALSE;
1695}
1696
1697CubitBoolean AnalyticGeometryTool::is_ln_on_pln( double ln_orig[3],
1698                                                double ln_vec[3],
1699                                                double pln_orig[3],
1700                                                double pln_norm[3] )
1701{     
1702   
1703   // Check to see if line origin is on the plane.  If so, check to see if
1704   // line vector is perpendicular to plane normal.
1705   
1706   if (is_pnt_on_pln(ln_orig, pln_orig, pln_norm) &&
1707       is_vec_perp(ln_vec, pln_norm))     
1708      return CUBIT_TRUE;     
1709   else     
1710      return CUBIT_FALSE;
1711}
1712
1713
1714
1715CubitBoolean AnalyticGeometryTool::is_pln_on_pln( double pln_orig1[3],
1716                                                 double pln_norm1[3],
1717                                                 double pln_orig2[3],
1718                                                 double pln_norm2[3] )
1719{ 
1720   // If 1st plane origin is on the 2nd plane and the normals are
1721   // parallel they are coincident
1722   if( is_vec_par( pln_norm1, pln_norm2 ) &&
1723      is_pnt_on_pln( pln_orig1, pln_orig2, pln_norm2 ) )
1724      return CUBIT_TRUE;
1725   else
1726      return CUBIT_FALSE;
1727}
1728
1729//***************************************************************************
1730// Arcs/Circles
1731//***************************************************************************
1732void AnalyticGeometryTool::setup_arc( double vec_1[3], double vec_2[3], 
1733                                     double origin[3], double start_angle, 
1734                                     double end_angle, double radius,
1735                                     AGT_3D_Arc &arc )
1736{
1737   copy_pnt( vec_1, arc.Vec1 );
1738   copy_pnt( vec_2, arc.Vec2 );
1739   copy_pnt( origin, arc.Origin );
1740   arc.StartAngle = start_angle;
1741   arc.EndAngle = end_angle;
1742   arc.Radius = radius;
1743}
1744
1745void AnalyticGeometryTool::setup_arc( CubitVector& vec_1, CubitVector& vec_2, 
1746                                     CubitVector origin, double start_angle, 
1747                                     double end_angle, double radius,
1748                                     AGT_3D_Arc &arc )
1749{
1750   vec_1.get_xyz( arc.Vec1 );
1751   vec_2.get_xyz( arc.Vec2 );
1752   origin.get_xyz( arc.Origin );
1753   arc.StartAngle = start_angle;
1754   arc.EndAngle = end_angle;
1755   arc.Radius = radius;
1756}
1757
1758void AnalyticGeometryTool::get_arc_xyz( AGT_3D_Arc &arc, double param, double pnt[3] )
1759{
1760   double Tp;
1761   
1762   // Un-normalized parameter
1763   Tp = arc.StartAngle * ( 1.0 - param ) + arc.EndAngle * param;
1764   
1765   // Solve for XYZ
1766   pnt[0] = arc.Radius * ( cos( Tp ) * arc.Vec1[0] +
1767                           sin( Tp ) * arc.Vec2[0] ) + 
1768                           arc.Origin[0];
1769   
1770   pnt[1] = arc.Radius * ( cos( Tp ) * arc.Vec1[1] +
1771                           sin( Tp ) * arc.Vec2[1] ) + 
1772                           arc.Origin[1];
1773   
1774   pnt[2] = arc.Radius * ( cos( Tp ) * arc.Vec1[2] +
1775                           sin( Tp ) * arc.Vec2[2] ) + 
1776                           arc.Origin[2];
1777}
1778
1779void AnalyticGeometryTool::get_arc_xyz( AGT_3D_Arc &arc, double param, CubitVector& pnt )
1780{
1781   double Tp;
1782   
1783   // Un-normalized parameter
1784   Tp = arc.StartAngle * ( 1.0 - param ) + arc.EndAngle * param;
1785   
1786   // Solve for XYZ
1787   pnt.x( arc.Radius * ( cos( Tp ) * arc.Vec1[0] +
1788                         sin( Tp ) * arc.Vec2[0] ) + 
1789                         arc.Origin[0] );
1790   
1791   pnt.y( arc.Radius * ( cos( Tp ) * arc.Vec1[1] +
1792                         sin( Tp ) * arc.Vec2[1] ) + 
1793                         arc.Origin[1] );
1794   
1795   pnt.z( arc.Radius * ( cos( Tp ) * arc.Vec1[2] +
1796                         sin( Tp ) * arc.Vec2[2] ) + 
1797                         arc.Origin[2] );
1798}
1799
1800int 
1801AnalyticGeometryTool::get_num_circle_tess_pnts( double radius, 
1802                                                double len_tol )
1803{
1804  double cmin, cmax;
1805
1806  double c = 2*CUBIT_PI*radius; // Circumference
1807
1808  // Find the number of points required for the given accuracy.  Use
1809  // a bisection method.
1810  int nmin = 8, nmax = 100;
1811  cmin = 2.0*nmin*radius*sin(CUBIT_PI/nmin); // Circumference of circle using segments
1812  cmax = 2.0*nmax*radius*sin(CUBIT_PI/nmax);
1813
1814  if( dbl_eq( cmin, c ) )
1815    return nmin;
1816
1817  double old_epsilon = set_epsilon( len_tol );
1818
1819  // Find an n that is more than accurate enough
1820  while( !dbl_eq( cmax, c ) )
1821  {
1822    nmin = nmax;
1823    nmax = nmin * 10;
1824    cmin = 2.0*nmin*radius*sin(CUBIT_PI/nmin);
1825    cmax = 2.0*nmax*radius*sin(CUBIT_PI/nmax);
1826  }
1827 
1828  // Biscect until the minimum number of segments satisfying
1829  // the tolerance is found.
1830  int n;
1831  while( 1 )
1832  {
1833    n = (nmin + nmax)/2;
1834    double cn = 2.0*n*radius*sin(CUBIT_PI/n);
1835    if( dbl_eq( cn, c ) )
1836    {
1837      // Go lower
1838      nmax = n;
1839    }
1840    else
1841    {
1842      // Go higher
1843      nmin = n;
1844    }
1845    if( nmax-nmin < 2 )
1846      break;
1847  }
1848  set_epsilon( old_epsilon );
1849
1850  return nmax;
1851}
1852
1853//***************************************************************************
1854// Miscellaneous
1855//***************************************************************************
1856void AnalyticGeometryTool::get_pln_orig_norm( double A, double B, double C,
1857                                             double D, double pln_orig[3], 
1858                                             double pln_norm[3] )
1859{
1860   double x = 0.0, y = 0.0, z = 0.0;
1861
1862   // Try to have origin aligned with one of the principal axes
1863   if( !dbl_eq( C, 0.0 ) )
1864      z = -D/C;
1865   else if (!dbl_eq( A, 0.0 ) )
1866      x = -D/A;
1867   else if (!dbl_eq( B, 0.0 ) )
1868      y = -D/B;
1869
1870   pln_orig[0] = x;
1871   pln_orig[1] = y;
1872   pln_orig[2] = z;
1873
1874   if( pln_norm )
1875   {
1876      pln_norm[0] = A;
1877      pln_norm[1] = B;
1878      pln_norm[2] = C;
1879   }
1880}
1881
1882void AnalyticGeometryTool::get_box_corners( double box_min[3], 
1883                                           double box_max[3], 
1884                                           double c[8][3] )
1885{
1886   // Left-Bottom-Front       // Left-Top-Front
1887   c[0][0] = box_min[0];      c[1][0] = box_min[0];
1888   c[0][1] = box_min[1];      c[1][1] = box_max[1];
1889   c[0][2] = box_max[2];      c[1][2] = box_max[2];
1890
1891   // Right-Top-Front         // Right-Bottom-Front
1892   c[2][0] = box_max[0];      c[3][0] = box_max[0];
1893   c[2][1] = box_max[1];      c[3][1] = box_min[1];
1894   c[2][2] = box_max[2];      c[3][2] = box_max[2];
1895
1896   // Left-Bottom-Back        // Left-Top-Back
1897   c[4][0] = box_min[0];      c[5][0] = box_min[0];
1898   c[4][1] = box_min[1];      c[5][1] = box_max[1];
1899   c[4][2] = box_min[2];      c[5][2] = box_min[2];
1900
1901   // Right-Top-Back          // Right-Bottom-Back
1902   c[6][0] = box_max[0];      c[7][0] = box_max[0];
1903   c[6][1] = box_max[1];      c[7][1] = box_min[1];
1904   c[6][2] = box_min[2];      c[7][2] = box_min[2];
1905   
1906}
1907
1908CubitStatus
1909AnalyticGeometryTool::min_pln_box_int_corners( const CubitPlane& plane,
1910                                              const CubitBox& box,
1911                                              int extension_type,
1912                                              double extension,
1913                                              CubitVector& p1, CubitVector& p2,
1914                                              CubitVector& p3, CubitVector& p4,
1915                                              CubitBoolean silent )
1916{
1917   CubitVector box_min = box.minimum();
1918   CubitVector box_max = box.maximum();
1919   
1920   CubitVector plane_norm = plane.normal();
1921   
1922   double box_min_pnt[3], box_max_pnt[3], pln_norm[3];
1923   box_min.get_xyz( box_min_pnt ); box_max.get_xyz( box_max_pnt );
1924   plane_norm.get_xyz( pln_norm );
1925   
1926   double pnt1[3], pnt2[3], pnt3[3], pnt4[3];
1927   
1928   if( min_pln_box_int_corners( pln_norm, plane.coefficient(),
1929      box_min_pnt, box_max_pnt, 
1930      extension_type, extension, 
1931      pnt1, pnt2, pnt3, pnt4, silent ) == CUBIT_FAILURE )
1932         return CUBIT_FAILURE;
1933   
1934   p1.set( pnt1 ); p2.set( pnt2 ); p3.set( pnt3 ); p4.set( pnt4 );
1935   
1936   return CUBIT_SUCCESS;
1937}
1938
1939CubitStatus
1940AnalyticGeometryTool::min_pln_box_int_corners( CubitVector& vec1,
1941                                              CubitVector& vec2,
1942                                              CubitVector& vec3,
1943                                              CubitVector& box_min,
1944                                              CubitVector& box_max,
1945                                              int extension_type,
1946                                              double extension,
1947                                              CubitVector& p1, CubitVector& p2, 
1948                                              CubitVector& p3, CubitVector& p4,
1949                                              CubitBoolean silent )
1950{
1951   CubitPlane plane;
1952   if( plane.mk_plane_with_points( vec1, vec2, vec3 ) == CUBIT_FAILURE )
1953      return CUBIT_FAILURE;
1954
1955   CubitVector plane_norm = plane.normal();
1956   double coefficient = plane.coefficient();
1957
1958   double plane_norm3[3];
1959   double box_min3[3];
1960   double box_max3[3];
1961
1962   box_min.get_xyz( box_min3 );
1963   box_max.get_xyz( box_max3 );
1964   plane_norm.get_xyz( plane_norm3 );
1965
1966   double p1_3[3], p2_3[3], p3_3[3], p4_3[3];
1967   p1.get_xyz( p1_3 );
1968   p2.get_xyz( p2_3 );
1969   p3.get_xyz( p3_3 );
1970   p4.get_xyz( p4_3 );
1971   
1972   if( min_pln_box_int_corners( plane_norm3, coefficient, box_min3, box_max3, 
1973      extension_type, extension, p1_3, p2_3, p3_3, p4_3, silent ) == CUBIT_FAILURE )
1974      return CUBIT_FAILURE;
1975
1976   p1.set( p1_3 );
1977   p2.set( p2_3 );
1978   p3.set( p3_3 );
1979   p4.set( p4_3 );
1980
1981   return CUBIT_SUCCESS;
1982}
1983
1984CubitStatus
1985AnalyticGeometryTool::min_pln_box_int_corners( double pln_norm[3], 
1986                                              double pln_coeff,
1987                                              double box_min[3],
1988                                              double box_max[3],
1989                                              int extension_type,
1990                                              double extension,
1991                                              double p1[3], double p2[3],
1992                                              double p3[3], double p4[3],
1993                                              CubitBoolean silent )
1994{
1995   int i;
1996   double cubit2pln_mtx[4][4],
1997      pln2cubit_mtx[4][4];
1998   double pln_orig[3];
1999
2000   double A = pln_norm[0];
2001   double B = pln_norm[1];
2002   double C = pln_norm[2];
2003   double D = pln_coeff;
2004
2005   //PRINT_INFO( "A=%0.4lf, B=%0.4lf, C=%0.4lf, D=%0.4lf\n", A, B, C, D );
2006
2007   get_pln_orig_norm( A, B, C, D, pln_orig );
2008
2009//   PRINT_INFO( "Plane Orig = %0.4lf, %0.4lf, %0.4lf\n", pln_orig[0],
2010//      pln_orig[1], pln_orig[2] );
2011
2012   // Find intersections of edges with plane.  Add to unique
2013   // array.  At most there are 6 intersections...
2014   double int_array[6][3];
2015   int num_int = 0;
2016   num_int = get_plane_bbox_intersections( box_min, box_max, pln_orig, pln_norm, int_array );
2017
2018   //attempt to adjust bounding box to x,y,z intercepts of plane
2019   if( num_int == 0 )
2020   {
2021     //Stretch bounding box so that plane will fit, for sure
2022     //get x,y,z intercepts
2023     double x_intercept = 0;
2024     double y_intercept = 0;
2025     double z_intercept = 0;
2026     if( !dbl_eq( A, 0.0 ) )
2027       x_intercept = -D/A;
2028     if( !dbl_eq( B, 0.0 ) )
2029       y_intercept = -D/B;
2030     if( !dbl_eq( C, 0.0 ) )
2031       z_intercept = -D/C;
2032   
2033    //adjust box
2034    if( x_intercept < box_min[0] )
2035      box_min[0] = x_intercept;
2036    else if( x_intercept > box_max[0] )
2037      box_max[0] = x_intercept;
2038
2039    if( y_intercept < box_min[1] )
2040      box_min[1] = y_intercept;
2041    else if( y_intercept > box_max[1] )
2042      box_max[1] = y_intercept;
2043     
2044    if( z_intercept < box_min[2] )
2045      box_min[2] = z_intercept;
2046    else if( z_intercept > box_max[2] )
2047      box_max[2] = z_intercept;
2048
2049     num_int = get_plane_bbox_intersections( box_min, box_max, pln_orig, pln_norm, int_array );
2050   }
2051
2052   if( num_int == 0 )
2053   {
2054     if( silent == CUBIT_FALSE )
2055       PRINT_ERROR( "Plane does not intersect the bounding box\n"
2056       "       Can't find 4 corners of plane\n" );
2057     return CUBIT_FAILURE;
2058   }
2059   if( num_int < 3 )
2060   {
2061     if( silent == CUBIT_FALSE )
2062       PRINT_ERROR( "Plane intersects the bounding box at only %d locations\n"
2063       "      Can't calculate 4 corners of plane\n", num_int );
2064      return CUBIT_FAILURE;
2065   }
2066
2067   // Transform pnts to plane coordinate system
2068   double pln_x[3], pln_y[3];
2069   orth_vecs( pln_norm, pln_x, pln_y );
2070   vecs_to_mtx( pln_x, pln_y, pln_norm, pln_orig, pln2cubit_mtx );
2071   inv_trans_mtx( pln2cubit_mtx, cubit2pln_mtx );
2072
2073   double int_arr_pln[6][3];
2074   for( i=0; i<num_int; i++ )
2075      transform_pnt( cubit2pln_mtx, int_array[i], int_arr_pln[i] );
2076
2077   // Place into format for mimimal box calculation
2078   Point2 pt[6];
2079   for ( i=0; i<num_int; i++ )
2080   {
2081      pt[i].x = int_arr_pln[i][0];
2082      pt[i].y = int_arr_pln[i][1];
2083      if( !dbl_eq( int_arr_pln[i][2], 0.0 ) )
2084      {
2085        if( silent == CUBIT_FALSE )
2086          PRINT_ERROR( "in AnalyticGeometryTool::min_box_pln_int_corners\n"
2087          "       Transform to plane wrong\n" );
2088         return CUBIT_FAILURE;
2089      }
2090   }
2091   
2092   // Find rectangle with minimal area to surround the points
2093   // (this is definitely overkill esp. for the simple cases.....)
2094   OBBox2 minimal = MinimalBox2( num_int, pt );
2095   
2096   // Strip out results
2097   double old_epsilon = set_epsilon( 1e-10 );
2098   double centroid[3];
2099   centroid[0] = minimal.center.x;
2100   centroid[1] = minimal.center.y;
2101   centroid[2] = 0.0;
2102   round_near_val( centroid[0] ); // Makes near -1, 0, 1 values -1, 0, 1
2103   round_near_val( centroid[1] );
2104   transform_pnt( pln2cubit_mtx, centroid, centroid );
2105   
2106   double x_axis[3];
2107   x_axis[0] = minimal.axis[0].x;
2108   x_axis[1] = minimal.axis[0].y;
2109   x_axis[2] = 0.0;
2110   round_near_val( x_axis[0] );
2111   round_near_val( x_axis[1] );
2112   transform_vec( pln2cubit_mtx, x_axis, x_axis );
2113   
2114   double y_axis[3];
2115   y_axis[0] = minimal.axis[1].x;
2116   y_axis[1] = minimal.axis[1].y;
2117   y_axis[2] = 0.0;
2118   round_near_val( y_axis[0] );
2119   round_near_val( y_axis[1] );
2120   transform_vec( pln2cubit_mtx, y_axis, y_axis );
2121
2122   set_epsilon( old_epsilon );
2123   
2124   double dist_x;
2125   double dist_y;
2126   double extension_distance = 0.0;
2127   if( extension_type == 1 ) // Percentage (of 1/2 diagonal)
2128   {
2129      double diag_len = sqrt(  minimal.extent[0]*minimal.extent[0]
2130                             + minimal.extent[1]*minimal.extent[1] );
2131      extension_distance = diag_len*extension/100.0;
2132   }
2133   else if( extension_type == 2 ) // Absolute distance in x and y
2134      extension_distance = extension;
2135
2136   dist_x = minimal.extent[0] + extension_distance;
2137   dist_y = minimal.extent[1] + extension_distance;
2138   
2139   next_pnt( centroid, x_axis, -dist_x, p1 );
2140   next_pnt( p1, y_axis, -dist_y, p1 );
2141   
2142   next_pnt( centroid, x_axis, -dist_x, p2 );
2143   next_pnt( p2, y_axis, dist_y, p2 );
2144   
2145   next_pnt( centroid, x_axis, dist_x, p3 );
2146   next_pnt( p3, y_axis, dist_y, p3 );
2147   
2148   next_pnt( centroid, x_axis, dist_x, p4 );
2149   next_pnt( p4, y_axis, -dist_y, p4 );
2150   
2151   return CUBIT_SUCCESS;
2152}
2153
2154int AnalyticGeometryTool::get_plane_bbox_intersections( double box_min[3],
2155                                                           double box_max[3],
2156                                                           double pln_orig[3],
2157                                                           double pln_norm[3],
2158                                                           double int_array[6][3])
2159{
2160
2161   // Fill in an array with all 8 box corners
2162   double corner[8][3];
2163   get_box_corners( box_min, box_max, corner );
2164 
2165   // Get 12 edges of the box
2166   double ln_start[12][3], ln_end[12][3];
2167   copy_pnt( corner[0], ln_start[0] );  copy_pnt( corner[1], ln_end[0] );
2168   copy_pnt( corner[1], ln_start[1] );  copy_pnt( corner[2], ln_end[1] );
2169   copy_pnt( corner[2], ln_start[2] );  copy_pnt( corner[3], ln_end[2] );
2170   copy_pnt( corner[3], ln_start[3] );  copy_pnt( corner[0], ln_end[3] ); 
2171   copy_pnt( corner[4], ln_start[4] );  copy_pnt( corner[5], ln_end[4] );
2172   copy_pnt( corner[5], ln_start[5] );  copy_pnt( corner[6], ln_end[5] );
2173   copy_pnt( corner[6], ln_start[6] );  copy_pnt( corner[7], ln_end[6] );
2174   copy_pnt( corner[7], ln_start[7] );  copy_pnt( corner[4], ln_end[7] );
2175   copy_pnt( corner[0], ln_start[8] );  copy_pnt( corner[4], ln_end[8] );
2176   copy_pnt( corner[1], ln_start[9] );  copy_pnt( corner[5], ln_end[9] );
2177   copy_pnt( corner[2], ln_start[10] ); copy_pnt( corner[6], ln_end[10] );
2178   copy_pnt( corner[3], ln_start[11] ); copy_pnt( corner[7], ln_end[11] );
2179   
2180   double ln_vec[3];
2181   double int_pnt[3];
2182   int num_int = 0;
2183   int i, j, found;
2184   for( i=0; i<12; i++ )
2185   {
2186      get_vec_unit( ln_start[i], ln_end[i], ln_vec );
2187      if( int_ln_pln( ln_start[i], ln_vec, pln_orig, pln_norm, int_pnt ) )
2188      {
2189         // Only add if on the bounded line segment
2190         if( is_pnt_on_ln_seg( int_pnt, ln_start[i], ln_end[i] ) )
2191         {
2192            // Only add if unique
2193            found = 0;
2194            for( j=0; j<num_int; j++ )
2195            {
2196               if( pnt_eq( int_pnt, int_array[j] ) )
2197               {
2198                  found = 1;
2199                  break;
2200               }
2201            }
2202            if( !found )
2203            {
2204               copy_pnt( int_pnt, int_array[num_int] );
2205               num_int++;
2206            }
2207         }
2208      }
2209   }
2210  return num_int;
2211}
2212
2213CubitStatus
2214AnalyticGeometryTool::get_tight_bounding_box( DLIList<CubitVector*> &point_list,                                             
2215                                              CubitVector &center,
2216                                              CubitVector axes[3],
2217                                              CubitVector &extension )
2218{
2219   int num_pnts = point_list.size();
2220   if( num_pnts == 0 )
2221      return CUBIT_FAILURE;
2222   Point3 *pnt_arr = new Point3[num_pnts];
2223
2224   int i;
2225   point_list.reset();
2226   CubitVector *vec;
2227   for( i=0; i<num_pnts; i++ )
2228   {
2229      vec = point_list.get_and_step();
2230
2231      pnt_arr[i].x = vec->x();
2232      pnt_arr[i].y = vec->y();
2233      pnt_arr[i].z = vec->z();
2234   }
2235
2236   OBBox3 minimal = MinimalBox3 (point_list.size(), pnt_arr);
2237
2238   //PRINT_INFO( "MinBox center = %lf, %lf, %lf\n", minimal.center.x, minimal.center.y, minimal.center.z );
2239   //PRINT_INFO( "MinBox axis 1 = %lf, %lf, %lf\n", minimal.axis[0].x, minimal.axis[0].y, minimal.axis[0].z );
2240   //PRINT_INFO( "MinBox axis 2 = %lf, %lf, %lf\n", minimal.axis[1].x, minimal.axis[1].y, minimal.axis[1].z );
2241   //PRINT_INFO( "MinBox axis 3 = %lf, %lf, %lf\n", minimal.axis[2].x, minimal.axis[2].y, minimal.axis[2].z );
2242   //PRINT_INFO( "MinBox extent = %lf, %lf, %lf\n", minimal.extent[0], minimal.extent[1], minimal.extent[2] );
2243
2244   center.set(minimal.center.x, minimal.center.y, minimal.center.z);
2245   axes[0].set(minimal.axis[0].x, minimal.axis[0].y, minimal.axis[0].z);
2246   axes[1].set(minimal.axis[1].x, minimal.axis[1].y, minimal.axis[1].z);
2247   axes[2].set(minimal.axis[2].x, minimal.axis[2].y, minimal.axis[2].z);
2248   extension.set(minimal.extent[0], minimal.extent[1], minimal.extent[2]);
2249
2250   delete [] pnt_arr;
2251
2252   return CUBIT_SUCCESS;
2253}
2254
2255CubitStatus
2256AnalyticGeometryTool::get_tight_bounding_box( DLIList<CubitVector*> &point_list,                                             
2257                                              CubitVector& p1, CubitVector& p2,
2258                                              CubitVector& p3, CubitVector& p4,
2259                                              CubitVector& p5, CubitVector& p6,
2260                                              CubitVector& p7, CubitVector& p8)
2261{
2262   int num_pnts = point_list.size();
2263   if( num_pnts == 0 )
2264      return CUBIT_FAILURE;
2265   Point3 *pnt_arr = new Point3[num_pnts];
2266
2267   int i;
2268   point_list.reset();
2269   CubitVector *vec;
2270   for( i=0; i<num_pnts; i++ )
2271   {
2272      vec = point_list.get_and_step();
2273
2274      pnt_arr[i].x = vec->x();
2275      pnt_arr[i].y = vec->y();
2276      pnt_arr[i].z = vec->z();
2277   }
2278
2279   OBBox3 minimal = MinimalBox3 (point_list.size(), pnt_arr);
2280
2281   //PRINT_INFO( "MinBox center = %lf, %lf, %lf\n", minimal.center.x, minimal.center.y, minimal.center.z );
2282   //PRINT_INFO( "MinBox axis 1 = %lf, %lf, %lf\n", minimal.axis[0].x, minimal.axis[0].y, minimal.axis[0].z );
2283   //PRINT_INFO( "MinBox axis 2 = %lf, %lf, %lf\n", minimal.axis[1].x, minimal.axis[1].y, minimal.axis[1].z );
2284   //PRINT_INFO( "MinBox axis 3 = %lf, %lf, %lf\n", minimal.axis[2].x, minimal.axis[2].y, minimal.axis[2].z );
2285   //PRINT_INFO( "MinBox extent = %lf, %lf, %lf\n", minimal.extent[0], minimal.extent[1], minimal.extent[2] );
2286
2287   CubitVector center(minimal.center.x, minimal.center.y, minimal.center.z);
2288   CubitVector x(minimal.axis[0].x, minimal.axis[0].y, minimal.axis[0].z);
2289   CubitVector y(minimal.axis[1].x, minimal.axis[1].y, minimal.axis[1].z);
2290   CubitVector z(minimal.axis[2].x, minimal.axis[2].y, minimal.axis[2].z);
2291   CubitVector extent(minimal.extent[0], minimal.extent[1], minimal.extent[2]);
2292
2293   center.next_point( -x, extent.x(), p1 ); p1.next_point( -y, extent.y(), p1 );
2294   p1.next_point( z, extent.z(), p1 );
2295
2296   center.next_point( -x, extent.x(), p2 ); p2.next_point( y, extent.y(), p2 );
2297   p2.next_point( z, extent.z(), p2 );
2298
2299   center.next_point( x, extent.x(), p3 ); p3.next_point( y, extent.y(), p3 );
2300   p3.next_point( z, extent.z(), p3 );
2301
2302   center.next_point( x, extent.x(), p4 ); p4.next_point( -y, extent.y(), p4 );
2303   p4.next_point( z, extent.z(), p4 );
2304
2305   center.next_point( -x, extent.x(), p5 ); p5.next_point( -y, extent.y(), p5 );
2306   p5.next_point( -z, extent.z(), p5 );
2307
2308   center.next_point( -x, extent.x(), p6 ); p6.next_point( y, extent.y(), p6 );
2309   p6.next_point( -z, extent.z(), p6 );
2310
2311   center.next_point( x, extent.x(), p7 ); p7.next_point( y, extent.y(), p7 );
2312   p7.next_point( -z, extent.z(), p7 );
2313
2314   center.next_point( x, extent.x(), p8 ); p8.next_point( -y, extent.y(), p8 );
2315   p8.next_point( -z, extent.z(), p8 );
2316
2317   delete pnt_arr;
2318
2319   return CUBIT_SUCCESS;
2320}
2321
2322CubitStatus
2323AnalyticGeometryTool::min_cyl_box_int( double radius,
2324                                       CubitVector& axis,
2325                                       CubitVector& center,
2326                                       CubitBox& box,
2327                                       int extension_type,
2328                                       double extension,
2329                                       CubitVector &start,
2330                                       CubitVector &end,
2331                                       int num_tess_pnts )
2332                                       
2333{
2334   CubitVector box_min = box.minimum();
2335   CubitVector box_max = box.maximum();
2336   
2337   double box_min_pnt[3], box_max_pnt[3], axis_vec[3], center_pnt[3];
2338   box_min.get_xyz( box_min_pnt ); box_max.get_xyz( box_max_pnt );
2339   axis.get_xyz( axis_vec ); center.get_xyz( center_pnt );
2340   
2341   double start_pnt[3], end_pnt[3];
2342   
2343   if( min_cyl_box_int( radius, axis_vec, center_pnt, 
2344                        box_min_pnt, box_max_pnt, 
2345                        extension_type, extension, 
2346                        start_pnt, end_pnt, num_tess_pnts )
2347                        == CUBIT_FAILURE )
2348     return CUBIT_FAILURE;
2349   
2350   start.set( start_pnt ); end.set( end_pnt );
2351   
2352   return CUBIT_SUCCESS;
2353}
2354
2355CubitStatus
2356AnalyticGeometryTool::min_cyl_box_int( double radius, double axis[3], 
2357                                      double center[3], 
2358                                      double box_min[3], double box_max[3], 
2359                                      int extension_type, double extension, 
2360                                      double start[3], double end[3], 
2361                                      int num_tess_pnts )
2362{
2363  double cyl_z[3];
2364  unit_vec( axis, cyl_z );
2365
2366  //PRINT_INFO( "Axis = %f, %f, %f\n", cyl_z[0], cyl_z[1], cyl_z[2] );
2367  //PRINT_INFO( "Center = %f, %f, %f\n", center[0], center[1], center[2] );
2368
2369  // Find transformation matrix to take a point into cylinder's
2370  // coordinate system
2371  double cubit2cyl_mtx[4][4], cyl2cubit_mtx[4][4];
2372  double cyl_x[3], cyl_y[3];
2373  orth_vecs( cyl_z, cyl_x, cyl_y );
2374  vecs_to_mtx( cyl_x, cyl_y, cyl_z, center, cyl2cubit_mtx );
2375  inv_trans_mtx( cyl2cubit_mtx, cubit2cyl_mtx );
2376
2377  // Setup the circle
2378  double vec_1[3], vec_2[3];
2379  orth_vecs( cyl_z, vec_1, vec_2 );
2380  AGT_3D_Arc arc;
2381  setup_arc( vec_1, vec_2, center, 0.0, 2.0 * CUBIT_PI, radius, arc );
2382
2383  // Setup the planes of the box
2384  double pln_norm[6][3], pln_orig[6][3];
2385  // Front
2386  pln_orig[0][0] = 0.0; pln_orig[0][1] = 0.0; pln_orig[0][2] = box_max[2];
2387  pln_norm[0][0] = 0.0; pln_norm[0][1] = 0.0; pln_norm[0][2] = 1.0;
2388  // Left
2389  pln_orig[1][0] = box_min[0]; pln_orig[1][1] = 0.0; pln_orig[1][2] = 0.0;
2390  pln_norm[1][0] = -1.0; pln_norm[1][1] = 0.0; pln_norm[1][2] = 0.0;
2391  // Top
2392  pln_orig[2][0] = 0.0; pln_orig[2][1] = box_max[1]; pln_orig[2][2] = 0.0;
2393  pln_norm[2][0] = 0.0; pln_norm[2][1] = 1.0; pln_norm[2][2] = 0.0;
2394  // Right
2395  pln_orig[3][0] = box_max[0]; pln_orig[3][1] = 0.0; pln_orig[3][2] = 0.0;
2396  pln_norm[3][0] = 1.0; pln_norm[3][1] = 0.0; pln_norm[3][2] = 0.0;
2397  // Bottom
2398  pln_orig[4][0] = 0.0; pln_orig[4][1] = box_min[1]; pln_orig[4][2] = 0.0;
2399  pln_norm[4][0] = 0.0; pln_norm[4][1] = -1.0; pln_norm[4][2] = 0.0;
2400  // Back
2401  pln_orig[5][0] = 0.0; pln_orig[5][1] = 0.0; pln_orig[5][2] = box_min[2];
2402  pln_norm[5][0] = 0.0; pln_norm[5][1] = 0.0; pln_norm[5][2] = -1.0;
2403
2404  double z; // Intersection along cylinder's axis
2405  double min_z = CUBIT_DBL_MAX, max_z = -CUBIT_DBL_MAX;
2406 
2407  double t = 0.0, dt;
2408  dt = 1.0/(double)num_tess_pnts;
2409  double pnt[3];
2410  double int_pnt[3];
2411  double box_tol = 1e-14;
2412  double box_min_0 = box_min[0]-box_tol;
2413  double box_min_1 = box_min[1]-box_tol;
2414  double box_min_2 = box_min[2]-box_tol;
2415  double box_max_0 = box_max[0]+box_tol;
2416  double box_max_1 = box_max[1]+box_tol;
2417  double box_max_2 = box_max[2]+box_tol;
2418
2419  int i,j;
2420  for( i=0; i<num_tess_pnts; i++ )
2421  {
2422    get_arc_xyz( arc, t, pnt );
2423
2424    for( j=0; j<6; j++ )
2425    {
2426      // Evaluate the intersection at this point
2427      if( int_ln_pln( pnt, cyl_z, pln_orig[j], pln_norm[j], int_pnt )
2428        == CUBIT_FAILURE )
2429        continue;
2430
2431      // Throw-out if intersection not on physical box
2432      if( int_pnt[0] < box_min_0 || int_pnt[1] < box_min_1 ||
2433          int_pnt[2] < box_min_2 || int_pnt[0] > box_max_0 ||
2434          int_pnt[1] > box_max_1 || int_pnt[2] > box_max_2 ) 
2435        continue;
2436
2437      // Find min/max cylinder z on box so far
2438      // z-distance (in cylinder coordinate system)
2439      z = cubit2cyl_mtx[0][2]*int_pnt[0] + cubit2cyl_mtx[1][2]*int_pnt[1] + 
2440        cubit2cyl_mtx[2][2]*int_pnt[2] + cubit2cyl_mtx[3][2];
2441
2442      if( z < min_z ) min_z = z;
2443      if( z > max_z ) max_z = z;
2444     
2445    }
2446
2447    t += dt;
2448
2449  }
2450
2451  // Check the 8 corners of the box - they are likely min/max's.
2452  double box_corners[8][3];
2453  get_box_corners( box_min, box_max, box_corners );
2454  for( i=0; i<8; i++ )
2455  {
2456    // Get the corner in the cylinder csys
2457    transform_pnt( cubit2cyl_mtx, box_corners[i], pnt );
2458    // If the pnt is within the circle's radius, check it's z-coord
2459    // (distance from center)
2460    if(  sqrt( pnt[0]*pnt[0] + pnt[1]*pnt[1] ) <= radius+box_tol )
2461    {
2462      if( pnt[2] < min_z ) min_z = pnt[2];
2463      if( pnt[2] > max_z ) max_z = pnt[2];
2464    }
2465  }
2466
2467  if( min_z == CUBIT_DBL_MAX || max_z == -CUBIT_DBL_MAX )
2468  {
2469    PRINT_ERROR( "Unable to find cylinder/box intersection\n" );
2470    return CUBIT_FAILURE;
2471  }
2472
2473  if( min_z == max_z )
2474  {
2475    PRINT_ERROR( "Unable to find cylinder/box intersection\n" );
2476    return CUBIT_FAILURE;
2477  }
2478
2479  //PRINT_INFO( "Min dist = %f\n", min_z );
2480  //PRINT_INFO( "Max dist = %f\n", max_z );
2481
2482  // Find the start and end of the cylinder
2483  next_pnt( center, cyl_z, min_z, start );
2484  next_pnt( center, cyl_z, max_z, end );
2485
2486  //PRINT_INFO( "Start = %f, %f, %f\n", start[0], start[1], start[2] );
2487  //PRINT_INFO( "End = %f, %f, %f\n", end[0], end[1], end[2] );
2488
2489  // Extend start and end, if necessary
2490  if( extension_type > 0 )
2491  {
2492    double ext_distance = 0.0;
2493    if( extension_type == 1 ) // percentage
2494    {
2495      double cyl_length = dist_pnt_pnt( start, end );
2496      ext_distance = extension/100.0 * cyl_length;
2497    }
2498    else
2499      ext_distance = extension;
2500
2501    next_pnt( end, cyl_z, ext_distance, end );
2502    reverse_vec( cyl_z, cyl_z );
2503    next_pnt( start, cyl_z, ext_distance, start );
2504  }
2505
2506  return CUBIT_SUCCESS;
2507}
2508
2509// MAGIC SOFTWARE - see .hpp file
2510// FILE: minbox2.cpp
2511//---------------------------------------------------------------------------
2512double AnalyticGeometryTool::Area (int N, Point2* pt, double angle)
2513{
2514    double cs = cos(angle), sn = sin(angle);
2515
2516    double umin = +cs*pt[0].x+sn*pt[0].y, umax = umin;
2517    double vmin = -sn*pt[0].x+cs*pt[0].y, vmax = vmin;
2518    for (int i = 1; i < N; i++)
2519    {
2520        double u = +cs*pt[i].x+sn*pt[i].y;
2521        if ( u < umin )
2522            umin = u;
2523        else if ( u > umax )
2524            umax = u;
2525
2526        double v = -sn*pt[i].x+cs*pt[i].y;
2527        if ( v < vmin )
2528            vmin = v;
2529        else if ( v > vmax )
2530            vmax = v;
2531    }
2532
2533    double area = (umax-umin)*(vmax-vmin);
2534    return area;
2535}
2536//---------------------------------------------------------------------------
2537void AnalyticGeometryTool::MinimalBoxForAngle (int N, Point2