Merge pull request #5351 from OPM/feature-reservoir-surface-results

Feature reservoir surface results
This commit is contained in:
Jacob Støren 2020-01-20 07:40:23 +01:00 committed by GitHub
commit 1095165a64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 55656 additions and 113 deletions

View File

@ -100,8 +100,6 @@ Rim3dView* RicNewViewFeature::createReservoirView( RimEclipseCase* eclipseCase,
insertedView = geomCase->createAndAddReservoirView();
}
insertedView->updateSurfacesInViewTreeItems();
// Must be run before buildViewItems, as wells are created in this function
insertedView->loadDataAndUpdate();

View File

@ -190,21 +190,27 @@ void RivIntersectionResultsColoringTools::calculateNodeOrElementNodeBasedGeoMech
#pragma omp parallel for schedule( dynamic )
for ( int triangleVxIdx = 0; triangleVxIdx < vxCount; ++triangleVxIdx )
{
float resValue = 0;
int weightCount = vertexWeights[triangleVxIdx].size();
for ( int wIdx = 0; wIdx < weightCount; ++wIdx )
{
size_t resIdx;
if ( isElementNodalResult )
{
resIdx = vertexWeights[triangleVxIdx].vxId( wIdx );
}
else
{
resIdx = femPart->nodeIdxFromElementNodeResultIdx( vertexWeights[triangleVxIdx].vxId( wIdx ) );
}
float resValue = HUGE_VAL;
resValue += resultValues[resIdx] * vertexWeights[triangleVxIdx].weight( wIdx );
int weightCount = vertexWeights[triangleVxIdx].size();
if ( weightCount )
{
resValue = 0;
for ( int wIdx = 0; wIdx < weightCount; ++wIdx )
{
size_t resIdx;
if ( isElementNodalResult )
{
resIdx = vertexWeights[triangleVxIdx].vxId( wIdx );
}
else
{
resIdx = femPart->nodeIdxFromElementNodeResultIdx( vertexWeights[triangleVxIdx].vxId( wIdx ) );
}
resValue += resultValues[resIdx] * vertexWeights[triangleVxIdx].weight( wIdx );
}
}
if ( resValue == HUGE_VAL || resValue != resValue ) // a != a is true for NAN's
@ -590,8 +596,8 @@ void RivExtrudedCurveIntersectionPartMgr::createExtrusionDirParts( bool useBuffe
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivExtrudedCurveIntersectionPartMgr::appendNativeIntersectionFacesToModel( cvf::ModelBasicList* model,
cvf::Transform* scaleTransform )
void RivExtrudedCurveIntersectionPartMgr::appendIntersectionFacesToModel( cvf::ModelBasicList* model,
cvf::Transform* scaleTransform )
{
if ( m_intersectionFaces.isNull() )
{

View File

@ -72,7 +72,7 @@ public:
const cvf::ScalarMapper* explicitScalarColorMapper,
const RivTernaryScalarMapper* explicitTernaryColorMapper );
void appendNativeIntersectionFacesToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform );
void appendIntersectionFacesToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform );
void appendMeshLinePartsToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform );
void appendPolylinePartsToModel( Rim3dView& view, cvf::ModelBasicList* model, cvf::Transform* scaleTransform );

View File

@ -123,7 +123,7 @@ public:
Where the k's are normalized distances along the edge, from the edge start vertex .
This is the interpolation sceme:
This is the interpolation scheme:
v = (1 - k )* v1 + k *v2;
@ -205,6 +205,13 @@ public:
m_weights[1] = ( (float)( normDistFromE1V1 ) );
}
explicit RivIntersectionVertexWeights( const std::array<size_t, 8> vxIds, const std::array<double, 8> explicitWeights )
: m_count( 8 )
, m_vxIds( vxIds )
{
std::copy( explicitWeights.begin(), explicitWeights.end(), m_weights.begin() );
}
int size() const
{
return m_count;

View File

@ -1,10 +1,14 @@
set (SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RivSurfacePartMgr.h
${CMAKE_CURRENT_LIST_DIR}/RivSurfaceIntersectionGeometryGenerator.h
${CMAKE_CURRENT_LIST_DIR}/RivReservoirSurfaceIntersectionSourceInfo.h
)
set (SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RivSurfacePartMgr.cpp
${CMAKE_CURRENT_LIST_DIR}/RivSurfaceIntersectionGeometryGenerator.cpp
${CMAKE_CURRENT_LIST_DIR}/RivReservoirSurfaceIntersectionSourceInfo.cpp
)
list(APPEND CODE_HEADER_FILES
@ -16,3 +20,4 @@ ${SOURCE_GROUP_SOURCE_FILES}
)
source_group( "ModelVisualization\\Surfaces" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )

View File

@ -0,0 +1,62 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- Equinor ASA
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivReservoirSurfaceIntersectionSourceInfo.h"
#include "RivSurfaceIntersectionGeometryGenerator.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivReservoirSurfaceIntersectionSourceInfo::RivReservoirSurfaceIntersectionSourceInfo(
RivSurfaceIntersectionGeometryGenerator* geometryGenerator )
: m_intersectionGeometryGenerator( geometryGenerator )
{
CVF_ASSERT( m_intersectionGeometryGenerator.notNull() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<size_t>& RivReservoirSurfaceIntersectionSourceInfo::triangleToCellIndex() const
{
CVF_ASSERT( m_intersectionGeometryGenerator.notNull() );
return m_intersectionGeometryGenerator->triangleToCellIndex();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::array<cvf::Vec3f, 3> RivReservoirSurfaceIntersectionSourceInfo::triangle( int triangleIdx ) const
{
std::array<cvf::Vec3f, 3> tri;
tri[0] = ( *m_intersectionGeometryGenerator->triangleVxes() )[triangleIdx * 3];
tri[1] = ( *m_intersectionGeometryGenerator->triangleVxes() )[triangleIdx * 3 + 1];
tri[2] = ( *m_intersectionGeometryGenerator->triangleVxes() )[triangleIdx * 3 + 2];
return tri;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSurfaceInView* RivReservoirSurfaceIntersectionSourceInfo::intersection() const
{
return m_intersectionGeometryGenerator->intersection();
}

View File

@ -0,0 +1,38 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- Equinor ASA
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cvfArray.h"
#include "cvfObject.h"
#include <array>
class RivSurfaceIntersectionGeometryGenerator;
class RimSurfaceInView;
class RivReservoirSurfaceIntersectionSourceInfo : public cvf::Object
{
public:
explicit RivReservoirSurfaceIntersectionSourceInfo( RivSurfaceIntersectionGeometryGenerator* geometryGenerator );
const std::vector<size_t>& triangleToCellIndex() const;
std::array<cvf::Vec3f, 3> triangle( int triangleIdx ) const;
RimSurfaceInView* intersection() const;
private:
cvf::cref<RivSurfaceIntersectionGeometryGenerator> m_intersectionGeometryGenerator;
};

View File

@ -0,0 +1,397 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
// Copyright (C) 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RivSurfaceIntersectionGeometryGenerator.h"
#include "RigMainGrid.h"
#include "RigResultAccessor.h"
#include "RigSurface.h"
#include "Rim3dView.h"
#include "RimCase.h"
#include "RimGridView.h"
#include "RimSurface.h"
#include "RimSurfaceInView.h"
#include "RivExtrudedCurveIntersectionPartMgr.h"
#include "RivHexGridIntersectionTools.h"
#include "RivPolylineGenerator.h"
#include "cafDisplayCoordTransform.h"
#include "cafHexGridIntersectionTools/cafHexGridIntersectionTools.h"
#include "cvfDrawableGeo.h"
#include "cvfGeometryTools.h"
#include "cvfPlane.h"
#include "cvfPrimitiveSetDirect.h"
#include "cvfPrimitiveSetIndexedUInt.h"
#include "cvfRay.h"
#include "cvfScalarMapper.h"
#include "../cafHexInterpolator/cafHexInterpolator.h"
#include "RivSectionFlattner.h"
cvf::ref<caf::DisplayCoordTransform> displayCoordTransform( const RimIntersection* intersection )
{
Rim3dView* rimView = nullptr;
intersection->firstAncestorOrThisOfType( rimView );
CVF_ASSERT( rimView );
cvf::ref<caf::DisplayCoordTransform> transForm = rimView->displayCoordTransform();
return transForm;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivSurfaceIntersectionGeometryGenerator::RivSurfaceIntersectionGeometryGenerator( RimSurfaceInView* surfInView,
const RivIntersectionHexGridInterface* grid )
: m_surfaceInView( surfInView )
, m_hexGrid( grid )
{
m_triangleVxes = new cvf::Vec3fArray;
m_cellBorderLineVxes = new cvf::Vec3fArray;
m_faultCellBorderLineVxes = new cvf::Vec3fArray;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RivSurfaceIntersectionGeometryGenerator::~RivSurfaceIntersectionGeometryGenerator() {}
class MeshLinesAccumulator
{
public:
MeshLinesAccumulator( const RivIntersectionHexGridInterface* hexGrid )
: m_hexGrid( hexGrid )
{
}
std::vector<cvf::Vec3f> cellBorderLineVxes;
std::vector<cvf::Vec3f> faultCellBorderLineVxes;
std::map<const RigFault*, cvf::Vec3d> faultToHighestFaultMeshVxMap;
void accumulateMeshLines( const std::vector<int>& cellFaceForEachClippedTriangleEdge,
uint triVxIdx,
size_t globalCellIdx,
const cvf::Vec3d& p0,
const cvf::Vec3d& p1 )
{
#define isFace( faceEnum ) ( 0 <= faceEnum && faceEnum <= 5 )
using FaceType = cvf::StructGridInterface::FaceType;
if ( isFace( cellFaceForEachClippedTriangleEdge[triVxIdx] ) )
{
const RigFault* fault =
m_hexGrid->findFaultFromCellIndexAndCellFace( globalCellIdx,
(FaceType)cellFaceForEachClippedTriangleEdge[triVxIdx] );
if ( fault )
{
cvf::Vec3d highestVx = p0.z() > p1.z() ? p0 : p1;
auto itIsInsertedPair = faultToHighestFaultMeshVxMap.insert( {fault, highestVx} );
if ( !itIsInsertedPair.second )
{
if ( itIsInsertedPair.first->second.z() < highestVx.z() )
{
itIsInsertedPair.first->second = highestVx;
}
}
faultCellBorderLineVxes.emplace_back( p0 );
faultCellBorderLineVxes.emplace_back( p1 );
}
else
{
cellBorderLineVxes.emplace_back( p0 );
cellBorderLineVxes.emplace_back( p1 );
}
}
}
private:
cvf::cref<RivIntersectionHexGridInterface> m_hexGrid;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivSurfaceIntersectionGeometryGenerator::calculateArrays()
{
if ( m_triangleVxes->size() ) return;
if ( m_hexGrid.isNull() ) return;
std::vector<cvf::Vec3f> outputTriangleVertices;
MeshLinesAccumulator meshAcc( m_hexGrid.p() );
cvf::BoundingBox gridBBox = m_hexGrid->boundingBox();
m_usedSurfaceData = m_surfaceInView->surface()->surfaceData();
const std::vector<cvf::Vec3d>& nativeVertices = m_usedSurfaceData->vertices();
const std::vector<unsigned>& nativeTriangleIndices = m_usedSurfaceData->triangleIndices();
cvf::Vec3d displayModelOffset = m_hexGrid->displayOffset();
for ( size_t ntVxIdx = 0; ntVxIdx < nativeTriangleIndices.size(); ntVxIdx += 3 )
{
cvf::Vec3d p0 = nativeVertices[nativeTriangleIndices[ntVxIdx + 0]];
cvf::Vec3d p1 = nativeVertices[nativeTriangleIndices[ntVxIdx + 1]];
cvf::Vec3d p2 = nativeVertices[nativeTriangleIndices[ntVxIdx + 2]];
cvf::BoundingBox triangleBBox;
triangleBBox.add( p0 );
triangleBBox.add( p1 );
triangleBBox.add( p2 );
cvf::Vec3d maxHeightVec;
std::vector<size_t> triIntersectedCellCandidates;
m_hexGrid->findIntersectingCells( triangleBBox, &triIntersectedCellCandidates );
cvf::Plane plane;
plane.setFromPoints( p0, p1, p2 );
std::vector<caf::HexGridIntersectionTools::ClipVx> hexPlaneCutTriangleVxes;
hexPlaneCutTriangleVxes.reserve( 5 * 3 );
std::vector<int> cellFaceForEachTriangleEdge;
cellFaceForEachTriangleEdge.reserve( 5 * 3 );
std::array<cvf::Vec3d, 8> cellCorners;
std::array<size_t, 8> cornerIndices;
size_t startOfGeneratedTrianglesForNativeTriangles = outputTriangleVertices.size();
for ( size_t ticIdx = 0; ticIdx < triIntersectedCellCandidates.size(); ++ticIdx )
{
size_t globalCellIdx = triIntersectedCellCandidates[ticIdx];
if ( !m_hexGrid->useCell( globalCellIdx ) ) continue;
m_hexGrid->cellCornerVertices( globalCellIdx, &cellCorners[0] );
m_hexGrid->cellCornerIndices( globalCellIdx, &cornerIndices[0] );
hexPlaneCutTriangleVxes.clear();
int triangleCount = caf::HexGridIntersectionTools::planeHexIntersectionMC( plane,
&cellCorners[0],
&cornerIndices[0],
&hexPlaneCutTriangleVxes,
&cellFaceForEachTriangleEdge );
if ( triangleCount == 0 ) continue;
std::vector<cvf::Vec3d> cellCutTriangles;
for ( const auto& clipVx : hexPlaneCutTriangleVxes )
{
cellCutTriangles.push_back( clipVx.vx );
}
std::vector<cvf::Vec3d> clippedTriangleVxes;
std::vector<int> cellFaceForEachClippedTriangleEdge;
caf::HexGridIntersectionTools::clipPlanarTrianglesWithInPlaneTriangle( cellCutTriangles,
cellFaceForEachTriangleEdge,
p0,
p1,
p2,
&clippedTriangleVxes,
&cellFaceForEachClippedTriangleEdge );
size_t clippedTriangleCount = clippedTriangleVxes.size() / 3;
for ( uint clippTrIdx = 0; clippTrIdx < clippedTriangleCount; ++clippTrIdx )
{
uint triVxIdx = clippTrIdx * 3;
// Accumulate triangle vertices
cvf::Vec3d point0( clippedTriangleVxes[triVxIdx + 0] - displayModelOffset );
cvf::Vec3d point1( clippedTriangleVxes[triVxIdx + 1] - displayModelOffset );
cvf::Vec3d point2( clippedTriangleVxes[triVxIdx + 2] - displayModelOffset );
outputTriangleVertices.emplace_back( point0 );
outputTriangleVertices.emplace_back( point1 );
outputTriangleVertices.emplace_back( point2 );
// Accumulate mesh lines
meshAcc.accumulateMeshLines( cellFaceForEachClippedTriangleEdge, triVxIdx + 0, globalCellIdx, point0, point1 );
meshAcc.accumulateMeshLines( cellFaceForEachClippedTriangleEdge, triVxIdx + 1, globalCellIdx, point1, point2 );
meshAcc.accumulateMeshLines( cellFaceForEachClippedTriangleEdge, triVxIdx + 2, globalCellIdx, point2, point0 );
// Mapping to cell index
m_triangleToCellIdxMap.push_back( globalCellIdx );
// Interpolation from nodes
for ( int i = 0; i < 3; ++i )
{
cvf::Vec3d cvx = clippedTriangleVxes[triVxIdx + i];
std::array<double, 8> cornerWeights = caf::HexInterpolator::vertexWeights( cellCorners, cvx );
m_triVxToCellCornerWeights.push_back( RivIntersectionVertexWeights( cornerIndices, cornerWeights ) );
}
}
}
// Add triangles for the part of the native triangle outside any gridcells
if ( startOfGeneratedTrianglesForNativeTriangles == outputTriangleVertices.size() )
{
// No triangles created, use the complete native triangle
outputTriangleVertices.push_back( cvf::Vec3f( p0 - displayModelOffset ) );
outputTriangleVertices.push_back( cvf::Vec3f( p1 - displayModelOffset ) );
outputTriangleVertices.push_back( cvf::Vec3f( p2 - displayModelOffset ) );
m_triangleToCellIdxMap.push_back( cvf::UNDEFINED_SIZE_T );
m_triVxToCellCornerWeights.push_back( RivIntersectionVertexWeights() );
m_triVxToCellCornerWeights.push_back( RivIntersectionVertexWeights() );
m_triVxToCellCornerWeights.push_back( RivIntersectionVertexWeights() );
}
else
{
// Todo:
// Subtract the created triangles from the native triangle
// Add the remains
}
}
m_triangleVxes->assign( outputTriangleVertices );
m_cellBorderLineVxes->assign( meshAcc.cellBorderLineVxes );
m_faultCellBorderLineVxes->assign( meshAcc.faultCellBorderLineVxes );
for ( const auto& it : meshAcc.faultToHighestFaultMeshVxMap )
{
m_faultMeshLabelAndAnchorPositions.push_back( {it.first->name(), it.second} );
}
}
//--------------------------------------------------------------------------------------------------
/// Generate surface drawable geo from the specified region
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> RivSurfaceIntersectionGeometryGenerator::generateSurface()
{
calculateArrays();
CVF_ASSERT( m_triangleVxes.notNull() );
if ( m_triangleVxes->size() == 0 ) return nullptr;
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setFromTriangleVertexArray( m_triangleVxes.p() );
return geo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> RivSurfaceIntersectionGeometryGenerator::createMeshDrawable()
{
if ( !( m_cellBorderLineVxes.notNull() && m_cellBorderLineVxes->size() != 0 ) ) return nullptr;
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setVertexArray( m_cellBorderLineVxes.p() );
cvf::ref<cvf::PrimitiveSetDirect> prim = new cvf::PrimitiveSetDirect( cvf::PT_LINES );
prim->setIndexCount( m_cellBorderLineVxes->size() );
geo->addPrimitiveSet( prim.p() );
return geo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> RivSurfaceIntersectionGeometryGenerator::createFaultMeshDrawable()
{
if ( !( m_faultCellBorderLineVxes.notNull() && m_faultCellBorderLineVxes->size() != 0 ) ) return nullptr;
cvf::ref<cvf::DrawableGeo> geo = new cvf::DrawableGeo;
geo->setVertexArray( m_faultCellBorderLineVxes.p() );
cvf::ref<cvf::PrimitiveSetDirect> prim = new cvf::PrimitiveSetDirect( cvf::PT_LINES );
prim->setIndexCount( m_faultCellBorderLineVxes->size() );
geo->addPrimitiveSet( prim.p() );
return geo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<std::pair<QString, cvf::Vec3d>>&
RivSurfaceIntersectionGeometryGenerator::faultMeshLabelAndAnchorPositions()
{
return m_faultMeshLabelAndAnchorPositions;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<size_t>& RivSurfaceIntersectionGeometryGenerator::triangleToCellIndex() const
{
CVF_ASSERT( m_triangleVxes->size() );
return m_triangleToCellIdxMap;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<RivIntersectionVertexWeights>&
RivSurfaceIntersectionGeometryGenerator::triangleVxToCellCornerInterpolationWeights() const
{
CVF_ASSERT( m_triangleVxes->size() );
return m_triVxToCellCornerWeights;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const cvf::Vec3fArray* RivSurfaceIntersectionGeometryGenerator::triangleVxes() const
{
CVF_ASSERT( m_triangleVxes->size() );
return m_triangleVxes.p();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSurfaceInView* RivSurfaceIntersectionGeometryGenerator::intersection() const
{
return m_surfaceInView;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RivSurfaceIntersectionGeometryGenerator::isAnyGeometryPresent() const
{
if ( m_triangleVxes->size() == 0 )
{
return false;
}
else
{
return true;
}
}

View File

@ -0,0 +1,89 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) Statoil ASA
// Copyright (C) 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmPointer.h"
#include "RivHexGridIntersectionTools.h"
#include "cvfArray.h"
#include "cvfBoundingBox.h"
#include "cvfObject.h"
#include "cvfVector3.h"
#include <QString>
#include <vector>
class RigMainGrid;
class RigActiveCellInfo;
class RigResultAccessor;
class RigSurface;
class RimSurfaceInView;
class RivIntersectionHexGridInterface;
class RivIntersectionVertexWeights;
namespace cvf
{
class ScalarMapper;
class DrawableGeo;
} // namespace cvf
class RivSurfaceIntersectionGeometryGenerator : public cvf::Object, public RivIntersectionGeometryGeneratorIF
{
public:
RivSurfaceIntersectionGeometryGenerator( RimSurfaceInView* surfInView, const RivIntersectionHexGridInterface* grid );
~RivSurfaceIntersectionGeometryGenerator() override;
// Generate geometry
cvf::ref<cvf::DrawableGeo> generateSurface();
cvf::ref<cvf::DrawableGeo> createMeshDrawable();
cvf::ref<cvf::DrawableGeo> createFaultMeshDrawable();
const std::vector<std::pair<QString, cvf::Vec3d>>& faultMeshLabelAndAnchorPositions();
RimSurfaceInView* intersection() const;
// GeomGen Interface
bool isAnyGeometryPresent() const override;
const std::vector<size_t>& triangleToCellIndex() const override;
const std::vector<RivIntersectionVertexWeights>& triangleVxToCellCornerInterpolationWeights() const override;
const cvf::Vec3fArray* triangleVxes() const override;
private:
void calculateArrays();
RimSurfaceInView* m_surfaceInView;
cvf::ref<RigSurface> m_usedSurfaceData; // Store the reference to the old data, to know when new data has arrived.
cvf::cref<RivIntersectionHexGridInterface> m_hexGrid;
// Output arrays
cvf::ref<cvf::Vec3fArray> m_triangleVxes;
cvf::ref<cvf::Vec3fArray> m_cellBorderLineVxes;
cvf::ref<cvf::Vec3fArray> m_faultCellBorderLineVxes;
std::vector<size_t> m_triangleToCellIdxMap;
std::vector<RivIntersectionVertexWeights> m_triVxToCellCornerWeights;
std::vector<std::pair<QString, cvf::Vec3d>> m_faultMeshLabelAndAnchorPositions;
};

View File

@ -18,12 +18,38 @@
#include "RivSurfacePartMgr.h"
#include "RigSurface.h"
#include "RimSurface.h"
#include "RimSurfaceInView.h"
#include "RiaApplication.h"
#include "RiaPreferences.h"
#include "RimCase.h"
#include "RimEclipseCase.h"
#include "RimEclipseCellColors.h"
#include "RimEclipseResultDefinition.h"
#include "RimEclipseView.h"
#include "RimGeoMechCellColors.h"
#include "RimGeoMechResultDefinition.h"
#include "RimGeoMechView.h"
#include "RimRegularLegendConfig.h"
#include "RimSurface.h"
#include "RimSurfaceInView.h"
#include "RimTernaryLegendConfig.h"
#include "RigHexIntersectionTools.h"
#include "RigResultAccessor.h"
#include "RigResultAccessorFactory.h"
#include "RigSurface.h"
#include "RivHexGridIntersectionTools.h"
#include "RivIntersectionResultsColoringTools.h"
#include "RivMeshLinesSourceInfo.h"
#include "RivPartPriority.h"
#include "RivReservoirSurfaceIntersectionSourceInfo.h"
#include "RivScalarMapperUtils.h"
#include "RivSurfaceIntersectionGeometryGenerator.h"
#include "RivTernaryScalarMapper.h"
#include "cafEffectGenerator.h"
#include "cvfDrawableGeo.h"
#include "cvfModelBasicList.h"
#include "cvfPart.h"
@ -35,6 +61,12 @@
RivSurfacePartMgr::RivSurfacePartMgr( RimSurfaceInView* surface )
: m_surfaceInView( surface )
{
CVF_ASSERT( surface );
m_intersectionFacesTextureCoords = new cvf::Vec2fArray;
cvf::ref<RivIntersectionHexGridInterface> hexGrid = m_surfaceInView->createHexGridInterface();
m_intersectionGenerator = new RivSurfaceIntersectionGeometryGenerator( m_surfaceInView, hexGrid.p() );
}
//--------------------------------------------------------------------------------------------------
@ -50,10 +82,7 @@ void RivSurfacePartMgr::appendNativeGeometryPartsToModel( cvf::ModelBasicList* m
if ( m_nativeTrianglesPart.notNull() )
{
m_nativeTrianglesPart->setTransform( scaleTransform );
caf::SurfaceEffectGenerator surfaceGen( cvf::Color4f( m_surfaceInView->surface()->color() ), caf::PO_1 );
cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect();
m_nativeTrianglesPart->setEffect( eff.p() );
this->applySingleColor();
model->addPart( m_nativeTrianglesPart.p() );
@ -65,6 +94,275 @@ void RivSurfacePartMgr::appendNativeGeometryPartsToModel( cvf::ModelBasicList* m
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivSurfacePartMgr::updateCellResultColor( size_t timeStepIndex )
{
if ( m_intersectionFaces.notNull() )
{
RivIntersectionResultsColoringTools::calculateIntersectionResultColors( timeStepIndex,
false,
m_surfaceInView,
m_intersectionGenerator.p(),
nullptr,
nullptr,
m_intersectionFaces.p(),
m_intersectionFacesTextureCoords.p() );
}
if ( m_nativeTrianglesPart.notNull() )
{
if ( !m_nativeVertexToCellIndexMap.size() )
{
generateNativeVertexToCellIndexMap();
}
RimGridView* gridView = nullptr;
m_surfaceInView->firstAncestorOrThisOfType( gridView );
if ( !gridView ) return;
bool isLightingDisabled = gridView->isLightingDisabled();
RimEclipseResultDefinition* eclipseResDef = nullptr;
RimGeoMechResultDefinition* geomResultDef = nullptr;
const cvf::ScalarMapper* scalarColorMapper = nullptr;
const RivTernaryScalarMapper* ternaryColorMapper = nullptr;
// Ordinary result
if ( !eclipseResDef && !geomResultDef )
{
RimEclipseView* eclipseView = nullptr;
m_surfaceInView->firstAncestorOrThisOfType( eclipseView );
if ( eclipseView )
{
eclipseResDef = eclipseView->cellResult();
if ( !scalarColorMapper ) scalarColorMapper = eclipseView->cellResult()->legendConfig()->scalarMapper();
if ( !ternaryColorMapper )
ternaryColorMapper = eclipseView->cellResult()->ternaryLegendConfig()->scalarMapper();
}
RimGeoMechView* geoView;
m_surfaceInView->firstAncestorOrThisOfType( geoView );
if ( geoView )
{
geomResultDef = geoView->cellResult();
if ( !scalarColorMapper ) scalarColorMapper = geoView->cellResult()->legendConfig()->scalarMapper();
}
}
cvf::ref<cvf::Vec2fArray> nativeFacesTextureCoords = new cvf::Vec2fArray();
if ( eclipseResDef )
{
if ( !eclipseResDef->isTernarySaturationSelected() )
{
RigEclipseCaseData* eclipseCaseData = eclipseResDef->eclipseCase()->eclipseCaseData();
cvf::ref<RigResultAccessor> resultAccessor;
if ( !RiaDefines::isPerCellFaceResult( eclipseResDef->resultVariable() ) )
{
resultAccessor = RigResultAccessorFactory::createFromResultDefinition( eclipseCaseData,
0,
timeStepIndex,
eclipseResDef );
}
if ( resultAccessor.isNull() )
{
resultAccessor = new RigHugeValResultAccessor;
}
RivSurfacePartMgr::calculateVertexTextureCoordinates( nativeFacesTextureCoords.p(),
m_nativeVertexToCellIndexMap,
resultAccessor.p(),
scalarColorMapper );
RivScalarMapperUtils::applyTextureResultsToPart( m_nativeTrianglesPart.p(),
nativeFacesTextureCoords.p(),
scalarColorMapper,
1.0,
caf::FC_NONE,
isLightingDisabled );
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivSurfacePartMgr::appendIntersectionGeometryPartsToModel( cvf::ModelBasicList* model,
cvf::Transform* scaleTransform )
{
if ( m_intersectionFaces.isNull() )
{
generatePartGeometry();
}
if ( m_intersectionFaces.notNull() )
{
m_intersectionFaces->setTransform( scaleTransform );
model->addPart( m_intersectionFaces.p() );
}
// Mesh Lines
if ( m_intersectionGridLines.isNull() )
{
generatePartGeometry();
}
if ( m_intersectionGridLines.notNull() )
{
m_intersectionGridLines->setTransform( scaleTransform );
model->addPart( m_intersectionGridLines.p() );
}
if ( m_intersectionFaultGridLines.notNull() )
{
m_intersectionFaultGridLines->setTransform( scaleTransform );
model->addPart( m_intersectionFaultGridLines.p() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivSurfacePartMgr::applySingleColor()
{
{
caf::SurfaceEffectGenerator surfaceGen( cvf::Color4f( m_surfaceInView->surface()->color() ), caf::PO_1 );
cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect();
if ( m_nativeTrianglesPart.notNull() )
{
m_nativeTrianglesPart->setEffect( eff.p() );
}
if ( m_intersectionFaces.notNull() )
{
m_intersectionFaces->setEffect( eff.p() );
}
}
// Update mesh colors as well, in case of change
RiaPreferences* prefs = RiaApplication::instance()->preferences();
if ( m_intersectionGridLines.notNull() )
{
cvf::ref<cvf::Effect> eff;
caf::MeshEffectGenerator CrossSectionEffGen( prefs->defaultGridLineColors() );
eff = CrossSectionEffGen.generateCachedEffect();
m_intersectionGridLines->setEffect( eff.p() );
}
if ( m_intersectionFaultGridLines.notNull() )
{
cvf::ref<cvf::Effect> eff;
caf::MeshEffectGenerator CrossSectionEffGen( prefs->defaultFaultGridLineColors() );
eff = CrossSectionEffGen.generateCachedEffect();
m_intersectionFaultGridLines->setEffect( eff.p() );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivSurfacePartMgr::generatePartGeometry()
{
if ( m_intersectionGenerator.isNull() ) return;
bool useBufferObjects = true;
// Surface geometry
{
cvf::ref<cvf::DrawableGeo> geo = m_intersectionGenerator->generateSurface();
if ( geo.notNull() )
{
geo->computeNormals();
if ( useBufferObjects )
{
geo->setRenderMode( cvf::DrawableGeo::BUFFER_OBJECT );
}
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName( "Reservoir Surface" );
part->setDrawable( geo.p() );
// Set mapping from triangle face index to cell index
cvf::ref<RivReservoirSurfaceIntersectionSourceInfo> si = new RivReservoirSurfaceIntersectionSourceInfo(
m_intersectionGenerator.p() );
part->setSourceInfo( si.p() );
part->updateBoundingBox();
part->setEnableMask( intersectionCellFaceBit );
part->setPriority( RivPartPriority::PartType::Intersection );
m_intersectionFaces = part;
}
}
// Cell Mesh geometry
{
cvf::ref<cvf::DrawableGeo> geoMesh = m_intersectionGenerator->createMeshDrawable();
if ( geoMesh.notNull() )
{
if ( useBufferObjects )
{
geoMesh->setRenderMode( cvf::DrawableGeo::BUFFER_OBJECT );
}
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName( "Surface intersection mesh" );
part->setDrawable( geoMesh.p() );
part->updateBoundingBox();
part->setEnableMask( intersectionCellMeshBit );
part->setPriority( RivPartPriority::PartType::MeshLines );
part->setSourceInfo( new RivMeshLinesSourceInfo( m_surfaceInView ) );
m_intersectionGridLines = part;
}
}
// Fault Mesh geometry
{
cvf::ref<cvf::DrawableGeo> geoMesh = m_intersectionGenerator->createFaultMeshDrawable();
if ( geoMesh.notNull() )
{
if ( useBufferObjects )
{
geoMesh->setRenderMode( cvf::DrawableGeo::BUFFER_OBJECT );
}
cvf::ref<cvf::Part> part = new cvf::Part;
part->setName( "Surface faultmesh" );
part->setDrawable( geoMesh.p() );
part->updateBoundingBox();
part->setEnableMask( intersectionFaultMeshBit );
part->setPriority( RivPartPriority::PartType::FaultMeshLines );
part->setSourceInfo( new RivMeshLinesSourceInfo( m_surfaceInView ) );
m_intersectionFaultGridLines = part;
}
}
applySingleColor();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -94,5 +392,69 @@ void RivSurfacePartMgr::generateNativePartGeometry()
drawGeo->computeNormals();
m_nativeTrianglesPart = new cvf::Part();
m_nativeTrianglesPart->setName( "Native Reservoir Surface" );
m_nativeTrianglesPart->setDrawable( drawGeo.p() );
m_nativeVertexToCellIndexMap.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RivSurfacePartMgr::generateNativeVertexToCellIndexMap()
{
cvf::ref<RivIntersectionHexGridInterface> hexGrid = m_surfaceInView->createHexGridInterface();
const std::vector<cvf::Vec3d>& vertices = m_usedSurfaceData->vertices();
m_nativeVertexToCellIndexMap.resize( vertices.size(), -1 );
for ( size_t vxIdx = 0; vxIdx < vertices.size(); ++vxIdx )
{
cvf::BoundingBox box;
box.add( vertices[vxIdx] );
std::vector<size_t> cellCandidates;
hexGrid->findIntersectingCells( box, &cellCandidates );
for ( size_t cellIdx : cellCandidates )
{
cvf::Vec3d cellCorners[8];
hexGrid->cellCornerVertices( cellIdx, cellCorners );
if ( RigHexIntersectionTools::isPointInCell( vertices[vxIdx], cellCorners ) )
{
m_nativeVertexToCellIndexMap[vxIdx] = cellIdx;
break;
}
}
}
}
//--------------------------------------------------------------------------------------------------
/// Calculates the texture coordinates in a "nearly" one dimensional texture.
/// Undefined values are coded with a y-texturecoordinate value of 1.0 instead of the normal 0.5
//--------------------------------------------------------------------------------------------------
void RivSurfacePartMgr::calculateVertexTextureCoordinates( cvf::Vec2fArray* textureCoords,
const std::vector<size_t>& vertexToCellIdxMap,
const RigResultAccessor* resultAccessor,
const cvf::ScalarMapper* mapper )
{
if ( !resultAccessor ) return;
size_t numVertices = vertexToCellIdxMap.size();
textureCoords->resize( numVertices );
cvf::Vec2f* rawPtr = textureCoords->ptr();
#pragma omp parallel for
for ( int vxIdx = 0; vxIdx < numVertices; vxIdx++ )
{
double cellScalarValue = resultAccessor->cellScalarGlobIdx( vertexToCellIdxMap[vxIdx] );
cvf::Vec2f texCoord = mapper->mapToTextureCoord( cellScalarValue );
if ( cellScalarValue == HUGE_VAL || cellScalarValue != cellScalarValue ) // a != a is true for NAN's
{
texCoord[1] = 1.0f;
}
rawPtr[vxIdx] = texCoord;
}
}

View File

@ -18,6 +18,7 @@
#pragma once
#include "cafPdmPointer.h"
#include "cvfArray.h"
#include "cvfObject.h"
namespace cvf
@ -31,20 +32,49 @@ class DrawableGeo;
class RimSurfaceInView;
class RigSurface;
class RigResultAccessor;
class RivSurfaceIntersectionGeometryGenerator;
class RivSurfacePartMgr : public cvf::Object
{
public:
explicit RivSurfacePartMgr( RimSurfaceInView* surface );
void applySingleColor();
void updateCellResultColor( size_t timeStepIndex );
void appendIntersectionGeometryPartsToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform );
void appendNativeGeometryPartsToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform );
private:
void generatePartGeometry();
void generateNativePartGeometry();
void generateNativeVertexToCellIndexMap();
static void calculateVertexTextureCoordinates( cvf::Vec2fArray* textureCoords,
const std::vector<size_t>& vertexToCellIdxMap,
const RigResultAccessor* resultAccessor,
const cvf::ScalarMapper* mapper );
cvf::ref<RivSurfaceIntersectionGeometryGenerator> m_intersectionGenerator;
caf::PdmPointer<RimSurfaceInView> m_surfaceInView;
cvf::ref<RigSurface> m_usedSurfaceData; // Store the reference to the old data, to know when new data has arrived.
cvf::ref<cvf::Part> m_nativeTrianglesPart;
cvf::ref<cvf::Part> m_nativeMeshLinesPart;
cvf::ref<cvf::Part> m_intersectionFaces;
cvf::ref<cvf::Part> m_intersectionGridLines;
cvf::ref<cvf::Part> m_intersectionFaultGridLines;
cvf::ref<cvf::Vec2fArray> m_intersectionFacesTextureCoords;
std::vector<size_t> m_nativeVertexToCellIndexMap;
};
class RivReservoirSurfaceGeometryGenerator : public cvf::Object
{
};

View File

@ -544,7 +544,7 @@ void Rim2dIntersectionView::onCreateDisplayModel()
m_intersectionVizModel->removeAllParts();
m_flatIntersectionPartMgr->appendNativeIntersectionFacesToModel( m_intersectionVizModel.p(), scaleTransform() );
m_flatIntersectionPartMgr->appendIntersectionFacesToModel( m_intersectionVizModel.p(), scaleTransform() );
m_flatIntersectionPartMgr->appendMeshLinePartsToModel( m_intersectionVizModel.p(), scaleTransform() );
m_flatIntersectionPartMgr->appendPolylinePartsToModel( *this, m_intersectionVizModel.p(), scaleTransform() );

View File

@ -55,6 +55,8 @@ RimBoxIntersection::RimBoxIntersection()
{
CAF_PDM_InitObject( "Intersection Box", ":/IntersectionBox16x16.png", "", "" );
CAF_PDM_InitField( &m_name, "UserDescription", QString( "Intersection Name" ), "Name", "", "", "" );
CAF_PDM_InitField( &m_singlePlaneState,
"singlePlaneState",
caf::AppEnum<SinglePlaneState>( SinglePlaneState::PLANE_STATE_NONE ),
@ -100,6 +102,30 @@ RimBoxIntersection::~RimBoxIntersection()
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimBoxIntersection::userDescriptionField()
{
return &m_name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimBoxIntersection::name() const
{
return m_name();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimBoxIntersection::setName( const QString& newName )
{
m_name = newName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -62,6 +62,9 @@ public:
RimBoxIntersection();
~RimBoxIntersection() override;
QString name() const override;
void setName( const QString& newName );
cvf::Mat4d boxOrigin() const;
cvf::Vec3d boxSize() const;
SinglePlaneState singlePlaneState() const;
@ -76,6 +79,8 @@ public:
void setToDefaultSizeSlice( SinglePlaneState plane, const cvf::Vec3d& position );
protected:
caf::PdmFieldHandle* userDescriptionField() override final;
void defineEditorAttribute( const caf::PdmFieldHandle* field,
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute ) override;
@ -105,6 +110,8 @@ private:
RiuViewer* viewer();
private:
caf::PdmField<QString> m_name;
caf::PdmField<caf::AppEnum<SinglePlaneState>> m_singlePlaneState;
caf::PdmField<double> m_minXCoord;

View File

@ -803,10 +803,11 @@ void RimEclipseView::updateVisibleGeometriesAndCellColors()
this->updateFaultColors();
m_intersectionCollection->updateCellResultColor( ( this->hasUserRequestedAnimation() &&
this->cellResult()->hasResult() ) ||
this->cellResult()->isTernarySaturationSelected(),
m_currentTimeStep );
bool hasGeneralCellResult = ( this->hasUserRequestedAnimation() && this->cellResult()->hasResult() ) ||
this->cellResult()->isTernarySaturationSelected();
m_intersectionCollection->updateCellResultColor( hasGeneralCellResult, m_currentTimeStep );
if ( m_surfaceCollection ) m_surfaceCollection->updateCellResultColor( hasGeneralCellResult, m_currentTimeStep );
}
//--------------------------------------------------------------------------------------------------
@ -890,6 +891,8 @@ void RimEclipseView::appendWellsAndFracturesToModel()
//--------------------------------------------------------------------------------------------------
void RimEclipseView::onLoadDataAndUpdate()
{
this->updateSurfacesInViewTreeItems();
onUpdateScaleTransform();
if ( m_eclipseCase )
@ -1738,6 +1741,8 @@ void RimEclipseView::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrderin
uiTreeOrdering.add( cellEdgeResult() );
uiTreeOrdering.add( faultResultSettings() );
uiTreeOrdering.add( &m_intersectionResultDefCollection );
uiTreeOrdering.add( &m_surfaceResultDefCollection );
uiTreeOrdering.add( wellCollection() );
uiTreeOrdering.add( &m_wellMeasurementCollection );

View File

@ -83,6 +83,7 @@ CAF_PDM_SOURCE_INIT( RimExtrudedCurveIntersection, "CrossSection" );
RimExtrudedCurveIntersection::RimExtrudedCurveIntersection()
{
CAF_PDM_InitObject( "Intersection", ":/CrossSection16x16.png", "", "" );
CAF_PDM_InitField( &m_name, "UserDescription", QString( "Intersection Name" ), "Name", "", "", "" );
CAF_PDM_InitFieldNoDefault( &type, "Type", "Type", "", "", "" );
CAF_PDM_InitFieldNoDefault( &direction, "Direction", "Direction", "", "", "" );
@ -139,6 +140,30 @@ RimExtrudedCurveIntersection::RimExtrudedCurveIntersection()
//--------------------------------------------------------------------------------------------------
RimExtrudedCurveIntersection::~RimExtrudedCurveIntersection() {}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimExtrudedCurveIntersection::userDescriptionField()
{
return &m_name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimExtrudedCurveIntersection::name() const
{
return m_name();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimExtrudedCurveIntersection::setName( const QString& newName )
{
m_name = newName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -81,6 +81,9 @@ public:
caf::PdmField<bool> inputExtrusionPointsFromViewerEnabled;
caf::PdmField<bool> inputTwoAzimuthPointsFromViewerEnabled;
QString name() const override;
void setName( const QString& newName );
std::vector<std::vector<cvf::Vec3d>> polyLines( cvf::Vec3d* flattenedPolylineStartPoint = nullptr ) const;
void appendPointToPolyLine( const cvf::Vec3d& point );
@ -106,6 +109,7 @@ public:
void rebuildGeometryAndScheduleCreateDisplayModel();
protected:
caf::PdmFieldHandle* userDescriptionField() override final;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField,
const QVariant& oldValue,
const QVariant& newValue ) override;
@ -117,6 +121,8 @@ protected:
bool* useOptionsOnly ) override;
private:
caf::PdmField<QString> m_name;
caf::PdmField<int> m_branchIndex;
caf::PdmField<double> m_extentLength;
caf::PdmField<double> m_azimuthAngle;

View File

@ -131,8 +131,11 @@ void RimGeoMechView::onLoadDataAndUpdate()
{
caf::ProgressInfo progress( 7, "" );
progress.setNextProgressIncrement( 5 );
onUpdateScaleTransform();
this->updateSurfacesInViewTreeItems();
if ( m_geomechCase )
{
std::string errorMessage;
@ -395,13 +398,20 @@ void RimGeoMechView::onUpdateDisplayModelForCurrentTimeStep()
else
m_vizLogic->updateStaticCellColors( m_currentTimeStep() );
m_intersectionCollection->updateCellResultColor( this->cellResult()->hasResult(), m_currentTimeStep );
bool hasGeneralCellResult = this->cellResult()->hasResult();
m_intersectionCollection->updateCellResultColor( hasGeneralCellResult, m_currentTimeStep );
if ( m_surfaceCollection )
{
m_surfaceCollection->updateCellResultColor( hasGeneralCellResult, m_currentTimeStep );
}
}
else
{
m_vizLogic->updateStaticCellColors( -1 );
m_intersectionCollection->updateCellResultColor( false, m_currentTimeStep );
if ( m_surfaceCollection ) m_surfaceCollection->updateCellResultColor( false, m_currentTimeStep );
nativeOrOverrideViewer()->animationControl()->slotPause(); // To avoid animation timer spinning in the background
}
@ -914,6 +924,7 @@ void RimGeoMechView::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrderin
uiTreeOrdering.add( cellResult() );
uiTreeOrdering.add( m_tensorResults() );
uiTreeOrdering.add( &m_intersectionResultDefCollection );
uiTreeOrdering.add( &m_surfaceResultDefCollection );
uiTreeOrdering.add( &m_wellMeasurementCollection );
uiTreeOrdering.add( m_intersectionCollection() );

View File

@ -87,6 +87,17 @@ RimGridView::RimGridView()
m_intersectionResultDefCollection.uiCapability()->setUiTreeHidden( true );
m_intersectionResultDefCollection = new RimIntersectionResultsDefinitionCollection;
CAF_PDM_InitFieldNoDefault( &m_surfaceResultDefCollection,
"ReservoirSurfaceResultDefColl",
"Separate Surface Results",
"",
"",
"" );
m_surfaceResultDefCollection.uiCapability()->setUiTreeHidden( true );
m_surfaceResultDefCollection = new RimIntersectionResultsDefinitionCollection;
m_surfaceResultDefCollection->uiCapability()->setUiName( "Separate Surface Results" );
m_surfaceResultDefCollection->uiCapability()->setUiIcon( caf::QIconProvider( ":/ReservoirSurface16x16.png" ) );
CAF_PDM_InitFieldNoDefault( &m_gridCollection, "GridCollection", "GridCollection", "", "", "" );
m_gridCollection.uiCapability()->setUiHidden( true );
m_gridCollection = new RimGridCollection();
@ -208,6 +219,14 @@ RimIntersectionResultsDefinitionCollection* RimGridView::separateIntersectionRes
return m_intersectionResultDefCollection;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimIntersectionResultsDefinitionCollection* RimGridView::separateSurfaceResultsCollection() const
{
return m_surfaceResultDefCollection;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -50,6 +50,7 @@ public:
RimIntersectionCollection* intersectionCollection() const;
RimSurfaceInViewCollection* surfaceInViewCollection() const;
RimIntersectionResultsDefinitionCollection* separateIntersectionResultsCollection() const;
RimIntersectionResultsDefinitionCollection* separateSurfaceResultsCollection() const;
RimAnnotationInViewCollection* annotationCollection() const;
RimWellMeasurementInViewCollection* measurementCollection() const;
@ -96,6 +97,7 @@ protected:
caf::PdmChildField<RimIntersectionCollection*> m_intersectionCollection;
caf::PdmChildField<RimIntersectionResultsDefinitionCollection*> m_intersectionResultDefCollection;
caf::PdmChildField<RimIntersectionResultsDefinitionCollection*> m_surfaceResultDefCollection;
caf::PdmChildField<Rim3dOverlayInfoConfig*> m_overlayInfoConfig;
caf::PdmChildField<RimCellRangeFilterCollection*> m_rangeFilterCollection;

View File

@ -31,14 +31,13 @@
#include "RimIntersectionResultsDefinitionCollection.h"
#include "RivHexGridIntersectionTools.h"
CAF_PDM_SOURCE_INIT( RimIntersection, "RimIntersectionHandle" );
CAF_PDM_ABSTRACT_SOURCE_INIT( RimIntersection, "RimIntersectionHandle" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimIntersection::RimIntersection()
{
CAF_PDM_InitField( &m_name, "UserDescription", QString( "Intersection Name" ), "Name", "", "", "" );
CAF_PDM_InitField( &m_isActive, "Active", true, "Active", "", "", "" );
m_isActive.uiCapability()->setUiHidden( true );
CAF_PDM_InitField( &m_showInactiveCells, "ShowInactiveCells", false, "Show Inactive Cells", "", "", "" );
@ -51,22 +50,6 @@ RimIntersection::RimIntersection()
//--------------------------------------------------------------------------------------------------
RimIntersection::~RimIntersection() {}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimIntersection::name() const
{
return m_name();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimIntersection::setName( const QString& newName )
{
m_name = newName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -104,10 +87,9 @@ RimIntersectionResultDefinition* RimIntersection::activeSeparateResultDefinition
if ( !m_separateDataSource->isActive() ) return nullptr;
RimGridView* view;
this->firstAncestorOrThisOfTypeAsserted( view );
if ( !findSeparateResultsCollection() ) return nullptr;
if ( !view->separateIntersectionResultsCollection()->isActive() ) return nullptr;
if ( !findSeparateResultsCollection()->isActive() ) return nullptr;
return m_separateDataSource;
}
@ -122,11 +104,8 @@ QList<caf::PdmOptionItemInfo> RimIntersection::calculateValueOptions( const caf:
if ( fieldNeedingOptions == &m_separateDataSource )
{
RimGridView* view;
this->firstAncestorOrThisOfTypeAsserted( view );
std::vector<RimIntersectionResultDefinition*> iResDefs =
view->separateIntersectionResultsCollection()->intersectionResultsDefinitions();
findSeparateResultsCollection()->intersectionResultsDefinitions();
for ( auto iresdef : iResDefs )
{
@ -140,9 +119,11 @@ QList<caf::PdmOptionItemInfo> RimIntersection::calculateValueOptions( const caf:
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimIntersection::userDescriptionField()
RimIntersectionResultsDefinitionCollection* RimIntersection::findSeparateResultsCollection()
{
return &m_name;
RimGridView* view;
this->firstAncestorOrThisOfTypeAsserted( view );
return view->separateIntersectionResultsCollection();
}
//--------------------------------------------------------------------------------------------------
@ -188,18 +169,12 @@ void RimIntersection::updateDefaultSeparateDataSource()
{
if ( m_separateDataSource() == nullptr )
{
RimGridView* view;
this->firstAncestorOrThisOfType( view );
std::vector<RimIntersectionResultDefinition*> iResDefs =
findSeparateResultsCollection()->intersectionResultsDefinitions();
if ( view )
if ( iResDefs.size() )
{
std::vector<RimIntersectionResultDefinition*> iResDefs =
view->separateIntersectionResultsCollection()->intersectionResultsDefinitions();
if ( iResDefs.size() )
{
m_separateDataSource = iResDefs[0];
}
m_separateDataSource = iResDefs[0];
}
}
}

View File

@ -26,6 +26,7 @@
class RimIntersectionResultDefinition;
class RivIntersectionHexGridInterface;
class RimIntersectionResultsDefinitionCollection;
class RimIntersection : public caf::PdmObject
{
@ -35,17 +36,18 @@ public:
RimIntersection();
~RimIntersection() override;
QString name() const;
void setName( const QString& newName );
bool isActive() const;
void setActive( bool isActive );
bool isInactiveCellsVisible() const;
virtual QString name() const = 0;
bool isActive() const;
void setActive( bool isActive );
bool isInactiveCellsVisible() const;
RimIntersectionResultDefinition* activeSeparateResultDefinition();
cvf::ref<RivIntersectionHexGridInterface> createHexGridInterface();
protected:
caf::PdmFieldHandle* userDescriptionField() override final;
virtual RimIntersectionResultsDefinitionCollection* findSeparateResultsCollection();
caf::PdmFieldHandle* objectToggleField() override final;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions,
bool* useOptionsOnly ) override;
@ -54,7 +56,6 @@ protected:
void defineSeparateDataSourceUi( QString uiConfigName, caf::PdmUiOrdering& uiOrdering );
void updateDefaultSeparateDataSource();
caf::PdmField<QString> m_name;
caf::PdmField<bool> m_isActive;
caf::PdmField<bool> m_showInactiveCells;
caf::PdmField<bool> m_useSeparateDataSource;

View File

@ -150,7 +150,7 @@ void RimIntersectionCollection::appendPartsToModel( Rim3dView& view,
{
if ( cs->isActive() )
{
cs->intersectionPartMgr()->appendNativeIntersectionFacesToModel( model, scaleTransform );
cs->intersectionPartMgr()->appendIntersectionFacesToModel( model, scaleTransform );
cs->intersectionPartMgr()->appendMeshLinePartsToModel( model, scaleTransform );
cs->intersectionPartMgr()->appendPolylinePartsToModel( view, model, scaleTransform );
}

View File

@ -21,6 +21,10 @@
#include "RimGridView.h"
#include "RimSurface.h"
#include "RigFemPartCollection.h"
#include "RimEclipseView.h"
#include "RimGeoMechView.h"
#include "RivHexGridIntersectionTools.h"
#include "RivSurfacePartMgr.h"
CAF_PDM_SOURCE_INIT( RimSurfaceInView, "SurfaceInView" );
@ -32,11 +36,9 @@ RimSurfaceInView::RimSurfaceInView()
{
CAF_PDM_InitObject( "Surface", ":/ReservoirSurface16x16.png", "", "" );
CAF_PDM_InitField( &m_isActive, "IsActive", true, "Visible", "", "", "" );
m_isActive.uiCapability()->setUiHidden( true );
CAF_PDM_InitFieldNoDefault( &m_name, "Name", "Name", "", "", "" );
m_name.registerGetMethod( this, &RimSurfaceInView::name );
m_name.uiCapability()->setUiReadOnly( true );
CAF_PDM_InitFieldNoDefault( &m_surface, "SurfaceRef", "Surface", "", "", "" );
m_surface.uiCapability()->setUiHidden( true );
@ -57,11 +59,6 @@ QString RimSurfaceInView::name() const
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSurfaceInView::loadDataAndUpdate() {}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -78,14 +75,6 @@ void RimSurfaceInView::setSurface( RimSurface* surf )
m_surface = surf;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSurfaceInView::isActive()
{
return m_isActive();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -117,6 +106,37 @@ void RimSurfaceInView::fieldChangedByUi( const caf::PdmFieldHandle* changedField
this->firstAncestorOrThisOfTypeAsserted( ownerView );
ownerView->scheduleCreateDisplayModelAndRedraw();
}
else if ( changedField == &m_showInactiveCells )
{
m_surfacePartMgr = nullptr;
RimGridView* ownerView;
this->firstAncestorOrThisOfTypeAsserted( ownerView );
ownerView->scheduleCreateDisplayModelAndRedraw();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSurfaceInView::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_name );
uiOrdering.add( &m_showInactiveCells );
this->defineSeparateDataSourceUi( uiConfigName, uiOrdering );
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimIntersectionResultsDefinitionCollection* RimSurfaceInView::findSeparateResultsCollection()
{
RimGridView* view;
this->firstAncestorOrThisOfTypeAsserted( view );
return view->separateSurfaceResultsCollection();
}
//--------------------------------------------------------------------------------------------------
@ -126,11 +146,3 @@ caf::PdmFieldHandle* RimSurfaceInView::userDescriptionField()
{
return &m_name;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmFieldHandle* RimSurfaceInView::objectToggleField()
{
return &m_isActive;
}

View File

@ -24,10 +24,14 @@
#include "cvfObject.h"
class RimSurface;
class RivSurfacePartMgr;
#include "RimIntersection.h"
class RimSurfaceInView : public caf::PdmObject
class RimSurface;
class RivSurfacePartMgr;
class RivIntersectionHexGridInterface;
class RimSurfaceInView : public RimIntersection
{
CAF_PDM_HEADER_INIT;
@ -35,25 +39,23 @@ public:
RimSurfaceInView();
~RimSurfaceInView() override;
void loadDataAndUpdate();
QString name() const;
QString name() const override;
RimSurface* surface() const;
void setSurface( RimSurface* surf );
bool isActive();
void clearGeometry();
RivSurfacePartMgr* surfacePartMgr();
private:
virtual RimIntersectionResultsDefinitionCollection* findSeparateResultsCollection() override;
caf::PdmFieldHandle* userDescriptionField() override;
caf::PdmFieldHandle* objectToggleField() override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField,
const QVariant& oldValue,
const QVariant& newValue ) override;
virtual void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
caf::PdmProxyValueField<QString> m_name;
caf::PdmField<bool> m_isActive;
caf::PdmPtrField<RimSurface*> m_surface;
cvf::ref<RivSurfacePartMgr> m_surfacePartMgr;

View File

@ -102,7 +102,8 @@ void RimSurfaceInViewCollection::appendPartsToModel( cvf::ModelBasicList* model,
{
if ( surf->isActive() )
{
surf->surfacePartMgr()->appendNativeGeometryPartsToModel( model, scaleTransform );
// surf->surfacePartMgr()->appendNativeGeometryPartsToModel( model, scaleTransform );
surf->surfacePartMgr()->appendIntersectionGeometryPartsToModel( model, scaleTransform );
}
}
@ -147,3 +148,28 @@ caf::PdmFieldHandle* RimSurfaceInViewCollection::objectToggleField()
{
return &m_isActive;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSurfaceInViewCollection::updateCellResultColor( bool hasGeneralCellResult, size_t timeStepIndex )
{
if ( !this->m_isActive() ) return;
for ( RimSurfaceInView* surf : m_surfacesInView )
{
if ( surf->isActive() )
{
bool hasSeparateInterResult = false; // surf->activeSeparateResultDefinition() &&
// surf->activeSeparateResultDefinition()->hasResult();
if ( hasSeparateInterResult || hasGeneralCellResult )
{
surf->surfacePartMgr()->updateCellResultColor( timeStepIndex );
}
else
{
surf->surfacePartMgr()->applySingleColor();
}
}
}
}

View File

@ -42,6 +42,7 @@ public:
void updateFromSurfaceCollection();
void appendPartsToModel( cvf::ModelBasicList* surfaceVizModel, cvf::Transform* scaleTransform );
void updateCellResultColor( bool hasGeneralCellResult, size_t timeStepIndex );
private:
caf::PdmFieldHandle* objectToggleField() override;

View File

@ -525,3 +525,137 @@ TEST( RigWellPathStimplanIntersector, intersection )
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Test of whether we can transport edge information trough clipper clipping
// Seems as if it might be possible, but clipper will ignore the edge information
// processed by the callback if one of the edges is horizontal
//
#include "clipper/clipper.hpp"
double clipperConversionFactor2 = 10000; // For transform to clipper int
ClipperLib::IntPoint toClipperEdgePoint( const cvf::Vec3d& cvfPoint )
{
int xInt = cvfPoint.x() * clipperConversionFactor2;
int yInt = cvfPoint.y() * clipperConversionFactor2;
int zInt = cvfPoint.z();
return ClipperLib::IntPoint( xInt, yInt, zInt );
}
cvf::Vec3d fromClipperEdgePoint( const ClipperLib::IntPoint& clipPoint )
{
double zDValue;
if ( clipPoint.Z == std::numeric_limits<int>::max() )
{
zDValue = HUGE_VAL;
}
else
{
zDValue = clipPoint.Z;
}
return cvf::Vec3d( clipPoint.X / clipperConversionFactor2, clipPoint.Y / clipperConversionFactor2, zDValue );
}
void swapPointsIfNeedeed( ClipperLib::IntPoint*& p1, ClipperLib::IntPoint*& p2 )
{
if ( p1->Z > p2->Z )
{
std::swap( p1, p2 );
}
if ( ( p2->Z - p1->Z ) > 1 ) // End edge of polygon
{
std::swap( p1, p2 ); // Swap back
}
}
void clipperEdgeIntersectCallback( ClipperLib::IntPoint& e1bot,
ClipperLib::IntPoint& e1top,
ClipperLib::IntPoint& e2bot,
ClipperLib::IntPoint& e2top,
ClipperLib::IntPoint& pt )
{
ClipperLib::IntPoint* e11 = &e1bot;
ClipperLib::IntPoint* e12 = &e1top;
ClipperLib::IntPoint* e21 = &e2bot;
ClipperLib::IntPoint* e22 = &e2top;
swapPointsIfNeedeed( e11, e12 );
swapPointsIfNeedeed( e21, e22 );
cvf::Vec3f e1( e12->X - e11->X, e12->Y - e11->Y, 0.0 );
cvf::Vec3f e2( e22->X - e21->X, e22->Y - e21->Y, 0.0 );
cvf::Vec3f up = e1 ^ e2;
if ( up.z() > 0 )
{
pt.Z = e12->Z;
std::cout << "E1 :" << e11->Z << " " << e12->Z << std::endl;
std::cout << "E2 :" << e21->Z << " " << e22->Z << std::endl << std::endl;
}
else
{
pt.Z = e22->Z;
std::cout << "E1 :" << e21->Z << " " << e22->Z << std::endl;
std::cout << "E2 :" << e11->Z << " " << e12->Z << std::endl << std::endl;
}
}
TEST( RigCellGeometryTools, ClipperEdgeTracking )
{
// If the first edges of the polygons are horizontal, the edge tracking will fail.
// Encode polygon and edge into Z coordinate of the vertex
std::vector<cvf::Vec3d> polygon1 = {{0.0, 0.51, 1002.0}, {1.0, 0.5, 1000.0}, {0.0, 1.0, 1001.0}};
std::vector<cvf::Vec3d> polygon2 = {{0.5, 0.01, 2002.0}, {1.0, 0.0, 2000.0}, {0.5, 1.0, 2001.0}};
std::vector<std::vector<cvf::Vec3d>> clippedPolygons;
// Convert to int for clipper library and store as clipper "path"
ClipperLib::Path polygon1path;
for ( const cvf::Vec3d& v : polygon1 )
{
polygon1path.push_back( toClipperEdgePoint( v ) );
}
ClipperLib::Path polygon2path;
for ( const cvf::Vec3d& v : polygon2 )
{
polygon2path.push_back( toClipperEdgePoint( v ) );
}
ClipperLib::Clipper clpr;
clpr.AddPath( polygon1path, ClipperLib::ptSubject, true );
clpr.AddPath( polygon2path, ClipperLib::ptClip, true );
clpr.ZFillFunction( &clipperEdgeIntersectCallback );
ClipperLib::Paths solution;
clpr.Execute( ClipperLib::ctIntersection, solution, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd );
// Convert back to std::vector<std::vector<cvf::Vec3d> >
for ( ClipperLib::Path pathInSol : solution )
{
std::vector<cvf::Vec3d> clippedPolygon;
for ( ClipperLib::IntPoint IntPosition : pathInSol )
{
clippedPolygon.push_back( fromClipperEdgePoint( IntPosition ) );
}
clippedPolygons.push_back( clippedPolygon );
}
int pIdx = 1;
for ( auto& polygon : clippedPolygons )
{
std::cout << "Polygon: " << pIdx << std::endl;
for ( auto& point : polygon )
{
std::cout << " [ " << point[0] << ", " << point[1] << ", " << point[2] << " ]" << std::endl;
}
pIdx++;
}
}

View File

@ -381,6 +381,7 @@ set_property(TARGET cafCommandFeatures PROPERTY FOLDER "AppFwk")
#add_subdirectory(Fwk/AppFwk/cafTests/cafTestCvfApplication)
add_subdirectory(Fwk/AppFwk/cafTensor)
add_subdirectory(Fwk/AppFwk/cafHexInterpolator)
list(APPEND APP_FWK_LIBRARIES
cafPdmCore
@ -401,6 +402,7 @@ list(APPEND APP_FWK_LIBRARIES
set_property(TARGET
${APP_FWK_LIBRARIES}
cafHexInterpolator
PROPERTY FOLDER "AppFwk"
)

View File

@ -0,0 +1,21 @@
cmake_minimum_required (VERSION 2.8.12)
project (cafHexInterpolator)
set( PROJECT_FILES
cafHexInterpolator.h
)
add_library( ${PROJECT_NAME}
${PROJECT_FILES}
)
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries( ${PROJECT_NAME} LibCore )
source_group("" FILES ${PROJECT_FILES})

View File

@ -0,0 +1,381 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) Ceetron Solutions AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library 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.
//
// This library 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 <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
/*
Interpolating inside a general 8 node hexahedral element
Calculating an interpolated value at a position inside the element from values at each corner.
Author Jacob Støren
| v1 |
Vectors: [v] = | v2 | = { v1, v2, v3 }
| v3 |
the {} means that the elment list are a standing vector, but written as a row for convenience
[] means matrix or vector quantity
// HEX8
// 7---------6
// /| /| |k, z,
// / | / | | /j, y
// 4---------5 | |/
// | 3------|--2 *---i, x,
// | / | /
// |/ |/
// 0---------1
Normalized coordinates i, j, k
Normalized origo in center of element
Normalized cell corners NCn in :
[NC0] = {-1,-1,-1}
[NC1] = { 1,-1,-1}
[NC2] = { 1, 1,-1}
[NC3] = {-1, 1,-1}
[NC4] = {-1,-1, 1}
[NC5] = { 1,-1, 1}
[NC6] = { 1, 1, 1}
[NC7] = {-1, 1, 1}
Thus Interpolation polynomials (follows sign of corner position) Nn =
N0 = 1/8 *(1-i)(1-j)(1-k) = 1/8 * ( 1 - i - j - k + ij + ik + jk - ijk )
N1 = 1/8 *(1+i)(1-j)(1-k) = 1/8 * ( 1 + i - j - k - ij - ik + jk + ijk )
N2 = 1/8 *(1+i)(1+j)(1-k) = 1/8 * ( 1 + i + j - k + ij - ik - jk - ijk )
N3 = 1/8 *(1-i)(1+j)(1-k) = 1/8 * ( 1 - i + j - k - ij + ik - jk + ijk )
N4 = 1/8 *(1-i)(1-j)(1+k) = 1/8 * ( 1 - i - j + k + ij - ik - jk + ijk )
N5 = 1/8 *(1+i)(1-j)(1+k) = 1/8 * ( 1 + i - j + k - ij + ik - jk - ijk )
N6 = 1/8 *(1+i)(1+j)(1+k) = 1/8 * ( 1 + i + j + k + ij + ik + jk + ijk )
N7 = 1/8 *(1-i)(1+j)(1+k) = 1/8 * ( 1 - i + j + k - ij - ik + jk - ijk )
To calculate an interpolated value R at position { i, j, k } from values Vn in each corner of the cell
we use i,j,k to calculate all Nn, and then :
R = sum_n(Nn * Vn)
A point [P] = {x,y,z} inside a general element can then be calculated by the {i,j,k} coordinates correponding to the point and the corner positions Cn = {Cx_n, Cy_n, Cz_n} (n = 0..7) of the general hex as:
x = sum_n(Nn * Cn_x)
y = sum_n(Nn * Cn_y)
z = sum_n(Nn * Cn_z)
If we define
[Cn] = | [C0] ... [C7] |
Where
| Cx_0 | | Cx_7 |
[C0] = | Cy_0 |, ... , [C7] = | Cy_7 |
| Cz_0 | | Cz_7 |
And
| N0 |
[Nn] = | .. |
| N7 |
it can be written
[P] = [Cn]*[Nn]
As seen, we need to know the { i, j, k} position of the point. This can only be calculated using some sort of iterative solution, eg. Newton-Rapson.
Using m as iteration number we can use { im, jm, km } to evaluate [Nn] and name it [Nnm].
We use an initial guess of {im,jm,km} = { 0.5, 0.5, 0.5} // But why ? the element origo is at 0,0,0 !
[Pm] = {xm, ym, zm} = sum_n(Nnm * Cn_x), sum_n(Nnm * Cn_y), sum_n(Nnm * Cn_z) } When using im,jm,km to evaluate Nnm
P is the position we want to calculate i,j,k for.
So our function to solve for roots become F = Pm - P = 0
Then multidimensional Newton-Rapson says:
{im, jm, km}_new = {im,jm,km} - [J-1]_m * ( [Pm] - [P] ) }
Where [J-1] is the inverse Jacobian giving the change in i,j,k when varying x,y,z (The partial derivatives)
The Jacobian is the partially derived x, y, z with respect to i, j, k as follows:
( The organization of the Jacobi is not quite concistent in the litterature.
It seems as if NTNU uses the following, while others use the Transpose.
(Seems as if the correct one to use in the newton-rapson iteration is the transpose of the following: )
| dx/di dy/di dz/di |
J = | dx/dj dy/dj dz/dj |
| dx/dk dy/dk dz/dk |
The partial derivatives are calculated by deriving the function [F(i,j,k)] = [Pm(i,j,k)] - [P]
Since [P] is constant, this is the same as deriving [Pm(i,j,k)] = [Cn]*[Nnm]
Explicitly:
|xm| | N0m*C0_x + ... + N7m*C7_x |
[Pm] = |ym| = | N0m*C0_y + ... + N7m*C7_y |
|zm| | N0m*C0_z + ... + N7m*C7_z |
In the following we remove the iteration index m for simplicity
The elements of the Jacobi can be calculated by partially deriving the polynomials for each of the components x, y, z
dx/di = (dN0/di)*C0_x + ... + (dN7/di)*C7_x
dx/dj = (dN0/dj)*C0_x + ... + (dN7/dj)*C7_x
dx/dk = (dN0/dk)*C0_x + ... + (dN7/dk)*C7_x
dy/di = (dN0/di)*C0_y + ... + (dN7/di)*C7_y
dy/dj = (dN0/dj)*C0_y + ... + (dN7/dj)*C7_y
dy/dk = (dN0/dk)*C0_y + ... + (dN7/dk)*C7_y
dz/di = (dN0/di)*C0_z + ... + (dN7/di)*C7_z
dz/dj = (dN0/dj)*C0_z + ... + (dN7/dj)*C7_z
dz/dk = (dN0/dk)*C0_z + ... + (dN7/dk)*C7_z
Which can be written in more compact form:
| dx/di |
| dy/di | = [Cn]*[dNn/di]
| dz/di |
, etc.
And in detail every partial derivative of the polynomials:
dN0/di = 1/8 * ( - 1 + j + k - jk )
dN1/di = 1/8 * ( + 1 - j - k + jk )
dN2/di = 1/8 * ( + i + j - k - jk )
dN3/di = 1/8 * ( - 1 - j + k + jk )
dN4/di = 1/8 * ( - 1 + j - k + jk )
dN5/di = 1/8 * ( + 1 - j + k - jk )
dN6/di = 1/8 * ( + 1 + j + k + jk )
dN7/di = 1/8 * ( - 1 - j - k - jk )
dN0/dj = 1/8 * ( - 1 + i + k - ik )
dN1/dj = 1/8 * ( - 1 - i + k + ik )
dN2/dj = 1/8 * ( + 1 + i - k - ik )
dN3/dj = 1/8 * ( + 1 - i - k + ik )
dN4/dj = 1/8 * ( - 1 + i - k + ik )
dN5/dj = 1/8 * ( - 1 - i - k - ik )
dN6/dj = 1/8 * ( + 1 + i + k + ik )
dN7/dj = 1/8 * ( + 1 - i + k - ik )
dN0/dk = 1/8 * ( - 1 + i + j - ij )
dN1/dk = 1/8 * ( - 1 - i + j + ij )
dN2/dk = 1/8 * ( - 1 - i - j - ij )
dN3/dk = 1/8 * ( - 1 + i - j + ij )
dN4/dk = 1/8 * ( + 1 - i - j + ij )
dN5/dk = 1/8 * ( + 1 + i - j - ij )
dN6/dk = 1/8 * ( + 1 + i + j + ij )
dN7/dk = 1/8 * ( + 1 - i + j - ij )
The inverse Jacobian can be calculated by inverting the resulting Jacobian matrix for a specifically chosen set of i,j,k
*/
#include "cvfVector3.h"
#include "cvfMatrix3.h"
#include <array>
namespace caf {
class HexInterpolator
{
public:
static double interpolateHex(const std::array<cvf::Vec3d, 8>& hexCorners,
const std::array<double, 8>& values,
const cvf::Vec3d& point)
{
cvf::Vec3d pointInNormElm = findNormalizedCoords(hexCorners, point);
return interpolateInNormElm( pointInNormElm, values);
}
static std::array<double, 8> vertexWeights(const std::array<cvf::Vec3d, 8>& hexCorners,
const cvf::Vec3d& point )
{
cvf::Vec3d pointInNormElm = findNormalizedCoords(hexCorners, point);
return interpolationCoeffs(pointInNormElm);
}
private:
static double interpolateInNormElm( const cvf::Vec3d & pointInNormElm, const std::array<double, 8>& values)
{
std::array<double, 8> Ni = interpolationCoeffs(pointInNormElm);
double result = 0.0;
for (int i = 0 ; i < 8 ; ++i )
{
result += values[i]*Ni[i];
}
return result;
}
static cvf::Vec3d interpolateInNormElm( const cvf::Vec3d & pointInNormElm, const std::array<cvf::Vec3d, 8>& values)
{
std::array<double, 8> Ni = interpolationCoeffs(pointInNormElm);
cvf::Vec3d result(cvf::Vec3d::ZERO);
for (int i = 0 ; i < 8 ; ++i )
{
result += values[i]*Ni[i];
}
return result;
}
static std::array<double, 8> interpolationCoeffs( const cvf::Vec3d & pointInNormalizedElement)
{
const double k_1_8 = 0.125;
double i = pointInNormalizedElement[0];
double j = pointInNormalizedElement[1];
double k = pointInNormalizedElement[2];
// could use as optimization ... >> double oni = 1 - i;
// could use as optimization ... >> double opi = 1 + i;
// could use as optimization ... >> double onj = 1 - j;
// could use as optimization ... >> double opj = 1 + j;
// could use as optimization ... >> double onk = 1 - k;
// could use as optimization ... >> double opk = 1 + k;
return {
k_1_8 *(1-i)*(1-j)*(1-k),
k_1_8 *(1+i)*(1-j)*(1-k),
k_1_8 *(1+i)*(1+j)*(1-k),
k_1_8 *(1-i)*(1+j)*(1-k),
k_1_8 *(1-i)*(1-j)*(1+k),
k_1_8 *(1+i)*(1-j)*(1+k),
k_1_8 *(1+i)*(1+j)*(1+k),
k_1_8 *(1-i)*(1+j)*(1+k)
};
}
static cvf::Vec3d findNormalizedCoords(const std::array<cvf::Vec3d, 8>& hexCorners, const cvf::Vec3d& P)
{
cvf::Vec3d normPoint = {0.0, 0.0, 0.0}; // Start value
int m = 0;
while ( m < 5 )
{
cvf::Vec3d Pm = interpolateInNormElm(normPoint, hexCorners);
cvf::Vec3d Pdiff = Pm - P;
cvf::Mat3d J_inv = jacobi(hexCorners, normPoint) ;
bool inversionOk = J_inv.invert();
if ( !inversionOk ) break;
cvf::Vec3d ijkStep = Pdiff.getTransformedVector(J_inv);
normPoint = normPoint - ijkStep;
m++;
}
return normPoint;
}
static cvf::Mat3d jacobi(const std::array<cvf::Vec3d, 8>& hexCorners, const cvf::Vec3d & pointInNormalizedElement)
{
const double k_1_8 = 0.125;
double i = pointInNormalizedElement[0];
double j = pointInNormalizedElement[1];
double k = pointInNormalizedElement[2];
double ij = i*j;
double ik = i*k;
double jk = j*k;
double C0_x = hexCorners[0][0]; double C0_y = hexCorners[0][1]; double C0_z = hexCorners[0][2];
double C1_x = hexCorners[1][0]; double C1_y = hexCorners[1][1]; double C1_z = hexCorners[1][2];
double C2_x = hexCorners[2][0]; double C2_y = hexCorners[2][1]; double C2_z = hexCorners[2][2];
double C3_x = hexCorners[3][0]; double C3_y = hexCorners[3][1]; double C3_z = hexCorners[3][2];
double C4_x = hexCorners[4][0]; double C4_y = hexCorners[4][1]; double C4_z = hexCorners[4][2];
double C5_x = hexCorners[5][0]; double C5_y = hexCorners[5][1]; double C5_z = hexCorners[5][2];
double C6_x = hexCorners[6][0]; double C6_y = hexCorners[6][1]; double C6_z = hexCorners[6][2];
double C7_x = hexCorners[7][0]; double C7_y = hexCorners[7][1]; double C7_z = hexCorners[7][2];
double dN0_di = k_1_8 * (- 1 + j + k - jk);
double dN1_di = k_1_8 * (+ 1 - j - k + jk);
double dN2_di = k_1_8 * (+ 1 + j - k - jk);
double dN3_di = k_1_8 * (- 1 - j + k + jk);
double dN4_di = k_1_8 * (- 1 + j - k + jk);
double dN5_di = k_1_8 * (+ 1 - j + k - jk);
double dN6_di = k_1_8 * (+ 1 + j + k + jk);
double dN7_di = k_1_8 * (- 1 - j - k - jk);
double dN0_dj = k_1_8 * (- 1 + i + k - ik);
double dN1_dj = k_1_8 * (- 1 - i + k + ik);
double dN2_dj = k_1_8 * (+ 1 + i - k - ik);
double dN3_dj = k_1_8 * (+ 1 - i - k + ik);
double dN4_dj = k_1_8 * (- 1 + i - k + ik);
double dN5_dj = k_1_8 * (- 1 - i - k - ik);
double dN6_dj = k_1_8 * (+ 1 + i + k + ik);
double dN7_dj = k_1_8 * (+ 1 - i + k - ik);
double dN0_dk = k_1_8 * (- 1 + i + j - ij);
double dN1_dk = k_1_8 * (- 1 - i + j + ij);
double dN2_dk = k_1_8 * (- 1 - i - j - ij);
double dN3_dk = k_1_8 * (- 1 + i - j + ij);
double dN4_dk = k_1_8 * (+ 1 - i - j + ij);
double dN5_dk = k_1_8 * (+ 1 + i - j - ij);
double dN6_dk = k_1_8 * (+ 1 + i + j + ij);
double dN7_dk = k_1_8 * (+ 1 - i + j - ij);
double dx_di = (dN0_di) * C0_x + (dN1_di) * C1_x + (dN2_di) * C2_x + (dN3_di) * C3_x + (dN4_di) * C4_x + (dN5_di) * C5_x + (dN6_di) * C6_x + (dN7_di) * C7_x;
double dx_dj = (dN0_dj) * C0_x + (dN1_dj) * C1_x + (dN2_dj) * C2_x + (dN3_dj) * C3_x + (dN4_dj) * C4_x + (dN5_dj) * C5_x + (dN6_dj) * C6_x + (dN7_dj) * C7_x;
double dx_dk = (dN0_dk) * C0_x + (dN1_dk) * C1_x + (dN2_dk) * C2_x + (dN3_dk) * C3_x + (dN4_dk) * C4_x + (dN5_dk) * C5_x + (dN6_dk) * C6_x + (dN7_dk) * C7_x;
double dy_di = (dN0_di) * C0_y + (dN1_di) * C1_y + (dN2_di) * C2_y + (dN3_di) * C3_y + (dN4_di) * C4_y + (dN5_di) * C5_y + (dN6_di) * C6_y + (dN7_di) * C7_y;
double dy_dj = (dN0_dj) * C0_y + (dN1_dj) * C1_y + (dN2_dj) * C2_y + (dN3_dj) * C3_y + (dN4_dj) * C4_y + (dN5_dj) * C5_y + (dN6_dj) * C6_y + (dN7_dj) * C7_y;
double dy_dk = (dN0_dk) * C0_y + (dN1_dk) * C1_y + (dN2_dk) * C2_y + (dN3_dk) * C3_y + (dN4_dk) * C4_y + (dN5_dk) * C5_y + (dN6_dk) * C6_y + (dN7_dk) * C7_y;
double dz_di = (dN0_di) * C0_z + (dN1_di) * C1_z + (dN2_di) * C2_z + (dN3_di) * C3_z + (dN4_di) * C4_z + (dN5_di) * C5_z + (dN6_di) * C6_z + (dN7_di) * C7_z;
double dz_dj = (dN0_dj) * C0_z + (dN1_dj) * C1_z + (dN2_dj) * C2_z + (dN3_dj) * C3_z + (dN4_dj) * C4_z + (dN5_dj) * C5_z + (dN6_dj) * C6_z + (dN7_dj) * C7_z;
double dz_dk = (dN0_dk) * C0_z + (dN1_dk) * C1_z + (dN2_dk) * C2_z + (dN3_dk) * C3_z + (dN4_dk) * C4_z + (dN5_dk) * C5_z + (dN6_dk) * C6_z + (dN7_dk) * C7_z;
// Do not know which ordering ends up as correct
#if 1 // Use literature jacobi ordering
return cvf::Mat3d(
dx_di, dx_dj, dx_dk,
dy_di, dy_dj, dy_dk,
dz_di, dz_dj, dz_dk
);
#else // use NTNU ordering
return cvf::Mat3d(
dx_di, dy_di, dz_di,
dx_dj, dy_dj, dz_dj,
dx_dk, dy_dk, dz_dk
);
#endif
}
};
}

View File

@ -0,0 +1,34 @@
cmake_minimum_required (VERSION 2.8.12)
project ( cafHexInterpolator_UnitTests )
if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11))
# VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1
add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
message(STATUS "Add flag to disable warings from gtest - _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING")
endif()
set (VIZ_MODULES_FOLDER_NAME ../../../../Fwk/VizFwk)
add_subdirectory(${VIZ_MODULES_FOLDER_NAME}/LibCore LibCoreDir})
include_directories (
${CMAKE_CURRENT_SOURCE_DIR} # required for gtest-all.cpp
)
set( PROJECT_FILES
cafHexInterpolatorBasicTest.cpp
cafHexInterpolator_UnitTests_main.cpp
)
# add the executable
add_executable (${PROJECT_NAME}
${PROJECT_FILES}
gtest/gtest-all.cpp
)
target_link_libraries ( ${PROJECT_NAME}
LibCore
)
source_group("" FILES ${PROJECT_FILES})

View File

@ -0,0 +1,331 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) Ceetron Solutions AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library 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.
//
// This library 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 <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#include <iostream>
#include "gtest/gtest.h"
#include "../cafHexInterpolator.h"
#include "cvfMatrix4.h"
namespace caf {
class HexInterpolatorTester
{
};
}
void testHex(const std::array<cvf::Vec3d, 8>& hexCorners, double tolerance = 1e-6)
{
double result = 0.0;
result = caf::HexInterpolator::interpolateHex(hexCorners, {0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0 }, hexCorners[0]);
EXPECT_NEAR(result, 0.0, tolerance);
result = caf::HexInterpolator::interpolateHex(hexCorners, {0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0 }, hexCorners[1]);
EXPECT_NEAR(result, 1.0, tolerance);
result = caf::HexInterpolator::interpolateHex(hexCorners, {0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0 }, hexCorners[2]);
EXPECT_NEAR(result, 2.0, tolerance);
result = caf::HexInterpolator::interpolateHex(hexCorners, {0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0 }, hexCorners[3]);
EXPECT_NEAR(result, 3.0, tolerance);
result = caf::HexInterpolator::interpolateHex(hexCorners, {0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0 }, hexCorners[4]);
EXPECT_NEAR(result, 4.0, tolerance);
result = caf::HexInterpolator::interpolateHex(hexCorners, {0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0 }, hexCorners[5]);
EXPECT_NEAR(result, 5.0, tolerance);
result = caf::HexInterpolator::interpolateHex(hexCorners, {0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0 }, hexCorners[6]);
EXPECT_NEAR(result, 6.0, tolerance);
result = caf::HexInterpolator::interpolateHex(hexCorners, {0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0 }, hexCorners[7]);
EXPECT_NEAR(result, 7.0, tolerance);
cvf::Vec3d avg = cvf::Vec3d::ZERO;
for ( const auto & v : hexCorners) avg += v;
avg *= 0.125;
result = caf::HexInterpolator::interpolateHex(hexCorners, {0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0 }, avg);
EXPECT_NEAR(result, 3.5, tolerance);
}
TEST(InterpolationTest, UnitElement)
{
// Identity element
std::array<cvf::Vec3d, 8> hexCorners = {
cvf::Vec3d(-1.0,-1.0,-1.0),
cvf::Vec3d( 1.0,-1.0,-1.0),
cvf::Vec3d( 1.0, 1.0,-1.0),
cvf::Vec3d(-1.0, 1.0,-1.0),
cvf::Vec3d(-1.0,-1.0, 1.0),
cvf::Vec3d( 1.0,-1.0, 1.0),
cvf::Vec3d( 1.0, 1.0, 1.0),
cvf::Vec3d(-1.0, 1.0, 1.0)
};
testHex(hexCorners);
}
TEST(InterpolationTest, ScaledElement)
{
// Identity element
std::array<cvf::Vec3d, 8> hexCorners = {
cvf::Vec3d(-1.0,-1.0,-1.0),
cvf::Vec3d( 1.0,-1.0,-1.0),
cvf::Vec3d( 1.0, 1.0,-1.0),
cvf::Vec3d(-1.0, 1.0,-1.0),
cvf::Vec3d(-1.0,-1.0, 1.0),
cvf::Vec3d( 1.0,-1.0, 1.0),
cvf::Vec3d( 1.0, 1.0, 1.0),
cvf::Vec3d(-1.0, 1.0, 1.0)
};
for ( auto & v : hexCorners) v *= 2;
testHex(hexCorners);
}
TEST(InterpolationTest, TranslatedElement)
{
// Identity element
std::array<cvf::Vec3d, 8> hexCorners = {
cvf::Vec3d(-1.0,-1.0,-1.0),
cvf::Vec3d( 1.0,-1.0,-1.0),
cvf::Vec3d( 1.0, 1.0,-1.0),
cvf::Vec3d(-1.0, 1.0,-1.0),
cvf::Vec3d(-1.0,-1.0, 1.0),
cvf::Vec3d( 1.0,-1.0, 1.0),
cvf::Vec3d( 1.0, 1.0, 1.0),
cvf::Vec3d(-1.0, 1.0, 1.0)
};
for ( auto & v : hexCorners) v += {2.2, 4.4, -7.6};
testHex(hexCorners);
}
TEST(InterpolationTest, RotatedElement)
{
// Identity element
std::array<cvf::Vec3d, 8> hexCorners = {
cvf::Vec3d(-1.0,-1.0,-1.0),
cvf::Vec3d( 1.0,-1.0,-1.0),
cvf::Vec3d( 1.0, 1.0,-1.0),
cvf::Vec3d(-1.0, 1.0,-1.0),
cvf::Vec3d(-1.0,-1.0, 1.0),
cvf::Vec3d( 1.0,-1.0, 1.0),
cvf::Vec3d( 1.0, 1.0, 1.0),
cvf::Vec3d(-1.0, 1.0, 1.0)
};
cvf::Mat4d rot = cvf::Mat4d::fromRotation({1,1, 0}, 3.14159);
for ( auto & v : hexCorners) v.transformPoint(rot);
testHex(hexCorners);
}
TEST(InterpolationTest, CombinedUndeformed)
{
// Identity element
std::array<cvf::Vec3d, 8> hexCorners = {
cvf::Vec3d(-1.0,-1.0,-1.0),
cvf::Vec3d( 1.0,-1.0,-1.0),
cvf::Vec3d( 1.0, 1.0,-1.0),
cvf::Vec3d(-1.0, 1.0,-1.0),
cvf::Vec3d(-1.0,-1.0, 1.0),
cvf::Vec3d( 1.0,-1.0, 1.0),
cvf::Vec3d( 1.0, 1.0, 1.0),
cvf::Vec3d(-1.0, 1.0, 1.0)
};
for ( auto & v : hexCorners) v *= 2;
for ( auto & v : hexCorners) v += {2.2, 4.4, -7.6};
cvf::Mat4d rot = cvf::Mat4d::fromRotation({1,1, 0}, 3.14159);
for ( auto & v : hexCorners) v.transformPoint(rot);
testHex(hexCorners);
}
TEST(InterpolationTest, Compressed)
{
// Identity element
std::array<cvf::Vec3d, 8> hexCorners = {
cvf::Vec3d(-1.0,-1.0,-1.0),
cvf::Vec3d( 1.0,-1.0,-1.0),
cvf::Vec3d( 1.0, 1.0,-1.0),
cvf::Vec3d(-1.0, 1.0,-1.0),
cvf::Vec3d(-1.0,-1.0, 1.0),
cvf::Vec3d( 1.0,-1.0, 1.0),
cvf::Vec3d( 1.0, 1.0, 1.0),
cvf::Vec3d(-1.0, 1.0, 1.0)
};
for ( auto & v : hexCorners) v[0] *= 0.1;
testHex(hexCorners);
for ( auto & v : hexCorners) v[0] *= 10.0;
for ( auto & v : hexCorners) v[1] *= 0.1;
testHex(hexCorners);
for ( auto & v : hexCorners) v[1] *= 10.0;
for ( auto & v : hexCorners) v[2] *= 0.1;
testHex(hexCorners);
}
TEST(InterpolationTest, Scewed)
{
// Identity element
std::array<cvf::Vec3d, 8> hexCorners = {
cvf::Vec3d(-1.0,-1.0,-1.0),
cvf::Vec3d( 1.0,-1.0,-1.0),
cvf::Vec3d( 1.0, 1.0,-1.0),
cvf::Vec3d(-1.0, 1.0,-1.0),
cvf::Vec3d(-1.0,-1.0, 1.0),
cvf::Vec3d( 1.0,-1.0, 1.0),
cvf::Vec3d( 1.0, 1.0, 1.0),
cvf::Vec3d(-1.0, 1.0, 1.0)
};
for ( int i = 4 ; i< 8 ; ++i) hexCorners[i] += {1.0, 0.0, 0.0};
testHex(hexCorners);
}
TEST(InterpolationTest, Screwed)
{
// Identity element
std::array<cvf::Vec3d, 8> hexCorners = {
cvf::Vec3d(-1.0,-1.0,-1.0),
cvf::Vec3d( 1.0,-1.0,-1.0),
cvf::Vec3d( 1.0, 1.0,-1.0),
cvf::Vec3d(-1.0, 1.0,-1.0),
cvf::Vec3d(-1.0,-1.0, 1.0),
cvf::Vec3d( 1.0,-1.0, 1.0),
cvf::Vec3d( 1.0, 1.0, 1.0),
cvf::Vec3d(-1.0, 1.0, 1.0)
};
cvf::Mat4d rot = cvf::Mat4d::fromRotation({0, 0, 1}, 1.0*0.25*3.14159);
for ( int i = 4 ; i< 8 ; ++i) hexCorners[i].transformPoint(rot);
testHex(hexCorners);
}
TEST(InterpolationTest, Warp)
{
// Identity element
std::array<cvf::Vec3d, 8> hexCorners = {
cvf::Vec3d(-1.0,-1.0,-1.0),
cvf::Vec3d( 1.0,-1.0,-1.0),
cvf::Vec3d( 1.0, 1.0,-1.0),
cvf::Vec3d(-1.0, 1.0,-1.0),
cvf::Vec3d(-1.0,-1.0, 1.0),
cvf::Vec3d( 1.0,-1.0, 1.0),
cvf::Vec3d( 1.0, 1.0, 1.0),
cvf::Vec3d(-1.0, 1.0, 1.0)
};
{
std::array<cvf::Vec3d, 8> cornerCopy = hexCorners;
// Compress x
for ( auto & v : cornerCopy ) v[0] *= 0.1;
cornerCopy[0][0] += 0.25;
cornerCopy[1][0] += 0.20;
cornerCopy[7][0] += 0.25;
cornerCopy[6][0] += 0.4;
testHex(cornerCopy);
}
{
std::array<cvf::Vec3d, 8> cornerCopy = hexCorners;
// Compress z
for ( auto & v : cornerCopy ) v[2] *= 0.1;
cornerCopy[0][2] += 0.25;
cornerCopy[2][2] += 0.25;
cornerCopy[4][2] += 0.2;
cornerCopy[6][2] += 0.4;
testHex(cornerCopy);
}
}
TEST(InterpolationTest, TotalCombined)
{
// Identity element
std::array<cvf::Vec3d, 8> hexCorners = {
cvf::Vec3d(-1.0,-1.0,-1.0),
cvf::Vec3d( 1.0,-1.0,-1.0),
cvf::Vec3d( 1.0, 1.0,-1.0),
cvf::Vec3d(-1.0, 1.0,-1.0),
cvf::Vec3d(-1.0,-1.0, 1.0),
cvf::Vec3d( 1.0,-1.0, 1.0),
cvf::Vec3d( 1.0, 1.0, 1.0),
cvf::Vec3d(-1.0, 1.0, 1.0)
};
cvf::Mat4d rot = cvf::Mat4d::fromRotation({0, 0, 1}, 1.0*0.25*3.14159);
for ( int i = 4 ; i< 8 ; ++i) hexCorners[i].transformPoint(rot);
for ( int i = 4 ; i< 8 ; ++i) hexCorners[i] += {0.2, 0.0, 0.0};
{
std::array<cvf::Vec3d, 8> cornerCopy = hexCorners;
// Compress z
for ( auto & v : hexCorners ) v[2] *= 0.3;
hexCorners[0][2] += 0.25;
hexCorners[2][2] += 0.25;
hexCorners[4][2] += 0.2;
hexCorners[6][2] += 0.4;
}
for ( auto & v : hexCorners) v *= 200;
for ( auto & v : hexCorners) v += {2.3e5, 4.7e6, -2000};
cvf::Mat4d rot2 = cvf::Mat4d::fromRotation({1,1, 0}, 3.14159);
for ( auto & v : hexCorners) v.transformPoint(rot2);
testHex(hexCorners);
}

View File

@ -0,0 +1,56 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) Ceetron Solutions AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library 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.
//
// This library 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 <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#include "gtest/gtest.h"
#include <stdio.h>
#include <iostream>
#include <string>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS();
char text[5];
std::cin.getline(text, 5);
return result;
}

View File

@ -0,0 +1,43 @@
namespace cvftest {
//==================================================================================================
//
//
//==================================================================================================
class Utils
{
public:
static cvf::String getTestDataDir(const cvf::String& unitTestFolder)
{
#ifdef WIN32
std::string exe = std::string(testing::internal::GetArgvs()[0]);
#else
std::string dir = std::string(testing::internal::FilePath::GetCurrentDir().ToString());
std::string exe = dir + std::string("/") + std::string(testing::internal::GetArgvs()[0]);
#endif
std::string testPath = exe.substr(0, exe.find(unitTestFolder.toStdString())) + std::string("TestData/");
return testPath;
}
static cvf::String getGLSLDir(const cvf::String& unitTestFolder)
{
#ifdef WIN32
std::string exe = std::string(testing::internal::GetArgvs()[0]);
#else
std::string dir = std::string(testing::internal::FilePath::GetCurrentDir().ToString());
std::string exe = dir + std::string("/") + std::string(testing::internal::GetArgvs()[0]);
#endif
std::string glslPath = exe.substr(0, exe.find(unitTestFolder.toStdString())) + std::string("../LibRender/glsl/");
return glslPath;
}
};
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
#include <cmath>
#include <algorithm>
#include <array>
namespace caf {
@ -502,6 +503,157 @@ void HexGridIntersectionTools::clipTrianglesBetweenTwoParallelPlanes(const std::
}
}
//--------------------------------------------------------------------------------------------------
// Creates a plane with normal perpendicular to the edge, pointing in the direction of the pointInNormalDirection
//--------------------------------------------------------------------------------------------------
cvf::Plane createPlaneFromEdgeAndPointInNormalDirection(cvf::Vec3d ep1, cvf::Vec3d ep2, cvf::Vec3d pointInNormalDirection)
{
cvf::Vec3d ep1ep2 = ep2 - ep1;
cvf::Vec3d ep1pointforNorm = pointInNormalDirection - ep1;
cvf::Vec3d triNormal = ep1ep2^ep1pointforNorm;
cvf::Vec3d pointInPlane = ep1 + triNormal;
cvf::Plane plane;
plane.setFromPoints(ep1, pointInPlane, ep2);
return plane;
}
//--------------------------------------------------------------------------------------------------
// Clips the supplied triangles into new triangles returned in clippedTriangleVxes.
// New vertices have set isVxIdsNative = false and their vxIds is indices into triangleVxes
// The cellFaceForEachTriangleEdge refer to the edge after the corresponding triangle vertex.
// This method will keep the faces provided, while added edges is marked with no face = 6
//--------------------------------------------------------------------------------------------------
void HexGridIntersectionTools::clipPlanarTrianglesWithInPlaneTriangle(const std::vector<cvf::Vec3d>& triangleVxes,
const std::vector<int>& cellFaceForEachTriangleEdge,
const cvf::Vec3d& tp1,
const cvf::Vec3d& tp2,
const cvf::Vec3d& tp3,
std::vector<cvf::Vec3d>* clippedTriangleVxes,
std::vector<int>* cellFaceForEachClippedTriangleEdge)
{
#define HT_NO_FACE 6
size_t triangleCount = triangleVxes.size() / 3;
// Creating a plane for each of the edges of the clipping triangle
std::array<cvf::Plane, 3> clipTrianglePlanes;
clipTrianglePlanes[0] = createPlaneFromEdgeAndPointInNormalDirection (tp1, tp2, tp3);
clipTrianglePlanes[1] = createPlaneFromEdgeAndPointInNormalDirection (tp2, tp3, tp1);
clipTrianglePlanes[2] = createPlaneFromEdgeAndPointInNormalDirection (tp3, tp1, tp2);
for (size_t tIdx = 0; tIdx < triangleCount; ++tIdx)
{
size_t triVxIdx = tIdx * 3;
std::vector<cvf::Vec3d> currentInputTriangleVxes;
std::vector<int> currentInputCellFaceForEachTriangleEdge;
std::vector<cvf::Vec3d> currentOutputTriangleVxes;
std::vector<int> currentOutputCellFaceForEachTriangleEdge;
currentInputTriangleVxes.push_back(triangleVxes[triVxIdx + 0]);
currentInputTriangleVxes.push_back(triangleVxes[triVxIdx + 1]);
currentInputTriangleVxes.push_back(triangleVxes[triVxIdx + 2]);
currentInputCellFaceForEachTriangleEdge.push_back(cellFaceForEachTriangleEdge[triVxIdx + 0]);
currentInputCellFaceForEachTriangleEdge.push_back(cellFaceForEachTriangleEdge[triVxIdx + 1]);
currentInputCellFaceForEachTriangleEdge.push_back(cellFaceForEachTriangleEdge[triVxIdx + 2]);
for ( int planeIdx = 0; planeIdx < 3; ++planeIdx )
{
size_t inTriangleCount = currentInputTriangleVxes.size()/3;
currentOutputTriangleVxes.clear();
currentOutputCellFaceForEachTriangleEdge.clear();
for ( size_t inTrIdx = 0; inTrIdx < inTriangleCount ; ++inTrIdx )
{
size_t inTriVxIdx = inTrIdx * 3;
ClipVx newVx1;
newVx1.isVxIdsNative = false;
ClipVx newVx2;
newVx2.isVxIdsNative = false;
bool isMostVxesOnPositiveSide = false;
bool isIntersectingPlane = planeTriangleIntersection(clipTrianglePlanes[planeIdx],
currentInputTriangleVxes[inTriVxIdx + 0], inTriVxIdx + 0,
currentInputTriangleVxes[inTriVxIdx + 1], inTriVxIdx + 1,
currentInputTriangleVxes[inTriVxIdx + 2], inTriVxIdx + 2,
&newVx1, &newVx2, &isMostVxesOnPositiveSide);
if ( !isIntersectingPlane)
{
// All on negative side: Discard triangle
if (!isMostVxesOnPositiveSide)
{
continue;
}
else // All on positive side: keep all
{
currentOutputTriangleVxes.push_back(currentInputTriangleVxes[inTriVxIdx + 0]);
currentOutputTriangleVxes.push_back(currentInputTriangleVxes[inTriVxIdx + 1]);
currentOutputTriangleVxes.push_back(currentInputTriangleVxes[inTriVxIdx + 2]);
currentOutputCellFaceForEachTriangleEdge.push_back(currentInputCellFaceForEachTriangleEdge[inTriVxIdx + 0]);
currentOutputCellFaceForEachTriangleEdge.push_back(currentInputCellFaceForEachTriangleEdge[inTriVxIdx + 1]);
currentOutputCellFaceForEachTriangleEdge.push_back(currentInputCellFaceForEachTriangleEdge[inTriVxIdx + 2]);
}
}
else // intersecting
{
if ( isMostVxesOnPositiveSide )
{
// We need the Quad
currentOutputTriangleVxes.push_back(newVx2.vx);
currentOutputTriangleVxes.push_back(newVx1.vx);
currentOutputTriangleVxes.push_back(currentInputTriangleVxes[newVx1.clippedEdgeVx2Id]);
currentOutputCellFaceForEachTriangleEdge.push_back(HT_NO_FACE);
currentOutputCellFaceForEachTriangleEdge.push_back(currentInputCellFaceForEachTriangleEdge[newVx1.clippedEdgeVx1Id]);
currentOutputCellFaceForEachTriangleEdge.push_back(HT_NO_FACE);
currentOutputTriangleVxes.push_back(currentInputTriangleVxes[newVx1.clippedEdgeVx2Id]);
currentOutputTriangleVxes.push_back(currentInputTriangleVxes[newVx2.clippedEdgeVx2Id]);
currentOutputTriangleVxes.push_back(newVx2.vx);
currentOutputCellFaceForEachTriangleEdge.push_back(currentInputCellFaceForEachTriangleEdge[newVx1.clippedEdgeVx2Id]);
currentOutputCellFaceForEachTriangleEdge.push_back(currentInputCellFaceForEachTriangleEdge[newVx2.clippedEdgeVx2Id]);
currentOutputCellFaceForEachTriangleEdge.push_back(HT_NO_FACE);
}
else
{
currentOutputTriangleVxes.push_back(newVx1.vx);
currentOutputTriangleVxes.push_back(newVx2.vx);
currentOutputTriangleVxes.push_back(currentInputTriangleVxes[newVx1.clippedEdgeVx1Id]);
currentOutputCellFaceForEachTriangleEdge.push_back(HT_NO_FACE);
currentOutputCellFaceForEachTriangleEdge.push_back(currentInputCellFaceForEachTriangleEdge[newVx2.clippedEdgeVx2Id]);
currentOutputCellFaceForEachTriangleEdge.push_back(currentInputCellFaceForEachTriangleEdge[newVx1.clippedEdgeVx1Id]);
}
}
}
currentInputTriangleVxes = currentOutputTriangleVxes;
currentInputCellFaceForEachTriangleEdge = currentOutputCellFaceForEachTriangleEdge;
}
// Append the result of the completely clipped triangle to the output
clippedTriangleVxes->insert(clippedTriangleVxes->end(), currentOutputTriangleVxes.begin(), currentOutputTriangleVxes.end());
cellFaceForEachClippedTriangleEdge->insert(cellFaceForEachClippedTriangleEdge->end(), currentOutputCellFaceForEachTriangleEdge.begin(), currentOutputCellFaceForEachTriangleEdge.end());
}
}
//--------------------------------------------------------------------------------------------------
/// Will return the intersection point. If the plane is outside the line, it returns the closest line endpoint
//--------------------------------------------------------------------------------------------------

View File

@ -65,7 +65,15 @@ public:
std::vector<ClipVx>* clippedTriangleVxes,
std::vector<int>* cellFaceForEachClippedTriangleEdge);
static cvf::Vec3d planeLineIntersectionForMC(const cvf::Plane& plane,
static void clipPlanarTrianglesWithInPlaneTriangle(const std::vector<cvf::Vec3d>& triangleVxes,
const std::vector<int>& cellFaceForEachTriangleEdge,
const cvf::Vec3d& tp1,
const cvf::Vec3d& tp2,
const cvf::Vec3d& tp3,
std::vector<cvf::Vec3d>* clippedTriangleVxes,
std::vector<int>* cellFaceForEachClippedTriangleEdge);
static cvf::Vec3d planeLineIntersectionForMC(const cvf::Plane& plane,
const cvf::Vec3d& p1,
const cvf::Vec3d& p2,
double* normalizedDistFromP1);

View File

@ -0,0 +1,36 @@
cmake_minimum_required (VERSION 2.8.12)
project ( cafHexGridIntersectionTools_UnitTests )
if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11))
# VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1
add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
message(STATUS "Add flag to disable warings from gtest - _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING")
endif()
set (VIZ_MODULES_FOLDER_NAME ../../../../../Fwk/VizFwk)
add_subdirectory(${VIZ_MODULES_FOLDER_NAME}/LibCore LibCoreDir})
include_directories (
${CMAKE_CURRENT_SOURCE_DIR} # required for gtest-all.cpp
)
set( PROJECT_FILES
cafHexGridIntersectionToolsBasicTests.cpp
cafHexGridIntersectionTools_UnitTests_main.cpp
../cafHexGridIntersectionTools.cpp
../cafHexGridIntersectionTools.h
)
# add the executable
add_executable (${PROJECT_NAME}
${PROJECT_FILES}
gtest/gtest-all.cpp
)
target_link_libraries ( ${PROJECT_NAME}
LibCore
)
source_group("" FILES ${PROJECT_FILES})

View File

@ -0,0 +1,100 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) Ceetron Solutions AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library 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.
//
// This library 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 <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#include <iostream>
#include "gtest/gtest.h"
#include "../cafHexGridIntersectionTools.h"
TEST(cafHexIntersectionTools, basic)
{
std::vector<cvf::Vec3d> triangleVxes = {{0.0, 0.5, 0.0}, {1.0, 0.5, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.5, 0.0}, {1.0, 0.8, 0.0}, {0.0, 1.0, 0.0} };
std::vector<cvf::Vec3d> polygon2 = {{0.5, 0.0, 2002.0}, {1.0, 0.0, 2000.0}, {0.5, 1.0, 2001.0}};
const std::vector<int> cellFaceForEachTriangleEdge = { 1, 6, 4, 2, 3, 6 };
const cvf::Vec3d tp1 = {0.5, 0.01, 0.0};
const cvf::Vec3d tp2 = {1.0, 0.0, 0.0};
const cvf::Vec3d tp3 = {0.5, 1.0, 0.0};
std::vector<cvf::Vec3d> clippedTriangleVxes;
std::vector<int> cellFaceForEachClippedTriangleEdge;
caf::HexGridIntersectionTools::clipPlanarTrianglesWithInPlaneTriangle(triangleVxes,
cellFaceForEachTriangleEdge,
tp1,
tp2,
tp3,
&clippedTriangleVxes,
&cellFaceForEachClippedTriangleEdge);
for ( auto& point : clippedTriangleVxes )
{
//std::cout << " ( " << point[0] << ", " << point[1] << ", " << point[2] << " )" << std::endl;
}
for ( auto& face : cellFaceForEachClippedTriangleEdge )
{
//std::cout << " [ " << face << " ]" << std::endl;
}
EXPECT_NEAR(0.5, clippedTriangleVxes[7][0], 1e-7);
EXPECT_NEAR(0.5, clippedTriangleVxes[7][1], 1e-7);
EXPECT_NEAR(0.75, clippedTriangleVxes[2][0], 1e-7);
EXPECT_NEAR(0.5, clippedTriangleVxes[2][1], 1e-7);
EXPECT_NEAR(0.555555, clippedTriangleVxes[13][0], 1e-5);
EXPECT_NEAR(0.888888, clippedTriangleVxes[13][1], 1e-5);
EXPECT_NEAR(0.5, clippedTriangleVxes[9][0], 1e-7);
EXPECT_NEAR(0.9, clippedTriangleVxes[9][1], 1e-7);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[0]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[1]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[2]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[3]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[4]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[5]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[6]);
EXPECT_EQ(1, cellFaceForEachClippedTriangleEdge[7]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[8]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[9]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[10]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[11]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[12]);
EXPECT_EQ(3, cellFaceForEachClippedTriangleEdge[13]);
EXPECT_EQ(6, cellFaceForEachClippedTriangleEdge[14]);
}

View File

@ -0,0 +1,56 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) Ceetron Solutions AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library 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.
//
// This library 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 <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
//
//##################################################################################################
#include "gtest/gtest.h"
#include <stdio.h>
#include <iostream>
#include <string>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS();
char text[5];
std::cin.getline(text, 5);
return result;
}

View File

@ -0,0 +1,43 @@
namespace cvftest {
//==================================================================================================
//
//
//==================================================================================================
class Utils
{
public:
static cvf::String getTestDataDir(const cvf::String& unitTestFolder)
{
#ifdef WIN32
std::string exe = std::string(testing::internal::GetArgvs()[0]);
#else
std::string dir = std::string(testing::internal::FilePath::GetCurrentDir().ToString());
std::string exe = dir + std::string("/") + std::string(testing::internal::GetArgvs()[0]);
#endif
std::string testPath = exe.substr(0, exe.find(unitTestFolder.toStdString())) + std::string("TestData/");
return testPath;
}
static cvf::String getGLSLDir(const cvf::String& unitTestFolder)
{
#ifdef WIN32
std::string exe = std::string(testing::internal::GetArgvs()[0]);
#else
std::string dir = std::string(testing::internal::FilePath::GetCurrentDir().ToString());
std::string exe = dir + std::string("/") + std::string(testing::internal::GetArgvs()[0]);
#endif
std::string glslPath = exe.substr(0, exe.find(unitTestFolder.toStdString())) + std::string("../LibRender/glsl/");
return glslPath;
}
};
}