From dd04c9a7938cc21854210617948563dc92b71342 Mon Sep 17 00:00:00 2001 From: kn Date: Wed, 12 Nov 2025 13:05:00 +0100 Subject: [PATCH] Add API method CreateBuildJobFromStorage. Creates a new build job from an existing storage stream --- ACT/LibMCEnv.xml | 6 ++ .../HeadersDev/CppDynamic/libmcenv_dynamic.h | 14 +++ .../CppDynamic/libmcenv_dynamic.hpp | 32 +++++++ Framework/InterfacesCore/libmcenv_abi.hpp | 13 +++ .../InterfacesCore/libmcenv_interfaces.hpp | 8 ++ .../libmcenv_interfacewrapper.cpp | 56 ++++++++++++ .../LibMCEnv/libmcenv_uienvironment.cpp | 90 +++++++++++++++++++ .../LibMCEnv/libmcenv_uienvironment.hpp | 2 + 8 files changed, 221 insertions(+) diff --git a/ACT/LibMCEnv.xml b/ACT/LibMCEnv.xml index 8a34b06b..622bff8d 100644 --- a/ACT/LibMCEnv.xml +++ b/ACT/LibMCEnv.xml @@ -6419,6 +6419,12 @@ + + + + + + diff --git a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h index 4fc7cb6b..b8ac7e41 100644 --- a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h +++ b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.h @@ -11868,6 +11868,19 @@ typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_GetBuildExecutionPtr) (LibMCEnv_ */ typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_GetRecentBuildJobsPtr) (LibMCEnv_UIEnvironment pUIEnvironment, LibMCEnv_uint32 nMaxCount, LibMCEnv_BuildIterator * pBuildIterator); +/** +* Creates a new build job from an existing storage stream. The storage stream must contain a valid 3MF file. +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] pStorageStreamUUID - UUID of the storage stream containing the 3MF file. +* @param[in] pBuildName - Display name for the build job. Must not be empty. +* @param[in] nBuildUUIDBufferSize - size of the buffer (including trailing 0) +* @param[out] pBuildUUIDNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pBuildUUIDBuffer - buffer of UUID of the newly created build job., may be NULL +* @return error code or 0 (success) +*/ +typedef LibMCEnvResult (*PLibMCEnvUIEnvironment_CreateBuildJobFromStoragePtr) (LibMCEnv_UIEnvironment pUIEnvironment, const char * pStorageStreamUUID, const char * pBuildName, const LibMCEnv_uint32 nBuildUUIDBufferSize, LibMCEnv_uint32* pBuildUUIDNeededChars, char * pBuildUUIDBuffer); + /** * Creates an empty discrete field. * @@ -13436,6 +13449,7 @@ typedef struct { PLibMCEnvUIEnvironment_HasBuildExecutionPtr m_UIEnvironment_HasBuildExecution; PLibMCEnvUIEnvironment_GetBuildExecutionPtr m_UIEnvironment_GetBuildExecution; PLibMCEnvUIEnvironment_GetRecentBuildJobsPtr m_UIEnvironment_GetRecentBuildJobs; + PLibMCEnvUIEnvironment_CreateBuildJobFromStoragePtr m_UIEnvironment_CreateBuildJobFromStorage; PLibMCEnvUIEnvironment_CreateDiscreteField2DPtr m_UIEnvironment_CreateDiscreteField2D; PLibMCEnvUIEnvironment_CreateDiscreteField2DFromImagePtr m_UIEnvironment_CreateDiscreteField2DFromImage; PLibMCEnvUIEnvironment_CheckPermissionPtr m_UIEnvironment_CheckPermission; diff --git a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp index d6bd51f0..98398703 100644 --- a/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp +++ b/Framework/HeadersDev/CppDynamic/libmcenv_dynamic.hpp @@ -3819,6 +3819,7 @@ class CUIEnvironment : public CBase { inline bool HasBuildExecution(const std::string & sExecutionUUID); inline PBuildExecution GetBuildExecution(const std::string & sExecutionUUID); inline PBuildIterator GetRecentBuildJobs(const LibMCEnv_uint32 nMaxCount); + inline std::string CreateBuildJobFromStorage(const std::string & sStorageStreamUUID, const std::string & sBuildName); inline PDiscreteFieldData2D CreateDiscreteField2D(const LibMCEnv_uint32 nPixelCountX, const LibMCEnv_uint32 nPixelCountY, const LibMCEnv_double dDPIValueX, const LibMCEnv_double dDPIValueY, const LibMCEnv_double dOriginX, const LibMCEnv_double dOriginY, const LibMCEnv_double dDefaultValue); inline PDiscreteFieldData2D CreateDiscreteField2DFromImage(classParam pImageDataInstance, const LibMCEnv_double dBlackValue, const LibMCEnv_double dWhiteValue, const LibMCEnv_double dOriginX, const LibMCEnv_double dOriginY); inline bool CheckPermission(const std::string & sPermissionIdentifier); @@ -5044,6 +5045,7 @@ class CUIEnvironment : public CBase { pWrapperTable->m_UIEnvironment_HasBuildExecution = nullptr; pWrapperTable->m_UIEnvironment_GetBuildExecution = nullptr; pWrapperTable->m_UIEnvironment_GetRecentBuildJobs = nullptr; + pWrapperTable->m_UIEnvironment_CreateBuildJobFromStorage = nullptr; pWrapperTable->m_UIEnvironment_CreateDiscreteField2D = nullptr; pWrapperTable->m_UIEnvironment_CreateDiscreteField2DFromImage = nullptr; pWrapperTable->m_UIEnvironment_CheckPermission = nullptr; @@ -15065,6 +15067,15 @@ class CUIEnvironment : public CBase { if (pWrapperTable->m_UIEnvironment_GetRecentBuildJobs == nullptr) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + #ifdef _WIN32 + pWrapperTable->m_UIEnvironment_CreateBuildJobFromStorage = (PLibMCEnvUIEnvironment_CreateBuildJobFromStoragePtr) GetProcAddress(hLibrary, "libmcenv_uienvironment_createbuildjobfromstorage"); + #else // _WIN32 + pWrapperTable->m_UIEnvironment_CreateBuildJobFromStorage = (PLibMCEnvUIEnvironment_CreateBuildJobFromStoragePtr) dlsym(hLibrary, "libmcenv_uienvironment_createbuildjobfromstorage"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_UIEnvironment_CreateBuildJobFromStorage == nullptr) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + #ifdef _WIN32 pWrapperTable->m_UIEnvironment_CreateDiscreteField2D = (PLibMCEnvUIEnvironment_CreateDiscreteField2DPtr) GetProcAddress(hLibrary, "libmcenv_uienvironment_creatediscretefield2d"); #else // _WIN32 @@ -19889,6 +19900,10 @@ class CUIEnvironment : public CBase { if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_GetRecentBuildJobs == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_uienvironment_createbuildjobfromstorage", (void**)&(pWrapperTable->m_UIEnvironment_CreateBuildJobFromStorage)); + if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_CreateBuildJobFromStorage == nullptr) ) + return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; + eLookupError = (*pLookup)("libmcenv_uienvironment_creatediscretefield2d", (void**)&(pWrapperTable->m_UIEnvironment_CreateDiscreteField2D)); if ( (eLookupError != 0) || (pWrapperTable->m_UIEnvironment_CreateDiscreteField2D == nullptr) ) return LIBMCENV_ERROR_COULDNOTFINDLIBRARYEXPORT; @@ -35363,6 +35378,23 @@ class CUIEnvironment : public CBase { return std::make_shared(m_pWrapper, hBuildIterator); } + /** + * CUIEnvironment::CreateBuildJobFromStorage - Creates a new build job from an existing storage stream. The storage stream must contain a valid 3MF file. + * @param[in] sStorageStreamUUID - UUID of the storage stream containing the 3MF file. + * @param[in] sBuildName - Display name for the build job. Must not be empty. + * @return UUID of the newly created build job. + */ + std::string CUIEnvironment::CreateBuildJobFromStorage(const std::string & sStorageStreamUUID, const std::string & sBuildName) + { + LibMCEnv_uint32 bytesNeededBuildUUID = 0; + LibMCEnv_uint32 bytesWrittenBuildUUID = 0; + CheckError(m_pWrapper->m_WrapperTable.m_UIEnvironment_CreateBuildJobFromStorage(m_pHandle, sStorageStreamUUID.c_str(), sBuildName.c_str(), 0, &bytesNeededBuildUUID, nullptr)); + std::vector bufferBuildUUID(bytesNeededBuildUUID); + CheckError(m_pWrapper->m_WrapperTable.m_UIEnvironment_CreateBuildJobFromStorage(m_pHandle, sStorageStreamUUID.c_str(), sBuildName.c_str(), bytesNeededBuildUUID, &bytesWrittenBuildUUID, &bufferBuildUUID[0])); + + return std::string(&bufferBuildUUID[0]); + } + /** * CUIEnvironment::CreateDiscreteField2D - Creates an empty discrete field. * @param[in] nPixelCountX - Pixel count in X. MUST be positive. diff --git a/Framework/InterfacesCore/libmcenv_abi.hpp b/Framework/InterfacesCore/libmcenv_abi.hpp index fc711aa4..a0853131 100644 --- a/Framework/InterfacesCore/libmcenv_abi.hpp +++ b/Framework/InterfacesCore/libmcenv_abi.hpp @@ -11881,6 +11881,19 @@ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_getbuildexecution(LibMCE */ LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_getrecentbuildjobs(LibMCEnv_UIEnvironment pUIEnvironment, LibMCEnv_uint32 nMaxCount, LibMCEnv_BuildIterator * pBuildIterator); +/** +* Creates a new build job from an existing storage stream. The storage stream must contain a valid 3MF file. +* +* @param[in] pUIEnvironment - UIEnvironment instance. +* @param[in] pStorageStreamUUID - UUID of the storage stream containing the 3MF file. +* @param[in] pBuildName - Display name for the build job. Must not be empty. +* @param[in] nBuildUUIDBufferSize - size of the buffer (including trailing 0) +* @param[out] pBuildUUIDNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pBuildUUIDBuffer - buffer of UUID of the newly created build job., may be NULL +* @return error code or 0 (success) +*/ +LIBMCENV_DECLSPEC LibMCEnvResult libmcenv_uienvironment_createbuildjobfromstorage(LibMCEnv_UIEnvironment pUIEnvironment, const char * pStorageStreamUUID, const char * pBuildName, const LibMCEnv_uint32 nBuildUUIDBufferSize, LibMCEnv_uint32* pBuildUUIDNeededChars, char * pBuildUUIDBuffer); + /** * Creates an empty discrete field. * diff --git a/Framework/InterfacesCore/libmcenv_interfaces.hpp b/Framework/InterfacesCore/libmcenv_interfaces.hpp index 7a068575..072aca16 100644 --- a/Framework/InterfacesCore/libmcenv_interfaces.hpp +++ b/Framework/InterfacesCore/libmcenv_interfaces.hpp @@ -9062,6 +9062,14 @@ class IUIEnvironment : public virtual IBase { */ virtual IBuildIterator * GetRecentBuildJobs(const LibMCEnv_uint32 nMaxCount) = 0; + /** + * IUIEnvironment::CreateBuildJobFromStorage - Creates a new build job from an existing storage stream. The storage stream must contain a valid 3MF file. + * @param[in] sStorageStreamUUID - UUID of the storage stream containing the 3MF file. + * @param[in] sBuildName - Display name for the build job. Must not be empty. + * @return UUID of the newly created build job. + */ + virtual std::string CreateBuildJobFromStorage(const std::string & sStorageStreamUUID, const std::string & sBuildName) = 0; + /** * IUIEnvironment::CreateDiscreteField2D - Creates an empty discrete field. * @param[in] nPixelCountX - Pixel count in X. MUST be positive. diff --git a/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp b/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp index c276033c..6813b89b 100644 --- a/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp +++ b/Framework/InterfacesCore/libmcenv_interfacewrapper.cpp @@ -35920,6 +35920,60 @@ LibMCEnvResult libmcenv_uienvironment_getrecentbuildjobs(LibMCEnv_UIEnvironment } } +LibMCEnvResult libmcenv_uienvironment_createbuildjobfromstorage(LibMCEnv_UIEnvironment pUIEnvironment, const char * pStorageStreamUUID, const char * pBuildName, const LibMCEnv_uint32 nBuildUUIDBufferSize, LibMCEnv_uint32* pBuildUUIDNeededChars, char * pBuildUUIDBuffer) +{ + IBase* pIBaseClass = (IBase *)pUIEnvironment; + + try { + if (pStorageStreamUUID == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + if (pBuildName == nullptr) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + if ( (!pBuildUUIDBuffer) && !(pBuildUUIDNeededChars) ) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_INVALIDPARAM); + std::string sStorageStreamUUID(pStorageStreamUUID); + std::string sBuildName(pBuildName); + std::string sBuildUUID(""); + IUIEnvironment* pIUIEnvironment = dynamic_cast(pIBaseClass); + if (!pIUIEnvironment) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + + bool isCacheCall = (pBuildUUIDBuffer == nullptr); + if (isCacheCall) { + sBuildUUID = pIUIEnvironment->CreateBuildJobFromStorage(sStorageStreamUUID, sBuildName); + + pIUIEnvironment->_setCache (new ParameterCache_1 (sBuildUUID)); + } + else { + auto cache = dynamic_cast*> (pIUIEnvironment->_getCache ()); + if (cache == nullptr) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDCAST); + cache->retrieveData (sBuildUUID); + pIUIEnvironment->_setCache (nullptr); + } + + if (pBuildUUIDNeededChars) + *pBuildUUIDNeededChars = (LibMCEnv_uint32) (sBuildUUID.size()+1); + if (pBuildUUIDBuffer) { + if (sBuildUUID.size() >= nBuildUUIDBufferSize) + throw ELibMCEnvInterfaceException (LIBMCENV_ERROR_BUFFERTOOSMALL); + for (size_t iBuildUUID = 0; iBuildUUID < sBuildUUID.size(); iBuildUUID++) + pBuildUUIDBuffer[iBuildUUID] = sBuildUUID[iBuildUUID]; + pBuildUUIDBuffer[sBuildUUID.size()] = 0; + } + return LIBMCENV_SUCCESS; + } + catch (ELibMCEnvInterfaceException & Exception) { + return handleLibMCEnvException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + LibMCEnvResult libmcenv_uienvironment_creatediscretefield2d(LibMCEnv_UIEnvironment pUIEnvironment, LibMCEnv_uint32 nPixelCountX, LibMCEnv_uint32 nPixelCountY, LibMCEnv_double dDPIValueX, LibMCEnv_double dDPIValueY, LibMCEnv_double dOriginX, LibMCEnv_double dOriginY, LibMCEnv_double dDefaultValue, LibMCEnv_DiscreteFieldData2D * pFieldDataInstance) { IBase* pIBaseClass = (IBase *)pUIEnvironment; @@ -39392,6 +39446,8 @@ LibMCEnvResult LibMCEnv::Impl::LibMCEnv_GetProcAddress (const char * pProcName, *ppProcAddress = (void*) &libmcenv_uienvironment_getbuildexecution; if (sProcName == "libmcenv_uienvironment_getrecentbuildjobs") *ppProcAddress = (void*) &libmcenv_uienvironment_getrecentbuildjobs; + if (sProcName == "libmcenv_uienvironment_createbuildjobfromstorage") + *ppProcAddress = (void*) &libmcenv_uienvironment_createbuildjobfromstorage; if (sProcName == "libmcenv_uienvironment_creatediscretefield2d") *ppProcAddress = (void*) &libmcenv_uienvironment_creatediscretefield2d; if (sProcName == "libmcenv_uienvironment_creatediscretefield2dfromimage") diff --git a/Implementation/LibMCEnv/libmcenv_uienvironment.cpp b/Implementation/LibMCEnv/libmcenv_uienvironment.cpp index 67e45b03..67b5915a 100644 --- a/Implementation/LibMCEnv/libmcenv_uienvironment.cpp +++ b/Implementation/LibMCEnv/libmcenv_uienvironment.cpp @@ -849,6 +849,96 @@ IBuildIterator* CUIEnvironment::GetRecentBuildJobs(const LibMCEnv_uint32 nMaxCou return pResultIterator.release(); } +std::string CUIEnvironment::CreateBuildJobFromStorage(const std::string& sStorageStreamUUID, const std::string& sBuildName) +{ + // Validate inputs + std::string sNormalizedStorageUUID = AMCCommon::CUtils::normalizeUUIDString(sStorageStreamUUID); + + if (sBuildName.empty()) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDPARAM, "build name must not be empty"); + + // Get services + auto pDataModel = m_pUISystemState->getDataModel(); + auto pStorage = pDataModel->CreateStorage(); + auto pGlobalChrono = m_pUISystemState->getGlobalChronoInstance(); + + // Verify stream exists and is 3MF + if (!pStorage->StreamIsReady(sNormalizedStorageUUID)) + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDPARAM, "storage stream does not exist: " + sNormalizedStorageUUID); + + auto pStream = pStorage->RetrieveStream(sNormalizedStorageUUID); + if (pStream->GetMIMEType() != "application/3mf") + throw ELibMCEnvInterfaceException(LIBMCENV_ERROR_INVALIDPARAM, "storage stream is not a 3MF file (MIME type: " + pStream->GetMIMEType() + ")"); + + // Create build job + std::string sBuildUUID = AMCCommon::CUtils::createUUID(); + auto pBuildJobHandler = pDataModel->CreateBuildJobHandler(); + pBuildJobHandler->CreateJob( + sBuildUUID, + sBuildName, + m_pAPIAuth->getUserUUID(), + sNormalizedStorageUUID, + pGlobalChrono->getUTCTimeStampInMicrosecondsSince1970() + ); + + // Validate and extract metadata + auto pBuildJob = pBuildJobHandler->RetrieveJob(sBuildUUID); + auto pToolpathHandler = m_pUISystemState->getToolpathHandler(); + + pBuildJob->StartValidating(); + + std::set attachmentRelationsToRead; + AMC::CToolpathEntity toolpathEntity( + pDataModel, + sNormalizedStorageUUID, + pToolpathHandler->getLib3MFWrapper(), + sBuildName, + true, + attachmentRelationsToRead + ); + + pBuildJob->FinishValidating(toolpathEntity.getLayerCount()); + + // Add toolpath data + pBuildJob->AddJobData( + pStream->GetContextIdentifier(), + pStream->GetName(), + pStream, + LibMCData::eCustomDataType::Toolpath, + m_pAPIAuth->getUserUUID(), + pGlobalChrono->getUTCTimeStampInMicrosecondsSince1970() + ); + + // Extract and add thumbnail if present + std::vector thumbNailBuffer; + std::string thumbNailMimeType; + if (toolpathEntity.readThumbnail(thumbNailBuffer, thumbNailMimeType)) { + std::string sThumbnailUUID = AMCCommon::CUtils::createUUID(); + pStorage->StoreNewStream( + sThumbnailUUID, + "thumbnail", + thumbNailMimeType, + thumbNailBuffer, + m_pAPIAuth->getUserUUID(), + pGlobalChrono->getUTCTimeStampInMicrosecondsSince1970() + ); + auto pThumbnailStream = pStorage->RetrieveStream(sThumbnailUUID); + + pBuildJob->AddJobData( + "thumbnail", + "thumbnail", + pThumbnailStream, + LibMCData::eCustomDataType::Thumbnail, + m_pAPIAuth->getUserUUID(), + pGlobalChrono->getUTCTimeStampInMicrosecondsSince1970() + ); + + pBuildJob->SetThumbnailStreamUUID(sThumbnailUUID); + } + + return sBuildUUID; +} + IDiscreteFieldData2D* CUIEnvironment::CreateDiscreteField2D(const LibMCEnv_uint32 nPixelSizeX, const LibMCEnv_uint32 nPixelSizeY, const LibMCEnv_double dDPIValueX, const LibMCEnv_double dDPIValueY, const LibMCEnv_double dOriginX, const LibMCEnv_double dOriginY, const LibMCEnv_double dDefaultValue) { diff --git a/Implementation/LibMCEnv/libmcenv_uienvironment.hpp b/Implementation/LibMCEnv/libmcenv_uienvironment.hpp index 42218821..f2aed315 100644 --- a/Implementation/LibMCEnv/libmcenv_uienvironment.hpp +++ b/Implementation/LibMCEnv/libmcenv_uienvironment.hpp @@ -238,6 +238,8 @@ class CUIEnvironment : public virtual IUIEnvironment, public virtual CBase { IBuildIterator* GetRecentBuildJobs(const LibMCEnv_uint32 nMaxCount) override; + std::string CreateBuildJobFromStorage(const std::string& sStorageStreamUUID, const std::string& sBuildName) override; + IDiscreteFieldData2D* CreateDiscreteField2D(const LibMCEnv_uint32 nPixelSizeX, const LibMCEnv_uint32 nPixelSizeY, const LibMCEnv_double dDPIValueX, const LibMCEnv_double dDPIValueY, const LibMCEnv_double dOriginX, const LibMCEnv_double dOriginY, const LibMCEnv_double dDefaultValue) override; IDiscreteFieldData2D* CreateDiscreteField2DFromImage(IImageData* pImageDataInstance, const LibMCEnv_double dBlackValue, const LibMCEnv_double dWhiteValue, const LibMCEnv_double dOriginX, const LibMCEnv_double dOriginY) override;