#include "nmPebiGridSceneController.h" #include "nmPebiGridViewData.h" #include "nmVTKMeshLayer.h" #include "nmVTKPlanarScaleGridLayer.h" #include "nmVTKScene.h" #include "nmWxVTKRenderContainerWidget.h" #include #include #include #include #include #include namespace { QString controllerText(const char* pText) { return QCoreApplication::translate( "nmPebiGridSceneController", pText); } bool getFiniteGridBounds(vtkUnstructuredGrid* pGrid, double dBounds[6]) { if(pGrid == nullptr || dBounds == nullptr) { return false; } pGrid->GetBounds(dBounds); if(!vtkMath::AreBoundsInitialized(dBounds)) { return false; } for(int nIndex = 0; nIndex < 6; ++nIndex) { if(!vtkMath::IsFinite(dBounds[nIndex])) { return false; } } return dBounds[0] <= dBounds[1] && dBounds[2] <= dBounds[3] && dBounds[4] <= dBounds[5]; } } class nmPebiGridSceneControllerPrivate { public: explicit nmPebiGridSceneControllerPrivate( nmWxVTKRenderContainerWidget* pRenderContainer) : m_pContainer(pRenderContainer), m_pMeshLayer(nullptr), m_pPlanarScaleGridLayer(nullptr), m_bBoundsGridVisible(false), m_bHasData(false) { } bool ensureBaseLayers() { nmVTKScene* pScene = m_pContainer != nullptr ? m_pContainer->getScene() : nullptr; vtkRenderer* pRenderer = m_pContainer != nullptr ? m_pContainer->getRenderer() : nullptr; if(pScene == nullptr || pRenderer == nullptr) { return false; } if(m_pMeshLayer == nullptr) { nmVTKMeshLayer* pLayer = new nmVTKMeshLayer("pebi.grid.mesh"); pLayer->setVisible(false); if(!pScene->addLayer(pLayer)) { delete pLayer; return false; } m_pMeshLayer = pLayer; // PEBI 预览固定使用稳定灰色表面和黑色单元边线。 m_pMeshLayer->getActor()->GetProperty()->SetColor( 211.0 / 255.0, 211.0 / 255.0, 211.0 / 255.0); m_pMeshLayer->getActor()->GetProperty()->SetEdgeColor( 0.0, 0.0, 0.0); // 仅关闭当前 PEBI 预览 Actor 的光照,避免固定面色随视角变化。 m_pMeshLayer->getActor()->GetProperty()->LightingOff(); } if(m_pPlanarScaleGridLayer == nullptr) { nmVTKPlanarScaleGridLayer* pLayer = new nmVTKPlanarScaleGridLayer("pebi.grid.scale_grid"); pLayer->setVisible(false); if(!pScene->addLayer(pLayer)) { delete pLayer; return false; } m_pPlanarScaleGridLayer = pLayer; } return true; } bool bindViewData(const nmPebiGridViewData& oViewData, const double dBounds[6]) { if(m_pMeshLayer == nullptr || m_pPlanarScaleGridLayer == nullptr || dBounds == nullptr) { return false; } // 本函数只提交已在外层验证过的数据,不渲染也不改变相机。 m_oViewData = oViewData; if(!m_pMeshLayer->setDataSet(oViewData.getGrid())) { m_oViewData.clear(); return false; } // 输入可能包含历史数组,网格预览始终关闭标量着色并显示单元边线。 m_pMeshLayer->setScalarVisibility(false); m_pMeshLayer->setDisplayMode( nmVTKMeshLayer::DisplayMode_SurfaceWithEdges); m_pMeshLayer->setVisible(true); if(!m_pPlanarScaleGridLayer->setBounds( dBounds[0], dBounds[1], dBounds[2], dBounds[3], dBounds[4])) { m_pMeshLayer->setDataSet(nullptr); m_pMeshLayer->setVisible(false); m_oViewData.clear(); return false; } m_pPlanarScaleGridLayer->setVisible(m_bBoundsGridVisible); m_bHasData = true; // 只有整份网格绑定成功后才允许公共拾取器命中主 Mesh Actor。 if(m_pContainer != nullptr) { m_pContainer->setRotationCenterPickTarget( m_pMeshLayer->getActor()); } return true; } void releaseGridData() { // 先取消临时拾取并清除弱目标,再解除 Mapper 对网格的共享引用。 if(m_pContainer != nullptr) { m_pContainer->setRotationCenterPickTarget(nullptr); } // 先断开 Mapper 对旧网格的引用,再释放 ViewData 的共享引用。 if(m_pMeshLayer != nullptr) { m_pMeshLayer->setScalarVisibility(false); m_pMeshLayer->setDataSet(nullptr); m_pMeshLayer->setVisible(false); } if(m_pPlanarScaleGridLayer != nullptr) { m_pPlanarScaleGridLayer->setVisible(false); } m_oViewData.clear(); m_bHasData = false; } nmWxVTKRenderContainerWidget* m_pContainer; ///< 非所有权指针。 nmVTKMeshLayer* m_pMeshLayer; ///< Scene 所有,控制器只观察。 nmVTKPlanarScaleGridLayer* m_pPlanarScaleGridLayer; ///< Scene 所有。 nmPebiGridViewData m_oViewData; bool m_bBoundsGridVisible; bool m_bHasData; }; nmPebiGridSceneController::nmPebiGridSceneController( nmWxVTKRenderContainerWidget* pContainer) : m_pPrivate(new nmPebiGridSceneControllerPrivate(pContainer)) { } nmPebiGridSceneController::~nmPebiGridSceneController() { if(m_pPrivate != nullptr) { // Layer 已归 Scene 所有;这里只解除数据和非所有权指针。 m_pPrivate->releaseGridData(); m_pPrivate->m_pContainer = nullptr; m_pPrivate->m_pMeshLayer = nullptr; m_pPrivate->m_pPlanarScaleGridLayer = nullptr; delete m_pPrivate; m_pPrivate = nullptr; } } bool nmPebiGridSceneController::setViewData( const nmPebiGridViewData& oViewData, QString* pError) { if(pError != nullptr) { pError->clear(); } if(m_pPrivate == nullptr || m_pPrivate->m_pContainer == nullptr || !oViewData.isValid()) { if(pError != nullptr) { *pError = controllerText("The grid preview data is invalid."); } return false; } double dBounds[6]; if(!getFiniteGridBounds(oViewData.getGrid(), dBounds)) { if(pError != nullptr) { *pError = controllerText("The grid bounds are invalid."); } return false; } if(!m_pPrivate->ensureBaseLayers()) { if(pError != nullptr) { *pError = controllerText("Unable to create the grid render layers."); } return false; } // 强引用保留上一份成功数据,提交任一步失败时可以完整恢复旧画面。 const bool bHadPreviousData = m_pPrivate->m_bHasData; const nmPebiGridViewData oPreviousViewData = m_pPrivate->m_oViewData; double dPreviousBounds[6]; const bool bHasPreviousBounds = bHadPreviousData && getFiniteGridBounds(oPreviousViewData.getGrid(), dPreviousBounds); // 几何替换先解除旧输入,再共享新网格;Renderer 和图层对象保持不变。 m_pPrivate->releaseGridData(); if(!m_pPrivate->bindViewData(oViewData, dBounds)) { // 回滚同样不渲染;外层失败状态会决定恢复旧画面还是显示错误页。 m_pPrivate->releaseGridData(); if(bHadPreviousData && bHasPreviousBounds) { m_pPrivate->bindViewData( oPreviousViewData, dPreviousBounds); } if(pError != nullptr) { *pError = controllerText("Unable to bind the grid render data."); } return false; } // 几何变化恢复正交顶视图,并将独立枢轴初始化为新网格可见边界中心。 // 两步都不立即渲染,整批更新最终只在就绪入口提交一次。 m_pPrivate->m_pContainer->fitTopViewWithoutRender(); m_pPrivate->m_pContainer->resetRotationCenterWithoutRender(); m_pPrivate->m_pContainer->showReadyState(); return true; } void nmPebiGridSceneController::clear() { if(m_pPrivate == nullptr) { return; } m_pPrivate->releaseGridData(); m_pPrivate->m_bBoundsGridVisible = false; } void nmPebiGridSceneController::setBoundsGridVisible(bool bVisible) { if(m_pPrivate == nullptr) { return; } m_pPrivate->m_bBoundsGridVisible = bVisible; if(m_pPrivate->m_pPlanarScaleGridLayer != nullptr) { m_pPrivate->m_pPlanarScaleGridLayer->setVisible( bVisible && m_pPrivate->m_bHasData); } if(m_pPrivate->m_bHasData && m_pPrivate->m_pContainer != nullptr) { m_pPrivate->m_pContainer->renderView(); } } bool nmPebiGridSceneController::hasViewData() const { return m_pPrivate != nullptr && m_pPrivate->m_bHasData; } bool nmPebiGridSceneController::isBoundsGridVisible() const { return m_pPrivate != nullptr && m_pPrivate->m_bBoundsGridVisible; }