opennurbs_polylinecurve.cpp
Go to the documentation of this file.
00001 /* $NoKeywords: $ */
00002 /*
00003 //
00004 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
00005 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
00006 // McNeel & Associates.
00007 //
00008 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
00009 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
00010 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
00011 //                              
00012 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
00013 //
00015 */
00016 
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018 
00019 ON_OBJECT_IMPLEMENT(ON_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( // returns true if successful
00095          double* boxmin,    // minimum
00096          double* boxmax,    // maximum
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     // common to all 1.x versions
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   //ON_BOOL32 rc = false;
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         // 7 April 2003 Dale Lear:
00255         //   If x coord of first point is set, then
00256         //   zero all z coords.  
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         // 7 April 2003 Dale Lear:
00270         //   If first point x coord is set and z is unset, then
00271         //   zero all z coords.  
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       // k already at start end of this curve
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( // span "knots" 
00355        double* s // array of length SpanCount() + 1 
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( // true if curve locus is a line segment
00376       double tolerance // tolerance to use when checking linearity
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); // the int converts 64 bit size_t
00389     nurbs_curve.m_knot = const_cast<double*>(m_t.Array());
00390     // using ptr to make sure we go through vtable
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( // true if curve locus in an arc or circle
00423       const ON_Plane* plane, // if not NULL, test is performed in this plane
00424       ON_Arc* arc,         // if not NULL and true is returned, then arc
00425                               // arc parameters are filled in
00426       double tolerance // tolerance to use when checking linearity
00427       ) const
00428 {
00429   return false;
00430 }
00431 
00432 
00433 ON_BOOL32
00434 ON_PolylineCurve::IsPlanar(
00435       ON_Plane* plane, // if not NULL and true is returned, then plane parameters
00436                          // are filled in
00437       double tolerance // tolerance to use when checking linearity
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); // the (int) converts 64 bit size_t
00456       nurbs_curve.m_knot = const_cast<double*>(m_t.Array());
00457       // using ptr to make sure we go through vtable
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, // plane to test
00470       double tolerance // tolerance to use when checking linearity
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++; // start checking at first m_t[i] > t0
00568         }
00569         else if ( t0 > t1 )
00570         {
00571           // Check backwards (have to handle this case so 
00572           // ON_CurveProxy::GetNextDiscontinuity() works on
00573           // reversed proxy curves.
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 ( /*empty*/; !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         // 20 March 2003 Dale Lear:
00619         //   Let base class test for locus continuities at start/end.
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, // default = NULL,
00633     double point_tolerance, // default=ON_ZERO_TOLERANCE
00634     double d1_tolerance, // default==ON_ZERO_TOLERANCE
00635     double d2_tolerance, // default==ON_ZERO_TOLERANCE
00636     double cos_angle_tolerance, // default==ON_DEFAULT_ANGLE_TOLERANCE_COSINE
00637     double curvature_tolerance  // default==ON_SQRT_EPSILON
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       // 20 March 2003 Dale Lear
00651       //     Consistently handles locus case and out of domain case.
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         // intentionally ignoring other ON::continuity enum values
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           // 20 March 2003 Dale Lear:
00672           //     If t is very near interior m_t[] value, see if it
00673           //     should be set to that value.  A bit or two of 
00674           //     precision sometimes gets lost in proxy
00675           //     domain to real curve domain conversions on the interior
00676           //     of a curve domain.
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           // "locus" and "parametric" tests are the same at this point.
00697           desired_continuity = ON::ParametricContinuity(desired_continuity);
00698           bPerformTest = true;
00699         }
00700       }
00701     }
00702 
00703     if ( bPerformTest )
00704     {
00705       // need to evaluate and test
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   // 10 March 2009 Dale Lear
00738   //    I'm using exact compare instead of the fuzzy IsClosed()
00739   //    check to permit setting the start point.  This fixes
00740   //    a bug Mikko reported that prevented making polylines
00741   //    exactly closed when the end points were almost exactly
00742   //    equal.  At this point, I don't remember why we don't allow
00743   //    SetStartPoint() the start point of a closed curve.
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 // used to call IsClosed()
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   // 10 March 2009 Dale Lear
00766   //    I'm using exact compare instead of the fuzzy IsClosed()
00767   //    check to permit setting the start point.  This fixes
00768   //    a bug Mikko reported that prevented making polylines
00769   //    exactly closed when the end points were almost exactly
00770   //    equal.  At this point, I don't remember why we don't allow
00771   //    SetEndPoint() the end point of a closed curve.
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 // used to call IsClosed()
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( // returns false if unable to evaluate
00791        double t,       // evaluation parameter
00792        int der_count,  // number of derivatives (>=0)
00793        int v_stride,   // v[] array stride (>=Dimension())
00794        double* v,      // v[] array of length stride*(ndir+1)
00795        int side,       // optional - determines which side to evaluate from
00796                        //         0 = default
00797                        //      <  0 to evaluate from below, 
00798                        //      >  0 to evaluate from above
00799        int* hint       // optional - evaluation hint (int) used to speed
00800                        //            repeated evaluations
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       // 9 November 2010 Dale Lear - ON_TuneupEvaluationParameter fix
00812       //   When evluation passes through ON_CurveProxy or ON_PolyCurve reparamterization
00813       //   and the original side parameter was -1 or +1, it is changed to -2 or +2
00814       //   to indicate that if t is numerically closed to an end paramter, then
00815       //   it should be tuned up to be at the end paramter.
00816       double a = t;
00817       if ( ON_TuneupEvaluationParameter( side, m_t[segment_index], m_t[segment_index+1], &a) )
00818       {
00819         // recalculate segment index
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 // returns true if t is sufficiently close to m_t[index]
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; // s0 gets set to index of first segment we keep
00913   int s1 = -3; // s1 gets set to index of last segment we keep
00914   
00915         if ( ParameterSearch(output_domain[0], s0, true ) )
00916   {
00917     // ParameterSearch says domain[0] is within "microtol" of
00918     // m_t[s0].  So we will actually trim at m_t[s0].
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       // ParameterSearch says domain[1] is within "microtol" of
00930       // m_t[s1].  So we will actually trim at m_t[s1].
00931       actual_trim_domain[1]=m_t[s1];
00932       s1--;
00933     }
00934   }
00935 
00936   if ( !actual_trim_domain.IsIncreasing() )
00937   {
00938     // After microtol snapping, there is not enough curve left to trim.
00939     return false;
00940   }
00941 
00942   if ( s0 < 0 || s0 > s1 || s1 >= segment_count )
00943   {
00944     // Because output_domain is a subinterval of original_polyline_domain,
00945     // the only way that (s0 < 0 || s0 > s1 || s1 >= segment_count) can be true
00946     // is if something is seriously wrong with the m_t[] values.
00947     return false;
00948   }
00949 
00950   // we will begin modifying the polyline
00951   DestroyCurveTree();
00952 
00953   if ( actual_trim_domain == original_polyline_domain )
00954   {
00955     // ParameterSearch says that the ends of output_domain
00956     // were microtol away from being the entire curve.  
00957     // Set the domain and return.
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; // trim is not viable
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         // trim will leave a micro segment at the start - just remove the first segment
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         // trim will leave a micro segment at the end - just remove the last segment
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   // If we get this far, trims were is successful.
01058   // The following makes potential tiny adjustments
01059   // that need to happen when trims get snapped to
01060   // input m_t[] values that are within fuzz of the
01061   // output_domain[] values.
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   // count = number of polyline segments
01139   const int count = m_t.Count()-1;
01140   if ( count >= 1 && m_t[0] < t && t < m_t[count] )
01141         {
01142     // March 26 2003 Greg Arden
01143     //   Use new function ParameterSearch() to snap parameter value
01144           //     when close to break point.
01145                 int segment_index;
01146                 bool split_at_break = ParameterSearch(t, segment_index, true);
01147 
01148     // 22 August 2008 Dale Lear
01149     //   Added segment_index checks to fix bug when
01150     //   t = m_t[count]-epsilon and segment_index is
01151     //   returned as count.  In this case right_point_count
01152     //   go set to 1 and an invalid polyline was returned.
01153     //   The || in the first expression prevents splitting
01154     //   when (t=m_t[0]+epsilon and epsilon is small enough
01155     //   that parameter search considers t to be nearly equal
01156     //   to m_t[0].
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                                         // reparameterize the last segment 
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                                         // Reparameterize the first segment
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  // OPTIONAL subdomain of ON::ProxyCurve::Domain()
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 }


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