KiCad PCB EDA Suite
create_3Dgraphic_brd_items.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2016 Mario Luzeiro <mrluzeiro@ua.pt>
5  * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
33 #include "../3d_rendering/3d_render_raytracing/shapes2D/cring2d.h"
34 #include "../3d_rendering/3d_render_raytracing/shapes2D/cfilledcircle2d.h"
35 #include "../3d_rendering/3d_render_raytracing/shapes2D/croundsegment2d.h"
36 #include "../3d_rendering/3d_render_raytracing/shapes2D/ctriangle2d.h"
37 #include <board_adapter.h>
38 #include <class_board.h>
39 #include <class_module.h>
40 #include <class_pad.h>
41 #include <class_pcb_text.h>
42 #include <class_edge_mod.h>
43 #include <class_zone.h>
44 #include <class_text_mod.h>
46 #include <trigo.h>
47 #include <geometry/shape_segment.h>
49 #include <geometry/shape_circle.h>
50 #include <geometry/shape_rect.h>
51 #include <geometry/shape_simple.h>
52 #include <gr_text.h>
53 #include <utility>
54 #include <vector>
55 
56 
57 // These variables are parameters used in addTextSegmToContainer.
58 // But addTextSegmToContainer is a call-back function,
59 // so we cannot send them as arguments.
60 static int s_textWidth;
62 static float s_biuTo3Dunits;
63 static const BOARD_ITEM *s_boardItem = NULL;
64 
65 // This is a call back function, used by GRText to draw the 3D text shape:
66 void addTextSegmToContainer( int x0, int y0, int xf, int yf, void* aData )
67 {
68  const SFVEC2F start3DU( x0 * s_biuTo3Dunits, -y0 * s_biuTo3Dunits );
69  const SFVEC2F end3DU ( xf * s_biuTo3Dunits, -yf * s_biuTo3Dunits );
70 
71  if( Is_segment_a_circle( start3DU, end3DU ) )
72  s_dstcontainer->Add( new CFILLEDCIRCLE2D( start3DU,
73  ( s_textWidth / 2 ) * s_biuTo3Dunits,
74  *s_boardItem) );
75  else
76  s_dstcontainer->Add( new CROUNDSEGMENT2D( start3DU,
77  end3DU,
79  *s_boardItem ) );
80 }
81 
82 
83 // Based on
84 // void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet
85 // board_items_to_polygon_shape_transform.cpp
87  CGENERICCONTAINER2D *aDstContainer,
88  PCB_LAYER_ID aLayerId,
89  int aClearanceValue )
90 {
91  wxSize size = aText->GetTextSize();
92 
93  if( aText->IsMirrored() )
94  size.x = -size.x;
95 
96  s_boardItem = (const BOARD_ITEM *) &aText;
97  s_dstcontainer = aDstContainer;
98  s_textWidth = aText->GetEffectiveTextPenWidth() + ( 2 * aClearanceValue );
100 
101  // not actually used, but needed by GRText
102  const COLOR4D dummy_color = COLOR4D::BLACK;
103  bool forceBold = true;
104  int penWidth = 0; // force max width for bold
105 
106  if( aText->IsMultilineAllowed() )
107  {
108  wxArrayString strings_list;
109  wxStringSplit( aText->GetShownText(), strings_list, '\n' );
110  std::vector<wxPoint> positions;
111  positions.reserve( strings_list.Count() );
112  aText->GetLinePositions( positions, strings_list.Count());
113 
114  for( unsigned ii = 0; ii < strings_list.Count(); ++ii )
115  {
116  wxString txt = strings_list.Item( ii );
117 
118  GRText( nullptr, positions[ii], dummy_color, txt, aText->GetTextAngle(), size,
119  aText->GetHorizJustify(), aText->GetVertJustify(), penWidth,
120  aText->IsItalic(), forceBold, addTextSegmToContainer );
121  }
122  }
123  else
124  {
125  GRText( nullptr, aText->GetTextPos(), dummy_color, aText->GetShownText(),
126  aText->GetTextAngle(), size, aText->GetHorizJustify(), aText->GetVertJustify(),
127  penWidth, aText->IsItalic(), forceBold, addTextSegmToContainer );
128  }
129 }
130 
131 
133  CGENERICCONTAINER2D *aDstContainer,
134  PCB_LAYER_ID aLayerId,
135  int aClearanceValue )
136 {
137  AddShapeWithClearanceToContainer(&aDimension->Text(), aDstContainer, aLayerId, aClearanceValue);
138 
139  const int linewidth = aDimension->GetWidth() + (2 * aClearanceValue);
140 
141  std::pair<wxPoint const *, wxPoint const *> segs[] = {
142  {&aDimension->m_crossBarO, &aDimension->m_crossBarF},
143  {&aDimension->m_featureLineGO, &aDimension->m_featureLineGF},
144  {&aDimension->m_featureLineDO, &aDimension->m_featureLineDF},
145  {&aDimension->m_crossBarF, &aDimension->m_arrowD1F},
146  {&aDimension->m_crossBarF, &aDimension->m_arrowD2F},
147  {&aDimension->m_crossBarO, &aDimension->m_arrowG1F},
148  {&aDimension->m_crossBarO, &aDimension->m_arrowG2F}};
149 
150  for( auto const & ii : segs )
151  {
152  const SFVEC2F start3DU( ii.first->x * m_biuTo3Dunits,
153  -ii.first->y * m_biuTo3Dunits );
154 
155  const SFVEC2F end3DU ( ii.second->x * m_biuTo3Dunits,
156  -ii.second->y * m_biuTo3Dunits );
157 
158  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU,
159  end3DU,
160  linewidth * m_biuTo3Dunits,
161  *aDimension ) );
162  }
163 }
164 
165 
166 // Based on
167 // void MODULE::TransformGraphicShapesWithClearanceToPolygonSet
168 // board_items_to_polygon_shape_transform.cpp#L204
170  CGENERICCONTAINER2D *aDstContainer,
171  PCB_LAYER_ID aLayerId,
172  int aInflateValue )
173 {
174  std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert
175  EDGE_MODULE* outline;
176 
177  for( auto item : aModule->GraphicalItems() )
178  {
179  switch( item->Type() )
180  {
181  case PCB_MODULE_TEXT_T:
182  {
183  TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );
184 
185  if( text->GetLayer() == aLayerId && text->IsVisible() )
186  texts.push_back( text );
187  }
188  break;
189 
190 
191  case PCB_MODULE_EDGE_T:
192  {
193  outline = (EDGE_MODULE*) item;
194 
195  if( outline->GetLayer() != aLayerId )
196  break;
197 
199  aDstContainer,
200  aLayerId, 0 );
201  }
202  break;
203 
204  default:
205  break;
206  }
207  }
208 
209  // Convert texts sur modules
210  if( aModule->Reference().GetLayer() == aLayerId && aModule->Reference().IsVisible() )
211  texts.push_back( &aModule->Reference() );
212 
213  if( aModule->Value().GetLayer() == aLayerId && aModule->Value().IsVisible() )
214  texts.push_back( &aModule->Value() );
215 
216  s_boardItem = (const BOARD_ITEM *)&aModule->Value();
217  s_dstcontainer = aDstContainer;
219 
220  for( TEXTE_MODULE* text : texts )
221  {
222  s_textWidth = text->GetEffectiveTextPenWidth() + ( 2 * aInflateValue );
223  wxSize size = text->GetTextSize();
224  bool forceBold = true;
225  int penWidth = 0; // force max width for bold
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(), penWidth, text->IsItalic(),
232  forceBold, addTextSegmToContainer );
233  }
234 }
235 
236 
237 void BOARD_ADAPTER::createNewTrack( const TRACK* aTrack, CGENERICCONTAINER2D *aDstContainer,
238  int aClearanceValue )
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  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius, *aTrack ) );
249  }
250  break;
251 
252  case PCB_ARC_T:
253  {
254  const ARC* arc = static_cast<const ARC*>( aTrack );
255  VECTOR2D center( arc->GetCenter() );
256  double arc_angle = arc->GetAngle();
257  double radius = arc->GetRadius();
258  int arcsegcount = GetArcToSegmentCount( radius, Millimeter2iu( 0.005), arc_angle/10 );
259  int circlesegcount;
260 
261  // We need a circle to segment count. However, the arc angle can be small, and the
262  // radius very big. so we calculate a reasonable value for circlesegcount.
263  if( arcsegcount <= 1 ) // The arc will be approximated by a segment
264  circlesegcount = 1;
265  else
266  {
267  double cnt = arcsegcount * 3600/std::abs( arc_angle );
268 
269  #define SEG_CNT_MAX 128
270  if( cnt < SEG_CNT_MAX )
271  {
272  circlesegcount = (int)cnt;
273 
274  if( circlesegcount == 0 )
275  circlesegcount = 1;
276  }
277  else
278  circlesegcount = SEG_CNT_MAX;
279  }
280 
281  TransformArcToSegments( wxPoint( center.x, center.y ), arc->GetStart(),
282  arc_angle, circlesegcount,
283  arc->GetWidth() + 2 * aClearanceValue, aDstContainer,
284  *arc );
285  }
286  break;
287 
288  case PCB_TRACE_T: // Track is a usual straight segment
289  {
290  SFVEC2F end3DU ( aTrack->GetEnd().x * m_biuTo3Dunits,
291  -aTrack->GetEnd().y * m_biuTo3Dunits );
292 
293  // Cannot add segments that have the same start and end point
294  if( Is_segment_a_circle( start3DU, end3DU ) )
295  {
296  const float radius = ((aTrack->GetWidth() / 2) + aClearanceValue) * m_biuTo3Dunits;
297 
298  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius, *aTrack ) );
299  }
300  else
301  {
302  const float width = (aTrack->GetWidth() + 2 * aClearanceValue ) * m_biuTo3Dunits;
303 
304  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, width, *aTrack ) );
305  }
306  }
307  break;
308 
309  default:
310  break;
311  }
312 }
313 
314 
316  CGENERICCONTAINER2D *aDstContainer,
317  wxSize aClearanceValue ) const
318 {
319  SHAPE_POLY_SET poly;
320 
321  if( aClearanceValue.x != aClearanceValue.y )
322  {
323  // Our shape-based builder can't handle differing x:y clearance values (which
324  // get generated when relative paste margin is used with an oblong pad). So
325  // we fake a larger pad and run the general-purpose polygon builder on it.
326  D_PAD dummy( *aPad );
327  dummy.SetSize( aPad->GetSize() + aClearanceValue + aClearanceValue );
328  dummy.TransformShapeWithClearanceToPolygon( poly, 0 );
329  }
330  else
331  {
332  auto padShapes = std::static_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() );
333  for( const SHAPE* shape : padShapes->Shapes() )
334  {
335  switch( shape->Type() )
336  {
337  case SH_SEGMENT:
338  {
339  const SHAPE_SEGMENT* seg = (SHAPE_SEGMENT*) shape;
340  const SFVEC2F start3DU( seg->GetSeg().A.x * m_biuTo3Dunits,
341  -seg->GetSeg().A.y * m_biuTo3Dunits );
342  const SFVEC2F end3DU ( seg->GetSeg().B.x * m_biuTo3Dunits,
343  -seg->GetSeg().B.y * m_biuTo3Dunits );
344  const int width = seg->GetWidth() + aClearanceValue.x * 2;
345 
346  // Cannot add segments that have the same start and end point
347  if( Is_segment_a_circle( start3DU, end3DU ) )
348  {
349  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
350  ( width / 2) * m_biuTo3Dunits,
351  *aPad ) );
352  }
353  else
354  {
355  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
356  width * m_biuTo3Dunits,
357  *aPad ) );
358  }
359  }
360  break;
361 
362  case SH_CIRCLE:
363  {
364  const SHAPE_CIRCLE* circle = (SHAPE_CIRCLE*) shape;
365  const int radius = circle->GetRadius() + aClearanceValue.x;
366  const SFVEC2F center( circle->GetCenter().x * m_biuTo3Dunits,
367  -circle->GetCenter().y * m_biuTo3Dunits );
368 
369  aDstContainer->Add( new CFILLEDCIRCLE2D( center, radius * m_biuTo3Dunits, *aPad ) );
370  }
371  break;
372 
373  case SH_RECT:
374  {
375  SHAPE_RECT* rect = (SHAPE_RECT*) shape;
376 
377  poly.NewOutline();
378  poly.Append( rect->GetPosition() );
379  poly.Append( rect->GetPosition().x + rect->GetSize().x, rect->GetPosition().y );
380  poly.Append( rect->GetPosition() + rect->GetSize() );
381  poly.Append( rect->GetPosition().x, rect->GetPosition().y + rect->GetSize().y );
382  }
383  break;
384 
385  case SH_SIMPLE:
386  poly.AddOutline( static_cast<const SHAPE_SIMPLE*>( shape )->Vertices() );
387  break;
388 
389  case SH_POLY_SET:
390  poly = *(SHAPE_POLY_SET*) shape;
391  break;
392 
393  default:
394  wxFAIL_MSG( "BOARD_ADAPTER::createNewPadWithClearance no implementation for "
395  + SHAPE_TYPE_asString( shape->Type() ) );
396  break;
397  }
398  }
399  }
400 
401  if( !poly.IsEmpty() )
402  {
403  if( aClearanceValue.x )
404  poly.Inflate( aClearanceValue.x, 32 );
405 
406  // Add the PAD polygon
407  Convert_shape_line_polygon_to_triangles( poly, *aDstContainer, m_biuTo3Dunits, *aPad );
408  }
409 }
410 
411 
412 COBJECT2D *BOARD_ADAPTER::createNewPadDrill( const D_PAD* aPad, int aInflateValue )
413 {
414  wxSize drillSize = aPad->GetDrillSize();
415 
416  if( !drillSize.x || !drillSize.y )
417  {
418  wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createNewPadDrill - found an invalid pad" ) );
419  return NULL;
420  }
421 
422  if( drillSize.x == drillSize.y ) // usual round hole
423  {
424  const int radius = (drillSize.x / 2) + aInflateValue;
425 
426  const SFVEC2F center( aPad->GetPosition().x * m_biuTo3Dunits,
427  -aPad->GetPosition().y * m_biuTo3Dunits );
428 
429  return new CFILLEDCIRCLE2D( center, radius * m_biuTo3Dunits, *aPad );
430 
431  }
432  else // Oblong hole
433  {
434  const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
435  float width = seg->GetWidth() + aInflateValue * 2;
436 
437  SFVEC2F start3DU( seg->GetSeg().A.x * m_biuTo3Dunits,
438  -seg->GetSeg().A.y * m_biuTo3Dunits );
439 
440  SFVEC2F end3DU ( seg->GetSeg().B.x * m_biuTo3Dunits,
441  -seg->GetSeg().B.y * m_biuTo3Dunits );
442 
443  return new CROUNDSEGMENT2D( start3DU, end3DU, width * m_biuTo3Dunits, *aPad );
444  }
445 
446  return NULL;
447 }
448 
449 
451  CGENERICCONTAINER2D *aDstContainer,
452  PCB_LAYER_ID aLayerId,
453  int aInflateValue,
454  bool aSkipNPTHPadsWihNoCopper )
455 {
456  wxSize margin;
457 
458  for( auto pad : aModule->Pads() )
459  {
460  if( !pad->IsOnLayer( aLayerId ) )
461  continue;
462 
463  // NPTH pads are not drawn on layers if the
464  // shape size and pos is the same as their hole:
465  if( aSkipNPTHPadsWihNoCopper && (pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED) )
466  {
467  if( (pad->GetDrillSize() == pad->GetSize()) &&
468  (pad->GetOffset() == wxPoint( 0, 0 )) )
469  {
470  switch( pad->GetShape() )
471  {
472  case PAD_SHAPE_CIRCLE:
473  if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
474  continue;
475  break;
476 
477  case PAD_SHAPE_OVAL:
478  if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
479  continue;
480  break;
481 
482  default:
483  break;
484  }
485  }
486  }
487 
488  switch( aLayerId )
489  {
490  case F_Mask:
491  case B_Mask:
492  margin.x = margin.y = pad->GetSolderMaskMargin() + aInflateValue;
493  break;
494 
495  case F_Paste:
496  case B_Paste:
497  margin = pad->GetSolderPasteMargin();
498  margin.x += aInflateValue;
499  margin.y += aInflateValue;
500  break;
501 
502  default:
503  margin.x = margin.y = aInflateValue;
504  break;
505  }
506 
507  createNewPadWithClearance( pad, aDstContainer, margin );
508  }
509 }
510 
511 // based on TransformArcToPolygon function from
512 // common/convert_basic_shapes_to_polygon.cpp
514  const wxPoint &aStart,
515  double aArcAngle,
516  int aCircleToSegmentsCount,
517  int aWidth,
518  CGENERICCONTAINER2D *aDstContainer,
519  const BOARD_ITEM &aBoardItem )
520 {
521  wxPoint arc_start, arc_end;
522  int delta = 3600 / aCircleToSegmentsCount; // rotate angle in 0.1 degree
523 
524  arc_end = arc_start = aStart;
525 
526  if( aArcAngle != 3600 )
527  {
528  RotatePoint( &arc_end, aCentre, -aArcAngle );
529  }
530 
531  if( aArcAngle < 0 )
532  {
533  std::swap( arc_start, arc_end );
534  aArcAngle = -aArcAngle;
535  }
536 
537  // Compute the ends of segments and creates poly
538  wxPoint curr_end = arc_start;
539  wxPoint curr_start = arc_start;
540 
541  for( int ii = delta; ii < aArcAngle; ii += delta )
542  {
543  curr_end = arc_start;
544  RotatePoint( &curr_end, aCentre, -ii );
545 
546  const SFVEC2F start3DU( curr_start.x * m_biuTo3Dunits, -curr_start.y * m_biuTo3Dunits );
547  const SFVEC2F end3DU ( curr_end.x * m_biuTo3Dunits, -curr_end.y * m_biuTo3Dunits );
548 
549  if( Is_segment_a_circle( start3DU, end3DU ) )
550  {
551  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
552  ( aWidth / 2 ) * m_biuTo3Dunits,
553  aBoardItem ) );
554  }
555  else
556  {
557  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
558  aWidth * m_biuTo3Dunits,
559  aBoardItem ) );
560  }
561 
562  curr_start = curr_end;
563  }
564 
565  if( curr_end != arc_end )
566  {
567  const SFVEC2F start3DU( curr_end.x * m_biuTo3Dunits, -curr_end.y * m_biuTo3Dunits );
568  const SFVEC2F end3DU ( arc_end.x * m_biuTo3Dunits, -arc_end.y * m_biuTo3Dunits );
569 
570  if( Is_segment_a_circle( start3DU, end3DU ) )
571  {
572  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
573  ( aWidth / 2 ) * m_biuTo3Dunits,
574  aBoardItem ) );
575  }
576  else
577  {
578  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU,
579  end3DU,
580  aWidth * m_biuTo3Dunits,
581  aBoardItem ) );
582  }
583  }
584 }
585 
586 // Based on
587 // TransformShapeWithClearanceToPolygon
588 // board_items_to_polygon_shape_transform.cpp#L431
590  CGENERICCONTAINER2D *aDstContainer,
591  PCB_LAYER_ID aLayerId,
592  int aClearanceValue )
593 {
594  // The full width of the lines to create
595  // The extra 1 protects the inner/outer radius values from degeneracy
596  const int linewidth = aDrawSegment->GetWidth() + (2 * aClearanceValue) + 1;
597 
598  switch( aDrawSegment->GetShape() )
599  {
600  case S_CIRCLE:
601  {
602  const SFVEC2F center3DU( aDrawSegment->GetCenter().x * m_biuTo3Dunits,
603  -aDrawSegment->GetCenter().y * m_biuTo3Dunits );
604 
605  float inner_radius = ( aDrawSegment->GetRadius() - linewidth / 2 ) * m_biuTo3Dunits;
606  float outer_radius = ( aDrawSegment->GetRadius() + linewidth / 2 ) * m_biuTo3Dunits;
607 
608  if( inner_radius < 0 )
609  inner_radius = 0;
610 
611  if( aDrawSegment->GetWidth() > 0 )
612  aDstContainer->Add( new CRING2D( center3DU, inner_radius, outer_radius, *aDrawSegment ) );
613  else
614  aDstContainer->Add( new CFILLEDCIRCLE2D( center3DU, outer_radius, *aDrawSegment ) );
615  }
616  break;
617 
618  case S_RECT:
619  {
620  if( aDrawSegment->GetWidth() > 0 )
621  {
622  std::vector<wxPoint> pts;
623  aDrawSegment->GetRectCorners( &pts );
624 
625  const SFVEC2F topLeft3DU( pts[0].x * m_biuTo3Dunits, -pts[0].y * m_biuTo3Dunits );
626  const SFVEC2F topRight3DU( pts[1].x * m_biuTo3Dunits, -pts[1].y * m_biuTo3Dunits );
627  const SFVEC2F botRight3DU( pts[2].x * m_biuTo3Dunits, -pts[2].y * m_biuTo3Dunits );
628  const SFVEC2F botLeft3DU( pts[3].x * m_biuTo3Dunits, -pts[3].y * m_biuTo3Dunits );
629 
630  aDstContainer->Add( new CROUNDSEGMENT2D( topLeft3DU, topRight3DU,
631  linewidth * m_biuTo3Dunits,
632  *aDrawSegment ) );
633  aDstContainer->Add( new CROUNDSEGMENT2D( topRight3DU, botRight3DU,
634  linewidth * m_biuTo3Dunits,
635  *aDrawSegment ) );
636  aDstContainer->Add( new CROUNDSEGMENT2D( botRight3DU, botLeft3DU,
637  linewidth * m_biuTo3Dunits,
638  *aDrawSegment ) );
639  aDstContainer->Add( new CROUNDSEGMENT2D( botLeft3DU, topLeft3DU,
640  linewidth * m_biuTo3Dunits,
641  *aDrawSegment ) );
642  }
643  else
644  {
645  SHAPE_POLY_SET polyList;
646 
647  aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aClearanceValue );
648 
649  polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
650 
651  Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits,
652  *aDrawSegment );
653  }
654  }
655  break;
656 
657  case S_ARC:
658  {
659  const unsigned int nr_segments =
660  GetNrSegmentsCircle( aDrawSegment->GetBoundingBox().GetSizeMax() );
661 
662  TransformArcToSegments( aDrawSegment->GetCenter(),
663  aDrawSegment->GetArcStart(),
664  aDrawSegment->GetAngle(),
665  nr_segments,
666  aDrawSegment->GetWidth(),
667  aDstContainer,
668  *aDrawSegment );
669  }
670  break;
671 
672  case S_SEGMENT:
673  {
674  const SFVEC2F start3DU( aDrawSegment->GetStart().x * m_biuTo3Dunits,
675  -aDrawSegment->GetStart().y * m_biuTo3Dunits );
676 
677  const SFVEC2F end3DU ( aDrawSegment->GetEnd().x * m_biuTo3Dunits,
678  -aDrawSegment->GetEnd().y * m_biuTo3Dunits );
679 
680  if( Is_segment_a_circle( start3DU, end3DU ) )
681  {
682  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
683  ( linewidth / 2 ) * m_biuTo3Dunits,
684  *aDrawSegment ) );
685  }
686  else
687  {
688  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
689  linewidth * m_biuTo3Dunits,
690  *aDrawSegment ) );
691  }
692  }
693  break;
694 
695  case S_CURVE:
696  case S_POLYGON:
697  {
698  SHAPE_POLY_SET polyList;
699 
700  aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aClearanceValue );
701 
702  polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
703 
704  if( polyList.IsEmpty() ) // Just for caution
705  break;
706 
707  Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits,
708  *aDrawSegment );
709  }
710  break;
711 
712  default:
713  wxFAIL_MSG( "BOARD_ADAPTER::AddShapeWithClearanceToContainer no implementation for "
714  + STROKE_T_asString( aDrawSegment->GetShape() ) );
715  break;
716  }
717 }
718 
719 
720 // Based on
721 // TransformSolidAreasShapesToPolygonSet
722 // board_items_to_polygon_shape_transform.cpp
724  CGENERICCONTAINER2D *aDstContainer,
725  PCB_LAYER_ID aLayerId )
726 {
727  // Copy the polys list because we have to simplify it
728  SHAPE_POLY_SET polyList = SHAPE_POLY_SET( aZoneContainer->GetFilledPolysList( aLayerId ) );
729 
730  // This convert the poly in outline and holes
731  Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits,
732  *aZoneContainer );
733 
734  // add filled areas outlines, which are drawn with thick lines segments
735  // but only if filled polygons outlines have thickness
736  if( !aZoneContainer->GetFilledPolysUseThickness() )
737  return;
738 
739  float line_thickness = aZoneContainer->GetMinThickness() * m_biuTo3Dunits;
740 
741  for( int i = 0; i < polyList.OutlineCount(); ++i )
742  {
743  // Add outline
744  const SHAPE_LINE_CHAIN& pathOutline = polyList.COutline( i );
745 
746  for( int j = 0; j < pathOutline.PointCount(); ++j )
747  {
748  const VECTOR2I& a = pathOutline.CPoint( j );
749  const VECTOR2I& b = pathOutline.CPoint( j + 1 );
750 
751  SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits );
752  SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits );
753 
754  if( Is_segment_a_circle( start3DU, end3DU ) )
755  {
756  float radius = line_thickness/2;
757 
758  if( radius > 0.0 ) // degenerated circles crash 3D viewer
759  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius,
760  *aZoneContainer ) );
761  }
762  else
763  {
764  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, line_thickness,
765  *aZoneContainer ) );
766  }
767  }
768 
769  // Add holes (of the poly, ie: the open parts) for this outline
770  for( int h = 0; h < polyList.HoleCount( i ); ++h )
771  {
772  const SHAPE_LINE_CHAIN& pathHole = polyList.CHole( i, h );
773 
774  for( int j = 0; j < pathHole.PointCount(); j++ )
775  {
776  const VECTOR2I& a = pathHole.CPoint( j );
777  const VECTOR2I& b = pathHole.CPoint( j + 1 );
778 
779  SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits );
780  SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits );
781 
782  if( Is_segment_a_circle( start3DU, end3DU ) )
783  {
784  float radius = line_thickness/2;
785 
786  if( radius > 0.0 ) // degenerated circles crash 3D viewer
787  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius,
788  *aZoneContainer ) );
789  }
790  else
791  {
792  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, line_thickness,
793  *aZoneContainer ) );
794  }
795  }
796  }
797  }
798 }
799 
800 
801 
803  CGENERICCONTAINER2D *aDstContainer,
804  int aWidth )
805 {
806  if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring
807  {
808  const SFVEC2F center3DU( aPad->ShapePos().x * m_biuTo3Dunits,
809  -aPad->ShapePos().y * m_biuTo3Dunits );
810 
811  const int radius = aPad->GetSize().x / 2;
812  const float inner_radius = ( radius - aWidth / 2 ) * m_biuTo3Dunits;
813  const float outer_radius = ( radius + aWidth / 2 ) * m_biuTo3Dunits;
814 
815  aDstContainer->Add( new CRING2D( center3DU, inner_radius, outer_radius, *aPad ) );
816 
817  return;
818  }
819 
820  // For other shapes, add outlines as thick segments in polygon buffer
821  const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
822  const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
823 
824  for( int j = 0; j < path.PointCount(); j++ )
825  {
826  const VECTOR2I& a = path.CPoint( j );
827  const VECTOR2I& b = path.CPoint( j + 1 );
828 
829  SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits );
830  SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits );
831 
832  if( Is_segment_a_circle( start3DU, end3DU ) )
833  {
834  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, ( aWidth / 2 ) * m_biuTo3Dunits,
835  *aPad ) );
836  }
837  else
838  {
839  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, aWidth * m_biuTo3Dunits,
840  *aPad ) );
841  }
842  }
843 }
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
Definition: common.cpp:341
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
wxPoint GetArcStart() const
TEXTE_MODULE & Reference()
Definition: class_module.h:485
int OutlineCount() const
Returns the number of outlines in the set
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:200
bool IsMirrored() const
Definition: eda_text.h:189
int GetWidth() const
TEXTE_PCB class definition.
int GetRadius() const
Definition: shape_circle.h:94
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
wxPoint m_crossBarF
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
#define SEG_CNT_MAX
wxPoint m_arrowD1F
wxPoint GetPosition() const override
Definition: class_pad.h:165
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aError=ARC_HIGH_DEF, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the draw segment to a closed polygon Used in fi...
const wxPoint & GetStart() const
Definition: class_track.h:118
const SHAPE_SEGMENT * GetEffectiveHoleShape() const
Function GetEffectiveHoleShape Returns a list of SHAPE objects representing the pad's hole.
Definition: class_pad.cpp:239
STROKE_T GetShape() const
bool IsVisible() const
Definition: eda_text.h:186
polygon (not yet used for tracks, but could be in microwave apps)
void AddGraphicsShapesWithClearanceToContainer(const MODULE *aModule, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aInflateValue)
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
PADS & Pads()
Definition: class_module.h:173
double GetTextAngle() const
Definition: eda_text.h:174
bool GetFilledPolysUseThickness() const
Definition: class_zone.h:672
const SHAPE_POLY_SET & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Function GetFilledPolysList returns a reference to the list of filled polygons.
Definition: class_zone.h:613
class ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
usual segment : line with rounded ends
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
const VECTOR2I GetCenter() const
Definition: shape_circle.h:99
wxPoint m_featureLineDF
Definition: color4d.h:44
DRAWINGS & GraphicalItems()
Definition: class_module.h:183
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
void Inflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Performs outline inflation/deflation.
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
int PointCount() const
Function PointCount()
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
void buildPadShapeThickOutlineAsSegments(const D_PAD *aPad, CGENERICCONTAINER2D *aDstContainer, int aWidth)
const SEG & GetSeg() const
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
void AddShapeWithClearanceToContainer(const TEXTE_PCB *aTextPCB, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aClearanceValue)
int GetEffectiveTextPenWidth(int aDefaultWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultWidth.
Definition: eda_text.cpp:157
static int s_textWidth
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon() const
Definition: class_pad.cpp:216
const VECTOR2I GetSize() const
Function GetSize()
Definition: shape_rect.h:121
wxPoint m_featureLineGO
bool IsItalic() const
Definition: eda_text.h:180
void TransformArcToSegments(const wxPoint &aCentre, const wxPoint &aStart, double aArcAngle, int aCircleToSegmentsCount, int aWidth, CGENERICCONTAINER2D *aDstContainer, const BOARD_ITEM &aBoardItem)
const VECTOR2I & CPoint(int aIndex) const
Function Point()
segment with non rounded ends
PCB_LAYER_ID
A quick note on layer IDs:
unsigned int GetNrSegmentsCircle(float aDiameter3DU) const
GetNrSegmentsCircle.
bool Is_segment_a_circle(const SFVEC2F &aStart, const SFVEC2F &aEnd)
Segment_is_a_circle - check if segment start and end is very close to each other should used to check...
Footprint text class description.
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:199
glm::vec2 SFVEC2F
Definition: xv3d_types.h:45
#define NULL
void AddPadsShapesWithClearanceToContainer(const MODULE *aModule, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aInflateValue, bool aSkipNPTHPadsWihNoCopper)
static float s_biuTo3Dunits
SHAPE_POLY_SET.
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:484
const VECTOR2I & GetPosition() const
Function GetPosition()
Definition: shape_rect.h:111
const wxSize & GetTextSize() const
Definition: eda_text.h:239
Arcs (with rounded ends)
wxPoint m_arrowG1F
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
wxPoint m_arrowD2F
wxPoint m_arrowG2F
static CGENERICCONTAINER2D * s_dstcontainer
double m_biuTo3Dunits
Normalization scale to convert board internal units to 3D units to normalize 3D units between -1....
static wxString SHAPE_TYPE_asString(SHAPE_TYPE a)
Definition: shape.h:51
virtual wxPoint GetCenter() const
Function GetCenter()
a few functions useful in geometry calculations.
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
SHAPE.
Definition: shape.h:74
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const override
Function GetEffectiveShape Some pad shapes can be complex (rounded/chamfered rectangle),...
Definition: class_pad.cpp:225
Bezier Curve.
double GetRadius() const
int NewOutline()
Creates a new empty polygon in the set and returns its index
int HoleCount(int aOutline) const
Returns the number of holes in a given outline
int GetWidth() const
bool IsMultilineAllowed() const
Definition: eda_text.h:197
line chain (polyline)
Definition: shape.h:44
Pad object description.
void GRText(wxDC *aDC, const wxPoint &aPos, COLOR4D aColor, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, void(*aCallback)(int x0, int y0, int xf, int yf, void *aData), void *aCallbackData, PLOTTER *aPlotter)
Function GRText Draw a graphic text (like module texts)
Definition: gr_text.cpp:134
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index
void Add(COBJECT2D *aObject)
Definition: ccontainer2d.h:52
double GetAngle() const
static wxString STROKE_T_asString(STROKE_T a)
double GetAngle() const
simple polygon
Definition: shape.h:46
int GetWidth() const
Definition: class_track.h:112
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
SHAPE_LINE_CHAIN.
void createNewPadWithClearance(const D_PAD *aPad, CGENERICCONTAINER2D *aDstContainer, wxSize aClearanceValue) const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
TEXTE_PCB & Text()
const wxSize & GetDrillSize() const
Definition: class_pad.h:230
VECTOR2I A
Definition: seg.h:47
wxPoint ShapePos() const
Definition: class_pad.cpp:563
void AddSolidAreasShapesToContainer(const ZONE_CONTAINER *aZoneContainer, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId)
COBJECT2D * createNewPadDrill(const D_PAD *aPad, int aInflateValue)
int GetMinThickness() const
Definition: class_zone.h:206
const wxPoint & GetEnd() const
Definition: class_track.h:115
void GetLinePositions(std::vector< wxPoint > &aPositions, int aLineCount) const
Populate aPositions with the position of each line of a multiline text, according to the vertical jus...
Definition: eda_text.cpp:423
void createNewTrack(const TRACK *aTrack, CGENERICCONTAINER2D *aDstContainer, int aClearanceValue)
void addTextSegmToContainer(int x0, int y0, int xf, int yf, void *aData)
const wxPoint & GetTextPos() const
Definition: eda_text.h:248
wxPoint m_crossBarO
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
Definition: shape.h:41
PAD_SHAPE_T GetShape() const
Definition: class_pad.h:157
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
static const BOARD_ITEM * s_boardItem
const wxSize & GetSize() const
Definition: class_pad.h:224
EDGE_MODULE class definition.
void GetRectCorners(std::vector< wxPoint > *pts) const
int GetWidth() const
static constexpr int Millimeter2iu(double mm)
wxPoint m_featureLineDO
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
circle
Definition: shape.h:45
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
int GetSizeMax() const
GetSizeMax.
Definition: eda_rect.h:109
DIMENSION.
void Convert_shape_line_polygon_to_triangles(SHAPE_POLY_SET &aPolyList, CGENERICCONTAINER2D &aDstContainer, float aBiuTo3DunitsScale, const BOARD_ITEM &aBoardItem)
wxPoint GetCenter() const override
Function GetCenter()
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
axis-aligned rectangle
Definition: shape.h:42
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:99
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
wxPoint m_featureLineGF
VECTOR2I B
Definition: seg.h:48