Files
ResInsight/ApplicationLibCode/ModelVisualization/Riv3dWellLogDrawSurfaceGenerator.cpp
T
Magne Sjaastad 56e98ba1c4 #14476 ApplicationLibCode: Replace CVF_ASSERT with CAF_ASSERT
Migrate all assert macros in ApplicationLibCode to CAF_ASSERT and remove every
use of cvfAssert.h.

CVF_ASSERT is replaced one to one. CVF_TIGHT_ASSERT is also replaced by
CAF_ASSERT, which is semantically exact: CVF_ENABLE_TIGHT_ASSERTS is 1 only
under _DEBUG, and that is what CAF_ASSERT now does. The two CVF_FAIL_MSG sites
become CAF_ASSERT( false && "message" ), preserving the message with the idiom
already used elsewhere in the code base.

Counts before and after: CVF_ASSERT 1044 to 0, CVF_TIGHT_ASSERT 66 to 0,
CVF_FAIL_MSG 2 to 0, cvfAssert.h references 154 to 0.

Include handling: files that included cvfAssert.h directly now include
cafAssert.h instead, includes left dead by the migration are removed, and files
that were relying on cvfAssert.h transitively get an explicit cafAssert.h. Files
that reach cafAssert.h through another caf header are left unchanged; a missing
include here is a compile error, not a silently disabled assert.

ResultStatisticsCache links only LibCore and therefore had no path to
cafAssert.h. Add the cafPdmCore directory as a private include path rather than
linking the library, since cafAssert.h is header only.

Note that this stops these asserts from firing in Release and RelWithDebInfo,
where CVF_ASSERT was previously active.
2026-08-07 15:05:57 +02:00

