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