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.

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