KiCad PCB EDA Suite
rs274d.cpp
Go to the documentation of this file.
1 
6 /*
7  * This program source code file is part of KiCad, a free EDA CAD application.
8  *
9  * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, you may find one here:
23  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
24  * or you may search the http://www.gnu.org website for the version 2 license,
25  * or you may write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28 
29 #include <fctsys.h>
30 #include <common.h>
31 
32 #include <gerbview.h>
33 #include <gerbview_frame.h>
34 #include <trigo.h>
37 
38 #include <cmath>
39 
40 /* Gerber: NOTES about some important commands found in RS274D and RS274X (G codes):
41  * Gn =
42  * G01 linear interpolation (right trace)
43  * G02, G20, G21 Circular interpolation, meaning trig <0 (clockwise)
44  * G03, G30, G31 Circular interpolation, meaning trigo> 0 (counterclockwise)
45  * G04 = comment. Since Sept 2014, file attributes can be found here
46  * if the line starts by G04 #@!
47  * G06 parabolic interpolation
48  * G07 Cubic Interpolation
49  * G10 linear interpolation (scale x10)
50  * G11 linear interpolation (0.1x range)
51  * G12 linear interpolation (0.01x scale)
52  * G36 Start polygon mode
53  * G37 Stop polygon mode (and close it)
54  * G54 Selection Tool
55  * G60 linear interpolation (scale x100)
56  * G70 Select Units = Inches
57  * G71 Select Units = Millimeters
58  * G74 disable 360 degrees circular interpolation (return to 90 deg mode)
59  * and perhaps circular interpolation (return to linear interpolation )
60  * see rs274xrevd_e.pdf pages 47 and 48
61  * Unfortunately page 47 said G74 disable G02 or G03
62  * and page 48 said G01 must be used to disable G02 or G03.
63  * Currently GerbView disable G02 or G03 after a G74 command (tests using 2 gerber files).
64  * G75 enable 360 degrees circular interpolation
65  * G90 mode absolute coordinates
66  *
67  * X, Y
68  * X and Y are followed by + or - and m + n digits (not separated)
69  * m = integer part
70  * n = part after the comma
71  * Classic formats: m = 2, n = 3 (size 2.3)
72  * m = 3, n = 4 (size 3.4)
73  * eg
74  * GxxX00345Y-06123*
75  *
76  * Tools and D_CODES
77  * Tool number (identification of shapes)
78  * 10 to 999
79  * D_CODES:
80  * D01 ... D9 = command codes:
81  * D01 = activating light (pen down) when placement
82  * D02 = light extinction (pen up) when placement
83  * D03 = Flash
84  * D09 = VAPE Flash (I never see this command in gerber file)
85  * D51 = G54 preceded by -> Select VAPE
86  *
87  * D10 ... D999 = Identification Tool: tool selection
88  */
89 
90 
91 /* Local Functions (are lower case since they are private to this source file)
92 **/
93 
94 
109  APERTURE_T aAperture,
110  int Dcode_index,
111  const wxPoint& aPos,
112  wxSize aSize,
113  bool aLayerNegative )
114 {
115  aGbrItem->m_Size = aSize;
116  aGbrItem->m_Start = aPos;
117  aGbrItem->m_End = aGbrItem->m_Start;
118  aGbrItem->m_DCode = Dcode_index;
119  aGbrItem->SetLayerPolarity( aLayerNegative );
120  aGbrItem->m_Flashed = true;
121  aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
122 
123  switch( aAperture )
124  {
125  case APT_POLYGON: // flashed regular polygon
126  aGbrItem->m_Shape = GBR_SPOT_POLY;
127  break;
128 
129  case APT_CIRCLE:
130  aGbrItem->m_Shape = GBR_SPOT_CIRCLE;
131  aGbrItem->m_Size.y = aGbrItem->m_Size.x;
132  break;
133 
134  case APT_OVAL:
135  aGbrItem->m_Shape = GBR_SPOT_OVAL;
136  break;
137 
138  case APT_RECT:
139  aGbrItem->m_Shape = GBR_SPOT_RECT;
140  break;
141 
142  case APT_MACRO:
143  aGbrItem->m_Shape = GBR_SPOT_MACRO;
144  break;
145  }
146 }
147 
148 
162  int Dcode_index,
163  const wxPoint& aStart,
164  const wxPoint& aEnd,
165  wxSize aPenSize,
166  bool aLayerNegative )
167 {
168  aGbrItem->m_Flashed = false;
169 
170  aGbrItem->m_Size = aPenSize;
171 
172  aGbrItem->m_Start = aStart;
173  aGbrItem->m_End = aEnd;
174 
175  aGbrItem->m_DCode = Dcode_index;
176  aGbrItem->SetLayerPolarity( aLayerNegative );
177 
178  aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
179 }
180 
181 
212 static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index,
213  const wxPoint& aStart, const wxPoint& aEnd,
214  const wxPoint& aRelCenter, wxSize aPenSize,
215  bool aClockwise, bool aMultiquadrant,
216  bool aLayerNegative )
217 {
218  wxPoint center, delta;
219 
220  aGbrItem->m_Shape = GBR_ARC;
221  aGbrItem->m_Size = aPenSize;
222  aGbrItem->m_Flashed = false;
223 
224  if( aGbrItem->m_GerberImageFile )
225  aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
226 
227  if( aMultiquadrant )
228  center = aStart + aRelCenter;
229  else
230  {
231  // in single quadrant mode the relative coordinate aRelCenter is always >= 0
232  // So we must recalculate the actual sign of aRelCenter.x and aRelCenter.y
233  center = aRelCenter;
234 
235  // calculate arc end coordinate relative to the starting point,
236  // because center is relative to the center point
237  delta = aEnd - aStart;
238 
239  // now calculate the relative to aStart center position, for a draw function
240  // that use trigonometric arc angle (or counter-clockwise)
241  /* Quadrants:
242  * Y
243  * 2 | 1
244  * -------X
245  * 3 | 4
246  * C = actual relative arc center, S = arc start (axis origin) E = relative arc end
247  */
248  if( (delta.x >= 0) && (delta.y >= 0) )
249  {
250  /* Quadrant 1 (trigo or cclockwise):
251  * C | E
252  * ---S---
253  * 3 | 4
254  */
255  center.x = -center.x;
256  }
257  else if( (delta.x >= 0) && (delta.y < 0) )
258  {
259  /* Quadrant 4 (trigo or cclockwise):
260  * 2 | C
261  * ---S---
262  * 3 | E
263  */
264  // Nothing to do
265  }
266  else if( (delta.x < 0) && (delta.y >= 0) )
267  {
268  /* Quadrant 2 (trigo or cclockwise):
269  * E | 1
270  * ---S---
271  * C | 4
272  */
273  center.x = -center.x;
274  center.y = -center.y;
275  }
276  else
277  {
278  /* Quadrant 3 (trigo or cclockwise):
279  * 2 | 1
280  * ---S---
281  * E | C
282  */
283  center.y = -center.y;
284  }
285 
286  // Due to your draw arc function, we need this:
287  if( !aClockwise )
288  center = - center;
289 
290  // Calculate actual arc center coordinate:
291  center += aStart;
292  }
293 
294  if( aClockwise )
295  {
296  aGbrItem->m_Start = aStart;
297  aGbrItem->m_End = aEnd;
298  }
299  else
300  {
301  aGbrItem->m_Start = aEnd;
302  aGbrItem->m_End = aStart;
303  }
304 
305  aGbrItem->m_ArcCentre = center;
306 
307  aGbrItem->m_DCode = Dcode_index;
308  aGbrItem->SetLayerPolarity( aLayerNegative );
309 }
310 
311 
339 static void fillArcPOLY( GERBER_DRAW_ITEM* aGbrItem,
340  const wxPoint& aStart, const wxPoint& aEnd,
341  const wxPoint& rel_center,
342  bool aClockwise, bool aMultiquadrant,
343  bool aLayerNegative )
344 {
345  /* in order to calculate arc parameters, we use fillArcGBRITEM
346  * so we muse create a dummy track and use its geometric parameters
347  */
348  static GERBER_DRAW_ITEM dummyGbrItem( NULL );
349 
350  aGbrItem->SetLayerPolarity( aLayerNegative );
351 
352  fillArcGBRITEM( &dummyGbrItem, 0,
353  aStart, aEnd, rel_center, wxSize(0, 0),
354  aClockwise, aMultiquadrant, aLayerNegative );
355 
356  aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
357 
358  wxPoint center;
359  center = dummyGbrItem.m_ArcCentre;
360 
361  // Calculate coordinates relative to arc center;
362  wxPoint start = dummyGbrItem.m_Start - center;
363  wxPoint end = dummyGbrItem.m_End - center;
364 
365  /* Calculate angle arc
366  * angles are in 0.1 deg
367  * angle is trigonometrical (counter-clockwise),
368  * and axis is the X,Y gerber coordinates
369  */
370  double start_angle = ArcTangente( start.y, start.x );
371  double end_angle = ArcTangente( end.y, end.x );
372 
373  // dummyTrack has right geometric parameters, but
374  // fillArcGBRITEM calculates arc parameters for a draw function that expects
375  // start_angle < end_angle. So ensure this is the case here:
376  // Due to the fact atan2 returns angles between -180 to + 180 degrees,
377  // this is not always the case ( a modulo 360.0 degrees can be lost )
378  if( start_angle > end_angle )
379  end_angle += 3600;
380 
381  double arc_angle = start_angle - end_angle;
382  // Approximate arc by 36 segments per 360 degree
383  const int increment_angle = 3600 / 36;
384  int count = std::abs( arc_angle / increment_angle );
385 
386  // calculate polygon corners
387  // when arc is counter-clockwise, dummyGbrItem arc goes from end to start
388  // and we must always create a polygon from start to end.
389  wxPoint start_arc = start;
390  for( int ii = 0; ii <= count; ii++ )
391  {
392  double rot;
393  wxPoint end_arc = start;
394  if( aClockwise )
395  rot = ii * increment_angle; // rot is in 0.1 deg
396  else
397  rot = (count - ii) * increment_angle; // rot is in 0.1 deg
398 
399  if( ii < count )
400  RotatePoint( &end_arc, -rot );
401  else // last point
402  end_arc = aClockwise ? end : start;
403 
404  aGbrItem->m_PolyCorners.push_back( end_arc + center );
405 
406  start_arc = end_arc;
407  }
408 }
409 
410 
411 /* Read the Gnn sequence and returns the value nn.
412  */
414 {
415  int ii = 0;
416  char* text;
417  char line[1024];
418 
419  if( Text == NULL )
420  return 0;
421  Text++;
422  text = line;
423  while( IsNumber( *Text ) )
424  {
425  *(text++) = *(Text++);
426  }
427 
428  *text = 0;
429  ii = atoi( line );
430  return ii;
431 }
432 
433 
434 /* Get the sequence Dnn and returns the value nn
435  */
437 {
438  int ii = 0;
439  char* text;
440  char line[1024];
441 
442  if( Text == NULL )
443  return 0;
444 
445  Text++;
446  text = line;
447  while( IsNumber( *Text ) )
448  *(text++) = *(Text++);
449 
450  *text = 0;
451  ii = atoi( line );
452  return ii;
453 }
454 
455 
456 bool GERBER_FILE_IMAGE::Execute_G_Command( char*& text, int G_command )
457 {
458 // D( printf( "%22s: G_CODE<%d>\n", __func__, G_command ); )
459 
460  switch( G_command )
461  {
462  case GC_PHOTO_MODE: // can starts a D03 flash command: redundant, can
463  // be safely ignored
464  break;
465 
468  break;
469 
472  break;
473 
476  break;
477 
478  case GC_COMMENT:
479  // Skip comment, but only if the line does not start by "G04 #@! TF"
480  // which is a metadata
481  if( strncmp( text, " #@! TF", 7 ) == 0 )
482  {
483  text += 7;
485  dummy.ParseAttribCmd( m_Current_File, NULL, 0, text );
486  if( dummy.IsFileFunction() )
487  {
488  delete m_FileFunction;
490  }
491  }
492 
493  while ( *text && (*text != '*') )
494  text++;
495  break;
496 
499  break;
500 
503  break;
504 
507  break;
508 
509  case GC_SELECT_TOOL:
510  {
511  int D_commande = DCodeNumber( text );
512  if( D_commande < FIRST_DCODE )
513  return false;
514  if( D_commande > (TOOLS_MAX_COUNT - 1) )
515  D_commande = TOOLS_MAX_COUNT - 1;
516  m_Current_Tool = D_commande;
517  D_CODE* pt_Dcode = GetDCODE( D_commande, false );
518  if( pt_Dcode )
519  pt_Dcode->m_InUse = true;
520  break;
521  }
522 
523  case GC_SPECIFY_INCHES:
524  m_GerbMetric = false; // false = Inches, true = metric
525  break;
526 
528  m_GerbMetric = true; // false = Inches, true = metric
529  break;
530 
531  case GC_TURN_OFF_360_INTERPOL: // disable Multi cadran arc and Arc interpol
532  m_360Arc_enbl = false;
533  m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // not sure it should be done
534  break;
535 
537  m_360Arc_enbl = true;
538  break;
539 
541  m_Relative = false; // false = absolute Coord, true = relative
542  // Coord
543  break;
544 
546  m_Relative = true; // false = absolute Coord, true = relative
547  // Coord
548  break;
549 
551  m_PolygonFillMode = true;
552  m_Exposure = false;
553  break;
554 
556  if( m_Exposure && GetItemsList() ) // End of polygon
557  {
558  GERBER_DRAW_ITEM * gbritem = m_Drawings.GetLast();
559  StepAndRepeatItem( *gbritem );
560  }
561  m_Exposure = false;
562  m_PolygonFillMode = false;
564  break;
565 
566  case GC_MOVE: // Non existent
567  default:
568  {
569  wxString msg;
570  msg.Printf( wxT( "G%0.2d command not handled" ), G_command );
571  AddMessageToList( msg );
572  return false;
573  }
574  }
575 
576 
577  return true;
578 }
579 
580 
581 bool GERBER_FILE_IMAGE::Execute_DCODE_Command( char*& text, int D_commande )
582 {
583  wxSize size( 15, 15 );
584 
585  APERTURE_T aperture = APT_CIRCLE;
586  GERBER_DRAW_ITEM* gbritem;
587 
588  int dcode = 0;
589  D_CODE* tool = NULL;
590  wxString msg;
591 
592  if( D_commande >= FIRST_DCODE ) // This is a "Set tool" command
593  {
594  if( D_commande > (TOOLS_MAX_COUNT - 1) )
595  D_commande = TOOLS_MAX_COUNT - 1;
596 
597  // remember which tool is selected, nothing is done with it in this
598  // call
599  m_Current_Tool = D_commande;
600 
601  D_CODE* pt_Dcode = GetDCODE( D_commande, false );
602  if( pt_Dcode )
603  pt_Dcode->m_InUse = true;
604 
605  return true;
606  }
607  else // D_commande = 0..9: this is a pen command (usually D1, D2 or D3)
608  {
609  m_Last_Pen_Command = D_commande;
610  }
611 
612  if( m_PolygonFillMode ) // Enter a polygon description:
613  {
614  switch( D_commande )
615  {
616  case 1: // code D01 Draw line, exposure ON
617  if( !m_Exposure ) // Start a new polygon outline:
618  {
619  m_Exposure = true;
620  gbritem = new GERBER_DRAW_ITEM( this );
621  m_Drawings.Append( gbritem );
622  gbritem->m_Shape = GBR_POLYGON;
623  gbritem->m_Flashed = false;
624  }
625 
626  switch( m_Iterpolation )
627  {
630  gbritem = m_Drawings.GetLast();
631 
632  fillArcPOLY( gbritem, m_PreviousPos,
634  ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ? false : true,
635  m_360Arc_enbl, GetLayerParams().m_LayerNegative );
636  break;
637 
638  default:
639  gbritem = m_Drawings.GetLast();
640 
641  gbritem->m_Start = m_PreviousPos; // m_Start is used as temporary storage
642  if( gbritem->m_PolyCorners.size() == 0 )
643  gbritem->m_PolyCorners.push_back( gbritem->m_Start );
644 
645  gbritem->m_End = m_CurrentPos; // m_End is used as temporary storage
646  gbritem->m_PolyCorners.push_back( gbritem->m_End );
647  break;
648  }
649 
652  break;
653 
654  case 2: // code D2: exposure OFF (i.e. "move to")
655  if( m_Exposure && GetItemsList() ) // End of polygon
656  {
657  gbritem = m_Drawings.GetLast();
658  StepAndRepeatItem( *gbritem );
659  }
660  m_Exposure = false;
663  break;
664 
665  default:
666  return false;
667  }
668  }
669  else
670  {
671  switch( D_commande )
672  {
673  case 1: // code D01 Draw line, exposure ON
674  m_Exposure = true;
675 
676  tool = GetDCODE( m_Current_Tool, false );
677  if( tool )
678  {
679  size = tool->m_Size;
680  dcode = tool->m_Num_Dcode;
681  aperture = tool->m_Shape;
682  }
683 
684  switch( m_Iterpolation )
685  {
687  gbritem = new GERBER_DRAW_ITEM( this );
688  m_Drawings.Append( gbritem );
689 
690  fillLineGBRITEM( gbritem, dcode, m_PreviousPos,
691  m_CurrentPos, size, GetLayerParams().m_LayerNegative );
692  StepAndRepeatItem( *gbritem );
693  break;
694 
698  wxBell();
699  break;
700 
703  gbritem = new GERBER_DRAW_ITEM( this );
704  m_Drawings.Append( gbritem );
705 
706  fillArcGBRITEM( gbritem, dcode, m_PreviousPos,
707  m_CurrentPos, m_IJPos, size,
709  false : true, m_360Arc_enbl, GetLayerParams().m_LayerNegative );
710  StepAndRepeatItem( *gbritem );
711  break;
712 
713  default:
714  msg.Printf( wxT( "RS274D: DCODE Command: interpol error (type %X)" ),
715  m_Iterpolation );
716  AddMessageToList( msg );
717  break;
718  }
719 
721  break;
722 
723  case 2: // code D2: exposure OFF (i.e. "move to")
724  m_Exposure = false;
726  break;
727 
728  case 3: // code D3: flash aperture
729  tool = GetDCODE( m_Current_Tool, false );
730  if( tool )
731  {
732  size = tool->m_Size;
733  dcode = tool->m_Num_Dcode;
734  aperture = tool->m_Shape;
735  }
736 
737  gbritem = new GERBER_DRAW_ITEM( this );
738  m_Drawings.Append( gbritem );
739  fillFlashedGBRITEM( gbritem, aperture, dcode, m_CurrentPos,
740  size, GetLayerParams().m_LayerNegative );
741  StepAndRepeatItem( *gbritem );
743  break;
744 
745  default:
746  return false;
747  }
748  }
749 
750  return true;
751 }
class X2_ATTRIBUTE_FILEFUNCTION ( from TF.FileFunction in Gerber file) Example file function: TF...
void AddMessageToList(const wxString &aMessage)
Function AddMessageToList Add a message to the message list.
X2_ATTRIBUTE_FILEFUNCTION * m_FileFunction
class X2_ATTRIBUTE The attribute value consists of a number of substrings separated by a comma ...
bool Execute_DCODE_Command(char *&text, int D_command)
Definition: rs274d.cpp:581
wxSize m_Size
Horizontal and vertical dimensions.
Definition: dcode.h:98
static void fillArcPOLY(GERBER_DRAW_ITEM *aGbrItem, const wxPoint &aStart, const wxPoint &aEnd, const wxPoint &rel_center, bool aClockwise, bool aMultiquadrant, bool aLayerNegative)
Function fillArcPOLY creates an arc G code when found in poly outlines.
Definition: rs274d.cpp:339
Definition: dcode.h:52
bool m_InUse
false if the aperure (previously defined) is not used to draw something
Definition: dcode.h:106
APERTURE_T m_Shape
shape ( Line, rectangle, circle , oval .. )
Definition: dcode.h:99
void Append(T *aNewElement)
Function Append adds aNewElement to the end of the list.
Definition: dlist.h:177
std::vector< wxPoint > m_PolyCorners
D_CODE * GetDCODE(int aDCODE, bool aCreateIfNoExist=true)
Function GetDCODE returns a pointer to the D_CODE within this GERBER for the given aDCODE...
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
void SetNetAttributes(const GBR_NETLIST_METADATA &aNetAttributes)
void fillLineGBRITEM(GERBER_DRAW_ITEM *aGbrItem, int Dcode_index, const wxPoint &aStart, const wxPoint &aEnd, wxSize aPenSize, bool aLayerNegative)
Function fillLineGBRITEM initializes a given GBRITEM so that it can draw a linear D code...
Definition: rs274d.cpp:161
#define abs(a)
Definition: auxiliary.h:84
static const int delta[8][2]
Definition: solve.cpp:112
#define IsNumber(x)
Definition: dcode.h:51
int GCodeNumber(char *&Text)
Definition: rs274d.cpp:413
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:271
T * GetLast() const
Function GetLast returns the last T* in the list without removing it, or NULL if the list is empty...
Definition: dlist.h:170
#define FIRST_DCODE
Definition: dcode.h:70
int DCodeNumber(char *&Text)
Definition: rs274d.cpp:436
APERTURE_T
Enum APERTURE_T is the set of all gerber aperture types allowed, according to page 16 of http://gerbv...
Definition: dcode.h:49
int m_Num_Dcode
D code value ( >= 10 )
Definition: dcode.h:100
bool ParseAttribCmd(FILE *aFile, char *aBuffer, int aBuffSize, char *&aText)
parse a TF command terminated with a % and fill m_Prms by the parameters found.
bool IsFileFunction()
return true if the attribute is .FileFunction
bool m_Exposure
whether an aperture macro tool is flashed on or off
bool Execute_G_Command(char *&text, int G_command)
Definition: rs274d.cpp:456
Class D_CODE holds a gerber DCODE (also called Aperture) definition.
Definition: dcode.h:81
static LIB_PART * dummy()
Used when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
void fillFlashedGBRITEM(GERBER_DRAW_ITEM *aGbrItem, APERTURE_T aAperture, int Dcode_index, const wxPoint &aPos, wxSize aSize, bool aLayerNegative)
Function fillFlashedGBRITEM initializes a given GBRITEM so that it can draw a circle which is filled ...
Definition: rs274d.cpp:108
DLIST< GERBER_DRAW_ITEM > m_Drawings
GERBER_DRAW_ITEM * GetItemsList()
Function GetItemsList.
GBR_NETLIST_METADATA m_NetAttributeDict
#define TOOLS_MAX_COUNT
Definition: dcode.h:72
void SetLayerPolarity(bool aNegative)
The common library.
static void fillArcGBRITEM(GERBER_DRAW_ITEM *aGbrItem, int Dcode_index, const wxPoint &aStart, const wxPoint &aEnd, const wxPoint &aRelCenter, wxSize aPenSize, bool aClockwise, bool aMultiquadrant, bool aLayerNegative)
Function fillArcGBRITEM initializes a given GBRITEM so that it can draw an arc G code.
Definition: rs274d.cpp:212
void StepAndRepeatItem(const GERBER_DRAW_ITEM &aItem)
Function StepAndRepeatItem Gerber format has a command Step an Repeat This function must be called wh...
GERBER_FILE_IMAGE * m_GerberImageFile
GERBER_LAYER & GetLayerParams()
Function GetLayerParams.