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 <[email protected]>
5 * Copyright (C) 1992-2022 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/raytracing/shapes2D/ring_2d.h"
34#include "../3d_rendering/raytracing/shapes2D/filled_circle_2d.h"
35#include "../3d_rendering/raytracing/shapes2D/round_segment_2d.h"
36#include "../3d_rendering/raytracing/shapes2D/triangle_2d.h"
37#include "fp_textbox.h"
38#include <board_adapter.h>
39#include <footprint.h>
40#include <pad.h>
41#include <pcb_text.h>
42#include <fp_shape.h>
44#include <pcb_painter.h> // for PCB_RENDER_SETTINGS
45#include <zone.h>
46#include <fp_text.h>
48#include <trigo.h>
52#include <geometry/shape_rect.h>
54#include <utility>
55#include <vector>
56#include <wx/log.h>
57#include <macros.h>
58#include <callback_gal.h>
59
60
61#define TO_3DU( x ) ( ( x ) * m_biuTo3Dunits )
62
63#define TO_SFVEC2F( vec ) SFVEC2F( TO_3DU( vec.x ), TO_3DU( -vec.y ) )
64
65
66void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContainer,
67 const BOARD_ITEM* aOwner )
68{
70 TEXT_ATTRIBUTES attrs = aText->GetAttributes();
71 float penWidth_3DU = TO_3DU( aText->GetEffectiveTextPenWidth() );
72 KIFONT::FONT* font = aText->GetFont();
73
74 if( !font )
75 font = KIFONT::FONT::GetFont( wxEmptyString, aText->IsBold(), aText->IsItalic() );
76
77 if( aOwner && aOwner->IsKnockout() )
78 {
79 SHAPE_POLY_SET knockouts;
80
81 CALLBACK_GAL callback_gal( empty_opts,
82 // Polygon callback
83 [&]( const SHAPE_LINE_CHAIN& aPoly )
84 {
85 knockouts.AddOutline( aPoly );
86 } );
87
89 attrs.m_Angle = aText->GetDrawRotation();
90
91 callback_gal.SetIsFill( font->IsOutline() );
92 callback_gal.SetIsStroke( font->IsStroke() );
93 callback_gal.SetLineWidth( attrs.m_StrokeWidth );
94 font->Draw( &callback_gal, aText->GetShownText(), aText->GetDrawPos(), attrs );
95
96 SHAPE_POLY_SET finalPoly;
97 int margin = attrs.m_StrokeWidth * 1.5 +
99
100 aText->TransformBoundingBoxToPolygon( &finalPoly, margin );
101 finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
103
104 ConvertPolygonToTriangles( finalPoly, *aContainer, m_biuTo3Dunits, *aOwner );
105 }
106 else
107 {
108 CALLBACK_GAL callback_gal( empty_opts,
109 // Stroke callback
110 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
111 {
112 const SFVEC2F pt1_3DU = TO_SFVEC2F( aPt1 );
113 const SFVEC2F pt2_3DU = TO_SFVEC2F( aPt2 );
114
115 if( Is_segment_a_circle( pt1_3DU, pt2_3DU ) )
116 {
117 aContainer->Add( new FILLED_CIRCLE_2D( pt1_3DU, penWidth_3DU / 2,
118 *aOwner ) );
119 }
120 else
121 {
122 aContainer->Add( new ROUND_SEGMENT_2D( pt1_3DU, pt2_3DU, penWidth_3DU,
123 *aOwner ) );
124 }
125 },
126 // Triangulation callback
127 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
128 {
129 aContainer->Add( new TRIANGLE_2D( TO_SFVEC2F( aPt1 ), TO_SFVEC2F( aPt2 ),
130 TO_SFVEC2F( aPt3 ), *aOwner ) );
131 } );
132
133 attrs.m_Angle = aText->GetDrawRotation();
134
135 font->Draw( &callback_gal, aText->GetShownText(), aText->GetDrawPos(), attrs );
136 }
137}
138
139
141 const BOARD_ITEM* aOwner )
142{
143 addText( &aDimension->Text(), aContainer, aDimension );
144
145 const int linewidth = aDimension->GetLineThickness();
146
147 for( const std::shared_ptr<SHAPE>& shape : aDimension->GetShapes() )
148 {
149 switch( shape->Type() )
150 {
151 case SH_SEGMENT:
152 {
153 const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
154
155 aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( seg.A ), TO_SFVEC2F( seg.B ),
156 TO_3DU( linewidth ), *aOwner ) );
157 break;
158 }
159
160 case SH_CIRCLE:
161 {
162 int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
163 int delta = aDimension->GetLineThickness() / 2;
164
165 aContainer->Add( new RING_2D( TO_SFVEC2F( shape->Centre() ), TO_3DU( radius - delta ),
166 TO_3DU( radius + delta ), *aOwner ) );
167 break;
168 }
169
170 default:
171 break;
172 }
173 }
174}
175
176
178 PCB_LAYER_ID aLayerId )
179{
181
182 if( aFootprint->Reference().GetLayer() == aLayerId && aFootprint->Reference().IsVisible() )
183 addText( &aFootprint->Reference(), aContainer, &aFootprint->Reference() );
184
185 if( aFootprint->Value().GetLayer() == aLayerId && aFootprint->Value().IsVisible() )
186 addText( &aFootprint->Value(), aContainer, &aFootprint->Value() );
187
188 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
189 {
190 switch( item->Type() )
191 {
192 case PCB_FP_TEXT_T:
193 {
194 FP_TEXT* text = static_cast<FP_TEXT*>( item );
195
196 if( text->GetLayer() == aLayerId && text->IsVisible() )
197 addText( text, aContainer, text );
198
199 break;
200 }
201
202 case PCB_FP_TEXTBOX_T:
203 {
204 FP_TEXTBOX* textbox = static_cast<FP_TEXTBOX*>( item );
205
206 if( textbox->GetLayer() == aLayerId )
207 {
208 addShape( textbox, aContainer, aFootprint );
209 addText( textbox, aContainer, aFootprint );
210 }
211
212 break;
213 }
214
220 {
221 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( item );
222
223 if( dimension->GetLayer() == aLayerId )
224 addShape( dimension, aContainer, aFootprint );
225
226 break;
227 }
228
229 case PCB_FP_SHAPE_T:
230 {
231 FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
232
233 if( shape->GetLayer() == aLayerId )
234 addShape( shape, aContainer, aFootprint );
235
236 break;
237 }
238
239 default:
240 break;
241 }
242 }
243}
244
245
246void BOARD_ADAPTER::createTrack( const PCB_TRACK* aTrack, CONTAINER_2D_BASE* aDstContainer )
247{
248 SFVEC2F start3DU = TO_SFVEC2F( aTrack->GetStart() );
249 SFVEC2F end3DU = TO_SFVEC2F( aTrack->GetEnd() );
250
251 switch( aTrack->Type() )
252 {
253 case PCB_VIA_T:
254 {
255 const float radius3DU = TO_3DU( aTrack->GetWidth() / 2 );
256 aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, radius3DU, *aTrack ) );
257 break;
258 }
259
260 case PCB_ARC_T:
261 {
262 const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
263
264 VECTOR2D center( arc->GetCenter() );
265 EDA_ANGLE arc_angle = arc->GetAngle();
266 double radius = arc->GetRadius();
267 int arcsegcount = GetArcToSegmentCount( radius, ARC_HIGH_DEF, arc_angle );
268 int circlesegcount;
269
270 // We need a circle to segment count. However, the arc angle can be small, and the
271 // radius very big. so we calculate a reasonable value for circlesegcount.
272 if( arcsegcount <= 1 ) // The arc will be approximated by a segment
273 {
274 circlesegcount = 1;
275 }
276 else
277 {
278 circlesegcount = KiROUND( arcsegcount * 360.0 / std::abs( arc_angle.AsDegrees() ) );
279 circlesegcount = std::max( 1, std::min( circlesegcount, 128 ) );
280 }
281
282 transformArcToSegments( VECTOR2I( center.x, center.y ), arc->GetStart(), arc_angle,
283 circlesegcount, arc->GetWidth(), aDstContainer, *arc );
284 break;
285 }
286
287 case PCB_TRACE_T: // Track is a usual straight segment
288 {
289 // Cannot add segments that have the same start and end point
290 if( Is_segment_a_circle( start3DU, end3DU ) )
291 {
292 aDstContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aTrack->GetWidth() / 2 ),
293 *aTrack ) );
294 }
295 else
296 {
297 aDstContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aTrack->GetWidth() ),
298 *aTrack ) );
299 }
300
301 break;
302 }
303
304 default:
305 break;
306 }
307}
308
309
311 PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const
312{
313 SHAPE_POLY_SET poly;
314 int maxError = GetBoard()->GetDesignSettings().m_MaxError;
315 VECTOR2I clearance = aMargin;
316
317 // Our shape-based builder can't handle negative or differing x:y clearance values (the
318 // former are common for solder paste while the later get generated when a relative paste
319 // margin is used with an oblong pad). So we apply this huge hack and fake a larger pad to
320 // run the general-purpose polygon builder on.
321 // Of course being a hack it falls down when dealing with custom shape pads (where the size
322 // is only the size of the anchor), so for those we punt and just use aMargin.x.
323
324 if( ( clearance.x < 0 || clearance.x != clearance.y )
325 && aPad->GetShape() != PAD_SHAPE::CUSTOM )
326 {
327 VECTOR2I dummySize = VECTOR2I( aPad->GetSize() ) + clearance + clearance;
328
329 if( dummySize.x <= 0 || dummySize.y <= 0 )
330 return;
331
332 PAD dummy( *aPad );
333 dummy.SetSize( wxSize( dummySize.x, dummySize.y ) );
334 dummy.TransformShapeToPolygon( poly, aLayer, 0, maxError, ERROR_INSIDE );
335 clearance = { 0, 0 };
336 }
337 else
338 {
339 auto padShapes = std::static_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape() );
340
341 for( const SHAPE* shape : padShapes->Shapes() )
342 {
343 switch( shape->Type() )
344 {
345 case SH_SEGMENT:
346 {
347 const SHAPE_SEGMENT* seg = static_cast<const SHAPE_SEGMENT*>( shape );
348
349 const SFVEC2F a3DU = TO_SFVEC2F( seg->GetSeg().A );
350 const SFVEC2F b3DU = TO_SFVEC2F( seg->GetSeg().B );
351 const double width3DU = TO_3DU( seg->GetWidth() + clearance.x * 2 );
352
353 // Cannot add segments that have the same start and end point
354 if( Is_segment_a_circle( a3DU, b3DU ) )
355 aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) );
356 else
357 aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) );
358 }
359 break;
360
361 case SH_CIRCLE:
362 {
363 const SHAPE_CIRCLE* circle = static_cast<const SHAPE_CIRCLE*>( shape );
364
365 const double radius3DU = TO_3DU( circle->GetRadius() + clearance.x );
366 const SFVEC2F center3DU = TO_SFVEC2F( circle->GetCenter() );
367
368 // Don't render zero radius circles
369 if( radius3DU != 0.0 )
370 aContainer->Add( new FILLED_CIRCLE_2D( center3DU, radius3DU, *aPad ) );
371 }
372 break;
373
374 case SH_RECT:
375 {
376 const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>( shape );
377
378 poly.NewOutline();
379 poly.Append( rect->GetPosition() );
380 poly.Append( rect->GetPosition().x + rect->GetSize().x, rect->GetPosition().y );
381 poly.Append( rect->GetPosition() + rect->GetSize() );
382 poly.Append( rect->GetPosition().x, rect->GetPosition().y + rect->GetSize().y );
383 }
384 break;
385
386 case SH_SIMPLE:
387 poly.AddOutline( static_cast<const SHAPE_SIMPLE*>( shape )->Vertices() );
388 break;
389
390 case SH_POLY_SET:
391 poly = *(SHAPE_POLY_SET*) shape;
392 break;
393
394 case SH_ARC:
395 {
396 const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( shape );
397 SHAPE_LINE_CHAIN l = arc->ConvertToPolyline( maxError );
398
399 for( int i = 0; i < l.SegmentCount(); i++ )
400 {
401 SHAPE_SEGMENT seg( l.Segment( i ).A, l.Segment( i ).B, arc->GetWidth() );
402 const SFVEC2F a3DU = TO_SFVEC2F( seg.GetSeg().A );
403 const SFVEC2F b3DU = TO_SFVEC2F( seg.GetSeg().B );
404 const double width3DU = TO_3DU( arc->GetWidth() + clearance.x * 2 );
405
406 // Cannot add segments that have the same start and end point
407 if( Is_segment_a_circle( a3DU, b3DU ) )
408 aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aPad ) );
409 else
410 aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aPad ) );
411 }
412 }
413 break;
414
415 default:
416 UNIMPLEMENTED_FOR( SHAPE_TYPE_asString( shape->Type() ) );
417 break;
418 }
419 }
420 }
421
422 if( !poly.IsEmpty() )
423 {
424 if( clearance.x )
425 poly.Inflate( clearance.x, 32 );
426
427 // Add the PAD polygon
428 ConvertPolygonToTriangles( poly, *aContainer, m_biuTo3Dunits, *aPad );
429 }
430}
431
432
433OBJECT_2D* BOARD_ADAPTER::createPadWithDrill( const PAD* aPad, int aInflateValue )
434{
435 if( !aPad->HasHole() )
436 {
437 wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createPadWithDrill - found an invalid pad" ) );
438 return nullptr;
439 }
440
441 std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
442
443 if( slot->GetSeg().A == slot->GetSeg().B )
444 {
445 return new FILLED_CIRCLE_2D( TO_SFVEC2F( slot->GetSeg().A ),
446 TO_3DU( slot->GetWidth() / 2 + aInflateValue ),
447 *aPad );
448 }
449 else
450 {
451 return new ROUND_SEGMENT_2D( TO_SFVEC2F( slot->GetSeg().A ),
452 TO_SFVEC2F( slot->GetSeg().B ),
453 TO_3DU( slot->GetWidth() + aInflateValue * 2 ),
454 *aPad );
455 }
456}
457
458
459void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer,
460 PCB_LAYER_ID aLayerId, bool aSkipNPTHPadsWihNoCopper,
461 bool aSkipPlatedPads, bool aSkipNonPlatedPads )
462{
463 for( PAD* pad : aFootprint->Pads() )
464 {
465 if( !pad->IsOnLayer( aLayerId ) )
466 continue;
467
468 // Skip pad annulus when not connected on this layer (if removing is enabled)
469 if( !pad->FlashLayer( aLayerId ) && IsCopperLayer( aLayerId ) )
470 continue;
471
472 // NPTH pads are not drawn on layers if the shape size and pos is the same as their hole:
473 if( aSkipNPTHPadsWihNoCopper && ( pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
474 {
475 if( pad->GetDrillSize() == pad->GetSize() && pad->GetOffset() == wxPoint( 0, 0 ) )
476 {
477 switch( pad->GetShape() )
478 {
480 if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
481 continue;
482
483 break;
484
485 case PAD_SHAPE::OVAL:
486 if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
487 continue;
488
489 break;
490
491 default:
492 break;
493 }
494 }
495 }
496
497 VECTOR2I margin( 0, 0 );
498
499 switch( aLayerId )
500 {
501 case F_Cu:
502 if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
503 continue;
504
505 if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
506 continue;
507
508 break;
509
510 case B_Cu:
511 if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
512 continue;
513
514 if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
515 continue;
516
517 break;
518
519 case F_Mask:
520 case B_Mask:
521 margin.x += pad->GetSolderMaskExpansion();
522 margin.y += pad->GetSolderMaskExpansion();
523 break;
524
525 case F_Paste:
526 case B_Paste:
527 margin += pad->GetSolderPasteMargin();
528 break;
529
530 default:
531 break;
532 }
533
534 createPadWithMargin( pad, aContainer, aLayerId, margin );
535 }
536}
537
538
539// based on TransformArcToPolygon function from
540// common/convert_basic_shapes_to_polygon.cpp
541void BOARD_ADAPTER::transformArcToSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart,
542 const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount,
543 int aWidth, CONTAINER_2D_BASE* aContainer,
544 const BOARD_ITEM& aOwner )
545{
546 VECTOR2I arc_start, arc_end;
547 EDA_ANGLE arcAngle( aArcAngle );
548 EDA_ANGLE delta = ANGLE_360 / aCircleToSegmentsCount; // rotate angle
549
550 arc_end = arc_start = aStart;
551
552 if( arcAngle != ANGLE_360 )
553 RotatePoint( arc_end, aCentre, -arcAngle );
554
555 if( arcAngle < ANGLE_0 )
556 {
557 std::swap( arc_start, arc_end );
558 arcAngle = -arcAngle;
559 }
560
561 // Compute the ends of segments and creates poly
562 VECTOR2I curr_end = arc_start;
563 VECTOR2I curr_start = arc_start;
564
565 for( EDA_ANGLE ii = delta; ii < arcAngle; ii += delta )
566 {
567 curr_end = arc_start;
568 RotatePoint( curr_end, aCentre, -ii );
569
570 const SFVEC2F start3DU = TO_SFVEC2F( curr_start );
571 const SFVEC2F end3DU = TO_SFVEC2F( curr_end );
572
573 if( Is_segment_a_circle( start3DU, end3DU ) )
574 aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), aOwner ) );
575 else
576 aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), aOwner ) );
577
578 curr_start = curr_end;
579 }
580
581 if( curr_end != arc_end )
582 {
583 const SFVEC2F start3DU = TO_SFVEC2F( curr_end );
584 const SFVEC2F end3DU = TO_SFVEC2F( arc_end );
585
586 if( Is_segment_a_circle( start3DU, end3DU ) )
587 aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), aOwner ) );
588 else
589 aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), aOwner ) );
590 }
591}
592
593
594void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer,
595 const BOARD_ITEM* aOwner )
596{
597 // The full width of the lines to create
598 // The extra 1 protects the inner/outer radius values from degeneracy
599 const int linewidth = aShape->GetWidth() + 1;
600 PLOT_DASH_TYPE lineStyle = aShape->GetStroke().GetPlotStyle();
601
602 if( lineStyle <= PLOT_DASH_TYPE::FIRST_TYPE )
603 {
604 switch( aShape->GetShape() )
605 {
606 case SHAPE_T::CIRCLE:
607 {
608 const SFVEC2F center3DU = TO_SFVEC2F( aShape->GetCenter() );
609 float inner_radius3DU = TO_3DU( aShape->GetRadius() - linewidth / 2 );
610 float outer_radius3DU = TO_3DU( aShape->GetRadius() + linewidth / 2 );
611
612 if( inner_radius3DU < 0 )
613 inner_radius3DU = 0;
614
615 if( aShape->IsFilled() )
616 aContainer->Add( new FILLED_CIRCLE_2D( center3DU, outer_radius3DU, *aOwner ) );
617 else
618 aContainer->Add( new RING_2D( center3DU, inner_radius3DU, outer_radius3DU, *aOwner ) );
619
620 break;
621 }
622
623 case SHAPE_T::RECT:
624 if( aShape->IsFilled() )
625 {
626 SHAPE_POLY_SET polyList;
627
629 ERROR_INSIDE );
630
632
633 ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
634 }
635 else
636 {
637 std::vector<VECTOR2I> pts = aShape->GetRectCorners();
638
639 aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[0] ), TO_SFVEC2F( pts[1] ),
640 TO_3DU( linewidth ), *aOwner ) );
641 aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[1] ), TO_SFVEC2F( pts[2] ),
642 TO_3DU( linewidth ), *aOwner ) );
643 aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[2] ), TO_SFVEC2F( pts[3] ),
644 TO_3DU( linewidth ), *aOwner ) );
645 aContainer->Add( new ROUND_SEGMENT_2D( TO_SFVEC2F( pts[3] ), TO_SFVEC2F( pts[0] ),
646 TO_3DU( linewidth ), *aOwner ) );
647 }
648 break;
649
650 case SHAPE_T::ARC:
651 {
652 unsigned int segCount = GetCircleSegmentCount( aShape->GetBoundingBox().GetSizeMax() );
653
654 transformArcToSegments( aShape->GetCenter(), aShape->GetStart(), aShape->GetArcAngle(),
655 segCount, linewidth, aContainer, *aOwner );
656 }
657 break;
658
659 case SHAPE_T::SEGMENT:
660 {
661 const SFVEC2F start3DU = TO_SFVEC2F( aShape->GetStart() );
662 const SFVEC2F end3DU = TO_SFVEC2F( aShape->GetEnd() );
663 const double linewidth3DU = TO_3DU( linewidth );
664
665 if( Is_segment_a_circle( start3DU, end3DU ) )
666 aContainer->Add( new FILLED_CIRCLE_2D( start3DU, linewidth3DU / 2, *aOwner ) );
667 else
668 aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, linewidth3DU, *aOwner ) );
669 }
670 break;
671
672 case SHAPE_T::BEZIER:
673 case SHAPE_T::POLY:
674 {
675 SHAPE_POLY_SET polyList;
676
678 ERROR_INSIDE );
679
680 if( polyList.IsEmpty() ) // Just for caution
681 break;
682
683 ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
684 }
685 break;
686
687 default:
688 wxFAIL_MSG( wxT( "BOARD_ADAPTER::addShape no implementation for " )
689 + aShape->SHAPE_T_asString() );
690 break;
691 }
692 }
693 else
694 {
695 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
696 SFVEC2F a3DU;
697 SFVEC2F b3DU;
698 double width3DU = TO_3DU( linewidth );
699
700 const PCB_PLOT_PARAMS& plotParams = aShape->GetBoard()->GetPlotOptions();
701 KIGFX::PCB_RENDER_SETTINGS renderSettings;
702
703 renderSettings.SetDashLengthRatio( plotParams.GetDashedLineDashRatio() );
704 renderSettings.SetGapLengthRatio( plotParams.GetDashedLineGapRatio() );
705
706 for( SHAPE* shape : shapes )
707 {
708 STROKE_PARAMS::Stroke( shape, lineStyle, linewidth, &renderSettings,
709 [&]( const VECTOR2I& a, const VECTOR2I& b )
710 {
711 a3DU = TO_SFVEC2F( a );
712 b3DU = TO_SFVEC2F( b );
713
714 if( Is_segment_a_circle( a3DU, b3DU ) )
715 aContainer->Add( new FILLED_CIRCLE_2D( a3DU, width3DU / 2, *aOwner ) );
716 else
717 aContainer->Add( new ROUND_SEGMENT_2D( a3DU, b3DU, width3DU, *aOwner ) );
718 } );
719 }
720
721 for( SHAPE* shape : shapes )
722 delete shape;
723 }
724}
725
726
728 PCB_LAYER_ID aLayerId )
729{
730 // This convert the poly in outline and holes
731 ConvertPolygonToTriangles( *aZone->GetFilledPolysList( aLayerId ), *aContainer,
732 m_biuTo3Dunits, *aZone );
733}
734
735
737 int aWidth )
738{
739 if( aPad->GetShape() == PAD_SHAPE::CIRCLE ) // Draw a ring
740 {
741 const SFVEC2F center3DU = TO_SFVEC2F( aPad->ShapePos() );
742 const int radius = aPad->GetSize().x / 2;
743 const float inner_radius3DU = TO_3DU( radius - aWidth / 2 );
744 const float outer_radius3DU = TO_3DU( radius + aWidth / 2 );
745
746 aContainer->Add( new RING_2D( center3DU, inner_radius3DU, outer_radius3DU, *aPad ) );
747
748 return;
749 }
750
751 // For other shapes, add outlines as thick segments in polygon buffer
752 const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon();
753 const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
754
755 for( int j = 0; j < path.PointCount(); j++ )
756 {
757 SFVEC2F start3DU = TO_SFVEC2F( path.CPoint( j ) );
758 SFVEC2F end3DU = TO_SFVEC2F( path.CPoint( j + 1 ) );
759
760 if( Is_segment_a_circle( start3DU, end3DU ) )
761 aContainer->Add( new FILLED_CIRCLE_2D( start3DU, TO_3DU( aWidth / 2 ), *aPad ) );
762 else
763 aContainer->Add( new ROUND_SEGMENT_2D( start3DU, end3DU, TO_3DU( aWidth ), *aPad ) );
764 }
765}
constexpr int ARC_HIGH_DEF
Definition: base_units.h:121
void addPads(const FOOTPRINT *aFootprint, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId, bool aSkipNPTHPadsWihNoCopper, bool aSkipPlatedPads, bool aSkipNonPlatedPads)
void addFootprintShapes(const FOOTPRINT *aFootprint, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId)
void addSolidAreasShapes(const ZONE *aZone, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId)
void createPadWithMargin(const PAD *aPad, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayer, const VECTOR2I &aMargin) const
const BOARD * GetBoard() const noexcept
void transformArcToSegments(const VECTOR2I &aCentre, const VECTOR2I &aStart, const EDA_ANGLE &aArcAngle, int aCircleToSegmentsCount, int aWidth, CONTAINER_2D_BASE *aDstContainer, const BOARD_ITEM &aOwner)
void buildPadOutlineAsSegments(const PAD *aPad, CONTAINER_2D_BASE *aDstContainer, int aWidth)
void addShape(const PCB_SHAPE *aShape, CONTAINER_2D_BASE *aContainer, const BOARD_ITEM *aOwner)
void createTrack(const PCB_TRACK *aTrack, CONTAINER_2D_BASE *aDstContainer)
unsigned int GetCircleSegmentCount(float aDiameter3DU) const
OBJECT_2D * createPadWithDrill(const PAD *aPad, int aInflateValue)
double m_biuTo3Dunits
Scale factor to convert board internal units to 3D units normalized between -1.0 and 1....
void addText(const EDA_TEXT *aText, CONTAINER_2D_BASE *aDstContainer, const BOARD_ITEM *aOwner)
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:180
virtual bool IsKnockout() const
Definition: board_item.h:250
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:43
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:627
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:628
int GetSizeMax() const
Definition: box2.h:200
void Add(OBJECT_2D *aObject)
Definition: container_2d.h:49
double AsDegrees() const
Definition: eda_angle.h:149
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
EDA_ANGLE GetArcAngle() const
Definition: eda_shape.cpp:541
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition: eda_shape.h:285
bool IsFilled() const
Definition: eda_shape.h:90
int GetRadius() const
Definition: eda_shape.cpp:479
SHAPE_T GetShape() const
Definition: eda_shape.h:111
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:141
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:116
std::vector< VECTOR2I > GetRectCorners() const
Definition: eda_shape.cpp:989
int GetWidth() const
Definition: eda_shape.h:107
wxString SHAPE_T_asString() const
Definition: eda_shape.cpp:75
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:72
void TransformBoundingBoxToPolygon(SHAPE_POLY_SET *aBuffer, int aClearance) const
Convert the text bounding box to a rectangular polygon depending on the text orientation,...
Definition: eda_text.cpp:945
bool IsItalic() const
Definition: eda_text.h:123
virtual bool IsVisible() const
Definition: eda_text.h:129
KIFONT::FONT * GetFont() const
Definition: eda_text.h:181
virtual EDA_ANGLE GetDrawRotation() const
Definition: eda_text.h:310
virtual VECTOR2I GetDrawPos() const
Definition: eda_text.h:311
const TEXT_ATTRIBUTES & GetAttributes() const
Definition: eda_text.h:165
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition: eda_text.cpp:297
bool IsBold() const
Definition: eda_text.h:126
virtual wxString GetShownText(int aDepth=0, bool aAllowExtraText=true) const
Return the string actually shown after processing of the base text.
Definition: eda_text.h:98
PADS & Pads()
Definition: footprint.h:170
FP_TEXT & Value()
read/write accessors:
Definition: footprint.h:558
DRAWINGS & GraphicalItems()
Definition: footprint.h:173
FP_TEXT & Reference()
Definition: footprint.h:559
FONT is an abstract base class for both outline and stroke fonts.
Definition: font.h:105
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false)
Definition: font.cpp:65
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttrs) const
Draw a string.
Definition: font.cpp:159
virtual bool IsStroke() const
Definition: font.h:112
virtual bool IsOutline() const
Definition: font.h:113
PCB specific render settings.
Definition: pcb_painter.h:72
void SetGapLengthRatio(double aRatio)
void SetDashLengthRatio(double aRatio)
Definition: pad.h:59
VECTOR2I ShapePos() const
Definition: pad.cpp:755
PAD_SHAPE GetShape() const
Definition: pad.h:189
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon() const
Definition: pad.cpp:346
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING flashPTHPads=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: pad.cpp:355
bool HasHole() const override
Definition: pad.h:106
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape() const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition: pad.cpp:392
const VECTOR2I & GetSize() const
Definition: pad.h:252
double GetRadius() const
Definition: pcb_track.cpp:1105
EDA_ANGLE GetAngle() const
Definition: pcb_track.cpp:1111
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_track.h:319
Abstract dimension API.
Definition: pcb_dimension.h:96
int GetLineThickness() const
PCB_TEXT & Text()
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
Parameters and options when plotting/printing a board.
double GetDashedLineGapRatio() const
double GetDashedLineDashRatio() const
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: pcb_shape.h:99
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_shape.h:65
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the shape to a closed polygon.
Definition: pcb_shape.cpp:388
STROKE_PARAMS GetStroke() const override
Definition: pcb_shape.h:69
int GetWidth() const
Definition: pcb_track.h:106
const VECTOR2I & GetStart() const
Definition: pcb_track.h:112
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:109
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
int GetWidth() const
Definition: shape_arc.h:157
const SHAPE_LINE_CHAIN ConvertToPolyline(double aAccuracy=DefaultAccuracyForPCB(), double *aEffectiveAccuracy=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
Definition: shape_arc.cpp:464
int GetRadius() const
Definition: shape_circle.h:108
const VECTOR2I GetCenter() const
Definition: shape_circle.h:113
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int SegmentCount() const
Return the number of segments in this line chain.
SEG Segment(int aIndex)
Return a copy of the aIndex-th segment in the line chain.
Represent a set of closed polygons.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
bool IsEmpty() const
void Inflate(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Perform outline inflation/deflation.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
void Simplify(POLYGON_MODE aFastMode)
int NewOutline()
Creates a new hole in a given outline.
const VECTOR2I & GetPosition() const
Definition: shape_rect.h:127
const VECTOR2I GetSize() const
Definition: shape_rect.h:135
const SEG & GetSeg() const
int GetWidth() const
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
Definition: shape_simple.h:42
const SHAPE_LINE_CHAIN & Vertices() const
Return the list of vertices defining this simple polygon.
Definition: shape_simple.h:124
An abstract shape on 2D plane.
Definition: shape.h:123
static void Stroke(const SHAPE *aShape, PLOT_DASH_TYPE aLineStyle, int aWidth, const KIGFX::RENDER_SETTINGS *aRenderSettings, std::function< void(const VECTOR2I &a, const VECTOR2I &b)> aStroker)
PLOT_DASH_TYPE GetPlotStyle() const
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
const std::shared_ptr< SHAPE_POLY_SET > & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:601
#define TO_3DU(x)
#define TO_SFVEC2F(vec)
static constexpr EDA_ANGLE & ANGLE_360
Definition: eda_angle.h:418
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:412
a few functions useful in geometry calculations.
@ ERROR_INSIDE
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
int GetKnockoutTextMargin(const VECTOR2I &aSize, int aThickness)
Returns the margin for knockout text.
Definition: gr_text.h:97
static const wxChar * m_logTrace
Trace mask used to enable or disable debug output for this class.
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:825
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ F_Paste
Definition: layer_ids.h:101
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
@ F_Cu
Definition: layer_ids.h:64
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:120
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:401
@ NPTH
like PAD_PTH, but not plated
@ PAD_DRILL_SHAPE_CIRCLE
Definition: pad_shapes.h:70
bool Is_segment_a_circle(const SFVEC2F &aStart, const SFVEC2F &aEnd)
Check if segment start and end is very close to each other.
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:74
@ SH_POLY_SET
set of polygons (with holes, etc.)
Definition: shape.h:49
@ SH_RECT
axis-aligned rectangle
Definition: shape.h:44
@ SH_CIRCLE
circle
Definition: shape.h:47
@ SH_SIMPLE
simple polygon
Definition: shape.h:48
@ SH_SEGMENT
line segment
Definition: shape.h:45
@ SH_ARC
circular arc
Definition: shape.h:51
static wxString SHAPE_TYPE_asString(SHAPE_TYPE a)
Definition: shape.h:56
PLOT_DASH_TYPE
Dashed line types.
Definition: stroke_params.h:48
constexpr int delta
void ConvertPolygonToTriangles(const SHAPE_POLY_SET &aPolyList, CONTAINER_2D_BASE &aDstContainer, float aBiuTo3dUnitsScale, const BOARD_ITEM &aBoardItem)
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
@ PCB_FP_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:95
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102
@ PCB_FP_TEXTBOX_T
class FP_TEXTBOX, wrapped text in a footprint
Definition: typeinfo.h:93
@ PCB_FP_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:97
@ PCB_FP_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:99
@ PCB_FP_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:96
@ PCB_FP_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:98
@ PCB_FP_TEXT_T
class FP_TEXT, text in a footprint
Definition: typeinfo.h:92
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:103
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:101
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618
glm::vec2 SFVEC2F
Definition: xv3d_types.h:42