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 (C) 1992-2023 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
35#include <board.h>
37#include <pcb_shape.h>
38
39#include <pcbplot.h>
41#include <gbr_metadata.h>
42#include <footprint.h>
43#include <pad.h>
44
45
47{
48 m_pcb = aPcb;
49 m_plotPad1Marker = true; // Place a marker to pin 1 (or A1) position
50 m_plotOtherPadsMarker = true; // Place a marker to other pins position
51 m_layer = PCB_LAYER_ID::UNDEFINED_LAYER; // No layer set
52}
53
54
55int PLACEFILE_GERBER_WRITER::CreatePlaceFile( wxString& aFullFilename, PCB_LAYER_ID aLayer,
56 bool aIncludeBrdEdges )
57{
58 m_layer = aLayer;
59
61
62 if( plotOpts.GetUseAuxOrigin() )
64
65 // Collect footprints on the right layer
66 std::vector<FOOTPRINT*> fp_list;
67
68 for( FOOTPRINT* footprint : m_pcb->Footprints() )
69 {
70 if( footprint->GetAttributes() & FP_EXCLUDE_FROM_POS_FILES )
71 continue;
72
73 if( footprint->GetLayer() == aLayer )
74 fp_list.push_back( footprint );
75 }
76
77 LOCALE_IO dummy_io; // Use the standard notation for float numbers
78
79 GERBER_PLOTTER plotter;
80
81 // Gerber drill file imply X2 format:
82 plotter.UseX2format( true );
83 plotter.UseX2NetAttributes( true );
84
85 // Add the standard X2 header, without FileFunction
86 AddGerberX2Header( &plotter, m_pcb );
87 plotter.SetViewport( m_offset, pcbIUScale.IU_PER_MILS/10, /* scale */ 1.0, /* mirror */false );
88
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( wxT( "%%TF.FileFunction,Component,L%d,%s*%%" ),
97 aLayer == B_Cu ? m_pcb->GetCopperLayerCount() : 1,
98 aLayer == B_Cu ? wxT( "Bot" ) : wxT( "Top" ) );
99 plotter.AddLineToHeader( text );
100
101 // Add file polarity (positive)
102 text = wxT( "%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( wxT( "1" ) );
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 = pcbIUScale.mmToIU( 0.3 ); // defined size for position shape (circle)
117 int pad1_mark_size = pcbIUScale.mmToIU( 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 = pcbIUScale.mmToIU( 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( false ),
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 aLayer == B_Cu ? true : false );
146
148
149 if( footprint->GetAttributes() & FP_THROUGH_HOLE )
151 else if( footprint->GetAttributes() & FP_SMD )
153
154 // Add component value info:
155 pnpAttrib.m_Value = ConvertNotAllowedCharsInGerber( footprint->Value().GetShownText( false ),
156 allowUtf8, true );
157
158 // Add component footprint info:
159 wxString fp_info = FROM_UTF8( footprint->GetFPID().GetLibItemName().c_str() );
160 pnpAttrib.m_Footprint = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, true );
161
162 // Add footprint lib name:
163 fp_info = FROM_UTF8( footprint->GetFPID().GetLibNickname().c_str() );
164 pnpAttrib.m_LibraryName = ConvertNotAllowedCharsInGerber( fp_info, allowUtf8, true );
165
166 gbr_metadata.m_NetlistMetadata.SetExtraData( pnpAttrib.FormatCmpPnPMetadata() );
167
168 VECTOR2I flash_pos = footprint->GetPosition();
169
170 plotter.FlashPadCircle( flash_pos, flash_position_shape_diam, FILLED, &gbr_metadata );
171 gbr_metadata.m_NetlistMetadata.ClearExtraData();
172
173 // Now some extra metadata is output, avoid blindly clearing the full metadata list
175
176 // We plot the footprint courtyard when possible.
177 // If not, the pads bounding box will be used.
178 bool useFpPadsBbox = true;
179 bool onBack = aLayer == B_Cu;
180
181 footprint->BuildCourtyardCaches();
182
183 int checkFlag = onBack ? MALFORMED_B_COURTYARD : MALFORMED_F_COURTYARD;
184
185 if( ( footprint->GetFlags() & checkFlag ) == 0 )
186 {
187 gbr_metadata.SetApertureAttrib(
189
190 const SHAPE_POLY_SET& courtyard = footprint->GetCourtyard( aLayer );
191
192 for( int ii = 0; ii < courtyard.OutlineCount(); ii++ )
193 {
194 SHAPE_LINE_CHAIN poly = courtyard.Outline( ii );
195
196 if( !poly.PointCount() )
197 continue;
198
199 useFpPadsBbox = false;
200 plotter.PLOTTER::PlotPoly( poly, FILL_T::NO_FILL, line_thickness, &gbr_metadata );
201 }
202 }
203
204 if( useFpPadsBbox )
205 {
206 gbr_metadata.SetApertureAttrib(
208
209 // bbox of fp pads, pos 0, rot 0, non flipped
210 BOX2I bbox = footprint->GetFpPadsLocalBbox();
211
212 // negate bbox Y values if the fp is flipped (always flipped around X axis
213 // in Gerber P&P files).
214 int y_sign = aLayer == B_Cu ? -1 : 1;
215
216 SHAPE_LINE_CHAIN poly;
217 poly.Append( bbox.GetLeft(), y_sign*bbox.GetTop() );
218 poly.Append( bbox.GetLeft(), y_sign*bbox.GetBottom() );
219 poly.Append( bbox.GetRight(), y_sign*bbox.GetBottom() );
220 poly.Append( bbox.GetRight(), y_sign*bbox.GetTop() );
221 poly.SetClosed( true );
222
223 poly.Rotate( footprint->GetOrientation() );
224 poly.Move( footprint->GetPosition() );
225 plotter.PLOTTER::PlotPoly( poly, FILL_T::NO_FILL, line_thickness, &gbr_metadata );
226 }
227
228 std::vector<PAD*>pad_key_list;
229
230 if( m_plotPad1Marker )
231 {
232 findPads1( pad_key_list, footprint );
233
234 for( PAD* pad1 : pad_key_list )
235 {
236 gbr_metadata.SetApertureAttrib(
238
239 gbr_metadata.SetPadName( pad1->GetNumber(), allowUtf8, true );
240
241 gbr_metadata.SetPadPinFunction( pad1->GetPinFunction(), allowUtf8, true );
242
244
245 // Flashes a diamond at pad position:
246 plotter.FlashRegularPolygon( pad1->GetPosition(), pad1_mark_size, 4, ANGLE_0,
247 FILLED, &gbr_metadata );
248 }
249 }
250
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->GetNumber(), 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(), other_pads_mark_size, FILLED,
284 &gbr_metadata );
285 }
286 }
287
288 plotter.ClearAllAttributes(); // Unconditionally close all .TO attributes
289
290 cmp_count++;
291 }
292
293 // Plot board outlines, if requested
294 if( aIncludeBrdEdges )
295 {
296 brd_plotter.SetLayerSet( LSET( Edge_Cuts ) );
297
298 // Plot edge layer and graphic items
299 brd_plotter.PlotBoardGraphicItems();
300
301 // Draw footprint other graphic items:
302 for( FOOTPRINT* footprint : fp_list )
303 {
304 for( BOARD_ITEM* item : footprint->GraphicalItems() )
305 {
306 if( item->Type() == PCB_SHAPE_T && item->GetLayer() == Edge_Cuts )
307 brd_plotter.PlotPcbShape( static_cast<PCB_SHAPE*>( item ) );
308 }
309 }
310 }
311
312 plotter.EndPlot();
313
314 return cmp_count;
315}
316
317
318double PLACEFILE_GERBER_WRITER::mapRotationAngle( double aAngle, bool aIsFlipped )
319{
320 // Convert a KiCad footprint orientation to gerber rotation, depending on the layer
321 // Gerber rotation is:
322 // rot angle > 0 for rot CW, seen from Top side
323 // same a Pcbnew for Top side
324 // (angle + 180) for Bottom layer i.e flipped around Y axis: X axis coordinates mirrored.
325 // because Pcbnew flip around the X axis : Y coord mirrored, that is similar to mirror
326 // around Y axis + 180 deg rotation
327 if( aIsFlipped )
328 {
329 double gbr_angle = 180.0 + aAngle;
330
331 // Normalize between -180 ... + 180 deg
332 // Not mandatory, but the angle is more easy to read
333 if( gbr_angle <= -180 )
334 gbr_angle += 360.0;
335 else if( gbr_angle > 180 )
336 gbr_angle -= 360.0;
337
338 return gbr_angle;
339 }
340
341 return aAngle;
342}
343
344
345void PLACEFILE_GERBER_WRITER::findPads1( std::vector<PAD*>& aPadList, FOOTPRINT* aFootprint ) const
346{
347 // Fint the pad "1" or pad "A1"
348 // this is possible only if only one pad is found
349 // useful to place a marker in this position
350
351 for( PAD* pad : aFootprint->Pads() )
352 {
353 if( !pad->IsOnLayer( m_layer ) )
354 continue;
355
356 if( pad->GetNumber() == wxT( "1" ) || pad->GetNumber() == wxT( "A1" ) )
357 aPadList.push_back( pad );
358 }
359}
360
361
362const wxString PLACEFILE_GERBER_WRITER::GetPlaceFileName( const wxString& aFullBaseFilename,
363 PCB_LAYER_ID aLayer ) const
364{
365 // Gerber files extension is always .gbr.
366 // Therefore, to mark pnp files, add "-pnp" to the filename, and a layer id.
367 wxFileName fn = aFullBaseFilename;
368
369 wxString post_id = wxT( "-pnp_" );
370 post_id += aLayer == B_Cu ? wxT( "bottom" ) : wxT( "top" );
371 fn.SetName( fn.GetName() + post_id );
372 fn.SetExt( GerberFileExtension );
373
374 return fn.GetFullPath();
375}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
const VECTOR2I & GetAuxOrigin()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:71
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:270
FOOTPRINTS & Footprints()
Definition: board.h:312
int GetCopperLayerCount() const
Definition: board.cpp:587
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:641
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:728
coord_type GetTop() const
Definition: box2.h:194
coord_type GetRight() const
Definition: box2.h:189
coord_type GetLeft() const
Definition: box2.h:193
coord_type GetBottom() const
Definition: box2.h:190
void PlotPcbShape(const PCB_SHAPE *aShape)
void SetLayerSet(LSET aLayerMask)
Definition: pcbplot.h:80
void PlotBoardGraphicItems()
Plot items like text and graphics but not tracks and footprints.
PADS & Pads()
Definition: footprint.h:172
@ GBR_APERTURE_ATTRIB_PAD1_POSITION
aperture used for flashed pads position in placement files.
Definition: gbr_metadata.h:149
@ GBR_APERTURE_ATTRIB_CMP_POSITION
aperture used for flashed pin 1 (or A1 or AA1) position in placement files.
Definition: gbr_metadata.h:146
@ GBR_APERTURE_ATTRIB_PADOTHER_POSITION
aperture used to draw component physical body outline without pins in placement files.
Definition: gbr_metadata.h:152
@ GBR_APERTURE_ATTRIB_CMP_FOOTPRINT
aperture used to draw component outline courtyard in placement files.
Definition: gbr_metadata.h:161
Information which can be added in a gerber P&P file as attribute of a component.
wxString FormatCmpPnPMetadata()
Metadata which can be added in a gerber file as attribute in X2 format.
Definition: gbr_metadata.h:205
void SetCmpReference(const wxString &aComponentRef)
Definition: gbr_metadata.h:241
void SetPadPinFunction(const wxString &aPadPinFunction, bool aUseUTF8, bool aEscapeString)
Definition: gbr_metadata.h:236
void SetApertureAttrib(GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB aApertAttribute)
Definition: gbr_metadata.h:209
GBR_NETLIST_METADATA m_NetlistMetadata
An item to handle object attribute.
Definition: gbr_metadata.h:262
void SetNetAttribType(int aNetAttribType)
Definition: gbr_metadata.h:219
void SetPadName(const wxString &aPadname, bool aUseUTF8=false, bool aEscapeString=false)
Definition: gbr_metadata.h:231
@ 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, OUTLINE_MODE trace_mode, void *aData) override
Filled circular flashes are stored as apertures.
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 void FlashRegularPolygon(const VECTOR2I &aShapePos, int aDiameter, int aCornerCount, const EDA_ANGLE &aOrient, OUTLINE_MODE aTraceMode, void *aData) override
Flash a regular polygon.
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: layer_ids.h:536
Definition: pad.h:59
Parameters and options when plotting/printing a board.
bool GetUseAuxOrigin() const
const wxString GetPlaceFileName(const wxString &aFullBaseFilename, PCB_LAYER_ID aLayer) const
int CreatePlaceFile(wxString &aFullFilename, PCB_LAYER_ID aLayer, bool aIncludeBrdEdges)
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:74
virtual void SetCreator(const wxString &aCreator)
Definition: plotter.h:159
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:168
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:429
#define MALFORMED_F_COURTYARD
#define MALFORMED_B_COURTYARD
@ FP_SMD
Definition: footprint.h:70
@ FP_EXCLUDE_FROM_POS_FILES
Definition: footprint.h:71
@ FP_THROUGH_HOLE
Definition: footprint.h:69
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 bool FILLED
Definition: gr_basic.cpp:30
const std::string GerberFileExtension
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:59
@ Edge_Cuts
Definition: layer_ids.h:113
@ B_Cu
Definition: layer_ids.h:95
This file contains miscellaneous commonly used macros and functions.
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
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:276
Plotting engine (Gerber)
const double IU_PER_MILS
Definition: base_units.h:78
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
Definition of file extensions used in Kicad.