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, aFootprint );
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 if( !aShape->ShortenArcForEndings( startAngle, arcAngle, aShape->GetRadius(), linewidth ) )
752 {
753 break;
754 }
755
756 // Rotate the original start point by the angular offset from shortening.
757 VECTOR2I arcStart = aShape->GetStart();
758 RotatePoint( arcStart, aShape->GetCenter(), origStartAngle - startAngle );
759
760 createArcSegments( aShape->GetCenter(), arcStart, arcAngle, segCount, linewidth, aContainer, *aOwner );
761 break;
762 }
763
764 case SHAPE_T::SEGMENT:
765 {
766 VECTOR2I segStart = aShape->GetStart();
767 VECTOR2I segEnd = aShape->GetEnd();
768
769 if( !EDA_SHAPE::ShortenSegmentForEndings( segStart, segEnd, aShape->GetStartEnding(),
770 aShape->GetEndEnding(), linewidth ) )
771 {
772 break;
773 }
774
775 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( segStart ), TO_SFVEC2F( segEnd ), linewidth3DU, *aOwner );
776 break;
777 }
778
779 case SHAPE_T::BEZIER:
780 {
781 std::vector<VECTOR2D> pts = aShape->ShortenedBezierPolyline( linewidth );
782
783 for( size_t i = 0; i + 1 < pts.size(); i++ )
784 {
785 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( VECTOR2I( pts[i] ) ), TO_SFVEC2F( VECTOR2I( pts[i + 1] ) ),
786 linewidth3DU, *aOwner );
787 }
788
789 break;
790 }
791
792 case SHAPE_T::POLY:
793 {
794 if( isSolidFill )
795 {
796 SHAPE_POLY_SET polyList;
797
798 // For a filled poly with a line style not a simple line, ignore line width
799 // the outline will be drawn later
800 bool ignoreLineWidth = lineStyle > LINE_STYLE::FIRST_TYPE;
801
802 aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, aShape->GetMaxError(),
803 ERROR_INSIDE, ignoreLineWidth );
804
805 // Some polygons can be a bit complex (especially when coming from a
806 // picture of a text converted to a polygon
807 // So call Simplify before calling ConvertPolygonToTriangles, just in case.
808 polyList.Simplify();
809
810 if( polyList.IsEmpty() ) // Just for caution
811 break;
812
813 if( margin != 0 )
814 {
817
818 polyList.Inflate( margin, cornerStr, aShape->GetMaxError() );
819 }
820
821 ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
822 }
823 else
824 {
825 const SHAPE_POLY_SET& polyShape = aShape->GetPolyShape();
826
827 for( int outlineIdx = 0; outlineIdx < polyShape.OutlineCount(); ++outlineIdx )
828 {
829 const SHAPE_LINE_CHAIN& outline = polyShape.COutline( outlineIdx );
830
831 if( outline.PointCount() < 2 )
832 continue;
833
834 std::vector<VECTOR2I> pts;
835
836 if( !aShape->GetShortenedBodyPolyPoints( outline, outlineIdx, pts, linewidth ) )
837 {
838 continue;
839 }
840
841 for( size_t i = 0; i + 1 < pts.size(); i++ )
842 {
843 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts[i] ), TO_SFVEC2F( pts[i + 1] ), linewidth3DU,
844 *aOwner );
845 }
846
847 if( outline.IsClosed() )
848 {
849 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( pts.back() ), TO_SFVEC2F( pts.front() ),
850 linewidth3DU, *aOwner );
851 }
852 }
853 }
854 break;
855 }
856
857 case SHAPE_T::ELLIPSE:
859 {
860 if( isSolidFill )
861 {
862 SHAPE_POLY_SET polyList;
863
864 aShape->TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, aShape->GetMaxError(), ERROR_INSIDE );
865
866 polyList.Simplify();
867
868 if( polyList.IsEmpty() )
869 break;
870
871 if( margin != 0 )
872 {
873 CORNER_STRATEGY cornerStr =
875 polyList.Inflate( margin, cornerStr, aShape->GetMaxError() );
876 }
877
878 ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
879 }
880 else
881 {
882 // Hatched fill: draw only the elliptical outline so the hatch polygons
883 // added below remain visible.
884 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
885
886 for( SHAPE* shape : shapes )
887 {
888 if( shape->Type() == SH_SEGMENT )
889 {
890 const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape )->GetSeg();
891 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( seg.A ), TO_SFVEC2F( seg.B ), linewidth3DU,
892 *aOwner );
893 }
894 }
895
896 for( SHAPE* shape : shapes )
897 delete shape;
898 }
899 break;
900 }
901
902 default:
903 wxFAIL_MSG( wxT( "BOARD_ADAPTER::addShape no implementation for " )
904 + aShape->SHAPE_T_asString() );
905 break;
906 }
907 }
908
909 if( lineStyle > LINE_STYLE::FIRST_TYPE )
910 {
911 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapesForStroking( linewidth );
912 SFVEC2F a3DU;
913 SFVEC2F b3DU;
914
915 const PCB_PLOT_PARAMS& plotParams = aShape->GetBoard()->GetPlotOptions();
916 KIGFX::PCB_RENDER_SETTINGS renderSettings;
917
918 renderSettings.SetDashLengthRatio( plotParams.GetDashedLineDashRatio() );
919 renderSettings.SetGapLengthRatio( plotParams.GetDashedLineGapRatio() );
920
921 for( SHAPE* shape : shapes )
922 {
923 STROKE_PARAMS::Stroke( shape, lineStyle, aShape->GetWidth(), &renderSettings,
924 [&]( const VECTOR2I& a, const VECTOR2I& b )
925 {
926 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( a ), TO_SFVEC2F( b ),
927 linewidth3DU, *aOwner );
928 } );
929 }
930
931 for( SHAPE* shape : shapes )
932 delete shape;
933 }
934
935 // Render line endings.
938 {
939 EDA_ANGLE startTangent, endTangent;
940 aShape->GetEndingTangents( startTangent, endTangent, aShape->GetWidth() );
941
942 VECTOR2I startPt, endPt;
943
944 if( aShape->GetLineEndingEndpoints( startPt, endPt ) )
945 {
946 auto addEnding = [&]( const LINE_ENDING& aEnding, const VECTOR2I& aPoint, const EDA_ANGLE& aTangent )
947 {
948 if( aEnding.GetStyle() == LINE_ENDING_STYLE::NONE )
949 return;
950
951 std::vector<VECTOR2I> polygon;
952 aEnding.GetShapes( aPoint, aTangent, linewidth, polygon );
953
954 if( polygon.empty() )
955 return;
956
957 if( aEnding.GetStyle() == LINE_ENDING_STYLE::ARROW_OPEN )
958 {
959 // Open V-shape: draw as thick line segments, not a filled polygon.
960 int strokeW = aEnding.GetStrokeWidth() > 0 ? aEnding.GetStrokeWidth() : linewidth;
961 float stroke3DU = TO_3DU( strokeW );
962
963 for( size_t ii = 0; ii + 1 < polygon.size(); ii++ )
964 {
965 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( polygon[ii] ), TO_SFVEC2F( polygon[ii + 1] ),
966 stroke3DU, *aOwner );
967 }
968 }
969 else
970 {
971 if( aEnding.GetStrokeWidth() > 0 )
972 {
973 float stroke3DU = TO_3DU( aEnding.GetStrokeWidth() );
974
975 for( size_t ii = 0; ii < polygon.size(); ii++ )
976 {
977 size_t next = ( ii + 1 ) % polygon.size();
978
979 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( polygon[ii] ), TO_SFVEC2F( polygon[next] ),
980 stroke3DU, *aOwner );
981 }
982 }
983
984 SHAPE_POLY_SET polySet;
985 polySet.NewOutline();
986
987 for( const VECTOR2I& pt : polygon )
988 polySet.Append( pt );
989
990 ConvertPolygonToTriangles( polySet, *aContainer, m_biuTo3Dunits, *aOwner );
991 }
992 };
993
994 addEnding( aShape->GetStartEnding(), startPt, startTangent );
995 addEnding( aShape->GetEndEnding(), endPt, endTangent );
996 }
997 }
998
999 if( isHatchedFill )
1000 ConvertPolygonToTriangles( aShape->GetHatching(), *aContainer, m_biuTo3Dunits, *aOwner );
1001}
1002
1003
1004void BOARD_ADAPTER::addShape( const PCB_TEXTBOX* aTextBox, CONTAINER_2D_BASE* aContainer,
1005 const BOARD_ITEM* aOwner )
1006{
1007 addText( aTextBox, aContainer, aOwner );
1008
1009 if( !aTextBox->IsBorderEnabled() )
1010 return;
1011
1012 // We cannot use PCB_TEXTBOX::TransformShapeToPolygon because it convert the textbox
1013 // as filled polygon even if there's no background colour.
1014 // So for polygon, we use PCB_SHAPE::TransformShapeToPolygon
1015
1016 if( aTextBox->GetShape() == SHAPE_T::RECTANGLE )
1017 {
1018 addShape( static_cast<const PCB_SHAPE*>( aTextBox ), aContainer, aOwner, UNDEFINED_LAYER );
1019 }
1020 else
1021 {
1022 SHAPE_POLY_SET polyList;
1023
1024 aTextBox->PCB_SHAPE::TransformShapeToPolygon( polyList, UNDEFINED_LAYER, 0, aTextBox->GetMaxError(),
1025 ERROR_INSIDE );
1026
1027 ConvertPolygonToTriangles( polyList, *aContainer, m_biuTo3Dunits, *aOwner );
1028 }
1029}
1030
1031
1032void BOARD_ADAPTER::addTable( const PCB_TABLE* aTable, CONTAINER_2D_BASE* aContainer,
1033 const BOARD_ITEM* aOwner )
1034{
1035 aTable->DrawBorders(
1036 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB, const STROKE_PARAMS& stroke )
1037 {
1038 addROUND_SEGMENT_2D( aContainer, TO_SFVEC2F( ptA ), TO_SFVEC2F( ptB ),
1039 TO_3DU( stroke.GetWidth() ), *aOwner );
1040 } );
1041
1042 for( PCB_TABLECELL* cell : aTable->GetCells() )
1043 {
1044 if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
1045 addText( cell, aContainer, aOwner );
1046 }
1047}
1048
1049
1051 PCB_LAYER_ID aLayerId )
1052{
1053 // This convert the poly in outline and holes
1054 ConvertPolygonToTriangles( *aZone->GetFilledPolysList( aLayerId ), *aContainer, m_biuTo3Dunits, *aZone );
1055}
1056
1057
1059 CONTAINER_2D_BASE* aContainer, int aWidth )
1060{
1061 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE ) // Draw a ring
1062 {
1063 const SFVEC2F center3DU = TO_SFVEC2F( aPad->ShapePos( aLayer ) );
1064 const int radius = aPad->GetSize( aLayer ).x / 2;
1065 const float inner_radius3DU = TO_3DU( radius - aWidth / 2.0 );
1066 const float outer_radius3DU = TO_3DU( radius + aWidth / 2.0 );
1067
1068 addRING_2D( aContainer, center3DU, inner_radius3DU, outer_radius3DU, *aPad );
1069 }
1070 else
1071 {
1072 // For other shapes, add outlines as thick segments in polygon buffer
1073 const std::shared_ptr<SHAPE_POLY_SET>& corners = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
1074 const SHAPE_LINE_CHAIN& path = corners->COutline( 0 );
1075
1076 for( int j = 0; j < path.PointCount(); j++ )
1077 {
1078 SFVEC2F start3DU = TO_SFVEC2F( path.CPoint( j ) );
1079 SFVEC2F end3DU = TO_SFVEC2F( path.CPoint( j + 1 ) );
1080
1081 addROUND_SEGMENT_2D( aContainer, start3DU, end3DU, TO_3DU( aWidth ), *aPad );
1082 }
1083 }
1084}
@ ERROR_INSIDE
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
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:84
virtual bool IsKnockout() const
Definition board_item.h:413
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:542
const KIFONT::METRICS & GetFontMetrics() const
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:266
int GetMaxError() const
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition board.h:1013
constexpr int GetSizeMax() const
Definition box2.h:232
void Add(OBJECT_2D *aObject)
double AsDegrees() const
Definition eda_angle.h:116
bool IsZero() const
Definition eda_angle.h:136
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.
const SHAPE_POLY_SET & GetHatching() const
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:549
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.
int GetRadius() const
SHAPE_T GetShape() const
Definition eda_shape.h:175
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:130
bool GetLineEndingEndpoints(VECTOR2I &aStartPoint, VECTOR2I &aEndPoint) const
Return the source endpoints used to place line endings.
bool IsSolidFill() const
Definition eda_shape.h:123
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:325
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:275
std::vector< VECTOR2I > GetRectCorners() const
const LINE_ENDING & GetStartEnding() const
Definition eda_shape.h:177
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:180
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:666
virtual EDA_ANGLE GetDrawRotation() const
Definition eda_text.h:419
virtual VECTOR2I GetDrawPos() const
Definition eda_text.h:420
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:422
bool IsBold() const
Definition eda_text.h:215
std::deque< PAD * > & Pads()
Definition footprint.h:404
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
DRAWINGS & GraphicalItems()
Definition footprint.h:407
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:143
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:240
PCB specific render settings.
Definition pcb_painter.h:84
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:1316
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:205
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc=ERROR_INSIDE, bool ignoreLineWidth=false) const override
Convert the pad shape to a closed polygon.
Definition pad.cpp:3010
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
Definition pad.cpp:288
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:1228
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:1241
bool HasHole() const override
Definition pad.h:113
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1855
bool IsDegenerated(int aThreshold=5) const
double GetRadius() const
EDA_ANGLE GetAngle() const
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_track.h:294
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:78
int GetWidth() const override
bool HasSolderMask() const
Definition pcb_shape.h:336
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:76
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:68
std::vector< PCB_TABLECELL * > GetCells() const
Definition pcb_table.h:160
void DrawBorders(const std::function< void(const VECTOR2I &aPt1, const VECTOR2I &aPt2, const STROKE_PARAMS &aStroke)> &aCallback) const
bool IsBorderEnabled() const
Disables the border, this is done by changing the stroke internally.
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:89
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:92
const VECTOR2I & GetStart() const
Definition pcb_track.h:93
const VECTOR2I & GetEnd() const
Definition pcb_track.h:90
virtual void SetWidth(int aWidth)
Definition pcb_track.h:86
virtual int GetWidth() const
Definition pcb_track.h:87
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:211
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:165
const VECTOR2I GetSize() const
Definition shape_rect.h:173
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:287
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)
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:692
@ FOR_CANVAS
Definition common.h:88
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:422
static constexpr EDA_ANGLE ANGLE_360
Definition eda_angle.h:428
@ 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:774
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:703
@ 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:411
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
int radius
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:225
@ 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:683
glm::vec2 SFVEC2F
Definition xv3d_types.h:38