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