41#include <unordered_set>
46#include <clipper2/clipper.h>
101 m_polys( aOther.m_polys )
129 m_polys( aOther.m_polys )
159 unsigned int contourIdx = 0;
162 int currentGlobalIdx = 0;
164 for( polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
168 for( contourIdx = 0; contourIdx < currentPolygon.size(); contourIdx++ )
171 int totalPoints = currentContour.
PointCount();
173 for( vertexIdx = 0; vertexIdx < totalPoints; vertexIdx++ )
176 if( currentGlobalIdx == aGlobalIdx )
178 aRelativeIndices->
m_polygon = polygonIdx;
179 aRelativeIndices->
m_contour = contourIdx;
180 aRelativeIndices->
m_vertex = vertexIdx;
196 int& aGlobalIdx )
const
198 int selectedVertex = aRelativeIndices.
m_vertex;
199 unsigned int selectedContour = aRelativeIndices.
m_contour;
200 unsigned int selectedPolygon = aRelativeIndices.
m_polygon;
203 if( selectedPolygon <
m_polys.size() && selectedContour <
m_polys[selectedPolygon].size()
204 && selectedVertex <
m_polys[selectedPolygon][selectedContour].PointCount() )
210 for(
unsigned int polygonIdx = 0; polygonIdx < selectedPolygon; polygonIdx++ )
212 currentPolygon =
Polygon( polygonIdx );
214 for(
unsigned int contourIdx = 0; contourIdx < currentPolygon.size(); contourIdx++ )
215 aGlobalIdx += currentPolygon[contourIdx].PointCount();
218 currentPolygon =
Polygon( selectedPolygon );
220 for(
unsigned int contourIdx = 0; contourIdx < selectedContour; contourIdx++ )
221 aGlobalIdx += currentPolygon[contourIdx].PointCount();
223 aGlobalIdx += selectedVertex;
240 poly.push_back( empty_path );
257 m_polys[aOutline].push_back( empty_path );
259 return m_polys.back().size() - 2;
277 assert( aOutline < (
int)
m_polys.size() );
278 assert( idx < (
int)
m_polys[aOutline].size() );
280 m_polys[aOutline][idx].Append( x, y, aAllowDuplication );
282 return m_polys[aOutline][idx].PointCount();
300 assert( aOutline < (
int)
m_polys.size() );
301 assert( idx < (
int)
m_polys[aOutline].size() );
303 m_polys[aOutline][idx].Append( aArc, aAccuracy );
305 return m_polys[aOutline][idx].PointCount();
313 if( aGlobalIndex < 0 )
326 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
346 if( aOutline >= (
int)
m_polys.size() )
349 if( idx >= (
int)
m_polys[aOutline].size() )
352 return m_polys[aOutline][idx].PointCount();
367 for(
int idx = 0; idx <=
HoleCount( ii ); idx++ )
369 full_count +=
m_polys[ii][idx].PointCount();
379 assert( aFirstPolygon >= 0 && aLastPolygon <=
OutlineCount() );
383 for(
int index = aFirstPolygon; index < aLastPolygon; index++ )
402 assert( aOutline < (
int)
m_polys.size() );
403 assert( idx < (
int)
m_polys[aOutline].size() );
405 return m_polys[aOutline][idx].CPoint( aIndex );
415 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
445 else if( index.
m_vertex == lastpoint )
463 *aPrevious = previous;
479 std::vector<SEG> segments;
483 segments.emplace_back( *it );
485 std::sort( segments.begin(), segments.end(), [](
const SEG& a,
const SEG& b )
487 int min_a_x = std::min( a.A.x, a.B.x );
488 int min_b_x = std::min( b.A.x, b.B.x );
490 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 ) );
493 for(
auto it = segments.begin(); it != segments.end(); ++it )
495 SEG& firstSegment = *it;
498 auto innerIterator = it;
499 int max_x = std::max( firstSegment.
A.
x, firstSegment.
B.
x );
500 int max_y = std::max( firstSegment.
A.
y, firstSegment.
B.
y );
503 for( innerIterator++; innerIterator != segments.end(); innerIterator++ )
505 SEG& secondSegment = *innerIterator;
506 int min_x = std::min( secondSegment.
A.
x, secondSegment.
B.
x );
507 int min_y = std::min( secondSegment.
A.
y, secondSegment.
B.
y );
511 if( max_x < min_x || ( max_x == min_x && max_y < min_y ) )
515 bool adjacent = ( index_diff == 1) || (index_diff == ((
int)segments.size() - 1) );
518 if( !adjacent && firstSegment.
Collide( secondSegment, 0 ) )
529 for(
unsigned int polygon = 0; polygon <
m_polys.size(); polygon++ )
545 poly.push_back( aOutline );
560 assert( aOutline < (
int)
m_polys.size() );
564 assert( poly.size() );
566 poly.push_back( aHole );
568 return poly.size() - 2;
588 for(
int j = 0; j <
HoleCount( i ); j++ )
602 for(
size_t i = 0; i < poly.size(); i++ )
614 for(
size_t i = 0; i < poly.size(); i++ )
617 aArcBuffer.push_back( arc );
627 for(
size_t i = 0; i < poly.size(); i++ )
635 std::vector<SHAPE_LINE_CHAIN> contours;
638 contours.insert( contours.end(), poly.begin(), poly.end() );
640 std::map<int, std::set<int>> parentToChildren;
641 std::map<int, std::set<int>> childToParents;
644 contour.GenerateBBoxCache();
646 for(
size_t i = 0; i < contours.size(); i++ )
650 for(
size_t j = 0; j < contours.size(); j++ )
660 parentToChildren[i].emplace( j );
661 childToParents[j].emplace( i );
666 std::set<int> topLevelParents;
668 for(
size_t i = 0; i < contours.size(); i++ )
670 if( childToParents[i].size() == 0 )
672 topLevelParents.emplace( i );
678 std::function<void(
int,
int, std::vector<int> )>
process;
681 [&](
int myId,
int parentOutlineId,
const std::vector<int>&
path )
683 std::set<int> relParents = childToParents[myId];
685 for(
int pathId :
path )
687 int erased = relParents.erase( pathId );
688 wxASSERT( erased > 0 );
691 wxASSERT( relParents.size() == 0 );
695 bool isOutline =
path.size() % 2 == 0;
699 int outlineId = result.
AddOutline( contours[myId] );
700 myOutline = outlineId;
704 wxASSERT( parentOutlineId != -1 );
705 result.
AddHole( contours[myId], parentOutlineId );
708 auto it = parentToChildren.find( myId );
709 if( it != parentToChildren.end() )
711 std::vector<int> thisPath =
path;
712 thisPath.emplace_back( myId );
714 std::set<int> thisPathSet;
715 thisPathSet.insert( thisPath.begin(), thisPath.end() );
717 for(
int childId : it->second )
719 const std::set<int>& childPathSet = childToParents[childId];
721 if( thisPathSet != childPathSet )
724 process( childId, myOutline, thisPath );
729 for(
int topParentId : topLevelParents )
731 std::vector<int>
path;
742 booleanOp( aType, *
this, aOtherShape, aFastMode );
752 wxFAIL_MSG( wxT(
"Boolean ops on curved polygons are not supported. You should call "
753 "ClearArcs() before carrying out the boolean operation." ) );
756 ClipperLib::Clipper c;
760 std::vector<CLIPPER_Z_VALUE> zValues;
761 std::vector<SHAPE_ARC> arcBuffer;
762 std::map<VECTOR2I, CLIPPER_Z_VALUE> newIntersectPoints;
766 for(
size_t i = 0; i < poly.size(); i++ )
768 c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
769 ClipperLib::ptSubject,
true );
775 for(
size_t i = 0; i < poly.size(); i++ )
777 c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
778 ClipperLib::ptClip,
true );
782 ClipperLib::PolyTree solution;
784 ClipperLib::ZFillCallback callback =
785 [&]( ClipperLib::IntPoint & e1bot, ClipperLib::IntPoint & e1top,
786 ClipperLib::IntPoint & e2bot, ClipperLib::IntPoint & e2top,
787 ClipperLib::IntPoint & pt )
790 [&](
const ssize_t& aZvalue,
const ssize_t& aCompareVal = -1 ) -> ssize_t
794 retval = zValues.at( aZvalue ).m_SecondArcIdx;
796 if( retval == -1 || ( aCompareVal > 0 && retval != aCompareVal ) )
797 retval = zValues.at( aZvalue ).m_FirstArcIdx;
803 [&](
const ssize_t& aBottomZ,
const ssize_t aTopZ ) -> ssize_t
805 ssize_t retval = arcIndex( aBottomZ );
809 if( retval != arcIndex( aTopZ, retval ) )
816 ssize_t e1ArcSegmentIndex = arcSegment( e1bot.Z, e1top.Z );
817 ssize_t e2ArcSegmentIndex = arcSegment( e2bot.Z, e2top.Z );
821 if( e1ArcSegmentIndex != -1 )
832 size_t z_value_ptr = zValues.size();
833 zValues.push_back( newZval );
837 newIntersectPoints.insert( {
VECTOR2I( pt.X, pt.Y ), newZval } );
843 c.ZFillFunction( std::move( callback ) );
845 c.Execute( aType, solution, ClipperLib::pftNonZero, ClipperLib::pftNonZero );
863 wxFAIL_MSG( wxT(
"Boolean ops on curved polygons are not supported. You should call "
864 "ClearArcs() before carrying out the boolean operation." ) );
867 Clipper2Lib::Clipper64 c;
869 std::vector<CLIPPER_Z_VALUE> zValues;
870 std::vector<SHAPE_ARC> arcBuffer;
871 std::map<VECTOR2I, CLIPPER_Z_VALUE> newIntersectPoints;
873 Clipper2Lib::Paths64 paths;
874 Clipper2Lib::Paths64 clips;
878 for(
size_t i = 0; i < poly.size(); i++ )
880 paths.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
886 for(
size_t i = 0; i < poly.size(); i++ )
888 clips.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
892 c.AddSubject( paths );
895 Clipper2Lib::PolyTree64 solution;
897 Clipper2Lib::ZCallback64 callback =
898 [&](
const Clipper2Lib::Point64 & e1bot,
const Clipper2Lib::Point64 & e1top,
899 const Clipper2Lib::Point64 & e2bot,
const Clipper2Lib::Point64 & e2top,
900 Clipper2Lib::Point64 & pt )
903 [&](
const ssize_t& aZvalue,
const ssize_t& aCompareVal = -1 ) -> ssize_t
907 retval = zValues.at( aZvalue ).m_SecondArcIdx;
909 if( retval == -1 || ( aCompareVal > 0 && retval != aCompareVal ) )
910 retval = zValues.at( aZvalue ).m_FirstArcIdx;
916 [&](
const ssize_t& aBottomZ,
const ssize_t aTopZ ) -> ssize_t
918 ssize_t retval = arcIndex( aBottomZ );
922 if( retval != arcIndex( aTopZ, retval ) )
929 ssize_t e1ArcSegmentIndex = arcSegment( e1bot.z, e1top.z );
930 ssize_t e2ArcSegmentIndex = arcSegment( e2bot.z, e2top.z );
934 if( e1ArcSegmentIndex != -1 )
945 size_t z_value_ptr = zValues.size();
946 zValues.push_back( newZval );
950 newIntersectPoints.insert( {
VECTOR2I( pt.x, pt.y ), newZval } );
956 c.SetZCallback( std::move( callback ) );
958 c.Execute( aType, Clipper2Lib::FillRule::NonZero, solution );
968 booleanOp( Clipper2Lib::ClipType::Union, b );
970 booleanOp( ClipperLib::ctUnion, b, aFastMode );
977 booleanOp( Clipper2Lib::ClipType::Difference, b );
979 booleanOp( ClipperLib::ctDifference, b, aFastMode );
986 booleanOp( Clipper2Lib::ClipType::Intersection, b );
988 booleanOp( ClipperLib::ctIntersection, b, aFastMode );
995 booleanOp( Clipper2Lib::ClipType::Xor, b );
997 booleanOp( ClipperLib::ctXor, b, aFastMode );
1005 booleanOp( Clipper2Lib::ClipType::Union, a, b );
1007 booleanOp( ClipperLib::ctUnion, a, b, aFastMode );
1015 booleanOp( Clipper2Lib::ClipType::Difference, a, b );
1017 booleanOp( ClipperLib::ctDifference, a, b, aFastMode );
1025 booleanOp( Clipper2Lib::ClipType::Intersection, a, b );
1027 booleanOp( ClipperLib::ctIntersection, a, b, aFastMode );
1035 booleanOp( Clipper2Lib::ClipType::Xor, a, b );
1037 booleanOp( ClipperLib::ctXor, a, b, aFastMode );
1045 Inflate( aFactor, aCornerStrategy, aMaxError );
1052 using namespace ClipperLib;
1056 #define SEG_CNT_MAX 64
1057 static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
1064 JoinType joinType = jtRound;
1065 double miterLimit = 2.0;
1066 JoinType miterFallback = jtSquare;
1068 switch( aCornerStrategy )
1070 case CORNER_STRATEGY::ALLOW_ACUTE_CORNERS:
1073 miterFallback = jtSquare;
1076 case CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS:
1078 miterFallback = jtRound;
1081 case CORNER_STRATEGY::ROUND_ACUTE_CORNERS:
1083 miterFallback = jtSquare;
1086 case CORNER_STRATEGY::CHAMFER_ALL_CORNERS:
1087 joinType = jtSquare;
1088 miterFallback = jtSquare;
1091 case CORNER_STRATEGY::ROUND_ALL_CORNERS:
1093 miterFallback = jtSquare;
1097 std::vector<CLIPPER_Z_VALUE> zValues;
1098 std::vector<SHAPE_ARC> arcBuffer;
1102 for(
size_t i = 0; i < poly.size(); i++ )
1104 c.AddPath( poly[i].convertToClipper( i == 0, zValues, arcBuffer ),
1105 joinType, etClosedPolygon );
1115 if( aCircleSegCount < 6 )
1116 aCircleSegCount = 6;
1120 if( aCircleSegCount >
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
1122 coeff = 1.0 - cos( M_PI / aCircleSegCount );
1125 arc_tolerance_factor[aCircleSegCount] = coeff;
1129 coeff = arc_tolerance_factor[aCircleSegCount];
1132 c.ArcTolerance =
std::abs( aAmount ) * coeff;
1133 c.MiterLimit = miterLimit;
1134 c.MiterFallback = miterFallback;
1135 c.Execute( solution, aAmount );
1144 using namespace Clipper2Lib;
1148 #define SEG_CNT_MAX 64
1149 static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
1156 JoinType joinType = JoinType::Round;
1157 double miterLimit = 2.0;
1159 switch( aCornerStrategy )
1161 case CORNER_STRATEGY::ALLOW_ACUTE_CORNERS:
1162 joinType = JoinType::Miter;
1166 case CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS:
1167 joinType = JoinType::Miter;
1170 case CORNER_STRATEGY::ROUND_ACUTE_CORNERS:
1171 joinType = JoinType::Miter;
1174 case CORNER_STRATEGY::CHAMFER_ALL_CORNERS:
1175 joinType = JoinType::Square;
1178 case CORNER_STRATEGY::ROUND_ALL_CORNERS:
1179 joinType = JoinType::Round;
1183 std::vector<CLIPPER_Z_VALUE> zValues;
1184 std::vector<SHAPE_ARC> arcBuffer;
1190 for(
size_t i = 0; i < poly.size(); i++ )
1191 paths.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
1193 c.AddPaths( paths, joinType, EndType::Polygon );
1200 if( aCircleSegCount < 6 )
1201 aCircleSegCount = 6;
1205 if( aCircleSegCount >
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
1207 coeff = 1.0 - cos( M_PI / aCircleSegCount );
1210 arc_tolerance_factor[aCircleSegCount] = coeff;
1214 coeff = arc_tolerance_factor[aCircleSegCount];
1217 c.ArcTolerance(
std::abs( aAmount ) * coeff );
1218 c.MiterLimit( miterLimit );
1225 c.Execute( aAmount, paths );
1227 Clipper2Lib::SimplifyPaths( paths,
std::abs( aAmount ) * coeff,
true );
1230 c2.PreserveCollinear(
false );
1231 c2.ReverseSolution(
false );
1232 c2.AddSubject( paths );
1233 c2.Execute(ClipType::Union, FillRule::Positive, tree);
1237 c.Execute( aAmount, tree );
1248 using namespace Clipper2Lib;
1252 #define SEG_CNT_MAX 64
1253 static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
1260 JoinType joinType = JoinType::Round;
1261 double miterLimit = 2.0;
1263 switch( aCornerStrategy )
1265 case CORNER_STRATEGY::ALLOW_ACUTE_CORNERS:
1266 joinType = JoinType::Miter;
1270 case CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS:
1271 joinType = JoinType::Miter;
1274 case CORNER_STRATEGY::ROUND_ACUTE_CORNERS:
1275 joinType = JoinType::Miter;
1278 case CORNER_STRATEGY::CHAMFER_ALL_CORNERS:
1279 joinType = JoinType::Square;
1282 case CORNER_STRATEGY::ROUND_ALL_CORNERS:
1283 joinType = JoinType::Round;
1287 std::vector<CLIPPER_Z_VALUE> zValues;
1288 std::vector<SHAPE_ARC> arcBuffer;
1291 c.AddPath(
path, joinType, EndType::Butt );
1297 if( aCircleSegCount < 6 )
1298 aCircleSegCount = 6;
1302 if( aCircleSegCount >
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
1304 coeff = 1.0 - cos( M_PI / aCircleSegCount );
1307 arc_tolerance_factor[aCircleSegCount] = coeff;
1311 coeff = arc_tolerance_factor[aCircleSegCount];
1314 c.ArcTolerance(
std::abs( aAmount ) * coeff );
1315 c.MiterLimit( miterLimit );
1322 c.Execute( aAmount, paths2 );
1324 Clipper2Lib::SimplifyPaths( paths2,
std::abs( aAmount ) * coeff,
false );
1327 c2.PreserveCollinear(
false );
1328 c2.ReverseSolution(
false );
1329 c2.AddSubject( paths2 );
1330 c2.Execute( ClipType::Union, FillRule::Positive, tree );
1334 c.Execute( aAmount, tree );
1348 inflate2( aAmount, segCount, aCornerStrategy, aSimplify );
1350 inflate1( aAmount, segCount, aCornerStrategy );
1359 inflateLine2( aLine, aAmount, segCount, aCornerStrategy, aSimplify );
1364 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1365 const std::vector<SHAPE_ARC>& aArcBuffer )
1369 for( ClipperLib::PolyNode* n = tree->GetFirst(); n; n = n->GetNext() )
1374 paths.reserve( n->Childs.size() + 1 );
1376 paths.emplace_back( n->Contour, aZValueBuffer, aArcBuffer );
1378 for(
unsigned int i = 0; i < n->Childs.size(); i++ )
1379 paths.emplace_back( n->Childs[i]->Contour, aZValueBuffer, aArcBuffer );
1388 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1389 const std::vector<SHAPE_ARC>& aArcBuffer )
1391 if( !aPolyPath->IsHole() )
1394 paths.reserve( aPolyPath->Count() + 1 );
1395 paths.emplace_back( aPolyPath->Polygon(), aZValueBuffer, aArcBuffer );
1397 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& child : *aPolyPath )
1399 paths.emplace_back( child->Polygon(), aZValueBuffer, aArcBuffer );
1401 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& grandchild : *child )
1411 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1412 const std::vector<SHAPE_ARC>& aArcBuffer )
1416 for(
const std::unique_ptr<Clipper2Lib::PolyPath64>& n : tree )
1422 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
1423 const std::vector<SHAPE_ARC>& aArcBuffer )
1428 for(
const Clipper2Lib::Path64& n : aPath )
1430 if( Clipper2Lib::Area( n ) > 0 )
1439 wxCHECK2_MSG( !
path.empty(),
continue, wxT(
"Cannot add a hole before an outline" ) );
1442 path.emplace_back( n, aZValueBuffer, aArcBuffer );
1479 int x = edge.
m_p1.
x;
1480 int y = edge.
m_p1.
y;
1481 int min_dist = std::numeric_limits<int>::max();
1500 x_intersect = std::max( e.
m_p1.
x, e.
m_p2.
x );
1508 int dist = ( x - x_intersect );
1510 if( dist >= 0 && dist < min_dist )
1513 x_nearest = x_intersect;
1526 edges[hole2outline_index] =
1529 edges[split_index] =
1534 e_nearest->
m_next = outline2hole_index;
1537 for( ; last->
m_next != edgeIndex; last = &edges[last->
m_next] )
1539 last->
m_next = hole2outline_index;
1549 bool outline =
true;
1551 if( paths.size() == 1 )
1554 size_t total_point_count = 0;
1558 total_point_count +=
path.PointCount();
1561 if( total_point_count > (
size_t) std::numeric_limits<FractureEdge::Index>::max() )
1563 wxLogWarning( wxT(
"Polygon has more points than int limit" ) );
1570 edges.reserve( total_point_count + paths.size() * 3 );
1576 int path_or_provoking_index;
1581 std::vector<PathInfo> sorted_paths;
1582 const int paths_count =
static_cast<int>( paths.size() );
1583 sorted_paths.reserve( paths_count );
1585 for(
int path_index = 0; path_index < paths_count; path_index++ )
1588 const std::vector<VECTOR2I>& points =
path.CPoints();
1589 const int point_count =
static_cast<int>( points.size() );
1590 int x_min = std::numeric_limits<int>::max();
1591 int y_min = std::numeric_limits<int>::max();
1594 for(
int point_index = 0; point_index < point_count; point_index++ )
1596 const VECTOR2I& point = points[point_index];
1597 if( point.
x < x_min )
1600 leftmost = point_index;
1602 if( point.
y < y_min )
1606 sorted_paths.emplace_back( PathInfo{ path_index, leftmost, x_min, y_min } );
1609 std::sort( sorted_paths.begin() + 1, sorted_paths.end(),
1610 [](
const PathInfo& a,
const PathInfo& b )
1613 return a.y_or_bridge < b.y_or_bridge;
1619 for( PathInfo& path_info : sorted_paths )
1622 const std::vector<VECTOR2I>& points =
path.CPoints();
1623 const size_t point_count = points.size();
1628 for(
size_t i = 0; i < point_count - 1; i++ )
1630 edges.emplace_back( points[i], points[i + 1], edge_index + 1 );
1635 edges.emplace_back( points[point_count - 1], points[0], provoking_edge );
1642 path_info.path_or_provoking_index = provoking_edge;
1643 path_info.y_or_bridge = edge_index;
1647 edges.resize( edge_index );
1653 for(
auto it = sorted_paths.begin() + 1; it != sorted_paths.end(); it++ )
1655 auto edge =
processHole( edges, it->path_or_provoking_index,
1656 it->path_or_provoking_index + it->leftmost, it->y_or_bridge );
1661 wxLogWarning( wxT(
"Broken polygon, dropping path" ) );
1709 int x = edge->
m_p1.
x;
1710 int y = edge->
m_p1.
y;
1711 int min_dist = std::numeric_limits<int>::max();
1718 if( !e->matches( y ) )
1723 if( e->m_p1.y == e->m_p2.y )
1725 x_intersect = std::max( e->m_p1.x, e->m_p2.x );
1729 x_intersect = e->m_p1.x
1730 +
rescale( e->m_p2.x - e->m_p1.x, y - e->m_p1.y, e->m_p2.y - e->m_p1.y );
1733 int dist = ( x - x_intersect );
1735 if( dist >= 0 && dist < min_dist && e->m_connected )
1738 x_nearest = x_intersect;
1754 edges.push_back( split_2 );
1755 edges.push_back( lead1 );
1756 edges.push_back( lead2 );
1761 e_nearest->
m_next = lead1;
1766 for( last = edge; last->
m_next != edge; last = last->
m_next )
1792 if( paths.size() == 1 )
1795 int num_unconnected = 0;
1799 const std::vector<VECTOR2I>& points =
path.CPoints();
1800 int pointCount = points.size();
1804 int x_min = std::numeric_limits<int>::max();
1806 for(
int i = 0; i < pointCount; i++ )
1808 if( points[i].x < x_min )
1809 x_min = points[i].x;
1814 points[i + 1 == pointCount ? 0 : i + 1] );
1825 if( i == pointCount - 1 )
1829 edges.push_back( fe );
1833 if( fe->
m_p1.
x == x_min )
1834 border_edges.push_back( fe );
1845 while( num_unconnected > 0 )
1847 int x_min = std::numeric_limits<int>::max();
1848 auto it = border_edges.begin();
1853 for( ; it != border_edges.end(); ++it )
1856 int xt = border_edge->
m_p1.
x;
1858 if( ( xt <= x_min ) && !border_edge->
m_connected )
1861 smallestX = border_edge;
1865 int num_processed =
processEdge( edges, smallestX );
1868 if( !num_processed )
1870 wxLogWarning( wxT(
"Broken polygon, dropping path" ) );
1878 num_unconnected -= num_processed;
1896 paths.push_back( std::move( newPath ) );
1919 assert( aPoly.size() == 1 );
1925 bool m_duplicate =
false;
1932 bool compareSegs(
const SEG& s1,
const SEG& s2 )
const
1934 return (s1.
A == s2.
B && s1.
B == s2.
A);
1939 return compareSegs( m_poly->
CSegment( m_index ),
1940 aOther.m_poly->CSegment( aOther.m_index ) );
1945 return !compareSegs( m_poly->
CSegment( m_index ),
1946 aOther.m_poly->CSegment( aOther.m_index ) );
1951 std::size_t operator()(
const EDGE& aEdge )
const
1953 const SEG& a = aEdge.m_poly->CSegment( aEdge.m_index );
1954 std::size_t seed = 0xa82de1c0;
1961 struct EDGE_LIST_ENTRY
1964 EDGE_LIST_ENTRY*
next;
1967 std::unordered_set<EDGE, EDGE::HASH> uniqueEdges;
1972 auto edgeList = std::make_unique<EDGE_LIST_ENTRY[]>( lc.
SegmentCount() );
1976 edgeList[i].index = i;
1977 edgeList[i].next = &edgeList[ (i != lc.
SegmentCount() - 1) ? i + 1 : 0 ];
1980 std::unordered_set<EDGE_LIST_ENTRY*> queue;
1985 uniqueEdges.insert( e );
1991 auto it = uniqueEdges.find( e );
1993 if( it != uniqueEdges.end() && it->m_index != i )
1995 int e1 = it->m_index;
1999 std::swap( e1, e2 );
2001 int e1_prev = e1 - 1;
2006 int e2_prev = e2 - 1;
2011 int e1_next = e1 + 1;
2016 int e2_next = e2 + 1;
2021 edgeList[e1_prev].next = &edgeList[ e2_next ];
2022 edgeList[e2_prev].next = &edgeList[ e1_next ];
2023 edgeList[i].next =
nullptr;
2024 edgeList[it->m_index].next =
nullptr;
2030 if( edgeList[i].
next )
2031 queue.insert( &edgeList[i] );
2034 auto edgeBuf = std::make_unique<EDGE_LIST_ENTRY* []>( lc.
SegmentCount() );
2040 double max_poly = 0.0;
2042 while( queue.size() )
2044 EDGE_LIST_ENTRY* e_first = *queue.begin();
2045 EDGE_LIST_ENTRY* e = e_first;
2052 }
while( e && e != e_first );
2056 for(
int i = 0; i < cnt; i++ )
2060 queue.erase( edgeBuf[i] );
2065 double area = std::fabs( outl.
Area() );
2067 if( area > max_poly )
2073 result.push_back( outl );
2078 std::swap( result[0], result[outline] );
2090 if( paths.size() > 1 )
2125 path.Simplify( aMaxError );
2143 while( outline.size() > 1 )
2168 std::stringstream ss;
2170 ss <<
"SHAPE_LINE_CHAIN poly; \n";
2172 for(
unsigned i = 0; i <
m_polys.size(); i++ )
2174 for(
unsigned j = 0; j <
m_polys[i].size(); j++ )
2177 ss <<
"{ auto tmp = " <<
m_polys[i][j].Format() <<
";\n";
2183 ss <<
" poly.AddOutline(tmp); } \n";
2187 ss <<
" poly.AddHole(tmp); } \n";
2203 if( tmp !=
"polyset" )
2208 int n_polys = atoi( tmp.c_str() );
2213 for(
int i = 0; i < n_polys; i++ )
2223 int n_outlines = atoi( tmp.c_str() );
2225 if( n_outlines < 0 )
2228 for(
int j = 0; j < n_outlines; j++ )
2235 int n_vertices = atoi( tmp.c_str() );
2237 for(
int v = 0; v < n_vertices; v++ )
2241 aStream >> tmp; p.
x = atoi( tmp.c_str() );
2242 aStream >> tmp; p.
y = atoi( tmp.c_str() );
2246 paths.push_back( outline );
2260 for(
unsigned i = 0; i <
m_polys.size(); i++ )
2277 for(
unsigned i = 0; i <
m_polys.size(); i++ )
2280 bb = *
m_polys[i][0].GetCachedBBox();
2297 if( lineChain.PointOnEdge( aP, aAccuracy ) )
2312 if( dist_sq == 0 || dist_sq <
SEG::Square( aClearance ) )
2315 *aLocation = nearest;
2318 *aActual = sqrt( dist_sq );
2336 if( dist_sq == 0 || dist_sq <
SEG::Square( aClearance ) )
2339 *aLocation = nearest;
2342 *aActual = sqrt( dist_sq );
2359 int extra = segment->
GetWidth() / 2;
2361 if(
Collide( segment->
GetSeg(), aClearance + extra, aActual, aLocation ) )
2364 *aActual = std::max( 0, *aActual - extra );
2377 if(
Collide( circle->
GetCenter(), aClearance + extra, aActual, aLocation ) )
2380 *aActual = std::max( 0, *aActual - extra );
2390 int actual = INT_MAX;
2397 if( aActual || aLocation )
2402 if( aShape->
Collide( &tri, aClearance, &triActual, &triLocation ) )
2404 if( triActual < actual )
2407 location = triLocation;
2413 if( aShape->
Collide( &tri, aClearance ) )
2419 if( actual < INT_MAX )
2422 *aActual = std::max( 0, actual );
2425 *aLocation = location;
2443 if( aPolygonIdx < 0 )
2444 aPolygonIdx +=
m_polys.size();
2446 m_polys[aPolygonIdx].erase(
m_polys[aPolygonIdx].begin() + aContourIdx );
2466 std::vector<VERTEX_INDEX> indices_to_remove;
2471 segmentStart = *iterator;
2477 segmentEnd = contourStart;
2485 contourStart = *iterator;
2493 wxCHECK_MSG( iterator, removed, wxT(
"Invalid polygon. Reached end without noticing. Please report this error" ) );
2495 segmentEnd = *iterator;
2499 if( segmentStart == segmentEnd )
2501 indices_to_remove.push_back( indexStart );
2508 for(
auto it = indices_to_remove.rbegin(); it != indices_to_remove.rend(); ++it )
2531 if( triangleSet->GetSourceOutlineIndex() == aIdx )
2533 else if( triangleSet->GetSourceOutlineIndex() > aIdx )
2534 triangleSet->SetSourceOutlineIndex( triangleSet->GetSourceOutlineIndex() - 1 );
2561 Append( aP.
x, aP.
y, aOutline, aHole );
2567 int aClearance )
const
2570 bool collision =
false;
2580 delta = *iterator - aPoint;
2583 distance_squared =
delta.SquaredEuclideanNorm();
2586 if( distance_squared <= clearance_squared )
2588 if( !aClosestVertex )
2594 clearance_squared = distance_squared;
2597 *aClosestVertex = iterator.GetIndex();
2607 int aClearance )
const
2610 bool collision =
false;
2615 const SEG currentSegment = *iterator;
2619 if( distance_squared <= clearance_squared )
2621 if( !aClosestVertex )
2627 clearance_squared = distance_squared;
2630 *aClosestVertex = iterator.GetIndex();
2640 for(
int polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
2644 for(
int holeIdx = 0; holeIdx <
HoleCount( polygonIdx ); holeIdx++ )
2651 bool aUseBBoxCaches )
const
2657 if( aSubpolyIndex >= 0 )
2658 return containsSingle( aP, aSubpolyIndex, aAccuracy, aUseBBoxCaches );
2661 for(
int polygonIdx = 0; polygonIdx <
OutlineCount(); polygonIdx++ )
2663 if(
containsSingle( aP, polygonIdx, aAccuracy, aUseBBoxCaches ) )
2679 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
2696 throw( std::out_of_range(
"aGlobalIndex-th vertex does not exist" ) );
2707 bool aUseBBoxCaches )
const
2713 for(
int holeIdx = 0; holeIdx <
HoleCount( aSubpolyIndex ); holeIdx++ )
2735 path.Move( aVector );
2739 tri->Move( aVector );
2751 path.Mirror( aRef, aFlipDirection );
2764 path.Rotate( aAngle, aCenter );
2780 c +=
path.PointCount();
2817 SEG::ecoord minDistance = (*iterator).SquaredDistance( aPoint );
2819 for( iterator++; iterator && minDistance > 0; iterator++ )
2821 SEG::ecoord currentDistance = (*iterator).SquaredDistance( aPoint );
2823 if( currentDistance < minDistance )
2826 *aNearest = (*iterator).NearestPoint( aPoint );
2828 minDistance = currentDistance;
2844 *aNearest = ( aSegment.
A + aSegment.
B ) / 2;
2850 SEG::ecoord minDistance = (*iterator).SquaredDistance( aSegment );
2852 if( aNearest && minDistance == 0 )
2853 *aNearest = ( *iterator ).NearestPoint( aSegment );
2855 for( iterator++; iterator && minDistance > 0; iterator++ )
2859 if( currentDistance < minDistance )
2862 *aNearest = (*iterator).NearestPoint( aSegment );
2864 minDistance = currentDistance;
2869 return minDistance < 0 ? 0 : minDistance;
2876 wxASSERT_MSG( !aOutlineOnly, wxT(
"Warning: SHAPE_POLY_SET::SquaredDistance does not yet "
2877 "support aOutlineOnly==true" ) );
2884 for(
unsigned int polygonIdx = 0; polygonIdx <
m_polys.size(); polygonIdx++ )
2887 aNearest ? &nearest :
nullptr );
2889 if( currentDistance_sq < minDistance_sq )
2892 *aNearest = nearest;
2894 minDistance_sq = currentDistance_sq;
2898 return minDistance_sq;
2909 for(
unsigned int polygonIdx = 0; polygonIdx <
m_polys.size(); polygonIdx++ )
2912 aNearest ? &nearest :
nullptr );
2914 if( currentDistance_sq < minDistance_sq )
2917 *aNearest = nearest;
2919 minDistance_sq = currentDistance_sq;
2923 return minDistance_sq;
2944 for(
unsigned int idx = 0; idx <
m_polys.size(); idx++ )
2955 for(
size_t idx = 0; idx <
m_polys.size(); idx++ )
2963 unsigned int aDistance,
2964 int aIndex,
int aErrorMax )
2973 if( aDistance == 0 )
2985 for(
int currVertex = 0; currVertex < currContour.PointCount(); currVertex++ )
2988 int x1 = currContour.
CPoint( currVertex ).
x;
2989 int y1 = currContour.CPoint( currVertex ).y;
2998 prevVertex = currVertex == 0 ? currContour.PointCount() - 1 : currVertex - 1;
3001 nextVertex = currVertex == currContour.PointCount() - 1 ? 0 : currVertex + 1;
3004 double xa = currContour.CPoint( prevVertex ).x - x1;
3005 double ya = currContour.CPoint( prevVertex ).y - y1;
3008 double xb = currContour.CPoint( nextVertex ).x - x1;
3009 double yb = currContour.CPoint( nextVertex ).y - y1;
3012 if(
std::abs( xa + xb ) < std::numeric_limits<double>::epsilon()
3013 &&
std::abs( ya + yb ) < std::numeric_limits<double>::epsilon() )
3019 double lena = hypot( xa, ya );
3020 double lenb = hypot( xb, yb );
3037 newContour.
Append( x1 + nx1, y1 + ny1 );
3042 newContour.
Append( x1 + nx2, y1 + ny2 );
3046 double cosine = ( xa * xb + ya * yb ) / ( lena * lenb );
3048 double radius = aDistance;
3049 double denom = sqrt( 2.0 / ( 1 + cosine ) - 1 );
3052 if( std::isinf( denom ) )
3056 if( 0.5 * lena * denom < radius )
3057 radius = 0.5 * lena * denom;
3059 if( 0.5 * lenb * denom < radius )
3060 radius = 0.5 * lenb * denom;
3063 double k = radius / sqrt( .5 * ( 1 - cosine ) );
3064 double lenab = sqrt( ( xa / lena + xb / lenb ) * ( xa / lena + xb / lenb ) +
3065 ( ya / lena + yb / lenb ) * ( ya / lena + yb / lenb ) );
3066 double xc = x1 + k * ( xa / lena + xb / lenb ) / lenab;
3067 double yc = y1 + k * ( ya / lena + yb / lenb ) / lenab;
3070 k = radius / sqrt( 2 / ( 1 + cosine ) - 1 );
3071 double xs = x1 + k * xa / lena - xc;
3072 double ys = y1 + k * ya / lena - yc;
3073 double xe = x1 + k * xb / lenb - xc;
3074 double ye = y1 + k * yb / lenb - yc;
3077 double argument = ( xs * xe + ys * ye ) / ( radius * radius );
3083 else if( argument > 1 )
3086 double arcAngle = acos( argument );
3090 double deltaAngle = arcAngle / segments;
3091 double startAngle = atan2( -ys, xs );
3094 if( xa * yb - ya * xb <= 0 )
3097 double nx = xc + xs;
3098 double ny = yc + ys;
3100 if( std::isnan( nx ) || std::isnan( ny ) )
3109 for(
int j = 0; j < segments; j++ )
3111 nx = xc + cos( startAngle + ( j + 1 ) * deltaAngle ) * radius;
3112 ny = yc - sin( startAngle + ( j + 1 ) * deltaAngle ) * radius;
3114 if( std::isnan( nx ) || std::isnan( ny ) )
3130 newPoly.push_back( newContour );
3139 static_cast<SHAPE&
>(*this) = aOther;
3188 if( w == 0.0 || h == 0.0 )
3191 int n_cells_x, n_cells_y;
3195 n_cells_x = w / aSize;
3196 n_cells_y = floor( h / w * n_cells_x ) + 1;
3200 n_cells_y = h / aSize;
3201 n_cells_x = floor( w / h * n_cells_y ) + 1;
3204 SHAPE_POLY_SET ps1( aPoly ), ps2( aPoly ), maskSetOdd, maskSetEven;
3206 for(
int yy = 0; yy < n_cells_y; yy++ )
3208 for(
int xx = 0; xx < n_cells_x; xx++ )
3212 p.
x = bb.
GetX() + w * xx / n_cells_x;
3213 p.
y = bb.
GetY() + h * yy / n_cells_y;
3217 p2.
x = bb.
GetX() + w * ( xx + 1 ) / n_cells_x;
3218 p2.
y = bb.
GetY() + h * ( yy + 1 ) / n_cells_y;
3226 mask.SetClosed(
true );
3228 if( ( xx ^ yy ) & 1 )
3240 for(
int i = 0; i < ps2.OutlineCount(); i++ )
3241 ps1.AddOutline( ps2.COutline( i ) );
3243 if( ps1.OutlineCount() )
3251 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>* aHintData )
3267 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>& dest,
3268 std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>* hintData )
3270 bool triangulationValid =
false;
3274 if( hintData && hintData->size() != (unsigned) polySet.
OutlineCount() )
3279 if( !dest.empty() && dest.back()->GetTriangleCount() == 0 )
3280 dest.erase( dest.end() - 1 );
3282 dest.push_back( std::make_unique<TRIANGULATED_POLYGON>( forOutline ) );
3289 hintData ? hintData->at( index ).get() :
nullptr ) )
3297 else if( pass == 2 )
3312 triangulationValid =
false;
3319 triangulationValid =
true;
3322 return triangulationValid;
3334 for(
int jj = 0; jj <
HoleCount( ii ); ++jj )
3341 else if( aSimplify )
3350 wxLogTrace(
TRIANGULATE_TRACE,
"Failed to triangulate partitioned polygon %d", ii );
3392 hash.
add( outline.size() );
3396 hash.
add( lc.PointCount() );
3398 for(
int i = 0; i < lc.PointCount(); i++ )
3426 std::set<long long> ptHashes;
3430 for(
const VECTOR2I& pt : lc.CPoints() )
3432 const long long ptHash = (
long long) pt.x << 32 | pt.y;
3434 if( ptHashes.count( ptHash ) > 0 )
3437 ptHashes.insert( ptHash );
3456 n += t->GetTriangleCount();
3469 aSubshapes.push_back( &tri );
3480 if( aClearance != 0 )
3530 bool aReverseOrientation,
bool aEvenOdd )
3532 ClipperLib::Clipper clipper;
3533 ClipperLib::PolyTree tree;
3539 ClipperLib::Path lc;
3541 for(
int i = 0; i <
path.PointCount(); i++ )
3543 lc.emplace_back(
path.CPoint( i ).x,
path.CPoint( i ).y );
3546 clipper.AddPath( lc, ClipperLib::ptSubject,
true );
3549 clipper.StrictlySimple(
true );
3550 clipper.Execute( ClipperLib::ctUnion, tree,
3551 aEvenOdd ? ClipperLib::pftEvenOdd : ClipperLib::pftNonZero,
3552 ClipperLib::pftNonZero );
3555 for( ClipperLib::PolyNode* n = tree.GetFirst(); n; n = n->GetNext() )
3561 for(
unsigned int i = 0; i < n->Contour.size(); i++ )
3562 result.
Outline( outl ).
Append( n->Contour[i].X, n->Contour[i].Y );
3564 for(
unsigned int i = 0; i < n->Childs.size(); i++ )
3566 int outh = result.
NewHole( outl );
3567 for(
unsigned int j = 0; j < n->Childs[i]->Contour.size(); j++ )
3569 result.
Hole( outl, outh )
3570 .
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)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
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
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)
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