41#include <unordered_set> 
   46#include <clipper2/clipper.h> 
   53#include <geometry/rtree.h> 
   66#if defined( __MINGW32__ ) 
   67    #define TRIANGULATESIMPLIFICATIONLEVEL 50 
   68    #define ENABLECACHEFRIENDLYFRACTURE true 
   70    #define TRIANGULATESIMPLIFICATIONLEVEL ADVANCED_CFG::GetCfg().m_TriangulateSimplificationLevel 
   71    #define ENABLECACHEFRIENDLYFRACTURE ADVANCED_CFG::GetCfg().m_EnableCacheFriendlyFracture 
  112        m_triangulatedPolys.reserve( aOther.TriangulatedPolyCount() );
 
  114        for( unsigned i = 0; i < aOther.TriangulatedPolyCount(); i++ )
 
  116            const TRIANGULATED_POLYGON* poly = aOther.TriangulatedPolygon( i );
 
  117            m_triangulatedPolys.push_back( std::make_unique<TRIANGULATED_POLYGON>( *poly ) );
 
  128        m_triangulationValid = 
false;
 
 
  164    unsigned int contourIdx = 0;
 
  167    int currentGlobalIdx = 0;
 
  169    for( polygonIdx = 0; polygonIdx < 
OutlineCount(); polygonIdx++ )
 
  173        for( contourIdx = 0; contourIdx < currentPolygon.size(); contourIdx++ )
 
  176            int totalPoints = currentContour.
PointCount();
 
  178            for( vertexIdx = 0; vertexIdx < totalPoints; vertexIdx++ )
 
  181                if( currentGlobalIdx == aGlobalIdx )
 
  183                    aRelativeIndices->
m_polygon = polygonIdx;
 
  184                    aRelativeIndices->
m_contour = contourIdx;
 
  185                    aRelativeIndices->
m_vertex  = vertexIdx;
 
 
  201                                     int& aGlobalIdx )
 const 
  203    int          selectedVertex = aRelativeIndices.
m_vertex;
 
  204    unsigned int selectedContour = aRelativeIndices.
m_contour;
 
  205    unsigned int selectedPolygon = aRelativeIndices.
m_polygon;
 
  208    if( selectedPolygon < 
m_polys.size() && selectedContour < 
m_polys[selectedPolygon].size()
 
  209        && selectedVertex < 
m_polys[selectedPolygon][selectedContour].PointCount() )
 
  215        for( 
unsigned int polygonIdx = 0; polygonIdx < selectedPolygon; polygonIdx++ )
 
  217            currentPolygon = 
Polygon( polygonIdx );
 
  219            for( 
unsigned int contourIdx = 0; contourIdx < currentPolygon.size(); contourIdx++ )
 
  220                aGlobalIdx += currentPolygon[contourIdx].PointCount();
 
  223        currentPolygon = 
Polygon( selectedPolygon );
 
  225        for( 
unsigned int contourIdx = 0; contourIdx < selectedContour; contourIdx++ )
 
  226            aGlobalIdx += currentPolygon[contourIdx].PointCount();
 
  228        aGlobalIdx += selectedVertex;
 
 
  245    poly.push_back( empty_path );
 
  246    m_polys.push_back( std::move( poly ) );
 
 
  262    m_polys[aOutline].push_back( empty_path );
 
  264    return m_polys.back().size() - 2;
 
 
  282    assert( aOutline < (
int) 
m_polys.size() );
 
  283    assert( idx < (
int) 
m_polys[aOutline].size() );
 
  285    m_polys[aOutline][idx].Append( x, y, aAllowDuplication );
 
  287    return m_polys[aOutline][idx].PointCount();
 
 
  292                            std::optional<int> aMaxError )
 
  306    assert( aOutline < (
int) 
m_polys.size() );
 
  307    assert( idx < (
int) 
m_polys[aOutline].size() );
 
  309    if( aMaxError.has_value() )
 
  310        m_polys[aOutline][idx].Append( aArc, aMaxError.value() );
 
  312        m_polys[aOutline][idx].Append( aArc );
 
  314    return m_polys[aOutline][idx].PointCount();
 
 
  322    if( aGlobalIndex < 0 )
 
  335            throw( std::out_of_range( 
"aGlobalIndex-th vertex does not exist" ) );
 
 
  355    if( aOutline >= (
int) 
m_polys.size() ) 
 
  358    if( idx >= (
int) 
m_polys[aOutline].size() ) 
 
  361    return m_polys[aOutline][idx].PointCount();
 
 
  376        for( 
int idx = 0; idx <= 
HoleCount( ii ); idx++ )
 
  378            full_count += 
m_polys[ii][idx].PointCount();
 
 
  388    assert( aFirstPolygon >= 0 && aLastPolygon <= 
OutlineCount() );
 
  392    for( 
int index = aFirstPolygon; index < aLastPolygon; index++ )
 
 
  411    assert( aOutline < (
int) 
m_polys.size() );
 
  412    assert( idx < (
int) 
m_polys[aOutline].size() );
 
  414    return m_polys[aOutline][idx].CPoint( aIndex );
 
 
  424        throw( std::out_of_range( 
"aGlobalIndex-th vertex does not exist" ) );
 
 
  454    else if( index.
m_vertex == lastpoint )
 
  472        *aPrevious = previous;
 
 
  488    std::vector<SEG> segments;
 
  492        segments.emplace_back( *it );
 
  494    std::sort( segments.begin(), segments.end(), []( 
const SEG& a, 
const SEG& b )
 
  496                int min_a_x = std::min( a.A.x, a.B.x );
 
  497                int min_b_x = std::min( b.A.x, b.B.x );
 
  499                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 ) );
 
  502    for( 
auto it = segments.begin(); it != segments.end(); ++it )
 
  504        SEG& firstSegment = *it;
 
  507        auto innerIterator = it;
 
  508        int max_x = std::max( firstSegment.
A.
x, firstSegment.
B.
x );
 
  509        int max_y = std::max( firstSegment.
A.
y, firstSegment.
B.
y );
 
  512        for( innerIterator++; innerIterator != segments.end(); innerIterator++ )
 
  514            SEG& secondSegment = *innerIterator;
 
  515            int min_x = std::min( secondSegment.
A.
x, secondSegment.
B.
x );
 
  516            int min_y = std::min( secondSegment.
A.
y, secondSegment.
B.
y );
 
  520            if( max_x < min_x || ( max_x == min_x && max_y < min_y ) )
 
  524            bool adjacent = ( index_diff == 1) || (index_diff == ((
int)segments.size() - 1) );
 
  527            if( !adjacent && firstSegment.
Collide( secondSegment, 0 ) )
 
 
  538    for( 
unsigned int polygon = 0; polygon < 
m_polys.size(); polygon++ )
 
 
  552    poly.push_back( aOutline );
 
  557    wxCHECK2_MSG( aOutline.
IsClosed(), poly.back().SetClosed( 
true ),
 
  558                  "Warning: non-closed outline added to SHAPE_POLY_SET" );
 
  560    m_polys.push_back( std::move( poly ) );
 
  562    return (
int) 
m_polys.size() - 1;
 
 
  571        aOutline += (int) 
