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