KiCad PCB EDA Suite
Loading...
Searching...
No Matches
gendrill_gerber_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) 2017 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
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
29
31#include <string_utils.h>
32#include <locale_io.h>
33#include <board.h>
34#include <footprint.h>
35#include <pcb_track.h>
36#include <pad.h>
37#include <pcbplot.h>
39#include <reporter.h>
40#include <gbr_metadata.h>
41
42// set to 1 to use flashed oblong holes, 0 to draw them by a line (route holes).
43// WARNING: currently ( gerber-layer-format-specification-revision-2023-08 ),
44// oblong holes **must be routed* in a drill file and not flashed,
45// so set FLASH_OVAL_HOLE to 0
46#define FLASH_OVAL_HOLE 0
47
48
58
59
60bool GERBER_WRITER::CreateDrillandMapFilesSet( const wxString& aPlotDirectory, bool aGenDrill,
61 bool aGenMap, bool aGenTenting, REPORTER* aReporter )
62{
63 bool success = true;
64 // Note: In Gerber drill files, NPTH and PTH are always separate files
65 m_merge_PTH_NPTH = false;
66
67 wxFileName fn;
68 wxString msg;
69
70 std::vector<DRILL_SPAN> hole_sets = getUniqueLayerPairs();
71
72 hole_sets.emplace_back( F_Cu, B_Cu, false, true );
73
74 for( std::vector<DRILL_SPAN>::const_iterator it = hole_sets.begin();
75 it != hole_sets.end(); ++it )
76 {
77 const DRILL_SPAN& span = *it;
78 bool doing_npth = span.m_IsNonPlatedFile;
79
80 buildHolesList( span, doing_npth );
81
82 if( getHolesCount() == 0 )
83 continue;
84
85 fn = getDrillFileName( span, doing_npth, m_merge_PTH_NPTH );
86 fn.SetPath( aPlotDirectory );
87
88 if( aGenDrill )
89 {
90 wxString fullFilename = fn.GetFullPath();
91 bool isNonPlated = doing_npth || span.m_IsBackdrill;
92 bool wroteDrillFile = false;
93
94 int result = createDrillFile( fullFilename, isNonPlated, span );
95
96 if( result < 0 )
97 {
98 if( aReporter )
99 {
100 msg.Printf( _( "Failed to create file '%s'." ), fullFilename );
101 aReporter->Report( msg, RPT_SEVERITY_ERROR );
102 }
103
104 success = false;
105 break;
106 }
107
108 wroteDrillFile = true;
109
110 if( aReporter )
111 {
112 msg.Printf( _( "Created file '%s'." ), fullFilename );
113 aReporter->Report( msg, RPT_SEVERITY_ACTION );
114 }
115
116 if( wroteDrillFile && span.m_IsBackdrill )
117 {
118 if( !writeBackdrillLayerPairFile( aPlotDirectory, aReporter, span ) )
119 {
120 success = false;
121 break;
122 }
123 }
124 }
125
126 if( doing_npth )
127 continue;
128
129 for( IPC4761_FEATURES feature :
134 {
135 if( !aGenTenting )
136 {
137 if( feature == IPC4761_FEATURES::TENTED_BACK
138 || feature == IPC4761_FEATURES::TENTED_FRONT )
139 {
140 continue;
141 }
142 }
143
144 if( !hasViaType( feature ) )
145 continue;
146
147 fn = getProtectionFileName( span, feature );
148 fn.SetPath( aPlotDirectory );
149
150 wxString fullFilename = fn.GetFullPath();
151
152 if( createProtectionFile( fullFilename, feature, span.Pair() ) < 0 )
153 {
154 if( aReporter )
155 {
156 msg.Printf( _( "Failed to create file '%s'." ), fullFilename );
157 aReporter->Report( msg, RPT_SEVERITY_ERROR );
158 success = false;
159 }
160 }
161 else
162 {
163 if( aReporter )
164 {
165 msg.Printf( _( "Created file '%s'." ), fullFilename );
166 aReporter->Report( msg, RPT_SEVERITY_ACTION );
167 }
168 }
169 }
170 }
171
172 if( aGenMap )
173 success &= CreateMapFilesSet( aPlotDirectory, aReporter );
174
175 if( aReporter )
176 aReporter->ReportTail( _( "Done." ), RPT_SEVERITY_INFO );
177
178 return success;
179}
180
181
182#if !FLASH_OVAL_HOLE
183// A helper class to transform an oblong hole to a segment
184static void convertOblong2Segment( const VECTOR2I& aSize, const EDA_ANGLE& aOrient, VECTOR2I& aStart, VECTOR2I& aEnd );
185#endif
186
187int GERBER_WRITER::createProtectionFile( const wxString& aFullFilename, IPC4761_FEATURES aFeature,
188 DRILL_LAYER_PAIR aLayerPair )
189{
190 GERBER_PLOTTER plotter;
191 // Gerber drill file imply X2 format:
192 plotter.UseX2format( true );
193 plotter.UseX2NetAttributes( true );
194 plotter.DisableApertMacros( false );
195
196 // Add the standard X2 header, without FileFunction
197 AddGerberX2Header( &plotter, m_pcb );
198 plotter.SetViewport( m_offset, pcbIUScale.IU_PER_MILS / 10, /* scale */ 1.0,
199 /* mirror */ false );
200
201 // has meaning only for gerber plotter. Must be called only after SetViewport
202 plotter.SetGerberCoordinatesFormat( 6 );
203 plotter.SetCreator( wxT( "PCBNEW" ) );
204
205 // Add the standard X2 FileFunction for drill files
206 // %TF.FileFunction,Plated[NonPlated],layer1num,layer2num,PTH[NPTH][Blind][Buried],Drill[Rout][Mixed]*%
207 wxString text = "%TF,FileFunction,Other,";
208
209 std::string attrib;
210 switch( aFeature )
211 {
213 text << wxT( "Capping" );
214 attrib = "Capping";
215 break;
217 text << wxT( "Filling" );
218 attrib = "Filling";
219 break;
221 text << wxT( "Covering-Back" );
222 attrib = "Covering";
223 break;
225 text << wxT( "Covering-Front" );
226 attrib = "Covering";
227 break;
229 text << wxT( "Plugging-Back" );
230 attrib = "Plugging";
231 break;
233 text << wxT( "Plugging-Front" );
234 attrib = "Plugging";
235 break;
237 text << wxT( "Tenting-Back" );
238 attrib = "Tenting";
239 break;
241 text << wxT( "Tenting-Front" );
242 attrib = "Tenting";
243 break;
244 default: return -1;
245 }
246 text << wxT( "*%" );
247 plotter.AddLineToHeader( text );
248
249 // Add file polarity (positive)
250 text = wxT( "%TF.FilePolarity,Positive*%" );
251 plotter.AddLineToHeader( text );
252
253
254 if( !plotter.OpenFile( aFullFilename ) )
255 return -1;
256
257 plotter.StartPlot( wxT( "1" ) );
258
259 int holes_count = 0;
260
261 for( auto& hole_descr : m_holeListBuffer )
262 {
263 if( !dyn_cast<const PCB_VIA*>( hole_descr.m_ItemParent ) )
264 {
265 continue;
266 }
267
268 const PCB_VIA* via = dyn_cast<const PCB_VIA*>( hole_descr.m_ItemParent );
269
270 bool cont = false;
271 int diameter = hole_descr.m_Hole_Diameter;
272 // clang-format off: suggestion is inconsitent
273 switch( aFeature )
274 {
276 cont = ! hole_descr.m_Hole_Filled;
277 break;
279 cont = ! hole_descr.m_Hole_Capped;
280 break;
282 cont = !hole_descr.m_Hole_Bot_Covered;
283 diameter = via->GetWidth( via->BottomLayer() );
284 break;
286 cont = ! hole_descr.m_Hole_Top_Covered;
287 diameter = via->GetWidth( via->TopLayer() );
288 break;
290 cont = !hole_descr.m_Hole_Bot_Plugged;
291 break;
293 cont = ! hole_descr.m_Hole_Top_Plugged;
294 break;
296 cont = ! hole_descr.m_Hole_Bot_Tented;
297 diameter = via->GetWidth( via->BottomLayer() );
298 break;
300 cont = ! hole_descr.m_Hole_Top_Tented;
301 diameter = via->GetWidth( via->TopLayer() );
302 break;
303 }
304 // clang-format on: suggestion is inconsitent
305
306 if( cont )
307 continue;
308
309 GBR_METADATA gbr_metadata;
310
311 gbr_metadata.SetApertureAttrib( attrib );
312
313 plotter.FlashPadCircle( hole_descr.m_Hole_Pos, diameter, &gbr_metadata );
314
315 holes_count++;
316 }
317
318 plotter.EndPlot();
319
320 return holes_count;
321}
322
323int GERBER_WRITER::createDrillFile( wxString& aFullFilename, bool aIsNpth,
324 const DRILL_SPAN& aSpan )
325{
326 int holes_count;
327
328 LOCALE_IO dummy; // Use the standard notation for double numbers
329
330 GERBER_PLOTTER plotter;
331
332 // Gerber drill file imply X2 format:
333 plotter.UseX2format( true );
334 plotter.UseX2NetAttributes( true );
335 plotter.DisableApertMacros( false );
336
337 // Add the standard X2 header, without FileFunction
338 AddGerberX2Header( &plotter, m_pcb );
339 plotter.SetViewport( m_offset, pcbIUScale.IU_PER_MILS/10, /* scale */ 1.0, /* mirror */false );
340
341 // has meaning only for gerber plotter. Must be called only after SetViewport
342 plotter.SetGerberCoordinatesFormat( 6 );
343 plotter.SetCreator( wxT( "PCBNEW" ) );
344
345 // Add the standard X2 FileFunction for drill files
346 // %TF.FileFunction,Plated[NonPlated],layer1num,layer2num,PTH[NPTH][Blind][Buried],Drill[Rout][Mixed]*%
347 wxString text = BuildFileFunctionAttributeString( aSpan,
348 aIsNpth ? TYPE_FILE::NPTH_FILE
350 plotter.AddLineToHeader( text );
351
352 // Add file polarity (positive)
353 text = wxT( "%TF.FilePolarity,Positive*%" );
354 plotter.AddLineToHeader( text );
355
356 if( !plotter.OpenFile( aFullFilename ) )
357 return -1;
358
359 plotter.StartPlot( wxT( "1" ) );
360
361 holes_count = 0;
362
363 VECTOR2I hole_pos;
364 bool last_item_is_via = true; // a flag to clear object attributes when a via hole is created.
365
366 for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ )
367 {
368 HOLE_INFO& hole_descr = m_holeListBuffer[ii];
369 hole_pos = hole_descr.m_Hole_Pos;
370
371 // Manage the aperture attributes: in drill files 3 attributes can be used:
372 // "ViaDrill", only for vias, not pads
373 // "ComponentDrill", only for Through Holes pads
374 // "Slot" for oblong holes;
375 GBR_METADATA gbr_metadata;
376
377 if( dyn_cast<const PCB_VIA*>( hole_descr.m_ItemParent ) )
378 {
379 if( hole_descr.m_IsBackdrill )
381 else
383
384 if( !last_item_is_via )
385 {
386 // be sure the current object attribute is cleared for vias
387 plotter.EndBlock( nullptr );
388 }
389
390 last_item_is_via = true;
391 }
392 else if( dyn_cast<const PAD*>( hole_descr.m_ItemParent ) )
393 {
394 last_item_is_via = false;
395 const PAD* pad = dyn_cast<const PAD*>( hole_descr.m_ItemParent );
396
397 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
398 {
399 gbr_metadata.SetApertureAttrib(
401 }
402 else if( pad->GetProperty() == PAD_PROP::PRESSFIT )
403 {
404 gbr_metadata.SetApertureAttrib(
406 }
407 else
408 {
409 // Good practice of oblong pad holes (slots) is to use a specific aperture for
410 // routing, not used in drill commands.
411 if( hole_descr.m_Hole_Shape )
412 {
413 gbr_metadata.SetApertureAttrib(
415 }
416 else
417 {
418 gbr_metadata.SetApertureAttrib(
420 }
421 }
422
423 // Add object attribute: component reference to pads (mainly useful for users)
424 wxString ref = pad->GetParentFootprint()->GetReference();
425
426 gbr_metadata.SetCmpReference( ref );
428 }
429
430 if( hole_descr.m_Hole_Shape )
431 {
432#if FLASH_OVAL_HOLE // set to 1 to use flashed oblong holes,
433 // 0 to draw them as a line.
434 plotter.FlashPadOval( hole_pos, hole_descr.m_Hole_Size, hole_descr.m_Hole_Orient,
435 &gbr_metadata );
436#else
437 // Use routing for oblong hole (Slots)
438 VECTOR2I start, end;
439 convertOblong2Segment( hole_descr.m_Hole_Size, hole_descr.m_Hole_Orient, start, end );
440 int width = std::min( hole_descr.m_Hole_Size.x, hole_descr.m_Hole_Size.y );
441
442 if ( width == 0 )
443 continue;
444
445 plotter.ThickSegment( start+hole_pos, end+hole_pos, width, &gbr_metadata );
446#endif
447 }
448 else
449 {
450 int diam = std::min( hole_descr.m_Hole_Size.x, hole_descr.m_Hole_Size.y );
451 plotter.FlashPadCircle( hole_pos, diam, &gbr_metadata );
452 }
453
454 holes_count++;
455 }
456
457 plotter.EndPlot();
458
459 return holes_count;
460}
461
462
464{
465 wxFileName fn = m_pcb->GetFileName();
466 wxString pairName = wxString::FromUTF8( layerPairName( aSpan.Pair() ).c_str() );
467
468 fn.SetName( fn.GetName() + wxT( "-" ) + pairName + wxT( "-backdrill-drl" ) );
469 fn.SetExt( m_drillFileExtension );
470
471 return fn;
472}
473
474
475bool GERBER_WRITER::writeBackdrillLayerPairFile( const wxString& aPlotDirectory,
476 REPORTER* aReporter, const DRILL_SPAN& aSpan )
477{
478 wxFileName fn = getBackdrillLayerPairFileName( aSpan );
479 fn.SetPath( aPlotDirectory );
480
481 wxString fullFilename = fn.GetFullPath();
482
483 if( createDrillFile( fullFilename, true, aSpan ) < 0 )
484 {
485 if( aReporter )
486 {
487 wxString msg;
488 msg.Printf( _( "Failed to create file '%s'." ), fullFilename );
489 aReporter->Report( msg, RPT_SEVERITY_ERROR );
490 }
491
492 return false;
493 }
494
495 if( aReporter )
496 {
497 wxString msg;
498 msg.Printf( _( "Created file '%s'." ), fullFilename );
499 aReporter->Report( msg, RPT_SEVERITY_ACTION );
500 }
501
502 return true;
503}
504
505
506#if !FLASH_OVAL_HOLE
507void convertOblong2Segment( const VECTOR2I& aSize, const EDA_ANGLE& aOrient, VECTOR2I& aStart,
508 VECTOR2I& aEnd )
509{
510 VECTOR2I size( aSize );
511 EDA_ANGLE orient( aOrient );
512
513 /* The pad will be drawn as an oblong shape with size.y > size.x
514 * (Oval vertical orientation 0)
515 */
516 if( size.x > size.y )
517 {
518 std::swap( size.x, size.y );
519 orient += ANGLE_90;
520 }
521
522 int deltaxy = size.y - size.x; // distance between centers of the oval
523 aStart = VECTOR2I( 0, deltaxy / 2 );
524 RotatePoint( aStart, orient );
525
526 aEnd = VECTOR2I( 0, -deltaxy / 2 );
527 RotatePoint( aEnd, orient );
528}
529#endif
530
531
532void GERBER_WRITER::SetFormat( int aRightDigits )
533{
534 /* Set conversion scale depending on drill file units */
535 m_conversionUnits = 1.0 / pcbIUScale.IU_PER_MM; // Gerber units = mm
536
537 // Set precision (unit is mm).
538 m_precision.m_Lhs = 4;
539 m_precision.m_Rhs = aRightDigits == 6 ? 6 : 5;
540}
541
542
543const wxString GERBER_WRITER::getDrillFileName( const DRILL_SPAN& aSpan, bool aNPTH,
544 bool aMerge_PTH_NPTH ) const
545{
546 // Gerber files extension is always .gbr.
547 // Therefore, to mark drill files, add "-drl" to the filename.
548 wxFileName fname( GENDRILL_WRITER_BASE::getDrillFileName( aSpan, aNPTH, aMerge_PTH_NPTH ) );
549 fname.SetName( fname.GetName() + wxT( "-drl" ) );
550
551 return fname.GetFullPath();
552}
553
554
556{
557 for( auto& hole_descr : m_holeListBuffer )
558 {
559 if( !dyn_cast<const PCB_VIA*>( hole_descr.m_ItemParent ) )
560 {
561 continue;
562 }
563
564 switch( aFeature )
565 {
567 if( hole_descr.m_Hole_Filled )
568 return true;
569 break;
570
572 if( hole_descr.m_Hole_Capped )
573 return true;
574 break;
575
577 if( hole_descr.m_Hole_Bot_Covered )
578 return true;
579 break;
580
582 if( hole_descr.m_Hole_Top_Covered )
583 return true;
584 break;
585
587 if( hole_descr.m_Hole_Bot_Plugged )
588 return true;
589 break;
590
592 if( hole_descr.m_Hole_Top_Plugged )
593 return true;
594 break;
595
597 if( hole_descr.m_Hole_Bot_Tented )
598 return true;
599 break;
600
602 if( hole_descr.m_Hole_Top_Tented )
603 return true;
604 break;
605 }
606 }
607
608 return false;
609}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:112
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
@ GBR_APERTURE_ATTRIB_PRESSFITDRILL
Aperture used for pressfit pads in drill files.
@ GBR_APERTURE_ATTRIB_BACKDRILL
Aperture used for pad holes in drill files.
@ GBR_APERTURE_ATTRIB_CMP_OBLONG_DRILL
Aperture used for pads oblong holes in drill files.
@ GBR_APERTURE_ATTRIB_CASTELLATEDDRILL
Aperture used for castellated pads in drill files.
@ GBR_APERTURE_ATTRIB_VIADRILL
Aperture used for backdrill holes in drill files.
Metadata which can be added in a gerber file as attribute in X2 format.
void SetCmpReference(const wxString &aComponentRef)
void SetApertureAttrib(GBR_APERTURE_METADATA::GBR_APERTURE_ATTRIB aApertAttribute)
void SetNetAttribType(int aNetAttribType)
@ GBR_NETINFO_CMP
print info associated to a component (TO.C attribute)
virtual const wxString getProtectionFileName(const DRILL_SPAN &aSpan, IPC4761_FEATURES aFeature) const
std::vector< HOLE_INFO > m_holeListBuffer
void buildHolesList(const DRILL_SPAN &aSpan, bool aGenerateNPTH_list)
Create the list of holes and tools for a given board.
std::vector< DRILL_SPAN > getUniqueLayerPairs() const
Get unique layer pairs by examining the micro and blind_buried vias.
const std::string layerPairName(DRILL_LAYER_PAIR aPair) const
bool CreateMapFilesSet(const wxString &aPlotDirectory, REPORTER *aReporter=nullptr)
Create the full set of map files for the board, in PS, PDF ... format (use SetMapFileFormat() to sele...
virtual const wxString getDrillFileName(const DRILL_SPAN &aSpan, bool aNPTH, bool aMerge_PTH_NPTH) const
const wxString BuildFileFunctionAttributeString(const DRILL_SPAN &aSpan, TYPE_FILE aHoleType, bool aCompatNCdrill=false) const
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData) override
virtual void SetGerberCoordinatesFormat(int aResolution, bool aUseInches=false) override
Selection of Gerber units and resolution (number of digits in mantissa).
virtual void FlashPadCircle(const VECTOR2I &pos, int diametre, void *aData) override
Filled circular flashes are stored as apertures.
virtual void FlashPadOval(const VECTOR2I &aPadPos, const VECTOR2I &aSize, const EDA_ANGLE &aOrient, void *aData) override
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 EndBlock(void *aData) override
Define the end of a group of drawing items the group is started by StartBlock().
virtual bool StartPlot(const wxString &pageNumber) override
Write GERBER header to file initialize global variable g_Plot_PlotOutputFile.
void DisableApertMacros(bool aDisable)
Disable Aperture Macro (AM) command, only for broken Gerber Readers.
bool CreateDrillandMapFilesSet(const wxString &aPlotDirectory, bool aGenDrill, bool aGenMap, bool aGenTenting, REPORTER *aReporter=nullptr)
Create the full set of Excellon drill file for the board filenames are computed from the board name,...
bool writeBackdrillLayerPairFile(const wxString &aPlotDirectory, REPORTER *aReporter, const DRILL_SPAN &aSpan)
int createDrillFile(wxString &aFullFilename, bool aIsNpth, const DRILL_SPAN &aSpan)
Create an Excellon drill file.
virtual const wxString getDrillFileName(const DRILL_SPAN &aSpan, bool aNPTH, bool aMerge_PTH_NPTH) const override
void SetFormat(int aRightDigits=6)
Initialize internal parameters to match the given format.
wxFileName getBackdrillLayerPairFileName(const DRILL_SPAN &aSpan) const
int createProtectionFile(const wxString &aFullFilename, IPC4761_FEATURES aFeature, DRILL_LAYER_PAIR aLayerPair)
Create a Gerber X2 file for via protection features.
bool hasViaType(IPC4761_FEATURES aFeature)
test for an existing via having the given feature IPC4761_FEATURES
Handle hole which must be drilled (diameter, position and layers).
BOARD_ITEM * m_ItemParent
EDA_ANGLE m_Hole_Orient
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:41
Definition pad.h:55
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition plotter.cpp:77
virtual void SetCreator(const wxString &aCreator)
Definition plotter.h:188
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:198
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
virtual REPORTER & ReportTail(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Places the report at the end of the list, for objects that support report ordering.
Definition reporter.h:112
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
Handle special data (items attributes) during plot.
static void convertOblong2Segment(const VECTOR2I &aSize, const EDA_ANGLE &aOrient, VECTOR2I &aStart, VECTOR2I &aEnd)
Classes used in drill files, map files and report files generation.
std::pair< PCB_LAYER_ID, PCB_LAYER_ID > DRILL_LAYER_PAIR
@ B_Cu
Definition layer_ids.h:65
@ F_Cu
Definition layer_ids.h:64
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
Definition padstack.h:123
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:121
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
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
@ RPT_SEVERITY_ACTION
std::vector< FAB_LAYER_COLOR > dummy
DRILL_LAYER_PAIR Pair() const
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:61
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695