KiCad PCB EDA Suite
board_items_to_polygon_shape_transform.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2009-2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 /***
26  * @file board_items_to_polygon_shape_transform.cpp
27  * @brief function to convert shapes of items ( pads, tracks... ) to polygons
28  */
29 
30 /* Function to convert pad and track shapes to polygons
31  * Used to fill zones areas and in 3D viewer
32  */
33 #include <vector>
34 
35 #include <fctsys.h>
36 #include <bezier_curves.h>
37 #include <base_units.h> // for IU_PER_MM
38 #include <draw_graphic_text.h>
39 #include <pcbnew.h>
40 #include <pcb_edit_frame.h>
41 #include <trigo.h>
42 #include <class_board.h>
43 #include <class_pad.h>
44 #include <class_track.h>
45 #include <class_drawsegment.h>
46 #include <class_pcb_text.h>
47 #include <class_zone.h>
48 #include <class_module.h>
49 #include <class_edge_mod.h>
52 
53 // A helper struct for the callback function
54 // These variables are parameters used in addTextSegmToPoly.
55 // But addTextSegmToPoly is a call-back function,
56 // so we cannot send them as arguments.
61 };
63 
64 // The max error is the distance between the middle of a segment, and the circle
65 // for circle/arc to segment approximation.
66 // Warning: too small values can create very long calculation time in zone filling
67 // 0.05 to 0.01 mm is a reasonable value
68 double s_error_max = Millimeter2iu( 0.02 );
69 
70 // This is a call back function, used by DrawGraphicText to draw the 3D text shape:
71 static void addTextSegmToPoly( int x0, int y0, int xf, int yf, void* aData )
72 {
73  TSEGM_2_POLY_PRMS* prm = static_cast<TSEGM_2_POLY_PRMS*>( aData );
75  wxPoint( x0, y0), wxPoint( xf, yf ),
77 }
78 
79 
81 {
82  // Number of segments to convert a circle to a polygon
83  const int segcountforcircle = 18;
84  double correctionFactor = GetCircletoPolyCorrectionFactor( segcountforcircle );
85 
86  // convert tracks and vias:
87  for( TRACK* track = m_Track; track != NULL; track = track->Next() )
88  {
89  if( !track->IsOnLayer( aLayer ) )
90  continue;
91 
92  track->TransformShapeWithClearanceToPolygon( aOutlines,
93  0, segcountforcircle, correctionFactor );
94  }
95 
96  // convert pads
97  for( MODULE* module = m_Modules; module != NULL; module = module->Next() )
98  {
99  module->TransformPadsShapesWithClearanceToPolygon( aLayer,
100  aOutlines, 0, segcountforcircle, correctionFactor );
101 
102  // Micro-wave modules may have items on copper layers
103  module->TransformGraphicShapesWithClearanceToPolygonSet( aLayer,
104  aOutlines, 0, segcountforcircle, correctionFactor );
105  }
106 
107  // convert copper zones
108  for( int ii = 0; ii < GetAreaCount(); ii++ )
109  {
110  ZONE_CONTAINER* zone = GetArea( ii );
111  PCB_LAYER_ID zonelayer = zone->GetLayer();
112 
113  if( zonelayer == aLayer )
115  aOutlines, segcountforcircle, correctionFactor );
116  }
117 
118  // convert graphic items on copper layers (texts)
119  for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
120  {
121  if( !item->IsOnLayer( aLayer ) )
122  continue;
123 
124  switch( item->Type() )
125  {
126  case PCB_LINE_T: // should not exist on copper layers
127  ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon(
128  aOutlines, 0, segcountforcircle, correctionFactor );
129  break;
130 
131  case PCB_TEXT_T:
132  ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet(
133  aOutlines, 0, segcountforcircle, correctionFactor );
134  break;
135 
136  default:
137  break;
138  }
139  }
140 }
141 
142 
144  SHAPE_POLY_SET& aCornerBuffer,
145  int aInflateValue,
146  int aCircleToSegmentsCount,
147  double aCorrectionFactor,
148  bool aSkipNPTHPadsWihNoCopper ) const
149 {
150  D_PAD* pad = PadsList();
151 
152  wxSize margin;
153  for( ; pad != NULL; pad = pad->Next() )
154  {
155  if( aLayer != UNDEFINED_LAYER && !pad->IsOnLayer(aLayer) )
156  continue;
157 
158  // NPTH pads are not drawn on layers if the shape size and pos is the same
159  // as their hole:
160  if( aSkipNPTHPadsWihNoCopper && pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED )
161  {
162  if( pad->GetDrillSize() == pad->GetSize() && pad->GetOffset() == wxPoint( 0, 0 ) )
163  {
164  switch( pad->GetShape() )
165  {
166  case PAD_SHAPE_CIRCLE:
167  if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
168  continue;
169  break;
170 
171  case PAD_SHAPE_OVAL:
172  if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
173  continue;
174  break;
175 
176  default:
177  break;
178  }
179  }
180  }
181 
182  switch( aLayer )
183  {
184  case F_Mask:
185  case B_Mask:
186  margin.x = margin.y = pad->GetSolderMaskMargin() + aInflateValue;
187  break;
188 
189  case F_Paste:
190  case B_Paste:
191  margin = pad->GetSolderPasteMargin();
192  margin.x += aInflateValue;
193  margin.y += aInflateValue;
194  break;
195 
196  default:
197  margin.x = margin.y = aInflateValue;
198  break;
199  }
200 
201  pad->BuildPadShapePolygon( aCornerBuffer, margin,
202  aCircleToSegmentsCount, aCorrectionFactor );
203  }
204 }
205 
206 /* generate shapes of graphic items (outlines) on layer aLayer as polygons,
207  * and adds these polygons to aCornerBuffer
208  * aCornerBuffer = the buffer to store polygons
209  * aInflateValue = a value to inflate shapes
210  * aCircleToSegmentsCount = number of segments to approximate a circle
211  * aCorrectionFactor = the correction to apply to the circle radius
212  * to generate the polygon.
213  * if aCorrectionFactor = 1.0, the polygon is inside the circle
214  * the radius of circle approximated by segments is
215  * initial radius * aCorrectionFactor
216  */
218  PCB_LAYER_ID aLayer,
219  SHAPE_POLY_SET& aCornerBuffer,
220  int aInflateValue,
221  int aCircleToSegmentsCount,
222  double aCorrectionFactor,
223  int aCircleToSegmentsCountForTexts,
224  bool aIncludeText ) const
225 {
226  std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert
227  EDGE_MODULE* outline;
228 
229  for( EDA_ITEM* item = GraphicalItemsList(); item != NULL; item = item->Next() )
230  {
231  switch( item->Type() )
232  {
233  case PCB_MODULE_TEXT_T:
234  {
235  TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );
236 
237  if( ( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer )
238  && text->IsVisible() )
239  texts.push_back( text );
240 
241  break;
242  }
243 
244  case PCB_MODULE_EDGE_T:
245  outline = (EDGE_MODULE*) item;
246 
247  if( aLayer != UNDEFINED_LAYER && outline->GetLayer() != aLayer )
248  break;
249 
250  outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, 0,
251  aCircleToSegmentsCount, aCorrectionFactor );
252  break;
253 
254  default:
255  break;
256  }
257  }
258 
259  if( !aIncludeText )
260  return;
261 
262  // Convert texts sur modules
263  if( Reference().GetLayer() == aLayer && Reference().IsVisible() )
264  texts.push_back( &Reference() );
265 
266  if( Value().GetLayer() == aLayer && Value().IsVisible() )
267  texts.push_back( &Value() );
268 
269  prms.m_cornerBuffer = &aCornerBuffer;
270 
271  // To allow optimization of circles approximated by segments,
272  // aCircleToSegmentsCountForTexts, when not 0, is used.
273  // if 0 (default value) the aCircleToSegmentsCount is used
274  prms.m_textCircle2SegmentCount = aCircleToSegmentsCountForTexts ?
275  aCircleToSegmentsCountForTexts : aCircleToSegmentsCount;
276 
277  for( unsigned ii = 0; ii < texts.size(); ii++ )
278  {
279  TEXTE_MODULE *textmod = texts[ii];
280  prms.m_textWidth = textmod->GetThickness() + ( 2 * aInflateValue );
281  wxSize size = textmod->GetTextSize();
282 
283  if( textmod->IsMirrored() )
284  size.x = -size.x;
285 
286  DrawGraphicText( NULL, NULL, textmod->GetTextPos(), BLACK,
287  textmod->GetShownText(), textmod->GetDrawRotation(), size,
288  textmod->GetHorizJustify(), textmod->GetVertJustify(),
289  textmod->GetThickness(), textmod->IsItalic(),
290  true, addTextSegmToPoly, &prms );
291  }
292 
293 }
294 
295 
296 // Same as function TransformGraphicShapesWithClearanceToPolygonSet but
297 // this only render text
299  PCB_LAYER_ID aLayer,
300  SHAPE_POLY_SET& aCornerBuffer,
301  int aInflateValue,
302  int aCircleToSegmentsCount,
303  double aCorrectionFactor,
304  int aCircleToSegmentsCountForTexts ) const
305 {
306  std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert
307 
308  for( EDA_ITEM* item = GraphicalItemsList(); item != NULL; item = item->Next() )
309  {
310  switch( item->Type() )
311  {
312  case PCB_MODULE_TEXT_T:
313  {
314  TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );
315 
316  if( text->GetLayer() == aLayer && text->IsVisible() )
317  texts.push_back( text );
318 
319  break;
320  }
321 
322  case PCB_MODULE_EDGE_T:
323  // This function does not render this
324  break;
325 
326  default:
327  break;
328  }
329  }
330 
331  // Convert texts sur modules
332  if( Reference().GetLayer() == aLayer && Reference().IsVisible() )
333  texts.push_back( &Reference() );
334 
335  if( Value().GetLayer() == aLayer && Value().IsVisible() )
336  texts.push_back( &Value() );
337 
338  prms.m_cornerBuffer = &aCornerBuffer;
339 
340  // To allow optimization of circles approximated by segments,
341  // aCircleToSegmentsCountForTexts, when not 0, is used.
342  // if 0 (default value) the aCircleToSegmentsCount is used
343  prms.m_textCircle2SegmentCount = aCircleToSegmentsCountForTexts ?
344  aCircleToSegmentsCountForTexts : aCircleToSegmentsCount;
345 
346  for( unsigned ii = 0; ii < texts.size(); ii++ )
347  {
348  TEXTE_MODULE *textmod = texts[ii];
349  prms.m_textWidth = textmod->GetThickness() + ( 2 * aInflateValue );
350  wxSize size = textmod->GetTextSize();
351 
352  if( textmod->IsMirrored() )
353  size.x = -size.x;
354 
355  DrawGraphicText( NULL, NULL, textmod->GetTextPos(), BLACK,
356  textmod->GetShownText(), textmod->GetDrawRotation(), size,
357  textmod->GetHorizJustify(), textmod->GetVertJustify(),
358  textmod->GetThickness(), textmod->IsItalic(),
359  true, addTextSegmToPoly, &prms );
360  }
361 
362 }
363 
364  /* Function TransformSolidAreasShapesToPolygonSet
365  * Convert solid areas full shapes to polygon set
366  * (the full shape is the polygon area with a thick outline)
367  * Used in 3D view
368  * Arcs (ends of segments) are approximated by segments
369  * aCornerBuffer = a buffer to store the polygons
370  * aCircleToSegmentsCount = the number of segments to approximate a circle
371  * aCorrectionFactor = the correction to apply to arcs radius to roughly
372  * keep arc radius when approximated by segments
373  */
375  SHAPE_POLY_SET& aCornerBuffer,
376  int aCircleToSegmentsCount,
377  double aCorrectionFactor ) const
378 {
379  if( GetFilledPolysList().IsEmpty() )
380  return;
381 
382  // add filled areas polygons
383  aCornerBuffer.Append( m_FilledPolysList );
384 
385  // add filled areas outlines, which are drawn with thick lines
386  for( int i = 0; i < m_FilledPolysList.OutlineCount(); i++ )
387  {
388  const SHAPE_LINE_CHAIN& path = m_FilledPolysList.COutline( i );
389 
390  for( int j = 0; j < path.PointCount(); j++ )
391  {
392  const VECTOR2I& a = path.CPoint( j );
393  const VECTOR2I& b = path.CPoint( j + 1 );
394 
395  TransformRoundedEndsSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ), wxPoint( b.x, b.y ),
396  aCircleToSegmentsCount,
397  GetMinThickness() );
398  }
399  }
400 }
401 
411  SHAPE_POLY_SET* aCornerBuffer,
412  int aClearanceValue ) const
413 {
414  // Oh dear. When in UTF-8 mode, wxString puts string iterators in a linked list, and
415  // that linked list is not thread-safe.
416  std::lock_guard<std::mutex> guard( m_mutex );
417 
418  if( GetText().Length() == 0 )
419  return;
420 
421  wxPoint corners[4]; // Buffer of polygon corners
422 
423  EDA_RECT rect = GetTextBox( -1 );
424  rect.Inflate( aClearanceValue );
425  corners[0].x = rect.GetOrigin().x;
426  corners[0].y = rect.GetOrigin().y;
427  corners[1].y = corners[0].y;
428  corners[1].x = rect.GetRight();
429  corners[2].x = corners[1].x;
430  corners[2].y = rect.GetBottom();
431  corners[3].y = corners[2].y;
432  corners[3].x = corners[0].x;
433 
434  aCornerBuffer->NewOutline();
435 
436  for( int ii = 0; ii < 4; ii++ )
437  {
438  // Rotate polygon
439  RotatePoint( &corners[ii].x, &corners[ii].y, GetTextPos().x, GetTextPos().y, GetTextAngle() );
440  aCornerBuffer->Append( corners[ii].x, corners[ii].y );
441  }
442 }
443 
444 
445 /* Function TransformShapeWithClearanceToPolygonSet
446  * Convert the text shape to a set of polygons (one by segment)
447  * Used in filling zones calculations and 3D view
448  * Circles and arcs are approximated by segments
449  * aCornerBuffer = SHAPE_POLY_SET to store the polygon corners
450  * aClearanceValue = the clearance around the text
451  * aCircleToSegmentsCount = the number of segments to approximate a circle
452  * aCorrectionFactor = the correction to apply to circles radius to keep
453  * clearance when the circle is approximated by segment bigger or equal
454  * to the real clearance value (usually near from 1.0)
455  */
456 
458  SHAPE_POLY_SET& aCornerBuffer,
459  int aClearanceValue,
460  int aCircleToSegmentsCount,
461  double aCorrectionFactor ) const
462 {
463  wxSize size = GetTextSize();
464 
465  if( IsMirrored() )
466  size.x = -size.x;
467 
468  prms.m_cornerBuffer = &aCornerBuffer;
469  prms.m_textWidth = GetThickness() + ( 2 * aClearanceValue );
470  prms.m_textCircle2SegmentCount = aCircleToSegmentsCount;
471  COLOR4D color = COLOR4D::BLACK; // not actually used, but needed by DrawGraphicText
472 
473  if( IsMultilineAllowed() )
474  {
475  wxArrayString strings_list;
476  wxStringSplit( GetShownText(), strings_list, '\n' );
477  std::vector<wxPoint> positions;
478  positions.reserve( strings_list.Count() );
479  GetPositionsOfLinesOfMultilineText( positions, strings_list.Count() );
480 
481  for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
482  {
483  wxString txt = strings_list.Item( ii );
484  DrawGraphicText( NULL, NULL, positions[ii], color,
485  txt, GetTextAngle(), size,
486  GetHorizJustify(), GetVertJustify(),
487  GetThickness(), IsItalic(),
488  true, addTextSegmToPoly, &prms );
489  }
490  }
491  else
492  {
493  DrawGraphicText( NULL, NULL, GetTextPos(), color,
494  GetShownText(), GetTextAngle(), size,
495  GetHorizJustify(), GetVertJustify(),
496  GetThickness(), IsItalic(),
497  true, addTextSegmToPoly, &prms );
498  }
499 }
500 
501 
517  int aClearanceValue,
518  int aCircleToSegmentsCount,
519  double aCorrectionFactor,
520  bool ignoreLineWidth ) const
521 {
522  // The full width of the lines to create:
523  int linewidth = ignoreLineWidth ? 0 : m_Width;
524 
525  linewidth += 2 * aClearanceValue;
526 
527  // Creating a reliable clearance shape for circles and arcs is not so easy, due to
528  // the error created by segment approximation.
529  // for a cicle this is not so hard: create a polygon from a circle slightly bigger:
530  // thickness = linewidth + s_error_max, and radius = initial radius + s_error_max/2
531  // giving a shape with a suitable internal radius and external radius
532  // For an arc this is more tricky: TODO
533  if( m_Shape == S_CIRCLE || m_Shape == S_ARC )
534  {
535  int segCount = GetArcToSegmentCount( GetRadius(), s_error_max, 360.0 );
536 
537  if( segCount > aCircleToSegmentsCount )
538  aCircleToSegmentsCount = segCount;
539  }
540 
541  switch( m_Shape )
542  {
543  case S_CIRCLE:
544  TransformRingToPolygon( aCornerBuffer, GetCenter(), GetRadius() + (s_error_max/2),
545  aCircleToSegmentsCount, linewidth + s_error_max ) ;
546  break;
547 
548  case S_ARC:
549  TransformArcToPolygon( aCornerBuffer, GetCenter(),
550  GetArcStart(), m_Angle,
551  aCircleToSegmentsCount, linewidth );
552  break;
553 
554  case S_SEGMENT:
555  TransformOvalClearanceToPolygon( aCornerBuffer, m_Start, m_End, linewidth,
556  aCircleToSegmentsCount, aCorrectionFactor );
557  break;
558 
559  case S_POLYGON:
560  if( IsPolyShapeValid() )
561  {
562  // The polygon is expected to be a simple polygon
563  // not self intersecting, no hole.
564  MODULE* module = GetParentModule(); // NULL for items not in footprints
565  double orientation = module ? module->GetOrientation() : 0.0;
566  wxPoint offset;
567 
568  if( module )
569  offset = module->GetPosition();
570 
571  // Build the polygon with the actual position and orientation:
572  std::vector< wxPoint> poly;
573  poly = BuildPolyPointsList();
574 
575  for( unsigned ii = 0; ii < poly.size(); ii++ )
576  {
577  RotatePoint( &poly[ii], orientation );
578  poly[ii] += offset;
579  }
580 
581  // If the polygon is not filled, treat it as a closed set of lines
582  if( !IsPolygonFilled() )
583  {
584  for( size_t ii = 1; ii < poly.size(); ii++ )
585  {
586  TransformOvalClearanceToPolygon( aCornerBuffer, poly[ii - 1], poly[ii],
587  linewidth, aCircleToSegmentsCount, aCorrectionFactor );
588  }
589 
590  TransformOvalClearanceToPolygon( aCornerBuffer, poly.back(), poly.front(),
591  linewidth, aCircleToSegmentsCount, aCorrectionFactor );
592  break;
593  }
594 
595  // Generate polygons for the outline + clearance
596  // This code is compatible with a polygon with holes linked to external outline
597  // by overlapping segments.
598 
599  // Insert the initial polygon:
600  aCornerBuffer.NewOutline();
601 
602  for( unsigned ii = 0; ii < poly.size(); ii++ )
603  aCornerBuffer.Append( poly[ii].x, poly[ii].y );
604 
605  if( linewidth ) // Add thick outlines
606  {
607  wxPoint corner1( poly[poly.size()-1] );
608 
609  for( unsigned ii = 0; ii < poly.size(); ii++ )
610  {
611  wxPoint corner2( poly[ii] );
612 
613  if( corner2 != corner1 )
614  {
616  corner1, corner2, aCircleToSegmentsCount, linewidth );
617  }
618 
619  corner1 = corner2;
620  }
621  }
622  }
623  break;
624 
625  case S_CURVE: // Bezier curve
626  {
627  std::vector<wxPoint> ctrlPoints = { m_Start, m_BezierC1, m_BezierC2, m_End };
628  BEZIER_POLY converter( ctrlPoints );
629  std::vector< wxPoint> poly;
630  converter.GetPoly( poly, m_Width );
631 
632  for( unsigned ii = 1; ii < poly.size(); ii++ )
633  {
635  poly[ii-1], poly[ii], aCircleToSegmentsCount, linewidth );
636  }
637  }
638  break;
639 
640  default:
641  break;
642  }
643 }
644 
645 
661  int aClearanceValue,
662  int aCircleToSegmentsCount,
663  double aCorrectionFactor,
664  bool ignoreLineWidth ) const
665 {
666  wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for tracks." );
667 
668  switch( Type() )
669  {
670  case PCB_VIA_T:
671  {
672  int radius = (m_Width / 2) + aClearanceValue;
673  radius = KiROUND( radius * aCorrectionFactor );
674  TransformCircleToPolygon( aCornerBuffer, m_Start, radius, aCircleToSegmentsCount );
675  }
676  break;
677 
678  default:
679  TransformOvalClearanceToPolygon( aCornerBuffer, m_Start, m_End,
680  m_Width + ( 2 * aClearanceValue),
681  aCircleToSegmentsCount,
682  aCorrectionFactor );
683  break;
684  }
685 }
686 
687 
688 /* Function TransformShapeWithClearanceToPolygon
689  * Convert the pad shape to a closed polygon
690  * Used in filling zones calculations and 3D view generation
691  * Circles and arcs are approximated by segments
692  * aCornerBuffer = a SHAPE_POLY_SET to store the polygon corners
693  * aClearanceValue = the clearance around the pad
694  * aCircleToSegmentsCount = the number of segments to approximate a circle
695  * aCorrectionFactor = the correction to apply to circles radius to keep
696  * clearance when the circle is approximated by segment bigger or equal
697  * to the real clearance value (usually near from 1.0)
698  * @param ignoreLineWidth = used for edge cut items where the line width is only
699  * for visualization
700  */
702  int aClearanceValue,
703  int aCircleToSegmentsCount,
704  double aCorrectionFactor,
705  bool ignoreLineWidth ) const
706 {
707  wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for pads." );
708 
709  double angle = m_Orient;
710  int dx = (m_Size.x / 2) + aClearanceValue;
711  int dy = (m_Size.y / 2) + aClearanceValue;
712 
713  wxPoint padShapePos = ShapePos(); /* Note: for pad having a shape offset,
714  * the pad position is NOT the shape position */
715 
716  switch( GetShape() )
717  {
718  case PAD_SHAPE_CIRCLE:
719  dx = KiROUND( dx * aCorrectionFactor );
720  TransformCircleToPolygon( aCornerBuffer, padShapePos, dx,
721  aCircleToSegmentsCount );
722  break;
723 
724  case PAD_SHAPE_OVAL:
725  // An oval pad has the same shape as a segment with rounded ends
726  {
727  int width;
728  wxPoint shape_offset;
729  if( dy > dx ) // Oval pad X/Y ratio for choosing translation axis
730  {
731  shape_offset.y = dy - dx;
732  width = dx * 2;
733  }
734  else //if( dy <= dx )
735  {
736  shape_offset.x = dy - dx;
737  width = dy * 2;
738  }
739 
740  RotatePoint( &shape_offset, angle );
741  wxPoint start = padShapePos - shape_offset;
742  wxPoint end = padShapePos + shape_offset;
743  TransformOvalClearanceToPolygon( aCornerBuffer, start, end, width,
744  aCircleToSegmentsCount, aCorrectionFactor );
745  }
746  break;
747 
748  case PAD_SHAPE_TRAPEZOID:
749  case PAD_SHAPE_RECT:
750  {
751  wxPoint corners[4];
752  BuildPadPolygon( corners, wxSize( 0, 0 ), angle );
753 
754  SHAPE_POLY_SET outline;
755  outline.NewOutline();
756 
757  for( int ii = 0; ii < 4; ii++ )
758  {
759  corners[ii] += padShapePos;
760  outline.Append( corners[ii].x, corners[ii].y );
761  }
762 
763  int rounding_radius = int( aClearanceValue * aCorrectionFactor );
764  outline.Inflate( rounding_radius, aCircleToSegmentsCount );
765 
766  aCornerBuffer.Append( outline );
767  }
768  break;
769 
770  case PAD_SHAPE_ROUNDRECT:
771  {
772  SHAPE_POLY_SET outline;
773  int pad_radius = GetRoundRectCornerRadius();
774  int clearance = int( aClearanceValue * aCorrectionFactor );
775  int rounding_radius = pad_radius + clearance;
776  wxSize shapesize( m_Size );
777  shapesize.x += clearance*2;
778  shapesize.y += clearance*2;
779 
780  TransformRoundRectToPolygon( outline, padShapePos, shapesize, angle,
781  rounding_radius, aCircleToSegmentsCount );
782 
783  aCornerBuffer.Append( outline );
784  }
785  break;
786 
787  case PAD_SHAPE_CUSTOM:
788  {
789  int clearance = KiROUND( aClearanceValue * aCorrectionFactor );
790 
791  SHAPE_POLY_SET outline; // Will contain the corners in board coordinates
792  outline.Append( m_customShapeAsPolygon );
793  CustomShapeAsPolygonToBoardPosition( &outline, GetPosition(), GetOrientation() );
794  outline.Inflate( clearance, aCircleToSegmentsCount );
795  aCornerBuffer.Append( outline );
796  }
797  break;
798  }
799 }
800 
801 
802 
803 /*
804  * Function BuildPadShapePolygon
805  * Build the Corner list of the polygonal shape,
806  * depending on shape, extra size (clearance ...) pad and orientation
807  * Note: for Round and oval pads this function is equivalent to
808  * TransformShapeWithClearanceToPolygon, but not for other shapes
809  */
811  wxSize aInflateValue, int aSegmentsPerCircle,
812  double aCorrectionFactor ) const
813 {
814  wxPoint corners[4];
815  wxPoint padShapePos = ShapePos(); /* Note: for pad having a shape offset,
816  * the pad position is NOT the shape position */
817  switch( GetShape() )
818  {
819  case PAD_SHAPE_CIRCLE:
820  case PAD_SHAPE_OVAL:
821  case PAD_SHAPE_ROUNDRECT:
822  {
823  // We are using TransformShapeWithClearanceToPolygon to build the shape.
824  // Currently, this method uses only the same inflate value for X and Y dirs.
825  // so because here this is not the case, we use a inflated dummy pad to build
826  // the polygonal shape
827  // TODO: remove this dummy pad when TransformShapeWithClearanceToPolygon will use
828  // a wxSize to inflate the pad size
829  D_PAD dummy( *this );
830  dummy.SetSize( GetSize() + aInflateValue + aInflateValue );
831  dummy.TransformShapeWithClearanceToPolygon( aCornerBuffer, 0,
832  aSegmentsPerCircle, aCorrectionFactor );
833  }
834  break;
835 
836  case PAD_SHAPE_TRAPEZOID:
837  case PAD_SHAPE_RECT:
838  aCornerBuffer.NewOutline();
839 
840  BuildPadPolygon( corners, aInflateValue, m_Orient );
841  for( int ii = 0; ii < 4; ii++ )
842  {
843  corners[ii] += padShapePos; // Shift origin to position
844  aCornerBuffer.Append( corners[ii].x, corners[ii].y );
845  }
846 
847  break;
848 
849  case PAD_SHAPE_CUSTOM:
850  // for a custom shape, that is in fact a polygon (with holes), we can use only a inflate value.
851  // so use ( aInflateValue.x + aInflateValue.y ) / 2 as polygon inflate value.
852  // (different values for aInflateValue.x and aInflateValue.y has no sense for a custom pad)
853  TransformShapeWithClearanceToPolygon( aCornerBuffer,
854  ( aInflateValue.x + aInflateValue.y ) / 2,
855  aSegmentsPerCircle, aCorrectionFactor );
856  break;
857  }
858 }
859 
860 /*
861  * Function BuildPadDrillShapePolygon
862  * Build the Corner list of the polygonal drill shape,
863  * depending on shape pad hole and orientation
864  * return false if the pad has no hole, true otherwise
865  */
867  int aInflateValue, int aSegmentsPerCircle ) const
868 {
869  wxSize drillsize = GetDrillSize();
870 
871  if( !drillsize.x || !drillsize.y )
872  return false;
873 
874  if( drillsize.x == drillsize.y ) // usual round hole
875  {
876  TransformCircleToPolygon( aCornerBuffer, GetPosition(),
877  (drillsize.x / 2) + aInflateValue, aSegmentsPerCircle );
878  }
879  else // Oblong hole
880  {
881  wxPoint start, end;
882  int width;
883 
884  GetOblongDrillGeometry( start, end, width );
885 
886  width += aInflateValue * 2;
887 
889  GetPosition() + start, GetPosition() + end, aSegmentsPerCircle, width );
890  }
891 
892  return true;
893 }
894 
909 /* thermal reliefs are created as 4 polygons.
910  * each corner of a polygon if calculated for a pad at position 0, 0, orient 0,
911  * and then moved and rotated acroding to the pad position and orientation
912  */
913 
914 /*
915  * Note 1: polygons are drawm using outlines witk a thickness = aMinThicknessValue
916  * so shapes must take in account this outline thickness
917  *
918  * Note 2:
919  * Trapezoidal pads are not considered here because they are very special case
920  * and are used in microwave applications and they *DO NOT* have a thermal relief that
921  * change the shape by creating stubs and destroy their properties.
922  */
924  const D_PAD& aPad,
925  int aThermalGap,
926  int aCopperThickness,
927  int aMinThicknessValue,
928  int aCircleToSegmentsCount,
929  double aCorrectionFactor,
930  double aThermalRot )
931 {
932  wxPoint corner, corner_end;
933  wxPoint padShapePos = aPad.ShapePos(); // Note: for pad having a shape offset,
934  // the pad position is NOT the shape position
935  wxSize copper_thickness;
936 
937  double delta = 3600.0 / aCircleToSegmentsCount; // rot angle in 0.1 degree
938 
939  /* Keep in account the polygon outline thickness
940  * aThermalGap must be increased by aMinThicknessValue/2 because drawing external outline
941  * with a thickness of aMinThicknessValue will reduce gap by aMinThicknessValue/2
942  */
943  aThermalGap += aMinThicknessValue / 2;
944 
945  /* Keep in account the polygon outline thickness
946  * copper_thickness must be decreased by aMinThicknessValue because drawing outlines
947  * with a thickness of aMinThicknessValue will increase real thickness by aMinThicknessValue
948  */
949  aCopperThickness -= aMinThicknessValue;
950 
951  if( aCopperThickness < 0 )
952  aCopperThickness = 0;
953 
954  int dx = aPad.GetSize().x / 2;
955  int dy = aPad.GetSize().y / 2;
956 
957  copper_thickness.x = std::min( dx, aCopperThickness );
958  copper_thickness.y = std::min( dy, aCopperThickness );
959 
960  switch( aPad.GetShape() )
961  {
962  case PAD_SHAPE_CIRCLE: // Add 4 similar holes
963  {
964  /* we create 4 copper holes and put them in position 1, 2, 3 and 4
965  * here is the area of the rectangular pad + its thermal gap
966  * the 4 copper holes remove the copper in order to create the thermal gap
967  * 4 ------ 1
968  * | |
969  * | |
970  * | |
971  * | |
972  * 3 ------ 2
973  * holes 2, 3, 4 are the same as hole 1, rotated 90, 180, 270 deg
974  */
975 
976  // Build the hole pattern, for the hole in the X >0, Y > 0 plane:
977  // The pattern roughtly is a 90 deg arc pie
978  std::vector <wxPoint> corners_buffer;
979 
980  // Radius of outer arcs of the shape corrected for arc approximation by lines
981  int outer_radius = KiROUND( (dx + aThermalGap) * aCorrectionFactor );
982 
983  // Crosspoint of thermal spoke sides, the first point of polygon buffer
984  corners_buffer.push_back( wxPoint( copper_thickness.x / 2, copper_thickness.y / 2 ) );
985 
986  // Add an intermediate point on spoke sides, to allow a > 90 deg angle between side
987  // and first seg of arc approx
988  corner.x = copper_thickness.x / 2;
989  int y = outer_radius - (aThermalGap / 4);
990  corner.y = KiROUND( sqrt( ( (double) y * y - (double) corner.x * corner.x ) ) );
991 
992  if( aThermalRot != 0 )
993  corners_buffer.push_back( corner );
994 
995  // calculate the starting point of the outter arc
996  corner.x = copper_thickness.x / 2;
997 
998  corner.y = KiROUND( sqrt( ( (double) outer_radius * outer_radius ) -
999  ( (double) corner.x * corner.x ) ) );
1000  RotatePoint( &corner, 90 ); // 9 degrees is the spoke fillet size
1001 
1002  // calculate the ending point of the outter arc
1003  corner_end.x = corner.y;
1004  corner_end.y = corner.x;
1005 
1006  // calculate intermediate points (y coordinate from corner.y to corner_end.y
1007  while( (corner.y > corner_end.y) && (corner.x < corner_end.x) )
1008  {
1009  corners_buffer.push_back( corner );
1010  RotatePoint( &corner, delta );
1011  }
1012 
1013  corners_buffer.push_back( corner_end );
1014 
1015  /* add an intermediate point, to avoid angles < 90 deg between last arc approx line
1016  * and radius line
1017  */
1018  corner.x = corners_buffer[1].y;
1019  corner.y = corners_buffer[1].x;
1020  corners_buffer.push_back( corner );
1021 
1022  // Now, add the 4 holes ( each is the pattern, rotated by 0, 90, 180 and 270 deg
1023  // aThermalRot = 450 (45.0 degrees orientation) work fine.
1024  double angle_pad = aPad.GetOrientation(); // Pad orientation
1025  double th_angle = aThermalRot;
1026 
1027  for( unsigned ihole = 0; ihole < 4; ihole++ )
1028  {
1029  aCornerBuffer.NewOutline();
1030 
1031  for( unsigned ii = 0; ii < corners_buffer.size(); ii++ )
1032  {
1033  corner = corners_buffer[ii];
1034  RotatePoint( &corner, th_angle + angle_pad ); // Rotate by segment angle and pad orientation
1035  corner += padShapePos;
1036  aCornerBuffer.Append( corner.x, corner.y );
1037  }
1038 
1039  th_angle += 900; // Note: th_angle in in 0.1 deg.
1040  }
1041  }
1042  break;
1043 
1044  case PAD_SHAPE_OVAL:
1045  {
1046  // Oval pad support along the lines of round and rectangular pads
1047  std::vector <wxPoint> corners_buffer; // Polygon buffer as vector
1048 
1049  dx = (aPad.GetSize().x / 2) + aThermalGap; // Cutout radius x
1050  dy = (aPad.GetSize().y / 2) + aThermalGap; // Cutout radius y
1051 
1052  wxPoint shape_offset;
1053 
1054  // We want to calculate an oval shape with dx > dy.
1055  // if this is not the case, exchange dx and dy, and rotate the shape 90 deg.
1056  int supp_angle = 0;
1057 
1058  if( dx < dy )
1059  {
1060  std::swap( dx, dy );
1061  supp_angle = 900;
1062  std::swap( copper_thickness.x, copper_thickness.y );
1063  }
1064 
1065  int deltasize = dx - dy; // = distance between shape position and the 2 demi-circle ends centre
1066  // here we have dx > dy
1067  // Radius of outer arcs of the shape:
1068  int outer_radius = dy; // The radius of the outer arc is radius end + aThermalGap
1069 
1070  // Some coordinate fiddling, depending on the shape offset direction
1071  shape_offset = wxPoint( deltasize, 0 );
1072 
1073  // Crosspoint of thermal spoke sides, the first point of polygon buffer
1074  corner.x = copper_thickness.x / 2;
1075  corner.y = copper_thickness.y / 2;
1076  corners_buffer.push_back( corner );
1077 
1078  // Arc start point calculation, the intersecting point of cutout arc and thermal spoke edge
1079  // If copper thickness is more than shape offset, we need to calculate arc intercept point.
1080  if( copper_thickness.x > deltasize )
1081  {
1082  corner.x = copper_thickness.x / 2;
1083  corner.y = KiROUND( sqrt( ( (double) outer_radius * outer_radius ) -
1084  ( (double) ( corner.x - delta ) * ( corner.x - deltasize ) ) ) );
1085  corner.x -= deltasize;
1086 
1087  /* creates an intermediate point, to have a > 90 deg angle
1088  * between the side and the first segment of arc approximation
1089  */
1090  wxPoint intpoint = corner;
1091  intpoint.y -= aThermalGap / 4;
1092  corners_buffer.push_back( intpoint + shape_offset );
1093  RotatePoint( &corner, 90 ); // 9 degrees of thermal fillet
1094  }
1095  else
1096  {
1097  corner.x = copper_thickness.x / 2;
1098  corner.y = outer_radius;
1099  corners_buffer.push_back( corner );
1100  }
1101 
1102  // Add an intermediate point on spoke sides, to allow a > 90 deg angle between side
1103  // and first seg of arc approx
1104  wxPoint last_corner;
1105  last_corner.y = copper_thickness.y / 2;
1106  int px = outer_radius - (aThermalGap / 4);
1107  last_corner.x =
1108  KiROUND( sqrt( ( ( (double) px * px ) - (double) last_corner.y * last_corner.y ) ) );
1109 
1110  // Arc stop point calculation, the intersecting point of cutout arc and thermal spoke edge
1111  corner_end.y = copper_thickness.y / 2;
1112  corner_end.x =
1113  KiROUND( sqrt( ( (double) outer_radius *
1114  outer_radius ) - ( (double) corner_end.y * corner_end.y ) ) );
1115  RotatePoint( &corner_end, -90 ); // 9 degrees of thermal fillet
1116 
1117  // calculate intermediate arc points till limit is reached
1118  while( (corner.y > corner_end.y) && (corner.x < corner_end.x) )
1119  {
1120  corners_buffer.push_back( corner + shape_offset );
1121  RotatePoint( &corner, delta );
1122  }
1123 
1124  //corners_buffer.push_back(corner + shape_offset); // TODO: about one mil geometry error forms somewhere.
1125  corners_buffer.push_back( corner_end + shape_offset );
1126  corners_buffer.push_back( last_corner + shape_offset ); // Enabling the line above shows intersection point.
1127 
1128  /* Create 2 holes, rotated by pad rotation.
1129  */
1130  double angle = aPad.GetOrientation() + supp_angle;
1131 
1132  for( int irect = 0; irect < 2; irect++ )
1133  {
1134  aCornerBuffer.NewOutline();
1135  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1136  {
1137  wxPoint cpos = corners_buffer[ic];
1138  RotatePoint( &cpos, angle );
1139  cpos += padShapePos;
1140  aCornerBuffer.Append( cpos.x, cpos.y );
1141  }
1142 
1143  angle = AddAngles( angle, 1800 ); // this is calculate hole 3
1144  }
1145 
1146  // Create holes, that are the mirrored from the previous holes
1147  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1148  {
1149  wxPoint swap = corners_buffer[ic];
1150  swap.x = -swap.x;
1151  corners_buffer[ic] = swap;
1152  }
1153 
1154  // Now add corner 4 and 2 (2 is the corner 4 rotated by 180 deg
1155  angle = aPad.GetOrientation() + supp_angle;
1156 
1157  for( int irect = 0; irect < 2; irect++ )
1158  {
1159  aCornerBuffer.NewOutline();
1160 
1161  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1162  {
1163  wxPoint cpos = corners_buffer[ic];
1164  RotatePoint( &cpos, angle );
1165  cpos += padShapePos;
1166  aCornerBuffer.Append( cpos.x, cpos.y );
1167  }
1168 
1169  angle = AddAngles( angle, 1800 );
1170  }
1171  }
1172  break;
1173 
1174  case PAD_SHAPE_ROUNDRECT: // thermal shape is the same for round rect and rect.
1175  case PAD_SHAPE_RECT:
1176  {
1177  /* we create 4 copper holes and put them in position 1, 2, 3 and 4
1178  * here is the area of the rectangular pad + its thermal gap
1179  * the 4 copper holes remove the copper in order to create the thermal gap
1180  * 4 ------ 1
1181  * | |
1182  * | |
1183  * | |
1184  * | |
1185  * 3 ------ 2
1186  * hole 3 is the same as hole 1, rotated 180 deg
1187  * hole 4 is the same as hole 2, rotated 180 deg and is the same as hole 1, mirrored
1188  */
1189 
1190  // First, create a rectangular hole for position 1 :
1191  // 2 ------- 3
1192  // | |
1193  // | |
1194  // | |
1195  // 1 -------4
1196 
1197  // Modified rectangles with one corner rounded. TODO: merging with oval thermals
1198  // and possibly round too.
1199 
1200  std::vector <wxPoint> corners_buffer; // Polygon buffer as vector
1201 
1202  dx = (aPad.GetSize().x / 2) + aThermalGap; // Cutout radius x
1203  dy = (aPad.GetSize().y / 2) + aThermalGap; // Cutout radius y
1204 
1205  // The first point of polygon buffer is left lower corner, second the crosspoint of
1206  // thermal spoke sides, the third is upper right corner and the rest are rounding
1207  // vertices going anticlockwise. Note the inveted Y-axis in CG.
1208  corners_buffer.push_back( wxPoint( -dx, -(aThermalGap / 4 + copper_thickness.y / 2) ) ); // Adds small miters to zone
1209  corners_buffer.push_back( wxPoint( -(dx - aThermalGap / 4), -copper_thickness.y / 2 ) ); // fill and spoke corner
1210  corners_buffer.push_back( wxPoint( -copper_thickness.x / 2, -copper_thickness.y / 2 ) );
1211  corners_buffer.push_back( wxPoint( -copper_thickness.x / 2, -(dy - aThermalGap / 4) ) );
1212  corners_buffer.push_back( wxPoint( -(aThermalGap / 4 + copper_thickness.x / 2), -dy ) );
1213 
1214  double angle = aPad.GetOrientation();
1215  int rounding_radius = KiROUND( aThermalGap * aCorrectionFactor ); // Corner rounding radius
1216 
1217  for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
1218  {
1219  wxPoint corner_position = wxPoint( 0, -rounding_radius );
1220 
1221  // Start at half increment offset
1222  RotatePoint( &corner_position, 1800.0 / aCircleToSegmentsCount );
1223  double angle_pg = i * delta;
1224 
1225  RotatePoint( &corner_position, angle_pg ); // Rounding vector rotation
1226  corner_position -= aPad.GetSize() / 2; // Rounding vector + Pad corner offset
1227 
1228  corners_buffer.push_back( wxPoint( corner_position.x, corner_position.y ) );
1229  }
1230 
1231  for( int irect = 0; irect < 2; irect++ )
1232  {
1233  aCornerBuffer.NewOutline();
1234 
1235  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1236  {
1237  wxPoint cpos = corners_buffer[ic];
1238  RotatePoint( &cpos, angle ); // Rotate according to module orientation
1239  cpos += padShapePos; // Shift origin to position
1240  aCornerBuffer.Append( cpos.x, cpos.y );
1241  }
1242 
1243  angle = AddAngles( angle, 1800 ); // this is calculate hole 3
1244  }
1245 
1246  // Create holes, that are the mirrored from the previous holes
1247  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1248  {
1249  wxPoint swap = corners_buffer[ic];
1250  swap.x = -swap.x;
1251  corners_buffer[ic] = swap;
1252  }
1253 
1254  // Now add corner 4 and 2 (2 is the corner 4 rotated by 180 deg
1255  for( int irect = 0; irect < 2; irect++ )
1256  {
1257  aCornerBuffer.NewOutline();
1258 
1259  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1260  {
1261  wxPoint cpos = corners_buffer[ic];
1262  RotatePoint( &cpos, angle );
1263  cpos += padShapePos;
1264  aCornerBuffer.Append( cpos.x, cpos.y );
1265  }
1266 
1267  angle = AddAngles( angle, 1800 );
1268  }
1269  }
1270  break;
1271 
1272  case PAD_SHAPE_TRAPEZOID:
1273  {
1274  SHAPE_POLY_SET antipad; // The full antipad area
1275 
1276  // We need a length to build the stubs of the thermal reliefs
1277  // the value is not very important. The pad bounding box gives a reasonable value
1278  EDA_RECT bbox = aPad.GetBoundingBox();
1279  int stub_len = std::max( bbox.GetWidth(), bbox.GetHeight() );
1280 
1281  aPad.TransformShapeWithClearanceToPolygon( antipad, aThermalGap,
1282  aCircleToSegmentsCount, aCorrectionFactor );
1283 
1284  SHAPE_POLY_SET stub; // A basic stub ( a rectangle)
1285  SHAPE_POLY_SET stubs; // the full stubs shape
1286 
1287 
1288  // We now substract the stubs (connections to the copper zone)
1289  //ClipperLib::Clipper clip_engine;
1290  // Prepare a clipping transform
1291  //clip_engine.AddPath( antipad, ClipperLib::ptSubject, true );
1292 
1293  // Create stubs and add them to clipper engine
1294  wxPoint stubBuffer[4];
1295  stubBuffer[0].x = stub_len;
1296  stubBuffer[0].y = copper_thickness.y/2;
1297  stubBuffer[1] = stubBuffer[0];
1298  stubBuffer[1].y = -copper_thickness.y/2;
1299  stubBuffer[2] = stubBuffer[1];
1300  stubBuffer[2].x = -stub_len;
1301  stubBuffer[3] = stubBuffer[2];
1302  stubBuffer[3].y = copper_thickness.y/2;
1303 
1304  stub.NewOutline();
1305 
1306  for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ )
1307  {
1308  wxPoint cpos = stubBuffer[ii];
1309  RotatePoint( &cpos, aPad.GetOrientation() );
1310  cpos += padShapePos;
1311  stub.Append( cpos.x, cpos.y );
1312  }
1313 
1314  stubs.Append( stub );
1315 
1316  stubBuffer[0].y = stub_len;
1317  stubBuffer[0].x = copper_thickness.x/2;
1318  stubBuffer[1] = stubBuffer[0];
1319  stubBuffer[1].x = -copper_thickness.x/2;
1320  stubBuffer[2] = stubBuffer[1];
1321  stubBuffer[2].y = -stub_len;
1322  stubBuffer[3] = stubBuffer[2];
1323  stubBuffer[3].x = copper_thickness.x/2;
1324 
1325  stub.RemoveAllContours();
1326  stub.NewOutline();
1327 
1328  for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ )
1329  {
1330  wxPoint cpos = stubBuffer[ii];
1331  RotatePoint( &cpos, aPad.GetOrientation() );
1332  cpos += padShapePos;
1333  stub.Append( cpos.x, cpos.y );
1334  }
1335 
1336  stubs.Append( stub );
1338 
1339  antipad.BooleanSubtract( stubs, SHAPE_POLY_SET::PM_FAST );
1340  aCornerBuffer.Append( antipad );
1341 
1342  break;
1343  }
1344 
1345  default:
1346  ;
1347  }
1348 }
1349 
1351  int aClearanceValue,
1352  int aCircleToSegmentsCount,
1353  double aCorrectionFactor,
1354  bool ignoreLineWidth ) const
1355 {
1356  wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for zones." );
1357 
1358  aCornerBuffer = m_FilledPolysList;
1360 }
void TransformRoundedEndsSegmentToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aStart, wxPoint aEnd, int aCircleToSegmentsCount, int aWidth)
Function TransformRoundedEndsSegmentToPolygon convert a segment with rounded ends to a polygon Conver...
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
Definition: common.cpp:183
#define DIM(x)
of elements in an array
Definition: macros.h:98
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:59
const wxPoint GetOrigin() const
Definition: eda_rect.h:112
double GetDrawRotation() const
PAD_ATTR_T GetAttribute() const
Definition: class_pad.h:405
TEXTE_PCB class definition.
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
const wxPoint & GetTextPos() const
Definition: eda_text.h:237
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:120
bool IsItalic() const
Definition: eda_text.h:183
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:65
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the track shape to a closed polygon Used in fil...
static void addTextSegmToPoly(int x0, int y0, int xf, int yf, void *aData)
Implementation of conversion functions that require both schematic and board internal units...
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
void TransformCircleToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aCenter, int aRadius, int aCircleToSegmentsCount)
Function TransformCircleToPolygon convert a circle to a polygon, using multiple straight lines...
int PointCount() const
Function PointCount()
void GetPoly(std::vector< wxPoint > &aOutput, int aMinSegLen=0)
Converts Bezier curve to a polygon.
void TransformGraphicShapesWithClearanceToPolygonSet(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aCornerBuffer, int aInflateValue, int aCircleToSegmentsCount, double aCorrectionFactor, int aCircleToSegmentsCountForTexts=0, bool aIncludeText=true) const
function TransformGraphicShapesWithClearanceToPolygonSet generate shapes of graphic items (outlines) ...
Class BOARD to handle a board.
void TransformRoundRectToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aPosition, const wxSize &aSize, double aRotation, int aCornerRadius, int aCircleToSegmentsCount)
Function TransformRoundRectToPolygon convert a rectangle with rounded corners to a polygon Convert ar...
int color
Definition: DXF_plotter.cpp:62
polygon (not yet used for tracks, but could be in microwave apps)
MODULE * Next() const
Definition: class_module.h:122
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:175
int GetHeight() const
Definition: eda_rect.h:118
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:92
void CreateThermalReliefPadPolygon(SHAPE_POLY_SET &aCornerBuffer, const D_PAD &aPad, int aThermalGap, int aCopperThickness, int aMinThicknessValue, int aCircleToSegmentsCount, double aCorrectionFactor, double aThermalRot)
Function CreateThermalReliefPadPolygon Add holes around a pad to create a thermal relief copper thick...
Classes to handle copper zones.
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:388
usual segment : line with rounded ends
EDA_ITEM * Next() const
Definition: base_struct.h:209
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
void TransformOvalClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aStart, wxPoint aEnd, int aWidth, int aCircleToSegmentsCount, double aCorrectionFactor)
convert a oblong shape to a polygon, using multiple segments It is similar to TransformRoundedEndsSeg...
const wxSize & GetDrillSize() const
Definition: class_pad.h:275
virtual wxString GetShownText() const override
Returns the string actually shown after processing of the base text.
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:216
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:203
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
static const int delta[8][2]
Definition: solve.cpp:112
void DrawGraphicText(EDA_RECT *aClipBox, wxDC *aDC, const wxPoint &aPos, COLOR4D aColor, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, void(*aCallback)(int x0, int y0, int xf, int yf, void *aData), void *aCallbackData, PLOTTER *aPlotter)
Function DrawGraphicText Draw a graphic text (like module texts)
Functions relatives to tracks, vias and segments used to fill zones.
int GetThickness() const
Function GetThickness returns pen width.
Definition: eda_text.h:167
wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
Definition: common.cpp:111
void TransformSolidAreasShapesToPolygonSet(SHAPE_POLY_SET &aCornerBuffer, int aCircleToSegmentsCount, double aCorrectionFactor) const
Function TransformSolidAreasShapesToPolygonSet Convert solid areas full shapes to polygon set (the fu...
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the pad shape to a closed polygon Used in filli...
BOARD_ITEM * Next() const
PCB_LAYER_ID
A quick note on layer IDs:
void TransformShapeWithClearanceToPolygonSet(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor) const
Function TransformShapeWithClearanceToPolygonSet Convert the text shape to a set of polygons (one by ...
void Inflate(int aFactor, int aCircleSegmentsCount)
Performs outline inflation/deflation, using round corners.
T AddAngles(T a1, T2 a2)
Add two angles (keeping the result normalized). T2 is here.
Definition: trigo.h:288
double GetOrientation() const
Definition: class_module.h:188
Class SHAPE_POLY_SET.
int GetSolderMaskMargin() const
Function GetSolderMaskMargin.
Definition: class_pad.cpp:593
TSEGM_2_POLY_PRMS prms
Arcs (with rounded ends)
D_PAD * Next() const
Definition: class_pad.h:160
const wxSize & GetSize() const
Definition: class_pad.h:269
void SetSize(const wxSize &aSize)
Definition: class_pad.h:268
void ConvertBrdLayerToPolygonalContours(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aOutlines)
Function ConvertBrdLayerToPolygonalContours Build a set of polygons which are the outlines of copper ...
a few functions useful in geometry calculations.
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
wxString GetText(GRAPHIC_PINSHAPE shape)
Definition: pin_shape.cpp:33
void TransformGraphicTextWithClearanceToPolygonSet(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aCornerBuffer, int aInflateValue, int aCircleToSegmentsCount, double aCorrectionFactor, int aCircleToSegmentsCountForTexts=0) const
TransformGraphicTextWithClearanceToPolygonSet This function is the same as TransformGraphicShapesWith...
int GetBottom() const
Definition: eda_rect.h:122
Bezier Curve.
int GetRight() const
Definition: eda_rect.h:119
void TransformPadsShapesWithClearanceToPolygon(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aCornerBuffer, int aInflateValue, int aCircleToSegmentsCount, double aCorrectionFactor, bool aSkipNPTHPadsWihNoCopper=false) const
function TransformPadsShapesWithClearanceToPolygon generate pads shapes on layer aLayer as polygons...
int NewOutline()
Creates a new empty polygon in the set and returns its index
Pad object description.
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the zone shape to a closed polygon Used in fill...
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:204
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the draw segment to a closed polygon Used in fi...
void TransformRingToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aCentre, int aRadius, int aCircleToSegmentsCount, int aWidth)
Function TransformRingToPolygon Creates a polygon from a ring Convert arcs to multiple straight segme...
Bezier curves to polygon converter.
Definition: bezier_curves.h:35
void TransformArcToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aCentre, wxPoint aStart, double aArcAngle, int aCircleToSegmentsCount, int aWidth)
Function TransformArcToPolygon Creates a polygon from an Arc Convert arcs to multiple straight segmen...
TRACK * Next() const
Definition: class_track.h:103
Class to handle a graphic segment.
void TransformBoundingBoxWithClearanceToPolygon(SHAPE_POLY_SET *aCornerBuffer, int aClearanceValue) const
Function TransformBoundingBoxWithClearanceToPolygon Convert the text bounding box to a rectangular po...
static LIB_PART * dummy()
Used when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
#define max(a, b)
Definition: auxiliary.h:86
bool IsMirrored() const
Definition: eda_text.h:192
Class SHAPE_LINE_CHAIN.
bool IsVisible() const
Definition: eda_text.h:189
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
size_t i
Definition: json11.cpp:597
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees, but soon degrees.
Definition: class_pad.h:382
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
wxSize GetSolderPasteMargin() const
Function GetSolderPasteMargin.
Definition: class_pad.cpp:636
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:154
int GetWidth() const
Definition: eda_rect.h:117
void BuildPadShapePolygon(SHAPE_POLY_SET &aCornerBuffer, wxSize aInflateValue, int aSegmentsPerCircle, double aCorrectionFactor) const
Function BuildPadShapePolygon Build the Corner list of the polygonal shape, depending on shape...
wxPoint ShapePos() const
Definition: class_pad.cpp:516
static bool GetLayer(MODEL_VRML &aModel, LAYER_NUM layer, VRML_LAYER **vlayer)
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp ...
Module description (excepted pads)
Definition: colors.h:45
const wxSize & GetTextSize() const
Definition: eda_text.h:228
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Function IsOnLayer tests to see if this object is on the given layer.
Definition: class_pad.h:663
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
bool BuildPadDrillShapePolygon(SHAPE_POLY_SET &aCornerBuffer, int aInflateValue, int aSegmentsPerCircle) const
Function BuildPadDrillShapePolygon Build the Corner list of the polygonal drill shape, depending on shape pad hole and orientation.
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
const wxPoint GetPosition() const override
Definition: class_module.h:183
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes...
Definition: class_pad.cpp:215
const wxPoint & GetOffset() const
Definition: class_pad.h:278
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
#define min(a, b)
Definition: auxiliary.h:85
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) ...
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
double GetCircletoPolyCorrectionFactor(int aSegCountforCircle)