#include "nmPebiResultDisplayStateBuilder.h" #include "nmPebiResultPropertyDisplayText.h" #include "nmPebiResultSnapshot.h" #include "nmVTKColorMapCatalog.h" #include #include #include #include #include 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( 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& 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 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; }