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 bool is_float = false;
79
80 std::string line;
81
82 // Reserve the anticipated length plus an optional sign and decimal
83 line.reserve( std::max( m_FmtLen.x, m_FmtLen.y ) + 3 );
84
85 // Set up return value for case where aText == nullptr
86 if( !m_Relative )
87 pos = m_CurrentPos;
88
89 if( aText == nullptr )
90 return pos;
91
92 while( *aText && ( ( *aText == 'X' ) || ( *aText == 'Y' ) || ( *aText == 'A' ) ) )
93 {
94 double decimal_scale = 1.0;
95 int nbdigits = 0;
96 int current_coord = 0;
97 char type_coord = *aText++;
98
99 line.clear();
100
101 while( IsNumber( *aText ) )
102 {
103 if( *aText == '.' ) // Force decimal format if reading a floating point number
104 is_float = true;
105
106 // count digits only (sign and decimal point are not counted)
107 if( (*aText >= '0') && (*aText <='9') )
108 nbdigits++;
109
110 line.push_back( *( aText++ ) );
111 }
112
113 double val;
114 wxString text( line.data() );
115 text.ToCDouble( &val );
116
117 if( is_float )
118 {
119 current_coord = scaletoIU( val, m_GerbMetric );
120 }
121 else
122 {
123 int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
124
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 // Truncate the extra digits if the len is more than expected
131 // because the conversion to internal units expect exactly
132 // digit_count digits. Alternatively, add some additional digits
133 // to pad out to the missing zeros
134 if( nbdigits < digit_count || ( aExcellonMode && ( nbdigits > digit_count ) ) )
135 decimal_scale = std::pow<double>( 10, digit_count - nbdigits );
136 }
137
138 double real_scale = scale_list[fmt_scale];
139
140 if( m_GerbMetric )
141 real_scale = real_scale / 25.4;
142
143 current_coord = KiROUND( val * real_scale * decimal_scale );
144 }
145
146 if( type_coord == 'X' )
147 {
148 pos.x = current_coord;
149 }
150 else if( type_coord == 'Y' )
151 {
152 pos.y = current_coord;
153 }
154 else if( type_coord == 'A' )
155 {
156 m_ArcRadius = current_coord;
158 }
159 }
160
161 if( m_Relative )
162 pos += m_CurrentPos;
163
164 m_CurrentPos = pos;
165 return pos;
166}
167
168
170{
171 VECTOR2I pos( 0, 0 );
172 bool is_float = false;
173
174 std::string line;
175
176 // Reserve the anticipated length plus an optional sign and decimal
177 line.reserve( std::max( m_FmtLen.x, m_FmtLen.y ) + 3 );
178
179 if( aText == nullptr )
180 return pos;
181
182 while( *aText && ( ( *aText == 'I' ) || ( *aText == 'J' ) ) )
183 {
184 double decimal_scale = 1.0;
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;
204 wxString text( line.data() );
205 text.Trim( true ).Trim( false );
206 text.ToCDouble( &val );
207
208 if( is_float )
209 {
210 current_coord = scaletoIU( val, m_GerbMetric );
211 }
212 else
213 {
214 int fmt_scale = ( type_coord == 'I' ) ? m_FmtScale.x : m_FmtScale.y;
215
217 {
218 // no trailing zero format, we need to add missing zeros.
219 int digit_count = ( type_coord == 'I' ) ? m_FmtLen.x : m_FmtLen.y;
220
221 // Truncate the extra digits if the len is more than expected
222 // because the conversion to internal units expect exactly
223 // digit_count digits. Alternatively, add some additional digits
224 // to pad out to the missing zeros
225 if( nbdigits < digit_count )
226 decimal_scale = std::pow<double>( 10, digit_count - nbdigits );
227 }
228
229 double real_scale = scale_list[fmt_scale];
230
231 if( m_GerbMetric )
232 real_scale = real_scale / 25.4;
233
234 current_coord = KiROUND( val * real_scale * decimal_scale );
235 }
236
237 if( type_coord == 'I' )
238 {
239 pos.x = current_coord;
240 }
241 else if( type_coord == 'J' )
242 {
243 pos.y = current_coord;
244 }
245 }
246
247 m_IJPos = pos;
249 m_LastCoordIsIJPos = true;
250
251 return pos;
252}
253
254
255// Helper functions:
256
267int ReadInt( char*& text, bool aSkipSeparator = true )
268{
269 int ret;
270
271 // For strtol, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
272 // However, 'X' is a separator in Gerber strings with numbers.
273 // We need to detect that
274 if( strncasecmp( text, "0X", 2 ) == 0 )
275 {
276 text++;
277 ret = 0;
278 }
279 else
280 {
281 ret = (int) strtol( text, &text, 10 );
282 }
283
284 if( *text == ',' || isspace( *text ) )
285 {
286 if( aSkipSeparator )
287 ++text;
288 }
289
290 return ret;
291}
292
293
304
305double ReadDouble( char*& text, bool aSkipSeparator = true )
306{
307 double ret;
308
309 // Skip spaces at the beginning of string: they are here not an operand separator
310 while( isspace( *text ) )
311 text++;
312
313 // For strtod, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
314 // However, 'X' is a separator in Gerber strings with numbers.
315 // We need to detect that
316 if( strncasecmp( text, "0X", 2 ) == 0 )
317 {
318 text++;
319 ret = 0.0;
320 }
321 else
322 {
323 wxString line( text );
324
325 // Warning: in locales using ',' as separator, wxString::ToCDouble accept both '.' and ','
326 // as separator (wxWidgets 3.2.6 bug?, look fixed in 3.2.8). So because ',' is used also
327 // to separe 2 operands in Gerber strings, remove the first ',' that is a operand separator,
328 // not a float separator
329 line.Replace( ",", " ", false );
330 line.ToCDouble( &ret );
331 // Find the end of the float number. The float number contains only chars
332 // "0123456789." but can start by a '+' or '-' char.
333 // others chars (usually '+' '-' '$' ',' ) are separators between operands and are not members
334 // of the current float number
335 if( ( line[0] == '+' || line[0] == '-' ) && line.Length() > 1 && line[1] != '$' )
336 {
337 // It is the sign of a number, not an operator. Remove it to find the last digit
338 line[0] = '0';
339 }
340
341 auto endpos = line.find_first_not_of( "0123456789." );
342
343 if( endpos != wxString::npos )
344 {
345 // Advance the text pointer to the end of the number
346 text += endpos;
347 }
348 else
349 {
350 // If no non-number characters found, advance to the end of the string
351 text += line.length();
352 }
353 }
354
355 if( *text == ',' || isspace( *text ) )
356 {
357 if( aSkipSeparator )
358 ++text;
359 }
360
361 return ret;
362}
363
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:986
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]
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683