61 virtual bool Run()
override;
63 virtual const wxString
GetName()
const override
65 return wxT(
"physical_clearance" );
70 return wxT(
"Tests item clearances irrespective of nets" );
98 reportAux( wxT(
"No physical clearance constraints found. Tests not run." ) );
104 size_t progressDelta = 250;
108 if( !
reportPhase(
_(
"Gathering physical items..." ) ) )
111 static const std::vector<KICAD_T> itemTypes = {
148 if( layers.Contains( F_Cu ) )
149 layers |= LSET::FrontBoardTechMask().set( F_CrtYd );
151 if( layers.Contains( B_Cu ) )
152 layers |= LSET::BackBoardTechMask().set( B_CrtYd );
154 if( layers.Contains( F_Cu ) && layers.Contains( B_Cu ) )
155 layers |= LSET::AllCuMask();
163 layers |= LSET::PhysicalLayersMask() | courtyards;
172 std::unordered_map<PTR_PTR_CACHE_KEY, LSET> checkedPairs;
183 if( !
reportPhase(
_(
"Checking physical clearances..." ) ) )
199 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( layer );
201 m_itemTree.QueryColliding( item, layer, layer,
203 [&]( BOARD_ITEM* other ) -> bool
205 BOARD_ITEM* a = item;
206 BOARD_ITEM* b = other;
210 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
213 auto it = checkedPairs.find( { a, b } );
215 if( it != checkedPairs.end() && it->second.test( layer ) )
221 checkedPairs[ { a, b } ].set( layer );
228 if( testItemAgainstItem( item, itemShape.get(), layer,
231 BOARD_ITEM* a = item;
232 BOARD_ITEM* b = other;
235 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
240 checkedPairs[ { a, b } ].set();
266 ZONE* zone =
dynamic_cast<ZONE*
>( item );
285 ZONE* zone =
dynamic_cast<ZONE*
>( item );
294 if( !reportProgress( ii++, count, progressDelta ) )
298 item,
nullptr, layer );
306 shape->
GetWidth(), layer, item, c );
318 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
333 for(
int step = 1; step <= steps; ++step )
335 EDA_ANGLE rotation = ( angle * step ) / steps;
342 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
356 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
366 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
376 testZoneLayer(
static_cast<ZONE*
>( item ), layer, c );
379 if( m_drcEngine->IsCancelled() )
383 return !m_drcEngine->IsCancelled();
386 reportRuleStatistics();
388 return !m_drcEngine->IsCancelled();
408 std::vector<double> angles;
409 angles.reserve( count );
412 [](
double a,
double b ) ->
double
420 return 2 * M_PI - diff;
425 for(
int ii = 0; ii < count; ++ii )
437 angles.push_back( angles.back() );
441 for(
int jj = 1; jj < count; ++jj )
455 std::vector< std::pair<VECTOR2I, int> > collisions;
457 for(
int ii = 0; ii < count; ++ii )
460 double segAngle = angles[ ii ];
463 int firstCandidate = ii + 1;
464 int lastCandidate = count - 1;
466 while( firstCandidate < count )
468 if( angleDiff( segAngle, angles[ firstCandidate ] ) < angleTolerance )
477 lastCandidate = ii - 1;
479 while( lastCandidate != std::min( firstCandidate, count - 1 ) )
481 if( angleDiff( segAngle, angles[ lastCandidate ] ) < angleTolerance )
482 lastCandidate = ( lastCandidate == 0 ) ? count - 1 : lastCandidate - 1;
489 if( lastCandidate < ii )
490 lastCandidate = count - 1;
492 for(
int jj = firstCandidate; jj <= lastCandidate; ++jj )
497 if( seg.
Collide( candidate, clearance + aLineWidth -
epsilon, &actual ) )
501 VECTOR2I pos = ( firstPoint + secondPoint ) / 2;
503 if( !collisions.empty() &&
504 ( pos - collisions.back().first ).EuclideanNorm() < clearance * 2 )
506 if( actual < collisions.back().second )
508 collisions.back().first = pos;
509 collisions.back().second = actual;
515 collisions.push_back( { pos, actual } );
520 for( std::pair<VECTOR2I, int> collision : collisions )
528 pt += parentFP->GetPosition();
531 wxString msg =
formatMsg(
_(
"Internal clearance violation (%s clearance %s; actual %s)" ),
536 drce->SetErrorMessage( msg );
537 drce->SetItems( aParentItem );
559 for(
int outlineIdx = 0; outlineIdx < fill.
OutlineCount(); ++outlineIdx )
567 for(
int ii = outlineIdx + 1; ii < fill.
OutlineCount(); ++ii )
571 for(
int jj = 0; jj < secondOutline->
SegmentCount(); ++jj )
577 if( firstOutline->
Collide( secondSeg, clearance -
epsilon, &actual, &pos ) )
580 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
585 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
586 drce->SetItems( aZone );
601 for(
int holeIdx = 0; holeIdx < fill.
HoleCount( outlineIdx ); ++holeIdx )
635 if( aItemShape->
Collide( otherShape.get(), clearance, &actual, &pos ) )
638 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
643 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
644 drce->SetItems( aItem, other );
654 std::shared_ptr<SHAPE_SEGMENT> itemHoleShape;
655 std::shared_ptr<SHAPE_SEGMENT> otherHoleShape;
671 wxCHECK_MSG( layers.
Contains( aLayer ), violations,
672 wxT(
"Bug! Vias should only be checked for layers on which they exist" ) );
694 wxCHECK_MSG( layers.
Contains( aLayer ), violations,
695 wxT(
"Bug! Vias should only be checked for layers on which they exist" ) );
704 if( itemHoleShape || otherHoleShape )
713 if( itemHoleShape && itemHoleShape->Collide( otherShape.get(), clearance, &actual, &pos ) )
716 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
721 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
722 drce->SetItems( aItem, other );
729 if( otherHoleShape && otherHoleShape->Collide( aItemShape, clearance, &actual, &pos ) )
732 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
737 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
738 drce->SetItems( aItem, other );
760 BOX2I worstCaseBBox = itemBBox;
770 if( !testClearance && !testHoles )
795 if( !
pad->FlashLayer( aLayer ) )
797 if(
pad->GetDrillSize().x == 0 &&
pad->GetDrillSize().y == 0 )
800 std::shared_ptr<SHAPE_SEGMENT> hole =
pad->GetEffectiveHoleShape();
801 int size = hole->GetWidth();
803 itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
809 colliding = zoneTree->
QueryColliding( itemBBox, itemShape.get(), aLayer, clearance,
814 colliding = zone->
Outline()->
Collide( itemShape.get(), clearance, &actual, &pos );
820 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
825 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
826 drce->SetItems( aItem, zone );
835 std::shared_ptr<SHAPE_SEGMENT> holeShape;
855 && zoneTree->
QueryColliding( itemBBox, holeShape.get(), aLayer, clearance,
859 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
864 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
865 drce->SetItems( aItem, zone );
constexpr int ARC_HIGH_DEF
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
BASE_SET & set(size_t pos=std::numeric_limits< size_t >::max(), bool value=true)
bool test(size_t pos) const
int GetDRCEpsilon() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual bool IsOnLayer(PCB_LAYER_ID aLayer) const
Test to see if this object is on the given layer.
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
virtual bool HasHole() const
int m_DRCMaxPhysicalClearance
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
std::vector< ZONE * > m_DRCZones
bool Intersects(const BOX2< Vec > &aRect) const
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
SEVERITY GetSeverity() const
const MINOPTMAX< int > & GetValue() const
DRC_RULE * GetParentRule() const
bool IsErrorLimitExceeded(int error_code)
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Implement an R-tree for fast spatial and layer indexing of connectable items.
void Insert(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, int aWorstClearance=0)
Insert an item into the tree on a particular layer with an optional worst clearance.
int QueryColliding(BOARD_ITEM *aRefItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer, std::function< bool(BOARD_ITEM *)> aFilter=nullptr, std::function< bool(BOARD_ITEM *)> aVisitor=nullptr, int aClearance=0) const
This is a fast test which essentially does bounding-box overlap given a worst-case clearance.
void clear()
Remove all items from the RTree.
int testItemAgainstItem(BOARD_ITEM *aItem, SHAPE *aItemShape, PCB_LAYER_ID aLayer, BOARD_ITEM *other)
void testZoneLayer(ZONE *aZone, PCB_LAYER_ID aLayer, DRC_CONSTRAINT &aConstraint)
virtual ~DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE()
void testItemAgainstZones(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
virtual const wxString GetName() const override
DRC_TEST_PROVIDER_PHYSICAL_CLEARANCE()
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
void testShapeLineChain(const SHAPE_LINE_CHAIN &aOutline, int aLineWidth, PCB_LAYER_ID aLayer, BOARD_ITEM *aParentItem, DRC_CONSTRAINT &aConstraint)
virtual const wxString GetDescription() const override
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual)
virtual bool reportPhase(const wxString &aStageName)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, LSET aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
void reportAux(const wxString &aMsg)
virtual bool reportProgress(size_t aCount, size_t aSize, size_t aDelta=1)
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
KICAD_T Type() const
Returns the type of object.
EDA_ANGLE GetArcAngle() 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
LSET is a set of PCB_LAYER_IDs.
static LSET AllLayersMask()
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
static LSET FrontBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on front side.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
static LSET BackBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on Back side.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
int GetWidth() const override
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
static SEG::ecoord Square(int a)
bool Collide(const SEG &aSeg, int aClearance, int *aActual=nullptr) const
ecoord SquaredLength() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
bool IsClosed() const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if point aP lies closer to us than aClearance.
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.
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.
Represent a set of closed polygons.
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
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 OutlineCount() const
Return the number of outlines in the set.
An abstract shape on 2D plane.
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
Handle a list of polygons defining a copper zone.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
const std::shared_ptr< SHAPE_POLY_SET > & GetFilledPolysList(PCB_LAYER_ID aLayer) const
const BOX2I GetBoundingBox() const override
SHAPE_POLY_SET * Outline()
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
@ PHYSICAL_CLEARANCE_CONSTRAINT
@ ARC
use RECTANGLE instead of RECT to avoid collision in a Windows header
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
double DEG2RAD(double deg)
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_ZONE_T
class ZONE, a copper pour area
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)