#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::ref<cvf::DrawableGeo> drawable = createProjectionMapDrawable(displayCoordTransform);
if (drawable.notNull() && drawable->boundingBox().isValid())
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels = createContourPolygons(displayCoordTransform);
cvf::ref<cvf::Part> mapPart = createProjectionMapPart(displayCoordTransform);
if (mapPart.notNull())
{
cvf::ref<cvf::Part> part = new cvf::Part;
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());
model->addPart(mapPart.p());
}
if (m_contourMapProjection->showContourLines())
@@ -56,7 +49,6 @@ void RivContourMapProjectionPartMgr::appendProjectionToModel(cvf::ModelBasicList
std::vector<double> tickValues;
mapper->majorTickValues(&tickValues);
std::vector<std::vector<cvf::ref<cvf::Drawable>>> contourDrawablesForAllLevels = createContourPolygons(displayCoordTransform);
for (size_t i = 0; i < contourDrawablesForAllLevels.size(); ++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::ref<cvf::Vec2fArray> textureCoords = new cvf::Vec2fArray(m_contourMapProjection->numberOfVertices());
cvf::ref<cvf::Vec2fArray> textureCoords = new cvf::Vec2fArray(values.size());
#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))
{
double value = m_contourMapProjection->valueAtVertex(i, j);
cvf::Vec2f textureCoord = m_contourMapProjection->legendConfig()->scalarMapper()->mapToTextureCoord(value);
textureCoord.y() = 0.0;
(*textureCoords)[i + j * patchSize.x()] = textureCoord;
}
else
{
RiaWeightedMeanCalculator<double> calc;
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);
}
}
cvf::Vec2f textureCoord = m_contourMapProjection->legendConfig()->scalarMapper()->mapToTextureCoord(values[i]);
textureCoord.y() = 0.0;
(*textureCoords)[i] = textureCoord;
}
else
{
(*textureCoords)[i] = cvf::Vec2f(0.0, 1.0);
}
}
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)
{
auto font = RiaFontCache::getFont(RiaFontCache::FONT_SIZE_8);
auto font = RiaFontCache::getFont(RiaFontCache::FONT_SIZE_10);
cvf::ref<cvf::DrawableText> labelDrawable = new cvf::DrawableText();
labelDrawable->setFont(font.p());
labelDrawable->setCheckPosVisible(true);
labelDrawable->setUseDepthBuffer(true);
labelDrawable->setDrawBorder(true);
labelDrawable->setDrawBackground(true);
labelDrawable->setDrawBorder(false);
labelDrawable->setDrawBackground(false);
labelDrawable->setBackgroundColor(backgroundColor);
labelDrawable->setVerticalAlignment(cvf::TextDrawer::BASELINE);
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();
if (vertices.empty()) return nullptr;
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray(vertices.size());
for (size_t i = 0; i < vertices.size(); ++i)
std::vector<cvf::Vec4d> vertices = m_contourMapProjection->generateTriangles();
if (vertices.size() < 3u)
{
cvf::Vec3f displayVertexPos (displayCoordTransform->transformToDisplayCoord(vertices[i]));
(*vertexArray)[i] = displayVertexPos;
return cvf::ref<cvf::Part>();
}
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::DrawableGeo> geo = new cvf::DrawableGeo;
geo->addPrimitiveSet(indexUInt.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;
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)
{
cvf::ref<cvf::DrawableText> label = createTextLabel(textColor, backgroundColor);
cvf::Vec3f labelVertex(displayCoordTransform->transformToDisplayCoord(contourPolygons[i][j].vertices[(nVertices * l) / nLabels]));
labelVertex.z() += 3.0f;
label->addText(contourPolygons[i][j].label, labelVertex);
cvf::Vec3d globalVertex = contourPolygons[i][j].vertices[(nVertices * l) / nLabels] + m_contourMapProjection->origin3d();
cvf::Vec3f displayVertex(displayCoordTransform->transformToDisplayCoord(globalVertex));
displayVertex.z() += 3.0f;
label->addText(cvf::String(contourPolygons[i][j].value), displayVertex);
bool overlaps = false;
cvf::BoundingBox bbox = label->boundingBox();
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);
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 displayVertex2 = displayCoordTransform->transformToDisplayCoord(contourPolygons[i][j].vertices[v + 1]);
cvf::Vec3d globalVertex = contourPolygons[i][j].vertices[v] + m_contourMapProjection->origin3d();
cvf::Vec3d displayVertex1 = displayCoordTransform->transformToDisplayCoord(globalVertex);
(*vertexArray)[v] = cvf::Vec3f(displayVertex1);
(*vertexArray)[v + 1] = cvf::Vec3f(displayVertex2);
}
std::vector<cvf::uint> indices;
@@ -279,7 +253,7 @@ std::vector<std::vector<cvf::ref<cvf::Drawable>>> RivContourMapProjectionPartMgr
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);
indexedUInt->setIndices(indexArray.p());
@@ -315,7 +289,8 @@ cvf::ref<cvf::DrawableGeo>
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;
}

