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