KiCad PCB EDA Suite
drc_clearance_test_functions.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) 2007 Dick Hollenbeck, dick@softplc.com
6  * Copyright (C) 2019 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 <fctsys.h>
27 #include <trigo.h>
28 #include <drc/drc.h>
29 #include <class_board.h>
30 #include <class_track.h>
31 #include <class_drawsegment.h>
32 #include <class_marker_pcb.h>
33 #include <math_for_graphics.h>
36 #include <geometry/shape_rect.h>
37 
38 
39 /*
40  * compare a trapezoid (can be rectangle) and a segment and return true if distance > aDist
41  */
42 bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd,
43  int aDist, int* aActual )
44 {
45  /* Test if the segment is contained in the polygon.
46  * This case is not covered by the following check if the segment is
47  * completely contained in the polygon (because edges don't intersect)!
48  */
49  if( TestPointInsidePolygon( aTref, aTrefCount, aSegStart ) )
50  {
51  *aActual = 0;
52  return false;
53  }
54 
55  for( int ii = 0, jj = aTrefCount-1; ii < aTrefCount; jj = ii, ii++ )
56  { // for all edges in polygon
57  double d;
58 
59  if( TestForIntersectionOfStraightLineSegments( aTref[ii].x, aTref[ii].y, aTref[jj].x,
60  aTref[jj].y, aSegStart.x, aSegStart.y,
61  aSegEnd.x, aSegEnd.y, NULL, NULL, &d ) )
62  {
63  *aActual = 0;
64  return false;
65  }
66 
67  if( d < aDist )
68  {
69  *aActual = KiROUND( d );
70  return false;
71  }
72  }
73 
74  return true;
75 }
76 
77 
78 void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aStartIt,
79  TRACKS::iterator aEndIt, bool aTestZones )
80 {
82 
83  SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
84  PCB_LAYER_ID refLayer = aRefSeg->GetLayer();
85  LSET refLayerSet = aRefSeg->GetLayerSet();
86 
87  EDA_RECT refSegBB = aRefSeg->GetBoundingBox();
88  int refSegWidth = aRefSeg->GetWidth();
89 
90 
91  /******************************************/
92  /* Phase 0 : via DRC tests : */
93  /******************************************/
94 
95  if( aRefSeg->Type() == PCB_VIA_T )
96  {
97  VIA *refvia = static_cast<VIA*>( aRefSeg );
98  int viaAnnulus = ( refvia->GetWidth() - refvia->GetDrill() ) / 2;
99  int minAnnulus = refvia->GetMinAnnulus( &m_clearanceSource );
100 
101  // test if the via size is smaller than minimum
102  if( refvia->GetViaType() == VIATYPE::MICROVIA )
103  {
104  if( viaAnnulus < minAnnulus )
105  {
107 
108  m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
110  MessageTextFromValue( userUnits(), minAnnulus, true ),
111  MessageTextFromValue( userUnits(), viaAnnulus, true ) );
112 
113  drcItem->SetErrorMessage( m_msg );
114  drcItem->SetItems( refvia );
115 
116  MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
117  addMarkerToPcb( aCommit, marker );
118  }
119 
120  if( refvia->GetWidth() < bds.m_MicroViasMinSize )
121  {
123 
124  m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
126  MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
127 
128  drcItem->SetErrorMessage( m_msg );
129  drcItem->SetItems( refvia );
130 
131  MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
132  addMarkerToPcb( aCommit, marker );
133  }
134  }
135  else
136  {
137  if( bds.m_ViasMinAnnulus > minAnnulus )
138  {
139  minAnnulus = bds.m_ViasMinAnnulus;
140  m_clearanceSource = _( "board minimum" );
141  }
142 
143  if( viaAnnulus < minAnnulus )
144  {
146 
147  m_msg.Printf( _( "Via annulus too small (%s %s; actual %s)" ),
149  MessageTextFromValue( userUnits(), minAnnulus, true ),
150  MessageTextFromValue( userUnits(), viaAnnulus, true ) );
151 
152  drcItem->SetErrorMessage( m_msg );
153  drcItem->SetItems( refvia );
154 
155  MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
156  addMarkerToPcb( aCommit, marker );
157  }
158 
159  if( refvia->GetWidth() < bds.m_ViasMinSize )
160  {
162 
163  m_msg.Printf( drcItem->GetErrorText() + _( " (board minimum %s; actual %s)" ),
165  MessageTextFromValue( userUnits(), refvia->GetWidth(), true ) );
166 
167  drcItem->SetErrorMessage( m_msg );
168  drcItem->SetItems( refvia );
169 
170  MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
171  addMarkerToPcb( aCommit, marker );
172  }
173  }
174 
175  // test if via's hole is bigger than its diameter
176  // This test is necessary since the via hole size and width can be modified
177  // and a default via hole can be bigger than some vias sizes
178  if( refvia->GetDrillValue() > refvia->GetWidth() )
179  {
181 
182  m_msg.Printf( drcItem->GetErrorText() + _( " (diameter %s; drill %s)" ),
183  MessageTextFromValue( userUnits(), refvia->GetWidth(), true ),
184  MessageTextFromValue( userUnits(), refvia->GetDrillValue(), true ) );
185 
186  drcItem->SetErrorMessage( m_msg );
187  drcItem->SetItems( refvia );
188 
189  MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
190  addMarkerToPcb( aCommit, marker );
191  }
192 
193  // test if the type of via is allowed due to design rules
194  if( refvia->GetViaType() == VIATYPE::MICROVIA && !bds.m_MicroViasAllowed )
195  {
197 
198  m_msg.Printf( _( "Microvia not allowed (board design rule constraints)" ) );
199  drcItem->SetErrorMessage( m_msg );
200  drcItem->SetItems( refvia );
201 
202  MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
203  addMarkerToPcb( aCommit, marker );
204  }
205 
206  // test if the type of via is allowed due to design rules
208  {
210 
211  m_msg.Printf( _( "Blind/buried via not allowed (board design rule constraints)" ) );
212  drcItem->SetErrorMessage( m_msg );
213  drcItem->SetItems( refvia );
214 
215  MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
216  addMarkerToPcb( aCommit, marker );
217  }
218 
219  // For microvias: test if they are blind vias and only between 2 layers
220  // because they are used for very small drill size and are drill by laser
221  // and **only one layer** can be drilled
222  if( refvia->GetViaType() == VIATYPE::MICROVIA )
223  {
224  PCB_LAYER_ID layer1, layer2;
225  bool err = true;
226 
227  refvia->LayerPair( &layer1, &layer2 );
228 
229  if( layer1 > layer2 )
230  std::swap( layer1, layer2 );
231 
232  if( layer2 == B_Cu && layer1 == bds.GetCopperLayerCount() - 2 )
233  err = false;
234  else if( layer1 == F_Cu && layer2 == In1_Cu )
235  err = false;
236 
237  if( err )
238  {
240 
241  m_msg.Printf( _( "Microvia through too many layers (%s and %s not adjacent)" ),
242  m_pcb->GetLayerName( layer1 ),
243  m_pcb->GetLayerName( layer2 ) );
244 
245  drcItem->SetErrorMessage( m_msg );
246  drcItem->SetItems( refvia );
247 
248  MARKER_PCB* marker = new MARKER_PCB( drcItem, refvia->GetPosition() );
249  addMarkerToPcb( aCommit, marker );
250  }
251  }
252 
253  }
254  else // This is a track segment
255  {
256  int minWidth, maxWidth;
257  aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
258 
259  int errorCode = 0;
260  int constraintWidth;
261 
262  if( refSegWidth < minWidth )
263  {
264  errorCode = DRCE_TRACK_WIDTH;
265  constraintWidth = minWidth;
266  }
267  else if( refSegWidth > maxWidth )
268  {
269  errorCode = DRCE_TRACK_WIDTH;
270  constraintWidth = maxWidth;
271  }
272 
273  if( errorCode )
274  {
275  wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
276 
277  DRC_ITEM* drcItem = DRC_ITEM::Create( errorCode );
278 
279  m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
281  MessageTextFromValue( userUnits(), constraintWidth, true ),
282  MessageTextFromValue( userUnits(), refSegWidth, true ) );
283 
284  drcItem->SetErrorMessage( m_msg );
285  drcItem->SetItems( aRefSeg );
286 
287  MARKER_PCB* marker = new MARKER_PCB( drcItem, refsegMiddle );
288  addMarkerToPcb( aCommit, marker );
289  }
290  }
291 
292 
293  /******************************************/
294  /* Phase 1 : test DRC track to pads : */
295  /******************************************/
296 
297  // Compute the min distance to pads
298  for( MODULE* mod : m_pcb->Modules() )
299  {
300  // Don't preflight at the module level. Getting a module's bounding box goes
301  // through all its pads anyway (so it's no faster), and also all its drawings
302  // (so it's in fact slower).
303 
304  for( D_PAD* pad : mod->Pads() )
305  {
306  // Preflight based on bounding boxes.
307  EDA_RECT inflatedBB = refSegBB;
308  inflatedBB.Inflate( pad->GetBoundingRadius() + m_largestClearance );
309 
310  if( !inflatedBB.Contains( pad->GetPosition() ) )
311  continue;
312 
313  if( !( pad->GetLayerSet() & refLayerSet ).any() )
314  continue;
315 
316  // No need to check pads with the same net as the refSeg.
317  if( pad->GetNetCode() && aRefSeg->GetNetCode() == pad->GetNetCode() )
318  continue;
319 
320  if( pad->GetDrillSize().x > 0 )
321  {
322  // For hole testing we use a dummy pad which is a copy of the current pad
323  // shrunk down to nothing but its hole.
324  D_PAD dummypad( *pad );
325  dummypad.SetSize( pad->GetDrillSize() );
326  dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
328  // Ensure the hole is on all copper layers
329  const static LSET all_cu = LSET::AllCuMask();
330  dummypad.SetLayerSet( all_cu | dummypad.GetLayerSet() );
331 
332  int minClearance;
333  DRC_RULE* rule = GetRule( aRefSeg, &dummypad, CLEARANCE_CONSTRAINT );
334 
335  if( rule )
336  {
337  m_clearanceSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
338  minClearance = rule->m_Clearance.Min;
339  }
340  else
341  {
342  minClearance = aRefSeg->GetClearance( nullptr, &m_clearanceSource );
343  }
344 
345  /* Treat an oval hole as a line segment along the hole's major axis,
346  * shortened by half its minor axis.
347  * A circular hole is just a degenerate case of an oval hole.
348  */
349  wxPoint slotStart, slotEnd;
350  int slotWidth;
351 
352  pad->GetOblongGeometry( pad->GetDrillSize(), &slotStart, &slotEnd, &slotWidth );
353  slotStart += pad->GetPosition();
354  slotEnd += pad->GetPosition();
355 
356  SEG slotSeg( slotStart, slotEnd );
357  int widths = ( slotWidth + refSegWidth ) / 2;
358  int center2centerAllowed = minClearance + widths + bds.GetDRCEpsilon();
359 
360  // Avoid square-roots if possible (for performance)
361  SEG::ecoord center2center_squared = refSeg.SquaredDistance( slotSeg );
362 
363  if( center2center_squared < SEG::Square( center2centerAllowed ) )
364  {
365  int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
367 
368  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
370  MessageTextFromValue( userUnits(), minClearance, true ),
371  MessageTextFromValue( userUnits(), actual, true ) );
372 
373  drcItem->SetErrorMessage( m_msg );
374  drcItem->SetItems( aRefSeg, pad );
375 
376  MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, slotSeg ) );
377  addMarkerToPcb( aCommit, marker );
378 
380  return;
381  }
382  }
383 
384  int minClearance = aRefSeg->GetClearance( pad, &m_clearanceSource );
385  int clearanceAllowed = minClearance - bds.GetDRCEpsilon();
386  int actual;
387 
388  if( !checkClearanceSegmToPad( refSeg, refSegWidth, pad, clearanceAllowed, &actual ) )
389  {
390  actual = std::max( 0, actual );
391  SEG padSeg( pad->GetPosition(), pad->GetPosition() );
393 
394  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
396  MessageTextFromValue( userUnits(), minClearance, true ),
397  MessageTextFromValue( userUnits(), actual, true ) );
398 
399  drcItem->SetErrorMessage( m_msg );
400  drcItem->SetItems( aRefSeg, pad );
401 
402  MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, padSeg ) );
403  addMarkerToPcb( aCommit, marker );
404 
406  return;
407  }
408  }
409  }
410 
411  /***********************************************/
412  /* Phase 2: test DRC with other track segments */
413  /***********************************************/
414 
415  // Test the reference segment with other track segments
416  for( auto it = aStartIt; it != aEndIt; it++ )
417  {
418  TRACK* track = *it;
419 
420  // No problem if segments have the same net code:
421  if( aRefSeg->GetNetCode() == track->GetNetCode() )
422  continue;
423 
424  // No problem if tracks are on different layers:
425  // Note that while the general case of GetLayerSet intersection always works,
426  // the others are much faster.
427  bool sameLayers;
428 
429  if( aRefSeg->Type() == PCB_VIA_T )
430  {
431  if( track->Type() == PCB_VIA_T )
432  sameLayers = ( refLayerSet & track->GetLayerSet() ).any();
433  else
434  sameLayers = refLayerSet.test( track->GetLayer() );
435  }
436  else
437  {
438  if( track->Type() == PCB_VIA_T )
439  sameLayers = track->GetLayerSet().test( refLayer );
440  else
441  sameLayers = track->GetLayer() == refLayer;
442  }
443 
444  if( !sameLayers )
445  continue;
446 
447  // Preflight based on worst-case inflated bounding boxes:
448  EDA_RECT trackBB = track->GetBoundingBox();
449  trackBB.Inflate( m_largestClearance );
450 
451  if( !trackBB.Intersects( refSegBB ) )
452  continue;
453 
454  int minClearance = aRefSeg->GetClearance( track, &m_clearanceSource );
455  SEG trackSeg( track->GetStart(), track->GetEnd() );
456  int widths = ( refSegWidth + track->GetWidth() ) / 2;
457  int center2centerAllowed = minClearance + widths;
458 
459  // Avoid square-roots if possible (for performance)
460  SEG::ecoord center2center_squared = refSeg.SquaredDistance( trackSeg );
461  OPT_VECTOR2I intersection = refSeg.Intersect( trackSeg );
462 
463  // Check two tracks crossing first as it reports a DRCE without distances
464  if( intersection )
465  {
467  drcItem->SetErrorMessage( m_msg );
468  drcItem->SetItems( aRefSeg, track );
469 
470  MARKER_PCB* marker = new MARKER_PCB( drcItem, (wxPoint) intersection.get() );
471  addMarkerToPcb( aCommit, marker );
472 
474  return;
475  }
476  else if( center2center_squared < SEG::Square( center2centerAllowed ) )
477  {
478  int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
480 
481  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
483  MessageTextFromValue( userUnits(), minClearance, true ),
484  MessageTextFromValue( userUnits(), actual, true ) );
485 
486  drcItem->SetErrorMessage( m_msg );
487  drcItem->SetItems( aRefSeg, track );
488 
489  MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, trackSeg ) );
490  addMarkerToPcb( aCommit, marker );
491 
493  return;
494  }
495  }
496 
497  /***************************************/
498  /* Phase 3: test DRC with copper zones */
499  /***************************************/
500  // Can be *very* time consumming.
501  if( aTestZones )
502  {
503  SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
504 
505  for( ZONE_CONTAINER* zone : m_pcb->Zones() )
506  {
507  if( !( refLayerSet & zone->GetLayerSet() ).any() || zone->GetIsKeepout() )
508  continue;
509 
510  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
511  {
512  if( zone->GetFilledPolysList( layer ).IsEmpty() )
513  continue;
514 
515  if( zone->GetNetCode() && zone->GetNetCode() == aRefSeg->GetNetCode() )
516  continue;
517 
518  int minClearance = aRefSeg->GetClearance( zone, &m_clearanceSource );
519  int widths = refSegWidth / 2;
520  int center2centerAllowed = minClearance + widths;
521  SHAPE_POLY_SET* outline =
522  const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList( layer ) );
523 
524  SEG::ecoord center2center_squared = outline->SquaredDistance( testSeg );
525 
526  // to avoid false positive, due to rounding issues and approxiamtions
527  // in distance and clearance calculations, use a small threshold for distance
528  // (1 micron)
529  #define THRESHOLD_DIST Millimeter2iu( 0.001 )
530 
531  if( center2center_squared + THRESHOLD_DIST < SEG::Square( center2centerAllowed ) )
532  {
533  int actual = std::max( 0.0, sqrt( center2center_squared ) - widths );
535 
536  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
538  MessageTextFromValue( userUnits(), minClearance, true ),
539  MessageTextFromValue( userUnits(), actual, true ) );
540 
541  drcItem->SetErrorMessage( m_msg );
542  drcItem->SetItems( aRefSeg, zone );
543 
544  MARKER_PCB* marker = new MARKER_PCB( drcItem, GetLocation( aRefSeg, zone ) );
545  addMarkerToPcb( aCommit, marker );
546  }
547  }
548  }
549  }
550 
551  /***********************************************/
552  /* Phase 4: test DRC with to board edge */
553  /***********************************************/
555  {
556  int minClearance = bds.m_CopperEdgeClearance;
557  m_clearanceSource = _( "board edge" );
558 
559  static DRAWSEGMENT dummyEdge;
560  dummyEdge.SetLayer( Edge_Cuts );
561 
562  if( aRefSeg->GetRuleClearance( &dummyEdge, &minClearance, &m_clearanceSource ) )
563  /* minClearance and m_clearanceSource set in GetRuleClearance() */;
564 
565  SEG testSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
566  int halfWidth = refSegWidth / 2;
567  int center2centerAllowed = minClearance + halfWidth;
568 
569  for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
570  {
571  SEG::ecoord center2center_squared = testSeg.SquaredDistance( *it );
572 
573  if( center2center_squared < SEG::Square( center2centerAllowed ) )
574  {
575  VECTOR2I pt = testSeg.NearestPoint( *it );
576 
577  KICAD_T types[] = { PCB_LINE_T, EOT };
578  DRAWSEGMENT* edge = nullptr;
579  INSPECTOR_FUNC inspector =
580  [&] ( EDA_ITEM* item, void* testData )
581  {
582  DRAWSEGMENT* test_edge = dynamic_cast<DRAWSEGMENT*>( item );
583 
584  if( !test_edge || test_edge->GetLayer() != Edge_Cuts )
586 
587  if( test_edge->HitTest( (wxPoint) pt, minClearance + halfWidth ) )
588  {
589  edge = test_edge;
590  return SEARCH_RESULT::QUIT;
591  }
592 
594  };
595 
596  // Best-efforts search for edge segment
597  BOARD::IterateForward<BOARD_ITEM*>( m_pcb->Drawings(), inspector, nullptr, types );
598 
599  int actual = std::max( 0.0, sqrt( center2center_squared ) - halfWidth );
601 
602  m_msg.Printf( drcItem->GetErrorText() + _( " (%s clearance %s; actual %s)" ),
604  MessageTextFromValue( userUnits(), minClearance, true ),
605  MessageTextFromValue( userUnits(), actual, true ) );
606 
607  drcItem->SetErrorMessage( m_msg );
608  drcItem->SetItems( aRefSeg, edge );
609 
610  MARKER_PCB* marker = new MARKER_PCB( drcItem, (wxPoint) pt );
611  addMarkerToPcb( aCommit, marker );
612  }
613  }
614  }
615 }
616 
617 
618 bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad, int aMinClearance, int* aActual )
619 {
620  int center2center = KiROUND( EuclideanNorm( aPad->ShapePos() - aRefPad->ShapePos() ) );
621 
622  // Quick test: Clearance is OK if the bounding circles are further away than aMinClearance
623  if( center2center - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius() >= aMinClearance )
624  return true;
625 
626  int actual = INT_MAX;
627 
628  for( const std::shared_ptr<SHAPE>& aShape : aRefPad->GetEffectiveShapes() )
629  {
630  for( const std::shared_ptr<SHAPE>& bShape : aPad->GetEffectiveShapes() )
631  {
632  int this_dist;
633 
634  if( aShape->Collide( bShape.get(), aMinClearance, &this_dist ) )
635  actual = std::min( actual, this_dist );
636  }
637  }
638 
639  if( actual < INT_MAX )
640  {
641  // returns the actual clearance (clearance < aMinClearance) for diags:
642  if( aActual )
643  *aActual = std::max( 0, actual );
644 
645  return false;
646  }
647 
648  return true;
649 }
650 
651 
652 /*
653  * Test if distance between a segment and a pad is > minClearance. Return the actual
654  * distance if it is less.
655  */
656 bool DRC::checkClearanceSegmToPad( const SEG& refSeg, int refSegWidth, const D_PAD* pad,
657  int minClearance, int* aActualDist )
658 {
659  if( ( pad->GetShape() == PAD_SHAPE_CIRCLE || pad->GetShape() == PAD_SHAPE_OVAL ) )
660  {
661  /* Treat an oval pad as a line segment along the hole's major axis,
662  * shortened by half its minor axis.
663  * A circular pad is just a degenerate case of an oval hole.
664  */
665  wxPoint padStart, padEnd;
666  int padWidth;
667 
668  pad->GetOblongGeometry( pad->GetSize(), &padStart, &padEnd, &padWidth );
669  padStart += pad->ShapePos();
670  padEnd += pad->ShapePos();
671 
672  SEG padSeg( padStart, padEnd );
673  int widths = ( padWidth + refSegWidth ) / 2;
674  int center2centerAllowed = minClearance + widths;
675 
676  // Avoid square-roots if possible (for performance)
677  SEG::ecoord center2center_squared = refSeg.SquaredDistance( padSeg );
678 
679  if( center2center_squared < SEG::Square( center2centerAllowed ) )
680  {
681  *aActualDist = std::max( 0.0, sqrt( center2center_squared ) - widths );
682  return false;
683  }
684  }
685  else if( ( pad->GetShape() == PAD_SHAPE_RECT || pad->GetShape() == PAD_SHAPE_ROUNDRECT )
686  && ( (int) pad->GetOrientation() % 900 == 0 ) )
687  {
688  EDA_RECT padBBox = pad->GetBoundingBox();
689  int widths = refSegWidth / 2;
690 
691  // Note a ROUNDRECT pad with a corner radius = r can be treated as a smaller
692  // RECT (size - 2*r) with a clearance increased by r
693  if( pad->GetShape() == PAD_SHAPE_ROUNDRECT )
694  {
695  padBBox.Inflate( - pad->GetRoundRectCornerRadius() );
696  widths += pad->GetRoundRectCornerRadius();
697  }
698 
699  SHAPE_RECT padShape( padBBox.GetPosition(), padBBox.GetWidth(), padBBox.GetHeight() );
700  int actual;
701 
702  if( padShape.Collide( refSeg, minClearance + widths, &actual ) )
703  {
704  *aActualDist = std::max( 0, actual - widths );
705  return false;
706  }
707  }
708  else // Convert the rest to polygons
709  {
710  SHAPE_POLY_SET polyset;
711 
712  BOARD* board = pad->GetBoard();
713  int maxError = board ? board->GetDesignSettings().m_MaxError : ARC_HIGH_DEF;
714 
715  pad->TransformShapeWithClearanceToPolygon( polyset, 0, maxError );
716 
717  const SHAPE_LINE_CHAIN& refpoly = polyset.COutline( 0 );
718  int widths = refSegWidth / 2;
719  int actual;
720 
721  if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
722  (wxPoint) refSeg.A, (wxPoint) refSeg.B,
723  minClearance + widths, &actual ) )
724  {
725  *aActualDist = std::max( 0, actual - widths );
726  return false;
727  }
728  }
729 
730  return true;
731 }
732 
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:128
int GetMinAnnulus(wxString *aSource) const
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:712
Too small via size.
Definition: drc.h:53
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
void GetWidthConstraints(int *aMin, int *aMax, wxString *aSource) const
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
BOARD_DESIGN_SETTINGS & bds()
Definition: dialog_drc.h:95
int GetNetCode() const
Function GetNetCode.
std::function< SEARCH_RESULT(EDA_ITEM *aItem, void *aTestData) > INSPECTOR_FUNC
Typedef INSPECTOR is used to inspect and possibly collect the (search) results of iterating over a li...
Definition: base_struct.h:80
void doTrackDrc(BOARD_COMMIT &aCommit, TRACK *aRefSeg, TRACKS::iterator aStartIt, TRACKS::iterator aEndIt, bool aTestZones)
Test the current segment.
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer.
BOARD * board() const
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
wxString m_msg
Definition: drc.h:142
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
items are too close together
Definition: drc.h:44
wxString m_Name
Definition: drc_rule.h:73
const wxPoint & GetStart() const
Definition: class_track.h:118
int m_largestClearance
Definition: drc.h:144
void SetItems(EDA_ITEM *aItem, EDA_ITEM *bItem=nullptr, EDA_ITEM *cItem=nullptr, EDA_ITEM *dItem=nullptr)
Definition: rc_item.h:119
VECTOR2I::extended_type ecoord
Definition: seg.h:42
int GetWidth() const
Definition: eda_rect.h:119
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
a copper item is too close to the board edge
Definition: drc.h:46
#define CLEARANCE_CONSTRAINT
Definition: drc_rule.h:35
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
EDA_UNITS userUnits() const
Definition: drc.h:155
bool checkClearancePadToPad(D_PAD *aRefPad, D_PAD *aPad, int aMinClearance, int *aActualDist)
ecoord SquaredDistance(const SEG &aSeg) const
Definition: seg.cpp:37
Too small micro via size.
Definition: drc.h:58
SEG::ecoord SquaredDistance(VECTOR2I aPoint) const
Function SquaredDistance computes the minimum distance squared between aPoint and all the polygons in...
tracks are crossing
Definition: drc.h:45
#define THRESHOLD_DIST
const std::vector< std::shared_ptr< SHAPE > > & GetEffectiveShapes() const
Function GetEffectiveShapes Returns a list of SHAPE objects representing the pad's copper.
Definition: class_pad.cpp:194
int PointCount() const
Function PointCount()
static SEG::ecoord Square(int a)
Definition: seg.h:116
a disallowed item has been used
Definition: drc.h:43
bool Contains(const wxPoint &aPoint) const
Function Contains.
search types array terminator (End Of Types)
Definition: typeinfo.h:82
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
A single base class (TRACK) represents both tracks and vias, with subclasses for curved tracks (ARC) ...
wxString m_clearanceSource
Definition: drc.h:143
wxString GetErrorText() const
Definition: rc_item.h:169
BOARD * m_pcb
Definition: drc.h:125
const VECTOR2I & CPoint(int aIndex) const
Function Point()
Markers used to show a drc problem on boards.
PCB_LAYER_ID
A quick note on layer IDs:
DRC_RULE * GetRule(const BOARD_ITEM *aItem, const BOARD_ITEM *bItem, int aConstraint)
Definition: drc_rule.cpp:67
LSET is a set of PCB_LAYER_IDs.
Track width is too small or too large.
Definition: drc.h:52
#define NULL
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
MODULES & Modules()
Definition: class_board.h:266
OPT< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:37
MINOPTMAX m_Clearance
Definition: drc_rule.h:79
SHAPE_POLY_SET.
int GetDrill() const
Function GetDrill returns the local drill setting for this VIA.
Definition: class_track.h:449
const wxPoint GetPosition() const
Definition: eda_rect.h:115
LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
Definition: class_pad.h:329
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
void addMarkerToPcb(BOARD_COMMIT &aCommit, MARKER_PCB *aMarker)
Adds a DRC marker to the PCB through the COMMIT mechanism.
void SetSize(const wxSize &aSize)
Definition: class_pad.h:219
static DRC_ITEM * Create(int aErrorCode)
Constructs a DRC_ITEM for the given error code.
Definition: drc_item.cpp:197
int GetBoundingRadius() const
Function GetBoundingRadius returns the radius of a minimum sized circle which fully encloses this pad...
Definition: class_pad.cpp:212
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
bool TestPointInsidePolygon(const wxPoint *aPolysList, int aCount, const wxPoint &aRefPoint)
Function TestPointInsidePolygon (overlaid) same as previous, but mainly use wxPoint.
bool m_reportAllTrackErrors
Definition: drc.h:121
via's hole is bigger than its diameter
Definition: drc.h:56
const wxPoint GetPosition() const override
Definition: class_track.h:406
int GetHeight() const
Definition: eda_rect.h:120
virtual int GetClearance(BOARD_ITEM *aItem=nullptr, wxString *aSource=nullptr) const
Function GetClearance returns the clearance in internal units.
bool m_board_outline_valid
Definition: drc.h:127
Definition: seg.h:39
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aUseMils, EDA_DATA_TYPE aType)
Definition: base_units.cpp:124
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aMaxError=ARC_HIGH_DEF, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the pad shape to a closed polygon.
bool poly2segmentDRC(wxPoint *aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd, int aDist, int *aActual)
void SetLayerSet(LSET aLayerMask)
Definition: class_pad.h:328
SHAPE_POLY_SET m_board_outlines
Definition: drc.h:126
ZONE_CONTAINERS & Zones()
Definition: class_board.h:280
int GetWidth() const
Definition: class_track.h:112
Class to handle a graphic segment.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:180
#define _(s)
Definition: 3d_actions.cpp:33
SHAPE_LINE_CHAIN.
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees,...
Definition: class_pad.h:313
something is wrong with a pad or via stackup
Definition: drc.h:57
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
VECTOR2I A
Definition: seg.h:47
wxPoint ShapePos() const
Definition: class_pad.cpp:491
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
VIATYPE GetViaType() const
Definition: class_track.h:368
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:159
void SetShape(PAD_SHAPE_T aShape)
Set the new shape of this pad.
Definition: class_pad.h:144
const wxPoint & GetEnd() const
Definition: class_track.h:115
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
int GetRoundRectCornerRadius() const
Definition: class_pad.cpp:163
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
void SetErrorMessage(const wxString &aMessage)
Definition: rc_item.h:117
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
PAD_SHAPE_T GetShape() const
Definition: class_pad.h:153
bool m_MicroViasAllowed
true to allow micro vias
Via size and drill leave annulus too small or too large.
Definition: drc.h:54
static wxPoint GetLocation(TRACK *aTrack, ZONE_CONTAINER *aConflictZone)
Fetches a reasonable point for marking a violoation between two non-point objects.
const wxSize & GetSize() const
Definition: class_pad.h:220
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
void GetOblongGeometry(const wxSize &aDrillOrPadSize, wxPoint *aStartPoint, wxPoint *aEndPoint, int *aWidth) const
JEY TODO: temporary until Tom is done with DRC stuff....
Definition: class_pad.cpp:753
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
int GetCopperLayerCount() const
Function GetCopperLayerCount.
DRAWINGS & Drawings()
Definition: class_board.h:275
virtual bool GetRuleClearance(BOARD_ITEM *aItem, int *aClearance, wxString *aSource) const
Function GetRuleClearance returns any rule-based clearance.
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: class_pad.cpp:371
virtual LSET GetLayerSet() const
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
bool checkClearanceSegmToPad(const SEG &seg, int segWidth, const D_PAD *pad, int minClearance, int *aActualDist)
Check the distance from a pad to segment.
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
VECTOR2I B
Definition: seg.h:48