opennurbs_revsurface.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_OBJECT_IMPLEMENT( ON_RevSurface, ON_Surface, "A16220D3-163B-11d4-8000-0010830122F0");
00020 
00021 
00022 void ON_RevSurface::DestroyRuntimeCache( bool bDelete )
00023 {
00024   ON_Surface::DestroyRuntimeCache(bDelete);
00025   if ( 0 != m_curve )
00026     m_curve->DestroyRuntimeCache(bDelete);
00027   // 15 August 2003 Dale Lear
00028   //    Added the call to destroy m_bbox.
00029   m_bbox.Destroy();
00030 }
00031 
00032 
00033 ON_RevSurface* ON_RevSurface::New()
00034 {
00035   return new ON_RevSurface();
00036 }
00037 
00038 ON_RevSurface* ON_RevSurface::New( const ON_RevSurface& rev_surface )
00039 {
00040   return new ON_RevSurface(rev_surface);
00041 }
00042 
00043 ON_RevSurface::ON_RevSurface() : m_curve(0), 
00044                                  m_axis( ON_origin, ON_zaxis ), 
00045                                  m_angle( 0.0, 2.0*ON_PI ),
00046                                  m_t( 0.0, 2.0*ON_PI ),
00047                                  m_bTransposed(0)
00048 {
00049   ON__SET__THIS__PTR(m_s_ON_RevSurface_ptr);
00050 }
00051 
00052 ON_RevSurface::~ON_RevSurface()
00053 {
00054   Destroy();
00055 }
00056 
00057 void ON_RevSurface::Destroy()
00058 {
00059   DestroySurfaceTree();
00060   if ( m_curve)
00061   {
00062     delete m_curve;
00063     m_curve = 0;
00064   }
00065   m_axis.Create( ON_origin, ON_zaxis );
00066   m_angle.Set(0.0,2.0*ON_PI);
00067   m_t = m_angle;
00068   m_bTransposed = false;
00069   m_bbox.Destroy();
00070 }
00071 
00072 ON_RevSurface::ON_RevSurface( const ON_RevSurface& src ) : ON_Surface(src)
00073 {
00074   ON__SET__THIS__PTR(m_s_ON_RevSurface_ptr);
00075   m_curve = src.m_curve ? src.m_curve->Duplicate() : NULL;
00076   m_axis = src.m_axis;
00077   m_angle = src.m_angle;
00078   m_t = src.m_t;
00079   m_bTransposed = src.m_bTransposed;
00080   m_bbox = src.m_bbox;
00081 }
00082 
00083 
00084 unsigned int ON_RevSurface::SizeOf() const
00085 {
00086   unsigned int sz = ON_Surface::SizeOf();
00087   if ( m_curve )
00088     sz += m_curve->SizeOf();
00089   return sz;
00090 }
00091 
00092 ON__UINT32 ON_RevSurface::DataCRC(ON__UINT32 current_remainder) const
00093 {
00094   if ( m_curve )
00095     current_remainder = m_curve->DataCRC(current_remainder);
00096   current_remainder = ON_CRC32(current_remainder,sizeof(m_axis),&m_axis);
00097   current_remainder = ON_CRC32(current_remainder,sizeof(m_angle),&m_angle);
00098   current_remainder = ON_CRC32(current_remainder,sizeof(m_t),&m_t);
00099   current_remainder = ON_CRC32(current_remainder,sizeof(m_bTransposed),&m_bTransposed);
00100   return current_remainder;
00101 }
00102 
00103 
00104 ON_RevSurface& ON_RevSurface::operator=( const ON_RevSurface& src )
00105 {
00106   if ( this != &src ) 
00107   {
00108     Destroy();
00109     ON_Surface::operator=(src);
00110     if ( src.m_curve ) 
00111       m_curve = src.m_curve->Duplicate();
00112     m_axis = src.m_axis;
00113     m_angle = src.m_angle;
00114     m_t = src.m_t;
00115     m_bTransposed = src.m_bTransposed;
00116     m_bbox = src.m_bbox;
00117   }
00118   return *this;
00119 }
00120 
00121 
00122 ON_BOOL32 ON_RevSurface::SetAngleRadians(
00123   double start_angle_radians,
00124   double end_angle_radians
00125   )
00126 {
00127   bool rc = false;
00128   double d = end_angle_radians-start_angle_radians;
00129   if ( d >= 0.0 )
00130   {
00131     if ( d <= ON_ZERO_TOLERANCE || d > 2.0*ON_PI )
00132     {
00133       end_angle_radians = start_angle_radians + 2.0*ON_PI;
00134     }
00135     m_angle.Set( start_angle_radians, end_angle_radians );
00136     rc = true;
00137     DestroySurfaceTree();
00138   }
00139   return rc;
00140 }
00141 
00142 
00143 ON_BOOL32 ON_RevSurface::SetAngleDegrees (
00144   double start_angle_degrees,
00145   double end_angle_degrees
00146   )
00147 {
00148   return SetAngleRadians( 
00149     start_angle_degrees*ON_PI/180.0, 
00150     end_angle_degrees*ON_PI/180.0 
00151     );
00152 }
00153 
00154 
00155 ON_BOOL32 ON_RevSurface::IsValid( ON_TextLog* text_log ) const
00156 {
00157   if ( !m_curve )
00158   {
00159     if ( text_log )
00160       text_log->Print( "ON_RevSurface.m_curve is NULL.\n");
00161     return false;
00162   }
00163   if ( !m_curve->IsValid(text_log) )
00164   {
00165     if ( text_log )
00166       text_log->Print( "ON_RevSurface.m_curve is not valid.\n");
00167     return false;
00168   }
00169   int dim = m_curve->Dimension();
00170   if ( dim != 3 )
00171   {
00172     if ( text_log )
00173       text_log->Print( "ON_RevSurface.m_curve->Dimension()=%d (should be 3).\n",dim);
00174     return false;
00175   }
00176   if ( !m_axis.IsValid() )
00177   {
00178     if ( text_log )
00179       text_log->Print( "ON_RevSurface.m_axis is not valid.\n");
00180     return false;
00181   }
00182   if ( !m_angle.IsIncreasing() )
00183   {
00184     if ( text_log )
00185       text_log->Print( "ON_RevSurface.m_angle = (%g,%g) (should be an increasing interval)\n",
00186                        m_angle[0],m_angle[1]);
00187     return false;
00188   }
00189   double length = m_angle.Length();
00190   if ( length > 2.0*ON_PI + ON_ZERO_TOLERANCE )
00191   {
00192     if ( text_log )
00193       text_log->Print( "ON_RevSurface.m_angle.Length() = %g (should be <= 2*pi radians).\n",length);
00194     return false;
00195   }
00196   if ( m_angle.Length() <= ON_ZERO_TOLERANCE )
00197   {
00198     if ( text_log )
00199       text_log->Print( "ON_RevSurface.m_angle.Length() = %g (should be > ON_ZERO_TOLERANCE).\n",length);
00200     return false;
00201   }
00202   if ( !m_t.IsIncreasing() )
00203   {
00204     if ( text_log )
00205       text_log->Print( "ON_RevSurface.m_t = (%g,%g) (should be an increasing interval)\n",
00206                        m_t[0],m_t[1]);
00207     return false;
00208   }
00209   return true;
00210 }
00211 
00212 void ON_RevSurface::Dump( ON_TextLog& dump ) const
00213 {
00214   ON_Object::Dump(dump); // print class id
00215   dump.PushIndent();
00216   if ( m_bTransposed )
00217     dump.Print("Paramerization: (curve,angle)\n");
00218   else
00219     dump.Print("Paramerization: (angle,curve)\n");
00220   dump.Print("Axis: ");
00221   dump.Print(m_axis.from);
00222   dump.Print(" to ");
00223   dump.Print(m_axis.to);
00224   dump.Print("\n");
00225   dump.Print("Rotation angle: %g to %g radians.\n",m_angle[0],m_angle[1]);
00226   dump.Print("Angle evaluation parameter interval: [%g,%g].\n",m_t[0],m_t[1]);
00227   if ( m_curve ) {
00228     dump.Print("Revolute: \n");
00229     dump.PushIndent();
00230     m_curve->Dump(dump);
00231     dump.PopIndent();
00232   }  
00233 }
00234 
00235 ON_BOOL32 ON_RevSurface::Write( ON_BinaryArchive& file ) const
00236 {
00237   ON_BOOL32 rc = file.Write3dmChunkVersion(2,0);
00238   if (rc) 
00239   {
00240     rc = file.WriteLine( m_axis );
00241     rc = file.WriteInterval( m_angle );
00242     rc = file.WriteInterval( m_t );
00243     rc = file.WriteBoundingBox( m_bbox );
00244     rc = file.WriteInt( m_bTransposed );
00245     if ( m_curve ) 
00246     {
00247       rc = file.WriteChar((char)1);
00248       if (rc) rc = file.WriteObject(*m_curve);
00249     }
00250     else 
00251     {
00252       rc = file.WriteChar((char)0);
00253     }
00254   }
00255   return rc;
00256 }
00257 
00258 
00259 ON_BOOL32 ON_RevSurface::Read( ON_BinaryArchive& file )
00260 {
00261   int major_version = 0;
00262   int minor_version = 0;
00263   char bHaveCurve = 0;
00264   ON_BOOL32 rc = file.Read3dmChunkVersion(&major_version,&minor_version);
00265   if (rc && major_version == 1) 
00266   {
00267     rc = file.ReadLine( m_axis );
00268     rc = file.ReadInterval( m_angle );
00269     rc = file.ReadBoundingBox( m_bbox );
00270     rc = file.ReadInt( &m_bTransposed );
00271     rc = file.ReadChar( &bHaveCurve );
00272     if ( bHaveCurve ) 
00273     {
00274       ON_Object* obj = 0;
00275       rc = file.ReadObject(&obj);
00276       if ( obj ) 
00277       {
00278         m_curve = ON_Curve::Cast(obj);
00279         if ( !m_curve )
00280           delete obj;
00281       }
00282     }
00283     m_t[0] = m_angle.Min();
00284     m_t[1] = m_angle.Max();
00285   }
00286   else if (rc && major_version == 2) 
00287   {
00288     rc = file.ReadLine( m_axis );
00289     rc = file.ReadInterval( m_angle );
00290     rc = file.ReadInterval( m_t );
00291     rc = file.ReadBoundingBox( m_bbox );
00292     rc = file.ReadInt( &m_bTransposed );
00293     rc = file.ReadChar( &bHaveCurve );
00294     if ( bHaveCurve ) 
00295     {
00296       ON_Object* obj = 0;
00297       rc = file.ReadObject(&obj);
00298       if ( obj ) 
00299       {
00300         m_curve = ON_Curve::Cast(obj);
00301         if ( !m_curve )
00302           delete obj;
00303       }
00304     }
00305   }
00306   return rc;
00307 }
00308 
00309 int ON_RevSurface::Dimension() const
00310 {
00311   return 3;
00312 }
00313 
00314 ON_BOOL32 ON_RevSurface::Transform( const ON_Xform& xform )
00315 {
00316   DestroyRuntimeCache();
00317   TransformUserData(xform);
00318   ON_BOOL32 rc = (m_curve) ? m_curve->Transform(xform) : false;
00319   ON_3dVector X, Y, Z;
00320   Z = m_axis.Tangent();
00321   X.PerpendicularTo( Z );
00322   X.Unitize();
00323   Y = ON_CrossProduct( Z, X );
00324   if ( !m_axis.Transform(xform) )
00325     rc = false;
00326   ON_3dVector transZ = m_axis.Tangent();
00327 
00328   if ( transZ.Length() == 0.0 )
00329   {
00330     // transformation collapsed axis
00331     m_axis.to = m_axis.from + Z;
00332   }
00333   else
00334   {
00335     // see if axis needs to be reversed.
00336     // (Happens with transformations that
00337     // have negative determinant - like mirroring.)
00338     ON_3dVector transX = xform*X;
00339     ON_3dVector transY = xform*Y;
00340     ON_3dVector transXxY = ON_CrossProduct( transX, transY );
00341     double d = transXxY*transZ;
00342     if ( d < 0.0 )
00343       m_axis.to = m_axis.from - m_axis.Direction();
00344   }
00345 
00346   m_bbox.Destroy();
00347   m_bbox = BoundingBox();
00348   return rc;
00349 }
00350 
00351 ON_BOOL32 ON_RevSurface::Evaluate( // returns false if unable to evaluate
00352        double s, // angle
00353        double t, // curve_parameter
00354        // evaluation parameters
00355        int der_count,            // number of derivatives (>=0)
00356        int v_stride,            // array stride (>=Dimension())
00357        double* v,        // array of length stride*(ndir+1)*(ndir+2)/2
00358        int side,        // optional - determines which quadrant to evaluate from
00359                        //         0 = default
00360                        //         1 from NE quadrant
00361                        //         2 from NW quadrant
00362                        //         3 from SW quadrant
00363                        //         4 from SE quadrant
00364        int* hint       // optional - evaluation hint (int[2]) used to speed
00365                        //            repeated evaluations
00366        ) const
00367 {
00368   bool rc = false;
00369 
00370   double ds = 1.0;
00371   double x,y,z;
00372   int i, j, k, src_i, dst_i;
00373   ON_3dPoint pt;
00374 
00375   if ( m_bTransposed ) 
00376   {
00377     x = s; s = t; t = x;
00378     if ( side == 2 ) side = 4; else if ( side == 4 ) side = 2;
00379   }
00380   
00381   if ( m_t != m_angle )
00382   {
00383     if ( m_t.m_t[1] != m_t.m_t[0] )
00384     {
00385       ds = (m_angle.m_t[1] - m_angle.m_t[0])/(m_t.m_t[1] - m_t.m_t[0]);
00386       x = m_t.NormalizedParameterAt(s);
00387       y = m_angle.ParameterAt(x);
00388       s = y;
00389     }
00390   }
00391 
00392   
00393   double a = cos(s);
00394   double b = sin(s);
00395   const double ca[4] = {a, -b, -a,  b}; // cosine derivatives
00396   const double sa[4] = {b,  a, -b, -a}; // sine derivatives
00397 
00398   const int curve_dim = m_curve ? m_curve->Dimension() : 0;
00399   if ( curve_dim == 2 || curve_dim == 3 ) 
00400   {
00401     int curve_side = 0;
00402     switch(side) 
00403     {
00404     case 1:
00405     case 2:
00406       curve_side = 1;
00407       break;
00408     case 3:
00409     case 4:
00410       curve_side = -1;
00411       break;
00412     }
00413     rc = m_curve->Evaluate( t, der_count, v_stride, v, curve_side, hint )?true:false;
00414     if ( rc ) 
00415     {
00416       ON_3dVector zaxis = m_axis.Tangent();
00417       ON_3dVector xaxis, yaxis;
00418       xaxis.PerpendicularTo(zaxis);
00419       xaxis.Unitize();
00420       yaxis = ON_CrossProduct(zaxis,xaxis);
00421 
00422       // move curve derivatives to pure t partial spaces in v[]
00423       if ( curve_dim == 2 ) 
00424       {
00425         for ( i = der_count; i >= 1; i-- ) 
00426         {
00427           // move curve derivative to proper spots
00428           src_i = v_stride*i;
00429           dst_i = v_stride*((i+1)*(i+2)/2 - 1);
00430           v[dst_i++] = v[src_i++];
00431           v[dst_i++] = 0.0;
00432           v[dst_i]   = v[src_i];
00433         }
00434       }
00435       else 
00436       {
00437         for ( i = der_count; i >= 1; i-- ) 
00438         {
00439           // move curve derivative to proper spots
00440           src_i = v_stride*i;
00441           dst_i = v_stride*((i+1)*(i+2)/2 - 1);
00442           v[dst_i++] = v[src_i++];
00443           v[dst_i++] = v[src_i++];
00444           v[dst_i]   = v[src_i];
00445         }
00446       }
00447 
00448       // convert location coordinates to local frame with origin at m_axis.from
00449       {
00450         pt = ON_3dPoint(v)-m_axis.from;
00451         v[0] = pt*xaxis;
00452         v[1] = pt*yaxis;
00453         v[2] = pt*zaxis;
00454       }
00455 
00456       // convert curve derivative coordinates to local frame
00457       for ( i = 1; i <= der_count; i++ ) 
00458       {
00459         dst_i = v_stride*((i+1)*(i+2)/2 - 1);
00460         pt = ON_3dPoint(v+dst_i); // pt = curve derivative in world coords
00461         v[dst_i++] = pt*xaxis;
00462         v[dst_i++] = pt*yaxis;
00463         v[dst_i]   = pt*zaxis;
00464       }
00465 
00466       for ( i = der_count; i >= 0; i-- )
00467       {
00468         // i = total order of derivative
00469         double f = 1.0; // f = chain rule scale factor
00470         for ( j = i; j >= 0; j-- )
00471         {
00472           // j = number of partials w.r.t curve parameter
00473           // i-j = number of partials w.r.t angular parameter
00474           dst_i = v_stride*(i*(i+1)/2 + j); // 
00475           src_i = v_stride*((j+1)*(j+2)/2 - 1); // curve derivative
00476           k=(i-j)%4;
00477           a = f*ca[k];
00478           b = f*sa[k];
00479           f *= ds;
00480 
00481           // calculate derivative in local frame
00482           x = a*v[src_i] - b*v[src_i+1];
00483           y = b*v[src_i] + a*v[src_i+1];
00484           z = (j<i) ? 0.0 : v[src_i+2];
00485           // store answer in world coordinates
00486           pt = x*xaxis + y*yaxis + z*zaxis;
00487           v[dst_i++] = pt.x;
00488           v[dst_i++] = pt.y;
00489           v[dst_i]   = pt.z;
00490         }
00491       }
00492 
00493       // translate location
00494       v[0] += m_axis.from.x;
00495       v[1] += m_axis.from.y;
00496       v[2] += m_axis.from.z;
00497 
00498       if ( m_bTransposed ) 
00499       {
00500         for ( i = 1; i <= der_count; i++ ) 
00501         {
00502           for ( j = 0, k = i; j < k; j++, k-- ) 
00503           {
00504             dst_i = i*(i+1)/2;
00505             src_i = dst_i + k;
00506             dst_i += j;
00507             src_i *= v_stride;
00508             dst_i *= v_stride;
00509             x = v[src_i]; v[src_i++] = v[dst_i]; v[dst_i++] = x;
00510             x = v[src_i]; v[src_i++] = v[dst_i]; v[dst_i++] = x;
00511             x = v[src_i]; v[src_i]   = v[dst_i]; v[dst_i]   = x;
00512           }
00513         }
00514       }
00515     }
00516   }
00517   return rc;
00518 }
00519 
00520 
00521 class ON_RevolutionTensor : public ON_TensorProduct
00522 {
00523 public:
00524   ON_3dPoint  O;
00525   ON_3dVector X;
00526   ON_3dVector Y;
00527   ON_3dVector Z;
00528   int DimensionA() const;
00529   int DimensionB() const;
00530   int DimensionC() const;
00531   bool Evaluate( double,        // a
00532                  const double*, // A
00533                  double,        // b
00534                  const double*, // B
00535                  double*        // C
00536                 );
00537 };
00538 
00539 int ON_RevolutionTensor::DimensionA() const
00540 {
00541   return 2;
00542 }
00543 
00544 int ON_RevolutionTensor::DimensionB() const
00545 {
00546   return 3;
00547 }
00548 
00549 int ON_RevolutionTensor::DimensionC() const
00550 {
00551   return 3;
00552 }
00553 
00554 bool ON_RevolutionTensor::Evaluate( double a, const double* ArcPoint, double b, const double* ShapePoint, double* SrfPoint )
00555 {
00556         double x, y, z, c, s, rx, ry, A[2], B[3];
00557 
00558         if (a != 1.0) {
00559                 A[0] = a*ArcPoint[0];
00560                 A[1] = a*ArcPoint[1];
00561                 ArcPoint = A;
00562         }
00563 
00564         if (b != 1.0) {
00565                 B[0] = b*ShapePoint[0];
00566                 B[1] = b*ShapePoint[1];
00567                 B[2] = b*ShapePoint[2];
00568                 ShapePoint = B;
00569         }
00570         
00571 
00572         x = (ShapePoint[0] - O.x)*X.x + (ShapePoint[1] - O.y)*X.y + (ShapePoint[2] - O.z)*X.z;
00573         y = (ShapePoint[0] - O.x)*Y.x + (ShapePoint[1] - O.y)*Y.y + (ShapePoint[2] - O.z)*Y.z;
00574         z = (ShapePoint[0] - O.x)*Z.x + (ShapePoint[1] - O.y)*Z.y + (ShapePoint[2] - O.z)*Z.z;
00575 
00576         c = ArcPoint[0];
00577         s = ArcPoint[1];
00578 
00579         rx = c*x - s*y;
00580         ry = s*x + c*y;
00581 
00582         SrfPoint[0] = O.x + rx*X.x + ry*Y.x + z*Z.x;
00583         SrfPoint[1] = O.y + rx*X.y + ry*Y.y + z*Z.y;
00584         SrfPoint[2] = O.z + rx*X.z + ry*Y.z + z*Z.z;
00585 
00586         return true;
00587 }
00588 
00589 int ON_RevSurface::GetNurbForm(class ON_NurbsSurface& srf , double tolerance ) const
00590 {
00591   int rc = 0;
00592   if ( 0 != m_curve ) 
00593   {
00594     ON_NurbsCurve a, c;
00595     ON_Arc arc;
00596     arc.plane.CreateFromNormal( ON_origin, ON_zaxis );
00597     arc.radius = 1.0;
00598     arc.SetAngleRadians(m_angle[1]-m_angle[0]);
00599     if ( arc.GetNurbForm(a) ) 
00600     {
00601       if ( m_t.IsIncreasing() )
00602         a.SetDomain( m_t[0], m_t[1] );
00603       rc = m_curve->GetNurbForm(c,tolerance);
00604       if (rc) 
00605       {
00606         if ( 2 == c.m_dim )
00607         {
00608           // Increasing the dimension of a 2d curve to 3d fixes
00609           // was added to make the Scale1D operation in
00610           // bug # 103845 work.
00611           ON_WARNING("ON_RevSurface.m_curve is 2-dimensional.");
00612           c.ChangeDimension(3);
00613         }
00614         if ( 3 != c.m_dim )
00615         {
00616           ON_ERROR("ON_RevSurface.m_curve is not valid.");
00617           return 0;
00618         }
00619 
00620         if ( m_angle[0] != 0.0 )
00621         {
00622           c.Rotate( m_angle[0], m_axis.Direction(), m_axis.from );
00623         }
00624         ON_RevolutionTensor rho;
00625         rho.O = m_axis.from;
00626         rho.Z = m_axis.Direction();
00627         rho.Z.Unitize();
00628         rho.X.PerpendicularTo(rho.Z);
00629         rho.X.Unitize();
00630         rho.Y = ON_CrossProduct(rho.Z,rho.X);
00631         rho.Y.Unitize();
00632         if ( !srf.TensorProduct( a, c, rho ) )
00633         {
00634           // Testing for false here prevents crashes
00635           // when and was added as part of investigating
00636           // bug # 103845.  A change a few lines up
00637           // made it so that particular bug no longer
00638           // fails to create a nurbs surface.
00639           return 0;
00640         }
00641 
00642         // make singular points "spot on"
00643         ON_3dPoint C0 = c.PointAtStart();
00644         ON_3dPoint C1 = c.PointAtEnd();
00645         ON_3dPoint A0, A1;
00646         ON_4dPoint CV;
00647         double t0 = ON_UNSET_VALUE;
00648         double t1 = ON_UNSET_VALUE;
00649         if (m_axis.ClosestPointTo(C0,&t0) && ON_IsValid(t0) )
00650         {
00651           A0 = m_axis.PointAt(t0);
00652           if ( C0.DistanceTo(A0) <= ON_ZERO_TOLERANCE )
00653           {
00654             // SouthPole
00655             int j = 0;
00656             for ( int i = 0; i < srf.m_cv_count[0]; i++ )
00657             {
00658               CV.w = srf.Weight(i,j);
00659               CV.x = CV.w*A0.x;
00660               CV.y = CV.w*A0.y;
00661               CV.z = CV.w*A0.z;
00662               srf.SetCV(i,j,CV);
00663             }
00664           }
00665         }
00666         if (m_axis.ClosestPointTo(C1,&t1) && ON_IsValid(t1) )
00667         {
00668           A1 = m_axis.PointAt(t1);
00669           if ( C1.DistanceTo(A1) <= ON_ZERO_TOLERANCE )
00670           {
00671             // NorthPole
00672             int j = srf.m_cv_count[1]-1;
00673             for ( int i = 0; i < srf.m_cv_count[0]; i++ )
00674             {
00675               CV.w = srf.Weight(i,j);
00676               CV.x = CV.w*A1.x;
00677               CV.y = CV.w*A1.y;
00678               CV.z = CV.w*A1.z;
00679               srf.SetCV(i,j,CV);
00680             }
00681           }
00682         }
00683 
00684         if ( m_bTransposed )
00685           srf.Transpose();
00686       }
00687     }
00688   }
00689   return (rc > 0) ? 2 : 0;
00690 }
00691 
00692 int ON_RevSurface::HasNurbForm() const
00693 
00694 {
00695   if (!IsValid())
00696     return 0;
00697   return 2;
00698 }
00699 
00700 bool ON_RevSurface::GetSurfaceParameterFromNurbFormParameter(
00701       double nurbs_s, double nurbs_t,
00702       double* surface_s, double* surface_t
00703       ) const
00704 {
00705   // NOTE: overrides ON_Surface virtual function
00706   bool rc = (0 != m_curve);
00707 
00708 
00709 
00710   if ( m_bTransposed )
00711   {
00712     double* pTemp = surface_s; surface_s = surface_t; surface_t = pTemp;
00713     double temp = nurbs_s; nurbs_s = nurbs_t; nurbs_t = temp;
00714   }
00715 
00716   *surface_s = nurbs_s;
00717   *surface_t = nurbs_t;
00718 
00719   ON_Circle circle( ON_xy_plane, 1.0 );
00720   ON_Arc arc( circle, m_angle );
00721   ON_ArcCurve arc_curve(arc, m_t[0], m_t[1]);
00722   if ( !arc_curve.GetCurveParameterFromNurbFormParameter( nurbs_s, surface_s ) )
00723     rc = false;
00724 
00725   if ( m_curve )
00726   {
00727     if (!m_curve->GetCurveParameterFromNurbFormParameter( nurbs_t, surface_t ))
00728       rc = false;
00729   }
00730 
00731 
00732   return rc;
00733 }
00734 
00735 bool ON_RevSurface::GetNurbFormParameterFromSurfaceParameter(
00736       double surface_s, double surface_t,
00737       double* nurbs_s,  double* nurbs_t
00738       ) const
00739 {
00740   // NOTE: overrides ON_Surface virtual function
00741   bool rc = (0 != m_curve);
00742 
00743   if ( m_bTransposed )
00744   {
00745     double temp = surface_s; surface_s = surface_t; surface_t = temp;
00746     double* pTemp = nurbs_s; nurbs_s = nurbs_t; nurbs_t = pTemp;
00747   }
00748 
00749   *nurbs_s = surface_s;
00750   *nurbs_t = surface_t;
00751 
00752   ON_Circle circle( ON_xy_plane, 1.0 );
00753   ON_Arc arc( circle, m_angle );
00754   ON_ArcCurve arc_curve(arc, m_t[0], m_t[1]);
00755   if ( !arc_curve.GetNurbFormParameterFromCurveParameter( surface_s, nurbs_s ) )
00756     rc = false;
00757 
00758   if ( m_curve )
00759   {
00760     if (!m_curve->GetNurbFormParameterFromCurveParameter( surface_t, nurbs_t ))
00761       rc = false;
00762   }
00763 
00764   return rc;
00765 }
00766 
00767 
00768 ON_Curve* ON_RevSurface::IsoCurve( int dir, double c ) const
00769 {
00770   if ( dir < 0 || dir > 1 || !m_curve )
00771     return NULL;
00772 
00773   ON_Curve* crv = 0;
00774   
00775   if ( m_bTransposed )
00776     dir = 1-dir;
00777 
00778   if ( dir == 0 )
00779   {
00780     // 8 December 2003 Chuck - fix iso extraction bug
00781     //   when m_angle[0] != 0.
00782     ON_Circle circle;
00783     ON_3dPoint P = m_curve->PointAt(c);
00784     circle.plane.origin = m_axis.ClosestPointTo(P);
00785     circle.plane.zaxis = m_axis.Tangent();
00786     circle.plane.xaxis = P - circle.plane.origin;
00787     circle.radius = circle.plane.xaxis.Length();
00788     if ( !circle.plane.xaxis.Unitize() )
00789     {
00790       // 8 December 2003 Dale Lear - get valid zero radius
00791       //   arc/circle when revolute hits the axis.
00792       // First: try middle of revolute for x-axis
00793       P = m_curve->PointAt(m_curve->Domain().ParameterAt(0.5));
00794       ON_3dPoint Q = m_axis.ClosestPointTo(P);
00795       circle.plane.xaxis = P-Q;
00796       if ( !circle.plane.xaxis.Unitize() )
00797       {
00798         // Then: just use a vector perp to zaxis
00799         circle.plane.xaxis.PerpendicularTo(circle.plane.zaxis);
00800       }
00801     }
00802     circle.plane.yaxis = ON_CrossProduct( circle.plane.zaxis, circle.plane.xaxis );
00803     circle.plane.yaxis.Unitize();
00804     circle.plane.UpdateEquation();
00805     ON_Arc arc( circle, m_angle );
00806     crv = new ON_ArcCurve(arc, m_t[0], m_t[1]);
00807   }
00808   else if ( dir == 1 && m_curve )
00809   {
00810     crv = m_curve->DuplicateCurve();
00811     if ( crv )
00812     {
00813       double a = c;
00814       if ( m_t != m_angle )
00815       {
00816         double t = m_t.NormalizedParameterAt(c);
00817         a = m_angle.ParameterAt(t);
00818       }
00819       if ( a != 0.0 )
00820       {
00821         crv->Rotate( a, m_axis.Direction(), m_axis.from );
00822       }
00823     }
00824   }
00825   return crv;
00826 }
00827 
00828 ON_BOOL32 ON_RevSurface::Trim( int dir, const ON_Interval& domain )
00829 {
00830   ON_BOOL32 rc = false;
00831   if ( dir != 0 && dir != 1 )
00832     return false;
00833   if ( !domain.IsIncreasing() )
00834     return false;
00835   if ( m_bTransposed )
00836     dir = 1-dir;
00837   if ( dir == 0 )
00838   {
00839     ON_Interval dom;
00840     dom.Intersection(domain,m_t);
00841     if ( !dom.IsIncreasing() || !m_t.IsIncreasing() || !m_angle.IsIncreasing() )
00842       return false;
00843     double t0 = m_t.NormalizedParameterAt(dom[0]);
00844     double t1 = m_t.NormalizedParameterAt(dom[1]);
00845     ON_Interval a;
00846     a[0] = m_angle.ParameterAt(t0);
00847     a[1] = m_angle.ParameterAt(t1);
00848     double d = a.Length();
00849     if ( fabs(d) > ON_ZERO_TOLERANCE && fabs(d) <= 2.0*ON_PI+ON_ZERO_TOLERANCE )
00850     {
00851       m_angle = a;
00852       m_t = domain;
00853       rc = true;
00854     }
00855   }
00856   else if ( dir == 1 && m_curve )
00857   {
00858     rc = m_curve->Trim( domain );
00859   }
00860   if ( rc )
00861   {
00862     // update bounding box
00863     ON_BoundingBox bbox0 = m_bbox;
00864     m_bbox.Destroy();
00865     BoundingBox();
00866     if ( m_bbox.IsValid() && bbox0.IsValid() )
00867       m_bbox.Intersection(bbox0);
00868   }
00869   return rc;
00870 }
00871 
00872 bool ON_RevSurface::Extend(
00873       int dir,
00874       const ON_Interval& domain
00875       )
00876 {
00877   if ( dir != 0 && dir != 1 ) 
00878     return false;
00879   if (IsClosed(dir)) 
00880     return false;
00881   bool do_it = false;
00882   ON_Interval dom = Domain(dir);
00883   if (domain[0] < dom[0])
00884   {
00885     dom[0] = domain[0];
00886     do_it = true;
00887   }
00888   
00889   if (domain[1] > dom[1])
00890   {
00891     dom[1] = domain[1];
00892     do_it = true;
00893   }
00894 
00895   if (!do_it) 
00896     return false;
00897 
00898   if ( m_bTransposed ) 
00899     dir = 1-dir;
00900 
00901   bool rc = false;
00902 
00903   if ( dir == 0 )
00904   {
00905     double t0 = m_t.NormalizedParameterAt(dom[0]);
00906     double t1 = m_t.NormalizedParameterAt(dom[1]);
00907     ON_Interval a;
00908     a[0] = m_angle.ParameterAt(t0);
00909     a[1] = m_angle.ParameterAt(t1);
00910     if (a.Length() > 2.0*ON_PI+ON_ZERO_TOLERANCE) a[1] = a[0]+2.0*ON_PI;
00911     m_angle = a;
00912     m_t = dom;
00913     rc = true;
00914   }
00915   else if ( dir == 1 && m_curve )
00916   {
00917     rc = m_curve->Extend(dom);
00918   }
00919 
00920   if ( rc )
00921   {
00922     DestroySurfaceTree();
00923     // update bounding box
00924     ON_BoundingBox bbox0 = m_bbox;
00925     m_bbox.Destroy();
00926     BoundingBox();
00927   }
00928   return rc;
00929 }
00930 
00931 ON_BOOL32 ON_RevSurface::Split(
00932        int dir,
00933        double c,
00934        ON_Surface*& west_or_south_side,
00935        ON_Surface*& east_or_north_side
00936        ) const
00937 {
00938   ON_BOOL32 rc = false;
00939 
00940   ON_RevSurface* srf_ws=ON_RevSurface::Cast(west_or_south_side);
00941   ON_RevSurface* srf_en=ON_RevSurface::Cast(east_or_north_side);
00942   if ( srf_ws && srf_ws == srf_en )
00943     return false;
00944   if ( west_or_south_side && !srf_ws )
00945     return false;
00946   if ( east_or_north_side && !srf_en )
00947     return false;
00948 
00949   if ( dir != 0 && dir != 1 )
00950     return false;
00951   if ( m_bTransposed )
00952     dir = 1-dir;
00953 
00954   ON_Curve* left_side = 0;
00955   ON_Curve* right_side = 0;
00956   ON_Interval left_angle, right_angle;
00957   ON_Interval left_t, right_t;
00958   left_angle = m_angle;
00959   right_angle = m_angle;
00960   left_t = m_t;
00961   right_t = m_t;
00962 
00963   if ( dir == 0 )
00964   {
00965     double t = m_t.NormalizedParameterAt(c);
00966     if ( m_t.Includes(c,true) && 0.0 < t && t < 1.0 )
00967     {
00968       double a = m_angle.ParameterAt( t );
00969       if ( m_angle.Includes(a,true) )
00970       {
00971         rc = true;
00972 
00973         left_angle[1] = a;
00974         right_angle[0] = a;
00975         left_t[1] = c;
00976         right_t[0] = c;
00977 
00978         if ( srf_ws == this )
00979           left_side = m_curve;
00980         else
00981           left_side = m_curve->Duplicate();
00982         if ( srf_en == this )
00983           right_side = m_curve;
00984         else
00985           right_side = m_curve->Duplicate();
00986       }
00987     }
00988   }
00989   else if ( dir == 1 && m_curve )
00990   {
00991     rc = m_curve->Split( c, left_side, right_side );
00992     if ( rc )
00993     {
00994       if ( this == srf_ws )
00995       {
00996         delete m_curve;
00997         srf_ws->m_curve = left_side;
00998       }
00999       else if ( this == srf_en )
01000       {
01001         delete m_curve;
01002         srf_en->m_curve = right_side;
01003       }
01004     }
01005   }
01006 
01007   if ( rc )
01008   {
01009     // save input bounding box
01010     const ON_BoundingBox input_bbox(m_bbox);
01011 
01012     if ( !srf_ws )
01013       west_or_south_side = srf_ws = new ON_RevSurface();
01014     else if ( srf_ws != this && srf_ws->m_curve )
01015     {
01016       delete srf_ws->m_curve;
01017       srf_ws->m_curve = 0;
01018     }
01019     if ( !srf_en )
01020       east_or_north_side = srf_en = new ON_RevSurface();
01021     if ( srf_en != this && srf_en->m_curve )
01022     {
01023       delete srf_en->m_curve;
01024       srf_en->m_curve = 0;
01025     }
01026 
01027     srf_ws->m_axis = m_axis;
01028     srf_ws->m_angle = left_angle;
01029     srf_ws->m_t = left_t;
01030     srf_ws->m_bTransposed = m_bTransposed;
01031     srf_ws->m_curve = left_side;
01032     srf_ws->m_bbox.Destroy();
01033 
01034     srf_en->m_axis = m_axis;
01035     srf_en->m_angle = right_angle;
01036     srf_en->m_t = right_t;
01037     srf_en->m_bTransposed = m_bTransposed;
01038     srf_en->m_curve = right_side;
01039     srf_en->m_bbox.Destroy();
01040 
01041     // update bounding boxes
01042     // if input box was valid, intesect calculated boxes with
01043     // input box
01044     srf_ws->BoundingBox(); // calcluates srf_ws->m_bbox
01045     if ( srf_ws->m_bbox.IsValid() && input_bbox.IsValid() )
01046       srf_ws->m_bbox.Intersection(input_bbox);
01047 
01048     srf_en->BoundingBox(); // calcluates srf_en->m_bbox
01049     if ( srf_en->m_bbox.IsValid() && input_bbox.IsValid() )
01050       srf_en->m_bbox.Intersection(input_bbox);
01051   }
01052 
01053   return rc;
01054 }
01055 
01056 ON_BOOL32 ON_RevSurface::Transpose()
01057 {
01058   m_bTransposed = m_bTransposed ? false : true;
01059   return true;
01060 }
01061 
01062 bool ON_RevSurface::IsContinuous(
01063     ON::continuity desired_continuity,
01064     double s, 
01065     double t, 
01066     int* hint, // default = NULL,
01067     double point_tolerance, // default=ON_ZERO_TOLERANCE
01068     double d1_tolerance, // default==ON_ZERO_TOLERANCE
01069     double d2_tolerance, // default==ON_ZERO_TOLERANCE
01070     double cos_angle_tolerance, // default==ON_DEFAULT_ANGLE_TOLERANCE_COSINE
01071     double curvature_tolerance  // default==ON_SQRT_EPSILON
01072     ) const
01073 {
01074   bool rc = true;
01075   if ( m_curve )
01076   {
01077     double curve_t =  m_bTransposed ? s : t;
01078     rc = m_curve->IsContinuous( desired_continuity, curve_t, hint,
01079                                 point_tolerance, d1_tolerance, d2_tolerance,
01080                                 cos_angle_tolerance, curvature_tolerance );
01081   }
01082   return rc;
01083 }
01084 
01085 ON_BOOL32 ON_RevSurface::Reverse( int dir )
01086 {
01087   ON_BOOL32 rc = false;
01088   if ( m_bTransposed )
01089     dir = dir ? 0 : 1;
01090   if ( dir == 0 )
01091   {
01092     m_axis.Reverse();
01093     double a0 = m_angle[0];
01094     double a1 = m_angle[1];
01095     m_angle.Set( 2.0*ON_PI - a1, 2.0*ON_PI - a0 );
01096     m_t.Reverse();
01097     rc = true;
01098   }
01099   else if ( dir == 1 && m_curve )
01100   {
01101     rc = m_curve->Reverse();
01102   }
01103   return rc;
01104 }
01105 
01106 bool ON_RevSurface::GetNextDiscontinuity( 
01107                 int dir,
01108                 ON::continuity c,
01109                 double t0,
01110                 double t1,
01111                 double* t,
01112                 int* hint,
01113                 int* dtype,
01114                 double cos_angle_tolerance,
01115                 double curvature_tolerance
01116                 ) const
01117 {
01118   // 28 Jan 2005 - untested code
01119   bool rc = false;
01120   if ( (m_bTransposed ? 1 : 0) == dir )
01121   {
01122     // angle direction
01123     ON_Circle circle(ON_xy_plane,1.0);
01124     ON_Arc arc( circle, m_angle );
01125     ON_ArcCurve arc_curve(arc, m_t[0], m_t[1]);
01126     rc = arc_curve.GetNextDiscontinuity(
01127       c,
01128       t0,t1,t,
01129       (hint? &hint[dir] : 0),
01130       dtype,cos_angle_tolerance,
01131       curvature_tolerance);
01132   }
01133   else
01134   {
01135     rc = m_curve->GetNextDiscontinuity(
01136       c,
01137       t0,t1,t,
01138       (hint? &hint[dir] : 0),
01139       dtype,cos_angle_tolerance,
01140       curvature_tolerance);
01141   }
01142   return rc;
01143 }
01144 
01145 ON_BOOL32 ON_RevSurface::IsSingular( int side ) const // 0 = south, 1 = east, 2 = north, 3 = west
01146 {
01147   bool rc = false;
01148   ON_3dPoint P, Q;
01149   //double d, tol;
01150   if ( side < 0 || side > 3 )
01151     return false;
01152 
01153   if ( m_bTransposed )
01154   {
01155     switch(side)
01156     {
01157     case 0: side = 3; break;
01158     case 1: side = 2; break;
01159     case 2: side = 1; break;
01160     case 3: side = 0; break;
01161     }
01162   }
01163 
01164   if ( 0 == side || 2 == side )
01165   {
01166     P = (0 == side)
01167       ? m_curve->PointAtStart()
01168       : m_curve->PointAtEnd();
01169     Q = m_axis.ClosestPointTo(P);
01170 
01171     // 26 Feb 2003 Dale Lear
01172     //
01173     //     I changed the code to handle cases when the
01174     //     "Q" has some coordinates that are small and
01175     //     other coordinates that are very large.  The
01176     //     fabs(Q.*)*ON_SQRT_EPSILON term is required
01177     //     in cases where the evaluations in PointAtStart()
01178     //     and/or ClosestPointTo() have more numerical 
01179     //     error than ON_ZERO_TOLERANCE.  The numerical
01180     //     tolerance term has to be calculated on a
01181     //     coordinate-by-coordinate basis.  See RR 9683.
01182     //
01183     // old test:
01184     //d = P.DistanceTo(Q);
01185     //if ( d <= ON_ZERO_TOLERANCE )
01186     //  rc = true;
01187 
01188     // 12 July 2012 Dale Lear
01189     //   Use ON_PointsAreCoincident() for all IsSingular queries
01190     //
01191     //d = fabs(P.x - Q.x);
01192     //tol = ON_ZERO_TOLERANCE + fabs(Q.x)*ON_SQRT_EPSILON;
01193     //if ( d <= tol )
01194     //{
01195     //  d = fabs(P.y - Q.y);
01196     //  tol = ON_ZERO_TOLERANCE + fabs(Q.y)*ON_SQRT_EPSILON;
01197     //  if ( d <= tol )
01198     //  {
01199     //    d = fabs(P.z - Q.z);
01200     //    tol = ON_ZERO_TOLERANCE + fabs(Q.z)*ON_SQRT_EPSILON;
01201     //    if ( d <= tol )
01202     //      rc = true;
01203     //  }
01204     //}
01205     rc = ON_PointsAreCoincident(3,0,&P.x,&Q.x);
01206 
01207   }
01208 
01209   return rc;
01210 }
01211 
01212 ON_BOOL32 ON_RevSurface::IsPeriodic( int dir ) const // dir  0 = "s", 1 = "t"
01213 {
01214   ON_BOOL32 rc = false;
01215   if ( m_bTransposed )
01216     dir = dir ? 0 : 1;
01217   if ( dir == 0 )
01218   {
01219     if (m_angle.Length() >= 2.0*ON_PI-ON_ZERO_TOLERANCE )
01220       rc = true;
01221   }
01222   else if ( dir == 1 && m_curve )
01223   {
01224     rc = m_curve->IsPeriodic();
01225   }
01226   return rc;
01227 }
01228 
01229 ON_BOOL32 ON_RevSurface::IsPlanar(
01230       ON_Plane* plane,
01231       double tolerance
01232       ) const
01233 {
01234   ON_BOOL32 rc = false;
01235   if( IsValid()){
01236     ON_Plane AxisNormal( m_curve->PointAtStart(), m_axis.Tangent() );
01237     rc = m_curve->IsInPlane( AxisNormal, tolerance);
01238     if(rc && plane)
01239       *plane = AxisNormal;
01240   }
01241   return rc;
01242 }
01243 
01244 ON_BOOL32 ON_RevSurface::IsClosed( int dir ) const  // dir  0 = "s", 1 = "t"
01245 {
01246   ON_BOOL32 rc = false;
01247   if ( m_bTransposed )
01248     dir = dir ? 0 : 1;
01249   if ( dir == 0 )
01250   {
01251     if (m_angle.Length() >= 2.0*ON_PI-ON_ZERO_TOLERANCE )
01252       rc = true;
01253   }
01254   else if ( dir == 1 && m_curve )
01255   {
01256     rc = m_curve->IsClosed();
01257   }
01258   return rc;
01259 }
01260 
01261 ON_BOOL32 ON_RevSurface::GetParameterTolerance( // returns tminus < tplus: parameters tminus <= s <= tplus
01262          int dir,        // 0 gets first parameter, 1 gets second parameter
01263          double t,       // t = parameter in domain
01264          double* tminus, // tminus
01265          double* tplus   // tplus
01266          ) const
01267 {
01268   ON_BOOL32 rc = false;
01269   if ( m_bTransposed )
01270     dir = dir ? 0 : 1;
01271   if ( dir == 0 )
01272   {
01273     if ( m_t.IsIncreasing() )
01274       rc = ON_GetParameterTolerance( m_t[0], m_t[1], t, tminus, tplus );
01275   }
01276   else if ( dir == 1 && m_curve )
01277   {
01278     rc = m_curve->GetParameterTolerance( t, tminus, tplus );
01279   }
01280   return rc;
01281 }
01282 
01283 ON_BOOL32 ON_RevSurface::SetDomain( 
01284   int dir, // 0 sets first parameter's domain, 1 gets second parameter's domain
01285   double t0, 
01286   double t1
01287   )
01288 {
01289   bool rc = false;
01290   if ( m_bTransposed )
01291     dir = 1-dir;
01292   if ( dir == 0 )
01293   {
01294     if ( t0 < t1 )
01295     {
01296       m_t.Set(t0,t1);
01297       DestroyRuntimeCache();
01298       rc = true;
01299     }
01300   }
01301   else if ( dir == 1 && m_curve )
01302   {
01303     rc = m_curve->SetDomain( t0, t1 ) ? true : false;
01304     DestroyRuntimeCache();
01305   }
01306   return rc;
01307 }
01308 
01309 ON_Interval ON_RevSurface::Domain( int dir ) const
01310 {
01311   ON_Interval d;
01312   if ( m_bTransposed )
01313     dir = 1-dir;
01314   if ( dir == 0 )
01315   {
01316     d = m_t;
01317   }
01318   else if ( dir == 1 && m_curve )
01319   {
01320     d = m_curve->Domain();
01321   }
01322   return d;
01323 }
01324 
01325 ON_BOOL32 ON_RevSurface::GetSurfaceSize( 
01326     double* width, 
01327     double* height 
01328     ) const
01329 {
01330   ON_BOOL32 rc = false;
01331   if ( m_bTransposed )
01332   {
01333     double* ptr = width;
01334     width = height;
01335     height = ptr;
01336   }
01337   if ( m_curve )
01338   {
01339     rc = true;
01340 
01341     ON_Interval cdom = m_curve->Domain();
01342     int i, hint = 0;
01343     int imax = 64;
01344     double d = 1.0/((double)imax);
01345     ON_3dPoint pt0 = ON_UNSET_POINT;
01346     ON_3dPoint pt;
01347     double length_estimate = 0.0;
01348 
01349     if ( width != NULL || height != NULL )
01350     {
01351       double radius_estimate = 0.0;
01352       double r;
01353       for ( i = 0; i <= imax; i++ )
01354       {
01355         if ( m_curve->EvPoint( cdom.ParameterAt(i*d), pt, 0, &hint ) )
01356         {
01357           r = m_axis.DistanceTo(pt);
01358           if ( r > radius_estimate )
01359             radius_estimate = r;
01360           if ( pt0 != ON_UNSET_POINT )
01361             length_estimate += pt0.DistanceTo(pt);
01362           pt0 = pt;
01363         }
01364       }
01365       if ( width != NULL )
01366         *width = m_angle.Length()*radius_estimate;
01367     }
01368 
01369     if ( height != NULL )
01370     {
01371       *height = length_estimate;
01372     }
01373   }
01374   else
01375   {
01376     if ( width )
01377       *width = 0.0;
01378     if ( height )
01379       *height = 0.0;
01380   }
01381   return rc;
01382 }
01383 
01384 int ON_RevSurface::SpanCount( int dir ) const
01385 {
01386   int span_count = 0;
01387   if ( m_bTransposed )
01388     dir = 1-dir;
01389   if ( dir==0 && m_t.IsIncreasing() )
01390   {
01391           double a = (0.5 + ON_SQRT_EPSILON)*ON_PI;
01392     double da = fabs(m_angle.Length());
01393           if (da <= a)
01394                   span_count = 1;
01395           else if (da <= 2.0*a)
01396                   span_count = 2;
01397           else
01398                   span_count = 4;
01399   }
01400   else if ( dir == 1 && m_curve )
01401     span_count = m_curve->SpanCount();
01402   return span_count;
01403 }
01404 
01405 
01406 ON_BOOL32 ON_RevSurface::GetSpanVector( int dir, double* s ) const
01407 {
01408   ON_BOOL32 rc = false;
01409   if ( m_bTransposed )
01410     dir = 1-dir;
01411   if ( dir==0 && m_t.IsIncreasing() ) {
01412     int span_count = SpanCount(m_bTransposed?1-dir:dir);
01413     if ( span_count > 0 )
01414     {
01415       double d = 1.0/span_count;
01416       s[0] = m_t[0];
01417       for ( int i = 1; i < span_count; i++ )
01418         s[i] = m_t.ParameterAt( i*d );
01419       s[span_count] = m_t[1];
01420       rc = true;
01421     }
01422   }
01423   else if ( dir==1 && m_curve ) {
01424     rc = m_curve->GetSpanVector(s);
01425   }
01426   return rc;
01427 }
01428 
01429 
01430 int ON_RevSurface::Degree( int dir ) const
01431 {
01432   int span_degree = 0;
01433   if ( m_bTransposed )
01434     dir = 1-dir;
01435   if ( dir == 0  )
01436     span_degree = 2;
01437   else if ( dir == 1 && m_curve )
01438     span_degree = m_curve->Degree();
01439   return span_degree;
01440 }
01441 
01442 void ON_RevSurface::ClearBoundingBox()
01443 {
01444   m_bbox.Destroy();
01445 }
01446 
01447 ON_BOOL32 ON_RevSurface::GetBBox(    // returns true if successful
01448        double* boxmin,  // boxmin[dim]
01449        double* boxmax,  // boxmax[dim]
01450        ON_BOOL32 bGrowBox    // true means grow box
01451        ) const
01452 {
01453   ON_BOOL32 rc = m_bbox.IsValid();
01454 
01455   if ( !rc )
01456   {
01457     ON_BoundingBox bbox, cbox, abox;
01458     rc = m_curve->GetBoundingBox( cbox );
01459     if (rc)
01460     {
01461       //Dec 16 2010 - Chuck - if the angle range does not include 0, m_curve is not part of the surface.
01462       //bbox = cbox;
01463 
01464       ON_3dPointArray corners;
01465       cbox.GetCorners(corners);
01466       ON_3dPoint P;
01467       ON_Arc arc;
01468       arc.plane.zaxis = m_axis.Tangent();
01469       arc.SetAngleRadians(m_angle[1] - m_angle[0]);
01470       int i;
01471       double t;
01472       for ( i = 0; i < 8; i++ )
01473       {
01474         P = corners[i];
01475         abox.Set(P,false);
01476         while( m_axis.ClosestPointTo(P,&t) ) // not a loop - used for flow control
01477         {
01478           abox.Set(arc.plane.origin,true);
01479           // If we cannot construct a valid arc, then P and the point on the axis
01480           // are added to the bounding box.  One case where this happens is when
01481           // P is on the axis of revolution.  See bug 84354.
01482 
01483           arc.plane.origin = m_axis.PointAt(t);
01484           arc.plane.xaxis = P-arc.plane.origin;
01485           arc.radius = arc.plane.xaxis.Length();
01486           if ( !arc.plane.xaxis.Unitize() )
01487             break;
01488           if ( fabs(arc.plane.xaxis*arc.plane.zaxis) > 0.0001 )
01489             break; 
01490           arc.plane.yaxis = ON_CrossProduct(arc.plane.zaxis,arc.plane.xaxis);
01491           if ( !arc.plane.yaxis.Unitize() )
01492             break;
01493           arc.plane.UpdateEquation();
01494           arc.plane.Rotate( m_angle[0], arc.plane.zaxis );
01495           if ( !arc.IsValid() )
01496             break;
01497           abox = arc.BoundingBox();
01498           break;
01499         }
01500         bbox.Union(abox);
01501       }
01502 
01503       if ( bbox.IsValid() )
01504       {
01505         ON_RevSurface* ptr = const_cast<ON_RevSurface*>(this);
01506         ptr->m_bbox = bbox;
01507         rc = true;
01508       }
01509     }
01510   }
01511 
01512   if ( rc )
01513   {
01514     if ( boxmin )
01515     {
01516       if (bGrowBox){
01517         if (m_bbox.m_min.x < boxmin[0]) boxmin[0] = m_bbox.m_min.x;
01518         if (m_bbox.m_min.y < boxmin[1]) boxmin[1] = m_bbox.m_min.y;
01519         if (m_bbox.m_min.z < boxmin[2]) boxmin[2] = m_bbox.m_min.z;
01520       }
01521       else {
01522         boxmin[0] = m_bbox.m_min.x;
01523         boxmin[1] = m_bbox.m_min.y;
01524         boxmin[2] = m_bbox.m_min.z;
01525       }
01526     }
01527     if ( boxmax )
01528     {
01529       if (bGrowBox){
01530         if (m_bbox.m_max.x > boxmax[0]) boxmax[0] = m_bbox.m_max.x;
01531         if (m_bbox.m_max.y > boxmax[1]) boxmax[1] = m_bbox.m_max.y;
01532         if (m_bbox.m_max.z > boxmax[2]) boxmax[2] = m_bbox.m_max.z;
01533       }
01534       else {
01535         boxmax[0] = m_bbox.m_max.x;
01536         boxmax[1] = m_bbox.m_max.y;
01537         boxmax[2] = m_bbox.m_max.z;
01538       }
01539     }
01540   }
01541 
01542   return rc;
01543 }
01544 
01545 ON_BOOL32 ON_RevSurface::IsSpherical(ON_Sphere* sphere, double tolerance ) const
01546 {
01547   ON_BOOL32 rc = false;
01548   if ( m_curve )
01549   {
01550     ON_Plane plane;
01551     ON_Arc arc;
01552     ON_3dPoint P = m_curve->PointAt( m_curve->Domain().Mid() );
01553     plane.origin = m_axis.from;
01554     plane.yaxis = m_axis.Tangent();
01555     plane.zaxis = ON_CrossProduct( P-plane.origin, plane.yaxis );
01556     plane.zaxis.Unitize();
01557     plane.xaxis = ON_CrossProduct( plane.yaxis, plane.zaxis );
01558     plane.UpdateEquation();
01559     if ( plane.IsValid() )
01560     {
01561       if ( m_curve->IsArc( &plane, &arc, tolerance ) )
01562       {
01563         P = m_axis.ClosestPointTo( arc.Center() );
01564         if ( P.DistanceTo(arc.Center()) <= tolerance )
01565         {
01566           rc = true;
01567           if ( sphere )
01568           {
01569             sphere->plane.origin = arc.Center();
01570             sphere->plane.zaxis = m_axis.Tangent();
01571             sphere->plane.yaxis = arc.plane.zaxis;
01572             sphere->plane.xaxis = ON_CrossProduct( sphere->plane.zaxis, sphere->plane.yaxis );
01573             sphere->plane.UpdateEquation();
01574             sphere->radius = arc.radius;
01575           }
01576         }
01577       }
01578     }
01579   }
01580   return rc;
01581 }
01582 
01583 
01584 bool ON_Surface::IsSphere( ON_Sphere* sphere, double tolerance ) const
01585 {
01586   if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
01587     tolerance = ON_ZERO_TOLERANCE;
01588   const ON_RevSurface* rs = ON_RevSurface::Cast(this);
01589   if (rs)
01590   {
01591     return rs->IsSpherical(sphere,tolerance) ? true : false;
01592   }
01593 
01594   ON_Curve* crv = IsoCurve(0,Domain(1).Mid());
01595   if ( !crv )
01596     return false;
01597 
01598   ON_Arc arc0;
01599   int bIsArc0 = crv->IsArc(0,&arc0,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01600   delete crv;
01601   crv = 0;
01602   if ( !bIsArc0 )
01603     return false;
01604 
01605   crv = IsoCurve(1,Domain(0).Mid());
01606   if ( !crv )
01607     return false;
01608   ON_Arc arc1;
01609   int bIsArc1 = crv->IsArc(0,&arc1,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01610   delete crv;
01611   crv = 0;
01612   if ( !bIsArc1 )
01613     return false;
01614 
01615   // Determine if one of these arcs is a a portion of a 
01616   // great circle.
01617 
01618   ON_Sphere sph0;
01619   sph0.plane = arc0.plane;
01620   sph0.radius = arc0.radius;
01621   bool bTestSphere0 = sph0.IsValid();
01622 
01623   ON_Sphere sph1;
01624   sph1.plane = arc1.plane;
01625   sph1.radius = arc1.radius;
01626   bool bTestSphere1 = sph1.IsValid();
01627 
01628   if ( !bTestSphere0 && !bTestSphere1 )
01629     return false;
01630 
01631   double sph0tol = 0.0;
01632   double sph1tol = 0.0;
01633 
01634   double tol = 0.5*ON_SQRT_EPSILON*(arc0.radius+arc1.radius);
01635 
01636   ON_3dPoint P, S;
01637   double a, d;
01638   for ( a = 0.0; a < 1.0; a += 0.25 )
01639   {
01640     P = arc0.PointAt(a*2.0*ON_PI);
01641     if ( bTestSphere0 )
01642     {
01643       S = sph0.ClosestPointTo(P);
01644       d = S.DistanceTo(P);
01645       if ( d > tol )
01646       {
01647         bTestSphere0 = false;
01648         if ( !bTestSphere1 )
01649           return false;
01650       }
01651       else if ( d > sph0tol )
01652         sph0tol = d;
01653     }
01654     if ( bTestSphere1 )
01655     {
01656       S = sph1.ClosestPointTo(P);
01657       d = S.DistanceTo(P);
01658       if ( d > tol )
01659       {
01660         bTestSphere1 = false;
01661         if ( !bTestSphere0 )
01662           return false;
01663       }
01664       else if ( d > sph1tol )
01665         sph1tol = d;
01666     }
01667 
01668     P = arc1.PointAt(a*2.0*ON_PI);
01669     if ( bTestSphere0 )
01670     {
01671       S = sph0.ClosestPointTo(P);
01672       d = S.DistanceTo(P);
01673       if ( d > tol )
01674       {
01675         bTestSphere0 = false;
01676         if ( !bTestSphere1 )
01677           return false;
01678       }
01679       else if ( d > sph0tol )
01680         sph0tol = d;
01681     }
01682     if ( bTestSphere1 )
01683     {
01684       S = sph1.ClosestPointTo(P);
01685       d = S.DistanceTo(P);
01686       if ( d > tol )
01687       {
01688         bTestSphere1 = false;
01689         if ( !bTestSphere0 )
01690           return false;
01691       }
01692       else if ( d > sph1tol )
01693         sph1tol = d;
01694     }
01695   }
01696   // If the arc's are both great circles, then
01697   // both will be true unless we have a bug or
01698   // numerical issues.
01699   if (!bTestSphere0 && !bTestSphere1)
01700     return false;
01701 
01702   if ( tol < tolerance )
01703     tol = tolerance;
01704 
01705   double u, v;
01706   int sc0 = SpanCount(0);
01707   int sc1 = SpanCount(1);
01708   double* s = (double*)onmalloc( (sc0+sc1+2)*sizeof(s[0]) );
01709   double* t = s + (sc0+1);
01710   GetSpanVector(0,s);
01711   GetSpanVector(1,t);
01712   for ( int i = 0; i < sc0; i++ )
01713   {
01714     for ( int ii = i?1:0; ii <= 4; ii++ )
01715     {
01716       u = 0.25*((4-ii)*s[i] + ii*s[i+1]);
01717       for ( int j = 0; j <= sc1; j++ )
01718       {
01719         for ( int jj = j?1:0; jj <= 4; jj++ )
01720         {
01721           v = 0.25*((4-jj)*t[j] + jj*t[j+1]);
01722           P = PointAt(u,v);
01723           if ( bTestSphere0 )
01724           {
01725             S = sph0.ClosestPointTo(P);
01726             d = S.DistanceTo(P);
01727             if ( d > tol )
01728             {
01729               bTestSphere0 = false;
01730               if ( !bTestSphere1 )
01731               {
01732                 onfree(s);
01733                 return false;
01734               }
01735             }
01736             else if ( d > sph0tol )
01737               sph0tol = d;
01738           }
01739           if ( bTestSphere1 )
01740           {
01741             S = sph1.ClosestPointTo(P);
01742             d = S.DistanceTo(P);
01743             if ( d > tol )
01744             {
01745               bTestSphere1 = false;
01746               if ( !bTestSphere0 )
01747               {
01748                 onfree(s);
01749                 return false;
01750               }
01751             }
01752             else if ( d > sph1tol )
01753               sph1tol = d;
01754           }
01755         }
01756       }
01757     }
01758   }
01759   onfree(s);
01760 
01761   bool rc = (bTestSphere0 || bTestSphere1);
01762   if ( rc && sphere )
01763   {
01764     if (!bTestSphere0)
01765       *sphere = sph1;
01766     else if (!bTestSphere1)
01767       *sphere = sph0;
01768     else if (sph0tol <= sph1tol)
01769       *sphere = sph0;
01770     else
01771       *sphere = sph1;
01772   }
01773 
01774   return rc;
01775 }
01776 
01777 bool ON_Surface::IsCylinder( ON_Cylinder* cylinder, double tolerance ) const
01778 {
01779   if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
01780     tolerance = ON_ZERO_TOLERANCE;
01781   const ON_RevSurface* rs = ON_RevSurface::Cast(this);
01782   bool rc = rs && rs->IsCylindrical(cylinder,tolerance);
01783 
01784   if ( !rc && !rs )
01785   {
01786     ON_Curve* crv = IsoCurve(0,Domain(1).Mid());
01787     if ( !crv )
01788       return false;
01789 
01790     ON_Arc arc;
01791     ON_Line line;
01792     int bIsLine = 0;
01793     int bIsArc = crv->IsArc(0,&arc,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01794     if ( !bIsArc )
01795     {
01796       bIsLine = crv->IsLinear(tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01797       if ( bIsLine )
01798       {
01799         line.from = crv->PointAtStart();
01800         line.to = crv->PointAtEnd();
01801       }
01802     }
01803     delete crv;
01804     crv = 0;
01805     if ( !bIsArc && !bIsLine )
01806       return false;
01807 
01808     crv = IsoCurve(1,Domain(0).Mid());
01809     if ( !crv )
01810       return false;
01811     if ( !bIsArc )
01812       bIsArc = crv->IsArc(0,&arc,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01813     else if ( !bIsLine )
01814     {
01815       bIsLine = crv->IsLinear(tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01816       if ( bIsLine )
01817       {
01818         line.from = crv->PointAtStart();
01819         line.to = crv->PointAtEnd();
01820       }
01821     }
01822     delete crv;
01823     crv = 0;
01824     if ( !bIsArc || !bIsLine )
01825       return false;
01826 
01827     double tol = 0.5*ON_SQRT_EPSILON*(arc.radius);
01828     if ( tol < tolerance )
01829       tol = tolerance;
01830     double r = arc.plane.origin.DistanceTo(arc.plane.ClosestPointTo(line.from));
01831     if ( fabs(arc.radius - r) > tol )
01832       return false;
01833     r = arc.plane.origin.DistanceTo(arc.plane.ClosestPointTo(line.to));
01834     if ( fabs(arc.radius - r) > tol )
01835       return false;
01836 
01837     ON_3dPoint P;
01838     double u, v;
01839     int sc0 = SpanCount(0);
01840     int sc1 = SpanCount(1);
01841     double* s = (double*)onmalloc( (sc0+sc1+2)*sizeof(s[0]) );
01842     double* t = s + (sc0+1);
01843     GetSpanVector(0,s);
01844     GetSpanVector(1,t);
01845     for ( int i = 0; i < sc0; i++ )
01846     {
01847       for ( int ii = i?1:0; ii <= 4; ii++ )
01848       {
01849         u = 0.25*((4-ii)*s[i] + ii*s[i+1]);
01850         for ( int j = 0; j < sc1; j++ )
01851         {
01852           for ( int jj = j?1:0; jj <= 4; jj++ )
01853           {
01854             v = 0.25*((4-jj)*t[j] + jj*t[j+1]);
01855             P = PointAt(u,v);
01856             r = arc.plane.origin.DistanceTo(arc.plane.ClosestPointTo(P));
01857             if ( fabs(arc.radius - r) > tol )
01858             {
01859               onfree(s);
01860               return false;
01861             }
01862           }
01863         }
01864       }
01865     }
01866     onfree(s);
01867 
01868 
01869     rc = true;
01870     if ( cylinder )
01871     {
01872       cylinder->Create(arc);
01873       rc = cylinder->IsValid();
01874     }
01875   }
01876 
01877   return rc;
01878 }
01879 
01880 
01881 bool ON_Surface::IsCone( ON_Cone* cone, double tolerance ) const
01882 {
01883   if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
01884     tolerance = ON_ZERO_TOLERANCE;
01885 
01886   const ON_RevSurface* rs = ON_RevSurface::Cast(this);
01887   if (rs)
01888   {
01889     return rs->IsConical(cone,tolerance) ? true : false;
01890   }
01891 
01892 
01893   ON_Curve* crv = IsoCurve(0,Domain(1).Mid());
01894   if ( !crv )
01895     return false;
01896 
01897   ON_Arc arc;
01898   ON_Line line;
01899   int bIsLine = 0;
01900   int bIsArc = crv->IsArc(0,&arc,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01901   if ( !bIsArc )
01902   {
01903     bIsLine = crv->IsLinear(tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01904     if ( bIsLine )
01905     {
01906       line.from = crv->PointAtStart();
01907       line.to = crv->PointAtEnd();
01908     }
01909   }
01910   delete crv;
01911   crv = 0;
01912   if ( !bIsArc && !bIsLine )
01913     return false;
01914 
01915   crv = IsoCurve(1,Domain(0).Mid());
01916   if ( !crv )
01917     return false;
01918   if ( !bIsArc )
01919     bIsArc = crv->IsArc(0,&arc,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01920   else if ( !bIsLine )
01921   {
01922     bIsLine = crv->IsLinear(tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
01923     if ( bIsLine )
01924     {
01925       line.from = crv->PointAtStart();
01926       line.to = crv->PointAtEnd();
01927     }
01928   }
01929   delete crv;
01930   crv = 0;
01931   if ( !bIsArc || !bIsLine )
01932     return false;
01933 
01934   double r0 = arc.plane.origin.DistanceTo(arc.plane.ClosestPointTo(line.from));
01935   double r1 = arc.plane.origin.DistanceTo(arc.plane.ClosestPointTo(line.to));
01936   if ( fabs(r0-r1) <= ON_ZERO_TOLERANCE )
01937     return false;
01938   double h0 = arc.plane.plane_equation.ValueAt(line.from);
01939   double h1 = arc.plane.plane_equation.ValueAt(line.to);
01940   if ( fabs(h0-h1) <= ON_ZERO_TOLERANCE )
01941     return false;
01942   double tol = 0.5*ON_SQRT_EPSILON*(r0+r1);
01943 
01944   ON_Cone cn;
01945   cn.height = (h0*r1 - r0*h1)/(r1-r0);
01946   if ( !ON_IsValid(cn.height) || fabs(cn.height) <= ON_ZERO_TOLERANCE )
01947     return false;
01948   cn.plane = arc.plane;
01949   cn.plane.origin = cn.plane.origin + cn.height*cn.plane.zaxis;
01950   cn.plane.UpdateEquation();
01951   if ( r0 >= r1 )
01952   {
01953     cn.radius = r0;
01954     cn.height = h0-cn.height;
01955   }
01956   else
01957   {
01958     cn.radius = r1;
01959     cn.height = h1-cn.height;
01960   }
01961   if ( !cn.IsValid() )
01962     return false;
01963   tol *= fabs(cn.height);
01964 
01965   // if (r - h*cn.radius/cn.height > tolerance) return false;
01966   double h = cn.plane.plane_equation.ValueAt(line.from);
01967   if ( fabs(r0*cn.height - h*cn.radius) > tol )
01968     return false;
01969   h = cn.plane.plane_equation.ValueAt(line.to);
01970   if ( fabs(r1*cn.height - h*cn.radius) > tol )
01971     return false;
01972 
01973   ON_3dPoint P;
01974   double u, v, r;
01975   int sc0 = SpanCount(0);
01976   int sc1 = SpanCount(1);
01977   double* s = (double*)onmalloc( (sc0+sc1+2)*sizeof(s[0]) );
01978   double* t = s + (sc0+1);
01979   GetSpanVector(0,s);
01980   GetSpanVector(1,t);
01981   tol = 0.5*ON_SQRT_EPSILON*(r0+r1);
01982   if ( tol < tolerance )
01983     tol = tolerance;
01984   tol *= fabs(cn.height);
01985   for ( int i = 0; i < sc0; i++ )
01986   {
01987     for ( int ii = i?1:0; ii <= 4; ii++ )
01988     {
01989       u = 0.25*((4-ii)*s[i] + ii*s[i+1]);
01990       for ( int j = 0; j < sc1; j++ )
01991       {
01992         for ( int jj = j?1:0; jj <= 4; jj++ )
01993         {
01994           v = 0.25*((4-jj)*t[j] + jj*t[j+1]);
01995           P = PointAt(u,v);
01996           h = cn.plane.plane_equation.ValueAt(P);
01997           r = cn.plane.origin.DistanceTo(cn.plane.ClosestPointTo(P));
01998           // if (r - h*cn.radius/cn.height > tolerance) return false;
01999           if ( fabs(r*cn.height - h*cn.radius) > tol )
02000           {
02001             onfree(s);
02002             return false;
02003           }
02004         }
02005       }
02006     }
02007   }
02008   onfree(s);
02009 
02010   if ( cone )
02011   {
02012     *cone = cn;
02013   }
02014 
02015   return true;
02016 }
02017 
02018 
02019 bool ON_Surface::IsTorus( ON_Torus* torus, double tolerance ) const
02020 {
02021   if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
02022     tolerance = ON_ZERO_TOLERANCE;
02023 
02024   ON_Curve* crv = IsoCurve(0,Domain(1).Mid());
02025   if ( !crv )
02026     return false;
02027 
02028   ON_Arc arc0;
02029   int bIsArc0 = crv->IsArc(0,&arc0,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
02030   delete crv;
02031   crv = 0;
02032   if ( !bIsArc0 )
02033     return false;
02034 
02035   crv = IsoCurve(1,Domain(0).Mid());
02036   if ( !crv )
02037     return false;
02038   ON_Arc arc1;
02039   int bIsArc1 = crv->IsArc(0,&arc1,tolerance > ON_ZERO_TOLERANCE ? tolerance : 0.0);
02040   delete crv;
02041   crv = 0;
02042   if ( !bIsArc1 )
02043     return false;
02044 
02045   double tol = 0.5*ON_SQRT_EPSILON*(arc0.radius+arc1.radius);
02046 
02047   ON_Torus tr0;
02048   tr0.plane = arc0.plane;
02049   double h = tr0.plane.plane_equation.ValueAt(arc1.plane.origin);
02050   tr0.plane.origin = tr0.plane.origin + h*tr0.plane.zaxis;
02051   tr0.plane.UpdateEquation();
02052   tr0.major_radius = tr0.plane.origin.DistanceTo(arc1.plane.origin);
02053   tr0.minor_radius = arc1.radius;
02054 
02055   ON_Torus tr1;
02056   tr1.plane = arc1.plane;
02057   h = tr1.plane.plane_equation.ValueAt(arc0.plane.origin);
02058   tr1.plane.origin = tr1.plane.origin + h*tr1.plane.zaxis;
02059   tr1.plane.UpdateEquation();
02060   tr1.major_radius = tr1.plane.origin.DistanceTo(arc0.plane.origin);
02061   tr1.minor_radius = arc0.radius;
02062 
02063   bool bTestTorus0 = tr0.IsValid()?true:false;
02064   bool bTestTorus1 = tr1.IsValid()?true:false;
02065   if ( !bTestTorus0 && !bTestTorus1 )
02066     return false;
02067   double tr0tol = 0.0;
02068   double tr1tol = 0.0;
02069 
02070   ON_3dPoint P, T;
02071   double a, d;
02072   for ( a = 0.0; a < 1.0; a += 0.25 )
02073   {
02074     P = arc0.PointAt(a*2.0*ON_PI);
02075     if ( bTestTorus0 )
02076     {
02077       T = tr0.ClosestPointTo(P);
02078       d = T.DistanceTo(P);
02079       if ( d > tol )
02080       {
02081         bTestTorus0 = false;
02082         if ( !bTestTorus1 )
02083           return false;
02084       }
02085       else if ( d > tr0tol )
02086         tr0tol = d;
02087     }
02088     if ( bTestTorus1 )
02089     {
02090       T = tr1.ClosestPointTo(P);
02091       d = T.DistanceTo(P);
02092       if ( d > tol )
02093       {
02094         bTestTorus1 = false;
02095         if ( !bTestTorus0 )
02096           return false;
02097       }
02098       else if ( d > tr1tol )
02099         tr1tol = d;
02100     }
02101 
02102     P = arc1.PointAt(a*2.0*ON_PI);
02103     if ( bTestTorus0 )
02104     {
02105       T = tr0.ClosestPointTo(P);
02106       d = T.DistanceTo(P);
02107       if ( d > tol )
02108       {
02109         bTestTorus0 = false;
02110         if ( !bTestTorus1 )
02111           return false;
02112       }
02113       else if ( d > tr0tol )
02114         tr0tol = d;
02115     }
02116     if ( bTestTorus1 )
02117     {
02118       T = tr1.ClosestPointTo(P);
02119       d = T.DistanceTo(P);
02120       if ( d > tol )
02121       {
02122         bTestTorus1 = false;
02123         if ( !bTestTorus0 )
02124           return false;
02125       }
02126       else if ( d > tr1tol )
02127         tr1tol = d;
02128     }
02129   }
02130   // If the arc's planes are perpendicular, then
02131   // both will be true unless we have a bug or
02132   // numerical issues.
02133   if (!bTestTorus0 && !bTestTorus1)
02134     return false;
02135 
02136   if ( tol < tolerance )
02137     tol = tolerance;
02138 
02139   double u, v;
02140   int sc0 = SpanCount(0);
02141   int sc1 = SpanCount(1);
02142   double* s = (double*)onmalloc( (sc0+sc1+2)*sizeof(s[0]) );
02143   double* t = s + (sc0+1);
02144   GetSpanVector(0,s);
02145   GetSpanVector(1,t);
02146   for ( int i = 0; i < sc0; i++ )
02147   {
02148     for ( int ii = i?1:0; ii <= 4; ii++ )
02149     {
02150       u = 0.25*((4-ii)*s[i] + ii*s[i+1]);
02151       for ( int j = 0; j < sc1; j++ )
02152       {
02153         for ( int jj = j?1:0; jj <= 4; jj++ )
02154         {
02155           v = 0.25*((4-jj)*t[j] + jj*t[j+1]);
02156           P = PointAt(u,v);
02157           if ( bTestTorus0 )
02158           {
02159             T = tr0.ClosestPointTo(P);
02160             d = T.DistanceTo(P);
02161             if ( d > tol )
02162             {
02163               bTestTorus0 = false;
02164               if ( !bTestTorus1 )
02165               {
02166                 onfree(s);
02167                 return false;
02168               }
02169             }
02170             else if ( d > tr0tol )
02171               tr0tol = d;
02172           }
02173           if ( bTestTorus1 )
02174           {
02175             T = tr1.ClosestPointTo(P);
02176             d = T.DistanceTo(P);
02177             if ( d > tol )
02178             {
02179               bTestTorus1 = false;
02180               if ( !bTestTorus0 )
02181               {
02182                 onfree(s);
02183                 return false;
02184               }
02185             }
02186             else if ( d > tr1tol )
02187               tr1tol = d;
02188           }
02189         }
02190       }
02191     }
02192   }
02193   onfree(s);
02194 
02195   bool rc = (bTestTorus0 || bTestTorus1);
02196   if ( rc && torus )
02197   {
02198     if (!bTestTorus0)
02199       *torus = tr1;
02200     else if (!bTestTorus1)
02201       *torus = tr0;
02202     else if (tr0tol <= tr1tol)
02203       *torus = tr0;
02204     else
02205       *torus = tr1;
02206   }
02207 
02208   return rc;
02209 }
02210 
02211 static
02212 bool ON__IsCylConeHelper(
02213           const ON_Line& axis, 
02214           const ON_Curve* curve,
02215           double tolerance,
02216           ON_Plane& plane,
02217           ON_Line& line,
02218           double r[2],
02219           double& h
02220           )
02221 {
02222   if ( !axis.IsValid() )
02223     return false;
02224   if ( !curve )
02225     return false;
02226   line.from = curve->PointAtStart();
02227   line.to   = curve->PointAtEnd();
02228   if ( !line.IsValid() )
02229     return false;
02230   if ( line.Length() <= ON_ZERO_TOLERANCE )
02231     return false;
02232 
02233   plane.zaxis = axis.Tangent();
02234   h = plane.zaxis*line.Direction();
02235   if ( !ON_IsValid(h) )
02236     return false;
02237   if ( h < 0.0 )
02238   {
02239     plane.zaxis.Reverse();
02240     h = -h;
02241   }
02242   if ( h <= ON_ZERO_TOLERANCE )
02243     return false;
02244 
02245   double a0 = ON_UNSET_VALUE;
02246   if ( !axis.ClosestPointTo(line.from,&a0) )
02247     return false;
02248   double a1 = ON_UNSET_VALUE;
02249   if ( !axis.ClosestPointTo(line.to,&a1) )
02250     return false;
02251   if ( !ON_IsValid(a0) || !ON_IsValid(a1) )
02252     return false;
02253 
02254 
02255   ON_3dPoint A0 = axis.PointAt(a0);
02256   ON_3dPoint A1 = axis.PointAt(a1);
02257   plane.origin = A0;
02258   ON_3dVector x0 = line.from - A0;
02259   ON_3dVector x1 = line.to   - A1;
02260   r[0] = x0.Length();
02261   r[1] = x1.Length();
02262   if ( x0*x0 < 0.0 && r[0] > ON_ZERO_TOLERANCE && r[1] > ON_ZERO_TOLERANCE )
02263     return false;
02264   plane.xaxis = ( r[0] >= r[1] ) ? x0 : x1;
02265   if (fabs(plane.xaxis.Length()) <= ON_ZERO_TOLERANCE)
02266     return false;
02267   if ( !plane.xaxis.Unitize() )
02268     return false;
02269   plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis);
02270   if ( !plane.yaxis.Unitize() )
02271     return false;
02272   plane.UpdateEquation();
02273   if ( !plane.IsValid() )
02274     return false;
02275 
02276   x0 = line.Tangent();
02277   if ( fabs(x0*plane.yaxis) > ON_ZERO_TOLERANCE )
02278     return false;
02279 
02280   return (curve->IsLinear( tolerance )?true:false);
02281 }
02282 
02283 ON_BOOL32 ON_RevSurface::IsCylindrical(
02284       ON_Cylinder* cylinder,
02285       double tolerance
02286       ) const
02287 {
02288   ON_Cylinder c;
02289   ON_Line line;
02290   double r[2] = {0.0,0.0};
02291   double h = 0.0;
02292   if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
02293     tolerance = ON_ZERO_TOLERANCE;
02294   if ( !ON__IsCylConeHelper(m_axis,m_curve,tolerance,c.circle.plane,line,r,h) )
02295     return false;
02296   if ( fabs(r[0]-r[1]) > tolerance )
02297     return false;
02298   if ( fabs(line.Tangent()*c.circle.plane.xaxis) > ON_ZERO_TOLERANCE )
02299     return false;
02300   c.circle.radius = (r[0]==r[1]) ? r[0] : (0.5*(r[0]+r[1]));
02301   c.height[0] = 0.0;
02302   c.height[1] = h;
02303   if ( cylinder )
02304     *cylinder = c;
02305   return c.IsValid();
02306 }
02307 
02308 ON_BOOL32 ON_RevSurface::IsConical(
02309       ON_Cone* cone,
02310       double tolerance
02311       ) const
02312 {
02313   ON_Cone c;
02314   ON_Line line;
02315   double r[2] = {0.0,0.0};
02316   double h = 0.0;
02317   if ( !ON_IsValid(tolerance) || tolerance <= 0.0 )
02318     tolerance = ON_ZERO_TOLERANCE;
02319   if ( !ON__IsCylConeHelper(m_axis,m_curve,tolerance,c.plane,line,r,h) )
02320     return false;
02321   double dr = r[0]-r[1];
02322   if ( fabs(dr) <= ON_ZERO_TOLERANCE )
02323     return false;
02324   if ( 0.0 == r[0] )
02325   {
02326     c.radius = r[1];
02327     c.height = h;
02328   }
02329   else if ( 0.0 == r[1] )
02330   {
02331     c.plane.origin += h*c.plane.zaxis;
02332     c.plane.UpdateEquation();
02333     c.radius = r[0];
02334     c.height = -h;
02335   }
02336   else if ( dr > 0.0 )
02337   {
02338     h *= (r[0]/dr);
02339     c.plane.origin += h*c.plane.zaxis;
02340     c.plane.UpdateEquation();
02341     c.radius = r[0];
02342     c.height = -h;
02343   }
02344   else
02345   {
02346     double d = h*r[0]/dr;
02347     c.plane.origin += d*c.plane.zaxis;
02348     c.plane.UpdateEquation();
02349     c.radius = r[1];
02350     c.height = h-d;
02351   }
02352 
02353   if ( cone )
02354     *cone = c;
02355   return c.IsValid();
02356 }
02357 


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