diff --git a/plugins/ldr/pluginldr.cpp b/plugins/ldr/pluginldr.cpp index 43b604c220..ed8a988272 100644 --- a/plugins/ldr/pluginldr.cpp +++ b/plugins/ldr/pluginldr.cpp @@ -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" ); diff --git a/utils/kicad2step/kicad2step.cpp b/utils/kicad2step/kicad2step.cpp index 1bd44f14f4..7115c3fe1f 100644 --- a/utils/kicad2step/kicad2step.cpp +++ b/utils/kicad2step/kicad2step.cpp @@ -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 ); diff --git a/utils/kicad2step/pcb/3d_resolver.cpp b/utils/kicad2step/pcb/3d_resolver.cpp index 99354a8d0f..9a54ff9d20 100644 --- a/utils/kicad2step/pcb/3d_resolver.cpp +++ b/utils/kicad2step/pcb/3d_resolver.cpp @@ -2,7 +2,7 @@ * This program source code file is part kicad2mcad * * Copyright (C) 2015-2016 Cirilo Bernardo - * 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; } diff --git a/utils/kicad2step/pcb/3d_resolver.h b/utils/kicad2step/pcb/3d_resolver.h index 76144f3372..c4af72b2fe 100644 --- a/utils/kicad2step/pcb/3d_resolver.h +++ b/utils/kicad2step/pcb/3d_resolver.h @@ -2,6 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2015-2016 Cirilo Bernardo + * 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 diff --git a/utils/kicad2step/pcb/kicadfootprint.h b/utils/kicad2step/pcb/kicadfootprint.h index 5c2b4d6f6a..6687b08669 100644 --- a/utils/kicad2step/pcb/kicadfootprint.h +++ b/utils/kicad2step/pcb/kicadfootprint.h @@ -2,6 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016 Cirilo Bernardo + * 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 diff --git a/utils/kicad2step/pcb/kicadpad.h b/utils/kicad2step/pcb/kicadpad.h index 7d32e7bc50..3ab4750a79 100644 --- a/utils/kicad2step/pcb/kicadpad.h +++ b/utils/kicad2step/pcb/kicadpad.h @@ -2,6 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016 Cirilo Bernardo + * 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 diff --git a/utils/kicad2step/pcb/kicadpcb.h b/utils/kicad2step/pcb/kicadpcb.h index 8f520fdeac..1acf0c4019 100644 --- a/utils/kicad2step/pcb/kicadpcb.h +++ b/utils/kicad2step/pcb/kicadpcb.h @@ -2,6 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016 Cirilo Bernardo + * 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 m_layersNames; - - // PCB parameters/entities - double m_thickness; - std::vector m_footprints; - std::vector 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 m_layersNames; + + // PCB parameters/entities + double m_thickness; + std::vector m_footprints; + std::vector m_curves; }; diff --git a/utils/kicad2step/pcb/oce_utils.cpp b/utils/kicad2step/pcb/oce_utils.cpp index 74eb86d2a7..5dc1a6d53e 100644 --- a/utils/kicad2step/pcb/oce_utils.cpp +++ b/utils/kicad2step/pcb/oce_utils.cpp @@ -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 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 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() ) diff --git a/utils/kicad2step/pcb/oce_utils.h b/utils/kicad2step/pcb/oce_utils.h index 7b385baefa..82e054b305 100644 --- a/utils/kicad2step/pcb/oce_utils.h +++ b/utils/kicad2step/pcb/oce_utils.h @@ -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::iterator m_mincurve; // iterator to the leftmost curve - - std::list m_curves; - std::vector 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::iterator m_mincurve; // iterator to the leftmost curve + + std::list m_curves; + std::vector m_cutouts; }; #endif // OCE_VIS_OCE_UTILS_H