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.

325 lines
9.2 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
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2010-2014 Jean-Pierre Charras jp.charras at wanadoo.fr
  5. * Copyright (C) 1992-2014 KiCad Developers, see change_log.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. #include <fctsys.h>
  25. #include <common.h>
  26. #include <gerber_file_image.h>
  27. #include <base_units.h>
  28. /* These routines read the text string point from Text.
  29. * On exit, Text points the beginning of the sequence unread
  30. */
  31. // convertion scale from gerber file units to Gerbview internal units
  32. // depending on the gerber file format
  33. // this scale list assumes gerber units are imperial.
  34. // for metric gerber units, the imperial to metric conversion is made in read functions
  35. #define SCALE_LIST_SIZE 9
  36. static double scale_list[SCALE_LIST_SIZE] =
  37. {
  38. 1000.0 * IU_PER_MILS, // x.1 format (certainly useless)
  39. 100.0 * IU_PER_MILS, // x.2 format (certainly useless)
  40. 10.0 * IU_PER_MILS, // x.3 format
  41. 1.0 * IU_PER_MILS, // x.4 format
  42. 0.1 * IU_PER_MILS, // x.5 format
  43. 0.01 * IU_PER_MILS, // x.6 format
  44. 0.001 * IU_PER_MILS, // x.7 format (currently the max allowed precision)
  45. 0.0001 * IU_PER_MILS, // provided, but not used
  46. 0.00001 * IU_PER_MILS, // provided, but not used
  47. };
  48. /*
  49. * Function scale
  50. * converts a coordinate given in floating point to Gerbvies internal units
  51. * (currently = 10 nanometers)
  52. */
  53. int scaletoIU( double aCoord, bool isMetric )
  54. {
  55. int ret;
  56. if( isMetric ) // gerber are units in mm
  57. ret = KiROUND( aCoord * IU_PER_MM );
  58. else // gerber are units in inches
  59. ret = KiROUND( aCoord * IU_PER_MILS * 1000.0 );
  60. return ret;
  61. }
  62. wxPoint GERBER_FILE_IMAGE::ReadXYCoord( char*& Text )
  63. {
  64. wxPoint pos;
  65. int type_coord = 0, current_coord, nbdigits;
  66. bool is_float = false;
  67. char* text;
  68. char line[256];
  69. if( m_Relative )
  70. pos.x = pos.y = 0;
  71. else
  72. pos = m_CurrentPos;
  73. if( Text == NULL )
  74. return pos;
  75. text = line;
  76. while( *Text )
  77. {
  78. if( (*Text == 'X') || (*Text == 'Y') )
  79. {
  80. type_coord = *Text;
  81. Text++;
  82. text = line;
  83. nbdigits = 0;
  84. while( IsNumber( *Text ) )
  85. {
  86. if( *Text == '.' ) // Force decimat format if reading a floating point number
  87. is_float = true;
  88. // count digits only (sign and decimal point are not counted)
  89. if( (*Text >= '0') && (*Text <='9') )
  90. nbdigits++;
  91. *(text++) = *(Text++);
  92. }
  93. *text = 0;
  94. if( is_float )
  95. {
  96. // When X or Y values are float numbers, they are given in mm or inches
  97. if( m_GerbMetric ) // units are mm
  98. current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
  99. else // units are inches
  100. current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
  101. }
  102. else
  103. {
  104. int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
  105. if( m_NoTrailingZeros )
  106. {
  107. int min_digit =
  108. (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
  109. while( nbdigits < min_digit )
  110. {
  111. *(text++) = '0';
  112. nbdigits++;
  113. }
  114. *text = 0;
  115. }
  116. current_coord = atoi( line );
  117. double real_scale = scale_list[fmt_scale];
  118. if( m_GerbMetric )
  119. real_scale = real_scale / 25.4;
  120. current_coord = KiROUND( current_coord * real_scale );
  121. }
  122. if( type_coord == 'X' )
  123. pos.x = current_coord;
  124. else if( type_coord == 'Y' )
  125. pos.y = current_coord;
  126. continue;
  127. }
  128. else
  129. break;
  130. }
  131. if( m_Relative )
  132. {
  133. pos.x += m_CurrentPos.x;
  134. pos.y += m_CurrentPos.y;
  135. }
  136. m_CurrentPos = pos;
  137. return pos;
  138. }
  139. /* Returns the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
  140. * These coordinates are relative, so if coordinate is absent, it's value
  141. * defaults to 0
  142. */
  143. wxPoint GERBER_FILE_IMAGE::ReadIJCoord( char*& Text )
  144. {
  145. wxPoint pos( 0, 0 );
  146. int type_coord = 0, current_coord, nbdigits;
  147. bool is_float = false;
  148. char* text;
  149. char line[256];
  150. if( Text == NULL )
  151. return pos;
  152. text = line;
  153. while( *Text )
  154. {
  155. if( (*Text == 'I') || (*Text == 'J') )
  156. {
  157. type_coord = *Text;
  158. Text++;
  159. text = line;
  160. nbdigits = 0;
  161. while( IsNumber( *Text ) )
  162. {
  163. if( *Text == '.' )
  164. is_float = true;
  165. // count digits only (sign and decimal point are not counted)
  166. if( (*Text >= '0') && (*Text <='9') )
  167. nbdigits++;
  168. *(text++) = *(Text++);
  169. }
  170. *text = 0;
  171. if( is_float )
  172. {
  173. // When X or Y values are float numbers, they are given in mm or inches
  174. if( m_GerbMetric ) // units are mm
  175. current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
  176. else // units are inches
  177. current_coord = KiROUND( atof( line ) * IU_PER_MILS * 1000 );
  178. }
  179. else
  180. {
  181. int fmt_scale =
  182. (type_coord == 'I') ? m_FmtScale.x : m_FmtScale.y;
  183. if( m_NoTrailingZeros )
  184. {
  185. int min_digit =
  186. (type_coord == 'I') ? m_FmtLen.x : m_FmtLen.y;
  187. while( nbdigits < min_digit )
  188. {
  189. *(text++) = '0';
  190. nbdigits++;
  191. }
  192. *text = 0;
  193. }
  194. current_coord = atoi( line );
  195. double real_scale = scale_list[fmt_scale];
  196. if( m_GerbMetric )
  197. real_scale = real_scale / 25.4;
  198. current_coord = KiROUND( current_coord * real_scale );
  199. }
  200. if( type_coord == 'I' )
  201. pos.x = current_coord;
  202. else if( type_coord == 'J' )
  203. pos.y = current_coord;
  204. continue;
  205. }
  206. else
  207. break;
  208. }
  209. m_IJPos = pos;
  210. return pos;
  211. }
  212. // Helper functions:
  213. /**
  214. * Function ReadInt
  215. * reads an int from an ASCII character buffer. If there is a comma after the
  216. * int, then skip over that.
  217. * @param text A reference to a character pointer from which bytes are read
  218. * and the pointer is advanced for each byte read.
  219. * @param aSkipSeparator = true (default) to skip comma
  220. * @return int - The int read in.
  221. */
  222. int ReadInt( char*& text, bool aSkipSeparator = true )
  223. {
  224. int ret;
  225. // For strtol, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
  226. // However, 'X' is a separator in Gerber strings with numbers.
  227. // We need to detect that
  228. if( strncasecmp( text, "0X", 2 ) == 0 )
  229. {
  230. text++;
  231. ret = 0;
  232. }
  233. else
  234. ret = (int) strtol( text, &text, 10 );
  235. if( *text == ',' || isspace( *text ) )
  236. {
  237. if( aSkipSeparator )
  238. ++text;
  239. }
  240. return ret;
  241. }
  242. /**
  243. * Function ReadDouble
  244. * reads a double from an ASCII character buffer. If there is a comma after
  245. * the double, then skip over that.
  246. * @param text A reference to a character pointer from which the ASCII double
  247. * is read from and the pointer advanced for each character read.
  248. * @param aSkipSeparator = true (default) to skip comma
  249. * @return double
  250. */
  251. double ReadDouble( char*& text, bool aSkipSeparator = true )
  252. {
  253. double ret;
  254. // For strtod, a string starting by 0X or 0x is a valid number in hexadecimal or octal.
  255. // However, 'X' is a separator in Gerber strings with numbers.
  256. // We need to detect that
  257. if( strncasecmp( text, "0X", 2 ) == 0 )
  258. {
  259. text++;
  260. ret = 0.0;
  261. }
  262. else
  263. ret = strtod( text, &text );
  264. if( *text == ',' || isspace( *text ) )
  265. {
  266. if( aSkipSeparator )
  267. ++text;
  268. }
  269. return ret;
  270. }