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