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, see <https://www.gnu.org/licenses/>.
19 */
20
25
27#include <string_utils.h>
28#include <locale_io.h>
29#include <board.h>
30#include <footprint.h>
31#include <pcb_track.h>
32#include <pad.h>
33#include <pcbplot.h>
35#include <reporter.h>
36#include <gbr_metadata.h>
37
38// set to 1 to use flashed oblong holes, 0 to draw them by a line (route holes).
39// WARNING: currently ( gerber-layer-format-specification-revision-2023-08 ),
40// oblong holes **must be routed* in a drill file and not flashed,
41// so set FLASH_OVAL_HOLE to 0
42#define FLASH_OVAL_HOLE 0
43
44
54
55
56bool GERBER_WRITER::CreateDrillandMapFilesSet( const wxString& aPlotDirectory, bool aGenDrill,
57 bool aGenMap, bool aGenTenting, REPORTER* aReporter )
58{
59 bool success = true;
60 // Note: In Gerber drill files, NPTH and PTH are always separate files
61 m_merge_PTH_NPTH = false;
62
63 wxFileName fn;
64 wxString msg;
65
66 std::vector<DRILL_SPAN> hole_sets = getUniqueLayerPairs();
67
68 hole_sets.emplace_back( F_Cu, B_Cu, false, true );
69
70 for( std::vector<DRILL_SPAN>::const_iterator it = hole_sets.begin();
71 it != hole_sets.end(); ++it )
72 {
73 const DRILL_SPAN& span = *it;
74 bool doing_npth = span.m_IsNonPlatedFile;
75
76 buildHolesList( span, doing_npth );
77
78 if( getHolesCount() == 0 )
79 continue;
80
81 fn = getDrillFileName( span, doing_npth, m_merge_PTH_NPTH );
82 fn.SetPath( aPlotDirectory );
83
84 if( aGenDrill )
85 {
86 wxString fullFilename = fn.GetFullPath();
87 bool isNonPlated = doing_npth || span.m_IsBackdrill;
88 bool wroteDrillFile = false;
89
90 int result = createDrillFile( fullFilename, isNonPlated, span );
91
92 if( result < 0 )
93 {
94 if( aReporter )
95 {
96 msg.Printf( _( "Failed to create file '%s'." ), fullFilename );
97 aReporter->Report( msg, RPT_SEVERITY_ERROR );
98 }
99
100 success = false;
101 break;
102 }
103
104 wroteDrillFile = true;
105
106 if( aReporter )
107 {
108 msg.Printf( _( "Created file '%s'." ), fullFilename );
109 aReporter->Report( msg, RPT_SEVERITY_ACTION );
110 }
111
112 if( wroteDrillFile && span.m_IsBackdrill )
113 {
114 if( !writeBackdrillLayerPairFile( aPlotDirectory, aReporter, span ) )
115 {
116 success = false;
117 break;
118 }
119 }
120 }
121
122 if( doing_npth )
123 continue;
124
125 for( IPC4761_FEATURES feature :
130 {
131 if( !aGenTenting )
132 {
133 if( feature == IPC4761_FEATURES::TENTED_BACK
134 || feature == IPC4761_FEATURES::TENTED_FRONT )
135 {
136 continue;
137 }
138 }
139
140 if( !hasViaType( feature ) )
141 continue;
142
143 fn = getProtectionFileName( span, feature );
144 fn.SetPath( aPlotDirectory );
145
146 wxString fullFilename = fn.GetFullPath();
147
148 if( createProtectionFile( fullFilename, feature, span.Pair() ) < 0 )
149 {
150 if( aReporter )
151 {
152 msg.Printf( _( "Failed to create file '%s'." ), fullFilename );
153 aReporter->Report( msg, RPT_SEVERITY_ERROR );
154 success = false;
155 }
156 }
157 else
158 {
159 if( aReporter )
160 {
161 msg.Printf( _( "Created file '%s'." ), fullFilename );
162 aReporter->Report( msg, RPT_SEVERITY_ACTION );
163 }
164 }
165 }
166 }
167
168 if( aGenMap )
169 success &= CreateMapFilesSet( aPlotDirectory, aReporter );
170
171 if( aReporter )
172 aReporter->ReportTail( _( "Done." ), RPT_SEVERITY_INFO );
173
174 return success;
175}
176
177
178#if !FLASH_OVAL_HOLE
179// A helper class to transform an oblong hole to a segment
180static void convertOblong2Segment( const VECTOR2I& aSize, const EDA_ANGLE& aOrient, VECTOR2I& aStart, VECTOR2I& aEnd );
181#endif
182
183int GERBER_WRITER::createProtectionFile( const wxString& aFullFilename, IPC4761_FEATURES aFeature,
184 DRILL_LAYER_PAIR aLayerPair )
185{
186 GERBER_PLOTTER plotter;
187 // Gerber drill file imply X2 format:
188 plotter.UseX2format( true );
189 plotter.UseX2NetAttributes( true );
190 plotter.DisableApertMacros( false );
191
192 // Add the standard X2 header, without FileFunction
193 AddGerberX2Header( &plotter, m_pcb );
194 plotter.SetViewport( m_offset, pcbIUScale.IU_PER_MILS / 10, /* scale */ 1.0,
195 /* mirror */ false );
196
197 // has meaning only for gerber plotter. Must be called only after SetViewport
199 plotter.SetCreator( wxT( "PCBNEW" ) );
200
201 // Add the standard X2 FileFunction for drill files
202 // %TF.FileFunction,Plated[NonPlated],layer1num,layer2num,PTH[NPTH][Blind][Buried],Drill[Rout][Mixed]*%
203 wxString text = "%TF,FileFunction,Other,";
204
205 std::string attrib;
206 switch( aFeature )
207 {
209 text << wxT( "Capping" );
210 attrib = "Capping";
211 break;
213 text << wxT( "Filling" );
214 attrib = "Filling";
215 break;
217 text << wxT( "Covering-Back" );
218 attrib = "Covering";
219 break;
221 text << wxT( "Covering-Front" );
222 attrib = "Covering";
223 break;
225 text << wxT( "Plugging-Back" );
226 attrib = "Plugging";
227 break;
229 text << wxT( "Plugging-Front" );
230 attrib = "Plugging";
231 break;
233 text << wxT( "Tenting-Back" );
234 attrib = "Tenting";
235 break;
237 text << wxT( "Tenting-Front" );
238 attrib = "Tenting";
239 break;
240 default: return -1;
241 }
242 text << wxT( "*%" );
243 plotter.AddLineToHeader( text );
244
245 // Add file polarity (positive)
246 text = wxT( "%TF.FilePolarity,Positive*%" );
247 plotter.AddLineToHeader( text );
248
249
250 if( !plotter.OpenFile( aFullFilename ) )
251 return -1;
252
253 plotter.StartPlot( wxT( "1" ) );
254
255 int holes_count = 0;
256
257 for( auto& hole_descr : m_holeListBuffer )
258 {
259 if( !dyn_cast<const PCB_VIA*>( hole_descr.m_ItemParent ) )
260 {
261 continue;
262 }
263
264 const PCB_VIA* via = dyn_cast<const PCB_VIA*>( hole_descr.m_ItemParent );
265
266 bool cont = false;
267 int diameter = hole_descr.m_Hole_Diameter;
268 // clang-format off: suggestion is inconsitent
269 switch( aFeature )
270 {
272 cont = ! hole_descr.m_Hole_Filled;
273 break;
275 cont = ! hole_descr.m_Hole_Capped;
276 break;
278 cont = !hole_descr.m_Hole_Bot_Covered;
279 diameter = via->GetWidth( via->BottomLayer() );
280 break;
282 cont = ! hole_descr.m_Hole_Top_Covered;
283 diameter = via->GetWidth( via->TopLayer() );
284 break;
286 cont = !hole_descr.m_Hole_Bot_Plugged;
287 break;
289 cont = ! hole_descr.m_Hole_Top_Plugged;
290 break;
292 cont = ! hole_descr.m_Hole_Bot_Tented;
293 diameter = via->GetWidth( via->BottomLayer() );
294 break;
296 cont = ! hole_descr.m_Hole_Top_Tented;
297 diameter = via->GetWidth( via->TopLayer() );
298 break;
299 }
300 // clang-format on: suggestion is inconsitent
301
302 if( cont )
303 continue;
304
305 GBR_METADATA gbr_metadata;
306
307 gbr_metadata.SetApertureAttrib( attrib );
308
309 plotter.FlashPadCircle( hole_descr.m_Hole_Pos, diameter, &gbr_metadata );
310
311 holes_count++;
312 }
313
314 plotter.EndPlot();
315
316 return holes_count;
317}
318
319int GERBER_WRITER::createDrillFile( wxString& aFullFilename, bool aIsNpth,
320 const DRILL_SPAN& aSpan )
321{
322 int holes_count;
323
324 LOCALE_IO dummy; // Use the standard notation for double numbers
325
326 GERBER_PLOTTER plotter;
327
328 // Gerber drill file imply X2 format:
329 plotter.UseX2format( true );
330 plotter.UseX2NetAttributes( true );
331 plotter.DisableApertMacros( false );
332
333 // Add the standard X2 header, without FileFunction
334 AddGerberX2Header( &plotter, m_pcb );
335 plotter.SetViewport( m_offset, pcbIUScale.IU_PER_MILS/10, /* scale */ 1.0, /* mirror */false );
336
337 // has meaning only for gerber plotter. Must be called only after SetViewport
339 plotter.SetCreator( wxT( "PCBNEW" ) );
340
341 // Add the standard X2 FileFunction for drill files
342 // %TF.FileFunction,Plated[NonPlated],layer1num,layer2num,PTH[NPTH][Blind][Buried],Drill[Rout][Mixed]*%
343 wxString text = BuildFileFunctionAttributeString( aSpan,
344 aIsNpth ? TYPE_FILE::NPTH_FILE
346 plotter.AddLineToHeader( text );
347
348 // Add file polarity (positive)
349 text = wxT( "%TF.FilePolarity,Positive*%" );
350 plotter.AddLineToHeader( text );
351
352 if( !plotter.OpenFile( aFullFilename ) )
353 return -1;
354
355 plotter.StartPlot( wxT( "1" ) );
356
357 holes_count = 0;
358
359 VECTOR2I hole_pos;
360 bool last_item_is_via = true; // a flag to clear object attributes when a via hole is created.
361
362 for( unsigned ii = 0; ii < m_holeListBuffer.size(); ii++ )
363 {
364 HOLE_INFO& hole_descr = m_holeListBuffer[ii];
365 hole_pos = hole_descr.m_Hole_Pos;
366
367 // Manage the aperture attributes: in drill files 3 attributes can be used:
368 // "ViaDrill", only for vias, not pads
369 // "ComponentDrill", only for Through Holes pads
370 // "Slot" for oblong holes;
371 GBR_METADATA gbr_metadata;
372
373 if( dyn_cast<const PCB_VIA*>( hole_descr.m_ItemParent ) )
374 {
375 if( hole_descr.m_IsBackdrill )
377 else
379
380 if( !last_item_is_via )
381 {
382 // be sure the current object attribute is cleared for vias
383 plotter.EndBlock( nullptr );
384 }
385
386 last_item_is_via = true;
387 }
388 else if( dyn_cast<const PAD*>( hole_descr.m_ItemParent ) )
389 {
390 last_item_is_via = false;
391 const PAD* pad = dyn_cast<const PAD*>( hole_descr.m_ItemParent );
392
393 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
394 {
395 gbr_metadata.SetApertureAttrib(
397 }
398 else if( pad->GetProperty() == PAD_PROP::PRESSFIT )
399 {
400 gbr_metadata.SetApertureAttrib(
402 }
403 else
404 {
405 // Good practice of oblong pad holes (slots) is to use a specific aperture for
406 // routing, not used in drill commands.
407 if( hole_descr.m_Hole_Shape )
408 {
409 gbr_metadata.SetApertureAttrib(
411 }
412 else
413 {
414 gbr_metadata.SetApertureAttrib(
416 }
417 }
418
419 // Add object attribute: component reference to pads (mainly useful for users)
420 wxString ref = pad->GetParentFootprint()->GetReference();
421
422 gbr_metadata.SetCmpReference( ref );
424 }
425
426 if( hole_descr.m_Hole_Shape )
427 {
428#if FLASH_OVAL_HOLE // set to 1 to use flashed oblong holes,
429 // 0 to draw them as a line.
430 plotter.FlashPadOval( hole_pos, hole_descr.m_Hole_Size, hole_descr.m_Hole_Orient,
431 &gbr_metadata );
432#else
433 // Use routing for oblong hole (Slots)
434 VECTOR2I start, end;
435 convertOblong2Segment( hole_descr.m_Hole_Size, hole_descr.m_Hole_Orient, start, end );
436 int width = std::min( hole_descr.m_Hole_Size.x, hole_descr.m_Hole_Size.y );
437
438 if ( width == 0 )
439 continue;
440
441 plotter.ThickSegment( start+hole_pos, end+hole_pos, width, &gbr_metadata );
442#endif
443 }
444 else
445 {
446 int diam = std::min( hole_descr.m_Hole_Size.x, hole_descr.m_Hole_Size.y );
447 plotter.FlashPadCircle( hole_pos, diam, &gbr_metadata );
448 }
449
450 holes_count++;
451 }
452
453 plotter.EndPlot();
454
455 return holes_count;
456}
457
458
460{
461 wxFileName fn = m_pcb->GetFileName();
462 wxString pairName = wxString::FromUTF8( layerPairName( aSpan.Pair() ).c_str() );
463
464 fn.SetName( fn.GetName() + wxT( "-" ) + pairName + wxT( "-backdrill-drl" ) );
465 fn.SetExt( m_drillFileExtension );
466
467 return fn;
468}
469
470
471bool GERBER_WRITER::writeBackdrillLayerPairFile( const wxString& aPlotDirectory,
472 REPORTER* aReporter, const DRILL_SPAN& aSpan )
473{
474 wxFileName fn = getBackdrillLayerPairFileName( aSpan );
475 fn.SetPath( aPlotDirectory );
476
477 wxString fullFilename = fn.GetFullPath();
478
479 if( createDrillFile( fullFilename, true, aSpan ) < 0 )
480 {
481 if( aReporter )
482 {
483 wxString msg;
484 msg.Printf( _( "Failed to create file '%s'." ), fullFilename );
485 aReporter->Report( msg, RPT_SEVERITY_ERROR );
486 }
487
488 return false;
489 }
490
491 if( aReporter )
492 {
493 wxString msg;
494 msg.Printf( _( "Created file '%s'." ), fullFilename );
495 aReporter->Report( msg, RPT_SEVERITY_ACTION );
496 }
497
498 return true;
499}
500
501
502#if !FLASH_OVAL_HOLE
503void convertOblong2Segment( const VECTOR2I& aSize, const EDA_ANGLE& aOrient, VECTOR2I& aStart,
504 VECTOR2I& aEnd )
505{
506 VECTOR2I size( aSize );
507 EDA_ANGLE orient( aOrient );
508
509 /* The pad will be drawn as an oblong shape with size.y > size.x
510 * (Oval vertical orientation 0)
511 */
512 if( size.x > size.y )
513 {
514 std::swap( size.x, size.y );
515 orient += ANGLE_90;
516 }
517
518 int deltaxy = size.y - size.x; // distance between centers of the oval
519 aStart = VECTOR2I( 0, deltaxy / 2 );
520 RotatePoint( aStart, orient );
521
522 aEnd = VECTOR2I( 0, -deltaxy / 2 );
523 RotatePoint( aEnd, orient );
524}
525#endif
526
527
528void GERBER_WRITER::SetFormat( int aRightDigits )
529{
530 /* Set conversion scale depending on drill file units */
531 m_conversionUnits = 1.0 / pcbIUScale.IU_PER_MM; // Gerber units = mm
532
533 // Set precision (unit is mm).
534 m_precision.m_Lhs = 4;
535 m_precision.m_Rhs = aRightDigits == 6 ? 6 : 5;
536}
537
538
539const wxString GERBER_WRITER::getDrillFileName( const DRILL_SPAN& aSpan, bool aNPTH,
540 bool aMerge_PTH_NPTH ) const
541{
542 // Gerber files extension is always .gbr.
543 // Therefore, to mark drill files, add "-drl" to the filename.
544 wxFileName fname( GENDRILL_WRITER_BASE::getDrillFileName( aSpan, aNPTH, aMerge_PTH_NPTH ) );
545 fname.SetName( fname.GetName() + wxT( "-drl" ) );
546
547 return fname.GetFullPath();
548}
549
550
552{
553 for( auto& hole_descr : m_holeListBuffer )
554 {
555 if( !dyn_cast<const PCB_VIA*>( hole_descr.m_ItemParent ) )
556 {
557 continue;
558 }
559
560 switch( aFeature )
561 {
563 if( hole_descr.m_Hole_Filled )
564 return true;
565 break;
566
568 if( hole_descr.m_Hole_Capped )
569 return true;
570 break;
571
573 if( hole_descr.m_Hole_Bot_Covered )
574 return true;
575 break;
576
578 if( hole_descr.m_Hole_Top_Covered )
579 return true;
580 break;
581
583 if( hole_descr.m_Hole_Bot_Plugged )
584 return true;
585 break;
586
588 if( hole_descr.m_Hole_Top_Plugged )
589 return true;
590 break;
591
593 if( hole_descr.m_Hole_Bot_Tented )
594 return true;
595 break;
596
598 if( hole_descr.m_Hole_Top_Tented )
599 return true;
600 break;
601 }
602 }
603
604 return false;
605}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:121
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:372
@ 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:37
Definition pad.h:61
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition plotter.cpp:73
virtual void SetCreator(const wxString &aCreator)
Definition plotter.h:185
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
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:71
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:100
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:110
#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:61
@ F_Cu
Definition layer_ids.h:60
@ 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:290
@ 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:225
Casted dyn_cast(From aObject)
A lightweight dynamic downcast.
Definition typeinfo.h:56
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683