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