KiCad2Step code cleaning.

This commit is contained in:
Wayne Stambaugh 2021-07-29 07:10:58 -04:00
parent 934b6e4cdc
commit d36fbb864f
9 changed files with 662 additions and 687 deletions

View File

@ -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" );

View File

@ -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 );

View File

@ -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;
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}; };

View File

@ -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() )

View File

@ -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