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.

811 lines
28 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. * @file class_aperture_macro.cpp
  3. */
  4. /*
  5. * This program source code file is part of KiCad, a free EDA CAD application.
  6. *
  7. * Copyright (C) 1992-2010 Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
  8. * Copyright (C) 2010 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  9. * Copyright (C) 1992-2010 KiCad Developers, see change_log.txt for contributors.
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version 2
  14. * of the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, you may find one here:
  23. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  24. * or you may search the http://www.gnu.org website for the version 2 license,
  25. * or you may write to the Free Software Foundation, Inc.,
  26. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  27. */
  28. #include <fctsys.h>
  29. #include <common.h>
  30. #include <macros.h>
  31. #include <trigo.h>
  32. #include <gr_basic.h>
  33. #include <gerbview.h>
  34. #include <class_GERBER.h>
  35. /**
  36. * Function scaletoIU
  37. * converts a distance given in floating point to our internal units
  38. */
  39. extern int scaletoIU( double aCoord, bool isMetric ); // defined it rs274d_read_XY_and_IJ_coordiantes.cpp
  40. /**
  41. * Function mapPt
  42. * translates a point from the aperture macro coordinate system to our
  43. * deci-mils coordinate system.
  44. * @return wxPoint - The GerbView coordinate system vector.
  45. */
  46. static wxPoint mapPt( double x, double y, bool isMetric )
  47. {
  48. wxPoint ret( scaletoIU( x, isMetric ), scaletoIU( y, isMetric ) );
  49. return ret;
  50. }
  51. /**
  52. * Function mapExposure
  53. * translates the first parameter from an aperture macro into a current
  54. * exposure setting.
  55. * @param aParent = a GERBER_DRAW_ITEM that handle:
  56. * ** m_Exposure A dynamic setting which can change throughout the
  57. * reading of the gerber file, and it indicates whether the current tool
  58. * is lit or not.
  59. * ** m_ImageNegative A dynamic setting which can change throughout the reading
  60. * of the gerber file, and it indicates whether the current D codes are to
  61. * be interpreted as erasures or not.
  62. * @return true to draw with current color, false to draw with alt color (erase)
  63. */
  64. bool AM_PRIMITIVE::mapExposure( GERBER_DRAW_ITEM* aParent )
  65. {
  66. bool exposure;
  67. switch( primitive_id )
  68. {
  69. case AMP_CIRCLE:
  70. case AMP_LINE2:
  71. case AMP_LINE20:
  72. case AMP_LINE_CENTER:
  73. case AMP_LINE_LOWER_LEFT:
  74. case AMP_OUTLINE:
  75. case AMP_THERMAL:
  76. case AMP_POLYGON:
  77. // All have an exposure parameter and can return true or false
  78. switch( GetExposure(aParent) )
  79. {
  80. case 0: // exposure always OFF
  81. exposure = false;
  82. break;
  83. default:
  84. case 1: // exposure always OON
  85. exposure = true;
  86. break;
  87. case 2: // reverse exposure
  88. exposure = !aParent->GetLayerPolarity();
  89. }
  90. break;
  91. case AMP_MOIRE:
  92. case AMP_EOF:
  93. case AMP_UNKNOWN:
  94. default:
  95. return true; // All have no exposure parameter and must return true (no change for exposure)
  96. break;
  97. }
  98. return exposure ^ aParent->m_imageParams->m_ImageNegative;
  99. }
  100. /**
  101. * Function GetExposure
  102. * returns the first parameter in integer form. Some but not all primitives
  103. * use the first parameter as an exposure control.
  104. */
  105. int AM_PRIMITIVE::GetExposure(GERBER_DRAW_ITEM* aParent) const
  106. {
  107. // No D_CODE* for GetValue()
  108. wxASSERT( params.size() && params[0].IsImmediate() );
  109. return (int) params[0].GetValue( aParent->GetDcodeDescr() );
  110. }
  111. /**
  112. * Function DrawBasicShape
  113. * Draw the primitive shape for flashed items.
  114. */
  115. void AM_PRIMITIVE::DrawBasicShape( GERBER_DRAW_ITEM* aParent,
  116. EDA_RECT* aClipBox,
  117. wxDC* aDC,
  118. EDA_COLOR_T aColor, EDA_COLOR_T aAltColor,
  119. wxPoint aShapePos,
  120. bool aFilledShape )
  121. {
  122. static std::vector<wxPoint> polybuffer; // create a static buffer to avoid a lot of memory reallocation
  123. polybuffer.clear();
  124. wxPoint curPos = aShapePos;
  125. D_CODE* tool = aParent->GetDcodeDescr();
  126. double rotation;
  127. if( mapExposure( aParent ) == false )
  128. {
  129. EXCHG(aColor, aAltColor);
  130. }
  131. switch( primitive_id )
  132. {
  133. case AMP_CIRCLE: // Circle, given diameter and position
  134. {
  135. /* Generated by an aperture macro declaration like:
  136. * "1,1,0.3,0.5, 1.0*"
  137. * type (1), exposure, diameter, pos.x, pos.y
  138. * type is not stored in parameters list, so the first parameter is exposure
  139. */
  140. curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
  141. curPos = aParent->GetABPosition( curPos );
  142. int radius = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ) / 2;
  143. if( !aFilledShape )
  144. GRCircle( aClipBox, aDC, curPos, radius, 0, aColor );
  145. else
  146. GRFilledCircle( aClipBox, aDC, curPos, radius, aColor );
  147. }
  148. break;
  149. case AMP_LINE2:
  150. case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
  151. {
  152. /* Generated by an aperture macro declaration like:
  153. * "2,1,0.3,0,0, 0.5, 1.0,-135*"
  154. * type (2), exposure, width, start.x, start.y, end.x, end.y, rotation
  155. * type is not stored in parameters list, so the first parameter is exposure
  156. */
  157. ConvertShapeToPolygon( aParent, polybuffer );
  158. // shape rotation:
  159. rotation = params[6].GetValue( tool ) * 10.0;
  160. if( rotation != 0)
  161. {
  162. for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
  163. RotatePoint( &polybuffer[ii], -rotation );
  164. }
  165. // Move to current position:
  166. for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
  167. {
  168. polybuffer[ii] += curPos;
  169. polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
  170. }
  171. GRClosedPoly( aClipBox, aDC,
  172. polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
  173. }
  174. break;
  175. case AMP_LINE_CENTER:
  176. {
  177. /* Generated by an aperture macro declaration like:
  178. * "21,1,0.3,0.03,0,0,-135*"
  179. * type (21), exposure, ,width, height, center pos.x, center pos.y, rotation
  180. * type is not stored in parameters list, so the first parameter is exposure
  181. */
  182. ConvertShapeToPolygon( aParent, polybuffer );
  183. // shape rotation:
  184. rotation = params[5].GetValue( tool ) * 10.0;
  185. if( rotation != 0 )
  186. {
  187. for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
  188. RotatePoint( &polybuffer[ii], -rotation );
  189. }
  190. // Move to current position:
  191. for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
  192. {
  193. polybuffer[ii] += curPos;
  194. polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
  195. }
  196. GRClosedPoly( aClipBox, aDC,
  197. polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
  198. }
  199. break;
  200. case AMP_LINE_LOWER_LEFT:
  201. {
  202. /* Generated by an aperture macro declaration like:
  203. * "22,1,0.3,0.03,0,0,-135*"
  204. * type (22), exposure, ,width, height, corner pos.x, corner pos.y, rotation
  205. * type is not stored in parameters list, so the first parameter is exposure
  206. */
  207. ConvertShapeToPolygon( aParent, polybuffer );
  208. // shape rotation:
  209. rotation = params[5].GetValue( tool ) * 10.0;
  210. if( rotation != 0)
  211. {
  212. for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
  213. RotatePoint( &polybuffer[ii], -rotation );
  214. }
  215. // Move to current position:
  216. for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
  217. {
  218. polybuffer[ii] += curPos;
  219. polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
  220. }
  221. GRClosedPoly( aClipBox, aDC,
  222. polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
  223. }
  224. break;
  225. case AMP_THERMAL:
  226. {
  227. /* Generated by an aperture macro declaration like:
  228. * "7, 0,0,1.0,0.3,0.01,-13*"
  229. * type (7), center.x , center.y, outside diam, inside diam, crosshair thickness, rotation
  230. * type is not stored in parameters list, so the first parameter is center.x
  231. */
  232. curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ), m_GerbMetric );
  233. ConvertShapeToPolygon( aParent, polybuffer );
  234. // shape rotation:
  235. rotation = params[5].GetValue( tool ) * 10.0;
  236. // Because a thermal shape has 4 identical sub-shapes, only one is created in polybuffer.
  237. // We must draw 4 sub-shapes rotated by 90 deg
  238. std::vector<wxPoint> subshape_poly;
  239. for( int ii = 0; ii < 4; ii++ )
  240. {
  241. subshape_poly = polybuffer;
  242. double sub_rotation = rotation + 900 * ii;
  243. for( unsigned jj = 0; jj < subshape_poly.size(); jj++ )
  244. RotatePoint( &subshape_poly[jj], -sub_rotation );
  245. // Move to current position:
  246. for( unsigned jj = 0; jj < subshape_poly.size(); jj++ )
  247. {
  248. subshape_poly[jj] += curPos;
  249. subshape_poly[jj] = aParent->GetABPosition( subshape_poly[jj] );
  250. }
  251. GRClosedPoly( aClipBox, aDC,
  252. subshape_poly.size(), &subshape_poly[0], true, aAltColor,
  253. aAltColor );
  254. }
  255. }
  256. break;
  257. case AMP_MOIRE: // A cross hair with n concentric circles
  258. {
  259. curPos += mapPt( params[0].GetValue( tool ), params[1].GetValue( tool ),
  260. m_GerbMetric );
  261. /* Generated by an aperture macro declaration like:
  262. * "6,0,0,0.125,.01,0.01,3,0.003,0.150,0"
  263. * type(6), pos.x, pos.y, diam, penwidth, gap, circlecount, crosshair thickness, crosshaire len, rotation
  264. * type is not stored in parameters list, so the first parameter is pos.x
  265. */
  266. int outerDiam = scaletoIU( params[2].GetValue( tool ), m_GerbMetric );
  267. int penThickness = scaletoIU( params[3].GetValue( tool ), m_GerbMetric );
  268. int gap = scaletoIU( params[4].GetValue( tool ), m_GerbMetric );
  269. int numCircles = KiROUND( params[5].GetValue( tool ) );
  270. // Draw circles:
  271. wxPoint center = aParent->GetABPosition( curPos );
  272. // adjust outerDiam by this on each nested circle
  273. int diamAdjust = (gap + penThickness); //*2; //Should we use * 2 ?
  274. for( int i = 0; i < numCircles; ++i, outerDiam -= diamAdjust )
  275. {
  276. if( outerDiam <= 0 )
  277. break;
  278. if( !aFilledShape )
  279. {
  280. // draw the border of the pen's path using two circles, each as narrow as possible
  281. GRCircle( aClipBox, aDC, center, outerDiam / 2, 0, aColor );
  282. GRCircle( aClipBox, aDC, center, outerDiam / 2 - penThickness, 0, aColor );
  283. }
  284. else // Filled mode
  285. {
  286. GRCircle( aClipBox, aDC, center,
  287. (outerDiam - penThickness) / 2, penThickness, aColor );
  288. }
  289. }
  290. // Draw the cross:
  291. ConvertShapeToPolygon( aParent, polybuffer );
  292. rotation = params[8].GetValue( tool ) * 10.0;
  293. for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
  294. {
  295. // shape rotation:
  296. RotatePoint( &polybuffer[ii], -rotation );
  297. // Move to current position:
  298. polybuffer[ii] += curPos;
  299. polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
  300. }
  301. GRClosedPoly( aClipBox, aDC,
  302. polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
  303. }
  304. break;
  305. case AMP_OUTLINE:
  306. {
  307. /* Generated by an aperture macro declaration like:
  308. * "4,1,3,0.0,0.0,0.0,0.5,0.5,0.5,0.5,0.0,-25"
  309. * type(4), exposure, corners count, corner1.x, corner.1y, ..., rotation
  310. * type is not stored in parameters list, so the first parameter is exposure
  311. */
  312. int numPoints = (int) params[1].GetValue( tool );
  313. rotation = params[numPoints * 2 + 4].GetValue( tool ) * 10.0;
  314. wxPoint pos;
  315. // Read points. numPoints does not include the starting point, so add 1.
  316. for( int i = 0; i<numPoints + 1; ++i )
  317. {
  318. int jj = i * 2 + 2;
  319. pos.x = scaletoIU( params[jj].GetValue( tool ), m_GerbMetric );
  320. pos.y = scaletoIU( params[jj + 1].GetValue( tool ), m_GerbMetric );
  321. polybuffer.push_back(pos);
  322. }
  323. // rotate polygon and move it to the actual position
  324. // shape rotation:
  325. for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
  326. {
  327. RotatePoint( &polybuffer[ii], -rotation );
  328. }
  329. // Move to current position:
  330. for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
  331. {
  332. polybuffer[ii] += curPos;
  333. polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
  334. }
  335. GRClosedPoly( aClipBox, aDC,
  336. polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
  337. }
  338. break;
  339. case AMP_POLYGON: // Is a regular polygon
  340. /* Generated by an aperture macro declaration like:
  341. * "5,1,0.6,0,0,0.5,25"
  342. * type(5), exposure, vertices count, pox.x, pos.y, diameter, rotation
  343. * type is not stored in parameters list, so the first parameter is exposure
  344. */
  345. curPos += mapPt( params[2].GetValue( tool ), params[3].GetValue( tool ), m_GerbMetric );
  346. // Creates the shape:
  347. ConvertShapeToPolygon( aParent, polybuffer );
  348. // rotate polygon and move it to the actual position
  349. rotation = params[5].GetValue( tool ) * 10.0;
  350. for( unsigned ii = 0; ii < polybuffer.size(); ii++ )
  351. {
  352. RotatePoint( &polybuffer[ii], -rotation );
  353. polybuffer[ii] += curPos;
  354. polybuffer[ii] = aParent->GetABPosition( polybuffer[ii] );
  355. }
  356. GRClosedPoly( aClipBox, aDC,
  357. polybuffer.size(), &polybuffer[0], aFilledShape, aColor, aColor );
  358. break;
  359. case AMP_EOF:
  360. // not yet supported, waiting for you.
  361. break;
  362. case AMP_UNKNOWN:
  363. default:
  364. DBG( printf( "AM_PRIMITIVE::DrawBasicShape() err: unknown prim id %d\n",primitive_id) );
  365. break;
  366. }
  367. }
  368. /**
  369. * Function ConvertShapeToPolygon (virtual)
  370. * convert a shape to an equivalent polygon.
  371. * Arcs and circles are approximated by segments
  372. * Useful when a shape is not a graphic primitive (shape with hole,
  373. * rotated shape ... ) and cannot be easily drawn.
  374. * note for some schapes conbining circles and solid lines (rectangles), only rectangles are converted
  375. * because circles are very easy to draw (no rotation problem) so convert them in polygons,
  376. * and draw them as polygons is not a good idea.
  377. */
  378. void AM_PRIMITIVE::ConvertShapeToPolygon( GERBER_DRAW_ITEM* aParent,
  379. std::vector<wxPoint>& aBuffer )
  380. {
  381. D_CODE* tool = aParent->GetDcodeDescr();
  382. switch( primitive_id )
  383. {
  384. case AMP_CIRCLE: // Circle, currently convertion not needed
  385. break;
  386. case AMP_LINE2:
  387. case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
  388. {
  389. int width = scaletoIU( params[1].GetValue( tool ), m_GerbMetric );
  390. wxPoint start = mapPt( params[2].GetValue( tool ),
  391. params[3].GetValue( tool ), m_GerbMetric );
  392. wxPoint end = mapPt( params[4].GetValue( tool ),
  393. params[5].GetValue( tool ), m_GerbMetric );
  394. wxPoint delta = end - start;
  395. int len = KiROUND( EuclideanNorm( delta ) );
  396. // To build the polygon, we must create a horizonta polygon starting to "start"
  397. // and rotate it to have it end point to "end"
  398. wxPoint currpt;
  399. currpt.y += width / 2; // Upper left
  400. aBuffer.push_back( currpt );
  401. currpt.x = len; // Upper right
  402. aBuffer.push_back( currpt );
  403. currpt.y -= width; // lower right
  404. aBuffer.push_back( currpt );
  405. currpt.x = 0; // Upper left
  406. aBuffer.push_back( currpt );
  407. // Rotate rectangle and move it to the actual start point
  408. double angle = ArcTangente( delta.y, delta.x );
  409. for( unsigned ii = 0; ii < 4; ii++ )
  410. {
  411. RotatePoint( &aBuffer[ii], -angle );
  412. aBuffer[ii] += start;
  413. }
  414. }
  415. break;
  416. case AMP_LINE_CENTER:
  417. {
  418. wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
  419. wxPoint pos = mapPt( params[3].GetValue( tool ), params[4].GetValue( tool ), m_GerbMetric );
  420. // Build poly:
  421. pos.x -= size.x / 2;
  422. pos.y -= size.y / 2; // Lower left
  423. aBuffer.push_back( pos );
  424. pos.y += size.y; // Upper left
  425. aBuffer.push_back( pos );
  426. pos.x += size.x; // Upper right
  427. aBuffer.push_back( pos );
  428. pos.y -= size.y; // lower right
  429. aBuffer.push_back( pos );
  430. }
  431. break;
  432. case AMP_LINE_LOWER_LEFT:
  433. {
  434. wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
  435. wxPoint lowerLeft = mapPt( params[3].GetValue( tool ), params[4].GetValue(
  436. tool ), m_GerbMetric );
  437. // Build poly:
  438. aBuffer.push_back( lowerLeft );
  439. lowerLeft.y += size.y; // Upper left
  440. aBuffer.push_back( lowerLeft );
  441. lowerLeft.x += size.x; // Upper right
  442. aBuffer.push_back( lowerLeft );
  443. lowerLeft.y -= size.y; // lower right
  444. aBuffer.push_back( lowerLeft );
  445. }
  446. break;
  447. case AMP_THERMAL:
  448. {
  449. // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from this first
  450. // rotated by 90, 180 and 270 deg.
  451. // params = center.x (unused here), center.y (unused here), outside diam, inside diam, crosshair thickness
  452. int outerRadius = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2;
  453. int innerRadius = scaletoIU( params[3].GetValue( tool ), m_GerbMetric ) / 2;
  454. int halfthickness = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;
  455. double angle_start = RAD2DECIDEG( asin( (double) halfthickness / innerRadius ) );
  456. // Draw shape in the first cadrant (X and Y > 0)
  457. wxPoint pos, startpos;
  458. // Inner arc
  459. startpos.x = innerRadius;
  460. double angle_end = 900 - angle_start;
  461. for( double angle = angle_start; angle < angle_end; angle += 100 )
  462. {
  463. pos = startpos;
  464. RotatePoint( &pos, angle );
  465. aBuffer.push_back( pos );
  466. }
  467. // Last point
  468. pos = startpos;
  469. RotatePoint( &pos, angle_end );
  470. aBuffer.push_back( pos );
  471. // outer arc
  472. startpos.x = outerRadius;
  473. startpos.y = 0;
  474. angle_start = RAD2DECIDEG( asin( (double) halfthickness / outerRadius ) );
  475. angle_end = 900 - angle_start;
  476. // First point, near Y axis, outer arc
  477. for( double angle = angle_end; angle > angle_start; angle -= 100 )
  478. {
  479. pos = startpos;
  480. RotatePoint( &pos, angle );
  481. aBuffer.push_back( pos );
  482. }
  483. // last point
  484. pos = startpos;
  485. RotatePoint( &pos, angle_start );
  486. aBuffer.push_back( pos );
  487. aBuffer.push_back( aBuffer[0] ); // Close poly
  488. }
  489. break;
  490. case AMP_MOIRE: // A cross hair with n concentric circles. Only the cros is build as polygon
  491. // because circles can be drawn easily
  492. {
  493. int crossHairThickness = scaletoIU( params[6].GetValue( tool ), m_GerbMetric );
  494. int crossHairLength = scaletoIU( params[7].GetValue( tool ), m_GerbMetric );
  495. // Create cross. First create 1/4 of the shape.
  496. // Others point are the same, totated by 90, 180 and 270 deg
  497. wxPoint pos( crossHairThickness / 2, crossHairLength / 2 );
  498. aBuffer.push_back( pos );
  499. pos.y = crossHairThickness / 2;
  500. aBuffer.push_back( pos );
  501. pos.x = -crossHairLength / 2;
  502. aBuffer.push_back( pos );
  503. pos.y = -crossHairThickness / 2;
  504. aBuffer.push_back( pos );
  505. // Copy the 4 shape, rotated by 90, 180 and 270 deg
  506. for( int jj = 1; jj <= 3; jj ++ )
  507. {
  508. for( int ii = 0; ii < 4; ii++ )
  509. {
  510. pos = aBuffer[ii];
  511. RotatePoint( &pos, jj*900 );
  512. aBuffer.push_back( pos );
  513. }
  514. }
  515. }
  516. break;
  517. case AMP_OUTLINE:
  518. // already is a polygon. Do nothing
  519. break;
  520. case AMP_POLYGON: // Creates a regular polygon
  521. {
  522. int vertexcount = KiROUND( params[1].GetValue( tool ) );
  523. int radius = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2;
  524. // rs274x said: vertex count = 3 ... 10, and the first corner is on the X axis
  525. if( vertexcount < 3 )
  526. vertexcount = 3;
  527. if( vertexcount > 10 )
  528. vertexcount = 10;
  529. for( int ii = 0; ii <= vertexcount; ii++ )
  530. {
  531. wxPoint pos( radius, 0);
  532. RotatePoint( &pos, ii * 3600 / vertexcount );
  533. aBuffer.push_back( pos );
  534. }
  535. }
  536. break;
  537. case AMP_COMMENT:
  538. case AMP_UNKNOWN:
  539. case AMP_EOF:
  540. break;
  541. }
  542. }
  543. /** GetShapeDim
  544. * Calculate a value that can be used to evaluate the size of text
  545. * when displaying the D-Code of an item
  546. * due to the complexity of the shape of some primitives
  547. * one cannot calculate the "size" of a shape (only abounding box)
  548. * but here, the "dimension" of the shape is the diameter of the primitive
  549. * or for lines the width of the line
  550. * @param aParent = the parent GERBER_DRAW_ITEM which is actually drawn
  551. * @return a dimension, or -1 if no dim to calculate
  552. */
  553. int AM_PRIMITIVE::GetShapeDim( GERBER_DRAW_ITEM* aParent )
  554. {
  555. int dim = -1;
  556. D_CODE* tool = aParent->GetDcodeDescr();
  557. switch( primitive_id )
  558. {
  559. case AMP_CIRCLE:
  560. // params = exposure, diameter, pos.x, pos.y
  561. dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); // Diameter
  562. break;
  563. case AMP_LINE2:
  564. case AMP_LINE20: // Line with rectangle ends. (Width, start and end pos + rotation)
  565. dim = scaletoIU( params[1].GetValue( tool ), m_GerbMetric ); // linne width
  566. break;
  567. case AMP_LINE_CENTER:
  568. {
  569. wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
  570. dim = std::min(size.x, size.y);
  571. }
  572. break;
  573. case AMP_LINE_LOWER_LEFT:
  574. {
  575. wxPoint size = mapPt( params[1].GetValue( tool ), params[2].GetValue( tool ), m_GerbMetric );
  576. dim = std::min(size.x, size.y);
  577. }
  578. break;
  579. case AMP_THERMAL:
  580. {
  581. // Only 1/4 of the full shape is built, because the other 3 shapes will be draw from this first
  582. // rotated by 90, 180 and 270 deg.
  583. // params = center.x (unused here), center.y (unused here), outside diam, inside diam, crosshair thickness
  584. dim = scaletoIU( params[2].GetValue( tool ), m_GerbMetric ) / 2; // Outer diam
  585. }
  586. break;
  587. case AMP_MOIRE: // A cross hair with n concentric circles.
  588. dim = scaletoIU( params[7].GetValue( tool ), m_GerbMetric ); // = cross hair len
  589. break;
  590. case AMP_OUTLINE: // a free polygon :
  591. // dim = min side of the bounding box (this is a poor criteria, but what is a good criteria b?)
  592. {
  593. // exposure, corners count, corner1.x, corner.1y, ..., rotation
  594. int numPoints = (int) params[1].GetValue( tool );
  595. // Read points. numPoints does not include the starting point, so add 1.
  596. // and calculate the bounding box;
  597. wxSize pos_min, pos_max, pos;
  598. for( int i = 0; i<numPoints + 1; ++i )
  599. {
  600. int jj = i * 2 + 2;
  601. pos.x = scaletoIU( params[jj].GetValue( tool ), m_GerbMetric );
  602. pos.y = scaletoIU( params[jj + 1].GetValue( tool ), m_GerbMetric );
  603. if( i == 0 )
  604. pos_min = pos_max = pos;
  605. else
  606. {
  607. // upper right corner:
  608. if( pos_min.x > pos.x )
  609. pos_min.x = pos.x;
  610. if( pos_min.y > pos.y )
  611. pos_min.y = pos.y;
  612. // lower left corner:
  613. if( pos_max.x < pos.x )
  614. pos_max.x = pos.x;
  615. if( pos_max.y < pos.y )
  616. pos_max.y = pos.y;
  617. }
  618. }
  619. // calculate dim
  620. wxSize size;
  621. size.x = pos_max.x - pos_min.x;
  622. size.y = pos_max.y - pos_min.y;
  623. dim = std::min( size.x, size.y );
  624. }
  625. break;
  626. case AMP_POLYGON: // Regular polygon
  627. dim = scaletoIU( params[4].GetValue( tool ), m_GerbMetric ) / 2; // Radius
  628. break;
  629. case AMP_COMMENT:
  630. case AMP_UNKNOWN:
  631. case AMP_EOF:
  632. break;
  633. }
  634. return dim;
  635. }
  636. /**
  637. * Function DrawApertureMacroShape
  638. * Draw the primitive shape for flashed items.
  639. * When an item is flashed, this is the shape of the item
  640. */
  641. void APERTURE_MACRO::DrawApertureMacroShape( GERBER_DRAW_ITEM* aParent,
  642. EDA_RECT* aClipBox, wxDC* aDC,
  643. EDA_COLOR_T aColor, EDA_COLOR_T aAltColor,
  644. wxPoint aShapePos, bool aFilledShape )
  645. {
  646. for( AM_PRIMITIVES::iterator prim_macro = primitives.begin();
  647. prim_macro != primitives.end(); ++prim_macro )
  648. {
  649. prim_macro->DrawBasicShape( aParent, aClipBox, aDC,
  650. aColor, aAltColor,
  651. aShapePos,
  652. aFilledShape );
  653. }
  654. }
  655. /* Function HasNegativeItems
  656. * return true if this macro has at least one aperture primitives
  657. * that must be drawn in background color
  658. * used to optimize screen refresh
  659. */
  660. bool APERTURE_MACRO::HasNegativeItems( GERBER_DRAW_ITEM* aParent )
  661. {
  662. for( AM_PRIMITIVES::iterator prim_macro = primitives.begin();
  663. prim_macro != primitives.end(); ++prim_macro )
  664. {
  665. if( prim_macro->mapExposure( aParent ) == false ) // = is negative
  666. return true;
  667. }
  668. return false;
  669. }
  670. /** GetShapeDim
  671. * Calculate a value that can be used to evaluate the size of text
  672. * when displaying the D-Code of an item
  673. * due to the complexity of a shape using many primitives
  674. * one cannot calculate the "size" of a shape (only abounding box)
  675. * but most of aperture macro are using one or few primitives
  676. * and the "dimension" of the shape is the diameter of the primitive
  677. * (or the max diameter of primitives)
  678. * @return a dimension, or -1 if no dim to calculate
  679. */
  680. int APERTURE_MACRO::GetShapeDim( GERBER_DRAW_ITEM* aParent )
  681. {
  682. int dim = -1;
  683. for( AM_PRIMITIVES::iterator prim_macro = primitives.begin();
  684. prim_macro != primitives.end(); ++prim_macro )
  685. {
  686. int pdim = prim_macro->GetShapeDim( aParent );
  687. if( dim < pdim )
  688. dim = pdim;
  689. }
  690. return dim;
  691. }
  692. /**
  693. * function GetLocalParam
  694. * Usually, parameters are defined inside the aperture primitive
  695. * using immediate mode or defered mode.
  696. * in defered mode the value is defined in a DCODE that want to use the aperture macro.
  697. * But some parameters are defined outside the aperture primitive
  698. * and are local to the aperture macro
  699. * @return the value of a defered parameter defined inside the aperture macro
  700. * @param aParamId = the param id (defined by $3 or $5 ..) to evaluate
  701. */
  702. double APERTURE_MACRO::GetLocalParam( const D_CODE* aDcode, unsigned aParamId ) const
  703. {
  704. // find parameter descr.
  705. const AM_PARAM * param = NULL;
  706. for( unsigned ii = 0; ii < m_localparamStack.size(); ii ++ )
  707. {
  708. if( m_localparamStack[ii].GetIndex() == aParamId )
  709. {
  710. param = &m_localparamStack[ii];
  711. break;
  712. }
  713. }
  714. if ( param == NULL ) // not found
  715. return 0.0;
  716. // Evaluate parameter
  717. double value = param->GetValue( aDcode );
  718. return value;
  719. }