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