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