m_polys.size();
 
  573    assert( aOutline < (
int)
m_polys.size() );
 
  577    assert( poly.size() );
 
  579    poly.push_back( aHole );
 
  581    return (
int) poly.size() - 2;
 
 
  601        for( 
int j = 0; j < 
HoleCount( i ); j++ )
 
 
  615        for( 
size_t i = 0; i < poly.size(); i++ )
 
 
  627        for( 
size_t i = 0; i < poly.size(); i++ )
 
  630                aArcBuffer.push_back( arc );
 
 
  640        for( 
size_t i = 0; i < poly.size(); i++ )
 
 
  648    std::vector<SHAPE_LINE_CHAIN> contours;
 
  651        contours.insert( contours.end(), poly.begin(), poly.end() );
 
  653    std::map<int, std::set<int>> parentToChildren;
 
  654    std::map<int, std::set<int>> childToParents;
 
  657        contour.GenerateBBoxCache();
 
  659    for( 
size_t i = 0; i < contours.size(); i++ )
 
  663        for( 
size_t j = 0; j < contours.size(); j++ )
 
  673                parentToChildren[i].emplace( j );
 
  674                childToParents[j].emplace( i );
 
  679    std::set<int> topLevelParents;
 
  681    for( 
size_t i = 0; i < contours.size(); i++ )
 
  683        if( childToParents[i].size() == 0 )
 
  685            topLevelParents.emplace( i );
 
  691    std::function<void( 
int, 
int, std::vector<int> )> 
process;
 
  694            [&]( 
int myId, 
int parentOutlineId, 
const std::vector<int>& 
path )
 
  696                std::set<int> relParents = childToParents[myId];
 
  698                for( 
int pathId : 
path )
 
  700                    int erased = relParents.erase( pathId );
 
  701                    wxASSERT( erased > 0 );
 
  704                wxASSERT( relParents.size() == 0 );
 
  708                bool isOutline = 
path.size() % 2 == 0;
 
  712                    int outlineId = 
result.AddOutline( contours[myId] );
 
  713                    myOutline = outlineId;
 
  717                    wxASSERT( parentOutlineId != -1 );
 
  718                    result.AddHole( contours[myId], parentOutlineId );
 
  721                auto it = parentToChildren.find( myId );
 
  722                if( it != parentToChildren.end() )
 
  724                    std::vector<int> thisPath = 
path;
 
  725                    thisPath.emplace_back( myId );
 
  727                    std::set<int> thisPathSet;
 
  728                    thisPathSet.insert( thisPath.begin(), thisPath.end() );
 
  730                    for( 
int childId : it->second )
 
  732                        const std::set<int>& childPathSet = childToParents[childId];
 
  734                        if( thisPathSet != childPathSet )
 
  737                        process( childId, myOutline, thisPath );
 
  742    for( 
int topParentId : topLevelParents )
 
  744        std::vector<int> 
path;
 
  748    *
this = std::move( 
result );
 
 
  764        wxFAIL_MSG( wxT( 
"Boolean ops on curved polygons are not supported. You should call " 
  765                         "ClearArcs() before carrying out the boolean operation." ) );
 
  768    Clipper2Lib::Clipper64 c;
 
  770    std::vector<CLIPPER_Z_VALUE> zValues;
 
  771    std::vector<SHAPE_ARC> arcBuffer;
 
  772    std::map<VECTOR2I, CLIPPER_Z_VALUE> newIntersectPoints;
 
  774    Clipper2Lib::Paths64 paths;
 
  775    Clipper2Lib::Paths64 clips;
 
  779        for( 
size_t i = 0; i < poly.size(); i++ )
 
  781            paths.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
 
  787        for( 
size_t i = 0; i < poly.size(); i++ )
 
  789            clips.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
 
  793    c.AddSubject( paths );
 
  796    Clipper2Lib::PolyTree64 solution;
 
  798    Clipper2Lib::ZCallback64 callback =
 
  799            [&]( 
const Clipper2Lib::Point64 & e1bot, 
const Clipper2Lib::Point64 & e1top,
 
  800                 const Clipper2Lib::Point64 & e2bot, 
const Clipper2Lib::Point64 & e2top,
 
  801                 Clipper2Lib::Point64 & pt )
 
  804                    [&]( 
const ssize_t& aZvalue, 
const ssize_t& aCompareVal = -1 ) -> ssize_t
 
  808                        retval = zValues.at( aZvalue ).m_SecondArcIdx;
 
  810                        if( retval == -1 || ( aCompareVal > 0 && retval != aCompareVal ) )
 
  811                            retval = zValues.at( aZvalue ).m_FirstArcIdx;
 
  817                    [&]( 
const ssize_t& aBottomZ, 
const ssize_t aTopZ ) -> ssize_t
 
  819                        ssize_t retval = arcIndex( aBottomZ );
 
  823                            if( retval != arcIndex( aTopZ, retval ) )
 
  830                ssize_t e1ArcSegmentIndex = arcSegment( e1bot.z, e1top.z );
 
  831                ssize_t e2ArcSegmentIndex = arcSegment( e2bot.z, e2top.z );
 
  835                if( e1ArcSegmentIndex != -1 )
 
  846                size_t z_value_ptr = zValues.size();
 
  847                zValues.push_back( newZval );
 
  851                    newIntersectPoints.insert( { 
VECTOR2I( pt.x, pt.y ), newZval } );
 
  857    c.SetZCallback( std::move( callback ) ); 
 
  859    c.Execute( aType, Clipper2Lib::FillRule::NonZero, solution );
 
 
  868    booleanOp( Clipper2Lib::ClipType::Union, b );
 
 
  874    booleanOp( Clipper2Lib::ClipType::Difference, b );
 
 
  880    booleanOp( Clipper2Lib::ClipType::Intersection, b );
 
 
  886    booleanOp( Clipper2Lib::ClipType::Xor, b );
 
 
  892    booleanOp( Clipper2Lib::ClipType::Union, a, b );
 
 
  898    booleanOp( Clipper2Lib::ClipType::Difference, a, b );
 
 
  904    booleanOp( Clipper2Lib::ClipType::Intersection, a, b );
 
 
  910    booleanOp( Clipper2Lib::ClipType::Xor, a, b );
 
 
  918    Inflate( aFactor, aCornerStrategy, aMaxError );
 
 
  926    using namespace Clipper2Lib;
 
  930    #define SEG_CNT_MAX 64 
  931    static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
 
  938    JoinType joinType = JoinType::Round;    
 
  939    double   miterLimit = 2.0;      
 
  941    switch( aCornerStrategy )
 
  944        joinType = JoinType::Miter;
 
  949        joinType = JoinType::Miter;
 
  953        joinType = JoinType::Miter;
 
  957        joinType = JoinType::Square;
 
  961        joinType = JoinType::Round;
 
  965    std::vector<CLIPPER_Z_VALUE> zValues;
 
  966    std::vector<SHAPE_ARC>       arcBuffer;
 
  972        for( 
size_t i = 0; i < poly.size(); i++ )
 
  973            paths.push_back( poly[i].convertToClipper2( i == 0, zValues, arcBuffer ) );
 
  975        c.AddPaths( paths, joinType, EndType::Polygon );
 
  982    if( aCircleSegCount < 6 ) 
 
  987    if( aCircleSegCount > 
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
 
  989        coeff = 1.0 - cos( 
M_PI / aCircleSegCount );
 
  992            arc_tolerance_factor[aCircleSegCount] = coeff;
 
  996        coeff = arc_tolerance_factor[aCircleSegCount];
 
  999    c.ArcTolerance( 
std::abs( aAmount ) * coeff );
 
 1000    c.MiterLimit( miterLimit );
 
 1007        c.Execute( aAmount, paths );
 
 1009        Clipper2Lib::SimplifyPaths( paths, 
std::abs( aAmount ) * coeff, 
true );
 
 1012        c2.PreserveCollinear( 
false );
 
 1013        c2.ReverseSolution( 
false );
 
 1014        c2.AddSubject( paths );
 
 1015        c2.Execute(ClipType::Union, FillRule::Positive, tree);
 
 1019        c.Execute( aAmount, tree );
 
 
 1030    using namespace Clipper2Lib;
 
 1034    #define SEG_CNT_MAX 64 
 1035    static double arc_tolerance_factor[
SEG_CNT_MAX + 1];
 
 1042    JoinType joinType = JoinType::Round; 
 
 1043    double   miterLimit = 2.0;           
 
 1045    switch( aCornerStrategy )
 
 1048        joinType = JoinType::Miter;
 
 1053        joinType = JoinType::Miter;
 
 1057        joinType = JoinType::Miter;
 
 1061        joinType = JoinType::Square;
 
 1065        joinType = JoinType::Round;
 
 1069    std::vector<CLIPPER_Z_VALUE> zValues;
 
 1070    std::vector<SHAPE_ARC>       arcBuffer;
 
 1073    c.AddPath( 
path, joinType, EndType::Butt );
 
 1079    if( aCircleSegCount < 6 ) 
 
 1080        aCircleSegCount = 6;
 
 1084    if( aCircleSegCount > 
SEG_CNT_MAX || arc_tolerance_factor[aCircleSegCount] == 0 )
 
 1086        coeff = 1.0 - cos( 
M_PI / aCircleSegCount );
 
 1089            arc_tolerance_factor[aCircleSegCount] = coeff;
 
 1093        coeff = arc_tolerance_factor[aCircleSegCount];
 
 1096    c.ArcTolerance( 
std::abs( aAmount ) * coeff );
 
 1097    c.MiterLimit( miterLimit );
 
 1104        c.Execute( aAmount, paths2 );
 
 1106        Clipper2Lib::SimplifyPaths( paths2, 
std::abs( aAmount ) * coeff, 
false );
 
 1109        c2.PreserveCollinear( 
false );
 
 1110        c2.ReverseSolution( 
false );
 
 1111        c2.AddSubject( paths2 );
 
 1112        c2.Execute( ClipType::Union, FillRule::Positive, tree );
 
 1116        c.Execute( aAmount, tree );
 
 
 1129    inflate2( aAmount, segCount, aCornerStrategy, aSimplify );
 
 
 1138    inflateLine2( aLine, aAmount, segCount, aCornerStrategy, aSimplify );
 
 
 1143                                     const std::vector<CLIPPER_Z_VALUE>&             aZValueBuffer,
 
 1144                                     const std::vector<SHAPE_ARC>&                   aArcBuffer )
 
 1146    if( !aPolyPath->IsHole() )
 
 1149        paths.reserve( aPolyPath->Count() + 1 );
 
 1150        paths.emplace_back( aPolyPath->Polygon(), aZValueBuffer, aArcBuffer );
 
 1152        for( 
const std::unique_ptr<Clipper2Lib::PolyPath64>& child : *aPolyPath )
 
 1154            paths.emplace_back( child->Polygon(), aZValueBuffer, aArcBuffer );
 
 1156            for( 
const std::unique_ptr<Clipper2Lib::PolyPath64>& grandchild : *child )
 
 1160        m_polys.emplace_back( std::move( paths ) );
 
 
 1166                                 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
 
 1167                                 const std::vector<SHAPE_ARC>&       aArcBuffer )
 
 1171    for( 
const std::unique_ptr<Clipper2Lib::PolyPath64>& n : tree )
 
 
 1177                                 const std::vector<CLIPPER_Z_VALUE>& aZValueBuffer,
 
 1178                                 const std::vector<SHAPE_ARC>&       aArcBuffer )
 
 1183    for( 
const Clipper2Lib::Path64& n : aPath )
 
 1185        if( Clipper2Lib::Area( n ) > 0 )
 
 1194            wxCHECK2_MSG( !
path.empty(), 
continue, wxT( 
"Cannot add a hole before an outline" ) );
 
 1197        path.emplace_back( n, aZValueBuffer, aArcBuffer );
 
 
 1236    int           x = edge.
