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-2021 KiCad Developers, see AUTHORS.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 
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 == nullptr )
86  return pos;
87 
88  text = line;
89 
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 decimal 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 
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  {
162  pos.x = current_coord;
163  }
164  else if( type_coord == 'Y' )
165  {
166  pos.y = current_coord;
167  }
168  else if( type_coord == 'A' )
169  {
170  m_ArcRadius = current_coord;
172  }
173 
174  continue;
175  }
176  else
177  {
178  break;
179  }
180  }
181 
182  if( m_Relative )
183  {
184  pos.x += m_CurrentPos.x;
185  pos.y += m_CurrentPos.y;
186  }
187 
188  m_CurrentPos = pos;
189  return pos;
190 }
191 
192 
193 wxPoint GERBER_FILE_IMAGE::ReadIJCoord( char*& Text )
194 {
195  wxPoint pos( 0, 0 );
196 
197  int type_coord = 0, current_coord, nbdigits;
198  bool is_float = false;
199  char* text;
200  char line[256];
201 
202  if( Text == nullptr )
203  return pos;
204 
205  text = line;
206 
207  while( *Text )
208  {
209  if( ( *Text == 'I' ) || ( *Text == 'J' ) )
210  {
211  type_coord = *Text;
212  Text++;
213  text = line;
214  nbdigits = 0;
215 
216  while( IsNumber( *Text ) )
217  {
218  if( *Text == '.' )
219  is_float = true;
220 
221  // count digits only (sign and decimal point are not counted)
222  if( ( *Text >= '0' ) && ( *Text <= '9' ) )
223  nbdigits++;
224 
225  *(text++) = *(Text++);
226  }
227 
228  *text = 0;
229 
230  if( is_float )
231  {
232  // When X or Y values are float numbers, they are given in mm or inches
233  if( m_GerbMetric ) // units are mm
234  current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
235  else // units are inches
236  current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
237  }
238  else
239  {
240  int fmt_scale = ( type_coord == 'I' ) ? m_FmtScale.x : m_FmtScale.y;
241 
242  if( m_NoTrailingZeros )
243  {
244  int min_digit = ( type_coord == 'I' ) ? m_FmtLen.x : m_FmtLen.y;
245 
246  while( nbdigits < min_digit )
247  {
248  *(text++) = '0';
249  nbdigits++;
250  }
251 
252  *text = 0;
253  }
254 
255  current_coord = atoi( line );
256 
257  double real_scale = scale_list[fmt_scale];
258 
259  if( m_GerbMetric )
260  real_scale = real_scale / 25.4;
261 
262  current_coord = KiROUND( current_coord * real_scale );
263  }
264 
265  if( type_coord == 'I' )
266  pos.x = current_coord;
267  else if( type_coord == 'J' )
268  pos.y = current_coord;
269 
270  continue;
271  }
272  else
273  {
274  break;
275  }
276  }
277 
278  m_IJPos = pos;
280  m_LastCoordIsIJPos = true;
281 
282  return pos;
283 }
284 
285 
286 // Helper functions:
287 
298 int ReadInt( char*& text, bool aSkipSeparator = true )
299 {
300  int ret;
301 
302  // For strtol, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
303  // However, 'X' is a separator in Gerber strings with numbers.
304  // We need to detect that
305  if( strncasecmp( text, "0X", 2 ) == 0 )
306  {
307  text++;
308  ret = 0;
309  }
310  else
311  {
312  ret = (int) strtol( text, &text, 10 );
313  }
314 
315  if( *text == ',' || isspace( *text ) )
316  {
317  if( aSkipSeparator )
318  ++text;
319  }
320 
321  return ret;
322 }
323 
324 
335 double ReadDouble( char*& text, bool aSkipSeparator = true )
336 {
337  double ret;
338 
339  // For strtod, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
340  // However, 'X' is a separator in Gerber strings with numbers.
341  // We need to detect that
342  if( strncasecmp( text, "0X", 2 ) == 0 )
343  {
344  text++;
345  ret = 0.0;
346  }
347  else
348  {
349  ret = strtod( text, &text );
350  }
351 
352  if( *text == ',' || isspace( *text ) )
353  {
354  if( aSkipSeparator )
355  ++text;
356  }
357 
358  return ret;
359 }
360 
int scaletoIU(double aCoord, bool isMetric)
Convert a coordinate given in floating point to GerbView's internal units (currently = 10 nanometers)...
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)
Read a double precision floating point number 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)).
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)
Read an integer from an ASCII character buffer.
#define IU_PER_MILS
Definition: plotter.cpp:136
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:73
#define IsNumber(x)