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.

579 lines
18 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright (C) 1992-2013 jean-pierre.charras
  5. * Copyright (C) 1992-2013 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 <cmath>
  25. #include <algorithm> // std::max
  26. // For some unknown reasons, polygon.hpp should be included first
  27. #include <boost/polygon/polygon.hpp>
  28. #include <wx/wx.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <errno.h>
  32. #include <stdlib.h>
  33. #include <cmath>
  34. #include <vector>
  35. #include <layers_id_colors_and_visibility.h>
  36. #include <potracelib.h>
  37. #include <auxiliary.h>
  38. #include <common.h>
  39. #include <bitmap2component.h>
  40. // Define some types used here from boost::polygon
  41. namespace bpl = boost::polygon; // bpl = boost polygon library
  42. using namespace bpl::operators; // +, -, =, ...
  43. typedef int coordinate_type;
  44. typedef bpl::polygon_data<coordinate_type> KPolygon; // define a basic polygon
  45. typedef std::vector<KPolygon> KPolygonSet; // define a set of polygons
  46. typedef bpl::point_data<coordinate_type> KPolyPoint; // define a corner of a polygon
  47. /* free a potrace bitmap */
  48. static void bm_free( potrace_bitmap_t* bm )
  49. {
  50. if( bm != NULL )
  51. {
  52. free( bm->map );
  53. }
  54. free( bm );
  55. }
  56. /* Helper class to handle useful info to convert a bitmap image to
  57. * a polygonal object description
  58. */
  59. class BITMAPCONV_INFO
  60. {
  61. public:
  62. enum OUTPUT_FMT_ID m_Format; // File format
  63. int m_PixmapWidth;
  64. int m_PixmapHeight; // the bitmap size in pixels
  65. double m_ScaleX;
  66. double m_ScaleY; // the conversion scale
  67. potrace_path_t* m_Paths; // the list of paths, from potrace (list of lines and bezier curves)
  68. FILE* m_Outfile; // File to create
  69. const char * m_CmpName; // The string used as cmp/footprint name
  70. public:
  71. BITMAPCONV_INFO();
  72. /**
  73. * Function CreateOutputFile
  74. * Creates the output file specified by m_Outfile,
  75. * depending on file format given by m_Format
  76. */
  77. void CreateOutputFile( BMP2CMP_MOD_LAYER aModLayer = (BMP2CMP_MOD_LAYER) 0 );
  78. private:
  79. /**
  80. * Function OuputFileHeader
  81. * write to file the header depending on file format
  82. */
  83. void OuputFileHeader( const char * aBrdLayerName );
  84. /**
  85. * Function OuputFileEnd
  86. * write to file the last strings depending on file format
  87. */
  88. void OuputFileEnd();
  89. /**
  90. * @return the board layer name depending on the board layer selected
  91. * @param aChoice = the choice (MOD_LYR_FSILKS to MOD_LYR_FINAL)
  92. */
  93. const char * getBrdLayerName( BMP2CMP_MOD_LAYER aChoice );
  94. /**
  95. * Function OuputOnePolygon
  96. * write one polygon to output file.
  97. * Polygon coordinates are expected scaled by the polugon extraction function
  98. */
  99. void OuputOnePolygon( KPolygon & aPolygon, const char * aBrdLayerName );
  100. };
  101. static void BezierToPolyline( std::vector <potrace_dpoint_t>& aCornersBuffer,
  102. potrace_dpoint_t p1,
  103. potrace_dpoint_t p2,
  104. potrace_dpoint_t p3,
  105. potrace_dpoint_t p4 );
  106. BITMAPCONV_INFO::BITMAPCONV_INFO()
  107. {
  108. m_Format = POSTSCRIPT_FMT;
  109. m_PixmapWidth = 0;
  110. m_PixmapHeight = 0;
  111. m_ScaleX = 1.0;
  112. m_ScaleY = 1.0;
  113. m_Paths = NULL;
  114. m_Outfile = NULL;
  115. m_CmpName = "LOGO";
  116. }
  117. int bitmap2component( potrace_bitmap_t* aPotrace_bitmap, FILE* aOutfile,
  118. OUTPUT_FMT_ID aFormat, int aDpi_X, int aDpi_Y,
  119. BMP2CMP_MOD_LAYER aModLayer )
  120. {
  121. potrace_param_t* param;
  122. potrace_state_t* st;
  123. // set tracing parameters, starting from defaults
  124. param = potrace_param_default();
  125. if( !param )
  126. {
  127. fprintf( stderr, "Error allocating parameters: %s\n", strerror( errno ) );
  128. return 1;
  129. }
  130. param->turdsize = 0;
  131. /* convert the bitmap to curves */
  132. st = potrace_trace( param, aPotrace_bitmap );
  133. if( !st || st->status != POTRACE_STATUS_OK )
  134. {
  135. if( st )
  136. {
  137. potrace_state_free( st );
  138. }
  139. potrace_param_free( param );
  140. fprintf( stderr, "Error tracing bitmap: %s\n", strerror( errno ) );
  141. return 1;
  142. }
  143. BITMAPCONV_INFO info;
  144. info.m_PixmapWidth = aPotrace_bitmap->w;
  145. info.m_PixmapHeight = aPotrace_bitmap->h; // the bitmap size in pixels
  146. info.m_Paths = st->plist;
  147. info.m_Outfile = aOutfile;
  148. switch( aFormat )
  149. {
  150. case KICAD_LOGO:
  151. info.m_Format = KICAD_LOGO;
  152. info.m_ScaleX = 1e3 * 25.4 / aDpi_X; // the conversion scale from PPI to micro
  153. info.m_ScaleY = 1e3 * 25.4 / aDpi_Y; // Y axis is top to bottom
  154. info.CreateOutputFile();
  155. break;
  156. case POSTSCRIPT_FMT:
  157. info.m_Format = POSTSCRIPT_FMT;
  158. info.m_ScaleX = 1.0; // the conversion scale
  159. info.m_ScaleY = info.m_ScaleX;
  160. // output vector data, e.g. as a rudimentary EPS file (mainly for tests)
  161. info.CreateOutputFile();
  162. break;
  163. case EESCHEMA_FMT:
  164. info.m_Format = EESCHEMA_FMT;
  165. info.m_ScaleX = 1000.0 / aDpi_X; // the conversion scale from PPI to UI
  166. info.m_ScaleY = -1000.0 / aDpi_Y; // Y axis is bottom to Top for components in libs
  167. info.CreateOutputFile();
  168. break;
  169. case PCBNEW_KICAD_MOD:
  170. info.m_Format = PCBNEW_KICAD_MOD;
  171. info.m_ScaleX = 1e6 * 25.4 / aDpi_X; // the conversion scale from PPI to UI
  172. info.m_ScaleY = 1e6 * 25.4 / aDpi_Y; // Y axis is top to bottom in modedit
  173. info.CreateOutputFile( aModLayer );
  174. break;
  175. default:
  176. break;
  177. }
  178. bm_free( aPotrace_bitmap );
  179. potrace_state_free( st );
  180. potrace_param_free( param );
  181. return 0;
  182. }
  183. const char* BITMAPCONV_INFO::getBrdLayerName( BMP2CMP_MOD_LAYER aChoice )
  184. {
  185. const char * layerName = "F.SilkS";
  186. switch( aChoice )
  187. {
  188. case MOD_LYR_FSOLDERMASK:
  189. layerName = "F.Mask";
  190. break;
  191. case MOD_LYR_ECO1:
  192. layerName = "Eco1.User";
  193. break;
  194. case MOD_LYR_ECO2:
  195. layerName = "Eco2.User";
  196. break;
  197. case MOD_LYR_FSILKS:
  198. default: // case MOD_LYR_FSILKS only unless there is a bug
  199. break;
  200. }
  201. return layerName;
  202. }
  203. void BITMAPCONV_INFO::OuputFileHeader( const char * aBrdLayerName )
  204. {
  205. int Ypos = (int) ( m_PixmapHeight / 2 * m_ScaleY );
  206. int fieldSize; // fields text size = 60 mils
  207. switch( m_Format )
  208. {
  209. case POSTSCRIPT_FMT:
  210. /* output vector data, e.g. as a rudimentary EPS file */
  211. fprintf( m_Outfile, "%%!PS-Adobe-3.0 EPSF-3.0\n" );
  212. fprintf( m_Outfile, "%%%%BoundingBox: 0 0 %d %d\n",
  213. m_PixmapWidth, m_PixmapHeight );
  214. fprintf( m_Outfile, "gsave\n" );
  215. break;
  216. case PCBNEW_KICAD_MOD:
  217. // fields text size = 1.5 mm
  218. // fields text thickness = 1.5 / 5 = 0.3mm
  219. fprintf( m_Outfile, "(module %s (layer F.Cu)\n (at 0 0)\n",
  220. m_CmpName );
  221. fprintf( m_Outfile, " (fp_text reference \"G***\" (at 0 0) (layer %s) hide\n"
  222. " (effects (font (thickness 0.3)))\n )\n", aBrdLayerName );
  223. fprintf( m_Outfile, " (fp_text value \"%s\" (at 0.75 0) (layer %s) hide\n"
  224. " (effects (font (thickness 0.3)))\n )\n", m_CmpName, aBrdLayerName );
  225. break;
  226. case KICAD_LOGO:
  227. fprintf( m_Outfile, "(polygon (pos 0 0 rbcorner) (rotate 0) (linewidth 0.01)\n" );
  228. break;
  229. case EESCHEMA_FMT:
  230. fprintf( m_Outfile, "EESchema-LIBRARY Version 2.3\n" );
  231. fprintf( m_Outfile, "#\n# %s\n", m_CmpName );
  232. fprintf( m_Outfile, "# pixmap size w = %d, h = %d\n#\n",
  233. m_PixmapWidth, m_PixmapHeight );
  234. // print reference and value
  235. fieldSize = 60; // fields text size = 60 mils
  236. Ypos += fieldSize / 2;
  237. fprintf( m_Outfile, "DEF %s G 0 40 Y Y 1 F N\n", m_CmpName );
  238. fprintf( m_Outfile, "F0 \"#G\" 0 %d %d H I C CNN\n", Ypos, fieldSize );
  239. fprintf( m_Outfile, "F1 \"%s\" 0 %d %d H I C CNN\n", m_CmpName, -Ypos, fieldSize );
  240. fprintf( m_Outfile, "DRAW\n" );
  241. break;
  242. }
  243. }
  244. void BITMAPCONV_INFO::OuputFileEnd()
  245. {
  246. switch( m_Format )
  247. {
  248. case POSTSCRIPT_FMT:
  249. fprintf( m_Outfile, "grestore\n" );
  250. fprintf( m_Outfile, "%%EOF\n" );
  251. break;
  252. case PCBNEW_KICAD_MOD:
  253. fprintf( m_Outfile, ")\n" );
  254. break;
  255. case KICAD_LOGO:
  256. fprintf( m_Outfile, ")\n" );
  257. break;
  258. case EESCHEMA_FMT:
  259. fprintf( m_Outfile, "ENDDRAW\n" );
  260. fprintf( m_Outfile, "ENDDEF\n" );
  261. break;
  262. }
  263. }
  264. /**
  265. * Function OuputOnePolygon
  266. * write one polygon to output file.
  267. * Polygon coordinates are expected scaled by the polygon extraction function
  268. */
  269. void BITMAPCONV_INFO::OuputOnePolygon( KPolygon & aPolygon, const char * aBrdLayerName )
  270. {
  271. unsigned ii, jj;
  272. KPolyPoint currpoint;
  273. int offsetX = (int)( m_PixmapWidth / 2 * m_ScaleX );
  274. int offsetY = (int)( m_PixmapHeight / 2 * m_ScaleY );
  275. KPolyPoint startpoint = *aPolygon.begin();
  276. switch( m_Format )
  277. {
  278. case POSTSCRIPT_FMT:
  279. offsetY = (int)( m_PixmapHeight * m_ScaleY );
  280. fprintf( m_Outfile, "newpath\n%d %d moveto\n",
  281. startpoint.x(), offsetY - startpoint.y() );
  282. jj = 0;
  283. for( ii = 1; ii < aPolygon.size(); ii++ )
  284. {
  285. currpoint = *(aPolygon.begin() + ii);
  286. fprintf( m_Outfile, " %d %d lineto",
  287. currpoint.x(), offsetY - currpoint.y() );
  288. if( jj++ > 6 )
  289. {
  290. jj = 0;
  291. fprintf( m_Outfile, ("\n") );
  292. }
  293. }
  294. fprintf( m_Outfile, "\nclosepath fill\n" );
  295. break;
  296. case PCBNEW_KICAD_MOD:
  297. {
  298. double width = 0.1;
  299. fprintf( m_Outfile, " (fp_poly (pts" );
  300. jj = 0;
  301. for( ii = 0; ii < aPolygon.size(); ii++ )
  302. {
  303. currpoint = *( aPolygon.begin() + ii );
  304. fprintf( m_Outfile, " (xy %f %f)",
  305. (currpoint.x() - offsetX) / 1e6,
  306. (currpoint.y() - offsetY) / 1e6 );
  307. if( jj++ > 6 )
  308. {
  309. jj = 0;
  310. fprintf( m_Outfile, ("\n ") );
  311. }
  312. }
  313. // Close polygon
  314. fprintf( m_Outfile, " (xy %f %f) )",
  315. (startpoint.x() - offsetX) / 1e6, (startpoint.y() - offsetY) / 1e6 );
  316. fprintf( m_Outfile, "(layer %s) (width %f)\n )\n", aBrdLayerName, width );
  317. }
  318. break;
  319. case KICAD_LOGO:
  320. fprintf( m_Outfile, " (pts" );
  321. // Internal units = micron, file unit = mm
  322. jj = 0;
  323. for( ii = 0; ii < aPolygon.size(); ii++ )
  324. {
  325. currpoint = *( aPolygon.begin() + ii );
  326. fprintf( m_Outfile, " (xy %.3f %.3f)",
  327. (currpoint.x() - offsetX) / 1e3,
  328. (currpoint.y() - offsetY) / 1e3 );
  329. if( jj++ > 4 )
  330. {
  331. jj = 0;
  332. fprintf( m_Outfile, ("\n ") );
  333. }
  334. }
  335. // Close polygon
  336. fprintf( m_Outfile, " (xy %.3f %.3f) )\n",
  337. (startpoint.x() - offsetX) / 1e3, (startpoint.y() - offsetY) / 1e3 );
  338. break;
  339. case EESCHEMA_FMT:
  340. fprintf( m_Outfile, "P %d 0 0 1", (int) aPolygon.size() + 1 );
  341. for( ii = 0; ii < aPolygon.size(); ii++ )
  342. {
  343. currpoint = *(aPolygon.begin() + ii);
  344. fprintf( m_Outfile, " %d %d",
  345. currpoint.x() - offsetX, currpoint.y() - offsetY );
  346. }
  347. // Close polygon
  348. fprintf( m_Outfile, " %d %d",
  349. startpoint.x() - offsetX, startpoint.y() - offsetY );
  350. fprintf( m_Outfile, " F\n" );
  351. break;
  352. }
  353. }
  354. void BITMAPCONV_INFO::CreateOutputFile( BMP2CMP_MOD_LAYER aModLayer )
  355. {
  356. KPolyPoint currpoint;
  357. std::vector <potrace_dpoint_t> cornersBuffer;
  358. // This KPolygonSet polyset_areas is a complex polygon to draw
  359. // and can be complex depending on holes inside this polygon
  360. KPolygonSet polyset_areas;
  361. // This KPolygonSet polyset_holes is the set of holes inside polyset_areas
  362. KPolygonSet polyset_holes;
  363. potrace_dpoint_t( *c )[3];
  364. LOCALE_IO toggle; // Temporary switch the locale to standard C to r/w floats
  365. // The layer name has meaning only for .kicad_mod files.
  366. // For these files the header creates 2 invisible texts: value and ref
  367. // (needed but not usefull) on silk screen layer
  368. OuputFileHeader( getBrdLayerName( MOD_LYR_FSILKS ) );
  369. bool main_outline = true;
  370. /* draw each as a polygon with no hole.
  371. * Bezier curves are approximated by a polyline
  372. */
  373. potrace_path_t* paths = m_Paths; // the list of paths
  374. while( paths != NULL )
  375. {
  376. int cnt = paths->curve.n;
  377. int* tag = paths->curve.tag;
  378. c = paths->curve.c;
  379. potrace_dpoint_t startpoint = c[cnt - 1][2];
  380. for( int i = 0; i < cnt; i++ )
  381. {
  382. switch( tag[i] )
  383. {
  384. case POTRACE_CORNER:
  385. cornersBuffer.push_back( c[i][1] );
  386. cornersBuffer.push_back( c[i][2] );
  387. startpoint = c[i][2];
  388. break;
  389. case POTRACE_CURVETO:
  390. BezierToPolyline( cornersBuffer, startpoint, c[i][0], c[i][1], c[i][2] );
  391. startpoint = c[i][2];
  392. break;
  393. }
  394. }
  395. // Store current path
  396. if( main_outline )
  397. {
  398. main_outline = false;
  399. // build the current main polygon
  400. std::vector<KPolyPoint> cornerslist; // a simple boost polygon
  401. for( unsigned int i = 0; i < cornersBuffer.size(); i++ )
  402. {
  403. currpoint.x( (coordinate_type) (cornersBuffer[i].x * m_ScaleX) );
  404. currpoint.y( (coordinate_type) (cornersBuffer[i].y * m_ScaleY) );
  405. cornerslist.push_back( currpoint );
  406. }
  407. KPolygon poly;
  408. bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
  409. polyset_areas.push_back( poly );
  410. }
  411. else
  412. {
  413. // Add current hole in polyset_holes
  414. std::vector<KPolyPoint> cornerslist; // a simple boost polygon
  415. for( unsigned int i = 0; i < cornersBuffer.size(); i++ )
  416. {
  417. currpoint.x( (coordinate_type) (cornersBuffer[i].x * m_ScaleX) );
  418. currpoint.y( (coordinate_type) (cornersBuffer[i].y * m_ScaleY) );
  419. cornerslist.push_back( currpoint );
  420. }
  421. KPolygon poly;
  422. bpl::set_points( poly, cornerslist.begin(), cornerslist.end() );
  423. polyset_holes.push_back( poly );
  424. }
  425. cornersBuffer.clear();
  426. /* at the end of a group of a positive path and its negative children, fill.
  427. */
  428. if( paths->next == NULL || paths->next->sign == '+' )
  429. {
  430. // Substract holes to main polygon:
  431. polyset_areas -= polyset_holes;
  432. // Output current resulting polygon(s)
  433. for( unsigned ii = 0; ii < polyset_areas.size(); ii++ )
  434. {
  435. KPolygon& poly = polyset_areas[ii];
  436. OuputOnePolygon(poly, getBrdLayerName( aModLayer ) );
  437. }
  438. polyset_areas.clear();
  439. polyset_holes.clear();
  440. main_outline = true;
  441. }
  442. paths = paths->next;
  443. }
  444. OuputFileEnd();
  445. }
  446. /* render a Bezier curve. */
  447. void BezierToPolyline( std::vector <potrace_dpoint_t>& aCornersBuffer,
  448. potrace_dpoint_t p1,
  449. potrace_dpoint_t p2,
  450. potrace_dpoint_t p3,
  451. potrace_dpoint_t p4 )
  452. {
  453. double dd0, dd1, dd, delta, e2, epsilon, t;
  454. // p1 = starting point
  455. /* we approximate the curve by small line segments. The interval
  456. * size, epsilon, is determined on the fly so that the distance
  457. * between the true curve and its approximation does not exceed the
  458. * desired accuracy delta. */
  459. delta = 0.25; /* desired accuracy, in pixels */
  460. /* let dd = maximal value of 2nd derivative over curve - this must
  461. * occur at an endpoint. */
  462. dd0 = sq( p1.x - 2 * p2.x + p3.x ) + sq( p1.y - 2 * p2.y + p3.y );
  463. dd1 = sq( p2.x - 2 * p3.x + p4.x ) + sq( p2.y - 2 * p3.y + p4.y );
  464. dd = 6 * sqrt( max( dd0, dd1 ) );
  465. e2 = 8 * delta <= dd ? 8 * delta / dd : 1;
  466. epsilon = sqrt( e2 ); /* necessary interval size */
  467. for( t = epsilon; t<1; t += epsilon )
  468. {
  469. potrace_dpoint_t intermediate_point;
  470. intermediate_point.x = p1.x * cu( 1 - t ) +
  471. 3* p2.x* sq( 1 - t ) * t +
  472. 3 * p3.x * (1 - t) * sq( t ) +
  473. p4.x* cu( t );
  474. intermediate_point.y = p1.y * cu( 1 - t ) +
  475. 3* p2.y* sq( 1 - t ) * t +
  476. 3 * p3.y * (1 - t) * sq( t ) + p4.y* cu( t );
  477. aCornersBuffer.push_back( intermediate_point );
  478. }
  479. aCornersBuffer.push_back( p4 );
  480. }