Add relative to footprint 3d model path resolution

Fixes https://gitlab.com/kicad/code/kicad/-/issues/2073
This commit is contained in:
Marek Roszko 2022-09-25 22:54:08 -04:00
parent 05f01ab6c6
commit c50b4fb04f
11 changed files with 79 additions and 18 deletions

View File

@ -212,12 +212,13 @@ S3D_CACHE::~S3D_CACHE()
}
SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, S3D_CACHE_ENTRY** aCachePtr )
SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, const wxString& aBasePath,
S3D_CACHE_ENTRY** aCachePtr )
{
if( aCachePtr )
*aCachePtr = nullptr;
wxString full3Dpath = m_FNResolver->ResolvePath( aModelFile );
wxString full3Dpath = m_FNResolver->ResolvePath( aModelFile, aBasePath );
if( full3Dpath.empty() )
{
@ -282,9 +283,9 @@ SCENEGRAPH* S3D_CACHE::load( const wxString& aModelFile, S3D_CACHE_ENTRY** aCach
}
SCENEGRAPH* S3D_CACHE::Load( const wxString& aModelFile )
SCENEGRAPH* S3D_CACHE::Load( const wxString& aModelFile, const wxString& aBasePath )
{
return load( aModelFile );
return load( aModelFile, aBasePath );
}
@ -641,10 +642,10 @@ void S3D_CACHE::ClosePlugins()
}
S3DMODEL* S3D_CACHE::GetModel( const wxString& aModelFileName )
S3DMODEL* S3D_CACHE::GetModel( const wxString& aModelFileName, const wxString& aBasePath )
{
S3D_CACHE_ENTRY* cp = nullptr;
SCENEGRAPH* sp = load( aModelFileName, &cp );
SCENEGRAPH* sp = load( aModelFileName, aBasePath,&cp );
if( !sp )
return nullptr;

View File

@ -92,9 +92,10 @@ public:
*
* @param aModelFile is the partial or full path to the model to be loaded.
* @param aBasePath is the path to search for any relative files
* @return true if the model was successfully loaded, otherwise false.
*/
SCENEGRAPH* Load( const wxString& aModelFile );
SCENEGRAPH* Load( const wxString& aModelFile, const wxString& aBasePath );
FILENAME_RESOLVER* GetResolver() noexcept;
@ -124,7 +125,7 @@ public:
* @param aModelFileName is the full path to the model to be loaded.
* @return is a pointer to the render data or NULL if not available.
*/
S3DMODEL* GetModel( const wxString& aModelFileName );
S3DMODEL* GetModel( const wxString& aModelFileName, const wxString& aBasePath );
/**
* Delete up old cache files in cache directory.
@ -164,7 +165,7 @@ private:
bool saveCacheData( S3D_CACHE_ENTRY* aCacheItem );
// the real load function (can supply a cache entry pointer to member functions)
SCENEGRAPH* load( const wxString& aModelFile, S3D_CACHE_ENTRY** aCachePtr = nullptr );
SCENEGRAPH* load( const wxString& aModelFile, const wxString& aBasePath, S3D_CACHE_ENTRY** aCachePtr = nullptr );
/// cache entries
std::list< S3D_CACHE_ENTRY* > m_CacheList;

View File

@ -156,7 +156,7 @@ void EDA_3D_MODEL_VIEWER::Set3DModel( const wxString& aModelPathName)
if( m_cacheManager )
{
const S3DMODEL* model = m_cacheManager->GetModel( aModelPathName );
const S3DMODEL* model = m_cacheManager->GetModel( aModelPathName, wxEmptyString );
if( model )
Set3DModel( (const S3DMODEL &)*model );

View File

@ -30,6 +30,7 @@
#include <trigo.h>
#include <project.h>
#include <profile.h> // To use GetRunningMicroSecs or another profiling utility
#include <fp_lib_table.h>
#include <eda_3d_canvas.h>
#include <eda_3d_viewer_frame.h>
@ -922,6 +923,19 @@ void RENDER_3D_OPENGL::load3dModels( REPORTER* aStatusReporter )
// Go for all footprints
for( const FOOTPRINT* footprint : m_boardAdapter.GetBoard()->Footprints() )
{
wxString libraryName = footprint->GetFPID().GetLibNickname();
wxString footprintBasePath = wxEmptyString;
if( m_boardAdapter.GetBoard()->GetProject() )
{
const FP_LIB_TABLE_ROW* fpRow =
m_boardAdapter.GetBoard()->GetProject()->PcbFootprintLibs()->FindRow(
libraryName, false );
if( fpRow )
footprintBasePath = fpRow->GetFullURI( true );
}
for( const FP_3DMODEL& fp_model : footprint->Models() )
{
if( fp_model.m_Show && !fp_model.m_Filename.empty() )
@ -941,7 +955,7 @@ void RENDER_3D_OPENGL::load3dModels( REPORTER* aStatusReporter )
{
// It is not present, try get it from cache
const S3DMODEL* modelPtr =
m_boardAdapter.Get3dCacheManager()->GetModel( fp_model.m_Filename );
m_boardAdapter.Get3dCacheManager()->GetModel( fp_model.m_Filename, footprintBasePath );
// only add it if the return is not NULL
if( modelPtr )

View File

@ -39,6 +39,8 @@
#include <board.h>
#include <footprint.h>
#include <fp_lib_table.h>
#include <eda_3d_viewer_frame.h>
#include <base_units.h>
#include <profile.h> // To use GetRunningMicroSecs or another profiling utility
@ -1251,13 +1253,27 @@ void RENDER_3D_RAYTRACE::load3DModels( CONTAINER_3D& aDstContainer, bool aSkipMa
auto sM = fp->Models().begin();
auto eM = fp->Models().end();
wxString libraryName = fp->GetFPID().GetLibNickname();
wxString footprintBasePath = wxEmptyString;
if( m_boardAdapter.GetBoard()->GetProject() )
{
const FP_LIB_TABLE_ROW* fpRow =
m_boardAdapter.GetBoard()->GetProject()->PcbFootprintLibs()->FindRow(
libraryName, false );
if( fpRow )
footprintBasePath = fpRow->GetFullURI( true );
}
while( sM != eM )
{
if( ( static_cast<float>( sM->m_Opacity ) > FLT_EPSILON )
&& ( sM->m_Show && !sM->m_Filename.empty() ) )
{
// get it from cache
const S3DMODEL* modelPtr = cacheMgr->GetModel( sM->m_Filename );
const S3DMODEL* modelPtr =
cacheMgr->GetModel( sM->m_Filename, footprintBasePath );
// only add it if the return is not NULL.
if( modelPtr )

View File

@ -54,6 +54,7 @@ PANEL_PREVIEW_3D_MODEL::PANEL_PREVIEW_3D_MODEL( wxWindow* aParent, PCB_BASE_FRAM
m_userUnits = aFrame->GetUserUnits();
m_dummyBoard = new BOARD();
m_dummyBoard->SetProject( &aFrame->Prj() );
// This board will only be used to hold a footprint for viewing
m_dummyBoard->SetBoardUse( BOARD_USE::FPHOLDER );

View File

@ -240,7 +240,7 @@ bool FILENAME_RESOLVER::UpdatePathList( const std::vector< SEARCH_PATH >& aPathL
}
wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName, const wxString& aWorkingPath )
{
std::lock_guard<std::mutex> lock( mutex_resolver );
@ -324,6 +324,21 @@ wxString FILENAME_RESOLVER::ResolvePath( const wxString& aFileName )
}
// check path relative to search path
if( !aWorkingPath.IsEmpty() && !tname.StartsWith( ":" ) )
{
wxString tmp = aWorkingPath;
tmp.Append( tmpFN.GetPathSeparator() );
tmp.Append( tname );
tmpFN.Assign( tmp );
if( tmpFN.MakeAbsolute() && tmpFN.FileExists() )
{
tname = tmpFN.GetFullPath();
return tname;
}
}
// check the partial path relative to ${KICAD6_3DMODEL_DIR} (legacy behavior)
if( !tname.StartsWith( ":" ) )
{

View File

@ -101,8 +101,11 @@ public:
* 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 aResolvedName if the URI is valid.
*
* @param aFileName The configured file path to resolve
* @param aWorkingPath The current working path for relative path resolutions
*/
wxString ResolvePath( const wxString& aFileName );
wxString ResolvePath( const wxString& aFileName, const wxString& aWorkingPath );
/**
* Produce a relative path based on the existing search directories or returns the same path

View File

@ -32,6 +32,7 @@
#include <widgets/grid_text_button_helpers.h>
#include <widgets/wx_grid.h>
#include <footprint.h>
#include <fp_lib_table.h>
#include <footprint_edit_frame.h>
#include <footprint_editor_settings.h>
#include <dialog_footprint_properties_fp_editor.h>
@ -427,7 +428,15 @@ MODEL_VALIDATE_ERRORS PANEL_FP_PROPERTIES_3D_MODEL::validateModelExists( const w
if( !resolv->ValidateFileName( aFilename, hasAlias ) )
return MODEL_VALIDATE_ERRORS::ILLEGAL_FILENAME;
wxString fullPath = resolv->ResolvePath( aFilename );
wxString libraryName = m_footprint->GetFPID().GetLibNickname();
const FP_LIB_TABLE_ROW* fpRow =
m_frame->Prj().PcbFootprintLibs()->FindRow( libraryName, false );
wxString footprintBasePath = wxEmptyString;
if( fpRow )
footprintBasePath = fpRow->GetFullURI( true );
wxString fullPath = resolv->ResolvePath( aFilename, footprintBasePath );
if( fullPath.IsEmpty() )
return MODEL_VALIDATE_ERRORS::RESOLVE_FAIL;

View File

@ -411,7 +411,7 @@ static void idf_export_footprint( BOARD* aPcb, FOOTPRINT* aFootprint, IDF3_BOARD
continue;
}
idfFile.Assign( resolver->ResolvePath( sM->m_Filename ) );
idfFile.Assign( resolver->ResolvePath( sM->m_Filename, wxEmptyString ) );
idfExt = idfFile.GetExt();
if( idfExt.Cmp( wxT( "idf" ) ) && idfExt.Cmp( wxT( "IDF" ) ) )

View File

@ -1013,7 +1013,7 @@ void EXPORTER_PCB_VRML::ExportVrmlFootprint( FOOTPRINT* aFootprint, std::ostream
continue;
}
SGNODE* mod3d = (SGNODE*) m_Cache3Dmodels->Load( sM->m_Filename );
SGNODE* mod3d = (SGNODE*) m_Cache3Dmodels->Load( sM->m_Filename, wxEmptyString );
if( nullptr == mod3d )
{
@ -1078,7 +1078,8 @@ void EXPORTER_PCB_VRML::ExportVrmlFootprint( FOOTPRINT* aFootprint, std::ostream
int old_precision = aOutputFile->precision();
aOutputFile->precision( m_precision );
wxFileName srcFile = m_Cache3Dmodels->GetResolver()->ResolvePath( sM->m_Filename );
wxFileName srcFile =
m_Cache3Dmodels->GetResolver()->ResolvePath( sM->m_Filename, wxEmptyString );
wxFileName dstFile;
dstFile.SetPath( m_Subdir3DFpModels );
dstFile.SetName( srcFile.GetName() );