KiCad PCB EDA Suite
drc_clearance_test_functions.cpp
Go to the documentation of this file.
1 
5 /*
6  * This program source code file is part of KiCad, a free EDA CAD application.
7  *
8  * Copyright (C) 2004-2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
9  * Copyright (C) 2007 Dick Hollenbeck, dick@softplc.com
10  * Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, you may find one here:
24  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
25  * or you may search the http://www.gnu.org website for the version 2 license,
26  * or you may write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29 
34 #include <fctsys.h>
35 #include <pcb_edit_frame.h>
36 #include <trigo.h>
37 
38 #include <pcbnew.h>
39 #include <drc.h>
40 
41 #include <class_board.h>
42 #include <class_module.h>
43 #include <class_track.h>
44 #include <class_zone.h>
45 #include <class_marker_pcb.h>
46 #include <math_for_graphics.h>
49 #include <board_commit.h>
50 
51 
52 /* compare 2 convex polygons and return true if distance > aDist
53  * i.e if for each edge of the first polygon distance from each edge of the other polygon
54  * is >= aDist
55  */
56 bool poly2polyDRC( wxPoint* aTref, int aTrefCount,
57  wxPoint* aTcompare, int aTcompareCount, int aDist )
58 {
59  /* Test if one polygon is contained in the other and thus the polygon overlap.
60  * This case is not covered by the following check if one polygone is
61  * completely contained in the other (because edges don't intersect)!
62  */
63  if( TestPointInsidePolygon( aTref, aTrefCount, aTcompare[0] ) )
64  return false;
65 
66  if( TestPointInsidePolygon( aTcompare, aTcompareCount, aTref[0] ) )
67  return false;
68 
69  for( int ii = 0, jj = aTrefCount - 1; ii < aTrefCount; jj = ii, ii++ )
70  { // for all edges in aTref
71  for( int kk = 0, ll = aTcompareCount - 1; kk < aTcompareCount; ll = kk, kk++ )
72  { // for all edges in aTcompare
73  double d;
75  aTref[ii].x, aTref[ii].y, aTref[jj].x, aTref[jj].y,
76  aTcompare[kk].x, aTcompare[kk].y, aTcompare[ll].x, aTcompare[ll].y,
77  NULL, NULL, &d );
78 
79  if( intersect || ( d < aDist ) )
80  return false;
81  }
82  }
83 
84  return true;
85 }
86 
87 /* compare a trapezoids (can be rectangle) and a segment and return true if distance > aDist
88  */
89 bool poly2segmentDRC( wxPoint* aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd, int aDist )
90 {
91  /* Test if the segment is contained in the polygon.
92  * This case is not covered by the following check if the segment is
93  * completely contained in the polygon (because edges don't intersect)!
94  */
95  if( TestPointInsidePolygon( aTref, aTrefCount, aSegStart ) )
96  return false;
97 
98  for( int ii = 0, jj = aTrefCount-1; ii < aTrefCount; jj = ii, ii++ )
99  { // for all edges in polygon
100  double d;
102  aTref[ii].x, aTref[ii].y, aTref[jj].x, aTref[jj].y,
103  aSegStart.x, aSegStart.y, aSegEnd.x, aSegEnd.y,
104  NULL, NULL, &d );
105 
106  if( intersect || ( d < aDist) )
107  return false;
108  }
109 
110  return true;
111 }
112 
113 /* compare a polygon to a point and return true if distance > aDist
114  * do not use this function for horizontal or vertical rectangles
115  * because there is a faster an easier way to compare the distance
116  */
117 bool convex2pointDRC( wxPoint* aTref, int aTrefCount, wxPoint aPcompare, int aDist )
118 {
119  /* Test if aPcompare point is contained in the polygon.
120  * This case is not covered by the following check if this point is inside the polygon
121  */
122  if( TestPointInsidePolygon( aTref, aTrefCount, aPcompare ) )
123  {
124  return false;
125  }
126 
127  // Test distance between aPcompare and each segment of the polygon:
128  for( int ii = 0, jj = aTrefCount - 1; ii < aTrefCount; jj = ii, ii++ ) // for all edge in polygon
129  {
130  if( TestSegmentHit( aPcompare, aTref[ii], aTref[jj], aDist ) )
131  return false;
132  }
133 
134  return true;
135 }
136 
137 
138 bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart, bool testPads )
139 {
140  TRACK* track;
141  wxPoint delta; // length on X and Y axis of segments
142  LSET layerMask;
143  int net_code_ref;
144  wxPoint shape_pos;
145 
146  std::vector<MARKER_PCB*> markers;
147 
148  auto commitMarkers = [&]()
149  {
150  // In legacy routing mode, do not add markers to the board.
151  // only shows the drc error message
153  {
154  while( markers.size() > 0 )
155  {
156  m_pcbEditorFrame->SetMsgPanel( markers.back() );
157  delete markers.back();
158  markers.pop_back();
159  }
160  }
161  else
162  {
163  BOARD_COMMIT commit( m_pcbEditorFrame );
164 
165  for( auto marker : markers )
166  commit.Add( marker );
167 
168  commit.Push( wxEmptyString, false, false );
169  }
170  };
171 
172  // Returns false if we should return false from call site, or true to continue
173  auto handleNewMarker = [&]() -> bool
174  {
176  {
177  if( markers.size() > 0 )
178  commitMarkers();
179 
180  return false;
181  }
182  else
183  return true;
184  };
185 
186  NETCLASSPTR netclass = aRefSeg->GetNetClass();
188 
189  /* In order to make some calculations more easier or faster,
190  * pads and tracks coordinates will be made relative to the reference segment origin
191  */
192  wxPoint origin = aRefSeg->GetStart(); // origin will be the origin of other coordinates
193 
194  m_segmEnd = delta = aRefSeg->GetEnd() - origin;
195  m_segmAngle = 0;
196 
197  layerMask = aRefSeg->GetLayerSet();
198  net_code_ref = aRefSeg->GetNetCode();
199 
200  /******************************************/
201  /* Phase 0 : via DRC tests : */
202  /******************************************/
203 
204  if( aRefSeg->Type() == PCB_VIA_T )
205  {
206  VIA *refvia = static_cast<VIA*>( aRefSeg );
207  wxPoint refviaPos = refvia->GetPosition();
208 
209  // test if the via size is smaller than minimum
210  if( refvia->GetViaType() == VIA_MICROVIA )
211  {
212  if( refvia->GetWidth() < dsnSettings.m_MicroViasMinSize )
213  {
214  markers.push_back( newMarker( refviaPos, refvia, DRCE_TOO_SMALL_MICROVIA ) );
215 
216  if( !handleNewMarker() )
217  return false;
218  }
219 
220  if( refvia->GetDrillValue() < dsnSettings.m_MicroViasMinDrill )
221  {
222  markers.push_back( newMarker( refviaPos, refvia, DRCE_TOO_SMALL_MICROVIA_DRILL ) );
223 
224  if( !handleNewMarker() )
225  return false;
226  }
227  }
228  else
229  {
230  if( refvia->GetWidth() < dsnSettings.m_ViasMinSize )
231  {
232  markers.push_back( newMarker( refviaPos, refvia, DRCE_TOO_SMALL_VIA ) );
233 
234  if( !handleNewMarker() )
235  return false;
236  }
237 
238  if( refvia->GetDrillValue() < dsnSettings.m_ViasMinDrill )
239  {
240  markers.push_back( newMarker( refviaPos, refvia, DRCE_TOO_SMALL_VIA_DRILL ) );
241 
242  if( !handleNewMarker() )
243  return false;
244  }
245  }
246 
247  // test if via's hole is bigger than its diameter
248  // This test is necessary since the via hole size and width can be modified
249  // and a default via hole can be bigger than some vias sizes
250  if( refvia->GetDrillValue() > refvia->GetWidth() )
251  {
252  markers.push_back( newMarker( refviaPos, refvia, DRCE_VIA_HOLE_BIGGER ) );
253 
254  if( !handleNewMarker() )
255  return false;
256  }
257 
258  // test if the type of via is allowed due to design rules
259  if( refvia->GetViaType() == VIA_MICROVIA && !dsnSettings.m_MicroViasAllowed )
260  {
261  markers.push_back( newMarker( refviaPos, refvia, DRCE_MICRO_VIA_NOT_ALLOWED ) );
262  if( !handleNewMarker() )
263  return false;
264  }
265 
266  // test if the type of via is allowed due to design rules
267  if( refvia->GetViaType() == VIA_BLIND_BURIED && !dsnSettings.m_BlindBuriedViaAllowed )
268  {
269  markers.push_back( newMarker( refviaPos, refvia, DRCE_BURIED_VIA_NOT_ALLOWED ) );
270 
271  if( !handleNewMarker() )
272  return false;
273  }
274 
275  // For microvias: test if they are blind vias and only between 2 layers
276  // because they are used for very small drill size and are drill by laser
277  // and **only one layer** can be drilled
278  if( refvia->GetViaType() == VIA_MICROVIA )
279  {
280  PCB_LAYER_ID layer1, layer2;
281  bool err = true;
282 
283  refvia->LayerPair( &layer1, &layer2 );
284 
285  if( layer1 > layer2 )
286  std::swap( layer1, layer2 );
287 
288  if( layer2 == B_Cu && layer1 == dsnSettings.GetCopperLayerCount() - 2 )
289  err = false;
290  else if( layer1 == F_Cu && layer2 == In1_Cu )
291  err = false;
292 
293  if( err )
294  {
295  markers.push_back( newMarker( refviaPos, refvia, DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR ) );
296 
297  if( !handleNewMarker() )
298  return false;
299  }
300  }
301 
302  }
303  else // This is a track segment
304  {
305  if( aRefSeg->GetWidth() < dsnSettings.m_TrackMinWidth )
306  {
307  wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
308 
309  markers.push_back( newMarker( refsegMiddle, aRefSeg, DRCE_TOO_SMALL_TRACK_WIDTH ) );
310 
311  if( !handleNewMarker() )
312  return false;
313  }
314  }
315 
316  // for a non horizontal or vertical segment Compute the segment angle
317  // in tenths of degrees and its length
318  if( delta.x || delta.y )
319  {
320  // Compute the segment angle in 0,1 degrees
321  m_segmAngle = ArcTangente( delta.y, delta.x );
322 
323  // Compute the segment length: we build an equivalent rotated segment,
324  // this segment is horizontal, therefore dx = length
325  RotatePoint( &delta, m_segmAngle ); // delta.x = length, delta.y = 0
326  }
327 
328  m_segmLength = delta.x;
329 
330  /******************************************/
331  /* Phase 1 : test DRC track to pads : */
332  /******************************************/
333 
334  /* Use a dummy pad to test DRC tracks versus holes, for pads not on all copper layers
335  * but having a hole
336  * This dummy pad has the size and shape of the hole
337  * to test tracks to pad hole DRC, using checkClearanceSegmToPad test function.
338  * Therefore, this dummy pad is a circle or an oval.
339  * A pad must have a parent because some functions expect a non null parent
340  * to find the parent board, and some other data
341  */
342  MODULE dummymodule( m_pcb ); // Creates a dummy parent
343  D_PAD dummypad( &dummymodule );
344 
345  dummypad.SetLayerSet( LSET::AllCuMask() ); // Ensure the hole is on all layers
346 
347  // Compute the min distance to pads
348  if( testPads )
349  {
350  unsigned pad_count = m_pcb->GetPadCount();
351 
352  auto pads = m_pcb->GetPads();
353 
354  for( unsigned ii = 0; ii < pad_count; ++ii )
355  {
356  D_PAD* pad = pads[ii];
357  SEG padSeg( pad->GetPosition(), pad->GetPosition() );
358 
359 
360  /* No problem if pads are on another layer,
361  * But if a drill hole exists (a pad on a single layer can have a hole!)
362  * we must test the hole
363  */
364  if( !( pad->GetLayerSet() & layerMask ).any() )
365  {
366  /* We must test the pad hole. In order to use the function
367  * checkClearanceSegmToPad(),a pseudo pad is used, with a shape and a
368  * size like the hole
369  */
370  if( pad->GetDrillSize().x == 0 )
371  continue;
372 
373  dummypad.SetSize( pad->GetDrillSize() );
374  dummypad.SetPosition( pad->GetPosition() );
375  dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
377  dummypad.SetOrientation( pad->GetOrientation() );
378 
379  m_padToTestPos = dummypad.GetPosition() - origin;
380 
381  if( !checkClearanceSegmToPad( &dummypad, aRefSeg->GetWidth(),
382  netclass->GetClearance() ) )
383  {
384  markers.push_back( newMarker( aRefSeg, pad, padSeg,
386 
387  if( !handleNewMarker() )
388  return false;
389  }
390 
391  continue;
392  }
393 
394  // The pad must be in a net (i.e pt_pad->GetNet() != 0 )
395  // but no problem if the pad netcode is the current netcode (same net)
396  if( pad->GetNetCode() // the pad must be connected
397  && net_code_ref == pad->GetNetCode() ) // the pad net is the same as current net -> Ok
398  continue;
399 
400  // DRC for the pad
401  shape_pos = pad->ShapePos();
402  m_padToTestPos = shape_pos - origin;
403 
404  if( !checkClearanceSegmToPad( pad, aRefSeg->GetWidth(), aRefSeg->GetClearance( pad ) ) )
405  {
406  markers.push_back( newMarker( aRefSeg, pad, padSeg, DRCE_TRACK_NEAR_PAD ) );
407 
408  if( !handleNewMarker() )
409  return false;
410  }
411  }
412  }
413 
414  /***********************************************/
415  /* Phase 2: test DRC with other track segments */
416  /***********************************************/
417 
418  // At this point the reference segment is the X axis
419 
420  // Test the reference segment with other track segments
421  wxPoint segStartPoint;
422  wxPoint segEndPoint;
423 
424  for( track = aStart; track; track = track->Next() )
425  {
426  // No problem if segments have the same net code:
427  if( net_code_ref == track->GetNetCode() )
428  continue;
429 
430  // No problem if segment are on different layers :
431  if( !( layerMask & track->GetLayerSet() ).any() )
432  continue;
433 
434  // the minimum distance = clearance plus half the reference track
435  // width plus half the other track's width
436  int w_dist = aRefSeg->GetClearance( track );
437  w_dist += ( aRefSeg->GetWidth() + track->GetWidth() ) / 2;
438 
439  // Due to many double to int conversions during calculations, which
440  // create rounding issues,
441  // the exact clearance margin cannot be really known.
442  // To avoid false bad DRC detection due to these rounding issues,
443  // slightly decrease the w_dist (remove one nanometer is enough !)
444  w_dist -= 1;
445 
446  // If the reference segment is a via, we test it here
447  if( aRefSeg->Type() == PCB_VIA_T )
448  {
449  delta = track->GetEnd() - track->GetStart();
450  segStartPoint = aRefSeg->GetStart() - track->GetStart();
451  wxPoint pos = aRefSeg->GetPosition();
452 
453  if( track->Type() == PCB_VIA_T )
454  {
455  // Test distance between two vias, i.e. two circles, trivial case
456  if( EuclideanNorm( segStartPoint ) < w_dist )
457  {
458  markers.push_back( newMarker( pos, aRefSeg, track, DRCE_VIA_NEAR_VIA ) );
459 
460  if( !handleNewMarker() )
461  return false;
462  }
463  }
464  else // test via to segment
465  {
466  // Compute l'angle du segment a tester;
467  double angle = ArcTangente( delta.y, delta.x );
468 
469  // Compute new coordinates ( the segment become horizontal)
470  RotatePoint( &delta, angle );
471  RotatePoint( &segStartPoint, angle );
472 
473  if( !checkMarginToCircle( segStartPoint, w_dist, delta.x ) )
474  {
475  markers.push_back( newMarker( pos, aRefSeg, track, DRCE_VIA_NEAR_TRACK ) );
476 
477  if( !handleNewMarker() )
478  return false;
479  }
480  }
481 
482  continue;
483  }
484 
485  /* We compute segStartPoint, segEndPoint = starting and ending point coordinates for
486  * the segment to test in the new axis : the new X axis is the
487  * reference segment. We must translate and rotate the segment to test
488  */
489  segStartPoint = track->GetStart() - origin;
490  segEndPoint = track->GetEnd() - origin;
491  RotatePoint( &segStartPoint, m_segmAngle );
492  RotatePoint( &segEndPoint, m_segmAngle );
493 
494  SEG seg( segStartPoint, segEndPoint );
495 
496  if( track->Type() == PCB_VIA_T )
497  {
498  if( checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
499  continue;
500 
501  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_NEAR_VIA ) );
502 
503  if( !handleNewMarker() )
504  return false;
505  }
506 
507  /* We have changed axis:
508  * the reference segment is Horizontal.
509  * 3 cases : the segment to test can be parallel, perpendicular or have another direction
510  */
511  if( segStartPoint.y == segEndPoint.y ) // parallel segments
512  {
513  if( abs( segStartPoint.y ) >= w_dist )
514  continue;
515 
516  // Ensure segStartPoint.x <= segEndPoint.x
517  if( segStartPoint.x > segEndPoint.x )
518  std::swap( segStartPoint.x, segEndPoint.x );
519 
520  if( segStartPoint.x > ( -w_dist ) && segStartPoint.x < ( m_segmLength + w_dist ) )
521  {
522  // the start point is inside the reference range
523  // X........
524  // O--REF--+
525 
526  // Fine test : we consider the rounded shape of each end of the track segment:
527  if( segStartPoint.x >= 0 && segStartPoint.x <= m_segmLength )
528  {
529  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_ENDS1 ) );
530 
531  if( !handleNewMarker() )
532  return false;
533  }
534 
535  if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
536  {
537  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_ENDS2 ) );
538 
539  if( !handleNewMarker() )
540  return false;
541  }
542  }
543 
544  if( segEndPoint.x > ( -w_dist ) && segEndPoint.x < ( m_segmLength + w_dist ) )
545  {
546  // the end point is inside the reference range
547  // .....X
548  // O--REF--+
549  // Fine test : we consider the rounded shape of the ends
550  if( segEndPoint.x >= 0 && segEndPoint.x <= m_segmLength )
551  {
552  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_ENDS3 ) );
553 
554  if( !handleNewMarker() )
555  return false;
556  }
557 
558  if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) )
559  {
560  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_ENDS4 ) );
561 
562  if( !handleNewMarker() )
563  return false;
564  }
565  }
566 
567  if( segStartPoint.x <= 0 && segEndPoint.x >= 0 )
568  {
569  // the segment straddles the reference range (this actually only
570  // checks if it straddles the origin, because the other cases where already
571  // handled)
572  // X.............X
573  // O--REF--+
574  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACK_SEGMENTS_TOO_CLOSE ) );
575 
576  if( !handleNewMarker() )
577  return false;
578  }
579  }
580  else if( segStartPoint.x == segEndPoint.x ) // perpendicular segments
581  {
582  if( segStartPoint.x <= -w_dist || segStartPoint.x >= m_segmLength + w_dist )
583  continue;
584 
585  // Test if segments are crossing
586  if( segStartPoint.y > segEndPoint.y )
587  std::swap( segStartPoint.y, segEndPoint.y );
588 
589  if( ( segStartPoint.y < 0 ) && ( segEndPoint.y > 0 ) )
590  {
591  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_TRACKS_CROSSING ) );
592 
593  if( !handleNewMarker() )
594  return false;
595  }
596 
597  // At this point the drc error is due to an end near a reference segm end
598  if( !checkMarginToCircle( segStartPoint, w_dist, m_segmLength ) )
599  {
600  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_ENDS_PROBLEM1 ) );
601 
602  if( !handleNewMarker() )
603  return false;
604  }
605  if( !checkMarginToCircle( segEndPoint, w_dist, m_segmLength ) )
606  {
607  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_ENDS_PROBLEM2 ) );
608 
609  if( !handleNewMarker() )
610  return false;
611  }
612  }
613  else // segments quelconques entre eux
614  {
615  // calcul de la "surface de securite du segment de reference
616  // First rought 'and fast) test : the track segment is like a rectangle
617 
618  m_xcliplo = m_ycliplo = -w_dist;
619  m_xcliphi = m_segmLength + w_dist;
620  m_ycliphi = w_dist;
621 
622  // A fine test is needed because a serment is not exactly a
623  // rectangle, it has rounded ends
624  if( !checkLine( segStartPoint, segEndPoint ) )
625  {
626  /* 2eme passe : the track has rounded ends.
627  * we must a fine test for each rounded end and the
628  * rectangular zone
629  */
630 
631  m_xcliplo = 0;
633 
634  if( !checkLine( segStartPoint, segEndPoint ) )
635  {
636  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_ENDS_PROBLEM3 ) );
637 
638  if( !handleNewMarker() )
639  return false;
640  }
641  else // The drc error is due to the starting or the ending point of the reference segment
642  {
643  // Test the starting and the ending point
644  segStartPoint = track->GetStart();
645  segEndPoint = track->GetEnd();
646  delta = segEndPoint - segStartPoint;
647 
648  // Compute the segment orientation (angle) en 0,1 degre
649  double angle = ArcTangente( delta.y, delta.x );
650 
651  // Compute the segment length: delta.x = length after rotation
652  RotatePoint( &delta, angle );
653 
654  /* Comute the reference segment coordinates relatives to a
655  * X axis = current tested segment
656  */
657  wxPoint relStartPos = aRefSeg->GetStart() - segStartPoint;
658  wxPoint relEndPos = aRefSeg->GetEnd() - segStartPoint;
659 
660  RotatePoint( &relStartPos, angle );
661  RotatePoint( &relEndPos, angle );
662 
663  if( !checkMarginToCircle( relStartPos, w_dist, delta.x ) )
664  {
665  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_ENDS_PROBLEM4 ) );
666 
667  if( !handleNewMarker() )
668  return false;
669  }
670 
671  if( !checkMarginToCircle( relEndPos, w_dist, delta.x ) )
672  {
673  markers.push_back( newMarker( aRefSeg, track, seg, DRCE_ENDS_PROBLEM5 ) );
674 
675  if( !handleNewMarker() )
676  return false;
677  }
678  }
679  }
680  }
681  }
682 
683  /***********************************************/
684  /* Phase 3: test DRC with zones */
685  /***********************************************/
686 
687  SEG refSeg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
688 
689  for( ZONE_CONTAINER* zone : m_pcb->Zones() )
690  {
691  if( zone->GetFilledPolysList().IsEmpty() || zone->GetIsKeepout() )
692  continue;
693 
694  if( !( layerMask & zone->GetLayerSet() ).any() )
695  continue;
696 
697  if( zone->GetNetCode() && zone->GetNetCode() == net_code_ref )
698  continue;
699 
700  int clearance = zone->GetClearance( aRefSeg );
701  SHAPE_POLY_SET* outline = const_cast<SHAPE_POLY_SET*>( &zone->GetFilledPolysList() );
702 
703  if( outline->Distance( refSeg, aRefSeg->GetWidth() ) < clearance )
704  addMarkerToPcb( newMarker( aRefSeg, zone, DRCE_TRACK_NEAR_ZONE ) );
705  }
706 
707  /***********************************************/
708  /* Phase 4: test DRC with to board edge */
709  /***********************************************/
710  {
711  SEG test_seg( aRefSeg->GetStart(), aRefSeg->GetEnd() );
712 
713  // the minimum distance = clearance plus half the reference track
714  // width. Board edges do not have width or clearance values, so we
715  // look for simple crossing.
716  SEG::ecoord w_dist = aRefSeg->GetClearance() + aRefSeg->GetWidth() / 2;
717  w_dist *= w_dist;
718 
719  for( auto it = m_board_outlines.IterateSegmentsWithHoles(); it; it++ )
720  {
721  if( test_seg.SquaredDistance( *it ) < w_dist )
722  {
723  auto pt = test_seg.NearestPoint( *it );
724  markers.push_back( newMarker( wxPoint( pt.x, pt.y ), aRefSeg, DRCE_TRACK_NEAR_EDGE ) );
725 
726  if( !handleNewMarker() )
727  return false;
728  }
729  }
730  }
731 
732 
733  if( markers.size() > 0 )
734  {
735  commitMarkers();
736  return false;
737  }
738  else
739  return true;
740 }
741 
742 
743 bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex )
744 {
745  if( !aArea->IsOnCopperLayer() ) // Cannot have a Drc error if not on copper layer
746  return true;
747  // Get polygon, contour and vertex index.
749 
750  // If the vertex does not exist, there is no conflict
751  if( !aArea->Outline()->GetRelativeIndices( aCornerIndex, &index ) )
752  return true;
753 
754  // Retrieve the selected contour
755  SHAPE_LINE_CHAIN contour;
756  contour = aArea->Outline()->Polygon( index.m_polygon )[index.m_contour];
757 
758  // Retrieve the segment that starts at aCornerIndex-th corner.
759  SEG selectedSegment = contour.Segment( index.m_vertex );
760 
761  VECTOR2I start = selectedSegment.A;
762  VECTOR2I end = selectedSegment.B;
763 
764  // iterate through all areas
765  for( int ia2 = 0; ia2 < m_pcb->GetAreaCount(); ia2++ )
766  {
767  ZONE_CONTAINER* area_to_test = m_pcb->GetArea( ia2 );
768  int zone_clearance = std::max( area_to_test->GetZoneClearance(),
769  aArea->GetZoneClearance() );
770 
771  // test for same layer
772  if( area_to_test->GetLayer() != aArea->GetLayer() )
773  continue;
774 
775  // Test for same net
776  if( ( aArea->GetNetCode() == area_to_test->GetNetCode() ) && (aArea->GetNetCode() >= 0) )
777  continue;
778 
779  // test for same priority
780  if( area_to_test->GetPriority() != aArea->GetPriority() )
781  continue;
782 
783  // test for same type
784  if( area_to_test->GetIsKeepout() != aArea->GetIsKeepout() )
785  continue;
786 
787  // For keepout, there is no clearance, so use a minimal value for it
788  // use 1, not 0 as value to avoid some issues in tests
789  if( area_to_test->GetIsKeepout() )
790  zone_clearance = 1;
791 
792  // test for ending line inside area_to_test
793  if( area_to_test->Outline()->Contains( end ) )
794  {
795  wxPoint pos( end.x, end.y );
796  m_currentMarker = newMarker( pos, aArea, area_to_test, DRCE_ZONES_INTERSECT );
797  return false;
798  }
799 
800  // now test spacing between areas
801  int ax1 = start.x;
802  int ay1 = start.y;
803  int ax2 = end.x;
804  int ay2 = end.y;
805 
806  // Iterate through all edges in the polygon.
808  for( iterator = area_to_test->Outline()->IterateSegmentsWithHoles(); iterator; iterator++ )
809  {
810  SEG segment = *iterator;
811 
812  int bx1 = segment.A.x;
813  int by1 = segment.A.y;
814  int bx2 = segment.B.x;
815  int by2 = segment.B.y;
816 
817  int x, y; // variables containing the intersecting point coordinates
818  int d = GetClearanceBetweenSegments( bx1, by1, bx2, by2,
819  0,
820  ax1, ay1, ax2, ay2,
821  0,
822  zone_clearance,
823  &x, &y );
824 
825  if( d < zone_clearance )
826  {
827  // COPPERAREA_COPPERAREA error : edge intersect or too close
828  m_currentMarker = newMarker( wxPoint( x, y ), aArea, area_to_test,
830  return false;
831  }
832 
833  }
834  }
835 
836  return true;
837 }
838 
839 
840 bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad )
841 {
842  int dist;
843  double pad_angle;
844 
845  // Get the clearance between the 2 pads. this is the min distance between aRefPad and aPad
846  int dist_min = aRefPad->GetClearance( aPad );
847 
848  // relativePadPos is the aPad shape position relative to the aRefPad shape position
849  wxPoint relativePadPos = aPad->ShapePos() - aRefPad->ShapePos();
850 
851  dist = KiROUND( EuclideanNorm( relativePadPos ) );
852 
853  // Quick test: Clearance is OK if the bounding circles are further away than "dist_min"
854  int delta = dist - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius();
855 
856  if( delta >= dist_min )
857  return true;
858 
859  /* Here, pads are near and DRC depend on the pad shapes
860  * We must compare distance using a fine shape analysis
861  * Because a circle or oval shape is the easier shape to test, try to have
862  * aRefPad shape type = PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL.
863  * if aRefPad = TRAP. and aPad = RECT, also swap pads
864  * Swap aRefPad and aPad if needed
865  */
866  bool swap_pads;
867  swap_pads = false;
868 
869  // swap pads to make comparisons easier
870  // Note also a ROUNDRECT pad with a corner radius = r can be considered as
871  // a smaller RECT (size - 2*r) with a clearance increased by r
872  // priority is aRefPad = ROUND then OVAL then RECT/ROUNDRECT then other
873  if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_SHAPE_CIRCLE )
874  {
875  // pad ref shape is here oval, rect, roundrect, trapezoid or custom
876  switch( aPad->GetShape() )
877  {
878  case PAD_SHAPE_CIRCLE:
879  swap_pads = true;
880  break;
881 
882  case PAD_SHAPE_OVAL:
883  swap_pads = true;
884  break;
885 
886  case PAD_SHAPE_RECT:
887  case PAD_SHAPE_ROUNDRECT:
888  if( aRefPad->GetShape() != PAD_SHAPE_OVAL )
889  swap_pads = true;
890  break;
891 
892  case PAD_SHAPE_TRAPEZOID:
893  case PAD_SHAPE_CUSTOM:
894  break;
895  }
896  }
897 
898  if( swap_pads )
899  {
900  std::swap( aRefPad, aPad );
901  relativePadPos = -relativePadPos;
902  }
903 
904  // corners of aRefPad (used only for rect/roundrect/trap pad)
905  wxPoint polyref[4];
906  // corners of aRefPad (used only for custom pad)
907  SHAPE_POLY_SET polysetref;
908 
909  // corners of aPad (used only for rect/roundrect/trap pad)
910  wxPoint polycompare[4];
911  // corners of aPad (used only custom pad)
912  SHAPE_POLY_SET polysetcompare;
913 
914  /* Because pad exchange, aRefPad shape is PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL,
915  * if one of the 2 pads was a PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL.
916  * Therefore, if aRefPad is a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID,
917  * aPad is also a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID
918  */
919  bool diag = true;
920 
921  switch( aRefPad->GetShape() )
922  {
923  case PAD_SHAPE_CIRCLE:
924 
925  /* One can use checkClearanceSegmToPad to test clearance
926  * aRefPad is like a track segment with a null length and a witdth = GetSize().x
927  */
928  m_segmLength = 0;
929  m_segmAngle = 0;
930 
931  m_segmEnd.x = m_segmEnd.y = 0;
932 
933  m_padToTestPos = relativePadPos;
934  diag = checkClearanceSegmToPad( aPad, aRefPad->GetSize().x, dist_min );
935  break;
936 
937  case PAD_SHAPE_TRAPEZOID:
938  case PAD_SHAPE_ROUNDRECT:
939  case PAD_SHAPE_RECT:
940  case PAD_SHAPE_CUSTOM:
941  // pad_angle = pad orient relative to the aRefPad orient
942  pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation();
943  NORMALIZE_ANGLE_POS( pad_angle );
944 
945  if( aRefPad->GetShape() == PAD_SHAPE_ROUNDRECT )
946  {
947  int padRadius = aRefPad->GetRoundRectCornerRadius();
948  dist_min += padRadius;
949  GetRoundRectCornerCenters( polyref, padRadius, wxPoint( 0, 0 ),
950  aRefPad->GetSize(), aRefPad->GetOrientation() );
951  }
952  else if( aRefPad->GetShape() == PAD_SHAPE_CUSTOM )
953  {
954  polysetref.Append( aRefPad->GetCustomShapeAsPolygon() );
955 
956  // The reference pad can be rotated. calculate the rotated
957  // coordiantes ( note, the ref pad position is the origin of
958  // coordinates for this drc test)
959  aRefPad->CustomShapeAsPolygonToBoardPosition( &polysetref,
960  wxPoint( 0, 0 ), aRefPad->GetOrientation() );
961  }
962  else
963  {
964  // BuildPadPolygon has meaning for rect a trapeziod shapes
965  // and returns the 4 corners
966  aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() );
967  }
968 
969  switch( aPad->GetShape() )
970  {
971  case PAD_SHAPE_ROUNDRECT:
972  case PAD_SHAPE_RECT:
973  case PAD_SHAPE_TRAPEZOID:
974  case PAD_SHAPE_CUSTOM:
975  if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
976  {
977  int padRadius = aPad->GetRoundRectCornerRadius();
978  dist_min += padRadius;
979  GetRoundRectCornerCenters( polycompare, padRadius, relativePadPos,
980  aPad->GetSize(), aPad->GetOrientation() );
981  }
982  else if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
983  {
984  polysetcompare.Append( aPad->GetCustomShapeAsPolygon() );
985 
986  // The pad to compare can be rotated. calculate the rotated
987  // coordinattes ( note, the pad to compare position
988  // is the relativePadPos for this drc test
989  aPad->CustomShapeAsPolygonToBoardPosition( &polysetcompare,
990  relativePadPos, aPad->GetOrientation() );
991  }
992  else
993  {
994  aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() );
995 
996  // Move aPad shape to relativePadPos
997  for( int ii = 0; ii < 4; ii++ )
998  polycompare[ii] += relativePadPos;
999  }
1000  // And now test polygons: We have 3 cases:
1001  // one poly is complex and the other is basic (has only 4 corners)
1002  // both polys are complex
1003  // both polys are basic (have only 4 corners) the most usual case
1004  if( polysetref.OutlineCount() && polysetcompare.OutlineCount() == 0)
1005  {
1006  const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 );
1007  // And now test polygons:
1008  if( !poly2polyDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
1009  polycompare, 4, dist_min ) )
1010  diag = false;
1011  }
1012  else if( polysetref.OutlineCount() == 0 && polysetcompare.OutlineCount())
1013  {
1014  const SHAPE_LINE_CHAIN& cmppoly = polysetcompare.COutline( 0 );
1015  // And now test polygons:
1016  if( !poly2polyDRC( (wxPoint*) &cmppoly.CPoint( 0 ), cmppoly.PointCount(),
1017  polyref, 4, dist_min ) )
1018  diag = false;
1019  }
1020  else if( polysetref.OutlineCount() && polysetcompare.OutlineCount() )
1021  {
1022  const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 );
1023  const SHAPE_LINE_CHAIN& cmppoly = polysetcompare.COutline( 0 );
1024 
1025  // And now test polygons:
1026  if( !poly2polyDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(),
1027  (wxPoint*) &cmppoly.CPoint( 0 ), cmppoly.PointCount(), dist_min ) )
1028  diag = false;
1029  }
1030  else if( !poly2polyDRC( polyref, 4, polycompare, 4, dist_min ) )
1031  diag = false;
1032  break;
1033 
1034  default:
1035  wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape %d" ), aPad->GetShape() );
1036  break;
1037  }
1038  break;
1039 
1040  case PAD_SHAPE_OVAL: /* an oval pad is like a track segment */
1041  {
1042  /* Create a track segment with same dimensions as the oval aRefPad
1043  * and use checkClearanceSegmToPad function to test aPad to aRefPad clearance
1044  */
1045  int segm_width;
1046  m_segmAngle = aRefPad->GetOrientation(); // Segment orient.
1047 
1048  if( aRefPad->GetSize().y < aRefPad->GetSize().x ) // Build an horizontal equiv segment
1049  {
1050  segm_width = aRefPad->GetSize().y;
1051  m_segmLength = aRefPad->GetSize().x - aRefPad->GetSize().y;
1052  }
1053  else // Vertical oval: build an horizontal equiv segment and rotate 90.0 deg
1054  {
1055  segm_width = aRefPad->GetSize().x;
1056  m_segmLength = aRefPad->GetSize().y - aRefPad->GetSize().x;
1057  m_segmAngle += 900;
1058  }
1059 
1060  /* the start point must be 0,0 and currently relativePadPos
1061  * is relative the center of pad coordinate */
1062  wxPoint segstart;
1063  segstart.x = -m_segmLength / 2; // Start point coordinate of the horizontal equivalent segment
1064 
1065  RotatePoint( &segstart, m_segmAngle ); // actual start point coordinate of the equivalent segment
1066  // Calculate segment end position relative to the segment origin
1067  m_segmEnd.x = -2 * segstart.x;
1068  m_segmEnd.y = -2 * segstart.y;
1069 
1070  // Recalculate the equivalent segment angle in 0,1 degrees
1071  // to prepare a call to checkClearanceSegmToPad()
1073 
1074  // move pad position relative to the segment origin
1075  m_padToTestPos = relativePadPos - segstart;
1076 
1077  // Use segment to pad check to test the second pad:
1078  diag = checkClearanceSegmToPad( aPad, segm_width, dist_min );
1079  break;
1080  }
1081 
1082  default:
1083  wxLogDebug( wxT( "DRC::checkClearancePadToPad: unknown pad shape" ) );
1084  break;
1085  }
1086 
1087  return diag;
1088 }
1089 
1090 
1091 /* test if distance between a segment is > aMinDist
1092  * segment start point is assumed in (0,0) and segment start point in m_segmEnd
1093  * and its orientation is m_segmAngle (m_segmAngle must be already initialized)
1094  * and have aSegmentWidth.
1095  */
1096 bool DRC::checkClearanceSegmToPad( const D_PAD* aPad, int aSegmentWidth, int aMinDist )
1097 {
1098  // Note:
1099  // we are using a horizontal segment for test, because we know here
1100  // only the length and orientation+ of the segment
1101  // Therefore the coordinates of the shape of pad to compare
1102  // must be calculated in a axis system rotated by m_segmAngle
1103  // and centered to the segment origin, before they can be tested
1104  // against the segment
1105  // We are using:
1106  // m_padToTestPos the position of the pad shape in this axis system
1107  // m_segmAngle the axis system rotation
1108 
1109  int segmHalfWidth = aSegmentWidth / 2;
1110  int distToLine = segmHalfWidth + aMinDist;
1111 
1112  wxSize padHalfsize; // half dimension of the pad
1113 
1114  if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
1115  {
1116  // For a custom pad, the pad size has no meaning, we only can
1117  // use the bounding radius
1118  padHalfsize.x = padHalfsize.y = aPad->GetBoundingRadius();
1119  }
1120  else
1121  {
1122  padHalfsize = aPad->GetSize() / 2;
1123  }
1124 
1125  if( aPad->GetShape() == PAD_SHAPE_TRAPEZOID ) // The size is bigger, due to GetDelta() extra size
1126  {
1127  padHalfsize.x += std::abs(aPad->GetDelta().y) / 2; // Remember: GetDelta().y is the GetSize().x change
1128  padHalfsize.y += std::abs(aPad->GetDelta().x) / 2; // Remember: GetDelta().x is the GetSize().y change
1129  }
1130 
1131  if( aPad->GetShape() == PAD_SHAPE_CIRCLE )
1132  {
1133  /* Easy case: just test the distance between segment and pad centre
1134  * calculate pad coordinates in the X,Y axis with X axis = segment to test
1135  */
1137  return checkMarginToCircle( m_padToTestPos, distToLine + padHalfsize.x, m_segmLength );
1138  }
1139 
1140  /* calculate the bounding box of the pad, including the clearance and the segment width
1141  * if the line from 0 to m_segmEnd does not intersect this bounding box,
1142  * the clearance is always OK
1143  * But if intersect, a better analysis of the pad shape must be done.
1144  */
1145  m_xcliplo = m_padToTestPos.x - distToLine - padHalfsize.x;
1146  m_ycliplo = m_padToTestPos.y - distToLine - padHalfsize.y;
1147  m_xcliphi = m_padToTestPos.x + distToLine + padHalfsize.x;
1148  m_ycliphi = m_padToTestPos.y + distToLine + padHalfsize.y;
1149 
1150  wxPoint startPoint( 0, 0 );
1151  wxPoint endPoint = m_segmEnd;
1152 
1153  double orient = aPad->GetOrientation();
1154 
1155  RotatePoint( &startPoint, m_padToTestPos, -orient );
1156  RotatePoint( &endPoint, m_padToTestPos, -orient );
1157 
1158  if( checkLine( startPoint, endPoint ) )
1159  return true;
1160 
1161  /* segment intersects the bounding box. But there is not always a DRC error.
1162  * A fine analysis of the pad shape must be done.
1163  */
1164  switch( aPad->GetShape() )
1165  {
1166  case PAD_SHAPE_CIRCLE:
1167  // This case was already tested, so it cannot be found here.
1168  // it is here just to avoid compil warning, and to remember
1169  // it is already tested.
1170  return false;
1171 
1172  case PAD_SHAPE_OVAL:
1173  {
1174  /* an oval is a complex shape, but is a rectangle and 2 circles
1175  * these 3 basic shapes are more easy to test.
1176  *
1177  * In calculations we are using a vertical or horizontal oval shape
1178  * (i.e. a vertical or horizontal rounded segment)
1179  */
1180  wxPoint cstart = m_padToTestPos;
1181  wxPoint cend = m_padToTestPos; // center of each circle
1182  int delta = std::abs( padHalfsize.y - padHalfsize.x );
1183  int radius = std::min( padHalfsize.y, padHalfsize.x );
1184 
1185  if( padHalfsize.x > padHalfsize.y ) // horizontal equivalent segment
1186  {
1187  cstart.x -= delta;
1188  cend.x += delta;
1189  // Build the rectangular clearance area between the two circles
1190  // the rect starts at cstart.x and ends at cend.x and its height
1191  // is (radius + distToLine)*2
1192  m_xcliplo = cstart.x;
1193  m_ycliplo = cstart.y - radius - distToLine;
1194  m_xcliphi = cend.x;
1195  m_ycliphi = cend.y + radius + distToLine;
1196  }
1197  else // vertical equivalent segment
1198  {
1199  cstart.y -= delta;
1200  cend.y += delta;
1201  // Build the rectangular clearance area between the two circles
1202  // the rect starts at cstart.y and ends at cend.y and its width
1203  // is (radius + distToLine)*2
1204  m_xcliplo = cstart.x - distToLine - radius;
1205  m_ycliplo = cstart.y;
1206  m_xcliphi = cend.x + distToLine + radius;
1207  m_ycliphi = cend.y;
1208  }
1209 
1210  // Test the rectangular clearance area between the two circles (the rounded ends)
1211  // If the segment legth is zero, only check the endpoints, skip the rectangle
1212  if( m_segmLength && !checkLine( startPoint, endPoint ) )
1213  {
1214  return false;
1215  }
1216 
1217  // test the first end
1218  // Calculate the actual position of the circle, given the pad orientation:
1219  RotatePoint( &cstart, m_padToTestPos, orient );
1220 
1221  // Calculate the actual position of the circle in the new X,Y axis, relative
1222  // to the segment:
1223  RotatePoint( &cstart, m_segmAngle );
1224 
1225  if( !checkMarginToCircle( cstart, radius + distToLine, m_segmLength ) )
1226  {
1227  return false;
1228  }
1229 
1230  // test the second end
1231  RotatePoint( &cend, m_padToTestPos, orient );
1232  RotatePoint( &cend, m_segmAngle );
1233 
1234  if( !checkMarginToCircle( cend, radius + distToLine, m_segmLength ) )
1235  {
1236  return false;
1237  }
1238  }
1239  break;
1240 
1241  case PAD_SHAPE_ROUNDRECT:
1242  {
1243  // a round rect is a smaller rect, with a clearance augmented by the corners radius
1244  int r = aPad->GetRoundRectCornerRadius();
1245  padHalfsize.x -= r;
1246  padHalfsize.y -= r;
1247  distToLine += r;
1248  }
1249  // Fall through
1250  case PAD_SHAPE_RECT:
1251  // the area to test is a rounded rectangle.
1252  // this can be done by testing 2 rectangles and 4 circles (the corners)
1253 
1254  // Testing the first rectangle dimx + distToLine, dimy:
1255  m_xcliplo = m_padToTestPos.x - padHalfsize.x - distToLine;
1256  m_ycliplo = m_padToTestPos.y - padHalfsize.y;
1257  m_xcliphi = m_padToTestPos.x + padHalfsize.x + distToLine;
1258  m_ycliphi = m_padToTestPos.y + padHalfsize.y;
1259 
1260  if( !checkLine( startPoint, endPoint ) )
1261  return false;
1262 
1263  // Testing the second rectangle dimx , dimy + distToLine
1264  m_xcliplo = m_padToTestPos.x - padHalfsize.x;
1265  m_ycliplo = m_padToTestPos.y - padHalfsize.y - distToLine;
1266  m_xcliphi = m_padToTestPos.x + padHalfsize.x;
1267  m_ycliphi = m_padToTestPos.y + padHalfsize.y + distToLine;
1268 
1269  if( !checkLine( startPoint, endPoint ) )
1270  return false;
1271 
1272  // testing the 4 circles which are the clearance area of each corner:
1273 
1274  // testing the left top corner of the rectangle
1275  startPoint.x = m_padToTestPos.x - padHalfsize.x;
1276  startPoint.y = m_padToTestPos.y - padHalfsize.y;
1277  RotatePoint( &startPoint, m_padToTestPos, orient );
1278  RotatePoint( &startPoint, m_segmAngle );
1279 
1280  if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) )
1281  return false;
1282 
1283  // testing the right top corner of the rectangle
1284  startPoint.x = m_padToTestPos.x + padHalfsize.x;
1285  startPoint.y = m_padToTestPos.y - padHalfsize.y;
1286  RotatePoint( &startPoint, m_padToTestPos, orient );
1287  RotatePoint( &startPoint, m_segmAngle );
1288 
1289  if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) )
1290  return false;
1291 
1292  // testing the left bottom corner of the rectangle
1293  startPoint.x = m_padToTestPos.x - padHalfsize.x;
1294  startPoint.y = m_padToTestPos.y + padHalfsize.y;
1295  RotatePoint( &startPoint, m_padToTestPos, orient );
1296  RotatePoint( &startPoint, m_segmAngle );
1297 
1298  if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) )
1299  return false;
1300 
1301  // testing the right bottom corner of the rectangle
1302  startPoint.x = m_padToTestPos.x + padHalfsize.x;
1303  startPoint.y = m_padToTestPos.y + padHalfsize.y;
1304  RotatePoint( &startPoint, m_padToTestPos, orient );
1305  RotatePoint( &startPoint, m_segmAngle );
1306 
1307  if( !checkMarginToCircle( startPoint, distToLine, m_segmLength ) )
1308  return false;
1309 
1310  break;
1311 
1312  case PAD_SHAPE_TRAPEZOID:
1313  {
1314  wxPoint poly[4];
1315  aPad->BuildPadPolygon( poly, wxSize( 0, 0 ), orient );
1316 
1317  // Move shape to m_padToTestPos
1318  for( int ii = 0; ii < 4; ii++ )
1319  {
1320  poly[ii] += m_padToTestPos;
1321  RotatePoint( &poly[ii], m_segmAngle );
1322  }
1323 
1324  if( !poly2segmentDRC( poly, 4, wxPoint( 0, 0 ),
1325  wxPoint(m_segmLength,0), distToLine ) )
1326  return false;
1327  }
1328  break;
1329 
1330  case PAD_SHAPE_CUSTOM:
1331  {
1332  SHAPE_POLY_SET polyset;
1333  polyset.Append( aPad->GetCustomShapeAsPolygon() );
1334  // The pad can be rotated. calculate the coordinates
1335  // relatives to the segment being tested
1336  // Note, the pad position relative to the segment origin
1337  // is m_padToTestPos
1338  aPad->CustomShapeAsPolygonToBoardPosition( &polyset,
1339  m_padToTestPos, orient );
1340 
1341  // Rotate all coordinates by m_segmAngle, because the segment orient
1342  // is m_segmAngle
1343  // we are using a horizontal segment for test, because we know here
1344  // only the lenght and orientation+ of the segment
1345  // therefore all coordinates of the pad to test must be rotated by
1346  // m_segmAngle (they are already relative to the segment origin)
1347  aPad->CustomShapeAsPolygonToBoardPosition( &polyset,
1348  wxPoint( 0, 0 ), m_segmAngle );
1349 
1350  const SHAPE_LINE_CHAIN& refpoly = polyset.COutline( 0 );
1351 
1352  if( !poly2segmentDRC( (wxPoint*) &refpoly.CPoint( 0 ),
1353  refpoly.PointCount(),
1354  wxPoint( 0, 0 ), wxPoint(m_segmLength,0),
1355  distToLine ) )
1356  return false;
1357  }
1358  break;
1359  }
1360 
1361  return true;
1362 }
1363 
1364 
1371 bool DRC::checkMarginToCircle( wxPoint aCentre, int aRadius, int aLength )
1372 {
1373  if( abs( aCentre.y ) >= aRadius ) // trivial case
1374  return true;
1375 
1376  // Here, distance between aCentre and X axis is < aRadius
1377  if( (aCentre.x > -aRadius ) && ( aCentre.x < (aLength + aRadius) ) )
1378  {
1379  if( (aCentre.x >= 0) && (aCentre.x <= aLength) )
1380  return false; // aCentre is between the starting point and the ending point of the segm
1381 
1382  if( aCentre.x > aLength ) // aCentre is after the ending point
1383  aCentre.x -= aLength; // move aCentre to the starting point of the segment
1384 
1385  if( EuclideanNorm( aCentre ) < aRadius )
1386  // distance between aCentre and the starting point or the ending point is < aRadius
1387  return false;
1388  }
1389 
1390  return true;
1391 }
1392 
1393 
1394 // Helper function used in checkLine::
1395 static inline int USCALE( unsigned arg, unsigned num, unsigned den )
1396 {
1397  int ii;
1398  double result;
1399 
1400  // Trivial check first
1401  if( !arg || !num)
1402  return 0;
1403 
1404  // If arg and num are both non-zero but den is zero, we return effective infinite
1405  if( !den )
1406  return INT_MAX;
1407 
1408  result = ( (double) arg * num ) / den;
1409 
1410  // Ensure that our result doesn't overflow into the sign bit
1411  if( result > INT_MAX )
1412  return INT_MAX;
1413 
1414  ii = KiROUND( ( (double) arg * num ) / den );
1415  return ii;
1416 }
1417 
1418 
1424 bool DRC::checkLine( wxPoint aSegStart, wxPoint aSegEnd )
1425 {
1426 #define WHEN_OUTSIDE return true
1427 #define WHEN_INSIDE
1428  int temp;
1429 
1430  if( aSegStart.x > aSegEnd.x )
1431  std::swap( aSegStart, aSegEnd );
1432 
1433  if( (aSegEnd.x <= m_xcliplo) || (aSegStart.x >= m_xcliphi) )
1434  {
1435  WHEN_OUTSIDE;
1436  }
1437 
1438  if( aSegStart.y < aSegEnd.y )
1439  {
1440  if( (aSegEnd.y <= m_ycliplo) || (aSegStart.y >= m_ycliphi) )
1441  {
1442  WHEN_OUTSIDE;
1443  }
1444 
1445  if( aSegStart.y < m_ycliplo )
1446  {
1447  temp = USCALE( (aSegEnd.x - aSegStart.x), (m_ycliplo - aSegStart.y),
1448  (aSegEnd.y - aSegStart.y) );
1449 
1450  if( (aSegStart.x += temp) >= m_xcliphi )
1451  {
1452  WHEN_OUTSIDE;
1453  }
1454 
1455  aSegStart.y = m_ycliplo;
1456  WHEN_INSIDE;
1457  }
1458 
1459  if( aSegEnd.y > m_ycliphi )
1460  {
1461  temp = USCALE( (aSegEnd.x - aSegStart.x), (aSegEnd.y - m_ycliphi),
1462  (aSegEnd.y - aSegStart.y) );
1463 
1464  if( (aSegEnd.x -= temp) <= m_xcliplo )
1465  {
1466  WHEN_OUTSIDE;
1467  }
1468 
1469  aSegEnd.y = m_ycliphi;
1470  WHEN_INSIDE;
1471  }
1472 
1473  if( aSegStart.x < m_xcliplo )
1474  {
1475  temp = USCALE( (aSegEnd.y - aSegStart.y), (m_xcliplo - aSegStart.x),
1476  (aSegEnd.x - aSegStart.x) );
1477  aSegStart.y += temp;
1478  aSegStart.x = m_xcliplo;
1479  WHEN_INSIDE;
1480  }
1481 
1482  if( aSegEnd.x > m_xcliphi )
1483  {
1484  temp = USCALE( (aSegEnd.y - aSegStart.y), (aSegEnd.x - m_xcliphi),
1485  (aSegEnd.x - aSegStart.x) );
1486  aSegEnd.y -= temp;
1487  aSegEnd.x = m_xcliphi;
1488  WHEN_INSIDE;
1489  }
1490  }
1491  else
1492  {
1493  if( (aSegStart.y <= m_ycliplo) || (aSegEnd.y >= m_ycliphi) )
1494  {
1495  WHEN_OUTSIDE;
1496  }
1497 
1498  if( aSegStart.y > m_ycliphi )
1499  {
1500  temp = USCALE( (aSegEnd.x - aSegStart.x), (aSegStart.y - m_ycliphi),
1501  (aSegStart.y - aSegEnd.y) );
1502 
1503  if( (aSegStart.x += temp) >= m_xcliphi )
1504  {
1505  WHEN_OUTSIDE;
1506  }
1507 
1508  aSegStart.y = m_ycliphi;
1509  WHEN_INSIDE;
1510  }
1511 
1512  if( aSegEnd.y < m_ycliplo )
1513  {
1514  temp = USCALE( (aSegEnd.x - aSegStart.x), (m_ycliplo - aSegEnd.y),
1515  (aSegStart.y - aSegEnd.y) );
1516 
1517  if( (aSegEnd.x -= temp) <= m_xcliplo )
1518  {
1519  WHEN_OUTSIDE;
1520  }
1521 
1522  aSegEnd.y = m_ycliplo;
1523  WHEN_INSIDE;
1524  }
1525 
1526  if( aSegStart.x < m_xcliplo )
1527  {
1528  temp = USCALE( (aSegStart.y - aSegEnd.y), (m_xcliplo - aSegStart.x),
1529  (aSegEnd.x - aSegStart.x) );
1530  aSegStart.y -= temp;
1531  aSegStart.x = m_xcliplo;
1532  WHEN_INSIDE;
1533  }
1534 
1535  if( aSegEnd.x > m_xcliphi )
1536  {
1537  temp = USCALE( (aSegStart.y - aSegEnd.y), (aSegEnd.x - m_xcliphi),
1538  (aSegEnd.x - aSegStart.x) );
1539  aSegEnd.y += temp;
1540  aSegEnd.x = m_xcliphi;
1541  WHEN_INSIDE;
1542  }
1543  }
1544 
1545  // Do not divide here to avoid rounding errors
1546  if( ( (aSegEnd.x + aSegStart.x) < m_xcliphi * 2 )
1547  && ( (aSegEnd.x + aSegStart.x) > m_xcliplo * 2) \
1548  && ( (aSegEnd.y + aSegStart.y) < m_ycliphi * 2 )
1549  && ( (aSegEnd.y + aSegStart.y) > m_ycliplo * 2 ) )
1550  {
1551  return false;
1552  }
1553  else
1554  {
1555  return true;
1556  }
1557 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:112
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:676
#define DRCE_TOO_SMALL_MICROVIA_DRILL
Too small micro via drill.
Definition: drc.h:76
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201
static int USCALE(unsigned arg, unsigned num, unsigned den)
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:59
#define DRCE_TOO_SMALL_VIA
Too small via size.
Definition: drc.h:73
static const int dist[10][10]
Definition: ar_matrix.cpp:320
#define WHEN_OUTSIDE
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:121
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
int m_ycliplo
Definition: drc.h:220
const SHAPE_POLY_SET & GetCustomShapeAsPolygon() const
Accessor to the custom shape as one polygon.
Definition: class_pad.h:341
void BuildPadPolygon(wxPoint aCoord[4], wxSize aInflateValue, double aRotation) const
Function BuildPadPolygon Has meaning only for polygonal pads (trapezoid and rectangular) Build the Co...
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
int PointCount() const
Function PointCount()
bool TestForIntersectionOfStraightLineSegments(int x1i, int y1i, int x1f, int y1f, int x2i, int y2i, int x2f, int y2f, int *x, int *y, double *d)
Function TestForIntersectionOfStraightLineSegments Test for intersection of line segments If lines ar...
Class BOARD to handle a board.
int GetRoundRectCornerRadius() const
Function GetRoundRectCornerRadius Has meaning only for rounded rect pads.
Definition: class_pad.h:531
VECTOR2I::extended_type ecoord
Definition: seg.h:39
#define DRCE_TRACK_ENDS4
2 parallel track segments too close: fine end point test
Definition: drc.h:56
int m_ycliphi
Definition: drc.h:222
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:175
bool TestPointInsidePolygon(const wxPoint *aPolysList, int aCount, const wxPoint &aRefPoint)
Function TestPointInsidePolygon (overlaid) same as previous, but mainly use wxPoint.
SHAPE_POLY_SET * Outline()
Definition: class_zone.h:243
bool poly2segmentDRC(wxPoint *aTref, int aTrefCount, wxPoint aSegStart, wxPoint aSegEnd, int aDist)
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, bool aIgnoreHoles=false) const
Returns true if a given subpolygon contains the point aP.
#define DRCE_TRACK_NEAR_PAD
pad too close to track
Definition: drc.h:49
Struct VERTEX_INDEX.
int m_segmLength
Definition: drc.h:214
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:219
Classes to handle copper zones.
Class SEGMENT_ITERATOR_TEMPLATE.
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:388
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
int GetClearanceBetweenSegments(int x1i, int y1i, int x1f, int y1f, int w1, int x2i, int y2i, int x2f, int y2f, int w2, int max_cl, int *x, int *y)
int OutlineCount() const
Returns the number of outlines in the set
void NORMALIZE_ANGLE_POS(T &Angle)
Definition: trigo.h:241
#define DRCE_ZONES_INTERSECT
copper area outlines intersect
Definition: drc.h:67
const wxSize & GetDrillSize() const
Definition: class_pad.h:275
wxPoint m_padToTestPos
Definition: drc.h:205
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:216
#define abs(a)
Definition: auxiliary.h:84
static const int delta[8][2]
Definition: solve.cpp:112
const wxPoint & GetEnd() const
Definition: class_track.h:123
#define DRCE_TRACK_ENDS2
2 parallel track segments too close: fine start point test
Definition: drc.h:54
#define DRCE_TRACK_SEGMENTS_TOO_CLOSE
2 parallel track segments too close: segm ends between segref ends
Definition: drc.h:57
Functions relatives to tracks, vias and segments used to fill zones.
#define DRCE_BURIED_VIA_NOT_ALLOWED
buried vias are not allowed
Definition: drc.h:95
#define DRCE_TRACK_NEAR_VIA
track too close to via
Definition: drc.h:50
BOARD * m_pcb
Definition: drc.h:225
#define DRCE_TOO_SMALL_MICROVIA
Too small micro via size.
Definition: drc.h:74
bool GetIsKeepout() const
Accessors to parameters used in Keepout zones:
Definition: class_zone.h:630
bool checkLine(wxPoint aSegStart, wxPoint aSegEnd)
Function checkLine (helper function used in drc calculations to see if one track is in contact with a...
#define DRCE_VIA_HOLE_BIGGER
via&#39;s hole is bigger than its diameter
Definition: drc.h:65
Markers used to show a drc problem on boards.
PCB_LAYER_ID
A quick note on layer IDs:
void addMarkerToPcb(MARKER_PCB *aMarker)
Adds a DRC marker to the PCB through the COMMIT mechanism.
Definition: drc.cpp:100
Class LSET is a set of PCB_LAYER_IDs.
int GetCopperLayerCount() const
Function GetCopperLayerCount.
void CustomShapeAsPolygonToBoardPosition(SHAPE_POLY_SET *aMergedPolygon, wxPoint aPosition, double aRotation) const
When created, the corners coordinates are relative to the pad position, orientation 0...
VIATYPE_T GetViaType() const
Definition: class_track.h:461
const wxPoint GetPosition() const override
Definition: class_track.h:117
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:170
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
std::shared_ptr< NETCLASS > GetNetClass() const
Function GetNetClass returns the NETCLASS for this item.
int GetBoundingRadius() const
Function GetBoundingRadius returns the radius of a minimum sized circle which fully encloses this pad...
Definition: class_pad.h:612
#define DRCE_MICRO_VIA_INCORRECT_LAYER_PAIR
micro via&#39;s layer pair incorrect (layers must be adjacent)
Definition: drc.h:66
Class SHAPE_POLY_SET.
const wxPoint & GetStart() const
Definition: class_track.h:126
int m_TrackMinWidth
track min value for width ((min copper size value
#define DRCE_TRACK_ENDS1
2 parallel track segments too close: fine start point test
Definition: drc.h:53
int m_ViasMinSize
vias (not micro vias) min diameter
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:402
bool GetRelativeIndices(int aGlobalIdx, VERTEX_INDEX *aRelativeIndices) const
Function GetRelativeIndices.
#define DRCE_TRACK_ENDS3
2 parallel track segments too close: fine end point test
Definition: drc.h:55
#define DRCE_ENDS_PROBLEM2
track ends are too close
Definition: drc.h:60
bool convex2pointDRC(wxPoint *aTref, int aTrefCount, wxPoint aPcompare, int aDist)
int m_ViasMinDrill
vias (not micro vias) min drill diameter
virtual LSET GetLayerSet() const
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
#define DRCE_TRACK_NEAR_ZONE
track & zone collide or are too close together
Definition: drc.h:89
#define DRCE_ENDS_PROBLEM3
track ends are too close
Definition: drc.h:61
const wxSize & GetSize() const
Definition: class_pad.h:269
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:539
void SetSize(const wxSize &aSize)
Definition: class_pad.h:268
static bool checkMarginToCircle(wxPoint aCentre, int aRadius, int aLength)
Check the distance from a point to a segment.
MARKER_PCB * newMarker(TRACK *aTrack, BOARD_ITEM *aConflitItem, const SEG &aConflictSeg, int aErrorCode)
Function newMarker Creates a marker on a track, via or pad.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
int GetAreaCount() const
Function GetAreaCount.
Definition: class_board.h:1026
bool m_reportAllTrackErrors
Definition: drc.h:187
static bool intersect(const SEGMENT_WITH_NORMALS &aSeg, const SFVEC2F &aStart, const SFVEC2F &aEnd)
Definition: cpolygon2d.cpp:293
virtual int GetClearance(BOARD_CONNECTED_ITEM *aItem=NULL) const override
Function GetClearance returns the clearance in internal units.
int m_xcliphi
Definition: drc.h:221
int m_MicroViasMinSize
micro vias (not vias) min diameter
PCB_EDIT_FRAME * m_pcbEditorFrame
The pcb frame editor which owns the board.
Definition: drc.h:224
string & err
Definition: json11.cpp:598
const wxPoint GetPosition() const override
Definition: class_track.h:433
unsigned GetPadCount()
Function GetPadCount.
bool doEdgeZoneDrc(ZONE_CONTAINER *aArea, int aCornerIndex)
Test a segment in ZONE_CONTAINER * aArea: Test Edge inside other areas Test Edge too close other area...
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...
#define DRCE_ENDS_PROBLEM4
track ends are too close
Definition: drc.h:62
bool checkClearancePadToPad(D_PAD *aRefPad, D_PAD *aPad)
int GetNetCode() const
Function GetNetCode.
MARKER_PCB * m_currentMarker
Definition: drc.h:191
Definition: seg.h:36
#define DRCE_VIA_NEAR_VIA
via too close to via
Definition: drc.h:51
#define WHEN_INSIDE
#define DRCE_TRACKS_CROSSING
tracks are crossing
Definition: drc.h:58
bool checkClearanceSegmToPad(const D_PAD *aPad, int aSegmentWidth, int aMinDist)
Check the distance from a pad to segment.
#define DRCE_ENDS_PROBLEM5
track ends are too close
Definition: drc.h:63
const std::vector< D_PAD * > GetPads()
Function GetPads returns a reference to a list of all the pads.
wxPoint m_segmEnd
Definition: drc.h:206
void SetLayerSet(LSET aLayerMask)
Definition: class_pad.h:401
SEG Segment(int aIndex)
Function Segment()
bool IsOnCopperLayer() const
Function IsOnCopperLayer.
Definition: class_zone.cpp:181
SHAPE_POLY_SET m_board_outlines
The board outline including cutouts.
Definition: drc.h:226
ZONE_CONTAINERS & Zones()
Definition: class_board.h:257
TRACK * Next() const
Definition: class_track.h:103
ZONE_CONTAINER * GetArea(int index) const
Function GetArea returns the Area (Zone Container) at a given index.
Definition: class_board.h:997
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
#define max(a, b)
Definition: auxiliary.h:86
Class SHAPE_LINE_CHAIN.
int GetWidth() const
Definition: class_track.h:120
int Distance(VECTOR2I aPoint)
Function DistanceToPolygon computes the minimum distance between aPoint and all the polygons in the s...
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees, but soon degrees.
Definition: class_pad.h:382
VECTOR2I A
Definition: seg.h:44
#define DRCE_VIA_NEAR_TRACK
via too close to track
Definition: drc.h:52
#define DRCE_ZONES_TOO_CLOSE
copper area outlines are too close
Definition: drc.h:68
const wxSize & GetDelta() const
Definition: class_pad.h:272
bool poly2polyDRC(wxPoint *aTref, int aTrefCount, wxPoint *aTcompare, int aTcompareCount, int aDist)
DRC control: these functions make a DRC between pads, tracks and pads versus tracks.
void GetRoundRectCornerCenters(wxPoint aCenters[4], int aRadius, const wxPoint &aPosition, const wxSize &aSize, double aRotation)
Helper function GetRoundRectCornerCenters Has meaning only for rounded rect Returns the centers of th...
int GetClearance(BOARD_CONNECTED_ITEM *aItem=NULL) const override
Function GetClearance returns the clearance in internal units.
Definition: class_pad.cpp:562
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Executes the changes.
void SetShape(PAD_SHAPE_T aShape)
Definition: class_pad.h:217
wxPoint ShapePos() const
Definition: class_pad.cpp:516
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: class_pad.cpp:417
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
bool doTrackDrc(TRACK *aRefSeg, TRACK *aStart, bool doPads=true)
Test the current segment.
Module description (excepted pads)
#define DRCE_TRACK_NEAR_EDGE
track too close to board edge
Definition: drc.h:98
bool m_MicroViasAllowed
true to allow micro vias
POLYGON & Polygon(int aIndex)
Returns the aIndex-th subpolygon in the set
#define DRCE_MICRO_VIA_NOT_ALLOWED
micro vias are not allowed
Definition: drc.h:94
int m_MicroViasMinDrill
micro vias (not vias) min drill diameter
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Function TestSegmentHit test for hit on line segment i.e.
Definition: trigo.cpp:122
unsigned GetPriority() const
Function GetPriority.
Definition: class_zone.h:106
const wxPoint GetPosition() const override
Definition: class_pad.h:220
bool m_drcInLegacyRoutingMode
in legacy canvas, when creating a track, the drc test must only display the error message...
Definition: drc.h:199
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
int m_xcliplo
Definition: drc.h:219
#define DRCE_ENDS_PROBLEM1
track ends are too close
Definition: drc.h:59
#define DRCE_TOO_SMALL_VIA_DRILL
Too small via drill.
Definition: drc.h:75
#define DRCE_TRACK_NEAR_THROUGH_HOLE
thru hole is too close to track
Definition: drc.h:48
int GetZoneClearance() const
Definition: class_zone.h:197
double m_segmAngle
Definition: drc.h:213
#define min(a, b)
Definition: auxiliary.h:85
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline) ...
#define DRCE_TOO_SMALL_TRACK_WIDTH
Too small track width.
Definition: drc.h:72
VECTOR2I B
Definition: seg.h:45