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.

312 lines
8.1 KiB

  1. /*
  2. * This program source code file is part of kicad2mcad
  3. *
  4. * Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
  5. * Copyright (C) 2016-2017 KiCad Developers, see AUTHORS.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 <wx/app.h>
  25. #include <wx/cmdline.h>
  26. #include <wx/log.h>
  27. #include <wx/string.h>
  28. #include <wx/filename.h>
  29. #include <sstream>
  30. #include <iostream>
  31. #include <sstream>
  32. #include <Standard_Failure.hxx>
  33. #include "kicadpcb.h"
  34. class KICAD2MCAD : public wxAppConsole
  35. {
  36. public:
  37. virtual bool OnInit() override;
  38. virtual int OnRun() override;
  39. virtual void OnInitCmdLine(wxCmdLineParser& parser) override;
  40. virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override;
  41. private:
  42. #ifdef SUPPORTS_IGES
  43. bool m_fmtIGES;
  44. #endif
  45. bool m_overwrite;
  46. bool m_useGridOrigin;
  47. bool m_useDrillOrigin;
  48. bool m_includeVirtual;
  49. wxString m_filename;
  50. wxString m_outputFile;
  51. double m_xOrigin;
  52. double m_yOrigin;
  53. double m_minDistance;
  54. };
  55. static const wxCmdLineEntryDesc cmdLineDesc[] =
  56. {
  57. { wxCMD_LINE_PARAM, NULL, NULL, _( "pcb_filename" ).mb_str(),
  58. wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY },
  59. { wxCMD_LINE_OPTION, "o", "output-filename", _( "output filename" ).mb_str(),
  60. wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
  61. #ifdef SUPPORTS_IGES
  62. { wxCMD_LINE_SWITCH, "fmt-iges", NULL, _("IGES output (default STEP)").mb_str(),
  63. wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
  64. #endif
  65. { wxCMD_LINE_SWITCH, "f", "force", _( "overwrite output file" ).mb_str(),
  66. wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
  67. { wxCMD_LINE_SWITCH, NULL, "drill-origin", _( "Use Drill Origin for output origin" ).mb_str(),
  68. wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
  69. { wxCMD_LINE_SWITCH, NULL, "grid-origin", _( "Use Grid Origin for output origin" ).mb_str(),
  70. wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
  71. { wxCMD_LINE_OPTION, NULL, "user-origin",
  72. _( "User-specified output origin ex. 1x1in, 1x1inch, 25.4x25.4mm (default mm)" ).mb_str(),
  73. wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
  74. { wxCMD_LINE_SWITCH, NULL, "no-virtual",
  75. _( "exclude 3D models for components with 'virtual' attribute" ).mb_str(),
  76. wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
  77. { wxCMD_LINE_OPTION, NULL, "min-distance",
  78. _( "Minimum distance between points to treat them as separate ones (default 0.01 mm)" ).mb_str(),
  79. wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
  80. { wxCMD_LINE_SWITCH, "h", NULL, _( "display this message" ).mb_str(),
  81. wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
  82. { wxCMD_LINE_NONE }
  83. };
  84. wxIMPLEMENT_APP_CONSOLE( KICAD2MCAD );
  85. bool KICAD2MCAD::OnInit()
  86. {
  87. #ifdef SUPPORTS_IGES
  88. m_fmtIGES = false;
  89. #endif
  90. m_overwrite = false;
  91. m_useGridOrigin = false;
  92. m_useDrillOrigin = false;
  93. m_includeVirtual = true;
  94. m_xOrigin = 0.0;
  95. m_yOrigin = 0.0;
  96. m_minDistance = MIN_DISTANCE;
  97. if( !wxAppConsole::OnInit() )
  98. return false;
  99. return true;
  100. }
  101. void KICAD2MCAD::OnInitCmdLine( wxCmdLineParser& parser )
  102. {
  103. parser.SetDesc( cmdLineDesc );
  104. parser.SetSwitchChars( "-" );
  105. return;
  106. }
  107. bool KICAD2MCAD::OnCmdLineParsed( wxCmdLineParser& parser )
  108. {
  109. #ifdef SUPPORTS_IGES
  110. if( parser.Found( "fmt-iges" ) )
  111. m_fmtIGES = true;
  112. #endif
  113. if( parser.Found( "f" ) )
  114. m_overwrite = true;
  115. if( parser.Found( "grid-origin" ) )
  116. m_useGridOrigin = true;
  117. if( parser.Found( "drill-origin" ) )
  118. m_useDrillOrigin = true;
  119. if( parser.Found( "no-virtual" ) )
  120. m_includeVirtual = false;
  121. wxString tstr;
  122. if( parser.Found( "user-origin", &tstr ) )
  123. {
  124. std::istringstream istr;
  125. istr.str( std::string( tstr.ToUTF8() ) );
  126. istr >> m_xOrigin;
  127. if( istr.fail() )
  128. {
  129. parser.Usage();
  130. return false;
  131. }
  132. char tmpc;
  133. istr >> tmpc;
  134. if( istr.fail() || ( tmpc != 'x' && tmpc != 'X' ) )
  135. {
  136. parser.Usage();
  137. return false;
  138. }
  139. istr >> m_yOrigin;
  140. if( istr.fail() )
  141. {
  142. parser.Usage();
  143. return false;
  144. }
  145. if( !istr.eof() )
  146. {
  147. std::string tunit;
  148. istr >> tunit;
  149. if( !tunit.compare( "in" ) || !tunit.compare( "inch" ) )
  150. {
  151. m_xOrigin *= 25.4;
  152. m_yOrigin *= 25.4;
  153. }
  154. else if( tunit.compare( "mm" ) )
  155. {
  156. parser.Usage();
  157. return false;
  158. }
  159. }
  160. }
  161. if( parser.Found( "min-distance", &tstr ) )
  162. {
  163. std::istringstream istr;
  164. istr.str( std::string( tstr.ToUTF8() ) );
  165. istr >> m_minDistance;
  166. if( istr.fail() )
  167. {
  168. parser.Usage();
  169. return false;
  170. }
  171. if( !istr.eof() )
  172. {
  173. std::string tunit;
  174. istr >> tunit;
  175. if( !tunit.compare( "in" ) || !tunit.compare( "inch" ) )
  176. {
  177. m_minDistance *= 25.4;
  178. }
  179. else if( tunit.compare( "mm" ) )
  180. {
  181. parser.Usage();
  182. return false;
  183. }
  184. }
  185. }
  186. if( parser.Found( "o", &tstr ) )
  187. m_outputFile = tstr;
  188. if( parser.GetParamCount() < 1 )
  189. {
  190. parser.Usage();
  191. return false;
  192. }
  193. m_filename = parser.GetParam( 0 );
  194. return true;
  195. }
  196. int KICAD2MCAD::OnRun()
  197. {
  198. wxFileName fname( m_filename );
  199. if( !fname.FileExists() )
  200. {
  201. std::ostringstream ostr;
  202. ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
  203. ostr << " * no such file: '" << m_filename.ToUTF8() << "'\n";
  204. wxLogMessage( "%s\n", ostr.str().c_str() );
  205. return -1;
  206. }
  207. wxFileName tfname;
  208. if( m_outputFile.empty() )
  209. tfname.Assign( fname.GetFullPath() );
  210. else
  211. tfname.Assign( m_outputFile );
  212. // Set the file extension if the user's requested file name does not have an extension.
  213. if( !tfname.HasExt() )
  214. {
  215. #ifdef SUPPORTS_IGES
  216. if( m_fmtIGES )
  217. tfname.SetExt( "igs" );
  218. else
  219. #endif
  220. tfname.SetExt( "stp" );
  221. }
  222. wxString outfile = tfname.GetFullPath();
  223. KICADPCB pcb;
  224. pcb.SetOrigin( m_xOrigin, m_yOrigin );
  225. pcb.SetMinDistance( m_minDistance );
  226. if( pcb.ReadFile( m_filename ) )
  227. {
  228. if( m_useDrillOrigin )
  229. pcb.UseDrillOrigin( true );
  230. if( m_useGridOrigin )
  231. pcb.UseGridOrigin( true );
  232. bool res;
  233. try
  234. {
  235. pcb.ComposePCB( m_includeVirtual );
  236. #ifdef SUPPORTS_IGES
  237. if( m_fmtIGES )
  238. res = pcb.WriteIGES( outfile, m_overwrite );
  239. else
  240. #endif
  241. res = pcb.WriteSTEP( outfile, m_overwrite );
  242. if( !res )
  243. return -1;
  244. }
  245. catch( const Standard_Failure& e )
  246. {
  247. e.Print( std::cerr );
  248. return -1;
  249. }
  250. catch( ... )
  251. {
  252. std::cerr << "** (no exception information)\n";
  253. return -1;
  254. }
  255. }
  256. return 0;
  257. }