mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-03 20:57:39 -06:00
533 lines
19 KiB
C++
533 lines
19 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2019- 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 "RivWellDiskPartMgr.h"
|
|
|
|
#include "RiaColorTools.h"
|
|
#include "RiaGuiApplication.h"
|
|
|
|
#include "RigActiveCellInfo.h"
|
|
#include "RigCell.h"
|
|
#include "Well/RigSimWellData.h"
|
|
#include "Well/RigWellResultFrame.h"
|
|
|
|
#include "RimEclipseCase.h"
|
|
#include "RimEclipseView.h"
|
|
#include "RimSimWellInView.h"
|
|
#include "RimSimWellInViewCollection.h"
|
|
|
|
#include "RivDiskGeometryGenerator.h"
|
|
#include "RivPartPriority.h"
|
|
#include "RivSectionFlattener.h"
|
|
#include "RivSimWellPipeSourceInfo.h"
|
|
#include "RivTextLabelSourceInfo.h"
|
|
|
|
#include "cafDisplayCoordTransform.h"
|
|
#include "cafEffectGenerator.h"
|
|
|
|
#include "cvfDrawableGeo.h"
|
|
#include "cvfDrawableText.h"
|
|
#include "cvfEffect.h"
|
|
#include "cvfGeometryBuilderDrawableGeo.h"
|
|
#include "cvfGeometryBuilderFaceList.h"
|
|
#include "cvfGeometryBuilderTriangles.h"
|
|
#include "cvfGeometryUtils.h"
|
|
#include "cvfModelBasicList.h"
|
|
#include "cvfPart.h"
|
|
#include "cvfRenderState_FF.h"
|
|
#include "cvfShaderProgram.h"
|
|
#include "cvfShaderProgramGenerator.h"
|
|
#include "cvfShaderSourceProvider.h"
|
|
#include "cvfShaderSourceRepository.h"
|
|
#include "cvfTransform.h"
|
|
#include "cvfUniform.h"
|
|
#include "cvfqtUtils.h"
|
|
|
|
#include <cmath>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RivWellDiskPartMgr::RivWellDiskPartMgr( RimSimWellInView* well )
|
|
: m_rimWell( well )
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RivWellDiskPartMgr::~RivWellDiskPartMgr()
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RivWellDiskPartMgr::buildWellDiskParts( size_t frameIndex, const caf::DisplayCoordTransform* displayXf )
|
|
{
|
|
clearAllGeometry();
|
|
|
|
if ( !viewWithSettings() ) return;
|
|
|
|
RimSimWellInView* well = m_rimWell;
|
|
|
|
double characteristicCellSize = viewWithSettings()->characteristicCellSize();
|
|
|
|
cvf::Vec3d whEndPos;
|
|
cvf::Vec3d whStartPos;
|
|
{
|
|
well->wellHeadTopBottomPosition( static_cast<int>( frameIndex ), &whEndPos, &whStartPos );
|
|
|
|
whEndPos = displayXf->transformToDisplayCoord( whEndPos );
|
|
whEndPos.z() += characteristicCellSize;
|
|
}
|
|
|
|
if ( !well->simWellData()->hasWellResult( frameIndex ) ) return;
|
|
|
|
auto productionType = well->simWellData()->wellResultFrame( frameIndex )->productionType();
|
|
|
|
double pipeRadius = m_rimWell->pipeRadius();
|
|
unsigned int numSectors = 100;
|
|
|
|
// Upper part of simulation well pipe is defined to use branch index 0
|
|
cvf::ref<RivSimWellPipeSourceInfo> sourceInfo = new RivSimWellPipeSourceInfo( m_rimWell, 0 );
|
|
|
|
// Well disk geometry
|
|
double arrowLength = characteristicCellSize * simWellInViewCollection()->wellHeadScaleFactor() * m_rimWell->wellHeadScaleFactor();
|
|
|
|
cvf::Vec3d diskPosition = whEndPos;
|
|
diskPosition.z() += pipeRadius + arrowLength * 2.0;
|
|
|
|
cvf::Vec3d textPosition = diskPosition;
|
|
textPosition.z() += 0.1;
|
|
|
|
double ijScaleFactor = arrowLength / 6;
|
|
ijScaleFactor *= simWellInViewCollection()->wellDiskScaleFactor();
|
|
|
|
cvf::ref<cvf::DrawableGeo> geo1 = new cvf::DrawableGeo;
|
|
{
|
|
cvf::Mat4f matr;
|
|
|
|
matr( 0, 0 ) *= ijScaleFactor;
|
|
matr( 1, 1 ) *= ijScaleFactor;
|
|
matr( 2, 2 ) *= ijScaleFactor;
|
|
|
|
matr.setTranslation( cvf::Vec3f( diskPosition ) );
|
|
|
|
cvf::GeometryBuilderFaceList builder;
|
|
{
|
|
RivDiskGeometryGenerator gen;
|
|
gen.setRelativeRadius( baseScaleFactor() * m_rimWell->diskScale() );
|
|
gen.setRelativeLength( 0.1f );
|
|
gen.setNumSlices( numSectors );
|
|
gen.generate( &builder );
|
|
}
|
|
|
|
cvf::ref<cvf::Vec3fArray> vertices = builder.vertices();
|
|
cvf::ref<cvf::UIntArray> faceList = builder.faceList();
|
|
|
|
for ( size_t i = 0; i < vertices->size(); i++ )
|
|
{
|
|
cvf::Vec3f v = vertices->get( i );
|
|
v.transformPoint( matr );
|
|
vertices->set( i, v );
|
|
}
|
|
|
|
geo1->setVertexArray( vertices.p() );
|
|
geo1->setFromFaceList( *faceList );
|
|
geo1->computeNormals();
|
|
}
|
|
|
|
// Create the fixed function effect
|
|
{
|
|
m_fixedFuncEffect = new cvf::Effect;
|
|
|
|
cvf::ref<cvf::RenderStateMaterial_FF> mat = new cvf::RenderStateMaterial_FF( cvf::Color3::BLUE );
|
|
mat->enableColorMaterial( true );
|
|
m_fixedFuncEffect->setRenderState( mat.p() );
|
|
|
|
cvf::ref<cvf::RenderStateLighting_FF> lighting = new cvf::RenderStateLighting_FF;
|
|
m_fixedFuncEffect->setRenderState( lighting.p() );
|
|
}
|
|
|
|
// Create effect with shader program
|
|
{
|
|
m_shaderEffect = new cvf::Effect;
|
|
|
|
cvf::ShaderProgramGenerator gen( "PerVertexColor", cvf::ShaderSourceProvider::instance() );
|
|
gen.addVertexCode( cvf::ShaderSourceRepository::vs_Standard );
|
|
|
|
gen.addFragmentCode( cvf::ShaderSourceRepository::src_VaryingColorGlobalAlpha );
|
|
gen.addFragmentCode( cvf::ShaderSourceRepository::fs_Unlit );
|
|
m_shaderProg = gen.generate();
|
|
|
|
m_shaderProg->setDefaultUniform( new cvf::UniformFloat( "u_alpha", 1.0f ) );
|
|
|
|
m_shaderEffect->setShaderProgram( m_shaderProg.p() );
|
|
}
|
|
|
|
cvf::ref<cvf::Effect> effectToUse = RiaGuiApplication::instance()->useShaders() ? m_shaderEffect : m_fixedFuncEffect;
|
|
|
|
const cvf::Color3ub colorTable[] = { cvf::Color3ub( 0, 177, 89 ), // Green
|
|
cvf::Color3ub( 255, 66, 66 ), // Red
|
|
cvf::Color3ub( 66, 66, 255 ) }; // Blue
|
|
|
|
size_t vertexCount = geo1->vertexCount();
|
|
cvf::ref<cvf::Color3ubArray> colorArray = new cvf::Color3ubArray;
|
|
colorArray->resize( vertexCount );
|
|
colorArray->setAll( cvf::Color3::WHITE );
|
|
CVF_ASSERT( vertexCount == numSectors * 3 );
|
|
|
|
std::vector<std::pair<cvf::String, cvf::Vec3f>> labelsWithPosition;
|
|
|
|
double accumulatedPropertyValue = 0.0;
|
|
const double valueThresholdForLabel = 1e-6;
|
|
|
|
QString labelText;
|
|
if ( m_rimWell->showWellLabel() )
|
|
{
|
|
labelText = m_rimWell->name();
|
|
}
|
|
|
|
RigWellDiskData diskData = m_rimWell->wellDiskData();
|
|
if ( diskData.isSingleProperty() )
|
|
{
|
|
// Set color for the triangle vertices
|
|
cvf::Color3ub c = cvf::Color3ub( m_rimWell->wellDiskColor );
|
|
for ( size_t i = 0; i < numSectors * 3; i++ )
|
|
{
|
|
colorArray->set( i, c );
|
|
}
|
|
|
|
accumulatedPropertyValue = diskData.singlePropertyValue();
|
|
|
|
if ( simWellInViewCollection()->showWellDiskQuantityLables() )
|
|
{
|
|
if ( diskData.singlePropertyValue() > valueThresholdForLabel )
|
|
{
|
|
const double singleProperty = diskData.singlePropertyValueSigned();
|
|
labelText += QString( "\n%2" ).arg( RivWellDiskPartMgr::formatNumber( singleProperty ) );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const double oil = diskData.oil();
|
|
const double gas = diskData.gas();
|
|
const double water = diskData.water();
|
|
|
|
const double total = diskData.total();
|
|
const double oilFraction = oil / total;
|
|
const double gasFraction = gas / total;
|
|
const double waterFraction = water / total;
|
|
|
|
accumulatedPropertyValue = total;
|
|
|
|
if ( total > valueThresholdForLabel )
|
|
{
|
|
double aggregatedFraction = 0.0;
|
|
|
|
if ( oilFraction > valueThresholdForLabel )
|
|
{
|
|
auto p = createTextAndLocation( oilFraction / 2.0, diskPosition, ijScaleFactor, diskData.oilSigned() );
|
|
|
|
labelsWithPosition.push_back( p );
|
|
aggregatedFraction += oilFraction;
|
|
}
|
|
|
|
if ( gasFraction > valueThresholdForLabel )
|
|
{
|
|
auto p = createTextAndLocation( aggregatedFraction + gasFraction / 2.0, diskPosition, ijScaleFactor, diskData.gasSigned() );
|
|
labelsWithPosition.push_back( p );
|
|
aggregatedFraction += gasFraction;
|
|
}
|
|
|
|
if ( waterFraction > valueThresholdForLabel )
|
|
{
|
|
auto p = createTextAndLocation( aggregatedFraction + waterFraction / 2.0, diskPosition, ijScaleFactor, diskData.waterSigned() );
|
|
|
|
labelsWithPosition.push_back( p );
|
|
aggregatedFraction += waterFraction;
|
|
}
|
|
}
|
|
|
|
for ( size_t i = 0; i < numSectors; i++ )
|
|
{
|
|
int colorIdx = 0;
|
|
|
|
// Find the color for this sector
|
|
double lim = ( i + 1 ) / static_cast<double>( numSectors );
|
|
if ( lim <= oilFraction )
|
|
{
|
|
colorIdx = 0;
|
|
}
|
|
else if ( lim <= oilFraction + gasFraction )
|
|
{
|
|
colorIdx = 1;
|
|
}
|
|
else
|
|
{
|
|
colorIdx = 2;
|
|
}
|
|
|
|
// Set color for the triangle vertices
|
|
for ( int t = 0; t < 3; t++ )
|
|
{
|
|
cvf::Color3ub c = colorTable[colorIdx];
|
|
colorArray->set( i * 3 + t, c );
|
|
}
|
|
}
|
|
}
|
|
geo1->setColorArray( colorArray.p() );
|
|
|
|
if ( accumulatedPropertyValue > valueThresholdForLabel )
|
|
{
|
|
{
|
|
cvf::ref<cvf::Part> part = new cvf::Part;
|
|
part->setName( "RivWellDiskPartMgr: disk " + cvfqt::Utils::toString( well->name() ) );
|
|
part->setDrawable( geo1.p() );
|
|
|
|
part->setEffect( effectToUse.p() );
|
|
part->setSourceInfo( sourceInfo.p() );
|
|
|
|
m_wellDiskPart = part;
|
|
}
|
|
|
|
// Add visual indicator for well type injector
|
|
if ( RiaDefines::isInjector( productionType ) )
|
|
{
|
|
cvf::GeometryBuilderFaceList builder;
|
|
cvf::Vec3f pos( 0.0, 0.0, 0.0 );
|
|
|
|
// Construct a cross using to "bars"
|
|
cvf::GeometryUtils::createBox( pos, 0.2f, 0.8f, 0.1f, &builder );
|
|
cvf::GeometryUtils::createBox( pos, 0.8f, 0.2f, 0.1f, &builder );
|
|
|
|
cvf::ref<cvf::Vec3fArray> vertices = builder.vertices();
|
|
cvf::ref<cvf::UIntArray> faceList = builder.faceList();
|
|
|
|
cvf::Mat4f matr;
|
|
matr( 0, 0 ) *= ijScaleFactor;
|
|
matr( 1, 1 ) *= ijScaleFactor;
|
|
matr( 2, 2 ) *= ijScaleFactor;
|
|
matr.setTranslation( cvf::Vec3f( diskPosition ) );
|
|
|
|
for ( size_t i = 0; i < vertices->size(); i++ )
|
|
{
|
|
cvf::Vec3f v = vertices->get( i );
|
|
v.transformPoint( matr );
|
|
vertices->set( i, v );
|
|
}
|
|
|
|
cvf::Color4f injectorMarkerColor = getWellInjectionColor( productionType );
|
|
caf::SurfaceEffectGenerator surfaceGen( injectorMarkerColor, caf::PO_1 );
|
|
surfaceGen.enableLighting( false );
|
|
cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect();
|
|
|
|
cvf::ref<cvf::DrawableGeo> injectorGeo = new cvf::DrawableGeo;
|
|
injectorGeo->setVertexArray( vertices.p() );
|
|
injectorGeo->setFromFaceList( *faceList );
|
|
injectorGeo->computeNormals();
|
|
|
|
cvf::ref<cvf::Part> part = new cvf::Part;
|
|
part->setName( "RivWellDiskPartMgr: injector " + cvfqt::Utils::toString( well->name() ) );
|
|
part->setDrawable( injectorGeo.p() );
|
|
|
|
part->setEffect( eff.p() );
|
|
part->setSourceInfo( sourceInfo.p() );
|
|
|
|
m_wellDiskInjectorPart = part;
|
|
}
|
|
}
|
|
|
|
if ( well->showWellDisks() )
|
|
{
|
|
cvf::Font* font = RiaGuiApplication::instance()->defaultWellLabelFont();
|
|
|
|
cvf::ref<cvf::DrawableText> drawableText = new cvf::DrawableText;
|
|
drawableText->setFont( font );
|
|
drawableText->setCheckPosVisible( false );
|
|
drawableText->setDrawBorder( false );
|
|
|
|
drawableText->setDrawBackground( simWellInViewCollection()->showWellDiskLabelBackground() );
|
|
drawableText->setVerticalAlignment( cvf::TextDrawer::CENTER );
|
|
|
|
auto textColor = simWellInViewCollection()->wellLabelColor();
|
|
drawableText->setTextColor( textColor );
|
|
|
|
auto bgColor = RiaColorTools::contrastColor( textColor, true );
|
|
drawableText->setBackgroundColor( bgColor );
|
|
|
|
cvf::String cvfString = cvfqt::Utils::toString( labelText );
|
|
|
|
if ( !cvfString.isEmpty() )
|
|
{
|
|
cvf::Vec3f textCoord( textPosition );
|
|
drawableText->addText( cvfString, textCoord );
|
|
}
|
|
|
|
if ( simWellInViewCollection()->showWellDiskQuantityLables() )
|
|
{
|
|
for ( const auto& t : labelsWithPosition )
|
|
{
|
|
drawableText->addText( t.first, t.second );
|
|
}
|
|
}
|
|
|
|
if ( drawableText->numberOfTexts() > 0 )
|
|
{
|
|
cvf::ref<cvf::Part> part = new cvf::Part;
|
|
part->setName( "RivWellDiskPartMgr: text " + cvfString );
|
|
part->setDrawable( drawableText.p() );
|
|
|
|
cvf::ref<cvf::Effect> eff = new cvf::Effect;
|
|
|
|
part->setEffect( eff.p() );
|
|
part->setPriority( RivPartPriority::PartType::Text );
|
|
|
|
m_wellDiskLabelPart = part;
|
|
}
|
|
}
|
|
}
|
|
|
|
QString RivWellDiskPartMgr::formatNumber( double num )
|
|
{
|
|
if ( std::fabs( num ) < 1e4 )
|
|
return QString::number( num, 'f', 1 );
|
|
else
|
|
return QString::number( num, 'g', 2 );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::pair<cvf::String, cvf::Vec3f> RivWellDiskPartMgr::createTextAndLocation( const double aggregatedFraction,
|
|
cvf::Vec3d diskPosition,
|
|
double ijScaleFactor,
|
|
const double fraction )
|
|
{
|
|
double sinA = cvf::Math::sin( aggregatedFraction * 2.0 * cvf::PI_F );
|
|
double cosA = cvf::Math::cos( aggregatedFraction * 2.0 * cvf::PI_F );
|
|
|
|
cvf::Vec3f v = cvf::Vec3f( diskPosition );
|
|
|
|
double radius = baseScaleFactor() * m_rimWell->diskScale();
|
|
radius *= ijScaleFactor;
|
|
radius *= 1.1; // Put label outside the disk
|
|
|
|
v.x() = v.x() + static_cast<float>( -sinA * radius );
|
|
v.y() = v.y() + static_cast<float>( cosA * radius );
|
|
|
|
auto s = RivWellDiskPartMgr::formatNumber( fraction );
|
|
cvf::String text = cvf::String( s.toStdString() );
|
|
|
|
auto p = std::make_pair( text, v );
|
|
|
|
return p;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RivWellDiskPartMgr::clearAllGeometry()
|
|
{
|
|
m_wellDiskPart = nullptr;
|
|
m_wellDiskLabelPart = nullptr;
|
|
m_wellDiskInjectorPart = nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RivWellDiskPartMgr::appendDynamicGeometryPartsToModel( cvf::ModelBasicList* model,
|
|
size_t frameIndex,
|
|
const caf::DisplayCoordTransform* displayXf )
|
|
{
|
|
if ( m_rimWell.isNull() ) return;
|
|
if ( !viewWithSettings() ) return;
|
|
|
|
if ( !m_rimWell->isWellDiskVisible() ) return;
|
|
if ( !m_rimWell->isValidDisk() ) return;
|
|
|
|
buildWellDiskParts( frameIndex, displayXf );
|
|
|
|
if ( m_rimWell->showWellDisks() && m_wellDiskLabelPart.notNull() )
|
|
{
|
|
model->addPart( m_wellDiskLabelPart.p() );
|
|
}
|
|
|
|
if ( m_rimWell->showWellDisks() && m_wellDiskPart.notNull() )
|
|
{
|
|
model->addPart( m_wellDiskPart.p() );
|
|
}
|
|
|
|
if ( m_rimWell->showWellDisks() && m_wellDiskInjectorPart.notNull() )
|
|
{
|
|
model->addPart( m_wellDiskInjectorPart.p() );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
Rim3dView* RivWellDiskPartMgr::viewWithSettings()
|
|
{
|
|
if ( m_rimWell ) return m_rimWell->firstAncestorOrThisOfType<Rim3dView>();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimSimWellInViewCollection* RivWellDiskPartMgr::simWellInViewCollection()
|
|
{
|
|
if ( m_rimWell ) return m_rimWell->firstAncestorOrThisOfType<RimSimWellInViewCollection>();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
cvf::Color4f RivWellDiskPartMgr::getWellInjectionColor( RiaDefines::WellProductionType productionType )
|
|
{
|
|
if ( productionType == RiaDefines::WellProductionType::OIL_INJECTOR )
|
|
{
|
|
return cvf::Color4f( cvf::Color3::ORANGE );
|
|
}
|
|
else if ( productionType == RiaDefines::WellProductionType::GAS_INJECTOR )
|
|
{
|
|
return cvf::Color4f( cvf::Color3::RED );
|
|
}
|
|
else if ( productionType == RiaDefines::WellProductionType::WATER_INJECTOR )
|
|
{
|
|
return cvf::Color4f( cvf::Color3::BLUE );
|
|
}
|
|
|
|
return cvf::Color4f( cvf::Color3::BLACK );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double RivWellDiskPartMgr::baseScaleFactor()
|
|
{
|
|
return 10.0;
|
|
}
|