CFx SDK Documentation  2023 SP0
FMImpTContour2D.h
Go to the documentation of this file.
1 // Copyright (C) 2002-2015, Open Design Alliance (the "Alliance").
3 // All rights reserved.
4 //
5 // This software and its documentation and related materials are owned by
6 // the Alliance. The software may only be incorporated into application
7 // programs owned by members of the Alliance, subject to a signed
8 // Membership Agreement and Supplemental Software License Agreement with the
9 // Alliance. The structure and organization of this software are the valuable
10 // trade secrets of the Alliance and its suppliers. The software is also
11 // protected by copyright law and international treaty provisions. Application
12 // programs incorporating this software must include the following statement
13 // with their copyright notices:
14 //
15 // This application incorporates Teigha(R) software pursuant to a license
16 // agreement with Open Design Alliance.
17 // Teigha(R) Copyright (C) 2002-2015 by Open Design Alliance.
18 // All rights reserved.
19 //
20 // By use of this software, its documentation or related materials, you
21 // acknowledge and accept the above terms.
23 #ifndef __FM_T_CONTOUR2D_IMPL_H__
24 #define __FM_T_CONTOUR2D_IMPL_H__
25 
26 #include "FMGeometry.h"
27 
28 #include "Contours/FM_IContour2D.h"
29 #include "Contours/FMBulgeSeg2D.h"
30 #include "Contours/FMCachedSeg2D.h"
31 
32 #include "Ge/GeMatrix2d.h"
33 #include "Ge/GeExtents2d.h"
34 #include "Ge/GeLineSeg2d.h"
35 #include "Ge/GeCircArc2d.h"
36 
37 // To Do: replace DBL_EPSILON in calculations with an appropriate constant
38 #include <limits.h>
39 #include <float.h>
40 //
41 
42 namespace FacetModeler
43 {
44 
45 
46 extern Result fast_isSelfIntersecting(const IContour2D & rContour, const OdGeTol & gTol,
47  bool & bIntersects );
48 
49 extern Result fast_isValidRegion (const IContour2D & rContour, const OdGeTol & gTol,
50  bool & bValidRegion );
51 
52 extern Result fast_intersect(const IContour2D& rContA, const IContour2D& rContB,
53  std::vector< Intersection > & vecPoints, const OdGeTol & gTol );
54 
55 extern Result fast_getInternalPoint( const IContour2D& rContour, OdGePoint2d& rPoint, const OdGeTol & gTol );
56 
57 extern void contour2d_mergeSegments( IContour2D& rContour, int iMergeFlags = 0, const OdGeTol & gTol = FMGeGbl::gTol );
58 
60 
62 //
63 // This template implements IContour2D methods
64 //
65 
66 template < class TContourData >
68  public IContour2D,
69  protected TContourData
70 {
71 public:
72  typedef typename TContourData::ImplSeg2D TImplSeg2D;
73  typedef typename TContourData::VertexData TVertexData;
74 
75 public:
77 
78  TContour2DImpl(const TContour2DImpl& rSrcCont) : TContourData( rSrcCont ) { };
79 
81 //
82 // IContour2D methods
83 //
84 
85  // Copy this contour from rSrcCont
86  virtual void set( const IContour2D & rSrcCont );
87 
88  // Create a new copy of this contour.
89  // Call delete to release memory
90  virtual IContour2D * clone( ) const;
91 
92 
93  // returns class info at runtime
94  virtual ContourImplClass implClass() const
95  {
96  return this->_implClass();
97  }
98 
100  //
101 
102  // Returns true if this entity is closed, false otherwise.
103  virtual bool isClosed() const
104  {
105  return this->_closed();
106  }
107 
108  // Makes the contour closed (open).
109  // This method doesn't change vertex count.
110  // In open contours the last bulge value is unused.
111  virtual void setClosed(bool bClosed = true)
112  {
113  if ( this->_closed() != bClosed )
114  this->_setClosed( bClosed );
115  }
116 
117  // Removes the last vertex and makes contour closed if
118  // the last and the first points are equal.
119  // Returns true, if the vertex was removed and the contour was closed
120  virtual bool setClosedIfEndsAreEqual( const OdGeTol& gTol = FMGeGbl::gTol );
121 
122 
123  // returns true, if there is no vertices
124  virtual bool isEmpty() const
125  {
126  return this->_empty();
127  }
128 
129  // returns number of vertices
130  virtual OdUInt32 numVerts() const
131  {
132  return this->_numVerts();
133  }
134 
135  // returns number of segments
136  // It is less than or equal (if the contour is closed) to the number of vertices.
137  virtual OdUInt32 numSegments() const
138  {
139  return this->_numSegments();
140  }
141 
142 
143  // Returns true, if the contour contains at least one arc
144  virtual bool hasArcs() const;
145 
146 
147 
149  //
150  // 1. Simple Segment and Vertex operations
151  //
152 
153 
154 
155  // Returns the type of the segment that begins at the specified vertex.
156  // If the index is out of range estUnknown is returned
157  // Otherwise one of estArc, estLine, estCoincident is returned
158  virtual SegmentType segmentType (OdUInt32 iIndex ) const;
159 
160 
161  // returns IBulgeSeg2D
162  virtual Result getSegmentAt (OdUInt32 iIndex, IBulgeSeg2D & rSegment ) const;
163 
164  // Returns coordinates of segment ends and a bulge value
165  virtual Result getSegmentAt (OdUInt32 iIndex,
166  OdGePoint2d & ptStart,
167  OdGePoint2d & ptEnd,
168  double & dBulge ) const;
169 
170  // Returns OdGeLineSeg2d corresponding to the segment given by iIndex
171  // Error code will be returned, if the segment's type is estArc
172  virtual Result getLineSegAt (OdUInt32 iIndex, OdGeLineSeg2d& geLine ) const;
173 
174  // Returns OdGeCircArc2d corresponding to the segment given by iIndex
175  // Error code will be returned, if the segment's type is not estArc
176  virtual Result getArcSegAt (OdUInt32 iIndex, OdGeCircArc2d& geArc ) const;
177 
178 
179  // Returns a point given by iIndex
180  virtual Result getPointAt (OdUInt32 iIndex, OdGePoint2d & ptPoint ) const;
181 
182  // Returns a bulge value of the segment given by the iIndex
183  virtual Result getBulgeAt (OdUInt32 iIndex, double & dBulge ) const;
184 
185  // Returns vertex data: starting point, bulge and metadata of corresponding segment
186  virtual Result getVertexAt(OdUInt32 iIndex, OdGePoint2d * pptPoint, double * pdBulge = 0, Attributes2D* pAttr = 0 ) const;
187 
188  // Returns internal angle of vertex vectors, given by the iIndex
189  virtual Result getInternalAngleAt( OdUInt32 iIndex, double & dAngle ) const;
190 
191  // Updates existing point coordinates
192  virtual Result setPointAt (OdUInt32 iIndex, const OdGePoint2d & ptPoint );
193 
194  // Updates existing bulge value
195  virtual Result setBulgeAt (OdUInt32 iIndex, double dBulge );
196 
197  // Updates existing point and bulge values
198  virtual Result setVertexAt (OdUInt32 iIndex, const OdGePoint2d & ptPoint, double dBulge );
199 
200  // Reset the contour
201  virtual void reset();
202 
203  // Makes capacity of the vertex vector >= iReservedSize
204  // Number of vertices is not changed
205  virtual void reserveVertices( OdUInt32 iReservedSize );
206 
207  // Returns attributes for given segment
208  virtual const Attributes2D& attributesAt(OdUInt32 iIndex ) const;
209 
210  // Returns attributes for given segment for update
212 
213  // Updates attributes for given segment
214  virtual Result setAttributesAt(OdUInt32 iIndex, const Attributes2D& rAttr );
215 
216  // Returns metadata for given segment or 0
217  virtual OdIntPtr metadataAt (OdUInt32 iIndex ) const;
218 
219  // Updates metadata for given segment
220  virtual Result setMetadataAt (OdUInt32 iIndex, OdIntPtr uNewData );
221 
222  // Adds a vertex at the specified index.
223  // The index should be <= numVerts()
224  // If it is equal to numVerts(), a new vertex will be appended to the array,
225  // otherwise it'll be inserted before the old iIndex vertex.
226  virtual Result addVertexAt (OdUInt32 iIndex, const OdGePoint2d& ptStart, double dBulge = 0.0, const Attributes2D& rAttr = Attributes2D::kNull );
227 
228  // Appends a new starting point and a bulge value.
229  // The bulge value relates to the segment starting at the point.
230  virtual Result appendVertex (const OdGePoint2d& ptStart, double dBulge = 0.0, const Attributes2D& rAttr = Attributes2D::kNull );
231 
232  // Appends vertex data from vecSource to this contour
233  virtual Result appendVertices ( const OdGePoint2dArray & vecSource );
234 
235  // Appends rSeg to this contour.
236  // Returns erPointNotOnThis if rSeg.startPt() is not equal to this->endPoint().
237  // if bShiftToHit is true, the rSeg is shifted and the operation succeedes
238  virtual Result appendSegment ( const IBulgeSeg2D & rSeg, bool bShiftToHit = false, const OdGeTol& gTol = FMGeGbl::gTol );
239 
240  // Appends new segment to this contour ( updates bulge and metadata at the last vertex and
241  // appends new vertex with zero bulge and data)
242  // Returns erEmptyContour if there are no vertices in the contour
243  // Note: if the contour is closed, the last (closing) segment is wiped out
244  virtual Result appendSegment (double dBulge, const OdGePoint2d& ptNewEnd, const Attributes2D& rAttr = Attributes2D::kNull );
245 
246 
247  // Appends rCont to this contour ( "closed" flags are ignored )
248  // Returns erPointNotOnThis if rCont.startPoint is not equal to the end of this (open) contour
249  // If bCloseGap is true, a segment, connecting the points is inserted and
250  // the return code is erWarnPointNotOnThis
251  virtual Result appendContour ( const IContour2D & rCont, bool bCloseGap = false, double dMaxGap = 1e99 );
252 
253 
254  // Removes a vertex (and a corresponding segment).
255  // Bulge values of the other segments are left intact.
256  virtual Result removeVertexAt (OdUInt32 iIndex );
257 
258 
259 
261  //
262  // 2. Parameterization and arbitrary point access
263  //
264 
265 
266  // There are 3 ways to pick some (non-vertex) point on the contour:
267  // a) use an integer index to get a segment and then
268  // use parameter on the segment (GeLine or GeArc).
269  // b) use a distance along the curve from the starting point.
270  // c) use a "parameter" value.
271  //
272  // The last way is the fastest (and preferred in most cases) because of
273  // the "parameter" structure:
274  // dParam = startParam() + iIndex * (dOffsetOnSegment/dSegmentLength)
275  //
276  // So the point given by parameter value can be found at constant time.
277 
278 
279  // Returns starting point of the contour, if the contour is not empty
280  virtual Result getStartPoint(OdGePoint2d & ptPoint ) const;
281 
282  // Returns ending point of the contour, if the contour is not empty.
283  // The ptPoint is equal to the starting point, if the contour is closed.
284  virtual Result getEndPoint (OdGePoint2d & ptPoint ) const;
285 
286 
287  // Returns the length of the contour
288  virtual double length() const;
289 
290 
291  // returns tangent vector at the parameter
292  virtual Result getTangent (double dParam, OdGeVector2d& vTangent ) const;
293 
294  // Returns a point given by a parameter value
295  virtual Result getPoint (double dParam, OdGePoint2d& ptPoint ) const;
296 
297  // Returns a point given by a distance along the curve from the starting point
298  virtual Result getPointAtDist (double dDist, OdGePoint2d& ptPoint ) const;
299 
300  // Converts parameter value to the distance from start along the curve
301  virtual Result getDistAtParam (double dParam, double& dDist ) const;
302 
303  // Converts distance from start to parameter value
304  virtual Result getParamAtDist (double dDist, double& dParam ) const;
305 
306 
307  //virtual Result getParamAtPoint(const OdGePoint2d& ptPoint, double& dParam) const;
308  //virtual Result getDistAtPoint (const OdGePoint2d& ptPoint, double& dDist) const;
309 
310 
312  // Distance along the contour and closed contours
313 
314  // Convert dParam to [0, endParam() ) range (on closed contours)
315  // and returns erOk, if the dParam is valid
316  virtual Result getNormalizedParam( double & dParam ) const;
317 
318  // Convert dDist to [0, length() ) range (on closed contours)
319  // and returns erOk, if the dDist is valid
320  virtual Result getNormalizedDist( double & dDist ) const;
321 
322  // Returns true, if the parameters are valid and equal (after normalization) with given tolerance
323  // should not be called on invalid parameters !
324  // ToDo: dParam tolerance!!!
325  virtual bool areEqualParams( double dParam1, double dParam2, const double dTol = 1e-10 ) const;
326 
327  // Returns true, if the distances are valid and equal (after normalization) with given tolerance
328  // returns false, if the params are not equal or not valid
329  virtual bool areEqualDists ( double dDist1, double dDist2, const double dTol = FMGeGbl::gTol.equalPoint() ) const;
330 
331 
332  // Get signed length of the shortest way btw the points 1 and 2.
333  // The points are given by distances along the curve
334  virtual double signedMinDist ( double dDist1, double dDist2 ) const;
335 
336  // Get signed length of the shortest way btw the points 1 and 2.
337  // The points are given by parameters on the curve
338  virtual double signedMinDistByParams( double dParam1, double dParam2 ) const;
339 
340 
341 
343  //
344  // 3. Geometrical Queries
345  //
346 
347 
348  // Adds geometrical extents of the contour to geExtents
349  virtual Result addExtents(OdGeExtents2d& geExtents ) const;
350 
351 
352  // Returns signed area of the contour. (positive for CCW contours)
353  // In open contours the first and last vertices are considered
354  // to be connected with a straight line.
355  virtual double signedArea() const;
356 
357  // returns true, if the contour is convex
358  // end false if otherwise
359  virtual bool isConvex() const;
360 
361  // returns internal point of the closed contour (contour orientation is ignored)
362  // If succeeded this->contains( rPoint, gTol ) will return true
363  virtual Result getInternalPoint( OdGePoint2d& rPoint, const OdGeTol& gTol = FMGeGbl::gTol ) const;
364 
365  // returns true, if the point lies on the contour
366  // *dParam stores the parameter of the point
367  virtual bool isOn( const OdGePoint2d & ptTest, double * pdParam = 0,
368  const OdGeTol & gTol = FMGeGbl::gTol ) const;
369 
370  // returns parameter of a point on the curve, which is closest to the ptTest
371  virtual double nearestParam( const OdGePoint2d & ptTest, OdGePoint2d * ptNearest = 0 ) const;
372 
373 
374  // Returns true if the point lies inside the contour or on it's border.
375  // Contour must be closed.
376  // pbOnBorder is true, if the point lies on the border of the contour
377  // Note: the contour is considered to be non-oriented.
378  virtual bool contains( const OdGePoint2d &rPoint, bool * pbOnBorder = 0,
379  const OdGeTol & gTol = FMGeGbl::gTol) const;
380 
381 
382  // Returns whether the contour intersects itself.
383  // Works O( N log N ) at the average
384  virtual bool isSelfIntersecting(const OdGeTol& gTol = FMGeGbl::gTol, bool bExcludeTouch = false ) const;
385 
386  // Returns whether this contour is closed and coincides with a directional
387  // boundary of some open 2D-region.
388  virtual bool isValidRegion( const OdGeTol& gTol = FMGeGbl::gTol ) const;
389 
390  virtual bool isInsideContour(const IContour2D& c2dOuter, bool fAllowBordersTouch = false, const OdGeTol& gTol = FMGeGbl::gTol) const;
391 
392  // Returns number of intersections
393  // and appends Intersection data to the vecPoints vector
394  // Note: some intersection points (esp. on segment bounds) can coincide
395  virtual OdUInt32 intersect( const IBulgeSeg2D & rSegB,
396  std::vector< Intersection > & vecPoints,
397  const OdGeTol & gTol = FMGeGbl::gTol ) const;
398 
399  // Returns number of intersections
400  // and appends Intersection data to the vecPoints vector
401  // Note: some intersection points (esp. on segment bounds) can coincide
402  virtual OdUInt32 intersect( const IContour2D& rContB,
403  std::vector< Intersection > & vecPoints,
404  const OdGeTol & gTol = FMGeGbl::gTol ) const;
405 
406  // Intersects this contour with an infinite line
407  // Returns number of intersections
408  // and APPENDS Intersection data to the vecPoints vector
409  // Note: some intersection points (esp. on segment bounds) can coincide
411  const OdGePoint2d& ptLineOrigin,
412  const OdGeVector2d& vLineDir,
413  std::vector< Intersection > & vecPoints,
414  const OdGeTol & gTol = FMGeGbl::gTol ) const;
415 
416 
418  //
419  // 4. Transformations
420  //
421 
422  // Transforms the contour
423  virtual Result transformBy(const OdGeMatrix2d& geMatrix,
424  const DeviationParams& devDeviation = FMGeGbl::gDefDev );
425 
426  // Reverses the contour.
427  virtual void reverse();
428 
429  // Deletes redundant segments that have length = 0.
430  virtual void deleteCoincident( const OdGeTol & gTol = FMGeGbl::gTol );
431 
432  // Merges adjacent segments that lie on the same line or arc
433  // emfMergeArcs - Merge circular segments
434  // emfIgnoreMetadata - Merge segments with different metadata
435  // emfMergeOrigin - Merge first and last segments of a closed contour
436  virtual void mergeSegments( int iMergeFlags = 0, const OdGeTol & gTol = FMGeGbl::gTol );
437 
438  // Explodes all arc segments to lines.
439  // Facet deviation defines the maximum distance from the chord to the arc.
440  virtual Result explodeTo( IContour2D & rDestCont,
441  const DeviationParams& devDeviation = FMGeGbl::gDefDev,
442  OdIntPtr uArcMetadata = 0 ) const;
443 
444 
446 
447 
448  // Adds a vertex corresponding to the specified parameter into the contour, if
449  // the vertex does not exist.
450  // Returns index of the created/existing vertex or OdUInt32(-1), if the dParam is not valid.
451  // Note: insertion/deletion of a vertex at dParam invalidates all parameters > dParam
452  virtual OdUInt32 createVertexAt( double dParam, const OdGeTol & gTol = FMGeGbl::gTol );
453 
454  // Adds vertices at the specified parameters into the contour, if
455  // the vertices do not exist.
456  virtual Result createVerticesAt( const std::vector<double> & vecParams, const OdGeTol & gTol = FMGeGbl::gTol );
457 
458 
459  // returns sub-contour given by 2 parameters
460  // Note: if (dStartParam > dEndParam) the rSubContour will have opposite direction
461  virtual Result getSubContour(double dStartParam, double dEndParam,
462  IContour2D & rSubContour, const OdGeTol & gTol = FMGeGbl::gTol ) const;
463 
464  // appends sub-contour to rSubContour, if possible
465  virtual Result appendSubContourTo(double dStartParam, double dEndParam,
466  IContour2D & rSubContour, const OdGeTol & gTol = FMGeGbl::gTol ) const;
467 
468  // Divides this contour into sets of contours that lie to the left of the given line and to the right.
469  // Note: if OdGeLinearEnd2d can be an infinite of a finite line, depending
470  // on it`s class: OdGeLine2d or OdGeLineSeg2d
471  //virtual Result splitByLine( const OdGeLinearEnt2d& rLine,
472  // AECProfile& rLeftSide, AECProfile& rRightSide,
473  // const OdGeTol & gTol = FMGeGbl::gTol ) const;
474 
475 
476  virtual Result replaceSubContourTo( IContour2D& rDest, const IContour2D & rSubContour, const OdGeTol & gTol = FMGeGbl::gTol ) const;
477 
479 //
480 // Internal implementation methods
481 //
482 protected:
483 
484  Result _param2IdxParam( double dParam, OdUInt32 & iIndex, double & dSegParam ) const;
485  Result _dist2IdxParam ( double dDist, OdUInt32 & iIndex, double & dSegParam ) const;
486  Result _param2dist ( double dParam, double & dDist ) const;
487 
488  Result _normalizeParam( double & dParam ) const;
489 
490  Result _createVerticesAt( OdUInt32 uCount, const double * pdParams, const OdGeTol & gTol );
491 
492  Result _getSubSegment ( OdUInt32 iIndex, double dStartOffs, double dEndOffs, IBulgeSeg2D & rDestSeg ) const;
493 
494  Result _paramRange2IdxParams( const double dParamA, const double dParamB,
495  OdUInt32& uIdxA, double& dSegParamA, OdUInt32& uIdxB, double& dSegParamB,
496  OdUInt32& iNumPeriodsAB, const double dParamTol = DBL_EPSILON ) const;
497 
498  Result _appendSubContourTo(double dStartParam, double dEndParam, IContour2D & rSubContour, const OdGeTol & gTol ) const;
499 
500 
501  inline bool _isEqualToThis( const IContour2D & rC ) const
502  {
503  return ((const IContour2D *)this) == &rC;
504  }
505 };
506 
507 
508 
511 //
512 //
513 // IMPLEMENTATiON
514 
515 
516 
517 template < class TContourData >
519 {
520  if ( this == &rSrcCont )
521  return;
522 
523  OdUInt32 iNumVerts = rSrcCont.numVerts();
524  bool bClosed = rSrcCont.isClosed();
525 
526  this->_reset( iNumVerts, bClosed );
527 
528  if ( iNumVerts > 0 )
529  {
530  for (OdUInt32 iVert = 0; iVert < iNumVerts; iVert++ )
531  {
532  TVertexData & rVert = this->_vertex( iVert );
533 
534  Result eRes = erOk;
535  eRes = rSrcCont.getVertexAt( iVert, & rVert.point(), & rVert.bulge(), & rVert.attributes() );
536  FMGE_ASSERT( isOk(eRes) );
537  }
538  }
539 
540  this->_setModifiedAll();
541 }
542 
543 
544 template < class TContourData >
546 {
547  FMGE_FAULT("Not Implemented");
548  return 0;
549 }
550 
551 
552 template < class TContourData >
554 {
555  OdUInt32 uNumVerts = this->_numVerts();
556 
557  if ( uNumVerts < 2 )
558  return false;
559 
560  if ( ! this->_vertex( 0 ).point().isEqualTo( this->_vertex( uNumVerts - 1 ).point(), gTol ) )
561  return false;
562 
563  this->_removeVertices( uNumVerts - 1 );
564  this->_setClosed( true );
565 
566  return true;
567 }
568 
569 
570 template < class TContourData >
572 {
573  OdUInt32 iNumSeg = this->_numSegments();
574 
575  TImplSeg2D ImplSeg;
576  for (OdUInt32 iSeg = 0; iSeg<iNumSeg; iSeg++ )
577  {
578  this->_getSegment( iSeg, ImplSeg );
579  if ( ImplSeg.type() == estArc )
580  return true;
581  }
582 
583  return false;
584 }
585 
586 
587 
588 
589 template < class TContourData >
591 {
592  TImplSeg2D Seg;
593  if ( isError( this->_getSegment( iIndex, Seg ) ) )
594  return estUnknown;
595 
596  return Seg.type();
597 }
598 
599 
600 template < class TContourData >
602 {
603  if ( iIndex < this->_numVerts() )
604  return this->_vertex( iIndex ).attributes();
605 
606  return Attributes2D::kNull;
607 }
608 
609 template < class TContourData >
611 {
612  if ( iIndex < this->_numVerts() )
613  return this->_vertex( iIndex ).attributes();
614 
615  return nullAttributesForUpdate();
616 }
617 
618 template < class TContourData >
620 {
621  if ( iIndex < this->_numVerts() )
622  {
623  this->_vertex( iIndex ).attributes() = rAttr;
624  return erOk;
625  }
626 
627  return erInvalidIndex;
628 }
629 
630 template < class TContourData >
632 {
633  OdIntPtr uData = 0; //FELIX_CHANGE
634 
635  if ( iIndex < this->_numVerts() )
636  uData = this->_vertex( iIndex ).attributes().metadata();
637 
638  return uData;
639 }
640 
641 template < class TContourData >
643 {
644  Result eRes = erOk;
645 
646  if ( iIndex < this->_numVerts() )
647  this->_vertex( iIndex ).attributes().metadata() = uNewData;
648  else
649  eRes = erInvalidIndex;
650 
651  return eRes;
652 }
653 
654 
655 //template < class TContourData >
656 //Result TContour2DImpl<TContourData>::setAllMetadata (OdUInt32 uNewData, OdUInt32 uBitsToModify )
657 //{
658 // OdUInt32 iNumVerts = this->_numVerts();
659 // if ( iNumVerts <= 0 )
660 // return erOk;
661 //
662 // if ( 0 == uBitsToModify )
663 // return erOk;
664 //
665 // OdUInt32 uAndMask = ~uBitsToModify;
666 // OdUInt32 uOrMask = (uNewData & uBitsToModify);
667 //
668 // for (OdUInt32 uVert = 0; uVert < iNumVerts; ++uVert )
669 // {
670 // OdUInt32 & rData = this->_vertex(uVert).attributes().metadata();
671 // rData &= uAndMask;
672 // rData |= uOrMask;
673 // }
674 //
675 // return erOk;
676 //}
677 
678 template < class TContourData >
680 {
681  TImplSeg2D ImplSeg;
682  Result eRes = this->_getSegment( iIndex, ImplSeg );
683  if ( isError( eRes ) )
684  return eRes;
685 
686  return worstResult( eRes, rSegment.set( ImplSeg ) );
687 }
688 
689 
690 
691 template < class TContourData >
693  OdGePoint2d & ptStart,
694  OdGePoint2d & ptEnd,
695  double & dBulge ) const
696 {
697  TImplSeg2D ImplSeg;
698  Result eRes = this->_getSegment( iIndex, ImplSeg );
699  if ( isError( eRes ) )
700  return eRes;
701 
702  ptStart = ImplSeg._startPt();
703  ptEnd = ImplSeg._endPt();
704  dBulge = ImplSeg._bulge();
705  //uMetadata = ImplSeg._metadata();
706 
707  return eRes;
708 }
709 
710 
711 
712 template < class TContourData >
714 {
715  TImplSeg2D ImplSeg;
716  Result eRes = this->_getSegment( iIndex, ImplSeg );
717  if ( isError( eRes ) )
718  return eRes;
719 
720  return worstResult( eRes, ImplSeg.getLineSeg( geLine ) );
721 }
722 
723 
724 
725 template < class TContourData >
727 {
728  TImplSeg2D ImplSeg;
729  Result eRes = this->_getSegment( iIndex, ImplSeg );
730  if ( isError( eRes ) )
731  return eRes;
732 
733  return worstResult( eRes, ImplSeg.getArcSeg( geArc ) );
734 }
735 
736 
737 
738 template < class TContourData >
740 {
741  Result eRes = this->_normalizeIndex( iIndex );
742  if ( isError( eRes ) )
743  return eRes;
744 
745  ptPoint = this->_vertex(iIndex).point();
746  return eRes;
747 }
748 
749 
750 
751 template < class TContourData >
753 {
754  Result eRes = this->_normalizeIndex( iIndex );
755  if ( isError( eRes ) )
756  return eRes;
757 
758  dBulge = this->_vertex(iIndex).bulge();
759  return eRes;
760 }
761 
762 
763 template < class TContourData >
764 Result TContour2DImpl<TContourData>::getVertexAt(OdUInt32 iIndex, OdGePoint2d * pptPoint, double * pdBulge, Attributes2D * pAttr ) const
765 {
766  Result eRes = this->_normalizeIndex( iIndex );
767  if ( isError( eRes ) )
768  return eRes;
769 
770  const TVertexData & rVert = this->_vertex(iIndex);
771 
772  if ( pptPoint )
773  *pptPoint = rVert.point();
774 
775  if ( pdBulge )
776  *pdBulge = rVert.bulge();
777 
778  if ( pAttr )
779  *pAttr = rVert.attributes();
780 
781  return eRes;
782 }
783 
784 
785 template < class TContourData >
787 {
788  Result eRes = this->_normalizeIndex( iIndex );
789  if ( isError( eRes ) )
790  return eRes;
791 
792  OdUInt32 iSize = this->numSegments();
793  if( !this->_closed() && ( iIndex == 0 || iIndex == iSize-1 ) )
794  {
795  dAngle = 0.0;
796  return eRes;
797  }
798 
799  TImplSeg2D rSeg;
800  OdGeVector2d vA;
801  OdGeVector2d vB;
802 
803  this->_getSegment( iIndex, rSeg );
804  rSeg.getTangent( 0.0, vA );
805 
806  if( iIndex == 0 )
807  this->_getSegment( iSize-1, rSeg );
808  else
809  this->_getSegment( iIndex-1, rSeg );
810 
811  rSeg.getTangent( 1.0, vB );
812 
813  dAngle = vA.angleToCCW( vB.negate() );
814  if( dAngle < 0 )
815  dAngle = dAngle + Oda2PI;
816 
817  return eRes;
818 }
819 
820 
821 
822 template < class TContourData >
824 {
825  this->_reset();
826 }
827 
828 
829 
830 template < class TContourData >
832 {
833  this->_reserveVertices( iReservedSize );
834 }
835 
836 
837 
838 template < class TContourData >
840 {
841  Result eRes = this->_normalizeIndex( iIndex );
842  if ( isError( eRes ) )
843  return eRes;
844 
845  this->_vertex( iIndex ).point() = ptPoint;
846  this->_setModifiedVerts( iIndex );
847 
848  return eRes;
849 }
850 
851 
852 
853 template < class TContourData >
855 {
856  Result eRes = this->_normalizeIndex( iIndex );
857  if ( isError( eRes ) )
858  return eRes;
859 
860  this->_vertex( iIndex ).bulge() = dBulge;
861  this->_setModifiedSegs( iIndex );
862 
863  return eRes;
864 }
865 
866 
867 template < class TContourData >
868 Result TContour2DImpl<TContourData>::setVertexAt (OdUInt32 iIndex, const OdGePoint2d & ptPoint, double dBulge )
869 {
870  Result eRes = this->_normalizeIndex( iIndex );
871  if ( isError( eRes ) )
872  return eRes;
873 
874  TVertexData & rVert = this->_vertex( iIndex );
875  rVert.point() = ptPoint;
876  rVert.bulge() = dBulge;
877  this->_setModifiedVerts( iIndex );
878 
879  return eRes;
880 }
881 
882 
883 
884 template < class TContourData >
885 Result TContour2DImpl<TContourData>::addVertexAt(OdUInt32 iIndex, const OdGePoint2d& ptStart, double dBulge, const Attributes2D& rAttr )
886 {
887  return this->_insertVerticesAt( iIndex, 1, &ptStart, &dBulge, &rAttr );
888 }
889 
890 
891 
892 template < class TContourData >
893 Result TContour2DImpl<TContourData>::appendVertex (const OdGePoint2d& ptStart, double dBulge, const Attributes2D& rAttr)
894 {
895  return this->_insertVerticesAt( this->_numVerts(), 1, &ptStart, &dBulge, &rAttr );
896 }
897 
898 
899 
900 
901 
902 template < class TContourData >
904 {
905  if ( vecSource.empty() )
906  return erInvalidIndex;
907 
908  return this->_insertVerticesAt( this->_numVerts(), vecSource.size(), &(vecSource[0]) );
909 }
910 
911 
912 template < class TContourData >
913 Result TContour2DImpl<TContourData>::appendSegment ( const IBulgeSeg2D & rSeg, bool bShiftToHit, const OdGeTol& gTol )
914 {
915  if ( this->_empty() )
916  {
917  OdGePoint2d vPoints[2] = { rSeg.startPt(), rSeg.endPt() };
918  double vBulges[2] = { rSeg.bulge(), 0.0 };
919 
920  Result eRes = this->_insertVerticesAt( 0, 2, vPoints, vBulges );
921  if ( isOk(eRes) )
922  this->_vertex( 0 ).attributes() = rSeg.attributes();
923 
924  return eRes;
925  }
926 
927  // Contour is not empty
928  OdUInt32 iLastVert = this->_numVerts() - 1;
929 
930  TVertexData & rLastVert = this->_vertex( iLastVert );
931  const OdGePoint2d & ptEnd = rLastVert.point();
932 
933  const OdGePoint2d & rSegStart = rSeg.startPt();
934  OdGePoint2d ptSegEnd = rSeg.endPt();
935 
936  Result eRes = erOk;
937 
938  if ( !ptEnd.isEqualTo( rSegStart, gTol ) )
939  {
940  if ( !bShiftToHit )
941  return erPointNotOnThis;
942 
943  eRes = erWarnPointNotOnThis;
944 
945  // shift the end
946  ptSegEnd.x += ptEnd.x - rSegStart.x;
947  ptSegEnd.y += ptEnd.y - rSegStart.y;
948  }
949 
950  double dBulge = rSeg.bulge();
951  if ( dBulge != rLastVert.bulge() )
952  {
953  rLastVert.bulge() = dBulge;
954  this->_setModifiedVerts( iLastVert );
955  }
956 
957  rLastVert.attributes() = rSeg.attributes();
958  eRes = worstResult( eRes, this->_insertVerticesAt( iLastVert+1, 1, &ptSegEnd ) );
959 
960  return eRes;
961 }
962 
963 
964 
965 template < class TContourData >
966 Result TContour2DImpl<TContourData>::appendSegment(double dBulge, const OdGePoint2d& ptNewEnd, const Attributes2D& rAttr )
967 {
968  if ( this->_empty() )
969  return erEmptyContour;
970 
971  // Contour is not empty
972  OdUInt32 iLastVert = this->_numVerts() - 1;
973  TVertexData & rLastVert = this->_vertex( iLastVert );
974 
975  // update bulge if different
976  if ( dBulge != rLastVert.bulge() )
977  {
978  rLastVert.bulge() = dBulge;
979  this->_setModifiedVerts( iLastVert );
980  }
981 
982  // update metadata
983  rLastVert.attributes() = rAttr;
984 
985  // append the new vertex
986  return this->_insertVerticesAt( iLastVert+1, 1, &ptNewEnd );
987 }
988 
989 
990 template < class TContourData >
991 Result TContour2DImpl<TContourData>::appendContour ( const IContour2D & rCont, bool bCloseGap, double dMaxGap )
992 {
993  FMGE_ASSERT( !_isEqualToThis( rCont ) );
994  if ( _isEqualToThis( rCont ) )
995  return erInvalidArgs;
996 
997  if ( rCont.isEmpty() )
998  return erOk;
999 
1000  if ( this->_empty() )
1001  {
1002  set( rCont );
1003  return erOk;
1004  }
1005 
1006  Result eBigRes = erOk;
1007 
1008  OdGePoint2d ptContStart;
1009  Result eRes = rCont.getStartPoint( ptContStart );
1010  if ( isError( eRes ) )
1011  return eRes;
1012 
1013  // this contour is not empty
1014  OdUInt32 iLastVert = this->_numVerts() - 1;
1015 
1016  TVertexData & rLastVert = this->_vertex( iLastVert );
1017  const OdGePoint2d & ptEnd = rLastVert.point();
1018 
1019  if ( ! ptEnd.isEqualTo( ptContStart, FMGeGbl::gTol ) )
1020  {
1021  if ( !bCloseGap || dMaxGap < ptEnd.distanceTo( ptContStart ) )
1022  return erPointNotOnThis;
1023 
1024  eBigRes = erWarnPointNotOnThis;
1025 
1026  // close the gap with a linear segment
1027 
1028  if ( rLastVert.bulge() != 0.0 )
1029  {
1030  rLastVert.bulge() = 0.0;
1031  this->_setModifiedVerts( iLastVert );
1032  }
1033 
1034  ++iLastVert; // start appending from the next vertex
1035  }
1036 
1037  OdUInt32 iNumContVerts = rCont.numVerts();
1038  FMGE_ASSERT( iNumContVerts > 0 );
1039 
1040  OdUInt32 iModifiedVert = iLastVert;
1041  this->_resize( iLastVert + iNumContVerts );
1042 
1043  for (OdUInt32 iContVert = 0 ; iContVert < iNumContVerts; ++iContVert, ++iLastVert )
1044  {
1045  TVertexData & rVert = this->_vertex( iLastVert );
1046 
1047  eRes = rCont.getVertexAt( iContVert, & rVert.point(), & rVert.bulge(), & rVert.attributes() );
1048  FMGE_ASSERT( isOk(eRes) );
1049  eBigRes = worstResult( eBigRes, eRes );
1050  }
1051  this->_setModifiedVerts( iModifiedVert, iNumContVerts );
1052 
1053  return eBigRes;
1054 }
1055 
1056 
1057 
1058 
1059 
1060 template < class TContourData >
1062 {
1063  return this->_removeVertices( iIndex );
1064 }
1065 
1066 
1067 
1068 
1069 template < class TContourData >
1071 {
1072  if ( this->_empty() )
1073  return erInvalidIndex;
1074 
1075  ptPoint = this->_vertex(0).point();
1076  return erOk;
1077 }
1078 
1079 
1080 
1081 
1082 template < class TContourData >
1084 {
1085  if ( this->_empty() )
1086  return erInvalidIndex;
1087 
1088  OdUInt32 iIndex = this->_closed() ? 0 : (this->_numVerts()-1);
1089 
1090  ptPoint = this->_vertex(iIndex).point();
1091  return erOk;
1092 }
1093 
1094 
1095 
1096 
1097 
1098 template < class TContourData >
1100 {
1101  OdUInt32 iNumSeg = this->_numSegments();
1102 
1103  double dL = 0;
1104 
1105  TImplSeg2D ImplSeg;
1106  for (OdUInt32 iSeg = 0; iSeg<iNumSeg; iSeg++ )
1107  {
1108  this->_getSegment( iSeg, ImplSeg );
1109  dL += ImplSeg.length();
1110  }
1111 
1112  return dL;
1113 }
1114 
1115 
1116 
1117 
1118 
1119 template < class TContourData >
1120 Result TContour2DImpl<TContourData>::_param2IdxParam(double dParam, OdUInt32 & iIndex, double & dSegParam ) const
1121 {
1122  long iNumSegs = this->_numSegments();
1123  if ( iNumSegs <= 0 )
1124  {
1125  iIndex = 0;
1126  dSegParam = 0;
1127  return erEmptyContour;
1128  }
1129 
1130  const double dParamTol = 4*DBL_EPSILON;
1131 
1132  double dIdx;
1133  double dNormalizedParam = ::modf( dParam, &dIdx );
1134  long iNormalizedIdx = long( ::floor( dIdx + 0.5 ) );
1135  if ( dNormalizedParam < 0 )
1136  {
1137  dNormalizedParam += 1;
1138  iNormalizedIdx -= 1;
1139  }
1140 
1141  Result eRes = erOk;
1142 
1143  if ( iNormalizedIdx >= long(iNumSegs) )
1144  {
1145  if ( iNormalizedIdx==iNumSegs && dNormalizedParam <= dParamTol )
1146  {
1147  iNormalizedIdx--;
1148  dNormalizedParam = 1.0;
1149  }
1150  else if ( this->_closed() )
1151  {
1152  iNormalizedIdx = ::ldiv( iNormalizedIdx, iNumSegs ).rem;
1153  FMGE_ASSERT( OdUInt32(iNormalizedIdx) < OdUInt32(iNumSegs) );
1154  }
1155  else
1156  eRes = erParamBounds;
1157  }
1158  else if ( iNormalizedIdx < 0 )
1159  {
1160  if ( iNormalizedIdx== -1 && dNormalizedParam >= (1.0-dParamTol) )
1161  {
1162  iNormalizedIdx++;
1163  dNormalizedParam = 0.0;
1164  }
1165  else if ( this->_closed() )
1166  {
1167  iNormalizedIdx = ::ldiv( iNormalizedIdx, iNumSegs ).rem + iNumSegs;
1168  FMGE_ASSERT( OdUInt32(iNormalizedIdx) < OdUInt32(iNumSegs) );
1169  }
1170  else
1171  eRes = erParamBounds;
1172  }
1173 
1174  dSegParam = dNormalizedParam;
1175  iIndex = OdUInt32( iNormalizedIdx );
1176 
1177  FMGE_ASSERT( dSegParam >= -DBL_EPSILON && dSegParam <= (1.0+DBL_EPSILON) );
1178 
1179  return eRes;
1180 }
1181 
1182 
1183 
1184 
1185 template < class TContourData >
1186 Result TContour2DImpl<TContourData>::_dist2IdxParam ( double dDist, OdUInt32 & iIndex, double & dSegParam ) const
1187 {
1188  iIndex = 0;
1189  dSegParam = 0;
1190 
1191  OdUInt32 iNumSegs = this->_numSegments();
1192  if ( iNumSegs <= 0 )
1193  return erEmptyContour;
1194 
1195  const double dTol = FMGeGbl::gTol.equalVector();
1196 
1197  bool bClosed = this->_closed();
1198 
1199  bool bDistNormalized = false;
1200 
1201  if ( dDist < 0.0 )
1202  {
1203  if ( !bClosed )
1204  return ( dDist >= -dTol ) ? erOk : erParamBounds;
1205 
1206  double dLength = ((IContour2D*)this)->length(); // virtual method
1207  if ( dLength <= dTol )
1208  return ( dDist >= -dTol ) ? erOk : erParamBounds; // zero-length contour
1209 
1210  // in closed contours we should convert dDist to range [0, dLength)
1211  bDistNormalized = true;
1212  dDist -= ::floor( dDist/dLength ) * dLength;
1213  if (dDist < 0.0 || dDist >= dLength )
1214  return erOk; // dDist = 0.0;
1215  }
1216 
1217  for(;;)
1218  {
1219  double dCurDist = 0;
1220  OdUInt32 iSeg = 0;
1221 
1222  TImplSeg2D ImplSeg;
1223  do
1224  {
1225  this->_getSegment( iSeg, ImplSeg );
1226  double dL = ImplSeg.length();
1227  if ( (dCurDist + dL) > dDist )
1228  {
1229  // We've just found the segment
1230  iIndex = iSeg;
1231  dSegParam = (dDist - dCurDist)/dL;
1232  return erOk;
1233  }
1234 
1235  dCurDist += dL;
1236 
1237  } while ( ++iSeg < iNumSegs );
1238 
1239  // Segment was not found
1240  if ( bDistNormalized )
1241  {
1242  FMGE_FAULT( "It seems that contour::length() returned a wrong value!" );
1243  return erParamBounds;
1244  }
1245 
1246  // dCurDist == length
1247  double dLength = dCurDist;
1248 
1249  if ( !this->_closed() || dLength <= dTol )
1250  {
1251  iIndex = iNumSegs - 1; // Last segment
1252  dSegParam = 1.0; // Last point
1253  return ( dDist - dLength ) <= dTol ? erOk : erParamBounds;
1254  }
1255 
1256  // convert dDist to range [0, dLength)
1257  bDistNormalized = true;
1258  dDist -= ::floor( dDist/dLength ) * dLength;
1259  if (dDist < 0.0 || dDist >= dLength )
1260  return erOk; // dDist = 0.0;
1261 
1262  } // try again with normalized dDist
1263 }
1264 
1265 
1266 
1267 template < class TContourData >
1268 Result TContour2DImpl<TContourData>::_param2dist ( double dParam, double & dDist ) const
1269 {
1270  OdUInt32 iIndex;
1271  double dSegParam;
1272  Result eRes = _param2IdxParam( dParam, iIndex, dSegParam );
1273  if ( isError(eRes) )
1274  return eRes;
1275 
1276  double dSumLen = 0;
1277 
1278  TImplSeg2D ImplSeg;
1279 
1280  // Add offset from the iIndex segment
1281  if ( dSegParam!= 0.0 )
1282  {
1283  this->_getSegment( iIndex, ImplSeg );
1284  dSumLen += ImplSeg.length()*dSegParam;
1285  }
1286 
1287  // Add lengths of all segments < iIndex
1288  for (OdUInt32 iSeg = 0; iSeg<iIndex; iSeg++ )
1289  {
1290  this->_getSegment( iSeg, ImplSeg );
1291  dSumLen += ImplSeg.length();
1292  }
1293 
1294  dDist = dSumLen;
1295  return eRes;
1296 }
1297 
1298 
1299 
1300 template < class TContourData >
1302 {
1303  OdUInt32 iIndex;
1304  double dSegParam;
1305  TImplSeg2D ImplSeg;
1306 
1307  Result eRes = _param2IdxParam( dParam, iIndex, dSegParam );
1308  if ( isError( eRes )
1309  || isError( eRes = worstResult( eRes, this->_getSegment( iIndex, ImplSeg ) ) )
1310  )
1311  {
1312  vTangent = OdGeVector2d::kIdentity;
1313  return eRes;
1314  }
1315 
1316  return worstResult( eRes, ImplSeg.getTangent( dSegParam, vTangent ) );
1317 }
1318 
1319 
1320 
1321 
1322 template < class TContourData >
1324 {
1325  // Handle empty and 1-point contours
1326  if ( this->_numVerts()<=1 )
1327  {
1328  if ( !this->_empty() && OdZero(dParam) )
1329  {
1330  ptPoint = this->_vertex(0).point();
1331  return erOk;
1332  }
1333  ptPoint = OdGePoint2d::kOrigin;
1334  return this->_empty() ? erEmptyContour : erParamBounds;
1335  }
1336 
1337  OdUInt32 iIndex;
1338  double dSegParam;
1339  TImplSeg2D ImplSeg;
1340 
1341  Result eRes = _param2IdxParam( dParam, iIndex, dSegParam );
1342  if ( isError( eRes )
1343  || isError( eRes = worstResult( eRes, this->_getSegment( iIndex, ImplSeg ) ) )
1344  )
1345  {
1346  ptPoint = OdGePoint2d::kOrigin;
1347  return eRes;
1348  }
1349 
1350  return worstResult( eRes, ImplSeg.getPoint( dSegParam, ptPoint ) );
1351 }
1352 
1353 
1354 
1355 
1356 template < class TContourData >
1358 {
1359  ptPoint = OdGePoint2d::kOrigin;
1360 
1361  // Handle empty and 1-point contours
1362  if ( this->_numVerts() <= 1 )
1363  {
1364  if ( !this->_empty() && OdZero( dDist, FMGeGbl::gTol.equalVector() ) )
1365  {
1366  ptPoint = this->_vertex(0).point();
1367  return erOk;
1368  }
1369  return this->_empty() ? erEmptyContour : erParamBounds;
1370  }
1371 
1372  double dParam = 0;
1373  Result eRes = ((IContour2D*)this)->getParamAtDist( dDist, dParam ); // virtual
1374  if ( isError(eRes) )
1375  return eRes;
1376 
1377  OdUInt32 iNumSegs = this->_numSegments();
1378  if ( dParam < 0.0 || dParam > iNumSegs )
1379  {
1380  FMGE_FAULT( "Contour::getParamAtDist returned an invalid parameter value." );
1381  return erParamBounds;
1382  }
1383 
1384  OdUInt32 iIndex = OdUInt32( ::floor(dParam) );
1385  if ( iIndex == iNumSegs )
1386  --iIndex;
1387 
1388  TImplSeg2D ImplSeg;
1389  eRes = worstResult( eRes, this->_getSegment( iIndex, ImplSeg ) );
1390  if ( isError( eRes ) )
1391  return eRes;
1392 
1393  return worstResult( eRes, ImplSeg.getPoint( dParam - iIndex, ptPoint ) );
1394 }
1395 
1396 
1397 
1398 
1399 template < class TContourData >
1400 Result TContour2DImpl<TContourData>::getDistAtParam (double dParam, double& dDist ) const
1401 {
1402  return _param2dist( dParam, dDist );
1403 }
1404 
1405 
1406 
1407 template < class TContourData >
1408 Result TContour2DImpl<TContourData>::getParamAtDist (double dDist, double& dParam ) const
1409 {
1410  OdUInt32 iIndex;
1411  double dSegParam;
1412 
1413  Result eRes = _dist2IdxParam( dDist, iIndex, dSegParam );
1414  if ( isError( eRes ) )
1415  {
1416  dParam = 0;
1417  return eRes;
1418  }
1419 
1420  dParam = iIndex + dSegParam;
1421 
1422  return eRes;
1423 }
1424 
1425 
1426 
1427 
1428 
1429 template < class TContourData >
1431 {
1432  const double dParamEps = 1e-10; // ToDo: tolerance !!!
1433 
1434  int iNumSegs = this->_numSegments();
1435  if ( iNumSegs <= 0 )
1436  {
1437  if ( this->_empty() )
1438  return erEmptyContour;
1439 
1440  if ( ::fabs( dParam ) > dParamEps )
1441  return erParamBounds;
1442 
1443  dParam = 0;
1444  return erOk;
1445  }
1446 
1447  Result eRes = erOk;
1448 
1449  // In closed contours parameter is periodic
1450  if ( this->_closed() )
1451  {
1452  if ( dParam < 0.0 || dParam >= iNumSegs )
1453  {
1454  dParam -= ::floor(dParam/iNumSegs)*iNumSegs;
1455  if ( dParam < 0.0 || dParam >=iNumSegs )
1456  dParam = 0.0;
1457  }
1458  }
1459  else
1460  {
1461  if ( dParam < 0 )
1462  {
1463  // eRes = erWarnParamBounds;
1464  if ( dParam >= -dParamEps )
1465  dParam = 0.0;
1466  else
1467  eRes = erParamBounds;
1468  }
1469  else if ( dParam > iNumSegs )
1470  {
1471  // eRes = erWarnParamBounds;
1472  if ( dParam < (iNumSegs+dParamEps) )
1473  dParam = iNumSegs;
1474  else
1475  eRes = erParamBounds;
1476  }
1477  }
1478 
1479  return eRes;
1480 }
1481 
1482 
1483 template < class TContourData >
1485 {
1486  return _normalizeParam( dParam );
1487 }
1488 
1489 
1490 
1491 template < class TContourData >
1493 {
1494  Result eRes = erOk;
1495 
1496  double dLength = length();
1497 
1498  const double dTol = FMGeGbl::gTol.equalVector();
1499 
1500  if ( this->_closed() )
1501  {
1502  if ( dDist < 0.0 || dDist >= dLength )
1503  {
1504  if ( dLength > dTol )
1505  {
1506  dDist -= ::floor(dDist/dLength)*dLength;
1507  if ( dDist < 0.0 || dDist > dLength )
1508  dDist = 0;
1509  }
1510  else
1511  dDist = 0; // empty contour ???
1512  }
1513  }
1514  else // open
1515  {
1516  if ( dDist < 0 )
1517  {
1518  // eRes = erWarnParamBounds;
1519  if ( dDist >= -dTol )
1520  dDist = 0.0;
1521  else
1522  eRes = erParamBounds;
1523  }
1524  else if ( dDist > dLength )
1525  {
1526  // eRes = erWarnParamBounds;
1527  if ( dDist < (dLength + dTol) )
1528  dDist = dLength;
1529  else
1530  eRes = erParamBounds;
1531  }
1532  }
1533 
1534  return eRes;
1535 }
1536 
1537 
1538 template < class TContourData >
1539 bool TContour2DImpl<TContourData>::areEqualParams( double dParam1, double dParam2, const double dTol ) const
1540 {
1541  double dDelta = ::fabs( dParam2 - dParam1 );
1542 
1543  if ( this->_closed() )
1544  {
1545  OdUInt32 iNumSegs = this->_numSegments();
1546 
1547  if ( iNumSegs > 0 )
1548  {
1549  if ( dDelta > iNumSegs )
1550  dDelta -= ::floor(dDelta/iNumSegs)*iNumSegs;
1551 
1552  if ( 2.0*dDelta > iNumSegs )
1553  dDelta = iNumSegs - dDelta;
1554  }
1555  }
1556 
1557  return ( dDelta <= dTol );
1558 }
1559 
1560 
1561 template < class TContourData >
1562 bool TContour2DImpl<TContourData>::areEqualDists ( double dDist1, double dDist2, const double dTol ) const
1563 {
1564  double dDelta = ::fabs( dDist2 - dDist1 );
1565 
1566  if ( this->_closed() )
1567  {
1568  if ( dDelta <= dTol )
1569  return true; // do not evaluate length, if possible
1570 
1571  double dLength = length();
1572 
1573  if ( dLength > dTol )
1574  {
1575  if ( dDelta > dLength )
1576  dDelta -= ::floor(dDelta/dLength)*dLength;
1577 
1578  if ( 2.0*dDelta > dLength )
1579  dDelta = dLength - dDelta;
1580  }
1581  }
1582 
1583  return ( dDelta <= dTol );
1584 }
1585 
1586 
1587 template < class TContourData >
1588 double TContour2DImpl<TContourData>::signedMinDist( double dDist1, double dDist2 ) const
1589 {
1590  if ( ! this->_closed() )
1591  {
1592  // open contour
1593  return dDist2 - dDist1;
1594  }
1595 
1596  // closed contour
1597 
1598  const double dTol = odmin( 1e-10, FMGeGbl::gTol.equalPoint() );
1599 
1600  if ( OdEqual( dDist1, dDist2, dTol ) )
1601  return 0;
1602 
1603  double dLength = length();
1604 
1605  if ( dLength < dTol )
1606  return 0;
1607 
1608  if ( dDist1 < 0.0 || dDist1 >= dLength )
1609  dDist1 -= ::floor(dDist1/dLength)*dLength;
1610 
1611  if ( dDist2 < 0.0 || dDist2 >= dLength )
1612  dDist2 -= ::floor(dDist2/dLength)*dLength;
1613 
1614  bool bSwap = ( dDist1 > dDist2 );
1615  if (bSwap)
1616  std::swap( dDist1, dDist2 );
1617 
1618  double dDelta = dDist2 - dDist1;
1619 
1620  if ( dDelta > dLength/2 )
1621  dDelta = dLength - dDelta;
1622 
1623  return bSwap ? -dDelta : dDelta;
1624 }
1625 
1626 
1627 template < class TContourData >
1628 double TContour2DImpl<TContourData>::signedMinDistByParams( double dParam1, double dParam2 ) const
1629 {
1630  if ( dParam1 == dParam2 )
1631  return 0;
1632 
1633  double dDist1, dDist2;
1634  Result eRes = worstResult(
1635  getDistAtParam ( dParam1, dDist1 ),
1636  getDistAtParam ( dParam2, dDist2 ) );
1637  if ( isError( eRes ) )
1638  return DBL_MAX; // ???
1639 
1640  return signedMinDist( dDist1, dDist2 );
1641 }
1642 
1643 
1644 
1645 
1646 
1647 
1648 
1649 
1650 
1651 
1652 
1653 
1654 template < class TContourData >
1656 {
1657  if ( this->_empty() )
1658  return erOk;
1659 
1660  OdGeExtents2d myExts;
1661 
1662  OdUInt32 iNumSeg = this->_numSegments();
1663  if ( iNumSeg > 0 )
1664  {
1665  // Iterate through segments
1666 
1667  TImplSeg2D ImplSeg;
1668  for (OdUInt32 iSeg = 0; iSeg<iNumSeg; iSeg++ )
1669  {
1670  this->_getSegment( iSeg, ImplSeg );
1671  ImplSeg.addExtents( myExts );
1672  }
1673  }
1674  else
1675  {
1676  myExts.addPoint( this->_vertex(0).point() );
1677  }
1678 
1679  // extend myExts with a tolerance ?
1680 
1681  geExtents.addExt( myExts );
1682 
1683  return erOk;
1684 }
1685 
1686 
1687 
1688 
1689 template < class TContourData >
1691 {
1692  // Sum of area of all the segments in contour.
1693  double dSum = 0;
1694 
1695  OdUInt32 iNumSeg = this->_numSegments();
1696  if ( iNumSeg > 0 )
1697  {
1698  // Iterate through segments and sum doubled areas
1699 
1700  TImplSeg2D ImplSeg;
1701  for (OdUInt32 iSeg = 0; iSeg<iNumSeg; iSeg++ )
1702  {
1703  this->_getSegment( iSeg, ImplSeg );
1704  dSum += ImplSeg.integrate();
1705  }
1706 
1707  if ( !this->_closed() )
1708  {
1709  // Connect last and first point with a straight line and get integral value
1710  dSum += BulgeSeg2D( this->_vertex(iNumSeg).point(), this->_vertex(0).point() ).integrate();
1711  }
1712 
1713  // "integrate" returns doubled area...
1714  dSum *= 0.5;
1715  }
1716 
1717  return dSum;
1718 }
1719 
1720 template < class TContourData >
1722 {
1723  bool bResult = false;
1724 
1725  OdUInt32 iSize = this->numSegments();
1726  if( iSize > 1 && this->_closed() )
1727  {
1728  TImplSeg2D rSeg;
1729  this->_getSegment( iSize-1, rSeg );
1730 
1731  OdGeVector2d vA;
1732  OdGeVector2d vB;
1733  rSeg.getTangent( 1.0, vB );
1734 
1735  double dCrossProduct;
1736  OdUInt32 iFlag = 0;
1737 
1738  // vector product calculation for each vertexes
1739  for( OdUInt32 i = 0; i < iSize; i++ )
1740  {
1741 
1742  this->_getSegment( i, rSeg );
1743  rSeg.getTangent( 0.0, vA );
1744 
1745  /*
1746  cross (vector) product between two tangent lines (handling line and arc types)
1747  vectors A=(ax ay), B=(bx by)
1748  matrix [ ax ay;
1749  bx by ];
1750  determinant of this matrix = vector product = ax*by-ay*bx = |a|*|b|*sin(alfa).
1751  If sin( alfa ) < 0 ( inner angle alfa > 180 ) then det < 0.
1752  */
1753  dCrossProduct = vA.crossProduct( vB.negate() );
1754 
1755  // convex contour not have different signs of product
1756  if( dCrossProduct >= 0.0 )
1757  iFlag |= 1;
1758  else
1759  iFlag |= 2;
1760 
1761  // non convex (concave) case
1762  if( iFlag == 3 )
1763  return false;
1764 
1765  if( i < iSize-1 ) // updating segments
1766  vB = vA;
1767  }
1768  if( iFlag != 0 )
1769  bResult = true;
1770  }
1771  return bResult;
1772 }
1773 
1774 
1775 template < class TContourData >
1777 {
1778  return fast_getInternalPoint( *(const IContour2D*)this, rPoint, gTol );
1779 }
1780 
1781 
1782 
1783 template < class TContourData >
1784 bool TContour2DImpl<TContourData>::isOn( const OdGePoint2d & ptTest, double * pdParam, const OdGeTol & gTol) const
1785 {
1786  bool bOn = false;
1787  double dParam = 0;
1788 
1789  OdUInt32 iNumSeg = this->_numSegments();
1790  if ( iNumSeg > 0 )
1791  {
1792  // Iterate through segments and find the first match
1793 
1794  TImplSeg2D ImplSeg;
1795  for (OdUInt32 iSeg = 0; iSeg<iNumSeg; iSeg++ )
1796  {
1797  this->_getSegment( iSeg, ImplSeg );
1798 
1799  double dSegParam;
1800  bOn = ImplSeg.isOn( ptTest, &dSegParam, gTol );
1801  if (bOn)
1802  {
1803  dParam = iSeg + dSegParam;
1804  break;
1805  }
1806  }
1807  }
1808  else if ( !this->_empty() )
1809  {
1810  // single point contour
1811  bOn = BulgeSeg2D( this->_vertex(0).point(), this->_vertex(0).point() ).isOn( ptTest, &dParam, gTol);
1812  }
1813 
1814  if (pdParam)
1815  *pdParam = dParam;
1816 
1817  return bOn;
1818 }
1819 
1820 
1821 
1822 template < class TContourData >
1823 double TContour2DImpl<TContourData>::nearestParam( const OdGePoint2d & ptTest, OdGePoint2d * pptNearest) const
1824 {
1825  if ( this->_empty() )
1826  {
1827  if (pptNearest)
1828  *pptNearest = ptTest; // What should I return here ?
1829  return -1.0;
1830  }
1831 
1832  // Nearest point and it`s parameter
1833  double dNearestParam = 0;
1834  OdGePoint2d ptNearest = this->_vertex(0).point();
1835 
1836  // Minimal distance
1837  double dMinDist = ptNearest.distanceTo( ptTest );
1838 
1839  const double dZeroDist = 1e-15; // stop search, if distance is <= this value
1840 
1841  OdUInt32 iNumSeg = this->_numSegments();
1842  if ( ( iNumSeg > 0 ) && (dMinDist > dZeroDist) )
1843  {
1844  // Iterate through segments and find the best match
1845 
1846  OdGePoint2d ptTmp;
1847  TImplSeg2D ImplSeg;
1848 
1849  for (OdUInt32 iSeg = 0; iSeg<iNumSeg; iSeg++ )
1850  {
1851  this->_getSegment( iSeg, ImplSeg );
1852 
1853  double dSegParam = ImplSeg.nearestParam( ptTest, &ptTmp );
1854 
1855  double dDist = ptTmp.distanceTo( ptTest );
1856 
1857  if ( dDist < dMinDist )
1858  {
1859  // This segment is more close
1860  dMinDist = dDist;
1861  dNearestParam = iSeg + dSegParam;
1862  ptNearest = ptTmp;
1863 
1864  if ( dMinDist <= dZeroDist )
1865  break;
1866  }
1867  }
1868  }
1869 
1870  if (pptNearest)
1871  *pptNearest = ptNearest;
1872 
1873  return dNearestParam;
1874 }
1875 
1876 
1877 
1878 template < class TContourData >
1879 bool TContour2DImpl<TContourData>::contains( const OdGePoint2d &rPoint, bool * pbOnBorder, const OdGeTol & gTol) const
1880 {
1881  if (pbOnBorder)
1882  *pbOnBorder = false;
1883 
1884  if ( this->_empty() )
1885  return false;
1886 
1887  if ( !this->_closed() )
1888  return false; // or close it?
1889 
1890  bool bInside = false;
1891 
1892 
1893  OdUInt32 iNumSeg = this->_numSegments();
1894  if ( iNumSeg > 0 )
1895  {
1896  // Iterate through segments and find the first match
1897 
1898  TImplSeg2D ImplSeg;
1899  for (OdUInt32 iSeg = 0; iSeg<iNumSeg; iSeg++ )
1900  {
1901  this->_getSegment( iSeg, ImplSeg );
1902 
1903  bool bOnSegment = false;
1904  OdUInt32 iCount = ImplSeg.intersectXRay( rPoint, &bOnSegment, gTol );
1905  if (bOnSegment)
1906  {
1907  if (pbOnBorder)
1908  *pbOnBorder = true;
1909  bInside = true;
1910  break;
1911  }
1912  if ( iCount&1 )
1913  bInside = !bInside;
1914  }
1915  }
1916  else if ( !this->_empty() )
1917  {
1918  // single point contour
1919  bInside = BulgeSeg2D( this->_vertex(0).point(), this->_vertex(0).point() ).isOn( rPoint, 0, gTol);
1920  if (pbOnBorder)
1921  *pbOnBorder = bInside;
1922  }
1923 
1924  return bInside;
1925 }
1926 
1927 
1928 
1929 
1930 
1931 template < class TContourData >
1932 bool TContour2DImpl<TContourData>::isSelfIntersecting(const OdGeTol & gTol, bool bExcludeTouch /*= false*/ ) const
1933 {
1934  OdUInt32 iNumSegs = this->_numSegments();
1935 
1936  if ( iNumSegs <= 1 )
1937  return false;
1938 
1939  // use fast ( N log N ) check if iNumSegs is big
1940  // ToDo: profile the code and find good condition
1941  if ( iNumSegs > 16 && !bExcludeTouch )
1942  {
1943  bool bIntersects = false;
1944  Result eRes = fast_isSelfIntersecting( *(const IContour2D*)(this), gTol, bIntersects );
1945  if ( isOk(eRes) )
1946  {
1947  return bIntersects;
1948  }
1949  // else => try the default method
1950  }
1951 
1952  Intersection XPt[2];
1953 
1954  TImplSeg2D ImplSegA; // ToDo: use cached segment here instead of the ImplSeg
1955  TImplSeg2D ImplSegB;
1956 
1957  for (OdUInt32 iSegA = 0; iSegA < iNumSegs; iSegA++ )
1958  {
1959  this->_getSegment( iSegA, ImplSegA );
1960 
1961  for (OdUInt32 iSegB = 0; iSegB < iSegA; iSegB++ )
1962  {
1963  this->_getSegment( iSegB, ImplSegB );
1964 
1965  OdUInt32 iCrosses = ImplSegA.intersect( ImplSegB, &(XPt[0]), &(XPt[1]), gTol );
1966  if ( iCrosses > 2 )
1967  iCrosses = 2;
1968 
1969  // do not count self-touch as self-intersection
1970 #if 1
1971  if(bExcludeTouch && (iSegA != iNumSegs-1 || iSegB != 0) && iCrosses == 1 && Intersection::eitTouch == XPt[0].eType && !this->areEqualParams( iSegB + XPt[0].dParamB, iSegA + XPt[0].dParamA, 1e-14 ))
1972  {
1973  const bool bAisTouchEnd = OdEqual(XPt[0].dParamA, 1., 1e-10);
1974  const bool bAisTouchBeg = OdEqual(XPt[0].dParamA, 0., 1e-10);
1975  ODA_ASSERT(!bAisTouchEnd || !bAisTouchBeg);
1976  const bool bBisTouchEnd = OdEqual(XPt[0].dParamB, 1., 1e-10);
1977  const bool bBisTouchBeg = OdEqual(XPt[0].dParamB, 0., 1e-10);
1978  ODA_ASSERT(!bBisTouchEnd || !bBisTouchBeg);
1979  const bool bAisTouch = bAisTouchEnd || bAisTouchBeg;
1980  const bool bBisTouch = bBisTouchEnd || bBisTouchBeg;
1981  if(bAisTouch && bBisTouch)
1982  {
1983  const OdGeVector2d vA1 = bAisTouchEnd ? ImplSegA.startPt() - ImplSegA.endPt() : ImplSegA.endPt() - ImplSegA.startPt();
1984  int iNext = ((iSegA + (bAisTouchEnd ? 1 : -1)) + iNumSegs) % iNumSegs;
1985  TImplSeg2D ImplNext;
1986  this->_getSegment( iNext, ImplNext );
1987  const OdGeVector2d vA2 = bAisTouchEnd ? ImplNext.endPt() - ImplSegA.endPt() : ImplNext.startPt() - ImplSegA.startPt();
1988 
1989  const OdGeVector2d vB1 = bBisTouchEnd ? ImplSegB.startPt() - ImplSegB.endPt() : ImplSegB.endPt() - ImplSegB.startPt();
1990  iNext = ((iSegB + (bBisTouchEnd ? 1 : -1)) + iNumSegs) % iNumSegs;
1991  this->_getSegment( iNext, ImplNext );
1992  const OdGeVector2d vB2 = bBisTouchEnd ? ImplNext.endPt() - ImplSegB.endPt() : ImplNext.startPt() - ImplSegB.startPt();
1993 
1994  double angA = vA1.angleToCCW(vA2);
1995  if(angA < 0)
1996  {
1997  angA += Oda2PI;
1998  }
1999  double angB1 = vA1.angleToCCW(vB1);
2000  if(angB1 < 0)
2001  {
2002  angB1 += Oda2PI;
2003  }
2004  double angB2 = vA1.angleToCCW(vB2);
2005  if(angB2 < 0)
2006  {
2007  angB2 += Oda2PI;
2008  }
2009  if((angB1 < angA && angB2 < angA) || (angB1 > angA && angB2 > angA))
2010  {
2011  continue;
2012  }
2013  }
2014  else if(bAisTouch)
2015  {
2016  int iNext = ((iSegA + (bAisTouchEnd ? 1 : -1)) + iNumSegs) % iNumSegs;
2017  TImplSeg2D ImplNext;
2018  this->_getSegment( iNext, ImplNext );
2019  const OdGePoint2d pt1 = bAisTouchEnd ? ImplNext.endPt() : ImplNext.startPt();
2020  const OdGePoint2d pt2 = bAisTouchEnd ? ImplSegA.startPt() : ImplSegA.endPt();
2021 
2022  OdGeVector2d vLine = ImplSegB.endPt() - ImplSegB.startPt();
2023  const double sign1 = vLine.crossProduct(pt1 - ImplSegB.startPt());
2024  const double sign2 = vLine.crossProduct(pt2 - ImplSegB.startPt());
2025  if(sign1*sign2 > -1e-14)
2026  {
2027  continue;
2028  }
2029  }
2030  else if(bBisTouch)
2031  {
2032  int iNext = ((iSegB + (bBisTouchEnd ? 1 : -1)) + iNumSegs) % iNumSegs;
2033  TImplSeg2D ImplNext;
2034  this->_getSegment( iNext, ImplNext );
2035  const OdGePoint2d pt1 = bBisTouchEnd ? ImplNext.endPt() : ImplNext.startPt();
2036  const OdGePoint2d pt2 = bBisTouchEnd ? ImplSegB.startPt() : ImplSegB.endPt();
2037 
2038  OdGeVector2d vLine = ImplSegA.endPt() - ImplSegA.startPt();
2039  const double sign1 = vLine.crossProduct(pt1 - ImplSegA.startPt());
2040  const double sign2 = vLine.crossProduct(pt2 - ImplSegA.startPt());
2041  if(sign1*sign2 > -1e-14)
2042  {
2043  continue;
2044  }
2045  }
2046  }
2047 #endif
2048 
2049  // Handle crossings
2050  for ( OdUInt32 iC = 0; iC < iCrosses; iC++ )
2051  {
2052  if ( !XPt[iC].eType )
2053  continue;
2054 
2055  // Note: this way will not count intersections on segment bounds
2056  if ( Intersection::eitCrossing == XPt[iC].eType )
2057  return true;
2058  /*if (bExcludeTouch && Intersection::eitTouch == XPt[iC].eType )
2059  continue;*/
2060 
2061  if ( this->areEqualParams( iSegB + XPt[iC].dParamB, iSegA + XPt[iC].dParamA, 1e-14 ) )
2062  continue; // equal parameters => no self-intersection
2063 
2064  double dDist = this->signedMinDistByParams( iSegB + XPt[iC].dParamB, iSegA + XPt[iC].dParamA );
2065  if ( OdZero( dDist, gTol.equalPoint() ) )
2066  continue; // equal distances => no self-intersection
2067 
2068  return true;
2069  }
2070  }
2071  }
2072 
2073  return false;
2074 }
2075 
2076 
2077 template < class TContourData >
2079 {
2080  bool bValidRegion = false;
2081 
2082  fast_isValidRegion( *(const IContour2D*)(this), gTol, bValidRegion );
2083 
2084  return bValidRegion;
2085 }
2086 
2087 template < class TContourData >
2088 bool TContour2DImpl<TContourData>::isInsideContour(const IContour2D& c2dOuter, bool fAllowBordersTouch, const OdGeTol& gTol) const
2089 {
2090  // this function is valid for contours with straight segments only
2091  ODA_ASSERT(!this->hasArcs());
2092  ODA_ASSERT(!c2dOuter.hasArcs());
2093 
2094  const OdUInt32 numVertices = this->numVerts();
2095  OdGePoint2d ptVertex;
2096  for(OdUInt32 uVertexIdx = 0; uVertexIdx < numVertices; uVertexIdx++)
2097  {
2098  this->getVertexAt(uVertexIdx, &ptVertex);
2099 
2100  bool fOnBorder = false;
2101  if(!c2dOuter.contains(ptVertex, &fOnBorder))
2102  return false;
2103 
2104  if(!fAllowBordersTouch && fOnBorder)
2105  return false;
2106  }
2107 
2108  return true;
2109 }
2110 
2111 
2112 template < class TContourData >
2114  std::vector< Intersection > & vecPoints,
2115  const OdGeTol & gTol) const
2116 {
2117  if ( this->_empty() )
2118  return 0;
2119 
2120  // ToDo: use cached segment here instead of rSegB
2121 
2122  OdUInt32 iOrigCrossCount = (OdUInt32)vecPoints.size();
2123 
2124  OdUInt32 iNumSegs = this->_numSegments();
2125 
2126  Intersection XPt[2];
2127 
2128  if ( iNumSegs > 0 )
2129  {
2130  TImplSeg2D ImplSeg;
2131  // ToDo: use cached segment here instead of the ImplSeg
2132 
2133  for (OdUInt32 iSeg = 0; iSeg < iNumSegs; iSeg++ )
2134  {
2135  this->_getSegment( iSeg, ImplSeg );
2136 
2137  OdUInt32 iCrosses = ImplSeg.intersect( rSegB, &(XPt[0]), &(XPt[1]), gTol );
2138  if ( iCrosses > 2 ) // overlapping seb-segments
2139  iCrosses = 2; // use only bounds
2140 
2141  for ( OdUInt32 iC = 0; iC < iCrosses; iC++ )
2142  if ( XPt[iC].eType != Intersection::eitNone )
2143  {
2144  if ( XPt[iC].eType != Intersection::eitCrossing )
2145  XPt[iC].eType = Intersection::eitAny; // To Do: update intersection type
2146 
2147  XPt[iC].dParamA += iSeg;
2148  vecPoints.push_back( XPt[iC] );
2149  }
2150  }
2151  }
2152  else if ( this->_numVerts() > 0 ) // Handle 1-point contour
2153  {
2154  const OdGePoint2d & ptVert = this->_vertex(0).point();
2155 
2156  double dBParam = 0;
2157  if ( rSegB.isOn( ptVert, &dBParam, gTol ) )
2158  {
2159  XPt[0].ptPoint = ptVert;
2160  XPt[0].dParamA = 0;
2161  XPt[0].dParamB = dBParam;
2162  XPt[0].eType = Intersection::eitTouch;
2163 
2164  vecPoints.push_back( XPt[0] );
2165  }
2166  }
2167 
2168  return (OdUInt32)vecPoints.size() - iOrigCrossCount;
2169 }
2170 
2171 
2172 
2173 
2174 template < class TContourData >
2176  std::vector< Intersection > & vecPoints,
2177  const OdGeTol & gTol ) const
2178 {
2179  if ( this->_empty() || rContB.isEmpty() )
2180  return 0;
2181 
2182  OdUInt32 iNumSegs = this->_numSegments();
2183  //OdUInt32 iNumSegsB= rContB.numSegments();
2184 
2185  OdUInt32 iOrigCrossCount = (OdUInt32)vecPoints.size();
2186  OdUInt32 iCrossCount = iOrigCrossCount;
2187 
2188  // use fast ( NLogN ) intersection method and caching in big contours
2189  // ToDo: profile the code and find good condition
2190  if ( iNumSegs > 16 || rContB.numSegments() > 16 )
2191  {
2192  Result eRes = fast_intersect( *(const IContour2D*)(this), rContB, vecPoints, gTol );
2193  if ( isOk(eRes) )
2194  {
2195  return (OdUInt32)vecPoints.size() - iOrigCrossCount;
2196  }
2197  // else => try the default method
2198  }
2199 
2200  if ( iNumSegs > 0 )
2201  {
2202  TImplSeg2D ImplSeg;
2203  // ToDo: use cached segment here instead of the ImplSeg
2204 
2205  for (OdUInt32 iSeg = 0; iSeg < iNumSegs; iSeg++ )
2206  {
2207  this->_getSegment( iSeg, ImplSeg );
2208 
2209  //OdUInt32 iCrosses =
2210  rContB.intersect( ImplSeg, vecPoints, gTol );
2211 
2212  //FMGE_ASSERT( (vecPoints.size() - iCrossCount) == iCrosses );
2213 
2214  while ( iCrossCount < vecPoints.size() )
2215  {
2216  Intersection & rCross = vecPoints[iCrossCount];
2217 
2218  double dBParam = rCross.dParamA;
2219  rCross.dParamA = iSeg + rCross.dParamB;
2220  rCross.dParamB = dBParam;
2221 
2222  // To Do: check and remove duplicates
2223  // To Do: update intersection type
2224  rCross.eType = Intersection::eitAny;
2225 
2226  ++iCrossCount;
2227  }
2228  }
2229  }
2230  else if ( this->_numVerts() > 0 ) // Handle 1-point contour
2231  {
2232 
2233  BulgeSeg2D ASeg( this->_vertex(0).point(), this->_vertex(0).point() );
2234 
2235  //OdUInt32 iCrosses =
2236  rContB.intersect( ASeg, vecPoints, gTol );
2237 
2238  while ( iCrossCount < vecPoints.size() )
2239  {
2240  Intersection & rCross = vecPoints[iCrossCount];
2241  rCross.dParamB = rCross.dParamA;
2242  rCross.dParamA = 0.0;
2243  rCross.eType = Intersection::eitTouch;
2244  ++iCrossCount;
2245  }
2246  }
2247 
2248  return iCrossCount - iOrigCrossCount;
2249 }
2250 
2251 
2252 template < class TContourData >
2254  const OdGePoint2d& ptLineOrigin,
2255  const OdGeVector2d& vLineDir,
2256  std::vector< Intersection > & vecPoints,
2257  const OdGeTol & gTol) const
2258 {
2259  if ( this->_empty() || vLineDir.isZeroLength( gTol ) )
2260  return 0;
2261 
2262  OdUInt32 iNumSegs = this->_numSegments();
2263 
2264  OdUInt32 iOrigCrossCount = (OdUInt32)vecPoints.size();
2265 
2266  // ToDo: use fast ( NLogN ) intersection method and caching in big contours
2267 // if ( iNumSegs > 16 || rContB.numSegments() > 16 )
2268 // {
2269 // Result eRes = fast_intersectLine( *(const IContour2D*)(this), rContB, vecPoints, gTol );
2270 // if ( isOk(eRes) )
2271 // {
2272 // return vecPoints.size() - iOrigCrossCount;
2273 // }
2274 // // else => try the default method
2275 // }
2276 
2277  Intersection XPt[2];
2278 
2279  if ( iNumSegs > 0 )
2280  {
2281  TImplSeg2D ImplSeg;
2282 
2283  for (OdUInt32 iSeg = 0; iSeg < iNumSegs; iSeg++ )
2284  {
2285  this->_getSegment( iSeg, ImplSeg );
2286 
2287  OdUInt32 iCrosses = ImplSeg.intersectLine( ptLineOrigin, vLineDir, &(XPt[0]), &(XPt[1]), gTol );
2288  if ( iCrosses > 0 )
2289  {
2290  if ( iCrosses > 2 )
2291  iCrosses = 2;
2292 
2293  for ( OdUInt32 iC = 0; iC < iCrosses; iC++ )
2294  if ( XPt[iC].eType != Intersection::eitNone )
2295  {
2296  if ( XPt[iC].eType != Intersection::eitCrossing )
2297  XPt[iC].eType = Intersection::eitAny; // To Do: update intersection type
2298 
2299  XPt[iC].dParamA += iSeg;
2300  vecPoints.push_back( XPt[iC] );
2301  }
2302  }
2303  }
2304  }
2305  else if ( this->_numVerts() > 0 ) // Handle 1-point contour
2306  {
2307  BulgeSeg2D ASeg( this->_vertex(0).point(), this->_vertex(0).point() );
2308 
2309  OdUInt32 iCrosses = ASeg.intersectLine( ptLineOrigin, vLineDir, &(XPt[0]), 0, gTol );
2310 
2311  if ( iCrosses > 0 && XPt[0].eType != Intersection::eitNone )
2312  {
2313  XPt[0].eType = Intersection::eitTouch;
2314  XPt[0].dParamA = 0.0;
2315  vecPoints.push_back( XPt[0] );
2316  }
2317  }
2318 
2319  return (OdUInt32)vecPoints.size() - iOrigCrossCount;
2320 }
2321 
2322 
2323 template < class TContourData >
2325  const DeviationParams& devDeviation )
2326 {
2327  // isScaledOrtho undefined!!!
2328  //if ( !geMatrix.isScaledOrtho( FMGeGbl::gTol ) )
2329  //{
2330  // FMGE_ASSERT( 0 );
2331  // return erFail;
2332  //}
2333 
2334  bool bExplodeRequired = false;
2335  {
2336  OdGePoint2d origin;
2337  OdGeVector2d x, y;
2338  geMatrix.getCoordSystem(origin, x, y);
2339 
2340  if ( !OdEqual( x.length(), y.length(), FMGeGbl::gTol.equalPoint() ) )
2341  {
2342  bExplodeRequired = true;
2343  }
2344  }
2345 
2346  if ( bExplodeRequired )
2347  {
2348  // Initial version.
2349  //
2350  this->explodeTo( *this, devDeviation );
2351  }
2352 
2353  OdUInt32 iNumVerts = this->_numVerts();
2354  if ( this->_numVerts() <= 0 )
2355  return erOk;
2356 
2357  bool bInverse = ( geMatrix.det() < 0 );
2358 
2359  for ( OdUInt32 iVert = 0; iVert<iNumVerts; iVert++ )
2360  {
2361  TVertexData & rVert = this->_vertex(iVert);
2362  rVert.point().transformBy( geMatrix );
2363  if ( bInverse )
2364  rVert.bulge() = -rVert.bulge();
2365  }
2366 
2367  this->_setModifiedAll();
2368 
2369  return erOk;
2370 }
2371 
2372 
2373 
2374 template < class TContourData >
2376 {
2377  OdUInt32 iNumVerts = this->_numVerts();
2378  if ( this->_numVerts() <= 0 )
2379  return;// erOk;
2380 
2381  if ( ! this->_closed() )
2382  {
2383  // Open contour -- swap all vertices except the odd middle one
2384  OdUInt32 iSwapNum = iNumVerts/2;
2385 
2386  for ( OdUInt32 iS = 0; iS < iSwapNum; iS++ )
2387  {
2388  TVertexData & rVertA = this->_vertex(iS);
2389  OdGePoint2d& rPtB = this->_vertex(iNumVerts - 1 - iS).point();
2390 
2391  std::swap( rVertA.point(), rPtB );
2392 
2393  TVertexData & rVertB = this->_vertex(iNumVerts - 2 - iS);
2394 
2395  std::swap( rVertA.bulge(), rVertB.bulge() );
2396  std::swap( rVertA.attributes(), rVertB.attributes() );
2397  }
2398  }
2399  else
2400  {
2401  // Closed contour -- swap all except the first vertex and the even middle one
2402 
2403  // swap points
2404  {
2405  OdUInt32 iPSwapNum = (iNumVerts-1)/2;
2406  for ( OdUInt32 iS = 0; iS < iPSwapNum; iS++ )
2407  {
2408  OdGePoint2d& rPtA = this->_vertex(iS+1).point();
2409  OdGePoint2d& rPtB = this->_vertex(iNumVerts - iS - 1).point();
2410  std::swap( rPtA, rPtB );
2411  }
2412  }
2413 
2414  // Swap bulges and metadata
2415  {
2416  OdUInt32 iBSwapNum = iNumVerts/2;
2417  for ( OdUInt32 iS = 0; iS < iBSwapNum; iS++ )
2418  {
2419  TVertexData & rVertA = this->_vertex(iS);
2420  TVertexData & rVertB = this->_vertex(iNumVerts - iS - 1);
2421 
2422  std::swap( rVertA.bulge(), rVertB.bulge() );
2423  std::swap( rVertA.attributes(), rVertB.attributes() );
2424  }
2425  }
2426  }
2427 
2428  // reverse bulges and attributes
2429  {
2430  for (OdUInt32 i = 0, iSize = numVerts(); i < iSize; i++ )
2431  {
2432  TVertexData & rVert = this->_vertex(i);
2433  rVert.bulge() = -rVert.bulge();
2434  rVert.attributes().reverse();
2435  }
2436  }
2437 
2438  this->_setModifiedAll();
2439 
2440  //return erOk;
2441 }
2442 
2443 
2444 
2445 template < class TContourData >
2447 {
2448  OdUInt32 iNumVerts = this->_numVerts();
2449  if ( this->_numVerts() <= 1 )
2450  return;// erOk;
2451 
2452  TVertexData * pPrevVert = & this->_vertex(0);
2453 
2454  // number of ready points
2455  OdUInt32 iNumHandled = 1;
2456 
2457  for ( OdUInt32 iVert = 1; iVert<iNumVerts; iVert++)
2458  {
2459  TVertexData& rThisVert = this->_vertex(iVert);
2460  if ( rThisVert.point().isEqualTo( pPrevVert->point(), gTol ) )
2461  {
2462  // equal points, override metadata of zero-length segment
2463  pPrevVert->bulge() = rThisVert.bulge();
2464  pPrevVert->attributes() = rThisVert.attributes();
2465  }
2466  else // different points
2467  {
2468  pPrevVert = & this->_vertex(iNumHandled);
2469  if ( iNumHandled < iVert )
2470  *pPrevVert = rThisVert;
2471 
2472  iNumHandled++;
2473  }
2474  }
2475 
2476  if ( this->_closed() )
2477  {
2478  if ( this->_vertex(0).point().isEqualTo( pPrevVert->point(), gTol ) )
2479  {
2480  iNumHandled--; // remove the duplicate endpoint
2481  }
2482  }
2483  else
2484  {
2485  // ensure the last vertex and bulge of an open contour are preserved
2486  if ( iNumHandled < (iNumVerts-1) )
2487  this->_vertex(iNumHandled) = this->_vertex( iNumVerts-1 );
2488  }
2489 
2490  if ( iNumHandled < iNumVerts )
2491  {
2492  // resize and reset cache
2493  this->_resize( iNumHandled );
2494  this->_setModifiedAll();
2495  }
2496 }
2497 
2498 
2499 template < class TContourData >
2500 void TContour2DImpl<TContourData>::mergeSegments( int iMergeFlags, const OdGeTol& gTol )
2501 {
2502  contour2d_mergeSegments( *static_cast<IContour2D*>(this), iMergeFlags, gTol );
2503 }
2504 
2505 
2506 template < class TContourData >
2508  const DeviationParams& devDeviation,
2509  OdIntPtr uArcMetadata ) const
2510 {
2511  // aliasing check:
2512  bool bThisDest = ( ((const IContour2D*)this) == &rDestCont );
2513 
2514  bool bClosed = this->_closed();
2515 
2516  OdUInt32 iNumVerts = this->_numVerts();
2517  OdUInt32 iNumSegs = this->_numSegments();
2518 
2519  Result eRes = erOk;
2520 
2521  if ( iNumSegs < 1 ) // 0 or 1 point(s)
2522  {
2523  if ( !bThisDest )
2524  rDestCont.set( *this );
2525 
2526  return erOk;
2527  }
2528 
2529 
2531  // first pass: get points and store metadata
2532 
2533  OdGePoint2dArray vecPoints;
2534 
2535  typedef std::pair< OdUInt32, Attributes2D > SegDataPair;
2536  std::vector< SegDataPair > vecAttributes;
2537 
2538  vecAttributes.reserve( iNumVerts + 1);
2539  vecPoints.reserve( iNumVerts );
2540 
2541  TImplSeg2D ImplSeg;
2542  CachedSeg2D arcSeg;
2543 
2544  bool bHasArcs = false;
2545 
2546  for ( OdUInt32 iSeg = 0; iSeg < iNumSegs; iSeg++ )
2547  {
2548  this->_getSegment( iSeg, ImplSeg );
2549 
2550  Attributes2D Attr = ImplSeg.attributes();
2551  vecAttributes.push_back( SegDataPair( vecPoints.size(), Attr ) );
2552 
2553  vecPoints.push_back( ImplSeg.startPt() );
2554 
2555  if ( ImplSeg.type() == estArc )
2556  {
2557  bHasArcs = true;
2558  vecAttributes.back().second.setExplodedArc(true).metadata() |= uArcMetadata; // ATTRTODO
2559 
2560  eRes = arcSeg.set( ImplSeg );
2561  FMGE_ASSERT( erOk == eRes );
2562  if ( isError(eRes) )
2563  return eRes;
2564 
2565  OdUInt32 iSegmentCount = FMGeGbl::GetSegmentCount(
2566  ::fabs( arcSeg.arcAngle() ), arcSeg.arcRadius(), devDeviation );
2567 
2568  // vecPoints.reserve( ... )
2569 
2570  // insert intermediate points
2571  OdGePoint2d ptVertex;
2572  for ( OdUInt32 iPt = 1; iPt<iSegmentCount; iPt++ )
2573  {
2574  eRes = arcSeg.getPoint( double(iPt)/iSegmentCount, ptVertex );
2575  if ( isError(eRes) )
2576  return eRes;
2577  vecPoints.push_back( ptVertex );
2578  }
2579  }
2580  }
2581 
2582  // append the last vertex for non-closed contours
2583  // ( in closed contours it coincides with the first one )
2584  if ( ! bClosed )
2585  {
2586  const TVertexData & rLast = this->_vertex( iNumVerts-1 );
2587  FMGE_ASSERT( ImplSeg.endPt().isEqualTo( rLast.point() ) );
2588 
2589  vecAttributes.push_back( SegDataPair( vecPoints.size(), rLast.attributes() ) );
2590  vecPoints.push_back( rLast.point() );
2591  }
2592 
2593  vecAttributes.push_back( SegDataPair( vecPoints.size(), Attributes2D::kNull ) ); // terminating record
2594 
2596  // second pass: set points and metadata
2597 
2598  if ( !bHasArcs ) // No arcs => no action
2599  {
2600  if ( !bThisDest ) // copy, if necessary
2601  rDestCont.set( *this );
2602 
2603  return erOk;
2604  }
2605 
2606  {
2607  rDestCont.reset();
2608  rDestCont.setClosed( bClosed );
2609 
2610  eRes = rDestCont.appendVertices( vecPoints );
2611  if ( isOk( eRes ) )
2612  {
2613  // update metadata (slower)
2614  for ( OdUInt32 uI = 1; uI < vecAttributes.size(); ++uI )
2615  {
2616  const Attributes2D& rAttr = vecAttributes[ uI-1 ].second;
2617  if ( !rAttr.isNull() )
2618  {
2619  OdUInt32 uVert = vecAttributes[ uI-1 ].first;
2620  OdUInt32 uLastVert = vecAttributes[ uI ].first;
2621 
2622  for ( ; uVert < uLastVert; ++uVert )
2623  rDestCont.setAttributesAt( uVert, rAttr );
2624  }
2625  }
2626  }
2627  }
2628 
2629  return eRes;
2630 }
2631 
2632 
2633 
2634 template < class TContourData >
2636 {
2637  OdUInt32 iIndex;
2638  double dSegParam;
2639  Result eRes = _param2IdxParam( dParam, iIndex, dSegParam );
2640  if ( isError(eRes) )
2641  return OdUInt32(-1);
2642 
2643  TImplSeg2D ImplSeg;
2644  eRes = this->_getSegment( iIndex, ImplSeg );
2645  FMGE_ASSERT( erOk==eRes );
2646  if ( isError(eRes) )
2647  return OdUInt32(-1);
2648 
2649  // Segment`s length is used to compare with tolerance
2650  double dLen = ImplSeg.length();
2651 
2652  const double dTol = gTol.equalVector();
2653 
2654  // Check if the vertex already exists
2655 
2656  if ( dSegParam*dLen <= dTol )
2657  {
2658  FMGE_ASSERT( dSegParam*dLen >= -dTol );
2659  return iIndex; // The vertex exists
2660  }
2661  else if ( (1.0 - dSegParam)*dLen <= dTol )
2662  {
2663  FMGE_ASSERT( (1.0 - dSegParam)*dLen >= -dTol );
2664  return (iIndex+1) % this->_numVerts(); // The vertex exists
2665  }
2666 
2667  // The vertex should be created
2668  OdUInt32 iNewIndex = (iIndex+1);
2669 
2670  // Get the new point
2671  OdGePoint2d ptSplit;
2672  eRes = ImplSeg.getPoint( dSegParam, ptSplit);
2673  FMGE_ASSERT( erOk==eRes );
2674  if ( isError(eRes) )
2675  return OdUInt32(-1);
2676 
2677  Attributes2D Attr = ImplSeg.attributes();
2678 
2679  if ( ImplSeg.type()==estArc )
2680  {
2681  // calculate new bulges
2682  double dAngle = ImplSeg.arcAngle();
2683  double dBulge1 = ::tan( 0.25 * dAngle * dSegParam );
2684  double dBulge2 = ::tan( 0.25 * dAngle * (1.0 - dSegParam) );
2685 
2686  // ImplSeg can become invalid, if reallocation happens
2687 
2688  this->_vertex( iIndex ).bulge() = dBulge1;
2689  this->_setModifiedSegs( iIndex );
2690  eRes = this->_insertVerticesAt(iNewIndex, 1, &ptSplit, &dBulge2, &Attr );
2691  }
2692  else
2693  {
2694  // No bulges
2695  if ( ImplSeg._bulge() != 0.0 )
2696  {
2697  this->_vertex( iIndex ).bulge() = 0.0;
2698  this->_setModifiedSegs( iIndex );
2699  }
2700 
2701  eRes = this->_insertVerticesAt(iNewIndex, 1, &ptSplit, 0, &Attr );
2702  }
2703 
2704  FMGE_ASSERT( erOk==eRes );
2705  if ( isError( eRes ) )
2706  return OdUInt32(-1);
2707 
2708  return iNewIndex;
2709 }
2710 
2711 
2712 template < class TContourData >
2713 Result TContour2DImpl<TContourData>::_createVerticesAt( OdUInt32 uCount, const double * pdParams, const OdGeTol & gTol )
2714 {
2715  FMGE_ASSERT( 0!= pdParams );
2716  if ( uCount<1 || !pdParams )
2717  return erOk;
2718 
2719  typedef std::pair< OdUInt32, double > SegOffsPair;
2720  std::vector< SegOffsPair > vecParams;
2721  vecParams.reserve( uCount );
2722 
2723  Result eBigRes = erOk;
2724 
2725  // convert contour parameters to segment/segParam pairs and sort
2726  {
2727  SegOffsPair currSO;
2728 
2729  for ( OdUInt32 uP = 0; uP < uCount; ++uP )
2730  {
2731  Result eRes = _param2IdxParam( pdParams[uP], currSO.first, currSO.second );
2732  eBigRes = worstResult( eBigRes, eRes );
2733  if ( isOk( eRes ) )
2734  vecParams.push_back( currSO );
2735  }
2736 
2737  std::sort( vecParams.begin(), vecParams.end() );
2738  }
2739 
2740 
2741  if ( !vecParams.empty() )
2742  {
2743  TImplSeg2D ImplSeg;
2744  CachedSeg2D currSeg;
2745  Result eRes = erOk;
2746 
2747  std::vector< double > vecSegParams;
2748  std::vector< OdGePoint2d > vecSegPoints;
2749  std::vector< double > vecSegBulges;
2750  std::vector< Attributes2D > vecSegAttributes;
2751  //vecSegParams.reserve( vecParams.size() + 1);
2752 
2753  const double dTol = gTol.equalVector();
2754 
2755  // Walk through the params from end to start, to avoid unnecessary recalculation
2756  OdUInt32 uSEnd = (OdUInt32)vecParams.size();
2757  while ( uSEnd > 0 )
2758  {
2759  OdInt32 uSBegin = uSEnd - 1;
2760  OdUInt32 uSeg = vecParams[uSBegin].first;
2761  while ( uSBegin > 0 && ( uSeg == vecParams[uSBegin-1].first ) )
2762  --uSBegin;
2763 
2764  // handle points [ uSBegin .. uSEnd ) lying on uSeg
2765  eRes = this->_getSegment( uSeg, ImplSeg );
2766  FMGE_ASSERT( erOk==eRes );
2767  currSeg.set( ImplSeg );
2768 
2769  // Segment`s length is used to compare with tolerance
2770  double dLen = currSeg.length();
2771 
2772  // add new parameters to vecSegParams
2773  {
2774  vecSegParams.resize( 0 );
2775 
2776  for ( OdUInt32 uP = uSBegin; uP < uSEnd; ++uP )
2777  {
2778  double dSegParam = vecParams[uP].second;
2779  if ( dSegParam*dLen > dTol && (1.0 - dSegParam)*dLen > dTol )
2780  {
2781  // point lies inside the segment
2782  if ( vecSegParams.empty()
2783  || !OdEqual( vecSegParams.back(), dSegParam, dTol ) )
2784  {
2785  // add it, skipping duplicates
2786  vecSegParams.push_back( dSegParam );
2787  }
2788  }
2789  }
2790  }
2791 
2792  if ( !vecSegParams.empty() )
2793  {
2794  OdUInt32 uNewNum = (OdUInt32)vecSegParams.size();
2795 
2796  // fill points
2797  vecSegPoints.resize( uNewNum );
2798  {
2799  for ( OdUInt32 uP = 0 ; uP < uNewNum; ++uP )
2800  {
2801  eRes = currSeg.getPoint( vecSegParams[uP], vecSegPoints[uP] );
2802  FMGE_ASSERT( isOk(eRes) );
2803  }
2804  }
2805 
2806  // fill metadata, if used
2807  const Attributes2D * pAttributes = 0;
2808  vecSegAttributes.resize( 0 );
2809  if ( !currSeg.attributes().isNull() )
2810  {
2811  vecSegAttributes.resize( uNewNum, currSeg.attributes() );
2812  pAttributes = &( vecSegAttributes.front() );
2813  }
2814 
2815  if ( currSeg.type() == estArc )
2816  {
2817  // recalculate bulges
2818  {
2819  vecSegBulges.resize( uNewNum+1 );
2820  vecSegParams.push_back( 1.0 );
2821 
2822  double dAngle4 = currSeg.arcAngle()/4.0;
2823 
2824  double dPrevParam = 0;
2825  for ( OdUInt32 uP = 0; uP <= uNewNum; ++uP )
2826  {
2827  vecSegBulges[ uP ] = ::tan( dAngle4 * ( vecSegParams[uP] - dPrevParam ) );
2828  dPrevParam = vecSegParams[uP];
2829  }
2830  }
2831 
2832  this->_vertex( uSeg ).bulge() = vecSegBulges[0];
2833  this->_setModifiedSegs( uSeg );
2834 
2835  // add vertices with bulges and metadata
2836  eRes = this->_insertVerticesAt( uSeg + 1, uNewNum,
2837  & ( vecSegPoints[0] ),
2838  & ( vecSegBulges[1] ),
2839  pAttributes );
2840 
2841  eBigRes = worstResult( eBigRes, eRes );
2842  }
2843  else
2844  {
2845  // linear segment
2846 
2847  // reset bulge, if it was not exactly zero
2848  if ( ImplSeg._bulge() != 0.0 )
2849  {
2850  this->_vertex( uSeg ).bulge() = 0.0;
2851  this->_setModifiedSegs( uSeg );
2852  }
2853 
2854  // add vertices with 0 bulges and metadata
2855  eRes = this->_insertVerticesAt( uSeg + 1, uNewNum, &( vecSegPoints.front() ), 0, pAttributes );
2856 
2857  eBigRes = worstResult( eBigRes, eRes );
2858  }
2859  }
2860 
2861  uSEnd = uSBegin;
2862  }
2863 
2864  }
2865 
2866  return eBigRes;
2867 }
2868 
2869 
2870 template < class TContourData >
2871 Result TContour2DImpl<TContourData>::createVerticesAt( const std::vector<double> & vecParams, const OdGeTol & gTol )
2872 {
2873  return _createVerticesAt( (OdUInt32)vecParams.size(), &( vecParams.front() ), gTol );
2874 }
2875 
2876 
2877 
2878 template < class TContourData >
2880  const double dParamA, const double dParamB,
2881  OdUInt32& uIdxA, double& dSegParamA, OdUInt32& uIdxB, double& dSegParamB,
2882  OdUInt32& iNumPeriodsAB, const double dParamTol ) const
2883 {
2884  iNumPeriodsAB = 0;
2885 
2886  OdUInt32 iNumSegs = this->_numSegments();
2887  if ( iNumSegs <= 0 )
2888  {
2889  uIdxA = uIdxB = 0;
2890  dSegParamA = dSegParamB = 0;
2891  if ( this->_numVerts() > 0 && OdZero(dParamA, dParamTol) && OdZero(dParamB, dParamTol) )
2892  return erWarnEmptyContour;
2893 
2894  return erInvalidIndex;
2895  }
2896 
2897  bool bReverse = (dParamA > dParamB);
2898 
2899  // split into segment index and fractional segment parameter
2900  long aiIdx[2];
2901  double adSegParams[2];
2902  {
2903  for (int i = 0; i<2; ++i )
2904  {
2905  double dIdx;
2906  adSegParams[i] = ::modf( i==int(bReverse) ? dParamA : dParamB, &dIdx );
2907  aiIdx[i] = long( ::floor( dIdx + 0.5 ) );
2908  if ( adSegParams[i] < 0 )
2909  {
2910  adSegParams[i] += 1;
2911  aiIdx[i] -= 1;
2912  }
2913  }
2914  }
2915 
2916  // adjust upper/lower bounds
2917  {
2918  if ( adSegParams[0] >= 1.0-dParamTol )
2919  {
2920  adSegParams[0] = 0.0;
2921  aiIdx[0] += 1;
2922  }
2923  else if ( adSegParams[0] <= dParamTol )
2924  {
2925  adSegParams[0] = 0.0;
2926  }
2927 
2928  if ( adSegParams[1] <= dParamTol )
2929  {
2930  adSegParams[1] = 1.0;
2931  aiIdx[1] -= 1;
2932  }
2933  else if ( adSegParams[1] >= 1.0-dParamTol )
2934  {
2935  adSegParams[1] = 1.0;
2936  }
2937  }
2938 
2939  Result eRes = erOk;
2940 
2941  if ( aiIdx[0] > aiIdx[1] || ( aiIdx[0] == aiIdx[1] && adSegParams[0] >= adSegParams[1] ) )
2942  {
2943  FMGE_ASSERTMSG( OdZero( (aiIdx[0]+adSegParams[0]) - (aiIdx[1]+adSegParams[1]), 2*dParamTol ),
2944  "Critical floating-point inaccuracy!" );
2945 
2946  aiIdx[1] = aiIdx[0];
2947  adSegParams[1] = adSegParams[0];
2948 
2949  eRes = erWarnEmptyContour;
2950  }
2951 
2952 
2953  if ( this->_closed() )
2954  {
2955  // contour is closed => remove periods
2956 
2957  ldiv_t aPeriodsIdxs[2];
2958  for (int i=0; i<2; ++i )
2959  {
2960  ldiv_t& rDest = aPeriodsIdxs[i];
2961  rDest = ::ldiv( aiIdx[i], long(iNumSegs) );
2962  if ( rDest.rem < 0 )
2963  {
2964  rDest.rem += long(iNumSegs);
2965  rDest.quot--;
2966  }
2967  }
2968 
2969  iNumPeriodsAB = aPeriodsIdxs[ !bReverse ].quot - aPeriodsIdxs[ bReverse ].quot;
2970  uIdxA = OdUInt32( aPeriodsIdxs[ bReverse ].rem );
2971  uIdxB = OdUInt32( aPeriodsIdxs[!bReverse ].rem );
2972  dSegParamA = adSegParams[ bReverse ];
2973  dSegParamB = adSegParams[!bReverse ];
2974  }
2975  else
2976  {
2977  // contour is not closed
2978 
2979  // validate bounds
2980  for (int i=0; i<2; ++i )
2981  {
2982  if ( aiIdx[i] < 0 )
2983  {
2984  if ( aiIdx[i] == -1 && adSegParams[i] >= (1.0-dParamTol) )
2985  {
2986  aiIdx[i] = 0;
2987  adSegParams[i] = 0.0;
2988  }
2989  else
2990  return erInvalidIndex;
2991  }
2992  else if ( aiIdx[i] >= long(iNumSegs) )
2993  {
2994  if ( aiIdx[i] == long(iNumSegs) && adSegParams[i] <= dParamTol )
2995  {
2996  aiIdx[i] = long(iNumSegs)-1;
2997  adSegParams[i] = 1.0;
2998  }
2999  else
3000  return erInvalidIndex;
3001  }
3002  }
3003 
3004  iNumPeriodsAB = 0;
3005  uIdxA = OdUInt32( aiIdx[ bReverse ] );
3006  uIdxB = OdUInt32( aiIdx[!bReverse ] );
3007  dSegParamA = adSegParams[ bReverse ];
3008  dSegParamB = adSegParams[!bReverse ];
3009  }
3010 
3011  return eRes;
3012 }
3013 
3014 
3015 
3016 template < class TContourData >
3017 Result TContour2DImpl<TContourData>::_getSubSegment ( OdUInt32 iIndex, double dStartOffs, double dEndOffs, IBulgeSeg2D & rDestSeg ) const
3018 {
3019  TImplSeg2D srcSeg;
3020  Result eRes = this->_getSegment( iIndex, srcSeg );
3021  if ( isError(eRes) )
3022  return eRes;
3023 
3024  return worstResult( eRes, srcSeg.getSubSegment( dStartOffs, dEndOffs, rDestSeg ) );
3025 }
3026 
3027 
3028 template < class TContourData >
3029 Result TContour2DImpl<TContourData>::_appendSubContourTo(double dStartParam, double dEndParam, IContour2D & rSubContour, const OdGeTol & gTol ) const
3030 {
3031  Result eRes = erOk;
3032  OdUInt32 iNumSegs = this->_numSegments();
3033 
3034  // TODO: skip zero-length starting/ending sub-segments
3035 
3036  {
3037  OdUInt32 iNumPeriods = 0;
3038  double adSegParams[2];
3039  OdUInt32 auSegIdxs[2];
3040 
3041  bool bReverse = ( dStartParam > dEndParam );
3042 
3043  eRes = _paramRange2IdxParams(
3044  bReverse ? dEndParam : dStartParam,
3045  bReverse ? dStartParam : dEndParam,
3046  auSegIdxs[0], adSegParams[0], auSegIdxs[1], adSegParams[1], iNumPeriods, 1e-14 );
3047  if ( isError(eRes) )
3048  return eRes;
3049 
3050 #ifdef _DEBUG
3051  if ( iNumSegs > 0 )
3052  {
3053  double dOldLen = ( bReverse ? -1 : 1)*(dEndParam - dStartParam);
3054  double dNewLen = (auSegIdxs[1]+adSegParams[1]) - (auSegIdxs[0]+adSegParams[0]) + iNumPeriods*double(iNumSegs);
3055  FMGE_ASSERT( OdEqual( dOldLen , dNewLen, 1e-10 ) );
3056 
3057  FMGE_ASSERT( auSegIdxs[0] < OdUInt32(iNumSegs) && auSegIdxs[1] < OdUInt32(iNumSegs) );
3058  FMGE_ASSERT( this->_closed() || 0==iNumPeriods );
3059  }
3060 #endif //_DEBUG
3061 
3062  if ( iNumPeriods < 0 || ( iNumPeriods==0 && auSegIdxs[0] > auSegIdxs[1] ) )
3063  {
3064  FMGE_FAULT("Illegal values caused by buggy code or FP-inaccuracy!");
3065  return erFail;
3066  }
3067 
3068  // Case 0: Append one point
3069  if ( erWarnEmptyContour==eRes )
3070  {
3071  TImplSeg2D srcSeg;
3072  Result tmpRes = this->_getSegment( auSegIdxs[bReverse], srcSeg );
3073  if ( isError(tmpRes) )
3074  return tmpRes;
3075 
3076  OdGePoint2d ptPoint;
3077  tmpRes = srcSeg.getPoint( adSegParams[bReverse], ptPoint );
3078  if ( isError(tmpRes) )
3079  return tmpRes;
3080 
3081  eRes = worstResult( eRes, rSubContour.appendSegment(
3082  BulgeSeg2D( ptPoint, ptPoint, 0.0, srcSeg.attributes() ),
3083  false, gTol ) );
3084 
3085  return eRes;
3086  }
3087 
3088  // Case 1: Append one (sub-)segment
3089  if ( auSegIdxs[0]==auSegIdxs[1] && 0==iNumPeriods )
3090  {
3091  BulgeSeg2D gSingleSeg;
3092  eRes = worstResult( eRes, _getSubSegment(
3093  auSegIdxs[0], adSegParams[ bReverse ], adSegParams[ !bReverse ], gSingleSeg ) );
3094  if ( isError(eRes) )
3095  return eRes;
3096 
3097  eRes = worstResult( eRes, rSubContour.appendSegment( gSingleSeg, false, gTol ) );
3098  return eRes;
3099  }
3100 
3102  // default case: Append multiple segments
3103  if ( iNumSegs <= 0 )
3104  {
3106  return erFail;
3107  }
3108 
3109  // get first/last (sub-)segments
3110  BulgeSeg2D gBoundarySegs[2];
3111  eRes = worstResult( eRes, _getSubSegment( auSegIdxs[0], adSegParams[0], 1.0, gBoundarySegs[0] ) );
3112  eRes = worstResult( eRes, _getSubSegment( auSegIdxs[1], 0.0, adSegParams[1], gBoundarySegs[1] ) );
3113  if ( isError(eRes) )
3114  return eRes;
3115 
3116  // first/last unbroken segments (should be copied as is)
3117  OdUInt32 aiUnbrokenSegs[2];
3118  aiUnbrokenSegs[0] = auSegIdxs[0] + 1;
3119  aiUnbrokenSegs[1] = auSegIdxs[1] - 1 + iNumPeriods*OdUInt32(iNumSegs);
3120 
3121  OdUInt32 iNumUnbroken = ( aiUnbrokenSegs[1] - aiUnbrokenSegs[0] + 1 );
3122  FMGE_ASSERT( iNumUnbroken >= 0 );
3123 
3124  OdUInt32 iDestVerts = rSubContour.numVerts();
3125  rSubContour.reserveVertices( iDestVerts + iNumUnbroken + 2 + 1 );
3126 
3127  if ( bReverse )
3128  {
3129  gBoundarySegs[0].reverse();
3130  gBoundarySegs[1].reverse();
3131  }
3132 
3133  // append the first segment. Fail if there is a big gap
3134  eRes = worstResult( eRes, rSubContour.appendSegment( gBoundarySegs[ bReverse ], false, gTol ) );
3135  if ( isError(eRes) )
3136  return eRes;
3137 
3138 
3139  // append middle segments
3140  if ( !bReverse )
3141  {
3142  // append in normal direction
3143  FMGE_ASSERT( aiUnbrokenSegs[0] >= 0 );
3144  TImplSeg2D srcSeg;
3145  for (OdUInt32 iSeg = aiUnbrokenSegs[0]; iSeg <= aiUnbrokenSegs[1]; ++iSeg )
3146  {
3147  OdUInt32 iIndex = OdUInt32( iSeg % OdUInt32(iNumSegs) );
3148  Result tmpRes = this->_getSegment( iIndex, srcSeg );
3149 
3150  FMGE_ASSERT( erOk==tmpRes );
3151  if ( isError(tmpRes) )
3152  return tmpRes;
3153 
3154  tmpRes = rSubContour.appendSegment( srcSeg._bulge(), srcSeg._endPt(), srcSeg._attr() );
3155  if ( isError(tmpRes) )
3156  return tmpRes;
3157  }
3158  }
3159  else
3160  {
3161  // append in reverse direction
3162  FMGE_ASSERT( aiUnbrokenSegs[0] >= 0 );
3163  for (OdUInt32 iSeg = aiUnbrokenSegs[1]; iSeg >= aiUnbrokenSegs[0]; --iSeg )
3164  {
3165  OdUInt32 iIndex = OdUInt32( iSeg % OdUInt32(iNumSegs) );
3166  const TVertexData & rVert = this->_vertex( iIndex );
3167 
3168  // append reversed segment
3169  Result tmpRes = rSubContour.appendSegment( -rVert.bulge(), rVert.point(), rVert.attributes().getReversed() );
3170  if ( isError(tmpRes) )
3171  return tmpRes;
3172  }
3173  }
3174 
3175  eRes = worstResult( eRes, rSubContour.appendSegment( gBoundarySegs[ !bReverse ], false, gTol ) );
3176  FMGE_ASSERT( isOk(eRes) ); // fails iff this code is buggy ?
3177  if ( isError(eRes) )
3178  return eRes;
3179  }
3180 
3181  return eRes;
3182 }
3183 
3184 
3185 
3186 template < class TContourData >
3188  double dStartParam, double dEndParam, IContour2D & rSubContour, const OdGeTol & gTol ) const
3189 {
3190  FMGE_ASSERT( ! _isEqualToThis(rSubContour) );
3191  if ( _isEqualToThis(rSubContour) )
3192  return erInvalidArgs;
3193 
3194  rSubContour.reset();
3195  return _appendSubContourTo( dStartParam, dEndParam, rSubContour, gTol );
3196 }
3197 
3198 template < class TContourData >
3200  double dStartParam, double dEndParam, IContour2D & rSubContour, const OdGeTol & gTol ) const
3201 {
3202  FMGE_ASSERT( ! _isEqualToThis(rSubContour) );
3203  if ( _isEqualToThis(rSubContour) )
3204  return erInvalidArgs;
3205 
3206  return _appendSubContourTo( dStartParam, dEndParam, rSubContour, gTol );
3207 }
3208 
3209 
3210 
3211 template < class TContourData >
3213 {
3214  FMGE_ASSERT( !_isEqualToThis(rDest) && (&rDest != &rSubContour) );
3215  if ( _isEqualToThis(rDest) || &rDest == &rSubContour )
3216  return erInvalidArgs;
3217 
3218  if ( rSubContour.isEmpty() )
3219  {
3220  rDest.set( *this );
3221  return erWarnEmptyContour;
3222  }
3223 
3224  Result eRes = erOk;
3225 
3226  OdGePoint2d aSubEnds[2];
3227  if ( erOk != ( eRes = rSubContour.getStartPoint( aSubEnds[0] ) )
3228  || erOk != ( eRes = rSubContour.getEndPoint( aSubEnds[1] ) ) )
3229  return eRes;
3230 
3231  double adParams[2];
3232  if ( !isOn( aSubEnds[0], &(adParams[0]), gTol )
3233  ||!isOn( aSubEnds[1], &(adParams[1]), gTol ) )
3234  return erPointNotOnThis;
3235 
3236  // now we have 2 points, 2 parameters and should replace
3237  // part of this contour from adParams[0] to adParams[1] with rSubContour
3238 
3239  bool bEqualEnds = aSubEnds[0].isEqualTo( aSubEnds[1], gTol );
3240  double dParamLength = double( this->_numSegments() );
3241 
3242  if ( this->_closed() )
3243  {
3244  rDest.reset();
3245 
3246  double dLoopStart = adParams[1];
3247  double dLoopEnd = adParams[0];
3248 
3249  if ( bEqualEnds )
3250  dLoopEnd = dLoopStart + dParamLength;
3251  else if ( dLoopEnd < dLoopStart )
3252  dLoopEnd += dParamLength;
3253 
3254  eRes = _appendSubContourTo( dLoopStart, dLoopEnd, rDest, gTol );
3255  if ( isError(eRes) )
3256  return eRes;
3257 
3258  eRes = rDest.appendContour( rSubContour );
3259  if ( isOk(eRes) )
3260  {
3261  // remove duplicate vertex and close the contour
3262  rDest.setClosedIfEndsAreEqual( gTol );
3263  rDest.setClosed( true );
3264  }
3265  }
3266  else
3267  {
3268  // Open contour
3269  if ( bEqualEnds )
3270  adParams[1] = adParams[0];
3271  else if ( adParams[0] > adParams[1] )
3272  return erInvalidDirection;
3273 
3274  rDest.reset();
3275 
3276  if ( adParams[0] > 0 )
3277  eRes = _appendSubContourTo( 0.0, adParams[0], rDest, gTol );
3278 
3279  if ( isOk(eRes) )
3280  eRes = rDest.appendContour( rSubContour );
3281 
3282  if ( isOk(eRes) && ( adParams[1] < dParamLength ) )
3283  eRes = _appendSubContourTo( adParams[1], dParamLength, rDest, gTol );
3284  }
3285 
3286  return eRes;
3287 }
3288 
3289 
3290 
3291 
3292 }; // namespace FacetModeler
3293 
3294 
3295 
3296 #endif //__FM_T_CONTOUR2D_IMPL_H__
3297 
3298 
3299 
3300 
3301 
3302 
3303 
3304 
3305 
3306 
3307 
3308 
3309 
3310 
3311 
3312 
3313 
3314 
3315 
3316 
3317 
#define ODA_ASSERT(exp)
Definition: DebugStuff.h:49
#define FMGE_ASSERTMSG(x, c)
#define FMGE_ASSERT(x)
#define FMGE_MUSTNOTEXECUTE
#define FMGE_FAULT(c)
#define odmin(X, Y)
Definition: OdPlatform.h:34
unsigned int OdUInt32
int OdInt32
ptrdiff_t OdIntPtr
#define Oda2PI
Definition: OdaCommon.h:57
bool OdEqual(double x, double y, double tol=1.e-10)
Definition: OdaDefs.h:525
bool OdZero(double x, double tol=1.e-10)
Definition: OdaDefs.h:515
static FMGEOMETRY_API_STATIC const Attributes2D kNull
Result set(const CachedSeg2D &rSeg)
virtual const Attributes2D & attributes() const
virtual double arcAngle() const
virtual double arcRadius() const
virtual SegmentType type() const
virtual double length() const
virtual Result getPoint(double dParam, OdGePoint2d &ptPoint) const
virtual OdUInt32 intersectLine(const OdGePoint2d &ptLineOrigin, const OdGeVector2d &vLineDir, Intersection *pInt1=0, Intersection *pInt2=0, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual double integrate(const OdGePoint2d &ptOrigin=OdGePoint2d::kOrigin) const
virtual bool isOn(const OdGePoint2d &ptTest, double *pdParam=0, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual const OdGePoint2d & endPt() const =0
virtual Result set(const OdGePoint2d &ptA, const OdGePoint2d &ptB, double dBulge, const Attributes2D &rAttr)=0
virtual const Attributes2D & attributes() const =0
virtual double bulge() const =0
virtual bool isOn(const OdGePoint2d &ptTest, double *pdParam=0, const OdGeTol &gTol=FMGeGbl::gTol) const =0
virtual const OdGePoint2d & startPt() const =0
virtual OdUInt32 intersect(const IBulgeSeg2D &rSegB, std::vector< Intersection > &vecPoints, const OdGeTol &gTol=FMGeGbl::gTol) const =0
virtual Result appendSegment(const IBulgeSeg2D &rSeg, bool bShiftToHit=false, const OdGeTol &gTol=FMGeGbl::gTol)=0
virtual Result getVertexAt(OdUInt32 iIndex, OdGePoint2d *pptPoint, double *pdBulge=0, Attributes2D *pAttr=0) const =0
virtual bool isClosed() const =0
virtual void set(const IContour2D &rSrcCont)=0
virtual Result setAttributesAt(OdUInt32 iIndex, const Attributes2D &rAttr)=0
virtual Result getStartPoint(OdGePoint2d &ptPoint) const =0
virtual void reserveVertices(OdUInt32 iReservedSize)=0
virtual bool setClosedIfEndsAreEqual(const OdGeTol &gTol=FMGeGbl::gTol)=0
virtual void reset()=0
virtual bool hasArcs() const =0
virtual bool isEmpty() const =0
virtual void setClosed(bool bClosed=true)=0
virtual bool contains(const OdGePoint2d &rPoint, bool *pbOnBorder=0, const OdGeTol &gTol=FMGeGbl::gTol) const =0
virtual OdUInt32 numVerts() const =0
virtual Result appendContour(const IContour2D &rCont, bool bCloseGap=false, double dMaxGap=1e99)=0
virtual Result getEndPoint(OdGePoint2d &ptPoint) const =0
virtual Result appendVertices(const OdGePoint2dArray &vecSource)=0
virtual OdUInt32 numSegments() const =0
virtual Result getPointAt(OdUInt32 iIndex, OdGePoint2d &ptPoint) const
virtual Result replaceSubContourTo(IContour2D &rDest, const IContour2D &rSubContour, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual OdUInt32 intersect(const IContour2D &rContB, std::vector< Intersection > &vecPoints, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual bool isSelfIntersecting(const OdGeTol &gTol=FMGeGbl::gTol, bool bExcludeTouch=false) const
Result _getSubSegment(OdUInt32 iIndex, double dStartOffs, double dEndOffs, IBulgeSeg2D &rDestSeg) const
Result _param2dist(double dParam, double &dDist) const
virtual Result appendSegment(double dBulge, const OdGePoint2d &ptNewEnd, const Attributes2D &rAttr=Attributes2D::kNull)
virtual OdUInt32 intersect(const IBulgeSeg2D &rSegB, std::vector< Intersection > &vecPoints, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual Result appendContour(const IContour2D &rCont, bool bCloseGap=false, double dMaxGap=1e99)
virtual Result getInternalPoint(OdGePoint2d &rPoint, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual double signedMinDistByParams(double dParam1, double dParam2) const
virtual Result setVertexAt(OdUInt32 iIndex, const OdGePoint2d &ptPoint, double dBulge)
virtual bool isClosed() const
virtual Result removeVertexAt(OdUInt32 iIndex)
virtual double signedMinDist(double dDist1, double dDist2) const
virtual Result getSubContour(double dStartParam, double dEndParam, IContour2D &rSubContour, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual Result getNormalizedDist(double &dDist) const
virtual double nearestParam(const OdGePoint2d &ptTest, OdGePoint2d *ptNearest=0) const
virtual OdUInt32 createVertexAt(double dParam, const OdGeTol &gTol=FMGeGbl::gTol)
Result _dist2IdxParam(double dDist, OdUInt32 &iIndex, double &dSegParam) const
virtual void deleteCoincident(const OdGeTol &gTol=FMGeGbl::gTol)
Result _param2IdxParam(double dParam, OdUInt32 &iIndex, double &dSegParam) const
virtual Result appendVertex(const OdGePoint2d &ptStart, double dBulge=0.0, const Attributes2D &rAttr=Attributes2D::kNull)
virtual IContour2D * clone() const
virtual OdUInt32 numSegments() const
Result _normalizeParam(double &dParam) const
Result _createVerticesAt(OdUInt32 uCount, const double *pdParams, const OdGeTol &gTol)
virtual Result setBulgeAt(OdUInt32 iIndex, double dBulge)
virtual Result getSegmentAt(OdUInt32 iIndex, IBulgeSeg2D &rSegment) const
virtual void reserveVertices(OdUInt32 iReservedSize)
virtual bool isConvex() const
Result _appendSubContourTo(double dStartParam, double dEndParam, IContour2D &rSubContour, const OdGeTol &gTol) const
virtual OdUInt32 intersectLine(const OdGePoint2d &ptLineOrigin, const OdGeVector2d &vLineDir, std::vector< Intersection > &vecPoints, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual Result getInternalAngleAt(OdUInt32 iIndex, double &dAngle) const
virtual Result appendSubContourTo(double dStartParam, double dEndParam, IContour2D &rSubContour, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual Result getSegmentAt(OdUInt32 iIndex, OdGePoint2d &ptStart, OdGePoint2d &ptEnd, double &dBulge) const
virtual double signedArea() const
virtual Result explodeTo(IContour2D &rDestCont, const DeviationParams &devDeviation=FMGeGbl::gDefDev, OdIntPtr uArcMetadata=0) const
virtual Result setAttributesAt(OdUInt32 iIndex, const Attributes2D &rAttr)
virtual bool isEmpty() const
virtual Result transformBy(const OdGeMatrix2d &geMatrix, const DeviationParams &devDeviation=FMGeGbl::gDefDev)
virtual Result appendSegment(const IBulgeSeg2D &rSeg, bool bShiftToHit=false, const OdGeTol &gTol=FMGeGbl::gTol)
virtual Result getParamAtDist(double dDist, double &dParam) const
virtual Result getStartPoint(OdGePoint2d &ptPoint) const
virtual OdUInt32 numVerts() const
virtual Result getPoint(double dParam, OdGePoint2d &ptPoint) const
virtual Result getDistAtParam(double dParam, double &dDist) const
virtual Result getNormalizedParam(double &dParam) const
virtual Attributes2D & attributes4UAt(OdUInt32 iIndex)
virtual SegmentType segmentType(OdUInt32 iIndex) const
virtual void setClosed(bool bClosed=true)
virtual bool setClosedIfEndsAreEqual(const OdGeTol &gTol=FMGeGbl::gTol)
virtual bool areEqualDists(double dDist1, double dDist2, const double dTol=FMGeGbl::gTol.equalPoint()) const
virtual Result getBulgeAt(OdUInt32 iIndex, double &dBulge) const
Result _paramRange2IdxParams(const double dParamA, const double dParamB, OdUInt32 &uIdxA, double &dSegParamA, OdUInt32 &uIdxB, double &dSegParamB, OdUInt32 &iNumPeriodsAB, const double dParamTol=DBL_EPSILON) const
virtual Result getPointAtDist(double dDist, OdGePoint2d &ptPoint) const
virtual bool contains(const OdGePoint2d &rPoint, bool *pbOnBorder=0, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual void set(const IContour2D &rSrcCont)
virtual ContourImplClass implClass() const
virtual bool hasArcs() const
TContourData::VertexData TVertexData
virtual Result getEndPoint(OdGePoint2d &ptPoint) const
virtual Result createVerticesAt(const std::vector< double > &vecParams, const OdGeTol &gTol=FMGeGbl::gTol)
virtual Result addVertexAt(OdUInt32 iIndex, const OdGePoint2d &ptStart, double dBulge=0.0, const Attributes2D &rAttr=Attributes2D::kNull)
virtual Result appendVertices(const OdGePoint2dArray &vecSource)
TContour2DImpl(const TContour2DImpl &rSrcCont)
virtual const Attributes2D & attributesAt(OdUInt32 iIndex) const
virtual bool isInsideContour(const IContour2D &c2dOuter, bool fAllowBordersTouch=false, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual Result getArcSegAt(OdUInt32 iIndex, OdGeCircArc2d &geArc) const
TContourData::ImplSeg2D TImplSeg2D
virtual Result getLineSegAt(OdUInt32 iIndex, OdGeLineSeg2d &geLine) const
virtual OdIntPtr metadataAt(OdUInt32 iIndex) const
virtual Result getTangent(double dParam, OdGeVector2d &vTangent) const
bool _isEqualToThis(const IContour2D &rC) const
virtual double length() const
virtual bool areEqualParams(double dParam1, double dParam2, const double dTol=1e-10) const
virtual void mergeSegments(int iMergeFlags=0, const OdGeTol &gTol=FMGeGbl::gTol)
virtual bool isOn(const OdGePoint2d &ptTest, double *pdParam=0, const OdGeTol &gTol=FMGeGbl::gTol) const
virtual Result addExtents(OdGeExtents2d &geExtents) const
virtual Result getVertexAt(OdUInt32 iIndex, OdGePoint2d *pptPoint, double *pdBulge=0, Attributes2D *pAttr=0) const
virtual Result setMetadataAt(OdUInt32 iIndex, OdIntPtr uNewData)
virtual Result setPointAt(OdUInt32 iIndex, const OdGePoint2d &ptPoint)
virtual bool isValidRegion(const OdGeTol &gTol=FMGeGbl::gTol) const
bool empty() const
Definition: OdArray.h:901
size_type size() const
Definition: OdArray.h:893
void push_back(const T &value)
Definition: OdArray.h:987
void reserve(size_type reserveLength)
Definition: OdArray.h:920
void addExt(const OdGeExtents2d &extents)
Definition: GeExtents2d.h:129
void addPoint(const OdGePoint2d &point)
Definition: GeExtents2d.h:108
double det() const
void getCoordSystem(OdGePoint2d &origin, OdGeVector2d &xAxis, OdGeVector2d &yAxis) const
double x
Definition: GePoint2d.h:299
double y
Definition: GePoint2d.h:300
bool isEqualTo(const OdGePoint2d &point, const OdGeTol &tol=OdGeContext::gTol) const
static GE_STATIC_EXPORT const OdGePoint2d kOrigin
Definition: GePoint2d.h:80
double distanceTo(const OdGePoint2d &point) const
Definition: GePoint2d.h:236
Definition: GeTol.h:49
double equalVector() const
Definition: GeTol.h:76
double equalPoint() const
Definition: GeTol.h:68
double crossProduct(const OdGeVector2d &vect) const
Definition: GeVector2d.h:397
bool isZeroLength(const OdGeTol &tol=OdGeContext::gTol) const
static GE_STATIC_EXPORT const OdGeVector2d kIdentity
Definition: GeVector2d.h:65
double angleToCCW(const OdGeVector2d &vect) const
Definition: GeVector2d.h:201
OdGeVector2d & negate()
GLuint GLsizei GLsizei * length
Definition: gles2_ext.h:274
GLfloat x
Definition: gles2_ext.h:314
GLfloat GLfloat y
Definition: gles2_ext.h:316
Result fast_isValidRegion(const IContour2D &rContour, const OdGeTol &gTol, bool &bValidRegion)
bool isOk(Result eRes)
Result fast_isSelfIntersecting(const IContour2D &rContour, const OdGeTol &gTol, bool &bIntersects)
Result fast_getInternalPoint(const IContour2D &rContour, OdGePoint2d &rPoint, const OdGeTol &gTol)
bool isError(Result eRes)
Result fast_intersect(const IContour2D &rContA, const IContour2D &rContB, std::vector< Intersection > &vecPoints, const OdGeTol &gTol)
void contour2d_mergeSegments(IContour2D &rContour, int iMergeFlags=0, const OdGeTol &gTol=FMGeGbl::gTol)
Result worstResult(Result eRes1, Result eRes2)
Attributes2D & nullAttributesForUpdate()
void swap(signal< Handler, SignalTraits, Allocator > &lhs, signal< Handler, SignalTraits, Allocator > &rhs)
static FMGEOMETRY_API_STATIC OdUInt16 GetSegmentCount(double dAngle, double dRadius, const DeviationParams &devDeviation)
static FMGEOMETRY_API_STATIC DeviationParams gDefDev
Definition: FMGeometry.h:148
static FMGEOMETRY_API_STATIC OdGeTol gTol
Definition: FMGeometry.h:156