62 virtual bool Run()
override;
64 virtual const wxString
GetName()
const override
66 return wxT(
"physical_clearance" );
71 return wxT(
"Tests item clearances irrespective of nets" );
99 reportAux( wxT(
"No physical clearance constraints found. Tests not run." ) );
105 size_t progressDelta = 250;
109 if( !
reportPhase(
_(
"Gathering physical items..." ) ) )
112 static const std::vector<KICAD_T> itemTypes = {
149 if( layers.Contains( F_Cu ) )
150 layers |= LSET::FrontBoardTechMask().set( F_CrtYd );
152 if( layers.Contains( B_Cu ) )
153 layers |= LSET::BackBoardTechMask().set( B_CrtYd );
155 if( layers.Contains( F_Cu ) && layers.Contains( B_Cu ) )
156 layers |= LSET::AllCuMask();
164 layers |= LSET::PhysicalLayersMask() | courtyards;
173 std::unordered_map<PTR_PTR_CACHE_KEY, LSET> checkedPairs;
184 if( !
reportPhase(
_(
"Checking physical clearances..." ) ) )
200 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( layer );
202 m_itemTree.QueryColliding( item, layer, layer,
204 [&]( BOARD_ITEM* other ) -> bool
206 BOARD_ITEM* a = item;
207 BOARD_ITEM* b = other;
211 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
214 auto it = checkedPairs.find( { a, b } );
216 if( it != checkedPairs.end() && it->second.test( layer ) )
222 checkedPairs[ { a, b } ].set( layer );
229 if( testItemAgainstItem( item, itemShape.get(), layer,
232 BOARD_ITEM* a = item;
233 BOARD_ITEM* b = other;
236 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
241 checkedPairs[ { a, b } ].set();
267 ZONE* zone =
dynamic_cast<ZONE*
>( item );
286 ZONE* zone =
dynamic_cast<ZONE*
>( item );
295 if( !reportProgress( ii++, count, progressDelta ) )
299 item,
nullptr, layer );
307 shape->
GetWidth(), layer, item, c );
319 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
334 for(
int step = 1; step <= steps; ++step )
336 EDA_ANGLE rotation = ( angle * step ) / steps;
343 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
357 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
367 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
377 testZoneLayer(
static_cast<ZONE*
>( item ), layer, c );
380 if( m_drcEngine->IsCancelled() )
384 return !m_drcEngine->IsCancelled();
387 reportRuleStatistics();
389 return !m_drcEngine->IsCancelled();
409 std::vector<double> angles;
410 angles.reserve( count );
413 [](
double a,
double b ) ->
double
421 return 2 * M_PI - diff;
426 for(
int ii = 0; ii < count; ++ii )
438 angles.push_back( angles.back() );
442 for(
int jj = 1; jj < count; ++jj )
456 std::vector< std::pair<VECTOR2I, int> > collisions;
458 for(
int ii = 0; ii < count; ++ii )
461 double segAngle = angles[ ii ];
464 int firstCandidate = ii + 1;
465 int lastCandidate = count - 1;
467 while( firstCandidate < count )
469 if( angleDiff( segAngle, angles[ firstCandidate ] ) < angleTolerance )
478 lastCandidate = ii - 1;
480 while( lastCandidate != std::min( firstCandidate, count - 1 ) )
482 if( angleDiff( segAngle, angles[ lastCandidate ] ) < angleTolerance )
483 lastCandidate = ( lastCandidate == 0 ) ? count - 1 : lastCandidate - 1;
490 if( lastCandidate < ii )
491 lastCandidate = count - 1;
493 for(
int jj = firstCandidate; jj <= lastCandidate; ++jj )
498 if( seg.
Collide( candidate, clearance + aLineWidth -
epsilon, &actual ) )
502 VECTOR2I pos = ( firstPoint + secondPoint ) / 2;
504 if( !collisions.empty() &&
505 ( pos - collisions.back().first ).EuclideanNorm() < clearance * 2 )
507 if( actual < collisions.back().second )
509 collisions.back().first = pos;
510 collisions.back().second = actual;
516 collisions.push_back( { pos, actual } );
521 for( std::pair<VECTOR2I, int> collision : collisions )
529 pt += parentFP->GetPosition();
532 wxString msg =
formatMsg(
_(
"Internal clearance violation (%s clearance %s; actual %s)" ),
537 drce->SetErrorMessage( msg );
538 drce->SetItems( aParentItem );
560 for(
int outlineIdx = 0; outlineIdx < fill.
OutlineCount(); ++outlineIdx )
568 for(
int ii = outlineIdx + 1; ii < fill.
OutlineCount(); ++ii )
572 for(
int jj = 0; jj < secondOutline->
SegmentCount(); ++jj )
578 if( firstOutline->
Collide( secondSeg, clearance -
epsilon, &actual, &pos ) )
581 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
586 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
587 drce->SetItems( aZone );
602 for(
int holeIdx = 0; holeIdx < fill.
HoleCount( outlineIdx ); ++holeIdx )
627 SHAPE* otherShape = otherShapeStorage.get();
641 std::swap( aItem, aOther );
642 std::swap( aItemShape, otherShape );
645 if( aItemShape->
Collide( otherShape, clearance, &actual, &pos ) )
648 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
653 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
654 drce->SetItems( aItem, aOther );
664 std::shared_ptr<SHAPE_SEGMENT> itemHoleShape;
665 std::shared_ptr<SHAPE_SEGMENT> otherHoleShape;
681 wxCHECK_MSG( layers.
Contains( aLayer ), violations,
682 wxT(
"Bug! Vias should only be checked for layers on which they exist" ) );
704 wxCHECK_MSG( layers.
Contains( aLayer ), violations,
705 wxT(
"Bug! Vias should only be checked for layers on which they exist" ) );
714 if( itemHoleShape || otherHoleShape )
723 if( itemHoleShape && itemHoleShape->Collide( otherShape, clearance, &actual, &pos ) )
726 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
731 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
732 drce->SetItems( aItem, aOther );
739 if( otherHoleShape && otherHoleShape->Collide( aItemShape, clearance, &actual, &pos ) )
742 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
747 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
748 drce->SetItems( aItem, aOther );
770 BOX2I worstCaseBBox = itemBBox;
780 if( !testClearance && !testHoles )
805 if( !
pad->FlashLayer( aLayer ) )
807 if(
pad->GetDrillSize().x == 0 &&
pad->GetDrillSize().y == 0 )
810 std::shared_ptr<SHAPE_SEGMENT> hole =
pad->GetEffectiveHoleShape();
811 int size = hole->GetWidth();
813 itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
819 colliding = zoneTree->
QueryColliding( itemBBox, itemShape.get(), aLayer, clearance,
824 colliding = zone->
Outline()->
Collide( itemShape.get(), clearance, &actual, &pos );
830 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
835 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
836 drce->SetItems( aItem, zone );
845 std::shared_ptr<SHAPE_SEGMENT> holeShape;
865 && zoneTree->
QueryColliding( itemBBox, holeShape.get(), aLayer, clearance,
869 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
874 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
875 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)
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
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
constexpr bool Intersects(const BOX2< Vec > &aRect) const
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.
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)
int testItemAgainstItem(BOARD_ITEM *aItem, SHAPE *aItemShape, PCB_LAYER_ID aLayer, BOARD_ITEM *aOther)
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()
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.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
static LSET BackBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on Back side.
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
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
a few functions useful in geometry calculations.
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)