KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_engine.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 (C) 2004-2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2014 Dick Hollenbeck, [email protected]
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <atomic>
27#include <wx/log.h>
28#include <reporter.h>
29#include <common.h>
30#include <progress_reporter.h>
31#include <string_utils.h>
33#include <drc/drc_engine.h>
34#include <drc/drc_rtree.h>
35#include <drc/drc_rule_parser.h>
36#include <drc/drc_rule.h>
39#include <drc/drc_item.h>
41#include <footprint.h>
42#include <pad.h>
43#include <pcb_track.h>
44#include <pcb_shape.h>
45#include <core/profile.h>
46#include <thread_pool.h>
47#include <zone.h>
50
51
52// wxListBox's performance degrades horrifically with very large datasets. It's not clear
53// they're useful to the user anyway.
54#define ERROR_LIMIT 199
55#define EXTENDED_ERROR_LIMIT 499
56
57
65static const wxChar* traceDrcProfile = wxT( "KICAD_DRC_PROFILE" );
66
67
68void drcPrintDebugMessage( int level, const wxString& msg, const char *function, int line )
69{
70 wxString valueStr;
71
72 if( wxGetEnv( wxT( "DRC_DEBUG" ), &valueStr ) )
73 {
74 int setLevel = wxAtoi( valueStr );
75
76 if( level <= setLevel )
77 printf( "%-30s:%d | %s\n", function, line, (const char *) msg.c_str() );
78 }
79}
80
81
84 m_designSettings ( aSettings ),
85 m_board( aBoard ),
86 m_drawingSheet( nullptr ),
87 m_schematicNetlist( nullptr ),
88 m_rulesValid( false ),
90 m_testFootprints( false ),
91 m_logReporter( nullptr ),
92 m_progressReporter( nullptr )
93{
94 m_errorLimits.resize( DRCE_LAST + 1 );
95
96 for( int ii = DRCE_FIRST; ii <= DRCE_LAST; ++ii )
98}
99
100
102{
103 m_rules.clear();
104
105 for( std::pair<DRC_CONSTRAINT_T, std::vector<DRC_ENGINE_CONSTRAINT*>*> pair : m_constraintMap )
106 {
107 for( DRC_ENGINE_CONSTRAINT* constraint : *pair.second )
108 delete constraint;
109
110 delete pair.second;
111 }
112}
113
114
115static bool isKeepoutZone( const BOARD_ITEM* aItem, bool aCheckFlags )
116{
117 if( !aItem || aItem->Type() != PCB_ZONE_T )
118 return false;
119
120 const ZONE* zone = static_cast<const ZONE*>( aItem );
121
122 if( !zone->GetIsRuleArea() )
123 return false;
124
125 if( !zone->HasKeepoutParametersSet() )
126 return false;
127
128 if( aCheckFlags )
129 {
130 if( !zone->GetDoNotAllowTracks()
131 && !zone->GetDoNotAllowVias()
132 && !zone->GetDoNotAllowPads()
133 && !zone->GetDoNotAllowZoneFills()
134 && !zone->GetDoNotAllowFootprints() )
135 {
136 return false;
137 }
138 }
139
140 return true;
141}
142
143
144std::shared_ptr<DRC_RULE> DRC_ENGINE::createImplicitRule( const wxString& name,
145 const DRC_IMPLICIT_SOURCE aImplicitSource )
146{
147 std::shared_ptr<DRC_RULE> rule = std::make_shared<DRC_RULE>();
148
149 rule->m_Name = name;
150 rule->SetImplicitSource( aImplicitSource );
151
152 addRule( rule );
153
154 return rule;
155}
156
157
159{
160 BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
161 wxString expr, expr2, ncName;
162
163 // 1) global defaults
164
165 std::shared_ptr<DRC_RULE> rule =
167
168 DRC_CONSTRAINT widthConstraint( TRACK_WIDTH_CONSTRAINT );
169 widthConstraint.Value().SetMin( bds.m_TrackMinWidth );
170 rule->AddConstraint( widthConstraint );
171
172 DRC_CONSTRAINT connectionConstraint( CONNECTION_WIDTH_CONSTRAINT );
173 connectionConstraint.Value().SetMin( bds.m_MinConn );
174 rule->AddConstraint( connectionConstraint );
175
176 DRC_CONSTRAINT drillConstraint( HOLE_SIZE_CONSTRAINT );
177 drillConstraint.Value().SetMin( bds.m_MinThroughDrill );
178 rule->AddConstraint( drillConstraint );
179
180 DRC_CONSTRAINT annulusConstraint( ANNULAR_WIDTH_CONSTRAINT );
181 annulusConstraint.Value().SetMin( bds.m_ViasMinAnnularWidth );
182 rule->AddConstraint( annulusConstraint );
183
184 DRC_CONSTRAINT diameterConstraint( VIA_DIAMETER_CONSTRAINT );
185 diameterConstraint.Value().SetMin( bds.m_ViasMinSize );
186 rule->AddConstraint( diameterConstraint );
187
188 DRC_CONSTRAINT holeToHoleConstraint( HOLE_TO_HOLE_CONSTRAINT );
189 holeToHoleConstraint.Value().SetMin( bds.m_HoleToHoleMin );
190 rule->AddConstraint( holeToHoleConstraint );
191
192 rule = createImplicitRule( _( "board setup constraints zone fill strategy" ),
194 DRC_CONSTRAINT thermalSpokeCountConstraint( MIN_RESOLVED_SPOKES_CONSTRAINT );
195 thermalSpokeCountConstraint.Value().SetMin( bds.m_MinResolvedSpokes );
196 rule->AddConstraint( thermalSpokeCountConstraint );
197
198 rule = createImplicitRule( _( "board setup constraints silk" ), DRC_IMPLICIT_SOURCE::BOARD_SETUP_CONSTRAINT );
199 rule->m_LayerCondition = LSET( { F_SilkS, B_SilkS } );
200 DRC_CONSTRAINT silkClearanceConstraint( SILK_CLEARANCE_CONSTRAINT );
201 silkClearanceConstraint.Value().SetMin( bds.m_SilkClearance );
202 rule->AddConstraint( silkClearanceConstraint );
203
204 rule = createImplicitRule( _( "board setup constraints silk text height" ),
206 rule->m_LayerCondition = LSET( { F_SilkS, B_SilkS } );
207 DRC_CONSTRAINT silkTextHeightConstraint( TEXT_HEIGHT_CONSTRAINT );
208 silkTextHeightConstraint.Value().SetMin( bds.m_MinSilkTextHeight );
209 rule->AddConstraint( silkTextHeightConstraint );
210
211 rule = createImplicitRule( _( "board setup constraints silk text thickness" ),
213 rule->m_LayerCondition = LSET( { F_SilkS, B_SilkS } );
214 DRC_CONSTRAINT silkTextThicknessConstraint( TEXT_THICKNESS_CONSTRAINT );
215 silkTextThicknessConstraint.Value().SetMin( bds.m_MinSilkTextThickness );
216 rule->AddConstraint( silkTextThicknessConstraint );
217
218 rule = createImplicitRule( _( "board setup constraints hole" ), DRC_IMPLICIT_SOURCE::BOARD_SETUP_CONSTRAINT );
219 DRC_CONSTRAINT holeClearanceConstraint( HOLE_CLEARANCE_CONSTRAINT );
220 holeClearanceConstraint.Value().SetMin( bds.m_HoleClearance );
221 rule->AddConstraint( holeClearanceConstraint );
222
223 rule = createImplicitRule( _( "board setup constraints edge" ), DRC_IMPLICIT_SOURCE::BOARD_SETUP_CONSTRAINT );
224 DRC_CONSTRAINT edgeClearanceConstraint( EDGE_CLEARANCE_CONSTRAINT );
225 edgeClearanceConstraint.Value().SetMin( bds.m_CopperEdgeClearance );
226 rule->AddConstraint( edgeClearanceConstraint );
227
228 rule = createImplicitRule( _( "board setup constraints courtyard" ), DRC_IMPLICIT_SOURCE::BOARD_SETUP_CONSTRAINT );
229 DRC_CONSTRAINT courtyardClearanceConstraint( COURTYARD_CLEARANCE_CONSTRAINT );
230 holeToHoleConstraint.Value().SetMin( 0 );
231 rule->AddConstraint( courtyardClearanceConstraint );
232
233 // 2a) micro-via specific defaults (new DRC doesn't treat microvias in any special way)
234
235 std::shared_ptr<DRC_RULE> uViaRule =
236 createImplicitRule( _( "board setup micro-via constraints" ), DRC_IMPLICIT_SOURCE::BOARD_SETUP_CONSTRAINT );
237
238 uViaRule->m_Condition = new DRC_RULE_CONDITION( wxT( "A.Via_Type == 'Micro'" ) );
239
240 DRC_CONSTRAINT uViaDrillConstraint( HOLE_SIZE_CONSTRAINT );
241 uViaDrillConstraint.Value().SetMin( bds.m_MicroViasMinDrill );
242 uViaRule->AddConstraint( uViaDrillConstraint );
243
244 DRC_CONSTRAINT uViaDiameterConstraint( VIA_DIAMETER_CONSTRAINT );
245 uViaDiameterConstraint.Value().SetMin( bds.m_MicroViasMinSize );
246 uViaRule->AddConstraint( uViaDiameterConstraint );
247
248 // 2b) barcode-specific defaults
249
250 std::shared_ptr<DRC_RULE> barcodeRule =
251 createImplicitRule( _( "barcode visual separation default" ), DRC_IMPLICIT_SOURCE::BARCODE_DEFAULTS );
252 DRC_CONSTRAINT barcodeSeparationConstraint( PHYSICAL_CLEARANCE_CONSTRAINT );
253 barcodeSeparationConstraint.Value().SetMin( GetIuScale().mmToIU( 1.0 ) );
254 barcodeRule->AddConstraint( barcodeSeparationConstraint );
255 barcodeRule->m_Condition = new DRC_RULE_CONDITION( wxT( "A.Type == 'Barcode'" ) );
256
257 // 3) per-netclass rules
258
259 std::vector<std::shared_ptr<DRC_RULE>> netclassClearanceRules;
260 std::vector<std::shared_ptr<DRC_RULE>> netclassItemSpecificRules;
261
262 auto makeNetclassRules =
263 [&]( const std::shared_ptr<NETCLASS>& nc, bool isDefault )
264 {
265 ncName = nc->GetName();
266 ncName.Replace( "'", "\\'" );
267
268 if( nc->HasClearance() )
269 {
270 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
271 netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ),
272 nc->GetClearanceParent()->GetHumanReadableName() );
273 netclassRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::NET_CLASS );
274
275 expr = wxString::Format( wxT( "A.hasExactNetclass('%s')" ), ncName );
276 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
277 netclassClearanceRules.push_back( netclassRule );
278
280 constraint.Value().SetMin( nc->GetClearance() );
281 netclassRule->AddConstraint( constraint );
282 }
283
284 if( nc->HasTrackWidth() )
285 {
286 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
287 netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ),
288 nc->GetTrackWidthParent()->GetHumanReadableName() );
289 netclassRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::NET_CLASS );
290
291 expr = wxString::Format( wxT( "A.hasExactNetclass('%s')" ), ncName );
292 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
293 netclassClearanceRules.push_back( netclassRule );
294
296 constraint.Value().SetMin( bds.m_TrackMinWidth );
297 constraint.Value().SetOpt( nc->GetTrackWidth() );
298 netclassRule->AddConstraint( constraint );
299 }
300
301 if( nc->HasDiffPairWidth() )
302 {
303 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
304 netclassRule->m_Name = wxString::Format( _( "netclass '%s' (diff pair)" ),
305 nc->GetDiffPairWidthParent()->GetHumanReadableName() );
306 netclassRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::NET_CLASS );
307
308 expr = wxString::Format( wxT( "A.hasExactNetclass('%s') && A.inDiffPair('*')" ), ncName );
309 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
310 netclassItemSpecificRules.push_back( netclassRule );
311
313 constraint.Value().SetMin( bds.m_TrackMinWidth );
314 constraint.Value().SetOpt( nc->GetDiffPairWidth() );
315 netclassRule->AddConstraint( constraint );
316 }
317
318 if( nc->HasDiffPairGap() )
319 {
320 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
321 netclassRule->m_Name = wxString::Format( _( "netclass '%s' (diff pair)" ),
322 nc->GetDiffPairGapParent()->GetHumanReadableName() );
323 netclassRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::NET_CLASS );
324
325 expr = wxString::Format( wxT( "A.hasExactNetclass('%s')" ), ncName );
326 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
327 netclassItemSpecificRules.push_back( netclassRule );
328
330 constraint.Value().SetMin( bds.m_MinClearance );
331 constraint.Value().SetOpt( nc->GetDiffPairGap() );
332 netclassRule->AddConstraint( constraint );
333
334 // A narrower diffpair gap overrides the netclass min clearance
335 if( nc->GetDiffPairGap() < nc->GetClearance() )
336 {
337 netclassRule = std::make_shared<DRC_RULE>();
338 netclassRule->m_Name = wxString::Format( _( "netclass '%s' (diff pair)" ),
339 nc->GetDiffPairGapParent()->GetHumanReadableName() );
340 netclassRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::NET_CLASS );
341
342 expr = wxString::Format( wxT( "A.hasExactNetclass('%s') && AB.isCoupledDiffPair()" ), ncName );
343 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
344 netclassItemSpecificRules.push_back( netclassRule );
345
346 DRC_CONSTRAINT min_clearanceConstraint( CLEARANCE_CONSTRAINT );
347 min_clearanceConstraint.Value().SetMin( nc->GetDiffPairGap() );
348 netclassRule->AddConstraint( min_clearanceConstraint );
349 }
350 }
351
352 if( nc->HasViaDiameter() )
353 {
354 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
355 netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ),
356 nc->GetViaDiameterParent()->GetHumanReadableName() );
357 netclassRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::NET_CLASS );
358
359 expr = wxString::Format( wxT( "A.hasExactNetclass('%s') && A.Via_Type != 'Micro'" ), ncName );
360 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
361 netclassItemSpecificRules.push_back( netclassRule );
362
364 constraint.Value().SetMin( bds.m_ViasMinSize );
365 constraint.Value().SetOpt( nc->GetViaDiameter() );
366 netclassRule->AddConstraint( constraint );
367 }
368
369 if( nc->HasViaDrill() )
370 {
371 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
372 netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ),
373 nc->GetViaDrillParent()->GetHumanReadableName() );
374 netclassRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::NET_CLASS );
375
376 expr = wxString::Format( wxT( "A.hasExactNetclass('%s') && A.Via_Type != 'Micro'" ), ncName );
377 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
378 netclassItemSpecificRules.push_back( netclassRule );
379
381 constraint.Value().SetMin( bds.m_MinThroughDrill );
382 constraint.Value().SetOpt( nc->GetViaDrill() );
383 netclassRule->AddConstraint( constraint );
384 }
385
386 if( nc->HasuViaDiameter() )
387 {
388 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
389 netclassRule->m_Name = wxString::Format( _( "netclass '%s' (uvia)" ),
390 nc->GetuViaDiameterParent()->GetHumanReadableName() );
391 netclassRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::NET_CLASS );
392
393 expr = wxString::Format( wxT( "A.hasExactNetclass('%s') && A.Via_Type == 'Micro'" ), ncName );
394 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
395 netclassItemSpecificRules.push_back( netclassRule );
396
398 constraint.Value().SetMin( bds.m_MicroViasMinSize );
399 constraint.Value().SetMin( nc->GetuViaDiameter() );
400 netclassRule->AddConstraint( constraint );
401 }
402
403 if( nc->HasuViaDrill() )
404 {
405 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
406 netclassRule->m_Name = wxString::Format( _( "netclass '%s' (uvia)" ),
407 nc->GetuViaDrillParent()->GetHumanReadableName() );
408 netclassRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::NET_CLASS );
409
410 expr = wxString::Format( wxT( "A.hasExactNetclass('%s') && A.Via_Type == 'Micro'" ), ncName );
411 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
412 netclassItemSpecificRules.push_back( netclassRule );
413
415 constraint.Value().SetMin( bds.m_MicroViasMinDrill );
416 constraint.Value().SetOpt( nc->GetuViaDrill() );
417 netclassRule->AddConstraint( constraint );
418 }
419 };
420
421 m_board->SynchronizeNetsAndNetClasses( false );
422 makeNetclassRules( bds.m_NetSettings->GetDefaultNetclass(), true );
423
424 for( const auto& [name, netclass] : bds.m_NetSettings->GetNetclasses() )
425 makeNetclassRules( netclass, false );
426
427 for( const auto& [name, netclass] : bds.m_NetSettings->GetCompositeNetclasses() )
428 makeNetclassRules( netclass, false );
429
430 // The netclass clearance rules have to be sorted by min clearance so the right one fires
431 // if 'A' and 'B' belong to two different netclasses.
432 //
433 // The item-specific netclass rules are all unary, so there's no 'A' vs 'B' issue.
434
435 std::sort( netclassClearanceRules.begin(), netclassClearanceRules.end(),
436 []( const std::shared_ptr<DRC_RULE>& lhs, const std::shared_ptr<DRC_RULE>& rhs )
437 {
438 return lhs->m_Constraints[0].m_Value.Min()
439 < rhs->m_Constraints[0].m_Value.Min();
440 } );
441
442 for( std::shared_ptr<DRC_RULE>& ncRule : netclassClearanceRules )
443 addRule( ncRule );
444
445 for( std::shared_ptr<DRC_RULE>& ncRule : netclassItemSpecificRules )
446 addRule( ncRule );
447
448 // 4) tuning profile rules
449 auto addTuningSingleRule =
450 [&]( const DELAY_PROFILE_TRACK_PROPAGATION_ENTRY& aLayerEntry, const wxString& aProfileName,
451 const wxString& aNetclassName )
452 {
453 if( aLayerEntry.GetWidth() <= 0 )
454 return;
455
456 std::shared_ptr<DRC_RULE> tuningRule = std::make_shared<DRC_RULE>();
457 tuningRule->m_Severity = bds.m_DRCSeverities[DRCE_TUNING_PROFILE_IMPLICIT_RULES];
458 tuningRule->m_Name = wxString::Format( _( "tuning profile '%s'" ), aProfileName );
459 tuningRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::TUNING_PROFILE );
460
461 expr = wxString::Format( wxT( "A.hasExactNetclass('%s') && A.Layer == '%s'" ),
462 aNetclassName,
463 LSET::Name( aLayerEntry.GetSignalLayer() ) );
464 tuningRule->m_Condition = new DRC_RULE_CONDITION( expr );
465
467 constraint.Value().SetMin( std::max( bds.m_TrackMinWidth, aLayerEntry.GetWidth() ) );
468 constraint.Value().SetOpt( aLayerEntry.GetWidth() );
469 constraint.Value().SetMax( aLayerEntry.GetWidth() );
470 tuningRule->AddConstraint( constraint );
471
472 addRule( tuningRule );
473 };
474
475 auto addTuningDifferentialRules =
476 [&]( const DELAY_PROFILE_TRACK_PROPAGATION_ENTRY& aLayerEntry, const wxString& aProfileName,
477 const NETCLASS* aNetclass )
478 {
479 if( aLayerEntry.GetWidth() <= 0 || aLayerEntry.GetDiffPairGap() <= 0 )
480 return;
481
482 std::shared_ptr<DRC_RULE> tuningRule = std::make_shared<DRC_RULE>();
483 tuningRule->m_Severity = bds.m_DRCSeverities[DRCE_TUNING_PROFILE_IMPLICIT_RULES];
484 tuningRule->m_Name = wxString::Format( _( "tuning profile '%s'" ), aProfileName );
485 tuningRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::TUNING_PROFILE );
486
487 expr = wxString::Format( wxT( "A.hasExactNetclass('%s') && A.Layer == '%s' && A.inDiffPair('*')" ),
488 aNetclass->GetName(),
489 LSET::Name( aLayerEntry.GetSignalLayer() ) );
490 tuningRule->m_Condition = new DRC_RULE_CONDITION( expr );
491
493 constraint.Value().SetMin( std::max( bds.m_TrackMinWidth, aLayerEntry.GetWidth() ) );
494 constraint.Value().SetOpt( aLayerEntry.GetWidth() );
495 constraint.Value().SetMax( aLayerEntry.GetWidth() );
496 tuningRule->AddConstraint( constraint );
497
498 addRule( tuningRule );
499
500 std::shared_ptr<DRC_RULE> tuningRule2 = std::make_shared<DRC_RULE>();
501 tuningRule2->m_Severity = bds.m_DRCSeverities[DRCE_TUNING_PROFILE_IMPLICIT_RULES];
502 tuningRule2->m_Name = wxString::Format( _( "tuning profile '%s'" ), aProfileName );
503 tuningRule2->SetImplicitSource( DRC_IMPLICIT_SOURCE::TUNING_PROFILE );
504
505 expr2 = wxString::Format( wxT( "A.hasExactNetclass('%s') && A.Layer == '%s' && A.inDiffPair('*')" ),
506 aNetclass->GetName(),
507 LSET::Name( aLayerEntry.GetSignalLayer() ) );
508 tuningRule2->m_Condition = new DRC_RULE_CONDITION( expr2 );
509
511 constraint2.Value().SetMin( std::max( bds.m_MinClearance, aLayerEntry.GetDiffPairGap() ) );
512 constraint2.Value().SetOpt( aLayerEntry.GetDiffPairGap() );
513 constraint2.Value().SetMax( aLayerEntry.GetDiffPairGap() );
514 tuningRule2->AddConstraint( constraint2 );
515
516 addRule( tuningRule2 );
517
518 // A narrower diffpair gap overrides the netclass min clearance
519 if( aLayerEntry.GetDiffPairGap() < aNetclass->GetClearance() )
520 {
521 std::shared_ptr<DRC_RULE> diffPairClearanceRule = std::make_shared<DRC_RULE>();
522 diffPairClearanceRule->m_Severity = bds.m_DRCSeverities[DRCE_TUNING_PROFILE_IMPLICIT_RULES];
523 diffPairClearanceRule->m_Name = wxString::Format( _( "tuning profile '%s'" ), aProfileName );
524 diffPairClearanceRule->SetImplicitSource( DRC_IMPLICIT_SOURCE::TUNING_PROFILE );
525
526 expr = wxString::Format( wxT( "A.hasExactNetclass('%s') && A.Layer == '%s' && A.inDiffPair('*')" ),
527 aNetclass->GetName(),
528 LSET::Name( aLayerEntry.GetSignalLayer() ) );
529 diffPairClearanceRule->m_Condition = new DRC_RULE_CONDITION( expr );
530
531 DRC_CONSTRAINT min_clearanceConstraint( CLEARANCE_CONSTRAINT );
532 min_clearanceConstraint.Value().SetMin( aLayerEntry.GetDiffPairGap() );
533 diffPairClearanceRule->AddConstraint( min_clearanceConstraint );
534
535 addRule( diffPairClearanceRule );
536 }
537 };
538
539 if( PROJECT* project = m_board->GetProject() )
540 {
541 std::shared_ptr<TUNING_PROFILES> tuningParams = project->GetProjectFile().TuningProfileParameters();
542
543 auto addNetclassTuningProfileRules =
544 [&tuningParams, &addTuningSingleRule, &addTuningDifferentialRules]( NETCLASS* aNetclass )
545 {
546 if( aNetclass->HasTuningProfile() )
547 {
548 const wxString delayProfileName = aNetclass->GetTuningProfile();
549 const TUNING_PROFILE& profile = tuningParams->GetTuningProfile( delayProfileName );
550
552 {
553 if( entry.GetWidth() <= 0 )
554 continue;
555
557 addTuningSingleRule( entry, delayProfileName, aNetclass->GetName() );
558 else
559 addTuningDifferentialRules( entry, delayProfileName, aNetclass );
560 }
561 }
562 };
563
564 addNetclassTuningProfileRules( bds.m_NetSettings->GetDefaultNetclass().get() );
565
566 for( const auto& [netclassName, netclass] : bds.m_NetSettings->GetNetclasses() )
567 addNetclassTuningProfileRules( netclass.get() );
568
569 for( const auto& [netclassName, netclass] : bds.m_NetSettings->GetCompositeNetclasses() )
570 addNetclassTuningProfileRules( netclass.get() );
571 }
572
573 // 5) keepout area rules
574 auto addKeepoutZoneRule =
575 [&]( ZONE* zone, FOOTPRINT* parentFP )
576 {
577 const wxString& name = zone->GetZoneName();
578
579 if( name.IsEmpty() )
580 {
581 if( parentFP )
582 {
583 rule = createImplicitRule(
584 wxString::Format( _( "keepout area of %s" ), DescribeRef( parentFP->GetReference() ) ),
586 }
587 else
588 {
589 rule = createImplicitRule( _( "keepout area" ), DRC_IMPLICIT_SOURCE::KEEPOUT );
590 }
591
592 }
593 else
594 {
595 if( parentFP )
596 {
597 rule = createImplicitRule( wxString::Format( _( "keepout area '%s' of %s" ), name,
598 DescribeRef( parentFP->GetReference() ) ),
600 }
601 else
602 {
603 rule = createImplicitRule( wxString::Format( _( "keepout area '%s'" ), name ),
605 }
606 }
607
608 rule->m_ImplicitItemId = zone->m_Uuid;
609
610 rule->m_Condition = new DRC_RULE_CONDITION( wxString::Format( wxT( "A.intersectsArea('%s')" ),
611 zone->m_Uuid.AsString() ) );
612
613 rule->m_LayerCondition = zone->GetLayerSet();
614
615 int disallowFlags = 0;
616
617 if( zone->GetDoNotAllowTracks() )
618 disallowFlags |= DRC_DISALLOW_TRACKS;
619
620 if( zone->GetDoNotAllowVias() )
621 disallowFlags |= DRC_DISALLOW_VIAS;
622
623 if( zone->GetDoNotAllowPads() )
624 disallowFlags |= DRC_DISALLOW_PADS;
625
626 if( zone->GetDoNotAllowZoneFills() )
627 disallowFlags |= DRC_DISALLOW_ZONES;
628
629 if( zone->GetDoNotAllowFootprints() )
630 disallowFlags |= DRC_DISALLOW_FOOTPRINTS;
631
632 DRC_CONSTRAINT disallowConstraint( DISALLOW_CONSTRAINT );
633 disallowConstraint.m_DisallowFlags = disallowFlags;
634 rule->AddConstraint( disallowConstraint );
635 };
636
637 for( ZONE* zone : m_board->Zones() )
638 {
639 if( isKeepoutZone( zone, true ) )
640 addKeepoutZoneRule( zone, nullptr );
641 }
642
643 for( FOOTPRINT* footprint : m_board->Footprints() )
644 {
645 for( ZONE* zone : footprint->Zones() )
646 {
647 if( isKeepoutZone( zone, true ) )
648 addKeepoutZoneRule( zone, footprint );
649 }
650 }
651}
652
653
654void DRC_ENGINE::loadRules( const wxFileName& aPath )
655{
656 if( m_board && aPath.FileExists() )
657 {
658 std::vector<std::shared_ptr<DRC_RULE>> rules;
659
660 if( FILE* fp = wxFopen( aPath.GetFullPath(), wxT( "rt" ) ) )
661 {
662 FILE_LINE_READER lineReader( fp, aPath.GetFullPath() ); // Will close rules file
663 wxString rulesText;
664
665 std::function<bool( wxString* )> resolver =
666 [&]( wxString* token ) -> bool
667 {
668 return m_board->ResolveTextVar( token, 0 );
669 };
670
671 while( char* line = lineReader.ReadLine() )
672 {
673 wxString str( line );
674 str = m_board->ConvertCrossReferencesToKIIDs( str );
675 str = ExpandTextVars( str, &resolver );
676
677 rulesText << str << '\n';
678 }
679
680 DRC_RULES_PARSER parser( rulesText, aPath.GetFullPath() );
681 parser.Parse( rules, m_logReporter );
682 }
683
684 // Copy the rules into the member variable afterwards so that if Parse() throws then
685 // the possibly malformed rules won't contaminate the current ruleset.
686
687 for( std::shared_ptr<DRC_RULE>& rule : rules )
688 m_rules.push_back( rule );
689 }
690}
691
692
694{
695 if( m_logReporter )
696 m_logReporter->Report( wxT( "Compiling Rules" ) );
697
698 REPORTER error_semaphore;
699
700 for( std::shared_ptr<DRC_RULE>& rule : m_rules )
701 {
702 DRC_RULE_CONDITION* condition = nullptr;
703
704 if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() )
705 {
706 condition = rule->m_Condition;
707 condition->Compile( &error_semaphore );
708 }
709
710 if( error_semaphore.HasMessageOfSeverity( RPT_SEVERITY_ERROR ) )
711 THROW_PARSE_ERROR( wxT( "Parse error" ), rule->m_Name,
712 TO_UTF8( rule->m_Condition->GetExpression() ), 0, 0 );
713
714 for( const DRC_CONSTRAINT& constraint : rule->m_Constraints )
715 {
716 if( !m_constraintMap.count( constraint.m_Type ) )
717 m_constraintMap[ constraint.m_Type ] = new std::vector<DRC_ENGINE_CONSTRAINT*>();
718
719 DRC_ENGINE_CONSTRAINT* engineConstraint = new DRC_ENGINE_CONSTRAINT;
720
721 engineConstraint->layerTest = rule->m_LayerCondition;
722 engineConstraint->condition = condition;
723 engineConstraint->constraint = constraint;
724 engineConstraint->parentRule = rule;
725 m_constraintMap[ constraint.m_Type ]->push_back( engineConstraint );
726 }
727 }
728}
729
730
731void DRC_ENGINE::InitEngine( const wxFileName& aRulePath )
732{
734
735 for( DRC_TEST_PROVIDER* provider : m_testProviders )
736 {
737 if( m_logReporter )
738 m_logReporter->Report( wxString::Format( wxT( "Create DRC provider: '%s'" ), provider->GetName() ) );
739
740 provider->SetDRCEngine( this );
741 }
742
743 m_rules.clear();
744 m_rulesValid = false;
745
746 for( std::pair<DRC_CONSTRAINT_T, std::vector<DRC_ENGINE_CONSTRAINT*>*> pair : m_constraintMap )
747 {
748 for( DRC_ENGINE_CONSTRAINT* constraint : *pair.second )
749 delete constraint;
750
751 delete pair.second;
752 }
753
754 m_constraintMap.clear();
755
756 m_board->IncrementTimeStamp(); // Clear board-level caches
757
758 try // attempt to load full set of rules (implicit + user rules)
759 {
761 loadRules( aRulePath );
762 compileRules();
763 }
764 catch( PARSE_ERROR& original_parse_error )
765 {
766 m_rules.clear();
767
768 try // try again with just our implicit rules
769 {
771 compileRules();
772 }
773 catch( PARSE_ERROR& )
774 {
775 wxFAIL_MSG( wxT( "Compiling implicit rules failed." ) );
776 }
777
778 throw original_parse_error;
779 }
780
781 for( int ii = DRCE_FIRST; ii <= DRCE_LAST; ++ii )
783
784 m_rulesValid = true;
785}
786
787
788void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints,
789 BOARD_COMMIT* aCommit )
790{
791 PROF_TIMER timer;
792
793 SetUserUnits( aUnits );
794
795 m_reportAllTrackErrors = aReportAllTrackErrors;
796 m_testFootprints = aTestFootprints;
797
798 for( int ii = DRCE_FIRST; ii <= DRCE_LAST; ++ii )
799 {
800 if( m_designSettings->Ignore( ii ) )
801 m_errorLimits[ ii ] = 0;
802 else if( ii == DRCE_CLEARANCE || ii == DRCE_UNCONNECTED_ITEMS )
804 else
806 }
807
809
810 m_board->IncrementTimeStamp(); // Invalidate all caches...
811
812 DRC_CACHE_GENERATOR cacheGenerator;
813 cacheGenerator.SetDRCEngine( this );
814
815 if( !cacheGenerator.Run() ) // ... and regenerate them.
816 return;
817
818 // Recompute component classes
819 m_board->GetComponentClassManager().ForceComponentClassRecalculation();
820
821 int timestamp = m_board->GetTimeStamp();
822
823 for( DRC_TEST_PROVIDER* provider : m_testProviders )
824 {
825 if( m_logReporter )
826 m_logReporter->Report( wxString::Format( wxT( "Run DRC provider: '%s'" ), provider->GetName() ) );
827
828 if( !provider->RunTests( aUnits ) )
829 break;
830 }
831
832 timer.Stop();
833 wxLogTrace( traceDrcProfile, "DRC took %0.3f ms", timer.msecs() );
834
835 // DRC tests are multi-threaded; anything that causes us to attempt to re-generate the
836 // caches while DRC is running is problematic.
837 wxASSERT( timestamp == m_board->GetTimeStamp() );
838}
839
840
841#define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } }
842
844 PCB_LAYER_ID aLayer, REPORTER* aReporter )
845{
846 DRC_CONSTRAINT constraint = EvalRules( ZONE_CONNECTION_CONSTRAINT, a, b, aLayer, aReporter );
847
848 REPORT( "" )
849 REPORT( wxString::Format( _( "Resolved zone connection type: %s." ),
850 PrintZoneConnection( constraint.m_ZoneConnection ) ) )
851
853 {
854 const PAD* pad = nullptr;
855
856 if( a->Type() == PCB_PAD_T )
857 pad = static_cast<const PAD*>( a );
858 else if( b->Type() == PCB_PAD_T )
859 pad = static_cast<const PAD*>( b );
860
861 if( pad && pad->GetAttribute() == PAD_ATTRIB::PTH )
862 {
864 }
865 else
866 {
867 REPORT( wxString::Format( _( "Pad is not a through hole pad; connection will be: %s." ),
870 }
871 }
872
873 return constraint;
874}
875
876
878 const BOARD_ITEM* b, PCB_LAYER_ID aLayer,
879 REPORTER* aReporter )
880{
881 /*
882 * NOTE: all string manipulation MUST BE KEPT INSIDE the REPORT macro. It absolutely
883 * kills performance when running bulk DRC tests (where aReporter is nullptr).
884 */
885
886 const BOARD_CONNECTED_ITEM* ac = a && a->IsConnected() ? static_cast<const BOARD_CONNECTED_ITEM*>( a ) : nullptr;
887 const BOARD_CONNECTED_ITEM* bc = b && b->IsConnected() ? static_cast<const BOARD_CONNECTED_ITEM*>( b ) : nullptr;
888
889 bool a_is_non_copper = a && ( !a->IsOnCopperLayer() || isKeepoutZone( a, false ) );
890 bool b_is_non_copper = b && ( !b->IsOnCopperLayer() || isKeepoutZone( b, false ) );
891
892 const PAD* pad = nullptr;
893 const ZONE* zone = nullptr;
894 const FOOTPRINT* parentFootprint = nullptr;
895
896 if( aConstraintType == ZONE_CONNECTION_CONSTRAINT
897 || aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT
898 || aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT
899 || aConstraintType == SOLDER_MASK_EXPANSION_CONSTRAINT
900 || aConstraintType == SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
901 || aConstraintType == SOLDER_PASTE_REL_MARGIN_CONSTRAINT )
902 {
903 if( a && a->Type() == PCB_PAD_T )
904 pad = static_cast<const PAD*>( a );
905 else if( a && a->Type() == PCB_ZONE_T )
906 zone = static_cast<const ZONE*>( a );
907
908 if( b && b->Type() == PCB_PAD_T )
909 pad = static_cast<const PAD*>( b );
910 else if( b && b->Type() == PCB_ZONE_T )
911 zone = static_cast<const ZONE*>( b );
912
913 if( pad )
914 parentFootprint = pad->GetParentFootprint();
915 }
916
917 DRC_CONSTRAINT constraint;
918 constraint.m_Type = aConstraintType;
919
920 auto applyConstraint =
921 [&]( const DRC_ENGINE_CONSTRAINT* c )
922 {
923 if( c->constraint.m_Value.HasMin() )
924 {
925 if( c->parentRule && c->parentRule->IsImplicit() )
926 constraint.m_ImplicitMin = true;
927
928 constraint.m_Value.SetMin( c->constraint.m_Value.Min() );
929 }
930
931 if( c->constraint.m_Value.HasOpt() )
932 constraint.m_Value.SetOpt( c->constraint.m_Value.Opt() );
933
934 if( c->constraint.m_Value.HasMax() )
935 constraint .m_Value.SetMax( c->constraint.m_Value.Max() );
936
937 switch( c->constraint.m_Type )
938 {
946 if( constraint.m_Value.Min() > MAXIMUM_CLEARANCE )
947 constraint.m_Value.SetMin( MAXIMUM_CLEARANCE );
948
949 break;
950
951 default:
952 break;
953 }
954
955 // While the expectation would be to OR the disallow flags, we've already
956 // masked them down to aItem's type -- so we're really only looking for a
957 // boolean here.
958 constraint.m_DisallowFlags = c->constraint.m_DisallowFlags;
959
960 constraint.m_ZoneConnection = c->constraint.m_ZoneConnection;
961
962 constraint.SetParentRule( c->constraint.GetParentRule() );
963
964 constraint.SetOptionsFromOther( c->constraint );
965 };
966
967 const FOOTPRINT* footprints[2] = { a ? a->GetParentFootprint() : nullptr,
968 b ? b->GetParentFootprint() : nullptr };
969
970 // Handle Footprint net ties, which will zero out the clearance for footprint objects
971 if( aConstraintType == CLEARANCE_CONSTRAINT // Only zero clearance, other constraints still apply
972 && ( ( ( !ac ) ^ ( !bc ) )// Only apply to cases where we are comparing a connected item to a non-connected item
973 // and not both connected. Connected items of different nets still need to be checked
974 // for their standard clearance value
975 || ( ( footprints[0] == footprints[1] ) // Unless both items are in the same footprint
976 && footprints[0] ) ) // And that footprint exists
977 && !a_is_non_copper // Also, both elements need to be on copper layers
978 && !b_is_non_copper )
979 {
980 const BOARD_ITEM* child_items[2] = {a, b};
981
982 // These are the items being compared against, so the order is reversed
983 const BOARD_CONNECTED_ITEM* alt_items[2] = {bc, ac};
984
985 for( int ii = 0; ii < 2; ++ii )
986 {
987 // We need both a footprint item and a connected item to check for a net tie
988 if( !footprints[ii] || !alt_items[ii] )
989 continue;
990
991 const std::set<int>& netcodes = footprints[ii]->GetNetTieCache( child_items[ii] );
992
993 auto it = netcodes.find( alt_items[ii]->GetNetCode() );
994
995 if( it != netcodes.end() )
996 {
997 REPORT( "" )
998 REPORT( wxString::Format( _( "Net tie on %s; clearance: 0." ),
999 EscapeHTML( footprints[ii]->GetItemDescription( this, true ) ) ) )
1000
1001 constraint.SetName( _( "net tie" ) );
1002 constraint.m_Value.SetMin( 0 );
1003 return constraint;
1004 }
1005 }
1006 }
1007
1008 // Local overrides take precedence over everything *except* board min clearance
1009 if( aConstraintType == CLEARANCE_CONSTRAINT || aConstraintType == HOLE_CLEARANCE_CONSTRAINT )
1010 {
1011 int override_val = 0;
1012 std::optional<int> overrideA;
1013 std::optional<int> overrideB;
1014
1015 if( ac && !b_is_non_copper )
1016 overrideA = ac->GetClearanceOverrides( nullptr );
1017
1018 if( bc && !a_is_non_copper )
1019 overrideB = bc->GetClearanceOverrides( nullptr );
1020
1021 if( overrideA.has_value() || overrideB.has_value() )
1022 {
1023 wxString msg;
1024
1025 if( overrideA.has_value() )
1026 {
1027 REPORT( "" )
1028 REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
1029 EscapeHTML( a->GetItemDescription( this, true ) ),
1030 MessageTextFromValue( overrideA.value() ) ) )
1031
1032 override_val = ac->GetClearanceOverrides( &msg ).value();
1033 }
1034
1035 if( overrideB.has_value() )
1036 {
1037 REPORT( "" )
1038 REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
1039 EscapeHTML( b->GetItemDescription( this, true ) ),
1040 MessageTextFromValue( overrideB.value() ) ) )
1041
1042 if( overrideB > override_val )
1043 override_val = bc->GetClearanceOverrides( &msg ).value();
1044 }
1045
1046 if( override_val )
1047 {
1048 if( aConstraintType == CLEARANCE_CONSTRAINT )
1049 {
1050 if( override_val < m_designSettings->m_MinClearance )
1051 {
1052 override_val = m_designSettings->m_MinClearance;
1053 msg = _( "board minimum" );
1054
1055 REPORT( "" )
1056 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
1057 MessageTextFromValue( override_val ) ) )
1058 }
1059 }
1060 else
1061 {
1062 if( override_val < m_designSettings->m_HoleClearance )
1063 {
1064 override_val = m_designSettings->m_HoleClearance;
1065 msg = _( "board minimum hole" );
1066
1067 REPORT( "" )
1068 REPORT( wxString::Format( _( "Board minimum hole clearance: %s." ),
1069 MessageTextFromValue( override_val ) ) )
1070 }
1071 }
1072
1073 constraint.SetName( msg );
1074 constraint.m_Value.SetMin( override_val );
1075 return constraint;
1076 }
1077 }
1078 }
1079 else if( aConstraintType == ZONE_CONNECTION_CONSTRAINT )
1080 {
1081 if( pad && pad->GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED )
1082 {
1083 wxString msg;
1084 ZONE_CONNECTION override = pad->GetZoneConnectionOverrides( &msg );
1085
1086 REPORT( "" )
1087 REPORT( wxString::Format( _( "Local override on %s; zone connection: %s." ),
1088 EscapeHTML( pad->GetItemDescription( this, true ) ),
1089 PrintZoneConnection( override ) ) )
1090
1091 constraint.SetName( msg );
1092 constraint.m_ZoneConnection = override;
1093 return constraint;
1094 }
1095 }
1096 else if( aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT )
1097 {
1098 if( pad && pad->GetLocalThermalGapOverride( nullptr ) > 0 )
1099 {
1100 wxString msg;
1101 int gap_override = pad->GetLocalThermalGapOverride( &msg );
1102
1103 REPORT( "" )
1104 REPORT( wxString::Format( _( "Local override on %s; thermal relief gap: %s." ),
1105 EscapeHTML( pad->GetItemDescription( this, true ) ),
1106 MessageTextFromValue( gap_override ) ) )
1107
1108 constraint.SetName( msg );
1109 constraint.m_Value.SetMin( gap_override );
1110 return constraint;
1111 }
1112 }
1113 else if( aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT )
1114 {
1115 if( pad && pad->GetLocalSpokeWidthOverride( nullptr ) > 0 )
1116 {
1117 wxString msg;
1118 int spoke_override = pad->GetLocalSpokeWidthOverride( &msg );
1119
1120 REPORT( "" )
1121 REPORT( wxString::Format( _( "Local override on %s; thermal spoke width: %s." ),
1122 EscapeHTML( pad->GetItemDescription( this, true ) ),
1123 MessageTextFromValue( spoke_override ) ) )
1124
1125 if( zone && zone->GetMinThickness() > spoke_override )
1126 {
1127 spoke_override = zone->GetMinThickness();
1128
1129 REPORT( "" )
1130 REPORT( wxString::Format( _( "%s min thickness: %s." ),
1131 EscapeHTML( zone->GetItemDescription( this, true ) ),
1132 MessageTextFromValue( spoke_override ) ) )
1133 }
1134
1135 constraint.SetName( msg );
1136 constraint.m_Value.SetMin( spoke_override );
1137 return constraint;
1138 }
1139 }
1140 else if( aConstraintType == SOLDER_MASK_EXPANSION_CONSTRAINT )
1141 {
1142 std::optional<int> override;
1143
1144 if( pad )
1145 override = pad->GetLocalSolderMaskMargin();
1146 else if( a->Type() == PCB_SHAPE_T )
1147 override = static_cast<const PCB_SHAPE*>( a )->GetLocalSolderMaskMargin();
1148 else if( const PCB_TRACK* track = dynamic_cast<const PCB_TRACK*>( a ) )
1149 override = track->GetLocalSolderMaskMargin();
1150
1151 if( override )
1152 {
1153 REPORT( "" )
1154 REPORT( wxString::Format( _( "Local override on %s; solder mask expansion: %s." ),
1155 EscapeHTML( pad->GetItemDescription( this, true ) ),
1156 MessageTextFromValue( override.value() ) ) )
1157
1158 constraint.m_Value.SetOpt( override.value() );
1159 return constraint;
1160 }
1161 }
1162 else if( aConstraintType == SOLDER_PASTE_ABS_MARGIN_CONSTRAINT )
1163 {
1164 std::optional<int> override;
1165
1166 if( pad )
1167 override = pad->GetLocalSolderPasteMargin();
1168
1169 if( override )
1170 {
1171 REPORT( "" )
1172 REPORT( wxString::Format( _( "Local override on %s; solder paste absolute clearance: %s." ),
1173 EscapeHTML( pad->GetItemDescription( this, true ) ),
1174 MessageTextFromValue( override.value() ) ) )
1175
1176 constraint.m_Value.SetOpt( override.value_or( 0 ) );
1177 return constraint;
1178 }
1179 }
1180 else if( aConstraintType == SOLDER_PASTE_REL_MARGIN_CONSTRAINT )
1181 {
1182 std::optional<double> overrideRatio;
1183
1184 if( pad )
1185 overrideRatio = pad->GetLocalSolderPasteMarginRatio();
1186
1187 if( overrideRatio )
1188 {
1189 REPORT( "" )
1190 REPORT( wxString::Format( _( "Local override on %s; solder paste relative clearance: %s." ),
1191 EscapeHTML( pad->GetItemDescription( this, true ) ),
1192 MessageTextFromValue( overrideRatio.value() * 100.0 ) ) )
1193
1194 constraint.m_Value.SetOpt( KiROUND( overrideRatio.value_or( 0 ) * 1000 ) );
1195 return constraint;
1196 }
1197 }
1198
1199 auto testAssertion =
1200 [&]( const DRC_ENGINE_CONSTRAINT* c )
1201 {
1202 REPORT( wxString::Format( _( "Checking assertion '%s'." ),
1203 EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
1204
1205 if( c->constraint.m_Test->EvaluateFor( a, b, c->constraint.m_Type, aLayer, aReporter ) )
1206 REPORT( _( "Assertion passed." ) )
1207 else
1208 REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
1209 };
1210
1211 auto processConstraint =
1212 [&]( const DRC_ENGINE_CONSTRAINT* c )
1213 {
1214 bool implicit = c->parentRule && c->parentRule->IsImplicit();
1215
1216 REPORT( "" )
1217
1218 switch( c->constraint.m_Type )
1219 {
1227 REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
1228 EscapeHTML( c->constraint.GetName() ),
1229 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
1230 break;
1232 REPORT( wxString::Format( _( "Checking %s creepage: %s." ),
1233 EscapeHTML( c->constraint.GetName() ),
1234 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
1235 break;
1237 REPORT( wxString::Format( _( "Checking %s max uncoupled length: %s." ),
1238 EscapeHTML( c->constraint.GetName() ),
1239 MessageTextFromValue( c->constraint.m_Value.Max() ) ) )
1240 break;
1241
1242 case SKEW_CONSTRAINT:
1243 REPORT( wxString::Format( _( "Checking %s max skew: %s." ),
1244 EscapeHTML( c->constraint.GetName() ),
1245 MessageTextFromValue( c->constraint.m_Value.Max() ) ) )
1246 break;
1247
1249 REPORT( wxString::Format( _( "Checking %s gap: %s." ),
1250 EscapeHTML( c->constraint.GetName() ),
1251 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
1252 break;
1253
1255 REPORT( wxString::Format( _( "Checking %s thermal spoke width: %s." ),
1256 EscapeHTML( c->constraint.GetName() ),
1257 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
1258 break;
1259
1261 REPORT( wxString::Format( _( "Checking %s solder mask expansion: %s." ),
1262 EscapeHTML( c->constraint.GetName() ),
1263 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
1264 break;
1265
1267 REPORT( wxString::Format( _( "Checking %s solder paste absolute clearance: %s." ),
1268 EscapeHTML( c->constraint.GetName() ),
1269 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
1270 break;
1271
1273 REPORT( wxString::Format( _( "Checking %s solder paste relative clearance: %s." ),
1274 EscapeHTML( c->constraint.GetName() ),
1275 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
1276 break;
1277
1279 REPORT( wxString::Format( _( "Checking %s min spoke count: %s." ),
1280 EscapeHTML( c->constraint.GetName() ),
1281 MessageTextFromUnscaledValue( c->constraint.m_Value.Min() ) ) )
1282 break;
1283
1285 REPORT( wxString::Format( _( "Checking %s zone connection: %s." ),
1286 EscapeHTML( c->constraint.GetName() ),
1287 PrintZoneConnection( c->constraint.m_ZoneConnection ) ) )
1288 break;
1289
1297 case LENGTH_CONSTRAINT:
1300 {
1301 if( implicit )
1302 {
1303 switch( c->constraint.m_Type )
1304 {
1306 if( c->constraint.m_Value.HasOpt() )
1307 {
1308 REPORT( wxString::Format( _( "Checking %s track width: opt %s." ),
1309 EscapeHTML( c->constraint.GetName() ),
1310 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
1311 }
1312 else if( c->constraint.m_Value.HasMin() )
1313 {
1314 REPORT( wxString::Format( _( "Checking %s track width: min %s." ),
1315 EscapeHTML( c->constraint.GetName() ),
1316 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
1317 }
1318
1319 break;
1320
1322 REPORT( wxString::Format( _( "Checking %s annular width: min %s." ),
1323 EscapeHTML( c->constraint.GetName() ),
1324 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
1325 break;
1326
1328 if( c->constraint.m_Value.HasOpt() )
1329 {
1330 REPORT( wxString::Format( _( "Checking %s via diameter: opt %s." ),
1331 EscapeHTML( c->constraint.GetName() ),
1332 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
1333 }
1334 else if( c->constraint.m_Value.HasMin() )
1335 {
1336 REPORT( wxString::Format( _( "Checking %s via diameter: min %s." ),
1337 EscapeHTML( c->constraint.GetName() ),
1338 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
1339 }
1340 break;
1341
1343 if( c->constraint.m_Value.HasOpt() )
1344 {
1345 REPORT( wxString::Format( _( "Checking %s hole size: opt %s." ),
1346 EscapeHTML( c->constraint.GetName() ),
1347 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
1348 }
1349 else if( c->constraint.m_Value.HasMin() )
1350 {
1351 REPORT( wxString::Format( _( "Checking %s hole size: min %s." ),
1352 EscapeHTML( c->constraint.GetName() ),
1353 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
1354 }
1355
1356 break;
1357
1361 REPORT( wxString::Format( _( "Checking %s: min %s." ),
1362 EscapeHTML( c->constraint.GetName() ),
1363 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
1364 break;
1365
1367 if( c->constraint.m_Value.HasOpt() )
1368 {
1369 REPORT( wxString::Format( _( "Checking %s diff pair gap: opt %s." ),
1370 EscapeHTML( c->constraint.GetName() ),
1371 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
1372 }
1373 else if( c->constraint.m_Value.HasMin() )
1374 {
1375 REPORT( wxString::Format( _( "Checking %s clearance: min %s." ),
1376 EscapeHTML( c->constraint.GetName() ),
1377 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
1378 }
1379
1380 break;
1381
1383 REPORT( wxString::Format( _( "Checking %s hole to hole: min %s." ),
1384 EscapeHTML( c->constraint.GetName() ),
1385 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
1386 break;
1387
1388 default:
1389 REPORT( wxString::Format( _( "Checking %s." ),
1390 EscapeHTML( c->constraint.GetName() ) ) )
1391 }
1392 }
1393 else
1394 {
1395 REPORT( wxString::Format( _( "Checking %s: min %s; opt %s; max %s." ),
1396 EscapeHTML( c->constraint.GetName() ),
1397 c->constraint.m_Value.HasMin()
1398 ? MessageTextFromValue( c->constraint.m_Value.Min() )
1399 : wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" ),
1400 c->constraint.m_Value.HasOpt()
1401 ? MessageTextFromValue( c->constraint.m_Value.Opt() )
1402 : wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" ),
1403 c->constraint.m_Value.HasMax()
1404 ? MessageTextFromValue( c->constraint.m_Value.Max() )
1405 : wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" ) ) )
1406 }
1407 break;
1408 }
1409
1410 default:
1411 REPORT( wxString::Format( _( "Checking %s." ),
1412 EscapeHTML( c->constraint.GetName() ) ) )
1413 }
1414
1415 if( c->constraint.m_Type == CLEARANCE_CONSTRAINT )
1416 {
1417 if( a_is_non_copper || b_is_non_copper )
1418 {
1419 if( implicit )
1420 {
1421 REPORT( _( "Netclass clearances apply only between copper items." ) )
1422 }
1423 else if( a_is_non_copper )
1424 {
1425 REPORT( wxString::Format( _( "%s contains no copper. Rule ignored." ),
1426 EscapeHTML( a->GetItemDescription( this, true ) ) ) )
1427 }
1428 else if( b_is_non_copper )
1429 {
1430 REPORT( wxString::Format( _( "%s contains no copper. Rule ignored." ),
1431 EscapeHTML( b->GetItemDescription( this, true ) ) ) )
1432 }
1433
1434 return;
1435 }
1436 }
1437 else if( c->constraint.m_Type == DISALLOW_CONSTRAINT )
1438 {
1439 int mask;
1440
1441 if( a->GetFlags() & HOLE_PROXY )
1442 {
1443 mask = DRC_DISALLOW_HOLES;
1444 }
1445 else if( a->Type() == PCB_VIA_T )
1446 {
1447 const PCB_VIA* via = static_cast<const PCB_VIA*>( a );
1448
1449 if( via->IsMicroVia() )
1451 else if( via->IsBlindVia() )
1453 else if( via->IsBuriedVia() )
1455 else
1457 }
1458 else
1459 {
1460 switch( a->Type() )
1461 {
1462 case PCB_TRACE_T: mask = DRC_DISALLOW_TRACKS; break;
1463 case PCB_ARC_T: mask = DRC_DISALLOW_TRACKS; break;
1464 case PCB_PAD_T: mask = DRC_DISALLOW_PADS; break;
1465 case PCB_FOOTPRINT_T: mask = DRC_DISALLOW_FOOTPRINTS; break;
1466 case PCB_SHAPE_T: mask = DRC_DISALLOW_GRAPHICS; break;
1467 case PCB_BARCODE_T: mask = DRC_DISALLOW_GRAPHICS; break;
1468 case PCB_FIELD_T: mask = DRC_DISALLOW_TEXTS; break;
1469 case PCB_TEXT_T: mask = DRC_DISALLOW_TEXTS; break;
1470 case PCB_TEXTBOX_T: mask = DRC_DISALLOW_TEXTS; break;
1471 case PCB_TABLE_T: mask = DRC_DISALLOW_TEXTS; break;
1472
1473 case PCB_ZONE_T:
1474 // Treat teardrop areas as tracks for DRC purposes
1475 if( static_cast<const ZONE*>( a )->IsTeardropArea() )
1476 mask = DRC_DISALLOW_TRACKS;
1477 else
1478 mask = DRC_DISALLOW_ZONES;
1479
1480 break;
1481
1482 case PCB_LOCATE_HOLE_T: mask = DRC_DISALLOW_HOLES; break;
1483 default: mask = 0; break;
1484 }
1485 }
1486
1487 if( ( c->constraint.m_DisallowFlags & mask ) == 0 )
1488 {
1489 if( implicit )
1490 REPORT( _( "Keepout constraint not met." ) )
1491 else
1492 REPORT( _( "Disallow constraint not met." ) )
1493
1494 return;
1495 }
1496
1497 LSET itemLayers = a->GetLayerSet();
1498
1499 if( a->Type() == PCB_FOOTPRINT_T )
1500 {
1501 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( a );
1502
1503 if( !footprint->GetCourtyard( F_CrtYd ).IsEmpty() )
1504 itemLayers |= LSET::FrontMask();
1505
1506 if( !footprint->GetCourtyard( B_CrtYd ).IsEmpty() )
1507 itemLayers |= LSET::BackMask();
1508 }
1509
1510 if( !( c->layerTest & itemLayers ).any() )
1511 {
1512 if( implicit )
1513 {
1514 REPORT( _( "Keepout layer(s) not matched." ) )
1515 }
1516 else if( c->parentRule )
1517 {
1518 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1519 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1520 }
1521 else
1522 {
1523 REPORT( _( "Rule layer not matched; rule ignored." ) )
1524 }
1525
1526 return;
1527 }
1528 }
1529
1530 if( ( aLayer != UNDEFINED_LAYER && !c->layerTest.test( aLayer ) )
1531 || ( m_board->GetEnabledLayers() & c->layerTest ).count() == 0 )
1532 {
1533 if( implicit )
1534 {
1535 REPORT( _( "Constraint layer not matched." ) )
1536 }
1537 else if( c->parentRule )
1538 {
1539 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1540 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1541 }
1542 else
1543 {
1544 REPORT( _( "Rule layer not matched; rule ignored." ) )
1545 }
1546 }
1547 else if( c->constraint.m_Type == HOLE_TO_HOLE_CONSTRAINT
1548 && ( !a->HasDrilledHole() && !b->HasDrilledHole() ) )
1549 {
1550 // Report non-drilled-holes as an implicit condition
1551 REPORT( wxString::Format( _( "%s is not a drilled hole; rule ignored." ),
1552 a->GetItemDescription( this, true ) ) )
1553 }
1554 else if( !c->condition || c->condition->GetExpression().IsEmpty() )
1555 {
1556 if( aReporter )
1557 {
1558 if( implicit )
1559 {
1560 REPORT( _( "Unconditional constraint applied." ) )
1561 }
1562 else if( constraint.m_Type == ASSERTION_CONSTRAINT )
1563 {
1564 REPORT( _( "Unconditional rule applied." ) )
1565 testAssertion( c );
1566 }
1567 else
1568 {
1569 REPORT( _( "Unconditional rule applied; overrides previous constraints." ) )
1570 }
1571 }
1572
1573 applyConstraint( c );
1574 }
1575 else
1576 {
1577 if( implicit )
1578 {
1579 // Don't report on implicit rule conditions; they're synthetic.
1580 }
1581 else
1582 {
1583 REPORT( wxString::Format( _( "Checking rule condition '%s'." ),
1584 EscapeHTML( c->condition->GetExpression() ) ) )
1585 }
1586
1587 if( c->condition->EvaluateFor( a, b, c->constraint.m_Type, aLayer, aReporter ) )
1588 {
1589 if( aReporter )
1590 {
1591 if( implicit )
1592 {
1593 REPORT( _( "Constraint applied." ) )
1594 }
1595 else if( constraint.m_Type == ASSERTION_CONSTRAINT )
1596 {
1597 REPORT( _( "Rule applied." ) )
1598 testAssertion( c );
1599 }
1600 else
1601 {
1602 REPORT( _( "Rule applied; overrides previous constraints." ) )
1603 }
1604 }
1605
1606 applyConstraint( c );
1607 }
1608 else
1609 {
1610 REPORT( implicit ? _( "Membership not satisfied; constraint ignored." )
1611 : _( "Condition not satisfied; rule ignored." ) )
1612 }
1613 }
1614 };
1615
1616 if( m_constraintMap.count( aConstraintType ) )
1617 {
1618 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
1619
1620 for( DRC_ENGINE_CONSTRAINT* rule : *ruleset )
1621 processConstraint( rule );
1622 }
1623
1624 if( constraint.GetParentRule() && !constraint.GetParentRule()->IsImplicit() )
1625 return constraint;
1626
1627 // Special case for properties which can be inherited from parent footprints. We've already
1628 // checked for local overrides, and there were no rules targetting the item itself, so we know
1629 // we're inheriting and need to see if there are any rules targetting the parent footprint.
1630 if( pad && parentFootprint && ( aConstraintType == ZONE_CONNECTION_CONSTRAINT
1631 || aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT
1632 || aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT
1633 || aConstraintType == SOLDER_MASK_EXPANSION_CONSTRAINT
1634 || aConstraintType == SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
1635 || aConstraintType == SOLDER_PASTE_REL_MARGIN_CONSTRAINT ) )
1636 {
1637 REPORT( "" )
1638 REPORT( wxString::Format( _( "Inheriting from parent: %s." ),
1639 EscapeHTML( parentFootprint->GetItemDescription( this, true ) ) ) )
1640
1641 if( a == pad )
1642 a = parentFootprint;
1643 else
1644 b = parentFootprint;
1645
1646 if( m_constraintMap.count( aConstraintType ) )
1647 {
1648 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
1649
1650 for( DRC_ENGINE_CONSTRAINT* rule : *ruleset )
1651 processConstraint( rule );
1652
1653 if( constraint.GetParentRule() && !constraint.GetParentRule()->IsImplicit() )
1654 return constraint;
1655 }
1656
1657 // Found nothing again? Return the defaults.
1658 if( aConstraintType == SOLDER_MASK_EXPANSION_CONSTRAINT )
1659 {
1660 constraint.SetParentRule( nullptr );
1661 constraint.SetName( _( "board setup" ) );
1662 constraint.m_Value.SetOpt( m_designSettings->m_SolderMaskExpansion );
1663 return constraint;
1664 }
1665 else if( aConstraintType == SOLDER_PASTE_ABS_MARGIN_CONSTRAINT )
1666 {
1667 constraint.SetParentRule( nullptr );
1668 constraint.SetName( _( "board setup" ) );
1669 constraint.m_Value.SetOpt( m_designSettings->m_SolderPasteMargin );
1670 return constraint;
1671 }
1672 else if( aConstraintType == SOLDER_PASTE_REL_MARGIN_CONSTRAINT )
1673 {
1674 constraint.SetParentRule( nullptr );
1675 constraint.SetName( _( "board setup" ) );
1676 constraint.m_Value.SetOpt( KiROUND( m_designSettings->m_SolderPasteMarginRatio * 1000 ) );
1677 return constraint;
1678 }
1679 }
1680
1681 // Unfortunately implicit rules don't work for local clearances (such as zones) because
1682 // they have to be max'ed with netclass values (which are already implicit rules), and our
1683 // rule selection paradigm is "winner takes all".
1684 if( aConstraintType == CLEARANCE_CONSTRAINT )
1685 {
1686 int global = constraint.m_Value.Min();
1687 int clearance = global;
1688 bool needBlankLine = true;
1689
1690 if( ac && ac->GetLocalClearance().has_value() )
1691 {
1692 int localA = ac->GetLocalClearance().value();
1693
1694 if( needBlankLine )
1695 {
1696 REPORT( "" )
1697 needBlankLine = false;
1698 }
1699
1700 REPORT( wxString::Format( _( "Local clearance on %s: %s." ),
1701 EscapeHTML( a->GetItemDescription( this, true ) ),
1702 MessageTextFromValue( localA ) ) )
1703
1704 if( localA > clearance )
1705 {
1706 wxString msg;
1707 clearance = ac->GetLocalClearance( &msg ).value();
1708 constraint.SetParentRule( nullptr );
1709 constraint.SetName( msg );
1710 constraint.m_Value.SetMin( clearance );
1711 }
1712 }
1713
1714 if( bc && bc->GetLocalClearance().has_value() )
1715 {
1716 int localB = bc->GetLocalClearance().value();
1717
1718 if( needBlankLine )
1719 {
1720 REPORT( "" )
1721 needBlankLine = false;
1722 }
1723
1724 REPORT( wxString::Format( _( "Local clearance on %s: %s." ),
1725 EscapeHTML( b->GetItemDescription( this, true ) ),
1726 MessageTextFromValue( localB ) ) )
1727
1728 if( localB > clearance )
1729 {
1730 wxString msg;
1731 clearance = bc->GetLocalClearance( &msg ).value();
1732 constraint.SetParentRule( nullptr );
1733 constraint.SetName( msg );
1734 constraint.m_Value.SetMin( clearance );
1735 }
1736 }
1737
1738 if( !a_is_non_copper && !b_is_non_copper )
1739 {
1740 if( needBlankLine )
1741 {
1742 REPORT( "" )
1743 needBlankLine = false;
1744 }
1745
1746 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
1747 MessageTextFromValue( m_designSettings->m_MinClearance ) ) )
1748
1749 if( clearance < m_designSettings->m_MinClearance )
1750 {
1751 constraint.SetParentRule( nullptr );
1752 constraint.SetName( _( "board minimum" ) );
1753 constraint.m_Value.SetMin( m_designSettings->m_MinClearance );
1754 }
1755 }
1756
1757 return constraint;
1758 }
1759 else if( aConstraintType == DIFF_PAIR_GAP_CONSTRAINT )
1760 {
1761 REPORT( "" )
1762 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
1763 MessageTextFromValue( m_designSettings->m_MinClearance ) ) )
1764
1765 if( constraint.m_Value.Min() < m_designSettings->m_MinClearance )
1766 {
1767 constraint.SetParentRule( nullptr );
1768 constraint.SetName( _( "board minimum" ) );
1769 constraint.m_Value.SetMin( m_designSettings->m_MinClearance );
1770 }
1771
1772 return constraint;
1773 }
1774 else if( aConstraintType == ZONE_CONNECTION_CONSTRAINT )
1775 {
1776 if( pad && parentFootprint )
1777 {
1778 ZONE_CONNECTION local = parentFootprint->GetLocalZoneConnection();
1779
1780 if( local != ZONE_CONNECTION::INHERITED )
1781 {
1782 REPORT( "" )
1783 REPORT( wxString::Format( _( "%s zone connection: %s." ),
1784 EscapeHTML( parentFootprint->GetItemDescription( this, true ) ),
1785 PrintZoneConnection( local ) ) )
1786
1787 constraint.SetParentRule( nullptr );
1788 constraint.SetName( _( "footprint" ) );
1789 constraint.m_ZoneConnection = local;
1790 return constraint;
1791 }
1792 }
1793
1794 if( zone )
1795 {
1796 ZONE_CONNECTION local = zone->GetPadConnection();
1797
1798 REPORT( "" )
1799 REPORT( wxString::Format( _( "%s pad connection: %s." ),
1800 EscapeHTML( zone->GetItemDescription( this, true ) ),
1801 PrintZoneConnection( local ) ) )
1802
1803 constraint.SetParentRule( nullptr );
1804 constraint.SetName( _( "zone" ) );
1805 constraint.m_ZoneConnection = local;
1806 return constraint;
1807 }
1808 }
1809 else if( aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT )
1810 {
1811 if( zone )
1812 {
1813 int local = zone->GetThermalReliefGap();
1814
1815 REPORT( "" )
1816 REPORT( wxString::Format( _( "%s thermal relief gap: %s." ),
1817 EscapeHTML( zone->GetItemDescription( this, true ) ),
1818 MessageTextFromValue( local ) ) )
1819
1820 constraint.SetParentRule( nullptr );
1821 constraint.SetName( _( "zone" ) );
1822 constraint.m_Value.SetMin( local );
1823 return constraint;
1824 }
1825 }
1826 else if( aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT )
1827 {
1828 if( zone )
1829 {
1830 int local = zone->GetThermalReliefSpokeWidth();
1831
1832 REPORT( "" )
1833 REPORT( wxString::Format( _( "%s thermal spoke width: %s." ),
1834 EscapeHTML( zone->GetItemDescription( this, true ) ),
1835 MessageTextFromValue( local ) ) )
1836
1837 constraint.SetParentRule( nullptr );
1838 constraint.SetName( _( "zone" ) );
1839 constraint.m_Value.SetMin( local );
1840 return constraint;
1841 }
1842 }
1843
1844 if( !constraint.GetParentRule() )
1845 {
1846 constraint.m_Type = NULL_CONSTRAINT;
1847 constraint.m_DisallowFlags = 0;
1848 }
1849
1850 return constraint;
1851}
1852
1853
1855 std::function<void( const DRC_CONSTRAINT* )> aFailureHandler,
1856 REPORTER* aReporter )
1857{
1858 /*
1859 * NOTE: all string manipulation MUST BE KEPT INSIDE the REPORT macro. It absolutely
1860 * kills performance when running bulk DRC tests (where aReporter is nullptr).
1861 */
1862
1863 auto testAssertion =
1864 [&]( const DRC_ENGINE_CONSTRAINT* c )
1865 {
1866 REPORT( wxString::Format( _( "Checking rule assertion '%s'." ),
1867 EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
1868
1869 if( c->constraint.m_Test->EvaluateFor( a, nullptr, c->constraint.m_Type,
1870 a->GetLayer(), aReporter ) )
1871 {
1872 REPORT( _( "Assertion passed." ) )
1873 }
1874 else
1875 {
1876 REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
1877 aFailureHandler( &c->constraint );
1878 }
1879 };
1880
1881 auto processConstraint =
1882 [&]( const DRC_ENGINE_CONSTRAINT* c )
1883 {
1884 REPORT( "" )
1885 REPORT( wxString::Format( _( "Checking %s." ), c->constraint.GetName() ) )
1886
1887 if( !( a->GetLayerSet() & c->layerTest ).any() )
1888 {
1889 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1890 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1891 }
1892
1893 if( !c->condition || c->condition->GetExpression().IsEmpty() )
1894 {
1895 REPORT( _( "Unconditional rule applied." ) )
1896 testAssertion( c );
1897 }
1898 else
1899 {
1900 REPORT( wxString::Format( _( "Checking rule condition '%s'." ),
1901 EscapeHTML( c->condition->GetExpression() ) ) )
1902
1903 if( c->condition->EvaluateFor( a, nullptr, c->constraint.m_Type,
1904 a->GetLayer(), aReporter ) )
1905 {
1906 REPORT( _( "Rule applied." ) )
1907 testAssertion( c );
1908 }
1909 else
1910 {
1911 REPORT( _( "Condition not satisfied; rule ignored." ) )
1912 }
1913 }
1914 };
1915
1917 {
1918 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ ASSERTION_CONSTRAINT ];
1919
1920 for( int ii = 0; ii < (int) ruleset->size(); ++ii )
1921 processConstraint( ruleset->at( ii ) );
1922 }
1923}
1924
1925
1926#undef REPORT
1927
1928
1930{
1931 assert( error_code >= 0 && error_code <= DRCE_LAST );
1932 return m_errorLimits[ error_code ] <= 0;
1933}
1934
1935
1936void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos,
1937 int aMarkerLayer, const std::function<void( PCB_MARKER* )>& aPathGenerator )
1938{
1939 static std::mutex globalLock;
1940
1941 m_errorLimits[ aItem->GetErrorCode() ] -= 1;
1942
1943 if( m_violationHandler )
1944 {
1945 std::lock_guard<std::mutex> guard( globalLock );
1946 m_violationHandler( aItem, aPos, aMarkerLayer, aPathGenerator );
1947 }
1948
1949 if( m_logReporter )
1950 {
1951 wxString msg = wxString::Format( wxT( "Test '%s': %s (code %d)" ),
1952 aItem->GetViolatingTest()->GetName(),
1953 aItem->GetErrorMessage( false ),
1954 aItem->GetErrorCode() );
1955
1956 DRC_RULE* rule = aItem->GetViolatingRule();
1957
1958 if( rule )
1959 msg += wxString::Format( wxT( ", violating rule: '%s'" ), rule->m_Name );
1960
1961 m_logReporter->Report( msg );
1962
1963 wxString violatingItemsStr = wxT( "Violating items: " );
1964
1965 m_logReporter->Report( wxString::Format( wxT( " |- violating position (%d, %d)" ),
1966 aPos.x,
1967 aPos.y ) );
1968 }
1969}
1970
1971
1973{
1974 if( !m_progressReporter )
1975 return true;
1976
1977 return m_progressReporter->KeepRefreshing( aWait );
1978}
1979
1980
1982{
1983 if( m_progressReporter )
1984 m_progressReporter->AdvanceProgress();
1985}
1986
1987
1989{
1990 if( m_progressReporter )
1991 m_progressReporter->SetMaxProgress( aSize );
1992}
1993
1994
1995bool DRC_ENGINE::ReportProgress( double aProgress )
1996{
1997 if( !m_progressReporter )
1998 return true;
1999
2000 m_progressReporter->SetCurrentProgress( aProgress );
2001 return m_progressReporter->KeepRefreshing( false );
2002}
2003
2004
2005bool DRC_ENGINE::ReportPhase( const wxString& aMessage )
2006{
2007 if( !m_progressReporter )
2008 return true;
2009
2010 m_progressReporter->AdvancePhase( aMessage );
2011 bool retval = m_progressReporter->KeepRefreshing( false );
2012 wxSafeYield( nullptr, true ); // Force an update for the message
2013 return retval;
2014}
2015
2016
2018{
2019 return m_progressReporter && m_progressReporter->IsCancelled();
2020}
2021
2022
2024{
2025 //drc_dbg( 10, "hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size() );
2026
2027 if( m_constraintMap.count( constraintID ) )
2028 return m_constraintMap[ constraintID ]->size() > 0;
2029
2030 return false;
2031}
2032
2033
2035{
2036 int worst = 0;
2037
2038 if( m_constraintMap.count( aConstraintId ) )
2039 {
2040 for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
2041 {
2042 int current = c->constraint.GetValue().Min();
2043
2044 if( current > worst )
2045 {
2046 worst = current;
2047 aConstraint = c->constraint;
2048 }
2049 }
2050 }
2051
2052 return worst > 0;
2053}
2054
2055
2057{
2058 std::set<int> distinctMinimums;
2059
2060 if( m_constraintMap.count( aConstraintId ) )
2061 {
2062 for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
2063 distinctMinimums.emplace( c->constraint.GetValue().Min() );
2064 }
2065
2066 return distinctMinimums;
2067}
2068
2069
2070// fixme: move two functions below to pcbcommon?
2071int DRC_ENGINE::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet,
2072 wxString& aBaseDpName )
2073{
2074 int rv = 0;
2075 int count = 0;
2076
2077 for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
2078 {
2079 int ch = *it;
2080
2081 if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
2082 {
2083 continue;
2084 }
2085 else if( ch == '+' )
2086 {
2087 aComplementNet = wxT( "-" );
2088 rv = 1;
2089 }
2090 else if( ch == '-' )
2091 {
2092 aComplementNet = wxT( "+" );
2093 rv = -1;
2094 }
2095 else if( ch == 'N' )
2096 {
2097 aComplementNet = wxT( "P" );
2098 rv = -1;
2099 }
2100 else if ( ch == 'P' )
2101 {
2102 aComplementNet = wxT( "N" );
2103 rv = 1;
2104 }
2105 else
2106 {
2107 break;
2108 }
2109 }
2110
2111 if( rv != 0 && count >= 1 )
2112 {
2113 aBaseDpName = aNetName.Left( aNetName.Length() - count );
2114 aComplementNet = wxString( aBaseDpName ) << aComplementNet << aNetName.Right( count - 1 );
2115 }
2116
2117 return rv;
2118}
2119
2120
2121bool DRC_ENGINE::IsNetADiffPair( BOARD* aBoard, NETINFO_ITEM* aNet, int& aNetP, int& aNetN )
2122{
2123 wxString refName = aNet->GetNetname();
2124 wxString dummy, coupledNetName;
2125
2126 if( int polarity = MatchDpSuffix( refName, coupledNetName, dummy ) )
2127 {
2128 NETINFO_ITEM* net = aBoard->FindNet( coupledNetName );
2129
2130 if( !net )
2131 return false;
2132
2133 if( polarity > 0 )
2134 {
2135 aNetP = aNet->GetNetCode();
2136 aNetN = net->GetNetCode();
2137 }
2138 else
2139 {
2140 aNetP = net->GetNetCode();
2141 aNetN = aNet->GetNetCode();
2142 }
2143
2144 return true;
2145 }
2146
2147 return false;
2148}
2149
2150
2155bool DRC_ENGINE::IsNetTieExclusion( int aTrackNetCode, PCB_LAYER_ID aTrackLayer,
2156 const VECTOR2I& aCollisionPos, BOARD_ITEM* aCollidingItem )
2157{
2158 FOOTPRINT* parentFootprint = aCollidingItem->GetParentFootprint();
2159
2160 if( parentFootprint && parentFootprint->IsNetTie() )
2161 {
2163 std::map<wxString, int> padToNetTieGroupMap = parentFootprint->MapPadNumbersToNetTieGroups();
2164
2165 for( PAD* pad : parentFootprint->Pads() )
2166 {
2167 if( padToNetTieGroupMap[ pad->GetNumber() ] >= 0 && aTrackNetCode == pad->GetNetCode() )
2168 {
2169 if( pad->GetEffectiveShape( aTrackLayer )->Collide( aCollisionPos, epsilon ) )
2170 return true;
2171 }
2172 }
2173 }
2174
2175 return false;
2176}
2177
2178
2180{
2181 for( DRC_TEST_PROVIDER* prov : m_testProviders )
2182 {
2183 if( name == prov->GetName() )
2184 return prov;
2185 }
2186
2187 return nullptr;
2188}
2189
2190
2191std::vector<BOARD_ITEM*> DRC_ENGINE::GetItemsMatchingCondition( const wxString& aExpression,
2192 DRC_CONSTRAINT_T aConstraint,
2193 REPORTER* aReporter )
2194{
2195 std::vector<BOARD_ITEM*> matches;
2196
2197 if( !m_board )
2198 return matches;
2199
2200 DRC_RULE_CONDITION condition( aExpression );
2201
2202 if( !condition.Compile( aReporter ? aReporter : m_logReporter ) )
2203 return matches;
2204
2205 BOARD_ITEM_SET items = m_board->GetItemSet();
2206
2207 for( auto& [kiid, item] : m_board->GetItemByIdCache() )
2208 {
2209 LSET itemLayers = item->GetLayerSet();
2210
2211 for( PCB_LAYER_ID layer : itemLayers )
2212 {
2213 if( condition.EvaluateFor( item, nullptr, static_cast<int>( aConstraint ), layer,
2214 aReporter ? aReporter : m_logReporter ) )
2215 {
2216 matches.push_back( item );
2217 break; // No need to check other layers
2218 }
2219 }
2220 }
2221
2222 return matches;
2223}
const char * name
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
std::set< BOARD_ITEM *, CompareByUuid > BOARD_ITEM_SET
Set of BOARD_ITEMs ordered by UUID.
Definition board.h:306
#define MAXIMUM_CLEARANCE
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual std::optional< int > GetClearanceOverrides(wxString *aSource) const
Return any clearance overrides set in the "classic" (ie: pre-rule) system.
virtual std::optional< int > GetLocalClearance() const
Return any local clearances set in the "classic" (ie: pre-rule) system.
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
std::map< int, SEVERITY > m_DRCSeverities
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:83
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition board_item.h:236
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition board_item.h:138
FOOTPRINT * GetParentFootprint() const
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition board_item.h:256
virtual bool HasDrilledHole() const
Definition board_item.h:165
virtual bool IsOnCopperLayer() const
Definition board_item.h:155
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition board.cpp:2331
Represents a single line in a time domain profile track propagation setup.
int GetDiffPairGap() const
int GetWidth() const
PCB_LAYER_ID GetSignalLayer() const
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
int m_DisallowFlags
Definition drc_rule.h:229
void SetParentRule(DRC_RULE *aParentRule)
Definition drc_rule.h:189
MINOPTMAX< int > & Value()
Definition drc_rule.h:187
ZONE_CONNECTION m_ZoneConnection
Definition drc_rule.h:230
void SetName(const wxString &aName)
Definition drc_rule.h:192
MINOPTMAX< int > m_Value
Definition drc_rule.h:228
DRC_CONSTRAINT_T m_Type
Definition drc_rule.h:227
void SetOptionsFromOther(const DRC_CONSTRAINT &aOther)
Definition drc_rule.h:224
DRC_RULE * GetParentRule() const
Definition drc_rule.h:190
bool m_ImplicitMin
Definition drc_rule.h:232
std::map< DRC_CONSTRAINT_T, std::vector< DRC_ENGINE_CONSTRAINT * > * > m_constraintMap
Definition drc_engine.h:266
void AdvanceProgress()
std::shared_ptr< DRC_RULE > createImplicitRule(const wxString &name, DRC_IMPLICIT_SOURCE aImplicitSource)
void RunTests(EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints, BOARD_COMMIT *aCommit=nullptr)
Run the DRC tests.
bool m_testFootprints
Definition drc_engine.h:263
void addRule(std::shared_ptr< DRC_RULE > &rule)
Definition drc_engine.h:226
PROGRESS_REPORTER * m_progressReporter
Definition drc_engine.h:270
void loadRules(const wxFileName &aPath)
Load and parse a rule set from an sexpr text file.
std::vector< DRC_TEST_PROVIDER * > m_testProviders
Definition drc_engine.h:259
REPORTER * m_logReporter
Definition drc_engine.h:269
void compileRules()
std::set< int > QueryDistinctConstraints(DRC_CONSTRAINT_T aConstraintId)
DS_PROXY_VIEW_ITEM * m_drawingSheet
Definition drc_engine.h:254
NETLIST * m_schematicNetlist
Definition drc_engine.h:255
bool KeepRefreshing(bool aWait=false)
BOARD * m_board
Definition drc_engine.h:253
bool m_reportAllTrackErrors
Definition drc_engine.h:262
bool ReportProgress(double aProgress)
DRC_TEST_PROVIDER * GetTestProvider(const wxString &name) const
bool HasRulesForConstraintType(DRC_CONSTRAINT_T constraintID)
BOARD_DESIGN_SETTINGS * GetDesignSettings() const
Definition drc_engine.h:100
void SetMaxProgress(int aSize)
DRC_ENGINE(BOARD *aBoard=nullptr, BOARD_DESIGN_SETTINGS *aSettings=nullptr)
std::vector< int > m_errorLimits
Definition drc_engine.h:261
bool IsErrorLimitExceeded(int error_code)
void ProcessAssertions(const BOARD_ITEM *a, std::function< void(const DRC_CONSTRAINT *)> aFailureHandler, REPORTER *aReporter=nullptr)
void loadImplicitRules()
DRC_VIOLATION_HANDLER m_violationHandler
Definition drc_engine.h:268
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
std::vector< std::shared_ptr< DRC_RULE > > m_rules
Definition drc_engine.h:257
bool IsCancelled() const
static bool IsNetADiffPair(BOARD *aBoard, NETINFO_ITEM *aNet, int &aNetP, int &aNetN)
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 ...
virtual ~DRC_ENGINE()
bool QueryWorstConstraint(DRC_CONSTRAINT_T aRuleId, DRC_CONSTRAINT &aConstraint)
std::vector< BOARD_ITEM * > GetItemsMatchingCondition(const wxString &aExpression, DRC_CONSTRAINT_T aConstraint=ASSERTION_CONSTRAINT, REPORTER *aReporter=nullptr)
Evaluate a DRC condition against all board items and return matches.
void InitEngine(const wxFileName &aRulePath)
Initialize the DRC engine.
DRC_CONSTRAINT EvalZoneConnection(const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
static int MatchDpSuffix(const wxString &aNetName, wxString &aComplementNet, wxString &aBaseDpName)
Check if the given net is a diff pair, returning its polarity and complement if so.
bool ReportPhase(const wxString &aMessage)
bool m_rulesValid
Definition drc_engine.h:258
BOARD_DESIGN_SETTINGS * m_designSettings
Definition drc_engine.h:252
void ReportViolation(const std::shared_ptr< DRC_ITEM > &aItem, const VECTOR2I &aPos, int aMarkerLayer, const std::function< void(PCB_MARKER *)> &aPathGenerator={})
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
bool Compile(REPORTER *aReporter, int aSourceLine=0, int aSourceOffset=0)
bool EvaluateFor(const BOARD_ITEM *aItemA, const BOARD_ITEM *aItemB, int aConstraint, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
bool IsImplicit() const
Definition drc_rule.h:134
wxString m_Name
Definition drc_rule.h:143
std::vector< DRC_TEST_PROVIDER * > GetTestProviders() const
static DRC_TEST_PROVIDER_REGISTRY & Instance()
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out DRC_ITEM and posi...
void SetDRCEngine(DRC_ENGINE *engine)
virtual wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const
Return a user-visible description string of this item.
Definition eda_item.cpp:144
const KIID m_Uuid
Definition eda_item.h:516
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:145
A LINE_READER that reads from an open file.
Definition richio.h:158
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition richio.cpp:208
ZONE_CONNECTION GetLocalZoneConnection() const
Definition footprint.h:309
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
std::deque< PAD * > & Pads()
Definition footprint.h:224
const std::set< int > & GetNetTieCache(const BOARD_ITEM *aItem) const
Get the set of net codes that are allowed to connect to a footprint item.
Definition footprint.h:556
bool IsNetTie() const
Definition footprint.h:340
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
wxString AsString() const
Definition kiid.cpp:246
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition lset.cpp:705
static const LSET & BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition lset.cpp:712
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:188
T Min() const
Definition minoptmax.h:33
void SetMin(T v)
Definition minoptmax.h:41
void SetOpt(T v)
Definition minoptmax.h:43
void SetMax(T v)
Definition minoptmax.h:42
A collection of nets and the parameters used to route or test these nets.
Definition netclass.h:45
Handle the data for a net.
Definition netinfo.h:54
const wxString & GetNetname() const
Definition netinfo.h:112
int GetNetCode() const
Definition netinfo.h:106
const std::map< wxString, std::shared_ptr< NETCLASS > > & GetCompositeNetclasses() const
Gets all composite (multiple assignment / missing defaults) netclasses.
const std::map< wxString, std::shared_ptr< NETCLASS > > & GetNetclasses() const
Gets all netclasses.
std::shared_ptr< NETCLASS > GetDefaultNetclass()
Gets the default netclass for the project.
Definition pad.h:55
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_shape.h:210
A small class to help profiling.
Definition profile.h:49
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition profile.h:88
double msecs(bool aSinceLast=false)
Definition profile.h:149
Container for project specific data.
Definition project.h:65
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual bool HasMessageOfSeverity(int aSeverityMask) const
Returns true if the reporter has one or more messages matching the specified severity mask.
Definition reporter.h:143
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
const EDA_IU_SCALE & GetIuScale() const
wxString MessageTextFromUnscaledValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
UNITS_PROVIDER(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits)
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
void SetUserUnits(EDA_UNITS aUnits)
Handle a list of polygons defining a copper zone.
Definition zone.h:74
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition zone.cpp:1155
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:701
bool GetDoNotAllowVias() const
Definition zone.h:712
bool GetDoNotAllowPads() const
Definition zone.h:714
bool GetDoNotAllowTracks() const
Definition zone.h:713
const wxString & GetZoneName() const
Definition zone.h:159
int GetMinThickness() const
Definition zone.h:297
ZONE_CONNECTION GetPadConnection() const
Definition zone.h:294
int GetThermalReliefSpokeWidth() const
Definition zone.h:241
bool GetDoNotAllowFootprints() const
Definition zone.h:715
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:136
bool HasKeepoutParametersSet() const
Accessor to determine if any keepout parameters are set.
Definition zone.h:692
bool GetDoNotAllowZoneFills() const
Definition zone.h:711
int GetThermalReliefGap() const
Definition zone.h:230
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition common.cpp:61
wxString DescribeRef(const wxString &aRef)
Returns a user-visible HTML string describing a footprint reference designator.
Definition common.cpp:293
The common library.
void drcPrintDebugMessage(int level, const wxString &msg, const char *function, int line)
#define EXTENDED_ERROR_LIMIT
static bool isKeepoutZone(const BOARD_ITEM *aItem, bool aCheckFlags)
#define ERROR_LIMIT
@ DRCE_TUNING_PROFILE_IMPLICIT_RULES
Definition drc_item.h:114
@ DRCE_UNCONNECTED_ITEMS
Definition drc_item.h:40
@ DRCE_CLEARANCE
Definition drc_item.h:44
@ DRCE_FIRST
Definition drc_item.h:39
@ DRCE_LAST
Definition drc_item.h:120
DRC_IMPLICIT_SOURCE
Definition drc_rule.h:104
@ DRC_DISALLOW_PADS
Definition drc_rule.h:94
@ DRC_DISALLOW_BURIED_VIAS
Definition drc_rule.h:92
@ DRC_DISALLOW_BLIND_VIAS
Definition drc_rule.h:91
@ DRC_DISALLOW_TEXTS
Definition drc_rule.h:96
@ DRC_DISALLOW_ZONES
Definition drc_rule.h:95
@ DRC_DISALLOW_HOLES
Definition drc_rule.h:98
@ DRC_DISALLOW_GRAPHICS
Definition drc_rule.h:97
@ DRC_DISALLOW_THROUGH_VIAS
Definition drc_rule.h:89
@ DRC_DISALLOW_FOOTPRINTS
Definition drc_rule.h:99
@ DRC_DISALLOW_TRACKS
Definition drc_rule.h:93
@ DRC_DISALLOW_MICRO_VIAS
Definition drc_rule.h:90
DRC_CONSTRAINT_T
Definition drc_rule.h:47
@ ANNULAR_WIDTH_CONSTRAINT
Definition drc_rule.h:61
@ COURTYARD_CLEARANCE_CONSTRAINT
Definition drc_rule.h:55
@ VIA_DIAMETER_CONSTRAINT
Definition drc_rule.h:70
@ ZONE_CONNECTION_CONSTRAINT
Definition drc_rule.h:62
@ DIFF_PAIR_GAP_CONSTRAINT
Definition drc_rule.h:73
@ DISALLOW_CONSTRAINT
Definition drc_rule.h:69
@ TRACK_WIDTH_CONSTRAINT
Definition drc_rule.h:59
@ SILK_CLEARANCE_CONSTRAINT
Definition drc_rule.h:56
@ EDGE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:53
@ MIN_RESOLVED_SPOKES_CONSTRAINT
Definition drc_rule.h:65
@ TEXT_THICKNESS_CONSTRAINT
Definition drc_rule.h:58
@ LENGTH_CONSTRAINT
Definition drc_rule.h:71
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:78
@ CLEARANCE_CONSTRAINT
Definition drc_rule.h:49
@ NULL_CONSTRAINT
Definition drc_rule.h:48
@ THERMAL_SPOKE_WIDTH_CONSTRAINT
Definition drc_rule.h:64
@ CONNECTION_WIDTH_CONSTRAINT
Definition drc_rule.h:80
@ THERMAL_RELIEF_GAP_CONSTRAINT
Definition drc_rule.h:63
@ MAX_UNCOUPLED_CONSTRAINT
Definition drc_rule.h:74
@ ASSERTION_CONSTRAINT
Definition drc_rule.h:79
@ SKEW_CONSTRAINT
Definition drc_rule.h:72
@ HOLE_CLEARANCE_CONSTRAINT
Definition drc_rule.h:51
@ SOLDER_PASTE_ABS_MARGIN_CONSTRAINT
Definition drc_rule.h:67
@ SOLDER_MASK_EXPANSION_CONSTRAINT
Definition drc_rule.h:66
@ HOLE_SIZE_CONSTRAINT
Definition drc_rule.h:54
@ TEXT_HEIGHT_CONSTRAINT
Definition drc_rule.h:57
@ CREEPAGE_CONSTRAINT
Definition drc_rule.h:50
@ PHYSICAL_CLEARANCE_CONSTRAINT
Definition drc_rule.h:77
@ SOLDER_PASTE_REL_MARGIN_CONSTRAINT
Definition drc_rule.h:68
@ HOLE_TO_HOLE_CONSTRAINT
Definition drc_rule.h:52
constexpr int DRC_DISALLOW_VIAS
Definition drc_rule.h:114
#define _(s)
#define HOLE_PROXY
Indicates the BOARD_ITEM is a proxy for its hole.
EDA_UNITS
Definition eda_units.h:48
static FILENAME_RESOLVER * resolver
static const wxChar * traceDrcProfile
Flag to enable DRC profile timing logging.
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:60
@ F_CrtYd
Definition layer_ids.h:116
@ F_SilkS
Definition layer_ids.h:100
@ B_CrtYd
Definition layer_ids.h:115
@ UNDEFINED_LAYER
Definition layer_ids.h:61
@ B_SilkS
Definition layer_ids.h:101
#define REPORT(msg)
@ PTH
Plated through hole pad.
Definition padstack.h:98
@ RPT_SEVERITY_ERROR
const double epsilon
std::vector< FAB_LAYER_COLOR > dummy
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
std::shared_ptr< DRC_RULE > parentRule
Definition drc_engine.h:244
DRC_RULE_CONDITION * condition
Definition drc_engine.h:243
A filename or source description, a problem input line, a line number, a byte offset,...
Represents a single line in the tuning profile configuration grid.
PROFILE_TYPE m_Type
std::vector< DELAY_PROFILE_TRACK_PROPAGATION_ENTRY > m_TrackPropagationEntries
int clearance
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:97
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:108
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:92
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:90
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:101
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:86
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:98
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:94
@ PCB_LOCATE_HOLE_T
Definition typeinfo.h:131
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:96
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
wxString PrintZoneConnection(ZONE_CONNECTION aConnection)
Definition zones.h:56
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition zones.h:47
@ THERMAL
Use thermal relief for pads.
Definition zones.h:50
@ THT_THERMAL
Thermal relief only for THT pads.
Definition zones.h:52
@ FULL
pads are covered by copper
Definition zones.h:51