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