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"
/**
* Flag to enable plugin loader trace output.
*
* @ingroup trace_env_vars
*/
const wxChar* const tracePluginLoader = wxT( "KICAD_PLUGIN_LOADER" );

View File

@ -44,8 +44,8 @@ class KICAD2MCAD_APP : public wxApp
public:
KICAD2MCAD_APP() :
wxApp(),
m_frame( nullptr ),
m_Panel( nullptr )
m_Panel( nullptr ),
m_frame( nullptr )
{}
virtual bool OnInit() override;
@ -53,24 +53,24 @@ public:
virtual void OnInitCmdLine(wxCmdLineParser& parser) override;
virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override;
private:
KICAD2STEP_FRAME * m_frame;
KICAD2MCAD_PRMS m_params;
public:
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
{
public:
KICAD2STEP_FRAME(const wxString& title);
private:
KICAD2STEP_FRAME( const wxString& title );
};
KICAD2MCAD_PRMS::KICAD2MCAD_PRMS()
{
#ifdef SUPPORTS_IGES
@ -95,38 +95,40 @@ void ReportMessage( const wxString& aMessage )
}
static const wxCmdLineEntryDesc cmdLineDesc[] =
{
{ wxCMD_LINE_PARAM, NULL, NULL, _( "pcb_filename" ).mb_str(),
wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY },
{ wxCMD_LINE_OPTION, "o", "output-filename", _( "output filename" ).mb_str(),
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
static const wxCmdLineEntryDesc cmdLineDesc[] = {
{ wxCMD_LINE_PARAM, NULL, NULL, _( "pcb_filename" ).mb_str(), wxCMD_LINE_VAL_STRING,
wxCMD_LINE_OPTION_MANDATORY },
{ wxCMD_LINE_OPTION, "o", "output-filename", _( "output filename" ).mb_str(),
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
#ifdef SUPPORTS_IGES
{ wxCMD_LINE_SWITCH, "fmt-iges", NULL, _("IGES output (default STEP)").mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_SWITCH, "fmt-iges", NULL, _( "IGES output (default STEP)" ).mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
#endif
{ wxCMD_LINE_SWITCH, "f", "force", _( "overwrite output file" ).mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_SWITCH, NULL, "drill-origin", _( "Use Drill Origin for output origin" ).mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_SWITCH, NULL, "grid-origin", _( "Use Grid Origin for output origin" ).mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_OPTION, NULL, "user-origin",
_( "User-specified output origin ex. 1x1in, 1x1inch, 25.4x25.4mm (default mm)" ).mb_str(),
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_SWITCH, NULL, "no-virtual",
_( "Exclude 3D models for components with 'virtual' attribute" ).mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_SWITCH, NULL, "subst-models",
_( "Substitute STEP or IGS models with the same name in place of VRML models" ).mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_OPTION, NULL, "min-distance",
_( "Minimum distance between points to treat them as separate ones (default 0.01 mm)" ).mb_str(),
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
{ 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 }
};
{ wxCMD_LINE_SWITCH, "f", "force", _( "overwrite output file" ).mb_str(), wxCMD_LINE_VAL_NONE,
wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_SWITCH, NULL, "drill-origin", _( "Use Drill Origin for output origin" ).mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_SWITCH, NULL, "grid-origin", _( "Use Grid Origin for output origin" ).mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_OPTION, NULL, "user-origin",
_( "User-specified output origin ex. 1x1in, 1x1inch, 25.4x25.4mm (default mm)" ).mb_str(),
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_SWITCH, NULL, "no-virtual",
_( "Exclude 3D models for components with 'virtual' attribute" ).mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_SWITCH, NULL, "subst-models",
_( "Substitute STEP or IGS models with the same name in place of VRML models" ).mb_str(),
wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_OPTION, NULL, "min-distance",
_( "Minimum distance between points to treat them as separate ones (default 0.01 mm)" )
.mb_str(),
wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
{ 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()
@ -157,8 +159,8 @@ int KICAD2MCAD_APP::OnRun()
}
KICAD2STEP_FRAME::KICAD2STEP_FRAME(const wxString& title)
: KICAD2STEP_FRAME_BASE(NULL, wxID_ANY, title)
KICAD2STEP_FRAME::KICAD2STEP_FRAME( const wxString& title ) :
KICAD2STEP_FRAME_BASE( NULL, wxID_ANY, title )
{
}
@ -167,7 +169,6 @@ void KICAD2MCAD_APP::OnInitCmdLine( wxCmdLineParser& parser )
{
parser.SetDesc( cmdLineDesc );
parser.SetSwitchChars( "-" );
return;
}
@ -178,8 +179,8 @@ PANEL_KICAD2STEP::PANEL_KICAD2STEP( wxWindow* parent, wxWindowID id, const wxPoi
wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
m_tcMessages = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE|wxTE_READONLY );
bSizer->Add( m_tcMessages, 1, wxALL|wxEXPAND, 5 );
wxTE_MULTILINE | wxTE_READONLY );
bSizer->Add( m_tcMessages, 1, wxALL | wxEXPAND, 5 );
SetSizer( bSizer );
Layout();
@ -196,10 +197,10 @@ void PANEL_KICAD2STEP::AppendMessage( const wxString& aMessage )
bool KICAD2MCAD_APP::OnCmdLineParsed( wxCmdLineParser& parser )
{
#ifdef SUPPORTS_IGES
#ifdef SUPPORTS_IGES
if( parser.Found( "fmt-iges" ) )
m_fmtIGES = true;
#endif
#endif
if( parser.Found( "f" ) )
m_params.m_overwrite = true;
@ -265,7 +266,6 @@ bool KICAD2MCAD_APP::OnCmdLineParsed( wxCmdLineParser& parser )
}
}
if( parser.Found( "min-distance", &tstr ) )
{
std::istringstream istr;
@ -319,20 +319,21 @@ bool KICAD2MCAD_APP::OnCmdLineParsed( wxCmdLineParser& parser )
class STREAMBUF_SWAPPER
{
public:
STREAMBUF_SWAPPER( std::ostream & orig, std::ostream & replacement )
: m_buf( orig.rdbuf() ), m_str( orig )
STREAMBUF_SWAPPER( std::ostream& orig, std::ostream& replacement ) :
m_buf( orig.rdbuf() ),
m_str( orig )
{
orig.rdbuf( replacement.rdbuf() );
}
~STREAMBUF_SWAPPER()
{
m_str.rdbuf( m_buf);
m_str.rdbuf( m_buf );
}
private:
std::streambuf * m_buf;
std::ostream & m_str;
std::streambuf* m_buf;
std::ostream& m_str;
};
@ -342,7 +343,7 @@ int PANEL_KICAD2STEP::RunConverter()
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;
}
@ -365,8 +366,8 @@ int PANEL_KICAD2STEP::RunConverter()
if( out_fname.FileExists() && !m_params.m_overwrite )
{
ReportMessage( "** Output already exists.\n"
"Enable the force overwrite flag to overwrite it." );
ReportMessage( _( "** Output already exists.\n"
"Enable the force overwrite flag to overwrite it." ) );
return -1;
}
@ -376,14 +377,14 @@ int PANEL_KICAD2STEP::RunConverter()
pcb.SetOrigin( m_params.m_xOrigin, m_params.m_yOrigin );
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
// msgs_from_opencascade and errors_from_opencascade
std::ostringstream msgs_from_opencascade;
std::ostringstream errors_from_opencascade;
STREAMBUF_SWAPPER swapper_cout(std::cout, msgs_from_opencascade);
STREAMBUF_SWAPPER swapper_cerr(std::cerr, errors_from_opencascade);
STREAMBUF_SWAPPER swapper_cout( std::cout, msgs_from_opencascade );
STREAMBUF_SWAPPER swapper_cerr( std::cerr, errors_from_opencascade );
if( pcb.ReadFile( m_params.m_filename ) )
{
@ -397,44 +398,44 @@ int PANEL_KICAD2STEP::RunConverter()
try
{
ReportMessage( "Build STEP data\n" );
ReportMessage( _( "Build STEP data\n" ) );
res = pcb.ComposePCB( m_params.m_includeVirtual, m_params.m_substModels );
if( !res )
{
ReportMessage( "\n**Error building STEP board model. Abort export **\n" );
ReportMessage( _( "\n**Error building STEP board model. Abort export **\n" ) );
return -1;
}
ReportMessage( "Write STEP file\n" );
ReportMessage( _( "Write STEP file\n" ) );
#ifdef SUPPORTS_IGES
#ifdef SUPPORTS_IGES
if( m_fmtIGES )
res = pcb.WriteIGES( outfile );
else
#endif
#endif
res = pcb.WriteSTEP( outfile );
if( !res )
{
ReportMessage( "\nError Write STEP file\n" );
ReportMessage( _( "\nError Write STEP file\n" ) );
return -1;
}
}
catch( const Standard_Failure& e )
{
wxString err = e.GetMessageString();
wxMessageBox( err, "Export Error" );
wxMessageBox( err, _( "Export Error" ) );
ReportMessage( wxString::Format( "\nExport Error: %s\n", err ) );
ReportMessage( "\n*** Abort export ***\n" );
ReportMessage( wxString::Format( _( "\nExport Error: %s\n" ), err ) );
ReportMessage( _( "\n*** Abort export ***\n" ) );
return -1;
}
catch( ... )
{
wxMessageBox( "(no exception information)", "Unknown error" );
ReportMessage( "\nUnknown error\n*** Abort export ***\n" );
wxMessageBox( _( "(no exception information)" ), _( "Unknown error" ) );
ReportMessage( _( "\nUnknown error\n*** Abort export ***\n" ) );
return -1;
}
}
@ -443,7 +444,7 @@ int PANEL_KICAD2STEP::RunConverter()
msgs << msgs_from_opencascade.str();
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();
ReportMessage( errs );
@ -456,17 +457,17 @@ int PANEL_KICAD2STEP::RunConverter()
{
if( !success )
{
msg = "Unable to create STEP file.\n"
"Check that the board has a valid outline and models.";
msg = _( "Unable to create STEP file.\n"
"Check that the board has a valid outline and models." );
}
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
{
msg.Printf( "STEP file:\n%s\nhas been created successfully.", outfile );
msg.Printf( _( "STEP file:\n%s\nhas been created successfully." ), outfile );
}
ReportMessage( msg );

View File

@ -2,7 +2,7 @@
* This program source code file is part kicad2mcad
*
* 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
* modify it under the terms of the GNU General Public License
@ -49,12 +49,21 @@
#define ERRFLG_RELPATH (2)
#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 bool getHollerith( const std::string& aString, size_t& aIndex, wxString& aResult );
S3D_RESOLVER::S3D_RESOLVER()
{
m_errflags = 0;
@ -116,15 +125,9 @@ bool S3D_RESOLVER::SetProjectDir( const wxString& aProjDir, bool* flgChanged )
}
}
#ifdef DEBUG
do {
std::ostringstream ostr;
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
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
" * [INFO] changed project dir to '%s'" ),
__FILE__, __FUNCTION__, __LINE__, m_Paths.front().m_Pathexp );
return true;
}
@ -244,15 +247,10 @@ bool S3D_RESOLVER::createPathList( void )
return false;
#ifdef DEBUG
wxLogTrace( MASK_3D_RESOLVER, " * [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();
wxLogTrace( trace3dResolver, " * [3D model] search paths:\n" );
while( sPL != ePL )
{
wxLogTrace( MASK_3D_RESOLVER, " + '%s'\n", (*sPL).m_Pathexp.ToUTF8() );
++sPL;
}
for( const auto searchPath : m_Paths )
wxLogTrace( trace3dResolver, " + '%s'\n", searchPath.m_Pathexp );
#endif
return true;
@ -409,7 +407,7 @@ wxString S3D_RESOLVER::ResolvePath( const wxString& aFileName )
wxString errmsg = "[3D File Resolver] No such path";
errmsg.append( "\n" );
errmsg.append( tname );
wxLogTrace( MASK_3D_RESOLVER, "%s\n", errmsg.ToUTF8() );
wxLogTrace( trace3dResolver, "%s\n", errmsg.ToUTF8() );
}
return wxEmptyString;
@ -443,10 +441,9 @@ wxString S3D_RESOLVER::ResolvePath( const wxString& aFileName )
if( !( m_errflags & ERRFLG_ALIAS ) )
{
m_errflags |= ERRFLG_ALIAS;
wxString errmsg = "[3D File Resolver] No such path; ensure the path alias is defined";
errmsg.append( "\n" );
errmsg.append( tname.substr( 1 ) );
wxLogTrace( MASK_3D_RESOLVER, "%s\n", errmsg.ToUTF8() );
wxLogTrace( trace3dResolver,
wxT( "[3D File Resolver] No such path; ensure the path alias is defined %s" ),
tname.substr( 1 ) );
}
return wxEmptyString;
@ -476,7 +473,8 @@ bool S3D_RESOLVER::addPath( const SEARCH_PATH& aPath )
if( !path.DirExists() )
{
// 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" );
msg.append( "\n" );
@ -541,12 +539,10 @@ bool S3D_RESOLVER::readPathList( void )
if( !wxFileName::Exists( cfgname ) )
{
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = "no 3D configuration file";
ostr << " * " << errmsg.ToUTF8() << " '";
ostr << cfgname.ToUTF8() << "'";
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
wxLogTrace( trace3dResolver, wxT( "%s:%s:d\n"
" * no 3D configuration file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, cfgname );
return false;
}
@ -554,11 +550,10 @@ bool S3D_RESOLVER::readPathList( void )
if( !cfgFile.is_open() )
{
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = "Could not open configuration file";
ostr << " * " << errmsg.ToUTF8() << " '" << cfgname.ToUTF8() << "'";
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
" * Could not open configuration file '%s'" ),
__FILE__, __FUNCTION__, __LINE__, cfgname );
return false;
}
@ -729,8 +724,7 @@ wxString S3D_RESOLVER::ShortenPath( const wxString& aFullPathName )
while( sL != eL )
{
// undefined paths do not participate in the
// file name shortening procedure
// undefined paths do not participate in the file name shortening procedure.
if( sL->m_Pathexp.empty() )
{
++sL;
@ -793,8 +787,7 @@ const std::list< SEARCH_PATH >* S3D_RESOLVER::GetPaths( void )
}
bool S3D_RESOLVER::SplitAlias( const wxString& aFileName,
wxString& anAlias, wxString& aRelPath )
bool S3D_RESOLVER::SplitAlias( const wxString& aFileName, wxString& anAlias, wxString& aRelPath )
{
anAlias.clear();
aRelPath.clear();
@ -823,11 +816,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
if( aIndex >= aString.size() )
{
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = "bad Hollerith string on line";
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
" * Bad Hollerith string in line \"%s\"" ),
__FILE__, __FUNCTION__, __LINE__, aString );
return false;
}
@ -836,11 +827,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
if( std::string::npos == i2 )
{
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = "missing opening quote mark in config file";
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
" * missing opening quote mark in line \"%s\"" ),
__FILE__, __FUNCTION__, __LINE__, aString );
return false;
}
@ -849,11 +838,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
if( i2 >= aString.size() )
{
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = "invalid entry (unexpected end of line)";
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
" * unexpected end of line in line \"%s\"" ),
__FILE__, __FUNCTION__, __LINE__, aString );
return false;
}
@ -865,11 +852,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
if( tnum.empty() || aString[i2++] != ':' )
{
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = "bad Hollerith string on line";
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
" * Bad Hollerith string in line \"%s\"" ),
__FILE__, __FUNCTION__, __LINE__, aString );
return false;
}
@ -881,11 +866,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
if( (i2 + nchars) >= aString.size() )
{
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = "invalid entry (unexpected end of line)";
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
" * unexpected end of line in line \"%s\"\n" ),
__FILE__, __FUNCTION__, __LINE__, aString );
return false;
}
@ -898,11 +881,9 @@ static bool getHollerith( const std::string& aString, size_t& aIndex, wxString&
if( i2 >= aString.size() || aString[i2] != '"' )
{
std::ostringstream ostr;
ostr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
wxString errmsg = "missing closing quote mark in config file";
ostr << " * " << errmsg.ToUTF8() << "\n'" << aString << "'";
wxLogTrace( MASK_3D_RESOLVER, "%s\n", ostr.str().c_str() );
wxLogTrace( trace3dResolver, wxT( "%s:%s:%d\n"
" * missing closing quote mark in line \"%s\"" ),
__FILE__, __FUNCTION__, __LINE__, aString );
return false;
}

View File

@ -2,6 +2,7 @@
* 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) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -38,53 +39,52 @@
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() )
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;
// note: this rule implies that a null string is first in the sort order
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
@ -99,128 +99,114 @@ struct SEARCH_PATH
wxString m_Description; // description of the aliased path
};
class S3D_RESOLVER
{
private:
wxString m_ConfigDir; // 3D configuration directory
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;
public:
S3D_RESOLVER();
/**
* Function createPathList
* builds 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.
* Set the user's configuration directory for 3D models.
*
* @param aConfigDir
* @return true if the call succeeds (directory exists).
*/
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
*/
bool createPathList( void );
/**
* Function addPath
* checks that a path is valid and adds it to the search list
* Check that \a aPath is valid and adds it to the search list.
*
* @param aPath is the alias set to be checked and added
* @return true if aPath is valid
* @param aPath is the alias set to be checked and added.
* @return true if \a aPath is valid.
*/
bool addPath( const SEARCH_PATH& aPath );
/**
* Function readPathList
* reads a list of path names from a configuration file
* Read a list of path names from a configuration file.
*
* @return true if a file was found and contained at least
* one valid path
* @return true if a file was found and contained at least one valid path.
*/
bool readPathList( void );
/**
* Function checkEnvVarPath
* checks the ${ENV_VAR} component of a path and adds
* it to the resolver's path list if it is not yet in
* the list
* Check the ${ENV_VAR} component of a path and adds it to the resolver's path list if it
* is not yet in the list.
*/
void checkEnvVarPath( const wxString& aPath );
wxString expandVars( const wxString& aPath );
public:
S3D_RESOLVER();
wxString m_ConfigDir; ///< 3D configuration directory.
std::list< SEARCH_PATH > m_Paths; ///< List of base search paths.
/**
* Function Set3DConfigDir
* sets the user's configuration directory
* for 3D models.
*
* @param aConfigDir
* @return true if the call succeeds (directory exists)
*/
bool Set3DConfigDir( const wxString& aConfigDir );
///< Mapping of (short) file names to resolved names.
std::map< wxString, wxString, S3D::rsort_wxString > m_NameMap;
int m_errflags;
wxString m_curProjDir;
/**
* Function SetProjectDir
* 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 );
///< Environment variables.
std::map< wxString, wxString > m_EnvVars;
};
#endif // RESOLVER_3D_H

View File

@ -2,6 +2,7 @@
* 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) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -43,6 +44,15 @@ class S3D_RESOLVER;
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:
bool parseModel( SEXPR::SEXPR* data );
bool parseCurve( SEXPR::SEXPR* data, CURVE_TYPE aCurveType );
@ -64,15 +74,6 @@ private:
std::vector< KICADPAD* > m_pads;
std::vector< KICADCURVE* > m_curves;
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

View File

@ -2,6 +2,7 @@
* 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) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -23,7 +24,7 @@
/**
* @file kicadpad.h
* declares the PAD description object.
* Declare the PAD description object.
*/
#ifndef KICADPAD_H
@ -43,10 +44,6 @@ struct KICADDRILL
class KICADPAD
{
private:
bool m_thruhole;
bool parseDrill( const SEXPR::SEXPR* aDrill );
public:
KICADPAD();
virtual ~KICADPAD();
@ -58,9 +55,16 @@ public:
return m_thruhole;
}
private:
bool parseDrill( const SEXPR::SEXPR* aDrill );
public:
DOUBLET m_position;
double m_rotation; // rotation (radians)
KICADDRILL m_drill;
private:
bool m_thruhole;
};
#endif // KICADPAD_H

