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-2020 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>
34 #include <geometry/shape_segment.h>
35 #include <pcb_base_frame.h>
36 #include <math/util.h> // for KiROUND
37 
38 #include <board.h>
39 #include <core/arraydim.h>
40 #include <footprint.h>
41 #include <track.h>
42 #include <fp_shape.h>
43 #include <pcb_text.h>
44 #include <zone.h>
45 #include <pcb_shape.h>
46 #include <pcb_target.h>
47 #include <dimension.h>
48 
49 #include <pcbplot.h>
50 #include <plotters_specific.h>
51 #include <pcb_painter.h>
52 #include <gbr_metadata.h>
53 #include <advanced_config.h>
54 
55 /*
56  * Plot a solder mask layer. Solder mask layers have a minimum thickness value and cannot be
57  * drawn like standard layers, unless the minimum thickness is 0.
58  */
59 static void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
60  const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness );
61 
62 
63 void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
64  const PCB_PLOT_PARAMS& aPlotOpt )
65 {
66  PCB_PLOT_PARAMS plotOpt = aPlotOpt;
67  int soldermask_min_thickness = aBoard->GetDesignSettings().m_SolderMaskMinWidth;
68 
69  // Set a default color and the text mode for this layer
70  aPlotter->SetColor( BLACK );
71  aPlotter->SetTextMode( aPlotOpt.GetTextMode() );
72 
73  // Specify that the contents of the "Edges Pcb" layer are to be plotted in addition to the
74  // contents of the currently specified layer.
75  LSET layer_mask( aLayer );
76 
77  if( !aPlotOpt.GetExcludeEdgeLayer() )
78  layer_mask.set( Edge_Cuts );
79 
80  if( IsCopperLayer( aLayer ) )
81  {
82  // Skip NPTH pads on copper layers ( only if hole size == pad size ):
83  // Drill mark will be plotted if drill mark is SMALL_DRILL_SHAPE or FULL_DRILL_SHAPE
84  if( plotOpt.GetFormat() == PLOT_FORMAT::DXF )
85  {
86  plotOpt.SetSkipPlotNPTH_Pads( false );
87  PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
88  }
89  else
90  {
91  plotOpt.SetSkipPlotNPTH_Pads( true );
92  PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
93  }
94  }
95  else
96  {
97  switch( aLayer )
98  {
99  case B_Mask:
100  case F_Mask:
101  plotOpt.SetSkipPlotNPTH_Pads( false );
102  // Disable plot pad holes
104 
105  // Plot solder mask:
106  if( soldermask_min_thickness == 0 )
107  {
108  if( plotOpt.GetFormat() == PLOT_FORMAT::DXF )
109  PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
110  else
111  PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
112  }
113  else
114  PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt,
115  soldermask_min_thickness );
116 
117  break;
118 
119  case B_Adhes:
120  case F_Adhes:
121  case B_Paste:
122  case F_Paste:
123  plotOpt.SetSkipPlotNPTH_Pads( false );
124  // Disable plot pad holes
126 
127  if( plotOpt.GetFormat() == PLOT_FORMAT::DXF )
128  PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
129  else
130  PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
131  break;
132 
133  case F_SilkS:
134  case B_SilkS:
135  if( plotOpt.GetFormat() == PLOT_FORMAT::DXF && plotOpt.GetDXFPlotPolygonMode() )
136  // PlotLayerOutlines() is designed only for DXF plotters.
137  // and must not be used for other plot formats
138  PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
139  else
140  PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
141 
142  // Gerber: Subtract soldermask from silkscreen if enabled
143  if( aPlotter->GetPlotterType() == PLOT_FORMAT::GERBER
144  && plotOpt.GetSubtractMaskFromSilk() )
145  {
146  if( aLayer == F_SilkS )
147  layer_mask = LSET( F_Mask );
148  else
149  layer_mask = LSET( B_Mask );
150 
151  // Create the mask to subtract by creating a negative layer polarity
152  aPlotter->SetLayerPolarity( false );
153 
154  // Disable plot pad holes
156 
157  // Plot the mask
158  PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
159  }
160  break;
161 
162  // These layers are plotted like silk screen layers.
163  // Mainly, pads on these layers are not filled.
164  // This is not necessary the best choice.
165  case Dwgs_User:
166  case Cmts_User:
167  case Eco1_User:
168  case Eco2_User:
169  case Edge_Cuts:
170  case Margin:
171  case F_CrtYd:
172  case B_CrtYd:
173  case F_Fab:
174  case B_Fab:
175  plotOpt.SetSkipPlotNPTH_Pads( false );
177 
178  if( plotOpt.GetFormat() == PLOT_FORMAT::DXF && plotOpt.GetDXFPlotPolygonMode() )
179  // PlotLayerOutlines() is designed only for DXF plotters.
180  // and must not be used for other plot formats
181  PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
182  else
183  PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
184  break;
185 
186  default:
187  plotOpt.SetSkipPlotNPTH_Pads( false );
189 
190  if( plotOpt.GetFormat() == PLOT_FORMAT::DXF && plotOpt.GetDXFPlotPolygonMode() )
191  // PlotLayerOutlines() is designed only for DXF plotters.
192  // and must not be used for other plot formats
193  PlotLayerOutlines( aBoard, aPlotter, layer_mask, plotOpt );
194  else
195  PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
196  break;
197  }
198  }
199 }
200 
201 
202 /*
203  * Plot a copper layer or mask.
204  * Silk screen layers are not plotted here.
205  */
206 void PlotStandardLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
207  const PCB_PLOT_PARAMS& aPlotOpt )
208 {
209  BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
210 
211  itemplotter.SetLayerSet( aLayerMask );
212 
213  OUTLINE_MODE plotMode = aPlotOpt.GetPlotMode();
214  bool onCopperLayer = ( LSET::AllCuMask() & aLayerMask ).any();
215  bool onSolderMaskLayer = ( LSET( 2, F_Mask, B_Mask ) & aLayerMask ).any();
216  bool onSolderPasteLayer = ( LSET( 2, F_Paste, B_Paste ) & aLayerMask ).any();
217  bool onFrontFab = ( LSET( F_Fab ) & aLayerMask ).any();
218  bool onBackFab = ( LSET( B_Fab ) & aLayerMask ).any();
219  bool sketchPads = ( onFrontFab || onBackFab ) && aPlotOpt.GetSketchPadsOnFabLayers();
220 
221  // Plot edge layer and graphic items
222  itemplotter.PlotBoardGraphicItems();
223 
224  // Draw footprint texts:
225  for( FOOTPRINT* footprint : aBoard->Footprints() )
226  itemplotter.PlotFootprintTextItems( footprint );
227 
228  // Draw footprint other graphic items:
229  for( FOOTPRINT* footprint : aBoard->Footprints() )
230  itemplotter.PlotFootprintGraphicItems( footprint );
231 
232  // Plot footprint pads
233  for( FOOTPRINT* footprint : aBoard->Footprints() )
234  {
235  aPlotter->StartBlock( NULL );
236 
237  for( PAD* pad : footprint->Pads() )
238  {
239  OUTLINE_MODE padPlotMode = plotMode;
240 
241  if( !( pad->GetLayerSet() & aLayerMask ).any() )
242  {
243  if( sketchPads &&
244  ( ( onFrontFab && pad->GetLayerSet().Contains( F_Cu ) ) ||
245  ( onBackFab && pad->GetLayerSet().Contains( B_Cu ) ) ) )
246  padPlotMode = SKETCH;
247  else
248  continue;
249  }
250 
252  if( onCopperLayer && !pad->FlashLayer( aLayerMask ) )
253  continue;
254 
256 
257  if( pad->GetLayerSet()[B_Cu] )
258  color = aPlotOpt.ColorSettings()->GetColor( LAYER_PAD_BK );
259 
260  if( pad->GetLayerSet()[F_Cu] )
261  color = color.LegacyMix( aPlotOpt.ColorSettings()->GetColor( LAYER_PAD_FR ) );
262 
263  if( sketchPads && aLayerMask[F_Fab] )
264  color = aPlotOpt.ColorSettings()->GetColor( F_Fab );
265  else if( sketchPads && aLayerMask[B_Fab] )
266  color = aPlotOpt.ColorSettings()->GetColor( B_Fab );
267 
268  wxSize margin;
269  int width_adj = 0;
270 
271  if( onCopperLayer )
272  width_adj = itemplotter.getFineWidthAdj();
273 
274  if( onSolderMaskLayer )
275  margin.x = margin.y = pad->GetSolderMaskMargin();
276 
277  if( onSolderPasteLayer )
278  margin = pad->GetSolderPasteMargin();
279 
280  // not all shapes can have a different margin for x and y axis
281  // in fact only oval and rect shapes can have different values.
282  // Round shape have always the same x,y margin
283  // so define a unique value for other shapes that do not support different values
284  int mask_clearance = margin.x;
285 
286  // Now offset the pad size by margin + width_adj
287  wxSize padPlotsSize = pad->GetSize() + margin * 2 + wxSize( width_adj, width_adj );
288 
289  // Store these parameters that can be modified to plot inflated/deflated pads shape
290  PAD_SHAPE_T padShape = pad->GetShape();
291  wxSize padSize = pad->GetSize();
292  wxSize padDelta = pad->GetDelta(); // has meaning only for trapezoidal pads
293  double padCornerRadius = pad->GetRoundRectCornerRadius();
294 
295  // Don't draw a null size item :
296  if( padPlotsSize.x <= 0 || padPlotsSize.y <= 0 )
297  continue;
298 
299  switch( pad->GetShape() )
300  {
301  case PAD_SHAPE_CIRCLE:
302  case PAD_SHAPE_OVAL:
303  pad->SetSize( padPlotsSize );
304 
305  if( aPlotOpt.GetSkipPlotNPTH_Pads() &&
307  ( pad->GetSize() == pad->GetDrillSize() ) &&
308  ( pad->GetAttribute() == PAD_ATTRIB_NPTH ) )
309  break;
310 
311  itemplotter.PlotPad( pad, color, padPlotMode );
312  break;
313 
314  case PAD_SHAPE_RECT:
315  pad->SetSize( padPlotsSize );
316 
317  if( mask_clearance > 0 )
318  {
319  pad->SetShape( PAD_SHAPE_ROUNDRECT );
320  pad->SetRoundRectCornerRadius( mask_clearance );
321  }
322 
323  itemplotter.PlotPad( pad, color, padPlotMode );
324  break;
325 
326  case PAD_SHAPE_TRAPEZOID:
327  // inflate/deflate a trapezoid is a bit complex.
328  // so if the margin is not null, build a similar polygonal pad shape,
329  // and inflate/deflate the polygonal shape
330  // because inflating/deflating using different values for y and y
331  // we are using only margin.x as inflate/deflate value
332  if( mask_clearance == 0 )
333  itemplotter.PlotPad( pad, color, padPlotMode );
334  else
335  {
336  PAD dummy( *pad );
337  dummy.SetAnchorPadShape( PAD_SHAPE_CIRCLE );
338  dummy.SetShape( PAD_SHAPE_CUSTOM );
339  SHAPE_POLY_SET outline;
340  outline.NewOutline();
341  int dx = padSize.x / 2;
342  int dy = padSize.y / 2;
343  int ddx = padDelta.x / 2;
344  int ddy = padDelta.y / 2;
345 
346  outline.Append( -dx - ddy, dy + ddx );
347  outline.Append( dx + ddy, dy - ddx );
348  outline.Append( dx - ddy, -dy + ddx );
349  outline.Append( -dx + ddy, -dy - ddx );
350 
351  // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
352  // which can create bad shapes if margin.x is < 0
353  int maxError = aBoard->GetDesignSettings().m_MaxError;
354  int numSegs = GetArcToSegmentCount( mask_clearance, maxError, 360.0 );
355  outline.InflateWithLinkedHoles( mask_clearance, numSegs, SHAPE_POLY_SET::PM_FAST );
356  dummy.DeletePrimitivesList();
357  dummy.AddPrimitivePoly( outline, 0, true );
358 
359  // Be sure the anchor pad is not bigger than the deflated shape because this
360  // anchor will be added to the pad shape when plotting the pad. So now the
361  // polygonal shape is built, we can clamp the anchor size
362  dummy.SetSize( wxSize( 0,0 ) );
363 
364  itemplotter.PlotPad( &dummy, color, padPlotMode );
365  }
366 
367  break;
368 
369  case PAD_SHAPE_ROUNDRECT:
371  // Chamfer and rounding are stored as a percent and so don't need scaling
372  pad->SetSize( padPlotsSize );
373  itemplotter.PlotPad( pad, color, padPlotMode );
374  break;
375 
376  case PAD_SHAPE_CUSTOM:
377  {
378  // inflate/deflate a custom shape is a bit complex.
379  // so build a similar pad shape, and inflate/deflate the polygonal shape
380  PAD dummy( *pad );
381  SHAPE_POLY_SET shape;
382  pad->MergePrimitivesAsPolygon( &shape, UNDEFINED_LAYER );
383  // Shape polygon can have holes so use InflateWithLinkedHoles(), not Inflate()
384  // which can create bad shapes if margin.x is < 0
385  int maxError = aBoard->GetDesignSettings().m_MaxError;
386  int numSegs = GetArcToSegmentCount( mask_clearance, maxError, 360.0 );
387  shape.InflateWithLinkedHoles( mask_clearance, numSegs, SHAPE_POLY_SET::PM_FAST );
388  dummy.DeletePrimitivesList();
389  dummy.AddPrimitivePoly( shape, 0, true );
390 
391  // Be sure the anchor pad is not bigger than the deflated shape because this
392  // anchor will be added to the pad shape when plotting the pad. So now the
393  // polygonal shape is built, we can clamp the anchor size
394  if( mask_clearance < 0 ) // we expect margin.x = margin.y for custom pads
395  dummy.SetSize( padPlotsSize );
396 
397  itemplotter.PlotPad( &dummy, color, padPlotMode );
398  }
399  break;
400  }
401 
402  // Restore the pad parameters modified by the plot code
403  pad->SetSize( padSize );
404  pad->SetDelta( padDelta );
405  pad->SetShape( padShape );
406  pad->SetRoundRectCornerRadius( padCornerRadius );
407  }
408 
409  aPlotter->EndBlock( NULL );
410  }
411 
412  // Plot vias on copper layers, and if aPlotOpt.GetPlotViaOnMaskLayer() is true,
413  // plot them on solder mask
414 
415  GBR_METADATA gbr_metadata;
416 
417  bool isOnCopperLayer = ( aLayerMask & LSET::AllCuMask() ).any();
418 
419  if( isOnCopperLayer )
420  {
423  }
424 
425  aPlotter->StartBlock( NULL );
426 
427  for( TRACK* track : aBoard->Tracks() )
428  {
429  const VIA* via = dyn_cast<const VIA*>( track );
430 
431  if( !via )
432  continue;
433 
434  // vias are not plotted if not on selected layer, but if layer is SOLDERMASK_LAYER_BACK
435  // or SOLDERMASK_LAYER_FRONT, vias are drawn only if they are on the corresponding
436  // external copper layer
437  LSET via_mask_layer = via->GetLayerSet();
438 
439  if( aPlotOpt.GetPlotViaOnMaskLayer() )
440  {
441  if( via_mask_layer[B_Cu] )
442  via_mask_layer.set( B_Mask );
443 
444  if( via_mask_layer[F_Cu] )
445  via_mask_layer.set( F_Mask );
446  }
447 
448  if( !( via_mask_layer & aLayerMask ).any() )
449  continue;
450 
451  int via_margin = 0;
452  double width_adj = 0;
453 
454  // If the current layer is a solder mask, use the global mask clearance for vias
455  if( aLayerMask[B_Mask] || aLayerMask[F_Mask] )
456  via_margin = aBoard->GetDesignSettings().m_SolderMaskMargin;
457 
458  if( ( aLayerMask & LSET::AllCuMask() ).any() )
459  width_adj = itemplotter.getFineWidthAdj();
460 
461  int diameter = via->GetWidth() + 2 * via_margin + width_adj;
462 
464  if( onCopperLayer && !via->FlashLayer( aLayerMask ) )
465  continue;
466 
467  // Don't draw a null size item :
468  if( diameter <= 0 )
469  continue;
470 
471  // Some vias can be not connected (no net).
472  // Set the m_NotInNet for these vias to force a empty net name in gerber file
473  gbr_metadata.m_NetlistMetadata.m_NotInNet = via->GetNetname().IsEmpty();
474 
475  gbr_metadata.SetNetName( via->GetNetname() );
476 
477  COLOR4D color = aPlotOpt.ColorSettings()->GetColor(
478  LAYER_VIAS + static_cast<int>( via->GetViaType() ) );
479  // Set plot color (change WHITE to LIGHTGRAY because the white items are not seen on a
480  // white paper or screen
481  aPlotter->SetColor( color != WHITE ? color : LIGHTGRAY );
482  aPlotter->FlashPadCircle( via->GetStart(), diameter, plotMode, &gbr_metadata );
483  }
484 
485  aPlotter->EndBlock( NULL );
486  aPlotter->StartBlock( NULL );
488 
489  // Plot tracks (not vias) :
490  for( TRACK* track : aBoard->Tracks() )
491  {
492  if( track->Type() == PCB_VIA_T )
493  continue;
494 
495  if( !aLayerMask[track->GetLayer()] )
496  continue;
497 
498  // Some track segments can be not connected (no net).
499  // Set the m_NotInNet for these segments to force a empty net name in gerber file
500  gbr_metadata.m_NetlistMetadata.m_NotInNet = track->GetNetname().IsEmpty();
501 
502  gbr_metadata.SetNetName( track->GetNetname() );
503  int width = track->GetWidth() + itemplotter.getFineWidthAdj();
504  aPlotter->SetColor( itemplotter.getColor( track->GetLayer() ) );
505 
506  if( track->Type() == PCB_ARC_T )
507  {
508  ARC* arc = static_cast<ARC*>( track );
509  VECTOR2D center( arc->GetCenter() );
510  int radius = arc->GetRadius();
511  double start_angle = arc->GetArcAngleStart();
512  double end_angle = start_angle + arc->GetAngle();
513 
514  aPlotter->ThickArc( wxPoint( center.x, center.y ), -end_angle, -start_angle,
515  radius, width, plotMode, &gbr_metadata );
516  }
517  else
518  {
519  aPlotter->ThickSegment( track->GetStart(), track->GetEnd(), width, plotMode,
520  &gbr_metadata );
521  }
522 
523  }
524 
525  aPlotter->EndBlock( NULL );
526 
527  // Plot filled ares
528  aPlotter->StartBlock( NULL );
529 
530  NETINFO_ITEM nonet( aBoard );
531 
532  for( ZONE* zone : aBoard->Zones() )
533  {
534  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
535  {
536  if( !aLayerMask[layer] )
537  continue;
538 
539  SHAPE_POLY_SET mainArea = zone->GetFilledPolysList( layer );
540  SHAPE_POLY_SET islands;
541 
542  for( int i = mainArea.OutlineCount() - 1; i >= 0; i-- )
543  {
544  if( zone->IsIsland( layer, i ) )
545  {
546  islands.AddOutline( mainArea.CPolygon( i )[0] );
547  mainArea.DeletePolygon( i );
548  }
549  }
550 
551  itemplotter.PlotFilledAreas( zone, mainArea );
552 
553  if( !islands.IsEmpty() )
554  {
555  ZONE dummy( *zone );
556  dummy.SetNet( &nonet );
557  itemplotter.PlotFilledAreas( &dummy, islands );
558  }
559  }
560  }
561 
562  aPlotter->EndBlock( NULL );
563 
564  // Adding drill marks, if required and if the plotter is able to plot them:
566  itemplotter.PlotDrillMarks();
567 }
568 
569 
570 // Seems like we want to plot from back to front?
571 static const PCB_LAYER_ID plot_seq[] = {
572 
573  B_Adhes, // 32
574  F_Adhes,
575  B_Paste,
576  F_Paste,
577  B_SilkS,
578  B_Mask,
579  F_Mask,
580  Dwgs_User,
581  Cmts_User,
582  Eco1_User,
583  Eco2_User,
584  Edge_Cuts,
585  Margin,
586 
587  F_CrtYd, // CrtYd & Body are footprint only
588  B_CrtYd,
589  F_Fab,
590  B_Fab,
591 
592  B_Cu,
593  In30_Cu,
594  In29_Cu,
595  In28_Cu,
596  In27_Cu,
597  In26_Cu,
598  In25_Cu,
599  In24_Cu,
600  In23_Cu,
601  In22_Cu,
602  In21_Cu,
603  In20_Cu,
604  In19_Cu,
605  In18_Cu,
606  In17_Cu,
607  In16_Cu,
608  In15_Cu,
609  In14_Cu,
610  In13_Cu,
611  In12_Cu,
612  In11_Cu,
613  In10_Cu,
614  In9_Cu,
615  In8_Cu,
616  In7_Cu,
617  In6_Cu,
618  In5_Cu,
619  In4_Cu,
620  In3_Cu,
621  In2_Cu,
622  In1_Cu,
623  F_Cu,
624 
625  F_SilkS,
626 };
627 
628 
629 /*
630  * Plot outlines of copper, for copper layer
631  */
632 void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
633  const PCB_PLOT_PARAMS& aPlotOpt )
634 {
635  BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
636  itemplotter.SetLayerSet( aLayerMask );
637 
638  SHAPE_POLY_SET outlines;
639 
640  for( LSEQ seq = aLayerMask.Seq( plot_seq, arrayDim( plot_seq ) ); seq; ++seq )
641  {
642  PCB_LAYER_ID layer = *seq;
643 
644  outlines.RemoveAllContours();
645  aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines );
646 
647  outlines.Simplify( SHAPE_POLY_SET::PM_FAST );
648 
649  // Plot outlines
650  std::vector<wxPoint> cornerList;
651 
652  // Now we have one or more basic polygons: plot each polygon
653  for( int ii = 0; ii < outlines.OutlineCount(); ii++ )
654  {
655  for(int kk = 0; kk <= outlines.HoleCount (ii); kk++ )
656  {
657  cornerList.clear();
658  const SHAPE_LINE_CHAIN& path = (kk == 0) ? outlines.COutline( ii ) : outlines.CHole( ii, kk - 1 );
659 
660  for( int jj = 0; jj < path.PointCount(); jj++ )
661  cornerList.emplace_back( (wxPoint) path.CPoint( jj ) );
662 
663  // Ensure the polygon is closed
664  if( cornerList[0] != cornerList[cornerList.size() - 1] )
665  cornerList.push_back( cornerList[0] );
666 
667  aPlotter->PlotPoly( cornerList, FILL_TYPE::NO_FILL );
668  }
669  }
670 
671  // Plot pad holes
673  {
674  int smallDrill = (aPlotOpt.GetDrillMarksType() == PCB_PLOT_PARAMS::SMALL_DRILL_SHAPE)
676 
677  for( FOOTPRINT* footprint : aBoard->Footprints() )
678  {
679  for( PAD* pad : footprint->Pads() )
680  {
681  wxSize hole = pad->GetDrillSize();
682 
683  if( hole.x == 0 || hole.y == 0 )
684  continue;
685 
686  if( hole.x == hole.y )
687  {
688  hole.x = std::min( smallDrill, hole.x );
689  aPlotter->Circle( pad->GetPosition(), hole.x, FILL_TYPE::NO_FILL );
690  }
691  else
692  {
693  // Note: small drill marks have no significance when applied to slots
694  const SHAPE_SEGMENT* seg = pad->GetEffectiveHoleShape();
695  aPlotter->ThickSegment( (wxPoint) seg->GetSeg().A,
696  (wxPoint) seg->GetSeg().B,
697  seg->GetWidth(), SKETCH, NULL );
698  }
699  }
700  }
701  }
702 
703  // Plot vias holes
704  for( TRACK* track : aBoard->Tracks() )
705  {
706  const VIA* via = dyn_cast<const VIA*>( track );
707 
708  if( via && via->IsOnLayer( layer ) ) // via holes can be not through holes
709  {
710  aPlotter->Circle( via->GetPosition(), via->GetDrillValue(), FILL_TYPE::NO_FILL );
711  }
712  }
713  }
714 }
715 
716 
717 /* Plot a solder mask layer.
718  * Solder mask layers have a minimum thickness value and cannot be drawn like standard layers,
719  * unless the minimum thickness is 0.
720  * Currently the algo is:
721  * 1 - build all pad shapes as polygons with a size inflated by
722  * mask clearance + (min width solder mask /2)
723  * 2 - Merge shapes
724  * 3 - deflate result by (min width solder mask /2)
725  * 4 - ORing result by all pad shapes as polygons with a size inflated by
726  * mask clearance only (because deflate sometimes creates shape artifacts)
727  * 5 - draw result as polygons
728  *
729  * We have 2 algos:
730  * the initial algo, that create polygons for every shape, inflate and deflate polygons
731  * with Min Thickness/2, and merges the result.
732  * Drawback: pads attributes are lost (annoying in Gerber)
733  * the new algo:
734  * create initial polygons for every shape (pad or polygon),
735  * inflate and deflate polygons
736  * with Min Thickness/2, and merges the result (like initial algo)
737  * remove all initial polygons.
738  * The remaining polygons are areas with thickness < min thickness
739  * plot all initial shapes by flashing (or using regions) for pad and polygons
740  * (shapes will be better) and remaining polygons to
741  * remove areas with thickness < min thickness from final mask
742  *
743  * TODO: remove old code after more testing.
744  */
745 #define NEW_ALGO 1
746 
747 void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
748  const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness )
749 {
750  int maxError = aBoard->GetDesignSettings().m_MaxError;
751  PCB_LAYER_ID layer = aLayerMask[B_Mask] ? B_Mask : F_Mask;
752  SHAPE_POLY_SET buffer;
753  SHAPE_POLY_SET* boardOutline = nullptr;
754 
755  if( aBoard->GetBoardPolygonOutlines( buffer ) )
756  boardOutline = &buffer;
757 
758  // We remove 1nm as we expand both sides of the shapes, so allowing for
759  // a strictly greater than or equal comparison in the shape separation (boolean add)
760  // means that we will end up with separate shapes that then are shrunk
761  int inflate = aMinThickness/2 - 1;
762 
763  BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
764  itemplotter.SetLayerSet( aLayerMask );
765 
766  // Plot edge layer and graphic items.
767  // They do not have a solder Mask margin, because they are graphic items
768  // on this layer (like logos), not actually areas around pads.
769 
770  itemplotter.PlotBoardGraphicItems();
771 
772  for( FOOTPRINT* footprint : aBoard->Footprints() )
773  {
774  for( BOARD_ITEM* item : footprint->GraphicalItems() )
775  {
776  itemplotter.PlotFootprintTextItems( footprint );
777 
778  if( item->Type() == PCB_FP_SHAPE_T && item->GetLayer() == layer )
779  itemplotter.PlotFootprintGraphicItem( (FP_SHAPE*) item );
780  }
781  }
782 
783  // Build polygons for each pad shape. The size of the shape on solder mask should be size
784  // of pad + clearance around the pad, where clearance = solder mask clearance + extra margin.
785  // Extra margin is half the min width for solder mask, which is used to merge too-close shapes
786  // (distance < aMinThickness), and will be removed when creating the actual shapes.
787 
788  // Will contain shapes inflated by inflate value that will be merged and deflated by
789  // inflate value to build final polygons
790  // After calculations the remaining polygons are polygons to plot
791  SHAPE_POLY_SET areas;
792  // Will contain exact shapes of all items on solder mask
793  SHAPE_POLY_SET initialPolys;
794 
795 #if NEW_ALGO
796  // Generate polygons with arcs inside the shape or exact shape
797  // to minimize shape changes created by arc to segment size correction.
799 #endif
800  {
801  // Plot pads
802  for( FOOTPRINT* footprint : aBoard->Footprints() )
803  {
804  // add shapes with their exact mask layer size in initialPolys
805  footprint->TransformPadsWithClearanceToPolygon( initialPolys, layer, 0, maxError,
806  ERROR_OUTSIDE );
807  // add shapes inflated by aMinThickness/2 in areas
808  footprint->TransformPadsWithClearanceToPolygon( areas, layer, inflate, maxError,
809  ERROR_OUTSIDE );
810  }
811 
812  // Plot vias on solder masks, if aPlotOpt.GetPlotViaOnMaskLayer() is true,
813  if( aPlotOpt.GetPlotViaOnMaskLayer() )
814  {
815  // The current layer is a solder mask, use the global mask clearance for vias
816  int via_clearance = aBoard->GetDesignSettings().m_SolderMaskMargin;
817  int via_margin = via_clearance + inflate;
818 
819  for( TRACK* track : aBoard->Tracks() )
820  {
821  const VIA* via = dyn_cast<const VIA*>( track );
822 
823  if( !via )
824  continue;
825 
826  // vias are plotted only if they are on the corresponding external copper layer
827  LSET via_set = via->GetLayerSet();
828 
829  if( via_set[B_Cu] )
830  via_set.set( B_Mask );
831 
832  if( via_set[F_Cu] )
833  via_set.set( F_Mask );
834 
835  if( !( via_set & aLayerMask ).any() )
836  continue;
837 
838  // add shapes with their exact mask layer size in initialPolys
839  via->TransformShapeWithClearanceToPolygon( initialPolys, layer, via_clearance,
840  maxError, ERROR_OUTSIDE );
841  // add shapes inflated by aMinThickness/2 in areas
842  via->TransformShapeWithClearanceToPolygon( areas, layer, via_margin, maxError,
843  ERROR_OUTSIDE );
844  }
845  }
846 
847  // Add filled zone areas.
848 #if 0 // Set to 1 if a solder mask margin must be applied to zones on solder mask
849  int zone_margin = aBoard->GetDesignSettings().m_SolderMaskMargin;
850 #else
851  int zone_margin = 0;
852 #endif
853 
854  for( ZONE* zone : aBoard->Zones() )
855  {
856  if( zone->GetLayer() != layer )
857  continue;
858 
859  // add shapes inflated by aMinThickness/2 in areas
860  zone->TransformSmoothedOutlineToPolygon( areas, inflate + zone_margin, boardOutline );
861  // add shapes with their exact mask layer size in initialPolys
862  zone->TransformSmoothedOutlineToPolygon( initialPolys, zone_margin, boardOutline );
863  }
864 
865  int numSegs = GetArcToSegmentCount( inflate, maxError, 360.0 );
866 
867  // Merge all polygons: After deflating, not merged (not overlapping) polygons
868  // will have the initial shape (with perhaps small changes due to deflating transform)
870  areas.Deflate( inflate, numSegs );
871  }
872 
873 #if !NEW_ALGO
874  // To avoid a lot of code, use a ZONE to handle and plot polygons, because our polygons look
875  // exactly like filled areas in zones.
876  // Note, also this code is not optimized: it creates a lot of copy/duplicate data.
877  // However it is not complex, and fast enough for plot purposes (copy/convert data is only a
878  // very small calculation time for these calculations).
879  ZONE zone( aBoard );
880  zone.SetMinThickness( 0 ); // trace polygons only
881  zone.SetLayer( layer );
882  // Combine the current areas to initial areas. This is mandatory because inflate/deflate
883  // transform is not perfect, and we want the initial areas perfectly kept
884  areas.BooleanAdd( initialPolys, SHAPE_POLY_SET::PM_FAST );
886 
887  itemplotter.PlotFilledAreas( &zone, areas );
888 #else
889 
890  // Remove initial shapes: each shape will be added later, as flashed item or region
891  // with a suitable attribute.
892  // Do not merge pads is mandatory in Gerber files: They must be identified as pads
893 
894  // we deflate areas in polygons, to avoid after subtracting initial shapes
895  // having small artifacts due to approximations during polygon transforms
897 
898  // Slightly inflate polygons to avoid any gap between them and other shapes,
899  // These gaps are created by arc to segments approximations
900  areas.Inflate( Millimeter2iu( 0.002 ),6 );
901 
902  // Now, only polygons with a too small thickness are stored in areas.
904 
905  // Plot each initial shape (pads and polygons on mask layer), with suitable attributes:
906  PlotStandardLayer( aBoard, aPlotter, aLayerMask, aPlotOpt );
907 
908  // Add shapes corresponding to areas having too small thickness.
909  std::vector<wxPoint> cornerList;
910 
911  for( int ii = 0; ii < areas.OutlineCount(); ii++ )
912  {
913  cornerList.clear();
914  const SHAPE_LINE_CHAIN& path = areas.COutline( ii );
915 
916  // polygon area in mm^2 :
917  double curr_area = path.Area() / ( IU_PER_MM * IU_PER_MM );
918 
919  // Skip very small polygons: they are certainly artifacts created by
920  // arc approximations and polygon transforms
921  // (inflate/deflate transforms)
922  constexpr double poly_min_area_mm2 = 0.01; // 0.01 mm^2 gives a good filtering
923 
924  if( curr_area < poly_min_area_mm2 )
925  continue;
926 
927  for( int jj = 0; jj < path.PointCount(); jj++ )
928  cornerList.emplace_back( (wxPoint) path.CPoint( jj ) );
929 
930  // Ensure the polygon is closed
931  if( cornerList[0] != cornerList[cornerList.size() - 1] )
932  cornerList.push_back( cornerList[0] );
933 
934  aPlotter->PlotPoly( cornerList, FILL_TYPE::FILLED_SHAPE );
935  }
936 #endif
937 }
938 
939 
946 static void initializePlotter( PLOTTER *aPlotter, BOARD * aBoard,
947  PCB_PLOT_PARAMS *aPlotOpts )
948 {
949  PAGE_INFO pageA4( wxT( "A4" ) );
950  const PAGE_INFO& pageInfo = aBoard->GetPageSettings();
951  const PAGE_INFO* sheet_info;
952  double paperscale; // Page-to-paper ratio
953  wxSize paperSizeIU;
954  wxSize pageSizeIU( pageInfo.GetSizeIU() );
955  bool autocenter = false;
956 
957  // Special options: to fit the sheet to an A4 sheet replace the paper size. However there
958  // is a difference between the autoscale and the a4paper option:
959  // - Autoscale fits the board to the paper size
960  // - A4paper fits the original paper size to an A4 sheet
961  // - Both of them fit the board to an A4 sheet
962  if( aPlotOpts->GetA4Output() )
963  {
964  sheet_info = &pageA4;
965  paperSizeIU = pageA4.GetSizeIU();
966  paperscale = (double) paperSizeIU.x / pageSizeIU.x;
967  autocenter = true;
968  }
969  else
970  {
971  sheet_info = &pageInfo;
972  paperSizeIU = pageSizeIU;
973  paperscale = 1;
974 
975  // Need autocentering only if scale is not 1:1
976  autocenter = (aPlotOpts->GetScale() != 1.0);
977  }
978 
979  EDA_RECT bbox = aBoard->ComputeBoundingBox();
980  wxPoint boardCenter = bbox.Centre();
981  wxSize boardSize = bbox.GetSize();
982 
983  double compound_scale;
984 
985  // Fit to 80% of the page if asked; it could be that the board is empty, in this case
986  // regress to 1:1 scale
987  if( aPlotOpts->GetAutoScale() && boardSize.x > 0 && boardSize.y > 0 )
988  {
989  double xscale = (paperSizeIU.x * 0.8) / boardSize.x;
990  double yscale = (paperSizeIU.y * 0.8) / boardSize.y;
991 
992  compound_scale = std::min( xscale, yscale ) * paperscale;
993  }
994  else
995  compound_scale = aPlotOpts->GetScale() * paperscale;
996 
997 
998  // For the plot offset we have to keep in mind the auxiliary origin too: if autoscaling is
999  // off we check that plot option (i.e. autoscaling overrides auxiliary origin)
1000  wxPoint offset( 0, 0);
1001 
1002  if( autocenter )
1003  {
1004  offset.x = KiROUND( boardCenter.x - ( paperSizeIU.x / 2.0 ) / compound_scale );
1005  offset.y = KiROUND( boardCenter.y - ( paperSizeIU.y / 2.0 ) / compound_scale );
1006  }
1007  else
1008  {
1009  if( aPlotOpts->GetUseAuxOrigin() )
1010  offset = aBoard->GetDesignSettings().m_AuxOrigin;
1011  }
1012 
1013  aPlotter->SetPageSettings( *sheet_info );
1014 
1015  aPlotter->SetViewport( offset, IU_PER_MILS/10, compound_scale, aPlotOpts->GetMirror() );
1016  // Has meaning only for gerber plotter. Must be called only after SetViewport
1017  aPlotter->SetGerberCoordinatesFormat( aPlotOpts->GetGerberPrecision() );
1018  // Has meaning only for SVG plotter. Must be called only after SetViewport
1019  aPlotter->SetSvgCoordinatesFormat( aPlotOpts->GetSvgPrecision(), aPlotOpts->GetSvgUseInch() );
1020 
1021  aPlotter->SetCreator( wxT( "PCBNEW" ) );
1022  aPlotter->SetColorMode( false ); // default is plot in Black and White.
1023  aPlotter->SetTextMode( aPlotOpts->GetTextMode() );
1024 }
1025 
1026 
1030 static void FillNegativeKnockout( PLOTTER *aPlotter, const EDA_RECT &aBbbox )
1031 {
1032  const int margin = 5 * IU_PER_MM; // Add a 5 mm margin around the board
1033  aPlotter->SetNegative( true );
1034  aPlotter->SetColor( WHITE ); // Which will be plotted as black
1035  EDA_RECT area = aBbbox;
1036  area.Inflate( margin );
1037  aPlotter->Rect( area.GetOrigin(), area.GetEnd(), FILL_TYPE::FILLED_SHAPE );
1038  aPlotter->SetColor( BLACK );
1039 }
1040 
1041 
1045 static void ConfigureHPGLPenSizes( HPGL_PLOTTER *aPlotter, PCB_PLOT_PARAMS *aPlotOpts )
1046 {
1047  // Compute penDiam (the value is given in mils) in pcb units, with plot scale (if Scale is 2,
1048  // penDiam value is always m_HPGLPenDiam so apparent penDiam is actually penDiam / Scale
1049  int penDiam = KiROUND( aPlotOpts->GetHPGLPenDiameter() * IU_PER_MILS / aPlotOpts->GetScale() );
1050 
1051  // Set HPGL-specific options and start
1052  aPlotter->SetPenSpeed( aPlotOpts->GetHPGLPenSpeed() );
1053  aPlotter->SetPenNumber( aPlotOpts->GetHPGLPenNum() );
1054  aPlotter->SetPenDiameter( penDiam );
1055 }
1056 
1057 
1063 PLOTTER* StartPlotBoard( BOARD *aBoard, PCB_PLOT_PARAMS *aPlotOpts, int aLayer,
1064  const wxString& aFullFileName, const wxString& aSheetDesc )
1065 {
1066  // Create the plotter driver and set the few plotter specific options
1067  PLOTTER* plotter = NULL;
1068 
1069  switch( aPlotOpts->GetFormat() )
1070  {
1071  case PLOT_FORMAT::DXF:
1072  DXF_PLOTTER* DXF_plotter;
1073  DXF_plotter = new DXF_PLOTTER();
1074  DXF_plotter->SetUnits( aPlotOpts->GetDXFPlotUnits() );
1075 
1076  plotter = DXF_plotter;
1077  break;
1078 
1079  case PLOT_FORMAT::POST:
1080  PS_PLOTTER* PS_plotter;
1081  PS_plotter = new PS_PLOTTER();
1082  PS_plotter->SetScaleAdjust( aPlotOpts->GetFineScaleAdjustX(),
1083  aPlotOpts->GetFineScaleAdjustY() );
1084  plotter = PS_plotter;
1085  break;
1086 
1087  case PLOT_FORMAT::PDF:
1088  plotter = new PDF_PLOTTER();
1089  break;
1090 
1091  case PLOT_FORMAT::HPGL:
1092  HPGL_PLOTTER* HPGL_plotter;
1093  HPGL_plotter = new HPGL_PLOTTER();
1094 
1095  // HPGL options are a little more convoluted to compute, so they get their own function
1096  ConfigureHPGLPenSizes( HPGL_plotter, aPlotOpts );
1097  plotter = HPGL_plotter;
1098  break;
1099 
1100  case PLOT_FORMAT::GERBER:
1101  plotter = new GERBER_PLOTTER();
1102  break;
1103 
1104  case PLOT_FORMAT::SVG:
1105  plotter = new SVG_PLOTTER();
1106  break;
1107 
1108  default:
1109  wxASSERT( false );
1110  return NULL;
1111  }
1112 
1114  renderSettings->LoadColors( aPlotOpts->ColorSettings() );
1115  renderSettings->SetDefaultPenWidth( Millimeter2iu( 0.0212 ) ); // Hairline at 1200dpi
1116  plotter->SetRenderSettings( renderSettings );
1117 
1118  // Compute the viewport and set the other options
1119 
1120  // page layout is not mirrored, so temporarily change mirror option for the page layout
1121  PCB_PLOT_PARAMS plotOpts = *aPlotOpts;
1122 
1123  if( plotOpts.GetPlotFrameRef() && plotOpts.GetMirror() )
1124  plotOpts.SetMirror( false );
1125 
1126  initializePlotter( plotter, aBoard, &plotOpts );
1127 
1128  if( plotter->OpenFile( aFullFileName ) )
1129  {
1130  plotter->ClearHeaderLinesList();
1131 
1132  // For the Gerber "file function" attribute, set the layer number
1133  if( plotter->GetPlotterType() == PLOT_FORMAT::GERBER )
1134  {
1135  bool useX2mode = plotOpts.GetUseGerberX2format();
1136 
1137  GERBER_PLOTTER* gbrplotter = static_cast <GERBER_PLOTTER*> ( plotter );
1138  gbrplotter->DisableApertMacros( plotOpts.GetDisableGerberMacros() );
1139  gbrplotter->UseX2format( useX2mode );
1140  gbrplotter->UseX2NetAttributes( plotOpts.GetIncludeGerberNetlistInfo() );
1141 
1142  // Attributes can be added using X2 format or as comment (X1 format)
1143  AddGerberX2Attribute( plotter, aBoard, aLayer, not useX2mode );
1144  }
1145 
1146  plotter->StartPlot();
1147 
1148  // Plot the frame reference if requested
1149  if( aPlotOpts->GetPlotFrameRef() )
1150  {
1151  PlotDrawingSheet( plotter, aBoard->GetProject(), aBoard->GetTitleBlock(),
1152  aBoard->GetPageSettings(), "1", 1, aSheetDesc,
1153  aBoard->GetFileName() );
1154 
1155  if( aPlotOpts->GetMirror() )
1156  initializePlotter( plotter, aBoard, aPlotOpts );
1157  }
1158 
1159  // When plotting a negative board: draw a black rectangle (background for plot board
1160  // in white) and switch the current color to WHITE; note the color inversion is actually
1161  // done in the driver (if supported)
1162  if( aPlotOpts->GetNegative() )
1163  {
1164  EDA_RECT bbox = aBoard->ComputeBoundingBox();
1165  FillNegativeKnockout( plotter, bbox );
1166  }
1167 
1168  return plotter;
1169  }
1170 
1171  delete plotter->RenderSettings();
1172  delete plotter;
1173  return NULL;
1174 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
OUTLINE_MODE GetPlotMode() const
Handle special data (items attributes) during plot.
OUTLINE_MODE
Definition: outline_mode.h:24
Definition: track.h:343
virtual wxPoint GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: track.h:301
const POLYGON & CPolygon(int aIndex) const
const PAGE_INFO & GetPageSettings() const
Definition: board.h:606
virtual void SetCreator(const wxString &aCreator)
Definition: plotter.h:172
virtual void LoadColors(const COLOR_SETTINGS *aSettings) override
Definition: pcb_painter.cpp:86
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void UseX2NetAttributes(bool aEnable)
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:484
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:1862
ZONES & Zones()
Definition: board.h:309
bool GetPlotFrameRef() const
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: track.cpp:376
bool GetDXFPlotPolygonMode() const
static void initializePlotter(PLOTTER *aPlotter, BOARD *aBoard, PCB_PLOT_PARAMS *aPlotOpts)
Set up most plot options for plotting a board (especially the viewport) Important thing: page size is...
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
virtual bool StartPlot()=0
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
Plotting engines (PostScript, Gerber, HPGL and DXF)
virtual void SetColor(COLOR4D color)=0
static void FillNegativeKnockout(PLOTTER *aPlotter, const EDA_RECT &aBbbox)
Prefill in black an area a little bigger than the board to prepare for the negative plot.
virtual void Rect(const wxPoint &p1, const wxPoint &p2, FILL_TYPE fill, int width=USE_DEFAULT_LINE_WIDTH)=0
const wxPoint & GetStart() const
Definition: track.h:116
static constexpr double IU_PER_MM
Mock up a conversion function.
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition: plotter.cpp:76
void SetNetAttribType(int aNetAttribType)
Definition: gbr_metadata.h:219
virtual void SetColorMode(bool aColorMode)
Plot in B/W or color.
Definition: plotter.h:151
bool GetDisableGerberMacros() const
void SetScaleAdjust(double scaleX, double scaleY)
Set the 'fine' scaling for the postscript engine.
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:444
static const PCB_LAYER_ID plot_seq[]
void PlotStandardLayer(BOARD *aBoard, PLOTTER *aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
Function PlotStandardLayer plot copper or technical layers.
int color
Definition: DXF_plotter.cpp:60
bool IsEmpty() const
void SetRenderSettings(RENDER_SETTINGS *aSettings)
Definition: plotter.h:154
PROJECT * GetProject() const
Definition: board.h:430
void PlotDrillMarks()
Function PlotDrillMarks Draw a drill mark for pads and vias.
void SetMirror(bool aFlag)
virtual void SetPenDiameter(double diameter)
virtual void StartBlock(void *aData)
calling this function allows one to define the beginning of a group of drawing items,...
Definition: plotter.h:475
void PlotFootprintTextItems(FOOTPRINT *aFootprint)
class ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
Definition: sch_symbol.cpp:69
void UseX2format(bool aEnable)
wxString GetNetname() const
virtual void PlotPoly(const std::vector< wxPoint > &aCornerList, FILL_TYPE aFill, int aWidth=USE_DEFAULT_LINE_WIDTH, void *aData=NULL)=0
Draw a polygon ( filled or not )
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:591
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
int GetHPGLPenSpeed() const
const SHAPE_LINE_CHAIN & CHole(int aOutline, int aHole) const
void AddGerberX2Attribute(PLOTTER *aPlotter, const BOARD *aBoard, LAYER_NUM aLayer, bool aUseX1CompatibilityMode)
Calculates some X2 attributes, as defined in the Gerber file format specification and add them to the...
Definition: pcbplot.cpp:350
void SetUnits(DXF_UNITS aUnit)
Set the units to use for plotting the DXF file.
Definition: color4d.h:44
void SetDrillMarksType(DrillMarksType aVal)
void Inflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Perform outline inflation/deflation.
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
double m_SmallDrillMarkSize
The diameter of the drill marks on print and plot outputs (in mm), when the "Drill marks" option is s...
int PointCount() const
Function PointCount()
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
const wxString & GetFileName() const
Definition: board.h:298
double GetScale() const
bool GetUseGerberX2format() const
virtual void ThickSegment(const wxPoint &start, const wxPoint &end, int width, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:506
PAD_SHAPE_T
The set of pad shapes, used with PAD::{Set,Get}Shape()
Definition: pad_shapes.h:32
virtual void SetGerberCoordinatesFormat(int aResolution, bool aUseInches=false)
Definition: plotter.h:458
virtual void SetSvgCoordinatesFormat(unsigned aResolution, bool aUseInches=false)
Definition: plotter.h:463
const SEG & GetSeg() const
bool GetMirror() const
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, PCB_LAYER_ID aLayer, int aClearanceValue, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the track shape to a closed polygon Used in fil...
Classes used in Pcbnew, CvPcb and GerbView.
void DeletePolygon(int aIdx)
Board plot function definition file.
static void PlotSolderMaskLayer(BOARD *aBoard, PLOTTER *aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt, int aMinThickness)
PCB specific render settings.
Definition: pcb_painter.h:64
const VECTOR2I & CPoint(int aIndex) const
Function Point()
const wxPoint GetEnd() const
Definition: eda_rect.h:108
void PlotLayerOutlines(BOARD *aBoard, PLOTTER *aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS &aPlotOpt)
Function PlotLayerOutlines plot copper outline of a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
bool GetA4Output() const
int GetGerberPrecision() const
LSET is a set of PCB_LAYER_IDs.
PLOT_FORMAT GetFormat() const
void SetLayerSet(LSET aLayerMask)
Definition: pcbplot.h:90
#define NULL
int GetDrillValue() const
Function GetDrillValue "calculates" the drill value for vias (m-Drill if > 0, or default drill value ...
Definition: track.cpp:173
void PlotOneBoardLayer(BOARD *aBoard, PLOTTER *aPlotter, PCB_LAYER_ID aLayer, const PCB_PLOT_PARAMS &aPlotOpt)
Function PlotOneBoardLayer main function to plot one copper or technical layer.
Represent a set of closed polygons.
unsigned GetSvgPrecision() const
bool FlashLayer(int aLayer) const
Checks to see whether the via should have a pad on the specific layer.
Definition: track.cpp:494
const wxPoint GetOrigin() const
Definition: eda_rect.h:106
virtual PLOT_FORMAT GetPlotterType() const =0
Returns the effective plot engine in use.
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:53
void PlotBoardGraphicItems()
plot items like text and graphics, but not tracks and footprints
virtual void SetPenSpeed(int speed)
Definition: plotter_hpgl.h:77
FOOTPRINTS & Footprints()
Definition: board.h:303
bool GetIncludeGerberNetlistInfo() const
virtual void SetTextMode(PLOT_TEXT_MODE mode)
Change the current text mode.
Definition: plotter.h:453
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
void SetSkipPlotNPTH_Pads(bool aSkip)
PLOT_TEXT_MODE GetTextMode() const
void ConvertBrdLayerToPolygonalContours(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aOutlines)
Build a set of polygons which are the outlines of copper items (pads, tracks, vias,...
bool GetSkipPlotNPTH_Pads() const
void PlotFootprintGraphicItems(FOOTPRINT *aFootprint)
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
a few functions useful in geometry calculations.
void Simplify(POLYGON_MODE aFastMode)
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
static void ConfigureHPGLPenSizes(HPGL_PLOTTER *aPlotter, PCB_PLOT_PARAMS *aPlotOpts)
Calculate the effective size of HPGL pens and set them in the plotter object.
void SetMinThickness(int aMinThickness)
Definition: zone.h:248
double GetRadius() const
Definition: track.cpp:922
Metadata which can be added in a gerber file as attribute in X2 format.
Definition: gbr_metadata.h:204
bool GetAutoScale() const
PCB_PLOT_PARAMS handles plot parameters and options when plotting/printing a board.
virtual void Circle(const wxPoint &pos, int diametre, FILL_TYPE fill, int width=USE_DEFAULT_LINE_WIDTH)=0
int NewOutline()
Creates a new hole in a given outline.
int HoleCount(int aOutline) const
Return the reference to aIndex-th outline in the set.
PLOTTER * StartPlotBoard(BOARD *aBoard, PCB_PLOT_PARAMS *aPlotOpts, int aLayer, const wxString &aFullFileName, const wxString &aSheetDesc)
Open a new plotfile using the options (and especially the format) specified in the options and prepar...
virtual void SetNegative(bool aNegative)
Definition: plotter.h:142
double GetFineScaleAdjustX() const
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
virtual void SetViewport(const wxPoint &aOffset, double aIusPerDecimil, double aScale, bool aMirror)=0
Set the plot offset and scaling for the current plot.
Definition: color4d.h:48
int GetHPGLPenNum() const
void PlotFilledAreas(ZONE *aZone, SHAPE_POLY_SET &aPolysList)
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
void PlotPad(PAD *aPad, COLOR4D aColor, OUTLINE_MODE aPlotMode)
Plot a pad.
double GetAngle() const
Definition: track.cpp:928
void DisableApertMacros(bool aDisable)
Disable Aperture Macro (AM) command, only for broken Gerber Readers Regions will be used instead of A...
void SetNetName(const wxString &aNetname)
Definition: gbr_metadata.h:229
Base plotter engine class.
Definition: plotter.h:121
COLOR4D GetColor(int aLayer) const
bool GetSketchPadsOnFabLayers() const
Handle the data for a net.
Definition: netinfo.h:64
RENDER_SETTINGS * RenderSettings()
Definition: plotter.h:155
bool GetPlotViaOnMaskLayer() const
smd pads, front layer
TITLE_BLOCK & GetTitleBlock()
Definition: board.h:612
int GetWidth() const
Definition: track.h:110
Meta control for all vias opacity/visibility.
Definition: track.h:262
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
bool GetSubtractMaskFromSilk() const
SHAPE_LINE_CHAIN.
When creating polygons to create a clearance polygonal area, the polygon must be same or bigger than ...
void PlotFootprintGraphicItem(FP_SHAPE *aShape)
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
virtual void SetPenNumber(int number)
Definition: plotter_hpgl.h:82
void PlotDrawingSheet(PLOTTER *plotter, const PROJECT *aProject, const TITLE_BLOCK &aTitleBlock, const PAGE_INFO &aPageInfo, const wxString &aSheetNumber, int aSheetCount, const wxString &aSheetDesc, const wxString &aFilename, COLOR4D aColor, bool aIsFirstPage)
double GetHPGLPenDiameter() const
VECTOR2I A
Definition: seg.h:49
Handle the component boundary box.
Definition: eda_rect.h:42
VIATYPE GetViaType() const
Definition: track.h:373
#define IU_PER_MILS
Definition: plotter.cpp:137
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:68
void InflateWithLinkedHoles(int aFactor, int aCircleSegmentsCount, POLYGON_MODE aFastMode)
Perform outline inflation/deflation, using round corners.
wxPoint Centre() const
Definition: eda_rect.h:60
void ClearHeaderLinesList()
Remove all lines from the list of free lines to print at the beginning of the file.
Definition: plotter.h:188
virtual void ThickArc(const wxPoint &centre, double StAngle, double EndAngle, int rayon, int width, OUTLINE_MODE tracemode, void *aData)
Definition: plotter.cpp:530
EDA_RECT ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Calculate the bounding box containing all board items (or board edge segments).
Definition: board.cpp:1029
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
double GetFineScaleAdjustY() const
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void SetApertureAttrib(GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB aApertAttribute)
Definition: gbr_metadata.h:209
COLOR_SETTINGS * ColorSettings() const
DXF_UNITS GetDXFPlotUnits() const
double GetArcAngleStart() const
Definition: track.cpp:940
bool m_NotInNet
true if a pad of a footprint cannot be connected (for instance a mechanical NPTH, ot a not named pad)...
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: zone.cpp:235
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
bool GetSvgUseInch() const
int getFineWidthAdj()
Definition: pcbplot.h:81
GBR_NETLIST_METADATA m_NetlistMetadata
An item to handle object attribute.
Definition: gbr_metadata.h:262
bool GetNegative() const
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: track.cpp:361
bool GetUseAuxOrigin() const
Definition: pad.h:60
void SetDefaultPenWidth(int aWidth)
wxPoint GetPosition() const override
Definition: track.h:411
DrillMarksType GetDrillMarksType() const
int GetWidth() const
static constexpr int Millimeter2iu(double mm)
print info associated to a net (TO.N attribute)
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
wxPoint m_AuxOrigin
origin for plot exports
COLOR4D getColor(LAYER_NUM aLayer)
Function getColor.
TRACKS & Tracks()
Definition: board.h:300
bool GetExcludeEdgeLayer() const
Definition: track.h:83
virtual void FlashPadCircle(const wxPoint &aPadPos, int aDiameter, OUTLINE_MODE aTraceMode, void *aData)=0
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Inflate the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:363
const wxSize GetSize() const
Definition: eda_rect.h:96
virtual void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition: plotter.h:157
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...
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:98
VECTOR2I B
Definition: seg.h:50