KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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
31#include <string_utils.h>
32#include <locale_io.h>
33#include <macros.h>
34#include <pcb_shape.h>
35#include <pcbplot.h>
37#include <gbr_metadata.h>
38#include <footprint.h>
39#include <pad.h>
40
41
43{
44 m_pcb = aPcb;
45 m_plotPad1Marker = true; // Place a marker to pin 1 (or A1) position
46 m_plotOtherPadsMarker = true; // Place a marker to other pins position
47 m_layer = PCB_LAYER_ID::UNDEFINED_LAYER; // No layer set
48}
49
50
51int PLACEFILE_GERBER_WRITER::CreatePlaceFile( const wxString& aFullFilename, PCB_LAYER_ID aLayer,
52 bool aIncludeBrdEdges, bool aExcludeDNP )
53{
54 m_layer = aLayer;
55
57
58 if( plotOpts.GetUseAuxOrigin() )
60
61 // Collect footprints on the right layer
62 std::vector<FOOTPRINT*> fp_list;
63
64 for( FOOTPRINT* footprint : m_pcb->Footprints() )
65 {
66 if( footprint->GetAttributes() & FP_EXCLUDE_FROM_POS_FILES )
67 continue;
68
69 if( aExcludeDNP && ( footprint->GetAttributes() & FP_DNP ) )
70 continue;
71
72 if( footprint->GetLayer() == aLayer )
73 fp_list.push_back( footprint );
74 }
75
76 LOCALE_IO dummy_io; // Use the standard notation for float numbers
77
78 GERBER_PLOTTER plotter;
79
80 // Gerber drill file imply X2 format:
81 plotter.UseX2format( true );
82 plotter.UseX2NetAttributes( true );
83
84 // Add the standard X2 header, without FileFunction
85 AddGerberX2Header( &plotter, m_pcb );
86 plotter.SetViewport( m_offset, pcbIUScale.IU_PER_MILS/10, /* scale */ 1.0, /* mirror */false );
87
88 // has meaning only for gerber plotter. Must be called only after SetViewport
89 plotter.SetGerberCoordinatesFormat( 6 );
90 plotter.SetCreator( wxT( "PCBNEW" ) );
91
92 // Add the standard X2 FileFunction for P&P files
93 // %TF.FileFunction,Component,Ln,[top][bottom]*%
94 wxString text;
95 text.Printf( wxT( "%%TF.FileFunction,Component,L%d,%s*%%" ),
96 aLayer == B_Cu ? m_pcb->GetCopperLayerCount() : 1,
97 aLayer == B_Cu ? wxT( "Bot" ) : wxT( "Top" ) );
98 plotter.AddLineToHeader( text );
99
100 // Add file polarity (positive)
101 text = wxT( "%TF.FilePolarity,Positive*%" );
102 plotter.AddLineToHeader( text );
103
104 if( !plotter.OpenFile( aFullFilename ) )
105 return -1;
106
107 // We need a BRDITEMS_PLOTTER to plot pads
108 BRDITEMS_PLOTTER brd_plotter( &plotter, m_pcb, plotOpts );
109
110 plotter.StartPlot( wxT( "1" ) );
111
112 // Some tools in P&P files have the type and size defined.
113 // they are position flash (round), pad1 flash (diamond), other pads flash (round)
114 // and component outline thickness (polyline)
115
116 // defined size for footprint position shape (circle)
117 int flash_position_shape_diam = pcbIUScale.mmToIU( 0.3 );
118
119 // defined size for pad 1 position (diamond)
120 int pad1_mark_size = pcbIUScale.mmToIU( 0.36 );
121
122 // Normalized size for other pads (circle)
123 // It was initially the size 0, but was changed later to 0.1 mm in rev 2023-08
124 // See ComponentPin aperture attribute (see 5.6.10 .AperFunction value)
125 int other_pads_mark_size = pcbIUScale.mmToIU( 0.1 );
126
127 // defined size for component outlines
128 int line_thickness = pcbIUScale.mmToIU( 0.1 );
129
130 brd_plotter.SetLayerSet( LSET( { aLayer } ) );
131 int cmp_count = 0;
132 const bool allowUtf8 = true;
133 const bool quoteOption = false;
134
135 // Plot components data: position, outlines, pad1 and other pads.
136 for( FOOTPRINT* footprint : fp_list )
137 {
138 // Manage the aperture attribute component position:
139 GBR_METADATA metadata;
141
142 // Add object attribute: component reference to flash (mainly useful for users)
143 // using not quoted UTF8 string
144 wxString ref = ConvertNotAllowedCharsInGerber( footprint->Reference().GetShownText( false ),
145 allowUtf8, quoteOption );
146
147 metadata.SetCmpReference( ref );
149
150 // Add P&P specific attributes
151 GBR_CMP_PNP_METADATA pnpAttrib;
152
153 // Add rotation info (rotation is CCW, in degrees):
154 pnpAttrib.m_Orientation = mapRotationAngle( footprint->GetOrientationDegrees(),
155 aLayer == B_Cu ? true : false );
156
158
159 if( footprint->GetAttributes() & FP_THROUGH_HOLE )
161 else if( footprint->GetAttributes() & FP_SMD )
163
164 // Add component value info:
165 pnpAttrib.m_Value = ConvertNotAllowedCharsInGerber( footprint->Value().GetShownText( false ),
166 allowUtf8, quoteOption );
167
168 // Add component footprint info:
169 wxString fp_info = From_UTF8( footprint->GetFPID().GetLibItemName().c_str() );
170 pnpAttrib.m_Footprint = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, quoteOption );
171
172 // Add footprint lib name:
173 fp_info = From_UTF8( footprint->GetFPID().GetLibNickname().c_str() );
174 pnpAttrib.m_LibraryName = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, quoteOption );
175
177
178 VECTOR2I flash_pos = footprint->GetPosition();
179
180 plotter.FlashPadCircle( flash_pos, flash_position_shape_diam, &metadata );
182
183 // Now some extra metadata is output, avoid blindly clearing the full metadata list
185
186 // We plot the footprint courtyard when possible.
187 // If not, the pads bounding box will be used.
188 bool useFpPadsBbox = true;
189 bool onBack = aLayer == B_Cu;
190
191 footprint->BuildCourtyardCaches();
192
193 int checkFlag = onBack ? MALFORMED_B_COURTYARD : MALFORMED_F_COURTYARD;
194
195 if( ( footprint->GetFlags() & checkFlag ) == 0 )
196 {
198
199 const SHAPE_POLY_SET& courtyard = footprint->GetCourtyard( aLayer );
200
201 for( int ii = 0; ii < courtyard.OutlineCount(); ii++ )
202 {
203 SHAPE_LINE_CHAIN poly = courtyard.Outline( ii );
204
205 if( !poly.PointCount() )
206 continue;
207
208 useFpPadsBbox = false;
209 plotter.PLOTTER::PlotPoly( poly, FILL_T::NO_FILL, line_thickness, &metadata );
210 }
211 }
212
213 if( useFpPadsBbox )
214 {
216
217 // bbox of fp pads, pos 0, rot 0, non flipped
218 BOX2I bbox = footprint->GetFpPadsLocalBbox();
219
220 // negate bbox Y values if the fp is flipped (always flipped around X axis
221 // in Gerber P&P files).
222 int y_sign = aLayer == B_Cu ? -1 : 1;
223
224 SHAPE_LINE_CHAIN poly;
225 poly.Append( bbox.GetLeft(), y_sign*bbox.GetTop() );
226 poly.Append( bbox.GetLeft(), y_sign*bbox.GetBottom() );
227 poly.Append( bbox.GetRight(), y_sign*bbox.GetBottom() );
228 poly.Append( bbox.GetRight(), y_sign*bbox.GetTop() );
229 poly.SetClosed( true );
230
231 poly.Rotate( footprint->GetOrientation() );
232 poly.Move( footprint->GetPosition() );
233 plotter.PLOTTER::PlotPoly( poly, FILL_T::NO_FILL, line_thickness, &metadata );
234 }
235
236 std::vector<PAD*>pad_key_list;
237
238 if( m_plotPad1Marker )
239 {
240 findPads1( pad_key_list, footprint );
241
242 for( PAD* pad1 : pad_key_list )
243 {
245 metadata.SetPadName( pad1->GetNumber(), allowUtf8, quoteOption );
246 metadata.SetPadPinFunction( pad1->GetPinFunction(), allowUtf8, quoteOption );
248
249 // Flashes a diamond at pad position:
250 plotter.FlashRegularPolygon( pad1->GetPosition(), pad1_mark_size, 4, ANGLE_0,
251 &metadata );
252 }
253 }
254
256 {
259
260 for( PAD* pad: footprint->Pads() )
261 {
262 bool skip_pad = false;
263
264 for( PAD* pad1 : pad_key_list )
265 {
266 if( pad == pad1 ) // Already plotted
267 {
268 skip_pad = true;
269 break;
270 }
271 }
272
273 if( skip_pad )
274 continue;
275
276 // Skip also pads not on the current layer, like pads only
277 // on a tech layer
278 if( !pad->IsOnLayer( aLayer ) )
279 continue;
280
281 metadata.SetPadName( pad->GetNumber(), allowUtf8, quoteOption );
282 metadata.SetPadPinFunction( pad->GetPinFunction(), allowUtf8, quoteOption );
283
284 // Flashes a round, 0 sized round shape at pad position
285 plotter.FlashPadCircle( pad->GetPosition(), other_pads_mark_size, &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 for( const BOARD_ITEM* item : m_pcb->Drawings() )
301 brd_plotter.PlotBoardGraphicItem( item );
302
303 // Draw footprint other graphic items:
304 for( FOOTPRINT* footprint : fp_list )
305 {
306 for( BOARD_ITEM* item : footprint->GraphicalItems() )
307 {
308 if( item->Type() == PCB_SHAPE_T && item->GetLayer() == Edge_Cuts )
309 brd_plotter.PlotShape( static_cast<PCB_SHAPE*>( item ) );
310 }
311 }
312 }
313
314 plotter.EndPlot();
315
316 return cmp_count;
317}
318
319
320double PLACEFILE_GERBER_WRITER::mapRotationAngle( double aAngle, bool aIsFlipped )
321{
322 // Convert a KiCad footprint orientation to gerber rotation, depending on the layer
323 // Gerber rotation is:
324 // rot angle > 0 for rot CW, seen from Top side
325 // same a Pcbnew for Top side
326 // (angle + 180) for Bottom layer i.e flipped around Y axis: X axis coordinates mirrored.
327 // because Pcbnew flip around the X axis : Y coord mirrored, that is similar to mirror
328 // around Y axis + 180 deg rotation
329 if( aIsFlipped )
330 {
331 double gbr_angle = 180.0 + aAngle;
332
333 // Normalize between -180 ... + 180 deg
334 // Not mandatory, but the angle is more easy to read
335 if( gbr_angle <= -180 )
336 gbr_angle += 360.0;
337 else if( gbr_angle > 180 )
338 gbr_angle -= 360.0;
339
340 return gbr_angle;
341 }
342
343 return aAngle;
344}
345
346
347void PLACEFILE_GERBER_WRITER::findPads1( std::vector<PAD*>& aPadList, FOOTPRINT* aFootprint ) const
348{
349 // Fint the pad "1" or pad "A1"
350 // this is possible only if only one pad is found
351 // useful to place a marker in this position
352
353 for( PAD* pad : aFootprint->Pads() )
354 {
355 if( !pad->IsOnLayer( m_layer ) )
356 continue;
357
358 if( pad->GetNumber() == wxT( "1" ) || pad->GetNumber() == wxT( "A1" ) )
359 aPadList.push_back( pad );
360 }
361}
362
363
364const wxString PLACEFILE_GERBER_WRITER::GetPlaceFileName( const wxString& aFullBaseFilename,
365 PCB_LAYER_ID aLayer ) const
366{
367 // Gerber files extension is always .gbr.
368 // Therefore, to mark pnp files, add "-pnp" to the filename, and a layer id.
369 wxFileName fn = aFullBaseFilename;
370
371 wxString post_id = wxT( "-pnp_" );
372 post_id += aLayer == B_Cu ? wxT( "bottom" ) : wxT( "top" );
373 fn.SetName( fn.GetName() + post_id );
374 fn.SetExt( FILEEXT::GerberFileExtension );
375
376 return fn.GetFullPath();
377}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:112
const VECTOR2I & GetAuxOrigin() const
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:317
int GetCopperLayerCount() const
Definition: board.cpp:859
const FOOTPRINTS & Footprints() const
Definition: board.h:358
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:745
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:1024
const DRAWINGS & Drawings() const
Definition: board.h:360
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr coord_type GetRight() const
Definition: box2.h:217
constexpr coord_type GetTop() const
Definition: box2.h:229
constexpr coord_type GetBottom() const
Definition: box2.h:222
void SetLayerSet(const LSET &aLayerMask)
Definition: pcbplot.h:86
void PlotBoardGraphicItem(const BOARD_ITEM *item)
Plot items like text and graphics but not tracks and footprints.
void PlotShape(const PCB_SHAPE *aShape)
std::deque< PAD * > & Pads()
Definition: footprint.h:209
@ GBR_APERTURE_ATTRIB_PAD1_POS
Aperture used for flashed pin 1 (or A1 or AA1) position in placement files.
Definition: gbr_metadata.h:154
@ GBR_APERTURE_ATTRIB_CMP_COURTYARD
Aperture used to draw component outline courtyard in placement files.
Definition: gbr_metadata.h:169
@ GBR_APERTURE_ATTRIB_CMP_POSITION
Aperture used for flashed cmp position in placement files.
Definition: gbr_metadata.h:151
@ GBR_APERTURE_ATTRIB_PADOTHER_POS
Aperture used for flashed pads position in placement files.
Definition: gbr_metadata.h:157
@ GBR_APERTURE_ATTRIB_CMP_FOOTPRINT
Aperture used to draw component footprint bounding box in placement files.
Definition: gbr_metadata.h:166
Information which can be added in a gerber P&P file as attribute of a component.
wxString FormatCmpPnPMetadata()
One line by non empty data the orientation (.CRot) and mount type (.CMnt) are always generated.
Metadata which can be added in a gerber file as attribute in X2 format.
Definition: gbr_metadata.h:215
void SetCmpReference(const wxString &aComponentRef)
Definition: gbr_metadata.h:259
void SetPadPinFunction(const wxString &aPadPinFunction, bool aUseUTF8, bool aEscapeString)
Definition: gbr_metadata.h:254
void SetApertureAttrib(GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB aApertAttribute)
Definition: gbr_metadata.h:219
GBR_NETLIST_METADATA m_NetlistMetadata
An item to handle object attribute.
Definition: gbr_metadata.h:280
void SetNetAttribType(int aNetAttribType)
Definition: gbr_metadata.h:237
void SetPadName(const wxString &aPadname, bool aUseUTF8=false, bool aEscapeString=false)
Definition: gbr_metadata.h:249
@ GBR_NETINFO_CMP
print info associated to a component (TO.C attribute)
@ GBR_NETINFO_PAD
print info associated to a flashed pad (TO.P attribute)
void ClearExtraData()
Clear the extra data string printed at end of net attributes.
bool m_TryKeepPreviousAttributes
If true, do not clear all attributes when a attribute has changed.
void SetExtraData(const wxString &aExtraData)
Set the extra data string printed at end of net attributes.
virtual void SetGerberCoordinatesFormat(int aResolution, bool aUseInches=false) override
Selection of Gerber units and resolution (number of digits in mantissa).
void ClearAllAttributes()
Remove (clear) all attributes from object attributes dictionary (TO.
virtual void FlashPadCircle(const VECTOR2I &pos, int diametre, void *aData) override
Filled circular flashes are stored as apertures.
virtual void FlashRegularPolygon(const VECTOR2I &aShapePos, int aDiameter, int aCornerCount, const EDA_ANGLE &aOrient, void *aData) override
Flash a regular polygon.
virtual void SetViewport(const VECTOR2I &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the plot offset and scaling for the current plot.
virtual bool EndPlot() override
void UseX2format(bool aEnable)
void UseX2NetAttributes(bool aEnable)
virtual bool StartPlot(const wxString &pageNumber) override
Write GERBER header to file initialize global variable g_Plot_PlotOutputFile.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:41
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
Definition: pad.h:54
Parameters and options when plotting/printing a board.
bool GetUseAuxOrigin() const
const wxString GetPlaceFileName(const wxString &aFullBaseFilename, PCB_LAYER_ID aLayer) const
int CreatePlaceFile(const wxString &aFullFilename, PCB_LAYER_ID aLayer, bool aIncludeBrdEdges, bool aExcludeDNP)
Create an pnp gerber file.
double mapRotationAngle(double aAngle, bool aIsFlipped)
Convert a KiCad footprint orientation to gerber rotation both are in degrees.
void findPads1(std::vector< PAD * > &aPadList, FOOTPRINT *aFootprint) const
Find the pad(s) 1 (or pad "A1") of a footprint.
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition: plotter.cpp:75
virtual void SetCreator(const wxString &aCreator)
Definition: plotter.h:173
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
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int OutlineCount() const
Return the number of outlines in the set.
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:411
#define MALFORMED_F_COURTYARD
#define MALFORMED_B_COURTYARD
@ FP_SMD
Definition: footprint.h:81
@ FP_DNP
Definition: footprint.h:86
@ FP_EXCLUDE_FROM_POS_FILES
Definition: footprint.h:82
@ FP_THROUGH_HOLE
Definition: footprint.h:80
wxString ConvertNotAllowedCharsInGerber(const wxString &aString, bool aAllowUtf8Chars, bool aQuoteString)
Normalize aString and convert it to a Gerber compatible wxString.
Handle special data (items attributes) during plot.
Classes used in place file generation.
static const std::string GerberFileExtension
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ Edge_Cuts
Definition: layer_ids.h:112
@ B_Cu
Definition: layer_ids.h:65
This file contains miscellaneous commonly used macros and functions.
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:294
wxString From_UTF8(const char *cstring)
const double IU_PER_MILS
Definition: base_units.h:77
constexpr int mmToIU(double mm) const
Definition: base_units.h:92
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
Definition of file extensions used in Kicad.