KiCad PCB EDA Suite
Loading...
Searching...
No Matches
shape_poly_set.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2015-2019 CERN
5 * Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Tomasz Wlostowski <[email protected]>
8 * @author Alejandro García Montoro <[email protected]>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, you may find one here:
22 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23 * or you may search the http://www.gnu.org website for the version 2 license,
24 * or you may write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 */
27
28#ifndef __SHAPE_POLY_SET_H
29#define __SHAPE_POLY_SET_H
30
31#include <cstdio>
32#include <deque> // for deque
33#include <iosfwd> // for string, stringstream
34#include <memory>
35#include <set> // for set
36#include <stdexcept> // for out_of_range
37#include <stdlib.h> // for abs
38#include <vector>
39
40#include <clipper.hpp> // for ClipType, PolyTree (ptr only)
41#include <clipper2/clipper.h>
43#include <geometry/seg.h> // for SEG
44#include <geometry/shape.h>
46#include <math/box2.h> // for BOX2I
47#include <math/vector2d.h> // for VECTOR2I
48#include <md5_hash.h>
49
50
65class SHAPE_POLY_SET : public SHAPE
66{
67public:
71 typedef std::vector<SHAPE_LINE_CHAIN> POLYGON;
72
74 {
75 public:
76 struct TRI : public SHAPE_LINE_CHAIN_BASE
77 {
78 TRI( int _a = 0, int _b = 0, int _c = 0, TRIANGULATED_POLYGON* aParent = nullptr ) :
80 a( _a ),
81 b( _b ),
82 c( _c ),
83 parent( aParent )
84 {
85 }
86
87 virtual void Rotate( const EDA_ANGLE& aAngle,
88 const VECTOR2I& aCenter = { 0, 0 } ) override {};
89
90 virtual void Move( const VECTOR2I& aVector ) override {};
91
92 virtual bool IsSolid() const override { return true; }
93
94 virtual bool IsClosed() const override { return true; }
95
96 virtual const BOX2I BBox( int aClearance = 0 ) const override;
97
98 virtual const VECTOR2I GetPoint( int aIndex ) const override
99 {
100 switch(aIndex)
101 {
102 case 0: return parent->m_vertices[a];
103 case 1: return parent->m_vertices[b];
104 case 2: return parent->m_vertices[c];
105 default: wxCHECK( false, VECTOR2I() );
106 }
107 }
108
109 virtual const SEG GetSegment( int aIndex ) const override
110 {
111 switch(aIndex)
112 {
113 case 0: return SEG( parent->m_vertices[a], parent->m_vertices[b] );
114 case 1: return SEG( parent->m_vertices[b], parent->m_vertices[c] );
115 case 2: return SEG( parent->m_vertices[c], parent->m_vertices[a] );
116 default: wxCHECK( false, SEG() );
117 }
118 }
119
120 virtual size_t GetPointCount() const override { return 3; }
121 virtual size_t GetSegmentCount() const override { return 3; }
122
123 int a;
124 int b;
125 int c;
127 };
128
129 TRIANGULATED_POLYGON( int aSourceOutline );
132
133 void Clear()
134 {
135 m_vertices.clear();
136 m_triangles.clear();
137 }
138
139 void GetTriangle( int index, VECTOR2I& a, VECTOR2I& b, VECTOR2I& c ) const
140 {
141 auto tri = m_triangles[ index ];
142 a = m_vertices[ tri.a ];
143 b = m_vertices[ tri.b ];
144 c = m_vertices[ tri.c ];
145 }
146
148
149 void AddTriangle( int a, int b, int c );
150
151 void AddVertex( const VECTOR2I& aP )
152 {
153 m_vertices.push_back( aP );
154 }
155
156 size_t GetTriangleCount() const { return m_triangles.size(); }
157
159 void SetSourceOutlineIndex( int aIndex ) { m_sourceOutline = aIndex; }
160
161 std::deque<TRI>& Triangles() { return m_triangles; }
162 const std::deque<TRI>& Triangles() const { return m_triangles; }
163
164 size_t GetVertexCount() const
165 {
166 return m_vertices.size();
167 }
168
169 void Move( const VECTOR2I& aVec )
170 {
171 for( VECTOR2I& vertex : m_vertices )
172 vertex += aVec;
173 }
174
175 private:
177 std::deque<TRI> m_triangles;
178 std::deque<VECTOR2I> m_vertices;
179 };
180
187 {
193 m_polygon(-1),
194 m_contour(-1),
195 m_vertex(-1)
196 {
197 }
198 };
199
203 template <class T>
205 {
206 public:
207
212 bool IsEndContour() const
213 {
214 return m_currentVertex + 1 ==
216 }
217
221 bool IsLastPolygon() const
222 {
224 }
225
226 operator bool() const
227 {
229 return true;
230
231 if( m_currentPolygon != m_poly->OutlineCount() - 1 )
232 return false;
233
234 const auto& currentPolygon = m_poly->CPolygon( m_currentPolygon );
235
236 return m_currentContour < (int) currentPolygon.size() - 1
237 || m_currentVertex < currentPolygon[m_currentContour].PointCount();
238 }
239
244 void Advance()
245 {
246 // Advance vertex index
248
249 // Check whether the user wants to iterate through the vertices of the holes
250 // and behave accordingly
251 if( m_iterateHoles )
252 {
253 // If the last vertex of the contour was reached, advance the contour index
254 if( m_currentVertex >=
256 {
257 m_currentVertex = 0;
259
260 // If the last contour of the current polygon was reached, advance the
261 // outline index
262 int totalContours = m_poly->CPolygon( m_currentPolygon ).size();
263
264 if( m_currentContour >= totalContours )
265 {
268 }
269 }
270 }
271 else
272 {
273 // If the last vertex of the outline was reached, advance to the following polygon
274 if( m_currentVertex >= m_poly->CPolygon( m_currentPolygon )[0].PointCount() )
275 {
276 m_currentVertex = 0;
278 }
279 }
280 }
281
282 void operator++( int dummy )
283 {
284 Advance();
285 }
286
288 {
289 Advance();
290 }
291
292 const T& Get()
293 {
295 }
296
297 const T& operator*()
298 {
299 return Get();
300 }
301
302 const T* operator->()
303 {
304 return &Get();
305 }
306
311 {
312 VERTEX_INDEX index;
313
317
318 return index;
319 }
320
321 private:
322 friend class SHAPE_POLY_SET;
323
330 };
331
335 template <class T>
337 {
338 public:
342 bool IsLastPolygon() const
343 {
345 }
346
347 operator bool() const
348 {
350 }
351
356 void Advance()
357 {
358 // Advance vertex index
360 int last;
361
362 // Check whether the user wants to iterate through the vertices of the holes
363 // and behave accordingly.
364 if( m_iterateHoles )
365 {
366 last = m_poly->CPolygon( m_currentPolygon )[m_currentContour].SegmentCount();
367
368 // If the last vertex of the contour was reached, advance the contour index.
369 if( m_currentSegment >= last )
370 {
373
374 // If the last contour of the current polygon was reached, advance the
375 // outline index.
376 int totalContours = m_poly->CPolygon( m_currentPolygon ).size();
377
378 if( m_currentContour >= totalContours )
379 {
382 }
383 }
384 }
385 else
386 {
387 last = m_poly->CPolygon( m_currentPolygon )[0].SegmentCount();
388 // If the last vertex of the outline was reached, advance to the following
389 // polygon
390 if( m_currentSegment >= last )
391 {
394 }
395 }
396 }
397
398 void operator++( int dummy )
399 {
400 Advance();
401 }
402
404 {
405 Advance();
406 }
407
408 T Get()
409 {
411 }
412
414 {
415 return Get();
416 }
417
422 {
423 VERTEX_INDEX index;
424
428
429 return index;
430 }
431
438 {
439 // Check that both iterators point to the same contour of the same polygon of the
440 // same polygon set.
441 if( m_poly == aOther.m_poly && m_currentPolygon == aOther.m_currentPolygon &&
443 {
444 // Compute the total number of segments.
445 int numSeg;
446 numSeg = m_poly->CPolygon( m_currentPolygon )[m_currentContour].SegmentCount();
447
448 // Compute the difference of the segment indices. If it is exactly one, they
449 // are adjacent. The only missing case where they also are adjacent is when
450 // the segments are the first and last one, in which case the difference
451 // always equals the total number of segments minus one.
452 int indexDiff = std::abs( m_currentSegment - aOther.m_currentSegment );
453
454 return ( indexDiff == 1 ) || ( indexDiff == (numSeg - 1) );
455 }
456
457 return false;
458 }
459
460 private:
461 friend class SHAPE_POLY_SET;
462
469 };
470
471 // Iterator and const iterator types to visit polygon's points.
474
475 // Iterator and const iterator types to visit polygon's edges.
478
480
481 SHAPE_POLY_SET( const BOX2D& aRect );
482
488 SHAPE_POLY_SET( const SHAPE_LINE_CHAIN& aOutline );
489
495 SHAPE_POLY_SET( const POLYGON& aPolygon );
496
503 SHAPE_POLY_SET( const SHAPE_POLY_SET& aOther );
504
506
507 SHAPE_POLY_SET& operator=( const SHAPE_POLY_SET& aOther );
508
520 void CacheTriangulation( bool aPartition = true, bool aSimplify = false );
521 bool IsTriangulationUpToDate() const;
522
523 MD5_HASH GetHash() const;
524
525 virtual bool HasIndexableSubshapes() const override;
526
527 virtual size_t GetIndexableSubshapeCount() const override;
528
529 virtual void GetIndexableSubshapes( std::vector<const SHAPE*>& aSubshapes ) const override;
530
542 bool GetRelativeIndices( int aGlobalIdx, VERTEX_INDEX* aRelativeIndices ) const;
543
553 bool GetGlobalIndex( VERTEX_INDEX aRelativeIndices, int& aGlobalIdx ) const;
554
556 SHAPE* Clone() const override;
557
559
561 int NewOutline();
562
564 int NewHole( int aOutline = -1 );
565
567 int AddOutline( const SHAPE_LINE_CHAIN& aOutline );
568
570 int AddHole( const SHAPE_LINE_CHAIN& aHole, int aOutline = -1 );
571
573 int AddPolygon( const POLYGON& apolygon );
574
576 double Area();
577
579 int ArcCount() const;
580
582 void GetArcs( std::vector<SHAPE_ARC>& aArcBuffer ) const;
583
585 void ClearArcs();
586
588
600 int Append( int x, int y, int aOutline = -1, int aHole = -1, bool aAllowDuplication = false );
601
603 void Append( const SHAPE_POLY_SET& aSet );
604
606 void Append( const VECTOR2I& aP, int aOutline = -1, int aHole = -1 );
607
617 int Append( const SHAPE_ARC& aArc, int aOutline = -1, int aHole = -1,
618 double aAccuracy = SHAPE_ARC::DefaultAccuracyForPCB() );
619
627 void InsertVertex( int aGlobalIndex, const VECTOR2I& aNewVertex );
628
630 const VECTOR2I& CVertex( int aIndex, int aOutline, int aHole ) const;
631
633 const VECTOR2I& CVertex( int aGlobalIndex ) const;
634
636 const VECTOR2I& CVertex( VERTEX_INDEX aIndex ) const;
637
651 bool GetNeighbourIndexes( int aGlobalIndex, int* aPrevious, int* aNext ) const;
652
659 bool IsPolygonSelfIntersecting( int aPolygonIndex ) const;
660
666 bool IsSelfIntersecting() const;
667
669 unsigned int TriangulatedPolyCount() const { return m_triangulatedPolys.size(); }
670
672 int OutlineCount() const { return m_polys.size(); }
673
675 int VertexCount( int aOutline = -1, int aHole = -1 ) const;
676
679 int FullPointCount() const;
680
682 int HoleCount( int aOutline ) const
683 {
684 if( ( aOutline < 0 ) || ( aOutline >= (int) m_polys.size() )
685 || ( m_polys[aOutline].size() < 2 ) )
686 return 0;
687
688 // the first polygon in m_polys[aOutline] is the main contour,
689 // only others are holes:
690 return m_polys[aOutline].size() - 1;
691 }
692
695 {
696 return m_polys[aIndex][0];
697 }
698
699 const SHAPE_LINE_CHAIN& Outline( int aIndex ) const
700 {
701 return m_polys[aIndex][0];
702 }
703
713 SHAPE_POLY_SET Subset( int aFirstPolygon, int aLastPolygon );
714
715 SHAPE_POLY_SET UnitSet( int aPolygonIndex )
716 {
717 return Subset( aPolygonIndex, aPolygonIndex + 1 );
718 }
719
721 SHAPE_LINE_CHAIN& Hole( int aOutline, int aHole )
722 {
723 return m_polys[aOutline][aHole + 1];
724 }
725
727 POLYGON& Polygon( int aIndex )
728 {
729 return m_polys[aIndex];
730 }
731
732 const POLYGON& Polygon( int aIndex ) const
733 {
734 return m_polys[aIndex];
735 }
736
737 const TRIANGULATED_POLYGON* TriangulatedPolygon( int aIndex ) const
738 {
739 return m_triangulatedPolys[aIndex].get();
740 }
741
742 const SHAPE_LINE_CHAIN& COutline( int aIndex ) const
743 {
744 return m_polys[aIndex][0];
745 }
746
747 const SHAPE_LINE_CHAIN& CHole( int aOutline, int aHole ) const
748 {
749 return m_polys[aOutline][aHole + 1];
750 }
751
752 const POLYGON& CPolygon( int aIndex ) const
753 {
754 return m_polys[aIndex];
755 }
756
757 const std::vector<POLYGON>& CPolygons() const { return m_polys; }
758
769 ITERATOR Iterate( int aFirst, int aLast, bool aIterateHoles = false )
770 {
771 ITERATOR iter;
772
773 iter.m_poly = this;
774 iter.m_currentPolygon = aFirst;
775 iter.m_lastPolygon = aLast < 0 ? OutlineCount() - 1 : aLast;
776 iter.m_currentContour = 0;
777 iter.m_currentVertex = 0;
778 iter.m_iterateHoles = aIterateHoles;
779
780 return iter;
781 }
782
788 ITERATOR Iterate( int aOutline )
789 {
790 return Iterate( aOutline, aOutline );
791 }
792
799 {
800 return Iterate( aOutline, aOutline, true );
801 }
802
808 {
809 return Iterate( 0, OutlineCount() - 1 );
810 }
811
817 {
818 return Iterate( 0, OutlineCount() - 1, true );
819 }
820
821
822 CONST_ITERATOR CIterate( int aFirst, int aLast, bool aIterateHoles = false ) const
823 {
824 CONST_ITERATOR iter;
825
826 iter.m_poly = const_cast<SHAPE_POLY_SET*>( this );
827 iter.m_currentPolygon = aFirst;
828 iter.m_lastPolygon = aLast < 0 ? OutlineCount() - 1 : aLast;
829 iter.m_currentContour = 0;
830 iter.m_currentVertex = 0;
831 iter.m_iterateHoles = aIterateHoles;
832
833 return iter;
834 }
835
836 CONST_ITERATOR CIterate( int aOutline ) const
837 {
838 return CIterate( aOutline, aOutline );
839 }
840
841 CONST_ITERATOR CIterateWithHoles( int aOutline ) const
842 {
843 return CIterate( aOutline, aOutline, true );
844 }
845
847 {
848 return CIterate( 0, OutlineCount() - 1 );
849 }
850
852 {
853 return CIterate( 0, OutlineCount() - 1, true );
854 }
855
857 {
858 // Build iterator
859 ITERATOR iter = IterateWithHoles();
860
861 // Get the relative indices of the globally indexed vertex
862 VERTEX_INDEX indices;
863
864 if( !GetRelativeIndices( aGlobalIdx, &indices ) )
865 throw( std::out_of_range( "aGlobalIndex-th vertex does not exist" ) );
866
867 // Adjust where the iterator is pointing
868 iter.m_currentPolygon = indices.m_polygon;
869 iter.m_currentContour = indices.m_contour;
870 iter.m_currentVertex = indices.m_vertex;
871
872 return iter;
873 }
874
877 SEGMENT_ITERATOR IterateSegments( int aFirst, int aLast, bool aIterateHoles = false )
878 {
879 SEGMENT_ITERATOR iter;
880
881 iter.m_poly = this;
882 iter.m_currentPolygon = aFirst;
883 iter.m_lastPolygon = aLast < 0 ? OutlineCount() - 1 : aLast;
884 iter.m_currentContour = 0;
885 iter.m_currentSegment = 0;
886 iter.m_iterateHoles = aIterateHoles;
887
888 return iter;
889 }
890
894 bool aIterateHoles = false ) const
895 {
897
898 iter.m_poly = const_cast<SHAPE_POLY_SET*>( this );
899 iter.m_currentPolygon = aFirst;
900 iter.m_lastPolygon = aLast < 0 ? OutlineCount() - 1 : aLast;
901 iter.m_currentContour = 0;
902 iter.m_currentSegment = 0;
903 iter.m_iterateHoles = aIterateHoles;
904
905 return iter;
906 }
907
910 {
911 return IterateSegments( aPolygonIdx, aPolygonIdx );
912 }
913
916 {
917 return CIterateSegments( aPolygonIdx, aPolygonIdx );
918 }
919
922 {
923 return IterateSegments( 0, OutlineCount() - 1 );
924 }
925
928 {
929 return CIterateSegments( 0, OutlineCount() - 1 );
930 }
931
934 {
935 return IterateSegments( 0, OutlineCount() - 1, true );
936 }
937
940 {
941 return IterateSegments( aOutline, aOutline, true );
942 }
943
946 {
947 return CIterateSegments( 0, OutlineCount() - 1, true );
948 }
949
952 {
953 return CIterateSegments( aOutline, aOutline, true );
954 }
955
965 {
966 PM_FAST = true,
967 PM_STRICTLY_SIMPLE = false
968 };
969
972 void BooleanAdd( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode );
973
976 void BooleanSubtract( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode );
977
980 void BooleanIntersection( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode );
981
984 void BooleanXor( const SHAPE_POLY_SET& b, POLYGON_MODE aFastMode );
985
988 void BooleanAdd( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
989 POLYGON_MODE aFastMode );
990
993 void BooleanSubtract( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
994 POLYGON_MODE aFastMode );
995
998 void BooleanIntersection( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
999 POLYGON_MODE aFastMode );
1000
1003 void BooleanXor( const SHAPE_POLY_SET& a, const SHAPE_POLY_SET& b,
1004 POLYGON_MODE aFastMode );
1005
1011
1027 void Inflate( int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError,
1028 bool aSimplify = false );
1029
1030 void Deflate( int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError )
1031 {
1032 Inflate( -aAmount, aCornerStrategy, aMaxError );
1033 }
1034
1048 void OffsetLineChain( const SHAPE_LINE_CHAIN& aLine, int aAmount,
1049 CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify );
1050
1058 void InflateWithLinkedHoles( int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError,
1059 POLYGON_MODE aFastMode );
1060
1064 void Fracture( POLYGON_MODE aFastMode );
1065
1068 void Unfracture( POLYGON_MODE aFastMode );
1069
1071 bool HasHoles() const;
1072
1074 bool HasTouchingHoles() const;
1075
1076
1079 void Simplify( POLYGON_MODE aFastMode );
1080
1090
1092 const std::string Format( bool aCplusPlus = true ) const override;
1093
1095 bool Parse( std::stringstream& aStream ) override;
1096
1098 void Move( const VECTOR2I& aVector ) override;
1099
1107 void Mirror( bool aX = true, bool aY = false, const VECTOR2I& aRef = { 0, 0 } );
1108
1115 void Rotate( const EDA_ANGLE& aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override;
1116
1118 bool IsSolid() const override
1119 {
1120 return true;
1121 }
1122
1123 const BOX2I BBox( int aClearance = 0 ) const override;
1124
1131 bool PointOnEdge( const VECTOR2I& aP, int aAccuracy = 0 ) const;
1132
1145 bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr,
1146 VECTOR2I* aLocation = nullptr ) const override;
1147
1166 bool Collide( const VECTOR2I& aP, int aClearance = 0, int* aActual = nullptr,
1167 VECTOR2I* aLocation = nullptr ) const override;
1168
1187 bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr,
1188 VECTOR2I* aLocation = nullptr ) const override;
1189
1200 bool CollideVertex( const VECTOR2I& aPoint, VERTEX_INDEX* aClosestVertex = nullptr,
1201 int aClearance = 0 ) const;
1202
1213 bool CollideEdge( const VECTOR2I& aPoint, VERTEX_INDEX* aClosestVertex = nullptr,
1214 int aClearance = 0 ) const;
1215
1216 bool PointInside( const VECTOR2I& aPt, int aAccuracy = 0,
1217 bool aUseBBoxCache = false ) const override;
1218
1225 void BuildBBoxCaches() const;
1226
1227 const BOX2I BBoxFromCaches() const;
1228
1239 bool Contains( const VECTOR2I& aP, int aSubpolyIndex = -1, int aAccuracy = 0,
1240 bool aUseBBoxCaches = false ) const;
1241
1243 bool IsEmpty() const
1244 {
1245 return m_polys.empty();
1246 }
1247
1253 void RemoveVertex( int aGlobalIndex );
1254
1260 void RemoveVertex( VERTEX_INDEX aRelativeIndices );
1261
1263 void RemoveAllContours();
1264
1273 void RemoveContour( int aContourIdx, int aPolygonIdx = -1 );
1274
1280 int RemoveNullSegments();
1281
1288 void SetVertex( const VERTEX_INDEX& aIndex, const VECTOR2I& aPos );
1289
1298 void SetVertex( int aGlobalIndex, const VECTOR2I& aPos );
1299
1301 int TotalVertices() const;
1302
1304 void DeletePolygon( int aIdx );
1305
1308 void DeletePolygonAndTriangulationData( int aIdx, bool aUpdateHash = true );
1309
1311
1319 POLYGON ChamferPolygon( unsigned int aDistance, int aIndex );
1320
1329 POLYGON FilletPolygon( unsigned int aRadius, int aErrorMax, int aIndex );
1330
1337 SHAPE_POLY_SET Chamfer( int aDistance );
1338
1346 SHAPE_POLY_SET Fillet( int aRadius, int aErrorMax );
1347
1358 SEG::ecoord SquaredDistanceToPolygon( VECTOR2I aPoint, int aIndex,
1359 VECTOR2I* aNearest ) const;
1360
1373 SEG::ecoord SquaredDistanceToPolygon( const SEG& aSegment, int aIndex,
1374 VECTOR2I* aNearest) const;
1375
1386 SEG::ecoord SquaredDistance( const VECTOR2I& aPoint, bool aOutlineOnly,
1387 VECTOR2I* aNearest ) const;
1388
1389 SEG::ecoord SquaredDistance( const VECTOR2I& aPoint, bool aOutlineOnly = false ) const override
1390 {
1391 return SquaredDistance( aPoint, aOutlineOnly, nullptr );
1392 }
1393
1405 SEG::ecoord SquaredDistanceToSeg( const SEG& aSegment, VECTOR2I* aNearest = nullptr ) const;
1406
1413 bool IsVertexInHole( int aGlobalIdx );
1414
1423 static const SHAPE_POLY_SET BuildPolysetFromOrientedPaths( const std::vector<SHAPE_LINE_CHAIN>& aPaths, bool aReverseOrientation = false, bool aEvenOdd = false );
1424
1425 void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError,
1426 ERROR_LOC aErrorLoc ) const override
1427 {
1428 aBuffer.Append( *this );
1429 }
1430
1431private:
1433
1435
1436 void fractureSingle( POLYGON& paths );
1437 void unfractureSingle ( POLYGON& path );
1438 void importTree( ClipperLib::PolyTree* tree,
1439 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1440 const std::vector<SHAPE_ARC>& aArcBuffe );
1441 void importTree( Clipper2Lib::PolyTree64& tree,
1442 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1443 const std::vector<SHAPE_ARC>& aArcBuffe );
1444 void importPaths( Clipper2Lib::Paths64& paths,
1445 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1446 const std::vector<SHAPE_ARC>& aArcBuffe );
1447 void importPolyPath( const std::unique_ptr<Clipper2Lib::PolyPath64>& aPolyPath,
1448 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1449 const std::vector<SHAPE_ARC>& aArcBuffer );
1450
1451 void inflate1( int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy );
1452 void inflate2( int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy, bool aSimplify = false );
1453
1454 void inflateLine2( const SHAPE_LINE_CHAIN& aLine, int aAmount, int aCircleSegCount,
1455 CORNER_STRATEGY aCornerStrategy, bool aSimplify = false );
1456
1469 void booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aOtherShape,
1470 POLYGON_MODE aFastMode );
1471
1472 void booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aShape,
1473 const SHAPE_POLY_SET& aOtherShape, POLYGON_MODE aFastMode );
1474
1475 void booleanOp( Clipper2Lib::ClipType aType, const SHAPE_POLY_SET& aOtherShape );
1476
1477 void booleanOp( Clipper2Lib::ClipType aType, const SHAPE_POLY_SET& aShape,
1478 const SHAPE_POLY_SET& aOtherShape );
1479
1494 bool containsSingle( const VECTOR2I& aP, int aSubpolyIndex, int aAccuracy,
1495 bool aUseBBoxCaches = false ) const;
1496
1503 {
1505 FILLETED
1507
1521 POLYGON chamferFilletPolygon( CORNER_MODE aMode, unsigned int aDistance,
1522 int aIndex, int aErrorMax );
1523
1525 bool hasTouchingHoles( const POLYGON& aPoly ) const;
1526
1527 MD5_HASH checksum() const;
1528
1529private:
1530 std::vector<POLYGON> m_polys;
1531 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>> m_triangulatedPolys;
1532
1535};
1536
1537#endif // __SHAPE_POLY_SET_H
Definition: seg.h:42
VECTOR2I::extended_type ecoord
Definition: seg.h:44
static double DefaultAccuracyForPCB()
Definition: shape_arc.h:221
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Base class for iterating over all vertices in a given SHAPE_POLY_SET.
void Advance()
Advance the indices of the current vertex/outline/contour, checking whether the vertices in the holes...
Base class for iterating over all segments in a given SHAPE_POLY_SET.
bool IsAdjacent(SEGMENT_ITERATOR_TEMPLATE< T > aOther) const
void Advance()
Advance the indices of the current vertex/outline/contour, checking whether the vertices in the holes...
void AddVertex(const VECTOR2I &aP)
void GetTriangle(int index, VECTOR2I &a, VECTOR2I &b, VECTOR2I &c) const
const std::deque< TRI > & Triangles() const
void AddTriangle(int a, int b, int c)
TRIANGULATED_POLYGON & operator=(const TRIANGULATED_POLYGON &aOther)
void Move(const VECTOR2I &aVec)
Represent a set of closed polygons.
virtual bool HasIndexableSubshapes() const override
static const SHAPE_POLY_SET BuildPolysetFromOrientedPaths(const std::vector< SHAPE_LINE_CHAIN > &aPaths, bool aReverseOrientation=false, bool aEvenOdd=false)
Build a SHAPE_POLY_SET from a bunch of outlines in provided in random order.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
SHAPE_POLY_SET Chamfer(int aDistance)
Return a chamfered version of the polygon set.
bool CollideEdge(const VECTOR2I &aPoint, VERTEX_INDEX *aClosestVertex=nullptr, int aClearance=0) const
Check whether aPoint collides with any edge of any of the contours of the polygon.
virtual void GetIndexableSubshapes(std::vector< const SHAPE * > &aSubshapes) const override
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
ITERATOR_TEMPLATE< VECTOR2I > ITERATOR
void fractureSingle(POLYGON &paths)
bool HasHoles() const
Return true if the polygon set has any holes.
void InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError, POLYGON_MODE aFastMode)
Perform outline inflation/deflation, using round corners.
CONST_ITERATOR CIterateWithHoles() const
ITERATOR IterateWithHoles(int aOutline)
void BooleanXor(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset exclusive or For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
ITERATOR IterateWithHoles()
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
bool IsTriangulationUpToDate() const
void importPaths(Clipper2Lib::Paths64 &paths, const std::vector< CLIPPER_Z_VALUE > &aZValueBuffer, const std::vector< SHAPE_ARC > &aArcBuffe)
POLYGON_MODE
Operations on polygons use a aFastMode param if aFastMode is PM_FAST (true) the result can be a weak ...
void InsertVertex(int aGlobalIndex, const VECTOR2I &aNewVertex)
Adds a vertex in the globally indexed position aGlobalIndex.
CONST_ITERATOR CIterate() const
CORNER_MODE
Operation ChamferPolygon and FilletPolygon are computed under the private chamferFillet method; this ...
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
int VertexCount(int aOutline=-1, int aHole=-1) const
Return the number of vertices in a given outline/hole.
void DeletePolygon(int aIdx)
Delete aIdx-th polygon from the set.
double Area()
Return the area of this poly set.
void SetVertex(const VERTEX_INDEX &aIndex, const VECTOR2I &aPos)
Accessor function to set the position of a specific point.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
CONST_ITERATOR CIterate(int aFirst, int aLast, bool aIterateHoles=false) const
void CacheTriangulation(bool aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
ITERATOR Iterate(int aOutline)
bool Parse(std::stringstream &aStream) override
int TotalVertices() const
Return total number of vertices stored in the set.
CONST_ITERATOR CIterate(int aOutline) const
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
int FullPointCount() const
Return the number of points in the shape poly set.
void GetArcs(std::vector< SHAPE_ARC > &aArcBuffer) const
Appends all the arcs in this polyset to aArcBuffer.
bool IsVertexInHole(int aGlobalIdx)
Check whether the aGlobalIndex-th vertex belongs to a hole.
int NormalizeAreaOutlines()
Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s).
void RemoveVertex(int aGlobalIndex)
Delete the aGlobalIndex-th vertex.
void unfractureSingle(POLYGON &path)
void inflateLine2(const SHAPE_LINE_CHAIN &aLine, int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy, bool aSimplify=false)
SEGMENT_ITERATOR IterateSegments(int aPolygonIdx)
Return an iterator object, for iterating aPolygonIdx-th polygon edges.
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
SEGMENT_ITERATOR IterateSegmentsWithHoles(int aOutline)
Return an iterator object, for the aOutline-th outline in the set (with holes).
bool GetRelativeIndices(int aGlobalIdx, VERTEX_INDEX *aRelativeIndices) const
Convert a global vertex index —i.e., a number that globally identifies a vertex in a concatenated lis...
bool IsPolygonSelfIntersecting(int aPolygonIndex) const
Check whether the aPolygonIndex-th polygon in the set is self intersecting.
SHAPE_POLY_SET Subset(int aFirstPolygon, int aLastPolygon)
Return a subset of the polygons in this set, the ones between aFirstPolygon and aLastPolygon.
SHAPE_POLY_SET UnitSet(int aPolygonIndex)
void inflate1(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy)
MD5_HASH GetHash() const
const POLYGON & Polygon(int aIndex) const
int RemoveNullSegments()
Look for null segments; ie, segments whose ends are exactly the same and deletes them.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int AddPolygon(const POLYGON &apolygon)
Adds a polygon to the set.
const std::string Format(bool aCplusPlus=true) const override
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
std::vector< std::unique_ptr< TRIANGULATED_POLYGON > > m_triangulatedPolys
SEGMENT_ITERATOR IterateSegments()
Return an iterator object, for all outlines in the set (no holes).
void booleanOp(ClipperLib::ClipType aType, const SHAPE_POLY_SET &aOtherShape, POLYGON_MODE aFastMode)
This is the engine to execute all polygon boolean transforms (AND, OR, ... and polygon simplification...
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
ITERATOR Iterate()
const SHAPE_LINE_CHAIN & Outline(int aIndex) const
CONST_SEGMENT_ITERATOR CIterateSegments() const
Returns an iterator object, for all outlines in the set (no holes)
ITERATOR_TEMPLATE< const VECTOR2I > CONST_ITERATOR
void inflate2(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy, bool aSimplify=false)
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
SEG::ecoord SquaredDistance(const VECTOR2I &aPoint, bool aOutlineOnly, VECTOR2I *aNearest) const
Compute the minimum distance squared between aPoint and all the polygons in the set.
void RemoveContour(int aContourIdx, int aPolygonIdx=-1)
Delete the aContourIdx-th contour of the aPolygonIdx-th polygon in the set.
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
int ArcCount() const
Count the number of arc shapes present.
void Unfracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
bool GetGlobalIndex(VERTEX_INDEX aRelativeIndices, int &aGlobalIdx) const
Compute the global index of a vertex from the relative indices of polygon, contour and vertex.
bool GetNeighbourIndexes(int aGlobalIndex, int *aPrevious, int *aNext) const
Return the global indexes of the previous and the next corner of the aGlobalIndex-th corner of a cont...
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the reference to aHole-th hole in the aIndex-th outline.
bool IsSolid() const override
int NewOutline()
Creates a new empty polygon in the set and returns its index.
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
bool hasTouchingHoles(const POLYGON &aPoly) const
Return true if the polygon set has any holes that touch share a vertex.
CONST_SEGMENT_ITERATOR CIterateSegments(int aPolygonIdx) const
Return an iterator object, for iterating aPolygonIdx-th polygon edges.
SEG::ecoord SquaredDistance(const VECTOR2I &aPoint, bool aOutlineOnly=false) const override
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of some of the outlines or holes.
bool CollideVertex(const VECTOR2I &aPoint, VERTEX_INDEX *aClosestVertex=nullptr, int aClearance=0) const
Check whether aPoint collides with any vertex of any of the contours of the polygon.
void DeletePolygonAndTriangulationData(int aIdx, bool aUpdateHash=true)
Delete aIdx-th polygon and its triangulation data from the set.
unsigned int TriangulatedPolyCount() const
Return the number of triangulated polygons.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
void UpdateTriangulationDataHash()
int NewHole(int aOutline=-1)
Creates a new hole in a given outline.
SEG::ecoord SquaredDistanceToPolygon(VECTOR2I aPoint, int aIndex, VECTOR2I *aNearest) const
Compute the minimum distance between the aIndex-th polygon and aPoint.
CONST_SEGMENT_ITERATOR CIterateSegmentsWithHoles() const
Return an iterator object, for the aOutline-th outline in the set (with holes).
virtual size_t GetIndexableSubshapeCount() const override
SEGMENT_ITERATOR IterateSegments(int aFirst, int aLast, bool aIterateHoles=false)
Return an iterator object, for iterating between aFirst and aLast outline, with or without holes (def...
ITERATOR Iterate(int aFirst, int aLast, bool aIterateHoles=false)
Return an object to iterate through the points of the polygons between aFirst and aLast.
CONST_SEGMENT_ITERATOR CIterateSegments(int aFirst, int aLast, bool aIterateHoles=false) const
Return an iterator object, for iterating between aFirst and aLast outline, with or without holes (def...
ITERATOR IterateFromVertexWithHoles(int aGlobalIdx)
SEG::ecoord SquaredDistanceToSeg(const SEG &aSegment, VECTOR2I *aNearest=nullptr) const
Compute the minimum distance squared between aSegment and all the polygons in the set.
MD5_HASH checksum() const
void importPolyPath(const std::unique_ptr< Clipper2Lib::PolyPath64 > &aPolyPath, const std::vector< CLIPPER_Z_VALUE > &aZValueBuffer, const std::vector< SHAPE_ARC > &aArcBuffer)
void RebuildHolesFromContours()
Extract all contours from this polygon set, then recreate polygons with holes.
void OffsetLineChain(const SHAPE_LINE_CHAIN &aLine, int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify)
Perform offsetting of a line chain.
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
std::vector< POLYGON > m_polys
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
POLYGON FilletPolygon(unsigned int aRadius, int aErrorMax, int aIndex)
Return a filleted version of the aIndex-th polygon.
bool containsSingle(const VECTOR2I &aP, int aSubpolyIndex, int aAccuracy, bool aUseBBoxCaches=false) const
Check whether the point aP is inside the aSubpolyIndex-th polygon of the polyset.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
int OutlineCount() const
Return the number of outlines in the set.
SEGMENT_ITERATOR_TEMPLATE< SEG > SEGMENT_ITERATOR
POLYGON chamferFilletPolygon(CORNER_MODE aMode, unsigned int aDistance, int aIndex, int aErrorMax)
Return the chamfered or filleted version of the aIndex-th polygon in the set, depending on the aMode ...
SHAPE_POLY_SET Fillet(int aRadius, int aErrorMax)
Return a filleted version of the polygon set.
void Move(const VECTOR2I &aVector) override
bool HasTouchingHoles() const
Return true if the polygon set has any holes that share a vertex.
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
SHAPE_POLY_SET & operator=(const SHAPE_POLY_SET &aOther)
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
SHAPE_POLY_SET CloneDropTriangulation() const
void importTree(ClipperLib::PolyTree *tree, const std::vector< CLIPPER_Z_VALUE > &aZValueBuffer, const std::vector< SHAPE_ARC > &aArcBuffe)
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aError, ERROR_LOC aErrorLoc) const override
Fills a SHAPE_POLY_SET with a polygon representation of this shape.
const POLYGON & CPolygon(int aIndex) const
CONST_ITERATOR CIterateWithHoles(int aOutline) const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
POLYGON ChamferPolygon(unsigned int aDistance, int aIndex)
Return a chamfered version of the aIndex-th polygon.
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
const std::vector< POLYGON > & CPolygons() const
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
const BOX2I BBoxFromCaches() const
CONST_SEGMENT_ITERATOR CIterateSegmentsWithHoles(int aOutline) const
Return an iterator object, for the aOutline-th outline in the set (with holes).
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
SEGMENT_ITERATOR_TEMPLATE< const SEG > CONST_SEGMENT_ITERATOR
bool IsSelfIntersecting() const
Check whether any of the polygons in the set is self intersecting.
An abstract shape on 2D plane.
Definition: shape.h:126
CORNER_STRATEGY
define how inflate transform build inflated polygon
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:426
@ SH_POLY_SET_TRIANGLE
a single triangle belonging to a POLY_SET triangulation
Definition: shape.h:56
std::vector< FAB_LAYER_COLOR > dummy
virtual bool IsClosed() const override
TRI(int _a=0, int _b=0, int _c=0, TRIANGULATED_POLYGON *aParent=nullptr)
virtual bool IsSolid() const override
virtual void Move(const VECTOR2I &aVector) override
virtual void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
virtual const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
virtual size_t GetPointCount() const override
virtual const VECTOR2I GetPoint(int aIndex) const override
virtual size_t GetSegmentCount() const override
virtual const SEG GetSegment(int aIndex) const override
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588