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