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 
27 
28 #include <vector>
29 
30 #include <plotter.h>
31 #include <plotters_specific.h>
32 #include <kicad_string.h>
33 #include <locale_io.h>
34 #include <macros.h>
35 #include <pcb_edit_frame.h>
36 
37 #include <board.h>
38 #include <board_design_settings.h>
39 
40 #include <pcbplot.h>
42 #include <gbr_metadata.h>
43 #include <footprint.h>
44 #include <pad.h>
45 
46 
48 {
49  m_pcb = aPcb;
50  m_plotPad1Marker = true; // Place a marker to pin 1 (or A1) position
51  m_plotOtherPadsMarker = true; // Place a marker to other pins position
52  m_layer = PCB_LAYER_ID::UNDEFINED_LAYER; // No layer set
53 }
54 
55 
56 int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename, PCB_LAYER_ID aLayer,
57  bool aIncludeBrdEdges )
58 {
59  m_layer = aLayer;
60 
61  PCB_PLOT_PARAMS plotOpts = m_pcb->GetPlotOptions();
62 
63  if( plotOpts.GetUseAuxOrigin() )
65 
66  // Collect footprints on the right layer
67  std::vector<FOOTPRINT*> fp_list;
68 
69  for( FOOTPRINT* footprint : m_pcb->Footprints() )
70  {
71  if( footprint->GetAttributes() & FP_EXCLUDE_FROM_POS_FILES )
72  continue;
73 
74  if( footprint->GetLayer() == aLayer )
75  fp_list.push_back( footprint );
76  }
77 
78  LOCALE_IO dummy_io; // Use the standard notation for float numbers
79 
80  GERBER_PLOTTER plotter;
81 
82  // Gerber drill file imply X2 format:
83  plotter.UseX2format( true );
84  plotter.UseX2NetAttributes( true );
85 
86  // Add the standard X2 header, without FileFunction
87  AddGerberX2Header( &plotter, m_pcb );
88  plotter.SetViewport( m_offset, IU_PER_MILS/10, /* scale */ 1.0, /* mirror */false );
89  // has meaning only for gerber plotter. Must be called only after SetViewport
90  plotter.SetGerberCoordinatesFormat( 6 );
91  plotter.SetCreator( wxT( "PCBNEW" ) );
92 
93  // Add the standard X2 FileFunction for P&P files
94  // %TF.FileFunction,Component,Ln,[top][bottom]*%
95  wxString text;
96  text.Printf( "%%TF.FileFunction,Component,L%d,%s*%%",
97  aLayer == B_Cu ? m_pcb->GetCopperLayerCount() : 1,
98  aLayer == B_Cu ? "Bot" : "Top" );
99  plotter.AddLineToHeader( text );
100 
101  // Add file polarity (positive)
102  text = "%TF.FilePolarity,Positive*%";
103  plotter.AddLineToHeader( text );
104 
105  if( !plotter.OpenFile( aFullFilename ) )
106  return -1;
107 
108  // We need a BRDITEMS_PLOTTER to plot pads
109  BRDITEMS_PLOTTER brd_plotter( &plotter, m_pcb, plotOpts );
110 
111  plotter.StartPlot();
112 
113  // Some tools in P&P files have the type and size defined.
114  // they are position flash (round), pad1 flash (diamond), other pads flash (round)
115  // and component outline thickness (polyline)
116  int flash_position_shape_diam = Millimeter2iu( 0.3 ); // defined size for position shape (circle)
117  int pad1_mark_size = Millimeter2iu( 0.36 ); // defined size for pad 1 position (diamond)
118  int other_pads_mark_size = 0; // defined size for position shape (circle)
119  int line_thickness = Millimeter2iu( 0.1 ); // defined size for component outlines
120 
121  brd_plotter.SetLayerSet( LSET( aLayer ) );
122  int cmp_count = 0;
123  bool allowUtf8 = true;
124 
125  // Plot components data: position, outlines, pad1 and other pads.
126  for( FOOTPRINT* footprint : fp_list )
127  {
128  // Manage the aperture attribute component position:
129  GBR_METADATA gbr_metadata;
131 
132  // Add object attribute: component reference to flash (mainly useful for users)
133  // using quoted UTF8 string
134  wxString ref = ConvertNotAllowedCharsInGerber( footprint->Reference().GetShownText(),
135  allowUtf8, true );
136 
137  gbr_metadata.SetCmpReference( ref );
139 
140  // Add P&P specific attributes
141  GBR_CMP_PNP_METADATA pnpAttrib;
142 
143  // Add rotation info (rotation is CCW, in degrees):
144  pnpAttrib.m_Orientation = mapRotationAngle( footprint->GetOrientationDegrees() );
145 
147 
148  if( footprint->GetAttributes() & FP_THROUGH_HOLE )
150  else if( footprint->GetAttributes() & FP_SMD )
152 
153  // Add component value info:
154  pnpAttrib.m_Value = ConvertNotAllowedCharsInGerber( footprint->Value().GetShownText(),
155  allowUtf8, true );
156 
157  // Add component footprint info:
158  wxString fp_info = FROM_UTF8( footprint->GetFPID().GetLibItemName().c_str() );
159  pnpAttrib.m_Footprint = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, true );
160 
161  // Add footprint lib name:
162  fp_info = FROM_UTF8( footprint->GetFPID().GetLibNickname().c_str() );
163  pnpAttrib.m_LibraryName = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, true );
164 
165  gbr_metadata.m_NetlistMetadata.SetExtraData( pnpAttrib.FormatCmpPnPMetadata() );
166 
167  wxPoint flash_pos = footprint->GetPosition();
168 
169  plotter.FlashPadCircle( flash_pos, flash_position_shape_diam, FILLED, &gbr_metadata );
170  gbr_metadata.m_NetlistMetadata.ClearExtraData();
171 
172  // Now some extra metadata is output, avoid blindly clearing the full metadata list
174 
175  // We plot the footprint courtyard when possible.
176  // If not, the pads bounding box will be used.
177  bool useFpPadsBbox = true;
178  bool onBack = aLayer == B_Cu;
179 
180  footprint->BuildPolyCourtyards();
181 
182  int checkFlag = onBack ? MALFORMED_B_COURTYARD : MALFORMED_F_COURTYARD;
183 
184  if( ( footprint->GetFlags() & checkFlag ) == 0 )
185  {
187 
188  const SHAPE_POLY_SET& courtyard = onBack ? footprint->GetPolyCourtyardBack()
189  : footprint->GetPolyCourtyardFront();
190 
191  for( int ii = 0; ii < courtyard.OutlineCount(); ii++ )
192  {
193  SHAPE_LINE_CHAIN poly = courtyard.Outline( ii );
194 
195  if( !poly.PointCount() )
196  continue;
197 
198  useFpPadsBbox = false;
199  plotter.PLOTTER::PlotPoly( poly, FILL_TYPE::NO_FILL, line_thickness, &gbr_metadata );
200  }
201  }
202 
203  if( useFpPadsBbox )
204  {
206 
207  // bbox of fp pads, pos 0, rot 0, non flipped
208  EDA_RECT bbox = footprint->GetFpPadsLocalBbox();
209 
210  // negate bbox Y values if the fp is flipped (always flipped around X axis
211  // in Gerber P&P files).
212  int y_sign = aLayer == B_Cu ? -1 : 1;
213 
214  SHAPE_LINE_CHAIN poly;
215  poly.Append( bbox.GetLeft(), y_sign*bbox.GetTop() );
216  poly.Append( bbox.GetLeft(), y_sign*bbox.GetBottom() );
217  poly.Append( bbox.GetRight(), y_sign*bbox.GetBottom() );
218  poly.Append( bbox.GetRight(), y_sign*bbox.GetTop() );
219  poly.SetClosed( true );
220 
221  poly.Rotate( -footprint->GetOrientationRadians(), VECTOR2I( 0, 0 ) );
222  poly.Move( footprint->GetPosition() );
223  plotter.PLOTTER::PlotPoly( poly, FILL_TYPE::NO_FILL, line_thickness, &gbr_metadata );
224  }
225 
226  std::vector<PAD*>pad_key_list;
227 
228  if( m_plotPad1Marker )
229  {
230  findPads1( pad_key_list, footprint );
231 
232  for( PAD* pad1 : pad_key_list )
233  {
234  gbr_metadata.SetApertureAttrib(
236 
237  gbr_metadata.SetPadName( pad1->GetName(), allowUtf8, true );
238 
239  gbr_metadata.SetPadPinFunction( pad1->GetPinFunction(), allowUtf8, true );
240 
242 
243  // Flashes a diamond at pad position:
244  plotter.FlashRegularPolygon( pad1->GetPosition(),
245  pad1_mark_size,
246  4, 0.0, FILLED, &gbr_metadata );
247  }
248  }
249 
251  {
252 
253  gbr_metadata.SetApertureAttrib(
256 
257  for( PAD* pad: footprint->Pads() )
258  {
259  bool skip_pad = false;
260 
261  for( PAD* pad1 : pad_key_list )
262  {
263  if( pad == pad1 ) // Already plotted
264  {
265  skip_pad = true;
266  break;
267  }
268  }
269 
270  if( skip_pad )
271  continue;
272 
273  // Skip also pads not on the current layer, like pads only
274  // on a tech layer
275  if( !pad->IsOnLayer( aLayer ) )
276  continue;
277 
278  gbr_metadata.SetPadName( pad->GetName(), allowUtf8, true );
279 
280  gbr_metadata.SetPadPinFunction( pad->GetPinFunction(), allowUtf8, true );
281 
282  // Flashes a round, 0 sized round shape at pad position
283  plotter.FlashPadCircle( pad->GetPosition(),
284  other_pads_mark_size,
285  FILLED, &gbr_metadata );
286  }
287  }
288 
289  plotter.ClearAllAttributes(); // Unconditionally close all .TO attributes
290 
291  cmp_count++;
292  }
293 
294  // Plot board outlines, if requested
295  if( aIncludeBrdEdges )
296  {
297  brd_plotter.SetLayerSet( LSET( Edge_Cuts ) );
298 
299  // Plot edge layer and graphic items
300  brd_plotter.PlotBoardGraphicItems();
301 
302  // Draw footprint other graphic items:
303  for( FOOTPRINT* footprint : fp_list )
304  {
305  for( BOARD_ITEM* item : footprint->GraphicalItems() )
306  {
307  if( item->Type() == PCB_FP_SHAPE_T && item->GetLayer() == Edge_Cuts )
308  brd_plotter.PlotFootprintGraphicItem( (FP_SHAPE*) item );
309  }
310  }
311  }
312 
313 
314  plotter.EndPlot();
315 
316  return cmp_count;
317 }
318 
319 
321 {
322  // convert a kicad footprint orientation to gerber rotation, depending on the layer
323  // Currently, same notation as kicad
324  return aAngle;
325 }
326 
327 
328 void PLACEFILE_GERBER_WRITER::findPads1( std::vector<PAD*>& aPadList, FOOTPRINT* aFootprint ) const
329 {
330  // Fint the pad "1" or pad "A1"
331  // this is possible only if only one pad is found
332  // useful to place a marker in this position
333 
334  for( PAD* pad : aFootprint->Pads() )
335  {
336  if( !pad->IsOnLayer( m_layer ) )
337  continue;
338 
339  if( pad->GetName() == "1" || pad->GetName() == "A1")
340  aPadList.push_back( pad );
341  }
342 }
343 
344 
345 const wxString PLACEFILE_GERBER_WRITER::GetPlaceFileName( const wxString& aFullBaseFilename,
346  PCB_LAYER_ID aLayer ) const
347 {
348  // Gerber files extension is always .gbr.
349  // Therefore, to mark pnp files, add "-pnp" to the filename, and a layer id.
350  wxFileName fn = aFullBaseFilename;
351 
352  wxString post_id = "-pnp_";
353  post_id += aLayer == B_Cu ? "bottom" : "top";
354  fn.SetName( fn.GetName() + post_id );
355  fn.SetExt( GerberFileExtension );
356 
357  return fn.GetFullPath();
358 }
virtual void FlashRegularPolygon(const wxPoint &aShapePos, int aDiameter, int aCornerCount, double aOrient, OUTLINE_MODE aTraceMode, void *aData) override
Flash a regular polygon.
Handle special data (items attributes) during plot.
Classes used in place file generation.
int CreatePlaceFile(wxString &aFullFilename, PCB_LAYER_ID aLayer, bool aIncludeBrdEdges)
Create an pnp gerber file.
aperture used to draw component outline courtyard in placement files.
Definition: gbr_metadata.h:161
Plot settings, and plotting engines (PostScript, Gerber, HPGL and DXF)
virtual void SetCreator(const wxString &aCreator)
Definition: plotter.h:174
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:538
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void UseX2NetAttributes(bool aEnable)
#define MALFORMED_B_COURTYARD
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
aperture used for flashed pads position in placement files.
Definition: gbr_metadata.h:149
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:40
aperture used to draw component physical body outline without pins in placement files.
Definition: gbr_metadata.h:152
print info associated to a component (TO.C attribute)
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:80
Plotting engines (PostScript, Gerber, HPGL and DXF)
int GetTop() const
Definition: eda_rect.h:113
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
#define MALFORMED_F_COURTYARD
int GetLeft() const
Definition: eda_rect.h:112
void Move(const VECTOR2I &aVector) override
void AddGerberX2Header(PLOTTER *aPlotter, const BOARD *aBoard, bool aUseX1CompatibilityMode)
Calculate some X2 attributes as defined in the Gerber file format specification J4 (chapter 5) and ad...
Definition: pcbplot.cpp:282
void UseX2format(bool aEnable)
class FP_SHAPE, a footprint edge
Definition: typeinfo.h:93
const std::string GerberFileExtension
void PlotFootprintGraphicItem(const FP_SHAPE *aShape)
void AddLineToHeader(const wxString &aExtraString)
Add a line to the list of free lines to print at the beginning of the file.
Definition: plotter.h:183
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
int PointCount() const
Return the number of points (vertices) in this line chain.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:588
virtual bool StartPlot() override
Write GERBER header to file initialize global variable g_Plot_PlotOutputFile.
Information which can be added in a gerber P&P file as attribute of a component.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
PADS & Pads()
Definition: footprint.h:159
This file contains miscellaneous commonly used macros and functions.
int GetBottom() const
Definition: eda_rect.h:114
void SetPadPinFunction(const wxString &aPadPinFunction, bool aUseUTF8, bool aEscapeString)
Definition: gbr_metadata.h:236
Board plot function definition file.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
PCB_LAYER_ID
A quick note on layer IDs:
LSET is a set of PCB_LAYER_IDs.
void SetLayerSet(LSET aLayerMask)
Definition: pcbplot.h:84
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.
Represent a set of closed polygons.
void SetPadName(const wxString &aPadname, bool aUseUTF8=false, bool aEscapeString=false)
Definition: gbr_metadata.h:231
SHAPE_LINE_CHAIN & Outline(int aIndex)
void PlotBoardGraphicItems()
Plot items like text and graphics but not tracks and footprints.
FOOTPRINTS & Footprints()
Definition: board.h:233
int GetRight() const
Definition: eda_rect.h:111
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.
Metadata which can be added in a gerber file as attribute in X2 format.
Definition: gbr_metadata.h:204
Parameters and options when plotting/printing a board.
void Rotate(double aAngle, const VECTOR2I &aCenter=VECTOR2I(0, 0)) override
Rotate all vertices by a given angle.
aperture used for flashed pin 1 (or A1 or AA1) position in placement files.
Definition: gbr_metadata.h:146
const wxString GetPlaceFileName(const wxString &aFullBaseFilename, PCB_LAYER_ID aLayer) const
wxString FormatCmpPnPMetadata()
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
void findPads1(std::vector< PAD * > &aPadList, FOOTPRINT *aFootprint) const
Find the pad(s) 1 (or pad "A1") of a footprint.
virtual bool EndPlot() override
Represent a polyline (an zero-thickness chain of connected line segments).
int GetCopperLayerCount() const
Definition: board.cpp:453
Handle the component boundary box.
Definition: eda_rect.h:42
#define IU_PER_MILS
Definition: plotter.cpp:137
bool m_TryKeepPreviousAttributes
If true, do not clear all attributes when a attribute has changed.
wxString ConvertNotAllowedCharsInGerber(const wxString &aString, bool aAllowUtf8Chars, bool aQuoteString)
Normalize aString and convert it to a Gerber compatible wxString.
virtual void SetGerberCoordinatesFormat(int aResolution, bool aUseInches=false) override
Selection of Gerber units and resolution (number of digits in mantissa).
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:209
virtual void FlashPadCircle(const wxPoint &pos, int diametre, OUTLINE_MODE trace_mode, void *aData) override
Filled circular flashes are stored as apertures.
GBR_NETLIST_METADATA m_NetlistMetadata
An item to handle object attribute.
Definition: gbr_metadata.h:262
bool GetUseAuxOrigin() const
Definition: pad.h:57
static constexpr int Millimeter2iu(double mm)
void SetCmpReference(const wxString &aComponentRef)
Definition: gbr_metadata.h:241
wxPoint m_AuxOrigin
origin for plot exports
void ClearExtraData()
Clear the extra data string printed at end of net attributes.