57 virtual bool Run()
override;
59 virtual const wxString
GetName()
const override {
return wxT(
"physical_clearance" ); };
87 REPORT_AUX( wxT(
"No physical clearance constraints found. Tests not run." ) );
91 size_t progressDelta = 250;
98 static const std::vector<KICAD_T> itemTypes = {
136 if( layers.Contains( F_Cu ) )
137 layers |= LSET( LSET::FrontBoardTechMask() ).set( F_CrtYd );
139 if( layers.Contains( B_Cu ) )
140 layers |= LSET( LSET::BackBoardTechMask() ).set( B_CrtYd );
142 if( layers.Contains( F_Cu ) && layers.Contains( B_Cu ) )
143 layers |= boardCopperLayers;
151 layers |= LSET::PhysicalLayersMask() | courtyards;
160 std::unordered_map<PTR_PTR_CACHE_KEY, LSET> checkedPairs;
171 if( !
reportPhase(
_(
"Checking physical clearances..." ) ) )
187 std::shared_ptr<SHAPE> itemShape = item->GetEffectiveShape( layer );
189 m_itemTree.QueryColliding( item, layer, layer,
191 [&]( BOARD_ITEM* other ) -> bool
193 BOARD_ITEM* a = item;
194 BOARD_ITEM* b = other;
198 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
201 auto it = checkedPairs.find( { a, b } );
203 if( it != checkedPairs.end() && it->second.test( layer ) )
209 checkedPairs[ { a, b } ].set( layer );
216 if( testItemAgainstItem( item, itemShape.get(), layer,
219 BOARD_ITEM* a = item;
220 BOARD_ITEM* b = other;
223 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
228 checkedPairs[ { a, b } ].set();
253 ZONE* zone =
dynamic_cast<ZONE*
>( item );
258 count += ( item->GetLayerSet() & boardCopperLayers ).count();
271 ZONE* zone =
dynamic_cast<ZONE*
>( item );
280 if( !reportProgress( ii++, count, progressDelta ) )
304 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
319 for(
int step = 1; step <= steps; ++step )
321 EDA_ANGLE rotation = ( angle * step ) / steps;
328 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
342 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
352 testShapeLineChain( asPoly, shape->
GetWidth(), layer, item, c );
362 testZoneLayer(
static_cast<ZONE*
>( item ), layer, c );
365 if( m_drcEngine->IsCancelled() )
369 return !m_drcEngine->IsCancelled();
372 return !m_drcEngine->IsCancelled();
392 std::vector<double> angles;
393 angles.reserve( count );
396 [](
double a,
double b ) ->
double
404 return 2 * M_PI - diff;
409 for(
int ii = 0; ii < count; ++ii )
421 angles.push_back( angles.back() );
425 for(
int jj = 1; jj < count; ++jj )
439 std::vector< std::pair<VECTOR2I, int> > collisions;
441 for(
int ii = 0; ii < count; ++ii )
444 double segAngle = angles[ ii ];
447 int firstCandidate = ii + 1;
448 int lastCandidate = count - 1;
450 while( firstCandidate < count )
452 if( angleDiff( segAngle, angles[ firstCandidate ] ) < angleTolerance )
461 lastCandidate = ii - 1;
463 while( lastCandidate != std::min( firstCandidate, count - 1 ) )
465 if( angleDiff( segAngle, angles[ lastCandidate ] ) < angleTolerance )
466 lastCandidate = ( lastCandidate == 0 ) ? count - 1 : lastCandidate - 1;
473 if( lastCandidate < ii )
474 lastCandidate = count - 1;
476 for(
int jj = firstCandidate; jj <= lastCandidate; ++jj )
485 VECTOR2I pos = ( firstPoint + secondPoint ) / 2;
487 if( !collisions.empty() && ( 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(
const std::pair<VECTOR2I, int>& collision : collisions )
511 pt += parentFP->GetPosition();
514 wxString msg =
formatMsg(
_(
"Internal clearance violation (%s clearance %s; actual %s)" ),
519 drce->SetErrorMessage( msg );
520 drce->SetItems( aParentItem );
542 for(
int outlineIdx = 0; outlineIdx < fill.
OutlineCount(); ++outlineIdx )
550 for(
int ii = outlineIdx + 1; ii < fill.
OutlineCount(); ++ii )
554 for(
int jj = 0; jj < secondOutline->
SegmentCount(); ++jj )
563 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
568 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
569 drce->SetItems( aZone );
584 for(
int holeIdx = 0; holeIdx < fill.
HoleCount( outlineIdx ); ++holeIdx )
608 SHAPE* otherShape = otherShapeStorage.get();
622 std::swap( aItem, aOther );
623 std::swap( aItemShape, otherShape );
629 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
634 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
635 drce->SetItems( aItem, aOther );
645 std::shared_ptr<SHAPE_SEGMENT> itemHoleShape;
646 std::shared_ptr<SHAPE_SEGMENT> otherHoleShape;
660 layers |= boardCopperLayers;
662 wxCHECK_MSG( layers.
Contains( aLayer ), violations,
663 wxT(
"Bug! Vias should only be checked for layers on which they exist" ) );
683 layers |= boardCopperLayers;
685 wxCHECK_MSG( layers.
Contains( aLayer ), violations,
686 wxT(
"Bug! Vias should only be checked for layers on which they exist" ) );
695 if( itemHoleShape || otherHoleShape )
704 if( itemHoleShape && itemHoleShape->Collide( otherShape,
clearance, &
actual, &pos ) )
707 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
712 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
713 drce->SetItems( aItem, aOther );
720 if( otherHoleShape && otherHoleShape->Collide( aItemShape,
clearance, &
actual, &pos ) )
723 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
728 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
729 drce->SetItems( aItem, aOther );
751 BOX2I worstCaseBBox = itemBBox;
761 if( !testClearance && !testHoles )
786 if( !
pad->FlashLayer( aLayer ) )
788 if(
pad->GetDrillSize().x == 0 &&
pad->GetDrillSize().y == 0 )
791 std::shared_ptr<SHAPE_SEGMENT> hole =
pad->GetEffectiveHoleShape();
792 int size = hole->GetWidth();
794 itemShape = std::make_shared<SHAPE_SEGMENT>( hole->GetSeg(), size );
811 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
816 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
817 drce->SetItems( aItem, zone );
826 std::shared_ptr<SHAPE_SEGMENT> holeShape;
850 wxString msg =
formatMsg(
_(
"(%s clearance %s; actual %s)" ),
855 drce->SetErrorMessage( drce->GetErrorText() + wxS(
" " ) + msg );
856 drce->SetItems( aItem, zone );
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
Return an epsilon which accounts for rounding errors, etc.
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 GetCopperLayerCount() 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()=default
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 bool reportPhase(const wxString &aStageName)
virtual void reportViolation(std::shared_ptr< DRC_ITEM > &item, const VECTOR2I &aMarkerPos, int aMarkerLayer, DRC_CUSTOM_MARKER_HANDLER *aCustomHandler=nullptr)
int forEachGeometryItem(const std::vector< KICAD_T > &aTypes, const LSET &aLayers, const std::function< bool(BOARD_ITEM *)> &aFunc)
wxString formatMsg(const wxString &aFormatString, const wxString &aSource, double aConstraint, double aActual, EDA_DATA_TYPE aDataType=EDA_DATA_TYPE::DISTANCE)
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 const LSET & FrontBoardTechMask()
Return a mask holding technical layers used in a board fabrication (no CU layer) on front side.
static const LSET & AllLayersMask()
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
static const 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()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
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
@ RECTANGLE
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)
Test 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_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
@ 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_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)