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