2014-10-21 18:36:45 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2016-05-25 14:48:38 +00:00
|
|
|
* Copyright (C) 2007-2016 Jean-Pierre Charras jp.charras at wanadoo.fr
|
2016-08-08 17:21:27 +00:00
|
|
|
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
2014-10-21 18:36:45 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2011-09-23 13:57:12 +00:00
|
|
|
/**
|
|
|
|
* @file rs274x.cpp
|
|
|
|
*/
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <fctsys.h>
|
|
|
|
#include <common.h>
|
|
|
|
#include <macros.h>
|
2012-04-18 07:07:13 +00:00
|
|
|
#include <base_units.h>
|
2010-10-09 11:03:03 +00:00
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <gerbview.h>
|
2016-05-25 14:48:38 +00:00
|
|
|
#include <class_gerber_file_image.h>
|
2014-11-22 11:52:57 +00:00
|
|
|
#include <class_X2_gerber_attributes.h>
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2010-11-30 20:41:35 +00:00
|
|
|
extern int ReadInt( char*& text, bool aSkipSeparator = true );
|
|
|
|
extern double ReadDouble( char*& text, bool aSkipSeparator = true );
|
2016-05-25 09:45:55 +00:00
|
|
|
extern bool GetEndOfBlock( char* buff, char*& text, FILE* gerber_file );
|
2010-11-30 20:41:35 +00:00
|
|
|
|
2009-04-29 17:09:00 +00:00
|
|
|
|
2010-11-30 20:41:35 +00:00
|
|
|
#define CODE( x, y ) ( ( (x) << 8 ) + (y) )
|
2010-10-17 12:32:35 +00:00
|
|
|
|
2010-10-09 11:03:03 +00:00
|
|
|
// See rs274xrevd_e.pdf, table 1: RS-274X parameters order of entry
|
|
|
|
// in gerber files, when a coordinate is given (like X78Y600 or I0J80):
|
|
|
|
// Y and Y are logical coordinates
|
|
|
|
// A and B are plotter coordiantes
|
|
|
|
// Usually A = X, B = Y
|
|
|
|
// But we can have A = Y, B = X and/or offset, mirror, scale;
|
|
|
|
// Also:
|
|
|
|
// Image is what you must plot (the entire data of the file).
|
2011-09-23 13:57:12 +00:00
|
|
|
// Layer is just a set of data blocks with their parameters. An image can have more than one
|
2011-09-30 18:15:37 +00:00
|
|
|
// layer so a gerber layer is not like a board layer or the graphic layers used in GerbView
|
2011-09-23 13:57:12 +00:00
|
|
|
// to show a file.
|
2009-04-29 17:09:00 +00:00
|
|
|
enum RS274X_PARAMETERS {
|
2010-10-09 11:03:03 +00:00
|
|
|
// Directive parameters: single usage recommended
|
2010-10-09 20:05:03 +00:00
|
|
|
// Must be at the beginning of the file
|
2010-10-09 11:03:03 +00:00
|
|
|
AXIS_SELECT = CODE( 'A', 'S' ), // Default: A=X, B=Y
|
|
|
|
FORMAT_STATEMENT = CODE( 'F', 'S' ), // no default: this command must exists
|
|
|
|
MIRROR_IMAGE = CODE( 'M', 'I' ), // Default: mo mirror
|
|
|
|
MODE_OF_UNITS = CODE( 'M', 'O' ), // Default: inch
|
2009-04-29 17:09:00 +00:00
|
|
|
INCH = CODE( 'I', 'N' ),
|
|
|
|
MILLIMETER = CODE( 'M', 'M' ),
|
2010-10-09 11:03:03 +00:00
|
|
|
OFFSET = CODE( 'O', 'F' ), // Default: A = 0, B = 0
|
|
|
|
SCALE_FACTOR = CODE( 'S', 'F' ), // Default: A = 1.0, B = 1.0
|
|
|
|
|
|
|
|
// Image parameters:
|
|
|
|
// commands used only once at the beginning of the file
|
|
|
|
IMAGE_JUSTIFY = CODE( 'I', 'J' ), // Default: no justification
|
|
|
|
IMAGE_NAME = CODE( 'I', 'N' ), // Default: void
|
|
|
|
IMAGE_OFFSET = CODE( 'I', 'O' ), // Default: A = 0, B = 0
|
|
|
|
IMAGE_POLARITY = CODE( 'I', 'P' ), // Default: Positive
|
|
|
|
IMAGE_ROTATION = CODE( 'I', 'R' ), // Default: 0
|
|
|
|
PLOTTER_FILM = CODE( 'P', 'M' ),
|
|
|
|
|
|
|
|
// Aperture parameters:
|
|
|
|
// Usually for the whole file
|
2009-04-29 17:09:00 +00:00
|
|
|
AP_DEFINITION = CODE( 'A', 'D' ),
|
|
|
|
AP_MACRO = CODE( 'A', 'M' ),
|
2010-10-09 11:03:03 +00:00
|
|
|
|
2014-11-22 11:52:57 +00:00
|
|
|
// X2 extention attribute commands
|
|
|
|
// Mainly are found standard attributes and user attributes
|
|
|
|
// standard attributes commands are:
|
2016-07-27 13:27:19 +00:00
|
|
|
// TF (file attribute) TO (net attribute)
|
2014-11-22 11:52:57 +00:00
|
|
|
// TA (aperture attribute) and TD (delete aperture attribute)
|
|
|
|
FILE_ATTRIBUTE = CODE( 'T', 'F' ),
|
|
|
|
|
2016-07-27 13:27:19 +00:00
|
|
|
// X2 extention Net attribute info
|
|
|
|
// Net attribute options are:
|
2016-08-16 10:56:20 +00:00
|
|
|
// TO (net attribute data): TO.CN or TO.P TO.N or TO.C
|
2016-07-27 13:27:19 +00:00
|
|
|
NET_ATTRIBUTE = CODE( 'T', 'O' ),
|
|
|
|
|
|
|
|
// X2 extention Aperture attribute TA
|
|
|
|
APERTURE_ATTRIBUTE = CODE( 'T', 'A' ),
|
|
|
|
|
2016-08-16 10:56:20 +00:00
|
|
|
// TD (delete aperture/object attribute):
|
|
|
|
// Delete aperture attribute added by %TA or Oblect attribute added b %TO
|
|
|
|
// TD (delete all) or %TD<attr name> to delete <attr name>.
|
|
|
|
// eg: TD.P or TD.N or TD.C ...
|
2016-07-27 13:27:19 +00:00
|
|
|
REMOVE_APERTURE_ATTRIBUTE = CODE( 'T', 'D' ),
|
|
|
|
|
2010-10-09 11:03:03 +00:00
|
|
|
// Layer specific parameters
|
|
|
|
// May be used singly or may be layer specfic
|
|
|
|
// theses parameters are at the beginning of the file or layer
|
2010-10-17 16:42:06 +00:00
|
|
|
// and reset some layer parameters (like interpolation)
|
2010-10-09 11:03:03 +00:00
|
|
|
LAYER_NAME = CODE( 'L', 'N' ), // Default: Positive
|
2009-04-29 17:09:00 +00:00
|
|
|
LAYER_POLARITY = CODE( 'L', 'P' ),
|
2010-10-09 11:03:03 +00:00
|
|
|
KNOCKOUT = CODE( 'K', 'O' ), // Default: off
|
2010-10-15 18:59:26 +00:00
|
|
|
STEP_AND_REPEAT = CODE( 'S', 'R' ), // Default: A = 1, B = 1
|
2010-10-09 11:03:03 +00:00
|
|
|
ROTATE = CODE( 'R', 'O' ), // Default: 0
|
|
|
|
|
|
|
|
// Miscellaneous parameters:
|
|
|
|
INCLUDE_FILE = CODE( 'I', 'F' )
|
2007-06-05 12:10:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-11-07 07:55:28 +00:00
|
|
|
/**
|
|
|
|
* Function ReadXCommand
|
2008-12-29 20:05:47 +00:00
|
|
|
* reads in two bytes of data and assembles them into an int with the first
|
2008-11-07 07:55:28 +00:00
|
|
|
* byte in the sequence put into the most significant part of a 16 bit value
|
|
|
|
* and the second byte put into the least significant part of the 16 bit value.
|
2009-04-29 17:09:00 +00:00
|
|
|
* @param text A reference to a pointer to read bytes from and to advance as
|
|
|
|
* they are read.
|
2008-11-07 07:55:28 +00:00
|
|
|
* @return int - with 16 bits of data in the ls bits, upper bits zeroed.
|
2007-09-25 15:10:01 +00:00
|
|
|
*/
|
|
|
|
static int ReadXCommand( char*& text )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2007-09-25 15:10:01 +00:00
|
|
|
int result;
|
2016-08-01 17:47:35 +00:00
|
|
|
int currbyte;
|
2007-09-25 15:10:01 +00:00
|
|
|
|
|
|
|
if( text && *text )
|
2016-08-01 17:47:35 +00:00
|
|
|
{
|
|
|
|
currbyte = *text++;
|
|
|
|
result = ( currbyte & 0xFF ) << 8;
|
|
|
|
}
|
2007-09-25 15:10:01 +00:00
|
|
|
else
|
|
|
|
return -1;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
if( text && *text )
|
2016-08-01 17:47:35 +00:00
|
|
|
{
|
|
|
|
currbyte = *text++;
|
|
|
|
result += currbyte & 0xFF;
|
|
|
|
}
|
2007-09-25 15:10:01 +00:00
|
|
|
else
|
|
|
|
return -1;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
return result;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2016-07-27 13:27:19 +00:00
|
|
|
/**
|
2017-06-16 07:14:28 +00:00
|
|
|
* Convert a string read from a gerber file to an unicode string
|
|
|
|
* Usual chars (ASCII7 values) are the only values allowed in Gerber files,
|
|
|
|
* and are just copied.
|
|
|
|
* However Gerber format allows using non ASCII7 values by coding them in a
|
|
|
|
* sequence of 4 hexadecimal chars (16 bits hexadecimal value)
|
|
|
|
* Hexadecimal coded values ("\hhhh") are converted to
|
|
|
|
* the unicode char value
|
2016-07-27 13:27:19 +00:00
|
|
|
*/
|
|
|
|
static const wxString fromGerberString( const wxString& aGbrString )
|
|
|
|
{
|
|
|
|
wxString text;
|
|
|
|
|
|
|
|
for( unsigned ii = 0; ii < aGbrString.size(); ++ii )
|
|
|
|
{
|
|
|
|
if( aGbrString[ii] == '\\' )
|
|
|
|
{
|
|
|
|
unsigned value = 0;
|
|
|
|
|
|
|
|
for( int jj = 0; jj < 4; jj++ )
|
2016-08-16 10:56:20 +00:00
|
|
|
{ // Convert 4 hexa digits to binary value:
|
2016-07-27 13:27:19 +00:00
|
|
|
ii++;
|
|
|
|
value <<= 4;
|
|
|
|
int digit = aGbrString[ii];
|
|
|
|
|
|
|
|
if( digit >= '0' && digit <= '9' )
|
|
|
|
digit -= '0';
|
|
|
|
else if( digit >= 'A' && digit <= 'F' )
|
2016-08-16 10:56:20 +00:00
|
|
|
digit -= 'A' - 10;
|
2016-07-27 13:27:19 +00:00
|
|
|
else if( digit >= 'a' && digit <= 'f' )
|
2016-08-16 10:56:20 +00:00
|
|
|
digit -= 'a' - 10;
|
2016-07-27 13:27:19 +00:00
|
|
|
else digit = 0;
|
|
|
|
|
2016-08-16 10:56:20 +00:00
|
|
|
value += digit & 0xF;
|
2016-07-27 13:27:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
text.Append( wxUniChar( value ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
text.Append( aGbrString[ii] );
|
|
|
|
}
|
|
|
|
|
|
|
|
return text;
|
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2016-05-25 14:48:38 +00:00
|
|
|
bool GERBER_FILE_IMAGE::ReadRS274XCommand( char* buff, char*& text )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2007-09-25 15:10:01 +00:00
|
|
|
bool ok = true;
|
|
|
|
int code_command;
|
|
|
|
|
|
|
|
text++;
|
|
|
|
|
2009-04-29 17:09:00 +00:00
|
|
|
for( ; ; )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
|
|
|
while( *text )
|
|
|
|
{
|
|
|
|
switch( *text )
|
|
|
|
{
|
2008-11-08 06:44:07 +00:00
|
|
|
case '%': // end of command
|
2007-09-25 15:10:01 +00:00
|
|
|
text++;
|
|
|
|
m_CommandState = CMD_IDLE;
|
|
|
|
goto exit; // success completion
|
|
|
|
|
|
|
|
case ' ':
|
|
|
|
case '\r':
|
|
|
|
case '\n':
|
|
|
|
text++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '*':
|
|
|
|
text++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
code_command = ReadXCommand( text );
|
|
|
|
ok = ExecuteRS274XCommand( code_command, buff, text );
|
|
|
|
if( !ok )
|
|
|
|
goto exit;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
// end of current line, read another one.
|
2008-11-07 07:55:28 +00:00
|
|
|
if( fgets( buff, GERBER_BUFZ, m_Current_File ) == NULL )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
2008-11-08 06:44:07 +00:00
|
|
|
// end of file
|
2007-09-25 15:10:01 +00:00
|
|
|
ok = false;
|
|
|
|
break;
|
|
|
|
}
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
text = buff;
|
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
return ok;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-25 14:48:38 +00:00
|
|
|
bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int command, char* buff, char*& text )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2007-09-25 15:10:01 +00:00
|
|
|
int code;
|
2013-03-06 19:32:59 +00:00
|
|
|
int seq_len; // not used, just provided
|
|
|
|
int seq_char;
|
2010-12-02 17:26:32 +00:00
|
|
|
bool ok = true;
|
2008-11-07 07:55:28 +00:00
|
|
|
char line[GERBER_BUFZ];
|
2007-09-25 15:10:01 +00:00
|
|
|
wxString msg;
|
|
|
|
double fcoord;
|
2013-03-06 19:32:59 +00:00
|
|
|
bool x_fmt_known = false;
|
|
|
|
bool y_fmt_known = false;
|
2012-04-18 07:07:13 +00:00
|
|
|
|
|
|
|
// conv_scale = scaling factor from inch to Internal Unit
|
2012-04-26 21:34:20 +00:00
|
|
|
double conv_scale = IU_PER_MILS * 1000;
|
2012-04-18 07:07:13 +00:00
|
|
|
if( m_GerbMetric )
|
|
|
|
conv_scale /= 25.4;
|
2007-09-25 15:10:01 +00:00
|
|
|
|
2013-09-10 15:07:46 +00:00
|
|
|
// DBG( printf( "%22s: Command <%c%c>\n", __func__, (command >> 8) & 0xFF, command & 0xFF ); )
|
2008-12-16 02:20:21 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
switch( command )
|
|
|
|
{
|
2008-11-07 07:55:28 +00:00
|
|
|
case FORMAT_STATEMENT:
|
2013-03-06 19:32:59 +00:00
|
|
|
seq_len = 2;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
while( *text != '*' )
|
|
|
|
{
|
|
|
|
switch( *text )
|
|
|
|
{
|
|
|
|
case ' ':
|
|
|
|
text++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'L': // No Leading 0
|
2010-12-02 17:26:32 +00:00
|
|
|
m_DecimalFormat = false;
|
|
|
|
m_NoTrailingZeros = false;
|
2007-09-25 15:10:01 +00:00
|
|
|
text++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'T': // No trailing 0
|
2010-12-02 17:26:32 +00:00
|
|
|
m_DecimalFormat = false;
|
|
|
|
m_NoTrailingZeros = true;
|
|
|
|
text++;
|
|
|
|
break;
|
|
|
|
|
2009-11-09 14:00:22 +00:00
|
|
|
case 'A': // Absolute coord
|
2010-12-02 17:26:32 +00:00
|
|
|
m_Relative = false;
|
2008-11-07 07:55:28 +00:00
|
|
|
text++;
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
2010-12-02 17:26:32 +00:00
|
|
|
case 'I': // Relative coord
|
|
|
|
m_Relative = true;
|
2008-11-07 07:55:28 +00:00
|
|
|
text++;
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
2013-03-06 19:32:59 +00:00
|
|
|
case 'G':
|
|
|
|
case 'N': // Sequence code (followed by one digit: the sequence len)
|
|
|
|
// (sometimes found before the X,Y sequence)
|
|
|
|
// Obscure option
|
2007-09-25 15:10:01 +00:00
|
|
|
text++;
|
2013-03-06 19:32:59 +00:00
|
|
|
seq_char = *text++;
|
|
|
|
if( (seq_char >= '0') && (seq_char <= '9') )
|
|
|
|
seq_len = seq_char - '0';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'D':
|
|
|
|
case 'M': // Sequence code (followed by one digit: the sequence len)
|
|
|
|
// (sometimes found after the X,Y sequence)
|
|
|
|
// Obscure option
|
|
|
|
code = *text++;
|
|
|
|
if( ( *text >= '0' ) && ( *text<= '9' ) )
|
|
|
|
text++; // skip the digit
|
|
|
|
else if( code == 'D' )
|
|
|
|
// Decimal format: sometimes found, but not really documented
|
|
|
|
m_DecimalFormat = true;
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'X':
|
2013-03-06 19:32:59 +00:00
|
|
|
case 'Y':
|
2009-04-29 17:09:00 +00:00
|
|
|
{
|
|
|
|
code = *(text++);
|
|
|
|
char ctmp = *(text++) - '0';
|
|
|
|
if( code == 'X' )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
2013-03-06 19:32:59 +00:00
|
|
|
x_fmt_known = true;
|
2014-07-09 16:31:39 +00:00
|
|
|
// number of digits after the decimal point (0 to 7 allowed)
|
2009-11-09 14:00:22 +00:00
|
|
|
m_FmtScale.x = *text - '0';
|
|
|
|
m_FmtLen.x = ctmp + m_FmtScale.x;
|
2010-10-09 11:03:03 +00:00
|
|
|
|
2014-07-09 16:31:39 +00:00
|
|
|
// m_FmtScale is 0 to 7
|
|
|
|
// (Old Gerber specification was 0 to 6)
|
2010-10-08 14:02:49 +00:00
|
|
|
if( m_FmtScale.x < 0 )
|
|
|
|
m_FmtScale.x = 0;
|
2014-07-09 16:31:39 +00:00
|
|
|
if( m_FmtScale.x > 7 )
|
|
|
|
m_FmtScale.x = 7;
|
2007-09-25 15:10:01 +00:00
|
|
|
}
|
2009-04-29 17:09:00 +00:00
|
|
|
else
|
|
|
|
{
|
2013-03-06 19:32:59 +00:00
|
|
|
y_fmt_known = true;
|
2009-04-29 17:09:00 +00:00
|
|
|
m_FmtScale.y = *text - '0';
|
|
|
|
m_FmtLen.y = ctmp + m_FmtScale.y;
|
2010-10-08 14:02:49 +00:00
|
|
|
if( m_FmtScale.y < 0 )
|
|
|
|
m_FmtScale.y = 0;
|
2014-07-09 16:31:39 +00:00
|
|
|
if( m_FmtScale.y > 7 )
|
|
|
|
m_FmtScale.y = 7;
|
2009-04-29 17:09:00 +00:00
|
|
|
}
|
|
|
|
text++;
|
|
|
|
}
|
|
|
|
break;
|
2007-09-25 15:10:01 +00:00
|
|
|
|
|
|
|
case '*':
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2013-03-06 19:32:59 +00:00
|
|
|
msg.Printf( wxT( "Unknown id (%c) in FS command" ),
|
|
|
|
*text );
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( msg );
|
2007-09-25 15:10:01 +00:00
|
|
|
GetEndOfBlock( buff, text, m_Current_File );
|
2010-12-02 17:26:32 +00:00
|
|
|
ok = false;
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-03-06 19:32:59 +00:00
|
|
|
if( !x_fmt_known || !y_fmt_known )
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( wxT( "RS274X: Format Statement (FS) without X or Y format" ) );
|
2013-01-21 20:02:07 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
case AXIS_SELECT: // command ASAXBY*% or %ASAYBX*%
|
|
|
|
m_SwapAxis = false;
|
2016-08-16 08:27:09 +00:00
|
|
|
if( strncasecmp( text, "AYBX", 4 ) == 0 )
|
2010-10-16 14:51:22 +00:00
|
|
|
m_SwapAxis = true;
|
|
|
|
break;
|
|
|
|
|
2014-11-22 11:52:57 +00:00
|
|
|
case MIRROR_IMAGE: // command %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*%
|
2010-10-16 14:51:22 +00:00
|
|
|
m_MirrorA = m_MirrorB = 0;
|
|
|
|
while( *text && *text != '*' )
|
|
|
|
{
|
|
|
|
switch( *text )
|
|
|
|
{
|
|
|
|
case 'A': // Mirror A axis ?
|
|
|
|
text++;
|
|
|
|
if( *text == '1' )
|
|
|
|
m_MirrorA = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'B': // Mirror B axis ?
|
|
|
|
text++;
|
|
|
|
if( *text == '1' )
|
|
|
|
m_MirrorB = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
text++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MODE_OF_UNITS:
|
|
|
|
code = ReadXCommand( text );
|
|
|
|
if( code == INCH )
|
2010-12-02 17:26:32 +00:00
|
|
|
m_GerbMetric = false;
|
2007-09-25 15:10:01 +00:00
|
|
|
else if( code == MILLIMETER )
|
2010-12-02 17:26:32 +00:00
|
|
|
m_GerbMetric = true;
|
2012-04-26 21:34:20 +00:00
|
|
|
conv_scale = m_GerbMetric ? IU_PER_MILS / 25.4 : IU_PER_MILS;
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
2014-11-22 11:52:57 +00:00
|
|
|
case FILE_ATTRIBUTE: // Command %TF ...
|
|
|
|
m_IsX2_file = true;
|
|
|
|
{
|
|
|
|
X2_ATTRIBUTE dummy;
|
|
|
|
dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text );
|
2016-07-27 13:27:19 +00:00
|
|
|
|
2014-11-22 11:52:57 +00:00
|
|
|
if( dummy.IsFileFunction() )
|
|
|
|
{
|
|
|
|
delete m_FileFunction;
|
|
|
|
m_FileFunction = new X2_ATTRIBUTE_FILEFUNCTION( dummy );
|
|
|
|
}
|
|
|
|
else if( dummy.IsFileMD5() )
|
|
|
|
{
|
|
|
|
m_MD5_value = dummy.GetPrm( 1 );
|
|
|
|
}
|
|
|
|
else if( dummy.IsFilePart() )
|
|
|
|
{
|
|
|
|
m_PartString = dummy.GetPrm( 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2016-07-27 13:27:19 +00:00
|
|
|
case APERTURE_ATTRIBUTE: // Command %TA ... Not yet supported
|
|
|
|
{
|
|
|
|
X2_ATTRIBUTE dummy;
|
|
|
|
dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text );
|
2016-08-01 17:47:35 +00:00
|
|
|
|
2016-08-16 10:56:20 +00:00
|
|
|
if( dummy.GetAttribute() == ".AperFunction" )
|
|
|
|
{
|
2016-08-01 17:47:35 +00:00
|
|
|
m_AperFunction = dummy.GetPrm( 1 );
|
2016-08-16 10:56:20 +00:00
|
|
|
|
|
|
|
// A few function values can have other parameters. Add them
|
|
|
|
for( int ii = 2; ii < dummy.GetPrmCount(); ii++ )
|
|
|
|
m_AperFunction << "," << dummy.GetPrm( ii );
|
|
|
|
}
|
2016-07-27 13:27:19 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2016-08-16 10:56:20 +00:00
|
|
|
case NET_ATTRIBUTE: // Command %TO currently %TO.P %TO.N and %TO.C
|
2016-07-27 13:27:19 +00:00
|
|
|
{
|
|
|
|
X2_ATTRIBUTE dummy;
|
2016-08-01 17:47:35 +00:00
|
|
|
|
2016-07-27 13:27:19 +00:00
|
|
|
dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text );
|
|
|
|
|
2016-08-16 10:56:20 +00:00
|
|
|
if( dummy.GetAttribute() == ".N" )
|
2016-07-27 13:27:19 +00:00
|
|
|
{
|
2016-08-16 10:56:20 +00:00
|
|
|
m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_NET;
|
2016-08-01 17:47:35 +00:00
|
|
|
m_NetAttributeDict.m_Netname = fromGerberString( dummy.GetPrm( 1 ) );
|
2016-07-27 13:27:19 +00:00
|
|
|
}
|
|
|
|
else if( dummy.GetAttribute() == ".C" )
|
|
|
|
{
|
2016-08-16 10:56:20 +00:00
|
|
|
m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_CMP;
|
|
|
|
m_NetAttributeDict.m_Cmpref = fromGerberString( dummy.GetPrm( 1 ) );
|
|
|
|
}
|
|
|
|
else if( dummy.GetAttribute() == ".P" )
|
|
|
|
{
|
|
|
|
m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_PAD;
|
|
|
|
m_NetAttributeDict.m_Cmpref = fromGerberString( dummy.GetPrm( 1 ) );
|
|
|
|
m_NetAttributeDict.m_Padname = fromGerberString( dummy.GetPrm( 2 ) );
|
2016-07-27 13:27:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REMOVE_APERTURE_ATTRIBUTE: // Command %TD ...
|
|
|
|
{
|
|
|
|
X2_ATTRIBUTE dummy;
|
|
|
|
dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text );
|
2016-08-01 17:47:35 +00:00
|
|
|
RemoveAttribute( dummy );
|
2016-07-27 13:27:19 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-10-09 20:05:03 +00:00
|
|
|
case OFFSET: // command: OFAnnBnn (nn = float number) = layer Offset
|
2007-09-25 15:10:01 +00:00
|
|
|
m_Offset.x = m_Offset.y = 0;
|
|
|
|
while( *text != '*' )
|
|
|
|
{
|
|
|
|
switch( *text )
|
|
|
|
{
|
2009-11-09 14:00:22 +00:00
|
|
|
case 'A': // A axis offset in current unit (inch or mm)
|
2007-09-25 15:10:01 +00:00
|
|
|
text++;
|
|
|
|
fcoord = ReadDouble( text );
|
// 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
|
|
|
m_Offset.x = KiROUND( fcoord * conv_scale );
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
2009-11-09 14:00:22 +00:00
|
|
|
case 'B': // B axis offset in current unit (inch or mm)
|
2007-09-25 15:10:01 +00:00
|
|
|
text++;
|
|
|
|
fcoord = ReadDouble( text );
|
// 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
|
|
|
m_Offset.y = KiROUND( fcoord * conv_scale );
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCALE_FACTOR:
|
2010-10-16 14:51:22 +00:00
|
|
|
m_Scale.x = m_Scale.y = 1.0;
|
2010-10-08 14:02:49 +00:00
|
|
|
while( *text != '*' )
|
|
|
|
{
|
|
|
|
switch( *text )
|
|
|
|
{
|
|
|
|
case 'A': // A axis scale
|
|
|
|
text++;
|
2010-10-16 14:51:22 +00:00
|
|
|
m_Scale.x = ReadDouble( text );
|
2010-10-08 14:02:49 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'B': // B axis scale
|
|
|
|
text++;
|
2010-10-16 14:51:22 +00:00
|
|
|
m_Scale.y = ReadDouble( text );
|
2010-10-08 14:02:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-10-09 20:05:03 +00:00
|
|
|
break;
|
2010-10-09 11:03:03 +00:00
|
|
|
|
2010-10-09 20:05:03 +00:00
|
|
|
case IMAGE_OFFSET: // command: IOAnnBnn (nn = float number) = Image Offset
|
|
|
|
m_ImageOffset.x = m_ImageOffset.y = 0;
|
|
|
|
while( *text != '*' )
|
2010-10-08 14:02:49 +00:00
|
|
|
{
|
2010-10-09 20:05:03 +00:00
|
|
|
switch( *text )
|
|
|
|
{
|
|
|
|
case 'A': // A axis offset in current unit (inch or mm)
|
|
|
|
text++;
|
|
|
|
fcoord = ReadDouble( text );
|
// 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
|
|
|
m_ImageOffset.x = KiROUND( fcoord * conv_scale );
|
2010-10-09 20:05:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'B': // B axis offset in current unit (inch or mm)
|
|
|
|
text++;
|
|
|
|
fcoord = ReadDouble( text );
|
// 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
|
|
|
m_ImageOffset.y = KiROUND( fcoord * conv_scale );
|
2010-10-09 20:05:03 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-10-08 14:02:49 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-10-09 20:05:03 +00:00
|
|
|
case IMAGE_ROTATION: // command IR0* or IR90* or IR180* or IR270*
|
2016-08-16 08:27:09 +00:00
|
|
|
if( strncasecmp( text, "0*", 2 ) == 0 )
|
2010-10-16 14:51:22 +00:00
|
|
|
m_ImageRotation = 0;
|
2016-08-16 08:27:09 +00:00
|
|
|
else if( strncasecmp( text, "90*", 3 ) == 0 )
|
2010-10-17 16:42:06 +00:00
|
|
|
m_ImageRotation = 90;
|
2016-08-16 08:27:09 +00:00
|
|
|
else if( strncasecmp( text, "180*", 4 ) == 0 )
|
2010-10-17 16:42:06 +00:00
|
|
|
m_ImageRotation = 180;
|
2016-08-16 08:27:09 +00:00
|
|
|
else if( strncasecmp( text, "270*", 4 ) == 0 )
|
2010-10-17 16:42:06 +00:00
|
|
|
m_ImageRotation = 270;
|
2010-10-09 20:05:03 +00:00
|
|
|
else
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( _( "RS274X: Command \"IR\" rotation value not allowed" ) );
|
2010-10-09 20:05:03 +00:00
|
|
|
break;
|
|
|
|
|
2010-10-15 18:59:26 +00:00
|
|
|
case STEP_AND_REPEAT: // command SR, like %SRX3Y2I5.0J2*%
|
2010-10-17 16:42:06 +00:00
|
|
|
m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
|
2010-10-16 14:51:22 +00:00
|
|
|
GetLayerParams().m_StepForRepeat.x = 0.0;
|
|
|
|
GetLayerParams().m_StepForRepeat.x = 0.0; // offset for Step and Repeat command
|
|
|
|
GetLayerParams().m_XRepeatCount = 1;
|
|
|
|
GetLayerParams().m_YRepeatCount = 1; // The repeat count
|
|
|
|
GetLayerParams().m_StepForRepeatMetric = m_GerbMetric; // the step units
|
2010-10-15 18:59:26 +00:00
|
|
|
while( *text && *text != '*' )
|
|
|
|
{
|
|
|
|
switch( *text )
|
|
|
|
{
|
|
|
|
case 'I': // X axis offset
|
|
|
|
text++;
|
2010-10-16 14:51:22 +00:00
|
|
|
GetLayerParams().m_StepForRepeat.x = ReadDouble( text );
|
2010-10-15 18:59:26 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'J': // Y axis offset
|
|
|
|
text++;
|
2010-10-16 14:51:22 +00:00
|
|
|
GetLayerParams().m_StepForRepeat.y = ReadDouble( text );
|
2010-10-15 18:59:26 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'X': // X axis repeat count
|
|
|
|
text++;
|
2010-10-16 14:51:22 +00:00
|
|
|
GetLayerParams().m_XRepeatCount = ReadInt( text );
|
2010-10-15 18:59:26 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'Y': // Y axis offset
|
|
|
|
text++;
|
2010-10-16 14:51:22 +00:00
|
|
|
GetLayerParams().m_YRepeatCount = ReadInt( text );
|
2010-10-15 18:59:26 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
text++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
case IMAGE_JUSTIFY: // Command IJAnBn*
|
|
|
|
m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false)
|
|
|
|
m_ImageJustifyYCenter = false; // Image Justify Center on Y axis (default = false)
|
|
|
|
m_ImageJustifyOffset = wxPoint(0,0); // Image Justify Offset on XY axis (default = 0,0)
|
|
|
|
while( *text && *text != '*' )
|
|
|
|
{
|
|
|
|
// IJ command is (for A or B axis) AC or AL or A<coordinate>
|
|
|
|
switch( *text )
|
|
|
|
{
|
|
|
|
case 'A': // A axis justify
|
|
|
|
text++;
|
|
|
|
if( *text == 'C' )
|
|
|
|
{
|
|
|
|
m_ImageJustifyXCenter = true;
|
|
|
|
text++;
|
|
|
|
}
|
|
|
|
else if( *text == 'L' )
|
|
|
|
{
|
|
|
|
m_ImageJustifyXCenter = true;
|
|
|
|
text++;
|
|
|
|
}
|
// 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
|
|
|
else m_ImageJustifyOffset.x = KiROUND( ReadDouble( text ) * conv_scale);
|
2010-10-17 12:32:35 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'B': // B axis justify
|
|
|
|
text++;
|
|
|
|
if( *text == 'C' )
|
|
|
|
{
|
|
|
|
m_ImageJustifyYCenter = true;
|
|
|
|
text++;
|
|
|
|
}
|
|
|
|
else if( *text == 'L' )
|
|
|
|
{
|
|
|
|
m_ImageJustifyYCenter = true;
|
|
|
|
text++;
|
|
|
|
}
|
// 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
|
|
|
else m_ImageJustifyOffset.y = KiROUND( ReadDouble( text ) * conv_scale);
|
2010-10-17 12:32:35 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
text++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( m_ImageJustifyXCenter )
|
|
|
|
m_ImageJustifyOffset.x = 0;
|
|
|
|
if( m_ImageJustifyYCenter )
|
|
|
|
m_ImageJustifyOffset.y = 0;
|
|
|
|
break;
|
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
case KNOCKOUT:
|
2010-10-17 16:42:06 +00:00
|
|
|
m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
|
2011-09-30 18:15:37 +00:00
|
|
|
msg = _( "RS274X: Command KNOCKOUT ignored by GerbView" ) ;
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( msg );
|
2010-10-17 12:32:35 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PLOTTER_FILM: // Command PF <string>
|
|
|
|
// This is an info about film that must be used to plot this file
|
|
|
|
// Has no meaning here. We just display this string
|
2010-10-18 12:34:45 +00:00
|
|
|
msg = wxT( "Plotter Film info:<br>" );
|
2010-10-17 12:32:35 +00:00
|
|
|
while( *text != '*' )
|
|
|
|
{
|
|
|
|
msg.Append( *text++ );
|
|
|
|
}
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( msg );
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
2010-10-16 14:51:22 +00:00
|
|
|
case ROTATE: // Layer rotation: command like %RO45*%
|
2010-10-17 16:42:06 +00:00
|
|
|
m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
|
|
|
|
m_LocalRotation =ReadDouble( text ); // Store layer rotation in degrees
|
2010-10-16 14:51:22 +00:00
|
|
|
break;
|
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
case IMAGE_NAME:
|
2010-10-06 17:28:07 +00:00
|
|
|
m_ImageName.Empty();
|
2007-09-25 15:10:01 +00:00
|
|
|
while( *text != '*' )
|
|
|
|
{
|
2010-10-06 17:28:07 +00:00
|
|
|
m_ImageName.Append( *text++ );
|
2007-09-25 15:10:01 +00:00
|
|
|
}
|
2010-10-09 11:03:03 +00:00
|
|
|
|
2010-10-06 17:28:07 +00:00
|
|
|
break;
|
2007-09-25 15:10:01 +00:00
|
|
|
|
2010-10-06 17:28:07 +00:00
|
|
|
case LAYER_NAME:
|
2010-10-17 16:42:06 +00:00
|
|
|
m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
|
2010-10-16 14:51:22 +00:00
|
|
|
GetLayerParams( ).m_LayerName.Empty();
|
2010-10-06 17:28:07 +00:00
|
|
|
while( *text != '*' )
|
|
|
|
{
|
2010-10-16 14:51:22 +00:00
|
|
|
GetLayerParams( ).m_LayerName.Append( *text++ );
|
2010-10-06 17:28:07 +00:00
|
|
|
}
|
2010-10-09 11:03:03 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IMAGE_POLARITY:
|
2016-08-16 08:27:09 +00:00
|
|
|
if( strncasecmp( text, "NEG", 3 ) == 0 )
|
2008-12-29 20:05:47 +00:00
|
|
|
m_ImageNegative = true;
|
2007-09-25 15:10:01 +00:00
|
|
|
else
|
2008-12-29 20:05:47 +00:00
|
|
|
m_ImageNegative = false;
|
2013-09-10 15:07:46 +00:00
|
|
|
DBG( printf( "%22s: IMAGE_POLARITY m_ImageNegative=%s\n", __func__,
|
2009-04-29 17:09:00 +00:00
|
|
|
m_ImageNegative ? "true" : "false" ); )
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LAYER_POLARITY:
|
|
|
|
if( *text == 'C' )
|
2010-10-16 14:51:22 +00:00
|
|
|
GetLayerParams().m_LayerNegative = true;
|
2010-12-15 20:15:24 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
else
|
2010-10-16 14:51:22 +00:00
|
|
|
GetLayerParams().m_LayerNegative = false;
|
2016-05-26 11:57:43 +00:00
|
|
|
|
|
|
|
// DBG( printf( "%22s: LAYER_POLARITY m_LayerNegative=%s\n", __func__,
|
|
|
|
// GetLayerParams().m_LayerNegative ? "true" : "false" ); )
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case INCLUDE_FILE:
|
2010-10-09 11:03:03 +00:00
|
|
|
if( m_FilesPtr >= INCLUDE_FILES_CNT_MAX )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
2010-12-02 17:26:32 +00:00
|
|
|
ok = false;
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( _( "Too many include files!!" ) );
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-08-10 08:17:22 +00:00
|
|
|
|
|
|
|
strncpy( line, text, sizeof(line)-1 );
|
|
|
|
line[sizeof(line)-1] = '\0';
|
|
|
|
|
2008-11-07 07:55:28 +00:00
|
|
|
strtok( line, "*%%\n\r" );
|
2007-09-25 15:10:01 +00:00
|
|
|
m_FilesList[m_FilesPtr] = m_Current_File;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
|
|
|
m_Current_File = fopen( line, "rt" );
|
2007-09-25 15:10:01 +00:00
|
|
|
if( m_Current_File == 0 )
|
|
|
|
{
|
2010-10-06 17:28:07 +00:00
|
|
|
msg.Printf( wxT( "include file <%s> not found." ), line );
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( msg );
|
2010-12-02 17:26:32 +00:00
|
|
|
ok = false;
|
2007-09-25 15:10:01 +00:00
|
|
|
m_Current_File = m_FilesList[m_FilesPtr];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
m_FilesPtr++;
|
|
|
|
break;
|
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
case AP_MACRO: // lines like %AMMYMACRO*
|
|
|
|
// 5,1,8,0,0,1.08239X$1,22.5*
|
|
|
|
// %
|
2015-08-23 12:35:49 +00:00
|
|
|
/*ok = */ReadApertureMacro( buff, text, m_Current_File );
|
2008-11-09 02:57:42 +00:00
|
|
|
break;
|
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
case AP_DEFINITION:
|
2010-09-28 19:34:16 +00:00
|
|
|
/* input example: %ADD30R,0.081800X0.101500*%
|
|
|
|
* Aperture definition has 4 options: C, R, O, P
|
|
|
|
* (Circle, Rect, Oval, regular Polygon)
|
|
|
|
* and shapes can have a hole (round or rectangular).
|
|
|
|
* All optional parameters values start by X
|
|
|
|
* at this point, text points to 2nd 'D'
|
|
|
|
*/
|
2008-11-09 02:57:42 +00:00
|
|
|
if( *text++ != 'D' )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
2010-12-02 17:26:32 +00:00
|
|
|
ok = false;
|
2008-11-07 07:55:28 +00:00
|
|
|
break;
|
2007-09-25 15:10:01 +00:00
|
|
|
}
|
2008-11-09 02:57:42 +00:00
|
|
|
|
2010-12-02 17:26:32 +00:00
|
|
|
m_Has_DCode = true;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2009-04-29 17:09:00 +00:00
|
|
|
code = ReadInt( text );
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2009-04-29 17:09:00 +00:00
|
|
|
D_CODE* dcode;
|
2008-11-09 02:57:42 +00:00
|
|
|
dcode = GetDCODE( code );
|
2016-08-01 17:47:35 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
if( dcode == NULL )
|
|
|
|
break;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2016-08-01 17:47:35 +00:00
|
|
|
dcode->m_AperFunction = m_AperFunction;
|
|
|
|
|
2009-04-29 17:09:00 +00:00
|
|
|
// at this point, text points to character after the ADD<num>,
|
|
|
|
// i.e. R in example above. If text[0] is one of the usual
|
|
|
|
// apertures: (C,R,O,P), there is a comma after it.
|
2008-11-09 02:57:42 +00:00
|
|
|
if( text[1] == ',' )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
2009-04-29 17:09:00 +00:00
|
|
|
char stdAperture = *text;
|
2008-11-09 02:57:42 +00:00
|
|
|
|
|
|
|
text += 2; // skip "C," for example
|
|
|
|
|
2012-04-25 19:33:24 +00:00
|
|
|
dcode->m_Size.x = KiROUND( ReadDouble( text ) * conv_scale );
|
|
|
|
dcode->m_Size.y = dcode->m_Size.x;
|
2007-09-25 15:10:01 +00:00
|
|
|
|
2010-09-28 19:34:16 +00:00
|
|
|
switch( stdAperture ) // Aperture desceiption has optional parameters. Read them
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
|
|
|
case 'C': // Circle
|
2008-11-08 06:44:07 +00:00
|
|
|
dcode->m_Shape = APT_CIRCLE;
|
2007-09-25 15:10:01 +00:00
|
|
|
while( *text == ' ' )
|
|
|
|
text++;
|
|
|
|
|
|
|
|
if( *text == 'X' )
|
|
|
|
{
|
|
|
|
text++;
|
|
|
|
dcode->m_Drill.x = dcode->m_Drill.y =
|
// 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
|
|
|
KiROUND( ReadDouble( text ) * conv_scale );
|
2010-09-28 19:34:16 +00:00
|
|
|
dcode->m_DrillShape = APT_DEF_ROUND_HOLE;
|
2007-09-25 15:10:01 +00:00
|
|
|
}
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
while( *text == ' ' )
|
|
|
|
text++;
|
|
|
|
|
|
|
|
if( *text == 'X' )
|
|
|
|
{
|
|
|
|
text++;
|
|
|
|
dcode->m_Drill.y =
|
// 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
|
|
|
KiROUND( ReadDouble( text ) * conv_scale );
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2010-09-28 19:34:16 +00:00
|
|
|
dcode->m_DrillShape = APT_DEF_RECT_HOLE;
|
2007-09-25 15:10:01 +00:00
|
|
|
}
|
2010-12-02 17:26:32 +00:00
|
|
|
dcode->m_Defined = true;
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
case 'O': // oval
|
2007-09-25 15:10:01 +00:00
|
|
|
case 'R': // rect
|
2008-11-09 02:57:42 +00:00
|
|
|
dcode->m_Shape = (stdAperture == 'O') ? APT_OVAL : APT_RECT;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
while( *text == ' ' )
|
|
|
|
text++;
|
|
|
|
|
|
|
|
if( *text == 'X' )
|
|
|
|
{
|
|
|
|
text++;
|
|
|
|
dcode->m_Size.y =
|
// 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
|
|
|
KiROUND( ReadDouble( text ) * conv_scale );
|
2007-09-25 15:10:01 +00:00
|
|
|
}
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
while( *text == ' ' )
|
|
|
|
text++;
|
|
|
|
|
|
|
|
if( *text == 'X' )
|
|
|
|
{
|
|
|
|
text++;
|
2012-04-25 19:33:24 +00:00
|
|
|
dcode->m_Drill.x = KiROUND( ReadDouble( text ) * conv_scale );
|
|
|
|
dcode->m_Drill.y = dcode->m_Drill.x;
|
2010-09-28 19:34:16 +00:00
|
|
|
dcode->m_DrillShape = APT_DEF_ROUND_HOLE;
|
2007-09-25 15:10:01 +00:00
|
|
|
}
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
while( *text == ' ' )
|
|
|
|
text++;
|
|
|
|
|
2010-09-28 14:42:05 +00:00
|
|
|
if( *text == 'X' )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
|
|
|
text++;
|
|
|
|
dcode->m_Drill.y =
|
// 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
|
|
|
KiROUND( ReadDouble( text ) * conv_scale );
|
2010-09-28 19:34:16 +00:00
|
|
|
dcode->m_DrillShape = APT_DEF_RECT_HOLE;
|
2007-09-25 15:10:01 +00:00
|
|
|
}
|
2010-12-02 17:26:32 +00:00
|
|
|
dcode->m_Defined = true;
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
2010-09-28 19:34:16 +00:00
|
|
|
case 'P':
|
2010-10-09 11:03:03 +00:00
|
|
|
|
2010-09-28 19:34:16 +00:00
|
|
|
/* Regular polygon: a command line like %ADD12P,0.040X10X25X0.025X0.025X0.0150*%
|
|
|
|
* params are: <diameter>, X<edge count>, X<Rotation>, X<X hole dim>, X<Y hole dim>
|
|
|
|
*/
|
|
|
|
dcode->m_Shape = APT_POLYGON;
|
|
|
|
while( *text == ' ' )
|
|
|
|
text++;
|
|
|
|
|
|
|
|
if( *text == 'X' )
|
|
|
|
{
|
|
|
|
text++;
|
|
|
|
dcode->m_EdgesCount = ReadInt( text );
|
|
|
|
}
|
|
|
|
|
|
|
|
while( *text == ' ' )
|
|
|
|
text++;
|
|
|
|
|
|
|
|
if( *text == 'X' )
|
|
|
|
{
|
|
|
|
text++;
|
|
|
|
dcode->m_Rotation = ReadDouble( text );
|
|
|
|
}
|
|
|
|
|
|
|
|
while( *text == ' ' )
|
|
|
|
text++;
|
|
|
|
|
|
|
|
if( *text == 'X' )
|
|
|
|
{
|
|
|
|
text++;
|
2012-04-25 19:33:24 +00:00
|
|
|
dcode->m_Drill.x = KiROUND( ReadDouble( text ) * conv_scale );
|
|
|
|
dcode->m_Drill.y = dcode->m_Drill.x =
|
2010-09-28 19:34:16 +00:00
|
|
|
dcode->m_DrillShape = APT_DEF_ROUND_HOLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( *text == ' ' )
|
|
|
|
text++;
|
|
|
|
|
|
|
|
if( *text == 'X' )
|
|
|
|
{
|
|
|
|
text++;
|
2012-04-25 19:33:24 +00:00
|
|
|
dcode->m_Drill.y = KiROUND( ReadDouble( text ) * conv_scale );
|
2010-09-28 19:34:16 +00:00
|
|
|
dcode->m_DrillShape = APT_DEF_RECT_HOLE;
|
|
|
|
}
|
2010-12-02 17:26:32 +00:00
|
|
|
dcode->m_Defined = true;
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-11-09 02:57:42 +00:00
|
|
|
else // text[0] starts an aperture macro name
|
|
|
|
{
|
2009-04-29 17:09:00 +00:00
|
|
|
APERTURE_MACRO am_lookup;
|
2008-11-09 02:57:42 +00:00
|
|
|
|
2009-04-29 17:09:00 +00:00
|
|
|
while( *text && *text != '*' && *text != ',' )
|
2008-11-09 02:57:42 +00:00
|
|
|
am_lookup.name.Append( *text++ );
|
|
|
|
|
2010-10-09 11:03:03 +00:00
|
|
|
// When an aperture definition is like %AMLINE2* 22,1,$1,$2,0,0,-45*
|
|
|
|
// the ADDxx<MACRO_NAME> command has parameters, like %ADD14LINE2,0.8X0.5*%
|
|
|
|
if( *text == ',' )
|
|
|
|
{ // Read aperture macro parameters and store them
|
|
|
|
text++; // text points the first parameter
|
2017-04-08 10:53:40 +00:00
|
|
|
|
2009-04-29 17:09:00 +00:00
|
|
|
while( *text && *text != '*' )
|
2008-11-09 02:57:42 +00:00
|
|
|
{
|
|
|
|
double param = ReadDouble( text );
|
|
|
|
dcode->AppendParam( param );
|
2017-04-08 10:53:40 +00:00
|
|
|
|
|
|
|
while( isspace( *text ) )
|
|
|
|
text++;
|
|
|
|
|
|
|
|
// Skip 'X' separator:
|
|
|
|
if( *text == 'X' || *text == 'x' )
|
|
|
|
text++;
|
2008-11-09 02:57:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// lookup the aperture macro here.
|
|
|
|
APERTURE_MACRO* pam = FindApertureMacro( am_lookup );
|
2017-04-08 10:53:40 +00:00
|
|
|
|
2008-11-09 02:57:42 +00:00
|
|
|
if( !pam )
|
|
|
|
{
|
2010-10-05 19:54:27 +00:00
|
|
|
msg.Printf( wxT( "RS274X: aperture macro %s not found\n" ),
|
2011-02-28 18:36:19 +00:00
|
|
|
TO_UTF8( am_lookup.name ) );
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( msg );
|
2008-11-09 02:57:42 +00:00
|
|
|
ok = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-11-14 07:46:43 +00:00
|
|
|
dcode->m_Shape = APT_MACRO;
|
2016-05-25 09:45:55 +00:00
|
|
|
dcode->SetMacro( pam );
|
2008-11-09 02:57:42 +00:00
|
|
|
}
|
2017-04-08 10:53:40 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2010-12-02 17:26:32 +00:00
|
|
|
ok = false;
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-04-18 17:03:47 +00:00
|
|
|
(void) seq_len; // quiet g++, or delete the unused variable.
|
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
ok = GetEndOfBlock( buff, text, m_Current_File );
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
return ok;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
|
2016-05-25 09:45:55 +00:00
|
|
|
bool GetEndOfBlock( char* buff, char*& text, FILE* gerber_file )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2009-04-29 17:09:00 +00:00
|
|
|
for( ; ; )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
2008-11-07 07:55:28 +00:00
|
|
|
while( (text < buff + GERBER_BUFZ) && *text )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
|
|
|
if( *text == '*' )
|
2010-12-02 17:26:32 +00:00
|
|
|
return true;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
if( *text == '%' )
|
2010-12-02 17:26:32 +00:00
|
|
|
return true;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
text++;
|
|
|
|
}
|
|
|
|
|
2008-11-07 07:55:28 +00:00
|
|
|
if( fgets( buff, GERBER_BUFZ, gerber_file ) == NULL )
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2007-09-25 15:10:01 +00:00
|
|
|
text = buff;
|
|
|
|
}
|
|
|
|
|
2010-12-02 17:26:32 +00:00
|
|
|
return false;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2013-04-18 17:03:47 +00:00
|
|
|
|
2010-11-12 16:36:43 +00:00
|
|
|
/**
|
|
|
|
* Function GetNextLine
|
2010-10-17 12:32:35 +00:00
|
|
|
* test for an end of line
|
|
|
|
* if an end of line is found:
|
|
|
|
* read a new line
|
2010-12-18 18:47:58 +00:00
|
|
|
* @param aBuff = buffer (size = GERBER_BUFZ) to fill with a new line
|
2010-10-17 12:32:35 +00:00
|
|
|
* @param aText = pointer to the last useful char in aBuff
|
|
|
|
* on return: points the beginning of the next line.
|
|
|
|
* @param aFile = the opened GERBER file to read
|
|
|
|
* @return a pointer to the beginning of the next line or NULL if end of file
|
|
|
|
*/
|
2016-05-25 09:45:55 +00:00
|
|
|
static char* GetNextLine( char *aBuff, char* aText, FILE* aFile )
|
2010-05-11 16:35:40 +00:00
|
|
|
{
|
2010-10-17 12:32:35 +00:00
|
|
|
for( ; ; )
|
2010-05-11 16:35:40 +00:00
|
|
|
{
|
2010-10-17 12:32:35 +00:00
|
|
|
switch (*aText )
|
2010-05-11 16:35:40 +00:00
|
|
|
{
|
2010-10-17 12:32:35 +00:00
|
|
|
case ' ': // skip blanks
|
|
|
|
case '\n':
|
|
|
|
case '\r': // Skip line terminators
|
|
|
|
++aText;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0: // End of text found in aBuff: Read a new string
|
|
|
|
if( fgets( aBuff, GERBER_BUFZ, aFile ) == NULL )
|
|
|
|
return NULL;
|
|
|
|
aText = aBuff;
|
|
|
|
return aText;
|
2010-05-11 16:35:40 +00:00
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
default:
|
|
|
|
return aText;
|
2010-05-11 16:35:40 +00:00
|
|
|
}
|
|
|
|
}
|
2010-10-17 12:32:35 +00:00
|
|
|
return aText;
|
2010-05-11 16:35:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-25 14:48:38 +00:00
|
|
|
bool GERBER_FILE_IMAGE::ReadApertureMacro( char *buff,
|
2010-10-09 11:03:03 +00:00
|
|
|
char*& text,
|
|
|
|
FILE* gerber_file )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2010-10-09 11:03:03 +00:00
|
|
|
wxString msg;
|
2008-11-14 18:26:56 +00:00
|
|
|
APERTURE_MACRO am;
|
2007-09-25 15:10:01 +00:00
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
// read macro name
|
|
|
|
while( *text )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
|
|
|
if( *text == '*' )
|
2008-11-08 06:44:07 +00:00
|
|
|
{
|
|
|
|
++text;
|
2007-09-25 15:10:01 +00:00
|
|
|
break;
|
2008-11-08 06:44:07 +00:00
|
|
|
}
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
am.name.Append( *text++ );
|
2007-09-25 15:10:01 +00:00
|
|
|
}
|
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
// Read aperture macro parameters
|
2009-04-29 17:09:00 +00:00
|
|
|
for( ; ; )
|
2007-09-25 15:10:01 +00:00
|
|
|
{
|
|
|
|
if( *text == '*' )
|
2008-11-08 06:44:07 +00:00
|
|
|
++text;
|
2008-11-07 07:55:28 +00:00
|
|
|
|
2017-04-08 10:53:40 +00:00
|
|
|
text = GetNextLine( buff, text, gerber_file );
|
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
if( text == NULL ) // End of File
|
2010-05-11 16:35:40 +00:00
|
|
|
return false;
|
2008-11-08 06:44:07 +00:00
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
// text points the beginning of a new line.
|
|
|
|
|
|
|
|
// Test for the last line in aperture macro lis:
|
|
|
|
// last line is % or *% sometime found.
|
|
|
|
if( *text == '*' )
|
|
|
|
++text;
|
2017-04-08 10:53:40 +00:00
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
if( *text == '%' )
|
|
|
|
break; // exit with text still pointing at %
|
|
|
|
|
2017-04-08 13:31:29 +00:00
|
|
|
int paramCount = 0; // will be set to the minimal parameters count,
|
|
|
|
// depending on the actual primitive
|
2010-10-25 09:57:00 +00:00
|
|
|
int primitive_type = AMP_UNKNOWN;
|
|
|
|
// Test for a valid symbol at the beginning of a description:
|
|
|
|
// it can be: a parameter declaration like $1=$2/4
|
|
|
|
// or a digit (macro primitive selection)
|
|
|
|
// all other symbols are illegal.
|
2010-12-01 19:30:52 +00:00
|
|
|
if( *text == '$' ) // local parameter declaration, inside the aperture macro
|
2010-10-25 09:57:00 +00:00
|
|
|
{
|
2010-12-01 19:30:52 +00:00
|
|
|
am.m_localparamStack.push_back( AM_PARAM() );
|
|
|
|
AM_PARAM& param = am.m_localparamStack.back();
|
|
|
|
text = GetNextLine( buff, text, gerber_file );
|
|
|
|
if( text == NULL) // End of File
|
|
|
|
return false;
|
|
|
|
param.ReadParam( text );
|
|
|
|
continue;
|
2010-10-25 09:57:00 +00:00
|
|
|
}
|
|
|
|
else if( !isdigit(*text) ) // Ill. symbol
|
|
|
|
{
|
|
|
|
msg.Printf( wxT( "RS274X: Aperture Macro \"%s\": ill. symbol, line: \"%s\"" ),
|
2011-02-28 18:36:19 +00:00
|
|
|
GetChars( am.name ), GetChars( FROM_UTF8( buff ) ) );
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( msg );
|
2010-10-25 09:57:00 +00:00
|
|
|
primitive_type = AMP_COMMENT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
primitive_type = ReadInt( text );
|
|
|
|
|
2017-04-08 10:53:40 +00:00
|
|
|
bool is_comment = false;
|
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
switch( primitive_type )
|
2008-11-08 06:44:07 +00:00
|
|
|
{
|
2010-10-25 10:22:54 +00:00
|
|
|
case AMP_COMMENT: // lines starting by 0 are a comment
|
|
|
|
paramCount = 0;
|
2017-04-08 10:53:40 +00:00
|
|
|
is_comment = true;
|
2010-10-25 09:57:00 +00:00
|
|
|
// Skip comment
|
2017-04-08 10:53:40 +00:00
|
|
|
while( *text && ( *text != '*' ) )
|
2010-10-25 09:57:00 +00:00
|
|
|
text++;
|
|
|
|
break;
|
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
case AMP_CIRCLE:
|
2017-04-08 13:31:29 +00:00
|
|
|
paramCount = 4; // minimal count. can have a optional parameter (rotation)
|
2008-11-08 06:44:07 +00:00
|
|
|
break;
|
2009-04-29 17:09:00 +00:00
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
case AMP_LINE2:
|
|
|
|
case AMP_LINE20:
|
|
|
|
paramCount = 7;
|
|
|
|
break;
|
2009-04-29 17:09:00 +00:00
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
case AMP_LINE_CENTER:
|
|
|
|
case AMP_LINE_LOWER_LEFT:
|
|
|
|
paramCount = 6;
|
|
|
|
break;
|
2009-04-29 17:09:00 +00:00
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
case AMP_EOF:
|
|
|
|
paramCount = 0;
|
|
|
|
break;
|
2009-04-29 17:09:00 +00:00
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
case AMP_OUTLINE:
|
|
|
|
paramCount = 4;
|
|
|
|
break;
|
2009-04-29 17:09:00 +00:00
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
case AMP_POLYGON:
|
2010-10-03 15:39:06 +00:00
|
|
|
paramCount = 6;
|
2008-11-08 06:44:07 +00:00
|
|
|
break;
|
2009-04-29 17:09:00 +00:00
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
case AMP_MOIRE:
|
|
|
|
paramCount = 9;
|
|
|
|
break;
|
2009-04-29 17:09:00 +00:00
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
case AMP_THERMAL:
|
|
|
|
paramCount = 6;
|
|
|
|
break;
|
2009-04-29 17:09:00 +00:00
|
|
|
|
2008-11-09 02:57:42 +00:00
|
|
|
default:
|
2009-04-29 17:09:00 +00:00
|
|
|
// @todo, there needs to be a way of reporting the line number
|
2010-10-17 12:32:35 +00:00
|
|
|
msg.Printf( wxT( "RS274X: Aperture Macro \"%s\": Invalid primitive id code %d, line: \"%s\"" ),
|
2011-02-28 18:36:19 +00:00
|
|
|
GetChars( am.name ), primitive_type, GetChars( FROM_UTF8( buff ) ) );
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( msg );
|
2008-11-09 02:57:42 +00:00
|
|
|
return false;
|
2008-11-08 06:44:07 +00:00
|
|
|
}
|
|
|
|
|
2017-04-08 10:53:40 +00:00
|
|
|
if( is_comment )
|
|
|
|
continue;
|
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
AM_PRIMITIVE prim( m_GerbMetric );
|
|
|
|
prim.primitive_id = (AM_PRIMITIVE_ID) primitive_type;
|
2016-05-06 15:15:30 +00:00
|
|
|
int ii;
|
2011-09-23 13:57:12 +00:00
|
|
|
|
2017-04-08 13:31:29 +00:00
|
|
|
for( ii = 0; ii < *text && *text != '*'; ++ii )
|
2008-11-08 06:44:07 +00:00
|
|
|
{
|
2010-11-30 20:41:35 +00:00
|
|
|
prim.params.push_back( AM_PARAM() );
|
2008-11-14 18:26:56 +00:00
|
|
|
|
2010-11-30 20:41:35 +00:00
|
|
|
AM_PARAM& param = prim.params.back();
|
2008-11-09 02:57:42 +00:00
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
text = GetNextLine( buff, text, gerber_file );
|
2011-09-23 13:57:12 +00:00
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
if( text == NULL) // End of File
|
2010-05-11 16:35:40 +00:00
|
|
|
return false;
|
2011-09-23 13:57:12 +00:00
|
|
|
|
2010-11-30 20:41:35 +00:00
|
|
|
param.ReadParam( text );
|
2008-11-08 06:44:07 +00:00
|
|
|
}
|
|
|
|
|
2016-05-06 15:15:30 +00:00
|
|
|
if( ii < paramCount )
|
2010-10-09 11:03:03 +00:00
|
|
|
{
|
|
|
|
// maybe some day we can throw an exception and track a line number
|
2010-10-18 12:34:45 +00:00
|
|
|
msg.Printf( wxT( "RS274X: read macro descr type %d: read %d parameters, insufficient parameters\n" ),
|
2016-05-06 15:15:30 +00:00
|
|
|
prim.primitive_id, ii );
|
2016-06-05 12:26:39 +00:00
|
|
|
AddMessageToList( msg );
|
2010-10-17 12:32:35 +00:00
|
|
|
|
2010-10-05 11:44:34 +00:00
|
|
|
}
|
2008-11-09 02:57:42 +00:00
|
|
|
// there are more parameters to read if this is an AMP_OUTLINE
|
2008-11-08 06:44:07 +00:00
|
|
|
if( prim.primitive_id == AMP_OUTLINE )
|
|
|
|
{
|
2010-05-11 16:35:40 +00:00
|
|
|
// so far we have read [0]:exposure, [1]:#points, [2]:X start, [3]: Y start
|
|
|
|
// Now read all the points, plus trailing rotation in degrees.
|
|
|
|
|
2008-11-09 02:57:42 +00:00
|
|
|
// params[1] is a count of polygon points, so it must be given
|
|
|
|
// in advance, i.e. be immediate.
|
|
|
|
wxASSERT( prim.params[1].IsImmediate() );
|
|
|
|
|
2009-04-29 17:09:00 +00:00
|
|
|
paramCount = (int) prim.params[1].GetValue( 0 ) * 2 + 1;
|
2008-11-08 06:44:07 +00:00
|
|
|
|
2016-05-06 15:15:30 +00:00
|
|
|
for( int jj = 0; jj < paramCount && *text != '*'; ++jj )
|
2008-11-08 06:44:07 +00:00
|
|
|
{
|
2010-11-30 20:41:35 +00:00
|
|
|
prim.params.push_back( AM_PARAM() );
|
2008-11-14 18:26:56 +00:00
|
|
|
|
2010-11-30 20:41:35 +00:00
|
|
|
AM_PARAM& param = prim.params.back();
|
2008-11-09 02:57:42 +00:00
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
text = GetNextLine( buff, text, gerber_file );
|
2011-09-23 13:57:12 +00:00
|
|
|
|
2010-10-17 12:32:35 +00:00
|
|
|
if( text == NULL ) // End of File
|
2010-05-11 16:35:40 +00:00
|
|
|
return false;
|
2011-09-23 13:57:12 +00:00
|
|
|
|
2010-11-30 20:41:35 +00:00
|
|
|
param.ReadParam( text );
|
2008-11-08 06:44:07 +00:00
|
|
|
}
|
|
|
|
}
|
2008-12-16 02:20:21 +00:00
|
|
|
|
|
|
|
am.primitives.push_back( prim );
|
2007-09-25 15:10:01 +00:00
|
|
|
}
|
|
|
|
|
2008-11-08 06:44:07 +00:00
|
|
|
m_aperture_macros.insert( am );
|
|
|
|
|
|
|
|
return true;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
2010-10-17 12:32:35 +00:00
|
|
|
|