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...

1032 lines
36 KiB
C++

#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::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;
}