KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_test_provider_hole_to_hole.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <common.h>
26#include <footprint.h>
27#include <pad.h>
28#include <pcb_track.h>
31#include <drc/drc_engine.h>
32#include <drc/drc_item.h>
33#include <drc/drc_rule.h>
35#include "drc_rtree.h"
36
37/*
38 Holes clearance test. Checks pad and via holes for their mechanical clearances.
39 Generated errors:
40 - DRCE_DRILLED_HOLES_TOO_CLOSE
41 - DRCE_DRILLED_HOLES_COLOCATED
42*/
43
45{
46public:
49 m_board( nullptr ),
51 {}
52
54
55 virtual bool Run() override;
56
57 virtual const wxString GetName() const override { return wxT( "hole_to_hole_clearance" ); };
58
59private:
60 bool testHoleAgainstHole( BOARD_ITEM* aItem, SHAPE_CIRCLE* aHole, BOARD_ITEM* aOther );
61
65};
66
67
68static std::shared_ptr<SHAPE_CIRCLE> getHoleShape( BOARD_ITEM* aItem )
69{
70 if( aItem->Type() == PCB_VIA_T )
71 {
72 PCB_VIA* via = static_cast<PCB_VIA*>( aItem );
73 return std::make_shared<SHAPE_CIRCLE>( via->GetCenter(), via->GetDrillValue() / 2 );
74 }
75 else if( aItem->Type() == PCB_PAD_T )
76 {
77 PAD* pad = static_cast<PAD*>( aItem );
78 return std::make_shared<SHAPE_CIRCLE>( pad->GetPosition(), pad->GetDrillSize().x / 2 );
79 }
80
81 return std::make_shared<SHAPE_CIRCLE>( VECTOR2I( 0, 0 ), 0 );
82}
83
84
86{
89 {
90 REPORT_AUX( wxT( "Hole to hole violations ignored. Tests not run." ) );
91 return true; // continue with other tests
92 }
93
95
96 DRC_CONSTRAINT worstClearanceConstraint;
97
98 if( m_drcEngine->QueryWorstConstraint( HOLE_TO_HOLE_CONSTRAINT, worstClearanceConstraint ) )
99 {
100 m_largestHoleToHoleClearance = worstClearanceConstraint.GetValue().Min();
101 }
102 else
103 {
104 REPORT_AUX( wxT( "No hole to hole constraints found. Skipping check." ) );
105 return true; // continue with other tests
106 }
107
108 if( !reportPhase( _( "Checking hole to hole clearances..." ) ) )
109 return false; // DRC cancelled
110
111 const size_t progressDelta = 200;
112 size_t count = 0;
113 size_t ii = 0;
114
116
118 [&]( BOARD_ITEM* item ) -> bool
119 {
120 ++count;
121 return true;
122 } );
123
124 count *= 2; // One for adding to the rtree; one for checking
125
127 [&]( BOARD_ITEM* item ) -> bool
128 {
129 if( !reportProgress( ii++, count, progressDelta ) )
130 return false;
131
132 if( item->Type() == PCB_PAD_T )
133 {
134 PAD* pad = static_cast<PAD*>( item );
135
136 // Slots are generally milled _after_ drilling, so we ignore them.
137 if( pad->GetDrillSize().x && pad->GetDrillSize().x == pad->GetDrillSize().y )
139 }
140 else if( item->Type() == PCB_VIA_T )
141 {
142 // Blind/buried/microvias will be drilled/burned _prior_ to lamination, so
143 // subsequently drilled holes need to avoid them.
145 }
146
147 return true;
148 } );
149
150 std::unordered_map<PTR_PTR_CACHE_KEY, int> checkedPairs;
151
152 for( PCB_TRACK* track : m_board->Tracks() )
153 {
154 if( track->Type() != PCB_VIA_T )
155 continue;
156
157 PCB_VIA* via = static_cast<PCB_VIA*>( track );
158
159 if( !reportProgress( ii++, count, progressDelta ) )
160 return false; // DRC cancelled
161
162 // We only care about mechanically drilled (ie: non-laser) holes. These include both
163 // blind/buried via holes (drilled prior to lamination) and through-via and drilled pad
164 // holes (which are generally drilled post laminataion).
165 if( via->GetViaType() != VIATYPE::MICROVIA )
166 {
167 std::shared_ptr<SHAPE_CIRCLE> holeShape = getHoleShape( via );
168
170 // Filter:
171 [&]( BOARD_ITEM* other ) -> bool
172 {
173 BOARD_ITEM* a = via;
174 BOARD_ITEM* b = other;
175
176 // store canonical order so we don't collide in both directions
177 // (a:b and b:a)
178 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
179 std::swap( a, b );
180
181 if( checkedPairs.find( { a, b } ) != checkedPairs.end() )
182 {
183 return false;
184 }
185 else
186 {
187 checkedPairs[ { a, b } ] = 1;
188 return true;
189 }
190 },
191 // Visitor:
192 [&]( BOARD_ITEM* other ) -> bool
193 {
194 return testHoleAgainstHole( via, holeShape.get(), other );
195 },
197 }
198 }
199
200 checkedPairs.clear();
201
202 for( FOOTPRINT* footprint : m_board->Footprints() )
203 {
204 for( PAD* pad : footprint->Pads() )
205 {
206 if( !reportProgress( ii++, count, progressDelta ) )
207 return false; // DRC cancelled
208
209 // We only care about drilled (ie: round) pad holes
210 if( pad->HasDrilledHole() )
211 {
212 std::shared_ptr<SHAPE_CIRCLE> holeShape = getHoleShape( pad );
213
214 m_holeTree.QueryColliding( pad, Edge_Cuts, Edge_Cuts,
215 // Filter:
216 [&]( BOARD_ITEM* other ) -> bool
217 {
218 BOARD_ITEM* a = pad;
219 BOARD_ITEM* b = other;
220
221 // store canonical order so we don't collide in both directions
222 // (a:b and b:a)
223 if( static_cast<void*>( a ) > static_cast<void*>( b ) )
224 std::swap( a, b );
225
226 if( checkedPairs.find( { a, b } ) != checkedPairs.end() )
227 {
228 return false;
229 }
230 else
231 {
232 checkedPairs[ { a, b } ] = 1;
233 return true;
234 }
235 },
236 // Visitor:
237 [&]( BOARD_ITEM* other ) -> bool
238 {
239 return testHoleAgainstHole( pad, holeShape.get(), other );
240 },
241 m_largestHoleToHoleClearance );
242 }
243 }
244
245 if( m_drcEngine->IsCancelled() )
246 return false;
247 }
248
249 return !m_drcEngine->IsCancelled();
250}
251
252
254 BOARD_ITEM* aOther )
255{
258
259 if( !reportCoLocation && !reportHole2Hole )
260 return false;
261
262 std::shared_ptr<SHAPE_CIRCLE> otherHole = getHoleShape( aOther );
264 SEG::ecoord epsilon_sq = SEG::Square( epsilon );
265
266 // Blind-buried vias are drilled prior to stackup; they're only an issue if they share layers
267 if( aItem->Type() == PCB_VIA_T && aOther->Type() == PCB_VIA_T )
268 {
269 LSET viaHoleLayers = static_cast<PCB_VIA*>( aItem )->GetLayerSet() & LSET::AllCuMask();
270
271 if( ( viaHoleLayers & static_cast<PCB_VIA*>( aOther )->GetLayerSet() ).none() )
272 return false;
273 }
274
275 // Holes at same location generate a separate violation
276 if( ( aHole->GetCenter() - otherHole->GetCenter() ).SquaredEuclideanNorm() < epsilon_sq )
277 {
278 if( reportCoLocation )
279 {
280 // Generate violations based on a well-defined order so that exclusion checking
281 // against previously-generated violations will work.
282 if( aItem->m_Uuid > aOther->m_Uuid )
283 std::swap( aItem, aOther );
284
285 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_DRILLED_HOLES_COLOCATED );
286 drce->SetItems( aItem, aOther );
287 reportViolation( drce, aHole->GetCenter(), UNDEFINED_LAYER );
288 }
289 }
290 else if( reportHole2Hole )
291 {
292 int actual = ( aHole->GetCenter() - otherHole->GetCenter() ).EuclideanNorm();
293 actual = std::max( 0, actual - aHole->GetRadius() - otherHole->GetRadius() );
294
295 auto constraint = m_drcEngine->EvalRules( HOLE_TO_HOLE_CONSTRAINT, aItem, aOther,
296 UNDEFINED_LAYER /* holes pierce all layers */ );
297 int minClearance = std::max( 0, constraint.GetValue().Min() - epsilon );
298
299 if( constraint.GetSeverity() != RPT_SEVERITY_IGNORE
300 && minClearance >= 0
301 && actual < minClearance )
302 {
303 // Generate violations based on a well-defined order so that exclusion checking
304 // against previously-generated violations will work.
305 if( aItem->m_Uuid > aOther->m_Uuid )
306 std::swap( aItem, aOther );
307
308 std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_DRILLED_HOLES_TOO_CLOSE );
309 wxString msg = formatMsg( _( "(%s min %s; actual %s)" ),
310 constraint.GetName(),
311 minClearance,
312 actual );
313
314 drce->SetErrorMessage( drce->GetErrorText() + wxS( " " ) + msg );
315 drce->SetItems( aItem, aOther );
316 drce->SetViolatingRule( constraint.GetParentRule() );
317
318 reportViolation( drce, aHole->GetCenter(), UNDEFINED_LAYER );
319 }
320 }
321
322 return !m_drcEngine->IsCancelled();
323}
324
325
326namespace detail
327{
329}
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...
Definition: board_item.h:79
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:314
const TRACKS & Tracks() const
Definition: board.h:353
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:943
const MINOPTMAX< int > & GetValue() const
Definition: drc_rule.h:160
BOARD * GetBoard() const
Definition: drc_engine.h:95
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)
Definition: drc_engine.cpp:693
bool IsCancelled() const
bool QueryWorstConstraint(DRC_CONSTRAINT_T aRuleId, DRC_CONSTRAINT &aConstraint)
static std::shared_ptr< DRC_ITEM > Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:393
Implement an R-tree for fast spatial and layer indexing of connectable items.
Definition: drc_rtree.h:48
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.
Definition: drc_rtree.h:104
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.
Definition: drc_rtree.h:214
void clear()
Remove all items from the RTree.
Definition: drc_rtree.h:167
virtual const wxString GetName() const override
bool testHoleAgainstHole(BOARD_ITEM *aItem, SHAPE_CIRCLE *aHole, BOARD_ITEM *aOther)
virtual ~DRC_TEST_PROVIDER_HOLE_TO_HOLE()=default
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
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)
DRC_ENGINE * m_drcEngine
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)
const KIID m_Uuid
Definition: eda_item.h:507
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:109
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:583
static const LSET & AllLayersMask()
Definition: lset.cpp:627
T Min() const
Definition: minoptmax.h:33
Definition: pad.h:54
VECTOR2I::extended_type ecoord
Definition: seg.h:44
static SEG::ecoord Square(int a)
Definition: seg.h:123
int GetRadius() const
Definition: shape_circle.h:118
const VECTOR2I GetCenter() const
Definition: shape_circle.h:123
The common library.
@ DRCE_DRILLED_HOLES_TOO_CLOSE
Definition: drc_item.h:52
@ DRCE_DRILLED_HOLES_COLOCATED
Definition: drc_item.h:53
@ HOLE_TO_HOLE_CONSTRAINT
Definition: drc_rule.h:52
#define REPORT_AUX(s)
static std::shared_ptr< SHAPE_CIRCLE > getHoleShape(BOARD_ITEM *aItem)
#define _(s)
@ Edge_Cuts
Definition: layer_ids.h:112
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
static DRC_REGISTER_TEST_PROVIDER< DRC_TEST_PROVIDER_ANNULAR_WIDTH > dummy
@ RPT_SEVERITY_IGNORE
const double epsilon
int actual
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695