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_PolylineCurve,ON_Curve,"4ED7D4E6-E947-11d3-BFE5-0010830122F0");
00020
00021 ON_PolylineCurve::ON_PolylineCurve()
00022 {
00023 m_dim = 3;
00024 }
00025
00026 ON_PolylineCurve::ON_PolylineCurve( const ON_PolylineCurve& L )
00027 {
00028 *this = L;
00029 }
00030
00031 ON_PolylineCurve::ON_PolylineCurve( const ON_3dPointArray& L )
00032 {
00033 *this = L;
00034 }
00035
00036 ON_PolylineCurve::~ON_PolylineCurve()
00037 {
00038 }
00039
00040 unsigned int ON_PolylineCurve::SizeOf() const
00041 {
00042 unsigned int sz = ON_Curve::SizeOf();
00043 sz += (sizeof(*this) - sizeof(ON_Curve));
00044 sz += m_pline.SizeOfArray();
00045 sz += m_t.SizeOfArray();
00046 return sz;
00047 }
00048
00049 ON__UINT32 ON_PolylineCurve::DataCRC(ON__UINT32 current_remainder) const
00050 {
00051 current_remainder = m_pline.DataCRC(current_remainder);
00052 current_remainder = m_t.DataCRC(current_remainder);
00053 current_remainder = ON_CRC32(current_remainder,sizeof(m_dim),&m_dim);
00054 return current_remainder;
00055 }
00056
00057 void ON_PolylineCurve::EmergencyDestroy()
00058 {
00059 m_pline.EmergencyDestroy();
00060 m_t.EmergencyDestroy();
00061 }
00062
00063 ON_PolylineCurve& ON_PolylineCurve::operator=( const ON_PolylineCurve& src )
00064 {
00065 if ( this != &src ) {
00066 ON_Curve::operator=(src);
00067 m_pline = src.m_pline;
00068 m_t = src.m_t;
00069 m_dim = src.m_dim;
00070 }
00071 return *this;
00072 }
00073
00074 ON_PolylineCurve& ON_PolylineCurve::operator=( const ON_3dPointArray& src )
00075 {
00076 m_pline = src;
00077 m_dim = 3;
00078 const int count = src.Count();
00079 m_t.Reserve(count);
00080 m_t.SetCount(count);
00081 int i;
00082 for (i = 0; i < count; i++) {
00083 m_t[i] = (double)i;
00084 }
00085 return *this;
00086 }
00087
00088 int ON_PolylineCurve::Dimension() const
00089 {
00090 return m_dim;
00091 }
00092
00093 ON_BOOL32
00094 ON_PolylineCurve::GetBBox(
00095 double* boxmin,
00096 double* boxmax,
00097 ON_BOOL32 bGrowBox
00098 ) const
00099 {
00100 return ON_GetPointListBoundingBox( m_dim, false, PointCount(), 3, m_pline[0],
00101 boxmin, boxmax, bGrowBox?true:false
00102 );
00103 }
00104
00105
00106 ON_BOOL32
00107 ON_PolylineCurve::Transform( const ON_Xform& xform )
00108 {
00109 TransformUserData(xform);
00110 DestroyCurveTree();
00111 return m_pline.Transform( xform );
00112 }
00113
00114
00115
00116 ON_BOOL32
00117 ON_PolylineCurve::SwapCoordinates( int i, int j )
00118 {
00119 DestroyCurveTree();
00120 return m_pline.SwapCoordinates(i,j);
00121 }
00122
00123 ON_BOOL32 ON_PolylineCurve::IsValid( ON_TextLog* text_log ) const
00124 {
00125 const int count = PointCount();
00126 if ( count >= 2 && count == m_t.Count() )
00127 {
00128 if ( !m_pline.IsValid() )
00129 {
00130 if ( 0 != text_log )
00131 {
00132 text_log->Print("PolylineCurve m_pline[] is not valid.\n");
00133 }
00134 return ON_IsNotValid();
00135 }
00136 int i;
00137 for ( i = 1; i < count; i++ )
00138 {
00139 if ( m_t[i] <= m_t[i-1] )
00140 {
00141 if ( 0 != text_log )
00142 {
00143 text_log->Print("PolylineCurve m_t[%d]=%g should be less than m_t[%d]=(%g).\n",
00144 i-1,m_t[i-1],i,m_t[i]);
00145 }
00146 return ON_IsNotValid();
00147 }
00148 }
00149
00150 if (m_dim < 2 || m_dim > 3 )
00151 {
00152 if (0 != text_log )
00153 text_log->Print("PolylineCurve m_dim = %d (should be 2 or 3).\n",m_dim);
00154 return ON_IsNotValid();
00155 }
00156 }
00157 else if ( 0 != text_log )
00158 {
00159 if ( count < 2 )
00160 text_log->Print("PolylineCurve has %d points (should be >= 2)\n",count);
00161 else
00162 text_log->Print("PolylineCurve m_t.Count() = %d and PointCount() = %d (should be equal)\n",
00163 m_t.Count(),count);
00164 return ON_IsNotValid();
00165 }
00166
00167 return true;
00168 }
00169
00170 void ON_PolylineCurve::Dump( ON_TextLog& dump ) const
00171 {
00172 ON_Interval d = Domain();
00173 dump.Print( "ON_PolylineCurve: domain = [%g,%g]\n",d[0],d[1]);
00174 for ( int i = 0; i < PointCount(); i++ ) {
00175 dump.Print( " point[%2d] = ",i);
00176 dump.Print( m_pline[i] );
00177 dump.Print( ", %g\n",m_t[i]);
00178 }
00179 }
00180
00181 ON_BOOL32 ON_PolylineCurve::Write( ON_BinaryArchive& file ) const
00182 {
00183 ON_BOOL32 rc = file.Write3dmChunkVersion(1,0);
00184 if (rc) {
00185 if (rc) rc = file.WriteArray( m_pline );
00186 if (rc) rc = file.WriteArray( m_t );
00187 if (rc) rc = file.WriteInt(m_dim);
00188 }
00189 return rc;
00190 }
00191
00192 ON_BOOL32 ON_PolylineCurve::Read( ON_BinaryArchive& file )
00193 {
00194 int major_version = 0;
00195 int minor_version = 0;
00196 ON_BOOL32 rc = file.Read3dmChunkVersion(&major_version,&minor_version);
00197 if (rc && major_version==1) {
00198
00199 if (rc) rc = file.ReadArray( m_pline );
00200 if (rc) rc = file.ReadArray( m_t );
00201 if (rc) rc = file.ReadInt(&m_dim);
00202 }
00203 return rc;
00204 }
00205
00206 ON_Interval ON_PolylineCurve::Domain() const
00207 {
00208 ON_Interval d;
00209
00210 const int count = PointCount();
00211 if ( count >= 2 && m_t[0] < m_t[count-1] ) {
00212 d.Set(m_t[0],m_t[count-1]);
00213 }
00214 return d;
00215 }
00216
00217 ON_BOOL32 ON_PolylineCurve::SetDomain( double t0, double t1 )
00218 {
00219 ON_BOOL32 rc = false;
00220 const int count = m_t.Count()-1;
00221 if ( count >= 1 )
00222 {
00223 if ( t0 == m_t[0] && t1 == m_t[count] )
00224 rc = true;
00225 else if ( t0 < t1 )
00226 {
00227 const ON_Interval old_domain = Domain();
00228 const ON_Interval new_domain(t0,t1);
00229 m_t[0] = t0;
00230 m_t[count] = t1;
00231 for ( int i = 1; i < count; i++ )
00232 {
00233 m_t[i] = new_domain.ParameterAt( old_domain.NormalizedParameterAt(m_t[i]) );
00234 }
00235 rc=true;
00236 }
00237 }
00238 DestroyCurveTree();
00239 return rc;
00240 }
00241
00242 bool ON_PolylineCurve::ChangeDimension( int desired_dimension )
00243 {
00244 bool rc = (desired_dimension>=2 && desired_dimension<=3);
00245
00246 if ( rc && m_dim != desired_dimension )
00247 {
00248 DestroyCurveTree();
00249 int i, count = m_pline.Count();
00250 if ( 2 == desired_dimension )
00251 {
00252 if ( count > 0 )
00253 {
00254
00255
00256
00257 if ( ON_UNSET_VALUE != m_pline[0].x )
00258 {
00259 for ( i = 0; i < count; i++ )
00260 m_pline[i].z = 0.0;
00261 }
00262 }
00263 m_dim = 2;
00264 }
00265 else
00266 {
00267 if ( count > 0 )
00268 {
00269
00270
00271
00272 if ( ON_UNSET_VALUE != m_pline[0].x && ON_UNSET_VALUE == m_pline[0].z )
00273 {
00274 for ( i = 0; i < count; i++ )
00275 m_pline[i].z = 0.0;
00276 }
00277 }
00278 m_dim = 3;
00279 }
00280 }
00281
00282 return rc;
00283 }
00284
00285
00286 ON_BOOL32 ON_PolylineCurve::ChangeClosedCurveSeam( double t )
00287 {
00288 const ON_Interval old_dom = Domain();
00289 ON_BOOL32 rc = IsClosed();
00290 if ( rc )
00291 {
00292 double k = t;
00293 if ( !old_dom.Includes(t) )
00294 {
00295 double s = old_dom.NormalizedParameterAt(t);
00296 s = fmod(s,1.0);
00297 if ( s < 0.0 )
00298 s += 1.0;
00299 k = old_dom.ParameterAt(s);
00300 }
00301 if ( old_dom.Includes(k,true) )
00302 {
00303 int old_count = PointCount();
00304 int i = ON_NurbsSpanIndex(2,old_count,m_t.Array(),k,0,0);
00305 if ( k < m_t[i] )
00306 return false;
00307 if ( k >= m_t[i+1] )
00308 return false;
00309 int new_count = (k==m_t[i]) ? old_count : old_count+1;
00310 ON_SimpleArray<ON_3dPoint> new_pt(new_count);
00311 ON_SimpleArray<double> new_t(new_count);
00312 ON_3dPoint new_start = (k==m_t[i]) ? m_pline[i] : PointAt(k);
00313 new_pt.Append( new_start );
00314 new_t.Append(k);
00315 int n = old_count-i-1;
00316 new_pt.Append( n, m_pline.Array() + i+1 );
00317 new_t.Append( n, m_t.Array() + i+1 );
00318
00319 int j = new_t.Count();
00320
00321 n = new_count-old_count+i-1;
00322 new_pt.Append( n, m_pline.Array() + 1 );
00323 new_t.Append( n, m_t.Array() + 1 );
00324
00325 new_pt.Append( new_start );
00326 new_t.Append(k);
00327
00328 double d = old_dom.Length();
00329 while ( j < new_t.Count() )
00330 {
00331 new_t[j] += d;
00332 j++;
00333 }
00334
00335 m_pline = new_pt;
00336 m_t = new_t;
00337 }
00338 else
00339 {
00340
00341 rc = true;
00342 }
00343 if ( rc )
00344 SetDomain( t, t + old_dom.Length() );
00345 }
00346 return rc;
00347 }
00348
00349 int ON_PolylineCurve::SpanCount() const
00350 {
00351 return m_pline.SegmentCount();
00352 }
00353
00354 ON_BOOL32 ON_PolylineCurve::GetSpanVector(
00355 double* s
00356 ) const
00357 {
00358 ON_BOOL32 rc = false;
00359 const int count = PointCount();
00360 if ( count >= 1 )
00361 {
00362 memcpy( s, m_t.Array(), count*sizeof(*s) );
00363 rc = true;
00364 }
00365 return rc;
00366 }
00367
00368 int ON_PolylineCurve::Degree() const
00369 {
00370 return 1;
00371 }
00372
00373
00374 ON_BOOL32
00375 ON_PolylineCurve::IsLinear(
00376 double tolerance
00377 ) const
00378 {
00379 ON_BOOL32 rc = false;
00380 ON_NurbsCurve nurbs_curve;
00381 nurbs_curve.m_dim = m_dim;
00382 nurbs_curve.m_is_rat = 0;
00383 nurbs_curve.m_order = 2;
00384 nurbs_curve.m_cv_count = m_pline.Count();
00385 if ( nurbs_curve.m_cv_count >= 2 )
00386 {
00387 nurbs_curve.m_cv = const_cast<double*>(&m_pline[0].x);
00388 nurbs_curve.m_cv_stride = (int)(&m_pline[1].x - nurbs_curve.m_cv);
00389 nurbs_curve.m_knot = const_cast<double*>(m_t.Array());
00390
00391 const ON_Curve* ptr = &nurbs_curve;
00392 rc = ptr->IsLinear(tolerance);
00393 nurbs_curve.m_cv = 0;
00394 nurbs_curve.m_knot = 0;
00395 }
00396 return rc;
00397 }
00398
00399 int ON_PolylineCurve::IsPolyline(
00400 ON_SimpleArray<ON_3dPoint>* pline_points,
00401 ON_SimpleArray<double>* pline_t
00402 ) const
00403 {
00404 if ( pline_points )
00405 pline_points->SetCount(0);
00406 if ( pline_t )
00407 pline_t->SetCount(0);
00408 int rc = this->PointCount();
00409 if ( rc >= 2 )
00410 {
00411 if ( pline_points )
00412 pline_points->operator=(m_pline);
00413 if ( pline_t )
00414 pline_t->operator=(m_t);
00415 }
00416 else
00417 rc = 0;
00418 return rc;
00419 }
00420
00421 ON_BOOL32
00422 ON_PolylineCurve::IsArc(
00423 const ON_Plane* plane,
00424 ON_Arc* arc,
00425
00426 double tolerance
00427 ) const
00428 {
00429 return false;
00430 }
00431
00432
00433 ON_BOOL32
00434 ON_PolylineCurve::IsPlanar(
00435 ON_Plane* plane,
00436
00437 double tolerance
00438 ) const
00439 {
00440 ON_BOOL32 rc = false;
00441 ON_NurbsCurve nurbs_curve;
00442 nurbs_curve.m_dim = m_dim;
00443 nurbs_curve.m_is_rat = 0;
00444 nurbs_curve.m_order = 2;
00445 nurbs_curve.m_cv_count = m_pline.Count();
00446 if ( nurbs_curve.m_cv_count >= 2 )
00447 {
00448 if (m_dim == 2 )
00449 {
00450 rc = ON_Curve::IsPlanar(plane,tolerance);
00451 }
00452 else
00453 {
00454 nurbs_curve.m_cv = const_cast<double*>(&m_pline[0].x);
00455 nurbs_curve.m_cv_stride = (int)(&m_pline[1].x - nurbs_curve.m_cv);
00456 nurbs_curve.m_knot = const_cast<double*>(m_t.Array());
00457
00458 const ON_Curve* ptr = &nurbs_curve;
00459 rc = ptr->IsPlanar(plane,tolerance);
00460 nurbs_curve.m_cv = 0;
00461 nurbs_curve.m_knot = 0;
00462 }
00463 }
00464 return rc;
00465 }
00466
00467 ON_BOOL32
00468 ON_PolylineCurve::IsInPlane(
00469 const ON_Plane& plane,
00470 double tolerance
00471 ) const
00472 {
00473 ON_BOOL32 rc = false;
00474 ON_NurbsCurve nurbs_curve;
00475 nurbs_curve.m_dim = m_dim;
00476 nurbs_curve.m_is_rat = 0;
00477 nurbs_curve.m_order = 2;
00478 nurbs_curve.m_cv_count = m_pline.Count();
00479 if ( nurbs_curve.m_cv_count >= 2 )
00480 {
00481 nurbs_curve.m_cv = const_cast<double*>(&m_pline[0].x);
00482 nurbs_curve.m_cv_stride = (int)(&m_pline[1].x - nurbs_curve.m_cv);
00483 nurbs_curve.m_knot = const_cast<double*>(m_t.Array());
00484 rc = nurbs_curve.IsInPlane(plane,tolerance);
00485 nurbs_curve.m_cv = 0;
00486 nurbs_curve.m_knot = 0;
00487 }
00488 return rc;
00489 }
00490
00491 ON_BOOL32
00492 ON_PolylineCurve::IsClosed() const
00493 {
00494 return m_pline.IsClosed(0.0);
00495 }
00496
00497 ON_BOOL32
00498 ON_PolylineCurve::IsPeriodic() const
00499 {
00500 return false;
00501 }
00502
00503 bool ON_PolylineCurve::GetNextDiscontinuity(
00504 ON::continuity c,
00505 double t0,
00506 double t1,
00507 double* t,
00508 int* hint,
00509 int* dtype,
00510 double cos_angle_tolerance,
00511 double curvature_tolerance
00512 ) const
00513 {
00514 bool rc = false;
00515
00516 const int segment_count = m_pline.SegmentCount();
00517
00518 if ( segment_count > 0 && t0 != t1 )
00519 {
00520 ON_Interval domain = Domain();
00521
00522 if ( t0 < t1 )
00523 {
00524 if ( t0 < domain[0] )
00525 t0 = domain[0];
00526 if ( t1 > domain[1] )
00527 t1 = domain[1];
00528 if ( t0 >= t1 )
00529 return false;
00530 }
00531 else if ( t0 > t1 )
00532 {
00533 if ( t1 < domain[0] )
00534 t1 = domain[0];
00535 if ( t0 > domain[1] )
00536 t0 = domain[1];
00537 if ( t1 >= t0 )
00538 return false;
00539 }
00540
00541 if ( t0 != t1 )
00542 {
00543 ON_3dPoint Pm, Pp;
00544 ON_3dVector D1m, D1p, Tm, Tp;
00545
00546 if ( dtype )
00547 *dtype = 0;
00548 c = ON::PolylineContinuity(c);
00549 ON::continuity parametric_c = ON::ParametricContinuity(c);
00550 if ( segment_count >= 2 && parametric_c != ON::C0_continuous )
00551 {
00552 int i = 0;
00553 int delta_i = 1;
00554 double s0 = t0;
00555 double s1 = t1;
00556 i = ON_NurbsSpanIndex(2,PointCount(),m_t,t0,0,(hint)?*hint:0);
00557 double segtol = (fabs(m_t[i]) + fabs(m_t[i+1]) + fabs(m_t[i+1]-m_t[i]))*ON_SQRT_EPSILON;
00558 if ( t0 < t1 )
00559 {
00560 if ( t0 < m_t[i+1] && t1 > m_t[i+1] && (m_t[i+1]-t0) <= segtol && i+1 < PointCount() )
00561 {
00562 t0 = m_t[i+1];
00563 i = ON_NurbsSpanIndex(2,PointCount(),m_t,t0,0,(hint)?*hint:0);
00564 }
00565 if ( hint )
00566 *hint = i;
00567 i++;
00568 }
00569 else if ( t0 > t1 )
00570 {
00571
00572
00573
00574 if ( t0 > m_t[i] && t1 < m_t[i] && (t0-m_t[i]) <= segtol && i > 0 )
00575 {
00576 t0 = m_t[i];
00577 i = ON_NurbsSpanIndex(2,PointCount(),m_t,t0,0,(hint)?*hint:0);
00578 }
00579 if ( hint )
00580 *hint = i;
00581 if ( t0 == m_t[i] )
00582 i--;
00583 delta_i = -1;
00584 s0 = t1;
00585 s1 = t0;
00586 }
00587 for ( ; !rc && 0 < i && i < segment_count && s0 < m_t[i] && m_t[i] < s1; i += delta_i )
00588 {
00589 Ev1Der(m_t[i], Pm, D1m, -1, hint );
00590 Ev1Der(m_t[i], Pp, D1p, +1, hint );
00591 if ( parametric_c == ON::C1_continuous || parametric_c == ON::C2_continuous )
00592 {
00593 if ( !(D1m-D1p).IsTiny(D1m.MaximumCoordinate()*ON_SQRT_EPSILON) )
00594 rc = true;
00595 }
00596 else if ( parametric_c == ON::G1_continuous || parametric_c == ON::G2_continuous || parametric_c == ON::Gsmooth_continuous )
00597 {
00598 Tm = D1m;
00599 Tp = D1p;
00600 Tm.Unitize();
00601 Tp.Unitize();
00602 if ( Tm*Tp < cos_angle_tolerance )
00603 rc = true;
00604 }
00605 if ( rc )
00606 {
00607 if ( dtype )
00608 *dtype = 1;
00609 if ( t )
00610 *t = m_t[i];
00611 break;
00612 }
00613 }
00614 }
00615
00616 if ( !rc && segment_count > 0 && parametric_c != c )
00617 {
00618
00619
00620 rc = ON_Curve::GetNextDiscontinuity( c, t0, t1, t, hint, dtype, cos_angle_tolerance, curvature_tolerance );
00621 }
00622 }
00623 }
00624
00625 return rc;
00626 }
00627
00628
00629 bool ON_PolylineCurve::IsContinuous(
00630 ON::continuity desired_continuity,
00631 double t,
00632 int* hint,
00633 double point_tolerance,
00634 double d1_tolerance,
00635 double d2_tolerance,
00636 double cos_angle_tolerance,
00637 double curvature_tolerance
00638 ) const
00639 {
00640 bool rc = true;
00641 const int segment_count = m_pline.SegmentCount();
00642
00643 if ( segment_count >= 1 )
00644 {
00645 bool bPerformTest = false;
00646 desired_continuity = ON::PolylineContinuity(desired_continuity);
00647
00648 if ( t <= m_t[0] || t >= m_t[segment_count] )
00649 {
00650
00651
00652 switch(desired_continuity)
00653 {
00654 case ON::C0_locus_continuous:
00655 case ON::C1_locus_continuous:
00656 case ON::G1_locus_continuous:
00657 bPerformTest = true;
00658 break;
00659 default:
00660
00661 break;
00662 }
00663 }
00664 else
00665 {
00666 if ( segment_count >= 2 && desired_continuity != ON::C0_continuous )
00667 {
00668 int i = ON_NurbsSpanIndex(2,PointCount(),m_t,t,0,(hint)?*hint:0);
00669
00670 {
00671
00672
00673
00674
00675
00676
00677 double segtol = (fabs(m_t[i]) + fabs(m_t[i+1]) + fabs(m_t[i+1]-m_t[i]))*ON_SQRT_EPSILON;
00678 if ( m_t[i]+segtol < m_t[i+1]-segtol )
00679 {
00680 if ( fabs(t-m_t[i]) <= segtol && i > 0 )
00681 {
00682 t = m_t[i];
00683 }
00684 else if ( fabs(t-m_t[i+1]) <= segtol && i+1 < PointCount() )
00685 {
00686 t = m_t[i+1];
00687 i = ON_NurbsSpanIndex(2,PointCount(),m_t,t,0,(hint)?*hint:0);
00688 }
00689 }
00690 }
00691
00692 if ( hint )
00693 *hint = i;
00694 if ( i > 0 && i < segment_count && t == m_t[i] )
00695 {
00696
00697 desired_continuity = ON::ParametricContinuity(desired_continuity);
00698 bPerformTest = true;
00699 }
00700 }
00701 }
00702
00703 if ( bPerformTest )
00704 {
00705
00706 rc = ON_Curve::IsContinuous( desired_continuity, t, hint,
00707 point_tolerance, d1_tolerance, d2_tolerance,
00708 cos_angle_tolerance, curvature_tolerance );
00709 }
00710 }
00711
00712 return rc;
00713 }
00714
00715 ON_BOOL32
00716 ON_PolylineCurve::Reverse()
00717 {
00718 ON_BOOL32 rc = false;
00719 const int count = PointCount();
00720 if ( count >= 2 ) {
00721 m_pline.Reverse();
00722 m_t.Reverse();
00723 double* t = m_t.Array();
00724 for ( int i = 0; i < count; i++ ) {
00725 t[i] = -t[i];
00726 }
00727 rc = true;
00728 }
00729 DestroyCurveTree();
00730 return rc;
00731 }
00732
00733 ON_BOOL32 ON_PolylineCurve::SetStartPoint(
00734 ON_3dPoint start_point
00735 )
00736 {
00737
00738
00739
00740
00741
00742
00743
00744 bool rc = false;
00745 int count = m_pline.Count();
00746 if ( count >= 2
00747 && ( !m_pline[0].IsValid()
00748 || m_pline[count-1].x != m_pline[0].x
00749 || m_pline[count-1].y != m_pline[0].y
00750 || m_pline[count-1].z != m_pline[0].z
00751 )
00752 )
00753 {
00754 m_pline[0] = start_point;
00755 rc = true;
00756 }
00757 DestroyCurveTree();
00758 return rc;
00759 }
00760
00761 ON_BOOL32 ON_PolylineCurve::SetEndPoint(
00762 ON_3dPoint end_point
00763 )
00764 {
00765
00766
00767
00768
00769
00770
00771
00772 bool rc = false;
00773 int count = m_pline.Count();
00774 if ( count >= 2
00775 && ( !m_pline[count-1].IsValid()
00776 || m_pline[count-1].x != m_pline[0].x
00777 || m_pline[count-1].y != m_pline[0].y
00778 || m_pline[count-1].z != m_pline[0].z
00779 )
00780 )
00781 {
00782 m_pline[count-1] = end_point;
00783 rc = true;
00784 }
00785 DestroyCurveTree();
00786 return rc;
00787 }
00788
00789 ON_BOOL32
00790 ON_PolylineCurve::Evaluate(
00791 double t,
00792 int der_count,
00793 int v_stride,
00794 double* v,
00795 int side,
00796
00797
00798
00799 int* hint
00800
00801 ) const
00802 {
00803 ON_BOOL32 rc = false;
00804 const int count = PointCount();
00805 if ( count >= 2 )
00806 {
00807 int segment_index = ON_NurbsSpanIndex(2,count,m_t,t,side,(hint)?*hint:0);
00808
00809 if ( -2 == side || 2 == side )
00810 {
00811
00812
00813
00814
00815
00816 double a = t;
00817 if ( ON_TuneupEvaluationParameter( side, m_t[segment_index], m_t[segment_index+1], &a) )
00818 {
00819
00820 t = a;
00821 segment_index = ON_NurbsSpanIndex(2,count,m_t,t,side,segment_index);
00822 }
00823 }
00824
00825 const double t0 = m_t[segment_index];
00826 const double t1 = m_t[segment_index+1];
00827 double s = (t == t1) ? 1.0 : (t-t0)/(t1-t0);
00828 const ON_3dPoint p = (1.0-s)*m_pline[segment_index] + s*m_pline[segment_index+1];
00829 v[0] = p.x;
00830 v[1] = p.y;
00831 if ( m_dim == 3 )
00832 v[2] = p.z;
00833 if ( der_count >= 1 ) {
00834 v += v_stride;
00835 ON_3dVector d = 1.0/(t1-t0)*(m_pline[segment_index+1] - m_pline[segment_index]);
00836 v[0] = d.x;
00837 v[1] = d.y;
00838 if ( m_dim == 3 )
00839 v[2] = d.z;
00840 }
00841 for ( int di = 2; di <= der_count; di++ ) {
00842 v += v_stride;
00843 v[0] = 0.0;
00844 v[1] = 0.0;
00845 if ( m_dim == 3 )
00846 v[2] = 0.0;
00847 }
00848 if ( hint )
00849 *hint = segment_index;
00850 rc = true;
00851 }
00852 return rc;
00853 }
00854
00855 ON_BOOL32
00856 ON_PolylineCurve::PointCount() const
00857 {
00858 return m_pline.PointCount();
00859 }
00860
00861 bool ON_PolylineCurve::Append( const ON_PolylineCurve& c )
00862 {
00863
00864 if ( PointCount() == 0 ) {
00865 *this = c;
00866 return IsValid() ? true : false;
00867 }
00868
00869 if (!IsValid() || !c.IsValid())
00870 return false;
00871
00872 if ( c.Dimension() == 3 && Dimension() == 2)
00873 m_dim = 3;
00874
00875 m_pline.Remove();
00876 m_pline.Append(c.m_pline.Count(), c.m_pline.Array());
00877 m_t.Reserve(m_t.Count()+c.m_t.Count()-1);
00878 double del = *m_t.Last() - c.m_t[0];
00879 int i;
00880 for (i=1; i<c.m_t.Count(); i++)
00881 m_t.Append(c.m_t[i] + del);
00882
00883 return true;
00884 }
00885
00886
00887 bool ON_PolylineCurve::ParameterSearch(double t, int& index, bool bEnableSnap) const{
00888 return ON_Curve::ParameterSearch( t, index,bEnableSnap, m_t, ON_SQRT_EPSILON);
00889 }
00890
00891
00892 ON_BOOL32 ON_PolylineCurve::Trim( const ON_Interval& domain )
00893 {
00894 int segment_count = m_t.Count()-1;
00895
00896 if ( segment_count < 1 || m_t.Count() != m_pline.Count() || !domain.IsIncreasing() )
00897 return false;
00898
00899 const ON_Interval original_polyline_domain = Domain();
00900 if ( !original_polyline_domain.IsIncreasing() )
00901 return false;
00902
00903 ON_Interval output_domain = domain;
00904 if ( !output_domain.Intersection(original_polyline_domain) )
00905 return false;
00906 if(!output_domain.IsIncreasing())
00907 return false;
00908
00909 ON_Interval actual_trim_domain = output_domain;
00910
00911 int i, j;
00912 int s0 = -2;
00913 int s1 = -3;
00914
00915 if ( ParameterSearch(output_domain[0], s0, true ) )
00916 {
00917
00918
00919 if (s0 >= 0 && s0 <= segment_count)
00920 {
00921 actual_trim_domain[0]=m_t[s0];
00922 }
00923 }
00924
00925 if ( ParameterSearch(output_domain[1], s1, true ) )
00926 {
00927 if (s1 >= 0 && s1 <= segment_count )
00928 {
00929
00930
00931 actual_trim_domain[1]=m_t[s1];
00932 s1--;
00933 }
00934 }
00935
00936 if ( !actual_trim_domain.IsIncreasing() )
00937 {
00938
00939 return false;
00940 }
00941
00942 if ( s0 < 0 || s0 > s1 || s1 >= segment_count )
00943 {
00944
00945
00946
00947 return false;
00948 }
00949
00950
00951 DestroyCurveTree();
00952
00953 if ( actual_trim_domain == original_polyline_domain )
00954 {
00955
00956
00957
00958 m_t[0] = output_domain[0];
00959 m_t[segment_count] = output_domain[1];
00960 return true;
00961 }
00962
00963 if ( s1 < segment_count-1 )
00964 {
00965 m_t.SetCount(s1+2);
00966 m_pline.SetCount(s1+2);
00967 segment_count = s1+1;
00968 }
00969
00970 if ( s0 > 0 )
00971 {
00972 double* tmp_t = m_t.Array();
00973 ON_3dPoint* tmp_P = m_pline.Array();
00974 for ( i = 0, j = s0; j <= segment_count; i++, j++ )
00975 {
00976 tmp_t[i] = tmp_t[j];
00977 tmp_P[i] = tmp_P[j];
00978 }
00979 s1 -= s0;
00980 s0 = 0;
00981 m_t.SetCount(s1+2);
00982 m_pline.SetCount(s1+2);
00983 segment_count = s1+1;
00984 }
00985
00986 bool bTrimFirstSegment = ( m_t[0] < actual_trim_domain[0] || (0 == s1 && actual_trim_domain[1] < m_t[1]) );
00987 bool bTrimLastSegment = (s1>s0 && m_t[s1] < actual_trim_domain[1] && actual_trim_domain[1] < m_t[s1+1]);
00988
00989 if ( bTrimFirstSegment )
00990 {
00991 ON_Interval seg_domain(m_t[0],m_t[1]);
00992 ON_3dPoint Q0 = m_pline[0];
00993 ON_3dPoint Q1 = m_pline[1];
00994 ON_Line seg_chord(Q0,Q1);
00995 double np0 = 0.0;
00996 double np1 = 1.0;
00997 bool bSet0 = false;
00998 bool bSet1 = false;
00999 if ( m_t[0] < actual_trim_domain[0] && actual_trim_domain[0] < m_t[1] )
01000 {
01001 np0 = seg_domain.NormalizedParameterAt(actual_trim_domain[0]);
01002 Q0 = seg_chord.PointAt( np0 );
01003 bSet0 = true;
01004 }
01005 if ( 0 == s1 && m_t[0] < actual_trim_domain[1] && actual_trim_domain[1] < m_t[1] )
01006 {
01007 np1 = seg_domain.NormalizedParameterAt(actual_trim_domain[1]);
01008 Q1 = seg_chord.PointAt( np1 );
01009 bSet1 = true;
01010 }
01011
01012 if ( np0 >= np1 )
01013 return false;
01014
01015 if ( bSet0 )
01016 {
01017 if ( np0 >= 1.0-ON_SQRT_EPSILON && Q0.DistanceTo(Q1) <= ON_ZERO_TOLERANCE && s1>0 && m_t[1] < actual_trim_domain[1] )
01018 {
01019
01020 m_t.Remove(0);
01021 m_pline.Remove(0);
01022 s1--;
01023 segment_count--;
01024 actual_trim_domain[0] = m_t[0];
01025 }
01026 m_t[0] = actual_trim_domain[0];
01027 m_pline[0] = Q0;
01028 }
01029 if ( bSet1 )
01030 {
01031 m_t[1] = actual_trim_domain[1];
01032 m_pline[1] = Q1;
01033 }
01034 }
01035
01036 if ( bTrimLastSegment )
01037 {
01038 ON_Interval seg_domain(m_t[s1],m_t[s1+1]);
01039 ON_3dPoint Q0 = m_pline[s1];
01040 ON_3dPoint Q1 = m_pline[s1+1];
01041 ON_Line seg_chord(Q0,Q1);
01042 double np = seg_domain.NormalizedParameterAt(actual_trim_domain[1]);
01043 Q1 = seg_chord.PointAt(np);
01044 if ( np <= ON_SQRT_EPSILON && Q1.DistanceTo(Q0) <= ON_ZERO_TOLERANCE && s1 > 0 )
01045 {
01046
01047 m_pline.SetCount(s1+1);
01048 m_t.SetCount(s1+1);
01049 s1--;
01050 segment_count--;
01051 actual_trim_domain[1] = m_t[s1+1];
01052 }
01053 m_t[s1+1] = actual_trim_domain[1];
01054 m_pline[s1+1] = Q1;
01055 }
01056
01057
01058
01059
01060
01061
01062 m_t[0] = output_domain[0];
01063 m_t[m_t.Count()-1] = output_domain[1];
01064
01065 return true;
01066 }
01067
01068 bool ON_PolylineCurve::Extend(
01069 const ON_Interval& domain
01070 )
01071
01072 {
01073 if (IsClosed())
01074 return false;
01075 if (PointCount() < 2)
01076 return false;
01077 if ( !domain.IsIncreasing() )
01078 return false;
01079 bool changed = false;
01080 if ( domain == Domain() )
01081 return true;
01082
01083 if (domain[0] < m_t[0]){
01084 changed = true;
01085 double len = m_t[1] - m_t[0];
01086 if ( len <= 0.0 )
01087 return false;
01088 ON_3dVector V = m_pline[1] - m_pline[0];
01089 ON_3dPoint Q0 = m_pline[0];
01090 Q0 += (domain[0]-m_t[0])/len*V;
01091 m_t[0] = domain[0];
01092 m_pline[0] = Q0;
01093 }
01094
01095 int last = PointCount()-1;
01096 if (domain[1] > m_t[last]){
01097 changed = true;
01098 double len = m_t[last] - m_t[last-1];
01099 if ( len <= 0.0 )
01100 return false;
01101 ON_3dVector V = m_pline[last] - m_pline[last-1];
01102 ON_3dPoint Q1 = m_pline[last];
01103 Q1 += (domain[1]-m_t[last])/len*V;
01104 m_t[last] = domain[1];
01105 m_pline[last] = Q1;
01106 }
01107
01108 if (changed){
01109 DestroyCurveTree();
01110 }
01111 return changed;
01112 }
01113
01114
01115
01116 ON_BOOL32 ON_PolylineCurve::Split(
01117 double t,
01118 ON_Curve*& left_side,
01119 ON_Curve*& right_side
01120 ) const
01121 {
01122 bool rc = false;
01123 ON_PolylineCurve* left_pl=0;
01124 ON_PolylineCurve* right_pl=0;
01125 if ( left_side )
01126 {
01127 left_pl = ON_PolylineCurve::Cast(left_side);
01128 if (!left_pl)
01129 return false;
01130 }
01131 if ( right_side )
01132 {
01133 right_pl = ON_PolylineCurve::Cast(right_side);
01134 if (!right_pl)
01135 return false;
01136 }
01137
01138
01139 const int count = m_t.Count()-1;
01140 if ( count >= 1 && m_t[0] < t && t < m_t[count] )
01141 {
01142
01143
01144
01145 int segment_index;
01146 bool split_at_break = ParameterSearch(t, segment_index, true);
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157 if ( ( segment_index >= 1 || (false==split_at_break && 0 == segment_index) )
01158 && segment_index < count
01159 && m_t[0] < t && t < m_t[count]
01160 )
01161 {
01162 int left_point_count = (split_at_break)
01163 ? segment_index+1
01164 : segment_index+2;
01165 int right_point_count = m_t.Count() - segment_index;
01166
01167 if ( left_pl != this )
01168 {
01169 if ( !left_pl )
01170 left_pl = new ON_PolylineCurve();
01171 left_pl->m_t.Reserve(left_point_count);
01172 left_pl->m_t.SetCount(left_point_count);
01173 left_pl->m_pline.Reserve(left_point_count);
01174 left_pl->m_pline.SetCount(left_point_count);
01175 memcpy( left_pl->m_t.Array(), m_t.Array(), left_point_count*sizeof(double) );
01176 memcpy( left_pl->m_pline.Array(), m_pline.Array(), left_point_count*sizeof(ON_3dPoint) );
01177 if(split_at_break)
01178 {
01179
01180 *left_pl->m_t.Last()= t;
01181 }
01182 left_pl->m_dim = m_dim;
01183 }
01184 if ( right_pl != this )
01185 {
01186 if ( !right_pl )
01187 right_pl = new ON_PolylineCurve();
01188 right_pl->m_t.Reserve(right_point_count);
01189 right_pl->m_t.SetCount(right_point_count);
01190 right_pl->m_pline.Reserve(right_point_count);
01191 right_pl->m_pline.SetCount(right_point_count);
01192 memcpy( right_pl->m_t.Array(),
01193 m_t.Array() + m_t.Count() - right_point_count,
01194 right_point_count*sizeof(double) );
01195 memcpy( right_pl->m_pline.Array(),
01196 m_pline.Array() + m_pline.Count() - right_point_count,
01197 right_point_count*sizeof(ON_3dPoint) );
01198 if( split_at_break)
01199 {
01200
01201 right_pl->m_t[0] = t;
01202 }
01203 right_pl->m_dim = m_dim;
01204 }
01205 left_pl->Trim( ON_Interval( left_pl->m_t[0], t ) );
01206 right_pl->Trim( ON_Interval( t, *right_pl->m_t.Last() ) );
01207 rc = true;
01208 }
01209
01210 }
01211
01212
01213 left_side = left_pl;
01214 right_side = right_pl;
01215 return rc;
01216 }
01217
01218
01219 int ON_PolylineCurve::GetNurbForm(
01220 ON_NurbsCurve& nurb,
01221 double tol,
01222 const ON_Interval* subdomain
01223 ) const
01224 {
01225 int rc = 0;
01226 const int count = PointCount();
01227 if ( count < 2 )
01228 nurb.Destroy();
01229 else if ( nurb.Create( Dimension(), false, 2, count) ) {
01230 int i;
01231 for ( i = 0; i < count; i++ ) {
01232 nurb.SetKnot( i, m_t[i] );
01233 nurb.SetCV( i, m_pline[i] );
01234 }
01235 if ( subdomain && *subdomain != Domain() )
01236 nurb.Trim(*subdomain);
01237 if ( nurb.IsValid() )
01238 rc = 1;
01239 }
01240 return rc;
01241 }
01242
01243 int ON_PolylineCurve::HasNurbForm() const
01244 {
01245 if (PointCount() < 2)
01246 return 0;
01247 if (!IsValid())
01248 return 0;
01249 return 1;
01250 }
01251
01252 ON_BOOL32 ON_PolylineCurve::GetCurveParameterFromNurbFormParameter(
01253 double nurbs_t,
01254 double* curve_t
01255 ) const
01256 {
01257 *curve_t = nurbs_t;
01258 return true;
01259 }
01260
01261 ON_BOOL32 ON_PolylineCurve::GetNurbFormParameterFromCurveParameter(
01262 double curve_t,
01263 double* nurbs_t
01264 ) const
01265 {
01266 *nurbs_t = curve_t;
01267 return true;
01268 }