26#include <unordered_set>
47#include <nanoflann.hpp>
87 return ( aLeft - aRight ).SquaredEuclideanNorm() <=
SEG::Square( aLimit );
101 return ( aRef - aFirst ).SquaredEuclideanNorm() < ( aRef - aSecond ).SquaredEuclideanNorm();
107 bool padOutside =
false;
111 pad->Padstack().ForEachUniqueLayer(
124 padPos.
x, padPos.
y );
134 padPos.
x, padPos.
y );
151 endpoints.emplace_back( shape->GetStart(), shape );
152 endpoints.emplace_back( shape->GetEnd(), shape );
163 return static_cast<double>(
endpoints[idx].first.x );
165 return static_cast<double>(
endpoints[idx].first.y );
168 template <
class BBOX>
175using KDTree = nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<double, PCB_SHAPE_ENDPOINTS_ADAPTOR>,
180 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*>& aShapeOwners,
181 int aErrorMax,
bool aAllowUseArcsInPolygons )
198 aShapeOwners[ std::make_pair( prevPt, pt ) ] = aShape;
214 aContour.
Append( arc360, aErrorMax );
217 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
218 aShapeOwners[ std::make_pair( aContour.
CPoint( ii-1 ), aContour.
CPoint( ii ) ) ] = aShape;
220 if( !aAllowUseArcsInPolygons )
235 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
236 aShapeOwners[ std::make_pair( aContour.
CPoint( ii - 1 ), aContour.
CPoint( ii ) ) ] = aShape;
238 if( !aAllowUseArcsInPolygons )
256 aShapeOwners[ std::make_pair( prevPt, pt ) ] = aShape;
272 for(
int ii = 0; ii <
chain.PointCount(); ++ii )
277 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
278 aShapeOwners[std::make_pair( aContour.
CPoint( ii - 1 ), aContour.
CPoint( ii ) )] = aShape;
288 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*>& aShapeOwners,
289 int aErrorMax,
int aChainingEpsilon,
bool aAllowUseArcsInPolygons )
298 nextPt = aShape->
GetEnd();
302 aContour.
Append( nextPt );
303 aShapeOwners[ std::make_pair( aPrevPt, nextPt ) ] = aShape;
313 if( !
close_enough( aPrevPt, pstart, aChainingEpsilon ) )
318 std::swap( pstart, pend );
324 arcChain.
Append( sarc, aErrorMax );
326 if( !aAllowUseArcsInPolygons )
329 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
331 aShapeOwners[ std::make_pair( arcChain.
CPoint( ii - 1 ),
332 arcChain.
CPoint( ii ) ) ] = aShape;
335 aContour.
Append( arcChain );
342 bool reverse =
false;
346 nextPt = aShape->
GetEnd();
366 aShapeOwners[ std::make_pair( aPrevPt, pt ) ] = aShape;
378 aShapeOwners[ std::make_pair( aPrevPt, pt ) ] = aShape;
390 bool reverse =
false;
392 if( !
close_enough( aPrevPt, pstart, aChainingEpsilon ) )
398 std::swap( pstart, pend );
409 for(
int ii = 0; ii < arcChain.
PointCount(); ++ii )
417 aShapeOwners[std::make_pair( aPrevPt, pt )] = aShape;
431 std::map<int, std::vector<int>> contourToParentIndexesMap;
433 for(
size_t ii = 0; ii < aContours.size(); ++ii )
435 if( aContours[ii].PointCount() < 1 )
438 VECTOR2I firstPt = aContours[ii].GetPoint( 0 );
439 std::vector<int> parents;
441 for(
size_t jj = 0; jj < aContours.size(); ++jj )
448 if( parentCandidate.
PointInside( firstPt, 0,
true ) )
449 parents.push_back( jj );
452 contourToParentIndexesMap[ii] = std::move( parents );
455 return contourToParentIndexesMap;
459 const std::map<
int, std::vector<int>>& aContourHierarchy,
462 const std::function<
PCB_SHAPE*(
const SEG&)>& aFetchOwner,
463 std::map<int, int>& aContourToOutlineIdxMap )
465 for(
const auto& [ contourIndex, parentIndexes ] : aContourHierarchy )
467 if( parentIndexes.size() % 2 == 0 )
470 if( !aAllowDisjoint && !aPolygons.
IsEmpty() )
475 BOARD_ITEM* b = aFetchOwner( aContours[ contourIndex ].GetSegment( 0 ) );
479 (*aErrorHandler)(
_(
"(multiple board outlines not supported)" ), a, b,
480 aContours[ contourIndex ].GetPoint( 0 ) );
486 aPolygons.
AddOutline( aContours[ contourIndex ] );
487 aContourToOutlineIdxMap[ contourIndex ] = aPolygons.
OutlineCount() - 1;
494 const std::map<
int, std::vector<int>>& aContourHierarchy,
495 const std::map<int, int>& aContourToOutlineIdxMap,
SHAPE_POLY_SET& aPolygons,
496 bool aAllowUseArcsInPolygons,
bool aHasMalformedOverlap )
498 if( aAllowUseArcsInPolygons || !aHasMalformedOverlap )
500 for(
const auto& [contourIndex, parentIndexes] : aContourHierarchy )
502 if( parentIndexes.size() % 2 == 1 )
507 for(
int parentContourIdx : parentIndexes )
509 if( aContourHierarchy.at( parentContourIdx ).size() == parentIndexes.size() - 1 )
511 int outlineIdx = aContourToOutlineIdxMap.at( parentContourIdx );
512 aPolygons.
AddHole( hole, outlineIdx );
526 for(
const auto& [contourIndex, parentIndexes] : aContourHierarchy )
528 if( parentIndexes.empty() )
531 if( parentIndexes.size() % 2 == 1 )
532 cutoutCandidates.
AddOutline( aContours[contourIndex] );
534 islandCandidates.
AddOutline( aContours[contourIndex] );
552 const std::function<
PCB_SHAPE*(
const SEG&)>& aFetchOwner )
554 bool selfIntersecting =
false;
555 std::vector<SEG> segments;
563 for(
int jj = 0; jj < aPolygons.
HoleCount( ii ); ++jj )
570 segments.reserve( total );
577 std::swap( segment.
A, segment.
B );
579 segments.push_back( segment );
582 std::sort( segments.begin(), segments.end(),
583 [](
const SEG& a,
const SEG& b )
586 return LexicographicalCompare( a.A, b.A ) < 0;
587 return LexicographicalCompare( a.B, b.B ) < 0;
590 for(
size_t i = 0; i < segments.size(); ++i )
592 const SEG& seg1 = segments[i];
594 for(
size_t j = i + 1; j < segments.size(); ++j )
596 const SEG& seg2 = segments[j];
598 if( seg2.
A > seg1.
B )
601 if( seg1 == seg2 || ( seg1.
A == seg2.
B && seg1.
B == seg2.
A ) )
607 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, seg1.
A );
609 selfIntersecting =
true;
617 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, *pt );
619 selfIntersecting =
true;
624 return !selfIntersecting;
631 const double query_pt[2] = {
static_cast<double>( aPoint.
x ),
static_cast<double>( aPoint.
y ) };
635 kdTree.knnSearch( query_pt, 2, indices, distances );
637 if( distances[0] == std::numeric_limits<double>::max() )
642 double closest_dist_sq = aChainingEpsilon * aChainingEpsilon;
644 for(
size_t i = 0; i < 2; ++i )
646 if( distances[i] == std::numeric_limits<double>::max() )
651 if( candidate == aShape )
654 if( distances[i] < closest_dist_sq )
656 closest_dist_sq = distances[i];
657 closest_graphic = candidate;
661 return closest_graphic;
667 for(
size_t ii = 0; ii < aContours.size(); ++ii )
669 for(
size_t jj = ii + 1; jj < aContours.size(); ++jj )
673 if( aContours[ii].Intersect( aContours[jj], intersections,
true ) != 0 )
690 int aErrorMax,
int aChainingEpsilon,
693 std::deque<PCB_SHAPE*>
chain;
694 chain.push_back( aStart );
700 std::set<PCB_SHAPE*> visited;
701 visited.insert( aStart );
703 auto extendChain = [&](
bool forward )
706 VECTOR2I prev = forward ? backPt : frontPt;
715 if(
next && aRemaining.find(
next ) == aRemaining.end() )
718 if(
next && visited.find(
next ) == visited.end() )
720 visited.insert(
next );
728 prev =
next->GetEnd();
730 prev =
next->GetStart();
739 VECTOR2I chainPt = forward ? frontPt : backPt;
757 extendChain(
false );
763 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
767 if(
chain.size() > 1 )
773 startPt = first->
GetEnd();
783 aContour.
Append( startPt );
787 processShapeSegment( shapeInChain, aContour, prevPt, shapeOwners, aErrorMax, aChainingEpsilon,
false );
798 aRemaining.erase( consumed );
806 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
810 if( aShapeList.size() == 0 )
813 bool selfIntersecting =
false;
816 std::set<PCB_SHAPE*> startCandidates( aShapeList.begin(), aShapeList.end() );
820 KDTree kdTree( 2, adaptor );
823 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
828 auto it = shapeOwners.find( std::make_pair( seg.A, seg.B ) );
829 return it == shapeOwners.end() ? nullptr : it->second;
832 std::set<std::pair<PCB_SHAPE*, PCB_SHAPE*>> reportedGaps;
833 std::vector<SHAPE_LINE_CHAIN> contours;
834 contours.reserve( startCandidates.size() );
836 for(
PCB_SHAPE* shape : startCandidates )
840 while( startCandidates.size() )
842 graphic = *startCandidates.begin();
844 aCleaner.insert( graphic );
845 startCandidates.erase( startCandidates.begin() );
847 contours.emplace_back();
855 processClosedShape( graphic, currContour, shapeOwners, aErrorMax, aAllowUseArcsInPolygons );
860 std::deque<PCB_SHAPE*>
chain;
861 chain.push_back( graphic );
867 auto extendChain = [&](
bool forward )
870 VECTOR2I prev = forward ? backPt : frontPt;
879 aCleaner.insert(
next );
880 startCandidates.erase(
next );
888 prev =
next->GetEnd();
890 prev =
next->GetStart();
899 VECTOR2I chainPt = forward ? frontPt : backPt;
908 ( *aErrorHandler )(
_(
"(self-intersecting)" ), curr,
next, prev );
910 selfIntersecting =
true;
926 extendChain(
false );
932 if(
chain.size() > 1 )
938 startPt = first->
GetEnd();
947 currContour.
Append( startPt );
953 aErrorMax, aChainingEpsilon, aAllowUseArcsInPolygons );
970 arcChain.
Append( sarc, aErrorMax );
972 if( !aAllowUseArcsInPolygons )
975 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
976 shapeOwners[std::make_pair( arcChain.
CPoint( ii - 1 ), arcChain.
CPoint( ii ) )] = owner;
979 currContour.
Append( arcChain );
985 shapeOwners[ std::make_pair( currContour.
CPoints()[currContour.
PointCount() - 2],
994 auto report_gap = [&](
const VECTOR2I& pt )
999 const double query_pt[2] = {
static_cast<double>( pt.x ),
static_cast<double>( pt.y ) };
1000 uint32_t indices[2] = { 0, 0 };
1004 kdTree.knnSearch( query_pt, 2, indices, dists );
1010 auto key = std::minmax( shapeA, shapeB );
1012 if( !reportedGaps.insert( key ).second )
1021 if( effectiveShapeA && effectiveShapeB
1022 && effectiveShapeA->NearestPoints( effectiveShapeB.get(), ptA, ptB ) )
1024 midpoint = ( ptA + ptB ) / 2;
1027 ( *aErrorHandler )(
_(
"(not a closed shape)" ), shapeA, shapeB, midpoint );
1030 report_gap( currContour.
CPoint( 0 ) );
1039 if( !contour.IsClosed() )
1044 for(
size_t ii = 0; ii < contours.size(); ++ii )
1058 std::map<int, int> contourToOutlineIdxMap;
1059 if( !
addOutlinesToPolygon( contours, contourHierarchy, aPolygons, aAllowDisjoint, aErrorHandler, fetchOwner,
1060 contourToOutlineIdxMap ) )
1066 addHolesToPolygon( contours, contourHierarchy, contourToOutlineIdxMap, aPolygons, aAllowUseArcsInPolygons,
1067 hasMalformedOverlap );
1075 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
1081 aAllowDisjoint, aErrorHandler, aAllowUseArcsInPolygons,
1089 bool success =
true;
1091 int min_dist = std::max( 0, aMinDist );
1096 std::vector<PCB_SHAPE*> shapeList;
1098 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1103 shapeList.push_back( seg );
1109 switch( shape->GetShape() )
1113 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
1116 if( dim <= min_dist )
1122 (*aErrorHandler)( wxString::Format(
_(
"(rectangle has null or very small "
1123 "size: %d nm)" ), dim ),
1124 shape,
nullptr, shape->GetStart() );
1132 int r = shape->GetRadius();
1140 (*aErrorHandler)( wxString::Format(
_(
"(circle has null or very small "
1141 "radius: %d nm)" ), r ),
1142 shape,
nullptr, shape->GetStart() );
1150 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
1153 if( dim <= min_dist )
1159 (*aErrorHandler)( wxString::Format(
_(
"(segment has null or very small "
1160 "length: %d nm)" ), dim ),
1161 shape,
nullptr, shape->GetStart() );
1171 VECTOR2I arcMiddle = shape->GetArcMid();
1172 VECTOR2I seg1 = arcMiddle - shape->GetStart();
1173 VECTOR2I seg2 = shape->GetEnd() - arcMiddle;
1176 if( dim <= min_dist )
1182 (*aErrorHandler)( wxString::Format(
_(
"(arc has null or very small size: "
1184 shape,
nullptr, shape->GetStart() );
1199 const int major = shape->GetEllipseMajorRadius();
1200 const int minor = shape->GetEllipseMinorRadius();
1202 if( major <= min_dist || minor <= min_dist )
1208 ( *aErrorHandler )( wxString::Format(
_(
"(ellipse has null or very small "
1209 "radii: major=%d nm, minor=%d nm)" ),
1211 shape,
nullptr, shape->GetEllipseCenter() );
1223 std::vector<std::pair<PCB_SHAPE*, SHAPE_LINE_CHAIN>> closedContours;
1224 closedContours.reserve( shapeList.size() );
1226 std::set<PCB_SHAPE*> openShapes;
1234 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
1237 closedContours.emplace_back( shape, std::move( contour ) );
1242 openShapes.insert( shape );
1248 if( !openShapes.empty() )
1250 std::vector<PCB_SHAPE*> openShapeList( openShapes.begin(), openShapes.end() );
1252 KDTree kdTree( 2, adaptor );
1257 while( !openShapes.empty() )
1264 chainingEpsilon, contour, owner ) )
1266 closedContours.emplace_back( owner, std::move( contour ) );
1270 openShapes.erase( start );
1275 for(
size_t ii = 0; ii < closedContours.size(); ++ii )
1279 for(
size_t jj = ii + 1; jj < closedContours.size(); ++jj )
1285 if( contourA.
Intersect( contourB, intersections,
true ) == 0 )
1292 PCB_SHAPE* shapeA = closedContours[ii].first;
1293 PCB_SHAPE* shapeB = closedContours[jj].first;
1295 VECTOR2I midpoint = intersections.front().p;
1299 if( effectiveShapeA && effectiveShapeB )
1301 BOX2I bboxA = effectiveShapeA->BBox();
1302 BOX2I bboxB = effectiveShapeB->BBox();
1306 midpoint = overlapBox.
Centre();
1309 ( *aErrorHandler )(
_(
"(self-intersecting)" ), shapeA, shapeB, midpoint );
1319 int aChainingEpsilon,
bool aInferOutlineIfNecessary,
1324 bool success =
false;
1331 for(
int ii = 0; ii < items.
GetCount(); ++ii )
1339 std::vector<PCB_SHAPE*> fpSegList;
1341 for(
int ii = 0; ii < fpItems.
GetCount(); ii++ )
1346 fpSegList.push_back( fpSeg );
1349 if( !fpSegList.empty() )
1356 aAllowUseArcsInPolygons,
1366 fpHoles.
Append( fpOutlines );
1372 for(
int ii = 0; ii < fpItems.
GetCount(); ++ii )
1379 std::vector<PCB_SHAPE*> segList;
1381 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1390 segList.push_back( seg );
1393 if( segList.size() )
1396 aErrorHandler, aAllowUseArcsInPolygons, cleaner );
1399 if( ( !success || !aOutlines.
OutlineCount() ) && aInferOutlineIfNecessary )
1422 aOutlines.
Append( corner );
1428 aOutlines.
Append( corner );
1431 if( aAllowUseArcsInPolygons )
1489 chain.SetClosed(
true );
1497 int aOutlineNum = 0 )
1499 int minDistance = -1;
1504 auto seg = it.Get();
1505 int dis = seg.Distance( aEndPoint );
1507 if( minDistance < 0 || ( dis < minDistance ) )
1510 projPoint = seg.NearestPoint( aEndPoint );
1526 bool foundA =
false;
1527 bool foundB =
false;
1545 if( foundA && foundB )
1548 if( foundSegs == 0 )
1552 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1560 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1586 bool success =
false;
1594 std::vector<PCB_SHAPE*> segList;
1596 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1598 if( items[ii]->GetLayer() ==
Edge_Cuts )
1599 segList.push_back(
static_cast<PCB_SHAPE*
>( items[ii] ) );
1602 if( !segList.empty() )
1605 aErrorHandler,
false, cleaner );
1629 for(
int j = 0; j < outlines.
HoleCount( i ); j++ )
1634 aOutlines.
AddHole( hole, -1 );
1642 aOutlines = std::move( outlines );
1660 std::vector<SHAPE_LINE_CHAIN> closedChains;
1661 std::vector<SHAPE_LINE_CHAIN> openChains;
1665 openChains.push_back( outlines.
Outline( 0 ) );
1667 for(
int j = 0; j < outlines.
HoleCount( 0 ); j++ )
1674 closedChains.push_back( hole );
1679 openChains.push_back( hole );
1691 chain.SetClosed(
false );
1702 if(
chain.SegmentCount() == 0 )
1706 aOutlines = std::move( bbox );
1709 else if(
chain.SegmentCount() == 1 )
1713 wxLogTrace(
traceBoardOutline, wxT(
"Only 1 line segment in provided outline" ) );
1715 startSeg =
chain.Segment( 0 );
1723 if( inter0 && inter2 && !inter1 && !inter3 )
1726 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects only vertical bbox sides" ) );
1742 else if( inter1 && inter3 && !inter0 && !inter2 )
1745 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects only horizontal bbox sides" ) );
1764 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects two perpendicular bbox sides" ) );
1792 else if( hit1 && hit2 )
1811 else if( hit2 && hit3 )
1857 aOutlines = std::move( bbox );
1874 aOutlines = std::move( poly2 );
1879 aOutlines = std::move( poly1 );
1886 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)