/////////////////////////////////////////////////////////////////////////////// // 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 "NwViewsImport.h" #define STL_USING_LIST #include "OdaSTL.h" //kernel #include "MemoryStream.h" #include "AbstractViewPE.h" #include "OdIesnaFile.h" #include "DynamicLinker.h" //tv #include "TvGsView.h" #include "TvDatabase.h" #include "Tools/TvMarkupDraggers.h" #include "TvModuleNames.h" //nw #include "NwDatabase.h" #include "NwSavedViewpoint.h" #include "NwSavedFolderViewItem.h" #include "NwSavedViewpointAnimation.h" #include "NwSavedViewpointAnimationCut.h" #include "NwViewpoint.h" #include "NwColor.h" #include "FileOptions/NwHeadlightElement.h" //clipplane #include "NwClipPlaneSet.h" #include "NwClipPlane.h" //redline #include "Redline/NwRedLine.h" #include "Redline/NwRedLineArrow.h" #include "Redline/NwRedLineCloud.h" #include "Redline/NwRedLineEllipse.h" #include "Redline/NwRedLineLine.h" #include "Redline/NwRedLineTag.h" #include "Redline/NwRedLineText.h" //lights #include "Lighting/NwLightItemDistant.h" #include "Lighting/NwLightItemPoint.h" #include "Lighting/NwLightItemSpot.h" #include "Lighting/NwLightItemWeb.h" #include "Lighting/NwLightsElement.h" #include "Lighting/NwLightIntensityUtils.h" #define OD_TV_SAVEDVIEWS_MODEL OD_T("$ODA_TVVIEWER_SAVEDVIEWS") //help structure for getting useful; parameters from OdNwViewpoint for correct view's setting struct NwImportParamsForTvView { void fillFromNwViewpoint(const OdNwObjectId& nwViewId, const OdTvDatabaseId& tvDbId) { OdNwViewpointPtr pNwCurView = nwViewId.safeOpenObject(); //if it's 'head light' mode - then set one default light from view point if (!pNwCurView->hasLighting() || pNwCurView->getLighting() == NwLightType::HEAD_LIGHT) { m_defaultLightingEnable = true; m_tvDefLightingType = OdTvGsView::kUserDefined; } //if view has lighting mode, and it's set in 'no light' or 'full light' - shut off view's dfault lighting else if (pNwCurView->getLighting() == NwLightType::NO_LIGHT || pNwCurView->getLighting() == NwLightType::FULL_LIGHT) { m_defaultLightingEnable = false; } //Original CAD lights or, if there are no any, set view default lighing with two lights else if (pNwCurView->getLighting() == NwLightType::SCENE_LIGHT) { //default lighting enabled if there's no kImportLights flag m_defaultLightingEnable = true; m_tvDefLightingType = OdTvGsView::kTwoLights; m_defaultLightIntensity = 1.0; } switch (pNwCurView->getRenderStyle()) { case NwModeType::FULL_RENDER: m_visId = tvDbId.openObject()->findVisualStyle(OD_T("Realistic")); m_tvRenderMode = OdTvGsView::kGouraudShaded; if (pNwCurView->hasLighting() && pNwCurView->getLighting() == NwLightType::NO_LIGHT) { auto visIdNoLights = tvDbId.openObject()->findVisualStyle(OD_T("NwRealisticLightsDisabled")); if (visIdNoLights.isNull()) { auto pTvDb = tvDbId.openObject(OdTv::kForWrite); m_visId = pTvDb->createVisualStyle(OD_T("NwRealisticLightsDisabled"), m_visId); auto pTvVisStyle = m_visId.openObject(OdTv::kForWrite); pTvVisStyle->setOption(OdTvVisualStyleOptions::kFaceLightingQuality, OdInt32(0)); } else m_visId = visIdNoLights; } break; case NwModeType::SHADED: m_visId = tvDbId.openObject()->findVisualStyle(OD_T("Shaded")); m_tvRenderMode = OdTvGsView::kGouraudShaded; if (pNwCurView->hasLighting() && pNwCurView->getLighting() == NwLightType::NO_LIGHT) { auto visIdNoLights = tvDbId.openObject()->findVisualStyle(OD_T("NwShadedLightsDisabled")); if (visIdNoLights.isNull()) { auto pTvDb = tvDbId.openObject(OdTv::kForWrite); m_visId = pTvDb->createVisualStyle(OD_T("NwShadedLightsDisabled"), m_visId); auto pTvVisStyle = m_visId.openObject(OdTv::kForWrite); pTvVisStyle->setOption(OdTvVisualStyleOptions::kFaceLightingQuality, OdInt32(0)); } else m_visId = visIdNoLights; } break; case NwModeType::WIREFRAME: m_visId = tvDbId.openObject()->findVisualStyle(OD_T("Wireframe")); m_tvRenderMode = OdTvGsView::kWireframe; break; case NwModeType::HIDDEN_LINE: m_visId = tvDbId.openObject()->findVisualStyle(OD_T("Hidden")); m_tvRenderMode = OdTvGsView::kHiddenLine; break; } m_position = pNwCurView->getPosition(); // calculate target point OdTvMatrix mtrxNvView = pNwCurView->getRotation().getMatrix(); m_upVector = mtrxNvView.getCsYAxis(); m_targetVector = mtrxNvView.getCsZAxis(); //pNwCurView object for perspetvie and orthographic view, but focal distance is set enable only for perspective if (pNwCurView->hasFocalDistance()) m_targetVector *= pNwCurView->getFocalDistance(); { OdAbstractViewPEPtr pViewPE(pNwCurView); m_near = pViewPE->frontClipDistance(pNwCurView); m_far = pViewPE->backClipDistance(pNwCurView); } switch (pNwCurView->getProjection()) { case NwViewType::PERSPECTIVE: { m_tvProjection = OdTvGsView::kPerspective; double focalLen = pNwCurView->hasFocalDistance() ? pNwCurView->getFocalDistance() : 1; m_fieldWidth = std::tan(pNwCurView->getHeightField() / 2) * 2 * focalLen * pNwCurView->getViewAspect(); m_fieldHeight = std::tan(pNwCurView->getHeightField() / 2) * 2 * focalLen; break; } case NwViewType::ORTHOGRAPHIC: { m_tvProjection = OdTvGsView::kParallel; m_fieldWidth = pNwCurView->getHeightField() * pNwCurView->getViewAspect(); m_fieldHeight = pNwCurView->getHeightField(); break; } } } OdTvPoint m_position = OdTvPoint(0,0,0); OdTvVector m_upVector = OdTvVector::kYAxis; OdTvVector m_targetVector = OdTvVector::kZAxis; double m_fieldHeight = 1.; double m_fieldWidth = 1.; double m_near = 1.; double m_far = 10.; OdTvGsView::Projection m_tvProjection = OdTvGsView::kParallel; OdTvGsView::RenderMode m_tvRenderMode = OdTvGsView::kGouraudShaded; bool m_defaultLightingEnable = true; OdTvGsView::DefaultLightingType m_tvDefLightingType = OdTvGsView::kOneLight; double m_defaultLightIntensity = 1.0; OdTvVisualStyleId m_visId; }; OdTvModelId getTvServiceModel(const OdTvDatabaseId& tvDbId, const OdTvGsViewId& viewId, const OdString& serviceModelName) { OdTvModelId tvServiceModelId; if (tvDbId.isNull()) return tvServiceModelId; OdTvDatabasePtr pDb = tvDbId.openObject(OdTv::kForWrite); tvServiceModelId = pDb->findModel(serviceModelName); if (tvServiceModelId.isNull()) { tvServiceModelId = pDb->createModel(serviceModelName, OdTvModel::kDirect); if (!viewId.isNull()) viewId.openObject(OdTv::kForWrite)->addModel(tvServiceModelId); } return tvServiceModelId; } void createCameraFromNwViewpoint(const OdNwObjectId& nwViewId, const OdString& sNwViewName, const OdTvGsDeviceId& tvDeviceId) { OdTvGsDevicePtr pTvDevice = tvDeviceId.openObject(OdTv::kForWrite); OdTvModelId tvServiceModelId = getTvServiceModel(pTvDevice->getDatabase(), pTvDevice->getActiveView(), OD_TV_SAVEDVIEWS_MODEL); if (tvServiceModelId.isNull()) return; OdTvResult tvRes = tvOk; OdTvEntityId tvCameraId = tvServiceModelId.openObject(OdTv::kForWrite)->appendCamera(sNwViewName, true, &tvRes); if (tvRes != tvOk) return; auto pTvCamera = tvCameraId.openObjectAsCamera(OdTv::kForWrite); NwImportParamsForTvView nwImportParams; nwImportParams.fillFromNwViewpoint(nwViewId, pTvDevice->getDatabase()); bool isPersp = nwImportParams.m_tvProjection == OdTvGsView::kPerspective; pTvCamera->setAdjustLensLength(true); pTvCamera->setupCamera(nwImportParams.m_position, nwImportParams.m_position - nwImportParams.m_targetVector, nwImportParams.m_upVector); pTvCamera->setViewParameters(nwImportParams.m_fieldWidth, nwImportParams.m_fieldHeight, isPersp); pTvCamera->setDisplayGlyph(false); if (!isPersp) { pTvCamera->setNearClip(true, nwImportParams.m_near); pTvCamera->setFarClip(true, nwImportParams.m_far); } } OdTvGsViewId setupCurrentView(const OdNwObjectId& nwCurViewId, const OdTvGsDeviceId& tvDeviceId, const OdTvModelId& tvModelId, const OdTvGsViewBackgroundId& backgroundId, const bool sheet3d, const OdNwObjectId& nwHeadLightElementId, bool defaultLights) { OdTvGsDevicePtr pTvDevice = tvDeviceId.openObject(OdTv::kForWrite); //if there is no viewpoint from BimNv - then set default TvGsView if (!nwCurViewId) { OdTvGsViewId tvViewId = pTvDevice->createView(OD_T("NW_CurrentViewpoint")); pTvDevice->addView(tvViewId); //setup view OdTvGsViewPtr pView = tvViewId.openObject(OdTv::kForWrite); if (!tvModelId.isNull()) pView->addModel(tvModelId); if (!sheet3d) pView->set2dMode(true); pView->setMode(OdTvGsView::kGouraudShaded); pView->setView(OdTvPoint(0., 0., 1.), OdTvPoint(0., 0., 0.), OdTvVector(0., 1., 0.), 1., 1.); pView->setActive(true); // since the GS is not setup yet,we can call empty zoomtoextens to mark the view. // The action will be performed inside first setupGs OdTvPoint minPt, maxPt; pView->zoomExtents(minPt, maxPt); return tvViewId; } OdString sName = pTvDevice->getName(); OdTvGsViewId tvViewId = pTvDevice->createView(sName.isEmpty() ? OdString(OD_T("NW_CurrentViewpoint")) : sName); pTvDevice->addView(tvViewId); //setup view OdTvGsViewPtr pView = tvViewId.openObject(OdTv::kForWrite); if (!tvModelId.isNull()) pView->addModel(tvModelId); NwImportParamsForTvView nwImportParams; nwImportParams.fillFromNwViewpoint(nwCurViewId, pTvDevice->getDatabase()); //if current view has not default view mode and there is property to set view to default, need to do it if (!nwImportParams.m_defaultLightingEnable && defaultLights) { nwImportParams.m_defaultLightingEnable = true; nwImportParams.m_tvDefLightingType = OdTvGsView::kOneLight; } pView->setMode(nwImportParams.m_tvRenderMode); if (!nwImportParams.m_visId.isNull()) pView->setVisualStyle(nwImportParams.m_visId); OdTvPoint targetPoint = (nwImportParams.m_position - nwImportParams.m_targetVector); pView->setAdjustLensLength(true); pView->setView(nwImportParams.m_position, targetPoint, nwImportParams.m_upVector, nwImportParams.m_fieldHeight, nwImportParams.m_fieldWidth, nwImportParams.m_tvProjection); pView->setActive(true); if (nwImportParams.m_defaultLightingEnable) { pView->enableDefaultLighting(true, nwImportParams.m_tvDefLightingType); if (nwImportParams.m_tvDefLightingType == OdTvGsView::kUserDefined) { pView->setUserDefinedLightDirection(OdTvVector(0, 0, -1)); if (nwHeadLightElementId) { //set head light's ambient and intensity values OdNwHeadlightElementPtr pHeadLightElement = nwHeadLightElementId.openObject(); nwImportParams.m_defaultLightIntensity = pHeadLightElement->getIntensity(); auto dAmbientClr = pHeadLightElement->getAmbient(); pView->setAmbientLightColor(OdTvColorDef(dAmbientClr * 255.0, dAmbientClr * 255.0, dAmbientClr * 255.0)); } else { //if nw file hasn't head light element - set to tv view default value of head light element pView->setAmbientLightColor(OdTvColorDef(0.3 * 255.0, 0.3 * 255.0, 0.3 * 255.0)); } } else { // } pView->setDefaultLightingIntensity(nwImportParams.m_defaultLightIntensity); } else pView->enableDefaultLighting(false); if (nwImportParams.m_tvProjection == OdTvGsView::kParallel) { pView->setFrontClip(true, nwImportParams.m_near); pView->setBackClip(true, nwImportParams.m_far); } if (!backgroundId.isNull()) pView->setBackground(backgroundId); //VAS: need to set AdjustLensLength in false state, because in other case if we will change settings of view(zoom, perspective type and etc.) in application there will be cumulative mathematical error pView->setAdjustLensLength(false); return tvViewId; } void setupSavedViewpoint(OdNwSavedViewpointPtr pSavedViewpoint, const OdString& savedViewpointName, const OdTvGsDeviceId& tvDeviceId, const OdTvModelId& tvModelId) { OdNwObjectIdArray aRedLines; pSavedViewpoint->getRedLineList(aRedLines); if (aRedLines.isEmpty()) { createCameraFromNwViewpoint(pSavedViewpoint->getViewpointId(), savedViewpointName, tvDeviceId); return; } OdTvGsDevicePtr pTvDevice = tvDeviceId.openObject(OdTv::kForWrite); NwImportParamsForTvView nwImportParams; nwImportParams.fillFromNwViewpoint(pSavedViewpoint->getViewpointId(), pTvDevice->getDatabase()); OdTvMatrix eyeTrfm; { OdGeMatrix3d xEyeToWorld; OdTvVector yVector(nwImportParams.m_upVector); yVector.normalize(); OdTvVector zVector(nwImportParams.m_targetVector); zVector.normalize(); OdTvVector xVector = yVector.crossProduct(zVector); eyeTrfm = xEyeToWorld.setCoordSystem(nwImportParams.m_position, xVector, yVector, zVector); } OdTvModelId tvMarkupModelId = getTvServiceModel(pTvDevice->getDatabase(), pTvDevice->getActiveView(), OD_TV_MARKUP_MODEL); if (tvMarkupModelId.isNull()) return; OdTvEntityId entId = tvMarkupModelId.openObject(OdTv::kForWrite)->appendEntity(savedViewpointName); if (entId.isNull()) return; OdTvEntityPtr pMarkupEnt = entId.openObject(OdTv::kForWrite); auto getTvColorFromNwColor = [](const OdNwColor& nwClr) { return OdTvColorDef(nwClr.R() * 255.0, nwClr.G() * 255.0, nwClr.B() * 255.0); }; auto toWorld = [&eyeTrfm](const OdTvPoint2d& pnt) { OdTvPoint wcs(pnt.x, pnt.y, -1.001); wcs.transformBy(eyeTrfm); return wcs; }; OdTvGeometryDataId lines; OdTvGeometryDataId ellipses; OdTvGeometryDataId clouds; OdTvGeometryDataId texts; OdTvGeometryDataId arrows; OdTvGeometryDataId tags; auto createRedlineSubEnt = [&pMarkupEnt](OdTvGeometryDataId& tvParentGeomData, const OdString& sMarkUpType) { if (tvParentGeomData.isNull()) tvParentGeomData = pMarkupEnt->appendSubEntity(sMarkUpType); OdTvEntityPtr pTvParentGeomData = tvParentGeomData.openAsSubEntity(OdTv::kForWrite); OdTvGeometryDataId tvGeomDataId = pTvParentGeomData->appendSubEntity(); return tvGeomDataId.openAsSubEntity(OdTv::kForWrite); }; for (auto& redLineId : aRedLines) { OdNwRedLinePtr pRedline = redLineId.safeOpenObject(); NwRedLineType::Enum type = pRedline->getType(); // line, ellipse, cloud, tag, text, arrow OdUInt32 thikness = pRedline->getLineThikness(); OdUInt32 linePattern = pRedline->getLinePattern(); OdNwColor color = pRedline->getLineColor(); OdTvEntityPtr pRedlineSubEnt; switch (type) { case NwRedLineType::line: { OdNwRedLineLinePtr pRedLine = pRedline; OdGePoint2d start = pRedLine->getStart(); OdGePoint2d end = pRedLine->getEnd(); pRedlineSubEnt = createRedlineSubEnt(lines, OD_T("Lines")); pRedlineSubEnt->appendPolyline(toWorld(start), toWorld(end)); } break; case NwRedLineType::ellipse: { OdNwRedLineEllipsePtr pRedEllipse = pRedline; OdTvPoint2d min = pRedEllipse->getMin(); OdTvPoint2d max = pRedEllipse->getMax(); auto deltaX = (max.x - min.x) * 0.5; auto deltaY = (max.y - min.y) * 0.5; OdGePoint2d centerPnt(min.x + deltaX, min.y + deltaY); OdGePoint2d maxPnt(centerPnt.x + deltaX, centerPnt.y); OdGePoint2d minPnt(centerPnt.x, centerPnt.y + deltaY); pRedlineSubEnt = createRedlineSubEnt(ellipses, OD_T("Ellipses")); pRedlineSubEnt->appendEllipse(toWorld(centerPnt), toWorld(maxPnt), toWorld(minPnt)); } break; case NwRedLineType::cloud: { OdNwRedLineCloudPtr pRedCloud = pRedline; OdArray aPoints = pRedCloud->getPoints(); pRedlineSubEnt = createRedlineSubEnt(clouds, OD_TV_MARKUP_CLOUDS); for (OdUInt32 i = 0; i < aPoints.size(); i += 2) { OdTvPoint lastPt = (i + 2) == aPoints.size() ? toWorld(aPoints[0]) : toWorld(aPoints[i + 2]); pRedlineSubEnt->appendCircleArc(toWorld(aPoints[i]), toWorld(aPoints[i + 1]), lastPt); } } break; case NwRedLineType::tag: { OdNwRedLineTagPtr red = pRedline; OdGeExtents2d pos = red->getPosition(); OdUInt64 tagId = red->getTagId(); pRedlineSubEnt = createRedlineSubEnt(tags, OD_T("Tags")); pRedlineSubEnt->appendPolyline(toWorld(pos.minPoint()), toWorld(pos.maxPoint())); OdTvGeometryDataId tvRedlineTextId = pRedlineSubEnt->appendText(toWorld(pos.maxPoint()), OdString().format(OD_T("%d"), tagId)); tvRedlineTextId.openAsText()->setTextSize(OD_TV_MARKUP_TEXTSIZE); tvRedlineTextId.openAsText()->setNonRotatable(true); } break; case NwRedLineType::text: { OdNwRedLineTextPtr pRedText = pRedline; OdString text = pRedText->getText(); OdTvPoint2d location = pRedText->getLocation(); pRedlineSubEnt = createRedlineSubEnt(texts, OD_TV_MARKUP_TEXT); OdTvGeometryDataId tvRedlineTextId = pRedlineSubEnt->appendText(toWorld(location), text); tvRedlineTextId.openAsText()->setTextSize(OD_TV_MARKUP_TEXTSIZE); tvRedlineTextId.openAsText()->setNonRotatable(true); } break; case NwRedLineType::arrow: { OdNwRedLineArrowPtr pRedArrow = pRedline; OdGePoint2d start = pRedArrow->getStart(); OdGePoint2d end = pRedArrow->getEnd(); OdGeVector2d arrowDir = start - end; auto arrDir0(arrowDir); arrDir0.rotateBy(OdaToRadian(30)); auto arrDir1(arrowDir); arrDir1.rotateBy(OdaToRadian(-30)); OdGePoint2d start0 = end + arrDir0 * 0.1; OdGePoint2d start1 = end + arrDir1 * 0.1; OdGePoint2d start2 = end + arrowDir * 0.05; pRedlineSubEnt = createRedlineSubEnt(arrows, OD_T("Arrow")); pRedlineSubEnt->appendPolyline(toWorld(start), toWorld(end)); OdTvPointArray arrowShell; arrowShell.push_back(toWorld(end)); arrowShell.push_back(toWorld(start0)); arrowShell.push_back(toWorld(start1)); arrowShell.push_back(toWorld(start2)); OdInt32Array arrowShellFaces; arrowShellFaces.push_back(3); // 3 indexes arrowShellFaces.push_back(0); arrowShellFaces.push_back(1); arrowShellFaces.push_back(3); arrowShellFaces.push_back(3); // 3 indexes arrowShellFaces.push_back(0); arrowShellFaces.push_back(2); arrowShellFaces.push_back(3); pRedlineSubEnt->appendShell(arrowShell, arrowShellFaces); } break; } if (!pRedlineSubEnt.isNull()) { pRedlineSubEnt->setLineWeight(thikness); pRedlineSubEnt->setColor(getTvColorFromNwColor(color)); } } // write binary data to entity OdTvSaveViewParams params; params.m_pos = nwImportParams.m_position; params.m_target = nwImportParams.m_position - nwImportParams.m_targetVector; params.m_up = nwImportParams.m_upVector; params.m_width = nwImportParams.m_fieldWidth; params.m_height = nwImportParams.m_fieldHeight; params.m_proj = nwImportParams.m_tvProjection; params.m_mode = nwImportParams.m_tvRenderMode; params.m_modelHandle = tvModelId.openObject()->getDatabaseHandle(); if (nwImportParams.m_tvProjection == OdTvGsView::kParallel) { params.setFrontClip(nwImportParams.m_near); params.setBackClip(nwImportParams.m_far); params.setAdjustLensLength(false); } else params.setAdjustLensLength(true); OdStreamBufPtr pStreamBuff = OdMemoryStream::createNew(); params.write(pStreamBuff); pStreamBuff->rewind(); OdUInt8Array buffer; buffer.resize(pStreamBuff->length()); pStreamBuff->getBytes(buffer.asArrayPtr(), pStreamBuff->length()); // create and append the binary data to the entity OdTvByteUserData* data = new OdTvByteUserData(buffer.asArrayPtr(), pStreamBuff->length(), OdTvByteUserData::kCopyOwn, true); bool alreadyExist = false; OdTvRegAppId regId = pTvDevice->getDatabase().openObject(OdTv::kForWrite)->registerAppName(OdTvNw2VisualizeModuleName, alreadyExist); pMarkupEnt->appendUserData(data, regId); pMarkupEnt->setVisibility(false); } void setupSavedViews(const OdNwObjectId& nwSavedViewsElId, const OdTvGsDeviceId& tvDeviceId, const OdTvModelId& tvModelId) { if (!nwSavedViewsElId) return; OdNwSavedItemsElementPtr pSavedViewsEl = nwSavedViewsElId.openObject(); OdNwObjectIdArray savedViewElements; if (pSavedViewsEl->getSavedItems(savedViewElements) != eOk) return; //VAS: helper collection which contain all names in one branch from hierarchy std::list savedViewNamesInHierarchy; auto getSavedViewName = [&savedViewNamesInHierarchy]() { if (savedViewNamesInHierarchy.empty()) return OdString(); auto itSavedViewName = savedViewNamesInHierarchy.begin(); if (savedViewNamesInHierarchy.size() == 1) return *itSavedViewName; OdString res = *itSavedViewName; ++itSavedViewName; for (;itSavedViewName != savedViewNamesInHierarchy.end(); ++itSavedViewName) { res += OD_T("->") + *itSavedViewName; } return res; }; std::function setupSavedView = [&tvDeviceId, &tvModelId, &setupSavedView, &savedViewNamesInHierarchy, &getSavedViewName](const OdNwObjectId& nwSavedViewId) { OdNwSavedItemPtr pItem = nwSavedViewId.safeOpenObject(); savedViewNamesInHierarchy.push_back(pItem->getDisplayName()); if (pItem->isA() == OdNwSavedViewpoint::desc()) { setupSavedViewpoint(pItem, getSavedViewName(), tvDeviceId, tvModelId); } else if (pItem->isA() == OdNwSavedFolderViewItem::desc()) { OdNwSavedFolderItemPtr pFolder = pItem; OdNwObjectIdArray children_items; if (pFolder->getChildren(children_items) == eOk) { for (auto& childId : children_items) { setupSavedView(childId); } } } else if (pItem->isA() == OdNwSavedViewpointAnimation::desc()) { //make import of animation views } else if (pItem->isA() == OdNwSavedViewpointAnimationCut::desc()) { //make import of animation cut views } else { ODA_ASSERT(!"unchecked OdNwSavedItem's derrived class detected!"); } savedViewNamesInHierarchy.pop_back(); }; for (auto& siId : savedViewElements) { setupSavedView(siId); } } void setupCurrentClipPlane(const OdNwObjectId& nwClipPlaneSetId, const OdTvGsViewId& tvGsViewId) { OdNwClipPlaneSetPtr pClipPlaneSet = nwClipPlaneSetId.safeOpenObject(); NwClipPlaneSetMode::Enum mode = pClipPlaneSet->getMode(); // CL_PLANES or CL_BOX bool isEnabled = pClipPlaneSet->isEnabled(); bool isLinked = pClipPlaneSet->isLinked(); OdUInt32 index = pClipPlaneSet->getCurrentPlaneIndex(); OdGeMatrix3d matrix = pClipPlaneSet->getTransform(); if (isEnabled) { OdTvGsViewPtr pTvGsView = tvGsViewId.openObject(OdTv::kForWrite); if (mode == NwClipPlaneSetMode::CL_BOX) { OdArray aPlanes; if (pClipPlaneSet->getPlanesForActiveMode(aPlanes) == eOk) { for (OdUInt32 i = 0; i < 6; ++i) pTvGsView->addCuttingPlane(aPlanes[i]); } } else { OdResult resCode = eOk; for (OdInt32 cliPlane = 0; cliPlane < 6; ++cliPlane) { OdNwClipPlanePtr pPlane = pClipPlaneSet->getClipPlaneByIndex(cliPlane, &resCode); if (eOk == resCode) { //get pkane state (DEFAULT - switched off or ENABLED - switched on) NwClipPlaneState::Enum state = pPlane->getState(); if (state == NwClipPlaneState::ENABLED) pTvGsView->addCuttingPlane(pPlane->getPlane()); } } } } } namespace { double normalizedSpotFlux(double hotSpotAngle, double fallOfAngle) { auto cosFallOfAngle = cos(fallOfAngle * 0.5); auto cosHotSpotAngle = cos(hotSpotAngle * 0.5); auto temp = log(0.5) / log(cosHotSpotAngle) + 1.0; auto normalizedSpotFlux = Oda2PI / temp; if (OdPositive(cosFallOfAngle)) return normalizedSpotFlux * (1.0 - pow(cosFallOfAngle, temp)); return normalizedSpotFlux; } } void setupLights(const OdTvModelId& tvModelId, std::function getLightsElement, std::function findFile, const OdNwObjectId& nwCurViewId, const OdTvGsViewId& tvGsViewId, OdNwColor* pSceneAmbient) { if (!getLightsElement) { ODA_ASSERT(!OD_T("Uninit getLightsElement parameter for setupLights.")); return; } //if nw database current view in no light or head lights mdoe - skip lights import OdNwViewpointPtr pCurView = nwCurViewId.openObject(); auto curLighting = pCurView->getLighting(); if (pCurView->hasLighting() && curLighting == NwLightType::SCENE_LIGHT) { if (pSceneAmbient) { auto pTvGsView = tvGsViewId.openObject(OdTv::kForWrite); pTvGsView->setAmbientLightColor(OdTvColorDef(255.0 * pSceneAmbient->R(), 255.0 * pSceneAmbient->G(), 255.0 * pSceneAmbient->B())); } } if (auto nwLightElementId = getLightsElement()) { OdNwLightsElementPtr pNwLightsElement = nwLightElementId.openObject(); OdNwObjectIdArray aLights; int i = 0; OdResult res = eOk; if (curLighting == NwLightType::FULL_LIGHT) res = pNwLightsElement->getSavedItems(aLights); else if (curLighting == NwLightType::SCENE_LIGHT) { res = pNwLightsElement->getSceneLights(aLights); if (res == eOk && !aLights.empty()) { auto pTvGsView = tvGsViewId.openObject(OdTv::kForWrite); pTvGsView->enableDefaultLighting(false); } } else res = eNoErrorHandler; if (res == eOk) { for (auto& nwLightItemId : aLights) { OdNwLightItemPtr pNwLightItem = nwLightItemId.openObject(); OdString sName = pNwLightItem->getDisplayName(); OdTvModelPtr pModel = tvModelId.openObject(OdTv::kForWrite); OdTvEntityId tvLightId = pModel->appendLight(sName.isEmpty() ? OdString().format(OD_T("Light_%d"), i++) : sName); OdTvLightPtr pTvLight = tvLightId.openObjectAsLight(OdTv::kForWrite); pTvLight->setOn(pNwLightItem->isLightOn()); if (pNwLightItem->isGlyphDisplay()) pTvLight->setGlyphDisplay(OdTvLight::kGlyphDisplayOn); else pTvLight->setGlyphDisplay(OdTvLight::kGlyphDisplayOff); OdNwColor color = pNwLightItem->getResultClr(); pTvLight->setLightColor(OdTvColorDef(255.0 * color.R(), 255.0 * color.G(), 255.0 * color.B())); OdTvLightAttenuation tvLightAttenuation; //TODO: at current state Visualize API hasn't possibility to set physical lamp intensity and lamp color, but Gi/Gs API has such things, maybe need to add ticket for this auto nwLightIntensity = pNwLightItem->getLampIntensity(); if (pNwLightItem->isKindOf(OdNwLightItemDistant::desc())) { OdNwLightItemDistantPtr pNwDistLightItem = pNwLightItem; pTvLight->setLightType(OdTvLight::kDistantLight); pTvLight->setPosition(pNwDistLightItem->getFrom()); pTvLight->setLightDirection(pNwDistLightItem->getTo() - pNwDistLightItem->getFrom()); } else if (pNwLightItem->isKindOf(OdNwLightItemPoint::desc())) { OdNwLightItemPointPtr pNwPointLightItem = pNwLightItem; pTvLight->setLightType(OdTvLight::kPointLight); pTvLight->setPosition(pNwPointLightItem->getPosition()); auto nwLightDistribution = pNwPointLightItem->getDistribution(); using namespace NwLightIntensityUtils; if (nwLightDistribution == NwLightDistribution::kDiffuse) { convertIntensityToCandella(nwLightIntensity); tvLightAttenuation.setAttenuationType(OdTvLightAttenuation::kInverseSquare); } else if (nwLightDistribution == NwLightDistribution::kIsotropic) { convertIntensityToCandella(nwLightIntensity); tvLightAttenuation.setAttenuationType(OdTvLightAttenuation::kInverseLinear); } } else if (pNwLightItem->isKindOf(OdNwLightItemSpot::desc())) { OdNwLightItemSpotPtr pNwSpotLightItem = pNwLightItem; pTvLight->setLightType(OdTvLight::kSpotLight); pTvLight->setPosition(pNwSpotLightItem->getPosition()); pTvLight->setTargetLocation(pNwSpotLightItem->getTarget()); auto hotSpot = pNwSpotLightItem->getHotSpotAngle(); auto fallOff = pNwSpotLightItem->getFallOffAngle(); pTvLight->setHotspotAndFalloff(hotSpot, fallOff); using namespace NwLightIntensityUtils; convertIntensityToCandella(nwLightIntensity, normalizedSpotFlux(hotSpot, fallOff)); tvLightAttenuation.setAttenuationType(OdTvLightAttenuation::kInverseSquare); } else if (pNwLightItem->isKindOf(OdNwLightItemWeb::desc())) { OdNwLightItemWebPtr pNwWebLightItem = pNwLightItem; auto webState = pNwWebLightItem->getWebState(); if (webState == NwLightWebState::kWebAsSpot) { pTvLight->setLightType(OdTvLight::kSpotLight); pTvLight->setPosition(pNwWebLightItem->getPosition()); pTvLight->setTargetLocation(pNwWebLightItem->getTarget()); auto hotSpot = pNwWebLightItem->getHotSpotAngle(); auto fallOff = pNwWebLightItem->getFallOffAngle(); pTvLight->setHotspotAndFalloff(hotSpot, fallOff); using namespace NwLightIntensityUtils; convertIntensityToCandella(nwLightIntensity, normalizedSpotFlux(hotSpot, fallOff)); tvLightAttenuation.setAttenuationType(OdTvLightAttenuation::kInverseSquare); } else { pTvLight->setLightType(OdTvLight::kWebLight); pTvLight->setPosition(pNwWebLightItem->getPosition()); pTvLight->setTargetLocation(pNwWebLightItem->getTarget()); //Gi/Gs has web rotation vector with degree value - need to convert radian values from BimNv offset OdGeVector3d webOffset = pNwWebLightItem->getRotationOffset(); pTvLight->setWebRotation(OdGeVector3d(OdaToDegree(webOffset.x), OdaToDegree(webOffset.y), OdaToDegree(webOffset.z))); double dIESInitialRatedLumens = -1.; double dIESmaxCandellaIntensity = 1.; OdInt32 nIESCandellaMultiplyingFactor = 1; if (webState == NwLightWebState::kWebFileExternal) { auto sLightIESFile = pNwWebLightItem->getWebFileExternal(); //trying get access to .ies file by path if (findFile && findFile(sLightIESFile)) { //if path is acceptable - then trying to load kernel ies-module and get some usefull data from it OdIesnaLoaderPtr pLoader = ::odrxDynamicLinker()->loadModule(OdIesnaModuleName); if (!pLoader.isNull()) { OdIesnaFilePtr pFile = pLoader->load(sLightIESFile, nullptr); dIESmaxCandellaIntensity = pFile->maxCandela(); pTvLight->setIESFile(sLightIESFile); } } } else if (webState == NwLightWebState::kWebFileEmbedded) { auto pWebIes = pNwWebLightItem->getWebFileEmbedded(); if (!pWebIes.isNull()) { //if path is acceptable - then trying to load kernel ies-module and get some use full data from it OdIesnaLoaderPtr pLoader = ::odrxDynamicLinker()->loadModule(OdIesnaModuleName); if (!pLoader.isNull()) { OdIesnaFilePtr pFile = pLoader->load(pWebIes, nullptr); dIESmaxCandellaIntensity = pFile->maxCandela(); pWebIes->rewind(); pTvLight->setIESFileBuf(pWebIes); } } } { using namespace NwLightIntensityUtils; convertIntensityToCandella(nwLightIntensity, dIESInitialRatedLumens, dIESmaxCandellaIntensity, nIESCandellaMultiplyingFactor); } tvLightAttenuation.setAttenuationType(OdTvLightAttenuation::kInverseSquare); } } pTvLight->setIntensity(nwLightIntensity.m_value); pTvLight->setLightAttenuation(tvLightAttenuation); } } } }