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