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