View File

@ -2,6 +2,7 @@
* 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) 2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -52,38 +53,6 @@ class PCBMODEL;
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:
KICADPCB();
virtual ~KICADPCB();
@ -114,9 +83,44 @@ public:
bool ReadFile( const wxString& aFileName );
bool ComposePCB( bool aComposeVirtual = true, bool aSubstituteModels = true );
bool WriteSTEP( const wxString& aFileName );
#ifdef SUPPORTS_IGES
#ifdef SUPPORTS_IGES
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_ANGLE_PREC = 1e-6;
// minimum PCB thickness in mm (2 microns assumes a very thin polyimide film)
static constexpr double THICKNESS_MIN = 0.002;
// default PCB thickness in mm
static constexpr double THICKNESS_DEFAULT = 1.6;
// nominal offset from the board
static constexpr double BOARD_OFFSET = 0.05;
// min. length**2 below which 2 points are considered coincident
static constexpr double MIN_LENGTH2 = MIN_DISTANCE * MIN_DISTANCE;
static void getEndPoints( const KICADCURVE& aCurve, double& spx0, double& spy0,
double& epx0, double& epy0 )
double& epx0, double& epy0 )
{
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;
epx0 = aCurve.m_end.x;
epy0 = aCurve.m_end.y;
return;
}
static void getCurveEndPoint( const KICADCURVE& aCurve, DOUBLET& aEndPoint )
{
if( CURVE_CIRCLE == aCurve.m_form )
@ -129,7 +133,6 @@ static void getCurveEndPoint( const KICADCURVE& aCurve, DOUBLET& aEndPoint )
// assume a line
aEndPoint.x = aCurve.m_end.x;
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_endangle, aCurve.m_startangle );
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_mincurve = m_curves.end();
BRepBuilderAPI::Precision( MIN_DISTANCE );
return;
}
PCBMODEL::~PCBMODEL()
{
m_doc->Close();
return;
}
// add an outline segment
bool PCBMODEL::AddOutlineSegment( KICADCURVE* aCurve )
{
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 )
{
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() );
ReportMessage( msg );
return false;
@ -343,124 +343,122 @@ bool PCBMODEL::AddOutlineSegment( KICADCURVE* aCurve )
// check if this curve has the current leftmost feature
switch( aCurve->m_form )
{
case CURVE_LINE:
if( aCurve->m_start.x < m_minx )
case CURVE_LINE:
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_mincurve = --(m_curves.end());
m_minx = dx;
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_mincurve = --(m_curves.end());
m_minx = minx;
m_mincurve = --( m_curves.end() );
}
break;
} while( 0 );
case CURVE_CIRCLE:
do
{
double dx = aCurve->m_start.x - aCurve->m_radius;
break;
if( dx < m_minx )
{
m_minx = dx;
m_mincurve = --(m_curves.end());
}
} while( 0 );
case CURVE_BEZIER:
if( aCurve->m_start.x < m_minx )
{
m_minx = aCurve->m_start.x;
m_mincurve = --( m_curves.end() );
}
break;
if( aCurve->m_end.x < m_minx )
{
m_minx = aCurve->m_end.x;
m_mincurve = --( m_curves.end() );
}
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
break;
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;
default:
// unexpected curve type
do
{
wxString msg;
msg.Printf( " * AddOutlineSegment() unsupported curve type: %d\n", aCurve->m_form );
ReportMessage( msg );
} while( 0 );
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 );
}
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 false;
}
return true;
}
// add a pad hole or slot
bool PCBMODEL::AddPadHole( const KICADPAD* aPad )
{
if( NULL == aPad || !aPad->IsThruHole() )
@ -469,9 +467,10 @@ bool PCBMODEL::AddPadHole( const KICADPAD* aPad )
if( !aPad->m_drill.oval )
{
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;
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 );
m_cutouts.push_back( hole.Shape() );
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 aBottom, DOUBLET aPosition, double aRotation,
TRIPLET aOffset, TRIPLET aOrientation, TRIPLET aScale,
@ -664,8 +662,6 @@ void PCBMODEL::SetPCBThickness( double aThickness )
m_thickness = THICKNESS_MIN;
else
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()
{
if( m_hasPCB )
@ -814,7 +809,8 @@ bool PCBMODEL::CreatePCB()
(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
// state to be sure there is no hang:
int char_count = 0;
@ -863,8 +859,7 @@ bool PCBMODEL::CreatePCB()
return false;
// color the PCB
Handle(XCAFDoc_ColorTool) color =
XCAFDoc_DocumentTool::ColorTool( m_doc->Main () );
Handle( XCAFDoc_ColorTool ) color = XCAFDoc_DocumentTool::ColorTool( m_doc->Main () );
Quantity_Color pcb_green( 0.06, 0.4, 0.06, Quantity_TOC_RGB );
color->SetColor( m_pcb_label, pcb_green, XCAFDoc_ColorSurf );
@ -915,7 +910,6 @@ bool PCBMODEL::WriteIGES( const wxString& aFileName )
#endif
// write the assembly model in STEP format
bool PCBMODEL::WriteSTEP( const wxString& aFileName )
{
if( m_pcb_label.IsNull() )
@ -942,9 +936,11 @@ bool PCBMODEL::WriteSTEP( const wxString& aFileName )
return false;
APIHeaderSection_MakeHeader hdr( writer.ChangeWriter().Model() );
// Note: use only Ascii7 chars, non Ascii7 chars (therefore UFT8 chars)
// are creating issues in the step file
hdr.SetName( new TCollection_HAsciiString( fn.GetFullName().ToAscii() ) );
// TODO: how to control and ensure consistency with IGES?
hdr.SetAuthorValue( 1, new TCollection_HAsciiString( "Pcbnew" ) );
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" ) );
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 workCWD =fn.GetPath();
wxString workCWD = fn.GetPath();
if( !workCWD.IsEmpty() )
wxSetWorkingDirectory( workCWD );
@ -1005,171 +1001,166 @@ bool PCBMODEL::getModelLabel( const std::string& aFileName, TRIPLET aScale, TDF_
switch( modelFmt )
{
case FMT_IGES:
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:
case FMT_IGES:
if( !readIGES( doc, aFileName.c_str() ) )
{
wxFFileInputStream ifile( aFileName );
wxFileName outFile( aFileName );
ReportMessage( wxString::Format( "readIGES() failed on filename '%s'.\n", aFileName ) );
return false;
}
break;
outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
outFile.SetExt( "STEP" );
case FMT_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 )
{
ReportMessage( wxString::Format( "readSTEP() failed on filename '%s'.\n",
aFileName ) );
return false;
}
outFile.SetPath( wxStandardPaths::Get().GetTempDir() );
outFile.SetExt( "STEP" );
{
bool success = false;
wxFFileOutputStream ofile( outFile.GetFullPath() );
wxFileOffset size = ifile.GetLength();
if( !ofile.IsOk() )
return false;
char *buffer = new char[size];
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;
if( size == wxInvalidOffset )
{
ReportMessage( wxString::Format( "readSTEP() failed on filename '%s'.\n", aFileName ) );
return false;
}
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 )
{
bool success = false;
wxFFileOutputStream ofile( outFile.GetFullPath() );
if( !ofile.IsOk() )
return false;
char* buffer = new char[size];
ifile.Read( buffer, size );
std::string expanded;
try
{
wxFileName wrlName( aFileName );
expanded = gzip::decompress( buffer, size );
success = true;
}
catch( ... )
{
}
wxString basePath = wrlName.GetPath();
wxString baseName = wrlName.GetName();
if( expanded.empty() )
{
ifile.Reset();
ifile.SeekI( 0 );
wxZipInputStream izipfile( ifile );
std::unique_ptr<wxZipEntry> zip_file( izipfile.GetNextEntry() );
// 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 )
if( zip_file && !zip_file->IsDir() && izipfile.CanRead() )
{
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();
// 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 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
default:
return false;
default:
return false;
}
aLabel = transferModel( doc, m_doc, aScale );
@ -1338,7 +1329,6 @@ TDF_Label PCBMODEL::transferModel( Handle( TDocStd_Document )& source,
0, 0, aScale.z ) );
BRepBuilderAPI_GTransform brep( scale_transform );
// s_assy = shape tool for the source
Handle(XCAFDoc_ShapeTool) s_assy = XCAFDoc_DocumentTool::ShapeTool ( source->Main() );
@ -1456,13 +1446,11 @@ OUTLINE::OUTLINE()
{
m_closed = false;
m_minDistance2 = MIN_LENGTH2;
return;
}
OUTLINE::~OUTLINE()
{
return;
}
@ -1470,7 +1458,6 @@ void OUTLINE::Clear()
{
m_closed = false;
m_curves.clear();
return;
}
@ -1618,53 +1605,52 @@ bool OUTLINE::addEdge( BRepBuilderAPI_MakeWire* aWire, KICADCURVE& aCurve, DOUBL
switch( aCurve.m_form )
{
case CURVE_LINE:
edge = BRepBuilderAPI_MakeEdge( gp_Pnt( aLastPoint.x, aLastPoint.y, 0.0 ),
gp_Pnt( endPoint.x, endPoint.y, 0.0 ) );
break;
case CURVE_LINE:
edge = BRepBuilderAPI_MakeEdge( gp_Pnt( aLastPoint.x, aLastPoint.y, 0.0 ),
gp_Pnt( endPoint.x, endPoint.y, 0.0 ) );
break;
case CURVE_ARC:
{
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 );
case CURVE_ARC:
{
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_Pnt sa( aLastPoint.x, aLastPoint.y, 0.0 );
gp_Pnt ea( endPoint.x, endPoint.y, 0.0 );
gp_Pnt sa( aLastPoint.x, aLastPoint.y, 0.0 );
gp_Pnt ea( endPoint.x, endPoint.y, 0.0 );
if( aCurve.m_angle < 0.0 )
edge = BRepBuilderAPI_MakeEdge( arc, ea, sa );
else
edge = BRepBuilderAPI_MakeEdge( arc, sa, ea );
}
break;
if( aCurve.m_angle < 0.0 )
edge = BRepBuilderAPI_MakeEdge( arc, ea, sa );
else
edge = BRepBuilderAPI_MakeEdge( arc, sa, ea );
}
break;
case CURVE_CIRCLE:
edge = BRepBuilderAPI_MakeEdge( gp_Circ( 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 ) );
break;
case CURVE_CIRCLE:
edge = BRepBuilderAPI_MakeEdge(
gp_Circ( 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 ) );
break;
case CURVE_BEZIER:
{
TColgp_Array1OfPnt poles(0, 3);
gp_Pnt pt = gp_Pnt( aCurve.m_start.x, aCurve.m_start.y, 0.0 );
poles(0) = pt;
pt = gp_Pnt( aCurve.m_bezierctrl1.x, aCurve.m_bezierctrl1.y, 0.0 );
poles(1) = pt;
pt = gp_Pnt( aCurve.m_bezierctrl2.x, aCurve.m_bezierctrl2.y, 0.0 );
poles(2) = pt;
pt = gp_Pnt( endPoint.x, endPoint.y, 0.0 );
poles(3) = pt;
case CURVE_BEZIER:
{
TColgp_Array1OfPnt poles( 0, 3 );
gp_Pnt pt = gp_Pnt( aCurve.m_start.x, aCurve.m_start.y, 0.0 );
poles( 0 ) = pt;
pt = gp_Pnt( aCurve.m_bezierctrl1.x, aCurve.m_bezierctrl1.y, 0.0 );
poles( 1 ) = pt;
pt = gp_Pnt( aCurve.m_bezierctrl2.x, aCurve.m_bezierctrl2.y, 0.0 );
poles( 2 ) = pt;
pt = gp_Pnt( endPoint.x, endPoint.y, 0.0 );
poles( 3 ) = pt;
Geom_BezierCurve* bezier_curve = new Geom_BezierCurve( poles );
edge = BRepBuilderAPI_MakeEdge( bezier_curve );
}
break;
Geom_BezierCurve* bezier_curve = new Geom_BezierCurve( poles );
edge = BRepBuilderAPI_MakeEdge( bezier_curve );
}
break;
default:
ReportMessage( wxString::Format( "unsupported curve type: %d\n", aCurve.m_form ) );
return false;
default:
ReportMessage( wxString::Format( "unsupported curve type: %d\n", aCurve.m_form ) );
return false;
}
if( edge.IsNull() )

View File

@ -49,15 +49,7 @@ class KICADPAD;
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:
std::list< KICADCURVE > m_curves; // list of contiguous segments
OUTLINE();
virtual ~OUTLINE();
@ -77,51 +69,22 @@ public:
}
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
{
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:
PCBMODEL();
virtual ~PCBMODEL();
@ -157,6 +120,50 @@ public:
// write the assembly model in STEP format
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