25#include <math_for_graphics.h>
69 virtual bool Run()
override;
71 virtual const wxString
GetName()
const override
73 return wxT(
"clearance" );
78 return wxT(
"Tests copper item clearance" );
126 reportAux( wxT(
"No Clearance constraints found. Tests not run." ) );
134 if( !
reportPhase(
_(
"Checking track & via clearances..." ) ) )
141 if( !
reportPhase(
_(
"Checking hole clearances..." ) ) )
165 if( !
reportPhase(
_(
"Checking copper zone clearances..." ) ) )
195 bool has_error =
false;
199 otherNet = connectedItem->GetNetCode();
207 if(
pad->GetAttribute() == PAD_ATTRIB::NPTH && !
pad->FlashLayer( layer ) )
208 testClearance = testShorting =
false;
211 if( testClearance || testShorting )
228 drcItem->SetItems( track, other );
244 else if( actual == 0 && otherNet && testShorting )
249 msg.Printf(
_(
"(nets %s and %s)" ),
253 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
254 drce->SetItems( track, other );
262 else if( testClearance )
265 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
270 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
271 drce->SetItems( track, other );
285 std::array<BOARD_ITEM*, 2> a{ track, other };
286 std::array<BOARD_ITEM*, 2> b{ other, track };
287 std::array<SHAPE*, 2> a_shape{ trackShape, otherShape.get() };
289 for(
size_t ii = 0; ii < 2; ++ii )
291 std::shared_ptr<SHAPE_SEGMENT> holeShape;
295 if( !(
dynamic_cast<PCB_TRACK*
>( a[ii] ) ) || !b[ii]->HasHole() )
301 if( b[ii]->GetLayerSet().Contains( layer ) )
302 holeShape = b[ii]->GetEffectiveHoleShape();
306 holeShape = b[ii]->GetEffectiveHoleShape();
320 wxString msg =
formatMsg( clearance ?
_(
"(%s clearance %s; actual %s)" )
321 :
_(
"(%s clearance %s; actual < 0)" ),
326 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
327 drce->SetItems( a[ii], b[ii] );
354 BOX2I worstCaseBBox = itemBBox;
364 if( !testClearance && !testHoles )
380 bool flashedPad =
pad->FlashLayer( aLayer );
381 bool platedHole =
pad->HasHole() &&
pad->GetAttribute() == PAD_ATTRIB::PTH;
383 if( !flashedPad && !platedHole )
384 testClearance =
false;
395 std::shared_ptr<SHAPE> itemShape = aItem->
GetEffectiveShape( aLayer, FLASHING::DEFAULT );
398 std::max( 0, clearance -
m_drcEpsilon ), &actual, &pos ) )
401 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
406 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
407 drce->SetItems( aItem, aZone );
414 if( testHoles && aItem->
HasHole() )
416 std::shared_ptr<SHAPE_SEGMENT> holeShape;
440 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
445 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
446 drce->SetItems( aItem, aZone );
460 const int progressDelta = 100;
465 std::map<BOARD_ITEM*, int> freePadsUsageMap;
466 std::unordered_map<PTR_PTR_CACHE_KEY, layers_checked> checkedPairs;
477 std::shared_ptr<SHAPE> trackShape = track->GetEffectiveShape( layer );
485 if( otherCItem && otherCItem->GetNetCode() == track->GetNetCode() )
493 if(
static_cast<void*
>( a ) >
static_cast<void*
>( b ) )
496 auto it = checkedPairs.find( { a, b } );
498 if( it != checkedPairs.end() && ( it->second.layers.test( layer )
505 checkedPairs[ { a, b } ].layers.set( layer );
516 auto it = freePadsUsageMap.find( other );
518 if( it == freePadsUsageMap.end() )
520 freePadsUsageMap[ other ] = track->GetNetCode();
523 else if( it->second == track->GetNetCode() )
535 if(
static_cast<void*
>( a ) >
static_cast<void*
>( b ) )
538 auto it = checkedPairs.find( { a, b } );
544 if( it != checkedPairs.end() )
545 it->second.has_error =
true;
579 int padGroupIdx = padToNetTieGroupMap[
pad->GetNumber() ];
583 PAD* otherPad =
static_cast<PAD*
>( other );
585 if( padGroupIdx >= 0 && padGroupIdx == padToNetTieGroupMap[ otherPad->
GetNumber() ] )
586 testClearance = testShorting =
false;
588 if(
pad->SameLogicalPadAs( otherPad ) )
593 testClearance = testShorting =
false;
596 PAD* otherPad =
nullptr;
600 otherPad =
static_cast<PAD*
>( other );
603 otherVia =
static_cast<PCB_VIA*
>( other );
606 testClearance = testShorting =
false;
609 if(
pad->GetAttribute() == PAD_ATTRIB::NPTH && !
pad->FlashLayer( aLayer ) )
610 testClearance = testShorting =
false;
613 testClearance = testShorting =
false;
617 testClearance = testShorting =
false;
619 int padNet =
pad->GetNetCode();
623 otherNet = connectedItem->GetNetCode();
626 if( ( otherPad || otherVia ) && otherNet && otherNet == padNet )
628 testClearance = testShorting =
false;
632 if( !(
pad->GetDrillSize().x > 0 )
634 && !( otherVia && otherVia->
GetDrill() > 0 ) )
639 if( !testClearance && !testShorting && !testHoles )
648 if( otherPad &&
pad->SameLogicalPadAs( otherPad ) )
660 msg.Printf(
_(
"(nets %s and %s)" ),
664 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
665 drce->SetItems(
pad, otherPad );
673 if( testClearance || testShorting )
688 else if( actual == 0 && otherNet && testShorting )
693 msg.Printf(
_(
"(nets %s and %s)" ),
697 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
698 drce->SetItems(
pad, other );
703 else if( testClearance )
706 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
711 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
712 drce->SetItems(
pad, other );
731 if( testHoles && otherPad &&
pad->FlashLayer( aLayer ) && otherPad->
HasHole() )
738 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
743 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
744 drce->SetItems(
pad, other );
752 if( testHoles && otherPad && otherPad->
FlashLayer( aLayer ) &&
pad->HasHole() )
754 if( clearance > 0 && otherShape->Collide(
pad->GetEffectiveHoleShape().get(),
759 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
764 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
765 drce->SetItems(
pad, other );
773 if( testHoles && otherVia && otherVia->
IsOnLayer( aLayer ) )
780 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
785 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
786 drce->SetItems(
pad, otherVia );
799 const int progressDelta = 100;
804 count += footprint->Pads().size();
806 reportAux( wxT(
"Testing %d pads..." ), count );
808 std::unordered_map<PTR_PTR_CACHE_KEY, int> checkedPairs;
814 for(
PAD*
pad : footprint->Pads() )
818 std::shared_ptr<SHAPE> padShape =
pad->GetEffectiveShape( layer );
829 if(
static_cast<void*
>( a ) >
static_cast<void*
>( b ) )
832 if( checkedPairs.find( { a, b } ) != checkedPairs.end() )
838 checkedPairs[ { a, b } ] = 1;
870 const int progressDelta = 50;
878 int zone2zoneClearance;
881 boardOutline = &buffer;
883 for(
int layer_id =
F_Cu; layer_id <=
B_Cu; ++layer_id )
886 std::vector<SHAPE_POLY_SET> smoothed_polys;
948 for(
auto it = smoothed_polys[ia].IterateWithHoles(); it; it++ )
952 if( smoothed_polys[ia2].Contains( currentVertex ) )
955 drce->SetItems( zoneA, zoneB );
963 for(
auto it = smoothed_polys[ia2].IterateWithHoles(); it; it++ )
967 if( smoothed_polys[ia].Contains( currentVertex ) )
970 drce->SetItems( zoneB, zoneA );
979 std::map<VECTOR2I, int> conflictPoints;
981 for(
auto refIt = smoothed_polys[ia].IterateSegmentsWithHoles(); refIt; refIt++ )
984 SEG refSegment = *refIt;
987 for(
auto it = smoothed_polys[ia2].IterateSegmentsWithHoles(); it; it++ )
990 SEG testSegment = *it;
993 int ax1, ay1, ax2, ay2;
994 ax1 = refSegment.
A.
x;
995 ay1 = refSegment.
A.
y;
996 ax2 = refSegment.
B.
x;
997 ay2 = refSegment.
B.
y;
999 int bx1, by1, bx2, by2;
1000 bx1 = testSegment.
A.
x;
1001 by1 = testSegment.
A.
y;
1002 bx2 = testSegment.
B.
x;
1003 by2 = testSegment.
B.
y;
1005 int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2, 0,
1006 ax1, ay1, ax2, ay2, 0,
1007 zone2zoneClearance, &pt.
x, &pt.
y );
1009 if( d < zone2zoneClearance )
1011 if( conflictPoints.count( pt ) )
1012 conflictPoints[ pt ] = std::min( conflictPoints[ pt ], d );
1014 conflictPoints[ pt ] = d;
1019 for(
const std::pair<const VECTOR2I, int>& conflict : conflictPoints )
1021 int actual = conflict.second;
1022 std::shared_ptr<DRC_ITEM> drce;
1024 if( actual <= 0 && testIntersects )
1028 else if( testClearance )
1031 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
1034 std::max( actual, 0 ) );
1036 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
1041 drce->SetItems( zoneA, zoneB );
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
wxString GetNetname() const
int GetDRCEpsilon() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
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 * GetParent() const
virtual std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const
virtual bool HasHole() const
std::vector< ZONE * > m_DRCCopperZones
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
bool IsLayerEnabled(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
FOOTPRINTS & Footprints()
int GetCopperLayerCount() const
std::shared_ptr< DRC_RTREE > m_CopperItemRTreeCache
std::unordered_map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTreeCache
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
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 GetReportAllTrackErrors() 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)
bool IsNetTieExclusion(int aTrackNetCode, PCB_LAYER_ID aTrackLayer, const VECTOR2I &aCollisionPos, BOARD_ITEM *aCollidingItem)
Check if the given collision between a track and another item occurs during the track's entry into a ...
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.
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.
struct DRC_TEST_PROVIDER_COPPER_CLEARANCE::checked layers_checked
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
DRC_TEST_PROVIDER_COPPER_CLEARANCE()
void testItemAgainstZone(BOARD_ITEM *aItem, ZONE *aZone, PCB_LAYER_ID aLayer)
bool testTrackAgainstItem(PCB_TRACK *track, SHAPE *trackShape, PCB_LAYER_ID layer, BOARD_ITEM *other)
Checks for track/via/hole <-> clearance.
void testTrackClearances()
virtual ~DRC_TEST_PROVIDER_COPPER_CLEARANCE()
virtual const wxString GetDescription() const override
virtual const wxString GetName() const override
bool testPadAgainstItem(PAD *pad, SHAPE *padShape, PCB_LAYER_ID layer, BOARD_ITEM *other)
virtual bool reportPhase(const wxString &aStageName)
virtual bool reportProgress(int aCount, int aSize, int aDelta)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer)
void reportAux(const wxString &aMsg)
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, int aConstraint, int aActual)
virtual void reportRuleStatistics()
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.
LSET is a set of PCB_LAYER_IDs.
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.
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
const VECTOR2I & GetDrillSize() const
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
VECTOR2I GetPosition() const override
bool HasHole() const override
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
int GetDrill() const
Return the local drill setting for this PCB_VIA.
bool IsOnLayer(PCB_LAYER_ID aLayer, bool aIncludeCourtyards=false) const override
Test to see if this object is on the given layer.
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
Represent a set of closed polygons.
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:
virtual bool IsOnLayer(PCB_LAYER_ID, bool aIncludeCourtyards=false) const override
Test to see if this object is on the given layer.
const BOX2I GetBoundingBox() const override
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
unsigned GetAssignedPriority() const
@ HOLE_CLEARANCE_CONSTRAINT
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
std::optional< VECTOR2I > OPT_VECTOR2I
static bool Collide(const SHAPE_CIRCLE &aA, const SHAPE_CIRCLE &aB, int aClearance, int *aActual, VECTOR2I *aLocation, VECTOR2I *aMTV)
checked(PCB_LAYER_ID aLayer)
@ 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_PAD_T
class PAD, a pad in a footprint
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)