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 layers |= LSET::PhysicalLayersMask() | courtyards;
156 layers |= LSET::PhysicalLayersMask() | courtyards;
165 std::unordered_map<PTR_PTR_CACHE_KEY, LSET> checkedPairs;
176 if( !
reportPhase(
_(
"Checking physical clearances..." ) ) )
192 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( layer );
194 m_itemTree.QueryColliding( item, layer, layer,
196 [&]( BOARD_ITEM* other ) -> bool
198 BOARD_ITEM* a = item;
199 BOARD_ITEM* b = other;
203 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
206 auto it = checkedPairs.find( { a, b } );
208 if( it != checkedPairs.end() && it->second.test( layer ) )
214 checkedPairs[ { a, b } ].set( layer );
221 if( testItemAgainstItem( item, itemShape.get(), layer,
224 BOARD_ITEM* a = item;
225 BOARD_ITEM* b = other;
228 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
233 checkedPairs[ { a, b } ].set();
259 ZONE* zone =
dynamic_cast<ZONE*
>( item );
278 ZONE* zone =
dynamic_cast<ZONE*
>( item );
287 if( !reportProgress( ii++, count, progressDelta ) )
291 item,
nullptr, layer );
299 shape->
GetWidth(), layer, item, c );
311 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
326 for(
int step = 1; step <= steps; ++step )
335 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
349 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
359 testZoneLayer(
static_cast<ZONE*
>( item ), layer, c );
362 if( m_drcEngine->IsCancelled() )
366 return !m_drcEngine->IsCancelled();
369 reportRuleStatistics();
371 return !m_drcEngine->IsCancelled();
391 std::vector<double> angles;
392 angles.reserve( count );
395 [](
double a,
double b ) ->
double
403 return 2 * M_PI - diff;
408 for(
int ii = 0; ii < count; ++ii )
420 angles.push_back( angles.back() );
424 for(
int jj = 1; jj < count; ++jj )
438 std::vector< std::pair<VECTOR2I, int> > collisions;
440 for(
int ii = 0; ii < count; ++ii )
443 double segAngle = angles[ ii ];
446 int firstCandidate = ii + 1;
447 int lastCandidate = count - 1;
449 while( firstCandidate < count )
451 if( angleDiff( segAngle, angles[ firstCandidate ] ) < angleTolerance )
460 lastCandidate = ii - 1;
462 while( lastCandidate != std::min( firstCandidate, count - 1 ) )
464 if( angleDiff( segAngle, angles[ lastCandidate ] ) < angleTolerance )
465 lastCandidate = ( lastCandidate == 0 ) ? count - 1 : lastCandidate - 1;
472 if( lastCandidate < ii )
473 lastCandidate = count - 1;
475 for(
int jj = firstCandidate; jj <= lastCandidate; ++jj )
480 if( seg.
Collide( candidate, clearance + aLineWidth - epsilon, &actual ) )
484 VECTOR2I pos = ( firstPoint + secondPoint ) / 2;
486 if( !collisions.empty() &&
487 ( pos - collisions.back().first ).
EuclideanNorm() < clearance * 2 )
489 if( actual < collisions.back().second )
491 collisions.back().first = pos;
492 collisions.back().second = actual;
498 collisions.push_back( { pos, actual } );
503 for( std::pair<VECTOR2I, int> collision : collisions )
511 wxString msg =
formatMsg(
_(
"Internal clearance violation (%s clearance %s; actual %s)" ),
516 drce->SetErrorMessage( msg );
517 drce->SetItems( aParentItem );
539 for(
int outlineIdx = 0; outlineIdx < fill.
OutlineCount(); ++outlineIdx )
547 for(
int ii = outlineIdx + 1; ii < fill.
OutlineCount(); ++ii )
551 for(
int jj = 0; jj < secondOutline->
SegmentCount(); ++jj )
557 if( firstOutline->
Collide( secondSeg, clearance - epsilon, &actual, &pos ) )
560 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
565 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
566 drce->SetItems( aZone );
581 for(
int holeIdx = 0; holeIdx < fill.
HoleCount( outlineIdx ); ++holeIdx )
615 if( aItemShape->
Collide( otherShape.get(), clearance, &actual, &pos ) )
618 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
623 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
624 drce->SetItems( aItem, other );
634 std::shared_ptr<SHAPE_SEGMENT> itemHoleShape;
635 std::shared_ptr<SHAPE_SEGMENT> otherHoleShape;
662 if( itemHoleShape || otherHoleShape )
671 if( itemHoleShape && itemHoleShape->Collide( otherShape.get(), clearance, &actual, &pos ) )
674 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
679 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
680 drce->SetItems( aItem, other );
687 if( otherHoleShape && otherHoleShape->Collide( aItemShape, clearance, &actual, &pos ) )
690 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
695 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
696 drce->SetItems( aItem, other );
718 BOX2I worstCaseBBox = itemBBox;
728 if( !testClearance && !testHoles )
753 if( !
pad->FlashLayer( aLayer ) )
755 if(
pad->GetDrillSize().x == 0 &&
pad->GetDrillSize().y == 0 )
758 std::shared_ptr<SHAPE_SEGMENT> hole =
pad->GetEffectiveHoleShape();
759 int size = hole->GetWidth();
761 itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
767 colliding = zoneTree->
QueryColliding( itemBBox, itemShape.get(), aLayer, clearance,
772 colliding = zone->
Outline()->
Collide( itemShape.get(), clearance, &actual, &pos );
778 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
783 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
784 drce->SetItems( aItem, zone );
793 std::shared_ptr<SHAPE_SEGMENT> holeShape;
813 && zoneTree->
QueryColliding( itemBBox, holeShape.get(), aLayer, clearance,
817 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
822 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
823 drce->SetItems( aItem, zone );
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
int GetDRCEpsilon() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
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.
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
BOARD_ITEM_CONTAINER * GetParentFootprint() const
virtual bool IsOnLayer(PCB_LAYER_ID aLayer, bool aIncludeCourtyards=false) const
Test to see if this object is on the given layer.
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
virtual bool reportPhase(const wxString &aStageName)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, LSET aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
virtual bool reportProgress(int aCount, int aSize, int aDelta)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
virtual void reportAux(wxString fmt,...)
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, int aConstraint, int aActual)
virtual VECTOR2I GetPosition() const
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
void RebuildBezierToSegmentsPointsList(int aMinSegLen)
Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of segments.
SHAPE_POLY_SET & GetPolyShape()
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 AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
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.
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.
SEG Segment(int aIndex)
Return a copy of the aIndex-th 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
Return the reference to aIndex-th outline in the set.
void Simplify(POLYGON_MODE aFastMode)
SHAPE_LINE_CHAIN & Outline(int aIndex)
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the aIndex-th subpolygon in the set.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
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
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 DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
double DEG2RAD(double deg)
double EuclideanNorm(const VECTOR2I &vector)
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_FP_TEXTBOX_T
class FP_TEXTBOX, wrapped text in a footprint
@ 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_FOOTPRINT_T
class FOOTPRINT, a footprint
@ PCB_FP_ZONE_T
class ZONE, managed by a footprint
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_FP_TEXT_T
class FP_TEXT, text 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)