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, 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
41{
42 1000.0 * GERB_IU_PER_MM * 0.0254, // x.1 format (certainly useless)
43 100.0 * GERB_IU_PER_MM * 0.0254, // x.2 format (certainly useless)
44 10.0 * GERB_IU_PER_MM * 0.0254, // x.3 format
45 1.0 * GERB_IU_PER_MM * 0.0254, // x.4 format
46 0.1 * GERB_IU_PER_MM * 0.0254, // x.5 format
47 0.01 * GERB_IU_PER_MM * 0.0254, // x.6 format
48 0.001 * GERB_IU_PER_MM * 0.0254, // x.7 format (currently the max allowed precision)
49 0.0001 * GERB_IU_PER_MM * 0.0254, // provided, but not used
50 0.00001 * GERB_IU_PER_MM * 0.0254, // provided, but not used
51};
52
53
58int scaletoIU( double aCoord, bool isMetric )
59{
60 int ret;
61
62 if( isMetric ) // gerber are units in mm
63 ret = KiROUND( aCoord * GERB_IU_PER_MM );
64 else // gerber are units in inches
65 ret = KiROUND( aCoord * GERB_IU_PER_MM * 25.4 );
66
67 return ret;
68}
69
70
71// An useful function used when reading gerber files
72static bool IsNumber( char x )
73{
74 return ( ( x >= '0' ) && ( x <='9' ) )
75 || ( x == '-' ) || ( x == '+' ) || ( x == '.' );
76}
77
78
79VECTOR2I GERBER_FILE_IMAGE::ReadXYCoord( char*& aText, bool aExcellonMode )
80{
81 VECTOR2I pos( 0, 0 );
82 bool is_float = false;
83
84 std::string line;
85
86 // Reserve the anticipated length plus an optional sign and decimal
87 line.reserve( std::max( m_FmtLen.x, m_FmtLen.y ) + 3 );
88
89 // Set up return value for case where aText == nullptr
90 if( !m_Relative )
91 pos = m_CurrentPos;
92
93 if( aText == nullptr )
94 return pos;
95
96 while( *aText && ( ( *aText == 'X' ) || ( *aText == 'Y' ) || ( *aText == 'A' ) ) )
97 {
98 double decimal_scale = 1.0;
99 int nbdigits = 0;
100 int current_coord = 0;
101 char type_coord = *aText++;
102
103 line.clear();
104
105 while( IsNumber( *aText ) )
106 {
107 if( *aText == '.' ) // Force decimal format if reading a floating point number
108 is_float = true;
109
110 // count digits only (sign and decimal point are not counted)
111 if( (*aText >= '0') && (*aText <='9') )
112 nbdigits++;
113
114 line.push_back( *( aText++ ) );
115 }
116
117 double val;
118 wxString text( line.data() );
119 text.ToCDouble( &val );
120
121 if( is_float )
122 {
123 current_coord = scaletoIU( val, m_GerbMetric );
124 }
125 else
126 {
127 int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
128
130 {
131 // no trailing zero format, we need to add missing zeros.
132 int digit_count = (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
133
134 // Truncate the extra digits if the len is more than expected
135 // because the conversion to internal units expect exactly
136 // digit_count digits. Alternatively, add some additional digits
137 // to pad out to the missing zeros
138 if( nbdigits < digit_count || ( aExcellonMode && ( nbdigits > digit_count ) ) )
139 decimal_scale = std::pow<double>( 10, digit_count - nbdigits );
140 }
141
142 double real_scale = scale_list[fmt_scale];
143
144 if( m_GerbMetric )
145 real_scale = real_scale / 25.4;
146
147 current_coord = KiROUND( val * real_scale * decimal_scale );
148 }
149
150 if( type_coord == 'X' )
151 {
152 pos.x = current_coord;
153 }
154 else if( type_coord == 'Y' )
155 {
156 pos.y = current_coord;
157 }
158 else if( type_coord == 'A' )
159 {
160 m_ArcRadius = current_coord;
162 }
163 }
164
165 if( m_Relative )
166 pos += m_CurrentPos;
167
168 m_CurrentPos = pos;
169 return pos;
170}
171
172
174{
175 VECTOR2I pos( 0, 0 );
176 bool is_float = false;
177
178 std::string line;
179
180 // Reserve the anticipated length plus an optional sign and decimal
181 line.reserve( std::max( m_FmtLen.x, m_FmtLen.y ) + 3 );
182
183 if( aText == nullptr )
184 return pos;
185
186 while( *aText && ( ( *aText == 'I' ) || ( *aText == 'J' ) ) )
187 {
188 double decimal_scale = 1.0;
189 int nbdigits = 0;
190 int current_coord = 0;
191 char type_coord = *aText++;
192
193 line.clear();
194
195 while( IsNumber( *aText ) )
196 {
197 if( *aText == '.' ) // Force decimal format if reading a floating point number
198 is_float = true;
199
200 // count digits only (sign and decimal point are not counted)
201 if( (*aText >= '0') && (*aText <='9') )
202 nbdigits++;
203
204 line.push_back( *( aText++ ) );
205 }
206
207 double val;
208 wxString text( line.data() );
209 text.Trim( true ).Trim( false );
210 text.ToCDouble( &val );
211
212 if( is_float )
213 {
214 current_coord = scaletoIU( val, m_GerbMetric );
215 }
216 else
217 {
218 int fmt_scale = ( type_coord == 'I' ) ? m_FmtScale.x : m_FmtScale.y;
219
221 {
222 // no trailing zero format, we need to add missing zeros.
223 int digit_count = ( type_coord == 'I' ) ? m_FmtLen.x : m_FmtLen.y;
224
225 // Truncate the extra digits if the len is more than expected
226 // because the conversion to internal units expect exactly
227 // digit_count digits. Alternatively, add some additional digits
228 // to pad out to the missing zeros
229 if( nbdigits < digit_count )
230 decimal_scale = std::pow<double>( 10, digit_count - nbdigits );
231 }
232
233 double real_scale = scale_list[fmt_scale];
234
235 if( m_GerbMetric )
236 real_scale = real_scale / 25.4;
237
238 current_coord = KiROUND( val * real_scale * decimal_scale );
239 }
240
241 if( type_coord == 'I' )
242 {
243 pos.x = current_coord;
244 }
245 else if( type_coord == 'J' )
246 {
247 pos.y = current_coord;
248 }
249 }
250
251 m_IJPos = pos;
253 m_LastCoordIsIJPos = true;
254
255 return pos;
256}
257
258
259// Helper functions:
260
271int ReadInt( char*& text, bool aSkipSeparator = true )
272{
273 int ret;
274
275 // For strtol, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
276 // However, 'X' is a separator in Gerber strings with numbers.
277 // We need to detect that
278 if( strncasecmp( text, "0X", 2 ) == 0 )
279 {
280 text++;
281 ret = 0;
282 }
283 else
284 {
285 ret = (int) strtol( text, &text, 10 );
286 }
287
288 if( *text == ',' || isspace( *text ) )
289 {
290 if( aSkipSeparator )
291 ++text;
292 }
293
294 return ret;
295}
296
297
308double ReadDouble( char*& text, bool aSkipSeparator = true )
309{
310 double ret;
311
312 // For strtod, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
313 // However, 'X' is a separator in Gerber strings with numbers.
314 // We need to detect that
315 if( strncasecmp( text, "0X", 2 ) == 0 )
316 {
317 text++;
318 ret = 0.0;
319 }
320 else
321 {
322 wxString line( text );
323 auto endpos = line.find_first_not_of( "0123456789.-+eE" );
324 line.Trim( false );
325 line.ToCDouble( &ret );
326
327 if( endpos != wxString::npos )
328 {
329 // Advance the text pointer to the end of the number
330 text += endpos;
331 }
332 else
333 {
334 // If no non-number characters found, advance to the end of the string
335 text += line.length();
336 }
337 }
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)
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:69
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
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
Identifier for arc data type (IJ (center) or A## (radius)).
LAST_EXTRA_ARC_DATA_TYPE m_LastArcDataType
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
A value ( = radius in circular routing in Excellon files ).
@ 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]