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 (C) 2017-2024 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 <progress_reporter.h>
30#include <string_utils.h>
32#include <drc/drc_engine.h>
33#include <drc/drc_rtree.h>
34#include <drc/drc_rule_parser.h>
35#include <drc/drc_rule.h>
38#include <drc/drc_item.h>
40#include <footprint.h>
41#include <pad.h>
42#include <pcb_track.h>
43#include <core/profile.h>
44#include <core/thread_pool.h>
45#include <zone.h>
46
47
48// wxListBox's performance degrades horrifically with very large datasets. It's not clear
49// they're useful to the user anyway.
50#define ERROR_LIMIT 199
51#define EXTENDED_ERROR_LIMIT 499
52
53
61static const wxChar* traceDrcProfile = wxT( "KICAD_DRC_PROFILE" );
62
63
64void drcPrintDebugMessage( int level, const wxString& msg, const char *function, int line )
65{
66 wxString valueStr;
67
68 if( wxGetEnv( wxT( "DRC_DEBUG" ), &valueStr ) )
69 {
70 int setLevel = wxAtoi( valueStr );
71
72 if( level <= setLevel )
73 printf( "%-30s:%d | %s\n", function, line, (const char *) msg.c_str() );
74 }
75}
76
77
80 m_designSettings ( aSettings ),
81 m_board( aBoard ),
82 m_drawingSheet( nullptr ),
83 m_schematicNetlist( nullptr ),
84 m_rulesValid( false ),
85 m_reportAllTrackErrors( false ),
86 m_testFootprints( false ),
87 m_reporter( nullptr ),
88 m_progressReporter( nullptr )
89{
90 m_errorLimits.resize( DRCE_LAST + 1 );
91
92 for( int ii = DRCE_FIRST; ii <= DRCE_LAST; ++ii )
94
96}
97
98
100{
101 m_rules.clear();
102
103 for( std::pair<DRC_CONSTRAINT_T, std::vector<DRC_ENGINE_CONSTRAINT*>*> pair : m_constraintMap )
104 {
105 for( DRC_ENGINE_CONSTRAINT* constraint : *pair.second )
106 delete constraint;
107
108 delete pair.second;
109 }
110}
111
112
113static bool isKeepoutZone( const BOARD_ITEM* aItem, bool aCheckFlags )
114{
115 if( !aItem || aItem->Type() != PCB_ZONE_T )
116 return false;
117
118 const ZONE* zone = static_cast<const ZONE*>( aItem );
119
120 if( !zone->GetIsRuleArea() )
121 return false;
122
123 if( !zone->HasKeepoutParametersSet() )
124 return false;
125
126 if( aCheckFlags )
127 {
128 if( !zone->GetDoNotAllowTracks()
129 && !zone->GetDoNotAllowVias()
130 && !zone->GetDoNotAllowPads()
131 && !zone->GetDoNotAllowCopperPour()
132 && !zone->GetDoNotAllowFootprints() )
133 {
134 return false;
135 }
136 }
137
138 return true;
139}
140
141
142std::shared_ptr<DRC_RULE> DRC_ENGINE::createImplicitRule( const wxString& name )
143{
144 std::shared_ptr<DRC_RULE> rule = std::make_shared<DRC_RULE>();
145
146 rule->m_Name = name;
147 rule->m_Implicit = true;
148
149 addRule( rule );
150
151 return rule;
152}
153
154
156{
157 ReportAux( wxString::Format( wxT( "Building implicit rules (per-item/class overrides, etc...)" ) ) );
158
160
161 // 1) global defaults
162
163 std::shared_ptr<DRC_RULE> rule = createImplicitRule( _( "board setup constraints" ) );
164
165 DRC_CONSTRAINT widthConstraint( TRACK_WIDTH_CONSTRAINT );
166 widthConstraint.Value().SetMin( bds.m_TrackMinWidth );
167 rule->AddConstraint( widthConstraint );
168
169 DRC_CONSTRAINT connectionConstraint( CONNECTION_WIDTH_CONSTRAINT );
170 connectionConstraint.Value().SetMin( bds.m_MinConn );
171 rule->AddConstraint( connectionConstraint );
172
173 DRC_CONSTRAINT drillConstraint( HOLE_SIZE_CONSTRAINT );
174 drillConstraint.Value().SetMin( bds.m_MinThroughDrill );
175 rule->AddConstraint( drillConstraint );
176
177 DRC_CONSTRAINT annulusConstraint( ANNULAR_WIDTH_CONSTRAINT );
178 annulusConstraint.Value().SetMin( bds.m_ViasMinAnnularWidth );
179 rule->AddConstraint( annulusConstraint );
180
181 DRC_CONSTRAINT diameterConstraint( VIA_DIAMETER_CONSTRAINT );
182 diameterConstraint.Value().SetMin( bds.m_ViasMinSize );
183 rule->AddConstraint( diameterConstraint );
184
185 DRC_CONSTRAINT holeToHoleConstraint( HOLE_TO_HOLE_CONSTRAINT );
186 holeToHoleConstraint.Value().SetMin( bds.m_HoleToHoleMin );
187 rule->AddConstraint( holeToHoleConstraint );
188
189 rule = createImplicitRule( _( "board setup constraints zone fill strategy" ) );
190 DRC_CONSTRAINT thermalSpokeCountConstraint( MIN_RESOLVED_SPOKES_CONSTRAINT );
191 thermalSpokeCountConstraint.Value().SetMin( bds.m_MinResolvedSpokes );
192 rule->AddConstraint( thermalSpokeCountConstraint );
193
194 rule = createImplicitRule( _( "board setup constraints silk" ) );
195 rule->m_LayerCondition = LSET( { F_SilkS, B_SilkS } );
196 DRC_CONSTRAINT silkClearanceConstraint( SILK_CLEARANCE_CONSTRAINT );
197 silkClearanceConstraint.Value().SetMin( bds.m_SilkClearance );
198 rule->AddConstraint( silkClearanceConstraint );
199
200 rule = createImplicitRule( _( "board setup constraints silk text height" ) );
201 rule->m_LayerCondition = LSET( { F_SilkS, B_SilkS } );
202 DRC_CONSTRAINT silkTextHeightConstraint( TEXT_HEIGHT_CONSTRAINT );
203 silkTextHeightConstraint.Value().SetMin( bds.m_MinSilkTextHeight );
204 rule->AddConstraint( silkTextHeightConstraint );
205
206 rule = createImplicitRule( _( "board setup constraints silk text thickness" ) );
207 rule->m_LayerCondition = LSET( { F_SilkS, B_SilkS } );
208 DRC_CONSTRAINT silkTextThicknessConstraint( TEXT_THICKNESS_CONSTRAINT );
209 silkTextThicknessConstraint.Value().SetMin( bds.m_MinSilkTextThickness );
210 rule->AddConstraint( silkTextThicknessConstraint );
211
212 rule = createImplicitRule( _( "board setup constraints hole" ) );
213 DRC_CONSTRAINT holeClearanceConstraint( HOLE_CLEARANCE_CONSTRAINT );
214 holeClearanceConstraint.Value().SetMin( bds.m_HoleClearance );
215 rule->AddConstraint( holeClearanceConstraint );
216
217 rule = createImplicitRule( _( "board setup constraints edge" ) );
218 DRC_CONSTRAINT edgeClearanceConstraint( EDGE_CLEARANCE_CONSTRAINT );
219 edgeClearanceConstraint.Value().SetMin( bds.m_CopperEdgeClearance );
220 rule->AddConstraint( edgeClearanceConstraint );
221
222 rule = createImplicitRule( _( "board setup constraints courtyard" ) );
223 DRC_CONSTRAINT courtyardClearanceConstraint( COURTYARD_CLEARANCE_CONSTRAINT );
224 holeToHoleConstraint.Value().SetMin( 0 );
225 rule->AddConstraint( courtyardClearanceConstraint );
226
227 // 2) micro-via specific defaults (new DRC doesn't treat microvias in any special way)
228
229 std::shared_ptr<DRC_RULE> uViaRule = createImplicitRule( _( "board setup micro-via constraints" ) );
230
231 uViaRule->m_Condition = new DRC_RULE_CONDITION( wxT( "A.Via_Type == 'Micro'" ) );
232
233 DRC_CONSTRAINT uViaDrillConstraint( HOLE_SIZE_CONSTRAINT );
234 uViaDrillConstraint.Value().SetMin( bds.m_MicroViasMinDrill );
235 uViaRule->AddConstraint( uViaDrillConstraint );
236
237 DRC_CONSTRAINT uViaDiameterConstraint( VIA_DIAMETER_CONSTRAINT );
238 uViaDiameterConstraint.Value().SetMin( bds.m_MicroViasMinSize );
239 uViaRule->AddConstraint( uViaDiameterConstraint );
240
241 // 3) per-netclass rules
242
243 std::vector<std::shared_ptr<DRC_RULE>> netclassClearanceRules;
244 std::vector<std::shared_ptr<DRC_RULE>> netclassItemSpecificRules;
245
246 auto makeNetclassRules =
247 [&]( const std::shared_ptr<NETCLASS>& nc, bool isDefault )
248 {
249 wxString ncName = nc->GetVariableSubstitutionName();
250 wxString friendlyName = nc->GetName();
251 wxString expr;
252
253 ncName.Replace( "'", "\\'" );
254
255 if( nc->HasClearance())
256 {
257 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
258 netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ),
259 nc->GetClearanceParent()->GetName() );
260 netclassRule->m_Implicit = true;
261
262 expr = wxString::Format( wxT( "A.NetClass == '%s'" ), ncName );
263 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
264 netclassClearanceRules.push_back( netclassRule );
265
267 constraint.Value().SetMin( nc->GetClearance() );
268 netclassRule->AddConstraint( constraint );
269 }
270
271 if( nc->HasTrackWidth() )
272 {
273 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
274 netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ),
275 nc->GetTrackWidthParent()->GetName() );
276 netclassRule->m_Implicit = true;
277
278 expr = wxString::Format( wxT( "A.NetClass == '%s'" ), ncName );
279 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
280 netclassClearanceRules.push_back( netclassRule );
281
283 constraint.Value().SetMin( bds.m_TrackMinWidth );
284 constraint.Value().SetOpt( nc->GetTrackWidth() );
285 netclassRule->AddConstraint( constraint );
286 }
287
288 if( nc->HasDiffPairWidth() )
289 {
290 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
291 netclassRule->m_Name = wxString::Format( _( "netclass '%s' (diff pair)" ),
292 nc->GetDiffPairWidthParent()->GetName() );
293 netclassRule->m_Implicit = true;
294
295 expr = wxString::Format( wxT( "A.NetClass == '%s' && A.inDiffPair('*')" ),
296 ncName );
297 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
298 netclassItemSpecificRules.push_back( netclassRule );
299
301 constraint.Value().SetMin( bds.m_TrackMinWidth );
302 constraint.Value().SetOpt( nc->GetDiffPairWidth() );
303 netclassRule->AddConstraint( constraint );
304 }
305
306 if( nc->HasDiffPairGap() )
307 {
308 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
309 netclassRule->m_Name = wxString::Format( _( "netclass '%s' (diff pair)" ),
310 nc->GetDiffPairGapParent()->GetName() );
311 netclassRule->m_Implicit = true;
312
313 expr = wxString::Format( wxT( "A.NetClass == '%s'" ), ncName );
314 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
315 netclassItemSpecificRules.push_back( netclassRule );
316
318 constraint.Value().SetMin( bds.m_MinClearance );
319 constraint.Value().SetOpt( nc->GetDiffPairGap() );
320 netclassRule->AddConstraint( constraint );
321
322 // A narrower diffpair gap overrides the netclass min clearance
323 if( nc->GetDiffPairGap() < nc->GetClearance() )
324 {
325 netclassRule = std::make_shared<DRC_RULE>();
326 netclassRule->m_Name = wxString::Format( _( "netclass '%s' (diff pair)" ),
327 nc->GetDiffPairGapParent()->GetName() );
328 netclassRule->m_Implicit = true;
329
330 expr = wxString::Format( wxT( "A.NetClass == '%s' && AB.isCoupledDiffPair()" ),
331 ncName );
332 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
333 netclassItemSpecificRules.push_back( netclassRule );
334
335 DRC_CONSTRAINT min_clearanceConstraint( CLEARANCE_CONSTRAINT );
336 min_clearanceConstraint.Value().SetMin( nc->GetDiffPairGap() );
337 netclassRule->AddConstraint( min_clearanceConstraint );
338 }
339 }
340
341 if( nc->HasViaDiameter() )
342 {
343 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
344 netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ),
345 nc->GetViaDiameterParent()->GetName() );
346 netclassRule->m_Implicit = true;
347
348 expr = wxString::Format( wxT( "A.NetClass == '%s' && A.Via_Type != 'Micro'" ),
349 ncName );
350 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
351 netclassItemSpecificRules.push_back( netclassRule );
352
354 constraint.Value().SetMin( bds.m_ViasMinSize );
355 constraint.Value().SetOpt( nc->GetViaDiameter() );
356 netclassRule->AddConstraint( constraint );
357 }
358
359 if( nc->HasViaDrill() )
360 {
361 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
362 netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ),
363 nc->GetViaDrillParent()->GetName() );
364 netclassRule->m_Implicit = true;
365
366 expr = wxString::Format( wxT( "A.NetClass == '%s' && A.Via_Type != 'Micro'" ),
367 ncName );
368 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
369 netclassItemSpecificRules.push_back( netclassRule );
370
372 constraint.Value().SetMin( bds.m_MinThroughDrill );
373 constraint.Value().SetOpt( nc->GetViaDrill() );
374 netclassRule->AddConstraint( constraint );
375 }
376
377 if( nc->HasuViaDiameter() )
378 {
379 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
380 netclassRule->m_Name = wxString::Format( _( "netclass '%s' (uvia)" ),
381 nc->GetuViaDiameterParent()->GetName() );
382 netclassRule->m_Implicit = true;
383
384 expr = wxString::Format( wxT( "A.NetClass == '%s' && A.Via_Type == 'Micro'" ),
385 ncName );
386 netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
387 netclassItemSpecificRules.push_back( netclassRule );
388
390 constraint.Value().SetMin( bds.m_MicroViasMinSize );
391 constraint.Value().SetMin( nc->GetuViaDiameter() );
392 netclassRule->AddConstraint( constraint );
393 }
394
395 if( nc->HasuViaDrill() )
396 {
397 std::shared_ptr<DRC_RULE> netclassRule = std::make_shared<DRC_RULE>();
398 netclassRule->m_Name = wxString::Format( _( "netclass '%s' (uvia)" ),
399 nc->GetuViaDrillParent()->GetName() );
400 netclassRule->m_Implicit = true;
401
402 expr = wxString::Format( wxT( "A.NetClass == '%s' && A.Via_Type == 'Micro'" ),
403 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
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 // 3) keepout area rules
442
443 std::vector<ZONE*> keepoutZones;
444
445 for( ZONE* zone : m_board->Zones() )
446 {
447 if( isKeepoutZone( zone, true ) )
448 keepoutZones.push_back( zone );
449 }
450
451 for( FOOTPRINT* footprint : m_board->Footprints() )
452 {
453 for( ZONE* zone : footprint->Zones() )
454 {
455 if( isKeepoutZone( zone, true ) )
456 keepoutZones.push_back( zone );
457 }
458 }
459
460 for( ZONE* zone : keepoutZones )
461 {
462 wxString name = zone->GetZoneName();
463
464 if( name.IsEmpty() )
465 rule = createImplicitRule( _( "keepout area" ) );
466 else
467 rule = createImplicitRule( wxString::Format( _( "keepout area '%s'" ), name ) );
468
469 rule->m_ImplicitItemId = zone->m_Uuid;
470
471 rule->m_Condition = new DRC_RULE_CONDITION( wxString::Format( wxT( "A.intersectsArea('%s')" ),
472 zone->m_Uuid.AsString() ) );
473
474 rule->m_LayerCondition = zone->GetLayerSet();
475
476 int disallowFlags = 0;
477
478 if( zone->GetDoNotAllowTracks() )
479 disallowFlags |= DRC_DISALLOW_TRACKS;
480
481 if( zone->GetDoNotAllowVias() )
482 disallowFlags |= DRC_DISALLOW_VIAS;
483
484 if( zone->GetDoNotAllowPads() )
485 disallowFlags |= DRC_DISALLOW_PADS;
486
487 if( zone->GetDoNotAllowCopperPour() )
488 disallowFlags |= DRC_DISALLOW_ZONES;
489
490 if( zone->GetDoNotAllowFootprints() )
491 disallowFlags |= DRC_DISALLOW_FOOTPRINTS;
492
493 DRC_CONSTRAINT disallowConstraint( DISALLOW_CONSTRAINT );
494 disallowConstraint.m_DisallowFlags = disallowFlags;
495 rule->AddConstraint( disallowConstraint );
496 }
497
498 ReportAux( wxString::Format( wxT( "Building %d implicit netclass rules" ),
499 (int) netclassClearanceRules.size() ) );
500}
501
502
503void DRC_ENGINE::loadRules( const wxFileName& aPath )
504{
505 if( aPath.FileExists() )
506 {
507 std::vector<std::shared_ptr<DRC_RULE>> rules;
508
509 FILE* fp = wxFopen( aPath.GetFullPath(), wxT( "rt" ) );
510
511 if( fp )
512 {
513 DRC_RULES_PARSER parser( fp, aPath.GetFullPath() );
514 parser.Parse( rules, m_reporter );
515 }
516
517 // Copy the rules into the member variable afterwards so that if Parse() throws then
518 // the possibly malformed rules won't contaminate the current ruleset.
519
520 for( std::shared_ptr<DRC_RULE>& rule : rules )
521 m_rules.push_back( rule );
522 }
523}
524
525
527{
528 ReportAux( wxString::Format( wxT( "Compiling Rules (%d rules): " ), (int) m_rules.size() ) );
529
530 for( std::shared_ptr<DRC_RULE>& rule : m_rules )
531 {
532 DRC_RULE_CONDITION* condition = nullptr;
533
534 if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() )
535 {
536 condition = rule->m_Condition;
537 condition->Compile( nullptr );
538 }
539
540 for( const DRC_CONSTRAINT& constraint : rule->m_Constraints )
541 {
542 if( !m_constraintMap.count( constraint.m_Type ) )
543 m_constraintMap[ constraint.m_Type ] = new std::vector<DRC_ENGINE_CONSTRAINT*>();
544
545 DRC_ENGINE_CONSTRAINT* engineConstraint = new DRC_ENGINE_CONSTRAINT;
546
547 engineConstraint->layerTest = rule->m_LayerCondition;
548 engineConstraint->condition = condition;
549 engineConstraint->constraint = constraint;
550 engineConstraint->parentRule = rule;
551 m_constraintMap[ constraint.m_Type ]->push_back( engineConstraint );
552 }
553 }
554}
555
556
557void DRC_ENGINE::InitEngine( const wxFileName& aRulePath )
558{
560
561 for( DRC_TEST_PROVIDER* provider : m_testProviders )
562 {
563 ReportAux( wxString::Format( wxT( "Create DRC provider: '%s'" ), provider->GetName() ) );
564 provider->SetDRCEngine( this );
565 }
566
567 m_rules.clear();
568 m_rulesValid = false;
569
570 for( std::pair<DRC_CONSTRAINT_T, std::vector<DRC_ENGINE_CONSTRAINT*>*> pair : m_constraintMap )
571 {
572 for( DRC_ENGINE_CONSTRAINT* constraint : *pair.second )
573 delete constraint;
574
575 delete pair.second;
576 }
577
578 m_constraintMap.clear();
579
580 m_board->IncrementTimeStamp(); // Clear board-level caches
581
582 try // attempt to load full set of rules (implicit + user rules)
583 {
585 loadRules( aRulePath );
586 compileRules();
587 }
588 catch( PARSE_ERROR& original_parse_error )
589 {
590 try // try again with just our implicit rules
591 {
593 compileRules();
594 }
595 catch( PARSE_ERROR& )
596 {
597 wxFAIL_MSG( wxT( "Compiling implicit rules failed." ) );
598 }
599
600 throw original_parse_error;
601 }
602
603 for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
605
606 m_rulesValid = true;
607}
608
609
610void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints,
611 BOARD_COMMIT* aCommit )
612{
613 PROF_TIMER timer;
614
615 SetUserUnits( aUnits );
616
617 m_reportAllTrackErrors = aReportAllTrackErrors;
618 m_testFootprints = aTestFootprints;
619
620 for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
621 {
622 if( m_designSettings->Ignore( ii ) )
623 m_errorLimits[ ii ] = 0;
624 else if( ii == DRCE_CLEARANCE || ii == DRCE_UNCONNECTED_ITEMS )
626 else
628 }
629
631
632 m_board->IncrementTimeStamp(); // Invalidate all caches...
633
634 DRC_CACHE_GENERATOR cacheGenerator;
635 cacheGenerator.SetDRCEngine( this );
636
637 if( !cacheGenerator.Run() ) // ... and regenerate them.
638 return;
639
640 int timestamp = m_board->GetTimeStamp();
641
642 for( DRC_TEST_PROVIDER* provider : m_testProviders )
643 {
644 ReportAux( wxString::Format( wxT( "Run DRC provider: '%s'" ), provider->GetName() ) );
645 provider->SetCommit( aCommit );
646
647 if( !provider->RunTests( aUnits ) )
648 break;
649 }
650
651 timer.Stop();
652 wxLogTrace( traceDrcProfile, "DRC took %0.3f ms", timer.msecs() );
653
654 // DRC tests are multi-threaded; anything that causes us to attempt to re-generate the
655 // caches while DRC is running is problematic.
656 wxASSERT( timestamp == m_board->GetTimeStamp() );
657}
658
659
660#define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } }
661
663 PCB_LAYER_ID aLayer, REPORTER* aReporter )
664{
665 DRC_CONSTRAINT constraint = EvalRules( ZONE_CONNECTION_CONSTRAINT, a, b, aLayer, aReporter );
666
667 REPORT( "" )
668 REPORT( wxString::Format( _( "Resolved zone connection type: %s." ),
670
671 if( constraint.m_ZoneConnection == ZONE_CONNECTION::THT_THERMAL )
672 {
673 const PAD* pad = nullptr;
674
675 if( a->Type() == PCB_PAD_T )
676 pad = static_cast<const PAD*>( a );
677 else if( b->Type() == PCB_PAD_T )
678 pad = static_cast<const PAD*>( b );
679
680 if( pad && pad->GetAttribute() == PAD_ATTRIB::PTH )
681 {
682 constraint.m_ZoneConnection = ZONE_CONNECTION::THERMAL;
683 }
684 else
685 {
686 REPORT( wxString::Format( _( "Pad is not a through hole pad; connection will be: %s." ),
687 EscapeHTML( PrintZoneConnection( ZONE_CONNECTION::FULL ) ) ) )
688 constraint.m_ZoneConnection = ZONE_CONNECTION::FULL;
689 }
690 }
691
692 return constraint;
693}
694
695
697 const BOARD_ITEM* b, PCB_LAYER_ID aLayer,
698 REPORTER* aReporter )
699{
700 /*
701 * NOTE: all string manipulation MUST BE KEPT INSIDE the REPORT macro. It absolutely
702 * kills performance when running bulk DRC tests (where aReporter is nullptr).
703 */
704
705 const BOARD_CONNECTED_ITEM* ac = a && a->IsConnected() ?
706 static_cast<const BOARD_CONNECTED_ITEM*>( a ) : nullptr;
707 const BOARD_CONNECTED_ITEM* bc = b && b->IsConnected() ?
708 static_cast<const BOARD_CONNECTED_ITEM*>( b ) : nullptr;
709
710 bool a_is_non_copper = a && ( !a->IsOnCopperLayer() || isKeepoutZone( a, false ) );
711 bool b_is_non_copper = b && ( !b->IsOnCopperLayer() || isKeepoutZone( b, false ) );
712
713 const PAD* pad = nullptr;
714 const ZONE* zone = nullptr;
715 const FOOTPRINT* parentFootprint = nullptr;
716
717 if( aConstraintType == ZONE_CONNECTION_CONSTRAINT
718 || aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT
719 || aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT )
720 {
721 if( a && a->Type() == PCB_PAD_T )
722 pad = static_cast<const PAD*>( a );
723 else if( a && a->Type() == PCB_ZONE_T )
724 zone = static_cast<const ZONE*>( a );
725
726 if( b && b->Type() == PCB_PAD_T )
727 pad = static_cast<const PAD*>( b );
728 else if( b && b->Type() == PCB_ZONE_T )
729 zone = static_cast<const ZONE*>( b );
730
731 if( pad )
732 parentFootprint = pad->GetParentFootprint();
733 }
734
735 DRC_CONSTRAINT constraint;
736 constraint.m_Type = aConstraintType;
737
738 auto applyConstraint =
739 [&]( const DRC_ENGINE_CONSTRAINT* c )
740 {
741 if( c->constraint.m_Value.HasMin() )
742 {
743 if( c->parentRule && c->parentRule->m_Implicit )
744 constraint.m_ImplicitMin = true;
745
746 constraint.m_Value.SetMin( c->constraint.m_Value.Min() );
747 }
748
749 if( c->constraint.m_Value.HasOpt() )
750 constraint.m_Value.SetOpt( c->constraint.m_Value.Opt() );
751
752 if( c->constraint.m_Value.HasMax() )
753 constraint .m_Value.SetMax( c->constraint.m_Value.Max() );
754
755 // While the expectation would be to OR the disallow flags, we've already
756 // masked them down to aItem's type -- so we're really only looking for a
757 // boolean here.
758 constraint.m_DisallowFlags = c->constraint.m_DisallowFlags;
759
760 constraint.m_ZoneConnection = c->constraint.m_ZoneConnection;
761
762 constraint.SetParentRule( c->constraint.GetParentRule() );
763 };
764
765 // Handle Footprint net ties, which will zero out the clearance for footprint objects
766 if( aConstraintType == CLEARANCE_CONSTRAINT && ( ac || bc ) && !a_is_non_copper && !b_is_non_copper )
767 {
768 const FOOTPRINT* footprints[2] = {a ? a->GetParentFootprint() : nullptr,
769 b ? b->GetParentFootprint() : nullptr};
770 const BOARD_ITEM* child_items[2] = {a, b};
771
772 // These are the items being compared against, so the order is reversed
773 const BOARD_CONNECTED_ITEM* alt_items[2] = {bc, ac};
774
775 for( int ii = 0; ii < 2; ++ii )
776 {
777 // We need both a footprint item and a connected item to check for a net tie
778 if( !footprints[ii] || !alt_items[ii] )
779 continue;
780
781 const std::set<int>& netcodes = footprints[ii]->GetNetTieCache( child_items[ii] );
782
783 auto it = netcodes.find( alt_items[ii]->GetNetCode() );
784
785 if( it != netcodes.end() )
786 {
787 REPORT( "" )
788 REPORT( wxString::Format( _( "Net tie on %s; clearance: 0." ),
789 EscapeHTML( footprints[ii]->GetItemDescription( this, true ) ) ) )
790
791 constraint.SetName( _( "net tie" ) );
792 constraint.m_Value.SetMin( 0 );
793 return constraint;
794 }
795 }
796 }
797
798 // Local overrides take precedence over everything *except* board min clearance
799 if( aConstraintType == CLEARANCE_CONSTRAINT || aConstraintType == HOLE_CLEARANCE_CONSTRAINT )
800 {
801 int override_val = 0;
802 std::optional<int> overrideA;
803 std::optional<int> overrideB;
804
805 if( ac && !b_is_non_copper )
806 overrideA = ac->GetClearanceOverrides( nullptr );
807
808 if( bc && !a_is_non_copper )
809 overrideB = bc->GetClearanceOverrides( nullptr );
810
811 if( overrideA.has_value() || overrideB.has_value() )
812 {
813 wxString msg;
814
815 if( overrideA.has_value() )
816 {
817 REPORT( "" )
818 REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
819 EscapeHTML( a->GetItemDescription( this, true ) ),
820 MessageTextFromValue( overrideA.value() ) ) )
821
822 override_val = ac->GetClearanceOverrides( &msg ).value();
823 }
824
825 if( overrideB.has_value() )
826 {
827 REPORT( "" )
828 REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
829 EscapeHTML( b->GetItemDescription( this, true ) ),
830 EscapeHTML( MessageTextFromValue( overrideB.value() ) ) ) )
831
832 if( overrideB > override_val )
833 override_val = bc->GetClearanceOverrides( &msg ).value();
834 }
835
836 if( override_val )
837 {
838 if( aConstraintType == CLEARANCE_CONSTRAINT )
839 {
840 if( override_val < m_designSettings->m_MinClearance )
841 {
842 override_val = m_designSettings->m_MinClearance;
843 msg = _( "board minimum" );
844
845 REPORT( "" )
846 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
847 MessageTextFromValue( override_val ) ) )
848 }
849 }
850 else
851 {
852 if( override_val < m_designSettings->m_HoleClearance )
853 {
854 override_val = m_designSettings->m_HoleClearance;
855 msg = _( "board minimum hole" );
856
857 REPORT( "" )
858 REPORT( wxString::Format( _( "Board minimum hole clearance: %s." ),
859 MessageTextFromValue( override_val ) ) )
860 }
861 }
862
863 constraint.SetName( msg );
864 constraint.m_Value.SetMin( override_val );
865 return constraint;
866 }
867 }
868 }
869 else if( aConstraintType == ZONE_CONNECTION_CONSTRAINT )
870 {
871 if( pad && pad->GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED )
872 {
873 wxString msg;
874 ZONE_CONNECTION override = pad->GetZoneConnectionOverrides( &msg );
875
876 REPORT( "" )
877 REPORT( wxString::Format( _( "Local override on %s; zone connection: %s." ),
878 EscapeHTML( pad->GetItemDescription( this, true ) ),
879 EscapeHTML( PrintZoneConnection( override ) ) ) )
880
881 constraint.SetName( msg );
882 constraint.m_ZoneConnection = override;
883 return constraint;
884 }
885 }
886 else if( aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT )
887 {
888 if( pad && pad->GetLocalThermalGapOverride( nullptr ) > 0 )
889 {
890 wxString msg;
891 int gap_override = pad->GetLocalThermalGapOverride( &msg );
892
893 REPORT( "" )
894 REPORT( wxString::Format( _( "Local override on %s; thermal relief gap: %s." ),
895 EscapeHTML( pad->GetItemDescription( this, true ) ),
896 EscapeHTML( MessageTextFromValue( gap_override ) ) ) )
897
898 constraint.SetName( msg );
899 constraint.m_Value.SetMin( gap_override );
900 return constraint;
901 }
902 }
903 else if( aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT )
904 {
905 if( pad && pad->GetLocalSpokeWidthOverride( nullptr ) > 0 )
906 {
907 wxString msg;
908 int spoke_override = pad->GetLocalSpokeWidthOverride( &msg );
909
910 REPORT( "" )
911 REPORT( wxString::Format( _( "Local override on %s; thermal spoke width: %s." ),
912 EscapeHTML( pad->GetItemDescription( this, true ) ),
913 EscapeHTML( MessageTextFromValue( spoke_override ) ) ) )
914
915 if( zone && zone->GetMinThickness() > spoke_override )
916 {
917 spoke_override = zone->GetMinThickness();
918
919 REPORT( "" )
920 REPORT( wxString::Format( _( "%s min thickness: %s." ),
921 EscapeHTML( zone->GetItemDescription( this, true ) ),
922 EscapeHTML( MessageTextFromValue( spoke_override ) ) ) )
923 }
924
925 constraint.SetName( msg );
926 constraint.m_Value.SetMin( spoke_override );
927 return constraint;
928 }
929 }
930
931 auto testAssertion =
932 [&]( const DRC_ENGINE_CONSTRAINT* c )
933 {
934 REPORT( wxString::Format( _( "Checking assertion \"%s\"." ),
935 EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
936
937 if( c->constraint.m_Test->EvaluateFor( a, b, c->constraint.m_Type, aLayer,
938 aReporter ) )
939 {
940 REPORT( _( "Assertion passed." ) )
941 }
942 else
943 {
944 REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
945 }
946 };
947
948 auto processConstraint =
949 [&]( const DRC_ENGINE_CONSTRAINT* c )
950 {
951 bool implicit = c->parentRule && c->parentRule->m_Implicit;
952
953 REPORT( "" )
954
955 switch( c->constraint.m_Type )
956 {
964 REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
965 EscapeHTML( c->constraint.GetName() ),
966 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
967 break;
969 REPORT( wxString::Format( _( "Checking %s creepage: %s." ),
970 EscapeHTML( c->constraint.GetName() ),
971 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
972 break;
974 REPORT( wxString::Format( _( "Checking %s max uncoupled length: %s." ),
975 EscapeHTML( c->constraint.GetName() ),
976 MessageTextFromValue( c->constraint.m_Value.Max() ) ) )
977 break;
978
979 case SKEW_CONSTRAINT:
980 REPORT( wxString::Format( _( "Checking %s max skew: %s." ),
981 EscapeHTML( c->constraint.GetName() ),
982 MessageTextFromValue( c->constraint.m_Value.Max() ) ) )
983 break;
984
986 REPORT( wxString::Format( _( "Checking %s gap: %s." ),
987 EscapeHTML( c->constraint.GetName() ),
988 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
989 break;
990
992 REPORT( wxString::Format( _( "Checking %s thermal spoke width: %s." ),
993 EscapeHTML( c->constraint.GetName() ),
994 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
995 break;
996
998 REPORT( wxString::Format( _( "Checking %s min spoke count: %s." ),
999 EscapeHTML( c->constraint.GetName() ),
1001 c->constraint.m_Value.Min() ) ) )
1002 break;
1003
1005 REPORT( wxString::Format( _( "Checking %s zone connection: %s." ),
1006 EscapeHTML( c->constraint.GetName() ),
1007 EscapeHTML( PrintZoneConnection( c->constraint.m_ZoneConnection ) ) ) )
1008 break;
1009
1017 case LENGTH_CONSTRAINT:
1020 {
1021 if( aReporter )
1022 {
1023 wxString min = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
1024 wxString opt = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
1025 wxString max = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
1026
1027 if( implicit )
1028 {
1029 min = MessageTextFromValue( c->constraint.m_Value.Min() );
1030 opt = MessageTextFromValue( c->constraint.m_Value.Opt() );
1031
1032 switch( c->constraint.m_Type )
1033 {
1035 if( c->constraint.m_Value.HasOpt() )
1036 {
1037 REPORT( wxString::Format( _( "Checking %s track width: opt %s." ),
1038 EscapeHTML( c->constraint.GetName() ),
1039 opt ) )
1040 }
1041 else if( c->constraint.m_Value.HasMin() )
1042 {
1043 REPORT( wxString::Format( _( "Checking %s track width: min %s." ),
1044 EscapeHTML( c->constraint.GetName() ),
1045 min ) )
1046 }
1047
1048 break;
1049
1051 REPORT( wxString::Format( _( "Checking %s annular width: min %s." ),
1052 EscapeHTML( c->constraint.GetName() ),
1053 opt ) )
1054 break;
1055
1057 if( c->constraint.m_Value.HasOpt() )
1058 {
1059 REPORT( wxString::Format( _( "Checking %s via diameter: opt %s." ),
1060 EscapeHTML( c->constraint.GetName() ),
1061 opt ) )
1062 }
1063 else if( c->constraint.m_Value.HasMin() )
1064 {
1065 REPORT( wxString::Format( _( "Checking %s via diameter: min %s." ),
1066 EscapeHTML( c->constraint.GetName() ),
1067 min ) )
1068 }
1069 break;
1070
1072 if( c->constraint.m_Value.HasOpt() )
1073 {
1074 REPORT( wxString::Format( _( "Checking %s hole size: opt %s." ),
1075 EscapeHTML( c->constraint.GetName() ),
1076 opt ) )
1077 }
1078 else if( c->constraint.m_Value.HasMin() )
1079 {
1080 REPORT( wxString::Format( _( "Checking %s hole size: min %s." ),
1081 EscapeHTML( c->constraint.GetName() ),
1082 min ) )
1083 }
1084
1085 break;
1086
1090 REPORT( wxString::Format( _( "Checking %s: min %s." ),
1091 EscapeHTML( c->constraint.GetName() ),
1092 min ) )
1093 break;
1094
1096 if( c->constraint.m_Value.HasOpt() )
1097 {
1098 REPORT( wxString::Format( _( "Checking %s diff pair gap: opt %s." ),
1099 EscapeHTML( c->constraint.GetName() ),
1100 opt ) )
1101 }
1102 else if( c->constraint.m_Value.HasMin() )
1103 {
1104 REPORT( wxString::Format( _( "Checking %s clearance: min %s." ),
1105 EscapeHTML( c->constraint.GetName() ),
1106 min ) )
1107 }
1108
1109 break;
1110
1112 REPORT( wxString::Format( _( "Checking %s hole to hole: min %s." ),
1113 EscapeHTML( c->constraint.GetName() ),
1114 min ) )
1115 break;
1116
1117 default:
1118 REPORT( wxString::Format( _( "Checking %s." ),
1119 EscapeHTML( c->constraint.GetName() ) ) )
1120 }
1121 }
1122 else
1123 {
1124 if( c->constraint.m_Value.HasMin() )
1125 min = MessageTextFromValue( c->constraint.m_Value.Min() );
1126
1127 if( c->constraint.m_Value.HasOpt() )
1128 opt = MessageTextFromValue( c->constraint.m_Value.Opt() );
1129
1130 if( c->constraint.m_Value.HasMax() )
1131 max = MessageTextFromValue( c->constraint.m_Value.Max() );
1132
1133 REPORT( wxString::Format( _( "Checking %s: min %s; opt %s; max %s." ),
1134 EscapeHTML( c->constraint.GetName() ),
1135 min,
1136 opt,
1137 max ) )
1138 }
1139 }
1140 break;
1141 }
1142
1143 default:
1144 REPORT( wxString::Format( _( "Checking %s." ),
1145 EscapeHTML( c->constraint.GetName() ) ) )
1146 }
1147
1148 if( c->constraint.m_Type == CLEARANCE_CONSTRAINT )
1149 {
1150 if( a_is_non_copper || b_is_non_copper )
1151 {
1152 if( implicit )
1153 {
1154 REPORT( _( "Netclass clearances apply only between copper items." ) )
1155 }
1156 else if( a_is_non_copper )
1157 {
1158 REPORT( wxString::Format( _( "%s contains no copper. Rule ignored." ),
1159 EscapeHTML( a->GetItemDescription( this, true ) ) ) )
1160 }
1161 else if( b_is_non_copper )
1162 {
1163 REPORT( wxString::Format( _( "%s contains no copper. Rule ignored." ),
1164 EscapeHTML( b->GetItemDescription( this, true ) ) ) )
1165 }
1166
1167 return;
1168 }
1169 }
1170 else if( c->constraint.m_Type == DISALLOW_CONSTRAINT )
1171 {
1172 int mask;
1173
1174 if( a->GetFlags() & HOLE_PROXY )
1175 {
1176 mask = DRC_DISALLOW_HOLES;
1177 }
1178 else if( a->Type() == PCB_VIA_T )
1179 {
1180 mask = DRC_DISALLOW_VIAS;
1181
1182 switch( static_cast<const PCB_VIA*>( a )->GetViaType() )
1183 {
1184 case VIATYPE::BLIND_BURIED: mask |= DRC_DISALLOW_BB_VIAS; break;
1185 case VIATYPE::MICROVIA: mask |= DRC_DISALLOW_MICRO_VIAS; break;
1186 default: break;
1187 }
1188 }
1189 else
1190 {
1191 switch( a->Type() )
1192 {
1193 case PCB_TRACE_T: mask = DRC_DISALLOW_TRACKS; break;
1194 case PCB_ARC_T: mask = DRC_DISALLOW_TRACKS; break;
1195 case PCB_PAD_T: mask = DRC_DISALLOW_PADS; break;
1196 case PCB_FOOTPRINT_T: mask = DRC_DISALLOW_FOOTPRINTS; break;
1197 case PCB_SHAPE_T: mask = DRC_DISALLOW_GRAPHICS; break;
1198 case PCB_FIELD_T: mask = DRC_DISALLOW_TEXTS; break;
1199 case PCB_TEXT_T: mask = DRC_DISALLOW_TEXTS; break;
1200 case PCB_TEXTBOX_T: mask = DRC_DISALLOW_TEXTS; break;
1201 case PCB_TABLE_T: mask = DRC_DISALLOW_TEXTS; break;
1202
1203 case PCB_ZONE_T:
1204 // Treat teardrop areas as tracks for DRC purposes
1205 if( static_cast<const ZONE*>( a )->IsTeardropArea() )
1206 mask = DRC_DISALLOW_TRACKS;
1207 else
1208 mask = DRC_DISALLOW_ZONES;
1209
1210 break;
1211
1212 case PCB_LOCATE_HOLE_T: mask = DRC_DISALLOW_HOLES; break;
1213 default: mask = 0; break;
1214 }
1215 }
1216
1217 if( ( c->constraint.m_DisallowFlags & mask ) == 0 )
1218 {
1219 if( implicit )
1220 REPORT( _( "Keepout constraint not met." ) )
1221 else
1222 REPORT( _( "Disallow constraint not met." ) )
1223
1224 return;
1225 }
1226
1227 LSET itemLayers = a->GetLayerSet();
1228
1229 if( a->Type() == PCB_FOOTPRINT_T )
1230 {
1231 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( a );
1232
1233 if( !footprint->GetCourtyard( F_CrtYd ).IsEmpty() )
1234 itemLayers |= LSET::FrontMask();
1235
1236 if( !footprint->GetCourtyard( B_CrtYd ).IsEmpty() )
1237 itemLayers |= LSET::BackMask();
1238 }
1239
1240 if( !( c->layerTest & itemLayers ).any() )
1241 {
1242 if( implicit )
1243 {
1244 REPORT( _( "Keepout layer(s) not matched." ) )
1245 }
1246 else if( c->parentRule )
1247 {
1248 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1249 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1250 }
1251 else
1252 {
1253 REPORT( _( "Rule layer not matched; rule ignored." ) )
1254 }
1255
1256 return;
1257 }
1258 }
1259
1260 if( ( aLayer != UNDEFINED_LAYER && !c->layerTest.test( aLayer ) )
1261 || ( m_board->GetEnabledLayers() & c->layerTest ).count() == 0 )
1262 {
1263 if( implicit )
1264 {
1265 REPORT( _( "Constraint layer not matched." ) )
1266 }
1267 else if( c->parentRule )
1268 {
1269 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1270 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1271 }
1272 else
1273 {
1274 REPORT( _( "Rule layer not matched; rule ignored." ) )
1275 }
1276 }
1277 else if( c->constraint.m_Type == HOLE_TO_HOLE_CONSTRAINT
1278 && ( !a->HasDrilledHole() && !b->HasDrilledHole() ) )
1279 {
1280 // Report non-drilled-holes as an implicit condition
1281 REPORT( wxString::Format( _( "%s is not a drilled hole; rule ignored." ),
1282 a->GetItemDescription( this, true ) ) )
1283 }
1284 else if( !c->condition || c->condition->GetExpression().IsEmpty() )
1285 {
1286 if( aReporter )
1287 {
1288 if( implicit )
1289 {
1290 REPORT( _( "Unconditional constraint applied." ) )
1291 }
1292 else if( constraint.m_Type == ASSERTION_CONSTRAINT )
1293 {
1294 REPORT( _( "Unconditional rule applied." ) )
1295 testAssertion( c );
1296 }
1297 else
1298 {
1299 REPORT( _( "Unconditional rule applied; overrides previous constraints." ) )
1300 }
1301 }
1302
1303 applyConstraint( c );
1304 }
1305 else
1306 {
1307 if( implicit )
1308 {
1309 // Don't report on implicit rule conditions; they're synthetic.
1310 }
1311 else
1312 {
1313 REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
1314 EscapeHTML( c->condition->GetExpression() ) ) )
1315 }
1316
1317 if( c->condition->EvaluateFor( a, b, c->constraint.m_Type, aLayer, aReporter ) )
1318 {
1319 if( aReporter )
1320 {
1321 if( implicit )
1322 {
1323 REPORT( _( "Constraint applied." ) )
1324 }
1325 else if( constraint.m_Type == ASSERTION_CONSTRAINT )
1326 {
1327 REPORT( _( "Rule applied." ) )
1328 testAssertion( c );
1329 }
1330 else
1331 {
1332 REPORT( _( "Rule applied; overrides previous constraints." ) )
1333 }
1334 }
1335
1336 applyConstraint( c );
1337 }
1338 else
1339 {
1340 REPORT( implicit ? _( "Membership not satisfied; constraint ignored." )
1341 : _( "Condition not satisfied; rule ignored." ) )
1342 }
1343 }
1344 };
1345
1346 if( m_constraintMap.count( aConstraintType ) )
1347 {
1348 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
1349
1350 for( int ii = 0; ii < (int) ruleset->size(); ++ii )
1351 processConstraint( ruleset->at( ii ) );
1352 }
1353
1354 if( constraint.GetParentRule() && !constraint.GetParentRule()->m_Implicit )
1355 return constraint;
1356
1357 // Special case for pad zone connections which can iherit from their parent footprints.
1358 // We've already checked for local overrides, and there were no rules targetting the pad
1359 // itself, so we know we're inheriting and need to see if there are any rules targetting
1360 // the parent footprint.
1361 if( pad && parentFootprint && ( aConstraintType == ZONE_CONNECTION_CONSTRAINT
1362 || aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT
1363 || aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT ) )
1364 {
1365 if( a == pad )
1366 a = parentFootprint;
1367 else
1368 b = parentFootprint;
1369
1370 if( m_constraintMap.count( aConstraintType ) )
1371 {
1372 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
1373
1374 for( int ii = 0; ii < (int) ruleset->size(); ++ii )
1375 processConstraint( ruleset->at( ii ) );
1376
1377 if( constraint.GetParentRule() && !constraint.GetParentRule()->m_Implicit )
1378 return constraint;
1379 }
1380 }
1381
1382 // Unfortunately implicit rules don't work for local clearances (such as zones) because
1383 // they have to be max'ed with netclass values (which are already implicit rules), and our
1384 // rule selection paradigm is "winner takes all".
1385 if( aConstraintType == CLEARANCE_CONSTRAINT )
1386 {
1387 int global = constraint.m_Value.Min();
1388 int clearance = global;
1389 bool needBlankLine = true;
1390
1391 if( ac && ac->GetLocalClearance().has_value() )
1392 {
1393 int localA = ac->GetLocalClearance().value();
1394
1395 if( needBlankLine )
1396 {
1397 REPORT( "" )
1398 needBlankLine = false;
1399 }
1400
1401 REPORT( wxString::Format( _( "Local clearance on %s: %s." ),
1402 EscapeHTML( a->GetItemDescription( this, true ) ),
1403 MessageTextFromValue( localA ) ) )
1404
1405 if( localA > clearance )
1406 {
1407 wxString msg;
1408 clearance = ac->GetLocalClearance( &msg ).value();
1409 constraint.SetParentRule( nullptr );
1410 constraint.SetName( msg );
1411 constraint.m_Value.SetMin( clearance );
1412 }
1413 }
1414
1415 if( bc && bc->GetLocalClearance().has_value() )
1416 {
1417 int localB = bc->GetLocalClearance().value();
1418
1419 if( needBlankLine )
1420 {
1421 REPORT( "" )
1422 needBlankLine = false;
1423 }
1424
1425 REPORT( wxString::Format( _( "Local clearance on %s: %s." ),
1426 EscapeHTML( b->GetItemDescription( this, true ) ),
1427 MessageTextFromValue( localB ) ) )
1428
1429 if( localB > clearance )
1430 {
1431 wxString msg;
1432 clearance = bc->GetLocalClearance( &msg ).value();
1433 constraint.SetParentRule( nullptr );
1434 constraint.SetName( msg );
1435 constraint.m_Value.SetMin( clearance );
1436 }
1437 }
1438
1439 if( !a_is_non_copper && !b_is_non_copper )
1440 {
1441 if( needBlankLine )
1442 {
1443 REPORT( "" )
1444 needBlankLine = false;
1445 }
1446
1447 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
1449
1450 if( clearance < m_designSettings->m_MinClearance )
1451 {
1452 constraint.SetParentRule( nullptr );
1453 constraint.SetName( _( "board minimum" ) );
1455 }
1456 }
1457
1458 return constraint;
1459 }
1460 else if( aConstraintType == DIFF_PAIR_GAP_CONSTRAINT )
1461 {
1462 REPORT( "" )
1463 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
1465
1466 if( constraint.m_Value.Min() < m_designSettings->m_MinClearance )
1467 {
1468 constraint.SetParentRule( nullptr );
1469 constraint.SetName( _( "board minimum" ) );
1471 }
1472
1473 return constraint;
1474 }
1475 else if( aConstraintType == ZONE_CONNECTION_CONSTRAINT )
1476 {
1477 if( pad && parentFootprint )
1478 {
1479 ZONE_CONNECTION local = parentFootprint->GetLocalZoneConnection();
1480
1481 if( local != ZONE_CONNECTION::INHERITED )
1482 {
1483 REPORT( "" )
1484 REPORT( wxString::Format( _( "%s zone connection: %s." ),
1485 EscapeHTML( parentFootprint->GetItemDescription( this, true ) ),
1486 EscapeHTML( PrintZoneConnection( local ) ) ) )
1487
1488 constraint.SetParentRule( nullptr );
1489 constraint.SetName( _( "footprint" ) );
1490 constraint.m_ZoneConnection = local;
1491 return constraint;
1492 }
1493 }
1494
1495 if( zone )
1496 {
1497 ZONE_CONNECTION local = zone->GetPadConnection();
1498
1499 REPORT( "" )
1500 REPORT( wxString::Format( _( "%s pad connection: %s." ),
1501 EscapeHTML( zone->GetItemDescription( this, true ) ),
1502 EscapeHTML( PrintZoneConnection( local ) ) ) )
1503
1504 constraint.SetParentRule( nullptr );
1505 constraint.SetName( _( "zone" ) );
1506 constraint.m_ZoneConnection = local;
1507 return constraint;
1508 }
1509 }
1510 else if( aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT )
1511 {
1512 if( zone )
1513 {
1514 int local = zone->GetThermalReliefGap();
1515
1516 REPORT( "" )
1517 REPORT( wxString::Format( _( "%s thermal relief gap: %s." ),
1518 EscapeHTML( zone->GetItemDescription( this, true ) ),
1519 EscapeHTML( MessageTextFromValue( local ) ) ) )
1520
1521 constraint.SetParentRule( nullptr );
1522 constraint.SetName( _( "zone" ) );
1523 constraint.m_Value.SetMin( local );
1524 return constraint;
1525 }
1526 }
1527 else if( aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT )
1528 {
1529 if( zone )
1530 {
1531 int local = zone->GetThermalReliefSpokeWidth();
1532
1533 REPORT( "" )
1534 REPORT( wxString::Format( _( "%s thermal spoke width: %s." ),
1535 EscapeHTML( zone->GetItemDescription( this, true ) ),
1536 EscapeHTML( MessageTextFromValue( local ) ) ) )
1537
1538 constraint.SetParentRule( nullptr );
1539 constraint.SetName( _( "zone" ) );
1540 constraint.m_Value.SetMin( local );
1541 return constraint;
1542 }
1543 }
1544
1545 if( !constraint.GetParentRule() )
1546 {
1547 constraint.m_Type = NULL_CONSTRAINT;
1548 constraint.m_DisallowFlags = 0;
1549 }
1550
1551 return constraint;
1552}
1553
1554
1556 std::function<void( const DRC_CONSTRAINT* )> aFailureHandler,
1557 REPORTER* aReporter )
1558{
1559 /*
1560 * NOTE: all string manipulation MUST BE KEPT INSIDE the REPORT macro. It absolutely
1561 * kills performance when running bulk DRC tests (where aReporter is nullptr).
1562 */
1563
1564 auto testAssertion =
1565 [&]( const DRC_ENGINE_CONSTRAINT* c )
1566 {
1567 REPORT( wxString::Format( _( "Checking rule assertion \"%s\"." ),
1568 EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
1569
1570 if( c->constraint.m_Test->EvaluateFor( a, nullptr, c->constraint.m_Type,
1571 a->GetLayer(), aReporter ) )
1572 {
1573 REPORT( _( "Assertion passed." ) )
1574 }
1575 else
1576 {
1577 REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
1578 aFailureHandler( &c->constraint );
1579 }
1580 };
1581
1582 auto processConstraint =
1583 [&]( const DRC_ENGINE_CONSTRAINT* c )
1584 {
1585 REPORT( "" )
1586 REPORT( wxString::Format( _( "Checking %s." ), c->constraint.GetName() ) )
1587
1588 if( !( a->GetLayerSet() & c->layerTest ).any() )
1589 {
1590 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1591 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1592 }
1593
1594 if( !c->condition || c->condition->GetExpression().IsEmpty() )
1595 {
1596 REPORT( _( "Unconditional rule applied." ) )
1597 testAssertion( c );
1598 }
1599 else
1600 {
1601 REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
1602 EscapeHTML( c->condition->GetExpression() ) ) )
1603
1604 if( c->condition->EvaluateFor( a, nullptr, c->constraint.m_Type,
1605 a->GetLayer(), aReporter ) )
1606 {
1607 REPORT( _( "Rule applied." ) )
1608 testAssertion( c );
1609 }
1610 else
1611 {
1612 REPORT( _( "Condition not satisfied; rule ignored." ) )
1613 }
1614 }
1615 };
1616
1618 {
1619 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ ASSERTION_CONSTRAINT ];
1620
1621 for( int ii = 0; ii < (int) ruleset->size(); ++ii )
1622 processConstraint( ruleset->at( ii ) );
1623 }
1624}
1625
1626
1627#undef REPORT
1628
1629
1631{
1632 assert( error_code >= 0 && error_code <= DRCE_LAST );
1633 return m_errorLimits[ error_code ] <= 0;
1634}
1635
1636
1637void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos,
1638 int aMarkerLayer )
1639{
1640 static std::mutex globalLock;
1641
1642 m_errorLimits[ aItem->GetErrorCode() ] -= 1;
1643
1644 if( m_violationHandler )
1645 {
1646 std::lock_guard<std::mutex> guard( globalLock );
1647 m_violationHandler( aItem, aPos, aMarkerLayer );
1648 }
1649
1650 if( m_reporter )
1651 {
1652 wxString msg = wxString::Format( wxT( "Test '%s': %s (code %d)" ),
1653 aItem->GetViolatingTest()->GetName(),
1654 aItem->GetErrorMessage(),
1655 aItem->GetErrorCode() );
1656
1657 DRC_RULE* rule = aItem->GetViolatingRule();
1658
1659 if( rule )
1660 msg += wxString::Format( wxT( ", violating rule: '%s'" ), rule->m_Name );
1661
1662 m_reporter->Report( msg );
1663
1664 wxString violatingItemsStr = wxT( "Violating items: " );
1665
1666 m_reporter->Report( wxString::Format( wxT( " |- violating position (%d, %d)" ),
1667 aPos.x,
1668 aPos.y ) );
1669 }
1670}
1671
1672
1673void DRC_ENGINE::ReportAux ( const wxString& aStr )
1674{
1675 if( !m_reporter )
1676 return;
1677
1679}
1680
1681
1683{
1684 if( !m_progressReporter )
1685 return true;
1686
1687 return m_progressReporter->KeepRefreshing( aWait );
1688}
1689
1690
1692{
1693 if( m_progressReporter )
1695}
1696
1697
1699{
1700 if( m_progressReporter )
1702}
1703
1704
1705bool DRC_ENGINE::ReportProgress( double aProgress )
1706{
1707 if( !m_progressReporter )
1708 return true;
1709
1711 return m_progressReporter->KeepRefreshing( false );
1712}
1713
1714
1715bool DRC_ENGINE::ReportPhase( const wxString& aMessage )
1716{
1717 if( !m_progressReporter )
1718 return true;
1719
1720 m_progressReporter->AdvancePhase( aMessage );
1721 return m_progressReporter->KeepRefreshing( false );
1722}
1723
1724
1726{
1728}
1729
1730
1732{
1733 //drc_dbg(10,"hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size( ) );
1734 if( m_constraintMap.count( constraintID ) )
1735 return m_constraintMap[ constraintID ]->size() > 0;
1736
1737 return false;
1738}
1739
1740
1742{
1743 int worst = 0;
1744
1745 if( m_constraintMap.count( aConstraintId ) )
1746 {
1747 for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
1748 {
1749 int current = c->constraint.GetValue().Min();
1750
1751 if( current > worst )
1752 {
1753 worst = current;
1754 aConstraint = c->constraint;
1755 }
1756 }
1757 }
1758
1759 return worst > 0;
1760}
1761
1762
1764{
1765 std::set<int> distinctMinimums;
1766
1767 if( m_constraintMap.count( aConstraintId ) )
1768 {
1769 for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
1770 distinctMinimums.emplace( c->constraint.GetValue().Min() );
1771 }
1772
1773 return distinctMinimums;
1774}
1775
1776
1777// fixme: move two functions below to pcbcommon?
1778int DRC_ENGINE::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet,
1779 wxString& aBaseDpName )
1780{
1781 int rv = 0;
1782 int count = 0;
1783
1784 for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
1785 {
1786 int ch = *it;
1787
1788 if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
1789 {
1790 continue;
1791 }
1792 else if( ch == '+' )
1793 {
1794 aComplementNet = wxT( "-" );
1795 rv = 1;
1796 }
1797 else if( ch == '-' )
1798 {
1799 aComplementNet = wxT( "+" );
1800 rv = -1;
1801 }
1802 else if( ch == 'N' )
1803 {
1804 aComplementNet = wxT( "P" );
1805 rv = -1;
1806 }
1807 else if ( ch == 'P' )
1808 {
1809 aComplementNet = wxT( "N" );
1810 rv = 1;
1811 }
1812 else
1813 {
1814 break;
1815 }
1816 }
1817
1818 if( rv != 0 && count >= 1 )
1819 {
1820 aBaseDpName = aNetName.Left( aNetName.Length() - count );
1821 aComplementNet = wxString( aBaseDpName ) << aComplementNet << aNetName.Right( count - 1 );
1822 }
1823
1824 return rv;
1825}
1826
1827
1828bool DRC_ENGINE::IsNetADiffPair( BOARD* aBoard, NETINFO_ITEM* aNet, int& aNetP, int& aNetN )
1829{
1830 wxString refName = aNet->GetNetname();
1831 wxString dummy, coupledNetName;
1832
1833 if( int polarity = MatchDpSuffix( refName, coupledNetName, dummy ) )
1834 {
1835 NETINFO_ITEM* net = aBoard->FindNet( coupledNetName );
1836
1837 if( !net )
1838 return false;
1839
1840 if( polarity > 0 )
1841 {
1842 aNetP = aNet->GetNetCode();
1843 aNetN = net->GetNetCode();
1844 }
1845 else
1846 {
1847 aNetP = net->GetNetCode();
1848 aNetN = aNet->GetNetCode();
1849 }
1850
1851 return true;
1852 }
1853
1854 return false;
1855}
1856
1857
1862bool DRC_ENGINE::IsNetTieExclusion( int aTrackNetCode, PCB_LAYER_ID aTrackLayer,
1863 const VECTOR2I& aCollisionPos, BOARD_ITEM* aCollidingItem )
1864{
1865 FOOTPRINT* parentFootprint = aCollidingItem->GetParentFootprint();
1866
1867 if( parentFootprint && parentFootprint->IsNetTie() )
1868 {
1870 std::map<wxString, int> padToNetTieGroupMap = parentFootprint->MapPadNumbersToNetTieGroups();
1871
1872 for( PAD* pad : parentFootprint->Pads() )
1873 {
1874 if( padToNetTieGroupMap[ pad->GetNumber() ] >= 0 && aTrackNetCode == pad->GetNetCode() )
1875 {
1876 if( pad->GetEffectiveShape( aTrackLayer )->Collide( aCollisionPos, epsilon ) )
1877 return true;
1878 }
1879 }
1880 }
1881
1882 return false;
1883}
1884
1885
1887{
1888 for( DRC_TEST_PROVIDER* prov : m_testProviders )
1889 {
1890 if( name == prov->GetName() )
1891 return prov;
1892 }
1893
1894 return nullptr;
1895}
const char * name
Definition: DXF_plotter.cpp:57
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
constexpr EDA_IU_SCALE unityScale
Definition: base_units.h:111
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
bool Ignore(int aDRCErrorCode)
Return true if the DRC error code's severity is SEVERITY_IGNORE.
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:237
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:133
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:298
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:257
virtual bool HasDrilledHole() const
Definition: board_item.h:160
virtual bool IsOnCopperLayer() const
Definition: board_item.h:150
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:290
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:778
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1922
const ZONES & Zones() const
Definition: board.h:335
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition: board.cpp:2055
void IncrementTimeStamp()
Definition: board.cpp:255
const FOOTPRINTS & Footprints() const
Definition: board.h:331
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:895
int GetTimeStamp() const
Definition: board.h:313
virtual bool Run() override
Run this provider against the given PCB with configured options (if any).
int m_DisallowFlags
Definition: drc_rule.h:191
void SetParentRule(DRC_RULE *aParentRule)
Definition: drc_rule.h:155
MINOPTMAX< int > & Value()
Definition: drc_rule.h:153
ZONE_CONNECTION m_ZoneConnection
Definition: drc_rule.h:192
void SetName(const wxString &aName)
Definition: drc_rule.h:158
MINOPTMAX< int > m_Value
Definition: drc_rule.h:190
DRC_CONSTRAINT_T m_Type
Definition: drc_rule.h:189
DRC_RULE * GetParentRule() const
Definition: drc_rule.h:156
bool m_ImplicitMin
Definition: drc_rule.h:194
std::map< DRC_CONSTRAINT_T, std::vector< DRC_ENGINE_CONSTRAINT * > * > m_constraintMap
Definition: drc_engine.h:273
REPORTER * m_reporter
Definition: drc_engine.h:278
void AdvanceProgress()
void ClearGraphicsHandler()
Definition: drc_engine.h:139
void RunTests(EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints, BOARD_COMMIT *aCommit=nullptr)
Run the DRC tests.
Definition: drc_engine.cpp:610
bool m_testFootprints
Definition: drc_engine.h:270
void addRule(std::shared_ptr< DRC_RULE > &rule)
Definition: drc_engine.h:233
PROGRESS_REPORTER * m_progressReporter
Definition: drc_engine.h:279
void loadRules(const wxFileName &aPath)
Load and parse a rule set from an sexpr text file.
Definition: drc_engine.cpp:503
std::vector< DRC_TEST_PROVIDER * > m_testProviders
Definition: drc_engine.h:266
void compileRules()
Definition: drc_engine.cpp:526
std::set< int > QueryDistinctConstraints(DRC_CONSTRAINT_T aConstraintId)
bool KeepRefreshing(bool aWait=false)
BOARD * m_board
Definition: drc_engine.h:260
bool m_reportAllTrackErrors
Definition: drc_engine.h:269
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:102
void ReportViolation(const std::shared_ptr< DRC_ITEM > &aItem, const VECTOR2I &aPos, int aMarkerLayer)
void SetMaxProgress(int aSize)
void ReportAux(const wxString &aStr)
DRC_ENGINE(BOARD *aBoard=nullptr, BOARD_DESIGN_SETTINGS *aSettings=nullptr)
Definition: drc_engine.cpp:78
std::vector< int > m_errorLimits
Definition: drc_engine.h:268
bool IsErrorLimitExceeded(int error_code)
void ProcessAssertions(const BOARD_ITEM *a, std::function< void(const DRC_CONSTRAINT *)> aFailureHandler, REPORTER *aReporter=nullptr)
void loadImplicitRules()
Definition: drc_engine.cpp:155
DRC_VIOLATION_HANDLER m_violationHandler
Definition: drc_engine.h:277
DRC_CONSTRAINT EvalRules(DRC_CONSTRAINT_T aConstraintType, const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
Definition: drc_engine.cpp:696
std::vector< std::shared_ptr< DRC_RULE > > m_rules
Definition: drc_engine.h:264
std::shared_ptr< DRC_RULE > createImplicitRule(const wxString &name)
Definition: drc_engine.cpp:142
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()
Definition: drc_engine.cpp:99
bool QueryWorstConstraint(DRC_CONSTRAINT_T aRuleId, DRC_CONSTRAINT &aConstraint)
void InitEngine(const wxFileName &aRulePath)
Initialize the DRC engine.
Definition: drc_engine.cpp:557
DRC_CONSTRAINT EvalZoneConnection(const BOARD_ITEM *a, const BOARD_ITEM *b, PCB_LAYER_ID aLayer, REPORTER *aReporter=nullptr)
Definition: drc_engine.cpp:662
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:265
BOARD_DESIGN_SETTINGS * m_designSettings
Definition: drc_engine.h:259
void Parse(std::vector< std::shared_ptr< DRC_RULE > > &aRules, REPORTER *aReporter)
bool Compile(REPORTER *aReporter, int aSourceLine=0, int aSourceOffset=0)
bool m_Implicit
Definition: drc_rule.h:115
wxString m_Name
Definition: drc_rule.h:117
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:111
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:130
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: footprint.h:288
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:3084
std::deque< PAD * > & Pads()
Definition: footprint.h:206
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:510
bool IsNetTie() const
Definition: footprint.h:297
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition: footprint.cpp:2058
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.cpp:2892
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
static LSET FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:782
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:789
T Min() const
Definition: minoptmax.h:33
void SetMin(T v)
Definition: minoptmax.h:41
void SetOpt(T v)
Definition: minoptmax.h:43
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
int GetNetCode() const
Definition: netinfo.h:108
Definition: pad.h:54
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
virtual bool IsCancelled() const =0
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
virtual void AdvanceProgress()=0
Increment the progress bar length (inside the current virtual zone).
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
virtual void SetMaxProgress(int aMaxProgress)=0
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:72
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
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:73
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition: zone.cpp:1051
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:724
bool GetDoNotAllowVias() const
Definition: zone.h:732
bool GetDoNotAllowPads() const
Definition: zone.h:734
bool GetDoNotAllowTracks() const
Definition: zone.h:733
int GetMinThickness() const
Definition: zone.h:273
ZONE_CONNECTION GetPadConnection() const
Definition: zone.h:270
int GetThermalReliefSpokeWidth() const
Definition: zone.h:217
bool GetDoNotAllowFootprints() const
Definition: zone.h:735
bool GetDoNotAllowCopperPour() const
Definition: zone.h:731
bool HasKeepoutParametersSet() const
Accessor to determine if any keepout parameters are set.
Definition: zone.h:715
int GetThermalReliefGap() const
Definition: zone.h:206
void drcPrintDebugMessage(int level, const wxString &msg, const char *function, int line)
Definition: drc_engine.cpp:64
#define EXTENDED_ERROR_LIMIT
Definition: drc_engine.cpp:51
static bool isKeepoutZone(const BOARD_ITEM *aItem, bool aCheckFlags)
Definition: drc_engine.cpp:113
#define ERROR_LIMIT
Definition: drc_engine.cpp:50
@ DRCE_UNCONNECTED_ITEMS
Definition: drc_item.h:39
@ DRCE_CLEARANCE
Definition: drc_item.h:43
@ DRCE_FIRST
Definition: drc_item.h:38
@ DRCE_LAST
Definition: drc_item.h:112
@ DRC_DISALLOW_PADS
Definition: drc_rule.h:88
@ DRC_DISALLOW_VIAS
Definition: drc_rule.h:84
@ DRC_DISALLOW_TEXTS
Definition: drc_rule.h:90
@ DRC_DISALLOW_ZONES
Definition: drc_rule.h:89
@ DRC_DISALLOW_HOLES
Definition: drc_rule.h:92
@ DRC_DISALLOW_GRAPHICS
Definition: drc_rule.h:91
@ DRC_DISALLOW_FOOTPRINTS
Definition: drc_rule.h:93
@ DRC_DISALLOW_TRACKS
Definition: drc_rule.h:87
@ DRC_DISALLOW_MICRO_VIAS
Definition: drc_rule.h:85
@ DRC_DISALLOW_BB_VIAS
Definition: drc_rule.h:86
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:67
@ ZONE_CONNECTION_CONSTRAINT
Definition: drc_rule.h:62
@ DIFF_PAIR_GAP_CONSTRAINT
Definition: drc_rule.h:70
@ DISALLOW_CONSTRAINT
Definition: drc_rule.h:66
@ 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:68
@ PHYSICAL_HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:75
@ 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:77
@ THERMAL_RELIEF_GAP_CONSTRAINT
Definition: drc_rule.h:63
@ MAX_UNCOUPLED_CONSTRAINT
Definition: drc_rule.h:71
@ ASSERTION_CONSTRAINT
Definition: drc_rule.h:76
@ SKEW_CONSTRAINT
Definition: drc_rule.h:69
@ HOLE_CLEARANCE_CONSTRAINT
Definition: drc_rule.h:51
@ 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:74
@ HOLE_TO_HOLE_CONSTRAINT
Definition: drc_rule.h:52
#define _(s)
#define HOLE_PROXY
Indicates the BOARD_ITEM is a proxy for its hole.
EDA_UNITS
Definition: eda_units.h:46
static const wxChar * traceDrcProfile
Flag to enable DRC profile timing logging.
Definition: drc_engine.cpp:61
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.
Definition: eda_units.cpp:408
@ RPT_SEVERITY_INFO
const double epsilon
std::vector< FAB_LAYER_COLOR > dummy
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
std::shared_ptr< DRC_RULE > parentRule
Definition: drc_engine.h:251
DRC_RULE_CONDITION * condition
Definition: drc_engine.h:250
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:120
@ 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:107
@ 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_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:127
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
wxString PrintZoneConnection(ZONE_CONNECTION aConnection)
Definition: zones.h:56
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:47