opennurbs_nurbsvolume.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_NurbsCage,ON_Geometry,"06936AFB-3D3C-41ac-BF70-C9319FA480A1");
00020 
00021 ON_OBJECT_IMPLEMENT(ON_MorphControl,ON_Geometry,"D379E6D8-7C31-4407-A913-E3B7040D034A");
00022 
00023 
00024 ON_BOOL32 ON_NurbsCage::Read(ON_BinaryArchive& archive)
00025 {
00026   Destroy();
00027 
00028   int major_version = 0;
00029   int minor_version = 0;
00030   bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
00031   if ( rc )
00032   {
00033     while(rc)
00034     {
00035       if ( major_version != 1 )
00036       {
00037         ON_ERROR("ON_NurbsCage::Read - old code unable to read new version of chunk");
00038         rc = false;
00039         break;
00040       }
00041 
00042       int dim=0;
00043       int order0=0,order1=0,order2=0;
00044       int cv_count0=0,cv_count1=0,cv_count2=0;
00045       int is_rat=0;
00046 
00047       rc = archive.ReadInt(&dim);
00048       if (!rc)
00049         break;
00050       if (dim < 1 || dim > 10000)
00051       {
00052         ON_ERROR("ON_NurbsCage::Read - invalid dim");
00053         rc=false;
00054         break;
00055       }
00056 
00057       rc = archive.ReadInt(&is_rat);
00058       if (!rc)
00059         break;
00060       if (is_rat != 0 && is_rat != 1)
00061       {
00062         ON_ERROR("ON_NurbsCage::Read - invalid is_rat");
00063         rc=false;
00064         break;
00065       }
00066 
00067       rc = archive.ReadInt(&order0);
00068       if (!rc)
00069         break;
00070       if ( order0 < 2 || order0 > 10000 )
00071       {
00072         ON_ERROR("ON_NurbsCage::Read - invalid order0");
00073         rc=false;
00074         break;
00075       }
00076 
00077       rc = archive.ReadInt(&order1);
00078       if (!rc)
00079         break;
00080       if ( order1 < 2 || order1 > 10000 )
00081       {
00082         ON_ERROR("ON_NurbsCage::Read - invalid order1");
00083         rc=false;
00084         break;
00085       }
00086 
00087       rc = archive.ReadInt(&order2);
00088       if (!rc)
00089         break;
00090       if ( order2 < 2 || order2 > 10000 )
00091       {
00092         ON_ERROR("ON_NurbsCage::Read - invalid order2");
00093         rc=false;
00094         break;
00095       }
00096 
00097       rc = archive.ReadInt(&cv_count0);
00098       if (!rc)
00099         break;
00100       if ( cv_count0 < order0 || cv_count0 > 100000 )
00101       {
00102         ON_ERROR("ON_NurbsCage::Read - invalid cv_count0");
00103         rc=false;
00104         break;
00105       }
00106 
00107       rc = archive.ReadInt(&cv_count1);
00108       if (!rc)
00109         break;
00110       if ( cv_count1 < order1 || cv_count1 > 100000 )
00111       {
00112         ON_ERROR("ON_NurbsCage::Read - invalid cv_count1");
00113         rc=false;
00114         break;
00115       }
00116 
00117       rc = archive.ReadInt(&cv_count2);
00118       if (!rc)
00119         break;
00120       if ( cv_count2 < order2 || cv_count2 > 100000 )
00121       {
00122         ON_ERROR("ON_NurbsCage::Read - invalid cv_count2");
00123         rc=false;
00124         break;
00125       }
00126 
00127       rc = Create(dim,is_rat==1,order0,order1,order2,cv_count0,cv_count1,cv_count2);
00128       if (!rc)
00129         break;
00130 
00131       if (rc)
00132         rc = archive.ReadDouble(KnotCount(0),m_knot[0]);
00133       if (rc)
00134         rc = archive.ReadDouble(KnotCount(1),m_knot[1]);
00135       if (rc)
00136         rc = archive.ReadDouble(KnotCount(2),m_knot[2]);
00137 
00138       int i,j,k;
00139       const int cv_dim = m_is_rat?(m_dim+1):m_dim;
00140       for(i = 0; i < cv_count0 && rc; i++)
00141       {
00142         for(j = 0; j < cv_count1 && rc; j++)
00143         {
00144           for ( k = 0; k < cv_count2 && rc; k++)
00145           {
00146             rc = archive.ReadDouble(cv_dim,CV(i,j,k));
00147           }
00148         }
00149       }
00150 
00151       
00152 
00153       break;
00154     }
00155 
00156     if ( !archive.EndRead3dmChunk() )
00157     {
00158       rc = false;
00159     }
00160   }
00161   return rc;
00162 }
00163 
00164 ON_BOOL32 ON_NurbsCage::Write(ON_BinaryArchive& archive) const
00165 {
00166   bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
00167 
00168   if (rc)
00169   {
00170     rc = archive.WriteInt(m_dim);
00171     if(rc)
00172       rc = archive.WriteInt(m_is_rat);
00173 
00174     if (rc)
00175       rc = archive.WriteInt(m_order[0]);
00176     if (rc)
00177       rc = archive.WriteInt(m_order[1]);
00178     if (rc)
00179       rc = archive.WriteInt(m_order[2]);
00180 
00181     if (rc)
00182       rc = archive.WriteInt(m_cv_count[0]);
00183     if (rc)
00184       rc = archive.WriteInt(m_cv_count[1]);
00185     if (rc)
00186       rc = archive.WriteInt(m_cv_count[2]);
00187 
00188     if (rc)
00189       rc = archive.WriteDouble(KnotCount(0),m_knot[0]);
00190     if (rc)
00191       rc = archive.WriteDouble(KnotCount(1),m_knot[1]);
00192     if (rc)
00193       rc = archive.WriteDouble(KnotCount(2),m_knot[2]);
00194 
00195     int i,j,k;
00196     const int cv_dim = m_is_rat?(m_dim+1):m_dim;
00197     double* bogus_cv = (double*)alloca(cv_dim*sizeof(*bogus_cv));
00198     for ( i = 0; i < cv_dim; i++ )
00199       bogus_cv[i] = ON_UNSET_VALUE;
00200     for(i = 0; i < m_cv_count[0] && rc; i++)
00201     {
00202       for(j = 0; j < m_cv_count[1] && rc; j++)
00203       {
00204         for ( k = 0; k < m_cv_count[2] && rc; k++)
00205         {
00206           const double* cv = CV(i,j,k);
00207           if ( !cv )
00208             cv = bogus_cv;
00209           rc = archive.WriteDouble(cv_dim,cv);
00210         }
00211       }
00212     }
00213 
00214     if ( !archive.EndWrite3dmChunk() )
00215     {
00216       rc = false;
00217     }
00218   }
00219 
00220   return rc;
00221 }
00222 
00223 
00224 
00225 ON_NurbsCage::ON_NurbsCage()
00226 : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
00227 {
00228   m_order[0] = 0;
00229   m_order[1] = 0;
00230   m_order[2] = 0;
00231   m_cv_count[0] = 0;
00232   m_cv_count[1] = 0;
00233   m_cv_count[2] = 0;
00234   m_knot_capacity[0] = 0;
00235   m_knot_capacity[1] = 0;
00236   m_knot_capacity[2] = 0;
00237   m_knot[0] = 0;
00238   m_knot[1] = 0;
00239   m_knot[2] = 0;
00240   m_cv_stride[0] = 0;
00241   m_cv_stride[1] = 0;
00242   m_cv_stride[2] = 0;
00243 }
00244 
00245 ON_NurbsCage::ON_NurbsCage( int dim, bool is_rat, 
00246                                 int order0,
00247                                 int order1,
00248                                 int order2,
00249                                 int cv_count0,
00250                                 int cv_count1,
00251                                 int cv_count2
00252                                 )
00253                  : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
00254 {
00255   m_order[0] = 0;
00256   m_order[1] = 0;
00257   m_order[2] = 0;
00258   m_cv_count[0] = 0;
00259   m_cv_count[1] = 0;
00260   m_cv_count[2] = 0;
00261   m_knot_capacity[0] = 0;
00262   m_knot_capacity[1] = 0;
00263   m_knot_capacity[2] = 0;
00264   m_knot[0] = 0;
00265   m_knot[1] = 0;
00266   m_knot[2] = 0;
00267   m_cv_stride[0] = 0;
00268   m_cv_stride[1] = 0;
00269   m_cv_stride[2] = 0;
00270   Create( dim, is_rat, order0, order1, order2, cv_count0, cv_count1, cv_count2 );
00271 }
00272 
00273 ON_NurbsCage::ON_NurbsCage( const ON_BoundingBox& bbox, 
00274                                int order0, int order1, int order2,
00275                                int cv_count0, int cv_count1, int cv_count2
00276                                )
00277 : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
00278 {
00279   m_order[0] = 0;
00280   m_order[1] = 0;
00281   m_order[2] = 0;
00282   m_cv_count[0] = 0;
00283   m_cv_count[1] = 0;
00284   m_cv_count[2] = 0;
00285   m_knot_capacity[0] = 0;
00286   m_knot_capacity[1] = 0;
00287   m_knot_capacity[2] = 0;
00288   m_knot[0] = 0;
00289   m_knot[1] = 0;
00290   m_knot[2] = 0;
00291   m_cv_stride[0] = 0;
00292   m_cv_stride[1] = 0;
00293   m_cv_stride[2] = 0;
00294   Create(bbox,order0,order1,order2, cv_count0, cv_count1, cv_count2);
00295 }
00296 
00297 bool ON_NurbsCage::IsParallelogram(double tolerance) const
00298 {
00299   int i,j,k;
00300   double r,s,t;
00301   double x,y,z,dist;
00302   ON_Interval d[3];
00303   ON_3dPoint P, X, Y, Z, Q, B;
00304 
00305   bool rc = IsValid()?true:false;
00306 
00307   for ( i = 0; i < 3 && rc; i++ )
00308   {
00309     d[i] = Domain(i);
00310     rc = (    d[i][0] == m_knot[i][0]
00311            && d[i][1] == m_knot[i][m_cv_count[i]+m_order[i]-3]
00312            );
00313   }
00314 
00315   if (rc)
00316   {
00317     GetCV(0,0,0,P);
00318     GetCV(m_cv_count[0]-1,0,0,X);
00319     GetCV(0,m_cv_count[1]-1,0,Y);
00320     GetCV(0,0,m_cv_count[2]-1,Z);
00321 
00322     if ( tolerance < ON_ZERO_TOLERANCE )
00323       tolerance = ON_ZERO_TOLERANCE;
00324 
00325     for ( i = 0; i < m_cv_count[0]; i++ )
00326     {
00327       r = ON_GrevilleAbcissa(m_order[0],m_knot[0]+i);
00328       x = d[0].NormalizedParameterAt(r);
00329       for ( j = 0; j < m_cv_count[1]; j++ )
00330       {
00331         s = ON_GrevilleAbcissa(m_order[1],m_knot[1]+j);
00332         y = d[1].NormalizedParameterAt(s);
00333         for ( k = 0; k < m_cv_count[2]; k++ )
00334         {
00335           t = ON_GrevilleAbcissa(m_order[2],m_knot[2]+k);
00336           z = d[2].NormalizedParameterAt(t);
00337           Evaluate(r,s,t,0,3,&Q.x);
00338           B = (1.0-x-y-z)*P + x*X + y*Y + z*Z;
00339           dist = B.DistanceTo(Q);
00340           if ( dist > tolerance )
00341             return false;          
00342         }
00343       }
00344     }
00345   }
00346 
00347   return rc;
00348 }
00349 
00350 
00351 ON_NurbsCage::ON_NurbsCage( const ON_3dPoint* box_corners, 
00352                                int order0, int order1, int order2,
00353                                int cv_count0, int cv_count1, int cv_count2
00354                                )
00355 : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
00356 {
00357   m_order[0] = 0;
00358   m_order[1] = 0;
00359   m_order[2] = 0;
00360   m_cv_count[0] = 0;
00361   m_cv_count[1] = 0;
00362   m_cv_count[2] = 0;
00363   m_knot_capacity[0] = 0;
00364   m_knot_capacity[1] = 0;
00365   m_knot_capacity[2] = 0;
00366   m_knot[0] = 0;
00367   m_knot[1] = 0;
00368   m_knot[2] = 0;
00369   m_cv_stride[0] = 0;
00370   m_cv_stride[1] = 0;
00371   m_cv_stride[2] = 0;
00372   Create(box_corners,order0,order1,order2, cv_count0, cv_count1, cv_count2);
00373 }
00374 
00375 ON_NurbsCage::ON_NurbsCage( const ON_BezierCage& src )
00376 : m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
00377 {
00378   m_order[0] = 0;
00379   m_order[1] = 0;
00380   m_order[2] = 0;
00381   m_cv_count[0] = 0;
00382   m_cv_count[1] = 0;
00383   m_cv_count[2] = 0;
00384   m_knot_capacity[0] = 0;
00385   m_knot_capacity[1] = 0;
00386   m_knot_capacity[2] = 0;
00387   m_knot[0] = 0;
00388   m_knot[1] = 0;
00389   m_knot[2] = 0;
00390   m_cv_stride[0] = 0;
00391   m_cv_stride[1] = 0;
00392   m_cv_stride[2] = 0;
00393   *this = src;
00394 }
00395 
00396 ON_NurbsCage::~ON_NurbsCage()
00397 {
00398   Destroy();
00399 }
00400 
00401 int ON_NurbsCage::KnotCount(int dir) const
00402 {
00403   return (dir>=0 && dir<=2) ? ON_KnotCount(m_order[dir],m_cv_count[dir]) : 0;
00404 }
00405 
00406 double ON_NurbsCage::GrevilleAbcissa(
00407          int dir,    // dir
00408          int gindex  // index (0 <= index < CVCount(dir)
00409          ) const
00410 {
00411   return (dir >= 0 && dir <= 2)
00412          ? ON_GrevilleAbcissa( m_order[dir], m_knot[dir] + gindex )
00413          : ON_UNSET_VALUE;
00414 }
00415 
00416 bool ON_NurbsCage::MakeDeformable()
00417 {
00418   return true;
00419 }
00420 
00421 bool ON_NurbsCage::IsDeformable() const
00422 {
00423   return true;
00424 }
00425 
00426 bool ON_NurbsCage::GetTightBoundingBox( ON_BoundingBox& tight_bbox,int bGrowBox,const ON_Xform* xform) const
00427 {
00428   if ( bGrowBox && !tight_bbox.IsValid() )
00429   {
00430     bGrowBox = false;
00431   }
00432 
00433   if ( !bGrowBox )
00434   {
00435     tight_bbox.Destroy();
00436   }
00437 
00438   if( xform && !xform->IsIdentity() )
00439   {
00440     ON_3dPoint P;
00441     int i,j,k;
00442     for ( i = 0; i < m_cv_count[0]; i++ )
00443     {
00444       for ( j = 0; j < m_cv_count[1]; j++ )
00445       {
00446         for ( k = 0; k < m_cv_count[2]; k++ )
00447         {
00448           GetCV(i,j,k,P);
00449           P = (*xform)*P;
00450           if ( tight_bbox.Set(P,bGrowBox) )
00451           {
00452             bGrowBox = true;
00453           }
00454         }           
00455       }
00456     }
00457   }
00458   else
00459   {
00460     if ( GetBoundingBox(tight_bbox,bGrowBox) )
00461       bGrowBox = true;
00462   }
00463 
00464   return bGrowBox?true:false;
00465 }
00466 
00467 int ON_NurbsCage::CVCount() const
00468 {
00469   return CVCount(0)*CVCount(1)*CVCount(2);
00470 }
00471 
00472 int ON_NurbsCage::CVCount(int dir) const
00473 {
00474   return (dir>=0&&dir<=2) ? m_cv_count[dir] : 0;
00475 }
00476 
00477 void ON_NurbsCage::DestroyRuntimeCache(bool bDelete)
00478 {
00479   ON_Geometry::DestroyRuntimeCache(bDelete);
00480 }
00481 
00482 ON::object_type ON_NurbsCage::ObjectType() const
00483 {
00484   return ON::cage_object;
00485 }
00486 
00487 ON_NurbsCage& ON_NurbsCage::operator=( const ON_BezierCage& src )
00488 {
00489   if ( Create(src.m_dim,src.m_is_rat,
00490               src.m_order[0],src.m_order[1],src.m_order[2],
00491               src.m_order[0],src.m_order[1],src.m_order[2]) )
00492   {
00493     int i,j,k;
00494     for ( i = 0; i < m_cv_count[0]; i++ )
00495     {
00496       for ( j = 0; j < m_cv_count[1]; j++ )
00497       {
00498         for ( k = 0; k < m_cv_count[2]; k++ )
00499         {
00500           SetCV(i,j,k,ON::intrinsic_point_style,src.CV(i,j,k));
00501         }           
00502       }
00503     }
00504   }
00505   return *this;
00506 }
00507 
00508 unsigned int ON_NurbsCage::SizeOf() const
00509 {
00510   unsigned int sz = ON_Geometry::SizeOf();
00511   sz += (sizeof(*this) - sizeof(ON_Geometry));
00512   sz += (KnotCount(0) + KnotCount(1) + KnotCount(2) + CVSize()*CVCount())*sizeof(double);
00513   return sz;
00514 }
00515 
00516 ON__UINT32 ON_NurbsCage::DataCRC(ON__UINT32 current_remainder) const
00517 {
00518   current_remainder = ON_CRC32(current_remainder,sizeof(m_dim),&m_dim);
00519   current_remainder = ON_CRC32(current_remainder,sizeof(m_is_rat),&m_is_rat);
00520   current_remainder = ON_CRC32(current_remainder,3*sizeof(m_order[0]),&m_order[0]);
00521   current_remainder = ON_CRC32(current_remainder,3*sizeof(m_cv_count[0]),&m_cv_count[0]);
00522   if (   m_cv_count[0] > 0 && m_cv_count[1] > 0 && m_cv_count[2] > 0
00523       && m_cv_stride[0] > 0 && m_cv_stride[1] > 0 && m_cv_stride[2] > 0
00524       && m_cv )
00525   {
00526     size_t sizeof_cv = CVSize()*sizeof(m_cv[0]);
00527     const double* cv = m_cv;
00528     int i, j, k;
00529     for ( i = 0; i < m_cv_count[0]; i++ )
00530     {
00531       for ( j = 0; j < m_cv_count[1]; j++ )
00532       {
00533         cv = CV(i,j,0);
00534         for (k = 0; i < m_cv_count[2]; k++ )
00535         {
00536           current_remainder = ON_CRC32(current_remainder,sizeof_cv,cv);
00537           cv += m_cv_stride[2];
00538         }
00539       }
00540     }
00541   }
00542   current_remainder = ON_CRC32(current_remainder,KnotCount(0)*sizeof(m_knot[0][0]),m_knot[0]);
00543   current_remainder = ON_CRC32(current_remainder,KnotCount(1)*sizeof(m_knot[1][0]),m_knot[1]);
00544   current_remainder = ON_CRC32(current_remainder,KnotCount(2)*sizeof(m_knot[2][0]),m_knot[2]);
00545 
00546   return current_remainder;
00547 }
00548 
00549 ON_NurbsCage::ON_NurbsCage(const ON_NurbsCage& src)
00550                  : ON_Geometry(src),
00551                    m_dim(0),m_is_rat(0),m_cv_capacity(0),m_cv(0)
00552 {
00553   m_order[0] = 0;
00554   m_order[1] = 0;
00555   m_order[2] = 0;
00556   m_cv_count[0] = 0;
00557   m_cv_count[1] = 0;
00558   m_cv_count[2] = 0;
00559   m_knot_capacity[0] = 0;
00560   m_knot_capacity[1] = 0;
00561   m_knot_capacity[2] = 0;
00562   m_knot[0] = 0;
00563   m_knot[1] = 0;
00564   m_knot[2] = 0;
00565   m_cv_stride[0] = 0;
00566   m_cv_stride[1] = 0;
00567   m_cv_stride[2] = 0;
00568 
00569   *this = src;
00570 }
00571 
00572 
00573 ON_NurbsCage& ON_NurbsCage::operator=(const ON_NurbsCage& src)
00574 {
00575   if ( this != &src ) 
00576   {
00577     ON_Geometry::operator=(src);
00578     if ( Create( src.m_dim, src.m_is_rat, 
00579          src.m_order[0], src.m_order[1], src.m_order[2],
00580          src.m_cv_count[0], src.m_cv_count[1], src.m_cv_count[2]
00581          ) )
00582     {
00583       if ( m_order[0] >= 2 && m_cv_count[0] >= m_order[0] && m_knot[0] && src.m_knot[0] )
00584         memcpy( m_knot[0], src.m_knot[0], KnotCount(0)*sizeof(m_knot[0][0]));
00585       if ( m_order[1] >= 2 && m_cv_count[1] >= m_order[1] && m_knot[1] && src.m_knot[1]  )
00586         memcpy( m_knot[1], src.m_knot[1], KnotCount(1)*sizeof(m_knot[1][0]));
00587       if ( m_order[2] >= 2 && m_cv_count[2] >= m_order[2] && m_knot[2] && src.m_knot[2]  )
00588         memcpy( m_knot[2], src.m_knot[2], KnotCount(2)*sizeof(m_knot[2][0]));
00589 
00590       if ( m_cv && src.m_cv && m_cv_stride[0] > 0 && m_cv_stride[1] > 0 && m_cv_stride[2] > 0 )
00591       {
00592         const int cv_dim = CVSize();
00593         const int sizeofcv = cv_dim*sizeof(m_cv[0]);
00594         if (    m_cv_stride[0] == src.m_cv_stride[0] 
00595             && m_cv_stride[1] == src.m_cv_stride[1]
00596             && m_cv_stride[2] == src.m_cv_stride[2] )
00597         {
00598           memcpy(m_cv,src.m_cv,m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*sizeofcv);
00599         }
00600         else
00601         {
00602           int i, j, k;
00603           double* cv = m_cv;
00604           for ( i = 0; i < m_cv_count[0]; i++ ) 
00605           for ( j = 0; j < m_cv_count[1]; j++ ) 
00606           for ( k = 0; k < m_cv_count[2]; k++ ) 
00607           {
00608             memcpy( cv, src.CV(i,j,k), sizeofcv );
00609             cv += cv_dim;
00610           }
00611         }
00612       }
00613     }
00614     else 
00615     {
00616       Destroy();
00617     }
00618   }
00619   return *this;
00620 }
00621 
00622 ON_BOOL32 ON_NurbsCage::IsValid( 
00623           ON_TextLog* //text_log 
00624           ) const
00625 {
00626   if ( 0 == m_cv )
00627     return false;
00628 
00629   if ( 0 == m_knot[0] )
00630     return false;
00631 
00632   if ( 0 == m_knot[1] )
00633     return false;
00634 
00635   if ( 0 == m_knot[2] )
00636     return false;
00637 
00638   if ( m_order[0] < 2 )
00639     return false;
00640   if ( m_order[1] < 2 )
00641     return false;
00642   if ( m_order[2] < 2 )
00643     return false;
00644 
00645   if ( m_cv_count[0] < m_order[0] )
00646     return false;
00647   if ( m_cv_count[1] < m_order[1] )
00648     return false;
00649   if ( m_cv_count[2] < m_order[2] )
00650     return false;
00651 
00652   if ( m_dim <= 0 )
00653     return false;
00654   if ( m_is_rat != 0 && m_is_rat != 1 )
00655     return false;
00656 
00657   const int cvdim = m_is_rat ? (m_dim+1) : m_dim;
00658 
00659   if ( m_cv_capacity > 0 && m_cv_capacity < cvdim*m_cv_count[0]*m_cv_count[1]*m_cv_count[2] )
00660     return false;
00661 
00662   int i[3];
00663   i[0] = (m_cv_stride[0] <= m_cv_stride[1]) ? 0 : 1;
00664   i[1] = 1-i[0];
00665   if ( m_cv_stride[2] < m_cv_stride[i[0]] )
00666   {
00667     i[2] = i[1];
00668     i[1] = i[0];
00669     i[0] = 2;
00670   }
00671   else if ( m_cv_stride[2] < m_cv_stride[i[1]] )
00672   {
00673     i[2] = i[1];
00674     i[1] = 2;
00675   }
00676   else
00677   {
00678     i[2] = 2;
00679   }
00680 
00681   if ( m_cv_stride[i[0]] < cvdim )
00682     return false;
00683   if ( m_cv_stride[i[1]] < m_cv_stride[i[0]]*m_cv_count[i[0]] )
00684     return false;
00685   if ( m_cv_stride[i[2]] < m_cv_stride[i[1]]*m_cv_count[i[1]] )
00686     return false;
00687 
00688   return true;
00689 }
00690 
00691 void ON_NurbsCage::Dump( ON_TextLog& dump ) const
00692 {
00693   dump.Print( "ON_NurbsCage dim = %d is_rat = %d\n"
00694                "        order = (%d, %d, %d) \n",
00695                "        cv_count = (%d, %d, %d) \n",
00696                m_dim, m_is_rat, 
00697                m_order[0], m_order[1], m_order[2], 
00698                m_cv_count[0], m_cv_count[1], m_cv_count[2] );
00699 
00700   int dir;
00701   for ( dir = 0; dir < 3; dir++ ) 
00702   {
00703     dump.Print( "Knot Vector %d ( %d knots )\n", dir, KnotCount(dir) );
00704     dump.PrintKnotVector( m_order[dir], m_cv_count[dir], m_knot[dir] );
00705   }
00706 
00707   dump.Print( "Control Points  %d %s points\n"
00708                "  index               value\n",
00709                m_cv_count[0]*m_cv_count[1]*m_cv_count[2], 
00710                (m_is_rat) ? "rational" : "non-rational" );
00711   if ( !m_cv ) 
00712   {
00713     dump.Print("  NULL cv array\n");
00714   }
00715   else 
00716   {
00717     int i,j;
00718     char sPreamble[128]; 
00719     memset(sPreamble,0,sizeof(sPreamble));
00720     for ( i = 0; i < m_order[0]; i++ )
00721     {
00722       for ( j = 0; j < m_order[1]; j++ )
00723       {
00724         if ( i > 0 || j > 0)
00725           dump.Print("\n");
00726         sPreamble[0] = 0;
00727         sprintf(sPreamble,"  CV[%2d][%2d]",i,j);
00728         dump.PrintPointList( m_dim, m_is_rat, 
00729                           m_cv_count[2], m_cv_stride[2],
00730                           CV(i,j,0), 
00731                           sPreamble );
00732       }
00733       if ( i < m_order[0]-1)
00734         dump.Print("\n");
00735     }
00736   }
00737 }
00738 
00739 int ON_NurbsCage::Dimension() const
00740 {
00741   return m_dim;
00742 }
00743 
00744 bool ON_NurbsCage::Create( const ON_BoundingBox& bbox, 
00745                             int order0, int order1, int order2,
00746                             int cv_count0, int cv_count1, int cv_count2 
00747                             )
00748 {
00749   /*
00750             7______________6
00751             |\             |\
00752             | \            | \
00753             |  \ _____________\
00754             |   4          |   5
00755             |   |          |   |
00756             |   |          |   |
00757             3---|----------2   |
00758             \   |          \   |
00759              \  |z          \  |
00760             y \ |            \ |
00761                \0_____________\1
00762                        x
00763   */
00764   ON_3dPoint box_corners[8];
00765   box_corners[0] = bbox.Corner(0,0,0);
00766   box_corners[1] = bbox.Corner(1,0,0);
00767   box_corners[2] = bbox.Corner(1,1,0);
00768   box_corners[3] = bbox.Corner(0,1,0);
00769   box_corners[4] = bbox.Corner(0,0,1);
00770   box_corners[5] = bbox.Corner(1,0,1);
00771   box_corners[6] = bbox.Corner(1,1,1);
00772   box_corners[7] = bbox.Corner(0,1,1);
00773   return Create(box_corners,order0,order1,order2,cv_count0,cv_count1,cv_count2);
00774 }
00775 
00776 
00777 bool ON_NurbsCage::Create( int dim, bool is_rat, 
00778                             int order0, int order1, int order2,
00779                             int cv_count0, int cv_count1, int cv_count2 
00780                             )
00781 {
00782   Destroy();
00783   if ( order0 < 2 || order1 < 2 || order2 < 2 )
00784   {
00785     if (   0 == dim && 0 == is_rat 
00786          && 0 == order0 && 0 == order1 && 0 == order2 
00787          && 0 == cv_count0 && 0 == cv_count1 && 0 == cv_count2 )
00788     {
00789       return true;
00790     }
00791     ON_ERROR("ON_NurbsCage::Create - invalid orders");
00792     return false;
00793   }
00794 
00795   if ( cv_count0 < order0 || cv_count1 < order1 || cv_count2 < order2 )
00796   {
00797     ON_ERROR("ON_NurbsCage::Create - invalid cv counts");
00798     return false;
00799   }
00800 
00801   if ( dim < 1 )
00802   {
00803     ON_ERROR("ON_NurbsCage::Create - invalid dim");
00804     return false;
00805   }
00806 
00807   if ( is_rat != true && is_rat != false )
00808   {
00809     ON_ERROR("ON_NurbsCage::Create - invalid is_rat");
00810     return false;
00811   }
00812 
00813   m_dim = dim;
00814   m_is_rat = is_rat ? 1 : 0;
00815   
00816   m_order[0] = order0;
00817   m_order[1] = order1;
00818   m_order[2] = order2;
00819   
00820   m_cv_count[0] = cv_count0;
00821   m_cv_count[1] = cv_count1;
00822   m_cv_count[2] = cv_count2;
00823   
00824   // Other ON_NurbsCage member functions, like operator=,
00825   // depend on the strides being set this way.  If you anything
00826   // in the next three lines, then you need to read all the
00827   // code in the ON_NurbsCage member functions and adjust
00828   // it accordingly.
00829   m_cv_stride[2] = m_dim+m_is_rat;
00830   m_cv_stride[1] = m_cv_stride[2]*m_cv_count[2];
00831   m_cv_stride[0] = m_cv_stride[1]*m_cv_count[1];
00832   
00833   ReserveCVCapacity(m_cv_stride[0]*m_cv_count[0]);
00834   
00835   ReserveKnotCapacity(0,ON_KnotCount(m_order[0],m_cv_count[0]));
00836   ReserveKnotCapacity(1,ON_KnotCount(m_order[1],m_cv_count[1]));
00837   ReserveKnotCapacity(2,ON_KnotCount(m_order[2],m_cv_count[2]));
00838   
00839   ON_MakeClampedUniformKnotVector(m_order[0],m_cv_count[0],m_knot[0],1.0);
00840   ON_MakeClampedUniformKnotVector(m_order[1],m_cv_count[1],m_knot[1],1.0);
00841   ON_MakeClampedUniformKnotVector(m_order[2],m_cv_count[2],m_knot[2],1.0);
00842 
00843   ON_SetKnotVectorDomain( m_order[0], m_cv_count[0], m_knot[0], 0.0, 1.0);
00844   ON_SetKnotVectorDomain( m_order[1], m_cv_count[1], m_knot[1], 0.0, 1.0);
00845   ON_SetKnotVectorDomain( m_order[2], m_cv_count[2], m_knot[2], 0.0, 1.0);
00846   
00847   return IsValid() ? true : false;
00848 }
00849 
00850 bool ON_NurbsCage::Create(
00851   const ON_3dPoint* box_corners,
00852   int order0, int order1, int order2,
00853   int cv_count0, int cv_count1, int cv_count2 
00854   )
00855 {
00856   int i, j, k;
00857   double r,s,t;
00858   //bool rc = false;
00859   if ( 0 == box_corners )
00860     return false;
00861   for( i = 0; i < 8; i++ )
00862   {
00863     if ( !box_corners[i].IsValid() )
00864       return false;
00865   }
00866 
00867   // create trilinear "cube" to make it easy
00868   // to calculate CV locations.
00869   ON_BezierCage cube(3,0,2,2,2);
00870   cube.SetCV(0,0,0,box_corners[0]);
00871   cube.SetCV(1,0,0,box_corners[1]);
00872   cube.SetCV(1,1,0,box_corners[2]);
00873   cube.SetCV(0,1,0,box_corners[3]);
00874   cube.SetCV(0,0,1,box_corners[4]);
00875   cube.SetCV(1,0,1,box_corners[5]);
00876   cube.SetCV(1,1,1,box_corners[6]);
00877   cube.SetCV(0,1,1,box_corners[7]);
00878 
00879   if ( 2 == cv_count0 && 2 == cv_count1 && 2 == cv_count2 )
00880   {
00881     operator=(cube);
00882   }
00883   else
00884   {
00885     if (!Create(3,0,order0,order1,order2,cv_count0,cv_count1,cv_count2))
00886       return false;
00887 
00888     double* g0 = (double*)onmalloc(m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*sizeof(*g0));
00889     double* g1 = g0 + m_cv_count[0];
00890     double* g2 = g1 + m_cv_count[1];
00891 
00892     ON_GetGrevilleAbcissae(m_order[0],m_cv_count[0],m_knot[0],false,g0);
00893     ON_GetGrevilleAbcissae(m_order[1],m_cv_count[1],m_knot[1],false,g1);
00894     ON_GetGrevilleAbcissae(m_order[2],m_cv_count[2],m_knot[2],false,g2);
00895 
00896     for (i = 0; i < m_cv_count[0]; i++)
00897     {
00898       r = g0[i];
00899       for (j = 0; j < m_cv_count[1]; j++)
00900       {
00901         s = g1[j];
00902         for (k = 0; k < m_cv_count[2]; k++)
00903         {
00904           t = g2[k];
00905           SetCV(i,j,k,cube.PointAt(r,s,t));
00906         }
00907       }
00908     }
00909 
00910     onfree(g0);
00911   }
00912   return IsValid()?true:false;
00913 }
00914 
00915 
00916 void ON_NurbsCage::Destroy()
00917 {
00918   DestroyRuntimeCache();
00919 
00920   if ( m_cv && m_cv_capacity > 0 )
00921   {
00922     onfree(m_cv);
00923     m_cv = 0;
00924   }
00925 
00926   if ( m_knot[0] && m_knot_capacity[0] > 0 )
00927   {
00928     onfree(m_knot[0]);
00929     m_knot[0] = 0;
00930   }
00931 
00932   if ( m_knot[1] && m_knot_capacity[1] > 0 )
00933   {
00934     onfree(m_knot[1]);
00935     m_knot[1] = 0;
00936   }
00937 
00938   if ( m_knot[2] && m_knot_capacity[2] > 0 )
00939   {
00940     onfree(m_knot[2]);
00941     m_knot[2] = 0;
00942   }
00943 
00944   m_cv_capacity = 0;
00945   m_knot_capacity[0] = 0;
00946   m_knot_capacity[1] = 0;
00947   m_knot_capacity[2] = 0;
00948 
00949   m_cv_stride[0] = 0;
00950   m_cv_stride[1] = 0;
00951   m_cv_stride[2] = 0;
00952 
00953   m_dim = 0;
00954   m_is_rat = 0;
00955 
00956   m_order[0] = 0;
00957   m_order[1] = 0;
00958   m_order[2] = 0;
00959 }
00960 
00961 void ON_NurbsCage::EmergencyDestroy()
00962 {
00963   DestroyRuntimeCache(false);
00964   m_cv = 0;
00965   m_knot[0] = 0;
00966   m_knot[1] = 0;
00967   m_knot[2] = 0;
00968   m_cv_capacity = 0;
00969   m_knot_capacity[0] = 0;
00970   m_knot_capacity[1] = 0;
00971   m_knot_capacity[2] = 0;
00972   m_cv_stride[0] = 0;
00973   m_cv_stride[1] = 0;
00974   m_cv_stride[2] = 0;
00975   m_dim = 0;
00976   m_is_rat = 0;
00977   m_order[0] = 0;
00978   m_order[1] = 0;
00979   m_order[2] = 0;
00980 }
00981 
00982 
00983 ON_BOOL32 ON_NurbsCage::GetBBox( // returns true if successful
00984        double* boxmin,    // minimum
00985        double* boxmax,    // maximum
00986        ON_BOOL32 bGrowBox  // true means grow box
00987        ) const
00988 {
00989   int i, j;
00990   bool rc = ( 0 != m_cv 
00991               && m_cv_count[0] >= 2 && m_cv_count[1] >= 2 && m_cv_count[2] >= 2 
00992               && m_cv_stride[0] > 0 && m_cv_stride[1] > 0 && m_cv_stride[2] > 0 ) ? true : false;
00993   if ( !rc )
00994   {
00995     ON_ERROR("ON_NurbsCage::GetBBox - invalid input");
00996   }
00997   else
00998   {
00999     for ( i = 0; rc && i < m_cv_count[0]; i++ ) 
01000     for ( j = 0; rc && j < m_cv_count[1]; j++ ) 
01001     {
01002       rc = ON_GetPointListBoundingBox( m_dim, m_is_rat, m_cv_count[2], m_cv_stride[2],
01003                                       CV(i,j,0), 
01004                                       boxmin, boxmax, bGrowBox?true:false );
01005       bGrowBox = true;
01006     }
01007   }
01008   return rc;
01009 }
01010 
01011 ON_BOOL32 ON_NurbsCage::Transform( const ON_Xform& xform )
01012 {
01013   int i,j;
01014   bool rc = (m_cv_count[0] > 0 && m_cv_count[1] > 0 && m_cv_count[2]) ? true : false;
01015   if ( rc || !xform.IsIdentity() )
01016   {  
01017     if ( 0 == m_is_rat )
01018     {
01019       if ( xform.m_xform[3][0] != 0.0 || xform.m_xform[3][1] != 0.0 || xform.m_xform[3][2] != 0.0 )
01020       {
01021         MakeRational();
01022       }
01023     }
01024   
01025     for ( i = 0; rc && i < m_cv_count[0]; i++ ) 
01026     {
01027       for ( j = 0; rc && j < m_cv_count[1]; j++ ) 
01028       {
01029         rc = ON_TransformPointList( m_dim, m_is_rat, 
01030                                     m_cv_count[2], m_cv_stride[2], 
01031                                     CV(i,j,0), xform );
01032       }
01033     }
01034   }
01035   return rc;
01036 }
01037 
01038 ON_Interval ON_NurbsCage::Domain( 
01039       int dir
01040       ) const
01041 {
01042   ON_Interval d;
01043   if ( dir < 0 || dir > 2 || !ON_GetKnotVectorDomain( m_order[dir], m_cv_count[dir], m_knot[dir], &d.m_t[0], &d.m_t[1] ) )
01044     d.Destroy();
01045   return d;
01046 }
01047 
01048 
01049 
01050 
01051 
01052 bool ON_EvaluateNurbsCageSpan(
01053         int dim,
01054         int is_rat,
01055         int order0, int order1, int order2,
01056         const double* knot0,
01057         const double* knot1,
01058         const double* knot2,
01059         int cv_stride0, int cv_stride1, int cv_stride2,
01060         const double* cv0,
01061         int der_count,
01062         double t0, double t1, double t2,
01063         int v_stride, 
01064         double* v
01065         )
01066 {
01067   double c;
01068   double* N_0, *N_1, *N_2, *P, *P0, *P00;
01069         const double *cv;
01070   int j0, j1, j2, d0, d1, d2, d;
01071   const int cvdim = is_rat ? (dim+1) : dim;
01072   const int dcv2 = cv_stride2 - cvdim;
01073         const int der_count0 = (der_count >= order0) ? order0-1 : der_count;
01074         const int der_count1 = (der_count >= order1) ? order1-1 : der_count;
01075         const int der_count2 = (der_count >= order1) ? order2-2 : der_count;
01076   int Pcount = der_count*(der_count*(der_count*2 + 9)+13)/6 + 1;
01077   int Psize = cvdim<<3;
01078   int i = order0*order0;
01079   int j = order1*order1;
01080   int k = order2*order2;
01081 
01082   // don't declare any variable below here to avoid problems caused
01083   // by compiler/optimizer/alloca() bugs that can't keep the SP 
01084   // properly set.
01085 
01086   N_0 = (double*)alloca( ((i+j+k)*sizeof(*N_0)) + Pcount*Psize);
01087   N_1 = N_0 + i;
01088   N_2 = N_1 + j;
01089   P0  = N_2 + k;
01090   memset( P0, 0, Pcount*Psize );
01091 
01092   ON_EvaluateNurbsBasis( order0, knot0, t0, N_0 );
01093   ON_EvaluateNurbsBasis( order1, knot1, t1, N_1 );
01094   ON_EvaluateNurbsBasis( order2, knot2, t2, N_2 );
01095   if ( der_count0 > 0 )
01096   {
01097                 ON_EvaluateNurbsBasisDerivatives( order0, knot0, der_count0, N_0 );
01098                 ON_EvaluateNurbsBasisDerivatives( order1, knot1, der_count1, N_1 );
01099                 ON_EvaluateNurbsBasisDerivatives( order2, knot2, der_count2, N_2 );
01100   }
01101 
01102   // compute point
01103         P = P0;
01104         for ( j0 = 0; j0 < order0; j0++) 
01105   {
01106                 for ( j1 = 0; j1 < order1; j1++ ) 
01107     {
01108       cv = cv0 + j0*cv_stride0 + j1*cv_stride1;
01109       for ( j2 = 0; j2 < order2; j2++ )
01110       {
01111                           c = N_0[j0]*N_1[j1]*N_2[j2];
01112                           j = cvdim;
01113                           while (j--) 
01114         {
01115                                   *P++ += c* *cv++;
01116         }
01117                           P -= cvdim;
01118         cv += dcv2;
01119                   }
01120           }
01121   }
01122 
01123   if ( der_count > 0 ) 
01124   {
01125     // quickly compute first derivatives
01126         P += cvdim; // step over point
01127                 for ( j0 = 0; j0 < order0; j0++) 
01128     {
01129                         for ( j1 = 0; j1 < order1; j1++ ) 
01130       {
01131         cv = cv0 + j0*cv_stride0 + j1*cv_stride1;
01132         for ( j2 = 0; j2 < order2; j2++ )
01133         {
01134           // "Dr"
01135                                   c = N_0[j0+order0]*N_1[j1]*N_2[j2];
01136                                   j = cvdim;
01137                                   while (j--) 
01138                                           *P++ += c* *cv++;
01139           cv -= cvdim;
01140 
01141           // "Ds"
01142                                   c = N_0[j0]*N_1[j1+order1]*N_2[j2];
01143                                   j = cvdim;
01144                                   while (j--) 
01145                                           *P++ += c* *cv++;
01146           cv -= cvdim;
01147 
01148           // "Dt"
01149                                   c = N_0[j0]*N_1[j1]*N_2[j2+order2];
01150                                   j = cvdim;
01151                                   while (j--) 
01152                                           *P++ += c* *cv++;
01153 
01154                                   P -= 3*cvdim;
01155           cv += dcv2;
01156                           }
01157                   }
01158     }
01159 
01160     // compute higher order derivatives in generic loop
01161     for ( d = 2; d <= der_count; d++ )
01162     {
01163       // compute second derivatives
01164       P += (cvdim*d*(d+1))>>1; // step over (d-1) derivatives
01165       // P points to first coordinate of Dr^d
01166       if ( der_count0+der_count1+der_count2 > 1 ) 
01167       {
01168                     for ( j0 = 0; j0 < order0; j0++) 
01169         {
01170                       for ( j1 = 0; j1 < order1; j1++) 
01171           {
01172             cv = cv0 + j0*cv_stride0 + j1*cv_stride1;
01173                               for ( j2 = 0; j2 < order2; j2++ ) 
01174             {
01175               P00 = P;
01176               for ( d0 = d; d0 >= 0; d0-- )
01177               {
01178                 for ( d1 = d-d0; d1 >= 0; d1-- )
01179                 {
01180                   d2 = d-d0-d1;
01181                   if ( d0 > der_count0 || d1 > der_count1 || d2 > der_count2 )
01182                   {
01183                     // this partial is zero
01184                     P += cvdim;
01185                   }
01186                   else
01187                   {
01188                     c = N_0[j0 + d0*order0]*N_1[j1 + d1*order1]*N_2[j2 + d2*order2];
01189                     j = cvdim;
01190                     while(j--)
01191                       *P++ += c* *cv++;
01192                     cv -= cvdim;
01193                   }
01194                 }
01195               }
01196               P = P00;
01197               cv += cv_stride2;
01198                               }
01199                       }
01200         }
01201       }
01202     }
01203 
01204   }
01205 
01206         if ( is_rat ) 
01207   {
01208                 ON_EvaluateQuotientRule3( dim, der_count, cvdim, P0 );
01209                 Psize -= 8;
01210         }
01211 
01212   Pcount = (der_count+1)*(der_count+2)*(der_count+3)/6;
01213         for ( i = 0; i < Pcount; i++) 
01214   {
01215                 memcpy( v, P0, Psize );
01216     v += v_stride;
01217                 P0 += cvdim;
01218         }
01219 
01220   return true;
01221 }
01222 
01223 bool ON_NurbsCage::Evaluate( // returns false if unable to evaluate
01224        double r, double s, double t,       // evaluation parameter
01225        int der_count,            // number of derivatives (>=0)
01226        int v_stride,             // array stride (>=Dimension())
01227        double* v,                // array of length stride*(ndir+1)*(ndir+2)/2
01228        int side,       // optional - determines which side to evaluate from
01229                        //         0 = default
01230                        //         1 = from upper NE quadrant
01231                        //         2 = from upper NW quadrant
01232                        //         3 = from upper SW quadrant
01233                        //         4 = from upper SE quadrant
01234                        //         5 = from lower NE quadrant
01235                        //         6 = from lower NW quadrant
01236                        //         7 = from lower SW quadrant
01237                        //         8 = from lower SE quadrant
01238        int* hint
01239        ) const
01240 {  
01241   int side0 = (side&&(side==2||side==3||side==6||side==7))?-1:1;
01242   int side1 = (side&&(side==3||side==4||side==7||side==8))?-1:1;
01243   int side2 = (side>=5&&side<=8)?-1:1;
01244 
01245   int hint0 = (hint) ? hint[0] : 0;
01246   int hint1 = (hint) ? hint[1] : 0;
01247   int hint2 = (hint) ? hint[2] : 0;
01248   const int span_index0 = ON_NurbsSpanIndex(m_order[0],m_cv_count[0],m_knot[0],r,side0,hint0);
01249   const int span_index1 = ON_NurbsSpanIndex(m_order[1],m_cv_count[1],m_knot[1],s,side1,hint1);
01250   const int span_index2 = ON_NurbsSpanIndex(m_order[2],m_cv_count[2],m_knot[2],t,side2,hint2);
01251 
01252   bool rc = ON_EvaluateNurbsCageSpan(m_dim,m_is_rat,
01253     m_order[0],m_order[1],m_order[2],
01254     m_knot[0]+span_index0,
01255     m_knot[1]+span_index1,
01256     m_knot[2]+span_index2,
01257     m_cv_stride[0],m_cv_stride[1],m_cv_stride[2],
01258     m_cv + (m_cv_stride[0]*span_index0+m_cv_stride[1]*span_index1+m_cv_stride[2]*span_index2),
01259     der_count,
01260     r,s,t,
01261     v_stride,v);
01262 
01263   if( hint )
01264   {
01265     hint[0] = span_index0;
01266     hint[1] = span_index1;
01267     hint[2] = span_index2;
01268   }
01269 
01270   return rc;
01271 }
01272 
01273 ON_3dPoint ON_NurbsCage::PointAt(
01274         double r, 
01275         double s, 
01276         double t
01277         ) const
01278 {
01279   ON_3dPoint pt;
01280   if ( m_dim <= 3 )
01281   {
01282     pt.x  = 0.0;
01283     pt.y  = 0.0;
01284     pt.z  = 0.0;
01285     Evaluate(r,s,t,0,3,&pt.x);
01286   }
01287   else
01288   {
01289     double* v = (double*)alloca(m_dim*sizeof(*v));
01290     v[0] = 0.0;
01291     v[1] = 0.0;
01292     v[2] = 0.0;
01293     Evaluate(r,s,t,0,m_dim,v);
01294     pt.x = v[0];
01295     pt.y = v[1];
01296     pt.z = v[2];
01297   }
01298   return pt;
01299 }
01300 
01301 ON_3dPoint ON_NurbsCage::PointAt( ON_3dPoint rst ) const
01302 {
01303   ON_3dPoint pt;
01304   if ( m_dim <= 3 )
01305   {
01306     pt.x  = 0.0;
01307     pt.y  = 0.0;
01308     pt.z  = 0.0;
01309     Evaluate(rst.x,rst.y,rst.z,0,3,&pt.x);
01310   }
01311   else
01312   {
01313     double* v = (double*)alloca(m_dim*sizeof(*v));
01314     v[0] = 0.0;
01315     v[1] = 0.0;
01316     v[2] = 0.0;
01317     Evaluate(rst.x,rst.y,rst.z,0,m_dim,v);
01318     pt.x = v[0];
01319     pt.y = v[1];
01320     pt.z = v[2];
01321   }
01322   return pt;
01323 }
01324 
01325 ON_NurbsSurface* ON_NurbsCage::IsoSurface(
01326         int dir,
01327         double c,
01328         ON_NurbsSurface* srf
01329         ) const
01330 {
01331   // c = 0; cage(c,s,t) = srf(s,t)
01332   // c = 1; cage(r,c,t) = srf(r,t)
01333   // c = 2; cage(r,s,c) = srf(r,s)
01334   if ( dir < 0 || dir > 2 )
01335   {
01336     ON_ERROR("ON_NurbsCage::IsoSurface - invalid dir parameter");
01337     return 0;
01338   }
01339   if ( m_order[dir] < 2 || m_cv_count[dir] < m_order[dir] || 0 == m_knot[dir] )
01340   {
01341     ON_ERROR("ON_NurbsCage::IsoSurface - invalid NURBS cage");
01342     return 0;
01343   }
01344 
01345   const int cage_cvdim = CVSize();
01346 
01347   int span_index = ON_NurbsSpanIndex(m_order[dir],m_cv_count[dir],m_knot[dir],c,0,0);
01348   ON_NurbsCurve nurbs_curve;
01349   nurbs_curve.m_dim = cage_cvdim*m_cv_count[0]*m_cv_count[1]*m_cv_count[2]/m_cv_count[dir];
01350   nurbs_curve.m_is_rat = 0;
01351   nurbs_curve.m_order = m_order[dir];
01352   nurbs_curve.m_cv_count = nurbs_curve.m_order;
01353   nurbs_curve.ReserveCVCapacity(nurbs_curve.m_dim*nurbs_curve.m_cv_count);
01354   nurbs_curve.m_cv_stride = nurbs_curve.m_dim;
01355   nurbs_curve.m_knot = m_knot[dir] + span_index;
01356   nurbs_curve.m_knot_capacity = 0;
01357 
01358   int ii,jj,kk;
01359   /*
01360   int i0 = 0;
01361   int i1 = m_cv_count[0];
01362   int j0 = 0;
01363   int j1 = m_cv_count[1];
01364   int k0 = 0;
01365   int k1 = m_cv_count[2];
01366   */
01367 
01368   //int i0 = span_index;
01369   //int i1 = span_index+m_order[dir];
01370   ii = dir;
01371   switch(dir)
01372   {
01373   case 0:
01374     jj = 1;
01375     kk = 2;
01376     break;
01377   case 1:
01378     jj = 0;
01379     kk = 2;
01380     break;
01381   case 2:
01382     jj = 0;
01383     kk = 1;
01384     break;
01385   default: // to keep lint happy
01386     ii = 0;
01387     jj = 1;
01388     kk = 2;
01389     break;
01390   };
01391 
01392 
01393   double* cv;
01394   const int cage_sizeofcv = cage_cvdim*sizeof(*cv);
01395   //int i0 = span_index;
01396   int i1 = span_index+m_order[ii];
01397   int j1 = m_cv_count[jj];
01398   int k1 = m_cv_count[kk];
01399 
01400   int i,j,k;
01401   int cage_ijk[3];
01402   for ( i = span_index; i < i1; i++) 
01403   {
01404     cv = nurbs_curve.CV(i-span_index);
01405     cage_ijk[ii] = i;
01406     for ( j = 0; j < j1; j++ ) 
01407     {
01408       cage_ijk[jj] = j;
01409       for ( k = 0; k < k1; k++ )
01410       {
01411         cage_ijk[kk] = k;
01412         memcpy(cv,CV(cage_ijk[0],cage_ijk[1],cage_ijk[2]),cage_sizeofcv);
01413         cv += cage_cvdim;
01414       }
01415     }
01416   }
01417 
01418   ON_NurbsSurface* iso_srf = srf ? srf : ON_NurbsSurface::New();
01419   iso_srf->Create(m_dim,m_is_rat,m_order[jj],m_order[kk],m_cv_count[jj],m_cv_count[kk]);
01420   nurbs_curve.Evaluate(c,0,nurbs_curve.m_dim,iso_srf->m_cv,0,0);
01421   nurbs_curve.m_knot = 0;
01422   memcpy(iso_srf->m_knot[0],m_knot[jj],iso_srf->KnotCount(0)*sizeof(*iso_srf->m_knot[0]));
01423   memcpy(iso_srf->m_knot[1],m_knot[kk],iso_srf->KnotCount(1)*sizeof(*iso_srf->m_knot[1]));
01424 
01425   return iso_srf;
01426 }
01427 
01428 bool ON_NurbsCage::IsRational() const
01429 {
01430   return m_is_rat ? true : false;
01431 }
01432 
01433 int ON_NurbsCage::CVSize() const
01434 {
01435   return ( m_is_rat && m_dim>0 ) ? m_dim+1 : m_dim;
01436 }
01437 
01438 int ON_NurbsCage::Order( int dir ) const
01439 {
01440   return (dir>=0&&dir<=2) ? m_order[dir] : 0;
01441 }
01442 
01443 int ON_NurbsCage::Degree(int dir) const
01444 {
01445   int order = Order(dir);
01446   return (order>=2) ? order-1 : 0;
01447 }
01448 
01449 bool ON_NurbsCage::IsClosed(int dir) const
01450 {
01451   bool bIsClosed = false;
01452   if ( dir >= 0 && dir <= 2 && m_dim > 0)
01453   {
01454     if ( ON_IsKnotVectorClamped( m_order[dir], m_cv_count[dir], m_knot[dir] ) ) 
01455     {
01456       const double *cv0, *cv1;
01457       int i,j,k,d[3] = {0,0,0};
01458       d[dir] = m_cv_count[dir] - 1;
01459       for ( i = 0; i+d[0] < m_cv_count[0]; i++ )
01460       {
01461         for ( j = 0; j+d[1] < m_cv_count[1]; j++ )
01462         {
01463           for ( k = 0; k+d[2] < m_cv_count[2]; k++ )
01464           {
01465             cv0 = CV(i,j,k);
01466             cv1 = CV(i+d[0],j+d[1],k+d[2]);
01467             if ( false == ON_PointsAreCoincident( m_dim, m_is_rat, cv0, cv1 ) )
01468               return false;
01469           }
01470         }
01471       }
01472       bIsClosed = true;
01473     }
01474     else
01475     {
01476       bIsClosed =  IsPeriodic(dir);
01477     }
01478   }
01479   return bIsClosed;
01480 }
01481 
01482 bool ON_NurbsCage::IsPeriodic(int dir) const
01483 {
01484   bool bIsPeriodic = false;
01485   if ( dir >= 0 && dir <= 2 && m_dim > 0 )
01486   {
01487     bIsPeriodic = ON_IsKnotVectorPeriodic( m_order[dir], m_cv_count[dir], m_knot[dir] );
01488     if ( bIsPeriodic ) 
01489     {
01490       const double *cv0, *cv1;
01491       int i,j,k,d[3] = {0,0,0};
01492       d[dir] = m_cv_count[dir] - (m_order[dir]-1);
01493       for ( i = 0; i+d[0] < m_cv_count[0]; i++ )
01494       {
01495         for ( j = 0; j+d[1] < m_cv_count[1]; j++ )
01496         {
01497           for ( k = 0; k+d[2] < m_cv_count[2]; k++ )
01498           {
01499             cv0 = CV(i,j,k);
01500             cv1 = CV(i+d[0],j+d[1],k+d[2]);
01501             if ( false == ON_PointsAreCoincident(m_dim, m_is_rat, cv0, cv1 ) )
01502               return false;
01503           }
01504         }
01505       }
01506     }
01507   }
01508   return bIsPeriodic;
01509 }
01510 
01511 double* ON_NurbsCage::CV( int i, int j, int k ) const
01512 {
01513 
01514 #if defined(ON_DEBUG)
01515   if ( 0 == m_cv )
01516   {
01517     ON_ERROR("ON_NurbsCage::CV - NULL m_cv");
01518     return 0;
01519   }
01520   if ( i < 0 || i >= m_cv_count[0] || j< 0 || j >= m_cv_count[1] || k < 0 || k >= m_cv_count[2])
01521   {
01522     ON_ERROR("ON_NurbsCage::CV - (i,j,k) out of range");
01523     return 0;
01524   }
01525 #endif
01526 
01527   return (m_cv) ? (m_cv + i*m_cv_stride[0] + j*m_cv_stride[1] + k*m_cv_stride[2]) : 0;
01528 }
01529 
01530 ON::point_style ON_NurbsCage::CVStyle() const
01531 {
01532   return m_is_rat ? ON::homogeneous_rational : ON::not_rational;
01533 }
01534 
01535 double ON_NurbsCage::Weight( int i, int j, int k ) const
01536 {
01537   return (m_cv && m_is_rat) ? m_cv[i*m_cv_stride[0] + j*m_cv_stride[1] + k*m_cv_stride[2] + + m_dim] : 1.0;
01538 }
01539 
01540 
01541 bool ON_NurbsCage::SetWeight( int i, int j, int k, double w )
01542 {
01543   bool rc = false;
01544   if ( m_is_rat ) 
01545   {
01546     double* cv = CV(i,j,k);
01547     if (cv) 
01548     {
01549       cv[m_dim] = w;
01550       rc = true;
01551     }
01552   }
01553   else if ( w == 1.0 ) 
01554   {
01555     rc = true;
01556   }
01557   return rc;
01558 }
01559 
01560 bool ON_NurbsCage::SetCV( int i, int j, int k, ON::point_style style, const double* Point )
01561 {
01562   bool rc = true;
01563   int n;
01564   double w;
01565 
01566   double* cv = CV(i,j,k);
01567   if ( !cv )
01568     return false;
01569 
01570   switch ( style ) {
01571 
01572   case ON::not_rational:  // input Point is not rational
01573     memcpy( cv, Point, m_dim*sizeof(*cv) );
01574     if ( IsRational() ) {
01575       // NURBS surface is rational - set weight to one
01576       cv[m_dim] = 1.0;
01577     }
01578     break;
01579 
01580   case ON::homogeneous_rational:  // input Point is homogeneous rational
01581     if ( IsRational() ) {
01582       // NURBS surface is rational
01583       memcpy( cv, Point, (m_dim+1)*sizeof(*cv) );
01584     }
01585     else {
01586       // NURBS surface is not rational
01587       w = (Point[m_dim] != 0.0) ? 1.0/Point[m_dim] : 1.0;
01588       for ( n = 0; n < m_dim; n++ ) {
01589         cv[n] = w*Point[n];
01590       }
01591     }
01592     break;
01593 
01594   case ON::euclidean_rational:  // input Point is euclidean rational
01595     if ( IsRational() ) {
01596       // NURBS surface is rational - convert euclean point to homogeneous form
01597       w = Point[m_dim];
01598       for ( n = 0; n < m_dim; n++ )
01599         cv[i] = w*Point[i];
01600       cv[m_dim] = w;
01601     }
01602     else {
01603       // NURBS surface is not rational
01604       memcpy( cv, Point, m_dim*sizeof(*cv) );
01605     }
01606     break;
01607 
01608   case ON::intrinsic_point_style:
01609     n = m_is_rat?m_dim+1:m_dim;
01610     memcpy(cv,Point,n*sizeof(*cv));
01611     break;
01612     
01613   default:
01614     rc = false;
01615     break;
01616   }
01617   return rc;
01618 }
01619 
01620 bool ON_NurbsCage::SetCV( int i, int j, int k, const ON_3dPoint& point )
01621 {
01622   bool rc = false;
01623   double* cv = CV(i,j,k);
01624   if ( cv ) {
01625     cv[0] = point.x;
01626     if ( m_dim > 1 ) {
01627       cv[1] = point.y;
01628       if ( m_dim > 2 )
01629         cv[2] = point.z;
01630     }
01631     if ( m_is_rat ) {
01632       cv[m_dim] = 1.0;
01633     }
01634     rc = true;
01635   }
01636   return rc;
01637 }
01638 
01639 bool ON_NurbsCage::SetCV( int i, int j, int k, const ON_4dPoint& point )
01640 {
01641   bool rc = false;
01642   double* cv = CV(i,j,k);
01643   if ( cv ) {
01644     if ( m_is_rat ) {
01645       cv[0] = point.x;
01646       if ( m_dim > 1 ) {
01647         cv[1] = point.y;
01648         if ( m_dim > 2 )
01649           cv[2] = point.z;
01650       }
01651       cv[m_dim] = point.w;
01652       rc = true;
01653     }
01654     else {
01655       double w;
01656       if ( point.w != 0.0 ) {
01657         w = 1.0/point.w;
01658         rc = true;
01659       }
01660       else {
01661         w = 1.0;
01662       }
01663       cv[0] = w*point.x;
01664       if ( m_dim > 1 ) {
01665         cv[1] = w*point.y;
01666         if ( m_dim > 2 ) {
01667           cv[2] = w*point.z;
01668         }
01669       }
01670     }
01671   }
01672   return rc;
01673 }
01674 
01675 bool ON_NurbsCage::GetCV( int i, int j, int k, ON::point_style style, double* Point ) const
01676 {
01677   const double* cv = CV(i,j,k);
01678   if ( !cv )
01679     return false;
01680   int dim = Dimension();
01681   double w = ( IsRational() ) ? cv[dim] : 1.0;
01682   switch(style) {
01683   case ON::euclidean_rational:
01684     Point[dim] = w;
01685     // no break here
01686   case ON::not_rational:
01687     if ( w == 0.0 )
01688       return false;
01689     w = 1.0/w;
01690     while(dim--) *Point++ = *cv++ * w;
01691     break;
01692   case ON::homogeneous_rational:
01693     Point[dim] = w;
01694     memcpy( Point, cv, dim*sizeof(*Point) );
01695     break;
01696   default:
01697     return false;
01698   }
01699   return true;
01700 }
01701 
01702 bool ON_NurbsCage::GetCV( int i, int j, int k, ON_3dPoint& point ) const
01703 {
01704   bool rc = false;
01705   const double* cv = CV(i,j,k);
01706   if ( cv ) {
01707     if ( m_is_rat ) {
01708       if (cv[m_dim] != 0.0) {
01709         const double w = 1.0/cv[m_dim];
01710         point.x = cv[0]*w;
01711         point.y = (m_dim>1)? cv[1]*w : 0.0;
01712         point.z = (m_dim>2)? cv[2]*w : 0.0;
01713         rc = true;
01714       }
01715     }
01716     else {
01717       point.x = cv[0];
01718       point.y = (m_dim>1)? cv[1] : 0.0;
01719       point.z = (m_dim>2)? cv[2] : 0.0;
01720       rc = true;
01721     }
01722   }
01723   return rc;
01724 }
01725 
01726 bool ON_NurbsCage::GetCV( int i, int j, int k, ON_4dPoint& point ) const
01727 {
01728   bool rc = false;
01729   const double* cv = CV(i,j,k);
01730   if ( cv ) {
01731     point.x = cv[0];
01732     point.y = (m_dim>1)? cv[1] : 0.0;
01733     point.z = (m_dim>2)? cv[2] : 0.0;
01734     point.w = (m_is_rat) ? cv[m_dim] : 1.0;
01735     rc = true;
01736   }
01737   return rc;
01738 }
01739 
01740 
01741 
01742 bool ON_NurbsCage::SetKnot(
01743       int dir,
01744       int knot_index,
01745       double knot_value
01746       )
01747 {
01748   bool rc;
01749 
01750   // Validate input so invalid input does not crash Rhino.
01751   // Expert programmers who want to write fast code can directly
01752   // access the m_knot[] arrays.
01753   if (    dir >= 0 && dir < 3 
01754        && 0 != m_knot[dir]
01755        && knot_index >= 0 
01756        && knot_index < m_order[dir]+m_cv_count[dir]-2
01757      )
01758   {
01759     m_knot[dir][knot_index] = knot_value;
01760     rc = true;
01761   }
01762   else
01763   {
01764     ON_ERROR("ON_NurbsCage::SetKnot - invalid input parameters");
01765     rc = false;
01766   }
01767   return rc;
01768 }
01769 
01770 double ON_NurbsCage::Knot(
01771       int dir,
01772       int knot_index
01773       ) const
01774 {
01775   double knot_value;
01776 
01777   // Validate input so invalid input does not crash Rhino.
01778   // Expert programmers who want to write fast code can directly
01779   // access the m_knot[] arrays.
01780   if (    dir >= 0 && dir < 3 
01781        && 0 != m_knot[dir]
01782        && knot_index >= 0 
01783        && knot_index < m_order[dir]+m_cv_count[dir]-2
01784      )
01785   {
01786     knot_value = m_knot[dir][knot_index];
01787   }
01788   else
01789   {
01790     ON_ERROR("ON_NurbsCage::Knot - invalid input parameters");
01791     knot_value = ON_UNSET_VALUE;
01792   }
01793   return knot_value;
01794 }
01795 
01796 bool ON_NurbsCage::ZeroCVs()
01797 {
01798   // zeros control vertices and, if rational, sets weights to 1
01799   bool rc = false;
01800   int i,j,k;
01801   if ( m_cv ) {
01802     if ( m_cv_capacity > 0 ) {
01803       memset( m_cv, 0, m_cv_capacity*sizeof(*m_cv) );
01804       if ( m_is_rat ) {
01805         for ( i = 0; i < m_order[0]; i++ ) {
01806           for ( j = 0; j < m_order[1]; j++ ) {
01807             for ( k = 0; k < m_order[2]; k++ ) {
01808               SetWeight( i,j,k, 1.0 );
01809             }
01810           }
01811         }
01812       }
01813       rc = true;
01814     }
01815     else {
01816       double* cv;
01817       int s = CVSize()*sizeof(*cv);
01818       for ( i = 0; i < m_order[0]; i++ ) {
01819         for ( j = 0; j < m_order[1]; j++ ) {
01820           for ( k = 0; k < m_order[2]; k++ ) {
01821             cv = CV(i,j,k);
01822             memset(cv,0,s);
01823             if ( m_is_rat )
01824               cv[m_dim] = 1.0;
01825           }
01826         }
01827       }
01828       rc = (i>0) ? true : false;
01829     }
01830   }
01831   return rc;
01832 }
01833 
01834 bool ON_NurbsCage::MakeRational()
01835 {
01836   if ( !IsRational() ) 
01837   {
01838     const int dim = Dimension();
01839     if ( m_cv_count[0] > 0 && m_cv_count[1] > 0 && m_cv_count[2] > 0 && dim > 0 ) 
01840     {
01841       int i,j,k;
01842       if ( m_cv_stride[0] <= dim || m_cv_stride[1] <= dim || m_cv_stride[2] <= dim )
01843       {
01844         // there's not room for the weight in the existing m_cv array - adjust the strides
01845         double* new_cv = (double*)onmalloc(m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*(dim+1)*sizeof(*new_cv));
01846         double* cv1 = new_cv;
01847         const int sizeofoldcv = dim*sizeof(*cv1);
01848         for (i = 0; i < m_cv_count[0]; i++) 
01849         {
01850           for(j = 0; j < m_cv_count[1]; j++) 
01851           {
01852             for(k = 0; k < m_cv_count[2]; k++)
01853             {
01854               memcpy(cv1,CV(i,j,k),sizeofoldcv);
01855               cv1 += dim;
01856               *cv1++ = 1.0;
01857             }
01858           }
01859         }
01860         m_is_rat = 1;
01861         ReserveCVCapacity(m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*(dim+1));
01862         memcpy(m_cv,new_cv,m_cv_count[0]*m_cv_count[1]*m_cv_count[2]*(dim+1)*sizeof(*m_cv));
01863         onfree(new_cv);
01864         m_cv_stride[2] = dim+1;
01865         m_cv_stride[1] = m_cv_stride[2]*m_cv_count[2];
01866         m_cv_stride[0] = m_cv_stride[1]*m_cv_count[1];
01867       }
01868       else
01869       {
01870         // there's room for the weight in the existing m_cv array
01871         for (i = 0; i < m_cv_count[0]; i++) 
01872         {
01873           for(j = 0; j < m_cv_count[1]; j++) 
01874           {
01875             for(k = 0; k < m_cv_count[2]; k++)
01876             {
01877               CV(i,j,k)[dim] = 1.0;
01878             }
01879           }
01880         }
01881         m_is_rat = 1;
01882       }
01883     }
01884   }
01885   return IsRational();
01886 }
01887 
01888 bool ON_NurbsCage::MakeNonRational()
01889 {
01890   if ( IsRational() && m_dim > 0 ) 
01891   {
01892     int i,j,k,n;
01893     double* cv;
01894     double w;
01895 
01896     for (i = 0; i < m_cv_count[0]; i++)
01897     for (j = 0; j < m_cv_count[1]; j++)
01898     for (k = 0; k < m_cv_count[2]; k++)
01899     {
01900       cv = CV(i,j,k);
01901       w = cv[m_dim];
01902       if ( w != 1.0 && w != 0.0 )
01903       {
01904         w = 1.0/w;
01905         n = m_dim;
01906         while(n--)
01907         {
01908           *cv++ *= w;
01909         }
01910         *cv = 1.0;
01911       }
01912     }
01913 
01914     m_is_rat = 0;
01915   }
01916   return ( IsRational() ) ? false : true;
01917 }
01918 
01920 // Tools for managing CV and knot memory
01921 bool ON_NurbsCage::ReserveCVCapacity(
01922   int capacity// number of doubles to reserve
01923   )
01924 {
01925   if ( capacity > 0 && m_cv_capacity < capacity ) 
01926   {
01927     if ( m_cv ) 
01928     {
01929       if ( m_cv_capacity ) 
01930       {
01931         m_cv = (double*)onrealloc( m_cv, capacity*sizeof(*m_cv) );
01932         m_cv_capacity = (m_cv) ? capacity : 0;
01933       }
01934       // else user supplied m_cv[] array
01935     }
01936     else 
01937     {
01938       m_cv = (double*)onmalloc( capacity*sizeof(*m_cv) );
01939       m_cv_capacity = (m_cv) ? capacity : 0;
01940     }
01941   }
01942   return ( m_cv ) ? true : false;
01943 }
01944 
01945 bool ON_NurbsCage::ReserveKnotCapacity(
01946   int dir,
01947   int knot_capacity
01948   )
01949 {
01950   bool rc = false;
01951   if ( dir >= 0 && dir <= 2 && knot_capacity > 0 )
01952   {
01953     if ( m_knot_capacity[dir] < knot_capacity )
01954     {
01955       if ( m_knot[dir] )
01956       {
01957         if( m_knot_capacity[dir] )
01958         {
01959           m_knot[dir] = (double*)onrealloc(m_knot[dir],knot_capacity*sizeof(m_knot[dir][0]));
01960           m_knot_capacity[dir] = m_knot[dir] ? knot_capacity : 0;
01961         }
01962         // else user supplied m_knot[dir] array.
01963       }
01964       else
01965       {
01966         m_knot[dir] = (double*)onmalloc(knot_capacity*sizeof(m_knot[dir][0]));
01967         m_knot_capacity[dir] = m_knot[dir] ? knot_capacity : 0;
01968       }
01969     }
01970     rc = m_knot[dir] != 0;
01971   }
01972   return rc;
01973 }
01974 
01975 
01976 
01977 bool ON_NurbsCage::IsSingular(           // true if surface side is collapsed to a point
01978        int //side                                                                                                                // side of parameter space to test
01979                                                                                                                                                         // 0 = south, 1 = east, 2 = north, 3 = west, 4 = bottom, 5 =top
01980                                 ) const
01981 {
01982   ON_ERROR("TODO: fill in ON_NurbsCage::IsSingular\n");
01983   return false;
01984 }
01985 
01986 bool ON_GetCageXform( const ON_NurbsCage& cage, ON_Xform& cage_xform )
01987 {
01988   bool rc = false;
01989   cage_xform.Identity();
01990   if ( cage.IsValid() )
01991   {
01992     ON_3dPoint P000, P100, P010, P001;
01993     if ( !cage.GetCV(0,0,0,P000) )
01994       return false;
01995     if ( !cage.GetCV(cage.CVCount(0)-1,0,0,P100))
01996       return false;
01997     if (!cage.GetCV(0,cage.CVCount(1)-1,0,P010))
01998       return false;
01999     if (!cage.GetCV(0,0,cage.CVCount(2)-1,P001))
02000       return false;
02001 
02002     ON_3dVector X0 = P100 - P000;
02003     ON_3dVector Y0 = P010 - P000;
02004     ON_3dVector Z0 = P001 - P000;
02005 
02006     double dx0 = X0.Length();
02007     double dy0 = Y0.Length();
02008     double dz0 = Z0.Length();
02009 
02010     ON_Interval d0 = cage.Domain(0);
02011     ON_Interval d1 = cage.Domain(1);
02012     ON_Interval d2 = cage.Domain(2);
02013 
02014     X0.Unitize();
02015     Y0.Unitize();
02016     Z0.Unitize();
02017 
02018     ON_Xform x1;
02019     x1.Rotation( 
02020       P000, X0, Y0, Z0, 
02021       ON_origin, ON_xaxis, ON_yaxis, ON_zaxis 
02022       );
02023 
02024     ON_Xform x2;
02025     x2.Scale( d0.Length()/dx0, d1.Length()/dy0, d2.Length()/dz0 );
02026       
02027     ON_Xform x3;
02028     x3.Translation( d0[0],d1[0],d2[0]);
02029 
02030 
02031     cage_xform = x3*(x2*x1);
02032     rc = true;
02033   }
02034   return rc;
02035 }
02036 
02037 ON_CageMorph::ON_CageMorph()
02038 {
02039   m_control = 0;
02040 }
02041 
02042 ON_CageMorph::~ON_CageMorph()
02043 {
02044   m_control = 0;
02045 }
02046 
02047 bool ON_MorphControl::IsIdentity( const ON_BoundingBox& bbox ) const
02048 {
02049   int i, count = m_localizers.Count();
02050   bool rc = (count > 0);
02051   for (i = 0; i < count && rc; i++ )
02052   {
02053     rc = m_localizers[i].IsZero(bbox);
02054   }
02055   return rc;
02056 }
02057 
02058 bool ON_CageMorph::IsIdentity( const ON_BoundingBox& bbox ) const
02059 {
02060   return m_control ? m_control->IsIdentity(bbox) : true;
02061 }
02062 
02063 ON_MorphControl::ON_MorphControl() 
02064                 : m_varient(0),
02065                   m_nurbs_cage0(1.0)
02066 {
02067   m_sporh_tolerance          = 0.0;
02068   m_sporh_bQuickPreview      = false;
02069   m_sporh_bPreserveStructure = false;
02070 }
02071 
02072 
02073 ON_MorphControl::~ON_MorphControl()
02074 {
02075 }
02076 
02077 void ON_MorphControl::Destroy()
02078 {
02079   m_varient = 0;
02080   m_nurbs_cage0.Identity();
02081   m_nurbs_curve0.Destroy();
02082   m_nurbs_curve.Destroy();
02083   m_nurbs_curve_domain.Destroy();
02084   m_nurbs_surface0.Destroy();
02085   m_nurbs_surface.Destroy();
02086   m_nurbs_surface_domain[0].Destroy();
02087   m_nurbs_surface_domain[1].Destroy();
02088   m_nurbs_cage.Destroy();
02089   m_captive_id.Empty();
02090   m_localizers.Destroy();
02091   m_sporh_tolerance = 0.0;
02092   m_sporh_bQuickPreview = false;
02093   m_sporh_bPreserveStructure = false;
02094 }
02095 
02096 
02097 void ON_MorphControl::MemoryRelocate()
02098 {
02099   m_nurbs_curve0.MemoryRelocate();
02100   m_nurbs_curve.MemoryRelocate();
02101   m_nurbs_surface0.MemoryRelocate();
02102   m_nurbs_surface.MemoryRelocate();
02103   m_nurbs_cage.MemoryRelocate();
02104   ON_Geometry::MemoryRelocate();
02105 }
02106 
02107 ON_BOOL32 ON_MorphControl::IsValid( ON_TextLog* text_log ) const
02108 {
02109   ON_BOOL32 rc = false;
02110   switch(m_varient)
02111   {
02112   case 1:
02113     rc = m_nurbs_curve0.IsValid(text_log);
02114     if (rc)
02115       rc = m_nurbs_curve.IsValid(text_log);
02116     break;
02117 
02118   case 2:
02119     rc = m_nurbs_surface0.IsValid(text_log);
02120     if (rc)
02121       rc = m_nurbs_surface.IsValid(text_log);
02122     break;
02123 
02124   case 3:
02125     rc = m_nurbs_cage.IsValid(text_log);
02126     break;
02127 
02128   default:
02129     rc = false;
02130     if ( text_log )
02131     {
02132       text_log->Print("m_varient = %d - should be 1, 2, or 3\n",m_varient);
02133     }
02134     break;
02135   }
02136   return rc;
02137 }
02138 
02139 void ON_MorphControl::Dump( ON_TextLog& text_log ) const
02140 {
02141   text_log.Print("Varient: %d\n",m_varient);
02142   text_log.Print("Control object:\n");
02143   text_log.PushIndent();
02144   switch(m_varient)
02145   {
02146   case 1:
02147     m_nurbs_curve0.Dump(text_log);
02148     m_nurbs_curve.Dump(text_log);
02149     break;
02150   case 2:
02151     m_nurbs_surface0.Dump(text_log);
02152     m_nurbs_surface.Dump(text_log);
02153     break;
02154   case 3:
02155     text_log.Print(m_nurbs_cage0);
02156     m_nurbs_cage.Dump(text_log);
02157     break;
02158   }
02159   text_log.PopIndent();
02160 }
02161 
02162 unsigned int ON_MorphControl::SizeOf() const
02163 {
02164   unsigned int sz = sizeof(*this) 
02165                   - 2*sizeof(ON_NurbsCurve) 
02166                   - 2*sizeof(ON_NurbsSurface) 
02167                   - sizeof(m_nurbs_cage);
02168   sz += m_nurbs_curve0.SizeOf();
02169   sz += m_nurbs_curve.SizeOf();
02170   sz += m_nurbs_surface0.SizeOf();
02171   sz += m_nurbs_surface.SizeOf();
02172   sz += m_nurbs_cage.SizeOf();
02173   sz += m_localizers.SizeOfArray();
02174 
02175   return sz;
02176 }
02177 
02178 
02179 ON::object_type ON_MorphControl::ObjectType() const
02180 {
02181   return ON::morph_control_object;
02182 }
02183 
02184 void ON_MorphControl::DestroyRuntimeCache( bool bDelete )
02185 {
02186   m_nurbs_curve.DestroyRuntimeCache(bDelete);
02187   m_nurbs_surface.DestroyRuntimeCache(bDelete);
02188   m_nurbs_cage.DestroyRuntimeCache(bDelete);
02189 }
02190 
02191 int ON_MorphControl::Dimension() const
02192 {
02193   int dim = 0;
02194   switch(m_varient)
02195   {
02196   case 1:
02197     dim = m_nurbs_curve.Dimension();
02198     break;
02199   case 2:
02200     dim = m_nurbs_surface.Dimension();
02201     break;
02202   case 3:
02203     dim = m_nurbs_cage.Dimension();
02204     break;
02205   }
02206   return dim;
02207 }
02208 
02209 ON_BOOL32 ON_MorphControl::GetBBox(
02210         double* boxmin,
02211         double* boxmax,
02212         int bGrowBox
02213         ) const
02214 {
02215   ON_BOOL32 rc = false;
02216   switch(m_varient)
02217   {
02218   case 1:
02219     rc = m_nurbs_curve.GetBBox(boxmin,boxmax,bGrowBox);
02220     break;
02221   case 2:
02222     rc = m_nurbs_surface.GetBBox(boxmin,boxmax,bGrowBox);
02223     break;
02224   case 3:
02225     rc = m_nurbs_cage.GetBBox(boxmin,boxmax,bGrowBox);
02226     break;
02227   }
02228   return rc;
02229 }
02230 
02231 bool ON_MorphControl::GetTightBoundingBox( 
02232                 ON_BoundingBox& tight_bbox, 
02233     int bGrowBox,
02234                 const ON_Xform* xform
02235     ) const
02236 {
02237   bool rc = false;
02238   switch(m_varient)
02239   {
02240   case 1:
02241     rc = m_nurbs_curve.GetTightBoundingBox(tight_bbox,bGrowBox);
02242     break;
02243   case 2:
02244     rc = m_nurbs_surface.GetTightBoundingBox(tight_bbox,bGrowBox);
02245     break;
02246   case 3:
02247     rc = m_nurbs_cage.GetTightBoundingBox(tight_bbox,bGrowBox);
02248     break;
02249   }
02250   return rc;
02251 }
02252 
02253 void ON_MorphControl::ClearBoundingBox()
02254 {
02255 }
02256 
02257 ON_BOOL32 ON_MorphControl::Transform( 
02258         const ON_Xform& xform
02259         )
02260 {
02261   ON_BOOL32 rc = false;
02262 
02263   switch(m_varient)
02264   {
02265   case 1:
02266     rc = m_nurbs_curve.Transform(xform);
02267     break;
02268 
02269   case 2:
02270     rc = m_nurbs_surface.Transform(xform);
02271     break;
02272 
02273   case 3:
02274     rc = m_nurbs_cage.Transform(xform);
02275     break;
02276   }
02277 
02278   return rc;
02279 }
02280 
02281 ON_BOOL32 ON_MorphControl::HasBrepForm() const
02282 {
02283   ON_BOOL32 rc = false;
02284 
02285   switch(m_varient)
02286   {
02287   case 1:
02288     rc = m_nurbs_curve.HasBrepForm();
02289     break;
02290 
02291   case 2:
02292     rc = m_nurbs_surface.HasBrepForm();
02293     break;
02294 
02295   case 3:
02296     rc = m_nurbs_cage.HasBrepForm();
02297     break;
02298   }
02299 
02300   return rc;
02301 }
02302 
02303 ON_Brep* ON_MorphControl::BrepForm( ON_Brep* brep ) const
02304 {
02305   switch(m_varient)
02306   {
02307   case 1:
02308     brep = m_nurbs_curve.BrepForm(brep);
02309     break;
02310 
02311   case 2:
02312     brep = m_nurbs_surface.BrepForm(brep);
02313     break;
02314 
02315   case 3:
02316     brep = m_nurbs_cage.BrepForm(brep);
02317     break;
02318 
02319   default:
02320     brep = 0;
02321     break;
02322   }
02323 
02324   return brep;
02325 }
02326 
02327 
02328 bool ON_MorphControl::IsRational() const
02329 {
02330   bool rc = false;
02331   switch(m_varient)
02332   {
02333   case 1:
02334     rc = m_nurbs_curve.IsRational();
02335     break;
02336   case 2:
02337     rc = m_nurbs_surface.IsRational();
02338     break;
02339   case 3:
02340     rc = m_nurbs_cage.IsRational();
02341     break;
02342   }
02343   return rc;
02344 }
02345 
02346 bool ON_MorphControl::MakeRational()
02347 {
02348   bool rc = false;
02349   switch(m_varient)
02350   {
02351   case 1:
02352     rc = m_nurbs_curve.MakeRational();
02353     break;
02354   case 2:
02355     rc = m_nurbs_surface.MakeRational();
02356     break;
02357   case 3:
02358     rc = m_nurbs_cage.MakeRational();
02359     break;
02360   }
02361   return rc;
02362 }
02363 
02364 bool ON_MorphControl::MakeNonRational()
02365 {
02366   bool rc = false;
02367   switch(m_varient)
02368   {
02369   case 1:
02370     rc = m_nurbs_curve.MakeNonRational();
02371     break;
02372   case 2:
02373     rc = m_nurbs_surface.MakeNonRational();
02374     break;
02375   case 3:
02376     rc = m_nurbs_cage.MakeNonRational();
02377     break;
02378   }
02379   return rc;
02380 }
02381 
02382 int ON_MorphControl::CVCount() const
02383 {
02384   int rc = 0;
02385   switch(m_varient)
02386   {
02387   case 1:
02388     rc = m_nurbs_curve.CVCount();
02389     break;
02390   case 2:
02391     rc = m_nurbs_surface.CVCount();
02392     break;
02393   case 3:
02394     rc = m_nurbs_cage.CVCount();
02395     break;
02396   }
02397   return rc;
02398 }
02399 
02400 int ON_MorphControl::CVCount(int dir) const
02401 {
02402   int rc = 0;
02403   switch(m_varient)
02404   {
02405   case 1:
02406     rc = (0==dir) ? m_nurbs_curve.CVCount() : 0;
02407     break;
02408   case 2:
02409     rc = m_nurbs_surface.CVCount(dir);
02410     break;
02411   case 3:
02412     rc = m_nurbs_cage.CVCount(dir);
02413     break;
02414   }
02415   return rc;
02416 }
02417 
02418 int ON_MorphControl::Order(int dir) const
02419 {
02420   int rc = 0;
02421   switch(m_varient)
02422   {
02423   case 1:
02424     rc = (0==dir) ? m_nurbs_curve.Order() : 0;
02425     break;
02426   case 2:
02427     rc = m_nurbs_surface.Order(dir);
02428     break;
02429   case 3:
02430     rc = m_nurbs_cage.Order(dir);
02431     break;
02432   }
02433   return rc;
02434 }
02435 
02436 ON_3dex ON_MorphControl::MaxCVIndex() const
02437 {
02438   ON_3dex maxdex;
02439   maxdex.i = maxdex.j = maxdex.k = 0;
02440   switch(m_varient)
02441   {
02442   case 1:
02443     maxdex.i = m_nurbs_curve.CVCount();
02444     maxdex.j = maxdex.k = 1;
02445     break;
02446   case 2:
02447     maxdex.i = m_nurbs_surface.CVCount(0);
02448     maxdex.j = m_nurbs_surface.CVCount(1);
02449     maxdex.k = 1;
02450     break;
02451   case 3:
02452     maxdex.i = m_nurbs_cage.CVCount(0);
02453     maxdex.j = m_nurbs_cage.CVCount(1);
02454     maxdex.k = m_nurbs_cage.CVCount(2);
02455     break;
02456   }
02457   return maxdex;
02458 }
02459 
02460 const double* ON_MorphControl::Knot(int dir) const
02461 {
02462   const double* knot = 0;
02463 
02464   switch(m_varient)
02465   {
02466   case 1:
02467     knot = (0 == dir) ? m_nurbs_curve.m_knot : 0;
02468     break;
02469   case 2:
02470     knot = (0 == dir || 1 == dir) ? m_nurbs_surface.m_knot[dir] : 0;
02471     break;
02472   case 3:
02473     knot = (0 <= dir && dir <= 2) ? m_nurbs_cage.m_knot[dir] : 0;
02474     break;
02475   }
02476 
02477   return knot;
02478 }
02479 
02480 const double* ON_MorphControl::CV(ON_3dex ijk) const
02481 {
02482   const double* cv = 0;
02483   switch(m_varient)
02484   {
02485   case 1:
02486     cv = (0 == ijk.j && 0 == ijk.k) ? m_nurbs_curve.CV(ijk.i) : 0;
02487     break;
02488   case 2:
02489     cv = (0 == ijk.k) ? m_nurbs_surface.CV(ijk.i,ijk.j) : 0;
02490     break;
02491   case 3:
02492     cv = m_nurbs_cage.CV(ijk.i,ijk.j,ijk.k);
02493     break;
02494   }
02495   return cv;
02496 }
02497 
02498 double ON_MorphControl::Weight(ON_3dex ijk) const
02499 {
02500   double w = 1.0;
02501 
02502   switch(m_varient)
02503   {
02504   case 1:
02505     w = (0 == ijk.j && 0 == ijk.k) ? m_nurbs_curve.Weight(ijk.i) : 1.0;
02506     break;
02507   case 2:
02508     w = (0 == ijk.k) ? m_nurbs_surface.Weight(ijk.i,ijk.j) : 1.0;
02509     break;
02510   case 3:
02511     w = m_nurbs_cage.Weight(ijk.i,ijk.j,ijk.k);
02512     break;
02513   }
02514 
02515   return w;
02516 }
02517 
02518 bool ON_MorphControl::GetCageMorph(ON_CageMorph& cage_morph) const
02519 {
02520   cage_morph.m_control = this;
02521   cage_morph.SetPreserveStructure(m_sporh_bPreserveStructure);
02522   cage_morph.SetQuickPreview(m_sporh_bQuickPreview);
02523   cage_morph.SetTolerance(m_sporh_tolerance);
02524   return true;
02525 }
02526 
02527 ON_BOOL32 ON_MorphControl::Read( ON_BinaryArchive& archive )
02528 {
02529   Destroy();
02530   int major_version = 0;
02531   int minor_version = 0;
02532   bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,
02533                                       &major_version,
02534                                       &minor_version);
02535   while(rc)
02536   {
02537     if ( 1 == major_version )
02538     {
02539       m_varient = 3;
02540       if (rc)
02541         rc = m_nurbs_cage.Read(archive)?true:false;
02542       if (rc)
02543         rc = m_captive_id.Read(archive);
02544       if (rc)
02545         rc = archive.ReadXform(m_nurbs_cage0);
02546     }
02547     else if ( 2 == major_version )
02548     {
02549       rc = archive.ReadInt(&m_varient);
02550       if (!rc) break;
02551 
02552       int mjv = 0;
02553       int mnv = 0;
02554       rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&mjv,&mnv);
02555       if (!rc) break;
02556       rc = (1 == mjv);
02557       if (rc)
02558       {
02559         switch(m_varient)
02560         {
02561         case 1:
02562           rc = m_nurbs_curve0.Read(archive)?true:false;
02563           if (rc)
02564             m_nurbs_curve_domain = m_nurbs_curve0.Domain();
02565           break;
02566         case 2:
02567           rc = m_nurbs_surface0.Read(archive)?true:false;
02568           if (rc)
02569           {
02570             m_nurbs_surface_domain[0] = m_nurbs_surface0.Domain(0);
02571             m_nurbs_surface_domain[1] = m_nurbs_surface0.Domain(1);
02572           }
02573           break;
02574         case 3:
02575           rc = archive.ReadXform(m_nurbs_cage0);
02576           break;
02577         }
02578       }
02579       if ( !archive.EndRead3dmChunk() )
02580         rc = false;
02581 
02582       if(!rc)
02583         break;
02584 
02585       mjv = 0;
02586       mnv = 0;
02587       rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&mjv,&mnv);
02588       if (!rc) break;
02589       rc = (1 == mjv);
02590       if (rc)
02591       {
02592         switch(m_varient)
02593         {
02594         case 1:
02595           rc = m_nurbs_curve.Read(archive)?true:false;
02596           break;
02597         case 2:
02598           rc = m_nurbs_surface.Read(archive)?true:false;
02599           break;
02600         case 3:
02601           rc = m_nurbs_cage.Read(archive)?true:false;
02602           break;
02603         }
02604       }
02605       if ( !archive.EndRead3dmChunk() )
02606         rc = false;
02607 
02608       // captive ids
02609       rc = m_captive_id.Read(archive);
02610       if (!rc)
02611         break;
02612 
02613       // localizers
02614       mjv = 0;
02615       mnv = 0;
02616       rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&mjv,&mnv);
02617       if (!rc) 
02618         break;
02619       int i, count = 0;
02620       rc = (1 == mjv);
02621       if (rc)
02622         rc = archive.ReadInt(&count);
02623       if (rc)
02624         m_localizers.Reserve(count);
02625       for ( i = 0; i < count && rc; i++ )
02626       {
02627         m_localizers.AppendNew();
02628         rc = m_localizers[i].Read(archive);
02629       }
02630       if ( !archive.EndRead3dmChunk() )
02631         rc = false;
02632       if ( !rc)
02633         break;
02634 
02635       if ( minor_version >= 1 )
02636       {
02637         rc = archive.ReadDouble(&m_sporh_tolerance);
02638         if (!rc) 
02639           break;
02640         rc = archive.ReadBool(&m_sporh_bQuickPreview);
02641         if (!rc) 
02642           break;
02643         rc = archive.ReadBool(&m_sporh_bPreserveStructure);
02644         if (!rc) 
02645           break;
02646       }
02647     }
02648     else
02649     {
02650       rc = false;
02651     }
02652 
02653     if ( !archive.EndRead3dmChunk() )
02654       rc = false;
02655     break;
02656   }
02657 
02658   return rc;
02659 }
02660 
02661 ON_BOOL32 ON_MorphControl::Write( ON_BinaryArchive& archive ) const
02662 {
02663   bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,2,1);
02664   if (!rc)
02665     return false;
02666 
02667   while(rc)
02668   {
02669     rc = archive.WriteInt(m_varient);
02670     if (!rc) break;
02671 
02672     // control start location
02673     rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
02674     if (!rc) break;
02675     switch(m_varient)
02676     {
02677     case 1:
02678       rc = m_nurbs_curve0.Write(archive)?true:false;
02679       break;
02680     case 2:
02681       rc = m_nurbs_surface0.Write(archive)?true:false;
02682       break;
02683     case 3:
02684       rc = archive.WriteXform(m_nurbs_cage0);
02685       break;
02686     }
02687     if ( !archive.EndWrite3dmChunk() )
02688       rc = false;
02689 
02690     if(!rc)
02691       break;
02692 
02693     // control end location
02694     rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
02695     if (!rc) break;
02696     switch(m_varient)
02697     {
02698     case 1:
02699       rc = m_nurbs_curve.Write(archive)?true:false;
02700       break;
02701     case 2:
02702       rc = m_nurbs_surface.Write(archive)?true:false;
02703       break;
02704     case 3:
02705       rc = m_nurbs_cage.Write(archive)?true:false;
02706       break;
02707     }
02708     if ( !archive.EndWrite3dmChunk() )
02709       rc = false;
02710 
02711     if ( !rc)
02712       break;
02713 
02714     // captive ids
02715     rc = m_captive_id.Write(archive);
02716     if (!rc)
02717       break;
02718 
02719     // localizers
02720     rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
02721     if (!rc) 
02722       break;
02723     int i, count = m_localizers.Count();
02724     rc = archive.WriteInt(count);
02725     for ( i = 0; i < count && rc; i++ )
02726     {
02727       rc = m_localizers[i].Write(archive);
02728     }
02729     if ( !archive.EndWrite3dmChunk() )
02730       rc = false;
02731     if ( !rc)
02732       break;
02733 
02734     // 2.1 fields 
02735     rc = archive.WriteDouble(m_sporh_tolerance);
02736     if (!rc) 
02737       break;
02738     rc = archive.WriteBool(m_sporh_bQuickPreview);
02739     if (!rc) 
02740       break;
02741     rc = archive.WriteBool(m_sporh_bPreserveStructure);
02742     if (!rc) 
02743       break;
02744 
02745     break;
02746   }
02747 
02748   if ( !archive.EndWrite3dmChunk() )
02749     rc = false;
02750 
02751   return rc;
02752 }
02753 
02754 bool ON_MorphControl::AddControlLocalizer(
02755   double support_distance, 
02756   double falloff_distance
02757   )
02758 {
02759   bool rc = (support_distance >= 0.0 && falloff_distance > 0.0 );
02760   if (rc)
02761   {
02762     switch(m_varient)
02763     {
02764     case 1:
02765     case 2:
02766       {
02767         ON_Localizer& localizer = m_localizers.AppendNew();
02768         localizer.m_type = ON_Localizer::distance_type;
02769         localizer.m_d.Set(support_distance+falloff_distance,support_distance);
02770         rc = true;
02771       }
02772       break;
02773 
02774     case 3:
02775       {
02776         ON_Xform xform = m_nurbs_cage0;
02777         xform.Invert();
02778         ON_Interval d[3];
02779         d[0] = m_nurbs_cage.Domain(0);
02780         d[1] = m_nurbs_cage.Domain(1);
02781         d[2] = m_nurbs_cage.Domain(2);
02782 
02783         ON_SimpleArray<ON_Plane> planes(6);
02784 
02785         ON_3dPoint C(d[0].ParameterAt(0.5),d[1].ParameterAt(0.5),d[2].ParameterAt(0.5));
02786         ON_3dPoint P;
02787         ON_3dVector N;
02788         int i;
02789         double det = (xform.Determinant() < 0.0) ? -1.0 : 1.0;
02790         for ( i = 0; i < 3; i++ )
02791         {
02792           P = C;
02793           N.Zero();
02794 
02795           N[i] = -det;
02796           P[i] = d[i][0];
02797           ON_Plane& plane0 = planes.AppendNew();
02798           plane0.CreateFromNormal(P,N);
02799           plane0.Transform(xform);
02800 
02801           P[i] = d[i][1];
02802           N[i] = det;
02803           ON_Plane& plane1 = planes.AppendNew();
02804           plane1.CreateFromNormal(P,N);
02805           plane1.Transform(xform);
02806         }
02807 
02808         rc = AddConvexPolygonLocalizer(planes,support_distance,falloff_distance);
02809       }
02810       break;
02811 
02812     default:
02813       rc = false;
02814       break;
02815     }
02816   }
02817   return rc;
02818 }
02819 
02820 bool ON_MorphControl::AddSphereLocalizer(
02821   ON_3dPoint center,
02822   double support_distance, 
02823   double falloff_distance
02824   )
02825 {
02826   bool rc = (center.IsValid() && support_distance >= 0.0 && falloff_distance > 0.0 );
02827   if (rc)
02828   {
02829     ON_Localizer& localizer = m_localizers.AppendNew();
02830     rc = localizer.CreateSphereLocalizer(
02831                   center,
02832                   support_distance+falloff_distance,
02833                   support_distance);
02834   }
02835   return rc;
02836 }
02837 
02838 bool ON_MorphControl::AddCylinderLocalizer(
02839   ON_Line axis,
02840   double support_distance, 
02841   double falloff_distance
02842   )
02843 {
02844   bool rc = (axis.IsValid() && support_distance >= 0.0 && falloff_distance > 0.0 );
02845   if (rc)
02846   {
02847     ON_Localizer& localizer = m_localizers.AppendNew();
02848     rc = localizer.CreateCylinderLocalizer(
02849                   axis.from,axis.Tangent(),
02850                   support_distance+falloff_distance,
02851                   support_distance);
02852   }
02853   return rc;
02854 }
02855 
02856 bool ON_MorphControl::AddBoxLocalizer(
02857   ON_BoundingBox bbox,
02858   double support_distance, 
02859   double falloff_distance
02860   )
02861 {
02862   ON_SimpleArray<ON_Plane> planes(6);
02863   bool rc = (bbox.IsValid() && support_distance >= 0.0 && falloff_distance > 0.0 );
02864   if (rc)
02865   {
02866     ON_3dPoint C = bbox.Center();
02867     ON_3dVector N;
02868     ON_3dPoint P;
02869     int i;
02870     for ( i = 0; i < 3; i++ )
02871     {
02872       P = C;
02873       N.Zero();
02874       ON_Plane& plane0 = planes.AppendNew();
02875       P[i] = bbox.m_min[i];
02876       N[i] = -1.0;
02877       plane0.CreateFromNormal(P,N);
02878 
02879       ON_Plane& plane1 = planes.AppendNew();
02880       P[i] = bbox.m_max[i];
02881       N[i] = 1.0;
02882       plane1.CreateFromNormal(P,N);
02883     }
02884     rc = AddConvexPolygonLocalizer(planes,support_distance,falloff_distance);
02885   }
02886   return rc;
02887 }
02888 
02889 bool ON_MorphControl::AddPlaneLocalizer(
02890             const ON_Plane& plane,
02891             double support_distance, 
02892             double falloff_distance
02893             )
02894 {
02895   ON_SimpleArray<ON_Plane> planes(1);
02896   planes.Append(plane);
02897   return AddConvexPolygonLocalizer(planes,support_distance,falloff_distance);
02898 }
02899 
02900 bool ON_MorphControl::AddConvexPolygonLocalizer(
02901   const ON_SimpleArray<ON_Plane>& planes,
02902   double support_distance, 
02903   double falloff_distance
02904   )
02905 {
02906   int i, count = planes.Count();
02907   bool rc = (support_distance >= 0.0 && falloff_distance > 0.0 );
02908   if (rc)
02909   {
02910     m_localizers.Reserve(m_localizers.Count() + count);
02911     for( i = 0; i < count && rc; i++)
02912     {
02913       const ON_Plane& plane = planes[i];
02914       ON_Localizer& localizer = m_localizers.AppendNew();
02915       rc = localizer.CreatePlaneLocalizer(
02916                     plane.origin,plane.zaxis,
02917                     support_distance+falloff_distance,
02918                     support_distance);
02919     }
02920   }
02921   return rc;
02922 }
02923 


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