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.GetDefault()->GetClearance() );
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'",
241  ncName );
242  netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
243  netclassClearanceRules.push_back( netclassRule );
244 
245  if( nc->GetClearance() )
246  {
247  DRC_CONSTRAINT constraint( CLEARANCE_CONSTRAINT );
248  constraint.Value().SetMin( std::max( bds.m_MinClearance, 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() || nc->GetDiffPairGap() )
262  {
263  netclassRule = new DRC_RULE;
264  netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ), ncName );
265  netclassRule->m_Implicit = true;
266 
267  expr = wxString::Format( "A.NetClass == '%s' && A.isDiffPair()",
268  ncName );
269  netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
270  netclassItemSpecificRules.push_back( netclassRule );
271 
272  if( nc->GetDiffPairWidth() )
273  {
275  constraint.Value().SetMin( bds.m_TrackMinWidth );
276  constraint.Value().SetOpt( nc->GetDiffPairWidth() );
277  netclassRule->AddConstraint( constraint );
278  }
279 
280  if( nc->GetDiffPairGap() )
281  {
283  constraint.Value().SetMin( std::max( bds.m_MinClearance, nc->GetClearance() ) );
284  constraint.Value().SetOpt( nc->GetDiffPairGap() );
285  netclassRule->AddConstraint( constraint );
286  }
287  }
288 
289  if( nc->GetViaDiameter() || nc->GetViaDrill() )
290  {
291  netclassRule = new DRC_RULE;
292  netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ), ncName );
293  netclassRule->m_Implicit = true;
294 
295  expr = wxString::Format( "A.NetClass == '%s' && A.Via_Type != 'Micro'",
296  ncName );
297  netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
298  netclassItemSpecificRules.push_back( netclassRule );
299 
300  if( nc->GetViaDiameter() )
301  {
303  constraint.Value().SetMin( bds.m_ViasMinSize );
304  constraint.Value().SetOpt( nc->GetViaDiameter() );
305  netclassRule->AddConstraint( constraint );
306  }
307 
308  if( nc->GetViaDrill() )
309  {
310  DRC_CONSTRAINT constraint( HOLE_SIZE_CONSTRAINT );
311  constraint.Value().SetMin( bds.m_MinThroughDrill );
312  constraint.Value().SetOpt( nc->GetViaDrill() );
313  netclassRule->AddConstraint( constraint );
314  }
315  }
316 
317  if( nc->GetuViaDiameter() || nc->GetuViaDrill() )
318  {
319  netclassRule = new DRC_RULE;
320  netclassRule->m_Name = wxString::Format( _( "netclass '%s'" ), ncName );
321  netclassRule->m_Implicit = true;
322 
323  expr = wxString::Format( "A.NetClass == '%s' && A.Via_Type == 'Micro'",
324  ncName );
325  netclassRule->m_Condition = new DRC_RULE_CONDITION( expr );
326  netclassItemSpecificRules.push_back( netclassRule );
327 
328  if( nc->GetuViaDiameter() )
329  {
331  constraint.Value().SetMin( bds.m_MicroViasMinSize );
332  constraint.Value().SetMin( nc->GetuViaDiameter() );
333  netclassRule->AddConstraint( constraint );
334  }
335 
336  if( nc->GetuViaDrill() )
337  {
338  DRC_CONSTRAINT constraint( HOLE_SIZE_CONSTRAINT );
339  constraint.Value().SetMin( bds.m_MicroViasMinDrill );
340  constraint.Value().SetOpt( nc->GetuViaDrill() );
341  netclassRule->AddConstraint( constraint );
342  }
343  }
344  };
345 
347  makeNetclassRules( bds.GetNetClasses().GetDefault(), true );
348 
349  for( const std::pair<const wxString, NETCLASSPTR>& netclass : bds.GetNetClasses() )
350  makeNetclassRules( netclass.second, false );
351 
352  // The netclass clearance rules have to be sorted by min clearance so the right one fires
353  // if 'A' and 'B' belong to two different netclasses.
354  //
355  // The item-specific netclass rules are all unary, so there's no 'A' vs 'B' issue.
356 
357  std::sort( netclassClearanceRules.begin(), netclassClearanceRules.end(),
358  []( DRC_RULE* lhs, DRC_RULE* rhs )
359  {
360  return lhs->m_Constraints[0].m_Value.Min()
361  < rhs->m_Constraints[0].m_Value.Min();
362  } );
363 
364  for( DRC_RULE* ncRule : netclassClearanceRules )
365  addRule( ncRule );
366 
367  for( DRC_RULE* ncRule : netclassItemSpecificRules )
368  addRule( ncRule );
369 
370  // 3) keepout area rules
371 
372  std::vector<ZONE*> keepoutZones;
373 
374  for( ZONE* zone : m_board->Zones() )
375  {
376  if( isKeepoutZone( zone, true ) )
377  keepoutZones.push_back( zone );
378  }
379 
380  for( FOOTPRINT* footprint : m_board->Footprints() )
381  {
382  for( ZONE* zone : footprint->Zones() )
383  {
384  if( isKeepoutZone( zone, true ) )
385  keepoutZones.push_back( zone );
386  }
387  }
388 
389  for( ZONE* zone : keepoutZones )
390  {
391  wxString name = zone->GetZoneName();
392 
393  if( name.IsEmpty() )
394  {
395  rule = createImplicitRule( _( "keepout area" ) );
396  name = zone->m_Uuid.AsString();
397  }
398  else
399  {
400  rule = createImplicitRule( wxString::Format( _( "keepout area '%s'" ), name ) );
401  }
402 
403  rule->m_Condition = new DRC_RULE_CONDITION( wxString::Format( "A.insideArea('%s')",
404  name ) );
405 
406  rule->m_LayerCondition = zone->GetLayerSet();
407 
408  int disallowFlags = 0;
409 
410  if( zone->GetDoNotAllowTracks() )
411  disallowFlags |= DRC_DISALLOW_TRACKS;
412 
413  if( zone->GetDoNotAllowVias() )
414  disallowFlags |= DRC_DISALLOW_VIAS;
415 
416  if( zone->GetDoNotAllowPads() )
417  disallowFlags |= DRC_DISALLOW_PADS;
418 
419  if( zone->GetDoNotAllowCopperPour() )
420  disallowFlags |= DRC_DISALLOW_ZONES;
421 
422  if( zone->GetDoNotAllowFootprints() )
423  disallowFlags |= DRC_DISALLOW_FOOTPRINTS;
424 
425  DRC_CONSTRAINT disallowConstraint( DISALLOW_CONSTRAINT );
426  disallowConstraint.m_DisallowFlags = disallowFlags;
427  rule->AddConstraint( disallowConstraint );
428  }
429 
430  ReportAux( wxString::Format( "Building %d implicit netclass rules",
431  (int) netclassClearanceRules.size() ) );
432 }
433 
434 static wxString formatConstraint( const DRC_CONSTRAINT& constraint )
435 {
436  struct FORMATTER
437  {
438  DRC_CONSTRAINT_T type;
439  wxString name;
440  std::function<wxString(const DRC_CONSTRAINT&)> formatter;
441  };
442 
443  auto formatMinMax =
444  []( const DRC_CONSTRAINT& c ) -> wxString
445  {
446  wxString str;
447  const auto value = c.GetValue();
448 
449  if ( value.HasMin() )
450  str += wxString::Format( " min: %d", value.Min() );
451 
452  if ( value.HasOpt() )
453  str += wxString::Format( " opt: %d", value.Opt() );
454 
455  if ( value.HasMax() )
456  str += wxString::Format( " max: %d", value.Max() );
457 
458  return str;
459  };
460 
461  std::vector<FORMATTER> formats =
462  {
463  { CLEARANCE_CONSTRAINT, "clearance", formatMinMax },
464  { HOLE_CLEARANCE_CONSTRAINT, "hole_clearance", formatMinMax },
465  { HOLE_TO_HOLE_CONSTRAINT, "hole_to_hole", formatMinMax },
466  { EDGE_CLEARANCE_CONSTRAINT, "edge_clearance", formatMinMax },
467  { HOLE_SIZE_CONSTRAINT, "hole_size", formatMinMax },
468  { COURTYARD_CLEARANCE_CONSTRAINT, "courtyard_clearance", formatMinMax },
469  { SILK_CLEARANCE_CONSTRAINT, "silk_clearance", formatMinMax },
470  { TRACK_WIDTH_CONSTRAINT, "track_width", formatMinMax },
471  { ANNULAR_WIDTH_CONSTRAINT, "annular_width", formatMinMax },
472  { DISALLOW_CONSTRAINT, "disallow", nullptr },
473  { VIA_DIAMETER_CONSTRAINT, "via_diameter", formatMinMax },
474  { LENGTH_CONSTRAINT, "length", formatMinMax },
475  { SKEW_CONSTRAINT, "skew", formatMinMax },
476  { VIA_COUNT_CONSTRAINT, "via_count", formatMinMax }
477  };
478 
479  for( FORMATTER& fmt : formats )
480  {
481  if( fmt.type == constraint.m_Type )
482  {
483  wxString rv = fmt.name + " ";
484 
485  if( fmt.formatter )
486  rv += fmt.formatter( constraint );
487 
488  return rv;
489  }
490  }
491 
492  return "?";
493 }
494 
495 
499 void DRC_ENGINE::loadRules( const wxFileName& aPath )
500 {
501  if( aPath.FileExists() )
502  {
503  std::vector<DRC_RULE*> rules;
504 
505  FILE* fp = wxFopen( aPath.GetFullPath(), wxT( "rt" ) );
506 
507  if( fp )
508  {
509  DRC_RULES_PARSER parser( fp, aPath.GetFullPath() );
510  parser.Parse( rules, m_reporter );
511  }
512 
513  // Copy the rules into the member variable afterwards so that if Parse() throws then
514  // the possibly malformed rules won't contaminate the current ruleset.
515 
516  for( DRC_RULE* rule : rules )
517  m_rules.push_back( rule );
518  }
519 }
520 
521 
523 {
524  ReportAux( wxString::Format( "Compiling Rules (%d rules): ",
525  (int) m_rules.size() ) );
526 
527  for( DRC_TEST_PROVIDER* provider : m_testProviders )
528  {
529  ReportAux( wxString::Format( "- Provider: '%s': ", provider->GetName() ) );
530  drc_dbg( 7, "do prov %s", provider->GetName() );
531 
532  for( DRC_CONSTRAINT_T id : provider->GetConstraintTypes() )
533  {
534  drc_dbg( 7, "do id %d", id );
535 
536  if( m_constraintMap.find( id ) == m_constraintMap.end() )
537  m_constraintMap[ id ] = new std::vector<DRC_ENGINE_CONSTRAINT*>();
538 
539  for( DRC_RULE* rule : m_rules )
540  {
541  DRC_RULE_CONDITION* condition = nullptr;
542  bool compileOk = false;
543  std::vector<DRC_CONSTRAINT> matchingConstraints;
544  drc_dbg( 7, "Scan provider %s, rule %s", provider->GetName(), rule->m_Name );
545 
546  if( rule->m_Condition && !rule->m_Condition->GetExpression().IsEmpty() )
547  {
548  condition = rule->m_Condition;
549  compileOk = condition->Compile( nullptr, 0, 0 ); // fixme
550  }
551 
552  for( const DRC_CONSTRAINT& constraint : rule->m_Constraints )
553  {
554  drc_dbg(7, "scan constraint id %d\n", constraint.m_Type );
555 
556  if( constraint.m_Type != id )
557  continue;
558 
560 
561  rcons->layerTest = rule->m_LayerCondition;
562  rcons->condition = condition;
563 
564  matchingConstraints.push_back( constraint );
565 
566  rcons->constraint = constraint;
567  rcons->parentRule = rule;
568  m_constraintMap[ id ]->push_back( rcons );
569  }
570 
571  if( !matchingConstraints.empty() )
572  {
573  ReportAux( wxString::Format( " |- Rule: '%s' ",
574  rule->m_Name ) );
575 
576  if( condition )
577  {
578  ReportAux( wxString::Format( " |- condition: '%s' compile: %s",
579  condition->GetExpression(),
580  compileOk ? "OK" : "ERROR" ) );
581  }
582 
583  for (const DRC_CONSTRAINT& constraint : matchingConstraints )
584  {
585  ReportAux( wxString::Format( " |- constraint: %s",
586  formatConstraint( constraint ) ) );
587  }
588  }
589  }
590  }
591  }
592 }
593 
594 
598 void DRC_ENGINE::InitEngine( const wxFileName& aRulePath )
599 {
601 
602  for( DRC_TEST_PROVIDER* provider : m_testProviders )
603  {
604  ReportAux( wxString::Format( "Create DRC provider: '%s'", provider->GetName() ) );
605  provider->SetDRCEngine( this );
606  }
607 
608  for( DRC_RULE* rule : m_rules )
609  delete rule;
610 
611  m_rules.clear();
612  m_rulesValid = false;
613 
614  for( std::pair<DRC_CONSTRAINT_T, std::vector<DRC_ENGINE_CONSTRAINT*>*> pair : m_constraintMap )
615  {
616  for( DRC_ENGINE_CONSTRAINT* constraint : *pair.second )
617  delete constraint;
618 
619  delete pair.second;
620  }
621 
622  m_constraintMap.clear();
623 
624  try // attempt to load full set of rules (implicit + user rules)
625  {
627  loadRules( aRulePath );
628  compileRules();
629  }
630  catch( PARSE_ERROR& original_parse_error )
631  {
632  try // try again with just our implicit rules
633  {
635  compileRules();
636  }
637  catch( PARSE_ERROR& )
638  {
639  wxFAIL_MSG( "Compiling implict rules failed." );
640  }
641 
642  throw original_parse_error;
643  }
644 
645  for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
646  m_errorLimits[ ii ] = INT_MAX;
647 
648  m_rulesValid = true;
649 }
650 
651 
652 void DRC_ENGINE::RunTests( EDA_UNITS aUnits, bool aReportAllTrackErrors, bool aTestFootprints )
653 {
654  m_userUnits = aUnits;
655 
656  // Note: set these first. The phase counts may be dependent on some of them.
657  m_reportAllTrackErrors = aReportAllTrackErrors;
658  m_testFootprints = aTestFootprints;
659 
660  for( int ii = DRCE_FIRST; ii < DRCE_LAST; ++ii )
661  {
662  if( m_designSettings->Ignore( ii ) )
663  m_errorLimits[ ii ] = 0;
664  else
665  m_errorLimits[ ii ] = INT_MAX;
666  }
667 
668  m_board->IncrementTimeStamp(); // Invalidate all caches
669 
670  if( !ReportPhase( _( "Tessellating copper zones..." ) ) )
671  return;
672 
673  // Number of zones between progress bar updates
674  int delta = 5;
675  std::vector<ZONE*> copperZones;
676 
677  for( ZONE* zone : m_board->Zones() )
678  {
679  zone->CacheBoundingBox();
680  zone->CacheTriangulation();
681 
682  if( !zone->GetIsRuleArea() )
683  copperZones.push_back( zone );
684  }
685 
686  for( FOOTPRINT* footprint : m_board->Footprints() )
687  {
688  for( ZONE* zone : footprint->Zones() )
689  {
690  zone->CacheBoundingBox();
691  zone->CacheTriangulation();
692 
693  if( !zone->GetIsRuleArea() )
694  copperZones.push_back( zone );
695  }
696 
697  footprint->BuildPolyCourtyards();
698  }
699 
700  int zoneCount = copperZones.size();
701 
702  for( int ii = 0; ii < zoneCount; ++ii )
703  {
704  ZONE* zone = copperZones[ ii ];
705 
706  if( ( ii % delta ) == 0 || ii == zoneCount - 1 )
707  {
708  if( !ReportProgress( (double) ii / (double) zoneCount ) )
709  return;
710  }
711 
712  m_board->m_CopperZoneRTrees[ zone ] = std::make_unique<DRC_RTREE>();
713 
714  for( int layer : zone->GetLayerSet().Seq() )
715  {
716  if( IsCopperLayer( layer ) )
717  m_board->m_CopperZoneRTrees[ zone ]->Insert( zone, layer );
718  }
719  }
720 
721  for( DRC_TEST_PROVIDER* provider : m_testProviders )
722  {
723  if( !provider->IsEnabled() )
724  continue;
725 
726  drc_dbg( 0, "Running test provider: '%s'\n", provider->GetName() );
727 
728  ReportAux( wxString::Format( "Run DRC provider: '%s'", provider->GetName() ) );
729 
730  if( !provider->Run() )
731  break;
732  }
733 }
734 
735 
737  const BOARD_ITEM* b, PCB_LAYER_ID aLayer,
738  REPORTER* aReporter )
739 {
740 #define REPORT( s ) { if( aReporter ) { aReporter->Report( s ); } }
741 #define UNITS aReporter ? aReporter->GetUnits() : EDA_UNITS::MILLIMETRES
742  /*
743  * NOTE: all string manipulation MUST BE KEPT INSIDE the REPORT macro. It absolutely
744  * kills performance when running bulk DRC tests (where aReporter is nullptr).
745  */
746 
747  const BOARD_CONNECTED_ITEM* ac = a && a->IsConnected() ?
748  static_cast<const BOARD_CONNECTED_ITEM*>( a ) : nullptr;
749  const BOARD_CONNECTED_ITEM* bc = b && b->IsConnected() ?
750  static_cast<const BOARD_CONNECTED_ITEM*>( b ) : nullptr;
751 
752  bool a_is_non_copper = a && ( !a->IsOnCopperLayer() || isKeepoutZone( a, false ) );
753  bool b_is_non_copper = b && ( !b->IsOnCopperLayer() || isKeepoutZone( b, false ) );
754 
755  const DRC_CONSTRAINT* constraintRef = nullptr;
756  bool implicit = false;
757 
758  // Local overrides take precedence
759  if( aConstraintId == CLEARANCE_CONSTRAINT || aConstraintId == HOLE_CLEARANCE_CONSTRAINT )
760  {
761  int overrideA = 0;
762  int overrideB = 0;
763 
764  if( ac && !b_is_non_copper && ac->GetLocalClearanceOverrides( nullptr ) > 0 )
765  {
766  overrideA = ac->GetLocalClearanceOverrides( &m_msg );
767 
768  REPORT( "" )
769  REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
771  EscapeHTML( MessageTextFromValue( UNITS, overrideA ) ) ) )
772  }
773 
774  if( bc && !a_is_non_copper && bc->GetLocalClearanceOverrides( nullptr ) > 0 )
775  {
776  overrideB = bc->GetLocalClearanceOverrides( &m_msg );
777 
778  REPORT( "" )
779  REPORT( wxString::Format( _( "Local override on %s; clearance: %s." ),
781  EscapeHTML( MessageTextFromValue( UNITS, overrideB ) ) ) )
782  }
783 
784  if( overrideA || overrideB )
785  {
786  DRC_CONSTRAINT constraint( aConstraintId, m_msg );
787  constraint.m_Value.SetMin( std::max( overrideA, overrideB ) );
788  return constraint;
789  }
790  }
791 
792  auto processConstraint =
793  [&]( const DRC_ENGINE_CONSTRAINT* c ) -> bool
794  {
795  implicit = c->parentRule && c->parentRule->m_Implicit;
796 
797  REPORT( "" )
798 
799  if( aConstraintId == CLEARANCE_CONSTRAINT )
800  {
801  int val = c->constraint.m_Value.Min();
802  REPORT( wxString::Format( _( "Checking %s; clearance: %s." ),
803  EscapeHTML( c->constraint.GetName() ),
804  EscapeHTML( MessageTextFromValue( UNITS, val ) ) ) )
805  }
806  else if( aConstraintId == COURTYARD_CLEARANCE_CONSTRAINT )
807  {
808  int val = c->constraint.m_Value.Min();
809  REPORT( wxString::Format( _( "Checking %s; courtyard clearance: %s." ),
810  EscapeHTML( c->constraint.GetName() ),
811  EscapeHTML( MessageTextFromValue( UNITS, val ) ) ) )
812  }
813  else if( aConstraintId == SILK_CLEARANCE_CONSTRAINT )
814  {
815  int val = c->constraint.m_Value.Min();
816  REPORT( wxString::Format( _( "Checking %s; silk clearance: %s." ),
817  EscapeHTML( c->constraint.GetName() ),
818  EscapeHTML( MessageTextFromValue( UNITS, val ) ) ) )
819  }
820  else if( aConstraintId == HOLE_CLEARANCE_CONSTRAINT )
821  {
822  int val = c->constraint.m_Value.Min();
823  REPORT( wxString::Format( _( "Checking %s; hole clearance: %s." ),
824  EscapeHTML( c->constraint.GetName() ),
825  EscapeHTML( MessageTextFromValue( UNITS, val ) ) ) )
826  }
827  else if( aConstraintId == EDGE_CLEARANCE_CONSTRAINT )
828  {
829  int val = c->constraint.m_Value.Min();
830  REPORT( wxString::Format( _( "Checking %s; edge clearance: %s." ),
831  EscapeHTML( c->constraint.GetName() ),
832  EscapeHTML( MessageTextFromValue( UNITS, val ) ) ) )
833  }
834  else
835  {
836  REPORT( wxString::Format( _( "Checking %s." ), c->constraint.GetName() ) )
837  }
838 
839  if( aConstraintId == CLEARANCE_CONSTRAINT )
840  {
841  if( implicit && ( a_is_non_copper || b_is_non_copper ) )
842  {
843  REPORT( _( "Board and netclass clearances apply only between copper "
844  "items." ) );
845  return true;
846  }
847  }
848  else if( aConstraintId == DISALLOW_CONSTRAINT )
849  {
850  int mask;
851 
852  if( a->GetFlags() & HOLE_PROXY )
853  {
854  mask = DRC_DISALLOW_HOLES;
855  }
856  else if( a->Type() == PCB_VIA_T )
857  {
858  if( static_cast<const VIA*>( a )->GetViaType() == VIATYPE::BLIND_BURIED )
860  else if( static_cast<const VIA*>( a )->GetViaType() == VIATYPE::MICROVIA )
862  else
863  mask = DRC_DISALLOW_VIAS;
864  }
865  else
866  {
867  switch( a->Type() )
868  {
869  case PCB_TRACE_T: mask = DRC_DISALLOW_TRACKS; break;
870  case PCB_ARC_T: mask = DRC_DISALLOW_TRACKS; break;
871  case PCB_PAD_T: mask = DRC_DISALLOW_PADS; break;
872  case PCB_FOOTPRINT_T: mask = DRC_DISALLOW_FOOTPRINTS; break;
873  case PCB_SHAPE_T: mask = DRC_DISALLOW_GRAPHICS; break;
874  case PCB_FP_SHAPE_T: mask = DRC_DISALLOW_GRAPHICS; break;
875  case PCB_TEXT_T: mask = DRC_DISALLOW_TEXTS; break;
876  case PCB_FP_TEXT_T: mask = DRC_DISALLOW_TEXTS; break;
877  case PCB_ZONE_T: mask = DRC_DISALLOW_ZONES; break;
878  case PCB_FP_ZONE_T: mask = DRC_DISALLOW_ZONES; break;
879  case PCB_LOCATE_HOLE_T: mask = DRC_DISALLOW_HOLES; break;
880  default: mask = 0; break;
881  }
882  }
883 
884  if( ( c->constraint.m_DisallowFlags & mask ) == 0 )
885  {
886  if( implicit )
887  REPORT( _( "Keepout constraint not met." ) )
888  else
889  REPORT( _( "Disallow constraint not met." ) )
890 
891  return false;
892  }
893 
894  LSET itemLayers = a->GetLayerSet();
895 
896  if( a->Type() == PCB_FOOTPRINT_T )
897  {
898  const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( a );
899 
900  if( !footprint->GetPolyCourtyardFront().IsEmpty() )
901  itemLayers |= LSET::FrontMask();
902 
903  if( !footprint->GetPolyCourtyardBack().IsEmpty() )
904  itemLayers |= LSET::BackMask();
905  }
906 
907  if( !( c->layerTest & itemLayers ).any() )
908  {
909  if( implicit )
910  {
911  REPORT( _( "Keepout layer(s) not matched." ) )
912  }
913  else if( c->parentRule )
914  {
915  REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule "
916  "ignored." ),
917  EscapeHTML( c->parentRule->m_LayerSource ) ) )
918  }
919  else
920  {
921  REPORT( _( "Rule layer not matched; rule ignored." ) )
922  }
923 
924  return false;
925  }
926  }
927 
928  if( aLayer != UNDEFINED_LAYER && !c->layerTest.test( aLayer ) )
929  {
930  if( implicit )
931  {
932  REPORT( "Constraint layer not matched." )
933  }
934  else if( c->parentRule )
935  {
936  REPORT( wxString::Format( _( "Rule layer '%s' not matched; rule ignored." ),
937  EscapeHTML( c->parentRule->m_LayerSource ) ) )
938  }
939  else
940  {
941  REPORT( _( "Rule layer not matched; rule ignored." ) )
942  }
943 
944  return false;
945  }
946 
947  if( !c->condition || c->condition->GetExpression().IsEmpty() )
948  {
949  REPORT( implicit ? _( "Unconditional constraint applied." )
950  : _( "Unconditional rule applied." ) );
951 
952  constraintRef = &c->constraint;
953  return true;
954  }
955  else
956  {
957  if( implicit )
958  {
959  // Don't report on implicit rule conditions; they're synthetic.
960  }
961  else
962  {
963  REPORT( wxString::Format( _( "Checking rule condition \"%s\"." ),
964  EscapeHTML( c->condition->GetExpression() ) ) )
965  }
966 
967  if( c->condition->EvaluateFor( a, b, aLayer, aReporter ) )
968  {
969  REPORT( implicit ? _( "Constraint applied." )
970  : _( "Rule applied; overrides previous constraints." ) )
971 
972  constraintRef = &c->constraint;
973  return true;
974  }
975  else
976  {
977  REPORT( implicit ? _( "Membership not satisfied; constraint ignored." )
978  : _( "Condition not satisfied; rule ignored." ) )
979 
980  return false;
981  }
982  }
983  };
984 
985  if( m_constraintMap.count( aConstraintId ) )
986  {
987  std::vector<DRC_ENGINE_CONSTRAINT*>* ruleset = m_constraintMap[ aConstraintId ];
988 
989  if( aReporter )
990  {
991  // We want to see all results so process in "natural" order
992  for( int ii = 0; ii < (int) ruleset->size(); ++ii )
993  {
994  processConstraint( ruleset->at( ii ) );
995  }
996  }
997  else
998  {
999  // Last matching rule wins, so process in reverse order and quit when match found
1000  for( int ii = (int) ruleset->size() - 1; ii >= 0; --ii )
1001  {
1002  if( processConstraint( ruleset->at( ii ) ) )
1003  break;
1004  }
1005  }
1006  }
1007 
1008  bool explicitConstraintFound = constraintRef && !implicit;
1009 
1010  // Unfortunately implicit rules don't work for local clearances (such as zones) because
1011  // they have to be max'ed with netclass values (which are already implicit rules), and our
1012  // rule selection paradigm is "winner takes all".
1013  if( aConstraintId == CLEARANCE_CONSTRAINT && !explicitConstraintFound )
1014  {
1015  int global = constraintRef ? constraintRef->m_Value.Min() : 0;
1016  int localA = ac ? ac->GetLocalClearance( nullptr ) : 0;
1017  int localB = bc ? bc->GetLocalClearance( nullptr ) : 0;
1018  int clearance = global;
1019 
1020  if( localA > 0 )
1021  {
1022  REPORT( "" )
1023  REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
1025  EscapeHTML( MessageTextFromValue( UNITS, localA ) ) ) )
1026 
1027  if( localA > clearance )
1028  clearance = ac->GetLocalClearance( &m_msg );
1029  }
1030 
1031  if( localB > 0 )
1032  {
1033  REPORT( "" )
1034  REPORT( wxString::Format( _( "Local clearance on %s; clearance: %s." ),
1036  EscapeHTML( MessageTextFromValue( UNITS, localB ) ) ) )
1037 
1038  if( localB > clearance )
1039  clearance = bc->GetLocalClearance( &m_msg );
1040  }
1041 
1042  if( localA > global || localB > global )
1043  {
1044  DRC_CONSTRAINT constraint( CLEARANCE_CONSTRAINT, m_msg );
1045  constraint.m_Value.SetMin( clearance );
1046  return constraint;
1047  }
1048  }
1049 
1050  static DRC_CONSTRAINT nullConstraint( NULL_CONSTRAINT );
1051  nullConstraint.m_DisallowFlags = 0;
1052 
1053  return constraintRef ? *constraintRef : nullConstraint;
1054 
1055 #undef REPORT
1056 #undef UNITS
1057 }
1058 
1059 
1060 bool DRC_ENGINE::IsErrorLimitExceeded( int error_code )
1061 {
1062  assert( error_code >= 0 && error_code <= DRCE_LAST );
1063  return m_errorLimits[ error_code ] <= 0;
1064 }
1065 
1066 
1067 void DRC_ENGINE::ReportViolation( const std::shared_ptr<DRC_ITEM>& aItem, wxPoint aPos )
1068 {
1069  m_errorLimits[ aItem->GetErrorCode() ] -= 1;
1070 
1071  if( m_violationHandler )
1072  m_violationHandler( aItem, aPos );
1073 
1074  if( m_reporter )
1075  {
1076  wxString msg = wxString::Format( "Test '%s': %s (code %d)",
1077  aItem->GetViolatingTest()->GetName(),
1078  aItem->GetErrorMessage(),
1079  aItem->GetErrorCode() );
1080 
1081  DRC_RULE* rule = aItem->GetViolatingRule();
1082 
1083  if( rule )
1084  msg += wxString::Format( ", violating rule: '%s'", rule->m_Name );
1085 
1086  m_reporter->Report( msg );
1087 
1088  wxString violatingItemsStr = "Violating items: ";
1089 
1090  m_reporter->Report( wxString::Format( " |- violating position (%d, %d)",
1091  aPos.x,
1092  aPos.y ) );
1093  }
1094 }
1095 
1096 void DRC_ENGINE::ReportAux ( const wxString& aStr )
1097 {
1098  if( !m_reporter )
1099  return;
1100 
1102 }
1103 
1104 
1105 bool DRC_ENGINE::ReportProgress( double aProgress )
1106 {
1107  if( !m_progressReporter )
1108  return true;
1109 
1110  m_progressReporter->SetCurrentProgress( aProgress );
1111  return m_progressReporter->KeepRefreshing( false );
1112 }
1113 
1114 
1115 bool DRC_ENGINE::ReportPhase( const wxString& aMessage )
1116 {
1117  if( !m_progressReporter )
1118  return true;
1119 
1120  m_progressReporter->AdvancePhase( aMessage );
1121  return m_progressReporter->KeepRefreshing( false );
1122 }
1123 
1124 
1126 {
1127  //drc_dbg(10,"hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size( ) );
1128  if( m_constraintMap.count( constraintID ) )
1129  return m_constraintMap[ constraintID ]->size() > 0;
1130 
1131  return false;
1132 }
1133 
1134 
1136 {
1137  int worst = 0;
1138 
1139  if( m_constraintMap.count( aConstraintId ) )
1140  {
1141  for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] )
1142  {
1143  int current = c->constraint.GetValue().Min();
1144 
1145  if( current > worst )
1146  {
1147  worst = current;
1148  aConstraint = c->constraint;
1149  }
1150  }
1151  }
1152 
1153  return worst > 0;
1154 }
1155 
1156 
1157 // fixme: move two functions below to pcbcommon?
1158 int DRC_ENGINE::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet,
1159  wxString& aBaseDpName )
1160 {
1161  int rv = 0;
1162 
1163  if( aNetName.EndsWith( "+" ) )
1164  {
1165  aComplementNet = "-";
1166  rv = 1;
1167  }
1168  else if( aNetName.EndsWith( "P" ) )
1169  {
1170  aComplementNet = "N";
1171  rv = 1;
1172  }
1173  else if( aNetName.EndsWith( "-" ) )
1174  {
1175  aComplementNet = "+";
1176  rv = -1;
1177  }
1178  else if( aNetName.EndsWith( "N" ) )
1179  {
1180  aComplementNet = "P";
1181  rv = -1;
1182  }
1183  // Match P followed by 2 digits
1184  else if( aNetName.Right( 2 ).IsNumber() && aNetName.Right( 3 ).Left( 1 ) == "P" )
1185  {
1186  aComplementNet = "N" + aNetName.Right( 2 );
1187  rv = 1;
1188  }
1189  // Match P followed by 1 digit
1190  else if( aNetName.Right( 1 ).IsNumber() && aNetName.Right( 2 ).Left( 1 ) == "P" )
1191  {
1192  aComplementNet = "N" + aNetName.Right( 1 );
1193  rv = 1;
1194  }
1195  // Match N followed by 2 digits
1196  else if( aNetName.Right( 2 ).IsNumber() && aNetName.Right( 3 ).Left( 1 ) == "N" )
1197  {
1198  aComplementNet = "P" + aNetName.Right( 2 );
1199  rv = -1;
1200  }
1201  // Match N followed by 1 digit
1202  else if( aNetName.Right( 1 ).IsNumber() && aNetName.Right( 2 ).Left( 1 ) == "N" )
1203  {
1204  aComplementNet = "P" + aNetName.Right( 1 );
1205  rv = -1;
1206  }
1207  if( rv != 0 )
1208  {
1209  aBaseDpName = aNetName.Left( aNetName.Length() - aComplementNet.Length() );
1210  aComplementNet = aBaseDpName + aComplementNet;
1211  }
1212 
1213  return rv;
1214 }
1215 
1216 
1217 bool DRC_ENGINE::IsNetADiffPair( BOARD* aBoard, NETINFO_ITEM* aNet, int& aNetP, int& aNetN )
1218 {
1219  wxString refName = aNet->GetNetname();
1220  wxString dummy, coupledNetName;
1221 
1222  if( int polarity = MatchDpSuffix( refName, coupledNetName, dummy ) )
1223  {
1224  NETINFO_ITEM* net = aBoard->FindNet( coupledNetName );
1225 
1226  if( !net )
1227  return false;
1228 
1229  if( polarity > 0 )
1230  {
1231  aNetP = aNet->GetNetCode();
1232  aNetN = net->GetNetCode();
1233  }
1234  else
1235  {
1236  aNetP = net->GetNetCode();
1237  aNetN = aNet->GetNetCode();
1238  }
1239 
1240  return true;
1241  }
1242 
1243  return false;
1244 }
1245 
1246 
1247 std::shared_ptr<SHAPE> DRC_ENGINE::GetShape( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer )
1248 {
1249  if( aItem->Type() == PCB_PAD_T && !static_cast<PAD*>( aItem )->FlashLayer( aLayer ) )
1250  {
1251  PAD* aPad = static_cast<PAD*>( aItem );
1252 
1253  if( aPad->GetAttribute() == PAD_ATTRIB_PTH )
1254  {
1256 
1257  // Note: drill size represents finish size, which means the actual holes size is the
1258  // plating thickness larger.
1259  auto hole = static_cast<SHAPE_SEGMENT*>( aPad->GetEffectiveHoleShape()->Clone() );
1260  hole->SetWidth( hole->GetWidth() + bds.GetHolePlatingThickness() );
1261  return std::make_shared<SHAPE_SEGMENT>( *hole );
1262  }
1263 
1264  return std::make_shared<SHAPE_NULL>();
1265  }
1266 
1267  return aItem->GetEffectiveShape( aLayer );
1268 }
1269 
1270 
1272 {
1273  if( aItem->GetParent() && aItem->GetParent()->Type() == PCB_FOOTPRINT_T )
1274  return static_cast<FOOTPRINT*>( aItem->GetParent() )->IsNetTie();
1275 
1276  return false;
1277 }
1278 
1279 
1281 {
1282  for( auto prov : m_testProviders )
1283  if( name == prov->GetName() )
1284  return prov;
1285 
1286  return nullptr;
1287 }
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:1268
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:125
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:648
void loadRules(const wxFileName &aPath)
Loads and parses a rule set from an sexpr text file.
Definition: drc_engine.cpp:499
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
bool GetDoNotAllowFootprints() const
Definition: zone.h:760
std::vector< int > m_errorLimits
Definition: drc_engine.h:221
ZONES & Zones()
Definition: board.h:309
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:755
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:522
int GetHolePlatingThickness() const
Pad & via drills are finish size.
bool GetDoNotAllowVias() const
Definition: zone.h:757
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:288
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: pcbnew/pad.cpp:286
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:591
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
DRC_RULE_CONDITION * condition
Definition: drc_engine.h:202
BOARD_DESIGN_SETTINGS * m_designSettings
Definition: drc_engine.h:211
PAD_ATTR_T GetAttribute() const
Definition: pad.h:363
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:1413
bool GetDoNotAllowPads() const
Definition: zone.h:759
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:756
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:303
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:758
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:649
NETCLASSES & GetNetClasses() const
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
ZONE handles 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:736
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:434
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:128
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)
int GetClearance() const
Definition: netclass.h:124
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:123
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
Plated through hole pad.
Definition: pad_shapes.h:80
NETCLASS * GetDefault() const
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:652
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:1154
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:346
void loadImplicitRules()
Definition: drc_engine.cpp:132
STATUS_FLAGS GetFlags() const
Definition: eda_item.h:204
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:598
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:162
Container for design settings for a BOARD object.
int GetNetCode() const
Definition: netinfo.h:113