From 9bb93ec8583b5cbd2f53eb8b1a7023e63ee71ea8 Mon Sep 17 00:00:00 2001 From: lh <2334563547@qq.com> Date: Thu, 8 Oct 2026 16:40:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(nmNum):=20=E5=A2=9E=E5=8A=A0=20PEBI=20?= =?UTF-8?q?=E7=BD=91=E6=A0=BC=E5=9B=9B=E7=A7=8D=E6=98=BE=E7=A4=BA=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 扩展通用 MeshLayer 的点、线框、表面和轮廓模式 - 为网格预览和结果视图增加独立显示模式控制 - 冻结动画导出的网格显示模式并校验请求 - 补充中文翻译 --- Bin/Config/Lang/cn/nmNum_cn.qm | Bin 157817 -> 158443 bytes Bin/Config/Lang/cn/nmNum_cn.ts | 10 +++ Include/nmNum/nmRender/nmVTKMeshLayer.h | 8 +- .../nmSubWxs/nmPebiGridSceneController.h | 6 ++ .../nmSubWxs/nmPebiResultAnimationExporter.h | 3 + .../nmSubWxs/nmPebiResultSceneController.h | 6 ++ .../nmNum/nmSubWxs/nmWxPebiGridViewWidget.h | 8 +- .../nmNum/nmSubWxs/nmWxPebiResultControlBar.h | 4 + Src/nmNum/nmRender/nmVTKMeshLayer.cpp | 39 +++++++-- .../nmSubWxs/nmPebiGridSceneController.cpp | 61 ++++++++++--- .../nmPebiResultAnimationExporter.cpp | 11 ++- .../nmSubWxs/nmPebiResultSceneController.cpp | 63 ++++++++++++-- Src/nmNum/nmSubWxs/nmWxPebiGridViewWidget.cpp | 81 +++++++++++++++++- .../nmSubWxs/nmWxPebiResultControlBar.cpp | 81 ++++++++++++++++++ .../nmSubWxs/nmWxPebiResultViewWidget.cpp | 9 +- 15 files changed, 357 insertions(+), 33 deletions(-) diff --git a/Bin/Config/Lang/cn/nmNum_cn.qm b/Bin/Config/Lang/cn/nmNum_cn.qm index 594a836b037a1c00bfc0bf0f15e8d7275608d7eb..9fbf221573fcae9bbff431cb9bc4c5fdd0b2482e 100644 GIT binary patch delta 5560 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 cY|d}By>mbNly^z@tkccI`GH;11QOm9{>OV diff --git a/Bin/Config/Lang/cn/nmNum_cn.ts b/Bin/Config/Lang/cn/nmNum_cn.ts index d669c20a..aae1c227 100644 --- a/Bin/Config/Lang/cn/nmNum_cn.ts +++ b/Bin/Config/Lang/cn/nmNum_cn.ts @@ -2930,6 +2930,11 @@ Reason: %1 nmWxPebiResultControlBar + Display显示 + Point点 + Wireframe线框 + Surface表面 + Contour轮廓 Property属性 Display property显示属性 Color settings颜色设置 @@ -2999,6 +3004,11 @@ Reason: %1 nmWxPebiGridViewWidget + Display显示 + Point点 + Wireframe线框 + Surface表面 + Contour轮廓 No grid data.暂无网格数据。 Scale Grid比例网格 The grid preview data is invalid.网格预览数据无效。 diff --git a/Include/nmNum/nmRender/nmVTKMeshLayer.h b/Include/nmNum/nmRender/nmVTKMeshLayer.h index e747d2bc..23e4ce77 100644 --- a/Include/nmNum/nmRender/nmVTKMeshLayer.h +++ b/Include/nmNum/nmRender/nmVTKMeshLayer.h @@ -25,7 +25,9 @@ public: enum DisplayMode { DisplayMode_Surface = 0, ///< 只显示填充表面。 - DisplayMode_SurfaceWithEdges ///< 同时显示表面和单元边线。 + DisplayMode_SurfaceWithEdges = 1, ///< 同时显示表面和单元边线。 + DisplayMode_Point = 2, ///< 显示 Mapper 实际可渲染的原始顶点。 + DisplayMode_Wireframe = 3 ///< 以线框方式显示网格单元。 }; enum ScalarAssociation @@ -75,7 +77,9 @@ public: /** @brief 返回当前直接数据或管线输出数据集的非所有权指针。 */ vtkDataSet* getDataSet() const; - /** @brief 设置表面或表面加边线显示模式。 */ + /** @brief 判断枚举值是否为受支持的网格显示模式。 */ + static bool isValidDisplayMode(DisplayMode eMode); + /** @brief 设置点、线框、表面或表面加边线显示模式。 */ void setDisplayMode(DisplayMode eMode); /** @brief 返回当前显示模式。 */ DisplayMode getDisplayMode() const; diff --git a/Include/nmNum/nmSubWxs/nmPebiGridSceneController.h b/Include/nmNum/nmSubWxs/nmPebiGridSceneController.h index 4b5961a7..a3224a22 100644 --- a/Include/nmNum/nmSubWxs/nmPebiGridSceneController.h +++ b/Include/nmNum/nmSubWxs/nmPebiGridSceneController.h @@ -2,6 +2,7 @@ #define NMPEBIGRIDSCENECONTROLLER_H #include "nmSubWxs_global.h" +#include "nmVTKMeshLayer.h" #include @@ -29,6 +30,11 @@ public: /** @brief 解除网格引用并隐藏图层,不销毁 Scene 或 Renderer。 */ void clear(); + /** @brief 设置本窗口网格显示模式;无有效数据时只保存偏好。 */ + void setMeshDisplayMode(nmVTKMeshLayer::DisplayMode eMode); + /** @brief 返回本窗口网格显示模式偏好。 */ + nmVTKMeshLayer::DisplayMode getMeshDisplayMode() const; + /** @brief 切换 XY 坐标比例网格。 */ void setBoundsGridVisible(bool bVisible); diff --git a/Include/nmNum/nmSubWxs/nmPebiResultAnimationExporter.h b/Include/nmNum/nmSubWxs/nmPebiResultAnimationExporter.h index 08c5fc9d..25f20ec1 100644 --- a/Include/nmNum/nmSubWxs/nmPebiResultAnimationExporter.h +++ b/Include/nmNum/nmSubWxs/nmPebiResultAnimationExporter.h @@ -4,6 +4,7 @@ #include "nmSubWxs_global.h" #include "nmPebiResultAnimationExportSettings.h" #include "nmPebiResultDisplaySettings.h" +#include "nmVTKMeshLayer.h" #include #include @@ -60,6 +61,8 @@ public: bool m_bGradientBackground; /** @brief 当前屏幕相机的深拷贝,导出器不会修改屏幕相机。 */ vtkSmartPointer m_pCamera; + /** @brief 开始导出前冻结的网格显示模式。 */ + nmVTKMeshLayer::DisplayMode m_eMeshDisplayMode; }; /** @param pParent Qt父对象,不参与VTK资源所有权。 */ diff --git a/Include/nmNum/nmSubWxs/nmPebiResultSceneController.h b/Include/nmNum/nmSubWxs/nmPebiResultSceneController.h index a85c8464..c8324ddb 100644 --- a/Include/nmNum/nmSubWxs/nmPebiResultSceneController.h +++ b/Include/nmNum/nmSubWxs/nmPebiResultSceneController.h @@ -3,6 +3,7 @@ #include "nmSubWxs_global.h" #include "nmPebiResultDisplaySettings.h" +#include "nmVTKMeshLayer.h" #include #include @@ -71,6 +72,11 @@ public: const nmPebiResultDisplaySettings& oSettings, QString* pError = nullptr); + /** @brief 设置本窗口网格显示模式;无有效快照时只保存偏好。 */ + void setMeshDisplayMode(nmVTKMeshLayer::DisplayMode eMode); + /** @brief 返回本窗口网格显示模式偏好。 */ + nmVTKMeshLayer::DisplayMode getMeshDisplayMode() const; + /** @brief 设置色标显隐;默认显示,偏好跨快照保留。 */ void setScalarBarVisible(bool bVisible); /** @brief 设置平面比例网格显隐;偏好跨快照保留。 */ diff --git a/Include/nmNum/nmSubWxs/nmWxPebiGridViewWidget.h b/Include/nmNum/nmSubWxs/nmWxPebiGridViewWidget.h index ba110cbd..9da66ff5 100644 --- a/Include/nmNum/nmSubWxs/nmWxPebiGridViewWidget.h +++ b/Include/nmNum/nmSubWxs/nmWxPebiGridViewWidget.h @@ -6,6 +6,7 @@ #include class QAction; +class QComboBox; class QLabel; class QMenu; class QToolBar; @@ -17,7 +18,7 @@ class nmWxVTKRenderContainerWidget; /** * @brief 二维 PEBI 网格预览业务组合控件。 * - * 本类定位为网格几何检查窗口,只显示固定灰色表面、黑色单元边线和 + * 本类定位为网格几何检查窗口,支持点、线框、表面和轮廓四种模式及 * 可选的 XY 比例网格,不解释输入数据中的历史属性数组。右侧工具栏和 * 右键菜单复用同一批 QAction;通用导航、旋转中心、截图和打印能力由 * 内部 nmRender 容器提供,不继承业务视图基类。 @@ -48,6 +49,8 @@ public: bool hasViewData() const; private slots: + /** @brief 从 itemData 读取并提交当前窗口的网格显示模式。 */ + void onDisplayModeIndexChanged(int nIndex); /** @brief 切换世界坐标中的 XY 比例网格,不改变相机。 */ void onBoundsGridToggled(bool bVisible); /** @brief 向通用右键菜单追加本窗口独占的比例网格动作。 */ @@ -60,6 +63,8 @@ private: void createUi(); /** @brief 恢复无数据时的比例网格偏好和底栏文字。 */ void resetControls(); + /** @brief 从 SceneController 镜像显示模式,且不触发用户选择槽。 */ + void synchronizeDisplayModeFromScene(); /** @brief 统一启停依赖有效网格的业务动作。 */ void setControlsEnabled(bool bEnabled); @@ -67,6 +72,7 @@ private: nmPebiGridSceneController* m_pSceneController; ///< 本类独占,必须先于容器销毁。 QToolBar* m_pToolBar; ///< Qt 父对象拥有的右侧竖向工具栏。 QAction* m_pBoundsGridAction; ///< 工具栏和右键菜单共享的比例网格动作。 + QComboBox* m_pDisplayModeCombo; ///< 显示模式框,itemData 保存 DisplayMode 枚举值。 QLabel* m_pGridInfoLabel; ///< 底栏左侧的网格类型、单元数和平面信息。 QLabel* m_pStatusLabel; ///< 建网失败且保留旧网格时使用的黄色提示栏。 bool m_bHasViewData; ///< 与场景控制器的成功数据状态保持同步。 diff --git a/Include/nmNum/nmSubWxs/nmWxPebiResultControlBar.h b/Include/nmNum/nmSubWxs/nmWxPebiResultControlBar.h index 9b4c92e1..13a93a4a 100644 --- a/Include/nmNum/nmSubWxs/nmWxPebiResultControlBar.h +++ b/Include/nmNum/nmSubWxs/nmWxPebiResultControlBar.h @@ -56,6 +56,8 @@ signals: void exportAnimationRequested(); private slots: + /** @brief 用户选择显示模式时提交 itemData 中的 DisplayMode 枚举值。 */ + void onDisplayModeIndexChanged(int nIndex); /** @brief 用户选择属性时提交稳定属性 ID。 */ void onPropertyIndexChanged(int nIndex); /** @brief 用户选择时间时提交 itemData 中的零基帧。 */ @@ -100,6 +102,8 @@ private: nmPebiResultPlaybackController* m_pPlaybackController; /** @brief 已渲染属性、帧和显示设置的唯一真源;本控件不拥有。 */ nmPebiResultSceneController* m_pSceneController; + /** @brief 显示模式选择框,条目数据保存 DisplayMode 枚举值。 */ + QComboBox* m_pDisplayModeCombo; /** @brief 属性选择框,条目数据保存稳定英文属性 ID。 */ QComboBox* m_pPropertyCombo; /** @brief 使用固定色带图标打开颜色设置对话框。 */ diff --git a/Src/nmNum/nmRender/nmVTKMeshLayer.cpp b/Src/nmNum/nmRender/nmVTKMeshLayer.cpp index b6d7bbcf..44d943cd 100644 --- a/Src/nmNum/nmRender/nmVTKMeshLayer.cpp +++ b/Src/nmNum/nmRender/nmVTKMeshLayer.cpp @@ -52,6 +52,8 @@ nmVTKMeshLayer::nmVTKMeshLayer(const QString& sLayerId) m_pActor->SetMapper(m_pMapper); m_pActor->GetProperty()->SetRepresentationToSurface(); m_pActor->GetProperty()->EdgeVisibilityOff(); + m_pActor->GetProperty()->SetPointSize(3.0f); + m_pActor->GetProperty()->SetLineWidth(1.0f); setRenderProp(m_pActor); } @@ -208,6 +210,14 @@ vtkDataSet* nmVTKMeshLayer::getDataSet() const return getInputDataSet(false); } +bool nmVTKMeshLayer::isValidDisplayMode(DisplayMode eMode) +{ + return eMode == DisplayMode_Surface || + eMode == DisplayMode_SurfaceWithEdges || + eMode == DisplayMode_Point || + eMode == DisplayMode_Wireframe; +} + void nmVTKMeshLayer::setDisplayMode(DisplayMode eMode) { Q_ASSERT(isMeshLayerGuiThread()); @@ -215,13 +225,30 @@ void nmVTKMeshLayer::setDisplayMode(DisplayMode eMode) return; } - // 未识别枚举值按纯表面处理,避免把无效值带入 VTK Property。 - m_eDisplayMode = eMode == DisplayMode_SurfaceWithEdges - ? DisplayMode_SurfaceWithEdges : DisplayMode_Surface; + // 未识别枚举值仍按纯表面处理,保持旧接口的降级语义。 + m_eDisplayMode = isValidDisplayMode(eMode) + ? eMode : DisplayMode_Surface; vtkProperty* pProperty = m_pActor->GetProperty(); - pProperty->SetRepresentationToSurface(); - pProperty->SetEdgeVisibility( - m_eDisplayMode == DisplayMode_SurfaceWithEdges ? 1 : 0); + pProperty->SetPointSize(3.0f); + pProperty->SetLineWidth(1.0f); + pProperty->EdgeVisibilityOff(); + + switch(m_eDisplayMode) { + case DisplayMode_Point: + pProperty->SetRepresentationToPoints(); + break; + case DisplayMode_Wireframe: + pProperty->SetRepresentationToWireframe(); + break; + case DisplayMode_SurfaceWithEdges: + pProperty->SetRepresentationToSurface(); + pProperty->EdgeVisibilityOn(); + break; + case DisplayMode_Surface: + default: + pProperty->SetRepresentationToSurface(); + break; + } } nmVTKMeshLayer::DisplayMode nmVTKMeshLayer::getDisplayMode() const diff --git a/Src/nmNum/nmSubWxs/nmPebiGridSceneController.cpp b/Src/nmNum/nmSubWxs/nmPebiGridSceneController.cpp index 28cb766d..ff59a18f 100644 --- a/Src/nmNum/nmSubWxs/nmPebiGridSceneController.cpp +++ b/Src/nmNum/nmSubWxs/nmPebiGridSceneController.cpp @@ -52,11 +52,31 @@ public: : m_pContainer(pRenderContainer), m_pMeshLayer(nullptr), m_pPlanarScaleGridLayer(nullptr), + m_eMeshDisplayMode( + nmVTKMeshLayer::DisplayMode_SurfaceWithEdges), m_bBoundsGridVisible(false), m_bHasData(false) { } + /** @brief 将窗口偏好应用到现有网格 Actor,不触发渲染。 */ + void applyMeshDisplayModeWithoutRender() + { + if(m_pMeshLayer == nullptr) { + return; + } + + m_pMeshLayer->setDisplayMode(m_eMeshDisplayMode); + vtkProperty* pProperty = m_pMeshLayer->getActor()->GetProperty(); + const bool bUseBlackColor = + m_eMeshDisplayMode == nmVTKMeshLayer::DisplayMode_Point || + m_eMeshDisplayMode == + nmVTKMeshLayer::DisplayMode_Wireframe; + const double dColor = bUseBlackColor ? 0.0 : 211.0 / 255.0; + pProperty->SetColor(dColor, dColor, dColor); + pProperty->SetEdgeColor(0.0, 0.0, 0.0); + } + bool ensureBaseLayers() { nmVTKScene* pScene = m_pContainer != nullptr @@ -76,14 +96,9 @@ public: 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(); + applyMeshDisplayModeWithoutRender(); } if(m_pPlanarScaleGridLayer == nullptr) { @@ -113,10 +128,9 @@ public: m_oViewData.clear(); return false; } - // 输入可能包含历史数组,网格预览始终关闭标量着色并显示单元边线。 + // 输入可能包含历史数组,网格预览始终关闭标量着色。 m_pMeshLayer->setScalarVisibility(false); - m_pMeshLayer->setDisplayMode( - nmVTKMeshLayer::DisplayMode_SurfaceWithEdges); + applyMeshDisplayModeWithoutRender(); m_pMeshLayer->setVisible(true); if(!m_pPlanarScaleGridLayer->setBounds( @@ -161,6 +175,7 @@ public: nmVTKMeshLayer* m_pMeshLayer; ///< Scene 所有,控制器只观察。 nmVTKPlanarScaleGridLayer* m_pPlanarScaleGridLayer; ///< Scene 所有。 nmPebiGridViewData m_oViewData; + nmVTKMeshLayer::DisplayMode m_eMeshDisplayMode; ///< 本窗口显示偏好。 bool m_bBoundsGridVisible; bool m_bHasData; }; @@ -253,6 +268,31 @@ void nmPebiGridSceneController::clear() m_pPrivate->m_bBoundsGridVisible = false; } +void nmPebiGridSceneController::setMeshDisplayMode( + nmVTKMeshLayer::DisplayMode eMode) +{ + if(m_pPrivate == nullptr || + !nmVTKMeshLayer::isValidDisplayMode(eMode) || + m_pPrivate->m_eMeshDisplayMode == eMode) { + return; + } + + m_pPrivate->m_eMeshDisplayMode = eMode; + m_pPrivate->applyMeshDisplayModeWithoutRender(); + if(m_pPrivate->m_bHasData && + m_pPrivate->m_pContainer != nullptr) { + m_pPrivate->m_pContainer->renderView(); + } +} + +nmVTKMeshLayer::DisplayMode +nmPebiGridSceneController::getMeshDisplayMode() const +{ + return m_pPrivate != nullptr + ? m_pPrivate->m_eMeshDisplayMode + : nmVTKMeshLayer::DisplayMode_SurfaceWithEdges; +} + void nmPebiGridSceneController::setBoundsGridVisible(bool bVisible) { if(m_pPrivate == nullptr) { @@ -264,6 +304,7 @@ void nmPebiGridSceneController::setBoundsGridVisible(bool bVisible) bVisible && m_pPrivate->m_bHasData); } if(m_pPrivate->m_bHasData && m_pPrivate->m_pContainer != nullptr) { + m_pPrivate->applyMeshDisplayModeWithoutRender(); m_pPrivate->m_pContainer->renderView(); } } diff --git a/Src/nmNum/nmSubWxs/nmPebiResultAnimationExporter.cpp b/Src/nmNum/nmSubWxs/nmPebiResultAnimationExporter.cpp index 71a7a8c6..3b257928 100644 --- a/Src/nmNum/nmSubWxs/nmPebiResultAnimationExporter.cpp +++ b/Src/nmNum/nmSubWxs/nmPebiResultAnimationExporter.cpp @@ -255,7 +255,9 @@ nmPebiResultAnimationExporter::Request::Request() m_bScaleGridVisible(false), m_bWellNamesVisible(true), m_bGradientBackground(false), - m_pCamera(nullptr) + m_pCamera(nullptr), + m_eMeshDisplayMode( + nmVTKMeshLayer::DisplayMode_SurfaceWithEdges) { m_dBackground[0] = m_dBackground[1] = m_dBackground[2] = 0.0; m_dBackground2[0] = m_dBackground2[1] = m_dBackground2[2] = 0.0; @@ -291,7 +293,9 @@ nmPebiResultAnimationExporter::exportAnimation( oRequest.m_sPropertyId, oDescriptor) || oDescriptor.m_eTimeType != NM_PebiResultProperty_Dynamic || oDescriptor.m_eAssociation != - NM_PebiResultPropertyAssociation_CellData || + NM_PebiResultPropertyAssociation_CellData || + !nmVTKMeshLayer::isValidDisplayMode( + oRequest.m_eMeshDisplayMode) || !oRequest.m_oExportSettings.isValid(nAvailableFrameCount) || oRequest.m_sTargetFilePath.isEmpty() || oRequest.m_pCamera == nullptr) { @@ -370,8 +374,7 @@ nmPebiResultAnimationExporter::exportAnimation( nmVTKScene oScene(pRenderer); nmVTKMeshLayer* pMeshLayer = new nmVTKMeshLayer( QString::fromLatin1(EXPORT_MESH_LAYER_ID)); - pMeshLayer->setDisplayMode( - nmVTKMeshLayer::DisplayMode_SurfaceWithEdges); + pMeshLayer->setDisplayMode(oRequest.m_eMeshDisplayMode); pMeshLayer->getActor()->GetProperty()->SetEdgeColor(0.0, 0.0, 0.0); pMeshLayer->getActor()->GetProperty()->LightingOff(); if(!pMeshLayer->setInputConnection( diff --git a/Src/nmNum/nmSubWxs/nmPebiResultSceneController.cpp b/Src/nmNum/nmSubWxs/nmPebiResultSceneController.cpp index 29ece80f..981e3807 100644 --- a/Src/nmNum/nmSubWxs/nmPebiResultSceneController.cpp +++ b/Src/nmNum/nmSubWxs/nmPebiResultSceneController.cpp @@ -189,6 +189,8 @@ public: m_pScaleGridLayer(nullptr), m_pWellLayer(nullptr), m_pAdapter(nullptr), + m_eMeshDisplayMode( + nmVTKMeshLayer::DisplayMode_SurfaceWithEdges), m_nCurrentFrameIndex(-1), m_nSnapshotBindingRevision(0), m_nViewportWidth(0), @@ -214,6 +216,18 @@ public: return m_pContainer != nullptr ? m_pContainer->getScene() : nullptr; } + /** @brief 将窗口偏好应用到现有结果网格,不触发渲染。 */ + void applyMeshDisplayModeWithoutRender() + { + if(m_pMeshLayer == nullptr) { + return; + } + m_pMeshLayer->setDisplayMode(m_eMeshDisplayMode); + // Contour 使用黑色单元边线,其余模式关闭边线但保留该颜色偏好。 + m_pMeshLayer->getActor()->GetProperty()->SetEdgeColor( + 0.0, 0.0, 0.0); + } + bool synchronizeLayerPointers() { nmVTKScene* pScene = getScene(); @@ -335,6 +349,7 @@ public: m_pMeshLayer->getActor()->GetProperty()->SetEdgeColor( 0.0, 0.0, 0.0); m_pMeshLayer->getActor()->GetProperty()->LightingOff(); + applyMeshDisplayModeWithoutRender(); } if(m_pScalarBarLayer == nullptr) { @@ -471,11 +486,15 @@ public: } // MeshLayer 在触碰旧 Mapper 前完成全部校验,失败不会破坏旧画面。 - return m_pMeshLayer->setInputConnection( - pAdapter->getOutputPort(), - pAdapter->getCurrentScalarArrayName(), - nmVTKMeshLayer::ScalarAssociation_CellData, - pLookupTable); + if(!m_pMeshLayer->setInputConnection( + pAdapter->getOutputPort(), + pAdapter->getCurrentScalarArrayName(), + nmVTKMeshLayer::ScalarAssociation_CellData, + pLookupTable)) { + return false; + } + applyMeshDisplayModeWithoutRender(); + return true; } void applyScalarBarLayout() @@ -513,9 +532,7 @@ public: { synchronizeLayerPointers(); if(m_pMeshLayer != nullptr) { - // 结果网格固定显示彩色表面和黑色单元边线,不保存可关闭的偏好。 - m_pMeshLayer->setDisplayMode( - nmVTKMeshLayer::DisplayMode_SurfaceWithEdges); + applyMeshDisplayModeWithoutRender(); m_pMeshLayer->setScalarVisibility(bHasData); // 彩色结果网格是有效快照的主内容,不提供独立隐藏状态。 m_pMeshLayer->setVisible(bHasData); @@ -677,6 +694,7 @@ public: QString m_sCurrentPropertyId; /** @brief 按稳定属性 ID 保存的窗口级样式;clear 不删除。 */ QMap m_mapDisplaySettings; + nmVTKMeshLayer::DisplayMode m_eMeshDisplayMode; ///< 本窗口显示偏好。 int m_nCurrentFrameIndex; /** @brief 不同快照对象完整提交成功后的单调序号,clear 和失败均不回退。 */ quint64 m_nSnapshotBindingRevision; @@ -1139,6 +1157,35 @@ bool nmPebiResultSceneController::applyCurrentDisplaySettings( return true; } +void nmPebiResultSceneController::setMeshDisplayMode( + nmVTKMeshLayer::DisplayMode eMode) +{ + Q_ASSERT(isResultSceneGuiThread()); + if(!isResultSceneGuiThread() || m_pPrivate == nullptr || + !nmVTKMeshLayer::isValidDisplayMode(eMode)) { + return; + } + + m_pPrivate->discardActiveDataIfLayersLost(); + if(m_pPrivate->m_eMeshDisplayMode == eMode) { + return; + } + + m_pPrivate->m_eMeshDisplayMode = eMode; + m_pPrivate->applyMeshDisplayModeWithoutRender(); + if(hasSnapshot() && m_pPrivate->m_pContainer != nullptr) { + m_pPrivate->m_pContainer->renderView(); + } +} + +nmVTKMeshLayer::DisplayMode +nmPebiResultSceneController::getMeshDisplayMode() const +{ + return m_pPrivate != nullptr + ? m_pPrivate->m_eMeshDisplayMode + : nmVTKMeshLayer::DisplayMode_SurfaceWithEdges; +} + void nmPebiResultSceneController::setScalarBarVisible(bool bVisible) { Q_ASSERT(isResultSceneGuiThread()); diff --git a/Src/nmNum/nmSubWxs/nmWxPebiGridViewWidget.cpp b/Src/nmNum/nmSubWxs/nmWxPebiGridViewWidget.cpp index 3dd3dbf5..3a9665b0 100644 --- a/Src/nmNum/nmSubWxs/nmWxPebiGridViewWidget.cpp +++ b/Src/nmNum/nmSubWxs/nmWxPebiGridViewWidget.cpp @@ -3,10 +3,12 @@ #include "nmPebiGridSceneController.h" #include "nmPebiGridViewData.h" +#include "nmVTKMeshLayer.h" #include "nmVTKViewCommandController.h" #include "nmWxVTKRenderContainerWidget.h" #include +#include #include #include #include @@ -14,6 +16,7 @@ #include #include #include +#include #include namespace { @@ -33,6 +36,7 @@ nmWxPebiGridViewWidget::nmWxPebiGridViewWidget(QWidget* pParent) m_pSceneController(nullptr), m_pToolBar(nullptr), m_pBoundsGridAction(nullptr), + m_pDisplayModeCombo(nullptr), m_pGridInfoLabel(nullptr), m_pStatusLabel(nullptr), m_bHasViewData(false) @@ -41,6 +45,7 @@ nmWxPebiGridViewWidget::nmWxPebiGridViewWidget(QWidget* pParent) // 控制器必须在容器之后创建,以便使用当前实例独占的 Scene 和相机。 m_pSceneController = new nmPebiGridSceneController(m_pRenderContainer); + synchronizeDisplayModeFromScene(); resetControls(); setControlsEnabled(false); m_pRenderContainer->showEmptyState(tr("No grid data.")); @@ -176,18 +181,47 @@ void nmWxPebiGridViewWidget::createUi() m_pStatusLabel->hide(); pMainLayout->addWidget(m_pStatusLabel); - // 底栏只承担几何信息展示,不放置属性或渲染模式控件。 + // 显示模式属于当前预览窗口,业务控件不下沉到通用渲染容器。 QWidget* pControlBar = new QWidget(this); QHBoxLayout* pControlLayout = new QHBoxLayout(pControlBar); pControlLayout->setContentsMargins(8, 5, 8, 5); pControlLayout->setSpacing(6); + QLabel* pDisplayLabel = new QLabel(tr("Display"), pControlBar); + pDisplayLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + m_pDisplayModeCombo = new QComboBox(pControlBar); + m_pDisplayModeCombo->addItem( + tr("Point"), + QVariant(static_cast( + nmVTKMeshLayer::DisplayMode_Point))); + m_pDisplayModeCombo->addItem( + tr("Wireframe"), + QVariant(static_cast( + nmVTKMeshLayer::DisplayMode_Wireframe))); + m_pDisplayModeCombo->addItem( + tr("Surface"), + QVariant(static_cast( + nmVTKMeshLayer::DisplayMode_Surface))); + m_pDisplayModeCombo->addItem( + tr("Contour"), + QVariant(static_cast( + nmVTKMeshLayer::DisplayMode_SurfaceWithEdges))); + m_pDisplayModeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); + m_pDisplayModeCombo->setFixedHeight(24); + m_pDisplayModeCombo->setSizePolicy( + QSizePolicy::Preferred, QSizePolicy::Fixed); + m_pGridInfoLabel = new QLabel(pControlBar); m_pGridInfoLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + pControlLayout->addWidget(pDisplayLabel, 0, Qt::AlignVCenter); + pControlLayout->addWidget(m_pDisplayModeCombo); + pControlLayout->addSpacing(2); pControlLayout->addWidget(m_pGridInfoLabel); pControlLayout->addStretch(1); pMainLayout->addWidget(pControlBar); + connect(m_pDisplayModeCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(onDisplayModeIndexChanged(int))); connect(m_pBoundsGridAction, SIGNAL(toggled(bool)), this, SLOT(onBoundsGridToggled(bool))); connect(m_pRenderContainer, SIGNAL(contextMenuAboutToShow(QMenu*)), @@ -218,6 +252,7 @@ bool nmWxPebiGridViewWidget::setViewData( oViewData.getValidCellCount()))); m_pStatusLabel->hide(); m_bHasViewData = true; + synchronizeDisplayModeFromScene(); setControlsEnabled(true); return true; } @@ -275,6 +310,50 @@ void nmWxPebiGridViewWidget::resetControls() void nmWxPebiGridViewWidget::setControlsEnabled(bool bEnabled) { m_pBoundsGridAction->setEnabled(bEnabled); + m_pDisplayModeCombo->setEnabled(bEnabled); +} + +void nmWxPebiGridViewWidget::synchronizeDisplayModeFromScene() +{ + if(m_pDisplayModeCombo == nullptr || m_pSceneController == nullptr) { + return; + } + const int nMode = static_cast( + m_pSceneController->getMeshDisplayMode()); + for(int nIndex = 0; + nIndex < m_pDisplayModeCombo->count(); ++nIndex) { + if(m_pDisplayModeCombo->itemData(nIndex).toInt() == nMode) { + const bool bBlocked = + m_pDisplayModeCombo->blockSignals(true); + m_pDisplayModeCombo->setCurrentIndex(nIndex); + m_pDisplayModeCombo->blockSignals(bBlocked); + return; + } + } +} + +void nmWxPebiGridViewWidget::onDisplayModeIndexChanged(int nIndex) +{ + if(m_pDisplayModeCombo == nullptr || + !m_pDisplayModeCombo->isEnabled() || + m_pSceneController == nullptr || !m_bHasViewData || + !m_pSceneController->hasViewData() || nIndex < 0 || + nIndex >= m_pDisplayModeCombo->count()) { + return; + } + + bool bConverted = false; + const int nMode = m_pDisplayModeCombo->itemData(nIndex).toInt( + &bConverted); + const nmVTKMeshLayer::DisplayMode eMode = + static_cast( + nMode); + if(!bConverted || !nmVTKMeshLayer::isValidDisplayMode(eMode)) { + synchronizeDisplayModeFromScene(); + return; + } + m_pSceneController->setMeshDisplayMode(eMode); + synchronizeDisplayModeFromScene(); } void nmWxPebiGridViewWidget::onBoundsGridToggled(bool bVisible) diff --git a/Src/nmNum/nmSubWxs/nmWxPebiResultControlBar.cpp b/Src/nmNum/nmSubWxs/nmWxPebiResultControlBar.cpp index 93bbc9c5..9fa2d4e6 100644 --- a/Src/nmNum/nmSubWxs/nmWxPebiResultControlBar.cpp +++ b/Src/nmNum/nmSubWxs/nmWxPebiResultControlBar.cpp @@ -4,6 +4,7 @@ #include "nmPebiResultPlaybackController.h" #include "nmPebiResultPropertyDisplayText.h" #include "nmPebiResultSceneController.h" +#include "nmVTKMeshLayer.h" #include "nmWxPebiResultAnimationSettingsDlg.h" #include "nmWxPebiResultColorScaleSettingsDlg.h" @@ -56,6 +57,7 @@ nmWxPebiResultControlBar::nmWxPebiResultControlBar( : QWidget(pParent), m_pPlaybackController(nullptr), m_pSceneController(pSceneController), + m_pDisplayModeCombo(nullptr), m_pPropertyCombo(nullptr), m_pColorSettingsButton(nullptr), m_pFirstButton(nullptr), @@ -125,6 +127,34 @@ void nmWxPebiResultControlBar::setExportInProgress(bool bInProgress) refreshFromController(); } +void nmWxPebiResultControlBar::onDisplayModeIndexChanged(int nIndex) +{ + if(m_pDisplayModeCombo == nullptr || + !m_pDisplayModeCombo->isEnabled() || + m_pPlaybackController == nullptr || m_pSceneController == nullptr || + m_bExportInProgress || m_pPlaybackController->isPlaying() || + !m_pSceneController->hasSnapshot() || nIndex < 0 || + nIndex >= m_pDisplayModeCombo->count()) { + return; + } + + bool bConverted = false; + const int nMode = m_pDisplayModeCombo->itemData(nIndex).toInt( + &bConverted); + const nmVTKMeshLayer::DisplayMode eMode = + static_cast( + nMode); + if(!bConverted || !nmVTKMeshLayer::isValidDisplayMode(eMode)) { + refreshFromController(); + return; + } + if(eMode == m_pSceneController->getMeshDisplayMode()) { + return; + } + m_pSceneController->setMeshDisplayMode(eMode); + emit operationSucceeded(); +} + void nmWxPebiResultControlBar::onPropertyIndexChanged(int nIndex) { if(m_pPlaybackController == nullptr || m_bExportInProgress || @@ -252,6 +282,19 @@ void nmWxPebiResultControlBar::onExportAnimationTriggered() void nmWxPebiResultControlBar::refreshFromController() { + if(m_pDisplayModeCombo != nullptr && m_pSceneController != nullptr) { + const int nDisplayModeIndex = findItemByData( + m_pDisplayModeCombo, + QVariant(static_cast( + m_pSceneController->getMeshDisplayMode()))); + if(nDisplayModeIndex >= 0) { + const bool bDisplayModeBlocked = + m_pDisplayModeCombo->blockSignals(true); + m_pDisplayModeCombo->setCurrentIndex(nDisplayModeIndex); + m_pDisplayModeCombo->blockSignals(bDisplayModeBlocked); + } + } + // 控件状态严格镜像四类 Scene 状态:无快照、静态、单帧动态、多帧动态。 const bool bAvailable = m_pPlaybackController != nullptr && m_pPlaybackController->isAvailable(); @@ -263,6 +306,7 @@ void nmWxPebiResultControlBar::refreshFromController() m_sDisplayedSnapshotId.clear(); m_nDisplayedBindingRevision = 0; m_listDisplayedPropertyIds.clear(); + m_pDisplayModeCombo->setEnabled(false); m_pPropertyCombo->setEnabled(false); m_pColorSettingsButton->setEnabled(false); m_pFirstButton->setEnabled(false); @@ -336,6 +380,7 @@ void nmWxPebiResultControlBar::refreshFromController() nFrameCount > 1; const bool bPlaying = m_pPlaybackController->isPlaying(); const bool bLocked = bPlaying || m_bExportInProgress; + m_pDisplayModeCombo->setEnabled(!bLocked); m_pPropertyCombo->setEnabled(!bLocked); m_pColorSettingsButton->setEnabled(!bLocked); m_pTimeCombo->setEnabled(bHasTime && !bLocked); @@ -382,6 +427,37 @@ void nmWxPebiResultControlBar::createUi() pLayout->setContentsMargins(4, 3, 4, 3); pLayout->setSpacing(4); + QLabel* pDisplayLabel = new QLabel(tr("Display"), this); + pDisplayLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + m_pDisplayModeCombo = new QComboBox(this); + m_pDisplayModeCombo->addItem( + tr("Point"), + QVariant(static_cast( + nmVTKMeshLayer::DisplayMode_Point))); + m_pDisplayModeCombo->addItem( + tr("Wireframe"), + QVariant(static_cast( + nmVTKMeshLayer::DisplayMode_Wireframe))); + m_pDisplayModeCombo->addItem( + tr("Surface"), + QVariant(static_cast( + nmVTKMeshLayer::DisplayMode_Surface))); + m_pDisplayModeCombo->addItem( + tr("Contour"), + QVariant(static_cast( + nmVTKMeshLayer::DisplayMode_SurfaceWithEdges))); + m_pDisplayModeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); + m_pDisplayModeCombo->setFixedHeight(24); + m_pDisplayModeCombo->setSizePolicy( + QSizePolicy::Preferred, QSizePolicy::Fixed); + const int nInitialDisplayModeIndex = findItemByData( + m_pDisplayModeCombo, + QVariant(static_cast( + m_pSceneController->getMeshDisplayMode()))); + if(nInitialDisplayModeIndex >= 0) { + m_pDisplayModeCombo->setCurrentIndex(nInitialDisplayModeIndex); + } + QLabel* pPropertyLabel = new QLabel(tr("Property"), this); pPropertyLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); @@ -436,6 +512,9 @@ void nmWxPebiResultControlBar::createUi() m_pExportButton->setIconSize(QSize(16, 16)); m_pExportButton->setDefaultAction(m_pExportAction); + pLayout->addWidget(pDisplayLabel, 0, Qt::AlignVCenter); + pLayout->addWidget(m_pDisplayModeCombo); + pLayout->addSpacing(CONTROL_GROUP_GAP); pLayout->addWidget(pPropertyLabel, 0, Qt::AlignVCenter); pLayout->addWidget(m_pPropertyCombo); pLayout->addWidget(m_pColorSettingsButton); @@ -450,6 +529,8 @@ void nmWxPebiResultControlBar::createUi() pLayout->addWidget(m_pExportButton); pLayout->addStretch(1); + connect(m_pDisplayModeCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(onDisplayModeIndexChanged(int))); connect(m_pPropertyCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onPropertyIndexChanged(int))); connect(m_pColorSettingsButton, SIGNAL(clicked()), diff --git a/Src/nmNum/nmSubWxs/nmWxPebiResultViewWidget.cpp b/Src/nmNum/nmSubWxs/nmWxPebiResultViewWidget.cpp index 88a3417d..03ba6a54 100644 --- a/Src/nmNum/nmSubWxs/nmWxPebiResultViewWidget.cpp +++ b/Src/nmNum/nmSubWxs/nmWxPebiResultViewWidget.cpp @@ -7,6 +7,7 @@ #include "nmPebiResultPlaybackController.h" #include "nmPebiResultSceneController.h" #include "nmPebiResultSnapshot.h" +#include "nmVTKMeshLayer.h" #include "nmVTKViewCommandController.h" #include "nmWxPebiResultControlBar.h" #include "nmWxPebiResultAnimationExportDlg.h" @@ -300,10 +301,13 @@ void nmWxPebiResultViewWidget::onExportAnimationRequested() m_pSceneController->getCurrentSnapshotId(); const QString sFrozenPropertyId = m_pSceneController->getCurrentPropertyId(); + const nmVTKMeshLayer::DisplayMode eFrozenMeshDisplayMode = + m_pSceneController->getMeshDisplayMode(); const int nFrameCount = pFrozenSnapshot->getPropertyFrameCount( sFrozenPropertyId); if(nFrozenBindingRevision == 0 || sFrozenSnapshotId.isEmpty() || sFrozenPropertyId.isEmpty() || nFrameCount <= 1 || + !nmVTKMeshLayer::isValidDisplayMode(eFrozenMeshDisplayMode) || !m_pSceneController->isPropertyTimeDependent(sFrozenPropertyId)) { return; } @@ -333,7 +337,9 @@ void nmWxPebiResultViewWidget::onExportAnimationRequested() m_pSceneController->getSnapshotBindingRevision() != nFrozenBindingRevision || m_pSceneController->getCurrentSnapshotId() != sFrozenSnapshotId || - m_pSceneController->getCurrentPropertyId() != sFrozenPropertyId) { + m_pSceneController->getCurrentPropertyId() != sFrozenPropertyId || + m_pSceneController->getMeshDisplayMode() != + eFrozenMeshDisplayMode) { QMessageBox::warning( this, tr("Export Animation"), tr("The displayed result changed before export started.")); @@ -354,6 +360,7 @@ void nmWxPebiResultViewWidget::onExportAnimationRequested() oRequest.m_pSnapshot = pFrozenSnapshot; oRequest.m_sPropertyId = sFrozenPropertyId; oRequest.m_oDisplaySettings = oDisplaySettings; + oRequest.m_eMeshDisplayMode = eFrozenMeshDisplayMode; oRequest.m_oExportSettings = oSettingsDialog.getSettings(); oRequest.m_sTargetFilePath = oSettingsDialog.getTargetFilePath(); oRequest.m_bScalarBarVisible =