KiCad PCB EDA Suite
gerber_placefile_writer.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2019 Jean_Pierre Charras <jp.charras at wanadoo.fr>
5  * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation, either version 3 of the License, or (at your
10  * option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
26 #include <fctsys.h>
28 
29 #include <vector>
30 
31 #include <plotter.h>
32 #include <kicad_string.h>
33 #include <pcb_edit_frame.h>
34 #include <pgm_base.h>
35 #include <build_version.h>
36 
37 #include <class_board.h>
38 
39 #include <pcbplot.h>
40 #include <pcbnew.h>
42 #include <reporter.h>
43 #include <gbr_metadata.h>
44 #include <class_module.h>
45 #include <pcbplot.h>
46 
47 
49 {
50  m_pcb = aPcb;
51  /* Set conversion scale depending on drill file units */
52  m_conversionUnits = 1.0 / IU_PER_MM; // Gerber units = mm
53  m_forceSmdItems = false;
54  m_plotPad1Marker = true; // Place a marker to pin 1 (or A1) position
55  m_plotOtherPadsMarker = true; // Place a marker to other pins position
56  m_layer = PCB_LAYER_ID::UNDEFINED_LAYER; // No layer set
57 }
58 
59 
60 int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename,
61  PCB_LAYER_ID aLayer, bool aIncludeBrdEdges
62 )
63 {
64  m_layer = aLayer;
65 
66  PCB_PLOT_PARAMS plotOpts = m_pcb->GetPlotOptions();
67 
68  if( plotOpts.GetUseAuxOrigin() )
70 
71  // Collect footprints on the right layer
72  std::vector<MODULE*> fp_list;
73 
74  for( MODULE* footprint : m_pcb->Modules() )
75  {
76  if( footprint->GetAttributes() & MOD_VIRTUAL )
77  continue;
78 
79  if( footprint->GetLayer() == aLayer )
80  fp_list.push_back( footprint );
81  }
82 
83  LOCALE_IO dummy_io; // Use the standard notation for float numbers
84 
85  GERBER_PLOTTER plotter;
86 
87  // Gerber drill file imply X2 format:
88  plotter.UseX2format( true );
89  plotter.UseX2NetAttributes( true );
90 
91  // Add the standard X2 header, without FileFunction
92  AddGerberX2Header( &plotter, m_pcb );
93  plotter.SetViewport( m_offset, IU_PER_MILS/10, /* scale */ 1.0, /* mirror */false );
94  // has meaning only for gerber plotter. Must be called only after SetViewport
95  plotter.SetGerberCoordinatesFormat( 6 );
96  plotter.SetCreator( wxT( "PCBNEW" ) );
97 
98  // Add the standard X2 FileFunction for P&P files
99  // %TF.FileFunction,Component,Ln,[top][bottom]*%
100  wxString text;
101  text.Printf( "%%TF.FileFunction,Component,L%d,%s*%%",
102  aLayer == B_Cu ? m_pcb->GetCopperLayerCount() : 1,
103  aLayer == B_Cu ? "Bot" : "Top" );
104  plotter.AddLineToHeader( text );
105 
106  // Add file polarity (positive)
107  text = "%TF.FilePolarity,Positive*%";
108  plotter.AddLineToHeader( text );
109 
110  if( !plotter.OpenFile( aFullFilename ) )
111  return -1;
112 
113  // We need a BRDITEMS_PLOTTER to plot pads
114  BRDITEMS_PLOTTER brd_plotter( &plotter, m_pcb, plotOpts );
115 
116  plotter.StartPlot();
117 
118  // Some tools in P&P files have the type and size defined.
119  // they are position flash (round), pad1 flash (diamond), other pads flash (round)
120  // and component outline thickness (polyline)
121  int flash_position_shape_diam = Millimeter2iu( 0.3 ); // defined size for position shape (circle)
122  int pad1_mark_size = Millimeter2iu( 0.36 ); // defined size for pad 1 position (diamond)
123  int other_pads_mark_size = 0; // defined size for position shape (circle)
124  int line_thickness = Millimeter2iu( 0.1 ); // defined size for component outlines
125 
126  brd_plotter.SetLayerSet( LSET( aLayer ) );
127  int cmp_count = 0;
128  bool allowUtf8 = true;
129 
130  // Plot components data: position, outlines, pad1 and other pads.
131  for( MODULE* footprint : fp_list )
132  {
133  // Manage the aperture attribute component position:
134  GBR_METADATA gbr_metadata;
136 
137  // Add object attribute: component reference to flash (mainly usefull for users)
138  // using quoted UTF8 string
139  wxString ref = ConvertNotAllowedCharsInGerber( footprint->GetReference(),
140  allowUtf8, true );
141 
142  gbr_metadata.SetCmpReference( ref );
144 
145  // Add P&P specific attributes
146  GBR_CMP_PNP_METADATA pnpAttrib;
147 
148  // Add rotation info (rotation is CCW, in degrees):
149  pnpAttrib.m_Orientation = mapRotationAngle( footprint->GetOrientationDegrees() );
150 
151  // Add component type info (SMD or Through Hole):
152  bool is_smd_mount = footprint->GetAttributes() & MOD_CMS;
153 
154  // Smd footprints can have through holes (thermal vias).
155  // but if a footprint is not set as SMD, it will be set as SMD
156  // if it does not have through hole pads
157  if( !is_smd_mount && !footprint->HasNonSMDPins() )
158  is_smd_mount = true;
159 
160  pnpAttrib.m_MountType = is_smd_mount ? GBR_CMP_PNP_METADATA::MOUNT_TYPE_SMD
162 
163  // Add component value info:
164  pnpAttrib.m_Value = ConvertNotAllowedCharsInGerber( footprint->GetValue(), allowUtf8, true );
165 
166  // Add component footprint info:
167  wxString fp_info = FROM_UTF8( footprint->GetFPID().GetLibItemName().c_str() );
168  pnpAttrib.m_Footprint = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, true );
169 
170  // Add footprint lib name:
171  fp_info = FROM_UTF8( footprint->GetFPID().GetLibNickname().c_str() );
172  pnpAttrib.m_LibraryName = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, true );
173 
174  gbr_metadata.m_NetlistMetadata.SetExtraData( pnpAttrib.FormatCmpPnPMetadata() );
175 
176  wxPoint flash_pos = footprint->GetPosition();
177 
178  plotter.FlashPadCircle( flash_pos, flash_position_shape_diam, FILLED, &gbr_metadata );
179  gbr_metadata.m_NetlistMetadata.ClearExtraData();
180 
181  // Now some extra metadata is output, avoid blindly clearing the full metadata list
183 
184  // We plot the footprint courtyard when possible.
185  // If not, the pads bounding box will be used.
186  bool useFpPadsBbox = true;
187 
188  if( footprint->BuildPolyCourtyard() )
189  {
191 
192  SHAPE_POLY_SET& courtyard = aLayer == B_Cu ?
193  footprint->GetPolyCourtyardBack():
194  footprint->GetPolyCourtyardFront();
195 
196  for( int ii = 0; ii < courtyard.OutlineCount(); ii++ )
197  {
198  SHAPE_LINE_CHAIN poly = courtyard.Outline( ii );
199 
200  if( !poly.PointCount() )
201  continue;
202 
203  useFpPadsBbox = false;
204  plotter.PLOTTER::PlotPoly( poly, NO_FILL, line_thickness, &gbr_metadata );
205  }
206  }
207 
208  if( useFpPadsBbox )
209  {
211 
212  // bbox of fp pads, pos 0, rot 0, non flipped
213  EDA_RECT bbox = footprint->GetFpPadsLocalBbox();
214 
215  // negate bbox Y values if the fp is flipped (always flipped around X axis
216  // in Gerber P&P files).
217  int y_sign = aLayer == B_Cu ? -1 : 1;
218 
219  SHAPE_LINE_CHAIN poly;
220  poly.Append( bbox.GetLeft(), y_sign*bbox.GetTop() );
221  poly.Append( bbox.GetLeft(), y_sign*bbox.GetBottom() );
222  poly.Append( bbox.GetRight(), y_sign*bbox.GetBottom() );
223  poly.Append( bbox.GetRight(), y_sign*bbox.GetTop() );
224  poly.SetClosed( true );
225 
226  poly.Rotate( -footprint->GetOrientationRadians(), VECTOR2I( 0, 0 ) );
227  poly.Move( footprint->GetPosition() );
228  plotter.PLOTTER::PlotPoly( poly, NO_FILL, line_thickness, &gbr_metadata );
229  }
230 
231  std::vector<D_PAD*>pad_key_list;
232 
233  if( m_plotPad1Marker )
234  {
235  findPads1( pad_key_list, footprint );
236 
237  for( D_PAD* pad1 : pad_key_list )
238  {
239  gbr_metadata.SetApertureAttrib(
241 
242  gbr_metadata.SetPadName( pad1->GetName(), allowUtf8, true );
243 
244  gbr_metadata.SetPadPinFunction( pad1->GetPinFunction(), allowUtf8, true );
245 
247 
248  // Flashes a diamond at pad position:
249  plotter.FlashRegularPolygon( pad1->GetPosition(),
250  pad1_mark_size,
251  4, 0.0, FILLED, &gbr_metadata );
252  }
253  }
254 
256  {
257 
258  gbr_metadata.SetApertureAttrib(
261 
262  for( D_PAD* pad: footprint->Pads() )
263  {
264  bool skip_pad = false;
265 
266  for( D_PAD* pad1 : pad_key_list )
267  {
268  if( pad == pad1 ) // Already plotted
269  {
270  skip_pad = true;
271  break;
272  }
273  }
274 
275  if( skip_pad )
276  continue;
277 
278  // Skip also pads not on the current layer, like pads only
279  // on a tech layer
280  if( !pad->IsOnLayer( aLayer ) )
281  continue;
282 
283  gbr_metadata.SetPadName( pad->GetName(), allowUtf8, true );
284 
285  gbr_metadata.SetPadPinFunction( pad->GetPinFunction(), allowUtf8, true );
286 
287  // Flashes a round, 0 sized round shape at pad position
288  plotter.FlashPadCircle( pad->GetPosition(),
289  other_pads_mark_size,
290  FILLED, &gbr_metadata );
291  }
292  }
293 
294  plotter.ClearAllAttributes(); // Unconditionally close all .TO attributes
295 
296  cmp_count++;
297  }
298 
299  // Plot board outlines, if requested
300  if( aIncludeBrdEdges )
301  {
302  brd_plotter.SetLayerSet( LSET( Edge_Cuts ) );
303 
304  // Plot edge layer and graphic items
305  brd_plotter.PlotBoardGraphicItems();
306 
307  // Draw footprint other graphic items:
308  for( MODULE* footprint : fp_list )
309  {
310  for( auto item : footprint->GraphicalItems() )
311  {
312  if( item->Type() == PCB_MODULE_EDGE_T && item->GetLayer() == Edge_Cuts )
313  brd_plotter.Plot_1_EdgeModule( (EDGE_MODULE*) item );
314  }
315  }
316  }
317 
318 
319  plotter.EndPlot();
320 
321  return cmp_count;
322 }
323 
324 
326 {
327  // convert a kicad footprint orientation to gerber rotation, depending on the layer
328  // Currently, same notation as kicad
329  return aAngle;
330 }
331 
332 
333 void PLACEFILE_GERBER_WRITER::findPads1( std::vector<D_PAD*>& aPadList, MODULE* aFootprint ) const
334 {
335  // Fint the pad "1" or pad "A1"
336  // this is possible only if only one pad is found
337  // Usefull to place a marker in this position
338 
339  for( D_PAD* pad : aFootprint->Pads() )
340  {
341  if( !pad->IsOnLayer( m_layer ) )
342  continue;
343 
344  if( pad->GetName() == "1" || pad->GetName() == "A1")
345  aPadList.push_back( pad );
346  }
347 }
348 
349 
350 const wxString PLACEFILE_GERBER_WRITER::GetPlaceFileName( const wxString& aFullBaseFilename,
351  PCB_LAYER_ID aLayer ) const
352 {
353  // Gerber files extension is always .gbr.
354  // Therefore, to mark pnp files, add "-pnp" to the filename, and a layer id.
355  wxFileName fn = aFullBaseFilename;
356 
357  wxString post_id = "-pnp_";
358  post_id += aLayer == B_Cu ? "bottom" : "top";
359  fn.SetName( fn.GetName() + post_id );
360  fn.SetExt( GerberFileExtension );
361 
362  return fn.GetFullPath();
363 }
a class to handle special data (items attributes) during plot.
Classes used in place file generation.
int CreatePlaceFile(wxString &aFullFilename, PCB_LAYER_ID aLayer, bool aIncludeBrdEdges)
Creates an pnp gerber file.
void findPads1(std::vector< D_PAD * > &aPadList, MODULE *aFootprint) const
Find the pad(s) 1 (or pad "A1") of a footprint Usefull to plot a marker at this (these) position(s)
aperture used to draw component footprint bounding box in placement files
Definition: gbr_metadata.h:113
virtual void SetCreator(const wxString &aCreator)
Definition: plotter.h:167
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: class_board.h:548
int OutlineCount() const
Returns the number of outlines in the set
void UseX2NetAttributes(bool aEnable)
Definition: plotter.h:1282
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:62
aperture used for flashed pin 1 (or A1 or AA1) position in placement files
Definition: gbr_metadata.h:107
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:90
aperture used for flashed pads position in placement files
Definition: gbr_metadata.h:108
print info associated to a component (TO.C attribute)
int GetTop() const
Definition: eda_rect.h:123
void Rotate(double aAngle, const VECTOR2I &aCenter=VECTOR2I(0, 0))
Function Rotate rotates all vertices by a given angle.
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition: plotter.cpp:82
void SetNetAttribType(int aNetAttribType)
Definition: gbr_metadata.h:170
int GetLeft() const
Definition: eda_rect.h:122
void Move(const VECTOR2I &aVector) override
virtual void FlashRegularPolygon(const wxPoint &aShapePos, int aDiameter, int aCornerCount, double aOrient, EDA_DRAW_MODE_T aTraceMode, void *aData) override
Flash a regular polygon.
PADS & Pads()
Definition: class_module.h:173
Set for modules listed in the automatic insertion list (usually SMD footprints)
Definition: class_module.h:74
void AddGerberX2Header(PLOTTER *aPlotter, const BOARD *aBoard, bool aUseX1CompatibilityMode)
Calculates some X2 attributes, as defined in the Gerber file format specification J4 (chapter 5) and ...
Definition: pcbplot.cpp:282
void UseX2format(bool aEnable)
Definition: plotter.h:1281
const std::string GerberFileExtension
void AddLineToHeader(const wxString &aExtraString)
Function AddLineToHeader Add a line to the list of free lines to print at the beginning of the file.
Definition: plotter.h:182
VECTOR2< int > VECTOR2I
Definition: vector2d.h:594
int PointCount() const
Function PointCount()
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
virtual bool StartPlot() override
Function StartPlot Write GERBER header to file initialize global variable g_Plot_PlotOutputFile.
this class handle info which can be added in a gerber P&P file as attribute of a component Only appli...
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
int GetBottom() const
Definition: eda_rect.h:124
void SetPadPinFunction(const wxString &aPadPinFunction, bool aUseUTF8, bool aEscapeString)
Definition: gbr_metadata.h:187
Board plot function definition file.
void SetClosed(bool aClosed)
Function SetClosed()
PCB_LAYER_ID
A quick note on layer IDs:
LSET is a set of PCB_LAYER_IDs.
void SetLayerSet(LSET aLayerMask)
Definition: pcbplot.h:105
void ClearAllAttributes()
Remove (clear) all attributes from object attributes dictionary (TO.
void SetExtraData(const wxString &aExtraData)
Set the extra data string printed at end of net attributes.
MODULES & Modules()
Definition: class_board.h:226
SHAPE_POLY_SET.
void SetPadName(const wxString &aPadname, bool aUseUTF8=false, bool aEscapeString=false)
Definition: gbr_metadata.h:182
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
void PlotBoardGraphicItems()
plot items like text and graphics, but not tracks and modules
int GetRight() const
Definition: eda_rect.h:121
void Plot_1_EdgeModule(EDGE_MODULE *aEdge)
PCB_LAYER_ID m_layer
The board layer currently used (typically F_Cu or B_Cu)
Definition of file extensions used in Kicad.
virtual void SetViewport(const wxPoint &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the plot offset and scaling for the current plot.
const wxPoint & GetAuxOrigin() const
Definition: class_board.h:353
aperture used to draw component outline courtyard in placement files
Definition: gbr_metadata.h:115
PCB_PLOT_PARAMS handles plot parameters and options when plotting/printing a board.
virtual void FlashPadCircle(const wxPoint &pos, int diametre, EDA_DRAW_MODE_T trace_mode, void *aData) override
Filled circular flashes are stored as apertures.
aperture used for flashed cmp position in placement files
Definition: gbr_metadata.h:106
const wxString GetPlaceFileName(const wxString &aFullBaseFilename, PCB_LAYER_ID aLayer) const
see class PGM_BASE
wxString FormatCmpPnPMetadata()
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:160
virtual bool EndPlot() override
SHAPE_LINE_CHAIN.
Virtual component: when created by copper shapes on board (Like edge card connectors,...
Definition: class_module.h:76
int GetCopperLayerCount() const
Function GetCopperLayerCount.
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
#define IU_PER_MILS
Definition: plotter.cpp:137
bool m_TryKeepPreviousAttributes
If true, do not clear all attributes when a atribute has changed Usefull when some attributes need to...
wxString ConvertNotAllowedCharsInGerber(const wxString &aString, bool aAllowUtf8Chars, bool aQuoteString)
Similar to FormatStringToGerber.
virtual void SetGerberCoordinatesFormat(int aResolution, bool aUseInches=false) override
Function SetGerberCoordinatesFormat selection of Gerber units and resolution (number of digits in man...
print info associated to a flashed pad (TO.P attribute)
double mapRotationAngle(double aAngle)
convert a kicad footprint orientation to gerber rotation both are in degrees
void SetApertureAttrib(GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB aApertAttribute)
Definition: gbr_metadata.h:160
GBR_NETLIST_METADATA m_NetlistMetadata
a item to handle object attribute:
Definition: gbr_metadata.h:212
Module description (excepted pads)
bool GetUseAuxOrigin() const
void SetCmpReference(const wxString &aComponentRef)
Definition: gbr_metadata.h:192
void ClearExtraData()
Clear the extra data string printed at end of net attributes.