KiCad PCB EDA Suite
plot_board_layers.cpp
Go to the documentation of this file.
1
8/*
9 * This program source code file is part of KiCad, a free EDA CAD application.
10 *
11 * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, you may find one here:
25 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
26 * or you may search the http://www.gnu.org website for the version 2 license,
27 * or you may write to the Free Software Foundation, Inc.,
28 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
29 */
30
31
32#include <eda_item.h>
33#include <layer_ids.h>
36#include <pcb_base_frame.h>
37#include <math/util.h> // for KiROUND
38
39#include <board.h>
41#include <core/arraydim.h>
42#include <footprint.h>
43#include <pcb_track.h>
44#include <fp_shape.h>
45#include <pad.h>
46#include <pcb_text.h>
47#include <zone.h>
48#include <pcb_shape.h>
49#include <pcb_target.h>
50#include <pcb_dimension.h>
51
52#include <pcbplot.h>
57#include <pcb_painter.h>
58#include <gbr_metadata.h>
59#include <advanced_config.h>
60
61/*
62 * Plot a solder mask layer. Solder mask layers have a minimum thickness value and cannot be
63 * drawn like standard layers, unless the minimum thickness is 0.
64 */
65static void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
66 const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness );
67
68
69void PlotBoardLayers( BOARD* aBoard, PLOTTER* aPlotter, const LSEQ& aLayers,
70 const PCB_PLOT_PARAMS& aPlotOptions )
71{
72 wxCHECK( aBoard && aPlotter && aLayers.size(), /* void */ );
73
74 for( LSEQ seq = aLayers; seq; ++seq )
75 PlotOneBoardLayer( aBoard, aPlotter, *seq, aPlotOptions );
76}
77
78
79void PlotInteractiveLayer( BOARD* aBoard, PLOTTER* aPlotter )
80{
81 for( const FOOTPRINT* fp : aBoard->Footprints() )
82 {
83 std::vector<wxString> properties;
84
85 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
86 _( "Reference designator" ),
87 fp->Reference().GetShownText() ) );
88
89 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
90 _( "Value" ),
91 fp->Value().GetShownText() ) );
92
93 for( const auto& [ name, value ] : fp->GetProperties() )
94 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), name, value ) );
95
96 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
97 _( "Footprint" ),
98 fp->GetFPIDAsString() ) );
99
100 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
101 _( "Description" ),
102 fp->GetDescription() ) );
103
104 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
105 _( "Keywords" ),
106 fp->GetKeywords() ) );
107
108 aPlotter->HyperlinkMenu( fp->GetBoundingBox(), properties );
109 }
110}
111
112
113void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
114 const PCB_PLOT_PARAMS& aPlotOpt )
115{
116 PCB_PLOT_PARAMS plotOpt = aPlotOpt;
117 int soldermask_min_thickness = aBoard->GetDesignSettings().m_SolderMaskMinWidth;
118
119 // Set a default color and the text mode for this layer
120 aPlotter->SetColor( BLACK );
121 aPlotter->SetTextMode( aPlotOpt.GetTextMode() );
122
123 // Specify that the contents of the "Edges Pcb" layer are to be plotted in addition to the
124 // contents of the currently specified layer.
125 LSET layer_mask( aLayer );
126
127 if( IsCopperLayer( aLayer ) )
128 {
129 // Skip NPTH pads on copper layers ( only if hole size == pad size ):
130 // Drill mark will be plotted if drill mark is SMALL_DRILL_SHAPE or FULL_DRILL_SHAPE
131 if( plotOpt.GetFormat() == PLOT_FORMAT::DXF )
132 {
133 plotOpt.SetSkipPlotNPTH_Pads( false );
134 PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
135 }
136 else
137 {
138 plotOpt.SetSkipPlotNPTH_Pads( true );
139 PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
140 }
141 }
142 else
143 {
144 switch( aLayer )
145 {
146 case B_Mask:
147 case F_Mask:
148 plotOpt.SetSkipPlotNPTH_Pads( false );
149
150 // Disable plot pad holes
152
153 // Plot solder mask:
154 if( soldermask_min_thickness == 0 )
155 {
156 if( plotOpt.GetFormat() == PLOT_FORMAT::DXF )
157 PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
158 else
159 PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
160 }
161 else
162 {
163 PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt,
164 soldermask_min_thickness );
165 }
166
167 break;
168
169 case B_Adhes:
170 case F_Adhes:
171 case B_Paste:
172 case F_Paste:
173 plotOpt.SetSkipPlotNPTH_Pads( false );
174
175 // Disable plot pad holes
177
178 if( plotOpt.GetFormat() == PLOT_FORMAT::DXF )
179 PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
180 else
181 PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
182
183 break;
184
185 case F_SilkS:
186 case B_SilkS:
187 if( plotOpt.GetFormat() == PLOT_FORMAT::DXF && plotOpt.GetDXFPlotPolygonMode() )
188 // PlotLayerOutlines() is designed only for DXF plotters.
189 // and must not be used for other plot formats
190 PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
191 else
192 PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
193
194 // Gerber: Subtract soldermask from silkscreen if enabled
195 if( aPlotter->GetPlotterType() == PLOT_FORMAT::GERBER
196 && plotOpt.GetSubtractMaskFromSilk() )
197 {
198 if( aLayer == F_SilkS )
199 layer_mask = LSET( F_Mask );
200 else
201 layer_mask = LSET( B_Mask );
202
203 // Create the mask to subtract by creating a negative layer polarity
204 aPlotter->SetLayerPolarity( false );
205
206 // Disable plot pad holes
208
209 // Plot the mask
210 PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
211 }
212
213 break;
214
215 // These layers are plotted like silk screen layers.
216 // Mainly, pads on these layers are not filled.
217 // This is not necessary the best choice.
218 case Dwgs_User:
219 case Cmts_User:
220 case Eco1_User:
221 case Eco2_User:
222 case Edge_Cuts:
223 case Margin:
224 case F_CrtYd:
225 case B_CrtYd:
226 case F_Fab:
227 case B_Fab:
228 plotOpt.SetSkipPlotNPTH_Pads( false );
230
231 if( plotOpt.GetFormat() == PLOT_FORMAT::DXF && plotOpt.GetDXFPlotPolygonMode() )
232 // PlotLayerOutlines() is designed only for DXF plotters.
233 // and must not be used for other plot formats
234 PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
235 else
236 PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
237
238 break;
239
240 default:
241 plotOpt.SetSkipPlotNPTH_Pads( false );
243
244 if( plotOpt.GetFormat() == PLOT_FORMAT::DXF && plotOpt.GetDXFPlotPolygonMode() )
245 // PlotLayerOutlines() is designed only for DXF plotters.
246 // and must not be used for other plot formats
247 PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
248 else
249 PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
250
251 break;
252 }
253 }
254}
255
256
262void PlotStandardLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
263 const PCB_PLOT_PARAMS& aPlotOpt )
264{
265 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
266
267 itemplotter.SetLayerSet( aLayerMask );
268
269 OUTLINE_MODE plotMode = aPlotOpt.GetPlotMode();
270 bool onCopperLayer = ( LSET::AllCuMask() & aLayerMask ).any();
271 bool onSolderMaskLayer = ( LSET( 2, F_Mask, B_Mask ) & aLayerMask ).any();
272 bool onSolderPasteLayer = ( LSET( 2, F_Paste, B_Paste ) & aLayerMask ).any();
273 bool onFrontFab = ( LSET( F_Fab ) & aLayerMask ).any();
274 bool onBackFab = ( LSET( B_Fab ) & aLayerMask ).any();
275 bool sketchPads = ( onFrontFab || onBackFab ) && aPlotOpt.GetSketchPadsOnFabLayers();
276
277 // Plot edge layer and graphic items
278 itemplotter.PlotBoardGraphicItems();
279
280 // Draw footprint texts:
281 for( const FOOTPRINT* footprint : aBoard->Footprints() )
282 itemplotter.PlotFootprintTextItems( footprint );
283
284 // Draw footprint other graphic items:
285 for( const FOOTPRINT* footprint : aBoard->Footprints() )
286 itemplotter.PlotFootprintGraphicItems( footprint );
287
288 // Plot footprint pads
289 for( FOOTPRINT* footprint : aBoard->Footprints() )
290 {
291 aPlotter->StartBlock( nullptr );
292
293 for( PAD* pad : footprint->Pads() )
294 {
295 OUTLINE_MODE padPlotMode = plotMode;
296
297 if( !( pad->GetLayerSet() & aLayerMask ).any() )
298 {
299 if( sketchPads &&
300 ( ( onFrontFab && pad->GetLayerSet().Contains( F_Cu ) ) ||
301 ( onBackFab && pad->GetLayerSet().Contains( B_Cu ) ) ) )
302 {
303 padPlotMode = SKETCH;
304 }
305 else
306 {
307 continue;
308 }
309 }
310
312 if( onCopperLayer && !pad->FlashLayer( aLayerMask ) )
313 continue;
314
316
317 // If we're plotting a single layer, the color for that layer can be used directly.
318 if( aLayerMask.count() == 1 )
319 {
320 color = aPlotOpt.ColorSettings()->GetColor( aLayerMask.Seq()[0] );
321 }
322 else
323 {
324 if( ( pad->GetLayerSet() & aLayerMask )[B_Cu] )
325 color = aPlotOpt.ColorSettings()->GetColor( B_Cu );
326
327 if( ( pad->GetLayerSet() & aLayerMask )[F_Cu] )
328 color = color.LegacyMix( aPlotOpt.ColorSettings()->GetColor( F_Cu ) );
329
330 if( sketchPads && aLayerMask[F_Fab] )
331 color = aPlotOpt.ColorSettings()->GetColor( F_Fab );
332 else if( sketchPads && aLayerMask[B_Fab] )
333 color = aPlotOpt.ColorSettings()->GetColor( B_Fab );
334 }
335
336 VECTOR2I margin;
337 int width_adj = 0;
338
339 if( onCopperLayer )
340 width_adj = itemplotter.getFineWidthAdj();
341
342 if( onSolderMaskLayer )
343 margin.x = margin.y = pad->GetSolderMaskExpansion();
344
345 if( onSolderPasteLayer )
346 margin = pad->GetSolderPasteMargin();
347
348 // not all shapes can have a different margin for x and y axis
349 // in fact only oval and rect shapes can have different values.
350 // Round shape have always the same x,y margin
351 // so define a unique value for other shapes that do not support different values
352 int mask_clearance = margin.x;
353
354 // Now offset the pad size by margin + width_adj
355 VECTOR2I padPlotsSize = pad->GetSize() + margin * 2 + VECTOR2I( width_adj, width_adj );
356
357 // Store these parameters that can be modified to plot inflated/deflated pads shape
358 PAD_SHAPE padShape = pad->GetShape();
359 VECTOR2I padSize = pad->GetSize();
360 VECTOR2I padDelta = pad->GetDelta(); // has meaning only for trapezoidal pads
361 double padCornerRadius = pad->GetRoundRectCornerRadius();
362
363 // Don't draw a 0 sized pad.
364 // Note: a custom pad can have its pad anchor with size = 0
365 if( pad->GetShape() != PAD_SHAPE::CUSTOM
366 && ( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 ) )
367 continue;
368
369 switch( pad->GetShape() )
370 {
372 case PAD_SHAPE::OVAL:
373 pad->SetSize( padPlotsSize );
374
375 if( aPlotOpt.GetSkipPlotNPTH_Pads() &&
377 ( pad->GetSize() == pad->GetDrillSize() ) &&
378 ( pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
379 {
380 break;
381 }
382
383 itemplotter.PlotPad( pad, color, padPlotMode );
384 break;
385
386 case PAD_SHAPE::RECT:
387 pad->SetSize( padPlotsSize );
388
389 if( mask_clearance > 0 )
390 {
391 pad->SetShape( PAD_SHAPE::ROUNDRECT );
392 pad->SetRoundRectCornerRadius( mask_clearance );
393 }
394
395 itemplotter.PlotPad( pad, color, padPlotMode );
396 break;
397
399 // inflate/deflate a trapezoid is a bit complex.
400 // so if the margin is not null, build a similar polygonal pad shape,
401 // and inflate/deflate the polygonal shape
402 // because inflating/deflating using different values for y and y
403 // we are using only margin.x as inflate/deflate value
404 if( mask_clearance == 0 )
405 {
406 itemplotter.PlotPad( pad, color, padPlotMode );
407 }
408 else
409 {
410 PAD dummy( *pad );
411 dummy.SetAnchorPadShape( PAD_SHAPE::CIRCLE );
412 dummy.SetShape( PAD_SHAPE::CUSTOM );
413 SHAPE_POLY_SET outline;
414 outline.NewOutline();
415 int dx = padSize.x / 2;
416 int dy = padSize.y / 2;
417 int ddx = padDelta.x / 2;
418 int ddy = padDelta.y / 2;
419
420 outline.Append( -dx - ddy, dy + ddx );
421 outline.Append( dx + ddy, dy - ddx );
422 outline.Append( dx - ddy, -dy + ddx );
423 outline.Append( -dx + ddy, -dy - ddx );
424
425 // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
426 // which can create bad shapes if margin.x is < 0
427 int maxError = aBoard->GetDesignSettings().m_MaxError;
428 int numSegs = GetArcToSegmentCount( mask_clearance, maxError, FULL_CIRCLE );
429 outline.InflateWithLinkedHoles( mask_clearance, numSegs,
431 dummy.DeletePrimitivesList();
432 dummy.AddPrimitivePoly( outline, 0, true );
433
434 // Be sure the anchor pad is not bigger than the deflated shape because this
435 // anchor will be added to the pad shape when plotting the pad. So now the
436 // polygonal shape is built, we can clamp the anchor size
437 dummy.SetSize( VECTOR2I( 0, 0 ) );
438
439 itemplotter.PlotPad( &dummy, color, padPlotMode );
440 }
441
442 break;
443
445 {
446 // rounding is stored as a percent, but we have to change the new radius
447 // to initial_radius + clearance to have a inflated/deflated similar shape
448 int initial_radius = pad->GetRoundRectCornerRadius();
449 pad->SetSize( padPlotsSize );
450 pad->SetRoundRectCornerRadius( std::max( initial_radius + mask_clearance, 0 ) );
451
452 itemplotter.PlotPad( pad, color, padPlotMode );
453 break;
454 }
455
457 if( mask_clearance == 0 )
458 {
459 // the size can be slightly inflated by width_adj (PS/PDF only)
460 pad->SetSize( padPlotsSize );
461 itemplotter.PlotPad( pad, color, padPlotMode );
462 }
463 else
464 {
465 // Due to the polygonal shape of a CHAMFERED_RECT pad, the best way is to
466 // convert the pad shape to a full polygon, inflate/deflate the polygon
467 // and use a dummy CUSTOM pad to plot the final shape.
468 PAD dummy( *pad );
469 // Build the dummy pad outline with coordinates relative to the pad position
470 // and orientation 0. The actual pos and rotation will be taken in account
471 // later by the plot function
472 dummy.SetPosition( VECTOR2I( 0, 0 ) );
473 dummy.SetOrientation( ANGLE_0 );
474 SHAPE_POLY_SET outline;
475 int maxError = aBoard->GetDesignSettings().m_MaxError;
476 int numSegs = GetArcToSegmentCount( mask_clearance, maxError, FULL_CIRCLE );
477 dummy.TransformShapeToPolygon( outline, UNDEFINED_LAYER, 0, maxError,
478 ERROR_INSIDE );
479 outline.InflateWithLinkedHoles( mask_clearance, numSegs,
481
482 // Initialize the dummy pad shape:
483 dummy.SetAnchorPadShape( PAD_SHAPE::CIRCLE );
484 dummy.SetShape( PAD_SHAPE::CUSTOM );
485 dummy.DeletePrimitivesList();
486 dummy.AddPrimitivePoly( outline, 0, true );
487
488 // Be sure the anchor pad is not bigger than the deflated shape because this
489 // anchor will be added to the pad shape when plotting the pad.
490 // So we set the anchor size to 0
491 dummy.SetSize( VECTOR2I( 0, 0 ) );
492 dummy.SetPosition( pad->GetPosition() );
493 dummy.SetOrientation( pad->GetOrientation() );
494
495 itemplotter.PlotPad( &dummy, color, padPlotMode );
496 }
497
498 break;
499
501 {
502 // inflate/deflate a custom shape is a bit complex.
503 // so build a similar pad shape, and inflate/deflate the polygonal shape
504 PAD dummy( *pad );
505 SHAPE_POLY_SET shape;
506 pad->MergePrimitivesAsPolygon( &shape );
507
508 // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
509 // which can create bad shapes if margin.x is < 0
510 int maxError = aBoard->GetDesignSettings().m_MaxError;
511 int numSegs = GetArcToSegmentCount( mask_clearance, maxError, FULL_CIRCLE );
512 shape.InflateWithLinkedHoles( mask_clearance, numSegs, SHAPE_POLY_SET::PM_FAST );
513 dummy.DeletePrimitivesList();
514 dummy.AddPrimitivePoly( shape, 0, true );
515
516 // Be sure the anchor pad is not bigger than the deflated shape because this
517 // anchor will be added to the pad shape when plotting the pad. So now the
518 // polygonal shape is built, we can clamp the anchor size
519 if( mask_clearance < 0 ) // we expect margin.x = margin.y for custom pads
520 dummy.SetSize( padPlotsSize );
521
522 itemplotter.PlotPad( &dummy, color, padPlotMode );
523 break;
524 }
525 }
526
527 // Restore the pad parameters modified by the plot code
528 pad->SetSize( padSize );
529 pad->SetDelta( padDelta );
530 pad->SetShape( padShape );
531 pad->SetRoundRectCornerRadius( padCornerRadius );
532 }
533
534 aPlotter->EndBlock( nullptr );
535 aPlotter->Bookmark( footprint->GetBoundingBox(), footprint->GetReference(), _( "Footprints" ) );
536 }
537
538 // Plot vias on copper layers, and if aPlotOpt.GetPlotViaOnMaskLayer() is true,
539 // plot them on solder mask
540
541 GBR_METADATA gbr_metadata;
542
543 bool isOnCopperLayer = ( aLayerMask & LSET::AllCuMask() ).any();
544
545 if( isOnCopperLayer )
546 {
549 }
550
551 aPlotter->StartBlock( nullptr );
552
553 for( const PCB_TRACK* track : aBoard->Tracks() )
554 {
555 const PCB_VIA* via = dyn_cast<const PCB_VIA*>( track );
556
557 if( !via )
558 continue;
559
560 // vias are not plotted if not on selected layer, but if layer is SOLDERMASK_LAYER_BACK
561 // or SOLDERMASK_LAYER_FRONT, vias are drawn only if they are on the corresponding
562 // external copper layer
563 LSET via_mask_layer = via->GetLayerSet();
564
565 if( aPlotOpt.GetPlotViaOnMaskLayer() )
566 {
567 if( via_mask_layer[B_Cu] )
568 via_mask_layer.set( B_Mask );
569
570 if( via_mask_layer[F_Cu] )
571 via_mask_layer.set( F_Mask );
572 }
573
574 if( !( via_mask_layer & aLayerMask ).any() )
575 continue;
576
577 int via_margin = 0;
578 double width_adj = 0;
579
580 if( aLayerMask[B_Mask] || aLayerMask[F_Mask] )
581 via_margin = via->GetSolderMaskExpansion();
582
583 if( ( aLayerMask & LSET::AllCuMask() ).any() )
584 width_adj = itemplotter.getFineWidthAdj();
585
586 int diameter = via->GetWidth() + 2 * via_margin + width_adj;
587
589 if( onCopperLayer && !via->FlashLayer( aLayerMask ) )
590 continue;
591
592 // Don't draw a null size item :
593 if( diameter <= 0 )
594 continue;
595
596 // Some vias can be not connected (no net).
597 // Set the m_NotInNet for these vias to force a empty net name in gerber file
598 gbr_metadata.m_NetlistMetadata.m_NotInNet = via->GetNetname().IsEmpty();
599
600 gbr_metadata.SetNetName( via->GetNetname() );
601
602 COLOR4D color = aPlotOpt.ColorSettings()->GetColor(
603 LAYER_VIAS + static_cast<int>( via->GetViaType() ) );
604
605 // Set plot color (change WHITE to LIGHTGRAY because the white items are not seen on a
606 // white paper or screen
607 aPlotter->SetColor( color != WHITE ? color : LIGHTGRAY );
608 aPlotter->FlashPadCircle( via->GetStart(), diameter, plotMode, &gbr_metadata );
609 }
610
611 aPlotter->EndBlock( nullptr );
612 aPlotter->StartBlock( nullptr );
614
615 // Plot tracks (not vias) :
616 for( const PCB_TRACK* track : aBoard->Tracks() )
617 {
618 if( track->Type() == PCB_VIA_T )
619 continue;
620
621 if( !aLayerMask[track->GetLayer()] )
622 continue;
623
624 // Some track segments can be not connected (no net).
625 // Set the m_NotInNet for these segments to force a empty net name in gerber file
626 gbr_metadata.m_NetlistMetadata.m_NotInNet = track->GetNetname().IsEmpty();
627
628 gbr_metadata.SetNetName( track->GetNetname() );
629 int width = track->GetWidth() + itemplotter.getFineWidthAdj();
630 aPlotter->SetColor( itemplotter.getColor( track->GetLayer() ) );
631
632 if( track->Type() == PCB_ARC_T )
633 {
634 const PCB_ARC* arc = static_cast<const PCB_ARC*>( track );
635
636 // ThickArc expects only positive angle arcs, so flip start/end if
637 // we are negative
638 if( arc->GetAngle() < ANGLE_0 )
639 {
640 aPlotter->ThickArc( arc->GetCenter(), arc->GetEnd(), arc->GetStart(),
641 width, plotMode, &gbr_metadata );
642 }
643 else
644 {
645 aPlotter->ThickArc( arc->GetCenter(), arc->GetStart(), arc->GetEnd(),
646 width, plotMode, &gbr_metadata );
647 }
648 }
649 else
650 {
651 aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode,
652 &gbr_metadata );
653 }
654 }
655
656 aPlotter->EndBlock( nullptr );
657
658 // Plot filled ares
659 aPlotter->StartBlock( nullptr );
660
661 NETINFO_ITEM nonet( aBoard );
662
663 for( const ZONE* zone : aBoard->Zones() )
664 {
665 for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
666 {
667 if( !aLayerMask[layer] )
668 continue;
669
670 SHAPE_POLY_SET mainArea = zone->GetFilledPolysList( layer )->CloneDropTriangulation();
671 SHAPE_POLY_SET islands;
672
673 for( int i = mainArea.OutlineCount() - 1; i >= 0; i-- )
674 {
675 if( zone->IsIsland( layer, i ) )
676 {
677 islands.AddOutline( mainArea.CPolygon( i )[0] );
678 mainArea.DeletePolygon( i );
679 }
680 }
681
682 itemplotter.PlotFilledAreas( zone, layer, mainArea );
683
684 if( !islands.IsEmpty() )
685 {
686 ZONE dummy( *zone );
687 dummy.SetNet( &nonet );
688 itemplotter.PlotFilledAreas( &dummy, layer, islands );
689 }
690 }
691 }
692
693 aPlotter->EndBlock( nullptr );
694
695 // Adding drill marks, if required and if the plotter is able to plot them:
697 itemplotter.PlotDrillMarks();
698}
699
700
704void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
705 const PCB_PLOT_PARAMS& aPlotOpt )
706{
707 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
708 itemplotter.SetLayerSet( aLayerMask );
709
710 SHAPE_POLY_SET outlines;
711
712 for( LSEQ seq = aLayerMask.Seq( aLayerMask.SeqStackupBottom2Top() ); seq; ++seq )
713 {
714 PCB_LAYER_ID layer = *seq;
715
716 outlines.RemoveAllContours();
717 aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines );
718
720
721 // Plot outlines
722 std::vector<VECTOR2I> cornerList;
723
724 // Now we have one or more basic polygons: plot each polygon
725 for( int ii = 0; ii < outlines.OutlineCount(); ii++ )
726 {
727 for( int kk = 0; kk <= outlines.HoleCount(ii); kk++ )
728 {
729 cornerList.clear();
730 const SHAPE_LINE_CHAIN& path =
731 ( kk == 0 ) ? outlines.COutline( ii ) : outlines.CHole( ii, kk - 1 );
732
733 aPlotter->PlotPoly( path, FILL_T::NO_FILL );
734 }
735 }
736
737 // Plot pad holes
739 {
740 int smallDrill = ( aPlotOpt.GetDrillMarksType() == DRILL_MARKS::SMALL_DRILL_SHAPE )
742 INT_MAX;
743
744 for( FOOTPRINT* footprint : aBoard->Footprints() )
745 {
746 for( PAD* pad : footprint->Pads() )
747 {
748 if( pad->HasHole() )
749 {
750 std::shared_ptr<SHAPE_SEGMENT> slot = pad->GetEffectiveHoleShape();
751
752 if( slot->GetSeg().A == slot->GetSeg().B ) // circular hole
753 {
754 int drill = std::min( smallDrill, slot->GetWidth() );
755 aPlotter->Circle( pad->GetPosition(), drill, FILL_T::NO_FILL );
756 }
757 else
758 {
759 // Note: small drill marks have no significance when applied to slots
760 aPlotter->ThickSegment( slot->GetSeg().A,
761 slot->GetSeg().B,
762 slot->GetWidth(), SKETCH, nullptr );
763 }
764 }
765 }
766 }
767 }
768
769 // Plot vias holes
770 for( PCB_TRACK* track : aBoard->Tracks() )
771 {
772 const PCB_VIA* via = dyn_cast<const PCB_VIA*>( track );
773
774 if( via && via->IsOnLayer( layer ) ) // via holes can be not through holes
775 aPlotter->Circle( via->GetPosition(), via->GetDrillValue(), FILL_T::NO_FILL );
776 }
777 }
778}
779
780
811#define NEW_ALGO 1
812
813void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
814 const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness )
815{
816 int maxError = aBoard->GetDesignSettings().m_MaxError;
817 PCB_LAYER_ID layer = aLayerMask[B_Mask] ? B_Mask : F_Mask;
818 SHAPE_POLY_SET buffer;
819 SHAPE_POLY_SET* boardOutline = nullptr;
820
821 if( aBoard->GetBoardPolygonOutlines( buffer ) )
822 boardOutline = &buffer;
823
824 // We remove 1nm as we expand both sides of the shapes, so allowing for a strictly greater
825 // than or equal comparison in the shape separation (boolean add)
826 int inflate = aMinThickness / 2 - 1;
827
828 BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
829 itemplotter.SetLayerSet( aLayerMask );
830
831 for( FOOTPRINT* footprint : aBoard->Footprints() )
832 itemplotter.PlotFootprintTextItems( footprint );
833
834 // Build polygons for each pad shape. The size of the shape on solder mask should be size
835 // of pad + clearance around the pad, where clearance = solder mask clearance + extra margin.
836 // Extra margin is half the min width for solder mask, which is used to merge too-close shapes
837 // (distance < aMinThickness), and will be removed when creating the actual shapes.
838
839 // Will contain shapes inflated by inflate value that will be merged and deflated by
840 // inflate value to build final polygons
841 // After calculations the remaining polygons are polygons to plot
842 SHAPE_POLY_SET areas;
843
844 // Will contain exact shapes of all items on solder mask
845 SHAPE_POLY_SET initialPolys;
846
847#if NEW_ALGO
848 // Generate polygons with arcs inside the shape or exact shape to minimize shape changes
849 // created by arc to segment size correction.
851#endif
852 {
853 // Plot footprint pads and graphics
854 for( const FOOTPRINT* footprint : aBoard->Footprints() )
855 {
856 // add shapes with their exact mask layer size in initialPolys
857 footprint->TransformPadsToPolySet( initialPolys, layer, 0, maxError, ERROR_OUTSIDE );
858 // add shapes inflated by aMinThickness/2 in areas
859 footprint->TransformPadsToPolySet( areas, layer, inflate, maxError, ERROR_OUTSIDE );
860
861 for( const BOARD_ITEM* item : footprint->GraphicalItems() )
862 {
863 if( item->Type() == PCB_FP_SHAPE_T && item->IsOnLayer( layer ) )
864 {
865 // add shapes with their exact mask layer size in initialPolys
866 item->TransformShapeToPolygon( initialPolys, layer, 0, maxError, ERROR_OUTSIDE );
867
868 // add shapes inflated by aMinThickness/2 in areas
869 item->TransformShapeToPolygon( areas, layer, inflate, maxError, ERROR_OUTSIDE );
870 }
871 else if( item->Type() == PCB_FP_SHAPE_T && item->IsOnLayer( Edge_Cuts ) )
872 {
873 itemplotter.PlotFootprintShape( static_cast<const FP_SHAPE*>( item ) );
874 }
875 }
876 }
877
878 // Plot (untented) vias
879 for( const PCB_TRACK* track : aBoard->Tracks() )
880 {
881 const PCB_VIA* via = dyn_cast<const PCB_VIA*>( track );
882
883 // Note: IsOnLayer() checks relevant mask layers of untented vias
884 if( !via || !via->IsOnLayer( layer ) )
885 continue;
886
887 int clearance = via->GetSolderMaskExpansion();
888
889 // add shapes with their exact mask layer size in initialPolys
890 via->TransformShapeToPolygon( initialPolys, layer, clearance, maxError, ERROR_OUTSIDE );
891
892 // add shapes inflated by aMinThickness/2 in areas
893 clearance += inflate;
894 via->TransformShapeToPolygon( areas, layer, clearance, maxError, ERROR_OUTSIDE );
895 }
896
897 // Add filled zone areas.
898#if 0 // Set to 1 if a solder mask expansion must be applied to zones on solder mask
899 int zone_margin = aBoard->GetDesignSettings().m_SolderMaskExpansion;
900#else
901 int zone_margin = 0;
902#endif
903
904 for( const BOARD_ITEM* item : aBoard->Drawings() )
905 {
906 if( item->IsOnLayer( layer ) )
907 {
908 // add shapes with their exact mask layer size in initialPolys
909 item->TransformShapeToPolygon( initialPolys, layer, 0, maxError, ERROR_OUTSIDE );
910 // add shapes inflated by aMinThickness/2 in areas
911 item->TransformShapeToPolygon( areas, layer, inflate, maxError, ERROR_OUTSIDE );
912 }
913 else if( item->IsOnLayer( Edge_Cuts ) )
914 {
915 itemplotter.PlotPcbGraphicItem( item );
916 }
917 }
918
919 for( ZONE* zone : aBoard->Zones() )
920 {
921 if( !zone->IsOnLayer( layer ) )
922 continue;
923
924 // add shapes inflated by aMinThickness/2 in areas
925 zone->TransformSmoothedOutlineToPolygon( areas, inflate + zone_margin, maxError,
926 ERROR_OUTSIDE, boardOutline );
927
928 // add shapes with their exact mask layer size in initialPolys
929 zone->TransformSmoothedOutlineToPolygon( initialPolys, zone_margin, maxError,
930 ERROR_OUTSIDE, boardOutline );
931 }
932 }
933
934 int numSegs = GetArcToSegmentCount( inflate, maxError, FULL_CIRCLE );
935
936 // Merge all polygons: After deflating, not merged (not overlapping) polygons
937 // will have the initial shape (with perhaps small changes due to deflating transform)
939 areas.Deflate( inflate, numSegs );
940
941#if !NEW_ALGO
942 // To avoid a lot of code, use a ZONE to handle and plot polygons, because our polygons look
943 // exactly like filled areas in zones.
944 // Note, also this code is not optimized: it creates a lot of copy/duplicate data.
945 // However it is not complex, and fast enough for plot purposes (copy/convert data is only a
946 // very small calculation time for these calculations).
947 ZONE zone( aBoard );
948 zone.SetMinThickness( 0 ); // trace polygons only
949 zone.SetLayer( layer );
950
951 // Combine the current areas to initial areas. This is mandatory because inflate/deflate
952 // transform is not perfect, and we want the initial areas perfectly kept
953 areas.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST );
955
956 itemplotter.PlotFilledAreas( &zone, layer, areas );
957#else
958
959 // Remove initial shapes: each shape will be added later, as flashed item or region
960 // with a suitable attribute.
961 // Do not merge pads is mandatory in Gerber files: They must be identified as pads
962
963 // we deflate areas in polygons, to avoid after subtracting initial shapes
964 // having small artifacts due to approximations during polygon transforms
966
967 // Slightly inflate polygons to avoid any gap between them and other shapes,
968 // These gaps are created by arc to segments approximations
969 areas.Inflate( pcbIUScale.mmToIU( 0.002 ), 6 );
970
971 // Now, only polygons with a too small thickness are stored in areas.
973
974 // Plot each initial shape (pads and polygons on mask layer), with suitable attributes:
975 PlotStandardLayer( aBoard, aPlotter, aLayerMask, aPlotOpt );
976
977 for( int ii = 0; ii < areas.OutlineCount(); ii++ )
978 {
979 const SHAPE_LINE_CHAIN& path = areas.COutline( ii );
980
981 // polygon area in mm^2 :
982 double curr_area = path.Area() / ( pcbIUScale.IU_PER_MM * pcbIUScale.IU_PER_MM );
983
984 // Skip very small polygons: they are certainly artifacts created by
985 // arc approximations and polygon transforms
986 // (inflate/deflate transforms)
987 constexpr double poly_min_area_mm2 = 0.01; // 0.01 mm^2 gives a good filtering
988
989 if( curr_area < poly_min_area_mm2 )
990 continue;
991
992 aPlotter->PlotPoly( path, FILL_T::FILLED_SHAPE );
993 }
994#endif
995}
996
997
1004static void initializePlotter( PLOTTER* aPlotter, const BOARD* aBoard,
1005 const PCB_PLOT_PARAMS* aPlotOpts )
1006{
1007 PAGE_INFO pageA4( wxT( "A4" ) );
1008 const PAGE_INFO& pageInfo = aBoard->GetPageSettings();
1009 const PAGE_INFO* sheet_info;
1010 double paperscale; // Page-to-paper ratio
1011 VECTOR2I paperSizeIU;
1012 VECTOR2I pageSizeIU( pageInfo.GetSizeIU( pcbIUScale.IU_PER_MILS ) );
1013 bool autocenter = false;
1014
1015 // Special options: to fit the sheet to an A4 sheet replace the paper size. However there
1016 // is a difference between the autoscale and the a4paper option:
1017 // - Autoscale fits the board to the paper size
1018 // - A4paper fits the original paper size to an A4 sheet
1019 // - Both of them fit the board to an A4 sheet
1020 if( aPlotOpts->GetA4Output() )
1021 {
1022 sheet_info = &pageA4;
1023 paperSizeIU = pageA4.GetSizeIU( pcbIUScale.IU_PER_MILS );
1024 paperscale = (double) paperSizeIU.x / pageSizeIU.x;
1025 autocenter = true;
1026 }
1027 else
1028 {
1029 sheet_info = &pageInfo;
1030 paperSizeIU = pageSizeIU;
1031 paperscale = 1;
1032
1033 // Need autocentering only if scale is not 1:1
1034 autocenter = (aPlotOpts->GetScale() != 1.0);
1035 }
1036
1037 BOX2I bbox = aBoard->ComputeBoundingBox();
1038 VECTOR2I boardCenter = bbox.Centre();
1039 VECTOR2I boardSize = bbox.GetSize();
1040
1041 double compound_scale;
1042
1043 // Fit to 80% of the page if asked; it could be that the board is empty, in this case
1044 // regress to 1:1 scale
1045 if( aPlotOpts->GetAutoScale() && boardSize.x > 0 && boardSize.y > 0 )
1046 {
1047 double xscale = (paperSizeIU.x * 0.8) / boardSize.x;
1048 double yscale = (paperSizeIU.y * 0.8) / boardSize.y;
1049
1050 compound_scale = std::min( xscale, yscale ) * paperscale;
1051 }
1052 else
1053 {
1054 compound_scale = aPlotOpts->GetScale() * paperscale;
1055 }
1056
1057 // For the plot offset we have to keep in mind the auxiliary origin too: if autoscaling is
1058 // off we check that plot option (i.e. autoscaling overrides auxiliary origin)
1059 VECTOR2I offset( 0, 0);
1060
1061 if( autocenter )
1062 {
1063 offset.x = KiROUND( boardCenter.x - ( paperSizeIU.x / 2.0 ) / compound_scale );
1064 offset.y = KiROUND( boardCenter.y - ( paperSizeIU.y / 2.0 ) / compound_scale );
1065 }
1066 else
1067 {
1068 if( aPlotOpts->GetUseAuxOrigin() )
1069 offset = aBoard->GetDesignSettings().GetAuxOrigin();
1070 }
1071
1072 aPlotter->SetPageSettings( *sheet_info );
1073
1074 aPlotter->SetViewport( offset, pcbIUScale.IU_PER_MILS/10, compound_scale, aPlotOpts->GetMirror() );
1075
1076 // Has meaning only for gerber plotter. Must be called only after SetViewport
1077 aPlotter->SetGerberCoordinatesFormat( aPlotOpts->GetGerberPrecision() );
1078
1079 // Has meaning only for SVG plotter. Must be called only after SetViewport
1080 aPlotter->SetSvgCoordinatesFormat( aPlotOpts->GetSvgPrecision() );
1081
1082 aPlotter->SetCreator( wxT( "PCBNEW" ) );
1083 aPlotter->SetColorMode( !aPlotOpts->GetBlackAndWhite() ); // default is plot in Black and White.
1084 aPlotter->SetTextMode( aPlotOpts->GetTextMode() );
1085}
1086
1087
1091static void FillNegativeKnockout( PLOTTER *aPlotter, const BOX2I &aBbbox )
1092{
1093 const int margin = 5 * pcbIUScale.IU_PER_MM; // Add a 5 mm margin around the board
1094 aPlotter->SetNegative( true );
1095 aPlotter->SetColor( WHITE ); // Which will be plotted as black
1096
1097 BOX2I area = aBbbox;
1098 area.Inflate( margin );
1099 aPlotter->Rect( area.GetOrigin(), area.GetEnd(), FILL_T::FILLED_SHAPE );
1100 aPlotter->SetColor( BLACK );
1101}
1102
1103
1107static void ConfigureHPGLPenSizes( HPGL_PLOTTER *aPlotter, const PCB_PLOT_PARAMS *aPlotOpts )
1108{
1109 // Compute penDiam (the value is given in mils) in pcb units, with plot scale (if Scale is 2,
1110 // penDiam value is always m_HPGLPenDiam so apparent penDiam is actually penDiam / Scale
1111 int penDiam = KiROUND( aPlotOpts->GetHPGLPenDiameter() * pcbIUScale.IU_PER_MILS / aPlotOpts->GetScale() );
1112
1113 // Set HPGL-specific options and start
1114 aPlotter->SetPenSpeed( aPlotOpts->GetHPGLPenSpeed() );
1115 aPlotter->SetPenNumber( aPlotOpts->GetHPGLPenNum() );
1116 aPlotter->SetPenDiameter( penDiam );
1117}
1118
1119
1126PLOTTER* StartPlotBoard( BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer,
1127 const wxString& aFullFileName, const wxString& aSheetName,
1128 const wxString& aSheetPath )
1129{
1130 // Create the plotter driver and set the few plotter specific options
1131 PLOTTER* plotter = nullptr;
1132
1133 switch( aPlotOpts->GetFormat() )
1134 {
1135 case PLOT_FORMAT::DXF:
1136 DXF_PLOTTER* DXF_plotter;
1137 DXF_plotter = new DXF_PLOTTER();
1138 DXF_plotter->SetUnits( aPlotOpts->GetDXFPlotUnits() );
1139
1140 plotter = DXF_plotter;
1141 break;
1142
1143 case PLOT_FORMAT::POST:
1144 PS_PLOTTER* PS_plotter;
1145 PS_plotter = new PS_PLOTTER();
1146 PS_plotter->SetScaleAdjust( aPlotOpts->GetFineScaleAdjustX(),
1147 aPlotOpts->GetFineScaleAdjustY() );
1148 plotter = PS_plotter;
1149 break;
1150
1151 case PLOT_FORMAT::PDF:
1152 plotter = new PDF_PLOTTER();
1153 break;
1154
1155 case PLOT_FORMAT::HPGL:
1156 HPGL_PLOTTER* HPGL_plotter;
1157 HPGL_plotter = new HPGL_PLOTTER();
1158
1159 // HPGL options are a little more convoluted to compute, so they get their own function
1160 ConfigureHPGLPenSizes( HPGL_plotter, aPlotOpts );
1161 plotter = HPGL_plotter;
1162 break;
1163
1165 // For Gerber plotter, a valid board layer must be set, in order to create a valid
1166 // Gerber header, especially the TF.FileFunction and .FilePolarity data
1167 if( aLayer < PCBNEW_LAYER_ID_START || aLayer >= PCB_LAYER_ID_COUNT )
1168 {
1169 wxLogError( wxString::Format(
1170 "Invalid board layer %d, cannot build a valid Gerber file header",
1171 aLayer ) );
1172 }
1173
1174 plotter = new GERBER_PLOTTER();
1175 break;
1176
1177 case PLOT_FORMAT::SVG:
1178 plotter = new SVG_PLOTTER();
1179 break;
1180
1181 default:
1182 wxASSERT( false );
1183 return nullptr;
1184 }
1185
1187 renderSettings->LoadColors( aPlotOpts->ColorSettings() );
1188 renderSettings->SetDefaultPenWidth( pcbIUScale.mmToIU( 0.0212 ) ); // Hairline at 1200dpi
1189
1190 if( aLayer >= 0 && aLayer < GAL_LAYER_ID_END )
1191 renderSettings->SetLayerName( aBoard->GetLayerName( ToLAYER_ID( aLayer ) ) );
1192
1193 plotter->SetRenderSettings( renderSettings );
1194
1195 // Compute the viewport and set the other options
1196
1197 // page layout is not mirrored, so temporarily change mirror option for the page layout
1198 PCB_PLOT_PARAMS plotOpts = *aPlotOpts;
1199
1200 if( plotOpts.GetPlotFrameRef() && plotOpts.GetMirror() )
1201 plotOpts.SetMirror( false );
1202
1203 initializePlotter( plotter, aBoard, &plotOpts );
1204
1205 if( plotter->OpenFile( aFullFileName ) )
1206 {
1207 plotter->ClearHeaderLinesList();
1208
1209 // For the Gerber "file function" attribute, set the layer number
1210 if( plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1211 {
1212 bool useX2mode = plotOpts.GetUseGerberX2format();
1213
1214 GERBER_PLOTTER* gbrplotter = static_cast <GERBER_PLOTTER*> ( plotter );
1215 gbrplotter->DisableApertMacros( plotOpts.GetDisableGerberMacros() );
1216 gbrplotter->UseX2format( useX2mode );
1217 gbrplotter->UseX2NetAttributes( plotOpts.GetIncludeGerberNetlistInfo() );
1218
1219 // Attributes can be added using X2 format or as comment (X1 format)
1220 AddGerberX2Attribute( plotter, aBoard, aLayer, not useX2mode );
1221 }
1222
1223 plotter->StartPlot( wxT( "1" ) );
1224
1225 // Plot the frame reference if requested
1226 if( aPlotOpts->GetPlotFrameRef() )
1227 {
1228 PlotDrawingSheet( plotter, aBoard->GetProject(), aBoard->GetTitleBlock(),
1229 aBoard->GetPageSettings(), &aBoard->GetProperties(), wxT( "1" ), 1,
1230 aSheetName, aSheetPath, aBoard->GetFileName() );
1231
1232 if( aPlotOpts->GetMirror() )
1233 initializePlotter( plotter, aBoard, aPlotOpts );
1234 }
1235
1236 // When plotting a negative board: draw a black rectangle (background for plot board
1237 // in white) and switch the current color to WHITE; note the color inversion is actually
1238 // done in the driver (if supported)
1239 if( aPlotOpts->GetNegative() )
1240 {
1241 BOX2I bbox = aBoard->ComputeBoundingBox();
1242 FillNegativeKnockout( plotter, bbox );
1243 }
1244
1245 return plotter;
1246 }
1247
1248 delete plotter->RenderSettings();
1249 delete plotter;
1250 return nullptr;
1251}
int color
Definition: DXF_plotter.cpp:57
const char * name
Definition: DXF_plotter.cpp:56
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
const VECTOR2I & GetAuxOrigin()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:70
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:269
const PAGE_INFO & GetPageSettings() const
Definition: board.h:632
ZONES & Zones()
Definition: board.h:317
void ConvertBrdLayerToPolygonalContours(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aOutlines) const
Build a set of polygons which are the outlines of copper items (pads, tracks, vias,...
Definition: board.cpp:2272
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
Definition: board.cpp:1972
TITLE_BLOCK & GetTitleBlock()
Definition: board.h:638
BOX2I ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1253
FOOTPRINTS & Footprints()
Definition: board.h:311
const std::map< wxString, wxString > & GetProperties() const
Definition: board.h:338
TRACKS & Tracks()
Definition: board.h:308
const wxString & GetFileName() const
Definition: board.h:306
DRAWINGS & Drawings()
Definition: board.h:314
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:474
PROJECT * GetProject() const
Definition: board.h:446
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:704
const Vec & GetOrigin() const
Definition: box2.h:183
const Vec GetEnd() const
Definition: box2.h:185
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
Vec Centre() const
Definition: box2.h:70
const Vec & GetSize() const
Definition: box2.h:179
void PlotDrillMarks()
Draw a drill mark for pads and vias.
void SetLayerSet(LSET aLayerMask)
Definition: pcbplot.h:80
void PlotPcbGraphicItem(const BOARD_ITEM *item)
void PlotFilledAreas(const ZONE *aZone, PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
void PlotPad(const PAD *aPad, const COLOR4D &aColor, OUTLINE_MODE aPlotMode)
Plot a pad.
void PlotFootprintShape(const FP_SHAPE *aShape)
COLOR4D getColor(int aLayer) const
White color is special because it cannot be seen on a white paper in B&W mode.
void PlotBoardGraphicItems()
Plot items like text and graphics but not tracks and footprints.
void PlotFootprintTextItems(const FOOTPRINT *aFootprint)
int getFineWidthAdj() const
Definition: pcbplot.h:71
void PlotFootprintGraphicItems(const FOOTPRINT *aFootprint)
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_VIAPAD
aperture used for vias.
Definition: gbr_metadata.h:102
Metadata which can be added in a gerber file as attribute in X2 format.
Definition: gbr_metadata.h:205
void SetNetName(const wxString &aNetname)
Definition: gbr_metadata.h:229
void SetApertureAttrib(GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB aApertAttribute)
Definition: gbr_metadata.h:209
GBR_NETLIST_METADATA m_NetlistMetadata
An item to handle object attribute.
Definition: gbr_metadata.h:262
void SetNetAttribType(int aNetAttribType)
Definition: gbr_metadata.h:219
@ GBR_NETINFO_NET
print info associated to a net (TO.N attribute)
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.
virtual void SetPenSpeed(int speed)
Definition: plotter_hpgl.h:85
virtual void SetPenNumber(int number)
Definition: plotter_hpgl.h:90
virtual void SetPenDiameter(double diameter)
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:102
PCB specific render settings.
Definition: pcb_painter.h:72
void LoadColors(const COLOR_SETTINGS *aSettings) override
void SetDefaultPenWidth(int aWidth)
void SetLayerName(const wxString &aLayerName)
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:493
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:532
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
LSEQ SeqStackupBottom2Top() const
Return the sequence that is typical for a bottom-to-top stack-up.
Definition: lset.cpp:475
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:773
Handle the data for a net.
Definition: netinfo.h:67
Definition: pad.h:60
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:54
const VECTOR2I GetSizeIU(double aIUScale) const
Gets the page size in internal units.
Definition: page_info.h:162
EDA_ANGLE GetAngle() const
Definition: pcb_track.cpp:1146
virtual VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pcb_track.h:322
Parameters and options when plotting/printing a board.
bool GetNegative() const
PLOT_FORMAT GetFormat() const
bool GetSkipPlotNPTH_Pads() const
void SetDrillMarksType(DRILL_MARKS aVal)
bool GetUseAuxOrigin() const
void SetSkipPlotNPTH_Pads(bool aSkip)
bool GetMirror() const
DXF_UNITS GetDXFPlotUnits() const
bool GetAutoScale() const
PLOT_TEXT_MODE GetTextMode() const
double GetHPGLPenDiameter() const
unsigned GetSvgPrecision() const
unsigned GetBlackAndWhite() const
double GetScale() const
bool GetDXFPlotPolygonMode() const
void SetMirror(bool aFlag)
bool GetSketchPadsOnFabLayers() const
bool GetSubtractMaskFromSilk() const
int GetGerberPrecision() const
int GetHPGLPenSpeed() const
double GetFineScaleAdjustY() const
bool GetA4Output() const
int GetHPGLPenNum() const
DRILL_MARKS GetDrillMarksType() const
bool GetUseGerberX2format() const
bool GetIncludeGerberNetlistInfo() const
double GetFineScaleAdjustX() const
bool GetPlotFrameRef() const
bool GetPlotViaOnMaskLayer() const
bool GetDisableGerberMacros() const
OUTLINE_MODE GetPlotMode() const
COLOR_SETTINGS * ColorSettings() const
const VECTOR2I & GetStart() const
Definition: pcb_track.h:114
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:111
Base plotter engine class.
Definition: plotter.h:110
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:549
virtual void Circle(const VECTOR2I &pos, int diametre, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)=0
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition: plotter.cpp:74
virtual void SetNegative(bool aNegative)
Definition: plotter.h:130
virtual void SetSvgCoordinatesFormat(unsigned aPrecision)
Set the number of digits for mantissa in coordinates in mm for SVG plotter.
Definition: plotter.h:526
virtual void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: plotter.h:143
void SetRenderSettings(RENDER_SETTINGS *aSettings)
Definition: plotter.h:140
virtual bool StartPlot(const wxString &aPageNumber)=0
RENDER_SETTINGS * RenderSettings()
Definition: plotter.h:141
virtual void SetGerberCoordinatesFormat(int aResolution, bool aUseInches=false)
Definition: plotter.h:520
virtual void Bookmark(const BOX2I &aBox, const wxString &aName, const wxString &aGroupName=wxEmptyString)
Create a bookmark to a symbol.
Definition: plotter.h:477
virtual PLOT_FORMAT GetPlotterType() const =0
Returns the effective plot engine in use.
virtual void SetTextMode(PLOT_TEXT_MODE mode)
Change the current text mode.
Definition: plotter.h:515
virtual void SetCreator(const wxString &aCreator)
Definition: plotter.h:159
void ClearHeaderLinesList()
Remove all lines from the list of free lines to print at the beginning of the file.
Definition: plotter.h:176
virtual void FlashPadCircle(const VECTOR2I &aPadPos, int aDiameter, OUTLINE_MODE aTraceMode, void *aData)=0
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:137
virtual void StartBlock(void *aData)
calling this function allows one to define the beginning of a group of drawing items,...
Definition: plotter.h:538
virtual void PlotPoly(const std::vector< VECTOR2I > &aCornerList, FILL_T aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=nullptr)=0
Draw a polygon ( filled or not ).
virtual void HyperlinkMenu(const BOX2I &aBox, const std::vector< wxString > &aDestURLs)
Create a clickable hyperlink menu with a rectangular click area.
Definition: plotter.h:466
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:506
virtual void Rect(const VECTOR2I &p1, const VECTOR2I &p2, FILL_T fill, int width=USE_DEFAULT_LINE_WIDTH)=0
virtual void ThickArc(const VECTOR2I &aCentre, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aWidth, OUTLINE_MODE aTraceMode, void *aData)
Definition: plotter.cpp:592
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:547
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 BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
void DeletePolygon(int aIdx)
Delete aIdx-th polygon and its triangulation data from the set.
bool IsEmpty() const
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=CHAMFER_ALL_CORNERS)
void Inflate(int aAmount, int aCircleSegCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Return the reference to aIndex-th outline in the set.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
void Simplify(POLYGON_MODE aFastMode)
int NewOutline()
Creates a new hole in a given outline.
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
int OutlineCount() const
Return the number of vertices in a given outline/hole.
SHAPE_POLY_SET CloneDropTriangulation() const
Creates a new empty polygon in the set and returns its index.
void InflateWithLinkedHoles(int aFactor, int aCircleSegmentsCount, POLYGON_MODE aFastMode)
Perform outline inflation/deflation, using round corners.
const POLYGON & CPolygon(int aIndex) const
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
void SetMinThickness(int aMinThickness)
Definition: zone.h:252
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: zone.cpp:266
@ WHITE
Definition: color4d.h:46
@ LIGHTGRAY
Definition: color4d.h:45
@ BLACK
Definition: color4d.h:42
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)
#define _(s)
static constexpr EDA_ANGLE & FULL_CIRCLE
Definition: eda_angle.h:427
static constexpr EDA_ANGLE & ANGLE_0
Definition: eda_angle.h:429
@ FILLED_SHAPE
Handle special data (items attributes) during plot.
a few functions useful in geometry calculations.
@ ERROR_OUTSIDE
@ ERROR_INSIDE
int GetArcToSegmentCount(int aRadius, int aErrorMax, const EDA_ANGLE &aArcAngle)
double m_SmallDrillMarkSize
The diameter of the drill marks on print and plot outputs (in mm), when the "Drill marks" option is s...
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:827
@ GAL_LAYER_ID_END
Definition: layer_ids.h:260
@ LAYER_VIAS
Meta control for all vias opacity/visibility.
Definition: layer_ids.h:193
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ F_CrtYd
Definition: layer_ids.h:117
@ B_Adhes
Definition: layer_ids.h:97
@ Edge_Cuts
Definition: layer_ids.h:113
@ Dwgs_User
Definition: layer_ids.h:109
@ F_Paste
Definition: layer_ids.h:101
@ Cmts_User
Definition: layer_ids.h:110
@ F_Adhes
Definition: layer_ids.h:98
@ B_Mask
Definition: layer_ids.h:106
@ B_Cu
Definition: layer_ids.h:95
@ Eco1_User
Definition: layer_ids.h:111
@ F_Mask
Definition: layer_ids.h:107
@ B_Paste
Definition: layer_ids.h:100
@ F_Fab
Definition: layer_ids.h:120
@ Margin
Definition: layer_ids.h:114
@ F_SilkS
Definition: layer_ids.h:104
@ B_CrtYd
Definition: layer_ids.h:116
@ UNDEFINED_LAYER
Definition: layer_ids.h:60
@ Eco2_User
Definition: layer_ids.h:112
@ B_SilkS
Definition: layer_ids.h:103
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:137
@ F_Cu
Definition: layer_ids.h:64
@ B_Fab
Definition: layer_ids.h:119
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:932
OUTLINE_MODE
Definition: outline_mode.h:25
@ SKETCH
Definition: outline_mode.h:26
@ NPTH
like PAD_PTH, but not plated
PAD_SHAPE
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: pad_shapes.h:35
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:342
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 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, LSET aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
Plot a copper layer or mask.
static void PlotSolderMaskLayer(BOARD *aBoard, PLOTTER *aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt, int aMinThickness)
void PlotInteractiveLayer(BOARD *aBoard, PLOTTER *aPlotter)
Plot interactive items (hypertext links, properties, etc.).
void PlotOneBoardLayer(BOARD *aBoard, PLOTTER *aPlotter, PCB_LAYER_ID aLayer, const PCB_PLOT_PARAMS &aPlotOpt)
Plot one copper or technical layer.
void PlotLayerOutlines(BOARD *aBoard, PLOTTER *aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
Plot outlines of copper layer.
static void ConfigureHPGLPenSizes(HPGL_PLOTTER *aPlotter, const PCB_PLOT_PARAMS *aPlotOpts)
Calculate the effective size of HPGL pens and set them in the plotter object.
PLOTTER * StartPlotBoard(BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString &aFullFileName, const wxString &aSheetName, const wxString &aSheetPath)
Open a new plotfile using the options (and especially the format) specified in the options and prepar...
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...
Plotting engine (DXF)
Plotting engine (Gerber)
Plotting engine (HPGL)
Plotting engines similar to ps (PostScript, Gerber, svg)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
std::vector< FAB_LAYER_COLOR > dummy
const double IU_PER_MM
Definition: base_units.h:77
const double IU_PER_MILS
Definition: base_units.h:78
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
@ PCB_FP_SHAPE_T
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:94
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:102
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:103
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590