m_p1.
x;
 
 1237    int           y = edge.
m_p1.
y;
 
 1238    int           min_dist = std::numeric_limits<int>::max();
 
 1257            x_intersect = std::max( e.
m_p1.
x, e.
m_p2.
x );
 
 1265        int dist = ( x - x_intersect );
 
 1267        if( dist >= 0 && dist < min_dist )
 
 1270            x_nearest = x_intersect;
 
 1283        edges[hole2outline_index] =
 
 1286        edges[split_index] =
 
 1291        e_nearest->
m_next = outline2hole_index;
 
 1294        for( ; last->
m_next != edgeIndex; last = &edges[last->
m_next] )
 
 1296        last->
m_next = hole2outline_index;
 
 
 1306    bool            outline = 
true;
 
 1308    if( paths.size() == 1 )
 
 1311    size_t total_point_count = 0;
 
 1315        total_point_count += 
path.PointCount();
 
 1318    if( total_point_count > (
size_t) std::numeric_limits<FractureEdge::Index>::max() )
 
 1320        wxLogWarning( wxT( 
"Polygon has more points than int limit" ) );
 
 1327    edges.reserve( total_point_count + paths.size() * 3 );
 
 1333        int                 path_or_provoking_index;
 
 1338    std::vector<PathInfo> sorted_paths;
 
 1339    const int             paths_count = 
static_cast<int>( paths.size() );
 
 1340    sorted_paths.reserve( paths_count );
 
 1342    for( 
int path_index = 0; path_index < paths_count; path_index++ )
 
 1345        const std::vector<VECTOR2I>& points = 
path.CPoints();
 
 1346        const int                    point_count = 
static_cast<int>( points.size() );
 
 1347        int                          x_min = std::numeric_limits<int>::max();
 
 1348        int                          y_min = std::numeric_limits<int>::max();
 
 1351        for( 
int point_index = 0; point_index < point_count; point_index++ )
 
 1353            const VECTOR2I& point = points[point_index];
 
 1354            if( point.
x < x_min )
 
 1357                leftmost = point_index;
 
 1359            if( point.
y < y_min )
 
 1363        sorted_paths.emplace_back( PathInfo{ path_index, leftmost, x_min, y_min } );
 
 1366    std::sort( sorted_paths.begin() + 1, sorted_paths.end(),
 
 1367               []( 
const PathInfo& a, 
const PathInfo& b )
 
 1370                       return a.y_or_bridge < b.y_or_bridge;
 
 1376    for( PathInfo& path_info : sorted_paths )
 
 1379        const std::vector<VECTOR2I>& points = 
path.CPoints();
 
 1380        const size_t                 point_count = points.size();
 
 1385        for( 
size_t i = 0; i < point_count - 1; i++ )
 
 1387            edges.emplace_back( points[i], points[i + 1], edge_index + 1 );
 
 1392        edges.emplace_back( points[point_count - 1], points[0], provoking_edge );
 
 1399            path_info.path_or_provoking_index = provoking_edge;
 
 1400            path_info.y_or_bridge = edge_index;
 
 1404            edges.resize( edge_index );
 
 1410    for( 
auto it = sorted_paths.begin() + 1; it != sorted_paths.end(); it++ )
 
 1412        auto edge = 
processHole( edges, it->path_or_provoking_index,
 
 1413                                 it->path_or_provoking_index + it->leftmost, it->y_or_bridge );
 
 1418            wxLogWarning( wxT( 
"Broken polygon, dropping path" ) );
 
 
 1466    int x = edge->
m_p1.
x;
 
 1467    int y = edge->
m_p1.
y;
 
 1468    int min_dist = std::numeric_limits<int>::max();
 
 1475        if( !e->matches( y ) )
 
 1480        if( e->m_p1.y == e->m_p2.y ) 
 
 1482            x_intersect = std::max( e->m_p1.x, e->m_p2.x );
 
 1486            x_intersect = e->m_p1.x
 
 1487                          + 
rescale( e->m_p2.x - e->m_p1.x, y - e->m_p1.y, e->m_p2.y - e->m_p1.y );
 
 1490        int dist = ( x - x_intersect );
 
 1492        if( dist >= 0 && dist < min_dist && e->m_connected )
 
 1495            x_nearest = x_intersect;
 
 1511        edges.push_back( split_2 );
 
 1512        edges.push_back( lead1 );
 
 1513        edges.push_back( lead2 );
 
 1518        e_nearest->
m_next = lead1;
 
 1523        for( last = edge; last->
m_next != edge; last = last->
m_next )
 
 
 1549    if( paths.size() == 1 )
 
 1552    int num_unconnected = 0;
 
 1556        const std::vector<VECTOR2I>& points = 
path.CPoints();
 
 1557        int                          pointCount = points.size();
 
 1561        int x_min = std::numeric_limits<int>::max();
 
 1563        for( 
int i = 0; i < pointCount; i++ )
 
 1565            if( points[i].x < x_min )
 
 1566                x_min = points[i].x;
 
 1571                                                         points[i + 1 == pointCount ? 0 : i + 1] );
 
 1582            if( i == pointCount - 1 )
 
 1586            edges.push_back( fe );
 
 1590                if( fe->
m_p1.
x == x_min )
 
 1591                    border_edges.push_back( fe );
 
 1602    while( num_unconnected > 0 )
 
 1604        int  x_min = std::numeric_limits<int>::max();
 
 1605        auto it = border_edges.begin();
 
 1610        for( ; it != border_edges.end(); ++it )
 
 1613            int               xt = border_edge->
