42#include <unordered_set>
46#include <clipper2/clipper.h>
101 m_polys( aOther.m_polys )
127 m_polys( aOther.m_polys )
156 unsigned int contourIdx = 0;
159 int currentGlobalIdx = 0;
161 for( polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
165 for( contourIdx = 0; contourIdx < currentPolygon.size(); contourIdx++ )
168 int totalPoints = currentContour.
PointCount();
170 for( vertexIdx = 0; vertexIdx < totalPoints; vertexIdx++ )
173 if( currentGlobalIdx == aGlobalIdx )
175 aRelativeIndices->
m_polygon = polygonIdx;
176 aRelativeIndices->
m_contour = contourIdx;
177 aRelativeIndices->
m_vertex = vertexIdx;
193 int& aGlobalIdx )
const
195 int selectedVertex = aRelativeIndices.
m_vertex;
196 unsigned int selectedContour = aRelativeIndices.
m_contour;
197 unsigned int selectedPolygon = aRelativeIndices.
m_polygon;
200 if( selectedPolygon <
m_polys.size() && selectedContour <
m_polys[selectedPolygon].size()
201 && selectedVertex <
m_polys[selectedPolygon][selectedContour].PointCount() )
207 for(
unsigned int polygonIdx = 0; polygonIdx < selectedPolygon; polygonIdx++ )
209 currentPolygon =
Polygon( polygonIdx );
211 for(
unsigned int contourIdx = 0; contourIdx < currentPolygon.size(); contourIdx++ )
212 aGlobalIdx += currentPolygon[contourIdx].PointCount();
215 currentPolygon =
Polygon( selectedPolygon );
217 for(
unsigned int contourIdx = 0; contourIdx < selectedContour; contourIdx++ )
218 aGlobalIdx += currentPolygon[contourIdx].PointCount();
220 aGlobalIdx += selectedVertex;
237 poly.push_back( empty_path );
254 m_polys[aOutline].push_back( empty_path );
256 return m_polys.back().size() - 2;
274 assert( aOutline < (
int)
m_polys.size() );
275 assert( idx < (
int)
m_polys[aOutline].size() );
277 m_polys[aOutline][idx].Append( x, y, aAllowDuplication );
279 return m_polys[aOutline][idx].PointCount();
297 assert( aOutline < (
int)
m_polys.size() );
298 assert( idx < (
int)
m_polys[aOutline].size() );
300 m_polys[aOutline][idx].Append( aArc, aAccuracy );
302 return m_polys[aOutline][idx].PointCount();
310 if( aGlobalIndex < 0 )
323 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
343 if( aOutline >= (
int)
m_polys.size() )
346 if( idx >= (
int)
m_polys[aOutline].size() )
349 return m_polys[aOutline][idx].PointCount();
364 for(
int idx = 0; idx <=
HoleCount( ii ); idx++ )
366 full_count +=
m_polys[ii][idx].PointCount();
376 assert( aFirstPolygon >= 0 && aLastPolygon <=
OutlineCount() );
380 for(
int index = aFirstPolygon; index < aLastPolygon; index++ )
399 assert( aOutline < (
int)
m_polys.size() );
400 assert( idx < (
int)
m_polys[aOutline].size() );
402 return m_polys[aOutline][idx].CPoint( aIndex );
412 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
442 else if( index.
m_vertex == lastpoint )
457 *aPrevious = previous;
473 std::vector<SEG> segments;
477 segments.emplace_back( *it );
479 std::sort( segments.begin(), segments.end(), [](
const SEG& a,
const SEG& b )
481 int min_a_x = std::min( a.A.x, a.B.x );
482 int min_b_x = std::min( b.A.x, b.B.x );
484 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 ) );
487 for(
auto it = segments.begin(); it != segments.end(); ++it )
489 SEG& firstSegment = *it;
492 auto innerIterator = it;
493 int max_x = std::max( firstSegment.
A.
x, firstSegment.
B.
x );
494 int max_y = std::max( firstSegment.
A.
y, firstSegment.
B.
y );
497 for( innerIterator++; innerIterator != segments.end(); innerIterator++ )
499 SEG& secondSegment = *innerIterator;
500 int min_x = std::min( secondSegment.
A.
x, secondSegment.
B.
x );
501 int min_y = std::min( secondSegment.
A.
y, secondSegment.
B.
y );
505 if( max_x < min_x || ( max_x == min_x && max_y < min_y ) )
509 bool adjacent = ( index_diff == 1) || (index_diff == ((
int)segments.size() - 1) );
512 if( !adjacent && firstSegment.
Collide( secondSegment, 0 ) )
523 for(
unsigned int polygon = 0; polygon <
m_polys.size(); polygon++ )
539 poly.push_back( aOutline );
554 assert( aOutline < (
int)
m_polys.size() );
558 assert( poly.size() );
560 poly.push_back( aHole );
562 return poly.size() - 2;
582 for(
int j = 0; j <
HoleCount( i ); j++ )
596 for(
size_t i = 0; i < poly.size(); i++ )
608 for(
size_t i = 0; i < poly.size(); i++ )
611 aArcBuffer.push_back( arc );
621 for(
size_t i = 0; i < poly.size(); i++ )
629 std::vector<SHAPE_LINE_CHAIN> contours;
632 contours.insert( contours.end(), poly.begin(), poly.end() );
634 std::map<int, std::set<int>> parentToChildren;
635 std::map<int, std::set<int>> childToParents;
638 contour.GenerateBBoxCache();
640 for(
size_t i = 0; i < contours.size(); i++ )
644 for(
size_t j = 0; j < contours.size(); j++ )
654 parentToChildren[i].emplace( j );
655 childToParents[j].emplace( i );
660 std::set<int> topLevelParents;
662 for(
size_t i = 0; i < contours.size(); i++ )
664 if( childToParents[i].size() == 0 )
666 topLevelParents.emplace( i );
672 std::function<void(
int,
int, std::vector<int> )>
process;
674 process = [&](
int myId,
int parentOutlineId, std::vector<int>
path )
676 std::set<int> relParents = childToParents[myId];
678 for(
int pathId :
path )
680 int erased = relParents.erase( pathId );
681 wxASSERT( erased > 0 );
684 wxASSERT( relParents.size() == 0 );
688 bool isOutline =
path.size() % 2 == 0;
692 int outlineId = result.
AddOutline( contours[myId] );
693 myOutline = outlineId;
697 wxASSERT( parentOutlineId != -1 );
698 int holeId = result.
AddHole( contours[myId], parentOutlineId );
701 auto it = parentToChildren.find( myId );
702 if( it != parentToChildren.end() )
704 std::vector<int> thisPath =
path;
705 thisPath.emplace_back( myId );
707 std::set<int> thisPathSet;
708 thisPathSet.insert( thisPath.begin(), thisPath.end() );
710 for(
int childId : it->second )
712 const std::set<int>& childPathSet = childToParents[childId];
714 if( thisPathSet != childPathSet )
717 process( childId, myOutline, thisPath );
722 for(
int topParentId : topLevelParents )
724 std::vector<int>
path;
735 booleanOp( aType, *
this, aOtherShape, aFastMode );
745 wxFAIL_MSG( wxT(
"Boolean ops on curved polygons are not supported. You should call "
746 "ClearArcs() before carrying out the boolean operation." ) );
749 ClipperLib::Clipper c;
753 std::vector<CLIPPER_Z_VALUE> zValues;
754 std::vector<SHAPE_ARC> arcBuffer;
755 std::map<VECTOR2I, CLIPPER_Z_VALUE> newIntersectPoints;
759 for(
size_t i = 0; i < poly.size(); i++ )
761 c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
762 ClipperLib::ptSubject,
true );
768 for(
size_t i = 0; i < poly.size(); i++ )
770 c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
771 ClipperLib::ptClip,
true );
775 ClipperLib::PolyTree solution;
777 ClipperLib::ZFillCallback callback =
778 [&]( ClipperLib::IntPoint & e1bot, ClipperLib::IntPoint & e1top,
779 ClipperLib::IntPoint & e2bot, ClipperLib::IntPoint & e2top,
780 ClipperLib::IntPoint & pt )
783 [&](
const ssize_t& aZvalue,
const ssize_t& aCompareVal = -1 ) -> ssize_t
787 retval = zValues.at( aZvalue ).m_SecondArcIdx;
789 if( retval == -1 || ( aCompareVal > 0 && retval != aCompareVal ) )
790 retval = zValues.at( aZvalue ).m_FirstArcIdx;
796 [&](
const ssize_t& aBottomZ,
const ssize_t aTopZ ) -> ssize_t
798 ssize_t retval = arcIndex( aBottomZ );
802 if( retval != arcIndex( aTopZ, retval ) )
809 ssize_t e1ArcSegmentIndex = arcSegment( e1bot.Z, e1top.Z );
810 ssize_t e2ArcSegmentIndex = arcSegment( e2bot.Z, e2top.Z );
814 if( e1ArcSegmentIndex != -1 )
825 size_t z_value_ptr = zValues.size();
826 zValues.push_back( newZval );
830 newIntersectPoints.insert( {
VECTOR2I( pt.X, pt.Y ), newZval } );
836 c.ZFillFunction( callback );
838 c.Execute( aType, solution, ClipperLib::pftNonZero, ClipperLib::pftNonZero );
856 wxFAIL_MSG( wxT(
"Boolean ops on curved polygons are not supported. You should call "
857 "ClearArcs() before carrying out the boolean operation." ) );
860 Clipper2Lib::Clipper64 c;
862 std::vector<CLIPPER_Z_VALUE> zValues;
863 std::vector<SHAPE_ARC> arcBuffer;
864 std::map<VECTOR2I, CLIPPER_Z_VALUE> newIntersectPoints;
866 Clipper2Lib::Paths64 paths;
867 Clipper2Lib::Paths64 clips;
871 for(
size_t i = 0; i < poly.size(); i++ )
873 paths.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
879 for(
size_t i = 0; i < poly.size(); i++ )
881 clips.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
885 c.AddSubject( paths );
888 Clipper2Lib::PolyTree64 solution;
890 Clipper2Lib::ZCallback64 callback =
891 [&](
const Clipper2Lib::Point64 & e1bot,
const Clipper2Lib::Point64 & e1top,
892 const Clipper2Lib::Point64 & e2bot,
const Clipper2Lib::Point64 & e2top,
893 Clipper2Lib::Point64 & pt )
896 [&](
const ssize_t& aZvalue,
const ssize_t& aCompareVal = -1 ) -> ssize_t
900 retval = zValues.at( aZvalue ).m_SecondArcIdx;
902 if( retval == -1 || ( aCompareVal > 0 && retval != aCompareVal ) )
903 retval = zValues.at( aZvalue ).m_FirstArcIdx;
909 [&](
const ssize_t& aBottomZ,
const ssize_t aTopZ ) -> ssize_t
911 ssize_t retval = arcIndex( aBottomZ );
915 if( retval != arcIndex( aTopZ, retval ) )
922 ssize_t e1ArcSegmentIndex = arcSegment( e1bot.z, e1top.z );
923 ssize_t e2ArcSegmentIndex = arcSegment( e2bot.z, e2top.z );
927 if( e1ArcSegmentIndex != -1 )
938 size_t z_value_ptr = zValues.size();
939 zValues.push_back( newZval );
943 newIntersectPoints.insert( {
VECTOR2I( pt.x, pt.y ), newZval } );
949 c.SetZCallback( callback );
951 c.Execute( aType, Clipper2Lib::FillRule::NonZero, solution );
961 booleanOp( Clipper2Lib::ClipType::Union, b );
963 booleanOp( ClipperLib::ctUnion, b, aFastMode );
970 booleanOp( Clipper2Lib::ClipType::Difference, b );
972 booleanOp( ClipperLib::ctDifference, b, aFastMode );
979 booleanOp( Clipper2Lib::ClipType::Intersection, b );
981 booleanOp( ClipperLib::ctIntersection, b, aFastMode );
988 booleanOp( Clipper2Lib::ClipType::Xor, b );
990 booleanOp( ClipperLib::ctXor, b, aFastMode );
998 booleanOp( Clipper2Lib::ClipType::Union, a, b );
1000 booleanOp( ClipperLib::ctUnion, a, b, aFastMode );
1008 booleanOp( Clipper2Lib::ClipType::Difference, a, b );
1010 booleanOp( ClipperLib::ctDifference, a, b, aFastMode );
1018 booleanOp( Clipper2Lib::ClipType::Intersection, a, b );
1020 booleanOp( ClipperLib::ctIntersection, a, b, aFastMode );
1028 booleanOp( Clipper2Lib::ClipType::Xor, a, b );
1030 booleanOp( ClipperLib::ctXor, a, b, aFastMode );
1039 Inflate( aFactor, aCornerStrategy, aMaxError );
1046 using namespace ClipperLib;
1050 #define SEG_CNT_MAX 64
1051 static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
1058 JoinType joinType = jtRound;
1059 double miterLimit = 2.0;
1060 JoinType miterFallback = jtSquare;
1062 switch( aCornerStrategy )
1067 miterFallback = jtSquare;
1072 miterFallback = jtRound;
1077 miterFallback = jtSquare;
1081 joinType = jtSquare;
1082 miterFallback = jtSquare;
1087 miterFallback = jtSquare;
1091 std::vector<CLIPPER_Z_VALUE> zValues;
1092 std::vector<SHAPE_ARC> arcBuffer;
1096 for(
size_t i = 0; i < poly.size(); i++ )
1098 c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
1099 joinType, etClosedPolygon );
1109 if( aCircleSegCount < 6 )
1110 aCircleSegCount = 6;
1114 if( aCircleSegCount >
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
1116 coeff = 1.0 - cos( M_PI / aCircleSegCount );
1119 arc_tolerance_factor[aCircleSegCount] = coeff;
1123 coeff = arc_tolerance_factor[aCircleSegCount];
1126 c.ArcTolerance =
std::abs( aAmount ) * coeff;
1127 c.MiterLimit = miterLimit;
1128 c.MiterFallback = miterFallback;
1129 c.Execute( solution, aAmount );
1138 using namespace Clipper2Lib;
1142 #define SEG_CNT_MAX 64
1143 static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
1150 JoinType joinType = JoinType::Round;
1151 double miterLimit = 2.0;
1153 switch( aCornerStrategy )
1156 joinType = JoinType::Miter;
1161 joinType = JoinType::Miter;
1165 joinType = JoinType::Miter;
1169 joinType = JoinType::Square;
1173 joinType = JoinType::Round;
1177 std::vector<CLIPPER_Z_VALUE> zValues;
1178 std::vector<SHAPE_ARC> arcBuffer;
1184 for(
size_t i = 0; i < poly.size(); i++ )
1185 paths.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
1187 c.AddPaths( paths, joinType, EndType::Polygon );
1194 if( aCircleSegCount < 6 )
1195 aCircleSegCount = 6;
1199 if( aCircleSegCount >
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
1201 coeff = 1.0 - cos( M_PI / aCircleSegCount );
1204 arc_tolerance_factor[aCircleSegCount] = coeff;
1208 coeff = arc_tolerance_factor[aCircleSegCount];
1211 c.ArcTolerance(
std::abs( aAmount ) * coeff );
1212 c.MiterLimit( miterLimit );
1219 c.Execute( aAmount, paths );
1221 Clipper2Lib::SimplifyPaths( paths,
std::abs( aAmount ) * coeff,
false );
1224 c2.PreserveCollinear =
false;
1225 c2.ReverseSolution =
false;
1226 c2.AddSubject( paths );
1227 c2.Execute(ClipType::Union, FillRule::Positive, tree);
1231 c.Execute( aAmount, tree );
1245 inflate2( aAmount, segCount, aCornerStrategy, aSimplify );
1247 inflate1( aAmount, segCount, aCornerStrategy );
1252 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1253 const std::vector<SHAPE_ARC>& aArcBuffer )
1257 for( ClipperLib::PolyNode* n = tree->GetFirst(); n; n = n->GetNext() )
1262 paths.reserve( n->Childs.size() + 1 );
1264 paths.emplace_back( n->Contour, aZValueBuffer, aArcBuffer );
1266 for(
unsigned int i = 0; i < n->Childs.size(); i++ )
1267 paths.emplace_back( n->Childs[i]->Contour, aZValueBuffer, aArcBuffer );
1276 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1277 const std::vector<SHAPE_ARC>& aArcBuffer )
1279 if( !aPolyPath->IsHole() )
1282 paths.reserve( aPolyPath->Count() + 1 );
1283 paths.emplace_back( aPolyPath->Polygon(), aZValueBuffer, aArcBuffer );
1285 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& child : *aPolyPath )
1287 paths.emplace_back( child->Polygon(), aZValueBuffer, aArcBuffer );
1289 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& grandchild : *child )
1299 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1300 const std::vector<SHAPE_ARC>& aArcBuffer )
1304 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& n : tree )
1310 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1311 const std::vector<SHAPE_ARC>& aArcBuffer )
1316 for(
const Clipper2Lib::Path64& n : aPath )
1318 if( Clipper2Lib::Area( n ) > 0 )
1327 wxCHECK2_MSG( !
path.empty(),
continue, wxT(
"Cannot add a hole before an outline" ) );
1330 path.emplace_back( n, aZValueBuffer, aArcBuffer );
1372 int x = edge->
m_p1.
x;
1373 int y = edge->
m_p1.
y;
1374 int min_dist = std::numeric_limits<int>::max();
1381 if( !e->matches( y ) )
1386 if( e->m_p1.y == e->m_p2.y )
1388 x_intersect = std::max( e->m_p1.x, e->m_p2.x );
1392 x_intersect = e->m_p1.x +
rescale( e->m_p2.x - e->m_p1.x, y - e->m_p1.y,
1393 e->m_p2.y - e->m_p1.y );
1396 int dist = ( x - x_intersect );
1398 if( dist >= 0 && dist < min_dist && e->m_connected )
1401 x_nearest = x_intersect;
1414 edges.push_back( split_2 );
1415 edges.push_back( lead1 );
1416 edges.push_back( lead2 );
1421 e_nearest->
m_next = lead1;
1426 for( last = edge; last->
m_next != edge; last = last->
m_next )
1452 if( paths.size() == 1 )
1455 int num_unconnected = 0;
1459 const std::vector<VECTOR2I>& points =
path.CPoints();
1460 int pointCount = points.size();
1464 int x_min = std::numeric_limits<int>::max();
1466 for(
int i = 0; i < pointCount; i++ )
1468 if( points[i].x < x_min )
1469 x_min = points[i].x;
1474 points[ i+1 == pointCount ? 0 : i+1 ] );
1485 if( i == pointCount - 1 )
1489 edges.push_back( fe );
1493 if( fe->
m_p1.
x == x_min )
1494 border_edges.push_back( fe );
1505 while( num_unconnected > 0 )
1507 int x_min = std::numeric_limits<int>::max();
1508 auto it = border_edges.begin();
1513 for( ; it != border_edges.end(); ++it )
1516 int xt = border_edge->
m_p1.
x;
1518 if( ( xt <= x_min ) && !border_edge->
m_connected )
1521 smallestX = border_edge;
1525 int num_processed =
processEdge( edges, smallestX );
1528 if( !num_processed )
1530 wxLogWarning( wxT(
"Broken polygon, dropping path" ) );
1538 num_unconnected -= num_processed;
1556 paths.push_back( std::move( newPath ) );
1571 assert( aPoly.size() == 1 );
1577 bool m_duplicate =
false;
1584 bool compareSegs(
const SEG& s1,
const SEG& s2 )
const
1586 return (s1.
A == s2.
B && s1.
B == s2.
A);
1591 return compareSegs( m_poly->
CSegment( m_index ),
1592 aOther.m_poly->CSegment( aOther.m_index ) );
1597 return !compareSegs( m_poly->
CSegment( m_index ),
1598 aOther.m_poly->CSegment( aOther.m_index ) );
1603 std::size_t operator()(
const EDGE& aEdge )
const
1605 const SEG& a = aEdge.m_poly->CSegment( aEdge.m_index );
1606 std::size_t seed = 0xa82de1c0;
1613 struct EDGE_LIST_ENTRY
1616 EDGE_LIST_ENTRY*
next;
1619 std::unordered_set<EDGE, EDGE::HASH> uniqueEdges;
1624 auto edgeList = std::make_unique<EDGE_LIST_ENTRY[]>( lc.
SegmentCount() );
1628 edgeList[i].index = i;
1629 edgeList[i].next = &edgeList[ (i != lc.
SegmentCount() - 1) ? i + 1 : 0 ];
1632 std::unordered_set<EDGE_LIST_ENTRY*> queue;
1637 uniqueEdges.insert( e );
1643 auto it = uniqueEdges.find( e );
1645 if( it != uniqueEdges.end() && it->m_index != i )
1647 int e1 = it->m_index;
1651 std::swap( e1, e2 );
1653 int e1_prev = e1 - 1;
1658 int e2_prev = e2 - 1;
1663 int e1_next = e1 + 1;
1668 int e2_next = e2 + 1;
1673 edgeList[e1_prev].next = &edgeList[ e2_next ];
1674 edgeList[e2_prev].next = &edgeList[ e1_next ];
1675 edgeList[i].next =
nullptr;
1676 edgeList[it->m_index].next =
nullptr;
1682 if( edgeList[i].
next )
1683 queue.insert( &edgeList[i] );
1686 auto edgeBuf = std::make_unique<EDGE_LIST_ENTRY* []>( lc.
SegmentCount() );
1692 double max_poly = 0.0;
1694 while( queue.size() )
1696 EDGE_LIST_ENTRY* e_first = *queue.begin();
1697 EDGE_LIST_ENTRY* e = e_first;
1704 }
while( e && e != e_first );
1708 for(
int i = 0; i < cnt; i++ )
1712 queue.erase( edgeBuf[i] );
1717 double area = std::fabs( outl.
Area() );
1719 if( area > max_poly )
1725 result.push_back( outl );
1730 std::swap( result[0], result[outline] );
1742 if( paths.size() > 1 )
1783 while( outline.size() > 1 )
1808 std::stringstream ss;
1810 ss <<
"SHAPE_LINE_CHAIN poly; \n";
1812 for(
unsigned i = 0; i <
m_polys.size(); i++ )
1814 for(
unsigned j = 0; j <
m_polys[i].size(); j++ )
1817 ss <<
"{ auto tmp = " <<
m_polys[i][j].Format() <<
";\n";
1823 ss <<
" poly.AddOutline(tmp); } \n";
1827 ss <<
" poly.AddHole(tmp); } \n";
1843 if( tmp !=
"polyset" )
1848 int n_polys = atoi( tmp.c_str() );
1853 for(
int i = 0; i < n_polys; i++ )
1863 int n_outlines = atoi( tmp.c_str() );
1865 if( n_outlines < 0 )
1868 for(
int j = 0; j < n_outlines; j++ )
1875 int n_vertices = atoi( tmp.c_str() );
1877 for(
int v = 0; v < n_vertices; v++ )
1881 aStream >> tmp; p.
x = atoi( tmp.c_str() );
1882 aStream >> tmp; p.
y = atoi( tmp.c_str() );
1886 paths.push_back( outline );
1900 for(
unsigned i = 0; i <
m_polys.size(); i++ )
1917 for(
unsigned i = 0; i <
m_polys.size(); i++ )
1920 bb = *
m_polys[i][0].GetCachedBBox();
1937 if( lineChain.PointOnEdge( aP ) )
1952 if( dist_sq == 0 || dist_sq <
SEG::Square( aClearance ) )
1955 *aLocation = nearest;
1958 *aActual = sqrt( dist_sq );
1976 if( dist_sq == 0 || dist_sq <
SEG::Square( aClearance ) )
1979 *aLocation = nearest;
1982 *aActual = sqrt( dist_sq );
1999 int extra = segment->
GetWidth() / 2;
2001 if(
Collide( segment->
GetSeg(), aClearance + extra, aActual, aLocation ) )
2004 *aActual = std::max( 0, *aActual - extra );
2017 if(
Collide( circle->
GetCenter(), aClearance + extra, aActual, aLocation ) )
2020 *aActual = std::max( 0, *aActual - extra );
2030 int actual = INT_MAX;
2037 if( aActual || aLocation )
2042 if( aShape->
Collide( &tri, aClearance, &triActual, &triLocation ) )
2044 if( triActual < actual )
2047 location = triLocation;
2053 if( aShape->
Collide( &tri, aClearance ) )
2059 if( actual < INT_MAX )
2062 *aActual = std::max( 0, actual );
2065 *aLocation = location;
2083 if( aPolygonIdx < 0 )
2084 aPolygonIdx +=
m_polys.size();
2086 m_polys[aPolygonIdx].erase(
m_polys[aPolygonIdx].begin() + aContourIdx );
2100 std::vector<VERTEX_INDEX> indices_to_remove;
2105 segmentStart = *iterator;
2111 segmentEnd = contourStart;
2119 contourStart = *iterator;
2127 wxCHECK_MSG( iterator, removed, wxT(
"Invalid polygon. Reached end without noticing. Please report this error" ) );
2129 segmentEnd = *iterator;
2133 if( segmentStart == segmentEnd )
2135 indices_to_remove.push_back( indexStart );
2142 for(
auto it = indices_to_remove.rbegin(); it != indices_to_remove.rend(); ++it )
2165 if( triangleSet->GetSourceOutlineIndex() == aIdx )
2167 else if( triangleSet->GetSourceOutlineIndex() > aIdx )
2168 triangleSet->SetSourceOutlineIndex( triangleSet->GetSourceOutlineIndex() - 1 );
2191 Append( aP.
x, aP.
y, aOutline, aHole );
2197 int aClearance )
const
2200 bool collision =
false;
2210 delta = *iterator - aPoint;
2213 distance_squared =
delta.SquaredEuclideanNorm();
2216 if( distance_squared <= clearance_squared )
2218 if( !aClosestVertex )
2224 clearance_squared = distance_squared;
2227 *aClosestVertex = iterator.GetIndex();
2237 int aClearance )
const
2240 bool collision =
false;
2245 const SEG currentSegment = *iterator;
2249 if( distance_squared <= clearance_squared )
2251 if( !aClosestVertex )
2257 clearance_squared = distance_squared;
2260 *aClosestVertex = iterator.GetIndex();
2270 for(
int polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
2274 for(
int holeIdx = 0; holeIdx <
HoleCount( polygonIdx ); holeIdx++ )
2281 bool aUseBBoxCaches )
const
2287 if( aSubpolyIndex >= 0 )
2288 return containsSingle( aP, aSubpolyIndex, aAccuracy, aUseBBoxCaches );
2291 for(
int polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
2293 if(
containsSingle( aP, polygonIdx, aAccuracy, aUseBBoxCaches ) )
2309 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
2326 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
2337 bool aUseBBoxCaches )
const
2343 for(
int holeIdx = 0; holeIdx <
HoleCount( aSubpolyIndex ); holeIdx++ )
2365 path.Move( aVector );
2369 tri->Move( aVector );
2380 path.Mirror( aX, aY, aRef );
2393 path.Rotate( aAngle, aCenter );
2409 c +=
path.PointCount();
2446 SEG::ecoord minDistance = (*iterator).SquaredDistance( aPoint );
2448 for( iterator++; iterator && minDistance > 0; iterator++ )
2450 SEG::ecoord currentDistance = (*iterator).SquaredDistance( aPoint );
2452 if( currentDistance < minDistance )
2455 *aNearest = (*iterator).NearestPoint( aPoint );
2457 minDistance = currentDistance;
2473 *aNearest = ( aSegment.
A + aSegment.
B ) / 2;
2479 SEG::ecoord minDistance = (*iterator).SquaredDistance( aSegment );
2481 if( aNearest && minDistance == 0 )
2482 *aNearest = ( *iterator ).NearestPoint( aSegment );
2484 for( iterator++; iterator && minDistance > 0; iterator++ )
2486 SEG::ecoord currentDistance = (*iterator).SquaredDistance( aSegment );
2488 if( currentDistance < minDistance )
2491 *aNearest = (*iterator).NearestPoint( aSegment );
2493 minDistance = currentDistance;
2498 return minDistance < 0 ? 0 : minDistance;
2505 wxASSERT_MSG( !aOutlineOnly, wxT(
"Warning: SHAPE_POLY_SET::SquaredDistance does not yet "
2506 "support aOutlineOnly==true" ) );
2513 for(
unsigned int polygonIdx = 0; polygonIdx <
m_polys.size(); polygonIdx++ )
2516 aNearest ? &nearest :
nullptr );
2518 if( currentDistance_sq < minDistance_sq )
2521 *aNearest = nearest;
2523 minDistance_sq = currentDistance_sq;
2527 return minDistance_sq;
2538 for(
unsigned int polygonIdx = 0; polygonIdx <
m_polys.size(); polygonIdx++ )
2541 aNearest ? &nearest :
nullptr );
2543 if( currentDistance_sq < minDistance_sq )
2546 *aNearest = nearest;
2548 minDistance_sq = currentDistance_sq;
2552 return minDistance_sq;
2573 for(
unsigned int idx = 0; idx <
m_polys.size(); idx++ )
2584 for(
size_t idx = 0; idx <
m_polys.size(); idx++ )
2592 unsigned int aDistance,
2593 int aIndex,
int aErrorMax )
2602 if( aDistance == 0 )
2614 for(
int currVertex = 0; currVertex < currContour.PointCount(); currVertex++ )
2617 int x1 = currContour.
CPoint( currVertex ).
x;
2618 int y1 = currContour.CPoint( currVertex ).y;
2627 prevVertex = currVertex == 0 ? currContour.PointCount() - 1 : currVertex - 1;
2630 nextVertex = currVertex == currContour.PointCount() - 1 ? 0 : currVertex + 1;
2633 double xa = currContour.CPoint( prevVertex ).x - x1;
2634 double ya = currContour.CPoint( prevVertex ).y - y1;
2637 double xb = currContour.CPoint( nextVertex ).x - x1;
2638 double yb = currContour.CPoint( nextVertex ).y - y1;
2641 if(
std::abs( xa + xb ) < std::numeric_limits<double>::epsilon()
2642 &&
std::abs( ya + yb ) < std::numeric_limits<double>::epsilon() )
2648 double lena = hypot( xa, ya );
2649 double lenb = hypot( xb, yb );
2666 newContour.
Append( x1 + nx1, y1 + ny1 );
2671 newContour.
Append( x1 + nx2, y1 + ny2 );
2675 double cosine = ( xa * xb + ya * yb ) / ( lena * lenb );
2677 double radius = aDistance;
2678 double denom = sqrt( 2.0 / ( 1 + cosine ) - 1 );
2681 if( std::isinf( denom ) )
2685 if( 0.5 * lena * denom < radius )
2686 radius = 0.5 * lena * denom;
2688 if( 0.5 * lenb * denom < radius )
2689 radius = 0.5 * lenb * denom;
2692 double k = radius / sqrt( .5 * ( 1 - cosine ) );
2693 double lenab = sqrt( ( xa / lena + xb / lenb ) * ( xa / lena + xb / lenb ) +
2694 ( ya / lena + yb / lenb ) * ( ya / lena + yb / lenb ) );
2695 double xc = x1 + k * ( xa / lena + xb / lenb ) / lenab;
2696 double yc = y1 + k * ( ya / lena + yb / lenb ) / lenab;
2699 k = radius / sqrt( 2 / ( 1 + cosine ) - 1 );
2700 double xs = x1 + k * xa / lena - xc;
2701 double ys = y1 + k * ya / lena - yc;
2702 double xe = x1 + k * xb / lenb - xc;
2703 double ye = y1 + k * yb / lenb - yc;
2706 double argument = ( xs * xe + ys * ye ) / ( radius * radius );
2712 else if( argument > 1 )
2715 double arcAngle = acos( argument );
2719 double deltaAngle = arcAngle / segments;
2720 double startAngle = atan2( -ys, xs );
2723 if( xa * yb - ya * xb <= 0 )
2726 double nx = xc + xs;
2727 double ny = yc + ys;
2729 if( std::isnan( nx ) || std::isnan( ny ) )
2738 for(
int j = 0; j < segments; j++ )
2740 nx = xc + cos( startAngle + ( j + 1 ) * deltaAngle ) * radius;
2741 ny = yc - sin( startAngle + ( j + 1 ) * deltaAngle ) * radius;
2743 if( std::isnan( nx ) || std::isnan( ny ) )
2759 newPoly.push_back( newContour );
2768 static_cast<SHAPE&
>(*this) = aOther;
2816 if( w == 0.0 || h == 0.0 )
2819 int n_cells_x, n_cells_y;
2823 n_cells_x = w / aSize;
2824 n_cells_y = floor( h / w * n_cells_x ) + 1;
2828 n_cells_y = h / aSize;
2829 n_cells_x = floor( w / h * n_cells_y ) + 1;
2832 SHAPE_POLY_SET ps1( aPoly ), ps2( aPoly ), maskSetOdd, maskSetEven;
2834 for(
int yy = 0; yy < n_cells_y; yy++ )
2836 for(
int xx = 0; xx < n_cells_x; xx++ )
2840 p.
x = bb.
GetX() + w * xx / n_cells_x;
2841 p.
y = bb.
GetY() + h * yy / n_cells_y;
2845 p2.
x = bb.
GetX() + w * ( xx + 1 ) / n_cells_x;
2846 p2.
y = bb.
GetY() + h * ( yy + 1 ) / n_cells_y;
2854 mask.SetClosed(
true );
2856 if( ( xx ^ yy ) & 1 )
2868 for(
int i = 0; i < ps2.OutlineCount(); i++ )
2869 ps1.AddOutline( ps2.COutline( i ) );
2871 if( ps1.OutlineCount() )
2902 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>& dest )
2904 bool triangulationValid =
false;
2909 if( !dest.empty() && dest.back()->GetTriangleCount() == 0 )
2910 dest.erase( dest.end() - 1 );
2912 dest.push_back( std::make_unique<TRIANGULATED_POLYGON>( forOutline ) );
2924 else if( pass == 2 )
2929 triangulationValid =
false;
2934 triangulationValid =
true;
2937 return triangulationValid;
2950 for(
int jj = 0; jj <
HoleCount( ii ); ++jj )
2957 else if( aSimplify )
2991 hash.
Hash( outline.size() );
2995 hash.
Hash( lc.PointCount() );
2997 for(
int i = 0; i < lc.PointCount(); i++ )
2999 hash.
Hash( lc.CPoint( i ).x );
3000 hash.
Hash( lc.CPoint( i ).y );
3025 std::set<long long> ptHashes;
3029 for(
const VECTOR2I& pt : lc.CPoints() )
3031 const long long ptHash = (
long long) pt.x << 32 | pt.y;
3033 if( ptHashes.count( ptHash ) > 0 )
3036 ptHashes.insert( ptHash );
3055 n += t->GetTriangleCount();
3068 aSubshapes.push_back( &tri );
3079 if( aClearance != 0 )
3129 bool aReverseOrientation,
bool aEvenOdd )
3131 ClipperLib::Clipper clipper;
3132 ClipperLib::PolyTree tree;
3138 ClipperLib::Path lc;
3140 for(
int i = 0; i <
path.PointCount(); i++ )
3142 lc.emplace_back(
path.CPoint( i ).x,
path.CPoint( i ).y );
3145 clipper.AddPath( lc, ClipperLib::ptSubject,
true );
3148 clipper.StrictlySimple(
true );
3149 clipper.Execute( ClipperLib::ctUnion, tree,
3150 aEvenOdd ? ClipperLib::pftEvenOdd : ClipperLib::pftNonZero,
3151 ClipperLib::pftNonZero );
3154 for( ClipperLib::PolyNode* n = tree.GetFirst(); n; n = n->GetNext() )
3160 for(
unsigned int i = 0; i < n->Contour.size(); i++ )
3161 result.
Outline( outl ).
Append( n->Contour[i].X, n->Contour[i].Y );
3163 for(
unsigned int i = 0; i < n->Childs.size(); i++ )
3165 int outh = result.
NewHole( outl );
3166 for(
unsigned int j = 0; j < n->Childs[i]->Contour.size(); j++ )
3168 result.
Hole( outl, outh )
3169 .
Append( n->Childs[i]->Contour[j].X, n->Childs[i]->Contour[j].Y );
bool operator==(const wxAuiPaneInfo &aLhs, const wxAuiPaneInfo &aRhs)
static PGM_BASE * process
bool operator!=(const BOM_FIELD &lhs, const BOM_FIELD &rhs)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
coord_type GetTop() const
coord_type GetHeight() const
coord_type GetWidth() const
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
coord_type GetRight() const
coord_type GetLeft() const
coord_type GetBottom() const
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
void Hash(uint8_t *data, uint32_t length)
bool TesselatePolygon(const SHAPE_LINE_CHAIN &aPoly)
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...
SHAPE_LINE_CHAIN & Simplify(bool aRemoveColinear=true)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
bool IsClosed() const override
void GenerateBBoxCache() const
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this 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.
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.
virtual bool HasIndexableSubshapes() const override
bool m_triangulationValid
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.
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
bool PointOnEdge(const VECTOR2I &aP) const
Check if point aP lies on an edge or vertex of some of the outlines or holes.
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.
CORNER_STRATEGY
define how inflate transform build inflated polygon
@ ALLOW_ACUTE_CORNERS
just inflate the polygon. Acute angles create spikes
@ CHAMFER_ACUTE_CORNERS
Acute angles are chamfered.
@ ROUND_ACUTE_CORNERS
Acute angles are rounded.
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ ROUND_ALL_CORNERS
All angles are rounded.
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.
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,...
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 BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
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.
void inflate1(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy)
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
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...
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.
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.
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 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
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 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.
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)
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.
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
static constexpr extended_type ECOORD_MAX
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 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 float distance(const SFVEC2UI &a, const SFVEC2UI &b)
@ SH_POLY_SET
set of polygons (with holes, etc.)
static int processEdge(FractureEdgeSet &edges, FractureEdge *edge)
static SHAPE_POLY_SET partitionPolyIntoRegularCellGrid(const SHAPE_POLY_SET &aPoly, int aSize)
std::vector< FractureEdge * > FractureEdgeSet
Holds information on each point of a SHAPE_LINE_CHAIN that is retrievable after an operation with Cli...
FractureEdge(bool connected, const VECTOR2I &p1, const VECTOR2I &p2)
bool matches(int y) const
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...
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).