#3881 Smooth outer contour line and clip geometry

This commit is contained in:
Gaute Lindkvist
2019-01-02 15:53:13 +01:00
parent ec0419a945
commit 71cacc550f
5 changed files with 322 additions and 149 deletions

View File

@@ -37,18 +37,11 @@ void RivContourMapProjectionPartMgr::appendProjectionToModel(cvf::ModelBasicList
{ {
cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
cvf::ref<cvf::DrawableGeo> drawable = createProjectionMapDrawable(displayCoordTransform); std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels = createContourPolygons(displayCoordTransform);
if (drawable.notNull() && drawable->boundingBox().isValid()) cvf::ref<cvf::Part> mapPart = createProjectionMapPart(displayCoordTransform);
if (mapPart.notNull())
{ {
cvf::ref<cvf::Part> part = new cvf::Part; model->addPart(mapPart.p());
part->setDrawable(drawable.p());
cvf::ref<cvf::Vec2fArray> textureCoords = createTextureCoords();
RivScalarMapperUtils::applyTextureResultsToPart(part.p(), textureCoords.p(), mapper, 1.0f, caf::FC_NONE, true, m_parentContourMap->backgroundColor());
part->setSourceInfo(new RivObjectSourceInfo(m_contourMapProjection.p()));
model->addPart(part.p());
} }
if (m_contourMapProjection->showContourLines()) if (m_contourMapProjection->showContourLines())
@@ -56,7 +49,6 @@ void RivContourMapProjectionPartMgr::appendProjectionToModel(cvf::ModelBasicList
std::vector<double> tickValues; std::vector<double> tickValues;
mapper->majorTickValues(&tickValues); mapper->majorTickValues(&tickValues);
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels = createContourPolygons(displayCoordTransform);
for (size_t i = 0; i < contourDrawablesForAllLevels.size(); ++i) for (size_t i = 0; i < contourDrawablesForAllLevels.size(); ++i)
{ {
std::vector<cvf::ref<cvf::Drawable>> contourDrawables = contourDrawablesForAllLevels[i]; std::vector<cvf::ref<cvf::Drawable>> contourDrawables = contourDrawablesForAllLevels[i];
@@ -112,54 +104,24 @@ void RivContourMapProjectionPartMgr::appendPickPointVisToModel(cvf::ModelBasicLi
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
cvf::ref<cvf::Vec2fArray> RivContourMapProjectionPartMgr::createTextureCoords() const cvf::ref<cvf::Vec2fArray> RivContourMapProjectionPartMgr::createTextureCoords(const std::vector<double>& values) const
{ {
cvf::Vec2ui patchSize = m_contourMapProjection->numberOfVerticesIJ(); cvf::Vec2ui patchSize = m_contourMapProjection->numberOfVerticesIJ();
cvf::ref<cvf::Vec2fArray> textureCoords = new cvf::Vec2fArray(m_contourMapProjection->numberOfVertices()); cvf::ref<cvf::Vec2fArray> textureCoords = new cvf::Vec2fArray(values.size());
#pragma omp parallel for #pragma omp parallel for
for (int j = 0; j < static_cast<int>(patchSize.y()); ++j) for (int i = 0; i < (int) values.size(); ++i)
{ {
for (int i = 0; i < static_cast<int>(patchSize.x()); ++i) if (values[i] != std::numeric_limits<double>::infinity())
{ {
if (m_contourMapProjection->hasResultAtVertex(i, j)) cvf::Vec2f textureCoord = m_contourMapProjection->legendConfig()->scalarMapper()->mapToTextureCoord(values[i]);
{
double value = m_contourMapProjection->valueAtVertex(i, j);
cvf::Vec2f textureCoord = m_contourMapProjection->legendConfig()->scalarMapper()->mapToTextureCoord(value);
textureCoord.y() = 0.0; textureCoord.y() = 0.0;
(*textureCoords)[i + j * patchSize.x()] = textureCoord; (*textureCoords)[i] = textureCoord;
} }
else else
{ {
RiaWeightedMeanCalculator<double> calc; (*textureCoords)[i] = cvf::Vec2f(0.0, 1.0);
for (int jj = j - 1; jj <= j + 1; ++jj)
{
for (int ii = i - 1; ii <= i + 1; ++ii)
{
if (jj >= 0 && ii >= 0 && jj < static_cast<int>(patchSize.y()) && ii < static_cast<int>(patchSize.x()))
{
if (!(ii == i && jj == j) && m_contourMapProjection->hasResultAtVertex(ii, jj))
{
double value = m_contourMapProjection->valueAtVertex(ii, jj);
calc.addValueAndWeight(value, 1. / std::sqrt((i - ii)*(i - ii) + (j - jj)*(j - jj)));
}
}
}
}
if (calc.validAggregatedWeight())
{
const double maxTheoreticalWeightSum = 4.0 + 4.0 / std::sqrt(2.0);
double value = calc.weightedMean();
cvf::Vec2f textureCoord = m_contourMapProjection->legendConfig()->scalarMapper()->mapToTextureCoord(value);
textureCoord.y() = 1.0 - calc.aggregatedWeight() / maxTheoreticalWeightSum;
(*textureCoords)[i + j * patchSize.x()] = textureCoord;
}
else
{
(*textureCoords)[i + j * patchSize.x()] = cvf::Vec2f(0.0, 1.0);
}
}
} }
} }
return textureCoords; return textureCoords;
@@ -170,14 +132,14 @@ cvf::ref<cvf::Vec2fArray> RivContourMapProjectionPartMgr::createTextureCoords()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableText> RivContourMapProjectionPartMgr::createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor) cvf::ref<cvf::DrawableText> RivContourMapProjectionPartMgr::createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor)
{ {
auto font = RiaFontCache::getFont(RiaFontCache::FONT_SIZE_8); auto font = RiaFontCache::getFont(RiaFontCache::FONT_SIZE_10);
cvf::ref<cvf::DrawableText> labelDrawable = new cvf::DrawableText(); cvf::ref<cvf::DrawableText> labelDrawable = new cvf::DrawableText();
labelDrawable->setFont(font.p()); labelDrawable->setFont(font.p());
labelDrawable->setCheckPosVisible(true); labelDrawable->setCheckPosVisible(true);
labelDrawable->setUseDepthBuffer(true); labelDrawable->setUseDepthBuffer(true);
labelDrawable->setDrawBorder(true); labelDrawable->setDrawBorder(false);
labelDrawable->setDrawBackground(true); labelDrawable->setDrawBackground(false);
labelDrawable->setBackgroundColor(backgroundColor); labelDrawable->setBackgroundColor(backgroundColor);
labelDrawable->setVerticalAlignment(cvf::TextDrawer::BASELINE); labelDrawable->setVerticalAlignment(cvf::TextDrawer::BASELINE);
labelDrawable->setTextColor(textColor); labelDrawable->setTextColor(textColor);
@@ -188,31 +150,43 @@ cvf::ref<cvf::DrawableText> RivContourMapProjectionPartMgr::createTextLabel(cons
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> RivContourMapProjectionPartMgr::createProjectionMapDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const cvf::ref<cvf::Part> RivContourMapProjectionPartMgr::createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const
{ {
std::vector<cvf::Vec3d> vertices = m_contourMapProjection->generateVertices(); std::vector<cvf::Vec4d> vertices = m_contourMapProjection->generateTriangles();
if (vertices.empty()) return nullptr; if (vertices.size() < 3u)
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray(vertices.size());
for (size_t i = 0; i < vertices.size(); ++i)
{ {
cvf::Vec3f displayVertexPos (displayCoordTransform->transformToDisplayCoord(vertices[i])); return cvf::ref<cvf::Part>();
(*vertexArray)[i] = displayVertexPos; }
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray(vertices.size());
cvf::ref<cvf::UIntArray> faceList = new cvf::UIntArray(vertices.size());
std::vector<double> values(vertices.size());
for (uint i = 0; i < vertices.size(); ++i)
{
cvf::Vec3d globalVertex = cvf::Vec3d(vertices[i].x(), vertices[i].y(), vertices[i].z()) + m_contourMapProjection->origin3d();
cvf::Vec3f displayVertexPos (displayCoordTransform->transformToDisplayCoord(globalVertex));
(*vertexArray)[i] = displayVertexPos;
(*faceList)[i] = i;
values[i] = vertices[i].w();
} }
cvf::Vec2ui patchSize = m_contourMapProjection->numberOfVerticesIJ();
// Surface
cvf::ref<cvf::UIntArray> faceList = new cvf::UIntArray;
cvf::GeometryUtils::tesselatePatchAsTriangles(patchSize.x(), patchSize.y(), 0u, true, faceList.p());
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_TRIANGLES, faceList.p()); cvf::ref<cvf::PrimitiveSetIndexedUInt> indexUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_TRIANGLES, faceList.p());
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo; cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->addPrimitiveSet(indexUInt.p()); geo->addPrimitiveSet(indexUInt.p());
geo->setVertexArray(vertexArray.p()); geo->setVertexArray(vertexArray.p());
return geo;
cvf::ref<cvf::Part> part = new cvf::Part;
part->setDrawable(geo.p());
cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper();
cvf::ref<cvf::Vec2fArray> textureCoords = createTextureCoords(values);
RivScalarMapperUtils::applyTextureResultsToPart(
part.p(), textureCoords.p(), mapper, 1.0f, caf::FC_NONE, true, m_parentContourMap->backgroundColor());
part->setSourceInfo(new RivObjectSourceInfo(m_contourMapProjection.p()));
return part;
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -241,13 +215,14 @@ std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr
if (contourPolygons[i][j].vertices.empty()) continue; if (contourPolygons[i][j].vertices.empty()) continue;
size_t nVertices = contourPolygons[i][j].vertices.size(); size_t nVertices = contourPolygons[i][j].vertices.size();
size_t nLabels = m_contourMapProjection->showContourLabels() ? std::max((size_t)1, nVertices / 150u) : 0u; size_t nLabels = m_contourMapProjection->showContourLabels() ? std::max((size_t)1, nVertices / 100u) : 0u;
for (size_t l = 0; l < nLabels; ++l) for (size_t l = 0; l < nLabels; ++l)
{ {
cvf::ref<cvf::DrawableText> label = createTextLabel(textColor, backgroundColor); cvf::ref<cvf::DrawableText> label = createTextLabel(textColor, backgroundColor);
cvf::Vec3f labelVertex(displayCoordTransform->transformToDisplayCoord(contourPolygons[i][j].vertices[(nVertices * l) / nLabels])); cvf::Vec3d globalVertex = contourPolygons[i][j].vertices[(nVertices * l) / nLabels] + m_contourMapProjection->origin3d();
labelVertex.z() += 3.0f; cvf::Vec3f displayVertex(displayCoordTransform->transformToDisplayCoord(globalVertex));
label->addText(contourPolygons[i][j].label, labelVertex); displayVertex.z() += 3.0f;
label->addText(cvf::String(contourPolygons[i][j].value), displayVertex);
bool overlaps = false; bool overlaps = false;
cvf::BoundingBox bbox = label->boundingBox(); cvf::BoundingBox bbox = label->boundingBox();
for (cvf::ref<cvf::Drawable> existingLabel : labelDrawables) for (cvf::ref<cvf::Drawable> existingLabel : labelDrawables)
@@ -264,12 +239,11 @@ std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr
} }
} }
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray(nVertices); cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray(nVertices);
for (size_t v = 0; v < nVertices; v += 2) for (size_t v = 0; v < nVertices; ++v)
{ {
cvf::Vec3d displayVertex1 = displayCoordTransform->transformToDisplayCoord(contourPolygons[i][j].vertices[v]); cvf::Vec3d globalVertex = contourPolygons[i][j].vertices[v] + m_contourMapProjection->origin3d();
cvf::Vec3d displayVertex2 = displayCoordTransform->transformToDisplayCoord(contourPolygons[i][j].vertices[v + 1]); cvf::Vec3d displayVertex1 = displayCoordTransform->transformToDisplayCoord(globalVertex);
(*vertexArray)[v] = cvf::Vec3f(displayVertex1); (*vertexArray)[v] = cvf::Vec3f(displayVertex1);
(*vertexArray)[v + 1] = cvf::Vec3f(displayVertex2);
} }
std::vector<cvf::uint> indices; std::vector<cvf::uint> indices;
@@ -279,7 +253,7 @@ std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr
indices.push_back(k); indices.push_back(k);
} }
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_LINES); cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_LINE_LOOP);
cvf::ref<cvf::UIntArray> indexArray = new cvf::UIntArray(indices); cvf::ref<cvf::UIntArray> indexArray = new cvf::UIntArray(indices);
indexedUInt->setIndices(indexArray.p()); indexedUInt->setIndices(indexArray.p());
@@ -315,7 +289,8 @@ cvf::ref<cvf::DrawableGeo>
for (size_t i = 0; i < pickPointPolygon.size(); ++i) for (size_t i = 0; i < pickPointPolygon.size(); ++i)
{ {
cvf::Vec3f displayPoint(displayCoordTransform->transformToDisplayCoord(pickPointPolygon[i])); cvf::Vec3d globalPoint = pickPointPolygon[i] + m_contourMapProjection->origin3d();
cvf::Vec3f displayPoint(displayCoordTransform->transformToDisplayCoord(globalPoint));
(*vertexArray)[i] = displayPoint; (*vertexArray)[i] = displayPoint;
} }

View File

@@ -40,11 +40,11 @@ public:
void appendPickPointVisToModel(cvf::ModelBasicList* model, void appendPickPointVisToModel(cvf::ModelBasicList* model,
const caf::DisplayCoordTransform* displayCoordTransform) const; const caf::DisplayCoordTransform* displayCoordTransform) const;
cvf::ref<cvf::Vec2fArray> createTextureCoords() const; cvf::ref<cvf::Vec2fArray> createTextureCoords(const std::vector<double>& values) const;
private: private:
static cvf::ref<cvf::DrawableText> createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor); static cvf::ref<cvf::DrawableText> createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor);
cvf::ref<cvf::DrawableGeo> createProjectionMapDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const; cvf::ref<cvf::Part> createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const;
std::vector<std::vector<cvf::ref<cvf::Drawable>>> createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform) const; std::vector<std::vector<cvf::ref<cvf::Drawable>>> createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform) const;
cvf::ref<cvf::DrawableGeo> createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const; cvf::ref<cvf::DrawableGeo> createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const;
private: private:

