/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "NwRecapModuleImpl.h" #include "RcsFileServices/RxRcsFileServices.h" #include "DynamicLinker.h" #include "RxObjectImpl.h" #include "RxDynamicModule.h" #include "NwGeometryExternal.h" #include "CommonSchema/NwSchema.h" #include "CommonSchema/NwSchemaInt32Field.h" #include "CommonSchema/NwSchemaGuidField.h" #include "NwPathUtils.h" #include "RcsFileServices/OdPointCloudScanDatabase.h" #include "RcsFileServices/OdPointCloudProjectDatabase.h" #include "RcsFileServices/OdRcsDataManager.h" #include "NwDatabase.h" #include "NwDBExternalGeometryPE.h" #include "NwGeometryExternalPE.h" ODRX_NO_CONS_DEFINE_MEMBERS(OdNwPointCloud, OdRxObject); ODRX_NO_CONS_DEFINE_MEMBERS(OdNwPointCloudImpl, OdNwPointCloud); OdNwPointCloudImpl::OdNwPointCloudImpl() : m_scanStorage(m_streamMap, m_findReferenceCallback) { } OdNwPointCloudImpl::~OdNwPointCloudImpl() { } void OdNwPointCloudImpl::setFindReferenceCallback(std::function findReferenceCallback) { m_findReferenceCallback = findReferenceCallback; } void OdNwPointCloudImpl::setStreamMap(const std::map& streamMap) { ODA_ASSERT_ONCE(!OD_T("The method is deprecated since release/25.9.Use method setFindReferenceCallback with 'lazy' map initialization instead.")); m_streamMap = streamMap; } bool OdNwPointCloudImpl::isStreamMapEmpty() { ODA_ASSERT_ONCE(!OD_T("The method is deprecated since release/25.9.Use method setFindReferenceCallback with 'lazy' map initialization instead.")); return m_streamMap.size() == 0; } void OdNwPointCloudImpl::setRcsService(OdRxRcsFileServicesPtr pRcsSrv) { m_pRcsFileSrv = pRcsSrv; } OdStreamBufPtr OdNwPointCloudImpl::getEmbeddedStreamBuffer(const OdString& refName, const std::function& findReferenceCallback, bool /*create*/) { auto sIt = m_streamMap.find(refName); OdStreamBufPtr pEmbStrmBuf; if (sIt != m_streamMap.end()) { pEmbStrmBuf = sIt->second; } else { if (findReferenceCallback) { OdString pathTo = refName; if (findReferenceCallback(pathTo, pEmbStrmBuf)) { if (pEmbStrmBuf.isNull()) { pEmbStrmBuf = odrxSystemServices()->createFile(pathTo, Oda::FileAccessMode::kFileRead, Oda::FileShareMode::kShareDenyNo, Oda::FileCreationDisposition::kOpenExisting); } if (pEmbStrmBuf) { m_streamMap.insert({ refName, pEmbStrmBuf }); } } } } return pEmbStrmBuf; } OdResult OdNwPointCloudImpl::fillPointCloudScanDBMap(const OdString& refName) { StrToGuidPtCldScDbType::iterator pcdbIt; pcdbIt = m_pcdbDict.find(refName); if (pcdbIt == m_pcdbDict.end()) { OdStreamBufPtr pEmbStrmBuf = getEmbeddedStreamBuffer(refName, m_findReferenceCallback, true); OdRcsDataManagerPtr pRcsDataManager; if (refName.right(4).iCompare(OD_T(".rcp")) == 0) { OdPointCloudProjectDatabasePtr pPrjDb = m_pRcsFileSrv->readRcpFile(pEmbStrmBuf, &m_scanStorage); if (pPrjDb.isNull()) { return eNotApplicable; } [[maybe_unused]]OdUInt32 allScanCnt = pPrjDb->getTotalScansCount(); GuidToPointCloudScanDBMapType guidPcdbMap; OdPointCloudScanIteratorPtr pScanIt = pPrjDb->getScanIterator(); for (; !pScanIt->done(); pScanIt->step()) { OdPointCloudScanDatabasePtr pScanDb = pScanIt->getScanDb(); if (pScanDb.isNull()) { return eFileNotFound; } OdString scnIdStr = pScanDb->getScanId(); scnIdStr.remove('_'); OdGUID itScnGuid(scnIdStr); guidPcdbMap[itScnGuid] = OdNwPointCloudData{ pScanDb, pPrjDb, m_pRcsFileSrv->getRcsDataManager(pScanDb, pPrjDb)}; } m_pcdbDict.insert(std::make_pair(refName, guidPcdbMap)); } else if(refName.right(4).iCompare(OD_T(".rcs")) == 0) { GuidToPointCloudScanDBMapType guidPcdbMap; OdPointCloudScanDatabasePtr pPtCldScndb = m_pRcsFileSrv->readRcsFile(pEmbStrmBuf); if (!pPtCldScndb.isNull()) { OdString scanGuid = pPtCldScndb->getScanId(); scanGuid.replace(L"_", L"-"); guidPcdbMap[OdGUID(scanGuid)] = OdNwPointCloudData{ pPtCldScndb, nullptr, m_pRcsFileSrv->getRcsDataManager(pPtCldScndb, nullptr) }; m_pcdbDict[refName] = guidPcdbMap; } } } return eOk; } OdResult OdNwPointCloudImpl::getPointCloud(const OdString& refName, const OdGUID& scanGuid, OdUInt64 voxIdx, OdGePoint3dArray& coords, OdCmEntityColorArray& colors) { if (refName.isEmpty()) { return eInvalidInput; } if (m_pRcsFileSrv.isNull()) { return eNullPtr; } StrToGuidPtCldScDbType::iterator pcdbIt; pcdbIt = m_pcdbDict.find(refName); OdResult r = fillPointCloudScanDBMap(refName); if (r != eOk) { return r; } auto pcdDictIt = m_pcdbDict.find(refName); if (pcdDictIt == m_pcdbDict.end()) { return eNotAnEntity; } auto pcdDictScanIt = pcdDictIt->second.find(scanGuid); if (pcdDictScanIt == pcdDictIt->second.end()) { return eNotAnEntity; } OdPointCloudScanDatabasePtr pScanDb = pcdDictScanIt->second.pScanDb; OdUInt64 amountVoxels = pScanDb->getAmountOfVoxels(); if (amountVoxels == 0) { return eEndOfObject; } OdRcsVoxelIteratorPtr pVIt = pScanDb->getVoxelIterator(); if (voxIdx > amountVoxels - 1) { return eInvalidIndex; } pVIt->start(); for (OdUInt64 i = 0; i < voxIdx && !pVIt->done(); i++) { pVIt->step(); } OdRcsVoxelPtr pVox = pVIt->getVoxel(); pVIt->done(); OdGeExtents3d voxelExtents = pVox->getExtents(); OdUInt32 numPoints = pVox->getTotalNumberOfPoints(); OdRcsPointDataIteratorPtr pPointDataIt = pVox->getPointDataIterator(); [[maybe_unused]] OdUInt32 getPointAmount = pPointDataIt->getPoints(coords, colors, numPoints); return eOk; } OdResult OdNwPointCloudImpl::getPointCloud(const OdString& refName, OdGePoint3dArray& coords, OdCmEntityColorArray& colors) { if (refName.isEmpty()) { return eInvalidInput; } if (m_pRcsFileSrv.isNull()) { return eNullPtr; } OdResult r = fillPointCloudScanDBMap(refName); if (r != eOk) { return r; } for (StrToGuidPtCldScDbType::iterator pcdbDictIt = m_pcdbDict.begin(); pcdbDictIt != m_pcdbDict.end(); ++pcdbDictIt) { for (GuidToPointCloudScanDBMapType::iterator guidPcdDbDictIt = pcdbDictIt->second.begin(); guidPcdDbDictIt != pcdbDictIt->second.end(); ++guidPcdDbDictIt) { [[maybe_unused]] OdUInt64 totalVoxels = guidPcdDbDictIt->second.pScanDb->getAmountOfVoxels(); OdRcsVoxelIteratorPtr pVIt = guidPcdDbDictIt->second.pScanDb->getVoxelIterator(); pVIt->start(); while (!pVIt->done()) { OdRcsVoxelPtr pVox = pVIt->getVoxel(); OdGeExtents3d voxelExtents = pVox->getExtents(); OdGePoint3d minPoint = voxelExtents.minPoint(); OdUInt32 numPoints = pVox->getTotalNumberOfPoints(); OdGePoint3dArray coordsPerVoxel; OdCmEntityColorArray colorsPerVoxel; OdRcsPointDataIteratorPtr pPointDataIt = pVox->getPointDataIterator(); [[maybe_unused]] OdUInt32 getPointAmount = pPointDataIt->getPoints(coordsPerVoxel, colorsPerVoxel, numPoints); for (auto & p : coordsPerVoxel) { p = (p.asVector() + minPoint.asVector()).asPoint(); } [[maybe_unused]] unsigned int startinsert = coords.length(); coords.insertMove(coords.end(), coordsPerVoxel.begin(), coordsPerVoxel.end()); colors.insertMove(colors.end(), colorsPerVoxel.begin(), colorsPerVoxel.end()); pVIt->step(); } } } return eOk; } OdResult OdNwPointCloudImpl::getPointCloud(const OdString& refName, const OdGUID& scanGuid, OdPointCloudScanDatabasePtr& pScanDb, OdPointCloudProjectDatabasePtr& pProjDb) { OdNwPointCloudData pcData; OdResult result = getPointCloudInt(refName, scanGuid, pcData); pScanDb = pcData.pScanDb; pProjDb = pcData.pProjDb; return result; } OdResult OdNwPointCloudImpl::getPointCloudInt(const OdString& refName, const OdGUID& scanGuid, OdNwPointCloudData& pcData) { OdResult r = fillPointCloudScanDBMap(refName); if (r != eOk) { return r; } OdString head, tail; NwPathUtils::splitExt(refName, head, tail); // first is key denoting rcs/rcp resource (file) by its own path // second is a map of GUID and pointer to rcp/rcs internal representation (PointCloud project) StrToGuidPtCldScDbType::iterator pcdbIt = m_pcdbDict.find(refName); if (pcdbIt != m_pcdbDict.end() && !pcdbIt->second.empty()) { // map confronting guid than referer to part of project with rcs/rcp internal object pointer GuidToPointCloudScanDBMapType mapGuidToPtClObj = pcdbIt->second; auto fillDbData = [&pcData](GuidToPointCloudScanDBMapType::iterator it) { pcData = it->second; }; if (tail.makeLower() == L".rcp") { if (scanGuid == OdGUID::kNull) { // if GUID isn't specified (Inventor case) let's take first element, even if scanned map contains more fillDbData(mapGuidToPtClObj.begin()); return eOk; } // try to find guid // second element is pair GuidToPointCloudScanDBMapType::iterator pcdatIt = mapGuidToPtClObj.find(scanGuid); if (pcdatIt != mapGuidToPtClObj.end()) { fillDbData(pcdatIt); return eOk; } } else if (tail.makeLower() == L".rcs") { fillDbData(mapGuidToPtClObj.begin()); return eOk; } } return eUnknownFileType; } OdResult OdNwPointCloudImpl::getPointCloud(const OdString& refName, const OdGUID& scanGuid, OdNwPointCloudData& pcData) { return getPointCloudInt(refName, scanGuid, pcData); } void OdNwPointCloudImpl::resetCache() { m_streamMap.clear(); m_pcdbDict.clear(); } ODRX_DEFINE_DYNAMIC_MODULE(OdNwRecapModuleImpl); void OdNwRecapModuleImpl::initApp() { OdNwPointCloud::rxInit(); OdNwPointCloudImpl::rxInit(); ::odrxDynamicLinker()->loadModule(OdNwDbModuleName); NwRecapAbstractExternalGeometryPE::rxInit(); NwRecapAbstractDBExternalGeometryPE::rxInit(); m_pRcsFileServices = ::odrxDynamicLinker()->loadApp(RX_RCS_FILE_SERVICES); m_pPointCloudImporter = OdRxObjectImpl::createObject(); m_pPointCloudImporter->setRcsService(m_pRcsFileServices); m_pExtGeomPe = NwRecapAbstractExternalGeometryPE::createObject(); auto pRcpAbsDbExtGeomPe = NwRecapAbstractDBExternalGeometryPE::createObject(); OdNwGeometryExternal::desc()->addX(OdNwAbstractExternalGeometryPE::desc(), m_pExtGeomPe); OdNwDatabase::desc()->addX(OdNwAbstractDBExternalGeometryPE::desc(), pRcpAbsDbExtGeomPe); } void OdNwRecapModuleImpl::uninitApp() { OdNwDatabase::desc()->delX(OdNwAbstractDBExternalGeometryPE::desc()); OdNwGeometryExternal::desc()->delX(OdNwAbstractExternalGeometryPE::desc()); m_pExtGeomPe.release(); m_pRcsFileServices.release(); ::odrxDynamicLinker()->unloadModule(RX_RCS_FILE_SERVICES); NwRecapAbstractDBExternalGeometryPE::rxUninit(); NwRecapAbstractExternalGeometryPE::rxUninit(); OdNwPointCloudImpl::rxUninit(); OdNwPointCloud::rxUninit(); } OdNwPointCloudPtr OdNwRecapModuleImpl::getNwPointCloud() { if (!m_pRcsFileServices.isNull()) { if (m_pPointCloudImporter.isNull()) { m_pPointCloudImporter = OdRxObjectImpl::createObject(); } m_pPointCloudImporter->setRcsService(m_pRcsFileServices); return m_pPointCloudImporter; } return OdNwPointCloudPtr(); } OdNwPointCloudProjectScanStorage::OdNwPointCloudProjectScanStorage(StringToStreamType& str2strm, const std::function& findReferenceCallback) : OdPointCloudProjectScanStorage() , m_str2strm(str2strm) , m_findReferenceCallback(findReferenceCallback) { } OdStreamBufPtr OdNwPointCloudProjectScanStorage::getScanStreamByPath(const OdString& path) { StringToStreamType::const_iterator it = m_str2strm.find(path); if (it != m_str2strm.end()) { return it->second; } else { if (m_findReferenceCallback) { OdString sPath = path; OdStreamBufPtr pEmbStrmBuf; if (m_findReferenceCallback(sPath, pEmbStrmBuf)) { if (!pEmbStrmBuf.isNull()) { m_str2strm.insert({ path, pEmbStrmBuf }); } else { pEmbStrmBuf = odrxSystemServices()->createFile(sPath, Oda::FileAccessMode::kFileRead, Oda::FileShareMode::kShareDenyNo, Oda::FileCreationDisposition::kOpenExisting); ODA_ASSERT(!pEmbStrmBuf.isNull()); m_str2strm.insert({ path, pEmbStrmBuf }); } return pEmbStrmBuf; } } } return OdStreamBufPtr(); } OdNwPointCloudProjectScanStorage::~OdNwPointCloudProjectScanStorage() { }