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 <bitset> // for bitset, operator&, __bi...
22#include <math.h> // for abs
23
24#include <geometry/seg.h> // for SEG
27#include <geometry/shape_line_chain.h> // for SHAPE_LINE_CHAIN
28#include <geometry/shape_poly_set.h> // for SHAPE_POLY_SET, SHAPE_P...
29#include <geometry/shape_rect.h>
31#include <string_utils.h>
32#include <macros.h>
33#include <math/util.h> // for KiROUND
34#include <math/vector2d.h> // for VECTOR2I
36#include <trigo.h>
37#include <font/stroke_font.h>
39#include <callback_gal.h>
40#include <core/typeinfo.h> // for dyn_cast, PCB_DIMENSION_T
41#include <gbr_metadata.h>
42#include <gbr_netlist_metadata.h> // for GBR_NETLIST_METADATA
43#include <layer_ids.h> // for LSET, IsCopperLayer
44#include <lset.h>
50#include <pcb_drill_chart.h>
51#include <pcb_drill_map.h>
52#include <pcbplot.h>
53#include <pcb_plot_params.h> // for PCB_PLOT_PARAMS, PCB_PL...
54#include <advanced_config.h>
55
56#include <line_ending.h>
57#include <pcb_dimension.h>
58#include <pcb_shape.h>
59#include <footprint.h>
60#include <pcb_track.h>
61#include <pad.h>
62#include <pcb_target.h>
63#include <pcb_text.h>
64#include <pcb_textbox.h>
65#include <pcb_tablecell.h>
66#include <pcb_table.h>
67#include <zone.h>
68#include <pcb_barcode.h>
69
70#include <wx/debug.h> // for wxASSERT_MSG
71
72
74{
75 COLOR4D color = ColorSettings()->GetColor( aLayer );
76
77 // A hack to avoid plotting a white item in white color on white paper
78 if( color == COLOR4D::WHITE )
79 color = COLOR4D( LIGHTGRAY );
80
81 return color;
82}
83
84
85void BRDITEMS_PLOTTER::PlotPadNumber( const PAD* aPad, const COLOR4D& aColor )
86{
87 wxString padNumber = UnescapeString( aPad->GetNumber() );
88
89 if( padNumber.IsEmpty() )
90 return;
91
92 BOX2I padBBox = aPad->GetBoundingBox();
93 VECTOR2I position = padBBox.Centre();
94 VECTOR2I padsize = padBBox.GetSize();
95
96 // TODO(JE) padstacks
98 {
99 // See if we have a number box
100 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives( PADSTACK::TEMP_ALL_LAYERS ) )
101 {
102 if( primitive->IsProxyItem() && primitive->GetShape() == SHAPE_T::RECTANGLE )
103 {
104 position = primitive->GetCenter();
105 RotatePoint( position, aPad->GetOrientation() );
106 position += aPad->ShapePos( PADSTACK::TEMP_ALL_LAYERS );
107
108 padsize.x = abs( primitive->GetBotRight().x - primitive->GetTopLeft().x );
109 padsize.y = abs( primitive->GetBotRight().y - primitive->GetTopLeft().y );
110
111 break;
112 }
113 }
114 }
115
117 {
118 // Don't allow a 45° rotation to bloat a pad's bounding box unnecessarily
119 int limit = KiROUND( std::min( aPad->GetSize( PADSTACK::TEMP_ALL_LAYERS ).x,
120 aPad->GetSize( PADSTACK::TEMP_ALL_LAYERS ).y ) * 1.1 );
121
122 if( padsize.x > limit && padsize.y > limit )
123 {
124 padsize.x = limit;
125 padsize.y = limit;
126 }
127 }
128
129 TEXT_ATTRIBUTES textAttrs;
130
131 textAttrs.m_Mirrored = m_plotter->GetPlotMirrored();
132
133 if( padsize.x < ( padsize.y * 0.95 ) )
134 {
135 textAttrs.m_Angle = ANGLE_90;
136 std::swap( padsize.x, padsize.y );
137 }
138
139 // approximate the size of the pad number text:
140 // We use a size for at least 3 chars, to give a good look even for short numbers
141 int tsize = KiROUND( padsize.x / std::max( PrintableCharCount( padNumber ), 3 ) );
142 tsize = std::min( tsize, padsize.y );
143
144 // enforce a max size
145 tsize = std::min( tsize, pcbIUScale.mmToIU( 5.0 ) );
146
147 textAttrs.m_Size = VECTOR2I( tsize, tsize );
148
149 // use a somewhat spindly font to go with the outlined pads
150 textAttrs.m_StrokeWidth = KiROUND( tsize / 12.0 );
151
152 m_plotter->PlotText( position, aColor, padNumber, textAttrs );
153}
154
155
156void BRDITEMS_PLOTTER::PlotPad( const PAD* aPad, PCB_LAYER_ID aLayer, const COLOR4D& aColor,
157 bool aSketchMode )
158{
159 VECTOR2I shape_pos = aPad->ShapePos( aLayer );
160 GBR_METADATA metadata;
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 PlotText( reference, refLayer, reference->IsKnockout(), reference->GetFontMetrics(),
413 dnp && crossoutDNPItems( refLayer ) );
414 }
415
416 const PCB_TEXT* value = &aFootprint->Value();
417 PCB_LAYER_ID valueLayer = value->GetLayer();
418
419 if( GetPlotValue()
420 && m_layerMask[valueLayer]
421 && value->IsVisible()
422 && !( dnp && hideDNPItems( valueLayer ) ) )
423 {
424 PlotText( value, valueLayer, value->IsKnockout(), value->GetFontMetrics(), false );
425 }
426
427 std::vector<PCB_TEXT*> texts;
428
429 // Skip the reference and value texts that are handled specially
430 for( PCB_FIELD* field : aFootprint->GetFields() )
431 {
432 wxCHECK2( field, continue );
433
434 if( field->IsReference() || field->IsValue() )
435 continue;
436
437 if( field->IsVisible() )
438 texts.push_back( field );
439 }
440
441 for( BOARD_ITEM* item : aFootprint->GraphicalItems() )
442 {
443 if( PCB_TEXT* textItem = dynamic_cast<PCB_TEXT*>( item ) )
444 texts.push_back( textItem );
445 }
446
447 for( const PCB_TEXT* text : texts )
448 {
449 PCB_LAYER_ID textLayer = text->GetLayer();
450 bool strikeout = false;
451
452 if( textLayer == Edge_Cuts || textLayer >= PCB_LAYER_ID_COUNT )
453 continue;
454
455 if( dnp && hideDNPItems( textLayer ) )
456 continue;
457
458 if( !m_layerMask[textLayer] || aFootprint->GetPrivateLayers().test( textLayer ) )
459 continue;
460
461 if( text->GetText() == wxT( "${REFERENCE}" ) )
462 {
463 if( !GetPlotReference() )
464 continue;
465
466 strikeout = dnp && crossoutDNPItems( textLayer );
467 }
468
469 if( text->GetText() == wxT( "${VALUE}" ) )
470 {
471 if( !GetPlotValue() )
472 continue;
473 }
474
475 PlotText( text, textLayer, text->IsKnockout(), text->GetFontMetrics(), strikeout );
476 }
477}
478
479
481{
482 switch( item->Type() )
483 {
484 case PCB_SHAPE_T:
485 PlotShape( static_cast<const PCB_SHAPE*>( item ) );
486 break;
487
488 case PCB_TEXT_T:
489 {
490 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
491 PlotText( text, text->GetLayer(), text->IsKnockout(), text->GetFontMetrics() );
492 break;
493 }
494
495 case PCB_TEXTBOX_T:
496 {
497 m_plotter->SetTextMode( PLOT_TEXT_MODE::STROKE );
498
499 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( item );
500 PlotText( textbox, textbox->GetLayer(), textbox->IsKnockout(), textbox->GetFontMetrics() );
501
502 if( textbox->IsBorderEnabled() )
503 {
504 // PlotShape works only for textbox rotated by 0 or 180 degrees.
505 // This is not always the case so use the polygonal shape of the box of the text box.
507 PlotShape( &dummy );
508 }
509
510 m_plotter->SetTextMode( GetTextMode() );
511 break;
512 }
513
514 case PCB_BARCODE_T:
515 PlotBarCode( static_cast<const PCB_BARCODE*>( item ) );
516 break;
517
518 case PCB_TABLE_T:
520 {
521 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( item );
522
523 m_plotter->SetTextMode( PLOT_TEXT_MODE::STROKE );
524
525 for( const PCB_TABLECELL* cell : table->GetCells() )
526 PlotText( cell, cell->GetLayer(), cell->IsKnockout(), cell->GetFontMetrics() );
527
529
530 if( item->Type() == PCB_DRILL_CHART_T )
531 PlotChartSymbols( static_cast<const PCB_DRILL_CHART*>( item ) );
532
533 m_plotter->SetTextMode( GetTextMode() );
534 break;
535 }
536
538 case PCB_DIM_CENTER_T:
539 case PCB_DIM_RADIAL_T:
541 case PCB_DIM_LEADER_T:
542 m_plotter->SetTextMode( PLOT_TEXT_MODE::STROKE );
543
544 PlotDimension( static_cast<const PCB_DIMENSION_BASE*>( item ) );
545
546 m_plotter->SetTextMode( GetTextMode() );
547 break;
548
549 case PCB_TARGET_T:
550 PlotPcbTarget( static_cast<const PCB_TARGET*>( item ) );
551 break;
552
553 default:
554 break;
555 }
556}
557
558
560{
561 if( !m_layerMask[aDim->GetLayer()] )
562 return;
563
564 COLOR4D color = ColorSettings()->GetColor( aDim->GetLayer() );
565
566 // Set plot color (change WHITE to LIGHTGRAY because
567 // the white items are not seen on a white paper or screen
568 m_plotter->SetColor( color != WHITE ? color : LIGHTGRAY);
569
570 PlotText( aDim, aDim->GetLayer(), false, aDim->GetFontMetrics() );
571
572 PCB_SHAPE temp_item;
573
575 temp_item.SetLayer( aDim->GetLayer() );
576
577 for( const std::shared_ptr<SHAPE>& shape : aDim->GetShapes() )
578 {
579 switch( shape->Type() )
580 {
581 case SH_SEGMENT:
582 {
583 const SEG& seg = static_cast<const SHAPE_SEGMENT*>( shape.get() )->GetSeg();
584
585 temp_item.SetShape( SHAPE_T::SEGMENT );
586 temp_item.SetStart( seg.A );
587 temp_item.SetEnd( seg.B );
588
589 PlotShape( &temp_item );
590 break;
591 }
592
593 case SH_CIRCLE:
594 {
595 VECTOR2I start( shape->Centre() );
596 int radius = static_cast<const SHAPE_CIRCLE*>( shape.get() )->GetRadius();
597
598 temp_item.SetShape( SHAPE_T::CIRCLE );
599 temp_item.SetFilled( false );
600 temp_item.SetStart( start );
601 temp_item.SetEnd( VECTOR2I( start.x + radius, start.y ) );
602
603 PlotShape( &temp_item );
604 break;
605 }
606
607 default:
608 break;
609 }
610 }
611}
612
613
615{
616 int dx1, dx2, dy1, dy2, radius;
617
618 if( !m_layerMask[aMire->GetLayer()] )
619 return;
620
621 m_plotter->SetColor( getColor( aMire->GetLayer() ) );
622
623 PCB_SHAPE temp_item;
624
625 temp_item.SetShape( SHAPE_T::CIRCLE );
626 temp_item.SetFilled( false );
627 temp_item.SetStroke( STROKE_PARAMS( aMire->GetWidth(), LINE_STYLE::SOLID ) );
628 temp_item.SetLayer( aMire->GetLayer() );
629 temp_item.SetStart( aMire->GetPosition() );
630 radius = aMire->GetSize() / 3;
631
632 if( aMire->GetShape() ) // temp_item X
633 radius = aMire->GetSize() / 2;
634
635 // Draw the circle
636 temp_item.SetEnd( VECTOR2I( temp_item.GetStart().x + radius, temp_item.GetStart().y ) );
637
638 PlotShape( &temp_item );
639
640 temp_item.SetShape( SHAPE_T::SEGMENT );
641
642 radius = aMire->GetSize() / 2;
643 dx1 = radius;
644 dy1 = 0;
645 dx2 = 0;
646 dy2 = radius;
647
648 if( aMire->GetShape() ) // Shape X
649 {
650 dx1 = dy1 = radius;
651 dx2 = dx1;
652 dy2 = -dy1;
653 }
654
655 VECTOR2I mirePos( aMire->GetPosition() );
656
657 // Draw the X or + temp_item:
658 temp_item.SetStart( VECTOR2I( mirePos.x - dx1, mirePos.y - dy1 ) );
659 temp_item.SetEnd( VECTOR2I( mirePos.x + dx1, mirePos.y + dy1 ) );
660 PlotShape( &temp_item );
661
662 temp_item.SetStart( VECTOR2I( mirePos.x - dx2, mirePos.y - dy2 ) );
663 temp_item.SetEnd( VECTOR2I( mirePos.x + dx2, mirePos.y + dy2 ) );
664 PlotShape( &temp_item );
665}
666
667
669{
670 const wxString variantName = m_board ? m_board->GetCurrentVariant() : wxString();
671 const bool dnp = aFootprint->GetDNPForVariant( variantName );
672
673 for( const BOARD_ITEM* item : aFootprint->GraphicalItems() )
674 {
675 PCB_LAYER_ID itemLayer = item->GetLayer();
676
677 if( aFootprint->GetPrivateLayers().test( itemLayer ) )
678 continue;
679
680 if( dnp && hideDNPItems( itemLayer ) )
681 continue;
682
683 if( !( m_layerMask & item->GetLayerSet() ).any() )
684 continue;
685
686 switch( item->Type() )
687 {
688 case PCB_SHAPE_T:
689 PlotShape( static_cast<const PCB_SHAPE*>( item ) );
690 break;
691
692 case PCB_TEXTBOX_T:
693 {
694 const PCB_TEXTBOX* textbox = static_cast<const PCB_TEXTBOX*>( item );
695
696 m_plotter->SetTextMode( PLOT_TEXT_MODE::STROKE );
697
698 PlotText( textbox, textbox->GetLayer(), textbox->IsKnockout(),
699 textbox->GetFontMetrics() );
700
701 if( textbox->IsBorderEnabled() )
702 {
703 // PlotShape works only for textbox rotated by 0 or 180 degrees.
704 // This is not always the case so use the polygonal shape
706 PlotShape( &dummy );
707 }
708
709 m_plotter->SetTextMode( GetTextMode() );
710 break;
711 }
712
713 case PCB_BARCODE_T:
714 PlotBarCode( static_cast<const PCB_BARCODE*>( item ) );
715 break;
716
717 case PCB_TABLE_T:
719 {
720 const PCB_TABLE* table = static_cast<const PCB_TABLE*>( item );
721
722 m_plotter->SetTextMode( PLOT_TEXT_MODE::STROKE );
723
724 for( const PCB_TABLECELL* cell : table->GetCells() )
725 PlotText( cell, cell->GetLayer(), cell->IsKnockout(), cell->GetFontMetrics() );
726
728
729 m_plotter->SetTextMode( GetTextMode() );
730 break;
731 }
732
734 case PCB_DIM_CENTER_T:
735 case PCB_DIM_RADIAL_T:
737 case PCB_DIM_LEADER_T:
738 PlotDimension( static_cast<const PCB_DIMENSION_BASE*>( item ) );
739 break;
740
741 case PCB_TEXT_T:
742 // Plotted in PlotFootprintTextItems()
743 break;
744
746 // Not plotted at all
747 break;
748
749 default:
750 UNIMPLEMENTED_FOR( item->GetClass() );
751 }
752 }
753}
754
755
756#define getMetadata() ( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER ? (void*) &gbr_metadata \
757 : m_plotter->GetPlotterType() == PLOT_FORMAT::DXF ? (void*) this \
758 : (void*) nullptr )
759
760
761void BRDITEMS_PLOTTER::PlotText( const EDA_TEXT* aText, PCB_LAYER_ID aLayer, bool aIsKnockout,
762 const KIFONT::METRICS& aFontMetrics, bool aStrikeout )
763{
764 int maxError = m_board->GetDesignSettings().m_MaxError;
765 KIFONT::FONT* font = aText->GetDrawFont( m_plotter->RenderSettings() );
766 wxString shownText( aText->GetShownText( FOR_CANVAS ) );
767
768 const PCB_TEXTBOX* knockoutBox = aIsKnockout ? dynamic_cast<const PCB_TEXTBOX*>( aText ) : nullptr;
769
770 if( shownText.IsEmpty() && !knockoutBox )
771 return;
772
773 if( !m_layerMask[aLayer] )
774 return;
775
776 GBR_METADATA gbr_metadata;
777
778 if( IsCopperLayer( aLayer ) )
780
781 COLOR4D color = getColor( aLayer );
782 m_plotter->SetColor( color );
783
784 const VECTOR2I& pos = aText->GetTextPos();
785
786 TEXT_ATTRIBUTES attrs = aText->GetAttributes();
787 attrs.m_Size = aText->GetTextSize();
789 attrs.m_Angle = aText->GetDrawRotation();
790 attrs.m_Multiline = false;
791
792 m_plotter->SetCurrentLineWidth( attrs.m_StrokeWidth );
793
794 auto strikeoutText =
795 [&]( const PCB_TEXT* text )
796 {
797 SHAPE_POLY_SET textPoly;
798
799 text->TransformTextToPolySet( textPoly, 0, ARC_LOW_DEF, ERROR_INSIDE );
800 textPoly.Rotate( -text->GetDrawRotation(), text->GetDrawPos() );
801
802 BOX2I rect = textPoly.BBox();
803 VECTOR2I start( rect.GetLeft() - attrs.m_StrokeWidth,
804 ( rect.GetTop() + rect.GetBottom() ) / 2 );
805 VECTOR2I end( rect.GetRight() + attrs.m_StrokeWidth,
806 ( rect.GetTop() + rect.GetBottom() ) / 2 );
807
808 RotatePoint( start, text->GetDrawPos(), text->GetDrawRotation() );
809 RotatePoint( end, text->GetDrawPos(), text->GetDrawRotation() );
810
811 m_plotter->ThickSegment( start, end, attrs.m_StrokeWidth, getMetadata() );
812 };
813
814 if( aIsKnockout )
815 {
816 SHAPE_POLY_SET finalPoly;
817
818 if( knockoutBox )
819 knockoutBox->TransformTextToPolySet( finalPoly, 0, maxError, ERROR_INSIDE );
820 else if( const PCB_TEXT* text = dynamic_cast<const PCB_TEXT*>( aText ) )
821 text->TransformTextToPolySet( finalPoly, 0, maxError, ERROR_INSIDE );
822
823 finalPoly.Fracture();
824
825 for( int ii = 0; ii < finalPoly.OutlineCount(); ++ii )
826 m_plotter->PlotPoly( finalPoly.Outline( ii ), FILL_T::FILLED_SHAPE, 0, getMetadata() );
827 }
828 else
829 {
830 if( font->IsOutline() && !m_board->GetEmbeddedFiles()->GetAreFontsEmbedded() )
831 {
833
834 CALLBACK_GAL callback_gal( empty_opts,
835 // Stroke callback
836 [&]( const VECTOR2I& aPt1, const VECTOR2I& aPt2 )
837 {
838 m_plotter->ThickSegment( aPt1, aPt2, attrs.m_StrokeWidth, getMetadata() );
839 },
840 // Polygon callback
841 [&]( const SHAPE_LINE_CHAIN& aPoly )
842 {
843 m_plotter->PlotPoly( aPoly, FILL_T::FILLED_SHAPE, 0, getMetadata() );
844 } );
845
846 callback_gal.DrawGlyphs( *aText->GetRenderCache( font, shownText ) );
847 }
848 else if( aText->IsMultilineAllowed() )
849 {
850 std::vector<VECTOR2I> positions;
851 wxArrayString strings_list;
852 wxStringSplit( shownText, strings_list, '\n' );
853 positions.reserve( strings_list.Count() );
854
855 aText->GetLinePositions( m_plotter->RenderSettings(), positions, (int) strings_list.Count() );
856
857 for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
858 {
859 wxString& txt = strings_list.Item( ii );
860 m_plotter->PlotText( positions[ii], color, txt, attrs, font, aFontMetrics, getMetadata() );
861 }
862
863 if( aStrikeout && strings_list.Count() == 1 )
864 strikeoutText( static_cast<const PCB_TEXT*>( aText ) );
865 }
866 else
867 {
868 m_plotter->PlotText( pos, color, shownText, attrs, font, aFontMetrics, getMetadata() );
869
870 if( aStrikeout )
871 strikeoutText( static_cast<const PCB_TEXT*>( aText ) );
872 }
873 }
874}
875
876
877void BRDITEMS_PLOTTER::PlotZone( const ZONE* aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET& aPolysList )
878{
879 if( aPolysList.IsEmpty() )
880 return;
881
882 GBR_METADATA gbr_metadata;
883
884 if( aZone->IsOnCopperLayer() )
885 {
886 gbr_metadata.SetNetName( aZone->GetNetname() );
887 gbr_metadata.SetCopper( true );
888
889 // Zones with no net name can exist.
890 // they are not used to connect items, so the aperture attribute cannot
891 // be set as conductor
892 if( aZone->GetNetname().IsEmpty() )
893 {
895 }
896 else
897 {
900 }
901 }
902
903 m_plotter->SetColor( getColor( aLayer ) );
904
905 m_plotter->StartBlock( nullptr ); // Clean current object attributes
906
907 /*
908 * In non filled mode the outline is plotted, but not the filling items
909 */
910
911 for( int idx = 0; idx < aPolysList.OutlineCount(); ++idx )
912 {
913 const SHAPE_LINE_CHAIN& outline = aPolysList.Outline( idx );
914
915 // Plot the current filled area (as region for Gerber plotter to manage attributes)
916 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
917 {
918 static_cast<GERBER_PLOTTER*>( m_plotter )->PlotGerberRegion( outline, &gbr_metadata );
919 }
920 else if( m_plotter->GetPlotterType() == PLOT_FORMAT::DXF )
921 {
922 if( GetDXFPlotMode() == FILLED )
923 m_plotter->PlotPoly( outline, FILL_T::FILLED_SHAPE, 0, getMetadata() );
924 }
925 else
926 {
927 m_plotter->PlotPoly( outline, FILL_T::FILLED_SHAPE, 0, getMetadata() );
928 }
929 }
930
931 m_plotter->EndBlock( nullptr ); // Clear object attributes
932}
933
934
936{
937 if( !( m_layerMask & aShape->GetLayerSet() ).any() )
938 return;
939
940 int thickness = aShape->GetWidth();
941 int margin = thickness; // unclamped thickness (can be negative)
942 LINE_STYLE lineStyle = aShape->GetStroke().GetLineStyle();
943 bool onCopperLayer = ( LSET::AllCuMask() & m_layerMask ).any();
944 bool onSolderMaskLayer = ( LSET( { F_Mask, B_Mask } ) & m_layerMask ).any();
945 bool isSolidFill = aShape->IsSolidFill();
946 bool isHatchedFill = aShape->IsHatchedFill();
947
948 if( onSolderMaskLayer
949 && aShape->HasSolderMask()
950 && IsExternalCopperLayer( aShape->GetLayer() ) )
951 {
952 margin += 2 * aShape->GetSolderMaskExpansion();
953 thickness = std::max( margin, 0 );
954
955 if( isHatchedFill )
956 {
957 isSolidFill = true;
958 isHatchedFill = false;
959 }
960 }
961
962 m_plotter->SetColor( getColor( aShape->GetLayer() ) );
963
964 const FOOTPRINT* parentFP = aShape->GetParentFootprint();
965 GBR_METADATA gbr_metadata;
966 const wxString variantName = m_board ? m_board->GetCurrentVariant() : wxString();
967 const bool parentDnp = parentFP ? parentFP->GetDNPForVariant( variantName ) : false;
968
969 if( parentFP )
970 {
971 gbr_metadata.SetCmpReference( parentFP->GetReference() );
973 }
974
975 if( parentFP && parentDnp && GetSketchDNPFPsOnFabLayers() )
976 {
977 if( aShape->GetLayer() == F_Fab || aShape->GetLayer() == B_Fab )
978 {
979 thickness = GetSketchPadLineWidth();
980 isSolidFill = false;
981 isHatchedFill = false;
982 }
983 }
984
985 if( aShape->GetLayer() == Edge_Cuts )
986 {
988 }
989 else if( onCopperLayer )
990 {
991 if( parentFP )
992 {
994 gbr_metadata.SetCopper( true );
995 }
996 else if( aShape->GetNetCode() > 0 )
997 {
998 gbr_metadata.SetCopper( true );
1001 gbr_metadata.SetNetName( aShape->GetNetname() );
1002 }
1003 else
1004 {
1005 // Graphic items (PCB_SHAPE, TEXT) having no net have the NonConductor attribute
1006 // Graphic items having a net have the Conductor attribute, but are not (yet?)
1007 // supported in Pcbnew
1009 }
1010 }
1011
1012 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
1013 {
1014 switch( aShape->GetShape() )
1015 {
1016 case SHAPE_T::SEGMENT:
1017 {
1018 VECTOR2I segStart = aShape->GetStart();
1019 VECTOR2I segEnd = aShape->GetEnd();
1020
1021 if( EDA_SHAPE::ShortenSegmentForEndings( segStart, segEnd, aShape->GetStartEnding(), aShape->GetEndEnding(),
1022 thickness ) )
1023 {
1024 m_plotter->ThickSegment( segStart, segEnd, thickness, getMetadata() );
1025 }
1026
1027 break;
1028 }
1029
1030 case SHAPE_T::CIRCLE:
1031 if( isSolidFill )
1032 {
1033 int diameter = aShape->GetRadius() * 2 + thickness;
1034
1035 if( margin < 0 )
1036 {
1037 diameter += margin;
1038 diameter = std::max( diameter, 0 );
1039 }
1040
1041 m_plotter->FilledCircle( aShape->GetStart(), diameter, getMetadata() );
1042 }
1043 else
1044 {
1045 m_plotter->ThickCircle( aShape->GetStart(), aShape->GetRadius() * 2, thickness, getMetadata() );
1046 }
1047
1048 break;
1049
1050 case SHAPE_T::ARC:
1051 {
1052 // when startAngle == endAngle ThickArc() doesn't know whether it's 0 deg and 360 deg
1053 // but it is a circle
1054 if( std::abs( aShape->GetArcAngle().AsDegrees() ) == 360.0 )
1055 {
1056 m_plotter->ThickCircle( aShape->GetCenter(), aShape->GetRadius() * 2, thickness, getMetadata() );
1057 }
1058 else if( aShape->GetStartEnding().GetStyle() != LINE_ENDING_STYLE::NONE
1060 {
1061 EDA_ANGLE startAngle;
1062 EDA_ANGLE endAngle;
1063 aShape->CalcArcAngles( startAngle, endAngle );
1064
1065 EDA_ANGLE arcAngle = endAngle - startAngle;
1066 if( aShape->ShortenArcForEndings( startAngle, arcAngle, aShape->GetRadius(), thickness ) )
1067 {
1068 m_plotter->ThickArc( VECTOR2D( aShape->GetCenter() ), startAngle, arcAngle, aShape->GetRadius(),
1069 thickness, getMetadata() );
1070 }
1071 }
1072 else
1073 {
1074 m_plotter->ThickArc( *aShape, getMetadata(), thickness );
1075 }
1076
1077 break;
1078 }
1079
1080 case SHAPE_T::BEZIER:
1081 {
1082 std::optional<BEZIER<double>> curve = aShape->ShortenedBezierCurve( thickness );
1083
1084 if( curve && m_plotter->GetPlotterType() == PLOT_FORMAT::SVG )
1085 {
1086 m_plotter->BezierCurve( VECTOR2I( curve->Start ), VECTOR2I( curve->C1 ), VECTOR2I( curve->C2 ),
1087 VECTOR2I( curve->End ), aShape->GetMaxError(), thickness );
1088 }
1089 else
1090 {
1091 std::vector<VECTOR2D> pts = aShape->ShortenedBezierPolyline( thickness );
1092
1093 for( size_t i = 0; i + 1 < pts.size(); i++ )
1094 m_plotter->ThickSegment( VECTOR2I( pts[i] ), VECTOR2I( pts[i + 1] ), thickness, getMetadata() );
1095 }
1096
1097 break;
1098 }
1099
1100 case SHAPE_T::POLY:
1101 if( aShape->IsPolyShapeValid() )
1102 {
1103 bool hasEndings = aShape->GetStartEnding().GetStyle() != LINE_ENDING_STYLE::NONE
1105
1106 auto plotStrokeOutline =
1107 [&]( const SHAPE_LINE_CHAIN& aOutline, int aOutlineIdx )
1108 {
1109 if( aOutline.PointCount() < 2 )
1110 return;
1111
1112 if( hasEndings )
1113 {
1114 std::vector<VECTOR2I> pts;
1115
1116 if( !aShape->GetShortenedBodyPolyPoints( aOutline, aOutlineIdx, pts, thickness ) )
1117 return;
1118
1119 SHAPE_LINE_CHAIN shortened;
1120
1121 for( const VECTOR2I& pt : pts )
1122 shortened.Append( pt );
1123
1124 shortened.SetClosed( aOutline.IsClosed() );
1125 m_plotter->PlotPoly( shortened, FILL_T::NO_FILL, thickness, getMetadata() );
1126 return;
1127 }
1128
1129 m_plotter->PlotPoly( aOutline, FILL_T::NO_FILL, thickness, getMetadata() );
1130 };
1131
1132 if( !hasEndings && m_plotter->GetPlotterType() == PLOT_FORMAT::DXF && GetDXFPlotMode() == SKETCH )
1133 {
1134 m_plotter->ThickPoly( aShape->GetPolyShape(), thickness, getMetadata() );
1135 }
1136 else
1137 {
1138 m_plotter->SetCurrentLineWidth( thickness, &gbr_metadata );
1139
1140 const SHAPE_POLY_SET& origPoly = aShape->GetPolyShape();
1141
1142 // Stroke the unfractured outline so degenerate near-zero-width
1143 // spikes (which Fracture() collapses but the editor still draws as
1144 // thick lines) are preserved in the plot output (issue #24143).
1145 if( thickness > 0 )
1146 {
1147 for( int jj = 0; jj < origPoly.OutlineCount(); ++jj )
1148 plotStrokeOutline( origPoly.COutline( jj ), jj );
1149 }
1150
1151 if( !isSolidFill )
1152 break;
1153
1154 // Fracture before plotting the fill to avoid invalid gerber regions
1155 // from self-intersecting or overlapping outlines.
1156 SHAPE_POLY_SET tmpPoly = origPoly.CloneDropTriangulation();
1157 tmpPoly.Fracture();
1158
1159 if( margin < 0 )
1160 tmpPoly.Inflate( margin / 2, CORNER_STRATEGY::ROUND_ALL_CORNERS, aShape->GetMaxError() );
1161
1162 for( int jj = 0; jj < tmpPoly.OutlineCount(); ++jj )
1163 {
1164 SHAPE_LINE_CHAIN& poly = tmpPoly.Outline( jj );
1165 poly.SetClosed( true );
1166
1167 // Width 0; the stroke was already plotted from the unfractured outline.
1168 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1169 {
1170 GERBER_PLOTTER* gbr_plotter = static_cast<GERBER_PLOTTER*>( m_plotter );
1171 gbr_plotter->PlotPolyAsRegion( poly, FILL_T::FILLED_SHAPE, 0, &gbr_metadata );
1172 }
1173 else
1174 {
1175 m_plotter->PlotPoly( poly, FILL_T::FILLED_SHAPE, 0, getMetadata() );
1176 }
1177 }
1178 }
1179 }
1180
1181 break;
1182
1183 case SHAPE_T::RECTANGLE:
1184 {
1185 int radius = aShape->GetCornerRadius();
1186
1187 if( radius == 0 && m_plotter->GetPlotterType() == PLOT_FORMAT::DXF && GetDXFPlotMode() == SKETCH )
1188 {
1189 std::vector<VECTOR2I> pts = aShape->GetRectCorners();
1190 m_plotter->ThickRect( pts[0], pts[2], thickness, getMetadata() );
1191 }
1192 else
1193 {
1194 BOX2I box( aShape->GetStart(), VECTOR2I( aShape->GetEnd().x - aShape->GetStart().x,
1195 aShape->GetEnd().y - aShape->GetStart().y ) );
1196 box.Normalize();
1197
1198 if( margin < 0 )
1199 {
1200 box.Inflate( margin );
1201 radius += margin;
1202 }
1203
1204 SHAPE_RECT rect( box );
1205 rect.SetRadius( radius );
1206
1207 SHAPE_LINE_CHAIN outline = rect.Outline();
1208 SHAPE_POLY_SET poly( outline );
1209
1210 FILL_T fill_mode = isSolidFill ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL;
1211
1212 if( poly.OutlineCount() > 0 )
1213 {
1214 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1215 {
1216 GERBER_PLOTTER* gbr_plotter = static_cast<GERBER_PLOTTER*>( m_plotter );
1217 gbr_plotter->PlotPolyAsRegion( poly.COutline( 0 ), fill_mode, thickness, &gbr_metadata );
1218 }
1219 else
1220 {
1221 // TODO: PlotPoly needs to handle arcs...
1222 m_plotter->PlotPoly( poly.COutline( 0 ), fill_mode, thickness, getMetadata() );
1223 }
1224 }
1225 }
1226
1227 break;
1228 }
1229
1230 case SHAPE_T::ELLIPSE:
1232 {
1233 const bool isClosed = ( aShape->GetShape() == SHAPE_T::ELLIPSE );
1234
1235 SHAPE_ELLIPSE e = isClosed ? SHAPE_ELLIPSE( aShape->GetEllipseCenter(), aShape->GetEllipseMajorRadius(),
1236 aShape->GetEllipseMinorRadius(), aShape->GetEllipseRotation() )
1238 aShape->GetEllipseMinorRadius(), aShape->GetEllipseRotation(),
1239 aShape->GetEllipseStartAngle(), aShape->GetEllipseEndAngle() );
1240
1242
1243 if( isClosed )
1244 chain.SetClosed( true );
1245
1246 FILL_T fill = ( isClosed && isSolidFill ) ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL;
1247
1248 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER && isClosed )
1249 {
1250 GERBER_PLOTTER* gbr_plotter = static_cast<GERBER_PLOTTER*>( m_plotter );
1251 gbr_plotter->PlotPolyAsRegion( chain, fill, thickness, &gbr_metadata );
1252 }
1253 else
1254 {
1255 m_plotter->PlotPoly( chain, fill, thickness, getMetadata() );
1256 }
1257
1258 break;
1259 }
1260
1261 default:
1263 }
1264 }
1265 else
1266 {
1267 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapesForStroking( thickness );
1268
1269 for( SHAPE* shape : shapes )
1270 {
1271 STROKE_PARAMS::Stroke( shape, lineStyle, aShape->GetWidth(),
1272 m_plotter->RenderSettings(),
1273 [&]( const VECTOR2I& a, const VECTOR2I& b )
1274 {
1275 m_plotter->ThickSegment( a, b, thickness, getMetadata() );
1276 } );
1277 }
1278
1279 for( SHAPE* shape : shapes )
1280 delete shape;
1281 }
1282
1283 // Plot line endings for open shapes.
1286 {
1287 EDA_ANGLE startTangent, endTangent;
1288 aShape->GetEndingTangents( startTangent, endTangent, thickness );
1289
1290 VECTOR2I startPt, endPt;
1291
1292 if( aShape->GetLineEndingEndpoints( startPt, endPt ) )
1293 {
1294 aShape->GetStartEnding().Plot( m_plotter, startPt, startTangent, thickness, getMetadata() );
1295 aShape->GetEndEnding().Plot( m_plotter, endPt, endTangent, thickness, getMetadata() );
1296 }
1297 }
1298
1299 if( isHatchedFill )
1300 {
1301 for( int ii = 0; ii < aShape->GetHatching().OutlineCount(); ++ii )
1302 {
1303 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1304 {
1305 GERBER_PLOTTER* gbr_plotter = static_cast<GERBER_PLOTTER*>( m_plotter );
1306 gbr_plotter->PlotPolyAsRegion( aShape->GetHatching().Outline( ii ), FILL_T::FILLED_SHAPE, 0,
1307 &gbr_metadata );
1308 }
1309 else
1310 {
1311 m_plotter->PlotPoly( aShape->GetHatching().Outline( ii ), FILL_T::FILLED_SHAPE, 0, getMetadata() );
1312 }
1313 }
1314 }
1315}
1316
1317
1319{
1320 if( !m_layerMask[aBarCode->GetLayer()] )
1321 return;
1322
1323 // To avoid duplicate code, build a PCB_SHAPE to plot the polygon shape
1324 PCB_SHAPE dummy( aBarCode->GetParent(), SHAPE_T::POLY );
1325 dummy.SetLayer( aBarCode->GetLayer() );
1326 dummy.SetFillMode( FILL_T::FILLED_SHAPE );
1327 dummy.SetWidth( 0 );
1328
1329 SHAPE_POLY_SET shape;
1330 aBarCode->TransformShapeToPolySet( shape, aBarCode->GetLayer(), 0, 0, ERROR_INSIDE );
1331 dummy.SetPolyShape( shape );
1332
1333 PlotShape( &dummy );
1334}
1335
1336
1338{
1339 if( !m_layerMask[aTable->GetLayer()] )
1340 return;
1341
1342 GBR_METADATA gbr_metadata;
1343
1344 if( const FOOTPRINT* parentFP = aTable->GetParentFootprint() )
1345 {
1346 gbr_metadata.SetCmpReference( parentFP->GetReference() );
1348 }
1349
1350 aTable->DrawBorders(
1351 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB, const STROKE_PARAMS& stroke )
1352 {
1353 int lineWidth = stroke.GetWidth();
1354 LINE_STYLE lineStyle = stroke.GetLineStyle();
1355
1356 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
1357 {
1358 m_plotter->ThickSegment( ptA, ptB, lineWidth, getMetadata() );
1359 }
1360 else
1361 {
1362 SHAPE_SEGMENT seg( ptA, ptB );
1363
1364 STROKE_PARAMS::Stroke( &seg, lineStyle, lineWidth, m_plotter->RenderSettings(),
1365 [&]( const VECTOR2I& a, const VECTOR2I& b )
1366 {
1367 m_plotter->ThickSegment( a, b, lineWidth, getMetadata() );
1368 } );
1369 }
1370 } );
1371}
1372
1373
1375 const VECTOR2I& aDrillSize, const VECTOR2I& aPadSize,
1376 const EDA_ANGLE& aOrientation, int aSmallDrill )
1377{
1378 VECTOR2I drillSize = aDrillSize;
1379
1380 // Small drill marks have no significance when applied to slots
1381 if( aSmallDrill && aDrillShape == PAD_DRILL_SHAPE::CIRCLE )
1382 drillSize.x = std::min( aSmallDrill, drillSize.x );
1383
1384 // Round holes only have x diameter, slots have both
1385 drillSize.x -= getFineWidthAdj();
1386 drillSize.x = std::clamp( drillSize.x, 1, aPadSize.x - 1 );
1387
1388 if( aDrillShape == PAD_DRILL_SHAPE::OBLONG )
1389 {
1390 drillSize.y -= getFineWidthAdj();
1391 drillSize.y = std::clamp( drillSize.y, 1, aPadSize.y - 1 );
1392
1393 m_plotter->FlashPadOval( aDrillPos, drillSize, aOrientation, nullptr );
1394 }
1395 else
1396 {
1397 m_plotter->FlashPadCircle( aDrillPos, drillSize.x, nullptr );
1398 }
1399}
1400
1401
1403{
1404 int smallDrill = 0;
1405
1407 smallDrill = pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_SmallDrillMarkSize );
1408
1409 /* Drill marks are drawn white-on-black to knock-out the underlying pad. This works only
1410 * for drivers supporting color change, obviously... it means that:
1411 - PS, SVG and PDF output is correct (i.e. you have a 'donut' pad)
1412 - In gerbers you can't see them. This is arguably the right thing to do since having
1413 drill marks and high speed drill stations is a sure recipe for broken tools and angry
1414 manufacturers. If you *really* want them you could start a layer with negative
1415 polarity to knock-out the film.
1416 - In DXF they go into the 'WHITE' layer. This could be useful.
1417 */
1418 if( m_plotter->GetPlotterType() != PLOT_FORMAT::DXF || GetDXFPlotMode() == FILLED )
1419 m_plotter->SetColor( WHITE );
1420
1421 for( PCB_TRACK* track : m_board->Tracks() )
1422 {
1423 if( track->Type() == PCB_VIA_T )
1424 {
1425 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
1426
1427 // Via are not always on all layers
1428 if( ( via->GetLayerSet() & m_layerMask ).none() )
1429 continue;
1430
1432 VECTOR2I( via->GetDrillValue(), 0 ),
1433 VECTOR2I( via->GetWidth( PADSTACK::TEMP_ALL_LAYERS ), 0 ),
1434 ANGLE_0, smallDrill );
1435 }
1436 }
1437
1438 for( FOOTPRINT* footprint : m_board->Footprints() )
1439 {
1440 for( PAD* pad : footprint->Pads() )
1441 {
1442 if( pad->GetDrillSize().x == 0 )
1443 continue;
1444
1445 // Skip marks on layers the pad isn't on for Gerber only (24416). Other
1446 // formats keep them as a drill map, e.g. Edge.Cuts (24867).
1447 if( m_plotter->GetPlotterType() == PLOT_FORMAT::GERBER && ( pad->GetLayerSet() & m_layerMask ).none() )
1448 continue;
1449
1450 if( m_plotter->GetPlotterType() != PLOT_FORMAT::DXF || GetDXFPlotMode() == FILLED )
1451 {
1452 // Drill mark is in black unless we can find something to knock it out of
1453 m_plotter->SetColor( BLACK );
1454
1455 for( PCB_LAYER_ID layer : m_layerMask )
1456 {
1457 if( !pad->IsOnLayer( layer ) )
1458 continue;
1459
1460 VECTOR2I padSize = pad->GetSize( layer );
1461
1462 if( padSize.x > pad->GetDrillSizeX() || padSize.y > pad->GetDrillSizeY() )
1463 {
1464 m_plotter->SetColor( WHITE );
1465 break;
1466 }
1467 }
1468 }
1469
1470 plotOneDrillMark( pad->GetDrillShape(), pad->GetPosition(), pad->GetDrillSize(),
1471 pad->GetSize( PADSTACK::TEMP_ALL_LAYERS ), pad->GetOrientation(), smallDrill );
1472 }
1473 }
1474
1475 if( m_plotter->GetPlotterType() != PLOT_FORMAT::DXF || GetDXFPlotMode() == FILLED )
1476 m_plotter->SetColor( BLACK );
1477}
1478
1479
1481{
1482 const std::vector<const PCB_DRILL_MAP*> maps = m_board->DrillMapsOnLayer( aLayer );
1483
1484 if( maps.empty() )
1485 return;
1486
1487 const DRILL_SYMBOL_PROFILE& profile = m_board->GetDesignSettings().GetDrillSymbolProfile();
1488
1489 // Resolved rather than read straight from the profile, so a map drawn without any chart
1490 // ever having been placed still shows marks
1491 const std::shared_ptr<const DRILL_SYMBOL_CACHE> cache = m_board->DrillSymbolCache();
1492
1493 // DXF reads its sketch/filled mode back out of this. Without it every stroked mark is
1494 // emitted filled no matter what the user asked for
1495 GBR_METADATA gbr_metadata;
1496
1497 m_plotter->SetColor( getColor( aLayer ) );
1498 m_plotter->SetCurrentLineWidth( profile.GetSymbolWidth() );
1499
1500 DRILL_QUERY query;
1501 query.m_MergePTHNPTH = true;
1502
1503 // Several maps can share a layer. The UI prevents it but a parsed, pasted or
1504 // API-created board need not
1505 for( const PCB_DRILL_MAP* map : maps )
1506 {
1507
1508 const std::shared_ptr<const SHAPE_POLY_SET> outlines = map->GetBoardOutlines();
1509
1510 for( int ii = 0; ii < outlines->OutlineCount(); ++ii )
1511 {
1512 m_plotter->PlotPoly( outlines->COutline( ii ), FILL_T::NO_FILL, profile.GetSymbolWidth(),
1513 getMetadata() );
1514
1515 for( int jj = 0; jj < outlines->HoleCount( ii ); ++jj )
1516 {
1517 m_plotter->PlotPoly( outlines->CHole( ii, jj ), FILL_T::NO_FILL, profile.GetSymbolWidth(),
1518 getMetadata() );
1519 }
1520 }
1521
1522 for( const DRILL_SPAN& span : EnumerateDrillSpans( *m_board ) )
1523 {
1524 // The map's own span filter, so a backdrill map does not print every other hole too
1525 if( !map->GetAllSpans() && !( span == map->GetSpan() ) )
1526 continue;
1527
1528 query.m_Span = span;
1529
1530 for( const DRILL_OPERATION& op : EnumerateDrillOperations( *m_board, query ) )
1531 {
1532 // The map is a set of marks on the holes, displaced as a whole. The holes
1533 // themselves never move
1534 const VECTOR2I pos = op.m_Position + map->GetOffset();
1535
1536 const auto it = cache->m_ByGroup.find( profile.GroupKeyString( op ) );
1537
1538 if( it == cache->m_ByGroup.end() )
1539 continue;
1540
1541 const DRILL_SYMBOL_ASSIGNMENT& assignment = it->second;
1542
1543 if( assignment.m_MarkMode == DRILL_MARK_MODE::SHAPE )
1544 {
1545 m_plotter->Marker( pos, map->GetSymbolSize(),
1547 }
1548 else
1549 {
1550 const wxString text =
1552 ? assignment.m_Letter
1553 : wxString::Format( wxT( "%.2f" ),
1554 pcbIUScale.IUTomm( op.m_Diameter ) );
1555
1556 TEXT_ATTRIBUTES attrs;
1557 attrs.m_Size = VECTOR2I( map->GetSymbolSize(), map->GetSymbolSize() );
1558 attrs.m_StrokeWidth = profile.GetSymbolWidth();
1561
1562 m_plotter->PlotText( pos, getColor( aLayer ), text, attrs, nullptr,
1564 }
1565
1566 if( map->GetGuideCross() )
1567 {
1568 const int reach = map->GetSymbolSize();
1569
1570 m_plotter->ThickSegment( pos - VECTOR2I( reach, 0 ),
1571 pos + VECTOR2I( reach, 0 ),
1572 profile.GetSymbolWidth(), getMetadata() );
1573 m_plotter->ThickSegment( pos - VECTOR2I( 0, reach ),
1574 pos + VECTOR2I( 0, reach ),
1575 profile.GetSymbolWidth(), getMetadata() );
1576 }
1577
1578 // A slot's true extent is the cost driver, so it is drawn as well as marked
1579 if( map->GetOutlineSlots() && op.m_IsSlot )
1580 {
1581 m_plotter->ThickOval( pos, op.m_SizeXY, op.m_Orientation,
1582 profile.GetSymbolWidth(), getMetadata() );
1583 }
1584 }
1585 }
1586 }
1587
1588 m_plotter->SetCurrentLineWidth( PLOTTER::USE_DEFAULT_LINE_WIDTH );
1589}
1590
1591
1593{
1594
1595 if( aChart->GetSymbolColumn() < 0 || aChart->RowShapes().empty() )
1596 return;
1597
1598 const DRILL_SYMBOL_PROFILE& profile = m_board->GetDesignSettings().GetDrillSymbolProfile();
1599
1600 m_plotter->SetColor( getColor( aChart->GetLayer() ) );
1601 m_plotter->SetCurrentLineWidth( profile.GetSymbolWidth() );
1602
1603 for( const auto& [row, shapeIndex] : aChart->RowShapes() )
1604 {
1605 const PCB_TABLECELL* cell = aChart->GetCell( row, aChart->GetSymbolColumn() );
1606
1607 if( !cell )
1608 continue;
1609
1610 const BOX2I box = cell->GetBoundingBox();
1611
1612 // Same fit as the painter, so the plotted chart matches what was on screen
1613 const int size = std::min<int>( profile.GetSymbolSize(),
1614 std::min( box.GetWidth(), box.GetHeight() ) * 2 / 3 );
1615
1616 if( size > 0 )
1617 m_plotter->Marker( box.GetCenter(), size, DRILL_MARKERS::CuratedShape( shapeIndex ) );
1618 }
1619
1620 m_plotter->SetCurrentLineWidth( PLOTTER::USE_DEFAULT_LINE_WIDTH );
1621}
@ 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.
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:414
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:546
const KIFONT::METRICS & GetFontMetrics() const
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:266
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 PlotDrillMarks()
Draw a drill mark for pads and vias.
void PlotZone(const ZONE *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
void PlotPadNumber(const PAD *aPad, const COLOR4D &aColor)
void PlotBoardGraphicItem(const BOARD_ITEM *item)
Plot items like text and graphics but not tracks and footprints.
void PlotChartSymbols(const PCB_DRILL_CHART *aChart)
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)
Plot a pad.
void PlotDimension(const PCB_DIMENSION_BASE *aDim)
void PlotText(const EDA_TEXT *aText, PCB_LAYER_ID aLayer, bool aIsKnockout, const KIFONT::METRICS &aFontMetrics, bool aStrikeout=false)
BOARD * m_board
Definition pcbplot.h:162
void PlotShape(const PCB_SHAPE *aShape)
PLOTTER * m_plotter
Definition pcbplot.h:161
bool crossoutDNPItems(PCB_LAYER_ID aLayer)
Definition pcbplot.h:147
void PlotBarCode(const PCB_BARCODE *aBarCode)
COLOR4D getColor(int aLayer) const
White color is special because it cannot be seen on a white paper in B&W mode.
void PlotPcbTarget(const PCB_TARGET *aMire)
void PlotTableBorders(const PCB_TABLE *aTable)
void PlotFootprintTextItems(const FOOTPRINT *aFootprint)
int getFineWidthAdj() const
Definition pcbplot.h:75
void PlotDrillSymbols(PCB_LAYER_ID aLayer)
Draw each hole's chart symbol on aLayer, from the board's shared symbol profile.
void plotOneDrillMark(PAD_DRILL_SHAPE aDrillShape, const VECTOR2I &aDrillPos, const VECTOR2I &aDrillSize, const VECTOR2I &aPadSize, const EDA_ANGLE &aOrientation, int aSmallDrill)
Helper function to plot a single drill mark.
bool hideDNPItems(PCB_LAYER_ID aLayer)
Definition pcbplot.h:142
void PlotFootprintGraphicItems(const FOOTPRINT *aFootprint)
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:395
const VECTOR2I & GetEllipseCenter() const
Definition eda_shape.h:377
const SHAPE_POLY_SET & GetHatching() const
EDA_ANGLE GetEllipseEndAngle() const
Definition eda_shape.h:423
int GetEllipseMajorRadius() const
Definition eda_shape.h:386
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:404
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.
virtual void SetFilled(bool aFlag)
Definition eda_shape.h:142
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
EDA_ANGLE GetEllipseStartAngle() const
Definition eda_shape.h:414
const LINE_ENDING & GetStartEnding() const
Definition eda_shape.h:177
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:180
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:947
LSET GetPrivateLayers() const
Definition footprint.h:345
PCB_FIELD & Reference()
Definition footprint.h:948
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:909
DRAWINGS & GraphicalItems()
Definition footprint.h:408
@ 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:48
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.
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:2559
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:1182
const BOX2I GetBoundingBox() const override
The bounding box is cached, so this will be efficient most of the time.
Definition pad.cpp:1635
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:3046
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:205
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
Definition pad.cpp:298
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.cpp:1757
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:1240
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:834
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition pad.cpp:1868
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:78
int GetWidth() const override
bool HasSolderMask() const
Definition pcb_shape.h:344
int GetSolderMaskExpansion() const
void SetShape(SHAPE_T aShape) override
Definition pcb_shape.h:209
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:68
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
static const int USE_DEFAULT_LINE_WIDTH
Definition plotter.h:140
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:615
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:90
@ 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:703
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:714
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.
#define getMetadata()
@ SKETCH
Definition plotter.h:81
@ 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