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

232 lines
7.7 KiB
C++

#include "nmPebiResultDisplayStateBuilder.h"
#include "nmPebiResultPropertyDisplayText.h"
#include "nmPebiResultSnapshot.h"
#include "nmVTKColorMapCatalog.h"
#include <QCoreApplication>
#include <QtGlobal>
#include <vtkLookupTable.h>
#include <vtkMath.h>
#include <math.h>
namespace {
QString displayStateText(const char* pText)
{
// 沿用原 SceneController 翻译上下文,避免迁移既有 TS 条目。
return QCoreApplication::translate(
"nmPebiResultSceneController", pText);
}
bool getInternalDisplayRange(const double dVisibleRange[2],
bool bLogarithmic,
bool bSingleValueMode,
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;
}
if(dVisibleRange[0] < dVisibleRange[1]) {
dInternalRange[0] = dVisibleRange[0];
dInternalRange[1] = dVisibleRange[1];
return true;
}
if(!bSingleValueMode || dVisibleRange[0] != dVisibleRange[1]) {
return false;
}
// VTK要求映射范围严格递增;微量扩展只供内部映射,不改变业务值。
const double dValue = dVisibleRange[0];
double dMaximum = 0.0;
if(bLogarithmic) {
dMaximum = dValue * (1.0 + 1.0e-6);
if(!vtkMath::IsFinite(dMaximum) || dMaximum <= dValue) {
dMaximum = dValue * 2.0;
}
} else {
const double dEpsilon = qMax(1.0, fabs(dValue)) * 1.0e-6;
dMaximum = dValue + dEpsilon;
}
if(!vtkMath::IsFinite(dMaximum) || dValue >= dMaximum ||
(bLogarithmic && dValue <= 0.0)) {
return false;
}
dInternalRange[0] = dValue;
dInternalRange[1] = dMaximum;
return true;
}
bool fillLookupTableWithFirstColor(vtkLookupTable* pLookupTable)
{
if(pLookupTable == nullptr ||
pLookupTable->GetNumberOfTableValues() <= 0) {
return false;
}
double dFirstColor[4] = { 0.0, 0.0, 0.0, 1.0 };
pLookupTable->GetTableValue(0, dFirstColor);
for(int nComponent = 0; nComponent < 4; ++nComponent) {
if(!vtkMath::IsFinite(dFirstColor[nComponent])) {
return false;
}
}
const int nTableValueCount = static_cast<int>(
pLookupTable->GetNumberOfTableValues());
for(int nIndex = 0; nIndex < nTableValueCount; ++nIndex) {
pLookupTable->SetTableValue(nIndex, dFirstColor);
}
return true;
}
}
nmPebiResultDisplayState::nmPebiResultDisplayState()
: m_pLookupTable(nullptr),
m_bSingleValueMode(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;
}
bool nmPebiResultDisplayStateBuilder::build(
const QSharedPointer<const nmPebiResultSnapshot>& pSnapshot,
const QString& sPropertyId,
const nmPebiResultDisplaySettings& oRequestedSettings,
nmPebiResultDisplayState& oState,
QString* pError)
{
if(pError != nullptr) {
pError->clear();
}
nmPebiResultDisplaySettings oSettings =
oRequestedSettings.normalized();
if(pSnapshot.isNull() || !pSnapshot->hasProperty(sPropertyId) ||
!oSettings.isStructurallyValid()) {
if(pError != nullptr) {
*pError = displayStateText("The color settings are invalid.");
}
return false;
}
if(!nmVTKColorMapCatalog::contains(oSettings.m_sColorMapId)) {
if(pError != nullptr) {
*pError = displayStateText(
"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 = displayStateText(
"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 = displayStateText(
"The manual range must contain two finite increasing values.");
}
return false;
}
dVisibleRange[0] = oSettings.m_dManualMinimum;
dVisibleRange[1] = oSettings.m_dManualMaximum;
}
const bool bSingleValueMode =
!oSettings.m_bHasManualRange &&
dBusinessRange[0] == dBusinessRange[1];
const bool bLogarithmic =
oSettings.m_eScaleMode == NM_PebiColorScale_Logarithmic;
if(bLogarithmic &&
(dBusinessRange[0] <= 0.0 || dVisibleRange[0] <= 0.0)) {
if(pError != nullptr) {
*pError = displayStateText(
"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,
bSingleValueMode, dInternalRange)) {
if(pError != nullptr) {
*pError = displayStateText(
"Unable to construct the color mapping.");
}
return false;
}
pLookupTable->SetTableRange(dInternalRange);
if(bLogarithmic) {
pLookupTable->SetScaleToLog10();
} else {
pLookupTable->SetScaleToLinear();
}
// 单值自动范围固定到色带第0色,特殊越界色随后单独构造。
if(bSingleValueMode &&
!fillLookupTableWithFirstColor(pLookupTable)) {
if(pError != nullptr) {
*pError = displayStateText(
"Unable to construct the color mapping.");
}
return false;
}
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);
pLookupTable->BuildSpecialColors();
pLookupTable->IndexedLookupOff();
pLookupTable->ResetAnnotations();
oState.m_oSettings = oSettings;
oState.m_dBusinessRange[0] = dBusinessRange[0];
oState.m_dBusinessRange[1] = dBusinessRange[1];
oState.m_dVisibleRange[0] = dVisibleRange[0];
oState.m_dVisibleRange[1] = dVisibleRange[1];
oState.m_dInternalRange[0] = dInternalRange[0];
oState.m_dInternalRange[1] = dInternalRange[1];
oState.m_pLookupTable = pLookupTable;
oState.m_sScalarBarTitle =
nmPebiResultPropertyDisplayText::getScalarBarTitle(
sPropertyId, bLogarithmic);
oState.m_bSingleValueMode = bSingleValueMode;
return true;
}