You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmPebiResultSceneController...

1065 lines
37 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmPebiResultSceneController.h"
#include "nmPebiResultPropertyCatalog.h"
#include "nmPebiResultSnapshot.h"
#include "nmPebiResultSnapshotRenderAdapter.h"
#include "nmVTKMeshLayer.h"
#include "nmVTKPlanarScaleGridLayer.h"
#include "nmVTKScalarBarLayer.h"
#include "nmVTKScene.h"
#include "nmWxVTKRenderContainerWidget.h"
#include <QCoreApplication>
#include <QSet>
#include <QThread>
#include <QtGlobal>
#include <vtkActor.h>
#include <vtkAlgorithm.h>
#include <vtkAlgorithmOutput.h>
#include <vtkCellData.h>
#include <vtkDataArray.h>
#include <vtkDataSet.h>
#include <vtkLookupTable.h>
#include <vtkMath.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <math.h>
namespace {
const char* const RESULT_MESH_LAYER_ID = "pebi.result.mesh";
const char* const RESULT_SCALAR_BAR_LAYER_ID = "pebi.result.scalar_bar";
const char* const RESULT_SCALE_GRID_LAYER_ID = "pebi.result.scale_grid";
const char* const RESULT_WELLS_LAYER_ID = "pebi.result.wells";
/* Qt 4.8 的 lupdate 无法从变量参数中推导翻译原文,必须显式登记。 */
static const char* const s_pResultSceneTranslationMarkers[] =
{
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
"The result snapshot is invalid."),
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
"The result snapshot has no renderable property."),
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
"Unable to initialize the result render adapter."),
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
"The result render data failed validation."),
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
"Unable to create the result render layers."),
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
"Unable to commit the result render data."),
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
"The requested result property or frame is invalid."),
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
"The result property range is invalid."),
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
"Unable to apply the result property or frame.")
};
bool isResultSceneGuiThread()
{
QCoreApplication* pApplication = QCoreApplication::instance();
return pApplication == nullptr ||
pApplication->thread() == QThread::currentThread();
}
QString controllerText(const char* pText)
{
Q_UNUSED(s_pResultSceneTranslationMarkers);
return QCoreApplication::translate(
"nmPebiResultSceneController", pText);
}
void copyBounds(const double dSource[6], double dTarget[6])
{
for(int nIndex = 0; nIndex < 6; ++nIndex) {
dTarget[nIndex] = dSource[nIndex];
}
}
bool getFiniteBounds(vtkDataSet* pDataSet, double dBounds[6])
{
if(pDataSet == nullptr || dBounds == nullptr) {
return false;
}
pDataSet->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];
}
bool getDisplayRange(const double dBusinessRange[2],
double dDisplayRange[2])
{
if(dBusinessRange == nullptr || dDisplayRange == nullptr ||
!vtkMath::IsFinite(dBusinessRange[0]) ||
!vtkMath::IsFinite(dBusinessRange[1]) ||
dBusinessRange[0] > dBusinessRange[1]) {
return false;
}
dDisplayRange[0] = dBusinessRange[0];
dDisplayRange[1] = dBusinessRange[1];
if(dBusinessRange[0] < dBusinessRange[1]) {
return true;
}
// VTK 需要非零显示区间;业务层仍保存并返回原始常量范围 [c,c]。
const double dValue = dBusinessRange[0];
const double dEpsilon = qMax(1.0, fabs(dValue)) * 1.0e-6;
double dMinimum = dValue - dEpsilon;
double dMaximum = dValue + dEpsilon;
if(!vtkMath::IsFinite(dMinimum)) {
dMinimum = dValue;
}
if(!vtkMath::IsFinite(dMaximum)) {
dMaximum = dValue;
}
if(dMinimum >= dMaximum) {
return false;
}
dDisplayRange[0] = dMinimum;
dDisplayRange[1] = dMaximum;
return true;
}
bool getValidatedPropertyRanges(
const QSharedPointer<const nmPebiResultSnapshot>& pSnapshot,
const QString& sPropertyId,
double dBusinessRange[2],
double dDisplayRange[2])
{
return !pSnapshot.isNull() &&
pSnapshot->getPropertyRange(sPropertyId, dBusinessRange) &&
getDisplayRange(dBusinessRange, dDisplayRange);
}
QString chooseInitialProperty(
const QSharedPointer<const nmPebiResultSnapshot>& pSnapshot)
{
const QString sPressure = QString::fromLatin1("pressure");
if(!pSnapshot.isNull() && pSnapshot->hasProperty(sPressure) &&
pSnapshot->getPropertyFrameCount(sPressure) > 0) {
return sPressure;
}
// 无压力仅是防御分支;按 Catalog 顺序选择第一个可用静态属性。
const QList<nmPebiResultPropertyDescriptor> listDescriptors =
nmPebiResultPropertyCatalog::descriptors();
for(int nIndex = 0; nIndex < listDescriptors.size(); ++nIndex) {
const nmPebiResultPropertyDescriptor& oDescriptor =
listDescriptors[nIndex];
if(oDescriptor.m_eTimeType == NM_PebiResultProperty_Static &&
pSnapshot->hasProperty(oDescriptor.m_sPropertyId)) {
return oDescriptor.m_sPropertyId;
}
}
return QString();
}
bool areSnapshotWellsValid(
const QSharedPointer<const nmPebiResultSnapshot>& pSnapshot)
{
if(pSnapshot.isNull()) {
return false;
}
QSet<QString> setWellIds;
for(int nIndex = 0; nIndex < pSnapshot->getWellCount(); ++nIndex) {
const nmPebiResultWellSnapshot* pWell = pSnapshot->getWellAt(nIndex);
if(pWell == nullptr || pWell->m_sWellInstanceId.isEmpty() ||
pWell->m_sWellCode.isEmpty() ||
!vtkMath::IsFinite(pWell->m_oLocation.x()) ||
!vtkMath::IsFinite(pWell->m_oLocation.y()) ||
setWellIds.contains(pWell->m_sWellInstanceId)) {
return false;
}
setWellIds.insert(pWell->m_sWellInstanceId);
}
return true;
}
bool validateAdapterOutput(
nmPebiResultSnapshotRenderAdapter* pAdapter,
vtkIdType nExpectedCellCount,
double dBounds[6])
{
if(pAdapter == nullptr || dBounds == nullptr ||
pAdapter->getCellCount() != nExpectedCellCount ||
nExpectedCellCount <= 0) {
return false;
}
vtkAlgorithmOutput* pOutputPort = pAdapter->getOutputPort();
if(pOutputPort == nullptr || pOutputPort->GetProducer() == nullptr ||
pOutputPort->GetIndex() < 0) {
return false;
}
vtkAlgorithm* pProducer = pOutputPort->GetProducer();
pProducer->Update(pOutputPort->GetIndex());
vtkDataSet* pDataSet = vtkDataSet::SafeDownCast(
pProducer->GetOutputDataObject(pOutputPort->GetIndex()));
if(pDataSet == nullptr ||
pDataSet->GetNumberOfCells() != nExpectedCellCount ||
!getFiniteBounds(pDataSet, dBounds)) {
return false;
}
const QByteArray aScalarName =
pAdapter->getCurrentScalarArrayName().toUtf8();
vtkDataArray* pScalars = aScalarName.isEmpty() ? nullptr :
pDataSet->GetCellData()->GetArray(aScalarName.constData());
if(pScalars == nullptr || pScalars->GetNumberOfComponents() != 1 ||
pScalars->GetNumberOfTuples() != nExpectedCellCount) {
return false;
}
double dActualRange[2] = { 0.0, 0.0 };
pScalars->GetRange(dActualRange);
return vtkMath::IsFinite(dActualRange[0]) &&
vtkMath::IsFinite(dActualRange[1]) &&
dActualRange[0] <= dActualRange[1];
}
}
class nmPebiResultSceneControllerPrivate
{
public:
explicit nmPebiResultSceneControllerPrivate(
nmWxVTKRenderContainerWidget* pContainer)
: m_pContainer(pContainer),
m_pMeshLayer(nullptr),
m_pScalarBarLayer(nullptr),
m_pScaleGridLayer(nullptr),
m_pAdapter(nullptr),
m_nCurrentFrameIndex(-1),
m_bHasPropertyRange(false),
m_bHasBounds(false),
m_bMeshVisible(true),
// 5C 补齐属性名和单位标题前,避免显示语义不完整的色标。
m_bScalarBarVisible(false),
m_bScaleGridVisible(false),
m_bCellEdgesVisible(false)
{
m_dBusinessRange[0] = 0.0;
m_dBusinessRange[1] = 0.0;
m_dDisplayRange[0] = 0.0;
m_dDisplayRange[1] = 1.0;
for(int nIndex = 0; nIndex < 6; ++nIndex) {
m_dBounds[nIndex] = 0.0;
}
// 5A 固定保留该 ID,井位图层在 5C 才创建。
Q_UNUSED(RESULT_WELLS_LAYER_ID);
}
nmVTKScene* getScene() const
{
return m_pContainer != nullptr ? m_pContainer->getScene() : nullptr;
}
bool synchronizeLayerPointers()
{
nmVTKScene* pScene = getScene();
bool bPointersIntact = pScene != nullptr;
if(pScene == nullptr) {
bPointersIntact = m_pMeshLayer == nullptr &&
m_pScalarBarLayer == nullptr &&
m_pScaleGridLayer == nullptr;
m_pMeshLayer = nullptr;
m_pScalarBarLayer = nullptr;
m_pScaleGridLayer = nullptr;
return bPointersIntact;
}
// Scene 是图层唯一所有者。这里只比较指针身份,不解引用可能已经由
// 外部 Scene::clear() 删除的旧地址;不一致时立即丢弃观察指针。
if(m_pMeshLayer != nullptr &&
pScene->getLayer(QString::fromLatin1(RESULT_MESH_LAYER_ID)) !=
m_pMeshLayer) {
m_pMeshLayer = nullptr;
bPointersIntact = false;
}
if(m_pScalarBarLayer != nullptr &&
pScene->getLayer(
QString::fromLatin1(RESULT_SCALAR_BAR_LAYER_ID)) !=
m_pScalarBarLayer) {
m_pScalarBarLayer = nullptr;
bPointersIntact = false;
}
if(m_pScaleGridLayer != nullptr &&
pScene->getLayer(
QString::fromLatin1(RESULT_SCALE_GRID_LAYER_ID)) !=
m_pScaleGridLayer) {
m_pScaleGridLayer = nullptr;
bPointersIntact = false;
}
return bPointersIntact;
}
bool hasOwnedBaseLayers() const
{
if(!isResultSceneGuiThread()) {
return false;
}
nmVTKScene* pScene = getScene();
return pScene != nullptr &&
m_pMeshLayer != nullptr &&
m_pScalarBarLayer != nullptr &&
m_pScaleGridLayer != nullptr &&
pScene->getLayer(
QString::fromLatin1(RESULT_MESH_LAYER_ID)) ==
m_pMeshLayer &&
pScene->getLayer(
QString::fromLatin1(RESULT_SCALAR_BAR_LAYER_ID)) ==
m_pScalarBarLayer &&
pScene->getLayer(
QString::fromLatin1(RESULT_SCALE_GRID_LAYER_ID)) ==
m_pScaleGridLayer;
}
void discardActiveDataIfLayersLost()
{
const bool bPointersIntact = synchronizeLayerPointers();
const bool bHasActiveState = m_pAdapter != nullptr ||
!m_pSnapshot.isNull();
if(bHasActiveState &&
(!bPointersIntact || !hasOwnedBaseLayers())) {
// 外部已经清理业务 Scene 时无法继续兑现“当前快照可见”的状态,
// 因此采用 fail-closed:释放逻辑状态,但绝不访问已删除的 Layer。
releaseActiveData();
}
}
bool ensureBaseLayers(bool& bCreatedMesh,
bool& bCreatedScalarBar,
bool& bCreatedScaleGrid)
{
bCreatedMesh = false;
bCreatedScalarBar = false;
bCreatedScaleGrid = false;
const bool bPointersIntact = synchronizeLayerPointers();
nmVTKScene* pScene = getScene();
vtkRenderer* pRenderer = m_pContainer != nullptr
? m_pContainer->getRenderer() : nullptr;
if(pScene == nullptr || pRenderer == nullptr ||
(!bPointersIntact && m_pAdapter != nullptr)) {
return false;
}
if(m_pMeshLayer == nullptr) {
if(pScene->getLayer(
QString::fromLatin1(RESULT_MESH_LAYER_ID)) != nullptr) {
return false;
}
nmVTKMeshLayer* pLayer = new nmVTKMeshLayer(
QString::fromLatin1(RESULT_MESH_LAYER_ID));
pLayer->setVisible(false);
if(!pScene->addLayer(pLayer)) {
delete pLayer;
return false;
}
m_pMeshLayer = pLayer;
bCreatedMesh = true;
m_pMeshLayer->getActor()->GetProperty()->SetEdgeColor(
0.0, 0.0, 0.0);
m_pMeshLayer->getActor()->GetProperty()->LightingOff();
}
if(m_pScalarBarLayer == nullptr) {
if(pScene->getLayer(QString::fromLatin1(
RESULT_SCALAR_BAR_LAYER_ID)) != nullptr) {
rollbackCreatedLayers(
bCreatedMesh, false, false);
return false;
}
nmVTKScalarBarLayer* pLayer = new nmVTKScalarBarLayer(
QString::fromLatin1(RESULT_SCALAR_BAR_LAYER_ID));
pLayer->setVisible(false);
pLayer->setPosition(0.05, 0.1);
pLayer->setSize(0.1, 0.8);
if(!pScene->addLayer(pLayer)) {
delete pLayer;
rollbackCreatedLayers(
bCreatedMesh, false, false);
return false;
}
m_pScalarBarLayer = pLayer;
bCreatedScalarBar = true;
}
if(m_pScaleGridLayer == nullptr) {
if(pScene->getLayer(QString::fromLatin1(
RESULT_SCALE_GRID_LAYER_ID)) != nullptr) {
rollbackCreatedLayers(
bCreatedMesh, bCreatedScalarBar, false);
return false;
}
nmVTKPlanarScaleGridLayer* pLayer =
new nmVTKPlanarScaleGridLayer(
QString::fromLatin1(RESULT_SCALE_GRID_LAYER_ID));
pLayer->setVisible(false);
if(!pScene->addLayer(pLayer)) {
delete pLayer;
rollbackCreatedLayers(
bCreatedMesh, bCreatedScalarBar, false);
return false;
}
m_pScaleGridLayer = pLayer;
bCreatedScaleGrid = true;
}
return true;
}
void rollbackCreatedLayers(bool bCreatedMesh,
bool bCreatedScalarBar,
bool bCreatedScaleGrid)
{
synchronizeLayerPointers();
nmVTKScene* pScene = getScene();
if(pScene == nullptr) {
return;
}
if(bCreatedScaleGrid && m_pScaleGridLayer != nullptr &&
pScene->getLayer(
QString::fromLatin1(RESULT_SCALE_GRID_LAYER_ID)) ==
m_pScaleGridLayer) {
pScene->removeLayer(
QString::fromLatin1(RESULT_SCALE_GRID_LAYER_ID));
}
if(bCreatedScaleGrid) {
m_pScaleGridLayer = nullptr;
}
if(bCreatedScalarBar && m_pScalarBarLayer != nullptr &&
pScene->getLayer(
QString::fromLatin1(RESULT_SCALAR_BAR_LAYER_ID)) ==
m_pScalarBarLayer) {
pScene->removeLayer(
QString::fromLatin1(RESULT_SCALAR_BAR_LAYER_ID));
}
if(bCreatedScalarBar) {
m_pScalarBarLayer = nullptr;
}
if(bCreatedMesh && m_pMeshLayer != nullptr &&
pScene->getLayer(QString::fromLatin1(RESULT_MESH_LAYER_ID)) ==
m_pMeshLayer) {
pScene->removeLayer(
QString::fromLatin1(RESULT_MESH_LAYER_ID));
}
if(bCreatedMesh) {
m_pMeshLayer = nullptr;
}
}
bool bindMeshAdapter(nmPebiResultSnapshotRenderAdapter* pAdapter,
const double dDisplayRange[2])
{
if(m_pMeshLayer == nullptr || pAdapter == nullptr ||
dDisplayRange == nullptr) {
return false;
}
// MeshLayer 在触碰旧 Mapper 前完成全部校验,失败不会破坏旧画面。
return m_pMeshLayer->setInputConnection(
pAdapter->getOutputPort(),
pAdapter->getCurrentScalarArrayName(),
nmVTKMeshLayer::ScalarAssociation_CellData,
dDisplayRange[0], dDisplayRange[1]);
}
void applyLayerVisibility(bool bHasData)
{
synchronizeLayerPointers();
if(m_pMeshLayer != nullptr) {
m_pMeshLayer->setDisplayMode(m_bCellEdgesVisible
? nmVTKMeshLayer::DisplayMode_SurfaceWithEdges
: nmVTKMeshLayer::DisplayMode_Surface);
m_pMeshLayer->setScalarVisibility(bHasData);
m_pMeshLayer->setVisible(bHasData && m_bMeshVisible);
}
if(m_pScalarBarLayer != nullptr) {
m_pScalarBarLayer->setVisible(
bHasData && m_bScalarBarVisible);
}
if(m_pScaleGridLayer != nullptr) {
m_pScaleGridLayer->setVisible(
bHasData && m_bScaleGridVisible);
}
if(m_pContainer != nullptr) {
m_pContainer->setRotationCenterPickTarget(
bHasData && m_bMeshVisible && m_pMeshLayer != nullptr
? m_pMeshLayer->getActor() : nullptr);
}
}
bool restorePreviousScene()
{
synchronizeLayerPointers();
if(!hasOwnedBaseLayers() || m_pContainer == nullptr) {
return false;
}
if(m_pAdapter == nullptr || m_pSnapshot.isNull()) {
m_pMeshLayer->clearInput();
m_pContainer->clearPrimaryViewBounds();
if(m_pScalarBarLayer != nullptr) {
m_pScalarBarLayer->setLookupTable(nullptr);
m_pScalarBarLayer->setTitle(QString());
}
applyLayerVisibility(false);
return true;
}
const bool bMeshRestored = bindMeshAdapter(
m_pAdapter, m_dDisplayRange);
bool bGridRestored = !m_bHasBounds;
bool bBoundsRestored = !m_bHasBounds;
if(m_bHasBounds && m_pScaleGridLayer != nullptr) {
bGridRestored = m_pScaleGridLayer->setBounds(
m_dBounds[0], m_dBounds[1],
m_dBounds[2], m_dBounds[3], m_dBounds[4]);
bBoundsRestored = m_pContainer->setPrimaryViewBounds(m_dBounds);
}
if(m_pScalarBarLayer != nullptr) {
m_pScalarBarLayer->setLookupTable(
m_pMeshLayer->getLookupTable());
}
applyLayerVisibility(true);
return bMeshRestored && bGridRestored && bBoundsRestored;
}
void releaseActiveData()
{
// Scene 可能已由外部清空;先按稳定 ID 解除所有悬空观察指针。
synchronizeLayerPointers();
if(m_pContainer != nullptr) {
m_pContainer->setRotationCenterPickTarget(nullptr);
m_pContainer->clearPrimaryViewBounds();
}
if(m_pMeshLayer != nullptr) {
m_pMeshLayer->setScalarVisibility(false);
m_pMeshLayer->clearInput();
m_pMeshLayer->setVisible(false);
}
if(m_pScalarBarLayer != nullptr) {
m_pScalarBarLayer->setVisible(false);
m_pScalarBarLayer->setLookupTable(nullptr);
m_pScalarBarLayer->setTitle(QString());
}
if(m_pScaleGridLayer != nullptr) {
m_pScaleGridLayer->setVisible(false);
}
delete m_pAdapter;
m_pAdapter = nullptr;
m_pSnapshot.clear();
m_listAvailablePropertyIds.clear();
m_sCurrentPropertyId.clear();
m_nCurrentFrameIndex = -1;
m_bHasPropertyRange = false;
m_bHasBounds = false;
}
void removeOwnedLayers()
{
synchronizeLayerPointers();
nmVTKScene* pScene = getScene();
if(pScene == nullptr) {
return;
}
// 只删除仍与本控制器记录身份一致的图层,绝不误删同 ID 的外部替代层。
if(m_pScaleGridLayer != nullptr &&
pScene->getLayer(
QString::fromLatin1(RESULT_SCALE_GRID_LAYER_ID)) ==
m_pScaleGridLayer) {
pScene->removeLayer(
QString::fromLatin1(RESULT_SCALE_GRID_LAYER_ID));
}
m_pScaleGridLayer = nullptr;
if(m_pScalarBarLayer != nullptr &&
pScene->getLayer(
QString::fromLatin1(RESULT_SCALAR_BAR_LAYER_ID)) ==
m_pScalarBarLayer) {
pScene->removeLayer(
QString::fromLatin1(RESULT_SCALAR_BAR_LAYER_ID));
}
m_pScalarBarLayer = nullptr;
if(m_pMeshLayer != nullptr &&
pScene->getLayer(QString::fromLatin1(RESULT_MESH_LAYER_ID)) ==
m_pMeshLayer) {
pScene->removeLayer(
QString::fromLatin1(RESULT_MESH_LAYER_ID));
}
m_pMeshLayer = nullptr;
}
nmWxVTKRenderContainerWidget* m_pContainer; ///< 非所有权指针。
nmVTKMeshLayer* m_pMeshLayer; ///< Scene 所有。
nmVTKScalarBarLayer* m_pScalarBarLayer; ///< Scene 所有。
nmVTKPlanarScaleGridLayer* m_pScaleGridLayer; ///< Scene 所有。
nmPebiResultSnapshotRenderAdapter* m_pAdapter; ///< 控制器独占。
QSharedPointer<const nmPebiResultSnapshot> m_pSnapshot;
QStringList m_listAvailablePropertyIds;
QString m_sCurrentPropertyId;
int m_nCurrentFrameIndex;
double m_dBusinessRange[2];
double m_dDisplayRange[2];
double m_dBounds[6];
bool m_bHasPropertyRange;
bool m_bHasBounds;
bool m_bMeshVisible;
bool m_bScalarBarVisible;
bool m_bScaleGridVisible;
bool m_bCellEdgesVisible;
};
nmPebiResultSceneController::nmPebiResultSceneController(
nmWxVTKRenderContainerWidget* pContainer)
: m_pPrivate(new nmPebiResultSceneControllerPrivate(pContainer))
{
Q_ASSERT(isResultSceneGuiThread());
}
nmPebiResultSceneController::~nmPebiResultSceneController()
{
Q_ASSERT(isResultSceneGuiThread());
if(m_pPrivate != nullptr) {
m_pPrivate->releaseActiveData();
// Controller 结束后立即移除自己的业务图层,使同一容器可安全创建新实例。
m_pPrivate->removeOwnedLayers();
m_pPrivate->m_pContainer = nullptr;
delete m_pPrivate;
m_pPrivate = nullptr;
}
}
bool nmPebiResultSceneController::setSnapshot(
const QSharedPointer<const nmPebiResultSnapshot>& pSnapshot,
QString* pError)
{
Q_ASSERT(isResultSceneGuiThread());
if(pError != nullptr) {
pError->clear();
}
if(!isResultSceneGuiThread() || m_pPrivate == nullptr ||
m_pPrivate->m_pContainer == nullptr || pSnapshot.isNull() ||
!pSnapshot->isComplete()) {
if(pError != nullptr) {
*pError = controllerText("The result snapshot is invalid.");
}
return false;
}
m_pPrivate->discardActiveDataIfLayersLost();
if(m_pPrivate->m_pSnapshot == pSnapshot &&
m_pPrivate->m_pSnapshot->getSnapshotId() ==
pSnapshot->getSnapshotId()) {
return true;
}
const QString sInitialProperty = chooseInitialProperty(pSnapshot);
nmPebiResultPropertyDescriptor oInitialDescriptor;
if(sInitialProperty.isEmpty() ||
!nmPebiResultPropertyCatalog::findDescriptor(
sInitialProperty, oInitialDescriptor) ||
oInitialDescriptor.m_eAssociation !=
NM_PebiResultPropertyAssociation_CellData) {
if(pError != nullptr) {
*pError = controllerText(
"The result snapshot has no renderable property.");
}
return false;
}
nmPebiResultSnapshotRenderAdapter* pCandidateAdapter =
new nmPebiResultSnapshotRenderAdapter();
if(!pCandidateAdapter->initialize(
pSnapshot,
nmPebiResultSnapshotRenderAdapter::SharedPropertyArray) ||
!pCandidateAdapter->setPropertyFrame(sInitialProperty, 0)) {
delete pCandidateAdapter;
if(pError != nullptr) {
*pError = controllerText(
"Unable to initialize the result render adapter.");
}
return false;
}
double dBusinessRange[2];
double dDisplayRange[2];
double dBounds[6];
if(pCandidateAdapter->getCurrentScalarArrayName().isEmpty() ||
!getValidatedPropertyRanges(pSnapshot, sInitialProperty,
dBusinessRange, dDisplayRange) ||
!validateAdapterOutput(pCandidateAdapter,
pSnapshot->getResultCellCount(), dBounds) ||
!areSnapshotWellsValid(pSnapshot)) {
delete pCandidateAdapter;
if(pError != nullptr) {
*pError = controllerText(
"The result render data failed validation.");
}
return false;
}
bool bCreatedMesh = false;
bool bCreatedScalarBar = false;
bool bCreatedScaleGrid = false;
if(!m_pPrivate->ensureBaseLayers(
bCreatedMesh, bCreatedScalarBar, bCreatedScaleGrid)) {
delete pCandidateAdapter;
if(pError != nullptr) {
*pError = controllerText(
"Unable to create the result render layers.");
}
return false;
}
bool bCommitted = m_pPrivate->m_pScaleGridLayer->setBounds(
dBounds[0], dBounds[1], dBounds[2],
dBounds[3], dBounds[4]) &&
m_pPrivate->m_pContainer->setPrimaryViewBounds(dBounds) &&
m_pPrivate->bindMeshAdapter(
pCandidateAdapter, dDisplayRange);
if(!bCommitted) {
const bool bRestored = m_pPrivate->restorePreviousScene();
if(!bRestored) {
// 不允许 Release 构建留下“逻辑有快照、实际无输入”的半恢复状态。
m_pPrivate->releaseActiveData();
}
m_pPrivate->rollbackCreatedLayers(
bCreatedMesh, bCreatedScalarBar, bCreatedScaleGrid);
delete pCandidateAdapter;
if(pError != nullptr) {
*pError = controllerText(
"Unable to commit the result render data.");
}
return false;
}
nmPebiResultSnapshotRenderAdapter* pPreviousAdapter =
m_pPrivate->m_pAdapter;
m_pPrivate->m_pAdapter = pCandidateAdapter;
m_pPrivate->m_pSnapshot = pSnapshot;
m_pPrivate->m_listAvailablePropertyIds =
pSnapshot->getAvailablePropertyIds();
m_pPrivate->m_sCurrentPropertyId = sInitialProperty;
m_pPrivate->m_nCurrentFrameIndex = 0;
m_pPrivate->m_dBusinessRange[0] = dBusinessRange[0];
m_pPrivate->m_dBusinessRange[1] = dBusinessRange[1];
m_pPrivate->m_dDisplayRange[0] = dDisplayRange[0];
m_pPrivate->m_dDisplayRange[1] = dDisplayRange[1];
copyBounds(dBounds, m_pPrivate->m_dBounds);
m_pPrivate->m_bHasPropertyRange = true;
m_pPrivate->m_bHasBounds = true;
m_pPrivate->m_pScalarBarLayer->setLookupTable(
m_pPrivate->m_pMeshLayer->getLookupTable());
m_pPrivate->applyLayerVisibility(true);
// Mapper 已不再引用旧 Producer,此时才允许释放旧 Adapter。
delete pPreviousAdapter;
const bool bViewFitted =
m_pPrivate->m_pContainer->fitTopViewWithoutRender();
const bool bCenterReset =
m_pPrivate->m_pContainer->resetRotationCenterWithoutRender();
Q_ASSERT(bViewFitted && bCenterReset);
Q_UNUSED(bViewFitted);
Q_UNUSED(bCenterReset);
// showReadyState 是本提交路径唯一的 Render 入口。
m_pPrivate->m_pContainer->showReadyState();
return true;
}
void nmPebiResultSceneController::clear()
{
Q_ASSERT(isResultSceneGuiThread());
if(isResultSceneGuiThread() && m_pPrivate != nullptr) {
m_pPrivate->releaseActiveData();
}
}
bool nmPebiResultSceneController::applyPropertyFrame(
const QString& sPropertyId,
int nFrameIndex,
QString* pError)
{
Q_ASSERT(isResultSceneGuiThread());
if(pError != nullptr) {
pError->clear();
}
if(isResultSceneGuiThread() && m_pPrivate != nullptr) {
m_pPrivate->discardActiveDataIfLayersLost();
}
if(!isResultSceneGuiThread() || m_pPrivate == nullptr ||
m_pPrivate->m_pAdapter == nullptr ||
m_pPrivate->m_pSnapshot.isNull() ||
!m_pPrivate->hasOwnedBaseLayers() ||
!m_pPrivate->m_pSnapshot->hasProperty(sPropertyId) ||
nFrameIndex < 0 ||
nFrameIndex >= m_pPrivate->m_pSnapshot->getPropertyFrameCount(
sPropertyId)) {
if(pError != nullptr) {
*pError = controllerText(
"The requested result property or frame is invalid.");
}
return false;
}
nmPebiResultPropertyDescriptor oDescriptor;
if(!nmPebiResultPropertyCatalog::findDescriptor(
sPropertyId, oDescriptor) ||
oDescriptor.m_eAssociation !=
NM_PebiResultPropertyAssociation_CellData ||
(oDescriptor.m_eTimeType == NM_PebiResultProperty_Static &&
nFrameIndex != 0)) {
if(pError != nullptr) {
*pError = controllerText(
"The requested result property or frame is invalid.");
}
return false;
}
if(sPropertyId == m_pPrivate->m_sCurrentPropertyId &&
nFrameIndex == m_pPrivate->m_nCurrentFrameIndex) {
return true;
}
double dBusinessRange[2];
double dDisplayRange[2];
if(!getValidatedPropertyRanges(
m_pPrivate->m_pSnapshot, sPropertyId,
dBusinessRange, dDisplayRange)) {
if(pError != nullptr) {
*pError = controllerText(
"The result property range is invalid.");
}
return false;
}
const QString sPreviousProperty =
m_pPrivate->m_sCurrentPropertyId;
const int nPreviousFrame = m_pPrivate->m_nCurrentFrameIndex;
const double dPreviousDisplayRange[2] = {
m_pPrivate->m_dDisplayRange[0],
m_pPrivate->m_dDisplayRange[1]
};
bool bApplied = m_pPrivate->m_pAdapter->setPropertyFrame(
sPropertyId, nFrameIndex);
double dCurrentBounds[6];
if(bApplied) {
bApplied = validateAdapterOutput(
m_pPrivate->m_pAdapter,
m_pPrivate->m_pSnapshot->getResultCellCount(),
dCurrentBounds) &&
m_pPrivate->m_pMeshLayer->setScalarArray(
m_pPrivate->m_pAdapter->getCurrentScalarArrayName(),
nmVTKMeshLayer::ScalarAssociation_CellData,
dDisplayRange[0], dDisplayRange[1]);
}
if(!bApplied) {
const bool bAdapterRestored =
m_pPrivate->m_pAdapter->setPropertyFrame(
sPreviousProperty, nPreviousFrame);
const bool bMapperRestored = bAdapterRestored &&
m_pPrivate->m_pMeshLayer->setScalarArray(
m_pPrivate->m_pAdapter->getCurrentScalarArrayName(),
nmVTKMeshLayer::ScalarAssociation_CellData,
dPreviousDisplayRange[0], dPreviousDisplayRange[1]);
if(!bMapperRestored) {
// 极端恢复失败时清空逻辑和 VTK 状态,保证查询结果与实际画面一致。
m_pPrivate->releaseActiveData();
}
if(pError != nullptr) {
*pError = controllerText(
"Unable to apply the result property or frame.");
}
return false;
}
m_pPrivate->m_sCurrentPropertyId = sPropertyId;
m_pPrivate->m_nCurrentFrameIndex = nFrameIndex;
m_pPrivate->m_dBusinessRange[0] = dBusinessRange[0];
m_pPrivate->m_dBusinessRange[1] = dBusinessRange[1];
m_pPrivate->m_dDisplayRange[0] = dDisplayRange[0];
m_pPrivate->m_dDisplayRange[1] = dDisplayRange[1];
m_pPrivate->m_bHasPropertyRange = true;
m_pPrivate->m_pContainer->renderView();
return true;
}
void nmPebiResultSceneController::setMeshVisible(bool bVisible)
{
Q_ASSERT(isResultSceneGuiThread());
if(!isResultSceneGuiThread() || m_pPrivate == nullptr) {
return;
}
m_pPrivate->discardActiveDataIfLayersLost();
if(m_pPrivate->m_bMeshVisible == bVisible) {
return;
}
m_pPrivate->m_bMeshVisible = bVisible;
const bool bHasData = hasSnapshot();
m_pPrivate->applyLayerVisibility(bHasData);
if(bHasData) {
m_pPrivate->m_pContainer->renderView();
}
}
void nmPebiResultSceneController::setScalarBarVisible(bool bVisible)
{
Q_ASSERT(isResultSceneGuiThread());
if(!isResultSceneGuiThread() || m_pPrivate == nullptr) {
return;
}
m_pPrivate->discardActiveDataIfLayersLost();
if(m_pPrivate->m_bScalarBarVisible == bVisible) {
return;
}
m_pPrivate->m_bScalarBarVisible = bVisible;
const bool bHasData = hasSnapshot();
m_pPrivate->applyLayerVisibility(bHasData);
if(bHasData) {
m_pPrivate->m_pContainer->renderView();
}
}
void nmPebiResultSceneController::setScaleGridVisible(bool bVisible)
{
Q_ASSERT(isResultSceneGuiThread());
if(!isResultSceneGuiThread() || m_pPrivate == nullptr) {
return;
}
m_pPrivate->discardActiveDataIfLayersLost();
if(m_pPrivate->m_bScaleGridVisible == bVisible) {
return;
}
m_pPrivate->m_bScaleGridVisible = bVisible;
const bool bHasData = hasSnapshot();
m_pPrivate->applyLayerVisibility(bHasData);
if(bHasData) {
m_pPrivate->m_pContainer->renderView();
}
}
void nmPebiResultSceneController::setCellEdgesVisible(bool bVisible)
{
Q_ASSERT(isResultSceneGuiThread());
if(!isResultSceneGuiThread() || m_pPrivate == nullptr) {
return;
}
m_pPrivate->discardActiveDataIfLayersLost();
if(m_pPrivate->m_bCellEdgesVisible == bVisible) {
return;
}
m_pPrivate->m_bCellEdgesVisible = bVisible;
const bool bHasData = hasSnapshot();
m_pPrivate->applyLayerVisibility(bHasData);
if(bHasData) {
m_pPrivate->m_pContainer->renderView();
}
}
bool nmPebiResultSceneController::hasSnapshot() const
{
return isResultSceneGuiThread() &&
m_pPrivate != nullptr &&
m_pPrivate->m_pAdapter != nullptr &&
!m_pPrivate->m_pSnapshot.isNull() &&
m_pPrivate->hasOwnedBaseLayers();
}
QString nmPebiResultSceneController::getCurrentSnapshotId() const
{
return hasSnapshot()
? m_pPrivate->m_pSnapshot->getSnapshotId() : QString();
}
QStringList nmPebiResultSceneController::getAvailablePropertyIds() const
{
return hasSnapshot()
? m_pPrivate->m_listAvailablePropertyIds : QStringList();
}
QString nmPebiResultSceneController::getCurrentPropertyId() const
{
return hasSnapshot()
? m_pPrivate->m_sCurrentPropertyId : QString();
}
int nmPebiResultSceneController::getCurrentFrameIndex() const
{
return hasSnapshot()
? m_pPrivate->m_nCurrentFrameIndex : -1;
}
bool nmPebiResultSceneController::isPropertyTimeDependent(
const QString& sPropertyId) const
{
if(!hasSnapshot() ||
!m_pPrivate->m_pSnapshot->hasProperty(sPropertyId)) {
return false;
}
nmPebiResultPropertyDescriptor oDescriptor;
return nmPebiResultPropertyCatalog::findDescriptor(
sPropertyId, oDescriptor) &&
oDescriptor.m_eTimeType == NM_PebiResultProperty_Dynamic;
}
int nmPebiResultSceneController::getPropertyFrameCount(
const QString& sPropertyId) const
{
return hasSnapshot()
? m_pPrivate->m_pSnapshot->getPropertyFrameCount(sPropertyId)
: 0;
}
bool nmPebiResultSceneController::getPropertyTimeAt(
const QString& sPropertyId,
int nFrameIndex,
double& dTime) const
{
// 快照接口保证失败时不写输出参数,这里直接保持该事务语义。
return hasSnapshot() &&
m_pPrivate->m_pSnapshot->getPropertyTimeAt(
sPropertyId, nFrameIndex, dTime);
}
bool nmPebiResultSceneController::getCurrentPropertyRange(
double dRange[2]) const
{
if(!hasSnapshot() || dRange == nullptr ||
!m_pPrivate->m_bHasPropertyRange) {
return false;
}
dRange[0] = m_pPrivate->m_dBusinessRange[0];
dRange[1] = m_pPrivate->m_dBusinessRange[1];
return true;
}
bool nmPebiResultSceneController::isMeshVisible() const
{
return m_pPrivate != nullptr && m_pPrivate->m_bMeshVisible;
}
bool nmPebiResultSceneController::isScalarBarVisible() const
{
return m_pPrivate != nullptr && m_pPrivate->m_bScalarBarVisible;
}
bool nmPebiResultSceneController::isScaleGridVisible() const
{
return m_pPrivate != nullptr && m_pPrivate->m_bScaleGridVisible;
}
bool nmPebiResultSceneController::areCellEdgesVisible() const
{
return m_pPrivate != nullptr && m_pPrivate->m_bCellEdgesVisible;
}