You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1144 lines
35 KiB

// 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; }
14 years ago
// 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; }
14 years ago
// 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; }
14 years ago
// 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; }
14 years ago
// 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; }
14 years ago
// 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; }
14 years ago
// 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; }
14 years ago
// 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; }
14 years ago
// 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; }
14 years ago
// 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; }
14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2007-2016 Jean-Pierre Charras jp.charras at wanadoo.fr
  5. * Copyright (C) 1992-2016 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. * @file rs274x.cpp
  26. */
  27. #include <fctsys.h>
  28. #include <common.h>
  29. #include <macros.h>
  30. #include <base_units.h>
  31. #include <gerbview.h>
  32. #include <class_gerber_file_image.h>
  33. #include <class_X2_gerber_attributes.h>
  34. extern int ReadInt( char*& text, bool aSkipSeparator = true );
  35. extern double ReadDouble( char*& text, bool aSkipSeparator = true );
  36. #define CODE( x, y ) ( ( (x) << 8 ) + (y) )
  37. // See rs274xrevd_e.pdf, table 1: RS-274X parameters order of entry
  38. // in gerber files, when a coordinate is given (like X78Y600 or I0J80):
  39. // Y and Y are logical coordinates
  40. // A and B are plotter coordiantes
  41. // Usually A = X, B = Y
  42. // But we can have A = Y, B = X and/or offset, mirror, scale;
  43. // Also:
  44. // Image is what you must plot (the entire data of the file).
  45. // Layer is just a set of data blocks with their parameters. An image can have more than one
  46. // layer so a gerber layer is not like a board layer or the graphic layers used in GerbView
  47. // to show a file.
  48. enum RS274X_PARAMETERS {
  49. // Directive parameters: single usage recommended
  50. // Must be at the beginning of the file
  51. AXIS_SELECT = CODE( 'A', 'S' ), // Default: A=X, B=Y
  52. FORMAT_STATEMENT = CODE( 'F', 'S' ), // no default: this command must exists
  53. MIRROR_IMAGE = CODE( 'M', 'I' ), // Default: mo mirror
  54. MODE_OF_UNITS = CODE( 'M', 'O' ), // Default: inch
  55. INCH = CODE( 'I', 'N' ),
  56. MILLIMETER = CODE( 'M', 'M' ),
  57. OFFSET = CODE( 'O', 'F' ), // Default: A = 0, B = 0
  58. SCALE_FACTOR = CODE( 'S', 'F' ), // Default: A = 1.0, B = 1.0
  59. // Image parameters:
  60. // commands used only once at the beginning of the file, and are deprecated
  61. IMAGE_JUSTIFY = CODE( 'I', 'J' ), // Default: no justification
  62. IMAGE_NAME = CODE( 'I', 'N' ), // Default: void
  63. IMAGE_OFFSET = CODE( 'I', 'O' ), // Default: A = 0, B = 0
  64. IMAGE_POLARITY = CODE( 'I', 'P' ), // Default: Positive
  65. IMAGE_ROTATION = CODE( 'I', 'R' ), // Default: 0
  66. // Aperture parameters:
  67. // Usually for the whole file
  68. AP_DEFINITION = CODE( 'A', 'D' ),
  69. AP_MACRO = CODE( 'A', 'M' ),
  70. // X2 extention attribute commands
  71. // Mainly are found standard attributes and user attributes
  72. // standard attributes commands are:
  73. // TF (file attribute) TO (net attribute)
  74. // TA (aperture attribute) and TD (delete aperture attribute)
  75. FILE_ATTRIBUTE = CODE( 'T', 'F' ),
  76. // X2 extention Net attribute info
  77. // Net attribute options are:
  78. // TO (net attribute data): TO.CN or TO.P TO.N or TO.C
  79. NET_ATTRIBUTE = CODE( 'T', 'O' ),
  80. // X2 extention Aperture attribute TA
  81. APERTURE_ATTRIBUTE = CODE( 'T', 'A' ),
  82. // TD (delete aperture/object attribute):
  83. // Delete aperture attribute added by %TA or Oblect attribute added b %TO
  84. // TD (delete all) or %TD<attr name> to delete <attr name>.
  85. // eg: TD.P or TD.N or TD.C ...
  86. REMOVE_APERTURE_ATTRIBUTE = CODE( 'T', 'D' ),
  87. // Layer specific parameters
  88. // May be used singly or may be layer specfic
  89. // theses parameters are at the beginning of the file or layer
  90. // and reset some layer parameters (like interpolation)
  91. KNOCKOUT = CODE( 'K', 'O' ), // Default: off
  92. STEP_AND_REPEAT = CODE( 'S', 'R' ), // Default: A = 1, B = 1
  93. ROTATE = CODE( 'R', 'O' ), // Default: 0
  94. LOAD_POLARITY = CODE( 'L', 'P' ), //LPC or LPD. Default: Dark (LPD)
  95. LOAD_NAME = CODE( 'L', 'N' ), // Deprecated: equivalent to G04
  96. };
  97. /**
  98. * Function ReadXCommand
  99. * reads in two bytes of data and assembles them into an int with the first
  100. * byte in the sequence put into the most significant part of a 16 bit value
  101. * and the second byte put into the least significant part of the 16 bit value.
  102. * @param text A reference to a pointer to read bytes from and to advance as
  103. * they are read.
  104. * @return int - with 16 bits of data in the ls bits, upper bits zeroed.
  105. */
  106. static int ReadXCommand( char*& text )
  107. {
  108. int result;
  109. int currbyte;
  110. if( text && *text )
  111. {
  112. currbyte = *text++;
  113. result = ( currbyte & 0xFF ) << 8;
  114. }
  115. else
  116. return -1;
  117. if( text && *text )
  118. {
  119. currbyte = *text++;
  120. result += currbyte & 0xFF;
  121. }
  122. else
  123. return -1;
  124. return result;
  125. }
  126. /**
  127. * Convert a string read from a gerber file to an unicode string
  128. * Usual chars (ASCII7 values) are the only values allowed in Gerber files,
  129. * and are just copied.
  130. * However Gerber format allows using non ASCII7 values by coding them in a
  131. * sequence of 4 hexadecimal chars (16 bits hexadecimal value)
  132. * Hexadecimal coded values ("\hhhh") are converted to
  133. * the unicode char value
  134. */
  135. static const wxString fromGerberString( const wxString& aGbrString )
  136. {
  137. wxString text;
  138. for( unsigned ii = 0; ii < aGbrString.size(); ++ii )
  139. {
  140. if( aGbrString[ii] == '\\' )
  141. {
  142. unsigned value = 0;
  143. for( int jj = 0; jj < 4; jj++ )
  144. { // Convert 4 hexa digits to binary value:
  145. ii++;
  146. value <<= 4;
  147. int digit = aGbrString[ii];
  148. if( digit >= '0' && digit <= '9' )
  149. digit -= '0';
  150. else if( digit >= 'A' && digit <= 'F' )
  151. digit -= 'A' - 10;
  152. else if( digit >= 'a' && digit <= 'f' )
  153. digit -= 'a' - 10;
  154. else digit = 0;
  155. value += digit & 0xF;
  156. }
  157. text.Append( wxUniChar( value ) );
  158. }
  159. else
  160. text.Append( aGbrString[ii] );
  161. }
  162. return text;
  163. }
  164. bool GERBER_FILE_IMAGE::ReadRS274XCommand( char* buff, char*& text )
  165. {
  166. bool ok = true;
  167. int code_command;
  168. text++;
  169. for( ; ; )
  170. {
  171. while( *text )
  172. {
  173. switch( *text )
  174. {
  175. case '%': // end of command
  176. text++;
  177. m_CommandState = CMD_IDLE;
  178. goto exit; // success completion
  179. case ' ':
  180. case '\r':
  181. case '\n':
  182. text++;
  183. break;
  184. case '*':
  185. text++;
  186. break;
  187. default:
  188. code_command = ReadXCommand( text );
  189. ok = ExecuteRS274XCommand( code_command, buff, text );
  190. if( !ok )
  191. goto exit;
  192. break;
  193. }
  194. }
  195. // end of current line, read another one.
  196. if( fgets( buff, GERBER_BUFZ, m_Current_File ) == NULL )
  197. {
  198. // end of file
  199. ok = false;
  200. break;
  201. }
  202. m_LineNum++;
  203. text = buff;
  204. }
  205. exit:
  206. return ok;
  207. }
  208. bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int command, char* buff, char*& text )
  209. {
  210. int code;
  211. int seq_len; // not used, just provided
  212. int seq_char;
  213. bool ok = true;
  214. wxString msg;
  215. double fcoord;
  216. bool x_fmt_known = false;
  217. bool y_fmt_known = false;
  218. // conv_scale = scaling factor from inch to Internal Unit
  219. double conv_scale = IU_PER_MILS * 1000;
  220. if( m_GerbMetric )
  221. conv_scale /= 25.4;
  222. // DBG( printf( "%22s: Command <%c%c>\n", __func__, (command >> 8) & 0xFF, command & 0xFF ); )
  223. switch( command )
  224. {
  225. case FORMAT_STATEMENT:
  226. seq_len = 2;
  227. while( *text != '*' )
  228. {
  229. switch( *text )
  230. {
  231. case ' ':
  232. text++;
  233. break;
  234. case 'D': // Non-standard option for all zeros (leading + tailing)
  235. msg.Printf( _( "RS274X: Invalid GERBER format command '%c' at line %d: \"%s\"" ),
  236. 'D', m_LineNum, buff );
  237. AddMessageToList( msg );
  238. msg.Printf( _("GERBER file \"%s\" may not display as intended." ),
  239. m_FileName.ToAscii() );
  240. AddMessageToList( msg );
  241. // Fallthrough
  242. case 'L': // No Leading 0
  243. m_NoTrailingZeros = false;
  244. text++;
  245. break;
  246. case 'T': // No trailing 0
  247. m_NoTrailingZeros = true;
  248. text++;
  249. break;
  250. case 'A': // Absolute coord
  251. m_Relative = false;
  252. text++;
  253. break;
  254. case 'I': // Relative coord
  255. m_Relative = true;
  256. text++;
  257. break;
  258. case 'G':
  259. case 'N': // Sequence code (followed by one digit: the sequence len)
  260. // (sometimes found before the X,Y sequence)
  261. // Obscure option
  262. text++;
  263. seq_char = *text++;
  264. if( (seq_char >= '0') && (seq_char <= '9') )
  265. seq_len = seq_char - '0';
  266. break;
  267. case 'M': // Sequence code (followed by one digit: the sequence len)
  268. // (sometimes found after the X,Y sequence)
  269. // Obscure option
  270. code = *text++;
  271. if( ( *text >= '0' ) && ( *text<= '9' ) )
  272. text++; // skip the digit
  273. break;
  274. case 'X':
  275. case 'Y':
  276. {
  277. code = *(text++);
  278. char ctmp = *(text++) - '0';
  279. if( code == 'X' )
  280. {
  281. x_fmt_known = true;
  282. // number of digits after the decimal point (0 to 7 allowed)
  283. m_FmtScale.x = *text - '0';
  284. m_FmtLen.x = ctmp + m_FmtScale.x;
  285. // m_FmtScale is 0 to 7
  286. // (Old Gerber specification was 0 to 6)
  287. if( m_FmtScale.x < 0 )
  288. m_FmtScale.x = 0;
  289. if( m_FmtScale.x > 7 )
  290. m_FmtScale.x = 7;
  291. }
  292. else
  293. {
  294. y_fmt_known = true;
  295. m_FmtScale.y = *text - '0';
  296. m_FmtLen.y = ctmp + m_FmtScale.y;
  297. if( m_FmtScale.y < 0 )
  298. m_FmtScale.y = 0;
  299. if( m_FmtScale.y > 7 )
  300. m_FmtScale.y = 7;
  301. }
  302. text++;
  303. }
  304. break;
  305. case '*':
  306. break;
  307. default:
  308. msg.Printf( wxT( "Unknown id (%c) in FS command" ),
  309. *text );
  310. AddMessageToList( msg );
  311. GetEndOfBlock( buff, text, m_Current_File );
  312. ok = false;
  313. break;
  314. }
  315. }
  316. if( !x_fmt_known || !y_fmt_known )
  317. AddMessageToList( wxT( "RS274X: Format Statement (FS) without X or Y format" ) );
  318. break;
  319. case AXIS_SELECT: // command ASAXBY*% or %ASAYBX*%
  320. m_SwapAxis = false;
  321. if( strncasecmp( text, "AYBX", 4 ) == 0 )
  322. m_SwapAxis = true;
  323. break;
  324. case MIRROR_IMAGE: // command %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*%
  325. m_MirrorA = m_MirrorB = 0;
  326. while( *text && *text != '*' )
  327. {
  328. switch( *text )
  329. {
  330. case 'A': // Mirror A axis ?
  331. text++;
  332. if( *text == '1' )
  333. m_MirrorA = true;
  334. break;
  335. case 'B': // Mirror B axis ?
  336. text++;
  337. if( *text == '1' )
  338. m_MirrorB = true;
  339. break;
  340. default:
  341. text++;
  342. break;
  343. }
  344. }
  345. break;
  346. case MODE_OF_UNITS:
  347. code = ReadXCommand( text );
  348. if( code == INCH )
  349. m_GerbMetric = false;
  350. else if( code == MILLIMETER )
  351. m_GerbMetric = true;
  352. conv_scale = m_GerbMetric ? IU_PER_MILS / 25.4 : IU_PER_MILS;
  353. break;
  354. case FILE_ATTRIBUTE: // Command %TF ...
  355. m_IsX2_file = true;
  356. {
  357. X2_ATTRIBUTE dummy;
  358. dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text, m_LineNum );
  359. if( dummy.IsFileFunction() )
  360. {
  361. delete m_FileFunction;
  362. m_FileFunction = new X2_ATTRIBUTE_FILEFUNCTION( dummy );
  363. }
  364. else if( dummy.IsFileMD5() )
  365. {
  366. m_MD5_value = dummy.GetPrm( 1 );
  367. }
  368. else if( dummy.IsFilePart() )
  369. {
  370. m_PartString = dummy.GetPrm( 1 );
  371. }
  372. }
  373. break;
  374. case APERTURE_ATTRIBUTE: // Command %TA ... Not yet supported
  375. {
  376. X2_ATTRIBUTE dummy;
  377. dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text, m_LineNum );
  378. if( dummy.GetAttribute() == ".AperFunction" )
  379. {
  380. m_AperFunction = dummy.GetPrm( 1 );
  381. // A few function values can have other parameters. Add them
  382. for( int ii = 2; ii < dummy.GetPrmCount(); ii++ )
  383. m_AperFunction << "," << dummy.GetPrm( ii );
  384. }
  385. }
  386. break;
  387. case NET_ATTRIBUTE: // Command %TO currently %TO.P %TO.N and %TO.C
  388. {
  389. X2_ATTRIBUTE dummy;
  390. dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text, m_LineNum );
  391. if( dummy.GetAttribute() == ".N" )
  392. {
  393. m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_NET;
  394. m_NetAttributeDict.m_Netname = fromGerberString( dummy.GetPrm( 1 ) );
  395. }
  396. else if( dummy.GetAttribute() == ".C" )
  397. {
  398. m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_CMP;
  399. m_NetAttributeDict.m_Cmpref = fromGerberString( dummy.GetPrm( 1 ) );
  400. }
  401. else if( dummy.GetAttribute() == ".P" )
  402. {
  403. m_NetAttributeDict.m_NetAttribType |= GBR_NETLIST_METADATA::GBR_NETINFO_PAD;
  404. m_NetAttributeDict.m_Cmpref = fromGerberString( dummy.GetPrm( 1 ) );
  405. m_NetAttributeDict.m_Padname = fromGerberString( dummy.GetPrm( 2 ) );
  406. }
  407. }
  408. break;
  409. case REMOVE_APERTURE_ATTRIBUTE: // Command %TD ...
  410. {
  411. X2_ATTRIBUTE dummy;
  412. dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text, m_LineNum );
  413. RemoveAttribute( dummy );
  414. }
  415. break;
  416. case OFFSET: // command: OFAnnBnn (nn = float number) = layer Offset
  417. m_Offset.x = m_Offset.y = 0;
  418. while( *text != '*' )
  419. {
  420. switch( *text )
  421. {
  422. case 'A': // A axis offset in current unit (inch or mm)
  423. text++;
  424. fcoord = ReadDouble( text );
  425. m_Offset.x = KiROUND( fcoord * conv_scale );
  426. break;
  427. case 'B': // B axis offset in current unit (inch or mm)
  428. text++;
  429. fcoord = ReadDouble( text );
  430. m_Offset.y = KiROUND( fcoord * conv_scale );
  431. break;
  432. }
  433. }
  434. break;
  435. case SCALE_FACTOR:
  436. m_Scale.x = m_Scale.y = 1.0;
  437. while( *text != '*' )
  438. {
  439. switch( *text )
  440. {
  441. case 'A': // A axis scale
  442. text++;
  443. m_Scale.x = ReadDouble( text );
  444. break;
  445. case 'B': // B axis scale
  446. text++;
  447. m_Scale.y = ReadDouble( text );
  448. break;
  449. }
  450. }
  451. break;
  452. case IMAGE_OFFSET: // command: IOAnnBnn (nn = float number) = Image Offset
  453. m_ImageOffset.x = m_ImageOffset.y = 0;
  454. while( *text != '*' )
  455. {
  456. switch( *text )
  457. {
  458. case 'A': // A axis offset in current unit (inch or mm)
  459. text++;
  460. fcoord = ReadDouble( text );
  461. m_ImageOffset.x = KiROUND( fcoord * conv_scale );
  462. break;
  463. case 'B': // B axis offset in current unit (inch or mm)
  464. text++;
  465. fcoord = ReadDouble( text );
  466. m_ImageOffset.y = KiROUND( fcoord * conv_scale );
  467. break;
  468. }
  469. }
  470. break;
  471. case IMAGE_ROTATION: // command IR0* or IR90* or IR180* or IR270*
  472. if( strncasecmp( text, "0*", 2 ) == 0 )
  473. m_ImageRotation = 0;
  474. else if( strncasecmp( text, "90*", 3 ) == 0 )
  475. m_ImageRotation = 90;
  476. else if( strncasecmp( text, "180*", 4 ) == 0 )
  477. m_ImageRotation = 180;
  478. else if( strncasecmp( text, "270*", 4 ) == 0 )
  479. m_ImageRotation = 270;
  480. else
  481. AddMessageToList( _( "RS274X: Command \"IR\" rotation value not allowed" ) );
  482. break;
  483. case STEP_AND_REPEAT: // command SR, like %SRX3Y2I5.0J2*%
  484. m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
  485. GetLayerParams().m_StepForRepeat.x = 0.0;
  486. GetLayerParams().m_StepForRepeat.x = 0.0; // offset for Step and Repeat command
  487. GetLayerParams().m_XRepeatCount = 1;
  488. GetLayerParams().m_YRepeatCount = 1; // The repeat count
  489. GetLayerParams().m_StepForRepeatMetric = m_GerbMetric; // the step units
  490. while( *text && *text != '*' )
  491. {
  492. switch( *text )
  493. {
  494. case 'I': // X axis offset
  495. text++;
  496. GetLayerParams().m_StepForRepeat.x = ReadDouble( text );
  497. break;
  498. case 'J': // Y axis offset
  499. text++;
  500. GetLayerParams().m_StepForRepeat.y = ReadDouble( text );
  501. break;
  502. case 'X': // X axis repeat count
  503. text++;
  504. GetLayerParams().m_XRepeatCount = ReadInt( text );
  505. break;
  506. case 'Y': // Y axis offset
  507. text++;
  508. GetLayerParams().m_YRepeatCount = ReadInt( text );
  509. break;
  510. default:
  511. text++;
  512. break;
  513. }
  514. }
  515. break;
  516. case IMAGE_JUSTIFY: // Command IJAnBn*
  517. m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false)
  518. m_ImageJustifyYCenter = false; // Image Justify Center on Y axis (default = false)
  519. m_ImageJustifyOffset = wxPoint(0,0); // Image Justify Offset on XY axis (default = 0,0)
  520. while( *text && *text != '*' )
  521. {
  522. // IJ command is (for A or B axis) AC or AL or A<coordinate>
  523. switch( *text )
  524. {
  525. case 'A': // A axis justify
  526. text++;
  527. if( *text == 'C' )
  528. {
  529. m_ImageJustifyXCenter = true;
  530. text++;
  531. }
  532. else if( *text == 'L' )
  533. {
  534. m_ImageJustifyXCenter = true;
  535. text++;
  536. }
  537. else m_ImageJustifyOffset.x = KiROUND( ReadDouble( text ) * conv_scale);
  538. break;
  539. case 'B': // B axis justify
  540. text++;
  541. if( *text == 'C' )
  542. {
  543. m_ImageJustifyYCenter = true;
  544. text++;
  545. }
  546. else if( *text == 'L' )
  547. {
  548. m_ImageJustifyYCenter = true;
  549. text++;
  550. }
  551. else m_ImageJustifyOffset.y = KiROUND( ReadDouble( text ) * conv_scale);
  552. break;
  553. default:
  554. text++;
  555. break;
  556. }
  557. }
  558. if( m_ImageJustifyXCenter )
  559. m_ImageJustifyOffset.x = 0;
  560. if( m_ImageJustifyYCenter )
  561. m_ImageJustifyOffset.y = 0;
  562. break;
  563. case KNOCKOUT:
  564. m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
  565. msg = _( "RS274X: Command KNOCKOUT ignored by GerbView" ) ;
  566. AddMessageToList( msg );
  567. break;
  568. case ROTATE: // Layer rotation: command like %RO45*%
  569. m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Start a new Gerber layer
  570. m_LocalRotation =ReadDouble( text ); // Store layer rotation in degrees
  571. break;
  572. case IMAGE_NAME:
  573. m_ImageName.Empty();
  574. while( *text != '*' )
  575. {
  576. m_ImageName.Append( *text++ );
  577. }
  578. break;
  579. case LOAD_NAME:
  580. // %LN is a (deprecated) equivalentto G04: a comment
  581. while( *text && *text != '*' )
  582. {
  583. text++; // Skip text
  584. }
  585. break;
  586. case IMAGE_POLARITY:
  587. if( strncasecmp( text, "NEG", 3 ) == 0 )
  588. m_ImageNegative = true;
  589. else
  590. m_ImageNegative = false;
  591. DBG( printf( "%22s: IMAGE_POLARITY m_ImageNegative=%s\n", __func__,
  592. m_ImageNegative ? "true" : "false" ); )
  593. break;
  594. case LOAD_POLARITY:
  595. if( *text == 'C' )
  596. GetLayerParams().m_LayerNegative = true;
  597. else
  598. GetLayerParams().m_LayerNegative = false;
  599. break;
  600. case AP_MACRO: // lines like %AMMYMACRO*
  601. // 5,1,8,0,0,1.08239X$1,22.5*
  602. // %
  603. /*ok = */ReadApertureMacro( buff, text, m_Current_File );
  604. break;
  605. case AP_DEFINITION:
  606. /* input example: %ADD30R,0.081800X0.101500*%
  607. * Aperture definition has 4 options: C, R, O, P
  608. * (Circle, Rect, Oval, regular Polygon)
  609. * and shapes can have a hole (round or rectangular).
  610. * All optional parameters values start by X
  611. * at this point, text points to 2nd 'D'
  612. */
  613. if( *text++ != 'D' )
  614. {
  615. ok = false;
  616. break;
  617. }
  618. m_Has_DCode = true;
  619. code = ReadInt( text );
  620. D_CODE* dcode;
  621. dcode = GetDCODEOrCreate( code );
  622. if( dcode == NULL )
  623. break;
  624. dcode->m_AperFunction = m_AperFunction;
  625. // at this point, text points to character after the ADD<num>,
  626. // i.e. R in example above. If text[0] is one of the usual
  627. // apertures: (C,R,O,P), there is a comma after it.
  628. if( text[1] == ',' )
  629. {
  630. char stdAperture = *text;
  631. text += 2; // skip "C," for example
  632. dcode->m_Size.x = KiROUND( ReadDouble( text ) * conv_scale );
  633. dcode->m_Size.y = dcode->m_Size.x;
  634. switch( stdAperture ) // Aperture desceiption has optional parameters. Read them
  635. {
  636. case 'C': // Circle
  637. dcode->m_Shape = APT_CIRCLE;
  638. while( *text == ' ' )
  639. text++;
  640. if( *text == 'X' )
  641. {
  642. text++;
  643. dcode->m_Drill.x = dcode->m_Drill.y =
  644. KiROUND( ReadDouble( text ) * conv_scale );
  645. dcode->m_DrillShape = APT_DEF_ROUND_HOLE;
  646. }
  647. while( *text == ' ' )
  648. text++;
  649. if( *text == 'X' )
  650. {
  651. text++;
  652. dcode->m_Drill.y =
  653. KiROUND( ReadDouble( text ) * conv_scale );
  654. dcode->m_DrillShape = APT_DEF_RECT_HOLE;
  655. }
  656. dcode->m_Defined = true;
  657. break;
  658. case 'O': // oval
  659. case 'R': // rect
  660. dcode->m_Shape = (stdAperture == 'O') ? APT_OVAL : APT_RECT;
  661. while( *text == ' ' )
  662. text++;
  663. if( *text == 'X' )
  664. {
  665. text++;
  666. dcode->m_Size.y =
  667. KiROUND( ReadDouble( text ) * conv_scale );
  668. }
  669. while( *text == ' ' )
  670. text++;
  671. if( *text == 'X' )
  672. {
  673. text++;
  674. dcode->m_Drill.x = KiROUND( ReadDouble( text ) * conv_scale );
  675. dcode->m_Drill.y = dcode->m_Drill.x;
  676. dcode->m_DrillShape = APT_DEF_ROUND_HOLE;
  677. }
  678. while( *text == ' ' )
  679. text++;
  680. if( *text == 'X' )
  681. {
  682. text++;
  683. dcode->m_Drill.y =
  684. KiROUND( ReadDouble( text ) * conv_scale );
  685. dcode->m_DrillShape = APT_DEF_RECT_HOLE;
  686. }
  687. dcode->m_Defined = true;
  688. break;
  689. case 'P':
  690. /* Regular polygon: a command line like %ADD12P,0.040X10X25X0.025X0.025X0.0150*%
  691. * params are: <diameter>, X<edge count>, X<Rotation>, X<X hole dim>, X<Y hole dim>
  692. */
  693. dcode->m_Shape = APT_POLYGON;
  694. while( *text == ' ' )
  695. text++;
  696. if( *text == 'X' )
  697. {
  698. text++;
  699. dcode->m_EdgesCount = ReadInt( text );
  700. }
  701. while( *text == ' ' )
  702. text++;
  703. if( *text == 'X' )
  704. {
  705. text++;
  706. dcode->m_Rotation = ReadDouble( text );
  707. }
  708. while( *text == ' ' )
  709. text++;
  710. if( *text == 'X' )
  711. {
  712. text++;
  713. dcode->m_Drill.x = KiROUND( ReadDouble( text ) * conv_scale );
  714. dcode->m_Drill.y = dcode->m_Drill.x =
  715. dcode->m_DrillShape = APT_DEF_ROUND_HOLE;
  716. }
  717. while( *text == ' ' )
  718. text++;
  719. if( *text == 'X' )
  720. {
  721. text++;
  722. dcode->m_Drill.y = KiROUND( ReadDouble( text ) * conv_scale );
  723. dcode->m_DrillShape = APT_DEF_RECT_HOLE;
  724. }
  725. dcode->m_Defined = true;
  726. break;
  727. }
  728. }
  729. else // text[0] starts an aperture macro name
  730. {
  731. APERTURE_MACRO am_lookup;
  732. while( *text && *text != '*' && *text != ',' )
  733. am_lookup.name.Append( *text++ );
  734. // When an aperture definition is like %AMLINE2* 22,1,$1,$2,0,0,-45*
  735. // the ADDxx<MACRO_NAME> command has parameters, like %ADD14LINE2,0.8X0.5*%
  736. if( *text == ',' )
  737. { // Read aperture macro parameters and store them
  738. text++; // text points the first parameter
  739. while( *text && *text != '*' )
  740. {
  741. double param = ReadDouble( text );
  742. dcode->AppendParam( param );
  743. while( isspace( *text ) )
  744. text++;
  745. // Skip 'X' separator:
  746. if( *text == 'X' || *text == 'x' )
  747. text++;
  748. }
  749. }
  750. // lookup the aperture macro here.
  751. APERTURE_MACRO* pam = FindApertureMacro( am_lookup );
  752. if( !pam )
  753. {
  754. msg.Printf( wxT( "RS274X: aperture macro %s not found\n" ),
  755. TO_UTF8( am_lookup.name ) );
  756. AddMessageToList( msg );
  757. ok = false;
  758. break;
  759. }
  760. dcode->m_Shape = APT_MACRO;
  761. dcode->SetMacro( pam );
  762. }
  763. break;
  764. default:
  765. ok = false;
  766. break;
  767. }
  768. (void) seq_len; // quiet g++, or delete the unused variable.
  769. ok = GetEndOfBlock( buff, text, m_Current_File );
  770. return ok;
  771. }
  772. bool GERBER_FILE_IMAGE::GetEndOfBlock( char* buff, char*& text, FILE* gerber_file )
  773. {
  774. for( ; ; )
  775. {
  776. while( (text < buff + GERBER_BUFZ) && *text )
  777. {
  778. if( *text == '*' )
  779. return true;
  780. if( *text == '%' )
  781. return true;
  782. text++;
  783. }
  784. if( fgets( buff, GERBER_BUFZ, gerber_file ) == NULL )
  785. break;
  786. m_LineNum++;
  787. text = buff;
  788. }
  789. return false;
  790. }
  791. char* GERBER_FILE_IMAGE::GetNextLine( char *aBuff, char* aText, FILE* aFile )
  792. {
  793. for( ; ; )
  794. {
  795. switch (*aText )
  796. {
  797. case ' ': // skip blanks
  798. case '\n':
  799. case '\r': // Skip line terminators
  800. ++aText;
  801. break;
  802. case 0: // End of text found in aBuff: Read a new string
  803. if( fgets( aBuff, GERBER_BUFZ, aFile ) == NULL )
  804. return NULL;
  805. m_LineNum++;
  806. aText = aBuff;
  807. return aText;
  808. default:
  809. return aText;
  810. }
  811. }
  812. return aText;
  813. }
  814. bool GERBER_FILE_IMAGE::ReadApertureMacro( char *buff,
  815. char*& text,
  816. FILE* gerber_file )
  817. {
  818. wxString msg;
  819. APERTURE_MACRO am;
  820. // read macro name
  821. while( *text )
  822. {
  823. if( *text == '*' )
  824. {
  825. ++text;
  826. break;
  827. }
  828. am.name.Append( *text++ );
  829. }
  830. // Read aperture macro parameters
  831. for( ; ; )
  832. {
  833. if( *text == '*' )
  834. ++text;
  835. text = GetNextLine( buff, text, gerber_file );
  836. if( text == NULL ) // End of File
  837. return false;
  838. // text points the beginning of a new line.
  839. // Test for the last line in aperture macro lis:
  840. // last line is % or *% sometime found.
  841. if( *text == '*' )
  842. ++text;
  843. if( *text == '%' )
  844. break; // exit with text still pointing at %
  845. int paramCount = 0; // will be set to the minimal parameters count,
  846. // depending on the actual primitive
  847. int primitive_type = AMP_UNKNOWN;
  848. // Test for a valid symbol at the beginning of a description:
  849. // it can be: a parameter declaration like $1=$2/4
  850. // or a digit (macro primitive selection)
  851. // all other symbols are illegal.
  852. if( *text == '$' ) // local parameter declaration, inside the aperture macro
  853. {
  854. am.m_localparamStack.push_back( AM_PARAM() );
  855. AM_PARAM& param = am.m_localparamStack.back();
  856. text = GetNextLine( buff, text, gerber_file );
  857. if( text == NULL) // End of File
  858. return false;
  859. param.ReadParam( text );
  860. continue;
  861. }
  862. else if( !isdigit(*text) ) // Ill. symbol
  863. {
  864. msg.Printf( wxT( "RS274X: Aperture Macro \"%s\": ill. symbol, line: \"%s\"" ),
  865. GetChars( am.name ), GetChars( FROM_UTF8( buff ) ) );
  866. AddMessageToList( msg );
  867. primitive_type = AMP_COMMENT;
  868. }
  869. else
  870. primitive_type = ReadInt( text );
  871. bool is_comment = false;
  872. switch( primitive_type )
  873. {
  874. case AMP_COMMENT: // lines starting by 0 are a comment
  875. paramCount = 0;
  876. is_comment = true;
  877. // Skip comment
  878. while( *text && ( *text != '*' ) )
  879. text++;
  880. break;
  881. case AMP_CIRCLE:
  882. paramCount = 4; // minimal count. can have a optional parameter (rotation)
  883. break;
  884. case AMP_LINE2:
  885. case AMP_LINE20:
  886. paramCount = 7;
  887. break;
  888. case AMP_LINE_CENTER:
  889. case AMP_LINE_LOWER_LEFT:
  890. paramCount = 6;
  891. break;
  892. case AMP_EOF:
  893. paramCount = 0;
  894. break;
  895. case AMP_OUTLINE:
  896. paramCount = 4;
  897. break;
  898. case AMP_POLYGON:
  899. paramCount = 6;
  900. break;
  901. case AMP_MOIRE:
  902. paramCount = 9;
  903. break;
  904. case AMP_THERMAL:
  905. paramCount = 6;
  906. break;
  907. default:
  908. msg.Printf( wxT( "RS274X: Aperture Macro \"%s\": Invalid primitive id code %d, line %d: \"%s\"" ),
  909. GetChars( am.name ), primitive_type, m_LineNum, GetChars( FROM_UTF8( buff ) ) );
  910. AddMessageToList( msg );
  911. return false;
  912. }
  913. if( is_comment )
  914. continue;
  915. AM_PRIMITIVE prim( m_GerbMetric );
  916. prim.primitive_id = (AM_PRIMITIVE_ID) primitive_type;
  917. int ii;
  918. for( ii = 0; ii < *text && *text != '*'; ++ii )
  919. {
  920. prim.params.push_back( AM_PARAM() );
  921. AM_PARAM& param = prim.params.back();
  922. text = GetNextLine( buff, text, gerber_file );
  923. if( text == NULL) // End of File
  924. return false;
  925. param.ReadParam( text );
  926. }
  927. if( ii < paramCount )
  928. {
  929. // maybe some day we can throw an exception and track a line number
  930. msg.Printf( wxT( "RS274X: read macro descr type %d: read %d parameters, insufficient parameters\n" ),
  931. prim.primitive_id, ii );
  932. AddMessageToList( msg );
  933. }
  934. // there are more parameters to read if this is an AMP_OUTLINE
  935. if( prim.primitive_id == AMP_OUTLINE )
  936. {
  937. // so far we have read [0]:exposure, [1]:#points, [2]:X start, [3]: Y start
  938. // Now read all the points, plus trailing rotation in degrees.
  939. // params[1] is a count of polygon points, so it must be given
  940. // in advance, i.e. be immediate.
  941. wxASSERT( prim.params[1].IsImmediate() );
  942. paramCount = (int) prim.params[1].GetValue( 0 ) * 2 + 1;
  943. for( int jj = 0; jj < paramCount && *text != '*'; ++jj )
  944. {
  945. prim.params.push_back( AM_PARAM() );
  946. AM_PARAM& param = prim.params.back();
  947. text = GetNextLine( buff, text, gerber_file );
  948. if( text == NULL ) // End of File
  949. return false;
  950. param.ReadParam( text );
  951. }
  952. }
  953. am.primitives.push_back( prim );
  954. }
  955. m_aperture_macros.insert( am );
  956. return true;
  957. }