22#include <unordered_set>
44#include <nanoflann.hpp>
84 return ( aLeft - aRight ).SquaredEuclideanNorm() <=
SEG::Square( aLimit );
98 return ( aRef - aFirst ).SquaredEuclideanNorm() < ( aRef - aSecond ).SquaredEuclideanNorm();
104 bool padOutside =
false;
108 pad->Padstack().ForEachUniqueLayer(
121 padPos.
x, padPos.
y );
131 padPos.
x, padPos.
y );
148 endpoints.emplace_back( shape->GetStart(), shape );
149 endpoints.emplace_back( shape->GetEnd(), shape );
160 return static_cast<double>(
endpoints[idx].first.x );
162 return static_cast<double>(
endpoints[idx].first.y );
165 template <
class BBOX>
172using KDTree = nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<double, PCB_SHAPE_ENDPOINTS_ADAPTOR>,
177 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*>& aShapeOwners,
178 int aErrorMax,
bool aAllowUseArcsInPolygons )
195 aShapeOwners[ std::make_pair( prevPt, pt ) ] = aShape;
211 aContour.
Append( arc360, aErrorMax );
214 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
215 aShapeOwners[ std::make_pair( aContour.
CPoint( ii-1 ), aContour.
CPoint( ii ) ) ] = aShape;
217 if( !aAllowUseArcsInPolygons )
232 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
233 aShapeOwners[ std::make_pair( aContour.
CPoint( ii - 1 ), aContour.
CPoint( ii ) ) ] = aShape;
235 if( !aAllowUseArcsInPolygons )
253 aShapeOwners[ std::make_pair( prevPt, pt ) ] = aShape;
269 for(
int ii = 0; ii <
chain.PointCount(); ++ii )
274 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
275 aShapeOwners[std::make_pair( aContour.
CPoint( ii - 1 ), aContour.
CPoint( ii ) )] = aShape;
285 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*>& aShapeOwners,
286 int aErrorMax,
int aChainingEpsilon,
bool aAllowUseArcsInPolygons )
295 nextPt = aShape->
GetEnd();
299 aContour.
Append( nextPt );
300 aShapeOwners[ std::make_pair( aPrevPt, nextPt ) ] = aShape;
310 if( !
close_enough( aPrevPt, pstart, aChainingEpsilon ) )
315 std::swap( pstart, pend );
321 arcChain.
Append( sarc, aErrorMax );
323 if( !aAllowUseArcsInPolygons )
326 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
328 aShapeOwners[ std::make_pair( arcChain.
CPoint( ii - 1 ),
329 arcChain.
CPoint( ii ) ) ] = aShape;
332 aContour.
Append( arcChain );
339 bool reverse =
false;
343 nextPt = aShape->
GetEnd();
363 aShapeOwners[ std::make_pair( aPrevPt, pt ) ] = aShape;
375 aShapeOwners[ std::make_pair( aPrevPt, pt ) ] = aShape;
387 bool reverse =
false;
389 if( !
close_enough( aPrevPt, pstart, aChainingEpsilon ) )
395 std::swap( pstart, pend );
406 for(
int ii = 0; ii < arcChain.
PointCount(); ++ii )
414 aShapeOwners[std::make_pair( aPrevPt, pt )] = aShape;
428 std::map<int, std::vector<int>> contourToParentIndexesMap;
430 for(
size_t ii = 0; ii < aContours.size(); ++ii )
432 if( aContours[ii].PointCount() < 1 )
435 VECTOR2I firstPt = aContours[ii].GetPoint( 0 );
436 std::vector<int> parents;
438 for(
size_t jj = 0; jj < aContours.size(); ++jj )
445 if( parentCandidate.
PointInside( firstPt, 0,
true ) )
446 parents.push_back( jj );
449 contourToParentIndexesMap[ii] = std::move( parents );
452 return contourToParentIndexesMap;
456 const std::map<
int, std::vector<int>>& aContourHierarchy,
457 const std::set<int>& aCrossingContours,
SHAPE_POLY_SET& aPolygons,
459 const std::function<
PCB_SHAPE*(
const SEG& )>& aFetchOwner,
460 std::map<int, int>& aContourToOutlineIdxMap )
462 for(
const auto& [ contourIndex, parentIndexes ] : aContourHierarchy )
464 if( parentIndexes.size() % 2 == 0 )
467 if( !parentIndexes.empty() && aCrossingContours.count( contourIndex ) )
471 if( !aAllowDisjoint && !aPolygons.
IsEmpty() )
476 BOARD_ITEM* b = aFetchOwner( aContours[ contourIndex ].GetSegment( 0 ) );
480 (*aErrorHandler)(
_(
"(multiple board outlines not supported)" ), a, b,
481 aContours[ contourIndex ].GetPoint( 0 ) );
487 aPolygons.
AddOutline( aContours[ contourIndex ] );
488 aContourToOutlineIdxMap[ contourIndex ] = aPolygons.
OutlineCount() - 1;
495 const std::map<
int, std::vector<int>>& aContourHierarchy,
496 const std::map<int, int>& aContourToOutlineIdxMap,
SHAPE_POLY_SET& aPolygons,
497 bool aAllowUseArcsInPolygons,
const std::set<int>& aCrossingContours )
499 if( aAllowUseArcsInPolygons || aCrossingContours.empty() )
501 for(
const auto& [contourIndex, parentIndexes] : aContourHierarchy )
503 if( parentIndexes.size() % 2 == 1 )
508 for(
int parentContourIdx : parentIndexes )
510 if( aContourHierarchy.at( parentContourIdx ).size() == parentIndexes.size() - 1 )
512 int outlineIdx = aContourToOutlineIdxMap.at( parentContourIdx );
513 aPolygons.
AddHole( hole, outlineIdx );
527 for(
const auto& [contourIndex, parentIndexes] : aContourHierarchy )
529 if( parentIndexes.empty() )
532 if( parentIndexes.size() % 2 == 1 || aCrossingContours.count( contourIndex ) )
533 cutoutCandidates.
AddOutline( aContours[contourIndex] );
535 islandCandidates.
AddOutline( aContours[contourIndex] );
553 const std::function<
PCB_SHAPE*(
const SEG&)>& aFetchOwner )
555 bool selfIntersecting =
false;
556 std::vector<SEG> segments;
564 for(
int jj = 0; jj < aPolygons.
HoleCount( ii ); ++jj )
571 segments.reserve( total );
578 std::swap( segment.
A, segment.
B );
580 segments.push_back( segment );
583 std::sort( segments.begin(), segments.end(),
584 [](
const SEG& a,
const SEG& b )
587 return LexicographicalCompare( a.A, b.A ) < 0;
588 return LexicographicalCompare( a.B, b.B ) < 0;
591 for(
size_t i = 0; i < segments.size(); ++i )
593 const SEG& seg1 = segments[i];
595 for(
size_t j = i + 1; j < segments.size(); ++j )
597 const SEG& seg2 = segments[j];
599 if( seg2.
A > seg1.
B )
602 if( seg1 == seg2 || ( seg1.
A == seg2.
B && seg1.
B == seg2.
A ) )
608 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, seg1.
A );
610 selfIntersecting =
true;
618 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, *pt );
620 selfIntersecting =
true;
625 return !selfIntersecting;
632 const double query_pt[2] = {
static_cast<double>( aPoint.
x ),
static_cast<double>( aPoint.
y ) };
636 kdTree.knnSearch( query_pt, 2, indices, distances );
638 if( distances[0] == std::numeric_limits<double>::max() )
643 double closest_dist_sq = aChainingEpsilon * aChainingEpsilon;
645 for(
size_t i = 0; i < 2; ++i )
647 if( distances[i] == std::numeric_limits<double>::max() )
652 if( candidate == aShape )
655 if( distances[i] < closest_dist_sq )
657 closest_dist_sq = distances[i];
658 closest_graphic = candidate;
662 return closest_graphic;
668 std::set<int> crossing;
670 for(
size_t ii = 0; ii < aContours.size(); ++ii )
672 for(
size_t jj = ii + 1; jj < aContours.size(); ++jj )
676 if( aContours[ii].Intersect( aContours[jj], intersections,
true ) != 0 )
678 crossing.insert( ii );
679 crossing.insert( jj );
696 int aErrorMax,
int aChainingEpsilon,
699 std::deque<PCB_SHAPE*>
chain;
700 chain.push_back( aStart );
706 std::set<PCB_SHAPE*> visited;
707 visited.insert( aStart );
709 auto extendChain = [&](
bool forward )
712 VECTOR2I prev = forward ? backPt : frontPt;
721 if(
next && aRemaining.find(
next ) == aRemaining.end() )
724 if(
next && visited.find(
next ) == visited.end() )
726 visited.insert(
next );
734 prev =
next->GetEnd();
736 prev =
next->GetStart();
745 VECTOR2I chainPt = forward ? frontPt : backPt;
763 extendChain(
false );
769 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
773 if(
chain.size() > 1 )
779 startPt = first->
GetEnd();
789 aContour.
Append( startPt );
793 processShapeSegment( shapeInChain, aContour, prevPt, shapeOwners, aErrorMax, aChainingEpsilon,
false );
804 aRemaining.erase( consumed );
812 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
816 if( aShapeList.size() == 0 )
819 bool selfIntersecting =
false;
822 std::set<PCB_SHAPE*> startCandidates( aShapeList.begin(), aShapeList.end() );
826 KDTree kdTree( 2, adaptor );
829 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
834 auto it = shapeOwners.find( std::make_pair( seg.A, seg.B ) );
835 return it == shapeOwners.end() ? nullptr : it->second;
838 std::set<std::pair<PCB_SHAPE*, PCB_SHAPE*>> reportedGaps;
839 std::vector<SHAPE_LINE_CHAIN> contours;
840 contours.reserve( startCandidates.size() );
842 for(
PCB_SHAPE* shape : startCandidates )
846 while( startCandidates.size() )
848 graphic = *startCandidates.begin();
850 aCleaner.insert( graphic );
851 startCandidates.erase( startCandidates.begin() );
853 contours.emplace_back();
861 processClosedShape( graphic, currContour, shapeOwners, aErrorMax, aAllowUseArcsInPolygons );
866 std::deque<PCB_SHAPE*>
chain;
867 chain.push_back( graphic );
873 auto extendChain = [&](
bool forward )
876 VECTOR2I prev = forward ? backPt : frontPt;
885 aCleaner.insert(
next );
886 startCandidates.erase(
next );
894 prev =
next->GetEnd();
896 prev =
next->GetStart();
905 VECTOR2I chainPt = forward ? frontPt : backPt;
914 ( *aErrorHandler )(
_(
"(self-intersecting)" ), curr,
next, prev );
916 selfIntersecting =
true;
932 extendChain(
false );
938 if(
chain.size() > 1 )
944 startPt = first->
GetEnd();
953 currContour.
Append( startPt );
959 aErrorMax, aChainingEpsilon, aAllowUseArcsInPolygons );
976 arcChain.
Append( sarc, aErrorMax );
978 if( !aAllowUseArcsInPolygons )
981 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
982 shapeOwners[std::make_pair( arcChain.
CPoint( ii - 1 ), arcChain.
CPoint( ii ) )] = owner;
985 currContour.
Append( arcChain );
991 shapeOwners[ std::make_pair( currContour.
CPoints()[currContour.
PointCount() - 2],
1000 auto report_gap = [&](
const VECTOR2I& pt )
1002 if( !aErrorHandler )
1005 const double query_pt[2] = {
static_cast<double>( pt.x ),
static_cast<double>( pt.y ) };
1006 uint32_t indices[2] = { 0, 0 };
1010 kdTree.knnSearch( query_pt, 2, indices, dists );
1016 auto key = std::minmax( shapeA, shapeB );
1018 if( !reportedGaps.insert( key ).second )
1027 if( effectiveShapeA && effectiveShapeB
1028 && effectiveShapeA->NearestPoints( effectiveShapeB.get(), ptA, ptB ) )
1030 midpoint = ( ptA + ptB ) / 2;
1033 ( *aErrorHandler )(
_(
"(not a closed shape)" ), shapeA, shapeB, midpoint );
1036 report_gap( currContour.
CPoint( 0 ) );
1045 if( !contour.IsClosed() )
1050 for(
size_t ii = 0; ii < contours.size(); ++ii )
1061 std::set<int> crossingContours;
1063 if( !aAllowUseArcsInPolygons )
1067 std::map<int, int> contourToOutlineIdxMap;
1068 if( !
addOutlinesToPolygon( contours, contourHierarchy, crossingContours, aPolygons, aAllowDisjoint, aErrorHandler,
1069 fetchOwner, contourToOutlineIdxMap ) )
1075 addHolesToPolygon( contours, contourHierarchy, contourToOutlineIdxMap, aPolygons, aAllowUseArcsInPolygons,
1084 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
1090 aAllowDisjoint, aErrorHandler, aAllowUseArcsInPolygons,
1098 bool success =
true;
1100 int min_dist = std::max( 0, aMinDist );
1105 std::vector<PCB_SHAPE*> shapeList;
1107 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1112 shapeList.push_back( seg );
1118 switch( shape->GetShape() )
1122 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
1125 if( dim <= min_dist )
1131 (*aErrorHandler)( wxString::Format(
_(
"(rectangle has null or very small "
1132 "size: %d nm)" ), dim ),
1133 shape,
nullptr, shape->GetStart() );
1141 int r = shape->GetRadius();
1149 (*aErrorHandler)( wxString::Format(
_(
"(circle has null or very small "
1150 "radius: %d nm)" ), r ),
1151 shape,
nullptr, shape->GetStart() );
1159 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
1162 if( dim <= min_dist )
1168 (*aErrorHandler)( wxString::Format(
_(
"(segment has null or very small "
1169 "length: %d nm)" ), dim ),
1170 shape,
nullptr, shape->GetStart() );
1180 VECTOR2I arcMiddle = shape->GetArcMid();
1181 VECTOR2I seg1 = arcMiddle - shape->GetStart();
1182 VECTOR2I seg2 = shape->GetEnd() - arcMiddle;
1185 if( dim <= min_dist )
1191 (*aErrorHandler)( wxString::Format(
_(
"(arc has null or very small size: "
1193 shape,
nullptr, shape->GetStart() );
1208 const int major = shape->GetEllipseMajorRadius();
1209 const int minor = shape->GetEllipseMinorRadius();
1211 if( major <= min_dist || minor <= min_dist )
1217 ( *aErrorHandler )( wxString::Format(
_(
"(ellipse has null or very small "
1218 "radii: major=%d nm, minor=%d nm)" ),
1220 shape,
nullptr, shape->GetEllipseCenter() );
1232 std::vector<std::pair<PCB_SHAPE*, SHAPE_LINE_CHAIN>> closedContours;
1233 closedContours.reserve( shapeList.size() );
1235 std::set<PCB_SHAPE*> openShapes;
1243 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
1246 closedContours.emplace_back( shape, std::move( contour ) );
1251 openShapes.insert( shape );
1257 if( !openShapes.empty() )
1259 std::vector<PCB_SHAPE*> openShapeList( openShapes.begin(), openShapes.end() );
1261 KDTree kdTree( 2, adaptor );
1266 while( !openShapes.empty() )
1273 chainingEpsilon, contour, owner ) )
1275 closedContours.emplace_back( owner, std::move( contour ) );
1279 openShapes.erase( start );
1284 for(
size_t ii = 0; ii < closedContours.size(); ++ii )
1288 for(
size_t jj = ii + 1; jj < closedContours.size(); ++jj )
1294 if( contourA.
Intersect( contourB, intersections,
true ) == 0 )
1301 PCB_SHAPE* shapeA = closedContours[ii].first;
1302 PCB_SHAPE* shapeB = closedContours[jj].first;
1304 VECTOR2I midpoint = intersections.front().p;
1308 if( effectiveShapeA && effectiveShapeB )
1310 BOX2I bboxA = effectiveShapeA->BBox();
1311 BOX2I bboxB = effectiveShapeB->BBox();
1315 midpoint = overlapBox.
Centre();
1318 ( *aErrorHandler )(
_(
"(self-intersecting)" ), shapeA, shapeB, midpoint );
1328 int aChainingEpsilon,
bool aInferOutlineIfNecessary,
1333 bool success =
false;
1340 for(
int ii = 0; ii < items.
GetCount(); ++ii )
1348 std::vector<PCB_SHAPE*> fpSegList;
1350 for(
int ii = 0; ii < fpItems.
GetCount(); ii++ )
1355 fpSegList.push_back( fpSeg );
1358 if( !fpSegList.empty() )
1365 aAllowUseArcsInPolygons,
1375 fpHoles.
Append( fpOutlines );
1381 for(
int ii = 0; ii < fpItems.
GetCount(); ++ii )
1388 std::vector<PCB_SHAPE*> segList;
1390 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1399 segList.push_back( seg );
1402 if( segList.size() )
1405 aErrorHandler, aAllowUseArcsInPolygons, cleaner );
1408 if( ( !success || !aOutlines.
OutlineCount() ) && aInferOutlineIfNecessary )
1431 aOutlines.
Append( corner );
1437 aOutlines.
Append( corner );
1440 if( aAllowUseArcsInPolygons )
1498 chain.SetClosed(
true );
1506 int aOutlineNum = 0 )
1508 int minDistance = -1;
1513 auto seg = it.Get();
1514 int dis = seg.Distance( aEndPoint );
1516 if( minDistance < 0 || ( dis < minDistance ) )
1519 projPoint = seg.NearestPoint( aEndPoint );
1535 bool foundA =
false;
1536 bool foundB =
false;
1554 if( foundA && foundB )
1557 if( foundSegs == 0 )
1561 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1569 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1595 bool success =
false;
1603 std::vector<PCB_SHAPE*> segList;
1605 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1607 if( items[ii]->GetLayer() ==
Edge_Cuts )
1608 segList.push_back(
static_cast<PCB_SHAPE*
>( items[ii] ) );
1611 if( !segList.empty() )
1614 aErrorHandler,
false, cleaner );
1638 for(
int j = 0; j < outlines.
HoleCount( i ); j++ )
1643 aOutlines.
AddHole( hole, -1 );
1651 aOutlines = std::move( outlines );
1669 std::vector<SHAPE_LINE_CHAIN> closedChains;
1670 std::vector<SHAPE_LINE_CHAIN> openChains;
1674 openChains.push_back( outlines.
Outline( 0 ) );
1676 for(
int j = 0; j < outlines.
HoleCount( 0 ); j++ )
1683 closedChains.push_back( hole );
1688 openChains.push_back( hole );
1700 chain.SetClosed(
false );
1711 if(
chain.SegmentCount() == 0 )
1715 aOutlines = std::move( bbox );
1718 else if(
chain.SegmentCount() == 1 )
1722 wxLogTrace(
traceBoardOutline, wxT(
"Only 1 line segment in provided outline" ) );
1724 startSeg =
chain.Segment( 0 );
1732 if( inter0 && inter2 && !inter1 && !inter3 )
1735 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects only vertical bbox sides" ) );
1751 else if( inter1 && inter3 && !inter0 && !inter2 )
1754 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects only horizontal bbox sides" ) );
1773 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects two perpendicular bbox sides" ) );
1801 else if( hit1 && hit2 )
1820 else if( hit2 && hit3 )
1866 aOutlines = std::move( bbox );
1883 aOutlines = std::move( poly2 );
1888 aOutlines = std::move( poly1 );
1895 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, const std::set< int > &aCrossingContours)
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 addOutlinesToPolygon(const std::vector< SHAPE_LINE_CHAIN > &aContours, const std::map< int, std::vector< int > > &aContourHierarchy, const std::set< int > &aCrossingContours, SHAPE_POLY_SET &aPolygons, bool aAllowDisjoint, OUTLINE_ERROR_HANDLER *aErrorHandler, const std::function< PCB_SHAPE *(const SEG &)> &aFetchOwner, std::map< int, int > &aContourToOutlineIdxMap)
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
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.
static std::set< int > findCrossingContours(const std::vector< SHAPE_LINE_CHAIN > &aContours)
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)
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)