mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 15:10:22 -05:00
504 lines
18 KiB
C++
504 lines
18 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2025 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 "RimRegularSurface.h"
|
|
|
|
#include "RiaLogging.h"
|
|
#include "RiaQStringFormatter.h"
|
|
|
|
#include "Surface/RigSurface.h"
|
|
|
|
#include "RimSurfaceCollection.h"
|
|
|
|
#include "cafPdmFieldScriptingCapability.h"
|
|
#include "cafPdmObjectScriptingCapability.h"
|
|
#include "cafPdmUiDoubleSliderEditor.h"
|
|
|
|
#include "cvfVector3.h"
|
|
|
|
#include <numbers>
|
|
|
|
CAF_PDM_SOURCE_INIT( RimRegularSurface, "RegularSurface" );
|
|
|
|
namespace internal
|
|
{
|
|
QString fixedDepth()
|
|
{
|
|
return "FIXED_DEPTH";
|
|
}
|
|
} // namespace internal
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimRegularSurface::RimRegularSurface()
|
|
{
|
|
CAF_PDM_InitScriptableObject( "RegularSurface", ":/ReservoirSurface16x16.png" );
|
|
|
|
CAF_PDM_InitScriptableField( &m_originX, "OriginX", 0.0, "Origin X" );
|
|
CAF_PDM_InitScriptableField( &m_originY, "OriginY", 0.0, "Origin Y" );
|
|
CAF_PDM_InitScriptableField( &m_depth, "Depth", 0.0, "Depth" );
|
|
m_depth.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
|
|
|
CAF_PDM_InitScriptableField( &m_nx, "Nx", 10, "Nx" );
|
|
CAF_PDM_InitScriptableField( &m_ny, "Ny", 10, "Ny" );
|
|
CAF_PDM_InitScriptableField( &m_incrementX, "IncrementX", 20.0, "Increment X" );
|
|
CAF_PDM_InitScriptableField( &m_incrementY, "IncrementY", 20.0, "Increment Y" );
|
|
|
|
CAF_PDM_InitScriptableField( &m_rotation, "Rotation", 0.0, "Rotation" );
|
|
|
|
CAF_PDM_InitScriptableField( &m_depthProperty, "DepthProperty", internal::fixedDepth(), "Depth Property" );
|
|
m_rotation.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimRegularSurface::onLoadData()
|
|
{
|
|
clearCachedNativeData();
|
|
return updateSurfaceData();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimSurface* RimRegularSurface::createCopy()
|
|
{
|
|
return copyObject<RimRegularSurface>();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
|
{
|
|
RimSurface::fieldChangedByUi( changedField, oldValue, newValue );
|
|
|
|
if ( changedField == &m_nx || changedField == &m_ny )
|
|
{
|
|
// Invalidate all properties when dimensions changes
|
|
m_properties.clear();
|
|
m_depthProperty = "";
|
|
}
|
|
|
|
clearCachedNativeData();
|
|
updateSurfaceData();
|
|
|
|
auto surfColl = firstAncestorOrThisOfTypeAsserted<RimSurfaceCollection>();
|
|
surfColl->updateViews( { this } );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
|
|
{
|
|
RimSurface::defineEditorAttribute( field, uiConfigName, attribute );
|
|
|
|
if ( field == &m_rotation )
|
|
{
|
|
if ( auto attr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute ) )
|
|
{
|
|
attr->m_minimum = 0.0;
|
|
attr->m_maximum = 360.0;
|
|
}
|
|
}
|
|
|
|
if ( field == &m_depth )
|
|
{
|
|
if ( auto attr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute ) )
|
|
{
|
|
attr->m_minimum = 0.0;
|
|
attr->m_maximum = 10000.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
|
{
|
|
auto locationGroup = uiOrdering.addNewGroup( "Location" );
|
|
locationGroup->add( &m_originX );
|
|
locationGroup->add( &m_originY );
|
|
locationGroup->add( &m_depthProperty );
|
|
|
|
if ( m_depthProperty() == internal::fixedDepth() )
|
|
{
|
|
locationGroup->add( &m_depth );
|
|
}
|
|
|
|
auto extentGroup = uiOrdering.addNewGroup( "Extent" );
|
|
extentGroup->add( &m_nx );
|
|
extentGroup->add( &m_ny );
|
|
extentGroup->add( &m_incrementX );
|
|
extentGroup->add( &m_incrementY );
|
|
|
|
uiOrdering.add( &m_rotation );
|
|
uiOrdering.add( &m_depthOffset );
|
|
|
|
// Fields from RimSurface
|
|
auto appearanceGroup = uiOrdering.addNewGroup( "Appearance" );
|
|
appearanceGroup->add( &m_userDescription );
|
|
appearanceGroup->add( &m_color );
|
|
|
|
appearanceGroup->add( &m_enableOpacity );
|
|
appearanceGroup->add( &m_opacity );
|
|
|
|
uiOrdering.skipRemainingFields();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setFieldsReadOnly( bool enable )
|
|
{
|
|
m_nx.uiCapability()->setUiReadOnly( enable );
|
|
m_ny.uiCapability()->setUiReadOnly( enable );
|
|
m_originX.uiCapability()->setUiReadOnly( enable );
|
|
m_originY.uiCapability()->setUiReadOnly( enable );
|
|
m_incrementX.uiCapability()->setUiReadOnly( enable );
|
|
m_incrementY.uiCapability()->setUiReadOnly( enable );
|
|
m_rotation.uiCapability()->setUiReadOnly( enable );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QList<caf::PdmOptionItemInfo> RimRegularSurface::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
|
|
{
|
|
QList<caf::PdmOptionItemInfo> options;
|
|
if ( fieldNeedingOptions == &m_depthProperty )
|
|
{
|
|
options.push_back( caf::PdmOptionItemInfo( "Fixed Depth", internal::fixedDepth() ) );
|
|
|
|
for ( const auto& [key, value] : m_properties )
|
|
{
|
|
options.push_back( caf::PdmOptionItemInfo( key, key ) );
|
|
}
|
|
}
|
|
return options;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::clearCachedNativeData()
|
|
{
|
|
m_vertices.clear();
|
|
m_triangleIndices.clear();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns false for fatal failure
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RimRegularSurface::updateSurfaceData()
|
|
{
|
|
if ( m_depthProperty() != internal::fixedDepth() && !m_properties.contains( m_depthProperty() ) )
|
|
{
|
|
RiaLogging::warning( std::format( "Surface '{}': Depth property '{}' not found.", userDescription(), m_depthProperty() ) );
|
|
setSurfaceData( nullptr );
|
|
|
|
return false;
|
|
}
|
|
|
|
// Adapted from xtgeo surf_xyz_from_ij
|
|
auto computeXyzFromIj =
|
|
[]( int i, int j, double depth, double xori, double yori, double xinc, double yinc, double rotationDegrees ) -> cvf::Vec3d
|
|
{
|
|
CAF_ASSERT( i >= 0 );
|
|
CAF_ASSERT( j >= 0 );
|
|
|
|
double z = -depth;
|
|
|
|
if ( i == 0 && j == 0 ) return cvf::Vec3d( xori, yori, z );
|
|
|
|
// Surface rotation: this should be the usual angle, anti-clock from x axis,
|
|
// radians, positive
|
|
const double angle = rotationDegrees * std::numbers::pi / 180.0;
|
|
|
|
const double xdist = xinc * i;
|
|
const double ydist = yinc * j;
|
|
|
|
// Distance of point from "origo"
|
|
const double dist = sqrt( xdist * xdist + ydist * ydist );
|
|
|
|
const double beta = acos( xdist / dist );
|
|
|
|
if ( beta < 0 || beta > std::numbers::pi / 2.0 || std::isnan( beta ) ) return cvf::Vec3d::UNDEFINED;
|
|
|
|
// The difference in rotated coord system
|
|
double gamma = angle + beta;
|
|
|
|
double dxrot = dist * cos( gamma );
|
|
double dyrot = dist * sin( gamma );
|
|
|
|
return cvf::Vec3d( xori + dxrot, yori + dyrot, z );
|
|
};
|
|
|
|
for ( int j = 0; j < m_ny(); j++ )
|
|
{
|
|
for ( int i = 0; i < m_nx(); i++ )
|
|
{
|
|
double depth = m_depth;
|
|
if ( !m_depthProperty().isEmpty() && m_properties.contains( m_depthProperty ) && m_depthProperty() != internal::fixedDepth() )
|
|
{
|
|
depth = m_properties[m_depthProperty][j * m_nx + i];
|
|
}
|
|
m_vertices.push_back( computeXyzFromIj( i, j, depth, m_originX, m_originY, m_incrementX, m_incrementY, m_rotation ) );
|
|
}
|
|
}
|
|
|
|
// Iterate through the entire grid
|
|
for ( int j = 0; j < m_ny() - 1; j++ )
|
|
{
|
|
for ( int i = 0; i < m_nx() - 1; i++ )
|
|
{
|
|
// Calculate the indices of the four vertices in the current cell
|
|
// Top-left vertex
|
|
size_t idx00 = j * m_nx() + i;
|
|
// Top-right vertex
|
|
size_t idx01 = j * m_nx() + ( i + 1 );
|
|
// Bottom-left vertex
|
|
size_t idx10 = ( j + 1 ) * m_nx() + i;
|
|
// Bottom-right vertex
|
|
size_t idx11 = ( j + 1 ) * m_nx() + ( i + 1 );
|
|
|
|
// First triangle (top-left, top-right, bottom-left)
|
|
m_triangleIndices.push_back( static_cast<unsigned>( idx00 ) );
|
|
m_triangleIndices.push_back( static_cast<unsigned>( idx01 ) );
|
|
m_triangleIndices.push_back( static_cast<unsigned>( idx10 ) );
|
|
|
|
// Second triangle (top-right, bottom-right, bottom-left)
|
|
m_triangleIndices.push_back( static_cast<unsigned>( idx01 ) );
|
|
m_triangleIndices.push_back( static_cast<unsigned>( idx11 ) );
|
|
m_triangleIndices.push_back( static_cast<unsigned>( idx10 ) );
|
|
}
|
|
}
|
|
|
|
if ( !m_triangleIndices.empty() )
|
|
{
|
|
std::vector<unsigned> tringleIndices{ m_triangleIndices };
|
|
std::vector<cvf::Vec3d> vertices{ m_vertices };
|
|
|
|
cvf::Vec3d offset;
|
|
offset.z() += depthOffset();
|
|
|
|
RimSurface::applyDepthOffset( offset, &vertices );
|
|
auto surfaceData = new RigSurface;
|
|
surfaceData->setTriangleData( tringleIndices, vertices );
|
|
|
|
for ( auto& [key, vec] : m_properties )
|
|
{
|
|
surfaceData->addVertexResult( key, vec );
|
|
}
|
|
|
|
setSurfaceData( surfaceData );
|
|
}
|
|
else
|
|
{
|
|
setSurfaceData( nullptr );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setOriginX( double originX )
|
|
{
|
|
m_originX = originX;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setOriginY( double originY )
|
|
{
|
|
m_originY = originY;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setNx( int nx )
|
|
{
|
|
CAF_ASSERT( nx > 0 );
|
|
m_nx = nx;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setNy( int ny )
|
|
{
|
|
CAF_ASSERT( ny > 0 );
|
|
m_ny = ny;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setDepth( double depth )
|
|
{
|
|
m_depth = depth;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setIncrementX( double incrementX )
|
|
{
|
|
CAF_ASSERT( incrementX > 0.0 );
|
|
m_incrementX = incrementX;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setIncrementY( double incrementY )
|
|
{
|
|
CAF_ASSERT( incrementY > 0.0 );
|
|
m_incrementY = incrementY;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setRotation( double rotation )
|
|
{
|
|
CAF_ASSERT( rotation >= 0.0 && rotation <= 360.0 );
|
|
m_rotation = rotation;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setProperty( const QString& key, const std::vector<float>& values )
|
|
{
|
|
CAF_ASSERT( values.size() == static_cast<size_t>( m_nx() * m_ny() ) );
|
|
m_properties[key] = values;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRegularSurface::setPropertyAsDepth( const QString& key )
|
|
{
|
|
m_depthProperty = key;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<float> RimRegularSurface::getProperty( const QString& key ) const
|
|
{
|
|
auto it = m_properties.find( key );
|
|
if ( it != m_properties.end() ) return it->second;
|
|
return {};
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<QString> RimRegularSurface::propertyNames() const
|
|
{
|
|
std::vector<QString> names;
|
|
for ( const auto& [key, value] : m_properties )
|
|
{
|
|
names.push_back( key );
|
|
}
|
|
return names;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
int RimRegularSurface::nx() const
|
|
{
|
|
return m_nx;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
int RimRegularSurface::ny() const
|
|
{
|
|
return m_ny;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimRegularSurface::originX() const
|
|
{
|
|
return m_originX;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimRegularSurface::originY() const
|
|
{
|
|
return m_originY;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimRegularSurface::incrementX() const
|
|
{
|
|
return m_incrementX;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimRegularSurface::incrementY() const
|
|
{
|
|
return m_incrementY;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RimRegularSurface::rotation() const
|
|
{
|
|
return m_rotation;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns the depth values for all grid points in row-major order (index = j * nx + i).
|
|
/// Uses the active depth property if set, otherwise returns the fixed depth value.
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<float> RimRegularSurface::depthValues() const
|
|
{
|
|
const int size = m_nx * m_ny;
|
|
|
|
if ( m_depthProperty() != internal::fixedDepth() && !m_depthProperty().isEmpty() )
|
|
{
|
|
auto it = m_properties.find( m_depthProperty() );
|
|
if ( it != m_properties.end() ) return it->second;
|
|
}
|
|
|
|
return std::vector<float>( size, static_cast<float>( m_depth() ) );
|
|
}
|