m_p1.
x;
 
 1615            if( ( xt <= x_min ) && !border_edge->
m_connected )
 
 1618                smallestX = border_edge;
 
 1622        int num_processed = 
processEdge( edges, smallestX );
 
 1625        if( !num_processed )
 
 1627            wxLogWarning( wxT( 
"Broken polygon, dropping path" ) );
 
 1635        num_unconnected -= num_processed;
 
 1653    paths.push_back( std::move( newPath ) );
 
 
 1676    assert( aPoly.size() == 1 );
 
 1682        bool m_duplicate = 
false;
 
 1689        bool compareSegs( 
const SEG& s1, 
const SEG& s2 )
 const 
 1691            return (s1.
A == s2.
B && s1.
B == s2.
A);
 
 1696            return compareSegs( m_poly->
CSegment( m_index ),
 
 1697                                aOther.m_poly->CSegment( aOther.m_index ) );
 
 1702            return !compareSegs( m_poly->
CSegment( m_index ),
 
 1703                                 aOther.m_poly->CSegment( aOther.m_index ) );
 
 1708            std::size_t operator()(  
const EDGE& aEdge )
 const 
 1710                const SEG& a = aEdge.m_poly->CSegment( aEdge.m_index );
 
 1711                std::size_t seed = 0xa82de1c0;
 
 1718    struct EDGE_LIST_ENTRY
 
 1721        EDGE_LIST_ENTRY* 
next;
 
 1724    std::unordered_set<EDGE, EDGE::HASH> uniqueEdges;
 
 1729    auto edgeList = std::make_unique<EDGE_LIST_ENTRY[]>( lc.
SegmentCount() );
 
 1733        edgeList[i].index   = i;
 
 1734        edgeList[i].next    = &edgeList[ (i != lc.
SegmentCount() - 1) ? i + 1 : 0 ];
 
 1737    std::unordered_set<EDGE_LIST_ENTRY*> queue;
 
 1742        uniqueEdges.insert( e );
 
 1748        auto    it = uniqueEdges.find( e );
 
 1750        if( it != uniqueEdges.end() && it->m_index != i )
 
 1752            int e1  = it->m_index;
 
 1756                std::swap( e1, e2 );
 
 1758            int e1_prev = e1 - 1;
 
 1763            int e2_prev = e2 - 1;
 
 1768            int e1_next = e1 + 1;
 
 1773            int e2_next = e2 + 1;
 
 1778            edgeList[e1_prev].next  = &edgeList[ e2_next ];
 
 1779            edgeList[e2_prev].next  = &edgeList[ e1_next ];
 
 1780            edgeList[i].next = 
nullptr;
 
 1781            edgeList[it->m_index].next = 
nullptr;
 
 1787        if( edgeList[i].
next )
 
 1788            queue.insert( &edgeList[i] );
 
 1791    auto edgeBuf = std::make_unique<EDGE_LIST_ENTRY* []>( lc.
SegmentCount() );
 
 1797    double max_poly = 0.0;
 
 1799    while( queue.size() )
 
 1801        EDGE_LIST_ENTRY* e_first = *queue.begin();
 
 1802        EDGE_LIST_ENTRY* e = e_first;
 
 1809        } 