View File

@@ -33,10 +33,12 @@
#include "cvfArray.h" #include "cvfArray.h"
#include "cvfCellRange.h" #include "cvfCellRange.h"
#include "cvfGeometryTools.h" #include "cvfGeometryTools.h"
#include "cvfGeometryUtils.h"
#include "cvfScalarMapper.h" #include "cvfScalarMapper.h"
#include "cvfStructGridGeometryGenerator.h" #include "cvfStructGridGeometryGenerator.h"
#include <algorithm> #include <algorithm>
#include <omp.h>
namespace caf namespace caf
{ {
@@ -105,7 +107,139 @@ RimContourMapProjection::~RimContourMapProjection()
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::vector<cvf::Vec3d> RimContourMapProjection::generateVertices() std::vector<cvf::Vec4d> RimContourMapProjection::generateTriangles() const
{
std::vector<cvf::Vec3d> vertices = generateVertices();
cvf::Vec2ui patchSize = numberOfVerticesIJ();
cvf::ref<cvf::UIntArray> faceList = new cvf::UIntArray;
cvf::GeometryUtils::tesselatePatchAsTriangles(patchSize.x(), patchSize.y(), 0u, true, faceList.p());
std::vector<double> contourLevels;
if (legendConfig()->mappingMode() != RimRegularLegendConfig::CATEGORY_INTEGER)
{
legendConfig()->scalarMapper()->majorTickValues(&contourLevels);
}
std::vector<std::vector<cvf::Vec4d>> threadTriangles(omp_get_max_threads());
#pragma omp parallel
{
int myThread = omp_get_thread_num();
threadTriangles[myThread].reserve(faceList->size() / omp_get_num_threads());
#pragma omp for
for (int64_t i = 0; i < (int64_t) faceList->size(); i += 3)
{
std::vector<cvf::Vec3d> triangle(3);
std::vector<cvf::Vec4d> triangleWithValues(3);
bool allValuesAboveLevelOneTreshold = true;
RiaWeightedMeanCalculator<double> meanValueCalc;
for (size_t n = 0; n < 3; ++n)
{
uint vn = (*faceList)[i + n];
double value = m_aggregatedVertexResults[vn];
triangle[n] = vertices[vn];
triangleWithValues[n] = cvf::Vec4d(vertices[vn], value);
if (value == std::numeric_limits<double>::infinity())
{
allValuesAboveLevelOneTreshold = false;
}
else
{
if (contourLevels.size() >= 2u && value < contourLevels[1])
{
allValuesAboveLevelOneTreshold = false;
}
meanValueCalc.addValueAndWeight(value, 1.0);
}
}
if (allValuesAboveLevelOneTreshold || m_contourPolygons.empty())
{
// Triangle is completely within the threshold. Include it.
threadTriangles[myThread].insert(threadTriangles[myThread].end(), triangleWithValues.begin(), triangleWithValues.end());
continue;
}
double triangleMeanValue = std::numeric_limits<double>::infinity();
if (meanValueCalc.validAggregatedWeight())
{
triangleMeanValue = meanValueCalc.weightedMean();
}
for (size_t j = 0; j < m_contourPolygons.front().size(); ++j)
{
const std::vector<cvf::Vec3d>& contourLine = m_contourPolygons.front()[j].vertices;
std::vector<std::vector<cvf::Vec3d>> clippedPolygons = RigCellGeometryTools::intersectPolygons(triangle, contourLine);
std::vector<cvf::Vec4d> clippedTriangles;
for (std::vector<cvf::Vec3d>& clippedPolygon : clippedPolygons)
{
std::vector<std::vector<cvf::Vec3d>> polygonTriangles;
if (clippedPolygon.size() == 3u)
{
polygonTriangles.push_back(clippedPolygon);
}
else
{
cvf::Vec3d baryCenter = cvf::Vec3d::ZERO;
for (size_t v = 0; v < clippedPolygon.size(); ++v)
{
cvf::Vec3d& clippedVertex = clippedPolygon[v];
baryCenter += clippedVertex;
}
baryCenter /= clippedPolygon.size();
for (size_t v = 0; v < clippedPolygon.size(); ++v)
{
std::vector<cvf::Vec3d> clippedTriangle;
if (v == clippedPolygon.size() - 1)
{
clippedTriangle = { clippedPolygon[v], clippedPolygon[0], baryCenter };
}
else
{
clippedTriangle = { clippedPolygon[v], clippedPolygon[v + 1], baryCenter };
}
polygonTriangles.push_back(clippedTriangle);
}
}
for (const std::vector<cvf::Vec3d>& polygonTriangle: polygonTriangles)
{
for (const cvf::Vec3d& localVertex : polygonTriangle)
{
double value = triangleMeanValue;
for (size_t n = 0; n < 3; ++n)
{
if ((triangle[n] - localVertex).length() < m_sampleSpacing * 0.01 && triangleWithValues[n].w() != std::numeric_limits<double>::infinity())
{
value = triangleWithValues[n].w();
break;
}
}
cvf::Vec4d globalVertex(localVertex, value);
clippedTriangles.push_back(globalVertex);
}
}
}
threadTriangles[myThread].insert(threadTriangles[myThread].end(), clippedTriangles.begin(), clippedTriangles.end());
}
}
}
std::vector<cvf::Vec4d> finalTriangles;
for (size_t i = 0; i < threadTriangles.size(); ++i)
{
finalTriangles.insert(finalTriangles.end(), threadTriangles[i].begin(), threadTriangles[i].end());
}
return finalTriangles;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<cvf::Vec3d> RimContourMapProjection::generateVertices() const
{ {
size_t nVertices = numberOfVertices(); size_t nVertices = numberOfVertices();
std::vector<cvf::Vec3d> vertices(nVertices, cvf::Vec3d::ZERO); std::vector<cvf::Vec3d> vertices(nVertices, cvf::Vec3d::ZERO);
@@ -114,13 +248,13 @@ std::vector<cvf::Vec3d> RimContourMapProjection::generateVertices()
for (int index = 0; index < static_cast<int>(nVertices); ++index) for (int index = 0; index < static_cast<int>(nVertices); ++index)
{ {
cvf::Vec2ui ij = ijFromVertexIndex(index); cvf::Vec2ui ij = ijFromVertexIndex(index);
cvf::Vec2d globalPos = globalCellCenterPosition(ij.x(), ij.y()); cvf::Vec2d mapPos = cellCenterPosition(ij.x(), ij.y());
// Shift away from sample point to vertex // Shift away from sample point to vertex
globalPos.x() -= m_sampleSpacing * 0.5; mapPos.x() -= m_sampleSpacing * 0.5;
globalPos.y() -= m_sampleSpacing * 0.5; mapPos.y() -= m_sampleSpacing * 0.5;
cvf::Vec3d globalVertexPos(globalPos, m_fullBoundingBox.min().z()); cvf::Vec3d vertexPos(mapPos, 0.0);
vertices[index] = globalVertexPos; vertices[index] = vertexPos;
} }
return vertices; return vertices;
} }
@@ -145,33 +279,29 @@ void RimContourMapProjection::generateContourPolygons()
int nContourLevels = static_cast<int>(contourLevels.size()); int nContourLevels = static_cast<int>(contourLevels.size());
if (nContourLevels > 2) if (nContourLevels > 2)
{ {
std::vector<double> fudgedContourLevels = contourLevels;
if (legendConfig()->mappingMode() == RimRegularLegendConfig::LINEAR_CONTINUOUS || legendConfig()->mappingMode() == RimRegularLegendConfig::LINEAR_DISCRETE)
{
// Slight fudge to avoid very jagged contour lines at the very edge
// Shift the contour levels inwards.
fudgedContourLevels[0] += (contourLevels[1] - contourLevels[0]) * 0.1;
fudgedContourLevels[nContourLevels - 1] -= (contourLevels[nContourLevels - 1] - contourLevels[nContourLevels - 2]) * 0.1;
}
std::vector<caf::ContourLines::ClosedPolygons> closedContourLines = std::vector<caf::ContourLines::ClosedPolygons> closedContourLines =
caf::ContourLines::create(m_aggregatedVertexResults, xVertexPositions(), yVertexPositions(), fudgedContourLevels); caf::ContourLines::create(m_aggregatedVertexResults, xVertexPositions(), yVertexPositions(), contourLevels);
contourPolygons.resize(closedContourLines.size()); contourPolygons.resize(closedContourLines.size());
for (size_t i = 0; i < closedContourLines.size(); ++i) for (size_t i = 0; i < closedContourLines.size(); ++i)
{ {
for (size_t j = 0; j < closedContourLines[i].size(); ++j) for (size_t j = 0; j < closedContourLines[i].size(); ++j)
{ {
ContourPolygon contourPolygon; ContourPolygon contourPolygon;
contourPolygon.label = cvf::String(contourLevels[i]); contourPolygon.value = contourLevels[i];
contourPolygon.vertices.reserve(closedContourLines[i][j].size()); contourPolygon.vertices.reserve(closedContourLines[i][j].size() / 2);
for (size_t k = 0; k < closedContourLines[i][j].size(); ++k)
for (size_t k = 0; k < closedContourLines[i][j].size(); k += 2)
{ {
cvf::Vec3d contourPoint3d = cvf::Vec3d(closedContourLines[i][j][k], m_fullBoundingBox.min().z()); cvf::Vec3d contourPoint3d = cvf::Vec3d(closedContourLines[i][j][k], 0.0);
contourPolygon.vertices.push_back(contourPoint3d); contourPolygon.vertices.push_back(contourPoint3d);
} }
contourPolygons[i].push_back(contourPolygon); contourPolygons[i].push_back(contourPolygon);
} }
} }
smoothPolygonLoops(&contourPolygons[0]);
} }
} }
} }
@@ -188,31 +318,25 @@ RimContourMapProjection::generatePickPointPolygon()
if (!m_pickPoint.isUndefined()) if (!m_pickPoint.isUndefined())
{ {
double zPos = m_fullBoundingBox.min().z();
{ {
cvf::Vec2d gridorigin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y());
cvf::Vec2d localPickPoint = m_pickPoint - gridorigin;
cvf::Vec2d cellDiagonal(m_sampleSpacing*0.5, m_sampleSpacing*0.5); cvf::Vec2d cellDiagonal(m_sampleSpacing*0.5, m_sampleSpacing*0.5);
cvf::Vec2ui pickedCell = ijFromLocalPos(localPickPoint); cvf::Vec2ui pickedCell = ijFromLocalPos(m_pickPoint);
cvf::Vec2d cellCenter = globalCellCenterPosition(pickedCell.x(), pickedCell.y()); cvf::Vec2d cellCenter = cellCenterPosition(pickedCell.x(), pickedCell.y());
cvf::Vec2d cellCorner = cellCenter - cellDiagonal; cvf::Vec2d cellCorner = cellCenter - cellDiagonal;
#ifndef NDEBUG #ifndef NDEBUG
points.push_back(cvf::Vec3d(cellCorner, zPos)); points.push_back(cvf::Vec3d(cellCorner, 0.0));
points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, 0.0), zPos)); points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, 0.0), 0.0));
points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, 0.0), zPos)); points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, 0.0), 0.0));
points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, m_sampleSpacing), zPos)); points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, m_sampleSpacing), 0.0));
points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, m_sampleSpacing), zPos)); points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, m_sampleSpacing), 0.0));
points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(0.0, m_sampleSpacing), zPos)); points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(0.0, m_sampleSpacing), 0.0));
points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(0.0, m_sampleSpacing), zPos)); points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(0.0, m_sampleSpacing), 0.0));
points.push_back(cvf::Vec3d(cellCorner, zPos)); points.push_back(cvf::Vec3d(cellCorner, 0.0));
#endif #endif
points.push_back(cvf::Vec3d(m_pickPoint - cvf::Vec2d(0.5 * m_sampleSpacing, 0.0), zPos)); points.push_back(cvf::Vec3d(m_pickPoint - cvf::Vec2d(0.5 * m_sampleSpacing, 0.0), 0.0));
points.push_back(cvf::Vec3d(m_pickPoint + cvf::Vec2d(0.5 * m_sampleSpacing, 0.0), zPos)); points.push_back(cvf::Vec3d(m_pickPoint + cvf::Vec2d(0.5 * m_sampleSpacing, 0.0), 0.0));
points.push_back(cvf::Vec3d(m_pickPoint - cvf::Vec2d(0.0, 0.5 * m_sampleSpacing), zPos)); points.push_back(cvf::Vec3d(m_pickPoint - cvf::Vec2d(0.0, 0.5 * m_sampleSpacing), 0.0));
points.push_back(cvf::Vec3d(m_pickPoint + cvf::Vec2d(0.0, 0.5 * m_sampleSpacing), zPos)); points.push_back(cvf::Vec3d(m_pickPoint + cvf::Vec2d(0.0, 0.5 * m_sampleSpacing), 0.0));
} }
} }
return points; return points;
@@ -585,7 +709,7 @@ bool RimContourMapProjection::checkForMapIntersection(const cvf::Vec3d& localPoi
CVF_TIGHT_ASSERT(contourMapPoint); CVF_TIGHT_ASSERT(contourMapPoint);
CVF_TIGHT_ASSERT(valueAtPoint); CVF_TIGHT_ASSERT(valueAtPoint);
cvf::Vec3d localPos3d(localPoint3d.x() + m_sampleSpacing, localPoint3d.y() + m_sampleSpacing, 0.0); cvf::Vec3d localPos3d(localPoint3d.x() + gridEdgeOffset(), localPoint3d.y() + gridEdgeOffset(), 0.0);
cvf::Vec2d gridPos2d(localPos3d.x(), localPos3d.y()); cvf::Vec2d gridPos2d(localPos3d.x(), localPos3d.y());
cvf::Vec2d gridorigin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y()); cvf::Vec2d gridorigin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y());
@@ -600,16 +724,62 @@ bool RimContourMapProjection::checkForMapIntersection(const cvf::Vec3d& localPoi
return false; return false;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimContourMapProjection::smoothPolygonLoops(ContourPolygons* contourPolygons)
{
CVF_ASSERT(contourPolygons);
for (size_t i = 0; i < contourPolygons->size(); ++i)
{
ContourPolygon& polygon = contourPolygons->at(i);
for (size_t n = 0; n < 50; ++n)
{
std::vector<cvf::Vec3d> newVertices;
newVertices.resize(polygon.vertices.size());
double maxChange = 0.0;
for (size_t j = 0; j < polygon.vertices.size(); ++j)
{
cvf::Vec3d vm1 = polygon.vertices.back();
cvf::Vec3d v = polygon.vertices[j];
cvf::Vec3d vp1 = polygon.vertices.front();
if (j > 0u)
{
vm1 = polygon.vertices[j - 1];
}
if (j < polygon.vertices.size() - 1)
{
vp1 = polygon.vertices[j + 1];
}
// Only expand.
cvf::Vec3d modifiedVertex = 0.5 * (v + 0.5 * (vm1 + vp1));
cvf::Vec3d delta = (modifiedVertex - v).getNormalized();
cvf::Vec3d tangent3d = vp1 - vm1;
cvf::Vec2d tangent2d(tangent3d.x(), tangent3d.y());
cvf::Vec3d norm3d (tangent2d.getNormalized().perpendicularVector());
if (delta * norm3d > 0)
{
// Normal is always inwards facing so a positive dot product means inward movement
// Favour expansion rather than contraction by only contracting by half the amount
modifiedVertex = v + 0.5 *delta;
}
newVertices[j] = modifiedVertex;
maxChange = std::max(maxChange, (modifiedVertex - v).length());
}
polygon.vertices.swap(newVertices);
if (maxChange < m_sampleSpacing * 1.0e-2)
break;
}
}
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
double RimContourMapProjection::interpolateValue(const cvf::Vec2d& gridPos2d) const double RimContourMapProjection::interpolateValue(const cvf::Vec2d& gridPos2d) const
{ {
cvf::Vec2d gridorigin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y());
cvf::Vec2ui cellContainingPoint = ijFromLocalPos(gridPos2d); cvf::Vec2ui cellContainingPoint = ijFromLocalPos(gridPos2d);
cvf::Vec2d globalCellCenter = globalCellCenterPosition(cellContainingPoint.x(), cellContainingPoint.y()); cvf::Vec2d cellCenter = cellCenterPosition(cellContainingPoint.x(), cellContainingPoint.y());
cvf::Vec2d cellCenter = globalCellCenter - gridorigin;
std::array<cvf::Vec3d, 4> x; std::array<cvf::Vec3d, 4> x;
x[0] = cvf::Vec3d(cellCenter + cvf::Vec2d(-m_sampleSpacing * 0.5, -m_sampleSpacing * 0.5), 0.0); x[0] = cvf::Vec3d(cellCenter + cvf::Vec2d(-m_sampleSpacing * 0.5, -m_sampleSpacing * 0.5), 0.0);
@@ -631,7 +801,7 @@ double RimContourMapProjection::interpolateValue(const cvf::Vec2d& gridPos2d) co
double vertexValue = valueAtVertex(v[i].x(), v[i].y()); double vertexValue = valueAtVertex(v[i].x(), v[i].y());
if (vertexValue == std::numeric_limits<double>::infinity()) if (vertexValue == std::numeric_limits<double>::infinity())
{ {
return std::numeric_limits<double>::infinity(); return vertexValue;
} }
value += baryCentricCoords[i] * vertexValue; value += baryCentricCoords[i] * vertexValue;
} }
@@ -641,9 +811,17 @@ double RimContourMapProjection::interpolateValue(const cvf::Vec2d& gridPos2d) co
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RimContourMapProjection::setPickPoint(cvf::Vec2d pickedPoint) void RimContourMapProjection::setPickPoint(cvf::Vec2d globalPickPoint)
{ {
m_pickPoint = pickedPoint; m_pickPoint = globalPickPoint - origin2d();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3d RimContourMapProjection::origin3d() const
{
return m_fullBoundingBox.min();
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -765,7 +943,7 @@ void RimContourMapProjection::generateGridMapping()
{ {
cvf::Vec2ui ij = ijFromCellIndex(index); cvf::Vec2ui ij = ijFromCellIndex(index);
cvf::Vec2d globalPos = globalCellCenterPosition(ij.x(), ij.y()); cvf::Vec2d globalPos = cellCenterPosition(ij.x(), ij.y()) + origin2d();
m_projected3dGridIndices[index] = visibleCellsAndLengthInCellFrom2dPoint(globalPos, weightingResultValues); m_projected3dGridIndices[index] = visibleCellsAndLengthInCellFrom2dPoint(globalPos, weightingResultValues);
} }
} }
@@ -776,7 +954,7 @@ void RimContourMapProjection::generateGridMapping()
{ {
cvf::Vec2ui ij = ijFromCellIndex(index); cvf::Vec2ui ij = ijFromCellIndex(index);
cvf::Vec2d globalPos = globalCellCenterPosition(ij.x(), ij.y()); cvf::Vec2d globalPos = cellCenterPosition(ij.x(), ij.y()) + origin2d();
m_projected3dGridIndices[index] = visibleCellsAndOverlapVolumeFrom2dPoint(globalPos, weightingResultValues); m_projected3dGridIndices[index] = visibleCellsAndOverlapVolumeFrom2dPoint(globalPos, weightingResultValues);
} }
} }
@@ -1275,30 +1453,35 @@ cvf::Vec2ui RimContourMapProjection::ijFromLocalPos(const cvf::Vec2d& localPos2d
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
cvf::Vec2d RimContourMapProjection::globalCellCenterPosition(uint i, uint j) const cvf::Vec2d RimContourMapProjection::cellCenterPosition(uint i, uint j) const
{ {
cvf::Vec3d gridExtent = m_fullBoundingBox.extent(); cvf::Vec3d gridExtent = m_fullBoundingBox.extent();
cvf::Vec2d origin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y()); cvf::Vec2d cellCorner = cvf::Vec2d((i * gridExtent.x()) / (m_mapSize.x()), (j * gridExtent.y()) / (m_mapSize.y()));
cvf::Vec2d cellCorner = origin + cvf::Vec2d((i * gridExtent.x()) / (m_mapSize.x()), (j * gridExtent.y()) / (m_mapSize.y()));
return cellCorner + cvf::Vec2d(m_sampleSpacing * 0.5, m_sampleSpacing * 0.5); return cellCorner + cvf::Vec2d(m_sampleSpacing * 0.5, m_sampleSpacing * 0.5);
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec2d RimContourMapProjection::origin2d() const
{
return cvf::Vec2d(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y());
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::vector<double> RimContourMapProjection::xVertexPositions() const std::vector<double> RimContourMapProjection::xVertexPositions() const
{ {
double gridExtent = m_fullBoundingBox.extent().x(); double gridExtent = m_fullBoundingBox.extent().x();
double origin = m_fullBoundingBox.min().x();
cvf::Vec2ui gridSize = numberOfVerticesIJ(); cvf::Vec2ui gridSize = numberOfVerticesIJ();
std::vector<double> positions; std::vector<double> positions;
positions.reserve(gridSize.x()); positions.reserve(gridSize.x());
for (uint i = 0; i < gridSize.x(); ++i) for (uint i = 0; i < gridSize.x(); ++i)
{ {
positions.push_back(origin + (i * gridExtent) / (gridSize.x() - 1)); positions.push_back((i * gridExtent) / (gridSize.x() - 1));
} }
return positions; return positions;
@@ -1310,14 +1493,13 @@ std::vector<double> RimContourMapProjection::xVertexPositions() const
std::vector<double> RimContourMapProjection::yVertexPositions() const std::vector<double> RimContourMapProjection::yVertexPositions() const
{ {
double gridExtent = m_fullBoundingBox.extent().y(); double gridExtent = m_fullBoundingBox.extent().y();
double origin = m_fullBoundingBox.min().y();
cvf::Vec2ui gridSize = numberOfVerticesIJ(); cvf::Vec2ui gridSize = numberOfVerticesIJ();
std::vector<double> positions; std::vector<double> positions;
positions.reserve(gridSize.y()); positions.reserve(gridSize.y());
for (uint j = 0; j < gridSize.y(); ++j) for (uint j = 0; j < gridSize.y(); ++j)
{ {
positions.push_back(origin + (j * gridExtent) / (gridSize.y() - 1)); positions.push_back((j * gridExtent) / (gridSize.y() - 1));
} }
return positions; return positions;
@@ -1347,7 +1529,7 @@ void RimContourMapProjection::updateGridInformation()
m_mainGrid = eclipseCase()->eclipseCaseData()->mainGrid(); m_mainGrid = eclipseCase()->eclipseCaseData()->mainGrid();
m_sampleSpacing = m_relativeSampleSpacing * m_mainGrid->characteristicIJCellSize(); m_sampleSpacing = m_relativeSampleSpacing * m_mainGrid->characteristicIJCellSize();
m_fullBoundingBox = eclipseCase()->activeCellsBoundingBox(); m_fullBoundingBox = eclipseCase()->activeCellsBoundingBox();
m_fullBoundingBox.expand(m_sampleSpacing * 2.0); m_fullBoundingBox.expand(gridEdgeOffset() * 2.0);
m_mapSize = calculateMapSize(); m_mapSize = calculateMapSize();
// Re-jig max point to be an exact multiple of cell size // Re-jig max point to be an exact multiple of cell size
@@ -1390,3 +1572,11 @@ RimContourMapView* RimContourMapProjection::view() const
firstAncestorOrThisOfTypeAsserted(view); firstAncestorOrThisOfTypeAsserted(view);
return view; return view;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimContourMapProjection::gridEdgeOffset() const
{
return m_sampleSpacing * 2.0;
}

View File

@@ -49,7 +49,7 @@ public:
struct ContourPolygon struct ContourPolygon
{ {
std::vector<cvf::Vec3d> vertices; std::vector<cvf::Vec3d> vertices;
cvf::String label; double value;
}; };
enum ResultAggregationEnum enum ResultAggregationEnum
@@ -72,7 +72,8 @@ public:
RimContourMapProjection(); RimContourMapProjection();
~RimContourMapProjection() override; ~RimContourMapProjection() override;
std::vector<cvf::Vec3d> generateVertices(); std::vector<cvf::Vec4d> generateTriangles() const;
std::vector<cvf::Vec3d> generateVertices() const;
void generateContourPolygons(); void generateContourPolygons();
std::vector<cvf::Vec3d> generatePickPointPolygon(); std::vector<cvf::Vec3d> generatePickPointPolygon();
void generateResults(); void generateResults();
@@ -112,9 +113,11 @@ public:
void updatedWeightingResult(); void updatedWeightingResult();
bool checkForMapIntersection(const cvf::Vec3d& localPoint3d, cvf::Vec2d* contourMapPoint, double* valueAtPoint) const; bool checkForMapIntersection(const cvf::Vec3d& localPoint3d, cvf::Vec2d* contourMapPoint, double* valueAtPoint) const;
void setPickPoint(cvf::Vec2d pickedPoint); void setPickPoint(cvf::Vec2d globalPickPoint);
cvf::Vec3d origin3d() const;
protected: protected:
void smoothPolygonLoops(ContourPolygons* contourPolygons);
double interpolateValue(const cvf::Vec2d& gridPosition2d) const; double interpolateValue(const cvf::Vec2d& gridPosition2d) const;
void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override;
@@ -155,7 +158,8 @@ private:
cvf::Vec2ui ijFromVertexIndex(size_t gridIndex) const; cvf::Vec2ui ijFromVertexIndex(size_t gridIndex) const;
cvf::Vec2ui ijFromCellIndex(size_t mapIndex) const; cvf::Vec2ui ijFromCellIndex(size_t mapIndex) const;
cvf::Vec2ui ijFromLocalPos(const cvf::Vec2d& localPos2d) const; cvf::Vec2ui ijFromLocalPos(const cvf::Vec2d& localPos2d) const;
cvf::Vec2d globalCellCenterPosition(uint i, uint j) const; cvf::Vec2d cellCenterPosition(uint i, uint j) const;
cvf::Vec2d origin2d() const;
std::vector<double> xVertexPositions() const; std::vector<double> xVertexPositions() const;
std::vector<double> yVertexPositions() const; std::vector<double> yVertexPositions() const;
@@ -167,6 +171,8 @@ private:
RimEclipseResultCase* eclipseCase() const; RimEclipseResultCase* eclipseCase() const;
RimContourMapView* view() const; RimContourMapView* view() const;
double gridEdgeOffset() const;
protected: protected:
caf::PdmField<double> m_relativeSampleSpacing; caf::PdmField<double> m_relativeSampleSpacing;
caf::PdmField<ResultAggregation> m_resultAggregation; caf::PdmField<ResultAggregation> m_resultAggregation;

View File

@@ -69,7 +69,9 @@ void caf::ContourLines::create(const std::vector<double>& dataXY, const std::vec
temp2 = std::max(saneValue(gridIndex1d(i + 1, j, nx), dataXY, contourLevels), temp2 = std::max(saneValue(gridIndex1d(i + 1, j, nx), dataXY, contourLevels),
saneValue(gridIndex1d(i + 1, j + 1, nx), dataXY, contourLevels)); saneValue(gridIndex1d(i + 1, j + 1, nx), dataXY, contourLevels));
double dmax = std::max(temp1, temp2); double dmax = std::max(temp1, temp2);
if (dmax < contourLevels[0] || dmin > contourLevels[nContourLevels - 1]) // Using dmax <= contourLevels[0] as a deviation from Bourke because it empirically
// Reduces gridding artifacts in our code.
if (dmax <= contourLevels[0] || dmin > contourLevels[nContourLevels - 1])
continue; continue;
for (int k = 0; k < nContourLevels; k++) for (int k = 0; k < nContourLevels; k++)