41#include <unordered_set>
45#include <clipper2/clipper.h>
46#include <math_for_graphics.h>
65#if defined( __MINGW32__ )
66 #define TRIANGULATESIMPLIFICATIONLEVEL 50
67 #define ENABLECACHEFRIENDLYFRACTURE true
69 #define TRIANGULATESIMPLIFICATIONLEVEL ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel
70 #define ENABLECACHEFRIENDLYFRACTURE ADVANCED_CFG::GetCfg().m_EnableCacheFriendlyFracture
107 m_polys( aOther.m_polys )
134 m_polys( aOther.m_polys )
163 unsigned int contourIdx = 0;
166 int currentGlobalIdx = 0;
168 for( polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
172 for( contourIdx = 0; contourIdx < currentPolygon.size(); contourIdx++ )
175 int totalPoints = currentContour.
PointCount();
177 for( vertexIdx = 0; vertexIdx < totalPoints; vertexIdx++ )
180 if( currentGlobalIdx == aGlobalIdx )
182 aRelativeIndices->
m_polygon = polygonIdx;
183 aRelativeIndices->
m_contour = contourIdx;
184 aRelativeIndices->
m_vertex = vertexIdx;
200 int& aGlobalIdx )
const
202 int selectedVertex = aRelativeIndices.
m_vertex;
203 unsigned int selectedContour = aRelativeIndices.
m_contour;
204 unsigned int selectedPolygon = aRelativeIndices.
m_polygon;
207 if( selectedPolygon <
m_polys.size() && selectedContour <
m_polys[selectedPolygon].size()
208 && selectedVertex <
m_polys[selectedPolygon][selectedContour].PointCount() )
214 for(
unsigned int polygonIdx = 0; polygonIdx < selectedPolygon; polygonIdx++ )
216 currentPolygon =
Polygon( polygonIdx );
218 for(
unsigned int contourIdx = 0; contourIdx < currentPolygon.size(); contourIdx++ )
219 aGlobalIdx += currentPolygon[contourIdx].PointCount();
222 currentPolygon =
Polygon( selectedPolygon );
224 for(
unsigned int contourIdx = 0; contourIdx < selectedContour; contourIdx++ )
225 aGlobalIdx += currentPolygon[contourIdx].PointCount();
227 aGlobalIdx += selectedVertex;
244 poly.push_back( empty_path );
261 m_polys[aOutline].push_back( empty_path );
263 return m_polys.back().size() - 2;
281 assert( aOutline < (
int)
m_polys.size() );
282 assert( idx < (
int)
m_polys[aOutline].size() );
284 m_polys[aOutline][idx].Append( x, y, aAllowDuplication );
286 return m_polys[aOutline][idx].PointCount();
304 assert( aOutline < (
int)
m_polys.size() );
305 assert( idx < (
int)
m_polys[aOutline].size() );
307 m_polys[aOutline][idx].Append( aArc, aAccuracy );
309 return m_polys[aOutline][idx].PointCount();
317 if( aGlobalIndex < 0 )
330 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
350 if( aOutline >= (
int)
m_polys.size() )
353 if( idx >= (
int)
m_polys[aOutline].size() )
356 return m_polys[aOutline][idx].PointCount();
371 for(
int idx = 0; idx <=
HoleCount( ii ); idx++ )
373 full_count +=
m_polys[ii][idx].PointCount();
383 assert( aFirstPolygon >= 0 && aLastPolygon <=
OutlineCount() );
387 for(
int index = aFirstPolygon; index < aLastPolygon; index++ )
406 assert( aOutline < (
int)
m_polys.size() );
407 assert( idx < (
int)
m_polys[aOutline].size() );
409 return m_polys[aOutline][idx].CPoint( aIndex );
419 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
449 else if( index.
m_vertex == lastpoint )
467 *aPrevious = previous;
483 std::vector<SEG> segments;
487 segments.emplace_back( *it );
489 std::sort( segments.begin(), segments.end(), [](
const SEG& a,
const SEG& b )
491 int min_a_x = std::min( a.A.x, a.B.x );
492 int min_b_x = std::min( b.A.x, b.B.x );
494 return min_a_x < min_b_x || ( min_a_x == min_b_x && std::min( a.A.y, a.B.y ) < std::min( b.A.y, b.B.y ) );
497 for(
auto it = segments.begin(); it != segments.end(); ++it )
499 SEG& firstSegment = *it;
502 auto innerIterator = it;
503 int max_x = std::max( firstSegment.
A.
x, firstSegment.
B.
x );
504 int max_y = std::max( firstSegment.
A.
y, firstSegment.
B.
y );
507 for( innerIterator++; innerIterator != segments.end(); innerIterator++ )
509 SEG& secondSegment = *innerIterator;
510 int min_x = std::min( secondSegment.
A.
x, secondSegment.
B.
x );
511 int min_y = std::min( secondSegment.
A.
y, secondSegment.
B.
y );
515 if( max_x < min_x || ( max_x == min_x && max_y < min_y ) )
519 bool adjacent = ( index_diff == 1) || (index_diff == ((
int)segments.size() - 1) );
522 if( !adjacent && firstSegment.
Collide( secondSegment, 0 ) )
533 for(
unsigned int polygon = 0; polygon <
m_polys.size(); polygon++ )
547 poly.push_back( aOutline );
552 wxCHECK2_MSG( aOutline.
IsClosed(), poly.back().SetClosed(
true ),
553 "Warning: non-closed outline added to SHAPE_POLY_SET" );
568 assert( aOutline < (
int)
m_polys.size() );
572 assert( poly.size() );
574 poly.push_back( aHole );
576 return poly.size() - 2;
596 for(
int j = 0; j <
HoleCount( i ); j++ )
610 for(
size_t i = 0; i < poly.size(); i++ )
622 for(
size_t i = 0; i < poly.size(); i++ )
625 aArcBuffer.push_back( arc );
635 for(
size_t i = 0; i < poly.size(); i++ )
643 std::vector<SHAPE_LINE_CHAIN> contours;
646 contours.insert( contours.end(), poly.begin(), poly.end() );
648 std::map<int, std::set<int>> parentToChildren;
649 std::map<int, std::set<int>> childToParents;
652 contour.GenerateBBoxCache();
654 for(
size_t i = 0; i < contours.size(); i++ )
658 for(
size_t j = 0; j < contours.size(); j++ )
668 parentToChildren[i].emplace( j );
669 childToParents[j].emplace( i );
674 std::set<int> topLevelParents;
676 for(
size_t i = 0; i < contours.size(); i++ )
678 if( childToParents[i].size() == 0 )
680 topLevelParents.emplace( i );
686 std::function<void(
int,
int, std::vector<int> )>
process;
689 [&](
int myId,
int parentOutlineId,
const std::vector<int>&
path )
691 std::set<int> relParents = childToParents[myId];
693 for(
int pathId :
path )
695 int erased = relParents.erase( pathId );
696 wxASSERT( erased > 0 );
699 wxASSERT( relParents.size() == 0 );
703 bool isOutline =
path.size() % 2 == 0;
707 int outlineId = result.
AddOutline( contours[myId] );
708 myOutline = outlineId;
712 wxASSERT( parentOutlineId != -1 );
713 result.
AddHole( contours[myId], parentOutlineId );
716 auto it = parentToChildren.find( myId );
717 if( it != parentToChildren.end() )
719 std::vector<int> thisPath =
path;
720 thisPath.emplace_back( myId );
722 std::set<int> thisPathSet;
723 thisPathSet.insert( thisPath.begin(), thisPath.end() );
725 for(
int childId : it->second )
727 const std::set<int>& childPathSet = childToParents[childId];
729 if( thisPathSet != childPathSet )
732 process( childId, myOutline, thisPath );
737 for(
int topParentId : topLevelParents )
739 std::vector<int>
path;
759 wxFAIL_MSG( wxT(
"Boolean ops on curved polygons are not supported. You should call "
760 "ClearArcs() before carrying out the boolean operation." ) );
763 Clipper2Lib::Clipper64 c;
765 std::vector<CLIPPER_Z_VALUE> zValues;
766 std::vector<SHAPE_ARC> arcBuffer;
767 std::map<VECTOR2I, CLIPPER_Z_VALUE> newIntersectPoints;
769 Clipper2Lib::Paths64 paths;
770 Clipper2Lib::Paths64 clips;
774 for(
size_t i = 0; i < poly.size(); i++ )
776 paths.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
782 for(
size_t i = 0; i < poly.size(); i++ )
784 clips.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
788 c.AddSubject( paths );
791 Clipper2Lib::PolyTree64 solution;
793 Clipper2Lib::ZCallback64 callback =
794 [&](
const Clipper2Lib::Point64 & e1bot,
const Clipper2Lib::Point64 & e1top,
795 const Clipper2Lib::Point64 & e2bot,
const Clipper2Lib::Point64 & e2top,
796 Clipper2Lib::Point64 & pt )
799 [&](
const ssize_t& aZvalue,
const ssize_t& aCompareVal = -1 ) -> ssize_t
803 retval = zValues.at( aZvalue ).m_SecondArcIdx;
805 if( retval == -1 || ( aCompareVal > 0 && retval != aCompareVal ) )
806 retval = zValues.at( aZvalue ).m_FirstArcIdx;
812 [&](
const ssize_t& aBottomZ,
const ssize_t aTopZ ) -> ssize_t
814 ssize_t retval = arcIndex( aBottomZ );
818 if( retval != arcIndex( aTopZ, retval ) )
825 ssize_t e1ArcSegmentIndex = arcSegment( e1bot.z, e1top.z );
826 ssize_t e2ArcSegmentIndex = arcSegment( e2bot.z, e2top.z );
830 if( e1ArcSegmentIndex != -1 )
841 size_t z_value_ptr = zValues.size();
842 zValues.push_back( newZval );
846 newIntersectPoints.insert( {
VECTOR2I( pt.x, pt.y ), newZval } );
852 c.SetZCallback( std::move( callback ) );
854 c.Execute( aType, Clipper2Lib::FillRule::NonZero, solution );
863 booleanOp( Clipper2Lib::ClipType::Union, b );
869 booleanOp( Clipper2Lib::ClipType::Difference, b );
875 booleanOp( Clipper2Lib::ClipType::Intersection, b );
881 booleanOp( Clipper2Lib::ClipType::Xor, b );
887 booleanOp( Clipper2Lib::ClipType::Union, a, b );
893 booleanOp( Clipper2Lib::ClipType::Difference, a, b );
899 booleanOp( Clipper2Lib::ClipType::Intersection, a, b );
905 booleanOp( Clipper2Lib::ClipType::Xor, a, b );
913 Inflate( aFactor, aCornerStrategy, aMaxError );
921 using namespace Clipper2Lib;
925 #define SEG_CNT_MAX 64
926 static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
933 JoinType joinType = JoinType::Round;
934 double miterLimit = 2.0;
936 switch( aCornerStrategy )
938 case CORNER_STRATEGY::ALLOW_ACUTE_CORNERS:
939 joinType = JoinType::Miter;
943 case CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS:
944 joinType = JoinType::Miter;
947 case CORNER_STRATEGY::ROUND_ACUTE_CORNERS:
948 joinType = JoinType::Miter;
951 case CORNER_STRATEGY::CHAMFER_ALL_CORNERS:
952 joinType = JoinType::Square;
955 case CORNER_STRATEGY::ROUND_ALL_CORNERS:
956 joinType = JoinType::Round;
960 std::vector<CLIPPER_Z_VALUE> zValues;
961 std::vector<SHAPE_ARC> arcBuffer;
967 for(
size_t i = 0; i < poly.size(); i++ )
968 paths.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
970 c.AddPaths( paths, joinType, EndType::Polygon );
977 if( aCircleSegCount < 6 )
982 if( aCircleSegCount >
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
984 coeff = 1.0 - cos( M_PI / aCircleSegCount );
987 arc_tolerance_factor[aCircleSegCount] = coeff;
991 coeff = arc_tolerance_factor[aCircleSegCount];
994 c.ArcTolerance(
std::abs( aAmount ) * coeff );
995 c.MiterLimit( miterLimit );
1002 c.Execute( aAmount, paths );
1004 Clipper2Lib::SimplifyPaths( paths,
std::abs( aAmount ) * coeff,
true );
1007 c2.PreserveCollinear(
false );
1008 c2.ReverseSolution(
false );
1009 c2.AddSubject( paths );
1010 c2.Execute(ClipType::Union, FillRule::Positive, tree);
1014 c.Execute( aAmount, tree );
1025 using namespace Clipper2Lib;
1029 #define SEG_CNT_MAX 64
1030 static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
1037 JoinType joinType = JoinType::Round;
1038 double miterLimit = 2.0;
1040 switch( aCornerStrategy )
1042 case CORNER_STRATEGY::ALLOW_ACUTE_CORNERS:
1043 joinType = JoinType::Miter;
1047 case CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS:
1048 joinType = JoinType::Miter;
1051 case CORNER_STRATEGY::ROUND_ACUTE_CORNERS:
1052 joinType = JoinType::Miter;
1055 case CORNER_STRATEGY::CHAMFER_ALL_CORNERS:
1056 joinType = JoinType::Square;
1059 case CORNER_STRATEGY::ROUND_ALL_CORNERS:
1060 joinType = JoinType::Round;
1064 std::vector<CLIPPER_Z_VALUE> zValues;
1065 std::vector<SHAPE_ARC> arcBuffer;
1068 c.AddPath(
path, joinType, EndType::Butt );
1074 if( aCircleSegCount < 6 )
1075 aCircleSegCount = 6;
1079 if( aCircleSegCount >
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
1081 coeff = 1.0 - cos( M_PI / aCircleSegCount );
1084 arc_tolerance_factor[aCircleSegCount] = coeff;
1088 coeff = arc_tolerance_factor[aCircleSegCount];
1091 c.ArcTolerance(
std::abs( aAmount ) * coeff );
1092 c.MiterLimit( miterLimit );
1099 c.Execute( aAmount, paths2 );
1101 Clipper2Lib::SimplifyPaths( paths2,
std::abs( aAmount ) * coeff,
false );
1104 c2.PreserveCollinear(
false );
1105 c2.ReverseSolution(
false );
1106 c2.AddSubject( paths2 );
1107 c2.Execute( ClipType::Union, FillRule::Positive, tree );
1111 c.Execute( aAmount, tree );
1124 inflate2( aAmount, segCount, aCornerStrategy, aSimplify );
1133 inflateLine2( aLine, aAmount, segCount, aCornerStrategy, aSimplify );
1138 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1139 const std::vector<SHAPE_ARC>& aArcBuffer )
1141 if( !aPolyPath->IsHole() )
1144 paths.reserve( aPolyPath->Count() + 1 );
1145 paths.emplace_back( aPolyPath->Polygon(), aZValueBuffer, aArcBuffer );
1147 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& child : *aPolyPath )
1149 paths.emplace_back( child->Polygon(), aZValueBuffer, aArcBuffer );
1151 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& grandchild : *child )
1161 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1162 const std::vector<SHAPE_ARC>& aArcBuffer )
1166 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& n : tree )
1172 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1173 const std::vector<SHAPE_ARC>& aArcBuffer )
1178 for(
const Clipper2Lib::Path64& n : aPath )
1180 if( Clipper2Lib::Area( n ) > 0 )
1189 wxCHECK2_MSG( !
path.empty(),
continue, wxT(
"Cannot add a hole before an outline" ) );
1192 path.emplace_back( n, aZValueBuffer, aArcBuffer );
1229 int x = edge.
m_p1.
x;
1230 int y = edge.
m_p1.
y;
1231 int min_dist = std::numeric_limits<int>::max();
1250 x_intersect = std::max( e.
m_p1.
x, e.
m_p2.
x );
1258 int dist = ( x - x_intersect );
1260 if( dist >= 0 && dist < min_dist )
1263 x_nearest = x_intersect;
1276 edges[hole2outline_index] =
1279 edges[split_index] =
1284 e_nearest->
m_next = outline2hole_index;
1287 for( ; last->
m_next != edgeIndex; last = &edges[last->
m_next] )
1289 last->
m_next = hole2outline_index;
1299 bool outline =
true;
1301 if( paths.size() == 1 )
1304 size_t total_point_count = 0;
1308 total_point_count +=
path.PointCount();
1311 if( total_point_count > (
size_t) std::numeric_limits<FractureEdge::Index>::max() )
1313 wxLogWarning( wxT(
"Polygon has more points than int limit" ) );
1320 edges.reserve( total_point_count + paths.size() * 3 );
1326 int path_or_provoking_index;
1331 std::vector<PathInfo> sorted_paths;
1332 const int paths_count =
static_cast<int>( paths.size() );
1333 sorted_paths.reserve( paths_count );
1335 for(
int path_index = 0; path_index < paths_count; path_index++ )
1338 const std::vector<VECTOR2I>& points =
path.CPoints();
1339 const int point_count =
static_cast<int>( points.size() );
1340 int x_min = std::numeric_limits<int>::max();
1341 int y_min = std::numeric_limits<int>::max();
1344 for(
int point_index = 0; point_index < point_count; point_index++ )
1346 const VECTOR2I& point = points[point_index];
1347 if( point.
x < x_min )
1350 leftmost = point_index;
1352 if( point.
y < y_min )
1356 sorted_paths.emplace_back( PathInfo{ path_index, leftmost, x_min, y_min } );
1359 std::sort( sorted_paths.begin() + 1, sorted_paths.end(),
1360 [](
const PathInfo& a,
const PathInfo& b )
1363 return a.y_or_bridge < b.y_or_bridge;
1369 for( PathInfo& path_info : sorted_paths )
1372 const std::vector<VECTOR2I>& points =
path.CPoints();
1373 const size_t point_count = points.size();
1378 for(
size_t i = 0; i < point_count - 1; i++ )
1380 edges.emplace_back( points[i], points[i + 1], edge_index + 1 );
1385 edges.emplace_back( points[point_count - 1], points[0], provoking_edge );
1392 path_info.path_or_provoking_index = provoking_edge;
1393 path_info.y_or_bridge = edge_index;
1397 edges.resize( edge_index );
1403 for(
auto it = sorted_paths.begin() + 1; it != sorted_paths.end(); it++ )
1405 auto edge =
processHole( edges, it->path_or_provoking_index,
1406 it->path_or_provoking_index + it->leftmost, it->y_or_bridge );
1411 wxLogWarning( wxT(
"Broken polygon, dropping path" ) );
1459 int x = edge->
m_p1.
x;
1460 int y = edge->
m_p1.
y;
1461 int min_dist = std::numeric_limits<int>::max();
1468 if( !e->matches( y ) )
1473 if( e->m_p1.y == e->m_p2.y )
1475 x_intersect = std::max( e->m_p1.x, e->m_p2.x );
1479 x_intersect = e->m_p1.x
1480 +
rescale( e->m_p2.x - e->m_p1.x, y - e->m_p1.y, e->m_p2.y - e->m_p1.y );
1483 int dist = ( x - x_intersect );
1485 if( dist >= 0 && dist < min_dist && e->m_connected )
1488 x_nearest = x_intersect;
1504 edges.push_back( split_2 );
1505 edges.push_back( lead1 );
1506 edges.push_back( lead2 );
1511 e_nearest->
m_next = lead1;
1516 for( last = edge; last->
m_next != edge; last = last->
m_next )
1542 if( paths.size() == 1 )
1545 int num_unconnected = 0;
1549 const std::vector<VECTOR2I>& points =
path.CPoints();
1550 int pointCount = points.size();
1554 int x_min = std::numeric_limits<int>::max();
1556 for(
int i = 0; i < pointCount; i++ )
1558 if( points[i].x < x_min )
1559 x_min = points[i].x;
1564 points[i + 1 == pointCount ? 0 : i + 1] );
1575 if( i == pointCount - 1 )
1579 edges.push_back( fe );
1583 if( fe->
m_p1.
x == x_min )
1584 border_edges.push_back( fe );
1595 while( num_unconnected > 0 )
1597 int x_min = std::numeric_limits<int>::max();
1598 auto it = border_edges.begin();
1603 for( ; it != border_edges.end(); ++it )
1606 int xt = border_edge->
m_p1.
x;
1608 if( ( xt <= x_min ) && !border_edge->
m_connected )
1611 smallestX = border_edge;
1615 int num_processed =
processEdge( edges, smallestX );
1618 if( !num_processed )
1620 wxLogWarning( wxT(
"Broken polygon, dropping path" ) );
1628 num_unconnected -= num_processed;
1646 paths.push_back( std::move( newPath ) );
1669 assert( aPoly.size() == 1 );
1675 bool m_duplicate =
false;
1682 bool compareSegs(
const SEG& s1,
const SEG& s2 )
const
1684 return (s1.
A == s2.
B && s1.
B == s2.
A);
1689 return compareSegs( m_poly->
CSegment( m_index ),
1690 aOther.m_poly->CSegment( aOther.m_index ) );
1695 return !compareSegs( m_poly->
CSegment( m_index ),
1696 aOther.m_poly->CSegment( aOther.m_index ) );
1701 std::size_t operator()(
const EDGE& aEdge )
const
1703 const SEG& a = aEdge.m_poly->CSegment( aEdge.m_index );
1704 std::size_t seed = 0xa82de1c0;
1711 struct EDGE_LIST_ENTRY
1714 EDGE_LIST_ENTRY*
next;
1717 std::unordered_set<EDGE, EDGE::HASH> uniqueEdges;
1722 auto edgeList = std::make_unique<EDGE_LIST_ENTRY[]>( lc.
SegmentCount() );
1726 edgeList[i].index = i;
1727 edgeList[i].next = &edgeList[ (i != lc.
SegmentCount() - 1) ? i + 1 : 0 ];
1730 std::unordered_set<EDGE_LIST_ENTRY*> queue;
1735 uniqueEdges.insert( e );
1741 auto it = uniqueEdges.find( e );
1743 if( it != uniqueEdges.end() && it->m_index != i )
1745 int e1 = it->m_index;
1749 std::swap( e1, e2 );
1751 int e1_prev = e1 - 1;
1756 int e2_prev = e2 - 1;
1761 int e1_next = e1 + 1;
1766 int e2_next = e2 + 1;
1771 edgeList[e1_prev].next = &edgeList[ e2_next ];
1772 edgeList[e2_prev].next = &edgeList[ e1_next ];
1773 edgeList[i].next =
nullptr;
1774 edgeList[it->m_index].next =
nullptr;
1780 if( edgeList[i].
next )
1781 queue.insert( &edgeList[i] );
1784 auto edgeBuf = std::make_unique<EDGE_LIST_ENTRY* []>( lc.
SegmentCount() );
1790 double max_poly = 0.0;
1792 while( queue.size() )
1794 EDGE_LIST_ENTRY* e_first = *queue.begin();
1795 EDGE_LIST_ENTRY* e = e_first;
1802 }
while( e && e != e_first );
1806 for(
int i = 0; i < cnt; i++ )
1810 queue.erase( edgeBuf[i] );
1815 double area = std::fabs( outl.
Area() );
1817 if( area > max_poly )
1823 result.push_back( outl );
1828 std::swap( result[0], result[outline] );
1840 if( paths.size() > 1 )
1872 path.Simplify( aMaxError );
1890 while( outline.size() > 1 )
1915 std::stringstream ss;
1917 ss <<
"SHAPE_LINE_CHAIN poly; \n";
1919 for(
unsigned i = 0; i <
m_polys.size(); i++ )
1921 for(
unsigned j = 0; j <
m_polys[i].size(); j++ )
1924 ss <<
"{ auto tmp = " <<
m_polys[i][j].Format() <<
";\n";
1930 ss <<
" poly.AddOutline(tmp); } \n";
1934 ss <<
" poly.AddHole(tmp); } \n";
1950 if( tmp !=
"polyset" )
1955 int n_polys = atoi( tmp.c_str() );
1960 for(
int i = 0; i < n_polys; i++ )
1970 int n_outlines = atoi( tmp.c_str() );
1972 if( n_outlines < 0 )
1975 for(
int j = 0; j < n_outlines; j++ )
1982 int n_vertices = atoi( tmp.c_str() );
1984 for(
int v = 0; v < n_vertices; v++ )
1988 aStream >> tmp; p.
x = atoi( tmp.c_str() );
1989 aStream >> tmp; p.
y = atoi( tmp.c_str() );
1993 paths.push_back( outline );
2007 for(
unsigned i = 0; i <
m_polys.size(); i++ )
2024 for(
unsigned i = 0; i <
m_polys.size(); i++ )
2027 bb = *
m_polys[i][0].GetCachedBBox();
2044 if( lineChain.PointOnEdge( aP, aAccuracy ) )
2059 if( dist_sq == 0 || dist_sq <
SEG::Square( aClearance ) )
2062 *aLocation = nearest;
2065 *aActual = sqrt( dist_sq );
2083 if( dist_sq == 0 || dist_sq <
SEG::Square( aClearance ) )
2086 *aLocation = nearest;
2089 *aActual = sqrt( dist_sq );
2106 int extra = segment->
GetWidth() / 2;
2108 if(
Collide( segment->
GetSeg(), aClearance + extra, aActual, aLocation ) )
2111 *aActual = std::max( 0, *aActual - extra );
2127 *aActual = std::max( 0, *aActual - extra );
2144 if( aActual || aLocation )
2149 if( aShape->
Collide( &tri, aClearance, &triActual, &triLocation ) )
2160 if( aShape->
Collide( &tri, aClearance ) )
2169 *aActual = std::max( 0,
actual );
2190 if( aPolygonIdx < 0 )
2191 aPolygonIdx +=
m_polys.size();
2193 m_polys[aPolygonIdx].erase(
m_polys[aPolygonIdx].begin() + aContourIdx );
2213 std::vector<VERTEX_INDEX> indices_to_remove;
2218 segmentStart = *iterator;
2224 segmentEnd = contourStart;
2232 contourStart = *iterator;
2240 wxCHECK_MSG( iterator, removed, wxT(
"Invalid polygon. Reached end without noticing. Please report this error" ) );
2242 segmentEnd = *iterator;
2246 if( segmentStart == segmentEnd )
2248 indices_to_remove.push_back( indexStart );
2255 for(
auto it = indices_to_remove.rbegin(); it != indices_to_remove.rend(); ++it )
2278 if( triangleSet->GetSourceOutlineIndex() == aIdx )
2280 else if( triangleSet->GetSourceOutlineIndex() > aIdx )
2281 triangleSet->SetSourceOutlineIndex( triangleSet->GetSourceOutlineIndex() - 1 );
2308 Append( aP.
x, aP.
y, aOutline, aHole );
2314 int aClearance )
const
2317 bool collision =
false;
2327 delta = *iterator - aPoint;
2330 distance_squared =
delta.SquaredEuclideanNorm();
2333 if( distance_squared <= clearance_squared )
2335 if( !aClosestVertex )
2341 clearance_squared = distance_squared;
2344 *aClosestVertex = iterator.GetIndex();
2354 int aClearance )
const
2357 bool collision =
false;
2362 const SEG currentSegment = *iterator;
2366 if( distance_squared <= clearance_squared )
2368 if( !aClosestVertex )
2374 clearance_squared = distance_squared;
2377 *aClosestVertex = iterator.GetIndex();
2387 for(
int polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
2391 for(
int holeIdx = 0; holeIdx <
HoleCount( polygonIdx ); holeIdx++ )
2398 bool aUseBBoxCaches )
const
2404 if( aSubpolyIndex >= 0 )
2405 return containsSingle( aP, aSubpolyIndex, aAccuracy, aUseBBoxCaches );
2408 for(
int polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
2410 if(
containsSingle( aP, polygonIdx, aAccuracy, aUseBBoxCaches ) )
2426 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
2443 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
2454 bool aUseBBoxCaches )
const
2460 for(
int holeIdx = 0; holeIdx <
HoleCount( aSubpolyIndex ); holeIdx++ )
2482 path.Move( aVector );
2486 tri->Move( aVector );
2498 path.Mirror( aRef, aFlipDirection );
2511 path.Rotate( aAngle, aCenter );
2527 c +=
path.PointCount();
2564 SEG::ecoord minDistance = (*iterator).SquaredDistance( aPoint );
2566 for( iterator++; iterator && minDistance > 0; iterator++ )
2568 SEG::ecoord currentDistance = (*iterator).SquaredDistance( aPoint );
2570 if( currentDistance < minDistance )
2573 *aNearest = (*iterator).NearestPoint( aPoint );
2575 minDistance = currentDistance;
2591 *aNearest = ( aSegment.
A + aSegment.
B ) / 2;
2597 SEG::ecoord minDistance = (*iterator).SquaredDistance( aSegment );
2599 if( aNearest && minDistance == 0 )
2600 *aNearest = ( *iterator ).NearestPoint( aSegment );
2602 for( iterator++; iterator && minDistance > 0; iterator++ )
2606 if( currentDistance < minDistance )
2609 *aNearest = (*iterator).NearestPoint( aSegment );
2611 minDistance = currentDistance;
2616 return minDistance < 0 ? 0 : minDistance;
2623 wxASSERT_MSG( !aOutlineOnly, wxT(
"Warning: SHAPE_POLY_SET::SquaredDistance does not yet "
2624 "support aOutlineOnly==true" ) );
2631 for(
unsigned int polygonIdx = 0; polygonIdx <
m_polys.size(); polygonIdx++ )
2634 aNearest ? &nearest :
nullptr );
2636 if( currentDistance_sq < minDistance_sq )
2639 *aNearest = nearest;
2641 minDistance_sq = currentDistance_sq;
2645 return minDistance_sq;
2656 for(
unsigned int polygonIdx = 0; polygonIdx <
m_polys.size(); polygonIdx++ )
2659 aNearest ? &nearest :
nullptr );
2661 if( currentDistance_sq < minDistance_sq )
2664 *aNearest = nearest;
2666 minDistance_sq = currentDistance_sq;
2670 return minDistance_sq;
2691 for(
unsigned int idx = 0; idx <
m_polys.size(); idx++ )
2702 for(
size_t idx = 0; idx <
m_polys.size(); idx++ )
2711 SHAPE::operator=( aOther );
2771 if( w == 0.0 || h == 0.0 )
2774 int n_cells_x, n_cells_y;
2778 n_cells_x = w / aSize;
2779 n_cells_y = floor( h / w * n_cells_x ) + 1;
2783 n_cells_y = h / aSize;
2784 n_cells_x = floor( w / h * n_cells_y ) + 1;
2787 SHAPE_POLY_SET ps1( aPoly ), ps2( aPoly ), maskSetOdd, maskSetEven;
2789 for(
int yy = 0; yy < n_cells_y; yy++ )
2791 for(
int xx = 0; xx < n_cells_x; xx++ )
2795 p.
x = bb.
GetX() + w * xx / n_cells_x;
2796 p.
y = bb.
GetY() + h * yy / n_cells_y;
2800 p2.
x = bb.
GetX() + w * ( xx + 1 ) / n_cells_x;
2801 p2.
y = bb.
GetY() + h * ( yy + 1 ) / n_cells_y;
2809 mask.SetClosed(
true );
2811 if( ( xx ^ yy ) & 1 )
2818 ps1.BooleanIntersection( maskSetOdd );
2819 ps2.BooleanIntersection( maskSetEven );
2823 for(
int i = 0; i < ps2.OutlineCount(); i++ )
2824 ps1.AddOutline( ps2.COutline( i ) );
2826 if( ps1.OutlineCount() )
2834 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>* aHintData )
2850 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>& dest,
2851 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>* hintData )
2853 bool triangulationValid =
false;
2857 if( hintData && hintData->size() != (unsigned) polySet.
OutlineCount() )
2862 if( !dest.empty() && dest.back()->GetTriangleCount() == 0 )
2863 dest.erase( dest.end() - 1 );
2865 dest.push_back( std::make_unique<TRIANGULATED_POLYGON>( forOutline ) );
2872 hintData ? hintData->at( index ).get() :
nullptr ) )
2886 triangulationValid =
false;
2893 triangulationValid =
true;
2896 return triangulationValid;
2908 for(
int jj = 0; jj <
HoleCount( ii ); ++jj )
2915 else if( aSimplify )
2924 wxLogTrace(
TRIANGULATE_TRACE,
"Failed to triangulate partitioned polygon %d", ii );
2965 hash.
add( outline.size() );
2969 hash.
add( lc.PointCount() );
2971 for(
int i = 0; i < lc.PointCount(); i++ )
2999 std::set<long long> ptHashes;
3003 for(
const VECTOR2I& pt : lc.CPoints() )
3005 const long long ptHash = (
long long) pt.x << 32 | pt.y;
3007 if( ptHashes.count( ptHash ) > 0 )
3010 ptHashes.insert( ptHash );
3029 n += t->GetTriangleCount();
3042 aSubshapes.push_back( &tri );
3053 if( aClearance != 0 )
3105 Clipper2Lib::Clipper64 clipper;
3106 Clipper2Lib::PolyTree64 tree;
3107 Clipper2Lib::Paths64 paths;
3111 Clipper2Lib::Path64 lc;
3112 lc.reserve(
path.PointCount() );
3114 for(
int i = 0; i <
path.PointCount(); i++ )
3115 lc.emplace_back(
path.CPoint( i ).x,
path.CPoint( i ).y );
3117 paths.push_back( lc );
3120 clipper.AddSubject( paths );
3121 clipper.Execute( Clipper2Lib::ClipType::Union, aEvenOdd ? Clipper2Lib::FillRule::EvenOdd
3122 : Clipper2Lib::FillRule::NonZero, tree );
3125 std::vector<CLIPPER_Z_VALUE> zValues;
3126 std::vector<SHAPE_ARC> arcBuffer;
3146 int aSpacing,
int aLineLength )
const
3148 std::vector<SEG> hatchLines;
3158 if( iterator->x < min_x )
3159 min_x = iterator->x;
3161 if( iterator->x > max_x )
3162 max_x = iterator->x;
3164 if( iterator->y < min_y )
3165 min_y = iterator->y;
3167 if( iterator->y > max_y )
3168 max_y = iterator->y;
3171 auto sortEndsByDescendingX =
3174 return tst.x < ref.
x;
3177 for(
double slope : aSlopes )
3179 int64_t max_a, min_a;
3183 max_a = KiROUND<double, int64_t>( max_y - slope * min_x );
3184 min_a = KiROUND<double, int64_t>( min_y - slope * max_x );
3188 max_a = KiROUND<double, int64_t>( max_y - slope * max_x );
3189 min_a = KiROUND<double, int64_t>( min_y - slope * min_x );
3192 min_a = ( min_a / aSpacing ) * aSpacing;
3195 std::vector<VECTOR2I> pointbuffer;
3196 pointbuffer.reserve( 256 );
3198 for( int64_t a = min_a; a < max_a; a += aSpacing )
3200 pointbuffer.clear();
3205 const SEG seg = *iterator;
3208 if( FindLineSegmentIntersection( a, slope, seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y, x, y ) )
3215 if( pointbuffer.size() > 2 )
3216 sort( pointbuffer.begin(), pointbuffer.end(), sortEndsByDescendingX );
3219 for(
size_t ip = 0; ip + 1 < pointbuffer.size(); ip += 2 )
3221 int dx = pointbuffer[ip + 1].x - pointbuffer[ip].x;
3225 if( aLineLength == -1 ||
std::abs( dx ) < 2 * aLineLength )
3227 hatchLines.emplace_back(
SEG( pointbuffer[ip], pointbuffer[ ip + 1] ) );
3231 double dy = pointbuffer[ip + 1].y - pointbuffer[ip].y;
3239 int x1 =
KiROUND( pointbuffer[ip].x + dx );
3240 int x2 =
KiROUND( pointbuffer[ip + 1].x - dx );
3241 int y1 =
KiROUND( pointbuffer[ip].y + dx * slope );
3242 int y2 =
KiROUND( pointbuffer[ip + 1].y - dx * slope );
3244 hatchLines.emplace_back(
SEG( pointbuffer[ip].x, pointbuffer[ip].y, x1, y1 ) );
3246 hatchLines.emplace_back(
SEG( pointbuffer[ip+1].x, pointbuffer[ip+1].y, x2,
bool operator==(const wxAuiPaneInfo &aLhs, const wxAuiPaneInfo &aRhs)
bool operator!=(const BOM_FIELD &lhs, const BOM_FIELD &rhs)
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr coord_type GetY() const
constexpr size_type GetWidth() const
constexpr coord_type GetX() const
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr size_type GetHeight() const
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
A streaming C++ equivalent for MurmurHash3_x64_128.
FORCE_INLINE void add(const std::string &input)
FORCE_INLINE HASH_128 digest()
bool TesselatePolygon(const SHAPE_LINE_CHAIN &aPoly, SHAPE_POLY_SET::TRIANGULATED_POLYGON *aHintData)
ecoord SquaredDistance(const SEG &aSeg) const
VECTOR2I::extended_type ecoord
int Index() const
Return the index of this segment in its parent shape (applicable only to non-local segments).
static SEG::ecoord Square(int a)
bool Collide(const SEG &aSeg, int aClearance, int *aActual=nullptr) const
SHAPE_TYPE Type() const
Return the type of the shape.
const VECTOR2I GetCenter() const
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
bool IsClosed() const override
void GenerateBBoxCache() const
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Simplify(int aMaxError=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Clear()
Remove all points from the line chain.
double Area(bool aAbsolute=true) const
Return the area of this chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
Clipper2Lib::Path64 convertToClipper2(bool aRequiredOrientation, std::vector< CLIPPER_Z_VALUE > &aZValueBuffer, std::vector< SHAPE_ARC > &aArcBuffer) const
Create a new Clipper2 path from the SHAPE_LINE_CHAIN in a given orientation.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
Base class for iterating over all vertices in a given SHAPE_POLY_SET.
bool IsEndContour() const
Base class for iterating over all segments in a given SHAPE_POLY_SET.
TRIANGULATED_POLYGON(int aSourceOutline)
std::deque< TRI > m_triangles
std::deque< VECTOR2I > m_vertices
void AddTriangle(int a, int b, int c)
TRIANGULATED_POLYGON & operator=(const TRIANGULATED_POLYGON &aOther)
Represent a set of closed polygons.
std::mutex m_triangulationMutex
virtual bool HasIndexableSubshapes() const override
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.
void RemoveOutline(int aOutlineIdx)
Delete the aOutlineIdx-th outline of the set including its contours and holes.
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 BooleanXor(const SHAPE_POLY_SET &b)
Perform boolean polyset exclusive or.
void fractureSingle(POLYGON &paths)
bool HasHoles() const
Return true if the polygon set has any holes.
CONST_ITERATOR CIterateWithHoles() const
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
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)
void InsertVertex(int aGlobalIndex, const VECTOR2I &aNewVertex)
Adds a vertex in the globally indexed position aGlobalIndex.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
virtual void CacheTriangulation(bool aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
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 Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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,...
void BuildPolysetFromOrientedPaths(const std::vector< SHAPE_LINE_CHAIN > &aPaths, bool aEvenOdd=false)
Build a SHAPE_POLY_SET from a bunch of outlines in provided in random order.
bool Parse(std::stringstream &aStream) override
int TotalVertices() const
Return total number of vertices stored in the set.
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)
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.
int RemoveNullSegments()
Look for null segments; ie, segments whose ends are exactly the same and deletes them.
HASH_128 checksum() const
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::vector< SEG > GenerateHatchLines(const std::vector< double > &aSlopes, int aSpacing, int aLineLength) const
const std::string Format(bool aCplusPlus=true) const override
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
std::vector< std::unique_ptr< TRIANGULATED_POLYGON > > m_triangulatedPolys
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 Unfracture()
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int ArcCount() const
Count the number of arc shapes present.
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.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void SimplifyOutlines(int aMaxError=0)
Simplifies the lines in the polyset.
void booleanOp(Clipper2Lib::ClipType aType, const SHAPE_POLY_SET &aOtherShape)
This is the engine to execute all polygon boolean transforms (AND, OR, ... and polygon simplification...
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.
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.
std::atomic< bool > m_triangulationValid
void UpdateTriangulationDataHash()
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
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).
void cacheTriangulation(bool aPartition, bool aSimplify, std::vector< std::unique_ptr< TRIANGULATED_POLYGON > > *aHintData)
virtual size_t GetIndexableSubshapeCount() const override
SEG::ecoord SquaredDistanceToSeg(const SEG &aSegment, VECTOR2I *aNearest=nullptr) const
Compute the minimum distance squared between aSegment and all the polygons in the set.
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 Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
Mirror the line points about y or x (or both)
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.
void InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError)
Perform outline inflation/deflation, using round corners.
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 BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const POLYGON & CPolygon(int aIndex) 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 BOX2I BBoxFromCaches() const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
void importTree(Clipper2Lib::PolyTree64 &tree, const std::vector< CLIPPER_Z_VALUE > &aZValueBuffer, const std::vector< SHAPE_ARC > &aArcBuffe)
bool IsSelfIntersecting() const
Check whether any of the polygons in the set is self intersecting.
const SEG & GetSeg() const
An abstract shape on 2D plane.
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
VECTOR2I::extended_type ecoord
constexpr extended_type SquaredDistance(const VECTOR2< T > &aVector) const
Compute the squared distance between two vectors.
static constexpr extended_type ECOORD_MAX
CORNER_STRATEGY
define how inflate transform build inflated polygon
static bool empty(const wxTextEntryBase *aCtrl)
static constexpr EDA_ANGLE FULL_CIRCLE
a few functions useful in geometry calculations.
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
static PGM_BASE * process
#define TRIANGULATE_TRACE
#define TRIANGULATESIMPLIFICATIONLEVEL
@ SH_POLY_SET
set of polygons (with holes, etc.)
static void fractureSingleCacheFriendly(SHAPE_POLY_SET::POLYGON &paths)
static void fractureSingleSlow(SHAPE_POLY_SET::POLYGON &paths)
static FractureEdge * processHole(FractureEdgeSet &edges, FractureEdge::Index provokingIndex, FractureEdge::Index edgeIndex, FractureEdge::Index bridgeIndex)
std::vector< FractureEdge > FractureEdgeSet
std::vector< FractureEdgeSlow * > FractureEdgeSetSlow
static SHAPE_POLY_SET partitionPolyIntoRegularCellGrid(const SHAPE_POLY_SET &aPoly, int aSize)
#define ENABLECACHEFRIENDLYFRACTURE
static int processEdge(FractureEdgeSetSlow &edges, FractureEdgeSlow *edge)
Holds information on each point of a SHAPE_LINE_CHAIN that is retrievable after an operation with Cli...
FractureEdgeSlow(int y=0)
FractureEdgeSlow * m_next
bool matches(int y) const
FractureEdgeSlow(bool connected, const VECTOR2I &p1, const VECTOR2I &p2)
FractureEdge(const VECTOR2I &p1, const VECTOR2I &p2, Index next)
bool matches(int y) const
A storage class for 128-bit hash value.
virtual const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
TRIANGULATED_POLYGON * parent
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
VECTOR2< int32_t > VECTOR2I