while( e && e != e_first );
 
 1813        for( 
int i = 0; i < cnt; i++ )
 
 1817            queue.erase( edgeBuf[i] );
 
 1822        double area = std::fabs( outl.
Area() );
 
 1824        if( area > max_poly )
 
 1830        result.push_back( outl );
 
 1837    aPoly = std::move( 
result );
 
 
 1847        if( paths.size() > 1 )
 
 
 1871    std::array<VECTOR2I,4> pts = { aSegA.
A, aSegA.
B, aSegB.
A, aSegB.
B };
 
 1873    std::sort( pts.begin(), pts.end(), [axis]( 
const VECTOR2I& p, 
const VECTOR2I& q )
 
 1876            return p.x < q.x || ( p.x == q.x && p.y < q.y );
 
 1878            return p.y < q.y || ( p.y == q.y && p.x < q.x );
 
 1901        if( !side1 && !side2 )
 
 1903            wxLogTrace( wxT( 
"collinear" ), wxT( 
"Found exterior waist between (%d,%d)-(%d,%d) and (%d,%d)-(%d,%d)" ),
 
 1904                        aSegA.
A.
x, aSegA.
A.
y, aSegA.
B.
x, aSegA.
B.
y,
 
 1905                        aSegB.
A.
x, aSegB.
A.
y, aSegB.
B.
x, aSegB.
B.
y );
 
 
 1916    for( 
size_t polyIdx = 0; polyIdx < 
m_polys.size(); ++polyIdx )
 
 1918        bool changed = 
true;
 
 1927            RTree<intptr_t, intptr_t, 2, intptr_t> rtree;
 
 1929            for( intptr_t i = 0; i < count; ++i )
 
 1933                intptr_t min[2] = { std::min( a.
x, b.
x ), std::min( a.
y, b.
y ) };
 
 1934                intptr_t max[2] = { std::max( a.
x, b.
x ), std::max( a.
y, b.
y ) };
 
 1935                rtree.Insert( min, max, i );
 
 1942            for( intptr_t i = 0; i < count && !found; ++i )
 
 1947                intptr_t min[2] = { std::min( a.
x, b.
x ), std::min( a.
y, b.
y ) };
 
 1948                intptr_t max[2] = { std::max( a.
x, b.
x ), std::max( a.
y, b.
y ) };
 
 1951                        [&]( 
const int& j ) -> 
bool 
 1953                            if( j == i || j == ( ( i + 1 ) % count ) || j == ( ( i + count - 1 ) % count ) )
 
 1958                            SEG other( oa, ob );
 
 1962                            if( oa == a && ob == b )
 
 1965                            if( oa == b && ob == a )
 
 1979                rtree.Search( min, max, visitor );
 
 1986            int a1 = ( segA + 1 ) % outline.
PointCount();
 
 1988            int b1 = ( segB + 1 ) % outline.
PointCount();
 
 2014            m_polys[polyIdx][0] = std::move( lc1 );
 
 2017            np.push_back( std::move( lc2 ) );
 
 2018            m_polys.push_back( std::move( np ) );
 
 
 2042            path.Simplify( aTolerance );
 
 
 2060    while( outline.size() > 1 )
 
 
 2085    std::stringstream ss;
 
 2087    ss << 
"SHAPE_LINE_CHAIN poly; \n";
 
 2089    for( 
unsigned i = 0; i < 
m_polys.size(); i++ )
 
 2091        for( 
unsigned j = 0; j < 
m_polys[i].size(); j++ )
 
 2094            ss << 
"{ auto tmp = " << 
m_polys[i][j].Format() << 
";\n";
 
 2100                ss << 
" poly.AddOutline(tmp); } \n";
 
 2104                ss << 
" poly.AddHole(tmp); } \n";
 
 
 2120    if( tmp != 
"polyset" )
 
 2125    int n_polys = atoi( tmp.c_str() );
 
 2130    for( 
int i = 0; i < n_polys; i++ )
 
 2140        int n_outlines = atoi( tmp.c_str() );
 
 2142        if( n_outlines < 0 )
 
 2145        for( 
int j = 0; j < n_outlines; j++ )
 
 2152            int n_vertices = atoi( tmp.c_str() );
 
 2154            for( 
int v = 0; v < n_vertices; v++ )
 
 2158                aStream >> tmp; p.
x = atoi( tmp.c_str() );
 
 2159                aStream >> tmp; p.
y = atoi( tmp.c_str() );
 
 2163            paths.push_back( std::move( outline ) );
 
 2166        m_polys.push_back( std::move( paths ) );
 
 
 2177    for( 
unsigned i = 0; i < 
m_polys.size(); i++ )
 
 
 2194    for( 
unsigned i = 0; i < 
m_polys.size(); i++ )
 
 2197            bb = *
m_polys[i][0].GetCachedBBox();
 
 
 2214            if( lineChain.PointOnEdge( aP, aAccuracy ) )
 
 
 2229    if( dist_sq == 0 || dist_sq < 
SEG::Square( aClearance ) )
 
 2232            *aLocation = nearest;
 
 2235            *aActual = sqrt( dist_sq );
 
 
 2253    if( dist_sq == 0 || dist_sq < 
SEG::Square( aClearance ) )
 
 2256            *aLocation = nearest;
 
 2259            *aActual = sqrt( dist_sq );
 
 
 2276        int                  extra = segment->
GetWidth() / 2;
 
 2278        if( 
Collide( segment->
GetSeg(), aClearance + extra, aActual, aLocation ) )
 
 2281                *aActual = std::max( 0, *aActual - extra );
 
 2292        int                 extra = 
circle->GetRadius();
 
 2294        if( 
Collide( 
circle->GetCenter(), aClearance + extra, aActual, aLocation ) )
 
 2297                *aActual = std::max( 0, *aActual - extra );
 
 2314            if( aActual || aLocation )
 
 2319                if( aShape->
Collide( &tri, aClearance, &triActual, &triLocation ) )
 
 2330                if( aShape->
Collide( &tri, aClearance ) )
 
 2339            *aActual = std::max( 0, 
actual );
 
 
 2362    if( aPolygonIdx < 0 )
 
 2363        aPolygonIdx += 
m_polys.size();
 
 2365    m_polys[aPolygonIdx].erase( 
m_polys[aPolygonIdx].begin() + aContourIdx );
 
 
 2385    std::vector<VERTEX_INDEX> indices_to_remove;
 
 2390        segmentStart = *iterator;
 
 2396            segmentEnd = contourStart;
 
 2404                contourStart = *iterator;
 
 2412            wxCHECK_MSG( iterator, removed, wxT( 
"Invalid polygon.  Reached end without noticing.  Please report this error" ) );
 
 2414            segmentEnd = *iterator;
 
 2418        if( segmentStart == segmentEnd )
 
 2420            indices_to_remove.push_back( indexStart );
 
 2427    for( 
auto it = indices_to_remove.rbegin(); it != indices_to_remove.rend(); ++it )
 
 
 2450            if( triangleSet->GetSourceOutlineIndex() == aIdx )
 
 2452            else if( triangleSet->GetSourceOutlineIndex() > aIdx )
 
 2453                triangleSet->SetSourceOutlineIndex( triangleSet->GetSourceOutlineIndex() - 1 );
 
 
 2480    Append( aP.
x, aP.
y, aOutline, aHole );
 
 
 2486                                    int aClearance )
 const 
 2489    bool collision = 
false;
 
 2499        delta = *iterator - aPoint;
 
 2502        distance_squared = 
delta.SquaredEuclideanNorm();
 
 2505        if( distance_squared <= clearance_squared )
 
 2507            if( !aClosestVertex )
 
 2513            clearance_squared = distance_squared;
 
 2516            *aClosestVertex = iterator.GetIndex();
 
 
 2526                                  int aClearance )
 const 
 2529    bool   collision = 
false;
 
 2534        const SEG currentSegment = *iterator;
 
 2538        if( distance_squared <= clearance_squared )
 
 2540            if( !aClosestVertex )
 
 2546            clearance_squared = distance_squared;
 
 2549            *aClosestVertex = iterator.GetIndex();
 
 
 2559    for( 
int polygonIdx = 0; polygonIdx < 
OutlineCount(); polygonIdx++ )
 
 2563        for( 
int holeIdx = 0; holeIdx < 
HoleCount( polygonIdx ); holeIdx++ )
 
 
 2570                               bool aUseBBoxCaches )
 const 
 2576    if( aSubpolyIndex >= 0 )
 
 2577        return containsSingle( aP, aSubpolyIndex, aAccuracy, aUseBBoxCaches );
 
 2580    for( 
int polygonIdx = 0; polygonIdx < 
OutlineCount(); polygonIdx++ )
 
 2582        if( 
containsSingle( aP, polygonIdx, aAccuracy, aUseBBoxCaches ) )
 
 
 2598        throw( std::out_of_range( 
"aGlobalIndex-th vertex does not exist" ) );
 
 
 2615        throw( std::out_of_range( 
"aGlobalIndex-th vertex does not exist" ) );
 
 
 2626                                     bool aUseBBoxCaches )
 const 
 2632        for( 
int holeIdx = 0; holeIdx < 
HoleCount( aSubpolyIndex ); holeIdx++ )
 
 
 2654            path.Move( aVector );
 
 2658        tri->Move( aVector );
 
 
 2670            path.Mirror( aRef, aFlipDirection );
 
 
 2683            path.Rotate( aAngle, aCenter );
 
 
 2699            c += 
