26#include <unordered_set>
81 return ( aLeft - aRight ).SquaredEuclideanNorm() <=
SEG::Square( aLimit );
95 return ( aRef - aFirst ).SquaredEuclideanNorm() < ( aRef - aSecond ).SquaredEuclideanNorm();
109 const std::vector<PCB_SHAPE*>& aList,
unsigned aLimit )
114 if( graphic == aShape || ( graphic->GetFlags() &
SKIP_STRUCT ) != 0 )
117 if( aPoint == graphic->GetStart() || aPoint == graphic->GetEnd() )
130 if( graphic == aShape )
133 d_sq = ( pt - graphic->GetStart() ).SquaredEuclideanNorm();
135 if( d_sq < closest_dist_sq )
137 closest_dist_sq = d_sq;
138 closest_graphic = graphic;
141 d_sq = ( pt - graphic->GetEnd() ).SquaredEuclideanNorm();
143 if( d_sq < closest_dist_sq )
145 closest_dist_sq = d_sq;
146 closest_graphic = graphic;
150 return closest_graphic;
156 bool padOutside =
false;
160 pad->Padstack().ForEachUniqueLayer(
171 VECTOR2I padPos = pad->GetPosition();
172 wxLogTrace( traceBoardOutline, wxT(
"Tested pad (%d, %d): outside" ),
173 padPos.x, padPos.y );
183 padPos.
x, padPos.
y );
191 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
195 if( aShapeList.size() == 0 )
198 bool selfIntersecting =
false;
203 std::set<PCB_SHAPE*> startCandidates( aShapeList.begin(), aShapeList.end() );
207 std::map<std::pair<VECTOR2I, VECTOR2I>,
PCB_SHAPE*> shapeOwners;
212 auto it = shapeOwners.find( std::make_pair( seg.A, seg.B ) );
213 return it == shapeOwners.end() ? nullptr : it->second;
219 std::vector<SHAPE_LINE_CHAIN> contours;
221 for(
PCB_SHAPE* shape : startCandidates )
224 while( startCandidates.size() )
226 graphic = (
PCB_SHAPE*) *startCandidates.begin();
228 aCleaner.insert( graphic );
229 startCandidates.erase( startCandidates.begin() );
231 contours.emplace_back();
250 shapeOwners[ std::make_pair( prevPt, pt ) ] = graphic;
266 currContour.
Append( arc360, aErrorMax );
270 for(
int ii = 1; ii < currContour.
PointCount(); ++ii )
272 shapeOwners[ std::make_pair( currContour.
CPoint( ii-1 ),
273 currContour.
CPoint( ii ) ) ] = graphic;
276 if( !aAllowUseArcsInPolygons )
290 shapeOwners[ std::make_pair( prevPt, pt ) ] = graphic;
303 currContour.
Append( prevPt );
316 wxASSERT( prevGraphic );
317 (*aErrorHandler)(
_(
"(self-intersecting)" ), prevGraphic, graphic,
321 selfIntersecting =
true;
334 nextPt = graphic->
GetEnd();
338 currContour.
Append( nextPt );
339 shapeOwners[ std::make_pair( prevPt, nextPt ) ] = graphic;
354 std::swap( pstart, pend );
363 arcChain.
Append( sarc, aErrorMax );
365 if( !aAllowUseArcsInPolygons )
369 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
371 shapeOwners[std::make_pair( arcChain.
CPoint( ii - 1 ),
372 arcChain.
CPoint( ii ) )] = graphic;
375 currContour.
Append( arcChain );
386 bool reverse =
false;
392 nextPt = graphic->
GetEnd();
413 shapeOwners[ std::make_pair( prevPt, pt ) ] = graphic;
425 shapeOwners[ std::make_pair( prevPt, pt ) ] = graphic;
440 PCB_SHAPE* nextGraphic =
findNext( graphic, prevPt, aShapeList, aChainingEpsilon );
444 prevGraphic = graphic;
445 graphic = nextGraphic;
447 aCleaner.insert( graphic );
448 startCandidates.erase( graphic );
455 if( startPt != prevPt && currContour.
PointCount() > 2 )
469 arcChain.
Append( sarc, aErrorMax );
471 if( !aAllowUseArcsInPolygons )
475 for(
int ii = 1; ii < arcChain.
PointCount(); ++ii )
477 shapeOwners[std::make_pair( arcChain.
CPoint( ii - 1 ),
478 arcChain.
CPoint( ii ) )] = owner;
482 currContour.
Append( arcChain );
487 currContour.
SetPoint( -1, startPt );
489 shapeOwners[std::make_pair( currContour.
CPoint( -2 ),
490 currContour.
CPoint( -1 ) )] = owner;
499 else if( nextGraphic )
502 (*aErrorHandler)(
_(
"(self-intersecting)" ), graphic, nextGraphic,
510 (*aErrorHandler)(
_(
"(not a closed shape)" ), graphic,
nullptr, prevPt );
520 if( !contour.IsClosed() )
525 std::map<int, std::vector<int>> contourToParentIndexesMap;
527 for(
size_t ii = 0; ii < contours.size(); ++ii )
529 VECTOR2I firstPt = contours[ii].GetPoint( 0 );
530 std::vector<int> parents;
532 for(
size_t jj = 0; jj < contours.size(); ++jj )
540 parents.push_back( jj );
543 contourToParentIndexesMap[ii] = std::move( parents );
547 std::map<int, int> contourToOutlineIdxMap;
549 for(
const auto& [ contourIndex, parentIndexes ] : contourToParentIndexesMap )
551 if( parentIndexes.size() %2 == 0 )
554 if( !aAllowDisjoint && !aPolygons.
IsEmpty() )
559 BOARD_ITEM* b = fetchOwner( contours[ contourIndex ].GetSegment( 0 ) );
563 (*aErrorHandler)(
_(
"(multiple board outlines not supported)" ), a, b,
564 contours[ contourIndex ].GetPoint( 0 ) );
571 aPolygons.
AddOutline( contours[ contourIndex ] );
572 contourToOutlineIdxMap[ contourIndex ] = aPolygons.
OutlineCount() - 1;
577 for(
const auto& [ contourIndex, parentIndexes ] : contourToParentIndexesMap )
579 if( parentIndexes.size() %2 == 1 )
585 for(
int parentContourIdx : parentIndexes )
587 if( contourToParentIndexesMap[ parentContourIdx ].size() == parentIndexes.size() - 1 )
589 int outlineIdx = contourToOutlineIdxMap[ parentContourIdx ];
590 aPolygons.
AddHole( hole, outlineIdx );
604 for( ++seg2; seg2; seg2++ )
607 if( *seg1 == *seg2 || ( ( *seg1 ).A == ( *seg2 ).B && ( *seg1 ).B == ( *seg2 ).A ) )
613 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, ( *seg1 ).A );
616 selfIntersecting =
true;
619 if(
OPT_VECTOR2I pt = seg1.Get().Intersect( seg2.Get(),
true ) )
625 (*aErrorHandler)(
_(
"(self-intersecting)" ), a, b, *pt );
628 selfIntersecting =
true;
633 return !selfIntersecting;
638 int aErrorMax,
int aChainingEpsilon,
bool aAllowDisjoint,
644 aAllowDisjoint, aErrorHandler, aAllowUseArcsInPolygons,
654 int min_dist = std::max( 0, aMinDist );
659 std::vector<PCB_SHAPE*> shapeList;
661 for(
int ii = 0; ii < items.
GetCount(); ii++ )
666 shapeList.push_back( seg );
672 switch( shape->GetShape() )
676 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
679 if( dim <= min_dist )
685 (*aErrorHandler)( wxString::Format(
_(
"(rectangle has null or very small "
686 "size: %d nm)" ), dim ),
687 shape,
nullptr, shape->GetStart() );
695 int r = shape->GetRadius();
703 (*aErrorHandler)( wxString::Format(
_(
"(circle has null or very small "
704 "radius: %d nm)" ), r ),
705 shape,
nullptr, shape->GetStart() );
713 VECTOR2I seg = shape->GetEnd() - shape->GetStart();
716 if( dim <= min_dist )
722 (*aErrorHandler)( wxString::Format(
_(
"(segment has null or very small "
723 "length: %d nm)" ), dim ),
724 shape,
nullptr, shape->GetStart() );
734 VECTOR2I arcMiddle = shape->GetArcMid();
735 VECTOR2I seg1 = arcMiddle - shape->GetStart();
736 VECTOR2I seg2 = shape->GetEnd() - arcMiddle;
739 if( dim <= min_dist )
745 (*aErrorHandler)( wxString::Format(
_(
"(arc has null or very small size: "
747 shape,
nullptr, shape->GetStart() );
771 bool aAllowUseArcsInPolygons )
775 bool success =
false;
782 for(
int ii = 0; ii < items.
GetCount(); ++ii )
790 std::vector<PCB_SHAPE*> fpSegList;
792 for(
int ii = 0; ii < fpItems.
GetCount(); ii++ )
797 fpSegList.push_back( fpSeg );
800 if( !fpSegList.empty() )
807 nullptr, aAllowUseArcsInPolygons, cleaner );
816 fpHoles.
Append( fpOutlines );
822 for(
int ii = 0; ii < fpItems.
GetCount(); ++ii )
829 std::vector<PCB_SHAPE*> segList;
831 for(
int ii = 0; ii < items.
GetCount(); ii++ )
840 segList.push_back( seg );
846 aErrorHandler, aAllowUseArcsInPolygons, cleaner );
872 aOutlines.
Append( corner );
878 aOutlines.
Append( corner );
939 int aOutlineNum = 0 )
941 int minDistance = -1;
947 int dis = seg.
Distance( aEndPoint );
949 if( minDistance < 0 || ( dis < minDistance ) )
952 projPoint = seg.NearestPoint( aEndPoint );
987 if( foundA && foundB )
994 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1002 seg.
A.
x, seg.
A.
y, seg.
B.
x, seg.
B.
y );
1028 bool success =
false;
1036 std::vector<PCB_SHAPE*> segList;
1038 for(
int ii = 0; ii < items.
GetCount(); ii++ )
1040 if( items[ii]->GetLayer() ==
Edge_Cuts )
1041 segList.push_back(
static_cast<PCB_SHAPE*
>( items[ii] ) );
1044 if( !segList.empty() )
1047 aErrorHandler,
false, cleaner );
1071 for(
int j = 0; j < outlines.
HoleCount( i ); j++ )
1076 aOutlines.
AddHole( hole, -1 );
1084 aOutlines = outlines;
1102 std::vector<SHAPE_LINE_CHAIN> closedChains;
1103 std::vector<SHAPE_LINE_CHAIN> openChains;
1107 openChains.push_back( outlines.
Outline( 0 ) );
1109 for(
int j = 0; j < outlines.
HoleCount( 0 ); j++ )
1116 closedChains.push_back( hole );
1121 openChains.push_back( hole );
1155 wxLogTrace(
traceBoardOutline, wxT(
"Only 1 line segment in provided outline" ) );
1165 if( inter0 && inter2 && !inter1 && !inter3 )
1185 else if( inter1 && inter3 && !inter0 && !inter2 )
1208 wxLogTrace(
traceBoardOutline, wxT(
"Segment intersects two perpendicular bbox "
1237 else if( hit1 && hit2 )
1256 else if( hit2 && hit3 )
1331 aOutlines.
AddHole( closedChain, -1 );
constexpr int ARC_HIGH_DEF
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.
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
const FOOTPRINTS & Footprints() const
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 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
SHAPE_POLY_SET & GetPolyShape()
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
const std::vector< VECTOR2I > & GetBezierPoints() const
wxString SHAPE_T_asString() const
VECTOR2I GetArcMid() const
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
int GetWidth() const override
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.
EDA_ITEM_FLAGS m_flagsToClear
SCOPED_FLAGS_CLEANER(const EDA_ITEM_FLAGS &aFlagsToClear)
VECTOR2I::extended_type ecoord
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
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
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.
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 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.
void SetWidth(int aWidth)
Set the width of all segments in the chain.
Represent a set of closed polygons.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
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)
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
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
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 PCB_SHAPE * findNext(PCB_SHAPE *aShape, const VECTOR2I &aPoint, const std::vector< PCB_SHAPE * > &aList, unsigned aLimit)
Search for a PCB_SHAPE matching a given end point or start point in a list.
static bool isCopperOutside(const FOOTPRINT *aFootprint, SHAPE_POLY_SET &aShape)
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)
bool BuildBoardPolygonOutlines(BOARD *aBoard, SHAPE_POLY_SET &aOutlines, int aErrorMax, int aChainingEpsilon, 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 close_enough(VECTOR2I aLeft, VECTOR2I aRight, unsigned aLimit)
Local and tunable method of qualifying the proximity of two points.
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.
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
constexpr int mmToIU(double mm) const
const SHAPE_LINE_CHAIN chain
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers