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