path.PointCount();
 
 
 2736    SEG::ecoord minDistance = (*iterator).SquaredDistance( aPoint );
 
 2738    for( iterator++; iterator && minDistance > 0; iterator++ )
 
 2740        SEG::ecoord currentDistance = (*iterator).SquaredDistance( aPoint );
 
 2742        if( currentDistance < minDistance )
 
 2745                *aNearest = (*iterator).NearestPoint( aPoint );
 
 2747            minDistance = currentDistance;
 
 
 2763            *aNearest = ( aSegment.
A + aSegment.
B ) / 2;
 
 2769    SEG::ecoord            minDistance = (*iterator).SquaredDistance( aSegment );
 
 2771    if( aNearest && minDistance == 0 )
 
 2772        *aNearest = ( *iterator ).NearestPoint( aSegment );
 
 2774    for( iterator++; iterator && minDistance > 0; iterator++ )
 
 2776        SEG::ecoord currentDistance = (*iterator).SquaredDistance( aSegment );
 
 2778        if( currentDistance < minDistance )
 
 2781                *aNearest = (*iterator).NearestPoint( aSegment );
 
 2783            minDistance = currentDistance;
 
 2788    return minDistance < 0 ? 0 : minDistance;
 
 
 2795    wxASSERT_MSG( !aOutlineOnly, wxT( 
"Warning: SHAPE_POLY_SET::SquaredDistance does not yet " 
 2796                                      "support aOutlineOnly==true" ) );
 
 2803    for( 
unsigned int polygonIdx = 0; polygonIdx < 
m_polys.size(); polygonIdx++ )
 
 2806                                                       aNearest ? &nearest : 
nullptr );
 
 2808        if( currentDistance_sq < minDistance_sq )
 
 2811                *aNearest = nearest;
 
 2813            minDistance_sq = currentDistance_sq;
 
 2817    return minDistance_sq;
 
 
 2828    for( 
unsigned int polygonIdx = 0; polygonIdx < 
m_polys.size(); polygonIdx++ )
 
 2831                                                       aNearest ? &nearest : 
nullptr );
 
 2833        if( currentDistance_sq < minDistance_sq )
 
 2836                *aNearest = nearest;
 
 2838            minDistance_sq = currentDistance_sq;
 
 2842    return minDistance_sq;
 
 
 2863    for( 
unsigned int idx = 0; idx < 
m_polys.size(); idx++ )
 
 
 2874    for( 
size_t idx = 0; idx < 
m_polys.size(); idx++ )
 
 
 2883    SHAPE::operator=( aOther );
 
 
 2943    if( w == 0.0 || h == 0.0 )
 
 2946    int n_cells_x, n_cells_y;
 
 2950        n_cells_x = w / aSize;
 
 2951        n_cells_y = floor( h / w * n_cells_x ) + 1;
 
 2955        n_cells_y = h / aSize;
 
 2956        n_cells_x = floor( w / h * n_cells_y ) + 1;
 
 2959    SHAPE_POLY_SET ps1( aPoly ), ps2( aPoly ), maskSetOdd, maskSetEven;
 
 2961    for( 
int yy = 0; yy < n_cells_y; yy++ )
 
 2963        for( 
int xx = 0; xx < n_cells_x; xx++ )
 
 2967            p.
x = bb.
GetX() + w * xx / n_cells_x;
 
 2968            p.
y = bb.
GetY() + h * yy / n_cells_y;
 
 2972            p2.
x = bb.
GetX() + w * ( xx + 1 ) / n_cells_x;
 
 2973            p2.
y = bb.
GetY() + h * ( yy + 1 ) / n_cells_y;
 
 2981            mask.SetClosed( 
true );
 
 2983            if( ( xx ^ yy ) & 1 )
 
 2991    ps2.BooleanIntersection( maskSetEven );
 
 2995    for( 
int i = 0; i < ps2.OutlineCount(); i++ )
 
 2996        ps1.AddOutline( ps2.COutline( i ) );
 
 2998    if( ps1.OutlineCount() )
 
 
 3006                                         std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>* aHintData )
 
 3022                std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>& dest,
 
 3023                std::vector<std::unique_ptr<TRIANGULATED_POLYGON>>* hintData )
 
 3025                bool triangulationValid = 
false;
 
 3029                if( hintData && hintData->size() != (
unsigned) polySet.
OutlineCount() )
 
 3034                    if( !dest.empty() && dest.back()->GetTriangleCount() == 0 )
 
 3035                        dest.erase( dest.end() - 1 );
 
 3037                    dest.push_back( std::make_unique<TRIANGULATED_POLYGON>( forOutline ) );
 
 3044                                                hintData ? hintData->at( index ).get() : 
nullptr ) )
 
 3058                        triangulationValid = 
false;
 
 3065                    triangulationValid = 
true;
 
 3068                return triangulationValid;
 
 3080            for( 
int jj = 0; jj < 
HoleCount( ii ); ++jj )
 
 3087            else if( aSimplify )
 
 3096                wxLogTrace( 
TRIANGULATE_TRACE, 
"Failed to triangulate partitioned polygon %d", ii );
 
 
 3137        hash.
add( outline.size() );
 
 3141            hash.
add( lc.PointCount() );
 
 3143            for( 
int i = 0; i < lc.PointCount(); i++ )
 
 
 3171    std::set<long long> ptHashes;
 
 3175        for( 
const VECTOR2I& pt : lc.CPoints() )
 
 3177            const long long ptHash = (
long long) pt.x << 32 | pt.y;
 
 3179            if( ptHashes.count( ptHash ) > 0 )
 
 3182            ptHashes.insert( ptHash );
 
 
 3201        n += t->GetTriangleCount();
 
 
 3214            aSubshapes.push_back( &tri );
 
 
 3225    if( aClearance != 0 )
 
 
 3279            for( 
int i = 0; i < 
path.PointCount(); i++ )
 
 3283                vec.
x = ( pt.
x - aCenter.
x ) * aScaleFactorX;
 
 3284                vec.
y = ( pt.
y - aCenter.
y ) * aScaleFactorY;
 
 3287                path.SetPoint( i, pt );
 
 
 3301    Clipper2Lib::Clipper64 clipper;
 
 3302    Clipper2Lib::PolyTree64 tree;
 
 3303    Clipper2Lib::Paths64 paths;
 
 3307        Clipper2Lib::Path64 lc;
 
 3308        lc.reserve( 
path.PointCount() );
 
 3310        for( 
int i = 0; i < 
path.PointCount(); i++ )
 
 3311            lc.emplace_back( 
path.CPoint( i ).x, 
path.CPoint( i ).y );
 
 3313        paths.push_back( std::move( lc ) );
 
 3316    clipper.AddSubject( paths );
 
 3317    clipper.Execute( Clipper2Lib::ClipType::Union, aEvenOdd ? Clipper2Lib::FillRule::EvenOdd
 
 3318                                                            : Clipper2Lib::FillRule::NonZero, tree );
 
 3320    std::vector<CLIPPER_Z_VALUE> zValues;
 
 3321    std::vector<SHAPE_ARC> arcBuffer;
 
 
 3341                                                           int aSpacing, 
int aLineLength )
 const 
 3343    std::vector<SEG> hatchLines;
 
 3353        if( iterator->x < min_x )
 
 3354            min_x = iterator->x;
 
 3356        if( iterator->x > max_x )
 
 3357            max_x = iterator->x;
 
 3359        if( iterator->y < min_y )
 
 3360            min_y = iterator->y;
 
 3362        if( iterator->y > max_y )
 
 3363            max_y = iterator->y;
 
 3366    auto sortEndsByDescendingX =
 
 3369                return tst.x < ref.
