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_PolyCurve,ON_Curve,"4ED7D4E0-E947-11d3-BFE5-0010830122F0");
00020
00021 ON_PolyCurve::ON_PolyCurve()
00022 {
00023 }
00024
00025 ON_PolyCurve::ON_PolyCurve( int capacity )
00026 : m_segment(capacity), m_t(capacity+1)
00027 {
00028 m_segment.Zero();
00029 }
00030
00031 ON_PolyCurve::ON_PolyCurve( const ON_PolyCurve& src )
00032 : m_segment(src.Count()), m_t(src.Count()+1)
00033 {
00034 *this = src;
00035 }
00036
00037 void ON_PolyCurve::Destroy()
00038 {
00039
00040 m_segment.Destroy();
00041 m_t.Destroy();
00042 }
00043
00044 ON_PolyCurve::~ON_PolyCurve()
00045 {
00046 Destroy();
00047 }
00048
00049 void ON_PolyCurve::EmergencyDestroy()
00050 {
00051 m_segment.EmergencyDestroy();
00052 m_t.EmergencyDestroy();
00053 }
00054
00055 void ON_PolyCurve::DestroyRuntimeCache( bool bDelete )
00056 {
00057 ON_Curve::DestroyRuntimeCache(bDelete);
00058 int i, count = m_segment.Count();
00059 for ( i = 0; i < count; i++ )
00060 {
00061 ON_Curve* segment_curve = m_segment[i];
00062 if ( 0 != segment_curve && this != segment_curve )
00063 segment_curve->DestroyRuntimeCache(bDelete);
00064 }
00065 }
00066
00067 unsigned int ON_PolyCurve::SizeOf() const
00068 {
00069 unsigned int sz = ON_Curve::SizeOf();
00070 sz += (sizeof(*this) - sizeof(ON_Curve));
00071 sz += m_t.SizeOfArray();
00072 sz += m_segment.SizeOfArray();
00073 int i, count = m_segment.Count();
00074 for ( i = 0; i < count; i++ )
00075 {
00076 const ON_Curve* crv = m_segment[i];
00077 if ( crv )
00078 sz += crv->SizeOf();
00079 }
00080 return sz;
00081 }
00082
00083 ON__UINT32 ON_PolyCurve::DataCRC(ON__UINT32 current_remainder) const
00084 {
00085 int i, count = m_segment.Count();
00086 for ( i = 0; i < count; i++ )
00087 {
00088 const ON_Curve* crv = m_segment[i];
00089 if ( crv )
00090 current_remainder = crv->DataCRC(current_remainder);
00091 }
00092 current_remainder = m_t.DataCRC(current_remainder);
00093 return current_remainder;
00094 }
00095
00096
00097 ON_PolyCurve& ON_PolyCurve::operator=( const ON_PolyCurve& src )
00098 {
00099 if ( this != &src ) {
00100 ON_Curve::operator=(src);
00101 const int segment_capacity = m_segment.Capacity();
00102 ON_Curve** segment = m_segment.Array();
00103 int i;
00104 for ( i = 0; i < segment_capacity; i++ ) {
00105 if ( segment[i] ) {
00106 delete segment[i];
00107 segment[i] = 0;
00108 }
00109 }
00110 src.m_segment.Duplicate(m_segment);
00111 m_t.SetCount(0);
00112 m_t.SetCapacity(src.m_t.Count());
00113 m_t.Zero();
00114 m_t = src.m_t;
00115 }
00116 return *this;
00117 }
00118
00119 int ON_PolyCurve::Dimension() const
00120 {
00121 const ON_Curve* p = SegmentCurve(0);
00122 return (p) ? p->Dimension() : 0;
00123 }
00124
00125 ON_BOOL32
00126 ON_PolyCurve::GetBBox(
00127 double* boxmin,
00128 double* boxmax,
00129 ON_BOOL32 bGrowBox
00130 ) const
00131 {
00132 const int count = Count();
00133 int segment_index;
00134 ON_BOOL32 rc = (count>0) ? true : false;
00135 for ( segment_index = 0; segment_index < count && rc; segment_index++ ) {
00136 rc = m_segment[segment_index]->GetBBox( boxmin, boxmax, bGrowBox );
00137 bGrowBox = true;
00138 }
00139 return rc;
00140 }
00141
00142 ON_BOOL32
00143 ON_PolyCurve::Transform( const ON_Xform& xform )
00144 {
00145 TransformUserData(xform);
00146 DestroyRuntimeCache();
00147 const int count = Count();
00148 int segment_index;
00149 ON_BOOL32 rc = (count>0) ? true : false;
00150 for ( segment_index = 0; segment_index < count && rc; segment_index++ ) {
00151 rc = m_segment[segment_index]->Transform( xform );
00152 }
00153 return rc;
00154 }
00155
00156 bool ON_PolyCurve::IsDeformable() const
00157 {
00158 bool rc = true;
00159 const int count = Count();
00160 int segment_index;
00161 for ( segment_index = 0; segment_index < count ; segment_index++ )
00162 {
00163 const ON_Curve* seg = m_segment[segment_index];
00164 if ( seg && !seg->IsDeformable() )
00165 {
00166 rc = false;
00167 break;
00168 }
00169 }
00170 return rc;
00171 }
00172
00173 bool ON_PolyCurve::MakeDeformable()
00174 {
00175 bool rc = true;
00176 bool bDestroyRuntimeCache = false;
00177 const int count = Count();
00178 int segment_index;
00179 for ( segment_index = 0; segment_index < count ; segment_index++ )
00180 {
00181 ON_Curve* seg = m_segment[segment_index];
00182 if ( seg && !seg->IsDeformable() )
00183 {
00184 bDestroyRuntimeCache = true;
00185 if ( !seg->MakeDeformable() )
00186 {
00187 ON_NurbsCurve* nurbs_curve = seg->NurbsCurve();
00188 if ( nurbs_curve )
00189 {
00190 delete seg;
00191 m_segment[segment_index] = nurbs_curve;
00192 }
00193 else
00194 rc = false;
00195 }
00196 }
00197 }
00198 if ( bDestroyRuntimeCache )
00199 DestroyRuntimeCache();
00200 return rc;
00201 }
00202
00203
00204 ON_BOOL32
00205 ON_PolyCurve::SwapCoordinates( int i, int j )
00206 {
00207 const int count = Count();
00208 int segment_index;
00209 ON_BOOL32 rc = (count>0) ? true : false;
00210 for ( segment_index = 0; segment_index < count && rc; segment_index++ ) {
00211 rc = m_segment[segment_index]->SwapCoordinates( i, j );
00212 }
00213 DestroyCurveTree();
00214 return rc;
00215 }
00216
00217 ON_BOOL32 ON_PolyCurve::IsValid( ON_TextLog* text_log ) const
00218 {
00219 return IsValid(false,text_log);
00220 }
00221
00222 bool ON_PolyCurve::IsValid( bool bAllowGaps, ON_TextLog* text_log ) const
00223 {
00224 const int count = Count();
00225 const int dim = Dimension();
00226 ON_3dPoint p0, p1;
00227 int segment_index;
00228 if ( count <= 0 || dim <= 0 )
00229 {
00230 if ( text_log )
00231 text_log->Print("Polycurve segment count = %d and dim = %d\n",count,dim);
00232 return ON_IsNotValid();
00233 }
00234
00235 if ( m_t.Count() != count+1 )
00236 {
00237 if ( text_log )
00238 text_log->Print("Polycurve segment count = %d and m_t.Count()=%d (should be segment count+1)\n",
00239 count,m_t.Count());
00240 return ON_IsNotValid();
00241 }
00242
00243 for ( segment_index = 0; segment_index < count; segment_index++ )
00244 {
00245 if ( 0 == m_segment[segment_index] )
00246 {
00247 if ( text_log )
00248 {
00249 text_log->Print("Polycurve segment[%d] is null.\n",segment_index);
00250 }
00251 return ON_IsNotValid();
00252 }
00253
00254 if ( !m_segment[segment_index]->IsValid( text_log ) )
00255 {
00256 if ( text_log )
00257 {
00258 text_log->Print("Polycurve segment[%d] is not valid.\n",segment_index);
00259 }
00260 return ON_IsNotValid();
00261 }
00262
00263 int seg_dim = m_segment[segment_index]->Dimension();
00264 if ( seg_dim != dim )
00265 {
00266 if ( text_log )
00267 text_log->Print("Polycurve segment[%d]->Dimension()=%d (should be %d).\n",segment_index,seg_dim,dim);
00268 return ON_IsNotValid();
00269 }
00270
00271 if ( m_t[segment_index] >= m_t[segment_index+1] )
00272 {
00273 if ( text_log )
00274 text_log->Print("Polycurve m_t[%d]=%g and m_t[%d]=%g (should be increasing)\n",
00275 segment_index, m_t[segment_index],
00276 segment_index+1, m_t[segment_index+1]);
00277 return ON_IsNotValid();
00278 }
00279
00280 if ( count > 1 && !bAllowGaps && m_segment[segment_index]->IsClosed() )
00281 {
00282 if ( text_log )
00283 text_log->Print("Polycurve segment[%d] is closed (%d segments).\n",segment_index,count);
00284 return ON_IsNotValid();
00285 }
00286 }
00287
00288 if ( !bAllowGaps )
00289 {
00290
00291 int gap_index = FindNextGap(0);
00292 if ( gap_index > 0 )
00293 {
00294 p0 = m_segment[gap_index-1]->PointAtEnd();
00295 p1 = m_segment[gap_index]->PointAtStart();
00296 double d = p0.DistanceTo(p1);
00297 if ( text_log )
00298 text_log->Print("Polycurve end of segment[%d] != start of segment[%d] (distance=%g)\n",
00299 gap_index-1, gap_index, d );
00300 return ON_IsNotValid();
00301 }
00302 }
00303
00304 return true;
00305 }
00306
00307 void ON_PolyCurve::Dump( ON_TextLog& dump ) const
00308 {
00309 const int count = Count();
00310 int i;
00311
00312 ON_3dPoint segment_start = ON_3dPoint::UnsetPoint;
00313 ON_3dPoint segment_end = ON_3dPoint::UnsetPoint;
00314 double gap;
00315
00316 dump.Print( "ON_PolyCurve segment count = %d\n", count );
00317 dump.PushIndent();
00318 for ( i = 0; i < count; i++ )
00319 {
00320 if ( 0 != m_segment[i] )
00321 segment_start = m_segment[i]->PointAtStart();
00322 else
00323 segment_start = ON_3dPoint::UnsetPoint;
00324 gap = (segment_start.IsValid() && segment_end.IsValid())
00325 ? segment_start.DistanceTo(segment_end)
00326 : ON_UNSET_VALUE;
00327 dump.Print( "Segment %d: (%g,%g)", i+1, m_t[i], m_t[i+1] );
00328 if ( i > 0 )
00329 {
00330 if ( ON_IsValid(gap) )
00331 dump.Print(" gap = %.17g",gap);
00332 else if ( !segment_start.IsValid() )
00333 dump.Print(" invalid segment curve");
00334 else if ( !segment_end.IsValid() )
00335 dump.Print(" invalid previous segment curve");
00336 }
00337 dump.Print("\n");
00338
00339 dump.PushIndent();
00340 if ( 0 == m_segment[i] )
00341 {
00342 dump.Print("null curve pointer\n");
00343 segment_end = ON_3dPoint::UnsetPoint;
00344 }
00345 else
00346 {
00347 m_segment[i]->Dump(dump);
00348 segment_end = m_segment[i]->PointAtEnd();
00349 }
00350 dump.PopIndent();
00351 }
00352 dump.PopIndent();
00353 }
00354
00355 ON_BOOL32 ON_PolyCurve::Write(
00356 ON_BinaryArchive& file
00357 ) const
00358 {
00359
00360 ON_BOOL32 rc = file.Write3dmChunkVersion(1,0);
00361 if (rc) {
00362 int reserved1 = 0;
00363 int reserved2 = 0;
00364 const int count = Count();
00365 int segment_index;
00366
00367 rc = file.WriteInt( count );
00368 if (rc) file.WriteInt(reserved1);
00369 if (rc) file.WriteInt(reserved2);
00370 if (rc) {
00371
00372 ON_BoundingBox bbox;
00373 rc = file.WriteBoundingBox(bbox);
00374 }
00375 if (rc) rc = file.WriteArray( m_t );
00376
00377 for ( segment_index = 0; segment_index < count && rc; segment_index++ ) {
00378 rc = file.WriteObject( *SegmentCurve(segment_index) );
00379 }
00380
00381
00382 }
00383 return rc;
00384 }
00385
00386 ON_BOOL32 ON_PolyCurve::Read(
00387 ON_BinaryArchive& file
00388 )
00389 {
00390
00391 Destroy();
00392 int major_version = 0;
00393 int minor_version = 0;
00394
00395 ON_BOOL32 rc = file.Read3dmChunkVersion(&major_version,&minor_version);
00396
00397 if (rc)
00398 {
00399 ON_Object* obj;
00400 ON_Curve* crv;
00401 int segment_index;
00402 int segment_count = 0;
00403 int reserved1 = 0;
00404 int reserved2 = 0;
00405 rc = file.ReadInt(&segment_count);
00406 if (rc) rc = file.ReadInt(&reserved1);
00407 if (rc) rc = file.ReadInt(&reserved2);
00408 if (rc) {
00409
00410 ON_BoundingBox bbox;
00411 rc = file.ReadBoundingBox(bbox);
00412 }
00413 if (rc) rc = file.ReadArray( m_t );
00414
00415 for ( segment_index = 0; segment_index < segment_count && rc; segment_index++ ) {
00416 obj = 0;
00417 crv = 0;
00418 rc = file.ReadObject( &obj );
00419 if (rc) {
00420 crv = ON_Curve::Cast(obj);
00421 if (crv) {
00422
00423 m_segment.Append(crv);
00424 }
00425 else {
00426 ON_ERROR("ON_PolyCurve::Read() - non ON_Curve object in segment list\n");
00427 delete obj;
00428 rc = false;
00429 }
00430 }
00431 }
00432
00433 if ( rc && m_segment.Count()>0 &&
00434 m_segment.Count()==segment_count && m_t.Count()==segment_count+1)
00435 {
00436
00437 double s, t, d0, d1, fuzz;
00438 ON_Interval in0, in1;
00439 in1 = SegmentCurve(0)->Domain();
00440 d1 = in1.Length();
00441 for ( segment_index = 1; segment_index < segment_count; segment_index++ )
00442 {
00443 t = m_t[segment_index];
00444 in0 = in1;
00445 d0 = d1;
00446 in1 = SegmentCurve(segment_index)->Domain();
00447 d1 = in1.Length();
00448 s = in0[1];
00449 if ( s != t && s == in1[0] && t > in0[0] && t < in1[1] )
00450 {
00451 fuzz = ((d0<=d1)?d0:d1)*ON_SQRT_EPSILON;
00452 if ( fabs(t-s) <= fuzz )
00453 m_t[segment_index] = s;
00454 }
00455 }
00456 fuzz = d1*ON_SQRT_EPSILON;
00457 t = m_t[segment_count];
00458 s = in1[1];
00459 if ( s != t && t > in1[0] && fabs(s-t) <= fuzz )
00460 m_t[segment_count] = s;
00461 }
00462 }
00463
00464 if (rc && file.ArchiveOpenNURBSVersion() < 200304080 )
00465 {
00466
00467
00468
00469
00470
00471 RemoveNesting();
00472
00473 }
00474
00475 return rc;
00476 }
00477
00478
00479 ON_Curve* ON_PolyCurve::DuplicateCurve() const
00480 {
00481
00482 int cnt = Count();
00483 ON_PolyCurve* dup_crv = new ON_PolyCurve( cnt );
00484 dup_crv->CopyUserData(*this);
00485 for( int i=0; i<cnt; i++){
00486 const ON_Curve* seg = SegmentCurve(i);
00487 if(seg)
00488 dup_crv->Append( seg->DuplicateCurve() );
00489 }
00490 if( cnt == dup_crv->Count() )
00491 dup_crv->SetParameterization( m_t);
00492 return dup_crv;
00493 }
00494
00495
00496 ON_Interval ON_PolyCurve::Domain() const
00497 {
00498 ON_Interval d;
00499 const int count = Count();
00500 if ( count > 0 && count+1 == m_t.Count() && m_t[0] < m_t[count] ) {
00501 d.Set(m_t[0],m_t[count]);
00502 }
00503 return d;
00504 }
00505
00506 ON_BOOL32 ON_PolyCurve::SetDomain( double t0, double t1 )
00507 {
00508 ON_Interval d0 = Domain();
00509 ON_Interval d1(t0,t1);
00510 ON_BOOL32 rc = d1.IsIncreasing();
00511 if ( rc && d0 != d1 )
00512 {
00513 int i, count = m_t.Count();
00514 double s;
00515 for ( i = 0; i < count; i++ )
00516 {
00517 s = d0.NormalizedParameterAt( m_t[i] );
00518 m_t[i] = d1.ParameterAt( s );
00519 }
00520 DestroyRuntimeCache();
00521 }
00522 return rc;
00523 }
00524
00525
00526 bool ON_PolyCurve::ChangeDimension( int desired_dimension )
00527 {
00528 int i, count = m_segment.Count();
00529 bool rc = (count>0);
00530 for ( i = 0; i < count; i++ )
00531 {
00532 ON_Curve* curve = m_segment[i];
00533 if ( 0 != curve )
00534 {
00535 if ( !curve->ChangeDimension(desired_dimension) )
00536 rc = false;
00537 }
00538 else
00539 rc = false;
00540 }
00541 return rc;
00542 }
00543
00544 bool ON_PolyCurve::SetParameterization( const double* t )
00545 {
00546 bool rc = false;
00547 int i, count = m_segment.Count()+1;
00548 if ( count >= 2 && 0 != t && ON_UNSET_VALUE != t[0] )
00549 {
00550 for ( i = 1; i < count; i++ )
00551 {
00552 if ( t[i] == ON_UNSET_VALUE )
00553 break;
00554 if ( t[i-1] >= t[i] )
00555 break;
00556 }
00557 if ( i == count )
00558 {
00559 m_t.Reserve(count);
00560 m_t.SetCount(0);
00561 m_t.Append( count, t );
00562 rc = true;
00563 }
00564 }
00565 return rc;
00566 }
00567
00568 ON_BOOL32 ON_PolyCurve::ChangeClosedCurveSeam( double t )
00569 {
00570 ON_BOOL32 rc = IsClosed();
00571 if ( rc )
00572 {
00573 DestroyRuntimeCache();
00574 rc = false;
00575 const int old_count = Count();
00576 const ON_Interval old_dom = Domain();
00577 ON_Curve* scrv = 0;
00578 if ( old_count == 1 )
00579 {
00580 scrv = SegmentCurve(0);
00581 if ( scrv )
00582 {
00583 ON_Interval sdom = scrv->Domain();
00584 double s = ( old_dom == sdom )
00585 ? t
00586 : sdom.ParameterAt( old_dom.NormalizedParameterAt(t) );
00587 rc = scrv->ChangeClosedCurveSeam(s);
00588 if ( rc )
00589 SetDomain( t, t + old_dom.Length() );
00590 }
00591 }
00592 else
00593 {
00594 double k = t;
00595 if ( !old_dom.Includes(t) )
00596 {
00597 double s = old_dom.NormalizedParameterAt(t);
00598 s = fmod(s,1.0);
00599 if ( s < 0.0 )
00600 s += 1.0;
00601 k = old_dom.ParameterAt(s);
00602 }
00603 if ( old_dom.Includes(k,true) )
00604 {
00605 int segment_index = ON_NurbsSpanIndex(2,old_count+1,m_t.Array(),k,0,0);
00606 scrv = m_segment[segment_index];
00607 if ( k < m_t[segment_index] )
00608 return false;
00609 if ( k >= m_t[segment_index+1] )
00610 return false;
00611 int new_count = (k==m_t[segment_index]) ? old_count : old_count+1;
00612 ON_Curve* sleft = 0;
00613 ON_Curve* sright = 0;
00614 if ( new_count > old_count )
00615 {
00616 ON_Interval subdom(m_t[segment_index], m_t[segment_index+1]);
00617 double nt = subdom.NormalizedParameterAt(k);
00618 ON_Interval Segdom = scrv->Domain();
00619 double segt = Segdom.ParameterAt(nt);
00620 rc = scrv->Split( segt, sleft, sright );
00621
00622
00623
00624 if(!rc){
00625 if(nt>.5){
00626 segment_index++;
00627 if(segment_index<old_count)
00628 scrv = m_segment[segment_index];
00629 else
00630 scrv = NULL;
00631 }
00632 new_count--;
00633 }
00634 }
00635 if(new_count==old_count)
00636 {
00637 sright = scrv;
00638 scrv = 0;
00639 rc = true;
00640 }
00641 if ( rc && segment_index<old_count)
00642 {
00643 m_segment[segment_index] = 0;
00644 ON_SimpleArray<ON_Curve*> new_c(new_count);
00645 ON_SimpleArray<double> new_t(new_count+1);
00646 new_c.Append(sright);
00647 new_t.Append(k);
00648 new_c.Append( old_count-segment_index-1, m_segment.Array()+segment_index+1);
00649 new_t.Append( old_count-segment_index-1, m_t.Array()+segment_index+1);
00650 int j = new_t.Count();
00651 new_c.Append( segment_index, m_segment.Array() );
00652 new_t.Append( segment_index, m_t.Array() );
00653 if ( sleft )
00654 {
00655 new_c.Append(sleft);
00656 new_t.Append(m_t[segment_index]);
00657 }
00658 new_t.Append(k);
00659 double d = old_dom.Length();
00660 while (j < new_t.Count() )
00661 {
00662 new_t[j] += d;
00663 j++;
00664 }
00665
00666
00667
00668 memset( m_segment.Array(), 0, m_segment.Capacity()*sizeof( *m_segment.Array() ) );
00669 m_segment.SetCount(0);
00670 m_segment.Append( new_c.Count(), new_c.Array() );
00671 m_t = new_t;
00672 if ( scrv )
00673 {
00674 delete scrv;
00675 scrv = 0;
00676 }
00677 }
00678 }
00679 else
00680 {
00681
00682 rc = true;
00683 }
00684 if ( rc )
00685 SetDomain( t, t + old_dom.Length() );
00686 }
00687 }
00688 return rc;
00689 }
00690
00691 int ON_PolyCurve::SpanCount() const
00692 {
00693 int span_count = 0;
00694 const int segment_count = Count();
00695 int i, j;
00696 for ( i = 0; i < segment_count; i++ ) {
00697 if ( !m_segment[i] )
00698 return false;
00699 j = m_segment[i]->SpanCount();
00700 if ( j == 0 )
00701 return 0;
00702 span_count += j;
00703 }
00704 return span_count;
00705 }
00706
00707 ON_BOOL32 ON_PolyCurve::GetSpanVector(
00708 double* s
00709 ) const
00710 {
00711 ON_Interval sp;
00712 double t;
00713 const int segment_count = Count();
00714 int i, j, k;
00715 for ( i = 0; i < segment_count; i++ ) {
00716 if ( !m_segment[i] )
00717 return false;
00718 j = m_segment[i]->SpanCount();
00719 if ( j == 0 )
00720 return 0;
00721 if ( !m_segment[i]->GetSpanVector( s ) )
00722 return false;
00723 sp.Set( m_t[i], m_t[i+1] );
00724 ON_Interval segloc(s[0],s[j]);
00725 if ( sp.Min() != s[0] || sp.Max() != s[j] ) {
00726 for ( k = 0; k <= j; k++ ) {
00727 t = segloc.NormalizedParameterAt(s[k]);
00728 s[k] = sp.ParameterAt(t);
00729 }
00730 }
00731
00732 s += j;
00733 }
00734 return true;
00735 }
00736
00737 int ON_PolyCurve::Degree() const
00738 {
00739 const int segment_count = Count();
00740 int span_degree = 0;
00741 int segment_index, d;
00742 for ( segment_index = 0; segment_index < segment_count; segment_index++ ) {
00743 if ( !m_segment[segment_index] )
00744 return false;
00745 d = m_segment[segment_index]->Degree();
00746 if ( d <= 0 )
00747 return 0;
00748 if ( d > span_degree )
00749 span_degree = d;
00750 }
00751 return span_degree;
00752 }
00753
00754
00755 ON_BOOL32
00756 ON_PolyCurve::IsLinear(
00757 double tolerance
00758 ) const
00759 {
00760 ON_BOOL32 rc = false;
00761 int i, count = Count();
00762 if ( count==1)
00763 return m_segment[0]->IsLinear(tolerance);
00764
00765 else if ( count > 1 ) {
00766 rc = true;
00767 for ( i = 0; rc && i < count; i++ ) {
00768 if ( !m_segment[i] )
00769 rc = false;
00770 else
00771 rc = m_segment[i]->IsLinear(tolerance);
00772
00773 }
00774 if (rc)
00775 rc = ON_Curve::IsLinear(tolerance);
00776 }
00777 return rc;
00778 }
00779
00780 int ON_PolyCurve::IsPolyline(
00781 ON_SimpleArray<ON_3dPoint>* pline_points,
00782 ON_SimpleArray<double>* pline_t
00783 ) const
00784 {
00785 int i, seg_i, seg_rc;
00786 ON_Interval sdom, cdom;
00787 int rc = 0;
00788 if ( pline_points )
00789 pline_points->SetCount(0);
00790 if ( pline_t )
00791 pline_t->SetCount(0);
00792 const int seg_count = Count();
00793 if ( seg_count == 1 )
00794 {
00795 if ( m_segment[0] )
00796 rc = m_segment[0]->IsPolyline(pline_points,pline_t);
00797 if (pline_t && rc > 0)
00798 {
00799 sdom.Set(m_t[0],m_t[1]);
00800 cdom = m_segment[0]->Domain();
00801 if ( sdom != cdom )
00802 {
00803 for ( i = 0; i < pline_t->Count(); i++ )
00804 (*pline_t)[i] = sdom.ParameterAt(cdom.NormalizedParameterAt((*pline_t)[i]));
00805 }
00806 }
00807 }
00808 else if (seg_count > 1 )
00809 {
00810 ON_SimpleArray<ON_3dPoint> seg_points;
00811 ON_SimpleArray<double> seg_t;
00812 for ( seg_i = 0; seg_i < seg_count; seg_i++ )
00813 {
00814 seg_points.SetCount(0);
00815 seg_t.SetCount(0);
00816 seg_rc = m_segment[seg_i]->IsPolyline(pline_points?&seg_points:0,pline_t?&seg_t:0);
00817 if ( seg_rc < 2 )
00818 {
00819 if ( pline_points )
00820 pline_points->SetCount(0);
00821 if ( pline_t )
00822 pline_t->SetCount(0);
00823 rc = 0;
00824 break;
00825 }
00826 rc += seg_rc;
00827 if ( seg_i )
00828 rc--;
00829 if ( pline_t )
00830 {
00831 sdom.Set( m_t[seg_i], m_t[seg_i+1] );
00832 cdom = m_segment[seg_i]->Domain();
00833 if ( sdom != cdom )
00834 {
00835 for ( i = 0; i < seg_t.Count(); i++ )
00836 seg_t[i] = sdom.ParameterAt(cdom.NormalizedParameterAt(seg_t[i]));
00837 }
00838 if ( pline_t->Count() > 0 )
00839 pline_t->Remove();
00840 pline_t->Append( seg_t.Count(), seg_t.Array() );
00841 }
00842 if ( pline_points )
00843 {
00844 if ( pline_points->Count() > 0 )
00845 pline_points->Remove();
00846 pline_points->Append( seg_points.Count(), seg_points.Array() );
00847 }
00848 }
00849 if(IsClosed() && pline_points && pline_points->Count() > 3)
00850 {
00851
00852 *pline_points->Last() = *pline_points->First();
00853 }
00854 }
00855 return rc;
00856 }
00857
00858
00859 ON_BOOL32
00860 ON_PolyCurve::IsArc(
00861 const ON_Plane* plane,
00862 ON_Arc* arc,
00863
00864 double tolerance
00865 ) const
00866 {
00867 bool rc = false;
00868 if ( 1 == m_segment.Count() && 0 != m_segment[0] )
00869 {
00870 rc = m_segment[0]->IsArc( plane, arc, tolerance )?true:false;
00871 }
00872 return rc;
00873 }
00874
00875
00876 static bool GetTestPlane( const ON_Curve& curve, ON_Plane& plane )
00877 {
00878 int i, j;
00879 ON_3dPoint P, Q, R;
00880 ON_3dVector X;
00881 ON_Interval d = curve.Domain();
00882 if ( !curve.Ev1Der( d[0], P, X ) )
00883 {
00884 return false;
00885 }
00886 if ( !X.Unitize() )
00887 {
00888 return false;
00889 }
00890
00891 Q = P+X;
00892 for ( i = 2; i <= 16; i += 2 )
00893 {
00894 for ( j = 1; j < i; j += 2 )
00895 {
00896 R = curve.PointAt( d.ParameterAt( ((double)j)/((double)i) ) );
00897 if ( plane.CreateFromFrame( P, X, R-P ) )
00898 return true;
00899 }
00900 }
00901 return false;
00902 }
00903
00904
00905 ON_BOOL32
00906 ON_PolyCurve::IsPlanar(
00907 ON_Plane* plane,
00908
00909 double tolerance
00910 ) const
00911 {
00912 if ( Dimension() == 2 )
00913 {
00914 return ON_Curve::IsPlanar(plane,tolerance);
00915 }
00916
00917 ON_BOOL32 rc = false;
00918 ON_Plane test_plane;
00919 const int count = Count();
00920 const ON_Curve* crv = FirstSegmentCurve();
00921 if ( count == 1 && crv )
00922 rc = crv->IsPlanar( plane, tolerance );
00923 else if ( count > 1 )
00924 {
00925 if ( IsLinear(tolerance) )
00926 {
00927 if ( plane )
00928 {
00929 ON_Line line(PointAtStart(), PointAtEnd() );
00930 if ( !line.InPlane( *plane, tolerance ) )
00931 line.InPlane( *plane, 0.0 );
00932 }
00933 return true;
00934 }
00935 if ( !GetTestPlane( *this, test_plane ) )
00936 {
00937
00938
00939
00940 ON_3dPoint P, Q;
00941 ON_3dVector X;
00942 if (!Ev1Der(m_t[0],P,X))
00943 return false;
00944
00945 if ( !X.Unitize() )
00946 {
00947 X = PointAt(Domain().ParameterAt(0.5)) - P;
00948 if ( !X.Unitize() )
00949 return false;
00950 }
00951
00952 int i;
00953 for ( i = 1; i < count; i++ )
00954 {
00955 if ( m_segment[i] )
00956 {
00957 Q = m_segment[i]->PointAt(m_segment[i]->Domain().ParameterAt(0.5));
00958 if ( test_plane.CreateFromFrame(P,X,Q-P) )
00959 break;
00960 }
00961 }
00962 if ( i >= count )
00963 return false;
00964 }
00965 rc = IsInPlane( test_plane, tolerance );
00966 if (rc && plane)
00967 *plane = test_plane;
00968 }
00969 return rc;
00970 }
00971
00972 ON_BOOL32
00973 ON_PolyCurve::IsInPlane(
00974 const ON_Plane& plane,
00975 double tolerance
00976 ) const
00977 {
00978 ON_BOOL32 rc = false;
00979 int i, count = Count();
00980 for ( i = 0; i < count; i++ )
00981 {
00982 if ( !m_segment[i] )
00983 return false;
00984 rc = m_segment[i]->IsInPlane( plane, tolerance );
00985 if ( !rc )
00986 break;
00987 }
00988 return rc;
00989 }
00990
00991 ON_BOOL32
00992 ON_PolyCurve::IsClosed() const
00993 {
00994 ON_BOOL32 bIsClosed = false;
00995 const int count = Count();
00996 if ( count == 1 ) {
00997
00998 const ON_Curve* c = FirstSegmentCurve();
00999 if ( c )
01000 bIsClosed = c->IsClosed();
01001 }
01002 else if ( count > 1 )
01003 {
01004
01005
01006
01007
01008 bIsClosed = ( ON_Curve::IsClosed() && FindNextGap(0) <= 0 );
01009 }
01010 return bIsClosed;
01011 }
01012
01013 static bool GetLineIsoCoordinates( const ON_Line& line, const ON_3dPoint P, ON_3dPoint& C )
01014 {
01015 C.x = (line.from.x == line.to.x) ? P.x : ON_UNSET_VALUE;
01016 C.y = (line.from.y == line.to.y) ? P.y : ON_UNSET_VALUE;
01017 C.z = (line.from.z == line.to.z) ? P.z : ON_UNSET_VALUE;
01018 return ( ON_3dPoint::UnsetPoint != C );
01019 }
01020
01021 static void LineLineTieBreaker( const ON_Line& line0, const ON_Line& line1,
01022 ON_3dPoint& Q0, ON_3dPoint& Q1 )
01023 {
01024 double line0_length = line0.Length();
01025 double line1_length = line1.Length();
01026
01027 ON_3dPoint C0, C1;
01028 bool bHaveIsoCoords0 = GetLineIsoCoordinates(line0,Q0,C0);
01029 bool bHaveIsoCoords1 = GetLineIsoCoordinates(line1,Q1,C1);
01030 if ( bHaveIsoCoords0 || bHaveIsoCoords1 )
01031 {
01032 for ( int i = 0; i < 3; i++ )
01033 {
01034 double c0 = C0[i];
01035 double c1 = C1[i];
01036 if ( ON_UNSET_VALUE == c0 && ON_UNSET_VALUE == c1 )
01037 continue;
01038 double c = ON_UNSET_VALUE;
01039 if ( c0 == c1 )
01040 c = c0;
01041 else if ( ON_UNSET_VALUE == c0 )
01042 c = c1;
01043 else if ( ON_UNSET_VALUE == c1 )
01044 c = c0;
01045 else if ( line0_length > line1_length )
01046 c = c0;
01047 else
01048 c = c1;
01049 if ( ON_UNSET_VALUE != c && ON_IsValid(c) )
01050 {
01051 Q0[i] = c;
01052 Q1[i] = c;
01053 }
01054 }
01055 }
01056 }
01057
01058 static void SetLineIsoCoords( const ON_Line& line, const ON_3dPoint& P, ON_3dPoint& Q )
01059 {
01060 ON_3dPoint C;
01061 if ( GetLineIsoCoordinates(line,P,C) )
01062 {
01063 if ( ON_UNSET_VALUE != C.x && ON_IsValid(C.x) )
01064 Q.x = P.x;
01065 if ( ON_UNSET_VALUE != C.y && ON_IsValid(C.y) )
01066 Q.y = P.y;
01067 if ( ON_UNSET_VALUE != C.z && ON_IsValid(C.z) )
01068 Q.z = P.z;
01069 }
01070 }
01071
01072 static ON_NurbsCurve* ChangeArcEnd( const ON_ArcCurve* arc, ON_3dPoint P, ON_3dPoint Q, int end_index )
01073 {
01074 if ( P == Q )
01075 return 0;
01076
01077 ON_NurbsCurve* nc = arc->NurbsCurve();
01078 if ( 0 == nc || nc->m_cv_count < 3 )
01079 return 0;
01080
01081 int cv0_dex, cv1_dex;
01082 if ( 1 == end_index )
01083 {
01084 cv0_dex = nc->m_cv_count-1;
01085 cv1_dex = cv0_dex - 1;
01086 }
01087 else
01088 {
01089 cv0_dex = 0;
01090 cv1_dex = cv0_dex + 1;
01091 }
01092
01093 if ( !nc->SetCV(cv0_dex,Q) )
01094 {
01095 delete nc;
01096 return 0;
01097 }
01098
01099 ON_4dPoint R;
01100 if ( !nc->GetCV(cv1_dex,R) )
01101 {
01102 delete nc;
01103 return 0;
01104 }
01105
01106 R.x += (Q.x-P.x)*R.w;
01107 R.y += (Q.y-P.y)*R.w;
01108 R.z += (Q.z-P.z)*R.w;
01109 nc->SetCV(cv1_dex,R);
01110
01111 return nc;
01112 }
01113
01114 bool ON_PolyCurve::CloseGap( int gap_index, int ends_to_modify )
01115 {
01116 const int count = m_segment.Count();
01117
01118 if ( gap_index <= 0 || gap_index >= count )
01119 {
01120 ON_ERROR("Invalid gap_index parameter.");
01121 return 0;
01122 }
01123
01124 ON_Curve* c0 = m_segment[gap_index-1];
01125 ON_Curve* c1 = m_segment[gap_index];
01126 if ( 0 == c0 || 0 == c1 )
01127 {
01128 ON_ERROR("Null curve segments.");
01129 return false;
01130 }
01131
01132 const ON_3dPoint P0 = c0->PointAtEnd();
01133 const ON_3dPoint P1 = c1->PointAtStart();
01134 if ( P0 == P1 )
01135 return false;
01136
01137 ON_3dPoint Q0(P0);
01138 ON_3dPoint Q1(P1);
01139
01140 const ON_ArcCurve* arc0 = ON_ArcCurve::Cast(c0);
01141 const ON_ArcCurve* arc1 = ON_ArcCurve::Cast(c1);
01142
01143 if ( 0 != arc0 && 0 != arc1 )
01144 {
01145 if ( arc1->m_arc.Length() < arc0->m_arc.Length() )
01146 Q1 = P0;
01147 else
01148 Q0 = P1;
01149 }
01150 else if ( 0 != arc0 && 0 == arc1 )
01151 {
01152 Q1 = P0;
01153 }
01154 else if ( 0 != arc1 && 0 == arc0 )
01155 {
01156 Q0 = P1;
01157 }
01158 else
01159 {
01160 ON_Line line0, line1;
01161 double min_line_length = 0.0;
01162 double is_linear_tolerance = 0.0;
01163 bool bLine0 = (0 == arc0)
01164 ? c0->LastSpanIsLinear(min_line_length,is_linear_tolerance,&line0)
01165 : false;
01166 bool bLine1 = (0 == arc0)
01167 ? c1->FirstSpanIsLinear(min_line_length,is_linear_tolerance,&line1)
01168 : false;
01169 if ( bLine0 && bLine1 )
01170 LineLineTieBreaker(line0,line1,Q0,Q1);
01171 else if ( bLine0 )
01172 SetLineIsoCoords(line0,P0,Q1);
01173 else if ( bLine1 )
01174 SetLineIsoCoords(line1,P1,Q0);
01175 }
01176
01177 if ( Q0.x != Q1.x )
01178 Q0.x = Q1.x = 0.5*(P0.x + P1.x);
01179 if ( Q0.y != Q1.y )
01180 Q0.y = Q1.y = 0.5*(P0.y + P1.y);
01181 if ( Q0.z != Q1.z )
01182 Q0.z = Q1.z = 0.5*(P0.z + P1.z);
01183
01184 if ( Q0 != P0 )
01185 {
01186 if ( 0 != arc0 )
01187 {
01188 ON_NurbsCurve* nc0 = ChangeArcEnd( arc0, P0, Q0 , 1 );
01189 if ( nc0 )
01190 {
01191 delete m_segment[gap_index-1];
01192 m_segment[gap_index-1] = nc0;
01193 c0 = nc0;
01194 arc0 = 0;
01195 }
01196 }
01197 else
01198 {
01199 c0->SetEndPoint(Q0);
01200 }
01201 }
01202
01203 if ( Q1 != P1 )
01204 {
01205 if ( 0 != arc1 )
01206 {
01207 ON_NurbsCurve* nc1 = ChangeArcEnd( arc1, P1, Q1, 0 );
01208 if ( nc1 )
01209 {
01210 delete m_segment[gap_index];
01211 m_segment[gap_index] = nc1;
01212 c0 = nc1;
01213 arc1 = 0;
01214 }
01215 }
01216 else
01217 {
01218 c1->SetStartPoint(Q1);
01219 }
01220 }
01221
01222 return HasGapAt(gap_index-1) ? false : true;
01223 }
01224
01225 int ON_PolyCurve::CloseGaps()
01226 {
01227 int rc = 0;
01228 int segment_index0 = 0;
01229 int gap_index = 0;
01230
01231 for(;;)
01232 {
01233 gap_index = FindNextGap(segment_index0);
01234 if ( gap_index <= segment_index0 || gap_index >= m_segment.Count() )
01235 break;
01236 if ( CloseGap(gap_index,0) )
01237 rc++;
01238 segment_index0 = gap_index;
01239 }
01240
01241 return rc;
01242 }
01243
01244 int ON_PolyCurve::HasGap() const
01245 {
01246 return FindNextGap(0);
01247 }
01248
01249
01250 bool ON_PolyCurve::HasGapAt(int segment_index) const
01251 {
01252 const int count = m_segment.Count();
01253
01254 if ( segment_index < 0 || segment_index >= count-1 )
01255 return 0;
01256
01257 const ON_Curve* c0 = m_segment[segment_index];
01258 const ON_Curve* c1 = m_segment[segment_index+1];
01259 if ( 0 == c0 || 0 == c1 )
01260 return false;
01261
01262 ON_3dPoint P0 = c0->PointAtEnd();
01263 ON_3dPoint P1 = c1->PointAtStart();
01264
01265
01266 if ( false == ON_PointsAreCoincident( 3, false, &P0.x, &P1.x ) )
01267 {
01268
01269 const ON_ArcCurve* arc0 = ON_ArcCurve::Cast(c0);
01270 const ON_ArcCurve* arc1 = ON_ArcCurve::Cast(c1);
01271 if ( 0 == arc0 && 0 == arc1 )
01272 return true;
01273
01274 double tol = ON_ZERO_TOLERANCE;
01275 const double tol0 = arc0 ? ( arc0->m_arc.radius*arc0->m_arc.AngleRadians()*1.0e-10 ) : 0.0;
01276 const double tol1 = arc1 ? ( arc1->m_arc.radius*arc1->m_arc.AngleRadians()*1.0e-10 ) : 0.0;
01277 if ( tol < tol0 )
01278 tol = tol0;
01279 if ( tol < tol1 )
01280 tol = tol1;
01281 const double d = P0.DistanceTo(P1);
01282 if ( d > tol )
01283 {
01284 return true;
01285 }
01286 }
01287
01288 return false;
01289 }
01290
01291
01292 int ON_PolyCurve::FindNextGap(int segment_index0) const
01293 {
01294 if ( segment_index0 >= 0 )
01295 {
01296 const int count = m_segment.Count();
01297 for (int gap_index = segment_index0+1; gap_index < count; gap_index++ )
01298 {
01299 if ( HasGapAt(gap_index-1) )
01300 return gap_index;
01301 }
01302 }
01303 return 0;
01304 }
01305
01306
01307 ON_BOOL32
01308 ON_PolyCurve::IsPeriodic() const
01309 {
01310 ON_BOOL32 bIsPeriodic = false;
01311 if ( Count() == 1 ) {
01312 const ON_Curve* c = FirstSegmentCurve();
01313 if ( c )
01314 bIsPeriodic = c->IsPeriodic();
01315 }
01316 return bIsPeriodic;
01317 }
01318
01319 bool ON_PolyCurve::GetNextDiscontinuity(
01320 ON::continuity c,
01321 double t0,
01322 double t1,
01323 double* t,
01324 int* hint,
01325 int* dtype,
01326 double cos_angle_tolerance,
01327 double curvature_tolerance
01328 ) const
01329 {
01330 ON_3dPoint Pm, Pp;
01331 ON_3dVector D1m, D1p, D2m, D2p, Tm, Tp, Km, Kp;
01332 double s0, s1, s;
01333 bool rc = false;
01334 ON_Interval sdom, cdom;
01335 const int count = Count();
01336 int segment_hint=0, curve_hint=0;
01337 if ( dtype )
01338 *dtype = 0;
01339 if ( count > 0 && t0 != t1 )
01340 {
01341
01342
01343
01344
01345 ON::continuity input_c = c;
01346 c = ON::ParametricContinuity(c);
01347
01348 segment_hint = (hint) ? (*hint & 0x3FFF) : 0;
01349 int segment_index = ON_NurbsSpanIndex(2,count+1,m_t,t0,(t0>t1)?-1:1,segment_hint);
01350 curve_hint = ( hint && segment_hint == segment_index ) ? ((*hint)>>14) : 0;
01351
01352
01353 {
01354
01355
01356
01357
01358
01359
01360 double segtol = (fabs(m_t[segment_index]) + fabs(m_t[segment_index+1]) + fabs(m_t[segment_index+1]-m_t[segment_index]))*ON_SQRT_EPSILON;
01361 if ( m_t[segment_index]+segtol < m_t[segment_index+1]-segtol )
01362 {
01363 if ( t0 < t1 )
01364 {
01365 if ( t0 < m_t[segment_index+1] && t1 > m_t[segment_index+1] && fabs(t0-m_t[segment_index+1]) <= segtol && segment_index+1 < count )
01366 {
01367 t0 = m_t[segment_index+1];
01368 segment_index = ON_NurbsSpanIndex(2,count+1,m_t,t0,1,segment_hint);
01369 }
01370 }
01371 else
01372 {
01373 if ( t0 > m_t[segment_index] && t1 < m_t[segment_index] && fabs(t0-m_t[segment_index]) <= segtol && segment_index > 0 )
01374 {
01375 t0 = m_t[segment_index];
01376 }
01377 }
01378 }
01379 }
01380
01381 double tmin, tmax;
01382 int segment_index_delta;
01383 if (t0 > t1)
01384 {
01385 segment_index_delta = -1;
01386 tmin = t1;
01387 tmax = t0;
01388 }
01389 else
01390 {
01391 segment_index_delta = 1;
01392 tmin = t0;
01393 tmax = t1;
01394 }
01395
01396 const ON_Curve* crv;
01397 for ( ;
01398 segment_index >= 0
01399 && segment_index < count
01400 && tmin < m_t[segment_index+1] && m_t[segment_index] < tmax;
01401 segment_index += segment_index_delta )
01402 {
01403 crv = m_segment[segment_index];
01404 if ( !crv )
01405 break;
01406 cdom = crv->Domain();
01407 sdom.Set( m_t[segment_index], m_t[segment_index+1] );
01408 if ( sdom == cdom )
01409 {
01410 s0 = t0;
01411 s1 = t1;
01412 }
01413 else
01414 {
01415 s0 = cdom.ParameterAt( sdom.NormalizedParameterAt(t0) );
01416 s1 = cdom.ParameterAt( sdom.NormalizedParameterAt(t1) );
01417 }
01418 rc = crv->GetNextDiscontinuity( c, s0, s1, &s, &curve_hint, dtype, cos_angle_tolerance, curvature_tolerance );
01419 if ( rc )
01420 {
01421 double kink_t;
01422 if ( sdom == cdom )
01423 {
01424 kink_t = s;
01425 }
01426 else
01427 {
01428 kink_t = sdom.ParameterAt( cdom.NormalizedParameterAt(s) );
01429 double t_tol = (fabs(t0)+fabs(t1)+fabs(t0-t1))*ON_ZERO_TOLERANCE;
01430 if ( kink_t <= tmin+t_tol || kink_t >= tmax-t_tol)
01431 {
01432
01433
01434
01435
01436
01437
01438
01439
01440 double e = fabs(sdom.Length()/cdom.Length());
01441 if ( e < 1.0 ) e = 1.0; else if (e > 1000.0) e = 1000.0;
01442 double s_tol = (fabs(s0)+fabs(s1)+fabs(s0-s1))*ON_ZERO_TOLERANCE*e;
01443 if ( kink_t <= tmin+t_tol )
01444 {
01445 if( s0>s1 )
01446 s1 = s1 + s_tol;
01447 else
01448 s0 = s0 + s_tol;
01449 }
01450 if ( kink_t >= tmax-t_tol )
01451 {
01452 if ( s0>s1 )
01453 s0 = s0 - s_tol;
01454 else
01455 s1 = s1 - s_tol;
01456 }
01457 rc = crv->GetNextDiscontinuity( c, s0, s1, &s, &curve_hint, dtype, cos_angle_tolerance, curvature_tolerance );
01458 if (rc)
01459 {
01460 kink_t = sdom.ParameterAt( cdom.NormalizedParameterAt(s) );
01461 if ( kink_t <= tmin || kink_t >= tmax )
01462 rc = false;
01463 }
01464 }
01465 }
01466
01467 if (rc)
01468 {
01469 if ( t )
01470 {
01471 *t = kink_t;
01472 if ( hint )
01473 {
01474 *hint = segment_index | (curve_hint<<14);
01475 }
01476 }
01477 break;
01478 }
01479 }
01480
01481
01482
01483 int next_segment_index = segment_index+segment_index_delta;
01484 if ( next_segment_index < 0 || next_segment_index >= count )
01485 {
01486
01487 break;
01488 }
01489 const ON_Curve* crv1 = m_segment[next_segment_index];
01490 if ( !crv1 )
01491 break;
01492
01493 if ( t0 > t1 )
01494 {
01495 if ( sdom[0] <= t1 )
01496 {
01497
01498
01499 break;
01500 }
01501 }
01502 else
01503 {
01504 if ( t1 <= sdom[1] )
01505 {
01506
01507
01508 break;
01509 }
01510 }
01511
01512 double crv0_t, crv1_t;
01513 int crv0_side;
01514 if ( t0 > t1 )
01515 {
01516
01517 crv0_t = cdom[0];
01518 crv1_t = crv1->Domain()[1];
01519 crv0_side = 1;
01520 }
01521 else
01522 {
01523
01524 crv0_t = cdom[1];
01525 crv1_t = crv1->Domain()[0];
01526 crv0_side = -1;
01527 }
01528
01529 switch( c )
01530 {
01531 case ON::C1_continuous:
01532 case ON::G1_continuous:
01533 crv->Ev1Der( crv0_t, Pm, D1m, crv0_side );
01534 crv1->Ev1Der( crv1_t, Pp, D1p, -crv0_side );
01535 if ( c == ON::C1_continuous )
01536 {
01537 if ( !(D1m-D1p).IsTiny(D1m.MaximumCoordinate()*ON_SQRT_EPSILON) )
01538 rc = true;
01539 }
01540 else
01541 {
01542 Tm = D1m;
01543 Tp = D1p;
01544 Tm.Unitize();
01545 Tp.Unitize();
01546 if ( Tm*Tp < cos_angle_tolerance )
01547 rc = true;
01548 }
01549 if ( rc && dtype )
01550 *dtype = 1;
01551 break;
01552
01553 case ON::C2_continuous:
01554 case ON::G2_continuous:
01555 case ON::Gsmooth_continuous:
01556 crv->Ev2Der( crv0_t, Pm, D1m, D2m, crv0_side );
01557 crv1->Ev2Der( crv1_t, Pp, D1p, D2p, -crv0_side );
01558 if ( c == ON::C2_continuous )
01559 {
01560 if ( !(D1m-D1p).IsTiny(D1m.MaximumCoordinate()*ON_SQRT_EPSILON) )
01561 {
01562 rc = true;
01563 if ( dtype )
01564 *dtype = 1;
01565 }
01566 else if ( !(D2m-D2p).IsTiny(D2m.MaximumCoordinate()*ON_SQRT_EPSILON) )
01567 {
01568 rc = true;
01569 if ( dtype )
01570 *dtype = 2;
01571 }
01572 }
01573 else
01574 {
01575 ON_EvCurvature( D1m, D2m, Tm, Km );
01576 ON_EvCurvature( D1p, D2p, Tp, Kp );
01577 if ( Tm*Tp < cos_angle_tolerance )
01578 {
01579 rc = true;
01580 if ( dtype )
01581 *dtype = 1;
01582 }
01583 else
01584 {
01585 bool bIsCurvatureContinuous = ( ON::Gsmooth_continuous == c )
01586 ? ON_IsGsmoothCurvatureContinuous(Km, Kp, cos_angle_tolerance, curvature_tolerance)
01587 : ON_IsG2CurvatureContinuous(Km, Kp, cos_angle_tolerance, curvature_tolerance);
01588 if ( !bIsCurvatureContinuous )
01589 {
01590
01591
01592
01593 rc = true;
01594 if ( dtype )
01595 *dtype = 2;
01596 }
01597 else if ( ON::Gsmooth_continuous == c )
01598 {
01599 const double is_linear_tolerance = 1.0e-8;
01600 const double is_linear_min_length = 1.0e-8;
01601 const ON_Curve* seg0;
01602 const ON_Curve* seg1;
01603 if (crv0_side<0)
01604 {
01605 seg0 = crv;
01606 seg1 = crv1;
01607 }
01608 else
01609 {
01610 seg0 = crv1;
01611 seg1 = crv;
01612 }
01613 bool b0 = seg0->LastSpanIsLinear(is_linear_min_length,is_linear_tolerance);
01614 bool b1 = seg1->FirstSpanIsLinear(is_linear_min_length,is_linear_tolerance);
01615 if ( b0 != b1 )
01616 {
01617 rc = true;
01618 if ( dtype )
01619 *dtype = 3;
01620 }
01621 }
01622 }
01623 }
01624 break;
01625 default:
01626
01627 break;
01628 }
01629 if (rc)
01630 {
01631 int tindex = (t0>t1)?segment_index:(segment_index+1);
01632 if ( t )
01633 *t = m_t[tindex];
01634 if ( hint )
01635 {
01636 *hint = tindex;
01637 }
01638 break;
01639 }
01640 }
01641
01642 if ( !rc && input_c != c )
01643 {
01644
01645
01646 rc = ON_Curve::GetNextDiscontinuity( input_c,
01647 t0, t1, t, NULL,
01648 dtype,
01649 cos_angle_tolerance, curvature_tolerance );
01650 }
01651 }
01652 return rc;
01653 }
01654
01655 bool ON_PolyCurve::IsContinuous(
01656 ON::continuity desired_continuity,
01657 double t,
01658 int* hint,
01659 double point_tolerance,
01660 double d1_tolerance,
01661 double d2_tolerance,
01662 double cos_angle_tolerance,
01663 double curvature_tolerance
01664 ) const
01665 {
01666 bool rc = true;
01667 const int count = Count();
01668 if ( count > 0 )
01669 {
01670 if ( t <= m_t[0] || t >= m_t[count] )
01671 {
01672
01673
01674 rc = ON_Curve::IsContinuous(
01675 desired_continuity, t, hint,
01676 point_tolerance,
01677 d1_tolerance, d2_tolerance,
01678 cos_angle_tolerance,
01679 curvature_tolerance );
01680 return rc;
01681 }
01682
01683
01684 desired_continuity = ON::ParametricContinuity(desired_continuity);
01685
01686
01687 int segment_hint = 0, curve_hint = 0;
01688 if ( hint )
01689 segment_hint = (*hint & 0x3FFF);
01690 int segment_index = ON_NurbsSpanIndex(2,count+1,m_t,t,1,segment_hint);
01691
01692 {
01693
01694
01695
01696
01697
01698
01699 double segtol = (fabs(m_t[segment_index]) + fabs(m_t[segment_index+1]) + fabs(m_t[segment_index+1]-m_t[segment_index]))*ON_SQRT_EPSILON;
01700 if ( m_t[segment_index]+segtol < m_t[segment_index+1]-segtol )
01701 {
01702 if ( fabs(t-m_t[segment_index]) <= segtol && segment_index > 0 )
01703 {
01704 t = m_t[segment_index];
01705 }
01706 else if ( fabs(t-m_t[segment_index+1]) <= segtol && segment_index+1 < count )
01707 {
01708 t = m_t[segment_index+1];
01709 segment_index = ON_NurbsSpanIndex(2,count+1,m_t,t,1,segment_hint);
01710 }
01711 }
01712 }
01713
01714 if ( hint )
01715 {
01716 if ( segment_hint == segment_index )
01717 curve_hint = ((*hint)>>14);
01718 else
01719 {
01720 segment_hint = segment_index;
01721 *hint = segment_hint;
01722 }
01723 }
01724
01725 if ( m_t[segment_index] < t && t < m_t[segment_index+1] )
01726 {
01727
01728 const ON_Curve* segment_curve = SegmentCurve(segment_index);
01729 if ( segment_curve )
01730 {
01731 ON_Interval sdom, cdom;
01732 cdom = segment_curve->Domain();
01733 sdom.Set( m_t[segment_index], m_t[segment_index+1] );
01734 if ( sdom != cdom )
01735 t = cdom.ParameterAt( sdom.NormalizedParameterAt(t) );
01736 rc = segment_curve->IsContinuous( desired_continuity, t, &curve_hint,
01737 point_tolerance, d1_tolerance, d2_tolerance,
01738 cos_angle_tolerance, curvature_tolerance );
01739 if ( hint )
01740 *hint = (segment_index | (curve_hint<<14));
01741 }
01742 }
01743 else if ( count > 0 )
01744 {
01745 if ( segment_index == 0 && t == m_t[0] )
01746 rc = true;
01747 else if ( segment_index == count-1 && t == m_t[count] )
01748 rc = true;
01749 else
01750 {
01751
01752 rc = ON_Curve::IsContinuous( desired_continuity, t, hint,
01753 point_tolerance, d1_tolerance, d2_tolerance,
01754 cos_angle_tolerance, curvature_tolerance );
01755 if ( 0 != rc
01756 && ON::Gsmooth_continuous == desired_continuity
01757 && segment_index >= 0
01758 && segment_index < count
01759 )
01760 {
01761
01762 const int i0 = ( t >= m_t[segment_index] ) ? segment_index-1 : segment_index;
01763 if ( i0 >= 0 && t == m_t[i0+1] )
01764 {
01765 const ON_Curve* seg0 = SegmentCurve(i0);
01766 const ON_Curve* seg1 = SegmentCurve(i0+1);
01767 if ( 0 != seg0 && 0 != seg1 )
01768 {
01769 const double is_linear_tolerance = 1.0e-8;
01770 const double is_linear_min_length = 1.0e-8;
01771 bool b0 = seg0->LastSpanIsLinear(is_linear_min_length,is_linear_tolerance);
01772 bool b1 = seg1->FirstSpanIsLinear(is_linear_min_length,is_linear_tolerance);
01773 if ( b0 != b1 )
01774 rc = false;
01775 }
01776 }
01777 }
01778 }
01779 }
01780 }
01781 return rc;
01782 }
01783
01784 ON_BOOL32
01785 ON_PolyCurve::Reverse()
01786 {
01787 const int count = Count();
01788 int i;
01789 ON_BOOL32 rc = (count>0) ? true : false;
01790 if ( rc ) {
01791 m_segment.Reverse();
01792 m_t.Reverse();
01793 for ( i = 0; i < count; i++ ) {
01794 m_segment[i]->Reverse();
01795 m_t[i] = -m_t[i];
01796 }
01797 m_t[count] = -m_t[count];
01798 }
01799 DestroyCurveTree();
01800 return rc;
01801 }
01802
01803 bool ON_TuneupEvaluationParameter(
01804 int side,
01805 double s0, double s1,
01806 double *s
01807 )
01808 {
01809 double t = *s;
01810 if ( 0 != side && s0 < t && t < s1 )
01811 {
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824 double ds = (s1-s0)*1.0e-10;
01825 if ( side < 0 )
01826 {
01827 if ( t <= s0+ds )
01828 {
01829 *s = s0;
01830 return true;
01831 }
01832 }
01833 else
01834 {
01835 if ( t >= s1-ds )
01836 {
01837 *s = s1;
01838 return true;
01839 }
01840 }
01841 }
01842 return false;
01843 }
01844
01845
01846 ON_BOOL32 ON_PolyCurve::Evaluate(
01847 double t,
01848 int der_count,
01849 int v_stride,
01850 double* v,
01851 int side,
01852
01853
01854
01855 int* hint
01856
01857 ) const
01858 {
01859 ON_BOOL32 rc = false;
01860 const int count = Count();
01861 const int dim = Dimension();
01862 int segment_hint, curve_hint;
01863 if ( count > 0 && dim > 0 && dim <= v_stride )
01864 {
01865 segment_hint = (hint) ? (*hint & 0x3FFF) : 0;
01866 int segment_index = ON_NurbsSpanIndex(2,count+1,m_t,t,side,segment_hint);
01867 if ( -2 == side || 2 == side )
01868 {
01869
01870
01871
01872
01873
01874 double a = t;
01875 if ( ON_TuneupEvaluationParameter( side, m_t[segment_index], m_t[segment_index+1], &a) )
01876 {
01877
01878 t = a;
01879 segment_index = ON_NurbsSpanIndex(2,count+1,m_t,t,side,segment_index);
01880 }
01881 }
01882 const ON_Curve* c = m_segment[segment_index];
01883 if ( c ) {
01884 double s0, s1;
01885 {
01886 ON_Interval dom = c->Domain();
01887 s0 = dom.Min();
01888 s1 = dom.Max();
01889 }
01890 if ( s0 != s1 )
01891 {
01892 const double t0 = m_t[segment_index];
01893 const double t1 = m_t[segment_index+1];
01894 double s;
01895 if ( s0 == t0 && s1 == t1 )
01896 {
01897
01898 s = t;
01899 }
01900 else
01901 {
01902
01903 if ( fabs(t1 - t0) < (ON_ZERO_TOLERANCE + ON_EPSILON*fabs(t0)) )
01904 {
01905
01906 s = (fabs(t-t0) < fabs(t-t1)) ? s0 : s1;
01907 }
01908 else
01909 {
01910
01911
01912
01913 const double d = t1-t0;
01914 double a = (t - t0)/d;
01915 double b = (t1 - t)/d;
01916 if ( 0.0 == b )
01917 a = 1.0;
01918 else if ( 1.0 == b )
01919 a = 0.0;
01920 else if ( 0.0 == a )
01921 b = 1.0;
01922 else if ( 1.0 == a )
01923 b = 0.0;
01924 s = b*s0 + a*s1;
01925 }
01926 if ( -1 == side )
01927 side = -2;
01928 else if ( 1 == side )
01929 side = 2;
01930 }
01931 curve_hint = ( hint && segment_hint == segment_index ) ? ((*hint)>>14) : 0;
01932 rc = c->Evaluate(
01933 s,
01934 der_count,
01935 v_stride, v,
01936 side,
01937 &curve_hint );
01938
01939 if ( rc )
01940 {
01941 if ( der_count > 0 && s1 - s0 != t1 - t0 && t0 != t1 )
01942 {
01943
01944
01945 const double d = (s1-s0)/(t1-t0);
01946 s = d;
01947 int di, vi;
01948 v += v_stride;
01949 for ( di = 1; di <= der_count; di++ )
01950 {
01951 for ( vi = 0; vi < dim; vi++ )
01952 {
01953 v[vi] = s*v[vi];
01954 }
01955 s *= d;
01956 v += v_stride;
01957 }
01958 }
01959
01960 if ( hint )
01961 *hint = segment_index | (curve_hint<<14);
01962 }
01963
01964 }
01965 }
01966 }
01967 return rc;
01968 }
01969
01970 int
01971 ON_PolyCurve::Count() const
01972 {
01973 return m_segment.Count();
01974 }
01975
01976
01977 ON_Curve*
01978 ON_PolyCurve::operator[](int segment_index) const
01979 {
01980 return SegmentCurve(segment_index);
01981 }
01982
01983 ON_Curve*
01984 ON_PolyCurve::SegmentCurve(int segment_index) const
01985 {
01986 return ( segment_index >= 0 && segment_index < Count() )
01987 ? m_segment[segment_index]
01988 : NULL;
01989 }
01990
01991
01992 double ON_PolyCurve::SegmentCurveParameter(
01993 double polycurve_parameter
01994 ) const
01995 {
01996 int segment_index = SegmentIndex( polycurve_parameter );
01997 const ON_Curve* segment_curve = SegmentCurve(segment_index);
01998 if ( !segment_curve )
01999 return ON_UNSET_VALUE;
02000 ON_Interval cdom = segment_curve->Domain();
02001 ON_Interval sdom = SegmentDomain(segment_index);
02002 if ( cdom == sdom )
02003 return polycurve_parameter;
02004 double s = sdom.NormalizedParameterAt(polycurve_parameter);
02005 return cdom.ParameterAt(s);
02006 }
02007
02008
02009 double ON_PolyCurve::PolyCurveParameter(
02010 int segment_index,
02011 double segmentcurve_parameter
02012 ) const
02013 {
02014 const ON_Curve* segment_curve = SegmentCurve(segment_index);
02015 if ( !segment_curve )
02016 return ON_UNSET_VALUE;
02017 ON_Interval cdom = segment_curve->Domain();
02018 ON_Interval sdom = SegmentDomain(segment_index);
02019 if ( cdom == sdom )
02020 return segmentcurve_parameter;
02021 double s = cdom.NormalizedParameterAt(segmentcurve_parameter);
02022 return sdom.ParameterAt(s);
02023 }
02024
02025
02026 ON_Interval
02027 ON_PolyCurve::SegmentDomain( int segment_index ) const
02028 {
02029 ON_Interval domain;
02030 if ( segment_index >= 0 && segment_index < Count() ) {
02031 domain.m_t[0] = m_t[segment_index];
02032 domain.m_t[1] = m_t[segment_index+1];
02033 }
02034 return domain;
02035 }
02036
02037
02038 ON_Curve*
02039 ON_PolyCurve::FirstSegmentCurve() const
02040 {
02041 return SegmentCurve(0);
02042 }
02043
02044 ON_Curve*
02045 ON_PolyCurve::LastSegmentCurve() const
02046 {
02047 return SegmentCurve(Count()-1);
02048 }
02049
02050 void
02051 ON_PolyCurve::Reserve( int capacity )
02052 {
02053 m_segment.Reserve(capacity);
02054 m_t.Reserve(capacity+1);
02055 }
02056
02057 ON_BOOL32 ON_PolyCurve::Prepend( ON_Curve* c )
02058 {
02059 DestroyCurveTree();
02060 return Insert( 0, c );
02061 }
02062
02063 ON_BOOL32 ON_PolyCurve::Append( ON_Curve* c )
02064 {
02065 DestroyCurveTree();
02066 return Insert( Count(), c );
02067 }
02068
02069 ON_BOOL32 ON_PolyCurve::PrependAndMatch(ON_Curve* c)
02070
02071 {
02072 if (Count() == 0) return Prepend(c);
02073
02074 if (!c->SetEndPoint(PointAtStart())){
02075 if (!SetStartPoint(c->PointAtEnd()))
02076 return false;
02077 }
02078 return Prepend(c);
02079 }
02080
02081 ON_BOOL32 ON_PolyCurve::AppendAndMatch(ON_Curve* c)
02082
02083 {
02084 if (Count() == 0) return Append(c);
02085
02086 if (!c->SetStartPoint(PointAtEnd())){
02087 if (!SetEndPoint(c->PointAtStart()))
02088 return false;
02089 }
02090 return Append(c);
02091 }
02092
02093
02094 ON_BOOL32 ON_PolyCurve::Remove( )
02095 {
02096 return Remove(Count()-1);
02097 }
02098
02099 ON_BOOL32 ON_PolyCurve::Remove( int segment_index )
02100 {
02101 ON_BOOL32 rc = false;
02102 const int segment_count = Count();
02103 if ( segment_index >= 0 && segment_index < segment_count ) {
02104 delete m_segment[segment_index];
02105 m_segment[segment_index] = 0;
02106 m_segment.Remove(segment_index);
02107
02108 if ( segment_index >= 1 ) {
02109 double* d = m_t.Array();
02110 const double delta = d[segment_index] - d[segment_index+1];
02111 int i;
02112 for (i=segment_index+1; i <= segment_count; i++ ) {
02113 d[i] += delta;
02114 }
02115 }
02116
02117
02118 if( segment_count==1)
02119 m_t.Empty();
02120 else
02121 m_t.Remove(segment_index);
02122 rc = true;
02123 }
02124 return rc;
02125 }
02126
02127 ON_BOOL32 ON_PolyCurve::Insert( int segment_index, ON_Curve* c )
02128 {
02129 double s0, s1;
02130 ON_BOOL32 rc = false;
02131 const int count = Count();
02132 if ( segment_index >= 0 && segment_index <= count && c && c != this && c->GetDomain(&s0,&s1) )
02133 {
02134 rc = true;
02135 m_segment.Insert( segment_index, c );
02136
02137
02138 double t0, t1;
02139 if ( segment_index == count ) {
02140
02141 if ( count == 0 ) {
02142 m_t.Append(s0);
02143 m_t.Append(s1);
02144 }
02145 else {
02146 t0 = m_t[count];
02147 t1 = ( s0 == t0 ) ? s1 : (s1-s0+t0);
02148 m_t.Append(t1);
02149 }
02150 }
02151 else if ( segment_index == 0 ) {
02152
02153 t1 = m_t[0];
02154 t0 = ( s1 == t1 ) ? s0 : (s0-s1+t1);
02155 m_t.Insert(0,t0);
02156 }
02157 else {
02158
02159 t0 = m_t[segment_index];
02160 t1 = ( s0 == t0 ) ? s1 : (s1-s0+t0);
02161 const double dt = t1-t0;
02162 m_t.Insert(segment_index+1,t1);
02163 double* t = m_t.Array();
02164 for ( int i = segment_index+2; i <= count+1; i++ ) {
02165 t[i] += dt;
02166 }
02167 }
02168 }
02169 return rc;
02170 }
02171
02172 ON_BOOL32 ON_PolyCurve::SetStartPoint(ON_3dPoint start_point)
02173 {
02174 ON_BOOL32 rc = false;
02175
02176 {
02177 ON_Curve* c = FirstSegmentCurve();
02178 if ( c )
02179 rc = c->SetStartPoint(start_point);
02180 }
02181 DestroyCurveTree();
02182 return rc;
02183 }
02184
02185 ON_BOOL32 ON_PolyCurve::SetEndPoint(ON_3dPoint end_point)
02186 {
02187 ON_BOOL32 rc = false;
02188
02189 {
02190 ON_Curve* c = LastSegmentCurve();
02191 if ( c )
02192 rc = c->SetEndPoint(end_point);
02193 }
02194 DestroyCurveTree();
02195 return rc;
02196 }
02197
02198 int ON_PolyCurve::GetNurbForm(
02199 ON_NurbsCurve& nurb,
02200 double tol,
02201 const ON_Interval* subdomain
02202 ) const
02203 {
02204 ON_Interval domain = Domain();
02205 if ( !domain.IsIncreasing() )
02206 return false;
02207 int rc = 0;
02208 int si0 = 0;
02209 int si1 = Count();
02210 if ( subdomain ) {
02211 if ( !subdomain->IsIncreasing() )
02212 return 0;
02213 if ( !domain.Includes(subdomain->Min()) )
02214 return 0;
02215 if ( !domain.Includes(subdomain->Max()) )
02216 return 0;
02217 domain = *subdomain;
02218 }
02219
02220 while ( si0 < si1 && m_t[si0+1] <= domain.m_t[0] )
02221 si0++;
02222 while ( si0 < si1 && m_t[si1-1] >= domain.m_t[1] )
02223 si1--;
02224 if ( si0 >= si1 )
02225 return 0;
02226 {
02227 ON_NurbsCurve c;
02228 int i, rci;
02229 for ( i = si0; i < si1; i++ ) {
02230 if ( !m_segment[i] )
02231 return 0;
02232 if ( i == si0 ) {
02233 rc = m_segment[i]->GetNurbForm( nurb, tol, NULL );
02234 if ( rc < 1 )
02235 return rc;
02236 nurb.SetDomain( m_t[i], m_t[i+1] );
02237 }
02238 else {
02239 rci = m_segment[i]->GetNurbForm( c, tol, NULL );
02240 if ( rci < 1 )
02241 return rci;
02242 else if ( rc < rci )
02243 rc = rci;
02244 c.SetDomain( m_t[i], m_t[i+1] );
02245 if ( !nurb.Append( c ) )
02246 return 0;
02247 c.Destroy();
02248 }
02249 }
02250 }
02251
02252 if ( subdomain )
02253 nurb.Trim( *subdomain );
02254
02255 return rc;
02256 }
02257
02258 int ON_PolyCurve::HasNurbForm() const
02259
02260 {
02261 int count = m_segment.Count();
02262 if (!count)
02263 return 0;
02264 int i;
02265 int rc = 1;
02266 for (i=0; i<count; i++){
02267 const ON_Curve* scrv = SegmentCurve(i);
02268 if (!scrv)
02269 return 0;
02270 int nf = scrv->HasNurbForm();
02271 if (nf == 0)
02272 return 0;
02273 if (nf == 2)
02274 rc = 2;
02275 }
02276 return rc;
02277 }
02278
02279
02280 int ON_PolyCurve::SegmentIndex( double curve_t ) const
02281 {
02282 int count = m_segment.Count();
02283 int seg_index = ON_SearchMonotoneArray( m_t.Array(), m_t.Count(), curve_t );
02284 if ( seg_index < 0 )
02285 seg_index = 0;
02286 else if ( seg_index >= count )
02287 seg_index = count-1;
02288 return seg_index;
02289 }
02290
02291 int ON_PolyCurve::SegmentIndex(
02292 ON_Interval sub_domain,
02293 int* segment_index0,
02294 int* segment_index1
02295 ) const
02296 {
02297 const int segment_count = m_segment.Count();
02298 int s0 = 0, s1 = 0;
02299 ON_Interval seg_dom;
02300 sub_domain.Intersection( Domain() );
02301 if ( sub_domain.IsIncreasing() )
02302 {
02303 s0 = SegmentIndex(sub_domain.Min());
02304 for ( s1 = s0+1; s1 < segment_count; s1++ )
02305 {
02306 seg_dom = SegmentDomain(s1);
02307 if ( seg_dom[0] >= sub_domain.Max() )
02308 break;
02309 }
02310 }
02311 if ( segment_index0 )
02312 *segment_index0 = s0;
02313 if ( segment_index1 )
02314 *segment_index1 = s1;
02315 return s1-s0;
02316 }
02317
02318
02319 ON_BOOL32 ON_PolyCurve::GetCurveParameterFromNurbFormParameter(
02320 double nurbs_t,
02321 double* curve_t
02322 ) const
02323 {
02324 ON_BOOL32 rc = false;
02325 int i = SegmentIndex( nurbs_t );
02326 const ON_Curve* curve = SegmentCurve(i);
02327 if ( curve ) {
02328 ON_Interval in( m_t[i], m_t[i+1] );
02329 ON_Interval cdom = curve->Domain();
02330 if ( in != cdom ) {
02331 nurbs_t = cdom.ParameterAt(in.NormalizedParameterAt(nurbs_t));
02332 rc = curve->GetCurveParameterFromNurbFormParameter(nurbs_t,curve_t);
02333 if ( rc )
02334 *curve_t = in.ParameterAt(cdom.NormalizedParameterAt(*curve_t));
02335 }
02336 else {
02337 rc = curve->GetCurveParameterFromNurbFormParameter(nurbs_t,curve_t);
02338 }
02339 }
02340 return rc;
02341 }
02342
02343 ON_BOOL32 ON_PolyCurve::GetNurbFormParameterFromCurveParameter(
02344 double curve_t,
02345 double* nurbs_t
02346 ) const
02347 {
02348 ON_BOOL32 rc = false;
02349 int i = SegmentIndex( curve_t );
02350 const ON_Curve* curve = SegmentCurve(i);
02351 if ( curve ) {
02352 ON_Interval in( m_t[i], m_t[i+1] );
02353 ON_Interval cdom = curve->Domain();
02354 if ( in != cdom ) {
02355 curve_t = cdom.ParameterAt(in.NormalizedParameterAt(curve_t));
02356 rc = curve->GetNurbFormParameterFromCurveParameter(curve_t,nurbs_t);
02357 if ( rc )
02358 *nurbs_t = in.ParameterAt(cdom.NormalizedParameterAt(*nurbs_t));
02359 }
02360 else {
02361 rc = curve->GetNurbFormParameterFromCurveParameter(curve_t,nurbs_t);
02362 }
02363 }
02364 return rc;
02365 }
02366
02367
02368 ON_Curve* ON_PolyCurve::HarvestSegment( int i )
02369 {
02370 ON_Curve* segment_curve = 0;
02371 if ( i >= 0 && i < m_segment.Count() ) {
02372 segment_curve = m_segment[i];
02373 m_segment[i] = 0;
02374 }
02375 return segment_curve;
02376 }
02377
02378 ON_BOOL32 ON_PolyCurve::Trim(
02379 const ON_Interval& domain
02380 )
02381 {
02382
02383
02384
02385
02386
02387
02388 int segment_count = m_segment.Count();
02389 if ( m_t.Count() < 2 || segment_count+1 != m_t.Count() || !domain.IsIncreasing() )
02390 {
02391
02392 return false;
02393 }
02394
02395 const ON_Interval original_polycurve_domain = Domain();
02396 if ( !original_polycurve_domain.IsIncreasing() )
02397 return false;
02398
02399 ON_Interval output_domain = domain;
02400 if ( !output_domain.Intersection(original_polycurve_domain) )
02401 return false;
02402
02403 if(!output_domain.IsIncreasing())
02404 return false;
02405
02406 if (output_domain == original_polycurve_domain )
02407 return true;
02408
02409 ON_Interval actual_trim_domain = output_domain;
02410
02411 int s0 = -2;
02412 int s1 = -3;
02413
02414
02415
02416
02417
02418
02419
02420
02421
02422
02423
02424
02425
02426 if ( ParameterSearch(output_domain[0], s0, true ) )
02427 {
02428
02429
02430 if (s0 >= 0 && s0 <= segment_count)
02431 {
02432 actual_trim_domain[0]=m_t[s0];
02433 }
02434 }
02435
02436 if ( ParameterSearch(output_domain[1], s1, true ) )
02437 {
02438 if (s1 >= 0 && s1 <= segment_count )
02439 {
02440
02441
02442 actual_trim_domain[1]=m_t[s1];
02443 s1--;
02444 }
02445 }
02446
02447 if ( !actual_trim_domain.IsIncreasing() )
02448 {
02449
02450 return false;
02451 }
02452
02453 if ( s0 < 0 || s0 > s1 || s1 >= segment_count )
02454 {
02455
02456
02457
02458 return false;
02459 }
02460
02461
02462 DestroyCurveTree();
02463
02464 if ( actual_trim_domain == original_polycurve_domain )
02465 {
02466
02467
02468
02469 m_t[0] = output_domain[0];
02470 m_t[segment_count] = output_domain[1];
02471 return true;
02472 }
02473
02474 int i;
02475 for ( i = 0; i < s0; i++ )
02476 {
02477
02478 delete m_segment[i];
02479 m_segment[i] = 0;
02480 }
02481 for ( i = s1+1; i < segment_count; i++ )
02482 {
02483
02484 delete m_segment[i];
02485 m_segment[i] = 0;
02486 }
02487
02488
02489 m_segment.SetCount( s1+1 );
02490 m_t.SetCount(s1+2);
02491 segment_count = s1+1;
02492
02493 if ( s0 > 0 )
02494 {
02495
02496 ON_SimpleArray<ON_Curve*> tmp_seg(s1+1-s0);
02497 ON_SimpleArray<double> tmp_t(s1+2-s0);
02498 tmp_seg.Append( s1+1-s0, m_segment.Array()+s0 );
02499 tmp_t.Append( s1+2-s0, m_t.Array()+s0 );
02500 m_segment.Zero();
02501 m_segment.SetCount( 0 );
02502 m_segment.Append( tmp_seg.Count(), tmp_seg.Array() );
02503 m_t = tmp_t;
02504 segment_count = s1-s0+1;
02505 s1 = segment_count-1;
02506 s0 = 0;
02507 }
02508
02509
02510 const double fuzz = 0.001;
02511 bool bTrimFirstSegment = ( m_t[0] < actual_trim_domain[0] || (0 == s1 && actual_trim_domain[1] < m_t[s1+1]) );
02512 bool bTrimLastSegment = (s1>s0 && actual_trim_domain[1] < m_t[s1+1]);
02513
02514
02515 ON_Interval trim_s_dom, trim_c_dom, c_dom, s_dom;
02516
02517 if ( bTrimFirstSegment )
02518 {
02519 ON_Curve* curve = SegmentCurve(0);
02520 if ( 0 == curve )
02521 return false;
02522
02523 c_dom = curve->Domain();
02524 if ( !c_dom.IsIncreasing() )
02525 {
02526
02527 return false;
02528 }
02529
02530 s_dom = SegmentDomain(0);
02531 if ( !s_dom.IsIncreasing() )
02532 {
02533
02534 return false;
02535 }
02536
02537 trim_s_dom = s_dom;
02538 if ( !trim_s_dom.Intersection(actual_trim_domain) )
02539 {
02540
02541
02542 return false;
02543 }
02544
02545 if ( s1 > 0 && trim_s_dom[1] != s_dom[1] )
02546 {
02547
02548
02549 return false;
02550 }
02551
02552 if ( !trim_s_dom.IsIncreasing() )
02553 {
02554
02555
02556 return false;
02557 }
02558
02559 if ( c_dom != s_dom )
02560 {
02561
02562 trim_c_dom[0] = c_dom.ParameterAt( s_dom.NormalizedParameterAt(trim_s_dom[0]) );
02563 trim_c_dom[1] = c_dom.ParameterAt( s_dom.NormalizedParameterAt(trim_s_dom[1]) );
02564 if ( !trim_c_dom.IsIncreasing() )
02565 {
02566 if ( s_dom.NormalizedParameterAt(trim_s_dom[0]) >= 1.0-fuzz && s1 > 0 )
02567 {
02568
02569
02570
02571
02572 bTrimFirstSegment = false;
02573 curve = 0;
02574 delete m_segment[0];
02575 m_segment[0] = 0;
02576 m_t.Remove(0);
02577 m_segment.Remove(0);
02578 s1--;
02579 }
02580 else
02581 return false;
02582 }
02583 }
02584 else
02585 {
02586 trim_c_dom = trim_s_dom;
02587 }
02588
02589
02590
02591
02592 if ( bTrimFirstSegment && trim_c_dom != c_dom )
02593 {
02594
02595 if ( !curve->Trim(trim_c_dom) )
02596 {
02597
02598
02599
02600 if ( c_dom.NormalizedParameterAt(trim_c_dom[0]) >= 1.0 - fuzz && s1 > 0 )
02601 {
02602
02603 bTrimFirstSegment = false;
02604 curve = 0;
02605 delete m_segment[0];
02606 m_segment[0] = 0;
02607 m_t.Remove(0);
02608 m_segment.Remove(0);
02609 s1--;
02610 }
02611 else
02612 return false;
02613 }
02614 else
02615 {
02616 m_t[0] = actual_trim_domain[0];
02617 if ( 0 == s1 && 2 == m_t.Count() && !bTrimLastSegment )
02618 m_t[1] = actual_trim_domain[1];
02619 }
02620 }
02621 }
02622
02623
02624
02625 if ( bTrimLastSegment )
02626 {
02627
02628
02629
02630 if ( s1+1 != m_segment.Count() )
02631 {
02632
02633
02634 return false;
02635 }
02636
02637 ON_Curve* curve = SegmentCurve(s1);
02638 if ( 0 == curve )
02639 return false;
02640
02641 c_dom = curve->Domain();
02642 if ( !c_dom.IsIncreasing() )
02643 {
02644
02645 return false;
02646 }
02647
02648 s_dom = SegmentDomain(s1);
02649 if ( !s_dom.IsIncreasing() )
02650 {
02651
02652 return false;
02653 }
02654
02655
02656 trim_s_dom= ON_Interval(m_t[s1], actual_trim_domain[1]);
02657
02658 if ( !trim_s_dom.IsIncreasing() )
02659 {
02660
02661
02662 return false;
02663 }
02664
02665 trim_c_dom[0] = c_dom[0];
02666 if ( c_dom != s_dom )
02667 {
02668 trim_c_dom[1] = c_dom.ParameterAt( s_dom.NormalizedParameterAt(trim_s_dom[1]) );
02669 if ( !trim_c_dom.IsIncreasing() )
02670 {
02671 if ( s_dom.NormalizedParameterAt(trim_s_dom[1]) <= fuzz && s1 > 0 )
02672 {
02673
02674
02675
02676
02677 bTrimLastSegment = false;
02678 curve = 0;
02679 delete m_segment[s1];
02680 m_segment[s1] = 0;
02681 m_t.Remove();
02682 m_segment.Remove();
02683 s1--;
02684 }
02685 else
02686 return false;
02687 }
02688 }
02689 else
02690 {
02691 trim_c_dom[1] = trim_s_dom[1];
02692 }
02693
02694 if ( bTrimLastSegment && c_dom != trim_c_dom )
02695 {
02696
02697 if ( !curve->Trim(trim_c_dom) )
02698 {
02699
02700 if ( c_dom.NormalizedParameterAt(trim_c_dom[1]) <= fuzz && s1 > 0)
02701 {
02702
02703
02704
02705
02706
02707
02708 bTrimLastSegment = false;
02709 curve = 0;
02710 delete m_segment[s1];
02711 m_segment[s1] = 0;
02712 m_t.Remove();
02713 m_segment.Remove();
02714 s1--;
02715 }
02716 else
02717 return false;
02718 }
02719 else
02720 m_t[m_t.Count()-1] = actual_trim_domain[1];
02721 }
02722 }
02723
02724
02725
02726
02727
02728
02729 m_t[0] = output_domain[0];
02730 m_t[m_t.Count()-1] = output_domain[1];
02731
02732 DestroyCurveTree();
02733
02734 return true;
02735 }
02736
02737
02738
02739
02740 bool ON_PolyCurve::Extend(
02741 const ON_Interval& domain
02742 )
02743
02744 {
02745 if (IsClosed() || Count() < 1) return false;
02746
02747 bool changed = false;
02748 if (Domain()[0] > domain[0]){
02749 ON_Curve* seg = SegmentCurve(0);
02750 if (!seg) return false;
02751 ON_Interval sdom = SegmentDomain(0);
02752 ON_Interval cdom = seg->Domain();
02753 double a = (sdom == cdom) ? domain[0] : cdom.ParameterAt(sdom.NormalizedParameterAt(domain[0]));
02754 ON_Interval DesiredDom(a, cdom[1]);
02755 changed = seg->Extend(DesiredDom);
02756 if (changed) {
02757 if (seg->Domain() == DesiredDom)
02758 m_t[0] = domain[0];
02759 else
02760 m_t[0] = sdom.ParameterAt(cdom.NormalizedParameterAt(seg->Domain()[0]));
02761 }
02762 }
02763 if (Domain()[1] < domain[1]){
02764 bool chgd = false;
02765 ON_Curve* seg = SegmentCurve(Count()-1);
02766 if (!seg) return false;
02767 ON_Interval sdom = SegmentDomain(Count()-1);
02768 ON_Interval cdom = seg->Domain();
02769 double a = (sdom == cdom) ? domain[1] : cdom.ParameterAt(sdom.NormalizedParameterAt(domain[1]));
02770 ON_Interval DesiredDom(cdom[0], a);
02771 chgd = seg->Extend(DesiredDom);
02772 if (chgd) {
02773 if (seg->Domain() == DesiredDom)
02774 m_t[Count()] = domain[1];
02775 else
02776 m_t[Count()] = sdom.ParameterAt(cdom.NormalizedParameterAt(seg->Domain()[1]));
02777 changed = true;
02778 }
02779 }
02780
02781 if (changed){
02782 DestroyCurveTree();
02783 }
02784
02785 return changed;
02786 }
02787
02788
02789
02790
02791 ON_BOOL32 ON_PolyCurve::Split(
02792 double split_parameter,
02793 ON_Curve*& left_side,
02794 ON_Curve*& right_side
02795 ) const
02796 {
02797 int si;
02798 ON_Interval dom = Domain();
02799
02800 ON_PolyCurve* pLeftSide = ON_PolyCurve::Cast(left_side);
02801 ON_PolyCurve* pRightSide = ON_PolyCurve::Cast(right_side);
02802
02803 if ( pLeftSide && pLeftSide != this )
02804 pLeftSide->Destroy();
02805 else if ( pLeftSide == this )
02806 pLeftSide->DestroyCurveTree();
02807
02808 if ( pRightSide && pRightSide != this )
02809 pRightSide->Destroy();
02810 else if ( pRightSide == this )
02811 pRightSide->DestroyCurveTree();
02812
02813 if ( left_side && !pLeftSide )
02814 return false;
02815 if ( right_side && !pRightSide )
02816 return false;
02817 if ( !dom.Includes( split_parameter, true ) )
02818 return false;
02819
02820
02821 const ON_BOOL32 bDupSegs = ( this != pLeftSide && this != pRightSide );
02822
02823
02824
02825
02826
02827
02828
02829
02830 bool split_at_break = ParameterSearch(split_parameter, si, true);
02831 if( split_at_break && (si<=0 || si>=Count() ) )
02832 return false;
02833
02834 ON_Interval s_dom = SegmentDomain(si);
02835 ON_Curve* seg_curve = SegmentCurve(si);
02836 if ( !seg_curve )
02837 return false;
02838 ON_Interval c_dom = seg_curve->Domain();
02839
02840 double c;
02841 if( split_at_break)
02842 c = c_dom[0];
02843 else
02844 c = ( c_dom == s_dom )
02845 ? split_parameter
02846 : c_dom.ParameterAt( s_dom.NormalizedParameterAt(split_parameter) );
02847
02848 ON_Curve* seg_left = 0;
02849 ON_Curve* seg_right = 0;
02850
02851 if ( !split_at_break && c_dom.Includes(c,true) )
02852 {
02853 if ( !seg_curve->Split( c, seg_left, seg_right ) )
02854 {
02855 double fuzz = 0.001;
02856 if ( c_dom.NormalizedParameterAt(c) <= fuzz )
02857 c = c_dom[0];
02858 else if ( c_dom.NormalizedParameterAt(c) >= 1.0 - fuzz )
02859 c = c_dom[1];
02860 else
02861 return false;
02862 }
02863 }
02864 else if ( c <= c_dom.ParameterAt(0.5) )
02865 c = c_dom[0];
02866 else
02867 c = c_dom[1];
02868
02869
02870 ON_SimpleArray< ON_Curve* > left_segment;
02871 ON_SimpleArray< ON_Curve* > right_segment;
02872 ON_SimpleArray< double > left_t;
02873 ON_SimpleArray< double > right_t;
02874
02875 int i;
02876
02877 if ( seg_left && seg_right )
02878 {
02879
02880 left_segment.Reserve(si+1);
02881 right_segment.Reserve(m_segment.Count()-si);
02882 left_t.Reserve(left_segment.Count()+1);
02883 right_t.Reserve(right_segment.Count()+1);
02884 if ( !bDupSegs )
02885 {
02886 delete m_segment[si];
02887 const_cast<ON_PolyCurve*>(this)->m_segment[si] = 0;
02888 }
02889
02890 for ( i = 0; i < si; i++ )
02891 {
02892 if ( bDupSegs )
02893 left_segment.Append( m_segment[i]->Duplicate() );
02894 else
02895 left_segment.Append( m_segment[i] );
02896 left_t.Append( m_t[i] );
02897 }
02898 left_segment.Append( seg_left );
02899 left_t.Append( m_t[si] );
02900 left_t.Append( split_parameter );
02901
02902 right_segment.Append(seg_right);
02903 right_t.Append( split_parameter );
02904 for ( i = si+1; i < m_segment.Count(); i++ )
02905 {
02906 if ( bDupSegs )
02907 right_segment.Append( m_segment[i]->Duplicate() );
02908 else
02909 right_segment.Append( m_segment[i] );
02910 right_t.Append( m_t[i] );
02911 }
02912 right_t.Append( m_t[m_segment.Count()] );
02913 }
02914 else
02915 {
02916 if ( c == c_dom[1] )
02917 si++;
02918 if( (c==c_dom[0] && si==0 ) ||
02919 (c==c_dom[1] && si==m_segment.Count() ) )
02920 return false;
02921
02922 left_segment.Reserve(si);
02923 right_segment.Reserve(m_segment.Count()-si);
02924 left_t.Reserve(left_segment.Count()+1);
02925 right_t.Reserve(right_segment.Count()+1);
02926
02927 for ( i = 0; i < si; i++ )
02928 {
02929 if ( bDupSegs )
02930 left_segment.Append( m_segment[i]->Duplicate() );
02931 else
02932 left_segment.Append( m_segment[i] );
02933 left_t.Append( m_t[i] );
02934 }
02935 left_t.Append( split_parameter );
02936
02937 for ( i = si; i < m_segment.Count(); i++ )
02938 {
02939 if ( bDupSegs )
02940 right_segment.Append( m_segment[i]->Duplicate() );
02941 else
02942 right_segment.Append( m_segment[i] );
02943 if ( i == si )
02944 right_t.Append( split_parameter );
02945 else
02946 right_t.Append( m_t[i] );
02947 }
02948 right_t.Append( m_t[m_segment.Count()] );
02949 }
02950
02951 if ( !pLeftSide )
02952 pLeftSide = new ON_PolyCurve();
02953 if ( !pRightSide )
02954 pRightSide = new ON_PolyCurve();
02955 if ( !bDupSegs )
02956 {
02957
02958 ON_PolyCurve* this_ptr = const_cast<ON_PolyCurve*>(this);
02959 this_ptr->m_segment.Zero();
02960 this_ptr->m_t.Zero();
02961 this_ptr->m_segment.SetCount(0);
02962 this_ptr->m_t.SetCount(0);
02963 }
02964
02965 pLeftSide->m_segment.Append( left_segment.Count(), left_segment.Array() );
02966 pLeftSide->m_t.Append( left_t.Count(), left_t.Array() );
02967 pRightSide->m_segment.Append( right_segment.Count(), right_segment.Array() );
02968 pRightSide->m_t.Append( right_t.Count(), right_t.Array() );
02969
02970 left_side = pLeftSide;
02971 right_side = pRightSide;
02972
02973 return true;
02974 }
02975
02976
02977
02978 static
02979 void Flatten( ON_PolyCurve* poly, ON_Interval pdom, ON_SimpleArray<double>& new_t, ON_SimpleArray<ON_Curve*>& new_seg){
02980 int n= poly->Count();
02981 double t0 = pdom[0];
02982 ON_Interval pcdom = poly->Domain();
02983 for(int i=0; i<n; i++){
02984 double sdom=poly->SegmentDomain(i)[1];
02985 double ndom=pcdom.NormalizedParameterAt(sdom);
02986 double t1 =pdom.ParameterAt(ndom);
02987 ON_Curve* seg = poly->SegmentCurve(i);
02988 ON_PolyCurve* spoly = ON_PolyCurve::Cast(seg);
02989 if(spoly){
02990 Flatten(spoly, ON_Interval(t0,t1), new_t, new_seg );
02991 poly->HarvestSegment(i);
02992 delete spoly;
02993 } else {
02994 new_t.Append(t1);
02995 new_seg.Append(seg);
02996 poly->HarvestSegment(i);
02997 }
02998 t0 = t1;
02999 }
03000 }
03001
03002 bool ON_PolyCurve::HasSynchronizedSegmentDomains() const
03003 {
03004 double t0, t1;
03005 int i, count = m_segment.Count();
03006 const ON_Curve* const * c = m_segment.Array();
03007 if ( count < 1 || 0 == c )
03008 return false;
03009 if ( count != m_t.Count()+1 )
03010 return false;
03011 const double* t = m_t.Array();
03012 if ( 0 == t )
03013 return false;
03014
03015 for ( i = 0; i < count; i++ )
03016 {
03017 t0 = -ON_UNSET_VALUE;
03018 t1 = ON_UNSET_VALUE;
03019 if ( 0 != c[i]
03020 && c[i]->GetDomain(&t0,&t1)
03021 && t0 == t[i]
03022 && t1 == t[i+1]
03023 )
03024 {
03025 continue;
03026 }
03027 return false;
03028 }
03029
03030 return true;
03031 }
03032
03033
03034
03035
03036
03037
03038
03039
03040
03041
03042 bool ON_PolyCurve::SynchronizeSegmentDomains()
03043 {
03044 double t0, t1;
03045 int i, count = m_segment.Count();
03046 ON_Curve** c = m_segment.Array();
03047 if ( count < 1 || 0 == c )
03048 return false;
03049 if ( count+1 != m_t.Count() )
03050 return false;
03051 const double* t = m_t.Array();
03052 if ( 0 == t )
03053 return false;
03054
03055 bool rc = false;
03056 for ( i = 0; i < count; i++ )
03057 {
03058 if ( !c[i] )
03059 continue;
03060 t0 = -ON_UNSET_VALUE;
03061 t1 = ON_UNSET_VALUE;
03062 if ( c[i]->GetDomain(&t0,&t1)
03063 && t0 == t[i]
03064 && t1 == t[i+1]
03065 )
03066 {
03067 continue;
03068 }
03069
03070 if ( ON_IsValid(t[i])
03071 && ON_IsValid(t[i+1])
03072 && t[i] < t[i+1]
03073 && c[i]->SetDomain(t[i],t[i+1])
03074 )
03075 {
03076 rc = true;
03077 }
03078 }
03079 return rc;
03080 }
03081
03082
03083
03084 bool ON_PolyCurve::RemoveNestingEx( )
03085 {
03086
03087
03088
03089
03090
03091 bool rc = false;
03092 int n = Count();
03093
03094 ON_SimpleArray<double> old_t = m_t;
03095 ON_SimpleArray<ON_Curve*> old_seg = m_segment;
03096
03097 m_t.SetCount(1);
03098 m_segment.SetCount(0);
03099
03100 for(int i=0; i<n;i++){
03101 ON_PolyCurve* poly = ON_PolyCurve::Cast( old_seg[i]);
03102 if(poly){
03103 rc = true;
03104 Flatten( poly, ON_Interval(old_t[i], old_t[i+1]), m_t, m_segment );
03105 delete poly;
03106 } else {
03107 m_t.Append( old_t[i+1]);
03108 m_segment.Append( old_seg[i] );
03109 }
03110 }
03111 return rc;
03112 }
03113
03114 void ON_PolyCurve::RemoveNesting( )
03115 {
03116 RemoveNestingEx();
03117 }
03118
03119 bool ON_PolyCurve::IsNested() const
03120 {
03121 int i, count = m_segment.Count();
03122 for ( i = 0; i < count; i++ )
03123 {
03124 if ( ON_PolyCurve::Cast(m_segment[i]) )
03125 return true;
03126 }
03127 return false;
03128 }
03129
03130
03131
03132 void ON_PolyCurve::SetSegment(int i, ON_Curve* crv){
03133 if(i>=0 && i<Count())
03134 m_segment[i] = crv;
03135 }
03136
03137
03138 bool ON_PolyCurve::ParameterSearch(double t, int& index, bool bEnableSnap) const{
03139 return ON_Curve::ParameterSearch(t, index, bEnableSnap, m_t, ON_SQRT_EPSILON);
03140 }
03141
03142 const ON_CurveArray& ON_PolyCurve::SegmentCurves() const
03143 {
03144 return m_segment;
03145 }
03146
03147 const ON_SimpleArray<double>& ON_PolyCurve::SegmentParameters() const
03148 {
03149 return m_t;
03150 }