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 <pcb_text.h>
42 #include <fp_shape.h>
43 #include <class_zone.h>
44 #include <kicad_string.h>
45 #include <fp_text.h>
47 #include <trigo.h>
48 #include <geometry/shape_segment.h>
50 #include <geometry/shape_circle.h>
51 #include <geometry/shape_rect.h>
52 #include <geometry/shape_simple.h>
53 #include <gr_text.h>
54 #include <utility>
55 #include <vector>
56 
57 
58 // These variables are parameters used in addTextSegmToContainer.
59 // But addTextSegmToContainer is a call-back function,
60 // so we cannot send them as arguments.
61 static int s_textWidth;
63 static float s_biuTo3Dunits;
64 static const BOARD_ITEM *s_boardItem = NULL;
65 
66 // This is a call back function, used by GRText to draw the 3D text shape:
67 void addTextSegmToContainer( int x0, int y0, int xf, int yf, void* aData )
68 {
69  const SFVEC2F start3DU( x0 * s_biuTo3Dunits, -y0 * s_biuTo3Dunits );
70  const SFVEC2F end3DU ( xf * s_biuTo3Dunits, -yf * s_biuTo3Dunits );
71 
72  if( Is_segment_a_circle( start3DU, end3DU ) )
73  s_dstcontainer->Add( new CFILLEDCIRCLE2D( start3DU,
74  ( s_textWidth / 2 ) * s_biuTo3Dunits,
75  *s_boardItem) );
76  else
77  s_dstcontainer->Add( new CROUNDSEGMENT2D( start3DU,
78  end3DU,
80  *s_boardItem ) );
81 }
82 
83 
84 // Based on
85 // void PCB_TEXT::TransformShapeWithClearanceToPolygon
86 // board_items_to_polygon_shape_transform.cpp
88  CGENERICCONTAINER2D *aDstContainer,
89  PCB_LAYER_ID aLayerId,
90  int aClearanceValue )
91 {
92  wxSize size = aText->GetTextSize();
93 
94  if( aText->IsMirrored() )
95  size.x = -size.x;
96 
97  s_boardItem = (const BOARD_ITEM *) &aText;
98  s_dstcontainer = aDstContainer;
99  s_textWidth = aText->GetEffectiveTextPenWidth() + ( 2 * aClearanceValue );
101 
102  // not actually used, but needed by GRText
103  const COLOR4D dummy_color = COLOR4D::BLACK;
104  bool forceBold = true;
105  int penWidth = 0; // force max width for bold
106 
107  if( aText->IsMultilineAllowed() )
108  {
109  wxArrayString strings_list;
110  wxStringSplit( aText->GetShownText(), strings_list, '\n' );
111  std::vector<wxPoint> positions;
112  positions.reserve( strings_list.Count() );
113  aText->GetLinePositions( positions, strings_list.Count());
114 
115  for( unsigned ii = 0; ii < strings_list.Count(); ++ii )
116  {
117  wxString txt = strings_list.Item( ii );
118 
119  GRText( nullptr, positions[ii], dummy_color, txt, aText->GetTextAngle(), size,
120  aText->GetHorizJustify(), aText->GetVertJustify(), penWidth,
121  aText->IsItalic(), forceBold, addTextSegmToContainer );
122  }
123  }
124  else
125  {
126  GRText( nullptr, aText->GetTextPos(), dummy_color, aText->GetShownText(),
127  aText->GetTextAngle(), size, aText->GetHorizJustify(), aText->GetVertJustify(),
128  penWidth, aText->IsItalic(), forceBold, addTextSegmToContainer );
129  }
130 }
131 
132 
134  CGENERICCONTAINER2D *aDstContainer,
135  PCB_LAYER_ID aLayerId,
136  int aClearanceValue )
137 {
138  AddShapeWithClearanceToContainer(&aDimension->Text(), aDstContainer, aLayerId, aClearanceValue);
139 
140  const int linewidth = aDimension->GetLineThickness() + (2 * aClearanceValue);
141 
142  for( const std::shared_ptr<SHAPE>& shape : aDimension->GetShapes() )
143  {
144  switch( shape->Type() )
145  {
146  case SH_SEGMENT:
147  {
148  const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
149 
150  const SFVEC2F start3DU( seg.A.x * m_biuTo3Dunits,
151  -seg.A.y * m_biuTo3Dunits );
152 
153  const SFVEC2F end3DU ( seg.B.x * m_biuTo3Dunits,
154  -seg.B.y * m_biuTo3Dunits );
155 
156  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU,
157  end3DU,
158  linewidth * m_biuTo3Dunits,
159  *aDimension ) );
160  break;
161  }
162 
163  case SH_CIRCLE:
164  {
165  int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
166  int deltar = aDimension->GetLineThickness();
167 
168  SFVEC2F center( shape->Centre().x * m_biuTo3Dunits,
169  shape->Centre().y * m_biuTo3Dunits );
170 
171  aDstContainer->Add( new CRING2D( center, ( radius - deltar ) * m_biuTo3Dunits,
172  ( radius + deltar ) * m_biuTo3Dunits, *aDimension ) );
173 
174  break;
175  }
176 
177  default:
178  break;
179  }
180 
181  }
182 
183 }
184 
185 
186 // Based on
187 // void MODULE::TransformGraphicShapesWithClearanceToPolygonSet
188 // board_items_to_polygon_shape_transform.cpp#L204
190  CGENERICCONTAINER2D *aDstContainer,
191  PCB_LAYER_ID aLayerId,
192  int aInflateValue )
193 {
194  std::vector<FP_TEXT*> texts; // List of FP_TEXT to convert
195  FP_SHAPE* outline;
196 
197  for( BOARD_ITEM* item : aModule->GraphicalItems() )
198  {
199  switch( item->Type() )
200  {
201  case PCB_FP_TEXT_T:
202  {
203  FP_TEXT* text = static_cast<FP_TEXT*>( item );
204 
205  if( text->GetLayer() == aLayerId && text->IsVisible() )
206  texts.push_back( text );
207  }
208  break;
209 
210 
211  case PCB_FP_SHAPE_T:
212  {
213  outline = (FP_SHAPE*) item;
214 
215  if( outline->GetLayer() != aLayerId )
216  break;
217 
218  AddShapeWithClearanceToContainer( (const PCB_SHAPE*) outline, aDstContainer,
219  aLayerId, 0 );
220  }
221  break;
222 
223  default:
224  break;
225  }
226  }
227 
228  // Convert texts sur footprints
229  if( aModule->Reference().GetLayer() == aLayerId && aModule->Reference().IsVisible() )
230  texts.push_back( &aModule->Reference() );
231 
232  if( aModule->Value().GetLayer() == aLayerId && aModule->Value().IsVisible() )
233  texts.push_back( &aModule->Value() );
234 
235  s_boardItem = (const BOARD_ITEM *)&aModule->Value();
236  s_dstcontainer = aDstContainer;
238 
239  for( FP_TEXT* text : texts )
240  {
241  s_textWidth = text->GetEffectiveTextPenWidth() + ( 2 * aInflateValue );
242  wxSize size = text->GetTextSize();
243  bool forceBold = true;
244  int penWidth = 0; // force max width for bold
245 
246  if( text->IsMirrored() )
247  size.x = -size.x;
248 
249  GRText( NULL, text->GetTextPos(), BLACK, text->GetShownText(), text->GetDrawRotation(),
250  size, text->GetHorizJustify(), text->GetVertJustify(), penWidth, text->IsItalic(),
251  forceBold, addTextSegmToContainer );
252  }
253 }
254 
255 
256 void BOARD_ADAPTER::createNewTrack( const TRACK* aTrack, CGENERICCONTAINER2D *aDstContainer,
257  int aClearanceValue )
258 {
259  SFVEC2F start3DU( aTrack->GetStart().x * m_biuTo3Dunits,
260  -aTrack->GetStart().y * m_biuTo3Dunits ); // y coord is inverted
261 
262  switch( aTrack->Type() )
263  {
264  case PCB_VIA_T:
265  {
266  const float radius = ( ( aTrack->GetWidth() / 2 ) + aClearanceValue ) * m_biuTo3Dunits;
267  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius, *aTrack ) );
268  }
269  break;
270 
271  case PCB_ARC_T:
272  {
273  const ARC* arc = static_cast<const ARC*>( aTrack );
274  VECTOR2D center( arc->GetCenter() );
275  double arc_angle = arc->GetAngle();
276  double radius = arc->GetRadius();
277  int arcsegcount = GetArcToSegmentCount( radius, Millimeter2iu( 0.005), arc_angle/10 );
278  int circlesegcount;
279 
280  // We need a circle to segment count. However, the arc angle can be small, and the
281  // radius very big. so we calculate a reasonable value for circlesegcount.
282  if( arcsegcount <= 1 ) // The arc will be approximated by a segment
283  circlesegcount = 1;
284  else
285  {
286  double cnt = arcsegcount * 3600/std::abs( arc_angle );
287 
288  #define SEG_CNT_MAX 128
289  if( cnt < SEG_CNT_MAX )
290  {
291  circlesegcount = (int)cnt;
292 
293  if( circlesegcount == 0 )
294  circlesegcount = 1;
295  }
296  else
297  circlesegcount = SEG_CNT_MAX;
298  }
299 
300  TransformArcToSegments( wxPoint( center.x, center.y ), arc->GetStart(),
301  arc_angle, circlesegcount,
302  arc->GetWidth() + 2 * aClearanceValue, aDstContainer,
303  *arc );
304  }
305  break;
306 
307  case PCB_TRACE_T: // Track is a usual straight segment
308  {
309  SFVEC2F end3DU ( aTrack->GetEnd().x * m_biuTo3Dunits,
310  -aTrack->GetEnd().y * m_biuTo3Dunits );
311 
312  // Cannot add segments that have the same start and end point
313  if( Is_segment_a_circle( start3DU, end3DU ) )
314  {
315  const float radius = ((aTrack->GetWidth() / 2) + aClearanceValue) * m_biuTo3Dunits;
316 
317  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius, *aTrack ) );
318  }
319  else
320  {
321  const float width = (aTrack->GetWidth() + 2 * aClearanceValue ) * m_biuTo3Dunits;
322 
323  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, width, *aTrack ) );
324  }
325  }
326  break;
327 
328  default:
329  break;
330  }
331 }
332 
333 
335  CGENERICCONTAINER2D *aDstContainer,
336  PCB_LAYER_ID aLayer,
337  wxSize aClearanceValue ) const
338 {
339  SHAPE_POLY_SET poly;
340 
341  // Our shape-based builder can't handle negative or differing x:y clearance values (the
342  // former are common for solder paste whiel the later get generated when a relative paste
343  // margin is used with an oblong pad). So we apply this huge hack and fake a larger pad to
344  // run the general-purpose polygon builder on.
345  // Of course being a hack it falls down when dealing with custom shape pads (where the size
346  // is only the size of the anchor), so for those we punt and just use aClearanceValue.x.
347 
348  if( ( aClearanceValue.x < 0 || aClearanceValue.x != aClearanceValue.y )
349  && aPad->GetShape() != PAD_SHAPE_CUSTOM )
350  {
351  D_PAD dummy( *aPad );
352  dummy.SetSize( aPad->GetSize() + aClearanceValue + aClearanceValue );
353  dummy.TransformShapeWithClearanceToPolygon( poly, aLayer, 0, ARC_HIGH_DEF, ERROR_INSIDE );
354  aClearanceValue = { 0, 0 };
355  }
356  else
357  {
358  auto padShapes = std::static_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() );
359 
360  for( const SHAPE* shape : padShapes->Shapes() )
361  {
362  switch( shape->Type() )
363  {
364  case SH_SEGMENT:
365  {
366  const SHAPE_SEGMENT* seg = (SHAPE_SEGMENT*) shape;
367  const SFVEC2F start3DU( seg->GetSeg().A.x * m_biuTo3Dunits,
368  -seg->GetSeg().A.y * m_biuTo3Dunits );
369  const SFVEC2F end3DU ( seg->GetSeg().B.x * m_biuTo3Dunits,
370  -seg->GetSeg().B.y * m_biuTo3Dunits );
371  const int width = seg->GetWidth() + aClearanceValue.x * 2;
372 
373  // Cannot add segments that have the same start and end point
374  if( Is_segment_a_circle( start3DU, end3DU ) )
375  {
376  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
377  ( width / 2) * m_biuTo3Dunits,
378  *aPad ) );
379  }
380  else
381  {
382  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
383  width * m_biuTo3Dunits,
384  *aPad ) );
385  }
386  }
387  break;
388 
389  case SH_CIRCLE:
390  {
391  const SHAPE_CIRCLE* circle = (SHAPE_CIRCLE*) shape;
392  const int radius = circle->GetRadius() + aClearanceValue.x;
393  const SFVEC2F center( circle->GetCenter().x * m_biuTo3Dunits,
394  -circle->GetCenter().y * m_biuTo3Dunits );
395 
396  aDstContainer->Add( new CFILLEDCIRCLE2D( center, radius * m_biuTo3Dunits, *aPad ) );
397  }
398  break;
399 
400  case SH_RECT:
401  {
402  SHAPE_RECT* rect = (SHAPE_RECT*) shape;
403 
404  poly.NewOutline();
405  poly.Append( rect->GetPosition() );
406  poly.Append( rect->GetPosition().x + rect->GetSize().x, rect->GetPosition().y );
407  poly.Append( rect->GetPosition() + rect->GetSize() );
408  poly.Append( rect->GetPosition().x, rect->GetPosition().y + rect->GetSize().y );
409  }
410  break;
411 
412  case SH_SIMPLE:
413  poly.AddOutline( static_cast<const SHAPE_SIMPLE*>( shape )->Vertices() );
414  break;
415 
416  case SH_POLY_SET:
417  poly = *(SHAPE_POLY_SET*) shape;
418  break;
419 
420  default:
421  wxFAIL_MSG( "BOARD_ADAPTER::createNewPadWithClearance no implementation for "
422  + SHAPE_TYPE_asString( shape->Type() ) );
423  break;
424  }
425  }
426  }
427 
428  if( !poly.IsEmpty() )
429  {
430  if( aClearanceValue.x )
431  poly.Inflate( aClearanceValue.x, 32 );
432 
433  // Add the PAD polygon
434  Convert_shape_line_polygon_to_triangles( poly, *aDstContainer, m_biuTo3Dunits, *aPad );
435  }
436 }
437 
438 
439 COBJECT2D *BOARD_ADAPTER::createNewPadDrill( const D_PAD* aPad, int aInflateValue )
440 {
441  wxSize drillSize = aPad->GetDrillSize();
442 
443  if( !drillSize.x || !drillSize.y )
444  {
445  wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createNewPadDrill - found an invalid pad" ) );
446  return NULL;
447  }
448 
449  if( drillSize.x == drillSize.y ) // usual round hole
450  {
451  const int radius = (drillSize.x / 2) + aInflateValue;
452 
453  const SFVEC2F center( aPad->GetPosition().x * m_biuTo3Dunits,
454  -aPad->GetPosition().y * m_biuTo3Dunits );
455 
456  return new CFILLEDCIRCLE2D( center, radius * m_biuTo3Dunits, *aPad );
457 
458  }
459  else // Oblong hole
460  {
461  const SHAPE_SEGMENT* seg = aPad->GetEffectiveHoleShape();
462  float width = seg->GetWidth() + aInflateValue * 2;
463 
464  SFVEC2F start3DU( seg->GetSeg().A.x * m_biuTo3Dunits,
465  -seg->GetSeg().A.y * m_biuTo3Dunits );
466 
467  SFVEC2F end3DU ( seg->GetSeg().B.x * m_biuTo3Dunits,
468  -seg->GetSeg().B.y * m_biuTo3Dunits );
469 
470  return new CROUNDSEGMENT2D( start3DU, end3DU, width * m_biuTo3Dunits, *aPad );
471  }
472 
473  return NULL;
474 }
475 
476 
478  CGENERICCONTAINER2D *aDstContainer,
479  PCB_LAYER_ID aLayerId,
480  int aInflateValue,
481  bool aSkipNPTHPadsWihNoCopper,
482  bool aSkipPlatedPads,
483  bool aSkipNonPlatedPads )
484 {
485  for( D_PAD* pad : aModule->Pads() )
486  {
487  if( !pad->IsOnLayer( aLayerId ) )
488  continue;
489 
490  // Skip pad annulus when not connected on this layer (if removing is enabled)
491  if( !pad->FlashLayer( aLayerId ) && IsCopperLayer( aLayerId ) )
492  continue;
493 
494  // NPTH pads are not drawn on layers if the
495  // shape size and pos is the same as their hole:
496  if( aSkipNPTHPadsWihNoCopper && ( pad->GetAttribute() == PAD_ATTRIB_NPTH ) )
497  {
498  if( (pad->GetDrillSize() == pad->GetSize()) &&
499  (pad->GetOffset() == wxPoint( 0, 0 )) )
500  {
501  switch( pad->GetShape() )
502  {
503  case PAD_SHAPE_CIRCLE:
504  if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
505  continue;
506  break;
507 
508  case PAD_SHAPE_OVAL:
509  if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
510  continue;
511  break;
512 
513  default:
514  break;
515  }
516  }
517  }
518 
519  const bool isPlated = ( ( aLayerId == F_Cu ) && pad->FlashLayer( F_Mask ) ) ||
520  ( ( aLayerId == B_Cu ) && pad->FlashLayer( B_Mask ) );
521 
522  if( aSkipPlatedPads && isPlated )
523  continue;
524 
525  if( aSkipNonPlatedPads && !isPlated )
526  continue;
527 
528  wxSize margin( aInflateValue, aInflateValue );
529 
530  switch( aLayerId )
531  {
532  case F_Mask:
533  case B_Mask:
534  margin.x += pad->GetSolderMaskMargin();
535  margin.y += pad->GetSolderMaskMargin();
536  break;
537 
538  case F_Paste:
539  case B_Paste:
540  margin += pad->GetSolderPasteMargin();
541  break;
542 
543  default:
544  break;
545  }
546 
547  createNewPadWithClearance( pad, aDstContainer, aLayerId, margin );
548  }
549 }
550 
551 // based on TransformArcToPolygon function from
552 // common/convert_basic_shapes_to_polygon.cpp
553 void BOARD_ADAPTER::TransformArcToSegments( const wxPoint &aCentre,
554  const wxPoint &aStart,
555  double aArcAngle,
556  int aCircleToSegmentsCount,
557  int aWidth,
558  CGENERICCONTAINER2D *aDstContainer,
559  const BOARD_ITEM &aBoardItem )
560 {
561  wxPoint arc_start, arc_end;
562  int delta = 3600 / aCircleToSegmentsCount; // rotate angle in 0.1 degree
563 
564  arc_end = arc_start = aStart;
565 
566  if( aArcAngle != 3600 )
567  {
568  RotatePoint( &arc_end, aCentre, -aArcAngle );
569  }
570 
571  if( aArcAngle < 0 )
572  {
573  std::swap( arc_start, arc_end );
574  aArcAngle = -aArcAngle;
575  }
576 
577  // Compute the ends of segments and creates poly
578  wxPoint curr_end = arc_start;
579  wxPoint curr_start = arc_start;
580 
581  for( int ii = delta; ii < aArcAngle; ii += delta )
582  {
583  curr_end = arc_start;
584  RotatePoint( &curr_end, aCentre, -ii );
585 
586  const SFVEC2F start3DU( curr_start.x * m_biuTo3Dunits, -curr_start.y * m_biuTo3Dunits );
587  const SFVEC2F end3DU ( curr_end.x * m_biuTo3Dunits, -curr_end.y * m_biuTo3Dunits );
588 
589  if( Is_segment_a_circle( start3DU, end3DU ) )
590  {
591  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
592  ( aWidth / 2 ) * m_biuTo3Dunits,
593  aBoardItem ) );
594  }
595  else
596  {
597  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
598  aWidth * m_biuTo3Dunits,
599  aBoardItem ) );
600  }
601 
602  curr_start = curr_end;
603  }
604 
605  if( curr_end != arc_end )
606  {
607  const SFVEC2F start3DU( curr_end.x * m_biuTo3Dunits, -curr_end.y * m_biuTo3Dunits );
608  const SFVEC2F end3DU ( arc_end.x * m_biuTo3Dunits, -arc_end.y * m_biuTo3Dunits );
609 
610  if( Is_segment_a_circle( start3DU, end3DU ) )
611  {
612  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
613  ( aWidth / 2 ) * m_biuTo3Dunits,
614  aBoardItem ) );
615  }
616  else
617  {
618  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU,
619  end3DU,
620  aWidth * m_biuTo3Dunits,
621  aBoardItem ) );
622  }
623  }
624 }
625 
626 // Based on
627 // TransformShapeWithClearanceToPolygon
628 // board_items_to_polygon_shape_transform.cpp#L431
630  CGENERICCONTAINER2D *aDstContainer,
631  PCB_LAYER_ID aLayerId,
632  int aClearanceValue )
633 {
634  // The full width of the lines to create
635  // The extra 1 protects the inner/outer radius values from degeneracy
636  const int linewidth = aDrawSegment->GetWidth() + (2 * aClearanceValue) + 1;
637 
638  switch( aDrawSegment->GetShape() )
639  {
640  case S_CIRCLE:
641  {
642  const SFVEC2F center3DU( aDrawSegment->GetCenter().x * m_biuTo3Dunits,
643  -aDrawSegment->GetCenter().y * m_biuTo3Dunits );
644 
645  float inner_radius = ( aDrawSegment->GetRadius() - linewidth / 2 ) * m_biuTo3Dunits;
646  float outer_radius = ( aDrawSegment->GetRadius() + linewidth / 2 ) * m_biuTo3Dunits;
647 
648  if( inner_radius < 0 )
649  inner_radius = 0;
650 
651  if( aDrawSegment->GetWidth() > 0 )
652  aDstContainer->Add( new CRING2D( center3DU, inner_radius, outer_radius, *aDrawSegment ) );
653  else
654  aDstContainer->Add( new CFILLEDCIRCLE2D( center3DU, outer_radius, *aDrawSegment ) );
655  }
656  break;
657 
658  case S_RECT:
659  {
660  if( aDrawSegment->GetWidth() > 0 )
661  {
662  std::vector<wxPoint> pts = aDrawSegment->GetRectCorners();
663 
664  const SFVEC2F topLeft3DU( pts[0].x * m_biuTo3Dunits, -pts[0].y * m_biuTo3Dunits );
665  const SFVEC2F topRight3DU( pts[1].x * m_biuTo3Dunits, -pts[1].y * m_biuTo3Dunits );
666  const SFVEC2F botRight3DU( pts[2].x * m_biuTo3Dunits, -pts[2].y * m_biuTo3Dunits );
667  const SFVEC2F botLeft3DU( pts[3].x * m_biuTo3Dunits, -pts[3].y * m_biuTo3Dunits );
668 
669  aDstContainer->Add( new CROUNDSEGMENT2D( topLeft3DU, topRight3DU,
670  linewidth * m_biuTo3Dunits,
671  *aDrawSegment ) );
672  aDstContainer->Add( new CROUNDSEGMENT2D( topRight3DU, botRight3DU,
673  linewidth * m_biuTo3Dunits,
674  *aDrawSegment ) );
675  aDstContainer->Add( new CROUNDSEGMENT2D( botRight3DU, botLeft3DU,
676  linewidth * m_biuTo3Dunits,
677  *aDrawSegment ) );
678  aDstContainer->Add( new CROUNDSEGMENT2D( botLeft3DU, topLeft3DU,
679  linewidth * m_biuTo3Dunits,
680  *aDrawSegment ) );
681  }
682  else
683  {
684  SHAPE_POLY_SET polyList;
685 
686  aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aLayerId,
687  aClearanceValue,
688  ARC_HIGH_DEF, ERROR_INSIDE );
689 
690  polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
691 
692  Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits,
693  *aDrawSegment );
694  }
695  }
696  break;
697 
698  case S_ARC:
699  {
700  const unsigned int nr_segments =
701  GetNrSegmentsCircle( aDrawSegment->GetBoundingBox().GetSizeMax() );
702 
703  TransformArcToSegments( aDrawSegment->GetCenter(),
704  aDrawSegment->GetArcStart(),
705  aDrawSegment->GetAngle(),
706  nr_segments,
707  aDrawSegment->GetWidth(),
708  aDstContainer,
709  *aDrawSegment );
710  }
711  break;
712 
713  case S_SEGMENT:
714  {
715  const SFVEC2F start3DU( aDrawSegment->GetStart().x * m_biuTo3Dunits,
716  -aDrawSegment->GetStart().y * m_biuTo3Dunits );
717 
718  const SFVEC2F end3DU ( aDrawSegment->GetEnd().x * m_biuTo3Dunits,
719  -aDrawSegment->GetEnd().y * m_biuTo3Dunits );
720 
721  if( Is_segment_a_circle( start3DU, end3DU ) )
722  {
723  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU,
724  ( linewidth / 2 ) * m_biuTo3Dunits,
725  *aDrawSegment ) );
726  }
727  else
728  {
729  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU,
730  linewidth * m_biuTo3Dunits,
731  *aDrawSegment ) );
732  }
733  }
734  break;
735 
736  case S_CURVE:
737  case S_POLYGON:
738  {
739  SHAPE_POLY_SET polyList;
740 
741  aDrawSegment->TransformShapeWithClearanceToPolygon( polyList, aLayerId, aClearanceValue,
742  ARC_HIGH_DEF, ERROR_INSIDE );
743 
744  polyList.Simplify( SHAPE_POLY_SET::PM_FAST );
745 
746  if( polyList.IsEmpty() ) // Just for caution
747  break;
748 
749  Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits,
750  *aDrawSegment );
751  }
752  break;
753 
754  default:
755  wxFAIL_MSG( "BOARD_ADAPTER::AddShapeWithClearanceToContainer no implementation for "
756  + PCB_SHAPE_TYPE_T_asString( aDrawSegment->GetShape()) );
757  break;
758  }
759 }
760 
761 
762 // Based on
763 // TransformSolidAreasShapesToPolygonSet
764 // board_items_to_polygon_shape_transform.cpp
766  CGENERICCONTAINER2D *aDstContainer,
767  PCB_LAYER_ID aLayerId )
768 {
769  // Copy the polys list because we have to simplify it
770  SHAPE_POLY_SET polyList = SHAPE_POLY_SET( aZoneContainer->GetFilledPolysList( aLayerId ) );
771 
772  // This convert the poly in outline and holes
773  Convert_shape_line_polygon_to_triangles( polyList, *aDstContainer, m_biuTo3Dunits,
774  *aZoneContainer );
775 
776  // add filled areas outlines, which are drawn with thick lines segments
777  // but only if filled polygons outlines have thickness
778  if( !aZoneContainer->GetFilledPolysUseThickness() )
779  return;
780 
781  float line_thickness = aZoneContainer->GetMinThickness() * m_biuTo3Dunits;
782 
783  for( int i = 0; i < polyList.OutlineCount(); ++i )
784  {
785  // Add outline
786  const SHAPE_LINE_CHAIN& pathOutline = polyList.COutline( i );
787 
788  for( int j = 0; j < pathOutline.PointCount(); ++j )
789  {
790  const VECTOR2I& a = pathOutline.CPoint( j );
791  const VECTOR2I& b = pathOutline.CPoint( j + 1 );
792 
793  SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits );
794  SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits );
795 
796  if( Is_segment_a_circle( start3DU, end3DU ) )
797  {
798  float radius = line_thickness/2;
799 
800  if( radius > 0.0 ) // degenerated circles crash 3D viewer
801  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius,
802  *aZoneContainer ) );
803  }
804  else
805  {
806  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, line_thickness,
807  *aZoneContainer ) );
808  }
809  }
810 
811  // Add holes (of the poly, ie: the open parts) for this outline
812  for( int h = 0; h < polyList.HoleCount( i ); ++h )
813  {
814  const SHAPE_LINE_CHAIN& pathHole = polyList.CHole( i, h );
815 
816  for( int j = 0; j < pathHole.PointCount(); j++ )
817  {
818  const VECTOR2I& a = pathHole.CPoint( j );
819  const VECTOR2I& b = pathHole.CPoint( j + 1 );
820 
821  SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits );
822  SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits );
823 
824  if( Is_segment_a_circle( start3DU, end3DU ) )
825  {
826  float radius = line_thickness/2;
827 
828  if( radius > 0.0 ) // degenerated circles crash 3D viewer
829  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, radius,
830  *aZoneContainer ) );
831  }
832  else
833  {
834  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, line_thickness,
835  *aZoneContainer ) );
836  }
837  }
838  }
839  }
840 }
841 
842 
843 
845  CGENERICCONTAINER2D *aDstContainer,
846  int aWidth )
847 {
848  if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring
849  {
850  const SFVEC2F center3DU( aPad->ShapePos().x * m_biuTo3Dunits,
851  -aPad->ShapePos().y * m_biuTo3Dunits );
852 
853  const int radius = aPad->GetSize().x / 2;
854  const float inner_radius = ( radius - aWidth / 2 ) * m_biuTo3Dunits;
855  const float outer_radius = ( radius + aWidth / 2 ) * m_biuTo3Dunits;
856 
857  aDstContainer->Add( new CRING2D( center3DU, inner_radius, outer_radius, *aPad ) );
858 
859  return;
860  }
861 
862  // For other shapes, add outlines as thick segments in polygon buffer
863  const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
864  const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
865 
866  for( int j = 0; j < path.PointCount(); j++ )
867  {
868  const VECTOR2I& a = path.CPoint( j );
869  const VECTOR2I& b = path.CPoint( j + 1 );
870 
871  SFVEC2F start3DU( a.x * m_biuTo3Dunits, -a.y * m_biuTo3Dunits );
872  SFVEC2F end3DU ( b.x * m_biuTo3Dunits, -b.y * m_biuTo3Dunits );
873 
874  if( Is_segment_a_circle( start3DU, end3DU ) )
875  {
876  aDstContainer->Add( new CFILLEDCIRCLE2D( start3DU, ( aWidth / 2 ) * m_biuTo3Dunits,
877  *aPad ) );
878  }
879  else
880  {
881  aDstContainer->Add( new CROUNDSEGMENT2D( start3DU, end3DU, aWidth * m_biuTo3Dunits,
882  *aPad ) );
883  }
884  }
885 }
usual segment : line with rounded ends
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
virtual wxPoint GetCenter() const override
Function GetCenter()
Definition: class_track.h:312
void AddShapeWithClearanceToContainer(const PCB_TEXT *aText, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aClearanceValue)
int OutlineCount() const
Returns the number of outlines in the set
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:206
bool IsMirrored() const
Definition: eda_text.h:195
class FP_TEXT, text in a footprint
Definition: typeinfo.h:93
int GetRadius() const
Definition: shape_circle.h:99
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
Definition: pcb_shape.h:140
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
#define SEG_CNT_MAX
wxPoint GetPosition() const override
Definition: class_pad.h:172
FP_TEXT & Value()
read/write accessors:
Definition: class_module.h:475
const wxPoint & GetStart() const
Definition: class_track.h:116
const SHAPE_SEGMENT * GetEffectiveHoleShape() const
Function GetEffectiveHoleShape Returns a SHAPE object representing the pad's hole.
Definition: class_pad.cpp:270
bool IsVisible() const
Definition: eda_text.h:192
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
Definition: pcb_shape.h:185
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)
std::vector< wxPoint > GetRectCorners() const
Definition: pcb_shape.cpp:956
int GetWidth() const
Definition: pcb_shape.h:100
PADS & Pads()
Definition: class_module.h:182
static void isPlated(LIBEVAL::CONTEXT *aCtx, void *self)
double GetTextAngle() const
Definition: eda_text.h:180
bool GetFilledPolysUseThickness() const
Definition: class_zone.h:686
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:629
class ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
Bezier Curve.
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
const VECTOR2I GetCenter() const
Definition: shape_circle.h:104
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID=UNDEFINED_LAYER) const
Definition: class_pad.cpp:252
Definition: color4d.h:45
DRAWINGS & GraphicalItems()
Definition: class_module.h:185
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.
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
Arcs (with rounded ends)
int PointCount() const
Function PointCount()
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
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
int GetEffectiveTextPenWidth(int aDefaultWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultWidth.
Definition: eda_text.cpp:156
wxPoint GetArcStart() const
Definition: pcb_shape.h:163
static int s_textWidth
FP_TEXT & Reference()
Definition: class_module.h:476
const VECTOR2I GetSize() const
Function GetSize()
Definition: shape_rect.h:123
bool IsItalic() const
Definition: eda_text.h:186
void TransformArcToSegments(const wxPoint &aCentre, const wxPoint &aStart, double aArcAngle, int aCircleToSegmentsCount, int aWidth, CGENERICCONTAINER2D *aDstContainer, const BOARD_ITEM &aBoardItem)
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: pcb_text.cpp:51
const VECTOR2I & CPoint(int aIndex) const
Function Point()
PCB_LAYER_ID
A quick note on layer IDs:
unsigned int GetNrSegmentsCircle(float aDiameter3DU) const
GetNrSegmentsCircle.
bool Is_segment_a_circle(const SFVEC2F &aStart, const SFVEC2F &aEnd)
Segment_is_a_circle - check if segment start and end is very close to each other should used to check...
segment with non rounded ends
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:205
glm::vec2 SFVEC2F
Definition: xv3d_types.h:45
#define NULL
static float s_biuTo3Dunits
SHAPE_POLY_SET.
const VECTOR2I & GetPosition() const
Function GetPosition()
Definition: shape_rect.h:113
const wxSize & GetTextSize() const
Definition: eda_text.h:245
wxPoint GetCenter() const override
Function GetCenter()
Definition: pcb_shape.cpp:334
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
Definition: pcb_shape.h:129
PCB_TEXT & Text()
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:55
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:122
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:261
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
bool IsMultilineAllowed() const
Definition: eda_text.h:203
line chain (polyline)
Definition: shape.h:46
Pad object description.
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
Definition: string.cpp:796
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:131
Definition: seg.h:39
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
simple polygon
Definition: shape.h:48
int GetWidth() const
Definition: class_track.h:110
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
polygon (not yet used for tracks, but could be in microwave apps)
SHAPE_LINE_CHAIN.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: pcb_shape.cpp:562
const wxSize & GetDrillSize() const
Definition: class_pad.h:241
VECTOR2I A
Definition: seg.h:47
wxPoint ShapePos() const
Definition: class_pad.cpp:609
double GetAngle() const
Definition: pcb_shape.h:108
int GetLineThickness() const
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:224
const wxPoint & GetEnd() const
Definition: class_track.h:113
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
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
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:254
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
Definition: shape.h:43
PCB_SHAPE_TYPE_T GetShape() const
Definition: pcb_shape.h:114
PAD_SHAPE_T GetShape() const
Definition: class_pad.h:164
static const wxChar * m_logTrace
Trace mask used to enable or disable the trace output of this class.
void createNewPadWithClearance(const D_PAD *aPad, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayer, wxSize aClearanceValue) const
static const BOARD_ITEM * s_boardItem
const wxSize & GetSize() const
Definition: class_pad.h:231
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the draw segment to a closed polygon Used in fi...
int GetWidth() const
static constexpr int Millimeter2iu(double mm)
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
circle
Definition: shape.h:47
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
int GetSizeMax() const
GetSizeMax.
Definition: eda_rect.h:109
Abstract dimension API.
void AddPadsShapesWithClearanceToContainer(const MODULE *aModule, CGENERICCONTAINER2D *aDstContainer, PCB_LAYER_ID aLayerId, int aInflateValue, bool aSkipNPTHPadsWihNoCopper, bool aSkipPlatedPads, bool aSkipNonPlatedPads)
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: eda_item.h:182
axis-aligned rectangle
Definition: shape.h:44
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)
static wxString PCB_SHAPE_TYPE_T_asString(PCB_SHAPE_TYPE_T a)
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:100
VECTOR2I B
Definition: seg.h:48