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.

499 lines
16 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2007-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. /**
  25. * @file export_to_pcbnew.cpp
  26. * @brief Export the layers to Pcbnew.
  27. */
  28. #include <vector>
  29. #include <fctsys.h>
  30. #include <common.h>
  31. #include <confirm.h>
  32. #include <macros.h>
  33. #include <kicad_string.h>
  34. #include <gestfich.h>
  35. #include <trigo.h>
  36. #include <gerbview.h>
  37. #include <gerbview_frame.h>
  38. #include <class_gerber_draw_item.h>
  39. #include <class_GERBER.h>
  40. #include <select_layers_to_pcb.h>
  41. #include <build_version.h>
  42. #include <wildcards_and_files_ext.h>
  43. // Imported function
  44. extern const wxString GetPCBDefaultLayerName( LAYER_NUM aLayerNumber );
  45. #define TO_PCB_UNIT( x ) ( x / IU_PER_MM)
  46. #define TRACK_TYPE 0
  47. /* A helper class to export a Gerber set of files to Pcbnew
  48. */
  49. class GBR_TO_PCB_EXPORTER
  50. {
  51. private:
  52. GERBVIEW_FRAME* m_gerbview_frame; // the main gerber frame
  53. wxString m_pcb_file_name; // BOARD file to write to
  54. FILE* m_fp; // the board file
  55. int m_pcbCopperLayersCount;
  56. std::vector<wxPoint> m_vias_coordinates; // list of already generated vias,
  57. // used to export only once a via
  58. // having a given coordinate
  59. public:
  60. GBR_TO_PCB_EXPORTER( GERBVIEW_FRAME* aFrame, const wxString& aFileName );
  61. ~GBR_TO_PCB_EXPORTER();
  62. /**
  63. * Function ExportPcb
  64. * saves a board from a set of Gerber images.
  65. */
  66. bool ExportPcb( LAYER_NUM* aLayerLookUpTable, int aCopperLayers );
  67. private:
  68. /**
  69. * Function export_non_copper_item
  70. * write a non copper line or arc to the board file.
  71. * @param aGbrItem = the Gerber item (line, arc) to export
  72. * @param aLayer = the technical layer to use
  73. */
  74. void export_non_copper_item( GERBER_DRAW_ITEM* aGbrItem, LAYER_NUM aLayer );
  75. /**
  76. * Function export_copper_item
  77. * write a track or via) to the board file.
  78. * @param aGbrItem = the Gerber item (line, arc, flashed) to export
  79. * @param aLayer = the copper layer to use
  80. */
  81. void export_copper_item( GERBER_DRAW_ITEM* aGbrItem, LAYER_NUM aLayer );
  82. /**
  83. * Function export_flashed_copper_item
  84. * write a via to the board file (always uses a via through).
  85. * @param aGbrItem = the flashed Gerber item to export
  86. */
  87. void export_flashed_copper_item( GERBER_DRAW_ITEM* aGbrItem );
  88. /**
  89. * Function export_segline_copper_item
  90. * write a track (not via) to the board file.
  91. * @param aGbrItem = the Gerber item (line only) to export
  92. * @param aLayer = the copper layer to use
  93. */
  94. void export_segline_copper_item( GERBER_DRAW_ITEM* aGbrItem, LAYER_NUM aLayer );
  95. /**
  96. * Function export_segarc_copper_item
  97. * write a set of tracks (arcs are approximated by track segments)
  98. * to the board file.
  99. * @param aGbrItem = the Gerber item (arc only) to export
  100. * @param aLayer = the copper layer to use
  101. */
  102. void export_segarc_copper_item( GERBER_DRAW_ITEM* aGbrItem, LAYER_NUM aLayer );
  103. /**
  104. * function writePcbLineItem
  105. * basic write function to write a DRAWSEGMENT item or a TRACK item
  106. * to the board file, from a non flashed item
  107. */
  108. void writePcbLineItem( bool aIsArc, wxPoint& aStart, wxPoint& aEnd,
  109. int aWidth, LAYER_NUM aLayer, double aAngle = 0 );
  110. /**
  111. * function writeCopperLineItem
  112. * basic write function to write a a TRACK item
  113. * to the board file, from a non flashed item
  114. */
  115. void writeCopperLineItem( wxPoint& aStart, wxPoint& aEnd,
  116. int aWidth, LAYER_NUM aLayer );
  117. /**
  118. * function writePcbHeader
  119. * Write a very basic header to the board file
  120. */
  121. void writePcbHeader( LAYER_NUM* aLayerLookUpTable );
  122. };
  123. GBR_TO_PCB_EXPORTER::GBR_TO_PCB_EXPORTER( GERBVIEW_FRAME* aFrame, const wxString& aFileName )
  124. {
  125. m_gerbview_frame = aFrame;
  126. m_pcb_file_name = aFileName;
  127. m_fp = NULL;
  128. m_pcbCopperLayersCount = 2;
  129. }
  130. GBR_TO_PCB_EXPORTER::~GBR_TO_PCB_EXPORTER()
  131. {
  132. }
  133. /* Export data in Pcbnew format
  134. * remember Pcbnew uses a Y reversed axis, so we must negate all Y coordinates
  135. */
  136. void GERBVIEW_FRAME::ExportDataInPcbnewFormat( wxCommandEvent& event )
  137. {
  138. int layercount = 0;
  139. // Count the Gerber layers which are actually currently used
  140. for( LAYER_NUM ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
  141. {
  142. if( g_GERBER_List.GetGbrImage( ii ) )
  143. layercount++;
  144. }
  145. if( layercount == 0 )
  146. {
  147. DisplayInfoMessage( this,
  148. _( "None of the Gerber layers contain any data" ) );
  149. return;
  150. }
  151. wxString fileName;
  152. wxString path = wxGetCwd();
  153. wxFileDialog filedlg( this, _( "Board file name:" ),
  154. path, fileName, PcbFileWildcard,
  155. wxFD_SAVE );
  156. if( filedlg.ShowModal() == wxID_CANCEL )
  157. return;
  158. fileName = filedlg.GetPath();
  159. /* Install a dialog frame to choose the mapping
  160. * between gerber layers and Pcbnew layers
  161. */
  162. LAYERS_MAP_DIALOG* layerdlg = new LAYERS_MAP_DIALOG( this );
  163. int ok = layerdlg->ShowModal();
  164. layerdlg->Destroy();
  165. if( ok != wxID_OK )
  166. return;
  167. if( wxFileExists( fileName ) )
  168. {
  169. if( !IsOK( this, _( "OK to change the existing file ?" ) ) )
  170. return;
  171. }
  172. GBR_TO_PCB_EXPORTER gbr_exporter( this, fileName );
  173. gbr_exporter.ExportPcb( layerdlg->GetLayersLookUpTable(),
  174. layerdlg->GetCopperLayersCount() );
  175. }
  176. bool GBR_TO_PCB_EXPORTER::ExportPcb( LAYER_NUM* aLayerLookUpTable, int aCopperLayers )
  177. {
  178. LOCALE_IO toggle; // toggles on, then off, the C locale.
  179. m_fp = wxFopen( m_pcb_file_name, wxT( "wt" ) );
  180. if( m_fp == NULL )
  181. {
  182. wxString msg;
  183. msg.Printf( _( "Cannot create file '%s'" ), GetChars( m_pcb_file_name ) );
  184. DisplayError( m_gerbview_frame, msg );
  185. return false;
  186. }
  187. m_pcbCopperLayersCount = aCopperLayers;
  188. writePcbHeader( aLayerLookUpTable );
  189. // create an image of gerber data
  190. // First: non copper layers:
  191. GERBER_DRAW_ITEM* gerb_item = m_gerbview_frame->GetItemsList();
  192. int pcbCopperLayerMax = 31;
  193. for( ; gerb_item; gerb_item = gerb_item->Next() )
  194. {
  195. int layer = gerb_item->GetLayer();
  196. LAYER_NUM pcb_layer_number = aLayerLookUpTable[layer];
  197. if( !IsPcbLayer( pcb_layer_number ) )
  198. continue;
  199. if( pcb_layer_number > pcbCopperLayerMax )
  200. export_non_copper_item( gerb_item, pcb_layer_number );
  201. }
  202. // Copper layers
  203. gerb_item = m_gerbview_frame->GetItemsList();
  204. for( ; gerb_item; gerb_item = gerb_item->Next() )
  205. {
  206. int layer = gerb_item->GetLayer();
  207. LAYER_NUM pcb_layer_number = aLayerLookUpTable[layer];
  208. if( pcb_layer_number < 0 || pcb_layer_number > pcbCopperLayerMax )
  209. continue;
  210. else
  211. export_copper_item( gerb_item, pcb_layer_number );
  212. }
  213. fprintf( m_fp, ")\n" );
  214. fclose( m_fp );
  215. m_fp = NULL;
  216. return true;
  217. }
  218. void GBR_TO_PCB_EXPORTER::export_non_copper_item( GERBER_DRAW_ITEM* aGbrItem, LAYER_NUM aLayer )
  219. {
  220. bool isArc = false;
  221. double angle = 0;
  222. wxPoint seg_start = aGbrItem->m_Start;
  223. wxPoint seg_end = aGbrItem->m_End;
  224. if( aGbrItem->m_Shape == GBR_ARC )
  225. {
  226. double a = atan2( (double) ( aGbrItem->m_Start.y - aGbrItem->m_ArcCentre.y),
  227. (double) ( aGbrItem->m_Start.x - aGbrItem->m_ArcCentre.x ) );
  228. double b = atan2( (double) ( aGbrItem->m_End.y - aGbrItem->m_ArcCentre.y ),
  229. (double) ( aGbrItem->m_End.x - aGbrItem->m_ArcCentre.x ) );
  230. isArc = true;
  231. angle = RAD2DEG(b - a);
  232. seg_start = aGbrItem->m_ArcCentre;
  233. // Ensure arc orientation is CCW
  234. if( angle < 0 )
  235. angle += 360.0;
  236. }
  237. // Reverse Y axis:
  238. NEGATE( seg_start.y );
  239. NEGATE( seg_end.y );
  240. writePcbLineItem( isArc, seg_start, seg_end, aGbrItem->m_Size.x, aLayer, angle );
  241. }
  242. void GBR_TO_PCB_EXPORTER::export_copper_item( GERBER_DRAW_ITEM* aGbrItem, LAYER_NUM aLayer )
  243. {
  244. switch( aGbrItem->m_Shape )
  245. {
  246. case GBR_SPOT_CIRCLE:
  247. case GBR_SPOT_RECT:
  248. case GBR_SPOT_OVAL:
  249. // replace spots with vias when possible
  250. export_flashed_copper_item( aGbrItem );
  251. break;
  252. case GBR_ARC:
  253. export_segarc_copper_item( aGbrItem, aLayer );
  254. break;
  255. default:
  256. export_segline_copper_item( aGbrItem, aLayer );
  257. break;
  258. }
  259. }
  260. void GBR_TO_PCB_EXPORTER::export_segline_copper_item( GERBER_DRAW_ITEM* aGbrItem, LAYER_NUM aLayer )
  261. {
  262. wxPoint seg_start, seg_end;
  263. seg_start = aGbrItem->m_Start;
  264. seg_end = aGbrItem->m_End;
  265. // Reverse Y axis:
  266. NEGATE( seg_start.y );
  267. NEGATE( seg_end.y );
  268. writeCopperLineItem( seg_start, seg_end, aGbrItem->m_Size.x, aLayer );
  269. }
  270. void GBR_TO_PCB_EXPORTER::writeCopperLineItem( wxPoint& aStart, wxPoint& aEnd,
  271. int aWidth, LAYER_NUM aLayer )
  272. {
  273. fprintf( m_fp, "(segment (start %s %s) (end %s %s) (width %s) (layer %s) (net 0))\n",
  274. Double2Str( TO_PCB_UNIT(aStart.x) ).c_str(),
  275. Double2Str( TO_PCB_UNIT(aStart.y) ).c_str(),
  276. Double2Str( TO_PCB_UNIT(aEnd.x) ).c_str(),
  277. Double2Str( TO_PCB_UNIT(aEnd.y) ).c_str(),
  278. Double2Str( TO_PCB_UNIT( aWidth ) ).c_str(),
  279. TO_UTF8( GetPCBDefaultLayerName( aLayer ) ) );
  280. }
  281. void GBR_TO_PCB_EXPORTER::export_segarc_copper_item( GERBER_DRAW_ITEM* aGbrItem, LAYER_NUM aLayer )
  282. {
  283. double a = atan2( (double) ( aGbrItem->m_Start.y - aGbrItem->m_ArcCentre.y ),
  284. (double) ( aGbrItem->m_Start.x - aGbrItem->m_ArcCentre.x ) );
  285. double b = atan2( (double) ( aGbrItem->m_End.y - aGbrItem->m_ArcCentre.y ),
  286. (double) ( aGbrItem->m_End.x - aGbrItem->m_ArcCentre.x ) );
  287. wxPoint start = aGbrItem->m_Start;
  288. wxPoint end = aGbrItem->m_End;
  289. /* Because Pcbnew does not know arcs in tracks,
  290. * approximate arc by segments (SEG_COUNT__CIRCLE segment per 360 deg)
  291. * The arc is drawn anticlockwise from the start point to the end point.
  292. */
  293. #define SEG_COUNT_CIRCLE 16
  294. #define DELTA_ANGLE 2 * M_PI / SEG_COUNT_CIRCLE
  295. // calculate the number of segments from a to b.
  296. // we want CNT_PER_360 segments fo a circle
  297. if( a > b )
  298. b += 2 * M_PI;
  299. wxPoint curr_start = start;
  300. wxPoint seg_start, seg_end;
  301. int ii = 1;
  302. for( double rot = a; rot < (b - DELTA_ANGLE); rot += DELTA_ANGLE, ii++ )
  303. {
  304. seg_start = curr_start;
  305. wxPoint curr_end = start;
  306. RotatePoint( &curr_end, aGbrItem->m_ArcCentre,
  307. -RAD2DECIDEG( DELTA_ANGLE * ii ) );
  308. seg_end = curr_end;
  309. // Reverse Y axis:
  310. NEGATE( seg_start.y );
  311. NEGATE( seg_end.y );
  312. writeCopperLineItem( seg_start, seg_end, aGbrItem->m_Size.x, aLayer );
  313. curr_start = curr_end;
  314. }
  315. if( end != curr_start )
  316. {
  317. seg_start = curr_start;
  318. seg_end = end;
  319. // Reverse Y axis:
  320. NEGATE( seg_start.y );
  321. NEGATE( seg_end.y );
  322. writeCopperLineItem( seg_start, seg_end, aGbrItem->m_Size.x, aLayer );
  323. }
  324. }
  325. /*
  326. * creates a via from a flashed gerber item.
  327. * Flashed items are usually pads or vias, so we try to export all of them
  328. * using vias
  329. */
  330. void GBR_TO_PCB_EXPORTER::export_flashed_copper_item( GERBER_DRAW_ITEM* aGbrItem )
  331. {
  332. // First, explore already created vias, before creating a new via
  333. for( unsigned ii = 0; ii < m_vias_coordinates.size(); ii++ )
  334. {
  335. if( m_vias_coordinates[ii] == aGbrItem->m_Start ) // Already created
  336. return;
  337. }
  338. m_vias_coordinates.push_back( aGbrItem->m_Start );
  339. wxPoint via_pos = aGbrItem->m_Start;
  340. int width = (aGbrItem->m_Size.x + aGbrItem->m_Size.y) / 2;
  341. // Reverse Y axis:
  342. NEGATE( via_pos.y );
  343. // Layers are Front to Back
  344. fprintf( m_fp, " (via (at %s %s) (size %s)",
  345. Double2Str( TO_PCB_UNIT(via_pos.x) ).c_str(),
  346. Double2Str( TO_PCB_UNIT(via_pos.y) ).c_str(),
  347. Double2Str( TO_PCB_UNIT( width ) ).c_str() );
  348. fprintf( m_fp, " (layers %s %s))\n",
  349. TO_UTF8( GetPCBDefaultLayerName( F_Cu ) ),
  350. TO_UTF8( GetPCBDefaultLayerName( B_Cu ) ) );
  351. }
  352. void GBR_TO_PCB_EXPORTER::writePcbHeader( LAYER_NUM* aLayerLookUpTable )
  353. {
  354. fprintf( m_fp, "(kicad_pcb (version 4) (host Gerbview \"%s\")\n\n",
  355. TO_UTF8( GetBuildVersion() ) );
  356. // Write layers section
  357. fprintf( m_fp, " (layers \n" );
  358. for( int ii = 0; ii < m_pcbCopperLayersCount; ii++ )
  359. {
  360. int id = ii;
  361. if( ii == m_pcbCopperLayersCount-1)
  362. id = B_Cu;
  363. fprintf( m_fp, " (%d %s signal)\n", id, TO_UTF8( GetPCBDefaultLayerName( id ) ) );
  364. }
  365. for( int ii = B_Adhes; ii < LAYER_ID_COUNT; ii++ )
  366. {
  367. fprintf( m_fp, " (%d %s user)\n", ii, TO_UTF8( GetPCBDefaultLayerName( ii ) ) );
  368. }
  369. fprintf( m_fp, " )\n\n" );
  370. }
  371. void GBR_TO_PCB_EXPORTER::writePcbLineItem( bool aIsArc, wxPoint& aStart, wxPoint& aEnd,
  372. int aWidth, LAYER_NUM aLayer, double aAngle )
  373. {
  374. if( aIsArc && ( aAngle == 360.0 || aAngle == 0 ) )
  375. {
  376. fprintf( m_fp, "(gr_circle (center %s %s) (end %s %s)(layer %s) (width %s))\n",
  377. Double2Str( TO_PCB_UNIT(aStart.x) ).c_str(),
  378. Double2Str( TO_PCB_UNIT(aStart.y) ).c_str(),
  379. Double2Str( TO_PCB_UNIT(aEnd.x) ).c_str(),
  380. Double2Str( TO_PCB_UNIT(aEnd.y) ).c_str(),
  381. TO_UTF8( GetPCBDefaultLayerName( aLayer ) ),
  382. Double2Str( TO_PCB_UNIT( aWidth ) ).c_str()
  383. );
  384. }
  385. else if( aIsArc )
  386. {
  387. fprintf( m_fp, "(gr_arc (start %s %s) (end %s %s) (angle %s)(layer %s) (width %s))\n",
  388. Double2Str( TO_PCB_UNIT(aStart.x) ).c_str(),
  389. Double2Str( TO_PCB_UNIT(aStart.y) ).c_str(),
  390. Double2Str( TO_PCB_UNIT(aEnd.x) ).c_str(),
  391. Double2Str( TO_PCB_UNIT(aEnd.y) ).c_str(),
  392. Double2Str( aAngle ).c_str(),
  393. TO_UTF8( GetPCBDefaultLayerName( aLayer ) ),
  394. Double2Str( TO_PCB_UNIT( aWidth ) ).c_str()
  395. );
  396. }
  397. else
  398. {
  399. fprintf( m_fp, "(gr_line (start %s %s) (end %s %s)(layer %s) (width %s))\n",
  400. Double2Str( TO_PCB_UNIT(aStart.x) ).c_str(),
  401. Double2Str( TO_PCB_UNIT(aStart.y) ).c_str(),
  402. Double2Str( TO_PCB_UNIT(aEnd.x) ).c_str(),
  403. Double2Str( TO_PCB_UNIT(aEnd.y) ).c_str(),
  404. TO_UTF8( GetPCBDefaultLayerName( aLayer ) ),
  405. Double2Str( TO_PCB_UNIT( aWidth ) ).c_str()
  406. );
  407. }
  408. }