From 7e4cc450d251a3f35fab8197ee33f2471f5d466d Mon Sep 17 00:00:00 2001 From: lh <2334563547@qq.com> Date: Fri, 23 Oct 2026 16:14:45 +0800 Subject: [PATCH] =?UTF-8?q?perf(nm3d):=20=E4=BC=98=E5=8C=96=E5=8E=8B?= =?UTF-8?q?=E5=8A=9B=E5=9C=BA=E5=8A=A8=E7=94=BB=E5=88=87=E5=B8=A7=E4=B8=8E?= =?UTF-8?q?=E6=92=AD=E6=94=BE=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 复用当前颜色表,跳过不变的色标更新 - 播放速度限制为 1–30 步/秒,默认保持 5 - 缓存播放图标,按帧索引更新时间选择框 - 同步中文速度提示及 TS/QM 文件 --- Bin/Config/Lang/cn/nmNum_cn.qm | Bin 188031 -> 188061 bytes Bin/Config/Lang/cn/nmNum_cn.ts | 2 +- .../nmSubWxs/nmPebiResultPlaybackController.h | 5 +- .../nmNum/nmSubWxs/nmWxPebiResultControlBar.h | 6 ++ .../nmPebiResultPlaybackController.cpp | 11 ++-- .../nmSubWxs/nmPebiResultSceneController.cpp | 58 +++++++++++------- .../nmWxPebiResultAnimationSettingsDlg.cpp | 10 +-- .../nmSubWxs/nmWxPebiResultControlBar.cpp | 49 ++++++++++----- 8 files changed, 90 insertions(+), 51 deletions(-) diff --git a/Bin/Config/Lang/cn/nmNum_cn.qm b/Bin/Config/Lang/cn/nmNum_cn.qm index 9c073bf41633b0d981dcf955885c9cd584570ed3..619d2e754a9cfe1b1504dbc3308738cf2fefb21a 100644 GIT binary patch delta 14109 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 T;L&l>X$!*Hp#|amL(2aFwWQol delta 14196 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 nrC*g{35l^uv7=(D#KtGZ42&7EResult playback is unavailable.结果回放不可用。 The selected result property is unavailable.所选结果属性不可用。 The selected result frame is unavailable.所选结果帧不可用。 - Playback speed must be a positive integer.播放速度必须为正整数。 + Playback speed must be between %1 and %2 steps/second.播放速度必须为 %1 至 %2 步/秒。 nmFFmpegVideoWriter diff --git a/Include/nmNum/nmSubWxs/nmPebiResultPlaybackController.h b/Include/nmNum/nmSubWxs/nmPebiResultPlaybackController.h index 09f2f25c..5214408e 100644 --- a/Include/nmNum/nmSubWxs/nmPebiResultPlaybackController.h +++ b/Include/nmNum/nmSubWxs/nmPebiResultPlaybackController.h @@ -22,10 +22,11 @@ class NM_SUB_WXS_EXPORT nmPebiResultPlaybackController : public QObject Q_OBJECT public: - /** @brief 回放速度的合法下限和窗口默认值,单位均为步/秒。 */ + /** @brief 回放速度的合法范围和窗口默认值,单位均为步/秒。 */ enum { MinimumPlaybackSpeed = 1, + MaximumPlaybackSpeed = 30, DefaultPlaybackSpeed = 5 }; @@ -120,7 +121,7 @@ private: bool synchronizeSceneIdentity(); /** @brief 按固定顺序同步失败后的 Scene 状态并通知界面。 */ bool finishFailedOperation(const QString& sError); - /** @brief 使用当前速度计算至少 1ms 的定时器间隔。 */ + /** @brief 向上取整到毫秒,避免定时器请求频率超过设定速度。 */ int calculatePlaybackInterval() const; /** @brief 已渲染属性和帧的唯一真实来源;本类不拥有。 */ diff --git a/Include/nmNum/nmSubWxs/nmWxPebiResultControlBar.h b/Include/nmNum/nmSubWxs/nmWxPebiResultControlBar.h index 13a93a4a..5164aeeb 100644 --- a/Include/nmNum/nmSubWxs/nmWxPebiResultControlBar.h +++ b/Include/nmNum/nmSubWxs/nmWxPebiResultControlBar.h @@ -3,6 +3,7 @@ #include "nmSubWxs_global.h" +#include #include #include #include @@ -94,6 +95,8 @@ private: void rebuildTimeItems(const QString& sPropertyId, int nFrameCount); /** @brief 清空并禁用不适用于静态属性的时间下拉框。 */ void clearTimeItems(); + /** @brief 只在播放状态变化时切换缓存图标和提示。 */ + void updatePlayPauseButton(bool bPlaying); /** @brief 使用 QVariant 精确匹配 ComboBox 的稳定业务数据。 */ int findItemByData(QComboBox* pComboBox, const QVariant& oData) const; @@ -138,6 +141,9 @@ private: QString m_sDisplayedTimePropertyId; /** @brief 当前时间框已完整构建的帧数,失败时为 -1。 */ int m_nDisplayedTimeFrameCount; + QIcon m_oPlayIcon; + QIcon m_oPauseIcon; + bool m_bDisplayedPlaying; }; #endif // NMWXPEBIRESULTCONTROLBAR_H diff --git a/Src/nmNum/nmSubWxs/nmPebiResultPlaybackController.cpp b/Src/nmNum/nmSubWxs/nmPebiResultPlaybackController.cpp index 9365579d..1be0e102 100644 --- a/Src/nmNum/nmSubWxs/nmPebiResultPlaybackController.cpp +++ b/Src/nmNum/nmSubWxs/nmPebiResultPlaybackController.cpp @@ -20,7 +20,7 @@ static const char* const s_pPlaybackTranslationMarkers[] = QT_TRANSLATE_NOOP("nmPebiResultPlaybackController", "The selected result frame is unavailable."), QT_TRANSLATE_NOOP("nmPebiResultPlaybackController", - "Playback speed must be a positive integer.") + "Playback speed must be between %1 and %2 steps/second.") }; QString playbackText(const char* pText) @@ -244,10 +244,12 @@ bool nmPebiResultPlaybackController::setPlaybackSettings( int nStepsPerSecond, bool bLoopEnabled) { - if(nStepsPerSecond < MinimumPlaybackSpeed) { + if(nStepsPerSecond < MinimumPlaybackSpeed || + nStepsPerSecond > MaximumPlaybackSpeed) { // 公开接口不能依赖设置对话框兜底;非法参数也执行统一失败收尾。 return finishFailedOperation(playbackText( - "Playback speed must be a positive integer.")); + "Playback speed must be between %1 and %2 steps/second.") + .arg(MinimumPlaybackSpeed).arg(MaximumPlaybackSpeed)); } if(m_nStepsPerSecond == nStepsPerSecond && m_bLoopEnabled == bLoopEnabled) { @@ -482,6 +484,5 @@ bool nmPebiResultPlaybackController::finishFailedOperation( int nmPebiResultPlaybackController::calculatePlaybackInterval() const { - return qMax(1, qRound(1000.0 / - static_cast(m_nStepsPerSecond))); + return (1000 + m_nStepsPerSecond - 1) / m_nStepsPerSecond; } diff --git a/Src/nmNum/nmSubWxs/nmPebiResultSceneController.cpp b/Src/nmNum/nmSubWxs/nmPebiResultSceneController.cpp index 981e3807..990f517e 100644 --- a/Src/nmNum/nmSubWxs/nmPebiResultSceneController.cpp +++ b/Src/nmNum/nmSubWxs/nmPebiResultSceneController.cpp @@ -513,6 +513,8 @@ public: void applyScalarBarState(const nmPebiResultDisplayState& oDisplay) { + // 仅在快照、属性或配色提交成功后替换;普通切帧复用同一份 LUT。 + m_oCurrentDisplayState = oDisplay; if(m_pScalarBarLayer == nullptr) { return; } @@ -626,6 +628,7 @@ public: delete m_pAdapter; m_pAdapter = nullptr; m_pSnapshot.clear(); + m_oCurrentDisplayState = nmPebiResultDisplayState(); m_listAvailablePropertyIds.clear(); m_sCurrentPropertyId.clear(); m_nCurrentFrameIndex = -1; @@ -694,6 +697,8 @@ public: QString m_sCurrentPropertyId; /** @brief 按稳定属性 ID 保存的窗口级样式;clear 不删除。 */ QMap m_mapDisplaySettings; + /** @brief 仅缓存当前绑定、当前属性的显示状态,不按帧积累。 */ + nmPebiResultDisplayState m_oCurrentDisplayState; nmVTKMeshLayer::DisplayMode m_eMeshDisplayMode; ///< 本窗口显示偏好。 int m_nCurrentFrameIndex; /** @brief 不同快照对象完整提交成功后的单调序号,clear 和失败均不回退。 */ @@ -1030,9 +1035,16 @@ bool nmPebiResultSceneController::applyPropertyFrame( m_pPrivate->m_mapDisplaySettings.value( sPropertyId, nmPebiResultDisplaySettings()); nmPebiResultDisplayState oDisplayCandidate; - if(!nmPebiResultDisplayStateBuilder::build( - m_pPrivate->m_pSnapshot, sPropertyId, oTargetSettings, - oDisplayCandidate, pError)) { + const bool bReuseDisplayState = + sPropertyId == m_pPrivate->m_sCurrentPropertyId && + m_pPrivate->m_oCurrentDisplayState.m_pLookupTable != nullptr && + m_pPrivate->m_oCurrentDisplayState.m_oSettings == oTargetSettings; + if(bReuseDisplayState) { + // 色域来自整个快照,与帧号无关;快照绑定和配色提交负责刷新缓存。 + oDisplayCandidate = m_pPrivate->m_oCurrentDisplayState; + } else if(!nmPebiResultDisplayStateBuilder::build( + m_pPrivate->m_pSnapshot, sPropertyId, oTargetSettings, + oDisplayCandidate, pError)) { return false; } @@ -1069,18 +1081,20 @@ bool nmPebiResultSceneController::applyPropertyFrame( m_pPrivate->m_sCurrentPropertyId = sPropertyId; m_pPrivate->m_nCurrentFrameIndex = nFrameIndex; - m_pPrivate->m_mapDisplaySettings.insert( - sPropertyId, oDisplayCandidate.m_oSettings); - m_pPrivate->m_dBusinessRange[0] = - oDisplayCandidate.m_dBusinessRange[0]; - m_pPrivate->m_dBusinessRange[1] = - oDisplayCandidate.m_dBusinessRange[1]; - m_pPrivate->m_dDisplayRange[0] = - oDisplayCandidate.m_dVisibleRange[0]; - m_pPrivate->m_dDisplayRange[1] = - oDisplayCandidate.m_dVisibleRange[1]; - m_pPrivate->m_bHasPropertyRange = true; - m_pPrivate->applyScalarBarState(oDisplayCandidate); + if(!bReuseDisplayState) { + m_pPrivate->m_mapDisplaySettings.insert( + sPropertyId, oDisplayCandidate.m_oSettings); + m_pPrivate->m_dBusinessRange[0] = + oDisplayCandidate.m_dBusinessRange[0]; + m_pPrivate->m_dBusinessRange[1] = + oDisplayCandidate.m_dBusinessRange[1]; + m_pPrivate->m_dDisplayRange[0] = + oDisplayCandidate.m_dVisibleRange[0]; + m_pPrivate->m_dDisplayRange[1] = + oDisplayCandidate.m_dVisibleRange[1]; + m_pPrivate->m_bHasPropertyRange = true; + m_pPrivate->applyScalarBarState(oDisplayCandidate); + } m_pPrivate->m_pContainer->renderView(); return true; } @@ -1115,6 +1129,13 @@ bool nmPebiResultSceneController::applyCurrentDisplaySettings( return false; } + const nmPebiResultDisplaySettings oCurrentSettings = + m_pPrivate->m_mapDisplaySettings.value( + sExpectedPropertyId, nmPebiResultDisplaySettings()); + if(oSettings == oCurrentSettings) { + return true; + } + nmPebiResultDisplayState oDisplayCandidate; if(!nmPebiResultDisplayStateBuilder::build( m_pPrivate->m_pSnapshot, @@ -1125,13 +1146,6 @@ bool nmPebiResultSceneController::applyCurrentDisplaySettings( return false; } - const nmPebiResultDisplaySettings oCurrentSettings = - m_pPrivate->m_mapDisplaySettings.value( - sExpectedPropertyId, nmPebiResultDisplaySettings()); - if(oDisplayCandidate.m_oSettings == oCurrentSettings.normalized()) { - return true; - } - // MeshLayer 先完整验证候选 LUT;失败时旧 Mapper 和 ScalarBar 仍共享旧 LUT。 if(!m_pPrivate->m_pMeshLayer->setLookupTable( oDisplayCandidate.m_pLookupTable)) { diff --git a/Src/nmNum/nmSubWxs/nmWxPebiResultAnimationSettingsDlg.cpp b/Src/nmNum/nmSubWxs/nmWxPebiResultAnimationSettingsDlg.cpp index 47b55c38..f77c247e 100644 --- a/Src/nmNum/nmSubWxs/nmWxPebiResultAnimationSettingsDlg.cpp +++ b/Src/nmNum/nmSubWxs/nmWxPebiResultAnimationSettingsDlg.cpp @@ -16,8 +16,6 @@ #include #include -#include - namespace { QString resultAnimationIconPath(const QString& sFileName) @@ -44,11 +42,13 @@ nmWxPebiResultAnimationSettingsDlg( m_pSpeedSpin->setRange( nmPebiResultPlaybackController::MinimumPlaybackSpeed, - INT_MAX); - m_pSpeedSpin->setValue(qMax( + nmPebiResultPlaybackController::MaximumPlaybackSpeed); + m_pSpeedSpin->setValue(qBound( static_cast( nmPebiResultPlaybackController::MinimumPlaybackSpeed), - nStepsPerSecond)); + nStepsPerSecond, + static_cast( + nmPebiResultPlaybackController::MaximumPlaybackSpeed))); m_pLoopCheck->setChecked(bLoopEnabled); QFormLayout* pFormLayout = new QFormLayout(); diff --git a/Src/nmNum/nmSubWxs/nmWxPebiResultControlBar.cpp b/Src/nmNum/nmSubWxs/nmWxPebiResultControlBar.cpp index 9fa2d4e6..aae7fd53 100644 --- a/Src/nmNum/nmSubWxs/nmWxPebiResultControlBar.cpp +++ b/Src/nmNum/nmSubWxs/nmWxPebiResultControlBar.cpp @@ -71,7 +71,8 @@ nmWxPebiResultControlBar::nmWxPebiResultControlBar( m_pExportButton(nullptr), m_bExportInProgress(false), m_nDisplayedBindingRevision(0), - m_nDisplayedTimeFrameCount(-1) + m_nDisplayedTimeFrameCount(-1), + m_bDisplayedPlaying(false) { Q_ASSERT(pSceneController != nullptr); createUi(); @@ -287,7 +288,8 @@ void nmWxPebiResultControlBar::refreshFromController() m_pDisplayModeCombo, QVariant(static_cast( m_pSceneController->getMeshDisplayMode()))); - if(nDisplayModeIndex >= 0) { + if(nDisplayModeIndex >= 0 && + m_pDisplayModeCombo->currentIndex() != nDisplayModeIndex) { const bool bDisplayModeBlocked = m_pDisplayModeCombo->blockSignals(true); m_pDisplayModeCombo->setCurrentIndex(nDisplayModeIndex); @@ -316,9 +318,7 @@ void nmWxPebiResultControlBar::refreshFromController() m_pPlayPauseButton->setEnabled(false); m_pSettingsButton->setEnabled(false); m_pExportAction->setEnabled(false); - m_pPlayPauseButton->setIcon(QIcon(resultControlIconPath( - QString::fromLatin1("NmStartAnimation.png")))); - m_pPlayPauseButton->setToolTip(tr("Play")); + updatePlayPauseButton(false); return; } @@ -349,9 +349,11 @@ void nmWxPebiResultControlBar::refreshFromController() m_pPlaybackController->getCurrentPropertyId(); const int nPropertyIndex = findItemByData( m_pPropertyCombo, QVariant(sPropertyId)); - const bool bPropertyBlocked = m_pPropertyCombo->blockSignals(true); - m_pPropertyCombo->setCurrentIndex(nPropertyIndex); - m_pPropertyCombo->blockSignals(bPropertyBlocked); + if(m_pPropertyCombo->currentIndex() != nPropertyIndex) { + const bool bPropertyBlocked = m_pPropertyCombo->blockSignals(true); + m_pPropertyCombo->setCurrentIndex(nPropertyIndex); + m_pPropertyCombo->blockSignals(bPropertyBlocked); + } const bool bTimeDependent = m_pPlaybackController->isPropertyTimeDependent(sPropertyId); const int nFrameCount = bTimeDependent @@ -366,11 +368,16 @@ void nmWxPebiResultControlBar::refreshFromController() const int nCurrentFrame = m_pPlaybackController->getCurrentFrameIndex(); if(bTimeDependent) { - const int nTimeIndex = findItemByData( - m_pTimeCombo, QVariant(nCurrentFrame)); - const bool bTimeBlocked = m_pTimeCombo->blockSignals(true); - m_pTimeCombo->setCurrentIndex(nTimeIndex); - m_pTimeCombo->blockSignals(bTimeBlocked); + // rebuildTimeItems 按帧号完整构建,索引与帧号一致,无需每帧线性搜索。 + const int nTimeIndex = nCurrentFrame >= 0 && + nCurrentFrame < m_pTimeCombo->count() && + m_pTimeCombo->itemData(nCurrentFrame) == QVariant(nCurrentFrame) + ? nCurrentFrame : -1; + if(m_pTimeCombo->currentIndex() != nTimeIndex) { + const bool bTimeBlocked = m_pTimeCombo->blockSignals(true); + m_pTimeCombo->setCurrentIndex(nTimeIndex); + m_pTimeCombo->blockSignals(bTimeBlocked); + } } const bool bHasCompleteTimeList = bTimeDependent && @@ -408,9 +415,16 @@ void nmWxPebiResultControlBar::refreshFromController() m_pExportAction->setToolTip(sExportTip); m_pExportAction->setStatusTip(sExportTip); - m_pPlayPauseButton->setIcon(QIcon(resultControlIconPath( - bPlaying ? QString::fromLatin1("NmStopAnimation.png") - : QString::fromLatin1("NmStartAnimation.png")))); + updatePlayPauseButton(bPlaying); +} + +void nmWxPebiResultControlBar::updatePlayPauseButton(bool bPlaying) +{ + if(m_bDisplayedPlaying == bPlaying) { + return; + } + m_bDisplayedPlaying = bPlaying; + m_pPlayPauseButton->setIcon(bPlaying ? m_oPauseIcon : m_oPlayIcon); m_pPlayPauseButton->setToolTip( bPlaying ? tr("Pause") : tr("Play")); } @@ -499,6 +513,9 @@ void nmWxPebiResultControlBar::createUi() m_pPlayPauseButton = createControlButton( this, QString::fromLatin1("NmStartAnimation.png"), tr("Play")); + m_oPlayIcon = m_pPlayPauseButton->icon(); + m_oPauseIcon = QIcon(resultControlIconPath( + QString::fromLatin1("NmStopAnimation.png"))); m_pSettingsButton = createControlButton( this, QString::fromLatin1("NmAnimationSettings.png"), tr("Animation settings"));