View File

@@ -40,11 +40,11 @@ public:
void appendPickPointVisToModel(cvf::ModelBasicList* model,
const caf::DisplayCoordTransform* displayCoordTransform) const;
cvf::ref<cvf::Vec2fArray> createTextureCoords() const;
cvf::ref<cvf::Vec2fArray> createTextureCoords(const std::vector<double>& values) const;
private:
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;
cvf::ref<cvf::DrawableGeo> createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const;
private:

View File

@@ -33,10 +33,12 @@
#include "cvfArray.h"
#include "cvfCellRange.h"
#include "cvfGeometryTools.h"
#include "cvfGeometryUtils.h"
#include "cvfScalarMapper.h"
#include "cvfStructGridGeometryGenerator.h"
#include <algorithm>
#include <omp.h>
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();
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)
{
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
globalPos.x() -= m_sampleSpacing * 0.5;
globalPos.y() -= m_sampleSpacing * 0.5;
mapPos.x() -= m_sampleSpacing * 0.5;
mapPos.y() -= m_sampleSpacing * 0.5;
cvf::Vec3d globalVertexPos(globalPos, m_fullBoundingBox.min().z());
vertices[index] = globalVertexPos;
cvf::Vec3d vertexPos(mapPos, 0.0);
vertices[index] = vertexPos;
}
return vertices;
}
@@ -145,33 +279,29 @@ void RimContourMapProjection::generateContourPolygons()
int nContourLevels = static_cast<int>(contourLevels.size());
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 =
caf::ContourLines::create(m_aggregatedVertexResults, xVertexPositions(), yVertexPositions(), fudgedContourLevels);
caf::ContourLines::create(m_aggregatedVertexResults, xVertexPositions(), yVertexPositions(), contourLevels);
contourPolygons.resize(closedContourLines.size());
for (size_t i = 0; i < closedContourLines.size(); ++i)
{
for (size_t j = 0; j < closedContourLines[i].size(); ++j)
{
ContourPolygon contourPolygon;
contourPolygon.label = cvf::String(contourLevels[i]);
contourPolygon.vertices.reserve(closedContourLines[i][j].size());
for (size_t k = 0; k < closedContourLines[i][j].size(); ++k)
contourPolygon.value = contourLevels[i];
contourPolygon.vertices.reserve(closedContourLines[i][j].size() / 2);
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);
}
contourPolygons[i].push_back(contourPolygon);
}
}
smoothPolygonLoops(&contourPolygons[0]);
}
}
}
@@ -188,31 +318,25 @@ RimContourMapProjection::generatePickPointPolygon()
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::Vec2ui pickedCell = ijFromLocalPos(localPickPoint);
cvf::Vec2d cellCenter = globalCellCenterPosition(pickedCell.x(), pickedCell.y());
cvf::Vec2ui pickedCell = ijFromLocalPos(m_pickPoint);
cvf::Vec2d cellCenter = cellCenterPosition(pickedCell.x(), pickedCell.y());
cvf::Vec2d cellCorner = cellCenter - cellDiagonal;
#ifndef NDEBUG
points.push_back(cvf::Vec3d(cellCorner, zPos));
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), zPos));
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), zPos));
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), zPos));
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), 0.0));
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), 0.0));
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), 0.0));
points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(0.0, m_sampleSpacing), 0.0));
points.push_back(cvf::Vec3d(cellCorner, 0.0));
#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), zPos));
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), 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), 0.0));
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), 0.0));
}
}
return points;
@@ -585,7 +709,7 @@ bool RimContourMapProjection::checkForMapIntersection(const cvf::Vec3d& localPoi
CVF_TIGHT_ASSERT(contourMapPoint);
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 gridorigin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y());
@@ -600,16 +724,62 @@ bool RimContourMapProjection::checkForMapIntersection(const cvf::Vec3d& localPoi
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
{
cvf::Vec2d gridorigin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y());
cvf::Vec2ui cellContainingPoint = ijFromLocalPos(gridPos2d);
cvf::Vec2d globalCellCenter = globalCellCenterPosition(cellContainingPoint.x(), cellContainingPoint.y());
cvf::Vec2d cellCenter = globalCellCenter - gridorigin;
cvf::Vec2d cellCenter = cellCenterPosition(cellContainingPoint.x(), cellContainingPoint.y());
std::array<cvf::Vec3d, 4> x;
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());
if (vertexValue == std::numeric_limits<double>::infinity())
{
return std::numeric_limits<double>::infinity();
return 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::Vec2d globalPos = globalCellCenterPosition(ij.x(), ij.y());
cvf::Vec2d globalPos = cellCenterPosition(ij.x(), ij.y()) + origin2d();
m_projected3dGridIndices[index] = visibleCellsAndLengthInCellFrom2dPoint(globalPos, weightingResultValues);
}
}
@@ -776,7 +954,7 @@ void RimContourMapProjection::generateGridMapping()
{
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);
}
}
@@ -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::Vec2d origin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y());
cvf::Vec2d cellCorner = origin + cvf::Vec2d((i * gridExtent.x()) / (m_mapSize.x()), (j * gridExtent.y()) / (m_mapSize.y()));
cvf::Vec2d cellCorner = 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);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec2d RimContourMapProjection::origin2d() const
{
return cvf::Vec2d(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimContourMapProjection::xVertexPositions() const
{
double gridExtent = m_fullBoundingBox.extent().x();
double origin = m_fullBoundingBox.min().x();
cvf::Vec2ui gridSize = numberOfVerticesIJ();
std::vector<double> positions;
positions.reserve(gridSize.x());
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;
@@ -1310,14 +1493,13 @@ std::vector<double> RimContourMapProjection::xVertexPositions() const
std::vector<double> RimContourMapProjection::yVertexPositions() const
{
double gridExtent = m_fullBoundingBox.extent().y();
double origin = m_fullBoundingBox.min().y();
cvf::Vec2ui gridSize = numberOfVerticesIJ();
std::vector<double> positions;
positions.reserve(gridSize.y());
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;
@@ -1347,7 +1529,7 @@ void RimContourMapProjection::updateGridInformation()
m_mainGrid = eclipseCase()->eclipseCaseData()->mainGrid();
m_sampleSpacing = m_relativeSampleSpacing * m_mainGrid->characteristicIJCellSize();
m_fullBoundingBox = eclipseCase()->activeCellsBoundingBox();
m_fullBoundingBox.expand(m_sampleSpacing * 2.0);
m_fullBoundingBox.expand(gridEdgeOffset() * 2.0);
m_mapSize = calculateMapSize();
// Re-jig max point to be an exact multiple of cell size
@@ -1390,3 +1572,11 @@ RimContourMapView* RimContourMapProjection::view() const
firstAncestorOrThisOfTypeAsserted(view);
return view;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimContourMapProjection::gridEdgeOffset() const
{
return m_sampleSpacing * 2.0;
}

View File

@@ -49,7 +49,7 @@ public:
struct ContourPolygon
{
std::vector<cvf::Vec3d> vertices;
cvf::String label;
double value;
};
enum ResultAggregationEnum
@@ -72,7 +72,8 @@ public:
RimContourMapProjection();
~RimContourMapProjection() override;
std::vector<cvf::Vec3d> generateVertices();
std::vector<cvf::Vec4d> generateTriangles() const;
std::vector<cvf::Vec3d> generateVertices() const;
void generateContourPolygons();
std::vector<cvf::Vec3d> generatePickPointPolygon();
void generateResults();
@@ -112,9 +113,11 @@ public:
void updatedWeightingResult();
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:
void smoothPolygonLoops(ContourPolygons* contourPolygons);
double interpolateValue(const cvf::Vec2d& gridPosition2d) const;
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 ijFromCellIndex(size_t mapIndex) 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> yVertexPositions() const;
@@ -167,6 +171,8 @@ private:
RimEclipseResultCase* eclipseCase() const;
RimContourMapView* view() const;
double gridEdgeOffset() const;
protected:
caf::PdmField<double> m_relativeSampleSpacing;
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),
saneValue(gridIndex1d(i + 1, j + 1, nx), dataXY, contourLevels));
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;
for (int k = 0; k < nContourLevels; k++)