x;
 
 3372    for( 
double slope : aSlopes )
 
 3374        int64_t max_a, min_a;
 
 3387        min_a = ( min_a / aSpacing ) * aSpacing;
 
 3390        std::vector<VECTOR2I> pointbuffer;
 
 3391        pointbuffer.reserve( 256 );
 
 3393        for( int64_t a = min_a; a < max_a; a += aSpacing )
 
 3395            pointbuffer.clear();
 
 3400                const SEG seg = *iterator;
 
 3406                    if( pt.
x < min_x || pt.
x > max_x || pt.
y < min_y || pt.
y > max_y )
 
 3417            if( pointbuffer.size() > 2 )
 
 3418                sort( pointbuffer.begin(), pointbuffer.end(), sortEndsByDescendingX );
 
 3421            for( 
size_t ip = 0; ip + 1 < pointbuffer.size(); ip++ )
 
 3423                const VECTOR2I& p1 = pointbuffer[ip];
 
 3424                const VECTOR2I& p2 = pointbuffer[ip + 1];
 
 3430                SEG candidate( p1, p2 );
 
 3432                VECTOR2I mid( ( candidate.
A.
x + candidate.
B.
x ) / 2, ( candidate.
A.
y + candidate.
B.
y ) / 2 );
 
 3437                    int dx = p2.
x - p1.
x;
 
 3441                    if( aLineLength == -1 || 
std::abs( dx ) < 2 * aLineLength )
 
 3443                        hatchLines.emplace_back( candidate );
 
 3447                        double dy = p2.
y - p1.
y;
 
 3457                        int y1 = 
KiROUND( p1.
y + dx * slope );
 
 3458                        int y2 = 
KiROUND( p2.
y - dx * slope );
 
 3460                        hatchLines.emplace_back( 
SEG( p1.
x, p1.
y, x1, y1 ) );
 
 3462                        hatchLines.emplace_back( 
SEG( p2.
x, p2.
y, x2, y2 ) );
 
 
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
 
bool IntersectsLine(double aSlope, double aOffset, VECTOR2I &aIntersection) const
Check if this segment intersects a line defined by slope aSlope and offset aOffset.
 
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
 
bool ApproxCollinear(const SEG &aSeg, int aDistanceThreshold=1) const
 
SHAPE_TYPE Type() const
Return the type of the shape.
 
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.
 
int PointCount() const
Return the number of points (vertices) in this line chain.
 
void Clear()
Remove all points from the line chain.
 
