From 7ff7f42adc7448947de00e6d833b6f821a62ff05 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 12 Nov 2015 12:00:51 +0100 Subject: [PATCH] (#266) Added geometry for grid box faces Added legend lines and text --- ApplicationCode/CMakeLists.txt | 17 +- .../RivFemPartGeometryGenerator.cpp | 13 +- .../GridBox/CMakeLists_files.cmake | 26 + .../GridBox/RivGridBoxGenerator.cpp | 487 ++++++++++++++++++ .../GridBox/RivGridBoxGenerator.h | 118 +++++ .../GridBox/RivPatchGenerator.cpp | 163 ++++++ .../GridBox/RivPatchGenerator.h | 64 +++ .../ScalarMapper-Test.cpp | 34 ++ .../ProjectDataModel/RimEclipseView.cpp | 2 + .../ProjectDataModel/RimGeoMechView.cpp | 2 + ApplicationCode/UserInterface/RiuViewer.cpp | 33 ++ ApplicationCode/UserInterface/RiuViewer.h | 15 +- 12 files changed, 955 insertions(+), 19 deletions(-) create mode 100644 ApplicationCode/ModelVisualization/GridBox/CMakeLists_files.cmake create mode 100644 ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp create mode 100644 ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h create mode 100644 ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp create mode 100644 ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.h create mode 100644 ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/ScalarMapper-Test.cpp diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index f4ef776cee..1e91d60ed5 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -31,6 +31,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/FileInterface ${CMAKE_CURRENT_SOURCE_DIR}/SocketInterface ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization + ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/GridBox ${CMAKE_CURRENT_SOURCE_DIR}/UserInterface ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel ${CMAKE_CURRENT_SOURCE_DIR}/ResultStatisticsCache @@ -111,12 +112,11 @@ set( SOCKET_INTERFACE_FILES SocketInterface/RiaSocketDataTransfer.cpp ) -set( UNIT_TEST_FILES - ProjectDataModel/ProjectDataModel_UnitTests/RimWellLogExtractionCurveImpl-Test.cpp - ProjectDataModel/ProjectDataModel_UnitTests/WellPathAsciiFileReader-Test.cpp +# Using GLOB here to ease adding of new unit tests +FILE ( GLOB UNIT_TEST_FILES + ProjectDataModel/ProjectDataModel_UnitTests/*.cpp ) - list( APPEND CPP_SOURCES ${APPLICATION_FILES} ${USER_INTERFACE_FILES} @@ -124,16 +124,17 @@ list( APPEND CPP_SOURCES ${UNIT_TEST_FILES} ) - - list( APPEND REFERENCED_CMAKE_FILES ReservoirDataModel/CMakeLists_files.cmake ReservoirDataModel/CMakeLists_filesNotToUnitTest.cmake FileInterface/CMakeLists_files.cmake ProjectDataModel/CMakeLists_files.cmake + GeoMech/GeoMechVisualization/CMakeLists_files.cmake + ModelVisualization/CMakeLists_files.cmake - GeoMech/GeoMechVisualization/CMakeLists_files.cmake - Commands/CMakeLists_files.cmake + ModelVisualization/GridBox/CMakeLists_files.cmake + + Commands/CMakeLists_files.cmake Commands/OperationsUsingObjReferences/CMakeLists_files.cmake Commands/ToggleCommands/CMakeLists_files.cmake Commands/OctaveScriptCommands/CMakeLists_files.cmake diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp index 52d31a408c..e655ddf137 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp @@ -1,18 +1,17 @@ -#include + #include "RivFemPartGeometryGenerator.h" -#include "cvfBase.h" - #include "RigFemPart.h" -//#include "RigFemPartScalarDataAccess.h" +#include "cvfBase.h" +#include "cvfArray.h" #include "cvfDebugTimer.h" -#include "cvfGeometryBuilderDrawableGeo.h" +#include "cvfDrawableGeo.h" +#include "cvfOutlineEdgeExtractor.h" #include "cvfPrimitiveSetIndexedUInt.h" #include "cvfScalarMapper.h" -#include "cvfArray.h" -#include "cvfOutlineEdgeExtractor.h" +#include #include diff --git a/ApplicationCode/ModelVisualization/GridBox/CMakeLists_files.cmake b/ApplicationCode/ModelVisualization/GridBox/CMakeLists_files.cmake new file mode 100644 index 0000000000..0049fdae70 --- /dev/null +++ b/ApplicationCode/ModelVisualization/GridBox/CMakeLists_files.cmake @@ -0,0 +1,26 @@ + +# Use this workaround until we're on 2.8.3 on all platforms and can use CMAKE_CURRENT_LIST_DIR directly +if (${CMAKE_VERSION} VERSION_GREATER "2.8.2") + set(CEE_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/) +endif() + +set (SOURCE_GROUP_HEADER_FILES +${CEE_CURRENT_LIST_DIR}RivPatchGenerator.h +${CEE_CURRENT_LIST_DIR}RivGridBoxGenerator.h +) + +set (SOURCE_GROUP_SOURCE_FILES +${CEE_CURRENT_LIST_DIR}RivPatchGenerator.cpp +${CEE_CURRENT_LIST_DIR}RivGridBoxGenerator.cpp + +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +source_group( "ModelVisualization\\GridBox" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CEE_CURRENT_LIST_DIR}CMakeLists_files.cmake ) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp new file mode 100644 index 0000000000..81a393da58 --- /dev/null +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -0,0 +1,487 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#include "RivGridBoxGenerator.h" + +#include "RivPatchGenerator.h" + +#include "cafEffectGenerator.h" +#include "cvfCamera.h" +#include "cvfDrawableText.h" +#include "cvfFixedAtlasFont.h" +#include "cvfGeometryBuilderDrawableGeo.h" +#include "cvfGeometryBuilderFaceList.h" +#include "cvfMeshEdgeExtractor.h" +#include "cvfPrimitiveSetIndexedUInt.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivGridBoxGenerator::RivGridBoxGenerator() +{ + m_gridBoxModel = new cvf::ModelBasicList; + + m_linDiscreteScalarMapper = new cvf::ScalarMapperDiscreteLinear; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::setTransform(cvf::Transform* scaleTransform) +{ + m_scaleTransform = scaleTransform; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::setBoundingBox(const cvf::BoundingBox& boundingBox) +{ + m_boundingBox = boundingBox; + + m_xValues.clear(); + m_yValues.clear(); + m_zValues.clear(); + + cvf::Vec3d min = m_boundingBox.min(); + cvf::Vec3d max = m_boundingBox.max(); + + m_linDiscreteScalarMapper->setRange(min.x(), max.x()); + m_linDiscreteScalarMapper->setLevelCount(5, true); + m_linDiscreteScalarMapper->majorTickValues(&m_xValues); + + m_linDiscreteScalarMapper->setRange(min.y(), max.y()); + m_linDiscreteScalarMapper->setLevelCount(5, true); + m_linDiscreteScalarMapper->majorTickValues(&m_yValues); + + m_linDiscreteScalarMapper->setRange(min.z(), max.z()); + m_linDiscreteScalarMapper->setLevelCount(5, true); + m_linDiscreteScalarMapper->majorTickValues(&m_zValues); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::createGridBoxParts() +{ + createGridBoxSideParts(); + createGridBoxLegendParts(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::updateFromCamera(const cvf::Camera* camera) +{ + m_gridBoxModel->removeAllParts(); + + if (m_gridBoxSideParts.size() == 0) return; + + for (size_t i = POS_X; i <= NEG_Z; i++) + { + cvf::Vec3f sideNorm = sideNormalOutwards((FaceType)i); + + cvf::Vec3d camToSide = camera->position() - pointOnSide((FaceType)i); + camToSide.normalize(); + + if (sideNorm.dot(cvf::Vec3f(camToSide)) < 0.0) + { + m_gridBoxModel->addPart(m_gridBoxSideParts[i].p()); + } + } + + for (size_t i = 0; i < m_gridBoxLegendParts.size(); i++) + { + m_gridBoxModel->addPart(m_gridBoxLegendParts[i].p()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Model* RivGridBoxGenerator::model() +{ + return m_gridBoxModel.p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::createGridBoxSideParts() +{ + m_gridBoxSideParts.clear(); + + cvf::Vec3d min = m_boundingBox.min(); + cvf::Vec3d max = m_boundingBox.max(); + + + for (int face = POS_X; face <= NEG_Z; face++) + { + // TODO: move out of loop + RivPatchGenerator patchGen; + + if (face == POS_X) + { + patchGen.setOrigin(cvf::Vec3d(max.x(), 0.0, 0.0)); + patchGen.setAxes(cvf::Vec3d::Y_AXIS, cvf::Vec3d::Z_AXIS); + patchGen.setSubdivisions(m_yValues, m_zValues); + } + else if (face == NEG_X) + { + patchGen.setOrigin(cvf::Vec3d(min.x(), 0.0, 0.0)); + patchGen.setAxes(cvf::Vec3d::Y_AXIS, cvf::Vec3d::Z_AXIS); + patchGen.setSubdivisions(m_yValues, m_zValues); + } + else if (face == POS_Y) + { + patchGen.setOrigin(cvf::Vec3d(0.0, max.y(), 0.0)); + patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Z_AXIS); + patchGen.setSubdivisions(m_xValues, m_zValues); + } + else if (face == NEG_Y) + { + patchGen.setOrigin(cvf::Vec3d(0.0, min.y(), 0.0)); + patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Z_AXIS); + patchGen.setSubdivisions(m_xValues, m_zValues); + } + else if (face == POS_Z) + { + patchGen.setOrigin(cvf::Vec3d(0.0, 0.0, max.z())); + patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Y_AXIS); + patchGen.setSubdivisions(m_xValues, m_yValues); + } + else if (face == NEG_Z) + { + patchGen.setOrigin(cvf::Vec3d(0.0, 0.0, min.z())); + patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Y_AXIS); + patchGen.setSubdivisions(m_xValues, m_yValues); + } + else + { + CVF_ASSERT(false); + } + + cvf::GeometryBuilderFaceList builder; + patchGen.generate(&builder); + cvf::ref vertexArray = builder.vertices(); + cvf::ref faceList = builder.faceList(); + + { + // Box mesh + cvf::MeshEdgeExtractor ee; + ee.addFaceList(*faceList); + + cvf::ref geo = new cvf::DrawableGeo; + geo->setVertexArray(vertexArray.p()); + geo->addPrimitiveSet(new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES, ee.lineIndices().p())); + + cvf::ref part = new cvf::Part; + part->setName("Grid box "); + part->setDrawable(geo.p()); + + part->setTransform(m_scaleTransform.p()); + part->updateBoundingBox(); + + cvf::ref eff; + caf::MeshEffectGenerator effGen(cvf::Color3f::GRAY); + eff = effGen.generateCachedEffect(); + + part->setEffect(eff.p()); + + m_gridBoxSideParts.push_back(part.p()); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::createGridBoxLegendParts() +{ + m_gridBoxLegendParts.clear(); + + for (int edge = POS_Z_POS_X; edge <= NEG_X_NEG_Y; edge++) + { + cvf::Collection parts; + + createLegend((EdgeType)edge, &parts); + + for (int i = 0; i < parts.size(); i++) + { + m_gridBoxLegendParts.push_back(parts.at(i)); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection* parts) +{ + cvf::Vec3d posMin; + cvf::Vec3d posMax; + + cvf::Vec3d min = m_boundingBox.min(); + cvf::Vec3d max = m_boundingBox.max(); + + std::vector* tickValues = NULL; + AxisType axis; + + cvf::Vec3f tickMarkDir; + + switch (edge) + { + case RivGridBoxGenerator::POS_Z_POS_X: + axis = Y_AXIS; + tickValues = &m_yValues; + posMin.set(max.x(), min.y(), max.z()); + posMax.set(max.x(), max.y(), max.z()); + tickMarkDir = cornerDirection(POS_Z, POS_X); + break; + case RivGridBoxGenerator::POS_Z_NEG_X: + axis = Y_AXIS; + tickValues = &m_yValues; + posMin.set(min.x(), min.y(), max.z()); + posMax.set(min.x(), max.y(), max.z()); + tickMarkDir = cornerDirection(POS_Z, NEG_X); + break; + case RivGridBoxGenerator::POS_Z_POS_Y: + axis = X_AXIS; + tickValues = &m_xValues; + posMin.set(min.x(), max.y(), max.z()); + posMax.set(max.x(), max.y(), max.z()); + tickMarkDir = cornerDirection(POS_Z, POS_Y); + break; + case RivGridBoxGenerator::POS_Z_NEG_Y: + axis = X_AXIS; + tickValues = &m_xValues; + posMin.set(min.x(), min.y(), max.z()); + posMax.set(max.x(), min.y(), max.z()); + tickMarkDir = cornerDirection(POS_Z, NEG_Y); + break; + case RivGridBoxGenerator::NEG_Z_POS_X: + axis = Y_AXIS; + tickValues = &m_yValues; + posMin.set(max.x(), min.y(), min.z()); + posMax.set(max.x(), max.y(), min.z()); + tickMarkDir = cornerDirection(NEG_Z, POS_X); + break; + case RivGridBoxGenerator::NEG_Z_NEG_X: + axis = Y_AXIS; + tickValues = &m_yValues; + posMin.set(min.x(), min.y(), min.z()); + posMax.set(min.x(), max.y(), min.z()); + tickMarkDir = cornerDirection(NEG_Z, NEG_X); + break; + case RivGridBoxGenerator::NEG_Z_POS_Y: + axis = X_AXIS; + tickValues = &m_xValues; + posMin.set(min.x(), max.y(), min.z()); + posMax.set(max.x(), max.y(), min.z()); + tickMarkDir = cornerDirection(NEG_Z, POS_Y); + break; + case RivGridBoxGenerator::NEG_Z_NEG_Y: + axis = X_AXIS; + tickValues = &m_xValues; + posMin.set(min.x(), min.y(), min.z()); + posMax.set(max.x(), min.y(), min.z()); + tickMarkDir = cornerDirection(NEG_Z, NEG_Y); + break; + case RivGridBoxGenerator::POS_X_POS_Y: + axis = Z_AXIS; + tickValues = &m_zValues; + posMin.set(max.x(), max.y(), min.z()); + posMax.set(max.x(), max.y(), max.z()); + tickMarkDir = cornerDirection(POS_X, POS_Y); + break; + case RivGridBoxGenerator::POS_X_NEG_Y: + axis = Z_AXIS; + tickValues = &m_zValues; + posMin.set(max.x(), min.y(), min.z()); + posMax.set(max.x(), min.y(), max.z()); + tickMarkDir = cornerDirection(POS_X, NEG_Y); + break; + case RivGridBoxGenerator::NEG_X_POS_Y: + axis = Z_AXIS; + tickValues = &m_zValues; + posMin.set(min.x(), max.y(), min.z()); + posMax.set(min.x(), max.y(), max.z()); + tickMarkDir = cornerDirection(NEG_X, POS_Y); + break; + case RivGridBoxGenerator::NEG_X_NEG_Y: + axis = Z_AXIS; + tickValues = &m_zValues; + posMin.set(min.x(), min.y(), min.z()); + posMax.set(min.x(), min.y(), max.z()); + tickMarkDir = cornerDirection(NEG_X, NEG_Y); + break; + default: + break; + } + + CVF_ASSERT(tickValues); + + size_t numVerts = (tickValues->size()) * 2; + size_t numLines = (tickValues->size()) + 1; + + cvf::ref vertices = new cvf::Vec3fArray; + vertices->reserve(numVerts); + + cvf::ref indices = new cvf::UIntArray; + indices->reserve(2 * numLines); + + + float tickLength = static_cast(m_boundingBox.extent().length() / 100.0); + + cvf::Vec3f point = cvf::Vec3f(posMin); + cvf::Vec3f tickPoint; + + // Tick marks + for (size_t i = 0; i < tickValues->size(); ++i) + { + point[axis] = static_cast(tickValues->at(i)); + + vertices->add(point); + tickPoint = point + tickLength*tickMarkDir;; + vertices->add(tickPoint); + indices->add(2 * static_cast(i)); + indices->add(2 * static_cast(i) + 1); + } + + // Backbone of legend + indices->add(0); + indices->add(static_cast(numVerts) - 2); + + { + // Legend lines + + cvf::ref geo = new cvf::DrawableGeo; + geo->setVertexArray(vertices.p()); + + cvf::ref primSet = new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES); + primSet->setIndices(indices.p()); + geo->addPrimitiveSet(primSet.p()); + + cvf::ref part = new cvf::Part; + part->setName("Legend lines "); + part->setDrawable(geo.p()); + + part->setTransform(m_scaleTransform.p()); + part->updateBoundingBox(); + + cvf::ref eff; + caf::MeshEffectGenerator effGen(cvf::Color3f::WHITE); + eff = effGen.generateCachedEffect(); + + part->setEffect(eff.p()); + + parts->push_back(part.p()); + } + + + { + // Text labels + + cvf::ref geo = new cvf::DrawableText; + geo->setFont(new cvf::FixedAtlasFont(cvf::FixedAtlasFont::STANDARD)); + geo->setTextColor(cvf::Color3::WHITE); + geo->setDrawBackground(false); + geo->setDrawBorder(false); + //textGeo->setCheckPosVisible(false); + + for (size_t idx = 0; idx < tickValues->size(); idx++) + { + geo->addText(cvf::String(tickValues->at(idx)), vertices->get(idx*2 + 1) + (0.5f * tickLength) * tickMarkDir); + } + + cvf::ref part = new cvf::Part; + part->setDrawable(geo.p()); + part->setTransform(m_scaleTransform.p()); + part->updateBoundingBox(); + + cvf::ref eff = new cvf::Effect; + part->setEffect(eff.p()); + + //textPart->setPriority(11); + part->setName("Legend text"); + + parts->push_back(part.p()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3f RivGridBoxGenerator::sideNormalOutwards(FaceType face) +{ + switch (face) + { + case RivGridBoxGenerator::POS_X: + return cvf::Vec3f::X_AXIS; + case RivGridBoxGenerator::NEG_X: + return -cvf::Vec3f::X_AXIS; + case RivGridBoxGenerator::POS_Y: + return cvf::Vec3f::Y_AXIS; + case RivGridBoxGenerator::NEG_Y: + return -cvf::Vec3f::Y_AXIS; + case RivGridBoxGenerator::POS_Z: + return cvf::Vec3f::Z_AXIS; + case RivGridBoxGenerator::NEG_Z: + return -cvf::Vec3f::Z_AXIS; + default: + break; + } + + return cvf::Vec3f::ZERO; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RivGridBoxGenerator::pointOnSide(FaceType face) +{ + switch (face) + { + case RivGridBoxGenerator::POS_X: + case RivGridBoxGenerator::POS_Y: + case RivGridBoxGenerator::POS_Z: + return cvf::Vec3d(m_boundingBox.max()); + + case RivGridBoxGenerator::NEG_X: + case RivGridBoxGenerator::NEG_Y: + case RivGridBoxGenerator::NEG_Z: + return cvf::Vec3d(m_boundingBox.min()); + default: + break; + } + + return cvf::Vec3d::ZERO; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3f RivGridBoxGenerator::cornerDirection(FaceType face1, FaceType face2) +{ + cvf::Vec3f dir = sideNormalOutwards(face1) + sideNormalOutwards(face2); + dir.normalize(); + + return dir; +} diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h new file mode 100644 index 0000000000..666b90b69c --- /dev/null +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h @@ -0,0 +1,118 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#pragma once + +#include "cvfBase.h" + +#include "cvfCollection.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfTransform.h" +#include "cvfScalarMapperDiscreteLinear.h" + + +namespace cvf +{ + class Camera; +} + + +//================================================================================================== +// +// +//================================================================================================== +class RivGridBoxGenerator +{ +public: + RivGridBoxGenerator(); + + void setTransform(cvf::Transform* scaleTransform); + void setBoundingBox(const cvf::BoundingBox& boundingBox); + void createGridBoxParts(); + + void updateFromCamera(const cvf::Camera* camera); + + cvf::Model* model(); + +private: + enum AxisType + { + X_AXIS, + Y_AXIS, + Z_AXIS + }; + + enum FaceType + { + POS_X, + NEG_X, + POS_Y, + NEG_Y, + POS_Z, + NEG_Z + }; + + enum EdgeType + { + POS_Z_POS_X, + POS_Z_NEG_X, + POS_Z_POS_Y, + POS_Z_NEG_Y, + + NEG_Z_POS_X, + NEG_Z_NEG_X, + NEG_Z_POS_Y, + NEG_Z_NEG_Y, + + POS_X_POS_Y, + POS_X_NEG_Y, + NEG_X_POS_Y, + NEG_X_NEG_Y + }; + + +private: + void createGridBoxSideParts(); + void createGridBoxLegendParts(); + + void createLegend(EdgeType edge, cvf::Collection* parts); + + cvf::Vec3f sideNormalOutwards(FaceType face); + cvf::Vec3d pointOnSide(FaceType face); + cvf::Vec3f cornerDirection(FaceType face1, FaceType face2); + + +private: + cvf::Collection m_gridBoxSideParts; + cvf::Collection m_gridBoxLegendParts; + + cvf::ref m_gridBoxModel; + + cvf::ref m_scaleTransform; + cvf::BoundingBox m_boundingBox; + + cvf::ref m_linDiscreteScalarMapper; + + std::vector m_xValues; + std::vector m_yValues; + std::vector m_zValues; +}; + diff --git a/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp new file mode 100644 index 0000000000..e08862d935 --- /dev/null +++ b/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp @@ -0,0 +1,163 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#include "RivPatchGenerator.h" + +#include "cvfGeometryUtils.h" +#include "cvfArray.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivPatchGenerator::RivPatchGenerator() +: m_origin(0, 0, 0), + m_axisU(cvf::Vec3d::X_AXIS), + m_axisV(cvf::Vec3d::Y_AXIS), + m_useQuads(true), + m_windingCCW(true) +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::setOrigin(const cvf::Vec3d& origin) +{ + m_origin = origin; +} + +//-------------------------------------------------------------------------------------------------- +/// Set the axes +/// +/// The specified axes will be normalized +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::setAxes(const cvf::Vec3d& axisU, const cvf::Vec3d& axisV) +{ + m_axisU = axisU.getNormalized(); + m_axisV = axisV.getNormalized(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::setSubdivisions(const std::vector& uValues, const std::vector& vValues) +{ + m_uValues = uValues; + m_vValues = vValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::setQuads(bool useQuads) +{ + m_useQuads = useQuads; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::setWindingCCW(bool windingCCW) +{ + m_windingCCW = windingCCW; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::generate(cvf::GeometryBuilder* builder) +{ +/* + CVF_ASSERT(m_cellCountU > 0); + CVF_ASSERT(m_cellCountV > 0); + + size_t numVertices = (m_cellCountU + 1)*(m_cellCountV + 1); + + Vec3fArray vertices; + vertices.reserve(numVertices); + + const Vec3d unitU = (m_extentU*m_axisU)/m_cellCountU; + const Vec3d unitV = (m_extentV*m_axisV)/m_cellCountV; + + uint v; + for (v = 0; v <= m_cellCountV; v++) + { + Vec3d rowOrigo(m_origin + unitV*v); + + uint u; + for (u = 0; u <= m_cellCountU; u++) + { + vertices.add(Vec3f(rowOrigo + unitU*u)); + } + } + + uint baseNodeIdx = builder->addVertices(vertices); + + if (m_useQuads) + { + UIntArray conn; + GeometryUtils::tesselatePatchAsQuads(m_cellCountU + 1, m_cellCountV + 1, baseNodeIdx, m_windingCCW, &conn); + builder->addQuads(conn); + } + else + { + UIntArray conn; + GeometryUtils::tesselatePatchAsTriangles(m_cellCountU + 1, m_cellCountV + 1, baseNodeIdx, m_windingCCW, &conn); + builder->addTriangles(conn); + } +*/ + + CVF_ASSERT(m_uValues.size() > 0); + CVF_ASSERT(m_vValues.size() > 0); + + size_t numVertices = m_uValues.size() * m_vValues.size(); + + cvf::Vec3fArray vertices; + vertices.reserve(numVertices); + + for (size_t v = 0; v < m_vValues.size(); v++) + { + cvf::Vec3d rowOrigo(m_origin + m_axisV * m_vValues[v]); + + for (size_t u = 0; u < m_uValues.size(); u++) + { + vertices.add(cvf::Vec3f(rowOrigo + m_axisU * m_uValues[u])); + } + } + + cvf::uint baseNodeIdx = builder->addVertices(vertices); + + if (m_useQuads) + { + cvf::UIntArray conn; + cvf::GeometryUtils::tesselatePatchAsQuads(static_cast(m_uValues.size()), static_cast(m_vValues.size()), baseNodeIdx, m_windingCCW, &conn); + builder->addQuads(conn); + } + else + { + cvf::UIntArray conn; + cvf::GeometryUtils::tesselatePatchAsTriangles(static_cast(m_uValues.size()), static_cast(m_vValues.size()), baseNodeIdx, m_windingCCW, &conn); + builder->addTriangles(conn); + } +} + diff --git a/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.h b/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.h new file mode 100644 index 0000000000..c944c86ea1 --- /dev/null +++ b/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.h @@ -0,0 +1,64 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#pragma once + +#include "cvfBase.h" +#include "cvfVector3.h" + +#include + +namespace cvf +{ + class GeometryBuilder; +} + +//================================================================================================== +// +// Generates 2D patches based on predefined coordinates along u and v axis +// Inspired by cvf::PatchGenerator +// +//================================================================================================== +class RivPatchGenerator +{ +public: + RivPatchGenerator(); + + void setOrigin(const cvf::Vec3d& origin); + void setAxes(const cvf::Vec3d& axisU, const cvf::Vec3d& axisV); + void setSubdivisions(const std::vector& uValues, const std::vector& vValues); + + void setQuads(bool useQuads); + void setWindingCCW(bool windingCCW); + + void generate(cvf::GeometryBuilder* builder); + +private: + cvf::Vec3d m_origin; // Origin. Default (0, 0, 0) + cvf::Vec3d m_axisU; // First axis of patch. Default is global X-axis + cvf::Vec3d m_axisV; // Second axis of patch. Default is global Y-axis + + std::vector m_uValues; + std::vector m_vValues; + + bool m_useQuads; // If true, quads will be generated, otherwise triangles. Default is quads + bool m_windingCCW; // Winding of the generated quads. Controls which side of the patch will be front facing. +}; + diff --git a/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/ScalarMapper-Test.cpp b/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/ScalarMapper-Test.cpp new file mode 100644 index 0000000000..dc875050d6 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/ScalarMapper-Test.cpp @@ -0,0 +1,34 @@ +#include "gtest/gtest.h" + +#include "cvfScalarMapperDiscreteLinear.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(ScalarMapperTest, TestHumanReadableTickmarks) +{ + cvf::ref m_linDiscreteScalarMapper = new cvf::ScalarMapperDiscreteLinear; + + + double adjustedMin = 0.0; + double adjustedMax = 0.0; + + adjustedMin = 2141234; + adjustedMax = 2165239; + + size_t m_numLevels = 10; + + m_linDiscreteScalarMapper->setRange(adjustedMin, adjustedMax); + m_linDiscreteScalarMapper->setLevelCount(m_numLevels, true); + + std::vector tickValues; + m_linDiscreteScalarMapper->majorTickValues(&tickValues); + + for (size_t i = 0; i < tickValues.size(); i++) + { + qDebug() << i << " " << tickValues[i]; + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 43d21816f9..57bf83ae7a 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -480,6 +480,8 @@ void RimEclipseView::createDisplayModel() m_overlayInfoConfig()->update3DInfo(); updateLegends(); } + + m_viewer->showGridBox(true); } diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index f81f574e99..f1be68b085 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -250,6 +250,8 @@ void RimGeoMechView::createDisplayModel() m_vizLogic->updateStaticCellColors(-1); m_overlayInfoConfig()->update3DInfo(); } + + m_viewer->showGridBox(true); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 43a66055e3..160d6e74f5 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -28,6 +28,8 @@ #include "RimViewController.h" #include "RimViewLinker.h" +#include "RivGridBoxGenerator.h" + #include "RiuCadNavigation.h" #include "RiuGeoQuestNavigation.h" #include "RiuRmsNavigation.h" @@ -160,6 +162,9 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) // Setting this policy will make sure the handling is not deferred to the widget's parent, // which solves the problem setContextMenuPolicy(Qt::PreventContextMenu); + + m_showGridBox = true; + m_gridBoxGenerator = new RivGridBoxGenerator; } @@ -179,6 +184,7 @@ RiuViewer::~RiuViewer() delete m_animationProgress; delete m_histogramWidget; delete m_progressBarStyle; + delete m_gridBoxGenerator; } @@ -502,6 +508,11 @@ void RiuViewer::navigationPolicyUpdate() { viewLinker->updateCamera(m_reservoirView); } + + if (m_showGridBox) + { + m_gridBoxGenerator->updateFromCamera(mainCamera()); + } } } @@ -525,3 +536,25 @@ RimView* RiuViewer::ownerReservoirView() { return m_reservoirView; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::showGridBox(bool enable) +{ + m_showGridBox = enable; + + if (!enable) + { + currentScene()->removeModel(m_gridBoxGenerator->model()); + } + else + { + m_gridBoxGenerator->setBoundingBox(mainScene()->boundingBox()); +// m_gridBoxGenerator->setTransform(); + m_gridBoxGenerator->updateFromCamera(mainCamera()); + m_gridBoxGenerator->createGridBoxParts(); + + currentScene()->addModel(m_gridBoxGenerator->model()); + } +} diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index 81ad64224a..e32aa09a7a 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -29,11 +29,13 @@ #include "cvfStructGrid.h" class RimView; +class RiuSimpleHistogramWidget; +class RiuViewerCommands; +class RivGridBoxGenerator; + +class QCDEStyle; class QLabel; class QProgressBar; -class RiuSimpleHistogramWidget; -class QCDEStyle; -class RiuViewerCommands; namespace cvf { @@ -67,6 +69,8 @@ public: void setHistogram(double min, double max, const std::vector& histogram); void setHistogramPercentiles(double pmin, double pmax, double mean); + void showGridBox(bool enable); + void showAnimationProgress(bool enable); void removeAllColorLegends(); @@ -106,6 +110,9 @@ private: caf::PdmPointer m_reservoirView; QPoint m_lastMousePressPosition; - RiuViewerCommands * m_viewerCommands; + RiuViewerCommands* m_viewerCommands; + + bool m_showGridBox; + RivGridBoxGenerator* m_gridBoxGenerator; };