opennurbs_bounding_box.cpp
Go to the documentation of this file.
00001 /* $NoKeywords: $ */
00002 /*
00003 //
00004 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
00005 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
00006 // McNeel & Associates.
00007 //
00008 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
00009 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
00010 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
00011 //                              
00012 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
00013 //
00015 */
00016 
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018 
00019 ON_BoundingBox::ON_BoundingBox()
00020                 : m_min(1.0,0.0,0.0), 
00021                   m_max(-1.0,0.0,0.0)
00022 {}
00023 
00024 const ON_BoundingBox ON_BoundingBox::EmptyBoundingBox;
00025 
00026 ON_BoundingBox::ON_BoundingBox( const ON_3dPoint& min_pt, const ON_3dPoint& max_pt )
00027                 : m_min( min_pt ), 
00028                   m_max( max_pt )
00029 {}
00030 
00031 ON_BoundingBox::~ON_BoundingBox()
00032 {}
00033 
00034 void ON_BoundingBox::Destroy()
00035 {
00036   m_min.Zero();
00037   m_max.Zero();
00038   m_min.x = 1.0;
00039   m_max.x = -1.0;
00040 }
00041 
00043 // ON_BoundingBox::Transform() updates the bounding box
00044 // to be the smallest axis aligned bounding box that contains
00045 // the transform of the eight corner points of the input
00046 // bounding box.
00047 bool ON_BoundingBox::Transform( const ON_Xform& xform )
00048 {
00049   ON_3dPointArray corners;
00050   bool rc =  GetCorners( corners );
00051   if (rc) {
00052     rc = corners.Transform(xform);
00053     if (rc)
00054       rc = Set(corners);
00055   }
00056   return rc;
00057 }
00058 
00059 double ON_BoundingBox::Tolerance() const
00060 {
00061   // rough guess at a tolerance to use for comparing
00062   return ON_BoundingBoxTolerance( 3, m_min, m_max );
00063 }
00064 
00065 ON_3dPoint& ON_BoundingBox::operator[](int i)
00066 {
00067   return (i>0) ? m_max : m_min;
00068 }
00069 
00070 const ON_3dPoint& ON_BoundingBox::operator[](int i) const
00071 {
00072   return (i>0) ? m_max : m_min;
00073 }
00074 
00075 ON_3dPoint ON_BoundingBox::Min() const 
00076 {
00077         return m_min;
00078 }
00079 
00080 ON_3dPoint ON_BoundingBox::Max() const 
00081 {
00082         return m_max;
00083 }
00084 
00085 ON_3dVector ON_BoundingBox::Diagonal() const
00086 {
00087   return m_max - m_min;
00088 }
00089 
00090 ON_3dPoint ON_BoundingBox::Center() const
00091 {
00092   return 0.5*(m_max+m_min);
00093 }
00094 
00095 ON_3dPoint ON_BoundingBox::Corner( int x_index, int y_index, int z_index ) const
00096 {
00097   // 8 corners of box
00098   // x_index   0 = Min().x, 1 = Max().x
00099   // y_index   0 = Min().y, 1 = Max().y
00100   // z_index   0 = Min().z, 1 = Max().z
00101   ON_3dPoint corner;
00102   corner.x = (x_index>0) ? m_max.x : m_min.x;
00103   corner.y = (y_index>0) ? m_max.y : m_min.y;
00104   corner.z = (z_index>0) ? m_max.z : m_min.z;
00105   return corner;
00106 }
00107 
00108 bool
00109 ON_BoundingBox::GetCorners( 
00110   ON_3dPoint corners[8]// returns list of 8 corner points
00111   ) const
00112 {
00113   int n = 0;
00114   if ( IsValid() ) 
00115   {
00116     ON_3dPoint P;
00117     int i,j,k;
00118     for( i = 0; i < 2; i++ ) 
00119     {
00120       P.x = (i) ? m_max.x : m_min.x;
00121       for ( j = 0; j < 2; j++ )
00122       {
00123         P.y = (j) ? m_max.y : m_min.y;
00124         for ( k = 0; k < 2; k++ )
00125         {
00126           P.z = (k) ? m_max.z : m_min.z;
00127           corners[n++] = P;
00128         }
00129       }
00130     }
00131   }
00132   return (8==n);
00133 }
00134 
00135 bool
00136 ON_BoundingBox::GetCorners( 
00137   ON_3dPointArray& corners// returns list of 8 corner points
00138   ) const
00139 {
00140   ON_3dPoint c[8];
00141   corners.Empty();
00142   bool rc = GetCorners(c);
00143   if ( rc )
00144     corners.Append(8,c);
00145   return rc;
00146 }
00147 
00148 ON_ClippingRegion::ON_ClippingRegion()
00149 {
00150   memset(this,0,sizeof(*this));
00151 }
00152 
00153 void ON_ClippingRegion::SetClipPlaneTolerance( double clip_plane_tolerance )
00154 {
00155   if ( clip_plane_tolerance > 0.0 && clip_plane_tolerance < 3.402823466e+38 )
00156     m_clip_plane_tolerance = (float)clip_plane_tolerance;
00157   else
00158     m_clip_plane_tolerance = 0.0;
00159 }
00160 
00161 double ON_ClippingRegion::ClipPlaneTolerance() const
00162 {
00163   return (float)m_clip_plane_tolerance;
00164 }
00165 
00166 int ON_ClippingRegion::InViewFrustum( 
00167   ON_3dPoint P
00168   ) const
00169 {
00170   return InViewFrustum(1,&P);
00171 }
00172 
00173 int ON_ClippingRegion::InViewFrustum( 
00174   const ON_BoundingBox& bbox
00175   ) const
00176 {
00177   if (    !ON_IsValid(bbox.m_min.x) 
00178        || !ON_IsValid(bbox.m_max.x) 
00179        || bbox.m_min.x > bbox.m_max.x
00180        )
00181   {
00182     return 0;
00183   }
00184 
00185   ON_3dPoint P[8];
00186   P[0] = bbox.m_min;
00187   P[1] = bbox.m_max;
00188   P[2].x = bbox.m_min.x; P[2].y = bbox.m_min.y; P[2].z = bbox.m_max.z;
00189   P[3].x = bbox.m_min.x; P[3].y = bbox.m_max.y; P[3].z = bbox.m_min.z;
00190   P[4].x = bbox.m_min.x; P[4].y = bbox.m_max.y; P[4].z = bbox.m_max.z;
00191   P[5].x = bbox.m_max.x; P[5].y = bbox.m_min.y; P[5].z = bbox.m_min.z;
00192   P[6].x = bbox.m_max.x; P[6].y = bbox.m_min.y; P[6].z = bbox.m_max.z;
00193   P[7].x = bbox.m_max.x; P[7].y = bbox.m_max.y; P[7].z = bbox.m_min.z;
00194 
00195   return InViewFrustum(8,P);
00196 }
00197 
00198 int ON_ClippingRegion::InViewFrustum( 
00199   int count, 
00200   const ON_3fPoint* p
00201   ) const
00202 {
00203   const double* xform;
00204   const float* cv;
00205   double x, w;
00206   unsigned int out, all_out, some_out;
00207   int i;
00208 
00209   some_out = 0;
00210   all_out  = 0xFFFFFFFF;
00211   xform = &m_xform.m_xform[0][0];
00212   cv = &p[0].x;
00213   for ( i = count; i--; cv += 3 )
00214   {
00215     out = 0;
00216     w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15];
00217     x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3];
00218     if (x < -w) out  = 0x01; else if (x > w) out  = 0x02;
00219     x = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7];
00220     if (x < -w) out |= 0x04; else if (x > w) out |= 0x08;
00221     x = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11];
00222     if (x < -w) out |= 0x10; else if (x > w) out |= 0x20;
00223     some_out |= out;
00224     all_out  &= out;
00225     if ( some_out && !all_out )
00226     {
00227       //  no further "out" checking is necessary
00228       break;
00229     }
00230   }
00231 
00232   if ( all_out )
00233     i = 0;
00234   else if ( some_out )
00235     i = 1;
00236   else
00237     i = 2;
00238 
00239   return i;
00240 }
00241 
00242 int ON_ClippingRegion::InViewFrustum( 
00243   int count, 
00244   const ON_3dPoint* p
00245   ) const
00246 {
00247   const double* xform;
00248   const double* cv;
00249   double x, w;
00250   unsigned int out, all_out, some_out;
00251   int i;
00252 
00253   some_out = 0;
00254   all_out  = 0xFFFFFFFF;
00255   xform = &m_xform.m_xform[0][0];
00256   cv = &p[0].x;
00257   for ( i = count; i--; cv += 3 )
00258   {
00259     out = 0;
00260     w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15];
00261     x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3];
00262     if (x < -w) out  = 0x01; else if (x > w) out  = 0x02;
00263     x = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7];
00264     if (x < -w) out |= 0x04; else if (x > w) out |= 0x08;
00265     x = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11];
00266     if (x < -w) out |= 0x10; else if (x > w) out |= 0x20;
00267     some_out |= out;
00268     all_out  &= out;
00269     if ( some_out && !all_out )
00270     {
00271       //  no further "out" checking is necessary
00272       break;
00273     }
00274   }
00275 
00276   if ( all_out )
00277     i = 0;
00278   else if ( some_out )
00279     i = 1;
00280   else
00281     i = 2;
00282 
00283   return i;
00284 }
00285 
00286 int ON_ClippingRegion::InViewFrustum( 
00287   int count, 
00288   const ON_4dPoint* p
00289   ) const
00290 {
00291   const double* xform;
00292   const double* cv;
00293   double x, w;
00294   unsigned int out, all_out, some_out;
00295   int i;
00296 
00297   some_out = 0;
00298   all_out  = 0xFFFFFFFF;
00299   xform = &m_xform.m_xform[0][0];
00300   cv = &p[0].x;
00301   for ( i = count; i--; cv += 4 )
00302   {
00303     out = 0;
00304     w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15]*cv[3];
00305     x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3]*cv[3];
00306     if (x < -w) out  = 0x01; else if (x > w) out  = 0x02;
00307     x = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7]*cv[3];
00308     if (x < -w) out |= 0x04; else if (x > w) out |= 0x08;
00309     x = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11]*cv[3];
00310     if (x < -w) out |= 0x10; else if (x > w) out |= 0x20;
00311     some_out |= out;
00312     all_out  &= out;
00313     if ( some_out && !all_out )
00314     {
00315       //  no further "out" checking is necessary
00316       break;
00317     }
00318   }
00319 
00320   if ( all_out )
00321     i = 0;
00322   else if ( some_out )
00323     i = 1;
00324   else
00325     i = 2;
00326 
00327   return i;
00328 }
00329 
00330 int ON_ClippingRegion::InClipPlaneRegion( 
00331   ON_3dPoint P
00332   ) const
00333 {
00334   return InClipPlaneRegion(1,&P);
00335 }
00336 
00337 int ON_ClippingRegion::InClipPlaneRegion( 
00338   const ON_BoundingBox& bbox
00339   ) const
00340 {
00341   if (    !ON_IsValid(bbox.m_min.x) 
00342        || !ON_IsValid(bbox.m_max.x) 
00343        || bbox.m_min.x > bbox.m_max.x
00344        )
00345   {
00346     return 0;
00347   }
00348 
00349   if ( m_clip_plane_count <= 0 )
00350   {
00351     return 2;
00352   }
00353 
00354   ON_3dPoint P[8];
00355   P[0] = bbox.m_min;
00356   P[1] = bbox.m_max;
00357   P[2].x = bbox.m_min.x; P[2].y = bbox.m_min.y; P[2].z = bbox.m_max.z;
00358   P[3].x = bbox.m_min.x; P[3].y = bbox.m_max.y; P[3].z = bbox.m_min.z;
00359   P[4].x = bbox.m_min.x; P[4].y = bbox.m_max.y; P[4].z = bbox.m_max.z;
00360   P[5].x = bbox.m_max.x; P[5].y = bbox.m_min.y; P[5].z = bbox.m_min.z;
00361   P[6].x = bbox.m_max.x; P[6].y = bbox.m_min.y; P[6].z = bbox.m_max.z;
00362   P[7].x = bbox.m_max.x; P[7].y = bbox.m_max.y; P[7].z = bbox.m_min.z;
00363 
00364   return InClipPlaneRegion(8,P);
00365 }
00366 
00367 int ON_ClippingRegion::InClipPlaneRegion( 
00368   int count, 
00369   const ON_3fPoint* p
00370   ) const
00371 {
00372   const ON_PlaneEquation* cpeqn;
00373   const float* cv;
00374   double x;
00375   unsigned int out, all_out, some_out, cpbit;
00376   int i, j;
00377 
00378   // 14 May 2012 Dale Lear
00379   //   Fix http://dev.mcneel.com/bugtrack/?q=102481
00380   //   Picking hatches that are coplanar with clipping planes.
00381   //   The "fix" was to set clipping_plane_tolerance = same
00382   //   tolerance the display code uses.  Before the fix,
00383   //   0.0 was used as the clipping_plane_tolerance.
00384   const double clip_plane_tolerance = ClipPlaneTolerance();
00385 
00386   if ( count <= 0 || !p )
00387     return 0;
00388 
00389   if ( m_clip_plane_count <= 0 )
00390     return 2;
00391 
00392   some_out = 0;
00393   all_out  = 0xFFFFFFFF;
00394   cv = &p[0].x;
00395   for ( i = count; i--; cv += 3 )
00396   {
00397     out = 0;
00398     //if ( m_clip_plane_count )
00399     {
00400       cpbit = 0x40;
00401       cpeqn = m_clip_plane;
00402       j = m_clip_plane_count;
00403       while (j--)
00404       {
00405         x = cpeqn->x*cv[0] + cpeqn->y*cv[1] + cpeqn->z*cv[2] + cpeqn->d;
00406         if ( x < -clip_plane_tolerance )
00407           out |= cpbit;
00408         cpbit <<= 1;
00409         cpeqn++;;
00410       }
00411     }
00412     some_out |= out;
00413     all_out  &= out;
00414     if ( some_out && !all_out )
00415     {
00416       //  no further "out" checking is necessary
00417       break;
00418     }
00419   }
00420 
00421   if ( all_out )
00422     i = 0;
00423   else if ( some_out )
00424     i = 1;
00425   else
00426     i = 2;
00427 
00428   return i;
00429 }
00430 
00431 int ON_ClippingRegion::InClipPlaneRegion( 
00432   int count, 
00433   const ON_3dPoint* p
00434   ) const
00435 {
00436   const ON_PlaneEquation* cpeqn;
00437   const double* cv;
00438   double x;
00439   unsigned int out, all_out, some_out, cpbit;
00440   int i, j;
00441 
00442   if ( count <= 0 || !p )
00443     return 0;
00444 
00445   if ( m_clip_plane_count <= 0 )
00446     return 2;
00447 
00448   // 14 May 2012 Dale Lear
00449   //   Fix http://dev.mcneel.com/bugtrack/?q=102481
00450   //   Picking hatches that are coplanar with clipping planes.
00451   //   The "fix" was to set clipping_plane_tolerance = same
00452   //   tolerance the display code uses.  Before the fix,
00453   //   0.0 was used as the clipping_plane_tolerance.
00454   const double clip_plane_tolerance = ClipPlaneTolerance();
00455 
00456   some_out = 0;
00457   all_out  = 0xFFFFFFFF;
00458   cv = &p[0].x;
00459   for ( i = count; i--; cv += 3 )
00460   {
00461     out = 0;
00462     //if ( m_clip_plane_count )
00463     {
00464       cpbit = 0x40;
00465       cpeqn = m_clip_plane;
00466       j = m_clip_plane_count;
00467       while (j--)
00468       {
00469         x = cpeqn->x*cv[0] + cpeqn->y*cv[1] + cpeqn->z*cv[2] + cpeqn->d;
00470         if ( x < -clip_plane_tolerance )
00471           out |= cpbit;
00472         cpbit <<= 1;
00473         cpeqn++;;
00474       }
00475     }
00476     some_out |= out;
00477     all_out  &= out;
00478     if ( some_out && !all_out )
00479     {
00480       //  no further "out" checking is necessary
00481       break;
00482     }
00483   }
00484 
00485   if ( all_out )
00486     i = 0;
00487   else if ( some_out )
00488     i = 1;
00489   else
00490     i = 2;
00491 
00492   return i;
00493 }
00494 
00495 int ON_ClippingRegion::InClipPlaneRegion( 
00496   int count, 
00497   const ON_4dPoint* p
00498   ) const
00499 {
00500   const ON_PlaneEquation* cpeqn;
00501   const double* cv;
00502   double x;
00503   unsigned int out, all_out, some_out, cpbit;
00504   int i, j;
00505 
00506   if ( count <= 0 || !p )
00507     return 0;
00508 
00509   if ( m_clip_plane_count <= 0 )
00510     return 2;
00511 
00512   // 14 May 2012 Dale Lear
00513   //   Fix http://dev.mcneel.com/bugtrack/?q=102481
00514   //   Picking hatches that are coplanar with clipping planes.
00515   //   The "fix" was to set clipping_plane_tolerance = same
00516   //   tolerance the display code uses.  Before the fix,
00517   //   0.0 was used as the clipping_plane_tolerance.
00518   const double clip_plane_tolerance = ClipPlaneTolerance();
00519 
00520   some_out = 0;
00521   all_out  = 0xFFFFFFFF;
00522   cv = &p[0].x;
00523   for ( i = count; i--; cv += 4 )
00524   {
00525     out = 0;
00526     //if ( m_clip_plane_count )
00527     {
00528       cpbit = 0x40;
00529       cpeqn = m_clip_plane;
00530       j = m_clip_plane_count;
00531       while (j--)
00532       {
00533         x = cpeqn->x*cv[0] + cpeqn->y*cv[1] + cpeqn->z*cv[2] + cpeqn->d*cv[3];
00534         if ( x < -clip_plane_tolerance )
00535           out |= cpbit;
00536         cpbit <<= 1;
00537         cpeqn++;;
00538       }
00539     }
00540     some_out |= out;
00541     all_out  &= out;
00542     if ( some_out && !all_out )
00543     {
00544       //  no further "out" checking is necessary
00545       break;
00546     }
00547   }
00548 
00549   if ( all_out )
00550     i = 0;
00551   else if ( some_out )
00552     i = 1;
00553   else
00554     i = 2;
00555 
00556   return i;
00557 }
00558 
00559 int ON_ClippingRegion::IsVisible( ON_3dPoint P ) const
00560 {
00561   return IsVisible(1,&P);
00562 }
00563 
00564 int ON_ClippingRegion::IsVisible( const ON_BoundingBox& bbox ) const
00565 {
00566   if (    !ON_IsValid(bbox.m_min.x) 
00567        || !ON_IsValid(bbox.m_max.x) 
00568        || bbox.m_min.x > bbox.m_max.x
00569        )
00570   {
00571     return 0;
00572   }
00573 
00574   ON_3dPoint P[8];
00575   P[0] = bbox.m_min;
00576   P[1] = bbox.m_max;
00577   P[2].x = bbox.m_min.x; P[2].y = bbox.m_min.y; P[2].z = bbox.m_max.z;
00578   P[3].x = bbox.m_min.x; P[3].y = bbox.m_max.y; P[3].z = bbox.m_min.z;
00579   P[4].x = bbox.m_min.x; P[4].y = bbox.m_max.y; P[4].z = bbox.m_max.z;
00580   P[5].x = bbox.m_max.x; P[5].y = bbox.m_min.y; P[5].z = bbox.m_min.z;
00581   P[6].x = bbox.m_max.x; P[6].y = bbox.m_min.y; P[6].z = bbox.m_max.z;
00582   P[7].x = bbox.m_max.x; P[7].y = bbox.m_max.y; P[7].z = bbox.m_min.z;
00583 
00584   return IsVisible(8,P);
00585 }
00586 
00587 
00588 int ON_ClippingRegion::IsVisible( int count, const ON_3fPoint* p ) const
00589 {
00590   const double* xform;
00591   const ON_PlaneEquation* cpeqn;
00592   const float* cv;
00593   double x, w;
00594   unsigned int out, all_out, some_out, cpbit;
00595   int i, j;
00596 
00597   // 14 May 2012 Dale Lear
00598   //   Fix http://dev.mcneel.com/bugtrack/?q=102481
00599   //   Picking hatches that are coplanar with clipping planes.
00600   //   The "fix" was to set clipping_plane_tolerance = same
00601   //   tolerance the display code uses.  Before the fix,
00602   //   0.0 was used as the clipping_plane_tolerance.
00603   const double clip_plane_tolerance = ClipPlaneTolerance();
00604 
00605   some_out = 0;
00606   all_out  = 0xFFFFFFFF;
00607   xform = &m_xform.m_xform[0][0];
00608   cv = &p[0].x;
00609   for ( i = count; i--; cv += 3 )
00610   {
00611     out = 0;
00612     if ( m_clip_plane_count )
00613     {
00614       cpbit = 0x40;
00615       cpeqn = m_clip_plane;
00616       j = m_clip_plane_count;
00617       while (j--)
00618       {
00619         x = cpeqn->x*cv[0] + cpeqn->y*cv[1] + cpeqn->z*cv[2] + cpeqn->d;
00620         if ( x < -clip_plane_tolerance )
00621           out |= cpbit;
00622         cpbit <<= 1;
00623         cpeqn++;;
00624       }
00625     }
00626     w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15];
00627     x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3];
00628     if (x < -w) out |= 0x01; else if (x > w) out |= 0x02;
00629     x = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7];
00630     if (x < -w) out |= 0x04; else if (x > w) out |= 0x08;
00631     x = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11];
00632     if (x < -w) out |= 0x10; else if (x > w) out |= 0x20;
00633     some_out |= out;
00634     all_out  &= out;
00635     if ( some_out && !all_out )
00636     {
00637       //  no further "out" checking is necessary
00638       break;
00639     }
00640   }
00641 
00642   if ( all_out )
00643     i = 0;
00644   else if ( some_out )
00645     i = 1;
00646   else
00647     i = 2;
00648 
00649   return i;
00650 }
00651 
00652 int ON_ClippingRegion::IsVisible( int count, const ON_3dPoint* p ) const
00653 {
00654   const double* xform;
00655   const ON_PlaneEquation* cpeqn;
00656   const double* cv;
00657   double x, w;
00658   unsigned int out, all_out, some_out, cpbit;
00659   int i, j;
00660 
00661   // 14 May 2012 Dale Lear
00662   //   Fix http://dev.mcneel.com/bugtrack/?q=102481
00663   //   Picking hatches that are coplanar with clipping planes.
00664   //   The "fix" was to set clipping_plane_tolerance = same
00665   //   tolerance the display code uses.  Before the fix,
00666   //   0.0 was used as the clipping_plane_tolerance.
00667   const double clip_plane_tolerance = ClipPlaneTolerance();
00668 
00669   some_out = 0;
00670   all_out  = 0xFFFFFFFF;
00671   xform = &m_xform.m_xform[0][0];
00672   cv = &p[0].x;
00673   for ( i = count; i--; cv += 3 )
00674   {
00675     out = 0;
00676     if ( m_clip_plane_count )
00677     {
00678       cpbit = 0x40;
00679       cpeqn = m_clip_plane;
00680       j = m_clip_plane_count;
00681       while (j--)
00682       {
00683         x = cpeqn->x*cv[0] + cpeqn->y*cv[1] + cpeqn->z*cv[2] + cpeqn->d;
00684         if ( x < -clip_plane_tolerance )
00685           out |= cpbit;
00686         cpbit <<= 1;
00687         cpeqn++;;
00688       }
00689     }
00690     w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15];
00691     x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3];
00692     if (x < -w) out |= 0x01; else if (x > w) out |= 0x02;
00693     x = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7];
00694     if (x < -w) out |= 0x04; else if (x > w) out |= 0x08;
00695     x = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11];
00696     if (x < -w) out |= 0x10; else if (x > w) out |= 0x20;
00697     some_out |= out;
00698     all_out  &= out;
00699     if ( some_out && !all_out )
00700     {
00701       //  no further "out" checking is necessary
00702       break;
00703     }
00704   }
00705 
00706   if ( all_out )
00707     i = 0;
00708   else if ( some_out )
00709     i = 1;
00710   else
00711     i = 2;
00712 
00713   return i;
00714 }
00715 
00716 
00717 int ON_ClippingRegion::IsVisible( int count, const ON_4dPoint* p ) const
00718 {
00719   const double* xform;
00720   const ON_PlaneEquation* cpeqn;
00721   const double* cv;
00722   double x, w;
00723   unsigned int out, all_out, some_out, cpbit;
00724   int i, j;
00725 
00726   // 14 May 2012 Dale Lear
00727   //   Fix http://dev.mcneel.com/bugtrack/?q=102481
00728   //   Picking hatches that are coplanar with clipping planes.
00729   //   The "fix" was to set clipping_plane_tolerance = same
00730   //   tolerance the display code uses.  Before the fix,
00731   //   0.0 was used as the clipping_plane_tolerance.
00732   const double clip_plane_tolerance = ClipPlaneTolerance();
00733 
00734   some_out = 0;
00735   all_out  = 0xFFFFFFFF;
00736   xform = &m_xform.m_xform[0][0];
00737   cv = &p[0].x;
00738   for ( i = count; i--; cv += 4 )
00739   {
00740     out = 0;
00741     if ( m_clip_plane_count )
00742     {
00743       cpbit = 0x40;
00744       cpeqn = m_clip_plane;
00745       j = m_clip_plane_count;
00746       while (j--)
00747       {
00748         x = cpeqn->x*cv[0] + cpeqn->y*cv[1] + cpeqn->z*cv[2] + cpeqn->d*cv[3];
00749         if ( x < -clip_plane_tolerance )
00750           out |= cpbit;
00751         cpbit <<= 1;
00752         cpeqn++;
00753       }
00754     }
00755     w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15]*cv[3];
00756     x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3]*cv[3];
00757     if (x < -w) out |= 0x01; else if (x > w) out |= 0x02;
00758     x = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7]*cv[3];
00759     if (x < -w) out |= 0x04; else if (x > w) out |= 0x08;
00760     x = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11]*cv[3];
00761     if (x < -w) out |= 0x10; else if (x > w) out |= 0x20;
00762     some_out |= out;
00763     all_out  &= out;
00764     if ( some_out && !all_out )
00765     {
00766       //  no further "out" checking is necessary
00767       break;
00768     }
00769   }
00770 
00771   if ( all_out )
00772     i = 0;
00773   else if ( some_out )
00774     i = 1;
00775   else
00776     i = 2;
00777 
00778   return i;
00779 }
00780 
00781 unsigned int ON_ClippingRegion::TransformPoint(
00782                      const ON_4dPoint& P, 
00783                      ON_4dPoint& Q
00784                      ) const
00785 {
00786   unsigned int out, cpbit;
00787   const double* xform = &m_xform.m_xform[0][0];
00788   const double cv[4] = {P.x,P.y,P.z,P.w};
00789   const ON_PlaneEquation* cpeqn;
00790   int j;
00791   double x,y,z,w;
00792 
00793   // 14 May 2012 Dale Lear
00794   //   Fix http://dev.mcneel.com/bugtrack/?q=102481
00795   //   Picking hatches that are coplanar with clipping planes.
00796   //   The "fix" was to set clipping_plane_tolerance = same
00797   //   tolerance the display code uses.  Before the fix,
00798   //   0.0 was used as the clipping_plane_tolerance.
00799   const double clip_plane_tolerance = ClipPlaneTolerance();
00800 
00801   out = 0;
00802   if ( m_clip_plane_count )
00803   {
00804     cpbit = 0x40;
00805     cpeqn = m_clip_plane;
00806     j = m_clip_plane_count;
00807     while (j--)
00808     {
00809       x = cpeqn->x*cv[0] + cpeqn->y*cv[1] + cpeqn->z*cv[2] + cpeqn->d*cv[3];
00810       if ( x < -clip_plane_tolerance )
00811         out |= cpbit;
00812       cpbit <<= 1;
00813       cpeqn++;
00814     }
00815   }
00816   w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15]*cv[3];
00817   x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3]*cv[3];
00818   if (x < -w) out |= 0x01; else if (x > w) out |= 0x02;
00819   y = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7]*cv[3];
00820   if (y < -w) out |= 0x04; else if (y > w) out |= 0x08;
00821   z = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11]*cv[3];
00822   if (z < -w) out |= 0x10; else if (z > w) out |= 0x20;
00823   if ( w <= 0.0 )
00824     out = 0x80000000;
00825   Q.x = x; Q.y = y; Q.z = z; Q.w = w;
00826   return out;
00827 }
00828 
00829 unsigned int ON_ClippingRegion::TransformPoint(
00830                      const ON_3dPoint& P, 
00831                      ON_3dPoint& Q
00832                      ) const
00833 {
00834   unsigned int out, cpbit;
00835   const double* xform = &m_xform.m_xform[0][0];
00836   const double cv[3] = {P.x,P.y,P.z};
00837   const ON_PlaneEquation* cpeqn;
00838   int j;
00839   double x,y,z,w;
00840 
00841   // 14 May 2012 Dale Lear
00842   //   Fix http://dev.mcneel.com/bugtrack/?q=102481
00843   //   Picking hatches that are coplanar with clipping planes.
00844   //   The "fix" was to set clipping_plane_tolerance = same
00845   //   tolerance the display code uses.  Before the fix,
00846   //   0.0 was used as the clipping_plane_tolerance.
00847   const double clip_plane_tolerance = ClipPlaneTolerance();
00848 
00849   out = 0;
00850   if ( m_clip_plane_count )
00851   {
00852     cpbit = 0x40;
00853     cpeqn = m_clip_plane;
00854     j = m_clip_plane_count;
00855     while (j--)
00856     {
00857       x = cpeqn->x*cv[0] + cpeqn->y*cv[1] + cpeqn->z*cv[2] + cpeqn->d;
00858       if ( x < -clip_plane_tolerance )
00859         out |= cpbit;
00860       cpbit <<= 1;
00861       cpeqn++;
00862     }
00863   }
00864   w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15];
00865   x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3];
00866   if (x < -w) out |= 0x01; else if (x > w) out |= 0x02;
00867   y = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7];
00868   if (y < -w) out |= 0x04; else if (y > w) out |= 0x08;
00869   z = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11];
00870   if (z < -w) out |= 0x10; else if (z > w) out |= 0x20;
00871   if ( w <= 0.0 )
00872   {
00873     w = (0.0==w) ? 1.0 : 1.0/w;
00874     out |= 0x80000000;
00875   }
00876   else
00877   {
00878     w = 1.0/w;
00879   }
00880   Q.x = x*w; Q.y = y*w; Q.z = z*w;
00881   return out;
00882 }
00883 
00884 unsigned int ON_ClippingRegion::TransformPoint(
00885                      const ON_3fPoint& P, 
00886                      ON_3dPoint& Q
00887                      ) const
00888 {
00889   ON_3dPoint PP(P.x,P.y,P.z);
00890   return TransformPoint(PP,Q);
00891 }
00892 
00893 int ON_ClippingRegion::TransformPoints( int count, ON_4dPoint* p, unsigned int* pflags ) const
00894 {
00895   // transforms cv's to pick coordinates
00896   const double* xform;
00897   const ON_PlaneEquation* cpeqn;
00898   double* cv;
00899   double x, y, z, w;
00900   unsigned int out, all_out, some_out, cpbit;
00901   int i, j;
00902 
00903   // 14 May 2012 Dale Lear
00904   //   Fix http://dev.mcneel.com/bugtrack/?q=102481
00905   //   Picking hatches that are coplanar with clipping planes.
00906   //   The "fix" was to set clipping_plane_tolerance = same
00907   //   tolerance the display code uses.  Before the fix,
00908   //   0.0 was used as the clipping_plane_tolerance.
00909   const double clip_plane_tolerance = ClipPlaneTolerance();
00910 
00911   some_out = 0;
00912   all_out  = 0xFFFFFFFF;
00913   xform = &m_xform.m_xform[0][0];
00914   cv = &p[0].x;
00915   i = count;
00916   while (i--) 
00917   {
00918     out = 0;
00919     if ( m_clip_plane_count )
00920     {
00921       cpbit = 0x40;
00922       cpeqn = m_clip_plane;
00923       j = m_clip_plane_count;
00924       while (j--)
00925       {
00926         x = cpeqn->x*cv[0] + cpeqn->y*cv[1] + cpeqn->z*cv[2] + cpeqn->d*cv[3];
00927         if ( x < -clip_plane_tolerance )
00928           out |= cpbit;
00929         cpbit <<= 1;
00930         cpeqn++;;
00931       }
00932     }
00933     w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15]*cv[3];
00934     x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3]*cv[3];
00935     if (x < -w) out |= 0x01; else if (x > w) out |= 0x02;
00936     y = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7]*cv[3];
00937     if (y < -w) out |= 0x04; else if (y > w) out |= 0x08;
00938     z = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11]*cv[3];
00939     if (z < -w) out |= 0x10; else if (z > w) out |= 0x20;
00940     if ( w <= 0.0 )
00941       out |= 0x80000000;
00942     some_out |= out;
00943     all_out  &= out;
00944     *pflags++ = out;
00945     *cv++ = x; *cv++ = y; *cv++ = z; *cv++ = w;
00946   }
00947 
00948   if ( all_out )
00949     i = 0;
00950   else if ( some_out )
00951     i = 1;
00952   else
00953     i = 2;
00954 
00955   return i;
00956 }
00957 
00958 int ON_ClippingRegion::TransformPoints( int count, ON_4dPoint* p ) const
00959 {
00960   // transforms cv's to pick coordinates
00961   const double* xform;
00962   const ON_PlaneEquation* cpeqn;
00963   double* cv;
00964   double x, y, z, w;
00965   unsigned int out, all_out, some_out, cpbit;
00966   int i, j;
00967   
00968   // 14 May 2012 Dale Lear
00969   //   Fix http://dev.mcneel.com/bugtrack/?q=102481
00970   //   Picking hatches that are coplanar with clipping planes.
00971   //   The "fix" was to set clipping_plane_tolerance = same
00972   //   tolerance the display code uses.  Before the fix,
00973   //   0.0 was used as the clipping_plane_tolerance.
00974   const double clip_plane_tolerance = ClipPlaneTolerance();
00975 
00976   some_out = 0;
00977   all_out  = 0xFFFFFFFF;
00978   xform = &m_xform.m_xform[0][0];
00979   cv = &p[0].x;
00980   i = count;
00981   while (i--) 
00982   {
00983     out = 0;
00984     if ( m_clip_plane_count )
00985     {
00986       cpbit = 0x40;
00987       cpeqn = m_clip_plane;
00988       j = m_clip_plane_count;
00989       while (j--)
00990       {
00991         x = cpeqn->x*cv[0] + cpeqn->y*cv[1] + cpeqn->z*cv[2] + cpeqn->d*cv[3];
00992         if ( x < -clip_plane_tolerance )
00993           out |= cpbit;
00994         cpbit <<= 1;
00995         cpeqn++;;
00996       }
00997     }
00998     w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15]*cv[3];
00999     x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3]*cv[3];
01000     if (x < -w) out |= 0x01; else if (x > w) out |= 0x02;
01001     y = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7]*cv[3];
01002     if (y < -w) out |= 0x04; else if (y > w) out |= 0x08;
01003     z = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11]*cv[3];
01004     if (z < -w) out |= 0x10; else if (z > w) out |= 0x20;
01005     *cv++ = x; *cv++ = y; *cv++ = z; *cv++ = w;
01006     some_out |= out;
01007     all_out  &= out;
01008     if ( some_out && !all_out )
01009     {
01010       //  no further "out" checking is necessary
01011       while (i--)
01012       {
01013         x = xform[0]*cv[0] + xform[1]*cv[1] + xform[2]*cv[2] + xform[3]*cv[3];
01014         y = xform[4]*cv[0] + xform[5]*cv[1] + xform[6]*cv[2] + xform[7]*cv[3];
01015         z = xform[8]*cv[0] + xform[9]*cv[1] + xform[10]*cv[2] + xform[11]*cv[3];
01016         w = xform[12]*cv[0] + xform[13]*cv[1] + xform[14]*cv[2] + xform[15]*cv[3];
01017         *cv++ = x; *cv++ = y; *cv++ = z; *cv++ = w;
01018       }
01019       break;
01020     }
01021   }
01022 
01023   if ( all_out )
01024     i = 0;
01025   else if ( some_out )
01026     i = 1;
01027   else
01028     i = 2;
01029 
01030   return i;
01031 }
01032 
01033 
01034 bool ON_ClippingRegion::GetLineClipPlaneParamters( 
01035        ON_4dPoint P0, 
01036        ON_4dPoint P1, 
01037        double* t0, 
01038        double* t1 
01039        ) const
01040 {
01041   double s0, s1, x0, x1, s;
01042   const ON_PlaneEquation* eqn;
01043   int i;
01044   if ( m_clip_plane_count )
01045   {
01046     s0 = 0.0;
01047     s1 = 1.0;
01048     eqn = m_clip_plane;
01049     const double clip_plane_tolerance = ClipPlaneTolerance();
01050     for ( i = 0; i < m_clip_plane_count; i++, eqn++ )
01051     {
01052       x0 = eqn->x*P0.x + eqn->y*P0.y + eqn->z*P0.z + eqn->d*P0.w;
01053       x1 = eqn->x*P1.x + eqn->y*P1.y + eqn->z*P1.z + eqn->d*P1.w;
01054       if ( x0 < 0.0)
01055       {
01056         if ( x1 <= 0.0 )
01057         {
01058           if ( x0 < -clip_plane_tolerance && x1 <= - clip_plane_tolerance )
01059             return false;
01060         }
01061         if ( x0 != x1 )
01062         {
01063           s = x0/(x0-x1);
01064           if ( s > s0 )
01065           {
01066             s0 = s;
01067             if ( s0 >= s1 )
01068               return false;
01069           }
01070         }
01071       }
01072       else if ( x1 < 0.0 )
01073       {
01074         if ( x0 <= 0.0 )
01075         {
01076           if ( x1 < -clip_plane_tolerance && x0 <= - clip_plane_tolerance )
01077             return false;
01078         }
01079         if ( x0 != x1 )
01080         {
01081           s = x1/(x1-x0);
01082           if ( s < s1 )
01083           {
01084             s1 = s;
01085             if ( s0 >= s1 )
01086               return false;
01087           }
01088         }
01089       }
01090     }
01091     *t0 = s0;
01092     *t1 = s1;
01093   }
01094   else
01095   {
01096     *t0 = 0.0;
01097     *t1 = 1.0;
01098   }
01099   return true;
01100 }
01101 
01102 
01103 int ON_BoundingBox::IsVisible( 
01104   const ON_Xform& bbox2c
01105   ) const
01106 {
01107   int i,j,k,n;
01108   unsigned int all_out, some_out, out;
01109   double bx,by,bz,x,w;
01110   const double* p;
01111 
01112   if ( !ON_IsValid(m_min.x) || !ON_IsValid(m_max.x) || m_min.x > m_max.x)
01113     return 0;
01114 
01115   some_out = 0;    // will be != 0 if some portion of box is outside visible region
01116   all_out  = 0xFFFFFFFF; // will be == 0 if some portion of box is inside visible region
01117   p = &bbox2c.m_xform[0][0];
01118   n = 0; 
01119   i = 2; bx = m_min.x;
01120   while(i--)
01121   {
01122     j = 2; by = m_min.y;
01123     while(j--)
01124     {
01125       k = 2; bz = m_min.z;
01126       while(k--)
01127       {
01128         w = bx*p[12] + by*p[13] + bz*p[14] + p[15];
01129         x = bx*p[ 0] + by*p[ 1] + bz*p[ 2] + p[ 3];
01130         if ( x < -w) out  = 0x01; else if (x > w) out  = 0x02; else out = 0;
01131         x = bx*p[ 4] + by*p[ 5] + bz*p[ 6] + p[ 7];
01132         if ( x < -w) out |= 0x04; else if (x > w) out |= 0x08;
01133         x = bx*p[ 8] + by*p[ 9] + bz*p[10] + p[11];
01134         if ( x < -w) out |= 0x10; else if (x > w) out |= 0x20;
01135         some_out |= out;
01136         all_out  &= out;
01137         if ( some_out && !all_out )
01138         {
01139           // box intersects visble region but is not completely inside it.
01140           return  1;
01141         }
01142         bz = m_max.z;
01143       }
01144       by = m_max.y;
01145     }
01146     bx = m_max.x;
01147   }
01148 
01149   return ( all_out ? 0 : 2 );
01150 }
01151 
01152 bool ON_BoundingBox::IsPointIn( const ON_3dPoint& p, int bStrictlyIn ) const
01153 {
01154   bool bIn = false;
01155   if ( bStrictlyIn ) {
01156           bIn = m_min.x<p.x && p.x<m_max.x &&
01157                                         m_min.y<p.y && p.y<m_max.y &&
01158                                         m_min.z<p.z && p.z<m_max.z;
01159   }
01160   else {
01161           bIn = m_min.x<=p.x && p.x<=m_max.x &&
01162                                         m_min.y<=p.y && p.y<=m_max.y &&
01163                                         m_min.z<=p.z && p.z<=m_max.z;
01164   }
01165   return bIn;
01166 };
01167 
01168 ON_3dPoint ON_BoundingBox::ClosestPoint( 
01169   const ON_3dPoint& test_point
01170   ) const
01171 {
01172   ON_3dPoint near_point = test_point;
01173         // GBA  30 March 04.  For performance reasons in closest point to surface
01174         //this function no longer validates the bounding box. 
01175   if ( test_point.x < m_min.x )
01176     near_point.x = m_min.x;
01177   else if ( test_point.x > m_max.x )
01178     near_point.x = m_max.x;
01179   if ( test_point.y < m_min.y )
01180     near_point.y = m_min.y;
01181   else if ( test_point.y > m_max.y )
01182     near_point.y = m_max.y;
01183   if ( test_point.z < m_min.z )
01184     near_point.z = m_min.z;
01185   else if ( test_point.z > m_max.z )
01186     near_point.z = m_max.z;
01187   return near_point;
01188 }
01189 
01190 
01191 
01192 int ON_BoundingBox::GetClosestPoint( 
01193   const ON_Line& line, ON_3dPoint& box_point, double* t0, double* t1
01194   ) const
01195 {
01196   if(!IsValid() || !line.IsValid()) 
01197                 return 0;                       
01198         
01199         ON_3dPoint closest;
01200         
01201         if(line.Direction().Length()<=ON_SQRT_EPSILON){
01202                 ON_3dPoint center = line.PointAt(.5);
01203                 if(t0) *t0 = 0.0;
01204                 if(t1) *t1 = 1.0;
01205                 box_point = ClosestPoint(center);
01206                 return IsPointIn( center )? 3 : 1;
01207         }
01208 
01209         ON_Interval over[3];                    //parameter overlap for each direction
01210 
01211         for(int j=0; j<3; j++){
01212                 ON_Interval pl( line[0][j], line[1][j]);
01213                 if( pl[0]!=pl[1])
01214                         over[j]= ON_Interval(   pl.NormalizedParameterAt(Min()[j]),
01215                                                                                                                 pl.NormalizedParameterAt(Max()[j])  );
01216                 else 
01217                         if( Min()[j]<=pl[0] && pl[0]<=Max()[j] )
01218                                 over[j]=ON_Interval(-ON_DBL_MAX, ON_DBL_MAX);
01219                         else 
01220                                 over[j]=ON_Interval(ON_UNSET_VALUE, ON_UNSET_VALUE);
01221         }
01222 
01223 
01224 
01225         // Step 1.  Check for an intersection of the infinte line with the box
01226         ON_Interval overlap(-ON_DBL_MAX, ON_DBL_MAX);   
01227         bool nonempty=true;
01228   int i;
01229         for( i=0;i<3 && nonempty;i++)
01230                 nonempty = overlap.Intersection(over[i]);
01231         
01232         if(nonempty){   // infinte line intersects box
01233                 if( overlap.Intersection( ON_Interval(0,1) ) ){
01234                         // Box & Line segment  intersect
01235                         if(t0) *t0 = overlap[0];
01236                         if(t1) *t1 = overlap[1];
01237                         box_point = line.PointAt(overlap[0]);
01238                         return (overlap.Length()>0)? 3 : 2;
01239                 }
01240                 // closest point is at end of line segment
01241                 double EndInd=(overlap[1]<0)? 0.0: 1.0;
01242                 if(t0) *t0 = EndInd;
01243                 if(t1) *t1 = EndInd;
01244                 return 1;
01245         }
01246 
01247 
01248         //  Step 2.  Check for closest point on box edge and line segment interior
01249         //   In this case when we project orthogonal to the box edge we get a line 
01250         //   in the plane that doesn't intersect the 2d-box in the plane.  The projection
01251   //   of the 3d closest point is the closest point of this 2d closest point problem.
01252         int k[3];
01253         for(i=0; i<3; i++)
01254   {
01255                 // Project box and line onto coord plane with normal Unit(i).
01256 
01257                 if(!overlap.Intersection( over[(i+1)%3], over[(i+2)%3] )){      
01258                         // Projected line doesnt intersect the projexted box.  
01259                         // Find the closest  vertex of the projected box.  
01260                         ON_3dVector StdUnit(0,0,0);
01261                         StdUnit[i]=1.0;
01262                         ON_3dVector n = ON_CrossProduct(line.Direction(), StdUnit);
01263                         if(n.Length()==0)
01264                                 continue;
01265                         n.Unitize();
01266                         int ilo[3]={0,0,0};
01267                         int ihi[3]={1,1,1};
01268       int imin[3]={-1,-1,-1};
01269                         double amin=0.0;
01270                         ihi[i]=ilo[i];
01271                         for(k[0]=ilo[0];  k[0]<=ihi[0]; k[0]++)
01272                                 for(k[1]=ilo[1];  k[1]<=ihi[1]; k[1]++)
01273                                         for(k[2]=ilo[2];  k[2]<=ihi[2]; k[2]++){
01274                                                 double a = n*(Corner(k[0],k[1],k[2]) - line.from);
01275                                                 if(amin == 0.0 || fabs(a)<fabs(amin))
01276             {
01277                                                         amin= a;
01278                                                         imin[0]=k[0]; imin[1]=k[1]; imin[2]=k[2];
01279                                                 }
01280                         }
01281       if ( imin[0] < 0 )
01282       {
01283         return 0;
01284       }
01285                         ON_3dPoint vertex = Corner(imin[0],imin[1],imin[2]);
01286                         vertex[i] = line.from[i];
01287                         // Solve for 2d-closest point between closest corner and projected line 
01288                         ON_3dVector ProjDir = line.Direction();
01289                         ProjDir[i]=0.0;
01290                         double t = ( vertex - line.from)*ProjDir / ProjDir.LengthSquared();
01291                         ON_3dPoint cp = line.PointAt(t);
01292                         if( 0<=t && t<=1 && m_min[i]<=cp[i] &&cp[i]<= m_max[i] ){
01293                                 if(t0) *t0 = t;         // found the  closest point 
01294                                 if(t1) *t1 = t;
01295                                 vertex[i] =  cp[i];
01296                                 box_point = vertex;
01297                                 return 1;
01298                         }
01299                 }
01300         }
01301 
01302         //Step 3. Check each Corner of the box for closest points
01303         for( k[0]=0; k[0]<2; k[0]++)
01304                 for( k[1]=0; k[1]<2; k[1]++)
01305                         for( k[2]=0; k[2]<2; k[2]++){
01306                                 ON_3dPoint corner = Corner(k[0],k[1],k[2]);
01307                                 double tstar;
01308                                 line.ClosestPointTo( corner, &tstar );
01309                                 ON_3dPoint cp = line.PointAt( tstar);
01310                                 ON_3dVector disp = cp - corner;
01311                                 bool InNCone=true;
01312                                 for(int j=0;j<2 && InNCone;j++){
01313                                         InNCone = InNCone && ( k[j] )? disp[j]>=0 : disp[j]<=0  ;
01314                                 }
01315                                 if(InNCone){
01316                                         if(t0) *t0 = tstar;
01317                                         if(t1) *t1 = tstar;
01318                                         box_point = corner;
01319                                         return 1;
01320                                 } 
01321         }
01322 
01323         //Step 4. Closest point is at a line end
01324         for(i=0; i<2; i++){
01325                 closest = ClosestPoint(line[i]);
01326                 double dot = (closest - line[i]) * line.Direction();
01327                 if( (i==0 && dot<= 0) || (i==1 && dot>=0) )
01328     {
01329                         if(t0) *t0 = i;
01330                         if(t1) *t1 = i;
01331                         box_point = closest;
01332                         return 1;
01333                 }
01334         }
01335 
01336         ON_ASSERT(false);               //Should never get here
01337         return 0;  
01338 }                               
01339 
01340 
01341 
01342 ON_3dPoint ON_BoundingBox::FarPoint( 
01343   const ON_3dPoint& test_point
01344   ) const
01345 {
01346   ON_3dPoint far_point = test_point;
01347  // if ( IsValid() ) {
01348     far_point.x = ( fabs(m_min.x-test_point.x) >= fabs(m_max.x-test_point.x) )
01349                 ? m_min.x : m_max.x;
01350     far_point.y = ( fabs(m_min.y-test_point.y) >= fabs(m_max.y-test_point.y) )
01351                 ? m_min.y : m_max.y;
01352     far_point.z = ( fabs(m_min.z-test_point.z) >= fabs(m_max.z-test_point.z) )
01353                 ? m_min.z : m_max.z;
01354 //  }
01355   return far_point;
01356 }
01357 
01358 //TODO:  Replace this static function with an ON_Interval member function.
01359 //  Add to the ON_Interval class in ON_Interval.h
01360 //
01361 // returns true if the intersection is non-empty and sets AB to the intersection
01362 //  bool   GetIntersection(ON_Interval B, ON_Interval& AB);
01363 
01364 
01365 static bool Intersect( ON_Interval A, ON_Interval B, ON_Interval& AB);
01366 
01367 bool Intersect( ON_Interval A, ON_Interval B, ON_Interval& AB){
01368         if(A.IsDecreasing()) A.Swap();
01369         if(B.IsDecreasing()) B.Swap();
01370 
01371         bool NotEmpty=true;
01372         if( A.m_t[0] <= B.m_t[0] && B.m_t[0]<=A.m_t[1] &&  A.m_t[1]<= B.m_t[1]){
01373                 AB.Set(B.m_t[0], A.m_t[1]);
01374         } else if( B.m_t[0] <= A.m_t[0] && A.m_t[0]<=B.m_t[1] && B.m_t[1]<=A.m_t[1]){
01375                 AB.Set(A.m_t[0], B.m_t[1]);
01376         } else if( A.m_t[0] <=  B.m_t[0] && B.m_t[0] <= B.m_t[1] && B.m_t[1]<= A.m_t[1]){
01377                 AB.Set(B.m_t[0], B.m_t[1]);
01378         } else if( B.m_t[0] <= A.m_t[0] && A.m_t[0] <= A.m_t[1] && A.m_t[1]<= B.m_t[1]){
01379                 AB.Set(A.m_t[0], A.m_t[1]);
01380         } else if( B.m_t[0] <= A.m_t[0]  && A.m_t[0] <= A.m_t[1]  && A.m_t[1]<= B.m_t[1]){
01381                 AB.Set(A.m_t[0], A.m_t[1]);
01382         } else if(A.m_t[1] < B.m_t[0] || B.m_t[1] < A.m_t[0] ){
01383                 AB.Destroy();
01384                 NotEmpty = false;
01385         }
01386         return NotEmpty;
01387 }
01388 
01389 bool ON_BoundingBox::GetClosestPoint( 
01390        const ON_BoundingBox& other_box, // "other" bounding box
01391        ON_3dPoint& this_point, // point on "this" box that is closest to "other" box
01392        ON_3dPoint& other_point // point on "other" box that is closest to "this" box
01393        )  const
01394 {
01395   ON_BoundingBox b;
01396         if ( !IsValid() || !other_box.IsValid() )
01397                 return false;
01398 
01399         for (int i=0; i<3; i++ )
01400   {
01401                 ON_Interval It(m_min[i],m_max[i]);
01402                 ON_Interval Io(other_box.m_min[i],other_box.m_max[i]);
01403                 ON_Interval intersect;
01404                 bool NotEmpty = Intersect(It,Io,intersect);
01405                 if(NotEmpty)
01406     {
01407                         this_point[i] = other_point[i] = intersect.Mid();
01408                 } 
01409     else {
01410                         if(m_max[i]< other_box.m_min[i] )
01411       {
01412                                 this_point[i] = m_max[i];
01413                                 other_point[i] = other_box.m_min[i];
01414                         } 
01415       else {
01416                                 this_point[i] = m_min[i];
01417                                 other_point[i] = other_box.m_max[i];
01418                         }
01419                 }
01420         }
01421         return true;
01422 }
01423 
01425 // Get points on bounding boxes that are farthest from each other.
01426 bool ON_BoundingBox::GetFarPoint( 
01427        const ON_BoundingBox& other_box, // "other" bounding box
01428        ON_3dPoint& this_point, // point on "this" box that is farthest from "other" box point
01429        ON_3dPoint& other_point // point on "other" box that is farthest from "this" box point
01430        )  const
01431 {
01432         if(!IsValid() || !other_box.IsValid())
01433                 return false;
01434         for(int i=0; i<3; i++){
01435                 ON_Interval It(m_min[i], m_max[i]);
01436                 ON_Interval Io(other_box.m_min[i], other_box.m_max[i]);
01437                 if( It.Includes(Io) || Io.Includes(It)){
01438                         if( m_max[i] - other_box.m_min[i] > other_box.m_max[i] - m_min[i]){
01439                                 this_point[i] = m_max[i];
01440                                 other_point[i] = other_box.m_min[i];
01441                         } else {
01442                                 this_point[i] = m_min[i];
01443                                 other_point[i] = other_box.m_max[i];
01444                         }
01445                 } else {
01446                         if( m_min[i]< other_box.m_min[i]){
01447                                 this_point[i]=m_min[i];
01448                         } else {
01449                                 other_point[i] = other_box.m_min[i];
01450                         }
01451                         if( m_max[i]> other_box.m_max[i]){
01452                                 this_point[i]=m_max[i];
01453                         } else {
01454                                 other_point[i] = other_box.m_max[i];
01455                         }
01456                 }
01457         }
01458         return true;
01459 }
01460 
01461 bool ON_BoundingBox::SwapCoordinates( int i, int j )
01462 {
01463   bool rc = false;
01464   if ( IsValid() && 0 <= i && i < 3 && 0 <= j && j < 3 ) {
01465     rc = true;
01466     if ( i != j ) {
01467       double t = m_min[i]; m_min[i] = m_min[j]; m_min[j] = t;
01468       t = m_max[i]; m_max[i] = m_max[j]; m_max[j] = t;
01469     }
01470   }
01471   return rc;
01472 }
01473 
01474 bool ON_BoundingBox::IsDisjoint( const ON_BoundingBox& other_bbox ) const
01475 {
01476   if ( m_min.x > m_max.x || other_bbox.m_min.x > other_bbox.m_max.x 
01477        || m_min.x > other_bbox.m_max.x 
01478        || m_max.x < other_bbox.m_min.x )
01479   {
01480     return true;
01481   }
01482   if ( m_min.y > m_max.y || other_bbox.m_min.y > other_bbox.m_max.y 
01483        || m_min.y > other_bbox.m_max.y 
01484        || m_max.y < other_bbox.m_min.y )
01485   {
01486     return true;
01487   }
01488   if ( m_min.z > m_max.z || other_bbox.m_min.z > other_bbox.m_max.z 
01489        || m_min.z > other_bbox.m_max.z 
01490        || m_max.z < other_bbox.m_min.z )
01491   {
01492     return true;
01493   }
01494   return false;
01495 }
01496 
01497 bool ON_BoundingBox::Intersection(
01498           const ON_BoundingBox& a
01499           )
01500 {
01501   if ( IsValid() && a.IsValid() ) {
01502     if ( a.m_min.x > m_min.x )
01503       m_min.x = a.m_min.x;
01504     if ( a.m_min.y > m_min.y )
01505       m_min.y = a.m_min.y;
01506     if ( a.m_min.z > m_min.z )
01507       m_min.z = a.m_min.z;
01508     if ( a.m_max.x < m_max.x )
01509       m_max.x = a.m_max.x;
01510     if ( a.m_max.y < m_max.y )
01511       m_max.y = a.m_max.y;
01512     if ( a.m_max.z < m_max.z )
01513       m_max.z = a.m_max.z;
01514   }
01515   else {
01516     Destroy();
01517   }
01518   return IsValid();
01519 }
01520 
01521 bool ON_BoundingBox::Intersection(                              //Returns true when intersect is non-empty. 
01522                                  const ON_Line& line,           //Infinite Line segment to intersect with 
01523                                  double* t0 ,                   // t0  parameter of first intersection point
01524                                  double* t1       // t1  parameter of last intersection point (t0<=t1)   
01525                                  ) const
01526 {                
01527         ON_Interval t(-ON_DBL_MAX, ON_DBL_MAX), ti, Li;
01528   const double* boxmin = &m_min.x;
01529   const double* boxmax = &m_max.x;
01530   const double* from   = &line.from.x;
01531   const double* to     = &line.to.x;
01532         for(int i=0; i<3; i++)
01533   {
01534                 if( from[i] == to[i] )
01535     {
01536                         if( from[i] < boxmin[i] || from[i] > boxmax[i] )
01537                                 return false;
01538                 } 
01539     else 
01540     {
01541       Li.m_t[0] = from[i];
01542       Li.m_t[1] = to[i];
01543                         ti.m_t[0] = Li.NormalizedParameterAt( boxmin[i]); 
01544                         ti.m_t[1] = Li.NormalizedParameterAt( boxmax[i]);
01545                         if ( !t.Intersection(ti) )
01546         return false;
01547                 }
01548         }       
01549 
01550         if(t0)
01551                 *t0 = t.Min();
01552         if(t1)
01553                 *t1 = t.Max();
01554         return true;
01555 }                
01556 
01557 bool ON_BoundingBox::Union(
01558           const ON_BoundingBox& a
01559           )
01560 {
01561   if ( IsValid() ) {
01562     if ( a.IsValid() ) {
01563       if ( a.m_min.x < m_min.x )
01564         m_min.x = a.m_min.x;
01565       if ( a.m_min.y < m_min.y )
01566         m_min.y = a.m_min.y;
01567       if ( a.m_min.z < m_min.z )
01568         m_min.z = a.m_min.z;
01569       if ( a.m_max.x > m_max.x )
01570         m_max.x = a.m_max.x;
01571       if ( a.m_max.y > m_max.y )
01572         m_max.y = a.m_max.y;
01573       if ( a.m_max.z > m_max.z )
01574         m_max.z = a.m_max.z;
01575     }
01576   }
01577   else if ( a.IsValid() ) {
01578     *this = a;
01579   }
01580   else {
01581     Destroy();
01582   }
01583   return IsValid();
01584 }
01585 
01586 bool ON_BoundingBox::Intersection(
01587           const ON_BoundingBox& a,
01588           const ON_BoundingBox& b
01589           )
01590 {
01591   if ( a.IsValid() && b.IsValid() ) {
01592     m_min.x = (a.m_min.x >= b.m_min.x) ? a.m_min.x : b.m_min.x;
01593     m_min.y = (a.m_min.y >= b.m_min.y) ? a.m_min.y : b.m_min.y;
01594     m_min.z = (a.m_min.z >= b.m_min.z) ? a.m_min.z : b.m_min.z;
01595     m_max.x = (a.m_max.x <= b.m_max.x) ? a.m_max.x : b.m_max.x;
01596     m_max.y = (a.m_max.y <= b.m_max.y) ? a.m_max.y : b.m_max.y;
01597     m_max.z = (a.m_max.z <= b.m_max.z) ? a.m_max.z : b.m_max.z;
01598   }
01599   else {
01600     Destroy();
01601   }
01602   return IsValid();
01603 }
01604 
01605 bool ON_BoundingBox::Includes( 
01606     const ON_BoundingBox& other,
01607     bool bProperSubSet) const
01608 {
01609         bool rc = true;
01610         bool proper = false;
01611         for(int i=0; i<3 && rc ; i++)
01612   {
01613                 ON_Interval thisI( m_min[i], m_max[i]);
01614                 ON_Interval otherI( other.m_min[i], other.m_max[i]);
01615                 rc = thisI.Includes( otherI );
01616                 if(bProperSubSet && !proper)
01617     {
01618                         proper = (other.m_min[i] > m_min[i]) || (other.m_max[i] < m_max[i]);
01619     }
01620         }
01621   // 9 December 2004 Dale Lear
01622   //    fixed bug by changing if(proper) to if(bProperSubSet)
01623         if(bProperSubSet)
01624                 rc = rc && proper;
01625         return rc;
01626 }
01627 
01628 
01629 bool ON_BoundingBox::Union(
01630           const ON_BoundingBox& a,
01631           const ON_BoundingBox& b
01632           )
01633 {
01634   if ( a.IsValid() ) {
01635     if ( b.IsValid() ) {
01636       m_min.x = (a.m_min.x <= b.m_min.x) ? a.m_min.x : b.m_min.x;
01637       m_min.y = (a.m_min.y <= b.m_min.y) ? a.m_min.y : b.m_min.y;
01638       m_min.z = (a.m_min.z <= b.m_min.z) ? a.m_min.z : b.m_min.z;
01639       m_max.x = (a.m_max.x >= b.m_max.x) ? a.m_max.x : b.m_max.x;
01640       m_max.y = (a.m_max.y >= b.m_max.y) ? a.m_max.y : b.m_max.y;
01641       m_max.z = (a.m_max.z >= b.m_max.z) ? a.m_max.z : b.m_max.z;
01642     }
01643     else {
01644       *this = a;
01645     }
01646   }
01647   else if ( b.IsValid() ) {
01648     *this = b;
01649   }
01650   else {
01651     Destroy();
01652   }
01653   return IsValid();
01654 }
01655 
01656 double ON_BoundingBox::Volume() const
01657 {
01658   double dx = m_max.x - m_min.x;
01659   double dy = m_max.y - m_min.y;
01660   double dz = m_max.z - m_min.z;
01661   return (dx > 0.0 && dy > 0.0 && dz > 0.0) ? dx*dy*dz : 0.0;
01662 }
01663 
01664 double ON_BoundingBox::Area() const
01665 {
01666   double dx = m_max.x - m_min.x;
01667   double dy = m_max.y - m_min.y;
01668   double dz = m_max.z - m_min.z;
01669   return (dx >= 0.0 && dy >= 0.0 && dz >= 0.0) ? 2.0*(dx*dy + dy*dz + dz*dx) : 0.0;
01670 }
01671 
01672 bool ON_BoundingBox::Set(     
01673     int dim, int is_rat, int count, int stride, 
01674     const double* points, 
01675     int bGrowBox
01676   )
01677 {
01678   return ON_GetPointListBoundingBox(dim, is_rat, count, stride, points, *this, bGrowBox!=0, 0 );
01679 }
01680 
01681 bool ON_BoundingBox::Set ( const ON_3dPoint& P, int bGrowBox )
01682 {
01683   if ( !bGrowBox || !IsValid() )
01684   {
01685     m_min = P;
01686     m_max = P;    
01687   }
01688   else
01689   {
01690     if ( P.x < m_min.x ) m_min.x = P.x; else if ( m_max.x < P.x ) m_max.x = P.x;
01691     if ( P.y < m_min.y ) m_min.y = P.y; else if ( m_max.y < P.y ) m_max.y = P.y;
01692     if ( P.z < m_min.z ) m_min.z = P.z; else if ( m_max.z < P.z ) m_max.z = P.z;
01693   }
01694   return true;
01695 }
01696 
01697 
01698 bool ON_BoundingBox::Set( const ON_SimpleArray<ON_4dPoint>& a, int bGrowBox )
01699 {
01700   const int count = a.Count();
01701   const double* p = (count>0) ? &a.Array()->x : 0;
01702   return ON_GetPointListBoundingBox(3, 1, count, 4, p, *this, bGrowBox!=0, 0 );
01703 }
01704 
01705 bool ON_BoundingBox::Set( const ON_SimpleArray<ON_3dPoint>& a, int bGrowBox )
01706 {
01707   const int count = a.Count();
01708   const double* p = (count>0) ? &a.Array()->x : 0;
01709   return ON_GetPointListBoundingBox(3, 0, count, 3, p, *this, bGrowBox!=0, 0 );
01710 }
01711 
01712 bool ON_BoundingBox::Set( const ON_SimpleArray<ON_2dPoint>& a, int bGrowBox )
01713 {
01714   const int count = a.Count();
01715   const double* p = (count>0) ? &a.Array()->x : 0;
01716   return ON_GetPointListBoundingBox(2, 0, count, 2, p, *this, bGrowBox!=0, 0 );
01717 }
01718 
01719 ON_BoundingBox ON_PointListBoundingBox(
01720     int dim, int is_rat, int count, int stride, const double* points
01721     )
01722 {
01723   ON_BoundingBox bbox;
01724   ON_GetPointListBoundingBox( dim, is_rat, count, stride, points, bbox, false, 0 );
01725   return bbox;
01726 }
01727 
01728 bool ON_GetPointListBoundingBox( 
01729     int dim, int is_rat, int count, int stride, const double* points, 
01730     ON_BoundingBox& tight_bbox,
01731     int bGrowBox,
01732     const ON_Xform* xform
01733     )
01734 {
01735   // bounding box workhorse
01736   bool rc = false;
01737   if ( bGrowBox && !tight_bbox.IsValid() )
01738   {
01739     bGrowBox = false;
01740   }
01741   if ( !bGrowBox )
01742   {
01743     tight_bbox.Destroy();
01744   }
01745   if ( is_rat )
01746   {
01747     is_rat = 1;
01748   }
01749 
01750   if ( count > 0 && dim > 0 && points && (count == 1 || stride >= dim+is_rat) ) 
01751   {
01752     ON_BoundingBox bbox;
01753     ON_3dPoint P(0.0,0.0,0.0);
01754     double w;
01755     int i, wi;
01756 
01757     if ( xform && xform->IsIdentity() )
01758     {
01759       xform = 0;
01760     }
01761     wi = dim;
01762     if ( dim > 3 )
01763     {
01764       dim = 3;
01765     }
01766 
01767     rc = true;
01768     if ( is_rat ) 
01769     {
01770       // skip bogus starting points
01771       while ( count > 0 && points[wi] == 0.0 ) 
01772       {
01773         count--;
01774         points += stride;
01775         rc = false;
01776       }
01777       if ( count <= 0 )
01778         return false;
01779     }
01780 
01781     memcpy( &bbox.m_min.x, points, dim*sizeof(bbox.m_min.x) );
01782     if ( is_rat )
01783     {
01784       w = 1.0/points[wi];
01785       bbox.m_min.x *= w; bbox.m_min.y *= w; bbox.m_min.z *= w;
01786     }
01787     if ( xform )
01788     {
01789       bbox.m_min.Transform(*xform);
01790     }
01791     bbox.m_max = bbox.m_min;
01792     points += stride;
01793     count--;
01794 
01795     if ( count > 0 ) 
01796     {
01797       if ( is_rat )
01798       {
01799         // homogeneous rational points
01800         if ( xform )
01801         {
01802           for ( /*empty*/; count--; points += stride ) 
01803           {
01804             if ( 0.0 == (w = points[wi]) ) 
01805             {
01806               rc = false;
01807               continue;
01808             }
01809             memcpy( &P.x, points, dim*sizeof(P.x) );
01810             w = 1.0/w;
01811             P.x *= w; P.y *= w; P.z *= w;
01812             P.Transform(*xform);
01813             if ( bbox.m_min.x > P.x ) bbox.m_min.x = P.x; else if ( bbox.m_max.x < P.x ) bbox.m_max.x = P.x;
01814             if ( bbox.m_min.y > P.y ) bbox.m_min.y = P.y; else if ( bbox.m_max.y < P.y ) bbox.m_max.y = P.y;
01815             if ( bbox.m_min.z > P.z ) bbox.m_min.z = P.z; else if ( bbox.m_max.z < P.z ) bbox.m_max.z = P.z;
01816           }
01817           if ( dim < 3 )
01818           {
01819             for ( i = dim; i < 3; i++)
01820             {
01821               bbox.m_min[i] = 0.0;
01822               bbox.m_max[i] = 0.0;
01823             }
01824           }
01825         }
01826         else
01827         {
01828           for ( /*empty*/; count--; points += stride ) 
01829           {
01830             if ( 0.0 == (w = points[wi]) ) 
01831             {
01832               rc = false;
01833               continue;
01834             }
01835             memcpy( &P.x, points, dim*sizeof(P.x) );
01836             w = 1.0/w;
01837             P.x *= w; P.y *= w; P.z *= w;
01838             if ( bbox.m_min.x > P.x ) bbox.m_min.x = P.x; else if ( bbox.m_max.x < P.x ) bbox.m_max.x = P.x;
01839             if ( bbox.m_min.y > P.y ) bbox.m_min.y = P.y; else if ( bbox.m_max.y < P.y ) bbox.m_max.y = P.y;
01840             if ( bbox.m_min.z > P.z ) bbox.m_min.z = P.z; else if ( bbox.m_max.z < P.z ) bbox.m_max.z = P.z;
01841           }
01842         }
01843       }
01844       else 
01845       {
01846         // bounding box of non-rational points
01847         if ( xform )
01848         {
01849           for ( /*empty*/; count--; points += stride ) 
01850           {
01851             memcpy( &P.x, points, dim*sizeof(P.x) );
01852             P.Transform(*xform);
01853             if ( bbox.m_min.x > P.x ) bbox.m_min.x = P.x; else if ( bbox.m_max.x < P.x ) bbox.m_max.x = P.x;
01854             if ( bbox.m_min.y > P.y ) bbox.m_min.y = P.y; else if ( bbox.m_max.y < P.y ) bbox.m_max.y = P.y;
01855             if ( bbox.m_min.z > P.z ) bbox.m_min.z = P.z; else if ( bbox.m_max.z < P.z ) bbox.m_max.z = P.z;
01856           }
01857           if ( dim < 3 )
01858           {
01859             for ( i = dim; i < 3; i++)
01860             {
01861               bbox.m_min[i] = 0.0;
01862               bbox.m_max[i] = 0.0;
01863             }
01864           }
01865         }
01866         else
01867         {
01868           for ( /*empty*/; count--; points += stride ) 
01869           {
01870             memcpy( &P.x, points, dim*sizeof(P.x) );
01871             if ( bbox.m_min.x > P.x ) bbox.m_min.x = P.x; else if ( bbox.m_max.x < P.x ) bbox.m_max.x = P.x;
01872             if ( bbox.m_min.y > P.y ) bbox.m_min.y = P.y; else if ( bbox.m_max.y < P.y ) bbox.m_max.y = P.y;
01873             if ( bbox.m_min.z > P.z ) bbox.m_min.z = P.z; else if ( bbox.m_max.z < P.z ) bbox.m_max.z = P.z;
01874           }
01875         }
01876       }
01877     }
01878 
01879     tight_bbox.Union(bbox);
01880   }
01881   else if ( bGrowBox ) 
01882   {
01883     // result is still valid if no points are added to a valid input box
01884     rc = (0 == count);
01885   }
01886 
01887   return rc;
01888 }
01889 
01890 bool ON_GetPointListBoundingBox( 
01891     int dim, int is_rat, int count, int stride, const float* points, 
01892     ON_BoundingBox& tight_bbox,
01893     int bGrowBox,
01894     const ON_Xform* xform
01895     )
01896 {
01897   // bounding box workhorse
01898   ON_BoundingBox bbox;
01899   ON_3dPoint P(0.0,0.0,0.0);
01900   ON_3fPoint Q(0.0,0.0,0.0);
01901   double w;
01902   int i, wi;
01903   bool rc = false;
01904   if ( bGrowBox && !tight_bbox.IsValid() )
01905   {
01906     bGrowBox = false;
01907   }
01908   if ( !bGrowBox )
01909   {
01910     tight_bbox.Destroy();
01911   }
01912   if ( is_rat )
01913   {
01914     is_rat = 1;
01915   }
01916 
01917   if ( count > 0 && dim > 0 && points && (count == 1 || stride >= dim+is_rat) ) 
01918   {
01919     if ( xform && xform->IsIdentity() )
01920     {
01921       xform = 0;
01922     }
01923     wi = dim;
01924     if ( dim > 3 )
01925     {
01926       dim = 3;
01927     }
01928 
01929     rc = true;
01930     if ( is_rat ) 
01931     {
01932       // skip bogus starting points
01933       while ( count > 0 && points[wi] == 0.0f ) 
01934       {
01935         count--;
01936         points += stride;
01937         rc = false;
01938       }
01939       if ( count <= 0 )
01940         return false;
01941     }
01942 
01943     if ( !bGrowBox  )
01944     {
01945       memcpy( &Q.x, points, dim*sizeof(Q.x) );
01946       bbox.m_min = Q;
01947       if ( is_rat )
01948       {
01949         w = 1.0/points[wi];
01950         bbox.m_min.x *= w; bbox.m_min.y *= w; bbox.m_min.z *= w;
01951       }
01952       if ( xform )
01953       {
01954         bbox.m_min.Transform(*xform);
01955       }
01956       bbox.m_max = bbox.m_min;
01957       points += stride;
01958       count--;
01959       bGrowBox = true;
01960     }
01961 
01962     if ( count > 0 ) 
01963     {
01964       if ( is_rat )
01965       {
01966         // homogeneous rational points
01967         if ( xform )
01968         {
01969           for ( /*empty*/; count--; points += stride ) 
01970           {
01971             if ( 0.0 == (w = points[wi]) ) 
01972             {
01973               rc = false;
01974               continue;
01975             }
01976             memcpy( &Q.x, points, dim*sizeof(Q.x) );
01977             w = 1.0/w;
01978             P.x = w*Q.x; P.y = w*Q.y; P.z = w*Q.z;
01979             P.Transform(*xform);
01980             if ( bbox.m_min.x > P.x ) bbox.m_min.x = P.x; else if ( bbox.m_max.x < P.x ) bbox.m_max.x = P.x;
01981             if ( bbox.m_min.y > P.y ) bbox.m_min.y = P.y; else if ( bbox.m_max.y < P.y ) bbox.m_max.y = P.y;
01982             if ( bbox.m_min.z > P.z ) bbox.m_min.z = P.z; else if ( bbox.m_max.z < P.z ) bbox.m_max.z = P.z;
01983           }
01984           if ( dim < 3 )
01985           {
01986             for ( i = dim; i < 3; i++)
01987             {
01988               bbox.m_min[i] = 0.0;
01989               bbox.m_max[i] = 0.0;
01990             }
01991           }
01992         }
01993         else
01994         {
01995           for ( /*empty*/; count--; points += stride ) 
01996           {
01997             if ( 0.0 == (w = points[wi]) ) 
01998             {
01999               rc = false;
02000               continue;
02001             }
02002             memcpy( &Q.x, points, dim*sizeof(Q.x) );
02003             w = 1.0/w;
02004             P.x = w*Q.x; P.y = w*Q.y; P.z = w*Q.z;
02005             if ( bbox.m_min.x > P.x ) bbox.m_min.x = P.x; else if ( bbox.m_max.x < P.x ) bbox.m_max.x = P.x;
02006             if ( bbox.m_min.y > P.y ) bbox.m_min.y = P.y; else if ( bbox.m_max.y < P.y ) bbox.m_max.y = P.y;
02007             if ( bbox.m_min.z > P.z ) bbox.m_min.z = P.z; else if ( bbox.m_max.z < P.z ) bbox.m_max.z = P.z;
02008           }
02009         }
02010       }
02011       else 
02012       {
02013         // bounding box of non-rational points
02014         if ( xform )
02015         {
02016           for ( /*empty*/; count--; points += stride ) 
02017           {
02018             memcpy( &Q.x, points, dim*sizeof(Q.x) );
02019             P.x = Q.x; P.y = Q.y; P.z = Q.z;
02020             P.Transform(*xform);
02021             if ( bbox.m_min.x > P.x ) bbox.m_min.x = P.x; else if ( bbox.m_max.x < P.x ) bbox.m_max.x = P.x;
02022             if ( bbox.m_min.y > P.y ) bbox.m_min.y = P.y; else if ( bbox.m_max.y < P.y ) bbox.m_max.y = P.y;
02023             if ( bbox.m_min.z > P.z ) bbox.m_min.z = P.z; else if ( bbox.m_max.z < P.z ) bbox.m_max.z = P.z;
02024           }
02025           if ( dim < 3 )
02026           {
02027             for ( i = dim; i < 3; i++)
02028             {
02029               bbox.m_min[i] = 0.0;
02030               bbox.m_max[i] = 0.0;
02031             }
02032           }
02033         }
02034         else
02035         {
02036           for ( /*empty*/; count--; points += stride ) 
02037           {
02038             memcpy( &Q.x, points, dim*sizeof(Q.x) );
02039             P.x = Q.x; P.y = Q.y; P.z = Q.z;
02040             if ( bbox.m_min.x > P.x ) bbox.m_min.x = P.x; else if ( bbox.m_max.x < P.x ) bbox.m_max.x = P.x;
02041             if ( bbox.m_min.y > P.y ) bbox.m_min.y = P.y; else if ( bbox.m_max.y < P.y ) bbox.m_max.y = P.y;
02042             if ( bbox.m_min.z > P.z ) bbox.m_min.z = P.z; else if ( bbox.m_max.z < P.z ) bbox.m_max.z = P.z;
02043           }
02044         }
02045       }
02046     }
02047 
02048     tight_bbox.Union(bbox);
02049   }
02050   else if ( bGrowBox ) 
02051   {
02052     // result is still valid if no points are added to a valid input box
02053     rc = (0 == count);
02054   }
02055 
02056   return rc;
02057 }
02058 
02059 
02060 bool ON_GetPointListBoundingBox( 
02061     int dim, int is_rat, int count, int stride, const double* points, 
02062     double* boxmin, double* boxmax,
02063     int bGrowBox
02064     )
02065 /*****************************************************************************
02066 Bounding Box of a set of points
02067  
02068 INPUT:
02069   dim           ( >= 1 ) dimension of each point
02070   is_rat        ( true if points are rational )
02071   count         ( >= 1 ) number of points
02072   stride        ( >= (is_rat)?(dim+1):dim )
02073   points        array of dim*count doubles
02074   boxmin, boxmax      unused arrays of dim doubles
02075   bGrowBox       true if input box should be enlarged to contain points
02076                                                                                 boxmin[i]>boxmax[i] for some i, represents an empty initial box
02077                  false if input box should be ignored bounding box of points
02078                        is returned
02079 OUTPUT:
02080   boxmin, boxmax      diagonal corners of bounding box
02081 *****************************************************************************/
02082 {
02083   // OBSOLETE
02084   // bounding box workhorse
02085   double x, w;
02086   int j;
02087   bool rc = false;
02088   for ( j = 0; j < dim && bGrowBox; j++ )
02089   {
02090     if ( boxmin[j] > boxmax[j] )
02091       bGrowBox = false;
02092   }
02093 
02094   if ( count > 0 ) 
02095   {
02096     if ( is_rat )
02097     {
02098       is_rat = 1;
02099     }
02100     if ( points && dim > 0 && (count == 1 || stride >= dim+is_rat) ) 
02101     {
02102       // input is valid list of a least 1 point
02103 
02104       if ( is_rat ) 
02105       {
02106         // bounding box of homogeneous rational points
02107         rc = true;
02108         while ( count > 0 && points[dim] == 0.0 ) 
02109         {
02110           count--;
02111           points += stride;
02112           rc = false;
02113         }
02114         if ( count > 0 ) 
02115         {
02116           if ( !bGrowBox  )
02117           {
02118             ON_ArrayScale( dim, 1.0/points[dim], points, boxmin );
02119             memcpy( boxmax, boxmin, dim*sizeof(*boxmax) );
02120             points += stride;
02121             count--;
02122             bGrowBox = true;
02123           }
02124           if ( count > 0 ) 
02125           {
02126             for ( /*empty*/; count--; points += stride ) 
02127             {
02128               if ( points[dim] == 0.0 ) {
02129                 rc = false;
02130                 continue;
02131               }
02132               w = 1.0/points[dim];
02133               for ( j = 0; j < dim; j++ ) 
02134               {
02135                 x = w*points[j];
02136                 if (boxmin[j] > x) 
02137                   boxmin[j] = x; 
02138                 else if (boxmax[j] < x) 
02139                   boxmax[j] = x;
02140               }
02141             }
02142           }
02143         }
02144       }
02145       else 
02146       {
02147         // bounding box of non-rational points
02148         rc = true;
02149         if ( !bGrowBox ) 
02150         {
02151           // use first point to initialize box 
02152           memcpy( boxmin, points, dim*sizeof(*boxmin) );
02153           memcpy( boxmax, boxmin, dim*sizeof(*boxmax) );
02154           points += stride;
02155           count--;
02156           bGrowBox = true;
02157         }
02158         if ( count ) 
02159         {
02160           // grow box to contain the rest of the points
02161           for ( /*empty*/; count--; points += stride ) 
02162           {
02163             for ( j = 0; j < dim; j++ ) 
02164             {
02165               x = points[j];
02166               if (boxmin[j] > x) 
02167                 boxmin[j] = x; 
02168               else if (boxmax[j] < x) 
02169                 boxmax[j] = x;
02170             }
02171           }
02172         }
02173       }
02174     }
02175   }
02176   else if ( bGrowBox ) 
02177   {
02178     // result is still valid if no points are added to a valid input box
02179     rc = true;
02180   }
02181   return rc;
02182 }
02183 
02184 
02185 ON_BoundingBox ON_PointListBoundingBox(
02186     int dim, int is_rat, int count, int stride, const float* points
02187     )
02188 {
02189   ON_BoundingBox bbox;
02190   ON_GetPointListBoundingBox( dim, is_rat, count, stride, points, bbox, false, 0 );
02191   return bbox;
02192 }
02193 
02194 
02195 bool ON_GetPointListBoundingBox( 
02196     int dim, int is_rat, int count, int stride, const float* points, 
02197     float* boxmin, float* boxmax,
02198     int bGrowBox
02199     )
02200 /*****************************************************************************
02201 Bounding Box of a set of points
02202  
02203 INPUT:
02204   dim           ( >= 1 ) dimension of each point
02205   is_rat        ( true if points are rational )
02206   count         ( >= 1 ) number of points
02207   stride        ( >= (is_rat)?(dim+1):dim )
02208   points        array of dim*count floats
02209   boxmin, boxmax      unused arrays of dim floats
02210   bGrowBox       true if input box should be enlarged to contain points
02211                  false if input box should be ignored bounding box of points
02212                        is returned
02213 OUTPUT:
02214   boxmin, boxmax      diagonal corners of bounding box
02215 *****************************************************************************/
02216 {
02217   // OBSOLETE
02218   // bounding box workhorse
02219   float x;
02220   double w;
02221   int j;
02222   bool rc = false;
02223   for ( j = 0; j < dim && bGrowBox; j++ )
02224   {
02225     if ( boxmin[j] > boxmax[j] )
02226       bGrowBox = false;
02227   }
02228   if ( count > 0 ) 
02229   {
02230     if ( is_rat )
02231       is_rat = 1;
02232     if ( points && dim > 0 && (count == 1 || stride >= dim+is_rat) ) 
02233     {
02234       if ( is_rat ) {
02235         rc = true;
02236         while ( count > 0 && points[dim] == 0.0 ) {
02237           count--;
02238           points += stride;
02239           rc = false;
02240         }
02241         if ( count > 0 ) {
02242           if ( !bGrowBox ) 
02243           {
02244             ON_ArrayScale( dim, 1.0f/points[dim], points, boxmin );
02245             memcpy( boxmax, boxmin, dim*sizeof(*boxmax) );
02246             points += stride;
02247             count--;
02248             bGrowBox = true;
02249           }
02250           for ( /*empty*/; count--; points += stride ) 
02251           {
02252             if ( points[dim] == 0.0 )
02253               continue;
02254             w = 1.0/points[dim];
02255             for ( j = 0; j < dim; j++ ) {
02256               x = (float)(w*points[j]);
02257               if (boxmin[j] > x) 
02258                 boxmin[j] = x; 
02259               else if (boxmax[j] < x) 
02260                 boxmax[j] = x;
02261             }
02262           }
02263         }
02264       }
02265       else
02266       {
02267         rc = true;
02268         if ( !bGrowBox ) {
02269           memcpy( boxmin, points, dim*sizeof(*boxmin) );
02270           memcpy( boxmax, boxmin, dim*sizeof(*boxmax) );
02271           points += stride;
02272           count--;
02273           bGrowBox = true;
02274         }
02275         for ( /*empty*/; count--; points += stride ) 
02276         {
02277           for ( j = 0; j < dim; j++ ) {
02278             x = points[j];
02279             if (boxmin[j] > x) 
02280               boxmin[j] = x; 
02281             else if (boxmax[j] < x) 
02282               boxmax[j] = x;
02283           }
02284         }
02285       }
02286     }
02287   }
02288   else if ( bGrowBox ) 
02289   {
02290     rc = true;
02291   }
02292   return rc;
02293 }
02294 
02295 
02296 ON_BoundingBox ON_PointGridBoundingBox(
02297         int dim,
02298         ON_BOOL32 is_rat,
02299         int point_count0, int point_count1,
02300         int point_stride0, int point_stride1,
02301         const double* p
02302     )
02303 {
02304   ON_BoundingBox bbox;
02305   if ( dim > 3 )
02306   {
02307     // strides control stepping - no need to waste time on coordinates we don't return
02308     dim = 3;
02309   }
02310   ON_GetPointGridBoundingBox( dim, is_rat, 
02311                               point_count0, point_count1, 
02312                               point_stride0, point_stride1, p, 
02313                               &bbox.m_min.x, &bbox.m_max.x, false );
02314   return bbox;
02315 }
02316 
02317 
02318 bool ON_GetPointGridBoundingBox(
02319         int dim,
02320         int is_rat,
02321         int point_count0, int point_count1,
02322         int point_stride0, int point_stride1,
02323         const double* p,
02324         double* boxmin, double* boxmax,
02325         int bGrowBox
02326         )
02327 {
02328   int i;
02329   for ( i = 0; i < dim && bGrowBox; i++ )
02330   {
02331     if ( boxmin[i] > boxmax[i] )
02332       bGrowBox = false;
02333   }
02334   bool rc = bGrowBox ? true : false;
02335   for ( i = 0; i < point_count0; i++ ) 
02336   {
02337     if ( !ON_GetPointListBoundingBox( dim, is_rat, point_count1, point_stride1, p + i*point_stride0, boxmin, boxmax, bGrowBox ) ) {
02338       rc = false;
02339       break;
02340     }
02341     else 
02342     {
02343       bGrowBox = true;
02344       if (!i)
02345         rc = true;
02346     }
02347   }
02348   return rc;
02349 }
02350 
02351 bool ON_BeyondSinglePrecision( const ON_BoundingBox& bbox, ON_Xform* xform )
02352 {
02353   bool rc = false;
02354 
02355   if ( bbox.IsValid() )
02356   {
02357     // 31 March 2011:
02358     //   The values of too_far = 262144.0 and too_big = 1048576.0
02359     //   are first guesses.  If you changes these values,
02360     //   you must append a comment containing your name,
02361     //   the date, the values your are using, a bug number
02362     //   of a bug report containing a file that demonstrates
02363     //   why you changed the number.  You must retest all 
02364     //   previous bugs before committing your changes.
02365     //
02366     //   DATE: 31 March 2011
02367     //   NAME: Dale Lear
02368     //   COMMENT: First guess at values for too_far and too
02369     //   VALUES:  too_far = 262144.0 from tests with simple mesh sphere
02370     //            too_big = 1048576.0
02371     //   BUG: http://dev.mcneel.com/bugtrack/?q=83437
02372     const double too_far = 262144.0;  // should be a power of 2
02373     const double too_big = 1048576.0; // MUST be a power of 2
02374     bool bTooFar = (    bbox.m_min.x >=  too_far 
02375                      || bbox.m_min.y >=  too_far 
02376                      || bbox.m_min.x >=  too_far 
02377                      || bbox.m_max.x <= -too_far
02378                      || bbox.m_max.y <= -too_far
02379                      || bbox.m_max.x <= -too_far
02380                    );
02381     bool bTooBig = (   bbox.m_min.x <= -too_big 
02382                      || bbox.m_min.y <= -too_big 
02383                      || bbox.m_min.x <= -too_big 
02384                      || bbox.m_max.x >=  too_big
02385                      || bbox.m_max.y >=  too_big
02386                      || bbox.m_max.x >=  too_big
02387                      );
02388     if ( bTooFar || bTooBig )
02389     {
02390       rc = true;
02391       if ( 0 != xform )
02392       {
02393         ON_3dVector C = bbox.Center();
02394         // Any modification of coordinates contributes to 
02395         // less precision in calculations.  These tests 
02396         // remove small components of translations that 
02397         // do not help matters and may add more fuzz to 
02398         // calculations.
02399         if ( fabs(C.x) <= 100.0 )
02400           C.x = 0.0;
02401         if ( fabs(C.y) <= 100.0 )
02402           C.y = 0.0;
02403         if ( fabs(C.z) <= 100.0 )
02404           C.z = 0.0;
02405         double r = 0.5*bbox.m_max.DistanceTo(bbox.m_min);
02406         // T = translate center of bbox to origin
02407         ON_Xform T;
02408         T.Translation(-C);
02409 
02410         // S = scale to shrink things that are too big 
02411         //     to have a maximum coordinate of 1024.
02412         //     The scale is a power of 2 to preserve as much 
02413         //     precision as possible.
02414         double s = 1.0;
02415         if ( r > too_big/16.0 )
02416         {
02417           // also apply a power of 2 scale to shrink large 
02418           // object so its coordinates are <= 1024.0
02419           s = too_big;
02420           while ( r > s*1024.0 )
02421             s *= 2.0;
02422           s = 1.0/s;
02423         }
02424         ON_Xform S(s);
02425 
02426         // xform positions bbox in a region of space
02427         // where single precision coordinates should
02428         // work for most calculations.
02429         *xform = S*T;
02430       }
02431     }
02432   }
02433 
02434   if (!rc && 0 != xform )
02435     xform->Identity();
02436 
02437   return rc;
02438 }
02439 
02440 
02441 double ON_BoundingBoxTolerance(
02442         int dim,
02443         const double* bboxmin,
02444         const double* bboxmax
02445         )
02446 {
02447   int i;
02448   double x, tolerance=0.0;
02449 
02450 #if defined(ON_COMPILER_MSC)
02451 #pragma warning( push )
02452 // Disable the MSC /W4 "conditional expression is constant" warning
02453 // generated by the do {...} while(0) in the ON_ASSERT_OR_RETURN macro.
02454 #pragma warning( disable : 4127 )
02455 #endif
02456 
02457   ON_ASSERT_OR_RETURN( dim > 0 && bboxmin != NULL && bboxmax != NULL,tolerance);
02458   for ( i = 0; i < dim; i++ ) {
02459     ON_ASSERT_OR_RETURN(bboxmin[i] <= bboxmax[i],tolerance);
02460   }
02461 
02462 #if defined(ON_COMPILER_MSC)
02463 #pragma warning( pop )
02464 #endif
02465 
02466   tolerance = ON_ArrayDistance(dim,bboxmin,bboxmax)*ON_EPSILON;
02467   for ( i = 0; i < dim; i++ ) {
02468     x = (bboxmax[i] - bboxmin[i])*ON_SQRT_EPSILON;
02469     if ( x > tolerance )
02470       tolerance = x;
02471     x = (fabs(bboxmax[i]) - fabs(bboxmin[i]))*ON_EPSILON;
02472     if ( x > tolerance )
02473       tolerance = x;
02474   }
02475   if ( tolerance > 0.0 && tolerance < ON_ZERO_TOLERANCE )
02476     tolerance = ON_ZERO_TOLERANCE;
02477   return tolerance;
02478 }
02479 
02480 int ON_BoundingBox::IsDegenerate( double tolerance ) const
02481 {
02482   ON_3dVector diag = Diagonal();
02483   if ( tolerance < 0.0 )
02484   {
02485     // compute scale invarient tolerance
02486     tolerance = diag.MaximumCoordinate()*ON_SQRT_EPSILON;
02487   }
02488   int rc = 0;
02489   if ( diag.x < 0.0 )
02490     return 4;
02491   if ( diag.x <=  tolerance )
02492     rc++;
02493   if ( diag.y < 0.0 )
02494     return 4;
02495   if ( diag.y <=  tolerance )
02496     rc++;
02497   if ( diag.z < 0.0 )
02498     return 4;
02499   if ( diag.z <=  tolerance )
02500     rc++;
02501   return rc;
02502 }
02503 
02504 double ON_BoundingBox::MinimumDistanceTo( const ON_3dPoint& P ) const
02505 {
02506   // 8 Feb 2005 - new function - not tested yet
02507 
02508   // this function must be fast
02509   // If Q = any point in box, then
02510   // P.DistanceTo(Q) >= MinimumDistanceTo(P).
02511   ON_3dVector V;
02512 
02513   if ( P.x < m_min.x )
02514     V.x = m_min.x - P.x;
02515   else if ( P.x > m_max.x )
02516     V.x = P.x - m_max.x;
02517   else
02518     V.x = 0.0;
02519 
02520   if ( P.y < m_min.y )
02521     V.y = m_min.y - P.y;
02522   else if ( P.y > m_max.y )
02523     V.y = P.y - m_max.y;
02524   else
02525     V.y = 0.0;
02526 
02527   if ( P.z < m_min.z )
02528     V.z = m_min.z - P.z;
02529   else if ( P.z > m_max.z )
02530     V.z = P.z - m_max.z;
02531   else
02532     V.z = 0.0;
02533 
02534   return V.Length();
02535 }
02536 
02537 double ON_BoundingBox::MaximumDistanceTo( const ON_3dPoint& P ) const
02538 {
02539   // this function must be fast
02540   // If Q = any point in box, then
02541   // P.DistanceTo(Q) <= MaximumDistanceTo(P).
02542   ON_3dVector V;
02543 
02544   V.x = ( (P.x < 0.5*(m_min.x+m_max.x)) ? m_max.x : m_min.x) - P.x;
02545   V.y = ( (P.y < 0.5*(m_min.y+m_max.y)) ? m_max.y : m_min.y) - P.y;
02546   V.z = ( (P.z < 0.5*(m_min.z+m_max.z)) ? m_max.z : m_min.z) - P.z;
02547 
02548   return V.Length();
02549 }
02550 
02551 static double ON_BBoxMinimumDistanceToHelper( const ON_BoundingBox& bbox, ON_Line line )
02552 {
02553   // 8 Feb 2005 - new function - not tested yet
02554 
02555   // this function must be fast
02556 
02557   // returns 0.0 if the line intersects the box and 
02558   // returns != 0.0 if the line does not intersect 
02559   //   returns d > 0.0 if the line misses the box and the minimum dist is >= d.
02560   //   returns ON_UNSET_VALUE if the line misses the box but the minimum distance
02561   //   is not easily bounded away from zero.
02562 
02563 
02564   double d, t;
02565   bool bTrimmed;
02566 
02567 
02568   // quick check for line.from inside box
02569   if ( bbox.m_min.x <= line.from.x && line.from.x <= bbox.m_max.x )
02570   {
02571     if ( bbox.m_min.y <= line.from.y && line.from.y <= bbox.m_max.y )
02572     {
02573       if ( bbox.m_min.z <= line.from.z && line.from.z <= bbox.m_max.z )
02574       {
02575         return 0.0;
02576       }
02577     }
02578   }
02579    
02580   // quick check for line.to inside box
02581   if ( bbox.m_min.x <= line.to.x && line.to.x <= bbox.m_max.x )
02582   {
02583     if ( bbox.m_min.y <= line.to.y && line.to.y <= bbox.m_max.y )
02584     {
02585       if ( bbox.m_min.z <= line.to.z && line.to.z <= bbox.m_max.z )
02586       {
02587         return 0.0;
02588       }
02589     }
02590   }
02591 
02592   ON_BoundingBox line_bbox;
02593   line_bbox.Set(3,false,2,3,&line.from.x,false);
02594 
02595   d = bbox.MinimumDistanceTo(line_bbox);
02596   if ( d > 0.0 )
02597     return d;
02598 
02599   if ( bbox.m_min.x <= line_bbox.m_min.x && line_bbox.m_max.x <= bbox.m_max.x )
02600   {
02601     if ( bbox.m_min.y <= line_bbox.m_min.y && line_bbox.m_max.y <= bbox.m_max.y )
02602     {
02603       // The fact that MinimumDistanceTo(line_bbox) == 0.0 implies
02604       // that the z-extents of the line intersects this bounding box.
02605       return 0.0;
02606     }
02607     else if ( bbox.m_min.z <= line_bbox.m_min.z && line_bbox.m_max.z <= bbox.m_max.z )
02608     {
02609       // The fact that MinimumDistanceTo(line_bbox) == 0.0 implies
02610       // that the y-extents of the line intersects this bounding box.
02611       return 0.0;
02612     }
02613   }
02614   else if ( bbox.m_min.y <= line_bbox.m_min.y && line_bbox.m_max.y <= bbox.m_max.y 
02615             && bbox.m_min.z <= line_bbox.m_min.z && line_bbox.m_max.z <= bbox.m_max.z )
02616   {
02617     // The fact that MinimumDistanceTo(line_bbox) == 0.0 implies
02618     // that the x-extents of the line intersects this bounding box.
02619     return 0.0;
02620   }
02621 
02622   d = line.to.x - line.from.x;
02623   bTrimmed = false;
02624   if ( d != 0.0 )
02625   {
02626     if ( d < 0.0 )
02627     {
02628       line.Reverse();
02629       d = -d;
02630     }
02631     d = 1.0/d;
02632     t = (bbox.m_min.x - line.from.x)*d;
02633     if( 0.0 < t && t < 1.0 )
02634     {
02635       line.from = line.PointAt(t);
02636       line.from.x = bbox.m_min.x;
02637       d = line.to.x - line.from.x;
02638       if ( d != 0.0 )
02639         d = 1.0/d;
02640       bTrimmed = true;
02641     }
02642     t = (bbox.m_max.x - line.from.x)*d;
02643     if( 0.0 < t && t < 1.0 )
02644     {
02645       line.to = line.PointAt(t);
02646       line.to.x = bbox.m_max.x;
02647       bTrimmed = true;
02648     }
02649   }
02650 
02651   d = line.to.y - line.from.y;
02652   if ( d < 0.0 )
02653   {
02654     line.Reverse();
02655     d = -d;
02656   }
02657 
02658   if ( bTrimmed )
02659   {
02660     if ( line.to.y < bbox.m_min.y || line.from.y > bbox.m_max.y )
02661       return ON_UNSET_VALUE;
02662     if ( line.from.z < bbox.m_min.z && line.to.z < bbox.m_min.z )
02663       return ON_UNSET_VALUE;
02664     if ( line.from.z > bbox.m_max.z && line.to.z > bbox.m_max.z )
02665       return ON_UNSET_VALUE;
02666   }
02667 
02668   if ( d > 0.0 )
02669   {
02670     d = 1.0/d;
02671     t = (bbox.m_min.y - line.from.y)*d;
02672     if( 0.0 < t && t < 1.0 )
02673     {
02674       line.from = line.PointAt(t);
02675       line.from.y = bbox.m_min.y;
02676       d = line.to.y - line.from.y;
02677       if ( d != 0.0 )
02678         d = 1.0/d;
02679     }
02680     t = (bbox.m_max.y - line.from.y)*d;
02681     if( 0.0 < t && t < 1.0 )
02682     {
02683       line.to = line.PointAt(t);
02684       line.to.y = bbox.m_max.y;
02685     }
02686   }
02687 
02688   if ( line.from.z < bbox.m_min.z && line.to.z < bbox.m_min.z )
02689     return ON_UNSET_VALUE;
02690 
02691   if ( line.from.z > bbox.m_max.z && line.to.z > bbox.m_max.z )
02692     return ON_UNSET_VALUE;
02693 
02694   return 0.0; // some portion of the line hits the box
02695 }
02696 
02697 double ON_BoundingBox::MinimumDistanceTo( const ON_Plane& plane ) const
02698 {
02699   ON_PlaneEquation e;
02700   e.Create(plane.origin,plane.zaxis);
02701   return MinimumDistanceTo(e);
02702 }
02703 
02704 double ON_BoundingBox::MinimumDistanceTo( const ON_PlaneEquation& e ) const
02705 {
02706   double t, t0, t1;
02707   ON_3dPoint P(m_min); // min, min, min
02708   t0 = t1 = e.ValueAt(P);
02709   
02710   P.z = m_max.z; // min, min, max
02711   t = e.ValueAt(P); 
02712   if (t < t0) 
02713   {
02714     t0 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02715   }
02716   else if (t > t1) 
02717   {
02718     t1 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02719   }
02720   
02721   P.y = m_max.y; // min, max, max
02722   t = e.ValueAt(P); 
02723   if (t < t0) 
02724   {
02725     t0 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02726   }
02727   else if (t > t1) 
02728   {
02729     t1 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02730   }
02731   
02732   P.z = m_min.z; // min, max, min
02733   t = e.ValueAt(P); 
02734   if (t < t0) 
02735   {
02736     t0 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02737   }
02738   else if (t > t1) 
02739   {
02740     t1 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02741   }
02742 
02743   P.x = m_max.x; // max, max, min
02744   t = e.ValueAt(P); 
02745   if (t < t0) 
02746   {
02747     t0 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02748   }
02749   else if (t > t1) 
02750   {
02751     t1 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02752   }
02753 
02754   P.y = m_min.y; // max, min, min
02755   t = e.ValueAt(P); 
02756   if (t < t0) 
02757   {
02758     t0 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02759   }
02760   else if (t > t1) 
02761   {
02762     t1 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02763   }
02764 
02765   P.z = m_max.z; // max, min, max
02766   t = e.ValueAt(P); 
02767   if (t < t0) 
02768   {
02769     t0 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02770   }
02771   else if (t > t1) 
02772   {
02773     t1 = t;  if ( t0 <= 0.0 && t1 >= 0.0 ) return 0.0;
02774   }
02775 
02776   P.y = m_max.y; // max, max, max
02777   t = e.ValueAt(P); 
02778   if (t < t0) 
02779   {
02780     t0 = t;
02781   }
02782   else if (t > t1) 
02783   {
02784     t1 = t;
02785   }
02786 
02787   if ( t0 >= 0.0 ) return t0;
02788   if ( t1 <= 0.0 ) return -t1;
02789   return 0.0;
02790 }
02791 
02792 
02793 double ON_BoundingBox::MaximumDistanceTo( const ON_Plane& plane ) const
02794 {
02795   ON_PlaneEquation e;
02796   e.Create(plane.origin,plane.zaxis);
02797   return MinimumDistanceTo(e);
02798 }
02799 
02800 double ON_BoundingBox::MaximumDistanceTo( const ON_PlaneEquation& e ) const
02801 {
02802   double t, t0;
02803   ON_3dPoint P(m_min); // min, min, min
02804   t0 = fabs(e.ValueAt(P));
02805   
02806   P.z = m_max.z; // min, min, max
02807   t = fabs(e.ValueAt(P));  if (t > t0) t0 = t;
02808   
02809   P.y = m_max.y; // min, max, max
02810   t = fabs(e.ValueAt(P));  if (t > t0) t0 = t;
02811   
02812   P.z = m_min.z; // min, max, min
02813   t = fabs(e.ValueAt(P));  if (t > t0) t0 = t;
02814 
02815   P.x = m_max.x; // max, max, min
02816   t = fabs(e.ValueAt(P));  if (t > t0) t0 = t;
02817 
02818   P.y = m_min.y; // max, min, min
02819   t = fabs(e.ValueAt(P));  if (t > t0) t0 = t;
02820 
02821   P.z = m_max.z; // max, min, max
02822   t = fabs(e.ValueAt(P));  if (t > t0) t0 = t;
02823 
02824   P.y = m_max.y; // max, max, max
02825   t = fabs(e.ValueAt(P));  if (t > t0) t0 = t;
02826 
02827   return t0;
02828 }
02829 
02830 
02831 bool ON_BoundingBox::IsFartherThan( double d, const ON_Plane& plane ) const
02832 {
02833   ON_PlaneEquation e;
02834   e.Create(plane.origin,plane.zaxis);
02835   return IsFartherThan(d,e);
02836 }
02837 
02838 bool ON_BoundingBox::IsFartherThan( double d, const ON_PlaneEquation& e ) const
02839 {
02840   double t, t0, t1;
02841   ON_3dPoint P(m_min); // min, min, min
02842   t0 = t1 = e.ValueAt(P);
02843   if ( t0 <= d && t1 >= -d ) return false;
02844   
02845   P.z = m_max.z; // min, min, max
02846   t = e.ValueAt(P); 
02847   if (t < t0) 
02848   {
02849     t0 = t; if ( t0 <= d && t1 >= -d ) return false;
02850   }
02851   else if (t > t1) 
02852   {
02853     t1 = t; if ( t0 <= d && t1 >= -d ) return false;
02854   }
02855   
02856   P.y = m_max.y; // min, max, max
02857   t = e.ValueAt(P); 
02858   if (t < t0) 
02859   {
02860     t0 = t; if ( t0 <= d && t1 >= -d ) return false;
02861   }
02862   else if (t > t1) 
02863   {
02864     t1 = t; if ( t0 <= d && t1 >= -d ) return false;
02865   }
02866   
02867   P.z = m_min.z; // min, max, min
02868   t = e.ValueAt(P); 
02869   if (t < t0) 
02870   {
02871     t0 = t; if ( t0 <= d && t1 >= -d ) return false;
02872   }
02873   else if (t > t1) 
02874   {
02875     t1 = t; if ( t0 <= d && t1 >= -d ) return false;
02876   }
02877 
02878   P.x = m_max.x; // max, max, min
02879   t = e.ValueAt(P); 
02880   if (t < t0) 
02881   {
02882     t0 = t; if ( t0 <= d && t1 >= -d ) return false;
02883   }
02884   else if (t > t1) 
02885   {
02886     t1 = t; if ( t0 <= d && t1 >= -d ) return false;
02887   }
02888 
02889   P.y = m_min.y; // max, min, min
02890   t = e.ValueAt(P); 
02891   if (t < t0) 
02892   {
02893     t0 = t; if ( t0 <= d && t1 >= -d ) return false;
02894   }
02895   else if (t > t1) 
02896   {
02897     t1 = t; if ( t0 <= d && t1 >= -d ) return false;
02898   }
02899 
02900   P.z = m_max.z; // max, min, max
02901   if (t < t0) 
02902   {
02903     t0 = t; if ( t0 <= d && t1 >= -d ) return false;
02904   }
02905   else if (t > t1) 
02906   {
02907     t1 = t; if ( t0 <= d && t1 >= -d ) return false;
02908   }
02909 
02910   P.y = m_max.y; // max, max, max
02911   if (t < t0) 
02912   {
02913     t0 = t; if ( t0 <= d && t1 >= -d ) return false;
02914   }
02915   else if (t > t1) 
02916   {
02917     t1 = t; if ( t0 <= d && t1 >= -d ) return false;
02918   }
02919 
02920   return true;
02921 }
02922 
02923 
02924 double ON_BoundingBox::MinimumDistanceTo( const ON_Line& line ) const
02925 {
02926   double d = ON_BBoxMinimumDistanceToHelper( *this, line );
02927   if ( d < 0.0 )
02928   {
02929     // At this point we know the line does not intersect the box.
02930     // To get a lower bound on the shortest distance between the
02931     // line and the box, we need to compare the line to the
02932     // edges of the box.
02933 
02934     const ON_BoundingBox line_bbox(line.BoundingBox());
02935     ON_Line edge;
02936     double e,t;
02937     int i,j;
02938 
02939     edge.from.z = m_min.z;
02940     edge.to.z = m_max.z;
02941     for ( i = 0; i < 2; i++ )
02942     {    
02943       edge.from.x = i?m_min.x:m_max.x;
02944       if ( d > 0.0 )
02945       {
02946         if ( line_bbox.m_min.x - edge.from.x > d )
02947           continue;
02948         if ( edge.from.x - line_bbox.m_max.x > d )
02949           continue;
02950       }
02951       edge.to.x = edge.from.x;
02952       for ( j = 0; j < 2; j++ )
02953       {
02954         edge.from.y = j?m_min.y:m_max.y;
02955         if ( d > 0.0 )
02956         {
02957           if ( line_bbox.m_min.y - edge.from.y > d )
02958             continue;
02959           if ( edge.from.y - line_bbox.m_max.y > d )
02960             continue;
02961         }
02962         edge.to.y = edge.from.y;
02963         if ( ON_Intersect(edge,line,&e,&t) )
02964         {
02965           if ( e < 0.0 ) e = 0.0; else if (e > 1.0) e = 1.0;
02966           if ( t < 0.0 ) t = 0.0; else if (t > 1.0) t = 1.0;
02967           e = edge.PointAt(e).DistanceTo(line.PointAt(t));
02968           if ( d < 0.0 || e < d )
02969             d = e;
02970         }
02971       }
02972     }
02973 
02974     edge.from.y = m_min.y;
02975     edge.to.y = m_max.y;
02976     for ( i = 0; i < 2; i++ )
02977     {    
02978       edge.from.z = i?m_min.z:m_max.z;
02979       edge.to.z = edge.from.z;
02980       if ( d > 0.0 )
02981       {
02982         if ( line_bbox.m_min.z - edge.from.z > d )
02983           continue;
02984         if ( edge.from.z - line_bbox.m_max.z > d )
02985           continue;
02986       }
02987       for ( j = 0; j < 2; j++ )
02988       {
02989         edge.from.x = j?m_min.x:m_max.x;
02990         if ( d > 0.0 )
02991         {
02992           if ( line_bbox.m_min.x - edge.from.x > d )
02993             continue;
02994           if ( edge.from.x - line_bbox.m_max.x > d )
02995             continue;
02996         }
02997         edge.to.x = edge.from.x;
02998         if ( ON_Intersect(edge,line,&e,&t) )
02999         {
03000           if ( e < 0.0 ) e = 0.0; else if (e > 1.0) e = 1.0;
03001           if ( t < 0.0 ) t = 0.0; else if (t > 1.0) t = 1.0;
03002           e = edge.PointAt(e).DistanceTo(line.PointAt(t));
03003           if ( d < 0.0 || e < d )
03004             d = e;
03005         }
03006       }
03007     }
03008 
03009     edge.from.x = m_min.x;
03010     edge.to.x = m_max.x;
03011     for ( i = 0; i < 2; i++ )
03012     {    
03013       edge.from.y = i?m_min.y:m_max.y;
03014       edge.to.y = edge.from.y;
03015       if ( d > 0.0 )
03016       {
03017         if ( line_bbox.m_min.y - edge.from.y > d )
03018           continue;
03019         if ( edge.from.y - line_bbox.m_max.y > d )
03020           continue;
03021       }
03022       for ( j = 0; j < 2; j++ )
03023       {
03024         edge.from.z = j?m_min.z:m_max.z;
03025         edge.to.z = edge.from.z;
03026         if ( d > 0.0 )
03027         {
03028           if ( line_bbox.m_min.z - edge.from.z > d )
03029             continue;
03030           if ( edge.from.z - line_bbox.m_max.z > d )
03031             continue;
03032         }
03033         if ( ON_Intersect(edge,line,&e,&t) )
03034         {
03035           if ( e < 0.0 ) e = 0.0; else if (e > 1.0) e = 1.0;
03036           if ( t < 0.0 ) t = 0.0; else if (t > 1.0) t = 1.0;
03037           e = edge.PointAt(e).DistanceTo(line.PointAt(t));
03038           if ( d < 0.0 || e < d )
03039             d = e;
03040         }
03041       }
03042     }
03043 
03044     if ( d < 0.0 )
03045       d = 0.0;
03046 
03047   }
03048 
03049   return d;
03050 }
03051 
03052 double ON_BoundingBox::MaximumDistanceTo( const ON_Line& line ) const
03053 {
03054   // 8 Feb 2005 - new function - not tested yet
03055 
03056   // this function must be fast
03057   // If Q = any point on the line and 
03058   // P = any point in box, then
03059   // P.DistanceTo(Q) <= MaximumDistanceTo(line).
03060 
03061   double d,dx,dy,dz;
03062   const double* a;
03063   int i,j,k;
03064 
03065   d = 0.0;
03066   a = &line.from.x;
03067   for ( i = 0; i < 2; i++ )
03068   {
03069     dx = fabs(a[0] - (i?m_max.x:m_min.x));
03070     dx = dx*dx;
03071     if ( dx <= d )
03072       continue;
03073     for ( j = 0; j < 2; j++ )
03074     {
03075       dy = fabs(a[1] - (j?m_max.y:m_min.y));
03076       dy = dx + dy*dy;
03077       if ( dy <= d )
03078         continue;
03079       for ( k = 0; k < 2; k++ )
03080       {
03081         dz = fabs(a[2] - (k?m_max.z:m_min.z));          
03082         dz = dz*dz + dy;
03083         if ( dz > d )
03084           d = dz;
03085       }
03086     }
03087   }
03088 
03089   a = &line.to.x;
03090   for ( i = 0; i < 2; i++ )
03091   {
03092     dx = fabs(a[0] - (i?m_max.x:m_min.x));
03093     dx = dx*dx;
03094     if ( dx <= d )
03095       continue;
03096     for ( j = 0; j < 2; j++ )
03097     {
03098       dy = fabs(a[1] - (j?m_max.y:m_min.y));
03099       dy = dx + dy*dy;
03100       if ( dy <= d )
03101         continue;
03102       for ( k = 0; k < 2; k++ )
03103       {
03104         dz = fabs(a[2] - (k?m_max.z:m_min.z));          
03105         dz = dz*dz + dy;
03106         if ( dz > d )
03107           d = dz;
03108       }
03109     }
03110   }
03111 
03112   return sqrt(d);
03113 }
03114 
03115 double ON_BoundingBox::MinimumDistanceTo( const ON_BoundingBox& other ) const
03116 {
03117   // this must be fast
03118   ON_3dVector V;
03119 
03120   if ( m_min.x > other.m_max.x )
03121     V.x = m_min.x - other.m_max.x;
03122   else if ( m_max.x < other.m_min.x )
03123     V.x = other.m_min.x - m_max.x;
03124   else
03125     V.x = 0.0;
03126 
03127   if ( m_min.y > other.m_max.y )
03128     V.y = m_min.y - other.m_max.y;
03129   else if ( m_max.y < other.m_min.y )
03130     V.y = other.m_min.y - m_max.y;
03131   else
03132     V.y = 0.0;
03133 
03134   if ( m_min.z > other.m_max.z )
03135     V.z = m_min.z - other.m_max.z;
03136   else if ( m_max.z < other.m_min.z )
03137     V.z = other.m_min.z - m_max.z;
03138   else
03139     V.z = 0.0;
03140 
03141   return V.Length();
03142 }
03143 
03144 
03145 double ON_BoundingBox::MaximumDistanceTo( const ON_BoundingBox& other ) const
03146 {
03147   // this must be fast
03148   ON_3dVector V;
03149   double d;
03150 
03151   V.x = fabs(m_min.x - other.m_max.x);
03152   d = fabs(m_max.x - other.m_min.x);
03153   if ( d > V.x )
03154     V.x = d;
03155 
03156   V.y = fabs(m_min.y - other.m_max.y);
03157   d = fabs(m_max.y - other.m_min.y);
03158   if ( d > V.y )
03159     V.y = d;
03160 
03161   V.z = fabs(m_min.z - other.m_max.z);
03162   d = fabs(m_max.z - other.m_min.z);
03163   if ( d > V.z )
03164     V.z = d;
03165 
03166   return V.Length();
03167 }
03168 
03169 
03170 bool ON_BoundingBox::IsFartherThan( double d, const ON_3dPoint& P ) const
03171 {
03172   return (d < MinimumDistanceTo(P));
03173 }
03174 
03175 bool ON_BoundingBox::IsFartherThan( double d, const ON_Line& line ) const
03176 {
03177   ON_BoundingBox bbox = *this;
03178   bbox.m_min.x -= d;
03179   bbox.m_min.y -= d;
03180   bbox.m_min.z -= d;
03181   bbox.m_max.x += d;
03182   bbox.m_max.y += d;
03183   bbox.m_max.z += d;
03184   d = ON_BBoxMinimumDistanceToHelper( bbox, line );
03185   // d != 0.0 if and only if line misses the enlarged box
03186   return (d != 0.0);
03187 }
03188 
03189 bool ON_BoundingBox::IsFartherThan( double d, const ON_BoundingBox& other ) const
03190 {
03191   return (d < MinimumDistanceTo(other));
03192 }
03193 
03194 
03195 


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:27:00