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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, 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>
41#include <plotters/plotter.h>
45#include <pcb_painter.h>
46#include <gbr_metadata.h>
47#include <advanced_config.h>
48
49void GenerateLayerPoly( SHAPE_POLY_SET* aResult, BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
50 bool aPlotFPText, bool aPlotReferences, bool aPlotValues );
51
52
53void PlotLayer( BOARD* aBoard, PLOTTER* aPlotter, const LSET& layerMask,
54 const PCB_PLOT_PARAMS& plotOpts )
55{
56 // PlotLayerOutlines() is designed only for DXF plotters.
57 if( plotOpts.GetFormat() == PLOT_FORMAT::DXF && plotOpts.GetDXFPlotPolygonMode() )
58 PlotLayerOutlines( aBoard, aPlotter, layerMask, plotOpts );
59 else
60 PlotStandardLayer( aBoard, aPlotter, layerMask, plotOpts );
61};
62
63
64void PlotPolySet( BOARD* aBoard, PLOTTER* aPlotter, const PCB_PLOT_PARAMS& aPlotOpt,
65 SHAPE_POLY_SET* aPolySet, PCB_LAYER_ID aLayer )
66{
67 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
68 LSET layers = { aLayer };
69
70 itemplotter.SetLayerSet( layers );
71
72 // To avoid a lot of code, use a ZONE to handle and plot polygons, because our polygons look
73 // exactly like filled areas in zones.
74 // Note, also this code is not optimized: it creates a lot of copy/duplicate data.
75 // However it is not complex, and fast enough for plot purposes (copy/convert data is only a
76 // very small calculation time for these calculations).
77 ZONE zone( aBoard );
78 zone.SetMinThickness( 0 );
79 zone.SetLayer( aLayer );
80
81 aPolySet->Fracture();
82 itemplotter.PlotZone( &zone, aLayer, *aPolySet );
83}
84
85
92void PlotSolderMaskLayer( BOARD* aBoard, PLOTTER* aPlotter, const LSET& aLayerMask,
93 const PCB_PLOT_PARAMS& aPlotOpt )
94{
95 if( aBoard->GetDesignSettings().m_SolderMaskMinWidth == 0 )
96 {
97 PlotLayer( aBoard, aPlotter, aLayerMask, aPlotOpt );
98 return;
99 }
100
101 SHAPE_POLY_SET solderMask;
102 PCB_LAYER_ID layer = aLayerMask[B_Mask] ? B_Mask : F_Mask;
103
104 GenerateLayerPoly( &solderMask, aBoard, aPlotter, layer, aPlotOpt.GetPlotFPText(),
105 aPlotOpt.GetPlotReference(), aPlotOpt.GetPlotValue() );
106
107 PlotPolySet( aBoard, aPlotter, aPlotOpt, &solderMask, layer );
108}
109
110
111void PlotClippedSilkLayer( BOARD* aBoard, PLOTTER* aPlotter, const LSET& aLayerMask,
112 const PCB_PLOT_PARAMS& aPlotOpt )
113{
114 SHAPE_POLY_SET silkscreen, solderMask;
115 PCB_LAYER_ID silkLayer = aLayerMask[F_SilkS] ? F_SilkS : B_SilkS;
116 PCB_LAYER_ID maskLayer = aLayerMask[F_SilkS] ? F_Mask : B_Mask;
117
118 GenerateLayerPoly( &silkscreen, aBoard, aPlotter, silkLayer, aPlotOpt.GetPlotFPText(),
119 aPlotOpt.GetPlotReference(), aPlotOpt.GetPlotValue() );
120 GenerateLayerPoly( &solderMask, aBoard, aPlotter, maskLayer, aPlotOpt.GetPlotFPText(),
121 aPlotOpt.GetPlotReference(), aPlotOpt.GetPlotValue() );
122
123 silkscreen.BooleanSubtract( solderMask );
124 PlotPolySet( aBoard, aPlotter, aPlotOpt, &silkscreen, silkLayer );
125}
126
127
128void PlotBoardLayers( BOARD* aBoard, PLOTTER* aPlotter, const LSEQ& aLayers,
129 const PCB_PLOT_PARAMS& aPlotOptions )
130{
131 if( !aBoard || !aPlotter || aLayers.empty() )
132 return;
133
134 for( PCB_LAYER_ID layer : aLayers )
135 PlotOneBoardLayer( aBoard, aPlotter, layer, aPlotOptions, layer == aLayers[0] );
136
137 // Drill marks are plotted in white to knockout the pad if any layers of the pad are
138 // being plotted, and in black if the pad is not being plotted. For the former, this
139 // must happen after all other layers are plotted.
140 if( aPlotOptions.GetDrillMarksType() != DRILL_MARKS::NO_DRILL_SHAPE )
141 {
142 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOptions );
143 itemplotter.SetLayerSet( aLayers );
144 itemplotter.PlotDrillMarks();
145 }
146}
147
148
149void PlotInteractiveLayer( BOARD* aBoard, PLOTTER* aPlotter, const PCB_PLOT_PARAMS& aPlotOpt )
150{
151 for( const FOOTPRINT* fp : aBoard->Footprints() )
152 {
153 if( fp->GetLayer() == F_Cu && !aPlotOpt.m_PDFFrontFPPropertyPopups )
154 continue;
155
156 if( fp->GetLayer() == B_Cu && !aPlotOpt.m_PDFBackFPPropertyPopups )
157 continue;
158
159 std::vector<wxString> properties;
160
161 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
162 _( "Reference designator" ),
163 fp->Reference().GetShownText( false ) ) );
164
165 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
166 _( "Value" ),
167 fp->Value().GetShownText( false ) ) );
168
169 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
170 _( "Footprint" ),
171 fp->GetFPID().GetUniStringLibItemName() ) );
172
173 for( const PCB_FIELD* field : fp->GetFields() )
174 {
175 wxCHECK2( field, continue );
176
177 if( field->IsReference() || field->IsValue() )
178 continue;
179
180 if( field->GetText().IsEmpty() )
181 continue;
182
183 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
184 field->GetName(),
185 field->GetText() ) );
186 }
187
188 // These 2 properties are not very useful in a plot file (like a PDF)
189#if 0
190 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), _( "Library Description" ),
191 fp->GetLibDescription() ) );
192
193 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), _( "Keywords" ),
194 fp->GetKeywords() ) );
195#endif
196 // Draw items are plotted with a position offset. So we need to move
197 // our boxes (which are not plotted) by the same offset.
198 VECTOR2I offset = -aPlotter->GetPlotOffsetUserUnits();
199
200 // Use a footprint bbox without texts to create the hyperlink area
201 BOX2I bbox = fp->GetBoundingBox( false );
202 bbox.Move( offset );
203 aPlotter->HyperlinkMenu( bbox, properties );
204
205 // Use a footprint bbox with visible texts only to create the bookmark area
206 // which is the area to zoom on ft selection
207 // However the bbox need to be inflated for a better look.
208 bbox = fp->GetBoundingBox( true );
209 bbox.Move( offset );
210 bbox.Inflate( bbox.GetWidth() /2, bbox.GetHeight() /2 );
211 aPlotter->Bookmark( bbox, fp->GetReference(), _( "Footprints" ) );
212 }
213}
214
215
216void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
217 const PCB_PLOT_PARAMS& aPlotOpt, bool isPrimaryLayer )
218{
219 PCB_PLOT_PARAMS plotOpt = aPlotOpt;
220
221 // Set a default color and the text mode for this layer
222 aPlotter->SetColor( BLACK );
223 aPlotter->SetTextMode( aPlotOpt.GetTextMode() );
224
225 // Specify that the contents of the "Edges Pcb" layer are to be plotted in addition to the
226 // contents of the currently specified layer.
227 LSET layer_mask( { aLayer } );
228
229 if( IsCopperLayer( aLayer ) )
230 {
231 // Skip NPTH pads on copper layers ( only if hole size == pad size ):
232 // Drill mark will be plotted if drill mark is SMALL_DRILL_SHAPE or FULL_DRILL_SHAPE
233 if( plotOpt.GetFormat() == PLOT_FORMAT::DXF )
234 plotOpt.SetDXFPlotPolygonMode( true );
235 else
236 plotOpt.SetSkipPlotNPTH_Pads( true );
237
238 PlotLayer( aBoard, aPlotter, layer_mask, plotOpt );
239 }
240 else
241 {
242 switch( aLayer )
243 {
244 case B_Mask:
245 case F_Mask:
246 // Use outline mode for DXF
247 plotOpt.SetDXFPlotPolygonMode( true );
248
249 // Plot solder mask:
250 PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt );
251
252 break;
253
254 case B_Adhes:
255 case F_Adhes:
256 case B_Paste:
257 case F_Paste:
258 // Disable plot pad holes
260
261 // Use outline mode for DXF
262 plotOpt.SetDXFPlotPolygonMode( true );
263
264 PlotLayer( aBoard, aPlotter, layer_mask, plotOpt );
265
266 break;
267
268 case F_SilkS:
269 case B_SilkS:
270 if( plotOpt.GetSubtractMaskFromSilk() )
271 {
272 if( aPlotter->GetPlotterType() == PLOT_FORMAT::GERBER && isPrimaryLayer )
273 {
274 // Use old-school, positive/negative mask plotting which preserves utilization
275 // of Gerber aperture masks. This method can only be used when the given silk
276 // layer is the primary layer as the negative mask will also knockout any other
277 // (non-silk) layers that were plotted before the silk layer.
278
279 PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
280
281 // Create the mask to subtract by creating a negative layer polarity
282 aPlotter->SetLayerPolarity( false );
283
284 // Disable plot pad holes
286
287 // Plot the mask
288 layer_mask = ( aLayer == F_SilkS ) ? LSET( { F_Mask } ) : LSET( { B_Mask } );
289 PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt );
290
291 // Disable the negative polarity
292 aPlotter->SetLayerPolarity( true );
293 }
294 else
295 {
296 PlotClippedSilkLayer( aBoard, aPlotter, layer_mask, plotOpt );
297 }
298
299 break;
300 }
301
302 PlotLayer( aBoard, aPlotter, layer_mask, plotOpt );
303 break;
304
305 case Dwgs_User:
306 case Cmts_User:
307 case Eco1_User:
308 case Eco2_User:
309 case Edge_Cuts:
310 case Margin:
311 case F_CrtYd:
312 case B_CrtYd:
313 case F_Fab:
314 case B_Fab:
315 default:
316 PlotLayer( aBoard, aPlotter, layer_mask, plotOpt );
317 break;
318 }
319 }
320}
321
322
326void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, const LSET& aLayerMask,
327 const PCB_PLOT_PARAMS& aPlotOpt )
328{
329 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
330 int maxError = aBoard->GetDesignSettings().m_MaxError;
331
332 itemplotter.SetLayerSet( aLayerMask );
333
334 bool onCopperLayer = ( LSET::AllCuMask() & aLayerMask ).any();
335 bool onSolderMaskLayer = ( LSET( { F_Mask, B_Mask } ) & aLayerMask ).any();
336 bool onSolderPasteLayer = ( LSET( { F_Paste, B_Paste } ) & aLayerMask ).any();
337 bool onFrontFab = ( LSET( { F_Fab } ) & aLayerMask ).any();
338 bool onBackFab = ( LSET( { B_Fab } ) & aLayerMask ).any();
339 bool sketchPads = ( onFrontFab || onBackFab ) && aPlotOpt.GetSketchPadsOnFabLayers();
340 const wxString variantName = aBoard->GetCurrentVariant();
341
342 // Plot edge layer and graphic items
343 for( const BOARD_ITEM* item : aBoard->Drawings() )
344 itemplotter.PlotBoardGraphicItem( item );
345
346 // Draw footprint texts:
347 for( const FOOTPRINT* footprint : aBoard->Footprints() )
348 itemplotter.PlotFootprintTextItems( footprint );
349
350 // Draw footprint other graphic items:
351 for( const FOOTPRINT* footprint : aBoard->Footprints() )
352 itemplotter.PlotFootprintGraphicItems( footprint );
353
354 // Plot footprint pads
355 for( FOOTPRINT* footprint : aBoard->Footprints() )
356 {
357 const bool dnp = footprint->GetDNPForVariant( variantName );
358
359 aPlotter->StartBlock( nullptr );
360
361 for( PAD* pad : footprint->Pads() )
362 {
363 bool doSketchPads = false;
364
365 if( !( pad->GetLayerSet() & aLayerMask ).any() )
366 {
367 if( sketchPads && ( ( onFrontFab && pad->GetLayerSet().Contains( F_Cu ) )
368 || ( onBackFab && pad->GetLayerSet().Contains( B_Cu ) ) ) )
369 {
370 doSketchPads = true;
371 }
372 else
373 {
374 continue;
375 }
376 }
377
378 if( onCopperLayer && !pad->IsOnCopperLayer() )
379 continue;
380
382 if( onCopperLayer && !pad->FlashLayer( aLayerMask ) )
383 continue;
384
385 // TODO(JE) padstacks - different behavior for single layer or multilayer
386
387 COLOR4D color = COLOR4D::BLACK;
388
389 // If we're plotting a single layer, the color for that layer can be used directly.
390 if( aLayerMask.count() == 1 )
391 {
392 color = aPlotOpt.ColorSettings()->GetColor( aLayerMask.Seq()[0] );
393 }
394 else
395 {
396 if( ( pad->GetLayerSet() & aLayerMask )[B_Cu] )
397 color = aPlotOpt.ColorSettings()->GetColor( B_Cu );
398
399 if( ( pad->GetLayerSet() & aLayerMask )[F_Cu] )
400 color = color.LegacyMix( aPlotOpt.ColorSettings()->GetColor( F_Cu ) );
401
402 if( sketchPads && aLayerMask[F_Fab] )
403 color = aPlotOpt.ColorSettings()->GetColor( F_Fab );
404 else if( sketchPads && aLayerMask[B_Fab] )
405 color = aPlotOpt.ColorSettings()->GetColor( B_Fab );
406 }
407
408 if( sketchPads && ( ( onFrontFab && pad->GetLayerSet().Contains( F_Cu ) )
409 || ( onBackFab && pad->GetLayerSet().Contains( B_Cu ) ) ) )
410 {
411 if( aPlotOpt.GetPlotPadNumbers() )
412 itemplotter.PlotPadNumber( pad, color );
413 }
414
415 auto plotPadLayer =
416 [&]( PCB_LAYER_ID aLayer )
417 {
418 VECTOR2I margin;
419 int width_adj = 0;
420
421 if( onCopperLayer )
422 width_adj = itemplotter.getFineWidthAdj();
423
424 if( onSolderMaskLayer )
425 margin.x = margin.y = pad->GetSolderMaskExpansion( aLayer );
426
427 if( onSolderPasteLayer )
428 margin = pad->GetSolderPasteMargin( aLayer );
429
430 // not all shapes can have a different margin for x and y axis
431 // in fact only oval and rect shapes can have different values.
432 // Round shape have always the same x,y margin
433 // so define a unique value for other shapes that do not support different values
434 int mask_clearance = margin.x;
435 // When clearance is same for x and y pad axis, calculations are more easy
436 bool sameXYClearance = margin.x == margin.y;
437
438 // Now offset the pad size by margin + width_adj
439 VECTOR2I padPlotsSize = pad->GetSize( aLayer ) + margin * 2 + VECTOR2I( width_adj, width_adj );
440
441 // Store these parameters that can be modified to plot inflated/deflated pads shape
442 PAD_SHAPE padShape = pad->GetShape( aLayer );
443 VECTOR2I padSize = pad->GetSize( aLayer );
444 VECTOR2I padDelta = pad->GetDelta( aLayer ); // has meaning only for trapezoidal pads
445 // CornerRadius and CornerRadiusRatio can be modified
446 // the radius is built from the ratio, so saving/restoring the ratio is enough
447 double padCornerRadiusRatio = pad->GetRoundRectRadiusRatio( aLayer );
448
449 // Don't draw a 0 sized pad.
450 // Note: a custom pad can have its pad anchor with size = 0
451 if( padShape != PAD_SHAPE::CUSTOM
452 && ( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 ) )
453 {
454 return;
455 }
456
457 switch( padShape )
458 {
460 case PAD_SHAPE::OVAL:
461 pad->SetSize( aLayer, padPlotsSize );
462
463 if( aPlotOpt.GetSkipPlotNPTH_Pads() &&
465 ( pad->GetSize(aLayer ) == pad->GetDrillSize() ) &&
466 ( pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
467 {
468 break;
469 }
470
471 itemplotter.PlotPad( pad, aLayer, color, doSketchPads );
472 break;
473
475 pad->SetSize( aLayer, padPlotsSize );
476
477 if( mask_clearance > 0 )
478 {
479 pad->SetShape( aLayer, PAD_SHAPE::ROUNDRECT );
480 pad->SetRoundRectCornerRadius( aLayer, mask_clearance );
481 }
482
483 itemplotter.PlotPad( pad, aLayer, color, doSketchPads );
484 break;
485
487 // inflate/deflate a trapezoid is a bit complex.
488 // so if the margin is not null, build a similar polygonal pad shape,
489 // and inflate/deflate the polygonal shape
490 // because inflating/deflating using different values for y and y
491 // we are using only margin.x as inflate/deflate value
492 if( mask_clearance == 0 )
493 {
494 itemplotter.PlotPad( pad, aLayer, color, doSketchPads );
495 }
496 else
497 {
498 PAD dummy( *pad );
499 dummy.SetAnchorPadShape( aLayer, PAD_SHAPE::CIRCLE );
500 dummy.SetShape( aLayer, PAD_SHAPE::CUSTOM );
501 SHAPE_POLY_SET outline;
502 outline.NewOutline();
503 int dx = padSize.x / 2;
504 int dy = padSize.y / 2;
505 int ddx = padDelta.x / 2;
506 int ddy = padDelta.y / 2;
507
508 outline.Append( -dx - ddy, dy + ddx );
509 outline.Append( dx + ddy, dy - ddx );
510 outline.Append( dx - ddy, -dy + ddx );
511 outline.Append( -dx + ddy, -dy - ddx );
512
513 // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
514 // which can create bad shapes if margin.x is < 0
516 maxError );
517 dummy.DeletePrimitivesList();
518 dummy.AddPrimitivePoly( aLayer, outline, 0, true );
519
520 // Be sure the anchor pad is not bigger than the deflated shape because this
521 // anchor will be added to the pad shape when plotting the pad. So now the
522 // polygonal shape is built, we can clamp the anchor size
523 dummy.SetSize( aLayer, VECTOR2I( 0, 0 ) );
524
525 itemplotter.PlotPad( &dummy, aLayer, color, doSketchPads );
526 }
527
528 break;
529
531 {
532 // rounding is stored as a percent, but we have to update this ratio
533 // to force recalculation of other values after size changing (we do not
534 // really change the rounding percent value)
535 double radius_ratio = pad->GetRoundRectRadiusRatio( aLayer );
536 pad->SetSize( aLayer, padPlotsSize );
537 pad->SetRoundRectRadiusRatio( aLayer, radius_ratio );
538
539 itemplotter.PlotPad( pad, aLayer, color, doSketchPads );
540 break;
541 }
542
544 // for smaller/same rect size than initial shape (i.e. mask_clearance <= 0)
545 // use the rect with size set to padPlotsSize. It gives a good shape
546 if( mask_clearance <= 0 )
547 {
548 // the size can be slightly inflated by width_adj (PS/PDF only)
549 pad->SetSize( aLayer, padPlotsSize );
550 itemplotter.PlotPad( pad, aLayer, color, doSketchPads );
551 }
552 else
553 {
554 // Due to the polygonal shape of a CHAMFERED_RECT pad, the best way is to
555 // convert the pad shape to a full polygon and inflate it
556 // and use a dummy CUSTOM pad to plot the final shape.
557 // However one can inflate polygon only if X,Y has same inflate value
558 // if not the case, just use a rectangle having the padPlotsSize new size
559 PAD dummy( *pad );
560 // Build the dummy pad outline with coordinates relative to the pad position
561 // pad offset and orientation 0. The actual pos, offset and rotation will be
562 // taken in account later by the plot function
563 dummy.SetPosition( VECTOR2I( 0, 0 ) );
564 dummy.SetOffset( aLayer, VECTOR2I( 0, 0 ) );
565
566 if( !sameXYClearance )
567 dummy.SetSize( aLayer, padPlotsSize );
568
569 dummy.SetOrientation( ANGLE_0 );
570 SHAPE_POLY_SET outline;
571 dummy.TransformShapeToPolygon( outline, aLayer, 0, maxError, ERROR_INSIDE );
572
573 if( sameXYClearance )
575 maxError );
576
577 // Initialize the dummy pad shape:
578 dummy.SetAnchorPadShape( aLayer, PAD_SHAPE::CIRCLE );
579 dummy.SetShape( aLayer, PAD_SHAPE::CUSTOM );
580 dummy.DeletePrimitivesList();
581 dummy.AddPrimitivePoly( aLayer, outline, 0, true );
582
583 // Be sure the anchor pad is not bigger than the deflated shape because this
584 // anchor will be added to the pad shape when plotting the pad.
585 // So we set the anchor size to 0
586 dummy.SetSize( aLayer, VECTOR2I( 0, 0 ) );
587 // Restore pad position and offset
588 dummy.SetPosition( pad->GetPosition() );
589 dummy.SetOffset( aLayer, pad->GetOffset( aLayer ) );
590 dummy.SetOrientation( pad->GetOrientation() );
591
592 itemplotter.PlotPad( &dummy, aLayer, color, doSketchPads );
593 }
594
595 break;
596
598 {
599 // inflate/deflate a custom shape is a bit complex.
600 // so build a similar pad shape, and inflate/deflate the polygonal shape
601 PAD dummy( *pad );
602 dummy.SetParentGroup( nullptr );
603
604 SHAPE_POLY_SET shape;
605 pad->MergePrimitivesAsPolygon( aLayer, &shape );
606
607 // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
608 // which can create bad shapes if margin.x is < 0
609 shape.InflateWithLinkedHoles( mask_clearance,
611 dummy.DeletePrimitivesList();
612 dummy.AddPrimitivePoly( aLayer, shape, 0, true );
613
614 // Be sure the anchor pad is not bigger than the deflated shape because this
615 // anchor will be added to the pad shape when plotting the pad. So now the
616 // polygonal shape is built, we can clamp the anchor size
617 if( mask_clearance < 0 ) // we expect margin.x = margin.y for custom pads
618 {
619 dummy.SetSize( aLayer, VECTOR2I( std::max( 0, padPlotsSize.x ),
620 std::max( 0, padPlotsSize.y ) ) );
621 }
622
623 itemplotter.PlotPad( &dummy, aLayer, color, doSketchPads );
624 break;
625 }
626 }
627
628 // Restore the pad parameters modified by the plot code
629 pad->SetSize( aLayer, padSize );
630 pad->SetDelta( aLayer, padDelta );
631 pad->SetShape( aLayer, padShape );
632 pad->SetRoundRectRadiusRatio( aLayer, padCornerRadiusRatio );
633 };
634
635 for( PCB_LAYER_ID layer : aLayerMask.SeqStackupForPlotting() )
636 plotPadLayer( layer );
637 }
638
639 if( dnp
640 && !itemplotter.GetHideDNPFPsOnFabLayers()
641 && itemplotter.GetCrossoutDNPFPsOnFabLayers()
642 && ( ( onFrontFab && footprint->GetLayer() == F_Cu )
643 || ( onBackFab && footprint->GetLayer() == B_Cu ) ) )
644 {
645 BOX2I rect;
646 const SHAPE_POLY_SET& courtyard = footprint->GetCourtyard( footprint->GetLayer() );
647
648 if( courtyard.IsEmpty() )
649 rect = footprint->GetEffectiveShape()->BBox();
650 else
651 rect = courtyard.BBox();
652
653 int width = aBoard->GetDesignSettings().m_LineThickness[ LAYER_CLASS_FAB ];
654
655 // Use DNP cross color from color scheme
656 COLOR4D dnpMarkerColor = aPlotOpt.ColorSettings()->GetColor( LAYER_DNP_MARKER );
657 if( dnpMarkerColor != COLOR4D::UNSPECIFIED )
658 aPlotter->SetColor( dnpMarkerColor );
659 else
660 aPlotter->SetColor( aPlotOpt.ColorSettings()->GetColor( onFrontFab ? F_Fab : B_Fab ) );
661
662 aPlotter->ThickSegment( rect.GetOrigin(), rect.GetEnd(), width, nullptr );
663 aPlotter->ThickSegment( VECTOR2I( rect.GetLeft(), rect.GetBottom() ),
664 VECTOR2I( rect.GetRight(), rect.GetTop() ),
665 width, nullptr );
666 }
667
668 aPlotter->EndBlock( nullptr );
669 }
670
671 // Plot vias on copper layers, and if aPlotOpt.GetPlotViaOnMaskLayer() is true,
672
673 GBR_METADATA gbr_metadata;
674
675 if( onCopperLayer )
676 {
679 }
680
681 auto getMetadata =
682 [&]()
683 {
684 if( aPlotter->GetPlotterType() == PLOT_FORMAT::GERBER )
685 return (void*) &gbr_metadata;
686 else if( aPlotter->GetPlotterType() == PLOT_FORMAT::DXF )
687 return (void*) &aPlotOpt;
688 else
689 return (void*) nullptr;
690 };
691
692 aPlotter->StartBlock( nullptr );
693
694 for( const PCB_TRACK* track : aBoard->Tracks() )
695 {
696 if( track->Type() != PCB_VIA_T )
697 continue;
698
699 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
700
701 // vias are not plotted if not on selected layer
702 LSET via_mask_layer = via->GetLayerSet();
703
704 if( !( via_mask_layer & aLayerMask ).any() )
705 continue;
706
707 int via_margin = 0;
708 double width_adj = 0;
709
710 // TODO(JE) padstacks - separate top/bottom margin
711 if( onSolderMaskLayer )
712 via_margin = via->GetSolderMaskExpansion();
713
714 if( ( aLayerMask & LSET::AllCuMask() ).any() )
715 width_adj = itemplotter.getFineWidthAdj();
716
718 if( onCopperLayer && !via->FlashLayer( aLayerMask ) )
719 continue;
720
721 int diameter = 0;
722
723 for( PCB_LAYER_ID layer : aLayerMask )
724 diameter = std::max( diameter, via->GetWidth( layer ) );
725
726 diameter += 2 * via_margin + width_adj;
727
728 // Don't draw a null size item :
729 if( diameter <= 0 )
730 continue;
731
732 // Some vias can be not connected (no net).
733 // Set the m_NotInNet for these vias to force a empty net name in gerber file
734 gbr_metadata.m_NetlistMetadata.m_NotInNet = via->GetNetname().IsEmpty();
735
736 gbr_metadata.SetNetName( via->GetNetname() );
737
738 COLOR4D color;
739
740 // If we're plotting a single layer, the color for that layer can be used directly.
741 if( aLayerMask.count() == 1 )
742 color = aPlotOpt.ColorSettings()->GetColor( aLayerMask.Seq()[0] );
743 else
744 color = aPlotOpt.ColorSettings()->GetColor( LAYER_VIAS + static_cast<int>( via->GetViaType() ) );
745
746 // Change UNSPECIFIED or WHITE to LIGHTGRAY because the white items are not seen on a
747 // white paper or screen
748 if( color == COLOR4D::UNSPECIFIED || color == WHITE )
749 color = LIGHTGRAY;
750
751 aPlotter->SetColor( color );
752 aPlotter->FlashPadCircle( via->GetStart(), diameter, getMetadata() );
753 }
754
755 aPlotter->EndBlock( nullptr );
756 aPlotter->StartBlock( nullptr );
757
758 if( onCopperLayer )
759 {
762 }
763 else
764 {
765 // Reset attributes if non-copper (soldermask) layer
768 }
769
770 // Plot tracks (not vias) :
771 for( const PCB_TRACK* track : aBoard->Tracks() )
772 {
773 if( track->Type() == PCB_VIA_T )
774 continue;
775
776 if( !( aLayerMask & track->GetLayerSet() ).any() )
777 continue;
778
779 // Some track segments can be not connected (no net).
780 // Set the m_NotInNet for these segments to force a empty net name in gerber file
781 gbr_metadata.m_NetlistMetadata.m_NotInNet = track->GetNetname().IsEmpty();
782
783 gbr_metadata.SetNetName( track->GetNetname() );
784
785 int margin = 0;
786
787 if( onSolderMaskLayer )
788 margin = track->GetSolderMaskExpansion();
789
790 int width = track->GetWidth() + 2 * margin + itemplotter.getFineWidthAdj();
791
792 aPlotter->SetColor( itemplotter.getColor( track->GetLayer() ) );
793
794 if( track->Type() == PCB_ARC_T )
795 {
796 const PCB_ARC* arc = static_cast<const PCB_ARC*>( track );
797
798 // Too small arcs cannot be really handled: arc center (and arc radius)
799 // cannot be safely computed
800 if( !arc->IsDegenerated( 10 /* in IU */ ) )
801 {
802 aPlotter->ThickArc( arc->GetCenter(), arc->GetArcAngleStart(), arc->GetAngle(),
803 arc->GetRadius(), width, getMetadata() );
804 }
805 else
806 {
807 // Approximate this very small arc by a segment.
808 aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, getMetadata() );
809 }
810 }
811 else
812 {
813 aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, getMetadata() );
814 }
815 }
816
817 aPlotter->EndBlock( nullptr );
818
819 // Plot filled ares
820 aPlotter->StartBlock( nullptr );
821
822 NETINFO_ITEM nonet( aBoard );
823
824 for( const ZONE* zone : aBoard->Zones() )
825 {
826 if( zone->GetIsRuleArea() )
827 continue;
828
829 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
830 {
831 if( !aLayerMask[layer] )
832 continue;
833
834 SHAPE_POLY_SET mainArea = zone->GetFilledPolysList( layer )->CloneDropTriangulation();
835 SHAPE_POLY_SET islands;
836
837 for( int i = mainArea.OutlineCount() - 1; i >= 0; i-- )
838 {
839 if( zone->IsIsland( layer, i ) )
840 {
841 islands.AddOutline( mainArea.CPolygon( i )[0] );
842 mainArea.DeletePolygon( i );
843 }
844 }
845
846 itemplotter.PlotZone( zone, layer, mainArea );
847
848 if( !islands.IsEmpty() )
849 {
850 ZONE dummy( *zone );
851 dummy.SetNet( &nonet );
852 itemplotter.PlotZone( &dummy, layer, islands );
853 }
854 }
855 }
856
857 aPlotter->EndBlock( nullptr );
858}
859
860
864void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, const LSET& aLayerMask,
865 const PCB_PLOT_PARAMS& aPlotOpt )
866{
867 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
868 itemplotter.SetLayerSet( aLayerMask );
869
870 int smallDrill = pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_SmallDrillMarkSize );
871
872 SHAPE_POLY_SET outlines;
873
874 for( PCB_LAYER_ID layer : aLayerMask.Seq( aLayerMask.SeqStackupForPlotting() ) )
875 {
876 outlines.RemoveAllContours();
877 aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines, aPlotter->RenderSettings() );
878
879 outlines.Simplify();
880
881 // Plot outlines
882 std::vector<VECTOR2I> cornerList;
883
884 // Now we have one or more basic polygons: plot each polygon
885 for( int ii = 0; ii < outlines.OutlineCount(); ii++ )
886 {
887 for( int kk = 0; kk <= outlines.HoleCount(ii); kk++ )
888 {
889 cornerList.clear();
890 const SHAPE_LINE_CHAIN& path = ( kk == 0 ) ? outlines.COutline( ii )
891 : outlines.CHole( ii, kk - 1 );
892
894 }
895 }
896
897 // Plot pad holes
899 {
900 for( FOOTPRINT* footprint : aBoard->Footprints() )
901 {
902 for( PAD* pad : footprint->Pads() )
903 {
904 if( pad->HasHole() )
905 {
906 if( pad->GetDrillSizeX() == pad->GetDrillSizeY() )
907 {
908 int drill = pad->GetDrillSizeX();
909
911 drill = std::min( smallDrill, drill );
912
913 aPlotter->ThickCircle( pad->ShapePos( layer ), drill,
915 }
916 else
917 {
918 // Note: small drill marks have no significance when applied to slots
919
920 aPlotter->ThickOval( pad->ShapePos( layer ), pad->GetSize( layer ),
921 pad->GetOrientation(), PLOTTER::USE_DEFAULT_LINE_WIDTH,
922 nullptr );
923 }
924 }
925 }
926 }
927 }
928
929 // Plot vias holes
930 for( PCB_TRACK* track : aBoard->Tracks() )
931 {
932 if( track->Type() != PCB_VIA_T )
933 continue;
934
935 const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
936
937 if( via->GetLayerSet().Contains( layer ) ) // via holes can be not through holes
938 {
939 aPlotter->Circle( via->GetPosition(), via->GetDrillValue(), FILL_T::NO_FILL,
941 }
942 }
943 }
944}
945
946
950void GenerateLayerPoly( SHAPE_POLY_SET* aResult, BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
951 bool aPlotFPText, bool aPlotReferences, bool aPlotValues )
952{
953 int maxError = aBoard->GetDesignSettings().m_MaxError;
954 SHAPE_POLY_SET buffer;
955 int inflate = 0;
956
957 if( aLayer == F_Mask || aLayer == B_Mask )
958 {
959 // We remove 1nm as we expand both sides of the shapes, so allowing for a strictly greater
960 // than or equal comparison in the shape separation (boolean add)
961 inflate = aBoard->GetDesignSettings().m_SolderMaskMinWidth / 2 - 1;
962 }
963
964 // Build polygons for each pad shape. The size of the shape on solder mask should be size
965 // of pad + clearance around the pad, where clearance = solder mask clearance + extra margin.
966 // Extra margin is half the min width for solder mask, which is used to merge too-close shapes
967 // (distance < SolderMaskMinWidth).
968
969 // Will contain exact shapes of all items on solder mask. We add this back in at the end just
970 // to make sure that any artefacts introduced by the inflate/deflate don't remove parts of the
971 // individual shapes.
972 SHAPE_POLY_SET exactPolys;
973
974 auto handleFPTextItem =
975 [&]( const PCB_TEXT& aText )
976 {
977 if( !aPlotFPText )
978 return;
979
980 if( aText.GetText() == wxT( "${REFERENCE}" ) && !aPlotReferences )
981 return;
982
983 if( aText.GetText() == wxT( "${VALUE}" ) && !aPlotValues )
984 return;
985
986 if( inflate != 0 )
987 aText.TransformTextToPolySet( exactPolys, 0, maxError, ERROR_OUTSIDE );
988
989 aText.TransformTextToPolySet( *aResult, inflate, maxError, ERROR_OUTSIDE );
990 };
991
992 // Generate polygons with arcs inside the shape or exact shape to minimize shape changes
993 // created by arc to segment size correction.
995 {
996 // Plot footprint pads and graphics
997 for( const FOOTPRINT* footprint : aBoard->Footprints() )
998 {
999 if( inflate != 0 )
1000 footprint->TransformPadsToPolySet( exactPolys, aLayer, 0, maxError, ERROR_OUTSIDE );
1001
1002 footprint->TransformPadsToPolySet( *aResult, aLayer, inflate, maxError, ERROR_OUTSIDE );
1003
1004 for( const PCB_FIELD* field : footprint->GetFields() )
1005 {
1006 wxCHECK2( field, continue );
1007
1008 if( field->IsReference() && !aPlotReferences )
1009 continue;
1010
1011 if( field->IsValue() && !aPlotValues )
1012 continue;
1013
1014 if( field->IsVisible() && field->IsOnLayer( aLayer ) )
1015 handleFPTextItem( static_cast<const PCB_TEXT&>( *field ) );
1016 }
1017
1018 for( const BOARD_ITEM* item : footprint->GraphicalItems() )
1019 {
1020 if( item->IsOnLayer( aLayer ) )
1021 {
1022 if( item->Type() == PCB_TEXT_T )
1023 {
1024 handleFPTextItem( static_cast<const PCB_TEXT&>( *item ) );
1025 }
1026 else
1027 {
1028 if( inflate != 0 )
1029 item->TransformShapeToPolySet( exactPolys, aLayer, 0, maxError, ERROR_OUTSIDE );
1030
1031 item->TransformShapeToPolySet( *aResult, aLayer, inflate, maxError, ERROR_OUTSIDE );
1032 }
1033 }
1034 }
1035 }
1036
1037 // Plot untented vias and tracks
1038 for( const PCB_TRACK* track : aBoard->Tracks() )
1039 {
1040 // Note: IsOnLayer() checks relevant mask layers of untented vias and tracks
1041 if( !track->IsOnLayer( aLayer ) )
1042 continue;
1043
1044 int clearance = track->GetSolderMaskExpansion();
1045
1046 if( inflate != 0 )
1047 track->TransformShapeToPolygon( exactPolys, aLayer, clearance, maxError, ERROR_OUTSIDE );
1048
1049 track->TransformShapeToPolygon( *aResult, aLayer, clearance + inflate, maxError, ERROR_OUTSIDE );
1050 }
1051
1052 for( const BOARD_ITEM* item : aBoard->Drawings() )
1053 {
1054 if( item->IsOnLayer( aLayer ) )
1055 {
1056 if( item->Type() == PCB_TEXT_T )
1057 {
1058 const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
1059
1060 if( inflate != 0 )
1061 text->TransformTextToPolySet( exactPolys, 0, maxError, ERROR_OUTSIDE );
1062
1063 text->TransformTextToPolySet( *aResult, inflate, maxError, ERROR_OUTSIDE );
1064 }
1065 else
1066 {
1067 if( inflate != 0 )
1068 item->TransformShapeToPolySet( exactPolys, aLayer, 0, maxError, ERROR_OUTSIDE,
1069 aPlotter->RenderSettings() );
1070
1071 item->TransformShapeToPolySet( *aResult, aLayer, inflate, maxError,
1072 ERROR_OUTSIDE, aPlotter->RenderSettings() );
1073 }
1074 }
1075 }
1076
1077 // Add filled zone areas.
1078 for( ZONE* zone : aBoard->Zones() )
1079 {
1080 if( zone->GetIsRuleArea() )
1081 continue;
1082
1083 if( !zone->IsOnLayer( aLayer ) )
1084 continue;
1085
1086 SHAPE_POLY_SET area = *zone->GetFill( aLayer );
1087
1088 if( inflate != 0 )
1089 exactPolys.Append( area );
1090
1091 area.Inflate( inflate, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
1092 aResult->Append( area );
1093 }
1094 }
1095
1096 // Merge all polygons
1097 aResult->Simplify();
1098
1099 if( inflate != 0 )
1100 {
1101 aResult->Deflate( inflate, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
1102 // Add back in the exact polys. This is mandatory because inflate/deflate transform is
1103 // not perfect, and we want the initial areas perfectly kept.
1104 aResult->BooleanAdd( exactPolys );
1105 }
1106#undef ERROR
1107}
1108
1109
1116static void initializePlotter( PLOTTER* aPlotter, const BOARD* aBoard, const PCB_PLOT_PARAMS* aPlotOpts )
1117{
1118 PAGE_INFO pageA4( PAGE_SIZE_TYPE::A4 );
1119 const PAGE_INFO& pageInfo = aBoard->GetPageSettings();
1120 const PAGE_INFO* sheet_info;
1121 double paperscale; // Page-to-paper ratio
1122 VECTOR2I paperSizeIU;
1123 VECTOR2I pageSizeIU( pageInfo.GetSizeIU( pcbIUScale.IU_PER_MILS ) );
1124 bool autocenter = false;
1125
1126 // Special options: to fit the sheet to an A4 sheet replace the paper size. However there
1127 // is a difference between the autoscale and the a4paper option:
1128 // - Autoscale fits the board to the paper size
1129 // - A4paper fits the original paper size to an A4 sheet
1130 // - Both of them fit the board to an A4 sheet
1131 if( aPlotOpts->GetA4Output() )
1132 {
1133 sheet_info = &pageA4;
1134 paperSizeIU = pageA4.GetSizeIU( pcbIUScale.IU_PER_MILS );
1135 paperscale = (double) paperSizeIU.x / pageSizeIU.x;
1136 autocenter = true;
1137 }
1138 else
1139 {
1140 sheet_info = &pageInfo;
1141 paperSizeIU = pageSizeIU;
1142 paperscale = 1;
1143
1144 // Need autocentering only if scale is not 1:1
1145 autocenter = (aPlotOpts->GetScale() != 1.0) || aPlotOpts->GetAutoScale();
1146 }
1147
1148 BOX2I bbox = aBoard->ComputeBoundingBox( false );
1149 VECTOR2I boardCenter = bbox.Centre();
1150 VECTOR2I boardSize = bbox.GetSize();
1151
1152 double compound_scale;
1153
1154 // Fit to 80% of the page if asked; it could be that the board is empty, in this case
1155 // regress to 1:1 scale
1156 if( aPlotOpts->GetAutoScale() && boardSize.x > 0 && boardSize.y > 0 )
1157 {
1158 double xscale = (paperSizeIU.x * 0.8) / boardSize.x;
1159 double yscale = (paperSizeIU.y * 0.8) / boardSize.y;
1160
1161 compound_scale = std::min( xscale, yscale ) * paperscale;
1162 }
1163 else
1164 {
1165 compound_scale = aPlotOpts->GetScale() * paperscale;
1166 }
1167
1168 // For the plot offset we have to keep in mind the auxiliary origin too: if autoscaling is
1169 // off we check that plot option (i.e. autoscaling overrides auxiliary origin)
1170 VECTOR2I offset( 0, 0);
1171
1172 if( autocenter )
1173 {
1174 offset.x = KiROUND( boardCenter.x - ( paperSizeIU.x / 2.0 ) / compound_scale );
1175 offset.y = KiROUND( boardCenter.y - ( paperSizeIU.y / 2.0 ) / compound_scale );
1176 }
1177 else
1178 {
1179 if( aPlotOpts->GetUseAuxOrigin() )
1180 offset = aBoard->GetDesignSettings().GetAuxOrigin();
1181 }
1182
1183 aPlotter->SetPageSettings( *sheet_info );
1184
1185 aPlotter->SetViewport( offset, pcbIUScale.IU_PER_MILS/10, compound_scale, aPlotOpts->GetMirror() );
1186
1187 // Has meaning only for gerber plotter. Must be called only after SetViewport
1188 aPlotter->SetGerberCoordinatesFormat( aPlotOpts->GetGerberPrecision() );
1189
1190 // Has meaning only for SVG plotter. Must be called only after SetViewport
1191 aPlotter->SetSvgCoordinatesFormat( aPlotOpts->GetSvgPrecision() );
1192
1193 aPlotter->SetCreator( wxT( "PCBNEW" ) );
1194 aPlotter->SetColorMode( !aPlotOpts->GetBlackAndWhite() ); // default is plot in Black and White.
1195 aPlotter->SetTextMode( aPlotOpts->GetTextMode() );
1196}
1197
1198
1202static void FillNegativeKnockout( PLOTTER *aPlotter, const BOX2I &aBbbox )
1203{
1204 const int margin = 5 * pcbIUScale.IU_PER_MM; // Add a 5 mm margin around the board
1205 aPlotter->SetNegative( true );
1206 aPlotter->SetColor( WHITE ); // Which will be plotted as black
1207
1208 BOX2I area = aBbbox;
1209 area.Inflate( margin );
1210 aPlotter->Rect( area.GetOrigin(), area.GetEnd(), FILL_T::FILLED_SHAPE, 0, 0 );
1211 aPlotter->SetColor( BLACK );
1212}
1213
1214
1215static void plotPdfBackground( BOARD* aBoard, const PCB_PLOT_PARAMS* aPlotOpts, PLOTTER* aPlotter )
1216{
1217 const PAGE_INFO& pageInfo = aPlotter->PageSettings();
1218 const VECTOR2I plotOffset = aPlotter->GetPlotOffsetUserUnits();
1219 const VECTOR2I pageSizeIU( pageInfo.GetWidthIU( pcbIUScale.IU_PER_MILS ),
1220 pageInfo.GetHeightIU( pcbIUScale.IU_PER_MILS ) );
1221
1222 if( aPlotter->GetColorMode()
1223 && aPlotOpts->GetPDFBackgroundColor() != COLOR4D::UNSPECIFIED )
1224 {
1225 aPlotter->SetColor( aPlotOpts->GetPDFBackgroundColor() );
1226
1227 // Use plotter page size and offset so background matches the plotted output.
1228 VECTOR2I end = plotOffset + pageSizeIU;
1229
1230 aPlotter->Rect( plotOffset, end, FILL_T::FILLED_SHAPE, 1.0 );
1231 }
1232}
1233
1234
1241PLOTTER* StartPlotBoard( BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer,
1242 const wxString& aLayerName, const wxString& aFullFileName,
1243 const wxString& aSheetName, const wxString& aSheetPath,
1244 const wxString& aPageName, const wxString& aPageNumber,
1245 const int aPageCount )
1246{
1247 wxCHECK( aBoard && aPlotOpts, nullptr );
1248
1249 // Create the plotter driver and set the few plotter specific options
1250 PLOTTER* plotter = nullptr;
1251
1252 switch( aPlotOpts->GetFormat() )
1253 {
1254 case PLOT_FORMAT::DXF:
1255 DXF_PLOTTER* DXF_plotter;
1256 DXF_plotter = new DXF_PLOTTER();
1257 DXF_plotter->SetUnits( aPlotOpts->GetDXFPlotUnits() );
1258
1259 plotter = DXF_plotter;
1260
1261 if( !aPlotOpts->GetLayersToExport().empty() )
1262 plotter->SetLayersToExport( aPlotOpts->GetLayersToExport() );
1263 break;
1264
1265 case PLOT_FORMAT::POST:
1266 PS_PLOTTER* PS_plotter;
1267 PS_plotter = new PS_PLOTTER();
1268 PS_plotter->SetScaleAdjust( aPlotOpts->GetFineScaleAdjustX(),
1269 aPlotOpts->GetFineScaleAdjustY() );
1270 plotter = PS_plotter;
1271 break;
1272
1273 case PLOT_FORMAT::PDF:
1274 plotter = new PDF_PLOTTER( aBoard->GetProject() );
1275 break;
1276
1277 case PLOT_FORMAT::HPGL:
1278 wxLogError( _( "HPGL plotting is no longer supported as of KiCad 10.0" ) );
1279 return nullptr;
1280
1282 // For Gerber plotter, a valid board layer must be set, in order to create a valid
1283 // Gerber header, especially the TF.FileFunction and .FilePolarity data
1284 if( aLayer < PCBNEW_LAYER_ID_START || aLayer >= PCB_LAYER_ID_COUNT )
1285 {
1286 wxLogError( wxString::Format( "Invalid board layer %d, cannot build a valid Gerber file header",
1287 aLayer ) );
1288 }
1289
1290 plotter = new GERBER_PLOTTER();
1291 break;
1292
1293 case PLOT_FORMAT::SVG:
1294 plotter = new SVG_PLOTTER();
1295 break;
1296
1297 default:
1298 wxASSERT( false );
1299 return nullptr;
1300 }
1301
1303 renderSettings->LoadColors( aPlotOpts->ColorSettings() );
1304 renderSettings->SetDefaultPenWidth( pcbIUScale.mmToIU( 0.0212 ) ); // Hairline at 1200dpi
1305 renderSettings->SetLayerName( aLayerName );
1306
1307 plotter->SetRenderSettings( renderSettings );
1308
1309 // Compute the viewport and set the other options
1310
1311 // page layout is not mirrored, so temporarily change mirror option for the page layout
1312 PCB_PLOT_PARAMS plotOpts = *aPlotOpts;
1313
1314 if( plotOpts.GetPlotFrameRef() )
1315 {
1316 if( plotOpts.GetMirror() )
1317 plotOpts.SetMirror( false );
1318 if( plotOpts.GetScale() != 1.0 )
1319 plotOpts.SetScale( 1.0 );
1320 if( plotOpts.GetAutoScale() )
1321 plotOpts.SetAutoScale( false );
1322 }
1323
1324 initializePlotter( plotter, aBoard, &plotOpts );
1325
1326 if( plotter->OpenFile( aFullFileName ) )
1327 {
1328 plotter->ClearHeaderLinesList();
1329
1330 // For the Gerber "file function" attribute, set the layer number
1331 if( plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1332 {
1333 bool useX2mode = plotOpts.GetUseGerberX2format();
1334
1335 GERBER_PLOTTER* gbrplotter = static_cast <GERBER_PLOTTER*> ( plotter );
1336 gbrplotter->DisableApertMacros( plotOpts.GetDisableGerberMacros() );
1337 gbrplotter->UseX2format( useX2mode );
1338 gbrplotter->UseX2NetAttributes( plotOpts.GetIncludeGerberNetlistInfo() );
1339
1340 // Attributes can be added using X2 format or as comment (X1 format)
1341 AddGerberX2Attribute( plotter, aBoard, aLayer, not useX2mode );
1342 }
1343
1344 bool startPlotSuccess = false;
1345 try
1346 {
1347 if( plotter->GetPlotterType() == PLOT_FORMAT::PDF )
1348 startPlotSuccess = static_cast<PDF_PLOTTER*>( plotter )->StartPlot( aPageNumber, aPageName );
1349 else
1350 startPlotSuccess = plotter->StartPlot( aPageName );
1351 }
1352 catch( ... )
1353 {
1354 startPlotSuccess = false;
1355 }
1356
1357
1358 if( startPlotSuccess )
1359 {
1360 if( aPlotOpts->GetFormat() == PLOT_FORMAT::PDF )
1361 plotPdfBackground( aBoard, aPlotOpts, plotter );
1362
1363 // Plot the frame reference if requested
1364 if( aPlotOpts->GetPlotFrameRef() )
1365 {
1366 PlotDrawingSheet( plotter, aBoard->GetProject(), aBoard->GetTitleBlock(),
1367 aBoard->GetPageSettings(), &aBoard->GetProperties(), aPageNumber,
1368 aPageCount, aSheetName, aSheetPath, aBoard->GetFileName(),
1369 renderSettings->GetLayerColor( LAYER_DRAWINGSHEET ) );
1370
1371 if( aPlotOpts->GetMirror() || aPlotOpts->GetScale() != 1.0 || aPlotOpts->GetAutoScale() )
1372 initializePlotter( plotter, aBoard, aPlotOpts );
1373 }
1374
1375 // When plotting a negative board: draw a black rectangle (background for plot board
1376 // in white) and switch the current color to WHITE; note the color inversion is actually
1377 // done in the driver (if supported)
1378 if( aPlotOpts->GetNegative() )
1379 {
1380 BOX2I bbox = aBoard->ComputeBoundingBox( false );
1381 FillNegativeKnockout( plotter, bbox );
1382 }
1383
1384 return plotter;
1385 }
1386 }
1387
1388 delete plotter->RenderSettings();
1389 delete plotter;
1390 return nullptr;
1391}
1392
1393
1394void setupPlotterNewPDFPage( PLOTTER* aPlotter, BOARD* aBoard, PCB_PLOT_PARAMS* aPlotOpts,
1395 const wxString& aLayerName, const wxString& aSheetName,
1396 const wxString& aSheetPath, const wxString& aPageNumber,
1397 int aPageCount )
1398{
1399 plotPdfBackground( aBoard, aPlotOpts, aPlotter );
1400
1401 aPlotter->RenderSettings()->SetLayerName( aLayerName );
1402
1403 // Plot the frame reference if requested
1404 if( aPlotOpts->GetPlotFrameRef() )
1405 {
1406 // Mirror and scale shouldn't be applied to the drawing sheet
1407 bool revertOps = false;
1408 bool oldMirror = aPlotOpts->GetMirror();
1409 bool oldAutoScale = aPlotOpts->GetAutoScale();
1410 double oldScale = aPlotOpts->GetScale();
1411
1412 if( oldMirror || oldAutoScale || oldScale != 1.0 )
1413 {
1414 aPlotOpts->SetMirror( false );
1415 aPlotOpts->SetScale( 1.0 );
1416 aPlotOpts->SetAutoScale( false );
1417 initializePlotter( aPlotter, aBoard, aPlotOpts );
1418 revertOps = true;
1419 }
1420
1421 PlotDrawingSheet( aPlotter, aBoard->GetProject(), aBoard->GetTitleBlock(),
1422 aBoard->GetPageSettings(), &aBoard->GetProperties(), aPageNumber,
1423 aPageCount,
1424 aSheetName, aSheetPath, aBoard->GetFileName(),
1426
1427 if( revertOps )
1428 {
1429 aPlotOpts->SetMirror( oldMirror );
1430 aPlotOpts->SetScale( oldScale );
1431 aPlotOpts->SetAutoScale( oldAutoScale );
1432 initializePlotter( aPlotter, aBoard, aPlotOpts );
1433 }
1434 }
1435}
@ ERROR_OUTSIDE
@ ERROR_INSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
@ LAYER_CLASS_FAB
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
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() const
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:83
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
void ConvertBrdLayerToPolygonalContours(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aOutlines, KIGFX::RENDER_SETTINGS *aRenderSettings=nullptr) const
Build a set of polygons which are the outlines of copper items (pads, tracks, vias,...
Definition board.cpp:3437
const PAGE_INFO & GetPageSettings() const
Definition board.h:799
const ZONES & Zones() const
Definition board.h:367
TITLE_BLOCK & GetTitleBlock()
Definition board.h:805
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition board.cpp:2107
const std::map< wxString, wxString > & GetProperties() const
Definition board.h:400
const FOOTPRINTS & Footprints() const
Definition board.h:363
const TRACKS & Tracks() const
Definition board.h:361
const wxString & GetFileName() const
Definition board.h:359
wxString GetCurrentVariant() const
Definition board.h:404
PROJECT * GetProject() const
Definition board.h:579
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1084
const DRAWINGS & Drawings() const
Definition board.h:365
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 SetLayerSet(const LSET &aLayerMask)
Definition pcbplot.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 PlotPad(const PAD *aPad, PCB_LAYER_ID aLayer, const COLOR4D &aColor, bool aSketchMode)
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:78
void PlotFootprintGraphicItems(const FOOTPRINT *aFootprint)
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:402
static const COLOR4D BLACK
Definition color4d.h:406
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.
@ GBR_APERTURE_ATTRIB_CONDUCTOR
Aperture used for connected items like tracks (not vias).
@ GBR_APERTURE_ATTRIB_VIAPAD
Aperture used for vias.
@ GBR_APERTURE_ATTRIB_NONE
uninitialized attribute.
Metadata which can be added in a gerber file as attribute in X2 format.
void SetNetName(const wxString &aNetname)
void SetApertureAttrib(GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB aApertAttribute)
GBR_NETLIST_METADATA m_NetlistMetadata
An item to handle object attribute.
void SetNetAttribType(int aNetAttribType)
@ 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.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
COLOR4D LegacyMix(const COLOR4D &aColor) const
Mix this COLOR4D with an input COLOR4D using the OR-mixing of legacy canvas.
Definition color4d.cpp:236
PCB specific render settings.
Definition pcb_painter.h:82
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 SeqStackupForPlotting() const
Return the sequence that is typical for a bottom-to-top stack-up.
Definition lset.cpp:404
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:313
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:599
static LSET AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:608
Handle the data for a net.
Definition netinfo.h:54
Definition pad.h:55
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:79
int GetHeightIU(double aIUScale) const
Gets the page height in IU.
Definition page_info.h:168
const VECTOR2D GetSizeIU(double aIUScale) const
Gets the page size in internal units.
Definition page_info.h:177
int GetWidthIU(double aIUScale) const
Gets the page width in IU.
Definition page_info.h:159
bool IsDegenerated(int aThreshold=5) const
EDA_ANGLE GetArcAngleStart() const
double GetRadius() const
EDA_ANGLE GetAngle() const
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition pcb_track.h:354
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 GetCrossoutDNPFPsOnFabLayers() const
void SetDXFPlotPolygonMode(bool aFlag)
void SetAutoScale(bool aFlag)
unsigned GetSvgPrecision() const
double GetScale() const
PLOT_TEXT_MODE GetTextMode() const override
bool GetDXFPlotPolygonMode() const
bool GetPlotReference() const
bool m_PDFFrontFPPropertyPopups
Generate PDF property popup menus for footprints.
void SetScale(double aVal)
void SetMirror(bool aFlag)
bool GetSketchPadsOnFabLayers() const
bool GetSubtractMaskFromSilk() const
int GetGerberPrecision() const
double GetFineScaleAdjustY() const
bool GetPlotPadNumbers() const
bool GetA4Output() const
DRILL_MARKS GetDrillMarksType() const
bool GetUseGerberX2format() const
bool GetPlotValue() const
bool GetIncludeGerberNetlistInfo() const
double GetFineScaleAdjustX() const
bool GetBlackAndWhite() const
bool m_PDFBackFPPropertyPopups
on front and/or back of board
bool GetPlotFPText() const
bool GetPlotFrameRef() const
COLOR4D GetPDFBackgroundColor() const
bool GetDisableGerberMacros() const
std::vector< std::pair< PCB_LAYER_ID, wxString > > GetLayersToExport() const
COLOR_SETTINGS * ColorSettings() const
Base plotter engine class.
Definition plotter.h:136
virtual void Circle(const VECTOR2I &pos, int diametre, FILL_T fill, int width)=0
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition plotter.cpp:77
virtual void SetNegative(bool aNegative)
Definition plotter.h:156
virtual void SetSvgCoordinatesFormat(unsigned aPrecision)
Set the number of digits for mantissa in coordinates in mm for SVG plotter.
Definition plotter.h:578
virtual void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition plotter.h:169
void SetRenderSettings(RENDER_SETTINGS *aSettings)
Definition plotter.h:166
static const int USE_DEFAULT_LINE_WIDTH
Definition plotter.h:140
virtual void ThickOval(const VECTOR2I &aPos, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, int aWidth, void *aData)
Definition plotter.cpp:487
virtual bool StartPlot(const wxString &aPageNumber)=0
void SetLayersToExport(const std::vector< std::pair< PCB_LAYER_ID, wxString > > &aLayersToExport)
Sets the list of layers to export to the specified vector.
Definition plotter.h:234
RENDER_SETTINGS * RenderSettings()
Definition plotter.h:167
virtual void SetGerberCoordinatesFormat(int aResolution, bool aUseInches=false)
Definition plotter.h:572
virtual void Bookmark(const BOX2I &aBox, const wxString &aName, const wxString &aGroupName=wxEmptyString)
Create a bookmark to a symbol.
Definition plotter.h:528
virtual PLOT_FORMAT GetPlotterType() const =0
Return the effective plot engine in use.
virtual void ThickArc(const EDA_SHAPE &aArcShape, void *aData, int aWidth)
Definition plotter.cpp:562
virtual void SetTextMode(PLOT_TEXT_MODE mode)
Change the current text mode.
Definition plotter.h:567
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T fill, int width, int aCornerRadius=0)=0
virtual void SetCreator(const wxString &aCreator)
Definition plotter.h:188
VECTOR2I GetPlotOffsetUserUnits()
Definition plotter.h:604
void ClearHeaderLinesList()
Remove all lines from the list of free lines to print at the beginning of the file.
Definition plotter.h:206
bool GetColorMode() const
Definition plotter.h:164
PAGE_INFO & PageSettings()
Definition plotter.h:170
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:163
virtual void StartBlock(void *aData)
calling this function allows one to define the beginning of a group of drawing items,...
Definition plotter.h:590
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData)
Definition plotter.cpp:540
virtual void PlotPoly(const std::vector< VECTOR2I > &aCornerList, FILL_T aFill, int aWidth, void *aData)=0
Draw a polygon ( filled or not ).
virtual void FlashPadCircle(const VECTOR2I &aPadPos, int aDiameter, void *aData)=0
virtual void HyperlinkMenu(const BOX2I &aBox, const std::vector< wxString > &aDestURLs)
Create a clickable hyperlink menu with a rectangular click area.
Definition plotter.h:517
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:557
virtual void ThickCircle(const VECTOR2I &pos, int diametre, int width, void *aData)
Definition plotter.cpp:593
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:599
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 BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
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 Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
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()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
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.
void InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError)
Perform outline inflation/deflation, using round corners.
SHAPE_POLY_SET CloneDropTriangulation() const
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const POLYGON & CPolygon(int aIndex) const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Handle a list of polygons defining a copper zone.
Definition zone.h:74
void SetMinThickness(int aMinThickness)
Definition zone.h:308
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:545
A type-safe container of any type.
Definition ki_any.h:93
constexpr any() noexcept
Default constructor, creates an empty object.
Definition ki_any.h:156
@ 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:411
@ NO_FILL
Definition eda_shape.h:57
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:58
Handle special data (items attributes) during plot.
a few functions useful in geometry calculations.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:677
@ LAYER_DRAWINGSHEET
Sheet frame and title block.
Definition layer_ids.h:278
@ LAYER_VIAS
Meta control for all vias opacity/visibility.
Definition layer_ids.h:232
@ LAYER_DNP_MARKER
Definition layer_ids.h:478
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
@ Eco2_User
Definition layer_ids.h:110
@ B_SilkS
Definition layer_ids.h:101
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:171
@ F_Cu
Definition layer_ids.h:64
@ B_Fab
Definition layer_ids.h:118
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:103
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition padstack.h:52
@ CHAMFERED_RECT
Definition padstack.h:60
@ ROUNDRECT
Definition padstack.h:57
@ TRAPEZOID
Definition padstack.h:56
@ RECTANGLE
Definition padstack.h:54
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
void GenerateLayerPoly(SHAPE_POLY_SET *aResult, BOARD *aBoard, PLOTTER *aPlotter, PCB_LAYER_ID aLayer, bool aPlotFPText, bool aPlotReferences, bool aPlotValues)
Generates a SHAPE_POLY_SET representing the plotted items on a layer.
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 PlotClippedSilkLayer(BOARD *aBoard, PLOTTER *aPlotter, const LSET &aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
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, const LSET &aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
Plot any layer EXCEPT a solder-mask with an enforced minimum width.
PLOTTER * StartPlotBoard(BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString &aLayerName, const wxString &aFullFileName, const wxString &aSheetName, const wxString &aSheetPath, const wxString &aPageName, const wxString &aPageNumber, const int aPageCount)
Open a new plotfile using the options (and especially the format) specified in the options and prepar...
void PlotPolySet(BOARD *aBoard, PLOTTER *aPlotter, const PCB_PLOT_PARAMS &aPlotOpt, SHAPE_POLY_SET *aPolySet, PCB_LAYER_ID aLayer)
void setupPlotterNewPDFPage(PLOTTER *aPlotter, BOARD *aBoard, PCB_PLOT_PARAMS *aPlotOpts, const wxString &aLayerName, const wxString &aSheetName, const wxString &aSheetPath, const wxString &aPageNumber, int aPageCount)
void PlotSolderMaskLayer(BOARD *aBoard, PLOTTER *aPlotter, const LSET &aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
Plot a solder mask layer.
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.).
void PlotOneBoardLayer(BOARD *aBoard, PLOTTER *aPlotter, PCB_LAYER_ID aLayer, const PCB_PLOT_PARAMS &aPlotOpt, bool isPrimaryLayer)
Plot one copper or technical layer.
void PlotLayer(BOARD *aBoard, PLOTTER *aPlotter, const LSET &layerMask, const PCB_PLOT_PARAMS &plotOpts)
void PlotLayerOutlines(BOARD *aBoard, PLOTTER *aPlotter, const LSET &aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
Plot outlines.
static void plotPdfBackground(BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, PLOTTER *aPlotter)
#define getMetadata()
Plotting engines similar to ps (PostScript, Gerber, svg)
std::vector< FAB_LAYER_COLOR > dummy
std::string path
VECTOR2I end
int clearance
@ 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:695