41#include <unordered_set>
45#include <clipper2/clipper.h>
67#if defined( __MINGW32__ )
68 #define TRIANGULATESIMPLIFICATIONLEVEL 50
69 #define ENABLECACHEFRIENDLYFRACTURE true
71 #define TRIANGULATESIMPLIFICATIONLEVEL ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel
72 #define ENABLECACHEFRIENDLYFRACTURE ADVANCED_CFG::GetCfg().m_EnableCacheFriendlyFracture
109 m_polys( aOther.m_polys )
137 m_polys( aOther.m_polys )
167 unsigned int contourIdx = 0;
170 int currentGlobalIdx = 0;
172 for( polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
176 for( contourIdx = 0; contourIdx < currentPolygon.size(); contourIdx++ )
179 int totalPoints = currentContour.
PointCount();
181 for( vertexIdx = 0; vertexIdx < totalPoints; vertexIdx++ )
184 if( currentGlobalIdx == aGlobalIdx )
186 aRelativeIndices->
m_polygon = polygonIdx;
187 aRelativeIndices->
m_contour = contourIdx;
188 aRelativeIndices->
m_vertex = vertexIdx;
204 int& aGlobalIdx )
const
206 int selectedVertex = aRelativeIndices.
m_vertex;
207 unsigned int selectedContour = aRelativeIndices.
m_contour;
208 unsigned int selectedPolygon = aRelativeIndices.
m_polygon;
211 if( selectedPolygon <
m_polys.size() && selectedContour <
m_polys[selectedPolygon].size()
212 && selectedVertex <
m_polys[selectedPolygon][selectedContour].PointCount() )
218 for(
unsigned int polygonIdx = 0; polygonIdx < selectedPolygon; polygonIdx++ )
220 currentPolygon =
Polygon( polygonIdx );
222 for(
unsigned int contourIdx = 0; contourIdx < currentPolygon.size(); contourIdx++ )
223 aGlobalIdx += currentPolygon[contourIdx].PointCount();
226 currentPolygon =
Polygon( selectedPolygon );
228 for(
unsigned int contourIdx = 0; contourIdx < selectedContour; contourIdx++ )
229 aGlobalIdx += currentPolygon[contourIdx].PointCount();
231 aGlobalIdx += selectedVertex;
248 poly.push_back( empty_path );
265 m_polys[aOutline].push_back( empty_path );
267 return m_polys.back().size() - 2;
285 assert( aOutline < (
int)
m_polys.size() );
286 assert( idx < (
int)
m_polys[aOutline].size() );
288 m_polys[aOutline][idx].Append( x, y, aAllowDuplication );
290 return m_polys[aOutline][idx].PointCount();
308 assert( aOutline < (
int)
m_polys.size() );
309 assert( idx < (
int)
m_polys[aOutline].size() );
311 m_polys[aOutline][idx].Append( aArc, aAccuracy );
313 return m_polys[aOutline][idx].PointCount();
321 if( aGlobalIndex < 0 )
334 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
354 if( aOutline >= (
int)
m_polys.size() )
357 if( idx >= (
int)
m_polys[aOutline].size() )
360 return m_polys[aOutline][idx].PointCount();
375 for(
int idx = 0; idx <=
HoleCount( ii ); idx++ )
377 full_count +=
m_polys[ii][idx].PointCount();
387 assert( aFirstPolygon >= 0 && aLastPolygon <=
OutlineCount() );
391 for(
int index = aFirstPolygon; index < aLastPolygon; index++ )
410 assert( aOutline < (
int)
m_polys.size() );
411 assert( idx < (
int)
m_polys[aOutline].size() );
413 return m_polys[aOutline][idx].CPoint( aIndex );
423 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
453 else if( index.
m_vertex == lastpoint )
471 *aPrevious = previous;
487 std::vector<SEG> segments;
491 segments.emplace_back( *it );
493 std::sort( segments.begin(), segments.end(), [](
const SEG& a,
const SEG& b )
495 int min_a_x = std::min( a.A.x, a.B.x );
496 int min_b_x = std::min( b.A.x, b.B.x );
498 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 ) );
501 for(
auto it = segments.begin(); it != segments.end(); ++it )
503 SEG& firstSegment = *it;
506 auto innerIterator = it;
507 int max_x = std::max( firstSegment.
A.
x, firstSegment.
B.
x );
508 int max_y = std::max( firstSegment.
A.
y, firstSegment.
B.
y );
511 for( innerIterator++; innerIterator != segments.end(); innerIterator++ )
513 SEG& secondSegment = *innerIterator;
514 int min_x = std::min( secondSegment.
A.
x, secondSegment.
B.
x );
515 int min_y = std::min( secondSegment.
A.
y, secondSegment.
B.
y );
519 if( max_x < min_x || ( max_x == min_x && max_y < min_y ) )
523 bool adjacent = ( index_diff == 1) || (index_diff == ((
int)segments.size() - 1) );
526 if( !adjacent && firstSegment.
Collide( secondSegment, 0 ) )
537 for(
unsigned int polygon = 0; polygon <
m_polys.size(); polygon++ )
553 poly.push_back( aOutline );
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;
750 booleanOp( aType, *
this, aOtherShape, aFastMode );
760 wxFAIL_MSG( wxT(
"Boolean ops on curved polygons are not supported. You should call "
761 "ClearArcs() before carrying out the boolean operation." ) );
764 ClipperLib::Clipper c;
768 std::vector<CLIPPER_Z_VALUE> zValues;
769 std::vector<SHAPE_ARC> arcBuffer;
770 std::map<VECTOR2I, CLIPPER_Z_VALUE> newIntersectPoints;
774 for(
size_t i = 0; i < poly.size(); i++ )
776 c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
777 ClipperLib::ptSubject,
true );
783 for(
size_t i = 0; i < poly.size(); i++ )
785 c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
786 ClipperLib::ptClip,
true );
790 ClipperLib::PolyTree solution;
792 ClipperLib::ZFillCallback callback =
793 [&]( ClipperLib::IntPoint & e1bot, ClipperLib::IntPoint & e1top,
794 ClipperLib::IntPoint & e2bot, ClipperLib::IntPoint & e2top,
795 ClipperLib::IntPoint & pt )
798 [&](
const ssize_t& aZvalue,
const ssize_t& aCompareVal = -1 ) -> ssize_t
802 retval = zValues.at( aZvalue ).m_SecondArcIdx;
804 if( retval == -1 || ( aCompareVal > 0 && retval != aCompareVal ) )
805 retval = zValues.at( aZvalue ).m_FirstArcIdx;
811 [&](
const ssize_t& aBottomZ,
const ssize_t aTopZ ) -> ssize_t
813 ssize_t retval = arcIndex( aBottomZ );
817 if( retval != arcIndex( aTopZ, retval ) )
824 ssize_t e1ArcSegmentIndex = arcSegment( e1bot.Z, e1top.Z );
825 ssize_t e2ArcSegmentIndex = arcSegment( e2bot.Z, e2top.Z );
829 if( e1ArcSegmentIndex != -1 )
840 size_t z_value_ptr = zValues.size();
841 zValues.push_back( newZval );
845 newIntersectPoints.insert( {
VECTOR2I( pt.X, pt.Y ), newZval } );
851 c.ZFillFunction( std::move( callback ) );
853 c.Execute( aType, solution, ClipperLib::pftNonZero, ClipperLib::pftNonZero );
871 wxFAIL_MSG( wxT(
"Boolean ops on curved polygons are not supported. You should call "
872 "ClearArcs() before carrying out the boolean operation." ) );
875 Clipper2Lib::Clipper64 c;
877 std::vector<CLIPPER_Z_VALUE> zValues;
878 std::vector<SHAPE_ARC> arcBuffer;
879 std::map<VECTOR2I, CLIPPER_Z_VALUE> newIntersectPoints;
881 Clipper2Lib::Paths64 paths;
882 Clipper2Lib::Paths64 clips;
886 for(
size_t i = 0; i < poly.size(); i++ )
888 paths.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
894 for(
size_t i = 0; i < poly.size(); i++ )
896 clips.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
900 c.AddSubject( paths );
903 Clipper2Lib::PolyTree64 solution;
905 Clipper2Lib::ZCallback64 callback =
906 [&](
const Clipper2Lib::Point64 & e1bot,
const Clipper2Lib::Point64 & e1top,
907 const Clipper2Lib::Point64 & e2bot,
const Clipper2Lib::Point64 & e2top,
908 Clipper2Lib::Point64 & pt )
911 [&](
const ssize_t& aZvalue,
const ssize_t& aCompareVal = -1 ) -> ssize_t
915 retval = zValues.at( aZvalue ).m_SecondArcIdx;
917 if( retval == -1 || ( aCompareVal > 0 && retval != aCompareVal ) )
918 retval = zValues.at( aZvalue ).m_FirstArcIdx;
924 [&](
const ssize_t& aBottomZ,
const ssize_t aTopZ ) -> ssize_t
926 ssize_t retval = arcIndex( aBottomZ );
930 if( retval != arcIndex( aTopZ, retval ) )
937 ssize_t e1ArcSegmentIndex = arcSegment( e1bot.z, e1top.z );
938 ssize_t e2ArcSegmentIndex = arcSegment( e2bot.z, e2top.z );
942 if( e1ArcSegmentIndex != -1 )
953 size_t z_value_ptr = zValues.size();
954 zValues.push_back( newZval );
958 newIntersectPoints.insert( {
VECTOR2I( pt.x, pt.y ), newZval } );
964 c.SetZCallback( std::move( callback ) );
966 c.Execute( aType, Clipper2Lib::FillRule::NonZero, solution );
975 booleanOp( Clipper2Lib::ClipType::Union, b );
981 booleanOp( Clipper2Lib::ClipType::Difference, b );
987 booleanOp( Clipper2Lib::ClipType::Intersection, b );
993 booleanOp( Clipper2Lib::ClipType::Xor, b );
1000 booleanOp( Clipper2Lib::ClipType::Union, a, b );
1007 booleanOp( Clipper2Lib::ClipType::Difference, a, b );
1014 booleanOp( Clipper2Lib::ClipType::Intersection, a, b );
1021 booleanOp( Clipper2Lib::ClipType::Xor, a, b );
1029 Inflate( aFactor, aCornerStrategy, aMaxError );
1036 using namespace ClipperLib;
1040 #define SEG_CNT_MAX 64
1041 static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
1048 JoinType joinType = jtRound;
1049 double miterLimit = 2.0;
1050 JoinType miterFallback = jtSquare;
1052 switch( aCornerStrategy )
1054 case CORNER_STRATEGY::ALLOW_ACUTE_CORNERS:
1057 miterFallback = jtSquare;
1060 case CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS:
1062 miterFallback = jtRound;
1065 case CORNER_STRATEGY::ROUND_ACUTE_CORNERS:
1067 miterFallback = jtSquare;
1070 case CORNER_STRATEGY::CHAMFER_ALL_CORNERS:
1071 joinType = jtSquare;
1072 miterFallback = jtSquare;
1075 case CORNER_STRATEGY::ROUND_ALL_CORNERS:
1077 miterFallback = jtSquare;
1081 std::vector<CLIPPER_Z_VALUE> zValues;
1082 std::vector<SHAPE_ARC> arcBuffer;
1086 for(
size_t i = 0; i < poly.size(); i++ )
1088 c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
1089 joinType, etClosedPolygon );
1099 if( aCircleSegCount < 6 )
1100 aCircleSegCount = 6;
1104 if( aCircleSegCount >
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
1106 coeff = 1.0 - cos( M_PI / aCircleSegCount );
1109 arc_tolerance_factor[aCircleSegCount] = coeff;
1113 coeff = arc_tolerance_factor[aCircleSegCount];
1116 c.ArcTolerance =
std::abs( aAmount ) * coeff;
1117 c.MiterLimit = miterLimit;
1118 c.MiterFallback = miterFallback;
1119 c.Execute( solution, aAmount );
1128 using namespace Clipper2Lib;
1132 #define SEG_CNT_MAX 64
1133 static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
1140 JoinType joinType = JoinType::Round;
1141 double miterLimit = 2.0;
1143 switch( aCornerStrategy )
1145 case CORNER_STRATEGY::ALLOW_ACUTE_CORNERS:
1146 joinType = JoinType::Miter;
1150 case CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS:
1151 joinType = JoinType::Miter;
1154 case CORNER_STRATEGY::ROUND_ACUTE_CORNERS:
1155 joinType = JoinType::Miter;
1158 case CORNER_STRATEGY::CHAMFER_ALL_CORNERS:
1159 joinType = JoinType::Square;
1162 case CORNER_STRATEGY::ROUND_ALL_CORNERS:
1163 joinType = JoinType::Round;
1167 std::vector<CLIPPER_Z_VALUE> zValues;
1168 std::vector<SHAPE_ARC> arcBuffer;
1174 for(
size_t i = 0; i < poly.size(); i++ )
1175 paths.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
1177 c.AddPaths( paths, joinType, EndType::Polygon );
1184 if( aCircleSegCount < 6 )
1185 aCircleSegCount = 6;
1189 if( aCircleSegCount >
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
1191 coeff = 1.0 - cos( M_PI / aCircleSegCount );
1194 arc_tolerance_factor[aCircleSegCount] = coeff;
1198 coeff = arc_tolerance_factor[aCircleSegCount];
1201 c.ArcTolerance(
std::abs( aAmount ) * coeff );
1202 c.MiterLimit( miterLimit );
1209 c.Execute( aAmount, paths );
1211 Clipper2Lib::SimplifyPaths( paths,
std::abs( aAmount ) * coeff,
true );
1214 c2.PreserveCollinear(
false );
1215 c2.ReverseSolution(
false );
1216 c2.AddSubject( paths );
1217 c2.Execute(ClipType::Union, FillRule::Positive, tree);
1221 c.Execute( aAmount, tree );
1232 using namespace Clipper2Lib;
1236 #define SEG_CNT_MAX 64
1237 static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
1244 JoinType joinType = JoinType::Round;
1245 double miterLimit = 2.0;
1247 switch( aCornerStrategy )
1249 case CORNER_STRATEGY::ALLOW_ACUTE_CORNERS:
1250 joinType = JoinType::Miter;
1254 case CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS:
1255 joinType = JoinType::Miter;
1258 case CORNER_STRATEGY::ROUND_ACUTE_CORNERS:
1259 joinType = JoinType::Miter;
1262 case CORNER_STRATEGY::CHAMFER_ALL_CORNERS:
1263 joinType = JoinType::Square;
1266 case CORNER_STRATEGY::ROUND_ALL_CORNERS:
1267 joinType = JoinType::Round;
1271 std::vector<CLIPPER_Z_VALUE> zValues;
1272 std::vector<SHAPE_ARC> arcBuffer;
1275 c.AddPath(
path, joinType, EndType::Butt );
1281 if( aCircleSegCount < 6 )
1282 aCircleSegCount = 6;
1286 if( aCircleSegCount >
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
1288 coeff = 1.0 - cos( M_PI / aCircleSegCount );
1291 arc_tolerance_factor[aCircleSegCount] = coeff;
1295 coeff = arc_tolerance_factor[aCircleSegCount];
1298 c.ArcTolerance(
std::abs( aAmount ) * coeff );
1299 c.MiterLimit( miterLimit );
1306 c.Execute( aAmount, paths2 );
1308 Clipper2Lib::SimplifyPaths( paths2,
std::abs( aAmount ) * coeff,
false );
1311 c2.PreserveCollinear(
false );
1312 c2.ReverseSolution(
false );
1313 c2.AddSubject( paths2 );
1314 c2.Execute( ClipType::Union, FillRule::Positive, tree );
1318 c.Execute( aAmount, tree );
1331 inflate2( aAmount, segCount, aCornerStrategy, aSimplify );
1340 inflateLine2( aLine, aAmount, segCount, aCornerStrategy, aSimplify );
1345 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1346 const std::vector<SHAPE_ARC>& aArcBuffer )
1350 for( ClipperLib::PolyNode* n = tree->GetFirst(); n; n = n->GetNext() )
1355 paths.reserve( n->Childs.size() + 1 );
1357 paths.emplace_back( n->Contour, aZValueBuffer, aArcBuffer );
1359 for(
unsigned int i = 0; i < n->Childs.size(); i++ )
1360 paths.emplace_back( n->Childs[i]->Contour, aZValueBuffer, aArcBuffer );
1369 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1370 const std::vector<SHAPE_ARC>& aArcBuffer )
1372 if( !aPolyPath->IsHole() )
1375 paths.reserve( aPolyPath->Count() + 1 );
1376 paths.emplace_back( aPolyPath->Polygon(), aZValueBuffer, aArcBuffer );
1378 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& child : *aPolyPath )
1380 paths.emplace_back( child->Polygon(), aZValueBuffer, aArcBuffer );
1382 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& grandchild : *child )
1392 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1393 const std::vector<SHAPE_ARC>& aArcBuffer )
1397 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& n : tree )
1403 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1404 const std::vector<SHAPE_ARC>& aArcBuffer )
1409 for(
const Clipper2Lib::Path64& n : aPath )
1411 if( Clipper2Lib::Area( n ) > 0 )
1420 wxCHECK2_MSG( !
path.empty(),
continue, wxT(
"Cannot add a hole before an outline" ) );
1423 path.emplace_back( n, aZValueBuffer, aArcBuffer );
1460 int x = edge.
m_p1.
x;
1461 int y = edge.
m_p1.
y;
1462 int min_dist = std::numeric_limits<int>::max();
1481 x_intersect = std::max( e.
m_p1.
x, e.
m_p2.
x );
1489 int dist = ( x - x_intersect );
1491 if( dist >= 0 && dist < min_dist )
1494 x_nearest = x_intersect;
1507 edges[hole2outline_index] =
1510 edges[split_index] =
1515 e_nearest->
m_next = outline2hole_index;
1518 for( ; last->
m_next != edgeIndex; last = &edges[last->
m_next] )
1520 last->
m_next = hole2outline_index;
1530 bool outline =
true;
1532 if( paths.size() == 1 )
1535 size_t total_point_count = 0;
1539 total_point_count +=
path.PointCount();
1542 if( total_point_count > (
size_t) std::numeric_limits<FractureEdge::Index>::max() )
1544 wxLogWarning( wxT(
"Polygon has more points than int limit" ) );
1551 edges.reserve( total_point_count + paths.size() * 3 );
1557 int path_or_provoking_index;
1562 std::vector<PathInfo> sorted_paths;
1563 const int paths_count =
static_cast<int>( paths.size() );
1564 sorted_paths.reserve( paths_count );
1566 for(
int path_index = 0; path_index < paths_count; path_index++ )
1569 const std::vector<VECTOR2I>& points =
path.CPoints();
1570 const int point_count =
static_cast<int>( points.size() );
1571 int x_min = std::numeric_limits<int>::max();
1572 int y_min = std::numeric_limits<int>::max();
1575 for(
int point_index = 0; point_index < point_count; point_index++ )
1577 const VECTOR2I& point = points[point_index];
1578 if( point.
x < x_min )
1581 leftmost = point_index;
1583 if( point.
y < y_min )
1587 sorted_paths.emplace_back( PathInfo{ path_index, leftmost, x_min, y_min } );
1590 std::sort( sorted_paths.begin() + 1, sorted_paths.end(),
1591 [](
const PathInfo& a,
const PathInfo& b )
1594 return a.y_or_bridge < b.y_or_bridge;
1600 for( PathInfo& path_info : sorted_paths )
1603 const std::vector<VECTOR2I>& points =
path.CPoints();
1604 const size_t point_count = points.size();
1609 for(
size_t i = 0; i < point_count - 1; i++ )
1611 edges.emplace_back( points[i], points[i + 1], edge_index + 1 );
1616 edges.emplace_back( points[point_count - 1], points[0], provoking_edge );
1623 path_info.path_or_provoking_index = provoking_edge;
1624 path_info.y_or_bridge = edge_index;
1628 edges.resize( edge_index );
1634 for(
auto it = sorted_paths.begin() + 1; it != sorted_paths.end(); it++ )
1636 auto edge =
processHole( edges, it->path_or_provoking_index,
1637 it->path_or_provoking_index + it->leftmost, it->y_or_bridge );
1642 wxLogWarning( wxT(
"Broken polygon, dropping path" ) );
1690 int x = edge->
m_p1.
x;
1691 int y = edge->
m_p1.
y;
1692 int min_dist = std::numeric_limits<int>::max();
1699 if( !e->matches( y ) )
1704 if( e->m_p1.y == e->m_p2.y )
1706 x_intersect = std::max( e->m_p1.x, e->m_p2.x );
1710 x_intersect = e->m_p1.x
1711 +
rescale( e->m_p2.x - e->m_p1.x, y - e->m_p1.y, e->m_p2.y - e->m_p1.y );
1714 int dist = ( x - x_intersect );
1716 if( dist >= 0 && dist < min_dist && e->m_connected )
1719 x_nearest = x_intersect;
1735 edges.push_back( split_2 );
1736 edges.push_back( lead1 );
1737 edges.push_back( lead2 );
1742 e_nearest->
m_next = lead1;
1747 for( last = edge; last->
m_next != edge; last = last->
m_next )
1773 if( paths.size() == 1 )
1776 int num_unconnected = 0;
1780 const std::vector<VECTOR2I>& points =
path.CPoints();
1781 int pointCount = points.size();
1785 int x_min = std::numeric_limits<int>::max();
1787 for(
int i = 0; i < pointCount; i++ )
1789 if( points[i].x < x_min )
1790 x_min = points[i].x;
1795 points[i + 1 == pointCount ? 0 : i + 1] );
1806 if( i == pointCount - 1 )
1810 edges.push_back( fe );
1814 if( fe->
m_p1.
x == x_min )
1815 border_edges.push_back( fe );
1826 while( num_unconnected > 0 )
1828 int x_min = std::numeric_limits<int>::max();
1829 auto it = border_edges.begin();
1834 for( ; it != border_edges.end(); ++it )
1837 int xt = border_edge->
m_p1.
x;
1839 if( ( xt <= x_min ) && !border_edge->
m_connected )
1842 smallestX = border_edge;
1846 int num_processed =
processEdge( edges, smallestX );
1849 if( !num_processed )
1851 wxLogWarning( wxT(
"Broken polygon, dropping path" ) );
1859 num_unconnected -= num_processed;
1877 paths.push_back( std::move( newPath ) );
1900 assert( aPoly.size() == 1 );
1906 bool m_duplicate =
false;
1913 bool compareSegs(
const SEG& s1,
const SEG& s2 )
const
1915 return (s1.
A == s2.
B && s1.
B == s2.
A);
1920 return compareSegs( m_poly->
CSegment( m_index ),
1921 aOther.m_poly->CSegment( aOther.m_index ) );
1926 return !compareSegs( m_poly->
CSegment( m_index ),
1927 aOther.m_poly->CSegment( aOther.m_index ) );
1932 std::size_t operator()(
const EDGE& aEdge )
const
1934 const SEG& a = aEdge.m_poly->CSegment( aEdge.m_index );
1935 std::size_t seed = 0xa82de1c0;
1942 struct EDGE_LIST_ENTRY
1945 EDGE_LIST_ENTRY*
next;
1948 std::unordered_set<EDGE, EDGE::HASH> uniqueEdges;
1953 auto edgeList = std::make_unique<EDGE_LIST_ENTRY[]>( lc.
SegmentCount() );
1957 edgeList[i].index = i;
1958 edgeList[i].next = &edgeList[ (i != lc.
SegmentCount() - 1) ? i + 1 : 0 ];
1961 std::unordered_set<EDGE_LIST_ENTRY*> queue;
1966 uniqueEdges.insert( e );
1972 auto it = uniqueEdges.find( e );
1974 if( it != uniqueEdges.end() && it->m_index != i )
1976 int e1 = it->m_index;
1980 std::swap( e1, e2 );
1982 int e1_prev = e1 - 1;
1987 int e2_prev = e2 - 1;
1992 int e1_next = e1 + 1;
1997 int e2_next = e2 + 1;
2002 edgeList[e1_prev].next = &edgeList[ e2_next ];
2003 edgeList[e2_prev].next = &edgeList[ e1_next ];
2004 edgeList[i].next =
nullptr;
2005 edgeList[it->m_index].next =
nullptr;
2011 if( edgeList[i].
next )
2012 queue.insert( &edgeList[i] );
2015 auto edgeBuf = std::make_unique<EDGE_LIST_ENTRY* []>( lc.
SegmentCount() );
2021 double max_poly = 0.0;
2023 while( queue.size() )
2025 EDGE_LIST_ENTRY* e_first = *queue.begin();
2026 EDGE_LIST_ENTRY* e = e_first;
2033 }
while( e && e != e_first );
2037 for(
int i = 0; i < cnt; i++ )
2041 queue.erase( edgeBuf[i] );
2046 double area = std::fabs( outl.
Area() );
2048 if( area > max_poly )
2054 result.push_back( outl );
2059 std::swap( result[0], result[outline] );
2071 if( paths.size() > 1 )
2103 path.Simplify( aMaxError );
2121 while( outline.size() > 1 )
2146 std::stringstream ss;
2148 ss <<
"SHAPE_LINE_CHAIN poly; \n";
2150 for(
unsigned i = 0; i <
m_polys.size(); i++ )
2152 for(
unsigned j = 0; j <
m_polys[i].size(); j++ )
2155 ss <<
"{ auto tmp = " <<
m_polys[i][j].Format() <<
";\n";
2161 ss <<
" poly.AddOutline(tmp); } \n";
2165 ss <<
" poly.AddHole(tmp); } \n";
2181 if( tmp !=
"polyset" )
2186 int n_polys = atoi( tmp.c_str() );
2191 for(
int i = 0; i < n_polys; i++ )
2201 int n_outlines = atoi( tmp.c_str() );
2203 if( n_outlines < 0 )
2206 for(
int j = 0; j < n_outlines; j++ )
2213 int n_vertices = atoi( tmp.c_str() );
2215 for(
int v = 0; v < n_vertices; v++ )
2219 aStream >> tmp; p.
x = atoi( tmp.c_str() );
2220 aStream >> tmp; p.
y = atoi( tmp.c_str() );
2224 paths.push_back( outline );
2238 for(
unsigned i = 0; i <
m_polys.size(); i++ )
2255 for(
unsigned i = 0; i <
m_polys.size(); i++ )
2258 bb = *
m_polys[i][0].GetCachedBBox();
2275 if( lineChain.PointOnEdge( aP, aAccuracy ) )
2290 if( dist_sq == 0 || dist_sq <
SEG::Square( aClearance ) )
2293 *aLocation = nearest;
2296 *aActual = sqrt( dist_sq );
2314 if( dist_sq == 0 || dist_sq <
SEG::Square( aClearance ) )
2317 *aLocation = nearest;
2320 *aActual = sqrt( dist_sq );
2337 int extra = segment->
GetWidth() / 2;
2339 if(
Collide( segment->
GetSeg(), aClearance + extra, aActual, aLocation ) )
2342 *aActual = std::max( 0, *aActual - extra );
2355 if(
Collide( circle->
GetCenter(), aClearance + extra, aActual, aLocation ) )
2358 *aActual = std::max( 0, *aActual - extra );
2368 int actual = INT_MAX;
2375 if( aActual || aLocation )
2380 if( aShape->
Collide( &tri, aClearance, &triActual, &triLocation ) )
2382 if( triActual < actual )
2385 location = triLocation;
2391 if( aShape->
Collide( &tri, aClearance ) )
2397 if( actual < INT_MAX )
2400 *aActual = std::max( 0, actual );
2403 *aLocation = location;
2421 if( aPolygonIdx < 0 )
2422 aPolygonIdx +=
m_polys.size();
2424 m_polys[aPolygonIdx].erase(
m_polys[aPolygonIdx].begin() + aContourIdx );
2444 std::vector<VERTEX_INDEX> indices_to_remove;
2449 segmentStart = *iterator;
2455 segmentEnd = contourStart;
2463 contourStart = *iterator;
2471 wxCHECK_MSG( iterator, removed, wxT(
"Invalid polygon. Reached end without noticing. Please report this error" ) );
2473 segmentEnd = *iterator;
2477 if( segmentStart == segmentEnd )
2479 indices_to_remove.push_back( indexStart );
2486 for(
auto it = indices_to_remove.rbegin(); it != indices_to_remove.rend(); ++it )
2509 if( triangleSet->GetSourceOutlineIndex() == aIdx )
2511 else if( triangleSet->GetSourceOutlineIndex() > aIdx )
2512 triangleSet->SetSourceOutlineIndex( triangleSet->GetSourceOutlineIndex() - 1 );
2539 Append( aP.
x, aP.
y, aOutline, aHole );
2545 int aClearance )
const
2548 bool collision =
false;
2558 delta = *iterator - aPoint;
2561 distance_squared =
delta.SquaredEuclideanNorm();
2564 if( distance_squared <= clearance_squared )
2566 if( !aClosestVertex )
2572 clearance_squared = distance_squared;
2575 *aClosestVertex = iterator.GetIndex();
2585 int aClearance )
const
2588 bool collision =
false;
2593 const SEG currentSegment = *iterator;
2597 if( distance_squared <= clearance_squared )
2599 if( !aClosestVertex )
2605 clearance_squared = distance_squared;
2608 *aClosestVertex = iterator.GetIndex();
2618 for(
int polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
2622 for(
int holeIdx = 0; holeIdx <
HoleCount( polygonIdx ); holeIdx++ )
2629 bool aUseBBoxCaches )
const
2635 if( aSubpolyIndex >= 0 )
2636 return containsSingle( aP, aSubpolyIndex, aAccuracy, aUseBBoxCaches );
2639 for(
int polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
2641 if(
containsSingle( aP, polygonIdx, aAccuracy, aUseBBoxCaches ) )
2657 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
2674 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
2685 bool aUseBBoxCaches )
const
2691 for(
int holeIdx = 0; holeIdx <
HoleCount( aSubpolyIndex ); holeIdx++ )
2713 path.Move( aVector );
2717 tri->Move( aVector );
2729 path.Mirror( aRef, aFlipDirection );
2742 path.Rotate( aAngle, aCenter );
2758 c +=
path.PointCount();
2795 SEG::ecoord minDistance = (*iterator).SquaredDistance( aPoint );
2797 for( iterator++; iterator && minDistance > 0; iterator++ )
2799 SEG::ecoord currentDistance = (*iterator).SquaredDistance( aPoint );
2801 if( currentDistance < minDistance )
2804 *aNearest = (*iterator).NearestPoint( aPoint );
2806 minDistance = currentDistance;
2822 *aNearest = ( aSegment.
A + aSegment.
B ) / 2;
2828 SEG::ecoord minDistance = (*iterator).SquaredDistance( aSegment );
2830 if( aNearest && minDistance == 0 )
2831 *aNearest = ( *iterator ).NearestPoint( aSegment );
2833 for( iterator++; iterator && minDistance > 0; iterator++ )
2837 if( currentDistance < minDistance )
2840 *aNearest = (*iterator).NearestPoint( aSegment );
2842 minDistance = currentDistance;
2847 return minDistance < 0 ? 0 : minDistance;
2854 wxASSERT_MSG( !aOutlineOnly, wxT(
"Warning: SHAPE_POLY_SET::SquaredDistance does not yet "
2855 "support aOutlineOnly==true" ) );
2862 for(
unsigned int polygonIdx = 0; polygonIdx <
m_polys.size(); polygonIdx++ )
2865 aNearest ? &nearest :
nullptr );
2867 if( currentDistance_sq < minDistance_sq )
2870 *aNearest = nearest;
2872 minDistance_sq = currentDistance_sq;
2876 return minDistance_sq;
2887 for(
unsigned int polygonIdx = 0; polygonIdx <
m_polys.size(); polygonIdx++ )
2890 aNearest ? &nearest :
nullptr );
2892 if( currentDistance_sq < minDistance_sq )
2895 *aNearest = nearest;
2897 minDistance_sq = currentDistance_sq;
2901 return minDistance_sq;
2922 for(
unsigned int idx = 0; idx <
m_polys.size(); idx++ )
2933 for(
size_t idx = 0; idx <
m_polys.size(); idx++ )
2941 unsigned int aDistance,
2942 int aIndex,
int aErrorMax )
2951 if( aDistance == 0 )
2963 for(
int currVertex = 0; currVertex < currContour.PointCount(); currVertex++ )
2966 int x1 = currContour.
CPoint( currVertex ).
x;
2967 int y1 = currContour.CPoint( currVertex ).y;
2976 prevVertex = currVertex == 0 ? currContour.PointCount() - 1 : currVertex - 1;
2979 nextVertex = currVertex == currContour.PointCount() - 1 ? 0 : currVertex + 1;
2982 double xa = currContour.CPoint( prevVertex ).x - x1;
2983 double ya = currContour.CPoint( prevVertex ).y - y1;
2986 double xb = currContour.CPoint( nextVertex ).x - x1;
2987 double yb = currContour.CPoint( nextVertex ).y - y1;
2990 if(
std::abs( xa + xb ) < std::numeric_limits<double>::epsilon()
2991 &&
std::abs( ya + yb ) < std::numeric_limits<double>::epsilon() )
2997 double lena = hypot( xa, ya );
2998 double lenb = hypot( xb, yb );
3015 newContour.
Append( x1 + nx1, y1 + ny1 );
3020 newContour.
Append( x1 + nx2, y1 + ny2 );
3024 double cosine = ( xa * xb + ya * yb ) / ( lena * lenb );
3026 double radius = aDistance;
3027 double denom = sqrt( 2.0 / ( 1 + cosine ) - 1 );
3030 if( std::isinf( denom ) )
3034 if( 0.5 * lena * denom < radius )
3035 radius = 0.5 * lena * denom;
3037 if( 0.5 * lenb * denom < radius )
3038 radius = 0.5 * lenb * denom;
3041 double k = radius / sqrt( .5 * ( 1 - cosine ) );
3042 double lenab = sqrt( ( xa / lena + xb / lenb ) * ( xa / lena + xb / lenb ) +
3043 ( ya / lena + yb / lenb ) * ( ya / lena + yb / lenb ) );
3044 double xc = x1 + k * ( xa / lena + xb / lenb ) / lenab;
3045 double yc = y1 + k * ( ya / lena + yb / lenb ) / lenab;
3048 k = radius / sqrt( 2 / ( 1 + cosine ) - 1 );
3049 double xs = x1 + k * xa / lena - xc;
3050 double ys = y1 + k * ya / lena - yc;
3051 double xe = x1 + k * xb / lenb - xc;
3052 double ye = y1 + k * yb / lenb - yc;
3055 double argument = ( xs * xe + ys * ye ) / ( radius * radius );
3061 else if( argument > 1 )
3064 double arcAngle = acos( argument );
3068 double deltaAngle = arcAngle / segments;
3069 double startAngle = atan2( -ys, xs );
3072 if( xa * yb - ya * xb <= 0 )
3075 double nx = xc + xs;
3076 double ny = yc + ys;
3078 if( std::isnan( nx ) || std::isnan( ny ) )
3087 for(
int j = 0; j < segments; j++ )
3089 nx = xc + cos( startAngle + ( j + 1 ) * deltaAngle ) * radius;
3090 ny = yc - sin( startAngle + ( j + 1 ) * deltaAngle ) * radius;
3092 if( std::isnan( nx ) || std::isnan( ny ) )
3108 newPoly.push_back( newContour );
3117 static_cast<SHAPE&
>(*this) = aOther;
3166 if( w == 0.0 || h == 0.0 )
3169 int n_cells_x, n_cells_y;
3173 n_cells_x = w / aSize;
3174 n_cells_y = floor( h / w * n_cells_x ) + 1;
3178 n_cells_y = h / aSize;
3179 n_cells_x = floor( w / h * n_cells_y ) + 1;
3182 SHAPE_POLY_SET ps1( aPoly ), ps2( aPoly ), maskSetOdd, maskSetEven;
3184 for(
int yy = 0; yy < n_cells_y; yy++ )
3186 for(
int xx = 0; xx < n_cells_x; xx++ )
3190 p.
x = bb.
GetX() + w * xx / n_cells_x;
3191 p.
y = bb.
GetY() + h * yy / n_cells_y;
3195 p2.
x = bb.
GetX() + w * ( xx + 1 ) / n_cells_x;
3196 p2.
y = bb.
GetY() + h * ( yy + 1 ) / n_cells_y;
3204 mask.SetClosed(
true );
3206 if( ( xx ^ yy ) & 1 )
3218 for(
int i = 0; i < ps2.OutlineCount(); i++ )
3219 ps1.AddOutline( ps2.COutline( i ) );
3221 if( ps1.OutlineCount() )
3229 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>* aHintData )
3245 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>& dest,
3246 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>* hintData )
3248 bool triangulationValid =
false;
3252 if( hintData && hintData->size() != (unsigned) polySet.
OutlineCount() )
3257 if( !dest.empty() && dest.back()->GetTriangleCount() == 0 )
3258 dest.erase( dest.end() - 1 );
3260 dest.push_back( std::make_unique<TRIANGULATED_POLYGON>( forOutline ) );
3267 hintData ? hintData->at( index ).get() :
nullptr ) )
3275 else if( pass == 2 )
3285 triangulationValid =
false;
3292 triangulationValid =
true;
3295 return triangulationValid;
3307 for(
int jj = 0; jj <
HoleCount( ii ); ++jj )
3314 else if( aSimplify )
3323 wxLogTrace(
TRIANGULATE_TRACE,
"Failed to triangulate partitioned polygon %d", ii );
3365 hash.
add( outline.size() );
3369 hash.
add( lc.PointCount() );
3371 for(
int i = 0; i < lc.PointCount(); i++ )
3399 std::set<long long> ptHashes;
3403 for(
const VECTOR2I& pt : lc.CPoints() )
3405 const long long ptHash = (
long long) pt.x << 32 | pt.y;
3407 if( ptHashes.count( ptHash ) > 0 )
3410 ptHashes.insert( ptHash );
3429 n += t->GetTriangleCount();
3442 aSubshapes.push_back( &tri );
3453 if( aClearance != 0 )
3503 bool aReverseOrientation,
bool aEvenOdd )
3505 ClipperLib::Clipper clipper;
3506 ClipperLib::PolyTree tree;
3512 ClipperLib::Path lc;
3514 for(
int i = 0; i <
path.PointCount(); i++ )
3516 lc.emplace_back(
path.CPoint( i ).x,
path.CPoint( i ).y );
3519 clipper.AddPath( lc, ClipperLib::ptSubject,
true );
3522 clipper.StrictlySimple(
true );
3523 clipper.Execute( ClipperLib::ctUnion, tree,
3524 aEvenOdd ? ClipperLib::pftEvenOdd : ClipperLib::pftNonZero,
3525 ClipperLib::pftNonZero );
3528 for( ClipperLib::PolyNode* n = tree.GetFirst(); n; n = n->GetNext() )
3534 for(
unsigned int i = 0; i < n->Contour.size(); i++ )
3535 result.
Outline( outl ).
Append( n->Contour[i].X, n->Contour[i].Y );
3537 for(
unsigned int i = 0; i < n->Childs.size(); i++ )
3539 int outh = result.
NewHole( outl );
3540 for(
unsigned int j = 0; j < n->Childs[i]->Contour.size(); j++ )
3542 result.
Hole( outl, outh )
3543 .
Append( n->Childs[i]->Contour[j].X, n->Childs[i]->Contour[j].Y );
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
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.
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 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
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_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.
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 BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
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 inflateLine2(const SHAPE_LINE_CHAIN &aLine, int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy, bool aSimplify=false)
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.
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::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.
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.
void SimplifyOutlines(int aMaxError=0)
Simplifies the lines in the polyset.
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()
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.
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
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
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
@ 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...
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
VECTOR2< int32_t > VECTOR2I