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 
108  APERTURE_T aAperture,
109  int Dcode_index,
110  const wxPoint& aPos,
111  wxSize aSize,
112  bool aLayerNegative )
113 {
114  aGbrItem->m_Size = aSize;
115  aGbrItem->m_Start = aPos;
116  aGbrItem->m_End = aGbrItem->m_Start;
117  aGbrItem->m_DCode = Dcode_index;
118  aGbrItem->SetLayerPolarity( aLayerNegative );
119  aGbrItem->m_Flashed = true;
120  aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
121 
122  switch( aAperture )
123  {
124  case APT_POLYGON: // flashed regular polygon
125  aGbrItem->m_Shape = GBR_SPOT_POLY;
126  break;
127 
128  case APT_CIRCLE:
129  aGbrItem->m_Shape = GBR_SPOT_CIRCLE;
130  aGbrItem->m_Size.y = aGbrItem->m_Size.x;
131  break;
132 
133  case APT_OVAL:
134  aGbrItem->m_Shape = GBR_SPOT_OVAL;
135  break;
136 
137  case APT_RECT:
138  aGbrItem->m_Shape = GBR_SPOT_RECT;
139  break;
140 
141  case APT_MACRO:
142  aGbrItem->m_Shape = GBR_SPOT_MACRO;
143  break;
144  }
145 }
146 
147 
160  int Dcode_index,
161  const wxPoint& aStart,
162  const wxPoint& aEnd,
163  wxSize aPenSize,
164  bool aLayerNegative )
165 {
166  aGbrItem->m_Flashed = false;
167 
168  aGbrItem->m_Size = aPenSize;
169 
170  aGbrItem->m_Start = aStart;
171  aGbrItem->m_End = aEnd;
172 
173  aGbrItem->m_DCode = Dcode_index;
174  aGbrItem->SetLayerPolarity( aLayerNegative );
175 
176  aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
177 }
178 
179 
208 static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index,
209  const wxPoint& aStart, const wxPoint& aEnd,
210  const wxPoint& aRelCenter, wxSize aPenSize,
211  bool aClockwise, bool aMultiquadrant,
212  bool aLayerNegative )
213 {
214  wxPoint center, delta;
215 
216  aGbrItem->m_Shape = GBR_ARC;
217  aGbrItem->m_Size = aPenSize;
218  aGbrItem->m_Flashed = false;
219 
220  if( aGbrItem->m_GerberImageFile )
221  aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
222 
223  if( aMultiquadrant )
224  center = aStart + aRelCenter;
225  else
226  {
227  // in single quadrant mode the relative coordinate aRelCenter is always >= 0
228  // So we must recalculate the actual sign of aRelCenter.x and aRelCenter.y
229  center = aRelCenter;
230 
231  // calculate arc end coordinate relative to the starting point,
232  // because center is relative to the center point
233  delta = aEnd - aStart;
234 
235  // now calculate the relative to aStart center position, for a draw function
236  // that use trigonometric arc angle (or counter-clockwise)
237  /* Quadrants:
238  * Y
239  * 2 | 1
240  * -------X
241  * 3 | 4
242  * C = actual relative arc center, S = arc start (axis origin) E = relative arc end
243  */
244  if( (delta.x >= 0) && (delta.y >= 0) )
245  {
246  /* Quadrant 1 (trigo or cclockwise):
247  * C | E
248  * ---S---
249  * 3 | 4
250  */
251  center.x = -center.x;
252  }
253  else if( (delta.x >= 0) && (delta.y < 0) )
254  {
255  /* Quadrant 4 (trigo or cclockwise):
256  * 2 | C
257  * ---S---
258  * 3 | E
259  */
260  // Nothing to do
261  }
262  else if( (delta.x < 0) && (delta.y >= 0) )
263  {
264  /* Quadrant 2 (trigo or cclockwise):
265  * E | 1
266  * ---S---
267  * C | 4
268  */
269  center.x = -center.x;
270  center.y = -center.y;
271  }
272  else
273  {
274  /* Quadrant 3 (trigo or cclockwise):
275  * 2 | 1
276  * ---S---
277  * E | C
278  */
279  center.y = -center.y;
280  }
281 
282  // Due to your draw arc function, we need this:
283  if( !aClockwise )
284  center = - center;
285 
286  // Calculate actual arc center coordinate:
287  center += aStart;
288  }
289 
290  if( aClockwise )
291  {
292  aGbrItem->m_Start = aStart;
293  aGbrItem->m_End = aEnd;
294  }
295  else
296  {
297  aGbrItem->m_Start = aEnd;
298  aGbrItem->m_End = aStart;
299  }
300 
301  aGbrItem->m_ArcCentre = center;
302 
303  aGbrItem->m_DCode = Dcode_index;
304  aGbrItem->SetLayerPolarity( aLayerNegative );
305 }
306 
307 
335 static void fillArcPOLY( GERBER_DRAW_ITEM* aGbrItem,
336  const wxPoint& aStart, const wxPoint& aEnd,
337  const wxPoint& rel_center,
338  bool aClockwise, bool aMultiquadrant,
339  bool aLayerNegative )
340 {
341  /* in order to calculate arc parameters, we use fillArcGBRITEM
342  * so we muse create a dummy track and use its geometric parameters
343  */
344  static GERBER_DRAW_ITEM dummyGbrItem( NULL );
345 
346  aGbrItem->SetLayerPolarity( aLayerNegative );
347 
348  fillArcGBRITEM( &dummyGbrItem, 0,
349  aStart, aEnd, rel_center, wxSize(0, 0),
350  aClockwise, aMultiquadrant, aLayerNegative );
351 
352  aGbrItem->SetNetAttributes( aGbrItem->m_GerberImageFile->m_NetAttributeDict );
353 
354  wxPoint center;
355  center = dummyGbrItem.m_ArcCentre;
356 
357  // Calculate coordinates relative to arc center;
358  wxPoint start = dummyGbrItem.m_Start - center;
359  wxPoint end = dummyGbrItem.m_End - center;
360 
361  /* Calculate angle arc
362  * angles are in 0.1 deg
363  * angle is trigonometrical (counter-clockwise),
364  * and axis is the X,Y gerber coordinates
365  */
366  double start_angle = ArcTangente( start.y, start.x );
367  double end_angle = ArcTangente( end.y, end.x );
368 
369  // dummyTrack has right geometric parameters, but
370  // fillArcGBRITEM calculates arc parameters for a draw function that expects
371  // start_angle < end_angle. So ensure this is the case here:
372  // Due to the fact atan2 returns angles between -180 to + 180 degrees,
373  // this is not always the case ( a modulo 360.0 degrees can be lost )
374  if( start_angle > end_angle )
375  end_angle += 3600;
376 
377  double arc_angle = start_angle - end_angle;
378  // Approximate arc by 36 segments per 360 degree
379  const int increment_angle = 3600 / 36;
380  int count = std::abs( arc_angle / increment_angle );
381 
382  // calculate polygon corners
383  // when arc is counter-clockwise, dummyGbrItem arc goes from end to start
384  // and we must always create a polygon from start to end.
385  wxPoint start_arc = start;
386  for( int ii = 0; ii <= count; ii++ )
387  {
388  double rot;
389  wxPoint end_arc = start;
390  if( aClockwise )
391  rot = ii * increment_angle; // rot is in 0.1 deg
392  else
393  rot = (count - ii) * increment_angle; // rot is in 0.1 deg
394 
395  if( ii < count )
396  RotatePoint( &end_arc, -rot );
397  else // last point
398  end_arc = aClockwise ? end : start;
399 
400  aGbrItem->m_PolyCorners.push_back( end_arc + center );
401 
402  start_arc = end_arc;
403  }
404 }
405 
406 
407 /* Read the Gnn sequence and returns the value nn.
408  */
410 {
411  int ii = 0;
412  char* text;
413  char line[1024];
414 
415  if( Text == NULL )
416  return 0;
417  Text++;
418  text = line;
419  while( IsNumber( *Text ) )
420  {
421  *(text++) = *(Text++);
422  }
423 
424  *text = 0;
425  ii = atoi( line );
426  return ii;
427 }
428 
429 
430 /* Get the sequence Dnn and returns the value nn
431  */
433 {
434  int ii = 0;
435  char* text;
436  char line[1024];
437 
438  if( Text == NULL )
439  return 0;
440 
441  Text++;
442  text = line;
443  while( IsNumber( *Text ) )
444  *(text++) = *(Text++);
445 
446  *text = 0;
447  ii = atoi( line );
448  return ii;
449 }
450 
451 
452 bool GERBER_FILE_IMAGE::Execute_G_Command( char*& text, int G_command )
453 {
454 // D( printf( "%22s: G_CODE<%d>\n", __func__, G_command ); )
455 
456  switch( G_command )
457  {
458  case GC_PHOTO_MODE: // can starts a D03 flash command: redundant, can
459  // be safely ignored
460  break;
461 
464  break;
465 
468  break;
469 
472  break;
473 
474  case GC_COMMENT:
475  // Skip comment, but only if the line does not start by "G04 #@! TF"
476  // which is a metadata
477  if( strncmp( text, " #@! TF", 7 ) == 0 )
478  {
479  text += 7;
481  dummy.ParseAttribCmd( m_Current_File, NULL, 0, text );
482  if( dummy.IsFileFunction() )
483  {
484  delete m_FileFunction;
486  }
487  }
488 
489  while ( *text && (*text != '*') )
490  text++;
491  break;
492 
495  break;
496 
499  break;
500 
503  break;
504 
505  case GC_SELECT_TOOL:
506  {
507  int D_commande = DCodeNumber( text );
508  if( D_commande < FIRST_DCODE )
509  return false;
510  if( D_commande > (TOOLS_MAX_COUNT - 1) )
511  D_commande = TOOLS_MAX_COUNT - 1;
512  m_Current_Tool = D_commande;
513  D_CODE* pt_Dcode = GetDCODE( D_commande, false );
514  if( pt_Dcode )
515  pt_Dcode->m_InUse = true;
516  break;
517  }
518 
519  case GC_SPECIFY_INCHES:
520  m_GerbMetric = false; // false = Inches, true = metric
521  break;
522 
524  m_GerbMetric = true; // false = Inches, true = metric
525  break;
526 
527  case GC_TURN_OFF_360_INTERPOL: // disable Multi cadran arc and Arc interpol
528  m_360Arc_enbl = false;
529  m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // not sure it should be done
530  break;
531 
533  m_360Arc_enbl = true;
534  break;
535 
537  m_Relative = false; // false = absolute Coord, true = relative
538  // Coord
539  break;
540 
542  m_Relative = true; // false = absolute Coord, true = relative
543  // Coord
544  break;
545 
547  m_PolygonFillMode = true;
548  m_Exposure = false;
549  break;
550 
552  if( m_Exposure && GetItemsList() ) // End of polygon
553  {
554  GERBER_DRAW_ITEM * gbritem = m_Drawings.GetLast();
555  StepAndRepeatItem( *gbritem );
556  }
557  m_Exposure = false;
558  m_PolygonFillMode = false;
560  break;
561 
562  case GC_MOVE: // Non existent
563  default:
564  {
565  wxString msg;
566  msg.Printf( wxT( "G%0.2d command not handled" ), G_command );
567  AddMessageToList( msg );
568  return false;
569  }
570  }
571 
572 
573  return true;
574 }
575 
576 
577 bool GERBER_FILE_IMAGE::Execute_DCODE_Command( char*& text, int D_commande )
578 {
579  wxSize size( 15, 15 );
580 
581  APERTURE_T aperture = APT_CIRCLE;
582  GERBER_DRAW_ITEM* gbritem;
583 
584  int dcode = 0;
585  D_CODE* tool = NULL;
586  wxString msg;
587 
588  if( D_commande >= FIRST_DCODE ) // This is a "Set tool" command
589  {
590  if( D_commande > (TOOLS_MAX_COUNT - 1) )
591  D_commande = TOOLS_MAX_COUNT - 1;
592 
593  // remember which tool is selected, nothing is done with it in this
594  // call
595  m_Current_Tool = D_commande;
596 
597  D_CODE* pt_Dcode = GetDCODE( D_commande, false );
598  if( pt_Dcode )
599  pt_Dcode->m_InUse = true;
600 
601  return true;
602  }
603  else // D_commande = 0..9: this is a pen command (usually D1, D2 or D3)
604  {
605  m_Last_Pen_Command = D_commande;
606  }
607 
608  if( m_PolygonFillMode ) // Enter a polygon description:
609  {
610  switch( D_commande )
611  {
612  case 1: // code D01 Draw line, exposure ON
613  if( !m_Exposure ) // Start a new polygon outline:
614  {
615  m_Exposure = true;
616  gbritem = new GERBER_DRAW_ITEM( this );
617  m_Drawings.Append( gbritem );
618  gbritem->m_Shape = GBR_POLYGON;
619  gbritem->m_Flashed = false;
620  }
621 
622  switch( m_Iterpolation )
623  {
626  gbritem = m_Drawings.GetLast();
627 
628  fillArcPOLY( gbritem, m_PreviousPos,
630  ( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ? false : true,
631  m_360Arc_enbl, GetLayerParams().m_LayerNegative );
632  break;
633 
634  default:
635  gbritem = m_Drawings.GetLast();
636 
637  gbritem->m_Start = m_PreviousPos; // m_Start is used as temporary storage
638  if( gbritem->m_PolyCorners.size() == 0 )
639  gbritem->m_PolyCorners.push_back( gbritem->m_Start );
640 
641  gbritem->m_End = m_CurrentPos; // m_End is used as temporary storage
642  gbritem->m_PolyCorners.push_back( gbritem->m_End );
643  break;
644  }
645 
648  break;
649 
650  case 2: // code D2: exposure OFF (i.e. "move to")
651  if( m_Exposure && GetItemsList() ) // End of polygon
652  {
653  gbritem = m_Drawings.GetLast();
654  StepAndRepeatItem( *gbritem );
655  }
656  m_Exposure = false;
659  break;
660 
661  default:
662  return false;
663  }
664  }
665  else
666  {
667  switch( D_commande )
668  {
669  case 1: // code D01 Draw line, exposure ON
670  m_Exposure = true;
671 
672  tool = GetDCODE( m_Current_Tool, false );
673  if( tool )
674  {
675  size = tool->m_Size;
676  dcode = tool->m_Num_Dcode;
677  aperture = tool->m_Shape;
678  }
679 
680  switch( m_Iterpolation )
681  {
683  gbritem = new GERBER_DRAW_ITEM( this );
684  m_Drawings.Append( gbritem );
685 
686  fillLineGBRITEM( gbritem, dcode, m_PreviousPos,
687  m_CurrentPos, size, GetLayerParams().m_LayerNegative );
688  StepAndRepeatItem( *gbritem );
689  break;
690 
694  wxBell();
695  break;
696 
699  gbritem = new GERBER_DRAW_ITEM( this );
700  m_Drawings.Append( gbritem );
701 
702  fillArcGBRITEM( gbritem, dcode, m_PreviousPos,
703  m_CurrentPos, m_IJPos, size,
705  false : true, m_360Arc_enbl, GetLayerParams().m_LayerNegative );
706  StepAndRepeatItem( *gbritem );
707  break;
708 
709  default:
710  msg.Printf( wxT( "RS274D: DCODE Command: interpol error (type %X)" ),
711  m_Iterpolation );
712  AddMessageToList( msg );
713  break;
714  }
715 
717  break;
718 
719  case 2: // code D2: exposure OFF (i.e. "move to")
720  m_Exposure = false;
722  break;
723 
724  case 3: // code D3: flash aperture
725  tool = GetDCODE( m_Current_Tool, false );
726  if( tool )
727  {
728  size = tool->m_Size;
729  dcode = tool->m_Num_Dcode;
730  aperture = tool->m_Shape;
731  }
732 
733  gbritem = new GERBER_DRAW_ITEM( this );
734  m_Drawings.Append( gbritem );
735  fillFlashedGBRITEM( gbritem, aperture, dcode, m_CurrentPos,
736  size, GetLayerParams().m_LayerNegative );
737  StepAndRepeatItem( *gbritem );
739  break;
740 
741  default:
742  return false;
743  }
744  }
745 
746  return true;
747 }
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:577
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:335
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:159
#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:409
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:432
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:452
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:107
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:208
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.