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 if( !aBoard || !aPlotter || aLayers.empty() )
61 return;
62
63 // if a drill mark must be plotted, the copper layer needs to be plotted
64 // after other layers because the drill mark must be plotted as a filled
65 // white shape *after* all other shapes are plotted
66 bool plot_mark = aPlotOptions.GetDrillMarksType() != DRILL_MARKS::NO_DRILL_SHAPE;
67
68 for( PCB_LAYER_ID layer : aLayers )
69 {
70 // copper layers with drill marks will be plotted after all other layers
71 if( IsCopperLayer( layer ) && plot_mark )
72 continue;
73
74 PlotOneBoardLayer( aBoard, aPlotter, layer, aPlotOptions );
75 }
76
77 if( !plot_mark )
78 return;
79
80 for( PCB_LAYER_ID layer : aLayers )
81 {
82 if( !IsCopperLayer( layer ) )
83 continue;
84
85 PlotOneBoardLayer( aBoard, aPlotter, layer, aPlotOptions );
86 }
87}
88
89
90void PlotInteractiveLayer( BOARD* aBoard, PLOTTER* aPlotter, const PCB_PLOT_PARAMS& aPlotOpt )
91{
92 for( const FOOTPRINT* fp : aBoard->Footprints() )
93 {
94 if( fp->GetLayer() == F_Cu && !aPlotOpt.m_PDFFrontFPPropertyPopups )
95 continue;
96
97 if( fp->GetLayer() == B_Cu && !aPlotOpt.m_PDFBackFPPropertyPopups )
98 continue;
99
100 std::vector<wxString> properties;
101
102 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
103 _( "Reference designator" ),
104 fp->Reference().GetShownText( false ) ) );
105
106 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
107 _( "Value" ),
108 fp->Value().GetShownText( false ) ) );
109
110 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
111 _( "Footprint" ),
112 fp->GetFPID().GetUniStringLibItemName() ) );
113
114 for( int i = 0; i < fp->GetFieldCount(); i++ )
115 {
116 PCB_FIELD* field = fp->GetFields().at( i );
117
118 if( field->IsReference() || field->IsValue() )
119 continue;
120
121 if( field->GetText().IsEmpty() )
122 continue;
123
124 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
125 field->GetName(),
126 field->GetText() ) );
127 }
128
129 // These 2 properties are not very useful in a plot file (like a PDF)
130#if 0
131 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), _( "Library Description" ),
132 fp->GetLibDescription() ) );
133
134 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
135 _( "Keywords" ),
136 fp->GetKeywords() ) );
137#endif
138 // Draw items are plotted with a position offset. So we need to move
139 // our boxes (which are not plotted) by the same offset.
140 VECTOR2I offset = -aPlotter->GetPlotOffsetUserUnits();
141
142 // Use a footprint bbox without texts to create the hyperlink area
143 BOX2I bbox = fp->GetBoundingBox( false );
144 bbox.Move( offset );
145 aPlotter->HyperlinkMenu( bbox, properties );
146
147 // Use a footprint bbox with visible texts only to create the bookmark area
148 // which is the area to zoom on ft selection
149 // However the bbox need to be inflated for a better look.
150 bbox = fp->GetBoundingBox( true );
151 bbox.Move( offset );
152 bbox.Inflate( bbox.GetWidth() /2, bbox.GetHeight() /2 );
153 aPlotter->Bookmark( bbox, fp->GetReference(), _( "Footprints" ) );
154 }
155}
156
157
158void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
159 const PCB_PLOT_PARAMS& aPlotOpt )
160{
161 auto plotLayer =
162 [&]( LSET layerMask, PCB_PLOT_PARAMS& plotOpts )
163 {
164 // PlotLayerOutlines() is designed only for DXF plotters.
165 if( plotOpts.GetFormat() == PLOT_FORMAT::DXF && plotOpts.GetDXFPlotPolygonMode() )
166 PlotLayerOutlines( aBoard, aPlotter, layerMask, plotOpts );
167 else
168 PlotStandardLayer( aBoard, aPlotter, layerMask, plotOpts );
169 };
170
171 PCB_PLOT_PARAMS plotOpt = aPlotOpt;
172 int soldermask_min_thickness = aBoard->GetDesignSettings().m_SolderMaskMinWidth;
173
174 // Set a default color and the text mode for this layer
175 aPlotter->SetColor( BLACK );
176 aPlotter->SetTextMode( aPlotOpt.GetTextMode() );
177
178 // Specify that the contents of the "Edges Pcb" layer are to be plotted in addition to the
179 // contents of the currently specified layer.
180 LSET layer_mask( { aLayer } );
181
182 if( IsCopperLayer( aLayer ) )
183 {
184 // Skip NPTH pads on copper layers ( only if hole size == pad size ):
185 // Drill mark will be plotted if drill mark is SMALL_DRILL_SHAPE or FULL_DRILL_SHAPE
186 if( plotOpt.GetFormat() == PLOT_FORMAT::DXF )
187 plotOpt.SetDXFPlotPolygonMode( true );
188 else
189 plotOpt.SetSkipPlotNPTH_Pads( true );
190
191 plotLayer( layer_mask, plotOpt );
192 }
193 else
194 {
195 switch( aLayer )
196 {
197 case B_Mask:
198 case F_Mask:
199 // Disable plot pad holes
201
202 // Use outline mode for DXF
203 plotOpt.SetDXFPlotPolygonMode( true );
204
205 // Plot solder mask:
206 if( soldermask_min_thickness == 0 )
207 {
208 plotLayer( layer_mask, plotOpt );
209 }
210 else
211 {
212 PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt,
213 soldermask_min_thickness );
214 }
215
216 break;
217
218 case B_Adhes:
219 case F_Adhes:
220 case B_Paste:
221 case F_Paste:
222 // Disable plot pad holes
224
225 // Use outline mode for DXF
226 plotOpt.SetDXFPlotPolygonMode( true );
227
228 plotLayer( layer_mask, plotOpt );
229
230 break;
231
232 case F_SilkS:
233 case B_SilkS:
234 plotLayer( layer_mask, plotOpt );
235
236 // Gerber: Subtract soldermask from silkscreen if enabled
237 if( aPlotter->GetPlotterType() == PLOT_FORMAT::GERBER
238 && plotOpt.GetSubtractMaskFromSilk() )
239 {
240 if( aLayer == F_SilkS )
241 layer_mask = LSET( { F_Mask } );
242 else
243 layer_mask = LSET( { B_Mask } );
244
245 // Create the mask to subtract by creating a negative layer polarity
246 aPlotter->SetLayerPolarity( false );
247
248 // Disable plot pad holes
250
251 // Plot the mask
252 PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
253
254 // Disable the negative polarity
255 aPlotter->SetLayerPolarity( true );
256 }
257
258 break;
259
260 case Dwgs_User:
261 case Cmts_User:
262 case Eco1_User:
263 case Eco2_User:
264 case Edge_Cuts:
265 case Margin:
266 case F_CrtYd:
267 case B_CrtYd:
268 case F_Fab:
269 case B_Fab:
270 default:
271 plotLayer( layer_mask, plotOpt );
272 break;
273 }
274 }
275}
276
277
281void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
282 const PCB_PLOT_PARAMS& aPlotOpt )
283{
284 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
285 int maxError = aBoard->GetDesignSettings().m_MaxError;
286
287 itemplotter.SetLayerSet( aLayerMask );
288
289 OUTLINE_MODE plotMode = aPlotOpt.GetPlotMode();
290 bool onCopperLayer = ( LSET::AllCuMask() & aLayerMask ).any();
291 bool onSolderMaskLayer = ( LSET( { F_Mask, B_Mask } ) & aLayerMask ).any();
292 bool onSolderPasteLayer = ( LSET( { F_Paste, B_Paste } ) & aLayerMask ).any();
293 bool onFrontFab = ( LSET( { F_Fab } ) & aLayerMask ).any();
294 bool onBackFab = ( LSET( { B_Fab } ) & aLayerMask ).any();
295 bool sketchPads = ( onFrontFab || onBackFab ) && aPlotOpt.GetSketchPadsOnFabLayers();
296
297 // Plot edge layer and graphic items
298 for( const BOARD_ITEM* item : aBoard->Drawings() )
299 itemplotter.PlotBoardGraphicItem( item );
300
301 // Draw footprint texts:
302 for( const FOOTPRINT* footprint : aBoard->Footprints() )
303 itemplotter.PlotFootprintTextItems( footprint );
304
305 // Draw footprint other graphic items:
306 for( const FOOTPRINT* footprint : aBoard->Footprints() )
307 itemplotter.PlotFootprintGraphicItems( footprint );
308
309 // Plot footprint pads
310 for( FOOTPRINT* footprint : aBoard->Footprints() )
311 {
312 aPlotter->StartBlock( nullptr );
313
314 for( PAD* pad : footprint->Pads() )
315 {
316 OUTLINE_MODE padPlotMode = plotMode;
317
318 if( !( pad->GetLayerSet() & aLayerMask ).any() )
319 {
320 if( sketchPads &&
321 ( ( onFrontFab && pad->GetLayerSet().Contains( F_Cu ) ) ||
322 ( onBackFab && pad->GetLayerSet().Contains( B_Cu ) ) ) )
323 {
324 padPlotMode = SKETCH;
325 }
326 else
327 {
328 continue;
329 }
330 }
331
332 if( onCopperLayer && !pad->IsOnCopperLayer() )
333 continue;
334
336 if( onCopperLayer && !pad->FlashLayer( aLayerMask ) )
337 continue;
338
339 // TODO(JE) padstacks - different behavior for single layer or multilayer
340
342
343 // If we're plotting a single layer, the color for that layer can be used directly.
344 if( aLayerMask.count() == 1 )
345 {
346 color = aPlotOpt.ColorSettings()->GetColor( aLayerMask.Seq()[0] );
347 }
348 else
349 {
350 if( ( pad->GetLayerSet() & aLayerMask )[B_Cu] )
351 color = aPlotOpt.ColorSettings()->GetColor( B_Cu );
352
353 if( ( pad->GetLayerSet() & aLayerMask )[F_Cu] )
354 color = color.LegacyMix( aPlotOpt.ColorSettings()->GetColor( F_Cu ) );
355
356 if( sketchPads && aLayerMask[F_Fab] )
357 color = aPlotOpt.ColorSettings()->GetColor( F_Fab );
358 else if( sketchPads && aLayerMask[B_Fab] )
359 color = aPlotOpt.ColorSettings()->GetColor( B_Fab );
360 }
361
362 if( sketchPads &&
363 ( ( onFrontFab && pad->GetLayerSet().Contains( F_Cu ) ) ||
364 ( onBackFab && pad->GetLayerSet().Contains( B_Cu ) ) ) )
365 {
366 if( aPlotOpt.GetPlotPadNumbers() )
367 itemplotter.PlotPadNumber( pad, color );
368 }
369
370 auto plotPadLayer =
371 [&]( PCB_LAYER_ID aLayer )
372 {
373 VECTOR2I margin;
374 int width_adj = 0;
375
376 if( onCopperLayer )
377 width_adj = itemplotter.getFineWidthAdj();
378
379 if( onSolderMaskLayer )
380 margin.x = margin.y = pad->GetSolderMaskExpansion( aLayer );
381
382 if( onSolderPasteLayer )
383 margin = pad->GetSolderPasteMargin( aLayer );
384
385 // not all shapes can have a different margin for x and y axis
386 // in fact only oval and rect shapes can have different values.
387 // Round shape have always the same x,y margin
388 // so define a unique value for other shapes that do not support different values
389 int mask_clearance = margin.x;
390
391 // Now offset the pad size by margin + width_adj
392 VECTOR2I padPlotsSize =
393 pad->GetSize( aLayer ) + margin * 2 + VECTOR2I( width_adj, width_adj );
394
395 // Store these parameters that can be modified to plot inflated/deflated pads shape
396 PAD_SHAPE padShape = pad->GetShape( aLayer );
397 VECTOR2I padSize = pad->GetSize( aLayer );
398 VECTOR2I padDelta = pad->GetDelta( aLayer ); // has meaning only for trapezoidal pads
399 // CornerRadius and CornerRadiusRatio can be modified
400 // the radius is built from the ratio, so saving/restoring the ratio is enough
401 double padCornerRadiusRatio = pad->GetRoundRectRadiusRatio( aLayer );
402
403 // Don't draw a 0 sized pad.
404 // Note: a custom pad can have its pad anchor with size = 0
405 if( padShape != PAD_SHAPE::CUSTOM
406 && ( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 ) )
407 {
408 return;
409 }
410
411 switch( padShape )
412 {
414 case PAD_SHAPE::OVAL:
415 pad->SetSize( aLayer, padPlotsSize );
416
417 if( aPlotOpt.GetSkipPlotNPTH_Pads() &&
419 ( pad->GetSize(aLayer ) == pad->GetDrillSize() ) &&
420 ( pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
421 {
422 break;
423 }
424
425 itemplotter.PlotPad( pad, aLayer, color, padPlotMode );
426 break;
427
429 pad->SetSize( aLayer, padPlotsSize );
430
431 if( mask_clearance > 0 )
432 {
433 pad->SetShape( aLayer, PAD_SHAPE::ROUNDRECT );
434 pad->SetRoundRectCornerRadius( aLayer, mask_clearance );
435 }
436
437 itemplotter.PlotPad( pad, aLayer, color, padPlotMode );
438 break;
439
441 // inflate/deflate a trapezoid is a bit complex.
442 // so if the margin is not null, build a similar polygonal pad shape,
443 // and inflate/deflate the polygonal shape
444 // because inflating/deflating using different values for y and y
445 // we are using only margin.x as inflate/deflate value
446 if( mask_clearance == 0 )
447 {
448 itemplotter.PlotPad( pad, aLayer, color, padPlotMode );
449 }
450 else
451 {
452 PAD dummy( *pad );
453 dummy.SetAnchorPadShape( aLayer, PAD_SHAPE::CIRCLE );
454 dummy.SetShape( aLayer, PAD_SHAPE::CUSTOM );
455 SHAPE_POLY_SET outline;
456 outline.NewOutline();
457 int dx = padSize.x / 2;
458 int dy = padSize.y / 2;
459 int ddx = padDelta.x / 2;
460 int ddy = padDelta.y / 2;
461
462 outline.Append( -dx - ddy, dy + ddx );
463 outline.Append( dx + ddy, dy - ddx );
464 outline.Append( dx - ddy, -dy + ddx );
465 outline.Append( -dx + ddy, -dy - ddx );
466
467 // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
468 // which can create bad shapes if margin.x is < 0
469 outline.InflateWithLinkedHoles( mask_clearance,
472 dummy.DeletePrimitivesList();
473 dummy.AddPrimitivePoly( aLayer, outline, 0, true );
474
475 // Be sure the anchor pad is not bigger than the deflated shape because this
476 // anchor will be added to the pad shape when plotting the pad. So now the
477 // polygonal shape is built, we can clamp the anchor size
478 dummy.SetSize( aLayer, VECTOR2I( 0, 0 ) );
479
480 itemplotter.PlotPad( &dummy, aLayer, color, padPlotMode );
481 }
482
483 break;
484
486 {
487 // rounding is stored as a percent, but we have to update this ratio
488 // to force recalculation of other values after size changing (we do not
489 // really change the rounding percent value)
490 double radius_ratio = pad->GetRoundRectRadiusRatio( aLayer );
491 pad->SetSize( aLayer, padPlotsSize );
492 pad->SetRoundRectRadiusRatio( aLayer, radius_ratio );
493
494 itemplotter.PlotPad( pad, aLayer, color, padPlotMode );
495 break;
496 }
497
499 if( mask_clearance == 0 )
500 {
501 // the size can be slightly inflated by width_adj (PS/PDF only)
502 pad->SetSize( aLayer, padPlotsSize );
503 itemplotter.PlotPad( pad, aLayer, color, padPlotMode );
504 }
505 else
506 {
507 // Due to the polygonal shape of a CHAMFERED_RECT pad, the best way is to
508 // convert the pad shape to a full polygon, inflate/deflate the polygon
509 // and use a dummy CUSTOM pad to plot the final shape.
510 PAD dummy( *pad );
511 // Build the dummy pad outline with coordinates relative to the pad position
512 // pad offset and orientation 0. The actual pos, offset and rotation will be
513 // taken in account later by the plot function
514 dummy.SetPosition( VECTOR2I( 0, 0 ) );
515 dummy.SetOffset( aLayer, VECTOR2I( 0, 0 ) );
516 dummy.SetOrientation( ANGLE_0 );
517 SHAPE_POLY_SET outline;
518 dummy.TransformShapeToPolygon( outline, UNDEFINED_LAYER, 0, maxError,
519 ERROR_INSIDE );
520 outline.InflateWithLinkedHoles( mask_clearance,
523
524 // Initialize the dummy pad shape:
525 dummy.SetAnchorPadShape( aLayer, PAD_SHAPE::CIRCLE );
526 dummy.SetShape( aLayer, PAD_SHAPE::CUSTOM );
527 dummy.DeletePrimitivesList();
528 dummy.AddPrimitivePoly( aLayer, outline, 0, true );
529
530 // Be sure the anchor pad is not bigger than the deflated shape because this
531 // anchor will be added to the pad shape when plotting the pad.
532 // So we set the anchor size to 0
533 dummy.SetSize( aLayer, VECTOR2I( 0, 0 ) );
534 // Restore pad position and offset
535 dummy.SetPosition( pad->GetPosition() );
536 dummy.SetOffset( aLayer, pad->GetOffset( aLayer ) );
537 dummy.SetOrientation( pad->GetOrientation() );
538
539 itemplotter.PlotPad( &dummy, aLayer, color, padPlotMode );
540 }
541
542 break;
543
545 {
546 // inflate/deflate a custom shape is a bit complex.
547 // so build a similar pad shape, and inflate/deflate the polygonal shape
548 PAD dummy( *pad );
549 dummy.SetParentGroup( nullptr );
550
551 SHAPE_POLY_SET shape;
552 pad->MergePrimitivesAsPolygon( aLayer, &shape );
553
554 // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
555 // which can create bad shapes if margin.x is < 0
556 shape.InflateWithLinkedHoles( mask_clearance,
559 dummy.DeletePrimitivesList();
560 dummy.AddPrimitivePoly( aLayer, shape, 0, true );
561
562 // Be sure the anchor pad is not bigger than the deflated shape because this
563 // anchor will be added to the pad shape when plotting the pad. So now the
564 // polygonal shape is built, we can clamp the anchor size
565 if( mask_clearance < 0 ) // we expect margin.x = margin.y for custom pads
566 dummy.SetSize( aLayer, VECTOR2I( std::max( 0, padPlotsSize.x ),
567 std::max( 0, padPlotsSize.y ) ) );
568
569 itemplotter.PlotPad( &dummy, aLayer, color, padPlotMode );
570 break;
571 }
572 }
573
574 // Restore the pad parameters modified by the plot code
575 pad->SetSize( aLayer, padSize );
576 pad->SetDelta( aLayer, padDelta );
577 pad->SetShape( aLayer, padShape );
578 pad->SetRoundRectRadiusRatio( aLayer, padCornerRadiusRatio );
579 };
580
581 for( PCB_LAYER_ID layer : aLayerMask.SeqStackupForPlotting() )
582 plotPadLayer( layer );
583 }
584
585 if( footprint->IsDNP()
586 && !itemplotter.GetHideDNPFPsOnFabLayers()
587 && itemplotter.GetCrossoutDNPFPsOnFabLayers()
588 && ( onFrontFab || onBackFab ) )
589 {
590 BOX2I rect = footprint->GetBoundingHull().BBox();
591 int width = aBoard->GetDesignSettings().m_LineThickness[ LAYER_CLASS_FAB ];
592
593 aPlotter->ThickSegment( rect.GetOrigin(), rect.GetEnd(), width, FILLED, nullptr );
594 aPlotter->ThickSegment( VECTOR2I( rect.GetLeft(), rect.GetBottom() ),
595 VECTOR2I( rect.GetRight(), rect.GetTop() ),
596 width, FILLED, nullptr );
597 }
598
599 aPlotter->EndBlock( nullptr );
600 }
601
602 // Plot vias on copper layers, and if aPlotOpt.GetPlotViaOnMaskLayer() is true,
603
604 GBR_METADATA gbr_metadata;
605
606 if( onCopperLayer )
607 {
610 }
611
612 aPlotter->StartBlock( nullptr );
613
614 for( const PCB_TRACK* track : aBoard->Tracks() )
615 {
616 if( track->Type() != PCB_VIA_T )
617 continue;
618
619 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
620
621 // vias are not plotted if not on selected layer
622 LSET via_mask_layer = via->GetLayerSet();
623
624 if( !( via_mask_layer & aLayerMask ).any() )
625 continue;
626
627 int via_margin = 0;
628 double width_adj = 0;
629
630 // TODO(JE) padstacks - separate top/bottom margin
631 if( onSolderMaskLayer )
632 via_margin = via->GetSolderMaskExpansion();
633
634 if( ( aLayerMask & LSET::AllCuMask() ).any() )
635 width_adj = itemplotter.getFineWidthAdj();
636
638 if( onCopperLayer && !via->FlashLayer( aLayerMask ) )
639 continue;
640
641 int diameter = 0;
642
643 for( PCB_LAYER_ID layer : LSET( aLayerMask & LSET::AllCuMask() ).Seq() )
644 diameter = std::max( diameter, via->GetWidth( layer ) );
645
646 diameter += 2 * via_margin + width_adj;
647
648 // Don't draw a null size item :
649 if( diameter <= 0 )
650 continue;
651
652 // Some vias can be not connected (no net).
653 // Set the m_NotInNet for these vias to force a empty net name in gerber file
654 gbr_metadata.m_NetlistMetadata.m_NotInNet = via->GetNetname().IsEmpty();
655
656 gbr_metadata.SetNetName( via->GetNetname() );
657
658 COLOR4D color = aPlotOpt.ColorSettings()->GetColor(
659 LAYER_VIAS + static_cast<int>( via->GetViaType() ) );
660
661 // Set plot color (change WHITE to LIGHTGRAY because the white items are not seen on a
662 // white paper or screen
663 aPlotter->SetColor( color != WHITE ? color : LIGHTGRAY );
664 aPlotter->FlashPadCircle( via->GetStart(), diameter, plotMode, &gbr_metadata );
665 }
666
667 aPlotter->EndBlock( nullptr );
668 aPlotter->StartBlock( nullptr );
669
670 if( onCopperLayer )
671 {
674 }
675 else
676 {
677 // Reset attributes if non-copper (soldermask) layer
680 }
681
682 // Plot tracks (not vias) :
683 for( const PCB_TRACK* track : aBoard->Tracks() )
684 {
685 if( track->Type() == PCB_VIA_T )
686 continue;
687
688 if( !( aLayerMask & track->GetLayerSet() ).any() )
689 continue;
690
691 // Some track segments can be not connected (no net).
692 // Set the m_NotInNet for these segments to force a empty net name in gerber file
693 gbr_metadata.m_NetlistMetadata.m_NotInNet = track->GetNetname().IsEmpty();
694
695 gbr_metadata.SetNetName( track->GetNetname() );
696
697 int margin = 0;
698
699 if( onSolderMaskLayer )
700 margin = track->GetSolderMaskExpansion();
701
702 int width = track->GetWidth() + 2 * margin + itemplotter.getFineWidthAdj();
703
704 aPlotter->SetColor( itemplotter.getColor( track->GetLayer() ) );
705
706 if( track->Type() == PCB_ARC_T )
707 {
708 const PCB_ARC* arc = static_cast<const PCB_ARC*>( track );
709
710 // Too small arcs cannot be really handled: arc center (and arc radius)
711 // cannot be safely computed
712 if( !arc->IsDegenerated( 10 /* in IU */ ) )
713 {
714 aPlotter->ThickArc( arc->GetCenter(), arc->GetArcAngleStart(), arc->GetAngle(),
715 arc->GetRadius(), width, plotMode, &gbr_metadata );
716 }
717 else
718 {
719 // Approximate this very small arc by a segment.
720 aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode,
721 &gbr_metadata );
722 }
723 }
724 else
725 {
726 aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode,
727 &gbr_metadata );
728 }
729 }
730
731 aPlotter->EndBlock( nullptr );
732
733 // Plot filled ares
734 aPlotter->StartBlock( nullptr );
735
736 NETINFO_ITEM nonet( aBoard );
737
738 for( const ZONE* zone : aBoard->Zones() )
739 {
740 if( zone->GetIsRuleArea() )
741 continue;
742
743 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
744 {
745 if( !aLayerMask[layer] )
746 continue;
747
748 SHAPE_POLY_SET mainArea = zone->GetFilledPolysList( layer )->CloneDropTriangulation();
749 SHAPE_POLY_SET islands;
750
751 for( int i = mainArea.OutlineCount() - 1; i >= 0; i-- )
752 {
753 if( zone->IsIsland( layer, i ) )
754 {
755 islands.AddOutline( mainArea.CPolygon( i )[0] );
756 mainArea.DeletePolygon( i );
757 }
758 }
759
760 itemplotter.PlotZone( zone, layer, mainArea );
761
762 if( !islands.IsEmpty() )
763 {
764 ZONE dummy( *zone );
765 dummy.SetNet( &nonet );
766 itemplotter.PlotZone( &dummy, layer, islands );
767 }
768 }
769 }
770
771 aPlotter->EndBlock( nullptr );
772
773 // Adding drill marks, if required and if the plotter is able to plot them:
775 itemplotter.PlotDrillMarks();
776}
777
778
782void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
783 const PCB_PLOT_PARAMS& aPlotOpt )
784{
785 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
786 itemplotter.SetLayerSet( aLayerMask );
787
788 SHAPE_POLY_SET outlines;
789
790 for( PCB_LAYER_ID layer : aLayerMask.Seq( aLayerMask.SeqStackupForPlotting() ) )
791 {
792 outlines.RemoveAllContours();
793 aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines );
794
796
797 // Plot outlines
798 std::vector<VECTOR2I> cornerList;
799
800 // Now we have one or more basic polygons: plot each polygon
801 for( int ii = 0; ii < outlines.OutlineCount(); ii++ )
802 {
803 for( int kk = 0; kk <= outlines.HoleCount(ii); kk++ )
804 {
805 cornerList.clear();
806 const SHAPE_LINE_CHAIN& path = ( kk == 0 ) ? outlines.COutline( ii )
807 : outlines.CHole( ii, kk - 1 );
808
809 aPlotter->PlotPoly( path, FILL_T::NO_FILL );
810 }
811 }
812
813 // Plot pad holes
815 {
816 int smallDrill = ( aPlotOpt.GetDrillMarksType() == DRILL_MARKS::SMALL_DRILL_SHAPE )
818 : INT_MAX;
819
820 for( FOOTPRINT* footprint : aBoard->Footprints() )
821 {
822 for( PAD* pad : footprint->Pads() )
823 {
824 if( pad->HasHole() )
825 {
826 std::shared_ptr<SHAPE_SEGMENT> slot = pad->GetEffectiveHoleShape();
827
828 if( slot->GetSeg().A == slot->GetSeg().B ) // circular hole
829 {
830 int drill = std::min( smallDrill, slot->GetWidth() );
831 aPlotter->Circle( pad->GetPosition(), drill, FILL_T::NO_FILL );
832 }
833 else
834 {
835 // Note: small drill marks have no significance when applied to slots
836 aPlotter->ThickSegment( slot->GetSeg().A, slot->GetSeg().B,
837 slot->GetWidth(), SKETCH, nullptr );
838 }
839 }
840 }
841 }
842 }
843
844 // Plot vias holes
845 for( PCB_TRACK* track : aBoard->Tracks() )
846 {
847 if( track->Type() != PCB_VIA_T )
848 continue;
849
850 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
851
852 if( via->GetLayerSet().Contains( layer ) ) // via holes can be not through holes
853 aPlotter->Circle( via->GetPosition(), via->GetDrillValue(), FILL_T::NO_FILL );
854 }
855 }
856}
857
858
876void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
877 const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness )
878{
879 int maxError = aBoard->GetDesignSettings().m_MaxError;
880 PCB_LAYER_ID layer = aLayerMask[B_Mask] ? B_Mask : F_Mask;
881 SHAPE_POLY_SET buffer;
882 SHAPE_POLY_SET* boardOutline = nullptr;
883
884 if( aBoard->GetBoardPolygonOutlines( buffer ) )
885 boardOutline = &buffer;
886
887 // We remove 1nm as we expand both sides of the shapes, so allowing for a strictly greater
888 // than or equal comparison in the shape separation (boolean add)
889 int inflate = aMinThickness / 2 - 1;
890
891 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
892 itemplotter.SetLayerSet( aLayerMask );
893
894 // Build polygons for each pad shape. The size of the shape on solder mask should be size
895 // of pad + clearance around the pad, where clearance = solder mask clearance + extra margin.
896 // Extra margin is half the min width for solder mask, which is used to merge too-close shapes
897 // (distance < aMinThickness), and will be removed when creating the actual shapes.
898
899 // Will contain shapes inflated by inflate value that will be merged and deflated by inflate
900 // value to build final polygons
901 SHAPE_POLY_SET areas;
902
903 // Will contain exact shapes of all items on solder mask
904 SHAPE_POLY_SET initialPolys;
905
906 auto plotFPTextItem =
907 [&]( const PCB_TEXT& aText )
908 {
909 if( !itemplotter.GetPlotFPText() )
910 return;
911
912 if( !aText.IsVisible() && !itemplotter.GetPlotInvisibleText() )
913 return;
914
915 if( aText.GetText() == wxT( "${REFERENCE}" ) && !itemplotter.GetPlotReference() )
916 return;
917
918 if( aText.GetText() == wxT( "${VALUE}" ) && !itemplotter.GetPlotValue() )
919 return;
920
921 // add shapes with their exact mask layer size in initialPolys
922 aText.TransformTextToPolySet( initialPolys, 0, maxError, ERROR_OUTSIDE );
923
924 // add shapes inflated by aMinThickness/2 in areas
925 aText.TransformTextToPolySet( areas, inflate, maxError, ERROR_OUTSIDE );
926 };
927
928 // Generate polygons with arcs inside the shape or exact shape to minimize shape changes
929 // created by arc to segment size correction.
931 {
932 // Plot footprint pads and graphics
933 for( const FOOTPRINT* footprint : aBoard->Footprints() )
934 {
935 // add shapes with their exact mask layer size in initialPolys
936 footprint->TransformPadsToPolySet( initialPolys, layer, 0, maxError, ERROR_OUTSIDE );
937 // add shapes inflated by aMinThickness/2 in areas
938 footprint->TransformPadsToPolySet( areas, layer, inflate, maxError, ERROR_OUTSIDE );
939
940 for( const PCB_FIELD* field : footprint->Fields() )
941 {
942 if( field->IsReference() && !itemplotter.GetPlotReference() )
943 continue;
944
945 if( field->IsValue() && !itemplotter.GetPlotValue() )
946 continue;
947
948 if( field->IsOnLayer( layer ) )
949 plotFPTextItem( static_cast<const PCB_TEXT&>( *field ) );
950 }
951
952 for( const BOARD_ITEM* item : footprint->GraphicalItems() )
953 {
954 if( item->IsOnLayer( layer ) )
955 {
956 if( item->Type() == PCB_TEXT_T )
957 {
958 plotFPTextItem( static_cast<const PCB_TEXT&>( *item ) );
959 }
960 else
961 {
962 // add shapes with their exact mask layer size in initialPolys
963 item->TransformShapeToPolygon( initialPolys, layer, 0, maxError,
965
966 // add shapes inflated by aMinThickness/2 in areas
967 item->TransformShapeToPolygon( areas, layer, inflate, maxError,
969 }
970 }
971 }
972 }
973
974 // Plot (untented) vias
975 for( const PCB_TRACK* track : aBoard->Tracks() )
976 {
977 if( track->Type() != PCB_VIA_T )
978 continue;
979
980 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
981
982 // Note: IsOnLayer() checks relevant mask layers of untented vias
983 if( !via->IsOnLayer( layer ) )
984 continue;
985
986 int clearance = via->GetSolderMaskExpansion();
987
988 // add shapes with their exact mask layer size in initialPolys
989 via->TransformShapeToPolygon( initialPolys, layer, clearance, maxError, ERROR_OUTSIDE );
990
991 // add shapes inflated by aMinThickness/2 in areas
992 clearance += inflate;
993 via->TransformShapeToPolygon( areas, layer, clearance, maxError, ERROR_OUTSIDE );
994 }
995
996 // Add filled zone areas.
997#if 0 // Set to 1 if a solder mask expansion must be applied to zones on solder mask
998 int zone_margin = aBoard->GetDesignSettings().m_SolderMaskExpansion;
999#else
1000 int zone_margin = 0;
1001#endif
1002
1003 for( const BOARD_ITEM* item : aBoard->Drawings() )
1004 {
1005 if( item->IsOnLayer( layer ) )
1006 {
1007 if( item->Type() == PCB_TEXT_T )
1008 {
1009 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
1010
1011 // add shapes with their exact mask layer size in initialPolys
1012 text->TransformTextToPolySet( initialPolys, 0, maxError, ERROR_OUTSIDE );
1013
1014 // add shapes inflated by aMinThickness/2 in areas
1015 text->TransformTextToPolySet( areas, inflate, maxError, ERROR_OUTSIDE );
1016 }
1017 else
1018 {
1019 // add shapes with their exact mask layer size in initialPolys
1020 item->TransformShapeToPolygon( initialPolys, layer, 0, maxError,
1021 ERROR_OUTSIDE );
1022
1023 // add shapes inflated by aMinThickness/2 in areas
1024 item->TransformShapeToPolygon( areas, layer, inflate, maxError, ERROR_OUTSIDE );
1025 }
1026 }
1027 }
1028
1029 for( ZONE* zone : aBoard->Zones() )
1030 {
1031 if( zone->GetIsRuleArea() )
1032 continue;
1033
1034 if( !zone->IsOnLayer( layer ) )
1035 continue;
1036
1037 // add shapes inflated by aMinThickness/2 in areas
1038 zone->TransformSmoothedOutlineToPolygon( areas, inflate + zone_margin, maxError,
1039 ERROR_OUTSIDE, boardOutline );
1040
1041 // add shapes with their exact mask layer size in initialPolys
1042 zone->TransformSmoothedOutlineToPolygon( initialPolys, zone_margin, maxError,
1043 ERROR_OUTSIDE, boardOutline );
1044 }
1045 }
1046
1047 // Merge all polygons: After deflating, not merged (not overlapping) polygons will have the
1048 // initial shape (with perhaps small changes due to deflating transform)
1050 areas.Deflate( inflate, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
1051
1052 // To avoid a lot of code, use a ZONE to handle and plot polygons, because our polygons look
1053 // exactly like filled areas in zones.
1054 // Note, also this code is not optimized: it creates a lot of copy/duplicate data.
1055 // However it is not complex, and fast enough for plot purposes (copy/convert data is only a
1056 // very small calculation time for these calculations).
1057 ZONE zone( aBoard );
1058 zone.SetMinThickness( 0 ); // trace polygons only
1059 zone.SetLayer( layer );
1060
1061 // Combine the current areas to initial areas. This is mandatory because inflate/deflate
1062 // transform is not perfect, and we want the initial areas perfectly kept
1063 areas.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST );
1065
1066 itemplotter.PlotZone( &zone, layer, areas );
1067}
1068
1069
1076static void initializePlotter( PLOTTER* aPlotter, const BOARD* aBoard,
1077 const PCB_PLOT_PARAMS* aPlotOpts )
1078{
1079 PAGE_INFO pageA4( wxT( "A4" ) );
1080 const PAGE_INFO& pageInfo = aBoard->GetPageSettings();
1081 const PAGE_INFO* sheet_info;
1082 double paperscale; // Page-to-paper ratio
1083 VECTOR2I paperSizeIU;
1084 VECTOR2I pageSizeIU( pageInfo.GetSizeIU( pcbIUScale.IU_PER_MILS ) );
1085 bool autocenter = false;
1086
1087 // Special options: to fit the sheet to an A4 sheet replace the paper size. However there
1088 // is a difference between the autoscale and the a4paper option:
1089 // - Autoscale fits the board to the paper size
1090 // - A4paper fits the original paper size to an A4 sheet
1091 // - Both of them fit the board to an A4 sheet
1092 if( aPlotOpts->GetA4Output() )
1093 {
1094 sheet_info = &pageA4;
1095 paperSizeIU = pageA4.GetSizeIU( pcbIUScale.IU_PER_MILS );
1096 paperscale = (double) paperSizeIU.x / pageSizeIU.x;
1097 autocenter = true;
1098 }
1099 else
1100 {
1101 sheet_info = &pageInfo;
1102 paperSizeIU = pageSizeIU;
1103 paperscale = 1;
1104
1105 // Need autocentering only if scale is not 1:1
1106 autocenter = (aPlotOpts->GetScale() != 1.0);
1107 }
1108
1109 BOX2I bbox = aBoard->ComputeBoundingBox( false );
1110 VECTOR2I boardCenter = bbox.Centre();
1111 VECTOR2I boardSize = bbox.GetSize();
1112
1113 double compound_scale;
1114
1115 // Fit to 80% of the page if asked; it could be that the board is empty, in this case
1116 // regress to 1:1 scale
1117 if( aPlotOpts->GetAutoScale() && boardSize.x > 0 && boardSize.y > 0 )
1118 {
1119 double xscale = (paperSizeIU.x * 0.8) / boardSize.x;
1120 double yscale = (paperSizeIU.y * 0.8) / boardSize.y;
1121
1122 compound_scale = std::min( xscale, yscale ) * paperscale;
1123 }
1124 else
1125 {
1126 compound_scale = aPlotOpts->GetScale() * paperscale;
1127 }
1128
1129 // For the plot offset we have to keep in mind the auxiliary origin too: if autoscaling is
1130 // off we check that plot option (i.e. autoscaling overrides auxiliary origin)
1131 VECTOR2I offset( 0, 0);
1132
1133 if( autocenter )
1134 {
1135 offset.x = KiROUND( boardCenter.x - ( paperSizeIU.x / 2.0 ) / compound_scale );
1136 offset.y = KiROUND( boardCenter.y - ( paperSizeIU.y / 2.0 ) / compound_scale );
1137 }
1138 else
1139 {
1140 if( aPlotOpts->GetUseAuxOrigin() )
1141 offset = aBoard->GetDesignSettings().GetAuxOrigin();
1142 }
1143
1144 aPlotter->SetPageSettings( *sheet_info );
1145
1146 aPlotter->SetViewport( offset, pcbIUScale.IU_PER_MILS/10, compound_scale, aPlotOpts->GetMirror() );
1147
1148 // Has meaning only for gerber plotter. Must be called only after SetViewport
1149 aPlotter->SetGerberCoordinatesFormat( aPlotOpts->GetGerberPrecision() );
1150
1151 // Has meaning only for SVG plotter. Must be called only after SetViewport
1152 aPlotter->SetSvgCoordinatesFormat( aPlotOpts->GetSvgPrecision() );
1153
1154 aPlotter->SetCreator( wxT( "PCBNEW" ) );
1155 aPlotter->SetColorMode( !aPlotOpts->GetBlackAndWhite() ); // default is plot in Black and White.
1156 aPlotter->SetTextMode( aPlotOpts->GetTextMode() );
1157}
1158
1159
1163static void FillNegativeKnockout( PLOTTER *aPlotter, const BOX2I &aBbbox )
1164{
1165 const int margin = 5 * pcbIUScale.IU_PER_MM; // Add a 5 mm margin around the board
1166 aPlotter->SetNegative( true );
1167 aPlotter->SetColor( WHITE ); // Which will be plotted as black
1168
1169 BOX2I area = aBbbox;
1170 area.Inflate( margin );
1171 aPlotter->Rect( area.GetOrigin(), area.GetEnd(), FILL_T::FILLED_SHAPE );
1172 aPlotter->SetColor( BLACK );
1173}
1174
1175
1179static void ConfigureHPGLPenSizes( HPGL_PLOTTER *aPlotter, const PCB_PLOT_PARAMS *aPlotOpts )
1180{
1181 // Compute penDiam (the value is given in mils) in pcb units, with plot scale (if Scale is 2,
1182 // penDiam value is always m_HPGLPenDiam so apparent penDiam is actually penDiam / Scale
1183 int penDiam = KiROUND( aPlotOpts->GetHPGLPenDiameter() * pcbIUScale.IU_PER_MILS / aPlotOpts->GetScale() );
1184
1185 // Set HPGL-specific options and start
1186 aPlotter->SetPenSpeed( aPlotOpts->GetHPGLPenSpeed() );
1187 aPlotter->SetPenNumber( aPlotOpts->GetHPGLPenNum() );
1188 aPlotter->SetPenDiameter( penDiam );
1189}
1190
1191
1198PLOTTER* StartPlotBoard( BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer,
1199 const wxString& aLayerName, const wxString& aFullFileName,
1200 const wxString& aSheetName, const wxString& aSheetPath )
1201{
1202 wxCHECK( aBoard && aPlotOpts, nullptr );
1203
1204 // Create the plotter driver and set the few plotter specific options
1205 PLOTTER* plotter = nullptr;
1206
1207 switch( aPlotOpts->GetFormat() )
1208 {
1209 case PLOT_FORMAT::DXF:
1210 DXF_PLOTTER* DXF_plotter;
1211 DXF_plotter = new DXF_PLOTTER();
1212 DXF_plotter->SetUnits( aPlotOpts->GetDXFPlotUnits() );
1213
1214 plotter = DXF_plotter;
1215 break;
1216
1217 case PLOT_FORMAT::POST:
1218 PS_PLOTTER* PS_plotter;
1219 PS_plotter = new PS_PLOTTER();
1220 PS_plotter->SetScaleAdjust( aPlotOpts->GetFineScaleAdjustX(),
1221 aPlotOpts->GetFineScaleAdjustY() );
1222 plotter = PS_plotter;
1223 break;
1224
1225 case PLOT_FORMAT::PDF:
1226 plotter = new PDF_PLOTTER( aBoard->GetProject() );
1227 break;
1228
1229 case PLOT_FORMAT::HPGL:
1230 HPGL_PLOTTER* HPGL_plotter;
1231 HPGL_plotter = new HPGL_PLOTTER();
1232
1233 // HPGL options are a little more convoluted to compute, so they get their own function
1234 ConfigureHPGLPenSizes( HPGL_plotter, aPlotOpts );
1235 plotter = HPGL_plotter;
1236 break;
1237
1239 // For Gerber plotter, a valid board layer must be set, in order to create a valid
1240 // Gerber header, especially the TF.FileFunction and .FilePolarity data
1241 if( aLayer < PCBNEW_LAYER_ID_START || aLayer >= PCB_LAYER_ID_COUNT )
1242 {
1243 wxLogError( wxString::Format(
1244 "Invalid board layer %d, cannot build a valid Gerber file header",
1245 aLayer ) );
1246 }
1247
1248 plotter = new GERBER_PLOTTER();
1249 break;
1250
1251 case PLOT_FORMAT::SVG:
1252 plotter = new SVG_PLOTTER();
1253 break;
1254
1255 default:
1256 wxASSERT( false );
1257 return nullptr;
1258 }
1259
1261 renderSettings->LoadColors( aPlotOpts->ColorSettings() );
1262 renderSettings->SetDefaultPenWidth( pcbIUScale.mmToIU( 0.0212 ) ); // Hairline at 1200dpi
1263 renderSettings->SetLayerName( aLayerName );
1264
1265 plotter->SetRenderSettings( renderSettings );
1266
1267 // Compute the viewport and set the other options
1268
1269 // page layout is not mirrored, so temporarily change mirror option for the page layout
1270 PCB_PLOT_PARAMS plotOpts = *aPlotOpts;
1271
1272 if( plotOpts.GetPlotFrameRef() && plotOpts.GetMirror() )
1273 plotOpts.SetMirror( false );
1274
1275 initializePlotter( plotter, aBoard, &plotOpts );
1276
1277 if( plotter->OpenFile( aFullFileName ) )
1278 {
1279 plotter->ClearHeaderLinesList();
1280
1281 // For the Gerber "file function" attribute, set the layer number
1282 if( plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1283 {
1284 bool useX2mode = plotOpts.GetUseGerberX2format();
1285
1286 GERBER_PLOTTER* gbrplotter = static_cast <GERBER_PLOTTER*> ( plotter );
1287 gbrplotter->DisableApertMacros( plotOpts.GetDisableGerberMacros() );
1288 gbrplotter->UseX2format( useX2mode );
1289 gbrplotter->UseX2NetAttributes( plotOpts.GetIncludeGerberNetlistInfo() );
1290
1291 // Attributes can be added using X2 format or as comment (X1 format)
1292 AddGerberX2Attribute( plotter, aBoard, aLayer, not useX2mode );
1293 }
1294
1295 if( plotter->StartPlot( wxT( "1" ) ) )
1296 {
1297 // Plot the frame reference if requested
1298 if( aPlotOpts->GetPlotFrameRef() )
1299 {
1300 PlotDrawingSheet( plotter, aBoard->GetProject(), aBoard->GetTitleBlock(),
1301 aBoard->GetPageSettings(), &aBoard->GetProperties(), wxT( "1" ),
1302 1, aSheetName, aSheetPath, aBoard->GetFileName(),
1303 renderSettings->GetLayerColor( LAYER_DRAWINGSHEET ) );
1304
1305 if( aPlotOpts->GetMirror() )
1306 initializePlotter( plotter, aBoard, aPlotOpts );
1307 }
1308
1309 // When plotting a negative board: draw a black rectangle (background for plot board
1310 // in white) and switch the current color to WHITE; note the color inversion is actually
1311 // done in the driver (if supported)
1312 if( aPlotOpts->GetNegative() )
1313 {
1314 BOX2I bbox = aBoard->ComputeBoundingBox( false );
1315 FillNegativeKnockout( plotter, bbox );
1316 }
1317
1318 return plotter;
1319 }
1320 }
1321
1322 delete plotter->RenderSettings();
1323 delete plotter;
1324 return nullptr;
1325}
int color
Definition: DXF_plotter.cpp:58
@ ERROR_OUTSIDE
Definition: approximation.h:33
@ ERROR_INSIDE
Definition: approximation.h:34
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
@ LAYER_CLASS_FAB
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
const VECTOR2I & GetAuxOrigin()
int m_LineThickness[LAYER_CLASS_COUNT]
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:290
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:2497
const PAGE_INFO & GetPageSettings() const
Definition: board.h:689
const ZONES & Zones() const
Definition: board.h:335
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:2925
TITLE_BLOCK & GetTitleBlock()
Definition: board.h:695
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1674
const std::map< wxString, wxString > & GetProperties() const
Definition: board.h:362
const FOOTPRINTS & Footprints() const
Definition: board.h:331
const TRACKS & Tracks() const
Definition: board.h:329
const wxString & GetFileName() const
Definition: board.h:327
PROJECT * GetProject() const
Definition: board.h:491
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:895
const DRAWINGS & Drawings() const
Definition: board.h:333
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr const Vec GetEnd() const
Definition: box2.h:212
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr Vec Centre() const
Definition: box2.h:97
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr void Move(const Vec &aMoveVector)
Move the rectangle by the aMoveVector.
Definition: box2.h:138
constexpr const Vec & GetOrigin() const
Definition: box2.h:210
constexpr coord_type GetRight() const
Definition: box2.h:217
constexpr const SizeVec & GetSize() const
Definition: box2.h:206
constexpr coord_type GetTop() const
Definition: box2.h:229
constexpr coord_type GetBottom() const
Definition: box2.h:222
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, PCB_LAYER_ID aLayer, 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
@ GBR_APERTURE_ATTRIB_NONE
uninitialized attribute.
Definition: gbr_metadata.h:93
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)
@ GBR_NETINFO_UNSPECIFIED
idle command (no command)
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:36
LSEQ SeqStackupForPlotting() const
Return the sequence that is typical for a bottom-to-top stack-up.
Definition: lset.cpp:510
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:686
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:420
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:1890
EDA_ANGLE GetArcAngleStart() const
Definition: pcb_track.cpp:1872
double GetRadius() const
Definition: pcb_track.cpp:1855
EDA_ANGLE GetAngle() const
Definition: pcb_track.cpp:1862
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_track.h:312
bool IsReference() const
Definition: pcb_field.h:68
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
Definition: pcb_field.cpp:92
bool IsValue() const
Definition: pcb_field.h:69
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
bool GetHideDNPFPsOnFabLayers() const
void SetSkipPlotNPTH_Pads(bool aSkip)
bool GetMirror() const
DXF_UNITS GetDXFPlotUnits() const
bool GetAutoScale() const
bool GetPlotInvisibleText() const
PLOT_TEXT_MODE GetTextMode() const
bool GetCrossoutDNPFPsOnFabLayers() 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 ThickArc(const EDA_SHAPE &aArcShape, OUTLINE_MODE aTraceMode, void *aData, int aWidth)
Definition: plotter.cpp:597
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:554
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:75
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 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:274
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: zone.cpp:481
@ 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.
static const bool FILLED
Definition: gr_basic.cpp:30
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:218
@ LAYER_VIAS
Meta control for all vias opacity/visibility.
Definition: layer_ids.h:194
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:116
@ B_Adhes
Definition: layer_ids.h:103
@ Edge_Cuts
Definition: layer_ids.h:112
@ Dwgs_User
Definition: layer_ids.h:107
@ F_Paste
Definition: layer_ids.h:104
@ Cmts_User
Definition: layer_ids.h:108
@ F_Adhes
Definition: layer_ids.h:102
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ Eco1_User
Definition: layer_ids.h:109
@ F_Mask
Definition: layer_ids.h:97
@ B_Paste
Definition: layer_ids.h:105
@ F_Fab
Definition: layer_ids.h:119
@ Margin
Definition: layer_ids.h:113
@ F_SilkS
Definition: layer_ids.h:100
@ B_CrtYd
Definition: layer_ids.h:115
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
@ Eco2_User
Definition: layer_ids.h:110
@ B_SilkS
Definition: layer_ids.h:101
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:135
@ F_Cu
Definition: layer_ids.h:64
@ B_Fab
Definition: layer_ids.h:118
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:52
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:360
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
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691