00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00015
00016
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018
00019 ON_OBJECT_IMPLEMENT(ON_NurbsCurve,ON_Curve,"4ED7D4DD-E947-11d3-BFE5-0010830122F0");
00020
00021 ON_NurbsCurve* ON_NurbsCurve::New()
00022 {
00023 return new ON_NurbsCurve();
00024 }
00025
00026 ON_NurbsCurve* ON_NurbsCurve::New(
00027 const ON_NurbsCurve& nurbs_curve
00028 )
00029 {
00030 return new ON_NurbsCurve(nurbs_curve);
00031 }
00032
00033 ON_NurbsCurve* ON_NurbsCurve::New(
00034 const ON_BezierCurve& bezier_curve
00035 )
00036 {
00037 return new ON_NurbsCurve(bezier_curve);
00038 }
00039
00040 ON_NurbsCurve* ON_NurbsCurve::New(
00041 int dimension,
00042 ON_BOOL32 bIsRational,
00043 int order,
00044 int cv_count
00045 )
00046 {
00047 return new ON_NurbsCurve(dimension,bIsRational,order,cv_count);
00048 }
00049
00050
00051 ON_NurbsCurve::ON_NurbsCurve()
00052 {
00053 ON__SET__THIS__PTR(m_s_ON_NurbsCurve_ptr);
00054 Initialize();
00055 }
00056
00057 ON_NurbsCurve::ON_NurbsCurve( const ON_NurbsCurve& src )
00058 {
00059 ON__SET__THIS__PTR(m_s_ON_NurbsCurve_ptr);
00060 Initialize();
00061 *this = src;
00062 }
00063
00064 ON_NurbsCurve::ON_NurbsCurve( int dim, ON_BOOL32 bIsRational, int order, int cv_count )
00065 {
00066 ON__SET__THIS__PTR(m_s_ON_NurbsCurve_ptr);
00067 Initialize();
00068 Create(dim,bIsRational,order,cv_count);
00069 }
00070
00071 ON_NurbsCurve::ON_NurbsCurve(const ON_BezierCurve& src)
00072 {
00073 ON__SET__THIS__PTR(m_s_ON_NurbsCurve_ptr);
00074 Initialize();
00075 ON_NurbsCurve::operator=(src);
00076 }
00077
00078 ON_NurbsCurve::~ON_NurbsCurve()
00079 {
00080 Destroy();
00081 }
00082
00083 unsigned int ON_NurbsCurve::SizeOf() const
00084 {
00085 unsigned int sz = ON_Curve::SizeOf();
00086 sz += (sizeof(*this) - sizeof(ON_Curve));
00087 sz += m_knot_capacity*sizeof(*m_knot);
00088 sz += m_cv_capacity*sizeof(*m_cv);
00089 return sz;
00090 }
00091
00092 ON__UINT32 ON_NurbsCurve::DataCRC(ON__UINT32 current_remainder) const
00093 {
00094 current_remainder = ON_CRC32(current_remainder,sizeof(m_dim),&m_dim);
00095 current_remainder = ON_CRC32(current_remainder,sizeof(m_is_rat),&m_is_rat);
00096 current_remainder = ON_CRC32(current_remainder,sizeof(m_order),&m_order);
00097 current_remainder = ON_CRC32(current_remainder,sizeof(m_cv_count),&m_cv_count);
00098 if ( m_cv_count > 0 && m_cv_stride > 0 && m_cv )
00099 {
00100 size_t sizeof_cv = CVSize()*sizeof(m_cv[0]);
00101 const double* cv = m_cv;
00102 int i;
00103 for ( i = 0; i < m_cv_count; i++ )
00104 {
00105 current_remainder = ON_CRC32(current_remainder,sizeof_cv,cv);
00106 cv += m_cv_stride;
00107 }
00108 }
00109 current_remainder = ON_CRC32(current_remainder,KnotCount()*sizeof(m_knot[0]),m_knot);
00110 return current_remainder;
00111 }
00112
00113 int ON_NurbsCurve::Dimension() const
00114 {
00115 return m_dim;
00116 }
00117
00118 bool ON_NurbsCurve::IsRational() const
00119 {
00120 return m_is_rat?true:false;
00121 }
00122
00123 int ON_NurbsCurve::CVSize() const
00124 {
00125 return (m_dim>0) ? (m_is_rat?(m_dim+1):m_dim) : 0;
00126 }
00127
00128 int ON_NurbsCurve::Order( void ) const
00129 {
00130 return m_order;
00131 }
00132
00133 int ON_NurbsCurve::CVCount( void ) const
00134 {
00135 return m_cv_count;
00136 }
00137
00138 int ON_NurbsCurve::KnotCount( void ) const
00139 {
00140 return ON_KnotCount( m_order, m_cv_count );
00141 }
00142
00143 double* ON_NurbsCurve::CV( int i ) const
00144 {
00145 return (m_cv) ? (m_cv + i*m_cv_stride) : NULL;
00146 }
00147
00148 ON::point_style ON_NurbsCurve::CVStyle() const
00149 {
00150 return m_is_rat ? ON::homogeneous_rational : ON::not_rational;
00151 }
00152
00153
00154 double ON_NurbsCurve::Weight( int i ) const
00155 {
00156 return (m_cv && m_is_rat) ? m_cv[i*m_cv_stride+m_dim] : 1.0;
00157 }
00158
00159
00160 double ON_NurbsCurve::Knot( int i ) const
00161 {
00162 return (m_knot) ? m_knot[i] : 0.0;
00163 }
00164
00165 int ON_NurbsCurve::KnotMultiplicity( int i ) const
00166 {
00167 return ON_KnotMultiplicity(m_order,m_cv_count,m_knot,i);
00168 }
00169
00170 const double* ON_NurbsCurve::Knot() const
00171 {
00172 return m_knot;
00173 }
00174
00175 double ON_NurbsCurve::SuperfluousKnot( int end ) const
00176 {
00177 return(m_knot) ? ON_SuperfluousKnot(m_order,m_cv_count,m_knot,end) : 0.0;
00178 }
00179
00180
00181 bool ON_NurbsCurve::MakePeriodicUniformKnotVector( double delta )
00182 {
00183 DestroyCurveTree();
00184 ReserveKnotCapacity( ON_KnotCount( m_order, m_cv_count ) );
00185 return ON_MakePeriodicUniformKnotVector( m_order, m_cv_count, m_knot, delta );
00186 }
00187
00188
00189 bool ON_NurbsCurve::MakeClampedUniformKnotVector( double delta )
00190 {
00191 DestroyCurveTree();
00192 ReserveKnotCapacity( ON_KnotCount( m_order, m_cv_count ) );
00193 return ON_MakeClampedUniformKnotVector( m_order, m_cv_count, m_knot, delta );
00194 }
00195
00196 bool ON_NurbsCurve::CreateClampedUniformNurbs(
00197 int dimension,
00198 int order,
00199 int point_count,
00200 const ON_3dPoint* point,
00201 double knot_delta
00202 )
00203 {
00204 bool rc = (dimension >= 1 && dimension<=3 && point!=NULL);
00205 if (rc)
00206 rc = Create( dimension, false, order, point_count );
00207 if ( rc )
00208 {
00209 int i;
00210 for (i = 0; i < point_count; i++)
00211 SetCV( i, ON::intrinsic_point_style, point[i] );
00212 }
00213 if ( rc )
00214 rc = MakeClampedUniformKnotVector( knot_delta );
00215 return rc;
00216 }
00217
00218 bool ON_NurbsCurve::CreatePeriodicUniformNurbs(
00219 int dimension,
00220 int order,
00221 int point_count,
00222 const ON_3dPoint* point,
00223 double knot_delta
00224 )
00225 {
00226 bool rc = (dimension >= 1 && dimension<=3 && point!=NULL);
00227 if (rc)
00228 rc = Create( dimension, false, order, point_count+(order-1) );
00229 if ( rc )
00230 {
00231 int i;
00232 for (i = 0; i < point_count; i++)
00233 SetCV( i, ON::intrinsic_point_style, point[i] );
00234 for (i = 0; i <= order-2; i++)
00235 SetCV( m_cv_count-m_order+1+i, ON::intrinsic_point_style, CV(i) );
00236 }
00237 if ( rc )
00238 rc = MakePeriodicUniformKnotVector( knot_delta );
00239 return rc;
00240 }
00241
00242 bool ON_NurbsCurve::Create(
00243 int dim,
00244 ON_BOOL32 is_rat,
00245 int order,
00246 int cv_count
00247 )
00248 {
00249 DestroyCurveTree();
00250 if ( dim < 1 )
00251 return false;
00252 if ( order < 2 )
00253 return false;
00254 if ( cv_count < order )
00255 return false;
00256 m_dim = dim;
00257 m_is_rat = (is_rat) ? true : false;
00258 m_order = order;
00259 m_cv_count = cv_count;
00260 m_cv_stride = (m_is_rat) ? m_dim+1 : m_dim;
00261 bool rc = ReserveKnotCapacity( KnotCount() );
00262 if ( !ReserveCVCapacity( CVCount()*m_cv_stride ) )
00263 rc = false;
00264 return rc;
00265 }
00266
00267 void ON_NurbsCurve::Destroy()
00268 {
00269 DestroyCurveTree();
00270 double* cv = ( m_cv && m_cv_capacity ) ? m_cv : NULL;
00271 double* knot = ( m_knot && m_knot_capacity ) ? m_knot : NULL;
00272 Initialize();
00273 if ( cv )
00274 onfree(cv);
00275 if ( knot )
00276 onfree(knot);
00277 }
00278
00279 void ON_NurbsCurve::EmergencyDestroy()
00280 {
00281 Initialize();
00282 }
00283
00284
00285 void ON_NurbsCurve::Initialize()
00286 {
00287 m_dim = 0;
00288 m_is_rat = 0;
00289 m_order = 0;
00290 m_cv_count = 0;
00291 m_knot_capacity = 0;
00292 m_knot = 0;
00293 m_cv_stride = 0;
00294 m_cv_capacity = 0;
00295 m_cv = 0;
00296 }
00297
00298 static void ON_NurbsCurveCopyHelper( const ON_NurbsCurve& src, ON_NurbsCurve& dest )
00299 {
00300 dest.DestroyCurveTree();
00301 dest.m_dim = src.m_dim;
00302 dest.m_is_rat = src.m_is_rat;
00303 dest.m_order = src.m_order;
00304 dest.m_cv_count = src.m_cv_count;
00305 dest.m_cv_stride = dest.m_is_rat ? dest.m_dim+1 : dest.m_dim;
00306 if ( src.m_knot )
00307 {
00308
00309 dest.ReserveKnotCapacity( dest.KnotCount() );
00310 memcpy( dest.m_knot, src.m_knot, dest.KnotCount()*sizeof(*dest.m_knot) );
00311 }
00312 if ( src.m_cv )
00313 {
00314
00315 dest.ReserveCVCapacity( dest.m_cv_stride*dest.m_cv_count );
00316 const int dst_cv_size = dest.CVSize()*sizeof(*dest.m_cv);
00317 const int src_stride = src.m_cv_stride;
00318 const int dst_stride = dest.m_cv_stride;
00319 const double *src_cv = src.CV(0);
00320 double *dst_cv = dest.m_cv;
00321 if ( src_stride == dst_stride )
00322 {
00323 memcpy( dst_cv, src_cv, dest.m_cv_count*dst_stride*sizeof(*dst_cv) );
00324 }
00325 else
00326 {
00327 int i;
00328 for ( i = 0; i < dest.m_cv_count; i++ )
00329 {
00330 memcpy( dst_cv, src_cv, dst_cv_size );
00331 dst_cv += dst_stride;
00332 src_cv += src_stride;
00333 }
00334 }
00335 }
00336 }
00337
00338 ON_NurbsCurve& ON_NurbsCurve::operator=( const ON_NurbsCurve& src )
00339 {
00340 if ( this != &src )
00341 {
00342 ON_Curve::operator=(src);
00343 ON_NurbsCurveCopyHelper(src,*this);
00344 }
00345 return *this;
00346 }
00347
00348
00349 ON_NurbsCurve& ON_NurbsCurve::operator=(const ON_BezierCurve& src)
00350 {
00351 int i;
00352 Create(src.m_dim,src.m_is_rat,src.m_order,src.m_order);
00353 const int sizeof_cv = src.CVSize()*sizeof(double);
00354 for ( i = 0; i < m_cv_count; i++ ) {
00355 memcpy( CV(i), src.CV(i), sizeof_cv );
00356 }
00357 for ( i = 0; i <= m_order-2; i++ )
00358 m_knot[i] = 0.0;
00359 const int knot_count = KnotCount();
00360 for ( i = m_order-1; i < knot_count; i++ )
00361 m_knot[i] = 1.0;
00362 return *this;
00363 }
00364
00365 void ON_NurbsCurve::Dump( ON_TextLog& dump ) const
00366 {
00367 dump.Print( "ON_NurbsCurve dim = %d is_rat = %d\n"
00368 " order = %d cv_count = %d\n",
00369 m_dim, m_is_rat, m_order, m_cv_count );
00370 dump.Print( "Knot Vector ( %d knots )\n", KnotCount() );
00371 dump.PrintKnotVector( m_order, m_cv_count, m_knot );
00372 dump.Print( "Control Points %d %s points\n"
00373 " index value\n",
00374 m_cv_count,
00375 (m_is_rat) ? "rational" : "non-rational" );
00376 if ( !m_cv ) {
00377 dump.Print(" NULL cv array\n");
00378 }
00379 else {
00380 dump.PrintPointList( m_dim, m_is_rat,
00381 m_cv_count, m_cv_stride,
00382 m_cv,
00383 " CV" );
00384 }
00385 }
00386
00387
00388 static bool ON_NurbsCurveIsNotValid()
00389 {
00390 return ON_IsNotValid();
00391 }
00392
00393 static bool ON_ControlPointsAreNotValid()
00394 {
00395 return ON_IsNotValid();
00396 }
00397
00398 static bool ON_ControlPointsAreValid( int cv_size, int cv_count, int cv_stride, const double* cv, ON_TextLog* text_log )
00399 {
00400 int i, j;
00401 if ( 0 == cv )
00402 {
00403 if ( text_log )
00404 {
00405 text_log->Print("cv pointer is null.\n");
00406 }
00407 return ON_ControlPointsAreNotValid();
00408 }
00409
00410 if ( cv_count < 2 )
00411 {
00412 if ( text_log )
00413 {
00414 text_log->Print("cv_count = %d (must be >= 2).\n",cv_count);
00415 }
00416 return ON_ControlPointsAreNotValid();
00417 }
00418
00419 if ( cv_size < 1 )
00420 {
00421 if ( text_log )
00422 {
00423 text_log->Print("cv_size = %d (must be >= 1).\n",cv_size);
00424 }
00425 return ON_ControlPointsAreNotValid();
00426 }
00427
00428 if ( cv_stride < cv_size )
00429 {
00430 if ( text_log )
00431 {
00432 text_log->Print("cv_stride = %d and cv_size = %d (cv_stride must be >= cv_size).\n",cv_stride,cv_size);
00433 }
00434 return ON_ControlPointsAreNotValid();
00435 }
00436
00437 for ( i = 0; i < cv_count; i++, cv += cv_stride )
00438 {
00439 for ( j = 0; j < cv_size; j++ )
00440 {
00441 if ( !ON_IsValid(cv[j]) )
00442 {
00443 if ( text_log )
00444 {
00445 text_log->Print("cv[%d*cv_stride + %d] = %g is not valid.\n",i,j,cv[j]);
00446 }
00447 return ON_ControlPointsAreNotValid();
00448 }
00449 }
00450 }
00451
00452 return true;
00453 }
00454
00455 ON_BOOL32 ON_NurbsCurve::IsValid( ON_TextLog* text_log ) const
00456 {
00457 if ( m_dim <= 0 )
00458 {
00459 if ( text_log )
00460 {
00461 text_log->Print("ON_NurbsCurve.m_dim = %d (should be > 0).\n",m_dim);
00462 }
00463 return ON_NurbsCurveIsNotValid();
00464 }
00465
00466 if (m_order < 2 )
00467 {
00468 if ( text_log )
00469 {
00470 text_log->Print("ON_NurbsCurve.m_order = %d (should be >= 2).\n",m_order);
00471 }
00472 return ON_NurbsCurveIsNotValid();
00473 }
00474
00475 if (m_cv_count < m_order )
00476 {
00477 if ( text_log )
00478 {
00479 text_log->Print("ON_NurbsCurve.m_cv_count = %d (should be >= m_order=%d).\n",m_cv_count,m_order);
00480 }
00481 return ON_NurbsCurveIsNotValid();
00482 }
00483
00484 if (m_cv_stride < CVSize() )
00485 {
00486 if ( text_log )
00487 {
00488 text_log->Print("ON_NurbsCurve.m_cv_stride = %d (should be >= %d).\n",m_cv_stride,CVSize());
00489 }
00490 }
00491
00492 if (m_cv == NULL)
00493 {
00494 if ( text_log )
00495 {
00496 text_log->Print("ON_NurbsCurve.m_cv is NULL.\n");
00497 }
00498 return ON_NurbsCurveIsNotValid();
00499 }
00500
00501 if (m_knot == NULL)
00502 {
00503 if ( text_log )
00504 {
00505 text_log->Print("ON_NurbsCurve.m_knot is NULL.\n");
00506 }
00507 return ON_NurbsCurveIsNotValid();
00508 }
00509
00510 if ( !ON_IsValidKnotVector( m_order, m_cv_count, m_knot, text_log ) )
00511 {
00512 if ( text_log )
00513 {
00514 text_log->Print("ON_NurbsCurve.m_knot[] is not a valid knot vector.\n");
00515 }
00516 return ON_NurbsCurveIsNotValid();
00517 }
00518
00519 if ( !ON_ControlPointsAreValid(CVSize(),m_cv_count,m_cv_stride,m_cv,text_log) )
00520 {
00521 if ( text_log )
00522 {
00523 text_log->Print("ON_NurbsCurve.m_cv[] is not valid.\n");
00524 }
00525 return ON_NurbsCurveIsNotValid();
00526 }
00527
00528 if ( m_is_rat )
00529 {
00530
00531
00532 double sign = 0.0;
00533 const double* w = &m_cv[m_dim];
00534 int zcount = 0;
00535 int i;
00536 for ( i = 0; i < m_cv_count; i++, w += m_cv_stride )
00537 {
00538 if ( *w == 0.0 )
00539 zcount++;
00540 else
00541 zcount = 0;
00542
00543 if ( zcount >= m_order )
00544 {
00545 if ( text_log )
00546 {
00547 text_log->Print("ON_NurbsCurve.m_cv has zero weights for CV[%d],...,CV[%d].\n",i-m_order+1,i);
00548 }
00549 return ON_NurbsCurveIsNotValid();
00550 }
00551
00552 if ( m_knot[i] == m_knot[i+m_order-2] )
00553 {
00554 if ( *w == 0.0 )
00555 {
00556 if ( text_log )
00557 {
00558 text_log->Print("ON_NurbsCurve.m_cv has zero weights for CV[%d].\n",i);
00559 }
00560 return ON_NurbsCurveIsNotValid();
00561 }
00562
00563 if (sign == 0.0)
00564 {
00565 sign = (*w > 0.0) ? 1.0 : -1.0;
00566 }
00567 else if ( *w * sign <= 0.0 )
00568 {
00569 if ( text_log )
00570 {
00571 text_log->Print("ON_NurbsCurve.m_cv has a zero denominator in the parameter interval [%g,%g].\n",
00572 m_knot[i-1],m_knot[i]);
00573 }
00574 return ON_NurbsCurveIsNotValid();
00575 }
00576 }
00577 }
00578
00579 if ( m_dim <= 3 && 2 == m_order && 2 == m_cv_count )
00580 {
00581
00582
00583
00584
00585
00586 ON_3dPoint P0 = PointAtStart();
00587 ON_3dPoint P1 = PointAtEnd();
00588 if ( P0 == P1 )
00589 {
00590 if ( text_log )
00591 {
00592 text_log->Print("ON_NurbsCurve is a line with no length.\n");
00593 }
00594 return ON_NurbsCurveIsNotValid();
00595 }
00596 }
00597 }
00598
00599 return true;
00600 }
00601
00602 ON_BOOL32 ON_NurbsCurve::GetBBox(
00603 double* boxmin,
00604 double* boxmax,
00605 ON_BOOL32 bGrowBox
00606 ) const
00607 {
00608 return ON_GetPointListBoundingBox(
00609 m_dim, m_is_rat, m_cv_count,
00610 m_cv_stride, m_cv,
00611 boxmin, boxmax, bGrowBox?true:false
00612 );
00613 }
00614
00615 ON_BOOL32 ON_NurbsCurve::Transform( const ON_Xform& xform )
00616 {
00617 TransformUserData(xform);
00618 DestroyCurveTree();
00619 if ( 0 == m_is_rat )
00620 {
00621 if ( xform.m_xform[3][0] != 0.0 || xform.m_xform[3][1] != 0.0 || xform.m_xform[3][2] != 0.0 )
00622 {
00623 MakeRational();
00624 }
00625 }
00626 return ON_TransformPointList( m_dim, m_is_rat, m_cv_count, m_cv_stride, m_cv, xform );
00627 }
00628
00629 bool ON_NurbsCurve::IsDeformable() const
00630 {
00631 return true;
00632 }
00633
00634 bool ON_NurbsCurve::MakeDeformable()
00635 {
00636 return true;
00637 }
00638
00639 bool ON_PolylineCurve::IsDeformable() const
00640 {
00641 return true;
00642 }
00643
00644 bool ON_PolylineCurve::MakeDeformable()
00645 {
00646 return true;
00647 }
00648
00649
00650 ON_BOOL32 ON_NurbsCurve::Write(
00651 ON_BinaryArchive& file
00652 ) const
00653 {
00654
00655 ON_BOOL32 rc = file.Write3dmChunkVersion(1,0);
00656 if (rc)
00657 {
00658 if (rc) rc = file.WriteInt( m_dim );
00659 if (rc) rc = file.WriteInt( m_is_rat );
00660 if (rc) rc = file.WriteInt( m_order );
00661 if (rc) rc = file.WriteInt( m_cv_count );
00662 if (rc) rc = file.WriteInt( 0 );
00663 if (rc) rc = file.WriteInt( 0 );
00664
00665
00666 if (rc)
00667 {
00668 ON_BoundingBox bbox;
00669 rc = file.WriteBoundingBox(bbox);
00670 }
00671
00672
00673 int count = (0 != m_knot && m_cv_count >= m_order && m_order >= 2)
00674 ? KnotCount()
00675 : 0;
00676 if (rc) rc = file.WriteInt(count);
00677 if (rc) rc = file.WriteDouble( count, m_knot );
00678
00679
00680 const int cv_size = CVSize();
00681 count = ( m_cv && cv_size > 0 && m_cv_count > 0 && m_cv_stride >= cv_size )
00682 ? m_cv_count
00683 : 0;
00684 if (rc) rc = file.WriteInt(count);
00685 if (rc && count > 0 )
00686 {
00687 int i;
00688 for ( i = 0; i < m_cv_count && rc; i++ )
00689 {
00690 rc = file.WriteDouble( cv_size, CV(i) );
00691 }
00692 }
00693
00694 }
00695 return rc;
00696 }
00697
00698 ON_BOOL32 ON_NurbsCurve::Read(
00699 ON_BinaryArchive& file
00700 )
00701 {
00702
00703 Destroy();
00704 int major_version = 0;
00705 int minor_version = 0;
00706 ON_BOOL32 rc = file.Read3dmChunkVersion(&major_version,&minor_version);
00707 if (rc && major_version==1)
00708 {
00709
00710 int dim = 0, is_rat = 0, order = 0, cv_count = 0;
00711 int reserved1 = 0, reserved2 = 0;
00712 if (rc) rc = file.ReadInt( &dim );
00713 if (rc) rc = file.ReadInt( &is_rat );
00714 if (rc) rc = file.ReadInt( &order );
00715 if ( order < 0 )
00716 rc = false;
00717 if (rc) rc = file.ReadInt( &cv_count );
00718 if ( cv_count < order )
00719 rc = false;
00720 if (rc) rc = file.ReadInt( &reserved1 );
00721 if (rc) rc = file.ReadInt( &reserved2 );
00722
00723
00724 if (rc) {
00725
00726 ON_BoundingBox bbox;
00727 rc = file.ReadBoundingBox( bbox );
00728 }
00729
00730 if ( !Create( dim, is_rat, order, cv_count ) )
00731 rc = false;
00732
00733
00734 int count = 0;
00735 if (rc) rc = file.ReadInt(&count);
00736 if ( count < 0 )
00737 rc = false;
00738 else if ( 0 != count && count != ON_KnotCount(order,cv_count) )
00739 rc = false;
00740 if (rc ) rc = ReserveKnotCapacity(count);
00741 if (rc) rc = file.ReadDouble( count, m_knot );
00742
00743
00744 count = 0;
00745 if (rc) rc = file.ReadInt(&count);
00746 const int cv_size = CVSize();
00747 if (rc) rc = ReserveCVCapacity( count*cv_size );
00748 if (count > 0 && cv_size > 0 && rc )
00749 {
00750 int i;
00751 for ( i = 0; i < m_cv_count && rc; i++ )
00752 {
00753 rc = file.ReadDouble( cv_size, CV(i) );
00754 }
00755 }
00756 }
00757 if ( !rc )
00758 Destroy();
00759 return rc;
00760 }
00761
00762 ON_Interval ON_NurbsCurve::Domain() const
00763 {
00764 ON_Interval d;
00765 if ( !ON_GetKnotVectorDomain( m_order, m_cv_count, m_knot, &d.m_t[0], &d.m_t[1] ) )
00766 d.Destroy();
00767 return d;
00768 }
00769
00770 ON_BOOL32 ON_NurbsCurve::SetDomain( double t0, double t1 )
00771 {
00772 ON_BOOL32 rc = false;
00773 if ( m_order >= 2 && m_cv_count >= m_order && m_knot && t0 < t1 ) {
00774
00775 const double k0 = m_knot[m_order-2];
00776 const double k1 = m_knot[m_cv_count-1];
00777 if ( k0 == t0 && k1 == t1 )
00778 rc = true;
00779 else if ( k0 < k1 )
00780 {
00781 DestroyCurveTree();
00782 const double d = (t1-t0)/(k1-k0);
00783 const double km = 0.5*(k0+k1);
00784 const int knot_count = KnotCount();
00785 int i;
00786 for ( i = 0; i < knot_count; i++ )
00787 {
00788 if ( m_knot[i] <= km ) {
00789 m_knot[i] = (m_knot[i] - k0)*d + t0;
00790 }
00791 else {
00792 m_knot[i] = (m_knot[i] - k1)*d + t1;
00793 }
00794 }
00795 rc = true;
00796 }
00797 }
00798 return rc;
00799 }
00800
00801 ON_BOOL32 ON_NurbsCurve::ChangeClosedCurveSeam( double t )
00802 {
00803 ON_BOOL32 rc = IsClosed();
00804 if ( rc )
00805 {
00806
00807 const ON_Interval old_dom = Domain();
00808 double k = t;
00809 double s = old_dom.NormalizedParameterAt(t);
00810 if ( s < 0.0 || s > 1.0 )
00811 {
00812 s = fmod( s, 1.0 );
00813 if ( s < 0.0 )
00814 s += 1.0;
00815 k = old_dom.ParameterAt(s);
00816 }
00817 s = old_dom.NormalizedParameterAt( k);
00818 if ( old_dom.Includes(k,true) )
00819 {
00820 ON_NurbsCurve left, right;
00821
00822
00823 {
00824 ON_Curve* pleft = &left;
00825 ON_Curve* pright = &right;
00826 rc = Split( k, pleft, pright );
00827 if ( rc )
00828 {
00829
00830
00831 right.Append(left);
00832 *this = right;
00833 }
00834 }
00835 }
00836 else
00837 {
00838
00839 rc = true;
00840 }
00841 if (rc)
00842 SetDomain( t, t+old_dom.Length() );
00843 }
00844 return rc;
00845 }
00846
00847
00848 int ON_NurbsCurve::SpanCount() const
00849 {
00850
00851 return ON_KnotVectorSpanCount( m_order, m_cv_count, m_knot );
00852 }
00853
00854 ON_BOOL32 ON_NurbsCurve::GetSpanVector(
00855 double* s
00856 ) const
00857 {
00858 return ON_GetKnotVectorSpanVector( m_order, m_cv_count, m_knot, s );
00859 }
00860
00861 int ON_NurbsCurve::Degree() const
00862 {
00863 return m_order >= 2 ? m_order-1 : 0;
00864 }
00865
00866
00867
00868
00869 ON_BOOL32
00870 ON_NurbsCurve::IsLinear(
00871 double tolerance
00872 ) const
00873 {
00874
00875
00876
00877
00878 if ( !IsClamped() )
00879 return false;
00880
00881
00882
00883
00884 ON_Line L;
00885 ON_3dPoint P, Q;
00886 ON_3dVector V0, V1, D;
00887 double t0, t, d, s;
00888 int i;
00889
00890
00891 if ( !GetCV(0,L.from) )
00892 return false;
00893 if ( !GetCV(m_cv_count-1,L.to) )
00894 return false;
00895
00896
00897
00898 D.x = L.to.x - L.from.x; D.y = L.to.y - L.from.y; D.z = L.to.z - L.from.z;
00899 t = D.x*D.x + D.y*D.y + D.z*D.z;
00900 if ( !ON_IsValid(t) || !(t > 0.0) )
00901 return false;
00902
00903 if ( 2 == m_cv_count )
00904 return true;
00905
00906 t0 = 0.0;
00907 bool bDefaultTolerance = false;
00908 if ( !(tolerance > 0.0) )
00909 {
00910 bDefaultTolerance = true;
00911 tolerance = ON_ZERO_TOLERANCE;
00912 }
00913 const double tol2 = tolerance*tolerance;
00914 t = 1.0/t;
00915 D.x *= t; D.y *= t; D.z *= t;
00916
00917 for ( i = 1; i < m_cv_count-1; i++ )
00918 {
00919
00920
00921 GetCV(i,P);
00922
00923
00924 V0.x = P.x - L.from.x; V0.y = P.y - L.from.y; V0.z = P.z - L.from.z;
00925 V1.x = P.x - L.to.x; V1.y = P.y - L.to.y; V1.z = P.z - L.to.z;
00926 if ( V0.x*V0.x + V0.y*V0.y + V0.z*V0.z <= V1.x*V1.x + V1.y*V1.y + V1.z*V1.z )
00927 {
00928
00929 t = V0.x*D.x + V0.y*D.y + V0.z*D.z;
00930 if ( t < -0.01 )
00931 return false;
00932 }
00933 else
00934 {
00935
00936 t = 1.0 + V1.x*D.x + V1.y*D.y + V1.z*D.z;
00937 if ( t > 1.01 )
00938 return false;
00939 }
00940
00941
00942 s = 1.0-t;
00943 Q.x = s*L.from.x + t*L.to.x; Q.y = s*L.from.y + t*L.to.y; Q.z = s*L.from.z + t*L.to.z;
00944
00945 if ( bDefaultTolerance )
00946 {
00947 if ( !ON_PointsAreCoincident(3,0,&P.x,&Q.x) )
00948 return false;
00949 }
00950 else
00951 {
00952
00953 s = P.x-Q.x;
00954 d = tol2 - s*s;
00955 if ( d < 0.0 )
00956 return false;
00957 s = P.y-Q.y;
00958 d -= s*s;
00959 if ( d < 0.0 )
00960 return false;
00961 s = P.z-Q.z;
00962 d -= s*s;
00963 if ( d < 0.0 )
00964 return false;
00965 }
00966
00967 if ( t > t0 && t0 < 1.0 )
00968 {
00969 t0 = (t < 1.0) ? t : 1.0;
00970 }
00971
00972 if ( !(t >= t0 && t <= 1.0) )
00973 {
00974
00975
00976
00977
00978
00979
00980
00981
00982 P = L.PointAt(t0);
00983 d = Q.DistanceTo(P);
00984 if ( !(d <= tolerance) )
00985 return false;
00986 }
00987 }
00988
00989 return true;
00990 }
00991
00992 int ON_NurbsCurve::IsPolyline(
00993 ON_SimpleArray<ON_3dPoint>* pline_points,
00994 ON_SimpleArray<double>* pline_t
00995 ) const
00996 {
00997 int i;
00998 int rc = 0;
00999 if ( pline_points )
01000 pline_points->SetCount(0);
01001 if ( pline_t )
01002 pline_t->SetCount(0);
01003 if ( IsValid() )
01004 {
01005 if ( 2 == m_order )
01006 {
01007 rc = m_cv_count;
01008 if ( pline_points )
01009 {
01010 pline_points->Reserve(m_cv_count);
01011 for ( i = 0; i < m_cv_count; i++ )
01012 {
01013 GetCV(i,pline_points->AppendNew());
01014 }
01015 }
01016 if ( pline_t )
01017 {
01018 pline_t->Reserve(m_cv_count);
01019 for ( i = 0; i < m_cv_count; i++ )
01020 pline_t->Append(m_knot[i]);
01021 }
01022 }
01023 else if ( m_order > 2 && m_dim >= 2 && m_dim <= 3 )
01024 {
01025
01026
01027
01028 const double *k = m_knot;
01029 double t;
01030 int i, j, span_count = m_cv_count-m_order+1;
01031 ON_Line line;
01032 ON_3dPoint P, Q;
01033 GetCV(0,line.to);
01034 for ( i = 0; i < span_count; i++, k++ )
01035 {
01036 if ( k[m_order-2] < k[m_order-1] )
01037 {
01038 if ( k[0] != k[m_order-2] )
01039 {
01040
01041 return 0;
01042 }
01043 if ( k[m_order-1] != k[2*m_order-3] )
01044 {
01045
01046 return 0;
01047 }
01048
01049
01050
01051 line.from = line.to;
01052 GetCV(i+m_order-1,line.to);
01053 for ( j = 1; j < m_order-1; j++ )
01054 {
01055 GetCV(i+j,P);
01056 t = 0.0;
01057 if ( !line.ClosestPointTo(P,&t) )
01058 return 0;
01059 if ( fabs( t*(m_order-1) - j ) > 0.01 )
01060 {
01061
01062
01063
01064 return 0;
01065 }
01066 Q = line.PointAt(t);
01067
01068
01069 if ( fabs(P.x - Q.x) > (fabs(P.x) + fabs(Q.x))*0.00001 + ON_ZERO_TOLERANCE )
01070 return 0;
01071 if ( fabs(P.y - Q.y) > (fabs(P.y) + fabs(Q.y))*0.00001 + ON_ZERO_TOLERANCE )
01072 return 0;
01073 if ( fabs(P.z - Q.z) > (fabs(P.z) + fabs(Q.z))*0.00001 + ON_ZERO_TOLERANCE )
01074 return 0;
01075 }
01076 rc++;
01077 }
01078 }
01079
01080 if (rc > 0 )
01081 {
01082 rc++;
01083
01084 if ( 0 != pline_points || 0 != pline_t )
01085 {
01086 GetCV(0,P);
01087 if ( 0 != pline_points )
01088 {
01089 pline_points->Reserve(rc);
01090 GetCV(0,pline_points->AppendNew());
01091 }
01092 if ( 0 != pline_t )
01093 {
01094 pline_t->Reserve(rc);
01095 pline_t->Append( m_knot[m_order-2] );
01096 }
01097
01098 const double *k = m_knot;
01099 for ( i = 0; i < span_count; i++, k++ )
01100 {
01101 if ( k[m_order-2] < k[m_order-1] )
01102 {
01103
01104
01105 if ( 0 != pline_points )
01106 GetCV(i+m_order-1,pline_points->AppendNew());
01107 if ( 0 != pline_t )
01108 pline_t->Append(k[m_order-1]);
01109 }
01110 }
01111 }
01112 }
01113 }
01114
01115 if( IsClosed() && rc >= 4 && 0 != pline_points )
01116 {
01117
01118
01119 *pline_points->Last() = *pline_points->First();
01120 }
01121
01122 }
01123 return rc;
01124 }
01125
01126
01127
01128 ON_BOOL32
01129 ON_NurbsCurve::IsArc(
01130 const ON_Plane* plane,
01131 ON_Arc* arc,
01132 double tolerance
01133 ) const
01134 {
01135
01136
01137
01138
01139
01140
01141
01142
01143 const bool bLooseTest = (tolerance > ON_ZERO_TOLERANCE);
01144 const int knotcount = KnotCount();
01145 const int degree = m_order-1;
01146 if ( (2 == m_dim || 3 == m_dim)
01147 && m_cv_count >= m_order
01148 && degree >= 2
01149 && 0 != m_knot
01150 && 0 != m_cv
01151 && (bLooseTest || 0 != m_is_rat)
01152 )
01153 {
01154 if ( bLooseTest || 0 == (knotcount % degree) )
01155 {
01156
01157 if ( !bLooseTest )
01158 {
01159 for ( int i = 0; i < m_cv_count; i += degree )
01160 {
01161 if ( m_knot[i] != m_knot[i+degree-1] )
01162 return false;
01163 }
01164 }
01165
01166
01167
01168
01169
01170
01171 if ( IsLinear(tolerance) )
01172 return false;
01173
01174 if ( ON_Curve::IsArc( plane, arc, tolerance ) )
01175 return true;
01176 }
01177 }
01178
01179 return false;
01180 }
01181
01182 ON_BOOL32
01183 ON_NurbsCurve::IsPlanar(
01184 ON_Plane* plane,
01185
01186 double tolerance
01187 ) const
01188 {
01189 if ( m_dim == 2 )
01190 {
01191 return ON_Curve::IsPlanar(plane,tolerance);
01192 }
01193
01194 ON_BOOL32 rc = false;
01195 ON_3dPoint P;
01196 ON_3dVector X;
01197 EvTangent( Domain()[0], P, X );
01198 if ( IsLinear(tolerance) )
01199 {
01200 if ( plane )
01201 {
01202 ON_Line line( P, PointAtEnd() );
01203 if ( !line.InPlane( *plane, tolerance) )
01204 line.InPlane( *plane, 0.0 );
01205 }
01206 rc = true;
01207 }
01208 else if ( m_cv_count >= 3 )
01209 {
01210
01211
01212 ON_Plane test_plane;
01213 ON_3dPoint A, B, Q, R;
01214 Q = P;
01215 R = P;
01216 double d, maxd = 0.0;
01217 int i, j, k;
01218 k = m_cv_count/64;
01219 if ( k < 1 )
01220 k = 1;
01221 for ( i = 1; i < m_cv_count; i += k )
01222 {
01223 GetCV(i,A);
01224 for ( j = i+k; j < m_cv_count; j += k )
01225 {
01226 GetCV(j,B);
01227 d = ON_CrossProduct( A-P, B-P ).Length();
01228 if ( d > maxd )
01229 {
01230 maxd = d;
01231 Q = A;
01232 R = B;
01233 }
01234 }
01235 }
01236 if ( test_plane.CreateFromPoints(P,Q,R) )
01237 {
01238 ON_2dVector v( X*test_plane.xaxis, X*test_plane.yaxis );
01239 if ( v.Unitize() )
01240 {
01241
01242
01243 if ( fabs(v.y) <= ON_SQRT_EPSILON )
01244 {
01245 v.x = (v.x >= 0.0) ? 1.0 : -1.0;
01246 v.y = 0.0;
01247 }
01248 else if ( fabs(v.x) <= ON_SQRT_EPSILON )
01249 {
01250 v.y = (v.y >= 0.0) ? 1.0 : -1.0;
01251 v.x = 0.0;
01252 }
01253 X = test_plane.xaxis;
01254 ON_3dVector Y = test_plane.yaxis;
01255 test_plane.xaxis = v.x*X + v.y*Y;
01256 test_plane.yaxis = v.x*Y - v.y*X;
01257 }
01258 rc = IsInPlane( test_plane, tolerance );
01259 if ( rc && plane )
01260 *plane = test_plane;
01261 }
01262 }
01263 return rc;
01264 }
01265
01266 ON_BOOL32
01267 ON_NurbsCurve::IsInPlane(
01268 const ON_Plane& plane,
01269 double tolerance
01270 ) const
01271 {
01272 ON_BOOL32 rc = IsValid();
01273 ON_3dPoint P;
01274 int i;
01275 for ( i = 0; rc && i < m_cv_count; i++ )
01276 {
01277 GetCV(i,P);
01278 if ( fabs( plane.DistanceTo(P)) > tolerance)
01279 rc = false;
01280 }
01281 return rc;
01282 }
01283
01284 ON_BOOL32
01285 ON_NurbsCurve::GetParameterTolerance(
01286 double t,
01287 double* tminus,
01288 double* tplus
01289 ) const
01290 {
01291 ON_BOOL32 rc = false;
01292 ON_Interval d = Domain();
01293 if ( d.IsIncreasing() ) {
01294 const double* knot = Knot();
01295 const int order = Order();
01296 const int cv_count = CVCount();
01297 if ( t < knot[order-1] )
01298 d.m_t[1] = knot[order-1];
01299 else if ( t > knot[cv_count-2] )
01300 d.m_t[0] = knot[cv_count-2];
01301 rc = ON_GetParameterTolerance( d.m_t[0], d.m_t[1], t, tminus, tplus );
01302 }
01303 return rc;
01304 }
01305
01306 ON_BOOL32
01307 ON_NurbsCurve::Evaluate(
01308 double t,
01309 int der_count,
01310 int v_stride,
01311 double* v,
01312 int side,
01313
01314
01315
01316 int* hint
01317
01318 ) const
01319 {
01320 ON_BOOL32 rc = false;
01321
01322 if( m_order<2)
01323 return false;
01324
01325 int span_index = ON_NurbsSpanIndex(m_order,m_cv_count,m_knot,t,side,(hint)?*hint:0);
01326
01327 if ( -2 == side || 2 == side )
01328 {
01329
01330
01331
01332
01333
01334 double a = t;
01335 if ( ON_TuneupEvaluationParameter( side, m_knot[span_index+m_order-2], m_knot[span_index+m_order-1], &a) )
01336 {
01337
01338 t = a;
01339 span_index = ON_NurbsSpanIndex(m_order,m_cv_count,m_knot,t,side,span_index);
01340 }
01341 }
01342
01343 rc = ON_EvaluateNurbsSpan(
01344 m_dim, m_is_rat, m_order,
01345 m_knot + span_index,
01346 m_cv_stride, m_cv + (m_cv_stride*span_index),
01347 der_count,
01348 t,
01349 v_stride, v
01350 );
01351 if ( hint )
01352 *hint = span_index;
01353 return rc;
01354 }
01355
01356
01357 ON_BOOL32
01358 ON_NurbsCurve::IsClosed() const
01359 {
01360 ON_BOOL32 bIsClosed = false;
01361 if ( m_dim > 0 && m_cv_count >= 4 )
01362 {
01363 if ( IsPeriodic() ) {
01364 bIsClosed = true;
01365 }
01366 else {
01367 bIsClosed = ON_Curve::IsClosed();
01368 }
01369 }
01370 return bIsClosed;
01371 }
01372
01373 ON_BOOL32
01374 ON_NurbsCurve::IsPeriodic() const
01375 {
01376 ON_BOOL32 bIsPeriodic = ON_IsKnotVectorPeriodic( m_order, m_cv_count, m_knot );
01377 if ( bIsPeriodic ) {
01378 int i0 = m_order-2;
01379 int i1 = m_cv_count-1;
01380 const double* cv0 = m_cv + i0*m_cv_stride;
01381 const double* cv1 = m_cv + i1*m_cv_stride;
01382 for ( ; i0 >= 0; i0--, i1-- ) {
01383 if ( false == ON_PointsAreCoincident( m_dim, m_is_rat, cv0, cv1 ) )
01384 return false;
01385 cv0 -= m_cv_stride;
01386 cv1 -= m_cv_stride;
01387 }
01388 }
01389 return bIsPeriodic;
01390 }
01391
01392
01393 bool ON_IsCurvatureDiscontinuity(
01394 const ON_3dVector Km,
01395 const ON_3dVector Kp,
01396 double cos_angle_tolerance,
01397 double curvature_tolerance,
01398 double zero_curvature,
01399 double radius_tolerance
01400 )
01401 {
01402
01403
01404 return ON_IsCurvatureDiscontinuity( Km, Kp,
01405 cos_angle_tolerance,
01406 curvature_tolerance,
01407 zero_curvature,
01408 radius_tolerance,
01409 0.001
01410 );
01411 }
01412
01413 bool ON_IsG2CurvatureContinuous(
01414 const ON_3dVector Km,
01415 const ON_3dVector Kp,
01416 double cos_angle_tolerance,
01417 double curvature_tolerance
01418 )
01419 {
01420
01421
01422
01423
01424 double rel_tol = 0.05;
01425
01426 double cos_Kangle_tolerance = cos_angle_tolerance;
01427 if ( cos_Kangle_tolerance > ON_DEFAULT_ANGLE_TOLERANCE_COSINE )
01428 cos_Kangle_tolerance = ON_DEFAULT_ANGLE_TOLERANCE_COSINE;
01429 if ( cos_Kangle_tolerance > 0.95 )
01430 {
01431
01432 if ( cos_angle_tolerance < 0.0 )
01433 {
01434 cos_Kangle_tolerance = -1.0;
01435 }
01436 else
01437 {
01438 cos_Kangle_tolerance = 2.0*cos_Kangle_tolerance*cos_Kangle_tolerance - 1.0;
01439 if ( cos_angle_tolerance >= 0.0 && cos_Kangle_tolerance < 0.0 )
01440 cos_Kangle_tolerance = 0.0;
01441 }
01442 }
01443
01444 return !ON_IsCurvatureDiscontinuity(Km,Kp,
01445 cos_Kangle_tolerance,
01446 curvature_tolerance,
01447 ON_ZERO_CURVATURE_TOLERANCE,
01448 ON_UNSET_VALUE,
01449 rel_tol
01450 );
01451 }
01452
01453 bool ON_IsGsmoothCurvatureContinuous(
01454 const ON_3dVector Km,
01455 const ON_3dVector Kp,
01456 double cos_angle_tolerance,
01457 double curvature_tolerance
01458 )
01459 {
01460 double rel_tol = 1.0;
01461
01462
01463 double cos_Kangle_tolerance = 0.0;
01464
01465
01466
01467 return !ON_IsCurvatureDiscontinuity(Km,Kp,
01468 cos_Kangle_tolerance,
01469 curvature_tolerance,
01470 ON_ZERO_CURVATURE_TOLERANCE,
01471 ON_UNSET_VALUE,
01472 rel_tol
01473 );
01474 }
01475
01476 bool ON_IsCurvatureDiscontinuity(
01477 const ON_3dVector Km,
01478 const ON_3dVector Kp,
01479 double cos_angle_tolerance,
01480 double curvature_tolerance,
01481 double zero_curvature,
01482 double radius_tolerance,
01483 double relative_tolerance
01484 )
01485 {
01486 const double d = (Km-Kp).Length();
01487 if ( !ON_IsValid(d) )
01488 {
01489
01490
01491
01492 return true;
01493 }
01494
01495
01496
01497 if ( d <= 0.0 || d <= curvature_tolerance )
01498 return false;
01499
01500
01501
01502
01503
01504
01505 if ( !(zero_curvature > 7.7037197787136e-34) )
01506 zero_curvature = 7.7037197787136e-34;
01507 double km = Km.Length();
01508 double kp = Kp.Length();
01509
01510
01511
01512 if ( !(km > zero_curvature) )
01513 km = 0.0;
01514 if ( !(kp > zero_curvature) )
01515 {
01516 kp = 0.0;
01517 if ( 0.0 == km )
01518 {
01519
01520 return false;
01521 }
01522 }
01523
01524 if ( !(km > 0.0 && kp > 0.0) )
01525 {
01526
01527 return true;
01528 }
01529
01530 if ( 0.0 == curvature_tolerance )
01531 {
01532
01533 return true;
01534 }
01535
01536
01537
01538
01539 bool bPointOfInflection = (curvature_tolerance > 0.0);
01540 bool bDifferentScalars = bPointOfInflection;
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554 if ( cos_angle_tolerance >= -1.0 && cos_angle_tolerance <= 1.0 )
01555 {
01556 const double KmoKp = Kp*Km;
01557 if ( KmoKp < km*kp*cos_angle_tolerance )
01558 return true;
01559 bPointOfInflection = false;
01560 }
01561
01562
01563
01564 if ( radius_tolerance >= 0.0 )
01565 {
01566
01567
01568
01569 if ( fabs(km-kp) > kp*km*radius_tolerance )
01570
01571 return true;
01572 bDifferentScalars = false;
01573 }
01574
01575 if ( relative_tolerance > 0.0 )
01576 {
01577 if ( fabs(km-kp) > ((km>kp)?km:kp)*relative_tolerance )
01578 {
01579 return true;
01580 }
01581 bDifferentScalars = false;
01582 }
01583
01584 if ( bPointOfInflection || bDifferentScalars )
01585 {
01586
01587
01588 return true;
01589 }
01590
01591 return false;
01592 }
01593
01594
01595 bool ON_NurbsCurve::GetNextDiscontinuity(
01596 ON::continuity c,
01597 double t0,
01598 double t1,
01599 double* t,
01600 int* hint,
01601 int* dtype,
01602 double cos_angle_tolerance,
01603 double curvature_tolerance
01604 ) const
01605 {
01606 const double is_linear_tolerance = 1.0e-8;
01607 const double is_linear_min_length = 1.0e-8;
01608 int tmp_hint = 0, tmp_dtype=0;
01609 double d, tmp_t;
01610 ON_3dPoint Pm, Pp;
01611 ON_3dVector D1m, D1p, D2m, D2p, Tm, Tp, Km, Kp;
01612 int ki;
01613 if ( !hint )
01614 hint = &tmp_hint;
01615 if ( !dtype )
01616 dtype = &tmp_dtype;
01617 if ( !t )
01618 t = &tmp_t;
01619
01620 if ( c == ON::C0_continuous )
01621 return false;
01622 if ( c == ON::C0_locus_continuous )
01623 {
01624 return ON_Curve::GetNextDiscontinuity( c, t0, t1, t, hint, dtype,
01625 cos_angle_tolerance, curvature_tolerance );
01626 }
01627 if ( t0 == t1 )
01628 return false;
01629
01630
01631
01632 if ( m_order <= 2 )
01633 c = ON::PolylineContinuity(c);
01634 const ON::continuity input_c = c;
01635 c = ON::ParametricContinuity(c);
01636 bool bEv2ndDer = (c == ON::C2_continuous || c == ON::G2_continuous || c == ON::Gsmooth_continuous) && (m_order>2);
01637 bool bTestKappa = ( bEv2ndDer && c != ON::C2_continuous );
01638 bool bTestTangent = ( bTestKappa || c == ON::G1_continuous );
01639
01640 int delta_ki = 1;
01641 int delta = ((bEv2ndDer) ? 3 : 2) - m_order;
01642 if ( ON::Cinfinity_continuous == c )
01643 delta = 0;
01644
01645 ki = ON_NurbsSpanIndex(m_order,m_cv_count,m_knot,t0,(t0>t1)?-1:1,*hint);
01646 double segtol = (fabs(m_knot[ki]) + fabs(m_knot[ki+1]) + fabs(m_knot[ki+1]-m_knot[ki]))*ON_SQRT_EPSILON;
01647
01648 const bool bLineWiggleTest = (c == ON::Gsmooth_continuous && m_order >= 4);
01649 bool bSpanIsLinear = false;
01650
01651 if ( t0 < t1 )
01652 {
01653 int ii = ki+m_order-2;
01654 if ( t0 < m_knot[ii+1] && t1 > m_knot[ii+1] && (m_knot[ii+1]-t0) <= segtol && ii+2 < m_cv_count )
01655 {
01656 t0 = m_knot[ii+1];
01657 ki = ON_NurbsSpanIndex(m_order,m_cv_count,m_knot,t0,1,*hint);
01658 }
01659 if ( bLineWiggleTest )
01660 bSpanIsLinear = SpanIsLinear(ki,is_linear_min_length,is_linear_tolerance);
01661 *hint = ki;
01662 ki += m_order-2;
01663 while (ki < m_cv_count-1 && m_knot[ki] <= t0)
01664 ki++;
01665 if (ki >= m_cv_count-1)
01666 {
01667 if ( input_c != c && t0 < m_knot[m_cv_count-1] && t1 >= m_knot[m_cv_count-1] )
01668 {
01669
01670 return ON_Curve::GetNextDiscontinuity( input_c, t0, t1, t, hint, dtype,
01671 cos_angle_tolerance, curvature_tolerance );
01672 }
01673 return false;
01674 }
01675 }
01676 else
01677 {
01678
01679 int ii = ki+m_order-2;
01680 if ( t0 > m_knot[ii] && t1 < m_knot[ii] && (t0-m_knot[ii]) <= segtol && ii > m_order-2 )
01681 {
01682 t0 = m_knot[ii];
01683 ki = ON_NurbsSpanIndex(m_order,m_cv_count,m_knot,t0,-1,*hint);
01684 }
01685 if ( bLineWiggleTest )
01686 bSpanIsLinear = SpanIsLinear(ki,is_linear_min_length,is_linear_tolerance);
01687 *hint = ki;
01688 ki += m_order-2;
01689 while (ki > m_order-2 && m_knot[ki] >= t0)
01690 ki--;
01691 if (ki <= m_order-2)
01692 {
01693 if ( input_c != c && t0 > m_knot[m_order-2] && t1 < m_knot[m_order-2] )
01694 {
01695
01696 return ON_Curve::GetNextDiscontinuity( input_c, t0, t1, t, hint, dtype,
01697 cos_angle_tolerance, curvature_tolerance );
01698 }
01699 return false;
01700 }
01701 delta_ki = -1;
01702 delta = -delta;
01703 }
01704
01705 double search_domain[2];
01706 if ( t0 <= t1 )
01707 {
01708 search_domain[0] = t0;
01709 search_domain[1] = t1;
01710 }
01711 else
01712 {
01713 search_domain[0] = t1;
01714 search_domain[1] = t0;
01715 }
01716
01717 while ( search_domain[0] < m_knot[ki] && m_knot[ki] < search_domain[1] )
01718 {
01719 if ( delta_ki > 0 )
01720 {
01721
01722 while (ki < m_cv_count-1 && m_knot[ki] == m_knot[ki+1])
01723 ki++;
01724 if (ki >= m_cv_count-1)
01725 break;
01726 }
01727 else
01728 {
01729
01730
01731
01732 while (ki > m_order-2 && m_knot[ki] == m_knot[ki-1])
01733 ki--;
01734 if (ki <= m_order-2)
01735 break;
01736 }
01737
01738 if (m_knot[ki] == m_knot[ki+delta])
01739 {
01740 if ( ON::Cinfinity_continuous == c )
01741 {
01742
01743 *dtype = 3;
01744 *t = m_knot[ki];
01745 return true;
01746 }
01747
01748 if ( bEv2ndDer ) {
01749 Ev2Der( m_knot[ki], Pm, D1m, D2m, -1, hint );
01750 Ev2Der( m_knot[ki], Pp, D1p, D2p, 1, hint );
01751 }
01752 else {
01753 Ev1Der( m_knot[ki], Pm, D1m, -1, hint );
01754 Ev1Der( m_knot[ki], Pp, D1p, 1, hint );
01755 }
01756
01757 if ( bTestTangent )
01758 {
01759 if ( bTestKappa )
01760 {
01761 ON_EvCurvature( D1m, D2m, Tm, Km );
01762 ON_EvCurvature( D1p, D2p, Tp, Kp );
01763 }
01764 else
01765 {
01766 Tm = D1m;
01767 Tp = D1p;
01768 Tm.Unitize();
01769 Tp.Unitize();
01770 }
01771 d = Tm*Tp;
01772 if ( d < cos_angle_tolerance )
01773 {
01774 *dtype = 1;
01775 *t = m_knot[ki];
01776 return true;
01777 }
01778 else if ( bTestKappa )
01779 {
01780 bool bIsCurvatureContinuous = ( ON::Gsmooth_continuous == c )
01781 ? ON_IsGsmoothCurvatureContinuous( Km, Kp, cos_angle_tolerance, curvature_tolerance )
01782 : ON_IsG2CurvatureContinuous( Km, Kp, cos_angle_tolerance, curvature_tolerance );
01783 if ( !bIsCurvatureContinuous )
01784 {
01785
01786
01787
01788
01789 *dtype = 2;
01790 *t = m_knot[ki];
01791 return true;
01792 }
01793 if ( bLineWiggleTest )
01794 {
01795 if ( bSpanIsLinear != (( delta_ki < 0 )
01796 ? SpanIsLinear(ki - m_order + 1,is_linear_min_length,is_linear_tolerance)
01797 : SpanIsLinear(ki - m_order + 2,is_linear_min_length,is_linear_tolerance))
01798 )
01799 {
01800
01801 *dtype = 3;
01802 *t = m_knot[ki];
01803 return true;
01804 }
01805 }
01806 }
01807 }
01808 else
01809 {
01810 if ( !(D1m-D1p).IsTiny(D1m.MaximumCoordinate()*ON_SQRT_EPSILON) )
01811 {
01812 *dtype = 1;
01813 *t = m_knot[ki];
01814 return true;
01815 }
01816 else if ( bEv2ndDer )
01817 {
01818 if ( !(D2m-D2p).IsTiny(D2m.MaximumCoordinate()*ON_SQRT_EPSILON) )
01819 {
01820 *dtype = 2;
01821 *t = m_knot[ki];
01822 return true;
01823 }
01824 }
01825 }
01826 }
01827 ki += delta_ki;
01828 }
01829
01830
01831
01832
01833 bool rc = false;
01834
01835 if ( input_c != c )
01836 {
01837
01838 rc = ON_Curve::GetNextDiscontinuity( input_c, t0, t1, t, hint, dtype,
01839 cos_angle_tolerance, curvature_tolerance );
01840 }
01841
01842 return rc;
01843 }
01844
01845 bool ON_NurbsCurve::IsContinuous(
01846 ON::continuity desired_continuity,
01847 double t,
01848 int* hint,
01849 double point_tolerance,
01850 double d1_tolerance,
01851 double d2_tolerance,
01852 double cos_angle_tolerance,
01853 double curvature_tolerance
01854 ) const
01855 {
01856 bool rc = true;
01857
01858 if ( m_order <= 2 )
01859 desired_continuity = ON::PolylineContinuity(desired_continuity);
01860
01861 if ( t <= m_knot[m_order-2] || t >= m_knot[m_cv_count-1] )
01862 {
01863
01864
01865 rc = ON_Curve::IsContinuous(
01866 desired_continuity, t, hint,
01867 point_tolerance,
01868 d1_tolerance, d2_tolerance,
01869 cos_angle_tolerance,
01870 curvature_tolerance );
01871 return rc;
01872 }
01873
01874
01875 desired_continuity = ON::ParametricContinuity(desired_continuity);
01876
01877 if ( m_order < m_cv_count && desired_continuity != ON::C0_continuous )
01878 {
01879 int tmp_hint;
01880 if ( !hint )
01881 {
01882 tmp_hint = 0;
01883 hint = &tmp_hint;
01884 }
01885 int ki = ON_NurbsSpanIndex(m_order,m_cv_count,m_knot,t,1,*hint);
01886
01887 {
01888
01889
01890
01891
01892
01893
01894 int ii = ki+m_order-2;
01895 double segtol = (fabs(m_knot[ii]) + fabs(m_knot[ii+1]) + fabs(m_knot[ii+1]-m_knot[ii]))*ON_SQRT_EPSILON;
01896 if ( m_knot[ii]+segtol < m_knot[ii+1]-segtol )
01897 {
01898 if ( fabs(t-m_knot[ii]) <= segtol && ii > m_order-2 )
01899 {
01900 t = m_knot[ii];
01901 }
01902 else if ( fabs(t-m_knot[ii+1]) <= segtol && ii+2 < m_cv_count )
01903 {
01904 t = m_knot[ii+1];
01905 ki = ON_NurbsSpanIndex(m_order,m_cv_count,m_knot,t,1,*hint);
01906 }
01907 }
01908 }
01909
01910 if ( ki < 0 )
01911 ki = 0;
01912 *hint = ki;
01913 ki += m_order-2;
01914 if ( ki > m_order-2 && ki < m_cv_count-1 && m_knot[ki] == t )
01915 {
01916 if ( ON::Cinfinity_continuous == desired_continuity )
01917 {
01918
01919 return false;
01920 }
01921
01922
01923 int knot_mult = ON_KnotMultiplicity( m_order, m_cv_count, m_knot, ki );
01924
01925 switch(desired_continuity)
01926 {
01927 case ON::C2_continuous:
01928 if ( m_order - knot_mult >= 3 )
01929 return true;
01930 break;
01931 case ON::C1_continuous:
01932 if ( m_order - knot_mult >= 2 )
01933 return true;
01934 break;
01935 case ON::G2_continuous:
01936 case ON::Gsmooth_continuous:
01937 if ( m_order - knot_mult >= 3 )
01938 return true;
01939 break;
01940 case ON::G1_continuous:
01941 if ( m_order - knot_mult >= 2 )
01942 return true;
01943 break;
01944 default:
01945
01946 break;
01947 }
01948
01949
01950 rc = ON_Curve::IsContinuous( desired_continuity, t, hint,
01951 point_tolerance, d1_tolerance, d2_tolerance,
01952 cos_angle_tolerance, curvature_tolerance );
01953
01954 if ( rc
01955 && ON::Gsmooth_continuous == desired_continuity
01956 && knot_mult == m_order-1
01957 && ki > m_order-2
01958 && ki < m_cv_count-1
01959 )
01960 {
01961
01962 const double is_linear_tolerance = 1.0e-8;
01963 const double is_linear_min_length = 1.0e-8;
01964 if ( SpanIsLinear(ki - m_order + 2,is_linear_min_length,is_linear_tolerance) != SpanIsLinear(ki - 2*m_order + 3,is_linear_min_length,is_linear_tolerance) )
01965 rc = false;
01966
01967 }
01968 }
01969 }
01970 return rc;
01971 }
01972
01973
01974 ON_BOOL32
01975 ON_NurbsCurve::SetWeight( int i, double w )
01976 {
01977 ON_BOOL32 rc = false;
01978 if ( m_is_rat ) {
01979 double* cv = CV(i);
01980 if (cv) {
01981 cv[m_dim] = w;
01982 rc = true;
01983 }
01984 }
01985 else if ( w == 1.0 ) {
01986 rc = true;
01987 }
01988 DestroyCurveTree();
01989 return rc;
01990 }
01991
01992 ON_BOOL32
01993 ON_NurbsCurve::SetCV( int i, ON::point_style style, const double* Point )
01994 {
01995 ON_BOOL32 rc = true;
01996 int k;
01997 double w;
01998
01999
02000 if ( !m_cv || i < 0 || i >= m_cv_count )
02001 return false;
02002
02003 double* cv = m_cv + i*m_cv_stride;
02004
02005 switch ( style ) {
02006
02007 case ON::not_rational:
02008 memcpy( cv, Point, m_dim*sizeof(*cv) );
02009 if ( IsRational() ) {
02010
02011 cv[m_dim] = 1.0;
02012 }
02013 break;
02014
02015 case ON::homogeneous_rational:
02016 if ( IsRational() ) {
02017
02018 memcpy( cv, Point, (m_dim+1)*sizeof(*cv) );
02019 }
02020 else {
02021
02022 w = (Point[m_dim] != 0.0) ? 1.0/Point[m_dim] : 1.0;
02023 for ( k = 0; k < m_dim; k++ ) {
02024 cv[k] = w*Point[k];
02025 }
02026 }
02027 break;
02028
02029 case ON::euclidean_rational:
02030 if ( IsRational() ) {
02031
02032 w = Point[m_dim];
02033 for ( k = 0; k < m_dim; k++ )
02034 cv[k] = w*Point[k];
02035 cv[m_dim] = w;
02036 }
02037 else {
02038
02039 memcpy( cv, Point, m_dim*sizeof(*cv) );
02040 }
02041 break;
02042
02043 case ON::intrinsic_point_style:
02044 memcpy( cv, Point, CVSize()*sizeof(*cv) );
02045 break;
02046
02047 default:
02048 rc = false;
02049 break;
02050 }
02051 DestroyCurveTree();
02052 return rc;
02053 }
02054
02055 ON_BOOL32
02056 ON_NurbsCurve::SetCV( int i, const ON_3dPoint& point )
02057 {
02058 ON_BOOL32 rc = false;
02059 double* cv = CV(i);
02060 if ( cv ) {
02061 cv[0] = point.x;
02062 if ( m_dim > 1 ) {
02063 cv[1] = point.y;
02064 if ( m_dim > 2 )
02065 cv[2] = point.z;
02066 if ( m_dim > 3 ) {
02067 memset( &cv[3], 0, (m_dim-3)*sizeof(*cv) );
02068 }
02069 }
02070 if ( m_is_rat ) {
02071 cv[m_dim] = 1.0;
02072 }
02073 rc = true;
02074 }
02075 DestroyCurveTree();
02076 return rc;
02077 }
02078
02079 ON_BOOL32
02080 ON_NurbsCurve::SetCV( int i, const ON_4dPoint& point )
02081 {
02082 ON_BOOL32 rc = false;
02083 double* cv = CV(i);
02084 if ( cv ) {
02085 if ( m_is_rat ) {
02086 cv[0] = point.x;
02087 if ( m_dim > 1 ) {
02088 cv[1] = point.y;
02089 if ( m_dim > 2 )
02090 cv[2] = point.z;
02091 if ( m_dim > 3 ) {
02092 memset( &cv[3], 0, (m_dim-3)*sizeof(*cv) );
02093 }
02094 }
02095 cv[m_dim] = point.w;
02096 rc = true;
02097 }
02098 else {
02099 double w;
02100 if ( point.w != 0.0 ) {
02101 w = 1.0/point.w;
02102 rc = true;
02103 }
02104 else {
02105 w = 1.0;
02106 }
02107 cv[0] = w*point.x;
02108 if ( m_dim > 1 ) {
02109 cv[1] = w*point.y;
02110 if ( m_dim > 2 ) {
02111 cv[2] = w*point.z;
02112 }
02113 if ( m_dim > 3 ) {
02114 memset( &cv[3], 0, (m_dim-3)*sizeof(*cv) );
02115 }
02116 }
02117 }
02118 }
02119 DestroyCurveTree();
02120 return rc;
02121 }
02122
02123 ON_BOOL32
02124 ON_NurbsCurve::GetCV( int i, ON::point_style style, double* Point ) const
02125 {
02126 const double* cv = CV(i);
02127 if ( !cv )
02128 return false;
02129 int dim = Dimension();
02130 double w = ( IsRational() ) ? cv[dim] : 1.0;
02131 switch(style) {
02132 case ON::euclidean_rational:
02133 Point[dim] = w;
02134
02135 case ON::not_rational:
02136 if ( w == 0.0 )
02137 return false;
02138 w = 1.0/w;
02139 while(dim--) *Point++ = *cv++ * w;
02140 break;
02141 case ON::homogeneous_rational:
02142 Point[dim] = w;
02143 memcpy( Point, cv, dim*sizeof(*Point) );
02144 break;
02145 case ON::intrinsic_point_style:
02146 memcpy( Point, cv, CVSize()*sizeof(*Point) );
02147 break;
02148 default:
02149 return false;
02150 }
02151 return true;
02152 }
02153
02154 ON_BOOL32
02155 ON_NurbsCurve::GetCV( int i, ON_3dPoint& point ) const
02156 {
02157 ON_BOOL32 rc = false;
02158 const double* cv = CV(i);
02159 if ( cv ) {
02160 if ( m_is_rat ) {
02161 if (cv[m_dim] != 0.0) {
02162 const double w = 1.0/cv[m_dim];
02163 point.x = cv[0]*w;
02164 point.y = (m_dim>1)? cv[1]*w : 0.0;
02165 point.z = (m_dim>2)? cv[2]*w : 0.0;
02166 rc = true;
02167 }
02168 }
02169 else {
02170 point.x = cv[0];
02171 point.y = (m_dim>1)? cv[1] : 0.0;
02172 point.z = (m_dim>2)? cv[2] : 0.0;
02173 rc = true;
02174 }
02175 }
02176 return rc;
02177 }
02178
02179 ON_BOOL32
02180 ON_NurbsCurve::GetCV( int i, ON_4dPoint& point ) const
02181 {
02182 ON_BOOL32 rc = false;
02183 const double* cv = CV(i);
02184 if ( cv ) {
02185 point.x = cv[0];
02186 point.y = (m_dim>1)? cv[1] : 0.0;
02187 point.z = (m_dim>2)? cv[2] : 0.0;
02188 point.w = (m_is_rat) ? cv[m_dim] : 1.0;
02189 rc = true;
02190 }
02191 return rc;
02192 }
02193
02194 bool ON_NurbsCurve::SetKnot( int knot_index, double k )
02195 {
02196 if ( knot_index < 0 || knot_index >= KnotCount() )
02197 return false;
02198 m_knot[knot_index] = k;
02199 DestroyCurveTree();
02200 return true;
02201 }
02202
02203 ON_BOOL32 ON_NurbsCurve::SetStartPoint(
02204 ON_3dPoint start_point
02205 )
02206 {
02207 ON_BOOL32 rc = false;
02208 if ( IsValid() )
02209 {
02210 if ( PointAtStart() == start_point )
02211 {
02212 rc = true;
02213 }
02214 else
02215 {
02216 ClampEnd(2);
02217
02218 double w = 1.0;
02219 if (IsRational()) {
02220 w = Weight(0);
02221 start_point *= w;
02222 }
02223 SetCV(0,start_point);
02224 if (IsRational())
02225 SetWeight(0, w);
02226
02227 DestroyCurveTree();
02228 rc = true;
02229 }
02230 }
02231 return rc;
02232 }
02233
02234 ON_BOOL32 ON_NurbsCurve::SetEndPoint(
02235 ON_3dPoint end_point
02236 )
02237 {
02238 bool rc = false;
02239 if ( IsValid() )
02240 {
02241 if ( PointAtEnd() == end_point )
02242 {
02243 rc = true;
02244 }
02245 else
02246 {
02247 ClampEnd(2);
02248
02249 double w = 1.0;
02250 if (IsRational()) {
02251 w = Weight(m_cv_count-1);
02252 end_point *= w;
02253 }
02254 SetCV(m_cv_count-1,end_point);
02255 if (IsRational())
02256 SetWeight(m_cv_count-1, w);
02257
02258 DestroyCurveTree();
02259 rc = true;
02260 }
02261 }
02262 return rc;
02263 }
02264
02265
02266 ON_BOOL32
02267 ON_NurbsCurve::Reverse()
02268 {
02269 ON_BOOL32 rc0 = ON_ReverseKnotVector( m_order, m_cv_count, m_knot );
02270 ON_BOOL32 rc1 = ON_ReversePointList( m_dim, m_is_rat, m_cv_count, m_cv_stride, m_cv );
02271 DestroyCurveTree();
02272 return rc0 && rc1;
02273 }
02274
02275 ON_BOOL32
02276 ON_NurbsCurve::SwapCoordinates( int i, int j )
02277 {
02278 DestroyCurveTree();
02279 return ON_SwapPointListCoordinates( m_cv_count, m_cv_stride, m_cv, i, j );
02280 }
02281
02282 double ON_NurbsCurve::GrevilleAbcissa(
02283 int gindex
02284 ) const
02285 {
02286 return ON_GrevilleAbcissa( m_order, m_knot+gindex );
02287 }
02288
02289 bool ON_NurbsCurve::GetGrevilleAbcissae(
02290 double* g
02291 ) const
02292 {
02293 return ON_GetGrevilleAbcissae( m_order, m_cv_count, m_knot, false, g );
02294 }
02295
02296
02297 bool ON_NurbsCurve::ZeroCVs()
02298 {
02299 bool rc = false;
02300 int i;
02301 if ( m_cv ) {
02302 if ( m_cv_capacity > 0 ) {
02303 memset( m_cv, 0, m_cv_capacity*sizeof(*m_cv) );
02304 if ( m_is_rat ) {
02305 for ( i = 0; i < m_cv_count; i++ ) {
02306 SetWeight( i, 1.0 );
02307 }
02308 }
02309 rc = true;
02310 }
02311 else {
02312 double* cv;
02313 int s = CVSize()*sizeof(*cv);
02314 for ( i = 0; i < m_cv_count; i++ ) {
02315 cv = CV(i);
02316 memset(cv,0,s);
02317 if ( m_is_rat )
02318 cv[m_dim] = 1.0;
02319 }
02320 rc = (i>0) ? true : false;
02321 }
02322 }
02323 DestroyCurveTree();
02324 return rc;
02325 }
02326
02327 bool ON_NurbsCurve::IsClamped(
02328 int end
02329 ) const
02330 {
02331 return ON_IsKnotVectorClamped( m_order, m_cv_count, m_knot, end );
02332 }
02333
02334
02335 bool ON_NurbsCurve::ReserveCVCapacity(int desired_capacity)
02336 {
02337
02338
02339
02340 bool rc = true;
02341 if ( desired_capacity > m_cv_capacity ) {
02342 if ( !m_cv ) {
02343
02344 m_cv = (double*)onmalloc(desired_capacity*sizeof(*m_cv));
02345 if ( !m_cv ) {
02346 rc = false;
02347 }
02348 else {
02349 m_cv_capacity = desired_capacity;
02350 }
02351 }
02352 else if ( m_cv_capacity > 0 ) {
02353
02354
02355
02356
02357 m_cv = (double*)onrealloc(m_cv,desired_capacity*sizeof(*m_cv));
02358 if ( !m_cv ) {
02359 rc = false;
02360 m_cv_capacity = 0;
02361 }
02362 else {
02363 m_cv_capacity = desired_capacity;
02364 }
02365 }
02366 }
02367 return rc;
02368 }
02369
02370 bool ON_NurbsCurve::ReserveKnotCapacity(int desired_capacity)
02371 {
02372
02373
02374
02375 bool rc = true;
02376 if ( desired_capacity > m_knot_capacity ) {
02377 if ( !m_knot ) {
02378
02379 m_knot = (double*)onmalloc(desired_capacity*sizeof(*m_knot));
02380 if ( !m_knot ) {
02381 m_knot_capacity = 0;
02382 rc = false;
02383 }
02384 else {
02385 m_knot_capacity = desired_capacity;
02386 }
02387 }
02388 else if ( m_knot_capacity > 0 ) {
02389
02390
02391
02392
02393 m_knot = (double*)onrealloc(m_knot,desired_capacity*sizeof(*m_knot));
02394 if ( !m_knot ) {
02395 rc = false;
02396 m_knot_capacity = 0;
02397 }
02398 else {
02399 m_knot_capacity = desired_capacity;
02400 }
02401 }
02402 }
02403 return rc;
02404 }
02405
02406 bool ON_NurbsCurve::ConvertSpanToBezier( int span_index, ON_BezierCurve& bez ) const
02407 {
02408 bool rc = false;
02409 if ( span_index >= 0 && span_index <= m_cv_count-m_order && m_knot && m_cv )
02410 {
02411 const int cvdim = CVSize();
02412 const int sizeof_cv = cvdim*sizeof(*bez.m_cv);
02413 int i;
02414 rc = bez.ReserveCVCapacity( cvdim*m_order );
02415 if ( rc ) {
02416 bez.m_dim = m_dim;
02417 bez.m_is_rat = m_is_rat;
02418 bez.m_order = m_order;
02419 bez.m_cv_stride = cvdim;
02420 if ( bez.m_cv_stride == m_cv_stride )
02421 {
02422 memcpy( bez.m_cv, CV(span_index), bez.m_order*sizeof_cv );
02423 }
02424 else
02425 {
02426 for ( i = 0; i < m_order; i++ ) {
02427 memcpy( bez.CV(i), CV(span_index+i), sizeof_cv );
02428 }
02429 }
02430 const double* knot = m_knot + span_index;
02431 if( knot[m_order-2] < knot[m_order-1] )
02432 ON_ConvertNurbSpanToBezier( cvdim, bez.m_order, bez.m_cv_stride, bez.m_cv,
02433 knot, knot[m_order-2], knot[m_order-1] );
02434 else
02435 rc = false;
02436 }
02437 }
02438 return rc;
02439 }
02440
02441
02442 bool ON_NurbsCurve::HasBezierSpans() const
02443 {
02444 return ON_KnotVectorHasBezierSpans( m_order, m_cv_count, m_knot );
02445 }
02446
02447 bool ON_NurbsCurve::MakePiecewiseBezier( bool bSetEndWeightsToOne )
02448 {
02449 bool rc = HasBezierSpans();
02450 if ( !rc && IsValid() )
02451 {
02452 ON_Workspace ws;
02453 DestroyRuntimeCache();
02454 if ( !ClampEnd(2) )
02455 return false;
02456 int span_count = SpanCount();
02457
02458 ReserveKnotCapacity( (span_count + 1)*(m_order-1) );
02459 ReserveCVCapacity( m_cv_stride*(span_count*(m_order-1) + 1) );
02460 double* t = ws.GetDoubleMemory( span_count+1);
02461 GetSpanVector( t );
02462 int cvdim = CVSize();
02463 ON_BezierCurve* bez = new ON_BezierCurve[span_count];
02464 int ki, spani, i;
02465 for ( ki = m_order-2, spani = 0; ki < m_cv_count-1 && spani < span_count; ki++ ) {
02466 if ( m_knot[ki] < m_knot[ki+1] ) {
02467 bez[spani].Create(m_dim,m_is_rat,m_order);
02468 for ( i = 0; i < m_order; i++ )
02469 bez[spani].SetCV( i, ON::intrinsic_point_style, CV( i + ki - m_order + 2 ) );
02470 ON_ConvertNurbSpanToBezier( cvdim, bez[spani].m_order, bez[spani].m_cv_stride, bez[spani].m_cv,
02471 m_knot+ki-m_order+2, m_knot[ki], m_knot[ki+1] );
02472 spani++;
02473 }
02474 }
02475 m_cv_count = span_count*(m_order-1) + 1;
02476 for ( spani = 0; spani < span_count; spani++ ) {
02477 for ( i = 0; i < m_order; i++ ) {
02478 SetCV( spani*(m_order-1) + i, ON::intrinsic_point_style, bez[spani].CV( i ) );
02479 }
02480 for ( ki = 0; ki < m_order-1; ki++ )
02481 m_knot[ki+spani*(m_order-1)] = t[spani];
02482 }
02483 for ( ki = 0; ki < m_order-1; ki++ )
02484 m_knot[ki+span_count*(m_order-1)] = t[spani];
02485 delete[] bez;
02486 rc = true;
02487 }
02488 if ( rc && bSetEndWeightsToOne && m_is_rat )
02489 {
02490
02491 double w0, w1;
02492 ON_BezierCurve bez;
02493 bez.m_dim = m_dim;
02494 bez.m_is_rat = m_is_rat;
02495 bez.m_order = m_order;
02496 bez.m_cv_stride = m_cv_stride;
02497
02498 bez.m_cv = CV(0);
02499 if ( bez.Weight(0) != 1.0 )
02500 {
02501 DestroyRuntimeCache();
02502 w0 = 1.0;
02503 w1 = (m_order == m_cv_count) ? 1.0 : bez.Weight(m_order-1);
02504 bez.ChangeWeights(0,w0,m_order-1,w1);
02505 }
02506
02507 bez.m_cv = CV(m_cv_count-m_order);
02508 if ( bez.Weight(m_order-1) != 1.0 )
02509 {
02510 DestroyRuntimeCache();
02511 w0 = bez.Weight(0);
02512 w1 = 1.0;
02513 bez.ChangeWeights(0,w0,m_order-1,w1);
02514 }
02515
02516 bez.m_cv = 0;
02517 }
02518 return rc;
02519 }
02520
02521
02522 double ON_NurbsCurve::ControlPolygonLength() const
02523 {
02524 double length = 0.0;
02525 ON_GetPolylineLength( m_dim, m_is_rat, m_cv_count, m_cv_stride, m_cv, &length );
02526 return length;
02527 }
02528
02529
02530 bool ON_NurbsCurve::InsertKnot( double knot_value, int knot_multiplicity )
02531 {
02532 bool rc = false;
02533
02534 const int degree = Degree();
02535
02536 double t0, t1;
02537 {
02538 ON_Interval d = Domain();
02539 if ( !d.IsIncreasing() )
02540 return false;
02541 t0 = d[0];
02542 t1 = d[1];
02543 }
02544
02545 if ( knot_multiplicity < 1 || knot_multiplicity > degree )
02546 {
02547 ON_ERROR("ON_NurbsCurve::ON_InsertKnot(): knot_multiplicity < 1 or knot_multiplicity > degree.");
02548 return false;
02549 }
02550
02551 if( knot_value < t0 || knot_value > t1 )
02552 {
02553 ON_ERROR("ON_InsertKnot(): knot_value not in NURBS curve domain.");
02554 return false;
02555 }
02556
02557 if ( knot_value == t0 )
02558 {
02559 if ( knot_multiplicity == degree )
02560 {
02561 rc = ClampEnd(0);
02562 }
02563 else if ( knot_multiplicity == 1 )
02564 {
02565 rc = true;
02566 }
02567 else
02568 {
02569 ON_ERROR("ON_InsertKnot(): knot_value = t0 and 1 < knot_multiplicity < degree.");
02570 rc = false;
02571 }
02572 return rc;
02573 }
02574
02575 if ( knot_value == t1 )
02576 {
02577 if ( knot_multiplicity == degree )
02578 {
02579 rc = ClampEnd(1);
02580 }
02581 else if ( knot_multiplicity == 1 )
02582 {
02583 rc = true;
02584 }
02585 else
02586 {
02587 ON_ERROR("ON_InsertKnot(): knot_value = t1 and 1 < knot_multiplicity < degree.");
02588 rc = false;
02589 }
02590 return rc;
02591 }
02592
02593 DestroyCurveTree();
02594
02595 ON_BOOL32 bIsPeriodic = (degree>1) ? IsPeriodic() : false;
02596 int span_index = ON_NurbsSpanIndex( m_order, m_cv_count, m_knot, knot_value, 0, 0 );
02597
02598
02599 if ( !ReserveCVCapacity( m_cv_stride*(m_cv_count+knot_multiplicity) ) )
02600 return false;
02601 if ( !ReserveKnotCapacity( KnotCount()+knot_multiplicity ) )
02602 return false;
02603 if ( bIsPeriodic ) {
02604 }
02605
02606 rc = true;
02607 int span_hint = span_index;
02608 int new_knot_count = ON_InsertKnot( knot_value, knot_multiplicity,
02609 CVSize(), m_order, m_cv_count,
02610 m_cv_stride, m_cv, m_knot, &span_hint );
02611 if ( new_knot_count > 0 )
02612 {
02613 m_cv_count += new_knot_count;
02614 }
02615
02616 if ( bIsPeriodic && rc && !IsPeriodic() ) {
02617
02618 if ( ON_MakeKnotVectorPeriodic( m_order, m_cv_count, m_knot ) ) {
02619 int i0, i1;
02620 for ( i0 = 0, i1 = m_cv_count-degree; i0 < degree; i0++, i1++ ) {
02621 if ( span_index < degree-1 )
02622 SetCV( i1, ON::intrinsic_point_style, CV(i0) );
02623 else
02624 SetCV( i0, ON::intrinsic_point_style, CV(i1) );
02625 }
02626 }
02627 else {
02628 ClampEnd(2);
02629 }
02630 }
02631
02632 return rc;
02633 }
02634
02635 bool ON_NurbsCurve::MakeRational()
02636 {
02637 if ( !IsRational() ) {
02638 const int dim = Dimension();
02639 const int cv_count = CVCount();
02640 if ( cv_count > 0 && m_cv_stride >= dim && dim > 0 ) {
02641 const int new_stride = (m_cv_stride == dim) ? dim+1 : m_cv_stride;
02642 ReserveCVCapacity( cv_count*new_stride );
02643 const double* old_cv;
02644 double* new_cv;
02645 int cvi, j;
02646 for ( cvi = cv_count-1; cvi>=0; cvi-- ) {
02647 old_cv = CV(cvi);
02648 new_cv = m_cv+(cvi*new_stride);
02649 for ( j = dim-1; j >= 0; j-- ) {
02650 new_cv[j] = old_cv[j];
02651 }
02652 new_cv[dim] = 1.0;
02653 }
02654 m_cv_stride = new_stride;
02655 m_is_rat = 1;
02656 }
02657 }
02658 return IsRational();
02659 }
02660
02661 bool ON_NurbsCurve::MakeNonRational()
02662 {
02663 if ( IsRational() ) {
02664 const int dim = Dimension();
02665 const int cv_count = CVCount();
02666 if ( cv_count > 0 && m_cv_stride >= dim+1 && dim > 0 ) {
02667 double w;
02668 const double* old_cv;
02669 double* new_cv = m_cv;
02670 int cvi, j;
02671 for ( cvi = 0; cvi < cv_count; cvi++ ) {
02672 old_cv = CV(cvi);
02673 w = old_cv[dim];
02674 w = ( w != 0.0 ) ? 1.0/w : 1.0;
02675 for ( j = 0; j < dim; j++ ) {
02676 *new_cv++ = w*(*old_cv++);
02677 }
02678 }
02679 m_is_rat = 0;
02680 m_cv_stride = dim;
02681 }
02682 }
02683 DestroyCurveTree();
02684 return ( !IsRational() ) ? true : false;
02685 }
02686
02687 static ON_BOOL32 GetRaisedDegreeCV(int old_order,
02688 int cvdim,
02689 int old_cvstride,
02690 const double* oldCV,
02691 const double* oldkn,
02692 const double* newkn,
02693 int cv_id,
02694 double* newCV
02695 )
02696
02697 {
02698 int i,j,k;
02699
02700 if (!oldCV || !oldkn || !newkn || !newCV || cv_id < 0 || cv_id > old_order)
02701 return false;
02702
02703 int old_degree = old_order-1;
02704 int new_degree = old_degree+1;
02705
02706 double* t = (double*)onmalloc(old_degree*sizeof(double));
02707 if (!t) return false;
02708 double* P = (double*)onmalloc(cvdim*sizeof(double));
02709 if (!P) {
02710 onfree((void*)t);
02711 return false;
02712 }
02713
02714 memset(newCV, 0, cvdim*sizeof(double));
02715
02716 const double* kn = newkn + cv_id;
02717
02718 for (i=0; i<new_degree; i++){
02719 k=0;
02720 for (j=0; j<new_degree; j++){
02721 if (j != i) {
02722 t[k] = kn[j];
02723 k++;
02724 }
02725 }
02726 if (!ON_EvaluateNurbsBlossom(cvdim, old_order,
02727 old_cvstride, oldCV, oldkn, t, P)){
02728 onfree((void*)t);
02729 onfree((void*)P);
02730 return false;
02731 }
02732 for (k=0; k<cvdim; k++) newCV[k] += P[k];
02733 }
02734
02735 double denom = (double)new_degree;
02736 for (i=0; i<cvdim; i++)
02737 newCV[i] /= denom;
02738
02739 onfree((void*)t);
02740 onfree((void*)P);
02741
02742 return true;
02743 }
02744
02745
02746 static ON_BOOL32 IncrementNurbDegree(ON_NurbsCurve& N)
02747
02748
02749
02750 {
02751 ON_NurbsCurve M = N;
02752 int span_count = M.SpanCount();
02753 int new_kcount = M.KnotCount() + span_count + 1;
02754 N.m_order = M.Order()+1;
02755 N.m_cv_count = new_kcount - N.Order() + 2;
02756
02757
02758 int i=0;
02759 int k=0;
02760 int j;
02761 while (i<M.CVCount()){
02762 double kn = M.Knot(i);
02763 int mult = M.KnotMultiplicity(i);
02764 for (j=0; j<=mult; j++) {
02765 N.SetKnot(k, kn);
02766 k++;
02767 }
02768 i+=mult;
02769 }
02770
02771 memset(N.m_cv, 0, N.m_cv_capacity*sizeof(double));
02772 int cvdim = N.CVSize();
02773 const double* cvM;
02774 double* cvN;
02775 const double* knotN;
02776 const double* knotM;
02777 int siN = 0;
02778 int siM = 0;
02779
02780 for (i=0; i<span_count; i++){
02781 knotN = &N.m_knot[siN];
02782 knotM = &M.m_knot[siM];
02783 cvM = M.CV(siM);
02784 cvN = N.CV(siN);
02785 int span_mult = N.KnotMultiplicity(siN+N.Degree()-1);
02786 int skip = N.Order()-span_mult;
02787 cvN += skip*N.m_cv_stride;
02788 for (j=skip; j<N.Order(); j++){
02789 GetRaisedDegreeCV(M.Order(), cvdim, M.m_cv_stride, cvM, knotM, knotN, j, cvN);
02790 cvN += N.m_cv_stride;
02791 }
02792 siN = ON_NextNurbsSpanIndex(N.Order(), N.CVCount(), N.m_knot, siN);
02793 siM = ON_NextNurbsSpanIndex(M.Order(), M.CVCount(), M.m_knot, siM);
02794 }
02795
02796
02797 cvM = M.CV(0);
02798 cvN = N.CV(0);
02799 for (i=0; i<cvdim; i++) cvN[i] = cvM[i];
02800
02801 cvM = M.CV(M.CVCount()-1);
02802 cvN = N.CV(N.CVCount()-1);
02803 for (i=0; i<cvdim; i++) cvN[i] = cvM[i];
02804
02805 return true;
02806 }
02807
02808 bool ON_NurbsCurve::IncreaseDegree( int desired_degree )
02809 {
02810 if ( desired_degree < 1 || desired_degree < m_order-1 ) return false;
02811 if ( desired_degree == m_order-1 ) return true;
02812 if (!ClampEnd(2)) return false;
02813
02814 int del = desired_degree - Degree();
02815 int new_order = Order()+del;
02816 int span_count = SpanCount();
02817 int new_kcount = KnotCount()+(span_count+1)*del;
02818 int new_cvcount = new_kcount - new_order + 2;
02819
02820 if (!ReserveKnotCapacity(new_kcount)) return false;
02821 if (!ReserveCVCapacity(new_cvcount*m_cv_stride)) return false;
02822
02823 for (int i=0; i<del; i++) {
02824 if (!IncrementNurbDegree(*this)) return false;
02825 }
02826
02827 return true;
02828 }
02829
02830 bool ON_NurbsCurve::ChangeDimension( int desired_dimension )
02831 {
02832 bool rc = false;
02833 int i, j;
02834 if ( desired_dimension < 1 )
02835 return false;
02836 if ( desired_dimension == m_dim )
02837 return true;
02838
02839 DestroyCurveTree();
02840
02841 if ( desired_dimension < m_dim )
02842 {
02843 if ( m_is_rat ) {
02844 double* cv;
02845 for ( i = 0; i < m_cv_count; i++ ) {
02846 cv = CV(i);
02847 cv[desired_dimension] = cv[m_dim];
02848 }
02849 }
02850 m_dim = desired_dimension;
02851 rc = true;
02852 }
02853 else
02854 {
02855 const double* cv0;
02856 double* cv1;
02857
02858 const int cv_size1 = m_is_rat ? desired_dimension + 1 : desired_dimension;
02859 const int cv_stride1 = (m_cv_stride < cv_size1) ? cv_size1 : m_cv_stride;
02860 if ( m_cv_stride < cv_stride1 && m_cv_capacity > 0 ) {
02861 m_cv_capacity = cv_stride1*m_cv_count;
02862 m_cv = (double*)onrealloc( m_cv, m_cv_capacity*sizeof(*m_cv) );
02863 }
02864 for ( i = CVCount()-1; i >= 0; i-- ) {
02865 cv0 = CV(i);
02866 cv1 = m_cv + (i*cv_stride1);
02867 if ( m_is_rat )
02868 cv1[desired_dimension] = cv0[m_dim];
02869 for ( j = desired_dimension-1; j >= m_dim; j-- ) {
02870 cv1[j] = 0.0;
02871 }
02872 for ( j = m_dim-1; j >= 0; j-- ) {
02873 cv1[j] = cv0[j];
02874 }
02875 }
02876 m_dim = desired_dimension;
02877 m_cv_stride = cv_stride1;
02878 rc = true;
02879 }
02880 return rc;
02881 }
02882
02883 bool ON_NurbsCurve::Append( const ON_NurbsCurve& c )
02884 {
02885 bool rc = false;
02886
02887 if ( CVCount() == 0 ) {
02888 *this = c;
02889 return IsValid()?true:false;
02890 }
02891
02892 if ( c.IsRational() && !IsRational() ) {
02893 if ( !MakeRational() )
02894 return false;
02895 }
02896 if ( c.Degree() > Degree() ) {
02897 if ( !IncreaseDegree( c.Degree() ) )
02898 return false;
02899 }
02900 if ( c.Dimension() > Dimension() ) {
02901 if ( !ChangeDimension( c.Dimension() ) )
02902 return false;
02903 }
02904
02905 if ( (IsRational() && !c.IsRational())
02906 || c.Degree() < Degree()
02907 || !c.IsClamped(0)
02908 || c.Dimension() < Dimension() )
02909 {
02910 ON_NurbsCurve tmp(c);
02911 if ( !tmp.IncreaseDegree( Degree() ) )
02912 return false;
02913 if ( !tmp.ChangeDimension( Dimension() ) )
02914 return false;
02915 if ( IsRational() ) {
02916 if ( !tmp.MakeRational() )
02917 return false;
02918 }
02919 if ( !tmp.ClampEnd(0) )
02920 return false;
02921
02922
02923 if ( tmp.IsRational() != IsRational() )
02924 return false;
02925 if ( tmp.Degree() != Degree() )
02926 return false;
02927 if ( tmp.Dimension() != Dimension() )
02928 return false;
02929 if ( !tmp.IsClamped(0) )
02930 return false;
02931 return Append(tmp);
02932 }
02933
02934 if ( IsValid()
02935 && c.IsValid()
02936 && Degree() == c.Degree()
02937 && IsRational() == c.IsRational()
02938 && Dimension() == c.Dimension() )
02939 {
02940 if ( !ClampEnd(1) )
02941 return false;
02942 const double w0 = c.Weight(0);
02943 const double w1 = Weight(CVCount()-1);
02944 double w = 1.0;
02945 if ( IsRational() && w0 != w1 ) {
02946 w = w1/w0;
02947 }
02948 ReserveCVCapacity( (CVCount()+c.CVCount())*m_cv_stride );
02949 ReserveKnotCapacity( ON_KnotCount(Order(),CVCount()+c.CVCount()) );
02950 const double dk = Knot(CVCount()-1) - c.Knot(c.Order()-2);
02951
02952 double* cv = CV(CVCount()-1);
02953 const int cv_dim = CVSize();
02954 const int sizeof_cv = cv_dim*sizeof(*cv);
02955 const int c_cv_count = c.CVCount();
02956 const int c_knot_count = c.KnotCount();
02957 int i0, i1, j;
02958
02959 i0 = KnotCount();
02960 for ( i1 = c.Order()-1; i1 < c_knot_count; i1++ ) {
02961 m_knot[i0++] = c.Knot(i1) + dk;
02962 }
02963
02964 for ( i1 = 1; i1 < c_cv_count; i1++ ) {
02965 cv += m_cv_stride;
02966 memcpy( cv, c.CV(i1), sizeof_cv );
02967 if ( w != 1.0 ) {
02968 for ( j = 0; j < cv_dim; j++ )
02969 cv[j] *= w;
02970 }
02971 m_cv_count++;
02972 }
02973 rc = true;
02974 }
02975 return rc;
02976 }
02977
02978 static
02979 ON_BOOL32 TweakSplitTrimParameter( double k0, double k1, double& t )
02980 {
02981
02982
02983
02984
02985 ON_BOOL32 rc = false;
02986 double ktol;
02987 if ( k0 < t && t < k1 )
02988 {
02989
02990
02991
02992
02993 ktol = (fabs(k0) + fabs(k1))*4.0*ON_SQRT_EPSILON;
02994 if ( t-k0 <= ktol && k1-t > 16.0*ktol )
02995 {
02996 t = k0;
02997 rc = true;
02998 }
02999 else if ( k1-t <= ktol && t-k0 > 16.0*ktol )
03000 {
03001 t = k1;
03002 rc = true;
03003 }
03004 }
03005 return rc;
03006 }
03007
03008
03009
03010 ON_BOOL32 ON_NurbsCurve::Trim( const ON_Interval& in )
03011 {
03012 if ( !in.IsIncreasing() )
03013 return false;
03014
03015 const int cv_dim = CVSize();
03016 const int order = Order();
03017 double t, split_t;
03018 int ki, side, i0, i1, i1_max, new_cv_count;
03019
03020
03021
03022 if(in==Domain())
03023 return true;
03024
03025
03026 DestroyCurveTree();
03027
03028
03029 side = -1;
03030 t = in.m_t[1];
03031 ki = ON_NurbsSpanIndex( order, m_cv_count, m_knot, t, side, 0 );
03032
03033
03034 split_t = t;
03035 if ( TweakSplitTrimParameter( m_knot[ki+order-2], m_knot[ki+order-1], split_t ) )
03036 ki = ON_NurbsSpanIndex( order, m_cv_count, m_knot, split_t, side, ki );
03037
03038 if ( !ON_EvaluateNurbsDeBoor( cv_dim, order, m_cv_stride, CV(ki),
03039 m_knot + ki, side, 0.0, t ) )
03040 {
03041 ON_ERROR("ON_NurbsCurve::Trim() - right end de Boor algorithm failed.");
03042 return false;
03043 }
03044
03045 m_cv_count = ki + order;
03046 for ( i0 = ON_KnotCount( order, m_cv_count)-1; i0 >= m_cv_count-1; i0--)
03047 m_knot[i0] = t;
03048
03049
03050 side = 1;
03051 t = in.m_t[0];
03052 ki = ON_NurbsSpanIndex( order, m_cv_count, m_knot, t, side, 0 );
03053
03054
03055 split_t = t;
03056 if ( TweakSplitTrimParameter( m_knot[ki+order-2], m_knot[ki+order-1], split_t ) )
03057 ki = ON_NurbsSpanIndex( order, m_cv_count, m_knot, split_t, side, ki );
03058
03059 if ( !ON_EvaluateNurbsDeBoor( cv_dim, order, m_cv_stride, CV(ki),
03060 m_knot + ki, side, 0.0, t ) )
03061 {
03062 ON_ERROR("ON_NurbsCurve::Trim() - right end de Boor algorithm failed.");
03063 return false;
03064 }
03065
03066
03067 new_cv_count = m_cv_count - ki;
03068 if ( new_cv_count < m_cv_count ) {
03069
03070 i1_max = m_cv_stride*m_cv_count;
03071 for ( i0 = 0, i1 = ki*m_cv_stride; i1 < i1_max; i0++, i1++ )
03072 m_cv[i0] = m_cv[i1];
03073 i1_max = ON_KnotCount( order, m_cv_count );
03074 for ( i0 = 0, i1 = ki; i1 < i1_max; i0++, i1++ )
03075 m_knot[i0] = m_knot[i1];
03076 m_cv_count = new_cv_count;
03077 }
03078
03079
03080 for (i0 = 0; i0 <= order-2; i0++)
03081 m_knot[i0] = t;
03082
03083 ClampEnd(2);
03084
03085 DestroyCurveTree();
03086 return true;
03087 }
03088
03089 bool ON_NurbsCurve::Extend(
03090 const ON_Interval& domain
03091 )
03092
03093 {
03094 if (IsClosed()) return false;
03095 int is_rat = IsRational() ? 1 : 0;
03096 int dim = Dimension();
03097 int cvdim = dim+is_rat;
03098
03099 bool changed = false;
03100 if (domain[0] < Domain()[0]){
03101 ClampEnd(0);
03102 ON_EvaluateNurbsDeBoor(cvdim,Order(),m_cv_stride, CV(0),m_knot,1,0.0,domain[0]);
03103 for (int i = 0; i < Order()-1; i++)
03104 m_knot[i] = domain[0];
03105 changed = true;
03106 }
03107 if (domain[1] > Domain()[1]){
03108 ClampEnd(1);
03109 int i = CVCount() - Order();
03110 ON_EvaluateNurbsDeBoor(cvdim,Order(),m_cv_stride, CV(i),m_knot + i,-1,0.0,domain[1]);
03111 for (i = KnotCount()-1; i >= CVCount()-1; i--)
03112 m_knot[i] = domain[1];
03113 changed = true;
03114 }
03115
03116 if (changed){
03117 DestroyCurveTree();
03118 }
03119 return changed;
03120 }
03121
03122 ON_BOOL32 ON_NurbsCurve::Split(
03123 double t,
03124 ON_Curve*& left_crv,
03125 ON_Curve*& right_crv
03126 ) const
03127 {
03128
03129 int i;
03130 ON_BOOL32 rc = false;
03131 if ( left_crv && !ON_NurbsCurve::Cast(left_crv) )
03132 return false;
03133 if ( right_crv && !ON_NurbsCurve::Cast(right_crv) )
03134 return false;
03135 if ( IsValid() && t > m_knot[m_order-2] && t < m_knot[m_cv_count-1] )
03136 {
03137 ON_NurbsCurve* left = (ON_NurbsCurve*)left_crv;
03138 ON_NurbsCurve* right = (ON_NurbsCurve*)right_crv;
03139 if ( !left )
03140 left = new ON_NurbsCurve();
03141 else if ( left == right )
03142 return false;
03143
03144 if ( !right )
03145 right = new ON_NurbsCurve();
03146 left->DestroyCurveTree();
03147 right->DestroyCurveTree();
03148
03149 int span_index = ON_NurbsSpanIndex(m_order,m_cv_count,m_knot,t,1,0);
03150
03151 double split_t = t;
03152 if ( TweakSplitTrimParameter( m_knot[span_index+m_order-2], m_knot[span_index+m_order-1], split_t ) )
03153 {
03154 if ( split_t <= m_knot[m_order-2] || split_t >= m_knot[m_cv_count-1] ){
03155
03156
03157 if (!left_crv) delete left;
03158 if (!right_crv) delete right;
03159 return false;
03160 }
03161 span_index = ON_NurbsSpanIndex(m_order,m_cv_count,m_knot,split_t,1,span_index);
03162 }
03163
03164 if ( span_index >= 0 && span_index <= m_cv_count - m_order )
03165 {
03166 const int cvdim = CVSize();
03167 const int sizeof_cv = cvdim*sizeof(double);
03168
03169 int left_cv_count = m_order + span_index;
03170 if ( span_index > 0 && split_t == m_knot[span_index+m_order-2] )
03171 {
03172
03173 int k;
03174 for ( k = 0; left_cv_count >= m_order && k <= span_index+m_order-2; k++ )
03175 {
03176 if ( split_t == m_knot[span_index+m_order-2-k] )
03177 left_cv_count--;
03178 else
03179 break;
03180 }
03181 }
03182 int right_cv_count = m_cv_count - span_index;
03183 if ( left_cv_count < m_order || right_cv_count < m_order ){
03184
03185
03186 if (!left_crv) delete left;
03187 if (!right_crv) delete right;
03188 return false;
03189 }
03190
03191 if ( left != this )
03192 {
03193 left->m_dim = m_dim;
03194 left->m_is_rat = m_is_rat;
03195 left->m_order = m_order;
03196 left->m_cv_count = left_cv_count;
03197 left->m_cv_stride = cvdim;
03198 }
03199 if ( right != this )
03200 {
03201 right->m_dim = m_dim;
03202 right->m_is_rat = m_is_rat;
03203 right->m_order = m_order;
03204 right->m_cv_count = right_cv_count;
03205 right->m_cv_stride = cvdim;
03206 }
03207
03208
03209 if ( left->m_cv != m_cv )
03210 {
03211 left->ReserveCVCapacity(cvdim*left_cv_count);
03212 for( i = 0; i < left_cv_count; i++ ) {
03213 memcpy( left->m_cv + i*cvdim, CV(i), sizeof_cv );
03214 }
03215 }
03216 if ( left->m_knot != m_knot )
03217 {
03218 i = ON_KnotCount( m_order, left_cv_count);
03219 left->ReserveKnotCapacity( i );
03220 memcpy( left->m_knot, m_knot, i*sizeof(left->m_knot[0]) );
03221 }
03222
03223
03224 if ( right->m_cv != m_cv || span_index > 0 )
03225 {
03226 right->ReserveCVCapacity(cvdim*right_cv_count);
03227 for( i = 0; i < right_cv_count; i++ ) {
03228 memmove( right->m_cv + i*cvdim, CV(i+span_index), sizeof_cv );
03229 }
03230 }
03231 if ( right->m_knot != m_knot || span_index > 0 )
03232 {
03233 i = ON_KnotCount(m_order, right_cv_count);
03234 right->ReserveKnotCapacity( i );
03235 memmove( right->m_knot, m_knot + span_index, i*sizeof(right->m_knot[0]) );
03236 }
03237
03238 if ( right == this ) {
03239 right->m_cv_count = right_cv_count;
03240 right->m_cv_stride = cvdim;
03241 }
03242
03243 if ( left == this ) {
03244 left->m_cv_count = left_cv_count;
03245 left->m_cv_stride = cvdim;
03246 }
03247
03248
03249 i = left->m_cv_count - left->m_order;
03250 ON_EvaluateNurbsDeBoor( cvdim, m_order, cvdim, left->CV(i), left->m_knot + i, -1, 0.0, t );
03251 for ( i = left->m_cv_count-1; i < ON_KnotCount(left->m_order,left->m_cv_count); i++ )
03252 left->m_knot[i] = t;
03253 left->ClampEnd(2);
03254
03255
03256 ON_EvaluateNurbsDeBoor( cvdim, m_order, cvdim, right->m_cv, right->m_knot, +1, 0.0, t );
03257 for ( i = 0; i <= right->m_order-2; i++ )
03258 right->m_knot[i] = t;
03259 right->ClampEnd(2);
03260
03261 if ( 0 == left_crv )
03262 left_crv = left;
03263 if ( 0 == right_crv )
03264 right_crv = right;
03265 rc = true;
03266 }
03267 }
03268 return rc;
03269 }
03270
03271
03272 int ON_NurbsCurve::GetNurbForm( ON_NurbsCurve& curve,
03273 double tolerance,
03274 const ON_Interval* subdomain
03275 ) const
03276 {
03277 int rc = 1;
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289 ON_NurbsCurveCopyHelper(*this,curve);
03290
03291 if ( subdomain )
03292 {
03293 if ( !curve.Trim(*subdomain) )
03294 rc = 0;
03295 }
03296 return rc;
03297 }
03298
03299 int ON_NurbsCurve::HasNurbForm() const
03300 {
03301 return 1;
03302 }
03303
03304
03305 ON_BOOL32 ON_NurbsCurve::GetCurveParameterFromNurbFormParameter(
03306 double nurbs_t,
03307 double* curve_t
03308 ) const
03309 {
03310 *curve_t = nurbs_t;
03311 return true;
03312 }
03313
03314 ON_BOOL32 ON_NurbsCurve::GetNurbFormParameterFromCurveParameter(
03315 double curve_t,
03316 double* nurbs_t
03317 ) const
03318 {
03319 *nurbs_t = curve_t;
03320 return true;
03321 }
03322
03323 bool ON_NurbsCurve::ClampEnd(
03324 int end
03325 )
03326 {
03327
03328 return ON_ClampKnotVector( CVSize(), m_order,
03329 m_cv_count, m_cv_stride, m_cv,
03330 m_knot, end );
03331 }
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351
03352
03353
03354
03355 static bool ON_IsDuplicateKnotVector( int order, int cv_count,
03356 const double* knot, const double* other_knot,
03357 bool bIgnoreParameterization )
03358 {
03359 bool rc = ( 0 != knot
03360 && 0 != other_knot
03361 && order >= 2
03362 && cv_count >= order);
03363
03364 if (rc)
03365 {
03366 const int knot_count = ON_KnotCount( order, cv_count );
03367 int i;
03368 if ( bIgnoreParameterization )
03369 {
03370 const ON_Interval dom(knot[order-2],knot[cv_count-1]);
03371 const ON_Interval other_dom(other_knot[order-2],other_knot[cv_count-1]);
03372 double k, other_k;
03373 for ( i = 0; i < knot_count && rc; i++ )
03374 {
03375 k = dom.NormalizedParameterAt(knot[i]);
03376 other_k = dom.NormalizedParameterAt(other_knot[i]);
03377 rc = (fabs(k-other_k) <= ON_ZERO_TOLERANCE);
03378 }
03379 }
03380 else
03381 {
03382 for ( i = 0; i < knot_count && rc; i++ )
03383 {
03384 rc = (knot[i] == other_knot[i]);
03385 }
03386 }
03387 }
03388 return rc;
03389 }
03390
03391 static bool ON_IsDuplicatePointList( int dim, int is_rat,
03392 int count,
03393 int stride,
03394 const double* cv,
03395 int other_stride,
03396 const double* other_cv,
03397 double tolerance
03398 )
03399 {
03400 bool rc = (dim > 0 && is_rat >= 0 && is_rat <= 1 && count > 0
03401 && abs(stride) >= dim+is_rat && abs(other_stride) >= (dim+is_rat)
03402 && 0 != cv && 0 != other_cv);
03403 if (rc)
03404 {
03405 if ( tolerance < 0.0 )
03406 tolerance = 0.0;
03407 int i, j;
03408 double w = 1.0;
03409 double other_w = 1.0;
03410 double cv_tol = tolerance;
03411 for ( i = 0; i < count && rc; i++ )
03412 {
03413 if ( is_rat )
03414 {
03415 w = cv[dim];
03416 other_w = other_cv[dim];
03417 cv_tol = fabs(w*tolerance);
03418 rc = ( w == other_w );
03419 }
03420
03421 for ( j = 0; j < dim && rc; j++ )
03422 {
03423 rc = (fabs(cv[j] - other_cv[j]) <= cv_tol);
03424 }
03425 cv += stride;
03426 other_cv += other_stride;
03427 }
03428 }
03429 return rc;
03430 }
03431
03432
03433 bool ON_NurbsCurve::IsDuplicate(
03434 const ON_NurbsCurve& other,
03435 bool bIgnoreParameterization,
03436 double tolerance
03437 ) const
03438 {
03439 bool rc = (this == &other);
03440 if ( !rc
03441 && m_dim == other.m_dim
03442 && m_is_rat == other.m_is_rat
03443 && m_order == other.m_order
03444 && m_cv_count == other.m_cv_count
03445 )
03446 {
03447
03448 rc = ON_IsDuplicateKnotVector( m_order, m_cv_count, m_knot, other.m_knot, bIgnoreParameterization );
03449
03450
03451 if (rc)
03452 rc = ON_IsDuplicatePointList( m_dim, m_is_rat?1:0, m_cv_count,
03453 m_cv_stride, m_cv,
03454 other.m_cv_stride, other.m_cv,
03455 tolerance );
03456 }
03457 return rc;
03458 }
03459
03460 bool ON_NurbsSurface::IsDuplicate(
03461 const ON_NurbsSurface& other,
03462 bool bIgnoreParameterization,
03463 double tolerance
03464 ) const
03465 {
03466 bool rc = (this == &other);
03467 if ( !rc
03468 && m_dim == other.m_dim
03469 && m_is_rat == other.m_is_rat
03470 && m_order[0] == other.m_order[0]
03471 && m_order[1] == other.m_order[1]
03472 && m_cv_count[0] == other.m_cv_count[0]
03473 && m_cv_count[1] == other.m_cv_count[1]
03474 )
03475 {
03476
03477 rc = ON_IsDuplicateKnotVector( m_order[0], m_cv_count[0], m_knot[0], other.m_knot[0], bIgnoreParameterization );
03478 if (rc)
03479 rc = ON_IsDuplicateKnotVector( m_order[1], m_cv_count[1], m_knot[1], other.m_knot[1], bIgnoreParameterization );
03480
03481
03482 int i;
03483 for ( i = 0; i < m_cv_count[0] && rc; i++ )
03484 {
03485 rc = ON_IsDuplicatePointList( m_dim, m_is_rat?1:0, m_cv_count[1],
03486 m_cv_stride[1], CV(i,0),
03487 other.m_cv_stride[1], other.CV(i,0),
03488 tolerance );
03489 }
03490 }
03491 return rc;
03492 }
03493
03494
03495 bool ON_Brep::IsDuplicate(
03496 const ON_Brep& other,
03497 double tolerance
03498 ) const
03499 {
03500
03501 return false;
03502 }
03503
03504 bool ON_NurbsCurve::Reparameterize(double c)
03505 {
03506 if ( !ON_IsValid(c) || 0.0 == c )
03507 return false;
03508
03509 if ( 1.0 == c )
03510 return true;
03511
03512 if ( !MakeRational() )
03513 return false;
03514
03515 return ON_ReparameterizeRationalNurbsCurve(
03516 c,
03517 m_dim,m_order,m_cv_count,
03518 m_cv_stride,m_cv,m_knot
03519 );
03520 }
03521
03522 bool ON_ReparameterizeRationalNurbsCurve(
03523 double c,
03524 int dim,
03525 int order,
03526 int cv_count,
03527 int cvstride,
03528 double* cv,
03529 double* knot
03530 )
03531 {
03532
03533
03534
03535
03536 const double c1 = c-1.0;
03537 double k0, k1, k, d, w0, w1;
03538 int i,j;
03539
03540 if ( !ON_IsValid(c) || !ON_IsValid(c1) || 0.0 == c )
03541 return false;
03542
03543 if ( 1.0 == c )
03544 return true;
03545
03546
03547 k0 = knot[order-2];
03548 k1 = knot[cv_count-1];
03549 d = k1 - k0;
03550 if ( !ON_IsValid(d) || d <= 0.0 )
03551 return false;
03552 d = 1.0/d;
03553 j = cv_count+order-2;
03554 for ( i = 0; i < j; i++ )
03555 {
03556 k = knot[i];
03557 k = (k - k0)*d;
03558 knot[i] = c*k/(c1*k+1.0);
03559 }
03560
03561
03562 order -= 2;
03563 cvstride -= (dim+1);
03564 for ( i = 0; i < cv_count; i++ )
03565 {
03566 d = c - c1*(*knot++);
03567 j = order;
03568 while(j--)
03569 {
03570 d *= c - c1*knot[j];
03571 }
03572 w0 = cv[dim];
03573 w1 = w0*d;
03574 j = dim;
03575 while(j--)
03576 *cv++ *= d;
03577 *cv++ = w1;
03578 cv += cvstride;
03579 }
03580 order += 2;
03581 cvstride += (dim+1);
03582 cv -= cv_count*cvstride;
03583 knot -= cv_count;
03584
03585
03586 j = cv_count+order-2;
03587 for ( i = 0; i < j; i++ )
03588 {
03589 k = knot[i];
03590 knot[i] = (1.0-k)*k0 + k*k1;
03591 }
03592
03593 return true;
03594 }
03595
03596 bool ON_NurbsCurve::ChangeEndWeights(double w0, double w1)
03597 {
03598 if ( !ON_IsValid(w0) || !ON_IsValid(w1) || 0.0 == w0 || 0.0 == w1 )
03599 return false;
03600 if ( (w0 < 0.0 && w1 > 0.0) || (w0 > 0.0 && w0 < 0.0) )
03601 return false;
03602
03603 if (!ClampEnd(2))
03604 return false;
03605
03606 if ( w0 == Weight(0) && w1 == Weight(m_cv_count) )
03607 return true;
03608
03609 if ( !MakeRational() )
03610 return false;
03611
03612 return ON_ChangeRationalNurbsCurveEndWeights(
03613 m_dim,m_order,
03614 m_cv_count,m_cv_stride,m_cv,
03615 m_knot,
03616 w0,w1);
03617 }
03618
03619 bool ON_ChangeRationalNurbsCurveEndWeights(
03620 int dim,
03621 int order,
03622 int cv_count,
03623 int cvstride,
03624 double* cv,
03625 double* knot,
03626 double w0,
03627 double w1
03628 )
03629 {
03630 double r, s, v0, v1;
03631 int i, j;
03632
03633 if ( !ON_IsValid(w0) || !ON_IsValid(w1) || 0.0 == w0 || 0.0 == w1 )
03634 return false;
03635 if ( (w0 < 0.0 && w1 > 0.0) || (w0 > 0.0 && w0 < 0.0) )
03636 return false;
03637
03638 if ( !ON_ClampKnotVector( dim+1, order, cv_count, cvstride, cv, knot, 2 ) )
03639 return false;
03640
03641 v0 = cv[dim];
03642 v1 = cv[cvstride*(cv_count-1)+dim];
03643 if (!ON_IsValid(v0) || !ON_IsValid(v1) || v0 == 0.0 || v1 == 0.0)
03644 return false;
03645 if (v0 < 0.0 && v1 > 0.0)
03646 return false;
03647 if ( v0 > 0.0 && v1 < 0.0)
03648 return false;
03649
03650 r = w0/v0;
03651 s = w1/v1;
03652 if ( fabs(r-s) <= fabs(s)*ON_SQRT_EPSILON )
03653 {
03654
03655 if ( r != s )
03656 s = 0.5*(r+s);
03657 r = s;
03658 }
03659
03660 if ( 1.0 != s && v1 != w1 )
03661 {
03662
03663 dim++;
03664 cvstride -= dim;
03665 i = cv_count;
03666 while(i--)
03667 {
03668 j = dim;
03669 while(j--)
03670 *cv++ *= s;
03671 cv += cvstride;
03672 }
03673 cvstride += dim;
03674 dim--;
03675 cv -= cvstride*cv_count;
03676 }
03677
03678 if ( r != s )
03679 {
03680 v0 = cv[dim];
03681 v1 = cv[cvstride*(cv_count-1)+dim];
03682 if ( ON_IsValid(v0) && ON_IsValid(v1) && 0.0 != v0 )
03683 {
03684
03685 r = pow(w0/v0,1.0/((double)(order-1)));
03686 if ( !ON_IsValid(r) )
03687 return false;
03688 if ( !ON_ReparameterizeRationalNurbsCurve(r,dim,order,cv_count,cvstride,cv,knot) )
03689 return false;
03690 }
03691 }
03692
03693
03694 cv[dim] = w0;
03695 cv[cvstride*(cv_count-1)+dim] = w1;
03696
03697 return true;
03698 }
03699
03700 double ON_Fuzz( double x, double absolute_tolerance )
03701 {
03702 double fuzz = fabs(x)*ON_RELATIVE_TOLERANCE;
03703 return(fuzz > absolute_tolerance) ? fuzz : absolute_tolerance;
03704 }
03705
03706 bool ON_NurbsCurve::SpanIsSingular(
03707 int span_index
03708 ) const
03709 {
03710 const int cv_size = CVSize();
03711 if ( m_order < 2
03712 || m_cv_count < m_order
03713 || m_dim <= 0
03714 || cv_size > m_cv_stride
03715 || 0 == m_knot
03716 || 0 == m_cv
03717 )
03718 {
03719 ON_ERROR("Invalid NURBS curve.");
03720 return false;
03721 }
03722
03723 if ( span_index < 0 || span_index > m_cv_count-m_order )
03724 {
03725 ON_ERROR("span_index parameter is out of range.");
03726 return false;
03727 }
03728
03729 const double* cv = CV(span_index);
03730 const double* knot = m_knot + span_index;
03731
03732 if ( !(knot[m_order-2] < knot[m_order-1]) )
03733 {
03734
03735
03736
03737
03738 return false;
03739 }
03740
03741 double* p = 0;
03742 int cv_stride = m_cv_stride;
03743 if ( knot[0] != knot[m_order-2] || knot[m_order-1] != knot[2*m_order-3] )
03744 {
03745 const size_t sizeof_cv = cv_size*sizeof(p[0]);
03746 p = (double*)onmalloc(sizeof_cv*m_order);
03747 for ( int i = 0; i < m_order; i++ )
03748 memcpy( p+(i*cv_size), cv+(i*cv_stride), sizeof_cv );
03749 ON_ConvertNurbSpanToBezier( cv_size, m_order, cv_size, p,
03750 knot, knot[m_order-2], knot[m_order-1]
03751 );
03752 cv_stride = cv_size;
03753 cv = p;
03754 }
03755 const bool rc = ON_PointsAreCoincident(m_dim,m_is_rat,m_order,cv_stride,cv);
03756 if ( 0 != p )
03757 onfree(p);
03758
03759 return rc;
03760 }
03761
03762 bool ON_NurbsCurve::RemoveSpan(
03763 int span_index
03764 )
03765 {
03766 const int cv_size = CVSize();
03767 if ( m_order < 2
03768 || m_cv_count < m_order
03769 || m_dim <= 0
03770 || cv_size > m_cv_stride
03771 || 0 == m_knot
03772 || 0 == m_cv
03773 )
03774 {
03775 ON_ERROR("Invalid NURBS curve.");
03776 return false;
03777 }
03778
03779 if ( span_index < 0 || span_index > m_cv_count-m_order )
03780 {
03781 ON_ERROR("span_index parameter is out of range.");
03782 return false;
03783 }
03784
03785 if ( m_cv_count == m_order )
03786 {
03787 ON_ERROR("Cannot remove the only span from a Bezier NURBS curve.");
03788 return false;
03789 }
03790
03791 const size_t sizeof_cv = cv_size*sizeof(m_cv[0]);
03792 int i, j;
03793
03794 const double knot0 = m_knot[span_index+m_order-2];
03795 const double knot1 = m_knot[span_index+m_order-1];
03796 const double knot_delta = (knot0 < knot1) ? (knot1 - knot0) : 0.0;
03797
03798 const bool bIsPeriodic0 = IsPeriodic()?true:false;
03799
03800 if ( span_index <= 0 )
03801 {
03802
03803
03804 for ( span_index = 1; span_index < m_cv_count-m_order; span_index++ )
03805 {
03806 if ( m_knot[span_index+m_order-2] < m_knot[span_index+m_order-1] )
03807 break;
03808 }
03809 for ( i = 0; i+span_index < m_cv_count; i++ )
03810 memcpy(CV(i),CV(i+span_index),sizeof_cv);
03811 for ( i = 0; i+span_index < m_cv_count+m_order-2; i++ )
03812 {
03813 m_knot[i] = (knot1 == m_knot[i+span_index])
03814 ? knot0
03815 : (m_knot[i+span_index] - knot_delta);
03816 }
03817 m_cv_count -= span_index;
03818 }
03819 else if ( span_index >= m_cv_count-m_order )
03820 {
03821
03822
03823 for ( span_index = m_cv_count-m_order-1; span_index > 0; span_index-- )
03824 {
03825 if ( m_knot[span_index+m_order-2] < m_knot[span_index+m_order-1] )
03826 break;
03827 }
03828 m_cv_count = span_index+m_order;
03829 }
03830 else
03831 {
03832
03833 int k0 = span_index+m_order-2;
03834 int k1 = span_index+m_order-1;
03835 int i0 = k0;
03836 int i1 = k1;
03837 for ( i0 = k0; i0 > 0; i0-- )
03838 {
03839 if ( m_knot[i0-1] < m_knot[k0] )
03840 break;
03841 }
03842 for ( i1 = k1; i1 < m_cv_count+m_order-3; i1++ )
03843 {
03844 if ( m_knot[i1+1] > m_knot[k1] )
03845 break;
03846 }
03847 int m = (i1-i0+1);
03848 if ( !(knot_delta > 0.0) )
03849 {
03850 if ( !(m_knot[i0] == m_knot[i1]) || m < m_order )
03851 {
03852 ON_ERROR("span_index parameter identifies an empty span.");
03853 return false;
03854 }
03855 }
03856
03857 int span_index0 = i0 - (m_order-1);
03858 double* cv0 = 0;
03859 if ( span_index0 >= 0 && k0 - i0 + 1 < m_order-1 )
03860 {
03861 cv0 = (double*)onmalloc( (m_order*cv_size + 2*m_order-2)*sizeof(cv0[0]) );
03862 double* knot0 = cv0 + (m_order*cv_size);
03863 memcpy( knot0, m_knot+span_index0, (2*m_order-2)*sizeof(knot0[0]) );
03864 for ( i = 0; i < m_order; i++ )
03865 memcpy( cv0 + (i*cv_size), CV(span_index0+i), sizeof_cv );
03866 ON_ClampKnotVector( cv_size, m_order, m_order, cv_size, cv0, knot0, 1 );
03867 }
03868
03869 if ( m < m_order-1 )
03870 {
03871 i = m_order-1 - m;
03872 ReserveCVCapacity( m_cv_stride*(m_cv_count+i) );
03873 ReserveKnotCapacity( m_cv_count+m_order-2+i );
03874 for ( j = m_cv_count+m_order-3; j >= i1-m_order+2; j-- )
03875 m_knot[j+i] = m_knot[j];
03876 for ( j = m_cv_count-1; j >= i1-m_order+2; j-- )
03877 memcpy(CV(j+i),CV(j),sizeof_cv);
03878 i1 += i;
03879 k1 += i;
03880 m_cv_count += i;
03881 }
03882
03883 if ( i1-k1 < m_order-2 )
03884 ON_ClampKnotVector( cv_size, m_order, m_order, m_cv_stride,
03885 m_cv + ((i1-m_order+2)*m_cv_stride),
03886 m_knot + (i1-m_order+2),
03887 0 );
03888
03889 k0 = i0;
03890 k1 = i1-m_order+2;
03891
03892 if ( 0 != cv0 )
03893 {
03894 for ( i = 0; i < m_order-1; i++ )
03895 memcpy(CV(i+span_index0),cv0 + (i*cv_size),sizeof_cv);
03896 onfree(cv0);
03897 cv0 = 0;
03898 }
03899
03900 if ( k0 < k1 )
03901 {
03902 for ( i = 0; i + k1 < m_cv_count; i++ )
03903 memcpy(CV(i+k0),CV(i+k1),sizeof_cv);
03904 for ( i = 0; i + k1 < m_cv_count+m_order-2; i++ )
03905 {
03906 m_knot[i+k0] = (knot1 == m_knot[i+k1])
03907 ? knot0
03908 : (m_knot[i+k1] - knot_delta);
03909 }
03910 m_cv_count -= (k1-k0);
03911 }
03912 else if ( k0 == k1 && knot_delta > 0.0 )
03913 {
03914 for ( i = k0; i < m_cv_count+m_order-2; i++ )
03915 {
03916 m_knot[i] = (knot1 == m_knot[i])
03917 ? knot0
03918 : (m_knot[i] - knot_delta);
03919 }
03920 }
03921 }
03922
03923 if ( false == bIsPeriodic0 || false == IsPeriodic() )
03924 ClampEnd(2);
03925
03926 return true;
03927 }
03928
03929 int ON_NurbsCurve::RemoveSingularSpans()
03930 {
03931 const int cv_size = CVSize();
03932 if ( m_order < 2
03933 || m_cv_count < m_order
03934 || m_dim <= 0
03935 || cv_size > m_cv_stride
03936 || 0 == m_knot
03937 || 0 == m_cv
03938 )
03939 {
03940 ON_ERROR("Invalid NURBS curve.");
03941 return 0;
03942 }
03943
03944 int singular_span_count = 0;
03945
03946 for ( int span_index = 0; m_cv_count > m_order && span_index <= m_cv_count-m_order; span_index++ )
03947 {
03948 if ( m_knot[span_index+m_order-2] < m_knot[span_index+m_order-1]
03949 && SpanIsSingular(span_index)
03950 )
03951 {
03952 const int cv_count0 = m_cv_count;
03953 if ( RemoveSpan(span_index) )
03954 singular_span_count++;
03955 if ( 0 == span_index || m_cv_count < cv_count0 )
03956 span_index--;
03957 }
03958 }
03959
03960 return singular_span_count;
03961 }