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 (C) 1992-2023 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 = strtod( line.data(), nullptr );
118
119 if( is_float )
120 {
121 current_coord = scaletoIU( val, m_GerbMetric );
122 }
123 else
124 {
125 int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
126
128 {
129 // no trailing zero format, we need to add missing zeros.
130 int digit_count = (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
131
132 // Truncate the extra digits if the len is more than expected
133 // because the conversion to internal units expect exactly
134 // digit_count digits. Alternatively, add some additional digits
135 // to pad out to the missing zeros
136 if( nbdigits < digit_count || ( aExcellonMode && ( nbdigits > digit_count ) ) )
137 decimal_scale = std::pow<double>( 10, digit_count - nbdigits );
138 }
139
140 double real_scale = scale_list[fmt_scale];
141
142 if( m_GerbMetric )
143 real_scale = real_scale / 25.4;
144
145 current_coord = KiROUND( val * real_scale * decimal_scale );
146 }
147
148 if( type_coord == 'X' )
149 {
150 pos.x = current_coord;
151 }
152 else if( type_coord == 'Y' )
153 {
154 pos.y = current_coord;
155 }
156 else if( type_coord == 'A' )
157 {
158 m_ArcRadius = current_coord;
160 }
161 }
162
163 if( m_Relative )
164 pos += m_CurrentPos;
165
166 m_CurrentPos = pos;
167 return pos;
168}
169
170
172{
173 VECTOR2I pos( 0, 0 );
174 bool is_float = false;
175
176 std::string line;
177
178 // Reserve the anticipated length plus an optional sign and decimal
179 line.reserve( std::max( m_FmtLen.x, m_FmtLen.y ) + 3 );
180
181 if( aText == nullptr )
182 return pos;
183
184 while( *aText && ( ( *aText == 'I' ) || ( *aText == 'J' ) ) )
185 {
186 double decimal_scale = 1.0;
187 int nbdigits = 0;
188 int current_coord = 0;
189 char type_coord = *aText++;
190
191 line.clear();
192
193 while( IsNumber( *aText ) )
194 {
195 if( *aText == '.' ) // Force decimal format if reading a floating point number
196 is_float = true;
197
198 // count digits only (sign and decimal point are not counted)
199 if( (*aText >= '0') && (*aText <='9') )
200 nbdigits++;
201
202 line.push_back( *( aText++ ) );
203 }
204
205 double val = strtod( line.data(), nullptr );
206
207 if( is_float )
208 {
209 current_coord = scaletoIU( val, m_GerbMetric );
210 }
211 else
212 {
213 int fmt_scale = ( type_coord == 'I' ) ? m_FmtScale.x : m_FmtScale.y;
214
216 {
217 // no trailing zero format, we need to add missing zeros.
218 int digit_count = ( type_coord == 'I' ) ? m_FmtLen.x : m_FmtLen.y;
219
220 // Truncate the extra digits if the len is more than expected
221 // because the conversion to internal units expect exactly
222 // digit_count digits. Alternatively, add some additional digits
223 // to pad out to the missing zeros
224 if( nbdigits < digit_count )
225 decimal_scale = std::pow<double>( 10, digit_count - nbdigits );
226 }
227
228 double real_scale = scale_list[fmt_scale];
229
230 if( m_GerbMetric )
231 real_scale = real_scale / 25.4;
232
233 current_coord = KiROUND( val * real_scale * decimal_scale );
234 }
235
236 if( type_coord == 'I' )
237 {
238 pos.x = current_coord;
239 }
240 else if( type_coord == 'J' )
241 {
242 pos.y = current_coord;
243 }
244 }
245
246 m_IJPos = pos;
248 m_LastCoordIsIJPos = true;
249
250 return pos;
251}
252
253
254// Helper functions:
255
266int ReadInt( char*& text, bool aSkipSeparator = true )
267{
268 int ret;
269
270 // For strtol, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
271 // However, 'X' is a separator in Gerber strings with numbers.
272 // We need to detect that
273 if( strncasecmp( text, "0X", 2 ) == 0 )
274 {
275 text++;
276 ret = 0;
277 }
278 else
279 {
280 ret = (int) strtol( text, &text, 10 );
281 }
282
283 if( *text == ',' || isspace( *text ) )
284 {
285 if( aSkipSeparator )
286 ++text;
287 }
288
289 return ret;
290}
291
292
303double ReadDouble( char*& text, bool aSkipSeparator = true )
304{
305 double ret;
306
307 // For strtod, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
308 // However, 'X' is a separator in Gerber strings with numbers.
309 // We need to detect that
310 if( strncasecmp( text, "0X", 2 ) == 0 )
311 {
312 text++;
313 ret = 0.0;
314 }
315 else
316 {
317 ret = strtod( text, &text );
318 }
319
320 if( *text == ',' || isspace( *text ) )
321 {
322 if( aSkipSeparator )
323 ++text;
324 }
325
326 return ret;
327}
328
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
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]
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:85