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