2016-09-02 10:08:40 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of kicad2mcad
|
|
|
|
*
|
|
|
|
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
2017-08-09 17:17:26 +00:00
|
|
|
* Copyright (C) 2016-2017 KiCad Developers, see AUTHORS.txt for contributors.
|
2016-09-02 10:08:40 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <wx/app.h>
|
|
|
|
#include <wx/cmdline.h>
|
|
|
|
#include <wx/log.h>
|
|
|
|
#include <wx/string.h>
|
|
|
|
#include <wx/filename.h>
|
|
|
|
#include <sstream>
|
|
|
|
#include <iostream>
|
2016-09-18 02:24:04 +00:00
|
|
|
#include <sstream>
|
2016-09-02 10:08:40 +00:00
|
|
|
#include <Standard_Failure.hxx>
|
|
|
|
|
2019-04-15 17:09:27 +00:00
|
|
|
#include "pcb/kicadpcb.h"
|
2016-09-02 10:08:40 +00:00
|
|
|
|
|
|
|
class KICAD2MCAD : public wxAppConsole
|
|
|
|
{
|
|
|
|
public:
|
2016-09-26 06:40:12 +00:00
|
|
|
virtual bool OnInit() override;
|
|
|
|
virtual int OnRun() override;
|
|
|
|
virtual void OnInitCmdLine(wxCmdLineParser& parser) override;
|
|
|
|
virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override;
|
2016-09-02 10:08:40 +00:00
|
|
|
|
|
|
|
private:
|
2018-09-11 07:22:10 +00:00
|
|
|
///> Returns file extension for the selected output format
|
|
|
|
wxString getOutputExt() const;
|
|
|
|
|
2016-09-02 10:08:40 +00:00
|
|
|
#ifdef SUPPORTS_IGES
|
|
|
|
bool m_fmtIGES;
|
|
|
|
#endif
|
|
|
|
bool m_overwrite;
|
2016-09-04 07:08:56 +00:00
|
|
|
bool m_useGridOrigin;
|
|
|
|
bool m_useDrillOrigin;
|
2016-09-18 00:25:10 +00:00
|
|
|
bool m_includeVirtual;
|
2016-09-02 10:08:40 +00:00
|
|
|
wxString m_filename;
|
2016-09-18 02:24:04 +00:00
|
|
|
wxString m_outputFile;
|
2016-09-02 10:08:40 +00:00
|
|
|
double m_xOrigin;
|
|
|
|
double m_yOrigin;
|
2018-06-19 08:14:10 +00:00
|
|
|
double m_minDistance;
|
2016-09-02 10:08:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const wxCmdLineEntryDesc cmdLineDesc[] =
|
|
|
|
{
|
2016-09-22 14:50:44 +00:00
|
|
|
{ wxCMD_LINE_PARAM, NULL, NULL, _( "pcb_filename" ).mb_str(),
|
2016-09-02 10:08:40 +00:00
|
|
|
wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY },
|
2016-09-22 14:50:44 +00:00
|
|
|
{ wxCMD_LINE_OPTION, "o", "output-filename", _( "output filename" ).mb_str(),
|
2016-09-18 02:24:04 +00:00
|
|
|
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
2016-09-02 10:08:40 +00:00
|
|
|
#ifdef SUPPORTS_IGES
|
2016-09-22 14:50:44 +00:00
|
|
|
{ wxCMD_LINE_SWITCH, "fmt-iges", NULL, _("IGES output (default STEP)").mb_str(),
|
2016-09-02 10:08:40 +00:00
|
|
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
|
|
|
#endif
|
2016-09-22 14:50:44 +00:00
|
|
|
{ wxCMD_LINE_SWITCH, "f", "force", _( "overwrite output file" ).mb_str(),
|
2016-09-18 02:24:04 +00:00
|
|
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
2016-09-22 14:50:44 +00:00
|
|
|
{ wxCMD_LINE_SWITCH, NULL, "drill-origin", _( "Use Drill Origin for output origin" ).mb_str(),
|
2016-09-02 10:08:40 +00:00
|
|
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
2016-09-22 14:50:44 +00:00
|
|
|
{ wxCMD_LINE_SWITCH, NULL, "grid-origin", _( "Use Grid Origin for output origin" ).mb_str(),
|
2016-09-18 02:24:04 +00:00
|
|
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
|
|
|
{ wxCMD_LINE_OPTION, NULL, "user-origin",
|
2016-09-22 14:50:44 +00:00
|
|
|
_( "User-specified output origin ex. 1x1in, 1x1inch, 25.4x25.4mm (default mm)" ).mb_str(),
|
2016-09-18 02:24:04 +00:00
|
|
|
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
2016-09-18 00:25:10 +00:00
|
|
|
{ wxCMD_LINE_SWITCH, NULL, "no-virtual",
|
2016-09-22 14:50:44 +00:00
|
|
|
_( "exclude 3D models for components with 'virtual' attribute" ).mb_str(),
|
2016-09-18 00:25:10 +00:00
|
|
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
2018-06-19 08:14:10 +00:00
|
|
|
{ wxCMD_LINE_OPTION, NULL, "min-distance",
|
|
|
|
_( "Minimum distance between points to treat them as separate ones (default 0.01 mm)" ).mb_str(),
|
|
|
|
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
2016-09-22 14:50:44 +00:00
|
|
|
{ wxCMD_LINE_SWITCH, "h", NULL, _( "display this message" ).mb_str(),
|
2016-09-02 10:08:40 +00:00
|
|
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
|
|
|
|
{ wxCMD_LINE_NONE }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
wxIMPLEMENT_APP_CONSOLE( KICAD2MCAD );
|
|
|
|
|
|
|
|
|
|
|
|
bool KICAD2MCAD::OnInit()
|
|
|
|
{
|
|
|
|
#ifdef SUPPORTS_IGES
|
|
|
|
m_fmtIGES = false;
|
|
|
|
#endif
|
|
|
|
m_overwrite = false;
|
2016-09-04 07:08:56 +00:00
|
|
|
m_useGridOrigin = false;
|
|
|
|
m_useDrillOrigin = false;
|
2016-09-18 00:25:10 +00:00
|
|
|
m_includeVirtual = true;
|
2016-09-02 10:08:40 +00:00
|
|
|
m_xOrigin = 0.0;
|
|
|
|
m_yOrigin = 0.0;
|
2018-06-19 08:14:10 +00:00
|
|
|
m_minDistance = MIN_DISTANCE;
|
2016-09-02 10:08:40 +00:00
|
|
|
|
|
|
|
if( !wxAppConsole::OnInit() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KICAD2MCAD::OnInitCmdLine( wxCmdLineParser& parser )
|
|
|
|
{
|
|
|
|
parser.SetDesc( cmdLineDesc );
|
|
|
|
parser.SetSwitchChars( "-" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KICAD2MCAD::OnCmdLineParsed( wxCmdLineParser& parser )
|
|
|
|
{
|
|
|
|
#ifdef SUPPORTS_IGES
|
2016-09-18 02:24:04 +00:00
|
|
|
if( parser.Found( "fmt-iges" ) )
|
2016-09-02 10:08:40 +00:00
|
|
|
m_fmtIGES = true;
|
|
|
|
#endif
|
|
|
|
|
2016-09-18 02:24:04 +00:00
|
|
|
if( parser.Found( "f" ) )
|
2016-09-02 10:08:40 +00:00
|
|
|
m_overwrite = true;
|
|
|
|
|
2016-09-18 02:24:04 +00:00
|
|
|
if( parser.Found( "grid-origin" ) )
|
2016-09-04 07:08:56 +00:00
|
|
|
m_useGridOrigin = true;
|
|
|
|
|
2016-09-18 02:24:04 +00:00
|
|
|
if( parser.Found( "drill-origin" ) )
|
2016-09-04 07:08:56 +00:00
|
|
|
m_useDrillOrigin = true;
|
|
|
|
|
2016-09-18 00:25:10 +00:00
|
|
|
if( parser.Found( "no-virtual" ) )
|
|
|
|
m_includeVirtual = false;
|
|
|
|
|
2016-09-18 02:24:04 +00:00
|
|
|
wxString tstr;
|
|
|
|
|
|
|
|
if( parser.Found( "user-origin", &tstr ) )
|
|
|
|
{
|
|
|
|
std::istringstream istr;
|
|
|
|
istr.str( std::string( tstr.ToUTF8() ) );
|
|
|
|
istr >> m_xOrigin;
|
|
|
|
|
|
|
|
if( istr.fail() )
|
|
|
|
{
|
|
|
|
parser.Usage();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
char tmpc;
|
|
|
|
istr >> tmpc;
|
|
|
|
|
|
|
|
if( istr.fail() || ( tmpc != 'x' && tmpc != 'X' ) )
|
|
|
|
{
|
|
|
|
parser.Usage();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
istr >> m_yOrigin;
|
|
|
|
|
|
|
|
if( istr.fail() )
|
|
|
|
{
|
|
|
|
parser.Usage();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !istr.eof() )
|
|
|
|
{
|
|
|
|
std::string tunit;
|
|
|
|
istr >> tunit;
|
|
|
|
|
|
|
|
if( !tunit.compare( "in" ) || !tunit.compare( "inch" ) )
|
|
|
|
{
|
2018-06-19 08:01:32 +00:00
|
|
|
m_xOrigin *= 25.4;
|
|
|
|
m_yOrigin *= 25.4;
|
|
|
|
}
|
|
|
|
else if( tunit.compare( "mm" ) )
|
|
|
|
{
|
|
|
|
parser.Usage();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-19 08:14:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
if( parser.Found( "min-distance", &tstr ) )
|
|
|
|
{
|
|
|
|
std::istringstream istr;
|
|
|
|
istr.str( std::string( tstr.ToUTF8() ) );
|
|
|
|
istr >> m_minDistance;
|
|
|
|
|
|
|
|
if( istr.fail() )
|
|
|
|
{
|
|
|
|
parser.Usage();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !istr.eof() )
|
|
|
|
{
|
|
|
|
std::string tunit;
|
|
|
|
istr >> tunit;
|
|
|
|
|
|
|
|
if( !tunit.compare( "in" ) || !tunit.compare( "inch" ) )
|
|
|
|
{
|
|
|
|
m_minDistance *= 25.4;
|
2016-09-18 02:24:04 +00:00
|
|
|
}
|
|
|
|
else if( tunit.compare( "mm" ) )
|
|
|
|
{
|
|
|
|
parser.Usage();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( parser.Found( "o", &tstr ) )
|
|
|
|
m_outputFile = tstr;
|
2016-09-02 10:08:40 +00:00
|
|
|
|
2016-09-18 00:25:10 +00:00
|
|
|
|
|
|
|
if( parser.GetParamCount() < 1 )
|
|
|
|
{
|
|
|
|
parser.Usage();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_filename = parser.GetParam( 0 );
|
2016-09-02 10:08:40 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KICAD2MCAD::OnRun()
|
|
|
|
{
|
|
|
|
wxFileName fname( m_filename );
|
|
|
|
|
|
|
|
if( !fname.FileExists() )
|
|
|
|
{
|
|
|
|
std::ostringstream ostr;
|
|
|
|
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
|
|
ostr << " * no such file: '" << m_filename.ToUTF8() << "'\n";
|
|
|
|
wxLogMessage( "%s\n", ostr.str().c_str() );
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-09-18 02:24:04 +00:00
|
|
|
wxFileName tfname;
|
|
|
|
|
|
|
|
if( m_outputFile.empty() )
|
2018-09-11 07:22:10 +00:00
|
|
|
{
|
2016-09-18 02:24:04 +00:00
|
|
|
tfname.Assign( fname.GetFullPath() );
|
2018-09-11 07:22:10 +00:00
|
|
|
tfname.SetExt( getOutputExt() );
|
|
|
|
}
|
2016-09-18 02:24:04 +00:00
|
|
|
else
|
2018-09-11 07:22:10 +00:00
|
|
|
{
|
2016-09-18 02:24:04 +00:00
|
|
|
tfname.Assign( m_outputFile );
|
|
|
|
|
2018-09-11 07:22:10 +00:00
|
|
|
// Set the file extension if the user's requested
|
|
|
|
// file name does not have an extension.
|
|
|
|
if( !tfname.HasExt() )
|
|
|
|
tfname.SetExt( getOutputExt() );
|
2017-08-09 17:17:26 +00:00
|
|
|
}
|
2016-09-02 10:08:40 +00:00
|
|
|
|
2018-09-11 07:23:11 +00:00
|
|
|
if( tfname.FileExists() && !m_overwrite )
|
|
|
|
{
|
|
|
|
std::cerr << "** Output already exists. "
|
|
|
|
<< "Enable the force overwrite flag to overwrite it." << std::endl;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-09-18 02:24:04 +00:00
|
|
|
wxString outfile = tfname.GetFullPath();
|
2016-09-02 10:08:40 +00:00
|
|
|
KICADPCB pcb;
|
2016-09-18 02:24:04 +00:00
|
|
|
|
2018-06-19 08:01:32 +00:00
|
|
|
pcb.SetOrigin( m_xOrigin, m_yOrigin );
|
2018-06-19 08:14:10 +00:00
|
|
|
pcb.SetMinDistance( m_minDistance );
|
2016-09-02 10:08:40 +00:00
|
|
|
|
|
|
|
if( pcb.ReadFile( m_filename ) )
|
|
|
|
{
|
2016-09-04 07:08:56 +00:00
|
|
|
if( m_useDrillOrigin )
|
|
|
|
pcb.UseDrillOrigin( true );
|
|
|
|
|
|
|
|
if( m_useGridOrigin )
|
|
|
|
pcb.UseGridOrigin( true );
|
|
|
|
|
2016-09-02 10:08:40 +00:00
|
|
|
bool res;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2016-09-18 00:25:10 +00:00
|
|
|
pcb.ComposePCB( m_includeVirtual );
|
2016-09-02 10:08:40 +00:00
|
|
|
|
|
|
|
#ifdef SUPPORTS_IGES
|
|
|
|
if( m_fmtIGES )
|
2018-09-11 07:23:11 +00:00
|
|
|
res = pcb.WriteIGES( outfile );
|
2016-09-02 10:08:40 +00:00
|
|
|
else
|
|
|
|
#endif
|
2018-09-11 07:23:11 +00:00
|
|
|
res = pcb.WriteSTEP( outfile );
|
2016-09-02 10:08:40 +00:00
|
|
|
|
|
|
|
if( !res )
|
|
|
|
return -1;
|
|
|
|
}
|
2018-07-26 12:37:44 +00:00
|
|
|
catch( const Standard_Failure& e )
|
2016-09-02 10:08:40 +00:00
|
|
|
{
|
|
|
|
e.Print( std::cerr );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
catch( ... )
|
|
|
|
{
|
|
|
|
std::cerr << "** (no exception information)\n";
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-09-11 07:22:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
wxString KICAD2MCAD::getOutputExt() const
|
|
|
|
{
|
|
|
|
#ifdef SUPPORTS_IGES
|
|
|
|
if( m_fmtIGES )
|
|
|
|
return wxString( "igs" );
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
return wxString( "stp" );
|
|
|
|
}
|