/////////////////////////////////////////////////////////////////////////////// // 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 "NwGeometryImport.h" //kernel #include "OdPerfTimer.h" #include "DynamicLinker.h" #include "RxRasterServices.h" #include "Gi/GiRasterImage.h" //tv #include "TvTraitsDef.h" #include "TvInsert.h" #include "TvSubGroupData.h" #include "TvGroup.h" //nw #include "NwPartition.h" #include "NwComponent.h" #include "NwFragment.h" #include "NwColor.h" #include "NwUnitUtils.h" //nw attributes #include "NwCategoryConversionType.h" #include "Attribute/NwTransRotationAttribute.h" #include "Attribute/NwTransAttribute.h" #include "Attribute/NwTransformAttribute.h" #include "Attribute/NwMaterialAttribute.h" #include "Attribute/NwGraphicMaterialAttribute.h" //nw geometry #include "NwGeometryCircle.h" #include "NwGeometryLineSet.h" #include "NwGeometryShell.h" #include "NwGeometryPointSet.h" #include "NwGeometryText.h" #include "NwGeometryCylinder.h" #include "NwGeometryExternal.h" #include "NwGeometryExternalPE.h" #include "NwVerticesData.h" #include "NwTextStyle.h" //nw plot #include "Plot/NwPlotEnums.h" #include "Plot/NwPlotStroke.h" #include "Plot/NwPlotSolidColorBrush.h" #include "Plot/NwPlotCoreShapePathFigure.h" #include "Plot/NwPlotCoreShapeText.h" #include "Plot/NwPlotAppearance.h" #include "Plot/NwPlotPathFigureAppearance.h" #include "Plot/NwPlotTextAppearance.h" #include "Plot/NwPlotPathStyle.h" #include "Plot/NwPlotCanvasStyle.h" #include "Plot/NwPlotViewportStyle.h" #include "Plot/NwPlotPathFigure.h" #include "Plot/NwPlotPathFigureStyle.h" #include "Plot/Segments/NwPlotSegment.h" #include "Plot/Segments/NwPlotPointListSegment.h" #include "Plot/Segments/NwPlotPolyLineSegment.h" #include "Plot/Segments/NwPlotArcSegment.h" #include "Plot/Segments/NwPlotCircleSegment.h" #include "Plot/Segments/NwPlotEllipseSegment.h" #include "Plot/Segments/NwPlotPolyTriangle.h" #include "Plot/NwPlotCoreShapeText.h" #include "Plot/NwPlotTextLine.h" #include "Plot/NwPlotTextStyle.h" #include "Plot/NwPlotFontStyle.h" #include "Plot/NwPlotImageBrush.h" #include "Plot/NwPlotImageHeader.h" #if defined(NWRECAPIMPORT_ENABLED) #include "NwRecapModule.h" #endif //#define NW_DRAW_MESH_AS_POINTSET #define START_TV_NW_TIMER \ if (m_pTvTimer) \ m_pTvTimer->start(); #define END_TV_NW_TIMER \ if (m_pTvTimer) \ { \ m_nTotalTvTime += m_pTvTimer->permanentSec(); \ m_pTvTimer->stop(); \ } #include "NwGeometryImport.hpp" typedef std::map mapNwObjectId2EntityIdType; static void addBoundingBoxVisualization(OdTvEntityPtr entity, const OdGeExtents3d& bbox, const OdTvColorDef& color, OdGeMatrix3d trf = OdGeMatrix3d::kIdentity) { entity->setColor(color); const OdGePoint3d& minP = bbox.minPoint(); const OdGePoint3d& maxP = bbox.maxPoint(); OdTvPoint points_top[4] = { {minP.x, maxP.y, maxP.z}, {minP.x, minP.y, maxP.z}, {maxP.x, minP.y, maxP.z}, {maxP.x, maxP.y, maxP.z} }; OdTvPoint points_bottom[4] = { {maxP.x, minP.y, minP.z}, {maxP.x, maxP.y, minP.z}, {minP.x, maxP.y, minP.z}, {minP.x, minP.y, minP.z} }; OdTvPoint points_right[4] = { {minP.x, minP.y, maxP.z}, {minP.x, minP.y, minP.z}, {maxP.x, minP.y, minP.z}, {maxP.x, minP.y, maxP.z} }; OdTvPoint points_left[4] = { {maxP.x, maxP.y, minP.z}, {maxP.x, maxP.y, maxP.z}, {minP.x, maxP.y, maxP.z}, {minP.x, maxP.y, minP.z} }; entity->appendPolyline(4, points_top); entity->appendPolyline(4, points_bottom); entity->appendPolyline(4, points_right); entity->appendPolyline(4, points_left); if (trf != OdGeMatrix3d::kIdentity) entity->setModelingMatrix(trf); } static bool isModelItemClipped(const OdNwModelItemPtr& item, const OdGeMatrix3d& clipMatr) { OdGeExtents3d bbox = item->getBoundingBox(); OdGeMatrix3d invertMatrix = clipMatr; bbox.transformBy(invertMatrix.invert()); static const OdGeExtents3d clipbox( OdGePoint3d(-0.5, -0.5, -0.5), OdGePoint3d(0.5, 0.5, 0.5)); return bbox.intersectWith(clipbox) == OdGeExtents3d::kIntersectNot; } static OdNwModelItemPtr findTheFirstNonInsertNode(const OdNwModelItemPtr pModelItem) { OdNwModelItemPtr result; auto type = pModelItem->getIcon(); if (type != NwModelItemIcon::INSERT_GROUP && type != NwModelItemIcon::INSERT_GEOMETRY) { return pModelItem; } else { OdNwObjectIdArray aChildren; if (pModelItem->getChildren(aChildren) == eOk) { for (auto& chId : aChildren) { auto newModelItem = chId.openObject(NwOpenMode::kForRead); OdNwModelItemPtr result = findTheFirstNonInsertNode(newModelItem); if (result.isNull()) continue; return result; } } } return result; } //VAS: helper function for creating tv object with unique name(layers, blocks, materials, backgrounds) //T - return type of tv object id //pFindFunc - pointer to method fo finding tv object id from tv database //pFindFunc - pointer to method fo creating tv object id from tv database //pHelpMapWithNextNameIdx - pointer to map with help info like: by name object as key is possible to know next index for objects with same original name template inline T createTvDbUniqueObject(OdTvDatabasePtr pTvDb, const OdString& nwObjName, std::map* pHelpMapWithNextNameIdx = nullptr) { //VAS: check if tv database already has unique object with such name //VAS: for some unknown reasons constructions as 'pTvDb->*pFindFunc' with calling of pointer to function is not work, then we call operator -> directly from pTvDb object auto creatTvObj = [&pTvDb, &pHelpMapWithNextNameIdx](const OdString& nwObjName, OdTvResult* tvRes) { auto tvObjId = (pTvDb.operator->()->*pCreateFunc)(nwObjName, tvRes); if (tvRes && *tvRes == tvInvalidName) { //it's forrbiden to create tv unique objects(layers, blocks, materials, backgrounds and etc.) with inadmissible control letters, so for correct export need to remove those characters from name auto nwNewObjName = nwObjName; for (auto ch : { '<', '>', '\\', '/', ':', ';', '?', ',', '*', '|', '=', '\'', ' ', '\"' }) nwNewObjName.remove(ch); if (nwNewObjName.isEmpty()) nwNewObjName = OD_T("emptyName"); tvObjId = createTvDbUniqueObject(pTvDb, nwNewObjName); } else if (tvRes && *tvRes == tvForbiddenName)//tv database can't contain unique object with name "0" tvObjId = createTvDbUniqueObject(pTvDb, OD_T("0_"), pHelpMapWithNextNameIdx); return tvObjId; }; OdTvResult tvRes; auto tvObjId = creatTvObj(nwObjName, &tvRes); if(tvRes == tvAlreadyExistSameName) { tvRes = tvOk; tvObjId = (pTvDb.operator->()->*pFindFunc)(nwObjName, nullptr); //VAS: if tv database already has object with such name - try to find new name for object with adding integer number OdUInt32 nameIdx = 2; if (pHelpMapWithNextNameIdx) { //VASL for good import time there is good to remember last index for equal block name auto itFnd = pHelpMapWithNextNameIdx->find(nwObjName); if (itFnd != pHelpMapWithNextNameIdx->end()) { nameIdx = itFnd->second; } } for (;; ++nameIdx) { OdString sTempName = nwObjName + OdString().format(OD_T("_%u"), nameIdx); auto tempTvObjId = (pTvDb.operator->()->*pFindFunc)(sTempName, nullptr); if (tempTvObjId.isNull()) { tvObjId = creatTvObj(sTempName, &tvRes); if (pHelpMapWithNextNameIdx) { auto itFnd = pHelpMapWithNextNameIdx->find(nwObjName); if (itFnd != pHelpMapWithNextNameIdx->end()) itFnd->second++; else pHelpMapWithNextNameIdx->insert({ nwObjName, std::move(++nameIdx) }); } break; } } } return tvObjId; } //low memory import functions template OdTvResult writeLowMemoryImportObject(const OdTvEntityId& entId, const T& parentId, OdTvDatabasePtr pTvDb) { OdTvResult res = tvOk; auto pTvParent = parentId.openObject(OdTv::kForWrite); res = pTvParent->extendPartialViewIndex(entId); if (res == tvOk) { res = pTvDb->writeObjectPartial(entId); } return res; } template OdTvResult initLowMemoryImportTableRecord(const T& tvTableRecordId) { OdTvResult res = tvOk; auto pTvTableRecord = tvTableRecordId.openObject(OdTv::kForWrite); res = pTvTableRecord->addPartialViewIndex(false); return res; } namespace { OdTvColorDef ODCOLORREF2TvClrDef(ODCOLORREF* pDefColor) { if (pDefColor != nullptr) { //get default color from properties OdUInt8 r, g, b; r = ODGETRED(*pDefColor); g = ODGETGREEN(*pDefColor); b = ODGETBLUE(*pDefColor); return OdTvColorDef(r, g, b); } return OdTvColorDef(); } } OdNwGeometryImport::OdNwGeometryImport(const OdTvDatabaseId& tvDatabaseId, OdPerfTimerBase* pTvTimer, double& nTotalTvTime, ODCOLORREF* pDefColor, ImportProperties&& importProps, const OdString& sReflEnv, mapNwObjId2TvIdsType* mNwId2TvIds, NwModelUnits::Enum nwModelUnits, const OdNwObjectId& nwMatElId, std::function getTempFilePath) : m_tvDatabaseId(tvDatabaseId) , m_regAppId() , m_pTvTimer(pTvTimer) , m_nTotalTvTime(nTotalTvTime) , m_mNwId2TvIds(mNwId2TvIds) , m_ImportProperties(std::forward(importProps)) , m_stTvEntBranch() , m_lNwTrsfmBranch() , m_lNwPartitionTrm() , m_lTvInsBranch() , m_bIsHiddenBranch(false) , m_curLevelMaterial(nullptr, OdNwGraphicMaterialAttributePtr()) , m_mTvBlocks() , m_tvMaterialImporter(tvDatabaseId, nwMatElId, nwModelUnits, ODCOLORREF2TvClrDef(pDefColor), sReflEnv, getTempFilePath) , m_tvCurLayerId() , m_nwCurPartUnits(nwModelUnits) , m_isPtCldAdded(false) , m_numRefGeomBlock(0) { } auto getMIName = [](OdNwModelItemPtr pMI) { auto sName = pMI->getDisplayName(); if (sName.isEmpty()) { sName = pMI->getClassDisplayName(); if (sName.isEmpty()) sName = pMI->getClassName(); } return sName; }; void OdNwGeometryImport::importLH(const OdNwObjectId& nwModelItemRootId, OdTvModelId tvModelId) { if (!nwModelItemRootId) return; OdTvModelPtr pTvModel = tvModelId.openObject(OdTv::kForWrite); OdTvDatabasePtr pTvDb = m_tvDatabaseId.openObject(OdTv::kForWrite); //VAS: set units for tv model, if its first tv model of this tv database this units will be units for tv database pTvModel->setUnits([](NwModelUnits::Enum nwUnits)->OdTv::Units { switch (nwUnits) { case NwModelUnits::UNITS_METERS: return OdTv::kMeters; break; case NwModelUnits::UNITS_CENTIMETERS: return OdTv::kCentimeters; break; case NwModelUnits::UNITS_MILLIMETERS: return OdTv::kMillimeters; break; case NwModelUnits::UNITS_FEET: return OdTv::kFeet; break; case NwModelUnits::UNITS_INCHES: return OdTv::kInches; break; case NwModelUnits::UNITS_YARDS: return OdTv::kYards; break; case NwModelUnits::UNITS_KILOMETERS: return OdTv::kKilometers; break; case NwModelUnits::UNITS_MILES: return OdTv::kMiles; break; case NwModelUnits::UNITS_MICROMETERS: return OdTv::kMicrometers; break; case NwModelUnits::UNITS_MILS: return OdTv::kMils; break; case NwModelUnits::UNITS_MICROINCHES: return OdTv::kMicroInches; break; default: return OdTv::kUserDefined; break; } }(m_nwCurPartUnits)); bool alreadyExist = false; m_regAppId = pTvDb->registerAppName(OD_T("ExGsVisualizeDevice"), alreadyExist); OdRxModulePtr pRecapModule; if (m_ImportProperties.m_isImportRecap) { pRecapModule = odrxDynamicLinker()->loadModule(OdNwRecapImportModuleName); if (!pRecapModule.isNull()) { #ifdef NWRECAPIMPORT_ENABLED if (auto pRecapImport = dynamic_cast(pRecapModule.get())) { auto pPointCloud = pRecapImport->getNwPointCloud(); if (!pPointCloud.isNull()) { pPointCloud->setFindReferenceCallback(m_ImportProperties.m_clbkFindReference); } } #else //if nw2visualize is compiled without exchange/NwRecapImport - there still possible to set find reference callback in runtime //by using external geometry protocol extension auto pExtGeomPE = OdNwAbstractExternalGeometryPE::cast(OdRxObjectImpl::createObject()); if (!pExtGeomPE.isNull()) { pExtGeomPE->setFindReferenceCallback(m_ImportProperties.m_clbkFindReference); } #endif } } std::map geometryMap; if (m_ImportProperties.m_isImportRefGeomAsInserts) { collectGeometryInfo(nwModelItemRootId, geometryMap); } goThroughtLHTree(nwModelItemRootId, tvModelId, geometryMap); if (!pRecapModule.isNull()) { odrxDynamicLinker()->unloadModule(OdNwRecapImportModuleName); } } //helper nw attribute flags constexpr OdUInt32 transformAttr = NwCategoryConversionType::TransRotation | NwCategoryConversionType::Translation | NwCategoryConversionType::Transform; constexpr OdUInt32 materialAttr = NwCategoryConversionType::Material | NwCategoryConversionType::GraphicMaterial; template constexpr OdUInt32 getPhysicalLength() { return 0; } template <> constexpr OdUInt32 getPhysicalLength() { return 1; } template <> constexpr OdUInt32 getPhysicalLength() { return 2; } template <> constexpr OdUInt32 getPhysicalLength() { return 3; } template typename std::enable_if::type processAttr(OdNwAttribute* pAttr, OdTvMatrix& trm) { if (pAttr->isA() == OdNwTransRotationAttribute::desc()) { OdNwTransRotationAttributePtr pTransRotAttr = pAttr; trm = pTransRotAttr->getRotation().getMatrix(); trm.setTranslation(pTransRotAttr->getTranslation()); trm[3][3] = 1; } else if (pAttr->isA() == OdNwTransAttribute::desc()) { trm.setTranslation(OdNwTransAttribute::cast(pAttr)->getTranslation()); trm[3][3] = 1; } else if (pAttr->isA() == OdNwTransformAttribute::desc()) { trm = OdNwTransformAttribute::cast(pAttr)->getTransform(); trm[3][3] = 1; } } template typename std::enable_if::type processAttr(OdNwAttribute* pAttr, OdNwMaterial2TvNode& nwMat2TvNode) { if (pAttr->isA() == OdNwMaterialAttribute::desc()) { nwMat2TvNode.first = static_cast(pAttr); } else if (pAttr->isA() == OdNwGraphicMaterialAttribute::desc()) { nwMat2TvNode.second = static_cast(pAttr); } } template typename std::enable_if::type processAttr(OdNwAttribute* pAttr, OdTvMatrix& trm, OdNwMaterial2TvNode& nwMat2TvNode) { processAttr(pAttr, trm); processAttr(pAttr, nwMat2TvNode); } template void getNwAttributes(OdNwModelItem* pNwMI, Args&... args) { OdArray aMIAttrs(getPhysicalLength()); if (pNwMI->getAttributes(aMIAttrs, catConvFlags) == eOk) { for (auto& pAttr : aMIAttrs) { processAttr(pAttr, args...); } } } OdTvMaterialId OdNwGeometryImport::importMaterial(const OdNwMaterial2TvNode& nwMat2TvNode) { OdTvMaterialId tvMatId; //update asset attribute if (!nwMat2TvNode.second.isNull() && (m_curLevelMaterial.second.isNull() || !m_tvMaterialImporter.isEqual(m_curLevelMaterial.second.get(), nwMat2TvNode.second.get()))) { //try to find asset by guid, if this advanced material will not found in material element, then skip it while traversing if (m_tvMaterialImporter.checkAdvancedMaterialGUID(nwMat2TvNode.second)) m_curLevelMaterial.second = nwMat2TvNode.second; else m_curLevelMaterial.second = OdNwGraphicMaterialAttributePtr(); } //update simple material attribute if (nwMat2TvNode.first && m_curLevelMaterial.first != nwMat2TvNode.first) m_curLevelMaterial.first = nwMat2TvNode.first; if (nwMat2TvNode.first || !nwMat2TvNode.second.isNull()) tvMatId = m_tvMaterialImporter.getMaterial(nwMat2TvNode.first, nwMat2TvNode.second.get()); return tvMatId; } void OdNwGeometryImport::goThroughtLHTree(const OdNwObjectId& nwModelItemId, const OdTvModelId& tvModelId, std::map& geometryMap) { OdNwModelItemPtr pModelItem = nwModelItemId.openObject(); //pop flag for removing last elements from helper branches bool popEntBranch = false; bool popTrmBranch = false; bool popRefGeomGroup = false; //save old parent branch state of hidennes and materials OdNwMaterial2TvNode oldCurLevelMaterial = m_curLevelMaterial; bool oldIsHidden = m_bIsHiddenBranch; NwModelUnits::Enum oldCurPartUnits = m_nwCurPartUnits; //model item type flag for removing last elements from helper branches bool isInsert = false; bool isLayer = false; bool isPartition = false; bool isCollection = false; switch (pModelItem->getIcon()) { case NwModelItemIcon::FILE: { //TODO: when there will be possible to add sub models into tv database - need to add all sub partitions as tv models OdTvMatrix trsfm = OdTvMatrix::kIdentity; getNwAttributes(pModelItem, trsfm); //append isHidden flag in helper branch state, we skip partitions node and not add tv objects for it if (pModelItem->isHidden()) m_bIsHiddenBranch = true; //check if this partition is main if (m_lNwPartitionTrm.empty()) { //if transform is not identity and there is the first root partition then set transform attribute like tv model matrix if (trsfm != OdTvMatrix::kIdentity) { OdTvModelPtr pTvModel = tvModelId.openObject(OdTv::kForWrite); pTvModel->setModelingMatrix(trsfm); } } else { //if it's not main partition - then compare units from this partition and main partition m_nwCurPartUnits = OdNwPartition::cast(pModelItem)->getUnits(); //if units not the same - change translation if it's not null to current units if (oldCurPartUnits != m_nwCurPartUnits && !trsfm.translation().isEqualTo(OdTvVector::kIdentity)) { trsfm[0][3] = OdNwUnitUtils::convert(trsfm[0][3], m_nwCurPartUnits, oldCurPartUnits); trsfm[1][3] = OdNwUnitUtils::convert(trsfm[1][3], m_nwCurPartUnits, oldCurPartUnits); trsfm[2][3] = OdNwUnitUtils::convert(trsfm[2][3], m_nwCurPartUnits, oldCurPartUnits); } if (m_ImportProperties.m_isNeedGroupsUsing) { //get visibility status from model item node or from parent skipped noeds if this entity must be appended into tv model OdTvVisibilityDef tvVisDef = OdTvVisibilityDef::kVisible; if (pModelItem->isHidden()) { tvVisDef = OdTvVisibilityDef::kInvisible; } else { if (m_bIsHiddenBranch) tvVisDef = OdTvVisibilityDef::kInvisible; } auto pTvGroup = appendGroup(nwModelItemId, tvModelId, trsfm, OdTvMaterialDef(), tvVisDef); popEntBranch = true; } } //if partition transform is not identity - append it to branch transformation if (trsfm != OdTvMatrix::kIdentity) { m_lNwTrsfmBranch.push_back(trsfm); popTrmBranch = true; } //append transform into partition transform branch m_lNwPartitionTrm.push_back(trsfm); isPartition = true; break; } case NwModelItemIcon::INSERT_GROUP: case NwModelItemIcon::INSERT_GEOMETRY: { OdNwMaterial2TvNode nwMat2TvNode; OdTvMatrix tvTrsm = OdTvMatrix::kIdentity; getNwAttributes(pModelItem, tvTrsm, nwMat2TvNode); OdTvMaterialId tvMaterialId = importMaterial(nwMat2TvNode); if (tvTrsm != OdTvMatrix::kIdentity) { m_lNwTrsfmBranch.push_back(tvTrsm); popTrmBranch = true; } if (m_ImportProperties.m_isNeedGroupsUsing) { OdInt32 chldCnt = 0; OdNwObjectIdArray aChildren; if (pModelItem->getChildren(aChildren) == eOk) { chldCnt = aChildren.size(); } OdNwModelItemPtr pNwChildBlock = aChildren[0].openObject(); //if it's insert-block link(insert model item with one not insert children) then create insert and block if ((pNwChildBlock->getIcon() == NwModelItemIcon::GEOMETRY || pNwChildBlock->getIcon() == NwModelItemIcon::GROUP || pNwChildBlock->getIcon() == NwModelItemIcon::COMPOSITE_OBJECT) && chldCnt == 1) { OdNwObjectIdArray aInst; pNwChildBlock->getInstances(aInst); //appending insert-block structure is usefull only if block is used more then one time if (aInst.size() > 1) { //get is hidden flag from node or from skipped parent nodes bool isHidden = pNwChildBlock->isHidden(); if (!isHidden) { isHidden = m_bIsHiddenBranch; } appendInsert(pModelItem->objectId(), tvModelId, tvTrsm, tvMaterialId, m_tvCurLayerId, isHidden); if (popEntBranch) m_stTvEntBranch.pop(); if (popTrmBranch) m_lNwTrsfmBranch.pop_back(); //there is no need to go throught tree in deep by goThroughtLHTree and in this case return from it return; } } bool isFirstLevelEntity = m_stTvEntBranch.empty(); auto pNonInsertItem = findTheFirstNonInsertNode(pModelItem); //OdNwModelItemPtr pNwIns = pModelItem->objectId().openObject(); //get is hidden flag from node or from parent skipped nodes if entity must be append into tv model OdTvVisibilityDef tvVisDef = OdTvVisibilityDef::kVisible; if (pNonInsertItem->isHidden()) { tvVisDef = OdTvVisibilityDef::kInvisible; } else if (isFirstLevelEntity) { if (m_bIsHiddenBranch) tvVisDef = OdTvVisibilityDef::kInvisible; } auto pTvGroup = appendGroup(pNonInsertItem->objectId(), tvModelId, tvTrsm, OdTvMaterialDef(tvMaterialId), tvVisDef); //if it's first level entity - set extents if (isFirstLevelEntity) pTvGroup->setExtents(pModelItem->getBoundingBox()); popEntBranch = true; } else { //if model item is insert group or insert geometry - append new node into helper branch with insert data m_lTvInsBranch.push_back(Nw2TvInsBranchElement{ pModelItem->objectId(), OdUInt32(0), popEntBranch, OdTvEntityPtr(), tvTrsm, tvMaterialId }); isInsert = true; } break; } case NwModelItemIcon::LAYER: { //create tv layer object m_tvCurLayerId = createTvDbUniqueObject(m_tvDatabaseId.openObject(OdTv::kForWrite), getMIName(pModelItem)); if (!m_tvCurLayerId.isNull()) { isLayer = true; auto pTvLayer = m_tvCurLayerId.openObject(OdTv::kForWrite); //set visibility flag if layer is hidden or if skiped parent node are hidden if (pModelItem->isHidden()) { pTvLayer->setVisible(false); } else { if (m_bIsHiddenBranch) pTvLayer->setVisible(false); } //set material data from model item attributes { OdNwMaterial2TvNode nwMat2TvNode; getNwAttributes(pModelItem, nwMat2TvNode); OdTvMaterialId tvMaterialId = importMaterial(nwMat2TvNode); if (!tvMaterialId.isNull()) pTvLayer->setMaterial(OdTvMaterialDef(tvMaterialId)); pTvLayer->setColor(OdTvColorDef()); } } if (!m_ImportProperties.m_isNeedGroupsUsing) break; } case NwModelItemIcon::COLLECTION: { isCollection = true; //collection is some sort insert layer in naviswork structure, so skip it with saved usefull attribute data if (pModelItem->isHidden()) m_bIsHiddenBranch = true; if (!m_ImportProperties.m_isNeedGroupsUsing) break; } case NwModelItemIcon::GEOMETRY: { if (m_ImportProperties.m_isImportRefGeomAsInserts && !isCollection && !isLayer) { if (!m_ImportProperties.m_isNeedGroupsUsing) { //if there was parent insert - then this data may be import like block-insert if (!m_lTvInsBranch.empty()) { auto itLastIns = m_lTvInsBranch.rbegin(); //if it's insert-block link(insert model item with one not insert children) then create insert and block if (itLastIns->m_chldCnt == 1) { OdNwObjectIdArray aInst; pModelItem->getInstances(aInst); //appending insert-block structure is usefull only if block is used more then one time if (aInst.size() > 1) { //get is hidden flag from node or from skipped parent nodes bool isHidden = pModelItem->isHidden(); if (!isHidden) { isHidden = m_bIsHiddenBranch; } //insert node is append into tv model, so there is need then insert transform will contain parent insert transformations and sub partiotion transforms OdTvMatrix insTrm; if (m_lNwPartitionTrm.size() > 1) { auto itPartTr = m_lNwPartitionTrm.begin(); itPartTr++;//skip root partition transform - because this transform is set as tv model transformation and will be alreay applied for tv objects for (; itPartTr != m_lNwPartitionTrm.end(); itPartTr++) { insTrm *= *itPartTr; } } for (auto& tvIns : m_lTvInsBranch) { insTrm *= tvIns.m_trsfm; } appendInsert(itLastIns->m_nwInsMI, tvModelId, insTrm, itLastIns->m_tvMatId, m_tvCurLayerId, isHidden); //there is no need to go throught tree in deep by goThroughtLHTree and in this case return from it return; } } //if block from insert has not more then one instance - add insert branch like entities/subentities //find last insert node in helper branch by which is not created tv entity object auto resFnd = std::find_if(m_lTvInsBranch.rbegin(), m_lTvInsBranch.rend(), [](const Nw2TvInsBranchElement& tvInsBranch) { return !tvInsBranch.m_pTvEnt.isNull(); }); auto itNextIns = m_lTvInsBranch.begin(); if (resFnd != m_lTvInsBranch.rend()) itNextIns = resFnd.base(); bool isFirstLvlEntity = itNextIns == m_lTvInsBranch.begin(); //creaste for all insert node tv entity objects for (; itNextIns != m_lTvInsBranch.end(); ++itNextIns) { OdNwModelItemPtr pNwIns = itNextIns->m_nwInsMI.openObject(); //get is hidden flag from node or from parent skipped nodes if entity must be append into tv model OdTvVisibilityDef tvVisDef = OdTvVisibilityDef::kVisible; if (pNwIns->isHidden()) { tvVisDef = OdTvVisibilityDef::kInvisible; } else if (isFirstLvlEntity) { if (m_bIsHiddenBranch) tvVisDef = OdTvVisibilityDef::kInvisible; } itNextIns->m_pTvEnt = appendEntity(itNextIns->m_nwInsMI, tvModelId, itNextIns->m_trsfm, OdTvMaterialDef(itNextIns->m_tvMatId), tvVisDef); itNextIns->m_popEntBranch = true; //first level entity if (isFirstLvlEntity) { itNextIns->m_pTvEnt->setExtents(pNwIns->getBoundingBox()); isFirstLvlEntity = false; } } } } OdNwObjectId geomId = pModelItem->getGeometryComponentId(); OdNwComponentPtr pNwComp = geomId.openObject(); OdNwObjectIdArray aFragments; pNwComp->getFragments(aFragments); //append current model item node as tv entity object //get transformation and material attributes from model item OdNwMaterial2TvNode nwMat2TvNode; OdTvMatrix miTrm = OdTvMatrix::kIdentity; getNwAttributes(pModelItem, miTrm, nwMat2TvNode); OdTvMaterialId tvMaterialId = importMaterial(nwMat2TvNode); bool isFirstLevelEntity = m_stTvEntBranch.empty(); if (miTrm != OdTvMatrix::kIdentity) { m_lNwTrsfmBranch.push_back(miTrm); popTrmBranch = true; } //get visibility status from model item node or from parent skipped noeds if this entity must be appended into tv model OdTvVisibilityDef tvVisDef = OdTvVisibilityDef::kVisible; if (pModelItem->isHidden()) { tvVisDef = OdTvVisibilityDef::kInvisible; } else if (isFirstLevelEntity) { if (m_bIsHiddenBranch) tvVisDef = OdTvVisibilityDef::kInvisible; } OdTvMatrix branchTrm = OdTvMatrix::kIdentity; OdTvMatrix oldHierarchyTransform = OdTvMatrix::kIdentity; bool hasFirstPartTrm = !m_lNwPartitionTrm.empty() && m_lNwPartitionTrm.front() != OdTvMatrix::kIdentity; if (m_lNwTrsfmBranch.size() == 1) { branchTrm = m_lNwTrsfmBranch.back(); if (!hasFirstPartTrm) { oldHierarchyTransform = m_lNwTrsfmBranch.back(); } } else if(!m_lNwTrsfmBranch.empty()) { //accumulate branch transform value auto it = m_lNwTrsfmBranch.begin(); branchTrm = branchTrm * *it; if (!hasFirstPartTrm) oldHierarchyTransform = oldHierarchyTransform * *it; ++it; for (; it != m_lNwTrsfmBranch.end(); ++it) { branchTrm = branchTrm * *it; oldHierarchyTransform = oldHierarchyTransform * *it; } } bool isThereRefGeom = false; bool isThereRegularGeom = false; bool oneTrForAll = true; bool oneMatForAll = true; OdTvMatrix commonTr; OdNwObjectId commonMat; OdUInt32 numFragments = aFragments.size(); if(numFragments > 0) { OdNwFragmentPtr pFrag = aFragments[0].openObject(); //check if fragments has common transfom and common material commonTr = pFrag->getTransformation(); commonMat = pFrag->getMaterial(); for (auto fragment : aFragments) { OdNwFragmentPtr pFrag = fragment.openObject(); if (oneTrForAll && commonTr != pFrag->getTransformation()) oneTrForAll = false; OdNwObjectId fragGeomId = pFrag->getGeometryId(); auto it = geometryMap.find(fragGeomId); OdUInt32 geomSize = 0; if(it != geometryMap.end()) { OdNwGeometryPtr pNwGeom = it->first.safeOpenObject(); OdNwVerticesDataPtr pVerticesData; if (pNwGeom->isA() == OdNwGeometryShell::desc()) { OdNwGeometryShellPtr pGeometrMesh = pNwGeom; ODA_ASSERT(!pGeometrMesh.isNull()); pVerticesData = pGeometrMesh->getVerticesData(); geomSize += pGeometrMesh->getIndices().size() * sizeof(OdUInt16); } else if (pNwGeom->isA() == OdNwGeometryLineSet::desc()) { OdNwGeometryLineSetPtr pGeomertyLineSet = pNwGeom; ODA_ASSERT(!pGeomertyLineSet.isNull()); pVerticesData = pGeomertyLineSet->getVerticesData(); } else if (pNwGeom->isA() == OdNwGeometryPointSet::desc()) { OdNwGeometryPointSetPtr pGeometryPointSet = pNwGeom; pVerticesData = pGeometryPointSet->getVerticesData(); ODA_ASSERT(!pVerticesData.isNull()); } else if (pNwGeom->isA() == OdNwGeometryExternal::desc()) { OdNwGeometryExternalPtr pGeometryExt = pNwGeom; auto pAbstrGeomPE = OdNwAbstractExternalGeometryPE::cast(pGeometryExt); if (m_ImportProperties.m_isImportRecap && !pAbstrGeomPE.isNull()) { OdGePoint3dArray coords; OdCmEntityColorArray colors; OdResult ptCldRe = pAbstrGeomPE->getPointCloud(pGeometryExt, coords, colors); geomSize += coords.size() * sizeof(OdGePoint3d); geomSize += colors.size() * sizeof(OdCmEntityColor); } } if (!pVerticesData.isNull()) { OdGePoint3dArray vertices = pVerticesData->getVertices(); geomSize += vertices.size() * sizeof(OdGePoint3d); geomSize += pVerticesData->getColors().size() * sizeof(OdUInt32); geomSize += pVerticesData->getNormals().size() * sizeof(OdGeVector3d); geomSize += pVerticesData->getTexCoords().size() * sizeof(OdGePoint2d); } } constexpr OdUInt32 memSize2xThreshold = 900*2; if (it != geometryMap.end() && it->second.occurencesNum > 1 && geomSize * it->second.occurencesNum >= memSize2xThreshold) { if (oneMatForAll && commonMat != pFrag->getMaterial()) oneMatForAll = false; it->second.isReferencedGeom = true; isThereRefGeom = true; } else { isThereRegularGeom = true; } } } OdTvMaterialId tvMatId; OdTvColorDef tvEntClr; bool needSetTrcy = false; OdTvTransparencyDef tvTrcyDef; if (isThereRefGeom && m_ImportProperties.m_isNeedGroupsUsing && numFragments > 1) { OdTvGroupPtr pTvGroup = appendGroup(nwModelItemId, tvModelId, miTrm, OdTvMaterialDef(tvMaterialId), tvVisDef); popRefGeomGroup = true; if (oneTrForAll) { if (branchTrm != commonTr) { auto fragmentOffset = branchTrm.inverse() * commonTr; if (fragmentOffset != OdTvMatrix::kIdentity) { OdTvMatrix newModelingMatrix = pTvGroup->getModelingMatrix() * fragmentOffset; pTvGroup->setModelingMatrix(newModelingMatrix); if (miTrm != OdTvMatrix::kIdentity) { m_lNwTrsfmBranch.back() = newModelingMatrix; } else { m_lNwTrsfmBranch.push_back(newModelingMatrix); popTrmBranch = true; } } } } } if (isThereRefGeom) { if (oneMatForAll) { const OdNwObjectId& nwMatId = pNwComp->getMaterialId(); const OdNwObjectId& nwOrigMatId = pNwComp->getOriginalMaterialId(); if (nwOrigMatId && nwMatId == nwOrigMatId) { bool needCreateMat = true; //check if current material is the same with nearest parent material if (m_curLevelMaterial.first) { //tvEntClr = m_tvMaterialImporter.getDefaultEntClr(); switch (m_tvMaterialImporter.isEqual(nwOrigMatId, m_curLevelMaterial.first, tvEntClr, tvTrcyDef)) { case NwMaterialImport::OdNw2TvMaterialImport::kIsNotEqual: break; case NwMaterialImport::OdNw2TvMaterialImport::kIsEqaulWithOverrides: needSetTrcy = true; case NwMaterialImport::OdNw2TvMaterialImport::kIsEqual: needCreateMat = false; break; } } if (needCreateMat) { tvEntClr = m_tvMaterialImporter.getDefaultEntClr(); tvMatId = m_tvMaterialImporter.getMaterial(nwOrigMatId, tvEntClr); } } else if (nwMatId)//texture case { bool needCreateMat = true; if (!m_curLevelMaterial.second.isNull()) needCreateMat = !m_tvMaterialImporter.isEqual(nwMatId, m_curLevelMaterial.second); if (needCreateMat) tvMatId = m_tvMaterialImporter.getMaterial(nwMatId, nwOrigMatId, tvEntClr); else if (nwOrigMatId && m_curLevelMaterial.first) { m_tvMaterialImporter.isEqual(nwOrigMatId, m_curLevelMaterial.first, tvEntClr, tvTrcyDef); } } } OdTvMaterialDef tvDefaultMat = tvMaterialId.isNull() ? OdTv::kByLayer : OdTv::kByBlock; for (auto fragment : aFragments) { OdNwFragmentPtr pFrag = fragment.openObject(); OdNwObjectId fragGeomId = pFrag->getGeometryId(); auto it = geometryMap.find(fragGeomId); if (!oneMatForAll) { auto nwFragMatId = pFrag->getMaterial(); bool needCreateMat = true; //check if current material is the same with nearest parent material if (m_curLevelMaterial.first) { //tvEntClr = m_tvMaterialImporter.getDefaultEntClr(); switch (m_tvMaterialImporter.isEqual(nwFragMatId, m_curLevelMaterial.first, tvEntClr, tvTrcyDef)) { case NwMaterialImport::OdNw2TvMaterialImport::kIsNotEqual: break; case NwMaterialImport::OdNw2TvMaterialImport::kIsEqaulWithOverrides: needSetTrcy = true; case NwMaterialImport::OdNw2TvMaterialImport::kIsEqual: needCreateMat = false; break; } } if (needCreateMat) { tvEntClr = m_tvMaterialImporter.getDefaultEntClr(); tvMatId = m_tvMaterialImporter.getMaterial(nwFragMatId, tvEntClr); } } if (it != geometryMap.end() && it->second.isReferencedGeom) { OdTvBlockId tvBlockId; bool isCreatedRightNow = false; { OdTvResult rc = tvOk; OdTvDatabasePtr pTvDb = m_tvDatabaseId.openObject(OdTv::kForWrite, &rc); auto& blockRef = m_mTvBlocks[it->first]; if (blockRef.isNull()) { isCreatedRightNow = true; OdString refGeomName; refGeomName.format(L"%d_ref_geom_", m_numRefGeomBlock++); refGeomName += getMIName(pModelItem); tvBlockId = createTvDbUniqueObject(m_tvDatabaseId.openObject(OdTv::kForWrite), refGeomName); blockRef = tvBlockId; m_stTvEntBranch.push(std::make_tuple(OdTvEntityId(), OdTvGeometryDataId(), tvBlockId, OdTvGroupPtr())); auto pTvEntity = appendEntity(nwModelItemId, tvModelId, OdTvMatrix::kIdentity, tvMaterialId.isNull() ? tvDefaultMat : OdTvMaterialDef(tvMaterialId), OdTvVisibilityDef::kVisible); const OdNwObjectId& nwMatId = pNwComp->getMaterialId(); const OdNwObjectId& nwOrigMatId = pNwComp->getOriginalMaterialId(); OdTvMaterialId tvMatId; OdTvColorDef tvEntClr; bool needSetTrcy = false; OdTvTransparencyDef tvTrcyDef; //create tv material by nw material //if there is simple material case if (nwOrigMatId && nwMatId == nwOrigMatId) { bool needCreateMat = true; //check if current material is the same with nearest parent material if (m_curLevelMaterial.first) { //tvEntClr = m_tvMaterialImporter.getDefaultEntClr(); switch (m_tvMaterialImporter.isEqual(nwOrigMatId, m_curLevelMaterial.first, tvEntClr, tvTrcyDef)) { case NwMaterialImport::OdNw2TvMaterialImport::kIsNotEqual: break; case NwMaterialImport::OdNw2TvMaterialImport::kIsEqaulWithOverrides: needSetTrcy = true; case NwMaterialImport::OdNw2TvMaterialImport::kIsEqual: needCreateMat = false; break; } } if (needCreateMat) { tvEntClr = m_tvMaterialImporter.getDefaultEntClr(); tvMatId = m_tvMaterialImporter.getMaterial(nwOrigMatId, tvEntClr); } } else if (nwMatId)//texture case { bool needCreateMat = true; if (!m_curLevelMaterial.second.isNull()) needCreateMat = !m_tvMaterialImporter.isEqual(nwMatId, m_curLevelMaterial.second); if (needCreateMat) tvMatId = m_tvMaterialImporter.getMaterial(nwMatId, nwOrigMatId, tvEntClr); else if (nwOrigMatId && m_curLevelMaterial.first) { m_tvMaterialImporter.isEqual(nwOrigMatId, m_curLevelMaterial.first, tvEntClr, tvTrcyDef); } } appendGeomDataToEntity(it->first, pTvEntity, pFrag->isSolid()); if (!tvMatId.isNull()) pTvEntity->setMaterial(OdTvMaterialDef(tvMatId)); if (tvEntClr.getType() != OdTvColorDef::kDefault) pTvEntity->setColor(tvEntClr); if (needSetTrcy) pTvEntity->setTransparency(tvTrcyDef); m_stTvEntBranch.pop(); //block m_stTvEntBranch.pop(); //entity } else { tvBlockId = blockRef; } } OdTvMatrix insTransform; if (!m_ImportProperties.m_isNeedGroupsUsing) insTransform = oldHierarchyTransform; else if(numFragments == 1) insTransform = miTrm; //append insert OdTvEntityId insertId = createInsertByBlock(nwModelItemId, tvBlockId, tvModelId, getMIName(pModelItem), insTransform, OdTvMaterialDef(tvMaterialId), m_tvCurLayerId, tvVisDef); OdTvInsertPtr insPtr = insertId.openObjectAsInsert(OdTv::kForWrite); //TODO: replace DEBUG CODE if(!isCreatedRightNow) { OdTvBlockId blockId = insPtr->getBlock(); OdTvBlockPtr pBlock = blockId.openObject(OdTv::kForWrite); auto it = pBlock->getEntitiesIterator(); OdTvEntityId entityId = it->getEntity(); OdTvEntityPtr pEnt = entityId.openObject(OdTv::kForWrite); if(pEnt->getMaterial().getMaterial() != tvMatId) pEnt->setMaterial(OdTv::kByBlock); if(pEnt->getColor() != tvEntClr) pEnt->setColor(OdTv::kByBlock); if (needSetTrcy && pEnt->getTransparency() != tvTrcyDef) pEnt->setTransparency(OdTv::kByBlock); } if (!tvMatId.isNull()) insPtr->setMaterial(OdTvMaterialDef(tvMatId)); if (tvEntClr.getType() != OdTvColorDef::kDefault) insPtr->setColor(tvEntClr); if (needSetTrcy) insPtr->setTransparency(tvTrcyDef); if (!oneTrForAll || !m_ImportProperties.m_isNeedGroupsUsing || numFragments == 1) { OdTvMatrix fragTrans = pFrag->getTransformation(); if (branchTrm != fragTrans) { auto fragmentOffset = branchTrm.inverse() * fragTrans; if (fragmentOffset != OdTvMatrix::kIdentity) insPtr->setBlockTransform(insPtr->getBlockTransform() * fragmentOffset); } } } } } if (isThereRegularGeom) { auto pTvEntity = appendEntity(nwModelItemId, tvModelId, isThereRefGeom && m_ImportProperties.m_isNeedGroupsUsing ? OdTvMatrix::kIdentity : miTrm, isThereRefGeom ? OdTvMaterialDef() : OdTvMaterialDef(tvMaterialId), tvVisDef); popEntBranch = true; //if it's first level entity - set extents if (isFirstLevelEntity) pTvEntity->setExtents(pModelItem->getBoundingBox()); } //second run break; } } case NwModelItemIcon::GROUP: case NwModelItemIcon::COMPOSITE_OBJECT: { if (!m_ImportProperties.m_isNeedGroupsUsing) { //if there was parent insert - then this data may be import like block-insert if (!m_lTvInsBranch.empty()) { auto itLastIns = m_lTvInsBranch.rbegin(); //if it's insert-block link(insert model item with one not insert children) then create insert and block if (itLastIns->m_chldCnt == 1) { OdNwObjectIdArray aInst; pModelItem->getInstances(aInst); //appending insert-block structure is usefull only if block is used more then one time if (aInst.size() > 1) { //get is hidden flag from node or from skipped parent nodes bool isHidden = pModelItem->isHidden(); if (!isHidden) { isHidden = m_bIsHiddenBranch; } //insert node is append into tv model, so there is need then insert transform will contain parent insert transformations and sub partiotion transforms OdTvMatrix insTrm; if (m_lNwPartitionTrm.size() > 1) { auto itPartTr = m_lNwPartitionTrm.begin(); itPartTr++;//skip root partition transform - because this transform is set as tv model transformation and will be alreay applied for tv objects for (; itPartTr != m_lNwPartitionTrm.end(); itPartTr++) { insTrm *= *itPartTr; } } for (auto& tvIns : m_lTvInsBranch) { insTrm *= tvIns.m_trsfm; } appendInsert(itLastIns->m_nwInsMI, tvModelId, insTrm, itLastIns->m_tvMatId, m_tvCurLayerId, isHidden); //there is no need to go throught tree in deep by goThroughtLHTree and in this case return from it return; } } //if block from insert has not more then one instance - add insert branch like entities/subentities //find last insert node in helper branch by which is not created tv entity object auto resFnd = std::find_if(m_lTvInsBranch.rbegin(), m_lTvInsBranch.rend(), [](const Nw2TvInsBranchElement& tvInsBranch) { return !tvInsBranch.m_pTvEnt.isNull(); }); auto itNextIns = m_lTvInsBranch.begin(); if (resFnd != m_lTvInsBranch.rend()) itNextIns = resFnd.base(); bool isFirstLvlEntity = itNextIns == m_lTvInsBranch.begin(); //creaste for all insert node tv entity objects for (; itNextIns != m_lTvInsBranch.end(); ++itNextIns) { OdNwModelItemPtr pNwIns = itNextIns->m_nwInsMI.openObject(); //get is hidden flag from node or from parent skipped nodes if entity must be append into tv model OdTvVisibilityDef tvVisDef = OdTvVisibilityDef::kVisible; if (pNwIns->isHidden()) { tvVisDef = OdTvVisibilityDef::kInvisible; } else if (isFirstLvlEntity) { if (m_bIsHiddenBranch) tvVisDef = OdTvVisibilityDef::kInvisible; } itNextIns->m_pTvEnt = appendEntity(itNextIns->m_nwInsMI, tvModelId, itNextIns->m_trsfm, OdTvMaterialDef(itNextIns->m_tvMatId), tvVisDef); itNextIns->m_popEntBranch = true; //first level entity if (isFirstLvlEntity) { itNextIns->m_pTvEnt->setExtents(pNwIns->getBoundingBox()); isFirstLvlEntity = false; } } } } //append current model item node as tv entity object //get transformation and material attributes from model item OdNwMaterial2TvNode nwMat2TvNode; OdTvMatrix miTrm = OdTvMatrix::kIdentity; getNwAttributes(pModelItem, miTrm, nwMat2TvNode); OdTvMaterialId tvMaterialId = importMaterial(nwMat2TvNode); bool isFirstLevelEntity = m_stTvEntBranch.empty(); //get visibility status from model item node or from parent skipped noeds if this entity must be appended into tv model OdTvVisibilityDef tvVisDef = OdTvVisibilityDef::kVisible; if (pModelItem->isHidden()) { tvVisDef = OdTvVisibilityDef::kInvisible; } else if (isFirstLevelEntity) { if (m_bIsHiddenBranch) tvVisDef = OdTvVisibilityDef::kInvisible; } if (m_ImportProperties.m_isNeedGroupsUsing && !pModelItem->hasGeometry()) { auto pTvGroup = appendGroup(nwModelItemId, tvModelId, miTrm, OdTvMaterialDef(tvMaterialId), tvVisDef); if (m_ImportProperties.m_isNeedGroupsUsing && isLayer && !m_tvCurLayerId.isNull()) { pTvGroup->setLayer(m_tvCurLayerId); } //if it's first level entity - set extents if (isFirstLevelEntity) pTvGroup->setExtents(pModelItem->getBoundingBox()); } else { auto pTvEntity = appendEntity(nwModelItemId, tvModelId, miTrm, OdTvMaterialDef(tvMaterialId), tvVisDef); //if it's first level entity - set extents if (isFirstLevelEntity) pTvEntity->setExtents(pModelItem->getBoundingBox()); } popEntBranch = true; if (miTrm != OdTvMatrix::kIdentity) { m_lNwTrsfmBranch.push_back(miTrm); popTrmBranch = true; } break; } } if (pModelItem->hasGeometry()) { //if transfomration tree branch is empty - just set matrix from fragments if (m_lNwTrsfmBranch.empty()) { createEntitiesFromNwComponent(pModelItem->getGeometryComponentId(), geometryMap, [](OdTvEntityPtr pTvEntity, OdTvSubGroupDataPtr pTvSubGroup, const OdTvMatrix& trm) { if (!pTvEntity.isNull()) { if (trm != pTvEntity->getModelingMatrix()) pTvEntity->setModelingMatrix(trm); } else if (!pTvSubGroup.isNull()) { if (trm != pTvSubGroup->getModelingMatrix()) pTvSubGroup->setModelingMatrix(trm); } }); } else { OdTvMatrix branchTrm = OdTvMatrix::kIdentity; //if branch has only one element - process it while setting transform for fragments if (m_lNwTrsfmBranch.size() == 1) branchTrm = m_lNwTrsfmBranch.back(); else { //accumulate branch transform value for (auto& nodeTrm : m_lNwTrsfmBranch) branchTrm = branchTrm * nodeTrm; } createEntitiesFromNwComponent(pModelItem->getGeometryComponentId(), geometryMap, [&branchTrm](OdTvEntityPtr pTvEntity, OdTvSubGroupDataPtr pTvSubGroup, const OdTvMatrix& trm) { if (branchTrm != trm) { auto fragmentOffset = branchTrm.inverse() * trm; if (fragmentOffset != OdTvMatrix::kIdentity) { if (!pTvEntity.isNull()) pTvEntity->setModelingMatrix(pTvEntity->getModelingMatrix() * fragmentOffset); else if (!pTvSubGroup.isNull()) pTvSubGroup->setModelingMatrix(pTvSubGroup->getModelingMatrix() * fragmentOffset); } } }); } } else { OdNwObjectIdArray aChildren; if (pModelItem->getChildren(aChildren) == eOk) { if (!m_ImportProperties.m_isNeedGroupsUsing && isInsert) m_lTvInsBranch.back().m_chldCnt = aChildren.size(); for (auto& chId : aChildren) { goThroughtLHTree(chId, tvModelId, geometryMap); } if (!m_ImportProperties.m_isNeedGroupsUsing && isInsert) m_lTvInsBranch.pop_back(); if (isLayer) m_tvCurLayerId.setNull(); if (isPartition) m_lNwPartitionTrm.pop_back(); } } if (popEntBranch) { //need to check, if added entity hasn't geometry - remove it from model bool isGoodEntity = true; if (!std::get<0>(m_stTvEntBranch.top()).isNull()) { auto pTvEnt = std::get<0>(m_stTvEntBranch.top()).openObject(); if (pTvEnt->isEmpty()) { isGoodEntity = false; pTvEnt.release(); OdTvResult resCode = tvOk; auto pTvModel = tvModelId.openObject(OdTv::kForWrite, &resCode); if (resCode == tvOk) pTvModel->removeEntity(std::get<0>(m_stTvEntBranch.top())); } } else if (m_ImportProperties.m_isNeedGroupsUsing && !std::get<3>(m_stTvEntBranch.top()).isNull()) { auto pTvGroup = std::get<3>(m_stTvEntBranch.top()); if (pTvGroup->isEmpty()) { isGoodEntity = false; pTvGroup.release(); OdTvResult resCode = tvOk; auto pTvModel = tvModelId.openObject(OdTv::kForWrite, &resCode); if (resCode == tvOk) pTvModel->removeEntity(std::get<3>(m_stTvEntBranch.top())->getEntitiesIterator()->getEntity()); } } if (isGoodEntity) { if (m_ImportProperties.m_isLowMemoryImportToVSF && m_stTvEntBranch.size() == 1) { writeLowMemoryImportObject(std::get<0>(m_stTvEntBranch.top()), tvModelId, m_tvDatabaseId.openObject(OdTv::kForWrite)); } if (m_mNwId2TvIds) m_mNwId2TvIds->insert({ nwModelItemId, m_stTvEntBranch.top() }); } m_stTvEntBranch.pop(); } if (popTrmBranch) m_lNwTrsfmBranch.pop_back(); if(popRefGeomGroup) m_stTvEntBranch.pop(); //return parent branch state to old values m_bIsHiddenBranch = oldIsHidden; m_curLevelMaterial = oldCurLevelMaterial; m_nwCurPartUnits = oldCurPartUnits; } OdTvEntityPtr OdNwGeometryImport::appendEntity(const OdNwObjectId& nwModelItemId, const OdTvModelId& tvModelId, const OdTvMatrix& trm, OdTvMaterialDef tvMatDef, OdTvVisibilityDef tvVisDef) { OdNwModelItemPtr pModelItem = nwModelItemId.openObject(); OdTvEntityPtr pTvEntity; OdTvMatrix entTr = trm; if (m_stTvEntBranch.empty()) { OdTvModelPtr pTvModel = tvModelId.openObject(OdTv::kForWrite); OdTvEntityId entId = pTvModel->appendEntity(getMIName(pModelItem)); m_stTvEntBranch.push(std::make_tuple(entId, OdTvGeometryDataId(), OdTvBlockId(), OdTvGroupPtr())); pTvEntity = entId.openObject(OdTv::kForWrite); pTvEntity->setNeedCheckShellsTopology(true); if (!m_ImportProperties.m_isNeedGroupsUsing) { if (!pTvEntity.isNull() && !m_tvCurLayerId.isNull()) { pTvEntity->setLayer(OdTvLayerDef(m_tvCurLayerId)); } //if tv entity is append in tv model - then there is need to get all sub partition tranfrom and apply it for tv entity transform if (m_lNwPartitionTrm.size() > 1) { auto itPartTr = m_lNwPartitionTrm.begin(); itPartTr++; for (; itPartTr != m_lNwPartitionTrm.end(); itPartTr++) { entTr = *itPartTr * entTr; } } } } else { if (!std::get<0>(m_stTvEntBranch.top()).isNull()) { OdTvEntityPtr pTvParentEntity = std::get<0>(m_stTvEntBranch.top()).openObject(OdTv::kForWrite); OdTvGeometryDataId subEntId = pTvParentEntity->appendSubEntity(getMIName(pModelItem)); m_stTvEntBranch.push(std::make_tuple(OdTvEntityId(), subEntId, OdTvBlockId(), OdTvGroupPtr())); pTvEntity = subEntId.openAsSubEntity(OdTv::kForWrite); } else if (!std::get<1>(m_stTvEntBranch.top()).isNull()) { OdTvEntityPtr pTvParentEntity = std::get<1>(m_stTvEntBranch.top()).openAsSubEntity(OdTv::kForWrite); OdTvGeometryDataId subEntId = pTvParentEntity->appendSubEntity(getMIName(pModelItem)); m_stTvEntBranch.push(std::make_tuple(OdTvEntityId(), subEntId, OdTvBlockId(), OdTvGroupPtr())); pTvEntity = subEntId.openAsSubEntity(OdTv::kForWrite); } else if (!std::get<2>(m_stTvEntBranch.top()).isNull()) { OdTvBlockId tvBlockId = std::get<2>(m_stTvEntBranch.top()); OdTvBlockPtr pTvBlock = tvBlockId.openObject(OdTv::kForWrite); OdTvEntityId subEntId = pTvBlock->appendEntity(getMIName(pModelItem)); m_stTvEntBranch.push(std::make_tuple(subEntId, OdTvGeometryDataId(), OdTvBlockId(), OdTvGroupPtr())); pTvEntity = subEntId.openObject(OdTv::kForWrite); } else if (!std::get<3>(m_stTvEntBranch.top()).isNull()) { OdTvGroupPtr pTvParentGroup = std::get<3>(m_stTvEntBranch.top()); OdTvEntityId entId = pTvParentGroup->appendEntity(getMIName(pModelItem)); m_stTvEntBranch.push(std::make_tuple(entId, OdTvGeometryDataId(), OdTvBlockId(), OdTvGroupPtr())); pTvEntity = entId.openObject(OdTv::kForWrite); } } if (entTr != OdTvMatrix::kIdentity) pTvEntity->setModelingMatrix(entTr); pTvEntity->setMaterial(tvMatDef); pTvEntity->setVisibility(tvVisDef); // Add native handle to user data if (m_ImportProperties.m_isNeedCDATree || m_ImportProperties.m_isStoreSourceObjects) { OdUInt64 uinic_ID = nwModelItemId.getHandle(); OdTvByteUserData* data = new OdTvByteUserData(&uinic_ID, sizeof(OdUInt64), OdTvByteUserData::kCopyOwn, true); pTvEntity->appendUserData(data, m_regAppId); } return pTvEntity; } OdTvGroupPtr OdNwGeometryImport::appendGroup(const OdNwObjectId& nwModelItemId, const OdTvModelId& tvModelId, const OdTvMatrix& trm, OdTvMaterialDef tvMatDef, OdTvVisibilityDef tvVisDef) { OdNwModelItemPtr pModelItem = nwModelItemId.openObject(); OdTvGroupPtr pTvGroup; OdTvMatrix entTr = trm; if (m_stTvEntBranch.empty()) { OdTvModelPtr pTvModel = tvModelId.openObject(OdTv::kForWrite); OdTvEntityId groupId = pTvModel->appendGroup(getMIName(pModelItem)); pTvGroup = groupId.openObjectAsGroup(OdTv::kForWrite); m_stTvEntBranch.push(std::make_tuple(OdTvEntityId(), OdTvGeometryDataId(), OdTvBlockId(), pTvGroup)); } else { if (!std::get<3>(m_stTvEntBranch.top()).isNull()) { OdTvGroupPtr pTvParentGroup = std::get<3>(m_stTvEntBranch.top()); OdTvEntityId subgroupId = pTvParentGroup->appendGroup(getMIName(pModelItem)); pTvGroup = subgroupId.openObjectAsGroup(OdTv::kForWrite); m_stTvEntBranch.push(std::make_tuple(OdTvEntityId(), OdTvGeometryDataId(), OdTvBlockId(), pTvGroup)); } else if (!std::get<2>(m_stTvEntBranch.top()).isNull()) { OdTvBlockId tvBlockId = std::get<2>(m_stTvEntBranch.top()); OdTvBlockPtr pTvBlock = tvBlockId.openObject(OdTv::kForWrite); OdTvEntityId subgroupId = pTvBlock->appendGroup(getMIName(pModelItem)); pTvGroup = subgroupId.openObjectAsGroup(OdTv::kForWrite); m_stTvEntBranch.push(std::make_tuple(OdTvEntityId(), OdTvGeometryDataId(), OdTvBlockId(), pTvGroup)); } } if (entTr != OdTvMatrix::kIdentity) pTvGroup->setModelingMatrix(entTr); if(!tvMatDef.getMaterial().isNull()) pTvGroup->setMaterial(tvMatDef); pTvGroup->setVisibility(tvVisDef); // Add native handle to user data if (m_ImportProperties.m_isNeedCDATree || m_ImportProperties.m_isStoreSourceObjects) { OdUInt64 uinic_ID = nwModelItemId.getHandle(); OdTvByteUserData* data = new OdTvByteUserData(&uinic_ID, sizeof(OdUInt64), OdTvByteUserData::kCopyOwn, true); pTvGroup->appendUserData(data, m_regAppId); } return pTvGroup; } void OdNwGeometryImport::appendInsert(const OdNwObjectId& nwInsId, const OdTvModelId& tvModelId, const OdTvMatrix& insTrm, OdTvMaterialDef tvMatDef, OdTvLayerId tvLayerId, bool isHidden) { OdNwModelItemPtr pNwInsert = nwInsId.openObject(); bool popEntBranch = false; OdNwObjectIdArray aCh; pNwInsert->getChildren(aCh); OdNwModelItemPtr pNwBlock = aCh[0].openObject(); OdNwObjectIdArray aInstances; pNwBlock->getInstances(aInstances); // auto sNwInsName = pNwInsert->getDisplayName(); OdTvBlockId tvBlockId; OdTvEntityId tvInsId; auto itResFnd = m_mTvBlocks.find(aInstances[0]); if (itResFnd == m_mTvBlocks.end()) { OdString sNwBlockName = getMIName(pNwBlock); tvBlockId = createTvDbUniqueObject(m_tvDatabaseId.openObject(OdTv::kForWrite), sNwBlockName); m_mTvBlocks.insert({ aInstances[0], tvBlockId }); if (m_ImportProperties.m_isLowMemoryImportToVSF) initLowMemoryImportTableRecord(tvBlockId); tvInsId = createInsertByBlock(nwInsId, tvBlockId, tvModelId, sNwInsName.isEmpty() ? sNwBlockName : sNwInsName, insTrm, tvMatDef, tvLayerId, !isHidden); m_stTvEntBranch.push(std::make_tuple(OdTvEntityId(), OdTvGeometryDataId(), tvBlockId, OdTvGroupPtr())); popEntBranch = true; OdTvMatrix insWithPartTrm = insTrm; if (!m_ImportProperties.m_isNeedGroupsUsing) { //if model matrix is not empty - apply it with insert transform for correct comparing with child fragment transformations if (*m_lNwPartitionTrm.begin() != OdTvMatrix::kIdentity) insWithPartTrm = *m_lNwPartitionTrm.begin() * insWithPartTrm; } std::map emptyMap; std::function createEntForBlock = [this, &createEntForBlock, &insWithPartTrm, &tvModelId, &emptyMap](const OdNwObjectId& nwMIId, OdTvMaterialDef tvDefaultMat, bool bIsFirstLevel) { OdNwModelItemPtr pModelItem = nwMIId.openObject(); //get material auto oldCurLevelMaterial = m_curLevelMaterial; OdTvMaterialId tvMaterialId; { OdNwMaterial2TvNode nwMat2TvNode; getNwAttributes(pModelItem, nwMat2TvNode); tvMaterialId = importMaterial(nwMat2TvNode); } if (!m_ImportProperties.m_isNeedGroupsUsing) { //current tv object level has not material - then set default material as parent def type auto pTvEntity = appendEntity(nwMIId, tvModelId, OdTvMatrix::kIdentity, tvMaterialId.isNull() ? tvDefaultMat : OdTvMaterialDef(tvMaterialId), OdTvVisibilityDef::kVisible); if (bIsFirstLevel) { OdTvExtents3d blockEntExt = pModelItem->getBoundingBox(); blockEntExt.transformBy(insWithPartTrm.inverse()); pTvEntity->setExtents(blockEntExt); } } if (pModelItem->hasGeometry()) { if (m_ImportProperties.m_isNeedGroupsUsing) { //current tv object level has not material - then set default material as parent def type auto pTvEntity = appendEntity(nwMIId, tvModelId, OdTvMatrix::kIdentity, tvMaterialId.isNull() ? tvDefaultMat : OdTvMaterialDef(tvMaterialId), OdTvVisibilityDef::kVisible); if (bIsFirstLevel) { OdTvExtents3d blockEntExt = pModelItem->getBoundingBox(); blockEntExt.transformBy(insWithPartTrm.inverse()); pTvEntity->setExtents(blockEntExt); } OdTvMatrix branchTrm = OdTvMatrix::kIdentity; //if branch has only one element - process it while setting transform for fragments if (m_lNwTrsfmBranch.size() == 1) branchTrm = m_lNwTrsfmBranch.back(); else { //accumulate branch transform value for (auto& nodeTrm : m_lNwTrsfmBranch) branchTrm = branchTrm * nodeTrm; } createEntitiesFromNwComponent(pModelItem->getGeometryComponentId(), emptyMap, [branchTrm](OdTvEntityPtr pTvEnt, OdTvSubGroupDataPtr pTvSubGroup, const OdTvMatrix& trm) { auto fragmentOffset = branchTrm.inverse() * trm; if (fragmentOffset != OdTvMatrix::kIdentity) { if (!pTvEnt.isNull()) pTvEnt->setModelingMatrix(pTvEnt->getModelingMatrix() * fragmentOffset); else if (!pTvSubGroup.isNull()) pTvSubGroup->setModelingMatrix(pTvSubGroup->getModelingMatrix() * fragmentOffset); } }); } else { createEntitiesFromNwComponent(pModelItem->getGeometryComponentId(), emptyMap, [insWithPartTrm](OdTvEntityPtr pTvEnt, OdTvSubGroupDataPtr, const OdTvMatrix& trm) { if (insWithPartTrm != trm) pTvEnt->setModelingMatrix(insWithPartTrm.inverse() * trm); }); } } else { if (m_ImportProperties.m_isNeedGroupsUsing) { auto pTvGroup = appendGroup(nwMIId, tvModelId, OdTvMatrix::kIdentity, tvMaterialId.isNull() ? tvDefaultMat : OdTvMaterialDef(tvMaterialId), OdTvVisibilityDef::kVisible); if (bIsFirstLevel) { OdTvExtents3d blockEntExt = pModelItem->getBoundingBox(); blockEntExt.transformBy(insWithPartTrm.inverse()); pTvGroup->setExtents(blockEntExt); } } OdNwObjectIdArray aChildren; if (pModelItem->getChildren(aChildren) == eOk) { for (auto& chId : aChildren) { createEntForBlock(chId, tvMaterialId.isNull() ? tvDefaultMat : tvMaterialId, false); } } } //append block's entity node for animation's helper map if (m_mNwId2TvIds) m_mNwId2TvIds->insert({ nwMIId, m_stTvEntBranch.top() }); m_curLevelMaterial = oldCurLevelMaterial; m_stTvEntBranch.pop(); }; //if insert has material - then need set default material for block entities as by block, in other case - set as by layer createEntForBlock(pNwBlock->objectId(), tvMatDef.getMaterial().isNull() ? OdTv::kByLayer : OdTv::kByBlock, true); if (m_ImportProperties.m_isLowMemoryImportToVSF) { auto pTvBlock = tvBlockId.openObject(); auto tvBlockEntIt = pTvBlock->getEntitiesIterator(); while (!tvBlockEntIt->done()) { writeLowMemoryImportObject(tvBlockEntIt->getEntity(), tvBlockId, m_tvDatabaseId.openObject(OdTv::kForWrite)); tvBlockEntIt->step(); } } } else { tvBlockId = itResFnd->second; tvInsId = createInsertByBlock(pNwInsert->objectId(), tvBlockId, tvModelId, sNwInsName.isEmpty() ? getMIName(pNwBlock) : sNwInsName, insTrm, tvMatDef, tvLayerId, !isHidden); } if (m_ImportProperties.m_isLowMemoryImportToVSF) { writeLowMemoryImportObject(tvInsId, tvModelId, m_tvDatabaseId.openObject(OdTv::kForWrite)); } //append insert node for animation's helper map if (m_mNwId2TvIds) m_mNwId2TvIds->insert({ nwInsId, {tvInsId, OdTvGeometryDataId(), OdTvBlockId(), OdTvGroupPtr()}}); if (popEntBranch) { //append block node for animation's helper map if (m_mNwId2TvIds) m_mNwId2TvIds->insert({ aCh[0], m_stTvEntBranch.top() }); m_stTvEntBranch.pop(); } } OdTvEntityId OdNwGeometryImport::createInsertByBlock(const OdNwObjectId& nwInsId, const OdTvBlockId& tvBlockId, const OdTvModelId& tvModelId, const OdString& insName, const OdTvMatrix& insTrm, OdTvMaterialDef tvMatDef, OdTvLayerId tvLrId, OdTvVisibilityDef tvVisib) { OdTvResult resCode = tvOk; OdTvEntityId tvInsId; //VAS: create new insert object if (m_stTvEntBranch.empty() || !m_ImportProperties.m_isNeedGroupsUsing) { tvInsId = tvModelId.openObject(OdTv::kForWrite)->appendInsert(tvBlockId, insName, &resCode); } else { OdTvGroupPtr pTvParentGroup = std::get<3>(m_stTvEntBranch.top()); tvInsId = pTvParentGroup->appendInsert(tvBlockId, insName, &resCode); } OdTvInsertPtr pTvIns = tvInsId.openObjectAsInsert(OdTv::kForWrite); if (!m_ImportProperties.m_isNeedGroupsUsing && !tvLrId.isNull()) pTvIns->setLayer(OdTvLayerDef(tvLrId)); pTvIns->setVisibility(tvVisib); pTvIns->setBlockTransform(insTrm); pTvIns->setMaterial(tvMatDef); pTvIns->setExtents(OdNwModelItem::cast(nwInsId.openObject())->getBoundingBox()); // Add native handle to user data if (m_ImportProperties.m_isNeedCDATree || m_ImportProperties.m_isStoreSourceObjects) { OdUInt64 uinic_ID = nwInsId.getHandle(); OdTvByteUserData* data = new OdTvByteUserData(&uinic_ID, sizeof(OdUInt64), OdTvByteUserData::kCopyOwn, true); pTvIns->appendUserData(data, m_regAppId); } return tvInsId; } void OdNwGeometryImport::createEntitiesFromNwComponent(const OdNwObjectId& nwCompId, std::map&geometryMap, std::function setTrm) { if (m_stTvEntBranch.empty()) return; OdNwComponentPtr pNwComp = nwCompId.openObject(); const OdNwObjectId& nwMatId = pNwComp->getMaterialId(); const OdNwObjectId& nwOrigMatId = pNwComp->getOriginalMaterialId(); OdTvMaterialId tvMatId; OdTvColorDef tvEntClr; bool needSetTrcy = false; OdTvTransparencyDef tvTrcyDef; //create tv material by nw material //if there is simple material case if (nwOrigMatId && nwMatId == nwOrigMatId) { bool needCreateMat = true; //check if current material is the same with nearest parent material if (m_curLevelMaterial.first) { //tvEntClr = m_tvMaterialImporter.getDefaultEntClr(); switch (m_tvMaterialImporter.isEqual(nwOrigMatId, m_curLevelMaterial.first, tvEntClr, tvTrcyDef)) { case NwMaterialImport::OdNw2TvMaterialImport::kIsNotEqual: break; case NwMaterialImport::OdNw2TvMaterialImport::kIsEqaulWithOverrides: needSetTrcy = true; case NwMaterialImport::OdNw2TvMaterialImport::kIsEqual: needCreateMat = false; break; } } if (needCreateMat) { tvEntClr = m_tvMaterialImporter.getDefaultEntClr(); tvMatId = m_tvMaterialImporter.getMaterial(nwOrigMatId, tvEntClr); } } else if (nwMatId)//texture case { bool needCreateMat = true; if (!m_curLevelMaterial.second.isNull()) needCreateMat = !m_tvMaterialImporter.isEqual(nwMatId, m_curLevelMaterial.second); if (needCreateMat) tvMatId = m_tvMaterialImporter.getMaterial(nwMatId, nwOrigMatId, tvEntClr); else if (nwOrigMatId && m_curLevelMaterial.first) { m_tvMaterialImporter.isEqual(nwOrigMatId, m_curLevelMaterial.first, tvEntClr, tvTrcyDef); } } OdNwObjectIdArray aFragments; pNwComp->getFragments(aFragments); if (aFragments.size() == 1) { //if component has only one fragment - then append geometry data from fragment into parent entity/subentity OdNwFragmentPtr pFrag = aFragments[0].openObject(); if (!geometryMap.empty()) { auto frg = pFrag->getGeometryId(); auto it = geometryMap.find(frg); if (it != geometryMap.end() && it->second.isReferencedGeom) { return; } } OdTvEntityPtr pTvSubEntity; if (!std::get<0>(m_stTvEntBranch.top()).isNull()) { pTvSubEntity = std::get<0>(m_stTvEntBranch.top()).openObject(OdTv::kForWrite); } else if (!std::get<1>(m_stTvEntBranch.top()).isNull()) { pTvSubEntity = std::get<1>(m_stTvEntBranch.top()).openAsSubEntity(OdTv::kForWrite); } if (!pTvSubEntity.isNull()) { appendGeomDataToEntity(pFrag->getGeometryId(), pTvSubEntity, pFrag->isSolid()); setTrm(pTvSubEntity, OdTvSubGroupDataPtr(), pFrag->getTransformation()); if (!tvMatId.isNull()) pTvSubEntity->setMaterial(OdTvMaterialDef(tvMatId)); if (tvEntClr.getType() != OdTvColorDef::kDefault) pTvSubEntity->setColor(tvEntClr); if (needSetTrcy) pTvSubEntity->setTransparency(tvTrcyDef); } } else if (!aFragments.empty()) { //if component has more then one fragment and different transformation for each fragment- then need to append geometry data from fragment as different subentities, in other case as geometry data in parent entity/subentity bool oneTrForAll = true; bool oneMatForAll = true; bool isThereRefGeometry = false; //check if fragments has common transfom and common material OdNwFragmentPtr pFrag = aFragments[0].openObject(); OdTvMatrix commonTr = pFrag->getTransformation(); OdNwObjectId commonMat = pFrag->getMaterial(); OdUInt32 fragCnt = aFragments.size(); for (OdUInt32 i = 1; i < fragCnt; ++i) { pFrag = aFragments[i].openObject(); auto frg = pFrag->getGeometryId(); if (!geometryMap.empty()) { auto it = geometryMap.find(frg); if (it != geometryMap.end() && it->second.isReferencedGeom) { isThereRefGeometry = true; if (!oneMatForAll && !oneTrForAll) break; continue; } } if (oneTrForAll && commonTr != pFrag->getTransformation()) oneTrForAll = false; if (oneMatForAll && commonMat != pFrag->getMaterial()) oneMatForAll = false; if ( !oneMatForAll && !oneTrForAll && isThereRefGeometry) break; } OdTvEntityPtr pTvSubEntity; if (!std::get<0>(m_stTvEntBranch.top()).isNull()) { pTvSubEntity = std::get<0>(m_stTvEntBranch.top()).openObject(OdTv::kForWrite); } else if (!std::get<1>(m_stTvEntBranch.top()).isNull()) { pTvSubEntity = std::get<1>(m_stTvEntBranch.top()).openAsSubEntity(OdTv::kForWrite); } if (!pTvSubEntity.isNull()) { if (oneMatForAll) { if (!tvMatId.isNull()) pTvSubEntity->setMaterial(OdTvMaterialDef(tvMatId)); if (tvEntClr.getType() != OdTvColorDef::kDefault) pTvSubEntity->setColor(tvEntClr); if (needSetTrcy) pTvSubEntity->setTransparency(tvTrcyDef); } if (oneTrForAll) { setTrm(pTvSubEntity, OdTvSubGroupDataPtr(), commonTr); } OdTvEntityPtr pEmptyEntity; OdTvSubGroupDataPtr pEmptySubGroupData; for (auto& fragId : aFragments) { OdNwFragmentPtr pFrag = fragId.openObject(); OdNwObjectId nwGeomId = pFrag->getGeometryId(); if (!geometryMap.empty()) { auto it = geometryMap.find(nwGeomId); if (it != geometryMap.end() && it->second.isReferencedGeom) { continue; } } //if all fragments contain equal transfomarion and material - add data from them as geometry data to parent entity if (oneTrForAll && oneMatForAll) { appendGeomDataToEntity(nwGeomId, pTvSubEntity, pFrag->isSolid()); } else { OdTvEntityPtr pTvSubSubEntity; OdTvSubGroupDataPtr pTvSubSubGroup; if (m_ImportProperties.m_isNeedGroupsUsing) { OdTvGeometryDataId subGroupId = pTvSubEntity->appendSubGroup(OD_T("OdTvSubGroup")); pTvSubSubGroup = subGroupId.openAsSubGroup(); appendGeomDataToEntity(nwGeomId, pTvSubSubGroup, pFrag->isSolid()); if (!oneTrForAll) setTrm(pEmptyEntity, pTvSubSubGroup, pFrag->getTransformation()); } else { //fragments contain different transform or different material - add data from them as different sub entities with geometry data OdTvGeometryDataId subEntId = pTvSubEntity->appendSubEntity(OD_T("OdTvSubEntity")); pTvSubSubEntity = subEntId.openAsSubEntity(OdTv::kForWrite); appendGeomDataToEntity(nwGeomId, pTvSubSubEntity, pFrag->isSolid()); if (!oneTrForAll) setTrm(pTvSubSubEntity, pEmptySubGroupData, pFrag->getTransformation()); } if (!oneMatForAll) { auto nwFragMatId = pFrag->getMaterial(); bool needCreateMat = true; //check if current material is the same with nearest parent material if (m_curLevelMaterial.first) { switch (m_tvMaterialImporter.isEqual(nwFragMatId, m_curLevelMaterial.first, tvEntClr, tvTrcyDef)) { case NwMaterialImport::OdNw2TvMaterialImport::kIsNotEqual: break; case NwMaterialImport::OdNw2TvMaterialImport::kIsEqaulWithOverrides: needSetTrcy = true; case NwMaterialImport::OdNw2TvMaterialImport::kIsEqual: needCreateMat = false; break; } } if (needCreateMat) { tvEntClr = m_tvMaterialImporter.getDefaultEntClr(); tvMatId = m_tvMaterialImporter.getMaterial(nwFragMatId, tvEntClr); } if(m_ImportProperties.m_isNeedGroupsUsing) { if (!tvMatId.isNull()) pTvSubSubGroup->setMaterial(OdTvMaterialDef(tvMatId)); if (tvEntClr.getType() != OdTvColorDef::kDefault) pTvSubSubGroup->setColor(tvEntClr); if (needSetTrcy) pTvSubSubGroup->setTransparency(tvTrcyDef); } else { if (!tvMatId.isNull()) pTvSubSubEntity->setMaterial(OdTvMaterialDef(tvMatId)); if (tvEntClr.getType() != OdTvColorDef::kDefault) pTvSubSubEntity->setColor(tvEntClr); if (needSetTrcy) pTvSubSubEntity->setTransparency(tvTrcyDef); } } } } } } } void OdNwGeometryImport::collectGeometryInfo(const OdNwObjectId& nwModelItemId, std::map& geometryRefCounter) { OdNwModelItemPtr pModelItem = nwModelItemId.openObject(); if (pModelItem->getIcon() == NwModelItemIcon::GEOMETRY) { OdNwObjectId geomCompId = pModelItem->getGeometryComponentId(); OdNwComponentPtr pNwComp = geomCompId.openObject(); OdNwObjectIdArray aFragments; pNwComp->getFragments(aFragments); for (auto& frag : aFragments) { OdNwFragmentPtr pFrag = frag.openObject(); OdNwObjectId geomId = pFrag->getGeometryId(); auto it = geometryRefCounter.find(geomId); if (it == geometryRefCounter.end()) { geometryRefCounter.emplace(geomId, OdGeometryData(pFrag->isSolid())); } else { it->second.occurencesNum = it->second.occurencesNum + 1; } } } else if (pModelItem->getIcon() == NwModelItemIcon::INSERT_GEOMETRY || pModelItem->getIcon() == NwModelItemIcon::INSERT_GROUP) { return; } else { OdNwObjectIdArray aChildren; if (pModelItem->getChildren(aChildren) == eOk) { for (auto& chId : aChildren) { collectGeometryInfo(chId, geometryRefCounter); } } } }