void Simplify(int aTolerance=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
 
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.
 
bool IsEndContour() const
 
TRIANGULATED_POLYGON(int aSourceOutline)
 
std::deque< TRI > m_triangles
 
std::deque< VECTOR2I > m_vertices
 
void AddTriangle(int a, int b, int c)
 
TRIANGULATED_POLYGON & operator=(const TRIANGULATED_POLYGON &aOther)
 
Represent a set of closed polygons.
 
std::mutex m_triangulationMutex
 
virtual bool HasIndexableSubshapes() const override
 
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
 
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
 
SHAPE_POLY_SET Chamfer(int aDistance)
Return a chamfered version of the polygon set.
 
void RemoveOutline(int aOutlineIdx)
Delete the aOutlineIdx-th outline of the set including its contours and holes.
 
void Scale(double aScaleFactorX, double aScaleFactorY, const VECTOR2I &aCenter)
 
bool CollideEdge(const VECTOR2I &aPoint, VERTEX_INDEX *aClosestVertex=nullptr, int aClearance=0) const
Check whether aPoint collides with any edge of any of the contours of the polygon.
 
virtual void GetIndexableSubshapes(std::vector< const SHAPE * > &aSubshapes) const override
 
void BooleanXor(const SHAPE_POLY_SET &b)
Perform boolean polyset exclusive or.
 
ITERATOR_TEMPLATE< VECTOR2I > ITERATOR
 
void fractureSingle(POLYGON &paths)
 
bool HasHoles() const
Return true if the polygon set has any holes.
 
CONST_ITERATOR CIterateWithHoles() const
 
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
 
ITERATOR IterateWithHoles()
 
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
 
bool IsTriangulationUpToDate() const
 
void importPaths(Clipper2Lib::Paths64 &paths, const std::vector< CLIPPER_Z_VALUE > &aZValueBuffer, const std::vector< SHAPE_ARC > &aArcBuffe)
 
void InsertVertex(int aGlobalIndex, const VECTOR2I &aNewVertex)
Adds a vertex in the globally indexed position aGlobalIndex.
 
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
 
virtual void CacheTriangulation(bool aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
 
int VertexCount(int aOutline=-1, int aHole=-1) const
Return the number of vertices in a given outline/hole.
 
void DeletePolygon(int aIdx)
Delete aIdx-th polygon from the set.
 
void splitCollinearOutlines()
 
double Area()
Return the area of this poly set.
 
void SetVertex(const VERTEX_INDEX &aIndex, const VECTOR2I &aPos)
Accessor function to set the position of a specific point.
 
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
 
void Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
 
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
 
void BuildPolysetFromOrientedPaths(const std::vector< SHAPE_LINE_CHAIN > &aPaths, bool aEvenOdd=false)
Build a SHAPE_POLY_SET from a bunch of outlines in provided in random order.
 
bool Parse(std::stringstream &aStream) override
 
int TotalVertices() const
Return total number of vertices stored in the set.
 
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
 
int FullPointCount() const
Return the number of points in the shape poly set.
 
void GetArcs(std::vector< SHAPE_ARC > &aArcBuffer) const
Appends all the arcs in this polyset to aArcBuffer.
 
bool IsVertexInHole(int aGlobalIdx)
Check whether the aGlobalIndex-th vertex belongs to a hole.
 
int NormalizeAreaOutlines()
Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s).
 
void RemoveVertex(int aGlobalIndex)
Delete the aGlobalIndex-th vertex.
 
void unfractureSingle(POLYGON &path)
 
void inflateLine2(const SHAPE_LINE_CHAIN &aLine, int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy, bool aSimplify=false)
 
bool GetRelativeIndices(int aGlobalIdx, VERTEX_INDEX *aRelativeIndices) const
Convert a global vertex index —i.e., a number that globally identifies a vertex in a concatenated lis...
 
bool IsPolygonSelfIntersecting(int aPolygonIndex) const
Check whether the aPolygonIndex-th polygon in the set is self intersecting.
 
SHAPE_POLY_SET Subset(int aFirstPolygon, int aLastPolygon)
Return a subset of the polygons in this set, the ones between aFirstPolygon and aLastPolygon.
 
int RemoveNullSegments()
Look for null segments; ie, segments whose ends are exactly the same and deletes them.
 
HASH_128 checksum() const
 
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
 
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
 
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
 
int AddPolygon(const POLYGON &apolygon)
Adds a polygon to the set.
 
const std::vector< SEG > GenerateHatchLines(const std::vector< double > &aSlopes, int aSpacing, int aLineLength) const
 
const std::string Format(bool aCplusPlus=true) const override
 
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
 
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
 
std::vector< std::unique_ptr< TRIANGULATED_POLYGON > > m_triangulatedPolys
 
ITERATOR_TEMPLATE< const VECTOR2I > CONST_ITERATOR
 
void inflate2(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy, bool aSimplify=false)
 
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
 
SEG::ecoord SquaredDistance(const VECTOR2I &aPoint, bool aOutlineOnly, VECTOR2I *aNearest) const
Compute the minimum distance squared between aPoint and all the polygons in the set.
 
void RemoveContour(int aContourIdx, int aPolygonIdx=-1)
Delete the aContourIdx-th contour of the aPolygonIdx-th polygon in the set.
 
void Unfracture()
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
 
int ArcCount() const
Count the number of arc shapes present.
 
bool GetGlobalIndex(VERTEX_INDEX aRelativeIndices, int &aGlobalIdx) const
Compute the global index of a vertex from the relative indices of polygon, contour and vertex.
 
bool GetNeighbourIndexes(int aGlobalIndex, int *aPrevious, int *aNext) const
Return the global indexes of the previous and the next corner of the aGlobalIndex-th corner of a cont...
 
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
 
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the reference to aHole-th hole in the aIndex-th outline.
 
int NewOutline()
Creates a new empty polygon in the set and returns its index.
 
void SimplifyOutlines(int aMaxError=0)
Simplifies the lines in the polyset.
 
void booleanOp(Clipper2Lib::ClipType aType, const SHAPE_POLY_SET &aOtherShape)
This is the engine to execute all polygon boolean transforms (AND, OR, ... and polygon simplification...
 
const TRIANGULATED_POLYGON * TriangulatedPolygon(int aIndex) const
 
bool hasTouchingHoles(const POLYGON &aPoly) const
Return true if the polygon set has any holes that touch share a vertex.
 
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of some of the outlines or holes.
 
bool CollideVertex(const VECTOR2I &aPoint, VERTEX_INDEX *aClosestVertex=nullptr, int aClearance=0) const
Check whether aPoint collides with any vertex of any of the contours of the polygon.
 
void DeletePolygonAndTriangulationData(int aIdx, bool aUpdateHash=true)
Delete aIdx-th polygon and its triangulation data from the set.
 
unsigned int TriangulatedPolyCount() const
Return the number of triangulated polygons.
 
std::atomic< bool > m_triangulationValid
 
void UpdateTriangulationDataHash()
 
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
 
int NewHole(int aOutline=-1)
Creates a new hole in a given outline.
 
SEG::ecoord SquaredDistanceToPolygon(VECTOR2I aPoint, int aIndex, VECTOR2I *aNearest) const
Compute the minimum distance between the aIndex-th polygon and aPoint.
 
CONST_SEGMENT_ITERATOR CIterateSegmentsWithHoles() const
Return an iterator object, for the aOutline-th outline in the set (with holes).
 
void cacheTriangulation(bool aPartition, bool aSimplify, std::vector< std::unique_ptr< TRIANGULATED_POLYGON > > *aHintData)
 
virtual size_t GetIndexableSubshapeCount() const override
 
SEG::ecoord SquaredDistanceToSeg(const SEG &aSegment, VECTOR2I *aNearest=nullptr) const
Compute the minimum distance squared between aSegment and all the polygons in the set.
 
void importPolyPath(const std::unique_ptr< Clipper2Lib::PolyPath64 > &aPolyPath, const std::vector< CLIPPER_Z_VALUE > &aZValueBuffer, const std::vector< SHAPE_ARC > &aArcBuffer)
 
void RebuildHolesFromContours()
Extract all contours from this polygon set, then recreate polygons with holes.
 
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
Mirror the line points about y or x (or both)
 
void OffsetLineChain(const SHAPE_LINE_CHAIN &aLine, int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify)
Perform offsetting of a line chain.
 
void BuildBBoxCaches() const
Construct BBoxCaches for Contains(), below.
 
std::vector< POLYGON > m_polys
 
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
 
POLYGON FilletPolygon(unsigned int aRadius, int aErrorMax, int aIndex)
Return a filleted version of the aIndex-th polygon.
 
bool containsSingle(const VECTOR2I &aP, int aSubpolyIndex, int aAccuracy, bool aUseBBoxCaches=false) const
Check whether the point aP is inside the aSubpolyIndex-th polygon of the polyset.
 
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
 
int OutlineCount() const
Return the number of outlines in the set.
 
void InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError)
Perform outline inflation/deflation, using round corners.
 
POLYGON chamferFilletPolygon(CORNER_MODE aMode, unsigned int aDistance, int aIndex, int aErrorMax)
Return the chamfered or filleted version of the aIndex-th polygon in the set, depending on the aMode ...
 
SHAPE_POLY_SET Fillet(int aRadius, int aErrorMax)
Return a filleted version of the polygon set.
 
void Move(const VECTOR2I &aVector) override
 
bool HasTouchingHoles() const
Return true if the polygon set has any holes that share a vertex.
 
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
 
SHAPE_POLY_SET & operator=(const SHAPE_POLY_SET &aOther)
 
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
 
SHAPE_POLY_SET CloneDropTriangulation() const
 
bool isExteriorWaist(const SEG &aSegA, const SEG &aSegB) const
Check if two line segments are collinear and overlap.
 
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
 
const POLYGON & CPolygon(int aIndex) const
 
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
 
POLYGON ChamferPolygon(unsigned int aDistance, int aIndex)
Return a chamfered version of the aIndex-th polygon.
 
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
 
const BOX2I BBoxFromCaches() const
 
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
 
void importTree(Clipper2Lib::PolyTree64 &tree, const std::vector< CLIPPER_Z_VALUE > &aZValueBuffer, const std::vector< SHAPE_ARC > &aArcBuffe)
 
SEGMENT_ITERATOR_TEMPLATE< const SEG > CONST_SEGMENT_ITERATOR
 
bool IsSelfIntersecting() const
Check whether any of the polygons in the set is self intersecting.
 
const SEG & GetSeg() const
 
int GetWidth() const override
 
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
 
SHAPE(SHAPE_TYPE aType)
Create an empty shape of type aType.
 
static constexpr extended_type ECOORD_MAX
 
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
 
constexpr VECTOR2< T > Perpendicular() const
Compute the perpendicular vector.
 
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
 
CORNER_STRATEGY
define how inflate transform build inflated polygon
 
@ ROUND_ACUTE_CORNERS
Acute angles are rounded.
 
@ CHAMFER_ACUTE_CORNERS
Acute angles are chamfered.
 
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
 
@ ROUND_ALL_CORNERS
All angles are rounded.
 
@ ALLOW_ACUTE_CORNERS
just inflate the polygon. Acute angles create spikes
 
static bool empty(const wxTextEntryBase *aCtrl)
 
static constexpr EDA_ANGLE FULL_CIRCLE
 
a few functions useful in geometry calculations.
 
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
 
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
 
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
 
static PGM_BASE * process
 
#define TRIANGULATE_TRACE
 
#define TRIANGULATESIMPLIFICATIONLEVEL
 
@ SH_POLY_SET
set of polygons (with holes, etc.)
 
static void fractureSingleCacheFriendly(SHAPE_POLY_SET::POLYGON &paths)
 
static void fractureSingleSlow(SHAPE_POLY_SET::POLYGON &paths)
 
static FractureEdge * processHole(FractureEdgeSet &edges, FractureEdge::Index provokingIndex, FractureEdge::Index edgeIndex, FractureEdge::Index bridgeIndex)
 
std::vector< FractureEdge > FractureEdgeSet
 
std::vector< FractureEdgeSlow * > FractureEdgeSetSlow
 
static SHAPE_POLY_SET partitionPolyIntoRegularCellGrid(const SHAPE_POLY_SET &aPoly, int aSize)
 
#define ENABLECACHEFRIENDLYFRACTURE
 
static int processEdge(FractureEdgeSetSlow &edges, FractureEdgeSlow *edge)
 
Holds information on each point of a SHAPE_LINE_CHAIN that is retrievable after an operation with Cli...
 
FractureEdgeSlow(int y=0)
 
FractureEdgeSlow * m_next
 
bool matches(int y) const
 
FractureEdgeSlow(bool connected, const VECTOR2I &p1, const VECTOR2I &p2)
 
FractureEdge(const VECTOR2I &p1, const VECTOR2I &p2, Index next)
 
bool matches(int y) const
 
A storage class for 128-bit hash value.
 
virtual const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
 
TRIANGULATED_POLYGON * parent
 
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
 
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
 
wxString result
Test unit parsing edge cases and error handling.
 
T rescale(T aNumerator, T aValue, T aDenominator)
Scale a number (value) by rational (numerator/denominator).
 
VECTOR2< int32_t > VECTOR2I
 
VECTOR2< double > VECTOR2D