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