opennurbs_bezier.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 
00021 
00022 bool ON_BezierCurve::GetTightBoundingBox( 
00023                 ON_BoundingBox& tight_bbox, 
00024     int bGrowBox,
00025                 const ON_Xform* xform
00026     ) const
00027 {
00028   // The result from ON_GetPointListBoundingBox() is good enough
00029   // for file IO needs in the public souce code version.
00030   return ON_GetPointListBoundingBox(
00031     m_dim,
00032     m_is_rat, 
00033     m_order, 
00034     m_cv_stride,
00035     m_cv,
00036     tight_bbox,
00037     bGrowBox,
00038     xform 
00039     );
00040 }
00041 
00043 
00044 ON_PolynomialCurve::ON_PolynomialCurve()
00045                    : m_dim(0), m_is_rat(0), m_order(0), m_domain(0.0,1.0)
00046 {}
00047 
00048 ON_PolynomialCurve::ON_PolynomialCurve( int dim, ON_BOOL32 is_rat, int order )
00049                    : m_dim(0), m_is_rat(0), m_order(0), m_domain(0.0,1.0)
00050 {
00051   Create( dim, is_rat, order );
00052 }
00053 
00054 ON_PolynomialCurve::~ON_PolynomialCurve()
00055 {
00056   Destroy();
00057 }
00058 
00059 ON_PolynomialCurve::ON_PolynomialCurve(const ON_PolynomialCurve& src)
00060                    : m_dim(0), m_is_rat(0), m_order(0), m_domain(0.0,1.0)
00061 {
00062   *this = src;
00063 }
00064 
00065 ON_PolynomialCurve::ON_PolynomialCurve(const ON_BezierCurve& src)
00066                    : m_dim(0), m_is_rat(0), m_order(0), m_domain(0.0,1.0)
00067 {
00068   *this = src;
00069 }
00070 
00071 ON_BOOL32 ON_PolynomialCurve::Create( int dim, ON_BOOL32 is_rat, int order )
00072 {
00073   ON_BOOL32 rc = true;
00074   if ( dim > 0 ) m_dim = dim; else {m_dim = 0; rc = false;}
00075   m_is_rat = is_rat?1:0;
00076   if ( order >= 1 ) m_order = order; else {m_order = 0; rc = false;}
00077   m_cv.SetCapacity(m_order);
00078   m_domain.m_t[0] = 0.0;
00079   m_domain.m_t[1] = 1.0;
00080   return rc;
00081 }
00082 
00083 void ON_PolynomialCurve::Destroy()
00084 {
00085   m_dim = 0;
00086   m_is_rat = 0;
00087   m_order = 0;
00088   m_cv.Destroy();
00089   m_domain.m_t[0] = 0.0;
00090   m_domain.m_t[1] = 1.0;
00091 }
00092 
00093 
00094 ON_PolynomialCurve& ON_PolynomialCurve::operator=(const ON_PolynomialCurve& src)
00095 {
00096   if ( this != &src ) {
00097     m_dim = src.m_dim;
00098     m_is_rat = src.m_is_rat;
00099     m_order = src.m_order;
00100     m_cv = src.m_cv;
00101     m_domain = src.m_domain;
00102   }
00103   return *this;
00104 }
00105 
00106 ON_PolynomialCurve& ON_PolynomialCurve::operator=(const ON_BezierCurve& src)
00107 {
00108   int i;
00109   double d;
00110   m_dim = src.m_dim;
00111   m_is_rat = src.m_is_rat;
00112   m_order = src.m_order;
00113   m_cv.Reserve( src.m_order );
00114   m_cv.SetCount( src.m_order );
00115   m_cv.Zero();
00116   //m_domain = src.m_domain;
00117 
00118   if ( m_order >= 2 && src.CVSize() <= 4 ) {
00119     ON_BezierCurve s; // scratch surface for homogeneous evaluation
00120     s.m_dim = src.m_is_rat ? src.m_dim+1 : src.m_dim;
00121     s.m_is_rat = 0;
00122     s.m_order = src.m_order;
00123     s.m_cv = src.m_cv;
00124     //s.m_domain.m_t[0] = 0.0;
00125     //s.m_domain.m_t[1] = 1.0;
00126     if ( s.Evaluate( 0.0, m_order-1, 4, &m_cv[0].x ) ) {
00127       if ( m_is_rat ) {
00128         if ( m_dim < 3 ) {
00129           for ( i = 0; i < m_order; i++ ) {
00130             ON_4dPoint& cv = m_cv[i];
00131             cv.w = cv[m_dim];
00132             cv[m_dim] = 0.0;
00133           }
00134         }
00135       }
00136       else {
00137         m_cv[0].w = 1.0;
00138       }
00139       for ( i = 2; i < m_order; i++ ) {
00140         d = 1.0/i;
00141         ON_4dPoint& cv = m_cv[i];
00142         cv.x *= d;
00143         cv.y *= d;
00144         cv.z *= d;
00145         cv.w *= d;
00146       }
00147     }
00148     else {
00149       m_cv.Zero();
00150       m_cv[0].w = 1.0;
00151     }
00152     s.m_cv = 0;
00153   }
00154 
00155   return *this;
00156 }
00157 
00158 ON_BOOL32 ON_PolynomialCurve::Evaluate( // returns false if unable to evaluate
00159        double t,         // evaluation parameter
00160        int der_count,    // number of derivatives (>=0)
00161        int v_stride,     // array stride (>=Dimension())
00162        double* v         // array of length stride*(ndir+1)
00163        ) const
00164 {
00165   ON_BOOL32 rc = false;
00166   if ( m_order >= 1 && m_cv.Count() == m_order )
00167   {
00168     if ( m_domain.m_t[0] != 0.0 || m_domain.m_t[1] != 1.0 ) 
00169     {
00170       t = (1.0-t)*m_domain.m_t[0] + t*m_domain.m_t[1];
00171     }
00172     ON_4dPointArray p(der_count+1);
00173     ON_4dPoint c;
00174     double s;
00175     int i, j, der;
00176     p.Zero();
00177     for ( i = m_order-1; i >= 0; i-- ) {
00178       c = m_cv[i];
00179       p[0].x = t*p[0].x + c.x;
00180       p[0].y = t*p[0].y + c.y;
00181       p[0].z = t*p[0].z + c.z;
00182       p[0].w = t*p[0].w + c.w;
00183     }
00184     if ( der_count >= 1 ) {
00185       for ( i = m_order-1; i >= 1; i-- ) {
00186         c = m_cv[i];
00187         p[1].x = t*p[1].x + i*c.x;
00188         p[1].y = t*p[1].y + i*c.y;
00189         p[1].z = t*p[1].z + i*c.z;
00190         p[1].w = t*p[1].w + i*c.w;
00191       }
00192       for ( der = 2; der <= der_count; der++ ) {
00193         for ( i = m_order-1; i >= der; i-- ) {
00194           s = i;
00195           for ( j = 1; j < der; j++ ) {
00196             s *= (i-j);
00197           }
00198           c = m_cv[i];
00199           p[der].x = t*p[der].x + s*c.x;
00200           p[der].y = t*p[der].y + s*c.y;
00201           p[der].z = t*p[der].z + s*c.z;
00202           p[der].w = t*p[der].w + s*c.w;
00203         }
00204       }
00205       if ( m_is_rat ) {
00206         ON_EvaluateQuotientRule( 3, der_count, 4, &p[0].x );
00207       }
00208     }
00209     const int sz = m_dim*sizeof(v[0]);
00210     for ( i = 0; i <= der_count; i++ ) {
00211       memcpy( v, &p[i].x, sz );
00212       v += v_stride;
00213     }
00214     rc = true;
00215   }
00216   return rc;
00217 }
00218 
00219 ON_PolynomialSurface::ON_PolynomialSurface() : m_dim(0), m_is_rat(0)
00220 {
00221   m_order[0] = 0;
00222   m_order[1] = 0;
00223   m_domain[0].m_t[0] = 0.0;
00224   m_domain[0].m_t[1] = 1.0;
00225   m_domain[1].m_t[0] = 0.0;
00226   m_domain[1].m_t[1] = 1.0;
00227 }
00228 
00229 ON_PolynomialSurface::ON_PolynomialSurface( int dim, ON_BOOL32 is_rat, int order0, int order1 )
00230 {
00231   Create( dim, is_rat, order0, order1 );
00232 }
00233 
00234 ON_PolynomialSurface::~ON_PolynomialSurface()
00235 {
00236   Destroy();
00237 }
00238 
00239 ON_PolynomialSurface::ON_PolynomialSurface(const ON_PolynomialSurface& src)
00240 {
00241   m_order[0] = 0;
00242   m_order[1] = 0;
00243   m_domain[0].m_t[0] = 0.0;
00244   m_domain[0].m_t[1] = 1.0;
00245   m_domain[1].m_t[0] = 0.0;
00246   m_domain[1].m_t[1] = 1.0;
00247   *this = src;
00248 }
00249 
00250 ON_PolynomialSurface::ON_PolynomialSurface(const ON_BezierSurface& src)
00251 {
00252   m_order[0] = 0;
00253   m_order[1] = 0;
00254   m_domain[0].m_t[0] = 0.0;
00255   m_domain[0].m_t[1] = 1.0;
00256   m_domain[1].m_t[0] = 0.0;
00257   m_domain[1].m_t[1] = 1.0;
00258   *this = src;
00259 }
00260 
00261 ON_PolynomialSurface& ON_PolynomialSurface::operator=(const ON_PolynomialSurface& src)
00262 {
00263   if ( this != &src ) {
00264     if ( Create( src.m_dim, src.m_is_rat, src.m_order[0], src.m_order[1] ) ) {
00265       m_cv = src.m_cv;
00266       m_domain[0] = src.m_domain[0];
00267       m_domain[1] = src.m_domain[1];
00268     }
00269   }
00270   return *this;
00271 }
00272 
00273 ON_PolynomialSurface& ON_PolynomialSurface::operator=(const ON_BezierSurface& src)
00274 {
00275   if ( Create( src.m_dim, src.m_is_rat, src.m_order[0], src.m_order[1] ) ) {
00276     //m_domain[0] = src.m_domain[0];
00277     //m_domain[1] = src.m_domain[1];
00278     // TODO - convert coefficients from Bernstein to monomial basis
00279   }
00280   return *this;
00281 }
00282 
00283 ON_BOOL32 ON_PolynomialSurface::Create( int dim, int is_rat, int order0, int order1 )
00284 {
00285   ON_BOOL32 rc = true;
00286   if ( dim > 0 ) m_dim = dim; else {m_dim = 0; rc = false;};
00287   m_is_rat = is_rat?1:0;
00288   if ( order0 > 0 ) m_order[0] = order0; else { m_order[0] = 0; rc = false;}
00289   if ( order1 > 0 ) m_order[1] = order1; else { m_order[1] = 0; rc = false;}
00290   m_cv.SetCapacity( m_order[0]*m_order[1] );
00291   if ( m_order[0] > 0 && m_order[1] > 0 ) {
00292     m_cv.Zero();
00293     m_cv[0].w = 1.0;
00294   }
00295   return rc;
00296 }
00297 
00298 void ON_PolynomialSurface::Destroy()
00299 {
00300   m_dim = 0;
00301   m_is_rat = 0;
00302   m_order[0] = 0;
00303   m_order[1] = 0;
00304   m_cv.Destroy();
00305 }
00306 
00307 ON_BOOL32 ON_PolynomialSurface::Evaluate( // returns false if unable to evaluate
00308        double s, 
00309        double t,           // evaluation parameter
00310        int der_count,      // number of derivatives (>=0)
00311        int v_stride,       // array stride (>=Dimension())
00312        double* v           // array of length stride*(ndir+1)*(ndir+2)/2
00313        ) const
00314 {
00315   ON_ERROR("TODO: - finish ON_PolynomialSurface::Evaluate()\n");
00316   return false;
00317 }
00318 
00319 ON_BezierCurve::ON_BezierCurve()
00320                : m_dim(0), 
00321                  m_is_rat(0), 
00322                  m_order(0), 
00323                  m_cv_stride(0), 
00324                  m_cv(0), 
00325                  m_cv_capacity(0)
00326 {
00327 #if 8 == ON_SIZEOF_POINTER
00328   m_reserved_ON_BezierCurve = 0;
00329 #endif
00330 }
00331 
00332 ON_BezierCurve::ON_BezierCurve( int dim, ON_BOOL32 is_rat, int order )
00333                : m_dim(0), 
00334                  m_is_rat(0), 
00335                  m_order(0), 
00336                  m_cv_stride(0), 
00337                  m_cv(0),
00338                  m_cv_capacity(0)
00339 {
00340 #if 8 == ON_SIZEOF_POINTER
00341   m_reserved_ON_BezierCurve = 0;
00342 #endif
00343   Create(dim,is_rat,order);
00344 }
00345 
00346 ON_BezierCurve::~ON_BezierCurve()
00347 {
00348   Destroy();
00349 }
00350 
00351 ON_BezierCurve::ON_BezierCurve(const ON_BezierCurve& src)
00352                : m_dim(0), 
00353                  m_is_rat(0), 
00354                  m_order(0), 
00355                  m_cv_stride(0), 
00356                  m_cv(0),
00357                  m_cv_capacity(0)
00358 {
00359 #if 8 == ON_SIZEOF_POINTER
00360   m_reserved_ON_BezierCurve = 0;
00361 #endif
00362   *this = src;
00363 }
00364 
00365 ON_BezierCurve::ON_BezierCurve(const ON_PolynomialCurve& src)
00366                : m_dim(0), 
00367                  m_is_rat(0), 
00368                  m_order(0), 
00369                  m_cv_stride(0), 
00370                  m_cv(0),
00371                  m_cv_capacity(0)
00372 {
00373 #if 8 == ON_SIZEOF_POINTER
00374   m_reserved_ON_BezierCurve = 0;
00375 #endif
00376   *this = src;
00377 }
00378 
00379 ON_BezierCurve::ON_BezierCurve(const ON_2dPointArray& cv)
00380                : m_dim(0), 
00381                  m_is_rat(0), 
00382                  m_order(0), 
00383                  m_cv_stride(0), 
00384                  m_cv(0),
00385                  m_cv_capacity(0)
00386 {
00387 #if 8 == ON_SIZEOF_POINTER
00388   m_reserved_ON_BezierCurve = 0;
00389 #endif
00390   *this = cv;
00391 }
00392 
00393 ON_BezierCurve::ON_BezierCurve(const ON_3dPointArray& cv)
00394                : m_dim(0), 
00395                  m_is_rat(0), 
00396                  m_order(0), 
00397                  m_cv_stride(0), 
00398                  m_cv(0),
00399                  m_cv_capacity(0)
00400 {
00401 #if 8 == ON_SIZEOF_POINTER
00402   m_reserved_ON_BezierCurve = 0;
00403 #endif
00404   *this = cv;
00405 }
00406 
00407 ON_BezierCurve::ON_BezierCurve(const ON_4dPointArray& cv)
00408                : m_dim(0), 
00409                  m_is_rat(0), 
00410                  m_order(0), 
00411                  m_cv_stride(0), 
00412                  m_cv(0),
00413                  m_cv_capacity(0)
00414 {
00415 #if 8 == ON_SIZEOF_POINTER
00416   m_reserved_ON_BezierCurve = 0;
00417 #endif
00418   *this = cv;
00419 }
00420 
00421 ON_BezierCurve& ON_BezierCurve::operator=(const ON_2dPointArray& cv)
00422 {
00423   if ( Create( 2, false, cv.Count() ) )
00424   {
00425     int i;
00426     for ( i = 0; i < m_order; i++ )
00427       SetCV( i, ON::intrinsic_point_style, cv[i] );
00428   }
00429   return *this;
00430 }
00431 
00432 ON_BezierCurve& ON_BezierCurve::operator=(const ON_3dPointArray& cv)
00433 {
00434   if ( Create( 3, false, cv.Count() ) )
00435   {
00436     int i;
00437     for ( i = 0; i < m_order; i++ )
00438       SetCV( i, ON::intrinsic_point_style, cv[i] );
00439   }
00440   return *this;
00441 }
00442 
00443 ON_BezierCurve& ON_BezierCurve::operator=(const ON_4dPointArray& cv)
00444 {
00445   if ( Create( 3, true, cv.Count() ) )
00446   {
00447     int i;
00448     for ( i = 0; i < m_order; i++ )
00449       SetCV( i, ON::intrinsic_point_style, cv[i] );
00450   }
00451   return *this;
00452 }
00453 
00454 
00455 ON_BezierCurve& ON_BezierCurve::operator=(const ON_BezierCurve& src)
00456 {
00457   int i;
00458   if ( this != &src ) {
00459     //m_domain = src.m_domain;
00460     if ( Create( src.m_dim, src.m_is_rat, src.m_order ) ) {
00461       const int sizeof_cv = CVSize()*sizeof(m_cv[0]);
00462       for ( i = 0; i < m_order; i++ ) {
00463         memcpy( CV(i), src.CV(i), sizeof_cv );
00464       }
00465     }
00466   }
00467   return *this;
00468 }
00469 
00470 ON_BezierCurve& ON_BezierCurve::operator=(const ON_PolynomialCurve& src)
00471 {
00472   //m_domain = src.m_domain;
00473   if ( src.m_dim > 0 && src.m_cv.Count() == src.m_order && src.m_order >= 2 ) 
00474   {
00475     int i;
00476     
00477     ON_PolynomialCurve s; // scratch poly for homogeneous evaluation
00478     s.m_dim = src.m_is_rat ? 4 : src.m_dim; 
00479     s.m_is_rat = 0;
00480     s.m_domain.m_t[0] = 0.0;
00481     s.m_domain.m_t[1] = 1.0;
00482     s.m_order = src.m_order;
00483     s.m_cv = src.m_cv;
00484 
00485     if ( src.m_is_rat ) {
00486       m_dim++;
00487       m_is_rat = 0;
00488     }     
00489     const int degree = src.m_order-1;
00490     const double d = 1.0/degree;
00491     double t;
00492     ON_4dPointArray pt(src.m_order);
00493     for ( i = 0; i < src.m_order; i++ ) 
00494     {
00495       if ( i == 0 )
00496         t = 0.0;
00497       else if ( i < degree )
00498         t = i*d;
00499       else
00500         t = 1.0;
00501       s.Evaluate( t, 0, 4, pt[i] );
00502     }
00503     s.m_cv = 0;
00504     if ( src.m_is_rat && src.m_dim < 3 ) {
00505       for ( i = 0; i < src.m_order; i++ )
00506         pt[i][src.m_dim] = pt[i].w;
00507     }
00508     Loft( src.m_is_rat ? src.m_dim+1 : src.m_dim, src.m_order, 4, &pt[0].x, 0, NULL );
00509     if ( IsValid() && src.m_is_rat ) {
00510       m_is_rat = 1;
00511       m_dim--;
00512     }
00513   }
00514   else {
00515     Destroy();
00516   }
00517   
00518   return *this;
00519 }
00520 
00521 bool ON_BezierCurve::Loft( const ON_3dPointArray& pt )
00522 {
00523   const ON_3dPoint* p0 = pt.Array();
00524   return Loft( 3, pt.Count(), 3, p0?&p0->x:0, 0, NULL );
00525 }
00526 
00527 
00528 bool ON_BezierCurve::Loft( int pt_dim, int pt_count, int pt_stride, const double* pt,
00529                            int t_stride, const double* t )
00530 {
00531   bool rc = false;
00532   if ( pt_dim >= 1 && pt_count >= 2 && pt_stride >= pt_dim && pt != NULL && (t_stride >= 1 || t == 0) ) {
00533     int i, j;
00534     ON_SimpleArray<double> uniform_t;
00535     double s;
00536     if ( !t ) {
00537       uniform_t.Reserve(pt_count);
00538       s = 1.0/(pt_count-1);
00539       for ( i = 0; i < pt_count; i++ ) {
00540         uniform_t.Append(i*s);
00541       }
00542       uniform_t[0] = 0.0;
00543       uniform_t[pt_count-1] = 1.0;
00544       t = uniform_t.Array();
00545       t_stride = 1;
00546     }
00547     Create( pt_dim, false, pt_count );
00548     const int sizeof_cv = CVSize()*sizeof(m_cv[0]);
00549     const int degree = m_order-1;
00550     const double t0 = t[0];
00551     const double t1 = t[t_stride*(pt_count-1)];
00552     const double tm = 0.5*(t1-t0);
00553     const double d = (t1-t0);
00554     ON_Matrix M( m_order, m_order );
00555     for ( i = 0; i < m_order; i++ ) {
00556       if ( t[i] <= tm ) {
00557         s = (t[i] - t[0])/d;
00558       }
00559       else {
00560         s = 1.0 - (t1 - t[i])/d;
00561       }
00562       for ( j = 0; j < m_order; j++ ) {
00563         M.m[i][j] = ON_EvaluateBernsteinBasis( degree, j, s );
00564       }
00565       memcpy( m_cv + i*m_cv_stride, pt + i*pt_stride, sizeof_cv );
00566     }  
00567 
00568     int rank = M.RowReduce( ON_EPSILON, m_dim, m_cv_stride, m_cv );
00569     M.BackSolve( ON_EPSILON, m_dim, m_order, 
00570                  m_cv_stride, m_cv, 
00571                  m_cv_stride, m_cv );
00572     if ( rank == m_order )
00573       rc = true;
00574   }
00575   return rc;
00576 }
00577 
00578 bool ON_BezierCurve::IsValid() const
00579 {
00580   if ( m_dim <= 0 )
00581     return false;
00582   if ( m_is_rat != 0 && m_is_rat != 1 )
00583     return false;
00584   if ( m_order < 2 )
00585     return false;
00586   if ( m_cv_stride < m_dim+m_is_rat )
00587     return false;
00588   if ( m_cv_capacity > 0 && m_cv_capacity < m_cv_stride*m_order )
00589     return false;
00590   if ( m_cv == NULL )
00591     return false;
00592   return true;
00593 }
00594 
00595 void ON_BezierCurve::Dump( ON_TextLog& dump ) const
00596 {
00597   dump.Print( "ON_BezierCurve dim = %d is_rat = %d\n"
00598                "        order = %d \n",
00599                m_dim, m_is_rat, m_order );
00600   dump.Print( "Control Points  %d %s points\n"
00601                "  index               value\n",
00602                m_order, 
00603                (m_is_rat) ? "rational" : "non-rational" );
00604   if ( !m_cv ) {
00605     dump.Print("  NULL cv array\n");
00606   }
00607   else {
00608     dump.PrintPointList( m_dim, m_is_rat, 
00609                       m_order, m_cv_stride,
00610                       m_cv, 
00611                       "  CV" );
00612   }
00613 }
00614 
00615 int ON_BezierCurve::Dimension() const
00616 {
00617   return m_dim;
00618 }
00619 
00620 bool ON_BezierCurve::Create( int dim, int is_rat, int order )
00621 {
00622   m_dim = (dim>0) ? dim : 0;
00623   m_is_rat = is_rat ? 1 : 0;
00624   // 7 July 2005 Dale Lear
00625   //     Permit order=1 (degree=0) beziers with 1 cv
00626   //     for dots.
00627   m_order = (order >= 1) ? order : 0;
00628   m_cv_stride = (m_dim > 0) ? m_dim+m_is_rat : 0;
00629   m_cv_capacity = m_cv_stride*m_order;
00630   m_cv = (double*)onrealloc( m_cv, m_cv_capacity*sizeof(m_cv[0]) );
00631   //m_domain.m_t[0] = 0.0;
00632   //m_domain.m_t[1] = 1.0;
00633   return IsValid();
00634 }
00635 
00636 void ON_BezierCurve::Destroy()
00637 {
00638   if ( m_cv && m_cv_capacity > 0 )
00639     onfree(m_cv);
00640   m_cv_capacity = 0;
00641   m_cv_stride = 0;
00642   m_cv = 0;
00643   m_dim = 0;
00644   m_is_rat = 0;
00645   m_order = 0;
00646   //m_domain.m_t[0] = 0.0;
00647   //m_domain.m_t[1] = 1.0;
00648 }
00649 
00650 void ON_BezierCurve::EmergencyDestroy()
00651 {
00652   m_cv = 0;
00653 }
00654 
00655 bool ON_BezierCurve::GetBBox( // returns true if successful
00656        double* boxmin,    // minimum
00657        double* boxmax,    // maximum
00658        int bGrowBox
00659        ) const
00660 {
00661   return ON_GetPointListBoundingBox( m_dim, m_is_rat, m_order, m_cv_stride, m_cv, boxmin, boxmax, bGrowBox );
00662 }
00663 
00664 bool ON_BezierCurve::GetBoundingBox( // returns true if successful
00665        ON_BoundingBox& bbox,
00666        int bGrowBox             // true means grow box
00667        ) const
00668 {
00669   double *boxmin, *boxmax;
00670   if ( m_dim > 3 ) 
00671   {
00672     boxmin = (double*)alloca(2*m_dim*sizeof(*boxmin));
00673     memset( boxmin, 0, 2*m_dim*sizeof(*boxmin) );
00674     boxmax = boxmin + m_dim;
00675     if ( bGrowBox ) {
00676       boxmin[0] = bbox.m_min.x;
00677       boxmin[1] = bbox.m_min.y;
00678       boxmin[2] = bbox.m_min.z;
00679       boxmax[0] = bbox.m_max.x;
00680       boxmax[1] = bbox.m_max.y;
00681       boxmax[2] = bbox.m_max.z;
00682     }
00683   }
00684   else {
00685     boxmin = &bbox.m_min.x;
00686     boxmax = &bbox.m_max.x;
00687   }
00688   bool rc = GetBBox( boxmin, boxmax, bGrowBox );
00689   if ( rc && m_dim > 3 ) {
00690     bbox.m_min = boxmin;
00691     bbox.m_max = boxmax;
00692   }
00693   return rc;
00694 }
00695 
00696 ON_BoundingBox ON_BezierCurve::BoundingBox() const
00697 {
00698   ON_BoundingBox bbox;
00699   GetBoundingBox( bbox );
00700   return bbox;
00701 }
00702 
00703 bool ON_WorldBBoxIsInTightBBox( 
00704                     const ON_BoundingBox& tight_bbox, 
00705                     const ON_BoundingBox& world_bbox,
00706                     const ON_Xform* xform
00707                     )
00708 {
00709   if ( xform && !xform->IsIdentity() )
00710   {
00711     ON_3dPoint P, Q;
00712     int i,j,k;
00713     for ( i = 0; i < 2; i++ )
00714     {
00715       P.x = (i) ? world_bbox.m_min.x : world_bbox.m_max.x;
00716       for ( j = 0; j < 2; j++ )
00717       {
00718         P.y = (j) ? world_bbox.m_min.y : world_bbox.m_max.y;
00719         for ( k = 0; k < 2; k++ )
00720         {
00721           P.z = (k) ? world_bbox.m_min.z : world_bbox.m_max.z;
00722           Q = (*xform)*P;
00723           if ( !tight_bbox.IsPointIn(Q) )
00724           {
00725             return false;
00726           }
00727         }
00728       }
00729     }
00730     return true;
00731   }
00732 
00733   return ( tight_bbox.Includes(world_bbox) );
00734 }
00735 
00736 bool ON_Line::GetTightBoundingBox( 
00737                 ON_BoundingBox& tight_bbox, 
00738     int bGrowBox,
00739                 const ON_Xform* xform
00740     ) const
00741 {
00742   if ( bGrowBox && !tight_bbox.IsValid() )
00743   {
00744     bGrowBox = false;
00745   }
00746 
00747   if ( xform && !xform->IsIdentity() )
00748   {
00749     ON_3dPoint P = (*xform)*from;
00750     tight_bbox.Set(P,bGrowBox);
00751     bGrowBox = true;
00752     P = (*xform)*to;
00753     tight_bbox.Set(P,bGrowBox);
00754   }
00755   else
00756   {
00757     tight_bbox.Set(from,bGrowBox);
00758     bGrowBox = true;
00759     tight_bbox.Set(to,bGrowBox);
00760   }
00761 
00762   return (0!=bGrowBox);
00763 }
00764 
00765 bool ON_Arc::GetTightBoundingBox( 
00766                 ON_BoundingBox& tight_bbox, 
00767     int bGrowBox,
00768                 const ON_Xform* xform
00769     ) const
00770 {
00771   if ( IsCircle() && (0 == xform || xform->IsIdentity()) )
00772   {
00773     return ON_Circle::GetTightBoundingBox(tight_bbox,bGrowBox,0);
00774   }
00775 
00776   if ( bGrowBox && !tight_bbox.IsValid() )
00777   {
00778     bGrowBox = false;
00779   }
00780   if ( !bGrowBox )
00781   {
00782     tight_bbox.Destroy();
00783   }
00784 
00785   // Using the nurbs_knot[] and nurbs_cv[] arrays 
00786   // removes all calls to onmalloc() and onfree().
00787   double nurbs_knot[10];
00788   ON_4dPoint nurbs_cv[9];
00789   ON_NurbsCurve nurbs_arc;
00790   nurbs_arc.m_knot = nurbs_knot;
00791   nurbs_arc.m_cv = &nurbs_cv[0].x;
00792   if ( GetNurbForm(nurbs_arc) )
00793   {
00794     if ( xform && !xform->IsIdentity() )
00795     {
00796       nurbs_arc.Transform(*xform);
00797     }
00798     ON_BezierCurve bez_arc;
00799     bez_arc.m_dim = nurbs_arc.m_dim;
00800     bez_arc.m_is_rat = nurbs_arc.m_is_rat;
00801     bez_arc.m_order = nurbs_arc.m_order;
00802     bez_arc.m_cv_stride = nurbs_arc.m_cv_stride;
00803     bez_arc.m_cv = nurbs_arc.m_cv;
00804     int i;
00805     for ( i = nurbs_arc.m_order-2; i < nurbs_arc.m_cv_count-1; i++, bez_arc.m_cv += bez_arc.m_cv_stride )
00806     {
00807       if ( nurbs_arc.m_knot[i] < nurbs_arc.m_knot[i+1] )
00808       {
00809         if ( bez_arc.GetTightBoundingBox( tight_bbox, bGrowBox, 0 ) )
00810           bGrowBox = true;
00811       }
00812     }
00813     bez_arc.m_cv = 0;
00814   }
00815   nurbs_arc.m_cv = 0;
00816   nurbs_arc.m_knot = 0;
00817 
00818   return (0!=bGrowBox);
00819 }
00820 
00821 bool ON_Circle::GetTightBoundingBox( 
00822                 ON_BoundingBox& tight_bbox, 
00823     int bGrowBox,
00824                 const ON_Xform* xform
00825     ) const
00826 {
00827   // April 8, 2010 Dale Lear: 
00828   //   Changed this function to be faster when xform is the identity.
00829   if ( 0 != xform && !xform->IsIdentity() )
00830   {
00831     // The ON_Arc version handles all transformations including
00832     // ones that are not in rotations.
00833     ON_Arc arc(*this,2.0*ON_PI);
00834     return arc.GetTightBoundingBox(tight_bbox,bGrowBox,xform);
00835   }
00836 
00837   if ( bGrowBox && !tight_bbox.IsValid() )
00838   {
00839     bGrowBox = false;
00840   }
00841 
00842   const double rx = radius*ON_Length2d(plane.zaxis.y, plane.zaxis.z);
00843   const double ry = radius*ON_Length2d(plane.zaxis.z, plane.zaxis.x);
00844   const double rz = radius*ON_Length2d(plane.zaxis.x, plane.zaxis.y);
00845   if ( bGrowBox )
00846   {    
00847     if ( plane.origin.x-rx < tight_bbox.m_min.x )
00848       tight_bbox.m_min.x = plane.origin.x-rx;
00849     if ( plane.origin.x+rx > tight_bbox.m_max.x )
00850       tight_bbox.m_max.x = plane.origin.x+rx;
00851     if ( plane.origin.y-ry < tight_bbox.m_min.y )
00852       tight_bbox.m_min.y = plane.origin.y-ry;
00853     if ( plane.origin.y+ry > tight_bbox.m_max.y )
00854       tight_bbox.m_max.y = plane.origin.y+ry;
00855     if ( plane.origin.z-rz < tight_bbox.m_min.z )
00856       tight_bbox.m_min.z = plane.origin.z-rz;
00857     if ( plane.origin.z+rz > tight_bbox.m_max.z )
00858       tight_bbox.m_max.z = plane.origin.z+rz;
00859   }
00860   else
00861   {
00862     tight_bbox.m_min.x = plane.origin.x-rx;
00863     tight_bbox.m_max.x = plane.origin.x+rx;
00864     tight_bbox.m_min.y = plane.origin.y-ry;
00865     tight_bbox.m_max.y = plane.origin.y+ry;
00866     tight_bbox.m_min.z = plane.origin.z-rz;
00867     tight_bbox.m_max.z = plane.origin.z+rz;
00868   }  
00869 
00870   return true;  
00871 }
00872 
00873 bool ON_ArcCurve::GetTightBoundingBox( 
00874                 ON_BoundingBox& tight_bbox, 
00875     int bGrowBox,
00876                 const ON_Xform* xform
00877     ) const
00878 {
00879   return m_arc.GetTightBoundingBox(tight_bbox,bGrowBox,xform);
00880 }
00881 
00882 bool ON_LineCurve::GetTightBoundingBox( 
00883                 ON_BoundingBox& tight_bbox, 
00884     int bGrowBox,
00885                 const ON_Xform* xform
00886     ) const
00887 {
00888   return m_line.GetTightBoundingBox(tight_bbox,bGrowBox,xform);
00889 }
00890 
00891 bool ON_PolylineCurve::GetTightBoundingBox( 
00892                 ON_BoundingBox& tight_bbox, 
00893     int bGrowBox,
00894                 const ON_Xform* xform
00895     ) const
00896 {
00897   return m_pline.GetTightBoundingBox(tight_bbox,bGrowBox,xform);
00898 }
00899 
00900 bool ON_PolyCurve::GetTightBoundingBox( 
00901                 ON_BoundingBox& tight_bbox, 
00902     int bGrowBox,
00903                 const ON_Xform* xform
00904     ) const
00905 {
00906   return m_segment.GetTightBoundingBox(tight_bbox,bGrowBox,xform);
00907 }
00908 
00909 bool ON_CurveArray::GetTightBoundingBox( 
00910                 ON_BoundingBox& tight_bbox, 
00911     int bGrowBox,
00912                 const ON_Xform* xform
00913     ) const
00914 {
00915   if ( 1 == m_count && m_a[0] )
00916   {
00917     return m_a[0]->GetTightBoundingBox(tight_bbox,bGrowBox,xform);
00918   }
00919 
00920   if ( bGrowBox && !tight_bbox.IsValid() )
00921   {
00922     bGrowBox = false;
00923   }
00924   if ( !bGrowBox )
00925   {
00926     tight_bbox.Destroy();
00927   }
00928 
00929   if ( m_count > 0 )
00930   {
00931     int i;
00932     // getting box of endpoints tends to help us avoid testing curves
00933     ON_3dPointArray P(2*m_count);
00934     for ( i = 0; i < m_count; i++ )
00935     {
00936       if ( m_a[i] )
00937       {
00938         P.Append( m_a[i]->PointAtStart() );
00939         P.Append( m_a[i]->PointAtEnd() );
00940       }
00941     }
00942     if ( P.GetTightBoundingBox(tight_bbox,bGrowBox,xform) )
00943     {
00944       bGrowBox = true;
00945     }
00946 
00947     for ( i = 0; i < m_count; i++ )
00948     {
00949       if ( m_a[i] )
00950       {
00951         if ( m_a[i]->GetTightBoundingBox(tight_bbox,bGrowBox,xform) )
00952         {
00953           bGrowBox = true;
00954         }
00955       }
00956     }
00957   }
00958 
00959   return (0!=bGrowBox);  
00960 }
00961 
00962 bool ON_3dPointArray::GetTightBoundingBox( 
00963                         ON_BoundingBox& tight_bbox, 
00964       int bGrowBox,
00965                         const ON_Xform* xform
00966       ) const
00967 {
00968   if ( bGrowBox && !tight_bbox.IsValid() )
00969   {
00970     bGrowBox = false;
00971   }
00972   if ( !bGrowBox )
00973   {
00974     tight_bbox.Destroy();
00975   }
00976   if ( m_count > 0 )
00977   {
00978     ON_BoundingBox points_bbox;
00979     if ( xform && !xform->IsIdentity() )
00980     {
00981       ON_3dPoint P;
00982       points_bbox.m_min = (*xform)*m_a[0];
00983       points_bbox.m_max = points_bbox.m_min;
00984       int i;
00985       for ( i = 1; i < m_count; i++ )
00986       {
00987         P = (*xform)*m_a[i];
00988         if ( P.x < points_bbox.m_min.x ) points_bbox.m_min.x = P.x; else if ( P.x > points_bbox.m_max.x ) points_bbox.m_max.x = P.x;
00989         if ( P.y < points_bbox.m_min.y ) points_bbox.m_min.y = P.y; else if ( P.y > points_bbox.m_max.y ) points_bbox.m_max.y = P.y;
00990         if ( P.z < points_bbox.m_min.z ) points_bbox.m_min.z = P.z; else if ( P.z > points_bbox.m_max.z ) points_bbox.m_max.z = P.z;
00991       }
00992     }
00993     else
00994     {
00995       points_bbox = BoundingBox();
00996     }
00997     tight_bbox.Union(points_bbox);
00998     bGrowBox = true;
00999   }
01000   return (0!=bGrowBox);
01001 }
01002 
01003 bool ON_PointCloud::GetTightBoundingBox( 
01004                         ON_BoundingBox& tight_bbox, 
01005       int bGrowBox,
01006                         const ON_Xform* xform
01007       ) const
01008 {
01009   if ( bGrowBox && !tight_bbox.IsValid() )
01010   {
01011     bGrowBox = false;
01012   }
01013 
01014   if ( !bGrowBox )
01015   {
01016     tight_bbox.Destroy();
01017   }
01018 
01019   if ( m_P.Count() > 0 )
01020   {
01021     ON_BoundingBox pc_bbox = BoundingBox();
01022     if ( bGrowBox )
01023     {
01024       if ( ON_WorldBBoxIsInTightBBox( tight_bbox, pc_bbox, xform ) )
01025         return true;
01026     }
01027 
01028     if ( xform && !xform->IsIdentity() )
01029     {
01030       if ( m_P.GetTightBoundingBox(tight_bbox,bGrowBox,xform) )
01031         bGrowBox = true;
01032     }
01033     else
01034     {
01035       tight_bbox.Union(pc_bbox);
01036       bGrowBox = tight_bbox.IsValid();
01037     }
01038   }
01039 
01040   return (0!=bGrowBox);
01041 }
01042 
01043 
01044 bool ON_Mesh::GetTightBoundingBox( 
01045                 ON_BoundingBox& tight_bbox, 
01046     int bGrowBox,
01047                 const ON_Xform* xform 
01048     ) const
01049 {
01050   if ( bGrowBox && !tight_bbox.IsValid() )
01051   {
01052     bGrowBox = false;
01053   }
01054 
01055   ON_BoundingBox mesh_bbox = BoundingBox();
01056   if ( xform && !xform->IsIdentity() )
01057   {
01058     if ( ON_WorldBBoxIsInTightBBox( tight_bbox, mesh_bbox, xform ) )
01059     {
01060       return true;
01061     }
01062 
01063     const int vcount = m_V.Count();
01064     if ( vcount > 0 )
01065     {
01066       // calculate bbox of transformed mesh
01067       ON_3dPoint P(m_V[0]);
01068       mesh_bbox.m_min = (*xform)*P;
01069       mesh_bbox.m_max = mesh_bbox.m_min;
01070       int i;
01071       for ( i = 1; i < vcount; i++ )
01072       {
01073         P = m_V[i];
01074         P = (*xform)*P;
01075         if ( P.x < mesh_bbox.m_min.x ) mesh_bbox.m_min.x = P.x; else if (P.x > mesh_bbox.m_max.x) mesh_bbox.m_max.x = P.x;
01076         if ( P.y < mesh_bbox.m_min.y ) mesh_bbox.m_min.y = P.y; else if (P.y > mesh_bbox.m_max.y) mesh_bbox.m_max.y = P.y;
01077         if ( P.z < mesh_bbox.m_min.z ) mesh_bbox.m_min.z = P.z; else if (P.z > mesh_bbox.m_max.z) mesh_bbox.m_max.z = P.z;
01078       }
01079     }
01080   }
01081 
01082   if ( !bGrowBox )
01083   {
01084     tight_bbox = mesh_bbox;
01085     bGrowBox = tight_bbox.IsValid();
01086   }
01087   else
01088   {
01089     tight_bbox.Union(mesh_bbox);
01090   }
01091 
01092   return (0!=bGrowBox);
01093 }
01094 
01095 
01096 
01097 bool ON_BezierCurve::Transform( 
01098        const ON_Xform& xform
01099        )
01100 {
01101   if ( 0 == m_is_rat )
01102   {
01103     if ( xform.m_xform[3][0] != 0.0 || xform.m_xform[3][1] != 0.0 || xform.m_xform[3][2] != 0.0 )
01104     {
01105       MakeRational();
01106     }
01107   }
01108   return ON_TransformPointList( m_dim, m_is_rat, m_order, m_cv_stride, m_cv, xform );
01109 }
01110 
01111 bool ON_BezierCurve::Rotate(
01112       double sin_angle,          // sin(angle)
01113       double cos_angle,          // cos(angle)
01114       const ON_3dVector& axis, // axis of rotation
01115       const ON_3dPoint& center // center of rotation
01116       )
01117 {
01118   ON_Xform rot;
01119   rot.Rotation( sin_angle, cos_angle, axis, center );
01120   return Transform( rot );
01121 }
01122 
01123 bool ON_BezierCurve::Rotate(
01124       double angle,              // angle in radians
01125       const ON_3dVector& axis, // axis of rotation
01126       const ON_3dPoint& center // center of rotation
01127       )
01128 {
01129   return Rotate( sin(angle), cos(angle), axis, center );
01130 }
01131 
01132 bool ON_BezierCurve::Translate( const ON_3dVector& delta )
01133 {
01134   ON_Xform tr;
01135   tr.Translation( delta );
01136   return Transform( tr );
01137 }
01138 
01139 bool ON_BezierCurve::Scale( double x )
01140 {
01141   ON_Xform s;
01142   s.Scale( x, x, x );
01143   return Transform( s );
01144 }
01145 
01146 
01147 ON_Interval ON_BezierCurve::Domain() const
01148 {
01149   //return m_domain;
01150   return ON_Interval(0.0,1.0);
01151 }
01152 
01153 bool ON_BezierCurve::Reverse()
01154 {
01155   bool rc = ON_ReversePointList( m_dim, m_is_rat, m_order, m_cv_stride, m_cv )?true:false;
01156   //if ( rc )
01157   //  m_domain.Reverse();
01158   return rc;
01159 }
01160 
01161 bool ON_BezierCurve::Evaluate( // returns false if unable to evaluate
01162        double t,      // evaluation parameter
01163        int der_count, // number of derivatives (>=0)
01164        int v_stride,  // array stride (>=Dimension())
01165        double* v      // array of length stride*(ndir+1)
01166        ) const
01167 {
01168   return ON_EvaluateBezier( m_dim, m_is_rat, m_order, m_cv_stride, m_cv, 
01169                             0.0, 1.0, //m_domain[0], m_domain[1], 
01170                             der_count, t, v_stride, v )?true:false;
01171 }
01172 
01173 bool ON_BezierCurve::GetNurbForm( ON_NurbsCurve& n ) const
01174 {
01175   bool rc = false;
01176   if ( n.Create( m_dim, m_is_rat, m_order, m_order ) ) {
01177     const int sizeof_cv = CVSize()*sizeof(m_cv[0]);
01178     int i;
01179     for ( i = 0; i < m_order; i++ ) {
01180       memcpy( n.CV(i), CV(i), sizeof_cv );
01181     }
01182     n.m_knot[m_order-2] = 0.0;//m_domain.Min();
01183     n.m_knot[m_order-1] = 1.0;//m_domain.Max();
01184     rc = ON_ClampKnotVector( n.m_order, n.m_cv_count, n.m_knot, 2 )?true:false;
01185   }
01186   return rc;
01187 }
01188 
01189 bool ON_BezierCurve::IsRational() const
01190 {
01191   return m_is_rat ? true : false;
01192 }
01193   
01194 int ON_BezierCurve::CVSize() const
01195 {
01196   return (m_dim>0&&m_is_rat) ? m_dim+1 : m_dim;
01197 }
01198 
01199 int ON_BezierCurve::Order() const
01200 {
01201   return m_order;
01202 }
01203 
01204 int ON_BezierCurve::Degree() const
01205 {
01206   return m_order>=2 ? m_order-1 : 0;
01207 }
01208 
01209 double* ON_BezierCurve::CV( int i ) const
01210 {
01211   return m_cv ? m_cv + (i*m_cv_stride) : 0;
01212 }
01213 
01214 ON::point_style ON_BezierCurve::CVStyle() const
01215 {
01216   return m_is_rat ? ON::homogeneous_rational : ON::not_rational;
01217 }
01218 
01219 double ON_BezierCurve::Weight( int i ) const 
01220 {
01221   return ( m_is_rat && m_cv ) ? CV(i)[m_dim] : 1.0;
01222 }
01223 
01224 bool ON_BezierCurve::SetWeight( int i, double w )
01225 {
01226   bool rc = false;
01227   if ( m_is_rat ) {
01228     double* cv = CV(i);
01229     if (cv) {
01230       cv[m_dim] = w;
01231       rc = true;
01232     }
01233   }
01234   else if ( w == 1.0 ) {
01235     rc = true;
01236   }
01237   return rc;
01238 }
01239 
01240 bool ON_BezierCurve::SetCV( int i, ON::point_style style, const double* Point )
01241 {
01242   bool rc = true;
01243   int k;
01244   double w;
01245 
01246   // feeble but fast check for properly initialized class
01247   if ( !m_cv || i < 0 || i >= m_order )
01248     return false;
01249 
01250   double* cv = m_cv + i*m_cv_stride;
01251 
01252   switch ( style ) {
01253 
01254   case ON::not_rational:  // input Point is not rational
01255     memcpy( cv, Point, m_dim*sizeof(*cv) );
01256     if ( IsRational() ) {
01257       // NURBS curve is rational - set weight to one
01258       cv[m_dim] = 1.0;
01259     }
01260     break;
01261 
01262   case ON::homogeneous_rational:  // input Point is homogeneous rational
01263     if ( IsRational() ) {
01264       // NURBS curve is rational
01265       memcpy( cv, Point, (m_dim+1)*sizeof(*cv) );
01266     }
01267     else {
01268       // NURBS curve is not rational
01269       w = (Point[m_dim] != 0.0) ? 1.0/Point[m_dim] : 1.0;
01270       for ( k = 0; k < m_dim; k++ ) {
01271         cv[k] = w*Point[k];
01272       }
01273     }
01274     break;
01275 
01276   case ON::euclidean_rational:  // input Point is euclidean rational
01277     if ( IsRational() ) {
01278       // NURBS curve is rational - convert euclean point to homogeneous form
01279       w = Point[m_dim];
01280       for ( k = 0; k < m_dim; k++ )
01281         cv[k] = w*Point[k];
01282       cv[m_dim] = w;
01283     }
01284     else {
01285       // NURBS curve is not rational
01286       memcpy( cv, Point, m_dim*sizeof(*cv) );
01287     }
01288     break;
01289 
01290   case ON::intrinsic_point_style:
01291     k = m_is_rat?m_dim+1:m_dim;
01292     memcpy(cv,Point,k*sizeof(cv[0]));
01293     break;
01294 
01295   default:
01296     rc = false;
01297     break;
01298   }
01299 
01300   return rc;
01301 }
01302 
01303 bool ON_BezierCurve::SetCV( int i, const ON_3dPoint& point )
01304 {
01305   bool rc = false;
01306   double* cv = CV(i);
01307   if ( cv ) {
01308     cv[0] = point.x;
01309     if ( m_dim > 1 ) {
01310       cv[1] = point.y;
01311       if ( m_dim > 2 )
01312         cv[2] = point.z;
01313       if ( m_dim > 3 ) {
01314         memset( &cv[3], 0, (m_dim-3)*sizeof(*cv) );
01315       }
01316     }
01317     if ( m_is_rat ) {
01318       cv[m_dim] = 1.0;
01319     }
01320     rc = true;
01321   }
01322   return rc;
01323 }
01324 
01325 bool ON_BezierCurve::SetCV( int i, const ON_4dPoint& point )
01326 {
01327   bool rc = false;
01328   double* cv = CV(i);
01329   if ( cv ) {
01330     if ( m_is_rat ) {
01331       cv[0] = point.x;
01332       if ( m_dim > 1 ) {
01333         cv[1] = point.y;
01334         if ( m_dim > 2 )
01335           cv[2] = point.z;
01336         if ( m_dim > 3 ) {
01337           memset( &cv[3], 0, (m_dim-3)*sizeof(*cv) );
01338         }
01339       }
01340       cv[m_dim] = point.w;
01341       rc = true;
01342     }
01343     else {
01344       double w;
01345       if ( point.w != 0.0 ) {
01346         w = 1.0/point.w;
01347         rc = true;
01348       }
01349       else {
01350         w = 1.0;
01351       }
01352       cv[0] = w*point.x;
01353       if ( m_dim > 1 ) {
01354         cv[1] = w*point.y;
01355         if ( m_dim > 2 ) {
01356           cv[2] = w*point.z;
01357         }
01358         if ( m_dim > 3 ) {
01359           memset( &cv[3], 0, (m_dim-3)*sizeof(*cv) );
01360         }
01361       }
01362     }
01363   }
01364   return rc;
01365 }
01366 
01367 bool ON_BezierCurve::GetCV( int i, ON::point_style style, double* Point ) const
01368 {
01369   const double* cv = CV(i);
01370   if ( !cv )
01371     return false;
01372   int dim = Dimension();
01373   double w = ( IsRational() ) ? cv[dim] : 1.0;
01374   switch(style) {
01375   case ON::euclidean_rational:
01376     Point[dim] = w;
01377     // no break here
01378   case ON::not_rational:
01379     if ( w == 0.0 )
01380       return false;
01381     w = 1.0/w;
01382     while(dim--) *Point++ = *cv++ * w;
01383     break;
01384   case ON::homogeneous_rational:
01385     Point[dim] = w;
01386     memcpy( Point, cv, dim*sizeof(*Point) );
01387     break;
01388   default:
01389     return false;
01390   }
01391   return true;
01392 }
01393 
01394 bool ON_BezierCurve::GetCV( int i, ON_3dPoint& point ) const
01395 {
01396   bool rc = false;
01397   const double* cv = CV(i);
01398   if ( cv ) {
01399     if ( m_is_rat ) {
01400       if (cv[m_dim] != 0.0) {
01401         const double w = 1.0/cv[m_dim];
01402         point.x = cv[0]*w;
01403         point.y = (m_dim>1)? cv[1]*w : 0.0;
01404         point.z = (m_dim>2)? cv[2]*w : 0.0;
01405         rc = true;
01406       }
01407     }
01408     else {
01409       point.x = cv[0];
01410       point.y = (m_dim>1)? cv[1] : 0.0;
01411       point.z = (m_dim>2)? cv[2] : 0.0;
01412       rc = true;
01413     }
01414   }
01415   return rc;
01416 }
01417 
01418 bool 
01419 ON_BezierCurve::GetCV( int i, ON_4dPoint& point ) const
01420 {
01421   bool rc = false;
01422   const double* cv = CV(i);
01423   if ( cv ) {
01424     point.x = cv[0];
01425     point.y = (m_dim>1)? cv[1] : 0.0;
01426     point.z = (m_dim>2)? cv[2] : 0.0;
01427     point.w = (m_is_rat) ? cv[m_dim] : 1.0;
01428     rc = true;
01429   }
01430   return rc;
01431 }
01432 
01433 bool ON_BezierCurve::ZeroCVs()
01434 {
01435   bool rc = false;
01436   int i;
01437   if ( m_cv ) {
01438     if ( m_cv_capacity > 0 ) {
01439       memset( m_cv, 0, m_cv_capacity*sizeof(*m_cv) );
01440       if ( m_is_rat ) {
01441         for ( i = 0; i < m_order; i++ ) {
01442           SetWeight( i, 1.0 );
01443         }
01444       }
01445       rc = true;
01446     }
01447     else {
01448       double* cv;
01449       int s = CVSize()*sizeof(*cv);
01450       for ( i = 0; i < m_order; i++ ) {
01451         cv = CV(i);
01452         memset(cv,0,s);
01453         if ( m_is_rat )
01454           cv[m_dim] = 1.0;
01455       }
01456       rc = (i>0) ? true : false;
01457     }
01458   }
01459   return rc;
01460 }
01461 
01462 int ON_BezierCurve::CVCount() const
01463 {
01464   return Order();
01465 }
01466 
01467 bool ON_BezierCurve::MakeRational()
01468 {
01469   if ( !IsRational() ) {
01470     const int dim = Dimension();
01471     const int cv_count = CVCount();
01472     if ( cv_count > 0 && m_cv_stride >= dim && dim > 0 ) {
01473       const int new_stride = (m_cv_stride == dim) ? dim+1 : m_cv_stride;
01474       ReserveCVCapacity( cv_count*new_stride );
01475       const double* old_cv;
01476       double* new_cv;
01477       int cvi, j;
01478       for ( cvi = cv_count-1; cvi>=0; cvi-- ) {
01479         old_cv = CV(cvi);
01480         new_cv = m_cv+(cvi*new_stride);
01481         for ( j = dim-1; j >= 0; j-- ) {
01482           new_cv[j] = old_cv[j];
01483         }
01484         new_cv[dim] = 1.0;
01485       }
01486       m_cv_stride = new_stride;
01487       m_is_rat = 1;
01488     }
01489   }
01490   return IsRational();
01491 }
01492 
01493 bool ON_BezierCurve::MakeNonRational()
01494 {
01495   if ( IsRational() ) {
01496     const int dim = Dimension();
01497     const int cv_count = CVCount();
01498     if ( cv_count > 0 && m_cv_stride >= dim+1 && dim > 0 ) {
01499       double w;
01500       const double* old_cv;
01501       double* new_cv = m_cv;
01502       int cvi, j;
01503       for ( cvi = 0; cvi < cv_count; cvi++ ) {
01504         old_cv = CV(cvi);
01505         w = old_cv[dim];
01506         w = ( w != 0.0 ) ? 1.0/w : 1.0;
01507         for ( j = 0; j < dim; j++ ) {
01508           *new_cv++ = w*(*old_cv++);
01509         }
01510       }
01511       m_is_rat = 0;
01512       m_cv_stride = dim;
01513     }
01514   }
01515   return ( !IsRational() ) ? true : false;
01516 }
01517 
01518 bool ON_BezierCurve::IncreaseDegree( int desired_degree )
01519 {
01520   bool rc = false;
01521   if ( desired_degree > 0 ) {
01522     if ( desired_degree == m_order-1 )
01523       rc = true;
01524     else if ( desired_degree >= m_order ) {
01525       ReserveCVCapacity( m_cv_stride*(desired_degree+1) );
01526       while ( m_order <= desired_degree ) {
01527         rc = ON_IncreaseBezierDegree( m_dim, m_is_rat, m_order, m_cv_stride, m_cv )?true:false;
01528         if ( !rc )
01529           break;
01530         m_order++;
01531       }
01532     }
01533   }
01534   return rc;
01535 }
01536 
01538 // Tools for managing CV and knot memory
01539 bool ON_BezierCurve::ReserveCVCapacity( int desired_capacity )
01540 {
01541         bool rc = false;
01542         if ( desired_capacity > m_cv_capacity ) {
01543                 if ( !m_cv ) {
01544                         m_cv = (double*)onmalloc(desired_capacity*sizeof(*m_cv));
01545                         if ( !m_cv ) {
01546                                 m_cv_capacity = 0;
01547                         }
01548                         else {
01549                                 m_cv_capacity = desired_capacity;
01550                                 rc = true;
01551                         }
01552                 }
01553                 else if ( m_cv_capacity > 0 ) {
01554                         m_cv = (double*)onrealloc(m_cv,desired_capacity*sizeof(*m_cv));
01555                         if ( !m_cv ) {
01556                                 m_cv_capacity = 0;
01557                         }
01558                         else {
01559                                 m_cv_capacity = desired_capacity;
01560                                 rc = true;
01561                         }
01562                 }
01563         } 
01564         else 
01565                 rc =true;
01566         return rc;
01567 }
01568 
01569 bool ON_BezierCurve::ChangeDimension( int dim )
01570 {
01571   ON_NurbsCurve c;
01572   c.m_dim = m_dim;
01573   c.m_is_rat = m_is_rat;
01574   c.m_order = m_order;
01575   c.m_cv_count = m_order;
01576   c.m_cv_capacity = m_cv_capacity;
01577   c.m_cv_stride = m_cv_stride;
01578   c.m_cv = m_cv;
01579   bool rc = c.ChangeDimension(dim);
01580   m_dim = c.m_dim;
01581   m_cv_stride = c.m_cv_stride;
01582   m_cv = c.m_cv;
01583   m_cv_capacity = c.m_cv_capacity;
01584 
01585   // don't let destruction of stack "c" delete m_cv array.
01586   c.m_cv = 0;
01587   c.m_cv_capacity = 0;
01588   c.m_cv_stride = 0;
01589   return rc;
01590 }
01591  
01592 double ON_BezierCurve::ControlPolygonLength() const
01593 {
01594   double length = 0.0;
01595   ON_GetPolylineLength( m_dim, m_is_rat, m_order, m_cv_stride, m_cv, &length );
01596   return length;
01597 }
01598 
01599 bool ON_BezierCurve::Trim( const ON_Interval& n )
01600 {
01601   bool rc = n.IsIncreasing();
01602   if ( rc ) {
01603     double t0 = n.Min();
01604     double t1 = n.Max();
01605     int cvdim = CVSize(); // 9/9/03 fix rat trim bug - use cvdim instead of m_dim
01606     if ( t0 != 1.0 ) {
01607       double s1 = (t1-t0)/(1.0 - t0);
01608       ON_EvaluatedeCasteljau( cvdim, m_order, +1, m_cv_stride, m_cv, t0 );
01609       ON_EvaluatedeCasteljau( cvdim, m_order, -1, m_cv_stride, m_cv, s1 );
01610     }
01611     else {
01612       ON_EvaluatedeCasteljau( cvdim, m_order, -1, m_cv_stride, m_cv, t1 );
01613       if ( t0 != 0.0 )
01614       {
01615         // 9/9/03 fix add != 0 test to avoid divide by zero bug
01616         double s0 = t1/t0;
01617         ON_EvaluatedeCasteljau( cvdim, m_order, +1, m_cv_stride, m_cv, s0 );
01618       }
01619     }
01620   }
01621   return rc;
01622 }
01623 
01624 bool ON_BezierCurve::Split( 
01625        double t, // t = splitting parameter must 0 < t < 1
01626        ON_BezierCurve& left_bez, // left side returned here (can pass *this)
01627        ON_BezierCurve& right_bez // right side returned here (can pass *this)
01628        ) const
01629 {
01630   bool rc = ( 0.0 < t && t < 1.0 && IsValid() ) ? true : false;
01631   if ( rc ) {
01632     const int cvdim = CVSize();
01633     int i,j,k,n;
01634     double *p, *r, s;
01635     const double* q;
01636     double** b = (double**)alloca((2*m_order-1)*sizeof(*b));
01637     
01638     if ( this != &left_bez )
01639     {
01640       if ( 0 == left_bez.m_cv || (0 < left_bez.m_cv_capacity && left_bez.m_cv_capacity < cvdim*m_order) )
01641       {
01642         left_bez.Create( m_dim, m_is_rat, m_order );
01643       }
01644       else if ( left_bez.m_dim != m_dim || left_bez.m_is_rat != m_is_rat || left_bez.m_order != m_order || left_bez.m_cv_stride < cvdim )
01645       {
01646         left_bez.m_dim       = m_dim;
01647         left_bez.m_is_rat    = m_is_rat?1:0;
01648         left_bez.m_order     = m_order;
01649         left_bez.m_cv_stride = cvdim;
01650       }
01651     }
01652 
01653     if ( this != &right_bez )
01654     {
01655       if ( !right_bez.m_cv || (0 < right_bez.m_cv_capacity && right_bez.m_cv_capacity < cvdim*m_order) )
01656       {
01657         right_bez.Create( m_dim, m_is_rat, m_order );
01658       }
01659       else if ( right_bez.m_dim != m_dim || right_bez.m_is_rat != m_is_rat || right_bez.m_order != m_order || right_bez.m_cv_stride < cvdim )
01660       {
01661         right_bez.m_dim       = m_dim;
01662         right_bez.m_is_rat    = m_is_rat?1:0;
01663         right_bez.m_order     = m_order;
01664         right_bez.m_cv_stride = cvdim;
01665       }
01666     }
01667 
01668     b[0] = left_bez.m_cv;
01669     b[m_order-1] = right_bez.m_cv;
01670     for ( i = 1, j = m_order; i < m_order; i++, j++ ) {
01671       b[j] = b[j-1]+cvdim;
01672       b[i] = b[i-1]+cvdim;
01673     }
01674 
01675     if (m_cv == left_bez.m_cv) {
01676       // copy from back to front
01677       for (i = 2*m_order-2; i >= 0; i -= 2) {
01678         p = b[i]+cvdim;
01679         q = CV(i/2)+cvdim;
01680         k = cvdim;
01681         while(k--) *(--p) = *(--q);
01682       }
01683     }
01684     else {
01685       // copy from front to back
01686       for (i = 0; i < 2*m_order; i += 2) {
01687         p = b[i];
01688         q = CV(i/2);
01689         k = cvdim;
01690         while(k--) *p++ = *q++;
01691       }      
01692     }
01693     
01694     left_bez.m_dim = m_dim;
01695     left_bez.m_is_rat = m_is_rat;
01696     left_bez.m_order = m_order;
01697     left_bez.m_cv_stride = CVSize();
01698 
01699     right_bez.m_dim = left_bez.m_dim;
01700     right_bez.m_is_rat = left_bez.m_is_rat;
01701     right_bez.m_order = left_bez.m_order;
01702     right_bez.m_cv_stride = left_bez.m_cv_stride;
01703     
01704     // deCasteljau
01705     if (t == 0.5) {
01706       // use faster aritmetic for this common case
01707       for (i = 1, k = 2*m_order-2; i < k; i++, k--) {
01708         for (j = i; j < k; j++,j++)  {
01709           p = b[j-1];
01710           q = b[j+1];
01711           r = b[j];
01712           n = cvdim;
01713           while(n--) 
01714             *r++ = 0.5*(*p++ + *q++);
01715         }
01716       }
01717     }
01718     else {
01719       s = 1.0-t;
01720       for (i = 1, k = 2*m_order-2; i < k; i++, k--) {
01721         for (j = i; j < k; j++,j++) {
01722           p = b[j-1];
01723           q = b[j+1];
01724           r = b[j];
01725           n = cvdim;
01726           while(n--) 
01727             *r++ = (*p++ * s + *q++ * t);
01728         }
01729       }
01730     }
01731     
01732     // last cv of left side = first cv of right side
01733     p = right_bez.CV(0);
01734     q = left_bez.CV(m_order-1);
01735     if (p != q) {
01736       j = cvdim;
01737       while(j--) *p++ = *q++;
01738     }
01739   }
01740   return rc;
01741 }
01742 
01743 ON_BezierSurface::ON_BezierSurface()
01744                  : m_dim(0),
01745                    m_is_rat(0),
01746                    m_cv(0),
01747                    m_cv_capacity(0)
01748 {
01749   m_order[0] = 0;
01750   m_order[1] = 0;
01751   m_cv_stride[0] = 0;
01752   m_cv_stride[1] = 0;
01753 #if 8 == ON_SIZEOF_POINTER
01754   m_reserved_ON_BezierSurface = 0;
01755 #endif
01756 }
01757 
01758 ON_BezierSurface::ON_BezierSurface( int dim, ON_BOOL32 is_rat, int order0, int order1 )
01759                  : m_dim(0),
01760                    m_is_rat(0),
01761                    m_cv(0),
01762                    m_cv_capacity(0)
01763 {
01764   m_order[0] = 0;
01765   m_order[1] = 0;
01766   m_cv_stride[0] = 0;
01767   m_cv_stride[1] = 0;
01768 #if 8 == ON_SIZEOF_POINTER
01769   m_reserved_ON_BezierSurface = 0;
01770 #endif
01771   Create( dim, is_rat, order0, order1 );
01772 }
01773 
01774 ON_BezierSurface::~ON_BezierSurface()
01775 {
01776   Destroy();
01777 }
01778   
01779 ON_BezierSurface::ON_BezierSurface(const ON_BezierSurface& src)
01780                  : m_dim(0),
01781                    m_is_rat(0),
01782                    m_cv(0),
01783                    m_cv_capacity(0)
01784 {
01785   m_order[0] = 0;
01786   m_order[1] = 0;
01787   m_cv_stride[0] = 0;
01788   m_cv_stride[1] = 0;
01789 #if 8 == ON_SIZEOF_POINTER
01790   m_reserved_ON_BezierSurface = 0;
01791 #endif
01792   *this = src;
01793 }
01794 
01795 ON_BezierSurface::ON_BezierSurface(const ON_PolynomialSurface& src)
01796                  : m_dim(0),
01797                    m_is_rat(0),
01798                    m_cv(0),
01799                    m_cv_capacity(0)
01800 {
01801   m_order[0] = 0;
01802   m_order[1] = 0;
01803   m_cv_stride[0] = 0;
01804   m_cv_stride[1] = 0;
01805 #if 8 == ON_SIZEOF_POINTER
01806   m_reserved_ON_BezierSurface = 0;
01807 #endif
01808   *this = src;
01809 }
01810 
01811 ON_BezierSurface& ON_BezierSurface::operator=(const ON_BezierSurface& src)
01812 {
01813   if ( this != &src ) {
01814     if ( Create( src.m_dim, src.m_is_rat, src.m_order[0], src.m_order[1] ) ) {
01815       const int sizeof_cv = src.CVSize()*sizeof(m_cv[0]);
01816       int i, j;
01817       for ( i = 0; i < m_order[0]; i++ ) for ( j = 0; j < m_order[1]; j++ ) {
01818         memcpy( CV(i,j), src.CV(i,j), sizeof_cv );
01819       }
01820     }
01821     else {
01822       Destroy();
01823     }
01824   }
01825   return *this;
01826 }
01827 
01828 ON_BezierSurface& ON_BezierSurface::operator=(const ON_PolynomialSurface& src)
01829 {
01830   if ( Create( src.m_dim, src.m_is_rat, src.m_order[0], src.m_order[1] ) ) {
01831     // TODO - convert to bi-bezier
01832   }
01833   return *this;
01834 }
01835 
01836 bool ON_BezierSurface::IsValid() const
01837 {
01838   if ( m_dim <= 0 )
01839     return false;
01840   if ( m_is_rat != 0 && m_is_rat != 1 )
01841     return false;
01842   if ( m_order[0] < 2 )
01843     return false;
01844   if ( m_order[0] < 2 )
01845     return false;
01846   if ( m_cv_stride[0] < m_dim+m_is_rat )
01847     return false;
01848   if ( m_cv_stride[1] < m_dim+m_is_rat )
01849     return false;
01850   if ( m_cv_capacity > 0 && m_cv_capacity < (m_dim+m_is_rat)*m_order[0]*m_order[1] )
01851     return false;
01852   //if ( !m_domain[0].IsIncreasing() )
01853   //  return false;
01854   //if ( !m_domain[1].IsIncreasing() )
01855   //  return false;
01856   if ( m_cv == NULL )
01857     return false;
01858   return true;
01859 }
01860 
01861 void ON_BezierSurface::Dump( ON_TextLog& dump ) const
01862 {
01863   dump.Print( "ON_BezierSurface dim = %d is_rat = %d\n"
01864                "        order = (%d, %d) \n",
01865                m_dim, m_is_rat, m_order[0], m_order[1] );
01866   dump.Print( "Control Points  %d %s points\n"
01867                "  index               value\n",
01868                m_order[0]*m_order[1], 
01869                (m_is_rat) ? "rational" : "non-rational" );
01870   if ( !m_cv ) {
01871     dump.Print("  NULL cv array\n");
01872   }
01873   else {
01874     int i;
01875     char sPreamble[128]; 
01876     memset(sPreamble,0,sizeof(sPreamble));
01877     for ( i = 0; i < m_order[0]; i++ )
01878     {
01879       if ( i > 0 )
01880         dump.Print("\n");
01881       sPreamble[0] = 0;
01882       sprintf(sPreamble,"  CV[%2d]",i);
01883       dump.PrintPointList( m_dim, m_is_rat, 
01884                         m_order[1], m_cv_stride[1],
01885                         CV(i,0), 
01886                         sPreamble );
01887     }
01888   }
01889 }
01890 
01891 int ON_BezierSurface::Dimension() const
01892 {
01893   return m_dim;
01894 }
01895 
01896 bool ON_BezierSurface::Create( int dim, ON_BOOL32 is_rat, int order0, int order1 )
01897 {
01898   if ( m_cv_capacity < 1 )
01899     m_cv = 0;
01900   m_dim = (dim>0) ? dim : 0;
01901   m_is_rat = is_rat ? 1 : 0;
01902   m_order[0] = (order0 >= 2) ? order0 : 0;
01903   m_order[1] = (order1 >= 2) ? order1 : 0;
01904   m_cv_stride[1] = (m_dim > 0) ? m_dim+m_is_rat : 0;
01905   m_cv_stride[0] = m_cv_stride[1]*m_order[1];
01906   m_cv_capacity = m_cv_stride[0]*m_order[0];
01907   m_cv = (double*)onrealloc( m_cv, m_cv_capacity*sizeof(m_cv[0]) );
01908   //m_domain[0].m_t[0] = 0.0;
01909   //m_domain[0].m_t[1] = 1.0;
01910   //m_domain[1].m_t[0] = 0.0;
01911   //m_domain[1].m_t[1] = 1.0;
01912   return IsValid();
01913 }
01914 
01915 void ON_BezierSurface::Destroy()
01916 {
01917   if ( m_cv && m_cv_capacity > 0 )
01918     onfree(m_cv);
01919   m_cv_capacity = 0;
01920   m_cv_stride[0] = 0;
01921   m_cv_stride[1] = 0;
01922   m_cv = 0;
01923   m_dim = 0;
01924   m_is_rat = 0;
01925   m_order[0] = 0;
01926   m_order[1] = 0;
01927   //m_domain[0].m_t[0] = 0.0;
01928   //m_domain[0].m_t[1] = 1.0;
01929   //m_domain[1].m_t[0] = 0.0;
01930   //m_domain[1].m_t[1] = 1.0;
01931 }
01932 
01933 void ON_BezierSurface::EmergencyDestroy()
01934 {
01935   m_cv = 0;
01936 }
01937 
01938 bool ON_BezierSurface::Loft( const ON_ClassArray<ON_BezierCurve>& curve_list )
01939 {
01940   int i;
01941   int count = curve_list.Count();
01942   ON_SimpleArray<const ON_BezierCurve*> ptr_list(count);
01943   for (i = 0; i < count; i++ )
01944   {
01945     ptr_list.Append(&curve_list[i]);
01946   }
01947   return Loft(ptr_list.Count(),ptr_list.Array());
01948 }
01949 
01950 bool ON_BezierSurface::Loft( 
01951         int curve_count,
01952         const ON_BezierCurve* const* curve_list
01953         )
01954 {
01955   // 06-06-06 Dale Fugier - tested
01956   bool rc = false;
01957   if (curve_count >= 2 && 0 != curve_list && 0 != curve_list[0] )
01958   {
01959     // determine order, dimension, is_rat, and cv_stride of compatible shape curves
01960     int shape_order = curve_list[0]->m_order;
01961     int shape_dim = curve_list[0]->m_dim;
01962     int shape_is_rat = (0 != curve_list[0]->m_is_rat) ? 1 : 0;
01963     if ( shape_dim < 1 || shape_order < 2 )
01964       return false;
01965     int i, j, k;
01966     for ( i = 0; i < curve_count; i++ )
01967     {
01968       if ( curve_list[i]->m_order < 2 || curve_list[i]->m_dim < 1 || 0 == curve_list[i]->m_cv)
01969         return false;
01970       if ( curve_list[i]->m_dim != shape_dim )
01971         return false;
01972       if ( curve_list[i]->m_order > shape_order )
01973         shape_order = curve_list[i]->m_order;
01974       if ( 0 != curve_list[i]->m_is_rat )
01975         shape_is_rat = 1;
01976     }
01977 
01978     // build a list of compatible shape curves
01979     const int shape_cv_stride = (shape_is_rat) ? (shape_dim + 1) : shape_dim;
01980     ON_SimpleArray<double> meta_point(curve_count*shape_cv_stride*shape_order);
01981     ON_BezierCurve* temp_shape = 0;
01982     for ( i = 0; i < curve_count; i++ )
01983     {
01984       const ON_BezierCurve* shape = curve_list[i];
01985       if (    shape->m_order != shape_order 
01986            || shape->m_is_rat != shape_is_rat
01987            || shape->m_cv_stride != shape_cv_stride )
01988       {
01989         if ( 0 == temp_shape )
01990           temp_shape = new ON_BezierCurve();
01991         temp_shape->operator=(*shape);
01992         if ( shape_is_rat )
01993           temp_shape->MakeRational();
01994         temp_shape->IncreaseDegree(shape_order-1);
01995         if ( temp_shape->m_dim != shape_dim 
01996               || temp_shape->m_is_rat != shape_is_rat 
01997               || temp_shape->m_order != shape_order 
01998               || temp_shape->m_cv_stride != shape_cv_stride )
01999         {
02000           break;
02001         }
02002         shape = temp_shape;
02003       }
02004       for ( int j = 0; j < shape->m_order; j++ )
02005       {
02006         const double* cv = shape->CV(j);
02007         for ( int k = 0; k < shape_cv_stride; k++ )
02008           meta_point.Append(cv[k]);
02009       }
02010     }
02011     if ( 0 != temp_shape )
02012     {
02013       delete temp_shape;
02014       temp_shape = 0;
02015     }
02016     if ( meta_point.Count() == curve_count*shape_cv_stride*shape_order )
02017     {
02018       ON_BezierCurve bez;
02019       ON_SimpleArray<double>t(curve_count);
02020       double dt = 1.0/((double)curve_count);
02021       for ( i = 0; i < curve_count; i++ )
02022       {
02023         t.Append( i*dt );
02024       }
02025       t[curve_count-1] = 1.0;
02026       // use high dimensional curve loft trick
02027       rc = bez.Loft( shape_cv_stride*shape_dim, curve_count, shape_cv_stride*shape_dim, meta_point.Array(), 1, t.Array() )
02028          ? true : false;
02029       if (rc)
02030       {
02031         Create(shape_dim,shape_is_rat,curve_count,shape_order);
02032         // fill in surface CVs
02033         for ( i = 0; i < curve_count; i++ )
02034         {
02035           const double* bez_cv = bez.CV(i);
02036           for ( j = 0; j < shape_order; j++ )
02037           {
02038             double* srf_cv = CV(i,j);
02039             for ( k = 0; k < shape_cv_stride; k++ )
02040               srf_cv[k] = *bez_cv++;
02041           }
02042         }
02043       }
02044     }
02045   }
02046   return rc;
02047 }
02048 
02049 bool ON_BezierSurface::GetBBox( // returns true if successful
02050        double* boxmin,    // minimum
02051        double* boxmax,    // maximum
02052        int bGrowBox  // true means grow box
02053        ) const
02054 {
02055   int i;
02056   bool rc = (m_order[0] > 0 && m_order[1] > 0) ? true : false;
02057   for ( i = 0; rc && i < m_order[0]; i++ ) {
02058     rc = ON_GetPointListBoundingBox( m_dim, m_is_rat, m_order[1], m_cv_stride[1],
02059                                     CV(i,0), boxmin, boxmax, bGrowBox );
02060     bGrowBox = true;
02061   }
02062   return rc;
02063 }
02064 
02065 bool ON_BezierSurface::GetBoundingBox( // returns true if successful
02066        ON_BoundingBox& bbox,
02067        int bGrowBox             // true means grow box
02068        ) const
02069 {
02070   double *boxmin, *boxmax;
02071   if ( m_dim > 3 ) 
02072   {
02073     boxmin = (double*)alloca(2*m_dim*sizeof(*boxmin));
02074     memset( boxmin, 0, 2*m_dim*sizeof(*boxmin) );
02075     boxmax = boxmin + m_dim;
02076     if ( bGrowBox ) {
02077       boxmin[0] = bbox.m_min.x;
02078       boxmin[1] = bbox.m_min.y;
02079       boxmin[2] = bbox.m_min.z;
02080       boxmax[0] = bbox.m_max.x;
02081       boxmax[1] = bbox.m_max.y;
02082       boxmax[2] = bbox.m_max.z;
02083     }
02084   }
02085   else {
02086     boxmin = &bbox.m_min.x;
02087     boxmax = &bbox.m_max.x;
02088   }
02089   bool rc = GetBBox( boxmin, boxmax, bGrowBox );
02090   if ( rc && m_dim > 3 ) {
02091     bbox.m_min = boxmin;
02092     bbox.m_max = boxmax;
02093   }
02094   return rc;
02095 }
02096 
02097 ON_BoundingBox ON_BezierSurface::BoundingBox() const
02098 {
02099   ON_BoundingBox bbox;
02100   if ( !GetBoundingBox(bbox,false) )
02101     bbox.Destroy();
02102   return bbox;
02103 }
02104 
02105 bool ON_BezierSurface::Transform( const ON_Xform& xform )
02106 {
02107   int i;
02108   bool rc = (m_order[0] > 0 && m_order[1] > 0) ? true : false;
02109   if (rc)
02110   {  
02111     if ( 0 == m_is_rat )
02112     {
02113       if ( xform.m_xform[3][0] != 0.0 || xform.m_xform[3][1] != 0.0 || xform.m_xform[3][2] != 0.0 )
02114       {
02115         MakeRational();
02116       }
02117     }
02118   
02119     for ( i = 0; rc && i < m_order[0]; i++ ) 
02120     {
02121       rc = ON_TransformPointList( m_dim, m_is_rat, 
02122                                   m_order[1], m_cv_stride[1], 
02123                                   CV(i,0), xform );
02124     }
02125   }
02126   return rc;
02127 }
02128 
02129 bool ON_BezierSurface::Rotate(
02130       double sin_angle,          // sin(angle)
02131       double cos_angle,          // cos(angle)
02132       const ON_3dVector& axis, // axis of rotation
02133       const ON_3dPoint& center // center of rotation
02134       )
02135 {
02136   ON_Xform rot;
02137   rot.Rotation( sin_angle, cos_angle, axis, center );
02138   return Transform( rot );
02139 }
02140 
02141 bool ON_BezierSurface::Rotate(
02142       double angle,              // angle in radians
02143       const ON_3dVector& axis, // axis of rotation
02144       const ON_3dPoint& center // center of rotation
02145       )
02146 {
02147   return Rotate( sin(angle), cos(angle), axis, center );
02148 }
02149 
02150 bool ON_BezierSurface::Translate( const ON_3dVector& delta )
02151 {
02152   ON_Xform tr;
02153   tr.Translation( delta );
02154   return Transform( tr );
02155 }
02156 
02157 bool ON_BezierSurface::Scale( double x )
02158 {
02159   ON_Xform s;
02160   s.Scale( x, x, x );
02161   return Transform( s );
02162 }
02163 
02164 ON_Interval ON_BezierSurface::Domain( 
02165       int // dir - formal parameter intentionally ignored in this virtual function
02166       ) const
02167 {
02168   // 0 = "u" domain, 1 = "v" domain
02169   return ON_Interval(0.0,1.0); //m_domain[(dir>0)?1:0];
02170 }
02171 
02172 bool ON_BezierSurface::Reverse( int  dir )
02173 {
02174   int i;
02175   bool rc = (m_order[0] > 0 && m_order[1] > 0) ? true : false;
02176   if ( dir > 0 ) {
02177     for ( i = 0; rc && i < m_order[0]; i++ ) {
02178       rc = ON_ReversePointList( m_dim, m_is_rat, m_order[1], m_cv_stride[1], CV(i,0) );
02179     }
02180     //m_domain[1].Reverse();
02181   }
02182   else {
02183     for ( i = 0; rc && i < m_order[1]; i++ ) {
02184       rc = ON_ReversePointList( m_dim, m_is_rat, m_order[0], m_cv_stride[0], CV(0,i) );
02185     }
02186     //m_domain[0].Reverse();
02187   }
02188   return rc;
02189 }
02190 
02191 bool ON_BezierSurface::Transpose()
02192 {
02193   // transpose surface parameterization (swap "s" and "t")
02194   int i = m_order[0]; m_order[0] = m_order[1]; m_order[1] = i;
02195   i = m_cv_stride[0]; m_cv_stride[0] = m_cv_stride[1]; m_cv_stride[1] = i;
02196   //ON_Interval d = m_domain[0]; m_domain[0] = m_domain[1]; m_domain[1] = d;
02197   return true;
02198 }
02199 
02200 bool ON_BezierSurface::Evaluate( // returns false if unable to evaluate
02201        double s, double t,       // evaluation parameter
02202        int der_count,            // number of derivatives (>=0)
02203        int v_stride,             // array stride (>=Dimension())
02204        double* v                 // array of length stride*(ndir+1)*(ndir+2)/2
02205        ) const
02206 {
02207   // TODO: When time permits write a faster special case bezier surface evaluator.
02208   // For now, cook up some fake knot vectors and use NURBS surface span evaluator.
02209   double *knot0, *knot1, *p;
02210   int deg0 = m_order[0]-1;
02211   int deg1 = m_order[1]-1;
02212   int i = (deg0<=deg1)?deg1 : deg0;
02213   p = knot0 = (double*)alloca(i*2*sizeof(*knot0));
02214   memset(p,0,i*sizeof(*p));
02215   p += i;
02216   while (i--) *p++ = 1.0;
02217   if ( deg0 >= deg1 ) {
02218     knot1 = knot0 + (deg0-deg1);
02219   }
02220   else {
02221     knot1 = knot0;
02222     knot0 = knot1 + (deg1-deg0);
02223   }
02224 
02225   return ON_EvaluateNurbsSurfaceSpan(
02226         m_dim,                          // dimension
02227         m_is_rat,                       // true if NURBS is rational
02228         m_order[0], m_order[1],         // order0, order1
02229         knot0,                          // knot0[] array of (2*order0-2) doubles
02230         knot1,                          // knot1[] array of (2*order1-2) doubles
02231         m_cv_stride[0], m_cv_stride[1], // cv_stride0, cv_stride1
02232         m_cv,                          // cv at "lower left" of bispan
02233         der_count,                      // number of derivatives to compute (>=0)
02234         s,t,                            // evaluation parameters ("s" and "t")
02235         v_stride,                       // answer_stride (>=dimension)
02236         v                               // answer[] array of length (ndir+1)*answer_stride
02237         );
02238 }
02239 
02240 ON_3dPoint ON_BezierSurface::PointAt(double s, double t) const
02241 {
02242   ON_3dPoint P;
02243   Evaluate(s,t,0,3,&P.x);
02244   return P;
02245 }
02246 
02247 ON_BezierCurve* ON_BezierSurface::IsoCurve(int dir, double t, ON_BezierCurve* pCrv) const
02248 {
02249         if( pCrv == NULL )
02250   {
02251                 pCrv = new ON_BezierCurve(m_dim, m_is_rat, m_order[dir]);
02252         }
02253         else if ( pCrv->m_dim!=m_dim || pCrv->m_is_rat!= m_is_rat || pCrv->m_order!= m_order[dir])
02254   {
02255                 pCrv->Create(m_dim, m_is_rat, m_order[dir]);
02256   }
02257         
02258 
02259         int bigdim = CVSize() * m_order[dir];
02260         int stride;
02261         double* cv = 0;
02262         double* workspace = 0;
02263         if( m_cv_stride[1-dir]>m_cv_stride[dir])
02264   {
02265                 stride = m_cv_stride[1-dir];
02266                 cv = m_cv;
02267         }
02268         else
02269   {
02270                 // purify FMM trauma - // workspace = new double[bigdim*m_order[1-dir]];
02271                 workspace = (double*)onmalloc((bigdim*m_order[1-dir])*sizeof(*workspace));
02272 
02273                 cv = workspace;
02274                 stride = bigdim;
02275 
02276                 int i,j;
02277                 int cvsize = CVSize();
02278                 int cvsize_bytes = cvsize*sizeof(double);
02279                 double* dst = workspace;
02280                 for(i=0; i<m_order[1-dir] ; i++)
02281     {
02282                         double* src = dir ? CV(i,0): CV(0,i);
02283                         for(j=0; j<m_order[dir]; j++,dst+=cvsize, src+=m_cv_stride[dir] )
02284                                 memcpy(dst, src, cvsize_bytes ); 
02285                 }
02286         }
02287 
02288         ON_EvaluateBezier( bigdim, 0, m_order[1-dir], stride,  cv, 0.0, 1.0, 0, t, bigdim, pCrv->m_cv );
02289 
02290         if(workspace)
02291   {
02292                 // purify FMM trauma - // delete[] workspace;
02293     onfree(workspace);
02294   }
02295 
02296         return pCrv;
02297 }
02298 
02299 bool ON_BezierSurface::GetNurbForm( ON_NurbsSurface& n ) const
02300 {
02301   bool rc = false;
02302   if ( n.Create( m_dim, m_is_rat, m_order[0], m_order[1], m_order[0], m_order[1] ) ) 
02303   {
02304     if ( n.m_cv == m_cv )
02305     {
02306       n.m_cv_stride[0] = m_cv_stride[0];
02307       n.m_cv_stride[1] = m_cv_stride[1];
02308     }
02309     else
02310     {
02311       const int sizeof_cv = CVSize()*sizeof(m_cv[0]);
02312       int i,j;
02313       for ( i = 0; i < m_order[0]; i++ ) for ( j = 0; j < m_order[1]; j++ ) {
02314         memcpy( n.CV(i,j), CV(i,j), sizeof_cv );
02315       }
02316     }
02317     n.m_knot[0][m_order[0]-2] = 0.0;  //m_domain[0].Min();
02318     n.m_knot[0][m_order[0]-1] = 1.0;    //m_domain[0].Max();
02319     n.m_knot[1][m_order[1]-2] = 0.0;    //m_domain[1].Min();
02320     n.m_knot[1][m_order[1]-1] = 1.0;    //m_domain[1].Max();
02321     rc = ON_ClampKnotVector( n.m_order[0], n.m_cv_count[0], n.m_knot[0], 2 );
02322     rc = ON_ClampKnotVector( n.m_order[1], n.m_cv_count[1], n.m_knot[1], 2 );
02323   }
02324   return rc;
02325 }
02326 
02327 bool ON_BezierSurface::IsRational() const
02328 {
02329   return m_is_rat ? true : false;
02330 }
02331 
02332 int ON_BezierSurface::CVSize() const
02333 {
02334   return ( m_is_rat && m_dim>0 ) ? m_dim+1 : m_dim;
02335 }
02336 
02337 int ON_BezierSurface::Order( int dir ) const
02338 {
02339   return (dir>=0&&dir<=1) ? m_order[dir] : 0;
02340 }
02341 
02342 int ON_BezierSurface::Degree(int dir) const
02343 {
02344   int order = Order(dir);
02345   return (order>=2) ? order-1 : 0;
02346 }
02347 
02348 double* ON_BezierSurface::CV( int i, int j ) const
02349 {
02350   return (m_cv) ? (m_cv + i*m_cv_stride[0] + j*m_cv_stride[1]) : NULL;
02351 }
02352 
02353 ON::point_style ON_BezierSurface::CVStyle() const
02354 {
02355   return m_is_rat ? ON::homogeneous_rational : ON::not_rational;
02356 }
02357 
02358 double ON_BezierSurface::Weight( int i, int j ) const
02359 {
02360   return (m_cv && m_is_rat) ? m_cv[i*m_cv_stride[0] + j*m_cv_stride[1] + m_dim] : 1.0;
02361 }
02362 
02363 
02364 bool ON_BezierSurface::SetWeight( int i, int j, double w )
02365 {
02366   bool rc = false;
02367   if ( m_is_rat ) {
02368     double* cv = CV(i,j);
02369     if (cv) {
02370       cv[m_dim] = w;
02371       rc = true;
02372     }
02373   }
02374   else if ( w == 1.0 ) {
02375     rc = true;
02376   }
02377   return rc;
02378 }
02379 
02380 bool ON_BezierSurface::SetCV( int i, int j, ON::point_style style, const double* Point )
02381 {
02382   bool rc = true;
02383   int k;
02384   double w;
02385 
02386   double* cv = CV(i,j);
02387   if ( !cv )
02388     return false;
02389 
02390   switch ( style ) {
02391 
02392   case ON::not_rational:  // input Point is not rational
02393     memcpy( cv, Point, m_dim*sizeof(*cv) );
02394     if ( IsRational() ) {
02395       // NURBS surface is rational - set weight to one
02396       cv[m_dim] = 1.0;
02397     }
02398     break;
02399 
02400   case ON::homogeneous_rational:  // input Point is homogeneous rational
02401     if ( IsRational() ) {
02402       // NURBS surface is rational
02403       memcpy( cv, Point, (m_dim+1)*sizeof(*cv) );
02404     }
02405     else {
02406       // NURBS surface is not rational
02407       w = (Point[m_dim] != 0.0) ? 1.0/Point[m_dim] : 1.0;
02408       for ( k = 0; k < m_dim; k++ ) {
02409         cv[k] = w*Point[k];
02410       }
02411     }
02412     break;
02413 
02414   case ON::euclidean_rational:  // input Point is euclidean rational
02415     if ( IsRational() ) {
02416       // NURBS surface is rational - convert euclean point to homogeneous form
02417       w = Point[m_dim];
02418       for ( k = 0; k < m_dim; k++ )
02419         cv[i] = w*Point[i];
02420       cv[m_dim] = w;
02421     }
02422     else {
02423       // NURBS surface is not rational
02424       memcpy( cv, Point, m_dim*sizeof(*cv) );
02425     }
02426     break;
02427 
02428   case ON::intrinsic_point_style:
02429     k = m_is_rat?m_dim+1:m_dim;
02430     memcpy(cv,Point,k*sizeof(*cv));
02431     break;
02432     
02433   default:
02434     rc = false;
02435     break;
02436   }
02437   return rc;
02438 }
02439 
02440 bool ON_BezierSurface::SetCV( int i, int j, const ON_3dPoint& point )
02441 {
02442   bool rc = false;
02443   double* cv = CV(i,j);
02444   if ( cv ) {
02445     cv[0] = point.x;
02446     if ( m_dim > 1 ) {
02447       cv[1] = point.y;
02448       if ( m_dim > 2 )
02449         cv[2] = point.z;
02450     }
02451     if ( m_is_rat ) {
02452       cv[m_dim] = 1.0;
02453     }
02454     rc = true;
02455   }
02456   return rc;
02457 }
02458 
02459 bool ON_BezierSurface::SetCV( int i, int j, const ON_4dPoint& point )
02460 {
02461   bool rc = false;
02462   double* cv = CV(i,j);
02463   if ( cv ) {
02464     if ( m_is_rat ) {
02465       cv[0] = point.x;
02466       if ( m_dim > 1 ) {
02467         cv[1] = point.y;
02468         if ( m_dim > 2 )
02469           cv[2] = point.z;
02470       }
02471       cv[m_dim] = point.w;
02472       rc = true;
02473     }
02474     else {
02475       double w;
02476       if ( point.w != 0.0 ) {
02477         w = 1.0/point.w;
02478         rc = true;
02479       }
02480       else {
02481         w = 1.0;
02482       }
02483       cv[0] = w*point.x;
02484       if ( m_dim > 1 ) {
02485         cv[1] = w*point.y;
02486         if ( m_dim > 2 ) {
02487           cv[2] = w*point.z;
02488         }
02489       }
02490     }
02491   }
02492   return rc;
02493 }
02494 
02495 bool ON_BezierSurface::GetCV( int i, int j, ON::point_style style, double* Point ) const
02496 {
02497   const double* cv = CV(i,j);
02498   if ( !cv )
02499     return false;
02500   int dim = Dimension();
02501   double w = ( IsRational() ) ? cv[dim] : 1.0;
02502   switch(style) {
02503   case ON::euclidean_rational:
02504     Point[dim] = w;
02505     // no break here
02506   case ON::not_rational:
02507     if ( w == 0.0 )
02508       return false;
02509     w = 1.0/w;
02510     while(dim--) *Point++ = *cv++ * w;
02511     break;
02512   case ON::homogeneous_rational:
02513     Point[dim] = w;
02514     memcpy( Point, cv, dim*sizeof(*Point) );
02515     break;
02516   default:
02517     return false;
02518   }
02519   return true;
02520 }
02521 
02522 bool ON_BezierSurface::GetCV( int i, int j, ON_3dPoint& point ) const
02523 {
02524   bool rc = false;
02525   const double* cv = CV(i,j);
02526   if ( cv ) {
02527     if ( m_is_rat ) {
02528       if (cv[m_dim] != 0.0) {
02529         const double w = 1.0/cv[m_dim];
02530         point.x = cv[0]*w;
02531         point.y = (m_dim>1)? cv[1]*w : 0.0;
02532         point.z = (m_dim>2)? cv[2]*w : 0.0;
02533         rc = true;
02534       }
02535     }
02536     else {
02537       point.x = cv[0];
02538       point.y = (m_dim>1)? cv[1] : 0.0;
02539       point.z = (m_dim>2)? cv[2] : 0.0;
02540       rc = true;
02541     }
02542   }
02543   return rc;
02544 }
02545 
02546 bool ON_BezierSurface::GetCV( int i, int j, ON_4dPoint& point ) const
02547 {
02548   bool rc = false;
02549   const double* cv = CV(i,j);
02550   if ( cv ) {
02551     point.x = cv[0];
02552     point.y = (m_dim>1)? cv[1] : 0.0;
02553     point.z = (m_dim>2)? cv[2] : 0.0;
02554     point.w = (m_is_rat) ? cv[m_dim] : 1.0;
02555     rc = true;
02556   }
02557   return rc;
02558 }
02559 
02560 bool ON_BezierSurface::ZeroCVs()
02561 {
02562   // zeros control vertices and, if rational, sets weights to 1
02563   bool rc = false;
02564   int i,j;
02565   if ( m_cv ) {
02566     if ( m_cv_capacity > 0 ) {
02567       memset( m_cv, 0, m_cv_capacity*sizeof(*m_cv) );
02568       if ( m_is_rat ) {
02569         for ( i = 0; i < m_order[0]; i++ ) {
02570           for ( j = 0; j < m_order[1]; j++ ) {
02571             SetWeight( i,j, 1.0 );
02572           }
02573         }
02574       }
02575       rc = true;
02576     }
02577     else {
02578       double* cv;
02579       int s = CVSize()*sizeof(*cv);
02580       for ( i = 0; i < m_order[0]; i++ ) {
02581         for ( j = 0; j < m_order[1]; j++ ) {
02582           cv = CV(i,j);
02583           memset(cv,0,s);
02584           if ( m_is_rat )
02585             cv[m_dim] = 1.0;
02586         }
02587       }
02588       rc = (i>0) ? true : false;
02589     }
02590   }
02591   return rc;
02592 }
02593 
02594 bool ON_BezierSurface::MakeRational()
02595 {
02596   if ( !IsRational() ) {
02597     const int dim = Dimension();
02598     if ( m_order[0] > 0 && m_order[1] > 0 && dim > 0 ) {
02599       const double* old_cv;
02600       double* new_cv;
02601       int cvi, cvj, j, cvstride;
02602       if ( m_cv_stride[0] < m_cv_stride[1] ) {
02603         cvstride = m_cv_stride[0] > dim ? m_cv_stride[0] : dim+1;
02604         ReserveCVCapacity( cvstride*m_order[0]*m_order[1] );
02605         new_cv = m_cv + cvstride*m_order[0]*m_order[1]-1;
02606                                 for ( cvj = m_order[1]-1; cvj >= 0; cvj-- ) {
02607           for ( cvi = m_order[0]-1; cvi >= 0; cvi-- ) {
02608             old_cv = CV(cvi,cvj)+dim-1;
02609             *new_cv-- = 1.0;
02610             for ( j = 0; j < dim; j++ ) {
02611               *new_cv-- = *old_cv--;
02612             }
02613           }
02614         }
02615         m_cv_stride[0] = dim+1;
02616         m_cv_stride[1] = (dim+1)*m_order[0];
02617       }
02618       else {
02619         cvstride = m_cv_stride[1] > dim ? m_cv_stride[1] : dim+1;
02620         ReserveCVCapacity( cvstride*m_order[0]*m_order[1] );
02621         new_cv = m_cv + cvstride*m_order[0]*m_order[1]-1;
02622         for ( cvi = m_order[0]-1; cvi >= 0; cvi-- ) {
02623           for ( cvj = m_order[1]-1; cvj >= 0; cvj-- ) {
02624             old_cv = CV(cvi,cvj)+dim-1;
02625             *new_cv-- = 1.0;
02626             for ( j = 0; j < dim; j++ ) {
02627               *new_cv-- = *old_cv--;
02628             }
02629           }
02630         }
02631         m_cv_stride[1] = dim+1;
02632         m_cv_stride[0] = (dim+1)*m_order[1];
02633       }
02634       m_is_rat = 1;
02635     }
02636   }
02637   return IsRational();
02638 }
02639 
02640 bool ON_BezierSurface::MakeNonRational()
02641 {
02642   if ( IsRational() ) {
02643     const int dim = Dimension();
02644     if ( m_order[0] > 0 && m_order[1] > 0 && dim > 0 ) {
02645       double w;
02646       const double* old_cv;
02647       double* new_cv = m_cv;
02648       int cvi, cvj, j;
02649       if ( m_cv_stride[0] < m_cv_stride[1] ) {
02650         for ( cvj = 0; cvj < m_order[1]; cvj++ ) {
02651           for ( cvi = 0; cvi < m_order[0]; cvi++ ) {
02652             old_cv = CV(cvi,cvj);
02653             w = old_cv[dim];
02654             w = ( w != 0.0 ) ? 1.0/w : 1.0;
02655             for ( j = 0; j < dim; j++ ) {
02656               *new_cv++ = w*(*old_cv++);
02657             }
02658           }
02659         }
02660         m_cv_stride[0] = dim;
02661         m_cv_stride[1] = dim*m_order[0];
02662       }
02663       else {
02664         for ( cvi = 0; cvi < m_order[0]; cvi++ ) {
02665           for ( cvj = 0; cvj < m_order[1]; cvj++ ) {
02666             old_cv = CV(cvi,cvj);
02667             w = old_cv[dim];
02668             w = ( w != 0.0 ) ? 1.0/w : 1.0;
02669             for ( j = 0; j < dim; j++ ) {
02670               *new_cv++ = w*(*old_cv++);
02671             }
02672           }
02673         }
02674         m_cv_stride[1] = dim;
02675         m_cv_stride[0] = dim*m_order[1];
02676       }
02677       m_is_rat = 0;
02678     }
02679   }
02680   return ( !IsRational() ) ? true : false;
02681 }
02682 
02684 // Tools for managing CV and knot memory
02685 bool ON_BezierSurface::ReserveCVCapacity(
02686   int capacity// number of doubles to reserve
02687   )
02688 {
02689   if ( m_cv_capacity < capacity ) {
02690     if ( m_cv ) {
02691       if ( m_cv_capacity ) {
02692         m_cv = (double*)onrealloc( m_cv, capacity*sizeof(*m_cv) );
02693         m_cv_capacity = (m_cv) ? capacity : 0;
02694       }
02695       // else user supplied m_cv[] array
02696     }
02697     else {
02698       m_cv = (double*)onmalloc( capacity*sizeof(*m_cv) );
02699       m_cv_capacity = (m_cv) ? capacity : 0;
02700     }
02701   }
02702   return ( m_cv ) ? true : false;
02703 }
02704 
02705 bool ON_BezierSurface::Trim(
02706       int dir,
02707       const ON_Interval& domain
02708       )
02709 {
02710   bool rc = false;
02711   ON_BezierCurve crv;
02712   double* cv;
02713   const int k = m_is_rat ? (m_dim+1) : m_dim;
02714   const int sizeofcv = k*sizeof(*cv);
02715   
02716   // GBA 5-Dec-2007.  Rewrote this function.  The previous implementation
02717   // would never work if dir==0.
02718    
02719   if( m_cv_stride[dir] > m_cv_stride[1-dir])
02720   {
02721     // cv's are layed out in the right direction so we can interpret the 
02722     // them as the cv's of a high dim'l curve.
02723     crv.m_cv = m_cv;
02724     crv.m_dim = crv.m_cv_stride = m_cv_stride[dir]; 
02725     crv.m_is_rat = false;
02726     crv.m_order = m_order[0];
02727 
02728     rc = crv.Trim(domain);
02729 
02730     crv.m_cv = NULL;
02731     crv.m_dim = crv.m_order = crv.m_cv_stride = 0;
02732   }
02733 
02734   else
02735   {
02736     // cv's are layed out in the wrong direction so make a curve
02737     // and copy the cv's into the curve.
02738 
02739     crv.Create(k*m_order[1-dir],false,m_order[dir]);
02740     int ind[2];
02741     int& i= ind[dir];
02742     int& j= ind[1-dir];
02743     for( i=0; i<m_order[dir]; i++)
02744     {
02745       cv = crv.CV(i);
02746       for( j=0; j<m_order[1-dir]; j++){
02747         memcpy( cv, CV( ind[0],ind[1]), sizeofcv);
02748         cv += k;
02749       }
02750     }
02751 
02752     rc = crv.Trim(domain);
02753 
02754     if (rc)
02755     {
02756       for( i=0; i<m_order[dir]; i++)
02757       {
02758         cv = crv.CV(i);
02759         for( j=0; j<m_order[1-dir]; j++){
02760           memcpy( CV( ind[0],ind[1]), cv, sizeofcv);
02761           cv += k;
02762         }
02763       }      
02764     }
02765   }
02766 
02767 
02768   return rc;
02769 }
02770 
02771 
02772 bool ON_BezierSurface::Split( 
02773        int dir, // 0 split at "u"=t, 1= split at "v"=t
02774        double t, // t = splitting parameter must 0 < t < 1
02775        ON_BezierSurface& left_bez, // west/south side returned here (can pass *this)
02776        ON_BezierSurface& right_bez // east/north side returned here (can pass *this)
02777        ) const
02778 {
02779   bool rc = false;
02780   if ( 0.0 < t && t < 1.0 ) {
02781     double *crvcv;
02782     int i, j;
02783     const int hdim = (m_is_rat) ? m_dim+1 : m_dim;
02784     const int crvdim =  hdim*m_order[dir?0:1];
02785     ON_BezierCurve leftcrv, rightcrv;
02786     ON_BezierCurve crv(crvdim,0,m_order[dir?1:0]);
02787     if (dir) {
02788       for ( j = 0; j < m_order[1]; j++ ) {
02789         crvcv = crv.CV(j);
02790         for ( i = 0; i < m_order[0]; i++) {
02791           memcpy( crvcv, CV(i,j), hdim*sizeof(crvcv[0]) );
02792           crvcv += hdim;
02793         }
02794       }
02795     }
02796     else {
02797       for ( i = 0; i < m_order[0]; i++) {
02798         crvcv = crv.CV(i);
02799         for ( j = 0; j < m_order[1]; j++ ) {
02800           memcpy( crvcv, CV(i,j), hdim*sizeof(crvcv[0]) );
02801           crvcv += hdim;
02802         }
02803       }
02804     }
02805 
02806     // transfer output srf cv memory to output curves
02807     leftcrv.m_cv_capacity = left_bez.m_cv_capacity;
02808     leftcrv.m_cv = left_bez.m_cv;
02809     left_bez.m_cv = 0;
02810 
02811     rightcrv.m_cv_capacity = right_bez.m_cv_capacity;
02812     rightcrv.m_cv = right_bez.m_cv;
02813     right_bez.m_cv = 0;
02814 
02815     // call curve splitter
02816     rc = crv.Split( t, leftcrv, rightcrv );
02817 
02818     // transfer output crv cv memory back to output surfaces
02819     left_bez.m_cv_capacity = leftcrv.m_cv_capacity;
02820     left_bez.m_cv = leftcrv.m_cv;
02821     leftcrv.m_cv = 0;
02822 
02823     right_bez.m_cv_capacity = rightcrv.m_cv_capacity;
02824     right_bez.m_cv = rightcrv.m_cv;
02825     rightcrv.m_cv = 0;
02826 
02827     if ( rc ) 
02828     {
02829       // Greg Arden,    12 May 2003 Fixes TRR 10627.  This block of code was wrong. 
02830       right_bez.m_dim      = left_bez.m_dim      = m_dim;
02831       right_bez.m_is_rat   = left_bez.m_is_rat   = m_is_rat;
02832       right_bez.m_order[0] = left_bez.m_order[0] = m_order[0];
02833       right_bez.m_order[1] = left_bez.m_order[1] = m_order[1];
02834       right_bez.m_cv_stride[1-dir] = left_bez.m_cv_stride[1-dir] = hdim;                        
02835       left_bez.m_cv_stride[dir]    = leftcrv.m_cv_stride;  // 3 March 2005 - Dale Lear changed crvdim to m_cv_stride
02836       right_bez.m_cv_stride[dir]   = rightcrv.m_cv_stride;
02837     }
02838   }
02839 
02840   return rc;
02841 }
02842 
02843 
02844 bool ON_BezierSurface::IsSingular(               // true if surface side is collapsed to a point
02845        int side                                                                                                          // side of parameter space to test
02846                                                                                                                                                         // 0 = south, 1 = east, 2 = north, 3 = west
02847                                 ) const
02848 {
02849   const double* points = 0;
02850   int point_count = 0;
02851   int point_stride = 0;
02852 
02853   switch ( side ) 
02854   {
02855   case 0: // south
02856     points = CV(0,0);
02857     point_count = m_order[0];
02858     point_stride = m_cv_stride[0];
02859     break;
02860 
02861   case 1: // east
02862     points = CV(m_order[0]-1,0);
02863     point_count = m_order[1];
02864     point_stride = m_cv_stride[1];
02865     break;
02866 
02867   case 2: // north
02868     points = CV(0,m_order[1]-1);
02869     point_count = m_order[0];
02870     point_stride = m_cv_stride[0];
02871     break;
02872 
02873   case 3: // west
02874     points = CV(0,0);
02875     point_count = m_order[1];
02876     point_stride = m_cv_stride[1];
02877     break;
02878 
02879   default:
02880     return false;
02881     break;
02882   }
02883 
02884   return ON_PointsAreCoincident(m_dim,m_is_rat,point_count,point_stride,points);
02885 }
02886 
02887 bool ON_ReparameterizeRationalBezierCurve(
02888           double c,
02889           int dim,
02890           int order,
02891           int cvstride,
02892           double* cv
02893           )
02894 {
02895   double d;
02896   int j;
02897 
02898   if ( !ON_IsValid(c) || 0.0 == c )
02899     return false;
02900 
02901   if (c == 1.0) 
02902     return true;
02903 
02904   d = c;
02905   cv += cvstride;
02906   dim++;
02907   cvstride -= dim; 
02908   while(--order) 
02909   {
02910     j = dim;
02911     while(j--) 
02912       *cv++ *= d;
02913     cv += cvstride;
02914     d *= c;
02915   }
02916 
02917   return true;
02918 }
02919 
02920 bool ON_BezierCurve::Reparametrize( double c )
02921 {
02922   return Reparameterize(c);
02923 }
02924 
02925 bool ON_BezierCurve::Reparameterize( double c )
02926 {
02927   if ( !ON_IsValid(c) || 0.0 == c )
02928     return false;
02929 
02930   if (c == 1.0) 
02931     return true;
02932 
02933   MakeRational();
02934 
02935   return ON_ReparameterizeRationalBezierCurve(c,m_dim,m_order,m_cv_stride,m_cv);
02936 
02937   //return true;
02938 }
02939 
02940 bool ON_BezierCurve::ScaleConrolPoints( int i, double w )
02941 {
02942   if ( i < 0 || i >= m_order || w == 0.0 || w == ON_UNSET_VALUE )
02943     return false;
02944   if ( w == Weight(i) )
02945     return true;
02946 
02947   if ( !IsRational() )
02948     MakeRational();
02949 
02950   double c = Weight(i);
02951   if ( 0.0 == c || ON_UNSET_VALUE == c )
02952     return false;
02953   c = w/c;
02954 
02955   int k, j;
02956   double* cv;
02957   int cvdim = CVSize();
02958   for ( k = 0; k < m_order; k++ )
02959   {
02960     cv = CV(k);
02961     j = cvdim;
02962     while(j--) 
02963       *cv++ *= c;
02964   }
02965   CV(i)[m_dim] = w;
02966 
02967   return true;
02968 }
02969 
02970 bool ON_ChangeRationalBezierCurveWeights(
02971           int dim, int order, int cvstride, double* cv,
02972           int i0, double w0, 
02973           int i1, double w1
02974           )
02975 {
02976   // Reference - Farauki
02977   double r, s, v0, v1;
02978   int i, j;
02979 
02980   if ( !ON_IsValid(w0) || !ON_IsValid(w1) || 0.0 == w0 || 0.0 == w1 )
02981     return false;
02982   if ( i0 < 0 || i1 >= order )
02983     return false;
02984   if ( i0 == i1 && w0 != w1 )
02985     return false;
02986   if ( (w0 < 0.0 && w1 > 0.0) || (w0 > 0.0 && w0 < 0.0) )
02987     return false;
02988   if (i0 > i1) 
02989   {
02990     i = i0; i0 = i1; i1 = i; r = w0; w0 = w1; w1 = r;
02991   }
02992 
02993   v0 = cv[cvstride*i0 + dim];
02994   v1 = cv[cvstride*i1 + dim];
02995   if (!ON_IsValid(v0) || !ON_IsValid(v1) || v0 == 0.0 || v1 == 0.0)
02996     return false;
02997   if (v0 < 0.0 && v1 > 0.0)
02998     return false;
02999   if ( v0 > 0.0 && v1 < 0.0)
03000     return false;
03001 
03002   if (i0 == 0 || i0 == i1) 
03003   {
03004     s = w0/v0;
03005     r = (i0 != i1) ? pow( (w1/v1)/s, 1.0/((double)i1)) : 1.0;
03006   }
03007   else 
03008   {
03009     r = pow( (w1/v1)*(v0/w0), 1.0/((double)(i1-i0)) );
03010     s = (w0/v0)/pow(r,(double)i0);
03011   }
03012   if ( !ON_IsValid(r) || r <= 0.0 ) 
03013     return false;
03014   if ( !ON_IsValid(s) || 0.0 == s ) 
03015     return false;
03016 
03017   if (s != 1.0) 
03018   {
03019     dim++;
03020     cvstride -= dim;
03021     for ( i = 0; i < order; i++ )
03022     {
03023       j = dim;
03024       while(j--)
03025         *cv++ *= s;
03026       cv += cvstride;
03027     }
03028     cvstride += dim;
03029     dim--;
03030     cv -= (cvstride*order);
03031   } 
03032   if (r != 1.0)
03033     ON_ReparameterizeRationalBezierCurve(r,dim,order,cvstride,cv);
03034 
03035   // make sure weights agree to the last bit! 
03036   cv[cvstride*i0+dim] = w0;
03037   cv[cvstride*i1+dim] = w1;
03038 
03039   return true;
03040 }
03041 
03042 bool ON_BezierCurve::ChangeWeights( int i0, double w0, int i1, double w1 )
03043 {
03044   //double r, s, v0, v1;
03045   double v0, v1;
03046   int i;
03047   // 2 June 2003 Dale Lear bug fixes made this function work
03048 
03049   if ( i0 < 0 || i0 >= m_order || i1 < 0 || i1 >= m_order )
03050     return false;
03051   if ( 0.0 == w0 || !ON_IsValid(w0) || 0.0 == w1 || !ON_IsValid(w1) )
03052     return false;
03053   if ( w0 < 0.0 && w1 > 0.0 )
03054     return false;
03055   if ( w0 > 0.0 && w1 < 0.0 )
03056     return false;
03057   if ( i0 == i1 && w0 != w1 )
03058     return false;
03059 
03060   if (i0 > i1) 
03061   {
03062     i = i0; i0 = i1; i1 = i; v0 = w0; w0 = w1; w1 = v0;
03063   }
03064 
03065   v0 = Weight(i0);
03066   v1 = Weight(i1);
03067   if ( w0 == v0 && w1 == v1 ) 
03068     return true;
03069 
03070   MakeRational();
03071   return ON_ChangeRationalBezierCurveWeights(m_dim,m_order,m_cv_stride,m_cv,i0,w0,i1,w1);
03072 
03073   /*
03074   if ( 0.0 == v0 || !ON_IsValid(v0) || 0.0 == v1 || !ON_IsValid(v1) )
03075     return false;
03076   if ( v0 < 0.0 && v1 > 0.0 )
03077     return false;
03078   if ( v0 > 0.0 && v1 < 0.0 )
03079     return false;
03080 
03081   if (i0 == 0 || i0 == i1) 
03082   {
03083     s = w0/v0;
03084     r = (i0 != i1) ? pow( (w1/v1)/s, 1.0/((double)i1)) : 1.0;
03085   }
03086   else 
03087   {
03088     r = pow( (w1/v1)*(v0/w0), 1.0/((double)(i1-i0)) );
03089     s = (w0/v0)/pow(r,(double)i0);
03090   }
03091   if (r <= 0.0) 
03092     return false;
03093   
03094   MakeRational();
03095   int j, cvdim = CVSize();
03096   double* cv;
03097   if (s != 1.0) 
03098   {
03099     for ( i = 0; i < m_order; i++ )
03100     {
03101       cv = CV(i);
03102       j = cvdim;
03103       while (j--) *cv++ *= s;
03104     }
03105   } 
03106   if (r != 1.0)
03107     Reparametrize(r);
03108 
03109   // make sure weights agree to the last bit! 
03110   CV(i0)[m_dim] = w0;
03111   CV(i1)[m_dim] = w1;
03112 
03113   return true;
03114   */
03115 }
03116 
03118 
03119 
03120 ON_3dPoint ON_BezierCurve::PointAt( double t ) const
03121 {
03122   ON_3dPoint p(0.0,0.0,0.0);
03123   EvPoint(t,p);
03124   return p;
03125 }
03126 
03127 ON_3dVector ON_BezierCurve::DerivativeAt( double t ) const
03128 {
03129   ON_3dPoint  p(0.0,0.0,0.0);
03130   ON_3dVector d(0.0,0.0,0.0);
03131   Ev1Der(t,p,d);
03132   return d;
03133 }
03134 
03135 ON_3dVector ON_BezierCurve::TangentAt( double t ) const
03136 {
03137   ON_3dPoint point;
03138   ON_3dVector tangent;
03139   EvTangent( t, point, tangent );
03140   return tangent;
03141 }
03142 
03143 ON_3dVector ON_BezierCurve::CurvatureAt( double t ) const
03144 {
03145   ON_3dPoint point;
03146   ON_3dVector tangent, kappa;
03147   EvCurvature( t, point, tangent, kappa );
03148   return kappa;
03149 }
03150 
03151 bool ON_BezierCurve::EvTangent(
03152        double t,
03153        ON_3dPoint& point,
03154        ON_3dVector& tangent
03155        ) const
03156 {
03157   ON_3dVector D1, D2;//, K;
03158   tangent.Zero();
03159   bool rc = Ev1Der( t, point, tangent );
03160   if ( rc && !tangent.Unitize() ) 
03161   {
03162     if ( Ev2Der( t, point, D1, D2 ) )
03163     {
03164       // Use l'Hopital's rule to show that if the unit tanget
03165       // exists, the 1rst derivative is zero, and the 2nd
03166       // derivative is nonzero, then the unit tangent is equal
03167       // to +/-the unitized 2nd derivative.  The sign is equal
03168       // to the sign of D1(s) o D2(s) as s approaches the 
03169       // evaluation parameter.
03170       tangent = D2;
03171       rc = tangent.Unitize();
03172       if ( rc )
03173       {
03174         ON_Interval domain = Domain();
03175         double tminus = 0.0;
03176         double tplus = 0.0;
03177         if ( domain.IsIncreasing() && ON_GetParameterTolerance( domain[0], domain[1], t, &tminus, &tplus ) )
03178         {
03179           ON_3dPoint p;
03180           ON_3dVector d1, d2;
03181           double eps = 0.0;
03182           double d1od2tol = 0.0; //1.0e-10; // 1e-5 is too big
03183           double d1od2;
03184           double tt = t;
03185           //double dt = 0.0;
03186 
03187           if ( t < domain[1] )
03188           {
03189             eps = tplus-t;
03190             if ( eps <= 0.0 || t+eps > domain.ParameterAt(0.1) )
03191               return rc;
03192           }
03193           else 
03194           {
03195             eps = tminus - t;
03196             if ( eps >= 0.0 || t+eps < domain.ParameterAt(0.9) )
03197               return rc;
03198           }
03199 
03200           int i, negative_count=0, zero_count=0;
03201           int test_count = 3;
03202           for ( i = 0; i < test_count; i++, eps *= 0.5 )
03203           {
03204             tt = t + eps;
03205             if ( tt == t )
03206               break;
03207             if (!Ev2Der( tt, p, d1, d2 ))
03208               break;
03209             d1od2 = d1*d2;
03210             if ( d1od2 > d1od2tol )
03211               break;
03212             if ( d1od2 < d1od2tol )
03213               negative_count++;
03214             else
03215               zero_count++;
03216           }
03217           if ( negative_count > 0 && test_count == negative_count+zero_count )
03218           {
03219             // all sampled d1od2 values were <= 0 
03220             // and at least one was strictly < 0.
03221             tangent.Reverse();
03222           }
03223         }
03224       }
03225     }
03226   }
03227   return rc;
03228 }
03229 
03230 bool ON_BezierCurve::EvCurvature(
03231        double t,
03232        ON_3dPoint& point,
03233        ON_3dVector& tangent,
03234        ON_3dVector& kappa
03235        ) const
03236 {
03237   ON_3dVector d1, d2;
03238   bool rc = Ev2Der( t, point, d1, d2 );
03239   if ( rc )
03240   {
03241     rc = ON_EvCurvature( d1, d2, tangent, kappa )?true:false;
03242   }
03243   return rc;
03244 }
03245 
03246 
03247 bool ON_BezierCurve::EvPoint( // returns false if unable to evaluate
03248        double t,         // evaluation parameter
03249        ON_3dPoint& point   // returns value of curve
03250        ) const
03251 {
03252   bool rc = false;
03253   double ws[128];
03254   double* v;
03255   if ( Dimension() <= 3 ) {
03256     v = &point.x;
03257     point.x = 0.0;
03258     point.y = 0.0;
03259     point.z = 0.0;
03260   }
03261   else if ( Dimension() <= 128 ) {
03262     v = ws;
03263   }
03264   else {
03265     v = (double*)onmalloc(Dimension()*sizeof(*v));
03266   }
03267   rc = Evaluate( t, 0, Dimension(), v );
03268   if ( Dimension() > 3 ) {
03269     point.x = v[0];
03270     point.y = v[1];
03271     point.z = v[2];
03272     if ( Dimension() > 128 )
03273       onfree(v);
03274   }
03275   return rc;
03276 }
03277 
03278 bool ON_BezierCurve::Ev1Der( // returns false if unable to evaluate
03279        double t,         // evaluation parameter
03280        ON_3dPoint& point,
03281        ON_3dVector& derivative
03282        ) const
03283 {
03284   bool rc = false;
03285   const int dim = Dimension();
03286   double ws[2*64];
03287   double* v;
03288   point.x = 0.0;
03289   point.y = 0.0;
03290   point.z = 0.0;
03291   derivative.x = 0.0;
03292   derivative.y = 0.0;
03293   derivative.z = 0.0;
03294   if ( dim <= 64 ) {
03295     v = ws;
03296   }
03297   else {
03298     v = (double*)onmalloc(2*dim*sizeof(*v));
03299   }
03300   rc = Evaluate( t, 1, dim, v);
03301   point.x = v[0];
03302   derivative.x = v[dim];
03303   if ( dim > 1 ) {
03304     point.y = v[1];
03305     derivative.y = v[dim+1];
03306     if ( dim > 2 ) {
03307       point.z = v[2];
03308       derivative.z = v[dim+2];
03309       if ( dim > 64 )
03310         onfree(v);
03311     }
03312   }
03313 
03314   return rc;
03315 }
03316 
03317 bool ON_BezierCurve::Ev2Der( // returns false if unable to evaluate
03318        double t,         // evaluation parameter
03319        ON_3dPoint& point,
03320        ON_3dVector& firstDervative,
03321        ON_3dVector& secondDervative
03322        ) const
03323 {
03324   bool rc = false;
03325   const int dim = Dimension();
03326   double ws[3*64];
03327   double* v;
03328   point.x = 0.0;
03329   point.y = 0.0;
03330   point.z = 0.0;
03331   firstDervative.x = 0.0;
03332   firstDervative.y = 0.0;
03333   firstDervative.z = 0.0;
03334   secondDervative.x = 0.0;
03335   secondDervative.y = 0.0;
03336   secondDervative.z = 0.0;
03337   if ( dim <= 64 ) {
03338     v = ws;
03339   }
03340   else {
03341     v = (double*)onmalloc(3*dim*sizeof(*v));
03342   }
03343   rc = Evaluate( t, 2, dim, v );
03344   point.x = v[0];
03345   firstDervative.x = v[dim];
03346   secondDervative.x = v[2*dim];
03347   if ( dim > 1 ) {
03348     point.y = v[1];
03349     firstDervative.y = v[dim+1];
03350     secondDervative.y = v[2*dim+1];
03351     if ( dim > 2 ) {
03352       point.z = v[2];
03353       firstDervative.z = v[dim+2];
03354       secondDervative.z = v[2*dim+2];
03355       if ( dim > 64 )
03356         onfree(v);
03357     }
03358   }
03359 
03360   return rc;
03361 }
03362 
03363 
03364 
03365 
03366 
03367 


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