KiCad2Step code cleaning.
This commit is contained in:
parent
934b6e4cdc
commit
d36fbb864f
|
@ -32,6 +32,11 @@
|
||||||
#include "pluginldr.h"
|
#include "pluginldr.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag to enable plugin loader trace output.
|
||||||
|
*
|
||||||
|
* @ingroup trace_env_vars
|
||||||
|
*/
|
||||||
const wxChar* const tracePluginLoader = wxT( "KICAD_PLUGIN_LOADER" );
|
const wxChar* const tracePluginLoader = wxT( "KICAD_PLUGIN_LOADER" );
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,8 @@ class KICAD2MCAD_APP : public wxApp
|
||||||
public:
|
public:
|
||||||
KICAD2MCAD_APP() :
|
KICAD2MCAD_APP() :
|
||||||
wxApp(),
|
wxApp(),
|
||||||
m_frame( nullptr ),
|
m_Panel( nullptr ),
|
||||||
m_Panel( nullptr )
|
m_frame( nullptr )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual bool OnInit() override;
|
virtual bool OnInit() override;
|
||||||
|
@ -53,24 +53,24 @@ public:
|
||||||
virtual void OnInitCmdLine(wxCmdLineParser& parser) override;
|
virtual void OnInitCmdLine(wxCmdLineParser& parser) override;
|
||||||
virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override;
|
virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override;
|
||||||
|
|
||||||
private:
|
|
||||||
KICAD2STEP_FRAME * m_frame;
|
|
||||||
KICAD2MCAD_PRMS m_params;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PANEL_KICAD2STEP* m_Panel;
|
PANEL_KICAD2STEP* m_Panel;
|
||||||
|
|
||||||
|
private:
|
||||||
|
KICAD2STEP_FRAME* m_frame;
|
||||||
|
KICAD2MCAD_PRMS m_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
wxIMPLEMENT_APP(KICAD2MCAD_APP);
|
|
||||||
|
wxIMPLEMENT_APP( KICAD2MCAD_APP );
|
||||||
|
|
||||||
|
|
||||||
class KICAD2STEP_FRAME : public KICAD2STEP_FRAME_BASE
|
class KICAD2STEP_FRAME : public KICAD2STEP_FRAME_BASE
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
KICAD2STEP_FRAME(const wxString& title);
|
KICAD2STEP_FRAME( const wxString& title );
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
KICAD2MCAD_PRMS::KICAD2MCAD_PRMS()
|
KICAD2MCAD_PRMS::KICAD2MCAD_PRMS()
|
||||||
{
|
{
|
||||||
#ifdef SUPPORTS_IGES
|
#ifdef SUPPORTS_IGES
|
||||||
|
@ -95,38 +95,40 @@ void ReportMessage( const wxString& aMessage )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const wxCmdLineEntryDesc cmdLineDesc[] =
|
static const wxCmdLineEntryDesc cmdLineDesc[] = {
|
||||||
{
|
{ wxCMD_LINE_PARAM, NULL, NULL, _( "pcb_filename" ).mb_str(), wxCMD_LINE_VAL_STRING,
|
||||||
{ wxCMD_LINE_PARAM, NULL, NULL, _( "pcb_filename" ).mb_str(),
|
wxCMD_LINE_OPTION_MANDATORY },
|
||||||
wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY },
|
{ wxCMD_LINE_OPTION, "o", "output-filename", _( "output filename" ).mb_str(),
|
||||||
{ wxCMD_LINE_OPTION, "o", "output-filename", _( "output filename" ).mb_str(),
|
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
|
||||||
#ifdef SUPPORTS_IGES
|
#ifdef SUPPORTS_IGES
|
||||||
{ wxCMD_LINE_SWITCH, "fmt-iges", NULL, _("IGES output (default STEP)").mb_str(),
|
{ wxCMD_LINE_SWITCH, "fmt-iges", NULL, _( "IGES output (default STEP)" ).mb_str(),
|
||||||
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
#endif
|
#endif
|
||||||
{ wxCMD_LINE_SWITCH, "f", "force", _( "overwrite output file" ).mb_str(),
|
|
||||||
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
{ wxCMD_LINE_SWITCH, "f", "force", _( "overwrite output file" ).mb_str(), wxCMD_LINE_VAL_NONE,
|
||||||
{ wxCMD_LINE_SWITCH, NULL, "drill-origin", _( "Use Drill Origin for output origin" ).mb_str(),
|
wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
{ wxCMD_LINE_SWITCH, NULL, "drill-origin", _( "Use Drill Origin for output origin" ).mb_str(),
|
||||||
{ wxCMD_LINE_SWITCH, NULL, "grid-origin", _( "Use Grid Origin for output origin" ).mb_str(),
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
{ wxCMD_LINE_SWITCH, NULL, "grid-origin", _( "Use Grid Origin for output origin" ).mb_str(),
|
||||||
{ wxCMD_LINE_OPTION, NULL, "user-origin",
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
_( "User-specified output origin ex. 1x1in, 1x1inch, 25.4x25.4mm (default mm)" ).mb_str(),
|
{ wxCMD_LINE_OPTION, NULL, "user-origin",
|
||||||
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
_( "User-specified output origin ex. 1x1in, 1x1inch, 25.4x25.4mm (default mm)" ).mb_str(),
|
||||||
{ wxCMD_LINE_SWITCH, NULL, "no-virtual",
|
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
_( "Exclude 3D models for components with 'virtual' attribute" ).mb_str(),
|
{ wxCMD_LINE_SWITCH, NULL, "no-virtual",
|
||||||
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
_( "Exclude 3D models for components with 'virtual' attribute" ).mb_str(),
|
||||||
{ wxCMD_LINE_SWITCH, NULL, "subst-models",
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
_( "Substitute STEP or IGS models with the same name in place of VRML models" ).mb_str(),
|
{ wxCMD_LINE_SWITCH, NULL, "subst-models",
|
||||||
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
_( "Substitute STEP or IGS models with the same name in place of VRML models" ).mb_str(),
|
||||||
{ wxCMD_LINE_OPTION, NULL, "min-distance",
|
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
_( "Minimum distance between points to treat them as separate ones (default 0.01 mm)" ).mb_str(),
|
{ wxCMD_LINE_OPTION, NULL, "min-distance",
|
||||||
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
_( "Minimum distance between points to treat them as separate ones (default 0.01 mm)" )
|
||||||
{ wxCMD_LINE_SWITCH, "h", NULL, _( "display this message" ).mb_str(),
|
.mb_str(),
|
||||||
wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
|
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
{ wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
|
{ wxCMD_LINE_SWITCH, "h", NULL, _( "display this message" ).mb_str(), wxCMD_LINE_VAL_NONE,
|
||||||
};
|
wxCMD_LINE_OPTION_HELP },
|
||||||
|
{ wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
bool KICAD2MCAD_APP::OnInit()
|
bool KICAD2MCAD_APP::OnInit()
|
||||||
|
@ -157,8 +159,8 @@ int KICAD2MCAD_APP::OnRun()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
KICAD2STEP_FRAME::KICAD2STEP_FRAME(const wxString& title)
|
KICAD2STEP_FRAME::KICAD2STEP_FRAME( const wxString& title ) :
|
||||||
: KICAD2STEP_FRAME_BASE(NULL, wxID_ANY, title)
|
KICAD2STEP_FRAME_BASE( NULL, wxID_ANY, title )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +169,6 @@ void KICAD2MCAD_APP::OnInitCmdLine( wxCmdLineParser& parser )
|
||||||
{
|
{
|
||||||
parser.SetDesc( cmdLineDesc );
|
parser.SetDesc( cmdLineDesc );
|
||||||
parser.SetSwitchChars( "-" );
|
parser.SetSwitchChars( "-" );
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -178,8 +179,8 @@ PANEL_KICAD2STEP::PANEL_KICAD2STEP( wxWindow* parent, wxWindowID id, const wxPoi
|
||||||
wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
|
wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
|
||||||
|
|
||||||
m_tcMessages = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
m_tcMessages = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||||
wxTE_MULTILINE|wxTE_READONLY );
|
wxTE_MULTILINE | wxTE_READONLY );
|
||||||
bSizer->Add( m_tcMessages, 1, wxALL|wxEXPAND, 5 );
|
bSizer->Add( m_tcMessages, 1, wxALL | wxEXPAND, 5 );
|
||||||
|
|
||||||
SetSizer( bSizer );
|
SetSizer( bSizer );
|
||||||
Layout();
|
Layout();
|
||||||
|
@ -196,10 +197,10 @@ void PANEL_KICAD2STEP::AppendMessage( const wxString& aMessage )
|
||||||
|
|
||||||
bool KICAD2MCAD_APP::OnCmdLineParsed( wxCmdLineParser& parser )
|
bool KICAD2MCAD_APP::OnCmdLineParsed( wxCmdLineParser& parser )
|
||||||
{
|
{
|
||||||
#ifdef SUPPORTS_IGES
|
#ifdef SUPPORTS_IGES
|
||||||
if( parser.Found( "fmt-iges" ) )
|
if( parser.Found( "fmt-iges" ) )
|
||||||
m_fmtIGES = true;
|
m_fmtIGES = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( parser.Found( "f" ) )
|
if( parser.Found( "f" ) )
|
||||||
m_params.m_overwrite = true;
|
m_params.m_overwrite = true;
|
||||||
|
@ -265,7 +266,6 @@ bool KICAD2MCAD_APP::OnCmdLineParsed( wxCmdLineParser& parser )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if( parser.Found( "min-distance", &tstr ) )
|
if( parser.Found( "min-distance", &tstr ) )
|
||||||
{
|
{
|
||||||
std::istringstream istr;
|
std::istringstream istr;
|
||||||
|
@ -319,20 +319,21 @@ bool KICAD2MCAD_APP::OnCmdLineParsed( wxCmdLineParser& parser )
|
||||||
class STREAMBUF_SWAPPER
|
class STREAMBUF_SWAPPER
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
STREAMBUF_SWAPPER( std::ostream & orig, std::ostream & replacement )
|
STREAMBUF_SWAPPER( std::ostream& orig, std::ostream& replacement ) :
|
||||||
: m_buf( orig.rdbuf() ), m_str( orig )
|
m_buf( orig.rdbuf() ),
|
||||||
|
m_str( orig )
|
||||||
{
|
{
|
||||||
orig.rdbuf( replacement.rdbuf() );
|
orig.rdbuf( replacement.rdbuf() );
|
||||||
}
|
}
|
||||||
|
|
||||||
~STREAMBUF_SWAPPER()
|
~STREAMBUF_SWAPPER()
|
||||||
{
|
{
|
||||||
m_str.rdbuf( m_buf);
|
m_str.rdbuf( m_buf );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::streambuf * m_buf;
|
std::streambuf* m_buf;
|
||||||
std::ostream & m_str;
|
std::ostream& m_str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -342,7 +343,7 @@ int PANEL_KICAD2STEP::RunConverter()
|
||||||
|
|
||||||
if( !fname.FileExists() )
|
if( !fname.FileExists() )
|
||||||
{
|
{
|
||||||
wxMessageBox( wxString::Format( "No such file: %s", m_params.m_filename ) );
|
wxMessageBox( wxString::Format( _( "No such file: %s" ), m_params.m_filename ) );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,8 +366,8 @@ int PANEL_KICAD2STEP::RunConverter()
|
||||||
|
|
||||||
if( out_fname.FileExists() && !m_params.m_overwrite )
|
if( out_fname.FileExists() && !m_params.m_overwrite )
|
||||||
{
|
{
|
||||||
ReportMessage( "** Output already exists.\n"
|
ReportMessage( _( "** Output already exists.\n"
|
||||||
"Enable the force overwrite flag to overwrite it." );
|
"Enable the force overwrite flag to overwrite it." ) );
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -376,14 +377,14 @@ int PANEL_KICAD2STEP::RunConverter()
|
||||||
|
|
||||||
pcb.SetOrigin( m_params.m_xOrigin, m_params.m_yOrigin );
|
pcb.SetOrigin( m_params.m_xOrigin, m_params.m_yOrigin );
|
||||||
pcb.SetMinDistance( m_params.m_minDistance );
|
pcb.SetMinDistance( m_params.m_minDistance );
|
||||||
ReportMessage( wxString::Format( "Read: %s\n", m_params.m_filename ) );
|
ReportMessage( wxString::Format( _( "Read file: '%s'\n" ), m_params.m_filename ) );
|
||||||
|
|
||||||
// create the new streams to "redirect" cout and cerr output to
|
// create the new streams to "redirect" cout and cerr output to
|
||||||
// msgs_from_opencascade and errors_from_opencascade
|
// msgs_from_opencascade and errors_from_opencascade
|
||||||
std::ostringstream msgs_from_opencascade;
|
std::ostringstream msgs_from_opencascade;
|
||||||
std::ostringstream errors_from_opencascade;
|
std::ostringstream errors_from_opencascade;
|
||||||
STREAMBUF_SWAPPER swapper_cout(std::cout, msgs_from_opencascade);
|
STREAMBUF_SWAPPER swapper_cout( std::cout, msgs_from_opencascade );
|
||||||
STREAMBUF_SWAPPER swapper_cerr(std::cerr, errors_from_opencascade);
|
STREAMBUF_SWAPPER swapper_cerr( std::cerr, errors_from_opencascade );
|
||||||
|
|
||||||
if( pcb.ReadFile( m_params.m_filename ) )
|
if( pcb.ReadFile( m_params.m_filename ) )
|
||||||
{
|
{
|
||||||
|
@ -397,44 +398,44 @@ int PANEL_KICAD2STEP::RunConverter()
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ReportMessage( "Build STEP data\n" );
|
ReportMessage( _( "Build STEP data\n" ) );
|
||||||
|
|
||||||
res = pcb.ComposePCB( m_params.m_includeVirtual, m_params.m_substModels );
|
res = pcb.ComposePCB( m_params.m_includeVirtual, m_params.m_substModels );
|
||||||
|
|
||||||
if( !res )
|
if( !res )
|
||||||
{
|
{
|
||||||
ReportMessage( "\n**Error building STEP board model. Abort export **\n" );
|
ReportMessage( _( "\n**Error building STEP board model. Abort export **\n" ) );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportMessage( "Write STEP file\n" );
|
ReportMessage( _( "Write STEP file\n" ) );
|
||||||
|
|
||||||
#ifdef SUPPORTS_IGES
|
#ifdef SUPPORTS_IGES
|
||||||
if( m_fmtIGES )
|
if( m_fmtIGES )
|
||||||
res = pcb.WriteIGES( outfile );
|
res = pcb.WriteIGES( outfile );
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
res = pcb.WriteSTEP( outfile );
|
res = pcb.WriteSTEP( outfile );
|
||||||
|
|
||||||
if( !res )
|
if( !res )
|
||||||
{
|
{
|
||||||
ReportMessage( "\nError Write STEP file\n" );
|
ReportMessage( _( "\nError Write STEP file\n" ) );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch( const Standard_Failure& e )
|
catch( const Standard_Failure& e )
|
||||||
{
|
{
|
||||||
wxString err = e.GetMessageString();
|
wxString err = e.GetMessageString();
|
||||||
wxMessageBox( err, "Export Error" );
|
wxMessageBox( err, _( "Export Error" ) );
|
||||||
|
|
||||||
ReportMessage( wxString::Format( "\nExport Error: %s\n", err ) );
|
ReportMessage( wxString::Format( _( "\nExport Error: %s\n" ), err ) );
|
||||||
ReportMessage( "\n*** Abort export ***\n" );
|
ReportMessage( _( "\n*** Abort export ***\n" ) );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
catch( ... )
|
catch( ... )
|
||||||
{
|
{
|
||||||
wxMessageBox( "(no exception information)", "Unknown error" );
|
wxMessageBox( _( "(no exception information)" ), _( "Unknown error" ) );
|
||||||
ReportMessage( "\nUnknown error\n*** Abort export ***\n" );
|
ReportMessage( _( "\nUnknown error\n*** Abort export ***\n" ) );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,7 +444,7 @@ int PANEL_KICAD2STEP::RunConverter()
|
||||||
msgs << msgs_from_opencascade.str();
|
msgs << msgs_from_opencascade.str();
|
||||||
ReportMessage( msgs );
|
ReportMessage( msgs );
|
||||||
|
|
||||||
ReportMessage( wxString::Format( "\nStep file %s created\n\n", outfile ) );
|
ReportMessage( wxString::Format( _( "\nStep file '%s' created\n\n" ), outfile ) );
|
||||||
|
|
||||||
errs << errors_from_opencascade.str();
|
errs << errors_from_opencascade.str();
|
||||||
ReportMessage( errs );
|
ReportMessage( errs );
|
||||||
|
@ -456,17 +457,17 @@ int PANEL_KICAD2STEP::RunConverter()
|
||||||
{
|
{
|
||||||
if( !success )
|
if( !success )
|
||||||
{
|
{
|
||||||
msg = "Unable to create STEP file.\n"
|
msg = _( "Unable to create STEP file.\n"
|
||||||
"Check that the board has a valid outline and models.";
|
"Check that the board has a valid outline and models." );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg = "STEP file has been created, but there are warnings.";
|
msg = _( "STEP file has been created, but there are warnings." );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // No error messages: the file is expected OK
|
else // No error messages: the file is expected OK
|
||||||
{
|
{
|
||||||
msg.Printf( "STEP file:\n%s\nhas been created successfully.", outfile );
|
msg.Printf( _( "STEP file:\n%s\nhas been created successfully." ), outfile );
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportMessage( msg );
|
ReportMessage( msg );
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part kicad2mcad
|
* This program source code file is part kicad2mcad
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -49,12 +49,21 @@
|
||||||
#define ERRFLG_RELPATH (2)
|
#define ERRFLG_RELPATH (2)
|
||||||
#define ERRFLG_ENVPATH (4)
|
#define ERRFLG_ENVPATH (4)
|
||||||
|
|
||||||
#define MASK_3D_RESOLVER "3D_RESOLVER"
|
|
||||||
|
/**
|
||||||
|
* Flag to enable plugin loader trace output.
|
||||||
|
*
|
||||||
|
* @ingroup trace_env_vars
|
||||||
|
*/
|
||||||
|
const wxChar* const trace3dResolver = wxT( "KICAD_3D_RESOLVER" );
|
||||||
|
|
||||||
|
|
||||||
static std::mutex mutex3D_resolver;
|
static std::mutex mutex3D_resolver;
|
||||||
|
|
||||||
|
|
||||||
static bool getHollerith( const std::string& aString, size_t& aIndex, wxString& aResult );
|
static bool getHollerith( const std::string& aString, size_t& aIndex, wxString& aResult );
|
||||||
|
|
||||||
|
|
||||||
S3D_RESOLVER::S3D_RESOLVER()
|
S3D_RESOLVER::S3D_RESOLVER()
|
||||||
{
|
{
|
||||||
m_errflags = 0;
|
m_errflags = 0;
|
||||||
|
@ -116,15 +125,9 @@ bool S3D_RESOLVER::SetProjectDir( const wxString& aProjDir, bool* flgChanged )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
|
||||||
do {
|
" * [INFO] changed project dir to '%s'" ),
|
||||||
std::ostringstream ostr;
|
__FILE__, __FUNCTION__, __LINE__, m_Paths.front().m_Pathexp );
|
||||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
|
||||||
ostr << " * [INFO] changed project dir to ";
|
|
||||||
ostr << m_Paths.front().m_Pathexp.ToUTF8();
|
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
|
|
||||||
} while( 0 );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -244,15 +247,10 @@ bool S3D_RESOLVER::createPathList( void )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
wxLogTrace( MASK_3D_RESOLVER, " * [3D model] search paths:\n" );
|
wxLogTrace( trace3dResolver, " * [3D model] search paths:\n" );
|
||||||
std::list< SEARCH_PATH >::const_iterator sPL = m_Paths.begin();
|
|
||||||
std::list< SEARCH_PATH >::const_iterator ePL = m_Paths.end();
|
|
||||||
|
|
||||||
while( sPL != ePL )
|
for( const auto searchPath : m_Paths )
|
||||||
{
|
wxLogTrace( trace3dResolver, " + '%s'\n", searchPath.m_Pathexp );
|
||||||
wxLogTrace( MASK_3D_RESOLVER, " + '%s'\n", (*sPL).m_Pathexp.ToUTF8() );
|
|
||||||
++sPL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -409,7 +407,7 @@ wxString S3D_RESOLVER::ResolvePath( const wxString& aFileName )
|
||||||
wxString errmsg = "[3D File Resolver] No such path";
|
wxString errmsg = "[3D File Resolver] No such path";
|
||||||
errmsg.append( "\n" );
|
errmsg.append( "\n" );
|
||||||
errmsg.append( tname );
|
errmsg.append( tname );
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", errmsg.ToUTF8() );
|
wxLogTrace( trace3dResolver, "%s\n", errmsg.ToUTF8() );
|
||||||
}
|
}
|
||||||
|
|
||||||
return wxEmptyString;
|
return wxEmptyString;
|
||||||
|
@ -443,10 +441,9 @@ wxString S3D_RESOLVER::ResolvePath( const wxString& aFileName )
|
||||||
if( !( m_errflags & ERRFLG_ALIAS ) )
|
if( !( m_errflags & ERRFLG_ALIAS ) )
|
||||||
{
|
{
|
||||||
m_errflags |= ERRFLG_ALIAS;
|
m_errflags |= ERRFLG_ALIAS;
|
||||||
wxString errmsg = "[3D File Resolver] No such path; ensure the path alias is defined";
|
wxLogTrace( trace3dResolver,
|
||||||
errmsg.append( "\n" );
|
wxT( "[3D File Resolver] No such path; ensure the path alias is defined %s" ),
|
||||||
errmsg.append( tname.substr( 1 ) );
|
tname.substr( 1 ) );
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", errmsg.ToUTF8() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return wxEmptyString;
|
return wxEmptyString;
|
||||||
|
@ -476,7 +473,8 @@ bool S3D_RESOLVER::addPath( const SEARCH_PATH& aPath )
|
||||||
if( !path.DirExists() )
|
if( !path.DirExists() )
|
||||||
{
|
{
|
||||||
// suppress the message if the missing pathvar is the legacy KICAD6_3DMODEL_DIR variable
|
// suppress the message if the missing pathvar is the legacy KICAD6_3DMODEL_DIR variable
|
||||||
if( aPath.m_Pathvar != "${KICAD6_3DMODEL_DIR}" && aPath.m_Pathvar != "$(KICAD6_3DMODEL_DIR)" )
|
if( aPath.m_Pathvar != "${KICAD6_3DMODEL_DIR}" &&
|
||||||
|
aPath.m_Pathvar != "$(KICAD6_3DMODEL_DIR)" )
|
||||||
{
|
{
|
||||||
wxString msg = _( "The given path does not exist" );
|
wxString msg = _( "The given path does not exist" );
|
||||||
msg.append( "\n" );
|
msg.append( "\n" );
|
||||||
|
@ -541,12 +539,10 @@ bool S3D_RESOLVER::readPathList( void )
|
||||||
|
|
||||||
if( !wxFileName::Exists( cfgname ) )
|
if( !wxFileName::Exists( cfgname ) )
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
wxLogTrace( trace3dResolver, wxT( "%s:%s:d\n"
|
||||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
" * no 3D configuration file '%s'" ),
|
||||||
wxString errmsg = "no 3D configuration file";
|
__FILE__, __FUNCTION__, __LINE__, cfgname );
|
||||||
ostr << " * " << errmsg.ToUTF8() << " '";
|
|
||||||
ostr << cfgname.ToUTF8() << "'";
|
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,11 +550,10 @@ bool S3D_RESOLVER::readPathList( void )
|
||||||
|
|
||||||
if( !cfgFile.is_open() )
|
if( !cfgFile.is_open() )
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
|
||||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
" * Could not open configuration file '%s'" ),
|
||||||
wxString errmsg = "Could not open configuration file";
|
__FILE__, __FUNCTION__, __LINE__, cfgname );
|
||||||
ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
|
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,8 +724,7 @@ wxString S3D_RESOLVER::ShortenPath( const wxString& aFullPathName )
|
||||||
|
|
||||||
while( sL != eL )
|
while( sL != eL )
|
||||||
{
|
{
|
||||||
// undefined paths do not participate in the
|
// undefined paths do not participate in the file name shortening procedure.
|
||||||
// file name shortening procedure
|
|
||||||
if( sL->m_Pathexp.empty() )
|
if( sL->m_Pathexp.empty() )
|
||||||
{
|
{
|
||||||
++sL;
|
++sL;
|
||||||
|
@ -793,8 +787,7 @@ const std::list< SEARCH_PATH >* S3D_RESOLVER::GetPaths( void )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool S3D_RESOLVER::SplitAlias( const wxString& aFileName,
|
bool S3D_RESOLVER::SplitAlias( const wxString& aFileName, wxString& anAlias, wxString& aRelPath )
|
||||||
wxString& anAlias, wxString& aRelPath )
|
|
||||||
{
|
{
|
||||||
anAlias.clear();
|
anAlias.clear();
|
||||||
aRelPath.clear();
|
aRelPath.clear();
|
||||||
|
@ -823,11 +816,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
|
||||||
|
|
||||||
if( aIndex >= aString.size() )
|
if( aIndex >= aString.size() )
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
|
||||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
" * Bad Hollerith string in line \"%s\"" ),
|
||||||
wxString errmsg = "bad Hollerith string on line";
|
__FILE__, __FUNCTION__, __LINE__, aString );
|
||||||
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -836,11 +827,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
|
||||||
|
|
||||||
if( std::string::npos == i2 )
|
if( std::string::npos == i2 )
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
|
||||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
" * missing opening quote mark in line \"%s\"" ),
|
||||||
wxString errmsg = "missing opening quote mark in config file";
|
__FILE__, __FUNCTION__, __LINE__, aString );
|
||||||
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -849,11 +838,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
|
||||||
|
|
||||||
if( i2 >= aString.size() )
|
if( i2 >= aString.size() )
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
|
||||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
" * unexpected end of line in line \"%s\"" ),
|
||||||
wxString errmsg = "invalid entry (unexpected end of line)";
|
__FILE__, __FUNCTION__, __LINE__, aString );
|
||||||
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -865,11 +852,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
|
||||||
|
|
||||||
if( tnum.empty() || aString[i2++] != ':' )
|
if( tnum.empty() || aString[i2++] != ':' )
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
|
||||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
" * Bad Hollerith string in line \"%s\"" ),
|
||||||
wxString errmsg = "bad Hollerith string on line";
|
__FILE__, __FUNCTION__, __LINE__, aString );
|
||||||
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -881,11 +866,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
|
||||||
|
|
||||||
if( (i2 + nchars) >= aString.size() )
|
if( (i2 + nchars) >= aString.size() )
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
|
||||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
" * unexpected end of line in line \"%s\"\n" ),
|
||||||
wxString errmsg = "invalid entry (unexpected end of line)";
|
__FILE__, __FUNCTION__, __LINE__, aString );
|
||||||
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -898,11 +881,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
|
||||||
|
|
||||||
if( i2 >= aString.size() || aString[i2] != '"' )
|
if( i2 >= aString.size() || aString[i2] != '"' )
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
|
||||||
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
" * missing closing quote mark in line \"%s\"" ),
|
||||||
wxString errmsg = "missing closing quote mark in config file";
|
__FILE__, __FUNCTION__, __LINE__, aString );
|
||||||
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
|
|
||||||
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
* Copyright (C) 2015-2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||||
|
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -38,53 +39,52 @@
|
||||||
|
|
||||||
namespace S3D
|
namespace S3D
|
||||||
{
|
{
|
||||||
|
struct rsort_wxString
|
||||||
struct rsort_wxString
|
{
|
||||||
|
bool operator() (const wxString& strA, const wxString& strB ) const
|
||||||
{
|
{
|
||||||
bool operator() (const wxString& strA, const wxString& strB ) const
|
// sort a wxString using the reverse character order; for 3d model
|
||||||
|
// filenames this will typically be a much faster operation than
|
||||||
|
// a normal alphabetic sort
|
||||||
|
wxString::const_reverse_iterator sA = strA.rbegin();
|
||||||
|
wxString::const_reverse_iterator eA = strA.rend();
|
||||||
|
|
||||||
|
wxString::const_reverse_iterator sB = strB.rbegin();
|
||||||
|
wxString::const_reverse_iterator eB = strB.rend();
|
||||||
|
|
||||||
|
if( strA.empty() )
|
||||||
{
|
{
|
||||||
// sort a wxString using the reverse character order; for 3d model
|
|
||||||
// filenames this will typically be a much faster operation than
|
|
||||||
// a normal alphabetic sort
|
|
||||||
wxString::const_reverse_iterator sA = strA.rbegin();
|
|
||||||
wxString::const_reverse_iterator eA = strA.rend();
|
|
||||||
|
|
||||||
wxString::const_reverse_iterator sB = strB.rbegin();
|
|
||||||
wxString::const_reverse_iterator eB = strB.rend();
|
|
||||||
|
|
||||||
if( strA.empty() )
|
|
||||||
{
|
|
||||||
if( strB.empty() )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// note: this rule implies that a null string is first in the sort order
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( strB.empty() )
|
if( strB.empty() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while( sA != eA && sB != eB )
|
// note: this rule implies that a null string is first in the sort order
|
||||||
{
|
|
||||||
if( (*sA) == (*sB) )
|
|
||||||
{
|
|
||||||
++sA;
|
|
||||||
++sB;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( (*sA) < (*sB) )
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( sB == eB )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
if( strB.empty() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while( sA != eA && sB != eB )
|
||||||
|
{
|
||||||
|
if( (*sA) == (*sB) )
|
||||||
|
{
|
||||||
|
++sA;
|
||||||
|
++sB;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (*sA) < (*sB) )
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( sB == eB )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}; // end NAMESPACE
|
}; // end NAMESPACE
|
||||||
|
|
||||||
|
@ -99,128 +99,114 @@ struct SEARCH_PATH
|
||||||
wxString m_Description; // description of the aliased path
|
wxString m_Description; // description of the aliased path
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class S3D_RESOLVER
|
class S3D_RESOLVER
|
||||||
{
|
{
|
||||||
private:
|
public:
|
||||||
wxString m_ConfigDir; // 3D configuration directory
|
S3D_RESOLVER();
|
||||||
std::list< SEARCH_PATH > m_Paths; // list of base paths to search from
|
|
||||||
// mapping of (short) file names to resolved names
|
|
||||||
std::map< wxString, wxString, S3D::rsort_wxString > m_NameMap;
|
|
||||||
int m_errflags;
|
|
||||||
wxString m_curProjDir;
|
|
||||||
// environment variables
|
|
||||||
std::map< wxString, wxString > m_EnvVars;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function createPathList
|
* Set the user's configuration directory for 3D models.
|
||||||
* builds the path list using available information such as
|
*
|
||||||
* KICAD6_3DMODEL_DIR and the 3d_path_list configuration file. Invalid
|
* @param aConfigDir
|
||||||
* paths are silently discarded and removed from the configuration
|
* @return true if the call succeeds (directory exists).
|
||||||
* file.
|
*/
|
||||||
|
bool Set3DConfigDir( const wxString& aConfigDir );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current KiCad project directory as the first entry in the model path list.
|
||||||
|
*
|
||||||
|
* @param aProjDir is the current project directory.
|
||||||
|
* @param flgChanged, if specified, is set to true if the directory actually changed.
|
||||||
|
* @return true if the call succeeds.
|
||||||
|
*/
|
||||||
|
bool SetProjectDir( const wxString& aProjDir, bool* flgChanged = NULL );
|
||||||
|
wxString GetProjectDir( void );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the full path of the given file name.
|
||||||
|
*
|
||||||
|
* In the future remote files may be supported, in which case it is best to require a full
|
||||||
|
* URI in which case #ResolvePath should check that the URI conforms to RFC-2396 and related
|
||||||
|
* documents and copies \a aFileName into the resolved name if the URI is valid.
|
||||||
|
*/
|
||||||
|
wxString ResolvePath( const wxString& aFileName );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce a relative path based on the existing search directories or returns the same path
|
||||||
|
* if the path is not a superset of an existing search path.
|
||||||
|
*
|
||||||
|
* @param aFullPathName is an absolute path to shorten.
|
||||||
|
* @return the shortened path or aFullPathName.
|
||||||
|
*/
|
||||||
|
wxString ShortenPath( const wxString& aFullPathName );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a pointer to the internal path list.
|
||||||
|
*
|
||||||
|
* The list can be used to set up the list of search paths available to a 3D file browser.
|
||||||
|
*
|
||||||
|
* @return the search path list.
|
||||||
|
*/
|
||||||
|
const std::list< SEARCH_PATH >* GetPaths( void );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the given name contains an alias and populates the string with the alias
|
||||||
|
* and the relative path.
|
||||||
|
*/
|
||||||
|
bool SplitAlias( const wxString& aFileName, wxString& anAlias, wxString& aRelPath );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the path contains an alias then \a hasAlias is set true.
|
||||||
|
*
|
||||||
|
* @return true if the given path is a valid aliased relative path.
|
||||||
|
*/
|
||||||
|
bool ValidateFileName( const wxString& aFileName, bool& hasAlias );
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Build the path list using available information such as KICAD6_3DMODEL_DIR and the
|
||||||
|
* 3d_path_list configuration file.
|
||||||
|
*
|
||||||
|
* Invalid paths are silently discarded and removed from the configuration file.
|
||||||
*
|
*
|
||||||
* @return true if at least one valid path was found
|
* @return true if at least one valid path was found
|
||||||
*/
|
*/
|
||||||
bool createPathList( void );
|
bool createPathList( void );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function addPath
|
* Check that \a aPath is valid and adds it to the search list.
|
||||||
* checks that a path is valid and adds it to the search list
|
|
||||||
*
|
*
|
||||||
* @param aPath is the alias set to be checked and added
|
* @param aPath is the alias set to be checked and added.
|
||||||
* @return true if aPath is valid
|
* @return true if \a aPath is valid.
|
||||||
*/
|
*/
|
||||||
bool addPath( const SEARCH_PATH& aPath );
|
bool addPath( const SEARCH_PATH& aPath );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function readPathList
|
* Read a list of path names from a configuration file.
|
||||||
* reads a list of path names from a configuration file
|
|
||||||
*
|
*
|
||||||
* @return true if a file was found and contained at least
|
* @return true if a file was found and contained at least one valid path.
|
||||||
* one valid path
|
|
||||||
*/
|
*/
|
||||||
bool readPathList( void );
|
bool readPathList( void );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function checkEnvVarPath
|
* Check the ${ENV_VAR} component of a path and adds it to the resolver's path list if it
|
||||||
* checks the ${ENV_VAR} component of a path and adds
|
* is not yet in the list.
|
||||||
* it to the resolver's path list if it is not yet in
|
|
||||||
* the list
|
|
||||||
*/
|
*/
|
||||||
void checkEnvVarPath( const wxString& aPath );
|
void checkEnvVarPath( const wxString& aPath );
|
||||||
|
|
||||||
wxString expandVars( const wxString& aPath );
|
wxString expandVars( const wxString& aPath );
|
||||||
|
|
||||||
public:
|
wxString m_ConfigDir; ///< 3D configuration directory.
|
||||||
S3D_RESOLVER();
|
std::list< SEARCH_PATH > m_Paths; ///< List of base search paths.
|
||||||
|
|
||||||
/**
|
///< Mapping of (short) file names to resolved names.
|
||||||
* Function Set3DConfigDir
|
std::map< wxString, wxString, S3D::rsort_wxString > m_NameMap;
|
||||||
* sets the user's configuration directory
|
int m_errflags;
|
||||||
* for 3D models.
|
wxString m_curProjDir;
|
||||||
*
|
|
||||||
* @param aConfigDir
|
|
||||||
* @return true if the call succeeds (directory exists)
|
|
||||||
*/
|
|
||||||
bool Set3DConfigDir( const wxString& aConfigDir );
|
|
||||||
|
|
||||||
/**
|
///< Environment variables.
|
||||||
* Function SetProjectDir
|
std::map< wxString, wxString > m_EnvVars;
|
||||||
* sets the current KiCad project directory as the first
|
|
||||||
* entry in the model path list
|
|
||||||
*
|
|
||||||
* @param aProjDir is the current project directory
|
|
||||||
* @param flgChanged, if specified, is set to true if the directory actually changed
|
|
||||||
* @return true if the call succeeds
|
|
||||||
*/
|
|
||||||
bool SetProjectDir( const wxString& aProjDir, bool* flgChanged = NULL );
|
|
||||||
wxString GetProjectDir( void );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function ResolvePath
|
|
||||||
* determines the full path of the given file name. In the future
|
|
||||||
* remote files may be supported, in which case it is best to
|
|
||||||
* require a full URI in which case ResolvePath should check that
|
|
||||||
* the URI conforms to RFC-2396 and related documents and copies
|
|
||||||
* aFileName into aResolvedName if the URI is valid.
|
|
||||||
*/
|
|
||||||
wxString ResolvePath( const wxString& aFileName );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function ShortenPath
|
|
||||||
* produces a relative path based on the existing
|
|
||||||
* search directories or returns the same path if
|
|
||||||
* the path is not a superset of an existing search path.
|
|
||||||
*
|
|
||||||
* @param aFullPathName is an absolute path to shorten
|
|
||||||
* @return the shortened path or aFullPathName
|
|
||||||
*/
|
|
||||||
wxString ShortenPath( const wxString& aFullPathName );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function GetPaths
|
|
||||||
* returns a pointer to the internal path list; the items in:load
|
|
||||||
*
|
|
||||||
* the list can be used to set up the list of search paths
|
|
||||||
* available to a 3D file browser.
|
|
||||||
*
|
|
||||||
* @return pointer to the internal path list
|
|
||||||
*/
|
|
||||||
const std::list< SEARCH_PATH >* GetPaths( void );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function SplitAlias
|
|
||||||
* returns true if the given name contains an alias and
|
|
||||||
* populates the string anAlias with the alias and aRelPath
|
|
||||||
* with the relative path.
|
|
||||||
*/
|
|
||||||
bool SplitAlias( const wxString& aFileName, wxString& anAlias, wxString& aRelPath );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function ValidateName
|
|
||||||
* returns true if the given path is a valid aliased relative path.
|
|
||||||
* If the path contains an alias then hasAlias is set true.
|
|
||||||
*/
|
|
||||||
bool ValidateFileName( const wxString& aFileName, bool& hasAlias );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RESOLVER_3D_H
|
#endif // RESOLVER_3D_H
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||||
|
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -43,6 +44,15 @@ class S3D_RESOLVER;
|
||||||
|
|
||||||
class KICADFOOTPRINT
|
class KICADFOOTPRINT
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
KICADFOOTPRINT( KICADPCB* aParent );
|
||||||
|
virtual ~KICADFOOTPRINT();
|
||||||
|
|
||||||
|
bool Read( SEXPR::SEXPR* aEntry );
|
||||||
|
|
||||||
|
bool ComposePCB( class PCBMODEL* aPCB, S3D_RESOLVER* resolver,
|
||||||
|
DOUBLET aOrigin, bool aComposeVirtual = true, bool aSubstituteModels = true );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool parseModel( SEXPR::SEXPR* data );
|
bool parseModel( SEXPR::SEXPR* data );
|
||||||
bool parseCurve( SEXPR::SEXPR* data, CURVE_TYPE aCurveType );
|
bool parseCurve( SEXPR::SEXPR* data, CURVE_TYPE aCurveType );
|
||||||
|
@ -64,15 +74,6 @@ private:
|
||||||
std::vector< KICADPAD* > m_pads;
|
std::vector< KICADPAD* > m_pads;
|
||||||
std::vector< KICADCURVE* > m_curves;
|
std::vector< KICADCURVE* > m_curves;
|
||||||
std::vector< KICADMODEL* > m_models;
|
std::vector< KICADMODEL* > m_models;
|
||||||
|
|
||||||
public:
|
|
||||||
KICADFOOTPRINT( KICADPCB* aParent );
|
|
||||||
virtual ~KICADFOOTPRINT();
|
|
||||||
|
|
||||||
bool Read( SEXPR::SEXPR* aEntry );
|
|
||||||
|
|
||||||
bool ComposePCB( class PCBMODEL* aPCB, S3D_RESOLVER* resolver,
|
|
||||||
DOUBLET aOrigin, bool aComposeVirtual = true, bool aSubstituteModels = true );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KICADFOOTPRINT_H
|
#endif // KICADFOOTPRINT_H
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||||
|
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file kicadpad.h
|
* @file kicadpad.h
|
||||||
* declares the PAD description object.
|
* Declare the PAD description object.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef KICADPAD_H
|
#ifndef KICADPAD_H
|
||||||
|
@ -43,10 +44,6 @@ struct KICADDRILL
|
||||||
|
|
||||||
class KICADPAD
|
class KICADPAD
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
bool m_thruhole;
|
|
||||||
bool parseDrill( const SEXPR::SEXPR* aDrill );
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KICADPAD();
|
KICADPAD();
|
||||||
virtual ~KICADPAD();
|
virtual ~KICADPAD();
|
||||||
|
@ -58,9 +55,16 @@ public:
|
||||||
return m_thruhole;
|
return m_thruhole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool parseDrill( const SEXPR::SEXPR* aDrill );
|
||||||
|
|
||||||
|
public:
|
||||||
DOUBLET m_position;
|
DOUBLET m_position;
|
||||||
double m_rotation; // rotation (radians)
|
double m_rotation; // rotation (radians)
|
||||||
KICADDRILL m_drill;
|
KICADDRILL m_drill;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_thruhole;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KICADPAD_H
|
#endif // KICADPAD_H
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
* Copyright (C) 2016 Cirilo Bernardo <cirilo.bernardo@gmail.com>
|
||||||
|
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -52,38 +53,6 @@ class PCBMODEL;
|
||||||
|
|
||||||
class KICADPCB
|
class KICADPCB
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
S3D_RESOLVER m_resolver;
|
|
||||||
wxString m_filename;
|
|
||||||
PCBMODEL* m_pcb_model;
|
|
||||||
DOUBLET m_origin;
|
|
||||||
DOUBLET m_gridOrigin;
|
|
||||||
DOUBLET m_drillOrigin;
|
|
||||||
bool m_useGridOrigin;
|
|
||||||
bool m_useDrillOrigin;
|
|
||||||
// set to TRUE if the origin was actually parsed
|
|
||||||
bool m_hasGridOrigin;
|
|
||||||
bool m_hasDrillOrigin;
|
|
||||||
// minimum distance between points to treat them as separate entities (mm)
|
|
||||||
double m_minDistance;
|
|
||||||
// the names of layers in use, and the internal layer ID
|
|
||||||
std::map<std::string, int> m_layersNames;
|
|
||||||
|
|
||||||
// PCB parameters/entities
|
|
||||||
double m_thickness;
|
|
||||||
std::vector<KICADFOOTPRINT*> m_footprints;
|
|
||||||
std::vector<KICADCURVE*> m_curves;
|
|
||||||
|
|
||||||
bool parsePCB( SEXPR::SEXPR* data );
|
|
||||||
bool parseGeneral( SEXPR::SEXPR* data );
|
|
||||||
bool parseSetup( SEXPR::SEXPR* data );
|
|
||||||
bool parseLayers( SEXPR::SEXPR* data );
|
|
||||||
bool parseModule( SEXPR::SEXPR* data );
|
|
||||||
bool parseCurve( SEXPR::SEXPR* data, CURVE_TYPE aCurveType );
|
|
||||||
bool parseRect( SEXPR::SEXPR* data );
|
|
||||||
bool parsePolygon( SEXPR::SEXPR* data );
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KICADPCB();
|
KICADPCB();
|
||||||
virtual ~KICADPCB();
|
virtual ~KICADPCB();
|
||||||
|
@ -114,9 +83,44 @@ public:
|
||||||
bool ReadFile( const wxString& aFileName );
|
bool ReadFile( const wxString& aFileName );
|
||||||
bool ComposePCB( bool aComposeVirtual = true, bool aSubstituteModels = true );
|
bool ComposePCB( bool aComposeVirtual = true, bool aSubstituteModels = true );
|
||||||
bool WriteSTEP( const wxString& aFileName );
|
bool WriteSTEP( const wxString& aFileName );
|
||||||
#ifdef SUPPORTS_IGES
|
|
||||||
|
#ifdef SUPPORTS_IGES
|
||||||
bool WriteIGES( const wxString& aFileName );
|
bool WriteIGES( const wxString& aFileName );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool parsePCB( SEXPR::SEXPR* data );
|
||||||
|
bool parseGeneral( SEXPR::SEXPR* data );
|
||||||
|
bool parseSetup( SEXPR::SEXPR* data );
|
||||||
|
bool parseLayers( SEXPR::SEXPR* data );
|
||||||
|
bool parseModule( SEXPR::SEXPR* data );
|
||||||
|
bool parseCurve( SEXPR::SEXPR* data, CURVE_TYPE aCurveType );
|
||||||
|
bool parseRect( SEXPR::SEXPR* data );
|
||||||
|
bool parsePolygon( SEXPR::SEXPR* data );
|
||||||
|
|
||||||
|
S3D_RESOLVER m_resolver;
|
||||||
|
wxString m_filename;
|
||||||
|
PCBMODEL* m_pcb_model;
|
||||||
|
DOUBLET m_origin;
|
||||||
|
DOUBLET m_gridOrigin;
|
||||||
|
DOUBLET m_drillOrigin;
|
||||||
|
bool m_useGridOrigin;
|
||||||
|
bool m_useDrillOrigin;
|
||||||
|
|
||||||
|
// set to TRUE if the origin was actually parsed
|
||||||
|
bool m_hasGridOrigin;
|
||||||
|
bool m_hasDrillOrigin;
|
||||||
|
|
||||||
|
// minimum distance between points to treat them as separate entities (mm)
|
||||||
|
double m_minDistance;
|
||||||
|
|
||||||
|
// the names of layers in use, and the internal layer ID
|
||||||
|
std::map<std::string, int> m_layersNames;
|
||||||
|
|
||||||
|
// PCB parameters/entities
|
||||||
|
double m_thickness;
|
||||||
|
std::vector<KICADFOOTPRINT*> m_footprints;
|
||||||
|
std::vector<KICADCURVE*> m_curves;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -85,17 +85,21 @@
|
||||||
|
|
||||||
static constexpr double USER_PREC = 1e-4;
|
static constexpr double USER_PREC = 1e-4;
|
||||||
static constexpr double USER_ANGLE_PREC = 1e-6;
|
static constexpr double USER_ANGLE_PREC = 1e-6;
|
||||||
|
|
||||||
// minimum PCB thickness in mm (2 microns assumes a very thin polyimide film)
|
// minimum PCB thickness in mm (2 microns assumes a very thin polyimide film)
|
||||||
static constexpr double THICKNESS_MIN = 0.002;
|
static constexpr double THICKNESS_MIN = 0.002;
|
||||||
|
|
||||||
// default PCB thickness in mm
|
// default PCB thickness in mm
|
||||||
static constexpr double THICKNESS_DEFAULT = 1.6;
|
static constexpr double THICKNESS_DEFAULT = 1.6;
|
||||||
|
|
||||||
// nominal offset from the board
|
// nominal offset from the board
|
||||||
static constexpr double BOARD_OFFSET = 0.05;
|
static constexpr double BOARD_OFFSET = 0.05;
|
||||||
|
|
||||||
// min. length**2 below which 2 points are considered coincident
|
// min. length**2 below which 2 points are considered coincident
|
||||||
static constexpr double MIN_LENGTH2 = MIN_DISTANCE * MIN_DISTANCE;
|
static constexpr double MIN_LENGTH2 = MIN_DISTANCE * MIN_DISTANCE;
|
||||||
|
|
||||||
static void getEndPoints( const KICADCURVE& aCurve, double& spx0, double& spy0,
|
static void getEndPoints( const KICADCURVE& aCurve, double& spx0, double& spy0,
|
||||||
double& epx0, double& epy0 )
|
double& epx0, double& epy0 )
|
||||||
{
|
{
|
||||||
if( CURVE_ARC == aCurve.m_form )
|
if( CURVE_ARC == aCurve.m_form )
|
||||||
{
|
{
|
||||||
|
@ -111,9 +115,9 @@ static void getEndPoints( const KICADCURVE& aCurve, double& spx0, double& spy0,
|
||||||
spy0 = aCurve.m_start.y;
|
spy0 = aCurve.m_start.y;
|
||||||
epx0 = aCurve.m_end.x;
|
epx0 = aCurve.m_end.x;
|
||||||
epy0 = aCurve.m_end.y;
|
epy0 = aCurve.m_end.y;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void getCurveEndPoint( const KICADCURVE& aCurve, DOUBLET& aEndPoint )
|
static void getCurveEndPoint( const KICADCURVE& aCurve, DOUBLET& aEndPoint )
|
||||||
{
|
{
|
||||||
if( CURVE_CIRCLE == aCurve.m_form )
|
if( CURVE_CIRCLE == aCurve.m_form )
|
||||||
|
@ -129,7 +133,6 @@ static void getCurveEndPoint( const KICADCURVE& aCurve, DOUBLET& aEndPoint )
|
||||||
// assume a line
|
// assume a line
|
||||||
aEndPoint.x = aCurve.m_end.x;
|
aEndPoint.x = aCurve.m_end.x;
|
||||||
aEndPoint.y = aCurve.m_end.y;
|
aEndPoint.y = aCurve.m_end.y;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -154,8 +157,6 @@ static void reverseCurve( KICADCURVE& aCurve )
|
||||||
std::swap( aCurve.m_end, aCurve.m_ep );
|
std::swap( aCurve.m_end, aCurve.m_ep );
|
||||||
std::swap( aCurve.m_endangle, aCurve.m_startangle );
|
std::swap( aCurve.m_endangle, aCurve.m_startangle );
|
||||||
aCurve.m_angle = -aCurve.m_angle;
|
aCurve.m_angle = -aCurve.m_angle;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,17 +253,15 @@ PCBMODEL::PCBMODEL()
|
||||||
m_minx = 1.0e10; // absurdly large number; any valid PCB X value will be smaller
|
m_minx = 1.0e10; // absurdly large number; any valid PCB X value will be smaller
|
||||||
m_mincurve = m_curves.end();
|
m_mincurve = m_curves.end();
|
||||||
BRepBuilderAPI::Precision( MIN_DISTANCE );
|
BRepBuilderAPI::Precision( MIN_DISTANCE );
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PCBMODEL::~PCBMODEL()
|
PCBMODEL::~PCBMODEL()
|
||||||
{
|
{
|
||||||
m_doc->Close();
|
m_doc->Close();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add an outline segment
|
|
||||||
bool PCBMODEL::AddOutlineSegment( KICADCURVE* aCurve )
|
bool PCBMODEL::AddOutlineSegment( KICADCURVE* aCurve )
|
||||||
{
|
{
|
||||||
if( NULL == aCurve || LAYER_EDGE != aCurve->m_layer || CURVE_NONE == aCurve->m_form )
|
if( NULL == aCurve || LAYER_EDGE != aCurve->m_layer || CURVE_NONE == aCurve->m_form )
|
||||||
|
@ -330,7 +329,8 @@ bool PCBMODEL::AddOutlineSegment( KICADCURVE* aCurve )
|
||||||
if( rad < m_minDistance2 )
|
if( rad < m_minDistance2 )
|
||||||
{
|
{
|
||||||
wxString msg;
|
wxString msg;
|
||||||
msg.Printf( " * AddOutlineSegment() rejected an arc with equivalent end points, %s\n",
|
msg.Printf( " * AddOutlineSegment() rejected an arc with equivalent end "
|
||||||
|
"points, %s\n",
|
||||||
aCurve->Describe() );
|
aCurve->Describe() );
|
||||||
ReportMessage( msg );
|
ReportMessage( msg );
|
||||||
return false;
|
return false;
|
||||||
|
@ -343,124 +343,122 @@ bool PCBMODEL::AddOutlineSegment( KICADCURVE* aCurve )
|
||||||
// check if this curve has the current leftmost feature
|
// check if this curve has the current leftmost feature
|
||||||
switch( aCurve->m_form )
|
switch( aCurve->m_form )
|
||||||
{
|
{
|
||||||
case CURVE_LINE:
|
case CURVE_LINE:
|
||||||
if( aCurve->m_start.x < m_minx )
|
if( aCurve->m_start.x < m_minx )
|
||||||
|
{
|
||||||
|
m_minx = aCurve->m_start.x;
|
||||||
|
m_mincurve = --( m_curves.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aCurve->m_end.x < m_minx )
|
||||||
|
{
|
||||||
|
m_minx = aCurve->m_end.x;
|
||||||
|
m_mincurve = --( m_curves.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURVE_CIRCLE:
|
||||||
|
do
|
||||||
|
{
|
||||||
|
double dx = aCurve->m_start.x - aCurve->m_radius;
|
||||||
|
|
||||||
|
if( dx < m_minx )
|
||||||
{
|
{
|
||||||
m_minx = aCurve->m_start.x;
|
m_minx = dx;
|
||||||
m_mincurve = --(m_curves.end());
|
m_mincurve = --( m_curves.end() );
|
||||||
|
}
|
||||||
|
} while( 0 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURVE_ARC:
|
||||||
|
do
|
||||||
|
{
|
||||||
|
double dx0 = aCurve->m_end.x - aCurve->m_start.x;
|
||||||
|
double dy0 = aCurve->m_end.y - aCurve->m_start.y;
|
||||||
|
int q0; // quadrant of start point
|
||||||
|
|
||||||
|
if( dx0 > 0.0 && dy0 >= 0.0 )
|
||||||
|
q0 = 1;
|
||||||
|
else if( dx0 <= 0.0 && dy0 > 0.0 )
|
||||||
|
q0 = 2;
|
||||||
|
else if( dx0 < 0.0 && dy0 <= 0.0 )
|
||||||
|
q0 = 3;
|
||||||
|
else
|
||||||
|
q0 = 4;
|
||||||
|
|
||||||
|
double dx1 = aCurve->m_ep.x - aCurve->m_start.x;
|
||||||
|
double dy1 = aCurve->m_ep.y - aCurve->m_start.y;
|
||||||
|
int q1; // quadrant of end point
|
||||||
|
|
||||||
|
if( dx1 > 0.0 && dy1 >= 0.0 )
|
||||||
|
q1 = 1;
|
||||||
|
else if( dx1 <= 0.0 && dy1 > 0.0 )
|
||||||
|
q1 = 2;
|
||||||
|
else if( dx1 < 0.0 && dy1 <= 0.0 )
|
||||||
|
q1 = 3;
|
||||||
|
else
|
||||||
|
q1 = 4;
|
||||||
|
|
||||||
|
// calculate x0, y0 for the start point on a CCW arc
|
||||||
|
double x0 = aCurve->m_end.x;
|
||||||
|
double x1 = aCurve->m_ep.x;
|
||||||
|
|
||||||
|
if( aCurve->m_angle < 0.0 )
|
||||||
|
{
|
||||||
|
std::swap( q0, q1 );
|
||||||
|
std::swap( x0, x1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( aCurve->m_end.x < m_minx )
|
double minx;
|
||||||
|
|
||||||
|
if( ( q0 <= 2 && q1 >= 3 ) || ( q0 >= 3 && x0 > x1 ) )
|
||||||
|
minx = aCurve->m_start.x - aCurve->m_radius;
|
||||||
|
else
|
||||||
|
minx = std::min( x0, x1 );
|
||||||
|
|
||||||
|
if( minx < m_minx )
|
||||||
{
|
{
|
||||||
m_minx = aCurve->m_end.x;
|
m_minx = minx;
|
||||||
m_mincurve = --(m_curves.end());
|
m_mincurve = --( m_curves.end() );
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
} while( 0 );
|
||||||
|
|
||||||
case CURVE_CIRCLE:
|
break;
|
||||||
do
|
|
||||||
{
|
|
||||||
double dx = aCurve->m_start.x - aCurve->m_radius;
|
|
||||||
|
|
||||||
if( dx < m_minx )
|
case CURVE_BEZIER:
|
||||||
{
|
if( aCurve->m_start.x < m_minx )
|
||||||
m_minx = dx;
|
{
|
||||||
m_mincurve = --(m_curves.end());
|
m_minx = aCurve->m_start.x;
|
||||||
}
|
m_mincurve = --( m_curves.end() );
|
||||||
} while( 0 );
|
}
|
||||||
|
|
||||||
break;
|
if( aCurve->m_end.x < m_minx )
|
||||||
|
{
|
||||||
|
m_minx = aCurve->m_end.x;
|
||||||
|
m_mincurve = --( m_curves.end() );
|
||||||
|
}
|
||||||
|
|
||||||
case CURVE_ARC:
|
break;
|
||||||
do
|
|
||||||
{
|
|
||||||
double dx0 = aCurve->m_end.x - aCurve->m_start.x;
|
|
||||||
double dy0 = aCurve->m_end.y - aCurve->m_start.y;
|
|
||||||
int q0; // quadrant of start point
|
|
||||||
|
|
||||||
if( dx0 > 0.0 && dy0 >= 0.0 )
|
default:
|
||||||
q0 = 1;
|
// unexpected curve type
|
||||||
else if( dx0 <= 0.0 && dy0 > 0.0 )
|
do
|
||||||
q0 = 2;
|
{
|
||||||
else if( dx0 < 0.0 && dy0 <= 0.0 )
|
wxString msg;
|
||||||
q0 = 3;
|
msg.Printf( " * AddOutlineSegment() unsupported curve type: %d\n", aCurve->m_form );
|
||||||
else
|
ReportMessage( msg );
|
||||||
q0 = 4;
|
} while( 0 );
|
||||||
|
|
||||||
double dx1 = aCurve->m_ep.x - aCurve->m_start.x;
|
return false;
|
||||||
double dy1 = aCurve->m_ep.y - aCurve->m_start.y;
|
|
||||||
int q1; // quadrant of end point
|
|
||||||
|
|
||||||
if( dx1 > 0.0 && dy1 >= 0.0 )
|
|
||||||
q1 = 1;
|
|
||||||
else if( dx1 <= 0.0 && dy1 > 0.0 )
|
|
||||||
q1 = 2;
|
|
||||||
else if( dx1 < 0.0 && dy1 <= 0.0 )
|
|
||||||
q1 = 3;
|
|
||||||
else
|
|
||||||
q1 = 4;
|
|
||||||
|
|
||||||
// calculate x0, y0 for the start point on a CCW arc
|
|
||||||
double x0 = aCurve->m_end.x;
|
|
||||||
double x1 = aCurve->m_ep.x;
|
|
||||||
|
|
||||||
if( aCurve->m_angle < 0.0 )
|
|
||||||
{
|
|
||||||
std::swap( q0, q1 );
|
|
||||||
std::swap( x0, x1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
double minx;
|
|
||||||
|
|
||||||
if( ( q0 <= 2 && q1 >= 3 ) || ( q0 >= 3 && x0 > x1 ) )
|
|
||||||
minx = aCurve->m_start.x - aCurve->m_radius;
|
|
||||||
else
|
|
||||||
minx = std::min( x0, x1 );
|
|
||||||
|
|
||||||
if( minx < m_minx )
|
|
||||||
{
|
|
||||||
m_minx = minx;
|
|
||||||
m_mincurve = --(m_curves.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
} while( 0 );
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CURVE_BEZIER:
|
|
||||||
if( aCurve->m_start.x < m_minx )
|
|
||||||
{
|
|
||||||
m_minx = aCurve->m_start.x;
|
|
||||||
m_mincurve = --(m_curves.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
if( aCurve->m_end.x < m_minx )
|
|
||||||
{
|
|
||||||
m_minx = aCurve->m_end.x;
|
|
||||||
m_mincurve = --(m_curves.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// unexpected curve type
|
|
||||||
do
|
|
||||||
{
|
|
||||||
wxString msg;
|
|
||||||
msg.Printf( " * AddOutlineSegment() unsupported curve type: %d\n",
|
|
||||||
aCurve->m_form );
|
|
||||||
ReportMessage( msg );
|
|
||||||
} while( 0 );
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// add a pad hole or slot
|
|
||||||
bool PCBMODEL::AddPadHole( const KICADPAD* aPad )
|
bool PCBMODEL::AddPadHole( const KICADPAD* aPad )
|
||||||
{
|
{
|
||||||
if( NULL == aPad || !aPad->IsThruHole() )
|
if( NULL == aPad || !aPad->IsThruHole() )
|
||||||
|
@ -469,9 +467,10 @@ bool PCBMODEL::AddPadHole( const KICADPAD* aPad )
|
||||||
if( !aPad->m_drill.oval )
|
if( !aPad->m_drill.oval )
|
||||||
{
|
{
|
||||||
TopoDS_Shape s = BRepPrimAPI_MakeCylinder( aPad->m_drill.size.x * 0.5,
|
TopoDS_Shape s = BRepPrimAPI_MakeCylinder( aPad->m_drill.size.x * 0.5,
|
||||||
m_thickness * 2.0 ).Shape();
|
m_thickness * 2.0 ).Shape();
|
||||||
gp_Trsf shift;
|
gp_Trsf shift;
|
||||||
shift.SetTranslation( gp_Vec( aPad->m_position.x, aPad->m_position.y, -m_thickness * 0.5 ) );
|
shift.SetTranslation( gp_Vec( aPad->m_position.x, aPad->m_position.y,
|
||||||
|
-m_thickness * 0.5 ) );
|
||||||
BRepBuilderAPI_Transform hole( s, shift );
|
BRepBuilderAPI_Transform hole( s, shift );
|
||||||
m_cutouts.push_back( hole.Shape() );
|
m_cutouts.push_back( hole.Shape() );
|
||||||
return true;
|
return true;
|
||||||
|
@ -601,7 +600,6 @@ bool PCBMODEL::AddPadHole( const KICADPAD* aPad )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// add a component at the given position and orientation
|
|
||||||
bool PCBMODEL::AddComponent( const std::string& aFileName, const std::string& aRefDes,
|
bool PCBMODEL::AddComponent( const std::string& aFileName, const std::string& aRefDes,
|
||||||
bool aBottom, DOUBLET aPosition, double aRotation,
|
bool aBottom, DOUBLET aPosition, double aRotation,
|
||||||
TRIPLET aOffset, TRIPLET aOrientation, TRIPLET aScale,
|
TRIPLET aOffset, TRIPLET aOrientation, TRIPLET aScale,
|
||||||
|
@ -664,8 +662,6 @@ void PCBMODEL::SetPCBThickness( double aThickness )
|
||||||
m_thickness = THICKNESS_MIN;
|
m_thickness = THICKNESS_MIN;
|
||||||
else
|
else
|
||||||
m_thickness = aThickness;
|
m_thickness = aThickness;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -677,7 +673,6 @@ void PCBMODEL::SetMinDistance( double aDistance )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// create the PCB (board only) model using the current outlines and drill holes
|
|
||||||
bool PCBMODEL::CreatePCB()
|
bool PCBMODEL::CreatePCB()
|
||||||
{
|
{
|
||||||
if( m_hasPCB )
|
if( m_hasPCB )
|
||||||
|
@ -814,7 +809,8 @@ bool PCBMODEL::CreatePCB()
|
||||||
(int)m_cutouts.size() ) );
|
(int)m_cutouts.size() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 // First version for holes removing: very slow when having many (> 300) holes
|
#if 0
|
||||||
|
// First version for holes removing: very slow when having many (> 300) holes
|
||||||
// Substract holes (cutouts) can be time consuming, so display activity
|
// Substract holes (cutouts) can be time consuming, so display activity
|
||||||
// state to be sure there is no hang:
|
// state to be sure there is no hang:
|
||||||
int char_count = 0;
|
int char_count = 0;
|
||||||
|
@ -863,8 +859,7 @@ bool PCBMODEL::CreatePCB()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// color the PCB
|
// color the PCB
|
||||||
Handle(XCAFDoc_ColorTool) color =
|
Handle( XCAFDoc_ColorTool ) color = XCAFDoc_DocumentTool::ColorTool( m_doc->Main () );
|
||||||
XCAFDoc_DocumentTool::ColorTool( m_doc->Main () );
|
|
||||||
Quantity_Color pcb_green( 0.06, 0.4, 0.06, Quantity_TOC_RGB );
|
Quantity_Color pcb_green( 0.06, 0.4, 0.06, Quantity_TOC_RGB );
|
||||||
color->SetColor( m_pcb_label, pcb_green, XCAFDoc_ColorSurf );
|
color->SetColor( m_pcb_label, pcb_green, XCAFDoc_ColorSurf );
|
||||||
|
|
||||||
|
@ -915,7 +910,6 @@ bool PCBMODEL::WriteIGES( const wxString& aFileName )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// write the assembly model in STEP format
|
|
||||||
bool PCBMODEL::WriteSTEP( const wxString& aFileName )
|
bool PCBMODEL::WriteSTEP( const wxString& aFileName )
|
||||||
{
|
{
|
||||||
if( m_pcb_label.IsNull() )
|
if( m_pcb_label.IsNull() )
|
||||||
|
@ -942,9 +936,11 @@ bool PCBMODEL::WriteSTEP( const wxString& aFileName )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
|
APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
|
||||||
|
|
||||||
// Note: use only Ascii7 chars, non Ascii7 chars (therefore UFT8 chars)
|
// Note: use only Ascii7 chars, non Ascii7 chars (therefore UFT8 chars)
|
||||||
// are creating issues in the step file
|
// are creating issues in the step file
|
||||||
hdr.SetName( new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
|
hdr.SetName( new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
|
||||||
|
|
||||||
// TODO: how to control and ensure consistency with IGES?
|
// TODO: how to control and ensure consistency with IGES?
|
||||||
hdr.SetAuthorValue( 1, new TCollection_HAsciiString( "Pcbnew" ) );
|
hdr.SetAuthorValue( 1, new TCollection_HAsciiString( "Pcbnew" ) );
|
||||||
hdr.SetOrganizationValue( 1, new TCollection_HAsciiString( "Kicad" ) );
|
hdr.SetOrganizationValue( 1, new TCollection_HAsciiString( "Kicad" ) );
|
||||||
|
@ -952,10 +948,10 @@ bool PCBMODEL::WriteSTEP( const wxString& aFileName )
|
||||||
hdr.SetDescriptionValue( 1, new TCollection_HAsciiString( "KiCad electronic assembly" ) );
|
hdr.SetDescriptionValue( 1, new TCollection_HAsciiString( "KiCad electronic assembly" ) );
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
// Creates a temporary file with a ascii7 name, because writer does not know
|
|
||||||
// unicode filenames
|
// Creates a temporary file with a ascii7 name, because writer does not know unicode filenames.
|
||||||
wxString currCWD = wxGetCwd();
|
wxString currCWD = wxGetCwd();
|
||||||
wxString workCWD =fn.GetPath();
|
wxString workCWD = fn.GetPath();
|
||||||
|
|
||||||
if( !workCWD.IsEmpty() )
|
if( !workCWD.IsEmpty() )
|
||||||
wxSetWorkingDirectory( workCWD );
|
wxSetWorkingDirectory( workCWD );
|
||||||
|
@ -1005,171 +1001,166 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
|
||||||
|
|
||||||
switch( modelFmt )
|
switch( modelFmt )
|
||||||
{
|
{
|
||||||
case FMT_IGES:
|
case FMT_IGES:
|
||||||
if( !readIGES( doc, aFileName.c_str() ) )
|
if( !readIGES( doc, aFileName.c_str() ) )
|
||||||
{
|
|
||||||
ReportMessage( wxString::Format( "readIGES() failed on filename '%s'.\n",
|
|
||||||
aFileName ) );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FMT_STEP:
|
|
||||||
if( !readSTEP( doc, aFileName.c_str() ) )
|
|
||||||
{
|
|
||||||
ReportMessage( wxString::Format( "readSTEP() failed on filename '%s'.\n",
|
|
||||||
aFileName ) );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FMT_STEPZ:
|
|
||||||
{
|
{
|
||||||
wxFFileInputStream ifile( aFileName );
|
ReportMessage( wxString::Format( "readIGES() failed on filename '%s'.\n", aFileName ) );
|
||||||
wxFileName outFile( aFileName );
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
|
case FMT_STEP:
|
||||||
outFile.SetExt( "STEP" );
|
if( !readSTEP( doc, aFileName.c_str() ) )
|
||||||
|
{
|
||||||
|
ReportMessage( wxString::Format( "readSTEP() failed on filename '%s'.\n", aFileName ) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
wxFileOffset size = ifile.GetLength();
|
case FMT_STEPZ:
|
||||||
|
{
|
||||||
|
wxFFileInputStream ifile( aFileName );
|
||||||
|
wxFileName outFile( aFileName );
|
||||||
|
|
||||||
if( size == wxInvalidOffset )
|
outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
|
||||||
{
|
outFile.SetExt( "STEP" );
|
||||||
ReportMessage( wxString::Format( "readSTEP() failed on filename '%s'.\n",
|
|
||||||
aFileName ) );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
wxFileOffset size = ifile.GetLength();
|
||||||
bool success = false;
|
|
||||||
wxFFileOutputStream ofile( outFile.GetFullPath() );
|
|
||||||
|
|
||||||
if( !ofile.IsOk() )
|
if( size == wxInvalidOffset )
|
||||||
return false;
|
{
|
||||||
|
ReportMessage( wxString::Format( "readSTEP() failed on filename '%s'.\n", aFileName ) );
|
||||||
char *buffer = new char[size];
|
return false;
|
||||||
|
|
||||||
ifile.Read( buffer, size);
|
|
||||||
std::string expanded;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
expanded = gzip::decompress( buffer, size );
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{}
|
|
||||||
|
|
||||||
if( expanded.empty() )
|
|
||||||
{
|
|
||||||
ifile.Reset();
|
|
||||||
ifile.SeekI( 0 );
|
|
||||||
wxZipInputStream izipfile( ifile );
|
|
||||||
std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
|
|
||||||
|
|
||||||
if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
|
|
||||||
{
|
|
||||||
izipfile.Read( ofile );
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ofile.Write( expanded.data(), expanded.size() );
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] buffer;
|
|
||||||
ofile.Close();
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case FMT_WRL:
|
{
|
||||||
case FMT_WRZ:
|
bool success = false;
|
||||||
/* WRL files are preferred for internal rendering,
|
wxFFileOutputStream ofile( outFile.GetFullPath() );
|
||||||
* due to superior material properties, etc.
|
|
||||||
* However they are not suitable for MCAD export.
|
if( !ofile.IsOk() )
|
||||||
*
|
return false;
|
||||||
* If a .wrl file is specified, attempt to locate
|
|
||||||
* a replacement file for it.
|
char* buffer = new char[size];
|
||||||
*
|
|
||||||
* If a valid replacement file is found, the label
|
ifile.Read( buffer, size );
|
||||||
* for THAT file will be associated with the .wrl file
|
std::string expanded;
|
||||||
*
|
|
||||||
*/
|
try
|
||||||
if( aSubstituteModels )
|
|
||||||
{
|
{
|
||||||
wxFileName wrlName( aFileName );
|
expanded = gzip::decompress( buffer, size );
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
wxString basePath = wrlName.GetPath();
|
if( expanded.empty() )
|
||||||
wxString baseName = wrlName.GetName();
|
{
|
||||||
|
ifile.Reset();
|
||||||
|
ifile.SeekI( 0 );
|
||||||
|
wxZipInputStream izipfile( ifile );
|
||||||
|
std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
|
||||||
|
|
||||||
// List of alternate files to look for
|
if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
|
||||||
// Given in order of preference
|
|
||||||
// (Break if match is found)
|
|
||||||
wxArrayString alts;
|
|
||||||
|
|
||||||
// Step files
|
|
||||||
alts.Add( "stp" );
|
|
||||||
alts.Add( "step" );
|
|
||||||
alts.Add( "STP" );
|
|
||||||
alts.Add( "STEP" );
|
|
||||||
alts.Add( "Stp" );
|
|
||||||
alts.Add( "Step" );
|
|
||||||
alts.Add( "stpz" );
|
|
||||||
alts.Add( "stpZ" );
|
|
||||||
alts.Add( "STPZ" );
|
|
||||||
alts.Add( "step.gz" );
|
|
||||||
|
|
||||||
// IGES files
|
|
||||||
alts.Add( "iges" );
|
|
||||||
alts.Add( "IGES" );
|
|
||||||
alts.Add( "igs" );
|
|
||||||
alts.Add( "IGS" );
|
|
||||||
|
|
||||||
//TODO - Other alternative formats?
|
|
||||||
|
|
||||||
for( const auto& alt : alts )
|
|
||||||
{
|
{
|
||||||
wxFileName altFile( basePath, baseName + "." + alt );
|
izipfile.Read( ofile );
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ofile.Write( expanded.data(), expanded.size() );
|
||||||
|
}
|
||||||
|
|
||||||
if( altFile.IsOk() && altFile.FileExists() )
|
delete[] buffer;
|
||||||
|
ofile.Close();
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case FMT_WRL:
|
||||||
|
case FMT_WRZ:
|
||||||
|
/* WRL files are preferred for internal rendering, due to superior material properties, etc.
|
||||||
|
* However they are not suitable for MCAD export.
|
||||||
|
*
|
||||||
|
* If a .wrl file is specified, attempt to locate a replacement file for it.
|
||||||
|
*
|
||||||
|
* If a valid replacement file is found, the label for THAT file will be associated with
|
||||||
|
* the .wrl file
|
||||||
|
*/
|
||||||
|
if( aSubstituteModels )
|
||||||
|
{
|
||||||
|
wxFileName wrlName( aFileName );
|
||||||
|
|
||||||
|
wxString basePath = wrlName.GetPath();
|
||||||
|
wxString baseName = wrlName.GetName();
|
||||||
|
|
||||||
|
// List of alternate files to look for
|
||||||
|
// Given in order of preference
|
||||||
|
// (Break if match is found)
|
||||||
|
wxArrayString alts;
|
||||||
|
|
||||||
|
// Step files
|
||||||
|
alts.Add( "stp" );
|
||||||
|
alts.Add( "step" );
|
||||||
|
alts.Add( "STP" );
|
||||||
|
alts.Add( "STEP" );
|
||||||
|
alts.Add( "Stp" );
|
||||||
|
alts.Add( "Step" );
|
||||||
|
alts.Add( "stpz" );
|
||||||
|
alts.Add( "stpZ" );
|
||||||
|
alts.Add( "STPZ" );
|
||||||
|
alts.Add( "step.gz" );
|
||||||
|
|
||||||
|
// IGES files
|
||||||
|
alts.Add( "iges" );
|
||||||
|
alts.Add( "IGES" );
|
||||||
|
alts.Add( "igs" );
|
||||||
|
alts.Add( "IGS" );
|
||||||
|
|
||||||
|
//TODO - Other alternative formats?
|
||||||
|
|
||||||
|
for( const auto& alt : alts )
|
||||||
|
{
|
||||||
|
wxFileName altFile( basePath, baseName + "." + alt );
|
||||||
|
|
||||||
|
if( altFile.IsOk() && altFile.FileExists() )
|
||||||
|
{
|
||||||
|
std::string altFileName = altFile.GetFullPath().ToStdString();
|
||||||
|
|
||||||
|
// When substituting a STEP/IGS file for VRML, do not apply the VRML scaling
|
||||||
|
// to the new STEP model. This process of auto-substitution is janky as all
|
||||||
|
// heck so let's not mix up un-displayed scale factors with potentially
|
||||||
|
// mis-matched files. And hope that the user doesn't have multiples files
|
||||||
|
// named "model.wrl" and "model.stp" referring to different parts.
|
||||||
|
// TODO: Fix model handling in v7. Default models should only be STP.
|
||||||
|
// Have option to override this in DISPLAY.
|
||||||
|
if( getModelLabel( altFileName, TRIPLET( 1.0, 1.0, 1.0 ), aLabel, false ) )
|
||||||
{
|
{
|
||||||
std::string altFileName = altFile.GetFullPath().ToStdString();
|
return true;
|
||||||
|
|
||||||
// When substituting a STEP/IGS file for VRML, do not apply the VRML scaling
|
|
||||||
// to the new STEP model. This process of auto-substitution is janky as all
|
|
||||||
// heck so let's not mix up un-displayed scale factors with potentially
|
|
||||||
// mis-matched files. And hope that the user doesn't have multiples files
|
|
||||||
// named "model.wrl" and "model.stp" referring to different parts.
|
|
||||||
// TODO: Fix model handling in v7. Default models should only be STP.
|
|
||||||
// Have option to override this in DISPLAY.
|
|
||||||
if( getModelLabel( altFileName, TRIPLET( 1.0, 1.0, 1.0 ), aLabel, false ) )
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // No replacement model found
|
|
||||||
}
|
|
||||||
else // Substitution is not allowed
|
|
||||||
{
|
|
||||||
if( aErrorMessage )
|
|
||||||
aErrorMessage->Printf( "Cannot add a VRML model data to a Step file.\n",
|
|
||||||
aFileName );
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
return false; // No replacement model found
|
||||||
|
}
|
||||||
|
else // Substitution is not allowed
|
||||||
|
{
|
||||||
|
if( aErrorMessage )
|
||||||
|
aErrorMessage->Printf( "Cannot add a VRML model data to a Step file.\n",
|
||||||
|
aFileName );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
// TODO: implement IDF and EMN converters
|
// TODO: implement IDF and EMN converters
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
aLabel = transferModel( doc, m_doc, aScale );
|
aLabel = transferModel( doc, m_doc, aScale );
|
||||||
|
@ -1338,7 +1329,6 @@ TDF_Label PCBMODEL::transferModel( Handle( TDocStd_Document )& source,
|
||||||
0, 0, aScale.z ) );
|
0, 0, aScale.z ) );
|
||||||
BRepBuilderAPI_GTransform brep( scale_transform );
|
BRepBuilderAPI_GTransform brep( scale_transform );
|
||||||
|
|
||||||
|
|
||||||
// s_assy = shape tool for the source
|
// s_assy = shape tool for the source
|
||||||
Handle(XCAFDoc_ShapeTool) s_assy = XCAFDoc_DocumentTool::ShapeTool ( source->Main() );
|
Handle(XCAFDoc_ShapeTool) s_assy = XCAFDoc_DocumentTool::ShapeTool ( source->Main() );
|
||||||
|
|
||||||
|
@ -1456,13 +1446,11 @@ OUTLINE::OUTLINE()
|
||||||
{
|
{
|
||||||
m_closed = false;
|
m_closed = false;
|
||||||
m_minDistance2 = MIN_LENGTH2;
|
m_minDistance2 = MIN_LENGTH2;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
OUTLINE::~OUTLINE()
|
OUTLINE::~OUTLINE()
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1470,7 +1458,6 @@ void OUTLINE::Clear()
|
||||||
{
|
{
|
||||||
m_closed = false;
|
m_closed = false;
|
||||||
m_curves.clear();
|
m_curves.clear();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1618,53 +1605,52 @@ bool OUTLINE::addEdge( BRepBuilderAPI_MakeWire* aWire, KICADCURVE& aCurve, DOUBL
|
||||||
|
|
||||||
switch( aCurve.m_form )
|
switch( aCurve.m_form )
|
||||||
{
|
{
|
||||||
case CURVE_LINE:
|
case CURVE_LINE:
|
||||||
edge = BRepBuilderAPI_MakeEdge( gp_Pnt( aLastPoint.x, aLastPoint.y, 0.0 ),
|
edge = BRepBuilderAPI_MakeEdge( gp_Pnt( aLastPoint.x, aLastPoint.y, 0.0 ),
|
||||||
gp_Pnt( endPoint.x, endPoint.y, 0.0 ) );
|
gp_Pnt( endPoint.x, endPoint.y, 0.0 ) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CURVE_ARC:
|
case CURVE_ARC:
|
||||||
{
|
{
|
||||||
gp_Circ arc( gp_Ax2( gp_Pnt( aCurve.m_start.x, aCurve.m_start.y, 0.0 ),
|
gp_Circ arc( gp_Ax2( gp_Pnt( aCurve.m_start.x, aCurve.m_start.y, 0.0 ),
|
||||||
gp_Dir( 0.0, 0.0, 1.0 ) ), aCurve.m_radius );
|
gp_Dir( 0.0, 0.0, 1.0 ) ), aCurve.m_radius );
|
||||||
|
|
||||||
gp_Pnt sa( aLastPoint.x, aLastPoint.y, 0.0 );
|
gp_Pnt sa( aLastPoint.x, aLastPoint.y, 0.0 );
|
||||||
gp_Pnt ea( endPoint.x, endPoint.y, 0.0 );
|
gp_Pnt ea( endPoint.x, endPoint.y, 0.0 );
|
||||||
|
|
||||||
if( aCurve.m_angle < 0.0 )
|
if( aCurve.m_angle < 0.0 )
|
||||||
edge = BRepBuilderAPI_MakeEdge( arc, ea, sa );
|
edge = BRepBuilderAPI_MakeEdge( arc, ea, sa );
|
||||||
else
|
else
|
||||||
edge = BRepBuilderAPI_MakeEdge( arc, sa, ea );
|
edge = BRepBuilderAPI_MakeEdge( arc, sa, ea );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CURVE_CIRCLE:
|
case CURVE_CIRCLE:
|
||||||
edge = BRepBuilderAPI_MakeEdge( gp_Circ( gp_Ax2( gp_Pnt( aCurve.m_start.x,
|
edge = BRepBuilderAPI_MakeEdge(
|
||||||
aCurve.m_start.y, 0.0 ),
|
gp_Circ( gp_Ax2( gp_Pnt( aCurve.m_start.x, aCurve.m_start.y, 0.0 ),
|
||||||
gp_Dir( 0.0, 0.0, 1.0 ) ),
|
gp_Dir( 0.0, 0.0, 1.0 ) ), aCurve.m_radius ) );
|
||||||
aCurve.m_radius ) );
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
case CURVE_BEZIER:
|
case CURVE_BEZIER:
|
||||||
{
|
{
|
||||||
TColgp_Array1OfPnt poles(0, 3);
|
TColgp_Array1OfPnt poles( 0, 3 );
|
||||||
gp_Pnt pt = gp_Pnt( aCurve.m_start.x, aCurve.m_start.y, 0.0 );
|
gp_Pnt pt = gp_Pnt( aCurve.m_start.x, aCurve.m_start.y, 0.0 );
|
||||||
poles(0) = pt;
|
poles( 0 ) = pt;
|
||||||
pt = gp_Pnt( aCurve.m_bezierctrl1.x, aCurve.m_bezierctrl1.y, 0.0 );
|
pt = gp_Pnt( aCurve.m_bezierctrl1.x, aCurve.m_bezierctrl1.y, 0.0 );
|
||||||
poles(1) = pt;
|
poles( 1 ) = pt;
|
||||||
pt = gp_Pnt( aCurve.m_bezierctrl2.x, aCurve.m_bezierctrl2.y, 0.0 );
|
pt = gp_Pnt( aCurve.m_bezierctrl2.x, aCurve.m_bezierctrl2.y, 0.0 );
|
||||||
poles(2) = pt;
|
poles( 2 ) = pt;
|
||||||
pt = gp_Pnt( endPoint.x, endPoint.y, 0.0 );
|
pt = gp_Pnt( endPoint.x, endPoint.y, 0.0 );
|
||||||
poles(3) = pt;
|
poles( 3 ) = pt;
|
||||||
|
|
||||||
Geom_BezierCurve* bezier_curve = new Geom_BezierCurve( poles );
|
Geom_BezierCurve* bezier_curve = new Geom_BezierCurve( poles );
|
||||||
edge = BRepBuilderAPI_MakeEdge( bezier_curve );
|
edge = BRepBuilderAPI_MakeEdge( bezier_curve );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ReportMessage( wxString::Format( "unsupported curve type: %d\n", aCurve.m_form ) );
|
ReportMessage( wxString::Format( "unsupported curve type: %d\n", aCurve.m_form ) );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( edge.IsNull() )
|
if( edge.IsNull() )
|
||||||
|
|
|
@ -49,15 +49,7 @@ class KICADPAD;
|
||||||
|
|
||||||
class OUTLINE
|
class OUTLINE
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
bool m_closed; // set true if the loop is closed
|
|
||||||
double m_minDistance2; // min squared distance to treat points as separate entities (mm)
|
|
||||||
|
|
||||||
bool addEdge( BRepBuilderAPI_MakeWire* aWire, KICADCURVE& aCurve, DOUBLET& aLastPoint );
|
|
||||||
bool testClosed( const KICADCURVE& aFrontCurve, const KICADCURVE& aBackCurve );
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::list< KICADCURVE > m_curves; // list of contiguous segments
|
|
||||||
OUTLINE();
|
OUTLINE();
|
||||||
virtual ~OUTLINE();
|
virtual ~OUTLINE();
|
||||||
|
|
||||||
|
@ -77,51 +69,22 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MakeShape( TopoDS_Shape& aShape, double aThickness );
|
bool MakeShape( TopoDS_Shape& aShape, double aThickness );
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool addEdge( BRepBuilderAPI_MakeWire* aWire, KICADCURVE& aCurve, DOUBLET& aLastPoint );
|
||||||
|
bool testClosed( const KICADCURVE& aFrontCurve, const KICADCURVE& aBackCurve );
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::list< KICADCURVE > m_curves; // list of contiguous segments
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_closed; // set true if the loop is closed
|
||||||
|
double m_minDistance2; // min squared distance to treat points as separate entities (mm)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class PCBMODEL
|
class PCBMODEL
|
||||||
{
|
{
|
||||||
Handle( XCAFApp_Application ) m_app;
|
|
||||||
Handle( TDocStd_Document ) m_doc;
|
|
||||||
Handle( XCAFDoc_ShapeTool ) m_assy;
|
|
||||||
TDF_Label m_assy_label;
|
|
||||||
bool m_hasPCB; // set true if CreatePCB() has been invoked
|
|
||||||
TDF_Label m_pcb_label; // label for the PCB model
|
|
||||||
MODEL_MAP m_models; // map of file names to model labels
|
|
||||||
int m_components; // number of successfully loaded components;
|
|
||||||
double m_precision; // model (length unit) numeric precision
|
|
||||||
double m_angleprec; // angle numeric precision
|
|
||||||
double m_thickness; // PCB thickness, mm
|
|
||||||
double m_minx; // minimum X value in curves (leftmost curve feature)
|
|
||||||
double m_minDistance2; // minimum squared distance between items (mm)
|
|
||||||
std::list<KICADCURVE>::iterator m_mincurve; // iterator to the leftmost curve
|
|
||||||
|
|
||||||
std::list<KICADCURVE> m_curves;
|
|
||||||
std::vector<TopoDS_Shape> m_cutouts;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load a 3D model data
|
|
||||||
* aFileName is the filename (different formats allowed) but for WRML files a model
|
|
||||||
* data can be loaded instead of the vrml data, not suitable in a step file
|
|
||||||
* @param aScale is the X,Y,Z scaling factors
|
|
||||||
* @param aLabel is the TDF_Label to store the data
|
|
||||||
* @param aSubstituteModels = true to allows data substitution, false to disallow.
|
|
||||||
* @param aErrorMessage (can be nullptr) is an error message to be displayed on error.
|
|
||||||
* @return true if successfully loaded, false on error
|
|
||||||
*/
|
|
||||||
bool getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_Label& aLabel,
|
|
||||||
bool aSubstituteModels, wxString* aErrorMessage = nullptr );
|
|
||||||
|
|
||||||
bool getModelLocation( bool aBottom, DOUBLET aPosition, double aRotation,
|
|
||||||
TRIPLET aOffset, TRIPLET aOrientation, TopLoc_Location& aLocation );
|
|
||||||
|
|
||||||
bool readIGES( Handle( TDocStd_Document )& m_doc, const char* fname );
|
|
||||||
bool readSTEP( Handle( TDocStd_Document )& m_doc, const char* fname );
|
|
||||||
|
|
||||||
TDF_Label transferModel( Handle( TDocStd_Document )& source,
|
|
||||||
Handle( TDocStd_Document )& dest, TRIPLET aScale );
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PCBMODEL();
|
PCBMODEL();
|
||||||
virtual ~PCBMODEL();
|
virtual ~PCBMODEL();
|
||||||
|
@ -157,6 +120,50 @@ public:
|
||||||
|
|
||||||
// write the assembly model in STEP format
|
// write the assembly model in STEP format
|
||||||
bool WriteSTEP( const wxString& aFileName );
|
bool WriteSTEP( const wxString& aFileName );
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Load a 3D model data.
|
||||||
|
*
|
||||||
|
* @param aFileName is the filename (different formats allowed) but for WRML files a model
|
||||||
|
* data can be loaded instead of the vrml data, not suitable in a step file.
|
||||||
|
* @param aScale is the X,Y,Z scaling factors.
|
||||||
|
* @param aLabel is the TDF_Label to store the data.
|
||||||
|
* @param aSubstituteModels = true to allows data substitution, false to disallow.
|
||||||
|
* @param aErrorMessage (can be nullptr) is an error message to be displayed on error.
|
||||||
|
* @return true if successfully loaded, false on error.
|
||||||
|
*/
|
||||||
|
bool getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_Label& aLabel,
|
||||||
|
bool aSubstituteModels, wxString* aErrorMessage = nullptr );
|
||||||
|
|
||||||
|
bool getModelLocation( bool aBottom, DOUBLET aPosition, double aRotation, TRIPLET aOffset,
|
||||||
|
TRIPLET aOrientation, TopLoc_Location& aLocation );
|
||||||
|
|
||||||
|
bool readIGES( Handle( TDocStd_Document )& m_doc, const char* fname );
|
||||||
|
bool readSTEP( Handle( TDocStd_Document )& m_doc, const char* fname );
|
||||||
|
|
||||||
|
TDF_Label transferModel( Handle( TDocStd_Document )& source,
|
||||||
|
Handle( TDocStd_Document )& dest, TRIPLET aScale );
|
||||||
|
|
||||||
|
Handle( XCAFApp_Application ) m_app;
|
||||||
|
Handle( TDocStd_Document ) m_doc;
|
||||||
|
Handle( XCAFDoc_ShapeTool ) m_assy;
|
||||||
|
TDF_Label m_assy_label;
|
||||||
|
bool m_hasPCB; // set true if CreatePCB() has been invoked
|
||||||
|
TDF_Label m_pcb_label; // label for the PCB model
|
||||||
|
MODEL_MAP m_models; // map of file names to model labels
|
||||||
|
int m_components; // number of successfully loaded components;
|
||||||
|
double m_precision; // model (length unit) numeric precision
|
||||||
|
double m_angleprec; // angle numeric precision
|
||||||
|
double m_thickness; // PCB thickness, mm
|
||||||
|
|
||||||
|
// minimum X value in curves (leftmost curve feature).
|
||||||
|
double m_minx;
|
||||||
|
double m_minDistance2; // minimum squared distance between items (mm)
|
||||||
|
std::list<KICADCURVE>::iterator m_mincurve; // iterator to the leftmost curve
|
||||||
|
|
||||||
|
std::list<KICADCURVE> m_curves;
|
||||||
|
std::vector<TopoDS_Shape> m_cutouts;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // OCE_VIS_OCE_UTILS_H
|
#endif // OCE_VIS_OCE_UTILS_H
|
||||||
|
|
Loading…
Reference in New Issue