22#include <unordered_set>
43#include <nanoflann.hpp>
83 return ( aLeft - aRight ).SquaredEuclideanNorm() <=
SEG::Square( aLimit );
97 return ( aRef - aFirst ).SquaredEuclideanNorm() < ( aRef - aSecond ).SquaredEuclideanNorm();
103 bool padOutside =
false;
107 pad->Padstack().ForEachUniqueLayer(
120 padPos.
x, padPos.
y );
130 padPos.
x, padPos.
y );
147 endpoints.emplace_back( shape->GetStart(), shape );
148 endpoints.emplace_back( shape->GetEnd(), shape );
159 return static_cast<double>(
endpoints[idx].first.x );
161 return static_cast<double>(
endpoints[idx].first.y );
164 template <
class BBOX>
171using KDTree = nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<double, PCB_SHAPE_ENDPOINTS_ADAPTOR>,
176 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*>& aShapeOwners,
177 int aErrorMax,
bool aAllowUseArcsInPolygons )
194 aShapeOwners[ std::make_pair( prevPt, pt ) ] = aShape;
210 aContour.
Append( arc360, aErrorMax );
213 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
214 aShapeOwners[ std::make_pair( aContour.
CPoint( ii-1 ), aContour.
CPoint( ii ) ) ] = aShape;
216 if( !aAllowUseArcsInPolygons )
231 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
232 aShapeOwners[ std::make_pair( aContour.
CPoint( ii - 1 ), aContour.
CPoint( ii ) ) ] = aShape;
234 if( !aAllowUseArcsInPolygons )
252 aShapeOwners[ std::make_pair( prevPt, pt ) ] = aShape;
268 for(
int ii = 0; ii <
chain.PointCount(); ++ii )
273 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
274 aShapeOwners[std::make_pair( aContour.
CPoint( ii - 1 ), aContour.
CPoint( ii ) )] = aShape;
284 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*>& aShapeOwners,
285 int aErrorMax,
int aChainingEpsilon,
bool aAllowUseArcsInPolygons )
294 nextPt = aShape->
GetEnd();
298 aContour.
Append( nextPt );
299 aShapeOwners[ std::make_pair( aPrevPt, nextPt ) ] = aShape;
309 if( !
close_enough( aPrevPt, pstart, aChainingEpsilon ) )
314 std::swap( pstart, pend );
320 arcChain.
Append( sarc, aErrorMax );
322 if( !aAllowUseArcsInPolygons )
325 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
327 aShapeOwners[ std::make_pair( arcChain.
CPoint( ii - 1 ),
328 arcChain.
CPoint( ii ) ) ] = aShape;
331 aContour.
Append( arcChain );
338 bool reverse =
false;
342 nextPt = aShape->
GetEnd();
362 aShapeOwners[ std::make_pair( aPrevPt, pt ) ] = aShape;
374 aShapeOwners[ std::make_pair( aPrevPt, pt ) ] = aShape;
386 bool reverse =
false;
388 if( !
close_enough( aPrevPt, pstart, aChainingEpsilon ) )
394 std::swap( pstart, pend );
405 for(
int ii = 0; ii < arcChain.
PointCount(); ++ii )
413 aShapeOwners[std::make_pair( aPrevPt, pt )] = aShape;
427 std::map<int, std::vector<int>> contourToParentIndexesMap;
429 for(
size_t ii = 0; ii < aContours.size(); ++ii )
431 if( aContours[ii].PointCount() < 1 )
434 VECTOR2I firstPt = aContours[ii].GetPoint( 0 );
435 std::vector<int> parents;
437 for(
size_t jj = 0; jj < aContours.size(); ++jj )
444 if( parentCandidate.
PointInside( firstPt, 0,
true ) )
445 parents.push_back( jj );
448 contourToParentIndexesMap[ii] = std::move( parents );
451 return contourToParentIndexesMap;
455 const std::map<
int, std::vector<int>>& aContourHierarchy,
458 const std::function<
PCB_SHAPE*(
const SEG&)>& aFetchOwner,
459 std::map<int, int>& aContourToOutlineIdxMap )
461 for(
const auto& [ contourIndex, parentIndexes ] : aContourHierarchy )
463 if( parentIndexes.size() % 2 == 0 )
466 if( !aAllowDisjoint && !aPolygons.
IsEmpty() )
471 BOARD_ITEM* b = aFetchOwner( aContours[ contourIndex ].GetSegment( 0 ) );
475 (*aErrorHandler)(
_(
"(multiple board outlines not supported)" ), a, b,
476 aContours[ contourIndex ].GetPoint( 0 ) );
482 aPolygons.
AddOutline( aContours[ contourIndex ] );
483 aContourToOutlineIdxMap[ contourIndex ] = aPolygons.
OutlineCount() - 1;
490 const std::map<
int, std::vector<int>>& aContourHierarchy,
491 const std::map<int, int>& aContourToOutlineIdxMap,
SHAPE_POLY_SET& aPolygons,
492 bool aAllowUseArcsInPolygons,
bool aHasMalformedOverlap )
494 if( aAllowUseArcsInPolygons || !aHasMalformedOverlap )
496 for(
const auto& [contourIndex, parentIndexes] : aContourHierarchy )
498 if( parentIndexes.size() % 2 == 1 )
503 for(
int parentContourIdx : parentIndexes )
505 if( aContourHierarchy.at( parentContourIdx ).size() == parentIndexes.size() - 1 )
507 int outlineIdx = aContourToOutlineIdxMap.at( parentContourIdx );
508 aPolygons.
AddHole( hole, outlineIdx );
522 for(
const auto& [contourIndex, parentIndexes] : aContourHierarchy )
524 if( parentIndexes.empty() )
527 if( parentIndexes.size() % 2 == 1 )
528 cutoutCandidates.
AddOutline( aContours[contourIndex] );
530 islandCandidates.
AddOutline( aContours[contourIndex] );
548 const std::function<
PCB_SHAPE*(
const SEG&)>& aFetchOwner )
550 bool selfIntersecting =
false;
551 std::vector<SEG> segments;
559 for(
int jj = 0; jj < aPolygons.
HoleCount( ii ); ++jj )
566 segments.reserve( total );
573 std::swap( segment.
A, segment.
B );
575 segments.push_back( segment );
578 std::sort( segments.begin(), segments.end(),
579 [](
const SEG& a,
const SEG& b )
582 return LexicographicalCompare( a.A, b.A ) < 0;
583 return LexicographicalCompare( a.B, b.B ) < 0;
586 for(
size_t i = 0; i < segments.size(); ++i )
588 const SEG& seg1 = segments[i];
590 for(
size_t j = i + 1; j < segments.size(); ++j )
592 const SEG& seg2 = segments[j];
594 if( seg2.
A > seg1.
B )
597 if( seg1 == seg2 || ( seg1.
A == seg2.
B && seg1.
B == seg2.
A ) )
603 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, seg1.
A );
605 selfIntersecting =
true;
613 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, *pt );
615 selfIntersecting =
true;
620 return !selfIntersecting;
627 const double query_pt[2] = {
static_cast<double>( aPoint.
x ),
static_cast<double>( aPoint.
y ) };
631 kdTree.knnSearch( query_pt, 2, indices, distances );
633 if( distances[0] == std::numeric_limits<double>::max() )
638 double closest_dist_sq = aChainingEpsilon * aChainingEpsilon;
640 for(
size_t i = 0; i < 2; ++i )
642 if( distances[i] == std::numeric_limits<double>::max() )
647 if( candidate == aShape )
650 if( distances[i] < closest_dist_sq )
652 closest_dist_sq = distances[i];
653 closest_graphic = candidate;
657 return closest_graphic;
663 for(
size_t ii = 0; ii < aContours.size(); ++ii )
665 for(
size_t jj = ii + 1; jj < aContours.size(); ++jj )
669 if( aContours[ii].Intersect( aContours[jj], intersections,
true ) != 0 )
686 int aErrorMax,
int aChainingEpsilon,
689 std::deque<PCB_SHAPE*>
chain;
690 chain.push_back( aStart );
696 std::set<PCB_SHAPE*> visited;
697 visited.insert( aStart );
699 auto extendChain = [&](
bool forward )
702 VECTOR2I prev = forward ? backPt : frontPt;
711 if(
next && aRemaining.find(
next ) == aRemaining.end() )
714 if(
next && visited.find(
next ) == visited.end() )
716 visited.insert(
next );
724 prev =
next->GetEnd();
726 prev =
next->GetStart();
735 VECTOR2I chainPt = forward ? frontPt : backPt;
753 extendChain(
false );
759 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
763 if(
chain.size() > 1 )
769 startPt = first->
GetEnd();
779 aContour.
Append( startPt );
783 processShapeSegment( shapeInChain, aContour, prevPt, shapeOwners, aErrorMax, aChainingEpsilon,
false );
794 aRemaining.erase( consumed );
802 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
806 if( aShapeList.size() == 0 )
809 bool selfIntersecting =
false;
812 std::set<PCB_SHAPE*> startCandidates( aShapeList.begin(), aShapeList.end() );
816 KDTree kdTree( 2, adaptor );
819 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
824 auto it = shapeOwners.find( std::make_pair( seg.A, seg.B ) );
825 return it == shapeOwners.end() ? nullptr : it->second;
828 std::set<std::pair<PCB_SHAPE*, PCB_SHAPE*>> reportedGaps;
829 std::vector<SHAPE_LINE_CHAIN> contours;
830 contours.reserve( startCandidates.size() );
832 for(
PCB_SHAPE* shape : startCandidates )
836 while( startCandidates.size() )
838 graphic = *startCandidates.begin();
840 aCleaner.insert( graphic );
841 startCandidates.erase( startCandidates.begin() );
843 contours.emplace_back();
851 processClosedShape( graphic, currContour, shapeOwners, aErrorMax, aAllowUseArcsInPolygons );
856 std::deque<PCB_SHAPE*>
chain;
857 chain.push_back( graphic );
863 auto extendChain = [&](
bool forward )
866 VECTOR2I prev = forward ? backPt : frontPt;
875 aCleaner.insert(
next );
876 startCandidates.erase(
next );
884 prev =
next->GetEnd();
886 prev =
next->GetStart();
895 VECTOR2I chainPt = forward ? frontPt : backPt;
904 ( *aErrorHandler )(
_(
"(self-intersecting)" ), curr,
next, prev );
906 selfIntersecting =
true;
922 extendChain(
false );
928 if(
chain.size() > 1 )
934 startPt = first->
GetEnd();
943 currContour.
Append( startPt );
949 aErrorMax, aChainingEpsilon, aAllowUseArcsInPolygons );
966 arcChain.
Append( sarc, aErrorMax );
968 if( !aAllowUseArcsInPolygons )
971 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
972 shapeOwners[std::make_pair( arcChain.
CPoint( ii - 1 ), arcChain.
CPoint( ii ) )] = owner;
975 currContour.
Append( arcChain );
981 shapeOwners[ std::make_pair( currContour.
CPoints()[currContour.
PointCount() - 2],
990 auto report_gap = [&](
const VECTOR2I& pt )
995 const double query_pt[2] = {
static_cast<double>( pt.x ),
static_cast<double>( pt.y ) };
996 uint32_t indices[2] = { 0, 0 };
1000 kdTree.knnSearch( query_pt, 2, indices, dists );
1006 auto key = std::minmax( shapeA, shapeB );
1008 if( !reportedGaps.insert( key ).second )
1017 if( effectiveShapeA && effectiveShapeB
1018 && effectiveShapeA->NearestPoints( effectiveShapeB.get(), ptA, ptB ) )
1020 midpoint = ( ptA + ptB ) / 2;
1023 ( *aErrorHandler )(
_(
"(not a closed shape)" ), shapeA, shapeB, midpoint );
1026 report_gap( currContour.
CPoint( 0 ) );
1035 if( !contour.IsClosed() )
1040 for(
size_t ii = 0; ii < contours.size(); ++ii )
1054 std::map<int, int> contourToOutlineIdxMap;
1055 if( !
addOutlinesToPolygon( contours, contourHierarchy, aPolygons, aAllowDisjoint, aErrorHandler, fetchOwner,
1056 contourToOutlineIdxMap ) )
1062 addHolesToPolygon( contours, contourHierarchy, contourToOutlineIdxMap, aPolygons, aAllowUseArcsInPolygons,
1063 hasMalformedOverlap );
1071 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
1077 aAllowDisjoint, aErrorHandler, aAllowUseArcsInPolygons,
1085 bool success =
true;
1087 int min_dist = std::max( 0, aMinDist );
1092 std::vector<PCB_SHAPE*> shapeList;
1094 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1099 shapeList.push_back( seg );
1105 switch( shape->GetShape() )
1109 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
1112 if( dim <= min_dist )
1118 (*aErrorHandler)( wxString::Format(
_(
"(rectangle has null or very small "
1119 "size: %d nm)" ), dim ),
1120 shape,
nullptr, shape->GetStart() );
1128 int r = shape->GetRadius();
1136 (*aErrorHandler)( wxString::Format(
_(
"(circle has null or very small "
1137 "radius: %d nm)" ), r ),
1138 shape,
nullptr, shape->GetStart() );
1146 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
1149 if( dim <= min_dist )
1155 (*aErrorHandler)( wxString::Format(
_(
"(segment has null or very small "
1156 "length: %d nm)" ), dim ),
1157 shape,
nullptr, shape->GetStart() );
1167 VECTOR2I arcMiddle = shape->GetArcMid();
1168 VECTOR2I seg1 = arcMiddle - shape->GetStart();
1169 VECTOR2I seg2 = shape->GetEnd() - arcMiddle;
1172 if( dim <= min_dist )
1178 (*aErrorHandler)( wxString::Format(
_(
"(arc has null or very small size: "
1180 shape,
nullptr, shape->GetStart() );
1195 const int major = shape->GetEllipseMajorRadius();
1196 const int minor = shape->GetEllipseMinorRadius();
1198 if( major <= min_dist || minor <= min_dist )
1204 ( *aErrorHandler )( wxString::Format(
_(
"(ellipse has null or very small "
1205 "radii: major=%d nm, minor=%d nm)" ),
1207 shape,
nullptr, shape->GetEllipseCenter() );
1219 std::vector<std::pair<PCB_SHAPE*, SHAPE_LINE_CHAIN>> closedContours;
1220 closedContours.reserve( shapeList.size() );
1222 std::set<PCB_SHAPE*> openShapes;
1230 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
1233 closedContours.emplace_back( shape, std::move( contour ) );
1238 openShapes.insert( shape );
1244 if( !openShapes.empty() )
1246 std::vector<PCB_SHAPE*> openShapeList( openShapes.begin(), openShapes.end() );
1248 KDTree kdTree( 2, adaptor );
1253 while( !openShapes.empty() )
1260 chainingEpsilon, contour, owner ) )
1262 closedContours.emplace_back( owner, std::move( contour ) );
1266 openShapes.erase( start );
1271 for(
size_t ii = 0; ii < closedContours.size(); ++ii )
1275 for(
size_t jj = ii + 1; jj < closedContours.size(); ++jj )
1281 if( contourA.
Intersect( contourB, intersections,
true ) == 0 )
1288 PCB_SHAPE* shapeA = closedContours[ii].first;
1289 PCB_SHAPE* shapeB = closedContours[jj].first;
1291 VECTOR2I midpoint = intersections.front().p;
1295 if( effectiveShapeA && effectiveShapeB )
1297 BOX2I bboxA = effectiveShapeA->BBox();
1298 BOX2I bboxB = effectiveShapeB->BBox();
1302 midpoint = overlapBox.
Centre();
1305 ( *aErrorHandler )(
_(
"(self-intersecting)" ), shapeA, shapeB, midpoint );
1315 int aChainingEpsilon,
bool aInferOutlineIfNecessary,
1320 bool success =
false;
1327 for(
int ii = 0; ii < items.
GetCount(); ++ii )
1335 std::vector<PCB_SHAPE*> fpSegList;
1337 for(
int ii = 0; ii < fpItems.
GetCount(); ii++ )
1342 fpSegList.push_back( fpSeg );
1345 if( !fpSegList.empty() )
1352 aAllowUseArcsInPolygons,
1362 fpHoles.
Append( fpOutlines );
1368 for(
int ii = 0; ii < fpItems.
GetCount(); ++ii )
1375 std::vector<PCB_SHAPE*> segList;
1377 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1386 segList.push_back( seg );
1389 if( segList.size() )
1392 aErrorHandler, aAllowUseArcsInPolygons, cleaner );
1395 if( ( !success || !aOutlines.
OutlineCount() ) && aInferOutlineIfNecessary )
1418 aOutlines.
Append( corner );
1424 aOutlines.
Append( corner );
1427 if( aAllowUseArcsInPolygons )
1485 chain.SetClosed(
true );
1493 int aOutlineNum = 0 )
1495 int minDistance = -1;
1500 auto seg = it.Get();
1501 int dis = seg.Distance( aEndPoint );
1503 if( minDistance < 0 || ( dis < minDistance ) )
1506 projPoint = seg.NearestPoint( aEndPoint );
1522 bool foundA =
false;
1523 bool foundB =
false;
1541 if( foundA && foundB )
1544 if( foundSegs == 0 )
1548 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1556 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1582 bool success =
false;
1590 std::vector<PCB_SHAPE*> segList;
1592 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1594 if( items[ii]->GetLayer() ==
Edge_Cuts )
1595 segList.push_back(
static_cast<PCB_SHAPE*
>( items[ii] ) );
1598 if( !segList.empty() )
1601 aErrorHandler,
false, cleaner );
1625 for(
int j = 0; j < outlines.
HoleCount( i ); j++ )
1630 aOutlines.
AddHole( hole, -1 );
1638 aOutlines = std::move( outlines );
1656 std::vector<SHAPE_LINE_CHAIN> closedChains;
1657 std::vector<SHAPE_LINE_CHAIN> openChains;
1661 openChains.push_back( outlines.
Outline( 0 ) );
1663 for(
int j = 0; j < outlines.
HoleCount( 0 ); j++ )
1670 closedChains.push_back( hole );
1675 openChains.push_back( hole );
1687 chain.SetClosed(
false );
1698 if(
chain.SegmentCount() == 0 )
1702 aOutlines = std::move( bbox );
1705 else if(
chain.SegmentCount() == 1 )
1709 wxLogTrace(
traceBoardOutline, wxT(
"Only 1 line segment in provided outline" ) );
1711 startSeg =
chain.Segment( 0 );
1719 if( inter0 && inter2 && !inter1 && !inter3 )
1722 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects only vertical bbox sides" ) );
1738 else if( inter1 && inter3 && !inter0 && !inter2 )
1741 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects only horizontal bbox sides" ) );
1760 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects two perpendicular bbox sides" ) );
1788 else if( hit1 && hit2 )
1807 else if( hit2 && hit3 )
1853 aOutlines = std::move( bbox );
1870 aOutlines = std::move( poly2 );
1875 aOutlines = std::move( poly1 );
1882 aOutlines.
AddHole( closedChain, -1 );
constexpr EDA_IU_SCALE pcbIUScale
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Information pertinent to a Pcbnew printed circuit board.
const BOX2I GetBoardEdgesBoundingBox() const
Return the board bounding box calculated using exclusively the board edges (graphics on Edge....
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
const FOOTPRINTS & Footprints() const
int GetOutlinesChainingEpsilon()
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false, bool aPhysicalLayersOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
constexpr BOX2< Vec > Intersect(const BOX2< Vec > &aRect)
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr const Vec GetEnd() const
constexpr size_type GetWidth() const
constexpr Vec Centre() const
constexpr size_type GetHeight() const
constexpr const Vec & GetOrigin() const
constexpr bool IsValid() const
int GetCount() const
Return the number of objects in the list.
A base class for most all the KiCad significant classes used in schematics and boards.
void SetFlags(EDA_ITEM_FLAGS aMask)
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
EDA_ITEM_FLAGS GetFlags() const
int GetEllipseMinorRadius() const
const VECTOR2I & GetEllipseCenter() const
EDA_ANGLE GetEllipseEndAngle() const
int GetEllipseMajorRadius() const
int GetRectangleWidth() const
SHAPE_POLY_SET & GetPolyShape()
EDA_ANGLE GetEllipseRotation() const
void RebuildBezierToSegmentsPointsList(int aMaxError)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
std::vector< VECTOR2I > GetRectCorners() const
EDA_ANGLE GetEllipseStartAngle() const
const std::vector< VECTOR2I > & GetBezierPoints() const
int GetRectangleHeight() const
int GetCornerRadius() const
VECTOR2I GetArcMid() const
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
int GetWidth() const override
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Make a set of SHAPE objects representing the PCB_SHAPE.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Collect all BOARD_ITEM objects of a given set of KICAD_T type(s).
void Collect(BOARD_ITEM *aBoard, const std::vector< KICAD_T > &aTypes)
Collect BOARD_ITEM objects using this class's Inspector method, which does the collection.
A round rectangle shape, based on a rectangle and a radius.
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aMaxError) const
Get the polygonal representation of the roundrect.
EDA_ITEM_FLAGS m_flagsToClear
SCOPED_FLAGS_CLEANER(const EDA_ITEM_FLAGS &aFlagsToClear)
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
static SEG::ecoord Square(int a)
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
bool Contains(const SEG &aSeg) const
const VECTOR2I & GetArcMid() const
const VECTOR2I & GetP0() const
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_LINE_CHAIN Reverse() const
Reverse point order in the line chain.
const SHAPE_ARC & Arc(size_t aArc) const
bool IsClosed() const override
virtual const VECTOR2I GetPoint(int aIndex) const override
void SetPoint(int aIndex, const VECTOR2I &aPos)
Move a point to a specific location.
void GenerateBBoxCache() const
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Find all intersection points between our line chain and the segment aSeg.
int PointCount() const
Return the number of points (vertices) in this line chain.
bool IsArcEnd(size_t aIndex) const
void ClearArcs()
Remove all arc references in the line chain, resulting in a chain formed only of straight segments.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
void Clear()
Remove all points from the line chain.
void SetWidth(int aWidth) override
Set the width of all segments in the chain.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
BOX2I * GetCachedBBox() const override
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
virtual const SEG GetSegment(int aIndex) const override
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
void RemoveShape(int aPointIndex)
Remove the shape at the given index from the line chain.
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
std::vector< INTERSECTION > INTERSECTIONS
const std::vector< VECTOR2I > & CPoints() const
Represent a set of closed polygons.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
CONST_ITERATOR CIterate(int aFirst, int aLast, bool aIterateHoles=false) const
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)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
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 BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
CONST_SEGMENT_ITERATOR CIterateSegments(int aFirst, int aLast, bool aIterateHoles=false) const
Return an iterator object, for iterating between aFirst and aLast outline, with or without holes (def...
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET CloneDropTriangulation() const
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
VECTOR2I projectPointOnSegment(const VECTOR2I &aEndPoint, const SHAPE_POLY_SET &aOutline, int aOutlineNum=0)
static void addHolesToPolygon(const std::vector< SHAPE_LINE_CHAIN > &aContours, const std::map< int, std::vector< int > > &aContourHierarchy, const std::map< int, int > &aContourToOutlineIdxMap, SHAPE_POLY_SET &aPolygons, bool aAllowUseArcsInPolygons, bool aHasMalformedOverlap)
bool BuildBoardPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, int aErrorMax, int aChainingEpsilon, bool aInferOutlineIfNecessary, OUTLINE_ERROR_HANDLER *aErrorHandler, bool aAllowUseArcsInPolygons)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
static bool isCopperOutside(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aShape)
static void processClosedShape(PCB_SHAPE *aShape, SHAPE_LINE_CHAIN &aContour, std::map< std::pair< VECTOR2I, VECTOR2I >, PCB_SHAPE * > &aShapeOwners, int aErrorMax, bool aAllowUseArcsInPolygons)
nanoflann::KDTreeSingleIndexAdaptor< nanoflann::L2_Simple_Adaptor< double, PCB_SHAPE_ENDPOINTS_ADAPTOR >, PCB_SHAPE_ENDPOINTS_ADAPTOR, 2 > KDTree
static bool hasOverlappingClosedContours(const std::vector< SHAPE_LINE_CHAIN > &aContours)
bool ConvertOutlineToPolygon(std::vector< PCB_SHAPE * > &aShapeList, SHAPE_POLY_SET &aPolygons, int aErrorMax, int aChainingEpsilon, bool aAllowDisjoint, OUTLINE_ERROR_HANDLER *aErrorHandler, bool aAllowUseArcsInPolygons)
Build a polygon set with holes from a PCB_SHAPE list.
bool TestBoardOutlinesGraphicItems(BOARD *aBoard, int aMinDist, OUTLINE_ERROR_HANDLER *aErrorHandler)
Test a board graphic items on edge cut layer for validity.
void buildBoardBoundingBoxPoly(const BOARD *aBoard, SHAPE_POLY_SET &aOutline)
Get the complete bounding box of the board (including all items).
int findEndSegments(SHAPE_LINE_CHAIN &aChain, SEG &aStartSeg, SEG &aEndSeg)
static bool buildChainedClosedContour(PCB_SHAPE *aStart, std::set< PCB_SHAPE * > &aRemaining, const KDTree &aKdTree, const PCB_SHAPE_ENDPOINTS_ADAPTOR &aAdaptor, int aErrorMax, int aChainingEpsilon, SHAPE_LINE_CHAIN &aContour, PCB_SHAPE *&aOwnerShape)
static bool close_enough(VECTOR2I aLeft, VECTOR2I aRight, unsigned aLimit)
Local and tunable method of qualifying the proximity of two points.
static PCB_SHAPE * findNext(PCB_SHAPE *aShape, const VECTOR2I &aPoint, const KDTree &kdTree, const PCB_SHAPE_ENDPOINTS_ADAPTOR &adaptor, double aChainingEpsilon)
static bool checkSelfIntersections(SHAPE_POLY_SET &aPolygons, OUTLINE_ERROR_HANDLER *aErrorHandler, const std::function< PCB_SHAPE *(const SEG &)> &aFetchOwner)
static std::map< int, std::vector< int > > buildContourHierarchy(const std::vector< SHAPE_LINE_CHAIN > &aContours)
static bool closer_to_first(VECTOR2I aRef, VECTOR2I aFirst, VECTOR2I aSecond)
Local method which qualifies whether the start or end point of a segment is closest to a point.
bool BuildFootprintPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, int aErrorMax, int aChainingEpsilon, OUTLINE_ERROR_HANDLER *aErrorHandler)
Extract a board outline for a footprint view.
static void processShapeSegment(PCB_SHAPE *aShape, SHAPE_LINE_CHAIN &aContour, VECTOR2I &aPrevPt, std::map< std::pair< VECTOR2I, VECTOR2I >, PCB_SHAPE * > &aShapeOwners, int aErrorMax, int aChainingEpsilon, bool aAllowUseArcsInPolygons)
static bool addOutlinesToPolygon(const std::vector< SHAPE_LINE_CHAIN > &aContours, const std::map< int, std::vector< int > > &aContourHierarchy, SHAPE_POLY_SET &aPolygons, bool aAllowDisjoint, OUTLINE_ERROR_HANDLER *aErrorHandler, const std::function< PCB_SHAPE *(const SEG &)> &aFetchOwner, std::map< int, int > &aContourToOutlineIdxMap)
bool doConvertOutlineToPolygon(std::vector< PCB_SHAPE * > &aShapeList, SHAPE_POLY_SET &aPolygons, int aErrorMax, int aChainingEpsilon, bool aAllowDisjoint, OUTLINE_ERROR_HANDLER *aErrorHandler, bool aAllowUseArcsInPolygons, SCOPED_FLAGS_CLEANER &aCleaner)
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const VECTOR2I &pt)> OUTLINE_ERROR_HANDLER
static constexpr EDA_ANGLE ANGLE_360
#define SKIP_STRUCT
flag indicating that the structure should be ignored
std::uint32_t EDA_ITEM_FLAGS
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
a few functions useful in geometry calculations.
const wxChar * traceBoardOutline
Flag to enable debug tracing for the board outline creation.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
std::optional< VECTOR2I > OPT_VECTOR2I
std::vector< std::pair< VECTOR2I, PCB_SHAPE * > > endpoints
bool kdtree_get_bbox(BBOX &) const
PCB_SHAPE_ENDPOINTS_ADAPTOR(const std::vector< PCB_SHAPE * > &shapes)
size_t kdtree_get_point_count() const
double kdtree_get_pt(const size_t idx, const size_t dim) const
const SHAPE_LINE_CHAIN chain
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
VECTOR2< int32_t > VECTOR2I
constexpr int LexicographicalCompare(const VECTOR2< T > &aA, const VECTOR2< T > &aB)