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