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