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