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-2021 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 <reporter.h>
27 #include <progress_reporter.h>
28 #include <string_utils.h>
29 #include <board_design_settings.h>
30 #include <drc/drc_engine.h>
31 #include <drc/drc_rtree.h>
32 #include <drc/drc_rule_parser.h>
33 #include <drc/drc_rule.h>
34 #include <drc/drc_rule_condition.h>
35 #include <drc/drc_test_provider.h>
36 #include <footprint.h>
37 #include <pad.h>
38 #include <pcb_track.h>
39 #include <zone.h>
40 #include <geometry/shape.h>
41 #include <geometry/shape_segment.h>
42 #include <geometry/shape_null.h>
44 
45 void drcPrintDebugMessage( int level, const wxString& msg, const char *function, int line )
46 {
47  wxString valueStr;
48 
49  if( wxGetEnv( "DRC_DEBUG", &valueStr ) )
50  {
51  int setLevel = wxAtoi( valueStr );
52 
53  if( level <= setLevel )
54  {
55  printf("%-30s:%d | %s\n", function, line, (const char *) msg.c_str() );
56  }
57  }
58 }
59 
60 
62  m_designSettings ( aSettings ),
63  m_board( aBoard ),
64  m_drawingSheet( nullptr ),
65  m_schematicNetlist( nullptr ),
66  m_rulesValid( false ),
67  m_userUnits( EDA_UNITS::MILLIMETRES ),
68  m_reportAllTrackErrors( false ),
69  m_testFootprints( false ),
70  m_reporter( nullptr ),
71  m_progressReporter( nullptr )
72 {
73  m_errorLimits.resize( DRCE_LAST + 1 );
74 
75  for( int ii = DRCE_FIRST; ii <= DRCE_LAST; ++ii )
76  m_errorLimits[ ii ] = INT_MAX;
77 }
78 
79 
81 {
82  for( DRC_RULE* rule : m_rules )
83  delete rule;
84 
85  for( std::pair<DRC_CONSTRAINT_T, std::vector<DRC_ENGINE_CONSTRAINT*>*> pair : m_constraintMap )
86  {
87  for( DRC_ENGINE_CONSTRAINT* constraint : *pair.second )
88  delete constraint;
89 
90  delete pair.second;
91  }
92 }
93 
94 
95 static bool isKeepoutZone( const BOARD_ITEM* aItem, bool aCheckFlags )
96 {
97  if( !aItem )
98  return false;
99 
100  if( aItem->Type() != PCB_ZONE_T && aItem->Type() != PCB_FP_ZONE_T )
101  return false;
102 
103  const ZONE* zone = static_cast<const ZONE*>( aItem );
104 
105  if( !zone->GetIsRuleArea() )
106  return false;
107 
108  if( aCheckFlags )
109  {
110  if( !zone->GetDoNotAllowTracks()
111  && !zone->GetDoNotAllowVias()
112  && !zone->GetDoNotAllowPads()
113  && !zone->GetDoNotAllowCopperPour()
114  && !zone->GetDoNotAllowFootprints() )
115  {
116  return false;
117  }
118  }
119 
120  return true;
121 }
122 
123 
125 {
126  DRC_RULE *rule = new DRC_RULE;
127 
128  rule->m_Name = name;
129  rule->m_Implicit = true;
130 
131  addRule( rule );
132 
133  return rule;
134 }
135 
136 
138 {
139  ReportAux( wxString::Format( "Building implicit rules (per-item/class overrides, etc...)" ) );
140 
142 
143  // 1) global defaults
144 
145  DRC_RULE* rule = createImplicitRule( _( "board setup constraints" ) );
146 
147  DRC_CONSTRAINT clearanceConstraint( CLEARANCE_CONSTRAINT );
148  clearanceConstraint.Value().SetMin( bds.m_MinClearance );
149  rule->AddConstraint( clearanceConstraint );
150 
151  DRC_CONSTRAINT widthConstraint( TRACK_WIDTH_CONSTRAINT );
152  widthConstraint.Value().SetMin( bds.m_TrackMinWidth );
153  rule->AddConstraint( widthConstraint );
154 
155  DRC_CONSTRAINT drillConstraint( HOLE_SIZE_CONSTRAINT );
156  drillConstraint.Value().SetMin( bds.m_MinThroughDrill );
157  rule->AddConstraint( drillConstraint );
158 
159  DRC_CONSTRAINT annulusConstraint( ANNULAR_WIDTH_CONSTRAINT );
160  annulusConstraint.Value().SetMin( bds.m_ViasMinAnnularWidth );
161  rule->AddConstraint( annulusConstraint );
162 
163  DRC_CONSTRAINT diameterConstraint( VIA_DIAMETER_CONSTRAINT );
164  diameterConstraint.Value().SetMin( bds.m_ViasMinSize );
165  rule->AddConstraint( diameterConstraint );
166 
167  DRC_CONSTRAINT holeToHoleConstraint( HOLE_TO_HOLE_CONSTRAINT );
168  holeToHoleConstraint.Value().SetMin( bds.m_HoleToHoleMin );
169  rule->AddConstraint( holeToHoleConstraint );
170 
171  DRC_CONSTRAINT diffPairGapConstraint( DIFF_PAIR_GAP_CONSTRAINT );
172  diffPairGapConstraint.Value().SetMin( bds.m_MinClearance );
173  rule->AddConstraint( diffPairGapConstraint );
174 
175  rule = createImplicitRule( _( "board setup constraints silk" ) );
176  rule->m_LayerCondition = LSET( 2, F_SilkS, B_SilkS );
177  DRC_CONSTRAINT silkClearanceConstraint( SILK_CLEARANCE_CONSTRAINT );
178  silkClearanceConstraint.Value().SetMin( bds.m_SilkClearance );
179  rule->AddConstraint( silkClearanceConstraint );
180 
181  rule = createImplicitRule( _( "board setup constraints hole" ) );
182  DRC_CONSTRAINT holeClearanceConstraint( HOLE_CLEARANCE_CONSTRAINT );
183  holeClearanceConstraint.Value().SetMin( bds.m_HoleClearance );
184  rule->AddConstraint( holeClearanceConstraint );
185 
186  rule = createImplicitRule( _( "board setup constraints edge" ) );
187  DRC_CONSTRAINT edgeClearanceConstraint( EDGE_CLEARANCE_CONSTRAINT );
188  edgeClearanceConstraint.Value().SetMin( bds.m_CopperEdgeClearance );
189  rule->AddConstraint( edgeClearanceConstraint );
190 
191  rule = createImplicitRule( _( "board setup constraints courtyard" ) );
192  DRC_CONSTRAINT courtyardClearanceConstraint( COURTYARD_CLEARANCE_CONSTRAINT );
193  holeToHoleConstraint.Value().SetMin( 0 );
194  rule->AddConstraint( courtyardClearanceConstraint );
195 
196  // 2) micro-via specific defaults (new DRC doesn't treat microvias in any special way)
197 
198  DRC_RULE* uViaRule = createImplicitRule( _( "board setup micro-via constraints" ) );
199 
200  uViaRule->m_Condition = new DRC_RULE_CONDITION( "A.Via_Type == 'Micro'" );
201 
202  DRC_CONSTRAINT uViaDrillConstraint( HOLE_SIZE_CONSTRAINT );
203  uViaDrillConstraint.Value().SetMin( bds.m_MicroViasMinDrill );
204  uViaRule->AddConstraint( uViaDrillConstraint );
205 
206  DRC_CONSTRAINT uViaDiameterConstraint( VIA_DIAMETER_CONSTRAINT );
207  uViaDiameterConstraint.Value().SetMin( bds.m_MicroViasMinSize );
208  uViaRule->AddConstraint( uViaDiameterConstraint );
209 
210  if( !bds.m_MicroViasAllowed )
211  {
212  DRC_CONSTRAINT disallowConstraint( DISALLOW_CONSTRAINT );
213  disallowConstraint.m_DisallowFlags = DRC_DISALLOW_MICRO_VIAS;
214  uViaRule->AddConstraint( disallowConstraint );
215  }
216 
217  if( !bds.m_BlindBuriedViaAllowed )
218  {
219  DRC_RULE* bbViaRule = createImplicitRule( _( "board setup constraints" ) );
220 
221  bbViaRule->m_Condition = new DRC_RULE_CONDITION( "A.Via_Type == 'Blind/buried'" );
222 
223  DRC_CONSTRAINT disallowConstraint( DISALLOW_CONSTRAINT );
224  disallowConstraint.m_DisallowFlags = DRC_DISALLOW_BB_VIAS;
225  bbViaRule->AddConstraint( disallowConstraint );
226  }
227 
228  // 3) per-netclass rules
229 
230  std::vector<DRC_RULE*> netclassClearanceRules;
231  std::vector<DRC_RULE*> netclassItemSpecificRules;
232 
233  auto makeNetclassRules =
234  [&]( const NETCLASSPTR& nc, bool isDefault )
235  {
236  wxString ncName = nc->GetName();
237 
238  DRC_RULE* netclassRule;
239  wxString expr;
240 
241  if( nc->GetClearance() || nc->GetTrackWidth() )
242  {
243  netclassRule = new DRC_RULE;
244  netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ), ncName );
245  netclassRule->m_Implicit = true;
246 
247  expr = wxString::Format( "A.NetClass == '%s'", ncName );
248  netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
249  netclassClearanceRules.push_back( netclassRule );
250 
251  if( nc->GetClearance() )
252  {
253  DRC_CONSTRAINT constraint( CLEARANCE_CONSTRAINT );
254  constraint.Value().SetMin( std::max( bds.m_MinClearance,
255  nc->GetClearance() ) );
256  netclassRule->AddConstraint( constraint );
257  }
258 
259  if( nc->GetTrackWidth() )
260  {
262  constraint.Value().SetMin( bds.m_TrackMinWidth );
263  constraint.Value().SetOpt( nc->GetTrackWidth() );
264  netclassRule->AddConstraint( constraint );
265  }
266  }
267 
268  if( nc->GetDiffPairWidth() )
269  {
270  netclassRule = new DRC_RULE;
271  netclassRule->m_Name = wxString::Format( _( "netclass '%s' (diff pair)" ),
272  ncName );
273  netclassRule->m_Implicit = true;
274 
275  expr = wxString::Format( "A.NetClass == '%s' && A.inDiffPair('*')", ncName );
276  netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
277  netclassItemSpecificRules.push_back( netclassRule );
278 
280  constraint.Value().SetMin( bds.m_TrackMinWidth );
281  constraint.Value().SetOpt( nc->GetDiffPairWidth() );
282  netclassRule->AddConstraint( constraint );
283  }
284 
285  if( nc->GetDiffPairGap() )
286  {
287  netclassRule = new DRC_RULE;
288  netclassRule->m_Name = wxString::Format( _( "netclass '%s' (diff pair)" ),
289  ncName );
290  netclassRule->m_Implicit = true;
291 
292  expr = wxString::Format( "A.NetClass == '%s'", ncName );
293  netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
294  netclassItemSpecificRules.push_back( netclassRule );
295 
297  constraint.Value().SetMin( bds.m_MinClearance );
298  constraint.Value().SetOpt( nc->GetDiffPairGap() );
299  netclassRule->AddConstraint( constraint );
300 
301  // A narrower diffpair gap overrides the netclass min clearance (but is still
302  // trimmed to the board min clearance, which is absolute).
303  if( nc->GetDiffPairGap() < nc->GetClearance() )
304  {
305  netclassRule = new DRC_RULE;
306  netclassRule->m_Name = wxString::Format( _( "netclass '%s' (diff pair)" ),
307  ncName );
308  netclassRule->m_Implicit = true;
309 
310  expr = wxString::Format( "A.NetClass == '%s' && AB.isCoupledDiffPair()",
311  ncName );
312  netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
313  netclassItemSpecificRules.push_back( netclassRule );
314 
315  DRC_CONSTRAINT min_clearanceConstraint( CLEARANCE_CONSTRAINT );
316  min_clearanceConstraint.Value().SetMin( std::max( bds.m_MinClearance,
317  nc->GetDiffPairGap() ) );
318  netclassRule->AddConstraint( min_clearanceConstraint );
319  }
320  }
321 
322  if( nc->GetViaDiameter() || nc->GetViaDrill() )
323  {
324  netclassRule = new DRC_RULE;
325  netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ), ncName );
326  netclassRule->m_Implicit = true;
327 
328  expr = wxString::Format( "A.NetClass == '%s' && A.Via_Type != 'Micro'",
329  ncName );
330  netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
331  netclassItemSpecificRules.push_back( netclassRule );
332 
333  if( nc->GetViaDiameter() )
334  {
336  constraint.Value().SetMin( bds.m_ViasMinSize );
337  constraint.Value().SetOpt( nc->GetViaDiameter() );
338  netclassRule->AddConstraint( constraint );
339  }
340 
341  if( nc->GetViaDrill() )
342  {
343  DRC_CONSTRAINT constraint( HOLE_SIZE_CONSTRAINT );
344  constraint.Value().SetMin( bds.m_MinThroughDrill );
345  constraint.Value().SetOpt( nc->GetViaDrill() );
346  netclassRule->AddConstraint( constraint );
347  }
348  }
349 
350  if( nc->GetuViaDiameter() || nc->GetuViaDrill() )
351  {
352  netclassRule = new DRC_RULE;
353  netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ), ncName );
354  netclassRule->m_Implicit = true;
355 
356  expr = wxString::Format( "A.NetClass == '%s' && A.Via_Type == 'Micro'",
357  ncName );
358  netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
359  netclassItemSpecificRules.push_back( netclassRule );
360 
361  if( nc->GetuViaDiameter() )
362  {
364  constraint.Value().SetMin( bds.m_MicroViasMinSize );
365  constraint.Value().SetMin( nc->GetuViaDiameter() );
366  netclassRule->AddConstraint( constraint );
367  }
368 
369  if( nc->GetuViaDrill() )
370  {
371  DRC_CONSTRAINT constraint( HOLE_SIZE_CONSTRAINT );
372  constraint.Value().SetMin( bds.m_MicroViasMinDrill );
373  constraint.Value().SetOpt( nc->GetuViaDrill() );
374  netclassRule->AddConstraint( constraint );
375  }
376  }
377  };
378 
380  makeNetclassRules( bds.GetNetClasses().GetDefault(), true );
381 
382  for( const std::pair<const wxString, NETCLASSPTR>& netclass : bds.GetNetClasses() )
383  makeNetclassRules( netclass.second, false );
384 
385  // The netclass clearance rules have to be sorted by min clearance so the right one fires
386  // if 'A' and 'B' belong to two different netclasses.
387  //
388  // The item-specific netclass rules are all unary, so there's no 'A' vs 'B' issue.
389 
390  std::sort( netclassClearanceRules.begin(), netclassClearanceRules.end(),
391  []( DRC_RULE* lhs, DRC_RULE* rhs )
392  {
393  return lhs->m_Constraints[0].m_Value.Min()
394  < rhs->m_Constraints[0].m_Value.Min();
395  } );
396 
397  for( DRC_RULE* ncRule : netclassClearanceRules )
398  addRule( ncRule );
399 
400  for( DRC_RULE* ncRule : netclassItemSpecificRules )
401  addRule( ncRule );
402 
403  // 3) keepout area rules
404 
405  std::vector<ZONE*> keepoutZones;
406 
407  for( ZONE* zone : m_board->Zones() )
408  {
409  if( isKeepoutZone( zone, true ) )
410  keepoutZones.push_back( zone );
411  }
412 
413  for( FOOTPRINT* footprint : m_board->Footprints() )
414  {
415  for( ZONE* zone : footprint->Zones() )
416  {
417  if( isKeepoutZone( zone, true ) )
418  keepoutZones.push_back( zone );
419  }
420  }
421 
422  for( ZONE* zone : keepoutZones )
423  {
424  wxString name = zone->GetZoneName();
425 
426  if( name.IsEmpty() )
427  {
428  rule = createImplicitRule( _( "keepout area" ) );
429  name = zone->m_Uuid.AsString();
430  }
431  else
432  {
433  rule = createImplicitRule( wxString::Format( _( "keepout area '%s'" ), name ) );
434  }
435 
436  rule->m_Condition = new DRC_RULE_CONDITION( wxString::Format( "A.insideArea('%s')",
437  name ) );
438 
439  rule->m_LayerCondition = zone->GetLayerSet();
440 
441  int disallowFlags = 0;
442 
443  if( zone->GetDoNotAllowTracks() )
444  disallowFlags |= DRC_DISALLOW_TRACKS;
445 
446  if( zone->GetDoNotAllowVias() )
447  disallowFlags |= DRC_DISALLOW_VIAS;
448 
449  if( zone->GetDoNotAllowPads() )
450  disallowFlags |= DRC_DISALLOW_PADS;
451 
452  if( zone->GetDoNotAllowCopperPour() )
453  disallowFlags |= DRC_DISALLOW_ZONES;
454 
455  if( zone->GetDoNotAllowFootprints() )
456  disallowFlags |= DRC_DISALLOW_FOOTPRINTS;
457 
458  DRC_CONSTRAINT disallowConstraint( DISALLOW_CONSTRAINT );
459  disallowConstraint.m_DisallowFlags = disallowFlags;
460  rule->AddConstraint( disallowConstraint );
461  }
462 
463  ReportAux( wxString::Format( "Building %d implicit netclass rules",
464  (int) netclassClearanceRules.size() ) );
465 }
466 
467 
468 static wxString formatConstraint( const DRC_CONSTRAINT& constraint )
469 {
470  struct FORMATTER
471  {
472  DRC_CONSTRAINT_T type;
473  wxString name;
474  std::function<wxString(const DRC_CONSTRAINT&)> formatter;
475  };
476 
477  auto formatMinMax =
478  []( const DRC_CONSTRAINT& c ) -> wxString
479  {
480  wxString str;
481  const auto value = c.GetValue();
482 
483  if ( value.HasMin() )
484  str += wxString::Format( " min: %d", value.Min() );
485 
486  if ( value.HasOpt() )
487  str += wxString::Format( " opt: %d", value.Opt() );
488 
489  if ( value.HasMax() )
490  str += wxString::Format( " max: %d", value.Max() );
491 
492  return str;
493  };
494 
495  std::vector<FORMATTER> formats =
496  {
497  { CLEARANCE_CONSTRAINT, "clearance", formatMinMax },
498  { HOLE_CLEARANCE_CONSTRAINT, "hole_clearance", formatMinMax },
499  { HOLE_TO_HOLE_CONSTRAINT, "hole_to_hole", formatMinMax },
500  { EDGE_CLEARANCE_CONSTRAINT, "edge_clearance", formatMinMax },
501  { HOLE_SIZE_CONSTRAINT, "hole_size", formatMinMax },
502  { COURTYARD_CLEARANCE_CONSTRAINT, "courtyard_clearance", formatMinMax },
503  { SILK_CLEARANCE_CONSTRAINT, "silk_clearance", formatMinMax },
504  { TRACK_WIDTH_CONSTRAINT, "track_width", formatMinMax },
505  { ANNULAR_WIDTH_CONSTRAINT, "annular_width", formatMinMax },
506  { DISALLOW_CONSTRAINT, "disallow", nullptr },
507  { VIA_DIAMETER_CONSTRAINT, "via_diameter", formatMinMax },
508  { LENGTH_CONSTRAINT, "length", formatMinMax },
509  { SKEW_CONSTRAINT, "skew", formatMinMax },
510  { VIA_COUNT_CONSTRAINT, "via_count", formatMinMax }
511  };
512 
513  for( FORMATTER& fmt : formats )
514  {
515  if( fmt.type == constraint.m_Type )
516  {
517  wxString rv = fmt.name + " ";
518 
519  if( fmt.formatter )
520  rv += fmt.formatter( constraint );
521 
522  return rv;
523  }
524  }
525 
526  return "?";
527 }
528 
529 
530 void DRC_ENGINE::loadRules( const wxFileName& aPath )
531 {
532  if( aPath.FileExists() )
533  {
534  std::vector<DRC_RULE*> rules;
535 
536  FILE* fp = wxFopen( aPath.GetFullPath(), wxT( "rt" ) );
537 
538  if( fp )
539  {
540  DRC_RULES_PARSER parser( fp, aPath.GetFullPath() );
541  parser.Parse( rules, m_reporter );
542  }
543 
544  // Copy the rules into the member variable afterwards so that if Parse() throws then
545  // the possibly malformed rules won't contaminate the current ruleset.
546 
547  for( DRC_RULE* rule : rules )
548  m_rules.push_back( rule );
549  }
550 }
551 
552 
554 {
555  ReportAux( wxString::Format( "Compiling Rules (%d rules): ",
556  (int) m_rules.size() ) );
557 
558  for( DRC_TEST_PROVIDER* provider : m_testProviders )
559  {
560  ReportAux( wxString::Format( "- Provider: '%s': ", provider->GetName() ) );
561  drc_dbg( 7, "do prov %s", provider->GetName() );
562 
563  for( DRC_CONSTRAINT_T id : provider->GetConstraintTypes() )
564  {
565  drc_dbg( 7, "do id %d", id );
566 
567  if( m_constraintMap.find( id ) == m_constraintMap.end() )
568  m_constraintMap[ id ] = new std::vector<DRC_ENGINE_CONSTRAINT*>();
569 
570  for( DRC_RULE* rule : m_rules )
571  {
572  DRC_RULE_CONDITION* condition = nullptr;
573  bool compileOk = false;
574  std::vector<DRC_CONSTRAINT> matchingConstraints;
575  drc_dbg( 7, "Scan provider %s, rule %s", provider->GetName(), rule->m_Name );
576 
577  if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() )
578  {
579  condition = rule->m_Condition;
580  compileOk = condition->Compile( nullptr, 0, 0 ); // fixme
581  }
582 
583  for( const DRC_CONSTRAINT& constraint : rule->m_Constraints )
584  {
585  drc_dbg(7, "scan constraint id %d\n", constraint.m_Type );
586 
587  if( constraint.m_Type != id )
588  continue;
589 
591 
592  rcons->layerTest = rule->m_LayerCondition;
593  rcons->condition = condition;
594 
595  matchingConstraints.push_back( constraint );
596 
597  rcons->constraint = constraint;
598  rcons->parentRule = rule;
599  m_constraintMap[ id ]->push_back( rcons );
600  }
601 
602  if( !matchingConstraints.empty() )
603  {
604  ReportAux( wxString::Format( " |- Rule: '%s' ",
605  rule->m_Name ) );
606 
607  if( condition )
608  {
609  ReportAux( wxString::Format( " |- condition: '%s' compile: %s",
610  condition->GetExpression(),
611  compileOk ? "OK" : "ERROR" ) );
612  }
613 
614  for (const DRC_CONSTRAINT& constraint : matchingConstraints )
615  {
616  ReportAux( wxString::Format( " |- constraint: %s",
617  formatConstraint( constraint ) ) );
618  }
619  }
620  }
621  }
622  }
623 }
624 
625 
626 void DRC_ENGINE::InitEngine( const wxFileName& aRulePath )
627 {
629 
630  for( DRC_TEST_PROVIDER* provider : m_testProviders )
631  {
632  ReportAux( wxString::Format( "Create DRC provider: '%s'", provider->GetName() ) );
633  provider->SetDRCEngine( this );
634  }
635 
636  for( DRC_RULE* rule : m_rules )
637  delete rule;
638 
639  m_rules.clear();
640  m_rulesValid = false;
641 
642  for( std::pair<DRC_CONSTRAINT_T, std::vector<DRC_ENGINE_CONSTRAINT*>*> pair : m_constraintMap )
643  {
644  for( DRC_ENGINE_CONSTRAINT* constraint : *pair.second )
645  delete constraint;
646 
647  delete pair.second;
648  }
649 
650  m_constraintMap.clear();
651 
652  m_board->IncrementTimeStamp(); // Clear board-level caches
653 
654  try // attempt to load full set of rules (implicit + user rules)
655  {
657  loadRules( aRulePath );
658  compileRules();
659  }
660  catch( PARSE_ERROR& original_parse_error )
661  {
662  try // try again with just our implicit rules
663  {
665  compileRules();
666  }
667  catch( PARSE_ERROR& )
668  {
669  wxFAIL_MSG( "Compiling implicit rules failed." );
670  }
671 
672  throw original_parse_error;
673  }
674 
675  for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
676  m_errorLimits[ ii ] = INT_MAX;
677 
678  m_rulesValid = true;
679 }
680 
681 
682 void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints )
683 {
684  m_userUnits = aUnits;
685 
686  m_reportAllTrackErrors = aReportAllTrackErrors;
687  m_testFootprints = aTestFootprints;
688 
689  for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
690  {
691  if( m_designSettings->Ignore( ii ) )
692  m_errorLimits[ ii ] = 0;
693  else
694  m_errorLimits[ ii ] = INT_MAX;
695  }
696 
697  m_board->IncrementTimeStamp(); // Invalidate all caches
698 
699  if( !ReportPhase( _( "Tessellating copper zones..." ) ) )
700  return;
701 
702  // Number of zones between progress bar updates
703  int delta = 5;
704  std::vector<ZONE*> copperZones;
705 
706  for( ZONE* zone : m_board->Zones() )
707  {
708  zone->CacheBoundingBox();
709  zone->CacheTriangulation();
710 
711  if( !zone->GetIsRuleArea() )
712  copperZones.push_back( zone );
713  }
714 
715  for( FOOTPRINT* footprint : m_board->Footprints() )
716  {
717  for( ZONE* zone : footprint->Zones() )
718  {
719  zone->CacheBoundingBox();
720  zone->CacheTriangulation();
721 
722  if( !zone->GetIsRuleArea() )
723  copperZones.push_back( zone );
724  }
725 
726  footprint->BuildPolyCourtyards();
727  }
728 
729  int zoneCount = copperZones.size();
730 
731  for( int ii = 0; ii < zoneCount; ++ii )
732  {
733  ZONE* zone = copperZones[ ii ];
734 
735  if( ( ii % delta ) == 0 || ii == zoneCount - 1 )
736  {
737  if( !ReportProgress( (double) ii / (double) zoneCount ) )
738  return;
739  }
740 
741  m_board->m_CopperZoneRTrees[ zone ] = std::make_unique<DRC_RTREE>();
742 
743  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
744  {
745  if( IsCopperLayer( layer ) )
746  m_board->m_CopperZoneRTrees[ zone ]->Insert( zone, layer );
747  }
748  }
749 
750  for( DRC_TEST_PROVIDER* provider : m_testProviders )
751  {
752  if( !provider->IsEnabled() )
753  continue;
754 
755  drc_dbg( 0, "Running test provider: '%s'\n", provider->GetName() );
756 
757  ReportAux( wxString::Format( "Run DRC provider: '%s'", provider->GetName() ) );
758 
759  if( !provider->Run() )
760  break;
761  }
762 }
763 
764 
766  const BOARD_ITEM* b, PCB_LAYER_ID aLayer,
767  REPORTER* aReporter )
768 {
769 #define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } }
770 #define UNITS aReporter ? aReporter->GetUnits() : EDA_UNITS::MILLIMETRES
771 #define REPORT_VALUE( v ) MessageTextFromValue( UNITS, v )
772  /*
773  * NOTE: all string manipulation MUST BE KEPT INSIDE the REPORT macro. It absolutely
774  * kills performance when running bulk DRC tests (where aReporter is nullptr).
775  */
776 
777  const BOARD_CONNECTED_ITEM* ac = a && a->IsConnected() ?
778  static_cast<const BOARD_CONNECTED_ITEM*>( a ) : nullptr;
779  const BOARD_CONNECTED_ITEM* bc = b && b->IsConnected() ?
780  static_cast<const BOARD_CONNECTED_ITEM*>( b ) : nullptr;
781 
782  bool a_is_non_copper = a && ( !a->IsOnCopperLayer() || isKeepoutZone( a, false ) );
783  bool b_is_non_copper = b && ( !b->IsOnCopperLayer() || isKeepoutZone( b, false ) );
784 
785  DRC_CONSTRAINT constraint;
786  constraint.m_Type = aConstraintType;
787 
788  // Local overrides take precedence over everything *except* board min clearance
789  if( aConstraintType == CLEARANCE_CONSTRAINT || aConstraintType == HOLE_CLEARANCE_CONSTRAINT )
790  {
791  int override = 0;
792 
793  if( ac && !b_is_non_copper )
794  {
795  int overrideA = ac->GetLocalClearanceOverrides( nullptr );
796 
797  if( overrideA > 0 )
798  {
799  REPORT( "" )
800  REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
802  REPORT_VALUE( overrideA ) ) )
803 
804  override = ac->GetLocalClearanceOverrides( &m_msg );
805  }
806  }
807 
808  if( bc && !a_is_non_copper )
809  {
810  int overrideB = bc->GetLocalClearanceOverrides( nullptr );
811 
812  if( overrideB > 0 )
813  {
814  REPORT( "" )
815  REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
817  EscapeHTML( REPORT_VALUE( overrideB ) ) ) )
818 
819  if( overrideB > override )
820  override = bc->GetLocalClearanceOverrides( &m_msg );
821  }
822  }
823 
824  if( override )
825  {
826  if( aConstraintType == CLEARANCE_CONSTRAINT )
827  {
828  if( override < m_designSettings->m_MinClearance )
829  {
830  override = m_designSettings->m_MinClearance;
831  m_msg = _( "board minimum" );
832 
833  REPORT( "" )
834  REPORT( wxString::Format( _( "Board minimum clearance: %s." ),
835  REPORT_VALUE( override ) ) )
836  }
837  }
838  else
839  {
840  if( override < m_designSettings->m_HoleClearance )
841  {
842  override = m_designSettings->m_HoleClearance;
843  m_msg = _( "board minimum hole" );
844 
845  REPORT( "" )
846  REPORT( wxString::Format( _( "Board minimum hole clearance: %s." ),
847  REPORT_VALUE( override ) ) )
848  }
849  }
850 
851  constraint.SetName( m_msg );
852  constraint.m_Value.SetMin( override );
853  return constraint;
854  }
855  }
856 
857  auto processConstraint =
858  [&]( const DRC_ENGINE_CONSTRAINT* c ) -> bool
859  {
860  bool implicit = c->parentRule && c->parentRule->m_Implicit;
861 
862  REPORT( "" )
863 
864  switch( c->constraint.m_Type )
865  {
871  {
872  int val = c->constraint.m_Value.Min();
873  REPORT( wxString::Format( _( "Checking %s clearance: %s." ),
874  EscapeHTML( c->constraint.GetName() ),
875  REPORT_VALUE( val ) ) )
876  break;
877  }
878 
882  {
883  if( aReporter )
884  {
885  wxString min = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
886  wxString opt = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
887  wxString max = wxT( "<i>" ) + _( "undefined" ) + wxT( "</i>" );
888  wxString msg;
889 
890  if( implicit )
891  {
892  opt = StringFromValue( UNITS, c->constraint.m_Value.Opt(), true );
893 
894  switch( c->constraint.m_Type )
895  {
896  case TRACK_WIDTH_CONSTRAINT: msg = "track width"; break;
897  case ANNULAR_WIDTH_CONSTRAINT: msg = "annular width"; break;
898  case VIA_DIAMETER_CONSTRAINT: msg = "via diameter"; break;
899  default: msg = "constraint"; break;
900  }
901 
902  REPORT( wxString::Format( _( "Checking %s %s: %s." ),
903  EscapeHTML( c->constraint.GetName() ),
904  EscapeHTML( msg ),
905  opt ) )
906  }
907  else
908  {
909  if( c->constraint.m_Value.HasMin() )
910  min = StringFromValue( UNITS, c->constraint.m_Value.Min(), true );
911 
912  if( c->constraint.m_Value.HasOpt() )
913  opt = StringFromValue( UNITS, c->constraint.m_Value.Opt(), true );
914 
915  if( c->constraint.m_Value.HasMax() )
916  max = StringFromValue( UNITS, c->constraint.m_Value.Max(), true );
917 
918  REPORT( wxString::Format( _( "Checking %s: min %s; opt %s; max %s." ),
919  EscapeHTML( c->constraint.GetName() ),
920  min,
921  opt,
922  max ) )
923  }
924  }
925  break;
926  }
927 
928  default:
929  REPORT( wxString::Format( _( "Checking %s." ),
930  EscapeHTML( c->constraint.GetName() ) ) )
931  }
932 
933  if( c->constraint.m_Type == CLEARANCE_CONSTRAINT )
934  {
935  if( implicit && ( a_is_non_copper || b_is_non_copper ) )
936  {
937  REPORT( _( "Board and netclass clearances apply only between copper "
938  "items." ) );
939  return true;
940  }
941  }
942  else if( c->constraint.m_Type == DISALLOW_CONSTRAINT )
943  {
944  int mask;
945 
946  if( a->GetFlags() & HOLE_PROXY )
947  {
948  mask = DRC_DISALLOW_HOLES;
949  }
950  else if( a->Type() == PCB_VIA_T )
951  {
952  mask = DRC_DISALLOW_VIAS;
953 
954  switch( static_cast<const PCB_VIA*>( a )->GetViaType() )
955  {
956  case VIATYPE::BLIND_BURIED: mask |= DRC_DISALLOW_BB_VIAS; break;
957  case VIATYPE::MICROVIA: mask |= DRC_DISALLOW_MICRO_VIAS; break;
958  default: break;
959  }
960  }
961  else
962  {
963  switch( a->Type() )
964  {
965  case PCB_TRACE_T: mask = DRC_DISALLOW_TRACKS; break;
966  case PCB_ARC_T: mask = DRC_DISALLOW_TRACKS; break;
967  case PCB_PAD_T: mask = DRC_DISALLOW_PADS; break;
968  case PCB_FOOTPRINT_T: mask = DRC_DISALLOW_FOOTPRINTS; break;
969  case PCB_SHAPE_T: mask = DRC_DISALLOW_GRAPHICS; break;
970  case PCB_FP_SHAPE_T: mask = DRC_DISALLOW_GRAPHICS; break;
971  case PCB_TEXT_T: mask = DRC_DISALLOW_TEXTS; break;
972  case PCB_FP_TEXT_T: mask = DRC_DISALLOW_TEXTS; break;
973  case PCB_ZONE_T: mask = DRC_DISALLOW_ZONES; break;
974  case PCB_FP_ZONE_T: mask = DRC_DISALLOW_ZONES; break;
975  case PCB_LOCATE_HOLE_T: mask = DRC_DISALLOW_HOLES; break;
976  default: mask = 0; break;
977  }
978  }
979 
980  if( ( c->constraint.m_DisallowFlags & mask ) == 0 )
981  {
982  if( implicit )
983  REPORT( _( "Keepout constraint not met." ) )
984  else
985  REPORT( _( "Disallow constraint not met." ) )
986 
987  return false;
988  }
989 
990  LSET itemLayers = a->GetLayerSet();
991 
992  if( a->Type() == PCB_FOOTPRINT_T )
993  {
994  const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( a );
995 
996  if( !footprint->GetPolyCourtyard( F_CrtYd ).IsEmpty() )
997  itemLayers |= LSET::FrontMask();
998 
999  if( !footprint->GetPolyCourtyard( B_CrtYd ).IsEmpty() )
1000  itemLayers |= LSET::BackMask();
1001  }
1002 
1003  if( !( c->layerTest & itemLayers ).any() )
1004  {
1005  if( implicit )
1006  {
1007  REPORT( _( "Keepout layer(s) not matched." ) )
1008  }
1009  else if( c->parentRule )
1010  {
1011  REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule "
1012  "ignored." ),
1013  EscapeHTML( c->parentRule->m_LayerSource ) ) )
1014  }
1015  else
1016  {
1017  REPORT( _( "Rule layer not matched; rule ignored." ) )
1018  }
1019 
1020  return false;
1021  }
1022  }
1023 
1024  if( aLayer != UNDEFINED_LAYER && !c->layerTest.test( aLayer ) )
1025  {
1026  if( implicit )
1027  {
1028  REPORT( "Constraint layer not matched." )
1029  }
1030  else if( c->parentRule )
1031  {
1032  REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
1033  EscapeHTML( c->parentRule->m_LayerSource ) ) )
1034  }
1035  else
1036  {
1037  REPORT( _( "Rule layer not matched; rule ignored." ) )
1038  }
1039 
1040  return false;
1041  }
1042 
1043  if( !c->condition || c->condition->GetExpression().IsEmpty() )
1044  {
1045  REPORT( implicit ? _( "Unconditional constraint applied." )
1046  : _( "Unconditional rule applied." ) );
1047 
1048  constraint = c->constraint;
1049  return true;
1050  }
1051  else
1052  {
1053  if( implicit )
1054  {
1055  // Don't report on implicit rule conditions; they're synthetic.
1056  }
1057  else
1058  {
1059  REPORT( wxString::Format( _( "Checking rule condition '%s'." ),
1060  EscapeHTML( c->condition->GetExpression() ) ) )
1061  }
1062 
1063  if( c->condition->EvaluateFor( a, b, aLayer, aReporter ) )
1064  {
1065  REPORT( implicit ? _( "Constraint applied." )
1066  : _( "Rule applied; overrides previous constraints." ) )
1067 
1068  if( c->constraint.m_Value.HasMin() )
1069  constraint.m_Value.SetMin( c->constraint.m_Value.Min() );
1070 
1071  if( c->constraint.m_Value.HasOpt() )
1072  constraint.m_Value.SetOpt( c->constraint.m_Value.Opt() );
1073 
1074  if( c->constraint.m_Value.HasMax() )
1075  constraint .m_Value.SetMax( c->constraint.m_Value.Max() );
1076 
1077  // While the expectation would be to OR the disallow flags, we've already
1078  // masked them down to aItem's type -- so we're really only looking for a
1079  // boolean here.
1080  constraint.m_DisallowFlags = c->constraint.m_DisallowFlags;
1081 
1082  constraint.SetParentRule( c->constraint.GetParentRule() );
1083 
1084  return true;
1085  }
1086  else
1087  {
1088  REPORT( implicit ? _( "Membership not satisfied; constraint ignored." )
1089  : _( "Condition not satisfied; rule ignored." ) )
1090 
1091  return false;
1092  }
1093  }
1094  };
1095 
1096  if( m_constraintMap.count( aConstraintType ) )
1097  {
1098  std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintType ];
1099 
1100  for( int ii = 0; ii < (int) ruleset->size(); ++ii )
1101  processConstraint( ruleset->at( ii ) );
1102  }
1103 
1104  if( constraint.GetParentRule() && !constraint.GetParentRule()->m_Implicit )
1105  return constraint;
1106 
1107  // Unfortunately implicit rules don't work for local clearances (such as zones) because
1108  // they have to be max'ed with netclass values (which are already implicit rules), and our
1109  // rule selection paradigm is "winner takes all".
1110  if( aConstraintType == CLEARANCE_CONSTRAINT )
1111  {
1112  int global = constraint.m_Value.Min();
1113  int localA = ac ? ac->GetLocalClearance( nullptr ) : 0;
1114  int localB = bc ? bc->GetLocalClearance( nullptr ) : 0;
1115  int clearance = global;
1116 
1117  if( localA > 0 )
1118  {
1119  REPORT( "" )
1120  REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
1122  REPORT_VALUE( localA ) ) )
1123 
1124  if( localA > clearance )
1125  clearance = ac->GetLocalClearance( &m_msg );
1126  }
1127 
1128  if( localB > 0 )
1129  {
1130  REPORT( "" )
1131  REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
1133  REPORT_VALUE( localB ) ) )
1134 
1135  if( localB > clearance )
1136  clearance = bc->GetLocalClearance( &m_msg );
1137  }
1138 
1139  if( localA > global || localB > global )
1140  {
1141  constraint.SetName( m_msg );
1142  constraint.m_Value.SetMin( clearance );
1143  return constraint;
1144  }
1145  }
1146 
1147  if( !constraint.GetParentRule() )
1148  {
1149  constraint.m_Type = NULL_CONSTRAINT;
1150  constraint.m_DisallowFlags = 0;
1151  }
1152 
1153  return constraint;
1154 
1155 #undef REPORT
1156 #undef UNITS
1157 #undef REPORT_VALUE
1158 }
1159 
1160 
1161 bool DRC_ENGINE::IsErrorLimitExceeded( int error_code )
1162 {
1163  assert( error_code >= 0 && error_code <= DRCE_LAST );
1164  return m_errorLimits[ error_code ] <= 0;
1165 }
1166 
1167 
1168 void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, const wxPoint& aPos )
1169 {
1170  m_errorLimits[ aItem->GetErrorCode() ] -= 1;
1171 
1172  if( m_violationHandler )
1173  m_violationHandler( aItem, aPos );
1174 
1175  if( m_reporter )
1176  {
1177  wxString msg = wxString::Format( "Test '%s': %s (code %d)",
1178  aItem->GetViolatingTest()->GetName(),
1179  aItem->GetErrorMessage(),
1180  aItem->GetErrorCode() );
1181 
1182  DRC_RULE* rule = aItem->GetViolatingRule();
1183 
1184  if( rule )
1185  msg += wxString::Format( ", violating rule: '%s'", rule->m_Name );
1186 
1187  m_reporter->Report( msg );
1188 
1189  wxString violatingItemsStr = "Violating items: ";
1190 
1191  m_reporter->Report( wxString::Format( " |- violating position (%d, %d)",
1192  aPos.x,
1193  aPos.y ) );
1194  }
1195 }
1196 
1197 
1198 void DRC_ENGINE::ReportAux ( const wxString& aStr )
1199 {
1200  if( !m_reporter )
1201  return;
1202 
1204 }
1205 
1206 
1207 bool DRC_ENGINE::ReportProgress( double aProgress )
1208 {
1209  if( !m_progressReporter )
1210  return true;
1211 
1212  m_progressReporter->SetCurrentProgress( aProgress );
1213  return m_progressReporter->KeepRefreshing( false );
1214 }
1215 
1216 
1217 bool DRC_ENGINE::ReportPhase( const wxString& aMessage )
1218 {
1219  if( !m_progressReporter )
1220  return true;
1221 
1222  m_progressReporter->AdvancePhase( aMessage );
1223  return m_progressReporter->KeepRefreshing( false );
1224 }
1225 
1226 
1228 {
1229  //drc_dbg(10,"hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size( ) );
1230  if( m_constraintMap.count( constraintID ) )
1231  return m_constraintMap[ constraintID ]->size() > 0;
1232 
1233  return false;
1234 }
1235 
1236 
1238 {
1239  int worst = 0;
1240 
1241  if( m_constraintMap.count( aConstraintId ) )
1242  {
1243  for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
1244  {
1245  int current = c->constraint.GetValue().Min();
1246 
1247  if( current > worst )
1248  {
1249  worst = current;
1250  aConstraint = c->constraint;
1251  }
1252  }
1253  }
1254 
1255  return worst > 0;
1256 }
1257 
1258 
1259 // fixme: move two functions below to pcbcommon?
1260 int DRC_ENGINE::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet,
1261  wxString& aBaseDpName )
1262 {
1263  int rv = 0;
1264  int count = 0;
1265 
1266  for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
1267  {
1268  int ch = *it;
1269 
1270  if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
1271  {
1272  continue;
1273  }
1274  else if( ch == '+' )
1275  {
1276  aComplementNet = "-";
1277  rv = 1;
1278  }
1279  else if( ch == '-' )
1280  {
1281  aComplementNet = "+";
1282  rv = -1;
1283  }
1284  else if( ch == 'N' )
1285  {
1286  aComplementNet = "P";
1287  rv = -1;
1288  }
1289  else if ( ch == 'P' )
1290  {
1291  aComplementNet = "N";
1292  rv = 1;
1293  }
1294  else
1295  {
1296  break;
1297  }
1298  }
1299 
1300  if( rv != 0 && count >= 1 )
1301  {
1302  aBaseDpName = aNetName.Left( aNetName.Length() - count );
1303  aComplementNet = aBaseDpName + aComplementNet + aNetName.Right( count - 1 );
1304  }
1305 
1306  return rv;
1307 }
1308 
1309 
1310 bool DRC_ENGINE::IsNetADiffPair( BOARD* aBoard, NETINFO_ITEM* aNet, int& aNetP, int& aNetN )
1311 {
1312  wxString refName = aNet->GetNetname();
1313  wxString dummy, coupledNetName;
1314 
1315  if( int polarity = MatchDpSuffix( refName, coupledNetName, dummy ) )
1316  {
1317  NETINFO_ITEM* net = aBoard->FindNet( coupledNetName );
1318 
1319  if( !net )
1320  return false;
1321 
1322  if( polarity > 0 )
1323  {
1324  aNetP = aNet->GetNetCode();
1325  aNetN = net->GetNetCode();
1326  }
1327  else
1328  {
1329  aNetP = net->GetNetCode();
1330  aNetN = aNet->GetNetCode();
1331  }
1332 
1333  return true;
1334  }
1335 
1336  return false;
1337 }
1338 
1339 
1340 std::shared_ptr<SHAPE> DRC_ENGINE::GetShape( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer )
1341 {
1342  if( aItem->Type() == PCB_PAD_T && !static_cast<PAD*>( aItem )->FlashLayer( aLayer ) )
1343  {
1344  PAD* aPad = static_cast<PAD*>( aItem );
1345 
1346  if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
1347  {
1349 
1350  // Note: drill size represents finish size, which means the actual holes size is the
1351  // plating thickness larger.
1352  auto hole = static_cast<SHAPE_SEGMENT*>( aPad->GetEffectiveHoleShape()->Clone() );
1353  hole->SetWidth( hole->GetWidth() + bds.GetHolePlatingThickness() );
1354  return std::make_shared<SHAPE_SEGMENT>( *hole );
1355  }
1356 
1357  return std::make_shared<SHAPE_NULL>();
1358  }
1359 
1360  return aItem->GetEffectiveShape( aLayer );
1361 }
1362 
1363 
1365 {
1366  if( aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
1367  return static_cast<FOOTPRINT*>( aItem->GetParent() )->IsNetTie();
1368 
1369  return false;
1370 }
1371 
1372 
1374 {
1375  for( auto prov : m_testProviders )
1376  {
1377  if( name == prov->GetName() )
1378  return prov;
1379  }
1380 
1381  return nullptr;
1382 }
DRC_TEST_PROVIDER * GetTestProvider(const wxString &name) const
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1325
EDA_UNITS m_userUnits
Definition: drc_engine.h:224
#define UNITS
void loadRules(const wxFileName &aPath)
Load and parse a rule set from an sexpr text file.
Definition: drc_engine.cpp:530
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
bool GetDoNotAllowFootprints() const
Definition: zone.h:738
std::vector< int > m_errorLimits
Definition: drc_engine.h:225
ZONES & Zones()
Definition: board.h:239
bool ReportPhase(const wxString &aMessage)
DRC_RULE_CONDITION * m_Condition
Definition: drc_rule.h:99
std::vector< DRC_TEST_PROVIDER * > m_testProviders
Definition: drc_engine.h:222
bool m_Implicit
Definition: drc_rule.h:95
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:733
void SetMin(T v)
Definition: minoptmax.h:41
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:49
MINOPTMAX< int > & Value()
Definition: drc_rule.h:123
std::vector< DRC_TEST_PROVIDER * > GetTestProviders() const
static std::shared_ptr< SHAPE > GetShape(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer)
wxString m_Name
Definition: drc_rule.h:96
void SetOpt(T v)
Definition: minoptmax.h:43
static bool IsNetADiffPair(BOARD *aBoard, NETINFO_ITEM *aNet, int &aNetP, int &aNetN)
static DRC_TEST_PROVIDER_REGISTRY & Instance()
void compileRules()
Definition: drc_engine.cpp:553
int GetHolePlatingThickness() const
Pad & via drills are finish size.
bool GetDoNotAllowVias() const
Definition: zone.h:735
bool IsErrorLimitExceeded(int error_code)
bool IsEmpty() const
bool Ignore(int aDRCErrorCode)
Return true if the DRC error code's severity is SEVERITY_IGNORE.
bool m_testFootprints
Definition: drc_engine.h:227
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.cpp:295
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
const SHAPE_SEGMENT * GetEffectiveHoleShape() const
Return a SHAPE object representing the pad's hole.
Definition: pad.cpp:304
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
class PAD, a pad in a footprint
Definition: typeinfo.h:89
bool m_rulesValid
Definition: drc_engine.h:221
virtual int GetLocalClearanceOverrides(wxString *aSource) const
Return any local clearance overrides set in the "classic" (ie: pre-rule) system.
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.
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:70
static bool IsNetTie(BOARD_ITEM *aItem)
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:590
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
static LSET FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition: lset.cpp:874
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
Plated through hole pad.
DRC_RULE_CONDITION * condition
Definition: drc_engine.h:206
BOARD_DESIGN_SETTINGS * m_designSettings
Definition: drc_engine.h:215
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
bool HasRulesForConstraintType(DRC_CONSTRAINT_T constraintID)
DRC_CONSTRAINT_T
Definition: drc_rule.h:41
wxString GetExpression() const
void SynchronizeNetsAndNetClasses()
Copy NETCLASS info to each NET, based on NET membership in a NETCLASS.
Definition: board.cpp:1391
bool GetDoNotAllowPads() const
Definition: zone.h:737
bool GetDoNotAllowCopperPour() const
Definition: zone.h:734
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:504
#define HOLE_PROXY
Indicates the BOARD_ITEM is a proxy for its hole.
bool QueryWorstConstraint(DRC_CONSTRAINT_T aRuleId, DRC_CONSTRAINT &aConstraint)
void addRule(DRC_RULE *rule)
Definition: drc_engine.h:189
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
std::vector< DRC_RULE * > m_rules
Definition: drc_engine.h:220
std::vector< DRC_CONSTRAINT > m_Constraints
Definition: drc_rule.h:100
void drcPrintDebugMessage(int level, const wxString &msg, const char *function, int line)
Definition: drc_engine.cpp:45
FOOTPRINTS & Footprints()
Definition: board.h:233
bool GetDoNotAllowTracks() const
Definition: zone.h:736
void Parse(std::vector< DRC_RULE * > &aRules, REPORTER *aReporter)
bool ReportProgress(double aProgress)
const wxString & GetNetname() const
Definition: netinfo.h:121
std::unordered_map< DRC_CONSTRAINT_T, std::vector< DRC_ENGINE_CONSTRAINT * > * > m_constraintMap
Definition: drc_engine.h:230
#define _(s)
const SHAPE_POLY_SET & GetPolyCourtyard(PCB_LAYER_ID aLayer) const
Used in DRC to test the courtyard area (a complex polygon).
Definition: footprint.h:695
NETCLASSES & GetNetClasses() const
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
class ZONE, a copper pour area
Definition: typeinfo.h:105
PROGRESS_REPORTER * m_progressReporter
Definition: drc_engine.h:234
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:765
void IncrementTimeStamp()
Definition: board.cpp:192
static bool isKeepoutZone(const BOARD_ITEM *aItem, bool aCheckFlags)
Definition: drc_engine.cpp:95
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:796
REPORTER * m_reporter
Definition: drc_engine.h:233
static wxString formatConstraint(const DRC_CONSTRAINT &constraint)
Definition: drc_engine.cpp:468
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:155
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
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
EDA_UNITS
Definition: eda_units.h:38
DRC_ENGINE(BOARD *aBoard=nullptr, BOARD_DESIGN_SETTINGS *aSettings=nullptr)
Definition: drc_engine.cpp:61
Represent a DRC "provider" which runs some DRC functions over a BOARD and spits out #DRC_ITEMs and po...
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
DRC_RULE * createImplicitRule(const wxString &name)
Definition: drc_engine.cpp:124
Handle the data for a net.
Definition: netinfo.h:66
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:118
const char * name
Definition: DXF_plotter.cpp:56
LSET m_LayerCondition
Definition: drc_rule.h:98
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
SHAPE * Clone() const override
Return a dynamically allocated copy of the shape.
Definition: shape_segment.h:57
void ReportAux(const wxString &aStr)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
PAD_ATTRIB GetAttribute() const
Definition: pad.h:371
virtual wxString GetSelectMenuText(EDA_UNITS aUnits) const
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: eda_item.cpp:109
void AddConstraint(DRC_CONSTRAINT &aConstraint)
Definition: drc_rule.cpp:46
class ZONE, managed by a footprint
Definition: typeinfo.h:94
wxString m_msg
Definition: drc_engine.h:236
void RunTests(EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints)
Run the DRC tests.
Definition: drc_engine.cpp:682
int m_DisallowFlags
Definition: drc_rule.h:146
static LSET BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition: lset.cpp:881
#define REPORT_VALUE(v)
DRC_VIOLATION_HANDLER m_violationHandler
Definition: drc_engine.h:232
bool Compile(REPORTER *aReporter, int aSourceLine=0, int aSourceOffset=0)
std::map< ZONE *, std::unique_ptr< DRC_RTREE > > m_CopperZoneRTrees
Definition: board.h:1096
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:167
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:204
BOARD * m_board
Definition: drc_engine.h:216
NETCLASSPTR GetDefault() const
Definition: netclass.h:253
constexpr int delta
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:103
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:36
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
DRC_CONSTRAINT_T m_Type
Definition: drc_rule.h:144
bool m_MicroViasAllowed
true to allow micro vias
#define drc_dbg(level, fmt,...)
Definition: drc_engine.h:57
Definition: pad.h:57
void loadImplicitRules()
Definition: drc_engine.cpp:137
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:135
bool m_reportAllTrackErrors
Definition: drc_engine.h:226
virtual int GetLocalClearance(wxString *aSource) const
Return any local clearances set in the "classic" (ie: pre-rule) system.
void ReportViolation(const std::shared_ptr< DRC_ITEM > &aItem, const wxPoint &aPos)
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:90
virtual bool IsOnCopperLayer() const
Definition: board_item.h:111
void InitEngine(const wxFileName &aRulePath)
Initialize the DRC engine.
Definition: drc_engine.cpp:626
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:145
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
Container for design settings for a BOARD object.
int GetNetCode() const
Definition: netinfo.h:115
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).