KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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) 2023 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
27
32#include <board_adapter.h>
33#include <board.h>
34#include <footprint.h>
35#include <pad.h>
36#include <pcb_text.h>
37#include <pcb_textbox.h>
38#include <pcb_table.h>
39#include <pcb_track.h>
40#include <pcb_painter.h> // for PCB_RENDER_SETTINGS
41#include <zone.h>
43#include <trigo.h>
47#include <geometry/roundrect.h>
48#include <geometry/shape_rect.h>
51#include <bezier_curves.h>
52#include <utility>
53#include <vector>
54#include <wx/log.h>
55#include <macros.h>
56#include <callback_gal.h>
57#include <line_ending.h>
58#include <pcb_barcode.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 addFILLED_CIRCLE_2D( CONTAINER_2D_BASE* aContainer, const SFVEC2F& aCenter, float aRadius,
67 const BOARD_ITEM& aBoardItem )
68{
69 if( aRadius > 0.0f )
70 aContainer->Add( new FILLED_CIRCLE_2D( aCenter, aRadius, aBoardItem ) );
71}
72
73
74void addRING_2D( CONTAINER_2D_BASE* aContainer, const SFVEC2F& aCenter, float aInnerRadius,
75 float aOuterRadius, const BOARD_ITEM& aBoardItem )
76{
77 if( aOuterRadius > aInnerRadius && aInnerRadius > 0.0f )
78 aContainer->Add( new RING_2D( aCenter, aInnerRadius, aOuterRadius, aBoardItem ) );
79}
80
81
82void addROUND_SEGMENT_2D( CONTAINER_2D_BASE* aContainer, const SFVEC2F& aStart, const SFVEC2F& aEnd,
83 float aWidth, const BOARD_ITEM& aBoardItem )
84{
85 if( Is_segment_a_circle( aStart, aEnd ) )
86 {
87 // Cannot add segments that have the same start and end point
88 addFILLED_CIRCLE_2D( aContainer, aStart, aWidth / 2, aBoardItem );
89 return;
90 }
91
92 if( aWidth > 0.0f )
93 aContainer->Add( new ROUND_SEGMENT_2D( aStart, aEnd, aWidth, aBoardItem ) );
94}
95
96
97void BOARD_ADAPTER::addText( const EDA_TEXT* aText, CONTAINER_2D_BASE* aContainer, const BOARD_ITEM* aOwner )
98{
100 TEXT_ATTRIBUTES attrs = aText->GetAttributes();
101 float penWidth_3DU = TO_3DU( aText->GetEffectiveTextPenWidth() );
102 KIFONT::FONT* font = aText->GetFont();
103 wxString shownText = aText->GetShownText( FOR_CANVAS );
104
105 if( !font )
106 font = KIFONT::FONT::GetFont( wxEmptyString, aText->IsBold(), aText->IsItalic() );
107
108 if( aOwner && aOwner->IsKnockout() )
109 {
110 SHAPE_POLY_SET finalPoly;
111
112 if( const PCB_TEXTBOX* pcbTextBox = dynamic_cast<const PCB_TEXTBOX*>( aOwner ) )
113 pcbTextBox->TransformTextToPolySet( finalPoly, 0, aOwner->GetMaxError(), ERROR_INSIDE );
114 else if( const PCB_TEXT* pcbText = dynamic_cast<const PCB_TEXT*>( aOwner ) )
115 pcbText->TransformTextToPolySet( finalPoly, 0, aOwner->GetMaxError(), ERROR_INSIDE );
116
117 // Do not call finalPoly.Fracture() here: ConvertPolygonToTriangles() call it
118 // if needed, and Fracture() called twice can create bad results and is useless
119 ConvertPolygonToTriangles( finalPoly, *aContainer, m_biuTo3Dunits, *aOwner );
120 }
121 else
122 {
123 CALLBACK_GAL callback_gal( empty_opts,
124 // Stroke callback
125 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
126 {
127 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( aPt1 ), TO_SFVEC2F( aPt2 ),
128 penWidth_3DU, *aOwner );
129 },
130 // Triangulation callback
131 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2, const VECTOR2I& aPt3 )
132 {
133 aContainer->Add( new TRIANGLE_2D( TO_SFVEC2F( aPt1 ), TO_SFVEC2F( aPt2 ),
134 TO_SFVEC2F( aPt3 ), *aOwner ) );
135 } );
136
137 attrs.m_Angle = aText->GetDrawRotation();
138
139 if( auto* cache = aText->GetRenderCache( font, shownText ) )
140 {
141 callback_gal.DrawGlyphs( *cache );
142 }
143 else
144 {
145 font->Draw( &callback_gal, shownText, aText->GetDrawPos(), attrs,
146 aOwner->GetFontMetrics() );
147 }
148 }
149}
150
151
152void BOARD_ADAPTER::addBarCode( const PCB_BARCODE* aBarCode, CONTAINER_2D_BASE* aDstContainer,
153 const BOARD_ITEM* aOwner )
154{
155 SHAPE_POLY_SET shape;
156 aBarCode->TransformShapeToPolySet( shape, aBarCode->GetLayer(), 0, 0, ERROR_INSIDE );
157 shape.Simplify();
158
159 ConvertPolygonToTriangles( shape, *aDstContainer, m_biuTo3Dunits, *aOwner );
160}
161
162
164 const BOARD_ITEM* aOwner )
165{
166 addText( aDimension, aContainer, aDimension );
167
168 const int linewidth = aDimension->GetLineThickness();
169
170 for( const std::shared_ptr<SHAPE>& shape : aDimension->GetShapes() )
171 {
172 switch( shape->Type() )
173 {
174 case SH_SEGMENT:
175 {
176 const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
177
178 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( seg.A ), TO_SFVEC2F( seg.B ),
179 TO_3DU( linewidth ), *aOwner );
180 break;
181 }
182
183 case SH_CIRCLE:
184 {
185 int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
186 float innerR3DU = TO_3DU( radius ) - TO_3DU( aDimension->GetLineThickness() ) / 2.0f;
187 float outerR3DU = TO_3DU( radius ) + TO_3DU( aDimension->GetLineThickness() ) / 2.0f;
188
189 addRING_2D( aContainer, TO_SFVEC2F( shape->Centre() ), innerR3DU, outerR3DU, *aOwner );
190
191 break;
192 }
193
194 default:
195 break;
196 }
197 }
198}
199
200
202 PCB_LAYER_ID aLayerId,
203 const std::bitset<LAYER_3D_END>& aFlags )
204{
206
207 for( PCB_FIELD* field : aFootprint->GetFields() )
208 {
209 if( !aFlags.test( LAYER_FP_TEXT ) )
210 continue;
211
212 wxCHECK2( field, continue );
213
214 if( field->IsReference() && !aFlags.test( LAYER_FP_REFERENCES ) )
215 continue;
216
217 if( field->IsValue() && !aFlags.test( LAYER_FP_VALUES ) )
218 continue;
219
220 if( field->GetLayer() == aLayerId && field->IsVisible() )
221 addText( field, aContainer, field );
222 }
223
224 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
225 {
226 switch( item->Type() )
227 {
228 case PCB_TEXT_T:
229 {
230 PCB_TEXT* text = static_cast<PCB_TEXT*>( item );
231
232 if( !aFlags.test( LAYER_FP_TEXT ) )
233 continue;
234
235 if( text->GetText() == wxT( "${REFERENCE}" ) && !aFlags.test( LAYER_FP_REFERENCES ) )
236 continue;
237
238 if( text->GetText() == wxT( "${VALUE}" ) && !aFlags.test( LAYER_FP_VALUES ) )
239 continue;
240
241 if( text->GetLayer() == aLayerId )
242 addText( text, aContainer, text );
243
244 break;
245 }
246
247 case PCB_TEXTBOX_T:
248 {
249 PCB_TEXTBOX* textbox = static_cast<PCB_TEXTBOX*>( item );
250
251 if( textbox->GetLayer() == aLayerId )
252 addShape( textbox, aContainer, textbox );
253
254 break;
255 }
256
257 case PCB_TABLE_T:
258 {
259 PCB_TABLE* table = static_cast<PCB_TABLE*>( item );
260
261 if( table->GetLayer() == aLayerId )
262 addTable( table, aContainer, aFootprint );
263
264 break;
265 }
266
268 case PCB_DIM_CENTER_T:
270 case PCB_DIM_RADIAL_T:
271 case PCB_DIM_LEADER_T:
272 {
273 PCB_DIMENSION_BASE* dimension = static_cast<PCB_DIMENSION_BASE*>( item );
274
275 if( dimension->GetLayer() == aLayerId )
276 addShape( dimension, aContainer, aFootprint );
277
278 break;
279 }
280
281 case PCB_SHAPE_T:
282 {
283 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
284
285 if( shape->IsOnLayer( aLayerId ) )
286 addShape( shape, aContainer, aFootprint, aLayerId );
287
288 break;
289 }
290
291 case PCB_BARCODE_T:
292 {
293 PCB_BARCODE* barcode = static_cast<PCB_BARCODE*>( item );
294
295 if( barcode->GetLayer() == aLayerId )
296 addBarCode( barcode, aContainer, aFootprint );
297
298 break;
299 }
300
301 default:
302 break;
303 }
304 }
305}
306
307
309 PCB_LAYER_ID aLayer, int aMargin )
310{
311 SFVEC2F start3DU = TO_SFVEC2F( aTrack->GetStart() );
312 SFVEC2F end3DU = TO_SFVEC2F( aTrack->GetEnd() );
313
314 switch( aTrack->Type() )
315 {
316 case PCB_VIA_T:
317 {
318 const PCB_VIA* via = static_cast<const PCB_VIA*>( aTrack );
319 float width3DU = TO_3DU( via->GetWidth( aLayer ) + aMargin * 2 );
320
321 addFILLED_CIRCLE_2D( aDstContainer, start3DU, width3DU / 2.0, *aTrack );
322 break;
323 }
324
325 case PCB_ARC_T:
326 {
327 const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
328
329 if( arc->IsDegenerated() )
330 {
331 // Draw this very small arc like a track segment (a PCB_TRACE_T)
332 PCB_TRACK track( arc->GetParent() );
333 track.SetStart( arc->GetStart() );
334 track.SetEnd( arc->GetEnd() );
335 track.SetWidth( arc->GetWidth() );
336 track.SetLayer( arc->GetLayer() );
337
338 createTrackWithMargin( &track, aDstContainer, aLayer, aMargin );
339 return;
340 }
341
342 VECTOR2I center( arc->GetCenter() );
343 EDA_ANGLE arc_angle = arc->GetAngle();
344 double radius = arc->GetRadius();
345 int arcsegcount = GetArcToSegmentCount( KiROUND( radius ), arc->GetMaxError(), arc_angle );
346 int circlesegcount;
347
348 // Avoid arcs that cannot be drawn
349 if( radius < std::numeric_limits<double>::min() || arc_angle.IsZero() )
350 break;
351
352 // We need a circle to segment count. However, the arc angle can be small, and the
353 // radius very big. so we calculate a reasonable value for circlesegcount.
354 if( arcsegcount <= 1 ) // The arc will be approximated by a segment
355 {
356 circlesegcount = 1;
357 }
358 else
359 {
360 circlesegcount = KiROUND( arcsegcount * 360.0 / std::abs( arc_angle.AsDegrees() ) );
361 circlesegcount = std::clamp( circlesegcount, 1, 128 );
362 }
363
364 createArcSegments( center, arc->GetStart(), arc_angle, circlesegcount,
365 arc->GetWidth() + aMargin * 2, aDstContainer, *arc );
366 break;
367 }
368
369 case PCB_TRACE_T: // Track is a usual straight segment
370 {
371 float width3DU = TO_3DU( aTrack->GetWidth() + aMargin * 2 );
372 addROUND_SEGMENT_2D( aDstContainer, start3DU, end3DU, width3DU, *aTrack );
373 break;
374 }
375
376 default:
377 break;
378 }
379}
380
381
383 PCB_LAYER_ID aLayer, const VECTOR2I& aMargin ) const
384{
385 SHAPE_POLY_SET poly;
386 VECTOR2I clearance = aMargin;
387
388 // Our shape-based builder can't handle negative or differing x:y clearance values (the
389 // former are common for solder paste while the later get generated when a relative paste
390 // margin is used with an oblong pad). So we apply this huge hack and fake a larger pad to
391 // run the general-purpose polygon builder on.
392 // Of course being a hack it falls down when dealing with custom shape pads (where the size
393 // is only the size of the anchor), so for those we punt and just use aMargin.x.
394
395 if( ( clearance.x < 0 || clearance.x != clearance.y ) && aPad->GetShape( aLayer ) != PAD_SHAPE::CUSTOM )
396 {
397 VECTOR2I dummySize = VECTOR2I( aPad->GetSize( aLayer ) ) + clearance + clearance;
398
399 if( dummySize.x <= 0 || dummySize.y <= 0 )
400 return;
401
402 PAD dummy( *aPad );
403 dummy.SetSize( aLayer, VECTOR2I( dummySize.x, dummySize.y ) );
404 dummy.TransformShapeToPolygon( poly, aLayer, 0, aPad->GetMaxError(), ERROR_INSIDE );
405 clearance = { 0, 0 };
406 }
407 else if( aPad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
408 {
409 // A custom pad can have many complex subshape items. To avoid issues, use its
410 // final polygon shape, not its basic shape set. One cannot apply the clearance
411 // to each subshape: it does no work
412 aPad->TransformShapeToPolygon( poly, aLayer, 0, aPad->GetMaxError() );
413 }
414 else
415 {
416 auto padShapes = std::static_pointer_cast<SHAPE_COMPOUND>( aPad->GetEffectiveShape( aLayer ) );
417
418 for( const SHAPE* shape : padShapes->Shapes() )
419 {
420 switch( shape->Type() )
421 {
422 case SH_SEGMENT:
423 {
424 const SHAPE_SEGMENT* seg = static_cast<const SHAPE_SEGMENT*>( shape );
425
426 addROUND_SEGMENT_2D( aContainer,
427 TO_SFVEC2F( seg->GetSeg().A ),
428 TO_SFVEC2F( seg->GetSeg().B ),
429 TO_3DU( seg->GetWidth() + clearance.x * 2 ),
430 *aPad );
431 break;
432 }
433
434 case SH_CIRCLE:
435 {
436 const SHAPE_CIRCLE* circle = static_cast<const SHAPE_CIRCLE*>( shape );
437
438 addFILLED_CIRCLE_2D( aContainer,
439 TO_SFVEC2F( circle->GetCenter() ),
440 TO_3DU( circle->GetRadius() + clearance.x ),
441 *aPad );
442 break;
443 }
444
445 case SH_RECT:
446 {
447 const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>( shape );
448
449 poly.NewOutline();
450 poly.Append( rect->GetPosition() );
451 poly.Append( rect->GetPosition().x + rect->GetSize().x, rect->GetPosition().y );
452 poly.Append( rect->GetPosition() + rect->GetSize() );
453 poly.Append( rect->GetPosition().x, rect->GetPosition().y + rect->GetSize().y );
454 break;
455 }
456
457 case SH_SIMPLE:
458 poly.AddOutline( static_cast<const SHAPE_SIMPLE*>( shape )->Vertices() );
459 break;
460
461 case SH_POLY_SET:
462 poly.Append( *static_cast<const SHAPE_POLY_SET*>( shape ) );
463 break;
464
465 case SH_ARC:
466 {
467 const SHAPE_ARC* arc = static_cast<const SHAPE_ARC*>( shape );
469
470 for( int i = 0; i < l.SegmentCount(); i++ )
471 {
472 SHAPE_SEGMENT seg( l.Segment( i ).A, l.Segment( i ).B, arc->GetWidth() );
473
474 addROUND_SEGMENT_2D( aContainer,
475 TO_SFVEC2F( seg.GetSeg().A ),
476 TO_SFVEC2F( seg.GetSeg().B ),
477 TO_3DU( arc->GetWidth() + clearance.x * 2 ),
478 *aPad );
479 }
480
481 break;
482 }
483
484 case SH_ELLIPSE:
485 {
486 const SHAPE_ELLIPSE* ellipse = static_cast<const SHAPE_ELLIPSE*>( shape );
487 SHAPE_LINE_CHAIN l = ellipse->ConvertToPolyline( aPad->GetMaxError() );
488 const int width = ellipse->GetWidth();
489
490 for( int i = 0; i < l.SegmentCount(); i++ )
491 {
492 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( l.Segment( i ).A ), TO_SFVEC2F( l.Segment( i ).B ),
493 TO_3DU( width + clearance.x * 2 ), *aPad );
494 }
495
496 break;
497 }
498
499 default:
500 UNIMPLEMENTED_FOR( SHAPE_TYPE_asString( shape->Type() ) );
501 break;
502 }
503 }
504 }
505
506 if( !poly.IsEmpty() )
507 {
508 if( clearance.x )
510
511 // Add the PAD polygon
512 ConvertPolygonToTriangles( poly, *aContainer, m_biuTo3Dunits, *aPad );
513 }
514}
515
516
518 int aInflateValue )
519{
520 if( !aPad->HasHole() )
521 {
522 wxLogTrace( m_logTrace, wxT( "BOARD_ADAPTER::createPadHole pad has no hole" ) );
523 return;
524 }
525
526 std::shared_ptr<SHAPE_SEGMENT> slot = aPad->GetEffectiveHoleShape();
527
528 addROUND_SEGMENT_2D( aDstContainer,
529 TO_SFVEC2F( slot->GetSeg().A ),
530 TO_SFVEC2F( slot->GetSeg().B ),
531 TO_3DU( slot->GetWidth() + aInflateValue * 2 ),
532 *aPad );
533}
534
535
536void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aContainer,
537 PCB_LAYER_ID aLayerId )
538{
539 for( PAD* pad : aFootprint->Pads() )
540 {
541 if( !pad->IsOnLayer( aLayerId ) )
542 continue;
543
544 if( IsCopperLayer( aLayerId ) )
545 {
546 // Skip pad annulus when there isn't one (note: this is more discerning than
547 // pad->IsOnLayer(), which doesn't check for NPTH pads with holes that consume
548 // the entire pad).
549 if( !pad->IsOnCopperLayer() )
550 continue;
551
552 // Skip pad annulus when not connected on this layer (if removing is enabled)
553 if( !pad->FlashLayer( aLayerId ) )
554 continue;
555 }
556
557 VECTOR2I margin( 0, 0 );
558
559 switch( aLayerId )
560 {
561 case F_Mask:
562 case B_Mask:
563 margin.x += pad->GetSolderMaskExpansion( aLayerId );
564 margin.y += pad->GetSolderMaskExpansion( aLayerId );
565 break;
566
567 case F_Paste:
568 case B_Paste:
569 margin += pad->GetSolderPasteMargin( aLayerId );
570 break;
571
572 default:
573 break;
574 }
575
576 createPadWithMargin( pad, aContainer, aLayerId, margin );
577 }
578}
579
580
581// based on TransformArcToPolygon function from
582// common/convert_basic_shapes_to_polygon.cpp
583void BOARD_ADAPTER::createArcSegments( const VECTOR2I& aCentre, const VECTOR2I& aStart,
584 const EDA_ANGLE& aArcAngle, int aCircleToSegmentsCount,
585 int aWidth, CONTAINER_2D_BASE* aContainer,
586 const BOARD_ITEM& aOwner )
587{
588 // Don't attempt to render degenerate shapes
589 if( aWidth == 0 )
590 return;
591
592 VECTOR2I arc_start, arc_end;
593 EDA_ANGLE arcAngle( aArcAngle );
594 EDA_ANGLE delta = ANGLE_360 / aCircleToSegmentsCount; // rotate angle
595
596 arc_end = arc_start = aStart;
597
598 if( arcAngle != ANGLE_360 )
599 RotatePoint( arc_end, aCentre, -arcAngle );
600
601 if( arcAngle < ANGLE_0 )
602 {
603 std::swap( arc_start, arc_end );
604 arcAngle = -arcAngle;
605 }
606
607 // Compute the ends of segments and creates poly
608 VECTOR2I curr_end = arc_start;
609 VECTOR2I curr_start = arc_start;
610
611 for( EDA_ANGLE ii = delta; ii < arcAngle; ii += delta )
612 {
613 curr_end = arc_start;
614 RotatePoint( curr_end, aCentre, -ii );
615
616 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( curr_start ), TO_SFVEC2F( curr_end ),
617 TO_3DU( aWidth ), aOwner );
618
619 curr_start = curr_end;
620 }
621
622 if( curr_end != arc_end )
623 {
624 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( curr_end ), TO_SFVEC2F( arc_end ),
625 TO_3DU( aWidth ), aOwner );
626 }
627}
628
629
630void BOARD_ADAPTER::addShape( const PCB_SHAPE* aShape, CONTAINER_2D_BASE* aContainer,
631 const BOARD_ITEM* aOwner, PCB_LAYER_ID aLayer )
632{
633 LINE_STYLE lineStyle = aShape->GetStroke().GetLineStyle();
634 int linewidth = aShape->GetWidth();
635 int margin = 0;
636 bool isSolidFill = aShape->IsSolidFill();
637 bool isHatchedFill = aShape->IsHatchedFill();
638
639 if( IsSolderMaskLayer( aLayer )
640 && aShape->HasSolderMask()
641 && ( aShape->IsOnLayer( F_Cu ) || aShape->IsOnLayer( B_Cu ) ) )
642 {
643 margin = aShape->GetSolderMaskExpansion();
644 linewidth += margin * 2;
645 lineStyle = LINE_STYLE::SOLID;
646
647 if( isHatchedFill )
648 {
649 isSolidFill = true;
650 isHatchedFill = false;
651 }
652 }
653
654 float linewidth3DU = TO_3DU( linewidth );
655
656 if( lineStyle <= LINE_STYLE::FIRST_TYPE || isSolidFill )
657 {
658 switch( aShape->GetShape() )
659 {
660 case SHAPE_T::CIRCLE:
661 {
662 SFVEC2F center3DU = TO_SFVEC2F( aShape->GetCenter() );
663 float innerR3DU = TO_3DU( aShape->GetRadius() ) - linewidth3DU / 2.0;
664 float outerR3DU = TO_3DU( aShape->GetRadius() ) + linewidth3DU / 2.0;
665
666 if( isSolidFill || innerR3DU <= 0.0 )
667 {
668 // For a filled circle with a line style not a simple line, ignore line width
669 // the outline will be drawn later
670 if( lineStyle > LINE_STYLE::FIRST_TYPE )
671 addFILLED_CIRCLE_2D( aContainer, center3DU, TO_3DU( aShape->GetRadius() ), *aOwner );
672 else
673 addFILLED_CIRCLE_2D( aContainer, center3DU, outerR3DU, *aOwner );
674 }
675 else
676 addRING_2D( aContainer, center3DU, innerR3DU, outerR3DU, *aOwner );
677
678 break;
679 }
680
682 if( isSolidFill )
683 {
684 SHAPE_POLY_SET polyList;
685
686 // For a filled rect with a line style not a simple line, ignore line width
687 // the outline will be drawn later
688 bool ignoreLineWidth = lineStyle > LINE_STYLE::FIRST_TYPE;
689
690 aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, aShape->GetMaxError(),
691 ERROR_INSIDE, ignoreLineWidth );
692
693 polyList.Simplify();
694
695 if( margin != 0 )
696 {
697 polyList.Inflate( margin, CORNER_STRATEGY::ROUND_ALL_CORNERS, aShape->GetMaxError() );
698 }
699
700 ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
701 }
702 else
703 {
704 if( aShape->GetCornerRadius() > 0 )
705 {
706 ROUNDRECT rr( SHAPE_RECT( aShape->GetPosition(),
707 aShape->GetRectangleWidth(),
708 aShape->GetRectangleHeight() ),
709 aShape->GetCornerRadius() );
710 SHAPE_POLY_SET poly;
711 rr.TransformToPolygon( poly, aShape->GetMaxError() );
712 SHAPE_LINE_CHAIN& r_outline = poly.Outline( 0 );
713 r_outline.SetClosed( true );
714
715 for( int ii = 0; ii < r_outline.PointCount(); ii++ )
716 {
717 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( r_outline.CPoint( ii ) ),
718 TO_SFVEC2F( r_outline.CPoint( ii+1 ) ),
719 linewidth3DU, *aOwner );
720 }
721
722 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( r_outline.CLastPoint() ),
723 TO_SFVEC2F( r_outline.CPoint( 0 ) ), linewidth3DU, *aOwner );
724 }
725 else
726 {
727 std::vector<VECTOR2I> pts = aShape->GetRectCorners();
728
729 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[0] ), TO_SFVEC2F( pts[1] ),
730 linewidth3DU, *aOwner );
731 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[1] ), TO_SFVEC2F( pts[2] ),
732 linewidth3DU, *aOwner );
733 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[2] ), TO_SFVEC2F( pts[3] ),
734 linewidth3DU, *aOwner );
735 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[3] ), TO_SFVEC2F( pts[0] ),
736 linewidth3DU, *aOwner );
737 }
738 }
739 break;
740
741 case SHAPE_T::ARC:
742 {
743 unsigned int segCount = GetCircleSegmentCount( aShape->GetBoundingBox().GetSizeMax() );
744
745 EDA_ANGLE origStartAngle;
746 EDA_ANGLE endAngle;
747 aShape->CalcArcAngles( origStartAngle, endAngle );
748
749 EDA_ANGLE startAngle = origStartAngle;
750 EDA_ANGLE arcAngle = endAngle - startAngle;
751
752 if( aShape->ShortenArcForEndings( startAngle, arcAngle, aShape->GetRadius(), linewidth ) )
753 {
754 // Rotate the original start point by the angular offset from shortening.
755 VECTOR2I arcStart = aShape->GetStart();
756 RotatePoint( arcStart, aShape->GetCenter(), origStartAngle - startAngle );
757
758 createArcSegments( aShape->GetCenter(), arcStart, arcAngle, segCount, linewidth, aContainer,
759 *aOwner );
760 }
761
762 break;
763 }
764
765 case SHAPE_T::SEGMENT:
766 {
767 VECTOR2I segStart = aShape->GetStart();
768 VECTOR2I segEnd = aShape->GetEnd();
769
770 if( EDA_SHAPE::ShortenSegmentForEndings( segStart, segEnd, aShape->GetStartEnding(),
771 aShape->GetEndEnding(), linewidth ) )
772 {
773 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( segStart ), TO_SFVEC2F( segEnd ), linewidth3DU,
774 *aOwner );
775 }
776
777 break;
778 }
779
780 case SHAPE_T::BEZIER:
781 {
782 std::vector<VECTOR2D> pts = aShape->ShortenedBezierPolyline( linewidth );
783
784 for( size_t i = 0; i + 1 < pts.size(); i++ )
785 {
786 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( VECTOR2I( pts[i] ) ), TO_SFVEC2F( VECTOR2I( pts[i + 1] ) ),
787 linewidth3DU, *aOwner );
788 }
789
790 break;
791 }
792
793 case SHAPE_T::POLY:
794 {
795 if( isSolidFill )
796 {
797 SHAPE_POLY_SET polyList;
798
799 // For a filled poly with a line style not a simple line, ignore line width
800 // the outline will be drawn later
801 bool ignoreLineWidth = lineStyle > LINE_STYLE::FIRST_TYPE;
802
803 aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, aShape->GetMaxError(),
804 ERROR_INSIDE, ignoreLineWidth );
805
806 // Some polygons can be a bit complex (especially when coming from a
807 // picture of a text converted to a polygon
808 // So call Simplify before calling ConvertPolygonToTriangles, just in case.
809 polyList.Simplify();
810
811 if( polyList.IsEmpty() ) // Just for caution
812 break;
813
814 if( margin != 0 )
815 {
818
819 polyList.Inflate( margin, cornerStr, aShape->GetMaxError() );
820 }
821
822 ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
823 }
824 else
825 {
826 const SHAPE_POLY_SET& polyShape = aShape->GetPolyShape();
827
828 for( int outlineIdx = 0; outlineIdx < polyShape.OutlineCount(); ++outlineIdx )
829 {
830 const SHAPE_LINE_CHAIN& outline = polyShape.COutline( outlineIdx );
831
832 if( outline.PointCount() < 2 )
833 continue;
834
835 std::vector<VECTOR2I> pts;
836
837 if( aShape->GetShortenedBodyPolyPoints( outline, outlineIdx, pts, linewidth ) )
838 {
839 for( size_t i = 0; i + 1 < pts.size(); i++ )
840 {
841 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[i] ), TO_SFVEC2F( pts[i + 1] ),
842 linewidth3DU, *aOwner );
843 }
844
845 if( outline.IsClosed() )
846 {
847 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts.back() ), TO_SFVEC2F( pts.front() ),
848 linewidth3DU, *aOwner );
849 }
850 }
851 }
852 }
853 break;
854 }
855
856 case SHAPE_T::ELLIPSE:
857 if( isSolidFill )
858 {
859 SHAPE_POLY_SET polyList;
860
861 aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, aShape->GetMaxError(), ERROR_INSIDE );
862
863 polyList.Simplify();
864
865 if( polyList.IsEmpty() )
866 break;
867
868 if( margin != 0 )
869 {
872 polyList.Inflate( margin, cornerStr, aShape->GetMaxError() );
873 }
874
875 ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
876 }
877 else
878 {
879 // Hatched fill: draw only the elliptical outline so the hatch polygons
880 // added below remain visible.
881 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
882
883 for( SHAPE* shape : shapes )
884 {
885 if( shape->Type() == SH_SEGMENT )
886 {
887 const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape )->GetSeg();
888 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( seg.A ), TO_SFVEC2F( seg.B ), linewidth3DU,
889 *aOwner );
890 }
891 }
892
893 for( SHAPE* shape : shapes )
894 delete shape;
895 }
896
897 break;
898
900 {
901 const VECTOR2D center( aShape->GetEllipseCenter() );
902 const int majorR = aShape->GetEllipseMajorRadius();
903 const int minorR = aShape->GetEllipseMinorRadius();
904 const EDA_ANGLE& rot = aShape->GetEllipseRotation();
905 const EDA_ANGLE& start = aShape->GetEllipseStartAngle();
906 const EDA_ANGLE& end = aShape->GetEllipseEndAngle();
907 SHAPE_ELLIPSE ellipse( center, majorR, minorR, rot, start, end );
909 std::vector<VECTOR2I> pts;
910
911 if( aShape->GetShortenedBodyPolyPoints( chain, 0, pts, linewidth ) )
912 {
913 for( size_t i = 0; i + 1 < pts.size(); i++ )
914 {
915 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[i] ), TO_SFVEC2F( pts[i + 1] ), linewidth3DU,
916 *aOwner );
917 }
918 }
919
920 break;
921 }
922
923 default:
924 wxFAIL_MSG( wxT( "BOARD_ADAPTER::addShape no implementation for " ) + aShape->SHAPE_T_asString() );
925 break;
926 }
927 }
928
929 if( lineStyle > LINE_STYLE::FIRST_TYPE )
930 {
931 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapesForStroking( linewidth );
932 SFVEC2F a3DU;
933 SFVEC2F b3DU;
934
935 const PCB_PLOT_PARAMS& plotParams = aShape->GetBoard()->GetPlotOptions();
936 KIGFX::PCB_RENDER_SETTINGS renderSettings;
937
938 renderSettings.SetDashLengthRatio( plotParams.GetDashedLineDashRatio() );
939 renderSettings.SetGapLengthRatio( plotParams.GetDashedLineGapRatio() );
940
941 for( SHAPE* shape : shapes )
942 {
943 STROKE_PARAMS::Stroke( shape, lineStyle, aShape->GetWidth(), &renderSettings,
944 [&]( const VECTOR2I& a, const VECTOR2I& b )
945 {
946 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( a ), TO_SFVEC2F( b ), linewidth3DU, *aOwner );
947 } );
948 }
949
950 for( SHAPE* shape : shapes )
951 delete shape;
952 }
953
954 // Render line endings.
957 {
958 EDA_ANGLE startTangent, endTangent;
959 aShape->GetEndingTangents( startTangent, endTangent, aShape->GetWidth() );
960
961 VECTOR2I startPt, endPt;
962
963 auto addEnding =
964 [&]( const LINE_ENDING& aEnding, const VECTOR2I& aPoint, const EDA_ANGLE& aTangent )
965 {
966 if( aEnding.GetStyle() == LINE_ENDING_STYLE::NONE )
967 return;
968
969 std::vector<VECTOR2I> pts;
970 aEnding.GetShapes( aPoint, aTangent, linewidth, pts );
971
972 if( pts.empty() )
973 return;
974
975 if( aEnding.GetStyle() == LINE_ENDING_STYLE::ARROW_OPEN )
976 {
977 // Open V-shape: draw as thick line segments, not a filled polygon.
978 int strokeW = aEnding.GetStrokeWidth() > 0 ? aEnding.GetStrokeWidth() : linewidth;
979 float stroke3DU = TO_3DU( strokeW );
980
981 for( size_t ii = 0; ii + 1 < pts.size(); ii++ )
982 {
983 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[ii] ), TO_SFVEC2F( pts[ii + 1] ),
984 stroke3DU, *aOwner );
985 }
986 }
987 else
988 {
989 if( aEnding.GetStrokeWidth() > 0 )
990 {
991 float stroke3DU = TO_3DU( aEnding.GetStrokeWidth() );
992
993 for( size_t ii = 0; ii < pts.size(); ii++ )
994 {
995 size_t next = ( ii + 1 ) % pts.size();
996
997 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[ii] ), TO_SFVEC2F( pts[next] ),
998 stroke3DU, *aOwner );
999 }
1000 }
1001
1002 SHAPE_POLY_SET polySet;
1003 polySet.NewOutline();
1004
1005 for( const VECTOR2I& pt : pts )
1006 polySet.Append( pt );
1007
1008 ConvertPolygonToTriangles( polySet, *aContainer, m_biuTo3Dunits, *aOwner );
1009 }
1010 };
1011
1012 if( aShape->GetLineEndingEndpoints( startPt, endPt ) )
1013 {
1014 addEnding( aShape->GetStartEnding(), startPt, startTangent );
1015 addEnding( aShape->GetEndEnding(), endPt, endTangent );
1016 }
1017 }
1018
1019 if( isHatchedFill )
1020 ConvertPolygonToTriangles( aShape->GetHatching(), *aContainer, m_biuTo3Dunits, *aOwner );
1021}
1022
1023
1024void BOARD_ADAPTER::addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
1025 const BOARD_ITEM* aOwner )
1026{
1027 addText( aTextBox, aContainer, aOwner );
1028
1029 if( !aTextBox->IsBorderEnabled() )
1030 return;
1031
1032 // we use the box polygonal shape to honor the text box rotation and box line style
1033 PCB_SHAPE tb_box = aTextBox->GetPolygonalBoxShape();
1034 addShape( &tb_box, aContainer, aOwner, UNDEFINED_LAYER );
1035}
1036
1037
1038void BOARD_ADAPTER::addTable( const PCB_TABLE* aTable, CONTAINER_2D_BASE* aContainer,
1039 const BOARD_ITEM* aOwner )
1040{
1041 aTable->DrawBorders(
1042 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB, const STROKE_PARAMS& stroke )
1043 {
1044 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( ptA ), TO_SFVEC2F( ptB ),
1045 TO_3DU( stroke.GetWidth() ), *aOwner );
1046 } );
1047
1048 for( PCB_TABLECELL* cell : aTable->GetCells() )
1049 {
1050 if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
1051 addText( cell, aContainer, aOwner );
1052 }
1053}
1054
1055
1057 PCB_LAYER_ID aLayerId )
1058{
1059 // This convert the poly in outline and holes
1060 ConvertPolygonToTriangles( *aZone->GetFilledPolysList( aLayerId ), *aContainer, m_biuTo3Dunits, *aZone );
1061}
1062
1063
1065 CONTAINER_2D_BASE* aContainer, int aWidth )
1066{
1067 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE ) // Draw a ring
1068 {
1069 const SFVEC2F center3DU = TO_SFVEC2F( aPad->ShapePos( aLayer ) );
1070 const int radius = aPad->GetSize( aLayer ).x / 2;
1071 const float inner_radius3DU = TO_3DU( radius - aWidth / 2.0 );
1072 const float outer_radius3DU = TO_3DU( radius + aWidth / 2.0 );
1073
1074 addRING_2D( aContainer, center3DU, inner_radius3DU, outer_radius3DU, *aPad );
1075 }
1076 else
1077 {
1078 // For other shapes, add outlines as thick segments in polygon buffer
1079 const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
1080 const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
1081
1082 for( int j = 0; j < path.PointCount(); j++ )
1083 {
1084 SFVEC2F start3DU = TO_SFVEC2F( path.CPoint( j ) );
1085 SFVEC2F end3DU = TO_SFVEC2F( path.CPoint( j + 1 ) );
1086
1087 addROUND_SEGMENT_2D( aContainer, start3DU, end3DU, TO_3DU( aWidth ), *aPad );
1088 }
1089 }
1090}
@ ERROR_INSIDE
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
void addPads(const FOOTPRINT *aFootprint, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId)
void createTrackWithMargin(const PCB_TRACK *aTrack, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayer, int aMargin=0)
void addSolidAreasShapes(const ZONE *aZone, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId)
void addFootprintShapes(const FOOTPRINT *aFootprint, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayerId, const std::bitset< LAYER_3D_END > &aVisibilityFlags)
void createArcSegments(const VECTOR2I &aCentre, const VECTOR2I &aStart, const EDA_ANGLE &aArcAngle, int aCircleToSegmentsCount, int aWidth, CONTAINER_2D_BASE *aContainer, const BOARD_ITEM &aOwner)
void createPadWithMargin(const PAD *aPad, CONTAINER_2D_BASE *aDstContainer, PCB_LAYER_ID aLayer, const VECTOR2I &aMargin) const
void addBarCode(const PCB_BARCODE *aBarCode, CONTAINER_2D_BASE *aDstContainer, const BOARD_ITEM *aOwner)
void buildPadOutlineAsSegments(const PAD *aPad, PCB_LAYER_ID aLayer, CONTAINER_2D_BASE *aDstContainer, int aWidth)
void addTable(const PCB_TABLE *aTable, CONTAINER_2D_BASE *aContainer, const BOARD_ITEM *aOwner)
void createPadHoleShape(const PAD *aPad, CONTAINER_2D_BASE *aDstContainer, int aInflateValue)
unsigned int GetCircleSegmentCount(float aDiameter3DU) const
void addShape(const PCB_SHAPE *aShape, CONTAINER_2D_BASE *aContainer, const BOARD_ITEM *aOwner, PCB_LAYER_ID aLayer)
double m_biuTo3Dunits
Scale factor to convert board internal units.
void addText(const EDA_TEXT *aText, CONTAINER_2D_BASE *aDstContainer, const BOARD_ITEM *aOwner)
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:85
virtual bool IsKnockout() const
Definition board_item.h:423
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
virtual void TransformShapeToPolySet(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, KIGFX::RENDER_SETTINGS *aRenderSettings=nullptr) const
Convert the item shape to a polyset.
Definition board_item.h:560
const KIFONT::METRICS & GetFontMetrics() const
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:267
int GetMaxError() const
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition board.h:1023
constexpr int GetSizeMax() const
Definition box2.h:232
void Add(OBJECT_2D *aObject)
double AsDegrees() const
Definition eda_angle.h:115
bool IsZero() const
Definition eda_angle.h:135
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
static bool ShortenSegmentForEndings(VECTOR2I &aStart, VECTOR2I &aEnd, const LINE_ENDING &aStartEnding, const LINE_ENDING &aEndEnding, int aLineWidth)
Shorten a segment body for line endings.
int GetEllipseMinorRadius() const
Definition eda_shape.h:403
const VECTOR2I & GetEllipseCenter() const
Definition eda_shape.h:385
const SHAPE_POLY_SET & GetHatching() const
EDA_ANGLE GetEllipseEndAngle() const
Definition eda_shape.h:431
int GetEllipseMajorRadius() const
Definition eda_shape.h:394
int GetRectangleWidth() const
virtual std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const
Make a set of SHAPE objects representing the EDA_SHAPE.
Definition eda_shape.h:565
SHAPE_POLY_SET & GetPolyShape()
void GetEndingTangents(EDA_ANGLE &aStartTangent, EDA_ANGLE &aEndTangent, int aLineWidth=0) const
Compute outward-facing tangent angles at the start and end of the shape.
void CalcArcAngles(EDA_ANGLE &aStartAngle, EDA_ANGLE &aEndAngle) const
Calc arc start and end angles such that aStartAngle < aEndAngle.
EDA_ANGLE GetEllipseRotation() const
Definition eda_shape.h:412
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:177
std::vector< SHAPE * > MakeEffectiveShapesForStroking(int aLineWidth=-1) const
Make a set of SHAPE objects to hand to STROKE_PARAMS::Stroke().
bool GetShortenedBodyPolyPoints(const SHAPE_LINE_CHAIN &aOutline, int aOutlineIdx, std::vector< VECTOR2I > &aPoints, int aLineWidth) const
Copy an outline and apply line-ending body shortening when applicable.
bool IsHatchedFill() const
Definition eda_shape.h:132
bool GetLineEndingEndpoints(VECTOR2I &aStartPoint, VECTOR2I &aEndPoint) const
Return the source endpoints used to place line endings.
bool IsSolidFill() const
Definition eda_shape.h:125
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:333
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:283
std::vector< VECTOR2I > GetRectCorners() const
EDA_ANGLE GetEllipseStartAngle() const
Definition eda_shape.h:422
const LINE_ENDING & GetStartEnding() const
Definition eda_shape.h:179
wxString SHAPE_T_asString() const
int GetRectangleHeight() const
bool ShortenArcForEndings(EDA_ANGLE &aStartAngle, EDA_ANGLE &aArcAngle, double aRadius, int aLineWidth) const
Shorten an arc body for line endings.
std::vector< VECTOR2D > ShortenedBezierPolyline(int aLineWidth) const
Return the flattened Bezier polyline after line-ending shortening.
const LINE_ENDING & GetEndEnding() const
Definition eda_shape.h:185
int GetCornerRadius() const
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
bool IsItalic() const
Definition eda_text.h:200
KIFONT::FONT * GetFont() const
Definition eda_text.h:286
std::vector< std::unique_ptr< KIFONT::GLYPH > > * GetRenderCache(const KIFONT::FONT *aFont, const wxString &forResolvedText, const VECTOR2I &aOffset={ 0, 0 }) const
Definition eda_text.cpp:683
virtual EDA_ANGLE GetDrawRotation() const
Definition eda_text.h:425
virtual VECTOR2I GetDrawPos() const
Definition eda_text.h:426
virtual wxString GetShownText(RESOLUTION_CONTEXT aContext, int aDepth=0) const
Return the string actually shown after processing of the base text.
Definition eda_text.h:128
const TEXT_ATTRIBUTES & GetAttributes() const
Definition eda_text.h:270
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
Definition eda_text.cpp:427
bool IsBold() const
Definition eda_text.h:215
std::deque< PAD * > & Pads()
Definition footprint.h:355
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
DRAWINGS & GraphicalItems()
Definition footprint.h:358
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:94
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition font.cpp:144
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics, std::optional< VECTOR2I > aMousePos=std::nullopt, wxString *aActiveUrl=nullptr) const
Draw a string.
Definition font.cpp:243
PCB specific render settings.
Definition pcb_painter.h:94
void SetGapLengthRatio(double aRatio)
void SetDashLengthRatio(double aRatio)
Decorative shape (arrowhead, circle, square) at the start or end of a graphic line,...
Definition line_ending.h:62
LINE_ENDING_STYLE GetStyle() const
Definition line_ending.h:81
void GetShapes(const VECTOR2I &aPoint, const EDA_ANGLE &aTangent, int aLineWidth, std::vector< VECTOR2I > &aPolygon) const
Generate ending geometry as polygon vertices at the given point and direction.
int GetStrokeWidth() const
Outline stroke width.
Definition pad.h:61
std::shared_ptr< SHAPE_SEGMENT > GetEffectiveHoleShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Return a SHAPE_SEGMENT object representing the pad's hole.
Definition pad.cpp:1361
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool aIgnoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition pad.cpp:3136
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:205
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
Definition pad.cpp:297
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:1239
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition pad.cpp:1252
bool HasHole() const override
Definition pad.h:113
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1906
bool IsDegenerated(int aThreshold=5) const
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_track.h:307
double GetRadius() const
EDA_ANGLE GetAngle() const
Abstract dimension API.
int GetLineThickness() const
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.
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_shape.h:80
int GetWidth() const override
bool HasSolderMask() const
Definition pcb_shape.h:347
int GetSolderMaskExpansion() const
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.
STROKE_PARAMS GetStroke() const override
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
VECTOR2I GetPosition() const override
Definition pcb_shape.h:78
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:70
std::vector< PCB_TABLECELL * > GetCells() const
Definition pcb_table.h:165
void DrawBorders(const std::function< void(const VECTOR2I &aPt1, const VECTOR2I &aPt2, const STROKE_PARAMS &aStroke)> &aCallback) const
bool IsBorderEnabled() const
Tests whether the border is disabled, as configured by the stroke.
PCB_SHAPE GetPolygonalBoxShape() const
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:94
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:97
const VECTOR2I & GetStart() const
Definition pcb_track.h:98
const VECTOR2I & GetEnd() const
Definition pcb_track.h:95
virtual void SetWidth(int aWidth)
Definition pcb_track.h:91
virtual int GetWidth() const
Definition pcb_track.h:92
A round rectangle shape, based on a rectangle and a radius.
Definition roundrect.h:32
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aMaxError) const
Get the polygonal representation of the roundrect.
Definition roundrect.cpp:79
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
int GetWidth() const override
Definition shape_arc.h:215
const SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError=DefaultAccuracyForPCB(), int *aActualError=nullptr) const
Construct a SHAPE_LINE_CHAIN of segments from a given arc.
int GetRadius() const
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
bool IsClosed() const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
SEG Segment(int aIndex) const
Return a copy of the aIndex-th segment in the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
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)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
int OutlineCount() const
Return the number of outlines in the set.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const VECTOR2I & GetPosition() const
Definition shape_rect.h:164
const VECTOR2I GetSize() const
Definition shape_rect.h:172
const SEG & GetSeg() const
int GetWidth() const override
Represent a simple polygon consisting of a zero-thickness closed chain of connected line segments.
An abstract shape on 2D plane.
Definition shape.h:124
virtual int GetWidth() const
Definition shape.h:299
Simple container to manage line stroke parameters.
int GetWidth() const
LINE_STYLE GetLineStyle() const
static void Stroke(const SHAPE *aShape, LINE_STYLE aLineStyle, int aWidth, const KIGFX::RENDER_SETTINGS *aRenderSettings, const std::function< void(const VECTOR2I &a, const VECTOR2I &b)> &aStroker)
EDA_ORIENTATION m_Angle
Handle a list of polygons defining a copper zone.
Definition zone.h:70
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition zone.h:699
@ FOR_CANVAS
Definition common.h:92
CORNER_STRATEGY
define how inflate transform build inflated polygon
@ ROUND_ALL_CORNERS
All angles are rounded.
@ ALLOW_ACUTE_CORNERS
just inflate the polygon. Acute angles create spikes
#define TO_3DU(x)
void addFILLED_CIRCLE_2D(CONTAINER_2D_BASE *aContainer, const SFVEC2F &aCenter, float aRadius, const BOARD_ITEM &aBoardItem)
#define TO_SFVEC2F(vec)
void addROUND_SEGMENT_2D(CONTAINER_2D_BASE *aContainer, const SFVEC2F &aStart, const SFVEC2F &aEnd, float aWidth, const BOARD_ITEM &aBoardItem)
void addRING_2D(CONTAINER_2D_BASE *aContainer, const SFVEC2F &aCenter, float aInnerRadius, float aOuterRadius, const BOARD_ITEM &aBoardItem)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:454
@ ELLIPSE
Definition eda_shape.h:62
@ SEGMENT
Definition eda_shape.h:56
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
@ ELLIPSE_ARC
Definition eda_shape.h:63
a few functions useful in geometry calculations.
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
static const wxChar * m_logTrace
Trace mask used to enable or disable debug output for this class.
bool IsSolderMaskLayer(int aLayer)
Definition layer_ids.h:812
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:741
@ LAYER_FP_REFERENCES
Show footprints references (when texts are visible).
Definition layer_ids.h:262
@ LAYER_FP_TEXT
Definition layer_ids.h:236
@ LAYER_FP_VALUES
Show footprints values (when texts are visible).
Definition layer_ids.h:259
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ F_Paste
Definition layer_ids.h:100
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ F_Mask
Definition layer_ids.h:93
@ B_Paste
Definition layer_ids.h:101
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ F_Cu
Definition layer_ids.h:60
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
BARCODE class definition.
CITER next(CITER it)
Definition ptree.cpp:120
bool Is_segment_a_circle(const SFVEC2F &aStart, const SFVEC2F &aEnd)
Check if segment start and end is very close to each other.
@ SH_POLY_SET
set of polygons (with holes, etc.)
Definition shape.h:48
@ SH_RECT
axis-aligned rectangle
Definition shape.h:43
@ SH_CIRCLE
circle
Definition shape.h:46
@ SH_SIMPLE
simple polygon
Definition shape.h:47
@ SH_ELLIPSE
ellipse or elliptical arc
Definition shape.h:53
@ SH_SEGMENT
line segment
Definition shape.h:44
@ SH_ARC
circular arc
Definition shape.h:50
static wxString SHAPE_TYPE_asString(SHAPE_TYPE a)
Definition shape.h:56
std::vector< FAB_LAYER_COLOR > dummy
LINE_STYLE
Dashed line types.
std::string path
VECTOR2I center
const SHAPE_LINE_CHAIN chain
int radius
VECTOR2I end
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
int clearance
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)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:98
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:95
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:96
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:94
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:97
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
glm::vec2 SFVEC2F
Definition xv3d_types.h:38