2026-07-27 11:21:05 +02:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Copyright (C) 2026- 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 "RivIjkIntersectionGeometryGenerator.h"
|
|
|
|
|
|
|
|
|
|
#include "RivIntersectionHexGridInterface.h"
|
|
|
|
|
|
|
|
|
|
#include "RigBoundingBoxIjk.h"
|
|
|
|
|
#include "RigMainGrid.h"
|
|
|
|
|
|
|
|
|
|
#include "RimIjkIntersection.h"
|
|
|
|
|
|
|
|
|
|
#include "cafVecIjk.h"
|
|
|
|
|
|
|
|
|
|
#include "cvfDrawableGeo.h"
|
|
|
|
|
#include "cvfPrimitiveSetDirect.h"
|
|
|
|
|
#include "cvfStructGrid.h"
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <array>
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RivIjkIntersectionGeometryGenerator::RivIjkIntersectionGeometryGenerator( RimIjkIntersection* intersection,
|
|
|
|
|
const RivIntersectionHexGridInterface* grid,
|
|
|
|
|
const RigMainGrid* mainGrid )
|
|
|
|
|
: m_hexGrid( grid )
|
|
|
|
|
, m_mainGrid( mainGrid )
|
|
|
|
|
, m_intersectionDefinition( intersection )
|
|
|
|
|
{
|
|
|
|
|
m_triangleVxes = new cvf::Vec3fArray;
|
|
|
|
|
m_cellBorderLineVxes = new cvf::Vec3fArray;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RivIjkIntersectionGeometryGenerator::~RivIjkIntersectionGeometryGenerator()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
bool RivIjkIntersectionGeometryGenerator::isAnyGeometryPresent() const
|
|
|
|
|
{
|
|
|
|
|
return m_triangleVxes->size() != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
cvf::ref<cvf::DrawableGeo> RivIjkIntersectionGeometryGenerator::generateSurface( cvf::UByteArray* visibleCells )
|
|
|
|
|
{
|
|
|
|
|
calculateArrays( visibleCells );
|
|
|
|
|
|
2026-08-06 21:18:33 +02:00
|
|
|
CAF_ASSERT( m_triangleVxes.notNull() );
|
2026-07-27 11:21:05 +02:00
|
|
|
|
|
|
|
|
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> RivIjkIntersectionGeometryGenerator::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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
const std::vector<size_t>& RivIjkIntersectionGeometryGenerator::triangleToCellIndex() const
|
|
|
|
|
{
|
2026-08-06 21:18:33 +02:00
|
|
|
CAF_ASSERT( m_triangleVxes->size() );
|
2026-07-27 11:21:05 +02:00
|
|
|
return m_triangleToCellIdxMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
const std::vector<RivIntersectionVertexWeights>& RivIjkIntersectionGeometryGenerator::triangleVxToCellCornerInterpolationWeights() const
|
|
|
|
|
{
|
2026-08-06 21:18:33 +02:00
|
|
|
CAF_ASSERT( m_triangleVxes->size() );
|
2026-07-27 11:21:05 +02:00
|
|
|
return m_triVxToCellCornerWeights;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
const cvf::Vec3fArray* RivIjkIntersectionGeometryGenerator::triangleVxes() const
|
|
|
|
|
{
|
2026-08-06 21:18:33 +02:00
|
|
|
CAF_ASSERT( m_triangleVxes->size() );
|
2026-07-27 11:21:05 +02:00
|
|
|
|
|
|
|
|
return m_triangleVxes.p();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RimIjkIntersection* RivIjkIntersectionGeometryGenerator::intersection() const
|
|
|
|
|
{
|
|
|
|
|
return m_intersectionDefinition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RivIjkIntersectionGeometryGenerator::calculateArrays( cvf::UByteArray* visibleCells )
|
|
|
|
|
{
|
|
|
|
|
if ( m_triangleVxes->size() ) return;
|
|
|
|
|
if ( m_mainGrid.isNull() || m_hexGrid.isNull() ) return;
|
|
|
|
|
|
|
|
|
|
using FaceType = cvf::StructGridInterface::FaceType;
|
|
|
|
|
|
|
|
|
|
const size_t ni = m_mainGrid->cellCountI();
|
|
|
|
|
const size_t nj = m_mainGrid->cellCountJ();
|
|
|
|
|
const size_t nk = m_mainGrid->cellCountK();
|
|
|
|
|
if ( ni == 0 || nj == 0 || nk == 0 ) return;
|
|
|
|
|
|
2026-08-06 08:06:53 +02:00
|
|
|
// Determine which cell face the surface follows
|
2026-07-27 11:21:05 +02:00
|
|
|
RimIjkIntersection::GridAxis axis = m_intersectionDefinition->axis();
|
|
|
|
|
bool neg = m_intersectionDefinition->useNegativeFace();
|
|
|
|
|
|
2026-08-06 08:06:53 +02:00
|
|
|
auto computeFace = [&]() -> FaceType
|
2026-07-27 11:21:05 +02:00
|
|
|
{
|
|
|
|
|
switch ( axis )
|
|
|
|
|
{
|
|
|
|
|
case RimIjkIntersection::GridAxis::AXIS_I:
|
2026-08-06 08:06:53 +02:00
|
|
|
return neg ? FaceType::NEG_I : FaceType::POS_I;
|
2026-07-27 11:21:05 +02:00
|
|
|
case RimIjkIntersection::GridAxis::AXIS_J:
|
2026-08-06 08:06:53 +02:00
|
|
|
return neg ? FaceType::NEG_J : FaceType::POS_J;
|
2026-07-27 11:21:05 +02:00
|
|
|
case RimIjkIntersection::GridAxis::AXIS_K:
|
|
|
|
|
default:
|
2026-08-06 08:06:53 +02:00
|
|
|
return neg ? FaceType::NEG_K : FaceType::POS_K;
|
2026-07-27 11:21:05 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-08-06 08:06:53 +02:00
|
|
|
const FaceType face = computeFace();
|
2026-07-27 11:21:05 +02:00
|
|
|
|
2026-08-06 08:06:53 +02:00
|
|
|
const auto visibleRange = m_intersectionDefinition->clampedCellRange( m_mainGrid.p() );
|
2026-07-27 11:21:05 +02:00
|
|
|
if ( !visibleRange ) return;
|
|
|
|
|
|
|
|
|
|
cvf::ubyte faceVtxIdx[4];
|
|
|
|
|
cvf::StructGridInterface::cellFaceVertexIndices( face, faceVtxIdx );
|
|
|
|
|
|
|
|
|
|
cvf::Vec3d displayOffset = m_hexGrid->displayOffset();
|
|
|
|
|
|
|
|
|
|
std::vector<cvf::Vec3f> triangleVertices;
|
|
|
|
|
std::vector<cvf::Vec3f> cellBorderLineVxes;
|
|
|
|
|
|
|
|
|
|
for ( size_t k = visibleRange->min().k(); k <= visibleRange->max().k(); ++k )
|
|
|
|
|
{
|
|
|
|
|
for ( size_t j = visibleRange->min().j(); j <= visibleRange->max().j(); ++j )
|
|
|
|
|
{
|
|
|
|
|
for ( size_t i = visibleRange->min().i(); i <= visibleRange->max().i(); ++i )
|
|
|
|
|
{
|
|
|
|
|
size_t globalCellIdx = m_mainGrid->cellIndexFromIJK( i, j, k );
|
|
|
|
|
|
|
|
|
|
if ( ( visibleCells != nullptr ) && ( ( *visibleCells )[globalCellIdx] == 0 ) ) continue;
|
|
|
|
|
if ( !m_hexGrid->useCell( globalCellIdx ) ) continue;
|
|
|
|
|
|
|
|
|
|
const std::array<cvf::Vec3d, 8> cellCorners = m_hexGrid->cellCornerVertices( globalCellIdx );
|
|
|
|
|
const std::array<size_t, 8> cornerIndices = m_hexGrid->cellCornerIndices( globalCellIdx );
|
|
|
|
|
|
|
|
|
|
cvf::Vec3f faceVx[4];
|
|
|
|
|
for ( int n = 0; n < 4; ++n )
|
|
|
|
|
{
|
|
|
|
|
faceVx[n] = cvf::Vec3f( cellCorners[faceVtxIdx[n]] - displayOffset );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Two triangles: (0, 1, 2) and (0, 2, 3)
|
|
|
|
|
const int triVtxOrder[6] = { 0, 1, 2, 0, 2, 3 };
|
|
|
|
|
for ( int n = 0; n < 6; ++n )
|
|
|
|
|
{
|
|
|
|
|
int corner = triVtxOrder[n];
|
|
|
|
|
triangleVertices.push_back( faceVx[corner] );
|
|
|
|
|
|
|
|
|
|
size_t nodeId = cornerIndices[faceVtxIdx[corner]];
|
|
|
|
|
m_triVxToCellCornerWeights.push_back( RivIntersectionVertexWeights( nodeId, nodeId, 0.0 ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_triangleToCellIdxMap.push_back( globalCellIdx );
|
|
|
|
|
m_triangleToCellIdxMap.push_back( globalCellIdx );
|
|
|
|
|
|
|
|
|
|
// Mesh border lines: the four face edges
|
|
|
|
|
for ( int n = 0; n < 4; ++n )
|
|
|
|
|
{
|
|
|
|
|
cellBorderLineVxes.push_back( faceVx[n] );
|
|
|
|
|
cellBorderLineVxes.push_back( faceVx[( n + 1 ) % 4] );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_cellBorderLineVxes->assign( cellBorderLineVxes );
|
|
|
|
|
m_triangleVxes->assign( triangleVertices );
|
|
|
|
|
}
|