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.

453 lines
13 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 1992-2016 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 <trigo.h>
  32. #include <gerbview_frame.h>
  33. #include <gerber_file_image.h>
  34. #include <convert_to_biu.h>
  35. #include <convert_basic_shapes_to_polygon.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_Polygon.RemoveAllContours();
  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, COLOR4D aColor,
  125. wxPoint aShapePos, bool aFilledShape )
  126. {
  127. int radius;
  128. switch( m_Shape )
  129. {
  130. case APT_MACRO:
  131. GetMacro()->DrawApertureMacroShape( aParent, aClipBox, aDC, aColor,
  132. aShapePos, aFilledShape);
  133. break;
  134. case APT_CIRCLE:
  135. radius = m_Size.x >> 1;
  136. if( !aFilledShape )
  137. GRCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos), radius, 0, aColor );
  138. else
  139. if( m_DrillShape == APT_DEF_NO_HOLE )
  140. {
  141. GRFilledCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos),
  142. radius, aColor );
  143. }
  144. else if( m_DrillShape == APT_DEF_ROUND_HOLE ) // round hole in shape
  145. {
  146. int width = (m_Size.x - m_Drill.x ) / 2;
  147. GRCircle( aClipBox, aDC, aParent->GetABPosition(aShapePos),
  148. radius - (width / 2), width, aColor );
  149. }
  150. else // rectangular hole
  151. {
  152. if( m_Polygon.OutlineCount() == 0 )
  153. ConvertShapeToPolygon();
  154. DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
  155. }
  156. break;
  157. case APT_RECT:
  158. {
  159. wxPoint start;
  160. start.x = aShapePos.x - m_Size.x / 2;
  161. start.y = aShapePos.y - m_Size.y / 2;
  162. wxPoint end = start + m_Size;
  163. start = aParent->GetABPosition( start );
  164. end = aParent->GetABPosition( end );
  165. if( !aFilledShape )
  166. {
  167. GRRect( aClipBox, aDC, start.x, start.y, end.x, end.y, 0, aColor );
  168. }
  169. else if( m_DrillShape == APT_DEF_NO_HOLE )
  170. {
  171. GRFilledRect( aClipBox, aDC, start.x, start.y, end.x, end.y, 0, aColor, aColor );
  172. }
  173. else
  174. {
  175. if( m_Polygon.OutlineCount() == 0 )
  176. ConvertShapeToPolygon();
  177. DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
  178. }
  179. }
  180. break;
  181. case APT_OVAL:
  182. {
  183. wxPoint start = aShapePos;
  184. wxPoint end = aShapePos;
  185. if( m_Size.x > m_Size.y ) // horizontal oval
  186. {
  187. int delta = (m_Size.x - m_Size.y) / 2;
  188. start.x -= delta;
  189. end.x += delta;
  190. radius = m_Size.y; // Width in fact
  191. }
  192. else // vertical oval
  193. {
  194. int delta = (m_Size.y - m_Size.x) / 2;
  195. start.y -= delta;
  196. end.y += delta;
  197. radius = m_Size.x; // Width in fact
  198. }
  199. start = aParent->GetABPosition( start );
  200. end = aParent->GetABPosition( end );
  201. if( !aFilledShape )
  202. {
  203. GRCSegm( aClipBox, aDC, start.x, start.y, end.x, end.y, radius, aColor );
  204. }
  205. else if( m_DrillShape == APT_DEF_NO_HOLE )
  206. {
  207. GRFillCSegm( aClipBox, aDC, start.x, start.y, end.x, end.y, radius, aColor );
  208. }
  209. else
  210. {
  211. if( m_Polygon.OutlineCount() == 0 )
  212. ConvertShapeToPolygon();
  213. DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
  214. }
  215. }
  216. break;
  217. case APT_POLYGON:
  218. if( m_Polygon.OutlineCount() == 0 )
  219. ConvertShapeToPolygon();
  220. DrawFlashedPolygon( aParent, aClipBox, aDC, aColor, aFilledShape, aShapePos );
  221. break;
  222. }
  223. }
  224. void D_CODE::DrawFlashedPolygon( GERBER_DRAW_ITEM* aParent,
  225. EDA_RECT* aClipBox, wxDC* aDC,
  226. COLOR4D aColor, bool aFilled,
  227. const wxPoint& aPosition )
  228. {
  229. if( m_Polygon.OutlineCount() == 0 )
  230. return;
  231. int pointCount = m_Polygon.VertexCount();
  232. std::vector<wxPoint> points;
  233. points.reserve( pointCount );
  234. for( int ii = 0; ii < pointCount; ii++ )
  235. {
  236. wxPoint p( m_Polygon.CVertex( ii ).x, m_Polygon.CVertex( ii ).y );
  237. points[ii] = p + aPosition;
  238. points[ii] = aParent->GetABPosition( points[ii] );
  239. }
  240. GRClosedPoly( aClipBox, aDC, pointCount, &points[0], aFilled, aColor, aColor );
  241. }
  242. // TODO(snh): Remove the hard-coded count
  243. #define SEGS_CNT 64 // number of segments to approximate a circle
  244. // A helper function for D_CODE::ConvertShapeToPolygon(). Add a hole to a polygon
  245. static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon,
  246. APERTURE_DEF_HOLETYPE aHoleShape,
  247. wxSize aSize,
  248. wxPoint aAnchorPos );
  249. void D_CODE::ConvertShapeToPolygon()
  250. {
  251. wxPoint initialpos;
  252. wxPoint currpos;
  253. m_Polygon.RemoveAllContours();
  254. switch( m_Shape )
  255. {
  256. case APT_CIRCLE: // creates only a circle with rectangular hole
  257. TransformCircleToPolygon( m_Polygon, initialpos, m_Size.x >> 1, ARC_HIGH_DEF );
  258. addHoleToPolygon( &m_Polygon, m_DrillShape, m_Drill, initialpos );
  259. break;
  260. case APT_RECT:
  261. m_Polygon.NewOutline();
  262. currpos.x = m_Size.x / 2;
  263. currpos.y = m_Size.y / 2;
  264. initialpos = currpos;
  265. m_Polygon.Append( VECTOR2I( currpos ) );
  266. currpos.x -= m_Size.x;
  267. m_Polygon.Append( VECTOR2I( currpos ) );
  268. currpos.y -= m_Size.y;
  269. m_Polygon.Append( VECTOR2I( currpos ) );
  270. currpos.x += m_Size.x;
  271. m_Polygon.Append( VECTOR2I( currpos ) );
  272. currpos.y += m_Size.y;
  273. m_Polygon.Append( VECTOR2I( currpos ) ); // close polygon
  274. m_Polygon.Append( VECTOR2I( initialpos ) );
  275. addHoleToPolygon( &m_Polygon, m_DrillShape, m_Drill, initialpos );
  276. break;
  277. case APT_OVAL:
  278. {
  279. m_Polygon.NewOutline();
  280. int delta, radius;
  281. // we create an horizontal oval shape. then rotate if needed
  282. if( m_Size.x > m_Size.y ) // horizontal oval
  283. {
  284. delta = (m_Size.x - m_Size.y) / 2;
  285. radius = m_Size.y / 2;
  286. }
  287. else // vertical oval
  288. {
  289. delta = (m_Size.y - m_Size.x) / 2;
  290. radius = m_Size.x / 2;
  291. }
  292. currpos.y = radius;
  293. initialpos = currpos;
  294. m_Polygon.Append( VECTOR2I( currpos ) );
  295. // build the right arc of the shape
  296. unsigned ii = 0;
  297. for( ; ii <= SEGS_CNT / 2; ii++ )
  298. {
  299. currpos = initialpos;
  300. RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT );
  301. currpos.x += delta;
  302. m_Polygon.Append( VECTOR2I( currpos ) );
  303. }
  304. // build the left arc of the shape
  305. for( ii = SEGS_CNT / 2; ii <= SEGS_CNT; ii++ )
  306. {
  307. currpos = initialpos;
  308. RotatePoint( &currpos, ii * 3600.0 / SEGS_CNT );
  309. currpos.x -= delta;
  310. m_Polygon.Append( VECTOR2I( currpos ) );
  311. }
  312. m_Polygon.Append( VECTOR2I( initialpos ) ); // close outline
  313. if( m_Size.y > m_Size.x ) // vertical oval, rotate polygon.
  314. m_Polygon.Rotate( -M_PI / 2 );
  315. addHoleToPolygon( &m_Polygon, m_DrillShape, m_Drill, initialpos );
  316. }
  317. break;
  318. case APT_POLYGON:
  319. m_Polygon.NewOutline();
  320. currpos.x = m_Size.x >> 1; // first point is on X axis
  321. initialpos = currpos;
  322. // rs274x said: m_EdgesCount = 3 ... 12
  323. if( m_EdgesCount < 3 )
  324. m_EdgesCount = 3;
  325. if( m_EdgesCount > 12 )
  326. m_EdgesCount = 12;
  327. for( int ii = 0; ii < m_EdgesCount; ii++ )
  328. {
  329. currpos = initialpos;
  330. RotatePoint( &currpos, ii * 3600.0 / m_EdgesCount );
  331. m_Polygon.Append( VECTOR2I( currpos ) );
  332. }
  333. addHoleToPolygon( &m_Polygon, m_DrillShape, m_Drill, initialpos );
  334. if( m_Rotation ) // rotate polygonal shape:
  335. {
  336. double angle = m_Rotation * M_PI / 180;
  337. m_Polygon.Rotate( angle, VECTOR2I( 0, 0 ) );
  338. }
  339. break;
  340. case APT_MACRO:
  341. // TODO
  342. break;
  343. }
  344. }
  345. // The helper function for D_CODE::ConvertShapeToPolygon().
  346. // Add a hole to a polygon
  347. static void addHoleToPolygon( SHAPE_POLY_SET* aPolygon,
  348. APERTURE_DEF_HOLETYPE aHoleShape,
  349. wxSize aSize,
  350. wxPoint aAnchorPos )
  351. {
  352. wxPoint currpos;
  353. SHAPE_POLY_SET holeBuffer;
  354. if( aHoleShape == APT_DEF_ROUND_HOLE )
  355. {
  356. TransformCircleToPolygon( holeBuffer, wxPoint( 0, 0 ), aSize.x / 2, ARC_HIGH_DEF );
  357. }
  358. else if( aHoleShape == APT_DEF_RECT_HOLE )
  359. {
  360. holeBuffer.NewOutline();
  361. currpos.x = aSize.x / 2;
  362. currpos.y = aSize.y / 2;
  363. holeBuffer.Append( VECTOR2I( currpos ) ); // link to hole and begin hole
  364. currpos.x -= aSize.x;
  365. holeBuffer.Append( VECTOR2I( currpos ) );
  366. currpos.y -= aSize.y;
  367. holeBuffer.Append( VECTOR2I( currpos ) );
  368. currpos.x += aSize.x;
  369. holeBuffer.Append( VECTOR2I( currpos ) );
  370. currpos.y += aSize.y;
  371. holeBuffer.Append( VECTOR2I( currpos ) ); // close hole
  372. }
  373. aPolygon->BooleanSubtract( holeBuffer, SHAPE_POLY_SET::PM_FAST );
  374. aPolygon->Fracture( SHAPE_POLY_SET::PM_FAST );
  375. }