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