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