KiCad PCB EDA Suite
create_3Dgraphic_brd_items.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) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
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 
33 #include "../3d_rendering/3d_render_raytracing/shapes2D/cring2d.h"
34 #include "../3d_rendering/3d_render_raytracing/shapes2D/cfilledcircle2d.h"
35 #include "../3d_rendering/3d_render_raytracing/shapes2D/croundsegment2d.h"
36 #include "../3d_rendering/3d_render_raytracing/shapes2D/cpolygon4pts2d.h"
37 #include "../3d_rendering/3d_render_raytracing/shapes2D/ctriangle2d.h"
38 #include <board_adapter.h>
39 #include <class_board.h>
40 #include <class_module.h>
41 #include <class_pad.h>
42 #include <class_pcb_text.h>
43 #include <class_edge_mod.h>
44 #include <class_zone.h>
45 #include <class_text_mod.h>
47 #include <trigo.h>
49 #include <gr_text.h>
50 #include <utility>
51 #include <vector>
52 
53 
54 
55 // These variables are parameters used in addTextSegmToContainer.
56 // But addTextSegmToContainer is a call-back function,
57 // so we cannot send them as arguments.
58 static int s_textWidth;
60 static float s_biuTo3Dunits;
61 static const BOARD_ITEM *s_boardItem = NULL;
62 
63 // This is a call back function, used by GRText to draw the 3D text shape:
64 void addTextSegmToContainer( int x0, int y0, int xf, int yf, void* aData )
65 {
66  const SFVEC2F start3DU( x0 * s_biuTo3Dunits, -y0 * s_biuTo3Dunits );
67  const SFVEC2F end3DU ( xf * s_biuTo3Dunits, -yf * s_biuTo3Dunits );
68 
69  if( Is_segment_a_circle( start3DU, end3DU ) )
70  s_dstcontainer->Add( new CFILLEDCIRCLE2D( start3DU,
71  ( s_textWidth / 2 ) * s_biuTo3Dunits,
72  *s_boardItem) );
73  else
74  s_dstcontainer->Add( new CROUNDSEGMENT2D( start3DU,
75  end3DU,
77  *s_boardItem ) );
78 }
79 
80 
81 // Based on
82 // void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet
83 // board_items_to_polygon_shape_transform.cpp
85  CGENERICCONTAINER2D *aDstContainer,
86  PCB_LAYER_ID aLayerId,
87  int aClearanceValue )
88 {
89  wxSize size = aText->GetTextSize();
90 
91  if( aText->IsMirrored() )
92  size.x = -size.x;
93 
94  s_boardItem = (const BOARD_ITEM *) &aText;
95  s_dstcontainer = aDstContainer;
96  s_textWidth = aText->GetEffectiveTextPenWidth() + ( 2 * aClearanceValue );
98 
99  // not actually used, but needed by GRText
100  const COLOR4D dummy_color = COLOR4D::BLACK;
101  bool forceBold = true;
102  int penWidth = 0; // force max width for bold
103 
104  if( aText->IsMultilineAllowed() )
105  {
106  wxArrayString strings_list;
107  wxStringSplit( aText->GetShownText(), strings_list, '\n' );
108  std::vector<wxPoint> positions;
109  positions.reserve( strings_list.Count() );
110  aText->GetLinePositions( positions, strings_list.Count());
111 
112  for( unsigned ii = 0; ii < strings_list.Count(); ++ii )
113  {
114  wxString txt = strings_list.Item( ii );
115 
116  GRText( nullptr, positions[ii], dummy_color, txt, aText->GetTextAngle(), size,
117  aText->GetHorizJustify(), aText->GetVertJustify(), penWidth,
118  aText->IsItalic(), forceBold, addTextSegmToContainer );
119  }
120  }
121  else
122  {
123  GRText( nullptr, aText->GetTextPos(), dummy_color, aText->GetShownText(),
124  aText->GetTextAngle(), size, aText->GetHorizJustify(), aText->GetVertJustify(),
125  penWidth, aText->IsItalic(), forceBold, addTextSegmToContainer );
126  }
127 }
128 
129 
131  CGENERICCONTAINER2D *aDstContainer,
132  PCB_LAYER_ID aLayerId,
133  int aClearanceValue )
134 {
135  AddShapeWithClearanceToContainer(&aDimension->Text(), aDstContainer, aLayerId, aClearanceValue);
136 
137  const int linewidth = aDimension->GetWidth() + (2 * aClearanceValue);
138 
139  std::pair<wxPoint const *, wxPoint const *> segs[] = {
140  {&aDimension->m_crossBarO, &aDimension->m_crossBarF},
141  {&aDimension->m_featureLineGO, &aDimension->m_featureLineGF},
142  {&aDimension->m_featureLineDO, &aDimension->m_featureLineDF},
143  {&aDimension->m_crossBarF, &aDimension->m_arrowD1F},
144  {&aDimension->m_crossBarF, &aDimension->m_arrowD2F},
145  {&aDimension->m_crossBarO, &aDimension->m_arrowG1F},
146  {&aDimension->m_crossBarO, &aDimension->m_arrowG2F}};
147 
148  for( auto const & ii : segs )
149  {
150  const SFVEC2F start3DU( ii.first->x * m_biuTo3Dunits,
151  -ii.first->y * m_biuTo3Dunits );
152 
153  const SFVEC2F end3DU ( ii.second->x * m_biuTo3Dunits,
154  -ii.second->y * m_biuTo3Dunits );
155 
156  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU,
157  end3DU,
158  linewidth * m_biuTo3Dunits,
159  *aDimension ) );
160  }
161 }
162 
163 
164 // Based on
165 // void MODULE::TransformGraphicShapesWithClearanceToPolygonSet
166 // board_items_to_polygon_shape_transform.cpp#L204
168  CGENERICCONTAINER2D *aDstContainer,
169  PCB_LAYER_ID aLayerId,
170  int aInflateValue )
171 {
172  std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert
173  EDGE_MODULE* outline;
174 
175  for( auto item : aModule->GraphicalItems() )
176  {
177  switch( item->Type() )
178  {
179  case PCB_MODULE_TEXT_T:
180  {
181  TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );
182 
183  if( text->GetLayer() == aLayerId && text->IsVisible() )
184  texts.push_back( text );
185  }
186  break;
187 
188 
189  case PCB_MODULE_EDGE_T:
190  {
191  outline = (EDGE_MODULE*) item;
192 
193  if( outline->GetLayer() != aLayerId )
194  break;
195 
197  aDstContainer,
198  aLayerId, 0 );
199  }
200  break;
201 
202  default:
203  break;
204  }
205  }
206 
207  // Convert texts sur modules
208  if( aModule->Reference().GetLayer() == aLayerId && aModule->Reference().IsVisible() )
209  texts.push_back( &aModule->Reference() );
210 
211  if( aModule->Value().GetLayer() == aLayerId && aModule->Value().IsVisible() )
212  texts.push_back( &aModule->Value() );
213 
214  s_boardItem = (const BOARD_ITEM *)&aModule->Value();
215  s_dstcontainer = aDstContainer;
217 
218  for( TEXTE_MODULE* text : texts )
219  {
220  s_textWidth = text->GetEffectiveTextPenWidth() + ( 2 * aInflateValue );
221  wxSize size = text->GetTextSize();
222  bool forceBold = true;
223  int penWidth = 0; // force max width for bold
224 
225  if( text->IsMirrored() )
226  size.x = -size.x;
227 
228  GRText( NULL, text->GetTextPos(), BLACK, text->GetShownText(), text->GetDrawRotation(),
229  size, text->GetHorizJustify(), text->GetVertJustify(), penWidth, text->IsItalic(),
230  forceBold, addTextSegmToContainer );
231  }
232 }
233 
234 
235 void BOARD_ADAPTER::createNewTrack( const TRACK* aTrack, CGENERICCONTAINER2D *aDstContainer,
236  int aClearanceValue )
237 {
238  SFVEC2F start3DU( aTrack->GetStart().x * m_biuTo3Dunits,
239  -aTrack->GetStart().y * m_biuTo3Dunits ); // y coord is inverted
240 
241  switch( aTrack->Type() )
242  {
243  case PCB_VIA_T:
244  {
245  const float radius = ( ( aTrack->GetWidth() / 2 ) + aClearanceValue ) * m_biuTo3Dunits;
246  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius, *aTrack ) );
247  }
248  break;
249 
250  case PCB_ARC_T:
251  {
252  const ARC* arc = static_cast<const ARC*>( aTrack );
253  VECTOR2D center( arc->GetCenter() );
254  double arc_angle = arc->GetAngle();
255  double radius = arc->GetRadius();
256  int arcsegcount = GetArcToSegmentCount( radius, Millimeter2iu( 0.005), arc_angle/10 );
257  int circlesegcount;
258 
259  // We need a circle to segment count. However, the arc angle can be small, and the
260  // radius very big. so we calculate a reasonable value for circlesegcount.
261  if( arcsegcount <= 1 ) // The arc will be approximated by a segment
262  circlesegcount = 1;
263  else
264  {
265  double cnt = arcsegcount * 3600/std::abs( arc_angle );
266 
267  #define SEG_CNT_MAX 128
268  if( cnt < SEG_CNT_MAX )
269  {
270  circlesegcount = (int)cnt;
271 
272  if( circlesegcount == 0 )
273  circlesegcount = 1;
274  }
275  else
276  circlesegcount = SEG_CNT_MAX;
277  }
278 
279  TransformArcToSegments( wxPoint( center.x, center.y ), arc->GetStart(),
280  arc_angle, circlesegcount,
281  arc->GetWidth() + 2 * aClearanceValue, aDstContainer,
282  *arc );
283  }
284  break;
285 
286  case PCB_TRACE_T: // Track is a usual straight segment
287  {
288  SFVEC2F end3DU ( aTrack->GetEnd().x * m_biuTo3Dunits,
289  -aTrack->GetEnd().y * m_biuTo3Dunits );
290 
291  // Cannot add segments that have the same start and end point
292  if( Is_segment_a_circle( start3DU, end3DU ) )
293  {
294  const float radius = ((aTrack->GetWidth() / 2) + aClearanceValue) * m_biuTo3Dunits;
295 
296  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius, *aTrack ) );
297  }
298  else
299  {
300  const float width = (aTrack->GetWidth() + 2 * aClearanceValue ) * m_biuTo3Dunits;
301 
302  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, width, *aTrack ) );
303  }
304  }
305  break;
306 
307  default:
308  break;
309  }
310 }
311 
312 
313 // Based on:
314 // void D_PAD:: TransformShapeWithClearanceToPolygon(
315 // board_items_to_polygon_shape_transform.cpp
317  CGENERICCONTAINER2D *aDstContainer,
318  wxSize aClearanceValue ) const
319 {
320  // note: for most of shapes, aClearanceValue.x = aClearanceValue.y
321  // only rectangular and oval shapes can have different values
322  // when drawn on the solder paste layer, because we can have a margin that is a
323  // percent of pad size
324  const int dx = (aPad->GetSize().x / 2) + aClearanceValue.x;
325  const int dy = (aPad->GetSize().y / 2) + aClearanceValue.y;
326 
327  if( !dx || !dy )
328  {
329  wxLogTrace( m_logTrace,
330  wxT( "BOARD_ADAPTER::createNewPadWithClearance - found an invalid pad" ) );
331 
332  return;
333  }
334 
335  wxPoint PadShapePos = aPad->ShapePos(); // Note: for pad having a shape offset,
336  // the pad position is NOT the shape position
337 
338  switch( aPad->GetShape() )
339  {
340  case PAD_SHAPE_CIRCLE:
341  {
342  const float radius = dx * m_biuTo3Dunits;
343 
344  const SFVEC2F center( PadShapePos.x * m_biuTo3Dunits,
345  -PadShapePos.y * m_biuTo3Dunits );
346 
347  aDstContainer->Add( new CFILLEDCIRCLE2D( center, radius, *aPad ) );
348  }
349  break;
350 
351  case PAD_SHAPE_OVAL:
352  {
353  if( dx == dy )
354  {
355  // The segment object cannot store start and end the same position,
356  // so add a circle instead
357  const float radius = dx * m_biuTo3Dunits;
358 
359  const SFVEC2F center( PadShapePos.x * m_biuTo3Dunits,
360  -PadShapePos.y * m_biuTo3Dunits );
361 
362  aDstContainer->Add( new CFILLEDCIRCLE2D( center, radius, *aPad ) );
363  }
364  else
365  {
366  // An oval pad has the same shape as a segment with rounded ends
367 
368  int iwidth;
369  wxPoint shape_offset = wxPoint( 0, 0 );
370 
371  if( dy > dx ) // Oval pad X/Y ratio for choosing translation axis
372  {
373  shape_offset.y = dy - dx;
374  iwidth = dx * 2;
375  }
376  else //if( dy < dx )
377  {
378  shape_offset.x = dy - dx;
379  iwidth = dy * 2;
380  }
381 
382  RotatePoint( &shape_offset, aPad->GetOrientation() );
383 
384  const wxPoint start = PadShapePos - shape_offset;
385  const wxPoint end = PadShapePos + shape_offset;
386 
387  const SFVEC2F start3DU( start.x * m_biuTo3Dunits, -start.y * m_biuTo3Dunits );
388  const SFVEC2F end3DU ( end.x * m_biuTo3Dunits, -end.y * m_biuTo3Dunits );
389 
390  // Cannot add segments that have the same start and end point
391  if( Is_segment_a_circle( start3DU, end3DU ) )
392  {
393  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
394  (iwidth / 2) * m_biuTo3Dunits,
395  *aPad ) );
396  }
397  else
398  {
399  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
400  iwidth * m_biuTo3Dunits,
401  *aPad ) );
402  }
403  }
404  }
405  break;
406 
407  case PAD_SHAPE_TRAPEZOID:
408  case PAD_SHAPE_RECT:
409  {
410  // see pcbnew/board_items_to_polygon_shape_transform.cpp
411  wxPoint corners[4];
412  bool drawOutline;
413 
414  // For aClearanceValue.x == aClearanceValue.y and > 0 we use the pad shape
415  // and draw outlines with thicknes = aClearanceValue.
416  // Otherwise we draw only the inflated/deflated shape
417  if( aClearanceValue.x > 0 && aClearanceValue.x == aClearanceValue.y )
418  {
419  drawOutline = true;
420  aPad->BuildPadPolygon( corners, wxSize( 0, 0 ), aPad->GetOrientation() );
421  }
422  else
423  {
424  drawOutline = false;
425  aPad->BuildPadPolygon( corners, aClearanceValue, aPad->GetOrientation() );
426  }
427 
428  SFVEC2F corners3DU[4];
429 
430  // Note: for pad having a shape offset,
431  // the pad position is NOT the shape position
432  for( unsigned int ii = 0; ii < 4; ++ii )
433  {
434  corners[ii] += aPad->ShapePos(); // Shift origin to position
435 
436  corners3DU[ii] = SFVEC2F( corners[ii].x * m_biuTo3Dunits,
437  -corners[ii].y * m_biuTo3Dunits );
438  }
439 
440 
441  // Learn more at:
442  // https://lists.launchpad.net/kicad-developers/msg18729.html
443 
444  // Add the PAD polygon
445  aDstContainer->Add( new CPOLYGON4PTS2D( corners3DU[0],
446  corners3DU[1],
447  corners3DU[2],
448  corners3DU[3],
449  *aPad ) );
450 
451  // Add the PAD contours
452  // Round segments cannot have 0-length elements, so we approximate them
453  // as a small circle
454  if( drawOutline )
455  {
456  for( int i = 1; i <= 4; i++ )
457  {
458  if( Is_segment_a_circle( corners3DU[i - 1], corners3DU[i & 3] ) )
459  {
460  aDstContainer->Add( new CFILLEDCIRCLE2D( corners3DU[i - 1],
461  aClearanceValue.x * m_biuTo3Dunits,
462  *aPad ) );
463  }
464  else
465  {
466  aDstContainer->Add( new CROUNDSEGMENT2D( corners3DU[i - 1],
467  corners3DU[i & 3],
468  aClearanceValue.x * 2.0f * m_biuTo3Dunits,
469  *aPad ) );
470  }
471  }
472  }
473  }
474  break;
475 
476  case PAD_SHAPE_ROUNDRECT:
477  {
478  wxSize shapesize( aPad->GetSize() );
479  shapesize.x += aClearanceValue.x * 2;
480  shapesize.y += aClearanceValue.y * 2;
481 
482  int rounding_radius = aPad->GetRoundRectCornerRadius( shapesize );
483 
484  wxPoint corners[4];
485 
486  GetRoundRectCornerCenters( corners,
487  rounding_radius,
488  PadShapePos,
489  shapesize,
490  aPad->GetOrientation() );
491 
492  SFVEC2F corners3DU[4];
493 
494  for( unsigned int ii = 0; ii < 4; ++ii )
495  corners3DU[ii] = SFVEC2F( corners[ii].x * m_biuTo3Dunits,
496  -corners[ii].y * m_biuTo3Dunits );
497 
498  // Add the PAD polygon (For some reason the corners need
499  // to be inverted to display with the correctly orientation)
500  aDstContainer->Add( new CPOLYGON4PTS2D( corners3DU[0],
501  corners3DU[3],
502  corners3DU[2],
503  corners3DU[1],
504  *aPad ) );
505 
506  // Add the PAD contours
507  // Round segments cannot have 0-length elements, so we approximate them
508  // as a small circle
509  for( int i = 1; i <= 4; i++ )
510  {
511  if( Is_segment_a_circle( corners3DU[i - 1], corners3DU[i & 3] ) )
512  {
513  aDstContainer->Add( new CFILLEDCIRCLE2D( corners3DU[i - 1],
514  rounding_radius * m_biuTo3Dunits,
515  *aPad ) );
516  }
517  else
518  {
519  aDstContainer->Add( new CROUNDSEGMENT2D( corners3DU[i - 1],
520  corners3DU[i & 3],
521  rounding_radius * 2.0f * m_biuTo3Dunits,
522  *aPad ) );
523  }
524  }
525  }
526  break;
527 
529  {
530  wxSize shapesize( aPad->GetSize() );
531  shapesize.x += aClearanceValue.x * 2;
532  shapesize.y += aClearanceValue.y * 2;
533 
534  SHAPE_POLY_SET polyList; // Will contain the pad outlines in board coordinates
535 
536  int corner_radius = aPad->GetRoundRectCornerRadius( shapesize );
537  TransformRoundChamferedRectToPolygon( polyList, PadShapePos, shapesize, aPad->GetOrientation(),
538  corner_radius, aPad->GetChamferRectRatio(),
539  aPad->GetChamferPositions(), ARC_HIGH_DEF );
540 
541  // Add the PAD polygon
542  Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits, *aPad );
543 
544  }
545  break;
546 
547  case PAD_SHAPE_CUSTOM:
548  {
549  SHAPE_POLY_SET polyList; // Will contain the pad outlines in board coordinates
550  polyList.Append( aPad->GetCustomShapeAsPolygon() );
551  aPad->CustomShapeAsPolygonToBoardPosition( &polyList, aPad->ShapePos(), aPad->GetOrientation() );
552 
553  if( aClearanceValue.x )
554  polyList.Inflate( aClearanceValue.x, 32 );
555 
556  // Add the PAD polygon
557  Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits, *aPad );
558 
559  }
560  break;
561  }
562 }
563 
564 
565 // Based on:
566 // BuildPadDrillShapePolygon
567 // board_items_to_polygon_shape_transform.cpp
568 COBJECT2D *BOARD_ADAPTER::createNewPadDrill( const D_PAD* aPad, int aInflateValue )
569 {
570  wxSize drillSize = aPad->GetDrillSize();
571 
572  if( !drillSize.x || !drillSize.y )
573  {
574  wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createNewPadDrill - found an invalid pad" ) );
575  return NULL;
576  }
577 
578  if( drillSize.x == drillSize.y ) // usual round hole
579  {
580  const int radius = (drillSize.x / 2) + aInflateValue;
581 
582  const SFVEC2F center( aPad->GetPosition().x * m_biuTo3Dunits,
583  -aPad->GetPosition().y * m_biuTo3Dunits );
584 
585  return new CFILLEDCIRCLE2D( center, radius * m_biuTo3Dunits, *aPad );
586 
587  }
588  else // Oblong hole
589  {
590  wxPoint start, end;
591  int width;
592 
593  aPad->GetOblongGeometry( aPad->GetDrillSize(), &start, &end, &width );
594 
595  width += aInflateValue * 2;
596  start += aPad->GetPosition();
597  end += aPad->GetPosition();
598 
599  SFVEC2F start3DU( start.x * m_biuTo3Dunits,
600  -start.y * m_biuTo3Dunits );
601 
602  SFVEC2F end3DU ( end.x * m_biuTo3Dunits,
603  -end.y * m_biuTo3Dunits );
604 
605  if( Is_segment_a_circle( start3DU, end3DU ) )
606  {
607  return new CFILLEDCIRCLE2D( start3DU, (width / 2) * m_biuTo3Dunits, *aPad );
608  }
609  else
610  {
611  return new CROUNDSEGMENT2D( start3DU, end3DU, width * m_biuTo3Dunits, *aPad );
612  }
613  }
614 
615  return NULL;
616 }
617 
618 
620  CGENERICCONTAINER2D *aDstContainer,
621  PCB_LAYER_ID aLayerId,
622  int aInflateValue,
623  bool aSkipNPTHPadsWihNoCopper )
624 {
625  wxSize margin;
626 
627  for( auto pad : aModule->Pads() )
628  {
629  if( !pad->IsOnLayer( aLayerId ) )
630  continue;
631 
632  // NPTH pads are not drawn on layers if the
633  // shape size and pos is the same as their hole:
634  if( aSkipNPTHPadsWihNoCopper && (pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED) )
635  {
636  if( (pad->GetDrillSize() == pad->GetSize()) &&
637  (pad->GetOffset() == wxPoint( 0, 0 )) )
638  {
639  switch( pad->GetShape() )
640  {
641  case PAD_SHAPE_CIRCLE:
642  if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
643  continue;
644  break;
645 
646  case PAD_SHAPE_OVAL:
647  if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
648  continue;
649  break;
650 
651  default:
652  break;
653  }
654  }
655  }
656 
657  switch( aLayerId )
658  {
659  case F_Mask:
660  case B_Mask:
661  margin.x = margin.y = pad->GetSolderMaskMargin() + aInflateValue;
662  break;
663 
664  case F_Paste:
665  case B_Paste:
666  margin = pad->GetSolderPasteMargin();
667  margin.x += aInflateValue;
668  margin.y += aInflateValue;
669  break;
670 
671  default:
672  margin.x = margin.y = aInflateValue;
673  break;
674  }
675 
676  createNewPadWithClearance( pad, aDstContainer, margin );
677  }
678 }
679 
680 // based on TransformArcToPolygon function from
681 // common/convert_basic_shapes_to_polygon.cpp
683  const wxPoint &aStart,
684  double aArcAngle,
685  int aCircleToSegmentsCount,
686  int aWidth,
687  CGENERICCONTAINER2D *aDstContainer,
688  const BOARD_ITEM &aBoardItem )
689 {
690  wxPoint arc_start, arc_end;
691  int delta = 3600 / aCircleToSegmentsCount; // rotate angle in 0.1 degree
692 
693  arc_end = arc_start = aStart;
694 
695  if( aArcAngle != 3600 )
696  {
697  RotatePoint( &arc_end, aCentre, -aArcAngle );
698  }
699 
700  if( aArcAngle < 0 )
701  {
702  std::swap( arc_start, arc_end );
703  aArcAngle = -aArcAngle;
704  }
705 
706  // Compute the ends of segments and creates poly
707  wxPoint curr_end = arc_start;
708  wxPoint curr_start = arc_start;
709 
710  for( int ii = delta; ii < aArcAngle; ii += delta )
711  {
712  curr_end = arc_start;
713  RotatePoint( &curr_end, aCentre, -ii );
714 
715  const SFVEC2F start3DU( curr_start.x * m_biuTo3Dunits, -curr_start.y * m_biuTo3Dunits );
716  const SFVEC2F end3DU ( curr_end.x * m_biuTo3Dunits, -curr_end.y * m_biuTo3Dunits );
717 
718  if( Is_segment_a_circle( start3DU, end3DU ) )
719  {
720  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
721  ( aWidth / 2 ) * m_biuTo3Dunits,
722  aBoardItem ) );
723  }
724  else
725  {
726  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
727  aWidth * m_biuTo3Dunits,
728  aBoardItem ) );
729  }
730 
731  curr_start = curr_end;
732  }
733 
734  if( curr_end != arc_end )
735  {
736  const SFVEC2F start3DU( curr_end.x * m_biuTo3Dunits, -curr_end.y * m_biuTo3Dunits );
737  const SFVEC2F end3DU ( arc_end.x * m_biuTo3Dunits, -arc_end.y * m_biuTo3Dunits );
738 
739  if( Is_segment_a_circle( start3DU, end3DU ) )
740  {
741  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
742  ( aWidth / 2 ) * m_biuTo3Dunits,
743  aBoardItem ) );
744  }
745  else
746  {
747  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU,
748  end3DU,
749  aWidth * m_biuTo3Dunits,
750  aBoardItem ) );
751  }
752  }
753 }
754 
755 // Based on
756 // TransformShapeWithClearanceToPolygon
757 // board_items_to_polygon_shape_transform.cpp#L431
759  CGENERICCONTAINER2D *aDstContainer,
760  PCB_LAYER_ID aLayerId,
761  int aClearanceValue )
762 {
763  // The full width of the lines to create
764  // The extra 1 protects the inner/outer radius values from degeneracy
765  const int linewidth = aDrawSegment->GetWidth() + (2 * aClearanceValue) + 1;
766 
767  switch( aDrawSegment->GetShape() )
768  {
769  case S_CIRCLE:
770  {
771  const SFVEC2F center3DU( aDrawSegment->GetCenter().x * m_biuTo3Dunits,
772  -aDrawSegment->GetCenter().y * m_biuTo3Dunits );
773 
774  float inner_radius = ( aDrawSegment->GetRadius() - linewidth / 2 ) * m_biuTo3Dunits;
775  float outer_radius = ( aDrawSegment->GetRadius() + linewidth / 2 ) * m_biuTo3Dunits;
776 
777  if( inner_radius < 0 )
778  inner_radius = 0;
779 
780  aDstContainer->Add( new CRING2D( center3DU, inner_radius, outer_radius, *aDrawSegment ) );
781  }
782  break;
783 
784  case S_ARC:
785  {
786  const unsigned int nr_segments =
787  GetNrSegmentsCircle( aDrawSegment->GetBoundingBox().GetSizeMax() );
788 
789  TransformArcToSegments( aDrawSegment->GetCenter(),
790  aDrawSegment->GetArcStart(),
791  aDrawSegment->GetAngle(),
792  nr_segments,
793  aDrawSegment->GetWidth(),
794  aDstContainer,
795  *aDrawSegment );
796  }
797  break;
798 
799  case S_SEGMENT:
800  {
801  const SFVEC2F start3DU( aDrawSegment->GetStart().x * m_biuTo3Dunits,
802  -aDrawSegment->GetStart().y * m_biuTo3Dunits );
803 
804  const SFVEC2F end3DU ( aDrawSegment->GetEnd().x * m_biuTo3Dunits,
805  -aDrawSegment->GetEnd().y * m_biuTo3Dunits );
806 
807  if( Is_segment_a_circle( start3DU, end3DU ) )
808  {
809  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
810  ( linewidth / 2 ) * m_biuTo3Dunits,
811  *aDrawSegment ) );
812  }
813  else
814  {
815  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU,
816  end3DU,
817  linewidth * m_biuTo3Dunits,
818  *aDrawSegment ) );
819  }
820  }
821  break;
822 
823  case S_CURVE:
824  case S_POLYGON:
825  {
826  SHAPE_POLY_SET polyList;
827 
828  aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aClearanceValue );
829 
830  polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
831 
832  if( polyList.IsEmpty() ) // Just for caution
833  break;
834 
835  Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer,
836  m_biuTo3Dunits, *aDrawSegment );
837  }
838  break;
839 
840  default:
841  break;
842  }
843 }
844 
845 
846 // Based on
847 // TransformSolidAreasShapesToPolygonSet
848 // board_items_to_polygon_shape_transform.cpp
850  CGENERICCONTAINER2D *aDstContainer,
851  PCB_LAYER_ID aLayerId )
852 {
853  // Copy the polys list because we have to simplify it
854  SHAPE_POLY_SET polyList = SHAPE_POLY_SET( aZoneContainer->GetFilledPolysList(), true );
855 
856  // This convert the poly in outline and holes
857  Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits,
858  *aZoneContainer );
859 
860  // add filled areas outlines, which are drawn with thick lines segments
861  // but only if filled polygons outlines have thickness
862  if( !aZoneContainer->GetFilledPolysUseThickness() )
863  return;
864 
865  float line_thickness = aZoneContainer->GetMinThickness() * m_biuTo3Dunits;
866 
867  for( int i = 0; i < polyList.OutlineCount(); ++i )
868  {
869  // Add outline
870  const SHAPE_LINE_CHAIN& pathOutline = polyList.COutline( i );
871 
872  for( int j = 0; j < pathOutline.PointCount(); ++j )
873  {
874  const VECTOR2I& a = pathOutline.CPoint( j );
875  const VECTOR2I& b = pathOutline.CPoint( j + 1 );
876 
877  SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits );
878  SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits );
879 
880  if( Is_segment_a_circle( start3DU, end3DU ) )
881  {
882  float radius = line_thickness/2;
883 
884  if( radius > 0.0 ) // degenerated circles crash 3D viewer
885  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius,
886  *aZoneContainer ) );
887  }
888  else
889  {
890  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, line_thickness,
891  *aZoneContainer ) );
892  }
893  }
894 
895  // Add holes (of the poly, ie: the open parts) for this outline
896  for( int h = 0; h < polyList.HoleCount( i ); ++h )
897  {
898  const SHAPE_LINE_CHAIN& pathHole = polyList.CHole( i, h );
899 
900  for( int j = 0; j < pathHole.PointCount(); j++ )
901  {
902  const VECTOR2I& a = pathHole.CPoint( j );
903  const VECTOR2I& b = pathHole.CPoint( j + 1 );
904 
905  SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits );
906  SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits );
907 
908  if( Is_segment_a_circle( start3DU, end3DU ) )
909  {
910  float radius = line_thickness/2;
911 
912  if( radius > 0.0 ) // degenerated circles crash 3D viewer
913  aDstContainer->Add(
914  new CFILLEDCIRCLE2D( start3DU, radius,
915  *aZoneContainer ) );
916  }
917  else
918  {
919  aDstContainer->Add(
920  new CROUNDSEGMENT2D( start3DU, end3DU, line_thickness,
921  *aZoneContainer ) );
922  }
923  }
924  }
925  }
926 }
927 
928 
929 
931  CGENERICCONTAINER2D *aDstContainer,
932  int aWidth )
933 {
934  if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring
935  {
936  const SFVEC2F center3DU( aPad->ShapePos().x * m_biuTo3Dunits,
937  -aPad->ShapePos().y * m_biuTo3Dunits );
938 
939  const int radius = aPad->GetSize().x / 2;
940  const float inner_radius = ( radius - aWidth / 2 ) * m_biuTo3Dunits;
941  const float outer_radius = ( radius + aWidth / 2 ) * m_biuTo3Dunits;
942 
943  aDstContainer->Add( new CRING2D( center3DU, inner_radius, outer_radius, *aPad ) );
944 
945  return;
946  }
947 
948  // For other shapes, draw polygon outlines
949  SHAPE_POLY_SET corners;
950  aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ) );
951 
952 
953  // Add outlines as thick segments in polygon buffer
954 
955  const SHAPE_LINE_CHAIN& path = corners.COutline( 0 );
956 
957  for( int j = 0; j < path.PointCount(); j++ )
958  {
959  const VECTOR2I& a = path.CPoint( j );
960  const VECTOR2I& b = path.CPoint( j + 1 );
961 
962  SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits );
963  SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits );
964 
965  if( Is_segment_a_circle( start3DU, end3DU ) )
966  {
967  aDstContainer->Add(
968  new CFILLEDCIRCLE2D( start3DU, ( aWidth / 2 ) * m_biuTo3Dunits, *aPad ) );
969  }
970  else
971  {
972  aDstContainer->Add(
973  new CROUNDSEGMENT2D( start3DU, end3DU, aWidth * m_biuTo3Dunits, *aPad ) );
974  }
975  }
976 }
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
Definition: common.cpp:333
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:60
TEXTE_MODULE & Reference()
Definition: class_module.h:481
int OutlineCount() const
Returns the number of outlines in the set
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:199
bool IsMirrored() const
Definition: eda_text.h:188
int GetWidth() const
TEXTE_PCB class definition.
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:66
wxPoint m_crossBarF
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
const wxPoint GetCenter() const override
Function GetCenter()
#define SEG_CNT_MAX
wxPoint m_arrowD1F
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aError=ARC_HIGH_DEF, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the draw segment to a closed polygon Used in fi...
const wxPoint & GetStart() const
Definition: class_track.h:118
STROKE_T GetShape() const
bool IsVisible() const
Definition: eda_text.h:185
polygon (not yet used for tracks, but could be in microwave apps)
void AddGraphicsShapesWithClearanceToContainer(const MODULE *aModule, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aInflateValue)
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
PADS & Pads()
Definition: class_module.h:169
double GetTextAngle() const
Definition: eda_text.h:173
void BuildPadShapePolygon(SHAPE_POLY_SET &aCornerBuffer, wxSize aInflateValue, int aError=ARC_HIGH_DEF) const
Function BuildPadShapePolygon Build the Corner list of the polygonal shape, depending on shape,...
bool GetFilledPolysUseThickness() const
Definition: class_zone.h:621
class ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
usual segment : line with rounded ends
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
wxPoint m_featureLineDF
DRAWINGS & GraphicalItems()
Definition: class_module.h:179
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
void Inflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Performs outline inflation/deflation.
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
int PointCount() const
Function PointCount()
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
void buildPadShapeThickOutlineAsSegments(const D_PAD *aPad, CGENERICCONTAINER2D *aDstContainer, int aWidth)
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
void AddShapeWithClearanceToContainer(const TEXTE_PCB *aTextPCB, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aClearanceValue)
int GetEffectiveTextPenWidth(int aDefaultWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultWidth.
Definition: eda_text.cpp:152
int GetChamferPositions() const
has meaning only for chamfered rect pads
Definition: class_pad.h:698
static int s_textWidth
wxPoint m_featureLineGO
bool IsItalic() const
Definition: eda_text.h:179
void TransformArcToSegments(const wxPoint &aCentre, const wxPoint &aStart, double aArcAngle, int aCircleToSegmentsCount, int aWidth, CGENERICCONTAINER2D *aDstContainer, const BOARD_ITEM &aBoardItem)
const VECTOR2I & CPoint(int aIndex) const
Function Point()
PCB_LAYER_ID
A quick note on layer IDs:
unsigned int GetNrSegmentsCircle(float aDiameter3DU) const
GetNrSegmentsCircle.
bool Is_segment_a_circle(const SFVEC2F &aStart, const SFVEC2F &aEnd)
Segment_is_a_circle - check if segment start and end is very close to each other should used to check...
Footprint text class description.
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:198
glm::vec2 SFVEC2F
Definition: xv3d_types.h:45
#define NULL
void AddPadsShapesWithClearanceToContainer(const MODULE *aModule, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aInflateValue, bool aSkipNPTHPadsWihNoCopper)
static float s_biuTo3Dunits
SHAPE_POLY_SET.
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:480
const wxSize & GetTextSize() const
Definition: eda_text.h:238
Arcs (with rounded ends)
double GetChamferRectRatio() const
has meaning only for chamfered rect pads
Definition: class_pad.h:675
wxPoint m_arrowG1F
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
wxPoint m_arrowD2F
wxPoint m_arrowG2F
static CGENERICCONTAINER2D * s_dstcontainer
double m_biuTo3Dunits
Normalization scale to convert board internal units to 3D units to normalize 3D units between -1....
a few functions useful in geometry calculations.
const wxPoint & GetArcStart() const
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
Bezier Curve.
double GetRadius() const
int HoleCount(int aOutline) const
Returns the number of holes in a given outline
int GetWidth() const
bool IsMultilineAllowed() const
Definition: eda_text.h:196
Pad object description.
void GRText(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 GRText Draw a graphic text (like module texts)
Definition: gr_text.cpp:134
void TransformRoundChamferedRectToPolygon(SHAPE_POLY_SET &aCornerBuffer, const wxPoint &aPosition, const wxSize &aSize, double aRotation, int aCornerRadius, double aChamferRatio, int aChamferCorners, int aApproxErrorMax, int aMinSegPerCircleCount=16)
convert a rectangle with rounded corners and/or chamfered corners to a polygon Convert rounded corner...
void BuildPadPolygon(wxPoint aCoord[4], wxSize aInflateValue, double aRotation) const
Function BuildPadPolygon Has meaning only for polygonal pads (trapezoid and rectangular) Build the Co...
Definition: class_pad.cpp:771
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
void Add(COBJECT2D *aObject)
Definition: ccontainer2d.h:52
double GetAngle() const
double GetAngle() const
This handles simple polygons with 4 points.
int GetWidth() const
Definition: class_track.h:112
SHAPE_LINE_CHAIN.
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees,...
Definition: class_pad.h:411
void CustomShapeAsPolygonToBoardPosition(SHAPE_POLY_SET *aMergedPolygon, wxPoint aPosition, double aRotation) const
When created, the corners coordinates are relative to the pad position, orientation 0,...
void createNewPadWithClearance(const D_PAD *aPad, CGENERICCONTAINER2D *aDstContainer, wxSize aClearanceValue) const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
TEXTE_PCB & Text()
const wxSize & GetDrillSize() const
Definition: class_pad.h:291
wxPoint ShapePos() const
Definition: class_pad.cpp:601
const SHAPE_POLY_SET & GetCustomShapeAsPolygon() const
Accessor to the custom shape as one polygon.
Definition: class_pad.h:363
void AddSolidAreasShapesToContainer(const ZONE_CONTAINER *aZoneContainer, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId)
COBJECT2D * createNewPadDrill(const D_PAD *aPad, int aInflateValue)
int GetMinThickness() const
Definition: class_zone.h:191
const wxPoint & GetEnd() const
Definition: class_track.h:115
void GetLinePositions(std::vector< wxPoint > &aPositions, int aLineCount) const
Populate aPositions with the position of each line of a multiline text, according to the vertical jus...
Definition: eda_text.cpp:418
int GetRoundRectCornerRadius() const
Function GetRoundRectCornerRadius Has meaning only for rounded rect pads.
Definition: class_pad.h:551
void createNewTrack(const TRACK *aTrack, CGENERICCONTAINER2D *aDstContainer, int aClearanceValue)
void GetRoundRectCornerCenters(wxPoint aCenters[4], int aRadius, const wxPoint &aPosition, const wxSize &aSize, double aRotation)
Helper function GetRoundRectCornerCenters Has meaning only for rounded rect Returns the centers of th...
void addTextSegmToContainer(int x0, int y0, int xf, int yf, void *aData)
const wxPoint & GetTextPos() const
Definition: eda_text.h:247
wxPoint m_crossBarO
virtual const wxPoint GetCenter() const
Function GetCenter()
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:222
Definition: colors.h:45
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
static const BOARD_ITEM * s_boardItem
const wxSize & GetSize() const
Definition: class_pad.h:285
const wxPoint GetPosition() const override
Definition: class_pad.h:226
EDGE_MODULE class definition.
void GetOblongGeometry(const wxSize &aDrillOrPadSize, wxPoint *aStartPoint, wxPoint *aEndPoint, int *aWidth) const
Function GetOblongGeometry calculates the start point, end point and width of an equivalent segment w...
Definition: class_pad.cpp:1007
wxPoint m_featureLineDO
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
int GetSizeMax() const
GetSizeMax.
Definition: eda_rect.h:109
DIMENSION.
void Convert_shape_line_polygon_to_triangles(SHAPE_POLY_SET &aPolyList, CGENERICCONTAINER2D &aDstContainer, float aBiuTo3DunitsScale, const BOARD_ITEM &aBoardItem)
KICAD_T Type() const
Function Type()
Definition: base_struct.h:197
const SHAPE_POLY_SET & GetFilledPolysList() const
Function GetFilledPolysList returns a reference to the list of filled polygons.
Definition: class_zone.h:575
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)
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:40
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
wxPoint m_featureLineGF