KiCad PCB EDA Suite
Loading...
Searching...
No Matches
plot_board_layers.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 1992-2024 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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <wx/log.h>
25#include <eda_item.h>
26#include <layer_ids.h>
27#include <lset.h>
30#include <pcb_base_frame.h>
31#include <math/util.h> // for KiROUND
32#include <board.h>
33#include <footprint.h>
34#include <pcb_track.h>
35#include <pad.h>
36#include <zone.h>
37#include <pcb_shape.h>
38#include <pcb_target.h>
39#include <pcb_dimension.h>
40#include <pcbplot.h>
45#include <pcb_painter.h>
46#include <gbr_metadata.h>
47#include <advanced_config.h>
48
49/*
50 * Plot a solder mask layer. Solder mask layers have a minimum thickness value and cannot be
51 * drawn like standard layers, unless the minimum thickness is 0.
52 */
53static void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
54 const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness );
55
56
57void PlotBoardLayers( BOARD* aBoard, PLOTTER* aPlotter, const LSEQ& aLayers,
58 const PCB_PLOT_PARAMS& aPlotOptions )
59{
60 wxCHECK( aBoard && aPlotter && aLayers.size(), /* void */ );
61
62 // if a drill mark must be plotted, the copper layer needs to be plotted
63 // after other layers because the drill mark must be plotted as a filled
64 // white shape *after* all other shapes are plotted
65 bool plot_mark = aPlotOptions.GetDrillMarksType() != DRILL_MARKS::NO_DRILL_SHAPE;
66
67 for( PCB_LAYER_ID layer : aLayers )
68 {
69 // copper layers with drill marks will be plotted after all other layers
70 if( layer <= B_Cu && plot_mark )
71 continue;
72
73 PlotOneBoardLayer( aBoard, aPlotter, layer, aPlotOptions );
74 }
75
76 if( !plot_mark )
77 return;
78
79 for( PCB_LAYER_ID layer : aLayers )
80 {
81 if( layer > B_Cu ) // already plotted
82 continue;
83
84 PlotOneBoardLayer( aBoard, aPlotter, layer, aPlotOptions );
85 }
86}
87
88
89void PlotInteractiveLayer( BOARD* aBoard, PLOTTER* aPlotter, const PCB_PLOT_PARAMS& aPlotOpt )
90{
91 for( const FOOTPRINT* fp : aBoard->Footprints() )
92 {
93 if( fp->GetLayer() == F_Cu && !aPlotOpt.m_PDFFrontFPPropertyPopups )
94 continue;
95
96 if( fp->GetLayer() == B_Cu && !aPlotOpt.m_PDFBackFPPropertyPopups )
97 continue;
98
99 std::vector<wxString> properties;
100
101 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
102 _( "Reference designator" ),
103 fp->Reference().GetShownText( false ) ) );
104
105 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
106 _( "Value" ),
107 fp->Value().GetShownText( false ) ) );
108
109 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
110 _( "Footprint" ),
111 fp->GetFPID().GetUniStringLibItemName() ) );
112
113 for( int i = 0; i < fp->GetFieldCount(); i++ )
114 {
115 PCB_FIELD* field = fp->GetFields().at( i );
116
117 if( field->IsReference() || field->IsValue() || field->IsFootprint() )
118 continue;
119
120 if( field->GetText().IsEmpty() )
121 continue;
122
123 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
124 field->GetName(),
125 field->GetText() ) );
126 }
127
128 // These 2 properties are not very useful in a plot file (like a PDF)
129#if 0
130 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), _( "Library Description" ),
131 fp->GetLibDescription() ) );
132
133 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
134 _( "Keywords" ),
135 fp->GetKeywords() ) );
136#endif
137 // Draw items are plotted with a position offset. So we need to move
138 // our boxes (which are not plotted) by the same offset.
139 VECTOR2I offset = -aPlotter->GetPlotOffsetUserUnits();
140
141 // Use a footprint bbox without texts to create the hyperlink area
142 BOX2I bbox = fp->GetBoundingBox( false, false );
143 bbox.Move( offset );
144 aPlotter->HyperlinkMenu( bbox, properties );
145
146 // Use a footprint bbox with visible texts only to create the bookmark area
147 // which is the area to zoom on ft selection
148 // However the bbox need to be inflated for a better look.
149 bbox = fp->GetBoundingBox( true, false );
150 bbox.Move( offset );
151 bbox.Inflate( bbox.GetWidth() /2, bbox.GetHeight() /2 );
152 aPlotter->Bookmark( bbox, fp->GetReference(), _( "Footprints" ) );
153 }
154}
155
156
157void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
158 const PCB_PLOT_PARAMS& aPlotOpt )
159{
160 auto plotLayer =
161 [&]( LSET layerMask, PCB_PLOT_PARAMS& plotOpts )
162 {
163 // PlotLayerOutlines() is designed only for DXF plotters.
164 if( plotOpts.GetFormat() == PLOT_FORMAT::DXF && plotOpts.GetDXFPlotPolygonMode() )
165 PlotLayerOutlines( aBoard, aPlotter, layerMask, plotOpts );
166 else
167 PlotStandardLayer( aBoard, aPlotter, layerMask, plotOpts );
168 };
169
170 PCB_PLOT_PARAMS plotOpt = aPlotOpt;
171 int soldermask_min_thickness = aBoard->GetDesignSettings().m_SolderMaskMinWidth;
172
173 // Set a default color and the text mode for this layer
174 aPlotter->SetColor( BLACK );
175 aPlotter->SetTextMode( aPlotOpt.GetTextMode() );
176
177 // Specify that the contents of the "Edges Pcb" layer are to be plotted in addition to the
178 // contents of the currently specified layer.
179 LSET layer_mask( aLayer );
180
181 if( IsCopperLayer( aLayer ) )
182 {
183 // Skip NPTH pads on copper layers ( only if hole size == pad size ):
184 // Drill mark will be plotted if drill mark is SMALL_DRILL_SHAPE or FULL_DRILL_SHAPE
185 if( plotOpt.GetFormat() == PLOT_FORMAT::DXF )
186 plotOpt.SetDXFPlotPolygonMode( true );
187 else
188 plotOpt.SetSkipPlotNPTH_Pads( true );
189
190 plotLayer( layer_mask, plotOpt );
191 }
192 else
193 {
194 switch( aLayer )
195 {
196 case B_Mask:
197 case F_Mask:
198 // Disable plot pad holes
200
201 // Use outline mode for DXF
202 plotOpt.SetDXFPlotPolygonMode( true );
203
204 // Plot solder mask:
205 if( soldermask_min_thickness == 0 )
206 {
207 plotLayer( layer_mask, plotOpt );
208 }
209 else
210 {
211 PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt,
212 soldermask_min_thickness );
213 }
214
215 break;
216
217 case B_Adhes:
218 case F_Adhes:
219 case B_Paste:
220 case F_Paste:
221 // Disable plot pad holes
223
224 // Use outline mode for DXF
225 plotOpt.SetDXFPlotPolygonMode( true );
226
227 plotLayer( layer_mask, plotOpt );
228
229 break;
230
231 case F_SilkS:
232 case B_SilkS:
233 plotLayer( layer_mask, plotOpt );
234
235 // Gerber: Subtract soldermask from silkscreen if enabled
236 if( aPlotter->GetPlotterType() == PLOT_FORMAT::GERBER
237 && plotOpt.GetSubtractMaskFromSilk() )
238 {
239 if( aLayer == F_SilkS )
240 layer_mask = LSET( F_Mask );
241 else
242 layer_mask = LSET( B_Mask );
243
244 // Create the mask to subtract by creating a negative layer polarity
245 aPlotter->SetLayerPolarity( false );
246
247 // Disable plot pad holes
249
250 // Plot the mask
251 PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
252
253 // Disable the negative polarity
254 aPlotter->SetLayerPolarity( true );
255 }
256
257 break;
258
259 case Dwgs_User:
260 case Cmts_User:
261 case Eco1_User:
262 case Eco2_User:
263 case Edge_Cuts:
264 case Margin:
265 case F_CrtYd:
266 case B_CrtYd:
267 case F_Fab:
268 case B_Fab:
269 default:
270 plotLayer( layer_mask, plotOpt );
271 break;
272 }
273 }
274}
275
276
280void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
281 const PCB_PLOT_PARAMS& aPlotOpt )
282{
283 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
284 int maxError = aBoard->GetDesignSettings().m_MaxError;
285
286 itemplotter.SetLayerSet( aLayerMask );
287
288 OUTLINE_MODE plotMode = aPlotOpt.GetPlotMode();
289 bool onCopperLayer = ( LSET::AllCuMask() & aLayerMask ).any();
290 bool onSolderMaskLayer = ( LSET( { F_Mask, B_Mask } ) & aLayerMask ).any();
291 bool onSolderPasteLayer = ( LSET( { F_Paste, B_Paste } ) & aLayerMask ).any();
292 bool onFrontFab = ( LSET( F_Fab ) & aLayerMask ).any();
293 bool onBackFab = ( LSET( B_Fab ) & aLayerMask ).any();
294 bool sketchPads = ( onFrontFab || onBackFab ) && aPlotOpt.GetSketchPadsOnFabLayers();
295
296 // Plot edge layer and graphic items
297 for( const BOARD_ITEM* item : aBoard->Drawings() )
298 itemplotter.PlotBoardGraphicItem( item );
299
300 // Draw footprint texts:
301 for( const FOOTPRINT* footprint : aBoard->Footprints() )
302 itemplotter.PlotFootprintTextItems( footprint );
303
304 // Draw footprint other graphic items:
305 for( const FOOTPRINT* footprint : aBoard->Footprints() )
306 itemplotter.PlotFootprintGraphicItems( footprint );
307
308 // Plot footprint pads
309 for( FOOTPRINT* footprint : aBoard->Footprints() )
310 {
311 aPlotter->StartBlock( nullptr );
312
313 for( PAD* pad : footprint->Pads() )
314 {
315 OUTLINE_MODE padPlotMode = plotMode;
316
317 if( !( pad->GetLayerSet() & aLayerMask ).any() )
318 {
319 if( sketchPads &&
320 ( ( onFrontFab && pad->GetLayerSet().Contains( F_Cu ) ) ||
321 ( onBackFab && pad->GetLayerSet().Contains( B_Cu ) ) ) )
322 {
323 padPlotMode = SKETCH;
324 }
325 else
326 {
327 continue;
328 }
329 }
330
331 if( onCopperLayer && !pad->IsOnCopperLayer() )
332 continue;
333
335 if( onCopperLayer && !pad->FlashLayer( aLayerMask ) )
336 continue;
337
339
340 // If we're plotting a single layer, the color for that layer can be used directly.
341 if( aLayerMask.count() == 1 )
342 {
343 color = aPlotOpt.ColorSettings()->GetColor( aLayerMask.Seq()[0] );
344 }
345 else
346 {
347 if( ( pad->GetLayerSet() & aLayerMask )[B_Cu] )
348 color = aPlotOpt.ColorSettings()->GetColor( B_Cu );
349
350 if( ( pad->GetLayerSet() & aLayerMask )[F_Cu] )
351 color = color.LegacyMix( aPlotOpt.ColorSettings()->GetColor( F_Cu ) );
352
353 if( sketchPads && aLayerMask[F_Fab] )
354 color = aPlotOpt.ColorSettings()->GetColor( F_Fab );
355 else if( sketchPads && aLayerMask[B_Fab] )
356 color = aPlotOpt.ColorSettings()->GetColor( B_Fab );
357 }
358
359 if( sketchPads &&
360 ( ( onFrontFab && pad->GetLayerSet().Contains( F_Cu ) ) ||
361 ( onBackFab && pad->GetLayerSet().Contains( B_Cu ) ) ) )
362 {
363 if( aPlotOpt.GetPlotPadNumbers() )
364 itemplotter.PlotPadNumber( pad, color );
365 }
366
367 VECTOR2I margin;
368 int width_adj = 0;
369
370 if( onCopperLayer )
371 width_adj = itemplotter.getFineWidthAdj();
372
373 if( onSolderMaskLayer )
374 margin.x = margin.y = pad->GetSolderMaskExpansion();
375
376 if( onSolderPasteLayer )
377 margin = pad->GetSolderPasteMargin();
378
379 // not all shapes can have a different margin for x and y axis
380 // in fact only oval and rect shapes can have different values.
381 // Round shape have always the same x,y margin
382 // so define a unique value for other shapes that do not support different values
383 int mask_clearance = margin.x;
384
385 // Now offset the pad size by margin + width_adj
386 VECTOR2I padPlotsSize = pad->GetSize() + margin * 2 + VECTOR2I( width_adj, width_adj );
387
388 // Store these parameters that can be modified to plot inflated/deflated pads shape
389 PAD_SHAPE padShape = pad->GetShape();
390 VECTOR2I padSize = pad->GetSize();
391 VECTOR2I padDelta = pad->GetDelta(); // has meaning only for trapezoidal pads
392 // CornerRadius and CornerRadiusRatio can be modified
393 // the radius is built from the ratio, so saving/restoring the ratio is enough
394 double padCornerRadiusRatio = pad->GetRoundRectRadiusRatio();
395
396 // Don't draw a 0 sized pad.
397 // Note: a custom pad can have its pad anchor with size = 0
398 if( pad->GetShape() != PAD_SHAPE::CUSTOM
399 && ( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 ) )
400 {
401 continue;
402 }
403
404 switch( pad->GetShape() )
405 {
407 case PAD_SHAPE::OVAL:
408 pad->SetSize( padPlotsSize );
409
410 if( aPlotOpt.GetSkipPlotNPTH_Pads() &&
412 ( pad->GetSize() == pad->GetDrillSize() ) &&
413 ( pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
414 {
415 break;
416 }
417
418 itemplotter.PlotPad( pad, color, padPlotMode );
419 break;
420
422 pad->SetSize( padPlotsSize );
423
424 if( mask_clearance > 0 )
425 {
426 pad->SetShape( PAD_SHAPE::ROUNDRECT );
427 pad->SetRoundRectCornerRadius( mask_clearance );
428 }
429
430 itemplotter.PlotPad( pad, color, padPlotMode );
431 break;
432
434 // inflate/deflate a trapezoid is a bit complex.
435 // so if the margin is not null, build a similar polygonal pad shape,
436 // and inflate/deflate the polygonal shape
437 // because inflating/deflating using different values for y and y
438 // we are using only margin.x as inflate/deflate value
439 if( mask_clearance == 0 )
440 {
441 itemplotter.PlotPad( pad, color, padPlotMode );
442 }
443 else
444 {
445 PAD dummy( *pad );
446 dummy.SetAnchorPadShape( PAD_SHAPE::CIRCLE );
447 dummy.SetShape( PAD_SHAPE::CUSTOM );
448 SHAPE_POLY_SET outline;
449 outline.NewOutline();
450 int dx = padSize.x / 2;
451 int dy = padSize.y / 2;
452 int ddx = padDelta.x / 2;
453 int ddy = padDelta.y / 2;
454
455 outline.Append( -dx - ddy, dy + ddx );
456 outline.Append( dx + ddy, dy - ddx );
457 outline.Append( dx - ddy, -dy + ddx );
458 outline.Append( -dx + ddy, -dy - ddx );
459
460 // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
461 // which can create bad shapes if margin.x is < 0
462 outline.InflateWithLinkedHoles( mask_clearance,
465 dummy.DeletePrimitivesList();
466 dummy.AddPrimitivePoly( outline, 0, true );
467
468 // Be sure the anchor pad is not bigger than the deflated shape because this
469 // anchor will be added to the pad shape when plotting the pad. So now the
470 // polygonal shape is built, we can clamp the anchor size
471 dummy.SetSize( VECTOR2I( 0, 0 ) );
472
473 itemplotter.PlotPad( &dummy, color, padPlotMode );
474 }
475
476 break;
477
479 {
480 // rounding is stored as a percent, but we have to update this ratio
481 // to force recalculation of other values after size changing (we do not
482 // really change the rounding percent value)
483 double radius_ratio = pad->GetRoundRectRadiusRatio();
484 pad->SetSize( padPlotsSize );
485 pad->SetRoundRectRadiusRatio( radius_ratio );
486
487 itemplotter.PlotPad( pad, color, padPlotMode );
488 break;
489 }
490
492 if( mask_clearance == 0 )
493 {
494 // the size can be slightly inflated by width_adj (PS/PDF only)
495 pad->SetSize( padPlotsSize );
496 itemplotter.PlotPad( pad, color, padPlotMode );
497 }
498 else
499 {
500 // Due to the polygonal shape of a CHAMFERED_RECT pad, the best way is to
501 // convert the pad shape to a full polygon, inflate/deflate the polygon
502 // and use a dummy CUSTOM pad to plot the final shape.
503 PAD dummy( *pad );
504 // Build the dummy pad outline with coordinates relative to the pad position
505 // pad offset and orientation 0. The actual pos, offset and rotation will be
506 // taken in account later by the plot function
507 dummy.SetPosition( VECTOR2I( 0, 0 ) );
508 dummy.SetOffset( VECTOR2I( 0, 0 ) );
509 dummy.SetOrientation( ANGLE_0 );
510 SHAPE_POLY_SET outline;
511 dummy.TransformShapeToPolygon( outline, UNDEFINED_LAYER, 0, maxError,
512 ERROR_INSIDE );
513 outline.InflateWithLinkedHoles( mask_clearance,
516
517 // Initialize the dummy pad shape:
518 dummy.SetAnchorPadShape( PAD_SHAPE::CIRCLE );
519 dummy.SetShape( PAD_SHAPE::CUSTOM );
520 dummy.DeletePrimitivesList();
521 dummy.AddPrimitivePoly( outline, 0, true );
522
523 // Be sure the anchor pad is not bigger than the deflated shape because this
524 // anchor will be added to the pad shape when plotting the pad.
525 // So we set the anchor size to 0
526 dummy.SetSize( VECTOR2I( 0, 0 ) );
527 // Restore pad position and offset
528 dummy.SetPosition( pad->GetPosition() );
529 dummy.SetOffset( pad->GetOffset() );
530 dummy.SetOrientation( pad->GetOrientation() );
531
532 itemplotter.PlotPad( &dummy, color, padPlotMode );
533 }
534
535 break;
536
538 {
539 // inflate/deflate a custom shape is a bit complex.
540 // so build a similar pad shape, and inflate/deflate the polygonal shape
541 PAD dummy( *pad );
542 dummy.SetParentGroup( nullptr );
543
544 SHAPE_POLY_SET shape;
545 pad->MergePrimitivesAsPolygon( &shape );
546
547 // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
548 // which can create bad shapes if margin.x is < 0
549 shape.InflateWithLinkedHoles( mask_clearance,
552 dummy.DeletePrimitivesList();
553 dummy.AddPrimitivePoly( shape, 0, true );
554
555 // Be sure the anchor pad is not bigger than the deflated shape because this
556 // anchor will be added to the pad shape when plotting the pad. So now the
557 // polygonal shape is built, we can clamp the anchor size
558 if( mask_clearance < 0 ) // we expect margin.x = margin.y for custom pads
559 dummy.SetSize( padPlotsSize );
560
561 itemplotter.PlotPad( &dummy, color, padPlotMode );
562 break;
563 }
564 }
565
566 // Restore the pad parameters modified by the plot code
567 pad->SetSize( padSize );
568 pad->SetDelta( padDelta );
569 pad->SetShape( padShape );
570 pad->SetRoundRectRadiusRatio( padCornerRadiusRatio );
571 }
572
573 aPlotter->EndBlock( nullptr );
574 }
575
576 // Plot vias on copper layers, and if aPlotOpt.GetPlotViaOnMaskLayer() is true,
577 // plot them on solder mask
578
579 GBR_METADATA gbr_metadata;
580
581 bool isOnCopperLayer = ( aLayerMask & LSET::AllCuMask() ).any();
582
583 if( isOnCopperLayer )
584 {
587 }
588
589 aPlotter->StartBlock( nullptr );
590
591 for( const PCB_TRACK* track : aBoard->Tracks() )
592 {
593 if( track->Type() != PCB_VIA_T )
594 continue;
595
596 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
597
598 // vias are not plotted if not on selected layer
599 LSET via_mask_layer = via->GetLayerSet();
600
601 if( !( via_mask_layer & aLayerMask ).any() )
602 continue;
603
604 int via_margin = 0;
605 double width_adj = 0;
606
607 if( aLayerMask[B_Mask] || aLayerMask[F_Mask] )
608 via_margin = via->GetSolderMaskExpansion();
609
610 if( ( aLayerMask & LSET::AllCuMask() ).any() )
611 width_adj = itemplotter.getFineWidthAdj();
612
613 int diameter = via->GetWidth() + 2 * via_margin + width_adj;
614
616 if( onCopperLayer && !via->FlashLayer( aLayerMask ) )
617 continue;
618
619 // Don't draw a null size item :
620 if( diameter <= 0 )
621 continue;
622
623 // Some vias can be not connected (no net).
624 // Set the m_NotInNet for these vias to force a empty net name in gerber file
625 gbr_metadata.m_NetlistMetadata.m_NotInNet = via->GetNetname().IsEmpty();
626
627 gbr_metadata.SetNetName( via->GetNetname() );
628
629 COLOR4D color = aPlotOpt.ColorSettings()->GetColor(
630 LAYER_VIAS + static_cast<int>( via->GetViaType() ) );
631
632 // Set plot color (change WHITE to LIGHTGRAY because the white items are not seen on a
633 // white paper or screen
634 aPlotter->SetColor( color != WHITE ? color : LIGHTGRAY );
635 aPlotter->FlashPadCircle( via->GetStart(), diameter, plotMode, &gbr_metadata );
636 }
637
638 aPlotter->EndBlock( nullptr );
639 aPlotter->StartBlock( nullptr );
641
642 // Plot tracks (not vias) :
643 for( const PCB_TRACK* track : aBoard->Tracks() )
644 {
645 if( track->Type() == PCB_VIA_T )
646 continue;
647
648 if( !aLayerMask[track->GetLayer()] )
649 continue;
650
651 // Some track segments can be not connected (no net).
652 // Set the m_NotInNet for these segments to force a empty net name in gerber file
653 gbr_metadata.m_NetlistMetadata.m_NotInNet = track->GetNetname().IsEmpty();
654
655 gbr_metadata.SetNetName( track->GetNetname() );
656 int width = track->GetWidth() + itemplotter.getFineWidthAdj();
657 aPlotter->SetColor( itemplotter.getColor( track->GetLayer() ) );
658
659 if( track->Type() == PCB_ARC_T )
660 {
661 const PCB_ARC* arc = static_cast<const PCB_ARC*>( track );
662
663 // Too small arcs cannot be really handled: arc center (and arc radius)
664 // cannot be safely computed
665 if( !arc->IsDegenerated( 10 /* in IU */ ) )
666 {
667 aPlotter->ThickArc( arc->GetCenter(), arc->GetArcAngleStart(), arc->GetAngle(),
668 arc->GetRadius(), width, plotMode, &gbr_metadata );
669 }
670 else
671 {
672 // Approximate this very small arc by a segment.
673 aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode,
674 &gbr_metadata );
675 }
676 }
677 else
678 {
679 aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode,
680 &gbr_metadata );
681 }
682 }
683
684 aPlotter->EndBlock( nullptr );
685
686 // Plot filled ares
687 aPlotter->StartBlock( nullptr );
688
689 NETINFO_ITEM nonet( aBoard );
690
691 for( const ZONE* zone : aBoard->Zones() )
692 {
693 if( zone->GetIsRuleArea() )
694 continue;
695
696 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
697 {
698 if( !aLayerMask[layer] )
699 continue;
700
701 SHAPE_POLY_SET mainArea = zone->GetFilledPolysList( layer )->CloneDropTriangulation();
702 SHAPE_POLY_SET islands;
703
704 for( int i = mainArea.OutlineCount() - 1; i >= 0; i-- )
705 {
706 if( zone->IsIsland( layer, i ) )
707 {
708 islands.AddOutline( mainArea.CPolygon( i )[0] );
709 mainArea.DeletePolygon( i );
710 }
711 }
712
713 itemplotter.PlotZone( zone, layer, mainArea );
714
715 if( !islands.IsEmpty() )
716 {
717 ZONE dummy( *zone );
718 dummy.SetNet( &nonet );
719 itemplotter.PlotZone( &dummy, layer, islands );
720 }
721 }
722 }
723
724 aPlotter->EndBlock( nullptr );
725
726 // Adding drill marks, if required and if the plotter is able to plot them:
728 itemplotter.PlotDrillMarks();
729}
730
731
735void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
736 const PCB_PLOT_PARAMS& aPlotOpt )
737{
738 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
739 itemplotter.SetLayerSet( aLayerMask );
740
741 SHAPE_POLY_SET outlines;
742
743 for( PCB_LAYER_ID layer : aLayerMask.Seq( aLayerMask.SeqStackupForPlotting() ) )
744 {
745 outlines.RemoveAllContours();
746 aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines );
747
749
750 // Plot outlines
751 std::vector<VECTOR2I> cornerList;
752
753 // Now we have one or more basic polygons: plot each polygon
754 for( int ii = 0; ii < outlines.OutlineCount(); ii++ )
755 {
756 for( int kk = 0; kk <= outlines.HoleCount(ii); kk++ )
757 {
758 cornerList.clear();
759 const SHAPE_LINE_CHAIN& path = ( kk == 0 ) ? outlines.COutline( ii )
760 : outlines.CHole( ii, kk - 1 );
761
762 aPlotter->PlotPoly( path, FILL_T::NO_FILL );
763 }
764 }
765
766 // Plot pad holes
768 {
769 int smallDrill = ( aPlotOpt.GetDrillMarksType() == DRILL_MARKS::SMALL_DRILL_SHAPE )
771 : INT_MAX;
772
773 for( FOOTPRINT* footprint : aBoard->Footprints() )
774 {
775 for( PAD* pad : footprint->Pads() )
776 {
777 if( pad->HasHole() )
778 {
779 std::shared_ptr<SHAPE_SEGMENT> slot = pad->GetEffectiveHoleShape();
780
781 if( slot->GetSeg().A == slot->GetSeg().B ) // circular hole
782 {
783 int drill = std::min( smallDrill, slot->GetWidth() );
784 aPlotter->Circle( pad->GetPosition(), drill, FILL_T::NO_FILL );
785 }
786 else
787 {
788 // Note: small drill marks have no significance when applied to slots
789 aPlotter->ThickSegment( slot->GetSeg().A, slot->GetSeg().B,
790 slot->GetWidth(), SKETCH, nullptr );
791 }
792 }
793 }
794 }
795 }
796
797 // Plot vias holes
798 for( PCB_TRACK* track : aBoard->Tracks() )
799 {
800 if( track->Type() != PCB_VIA_T )
801 continue;
802
803 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
804
805 if( via->GetLayerSet().Contains( layer ) ) // via holes can be not through holes
806 aPlotter->Circle( via->GetPosition(), via->GetDrillValue(), FILL_T::NO_FILL );
807 }
808 }
809}
810
811
829void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
830 const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness )
831{
832 int maxError = aBoard->GetDesignSettings().m_MaxError;
833 PCB_LAYER_ID layer = aLayerMask[B_Mask] ? B_Mask : F_Mask;
834 SHAPE_POLY_SET buffer;
835 SHAPE_POLY_SET* boardOutline = nullptr;
836
837 if( aBoard->GetBoardPolygonOutlines( buffer ) )
838 boardOutline = &buffer;
839
840 // We remove 1nm as we expand both sides of the shapes, so allowing for a strictly greater
841 // than or equal comparison in the shape separation (boolean add)
842 int inflate = aMinThickness / 2 - 1;
843
844 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
845 itemplotter.SetLayerSet( aLayerMask );
846
847 // Build polygons for each pad shape. The size of the shape on solder mask should be size
848 // of pad + clearance around the pad, where clearance = solder mask clearance + extra margin.
849 // Extra margin is half the min width for solder mask, which is used to merge too-close shapes
850 // (distance < aMinThickness), and will be removed when creating the actual shapes.
851
852 // Will contain shapes inflated by inflate value that will be merged and deflated by inflate
853 // value to build final polygons
854 SHAPE_POLY_SET areas;
855
856 // Will contain exact shapes of all items on solder mask
857 SHAPE_POLY_SET initialPolys;
858
859 auto plotFPTextItem =
860 [&]( const PCB_TEXT& aText )
861 {
862 if( !itemplotter.GetPlotFPText() )
863 return;
864
865 if( !aText.IsVisible() && !itemplotter.GetPlotInvisibleText() )
866 return;
867
868 if( aText.GetText() == wxT( "${REFERENCE}" ) && !itemplotter.GetPlotReference() )
869 return;
870
871 if( aText.GetText() == wxT( "${VALUE}" ) && !itemplotter.GetPlotValue() )
872 return;
873
874 // add shapes with their exact mask layer size in initialPolys
875 aText.TransformTextToPolySet( initialPolys, 0, maxError, ERROR_OUTSIDE );
876
877 // add shapes inflated by aMinThickness/2 in areas
878 aText.TransformTextToPolySet( areas, inflate, maxError, ERROR_OUTSIDE );
879 };
880
881 // Generate polygons with arcs inside the shape or exact shape to minimize shape changes
882 // created by arc to segment size correction.
884 {
885 // Plot footprint pads and graphics
886 for( const FOOTPRINT* footprint : aBoard->Footprints() )
887 {
888 // add shapes with their exact mask layer size in initialPolys
889 footprint->TransformPadsToPolySet( initialPolys, layer, 0, maxError, ERROR_OUTSIDE );
890 // add shapes inflated by aMinThickness/2 in areas
891 footprint->TransformPadsToPolySet( areas, layer, inflate, maxError, ERROR_OUTSIDE );
892
893 for( const PCB_FIELD* field : footprint->Fields() )
894 {
895 if( field->IsReference() && !itemplotter.GetPlotReference() )
896 continue;
897
898 if( field->IsValue() && !itemplotter.GetPlotValue() )
899 continue;
900
901 if( field->IsOnLayer( layer ) )
902 plotFPTextItem( static_cast<const PCB_TEXT&>( *field ) );
903 }
904
905 for( const BOARD_ITEM* item : footprint->GraphicalItems() )
906 {
907 if( item->IsOnLayer( layer ) )
908 {
909 if( item->Type() == PCB_TEXT_T )
910 {
911 plotFPTextItem( static_cast<const PCB_TEXT&>( *item ) );
912 }
913 else
914 {
915 // add shapes with their exact mask layer size in initialPolys
916 item->TransformShapeToPolygon( initialPolys, layer, 0, maxError,
918
919 // add shapes inflated by aMinThickness/2 in areas
920 item->TransformShapeToPolygon( areas, layer, inflate, maxError,
922 }
923 }
924 }
925 }
926
927 // Plot (untented) vias
928 for( const PCB_TRACK* track : aBoard->Tracks() )
929 {
930 if( track->Type() != PCB_VIA_T )
931 continue;
932
933 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
934
935 // Note: IsOnLayer() checks relevant mask layers of untented vias
936 if( !via->IsOnLayer( layer ) )
937 continue;
938
939 int clearance = via->GetSolderMaskExpansion();
940
941 // add shapes with their exact mask layer size in initialPolys
942 via->TransformShapeToPolygon( initialPolys, layer, clearance, maxError, ERROR_OUTSIDE );
943
944 // add shapes inflated by aMinThickness/2 in areas
945 clearance += inflate;
946 via->TransformShapeToPolygon( areas, layer, clearance, maxError, ERROR_OUTSIDE );
947 }
948
949 // Add filled zone areas.
950#if 0 // Set to 1 if a solder mask expansion must be applied to zones on solder mask
951 int zone_margin = aBoard->GetDesignSettings().m_SolderMaskExpansion;
952#else
953 int zone_margin = 0;
954#endif
955
956 for( const BOARD_ITEM* item : aBoard->Drawings() )
957 {
958 if( item->IsOnLayer( layer ) )
959 {
960 if( item->Type() == PCB_TEXT_T )
961 {
962 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
963
964 // add shapes with their exact mask layer size in initialPolys
965 text->TransformTextToPolySet( initialPolys, 0, maxError, ERROR_OUTSIDE );
966
967 // add shapes inflated by aMinThickness/2 in areas
968 text->TransformTextToPolySet( areas, inflate, maxError, ERROR_OUTSIDE );
969 }
970 else
971 {
972 // add shapes with their exact mask layer size in initialPolys
973 item->TransformShapeToPolygon( initialPolys, layer, 0, maxError,
975
976 // add shapes inflated by aMinThickness/2 in areas
977 item->TransformShapeToPolygon( areas, layer, inflate, maxError,
979 }
980 }
981 }
982
983 for( ZONE* zone : aBoard->Zones() )
984 {
985 if( zone->GetIsRuleArea() )
986 continue;
987
988 if( !zone->IsOnLayer( layer ) )
989 continue;
990
991 // add shapes inflated by aMinThickness/2 in areas
992 zone->TransformSmoothedOutlineToPolygon( areas, inflate + zone_margin, maxError,
993 ERROR_OUTSIDE, boardOutline );
994
995 // add shapes with their exact mask layer size in initialPolys
996 zone->TransformSmoothedOutlineToPolygon( initialPolys, zone_margin, maxError,
997 ERROR_OUTSIDE, boardOutline );
998 }
999 }
1000
1001 // Merge all polygons: After deflating, not merged (not overlapping) polygons will have the
1002 // initial shape (with perhaps small changes due to deflating transform)
1004 areas.Deflate( inflate, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
1005
1006 // To avoid a lot of code, use a ZONE to handle and plot polygons, because our polygons look
1007 // exactly like filled areas in zones.
1008 // Note, also this code is not optimized: it creates a lot of copy/duplicate data.
1009 // However it is not complex, and fast enough for plot purposes (copy/convert data is only a
1010 // very small calculation time for these calculations).
1011 ZONE zone( aBoard );
1012 zone.SetMinThickness( 0 ); // trace polygons only
1013 zone.SetLayer( layer );
1014
1015 // Combine the current areas to initial areas. This is mandatory because inflate/deflate
1016 // transform is not perfect, and we want the initial areas perfectly kept
1017 areas.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST );
1019
1020 itemplotter.PlotZone( &zone, layer, areas );
1021}
1022
1023
1030static void initializePlotter( PLOTTER* aPlotter, const BOARD* aBoard,
1031 const PCB_PLOT_PARAMS* aPlotOpts )
1032{
1033 PAGE_INFO pageA4( wxT( "A4" ) );
1034 const PAGE_INFO& pageInfo = aBoard->GetPageSettings();
1035 const PAGE_INFO* sheet_info;
1036 double paperscale; // Page-to-paper ratio
1037 VECTOR2I paperSizeIU;
1038 VECTOR2I pageSizeIU( pageInfo.GetSizeIU( pcbIUScale.IU_PER_MILS ) );
1039 bool autocenter = false;
1040
1041 // Special options: to fit the sheet to an A4 sheet replace the paper size. However there
1042 // is a difference between the autoscale and the a4paper option:
1043 // - Autoscale fits the board to the paper size
1044 // - A4paper fits the original paper size to an A4 sheet
1045 // - Both of them fit the board to an A4 sheet
1046 if( aPlotOpts->GetA4Output() )
1047 {
1048 sheet_info = &pageA4;
1049 paperSizeIU = pageA4.GetSizeIU( pcbIUScale.IU_PER_MILS );
1050 paperscale = (double) paperSizeIU.x / pageSizeIU.x;
1051 autocenter = true;
1052 }
1053 else
1054 {
1055 sheet_info = &pageInfo;
1056 paperSizeIU = pageSizeIU;
1057 paperscale = 1;
1058
1059 // Need autocentering only if scale is not 1:1
1060 autocenter = (aPlotOpts->GetScale() != 1.0);
1061 }
1062
1063 BOX2I bbox = aBoard->ComputeBoundingBox( false, false );
1064 VECTOR2I boardCenter = bbox.Centre();
1065 VECTOR2I boardSize = bbox.GetSize();
1066
1067 double compound_scale;
1068
1069 // Fit to 80% of the page if asked; it could be that the board is empty, in this case
1070 // regress to 1:1 scale
1071 if( aPlotOpts->GetAutoScale() && boardSize.x > 0 && boardSize.y > 0 )
1072 {
1073 double xscale = (paperSizeIU.x * 0.8) / boardSize.x;
1074 double yscale = (paperSizeIU.y * 0.8) / boardSize.y;
1075
1076 compound_scale = std::min( xscale, yscale ) * paperscale;
1077 }
1078 else
1079 {
1080 compound_scale = aPlotOpts->GetScale() * paperscale;
1081 }
1082
1083 // For the plot offset we have to keep in mind the auxiliary origin too: if autoscaling is
1084 // off we check that plot option (i.e. autoscaling overrides auxiliary origin)
1085 VECTOR2I offset( 0, 0);
1086
1087 if( autocenter )
1088 {
1089 offset.x = KiROUND( boardCenter.x - ( paperSizeIU.x / 2.0 ) / compound_scale );
1090 offset.y = KiROUND( boardCenter.y - ( paperSizeIU.y / 2.0 ) / compound_scale );
1091 }
1092 else
1093 {
1094 if( aPlotOpts->GetUseAuxOrigin() )
1095 offset = aBoard->GetDesignSettings().GetAuxOrigin();
1096 }
1097
1098 aPlotter->SetPageSettings( *sheet_info );
1099
1100 aPlotter->SetViewport( offset, pcbIUScale.IU_PER_MILS/10, compound_scale, aPlotOpts->GetMirror() );
1101
1102 // Has meaning only for gerber plotter. Must be called only after SetViewport
1103 aPlotter->SetGerberCoordinatesFormat( aPlotOpts->GetGerberPrecision() );
1104
1105 // Has meaning only for SVG plotter. Must be called only after SetViewport
1106 aPlotter->SetSvgCoordinatesFormat( aPlotOpts->GetSvgPrecision() );
1107
1108 aPlotter->SetCreator( wxT( "PCBNEW" ) );
1109 aPlotter->SetColorMode( !aPlotOpts->GetBlackAndWhite() ); // default is plot in Black and White.
1110 aPlotter->SetTextMode( aPlotOpts->GetTextMode() );
1111}
1112
1113
1117static void FillNegativeKnockout( PLOTTER *aPlotter, const BOX2I &aBbbox )
1118{
1119 const int margin = 5 * pcbIUScale.IU_PER_MM; // Add a 5 mm margin around the board
1120 aPlotter->SetNegative( true );
1121 aPlotter->SetColor( WHITE ); // Which will be plotted as black
1122
1123 BOX2I area = aBbbox;
1124 area.Inflate( margin );
1125 aPlotter->Rect( area.GetOrigin(), area.GetEnd(), FILL_T::FILLED_SHAPE );
1126 aPlotter->SetColor( BLACK );
1127}
1128
1129
1133static void ConfigureHPGLPenSizes( HPGL_PLOTTER *aPlotter, const PCB_PLOT_PARAMS *aPlotOpts )
1134{
1135 // Compute penDiam (the value is given in mils) in pcb units, with plot scale (if Scale is 2,
1136 // penDiam value is always m_HPGLPenDiam so apparent penDiam is actually penDiam / Scale
1137 int penDiam = KiROUND( aPlotOpts->GetHPGLPenDiameter() * pcbIUScale.IU_PER_MILS / aPlotOpts->GetScale() );
1138
1139 // Set HPGL-specific options and start
1140 aPlotter->SetPenSpeed( aPlotOpts->GetHPGLPenSpeed() );
1141 aPlotter->SetPenNumber( aPlotOpts->GetHPGLPenNum() );
1142 aPlotter->SetPenDiameter( penDiam );
1143}
1144
1145
1152PLOTTER* StartPlotBoard( BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer,
1153 const wxString& aLayerName, const wxString& aFullFileName,
1154 const wxString& aSheetName, const wxString& aSheetPath )
1155{
1156 // Create the plotter driver and set the few plotter specific options
1157 PLOTTER* plotter = nullptr;
1158
1159 switch( aPlotOpts->GetFormat() )
1160 {
1161 case PLOT_FORMAT::DXF:
1162 DXF_PLOTTER* DXF_plotter;
1163 DXF_plotter = new DXF_PLOTTER();
1164 DXF_plotter->SetUnits( aPlotOpts->GetDXFPlotUnits() );
1165
1166 plotter = DXF_plotter;
1167 break;
1168
1169 case PLOT_FORMAT::POST:
1170 PS_PLOTTER* PS_plotter;
1171 PS_plotter = new PS_PLOTTER();
1172 PS_plotter->SetScaleAdjust( aPlotOpts->GetFineScaleAdjustX(),
1173 aPlotOpts->GetFineScaleAdjustY() );
1174 plotter = PS_plotter;
1175 break;
1176
1177 case PLOT_FORMAT::PDF:
1178 plotter = new PDF_PLOTTER();
1179 break;
1180
1181 case PLOT_FORMAT::HPGL:
1182 HPGL_PLOTTER* HPGL_plotter;
1183 HPGL_plotter = new HPGL_PLOTTER();
1184
1185 // HPGL options are a little more convoluted to compute, so they get their own function
1186 ConfigureHPGLPenSizes( HPGL_plotter, aPlotOpts );
1187 plotter = HPGL_plotter;
1188 break;
1189
1191 // For Gerber plotter, a valid board layer must be set, in order to create a valid
1192 // Gerber header, especially the TF.FileFunction and .FilePolarity data
1193 if( aLayer < PCBNEW_LAYER_ID_START || aLayer >= PCB_LAYER_ID_COUNT )
1194 {
1195 wxLogError( wxString::Format(
1196 "Invalid board layer %d, cannot build a valid Gerber file header",
1197 aLayer ) );
1198 }
1199
1200 plotter = new GERBER_PLOTTER();
1201 break;
1202
1203 case PLOT_FORMAT::SVG:
1204 plotter = new SVG_PLOTTER();
1205 break;
1206
1207 default:
1208 wxASSERT( false );
1209 return nullptr;
1210 }
1211
1213 renderSettings->LoadColors( aPlotOpts->ColorSettings() );
1214 renderSettings->SetDefaultPenWidth( pcbIUScale.mmToIU( 0.0212 ) ); // Hairline at 1200dpi
1215 renderSettings->SetLayerName( aLayerName );
1216
1217 plotter->SetRenderSettings( renderSettings );
1218
1219 // Compute the viewport and set the other options
1220
1221 // page layout is not mirrored, so temporarily change mirror option for the page layout
1222 PCB_PLOT_PARAMS plotOpts = *aPlotOpts;
1223
1224 if( plotOpts.GetPlotFrameRef() && plotOpts.GetMirror() )
1225 plotOpts.SetMirror( false );
1226
1227 initializePlotter( plotter, aBoard, &plotOpts );
1228
1229 if( plotter->OpenFile( aFullFileName ) )
1230 {
1231 plotter->ClearHeaderLinesList();
1232
1233 // For the Gerber "file function" attribute, set the layer number
1234 if( plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1235 {
1236 bool useX2mode = plotOpts.GetUseGerberX2format();
1237
1238 GERBER_PLOTTER* gbrplotter = static_cast <GERBER_PLOTTER*> ( plotter );
1239 gbrplotter->DisableApertMacros( plotOpts.GetDisableGerberMacros() );
1240 gbrplotter->UseX2format( useX2mode );
1241 gbrplotter->UseX2NetAttributes( plotOpts.GetIncludeGerberNetlistInfo() );
1242
1243 // Attributes can be added using X2 format or as comment (X1 format)
1244 AddGerberX2Attribute( plotter, aBoard, aLayer, not useX2mode );
1245 }
1246
1247 if( plotter->StartPlot( wxT( "1" ) ) )
1248 {
1249 // Plot the frame reference if requested
1250 if( aPlotOpts->GetPlotFrameRef() )
1251 {
1252 PlotDrawingSheet( plotter, aBoard->GetProject(), aBoard->GetTitleBlock(),
1253 aBoard->GetPageSettings(), &aBoard->GetProperties(), wxT( "1" ),
1254 1, aSheetName, aSheetPath, aBoard->GetFileName(),
1255 renderSettings->GetLayerColor( LAYER_DRAWINGSHEET ) );
1256
1257 if( aPlotOpts->GetMirror() )
1258 initializePlotter( plotter, aBoard, aPlotOpts );
1259 }
1260
1261 // When plotting a negative board: draw a black rectangle (background for plot board
1262 // in white) and switch the current color to WHITE; note the color inversion is actually
1263 // done in the driver (if supported)
1264 if( aPlotOpts->GetNegative() )
1265 {
1266 BOX2I bbox = aBoard->ComputeBoundingBox( false, false );
1267 FillNegativeKnockout( plotter, bbox );
1268 }
1269
1270 return plotter;
1271 }
1272 }
1273
1274 delete plotter->RenderSettings();
1275 delete plotter;
1276 return nullptr;
1277}
int color
Definition: DXF_plotter.cpp:58
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
const VECTOR2I & GetAuxOrigin()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:288
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false, bool aIncludeNPTHAsOutlines=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
Definition: board.cpp:2451
const PAGE_INFO & GetPageSettings() const
Definition: board.h:674
const ZONES & Zones() const
Definition: board.h:333
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false, bool aIncludeHiddenText=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1630
void ConvertBrdLayerToPolygonalContours(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aOutlines) const
Build a set of polygons which are the outlines of copper items (pads, tracks, vias,...
Definition: board.cpp:2824
TITLE_BLOCK & GetTitleBlock()
Definition: board.h:680
const std::map< wxString, wxString > & GetProperties() const
Definition: board.h:360
const FOOTPRINTS & Footprints() const
Definition: board.h:329
const TRACKS & Tracks() const
Definition: board.h:327
const wxString & GetFileName() const
Definition: board.h:325
PROJECT * GetProject() const
Definition: board.h:482
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:872
const DRAWINGS & Drawings() const
Definition: board.h:331
const Vec & GetOrigin() const
Definition: box2.h:200
const SizeVec & GetSize() const
Definition: box2.h:196
size_type GetHeight() const
Definition: box2.h:205
size_type GetWidth() const
Definition: box2.h:204
const Vec GetEnd() const
Definition: box2.h:202
void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition: box2.h:128
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:541
Vec Centre() const
Definition: box2.h:87
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 SetLayerSet(LSET aLayerMask)
Definition: pcbplot.h:86
void PlotPad(const PAD *aPad, const COLOR4D &aColor, OUTLINE_MODE aPlotMode)
Plot a pad.
COLOR4D getColor(int aLayer) const
White color is special because it cannot be seen on a white paper in B&W mode.
void PlotFootprintTextItems(const FOOTPRINT *aFootprint)
int getFineWidthAdj() const
Definition: pcbplot.h:77
void PlotFootprintGraphicItems(const FOOTPRINT *aFootprint)
COLOR4D GetColor(int aLayer) const
When creating polygons to create a clearance polygonal area, the polygon must be same or bigger than ...
void SetUnits(DXF_UNITS aUnit)
Set the units to use for plotting the DXF file.
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:98
@ GBR_APERTURE_ATTRIB_VIAPAD
aperture used for vias.
Definition: gbr_metadata.h:102
Metadata which can be added in a gerber file as attribute in X2 format.
Definition: gbr_metadata.h:205
void SetNetName(const wxString &aNetname)
Definition: gbr_metadata.h:229
void SetApertureAttrib(GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB aApertAttribute)
Definition: gbr_metadata.h:209
GBR_NETLIST_METADATA m_NetlistMetadata
An item to handle object attribute.
Definition: gbr_metadata.h:262
void SetNetAttribType(int aNetAttribType)
Definition: gbr_metadata.h:219
@ GBR_NETINFO_NET
print info associated to a net (TO.N 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 UseX2format(bool aEnable)
void UseX2NetAttributes(bool aEnable)
void DisableApertMacros(bool aDisable)
Disable Aperture Macro (AM) command, only for broken Gerber Readers.
virtual void SetPenSpeed(int speed)
Definition: plotter_hpgl.h:88
virtual void SetPenNumber(int number)
Definition: plotter_hpgl.h:93
virtual void SetPenDiameter(double diameter)
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
static const COLOR4D BLACK
Definition: color4d.h:402
PCB specific render settings.
Definition: pcb_painter.h:78
void LoadColors(const COLOR_SETTINGS *aSettings) override
void SetDefaultPenWidth(int aWidth)
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
void SetLayerName(const wxString &aLayerName)
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:391
LSEQ SeqStackupForPlotting() const
Return the sequence that is typical for a bottom-to-top stack-up.
Definition: lset.cpp:536
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:737
Handle the data for a net.
Definition: netinfo.h:56
Definition: pad.h:54
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:59
const VECTOR2D GetSizeIU(double aIUScale) const
Gets the page size in internal units.
Definition: page_info.h:171
bool IsDegenerated(int aThreshold=5) const
Definition: pcb_track.cpp:1622
EDA_ANGLE GetArcAngleStart() const
Definition: pcb_track.cpp:1604
double GetRadius() const
Definition: pcb_track.cpp:1587
EDA_ANGLE GetAngle() const
Definition: pcb_track.cpp:1594
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_track.h:288
bool IsReference() const
Definition: pcb_field.h:70
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
Definition: pcb_field.cpp:92
bool IsValue() const
Definition: pcb_field.h:71
bool IsFootprint() const
Definition: pcb_field.h:72
Parameters and options when plotting/printing a board.
bool GetNegative() const
PLOT_FORMAT GetFormat() const
bool GetSkipPlotNPTH_Pads() const
void SetDrillMarksType(DRILL_MARKS aVal)
bool GetUseAuxOrigin() const
void SetSkipPlotNPTH_Pads(bool aSkip)
bool GetMirror() const
DXF_UNITS GetDXFPlotUnits() const
bool GetAutoScale() const
bool GetPlotInvisibleText() const
PLOT_TEXT_MODE GetTextMode() const
void SetDXFPlotPolygonMode(bool aFlag)
double GetHPGLPenDiameter() const
unsigned GetSvgPrecision() const
unsigned GetBlackAndWhite() const
double GetScale() const
bool GetPlotReference() const
bool m_PDFFrontFPPropertyPopups
Generate PDF property popup menus for footprints.
void SetMirror(bool aFlag)
bool GetSketchPadsOnFabLayers() const
bool GetSubtractMaskFromSilk() const
int GetGerberPrecision() const
int GetHPGLPenSpeed() const
double GetFineScaleAdjustY() const
bool GetPlotPadNumbers() const
bool GetA4Output() const
int GetHPGLPenNum() const
DRILL_MARKS GetDrillMarksType() const
bool GetUseGerberX2format() const
bool GetPlotValue() const
bool GetIncludeGerberNetlistInfo() const
double GetFineScaleAdjustX() const
bool m_PDFBackFPPropertyPopups
on front and/or back of board
bool GetPlotFPText() const
bool GetPlotFrameRef() const
bool GetDisableGerberMacros() const
OUTLINE_MODE GetPlotMode() const
COLOR_SETTINGS * ColorSettings() const
Base plotter engine class.
Definition: plotter.h:105
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:553
virtual void Circle(const VECTOR2I &pos, int diametre, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)=0
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition: plotter.cpp:74
virtual void SetNegative(bool aNegative)
Definition: plotter.h:125
virtual void SetSvgCoordinatesFormat(unsigned aPrecision)
Set the number of digits for mantissa in coordinates in mm for SVG plotter.
Definition: plotter.h:525
virtual void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: plotter.h:138
void SetRenderSettings(RENDER_SETTINGS *aSettings)
Definition: plotter.h:135
virtual bool StartPlot(const wxString &aPageNumber)=0
RENDER_SETTINGS * RenderSettings()
Definition: plotter.h:136
virtual void SetGerberCoordinatesFormat(int aResolution, bool aUseInches=false)
Definition: plotter.h:519
virtual void Bookmark(const BOX2I &aBox, const wxString &aName, const wxString &aGroupName=wxEmptyString)
Create a bookmark to a symbol.
Definition: plotter.h:476
virtual PLOT_FORMAT GetPlotterType() const =0
Returns the effective plot engine in use.
virtual void SetTextMode(PLOT_TEXT_MODE mode)
Change the current text mode.
Definition: plotter.h:514
virtual void SetCreator(const wxString &aCreator)
Definition: plotter.h:154
VECTOR2I GetPlotOffsetUserUnits()
Definition: plotter.h:552
void ClearHeaderLinesList()
Remove all lines from the list of free lines to print at the beginning of the file.
Definition: plotter.h:172
virtual void FlashPadCircle(const VECTOR2I &aPadPos, int aDiameter, OUTLINE_MODE aTraceMode, void *aData)=0
virtual void ThickArc(const EDA_SHAPE &aArcShape, OUTLINE_MODE aTraceMode, void *aData)
Definition: plotter.cpp:596
virtual void SetViewport(const VECTOR2I &aOffset, double aIusPerDecimil, double aScale, bool aMirror)=0
Set the plot offset and scaling for the current plot.
virtual void SetColorMode(bool aColorMode)
Plot in B/W or color.
Definition: plotter.h:132
virtual void StartBlock(void *aData)
calling this function allows one to define the beginning of a group of drawing items,...
Definition: plotter.h:537
virtual void PlotPoly(const std::vector< VECTOR2I > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=nullptr)=0
Draw a polygon ( filled or not ).
virtual void HyperlinkMenu(const BOX2I &aBox, const std::vector< wxString > &aDestURLs)
Create a clickable hyperlink menu with a rectangular click area.
Definition: plotter.h:465
virtual void SetLayerPolarity(bool aPositive)
Set the current Gerber layer polarity to positive or negative by writing %LPD*% or %LPC*% to the Gerb...
Definition: plotter.h:505
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)=0
virtual void SetColor(const COLOR4D &color)=0
virtual void EndBlock(void *aData)
calling this function allows one to define the end of a group of drawing items for instance in SVG or...
Definition: plotter.h:546
void SetScaleAdjust(double scaleX, double scaleY)
Set the 'fine' scaling for the postscript engine.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
void InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError, POLYGON_MODE aFastMode)
Perform outline inflation/deflation, using round corners.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
void DeletePolygon(int aIdx)
Delete aIdx-th polygon from the set.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify(POLYGON_MODE aFastMode)
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFastMo...
int NewOutline()
Creates a new empty polygon in the set and returns its index.
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of outlines in the set.
SHAPE_POLY_SET CloneDropTriangulation() const
const POLYGON & CPolygon(int aIndex) const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
void SetMinThickness(int aMinThickness)
Definition: zone.h:271
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: zone.cpp:263
@ WHITE
Definition: color4d.h:48
@ LIGHTGRAY
Definition: color4d.h:47
@ BLACK
Definition: color4d.h:44
void PlotDrawingSheet(PLOTTER *plotter, const PROJECT *aProject, const TITLE_BLOCK &aTitleBlock, const PAGE_INFO &aPageInfo, const std::map< wxString, wxString > *aProperties, const wxString &aSheetNumber, int aSheetCount, const wxString &aSheetName, const wxString &aSheetPath, const wxString &aFilename, COLOR4D aColor, bool aIsFirstPage)
@ CHAMFER_ALL_CORNERS
All angles are chamfered.
@ ROUND_ALL_CORNERS
All angles are rounded.
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
@ FILLED_SHAPE
Handle special data (items attributes) during plot.
a few functions useful in geometry calculations.
@ ERROR_OUTSIDE
@ ERROR_INSIDE
double m_SmallDrillMarkSize
The diameter of the drill marks on print and plot outputs (in mm) when the "Drill marks" option is se...
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:531
@ LAYER_DRAWINGSHEET
drawingsheet frame and titleblock
Definition: layer_ids.h:221
@ LAYER_VIAS
Meta control for all vias opacity/visibility.
Definition: layer_ids.h:197
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:117
@ B_Adhes
Definition: layer_ids.h:97
@ Edge_Cuts
Definition: layer_ids.h:113
@ Dwgs_User
Definition: layer_ids.h:109
@ F_Paste
Definition: layer_ids.h:101
@ Cmts_User
Definition: layer_ids.h:110
@ F_Adhes
Definition: layer_ids.h:98
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ Eco1_User
Definition: layer_ids.h:111
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ F_Fab
Definition: layer_ids.h:120
@ Margin
Definition: layer_ids.h:114
@ F_SilkS
Definition: layer_ids.h:104
@ B_CrtYd
Definition: layer_ids.h:116
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:112
@ B_SilkS
Definition: layer_ids.h:103
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:137
@ F_Cu
Definition: layer_ids.h:64
@ B_Fab
Definition: layer_ids.h:119
OUTLINE_MODE
Definition: outline_mode.h:25
@ SKETCH
Definition: outline_mode.h:26
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: padstack.h:46
void AddGerberX2Attribute(PLOTTER *aPlotter, const BOARD *aBoard, int aLayer, bool aUseX1CompatibilityMode)
Calculate some X2 attributes as defined in the Gerber file format specification and add them to the g...
Definition: pcbplot.cpp:354
static void FillNegativeKnockout(PLOTTER *aPlotter, const BOX2I &aBbbox)
Prefill in black an area a little bigger than the board to prepare for the negative plot.
void PlotBoardLayers(BOARD *aBoard, PLOTTER *aPlotter, const LSEQ &aLayers, const PCB_PLOT_PARAMS &aPlotOptions)
Plot a sequence of board layer IDs.
void PlotStandardLayer(BOARD *aBoard, PLOTTER *aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
Plot any layer EXCEPT a solder-mask with an enforced minimum width.
static void PlotSolderMaskLayer(BOARD *aBoard, PLOTTER *aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt, int aMinThickness)
Plot a solder mask layer.
void PlotOneBoardLayer(BOARD *aBoard, PLOTTER *aPlotter, PCB_LAYER_ID aLayer, const PCB_PLOT_PARAMS &aPlotOpt)
Plot one copper or technical layer.
void PlotLayerOutlines(BOARD *aBoard, PLOTTER *aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
Plot outlines.
static void ConfigureHPGLPenSizes(HPGL_PLOTTER *aPlotter, const PCB_PLOT_PARAMS *aPlotOpts)
Calculate the effective size of HPGL pens and set them in the plotter object.
static void initializePlotter(PLOTTER *aPlotter, const BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts)
Set up most plot options for plotting a board (especially the viewport) Important thing: page size is...
void PlotInteractiveLayer(BOARD *aBoard, PLOTTER *aPlotter, const PCB_PLOT_PARAMS &aPlotOpt)
Plot interactive items (hypertext links, properties, etc.).
PLOTTER * StartPlotBoard(BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString &aLayerName, const wxString &aFullFileName, const wxString &aSheetName, const wxString &aSheetPath)
Open a new plotfile using the options (and especially the format) specified in the options and prepar...
Plotting engine (HPGL)
Plotting engines similar to ps (PostScript, Gerber, svg)
std::vector< FAB_LAYER_COLOR > dummy
const double IU_PER_MM
Definition: base_units.h:76
const double IU_PER_MILS
Definition: base_units.h:77
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:121
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:673