|
|
#include "nmPebiResultSceneController.h"
|
|
|
|
|
|
#include "nmPebiResultPropertyCatalog.h"
|
|
|
#include "nmPebiResultPropertyDisplayText.h"
|
|
|
#include "nmPebiResultSnapshot.h"
|
|
|
#include "nmPebiResultSnapshotRenderAdapter.h"
|
|
|
#include "nmPebiResultWellAnnotationLayer.h"
|
|
|
|
|
|
#include "nmVTKColorMapCatalog.h"
|
|
|
#include "nmVTKMeshLayer.h"
|
|
|
#include "nmVTKPlanarScaleGridLayer.h"
|
|
|
#include "nmVTKScalarBarLayer.h"
|
|
|
#include "nmVTKScene.h"
|
|
|
#include "nmWxVTKRenderContainerWidget.h"
|
|
|
|
|
|
#include <QCoreApplication>
|
|
|
#include <QMap>
|
|
|
#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."),
|
|
|
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
|
|
|
"The color settings no longer match the current result."),
|
|
|
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
|
|
|
"The color settings are invalid."),
|
|
|
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
|
|
|
"The selected color map is unavailable."),
|
|
|
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
|
|
|
"The manual range must contain two finite increasing values."),
|
|
|
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
|
|
|
"Logarithmic scale requires positive property and display ranges."),
|
|
|
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
|
|
|
"Unable to construct the color mapping."),
|
|
|
QT_TRANSLATE_NOOP("nmPebiResultSceneController",
|
|
|
"Unable to apply the color settings."),
|
|
|
QT_TRANSLATE_NOOP("nmPebiResultSceneController", "Below min"),
|
|
|
QT_TRANSLATE_NOOP("nmPebiResultSceneController", "Above max")
|
|
|
};
|
|
|
|
|
|
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 getInternalDisplayRange(const double dVisibleRange[2],
|
|
|
bool bLogarithmic,
|
|
|
double dInternalRange[2])
|
|
|
{
|
|
|
if(dVisibleRange == nullptr || dInternalRange == nullptr ||
|
|
|
!vtkMath::IsFinite(dVisibleRange[0]) ||
|
|
|
!vtkMath::IsFinite(dVisibleRange[1]) ||
|
|
|
dVisibleRange[0] > dVisibleRange[1] ||
|
|
|
(bLogarithmic && dVisibleRange[0] <= 0.0)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
dInternalRange[0] = dVisibleRange[0];
|
|
|
dInternalRange[1] = dVisibleRange[1];
|
|
|
if(dVisibleRange[0] < dVisibleRange[1]) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// VTK 不接受零宽范围。常量值只扩展内部 LUT,业务和可见范围仍为 [c,c]。
|
|
|
const double dValue = dVisibleRange[0];
|
|
|
double dMinimum = 0.0;
|
|
|
double dMaximum = 0.0;
|
|
|
if(bLogarithmic) {
|
|
|
dMinimum = dValue * (1.0 - 1.0e-6);
|
|
|
dMaximum = dValue * (1.0 + 1.0e-6);
|
|
|
if(!vtkMath::IsFinite(dMinimum) || dMinimum <= 0.0 ||
|
|
|
dMinimum >= dValue) {
|
|
|
const double dHalfValue = dValue / 2.0;
|
|
|
dMinimum = dHalfValue > 0.0 && dHalfValue < dValue
|
|
|
? dHalfValue : dValue;
|
|
|
}
|
|
|
if(!vtkMath::IsFinite(dMaximum) || dMaximum <= dValue) {
|
|
|
const double dTwiceValue = dValue * 2.0;
|
|
|
dMaximum = vtkMath::IsFinite(dTwiceValue) &&
|
|
|
dTwiceValue > dValue ? dTwiceValue : dValue;
|
|
|
}
|
|
|
} else if(dValue == 0.0) {
|
|
|
dMinimum = -1.0e-6;
|
|
|
dMaximum = 1.0e-6;
|
|
|
} else {
|
|
|
const double dEpsilon = qMax(1.0, fabs(dValue)) * 1.0e-6;
|
|
|
dMinimum = dValue - dEpsilon;
|
|
|
dMaximum = dValue + dEpsilon;
|
|
|
if(!vtkMath::IsFinite(dMinimum) || dMinimum >= dValue) {
|
|
|
dMinimum = dValue > 0.0 ? dValue / 2.0 : dValue;
|
|
|
}
|
|
|
if(!vtkMath::IsFinite(dMaximum) || dMaximum <= dValue) {
|
|
|
dMaximum = dValue < 0.0 ? dValue / 2.0 : dValue;
|
|
|
}
|
|
|
}
|
|
|
if(!vtkMath::IsFinite(dMinimum) || !vtkMath::IsFinite(dMaximum) ||
|
|
|
dMinimum >= dMaximum || (bLogarithmic && dMinimum <= 0.0)) {
|
|
|
return false;
|
|
|
}
|
|
|
dInternalRange[0] = dMinimum;
|
|
|
dInternalRange[1] = dMaximum;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
struct ResultDisplayCandidate
|
|
|
{
|
|
|
ResultDisplayCandidate()
|
|
|
: m_pLookupTable(nullptr),
|
|
|
m_bConstantValueLabel(false)
|
|
|
{
|
|
|
m_dBusinessRange[0] = m_dBusinessRange[1] = 0.0;
|
|
|
m_dVisibleRange[0] = m_dVisibleRange[1] = 0.0;
|
|
|
m_dInternalRange[0] = 0.0;
|
|
|
m_dInternalRange[1] = 1.0;
|
|
|
}
|
|
|
|
|
|
nmPebiResultDisplaySettings m_oSettings;
|
|
|
double m_dBusinessRange[2];
|
|
|
double m_dVisibleRange[2];
|
|
|
double m_dInternalRange[2];
|
|
|
vtkSmartPointer<vtkLookupTable> m_pLookupTable;
|
|
|
QString m_sScalarBarTitle;
|
|
|
bool m_bConstantValueLabel;
|
|
|
};
|
|
|
|
|
|
bool prepareDisplayCandidate(
|
|
|
const QSharedPointer<const nmPebiResultSnapshot>& pSnapshot,
|
|
|
const QString& sPropertyId,
|
|
|
const nmPebiResultDisplaySettings& oRequestedSettings,
|
|
|
ResultDisplayCandidate& oCandidate,
|
|
|
QString* pError)
|
|
|
{
|
|
|
nmPebiResultDisplaySettings oSettings = oRequestedSettings.normalized();
|
|
|
if(pSnapshot.isNull() || !pSnapshot->hasProperty(sPropertyId) ||
|
|
|
!oSettings.isStructurallyValid()) {
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText("The color settings are invalid.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
if(!nmVTKColorMapCatalog::contains(oSettings.m_sColorMapId)) {
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText("The selected color map is unavailable.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
double dBusinessRange[2] = { 0.0, 0.0 };
|
|
|
if(!pSnapshot->getPropertyRange(sPropertyId, dBusinessRange) ||
|
|
|
!vtkMath::IsFinite(dBusinessRange[0]) ||
|
|
|
!vtkMath::IsFinite(dBusinessRange[1]) ||
|
|
|
dBusinessRange[0] > dBusinessRange[1]) {
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText("The result property range is invalid.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
double dVisibleRange[2] = {
|
|
|
dBusinessRange[0], dBusinessRange[1]
|
|
|
};
|
|
|
if(oSettings.m_bHasManualRange) {
|
|
|
if(!vtkMath::IsFinite(oSettings.m_dManualMinimum) ||
|
|
|
!vtkMath::IsFinite(oSettings.m_dManualMaximum) ||
|
|
|
oSettings.m_dManualMinimum >= oSettings.m_dManualMaximum) {
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText(
|
|
|
"The manual range must contain two finite increasing values.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
dVisibleRange[0] = oSettings.m_dManualMinimum;
|
|
|
dVisibleRange[1] = oSettings.m_dManualMaximum;
|
|
|
}
|
|
|
|
|
|
const bool bLogarithmic =
|
|
|
oSettings.m_eScaleMode == NM_PebiColorScale_Logarithmic;
|
|
|
if(bLogarithmic &&
|
|
|
(dBusinessRange[0] <= 0.0 || dVisibleRange[0] <= 0.0)) {
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText(
|
|
|
"Logarithmic scale requires positive property and display ranges.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
double dInternalRange[2] = { 0.0, 1.0 };
|
|
|
vtkSmartPointer<vtkLookupTable> pLookupTable =
|
|
|
nmVTKColorMapCatalog::createLookupTable(
|
|
|
oSettings.m_sColorMapId);
|
|
|
if(pLookupTable == nullptr ||
|
|
|
!getInternalDisplayRange(dVisibleRange, bLogarithmic,
|
|
|
dInternalRange)) {
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText("Unable to construct the color mapping.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
pLookupTable->SetTableRange(dInternalRange);
|
|
|
if(bLogarithmic) {
|
|
|
pLookupTable->SetScaleToLog10();
|
|
|
} else {
|
|
|
pLookupTable->SetScaleToLinear();
|
|
|
}
|
|
|
const QColor oBelowColor = oSettings.m_oBelowRangeColor;
|
|
|
const QColor oAboveColor = oSettings.m_oAboveRangeColor;
|
|
|
pLookupTable->SetBelowRangeColor(
|
|
|
oBelowColor.redF(), oBelowColor.greenF(),
|
|
|
oBelowColor.blueF(), 1.0);
|
|
|
pLookupTable->SetAboveRangeColor(
|
|
|
oAboveColor.redF(), oAboveColor.greenF(),
|
|
|
oAboveColor.blueF(), 1.0);
|
|
|
pLookupTable->SetUseBelowRangeColor(
|
|
|
oSettings.m_bUseBelowRangeColor ? 1 : 0);
|
|
|
pLookupTable->SetUseAboveRangeColor(
|
|
|
oSettings.m_bUseAboveRangeColor ? 1 : 0);
|
|
|
// VTK 7.1 的上下越界颜色位于特殊表项中,Setter 后必须显式同步。
|
|
|
// 不能使用 ForceBuild,否则会覆盖色带目录手工写入的 256 个颜色表项。
|
|
|
pLookupTable->BuildSpecialColors();
|
|
|
pLookupTable->IndexedLookupOff();
|
|
|
pLookupTable->ResetAnnotations();
|
|
|
|
|
|
const bool bConstantValueLabel =
|
|
|
!oSettings.m_bHasManualRange &&
|
|
|
dBusinessRange[0] == dBusinessRange[1];
|
|
|
QString sTitle =
|
|
|
nmPebiResultPropertyDisplayText::getDisplayName(sPropertyId);
|
|
|
const QString sUnit =
|
|
|
nmPebiResultPropertyDisplayText::getDefaultDisplayUnit(sPropertyId);
|
|
|
if(!sUnit.isEmpty()) {
|
|
|
sTitle += QString::fromLatin1(" (") + sUnit +
|
|
|
QString::fromLatin1(")");
|
|
|
}
|
|
|
|
|
|
oCandidate.m_oSettings = oSettings;
|
|
|
oCandidate.m_dBusinessRange[0] = dBusinessRange[0];
|
|
|
oCandidate.m_dBusinessRange[1] = dBusinessRange[1];
|
|
|
oCandidate.m_dVisibleRange[0] = dVisibleRange[0];
|
|
|
oCandidate.m_dVisibleRange[1] = dVisibleRange[1];
|
|
|
oCandidate.m_dInternalRange[0] = dInternalRange[0];
|
|
|
oCandidate.m_dInternalRange[1] = dInternalRange[1];
|
|
|
oCandidate.m_pLookupTable = pLookupTable;
|
|
|
oCandidate.m_sScalarBarTitle = sTitle;
|
|
|
oCandidate.m_bConstantValueLabel = bConstantValueLabel;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
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 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_pWellLayer(nullptr),
|
|
|
m_pAdapter(nullptr),
|
|
|
m_nCurrentFrameIndex(-1),
|
|
|
m_nSnapshotBindingRevision(0),
|
|
|
m_bHasPropertyRange(false),
|
|
|
m_bHasBounds(false),
|
|
|
m_bScalarBarVisible(true),
|
|
|
m_bScaleGridVisible(false),
|
|
|
m_bCellEdgesVisible(false),
|
|
|
m_bWellMarkersVisible(true),
|
|
|
m_bWellNamesVisible(true)
|
|
|
{
|
|
|
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;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
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_pWellLayer == nullptr;
|
|
|
m_pMeshLayer = nullptr;
|
|
|
m_pScalarBarLayer = nullptr;
|
|
|
m_pScaleGridLayer = nullptr;
|
|
|
m_pWellLayer = 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;
|
|
|
}
|
|
|
if(m_pWellLayer != nullptr &&
|
|
|
pScene->getLayer(
|
|
|
QString::fromLatin1(RESULT_WELLS_LAYER_ID)) !=
|
|
|
m_pWellLayer) {
|
|
|
m_pWellLayer = 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 &&
|
|
|
m_pWellLayer != 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 &&
|
|
|
pScene->getLayer(
|
|
|
QString::fromLatin1(RESULT_WELLS_LAYER_ID)) ==
|
|
|
m_pWellLayer;
|
|
|
}
|
|
|
|
|
|
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,
|
|
|
bool& bCreatedWells)
|
|
|
{
|
|
|
bCreatedMesh = false;
|
|
|
bCreatedScalarBar = false;
|
|
|
bCreatedScaleGrid = false;
|
|
|
bCreatedWells = 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, 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, 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, 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, false);
|
|
|
return false;
|
|
|
}
|
|
|
m_pScaleGridLayer = pLayer;
|
|
|
bCreatedScaleGrid = true;
|
|
|
}
|
|
|
|
|
|
if(m_pWellLayer == nullptr) {
|
|
|
if(pScene->getLayer(QString::fromLatin1(
|
|
|
RESULT_WELLS_LAYER_ID)) != nullptr) {
|
|
|
rollbackCreatedLayers(
|
|
|
bCreatedMesh, bCreatedScalarBar,
|
|
|
bCreatedScaleGrid, false);
|
|
|
return false;
|
|
|
}
|
|
|
nmPebiResultWellAnnotationLayer* pLayer =
|
|
|
new nmPebiResultWellAnnotationLayer(
|
|
|
QString::fromLatin1(RESULT_WELLS_LAYER_ID));
|
|
|
pLayer->setVisible(false);
|
|
|
pLayer->setWellMarkersVisible(m_bWellMarkersVisible);
|
|
|
pLayer->setWellNamesVisible(m_bWellNamesVisible);
|
|
|
if(!pScene->addLayer(pLayer)) {
|
|
|
delete pLayer;
|
|
|
rollbackCreatedLayers(
|
|
|
bCreatedMesh, bCreatedScalarBar,
|
|
|
bCreatedScaleGrid, false);
|
|
|
return false;
|
|
|
}
|
|
|
m_pWellLayer = pLayer;
|
|
|
bCreatedWells = true;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void rollbackCreatedLayers(bool bCreatedMesh,
|
|
|
bool bCreatedScalarBar,
|
|
|
bool bCreatedScaleGrid,
|
|
|
bool bCreatedWells)
|
|
|
{
|
|
|
synchronizeLayerPointers();
|
|
|
nmVTKScene* pScene = getScene();
|
|
|
if(pScene == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
if(bCreatedWells && m_pWellLayer != nullptr &&
|
|
|
pScene->getLayer(
|
|
|
QString::fromLatin1(RESULT_WELLS_LAYER_ID)) ==
|
|
|
m_pWellLayer) {
|
|
|
pScene->removeLayer(
|
|
|
QString::fromLatin1(RESULT_WELLS_LAYER_ID));
|
|
|
}
|
|
|
if(bCreatedWells) {
|
|
|
m_pWellLayer = nullptr;
|
|
|
}
|
|
|
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,
|
|
|
vtkLookupTable* pLookupTable)
|
|
|
{
|
|
|
if(m_pMeshLayer == nullptr || pAdapter == nullptr ||
|
|
|
pLookupTable == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// MeshLayer 在触碰旧 Mapper 前完成全部校验,失败不会破坏旧画面。
|
|
|
return m_pMeshLayer->setInputConnection(
|
|
|
pAdapter->getOutputPort(),
|
|
|
pAdapter->getCurrentScalarArrayName(),
|
|
|
nmVTKMeshLayer::ScalarAssociation_CellData,
|
|
|
pLookupTable);
|
|
|
}
|
|
|
|
|
|
void applyScalarBarState(const ResultDisplayCandidate& oDisplay)
|
|
|
{
|
|
|
if(m_pScalarBarLayer == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
m_pScalarBarLayer->setLookupTable(oDisplay.m_pLookupTable);
|
|
|
m_pScalarBarLayer->setTitle(oDisplay.m_sScalarBarTitle);
|
|
|
m_pScalarBarLayer->setLabelFormat(QString::fromLatin1("%.6g"));
|
|
|
m_pScalarBarLayer->setNumberOfLabels(
|
|
|
oDisplay.m_bConstantValueLabel ? 0 : 5);
|
|
|
m_pScalarBarLayer->setConstantValueLabel(
|
|
|
oDisplay.m_bConstantValueLabel,
|
|
|
oDisplay.m_bConstantValueLabel
|
|
|
? QString::number(oDisplay.m_dBusinessRange[0], 'g', 6)
|
|
|
: QString());
|
|
|
m_pScalarBarLayer->setBelowRangeSwatch(
|
|
|
oDisplay.m_oSettings.m_bUseBelowRangeColor,
|
|
|
controllerText("Below min"));
|
|
|
m_pScalarBarLayer->setAboveRangeSwatch(
|
|
|
oDisplay.m_oSettings.m_bUseAboveRangeColor,
|
|
|
controllerText("Above max"));
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
if(m_pScalarBarLayer != nullptr) {
|
|
|
m_pScalarBarLayer->setVisible(
|
|
|
bHasData && m_bScalarBarVisible);
|
|
|
}
|
|
|
if(m_pScaleGridLayer != nullptr) {
|
|
|
m_pScaleGridLayer->setVisible(
|
|
|
bHasData && m_bScaleGridVisible);
|
|
|
}
|
|
|
if(m_pWellLayer != nullptr) {
|
|
|
m_pWellLayer->setWellMarkersVisible(m_bWellMarkersVisible);
|
|
|
m_pWellLayer->setWellNamesVisible(m_bWellNamesVisible);
|
|
|
m_pWellLayer->setVisible(bHasData);
|
|
|
}
|
|
|
if(m_pContainer != nullptr) {
|
|
|
m_pContainer->setRotationCenterPickTarget(
|
|
|
bHasData && 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());
|
|
|
m_pScalarBarLayer->setNumberOfLabels(5);
|
|
|
m_pScalarBarLayer->setBelowRangeSwatch(false, QString());
|
|
|
m_pScalarBarLayer->setAboveRangeSwatch(false, QString());
|
|
|
m_pScalarBarLayer->setConstantValueLabel(false, QString());
|
|
|
}
|
|
|
applyLayerVisibility(false);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
const bool bMeshRestored = m_pMeshLayer->getLookupTable() != nullptr &&
|
|
|
bindMeshAdapter(m_pAdapter, m_pMeshLayer->getLookupTable());
|
|
|
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());
|
|
|
m_pScalarBarLayer->setNumberOfLabels(5);
|
|
|
m_pScalarBarLayer->setBelowRangeSwatch(false, QString());
|
|
|
m_pScalarBarLayer->setAboveRangeSwatch(false, QString());
|
|
|
m_pScalarBarLayer->setConstantValueLabel(false, QString());
|
|
|
}
|
|
|
if(m_pScaleGridLayer != nullptr) {
|
|
|
m_pScaleGridLayer->setVisible(false);
|
|
|
}
|
|
|
if(m_pWellLayer != nullptr) {
|
|
|
m_pWellLayer->setVisible(false);
|
|
|
m_pWellLayer->clear();
|
|
|
}
|
|
|
delete m_pAdapter;
|
|
|
m_pAdapter = nullptr;
|
|
|
m_pSnapshot.clear();
|
|
|
m_listAvailablePropertyIds.clear();
|
|
|
m_sCurrentPropertyId.clear();
|
|
|
m_nCurrentFrameIndex = -1;
|
|
|
m_bHasPropertyRange = false;
|
|
|
m_bHasBounds = false;
|
|
|
// clear()保留窗口样式,但任何活动快照相关的手工范围都必须失效。
|
|
|
QMap<QString, nmPebiResultDisplaySettings>::iterator oIterator =
|
|
|
m_mapDisplaySettings.begin();
|
|
|
for(; oIterator != m_mapDisplaySettings.end(); ++oIterator) {
|
|
|
oIterator.value().m_bHasManualRange = false;
|
|
|
oIterator.value().m_dManualMinimum = 0.0;
|
|
|
oIterator.value().m_dManualMaximum = 0.0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void removeOwnedLayers()
|
|
|
{
|
|
|
synchronizeLayerPointers();
|
|
|
nmVTKScene* pScene = getScene();
|
|
|
if(pScene == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 只删除仍与本控制器记录身份一致的图层,绝不误删同 ID 的外部替代层。
|
|
|
if(m_pWellLayer != nullptr &&
|
|
|
pScene->getLayer(
|
|
|
QString::fromLatin1(RESULT_WELLS_LAYER_ID)) ==
|
|
|
m_pWellLayer) {
|
|
|
pScene->removeLayer(
|
|
|
QString::fromLatin1(RESULT_WELLS_LAYER_ID));
|
|
|
}
|
|
|
m_pWellLayer = nullptr;
|
|
|
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 所有。
|
|
|
nmPebiResultWellAnnotationLayer* m_pWellLayer; ///< Scene 所有。
|
|
|
nmPebiResultSnapshotRenderAdapter* m_pAdapter; ///< 控制器独占。
|
|
|
QSharedPointer<const nmPebiResultSnapshot> m_pSnapshot;
|
|
|
QStringList m_listAvailablePropertyIds;
|
|
|
QString m_sCurrentPropertyId;
|
|
|
/** @brief 按稳定属性 ID 保存的窗口级样式;clear 不删除。 */
|
|
|
QMap<QString, nmPebiResultDisplaySettings> m_mapDisplaySettings;
|
|
|
int m_nCurrentFrameIndex;
|
|
|
/** @brief 不同快照对象完整提交成功后的单调序号,clear 和失败均不回退。 */
|
|
|
quint64 m_nSnapshotBindingRevision;
|
|
|
double m_dBusinessRange[2];
|
|
|
double m_dDisplayRange[2];
|
|
|
double m_dBounds[6];
|
|
|
bool m_bHasPropertyRange;
|
|
|
bool m_bHasBounds;
|
|
|
bool m_bScalarBarVisible;
|
|
|
bool m_bScaleGridVisible;
|
|
|
bool m_bCellEdgesVisible;
|
|
|
bool m_bWellMarkersVisible;
|
|
|
bool m_bWellNamesVisible;
|
|
|
};
|
|
|
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
// 新快照只继承样式;所有属性的手工范围都在候选表中先清除。
|
|
|
QMap<QString, nmPebiResultDisplaySettings> mapCandidateSettings =
|
|
|
m_pPrivate->m_mapDisplaySettings;
|
|
|
QMap<QString, nmPebiResultDisplaySettings>::iterator oSettingsIterator =
|
|
|
mapCandidateSettings.begin();
|
|
|
for(; oSettingsIterator != mapCandidateSettings.end();
|
|
|
++oSettingsIterator) {
|
|
|
oSettingsIterator.value().m_bHasManualRange = false;
|
|
|
oSettingsIterator.value().m_dManualMinimum = 0.0;
|
|
|
oSettingsIterator.value().m_dManualMaximum = 0.0;
|
|
|
oSettingsIterator.value() = oSettingsIterator.value().normalized();
|
|
|
}
|
|
|
const QStringList listCandidatePropertyIds =
|
|
|
pSnapshot->getAvailablePropertyIds();
|
|
|
QString sDisplayError;
|
|
|
for(int nPropertyIndex = 0;
|
|
|
nPropertyIndex < listCandidatePropertyIds.size();
|
|
|
++nPropertyIndex) {
|
|
|
const QString& sPropertyId =
|
|
|
listCandidatePropertyIds[nPropertyIndex];
|
|
|
nmPebiResultDisplaySettings oSettings =
|
|
|
mapCandidateSettings.value(
|
|
|
sPropertyId, nmPebiResultDisplaySettings()).normalized();
|
|
|
double dPropertyRange[2] = { 0.0, 0.0 };
|
|
|
if(!pSnapshot->getPropertyRange(sPropertyId, dPropertyRange)) {
|
|
|
delete pCandidateAdapter;
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText(
|
|
|
"The result property range is invalid.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
if(oSettings.m_eScaleMode == NM_PebiColorScale_Logarithmic &&
|
|
|
dPropertyRange[0] <= 0.0) {
|
|
|
// 当前快照不支持原 Log 时永久降级,避免保留不可见的隐藏偏好。
|
|
|
oSettings.m_eScaleMode = NM_PebiColorScale_Linear;
|
|
|
}
|
|
|
mapCandidateSettings.insert(sPropertyId, oSettings);
|
|
|
|
|
|
// 在触碰活动 Scene 前预检每个可用属性,避免隐藏的无效偏好延迟到切换时。
|
|
|
ResultDisplayCandidate oPropertyDisplayCandidate;
|
|
|
if(!prepareDisplayCandidate(
|
|
|
pSnapshot, sPropertyId, oSettings,
|
|
|
oPropertyDisplayCandidate, &sDisplayError)) {
|
|
|
delete pCandidateAdapter;
|
|
|
if(pError != nullptr) {
|
|
|
*pError = sDisplayError;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
ResultDisplayCandidate oDisplayCandidate;
|
|
|
if(!prepareDisplayCandidate(
|
|
|
pSnapshot, sInitialProperty,
|
|
|
mapCandidateSettings.value(sInitialProperty),
|
|
|
oDisplayCandidate, &sDisplayError)) {
|
|
|
delete pCandidateAdapter;
|
|
|
if(pError != nullptr) {
|
|
|
*pError = sDisplayError;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
double dBounds[6];
|
|
|
if(pCandidateAdapter->getCurrentScalarArrayName().isEmpty() ||
|
|
|
!validateAdapterOutput(pCandidateAdapter,
|
|
|
pSnapshot->getResultCellCount(), dBounds)) {
|
|
|
delete pCandidateAdapter;
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText(
|
|
|
"The result render data failed validation.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
bool bCreatedMesh = false;
|
|
|
bool bCreatedScalarBar = false;
|
|
|
bool bCreatedScaleGrid = false;
|
|
|
bool bCreatedWells = false;
|
|
|
if(!m_pPrivate->ensureBaseLayers(
|
|
|
bCreatedMesh, bCreatedScalarBar,
|
|
|
bCreatedScaleGrid, bCreatedWells)) {
|
|
|
delete pCandidateAdapter;
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText(
|
|
|
"Unable to create the result render layers.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
if(!m_pPrivate->m_pWellLayer->prepareCandidate(pSnapshot)) {
|
|
|
m_pPrivate->rollbackCreatedLayers(
|
|
|
bCreatedMesh, bCreatedScalarBar,
|
|
|
bCreatedScaleGrid, bCreatedWells);
|
|
|
delete pCandidateAdapter;
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText(
|
|
|
"The result render data failed validation.");
|
|
|
}
|
|
|
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, oDisplayCandidate.m_pLookupTable);
|
|
|
if(!bCommitted) {
|
|
|
m_pPrivate->m_pWellLayer->discardCandidate();
|
|
|
const bool bRestored = m_pPrivate->restorePreviousScene();
|
|
|
if(!bRestored) {
|
|
|
// 不允许 Release 构建留下“逻辑有快照、实际无输入”的半恢复状态。
|
|
|
m_pPrivate->releaseActiveData();
|
|
|
}
|
|
|
m_pPrivate->rollbackCreatedLayers(
|
|
|
bCreatedMesh, bCreatedScalarBar,
|
|
|
bCreatedScaleGrid, bCreatedWells);
|
|
|
delete pCandidateAdapter;
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText(
|
|
|
"Unable to commit the result render data.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// prepareCandidate 成功后,commitCandidate 仅交换 Assembly 子项且没有失败分支。
|
|
|
m_pPrivate->m_pWellLayer->commitCandidate();
|
|
|
|
|
|
nmPebiResultSnapshotRenderAdapter* pPreviousAdapter =
|
|
|
m_pPrivate->m_pAdapter;
|
|
|
m_pPrivate->m_pAdapter = pCandidateAdapter;
|
|
|
m_pPrivate->m_pSnapshot = pSnapshot;
|
|
|
m_pPrivate->m_listAvailablePropertyIds =
|
|
|
listCandidatePropertyIds;
|
|
|
m_pPrivate->m_sCurrentPropertyId = sInitialProperty;
|
|
|
m_pPrivate->m_mapDisplaySettings = mapCandidateSettings;
|
|
|
m_pPrivate->m_nCurrentFrameIndex = 0;
|
|
|
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];
|
|
|
copyBounds(dBounds, m_pPrivate->m_dBounds);
|
|
|
m_pPrivate->m_bHasPropertyRange = true;
|
|
|
m_pPrivate->m_bHasBounds = true;
|
|
|
m_pPrivate->applyScalarBarState(oDisplayCandidate);
|
|
|
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();
|
|
|
// 候选管线、相机和首次 Render 已完整提交,最后才发布新绑定序号。
|
|
|
++m_pPrivate->m_nSnapshotBindingRevision;
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
const nmPebiResultDisplaySettings oTargetSettings =
|
|
|
m_pPrivate->m_mapDisplaySettings.value(
|
|
|
sPropertyId, nmPebiResultDisplaySettings());
|
|
|
ResultDisplayCandidate oDisplayCandidate;
|
|
|
if(!prepareDisplayCandidate(
|
|
|
m_pPrivate->m_pSnapshot, sPropertyId, oTargetSettings,
|
|
|
oDisplayCandidate, pError)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
const QString sPreviousProperty =
|
|
|
m_pPrivate->m_sCurrentPropertyId;
|
|
|
const int nPreviousFrame = m_pPrivate->m_nCurrentFrameIndex;
|
|
|
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,
|
|
|
oDisplayCandidate.m_pLookupTable);
|
|
|
}
|
|
|
if(!bApplied) {
|
|
|
const bool bAdapterRestored =
|
|
|
m_pPrivate->m_pAdapter->setPropertyFrame(
|
|
|
sPreviousProperty, nPreviousFrame);
|
|
|
if(!bAdapterRestored) {
|
|
|
// 极端恢复失败时清空逻辑和 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_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;
|
|
|
}
|
|
|
|
|
|
bool nmPebiResultSceneController::applyCurrentDisplaySettings(
|
|
|
quint64 nExpectedBindingRevision,
|
|
|
const QString& sExpectedSnapshotId,
|
|
|
const QString& sExpectedPropertyId,
|
|
|
const nmPebiResultDisplaySettings& oSettings,
|
|
|
QString* pError)
|
|
|
{
|
|
|
Q_ASSERT(isResultSceneGuiThread());
|
|
|
if(pError != nullptr) {
|
|
|
pError->clear();
|
|
|
}
|
|
|
if(isResultSceneGuiThread() && m_pPrivate != nullptr) {
|
|
|
m_pPrivate->discardActiveDataIfLayersLost();
|
|
|
}
|
|
|
|
|
|
// 身份核对和实际提交处在同一个 GUI 线程调用中,旧对话框不能污染新快照。
|
|
|
if(!isResultSceneGuiThread() || !hasSnapshot() ||
|
|
|
nExpectedBindingRevision == 0 ||
|
|
|
nExpectedBindingRevision != getSnapshotBindingRevision() ||
|
|
|
sExpectedSnapshotId.isEmpty() ||
|
|
|
sExpectedPropertyId.isEmpty() ||
|
|
|
sExpectedSnapshotId != getCurrentSnapshotId() ||
|
|
|
sExpectedPropertyId != m_pPrivate->m_sCurrentPropertyId) {
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText(
|
|
|
"The color settings no longer match the current result.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
ResultDisplayCandidate oDisplayCandidate;
|
|
|
if(!prepareDisplayCandidate(
|
|
|
m_pPrivate->m_pSnapshot,
|
|
|
sExpectedPropertyId,
|
|
|
oSettings,
|
|
|
oDisplayCandidate,
|
|
|
pError)) {
|
|
|
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)) {
|
|
|
if(pError != nullptr) {
|
|
|
*pError = controllerText("Unable to apply the color settings.");
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
m_pPrivate->m_mapDisplaySettings.insert(
|
|
|
sExpectedPropertyId, 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;
|
|
|
}
|
|
|
|
|
|
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();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmPebiResultSceneController::setWellMarkersVisible(bool bVisible)
|
|
|
{
|
|
|
Q_ASSERT(isResultSceneGuiThread());
|
|
|
if(!isResultSceneGuiThread() || m_pPrivate == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
m_pPrivate->discardActiveDataIfLayersLost();
|
|
|
if(m_pPrivate->m_bWellMarkersVisible == bVisible) {
|
|
|
return;
|
|
|
}
|
|
|
m_pPrivate->m_bWellMarkersVisible = bVisible;
|
|
|
if(m_pPrivate->m_pWellLayer != nullptr) {
|
|
|
m_pPrivate->m_pWellLayer->setWellMarkersVisible(bVisible);
|
|
|
}
|
|
|
if(hasSnapshot()) {
|
|
|
m_pPrivate->m_pContainer->renderView();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void nmPebiResultSceneController::setWellNamesVisible(bool bVisible)
|
|
|
{
|
|
|
Q_ASSERT(isResultSceneGuiThread());
|
|
|
if(!isResultSceneGuiThread() || m_pPrivate == nullptr) {
|
|
|
return;
|
|
|
}
|
|
|
m_pPrivate->discardActiveDataIfLayersLost();
|
|
|
if(m_pPrivate->m_bWellNamesVisible == bVisible) {
|
|
|
return;
|
|
|
}
|
|
|
m_pPrivate->m_bWellNamesVisible = bVisible;
|
|
|
if(m_pPrivate->m_pWellLayer != nullptr) {
|
|
|
m_pPrivate->m_pWellLayer->setWellNamesVisible(bVisible);
|
|
|
}
|
|
|
if(hasSnapshot()) {
|
|
|
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() &&
|
|
|
m_pPrivate->m_pWellLayer->hasActiveAnnotations();
|
|
|
}
|
|
|
|
|
|
quint64 nmPebiResultSceneController::getSnapshotBindingRevision() const
|
|
|
{
|
|
|
return m_pPrivate != nullptr
|
|
|
? m_pPrivate->m_nSnapshotBindingRevision : 0;
|
|
|
}
|
|
|
|
|
|
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::getCurrentDisplayRange(
|
|
|
double dRange[2]) const
|
|
|
{
|
|
|
if(!hasSnapshot() || dRange == nullptr ||
|
|
|
!m_pPrivate->m_bHasPropertyRange) {
|
|
|
return false;
|
|
|
}
|
|
|
dRange[0] = m_pPrivate->m_dDisplayRange[0];
|
|
|
dRange[1] = m_pPrivate->m_dDisplayRange[1];
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool nmPebiResultSceneController::getCurrentDisplaySettings(
|
|
|
nmPebiResultDisplaySettings& oSettings) const
|
|
|
{
|
|
|
if(!hasSnapshot() ||
|
|
|
!m_pPrivate->m_mapDisplaySettings.contains(
|
|
|
m_pPrivate->m_sCurrentPropertyId)) {
|
|
|
return false;
|
|
|
}
|
|
|
oSettings = m_pPrivate->m_mapDisplaySettings.value(
|
|
|
m_pPrivate->m_sCurrentPropertyId);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
bool nmPebiResultSceneController::areWellMarkersVisible() const
|
|
|
{
|
|
|
return m_pPrivate != nullptr && m_pPrivate->m_bWellMarkersVisible;
|
|
|
}
|
|
|
|
|
|
bool nmPebiResultSceneController::areWellNamesVisible() const
|
|
|
{
|
|
|
return m_pPrivate != nullptr && m_pPrivate->m_bWellNamesVisible;
|
|
|
}
|