/////////////////////////////////////////////////////////////////////////////// // 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. /////////////////////////////////////////////////////////////////////////////// // ODA Platform #include "OdaCommon.h" #include "RxObject.h" #include "TvFactory.h" #include "TvInsert.h" #include "TvTraitsDef.h" #include "TvCamera.h" #include "TvGroup.h" #include "TvDatabaseCleaner.h" #include "TvDatabaseUtils.h" #include "Prc2VisualizeDirectImport.h" #include "PrcBrepModel.h" #include "PrcPolyBrepModel.h" #include "PrcCoordinateSystem.h" #include "PrcAnnotationSet.h" #include "PrcAnnotationItem.h" #include "PrcSet.h" #include "TvImportUserData.h" static OdUInt32 nMarkupID = 1; static OdUInt32 nBlockID = 1; static OdUInt32 nModelID = 1; /** \details Types for specific PRC map */ typedef std::map< OdPrcObjectId, OdArray > prcProductOccuranceReferenceMap; /** \details Methods forward declaration */ void traverseTreeForFillingTV(OdPrcProductOccurrencePtr productOccurrence, const OdTvVisualizePrcTraitsAssign* pTraitsAssign, OdTvVisualizePrcTraverseFilerContext& ctx, bool bIsPrototypePO, bool bIsRootOccuarance = false); /** \details Method checks that block is empty */ bool blockIsEmpty(OdTvBlockId tvBlockId) { if (!tvBlockId.isNull()) { OdTvEntitiesIteratorPtr blockEntIt = tvBlockId.openObject()->getEntitiesIterator(); if (blockEntIt.isNull() || blockEntIt->done()) return true; } else return true; return false; } /** \details Method for aplying custom background */ void setupCustomBackground(OdTvDatabaseId& dbId, OdTvGsViewPtr pView) { if (!pView.isNull()) { //open database OdTvDatabasePtr pDb = dbId.openObject(OdTv::kForWrite); //set gradient background to the active view OdTvGsViewBackgroundId bkgId = pDb->findBackground(OD_T("PRC2VISUALIZE")); if (bkgId.isNull()) bkgId = pDb->createBackground(OD_T("PRC2VISUALIZE"), OdTvGsViewBackgroundId::kGradient); if (!bkgId.isNull()) { { OdTvGsViewGradientBackgroundPtr pGradientBackground = bkgId.openAsGradientBackground(OdTv::kForWrite); pGradientBackground->setColorTop(OdTvColorDef(33, 108, 170)); pGradientBackground->setColorMiddle(OdTvColorDef(109, 158, 200)); pGradientBackground->setColorBottom(OdTvColorDef(184, 208, 230)); pGradientBackground->setHeight(0.33); pGradientBackground->setHorizon(0.5); } pView->setBackground(bkgId); } } } /** \details Converts PRC unit to the Visualize units */ OdTv::Units convertPrcUnitToVisualize(OdPrcUnit prc_unit, double& addUnitCoefToMeters) { addUnitCoefToMeters = 1.0; if (prc_unit.unitFromCADFile()) { const double prc_unit_val = prc_unit.unit(); if (OdEqual(prc_unit_val, 1.0)) { return OdTv::kMillimeters; } if (OdEqual(prc_unit_val, 10.0)) { return OdTv::kCentimeters; } if (OdEqual(prc_unit_val, 1000.0)) { return OdTv::kMeters; } if (OdEqual(prc_unit_val, 0.001)) { return OdTv::kMicrometers; } if (OdEqual(prc_unit_val, 1000000.0)) { return OdTv::kKilometers; } if (OdEqual(prc_unit_val, 25.40)) { return OdTv::kInches; } if (OdEqual(prc_unit_val, 12.0 * 25.40)) { return OdTv::kFeet; } if (OdEqual(prc_unit_val, 25.40 / 1000.0)) { return OdTv::kMils; } if (OdEqual(prc_unit_val, 25.40 / 1000000.0)) { return OdTv::kMicroInches; } if (OdEqual(prc_unit_val, 914.4)) { return OdTv::kYards; } if (OdEqual(prc_unit_val, 1760.0 * 914.4)) { return OdTv::kMiles; } addUnitCoefToMeters = prc_unit_val * 1000.0; return OdTv::kUserDefined; } return OdTv::kMillimeters; } /** \details Method which retunrs inheritance rule */ OdTvVisualizePrcBehaviorBitField getInheritance(OdUInt16 sonBits, OdUInt16 fatherBits, OdUInt16 sonInheritBit, OdUInt16 fatherInheritBit) { if (GETBIT(sonBits, sonInheritBit)) { return kUseSon; } else if (GETBIT(fatherBits, sonInheritBit)) { return kUseFather; } else if (!GETBIT(fatherBits, fatherInheritBit)) { return kUseSon; } else { return kUseFather; //kUseCurrent, but for us it's the same as kUseFather, graphics must be reset all the time } } /** \details Append data to references map */ void addReferencesToMap(const OdPrcObjectIdArray& entityReference, prcProductOccuranceReferenceMap& currentReferences, prcProductOccuranceReferenceMap& oldReferences) { oldReferences = currentReferences; //add local references for (OdUInt32 i = 0; i < entityReference.size(); ++i) { OdPrcReferencePtr pRef = entityReference[i].openObject(); const bool isReferenceOnPRCBase = pRef->isReferenceOnPRCBase(); std::map>::iterator entry = currentReferences.find(isReferenceOnPRCBase ? pRef->referenceData().referenceOnPRCBase() : pRef->referenceData().referenceOnTopology()); if (isReferenceOnPRCBase) { if (0 == currentReferences[pRef->referenceData().referenceOnPRCBase()].size()) currentReferences[pRef->referenceData().referenceOnPRCBase()].resize(1); currentReferences[pRef->referenceData().referenceOnPRCBase()][0] = entityReference[i]; } else { currentReferences[pRef->referenceData().referenceOnTopology()].push_back(entityReference[i]); } } } /** \details Reset references */ void restoreReferencesMap(prcProductOccuranceReferenceMap& currentReferences, const prcProductOccuranceReferenceMap& oldReferences) { currentReferences = oldReferences; return; } /** \details Get part definiton from product occurance */ OdPrcObjectId getPartDefinition(OdPrcProductOccurrencePtr productOccurrence, OdString& protoTypeName) { OdPrcObjectId partDefId = productOccurrence->referencesOfProductOccurrence().getCorrespondingPartDefinition(); if (!partDefId.isNull()) return partDefId; if (productOccurrence->referencesOfProductOccurrence().getSonProductOccurrences().size() != 0) //in opposite case we are going to prototype { OdPrcObjectId protoId = productOccurrence->referencesOfProductOccurrence().getPrototypeID(); while (!protoId.isNull()) { OdPrcProductOccurrencePtr pPO = protoId.safeOpenObject(); if (!pPO->referencesOfProductOccurrence().getCorrespondingPartDefinition().isNull()) { protoTypeName = pPO->name().name(); return pPO->referencesOfProductOccurrence().getCorrespondingPartDefinition(); } else { protoId = pPO->referencesOfProductOccurrence().getPrototypeID(); } } } return OdPrcObjectId(); } /** \details Setup views visibility */ void setupViewsVisibility(const OdPrcRepresentationItem* pRI, OdTvVisualizePrcTraverseFilerContext& ctx, OdTvEntityId& enId) { OdGiContextForPrcDatabase* pCtx = OdGiContextForPrcDatabase::cast(ctx.m_pGeometryCollector->context()); if (!pCtx) return; if (pCtx->isAlwaysShow()) return; OdPrcGraphicsValuesStorage& currentGraphicsStorage = pCtx->graphicsValuesStorage(); OdUInt16 fatherBits = currentGraphicsStorage.getCurrentBits(); OdPrcFilePtr pDb = ctx.m_pDb; bool bCurrentShowBit; if (pDb->getBEHAVIORBITFIELDMODE() == 0) bCurrentShowBit = true; else bCurrentShowBit = GETBIT(pRI->behaviourBitField(), PRC_GRAPHICS_Show); //if object is simply invisible - it not our case if (!bCurrentShowBit) return; //cycle over views std::set invViews; bool bHasInvisible = false; for (auto it = ctx.m_ViewToLinkedItemsMap->begin(); it != ctx.m_ViewToLinkedItemsMap->end(); ++it) { // 1. find appropriate OdTvGsViewId OdTvGsViewId viewId; auto itVNode = ctx.m_pViewsNodeMap->find(it->first); if (itVNode != ctx.m_pViewsNodeMap->end()) { auto itV = ctx.m_pViewsMap->find((OdInt32)itVNode->second); if (itV != ctx.m_pViewsMap->end()) viewId = itV->second; } if (viewId.isNull()) continue; // 2. try to find object in view dependent data std::map::const_iterator mliEntry = it->second.find(pRI->id()); if (mliEntry != it->second.end()) { OdPrcContentEntityReferencePtr pReference = mliEntry->second.openObject(); OdPrcGraphics* pCurrentGraphics = &pReference->graphics(); OdUInt16 sonBits = pCurrentGraphics->behaviourBitField(); //set new values for graphics storage OdUInt16 currentBits = sonBits; currentBits |= fatherBits; //show bit OdTvVisualizePrcBehaviorBitField showInheritance = getInheritance(sonBits, fatherBits, PRC_GRAPHICS_SonHeritShow, PRC_GRAPHICS_FatherHeritShow); SETBIT(currentBits, PRC_GRAPHICS_Show, GETBIT(showInheritance == kUseSon ? sonBits : fatherBits, PRC_GRAPHICS_Show)); //check visibility if (!GETBIT(currentBits, PRC_GRAPHICS_Show)) { bHasInvisible = true; invViews.insert(viewId); } } } // eo for... if (bHasInvisible && !invViews.empty()) { OdTvEntityPtr pEntity = enId.openObject(OdTv::kForWrite); for (auto it = ctx.m_pViewsMap->begin(); it != ctx.m_pViewsMap->end(); it++) { if (invViews.find(it->second) == invViews.end()) pEntity->addViewDependency(it->second); } } return; } /************************************************************************************************************************************/ /* OdTvVisualizePrcTraitsAssign implementation */ /************************************************************************************************************************************/ /** \details Constructor */ OdTvVisualizePrcTraitsAssign::OdTvVisualizePrcTraitsAssign(const OdPrcBaseWithGraphics* pBaseWithGraphics, OdTvVisualizePrcTraverseFilerContext& ctx) { m_curTransparency = 1.; m_pCtx = OdGiContextForPrcDatabase::cast(ctx.m_pGeometryCollector->context()); if (m_pCtx.isNull()) { throw (eInvalidContext); } //use default color if (ctx.m_parentType == OdTvVisualizePrcTraverseFilerContext::kModel || ctx.m_parentType == OdTvVisualizePrcTraverseFilerContext::kBlock) { const ODCOLORREF default_draw_color = ctx.m_pDb->getDEFAULTDRAWCOLOR(); m_color = OdCmEntityColor(ODGETRED(default_draw_color), ODGETGREEN(default_draw_color), ODGETBLUE(default_draw_color)); } const OdPrcGraphics* pCurrentGraphics = NULL; OdPrcContentEntityReferencePtr pReference; pCurrentGraphics = &pBaseWithGraphics->graphics(); //try to find object in references map std::map>& references = m_pCtx->references(); std::map>::iterator entry = references.find(pBaseWithGraphics->id()); if (entry != references.end() && 0 != entry->second.size()) { pReference = entry->second.first().openObject(); if (pReference->isReferenceOnPRCBase()) { m_coordinateSystemId = pReference->localCoordinateSystem(); pCurrentGraphics = &pReference->graphics(); } } //get graphics from views OdPrcObjectId objView = ctx.m_curAnnotationViewId; if (objView.isNull()) objView = ctx.m_pDb->getCurrentViewId(); if (!objView.isNull()) { OdPrcViewPtr pView = objView.openObject(); prcViewToLinkedItemsMap::iterator itMap = ctx.m_ViewToLinkedItemsMap->find(objView); if (itMap != ctx.m_ViewToLinkedItemsMap->end()) { std::map::const_iterator mliEntry = itMap->second.find(pBaseWithGraphics->id()); if (mliEntry != itMap->second.end()) { pReference = mliEntry->second.openObject(); m_coordinateSystemId = pReference->localCoordinateSystem(); pCurrentGraphics = &pReference->graphics(); } } } ODA_ASSERT(pCurrentGraphics); OdPrcGraphicsValuesStorage& currentGraphicsStorage = m_pCtx->graphicsValuesStorage(); //remember current storage for revert later in destructor m_fatherGraphicsStorage = currentGraphicsStorage; OdUInt16 fatherBits = m_fatherGraphicsStorage.getCurrentBits(); OdUInt16 sonBits = pCurrentGraphics->behaviourBitField(); // Color/Material stuff OdDbStub* material = NULL; OdTvVisualizePrcBehaviorBitField colorInheritance = getInheritance(sonBits, fatherBits, PRC_GRAPHICS_SonHeritColor, PRC_GRAPHICS_FatherHeritColor); if (colorInheritance == kUseFather && m_fatherGraphicsStorage.getCurrentMaterial()) { // do nothing, if father has color } else { material = pCurrentGraphics->styleId(); if (material) m_curGraphicsStorage.setCurrentMaterial(material); } // Line pattern stuff OdDbStub* line_pattern = NULL; OdTvVisualizePrcBehaviorBitField linePatternInheritance = getInheritance(sonBits, fatherBits, PRC_GRAPHICS_SonHeritLinePattern, PRC_GRAPHICS_FatherHeritLinePattern); if (linePatternInheritance == kUseFather && m_fatherGraphicsStorage.getCurrentLinePattern()) { // do nothing, if father has color } else { line_pattern = pCurrentGraphics->styleId(); if (line_pattern) m_curGraphicsStorage.setCurrentLinePattern(line_pattern); } //transparency OdTvVisualizePrcBehaviorBitField transparencyInheritance = getInheritance(sonBits, fatherBits, PRC_GRAPHICS_SonHeritTransparency, PRC_GRAPHICS_FatherHeritTransparency); if (transparencyInheritance == kUseSon && !pCurrentGraphics->styleId().isNull()) { OdPrcCategory1LineStylePtr pLs = pCurrentGraphics->styleId().openObject(); OdInt8 transparency; if (pLs->getTransparency(transparency)) m_curTransparency = OdUInt8(transparency) / 255.; } //set new values for graphics storage OdUInt16 currentBits = sonBits; currentBits |= fatherBits; //show bit OdTvVisualizePrcBehaviorBitField showInheritance = getInheritance(sonBits, fatherBits, PRC_GRAPHICS_SonHeritShow, PRC_GRAPHICS_FatherHeritShow); OdPrcFilePtr pDb = m_pCtx->database(); if (pDb->getBEHAVIORBITFIELDMODE() == 0) m_bCurrentShowBit = true; else m_bCurrentShowBit = GETBIT(pBaseWithGraphics->behaviourBitField(), PRC_GRAPHICS_Show); SETBIT(currentBits, PRC_GRAPHICS_Show, GETBIT(showInheritance == kUseSon ? sonBits : fatherBits, PRC_GRAPHICS_Show)); currentGraphicsStorage.setCurrentBits(currentBits); if (material) { currentGraphicsStorage.setCurrentMaterial(material); } if (line_pattern) { currentGraphicsStorage.setCurrentLinePattern(line_pattern); } return; } OdTvVisualizePrcTraitsAssign::~OdTvVisualizePrcTraitsAssign() { if (!m_pCtx.isNull()) { m_pCtx->graphicsValuesStorage() = m_fatherGraphicsStorage; } } bool OdTvVisualizePrcTraitsAssign::getRemovedBit() const { if (m_pCtx.isNull()) { throw (eInvalidContext); } return GETBIT(m_pCtx->graphicsValuesStorage().getCurrentBits(), PRC_GRAPHICS_Removed); } OdPrcObjectId OdTvVisualizePrcTraitsAssign::getCoordinateSystemId() const { return m_coordinateSystemId; } void OdTvVisualizePrcTraitsAssign::play(OdGiWorldDraw* pDraw) const { //here we need to play not current but the net traits (convolution). We need to have correct traits during draw in subentity traits if (pDraw) { if (m_pCtx->graphicsValuesStorage().getCurrentMaterial()) pDraw->subEntityTraits().setMaterial(m_pCtx->graphicsValuesStorage().getCurrentMaterial()); if (m_pCtx->graphicsValuesStorage().getCurrentLinePattern()) pDraw->subEntityTraits().setLineType(m_pCtx->graphicsValuesStorage().getCurrentLinePattern()); //ASSUMPTION: now we are not able to get net transparency if (!OdZero(1. - m_curTransparency)) pDraw->subEntityTraits().setTransparency(OdCmTransparency(m_curTransparency)); //ASSUMPTION: we await that color will be used only for support default color in PRC if (m_color != OdCmEntityColor()) pDraw->subEntityTraits().setTrueColor(m_color); } } void OdTvVisualizePrcTraitsAssign::play(OdTvEntityId entId, OdTvVisualizePrcTraverseFilerContext& ctx) const { OdTvTraitsIObjectPtr pTraitsObj = entId.openAsTraitsObject(OdTv::kForWrite); if (!pTraitsObj.isNull()) { if (m_curGraphicsStorage.getCurrentMaterial()) { OdUInt32 color = 0; OdTvMaterialId tvMatId = ctx.m_pGeometryCollector->getTvMaterial(m_curGraphicsStorage.getCurrentMaterial(), color); pTraitsObj->setMaterial(OdTvMaterialDef(tvMatId)); if (color != 0) pTraitsObj->setColor(OdTvColorDef(ODGETBLUE(color), ODGETGREEN(color), ODGETRED(color))); } if (m_curGraphicsStorage.getCurrentLinePattern()) { OdUInt32 flg = 0; OdTvLinetypeId tvLinetypeId = ctx.m_pGeometryCollector->getTvLineType(m_curGraphicsStorage.getCurrentLinePattern(), flg); pTraitsObj->setLinetype(OdTvLinetypeDef(tvLinetypeId)); } if (!OdZero(1. - m_curTransparency)) pTraitsObj->setTransparency(OdTvTransparencyDef(1. - m_curTransparency)); //ASSUMPTION: we await that color will be used only for support default color in PRC (and it's RGB color) if (m_color != OdCmEntityColor() && m_color.colorMethod() == OdCmEntityColor::kByColor) pTraitsObj->setColor(OdTvColorDef(m_color.red(), m_color.green(), m_color.blue())); } return; } void OdTvVisualizePrcTraitsAssign::setDefaultColor(OdTvVisualizePrcTraverseFilerContext& ctx) { const ODCOLORREF default_draw_color = ctx.m_pDb->getDEFAULTDRAWCOLOR(); m_color = OdCmEntityColor(ODGETRED(default_draw_color), ODGETGREEN(default_draw_color), ODGETBLUE(default_draw_color)); } /************************************************************************************************************************************/ /* OdTvVisualizePrcTraverseFilerContext implementation */ /************************************************************************************************************************************/ /** \details Default constructor for the OdGsClientViewInfo class. */ OdTvVisualizePrcTraverseFilerContext::OdTvVisualizePrcTraverseFilerContext(OdTvVisualize2PrcGeomCollector* pGeometryCollector, prcFileStructureHandleToPOAndPartDefRepeatMap* pMap, prcFileStructureToPOAndPartDefTvBlockMap* pPOBlockMap, prcViewNodeToTvViewMap* pViewsMap, prcViewIdToViewNodeMap* pViewsNodeMap) { m_parentType = kModel; m_pRepeatMap = pMap; m_pPOAndPartDefBlockMap = pPOBlockMap; m_pViewsMap = pViewsMap; m_pViewsNodeMap = pViewsNodeMap; m_nRepetitions = 1; m_pGeometryCollector = pGeometryCollector; m_bDefaultViewWasCreated = false; m_ViewToLinkedItemsMap = nullptr; } /** \details Sets that all further entites should be added to the block */ void OdTvVisualizePrcTraverseFilerContext::setParentBlock(OdTvBlockId id) { m_parentType = kBlock; m_blockId = id; } /** \details Sets that all further entites should be added to the group */ void OdTvVisualizePrcTraverseFilerContext::setParentGroup(OdTvEntityId id) { m_parentType = kGroup; m_groupId = id; } /************************************************************************************************************************************/ /* Different methods */ /************************************************************************************************************************************/ /** \details Get 'Repetitions' number of product occurance or part definition */ unsigned int getNumRepetitionsOfObject(const OdPrcObjectId& objId, prcFileStructureHandleToPOAndPartDefRepeatMap* pRepeatMap) { if (objId.isNull()) return 0; if (pRepeatMap == nullptr) return 0; OdPrcFileStructurePtr pFS = objId.database(); if (pFS.isNull()) return 0; OdDbHandle dbHandle = pFS->objectId().getHandle(); OdDbHandle poHandle = objId.getHandle(); unsigned int nRepetitions = 0; prcFileStructureHandleToPOAndPartDefRepeatMap::iterator it = pRepeatMap->find(dbHandle); if (it != pRepeatMap->end()) { prcHandleToPOAndPartDefRepeatMap::iterator itPO = it->second.find(poHandle); if (itPO != it->second.end()) nRepetitions = itPO->second; } return nRepetitions; } /** \details Append insert to the Visualize database */ OdTvEntityId appendInsert(OdTvVisualizePrcTraverseFilerContext& ctx, OdTvBlockId blockId) { OdTvEntityId id; OdTvResult tvRes = tvOk; OdString name = ctx.m_strDefaultName; if (!ctx.m_strNameForInsert.isEmpty()) name = ctx.m_strNameForInsert; switch (ctx.m_parentType) { case OdTvVisualizePrcTraverseFilerContext::kModel: id = ctx.m_modelId.openObject(OdTv::kForWrite)->appendInsert(blockId, name, &tvRes); break; case OdTvVisualizePrcTraverseFilerContext::kBlock: id = ctx.m_blockId.openObject(OdTv::kForWrite)->appendInsert(blockId, name, &tvRes); break; case OdTvVisualizePrcTraverseFilerContext::kGroup: id = ctx.m_groupId.openObjectAsGroup(OdTv::kForWrite)->appendInsert(blockId, name, &tvRes); break; } return id; } /** \details Append group to the Visualize database */ OdTvEntityId appendGroup(OdTvVisualizePrcTraverseFilerContext& ctx) { OdTvEntityId id; OdTvResult tvRes = tvOk; switch (ctx.m_parentType) { case OdTvVisualizePrcTraverseFilerContext::kModel: id = ctx.m_modelId.openObject(OdTv::kForWrite)->appendGroup(ctx.m_strDefaultName, &tvRes); break; case OdTvVisualizePrcTraverseFilerContext::kBlock: id = ctx.m_blockId.openObject(OdTv::kForWrite)->appendGroup(ctx.m_strDefaultName, &tvRes); break; case OdTvVisualizePrcTraverseFilerContext::kGroup: id = ctx.m_groupId.openObjectAsGroup(OdTv::kForWrite)->appendGroup(ctx.m_strDefaultName, &tvRes); break; } if (tvRes != tvOk) return OdTvEntityId(); return id; } /** \details Rmove group from the Visualize database */ OdTvResult removeGroup(OdTvEntityId groupId, OdTvVisualizePrcTraverseFilerContext& ctx) { OdTvResult res = tvOk; switch (ctx.m_parentType) { case OdTvVisualizePrcTraverseFilerContext::kModel: res = ctx.m_modelId.openObject(OdTv::kForWrite)->removeEntity(groupId); break; case OdTvVisualizePrcTraverseFilerContext::kBlock: res = ctx.m_blockId.openObject(OdTv::kForWrite)->removeEntity(groupId); break; case OdTvVisualizePrcTraverseFilerContext::kGroup: res = ctx.m_groupId.openObjectAsGroup(OdTv::kForWrite)->removeEntity(groupId); break; } return res; } /** \details Append entity to the Visualize database */ OdTvEntityId appendEntity(const OdString& sNewEntityName, OdTvVisualizePrcTraverseFilerContext& ctx) { OdTvEntityId id; OdTvResult tvRes = tvOk; switch (ctx.m_parentType) { case OdTvVisualizePrcTraverseFilerContext::kModel: id = ctx.m_modelId.openObject(OdTv::kForWrite)->appendEntity(sNewEntityName, &tvRes); break; case OdTvVisualizePrcTraverseFilerContext::kBlock: id = ctx.m_blockId.openObject(OdTv::kForWrite)->appendEntity(sNewEntityName, &tvRes); break; case OdTvVisualizePrcTraverseFilerContext::kGroup: id = ctx.m_groupId.openObjectAsGroup(OdTv::kForWrite)->appendEntity(sNewEntityName, &tvRes); break; } if (tvRes != tvOk) return OdTvEntityId(); return id; } /** \details Rmove entity from the Visualize database */ OdTvResult removeEntity(OdTvEntityId entId, OdTvVisualizePrcTraverseFilerContext& ctx) { OdTvResult res = tvOk; switch (ctx.m_parentType) { case OdTvVisualizePrcTraverseFilerContext::kModel: res = ctx.m_modelId.openObject(OdTv::kForWrite)->removeEntity(entId); break; case OdTvVisualizePrcTraverseFilerContext::kBlock: res = ctx.m_blockId.openObject(OdTv::kForWrite)->removeEntity(entId); break; case OdTvVisualizePrcTraverseFilerContext::kGroup: res = ctx.m_groupId.openObjectAsGroup(OdTv::kForWrite)->removeEntity(entId); break; } return res; } /** \details Method imports geometry representation item through draw of the item */ void drawRepresentationItem(const OdGiDrawable* pDrawable, OdTvEntityId entId, bool bIsBrep, const OdTvVisualizePrcTraitsAssign& traitsAssign, OdTvVisualizePrcTraverseFilerContext& ctx) { if (pDrawable == nullptr) return; if (ctx.m_pGeometryCollector == nullptr) return; //set entity to the geometry collector ctx.m_pGeometryCollector->setEntity(entId, bIsBrep); //play current entity traits (from part definition) traitsAssign.play(ctx.m_pGeometryCollector); //call draw pDrawable->worldDraw(ctx.m_pGeometryCollector); return; } /** \details Method imports markup */ void drawMarkup(OdPrcMarkupPtr markup, const OdTvVisualizePrcTraitsAssign& traitsAssign, OdTvVisualizePrcTraverseFilerContext& ctx) { if (markup.isNull()) return; if (ctx.m_pGeometryCollector == nullptr) return; //create group if need if (ctx.m_pmiGroupId.isNull()) { OdString strDefPrev = ctx.m_strDefaultName; ctx.m_strDefaultName = OD_T("PMI"); ctx.m_pmiGroupId = appendGroup(ctx); ctx.m_strDefaultName = strDefPrev; } //get markup name OdString sMarkupName = markup->name().name(); if (sMarkupName.isEmpty()) sMarkupName.format(L"%s_%d", OD_T("Markup"), nMarkupID++); //append entity OdTvEntityId prevGroupId = ctx.m_groupId; OdTvVisualizePrcTraverseFilerContext::ParentForAdd prevParentType = ctx.m_parentType; ctx.setParentGroup(ctx.m_pmiGroupId); OdTvEntityId entId = appendEntity(sMarkupName, ctx); ctx.m_groupId = prevGroupId; ctx.m_parentType = prevParentType; //set entity to the geometry collector ctx.m_pGeometryCollector->setEntity(entId, false); //play current entity traits (from part definition) traitsAssign.play(ctx.m_pGeometryCollector); //call draw for markup bool bRes = markup->worldDraw(ctx.m_pGeometryCollector); if (!bRes) markup->viewportDraw(ctx.m_pGeometryCollector); //delete entity if empty if (OdTvDatabaseCleaner::clearGeometryLevel(entId.openObject())) //TODO (support subgroups) { prevGroupId = ctx.m_groupId; prevParentType = ctx.m_parentType; ctx.setParentGroup(ctx.m_pmiGroupId); removeEntity(entId, ctx); ctx.m_groupId = prevGroupId; ctx.m_parentType = prevParentType; } else { //apply view dependency if (!ctx.m_curAnnotationTvViewId.isNull()) entId.openObject(OdTv::kForWrite)->addViewDependency(ctx.m_curAnnotationTvViewId); entId.openObject(OdTv::kForWrite)->setSectionable(false); //apply user data ctx.m_pGeometryCollector->setObjectUserData< OdTvEntityPtr >(entId.openObject(OdTv::kForWrite), markup->objectId()); } return; } /** \details Method imports annotation */ void importAnnotations(OdPrcAnnotationEntityPtr pAnnEnt, OdTvVisualizePrcTraverseFilerContext& ctx) { if (pAnnEnt.isNull()) return; if (!pAnnEnt->isKindOf(OdPrcAnnotationItem::desc()) && !pAnnEnt->isKindOf(OdPrcAnnotationSet::desc())) return; //check visibility and get traits OdTvVisualizePrcTraitsAssign traitsAssign(pAnnEnt, ctx); if (traitsAssign.getRemovedBit()) return; if (pAnnEnt->isKindOf(OdPrcAnnotationItem::desc())) { OdPrcAnnotationItemPtr pItem = pAnnEnt; if (!pItem->markup().isNull()) { OdPrcMarkupPtr markup = pItem->markup().safeOpenObject(kForRead); drawMarkup(markup, traitsAssign, ctx); } } else { OdPrcAnnotationSetPtr pSet = pAnnEnt; for (OdUInt32 i = 0; i < pSet->entities().size(); i++) { if (!pSet->entities()[i].isNull()) { OdPrcAnnotationEntityPtr pAnnEnt = pSet->entities()[i].safeOpenObject(kForRead); importAnnotations(pAnnEnt, ctx); } } } return; } /** \details Method imports annotation from view */ void importAnnotationsFromView(OdPrcViewPtr pView, OdTvVisualizePrcTraverseFilerContext& ctx) { if (pView.isNull()) return; //check visibility and get traits OdTvVisualizePrcTraitsAssign traitsAssign(pView, ctx); if (traitsAssign.getRemovedBit()) return; ctx.m_curAnnotationViewId = pView->objectId(); OdGiContextForPrcDatabasePtr pPrcContext = OdGiContextForPrcDatabase::cast(ctx.m_pGeometryCollector->context()); pPrcContext->setAlwaysShow(true); for (OdUInt32 i = 0; i < pView->annotations().size(); ++i) { OdPrcObjectPtr pObj = pView->annotations()[i].openObject(); //ASSUMPTION: we suppose that annotation here can't contain PrcMarkup itself if (pObj->isKindOf(OdPrcAnnotationItem::desc()) || pObj->isKindOf(OdPrcAnnotationSet::desc())) { OdPrcAnnotationEntityPtr pAnnEnt = pObj; importAnnotations(pAnnEnt, ctx); } } ctx.m_curAnnotationViewId = OdPrcObjectId(); pPrcContext->setAlwaysShow(false); //according PRC-761 prcViewToLinkedItemsMap::iterator itMap = ctx.m_ViewToLinkedItemsMap->find(pView->objectId()); if (itMap != ctx.m_ViewToLinkedItemsMap->end()) { for (auto& elem : itMap->second) { OdPrcObjectPtr pObj = elem.first.safeOpenObject(); if (pObj->isKindOf(OdPrcMarkup::desc())) { OdPrcMarkupPtr markup = pObj; drawMarkup(markup, traitsAssign, ctx); } } } return; } /** \details Method imports geometry from representation item */ void importRepresentationItem(const OdPrcRepresentationItem* pRI, const OdString& sPartName, OdTvVisualizePrcTraitsAssign& traitsAssign, OdTvVisualizePrcTraverseFilerContext& ctx) { if (pRI == nullptr) return; OdString sRepItemName = pRI->name().name(); OdString sNewEntityName = sRepItemName; if (sRepItemName.isEmpty()) { sNewEntityName = sPartName; if (sNewEntityName.isEmpty()) sNewEntityName = ctx.m_strDefaultName; } //check case for prc set if (pRI->isKindOf(OdPrcSet::desc())) { //check visibility and get traits OdTvVisualizePrcTraitsAssign traitsAssignRI(pRI, ctx); if (traitsAssignRI.getRemovedBit()) return; OdPrcSetPtr pSet = pRI; OdString prevstrDefaultName = ctx.m_strDefaultName; ctx.m_strDefaultName = sNewEntityName; OdTvEntityId prevGroupId = ctx.m_groupId; OdTvVisualizePrcTraverseFilerContext::ParentForAdd prevParentType = ctx.m_parentType; OdTvEntityId id = appendGroup(ctx); if (!id.isNull()) { ctx.setParentGroup(id); } for (OdUInt32 i = 0; i < pSet->representationItem().size(); i++) { if (!pSet->representationItem()[i].isNull()) { OdPrcRepresentationItemPtr pChildRI = pSet->representationItem()[i].safeOpenObject(kForRead); importRepresentationItem(pChildRI.get(), sNewEntityName, traitsAssignRI, ctx); } } ctx.m_groupId = prevGroupId; ctx.m_parentType = prevParentType; ctx.m_strDefaultName = prevstrDefaultName; return; } //check that we have deal with a brep bool bIsBrep = false; if (pRI->isKindOf(OdPrcBrepModel::desc())) { OdPrcBrepModelPtr pBrepModel = pRI; bIsBrep = pBrepModel->isClosed(); } else if (pRI->isKindOf(OdPrcPolyBrepModel::desc())) { OdPrcPolyBrepModelPtr pPolyBrepModel = pRI; bIsBrep = pPolyBrepModel->isClosed(); } OdTvEntityId entId = appendEntity(sNewEntityName, ctx); if (!entId.isNull()) { //setups views visiblity setupViewsVisibility(pRI, ctx, entId); //draw representation item drawRepresentationItem(pRI, entId, bIsBrep, traitsAssign, ctx); //remove if empty if (OdTvDatabaseCleaner::clearGeometryLevel(entId.openObject())) //TODO (support subgroups) removeEntity(entId, ctx); else { //apply user data ctx.m_pGeometryCollector->setObjectUserData< OdTvEntityPtr >(entId.openObject(OdTv::kForWrite), pRI->objectId()); if (bIsBrep) { OdTvEntityPtr pEntity = entId.openObject(OdTv::kForWrite); pEntity->setCalculateIsolinesForShells(true, 89.0 * OdaPI / 180.0); pEntity->setNeedCheckShellsTopology(true); } } } return; } /** \details Get or create block for the part definition */ OdTvBlockId getBlockForPartDefinition(const OdPrcPartDefinition* pPD, const OdString& sPartName, OdTvVisualizePrcTraverseFilerContext& ctx, bool& bNewBlock) { OdTvBlockId blockId; bNewBlock = false; //1. check that we already have a block if (ctx.m_pPOAndPartDefBlockMap == nullptr) return OdTvBlockId(); OdPrcFileStructurePtr pFS = pPD->objectId().database(); if (pFS.isNull()) return OdTvBlockId(); OdDbHandle dbHandle = pFS->objectId().getHandle(); OdDbHandle poHandle = pPD->objectId().getHandle(); prcFileStructureToPOAndPartDefTvBlockMap::iterator it = ctx.m_pPOAndPartDefBlockMap->find(dbHandle); if (it != ctx.m_pPOAndPartDefBlockMap->end()) { prcPOAndPartDefTvBlockMap::iterator itPOAndPDef = it->second.find(poHandle); if (itPOAndPDef != it->second.end()) blockId = itPOAndPDef->second; } //Check that exist or empty if (!blockId.isNull() && !blockIsEmpty(blockId)) return blockId; //create new block if (blockId.isNull()) { OdString strBlockName = sPartName; if (strBlockName.isEmpty()) strBlockName = ctx.m_strDefaultName; OdTvResult rc; strBlockName = OdTvDatabaseUtils::fixNameForTvObject(strBlockName, nBlockID); blockId = ctx.m_dbId.openObject(OdTv::kForWrite)->createBlock(strBlockName, &rc); if (rc != tvOk) return OdTvBlockId(); bNewBlock = true; } //7. add newly created block to a map if (it != ctx.m_pPOAndPartDefBlockMap->end()) it->second[poHandle] = blockId; else { prcPOAndPartDefTvBlockMap poMap; poMap[poHandle] = blockId; (*(ctx.m_pPOAndPartDefBlockMap))[dbHandle] = poMap; } return blockId; } /** \details Method imports geometry from part definition */ void importFromPartDefinition(const OdPrcPartDefinition* pPD, OdTvVisualizePrcTraverseFilerContext& ctx) { if (pPD == nullptr) return; //check visibility and get traits OdTvVisualizePrcTraitsAssign traitsAssign(pPD, ctx); if (traitsAssign.getRemovedBit()) return; //get part name OdString sPartName = pPD->name().name(); //get 'repeat' numbers (may be need to have a block) unsigned int nRepeats = getNumRepetitionsOfObject(pPD->objectId(), ctx.m_pRepeatMap); bool bNewBlock = false; OdTvBlockId blockId; if (nRepeats > ctx.m_nRepetitions) blockId = getBlockForPartDefinition(pPD, sPartName, ctx, bNewBlock); OdTvVisualizePrcTraverseFilerContext prevCtx = ctx; if (bNewBlock) { ctx.setParentBlock(blockId); traitsAssign.setDefaultColor(ctx); } if (bNewBlock || blockId.isNull()) { //iterate through the geometry representation OdPrcObjectIdArray::const_iterator pIt = pPD->representationItem().begin(); OdPrcObjectIdArray::const_iterator pEnd = pPD->representationItem().end(); for (; pIt != pEnd; ++pIt) { OdPrcObjectId id = *pIt; if (!id.isNull()) { OdPrcRepresentationItemPtr pObject = id.safeOpenObject(); importRepresentationItem(pObject.get(), sPartName, traitsAssign, ctx); } }//end of for... //need to draw all annotations if (ctx.m_bDefaultViewWasCreated) { //find appropriate TV view auto itV = ctx.m_pViewsMap->find(-1); if (itV != ctx.m_pViewsMap->end()) ctx.m_curAnnotationTvViewId = itV->second; OdPrcObjectIdArray::const_iterator pIt_AnnEnt = pPD->markups().annotationEntities().begin(); OdPrcObjectIdArray::const_iterator pEnd_AnnEnt = pPD->markups().annotationEntities().end(); for (; pIt_AnnEnt != pEnd_AnnEnt; ++pIt_AnnEnt) { OdPrcObjectId id = *pIt_AnnEnt; if (!id.isNull()) { OdPrcAnnotationEntityPtr pAnnEnt = id.safeOpenObject(kForRead); importAnnotations(pAnnEnt, ctx); } } } //import annotations for all view nodes OdPrcObjectIdArray::const_iterator pIt_AnnView = pPD->annotationView().begin(); OdPrcObjectIdArray::const_iterator pEnd_AnnView = pPD->annotationView().end(); for (; pIt_AnnView != pEnd_AnnView; ++pIt_AnnView) { OdPrcObjectId id = *pIt_AnnView; if (!id.isNull()) { //find appropriate tv view auto itVNode = ctx.m_pViewsNodeMap->find(id); if (itVNode != ctx.m_pViewsNodeMap->end()) { auto itV = ctx.m_pViewsMap->find((OdInt32)itVNode->second); if (itV != ctx.m_pViewsMap->end()) ctx.m_curAnnotationTvViewId = itV->second; } OdPrcViewPtr pView = id.safeOpenObject(kForRead); importAnnotationsFromView(pView, ctx); } } //reset Tv annotation view ctx.m_curAnnotationTvViewId.setNull(); //reset PMI group if (!ctx.m_pmiGroupId.isNull() && ctx.m_pmiGroupId.openObjectAsGroup()->isEmpty()) removeGroup(ctx.m_pmiGroupId, ctx); ctx.m_pmiGroupId.setNull(); } //reset in case of block if (bNewBlock) { ctx.m_parentType = prevCtx.m_parentType; ctx.m_groupId = prevCtx.m_groupId; ctx.m_blockId = prevCtx.m_blockId; } //create insert if need if (!blockId.isNull()) { if (!blockIsEmpty(blockId)) { OdTvEntityId id = appendInsert(ctx, blockId); //apply user data ctx.m_pGeometryCollector->setObjectUserData< OdTvInsertPtr >(id.openObjectAsInsert(OdTv::kForWrite), pPD->objectId()); } } return; } /** \details Method which traverses the sons of the product occurance */ void traverseSonsForFillingTV(OdPrcProductOccurrencePtr productOccurrence, OdTvVisualizePrcTraverseFilerContext& ctx) { if (productOccurrence.isNull()) return; //go through the sons const OdPrcObjectIdArray& sons = productOccurrence->referencesOfProductOccurrence().getSonProductOccurrences(); int count = sons.size(); for (int idx = 0; idx < count; ++idx) { OdPrcObjectPtr objPO = sons[idx].openObject(); OdPrcProductOccurrencePtr pPO = (OdPrcProductOccurrence*)objPO.get(); if (!pPO.isNull()) { //check visibility and get traits OdTvVisualizePrcTraitsAssign traitsAssign(pPO, ctx); if (traitsAssign.getRemovedBit()) continue; traverseTreeForFillingTV(pPO, &traitsAssign, ctx, false); } } //got through the prototype if (0 == count) { OdPrcProductOccurrencePtr pProto = productOccurrence->referencesOfProductOccurrence().getPrototypeID().openObject(); if (!pProto.isNull()) { //update parent name OdString sPOName = productOccurrence->name().name(); OdString sProtoPOName = pProto->name().name(); if (sPOName.isEmpty() && !sProtoPOName.isEmpty() && ctx.m_bAllowParentGroupNameChangeFromPrototype) { if (ctx.m_parentType == OdTvVisualizePrcTraverseFilerContext::kGroup && !ctx.m_groupId.isNull()) ctx.m_groupId.openObjectAsGroup(OdTv::kForWrite)->setName(sProtoPOName); } traverseTreeForFillingTV(pProto, nullptr, ctx, true); } } return; } /** \details Method which checks that group should be created for product occurrence */ bool needCreateGroup(OdPrcProductOccurrencePtr productOccurrence, const OdTvVisualizePrcTraitsAssign* pTraitsAssign, OdTvVisualizePrcTraverseFilerContext& ctx) { if (productOccurrence.isNull()) return false; if (productOccurrence->referencesOfProductOccurrence().getSonProductOccurrences().size() != 0) return true; if (!productOccurrence->referencesOfProductOccurrence().getCorrespondingPartDefinition().isNull()) return true; //prototype OdPrcProductOccurrencePtr pProto = productOccurrence->referencesOfProductOccurrence().getPrototypeID().openObject(); if (pProto.isNull()) return true; OdString sPOName = productOccurrence->name().name(); //get 'repeat' numbers unsigned int nRepeats = getNumRepetitionsOfObject(pProto->objectId(), ctx.m_pRepeatMap); if (nRepeats > ctx.m_nRepetitions) // means need block { OdString sProtoPOName = pProto->name().name(); if (!sPOName.isEmpty() || sProtoPOName.isEmpty()) ctx.m_strNameForInsert = ctx.m_strDefaultName; else ctx.m_strNameForInsert = sProtoPOName; //complex_1.prc OdPrcCoordinateSystemPtr pCS = pTraitsAssign->getCoordinateSystemId().openObject(kForRead); if (!pCS.isNull()) ctx.m_transForInsert = pCS->axisSet().getGeMatrix3d(); else if (productOccurrence->getLocation()) ctx.m_transForInsert = productOccurrence->getLocation()->getGeMatrix3d(); return false; } return true; } /** \details Method which traverses product occuarances to fulltill block (if it was not fullfilled yet) */ OdTvBlockId traversePOTreeForFillingBlock(OdPrcProductOccurrencePtr productOccurrence, OdTvVisualizePrcTraverseFilerContext& ctx) { if (productOccurrence.isNull()) return OdTvBlockId(); //ASSUMPTION: we suppose that block will be created for the prototype occurances and we will suppose that such occurances // will have NOT prototypes, references, annotations and annotations views //1. check that we already have a block if (ctx.m_pPOAndPartDefBlockMap == nullptr) return OdTvBlockId(); OdPrcFileStructurePtr pFS = productOccurrence->objectId().database(); if (pFS.isNull()) return OdTvBlockId(); OdDbHandle dbHandle = pFS->objectId().getHandle(); OdDbHandle poHandle = productOccurrence->objectId().getHandle(); unsigned int nRepetitions = 0; OdTvBlockId tvBlockId; prcFileStructureToPOAndPartDefTvBlockMap::iterator it = ctx.m_pPOAndPartDefBlockMap->find(dbHandle); if (it != ctx.m_pPOAndPartDefBlockMap->end()) { prcPOAndPartDefTvBlockMap::iterator itPO = it->second.find(poHandle); if (itPO != it->second.end()) tvBlockId = itPO->second; } //Depending on flags the block can be empty first time. But for the next object it will be not empty. if (!tvBlockId.isNull() && !blockIsEmpty(tvBlockId)) return tvBlockId; //2. copy context OdTvVisualizePrcTraverseFilerContext curCtx = ctx; //3. create new block if (tvBlockId.isNull()) { OdTvResult rc; OdString strBlockName = OdTvDatabaseUtils::fixNameForTvObject(ctx.m_strDefaultName, nBlockID); tvBlockId = curCtx.m_dbId.openObject(OdTv::kForWrite)->createBlock(strBlockName, &rc); if (rc != tvOk) return OdTvBlockId(); } //4. set block to context curCtx.setParentBlock(tvBlockId); //5. import geometry from part definition OdString protoTypeName; OdPrcObjectId partDefId = getPartDefinition(productOccurrence, protoTypeName); if (!partDefId.isNull()) { OdPrcPartDefinitionPtr pPartDef = partDefId.safeOpenObject(); if (!protoTypeName.isEmpty()) { OdString sStrDefaultName = curCtx.m_strDefaultName; curCtx.m_strDefaultName = protoTypeName; importFromPartDefinition(pPartDef, curCtx); curCtx.m_strDefaultName = sStrDefaultName; } else importFromPartDefinition(pPartDef, curCtx); } //6. traverse sons of the product occurances traverseSonsForFillingTV(productOccurrence, curCtx); //7. add newly created block to a map if (it != ctx.m_pPOAndPartDefBlockMap->end()) { it->second[poHandle] = tvBlockId; } else { prcPOAndPartDefTvBlockMap poMap; poMap[poHandle] = tvBlockId; (*(ctx.m_pPOAndPartDefBlockMap))[dbHandle] = poMap; } return tvBlockId; } void fillReferenceMatrix(OdTvVisualizePrcTraverseFilerContext& ctx, const OdPrcObjectId& occurrenceId, const OdTvEntityId& enId, TvViewAnimContainerMap& viewAnimContMap) { for (auto it = ctx.m_ViewToLinkedItemsMap->begin(); it != ctx.m_ViewToLinkedItemsMap->end(); ++it) { // 1. find appropriate OdTvGsViewId OdTvGsViewId viewId; auto itVNode = ctx.m_pViewsNodeMap->find(it->first); if (itVNode != ctx.m_pViewsNodeMap->end()) { auto itV = ctx.m_pViewsMap->find((OdInt32)itVNode->second); if (itV != ctx.m_pViewsMap->end()) viewId = itV->second; } if (viewId.isNull()) continue; // 2. try to find current occurrence in view dependent data std::map::const_iterator mliEntry = it->second.find(occurrenceId); if (mliEntry != it->second.end()) { OdPrcContentEntityReferencePtr pReference = mliEntry->second.openObject(); OdPrcCoordinateSystemPtr pCS = pReference->localCoordinateSystem().openObject(); if (!pCS.isNull()) { // 3. create animation action and add to container related to appropriate OdTvGsViewId OdTvDatabasePtr pTvDb = ctx.m_dbId.openObject(OdTv::kForWrite); OdTvMatrix mtx = pCS->axisSet().getGeMatrix3d(); OdTvSceneIObjectPtr pObj = enId.openAsSceneObject(); OdTvMatrix oMatrix = pObj->getModelingMatrix(); if (!pObj.isNull() && oMatrix != OdTvMatrix::kIdentity) mtx *= oMatrix.invert(); // 3.1 create animation action OdTvResult rc = tvOk; OdTvAnimationActionId actId = pTvDb->createAnimationAction(ctx.m_strDefaultName + OD_T("_ACTION"), true, &rc); if (rc == tvAlreadyExistSameName) { static int cnt = 0; OdString str; OdString curName = ctx.m_strDefaultName + OD_T("_ACTION"); str.format(OD_T("%s_%d"), curName.c_str(), cnt++); actId = pTvDb->createAnimationAction(str, true, &rc); } if (actId.isNull()) continue; { OdTvAnimationActionPtr pAction = actId.openObject(OdTv::kForWrite); pAction->setNumFrames(1); pAction->setFPS(1); pAction->setKeypoint(0, OdTvAnimationAction::kTranslationX, mtx.translation().x); pAction->setKeypoint(0, OdTvAnimationAction::kTranslationY, mtx.translation().y); pAction->setKeypoint(0, OdTvAnimationAction::kTranslationZ, mtx.translation().z); double scaleX = mtx.getCsXAxis().length(); double scaleY = mtx.getCsYAxis().length(); double scaleZ = mtx.getCsZAxis().length(); pAction->setKeypoint(0, OdTvAnimationAction::kScaleX, scaleX); pAction->setKeypoint(0, OdTvAnimationAction::kScaleY, scaleY); pAction->setKeypoint(0, OdTvAnimationAction::kScaleZ, scaleZ); OdGeMatrix3d rotationMatrix = mtx; rotationMatrix[0][0] /= scaleX; rotationMatrix[0][1] /= scaleX; rotationMatrix[0][2] /= scaleX; rotationMatrix[1][0] /= scaleY; rotationMatrix[1][1] /= scaleY; rotationMatrix[1][2] /= scaleY; rotationMatrix[2][0] /= scaleZ; rotationMatrix[2][1] /= scaleZ; rotationMatrix[2][2] /= scaleZ; double rotationX = atan2(rotationMatrix[2][1], rotationMatrix[2][2]); double rotationY = asin(-rotationMatrix[2][0]); double rotationZ = atan2(rotationMatrix[1][0], rotationMatrix[0][0]); pAction->setKeypoint(0, OdTvAnimationAction::kRotationX, rotationX); pAction->setKeypoint(0, OdTvAnimationAction::kRotationY, rotationY); pAction->setKeypoint(0, OdTvAnimationAction::kRotationZ, rotationZ); } // 3.2 create sub item path for actor OdTvSubItemPath path; path.entitiesIds().push_back(enId); // 3.3 add animation to container auto viewAnimContainerPos = viewAnimContMap.find(viewId); if (viewAnimContainerPos != viewAnimContMap.end()) viewAnimContainerPos->second.openObject(OdTv::kForWrite)->addAnimation(path, actId); else { OdTvAnimationContainerId newContId = pTvDb->createAnimationContainer(viewId.openObject()->getName() + OD_T("_CONTAINER")); OdTvAnimationContainerPtr pContainer = newContId.openObject(OdTv::kForWrite); pContainer->addAnimation(path, actId); viewAnimContMap.insert(std::make_pair(viewId, newContId)); // write handle to user data OdUInt64 val = pContainer->getDatabaseHandle(); odSwap8Bytes(&val); OdTvByteUserData* data = new OdTvByteUserData(&val, sizeof(OdUInt64), OdTvByteUserData::kCopyOwn, true); bool alreadyExist = false; OdTvRegAppId appId = pTvDb->registerAppName(OD_TV_RELATED_ANIM_CONTAINER_DATA_NAME, alreadyExist); viewId.openObject(OdTv::kForWrite)->appendUserData(data, appId); } } } } } /** \details Method which traverses the model file data tree and filling Visualize database */ void traverseTreeForFillingTV(OdPrcProductOccurrencePtr productOccurrence, const OdTvVisualizePrcTraitsAssign* pTraitsAssign, OdTvVisualizePrcTraverseFilerContext& ctx, bool bIsPrototypePO, bool bIsRootOccuarance) { if (productOccurrence.isNull()) return; //copy context OdTvVisualizePrcTraverseFilerContext curCtx = ctx; curCtx.m_bAllowParentGroupNameChangeFromPrototype = false; //manage entity references prcProductOccuranceReferenceMap& currentReferences = OdGiContextForPrcDatabase::cast(curCtx.m_pGeometryCollector->context())->references(); prcProductOccuranceReferenceMap oldReferences; if (!bIsPrototypePO) { const OdPrcObjectIdArray* pArrEntityReference = &productOccurrence->entityReference(); { OdPrcObjectId protoId = productOccurrence->referencesOfProductOccurrence().getPrototypeID(); while (pArrEntityReference->isEmpty() && !protoId.isNull()) { OdPrcProductOccurrencePtr pProtPO = protoId.safeOpenObject(); pArrEntityReference = &pProtPO->entityReference(); protoId = pProtPO->referencesOfProductOccurrence().getPrototypeID(); } } //apply references addReferencesToMap(*pArrEntityReference, currentReferences, oldReferences); } //get 'repeat' numbers unsigned int nRepeats = getNumRepetitionsOfObject(productOccurrence->objectId(), curCtx.m_pRepeatMap); //manage names OdString sPOName = productOccurrence->name().name(); OdString sName = sPOName; if (sName.isEmpty()) sName = curCtx.m_strDefaultName; curCtx.m_strDefaultName = sName; if (nRepeats > curCtx.m_nRepetitions) // means need block { // check visiblity of insert contents. If 'PRC_GRAPHICS_Show'was not set the contents of the prototype // will not be vectorized (block empty). But for the other ocurarnce the same block could be not empty. // Thus we need to check the flag and to control should we add insert or not bool bVisible = true; OdGiContextForPrcDatabasePtr pCtx = OdGiContextForPrcDatabase::cast(curCtx.m_pGeometryCollector->context()); if (!pCtx.isNull()) bVisible = GETBIT(pCtx->graphicsValuesStorage().getCurrentBits(), PRC_GRAPHICS_Show); //create a block curCtx.m_nRepetitions = nRepeats; OdTvBlockId blockId = traversePOTreeForFillingBlock(productOccurrence, curCtx); if (bVisible && !blockId.isNull()) // check that block is not empty and insert visible { if (!blockIsEmpty(blockId)) { OdTvEntityId id = appendInsert(curCtx, blockId); //apply user data curCtx.m_pGeometryCollector->setObjectUserData< OdTvInsertPtr >(id.openObjectAsInsert(OdTv::kForWrite), productOccurrence->objectId()); if (!bIsPrototypePO) { //apply traits pTraitsAssign->play(id, curCtx); //apply transform if exist if (productOccurrence->getLocation()) id.openObjectAsInsert(OdTv::kForWrite)->setBlockTransform(productOccurrence->getLocation()->getGeMatrix3d()); fillReferenceMatrix(curCtx, productOccurrence->objectId(), id, ctx.m_viewAnimContainerMap); } else { //here it is need to use incoming context 'ctx'. Not a copy 'curCtx' id.openObjectAsInsert(OdTv::kForWrite)->setBlockTransform(ctx.m_transForInsert); ctx.m_transForInsert = OdTvMatrix(); ctx.m_strNameForInsert = OdString(); } } } //remove references if (!bIsPrototypePO) restoreReferencesMap(currentReferences, oldReferences); return; } else { if (!bIsPrototypePO && !bIsRootOccuarance) { //ASSUMPTION: we supposed that if occurrence have not sons and part definitions, we should not create a separate group // it will be empty of with prototype if (needCreateGroup(productOccurrence, pTraitsAssign, curCtx)) { //create a OdTvGroup OdTvEntityId id = appendGroup(curCtx); if (!id.isNull()) { curCtx.setParentGroup(id); curCtx.m_bAllowParentGroupNameChangeFromPrototype = true; } //apply traits pTraitsAssign->play(id, curCtx); // apply modeling matrix if (productOccurrence->getLocation()) id.openObjectAsGroup(OdTv::kForWrite)->setModelingMatrix(productOccurrence->getLocation()->getGeMatrix3d()); //apply user data curCtx.m_pGeometryCollector->setObjectUserData(id.openObjectAsGroup(OdTv::kForWrite), productOccurrence->objectId()); fillReferenceMatrix(curCtx, productOccurrence->objectId(), id, ctx.m_viewAnimContainerMap); } } //import geometry from part definition OdString protoTypeName; OdPrcObjectId partDefId = getPartDefinition(productOccurrence, protoTypeName); if (!partDefId.isNull()) { OdPrcPartDefinitionPtr pPartDef = partDefId.safeOpenObject(); if (!protoTypeName.isEmpty()) { OdString sStrDefaultName = curCtx.m_strDefaultName; curCtx.m_strDefaultName = protoTypeName; importFromPartDefinition(pPartDef, curCtx); curCtx.m_strDefaultName = sStrDefaultName; } else importFromPartDefinition(pPartDef, curCtx); } //traverse sons of the product occurances traverseSonsForFillingTV(productOccurrence, curCtx); //traverse and import markups if (!bIsPrototypePO) { const OdPrcObjectIdArray* pArrAnnotationViews = &productOccurrence->annotationViews(); { OdPrcObjectId protoId = productOccurrence->referencesOfProductOccurrence().getPrototypeID(); while (pArrAnnotationViews->isEmpty() && !protoId.isNull()) { OdPrcProductOccurrencePtr pProtPO = protoId.safeOpenObject(); pArrAnnotationViews = &pProtPO->annotationViews(); protoId = pProtPO->referencesOfProductOccurrence().getPrototypeID(); } } const OdPrcObjectIdArray* pArrAnnotationEntities = &productOccurrence->markups().annotationEntities(); { OdPrcObjectId protoId = productOccurrence->referencesOfProductOccurrence().getPrototypeID(); while (pArrAnnotationEntities->isEmpty() && !protoId.isNull()) { OdPrcProductOccurrencePtr pProtPO = protoId.safeOpenObject(); pArrAnnotationEntities = &pProtPO->markups().annotationEntities(); protoId = pProtPO->referencesOfProductOccurrence().getPrototypeID(); } } //need to draw all annotations if (curCtx.m_bDefaultViewWasCreated) { //find appropriate TV view auto itV = curCtx.m_pViewsMap->find(-1); if (itV != curCtx.m_pViewsMap->end()) curCtx.m_curAnnotationTvViewId = itV->second; OdPrcObjectIdArray::const_iterator pIt_AnnEnt = pArrAnnotationEntities->begin(); OdPrcObjectIdArray::const_iterator pEnd_AnnEnt = pArrAnnotationEntities->end(); for (; pIt_AnnEnt != pEnd_AnnEnt; ++pIt_AnnEnt) { OdPrcObjectId id = *pIt_AnnEnt; if (!id.isNull()) { OdPrcAnnotationEntityPtr pAnnEnt = id.safeOpenObject(kForRead); importAnnotations(pAnnEnt, curCtx); } } } //import annotations for all view nodes OdPrcObjectIdArray::const_iterator pIt_AnnView = pArrAnnotationViews->begin(); OdPrcObjectIdArray::const_iterator pEnd_AnnView = pArrAnnotationViews->end(); for (; pIt_AnnView != pEnd_AnnView; ++pIt_AnnView) { OdPrcObjectId id = *pIt_AnnView; if (!id.isNull()) { //find appropriate tv view auto itVNode = curCtx.m_pViewsNodeMap->find(id); if (itVNode != curCtx.m_pViewsNodeMap->end()) { auto itV = curCtx.m_pViewsMap->find((OdInt32)itVNode->second); if (itV != curCtx.m_pViewsMap->end()) curCtx.m_curAnnotationTvViewId = itV->second; } OdPrcViewPtr pView = id.safeOpenObject(kForRead); importAnnotationsFromView(pView, curCtx); } } //reset Tv annotation view curCtx.m_curAnnotationTvViewId.setNull(); //reset PMI group if (!curCtx.m_pmiGroupId.isNull() && curCtx.m_pmiGroupId.openObjectAsGroup(OdTv::kForRead)->isEmpty()) removeGroup(curCtx.m_pmiGroupId, curCtx); curCtx.m_pmiGroupId.setNull(); } //remove references if (!bIsPrototypePO) restoreReferencesMap(currentReferences, oldReferences); }// not a block return; } /** \details Method which traverses product occuarances tree */ void traversePOTree(OdPrcProductOccurrencePtr productOccurrence, prcFileStructureHandleToPOAndPartDefRepeatMap& repeatMap) { if (productOccurrence.isNull()) return; //increase repeat counter OdPrcFileStructurePtr pFS = productOccurrence->objectId().database(); if (pFS.isNull()) return; OdDbHandle dbHandle = pFS->objectId().getHandle(); OdDbHandle poHandle = productOccurrence->objectId().getHandle(); prcFileStructureHandleToPOAndPartDefRepeatMap::iterator it = repeatMap.find(dbHandle); if (it != repeatMap.end()) { prcHandleToPOAndPartDefRepeatMap::iterator itPO = it->second.find(poHandle); if (itPO != it->second.end()) itPO->second++; else { it->second[poHandle] = 1; } } else { prcHandleToPOAndPartDefRepeatMap poMap; poMap[poHandle] = 1; repeatMap[dbHandle] = poMap; } //check part definition OdString temp; OdPrcObjectId partDefId = getPartDefinition(productOccurrence, temp); if (!partDefId.isNull()) { OdPrcPartDefinitionPtr pPartDef = partDefId.safeOpenObject(); if (!pPartDef.isNull()) { //increase repeat counter OdPrcFileStructurePtr pFS = partDefId.database(); if (pFS.isNull()) return; OdDbHandle dbHandlePdef = pFS->objectId().getHandle(); OdDbHandle pdefHandle = partDefId.getHandle(); prcFileStructureHandleToPOAndPartDefRepeatMap::iterator it = repeatMap.find(dbHandlePdef); if (it != repeatMap.end()) { prcHandleToPOAndPartDefRepeatMap::iterator itPDef = it->second.find(pdefHandle); if (itPDef != it->second.end()) itPDef->second++; else { it->second[pdefHandle] = 1; } } else { prcHandleToPOAndPartDefRepeatMap pdefMap; pdefMap[pdefHandle] = 1; repeatMap[dbHandlePdef] = pdefMap; } } } //go through the sons const OdPrcObjectIdArray& sons = productOccurrence->referencesOfProductOccurrence().getSonProductOccurrences(); int count = sons.size(); for (int idx = 0; idx < count; ++idx) { OdPrcObjectPtr objPO = sons[idx].openObject(); OdPrcProductOccurrencePtr pPO = (OdPrcProductOccurrence*)objPO.get(); if (!pPO.isNull()) traversePOTree(pPO, repeatMap); } //got through the prototype if (0 == count) { OdPrcProductOccurrencePtr pProto = productOccurrence->referencesOfProductOccurrence().getPrototypeID().openObject(); if (!pProto.isNull()) traversePOTree(pProto, repeatMap); } return; } /** \details Import data from start occuarance to Visualize model */ OdTvResult fillModel(OdPrcProductOccurrencePtr rootProductOccurrence, OdTvModelId& tvModelId, const OdTvVisualizePrcTraitsAssign* pTraitsAssign, OdTvVisualizePrcTraverseFilerContext& ctx) { if (rootProductOccurrence.isNull()) return tvInvalidInput; ctx.m_pGeometryCollector->setObjectUserData(tvModelId.openObject(OdTv::kForWrite), rootProductOccurrence->objectId()); //fill map for occurances with repeat numbers traversePOTree(rootProductOccurrence, *(ctx.m_pRepeatMap)); //set number of repetitions for the current root occuarance ctx.m_nRepetitions = 1; //call main traverse method traverseTreeForFillingTV(rootProductOccurrence, pTraitsAssign, ctx, false, true); return tvOk; } /** \details Function creates camera object for each view connects camera and view */ OdTvResult createCamerasForTheViews(OdPrcFilePtr pDb, const prcViewNodeToTvViewMap& viewsMap, OdTvModelId modelId, OdTvVisualize2PrcTimer* pTimer) { if (pDb.isNull()) return tvInvalidInput; if (modelId.isNull()) return tvInvalidInput; //get all view nodes const OdArray& views = pDb->getViewNodes(false); //true already was during viewport import OdTvModelPtr pModel = modelId.openObject(OdTv::kForWrite); if (pModel.isNull()) return tvInvalidInput; OdTvDatabaseId dbId = pModel->getDatabase(); bool bExist = false; OdTvRegAppId regAppId = dbId.openObject(OdTv::kForWrite)->registerAppName(OdTvLinkedCameraUserData, bExist); //iterate through the views map for (auto const& vIt : viewsMap) { OdInt32 vID = vIt.first; OdTvGsViewId tvViewId = vIt.second; if (!tvViewId.isNull()) { if (vID == -1) { //create Camera OdTvEntityId cameraId = pModel->appendCamera(tvViewId.openObject()->getName()); OdTvCameraPtr pTvCamera = cameraId.openObjectAsCamera(OdTv::kForWrite); pTvCamera->setupCamera(OdTvPoint(-0.90612681748501411, -0.37532908821626582, 0.19509553088993711), OdTvPoint::kOrigin, OdTvVector(0.18024483319542611, 0.074659669699104828, 0.98078424427943056)); pTvCamera->setViewParameters(100., 100.); pTvCamera->setDisplayGlyph(false); //assign view to the camera OdUInt64 h = pTvCamera->getDatabaseHandle(); odSwap8Bytes(&h); OdTvByteUserData* data = new OdTvByteUserData(&h, sizeof(OdUInt64), OdTvByteUserData::kCopyOwn, true); tvViewId.openObject(OdTv::kForWrite)->appendUserData(data, regAppId); } else if ((unsigned int)vID < views.size()) { OdPrcViewPtr pView = views[vID].view.openObject(); if (!pView.isNull()) { OdTvCameraPtr pTvCamera; //get parameters from Prc view OdPrcSceneDisplayParametersPtr pSceneDisplayParams = pView->sceneDisplayParameters().openObject(); if (pSceneDisplayParams.get() && !pSceneDisplayParams->camera().isNull()) // to allow cross sections in views without camera { OdPrcCameraPtr pCamera = pSceneDisplayParams->camera().openObject(); const OdGeMatrix3d& mat = views[vID].matrix; const OdGePoint3d locationCam = mat * pCamera->location(); const OdGePoint3d lookAtCam = mat * pCamera->lookAt(); OdGeVector3d upCam = mat * pCamera->up(); upCam.normalize(); OdTvEntityId cameraId = pModel->appendCamera(tvViewId.openObject()->getName()); pTvCamera = cameraId.openObjectAsCamera(OdTv::kForWrite); pTvCamera->setupCamera(locationCam, lookAtCam, upCam); if (pCamera->orthographic()) pTvCamera->setViewParameters(pCamera->xFov() * 2., pCamera->yFov() * 2., false); else { double focalLength = (lookAtCam - locationCam).length(); double fW = focalLength * tan(pCamera->xFov()); double fH = focalLength * tan(pCamera->yFov()); double lensLength = focalLength * 42./*PERSP_CONST*/ / sqrt(fW * fW + fH * fH); pTvCamera->setLensLength(lensLength); pTvCamera->setViewParameters(fW, fH, true); } pTvCamera->setDisplayGlyph(false); } else if (pView->isAnnotationView() && !pView->isDummyPlane()) { OdGePoint3d locationCam(0., 0., 1.); OdGePoint3d lookAtCam; OdGeVector3d upCam(0., 1., 0.); OdGeMatrix3d mat = views[vID].matrix * pView->plane()->getGeMatrix3d(); locationCam.transformBy(mat); lookAtCam.transformBy(mat); upCam.transformBy(mat); upCam.normalize(); OdTvEntityId cameraId = pModel->appendCamera(tvViewId.openObject()->getName()); pTvCamera = cameraId.openObjectAsCamera(OdTv::kForWrite); pTvCamera->setupCamera(locationCam, lookAtCam, upCam); pTvCamera->setViewParameters(100., 100.); pTvCamera->setDisplayGlyph(false); } //assign view to the camera if (!pTvCamera.isNull()) { OdUInt64 h = pTvCamera->getDatabaseHandle(); odSwap8Bytes(&h); OdTvByteUserData* data = new OdTvByteUserData(&h, sizeof(OdUInt64), OdTvByteUserData::kCopyOwn, true); tvViewId.openObject(OdTv::kForWrite)->appendUserData(data, regAppId); } } } } }//eo for... return tvOk; } /** \details Function which import views, setup them and creates and setup device */ OdTvResult performViewsImport(OdPrcFilePtr pDb, OdTvDatabaseId& tvDbId, prcViewNodeToTvViewMap& viewsMap, prcViewIdToViewNodeMap& viewsNodeMap, prcViewToLinkedItemsMap& viewToLinkedItemMap, OdTvVisualize2PrcTimer* pTimer) { if (pDb.isNull()) return tvInvalidInput; OdTvGsDevicePtr pDevice; { OdTvVisualize2PrcTiming t(pTimer); //create preferable visual styles OdTvDatabaseUtils::createAndApplyPreferableVS(tvDbId, true, false); //update one of the preferable style due to custom gradient background OdTvVisualStyleId visualStyleHiddenId = tvDbId.openObject(OdTv::kForWrite)->findVisualStyle(OD_T("Hidden Line Black")); if (!visualStyleHiddenId.isNull()) { OdTvVisualStylePtr pVisualStyle = visualStyleHiddenId.openObject(OdTv::kForWrite); if (!pVisualStyle.isNull()) pVisualStyle->setOption(OdTvVisualStyleOptions::kFaceColorMode, (OdInt32)OdTvVisualStyleOptions::kBackgroundTexture); } //create device OdTvGsDeviceId deviceId = tvDbId.openObject(OdTv::kForWrite)->createDevice(OD_T("Device")); pDevice = deviceId.openObject(OdTv::kForWrite); //setup device //a. set the palette OdArray > palCpy; OdTvDatabaseUtils::getPaletteForImportDevice(nullptr, palCpy); pDevice->setLogicalPalette(palCpy.asArrayPtr(), 256); //b. setup background color pDevice->setBackgroundColor(ODRGB(64, 64, 64)); //c. make device active pDevice->setActive(true); //d. activate block cache option pDevice->setOption(OdTvGsDevice::kBlocksCache, true); } //Get material for possible future usage OdTvMaterialId sectionMaterialId = tvDbId.openObject()->findMaterial(OD_T("SECTION_MATERIAL [PRC]")); //get all view nodes const OdArray& views = pDb->getViewNodes(); //check that we have default view OdInt32 iDefView = -1; for (OdUInt32 i = 0; i < views.size(); ++i) { OdPrcViewPtr pView = views[i].view.openObject(); if (!pView.isNull()) { if (pView->isDefaultView()) { iDefView = i; //make default view node as current node pDb->setViewNode(i); } } } //eo for... //create basic view (default view should be always) { OdTvVisualize2PrcTiming t(pTimer); OdTvGsViewId defViewId = pDevice->createView(OD_T("Default view [PRC]")); pDevice->addView(defViewId); OdTvGsViewPtr pTvDefView = defViewId.openObject(OdTv::kForWrite); if (!pTvDefView.isNull()) { viewsMap[-1] = defViewId; pTvDefView->setMode(OdTvGsView::kGouraudShaded); pTvDefView->setView(OdTvPoint(-0.90612681748501411, -0.37532908821626582, 0.19509553088993711), OdTvPoint::kOrigin, OdTvVector(0.18024483319542611, 0.074659669699104828, 0.98078424427943056), 100., 100.); //apply custom background setupCustomBackground(tvDbId, pTvDefView); //apply visual style pTvDefView->setVisualStyle(tvDbId.openObject()->getPreferableVisualStyle(OdTvDatabase::kShadedWithIsolines)); if (iDefView == -1) { // since the GS is not setup yet,we can call empty zoom to extents to mark the view. // The action will be performed inside first setupGs OdTvPoint minPt, maxPt; pTvDefView->zoomExtents(minPt, maxPt); pTvDefView->setVisible(true); pTvDefView->setActive(true); } else pTvDefView->setVisible(false); } else pDevice->eraseView(defViewId); } int uniqNum = 0; //create views for (OdUInt32 i = 0; i < views.size(); ++i) { OdPrcViewPtr pView = views[i].view.openObject(); if (!pView.isNull()) { //remember connect between view and view node viewsNodeMap[views[i].view] = i; //fulfill linked items map if (!pView->linkedItems().isEmpty()) { std::pair mapElement = viewToLinkedItemMap.insert(std::make_pair(views[i].view, prcViewsLinkedItemsMap())); for (OdPrcObjectIdArray::const_iterator pIt = pView->linkedItems().begin(); pIt != pView->linkedItems().end(); ++pIt) { if (pIt->safeOpenObject()->isKindOf(OdPrcMarkupLinkedItem::desc())) //874631_Pump_Assembly.prc, the last one view("08-EXPLODED[VIEW0019/*]") has OdPrcAnnotationSet here. { OdPrcMarkupLinkedItemPtr pMLI = pIt->safeOpenObject(); OdPrcObjectId objEntity = pMLI->referenceData().referenceOnPRCBase(); if (!objEntity.isNull()) mapElement.first->second[objEntity] = pMLI->objectId(); } } if (mapElement.first->second.empty()) viewToLinkedItemMap.erase(mapElement.first); } //get name OdString strViewName = pView->name().name(); if (strViewName.isEmpty()) strViewName = OdString().format(L"[%d]", i); strViewName = OdTvDatabaseUtils::fixNameForTvObject(strViewName, i); if (pView->isAnnotationView()) strViewName += OD_T("_Annotation"); //need since the view names can be repeated { OdTvVisualize2PrcTiming t(pTimer); //create view OdTvResult rc = tvOk; OdTvGsViewId viewId = pDevice->createView(strViewName, true, &rc); if (rc == tvAlreadyExistSameName) { strViewName += OdString().format(L"_%d", uniqNum++); viewId = pDevice->createView(strViewName); } if (viewId.isNull()) continue; //add view to the device pDevice->addView(viewId); //setup view { OdTvGsViewPtr pTvView = viewId.openObject(OdTv::kForWrite); if (!pTvView.isNull()) { pTvView->setVisible(false); viewsMap[i] = viewId; OdPrcSceneDisplayParametersPtr pSceneDisplayParams = pView->sceneDisplayParameters().openObject(); if (pSceneDisplayParams.get() && !pSceneDisplayParams->camera().isNull()) { OdPrcCameraPtr pCamera = pSceneDisplayParams->camera().openObject(); const OdGeMatrix3d& mat = views[i].matrix; const OdGePoint3d locationCam = mat * pCamera->location(); const OdGePoint3d lookAtCam = mat * pCamera->lookAt(); OdGeVector3d upCam = mat * pCamera->up(); upCam.normalize(); if (pCamera->orthographic()) pTvView->setView(locationCam, lookAtCam, upCam, pCamera->xFov() * 2., pCamera->yFov() * 2., OdTvGsView::kParallel); else { double focalLength = (lookAtCam - locationCam).length(); double fW = focalLength * tan(pCamera->xFov()); double fH = focalLength * tan(pCamera->yFov()); double lensLength = focalLength * 42./*PERSP_CONST*/ / sqrt(fW * fW + fH* fH); pTvView->setLensLength(lensLength); pTvView->setView(locationCam, lookAtCam, upCam, fW, fH, OdTvGsView::kPerspective); } } else if (pView->isAnnotationView() && !pView->isDummyPlane()) { OdGePoint3d locationCam(0., 0., 1.); OdGePoint3d lookAtCam; OdGeVector3d upCam(0., 1., 0.); OdGeMatrix3d mat = views[i].matrix * pView->plane()->getGeMatrix3d(); locationCam.transformBy(mat); lookAtCam.transformBy(mat); upCam.transformBy(mat); upCam.normalize(); pTvView->setView(locationCam, lookAtCam, upCam, 100., 100.); } //setup clipping plane if (pSceneDisplayParams.get()) { //get clipping info OdPrcSurfacePtrArray& viewClippingPlanes = pSceneDisplayParams->clippingPlanes(); if (!viewClippingPlanes.isEmpty()) { // Setup traits resolver for section geometry OdTvSectionGeometryOutputPtr pSectionGeometry = OdTvSectionGeometryOutput::createObject(); pSectionGeometry->traitsOverrides()->setColor(OdTvColorDef(179, 179, 179)); //TEMP: for test VIS-3731 //pSectionGeometry->traitsOverrides()->setColor(OdTvColorDef(255, 0, 0)); //pSectionGeometry->traitsOverrides()->setLineWeight(3); pSectionGeometry->setNonSectionableGeometryClipping(false); pSectionGeometry->enableOpenedSectionsOutput(true); pSectionGeometry->enableOutputOfClosedSectionsAsShellWithPolylines(true); pSectionGeometry->setSectionToleranceOverride(1.0e-3); //clipping boundary object OdTvPlanarClipBoundary boundary; // Setup clipping planes OdTvPlanarClipBoundary::ClipPlaneArray tvClipPlanes; for (OdPrcSurfacePtrArray::iterator it = viewClippingPlanes.begin(); it != viewClippingPlanes.end(); ++it) { //check that type is plane if (!(*it)->isKindOf(OdPrcPlane::desc())) { continue; } // check that plane is plane OdGeSurface* pSurf = NULL; OdResult result = (*it)->getOdGeSurface(pSurf); std::unique_ptr autoDelete(pSurf); if (!pSurf || (result != eOk)) { continue; } if (pSurf->type() != OdGe::kPlane) { continue; } OdGePlane* pPlane = (OdGePlane*)(pSurf); tvClipPlanes.push_back(OdTvPlanarClipBoundary::ClipPlane(pPlane->pointOnPlane().transformBy(views[i].matrix), -pPlane->normal().transformBy(views[i].matrix))); } if (!tvClipPlanes.isEmpty()) { //Material for override if (sectionMaterialId.isNull()) { sectionMaterialId = tvDbId.openObject(OdTv::kForWrite)->createMaterial(OD_T("SECTION_MATERIAL [PRC]")); OdTvMaterialPtr pMaterial = sectionMaterialId.openObject(OdTv::kForWrite); if (!pMaterial.isNull()) { OdTvMaterialMap materialMap; pMaterial->setDiffuse(OdTvMaterialColor(OdTvColorDef(136, 136, 136)), materialMap); pMaterial->setAmbient(OdTvMaterialColor(OdTvColorDef(0, 0, 0))); } } pSectionGeometry->traitsOverrides()->setMaterial(sectionMaterialId); boundary.setClipPlanes(tvClipPlanes); boundary.setSectionGeometryOutput(pSectionGeometry); //set 3D clipping for the view pTvView->set3DClipping(&boundary); } } } //set mode pTvView->setMode(OdTvGsView::kGouraudShaded); if (i == iDefView) { pTvView->setVisible(true); pTvView->setActive(true); } //apply custom background setupCustomBackground(tvDbId, pTvView); //apply visual style pTvView->setVisualStyle(tvDbId.openObject()->getPreferableVisualStyle(OdTvDatabase::kShadedWithIsolines)); if (i == iDefView) { // since the GS is not setup yet,we can call empty zoom to extens to mark the view. // The action will be performed inside first setupGs OdTvPoint minPt, maxPt; pTvView->zoomExtents(minPt, maxPt); } } else pDevice->eraseView(viewId); } } } } //eo for... return tvOk; } /** \details Main method for importing data from PRC to Visualize */ OdTvResult performDirectImport(OdPrcFilePtr pDb, OdTvDatabaseId& tvDbId, bool bNeedClearEmpty, double facetResForBrep, bool bImportBrepAsBrep, OdArray& outModels, prcViewNodeToTvViewMap& outViews, double& tvTime) { if (pDb.isNull()) return tvInvalidInput; nMarkupID = 1; nBlockID = 1; nModelID = 1; //get PRC units double addUnitCoefToMeters(1.0); OdTv::Units tvUnits = convertPrcUnitToVisualize(pDb->unit(), addUnitCoefToMeters); // set option for drawing breps if (bImportBrepAsBrep && pDb->getTESSDRAWMODE() == 0) pDb->setTESSDRAWMODE(1); //get filename as the default name for the model OdString strDefaultModelName = pDb->getFilename(); //create timer object OdPerfTimerBase* pTimer = OdPerfTimerBase::createTiming(); OdTvVisualize2PrcTimer timer(pTimer); //import views prcViewIdToViewNodeMap viewsNodeMap; prcViewToLinkedItemsMap viewToLinkedItemMap; OdTvResult rc = performViewsImport(pDb, tvDbId, outViews, viewsNodeMap, viewToLinkedItemMap, &timer); if (rc != tvOk || outViews.empty()) return rc; //create geometry collector objects (custom font folder will be empty) OdTvVisualize2PrcGeomCollector geometryCollector(tvDbId, pDb, strDefaultModelName, facetResForBrep, bImportBrepAsBrep, &timer); //create maps and context prcFileStructureHandleToPOAndPartDefRepeatMap repeatMap; prcFileStructureToPOAndPartDefTvBlockMap blocksMap; OdTvVisualizePrcTraverseFilerContext ctx(&geometryCollector, &repeatMap, &blocksMap, &outViews, &viewsNodeMap); ctx.m_dbId = tvDbId; ctx.m_pDb = pDb; ctx.m_bDefaultViewWasCreated = (outViews.find(-1) != outViews.end()); ctx.m_ViewToLinkedItemsMap = &viewToLinkedItemMap; //get model file data const OdPrcModelFileData& modelFileData = pDb->modelFileData(); //Iterate through the start ocurances, create tv model for each and fill each const OdPrcObjectIdArray& roots = modelFileData.getStartRootOccurrences(); OdUInt32 countRoots = roots.size(); for (OdUInt32 idx = 0; idx < countRoots; idx++) { OdPrcProductOccurrencePtr rootProductOccurrence = roots[idx].safeOpenObject(); if (!rootProductOccurrence.isNull()) { OdString tvModelName = rootProductOccurrence->name().name(); if (tvModelName.isEmpty()) { if (countRoots == 1) tvModelName = strDefaultModelName; else { OdString str; str.format(L"_%d", idx+1); tvModelName = strDefaultModelName + str; } } ctx.m_strDefaultName = tvModelName; //check visibility and get traits OdTvVisualizePrcTraitsAssign traitsAssign(rootProductOccurrence, ctx); if (traitsAssign.getRemovedBit()) continue; //create model OdTvModelId tvModelId; { OdTvVisualize2PrcTiming t(&timer); tvModelName = OdTvDatabaseUtils::fixNameForTvObject(tvModelName, nModelID); tvModelId = tvDbId.openObject(OdTv::kForWrite)->createModel(tvModelName); //update geometry collector name geometryCollector.setPrefixName(OdTvDatabaseUtils::getFileNameFromPath(strDefaultModelName) + OD_T("_" + tvModelName)); //apply transform if exist OdPrcCoordinateSystemPtr pCS = traitsAssign.getCoordinateSystemId().openObject(kForRead); if (!pCS.isNull() && !tvModelId.isNull()) tvModelId.openObject(OdTv::kForWrite)->setModelingMatrix(pCS->axisSet().getGeMatrix3d()); else if (rootProductOccurrence->getLocation()) tvModelId.openObject(OdTv::kForWrite)->setModelingMatrix(rootProductOccurrence->getLocation()->getGeMatrix3d()); } ctx.m_modelId = tvModelId; //fill models with geometry OdTvResult res = fillModel(rootProductOccurrence, tvModelId, &traitsAssign, ctx); if (res != tvOk) { tvDbId.openObject(OdTv::kForWrite)->removeModel(tvModelId); if (countRoots == 1) { tvTime = timer.time(); OdPerfTimerBase::destroyTiming(pTimer); return res; } else return tvWarning; } else if (bNeedClearEmpty) { if (OdTvDatabaseCleaner::cleanTvModel(tvModelId)) { OdTvVisualize2PrcTiming t(&timer); tvDbId.openObject(OdTv::kForWrite)->removeModel(tvModelId); } else { if (!tvModelId.isNull()) { outModels.push_back(tvModelId); tvModelId.openObject(OdTv::kForWrite)->setUnits(tvUnits, tvUnits == OdTv::kUserDefined ? addUnitCoefToMeters : 1.); } } } else { if (!tvModelId.isNull()) { outModels.push_back(tvModelId); tvModelId.openObject(OdTv::kForWrite)->setUnits(tvUnits, tvUnits == OdTv::kUserDefined ? addUnitCoefToMeters : 1.); } } } }// eo for... //remove empty blocks { OdTvDatabasePtr pTvDb = tvDbId.openObject(OdTv::kForWrite); OdTvBlocksIteratorPtr pBlocksIterator = pTvDb->getBlocksIterator(); if (!pBlocksIterator.isNull()) { while (!pBlocksIterator->done()) { OdTvBlockId blockId = pBlocksIterator->getBlock(); pBlocksIterator->step(); if (!blockId.isNull()) { if (blockIsEmpty(blockId)) pTvDb->removeBlock(blockId); } } } } //add models to the views for (auto const& it : outViews) { OdTvGsViewPtr pTvView = it.second.openObject(OdTv::kForWrite); if (!pTvView.isNull()) { for (OdUInt32 i = 0; i < outModels.size(); i++) pTvView->addModel(outModels[i]); } } //add cameras to the imported views createCamerasForTheViews(pDb, outViews, outModels[0], &timer); tvTime = timer.time(); OdPerfTimerBase::destroyTiming(pTimer); return tvOk; }