22#include <unordered_set>
44#include <nanoflann.hpp>
88 return ( aLeft - aRight ).SquaredEuclideanNorm() <=
SEG::Square( aLimit );
102 return ( aRef - aFirst ).SquaredEuclideanNorm() < ( aRef - aSecond ).SquaredEuclideanNorm();
114 return std::min( ( aPt - aSecond->
GetStart() ).SquaredEuclideanNorm(),
115 ( aPt - aSecond->
GetEnd() ).SquaredEuclideanNorm() );
125 bool padOutside =
false;
129 pad->Padstack().ForEachUniqueLayer(
141 wxLogTrace(
traceBoardOutline, wxT(
"Tested pad (%d, %d): outside" ), padPos.
x, padPos.
y );
150 wxLogTrace(
traceBoardOutline, wxT(
"Tested pad (%d, %d): not outside" ), padPos.
x, padPos.
y );
167 endpoints.emplace_back( shape->GetStart(), shape );
168 endpoints.emplace_back( shape->GetEnd(), shape );
179 return static_cast<double>(
endpoints[idx].first.x );
181 return static_cast<double>(
endpoints[idx].first.y );
184 template <
class BBOX>
191using KDTree = nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<double, PCB_SHAPE_ENDPOINTS_ADAPTOR>,
196 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*>& aShapeOwners,
197 int aErrorMax,
bool aAllowUseArcsInPolygons )
214 aShapeOwners[ std::make_pair( prevPt, pt ) ] = aShape;
230 aContour.
Append( arc360, aErrorMax );
233 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
234 aShapeOwners[ std::make_pair( aContour.
CPoint( ii-1 ), aContour.
CPoint( ii ) ) ] = aShape;
236 if( !aAllowUseArcsInPolygons )
251 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
252 aShapeOwners[ std::make_pair( aContour.
CPoint( ii - 1 ), aContour.
CPoint( ii ) ) ] = aShape;
254 if( !aAllowUseArcsInPolygons )
272 aShapeOwners[ std::make_pair( prevPt, pt ) ] = aShape;
288 for(
int ii = 0; ii <
chain.PointCount(); ++ii )
293 for(
int ii = 1; ii < aContour.
PointCount(); ++ii )
294 aShapeOwners[std::make_pair( aContour.
CPoint( ii - 1 ), aContour.
CPoint( ii ) )] = aShape;
304 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*>& aShapeOwners,
305 int aErrorMax,
int aChainingEpsilon,
bool aAllowUseArcsInPolygons )
314 nextPt = aShape->
GetEnd();
318 aContour.
Append( nextPt );
319 aShapeOwners[ std::make_pair( aPrevPt, nextPt ) ] = aShape;
333 std::swap( pstart, pend );
338 arcChain.
Append( sarc, aErrorMax );
340 if( !aAllowUseArcsInPolygons )
343 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
344 aShapeOwners[ std::make_pair( arcChain.
CPoint( ii - 1 ), arcChain.
CPoint( ii ) ) ] = aShape;
346 aContour.
Append( arcChain );
353 bool reverse =
false;
357 nextPt = aShape->
GetEnd();
377 aShapeOwners[ std::make_pair( aPrevPt, pt ) ] = aShape;
389 aShapeOwners[ std::make_pair( aPrevPt, pt ) ] = aShape;
401 bool reverse =
false;
413 std::swap( pstart, pend );
424 for(
int ii = 0; ii < arcChain.
PointCount(); ++ii )
432 aShapeOwners[std::make_pair( aPrevPt, pt )] = aShape;
446 std::map<int, std::vector<int>> contourToParentIndexesMap;
448 for(
size_t ii = 0; ii < aContours.size(); ++ii )
450 if( aContours[ii].PointCount() < 1 )
453 VECTOR2I firstPt = aContours[ii].GetPoint( 0 );
454 std::vector<int> parents;
456 for(
size_t jj = 0; jj < aContours.size(); ++jj )
463 if( parentCandidate.
PointInside( firstPt, 0,
true ) )
464 parents.push_back( jj );
467 contourToParentIndexesMap[ii] = std::move( parents );
470 return contourToParentIndexesMap;
474 const std::map<
int, std::vector<int>>& aContourHierarchy,
475 const std::set<int>& aCrossingContours,
SHAPE_POLY_SET& aPolygons,
477 const std::function<
PCB_SHAPE*(
const SEG& )>& aFetchOwner,
478 std::map<int, int>& aContourToOutlineIdxMap )
480 for(
const auto& [ contourIndex, parentIndexes ] : aContourHierarchy )
482 if( parentIndexes.size() % 2 == 0 )
485 if( !parentIndexes.empty() && aCrossingContours.count( contourIndex ) )
489 if( !aAllowDisjoint && !aPolygons.
IsEmpty() )
494 BOARD_ITEM* b = aFetchOwner( aContours[ contourIndex ].GetSegment( 0 ) );
498 (*aErrorHandler)(
_(
"(multiple board outlines not supported)" ), a, b,
499 aContours[ contourIndex ].GetPoint( 0 ) );
505 aPolygons.
AddOutline( aContours[ contourIndex ] );
506 aContourToOutlineIdxMap[ contourIndex ] = aPolygons.
OutlineCount() - 1;
513 const std::map<
int, std::vector<int>>& aContourHierarchy,
514 const std::map<int, int>& aContourToOutlineIdxMap,
SHAPE_POLY_SET& aPolygons,
515 bool aAllowUseArcsInPolygons,
const std::set<int>& aCrossingContours )
517 if( aAllowUseArcsInPolygons || aCrossingContours.empty() )
519 for(
const auto& [contourIndex, parentIndexes] : aContourHierarchy )
521 if( parentIndexes.size() % 2 == 1 )
526 for(
int parentContourIdx : parentIndexes )
528 if( aContourHierarchy.at( parentContourIdx ).size() == parentIndexes.size() - 1 )
530 int outlineIdx = aContourToOutlineIdxMap.at( parentContourIdx );
531 aPolygons.
AddHole( hole, outlineIdx );
545 for(
const auto& [contourIndex, parentIndexes] : aContourHierarchy )
547 if( parentIndexes.empty() )
550 if( parentIndexes.size() % 2 == 1 || aCrossingContours.count( contourIndex ) )
551 cutoutCandidates.
AddOutline( aContours[contourIndex] );
553 islandCandidates.
AddOutline( aContours[contourIndex] );
570 const std::function<
PCB_SHAPE*(
const SEG&)>& aFetchOwner )
572 bool selfIntersecting =
false;
573 std::vector<SEG> segments;
581 for(
int jj = 0; jj < aPolygons.
HoleCount( ii ); ++jj )
588 segments.reserve( total );
595 std::swap( segment.
A, segment.
B );
597 segments.push_back( segment );
600 std::sort( segments.begin(), segments.end(),
601 [](
const SEG& a,
const SEG& b )
604 return LexicographicalCompare( a.A, b.A ) < 0;
605 return LexicographicalCompare( a.B, b.B ) < 0;
608 for(
size_t i = 0; i < segments.size(); ++i )
610 const SEG& seg1 = segments[i];
612 for(
size_t j = i + 1; j < segments.size(); ++j )
614 const SEG& seg2 = segments[j];
616 if( seg2.
A > seg1.
B )
619 if( seg1 == seg2 || ( seg1.
A == seg2.
B && seg1.
B == seg2.
A ) )
625 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, seg1.
A );
627 selfIntersecting =
true;
635 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, *pt );
637 selfIntersecting =
true;
642 return !selfIntersecting;
654 const nanoflann::ResultItem<uint32_t, double>& aRight )
656 if( aLeft.second != aRight.second )
657 return aLeft.second < aRight.second;
659 return aLeft.first < aRight.first;
674template <
typename CONSUMED_FUNC>
677 CONSUMED_FUNC aIsConsumed )
679 const double query_pt[2] = {
static_cast<double>( aPoint.
x ),
static_cast<double>( aPoint.
y ) };
680 const double radius_sq = aChainingEpsilon * aChainingEpsilon;
682 std::vector<nanoflann::ResultItem<uint32_t, double>> matches;
683 aKdTree.radiusSearch( query_pt, radius_sq, matches );
689 for(
const nanoflann::ResultItem<uint32_t, double>& match : matches )
693 if( candidate == aShape )
711 std::set<int> crossing;
713 for(
size_t ii = 0; ii < aContours.size(); ++ii )
715 for(
size_t jj = ii + 1; jj < aContours.size(); ++jj )
717 std::vector<SHAPE_LINE_CHAIN::INTERSECTION> intersections;
719 if( aContours[ii].Intersect( aContours[jj], intersections,
true ) != 0 )
721 crossing.insert( ii );
722 crossing.insert( jj );
741 std::deque<PCB_SHAPE*>
chain;
742 chain.push_back( aStart );
748 std::set<PCB_SHAPE*> visited;
749 visited.insert( aStart );
756 return !aRemaining.contains( aCandidate ) || visited.contains( aCandidate );
763 VECTOR2I prev = forward ? backPt : frontPt;
772 visited.insert(
next.available );
780 prev =
next.available->GetEnd();
782 prev =
next.available->GetStart();
784 curr =
next.available;
789 VECTOR2I chainPt = forward ? frontPt : backPt;
806 extendChain(
false );
812 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
816 if(
chain.size() > 1 )
820 startPt =
free_end( first, second );
828 aContour.
Append( startPt );
832 processShapeSegment( shapeInChain, aContour, prevPt, shapeOwners, aErrorMax, aChainingEpsilon,
false );
843 aRemaining.erase( consumed );
851 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
855 if( aShapeList.size() == 0 )
858 bool selfIntersecting =
false;
862 std::unordered_set<PCB_SHAPE*> remaining( aShapeList.begin(), aShapeList.end() );
867 KDTree kdTree( 2, adaptor );
870 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
875 auto it = shapeOwners.find( std::make_pair( seg.A, seg.B ) );
876 return it == shapeOwners.end() ? nullptr : it->second;
879 std::set<std::pair<PCB_SHAPE*, PCB_SHAPE*>> reportedGaps;
880 std::vector<SHAPE_LINE_CHAIN> contours;
881 contours.reserve( aShapeList.size() );
889 return ( aCandidate->GetFlags() &
SKIP_STRUCT ) != 0;
893 while( !remaining.empty() )
895 while( nextSeed < aShapeList.size() && !remaining.count( aShapeList[nextSeed] ) )
898 if( nextSeed >= aShapeList.size() )
901 graphic = aShapeList[nextSeed];
903 aCleaner.insert( graphic );
904 remaining.erase( graphic );
906 contours.emplace_back();
916 processClosedShape( graphic, currContour, shapeOwners, aErrorMax, aAllowUseArcsInPolygons );
921 std::deque<PCB_SHAPE*>
chain;
922 chain.push_back( graphic );
932 VECTOR2I prev = forward ? backPt : frontPt;
942 aCleaner.insert(
next.available );
943 remaining.erase(
next.available );
951 prev =
next.available->GetEnd();
953 prev =
next.available->GetStart();
955 curr =
next.available;
959 VECTOR2I chainPt = forward ? frontPt : backPt;
965 else if(
next.consumed )
968 ( *aErrorHandler )(
_(
"(self-intersecting)" ), curr,
next.consumed, prev );
970 selfIntersecting =
true;
985 extendChain(
false );
991 if(
chain.size() > 1 )
995 startPt =
free_end( first, second );
1002 currContour.
Append( startPt );
1007 processShapeSegment( shapeInChain, currContour, prevPt, shapeOwners, aErrorMax, aChainingEpsilon,
1008 aAllowUseArcsInPolygons );
1025 arcChain.
Append( sarc, aErrorMax );
1027 if( !aAllowUseArcsInPolygons )
1030 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
1031 shapeOwners[std::make_pair( arcChain.
CPoint( ii - 1 ), arcChain.
CPoint( ii ) )] = owner;
1034 currContour.
Append( arcChain );
1040 shapeOwners[ std::make_pair( currContour.
CPoints()[currContour.
PointCount() - 2],
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 )
1093 && effectiveShapeA->NearestPoints( effectiveShapeB.get(), ptA, ptB ) )
1095 midpoint = ( ptA + ptB ) / 2;
1098 ( *aErrorHandler )(
_(
"(not a closed shape)" ), shapeA, shapeB, midpoint );
1101 report_gap( currContour.
CPoint( 0 ) );
1110 if( !contour.IsClosed() )
1117 if( !contour.GetCachedBBox()->IsValid() )
1118 contour.GenerateBBoxCache();
1124 std::set<int> crossingContours;
1126 if( !aAllowUseArcsInPolygons )
1130 std::map<int, int> contourToOutlineIdxMap;
1131 if( !
addOutlinesToPolygon( contours, contourHierarchy, crossingContours, aPolygons, aAllowDisjoint, aErrorHandler,
1132 fetchOwner, contourToOutlineIdxMap ) )
1138 addHolesToPolygon( contours, contourHierarchy, contourToOutlineIdxMap, aPolygons, aAllowUseArcsInPolygons,
1147 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
1153 aErrorHandler, aAllowUseArcsInPolygons, cleaner );
1159 bool success =
true;
1161 int min_dist = std::max( 0, aMinDist );
1166 std::vector<PCB_SHAPE*> shapeList;
1168 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1173 shapeList.push_back( seg );
1179 switch( shape->GetShape() )
1183 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
1186 if( dim <= min_dist )
1192 (*aErrorHandler)( wxString::Format(
_(
"(rectangle has null or very small size: %d nm)" ), dim ),
1193 shape,
nullptr, shape->GetStart() );
1201 int r = shape->GetRadius();
1209 (*aErrorHandler)( wxString::Format(
_(
"(circle has null or very small radius: %d nm)" ), r ),
1210 shape,
nullptr, shape->GetStart() );
1218 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
1221 if( dim <= min_dist )
1227 (*aErrorHandler)( wxString::Format(
_(
"(segment has null or very small length: %d nm)" ), dim ),
1228 shape,
nullptr, shape->GetStart() );
1238 VECTOR2I arcMiddle = shape->GetArcMid();
1239 VECTOR2I seg1 = arcMiddle - shape->GetStart();
1240 VECTOR2I seg2 = shape->GetEnd() - arcMiddle;
1243 if( dim <= min_dist )
1249 (*aErrorHandler)( wxString::Format(
_(
"(arc has null or very small size: %d nm)" ), dim ),
1250 shape,
nullptr, shape->GetStart() );
1265 const int major = shape->GetEllipseMajorRadius();
1266 const int minor = shape->GetEllipseMinorRadius();
1268 if( major <= min_dist || minor <= min_dist )
1274 ( *aErrorHandler )( wxString::Format(
_(
"(ellipse has null or very small "
1275 "radii: major=%d nm, minor=%d nm)" ),
1277 shape,
nullptr, shape->GetEllipseCenter() );
1289 std::vector<std::pair<PCB_SHAPE*, SHAPE_LINE_CHAIN>> closedContours;
1290 closedContours.reserve( shapeList.size() );
1292 std::set<PCB_SHAPE*> openShapes;
1302 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
1305 closedContours.emplace_back( shape, std::move( contour ) );
1312 openShapes.insert( shape );
1318 if( !openShapes.empty() )
1320 std::vector<PCB_SHAPE*> openShapeList( openShapes.begin(), openShapes.end() );
1322 KDTree kdTree( 2, adaptor );
1327 while( !openShapes.empty() )
1336 closedContours.emplace_back( owner, std::move( contour ) );
1340 openShapes.erase( start );
1345 for(
size_t ii = 0; ii < closedContours.size(); ++ii )
1349 for(
size_t jj = ii + 1; jj < closedContours.size(); ++jj )
1352 std::vector<SHAPE_LINE_CHAIN::INTERSECTION> intersections;
1355 if( contourA.
Intersect( contourB, intersections,
true ) == 0 )
1362 PCB_SHAPE* shapeA = closedContours[ii].first;
1363 PCB_SHAPE* shapeB = closedContours[jj].first;
1365 VECTOR2I midpoint = intersections.front().p;
1369 if( effectiveShapeA && effectiveShapeB )
1371 BOX2I bboxA = effectiveShapeA->BBox();
1372 BOX2I bboxB = effectiveShapeB->BBox();
1376 midpoint = overlapBox.
Centre();
1379 ( *aErrorHandler )(
_(
"(self-intersecting)" ), shapeA, shapeB, midpoint );
1389 int aChainingEpsilon,
bool aInferOutlineIfNecessary,
1394 bool success =
false;
1401 for(
int ii = 0; ii < items.
GetCount(); ++ii )
1409 std::vector<PCB_SHAPE*> fpSegList;
1411 for(
int ii = 0; ii < fpItems.
GetCount(); ii++ )
1416 fpSegList.push_back( fpSeg );
1419 if( !fpSegList.empty() )
1426 aAllowUseArcsInPolygons,
1436 fpHoles.
Append( fpOutlines );
1442 for(
int ii = 0; ii < fpItems.
GetCount(); ++ii )
1449 std::vector<PCB_SHAPE*> segList;
1451 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1460 segList.push_back( seg );
1463 if( segList.size() )
1466 aErrorHandler, aAllowUseArcsInPolygons, cleaner );
1469 if( ( !success || !aOutlines.
OutlineCount() ) && aInferOutlineIfNecessary )
1492 aOutlines.
Append( corner );
1498 aOutlines.
Append( corner );
1501 if( aAllowUseArcsInPolygons )
1559 chain.SetClosed(
true );
1567 int aOutlineNum = 0 )
1569 int minDistance = -1;
1574 auto seg = it.Get();
1575 int dis = seg.Distance( aEndPoint );
1577 if( minDistance < 0 || ( dis < minDistance ) )
1580 projPoint = seg.NearestPoint( aEndPoint );
1596 bool foundA =
false;
1597 bool foundB =
false;
1615 if( foundA && foundB )
1618 if( foundSegs == 0 )
1622 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1630 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1656 bool success =
false;
1664 std::vector<PCB_SHAPE*> segList;
1666 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1668 if( items[ii]->GetLayer() ==
Edge_Cuts )
1669 segList.push_back(
static_cast<PCB_SHAPE*
>( items[ii] ) );
1672 if( !segList.empty() )
1675 aErrorHandler,
false, cleaner );
1699 for(
int j = 0; j < outlines.
HoleCount( i ); j++ )
1704 aOutlines.
AddHole( hole, -1 );
1712 aOutlines = std::move( outlines );
1730 std::vector<SHAPE_LINE_CHAIN> closedChains;
1731 std::vector<SHAPE_LINE_CHAIN> openChains;
1735 openChains.push_back( outlines.
Outline( 0 ) );
1737 for(
int j = 0; j < outlines.
HoleCount( 0 ); j++ )
1744 closedChains.push_back( hole );
1749 openChains.push_back( hole );
1761 chain.SetClosed(
false );
1772 if(
chain.SegmentCount() == 0 )
1776 aOutlines = std::move( bbox );
1779 else if(
chain.SegmentCount() == 1 )
1783 wxLogTrace(
traceBoardOutline, wxT(
"Only 1 line segment in provided outline" ) );
1785 startSeg =
chain.Segment( 0 );
1793 if( inter0 && inter2 && !inter1 && !inter3 )
1796 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects only vertical bbox sides" ) );
1812 else if( inter1 && inter3 && !inter0 && !inter2 )
1815 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects only horizontal bbox sides" ) );
1834 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects two perpendicular bbox sides" ) );
1862 else if( hit1 && hit2 )
1881 else if( hit2 && hit3 )
1927 aOutlines = std::move( bbox );
1944 aOutlines = std::move( poly2 );
1949 aOutlines = std::move( poly1 );
1956 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()
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false, bool aPhysicalLayersOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
BOARD_DESIGN_SETTINGS & GetDesignSettings()
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
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.
SCOPED_FLAGS_CLEANER(const SCOPED_FLAGS_CLEANER &)=delete
EDA_ITEM_FLAGS m_flagsToClear
SCOPED_FLAGS_CLEANER(const EDA_ITEM_FLAGS &aFlagsToClear)
SCOPED_FLAGS_CLEANER & operator=(const SCOPED_FLAGS_CLEANER &)=delete
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...
int Intersect(const SEG &aSeg, std::vector< INTERSECTION > &aIp) const
Find all intersection points between our line chain and the segment aSeg.
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 SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
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.
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.
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)