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.

470 lines
13 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
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2009 Jean-Pierre Charras, jean-pierre.charras@gipsa-lab.inpg.fr
  5. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file dcode.cpp
  27. * @brief D_CODE class implementation
  28. */
  29. #include <fctsys.h>
  30. #include <common.h>
  31. #include <class_drawpanel.h>
  32. #include <trigo.h>
  33. #include <gerbview_frame.h>
  34. #include <class_gerber_file_image.h>
  35. #include <convert_to_biu.h>
  36. #define DCODE_DEFAULT_SIZE Millimeter2iu( 0.1 )
  37. /* Format Gerber: NOTES:
  38. * Tools and D_CODES
  39. * tool number (identification of shapes)
  40. * 1 to 999
  41. *
  42. * D_CODES:
  43. * D01 ... D9 = command codes:
  44. * D01 = activating light (pen down) while moving
  45. * D02 = light extinction (pen up) while moving
  46. * D03 = Flash
  47. * D04 to D09 = non used
  48. * D10 ... D999 = Identification Tool (Shape id)
  49. *
  50. * For tools defining a shape):
  51. * DCode min = D10
  52. * DCode max = 999
  53. */
  54. /***************/
  55. /* Class DCODE */
  56. /***************/
  57. D_CODE::D_CODE( int num_dcode )
  58. {
  59. m_Num_Dcode = num_dcode;
  60. Clear_D_CODE_Data();
  61. }
  62. D_CODE::~D_CODE()
  63. {
  64. }
  65. void D_CODE::Clear_D_CODE_Data()
  66. {
  67. m_Size.x = DCODE_DEFAULT_SIZE;
  68. m_Size.y = DCODE_DEFAULT_SIZE;
  69. m_Shape = APT_CIRCLE;
  70. m_Drill.x = m_Drill.y = 0;
  71. m_DrillShape = APT_DEF_NO_HOLE;
  72. m_InUse = false;
  73. m_Defined = false;
  74. m_Macro = NULL;
  75. m_Rotation = 0.0;
  76. m_EdgesCount = 0;
  77. m_PolyCorners.clear();
  78. }
  79. const wxChar* D_CODE::ShowApertureType( APERTURE_T aType )
  80. {
  81. const wxChar* ret;
  82. switch( aType )
  83. {
  84. case APT_CIRCLE:
  85. ret = wxT( "Round" ); break;
  86. case APT_RECT:
  87. ret = wxT( "Rect" ); break;
  88. case APT_OVAL:
  89. ret = wxT( "Oval" ); break;
  90. case APT_POLYGON:
  91. ret = wxT( "Poly" ); break;
  92. case APT_MACRO:
  93. ret = wxT( "Macro" ); break;
  94. default:
  95. ret = wxT( "???" ); break;
  96. }
  97. return ret;
  98. }
  99. int D_CODE::GetShapeDim( GERBER_DRAW_ITEM* aParent )
  100. {
  101. int dim = -1;
  102. switch( m_Shape )
  103. {
  104. case APT_CIRCLE:
  105. dim = m_Size.x;
  106. break;
  107. case APT_RECT:
  108. case APT_OVAL:
  109. dim = std::min( m_Size.x, m_Size.y );
  110. break;
  111. case APT_POLYGON:
  112. dim = std::min( m_Size.x, m_Size.y );
  113. break;
  114. case APT_MACRO:
  115. if( m_Macro )
  116. dim = m_Macro->GetShapeDim( aParent );
  117. break;
  118. default:
  119. break;
  120. }
  121. return dim;
  122. }
  123. void D_CODE::DrawFlashedShape( GERBER_DRAW_ITEM* aParent,
  124. EDA_RECT* aClipBox, wxDC* aDC, EDA_COLOR_T aColor,
  125. EDA_COLOR_T aAltColor,
  126. wxPoint aShapePos, bool aFilledShape )
  127. {
  128. int radius;
  129. switch( m_Shape )
  130. {
  131. case APT_MACRO:
  132. GetMacro()->DrawApertureMacroShape( aParent, aClipBox, aDC, aColor, aAltColor,
  133. aShapePos, aFilledShape);
  134. break;
  135. case APT_CIRCLE:
  136. radius = m_Size.x >> 1;
  137. if( !aFilledShape )
  138. GRCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos), radius, 0, aColor );
  139. else
  140. if( m_DrillShape == APT_DEF_NO_HOLE )
  141. {
  142. GRFilledCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos),
  143. radius, aColor );
  144. }
  145. else if( APT_DEF_ROUND_HOLE == 1 ) // round hole in shape
  146. {
  147. int width = (m_Size.x - m_Drill.x ) / 2;
  148. GRCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos),
  149. radius - (width / 2), width, aColor );
  150. }
  151. else // rectangular hole
  152. {
  153. if( m_PolyCorners.size() == 0 )
  154. ConvertShapeToPolygon();
  155. DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
  156. }
  157. break;
  158. case APT_RECT:
  159. {
  160. wxPoint start;
  161. start.x = aShapePos.x - m_Size.x / 2;
  162. start.y = aShapePos.y - m_Size.y / 2;
  163. wxPoint end = start + m_Size;
  164. start = aParent->GetABPosition( start );
  165. end = aParent->GetABPosition( end );
  166. if( !aFilledShape )
  167. {
  168. GRRect( aClipBox, aDC, start.x, start.y, end.x, end.y, 0, aColor );
  169. }
  170. else if( m_DrillShape == APT_DEF_NO_HOLE )
  171. {
  172. GRFilledRect( aClipBox, aDC, start.x, start.y, end.x, end.y, 0, aColor, aColor );
  173. }
  174. else
  175. {
  176. if( m_PolyCorners.size() == 0 )
  177. ConvertShapeToPolygon();
  178. DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
  179. }
  180. }
  181. break;
  182. case APT_OVAL:
  183. {
  184. wxPoint start = aShapePos;
  185. wxPoint end = aShapePos;
  186. if( m_Size.x > m_Size.y ) // horizontal oval
  187. {
  188. int delta = (m_Size.x - m_Size.y) / 2;
  189. start.x -= delta;
  190. end.x += delta;
  191. radius = m_Size.y;
  192. }
  193. else // horizontal oval
  194. {
  195. int delta = (m_Size.y - m_Size.x) / 2;
  196. start.y -= delta;
  197. end.y += delta;
  198. radius = m_Size.x;
  199. }
  200. start = aParent->GetABPosition( start );
  201. end = aParent->GetABPosition( end );
  202. if( !aFilledShape )
  203. {
  204. GRCSegm( aClipBox, aDC, start.x, start.y, end.x, end.y, radius, aColor );
  205. }
  206. else if( m_DrillShape == APT_DEF_NO_HOLE )
  207. {
  208. GRFillCSegm( aClipBox, aDC, start.x, start.y, end.x, end.y, radius, aColor );
  209. }
  210. else
  211. {
  212. if( m_PolyCorners.size() == 0 )
  213. ConvertShapeToPolygon();
  214. DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
  215. }
  216. }
  217. break;
  218. case APT_POLYGON:
  219. if( m_PolyCorners.size() == 0 )
  220. ConvertShapeToPolygon();
  221. DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
  222. break;
  223. }
  224. }
  225. void D_CODE::DrawFlashedPolygon( GERBER_DRAW_ITEM* aParent,
  226. EDA_RECT* aClipBox, wxDC* aDC,
  227. EDA_COLOR_T aColor, bool aFilled,
  228. const wxPoint& aPosition )
  229. {
  230. if( m_PolyCorners.size() == 0 )
  231. return;
  232. std::vector<wxPoint> points;
  233. points = m_PolyCorners;
  234. for( unsigned ii = 0; ii < points.size(); ii++ )
  235. {
  236. points[ii] += aPosition;
  237. points[ii] = aParent->GetABPosition( points[ii] );
  238. }
  239. GRClosedPoly( aClipBox, aDC, points.size(), &points[0], aFilled, aColor, aColor );
  240. }
  241. #define SEGS_CNT 32 // number of segments to approximate a circle
  242. // A helper function for D_CODE::ConvertShapeToPolygon(). Add a hole to a polygon
  243. static void addHoleToPolygon( std::vector<wxPoint>& aBuffer,
  244. APERTURE_DEF_HOLETYPE aHoleShape,
  245. wxSize aSize,
  246. wxPoint aAnchorPos );
  247. void D_CODE::ConvertShapeToPolygon()
  248. {
  249. wxPoint initialpos;
  250. wxPoint currpos;
  251. m_PolyCorners.clear();
  252. switch( m_Shape )
  253. {
  254. case APT_CIRCLE: // creates only a circle with rectangular hole
  255. currpos.x = m_Size.x >> 1;
  256. initialpos = currpos;
  257. for( unsigned ii = 0; ii <= SEGS_CNT; ii++ )
  258. {
  259. currpos = initialpos;
  260. RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT );
  261. m_PolyCorners.push_back( currpos );
  262. }
  263. addHoleToPolygon( m_PolyCorners, m_DrillShape, m_Drill, initialpos );
  264. break;
  265. case APT_RECT:
  266. currpos.x = m_Size.x / 2;
  267. currpos.y = m_Size.y / 2;
  268. initialpos = currpos;
  269. m_PolyCorners.push_back( currpos );
  270. currpos.x -= m_Size.x;
  271. m_PolyCorners.push_back( currpos );
  272. currpos.y -= m_Size.y;
  273. m_PolyCorners.push_back( currpos );
  274. currpos.x += m_Size.x;
  275. m_PolyCorners.push_back( currpos );
  276. currpos.y += m_Size.y;
  277. m_PolyCorners.push_back( currpos ); // close polygon
  278. addHoleToPolygon( m_PolyCorners, m_DrillShape, m_Drill, initialpos );
  279. break;
  280. case APT_OVAL:
  281. {
  282. int delta, radius;
  283. // we create an horizontal oval shape. then rotate if needed
  284. if( m_Size.x > m_Size.y ) // horizontal oval
  285. {
  286. delta = (m_Size.x - m_Size.y) / 2;
  287. radius = m_Size.y / 2;
  288. }
  289. else // vertical oval
  290. {
  291. delta = (m_Size.y - m_Size.x) / 2;
  292. radius = m_Size.x / 2;
  293. }
  294. currpos.y = radius;
  295. initialpos = currpos;
  296. m_PolyCorners.push_back( currpos );
  297. // build the right arc of the shape
  298. unsigned ii = 0;
  299. for( ; ii <= SEGS_CNT / 2; ii++ )
  300. {
  301. currpos = initialpos;
  302. RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT );
  303. currpos.x += delta;
  304. m_PolyCorners.push_back( currpos );
  305. }
  306. // build the left arc of the shape
  307. for( ii = SEGS_CNT / 2; ii <= SEGS_CNT; ii++ )
  308. {
  309. currpos = initialpos;
  310. RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT );
  311. currpos.x -= delta;
  312. m_PolyCorners.push_back( currpos );
  313. }
  314. m_PolyCorners.push_back( initialpos ); // close outline
  315. if( m_Size.y > m_Size.x ) // vertical oval, rotate polygon.
  316. {
  317. for( unsigned jj = 0; jj < m_PolyCorners.size(); jj++ )
  318. RotatePoint( &m_PolyCorners[jj], 900 );
  319. }
  320. addHoleToPolygon( m_PolyCorners, m_DrillShape, m_Drill, initialpos );
  321. }
  322. break;
  323. case APT_POLYGON:
  324. currpos.x = m_Size.x >> 1; // first point is on X axis
  325. initialpos = currpos;
  326. // rs274x said: m_EdgesCount = 3 ... 12
  327. if( m_EdgesCount < 3 )
  328. m_EdgesCount = 3;
  329. if( m_EdgesCount > 12 )
  330. m_EdgesCount = 12;
  331. for( int ii = 0; ii <= m_EdgesCount; ii++ )
  332. {
  333. currpos = initialpos;
  334. RotatePoint( &currpos, ii * 3600.0 / m_EdgesCount );
  335. m_PolyCorners.push_back( currpos );
  336. }
  337. addHoleToPolygon( m_PolyCorners, m_DrillShape, m_Drill, initialpos );
  338. if( m_Rotation ) // vertical oval, rotate polygon.
  339. {
  340. int angle = KiROUND( m_Rotation * 10 );
  341. for( unsigned jj = 0; jj < m_PolyCorners.size(); jj++ )
  342. {
  343. RotatePoint( &m_PolyCorners[jj], -angle );
  344. }
  345. }
  346. break;
  347. case APT_MACRO:
  348. // TODO
  349. break;
  350. }
  351. }
  352. // The helper function for D_CODE::ConvertShapeToPolygon().
  353. // Add a hole to a polygon
  354. static void addHoleToPolygon( std::vector<wxPoint>& aBuffer,
  355. APERTURE_DEF_HOLETYPE aHoleShape,
  356. wxSize aSize,
  357. wxPoint aAnchorPos )
  358. {
  359. wxPoint currpos;
  360. if( aHoleShape == APT_DEF_ROUND_HOLE ) // build a round hole
  361. {
  362. for( int ii = 0; ii <= SEGS_CNT; ii++ )
  363. {
  364. currpos.x = 0;
  365. currpos.y = aSize.x / 2; // aSize.x / 2 is the radius of the hole
  366. RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT );
  367. aBuffer.push_back( currpos );
  368. }
  369. aBuffer.push_back( aAnchorPos ); // link to outline
  370. }
  371. if( aHoleShape == APT_DEF_RECT_HOLE ) // Create rectangular hole
  372. {
  373. currpos.x = aSize.x / 2;
  374. currpos.y = aSize.y / 2;
  375. aBuffer.push_back( currpos ); // link to hole and begin hole
  376. currpos.x -= aSize.x;
  377. aBuffer.push_back( currpos );
  378. currpos.y -= aSize.y;
  379. aBuffer.push_back( currpos );
  380. currpos.x += aSize.x;
  381. aBuffer.push_back( currpos );
  382. currpos.y += aSize.y;
  383. aBuffer.push_back( currpos ); // close hole
  384. aBuffer.push_back( aAnchorPos ); // link to outline
  385. }
  386. }