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