KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <math/util.h> // for KiROUND
22
23#include <gerber_file_image.h>
24#include <base_units.h>
25
26
27/* These routines read the text string point from Text.
28 * On exit, Text points the beginning of the sequence unread
29 */
30
31// conversion scale from gerber file units to Gerbview internal units
32// depending on the gerber file format
33// this scale list assumes gerber units are imperial.
34// for metric gerber units, the imperial to metric conversion is made in read functions
35#define SCALE_LIST_SIZE 9
37{
38 1000.0 * GERB_IU_PER_MM * 0.0254, // x.1 format (certainly useless)
39 100.0 * GERB_IU_PER_MM * 0.0254, // x.2 format (certainly useless)
40 10.0 * GERB_IU_PER_MM * 0.0254, // x.3 format
41 1.0 * GERB_IU_PER_MM * 0.0254, // x.4 format
42 0.1 * GERB_IU_PER_MM * 0.0254, // x.5 format
43 0.01 * GERB_IU_PER_MM * 0.0254, // x.6 format
44 0.001 * GERB_IU_PER_MM * 0.0254, // x.7 format (currently the max allowed precision)
45 0.0001 * GERB_IU_PER_MM * 0.0254, // provided, but not used
46 0.00001 * GERB_IU_PER_MM * 0.0254, // provided, but not used
47};
48
49
54int scaletoIU( double aCoord, bool isMetric )
55{
56 int ret;
57
58 if( isMetric ) // gerber are units in mm
59 ret = KiROUND( aCoord * GERB_IU_PER_MM );
60 else // gerber are units in inches
61 ret = KiROUND( aCoord * GERB_IU_PER_MM * 25.4 );
62
63 return ret;
64}
65
66
67// An useful function used when reading gerber files
68static bool IsNumber( char x )
69{
70 return ( ( x >= '0' ) && ( x <='9' ) )
71 || ( x == '-' ) || ( x == '+' ) || ( x == '.' );
72}
73
74
75VECTOR2I GERBER_FILE_IMAGE::ReadXYCoord( char*& aText, bool aExcellonMode )
76{
77 VECTOR2I pos( 0, 0 );
78 std::string line;
79
80 // Reserve the anticipated length plus an optional sign and decimal
81 line.reserve( std::max( m_FmtLen.x, m_FmtLen.y ) + 3 );
82
83 // Set up return value for case where aText == nullptr
84 if( !m_Relative )
85 pos = m_CurrentPos;
86
87 if( aText == nullptr )
88 return pos;
89
90 while( *aText && ( ( *aText == 'X' ) || ( *aText == 'Y' ) || ( *aText == 'A' ) ) )
91 {
92 double decimal_scale = 1.0;
93 bool is_float = false;
94 int nbdigits = 0;
95 int current_coord = 0;
96 char type_coord = *aText++;
97
98 line.clear();
99
100 while( IsNumber( *aText ) )
101 {
102 if( *aText == '.' ) // Force decimal 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( (*aText >= '0') && (*aText <='9') )
107 nbdigits++;
108
109 line.push_back( *( aText++ ) );
110 }
111
112 double val = 0.0;
113 wxString text( line.data() );
114
115 if( !text.ToCDouble( &val ) )
116 continue;
117
118 if( is_float )
119 {
120 current_coord = scaletoIU( val, m_GerbMetric );
121 }
122 else
123 {
124 int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
125
127 {
128 // no trailing zero format, we need to add missing zeros.
129 int digit_count = (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
130
131 // Truncate the extra digits if the len is more than expected
132 // because the conversion to internal units expect exactly
133 // digit_count digits. Alternatively, add some additional digits
134 // to pad out to the missing zeros
135 if( nbdigits < digit_count || ( aExcellonMode && ( nbdigits > digit_count ) ) )
136 decimal_scale = std::pow<double>( 10, digit_count - nbdigits );
137 }
138
139 double real_scale = scale_list[fmt_scale];
140
141 if( m_GerbMetric )
142 real_scale = real_scale / 25.4;
143
144 current_coord = KiROUND( val * real_scale * decimal_scale );
145 }
146
147 if( type_coord == 'X' )
148 {
149 pos.x = current_coord;
150 }
151 else if( type_coord == 'Y' )
152 {
153 pos.y = current_coord;
154 }
155 else if( type_coord == 'A' )
156 {
157 m_ArcRadius = current_coord;
159 }
160 }
161
162 if( m_Relative )
163 pos += m_CurrentPos;
164
165 m_CurrentPos = pos;
166 return pos;
167}
168
169
171{
172 VECTOR2I pos( 0, 0 );
173 std::string line;
174
175 // Reserve the anticipated length plus an optional sign and decimal
176 line.reserve( std::max( m_FmtLen.x, m_FmtLen.y ) + 3 );
177
178 if( aText == nullptr )
179 return pos;
180
181 while( *aText && ( ( *aText == 'I' ) || ( *aText == 'J' ) ) )
182 {
183 double decimal_scale = 1.0;
184 bool is_float = false;
185 int nbdigits = 0;
186 int current_coord = 0;
187 char type_coord = *aText++;
188
189 line.clear();
190
191 while( IsNumber( *aText ) )
192 {
193 if( *aText == '.' ) // Force decimal format if reading a floating point number
194 is_float = true;
195
196 // count digits only (sign and decimal point are not counted)
197 if( (*aText >= '0') && (*aText <='9') )
198 nbdigits++;
199
200 line.push_back( *( aText++ ) );
201 }
202
203 double val = 0.0;
204 wxString text( line.data() );
205 text.Trim( true ).Trim( false );
206
207 if( !text.ToCDouble( &val ) )
208 continue;
209
210 if( is_float )
211 {
212 current_coord = scaletoIU( val, m_GerbMetric );
213 }
214 else
215 {
216 int fmt_scale = ( type_coord == 'I' ) ? m_FmtScale.x : m_FmtScale.y;
217
219 {
220 // no trailing zero format, we need to add missing zeros.
221 int digit_count = ( type_coord == 'I' ) ? m_FmtLen.x : m_FmtLen.y;
222
223 // Truncate the extra digits if the len is more than expected
224 // because the conversion to internal units expect exactly
225 // digit_count digits. Alternatively, add some additional digits
226 // to pad out to the missing zeros
227 if( nbdigits < digit_count )
228 decimal_scale = std::pow<double>( 10, digit_count - nbdigits );
229 }
230
231 double real_scale = scale_list[fmt_scale];
232
233 if( m_GerbMetric )
234 real_scale = real_scale / 25.4;
235
236 current_coord = KiROUND( val * real_scale * decimal_scale );
237 }
238
239 if( type_coord == 'I' )
240 {
241 pos.x = current_coord;
242 }
243 else if( type_coord == 'J' )
244 {
245 pos.y = current_coord;
246 }
247 }
248
249 m_IJPos = pos;
251 m_LastCoordIsIJPos = true;
252
253 return pos;
254}
255
256
257// Helper functions:
258
269int ReadInt( char*& text, bool aSkipSeparator = true )
270{
271 int ret;
272
273 // For strtol, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
274 // However, 'X' is a separator in Gerber strings with numbers.
275 // We need to detect that
276 if( strncasecmp( text, "0X", 2 ) == 0 )
277 {
278 text++;
279 ret = 0;
280 }
281 else
282 {
283 ret = (int) strtol( text, &text, 10 );
284 }
285
286 if( *text == ',' || isspace( *text ) )
287 {
288 if( aSkipSeparator )
289 ++text;
290 }
291
292 return ret;
293}
294
295
306
307double ReadDouble( char*& text, bool aSkipSeparator = true )
308{
309 double ret = 0.0;
310
311 // Skip spaces at the beginning of string: they are here not an operand separator
312 while( isspace( *text ) )
313 text++;
314
315 // For strtod, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
316 // However, 'X' is a separator in Gerber strings with numbers.
317 // We need to detect that
318 if( strncasecmp( text, "0X", 2 ) == 0 )
319 {
320 text++;
321 ret = 0.0;
322 }
323 else
324 {
325 wxString line( text );
326
327 // Warning: in locales using ',' as separator, wxString::ToCDouble accept both '.' and ','
328 // as separator (wxWidgets 3.2.6 bug?, look fixed in 3.2.8). So because ',' is used also
329 // to separe 2 operands in Gerber strings, remove the first ',' that is a operand separator,
330 // not a float separator
331 line.Replace( ",", " ", false );
332 line.ToCDouble( &ret );
333 // Find the end of the float number. The float number contains only chars
334 // "0123456789." but can start by a '+' or '-' char.
335 // others chars (usually '+' '-' '$' ',' ) are separators between operands and are not members
336 // of the current float number
337 if( line.Length() > 1 && ( line[0] == '+' || line[0] == '-' ) && line[1] != '$' )
338 {
339 // It is the sign of a number, not an operator. Remove it to find the last digit
340 line[0] = '0';
341 }
342
343 auto endpos = line.find_first_not_of( "0123456789." );
344
345 if( endpos != wxString::npos )
346 {
347 // Advance the text pointer to the end of the number
348 text += endpos;
349 }
350 else
351 {
352 // If no non-number characters found, advance to the end of the string
353 text += line.length();
354 }
355 }
356
357 if( *text == ',' || isspace( *text ) )
358 {
359 if( aSkipSeparator )
360 ++text;
361 }
362
363 return ret;
364}
int scaletoIU(double aCoord, bool isMetric)
Convert a distance given in floating point to our internal units.
constexpr double GERB_IU_PER_MM
some macros and functions to convert a value in mils, decimils or mm to the internal unit used in pcb...
Definition base_units.h:67
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
VECTOR2I ReadIJCoord(char *&Text)
Return the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
wxSize m_FmtScale
Fmt 2.3: m_FmtScale = 3, fmt 3.4: m_FmtScale = 4.
int m_ArcRadius
A value ( = radius in circular routing in Excellon files ).
LAST_EXTRA_ARC_DATA_TYPE m_LastArcDataType
Identifier for arc data type (IJ (center) or A## (radius)).
VECTOR2I m_IJPos
IJ coord (for arcs & circles )
bool m_Relative
false = absolute Coord, true = relative Coord.
VECTOR2I ReadXYCoord(char *&aText, bool aExcellonMode=false)
Return the current coordinate type pointed to by XnnYnn Text (XnnnnYmmmm).
wxSize m_FmtLen
Nb chars per coord. ex fmt 2.3, m_FmtLen = 5.
bool m_GerbMetric
false = Inches, true = metric
bool m_NoTrailingZeros
true: remove tailing zeros.
VECTOR2I m_CurrentPos
current specified coord for plot
bool m_LastCoordIsIJPos
True if a IJ coord was read (for arcs & circles ).
@ ARC_INFO_TYPE_RADIUS
@ ARC_INFO_TYPE_CENTER
int scaletoIU(double aCoord, bool isMetric)
Convert a coordinate given in floating point to GerbView's internal units (currently = 10 nanometers)...
int ReadInt(char *&text, bool aSkipSeparator=true)
Read an integer from an ASCII character buffer.
static bool IsNumber(char x)
double ReadDouble(char *&text, bool aSkipSeparator=true)
Read a double precision floating point number from an ASCII character buffer.
static double scale_list[SCALE_LIST_SIZE]
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708