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->GetDoNotAllowCopperPour()
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->GetDoNotAllowCopperPour() )
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 int timestamp = m_board->GetTimeStamp();
636
637 for( DRC_TEST_PROVIDER* provider : m_testProviders )
638 {
639 ReportAux( wxString::Format( wxT( "Run DRC provider: '%s'" ), provider->GetName() ) );
640
641 if( !provider->RunTests( aUnits ) )
642 break;
643 }
644
645 timer.Stop();
646 wxLogTrace( traceDrcProfile, "DRC took %0.3f ms", timer.msecs() );
647
648 // DRC tests are multi-threaded; anything that causes us to attempt to re-generate the
649 // caches while DRC is running is problematic.
650 wxASSERT( timestamp == m_board->GetTimeStamp() );
651}
652
653
654#define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } }
655
657 PCB_LAYER_ID aLayer, REPORTER* aReporter )
658{
659 DRC_CONSTRAINT constraint = EvalRules( ZONE_CONNECTION_CONSTRAINT, a, b, aLayer, aReporter );
660
661 REPORT( "" )
662 REPORT( wxString::Format( _( "Resolved zone connection type: %s." ),
664
665 if( constraint.m_ZoneConnection == ZONE_CONNECTION::THT_THERMAL )
666 {
667 const PAD* pad = nullptr;
668
669 if( a->Type() == PCB_PAD_T )
670 pad = static_cast<const PAD*>( a );
671 else if( b->Type() == PCB_PAD_T )
672 pad = static_cast<const PAD*>( b );
673
674 if( pad && pad->GetAttribute() == PAD_ATTRIB::PTH )
675 {
676 constraint.m_ZoneConnection = ZONE_CONNECTION::THERMAL;
677 }
678 else
679 {
680 REPORT( wxString::Format( _( "Pad is not a through hole pad; connection will be: %s." ),
681 EscapeHTML( PrintZoneConnection( ZONE_CONNECTION::FULL ) ) ) )
682 constraint.m_ZoneConnection = ZONE_CONNECTION::FULL;
683 }
684 }
685
686 return constraint;
687}
688
689
691 const BOARD_ITEM* b, PCB_LAYER_ID aLayer,
692 REPORTER* aReporter )
693{
694 /*
695 * NOTE: all string manipulation MUST BE KEPT INSIDE the REPORT macro. It absolutely
696 * kills performance when running bulk DRC tests (where aReporter is nullptr).
697 */
698
699 const BOARD_CONNECTED_ITEM* ac = a && a->IsConnected() ?
700 static_cast<const BOARD_CONNECTED_ITEM*>( a ) : nullptr;
701 const BOARD_CONNECTED_ITEM* bc = b && b->IsConnected() ?
702 static_cast<const BOARD_CONNECTED_ITEM*>( b ) : nullptr;
703
704 bool a_is_non_copper = a && ( !a->IsOnCopperLayer() || isKeepoutZone( a, false ) );
705 bool b_is_non_copper = b && ( !b->IsOnCopperLayer() || isKeepoutZone( b, false ) );
706
707 const PAD* pad = nullptr;
708 const ZONE* zone = nullptr;
709 const FOOTPRINT* parentFootprint = nullptr;
710
711 if( aConstraintType == ZONE_CONNECTION_CONSTRAINT
712 || aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT
713 || aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT )
714 {
715 if( a && a->Type() == PCB_PAD_T )
716 pad = static_cast<const PAD*>( a );
717 else if( a && a->Type() == PCB_ZONE_T )
718 zone = static_cast<const ZONE*>( a );
719
720 if( b && b->Type() == PCB_PAD_T )
721 pad = static_cast<const PAD*>( b );
722 else if( b && b->Type() == PCB_ZONE_T )
723 zone = static_cast<const ZONE*>( b );
724
725 if( pad )
726 parentFootprint = pad->GetParentFootprint();
727 }
728
729 DRC_CONSTRAINT constraint;
730 constraint.m_Type = aConstraintType;
731
732 auto applyConstraint =
733 [&]( const DRC_ENGINE_CONSTRAINT* c )
734 {
735 if( c->constraint.m_Value.HasMin() )
736 {
737 if( c->parentRule && c->parentRule->m_Implicit )
738 constraint.m_ImplicitMin = true;
739
740 constraint.m_Value.SetMin( c->constraint.m_Value.Min() );
741 }
742
743 if( c->constraint.m_Value.HasOpt() )
744 constraint.m_Value.SetOpt( c->constraint.m_Value.Opt() );
745
746 if( c->constraint.m_Value.HasMax() )
747 constraint .m_Value.SetMax( c->constraint.m_Value.Max() );
748
749 // While the expectation would be to OR the disallow flags, we've already
750 // masked them down to aItem's type -- so we're really only looking for a
751 // boolean here.
752 constraint.m_DisallowFlags = c->constraint.m_DisallowFlags;
753
754 constraint.m_ZoneConnection = c->constraint.m_ZoneConnection;
755
756 constraint.SetParentRule( c->constraint.GetParentRule() );
757 };
758
759 const FOOTPRINT* footprints[2] = {a ? a->GetParentFootprint() : nullptr,
760 b ? b->GetParentFootprint() : nullptr};
761
762 // Handle Footprint net ties, which will zero out the clearance for footprint objects
763 if( aConstraintType == CLEARANCE_CONSTRAINT // Only zero clearance, other constraints still apply
764 && ( ( ( !ac ) ^ ( !bc ) )// Only apply to cases where we are comparing a connected item to a non-connected item
765 // and not both connected. Connected items of different nets still need to be checked
766 // for their standard clearance value
767 || ( ( footprints[0] == footprints[1] ) // Unless both items are in the same footprint
768 && footprints[0] ) ) // And that footprint exists
769 && !a_is_non_copper // Also, both elements need to be on copper layers
770 && !b_is_non_copper )
771 {
772 const BOARD_ITEM* child_items[2] = {a, b};
773
774 // These are the items being compared against, so the order is reversed
775 const BOARD_CONNECTED_ITEM* alt_items[2] = {bc, ac};
776
777 for( int ii = 0; ii < 2; ++ii )
778 {
779 // We need both a footprint item and a connected item to check for a net tie
780 if( !footprints[ii] || !alt_items[ii] )
781 continue;
782
783 const std::set<int>& netcodes = footprints[ii]->GetNetTieCache( child_items[ii] );
784
785 auto it = netcodes.find( alt_items[ii]->GetNetCode() );
786
787 if( it != netcodes.end() )
788 {
789 REPORT( "" )
790 REPORT( wxString::Format( _( "Net tie on %s; clearance: 0." ),
791 EscapeHTML( footprints[ii]->GetItemDescription( this, true ) ) ) )
792
793 constraint.SetName( _( "net tie" ) );
794 constraint.m_Value.SetMin( 0 );
795 return constraint;
796 }
797 }
798 }
799
800 // Local overrides take precedence over everything *except* board min clearance
801 if( aConstraintType == CLEARANCE_CONSTRAINT || aConstraintType == HOLE_CLEARANCE_CONSTRAINT )
802 {
803 int override_val = 0;
804 std::optional<int> overrideA;
805 std::optional<int> overrideB;
806
807 if( ac && !b_is_non_copper )
808 overrideA = ac->GetClearanceOverrides( nullptr );
809
810 if( bc && !a_is_non_copper )
811 overrideB = bc->GetClearanceOverrides( nullptr );
812
813 if( overrideA.has_value() || overrideB.has_value() )
814 {
815 wxString msg;
816
817 if( overrideA.has_value() )
818 {
819 REPORT( "" )
820 REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
821 EscapeHTML( a->GetItemDescription( this, true ) ),
822 MessageTextFromValue( overrideA.value() ) ) )
823
824 override_val = ac->GetClearanceOverrides( &msg ).value();
825 }
826
827 if( overrideB.has_value() )
828 {
829 REPORT( "" )
830 REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
831 EscapeHTML( b->GetItemDescription( this, true ) ),
832 EscapeHTML( MessageTextFromValue( overrideB.value() ) ) ) )
833
834 if( overrideB > override_val )
835 override_val = bc->GetClearanceOverrides( &msg ).value();
836 }
837
838 if( override_val )
839 {
840 if( aConstraintType == CLEARANCE_CONSTRAINT )
841 {
842 if( override_val < m_designSettings->m_MinClearance )
843 {
844 override_val = m_designSettings->m_MinClearance;
845 msg = _( "board minimum" );
846
847 REPORT( "" )
848 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
849 MessageTextFromValue( override_val ) ) )
850 }
851 }
852 else
853 {
854 if( override_val < m_designSettings->m_HoleClearance )
855 {
856 override_val = m_designSettings->m_HoleClearance;
857 msg = _( "board minimum hole" );
858
859 REPORT( "" )
860 REPORT( wxString::Format( _( "Board minimum hole clearance: %s." ),
861 MessageTextFromValue( override_val ) ) )
862 }
863 }
864
865 constraint.SetName( msg );
866 constraint.m_Value.SetMin( override_val );
867 return constraint;
868 }
869 }
870 }
871 else if( aConstraintType == ZONE_CONNECTION_CONSTRAINT )
872 {
873 if( pad && pad->GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED )
874 {
875 wxString msg;
876 ZONE_CONNECTION override = pad->GetZoneConnectionOverrides( &msg );
877
878 REPORT( "" )
879 REPORT( wxString::Format( _( "Local override on %s; zone connection: %s." ),
880 EscapeHTML( pad->GetItemDescription( this, true ) ),
881 EscapeHTML( PrintZoneConnection( override ) ) ) )
882
883 constraint.SetName( msg );
884 constraint.m_ZoneConnection = override;
885 return constraint;
886 }
887 }
888 else if( aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT )
889 {
890 if( pad && pad->GetLocalThermalGapOverride( nullptr ) > 0 )
891 {
892 wxString msg;
893 int gap_override = pad->GetLocalThermalGapOverride( &msg );
894
895 REPORT( "" )
896 REPORT( wxString::Format( _( "Local override on %s; thermal relief gap: %s." ),
897 EscapeHTML( pad->GetItemDescription( this, true ) ),
898 EscapeHTML( MessageTextFromValue( gap_override ) ) ) )
899
900 constraint.SetName( msg );
901 constraint.m_Value.SetMin( gap_override );
902 return constraint;
903 }
904 }
905 else if( aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT )
906 {
907 if( pad && pad->GetLocalSpokeWidthOverride( nullptr ) > 0 )
908 {
909 wxString msg;
910 int spoke_override = pad->GetLocalSpokeWidthOverride( &msg );
911
912 REPORT( "" )
913 REPORT( wxString::Format( _( "Local override on %s; thermal spoke width: %s." ),
914 EscapeHTML( pad->GetItemDescription( this, true ) ),
915 EscapeHTML( MessageTextFromValue( spoke_override ) ) ) )
916
917 if( zone && zone->GetMinThickness() > spoke_override )
918 {
919 spoke_override = zone->GetMinThickness();
920
921 REPORT( "" )
922 REPORT( wxString::Format( _( "%s min thickness: %s." ),
923 EscapeHTML( zone->GetItemDescription( this, true ) ),
924 EscapeHTML( MessageTextFromValue( spoke_override ) ) ) )
925 }
926
927 constraint.SetName( msg );
928 constraint.m_Value.SetMin( spoke_override );
929 return constraint;
930 }
931 }
932
933 auto testAssertion =
934 [&]( const DRC_ENGINE_CONSTRAINT* c )
935 {
936 REPORT( wxString::Format( _( "Checking assertion \"%s\"." ),
937 EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
938
939 if( c->constraint.m_Test->EvaluateFor( a, b, c->constraint.m_Type, aLayer,
940 aReporter ) )
941 {
942 REPORT( _( "Assertion passed." ) )
943 }
944 else
945 {
946 REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
947 }
948 };
949
950 auto processConstraint =
951 [&]( const DRC_ENGINE_CONSTRAINT* c )
952 {
953 bool implicit = c->parentRule && c->parentRule->m_Implicit;
954
955 REPORT( "" )
956
957 switch( c->constraint.m_Type )
958 {
966 REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
967 EscapeHTML( c->constraint.GetName() ),
968 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
969 break;
971 REPORT( wxString::Format( _( "Checking %s creepage: %s." ),
972 EscapeHTML( c->constraint.GetName() ),
973 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
974 break;
976 REPORT( wxString::Format( _( "Checking %s max uncoupled length: %s." ),
977 EscapeHTML( c->constraint.GetName() ),
978 MessageTextFromValue( c->constraint.m_Value.Max() ) ) )
979 break;
980
981 case SKEW_CONSTRAINT:
982 REPORT( wxString::Format( _( "Checking %s max skew: %s." ),
983 EscapeHTML( c->constraint.GetName() ),
984 MessageTextFromValue( c->constraint.m_Value.Max() ) ) )
985 break;
986
988 REPORT( wxString::Format( _( "Checking %s gap: %s." ),
989 EscapeHTML( c->constraint.GetName() ),
990 MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
991 break;
992
994 REPORT( wxString::Format( _( "Checking %s thermal spoke width: %s." ),
995 EscapeHTML( c->constraint.GetName() ),
996 MessageTextFromValue( c->constraint.m_Value.Opt() ) ) )
997 break;
998
1000 REPORT( wxString::Format( _( "Checking %s min spoke count: %s." ),
1001 EscapeHTML( c->constraint.GetName() ),
1003 c->constraint.m_Value.Min() ) ) )
1004 break;
1005
1007 REPORT( wxString::Format( _( "Checking %s zone connection: %s." ),
1008 EscapeHTML( c->constraint.GetName() ),
1009 EscapeHTML( PrintZoneConnection( c->constraint.m_ZoneConnection ) ) ) )
1010 break;
1011
1019 case LENGTH_CONSTRAINT:
1022 {
1023 if( aReporter )
1024 {
1025 wxString min = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
1026 wxString opt = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
1027 wxString max = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
1028
1029 if( implicit )
1030 {
1031 min = MessageTextFromValue( c->constraint.m_Value.Min() );
1032 opt = MessageTextFromValue( c->constraint.m_Value.Opt() );
1033
1034 switch( c->constraint.m_Type )
1035 {
1037 if( c->constraint.m_Value.HasOpt() )
1038 {
1039 REPORT( wxString::Format( _( "Checking %s track width: opt %s." ),
1040 EscapeHTML( c->constraint.GetName() ),
1041 opt ) )
1042 }
1043 else if( c->constraint.m_Value.HasMin() )
1044 {
1045 REPORT( wxString::Format( _( "Checking %s track width: min %s." ),
1046 EscapeHTML( c->constraint.GetName() ),
1047 min ) )
1048 }
1049
1050 break;
1051
1053 REPORT( wxString::Format( _( "Checking %s annular width: min %s." ),
1054 EscapeHTML( c->constraint.GetName() ),
1055 opt ) )
1056 break;
1057
1059 if( c->constraint.m_Value.HasOpt() )
1060 {
1061 REPORT( wxString::Format( _( "Checking %s via diameter: opt %s." ),
1062 EscapeHTML( c->constraint.GetName() ),
1063 opt ) )
1064 }
1065 else if( c->constraint.m_Value.HasMin() )
1066 {
1067 REPORT( wxString::Format( _( "Checking %s via diameter: min %s." ),
1068 EscapeHTML( c->constraint.GetName() ),
1069 min ) )
1070 }
1071 break;
1072
1074 if( c->constraint.m_Value.HasOpt() )
1075 {
1076 REPORT( wxString::Format( _( "Checking %s hole size: opt %s." ),
1077 EscapeHTML( c->constraint.GetName() ),
1078 opt ) )
1079 }
1080 else if( c->constraint.m_Value.HasMin() )
1081 {
1082 REPORT( wxString::Format( _( "Checking %s hole size: min %s." ),
1083 EscapeHTML( c->constraint.GetName() ),
1084 min ) )
1085 }
1086
1087 break;
1088
1092 REPORT( wxString::Format( _( "Checking %s: min %s." ),
1093 EscapeHTML( c->constraint.GetName() ),
1094 min ) )
1095 break;
1096
1098 if( c->constraint.m_Value.HasOpt() )
1099 {
1100 REPORT( wxString::Format( _( "Checking %s diff pair gap: opt %s." ),
1101 EscapeHTML( c->constraint.GetName() ),
1102 opt ) )
1103 }
1104 else if( c->constraint.m_Value.HasMin() )
1105 {
1106 REPORT( wxString::Format( _( "Checking %s clearance: min %s." ),
1107 EscapeHTML( c->constraint.GetName() ),
1108 min ) )
1109 }
1110
1111 break;
1112
1114 REPORT( wxString::Format( _( "Checking %s hole to hole: min %s." ),
1115 EscapeHTML( c->constraint.GetName() ),
1116 min ) )
1117 break;
1118
1119 default:
1120 REPORT( wxString::Format( _( "Checking %s." ),
1121 EscapeHTML( c->constraint.GetName() ) ) )
1122 }
1123 }
1124 else
1125 {
1126 if( c->constraint.m_Value.HasMin() )
1127 min = MessageTextFromValue( c->constraint.m_Value.Min() );
1128
1129 if( c->constraint.m_Value.HasOpt() )
1130 opt = MessageTextFromValue( c->constraint.m_Value.Opt() );
1131
1132 if( c->constraint.m_Value.HasMax() )
1133 max = MessageTextFromValue( c->constraint.m_Value.Max() );
1134
1135 REPORT( wxString::Format( _( "Checking %s: min %s; opt %s; max %s." ),
1136 EscapeHTML( c->constraint.GetName() ),
1137 min,
1138 opt,
1139 max ) )
1140 }
1141 }
1142 break;
1143 }
1144
1145 default:
1146 REPORT( wxString::Format( _( "Checking %s." ),
1147 EscapeHTML( c->constraint.GetName() ) ) )
1148 }
1149
1150 if( c->constraint.m_Type == CLEARANCE_CONSTRAINT )
1151 {
1152 if( a_is_non_copper || b_is_non_copper )
1153 {
1154 if( implicit )
1155 {
1156 REPORT( _( "Netclass clearances apply only between copper items." ) )
1157 }
1158 else if( a_is_non_copper )
1159 {
1160 REPORT( wxString::Format( _( "%s contains no copper. Rule ignored." ),
1161 EscapeHTML( a->GetItemDescription( this, true ) ) ) )
1162 }
1163 else if( b_is_non_copper )
1164 {
1165 REPORT( wxString::Format( _( "%s contains no copper. Rule ignored." ),
1166 EscapeHTML( b->GetItemDescription( this, true ) ) ) )
1167 }
1168
1169 return;
1170 }
1171 }
1172 else if( c->constraint.m_Type == DISALLOW_CONSTRAINT )
1173 {
1174 int mask;
1175
1176 if( a->GetFlags() & HOLE_PROXY )
1177 {
1178 mask = DRC_DISALLOW_HOLES;
1179 }
1180 else if( a->Type() == PCB_VIA_T )
1181 {
1182 mask = DRC_DISALLOW_VIAS;
1183
1184 switch( static_cast<const PCB_VIA*>( a )->GetViaType() )
1185 {
1186 case VIATYPE::BLIND_BURIED: mask |= DRC_DISALLOW_BB_VIAS; break;
1187 case VIATYPE::MICROVIA: mask |= DRC_DISALLOW_MICRO_VIAS; break;
1188 default: break;
1189 }
1190 }
1191 else
1192 {
1193 switch( a->Type() )
1194 {
1195 case PCB_TRACE_T: mask = DRC_DISALLOW_TRACKS; break;
1196 case PCB_ARC_T: mask = DRC_DISALLOW_TRACKS; break;
1197 case PCB_PAD_T: mask = DRC_DISALLOW_PADS; break;
1198 case PCB_FOOTPRINT_T: mask = DRC_DISALLOW_FOOTPRINTS; break;
1199 case PCB_SHAPE_T: mask = DRC_DISALLOW_GRAPHICS; break;
1200 case PCB_FIELD_T: mask = DRC_DISALLOW_TEXTS; break;
1201 case PCB_TEXT_T: mask = DRC_DISALLOW_TEXTS; break;
1202 case PCB_TEXTBOX_T: mask = DRC_DISALLOW_TEXTS; break;
1203 case PCB_TABLE_T: mask = DRC_DISALLOW_TEXTS; break;
1204
1205 case PCB_ZONE_T:
1206 // Treat teardrop areas as tracks for DRC purposes
1207 if( static_cast<const ZONE*>( a )->IsTeardropArea() )
1208 mask = DRC_DISALLOW_TRACKS;
1209 else
1210 mask = DRC_DISALLOW_ZONES;
1211
1212 break;
1213
1214 case PCB_LOCATE_HOLE_T: mask = DRC_DISALLOW_HOLES; break;
1215 default: mask = 0; break;
1216 }
1217 }
1218
1219 if( ( c->constraint.m_DisallowFlags & mask ) == 0 )
1220 {
1221 if( implicit )
1222 REPORT( _( "Keepout constraint not met." ) )
1223 else
1224 REPORT( _( "Disallow constraint not met." ) )
1225
1226 return;
1227 }
1228
1229 LSET itemLayers = a->GetLayerSet();
1230
1231 if( a->Type() == PCB_FOOTPRINT_T )
1232 {
1233 const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( a );
1234
1235 if( !footprint->GetCourtyard( F_CrtYd ).IsEmpty() )
1236 itemLayers |= LSET::FrontMask();
1237
1238 if( !footprint->GetCourtyard( B_CrtYd ).IsEmpty() )
1239 itemLayers |= LSET::BackMask();
1240 }
1241
1242 if( !( c->layerTest & itemLayers ).any() )
1243 {
1244 if( implicit )
1245 {
1246 REPORT( _( "Keepout layer(s) not matched." ) )
1247 }
1248 else if( c->parentRule )
1249 {
1250 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1251 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1252 }
1253 else
1254 {
1255 REPORT( _( "Rule layer not matched; rule ignored." ) )
1256 }
1257
1258 return;
1259 }
1260 }
1261
1262 if( ( aLayer != UNDEFINED_LAYER && !c->layerTest.test( aLayer ) )
1263 || ( m_board->GetEnabledLayers() & c->layerTest ).count() == 0 )
1264 {
1265 if( implicit )
1266 {
1267 REPORT( _( "Constraint layer 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 else if( c->constraint.m_Type == HOLE_TO_HOLE_CONSTRAINT
1280 && ( !a->HasDrilledHole() && !b->HasDrilledHole() ) )
1281 {
1282 // Report non-drilled-holes as an implicit condition
1283 REPORT( wxString::Format( _( "%s is not a drilled hole; rule ignored." ),
1284 a->GetItemDescription( this, true ) ) )
1285 }
1286 else if( !c->condition || c->condition->GetExpression().IsEmpty() )
1287 {
1288 if( aReporter )
1289 {
1290 if( implicit )
1291 {
1292 REPORT( _( "Unconditional constraint applied." ) )
1293 }
1294 else if( constraint.m_Type == ASSERTION_CONSTRAINT )
1295 {
1296 REPORT( _( "Unconditional rule applied." ) )
1297 testAssertion( c );
1298 }
1299 else
1300 {
1301 REPORT( _( "Unconditional rule applied; overrides previous constraints." ) )
1302 }
1303 }
1304
1305 applyConstraint( c );
1306 }
1307 else
1308 {
1309 if( implicit )
1310 {
1311 // Don't report on implicit rule conditions; they're synthetic.
1312 }
1313 else
1314 {
1315 REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
1316 EscapeHTML( c->condition->GetExpression() ) ) )
1317 }
1318
1319 if( c->condition->EvaluateFor( a, b, c->constraint.m_Type, aLayer, aReporter ) )
1320 {
1321 if( aReporter )
1322 {
1323 if( implicit )
1324 {
1325 REPORT( _( "Constraint applied." ) )
1326 }
1327 else if( constraint.m_Type == ASSERTION_CONSTRAINT )
1328 {
1329 REPORT( _( "Rule applied." ) )
1330 testAssertion( c );
1331 }
1332 else
1333 {
1334 REPORT( _( "Rule applied; overrides previous constraints." ) )
1335 }
1336 }
1337
1338 applyConstraint( c );
1339 }
1340 else
1341 {
1342 REPORT( implicit ? _( "Membership not satisfied; constraint ignored." )
1343 : _( "Condition not satisfied; rule ignored." ) )
1344 }
1345 }
1346 };
1347
1348 if( m_constraintMap.count( aConstraintType ) )
1349 {
1350 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
1351
1352 for( int ii = 0; ii < (int) ruleset->size(); ++ii )
1353 processConstraint( ruleset->at( ii ) );
1354 }
1355
1356 if( constraint.GetParentRule() && !constraint.GetParentRule()->m_Implicit )
1357 return constraint;
1358
1359 // Special case for pad zone connections which can iherit from their parent footprints.
1360 // We've already checked for local overrides, and there were no rules targetting the pad
1361 // itself, so we know we're inheriting and need to see if there are any rules targetting
1362 // the parent footprint.
1363 if( pad && parentFootprint && ( aConstraintType == ZONE_CONNECTION_CONSTRAINT
1364 || aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT
1365 || aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT ) )
1366 {
1367 if( a == pad )
1368 a = parentFootprint;
1369 else
1370 b = parentFootprint;
1371
1372 if( m_constraintMap.count( aConstraintType ) )
1373 {
1374 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
1375
1376 for( int ii = 0; ii < (int) ruleset->size(); ++ii )
1377 processConstraint( ruleset->at( ii ) );
1378
1379 if( constraint.GetParentRule() && !constraint.GetParentRule()->m_Implicit )
1380 return constraint;
1381 }
1382 }
1383
1384 // Unfortunately implicit rules don't work for local clearances (such as zones) because
1385 // they have to be max'ed with netclass values (which are already implicit rules), and our
1386 // rule selection paradigm is "winner takes all".
1387 if( aConstraintType == CLEARANCE_CONSTRAINT )
1388 {
1389 int global = constraint.m_Value.Min();
1390 int clearance = global;
1391 bool needBlankLine = true;
1392
1393 if( ac && ac->GetLocalClearance().has_value() )
1394 {
1395 int localA = ac->GetLocalClearance().value();
1396
1397 if( needBlankLine )
1398 {
1399 REPORT( "" )
1400 needBlankLine = false;
1401 }
1402
1403 REPORT( wxString::Format( _( "Local clearance on %s: %s." ),
1404 EscapeHTML( a->GetItemDescription( this, true ) ),
1405 MessageTextFromValue( localA ) ) )
1406
1407 if( localA > clearance )
1408 {
1409 wxString msg;
1410 clearance = ac->GetLocalClearance( &msg ).value();
1411 constraint.SetParentRule( nullptr );
1412 constraint.SetName( msg );
1413 constraint.m_Value.SetMin( clearance );
1414 }
1415 }
1416
1417 if( bc && bc->GetLocalClearance().has_value() )
1418 {
1419 int localB = bc->GetLocalClearance().value();
1420
1421 if( needBlankLine )
1422 {
1423 REPORT( "" )
1424 needBlankLine = false;
1425 }
1426
1427 REPORT( wxString::Format( _( "Local clearance on %s: %s." ),
1428 EscapeHTML( b->GetItemDescription( this, true ) ),
1429 MessageTextFromValue( localB ) ) )
1430
1431 if( localB > clearance )
1432 {
1433 wxString msg;
1434 clearance = bc->GetLocalClearance( &msg ).value();
1435 constraint.SetParentRule( nullptr );
1436 constraint.SetName( msg );
1437 constraint.m_Value.SetMin( clearance );
1438 }
1439 }
1440
1441 if( !a_is_non_copper && !b_is_non_copper )
1442 {
1443 if( needBlankLine )
1444 {
1445 REPORT( "" )
1446 needBlankLine = false;
1447 }
1448
1449 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
1451
1452 if( clearance < m_designSettings->m_MinClearance )
1453 {
1454 constraint.SetParentRule( nullptr );
1455 constraint.SetName( _( "board minimum" ) );
1457 }
1458 }
1459
1460 return constraint;
1461 }
1462 else if( aConstraintType == DIFF_PAIR_GAP_CONSTRAINT )
1463 {
1464 REPORT( "" )
1465 REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
1467
1468 if( constraint.m_Value.Min() < m_designSettings->m_MinClearance )
1469 {
1470 constraint.SetParentRule( nullptr );
1471 constraint.SetName( _( "board minimum" ) );
1473 }
1474
1475 return constraint;
1476 }
1477 else if( aConstraintType == ZONE_CONNECTION_CONSTRAINT )
1478 {
1479 if( pad && parentFootprint )
1480 {
1481 ZONE_CONNECTION local = parentFootprint->GetLocalZoneConnection();
1482
1483 if( local != ZONE_CONNECTION::INHERITED )
1484 {
1485 REPORT( "" )
1486 REPORT( wxString::Format( _( "%s zone connection: %s." ),
1487 EscapeHTML( parentFootprint->GetItemDescription( this, true ) ),
1488 EscapeHTML( PrintZoneConnection( local ) ) ) )
1489
1490 constraint.SetParentRule( nullptr );
1491 constraint.SetName( _( "footprint" ) );
1492 constraint.m_ZoneConnection = local;
1493 return constraint;
1494 }
1495 }
1496
1497 if( zone )
1498 {
1499 ZONE_CONNECTION local = zone->GetPadConnection();
1500
1501 REPORT( "" )
1502 REPORT( wxString::Format( _( "%s pad connection: %s." ),
1503 EscapeHTML( zone->GetItemDescription( this, true ) ),
1504 EscapeHTML( PrintZoneConnection( local ) ) ) )
1505
1506 constraint.SetParentRule( nullptr );
1507 constraint.SetName( _( "zone" ) );
1508 constraint.m_ZoneConnection = local;
1509 return constraint;
1510 }
1511 }
1512 else if( aConstraintType == THERMAL_RELIEF_GAP_CONSTRAINT )
1513 {
1514 if( zone )
1515 {
1516 int local = zone->GetThermalReliefGap();
1517
1518 REPORT( "" )
1519 REPORT( wxString::Format( _( "%s thermal relief gap: %s." ),
1520 EscapeHTML( zone->GetItemDescription( this, true ) ),
1521 EscapeHTML( MessageTextFromValue( local ) ) ) )
1522
1523 constraint.SetParentRule( nullptr );
1524 constraint.SetName( _( "zone" ) );
1525 constraint.m_Value.SetMin( local );
1526 return constraint;
1527 }
1528 }
1529 else if( aConstraintType == THERMAL_SPOKE_WIDTH_CONSTRAINT )
1530 {
1531 if( zone )
1532 {
1533 int local = zone->GetThermalReliefSpokeWidth();
1534
1535 REPORT( "" )
1536 REPORT( wxString::Format( _( "%s thermal spoke width: %s." ),
1537 EscapeHTML( zone->GetItemDescription( this, true ) ),
1538 EscapeHTML( MessageTextFromValue( local ) ) ) )
1539
1540 constraint.SetParentRule( nullptr );
1541 constraint.SetName( _( "zone" ) );
1542 constraint.m_Value.SetMin( local );
1543 return constraint;
1544 }
1545 }
1546
1547 if( !constraint.GetParentRule() )
1548 {
1549 constraint.m_Type = NULL_CONSTRAINT;
1550 constraint.m_DisallowFlags = 0;
1551 }
1552
1553 return constraint;
1554}
1555
1556
1558 std::function<void( const DRC_CONSTRAINT* )> aFailureHandler,
1559 REPORTER* aReporter )
1560{
1561 /*
1562 * NOTE: all string manipulation MUST BE KEPT INSIDE the REPORT macro. It absolutely
1563 * kills performance when running bulk DRC tests (where aReporter is nullptr).
1564 */
1565
1566 auto testAssertion =
1567 [&]( const DRC_ENGINE_CONSTRAINT* c )
1568 {
1569 REPORT( wxString::Format( _( "Checking rule assertion \"%s\"." ),
1570 EscapeHTML( c->constraint.m_Test->GetExpression() ) ) )
1571
1572 if( c->constraint.m_Test->EvaluateFor( a, nullptr, c->constraint.m_Type,
1573 a->GetLayer(), aReporter ) )
1574 {
1575 REPORT( _( "Assertion passed." ) )
1576 }
1577 else
1578 {
1579 REPORT( EscapeHTML( _( "--> Assertion failed. <--" ) ) )
1580 aFailureHandler( &c->constraint );
1581 }
1582 };
1583
1584 auto processConstraint =
1585 [&]( const DRC_ENGINE_CONSTRAINT* c )
1586 {
1587 REPORT( "" )
1588 REPORT( wxString::Format( _( "Checking %s." ), c->constraint.GetName() ) )
1589
1590 if( !( a->GetLayerSet() & c->layerTest ).any() )
1591 {
1592 REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1593 EscapeHTML( c->parentRule->m_LayerSource ) ) )
1594 }
1595
1596 if( !c->condition || c->condition->GetExpression().IsEmpty() )
1597 {
1598 REPORT( _( "Unconditional rule applied." ) )
1599 testAssertion( c );
1600 }
1601 else
1602 {
1603 REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
1604 EscapeHTML( c->condition->GetExpression() ) ) )
1605
1606 if( c->condition->EvaluateFor( a, nullptr, c->constraint.m_Type,
1607 a->GetLayer(), aReporter ) )
1608 {
1609 REPORT( _( "Rule applied." ) )
1610 testAssertion( c );
1611 }
1612 else
1613 {
1614 REPORT( _( "Condition not satisfied; rule ignored." ) )
1615 }
1616 }
1617 };
1618
1620 {
1621 std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ ASSERTION_CONSTRAINT ];
1622
1623 for( int ii = 0; ii < (int) ruleset->size(); ++ii )
1624 processConstraint( ruleset->at( ii ) );
1625 }
1626}
1627
1628
1629#undef REPORT
1630
1631
1633{
1634 assert( error_code >= 0 && error_code <= DRCE_LAST );
1635 return m_errorLimits[ error_code ] <= 0;
1636}
1637
1638
1639void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, const VECTOR2I& aPos,
1640 int aMarkerLayer, DRC_CUSTOM_MARKER_HANDLER* aCustomHandler )
1641{
1642 static std::mutex globalLock;
1643
1644 m_errorLimits[ aItem->GetErrorCode() ] -= 1;
1645
1646 if( m_violationHandler )
1647 {
1648 std::lock_guard<std::mutex> guard( globalLock );
1649 m_violationHandler( aItem, aPos, aMarkerLayer, aCustomHandler );
1650 }
1651
1652 if( m_reporter )
1653 {
1654 wxString msg = wxString::Format( wxT( "Test '%s': %s (code %d)" ),
1655 aItem->GetViolatingTest()->GetName(),
1656 aItem->GetErrorMessage(),
1657 aItem->GetErrorCode() );
1658
1659 DRC_RULE* rule = aItem->GetViolatingRule();
1660
1661 if( rule )
1662 msg += wxString::Format( wxT( ", violating rule: '%s'" ), rule->m_Name );
1663
1664 m_reporter->Report( msg );
1665
1666 wxString violatingItemsStr = wxT( "Violating items: " );
1667
1668 m_reporter->Report( wxString::Format( wxT( " |- violating position (%d, %d)" ),
1669 aPos.x,
1670 aPos.y ) );
1671 }
1672}
1673
1674
1675void DRC_ENGINE::ReportAux ( const wxString& aStr )
1676{
1677 if( !m_reporter )
1678 return;
1679
1681}
1682
1683
1685{
1686 if( !m_progressReporter )
1687 return true;
1688
1689 return m_progressReporter->KeepRefreshing( aWait );
1690}
1691
1692
1694{
1695 if( m_progressReporter )
1697}
1698
1699
1701{
1702 if( m_progressReporter )
1704}
1705
1706
1707bool DRC_ENGINE::ReportProgress( double aProgress )
1708{
1709 if( !m_progressReporter )
1710 return true;
1711
1713 return m_progressReporter->KeepRefreshing( false );
1714}
1715
1716
1717bool DRC_ENGINE::ReportPhase( const wxString& aMessage )
1718{
1719 if( !m_progressReporter )
1720 return true;
1721
1722 m_progressReporter->AdvancePhase( aMessage );
1723 bool retval = m_progressReporter->KeepRefreshing( false );
1724 wxSafeYield( nullptr, true ); // Force an update for the message
1725 return retval;
1726}
1727
1728
1730{
1732}
1733
1734
1736{
1737 //drc_dbg(10,"hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size( ) );
1738 if( m_constraintMap.count( constraintID ) )
1739 return m_constraintMap[ constraintID ]->size() > 0;
1740
1741 return false;
1742}
1743
1744
1746{
1747 int worst = 0;
1748
1749 if( m_constraintMap.count( aConstraintId ) )
1750 {
1751 for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
1752 {
1753 int current = c->constraint.GetValue().Min();
1754
1755 if( current > worst )
1756 {
1757 worst = current;
1758 aConstraint = c->constraint;
1759 }
1760 }
1761 }
1762
1763 return worst > 0;
1764}
1765
1766
1768{
1769 std::set<int> distinctMinimums;
1770
1771 if( m_constraintMap.count( aConstraintId ) )
1772 {
1773 for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
1774 distinctMinimums.emplace( c->constraint.GetValue().Min() );
1775 }
1776
1777 return distinctMinimums;
1778}
1779
1780
1781// fixme: move two functions below to pcbcommon?
1782int DRC_ENGINE::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet,
1783 wxString& aBaseDpName )
1784{
1785 int rv = 0;
1786 int count = 0;
1787
1788 for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
1789 {
1790 int ch = *it;
1791
1792 if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
1793 {
1794 continue;
1795 }
1796 else if( ch == '+' )
1797 {
1798 aComplementNet = wxT( "-" );
1799 rv = 1;
1800 }
1801 else if( ch == '-' )
1802 {
1803 aComplementNet = wxT( "+" );
1804 rv = -1;
1805 }
1806 else if( ch == 'N' )
1807 {
1808 aComplementNet = wxT( "P" );
1809 rv = -1;
1810 }
1811 else if ( ch == 'P' )
1812 {
1813 aComplementNet = wxT( "N" );
1814 rv = 1;
1815 }
1816 else
1817 {
1818 break;
1819 }
1820 }
1821
1822 if( rv != 0 && count >= 1 )
1823 {
1824 aBaseDpName = aNetName.Left( aNetName.Length() - count );
1825 aComplementNet = wxString( aBaseDpName ) << aComplementNet << aNetName.Right( count - 1 );
1826 }
1827
1828 return rv;
1829}
1830
1831
1832bool DRC_ENGINE::IsNetADiffPair( BOARD* aBoard, NETINFO_ITEM* aNet, int& aNetP, int& aNetN )
1833{
1834 wxString refName = aNet->GetNetname();
1835 wxString dummy, coupledNetName;
1836
1837 if( int polarity = MatchDpSuffix( refName, coupledNetName, dummy ) )
1838 {
1839 NETINFO_ITEM* net = aBoard->FindNet( coupledNetName );
1840
1841 if( !net )
1842 return false;
1843
1844 if( polarity > 0 )
1845 {
1846 aNetP = aNet->GetNetCode();
1847 aNetN = net->GetNetCode();
1848 }
1849 else
1850 {
1851 aNetP = net->GetNetCode();
1852 aNetN = aNet->GetNetCode();
1853 }
1854
1855 return true;
1856 }
1857
1858 return false;
1859}
1860
1861
1866bool DRC_ENGINE::IsNetTieExclusion( int aTrackNetCode, PCB_LAYER_ID aTrackLayer,
1867 const VECTOR2I& aCollisionPos, BOARD_ITEM* aCollidingItem )
1868{
1869 FOOTPRINT* parentFootprint = aCollidingItem->GetParentFootprint();
1870
1871 if( parentFootprint && parentFootprint->IsNetTie() )
1872 {
1874 std::map<wxString, int> padToNetTieGroupMap = parentFootprint->MapPadNumbersToNetTieGroups();
1875
1876 for( PAD* pad : parentFootprint->Pads() )
1877 {
1878 if( padToNetTieGroupMap[ pad->GetNumber() ] >= 0 && aTrackNetCode == pad->GetNetCode() )
1879 {
1880 if( pad->GetEffectiveShape( aTrackLayer )->Collide( aCollisionPos, epsilon ) )
1881 return true;
1882 }
1883 }
1884 }
1885
1886 return false;
1887}
1888
1889
1891{
1892 for( DRC_TEST_PROVIDER* prov : m_testProviders )
1893 {
1894 if( name == prov->GetName() )
1895 return prov;
1896 }
1897
1898 return nullptr;
1899}
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
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:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:239
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:133
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:298
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:259
virtual bool HasDrilledHole() const
Definition: board_item.h:160
virtual bool IsOnCopperLayer() const
Definition: board_item.h:150
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:295
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:831
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1992
const ZONES & Zones() const
Definition: board.h:340
void SynchronizeNetsAndNetClasses(bool aResetTrackAndViaSizes)
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition: board.cpp:2125
void IncrementTimeStamp()
Definition: board.cpp:258
const FOOTPRINTS & Footprints() const
Definition: board.h:336
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:948
int GetTimeStamp() const
Definition: board.h:318
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:690
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:656
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:111
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:128
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: footprint.h:286
std::map< wxString, int > MapPadNumbersToNetTieGroups() const
Definition: footprint.cpp:3219
std::deque< PAD * > & Pads()
Definition: footprint.h:204
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:508
bool IsNetTie() const
Definition: footprint.h:295
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:3027
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:675
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:682
T Min() const
Definition: minoptmax.h:33
void SetMin(T v)
Definition: minoptmax.h:41
void SetOpt(T v)
Definition: minoptmax.h:43
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
int GetNetCode() const
Definition: netinfo.h:108
Definition: pad.h:54
A small class to help profiling.
Definition: profile.h:49
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition: profile.h:88
double msecs(bool aSinceLast=false)
Definition: profile.h:149
virtual bool IsCancelled() const =0
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
virtual void AdvanceProgress()=0
Increment the progress bar length (inside the current virtual zone).
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
virtual void SetMaxProgress(int aMaxProgress)=0
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:72
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
void SetUserUnits(EDA_UNITS aUnits)
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition: zone.cpp:1054
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:731
bool GetDoNotAllowVias() const
Definition: zone.h:739
bool GetDoNotAllowPads() const
Definition: zone.h:741
bool GetDoNotAllowTracks() const
Definition: zone.h:740
int GetMinThickness() const
Definition: zone.h:280
ZONE_CONNECTION GetPadConnection() const
Definition: zone.h:277
int GetThermalReliefSpokeWidth() const
Definition: zone.h:224
bool GetDoNotAllowFootprints() const
Definition: zone.h:742
bool GetDoNotAllowCopperPour() const
Definition: zone.h:738
bool HasKeepoutParametersSet() const
Accessor to determine if any keepout parameters are set.
Definition: zone.h:722
int GetThermalReliefGap() const
Definition: zone.h:213
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:385
@ 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