KiCad PCB EDA Suite
rs274_read_XY_and_IJ_coordinates.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) 2010-2014 Jean-Pierre Charras jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2014 KiCad Developers, see change_log.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 
25 #include <math/util.h> // for KiROUND
26 
27 #include <gerber_file_image.h>
28 #include <base_units.h>
29 
30 
31 /* These routines read the text string point from Text.
32  * On exit, Text points the beginning of the sequence unread
33  */
34 
35 // conversion scale from gerber file units to Gerbview internal units
36 // depending on the gerber file format
37 // this scale list assumes gerber units are imperial.
38 // for metric gerber units, the imperial to metric conversion is made in read functions
39 #define SCALE_LIST_SIZE 9
40 static double scale_list[SCALE_LIST_SIZE] =
41 {
42  1000.0 * IU_PER_MILS, // x.1 format (certainly useless)
43  100.0 * IU_PER_MILS, // x.2 format (certainly useless)
44  10.0 * IU_PER_MILS, // x.3 format
45  1.0 * IU_PER_MILS, // x.4 format
46  0.1 * IU_PER_MILS, // x.5 format
47  0.01 * IU_PER_MILS, // x.6 format
48  0.001 * IU_PER_MILS, // x.7 format (currently the max allowed precision)
49  0.0001 * IU_PER_MILS, // provided, but not used
50  0.00001 * IU_PER_MILS, // provided, but not used
51 };
52 
53 /*
54  * Function scale
55  * converts a coordinate given in floating point to Gerbvies internal units
56  * (currently = 10 nanometers)
57  */
58 int scaletoIU( double aCoord, bool isMetric )
59 {
60  int ret;
61 
62  if( isMetric ) // gerber are units in mm
63  ret = KiROUND( aCoord * IU_PER_MM );
64  else // gerber are units in inches
65  ret = KiROUND( aCoord * IU_PER_MILS * 1000.0 );
66 
67  return ret;
68 }
69 
70 
71 wxPoint GERBER_FILE_IMAGE::ReadXYCoord( char*& Text, bool aExcellonMode )
72 {
73  wxPoint pos;
74  int type_coord = 0, current_coord, nbdigits;
75  bool is_float = false;
76  char* text;
77  char line[256];
78 
79 
80  if( m_Relative )
81  pos.x = pos.y = 0;
82  else
83  pos = m_CurrentPos;
84 
85  if( Text == NULL )
86  return pos;
87 
88  text = line;
89  while( *Text )
90  {
91  if( (*Text == 'X') || (*Text == 'Y') || (*Text == 'A') )
92  {
93  type_coord = *Text;
94  Text++;
95  text = line;
96  nbdigits = 0;
97 
98  while( IsNumber( *Text ) )
99  {
100  if( *Text == '.' ) // Force decimat format if reading a floating point number
101  is_float = true;
102 
103  // count digits only (sign and decimal point are not counted)
104  if( (*Text >= '0') && (*Text <='9') )
105  nbdigits++;
106  *(text++) = *(Text++);
107  }
108 
109  *text = 0;
110 
111  if( is_float )
112  {
113  // When X or Y (or A) values are float numbers, they are given in mm or inches
114  if( m_GerbMetric ) // units are mm
115  current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
116  else // units are inches
117  current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
118  }
119  else
120  {
121  int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
122 
123  if( m_NoTrailingZeros )
124  {
125  // no trailing zero format, we need to add missing zeros.
126  int digit_count = (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
127 
128  while( nbdigits < digit_count )
129  {
130  *(text++) = '0';
131  nbdigits++;
132  }
133 
134  if( aExcellonMode )
135  {
136  // Truncate the extra digits if the len is more than expected
137  // because the conversion to internal units expect exactly
138  // digit_count digits
139  while( nbdigits > digit_count )
140  {
141  *(text--) = 0;
142  nbdigits--;
143  }
144  }
145 
146  *text = 0;
147  }
148 
149  current_coord = atoi( line );
150  double real_scale = scale_list[fmt_scale];
151 
152  if( m_GerbMetric )
153  real_scale = real_scale / 25.4;
154 
155  current_coord = KiROUND( current_coord * real_scale );
156  }
157 
158  if( type_coord == 'X' )
159  pos.x = current_coord;
160  else if( type_coord == 'Y' )
161  pos.y = current_coord;
162  else if( type_coord == 'A' )
163  {
164  m_ArcRadius = current_coord;
166  }
167 
168  continue;
169  }
170  else
171  break;
172  }
173 
174  if( m_Relative )
175  {
176  pos.x += m_CurrentPos.x;
177  pos.y += m_CurrentPos.y;
178  }
179 
180  m_CurrentPos = pos;
181  return pos;
182 }
183 
184 
185 /* Returns the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
186  * These coordinates are relative, so if coordinate is absent, it's value
187  * defaults to 0
188  */
189 wxPoint GERBER_FILE_IMAGE::ReadIJCoord( char*& Text )
190 {
191  wxPoint pos( 0, 0 );
192 
193  int type_coord = 0, current_coord, nbdigits;
194  bool is_float = false;
195  char* text;
196  char line[256];
197 
198  if( Text == NULL )
199  return pos;
200 
201  text = line;
202  while( *Text )
203  {
204  if( (*Text == 'I') || (*Text == 'J') )
205  {
206  type_coord = *Text;
207  Text++;
208  text = line;
209  nbdigits = 0;
210  while( IsNumber( *Text ) )
211  {
212  if( *Text == '.' )
213  is_float = true;
214 
215  // count digits only (sign and decimal point are not counted)
216  if( (*Text >= '0') && (*Text <='9') )
217  nbdigits++;
218 
219  *(text++) = *(Text++);
220  }
221 
222  *text = 0;
223  if( is_float )
224  {
225  // When X or Y values are float numbers, they are given in mm or inches
226  if( m_GerbMetric ) // units are mm
227  current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
228  else // units are inches
229  current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
230  }
231  else
232  {
233  int fmt_scale =
234  (type_coord == 'I') ? m_FmtScale.x : m_FmtScale.y;
235 
236  if( m_NoTrailingZeros )
237  {
238  int min_digit =
239  (type_coord == 'I') ? m_FmtLen.x : m_FmtLen.y;
240  while( nbdigits < min_digit )
241  {
242  *(text++) = '0';
243  nbdigits++;
244  }
245 
246  *text = 0;
247  }
248 
249  current_coord = atoi( line );
250 
251  double real_scale = scale_list[fmt_scale];
252 
253  if( m_GerbMetric )
254  real_scale = real_scale / 25.4;
255 
256  current_coord = KiROUND( current_coord * real_scale );
257  }
258  if( type_coord == 'I' )
259  pos.x = current_coord;
260  else if( type_coord == 'J' )
261  pos.y = current_coord;
262 
263  continue;
264  }
265  else
266  break;
267  }
268 
269  m_IJPos = pos;
271  m_LastCoordIsIJPos = true;
272 
273  return pos;
274 }
275 
276 
277 // Helper functions:
278 
288 int ReadInt( char*& text, bool aSkipSeparator = true )
289 {
290  int ret;
291 
292  // For strtol, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
293  // However, 'X' is a separator in Gerber strings with numbers.
294  // We need to detect that
295  if( strncasecmp( text, "0X", 2 ) == 0 )
296  {
297  text++;
298  ret = 0;
299  }
300  else
301  ret = (int) strtol( text, &text, 10 );
302 
303  if( *text == ',' || isspace( *text ) )
304  {
305  if( aSkipSeparator )
306  ++text;
307  }
308 
309  return ret;
310 }
311 
312 
322 double ReadDouble( char*& text, bool aSkipSeparator = true )
323 {
324  double ret;
325 
326  // For strtod, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
327  // However, 'X' is a separator in Gerber strings with numbers.
328  // We need to detect that
329  if( strncasecmp( text, "0X", 2 ) == 0 )
330  {
331  text++;
332  ret = 0.0;
333  }
334  else
335  ret = strtod( text, &text );
336 
337  if( *text == ',' || isspace( *text ) )
338  {
339  if( aSkipSeparator )
340  ++text;
341  }
342 
343  return ret;
344 }
345 
int scaletoIU(double aCoord, bool isMetric)
Function scaletoIU converts a distance given in floating point to our internal units.
Implementation of conversion functions that require both schematic and board internal units.
wxPoint ReadIJCoord(char *&Text)
Return the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
static constexpr double IU_PER_MM
Mock up a conversion function.
bool m_LastCoordIsIJPos
< True if a IJ coord was read (for arcs & circles ).
wxSize m_FmtLen
Image rotation (0, 90, 180, 270 only) in degrees.
double ReadDouble(char *&text, bool aSkipSeparator=true)
Function ReadDouble reads a double from an ASCII character buffer.
wxSize m_FmtScale
< Fmt 2.3: m_FmtScale = 3, fmt 3.4: m_FmtScale = 4.
int m_ArcRadius
Identifier for arc data type (IJ (center) or A## (radius)).
#define NULL
static double scale_list[SCALE_LIST_SIZE]
bool m_Relative
< false = absolute Coord, true = relative Coord.
wxPoint ReadXYCoord(char *&aText, bool aExcellonMode=false)
Return the current coordinate type pointed to by XnnYnn Text (XnnnnYmmmm).
LAST_EXTRA_ARC_DATA_TYPE m_LastArcDataType
int ReadInt(char *&text, bool aSkipSeparator=true)
Function ReadInt reads an int from an ASCII character buffer.
#define IU_PER_MILS
Definition: plotter.cpp:137
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:70
#define IsNumber(x)