KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcbplot.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) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <plotters/plotter.h>
23#include <pcbplot.h>
24#include <common.h>
25#include <base_units.h>
26#include <lset.h>
27#include <locale_io.h>
28#include <reporter.h>
29#include <board.h>
31#include <pcb_plot_params.h>
32#include <wx/ffile.h>
33#include <dialog_plot.h>
34#include <build_version.h>
35#include <gbr_metadata.h>
36#include <render_settings.h>
37#include <pcb_plotter.h>
38
39const wxString GetGerberProtelExtension( int aLayer )
40{
41 if( IsCopperLayer( aLayer ) )
42 {
43 if( aLayer == F_Cu )
44 return wxT( "gtl" );
45 else if( aLayer == B_Cu )
46 return wxT( "gbl" );
47 else
48 return wxString( wxT( "g" ) ) << CopperLayerToOrdinal( ToLAYER_ID( aLayer ) );
49 }
50 else
51 {
52 switch( aLayer )
53 {
54 case B_Adhes: return wxT( "gba" );
55 case F_Adhes: return wxT( "gta" );
56
57 case B_Paste: return wxT( "gbp" );
58 case F_Paste: return wxT( "gtp" );
59
60 case B_SilkS: return wxT( "gbo" );
61 case F_SilkS: return wxT( "gto" );
62
63 case B_Mask: return wxT( "gbs" );
64 case F_Mask: return wxT( "gts" );
65
66 case Edge_Cuts: return wxT( "gm1" );
67
68 case Dwgs_User:
69 case Cmts_User:
70 case Eco1_User:
71 case Eco2_User:
72 default: return wxT( "gbr" );
73 }
74 }
75}
76
77
78const wxString GetGerberFileFunctionAttribute( const BOARD* aBoard, int aLayer )
79{
80 wxString attrib;
81
82
83 switch( aLayer )
84 {
85 case F_Adhes:
86 attrib = wxT( "Glue,Top" );
87 break;
88
89 case B_Adhes:
90 attrib = wxT( "Glue,Bot" );
91 break;
92
93 case F_SilkS:
94 attrib = wxT( "Legend,Top" );
95 break;
96
97 case B_SilkS:
98 attrib = wxT( "Legend,Bot" );
99 break;
100
101 case F_Mask:
102 attrib = wxT( "Soldermask,Top" );
103 break;
104
105 case B_Mask:
106 attrib = wxT( "Soldermask,Bot" );
107 break;
108
109 case F_Paste:
110 attrib = wxT( "Paste,Top" );
111 break;
112
113 case B_Paste:
114 attrib = wxT( "Paste,Bot" );
115 break;
116
117 case Edge_Cuts:
118 // Board outline.
119 // Can be "Profile,NP" (Not Plated: usual) or "Profile,P"
120 // This last is the exception (Plated)
121 attrib = wxT( "Profile,NP" );
122 break;
123
124 case Dwgs_User:
125 attrib = wxT( "OtherDrawing,Comment" );
126 break;
127
128 case Cmts_User:
129 attrib = wxT( "Other,Comment" );
130 break;
131
132 case Eco1_User:
133 attrib = wxT( "Other,ECO1" );
134 break;
135
136 case Eco2_User:
137 attrib = wxT( "Other,ECO2" );
138 break;
139
140 case B_Fab:
141 // This is actually a assembly layer
142 attrib = wxT( "AssemblyDrawing,Bot" );
143 break;
144
145 case F_Fab:
146 // This is actually a assembly layer
147 attrib = wxT( "AssemblyDrawing,Top" );
148 break;
149
150 case B_Cu:
151 attrib.Printf( wxT( "Copper,L%d,Bot" ), aBoard->GetCopperLayerCount() );
152 break;
153
154 case F_Cu:
155 attrib = wxT( "Copper,L1,Top" );
156 break;
157
158 default:
159 if( IsCopperLayer( aLayer ) )
160 {
161 // aLayer use even values, and the first internal layer
162 // is B_Cu + 2. And in gerber file, layer id is 2 (1 is F_Cu)
163 int ly_id = ( ( aLayer - B_Cu ) / 2 ) + 1;
164 attrib.Printf( wxT( "Copper,L%d,Inr" ), ly_id );
165 }
166 else
167 attrib.Printf( wxT( "Other,User" ), aLayer+1 );
168 break;
169 }
170
171 // This code adds a optional parameter: the type of copper layers.
172 // Because it is not used by Pcbnew (it can be used only by external autorouters)
173 // user do not really set this parameter.
174 // Therefore do not add it.
175 // However, this code is left here, for perhaps a future usage.
176#if 0
177 // Add the signal type of the layer, if relevant
178 if( IsCopperLayer( aLayer ) )
179 {
180 LAYER_T type = aBoard->GetLayerType( ToLAYER_ID( aLayer ) );
181
182 switch( type )
183 {
184 case LT_SIGNAL:
185 attrib += wxT( ",Signal" );
186 break;
187 case LT_POWER:
188 attrib += wxT( ",Plane" );
189 break;
190 case LT_MIXED:
191 attrib += wxT( ",Mixed" );
192 break;
193 default:
194 break; // do nothing (but avoid a warning for unhandled LAYER_T values from GCC)
195 }
196 }
197#endif
198
199 wxString fileFct;
200 fileFct.Printf( wxT( "%%TF.FileFunction,%s*%%" ), attrib );
201
202 return fileFct;
203}
204
205
206static const wxString GetGerberFilePolarityAttribute( int aLayer )
207{
208 /* build the string %TF.FilePolarity,Positive*%
209 * or %TF.FilePolarity,Negative*%
210 * an emply string for layers which do not use a polarity
211 *
212 * The value of the .FilePolarity specifies whether the image represents the
213 * presence or absence of material.
214 * This attribute can only be used when the file represents a pattern in a material layer,
215 * e.g. copper, solder mask, legend.
216 * Together with.FileFunction it defines the role of that image in
217 * the layer structure of the PCB.
218 * Note that the .FilePolarity attribute does not change the image -
219 * no attribute does.
220 * It changes the interpretation of the image.
221 * For example, in a copper layer in positive polarity a round flash generates a copper pad.
222 * In a copper layer in negative polarity it generates a clearance.
223 * Solder mask images usually represent solder mask openings and are then negative.
224 * This may be counter-intuitive.
225 */
226 int polarity = 0;
227
228 switch( aLayer )
229 {
230 case F_Adhes:
231 case B_Adhes:
232 case F_SilkS:
233 case B_SilkS:
234 case F_Paste:
235 case B_Paste:
236 polarity = 1;
237 break;
238
239 case F_Mask:
240 case B_Mask:
241 polarity = -1;
242 break;
243
244 default:
245 if( IsCopperLayer( aLayer ) )
246 polarity = 1;
247 break;
248 }
249
250 wxString filePolarity;
251
252 if( polarity == 1 )
253 filePolarity = wxT( "%TF.FilePolarity,Positive*%" );
254 if( polarity == -1 )
255 filePolarity = wxT( "%TF.FilePolarity,Negative*%" );
256
257 return filePolarity;
258}
259
260
261/* Add some X2 attributes to the file header, as defined in the
262 * Gerber file format specification J4 and "Revision 2015.06"
263 */
264
265
266// A helper function to convert a X2 attribute string to a X1 structured comment:
267static wxString& makeStringCompatX1( wxString& aText, bool aUseX1CompatibilityMode )
268{
269 if( aUseX1CompatibilityMode )
270 {
271 aText.Replace( wxT( "%" ), wxEmptyString );
272 aText.Prepend( wxT( "G04 #@! " ) );
273 }
274
275 return aText;
276}
277
278
279// A helper function to replace reserved chars (separators in gerber fields)
280// in a gerber string field.
281// reserved chars are replaced by _ (for ,) or an escaped sequence (for * and %)
282static void replaceReservedCharsField( wxString& aMsg )
283{
284 aMsg.Replace( wxT( "," ), wxT( "_" ) ); // can be replaced by \\u002C
285 aMsg.Replace( wxT( "*" ), wxT( "\\u002A" ) );
286 aMsg.Replace( wxT( "%" ), wxT( "\\u0025" ) );
287}
288
289
290void AddGerberX2Header( PLOTTER* aPlotter, const BOARD* aBoard, bool aUseX1CompatibilityMode )
291{
292 wxString text;
293
294 // Creates the TF,.GenerationSoftware. Format is:
295 // %TF,.GenerationSoftware,<vendor>,<application name>[,<application version>]*%
296 text.Printf( wxT( "%%TF.GenerationSoftware,KiCad,Pcbnew,%s*%%" ), GetBuildVersion() );
297 aPlotter->AddLineToHeader( makeStringCompatX1( text, aUseX1CompatibilityMode ) );
298
299 // creates the TF.CreationDate attribute:
302 aPlotter->AddLineToHeader( text );
303
304 // Creates the TF,.ProjectId. Format is (from Gerber file format doc):
305 // %TF.ProjectId,<project id>,<project GUID>,<revision id>*%
306 // <project id> is the name of the project, restricted to basic ASCII symbols only,
307 // Rem: <project id> accepts only ASCII 7 code (only basic ASCII codes are allowed in
308 // gerber files) and comma not accepted.
309 // All illegal chars will be replaced by underscore.
310 //
311 // <project GUID> is a string which is an unique id of a project.
312 // However Kicad does not handle such a project GUID, so it is built from the board name
313 wxFileName fn = aBoard->GetFileName();
314 wxString msg = fn.GetFullName();
315
316 // Build a <project GUID>, from the board name
317 wxString guid = GbrMakeProjectGUIDfromString( msg );
318
319 // build the <project id> string: this is the board short filename (without ext)
320 // and all non ASCII chars and reserved chars (, * % ) are replaced by '_'
321 msg = fn.GetName();
323
324 // build the <revision id> string. All non ASCII chars and reserved chars are replaced by '_'
325 wxString rev = ExpandTextVars( aBoard->GetTitleBlock().GetRevision(), aBoard->GetProject() );
327
328 if( rev.IsEmpty() )
329 rev = wxT( "rev?" );
330
331 text.Printf( wxT( "%%TF.ProjectId,%s,%s,%s*%%" ), msg.ToAscii(), guid, rev.ToAscii() );
332 aPlotter->AddLineToHeader( makeStringCompatX1( text, aUseX1CompatibilityMode ) );
333
334 // Add the TF.SameCoordinates to specify that all gerber files uses the same origin and
335 // orientation, and the registration between files is OK.
336 // The parameter of TF.SameCoordinates is a string that is common to all files using the
337 // same registration. The string value has no meaning; it is just a key.
338 // Because there is no mirroring/rotation in Kicad, only the plot offset origin can create
339 // incorrect registration, so we create a key from plot offset options.
340 //
341 // Currently the key is "Original" when using absolute Pcbnew coordinates, and the PY and PY
342 // position of the auxiliary axis when using it.
343 // If we ever add user-settable absolute Pcbnew coordinates, we'll need to change the way
344 // the key is built to ensure file only using the *same* axis have the same key.
345 wxString registration_id = wxT( "Original" );
346 VECTOR2I auxOrigin = aBoard->GetDesignSettings().GetAuxOrigin();
347
348 if( aBoard->GetPlotOptions().GetUseAuxOrigin() && auxOrigin.x && auxOrigin.y )
349 registration_id.Printf( wxT( "PX%xPY%x" ), auxOrigin.x, auxOrigin.y );
350
351 text.Printf( wxT( "%%TF.SameCoordinates,%s*%%" ), registration_id.GetData() );
352 aPlotter->AddLineToHeader( makeStringCompatX1( text, aUseX1CompatibilityMode ) );
353}
354
355
356void AddGerberX2Attribute( PLOTTER* aPlotter, const BOARD* aBoard, int aLayer,
357 bool aUseX1CompatibilityMode )
358{
359 AddGerberX2Header( aPlotter, aBoard, aUseX1CompatibilityMode );
360
361 wxString text;
362
363 // Add the TF.FileFunction
364 text = GetGerberFileFunctionAttribute( aBoard, aLayer );
365 aPlotter->AddLineToHeader( makeStringCompatX1( text, aUseX1CompatibilityMode ) );
366
367 // Add the TF.FilePolarity (for layers which support that)
369
370 if( !text.IsEmpty() )
371 aPlotter->AddLineToHeader( makeStringCompatX1( text, aUseX1CompatibilityMode ) );
372}
LAYER_T
The allowed types of layers, same as Specctra DSN spec.
Definition board.h:235
@ LT_POWER
Definition board.h:238
@ LT_MIXED
Definition board.h:239
@ LT_SIGNAL
Definition board.h:237
wxString GetBuildVersion()
Get the full KiCad version string.
const VECTOR2I & GetAuxOrigin() const
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Return the type of the copper layer given by aLayer.
Definition board.cpp:849
TITLE_BLOCK & GetTitleBlock()
Definition board.h:895
int GetCopperLayerCount() const
Definition board.cpp:985
const wxString & GetFileName() const
Definition board.h:409
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition board.h:892
PROJECT * GetProject() const
Definition board.h:650
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1149
bool GetUseAuxOrigin() const
Base plotter engine class.
Definition plotter.h:133
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:195
const wxString & GetRevision() const
Definition title_block.h:82
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition common.cpp:59
The common library.
wxString GbrMakeProjectGUIDfromString(const wxString &aText)
Build a project GUID using format RFC4122 Version 1 or 4 from the project name, because a KiCad proje...
wxString GbrMakeCreationDateAttributeString(GBR_NC_STRING_FORMAT aFormat)
Handle special data (items attributes) during plot.
@ GBR_NC_STRING_FORMAT_X1
@ GBR_NC_STRING_FORMAT_X2
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:675
size_t CopperLayerToOrdinal(PCB_LAYER_ID aLayer)
Converts KiCad copper layer enum to an ordinal between the front and back layers.
Definition layer_ids.h:911
@ B_Adhes
Definition layer_ids.h:99
@ Edge_Cuts
Definition layer_ids.h:108
@ Dwgs_User
Definition layer_ids.h:103
@ F_Paste
Definition layer_ids.h:100
@ Cmts_User
Definition layer_ids.h:104
@ F_Adhes
Definition layer_ids.h:98
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ Eco1_User
Definition layer_ids.h:105
@ F_Mask
Definition layer_ids.h:93
@ B_Paste
Definition layer_ids.h:101
@ F_Fab
Definition layer_ids.h:115
@ F_SilkS
Definition layer_ids.h:96
@ Eco2_User
Definition layer_ids.h:106
@ B_SilkS
Definition layer_ids.h:97
@ F_Cu
Definition layer_ids.h:60
@ B_Fab
Definition layer_ids.h:114
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition lset.cpp:750
const wxString GetGerberProtelExtension(int aLayer)
Definition pcbplot.cpp:39
static wxString & makeStringCompatX1(wxString &aText, bool aUseX1CompatibilityMode)
Definition pcbplot.cpp:267
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:290
const wxString GetGerberFileFunctionAttribute(const BOARD *aBoard, int aLayer)
Return the "file function" attribute for aLayer, as defined in the Gerber file format specification J...
Definition pcbplot.cpp:78
static void replaceReservedCharsField(wxString &aMsg)
Definition pcbplot.cpp:282
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:356
static const wxString GetGerberFilePolarityAttribute(int aLayer)
Definition pcbplot.cpp:206
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683