319 lines
14 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- 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 "Riv3dWellLogDrawSurfaceGenerator.h"
#include "RimWellPath.h"
#include "RimWellPathCollection.h"
#include "Well/RigWellPath.h"
#include "Well/RigWellPathGeometryTools.h"
#include "cafDisplayCoordTransform.h"
#include "cvfArrowGenerator.h"
#include "cvfBoundingBox.h"
#include "cvfGeometryBuilderTriangles.h"
#include "cvfObject.h"
#include "cvfPrimitiveSetIndexedUInt.h"
#include <algorithm>
#include <map>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Riv3dWellLogDrawSurfaceGenerator::Riv3dWellLogDrawSurfaceGenerator( RimWellPath* wellPath )
: m_wellPath( wellPath )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool Riv3dWellLogDrawSurfaceGenerator::createDrawSurface( const caf::DisplayCoordTransform* displayCoordTransform,
const cvf::BoundingBox& wellPathClipBoundingBox,
double planeAngle,
double planeOffsetFromWellPathCenter,
double planeWidth,
double samplingIntervalSize )
{
CAF_ASSERT( samplingIntervalSize > 0 );
clearGeometry();
if ( !wellPathGeometry() || wellPathGeometry()->measuredDepths().empty() )
{
return false;
}
if ( !wellPathClipBoundingBox.isValid() )
{
return false;
}
auto wellPathCollection = m_wellPath->firstAncestorOrThisOfTypeAsserted<RimWellPathCollection>();
std::vector<cvf::Vec3d> wellPathDisplayCoords;
{
const std::vector<cvf::Vec3d>& domainCoords = wellPathGeometry()->wellPathPoints();
if ( domainCoords.size() < (size_t)2 )
{
// Need at least two well path points to create a valid path.
return false;
}
wellPathDisplayCoords = displayCoordTransform->transformToDisplayCoords( domainCoords );
}
std::vector<cvf::Vec3d> wellPathSegmentNormals = RigWellPathGeometryTools::calculateLineSegmentNormals( wellPathDisplayCoords, planeAngle );
size_t indexToFirstVisibleSegment = 0u;
if ( wellPathCollection->wellPathClip )
{
double clipZDistance = wellPathCollection->wellPathClipZDistance;
cvf::Vec3d clipLocation = wellPathClipBoundingBox.max() + clipZDistance * cvf::Vec3d::Z_AXIS;
auto clipLocationDisplay = displayCoordTransform->transformToDisplayCoord( clipLocation );
double horizontalLengthAlongWellToClipPoint = 0.0;
double measuredDepthAtFirstClipPoint = 0.0;
wellPathDisplayCoords = RigWellPath::clipPolylineStartAboveZ( wellPathDisplayCoords,
clipLocationDisplay.z(),
horizontalLengthAlongWellToClipPoint,
measuredDepthAtFirstClipPoint,
indexToFirstVisibleSegment );
}
// Create curve normal vectors using the unclipped well path points and normals.
createCurveNormalVectors( displayCoordTransform,
indexToFirstVisibleSegment,
planeOffsetFromWellPathCenter,
planeWidth,
samplingIntervalSize,
wellPathSegmentNormals );
// Note that normals are calculated on the full non-clipped well path. So we need to clip the start here.
wellPathSegmentNormals.erase( wellPathSegmentNormals.begin(), wellPathSegmentNormals.end() - wellPathDisplayCoords.size() );
if ( wellPathDisplayCoords.size() < (size_t)2 )
{
// Need at least two well path points to create a valid path.
return false;
}
m_vertices.reserve( wellPathDisplayCoords.size() * 2 );
for ( size_t i = 0; i < wellPathDisplayCoords.size(); i++ )
{
m_vertices.push_back( wellPathDisplayCoords[i] + wellPathSegmentNormals[i] * ( planeOffsetFromWellPathCenter - 0.025 * planeWidth ) );
m_vertices.push_back( wellPathDisplayCoords[i] + wellPathSegmentNormals[i] * ( planeOffsetFromWellPathCenter + 1.025 * planeWidth ) );
}
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray( m_vertices.size() );
for ( size_t i = 0; i < m_vertices.size(); ++i )
{
( *vertexArray )[i] = cvf::Vec3f( m_vertices[i] );
}
createBackground( vertexArray.p() );
createBorder( vertexArray.p() );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void Riv3dWellLogDrawSurfaceGenerator::clearGeometry()
{
m_background = nullptr;
m_border = nullptr;
m_curveNormalVectors = nullptr;
m_vertices.clear();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> Riv3dWellLogDrawSurfaceGenerator::background() const
{
return m_background;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableGeo> Riv3dWellLogDrawSurfaceGenerator::border() const
{
return m_border;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<cvf::DrawableVectors> Riv3dWellLogDrawSurfaceGenerator::curveNormalVectors() const
{
return m_curveNormalVectors;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<cvf::Vec3d>& Riv3dWellLogDrawSurfaceGenerator::vertices() const
{
return m_vertices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void Riv3dWellLogDrawSurfaceGenerator::createCurveNormalVectors( const caf::DisplayCoordTransform* displayCoordTransform,
size_t clipStartIndex,
double planeOffsetFromWellPathCenter,
double planeWidth,
double samplingIntervalSize,
const std::vector<cvf::Vec3d>& segmentNormals )
{
std::vector<cvf::Vec3d> interpolatedWellPathPoints;
std::vector<cvf::Vec3d> interpolatedWellPathNormals;
double firstMd = wellPathGeometry()->measuredDepths().at( clipStartIndex );
double lastMd = wellPathGeometry()->measuredDepths().back();
double md = lastMd;
while ( md >= firstMd )
{
cvf::Vec3d point = wellPathGeometry()->interpolatedPointAlongWellPath( md );
point = displayCoordTransform->transformToDisplayCoord( point );
cvf::Vec3d curveNormal = wellPathGeometry()->interpolatedVectorValuesAlongWellPath( segmentNormals, md );
interpolatedWellPathPoints.push_back( point );
interpolatedWellPathNormals.push_back( curveNormal.getNormalized() );
md -= samplingIntervalSize;
}
std::vector<cvf::Vec3f> arrowVertices;
std::vector<cvf::Vec3f> arrowVectors;
arrowVertices.reserve( interpolatedWellPathPoints.size() );
arrowVectors.reserve( interpolatedWellPathPoints.size() );
double shaftRelativeRadius = 0.0125f;
double arrowHeadRelativeRadius = shaftRelativeRadius * 3;
double arrowHeadRelativeLength = arrowHeadRelativeRadius * 3;
double totalArrowScaling = 1.0 / ( 1.0 - arrowHeadRelativeLength );
// Normal lines. Start from one to avoid drawing at surface edge.
for ( size_t i = 1; i < interpolatedWellPathNormals.size(); i++ )
{
arrowVertices.push_back( cvf::Vec3f( interpolatedWellPathPoints[i] + interpolatedWellPathNormals[i] * planeOffsetFromWellPathCenter ) );
arrowVectors.push_back( cvf::Vec3f( interpolatedWellPathNormals[i] * planeWidth * totalArrowScaling ) );
}
if ( arrowVertices.empty() || arrowVectors.empty() )
{
return;
}
m_curveNormalVectors = new cvf::DrawableVectors();
cvf::ref<cvf::Vec3fArray> vertexArray = new cvf::Vec3fArray( arrowVertices );
cvf::ref<cvf::Vec3fArray> vectorArray = new cvf::Vec3fArray( arrowVectors );
// Create the arrow glyph for the vector drawer
cvf::GeometryBuilderTriangles arrowBuilder;
cvf::ArrowGenerator gen;
gen.setShaftRelativeRadius( shaftRelativeRadius );
gen.setHeadRelativeRadius( arrowHeadRelativeRadius );
gen.setHeadRelativeLength( arrowHeadRelativeLength );
gen.setNumSlices( 4 );
gen.generate( &arrowBuilder );
m_curveNormalVectors->setGlyph( arrowBuilder.trianglesUShort().p(), arrowBuilder.vertices().p() );
m_curveNormalVectors->setVectors( vertexArray.p(), vectorArray.p() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void Riv3dWellLogDrawSurfaceGenerator::createBackground( cvf::Vec3fArray* vertexArray )
{
std::vector<cvf::uint> backgroundIndices;
backgroundIndices.reserve( vertexArray->size() );
for ( size_t i = 0; i < vertexArray->size(); ++i )
{
backgroundIndices.push_back( ( cvf::uint )( i ) );
}
// Background specific
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUInt = new cvf::PrimitiveSetIndexedUInt( cvf::PrimitiveType::PT_TRIANGLE_STRIP );
cvf::ref<cvf::UIntArray> indexArray = new cvf::UIntArray( backgroundIndices );
indexedUInt->setIndices( indexArray.p() );
m_background = new cvf::DrawableGeo();
m_background->addPrimitiveSet( indexedUInt.p() );
m_background->setVertexArray( vertexArray );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void Riv3dWellLogDrawSurfaceGenerator::createBorder( cvf::Vec3fArray* vertexArray )
{
std::vector<cvf::uint> borderIndices;
borderIndices.reserve( m_vertices.size() );
int secondLastEvenVertex = (int)vertexArray->size() - 4;
// Border close to the well. All even indices.
for ( int i = 0; i <= secondLastEvenVertex; i += 2 )
{
borderIndices.push_back( (cvf::uint)i );
borderIndices.push_back( (cvf::uint)i + 2 );
}
// Connect to border away from well
borderIndices.push_back( ( cvf::uint )( vertexArray->size() - 2 ) );
borderIndices.push_back( ( cvf::uint )( vertexArray->size() - 1 ) );
int secondOddVertex = 3;
int lastOddVertex = (int)vertexArray->size() - 1;
// Border away from from well are odd indices in reverse order to create a closed surface.
for ( int i = lastOddVertex; i >= secondOddVertex; i -= 2 )
{
borderIndices.push_back( (cvf::uint)i );
borderIndices.push_back( (cvf::uint)i - 2 );
}
// Close border
borderIndices.push_back( 1u );
borderIndices.push_back( 0u );
cvf::ref<cvf::PrimitiveSetIndexedUInt> indexedUInt = new cvf::PrimitiveSetIndexedUInt( cvf::PrimitiveType::PT_LINES );
cvf::ref<cvf::UIntArray> indexArray = new cvf::UIntArray( borderIndices );
indexedUInt->setIndices( indexArray.p() );
m_border = new cvf::DrawableGeo();
m_border->addPrimitiveSet( indexedUInt.p() );
m_border->setVertexArray( vertexArray );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigWellPath* Riv3dWellLogDrawSurfaceGenerator::wellPathGeometry() const
{
return m_wellPath->wellPathGeometry();
}