22#include <unordered_set>
44#include <nanoflann.hpp>
84 return ( aLeft - aRight ).SquaredEuclideanNorm() <=
SEG::Square( aLimit );
98 return ( aRef - aFirst ).SquaredEuclideanNorm() < ( aRef - aSecond ).SquaredEuclideanNorm();
110 return std::min( ( aPt - aSecond->
GetStart() ).SquaredEuclideanNorm(),
111 ( aPt - aSecond->
GetEnd() ).SquaredEuclideanNorm() );
121 bool padOutside =
false;
125 pad->Padstack().ForEachUniqueLayer(
138 padPos.
x, padPos.
y );
148 padPos.
x, padPos.
y );
165 endpoints.emplace_back( shape->GetStart(), shape );
166 endpoints.emplace_back( shape->GetEnd(), shape );
177 return static_cast<double>(
endpoints[idx].first.x );
179 return static_cast<double>(
endpoints[idx].first.y );
182 template <
class BBOX>
189using KDTree = nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<double, PCB_SHAPE_ENDPOINTS_ADAPTOR>,
194 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*>& aShapeOwners,
195 int aErrorMax,
bool aAllowUseArcsInPolygons )
212 aShapeOwners[ std::make_pair( prevPt, pt ) ] = aShape;
228 aContour.
Append( arc360, aErrorMax );
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 )
249 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
250 aShapeOwners[ std::make_pair( aContour.
CPoint( ii - 1 ), aContour.
CPoint( ii ) ) ] = aShape;
252 if( !aAllowUseArcsInPolygons )
270 aShapeOwners[ std::make_pair( prevPt, pt ) ] = aShape;
286 for(
int ii = 0; ii <
chain.PointCount(); ++ii )
291 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
292 aShapeOwners[std::make_pair( aContour.
CPoint( ii - 1 ), aContour.
CPoint( ii ) )] = aShape;
302 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*>& aShapeOwners,
303 int aErrorMax,
int aChainingEpsilon,
bool aAllowUseArcsInPolygons )
312 nextPt = aShape->
GetEnd();
316 aContour.
Append( nextPt );
317 aShapeOwners[ std::make_pair( aPrevPt, nextPt ) ] = aShape;
334 std::swap( pstart, pend );
339 arcChain.
Append( sarc, aErrorMax );
341 if( !aAllowUseArcsInPolygons )
344 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
346 aShapeOwners[ std::make_pair( arcChain.
CPoint( ii - 1 ),
347 arcChain.
CPoint( ii ) ) ] = aShape;
350 aContour.
Append( arcChain );
357 bool reverse =
false;
361 nextPt = aShape->
GetEnd();
381 aShapeOwners[ std::make_pair( aPrevPt, pt ) ] = aShape;
393 aShapeOwners[ std::make_pair( aPrevPt, pt ) ] = aShape;
405 bool reverse =
false;
417 std::swap( pstart, pend );
428 for(
int ii = 0; ii < arcChain.
PointCount(); ++ii )
436 aShapeOwners[std::make_pair( aPrevPt, pt )] = aShape;
450 std::map<int, std::vector<int>> contourToParentIndexesMap;
452 for(
size_t ii = 0; ii < aContours.size(); ++ii )
454 if( aContours[ii].PointCount() < 1 )
457 VECTOR2I firstPt = aContours[ii].GetPoint( 0 );
458 std::vector<int> parents;
460 for(
size_t jj = 0; jj < aContours.size(); ++jj )
467 if( parentCandidate.
PointInside( firstPt, 0,
true ) )
468 parents.push_back( jj );
471 contourToParentIndexesMap[ii] = std::move( parents );
474 return contourToParentIndexesMap;
478 const std::map<
int, std::vector<int>>& aContourHierarchy,
479 const std::set<int>& aCrossingContours,
SHAPE_POLY_SET& aPolygons,
481 const std::function<
PCB_SHAPE*(
const SEG& )>& aFetchOwner,
482 std::map<int, int>& aContourToOutlineIdxMap )
484 for(
const auto& [ contourIndex, parentIndexes ] : aContourHierarchy )
486 if( parentIndexes.size() % 2 == 0 )
489 if( !parentIndexes.empty() && aCrossingContours.count( contourIndex ) )
493 if( !aAllowDisjoint && !aPolygons.
IsEmpty() )
498 BOARD_ITEM* b = aFetchOwner( aContours[ contourIndex ].GetSegment( 0 ) );
502 (*aErrorHandler)(
_(
"(multiple board outlines not supported)" ), a, b,
503 aContours[ contourIndex ].GetPoint( 0 ) );
509 aPolygons.
AddOutline( aContours[ contourIndex ] );
510 aContourToOutlineIdxMap[ contourIndex ] = aPolygons.
OutlineCount() - 1;
517 const std::map<
int, std::vector<int>>& aContourHierarchy,
518 const std::map<int, int>& aContourToOutlineIdxMap,
SHAPE_POLY_SET& aPolygons,
519 bool aAllowUseArcsInPolygons,
const std::set<int>& aCrossingContours )
521 if( aAllowUseArcsInPolygons || aCrossingContours.empty() )
523 for(
const auto& [contourIndex, parentIndexes] : aContourHierarchy )
525 if( parentIndexes.size() % 2 == 1 )
530 for(
int parentContourIdx : parentIndexes )
532 if( aContourHierarchy.at( parentContourIdx ).size() == parentIndexes.size() - 1 )
534 int outlineIdx = aContourToOutlineIdxMap.at( parentContourIdx );
535 aPolygons.
AddHole( hole, outlineIdx );
549 for(
const auto& [contourIndex, parentIndexes] : aContourHierarchy )
551 if( parentIndexes.empty() )
554 if( parentIndexes.size() % 2 == 1 || aCrossingContours.count( contourIndex ) )
555 cutoutCandidates.
AddOutline( aContours[contourIndex] );
557 islandCandidates.
AddOutline( aContours[contourIndex] );
575 const std::function<
PCB_SHAPE*(
const SEG&)>& aFetchOwner )
577 bool selfIntersecting =
false;
578 std::vector<SEG> segments;
586 for(
int jj = 0; jj < aPolygons.
HoleCount( ii ); ++jj )
593 segments.reserve( total );
600 std::swap( segment.
A, segment.
B );
602 segments.push_back( segment );
605 std::sort( segments.begin(), segments.end(),
606 [](
const SEG& a,
const SEG& b )
609 return LexicographicalCompare( a.A, b.A ) < 0;
610 return LexicographicalCompare( a.B, b.B ) < 0;
613 for(
size_t i = 0; i < segments.size(); ++i )
615 const SEG& seg1 = segments[i];
617 for(
size_t j = i + 1; j < segments.size(); ++j )
619 const SEG& seg2 = segments[j];
621 if( seg2.
A > seg1.
B )
624 if( seg1 == seg2 || ( seg1.
A == seg2.
B && seg1.
B == seg2.
A ) )
630 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, seg1.
A );
632 selfIntersecting =
true;
640 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, *pt );
642 selfIntersecting =
true;
647 return !selfIntersecting;
659 const nanoflann::ResultItem<uint32_t, double>& aRight )
661 if( aLeft.second != aRight.second )
662 return aLeft.second < aRight.second;
664 return aLeft.first < aRight.first;
679template <
typename CONSUMED_FUNC>
682 CONSUMED_FUNC aIsConsumed )
684 const double query_pt[2] = {
static_cast<double>( aPoint.
x ),
static_cast<double>( aPoint.
y ) };
685 const double radius_sq = aChainingEpsilon * aChainingEpsilon;
687 std::vector<nanoflann::ResultItem<uint32_t, double>> matches;
688 aKdTree.radiusSearch( query_pt, radius_sq, matches );
694 for(
const nanoflann::ResultItem<uint32_t, double>& match : matches )
698 if( candidate == aShape )
716 std::set<int> crossing;
718 for(
size_t ii = 0; ii < aContours.size(); ++ii )
720 for(
size_t jj = ii + 1; jj < aContours.size(); ++jj )
724 if( aContours[ii].Intersect( aContours[jj], intersections,
true ) != 0 )
726 crossing.insert( ii );
727 crossing.insert( jj );
744 int aErrorMax,
int aChainingEpsilon,
747 std::deque<PCB_SHAPE*>
chain;
748 chain.push_back( aStart );
754 std::set<PCB_SHAPE*> visited;
755 visited.insert( aStart );
757 auto extendChain = [&](
bool forward )
760 VECTOR2I prev = forward ? backPt : frontPt;
770 return aRemaining.find( aCandidate ) == aRemaining.end()
771 || visited.find( aCandidate ) != visited.end();
779 visited.insert(
next.available );
787 prev =
next.available->GetEnd();
789 prev =
next.available->GetStart();
791 curr =
next.available;
796 VECTOR2I chainPt = forward ? frontPt : backPt;
813 extendChain(
false );
819 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
823 if(
chain.size() > 1 )
827 startPt =
free_end( first, second );
835 aContour.
Append( startPt );
839 processShapeSegment( shapeInChain, aContour, prevPt, shapeOwners, aErrorMax, aChainingEpsilon,
false );
850 aRemaining.erase( consumed );
858 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
862 if( aShapeList.size() == 0 )
865 bool selfIntersecting =
false;
869 std::unordered_set<PCB_SHAPE*> remaining( aShapeList.begin(), aShapeList.end() );
874 KDTree kdTree( 2, adaptor );
877 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
882 auto it = shapeOwners.find( std::make_pair( seg.A, seg.B ) );
883 return it == shapeOwners.end() ? nullptr : it->second;
886 std::set<std::pair<PCB_SHAPE*, PCB_SHAPE*>> reportedGaps;
887 std::vector<SHAPE_LINE_CHAIN> contours;
888 contours.reserve( aShapeList.size() );
894 while( !remaining.empty() )
896 while( nextSeed < aShapeList.size() && !remaining.count( aShapeList[nextSeed] ) )
899 if( nextSeed >= aShapeList.size() )
902 graphic = aShapeList[nextSeed];
904 aCleaner.insert( graphic );
905 remaining.erase( graphic );
907 contours.emplace_back();
915 processClosedShape( graphic, currContour, shapeOwners, aErrorMax, aAllowUseArcsInPolygons );
920 std::deque<PCB_SHAPE*>
chain;
921 chain.push_back( graphic );
927 auto extendChain = [&](
bool forward )
930 VECTOR2I prev = forward ? backPt : frontPt;
943 aCleaner.insert(
next.available );
944 remaining.erase(
next.available );
952 prev =
next.available->GetEnd();
954 prev =
next.available->GetStart();
956 curr =
next.available;
960 VECTOR2I chainPt = forward ? frontPt : backPt;
966 else if(
next.consumed )
969 ( *aErrorHandler )(
_(
"(self-intersecting)" ), curr,
next.consumed, prev );
971 selfIntersecting =
true;
986 extendChain(
false );
992 if(
chain.size() > 1 )
996 startPt =
free_end( first, second );
1003 currContour.
Append( startPt );
1009 aErrorMax, aChainingEpsilon, aAllowUseArcsInPolygons );
1026 arcChain.
Append( sarc, aErrorMax );
1028 if( !aAllowUseArcsInPolygons )
1031 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
1032 shapeOwners[std::make_pair( arcChain.
CPoint( ii - 1 ), arcChain.
CPoint( ii ) )] = owner;
1035 currContour.
Append( arcChain );
1041 shapeOwners[ std::make_pair( currContour.
CPoints()[currContour.
PointCount() - 2],
1050 auto report_gap = [&](
const VECTOR2I& pt )
1052 if( !aErrorHandler )
1055 const double query_pt[2] = {
static_cast<double>( pt.x ),
static_cast<double>( pt.y ) };
1058 uint32_t indices[8] = { 0 };
1061 const size_t found = kdTree.knnSearch( query_pt, 8, indices, dists );
1070 for(
size_t ii = 1; ii < found; ++ii )
1072 if( adaptor.
endpoints[indices[ii]].second != shapeA )
1074 shapeB = adaptor.
endpoints[indices[ii]].second;
1080 auto key = std::minmax( shapeA, shapeB );
1082 if( !reportedGaps.insert( key ).second )
1091 if( effectiveShapeA && effectiveShapeB
1092 && effectiveShapeA->NearestPoints( effectiveShapeB.get(), ptA, ptB ) )
1094 midpoint = ( ptA + ptB ) / 2;
1097 ( *aErrorHandler )(
_(
"(not a closed shape)" ), shapeA, shapeB, midpoint );
1100 report_gap( currContour.
CPoint( 0 ) );
1109 if( !contour.IsClosed() )
1114 for(
size_t ii = 0; ii < contours.size(); ++ii )
1125 std::set<int> crossingContours;
1127 if( !aAllowUseArcsInPolygons )
1131 std::map<int, int> contourToOutlineIdxMap;
1132 if( !
addOutlinesToPolygon( contours, contourHierarchy, crossingContours, aPolygons, aAllowDisjoint, aErrorHandler,
1133 fetchOwner, contourToOutlineIdxMap ) )
1139 addHolesToPolygon( contours, contourHierarchy, contourToOutlineIdxMap, aPolygons, aAllowUseArcsInPolygons,
1148 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
1154 aAllowDisjoint, aErrorHandler, aAllowUseArcsInPolygons,
1162 bool success =
true;
1164 int min_dist = std::max( 0, aMinDist );
1169 std::vector<PCB_SHAPE*> shapeList;
1171 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1176 shapeList.push_back( seg );
1182 switch( shape->GetShape() )
1186 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
1189 if( dim <= min_dist )
1195 (*aErrorHandler)( wxString::Format(
_(
"(rectangle has null or very small "
1196 "size: %d nm)" ), dim ),
1197 shape,
nullptr, shape->GetStart() );
1205 int r = shape->GetRadius();
1213 (*aErrorHandler)( wxString::Format(
_(
"(circle has null or very small "
1214 "radius: %d nm)" ), r ),
1215 shape,
nullptr, shape->GetStart() );
1223 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
1226 if( dim <= min_dist )
1232 (*aErrorHandler)( wxString::Format(
_(
"(segment has null or very small "
1233 "length: %d nm)" ), dim ),
1234 shape,
nullptr, shape->GetStart() );
1244 VECTOR2I arcMiddle = shape->GetArcMid();
1245 VECTOR2I seg1 = arcMiddle - shape->GetStart();
1246 VECTOR2I seg2 = shape->GetEnd() - arcMiddle;
1249 if( dim <= min_dist )
1255 (*aErrorHandler)( wxString::Format(
_(
"(arc has null or very small size: "
1257 shape,
nullptr, shape->GetStart() );
1272 const int major = shape->GetEllipseMajorRadius();
1273 const int minor = shape->GetEllipseMinorRadius();
1275 if( major <= min_dist || minor <= min_dist )
1281 ( *aErrorHandler )( wxString::Format(
_(
"(ellipse has null or very small "
1282 "radii: major=%d nm, minor=%d nm)" ),
1284 shape,
nullptr, shape->GetEllipseCenter() );
1296 std::vector<std::pair<PCB_SHAPE*, SHAPE_LINE_CHAIN>> closedContours;
1297 closedContours.reserve( shapeList.size() );
1299 std::set<PCB_SHAPE*> openShapes;
1307 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
1310 closedContours.emplace_back( shape, std::move( contour ) );
1315 openShapes.insert( shape );
1321 if( !openShapes.empty() )
1323 std::vector<PCB_SHAPE*> openShapeList( openShapes.begin(), openShapes.end() );
1325 KDTree kdTree( 2, adaptor );
1330 while( !openShapes.empty() )
1337 chainingEpsilon, contour, owner ) )
1339 closedContours.emplace_back( owner, std::move( contour ) );
1343 openShapes.erase( start );
1348 for(
size_t ii = 0; ii < closedContours.size(); ++ii )
1352 for(
size_t jj = ii + 1; jj < closedContours.size(); ++jj )
1358 if( contourA.
Intersect( contourB, intersections,
true ) == 0 )
1365 PCB_SHAPE* shapeA = closedContours[ii].first;
1366 PCB_SHAPE* shapeB = closedContours[jj].first;
1368 VECTOR2I midpoint = intersections.front().p;
1372 if( effectiveShapeA && effectiveShapeB )
1374 BOX2I bboxA = effectiveShapeA->BBox();
1375 BOX2I bboxB = effectiveShapeB->BBox();
1379 midpoint = overlapBox.
Centre();
1382 ( *aErrorHandler )(
_(
"(self-intersecting)" ), shapeA, shapeB, midpoint );
1392 int aChainingEpsilon,
bool aInferOutlineIfNecessary,
1397 bool success =
false;
1404 for(
int ii = 0; ii < items.
GetCount(); ++ii )
1412 std::vector<PCB_SHAPE*> fpSegList;
1414 for(
int ii = 0; ii < fpItems.
GetCount(); ii++ )
1419 fpSegList.push_back( fpSeg );
1422 if( !fpSegList.empty() )
1429 aAllowUseArcsInPolygons,
1439 fpHoles.
Append( fpOutlines );
1445 for(
int ii = 0; ii < fpItems.
GetCount(); ++ii )
1452 std::vector<PCB_SHAPE*> segList;
1454 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1463 segList.push_back( seg );
1466 if( segList.size() )
1469 aErrorHandler, aAllowUseArcsInPolygons, cleaner );
1472 if( ( !success || !aOutlines.
OutlineCount() ) && aInferOutlineIfNecessary )
1495 aOutlines.
Append( corner );
1501 aOutlines.
Append( corner );
1504 if( aAllowUseArcsInPolygons )
1562 chain.SetClosed(
true );
1570 int aOutlineNum = 0 )
1572 int minDistance = -1;
1577 auto seg = it.Get();
1578 int dis = seg.Distance( aEndPoint );
1580 if( minDistance < 0 || ( dis < minDistance ) )
1583 projPoint = seg.NearestPoint( aEndPoint );
1599 bool foundA =
false;
1600 bool foundB =
false;
1618 if( foundA && foundB )
1621 if( foundSegs == 0 )
1625 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1633 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1659 bool success =
false;
1667 std::vector<PCB_SHAPE*> segList;
1669 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1671 if( items[ii]->GetLayer() ==
Edge_Cuts )
1672 segList.push_back(
static_cast<PCB_SHAPE*
>( items[ii] ) );
1675 if( !segList.empty() )
1678 aErrorHandler,
false, cleaner );
1702 for(
int j = 0; j < outlines.
HoleCount( i ); j++ )
1707 aOutlines.
AddHole( hole, -1 );
1715 aOutlines = std::move( outlines );
1733 std::vector<SHAPE_LINE_CHAIN> closedChains;
1734 std::vector<SHAPE_LINE_CHAIN> openChains;
1738 openChains.push_back( outlines.
Outline( 0 ) );
1740 for(
int j = 0; j < outlines.
HoleCount( 0 ); j++ )
1747 closedChains.push_back( hole );
1752 openChains.push_back( hole );
1764 chain.SetClosed(
false );
1775 if(
chain.SegmentCount() == 0 )
1779 aOutlines = std::move( bbox );
1782 else if(
chain.SegmentCount() == 1 )
1786 wxLogTrace(
traceBoardOutline, wxT(
"Only 1 line segment in provided outline" ) );
1788 startSeg =
chain.Segment( 0 );
1796 if( inter0 && inter2 && !inter1 && !inter3 )
1799 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects only vertical bbox sides" ) );
1815 else if( inter1 && inter3 && !inter0 && !inter2 )
1818 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects only horizontal bbox sides" ) );
1837 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects two perpendicular bbox sides" ) );
1865 else if( hit1 && hit2 )
1884 else if( hit2 && hit3 )
1930 aOutlines = std::move( bbox );
1947 aOutlines = std::move( poly2 );
1952 aOutlines = std::move( poly1 );
1959 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, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) 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 closerEndpoint(const nanoflann::ResultItem< uint32_t, double > &aLeft, const nanoflann::ResultItem< uint32_t, double > &aRight)
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 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 CHAIN_NEIGHBOURS findNeighbours(PCB_SHAPE *aShape, const VECTOR2I &aPoint, const KDTree &aKdTree, const PCB_SHAPE_ENDPOINTS_ADAPTOR &aAdaptor, double aChainingEpsilon, CONSUMED_FUNC aIsConsumed)
Find the shapes that could continue a chain at aPoint.
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 VECTOR2I free_end(const PCB_SHAPE *aFirst, const PCB_SHAPE *aSecond)
Return the end of aFirst that does not join aSecond.
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
PCB_SHAPE * available
nearest unchained
PCB_SHAPE * consumed
nearest already chained
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
wxString result
Test unit parsing edge cases and error handling.
@ 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)