KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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, dick@softplc.com
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
780 const FOOTPRINT* footprints[2] = {a ? a->GetParentFootprint() : nullptr,
781 b ? b->GetParentFootprint() : nullptr};
782
783 // Handle Footprint net ties, which will zero out the clearance for footprint objects
784 if( aConstraintType == CLEARANCE_CONSTRAINT // Only zero clearance, other constraints still apply
785 && ( ( ( !ac ) ^ ( !bc ) )// Only apply to cases where we are comparing a connected item to a non-connected item
786 // and not both connected. Connected items of different nets still need to be checked
787 // for their standard clearance value
788 || ( ( footprints[0] == footprints[1] ) // Unless both items are in the same footprint
789 && footprints[0] ) ) // And that footprint exists
790 && !a_is_non_copper // Also, both elements need to be on copper layers
791 && !b_is_non_copper )
792 {
793 const BOARD_ITEM* child_items[2] = {a, b};
794
795 // These are the items being compared against, so the order is reversed
796 const BOARD_CONNECTED_ITEM* alt_items[2] = {bc, ac};
797
798 for( int ii = 0; ii < 2; ++ii )
799 {
800 // We need both a footprint item and a connected item to check for a net tie
801 if( !footprints[ii] || !alt_items[ii] )
802 continue;
803
804 const std::set<int>& netcodes = footprints[ii]->GetNetTieCache( child_items[ii] );
805
806 auto it = netcodes.find( alt_items[ii]->GetNetCode() );
807
808 if( it != netcodes.end() )
809 {
810 REPORT( "" )
811 REPORT( wxString::Format( _( "Net tie on %s; clearance: 0." ),
812 EscapeHTML( footprints[ii]->GetItemDescription( this, true ) ) ) )
813
814 constraint.SetName( _( "net tie" ) );
815 constraint.m_Value.SetMin( 0 );
816 return constraint;
817 }
818 }
819 }
820
821 // Local overrides take precedence over everything *except* board min clearance
822 if( aConstraintType == CLEARANCE_CONSTRAINT || aConstraintType == HOLE_CLEARANCE_CONSTRAINT )
823 {
824 int override_val = 0;
825 std::optional<int> overrideA;
826 std::optional<int> overrideB;
827
828 if( ac && !b_is_non_copper )
829 overrideA = ac->GetClearanceOverrides( nullptr );
830
831 if( bc && !a_is_non_copper )
832 overrideB = bc->GetClearanceOverrides( nullptr );
833
834 if( overrideA.has_value() || overrideB.has_value() )
835 {
836 wxString msg;
837
838 if( overrideA.has_value() )
839 {
840 REPORT( "" )
841 REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
842 EscapeHTML( a->GetItemDescription( this, true ) ),
843 MessageTextFromValue( overrideA.value() ) ) )
844
845 override_val = ac->GetClearanceOverrides( &msg ).value();
846 }
847
848 if( overrideB.has_value() )
849 {
850 REPORT( "" )
851 REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
852 EscapeHTML( b->GetItemDescription( this, true ) ),
853 EscapeHTML( MessageTextFromValue( overrideB.value() ) ) ) )
854
855 if( overrideB > override_val )
856 override_val = bc->GetClearanceOverrides( &msg ).value();
857 }
858
859 if( override_val )
860 {
861 if( aConstraintType == CLEARANCE_CONSTRAINT )
862 {
863 if( override_val < m_designSettings->m_MinClearance )
864 {
865 override_val = m_designSettings->m_MinClearance;
866 msg = _( "board minimum" );
867
868 REPORT( "" )
869 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
870 MessageTextFromValue( override_val ) ) )
871 }
872 }
873 else
874 {
875 if( override_val < m_designSettings->m_HoleClearance )
876 {
877 override_val = m_designSettings->m_HoleClearance;
878 msg = _( "board minimum hole" );
879
880 REPORT( "" )
881 REPORT( wxString::Format( _( "Board minimum hole clearance: %s." ),
882 MessageTextFromValue( override_val ) ) )
883 }
884 }
885
886 constraint.SetName( msg );
887 constraint.m_Value.SetMin( override_val );
888 return constraint;
889 }
890 }
891 }
892 else if( aConstraintType == ZONE_CONNECTION_CONSTRAINT )
893 {
894 if( pad && pad->GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED )
895 {
896 wxString msg;
897 ZONE_CONNECTION override = pad->GetZoneConnectionOverrides( &msg );
898
899 REPORT( "" )
900 REPORT( wxString::Format( _( "Local override on %s; zone connection: %s." ),
901 EscapeHTML( pad->GetItemDescription( this, true ) ),
902 EscapeHTML( PrintZoneConnection( override ) ) ) )
903
904 constraint.SetName( msg );
905 constraint.m_ZoneConnection = override;
906 return constraint;
907 }
908 }
909 else if( aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT )
910 {
911 if( pad && pad->GetLocalThermalGapOverride( nullptr ) > 0 )
912 {
913 wxString msg;
914 int gap_override = pad->GetLocalThermalGapOverride( &msg );
915
916 REPORT( "" )
917 REPORT( wxString::Format( _( "Local override on %s; thermal relief gap: %s." ),
918 EscapeHTML( pad->GetItemDescription( this, true ) ),
919 EscapeHTML( MessageTextFromValue( gap_override ) ) ) )
920
921 constraint.SetName( msg );
922 constraint.m_Value.SetMin( gap_override );
923 return constraint;
924 }
925 }
926 else if( aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT )
927 {
928 if( pad && pad->GetLocalSpokeWidthOverride( nullptr ) > 0 )
929 {
930 wxString msg;
931 int spoke_override = pad->GetLocalSpokeWidthOverride( &msg );
932
933 REPORT( "" )
934 REPORT( wxString::Format( _( "Local override on %s; thermal spoke width: %s." ),
935 EscapeHTML( pad->GetItemDescription( this, true ) ),
936 EscapeHTML( MessageTextFromValue( spoke_override ) ) ) )
937
938 if( zone && zone->GetMinThickness() > spoke_override )
939 {
940 spoke_override = zone->GetMinThickness();
941
942 REPORT( "" )
943 REPORT( wxString::Format( _( "%s min thickness: %s." ),
944 EscapeHTML( zone->GetItemDescription( this, true ) ),
945 EscapeHTML( MessageTextFromValue( spoke_override ) ) ) )
946 }
947
948 constraint.SetName( msg );
949 constraint.m_Value.SetMin( spoke_override );
950 return constraint;
951 }
952 }
953
954 auto testAssertion =
955 [&]( const DRC_ENGINE_CONSTRAINT* c )
956 {
957 REPORT( wxString::Format( _( "Checking assertion \"%s\"." ),
958 EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
959
960 if( c->constraint.m_Test->EvaluateFor( a, b, c->constraint.m_Type, aLayer,
961 aReporter ) )
962 {
963 REPORT( _( "Assertion passed." ) )
964 }
965 else
966 {
967 REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
968 }
969 };
970
971 auto processConstraint =
972 [&]( const DRC_ENGINE_CONSTRAINT* c )
973 {
974 bool implicit = c->parentRule && c->parentRule->m_Implicit;
975
976 REPORT( "" )
977
978 switch( c->constraint.m_Type )
979 {
987 REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
988 EscapeHTML( c->constraint.GetName() ),
989 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
990 break;
992 REPORT( wxString::Format( _( "Checking %s creepage: %s." ),
993 EscapeHTML( c->constraint.GetName() ),
994 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
995 break;
997 REPORT( wxString::Format( _( "Checking %s max uncoupled length: %s." ),
998 EscapeHTML( c->constraint.GetName() ),
999 MessageTextFromValue( c->constraint.m_Value.Max() ) ) )
1000 break;
1001
1002 case SKEW_CONSTRAINT:
1003 REPORT( wxString::Format( _( "Checking %s max skew: %s." ),
1004 EscapeHTML( c->constraint.GetName() ),
1005 MessageTextFromValue( c->constraint.m_Value.Max() ) ) )
1006 break;
1007
1009 REPORT( wxString::Format( _( "Checking %s gap: %s." ),
1010 EscapeHTML( c->constraint.GetName() ),
1011 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
1012 break;
1013
1015 REPORT( wxString::Format( _( "Checking %s thermal spoke width: %s." ),
1016 EscapeHTML( c->constraint.GetName() ),
1017 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
1018 break;
1019
1021 REPORT( wxString::Format( _( "Checking %s min spoke count: %s." ),
1022 EscapeHTML( c->constraint.GetName() ),
1024 c->constraint.m_Value.Min() ) ) )
1025 break;
1026
1028 REPORT( wxString::Format( _( "Checking %s zone connection: %s." ),
1029 EscapeHTML( c->constraint.GetName() ),
1030 EscapeHTML( PrintZoneConnection( c->constraint.m_ZoneConnection ) ) ) )
1031 break;
1032
1040 case LENGTH_CONSTRAINT:
1043 {
1044 if( aReporter )
1045 {
1046 wxString min = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
1047 wxString opt = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
1048 wxString max = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
1049
1050 if( implicit )
1051 {
1052 min = MessageTextFromValue( c->constraint.m_Value.Min() );
1053 opt = MessageTextFromValue( c->constraint.m_Value.Opt() );
1054
1055 switch( c->constraint.m_Type )
1056 {
1058 if( c->constraint.m_Value.HasOpt() )
1059 {
1060 REPORT( wxString::Format( _( "Checking %s track width: opt %s." ),
1061 EscapeHTML( c->constraint.GetName() ),
1062 opt ) )
1063 }
1064 else if( c->constraint.m_Value.HasMin() )
1065 {
1066 REPORT( wxString::Format( _( "Checking %s track width: min %s." ),
1067 EscapeHTML( c->constraint.GetName() ),
1068 min ) )
1069 }
1070
1071 break;
1072
1074 REPORT( wxString::Format( _( "Checking %s annular width: min %s." ),
1075 EscapeHTML( c->constraint.GetName() ),
1076 opt ) )
1077 break;
1078
1080 if( c->constraint.m_Value.HasOpt() )
1081 {
1082 REPORT( wxString::Format( _( "Checking %s via diameter: opt %s." ),
1083 EscapeHTML( c->constraint.GetName() ),
1084 opt ) )
1085 }
1086 else if( c->constraint.m_Value.HasMin() )
1087 {
1088 REPORT( wxString::Format( _( "Checking %s via diameter: min %s." ),
1089 EscapeHTML( c->constraint.GetName() ),
1090 min ) )
1091 }
1092 break;
1093
1095 if( c->constraint.m_Value.HasOpt() )
1096 {
1097 REPORT( wxString::Format( _( "Checking %s hole size: opt %s." ),
1098 EscapeHTML( c->constraint.GetName() ),
1099 opt ) )
1100 }
1101 else if( c->constraint.m_Value.HasMin() )
1102 {
1103 REPORT( wxString::Format( _( "Checking %s hole size: min %s." ),
1104 EscapeHTML( c->constraint.GetName() ),
1105 min ) )
1106 }
1107
1108 break;
1109
1113 REPORT( wxString::Format( _( "Checking %s: min %s." ),
1114 EscapeHTML( c->constraint.GetName() ),
1115 min ) )
1116 break;
1117
1119 if( c->constraint.m_Value.HasOpt() )
1120 {
1121 REPORT( wxString::Format( _( "Checking %s diff pair gap: opt %s." ),
1122 EscapeHTML( c->constraint.GetName() ),
1123 opt ) )
1124 }
1125 else if( c->constraint.m_Value.HasMin() )
1126 {
1127 REPORT( wxString::Format( _( "Checking %s clearance: min %s." ),
1128 EscapeHTML( c->constraint.GetName() ),
1129 min ) )
1130 }
1131
1132 break;
1133
1135 REPORT( wxString::Format( _( "Checking %s hole to hole: min %s." ),
1136 EscapeHTML( c->constraint.GetName() ),
1137 min ) )
1138 break;
1139
1140 default:
1141 REPORT( wxString::Format( _( "Checking %s." ),
1142 EscapeHTML( c->constraint.GetName() ) ) )
1143 }
1144 }
1145 else
1146 {
1147 if( c->constraint.m_Value.HasMin() )
1148 min = MessageTextFromValue( c->constraint.m_Value.Min() );
1149
1150 if( c->constraint.m_Value.HasOpt() )
1151 opt = MessageTextFromValue( c->constraint.m_Value.Opt() );
1152
1153 if( c->constraint.m_Value.HasMax() )
1154 max = MessageTextFromValue( c->constraint.m_Value.Max() );
1155
1156 REPORT( wxString::Format( _( "Checking %s: min %s; opt %s; max %s." ),
1157 EscapeHTML( c->constraint.GetName() ),
1158 min,
1159 opt,
1160 max ) )
1161 }
1162 }
1163 break;
1164 }
1165
1166 default:
1167 REPORT( wxString::Format( _( "Checking %s." ),
1168 EscapeHTML( c->constraint.GetName() ) ) )
1169 }
1170
1171 if( c->constraint.m_Type == CLEARANCE_CONSTRAINT )
1172 {
1173 if( a_is_non_copper || b_is_non_copper )
1174 {
1175 if( implicit )
1176 {
1177 REPORT( _( "Netclass clearances apply only between copper items." ) )
1178 }
1179 else if( a_is_non_copper )
1180 {
1181 REPORT( wxString::Format( _( "%s contains no copper. Rule ignored." ),
1182 EscapeHTML( a->GetItemDescription( this, true ) ) ) )
1183 }
1184 else if( b_is_non_copper )
1185 {
1186 REPORT( wxString::Format( _( "%s contains no copper. Rule ignored." ),
1187 EscapeHTML( b->GetItemDescription( this, true ) ) ) )
1188 }
1189
1190 return;
1191 }
1192 }
1193 else if( c->constraint.m_Type == DISALLOW_CONSTRAINT )
1194 {
1195 int mask;
1196
1197 if( a->GetFlags() & HOLE_PROXY )
1198 {
1199 mask = DRC_DISALLOW_HOLES;
1200 }
1201 else if( a->Type() == PCB_VIA_T )
1202 {
1203 mask = DRC_DISALLOW_VIAS;
1204
1205 switch( static_cast<const PCB_VIA*>( a )->GetViaType() )
1206 {
1207 case VIATYPE::BLIND_BURIED: mask |= DRC_DISALLOW_BB_VIAS; break;
1208 case VIATYPE::MICROVIA: mask |= DRC_DISALLOW_MICRO_VIAS; break;
1209 default: break;
1210 }
1211 }
1212 else
1213 {
1214 switch( a->Type() )
1215 {
1216 case PCB_TRACE_T: mask = DRC_DISALLOW_TRACKS; break;
1217 case PCB_ARC_T: mask = DRC_DISALLOW_TRACKS; break;
1218 case PCB_PAD_T: mask = DRC_DISALLOW_PADS; break;
1219 case PCB_FOOTPRINT_T: mask = DRC_DISALLOW_FOOTPRINTS; break;
1220 case PCB_SHAPE_T: mask = DRC_DISALLOW_GRAPHICS; break;
1221 case PCB_FIELD_T: mask = DRC_DISALLOW_TEXTS; break;
1222 case PCB_TEXT_T: mask = DRC_DISALLOW_TEXTS; break;
1223 case PCB_TEXTBOX_T: mask = DRC_DISALLOW_TEXTS; break;
1224 case PCB_TABLE_T: mask = DRC_DISALLOW_TEXTS; break;
1225
1226 case PCB_ZONE_T:
1227 // Treat teardrop areas as tracks for DRC purposes
1228 if( static_cast<const ZONE*>( a )->IsTeardropArea() )
1229 mask = DRC_DISALLOW_TRACKS;
1230 else
1231 mask = DRC_DISALLOW_ZONES;
1232
1233 break;
1234
1235 case PCB_LOCATE_HOLE_T: mask = DRC_DISALLOW_HOLES; break;
1236 default: mask = 0; break;
1237 }
1238 }
1239
1240 if( ( c->constraint.m_DisallowFlags & mask ) == 0 )
1241 {
1242 if( implicit )
1243 REPORT( _( "Keepout constraint not met." ) )
1244 else
1245 REPORT( _( "Disallow constraint not met." ) )
1246
1247 return;
1248 }
1249
1250 LSET itemLayers = a->GetLayerSet();
1251
1252 if( a->Type() == PCB_FOOTPRINT_T )
1253 {
1254 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( a );
1255
1256 if( !footprint->GetCourtyard( F_CrtYd ).IsEmpty() )
1257 itemLayers |= LSET::FrontMask();
1258
1259 if( !footprint->GetCourtyard( B_CrtYd ).IsEmpty() )
1260 itemLayers |= LSET::BackMask();
1261 }
1262
1263 if( !( c->layerTest & itemLayers ).any() )
1264 {
1265 if( implicit )
1266 {
1267 REPORT( _( "Keepout layer(s) not matched." ) )
1268 }
1269 else if( c->parentRule )
1270 {
1271 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1272 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1273 }
1274 else
1275 {
1276 REPORT( _( "Rule layer not matched; rule ignored." ) )
1277 }
1278
1279 return;
1280 }
1281 }
1282
1283 if( ( aLayer != UNDEFINED_LAYER && !c->layerTest.test( aLayer ) )
1284 || ( m_board->GetEnabledLayers() & c->layerTest ).count() == 0 )
1285 {
1286 if( implicit )
1287 {
1288 REPORT( _( "Constraint layer not matched." ) )
1289 }
1290 else if( c->parentRule )
1291 {
1292 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1293 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1294 }
1295 else
1296 {
1297 REPORT( _( "Rule layer not matched; rule ignored." ) )
1298 }
1299 }
1300 else if( c->constraint.m_Type == HOLE_TO_HOLE_CONSTRAINT
1301 && ( !a->HasDrilledHole() && !b->HasDrilledHole() ) )
1302 {
1303 // Report non-drilled-holes as an implicit condition
1304 REPORT( wxString::Format( _( "%s is not a drilled hole; rule ignored." ),
1305 a->GetItemDescription( this, true ) ) )
1306 }
1307 else if( !c->condition || c->condition->GetExpression().IsEmpty() )
1308 {
1309 if( aReporter )
1310 {
1311 if( implicit )
1312 {
1313 REPORT( _( "Unconditional constraint applied." ) )
1314 }
1315 else if( constraint.m_Type == ASSERTION_CONSTRAINT )
1316 {
1317 REPORT( _( "Unconditional rule applied." ) )
1318 testAssertion( c );
1319 }
1320 else
1321 {
1322 REPORT( _( "Unconditional rule applied; overrides previous constraints." ) )
1323 }
1324 }
1325
1326 applyConstraint( c );
1327 }
1328 else
1329 {
1330 if( implicit )
1331 {
1332 // Don't report on implicit rule conditions; they're synthetic.
1333 }
1334 else
1335 {
1336 REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
1337 EscapeHTML( c->condition->GetExpression() ) ) )
1338 }
1339
1340 if( c->condition->EvaluateFor( a, b, c->constraint.m_Type, aLayer, aReporter ) )
1341 {
1342 if( aReporter )
1343 {
1344 if( implicit )
1345 {
1346 REPORT( _( "Constraint applied." ) )
1347 }
1348 else if( constraint.m_Type == ASSERTION_CONSTRAINT )
1349 {
1350 REPORT( _( "Rule applied." ) )
1351 testAssertion( c );
1352 }
1353 else
1354 {
1355 REPORT( _( "Rule applied; overrides previous constraints." ) )
1356 }
1357 }
1358
1359 applyConstraint( c );
1360 }
1361 else
1362 {
1363 REPORT( implicit ? _( "Membership not satisfied; constraint ignored." )
1364 : _( "Condition not satisfied; rule ignored." ) )
1365 }
1366 }
1367 };
1368
1369 if( m_constraintMap.count( aConstraintType ) )
1370 {
1371 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
1372
1373 for( DRC_ENGINE_CONSTRAINT* rule : *ruleset )
1374 processConstraint( rule );
1375 }
1376
1377 if( constraint.GetParentRule() && !constraint.GetParentRule()->m_Implicit )
1378 return constraint;
1379
1380 // Special case for pad zone connections which can iherit from their parent footprints.
1381 // We've already checked for local overrides, and there were no rules targetting the pad
1382 // itself, so we know we're inheriting and need to see if there are any rules targetting
1383 // the parent footprint.
1384 if( pad && parentFootprint && ( aConstraintType == ZONE_CONNECTION_CONSTRAINT
1385 || aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT
1386 || aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT ) )
1387 {
1388 REPORT( "" )
1389 REPORT( wxString::Format( _( "Inheriting from parent: %s." ),
1390 EscapeHTML( parentFootprint->GetItemDescription( this, true ) ) ) )
1391
1392 if( a == pad )
1393 a = parentFootprint;
1394 else
1395 b = parentFootprint;
1396
1397 if( m_constraintMap.count( aConstraintType ) )
1398 {
1399 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
1400
1401 for( DRC_ENGINE_CONSTRAINT* rule : *ruleset )
1402 processConstraint( rule );
1403
1404 if( constraint.GetParentRule() && !constraint.GetParentRule()->m_Implicit )
1405 return constraint;
1406 }
1407 }
1408
1409 // Unfortunately implicit rules don't work for local clearances (such as zones) because
1410 // they have to be max'ed with netclass values (which are already implicit rules), and our
1411 // rule selection paradigm is "winner takes all".
1412 if( aConstraintType == CLEARANCE_CONSTRAINT )
1413 {
1414 int global = constraint.m_Value.Min();
1415 int clearance = global;
1416 bool needBlankLine = true;
1417
1418 if( ac && ac->GetLocalClearance().has_value() )
1419 {
1420 int localA = ac->GetLocalClearance().value();
1421
1422 if( needBlankLine )
1423 {
1424 REPORT( "" )
1425 needBlankLine = false;
1426 }
1427
1428 REPORT( wxString::Format( _( "Local clearance on %s: %s." ),
1429 EscapeHTML( a->GetItemDescription( this, true ) ),
1430 MessageTextFromValue( localA ) ) )
1431
1432 if( localA > clearance )
1433 {
1434 wxString msg;
1435 clearance = ac->GetLocalClearance( &msg ).value();
1436 constraint.SetParentRule( nullptr );
1437 constraint.SetName( msg );
1438 constraint.m_Value.SetMin( clearance );
1439 }
1440 }
1441
1442 if( bc && bc->GetLocalClearance().has_value() )
1443 {
1444 int localB = bc->GetLocalClearance().value();
1445
1446 if( needBlankLine )
1447 {
1448 REPORT( "" )
1449 needBlankLine = false;
1450 }
1451
1452 REPORT( wxString::Format( _( "Local clearance on %s: %s." ),
1453 EscapeHTML( b->GetItemDescription( this, true ) ),
1454 MessageTextFromValue( localB ) ) )
1455
1456 if( localB > clearance )
1457 {
1458 wxString msg;
1459 clearance = bc->GetLocalClearance( &msg ).value();
1460 constraint.SetParentRule( nullptr );
1461 constraint.SetName( msg );
1462 constraint.m_Value.SetMin( clearance );
1463 }
1464 }
1465
1466 if( !a_is_non_copper && !b_is_non_copper )
1467 {
1468 if( needBlankLine )
1469 {
1470 REPORT( "" )
1471 needBlankLine = false;
1472 }
1473
1474 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
1476
1477 if( clearance < m_designSettings->m_MinClearance )
1478 {
1479 constraint.SetParentRule( nullptr );
1480 constraint.SetName( _( "board minimum" ) );
1482 }
1483 }
1484
1485 return constraint;
1486 }
1487 else if( aConstraintType == DIFF_PAIR_GAP_CONSTRAINT )
1488 {
1489 REPORT( "" )
1490 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
1492
1493 if( constraint.m_Value.Min() < m_designSettings->m_MinClearance )
1494 {
1495 constraint.SetParentRule( nullptr );
1496 constraint.SetName( _( "board minimum" ) );
1498 }
1499
1500 return constraint;
1501 }
1502 else if( aConstraintType == ZONE_CONNECTION_CONSTRAINT )
1503 {
1504 if( pad && parentFootprint )
1505 {
1506 ZONE_CONNECTION local = parentFootprint->GetLocalZoneConnection();
1507
1508 if( local != ZONE_CONNECTION::INHERITED )
1509 {
1510 REPORT( "" )
1511 REPORT( wxString::Format( _( "%s zone connection: %s." ),
1512 EscapeHTML( parentFootprint->GetItemDescription( this, true ) ),
1513 EscapeHTML( PrintZoneConnection( local ) ) ) )
1514
1515 constraint.SetParentRule( nullptr );
1516 constraint.SetName( _( "footprint" ) );
1517 constraint.m_ZoneConnection = local;
1518 return constraint;
1519 }
1520 }
1521
1522 if( zone )
1523 {
1524 ZONE_CONNECTION local = zone->GetPadConnection();
1525
1526 REPORT( "" )
1527 REPORT( wxString::Format( _( "%s pad connection: %s." ),
1528 EscapeHTML( zone->GetItemDescription( this, true ) ),
1529 EscapeHTML( PrintZoneConnection( local ) ) ) )
1530
1531 constraint.SetParentRule( nullptr );
1532 constraint.SetName( _( "zone" ) );
1533 constraint.m_ZoneConnection = local;
1534 return constraint;
1535 }
1536 }
1537 else if( aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT )
1538 {
1539 if( zone )
1540 {
1541 int local = zone->GetThermalReliefGap();
1542
1543 REPORT( "" )
1544 REPORT( wxString::Format( _( "%s thermal relief gap: %s." ),
1545 EscapeHTML( zone->GetItemDescription( this, true ) ),
1546 EscapeHTML( MessageTextFromValue( local ) ) ) )
1547
1548 constraint.SetParentRule( nullptr );
1549 constraint.SetName( _( "zone" ) );
1550 constraint.m_Value.SetMin( local );
1551 return constraint;
1552 }
1553 }
1554 else if( aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT )
1555 {
1556 if( zone )
1557 {
1558 int local = zone->GetThermalReliefSpokeWidth();
1559
1560 REPORT( "" )
1561 REPORT( wxString::Format( _( "%s thermal spoke width: %s." ),
1562 EscapeHTML( zone->GetItemDescription( this, true ) ),
1563 EscapeHTML( MessageTextFromValue( local ) ) ) )
1564
1565 constraint.SetParentRule( nullptr );
1566 constraint.SetName( _( "zone" ) );
1567 constraint.m_Value.SetMin( local );
1568 return constraint;
1569 }
1570 }
1571
1572 if( !constraint.GetParentRule() )
1573 {
1574 constraint.m_Type = NULL_CONSTRAINT;
1575 constraint.m_DisallowFlags = 0;
1576 }
1577
1578 return constraint;
1579}
1580
1581
1583 std::function<void( const DRC_CONSTRAINT* )> aFailureHandler,
1584 REPORTER* aReporter )
1585{
1586 /*
1587 * NOTE: all string manipulation MUST BE KEPT INSIDE the REPORT macro. It absolutely
1588 * kills performance when running bulk DRC tests (where aReporter is nullptr).
1589 */
1590
1591 auto testAssertion =
1592 [&]( const DRC_ENGINE_CONSTRAINT* c )
1593 {
1594 REPORT( wxString::Format( _( "Checking rule assertion \"%s\"." ),
1595 EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
1596
1597 if( c->constraint.m_Test->EvaluateFor( a, nullptr, c->constraint.m_Type,
1598 a->GetLayer(), aReporter ) )
1599 {
1600 REPORT( _( "Assertion passed." ) )
1601 }
1602 else
1603 {
1604 REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
1605 aFailureHandler( &c->constraint );
1606 }
1607 };
1608
1609 auto processConstraint =
1610 [&]( const DRC_ENGINE_CONSTRAINT* c )
1611 {
1612 REPORT( "" )
1613 REPORT( wxString::Format( _( "Checking %s." ), c->constraint.GetName() ) )
1614
1615 if( !( a->GetLayerSet() & c->layerTest ).any() )
1616 {
1617 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1618 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1619 }
1620
1621 if( !c->condition || c->condition->GetExpression().IsEmpty() )
1622 {
1623 REPORT( _( "Unconditional rule applied." ) )
1624 testAssertion( c );
1625 }
1626 else
1627 {
1628 REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
1629 EscapeHTML( c->condition->GetExpression() ) ) )
1630
1631 if( c->condition->EvaluateFor( a, nullptr, c->constraint.m_Type,
1632 a->GetLayer(), aReporter ) )
1633 {
1634 REPORT( _( "Rule applied." ) )
1635 testAssertion( c );
1636 }
1637 else
1638 {
1639 REPORT( _( "Condition not satisfied; rule ignored." ) )
1640 }
1641 }
1642 };
1643
1645 {
1646 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ ASSERTION_CONSTRAINT ];
1647
1648 for( int ii = 0; ii < (int) ruleset->size(); ++ii )
1649 processConstraint( ruleset->at( ii ) );
1650 }
1651}
1652
1653
1654#undef REPORT
1655
1656
1658{
1659 assert( error_code >= 0 && error_code <= DRCE_LAST );
1660 return m_errorLimits[ error_code ] <= 0;
1661}
1662
1663
1664void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos,
1665 int aMarkerLayer, DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
1666{
1667 static std::mutex globalLock;
1668
1669 m_errorLimits[ aItem->GetErrorCode() ] -= 1;
1670
1671 if( m_violationHandler )
1672 {
1673 std::lock_guard<std::mutex> guard( globalLock );
1674 m_violationHandler( aItem, aPos, aMarkerLayer, aCustomHandler );
1675 }
1676
1677 if( m_reporter )
1678 {
1679 wxString msg = wxString::Format( wxT( "Test '%s': %s (code %d)" ),
1680 aItem->GetViolatingTest()->GetName(),
1681 aItem->GetErrorMessage(),
1682 aItem->GetErrorCode() );
1683
1684 DRC_RULE* rule = aItem->GetViolatingRule();
1685
1686 if( rule )
1687 msg += wxString::Format( wxT( ", violating rule: '%s'" ), rule->m_Name );
1688
1689 m_reporter->Report( msg );
1690
1691 wxString violatingItemsStr = wxT( "Violating items: " );
1692
1693 m_reporter->Report( wxString::Format( wxT( " |- violating position (%d, %d)" ),
1694 aPos.x,
1695 aPos.y ) );
1696 }
1697}
1698
1699
1700void DRC_ENGINE::ReportAux ( const wxString& aStr )
1701{
1702 if( !m_reporter )
1703 return;
1704
1706}
1707
1708
1710{
1711 if( !m_progressReporter )
1712 return true;
1713
1714 return m_progressReporter->KeepRefreshing( aWait );
1715}
1716
1717
1719{
1720 if( m_progressReporter )
1722}
1723
1724
1726{
1727 if( m_progressReporter )
1729}
1730
1731
1732bool DRC_ENGINE::ReportProgress( double aProgress )
1733{
1734 if( !m_progressReporter )
1735 return true;
1736
1738 return m_progressReporter->KeepRefreshing( false );
1739}
1740
1741
1742bool DRC_ENGINE::ReportPhase( const wxString& aMessage )
1743{
1744 if( !m_progressReporter )
1745 return true;
1746
1747 m_progressReporter->AdvancePhase( aMessage );
1748 bool retval = m_progressReporter->KeepRefreshing( false );
1749 wxSafeYield( nullptr, true ); // Force an update for the message
1750 return retval;
1751}
1752
1753
1755{
1757}
1758
1759
1761{
1762 //drc_dbg(10,"hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size( ) );
1763 if( m_constraintMap.count( constraintID ) )
1764 return m_constraintMap[ constraintID ]->size() > 0;
1765
1766 return false;
1767}
1768
1769
1771{
1772 int worst = 0;
1773
1774 if( m_constraintMap.count( aConstraintId ) )
1775 {
1776 for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
1777 {
1778 int current = c->constraint.GetValue().Min();
1779
1780 if( current > worst )
1781 {
1782 worst = current;
1783 aConstraint = c->constraint;
1784 }
1785 }
1786 }
1787
1788 return worst > 0;
1789}
1790
1791
1793{
1794 std::set<int> distinctMinimums;
1795
1796 if( m_constraintMap.count( aConstraintId ) )
1797 {
1798 for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
1799 distinctMinimums.emplace( c->constraint.GetValue().Min() );
1800 }
1801
1802 return distinctMinimums;
1803}
1804
1805
1806// fixme: move two functions below to pcbcommon?
1807int DRC_ENGINE::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet,
1808 wxString& aBaseDpName )
1809{
1810 int rv = 0;
1811 int count = 0;
1812
1813 for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
1814 {
1815 int ch = *it;
1816
1817 if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
1818 {
1819 continue;
1820 }
1821 else if( ch == '+' )
1822 {
1823 aComplementNet = wxT( "-" );
1824 rv = 1;
1825 }
1826 else if( ch == '-' )
1827 {
1828 aComplementNet = wxT( "+" );
1829 rv = -1;
1830 }
1831 else if( ch == 'N' )
1832 {
1833 aComplementNet = wxT( "P" );
1834 rv = -1;
1835 }
1836 else if ( ch == 'P' )
1837 {
1838 aComplementNet = wxT( "N" );
1839 rv = 1;
1840 }
1841 else
1842 {
1843 break;
1844 }
1845 }
1846
1847 if( rv != 0 && count >= 1 )
1848 {
1849 aBaseDpName = aNetName.Left( aNetName.Length() - count );
1850 aComplementNet = wxString( aBaseDpName ) << aComplementNet << aNetName.Right( count - 1 );
1851 }
1852
1853 return rv;
1854}
1855
1856
1857bool DRC_ENGINE::IsNetADiffPair( BOARD* aBoard, NETINFO_ITEM* aNet, int& aNetP, int& aNetN )
1858{
1859 wxString refName = aNet->GetNetname();
1860 wxString dummy, coupledNetName;
1861
1862 if( int polarity = MatchDpSuffix( refName, coupledNetName, dummy ) )
1863 {
1864 NETINFO_ITEM* net = aBoard->FindNet( coupledNetName );
1865
1866 if( !net )
1867 return false;
1868
1869 if( polarity > 0 )
1870 {
1871 aNetP = aNet->GetNetCode();
1872 aNetN = net->GetNetCode();
1873 }
1874 else
1875 {
1876 aNetP = net->GetNetCode();
1877 aNetN = aNet->GetNetCode();
1878 }
1879
1880 return true;
1881 }
1882
1883 return false;
1884}
1885
1886
1891bool DRC_ENGINE::IsNetTieExclusion( int aTrackNetCode, PCB_LAYER_ID aTrackLayer,
1892 const VECTOR2I& aCollisionPos, BOARD_ITEM* aCollidingItem )
1893{
1894 FOOTPRINT* parentFootprint = aCollidingItem->GetParentFootprint();
1895
1896 if( parentFootprint && parentFootprint->IsNetTie() )
1897 {
1899 std::map<wxString, int> padToNetTieGroupMap = parentFootprint->MapPadNumbersToNetTieGroups();
1900
1901 for( PAD* pad : parentFootprint->Pads() )
1902 {
1903 if( padToNetTieGroupMap[ pad->GetNumber() ] >= 0 && aTrackNetCode == pad->GetNetCode() )
1904 {
1905 if( pad->GetEffectiveShape( aTrackLayer )->Collide( aCollisionPos, epsilon ) )
1906 return true;
1907 }
1908 }
1909 }
1910
1911 return false;
1912}
1913
1914
1916{
1917 for( DRC_TEST_PROVIDER* prov : m_testProviders )
1918 {
1919 if( name == prov->GetName() )
1920 return prov;
1921 }
1922
1923 return nullptr;
1924}
const char * name
Definition: DXF_plotter.cpp:59
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
constexpr EDA_IU_SCALE unityScale
Definition: base_units.h:111
#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:235
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:137
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:305
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:255
virtual bool HasDrilledHole() const
Definition: board_item.h:164
virtual bool IsOnCopperLayer() const
Definition: board_item.h:154
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:297
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:829
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:2144
void IncrementTimeStamp()
Definition: board.cpp:253
const FOOTPRINTS & Footprints() const
Definition: board.h:338
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:946
COMPONENT_CLASS_MANAGER & GetComponentClassManager()
Gets the component class manager.
Definition: board.h:1316
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: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: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:115
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:107
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:134
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: footprint.h:293
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:3179
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:2161
const SHAPE_POLY_SET & GetCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.cpp:2987
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
static LSET FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:683
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:690
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)=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: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: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:361
@ 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