#2460 Tensor Vectors: Use result as colormapping on the vectors

This commit is contained in:
Rebecca Cox 2018-02-20 13:38:45 +01:00
parent 9b1b94a4ae
commit 4ca78ca833
8 changed files with 267 additions and 57 deletions

View File

@ -34,6 +34,7 @@
#include "RigFemPartResults.h"
#include "RigFemScalarResultFrames.h"
#include "RigFormationNames.h"
#include "RigHexIntersectionTools.h"
#include "RigStatisticsDataCache.h"
#include "RimMainPlotCollection.h"
@ -53,7 +54,6 @@
#include <stdlib.h>
#include <cmath>
#include "RigHexIntersectionTools.h"
//--------------------------------------------------------------------------------------------------
@ -2293,6 +2293,35 @@ const std::vector<size_t>& RigFemPartResultsCollection::scalarValuesHistogram(co
return this->statistics(resVarAddr)->cellScalarValuesHistogram(frameIndex);
}
std::vector<RigFemResultAddress> RigFemPartResultsCollection::tensorPrincipalComponentAdresses(const RigFemResultAddress& resVarAddr)
{
std::vector<RigFemResultAddress> addresses;
for (size_t i = 0; i < 3; ++i)
{
addresses.push_back(RigFemResultAddress(resVarAddr.resultPosType, resVarAddr.fieldName, ""));
}
if (resVarAddr.fieldName == "SE" || resVarAddr.fieldName == "ST")
{
addresses[0].componentName = "S1";
addresses[1].componentName = "S2";
addresses[2].componentName = "S3";
}
else if (resVarAddr.fieldName == "E")
{
addresses[0].componentName = "E1";
addresses[1].componentName = "E2";
addresses[2].componentName = "E3";
}
else
{
addresses.clear();
}
return addresses;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -2301,37 +2330,9 @@ void RigFemPartResultsCollection::minMaxScalarValuesOverAllTensorComponents(cons
double currentMin = HUGE_VAL;
double currentMax = -HUGE_VAL;
double min;
double max;
double min, max;
std::vector<RigFemResultAddress> addresses;
for (size_t i = 0; i < 6; ++i)
{
addresses.push_back(RigFemResultAddress(resVarAddr.resultPosType, resVarAddr.fieldName, ""));
}
if (resVarAddr.fieldName == "SE" || resVarAddr.fieldName == "ST")
{
addresses[0].componentName = "S11";
addresses[1].componentName = "S22";
addresses[2].componentName = "S33";
addresses[3].componentName = "S12";
addresses[4].componentName = "S13";
addresses[5].componentName = "S23";
}
else if (resVarAddr.fieldName == "E")
{
addresses[0].componentName = "E11";
addresses[1].componentName = "E22";
addresses[2].componentName = "E33";
addresses[3].componentName = "E12";
addresses[4].componentName = "E13";
addresses[5].componentName = "E23";
}
else return;
for (auto address : addresses)
for (auto address : tensorPrincipalComponentAdresses(resVarAddr))
{
this->statistics(address)->minMaxCellScalarValues(frameIndex, min, max);
if (min < currentMin)
@ -2348,6 +2349,87 @@ void RigFemPartResultsCollection::minMaxScalarValuesOverAllTensorComponents(cons
*localMax = currentMax;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigFemPartResultsCollection::minMaxScalarValuesOverAllTensorComponents(const RigFemResultAddress& resVarAddr, double* globalMin, double* globalMax)
{
double currentMin = HUGE_VAL;
double currentMax = -HUGE_VAL;
double min, max;
for (auto address : tensorPrincipalComponentAdresses(resVarAddr))
{
this->statistics(address)->minMaxCellScalarValues(min, max);
if (min < currentMin)
{
currentMin = min;
}
if (max > currentMax)
{
currentMax = max;
}
}
*globalMin = currentMin;
*globalMax = currentMax;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigFemPartResultsCollection::posNegClosestToZeroOverAllTensorComponents(const RigFemResultAddress& resVarAddr, int frameIndex, double* localPosClosestToZero, double* localNegClosestToZero)
{
double currentPosClosestToZero = HUGE_VAL;
double currentNegClosestToZero = -HUGE_VAL;
double pos, neg;
for (auto address : tensorPrincipalComponentAdresses(resVarAddr))
{
this->statistics(address)->posNegClosestToZero(frameIndex, pos, neg);
if (pos < currentPosClosestToZero)
{
currentPosClosestToZero = pos;
}
if (neg > currentNegClosestToZero)
{
currentNegClosestToZero = neg;
}
}
*localPosClosestToZero = currentPosClosestToZero;
*localNegClosestToZero = currentNegClosestToZero;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigFemPartResultsCollection::posNegClosestToZeroOverAllTensorComponents(const RigFemResultAddress& resVarAddr, double* globalPosClosestToZero, double* globalNegClosestToZero)
{
double currentPosClosestToZero = HUGE_VAL;
double currentNegClosestToZero = -HUGE_VAL;
double pos, neg;
for (auto address : tensorPrincipalComponentAdresses(resVarAddr))
{
this->statistics(address)->posNegClosestToZero(pos, neg);
if (pos < currentPosClosestToZero)
{
currentPosClosestToZero = pos;
}
if (neg > currentNegClosestToZero)
{
currentNegClosestToZero = neg;
}
}
*globalPosClosestToZero = currentPosClosestToZero;
*globalNegClosestToZero = currentNegClosestToZero;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -88,7 +88,9 @@ public:
const std::vector<size_t>& scalarValuesHistogram(const RigFemResultAddress& resVarAddr, int frameIndex);
void minMaxScalarValuesOverAllTensorComponents(const RigFemResultAddress& resVarAddr, int frameIndex, double* localMin, double* localMax);
void minMaxScalarValuesOverAllTensorComponents(const RigFemResultAddress& resVarAddr, double* globalMin, double* globalMax);
void posNegClosestToZeroOverAllTensorComponents(const RigFemResultAddress& resVarAddr, int frameIndex, double* localPosClosestToZero, double* localNegClosestToZero);
void posNegClosestToZeroOverAllTensorComponents(const RigFemResultAddress& resVarAddr, double* globalPosClosestToZero, double* globalNegClosestToZero);
private:
RigFemScalarResultFrames* findOrLoadScalarResult(int partIndex,
const RigFemResultAddress& resVarAddr);
@ -119,6 +121,9 @@ private:
RigFemScalarResultFrames* calculatePrincipalStrainValues(int partIndex, const RigFemResultAddress &resVarAddr);
RigFemScalarResultFrames* calculateCompactionValues(int partIndex, const RigFemResultAddress &resVarAddr);
static std::vector<RigFemResultAddress> tensorPrincipalComponentAdresses(const RigFemResultAddress& resVarAddr);
private:
cvf::Collection<RigFemPartResults> m_femPartResults;
cvf::ref<RifGeoMechReaderInterface> m_readerInterface;
cvf::ref<RifElementPropertyReader> m_elementPropertyReader;

View File

@ -20,6 +20,7 @@
#include "RimGeoMechCase.h"
#include "RimGeoMechView.h"
#include "RimLegendConfig.h"
#include "RimTensorResults.h"
#include "RigFemPartCollection.h"
@ -123,8 +124,7 @@ void RivTensorResultPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicLi
const std::vector<size_t>& quadVerticesToNodeIdxMapping = surfaceGenerator->quadVerticesToNodeIdxMapping();
const std::vector<size_t>& quadVerticesToElmIdx = surfaceGenerator->quadVerticesToGlobalElmIdx();
for (int quadVertex = 0; quadVertex < static_cast<int>(quadVerticesToNodeIdxMapping.size());
quadVertex = quadVertex + 4)
for (int quadVertex = 0; quadVertex < static_cast<int>(quadVerticesToNodeIdxMapping.size()); quadVertex += 4)
{
cvf::Vec3f center = nodes.coordinates.at(quadVerticesToNodeIdxMapping[quadVertex]) +
nodes.coordinates.at(quadVerticesToNodeIdxMapping[quadVertex + 2]);
@ -331,36 +331,34 @@ cvf::ref<cvf::Part> RivTensorResultPartMgr::createPart(const std::vector<TensorV
{
lineTexCoords = new cvf::Vec2fArray;
}
cvf::ref<cvf::ScalarMapperDiscreteLinear> scalarMapper = new cvf::ScalarMapperDiscreteLinear;
cvf::ScalarMapper* activeScalerMapper = nullptr;
auto vectorColors = m_rimReservoirView->tensorResults()->vectorColors();
if (vectorColors == RimTensorResults::MAGENTA_BROWN_BLACK || vectorColors == RimTensorResults::WHITE_GRAY_BLACK)
{
createOneColorPerPrincipalScalarMapper(m_rimReservoirView->tensorResults()->vectorColors(), scalarMapper.p());
createOneColorPerPrincipalTextureCoords(lineTexCoords.p(), tensorVisualizations, scalarMapper.p());
cvf::ref<cvf::ScalarMapperDiscreteLinear> discreteScalarMapper = new cvf::ScalarMapperDiscreteLinear;
activeScalerMapper = discreteScalarMapper.p();
createOneColorPerPrincipalScalarMapper(vectorColors, discreteScalarMapper.p());
createOneColorPerPrincipalTextureCoords(lineTexCoords.p(), tensorVisualizations, discreteScalarMapper.p());
}
else
{
// THIS WILL BE REPLACED BY REAL RESULT COLOR MAPPER
cvf::Color3ubArray arrowColors;
arrowColors.resize(3);
arrowColors[0] = cvf::Color3::BLACK;
arrowColors[1] = cvf::Color3::BLACK;
arrowColors[2] = cvf::Color3::BLACK;
scalarMapper->setColors(arrowColors);
scalarMapper->setRange(0.5, 3.5);
scalarMapper->setLevelCount(3, true);
createOneColorPerPrincipalTextureCoords(lineTexCoords.p(), tensorVisualizations, scalarMapper.p());
activeScalerMapper = m_rimReservoirView->tensorResults()->legendConfig()->scalarMapper();
createResultColorTextureCoords(lineTexCoords.p(), tensorVisualizations, activeScalerMapper);
}
caf::ScalarMapperEffectGenerator surfEffGen(scalarMapper.p(), caf::PO_1);
caf::ScalarMapperEffectGenerator surfEffGen(activeScalerMapper, caf::PO_1);
if (m_rimReservoirView && m_rimReservoirView->isLightingDisabled())
{
surfEffGen.disableLighting(true);
}
caf::ScalarMapperMeshEffectGenerator meshEffGen(scalarMapper.p());
caf::ScalarMapperMeshEffectGenerator meshEffGen(activeScalerMapper);
cvf::ref<cvf::Effect> scalarMapperMeshEffect = meshEffGen.generateUnCachedEffect();
drawable->setTextureCoordArray(lineTexCoords.p());
@ -423,6 +421,31 @@ void RivTensorResultPartMgr::createOneColorPerPrincipalTextureCoords(cvf::Vec2fA
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivTensorResultPartMgr::createResultColorTextureCoords(cvf::Vec2fArray* textureCoords,
const std::vector<TensorVisualization>& tensorVisualizations,
const cvf::ScalarMapper* mapper)
{
CVF_ASSERT(textureCoords);
CVF_ASSERT(mapper);
size_t vertexCount = tensorVisualizations.size() * 5;
if (textureCoords->size() != vertexCount) textureCoords->reserve(vertexCount);
for (auto tensor : tensorVisualizations)
{
int sign = tensor.isPressure ? 1 : -1;
for (size_t vxIdx = 0; vxIdx < 5; ++vxIdx)
{
cvf::Vec2f texCoord = mapper->mapToTextureCoord(sign * tensor.result.length());
textureCoords->add(texCoord);
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -472,11 +495,12 @@ bool RivTensorResultPartMgr::isValid(cvf::Vec3f resultVector)
//--------------------------------------------------------------------------------------------------
bool RivTensorResultPartMgr::isPressure(float principalValue)
{
if (principalValue < 0)
if (principalValue >= 0)
{
return false;
return true;
}
return true;
return false;
}
//--------------------------------------------------------------------------------------------------

View File

@ -87,9 +87,13 @@ private:
static void createOneColorPerPrincipalScalarMapper(const RimTensorResults::TensorColors& colorSet, cvf::ScalarMapperDiscreteLinear* scalarMapper);
static void createOneColorPerPrincipalTextureCoords(cvf::Vec2fArray* textureCoords,
const std::vector<TensorVisualization>& tensorVisualization,
const std::vector<TensorVisualization>& tensorVisualizations,
const cvf::ScalarMapper* mapper);
static void createResultColorTextureCoords(cvf::Vec2fArray* textureCoords,
const std::vector<TensorVisualization>& tensorVisualizations,
const cvf::ScalarMapper* mapper);
static bool isTensorAddress(RigFemResultAddress address);
static bool isValid(cvf::Vec3f resultVector);
static bool isPressure(float principalValue);

View File

@ -379,9 +379,51 @@ void RimGeoMechView::updateLegends()
{
m_viewer->addColorLegendToBottomLeftCorner(cellResult()->legendConfig->legend());
}
updateTensorLegendTextAndRanges(m_tensorResults->legendConfig(), m_currentTimeStep());
if (tensorResults()->vectorColors() == RimTensorResults::RESULT_COLORS)
{
m_viewer->addColorLegendToBottomLeftCorner(m_tensorResults->legendConfig->legend());
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechView::updateTensorLegendTextAndRanges(RimLegendConfig* legendConfig, int timeStepIndex)
{
if (!m_geomechCase || !m_geomechCase->geoMechData()) return;
double localMin, localMax;
double localPosClosestToZero, localNegClosestToZero;
double globalMin, globalMax;
double globalPosClosestToZero, globalNegClosestToZero;
RigGeoMechCaseData* gmCase = m_geomechCase->geoMechData();
CVF_ASSERT(gmCase);
RigFemResultPosEnum resPos = tensorResults()->resultPositionType();
QString resFieldName = tensorResults()->resultFieldName();
RigFemResultAddress resVarAddress(resPos, resFieldName.toStdString(), "");
gmCase->femPartResults()->minMaxScalarValuesOverAllTensorComponents(resVarAddress, timeStepIndex, &localMin, &localMax);
gmCase->femPartResults()->posNegClosestToZeroOverAllTensorComponents(resVarAddress, timeStepIndex, &localPosClosestToZero, &localNegClosestToZero);
gmCase->femPartResults()->minMaxScalarValuesOverAllTensorComponents(resVarAddress, &globalMin, &globalMax);
gmCase->femPartResults()->posNegClosestToZeroOverAllTensorComponents(resVarAddress, &globalPosClosestToZero, &globalNegClosestToZero);
legendConfig->setClosestToZeroValues(globalPosClosestToZero, globalNegClosestToZero, localPosClosestToZero, localNegClosestToZero);
legendConfig->setAutomaticRanges(globalMin, globalMax, localMin, localMax);
QString legendTitle = "Tensors:\n" + caf::AppEnum<RigFemResultPosEnum>(tensorResults()->resultPositionType()).uiText() + "\n"
+ tensorResults()->resultFieldName();
legendConfig->setTitle(legendTitle);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -424,9 +466,8 @@ void RimGeoMechView::updateLegendTextAndRanges(RimLegendConfig* legendConfig, in
legendConfig->setNamedCategoriesInverse(fnVector);
}
QString legendTitle =
caf::AppEnum<RigFemResultPosEnum>(cellResult->resultPositionType()).uiText() + "\n"
+ cellResult->resultFieldUiName();
QString legendTitle = "Cell Results:\n" + caf::AppEnum<RigFemResultPosEnum>(cellResult->resultPositionType()).uiText() +
"\n" + cellResult->resultFieldUiName();
if (!cellResult->resultComponentUiName().isEmpty())
{
@ -463,6 +504,14 @@ const RimTensorResults* RimGeoMechView::tensorResults() const
return m_tensorResults;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimTensorResults* RimGeoMechView::tensorResults()
{
return m_tensorResults;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -91,6 +91,7 @@ public:
const cvf::ref<RivGeoMechVizLogic> vizLogic() const;
const RimTensorResults* tensorResults() const;
RimTensorResults* tensorResults();
protected:
virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override;
@ -111,6 +112,8 @@ private:
void updateLegends();
void updateTensorLegendTextAndRanges(RimLegendConfig* legendConfig, int timeStepIndex);
virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override;
virtual void initAfterRead() override;

View File

@ -21,6 +21,7 @@
#include "RigFemResultAddress.h"
#include "RimGeoMechResultDefinition.h"
#include "RimGeoMechView.h"
#include "RimLegendConfig.h"
#include "cafAppEnum.h"
#include "cafPdmUiListEditor.h"
@ -59,6 +60,10 @@ RimTensorResults::RimTensorResults()
{
CAF_PDM_InitObject("Tensor Results", ":/CellResult.png", "", "");
CAF_PDM_InitFieldNoDefault(&legendConfig, "LegendDefinition", "Legend Definition", "", "", "");
this->legendConfig = new RimLegendConfig();
legendConfig.uiCapability()->setUiHidden(true);
CAF_PDM_InitFieldNoDefault(&m_resultPositionType, "ResultPositionType", "Result Position", "", "", "");
m_resultPositionType.uiCapability()->setUiHidden(true);
@ -97,7 +102,7 @@ RimTensorResults::RimTensorResults()
//--------------------------------------------------------------------------------------------------
RimTensorResults::~RimTensorResults()
{
delete legendConfig;
}
//--------------------------------------------------------------------------------------------------
@ -108,6 +113,16 @@ RigFemResultAddress RimTensorResults::selectedTensorResult() const
return RigFemResultAddress(m_resultPositionType(), m_resultFieldName().toStdString(), "");
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimTensorResults::setShowTensors(bool enableTensors)
{
m_showTensors = enableTensors;
updateConnectedEditors();
updateUiIconFromState(enableTensors);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -172,6 +187,22 @@ RimTensorResults::ScaleMethod RimTensorResults::scaleMethod() const
return m_scaleMethod();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigFemResultPosEnum RimTensorResults::resultPositionType() const
{
return m_resultPositionType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimTensorResults::resultFieldName() const
{
return m_resultFieldName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -208,6 +239,10 @@ void RimTensorResults::fieldChangedByUi(const caf::PdmFieldHandle* changedField,
m_resultPositionType = m_resultPositionTypeUiField;
m_resultFieldName = m_resultFieldNameUiField;
}
if (changedField == &m_showTensors)
{
setShowTensors(m_showTensors);
}
RimGeoMechView* view;
firstAncestorOrThisOfType(view);

View File

@ -18,6 +18,7 @@
#pragma once
#include "cafPdmChildField.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
@ -28,6 +29,7 @@
#include <vector>
class RigFemResultAddress;
class RimLegendConfig;
//==================================================================================================
///
@ -56,6 +58,7 @@ public:
virtual ~RimTensorResults();
RigFemResultAddress selectedTensorResult() const;
void setShowTensors(bool enableTensors);
bool showTensors() const;
bool showPrincipal1() const;
bool showPrincipal2() const;
@ -65,6 +68,11 @@ public:
TensorColors vectorColors() const;
ScaleMethod scaleMethod() const;
RigFemResultPosEnum resultPositionType() const;
QString resultFieldName() const;
caf::PdmChildField<RimLegendConfig*> legendConfig;
private:
std::vector<std::string> getResultMetaDataForUIFieldSetting();
virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override;