KiCad PCB EDA Suite
Loading...
Searching...
No Matches
plot_brditems_plotter.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <algorithm> // for min
21#include <cmath> // for abs
22
23#include <geometry/seg.h> // for SEG
26#include <geometry/shape_line_chain.h> // for SHAPE_LINE_CHAIN
27#include <geometry/shape_poly_set.h> // for SHAPE_POLY_SET, SHAPE_P...
28#include <geometry/shape_rect.h>
30#include <string_utils.h>
31#include <macros.h>
32#include <math/util.h> // for KiROUND
33#include <math/vector2d.h> // for VECTOR2I
35#include <trigo.h>
36#include <font/stroke_font.h>
38#include <callback_gal.h>
39#include <core/typeinfo.h> // for dyn_cast, PCB_DIMENSION_T
40#include <gbr_metadata.h>
41#include <gbr_netlist_metadata.h> // for GBR_NETLIST_METADATA
42#include <layer_ids.h> // for LSET, IsCopperLayer
43#include <lset.h>
49#include <pcb_drill_chart.h>
50#include <pcb_drill_map.h>
51#include <pcbplot.h>
52#include <pcb_plot_params.h> // for PCB_PLOT_PARAMS, PCB_PL...
53#include <advanced_config.h>
54
55#include <line_ending.h>
56#include <pcb_dimension.h>
57#include <pcb_shape.h>
58#include <footprint.h>
59#include <pcb_track.h>
60#include <pad.h>
61#include <pcb_target.h>
62#include <pcb_text.h>
63#include <pcb_textbox.h>
64#include <pcb_tablecell.h>
65#include <pcb_table.h>
66#include <zone.h>
67#include <pcb_barcode.h>
68
69#include <wx/debug.h> // for wxASSERT_MSG
70
71
73{
74 COLOR4D color = ColorSettings()->GetColor( aLayer );
75
76 // A hack to avoid plotting a white item in white color on white paper
77 if( color == COLOR4D::WHITE )
78 color = COLOR4D( LIGHTGRAY );
79
80 return color;
81}
82
83
84void BRDITEMS_PLOTTER::PlotPadNumber( const PAD* aPad, const COLOR4D& aColor ) const
85{
86 wxString padNumber = UnescapeString( aPad->GetNumber() );
87
88 if( padNumber.IsEmpty() )
89 return;
90
91 BOX2I padBBox = aPad->GetBoundingBox();
92 VECTOR2I position = padBBox.Centre();
93 VECTOR2I padsize = padBBox.GetSize();
94
95 // TODO(JE) padstacks
97 {
98 // See if we have a number box
99 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives( PADSTACK::TEMP_ALL_LAYERS ) )
100 {
101 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::RECTANGLE )
102 {
103 position = primitive->GetCenter();
104 RotatePoint( position, aPad->GetOrientation() );
105 position += aPad->ShapePos( PADSTACK::TEMP_ALL_LAYERS );
106
107 padsize.x = std::abs( primitive->GetBotRight().x - primitive->GetTopLeft().x );
108 padsize.y = std::abs( primitive->GetBotRight().y - primitive->GetTopLeft().y );
109
110 break;
111 }
112 }
113 }
114
116 {
117 // Don't allow a 45° rotation to bloat a pad's bounding box unnecessarily
118 int limit = KiROUND( std::min( aPad->GetSize( PADSTACK::TEMP_ALL_LAYERS ).x,
119 aPad->GetSize( PADSTACK::TEMP_ALL_LAYERS ).y ) * 1.1 );
120
121 if( padsize.x > limit && padsize.y > limit )
122 {
123 padsize.x = limit;
124 padsize.y = limit;
125 }
126 }
127
128 TEXT_ATTRIBUTES textAttrs;
129
130 textAttrs.m_Mirrored = m_plotter->GetPlotMirrored();
131
132 if( padsize.x < ( padsize.y * 0.95 ) )
133 {
134 textAttrs.m_Angle = ANGLE_90;
135 std::swap( padsize.x, padsize.y );
136 }
137
138 // approximate the size of the pad number text:
139 // We use a size for at least 3 chars, to give a good look even for short numbers
140 int tsize = KiROUND( padsize.x / std::max( PrintableCharCount( padNumber ), 3 ) );
141 tsize = std::min( tsize, padsize.y );
142
143 // enforce a max size
144 tsize = std::min( tsize, pcbIUScale.mmToIU( 5.0 ) );
145
146 textAttrs.m_Size = VECTOR2I( tsize, tsize );
147
148 // use a somewhat spindly font to go with the outlined pads
149 textAttrs.m_StrokeWidth = KiROUND( tsize / 12.0 );
150
151 m_plotter->PlotText( position, aColor, padNumber, textAttrs );
152}
153
154
155void BRDITEMS_PLOTTER::PlotPad( const PAD* aPad, PCB_LAYER_ID aLayer, const COLOR4D& aColor, bool aSketchMode ) const
156{
157 VECTOR2I shape_pos = aPad->ShapePos( aLayer );
158 GBR_METADATA metadata;
159
160 m_plotter->MarkFootprintPlotted( aPad->GetParentFootprint() );
161
162 bool plotOnCopperLayer = ( m_layerMask & LSET::AllCuMask() ).any();
163 bool plotOnExternalCopperLayer = ( m_layerMask & LSET::ExternalCuMask() ).any();
164
165 // Pad not on the solder mask layer cannot be soldered.
166 // therefore it can have a specific aperture attribute.
167 // Not yet in use.
168 // bool isPadOnBoardTechLayers = ( aPad->GetLayerSet() & LSET::AllBoardTechMask() ).any();
169
170 metadata.SetCmpReference( aPad->GetParentFootprint()->GetReference() );
171
172 if( plotOnCopperLayer )
173 {
175 metadata.SetCopper( true );
176
177 // Gives a default attribute, for instance for pads used as tracks in net ties:
178 // Connector pads and SMD pads are on external layers
179 // if on internal layers, they are certainly used as net tie
180 // and are similar to tracks: just conductor items
182
183 const bool useUTF8 = false;
184 const bool useQuoting = false;
185 metadata.SetPadName( aPad->GetNumber(), useUTF8, useQuoting );
186
187 if( !aPad->GetNumber().IsEmpty() )
188 metadata.SetPadPinFunction( aPad->GetPinFunction(), useUTF8, useQuoting );
189
190 metadata.SetNetName( aPad->GetNetname() );
191
192 // Some pads are mechanical pads ( through hole or smd )
193 // when this is the case, they have no pad name and/or are not plated.
194 // In this case gerber files have slightly different attributes.
195 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH || aPad->GetNumber().IsEmpty() )
196 metadata.m_NetlistMetadata.m_NotInNet = true;
197
198 if( !plotOnExternalCopperLayer )
199 {
200 // the .P object attribute (GBR_NETLIST_METADATA::GBR_NETINFO_PAD)
201 // is used on outer layers, unless the component is embedded
202 // or a "etched" component (fp only drawn, not a physical component)
203 // Currently, Pcbnew does not handle embedded component, so we disable the .P
204 // attribute on internal layers
205 // Note the Gerber doc is not really clear about through holes pads about the .P
208
209 }
210
211 // Some attributes are reserved to the external copper layers:
212 // GBR_APERTURE_ATTRIB_CONNECTORPAD and GBR_APERTURE_ATTRIB_SMDPAD_CUDEF
213 // for instance.
214 // Pad with type PAD_ATTRIB::CONN or PAD_ATTRIB::SMD that is not on outer layer
215 // has its aperture attribute set to GBR_APERTURE_ATTRIB_CONDUCTOR
216 switch( aPad->GetAttribute() )
217 {
218 case PAD_ATTRIB::NPTH: // Mechanical pad through hole
220 break;
221
222 case PAD_ATTRIB::PTH : // Pad through hole, a hole is also expected
224 break;
225
226 case PAD_ATTRIB::CONN: // Connector pads, no solder paste but with solder mask.
227 if( plotOnExternalCopperLayer )
229 break;
230
231 case PAD_ATTRIB::SMD: // SMD pads (on external copper layer only)
232 // with solder paste and mask
233 if( plotOnExternalCopperLayer )
235 break;
236 }
237
238 // Fabrication properties can have specific GBR_APERTURE_METADATA options
239 // that replace previous aperture attribute:
240 switch( aPad->GetProperty() )
241 {
242 case PAD_PROP::BGA: // Only applicable to outer layers
243 if( plotOnExternalCopperLayer )
245 break;
246
249 break;
250
253 break;
254
255 case PAD_PROP::TESTPOINT: // Only applicable to outer layers
256 if( plotOnExternalCopperLayer )
258 break;
259
262 break;
263
266 break;
267
268 case PAD_PROP::PRESSFIT: // used only in drill files
269 case PAD_PROP::NONE:
271 break;
272 }
273
274 // Ensure NPTH pads have *always* the GBR_APERTURE_ATTRIB_WASHERPAD attribute
275 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
277 }
278 else
279 {
281 }
282
283 // Set plot color (change WHITE to LIGHTGRAY because
284 // the white items are not seen on a white paper or screen
285 m_plotter->SetColor( aColor != WHITE ? aColor : LIGHTGRAY );
286
287 if( aSketchMode )
288 {
289 switch( aPad->GetShape( aLayer ) )
290 {
292 m_plotter->ThickCircle( shape_pos, aPad->GetSize( aLayer ).x, GetSketchPadLineWidth(),
293 nullptr );
294 break;
295
296 case PAD_SHAPE::OVAL:
297 {
298 m_plotter->ThickOval( shape_pos, aPad->GetSize( aLayer ), aPad->GetOrientation(),
299 GetSketchPadLineWidth(), nullptr );
300 break;
301 }
302
308 {
309 SHAPE_POLY_SET outline;
310 aPad->TransformShapeToPolygon( outline, aLayer, 0, m_plotter->GetPlotterArcHighDef(),
311 ERROR_INSIDE, false );
312
313 m_plotter->ThickPoly( outline, GetSketchPadLineWidth(), nullptr );
314 break;
315 }
316
317 default:
319 }
320
321 return;
322 }
323
324 switch( aPad->GetShape( aLayer ) )
325 {
327 m_plotter->FlashPadCircle( shape_pos, aPad->GetSize( aLayer ).x, &metadata );
328 break;
329
330 case PAD_SHAPE::OVAL:
331 m_plotter->FlashPadOval( shape_pos, aPad->GetSize( aLayer ), aPad->GetOrientation(), &metadata );
332 break;
333
335 m_plotter->FlashPadRect( shape_pos, aPad->GetSize( aLayer ), aPad->GetOrientation(), &metadata );
336 break;
337
339 m_plotter->FlashPadRoundRect( shape_pos, aPad->GetSize( aLayer ),
340 aPad->GetRoundRectCornerRadius( aLayer ),
341 aPad->GetOrientation(), &metadata );
342 break;
343
345 {
346 // Build the pad polygon in coordinates relative to the pad
347 // (i.e. for a pad at pos 0,0, rot 0.0). Needed to use aperture macros,
348 // to be able to create a pattern common to all trapezoid pads having the same shape
349 VECTOR2I coord[4];
350
351 // Order is lower left, lower right, upper right, upper left.
352 VECTOR2I half_size = aPad->GetSize( aLayer ) / 2;
353 VECTOR2I trap_delta = aPad->GetDelta( aLayer ) / 2;
354
355 coord[0] = VECTOR2I( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
356 coord[1] = VECTOR2I( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
357 coord[2] = VECTOR2I( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
358 coord[3] = VECTOR2I( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
359
360 m_plotter->FlashPadTrapez( shape_pos, coord, aPad->GetOrientation(), &metadata );
361 break;
362 }
363
365 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
366 {
367 GERBER_PLOTTER* gerberPlotter = static_cast<GERBER_PLOTTER*>( m_plotter );
368
369 gerberPlotter->FlashPadChamferRoundRect( shape_pos, aPad->GetSize( aLayer ),
370 aPad->GetRoundRectCornerRadius( aLayer ),
371 aPad->GetChamferRectRatio( aLayer ),
372 aPad->GetChamferPositions( aLayer ),
373 aPad->GetOrientation(), &metadata );
374 break;
375 }
376
378
379 default:
381 {
382 const std::shared_ptr<SHAPE_POLY_SET>& polygons = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
383
384 if( polygons->OutlineCount() )
385 {
386 m_plotter->FlashPadCustom( shape_pos, aPad->GetSize( aLayer ), aPad->GetOrientation(),
387 polygons.get(), &metadata );
388 }
389 }
390 break;
391 }
392}
393
394
396{
397 if( !GetPlotFPText() )
398 return;
399
400 const wxString variantName = m_board ? m_board->GetCurrentVariant() : wxString();
401 const bool dnp = aFootprint->GetDNPForVariant( variantName );
402
403 const PCB_TEXT* reference = &aFootprint->Reference();
404 PCB_LAYER_ID refLayer = reference->GetLayer();
405
406 // Reference and value have special controls for forcing their plotting
407 if( GetPlotReference()
408 && m_layerMask[refLayer]
409 && reference->IsVisible()
410 && !( dnp && hideDNPItems( refLayer ) ) )
411 {
412 m_plotter->MarkFootprintPlotted( aFootprint );
413 PlotText( reference, refLayer, reference->IsKnockout(), reference->GetFontMetrics(),
414 dnp && crossoutDNPItems( refLayer ) );
415 }
416
417 const PCB_TEXT* value = &aFootprint->Value();
418 PCB_LAYER_ID valueLayer = value->GetLayer();
419
420 if( GetPlotValue()
421 && m_layerMask[valueLayer]
422 && value->IsVisible()
423 && !( dnp && hideDNPItems( valueLayer ) ) )
424 {
425 m_plotter->MarkFootprintPlotted( aFootprint );
426 PlotText( value, valueLayer, value->IsKnockout(), value->GetFontMetrics(), false );
427 }
428
429 std::vector<PCB_TEXT*> texts;
430
431 // Skip the reference and value texts that are handled specially
432 for( PCB_FIELD* field : aFootprint->GetFields() )
433 {
434 wxCHECK2( field, continue );
435
436 if( field->IsReference() || field->IsValue() )
437 continue;
438
439 if( field->IsVisible() )
440 texts.push_back( field );
441 }
442
443 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
444 {
445 if( PCB_TEXT* textItem = dynamic_cast<PCB_TEXT*>( item ) )
446 texts.push_back( textItem );
447 }
448
449 for( const PCB_TEXT* text : texts )
450 {
451 PCB_LAYER_ID textLayer = text->GetLayer();
452 bool strikeout = false;
453
454 if( textLayer == Edge_Cuts || textLayer >= PCB_LAYER_ID_COUNT )
455 continue;
456
457 if( dnp && hideDNPItems( textLayer ) )
458 continue;
459
460 if( !m_layerMask[textLayer] || aFootprint->GetPrivateLayers().test( textLayer ) )
461 continue;
462
463 if( text->GetText() == wxT( "${REFERENCE}" ) )
464 {
465 if( !GetPlotReference() )
466 continue;
467
468 strikeout = dnp && crossoutDNPItems( textLayer );
469 }
470
471 if( text->GetText() == wxT( "${VALUE}" ) )
472 {
473 if( !GetPlotValue() )
474 continue;
475 }
476
477 m_plotter->MarkFootprintPlotted( aFootprint );
478 PlotText( text, textLayer, text->IsKnockout(), text->GetFontMetrics(), strikeout );
479 }
480}
481
482
484{
485 switch( item->Type() )
486 {
487 case PCB_SHAPE_T:
488 PlotShape( static_cast<const PCB_SHAPE*>( item ) );
489 break;
490
491 case PCB_TEXT_T:
492 {
493 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
494 PlotText( text, text->GetLayer(), text->IsKnockout(), text->GetFontMetrics() );
495 break;
496 }
497
498 case PCB_TEXTBOX_T:
499 {
500 m_plotter->SetTextMode( PLOT_TEXT_MODE::STROKE );
501
502 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( item );
503 PlotText( textbox, textbox->GetLayer(), textbox->IsKnockout(), textbox->GetFontMetrics() );
504
505 if( textbox->IsBorderEnabled() )
506 {
507 // PlotShape works only for textbox rotated by 0 or 180 degrees.
508 // This is not always the case so use the polygonal shape of the box of the text box.
510 PlotShape( &dummy );
511 }
512
513 m_plotter->SetTextMode( GetTextMode() );
514 break;
515 }
516
517 case PCB_BARCODE_T:
518 PlotBarCode( static_cast<const PCB_BARCODE*>( item ) );
519 break;
520
521 case PCB_TABLE_T:
523 {
524 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( item );
525
526 m_plotter->SetTextMode( PLOT_TEXT_MODE::STROKE );
527
528 for( const PCB_TABLECELL* cell : table->GetCells() )
529 PlotText( cell, cell->GetLayer(), cell->IsKnockout(), cell->GetFontMetrics() );
530
532
533 if( item->Type() == PCB_DRILL_CHART_T )
534 PlotChartSymbols( static_cast<const PCB_DRILL_CHART*>( item ) );
535
536 m_plotter->SetTextMode( GetTextMode() );
537 break;
538 }
539
541 case PCB_DIM_CENTER_T:
542 case PCB_DIM_RADIAL_T:
544 case PCB_DIM_LEADER_T:
545 m_plotter->SetTextMode( PLOT_TEXT_MODE::STROKE );
546
547 PlotDimension( static_cast<const PCB_DIMENSION_BASE*>( item ) );
548
549 m_plotter->SetTextMode( GetTextMode() );
550 break;
551
552 case PCB_TARGET_T:
553 PlotPcbTarget( static_cast<const PCB_TARGET*>( item ) );
554 break;
555
556 default:
557 break;
558 }
559}
560
561
563{
564 if( !m_layerMask[aDim->GetLayer()] )
565 return;
566
567 COLOR4D color = ColorSettings()->GetColor( aDim->GetLayer() );
568
569 // Set plot color (change WHITE to LIGHTGRAY because
570 // the white items are not seen on a white paper or screen
571 m_plotter->SetColor( color != WHITE ? color : LIGHTGRAY);
572
573 PlotText( aDim, aDim->GetLayer(), false, aDim->GetFontMetrics() );
574
575 PCB_SHAPE temp_item;
576
578 temp_item.SetLayer( aDim->GetLayer() );
579
580 for( const std::shared_ptr<SHAPE>& shape : aDim->GetShapes() )
581 {
582 switch( shape->Type() )
583 {
584 case SH_SEGMENT:
585 {
586 const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
587
588 temp_item.SetShape( SHAPE_T::SEGMENT );
589 temp_item.SetStart( seg.A );
590 temp_item.SetEnd( seg.B );
591
592 PlotShape( &temp_item );
593 break;
594 }
595
596 case SH_CIRCLE:
597 {
598 VECTOR2I start( shape->Centre() );
599 int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
600
601 temp_item.SetShape( SHAPE_T::CIRCLE );
602 temp_item.SetFilled( false );
603 temp_item.SetStart( start );
604 temp_item.SetEnd( VECTOR2I( start.x + radius, start.y ) );
605
606 PlotShape( &temp_item );
607 break;
608 }
609
610 default:
611 break;
612 }
613 }
614}
615
616
618{
619 int dx1, dx2, dy1, dy2, radius;
620
621 if( !m_layerMask[aMire->GetLayer()] )
622 return;
623
624 m_plotter->SetColor( getColor( aMire->GetLayer() ) );
625
626 PCB_SHAPE temp_item;
627
628 temp_item.SetShape( SHAPE_T::CIRCLE );
629 temp_item.SetFilled( false );
630 temp_item.SetStroke( STROKE_PARAMS( aMire->GetWidth(), LINE_STYLE::SOLID ) );
631 temp_item.SetLayer( aMire->GetLayer() );
632 temp_item.SetStart( aMire->GetPosition() );
633 radius = aMire->GetSize() / 3;
634
635 if( aMire->GetShape() ) // temp_item X
636 radius = aMire->GetSize() / 2;
637
638 // Draw the circle
639 temp_item.SetEnd( VECTOR2I( temp_item.GetStart().x + radius, temp_item.GetStart().y ) );
640
641 PlotShape( &temp_item );
642
643 temp_item.SetShape( SHAPE_T::SEGMENT );
644
645 radius = aMire->GetSize() / 2;
646 dx1 = radius;
647 dy1 = 0;
648 dx2 = 0;
649 dy2 = radius;
650
651 if( aMire->GetShape() ) // Shape X
652 {
653 dx1 = dy1 = radius;
654 dx2 = dx1;
655 dy2 = -dy1;
656 }
657
658 VECTOR2I mirePos( aMire->GetPosition() );
659
660 // Draw the X or + temp_item:
661 temp_item.SetStart( VECTOR2I( mirePos.x - dx1, mirePos.y - dy1 ) );
662 temp_item.SetEnd( VECTOR2I( mirePos.x + dx1, mirePos.y + dy1 ) );
663 PlotShape( &temp_item );
664
665 temp_item.SetStart( VECTOR2I( mirePos.x - dx2, mirePos.y - dy2 ) );
666 temp_item.SetEnd( VECTOR2I( mirePos.x + dx2, mirePos.y + dy2 ) );
667 PlotShape( &temp_item );
668}
669
670
672{
673 const wxString variantName = m_board ? m_board->GetCurrentVariant() : wxString();
674 const bool dnp = aFootprint->GetDNPForVariant( variantName );
675
676 for( const BOARD_ITEM* item : aFootprint->GraphicalItems() )
677 {
678 PCB_LAYER_ID itemLayer = item->GetLayer();
679
680 if( aFootprint->GetPrivateLayers().test( itemLayer ) )
681 continue;
682
683 if( dnp && hideDNPItems( itemLayer ) )
684 continue;
685
686 if( !( m_layerMask & item->GetLayerSet() ).any() )
687 continue;
688
689 m_plotter->MarkFootprintPlotted( aFootprint );
690
691 switch( item->Type() )
692 {
693 case PCB_SHAPE_T:
694 PlotShape( static_cast<const PCB_SHAPE*>( item ) );
695 break;
696
697 case PCB_TEXTBOX_T:
698 {
699 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( item );
700
701 m_plotter->SetTextMode( PLOT_TEXT_MODE::STROKE );
702
703 PlotText( textbox, textbox->GetLayer(), textbox->IsKnockout(),
704 textbox->GetFontMetrics() );
705
706 if( textbox->IsBorderEnabled() )
707 {
708 // PlotShape works only for textbox rotated by 0 or 180 degrees.
709 // This is not always the case so use the polygonal shape
711 PlotShape( &dummy );
712 }
713
714 m_plotter->SetTextMode( GetTextMode() );
715 break;
716 }
717
718 case PCB_BARCODE_T:
719 PlotBarCode( static_cast<const PCB_BARCODE*>( item ) );
720 break;
721
722 case PCB_TABLE_T:
724 {
725 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( item );
726
727 m_plotter->SetTextMode( PLOT_TEXT_MODE::STROKE );
728
729 for( const PCB_TABLECELL* cell : table->GetCells() )
730 PlotText( cell, cell->GetLayer(), cell->IsKnockout(), cell->GetFontMetrics() );
731
733
734 m_plotter->SetTextMode( GetTextMode() );
735 break;
736 }
737
739 case PCB_DIM_CENTER_T:
740 case PCB_DIM_RADIAL_T:
742 case PCB_DIM_LEADER_T:
743 PlotDimension( static_cast<const PCB_DIMENSION_BASE*>( item ) );
744 break;
745
746 case PCB_TEXT_T:
747 // Plotted in PlotFootprintTextItems()
748 break;
749
751 // Not plotted at all
752 break;
753
754 default:
755 UNIMPLEMENTED_FOR( item->GetClass() );
756 }
757 }
758}
759
760
761static void* plotMetadata( PLOTTER* aPlotter, GBR_METADATA& aMetadata, const PLOT_PARAMS* aPlotOptions )
762{
763 // Gerber writes its metadata through the plotters' opaque data parameter, so that parameter
764 // stays void*. DXF instead reads the sketch/filled mode back out of the plot options and
765 // never writes to them, which is what lets a const plot hand them over at all.
766 switch( aPlotter->GetPlotterType() )
767 {
768 case PLOT_FORMAT::GERBER: return &aMetadata;
769 case PLOT_FORMAT::DXF: return const_cast<PLOT_PARAMS*>( aPlotOptions );
770 default: return nullptr;
771 }
772}
773
774
775#define getMetadata() plotMetadata( m_plotter, gbr_metadata, this )
776
777
778void BRDITEMS_PLOTTER::PlotText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer, bool aIsKnockout,
779 const KIFONT::METRICS& aFontMetrics, bool aStrikeout ) const
780{
781 int maxError = m_board->GetDesignSettings().m_MaxError;
782 KIFONT::FONT* font = aText->GetDrawFont( m_plotter->RenderSettings() );
783 wxString shownText( aText->GetShownText( FOR_CANVAS ) );
784
785 const PCB_TEXTBOX* knockoutBox = aIsKnockout ? dynamic_cast<const PCB_TEXTBOX*>( aText ) : nullptr;
786
787 if( shownText.IsEmpty() && !knockoutBox )
788 return;
789
790 if( !m_layerMask[aLayer] )
791 return;
792
793 GBR_METADATA gbr_metadata;
794
795 if( IsCopperLayer( aLayer ) )
797
798 COLOR4D color = getColor( aLayer );
799 m_plotter->SetColor( color );
800
801 const VECTOR2I& pos = aText->GetTextPos();
802
803 TEXT_ATTRIBUTES attrs = aText->GetAttributes();
804 attrs.m_Size = aText->GetTextSize();
806 attrs.m_Angle = aText->GetDrawRotation();
807 attrs.m_Multiline = false;
808
809 m_plotter->SetCurrentLineWidth( attrs.m_StrokeWidth );
810
811 const auto strikeoutText =
812 [&]( const PCB_TEXT* text )
813 {
814 SHAPE_POLY_SET textPoly;
815
816 text->TransformTextToPolySet( textPoly, 0, ARC_LOW_DEF, ERROR_INSIDE );
817 textPoly.Rotate( -text->GetDrawRotation(), text->GetDrawPos() );
818
819 BOX2I rect = textPoly.BBox();
820 VECTOR2I start( rect.GetLeft() - attrs.m_StrokeWidth,
821 ( rect.GetTop() + rect.GetBottom() ) / 2 );
822 VECTOR2I end( rect.GetRight() + attrs.m_StrokeWidth,
823 ( rect.GetTop() + rect.GetBottom() ) / 2 );
824
825 RotatePoint( start, text->GetDrawPos(), text->GetDrawRotation() );
826 RotatePoint( end, text->GetDrawPos(), text->GetDrawRotation() );
827
828 m_plotter->ThickSegment( start, end, attrs.m_StrokeWidth, getMetadata() );
829 };
830
831 if( aIsKnockout )
832 {
833 SHAPE_POLY_SET finalPoly;
834
835 if( knockoutBox )
836 knockoutBox->TransformTextToPolySet( finalPoly, 0, maxError, ERROR_INSIDE );
837 else if( const PCB_TEXT* text = dynamic_cast<const PCB_TEXT*>( aText ) )
838 text->TransformTextToPolySet( finalPoly, 0, maxError, ERROR_INSIDE );
839
840 finalPoly.Fracture();
841
842 for( int ii = 0; ii < finalPoly.OutlineCount(); ++ii )
843 m_plotter->PlotPoly( finalPoly.Outline( ii ), FILL_T::FILLED_SHAPE, 0, getMetadata() );
844 }
845 else
846 {
847 if( font->IsOutline() && !m_board->GetEmbeddedFiles()->GetAreFontsEmbedded() )
848 {
850
851 CALLBACK_GAL callback_gal( empty_opts,
852 // Stroke callback
853 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
854 {
855 m_plotter->ThickSegment( aPt1, aPt2, attrs.m_StrokeWidth, getMetadata() );
856 },
857 // Polygon callback
858 [&]( const SHAPE_LINE_CHAIN& aPoly )
859 {
860 m_plotter->PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0, getMetadata() );
861 } );
862
863 callback_gal.DrawGlyphs( *aText->GetRenderCache( font, shownText ) );
864 }
865 else if( aText->IsMultilineAllowed() )
866 {
867 std::vector<VECTOR2I> positions;
868 wxArrayString strings_list;
869 wxStringSplit( shownText, strings_list, '\n' );
870 positions.reserve( strings_list.Count() );
871
872 aText->GetLinePositions( m_plotter->RenderSettings(), positions, (int) strings_list.Count() );
873
874 for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
875 {
876 wxString& txt = strings_list.Item( ii );
877 m_plotter->PlotText( positions[ii], color, txt, attrs, font, aFontMetrics, getMetadata() );
878 }
879
880 if( aStrikeout && strings_list.Count() == 1 )
881 strikeoutText( static_cast<const PCB_TEXT*>( aText ) );
882 }
883 else
884 {
885 m_plotter->PlotText( pos, color, shownText, attrs, font, aFontMetrics, getMetadata() );
886
887 if( aStrikeout )
888 strikeoutText( static_cast<const PCB_TEXT*>( aText ) );
889 }
890 }
891}
892
893
894void BRDITEMS_PLOTTER::PlotZone( const ZONE* aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET& aPolysList ) const
895{
896 if( aPolysList.IsEmpty() )
897 return;
898
899 GBR_METADATA gbr_metadata;
900
901 if( aZone->IsOnCopperLayer() )
902 {
903 gbr_metadata.SetNetName( aZone->GetNetname() );
904 gbr_metadata.SetCopper( true );
905
906 // Zones with no net name can exist.
907 // they are not used to connect items, so the aperture attribute cannot
908 // be set as conductor
909 if( aZone->GetNetname().IsEmpty() )
910 {
912 }
913 else
914 {
917 }
918 }
919
920 m_plotter->SetColor( getColor( aLayer ) );
921
922 m_plotter->StartBlock( nullptr ); // Clean current object attributes
923
924 /*
925 * In non filled mode the outline is plotted, but not the filling items
926 */
927
928 for( int idx = 0; idx < aPolysList.OutlineCount(); ++idx )
929 {
930 const SHAPE_LINE_CHAIN& outline = aPolysList.Outline( idx );
931
932 // Plot the current filled area (as region for Gerber plotter to manage attributes)
933 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
934 {
935 static_cast<GERBER_PLOTTER*>( m_plotter )->PlotGerberRegion( outline, &gbr_metadata );
936 }
937 else if( m_plotter->GetPlotterType() == PLOT_FORMAT::DXF )
938 {
939 if( GetDXFPlotMode() == FILLED )
940 m_plotter->PlotPoly( outline, FILL_T::FILLED_SHAPE, 0, getMetadata() );
941 }
942 else
943 {
944 m_plotter->PlotPoly( outline, FILL_T::FILLED_SHAPE, 0, getMetadata() );
945 }
946 }
947
948 m_plotter->EndBlock( nullptr ); // Clear object attributes
949}
950
951
952void BRDITEMS_PLOTTER::PlotShape( const PCB_SHAPE* aShape ) const
953{
954 if( !( m_layerMask & aShape->GetLayerSet() ).any() )
955 return;
956
957 int thickness = aShape->GetWidth();
958 int margin = thickness; // unclamped thickness (can be negative)
959 LINE_STYLE lineStyle = aShape->GetStroke().GetLineStyle();
960 bool onCopperLayer = ( LSET::AllCuMask() & m_layerMask ).any();
961 bool onSolderMaskLayer = ( LSET( { F_Mask, B_Mask } ) & m_layerMask ).any();
962 bool isSolidFill = aShape->IsSolidFill();
963 bool isHatchedFill = aShape->IsHatchedFill();
964
965 if( onSolderMaskLayer
966 && aShape->HasSolderMask()
967 && IsExternalCopperLayer( aShape->GetLayer() ) )
968 {
969 margin += 2 * aShape->GetSolderMaskExpansion();
970 thickness = std::max( margin, 0 );
971
972 if( isHatchedFill )
973 {
974 isSolidFill = true;
975 isHatchedFill = false;
976 }
977 }
978
979 m_plotter->SetColor( getColor( aShape->GetLayer() ) );
980
981 const FOOTPRINT* parentFP = aShape->GetParentFootprint();
982 GBR_METADATA gbr_metadata;
983 const wxString variantName = m_board ? m_board->GetCurrentVariant() : wxString();
984 const bool parentDnp = parentFP ? parentFP->GetDNPForVariant( variantName ) : false;
985
986 if( parentFP )
987 {
988 gbr_metadata.SetCmpReference( parentFP->GetReference() );
990 }
991
992 if( parentFP && parentDnp && GetSketchDNPFPsOnFabLayers() )
993 {
994 if( aShape->GetLayer() == F_Fab || aShape->GetLayer() == B_Fab )
995 {
996 thickness = GetSketchPadLineWidth();
997 isSolidFill = false;
998 isHatchedFill = false;
999 }
1000 }
1001
1002 if( aShape->GetLayer() == Edge_Cuts )
1003 {
1005 }
1006 else if( onCopperLayer )
1007 {
1008 if( parentFP )
1009 {
1011 gbr_metadata.SetCopper( true );
1012 }
1013 else if( aShape->GetNetCode() > 0 )
1014 {
1015 gbr_metadata.SetCopper( true );
1018 gbr_metadata.SetNetName( aShape->GetNetname() );
1019 }
1020 else
1021 {
1022 // Graphic items (PCB_SHAPE, TEXT) having no net have the NonConductor attribute
1023 // Graphic items having a net have the Conductor attribute, but are not (yet?)
1024 // supported in Pcbnew
1026 }
1027 }
1028
1029 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
1030 {
1031 switch( aShape->GetShape() )
1032 {
1033 case SHAPE_T::SEGMENT:
1034 {
1035 VECTOR2I segStart = aShape->GetStart();
1036 VECTOR2I segEnd = aShape->GetEnd();
1037
1038 if( EDA_SHAPE::ShortenSegmentForEndings( segStart, segEnd, aShape->GetStartEnding(), aShape->GetEndEnding(),
1039 thickness ) )
1040 {
1041 m_plotter->ThickSegment( segStart, segEnd, thickness, getMetadata() );
1042 }
1043
1044 break;
1045 }
1046
1047 case SHAPE_T::CIRCLE:
1048 if( isSolidFill )
1049 {
1050 int diameter = aShape->GetRadius() * 2 + thickness;
1051
1052 if( margin < 0 )
1053 {
1054 diameter += margin;
1055 diameter = std::max( diameter, 0 );
1056 }
1057
1058 m_plotter->FilledCircle( aShape->GetStart(), diameter, getMetadata() );
1059 }
1060 else
1061 {
1062 m_plotter->ThickCircle( aShape->GetStart(), aShape->GetRadius() * 2, thickness, getMetadata() );
1063 }
1064
1065 break;
1066
1067 case SHAPE_T::ARC:
1068 {
1069 // when startAngle == endAngle ThickArc() doesn't know whether it's 0 deg and 360 deg
1070 // but it is a circle
1071 if( std::abs( aShape->GetArcAngle().AsDegrees() ) == 360.0 )
1072 {
1073 m_plotter->ThickCircle( aShape->GetCenter(), aShape->GetRadius() * 2, thickness, getMetadata() );
1074 }
1075 else
1076 {
1077 EDA_ANGLE startAngle;
1078 EDA_ANGLE endAngle;
1079 aShape->CalcArcAngles( startAngle, endAngle );
1080
1081 EDA_ANGLE arcAngle = endAngle - startAngle;
1082
1083 if( aShape->ShortenArcForEndings( startAngle, arcAngle, aShape->GetRadius(), thickness ) )
1084 {
1085 m_plotter->ThickArc( VECTOR2D( aShape->GetCenter() ), startAngle, arcAngle, aShape->GetRadius(),
1086 thickness, getMetadata() );
1087 }
1088 }
1089
1090 break;
1091 }
1092
1093 case SHAPE_T::BEZIER:
1094 if( std::optional<BEZIER<double>> curve = aShape->ShortenedBezierCurve( thickness ) )
1095 {
1096 if( m_plotter->GetPlotterType() == PLOT_FORMAT::SVG )
1097 {
1098 m_plotter->BezierCurve( VECTOR2I( curve->Start ), VECTOR2I( curve->C1 ), VECTOR2I( curve->C2 ),
1099 VECTOR2I( curve->End ), aShape->GetMaxError(), thickness );
1100 }
1101 else
1102 {
1103 std::vector<VECTOR2D> pts = aShape->ShortenedBezierPolyline( thickness );
1104
1105 for( size_t i = 0; i + 1 < pts.size(); i++ )
1106 m_plotter->ThickSegment( VECTOR2I( pts[i] ), VECTOR2I( pts[i + 1] ), thickness, getMetadata() );
1107 }
1108 }
1109
1110 break;
1111
1112 case SHAPE_T::POLY:
1113 if( aShape->IsPolyShapeValid() )
1114 {
1115 auto plotStrokeOutline =
1116 [&]( const SHAPE_LINE_CHAIN& aOutline, int aOutlineIdx )
1117 {
1118 if( aOutline.PointCount() < 2 )
1119 return;
1120
1121 if( aShape->GetStartEnding().GetShortenDepth( thickness ) > 0
1122 || aShape->GetEndEnding().GetShortenDepth( thickness ) > 0 )
1123 {
1124 std::vector<VECTOR2I> pts;
1125
1126 if( !aShape->GetShortenedBodyPolyPoints( aOutline, aOutlineIdx, pts, thickness ) )
1127 return;
1128
1129 SHAPE_LINE_CHAIN shortened;
1130
1131 for( const VECTOR2I& pt : pts )
1132 shortened.Append( pt );
1133
1134 shortened.SetClosed( aOutline.IsClosed() );
1135 m_plotter->PlotPoly( shortened, FILL_T::NO_FILL, thickness, getMetadata() );
1136 }
1137 else
1138 {
1139 m_plotter->PlotPoly( aOutline, FILL_T::NO_FILL, thickness, getMetadata() );
1140 }
1141 };
1142
1143 if( m_plotter->GetPlotterType() == PLOT_FORMAT::DXF && GetDXFPlotMode() == SKETCH )
1144 {
1145 m_plotter->ThickPoly( aShape->GetPolyShape(), thickness, getMetadata() );
1146 }
1147 else
1148 {
1149 m_plotter->SetCurrentLineWidth( thickness, &gbr_metadata );
1150
1151 const SHAPE_POLY_SET& origPoly = aShape->GetPolyShape();
1152
1153 // Stroke the unfractured outline so degenerate near-zero-width spikes (which Fracture()
1154 // collapses but the editor still draws as thick lines) are preserved in the plot output
1155 // (issue #24143).
1156 if( thickness > 0 )
1157 {
1158 if( m_plotter->GetPlotterType() == PLOT_FORMAT::DXF && isSolidFill )
1159 {
1160 // We can't split outline and fill into separate instructions for DXF as it
1161 // doesn't do fills, so we need the outline to be drawn only once (and include
1162 // any thick edge).
1163 }
1164 else
1165 {
1166 for( int jj = 0; jj < origPoly.OutlineCount(); ++jj )
1167 plotStrokeOutline( origPoly.COutline( jj ), jj );
1168
1169 thickness = 0;
1170 }
1171 }
1172
1173 if( !isSolidFill )
1174 break;
1175
1176 // Fracture before plotting the fill to avoid invalid gerber regions generated from
1177 // self-intersecting or overlapping outlines.
1178 SHAPE_POLY_SET tmpPoly = origPoly.CloneDropTriangulation();
1179 tmpPoly.Fracture();
1180
1181 if( margin < 0 )
1182 tmpPoly.Inflate( margin / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS, aShape->GetMaxError() );
1183
1184 for( int jj = 0; jj < tmpPoly.OutlineCount(); ++jj )
1185 {
1186 SHAPE_LINE_CHAIN& poly = tmpPoly.Outline( jj );
1187 poly.SetClosed( true );
1188
1189 // Width 0; the stroke was already plotted from the unfractured outline.
1190 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1191 {
1192 GERBER_PLOTTER* gbr_plotter = static_cast<GERBER_PLOTTER*>( m_plotter );
1193 gbr_plotter->PlotPolyAsRegion( poly, FILL_T::FILLED_SHAPE, thickness, &gbr_metadata );
1194 }
1195 else
1196 {
1197 m_plotter->PlotPoly( poly, FILL_T::FILLED_SHAPE, thickness, getMetadata() );
1198 }
1199 }
1200 }
1201 }
1202
1203 break;
1204
1205 case SHAPE_T::RECTANGLE:
1206 {
1207 int radius = aShape->GetCornerRadius();
1208
1209 if( radius == 0 && m_plotter->GetPlotterType() == PLOT_FORMAT::DXF && GetDXFPlotMode() == SKETCH )
1210 {
1211 std::vector<VECTOR2I> pts = aShape->GetRectCorners();
1212 m_plotter->ThickRect( pts[0], pts[2], thickness, getMetadata() );
1213 }
1214 else
1215 {
1216 BOX2I box( aShape->GetStart(), VECTOR2I( aShape->GetEnd().x - aShape->GetStart().x,
1217 aShape->GetEnd().y - aShape->GetStart().y ) );
1218 box.Normalize();
1219
1220 if( margin < 0 )
1221 {
1222 box.Inflate( margin );
1223 radius += margin;
1224 }
1225
1226 SHAPE_RECT rect( box );
1227 rect.SetRadius( radius );
1228
1229 SHAPE_LINE_CHAIN outline = rect.Outline();
1230 SHAPE_POLY_SET poly( outline );
1231
1232 FILL_T fill_mode = isSolidFill ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL;
1233
1234 if( poly.OutlineCount() > 0 )
1235 {
1236 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1237 {
1238 GERBER_PLOTTER* gbr_plotter = static_cast<GERBER_PLOTTER*>( m_plotter );
1239 gbr_plotter->PlotPolyAsRegion( poly.COutline( 0 ), fill_mode, thickness, &gbr_metadata );
1240 }
1241 else
1242 {
1243 // TODO: PlotPoly needs to handle arcs...
1244 m_plotter->PlotPoly( poly.COutline( 0 ), fill_mode, thickness, getMetadata() );
1245 }
1246 }
1247 }
1248
1249 break;
1250 }
1251
1252 case SHAPE_T::ELLIPSE:
1254 {
1255 const bool isClosed = ( aShape->GetShape() == SHAPE_T::ELLIPSE );
1256
1257 SHAPE_ELLIPSE e = isClosed ? SHAPE_ELLIPSE( aShape->GetEllipseCenter(), aShape->GetEllipseMajorRadius(),
1258 aShape->GetEllipseMinorRadius(), aShape->GetEllipseRotation() )
1260 aShape->GetEllipseMinorRadius(), aShape->GetEllipseRotation(),
1261 aShape->GetEllipseStartAngle(), aShape->GetEllipseEndAngle() );
1262
1264
1265 if( isClosed )
1266 chain.SetClosed( true );
1267
1268 FILL_T fill = ( isClosed && isSolidFill ) ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL;
1269
1270 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER && isClosed )
1271 {
1272 GERBER_PLOTTER* gbr_plotter = static_cast<GERBER_PLOTTER*>( m_plotter );
1273 gbr_plotter->PlotPolyAsRegion( chain, fill, thickness, &gbr_metadata );
1274 }
1275 else
1276 {
1277 m_plotter->PlotPoly( chain, fill, thickness, getMetadata() );
1278 }
1279
1280 break;
1281 }
1282
1283 default:
1285 }
1286 }
1287 else
1288 {
1289 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapesForStroking( thickness );
1290
1291 for( SHAPE* shape : shapes )
1292 {
1293 STROKE_PARAMS::Stroke( shape, lineStyle, aShape->GetWidth(),
1294 m_plotter->RenderSettings(),
1295 [&]( const VECTOR2I& a, const VECTOR2I& b )
1296 {
1297 m_plotter->ThickSegment( a, b, thickness, getMetadata() );
1298 } );
1299 }
1300
1301 for( SHAPE* shape : shapes )
1302 delete shape;
1303 }
1304
1305 // Plot line endings for open shapes.
1308 {
1309 EDA_ANGLE startTangent, endTangent;
1310 aShape->GetEndingTangents( startTangent, endTangent, thickness );
1311
1312 VECTOR2I startPt, endPt;
1313
1314 if( aShape->GetLineEndingEndpoints( startPt, endPt ) )
1315 {
1316 aShape->GetStartEnding().Plot( m_plotter, startPt, startTangent, thickness, getMetadata() );
1317 aShape->GetEndEnding().Plot( m_plotter, endPt, endTangent, thickness, getMetadata() );
1318 }
1319 }
1320
1321 if( isHatchedFill )
1322 {
1323 for( int ii = 0; ii < aShape->GetHatching().OutlineCount(); ++ii )
1324 {
1325 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1326 {
1327 GERBER_PLOTTER* gbr_plotter = static_cast<GERBER_PLOTTER*>( m_plotter );
1328 gbr_plotter->PlotPolyAsRegion( aShape->GetHatching().Outline( ii ), FILL_T::FILLED_SHAPE, 0,
1329 &gbr_metadata );
1330 }
1331 else
1332 {
1333 m_plotter->PlotPoly( aShape->GetHatching().Outline( ii ), FILL_T::FILLED_SHAPE, 0, getMetadata() );
1334 }
1335 }
1336 }
1337}
1338
1339
1340void BRDITEMS_PLOTTER::PlotBarCode( const PCB_BARCODE* aBarCode ) const
1341{
1342 if( !m_layerMask[aBarCode->GetLayer()] )
1343 return;
1344
1345 // To avoid duplicate code, build a PCB_SHAPE to plot the polygon shape
1346 PCB_SHAPE dummy( aBarCode->GetParent(), SHAPE_T::POLY );
1347 dummy.SetLayer( aBarCode->GetLayer() );
1348 dummy.SetFillMode( FILL_T::FILLED_SHAPE );
1349 dummy.SetWidth( 0 );
1350
1351 SHAPE_POLY_SET shape;
1352 aBarCode->TransformShapeToPolySet( shape, aBarCode->GetLayer(), 0, 0, ERROR_INSIDE );
1353 dummy.SetPolyShape( shape );
1354
1355 PlotShape( &dummy );
1356}
1357
1358
1360{
1361 if( !m_layerMask[aTable->GetLayer()] )
1362 return;
1363
1364 GBR_METADATA gbr_metadata;
1365
1366 if( const FOOTPRINT* parentFP = aTable->GetParentFootprint() )
1367 {
1368 gbr_metadata.SetCmpReference( parentFP->GetReference() );
1370 }
1371
1372 aTable->DrawBorders(
1373 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB, const STROKE_PARAMS& stroke )
1374 {
1375 int lineWidth = stroke.GetWidth();
1376 LINE_STYLE lineStyle = stroke.GetLineStyle();
1377
1378 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
1379 {
1380 m_plotter->ThickSegment( ptA, ptB, lineWidth, getMetadata() );
1381 }
1382 else
1383 {
1384 SHAPE_SEGMENT seg( ptA, ptB );
1385
1386 STROKE_PARAMS::Stroke( &seg, lineStyle, lineWidth, m_plotter->RenderSettings(),
1387 [&]( const VECTOR2I& a, const VECTOR2I& b )
1388 {
1389 m_plotter->ThickSegment( a, b, lineWidth, getMetadata() );
1390 } );
1391 }
1392 } );
1393}
1394
1395
1397 const VECTOR2I& aDrillSize, const VECTOR2I& aPadSize,
1398 const EDA_ANGLE& aOrientation, int aSmallDrill ) const
1399{
1400 VECTOR2I drillSize = aDrillSize;
1401
1402 // Small drill marks have no significance when applied to slots
1403 if( aSmallDrill && aDrillShape == PAD_DRILL_SHAPE::CIRCLE )
1404 drillSize.x = std::min( aSmallDrill, drillSize.x );
1405
1406 // Round holes only have x diameter, slots have both
1407 drillSize.x -= getFineWidthAdj();
1408 drillSize.x = std::clamp( drillSize.x, 1, aPadSize.x - 1 );
1409
1410 if( aDrillShape == PAD_DRILL_SHAPE::OBLONG )
1411 {
1412 drillSize.y -= getFineWidthAdj();
1413 drillSize.y = std::clamp( drillSize.y, 1, aPadSize.y - 1 );
1414
1415 m_plotter->FlashPadOval( aDrillPos, drillSize, aOrientation, nullptr );
1416 }
1417 else
1418 {
1419 m_plotter->FlashPadCircle( aDrillPos, drillSize.x, nullptr );
1420 }
1421}
1422
1423
1425{
1426 int smallDrill = 0;
1427
1429 smallDrill = pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_SmallDrillMarkSize );
1430
1431 /* Drill marks are drawn white-on-black to knock-out the underlying pad. This works only
1432 * for drivers supporting color change, obviously... it means that:
1433 - PS, SVG and PDF output is correct (i.e. you have a 'donut' pad)
1434 - In gerbers you can't see them. This is arguably the right thing to do since having
1435 drill marks and high speed drill stations is a sure recipe for broken tools and angry
1436 manufacturers. If you *really* want them you could start a layer with negative
1437 polarity to knock-out the film.
1438 - In DXF they go into the 'WHITE' layer. This could be useful.
1439 */
1440 if( m_plotter->GetPlotterType() != PLOT_FORMAT::DXF || GetDXFPlotMode() == FILLED )
1441 m_plotter->SetColor( WHITE );
1442
1443 for( PCB_TRACK* track : m_board->Tracks() )
1444 {
1445 if( track->Type() == PCB_VIA_T )
1446 {
1447 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
1448
1449 // Via are not always on all layers
1450 if( ( via->GetLayerSet() & m_layerMask ).none() )
1451 continue;
1452
1454 VECTOR2I( via->GetDrillValue(), 0 ),
1455 VECTOR2I( via->GetWidth( PADSTACK::TEMP_ALL_LAYERS ), 0 ),
1456 ANGLE_0, smallDrill );
1457 }
1458 }
1459
1460 for( FOOTPRINT* footprint : m_board->Footprints() )
1461 {
1462 for( PAD* pad : footprint->Pads() )
1463 {
1464 if( pad->GetDrillSize().x == 0 )
1465 continue;
1466
1467 // Skip marks on layers the pad isn't on for Gerber only (24416). Other
1468 // formats keep them as a drill map, e.g. Edge.Cuts (24867).
1469 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER && ( pad->GetLayerSet() & m_layerMask ).none() )
1470 continue;
1471
1472 if( m_plotter->GetPlotterType() != PLOT_FORMAT::DXF || GetDXFPlotMode() == FILLED )
1473 {
1474 // Drill mark is in black unless we can find something to knock it out of
1475 m_plotter->SetColor( BLACK );
1476
1477 for( PCB_LAYER_ID layer : m_layerMask )
1478 {
1479 if( !pad->IsOnLayer( layer ) )
1480 continue;
1481
1482 VECTOR2I padSize = pad->GetSize( layer );
1483
1484 if( padSize.x > pad->GetDrillSize().x || padSize.y > pad->GetDrillSize().y )
1485 {
1486 m_plotter->SetColor( WHITE );
1487 break;
1488 }
1489 }
1490 }
1491
1492 plotOneDrillMark( pad->GetDrillShape(), pad->GetPosition(), pad->GetDrillSize(),
1493 pad->GetSize( PADSTACK::TEMP_ALL_LAYERS ), pad->GetOrientation(), smallDrill );
1494 }
1495 }
1496
1497 if( m_plotter->GetPlotterType() != PLOT_FORMAT::DXF || GetDXFPlotMode() == FILLED )
1498 m_plotter->SetColor( BLACK );
1499}
1500
1501
1503{
1504 const std::vector<const PCB_DRILL_MAP*> maps = m_board->DrillMapsOnLayer( aLayer );
1505
1506 if( maps.empty() )
1507 return;
1508
1509 const DRILL_SYMBOL_PROFILE& profile = m_board->GetDesignSettings().GetDrillSymbolProfile();
1510
1511 // Resolved rather than read straight from the profile, so a map drawn without any chart
1512 // ever having been placed still shows marks
1513 const std::shared_ptr<const DRILL_SYMBOL_CACHE> cache = m_board->DrillSymbolCache();
1514
1515 // DXF reads its sketch/filled mode back out of this. Without it every stroked mark is
1516 // emitted filled no matter what the user asked for
1517 GBR_METADATA gbr_metadata;
1518
1519 m_plotter->SetColor( getColor( aLayer ) );
1520 m_plotter->SetCurrentLineWidth( profile.GetSymbolWidth() );
1521
1522 DRILL_QUERY query;
1523 query.m_MergePTHNPTH = true;
1524
1525 // Several maps can share a layer. The UI prevents it but a parsed, pasted or
1526 // API-created board need not
1527 for( const PCB_DRILL_MAP* map : maps )
1528 {
1529
1530 const std::shared_ptr<const SHAPE_POLY_SET> outlines = map->GetBoardOutlines();
1531
1532 for( int ii = 0; ii < outlines->OutlineCount(); ++ii )
1533 {
1534 m_plotter->PlotPoly( outlines->COutline( ii ), FILL_T::NO_FILL, profile.GetSymbolWidth(),
1535 getMetadata() );
1536
1537 for( int jj = 0; jj < outlines->HoleCount( ii ); ++jj )
1538 {
1539 m_plotter->PlotPoly( outlines->CHole( ii, jj ), FILL_T::NO_FILL, profile.GetSymbolWidth(),
1540 getMetadata() );
1541 }
1542 }
1543
1544 for( const DRILL_SPAN& span : EnumerateDrillSpans( *m_board ) )
1545 {
1546 // The map's own span filter, so a backdrill map does not print every other hole too
1547 if( !map->GetAllSpans() && !( span == map->GetSpan() ) )
1548 continue;
1549
1550 query.m_Span = span;
1551
1552 for( const DRILL_OPERATION& op : EnumerateDrillOperations( *m_board, query ) )
1553 {
1554 // The map is a set of marks on the holes, displaced as a whole. The holes
1555 // themselves never move
1556 const VECTOR2I pos = op.m_Position + map->GetOffset();
1557
1558 const auto it = cache->m_ByGroup.find( profile.GroupKeyString( op ) );
1559
1560 if( it == cache->m_ByGroup.end() )
1561 continue;
1562
1563 const DRILL_SYMBOL_ASSIGNMENT& assignment = it->second;
1564
1565 if( assignment.m_MarkMode == DRILL_MARK_MODE::SHAPE )
1566 {
1567 m_plotter->Marker( pos, map->GetSymbolSize(),
1569 }
1570 else
1571 {
1572 const wxString text =
1574 ? assignment.m_Letter
1575 : wxString::Format( wxT( "%.2f" ),
1576 pcbIUScale.IUTomm( op.m_Diameter ) );
1577
1578 TEXT_ATTRIBUTES attrs;
1579 attrs.m_Size = VECTOR2I( map->GetSymbolSize(), map->GetSymbolSize() );
1580 attrs.m_StrokeWidth = profile.GetSymbolWidth();
1583
1584 m_plotter->PlotText( pos, getColor( aLayer ), text, attrs, nullptr,
1586 }
1587
1588 if( map->GetGuideCross() )
1589 {
1590 const int reach = map->GetSymbolSize();
1591
1592 m_plotter->ThickSegment( pos - VECTOR2I( reach, 0 ),
1593 pos + VECTOR2I( reach, 0 ),
1594 profile.GetSymbolWidth(), getMetadata() );
1595 m_plotter->ThickSegment( pos - VECTOR2I( 0, reach ),
1596 pos + VECTOR2I( 0, reach ),
1597 profile.GetSymbolWidth(), getMetadata() );
1598 }
1599
1600 // A slot's true extent is the cost driver, so it is drawn as well as marked
1601 if( map->GetOutlineSlots() && op.m_IsSlot )
1602 {
1603 m_plotter->ThickOval( pos, op.m_SizeXY, op.m_Orientation,
1604 profile.GetSymbolWidth(), getMetadata() );
1605 }
1606 }
1607 }
1608 }
1609
1610 m_plotter->SetCurrentLineWidth( PLOTTER::USE_DEFAULT_LINE_WIDTH );
1611}
1612
1613
1615{
1616
1617 if( aChart->GetSymbolColumn() < 0 || aChart->RowShapes().empty() )
1618 return;
1619
1620 const DRILL_SYMBOL_PROFILE& profile = m_board->GetDesignSettings().GetDrillSymbolProfile();
1621
1622 m_plotter->SetColor( getColor( aChart->GetLayer() ) );
1623 m_plotter->SetCurrentLineWidth( profile.GetSymbolWidth() );
1624
1625 for( const auto& [row, shapeIndex] : aChart->RowShapes() )
1626 {
1627 const PCB_TABLECELL* cell = aChart->GetCell( row, aChart->GetSymbolColumn() );
1628
1629 if( !cell )
1630 continue;
1631
1632 const BOX2I box = cell->GetBoundingBox();
1633
1634 // Same fit as the painter, so the plotted chart matches what was on screen
1635 const int size = std::min<int>( profile.GetSymbolSize(),
1636 std::min( box.GetWidth(), box.GetHeight() ) * 2 / 3 );
1637
1638 if( size > 0 )
1639 m_plotter->Marker( box.GetCenter(), size, DRILL_MARKERS::CuratedShape( shapeIndex ) );
1640 }
1641
1642 m_plotter->SetCurrentLineWidth( PLOTTER::USE_DEFAULT_LINE_WIDTH );
1643}
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
constexpr int ARC_LOW_DEF
Definition base_units.h:143
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Generic cubic Bezier representation.
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.
FOOTPRINT * GetParentFootprint() const
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
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr Vec Centre() const
Definition box2.h:94
constexpr const Vec GetCenter() const
Definition box2.h:227
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr coord_type GetLeft() const
Definition box2.h:225
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr const SizeVec & GetSize() const
Definition box2.h:203
constexpr coord_type GetTop() const
Definition box2.h:226
constexpr coord_type GetBottom() const
Definition box2.h:219
void PlotFootprintGraphicItems(const FOOTPRINT *aFootprint) const
void PlotBoardGraphicItem(const BOARD_ITEM *item) const
Plot items like text and graphics but not tracks and footprints.
void PlotText(const EDA_TEXT *aText, PCB_LAYER_ID aLayer, bool aIsKnockout, const KIFONT::METRICS &aFontMetrics, bool aStrikeout=false) const
void PlotPadNumber(const PAD *aPad, const COLOR4D &aColor) const
void PlotDimension(const PCB_DIMENSION_BASE *aDim) const
void PlotDrillSymbols(PCB_LAYER_ID aLayer) const
Draw each hole's chart symbol on aLayer, from the board's shared symbol profile.
void PlotZone(const ZONE *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList) const
void plotOneDrillMark(PAD_DRILL_SHAPE aDrillShape, const VECTOR2I &aDrillPos, const VECTOR2I &aDrillSize, const VECTOR2I &aPadSize, const EDA_ANGLE &aOrientation, int aSmallDrill) const
Helper function to plot a single drill mark.
bool crossoutDNPItems(PCB_LAYER_ID aLayer) const
Definition pcbplot.h:146
void PlotTableBorders(const PCB_TABLE *aTable) const
bool hideDNPItems(PCB_LAYER_ID aLayer) const
Definition pcbplot.h:141
void PlotFootprintTextItems(const FOOTPRINT *aFootprint) const
PLOTTER * m_plotter
Definition pcbplot.h:159
void PlotPcbTarget(const PCB_TARGET *aMire) const
const BOARD * m_board
Definition pcbplot.h:160
COLOR4D getColor(int aLayer) const
White color is special because it cannot be seen on a white paper in B&W mode.
void PlotDrillMarks() const
Draw a drill mark for pads and vias.
void PlotShape(const PCB_SHAPE *aShape) const
int getFineWidthAdj() const
Definition pcbplot.h:75
void PlotBarCode(const PCB_BARCODE *aBarCode) const
void PlotChartSymbols(const PCB_DRILL_CHART *aChart) const
Shape marks in a chart's symbol column, which carry no cell text of their own.
void PlotPad(const PAD *aPad, PCB_LAYER_ID aLayer, const COLOR4D &aColor, bool aSketchMode) const
Plot a pad.
static const COLOR4D WHITE
Definition color4d.h:403
COLOR4D GetColor(int aLayer) const
Grouping rules and symbol assignments, shared by reference so a chart and its map can never disagree ...
std::string GroupKeyString(const DRILL_OPERATION &aOperation) const
Stable identity for a group under the currently enabled keys.
double AsDegrees() const
Definition eda_angle.h:115
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.
EDA_ANGLE GetArcAngle() const
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
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.
virtual void SetFilled(bool aFlag)
Definition eda_shape.h:144
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
std::optional< BEZIER< double > > ShortenedBezierCurve(int aLineWidth) const
Return the cubic Bezier curve shortened for line endings.
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
bool IsPolyShapeValid() const
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
virtual VECTOR2I GetTextSize() const
Definition eda_text.h:301
virtual VECTOR2I GetTextPos() const
Definition eda_text.h:313
bool IsMultilineAllowed() const
Definition eda_text.h:236
virtual bool IsVisible() const
Definition eda_text.h:226
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 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
virtual KIFONT::FONT * GetDrawFont(const RENDER_SETTINGS *aSettings) const
Definition eda_text.cpp:647
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
void GetLinePositions(const RENDER_SETTINGS *aSettings, std::vector< VECTOR2I > &aPositions, int aLineCount) const
Populate aPositions with the position of each line of a multiline text, according to the vertical jus...
Definition eda_text.cpp:931
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:831
LSET GetPrivateLayers() const
Definition footprint.h:295
PCB_FIELD & Reference()
Definition footprint.h:832
bool GetDNPForVariant(const wxString &aVariantName) const
Get the DNP status for a specific variant.
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
const wxString & GetReference() const
Definition footprint.h:793
DRAWINGS & GraphicalItems()
Definition footprint.h:358
@ GBR_APERTURE_ATTRIB_CONDUCTOR
Aperture used for connected items like tracks (not vias).
@ GBR_APERTURE_ATTRIB_ETCHEDCMP
Aperture used for etched components.
@ GBR_APERTURE_ATTRIB_BGAPAD_CUDEF
Aperture used for BGA pad with a solder mask defined by the solder mask.
@ GBR_APERTURE_ATTRIB_HEATSINKPAD
Aperture used for heat sink pad (typically for SMDs).
@ GBR_APERTURE_ATTRIB_TESTPOINT
Aperture used for test point pad (outer layers).
@ GBR_APERTURE_ATTRIB_SMDPAD_CUDEF
Aperture used for SMD pad with a solder mask defined by the solder mask.
@ GBR_APERTURE_ATTRIB_CONNECTORPAD
Aperture used for edge connector pad (outer layers).
@ GBR_APERTURE_ATTRIB_NONCONDUCTOR
Aperture used for not connected items (texts, outlines on copper).
@ GBR_APERTURE_ATTRIB_WASHERPAD
Aperture used for mechanical pads (NPTH).
@ GBR_APERTURE_ATTRIB_COMPONENTPAD
Aperture used for through hole component on outer layer.
@ GBR_APERTURE_ATTRIB_FIDUCIAL_GLBL
Aperture used for fiducial pad (outer layers), at board level.
@ GBR_APERTURE_ATTRIB_CASTELLATEDPAD
Aperture used for castellated pads in copper layer files.
@ GBR_APERTURE_ATTRIB_FIDUCIAL_LOCAL
Aperture used for fiducial pad (outer layers), at footprint level.
@ GBR_APERTURE_ATTRIB_EDGECUT
Aperture used for board cutout,.
Metadata which can be added in a gerber file as attribute in X2 format.
void SetCopper(bool aValue)
void SetCmpReference(const wxString &aComponentRef)
void SetNetName(const wxString &aNetname)
void SetPadPinFunction(const wxString &aPadPinFunction, bool aUseUTF8, bool aEscapeString)
void SetApertureAttrib(GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB aApertAttribute)
GBR_NETLIST_METADATA m_NetlistMetadata
An item to handle object attribute.
void SetNetAttribType(int aNetAttribType)
void SetPadName(const wxString &aPadname, bool aUseUTF8=false, bool aEscapeString=false)
@ GBR_NETINFO_NET
print info associated to a net (TO.N attribute)
@ GBR_NETINFO_CMP
print info associated to a component (TO.C attribute)
bool m_NotInNet
true if a pad of a footprint cannot be connected (for instance a mechanical NPTH, ot a not named pad)...
void FlashPadChamferRoundRect(const VECTOR2I &aShapePos, const VECTOR2I &aPadSize, int aCornerRadius, double aChamferRatio, int aChamferPositions, const EDA_ANGLE &aPadOrient, void *aData)
Flash a chamfered round rect pad.
void PlotPolyAsRegion(const SHAPE_LINE_CHAIN &aPoly, FILL_T aFill, int aWidth, GBR_METADATA *aGbrMetadata)
Similar to PlotPoly(), plot a filled polygon using Gerber region, therefore adding X2 attributes to t...
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:94
virtual bool IsOutline() const
Definition font.h:102
static const METRICS & Default()
Definition font.cpp:49
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
virtual void DrawGlyphs(const std::vector< std::unique_ptr< KIFONT::GLYPH > > &aGlyphs)
Draw polygons representing font glyphs.
int GetShortenDepth(int aLineWidth) const
Return how far the line should be shortened at this ending.
LINE_ENDING_STYLE GetStyle() const
Definition line_ending.h:81
void Plot(PLOTTER *aPlotter, const VECTOR2I &aPoint, const EDA_ANGLE &aTangent, int aLineWidth, void *aData=nullptr) const
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
static const LSET & ExternalCuMask()
Return a mask holding the Front and Bottom layers.
Definition lset.cpp:630
static constexpr PCB_LAYER_ID TEMP_ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition padstack.h:176
Definition pad.h:61
PAD_PROP GetProperty() const
Definition pad.h:563
static wxString ShowPadShape(PAD_SHAPE aShape)
Definition pad.cpp:2627
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives(PCB_LAYER_ID aLayer) const
Accessor to the basic shape list for custom-shaped pads.
Definition pad.h:375
int GetRoundRectCornerRadius(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1181
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition pad.cpp:1673
PAD_ATTRIB GetAttribute() const
Definition pad.h:560
const wxString & GetPinFunction() const
Definition pad.h:154
const wxString & GetNumber() const
Definition pad.h:143
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
Definition pad.h:307
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
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.cpp:1795
int GetChamferPositions(PCB_LAYER_ID aLayer) const
Definition pad.h:852
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition pad.cpp:1239
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:834
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1906
Abstract dimension API.
int GetLineThickness() const
const std::vector< std::shared_ptr< SHAPE > > & GetShapes() const
A drill chart placed on the board, kept in step with the holes.
const std::map< int, int > & RowShapes() const
Curated shape index for each generated row, by table row.
int GetSymbolColumn() const
Table column the symbol is drawn in, or -1 when the chart has no symbol column.
Turns on drill symbols at the holes, for one layer.
bool GetSketchDNPFPsOnFabLayers() const
PLOT_TEXT_MODE GetTextMode() const override
bool GetPlotReference() const
DXF_OUTLINE_MODE GetDXFPlotMode() const override
int GetSketchPadLineWidth() const
DRILL_MARKS GetDrillMarksType() const
bool GetPlotValue() const
bool GetPlotFPText() const
COLOR_SETTINGS * ColorSettings() const
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 SetShape(SHAPE_T aShape) override
Definition pcb_shape.h:212
void SetEnd(const VECTOR2I &aEnd) override
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
STROKE_PARAMS GetStroke() const override
void SetStart(const VECTOR2I &aStart) override
void SetStroke(const STROKE_PARAMS &aStroke) override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:70
PCB_TABLECELL * GetCell(int aRow, int aCol) const
Definition pcb_table.h:155
void DrawBorders(const std::function< void(const VECTOR2I &aPt1, const VECTOR2I &aPt2, const STROKE_PARAMS &aStroke)> &aCallback) const
int GetShape() const
Definition pcb_target.h:54
int GetWidth() const
Definition pcb_target.h:60
int GetSize() const
Definition pcb_target.h:57
VECTOR2I GetPosition() const override
Definition pcb_target.h:51
bool IsBorderEnabled() const
Tests whether the border is disabled, as configured by the stroke.
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Convert the text to a polygonSet describing the actual character strokes (one per segment).
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
PCB_SHAPE GetPolygonalBoxShape() const
Base plotter engine class.
Definition plotter.h:138
static const int USE_DEFAULT_LINE_WIDTH
Definition plotter.h:142
virtual PLOT_FORMAT GetPlotterType() const =0
Return the effective plot engine in use.
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I B
Definition seg.h:46
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.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
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.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int OutlineCount() const
Return the number of outlines in the set.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
SHAPE_POLY_SET CloneDropTriangulation() const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
const SHAPE_LINE_CHAIN Outline() const
void SetRadius(int aRadius)
Definition shape_rect.h:201
const SEG & GetSeg() const
An abstract shape on 2D plane.
Definition shape.h:124
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
GR_TEXT_H_ALIGN_T m_Halign
GR_TEXT_V_ALIGN_T m_Valign
Handle a list of polygons defining a copper zone.
Definition zone.h:70
bool IsOnCopperLayer() const override
Definition zone.cpp:650
A type-safe container of any type.
Definition ki_any.h:92
constexpr any() noexcept
Default constructor, creates an empty object.
Definition ki_any.h:155
@ WHITE
Definition color4d.h:44
@ LIGHTGRAY
Definition color4d.h:43
@ BLACK
Definition color4d.h:40
@ FOR_CANVAS
Definition common.h:92
@ ROUND_ALL_CORNERS
All angles are rounded.
std::vector< DRILL_SPAN > EnumerateDrillSpans(const BOARD &aBoard, bool aPadBackdrills)
Every drill span present on the board, through-holes first.
std::vector< DRILL_OPERATION > EnumerateDrillOperations(const BOARD &aBoard, const DRILL_QUERY &aQuery)
The one place that decides what the board's holes are.
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:450
FILL_T
Definition eda_fill.h:29
@ NO_FILL
Definition eda_fill.h:30
@ FILLED_SHAPE
Fill with object color.
Definition eda_fill.h:31
@ 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
Handle special data (items attributes) during plot.
#define GBR_NETINFO_ALL
static const bool FILLED
Definition gr_basic.cpp:30
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:741
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:752
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ Edge_Cuts
Definition layer_ids.h:108
@ B_Mask
Definition layer_ids.h:94
@ F_Mask
Definition layer_ids.h:93
@ F_Fab
Definition layer_ids.h:115
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:167
@ B_Fab
Definition layer_ids.h:114
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:79
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
unsigned CuratedShape(int aIndex)
Pattern index for the nth curated mark.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
PAD_DRILL_SHAPE
The set of pad drill shapes, used with PAD::{Set,Get}DrillShape()
Definition padstack.h:68
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:102
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ PTH
Plated through hole pad.
Definition padstack.h:97
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:99
@ CHAMFERED_RECT
Definition padstack.h:59
@ ROUNDRECT
Definition padstack.h:56
@ TRAPEZOID
Definition padstack.h:55
@ RECTANGLE
Definition padstack.h:53
@ FIDUCIAL_LOCAL
a fiducial (usually a smd) local to the parent footprint
Definition padstack.h:117
@ FIDUCIAL_GLBL
a fiducial (usually a smd) for the full board
Definition padstack.h:116
@ MECHANICAL
a pad used for mechanical support
Definition padstack.h:121
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
Definition padstack.h:122
@ HEATSINK
a pad used as heat sink, usually in SMD footprints
Definition padstack.h:119
@ NONE
no special fabrication property
Definition padstack.h:114
@ TESTPOINT
a test point pad
Definition padstack.h:118
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:120
@ BGA
Smd pad, used in BGA footprints.
Definition padstack.h:115
BARCODE class definition.
static void * plotMetadata(PLOTTER *aPlotter, GBR_METADATA &aMetadata, const PLOT_PARAMS *aPlotOptions)
#define getMetadata()
@ SKETCH
Definition plotter.h:83
@ SH_CIRCLE
circle
Definition shape.h:46
@ SH_SEGMENT
line segment
Definition shape.h:44
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
int PrintableCharCount(const wxString &aString)
Return the number of printable (ie: non-formatting) chars.
LINE_STYLE
Dashed line types.
One machining action, which is also one NC hit and one tool assignment.
Selects which operations EnumerateDrillOperations() returns.
bool m_MergePTHNPTH
Emit plated and non-plated together, as the merged drill file does.
DRILL_SPAN m_Span
const SHAPE_LINE_CHAIN chain
int radius
VECTOR2I end
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_CENTER
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_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition typeinfo.h:81
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:99
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:94
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:97
@ PCB_DRILL_CHART_T
class PCB_DRILL_CHART, a live drill chart derived from PCB_TABLE
Definition typeinfo.h:239
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707