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