mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#5318 Surface Intersection geometry with results
This commit is contained in:
@@ -100,8 +100,6 @@ Rim3dView* RicNewViewFeature::createReservoirView( RimEclipseCase* eclipseCase,
|
|||||||
insertedView = geomCase->createAndAddReservoirView();
|
insertedView = geomCase->createAndAddReservoirView();
|
||||||
}
|
}
|
||||||
|
|
||||||
insertedView->updateSurfacesInViewTreeItems();
|
|
||||||
|
|
||||||
// Must be run before buildViewItems, as wells are created in this function
|
// Must be run before buildViewItems, as wells are created in this function
|
||||||
insertedView->loadDataAndUpdate();
|
insertedView->loadDataAndUpdate();
|
||||||
|
|
||||||
|
|||||||
@@ -190,21 +190,27 @@ void RivIntersectionResultsColoringTools::calculateNodeOrElementNodeBasedGeoMech
|
|||||||
#pragma omp parallel for schedule( dynamic )
|
#pragma omp parallel for schedule( dynamic )
|
||||||
for ( int triangleVxIdx = 0; triangleVxIdx < vxCount; ++triangleVxIdx )
|
for ( int triangleVxIdx = 0; triangleVxIdx < vxCount; ++triangleVxIdx )
|
||||||
{
|
{
|
||||||
float resValue = 0;
|
float resValue = HUGE_VAL;
|
||||||
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 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
if ( resValue == HUGE_VAL || resValue != resValue ) // a != a is true for NAN's
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ public:
|
|||||||
|
|
||||||
Where the k's are normalized distances along the edge, from the edge start vertex .
|
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;
|
v = (1 - k )* v1 + k *v2;
|
||||||
|
|
||||||
@@ -205,6 +205,13 @@ public:
|
|||||||
m_weights[1] = ( (float)( normDistFromE1V1 ) );
|
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
|
int size() const
|
||||||
{
|
{
|
||||||
return m_count;
|
return m_count;
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
|
|
||||||
set (SOURCE_GROUP_HEADER_FILES
|
set (SOURCE_GROUP_HEADER_FILES
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RivSurfacePartMgr.h
|
${CMAKE_CURRENT_LIST_DIR}/RivSurfacePartMgr.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RivSurfaceIntersectionGeometryGenerator.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RivReservoirSurfaceIntersectionSourceInfo.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set (SOURCE_GROUP_SOURCE_FILES
|
set (SOURCE_GROUP_SOURCE_FILES
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RivSurfacePartMgr.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RivSurfacePartMgr.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RivSurfaceIntersectionGeometryGenerator.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RivReservoirSurfaceIntersectionSourceInfo.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND CODE_HEADER_FILES
|
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 )
|
source_group( "ModelVisualization\\Surfaces" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake )
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -18,13 +18,9 @@
|
|||||||
|
|
||||||
#include "RivSurfacePartMgr.h"
|
#include "RivSurfacePartMgr.h"
|
||||||
|
|
||||||
#include "RigSurface.h"
|
#include "RiaApplication.h"
|
||||||
#include "RimSurface.h"
|
#include "RiaPreferences.h"
|
||||||
#include "RimSurfaceInView.h"
|
|
||||||
|
|
||||||
#include "RigHexIntersectionTools.h"
|
|
||||||
#include "RigResultAccessor.h"
|
|
||||||
#include "RigResultAccessorFactory.h"
|
|
||||||
#include "RimCase.h"
|
#include "RimCase.h"
|
||||||
#include "RimEclipseCase.h"
|
#include "RimEclipseCase.h"
|
||||||
#include "RimEclipseCellColors.h"
|
#include "RimEclipseCellColors.h"
|
||||||
@@ -34,11 +30,26 @@
|
|||||||
#include "RimGeoMechResultDefinition.h"
|
#include "RimGeoMechResultDefinition.h"
|
||||||
#include "RimGeoMechView.h"
|
#include "RimGeoMechView.h"
|
||||||
#include "RimRegularLegendConfig.h"
|
#include "RimRegularLegendConfig.h"
|
||||||
|
#include "RimSurface.h"
|
||||||
|
#include "RimSurfaceInView.h"
|
||||||
#include "RimTernaryLegendConfig.h"
|
#include "RimTernaryLegendConfig.h"
|
||||||
|
|
||||||
|
#include "RigHexIntersectionTools.h"
|
||||||
|
#include "RigResultAccessor.h"
|
||||||
|
#include "RigResultAccessorFactory.h"
|
||||||
|
#include "RigSurface.h"
|
||||||
|
|
||||||
#include "RivHexGridIntersectionTools.h"
|
#include "RivHexGridIntersectionTools.h"
|
||||||
|
#include "RivIntersectionResultsColoringTools.h"
|
||||||
|
#include "RivMeshLinesSourceInfo.h"
|
||||||
|
#include "RivPartPriority.h"
|
||||||
|
#include "RivReservoirSurfaceIntersectionSourceInfo.h"
|
||||||
#include "RivScalarMapperUtils.h"
|
#include "RivScalarMapperUtils.h"
|
||||||
|
#include "RivSurfaceIntersectionGeometryGenerator.h"
|
||||||
#include "RivTernaryScalarMapper.h"
|
#include "RivTernaryScalarMapper.h"
|
||||||
|
|
||||||
#include "cafEffectGenerator.h"
|
#include "cafEffectGenerator.h"
|
||||||
|
|
||||||
#include "cvfDrawableGeo.h"
|
#include "cvfDrawableGeo.h"
|
||||||
#include "cvfModelBasicList.h"
|
#include "cvfModelBasicList.h"
|
||||||
#include "cvfPart.h"
|
#include "cvfPart.h"
|
||||||
@@ -50,6 +61,12 @@
|
|||||||
RivSurfacePartMgr::RivSurfacePartMgr( RimSurfaceInView* surface )
|
RivSurfacePartMgr::RivSurfacePartMgr( RimSurfaceInView* surface )
|
||||||
: m_surfaceInView( 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() );
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -82,84 +99,136 @@ void RivSurfacePartMgr::appendNativeGeometryPartsToModel( cvf::ModelBasicList* m
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
void RivSurfacePartMgr::updateCellResultColor( size_t timeStepIndex )
|
void RivSurfacePartMgr::updateCellResultColor( size_t timeStepIndex )
|
||||||
{
|
{
|
||||||
if ( !m_vertexToCellIndexMap.size() )
|
if ( m_intersectionFaces.notNull() )
|
||||||
{
|
{
|
||||||
generateVertexToCellIndexMap();
|
RivIntersectionResultsColoringTools::calculateIntersectionResultColors( timeStepIndex,
|
||||||
|
false,
|
||||||
|
m_surfaceInView,
|
||||||
|
m_intersectionGenerator.p(),
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
m_intersectionFaces.p(),
|
||||||
|
m_intersectionFacesTextureCoords.p() );
|
||||||
}
|
}
|
||||||
|
|
||||||
RimGridView* gridView = nullptr;
|
if ( m_nativeTrianglesPart.notNull() )
|
||||||
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;
|
if ( !m_nativeVertexToCellIndexMap.size() )
|
||||||
m_surfaceInView->firstAncestorOrThisOfType( eclipseView );
|
|
||||||
|
|
||||||
if ( eclipseView )
|
|
||||||
{
|
{
|
||||||
eclipseResDef = eclipseView->cellResult();
|
generateNativeVertexToCellIndexMap();
|
||||||
if ( !scalarColorMapper ) scalarColorMapper = eclipseView->cellResult()->legendConfig()->scalarMapper();
|
|
||||||
if ( !ternaryColorMapper )
|
|
||||||
ternaryColorMapper = eclipseView->cellResult()->ternaryLegendConfig()->scalarMapper();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RimGeoMechView* geoView;
|
RimGridView* gridView = nullptr;
|
||||||
m_surfaceInView->firstAncestorOrThisOfType( geoView );
|
m_surfaceInView->firstAncestorOrThisOfType( gridView );
|
||||||
|
|
||||||
if ( geoView )
|
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 )
|
||||||
{
|
{
|
||||||
geomResultDef = geoView->cellResult();
|
RimEclipseView* eclipseView = nullptr;
|
||||||
if ( !scalarColorMapper ) scalarColorMapper = geoView->cellResult()->legendConfig()->scalarMapper();
|
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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cvf::ref<cvf::Vec2fArray> intersectionFacesTextureCoords = new cvf::Vec2fArray();
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
if ( eclipseResDef )
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RivSurfacePartMgr::appendIntersectionGeometryPartsToModel( cvf::ModelBasicList* model,
|
||||||
|
cvf::Transform* scaleTransform )
|
||||||
|
{
|
||||||
|
if ( m_intersectionFaces.isNull() )
|
||||||
{
|
{
|
||||||
if ( !eclipseResDef->isTernarySaturationSelected() )
|
generatePartGeometry();
|
||||||
{
|
}
|
||||||
RigEclipseCaseData* eclipseCaseData = eclipseResDef->eclipseCase()->eclipseCaseData();
|
|
||||||
|
|
||||||
cvf::ref<RigResultAccessor> resultAccessor;
|
if ( m_intersectionFaces.notNull() )
|
||||||
|
{
|
||||||
|
m_intersectionFaces->setTransform( scaleTransform );
|
||||||
|
model->addPart( m_intersectionFaces.p() );
|
||||||
|
}
|
||||||
|
|
||||||
if ( !RiaDefines::isPerCellFaceResult( eclipseResDef->resultVariable() ) )
|
// Mesh Lines
|
||||||
|
|
||||||
{
|
if ( m_intersectionGridLines.isNull() )
|
||||||
resultAccessor = RigResultAccessorFactory::createFromResultDefinition( eclipseCaseData,
|
{
|
||||||
0,
|
generatePartGeometry();
|
||||||
timeStepIndex,
|
}
|
||||||
eclipseResDef );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( resultAccessor.isNull() )
|
if ( m_intersectionGridLines.notNull() )
|
||||||
{
|
{
|
||||||
resultAccessor = new RigHugeValResultAccessor;
|
m_intersectionGridLines->setTransform( scaleTransform );
|
||||||
}
|
model->addPart( m_intersectionGridLines.p() );
|
||||||
|
}
|
||||||
|
|
||||||
RivSurfacePartMgr::calculateVertexTextureCoordinates( intersectionFacesTextureCoords.p(),
|
if ( m_intersectionFaultGridLines.notNull() )
|
||||||
m_vertexToCellIndexMap,
|
{
|
||||||
resultAccessor.p(),
|
m_intersectionFaultGridLines->setTransform( scaleTransform );
|
||||||
scalarColorMapper );
|
model->addPart( m_intersectionFaultGridLines.p() );
|
||||||
|
|
||||||
RivScalarMapperUtils::applyTextureResultsToPart( m_nativeTrianglesPart.p(),
|
|
||||||
intersectionFacesTextureCoords.p(),
|
|
||||||
scalarColorMapper,
|
|
||||||
1.0,
|
|
||||||
caf::FC_NONE,
|
|
||||||
isLightingDisabled );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,12 +237,130 @@ void RivSurfacePartMgr::updateCellResultColor( size_t timeStepIndex )
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
void RivSurfacePartMgr::applySingleColor()
|
void RivSurfacePartMgr::applySingleColor()
|
||||||
{
|
{
|
||||||
if ( m_nativeTrianglesPart.notNull() )
|
|
||||||
{
|
{
|
||||||
caf::SurfaceEffectGenerator surfaceGen( cvf::Color4f( m_surfaceInView->surface()->color() ), caf::PO_1 );
|
caf::SurfaceEffectGenerator surfaceGen( cvf::Color4f( m_surfaceInView->surface()->color() ), caf::PO_1 );
|
||||||
cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect();
|
cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect();
|
||||||
m_nativeTrianglesPart->setEffect( eff.p() );
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -205,20 +392,21 @@ void RivSurfacePartMgr::generateNativePartGeometry()
|
|||||||
drawGeo->computeNormals();
|
drawGeo->computeNormals();
|
||||||
|
|
||||||
m_nativeTrianglesPart = new cvf::Part();
|
m_nativeTrianglesPart = new cvf::Part();
|
||||||
|
m_nativeTrianglesPart->setName( "Native Reservoir Surface" );
|
||||||
m_nativeTrianglesPart->setDrawable( drawGeo.p() );
|
m_nativeTrianglesPart->setDrawable( drawGeo.p() );
|
||||||
|
|
||||||
m_vertexToCellIndexMap.clear();
|
m_nativeVertexToCellIndexMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
void RivSurfacePartMgr::generateVertexToCellIndexMap()
|
void RivSurfacePartMgr::generateNativeVertexToCellIndexMap()
|
||||||
{
|
{
|
||||||
cvf::ref<RivIntersectionHexGridInterface> hexGrid = m_surfaceInView->createHexGridInterface();
|
cvf::ref<RivIntersectionHexGridInterface> hexGrid = m_surfaceInView->createHexGridInterface();
|
||||||
|
|
||||||
const std::vector<cvf::Vec3d>& vertices = m_usedSurfaceData->vertices();
|
const std::vector<cvf::Vec3d>& vertices = m_usedSurfaceData->vertices();
|
||||||
m_vertexToCellIndexMap.resize( vertices.size(), -1 );
|
m_nativeVertexToCellIndexMap.resize( vertices.size(), -1 );
|
||||||
|
|
||||||
for ( size_t vxIdx = 0; vxIdx < vertices.size(); ++vxIdx )
|
for ( size_t vxIdx = 0; vxIdx < vertices.size(); ++vxIdx )
|
||||||
{
|
{
|
||||||
@@ -234,7 +422,7 @@ void RivSurfacePartMgr::generateVertexToCellIndexMap()
|
|||||||
|
|
||||||
if ( RigHexIntersectionTools::isPointInCell( vertices[vxIdx], cellCorners ) )
|
if ( RigHexIntersectionTools::isPointInCell( vertices[vxIdx], cellCorners ) )
|
||||||
{
|
{
|
||||||
m_vertexToCellIndexMap[vxIdx] = cellIdx;
|
m_nativeVertexToCellIndexMap[vxIdx] = cellIdx;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,29 +34,47 @@ class RimSurfaceInView;
|
|||||||
class RigSurface;
|
class RigSurface;
|
||||||
class RigResultAccessor;
|
class RigResultAccessor;
|
||||||
|
|
||||||
|
class RivSurfaceIntersectionGeometryGenerator;
|
||||||
|
|
||||||
class RivSurfacePartMgr : public cvf::Object
|
class RivSurfacePartMgr : public cvf::Object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit RivSurfacePartMgr( RimSurfaceInView* surface );
|
explicit RivSurfacePartMgr( RimSurfaceInView* surface );
|
||||||
|
|
||||||
void appendNativeGeometryPartsToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform );
|
|
||||||
void updateCellResultColor( size_t timeStepIndex );
|
|
||||||
void applySingleColor();
|
void applySingleColor();
|
||||||
|
void updateCellResultColor( size_t timeStepIndex );
|
||||||
|
void appendIntersectionGeometryPartsToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform );
|
||||||
|
|
||||||
|
void appendNativeGeometryPartsToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void generatePartGeometry();
|
||||||
|
|
||||||
void generateNativePartGeometry();
|
void generateNativePartGeometry();
|
||||||
void generateVertexToCellIndexMap();
|
void generateNativeVertexToCellIndexMap();
|
||||||
|
|
||||||
static void calculateVertexTextureCoordinates( cvf::Vec2fArray* textureCoords,
|
static void calculateVertexTextureCoordinates( cvf::Vec2fArray* textureCoords,
|
||||||
const std::vector<size_t>& vertexToCellIdxMap,
|
const std::vector<size_t>& vertexToCellIdxMap,
|
||||||
const RigResultAccessor* resultAccessor,
|
const RigResultAccessor* resultAccessor,
|
||||||
const cvf::ScalarMapper* mapper );
|
const cvf::ScalarMapper* mapper );
|
||||||
|
|
||||||
|
cvf::ref<RivSurfaceIntersectionGeometryGenerator> m_intersectionGenerator;
|
||||||
|
|
||||||
caf::PdmPointer<RimSurfaceInView> m_surfaceInView;
|
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<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_nativeTrianglesPart;
|
||||||
cvf::ref<cvf::Part> m_nativeMeshLinesPart;
|
cvf::ref<cvf::Part> m_nativeMeshLinesPart;
|
||||||
|
|
||||||
std::vector<size_t> m_vertexToCellIndexMap;
|
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
|
||||||
|
{
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -891,6 +891,8 @@ void RimEclipseView::appendWellsAndFracturesToModel()
|
|||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
void RimEclipseView::onLoadDataAndUpdate()
|
void RimEclipseView::onLoadDataAndUpdate()
|
||||||
{
|
{
|
||||||
|
this->updateSurfacesInViewTreeItems();
|
||||||
|
|
||||||
onUpdateScaleTransform();
|
onUpdateScaleTransform();
|
||||||
|
|
||||||
if ( m_eclipseCase )
|
if ( m_eclipseCase )
|
||||||
|
|||||||
@@ -131,8 +131,11 @@ void RimGeoMechView::onLoadDataAndUpdate()
|
|||||||
{
|
{
|
||||||
caf::ProgressInfo progress( 7, "" );
|
caf::ProgressInfo progress( 7, "" );
|
||||||
progress.setNextProgressIncrement( 5 );
|
progress.setNextProgressIncrement( 5 );
|
||||||
|
|
||||||
onUpdateScaleTransform();
|
onUpdateScaleTransform();
|
||||||
|
|
||||||
|
this->updateSurfacesInViewTreeItems();
|
||||||
|
|
||||||
if ( m_geomechCase )
|
if ( m_geomechCase )
|
||||||
{
|
{
|
||||||
std::string errorMessage;
|
std::string errorMessage;
|
||||||
@@ -395,13 +398,20 @@ void RimGeoMechView::onUpdateDisplayModelForCurrentTimeStep()
|
|||||||
else
|
else
|
||||||
m_vizLogic->updateStaticCellColors( m_currentTimeStep() );
|
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
|
else
|
||||||
{
|
{
|
||||||
m_vizLogic->updateStaticCellColors( -1 );
|
m_vizLogic->updateStaticCellColors( -1 );
|
||||||
|
|
||||||
m_intersectionCollection->updateCellResultColor( false, m_currentTimeStep );
|
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
|
nativeOrOverrideViewer()->animationControl()->slotPause(); // To avoid animation timer spinning in the background
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,6 +106,13 @@ void RimSurfaceInView::fieldChangedByUi( const caf::PdmFieldHandle* changedField
|
|||||||
this->firstAncestorOrThisOfTypeAsserted( ownerView );
|
this->firstAncestorOrThisOfTypeAsserted( ownerView );
|
||||||
ownerView->scheduleCreateDisplayModelAndRedraw();
|
ownerView->scheduleCreateDisplayModelAndRedraw();
|
||||||
}
|
}
|
||||||
|
else if ( changedField == &m_showInactiveCells )
|
||||||
|
{
|
||||||
|
m_surfacePartMgr = nullptr;
|
||||||
|
RimGridView* ownerView;
|
||||||
|
this->firstAncestorOrThisOfTypeAsserted( ownerView );
|
||||||
|
ownerView->scheduleCreateDisplayModelAndRedraw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -102,7 +102,8 @@ void RimSurfaceInViewCollection::appendPartsToModel( cvf::ModelBasicList* model,
|
|||||||
{
|
{
|
||||||
if ( surf->isActive() )
|
if ( surf->isActive() )
|
||||||
{
|
{
|
||||||
surf->surfacePartMgr()->appendNativeGeometryPartsToModel( model, scaleTransform );
|
// surf->surfacePartMgr()->appendNativeGeometryPartsToModel( model, scaleTransform );
|
||||||
|
surf->surfacePartMgr()->appendIntersectionGeometryPartsToModel( model, scaleTransform );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ set_property(TARGET cafCommandFeatures PROPERTY FOLDER "AppFwk")
|
|||||||
#add_subdirectory(Fwk/AppFwk/cafTests/cafTestCvfApplication)
|
#add_subdirectory(Fwk/AppFwk/cafTests/cafTestCvfApplication)
|
||||||
|
|
||||||
add_subdirectory(Fwk/AppFwk/cafTensor)
|
add_subdirectory(Fwk/AppFwk/cafTensor)
|
||||||
|
add_subdirectory(Fwk/AppFwk/cafHexInterpolator)
|
||||||
|
|
||||||
list(APPEND APP_FWK_LIBRARIES
|
list(APPEND APP_FWK_LIBRARIES
|
||||||
cafPdmCore
|
cafPdmCore
|
||||||
@@ -401,6 +402,7 @@ list(APPEND APP_FWK_LIBRARIES
|
|||||||
|
|
||||||
set_property(TARGET
|
set_property(TARGET
|
||||||
${APP_FWK_LIBRARIES}
|
${APP_FWK_LIBRARIES}
|
||||||
|
cafHexInterpolator
|
||||||
PROPERTY FOLDER "AppFwk"
|
PROPERTY FOLDER "AppFwk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user