2014-10-21 18:36:45 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2010-2014 Jean-Pierre Charras jp.charras at wanadoo.fr
|
|
|
|
* Copyright (C) 1992-2014 KiCad Developers, see change_log.txt for contributors.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
2010-10-15 18:59:26 +00:00
|
|
|
|
2020-01-07 17:12:59 +00:00
|
|
|
#include <math/util.h> // for KiROUND
|
2010-10-15 18:59:26 +00:00
|
|
|
|
2018-01-29 12:26:58 +00:00
|
|
|
#include <gerber_file_image.h>
|
2012-04-18 07:07:13 +00:00
|
|
|
#include <base_units.h>
|
2010-10-15 18:59:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* These routines read the text string point from Text.
|
2010-12-02 17:26:32 +00:00
|
|
|
* On exit, Text points the beginning of the sequence unread
|
2010-10-15 18:59:26 +00:00
|
|
|
*/
|
2012-04-18 07:07:13 +00:00
|
|
|
|
2021-06-09 19:32:58 +00:00
|
|
|
// conversion scale from gerber file units to Gerbview internal units
|
2012-04-18 07:07:13 +00:00
|
|
|
// depending on the gerber file format
|
|
|
|
// this scale list assumes gerber units are imperial.
|
|
|
|
// for metric gerber units, the imperial to metric conversion is made in read functions
|
2014-07-14 18:59:41 +00:00
|
|
|
#define SCALE_LIST_SIZE 9
|
2014-07-09 16:31:39 +00:00
|
|
|
static double scale_list[SCALE_LIST_SIZE] =
|
2012-04-18 07:07:13 +00:00
|
|
|
{
|
2014-07-09 16:31:39 +00:00
|
|
|
1000.0 * IU_PER_MILS, // x.1 format (certainly useless)
|
|
|
|
100.0 * IU_PER_MILS, // x.2 format (certainly useless)
|
|
|
|
10.0 * IU_PER_MILS, // x.3 format
|
|
|
|
1.0 * IU_PER_MILS, // x.4 format
|
|
|
|
0.1 * IU_PER_MILS, // x.5 format
|
|
|
|
0.01 * IU_PER_MILS, // x.6 format
|
2014-07-14 18:59:41 +00:00
|
|
|
0.001 * IU_PER_MILS, // x.7 format (currently the max allowed precision)
|
|
|
|
0.0001 * IU_PER_MILS, // provided, but not used
|
2014-07-09 16:31:39 +00:00
|
|
|
0.00001 * IU_PER_MILS, // provided, but not used
|
2012-04-18 07:07:13 +00:00
|
|
|
};
|
|
|
|
|
2014-07-09 16:31:39 +00:00
|
|
|
/*
|
2012-04-18 07:07:13 +00:00
|
|
|
* Function scale
|
2014-07-09 16:31:39 +00:00
|
|
|
* converts a coordinate given in floating point to Gerbvies internal units
|
|
|
|
* (currently = 10 nanometers)
|
2012-04-18 07:07:13 +00:00
|
|
|
*/
|
|
|
|
int scaletoIU( double aCoord, bool isMetric )
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2013-05-18 16:56:03 +00:00
|
|
|
if( isMetric ) // gerber are units in mm
|
|
|
|
ret = KiROUND( aCoord * IU_PER_MM );
|
|
|
|
else // gerber are units in inches
|
2014-10-21 18:36:45 +00:00
|
|
|
ret = KiROUND( aCoord * IU_PER_MILS * 1000.0 );
|
2012-04-18 07:07:13 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-07-17 12:28:51 +00:00
|
|
|
wxPoint GERBER_FILE_IMAGE::ReadXYCoord( char*& Text, bool aExcellonMode )
|
2010-10-15 18:59:26 +00:00
|
|
|
{
|
|
|
|
wxPoint pos;
|
|
|
|
int type_coord = 0, current_coord, nbdigits;
|
2017-09-28 22:38:36 +00:00
|
|
|
bool is_float = false;
|
2010-10-15 18:59:26 +00:00
|
|
|
char* text;
|
|
|
|
char line[256];
|
|
|
|
|
|
|
|
|
|
|
|
if( m_Relative )
|
|
|
|
pos.x = pos.y = 0;
|
|
|
|
else
|
|
|
|
pos = m_CurrentPos;
|
|
|
|
|
|
|
|
if( Text == NULL )
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
text = line;
|
|
|
|
while( *Text )
|
|
|
|
{
|
2018-09-22 11:04:20 +00:00
|
|
|
if( (*Text == 'X') || (*Text == 'Y') || (*Text == 'A') )
|
2010-10-15 18:59:26 +00:00
|
|
|
{
|
|
|
|
type_coord = *Text;
|
|
|
|
Text++;
|
|
|
|
text = line;
|
|
|
|
nbdigits = 0;
|
2014-07-09 16:31:39 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
while( IsNumber( *Text ) )
|
|
|
|
{
|
2010-12-02 17:26:32 +00:00
|
|
|
if( *Text == '.' ) // Force decimat format if reading a floating point number
|
2010-10-15 18:59:26 +00:00
|
|
|
is_float = true;
|
|
|
|
|
|
|
|
// count digits only (sign and decimal point are not counted)
|
|
|
|
if( (*Text >= '0') && (*Text <='9') )
|
|
|
|
nbdigits++;
|
|
|
|
*(text++) = *(Text++);
|
|
|
|
}
|
|
|
|
|
|
|
|
*text = 0;
|
2014-07-09 16:31:39 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
if( is_float )
|
|
|
|
{
|
2018-09-22 11:04:20 +00:00
|
|
|
// When X or Y (or A) values are float numbers, they are given in mm or inches
|
2012-04-18 07:07:13 +00:00
|
|
|
if( m_GerbMetric ) // units are mm
|
2012-04-26 21:34:20 +00:00
|
|
|
current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
|
2012-04-18 07:07:13 +00:00
|
|
|
else // units are inches
|
2012-04-26 21:34:20 +00:00
|
|
|
current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
|
2010-10-15 18:59:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
|
2014-07-09 16:31:39 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
if( m_NoTrailingZeros )
|
|
|
|
{
|
2018-07-17 12:28:51 +00:00
|
|
|
// no trailing zero format, we need to add missing zeros.
|
|
|
|
int digit_count = (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
|
|
|
|
|
|
|
|
while( nbdigits < digit_count )
|
2010-10-15 18:59:26 +00:00
|
|
|
{
|
|
|
|
*(text++) = '0';
|
|
|
|
nbdigits++;
|
|
|
|
}
|
|
|
|
|
2018-07-17 12:28:51 +00:00
|
|
|
if( aExcellonMode )
|
|
|
|
{
|
|
|
|
// Truncate the extra digits if the len is more than expected
|
|
|
|
// because the conversion to internal units expect exactly
|
|
|
|
// digit_count digits
|
|
|
|
while( nbdigits > digit_count )
|
|
|
|
{
|
|
|
|
*(text--) = 0;
|
|
|
|
nbdigits--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
*text = 0;
|
|
|
|
}
|
2014-07-09 16:31:39 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
current_coord = atoi( line );
|
2012-04-18 07:07:13 +00:00
|
|
|
double real_scale = scale_list[fmt_scale];
|
2010-10-15 18:59:26 +00:00
|
|
|
|
|
|
|
if( m_GerbMetric )
|
|
|
|
real_scale = real_scale / 25.4;
|
|
|
|
|
// Dick Hollenbeck's KiROUND R&D
// This provides better project control over rounding to int from double
// than wxRound() did. This scheme provides better logging in Debug builds
// and it provides for compile time calculation of constants.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
//-----<KiROUND KIT>------------------------------------------------------------
/**
* KiROUND
* rounds a floating point number to an int using
* "round halfway cases away from zero".
* In Debug build an assert fires if will not fit into an int.
*/
#if defined( DEBUG )
// DEBUG: a macro to capture line and file, then calls this inline
static inline int KiRound( double v, int line, const char* filename )
{
v = v < 0 ? v - 0.5 : v + 0.5;
if( v > INT_MAX + 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v );
}
else if( v < INT_MIN - 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v );
}
return int( v );
}
#define KiROUND( v ) KiRound( v, __LINE__, __FILE__ )
#else
// RELEASE: a macro so compile can pre-compute constants.
#define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 )
#endif
//-----</KiROUND KIT>-----------------------------------------------------------
// Only a macro is compile time calculated, an inline function causes a static constructor
// in a situation like this.
// Therefore the Release build is best done with a MACRO not an inline function.
int Computed = KiROUND( 14.3 * 8 );
int main( int argc, char** argv )
{
for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 )
{
int i = KiROUND( d );
printf( "t: %d %.16g\n", i, d );
}
return 0;
}
2012-04-19 06:55:45 +00:00
|
|
|
current_coord = KiROUND( current_coord * real_scale );
|
2010-10-15 18:59:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( type_coord == 'X' )
|
|
|
|
pos.x = current_coord;
|
|
|
|
else if( type_coord == 'Y' )
|
|
|
|
pos.y = current_coord;
|
2018-09-22 11:04:20 +00:00
|
|
|
else if( type_coord == 'A' )
|
|
|
|
{
|
|
|
|
m_ArcRadius = current_coord;
|
|
|
|
m_LastArcDataType = ARC_INFO_TYPE_RADIUS;
|
|
|
|
}
|
2010-10-15 18:59:26 +00:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( m_Relative )
|
|
|
|
{
|
|
|
|
pos.x += m_CurrentPos.x;
|
|
|
|
pos.y += m_CurrentPos.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_CurrentPos = pos;
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Returns the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
|
Fix source comment/doc typos (follow-up)
Found via `codespell -q 3 -S *.po,./thirdparty -L aactual,acount,aline,alocation,alog,anormal,anumber,aother,apoints,aparent,aray,dout,einstance,modul,ot,overide,serie,te,,tesselate,tesselator,tht`
2021-07-03 22:37:31 +00:00
|
|
|
* These coordinates are relative, so if coordinate is absent, its value
|
2010-10-15 18:59:26 +00:00
|
|
|
* defaults to 0
|
|
|
|
*/
|
2016-05-25 14:48:38 +00:00
|
|
|
wxPoint GERBER_FILE_IMAGE::ReadIJCoord( char*& Text )
|
2010-10-15 18:59:26 +00:00
|
|
|
{
|
|
|
|
wxPoint pos( 0, 0 );
|
|
|
|
|
|
|
|
int type_coord = 0, current_coord, nbdigits;
|
|
|
|
bool is_float = false;
|
|
|
|
char* text;
|
|
|
|
char line[256];
|
|
|
|
|
|
|
|
if( Text == NULL )
|
|
|
|
return pos;
|
|
|
|
|
|
|
|
text = line;
|
|
|
|
while( *Text )
|
|
|
|
{
|
|
|
|
if( (*Text == 'I') || (*Text == 'J') )
|
|
|
|
{
|
|
|
|
type_coord = *Text;
|
|
|
|
Text++;
|
|
|
|
text = line;
|
|
|
|
nbdigits = 0;
|
|
|
|
while( IsNumber( *Text ) )
|
|
|
|
{
|
|
|
|
if( *Text == '.' )
|
|
|
|
is_float = true;
|
|
|
|
|
|
|
|
// count digits only (sign and decimal point are not counted)
|
|
|
|
if( (*Text >= '0') && (*Text <='9') )
|
|
|
|
nbdigits++;
|
2014-07-09 16:31:39 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
*(text++) = *(Text++);
|
|
|
|
}
|
|
|
|
|
|
|
|
*text = 0;
|
|
|
|
if( is_float )
|
|
|
|
{
|
2012-04-18 07:07:13 +00:00
|
|
|
// When X or Y values are float numbers, they are given in mm or inches
|
|
|
|
if( m_GerbMetric ) // units are mm
|
2012-04-26 21:34:20 +00:00
|
|
|
current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
|
2012-04-18 07:07:13 +00:00
|
|
|
else // units are inches
|
2012-04-26 21:34:20 +00:00
|
|
|
current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
|
2010-10-15 18:59:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int fmt_scale =
|
|
|
|
(type_coord == 'I') ? m_FmtScale.x : m_FmtScale.y;
|
2014-07-09 16:31:39 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
if( m_NoTrailingZeros )
|
|
|
|
{
|
|
|
|
int min_digit =
|
|
|
|
(type_coord == 'I') ? m_FmtLen.x : m_FmtLen.y;
|
|
|
|
while( nbdigits < min_digit )
|
|
|
|
{
|
|
|
|
*(text++) = '0';
|
|
|
|
nbdigits++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*text = 0;
|
|
|
|
}
|
2012-04-18 07:07:13 +00:00
|
|
|
|
2014-07-09 16:31:39 +00:00
|
|
|
current_coord = atoi( line );
|
2010-10-15 18:59:26 +00:00
|
|
|
|
2012-04-18 07:07:13 +00:00
|
|
|
double real_scale = scale_list[fmt_scale];
|
2014-07-09 16:31:39 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
if( m_GerbMetric )
|
|
|
|
real_scale = real_scale / 25.4;
|
2014-07-09 16:31:39 +00:00
|
|
|
|
// Dick Hollenbeck's KiROUND R&D
// This provides better project control over rounding to int from double
// than wxRound() did. This scheme provides better logging in Debug builds
// and it provides for compile time calculation of constants.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
//-----<KiROUND KIT>------------------------------------------------------------
/**
* KiROUND
* rounds a floating point number to an int using
* "round halfway cases away from zero".
* In Debug build an assert fires if will not fit into an int.
*/
#if defined( DEBUG )
// DEBUG: a macro to capture line and file, then calls this inline
static inline int KiRound( double v, int line, const char* filename )
{
v = v < 0 ? v - 0.5 : v + 0.5;
if( v > INT_MAX + 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v );
}
else if( v < INT_MIN - 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v );
}
return int( v );
}
#define KiROUND( v ) KiRound( v, __LINE__, __FILE__ )
#else
// RELEASE: a macro so compile can pre-compute constants.
#define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 )
#endif
//-----</KiROUND KIT>-----------------------------------------------------------
// Only a macro is compile time calculated, an inline function causes a static constructor
// in a situation like this.
// Therefore the Release build is best done with a MACRO not an inline function.
int Computed = KiROUND( 14.3 * 8 );
int main( int argc, char** argv )
{
for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 )
{
int i = KiROUND( d );
printf( "t: %d %.16g\n", i, d );
}
return 0;
}
2012-04-19 06:55:45 +00:00
|
|
|
current_coord = KiROUND( current_coord * real_scale );
|
2010-10-15 18:59:26 +00:00
|
|
|
}
|
|
|
|
if( type_coord == 'I' )
|
|
|
|
pos.x = current_coord;
|
|
|
|
else if( type_coord == 'J' )
|
|
|
|
pos.y = current_coord;
|
2014-07-09 16:31:39 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_IJPos = pos;
|
2018-09-22 11:04:20 +00:00
|
|
|
m_LastArcDataType = ARC_INFO_TYPE_CENTER;
|
2018-11-28 17:46:25 +00:00
|
|
|
m_LastCoordIsIJPos = true;
|
2018-09-22 11:04:20 +00:00
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
return pos;
|
|
|
|
}
|
2010-11-30 20:41:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Helper functions:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function ReadInt
|
|
|
|
* reads an int from an ASCII character buffer. If there is a comma after the
|
|
|
|
* int, then skip over that.
|
|
|
|
* @param text A reference to a character pointer from which bytes are read
|
|
|
|
* and the pointer is advanced for each byte read.
|
|
|
|
* @param aSkipSeparator = true (default) to skip comma
|
|
|
|
* @return int - The int read in.
|
|
|
|
*/
|
|
|
|
int ReadInt( char*& text, bool aSkipSeparator = true )
|
|
|
|
{
|
2017-04-08 10:53:40 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
// For strtol, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
|
|
|
|
// However, 'X' is a separator in Gerber strings with numbers.
|
|
|
|
// We need to detect that
|
2017-04-08 12:26:32 +00:00
|
|
|
if( strncasecmp( text, "0X", 2 ) == 0 )
|
2017-04-08 10:53:40 +00:00
|
|
|
{
|
|
|
|
text++;
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = (int) strtol( text, &text, 10 );
|
2010-11-30 20:41:35 +00:00
|
|
|
|
|
|
|
if( *text == ',' || isspace( *text ) )
|
2014-07-09 16:31:39 +00:00
|
|
|
{
|
2010-11-30 20:41:35 +00:00
|
|
|
if( aSkipSeparator )
|
|
|
|
++text;
|
2014-07-09 16:31:39 +00:00
|
|
|
}
|
2010-11-30 20:41:35 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function ReadDouble
|
|
|
|
* reads a double from an ASCII character buffer. If there is a comma after
|
|
|
|
* the double, then skip over that.
|
|
|
|
* @param text A reference to a character pointer from which the ASCII double
|
|
|
|
* is read from and the pointer advanced for each character read.
|
|
|
|
* @param aSkipSeparator = true (default) to skip comma
|
|
|
|
* @return double
|
|
|
|
*/
|
|
|
|
double ReadDouble( char*& text, bool aSkipSeparator = true )
|
|
|
|
{
|
2017-04-08 10:53:40 +00:00
|
|
|
double ret;
|
|
|
|
|
|
|
|
// For strtod, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
|
|
|
|
// However, 'X' is a separator in Gerber strings with numbers.
|
|
|
|
// We need to detect that
|
2017-04-08 12:26:32 +00:00
|
|
|
if( strncasecmp( text, "0X", 2 ) == 0 )
|
2017-04-08 10:53:40 +00:00
|
|
|
{
|
|
|
|
text++;
|
|
|
|
ret = 0.0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ret = strtod( text, &text );
|
2010-11-30 20:41:35 +00:00
|
|
|
|
|
|
|
if( *text == ',' || isspace( *text ) )
|
2014-07-09 16:31:39 +00:00
|
|
|
{
|
2010-11-30 20:41:35 +00:00
|
|
|
if( aSkipSeparator )
|
|
|
|
++text;
|
2014-07-09 16:31:39 +00:00
|
|
|
}
|
2010-11-30 20:41:35 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|