///////////////////////////////////////////////////////////////////////////////// // // 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 // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RivStreamlinesPartMgr.h" #include "Rim3dView.h" #include "RimEclipseCase.h" #include "RimEclipseView.h" #include "RimRegularLegendConfig.h" #include "RimSimWellInView.h" #include "RimSimWellInViewCollection.h" #include "RimStreamlineInViewCollection.h" #include "RigActiveCellInfo.h" #include "RigCaseCellResultsData.h" #include "RigCell.h" #include "RigEclipseCaseData.h" #include "RigMainGrid.h" #include "RigSimulationWellCenterLineCalculator.h" #include "RigTracer.h" #include "RigTracerPoint.h" #include "RigWellResultPoint.h" #include "RiuViewer.h" #include "cafDisplayCoordTransform.h" #include "cafEffectGenerator.h" #include "cvfDrawableGeo.h" #include "cvfModelBasicList.h" #include "cvfPart.h" #include "cvfPrimitiveSetIndexedUInt.h" #include "cvfPrimitiveSetIndexedUIntScoped.h" #include "cvfShaderProgram.h" #include "cafPdmPointer.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivStreamlinesPartMgr::RivStreamlinesPartMgr( RimEclipseView* reservoirView ) { m_rimReservoirView = reservoirView; m_count = 0; m_currentT = 0; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivStreamlinesPartMgr::~RivStreamlinesPartMgr() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::appendDynamicGeometryPartsToModel( cvf::ModelBasicList* model, size_t timeStepIndex ) { m_streamlines.clear(); RimStreamlineInViewCollection* streamlineCollection = m_rimReservoirView->streamlineCollection(); if ( !streamlineCollection->isActive() ) return; CVF_ASSERT( model ); if ( m_rimReservoirView.isNull() ) return; RimEclipseCase* eclipseCase = m_rimReservoirView->eclipseCase(); if ( !eclipseCase ) return; RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); if ( !eclipseCaseData ) return; cvf::ref displayCordXf = m_rimReservoirView->displayCoordTransform(); for ( const RigTracer& tracer : streamlineCollection->tracers() ) { Streamline streamline; for ( size_t i = 0; i < tracer.tracerPoints().size() - 1; i++ ) { streamline.appendTracerPoint( tracer.tracerPoints()[i].position() ); streamline.appendAbsVelocity( tracer.tracerPoints()[i].absValue() ); streamline.appendPhase( tracer.tracerPoints()[i].phaseType() ); } m_streamlines.push_back( streamline ); } for ( Streamline& streamline : m_streamlines ) { if ( streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::ANIMATION || streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::MANUAL ) { if ( streamline.countTracerPoints() > 1 ) { model->addPart( createPart( *streamlineCollection, streamline ).p() ); } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::updateAnimation() { RimStreamlineInViewCollection* streamlineCollection = m_rimReservoirView->streamlineCollection(); if ( streamlineCollection && ( streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::ANIMATION || streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::MANUAL ) ) { for ( Streamline& streamline : m_streamlines ) { if ( streamline.getPart().notNull() && dynamic_cast( streamline.getPart()->drawable() ) ) { auto primitiveSet = dynamic_cast( static_cast( streamline.getPart()->drawable() )->primitiveSet( 0 ) ); if ( primitiveSet ) { size_t startIndex = 0; size_t endIndex = primitiveSet->indices()->size(); if ( streamlineCollection->visualizationMode() == RimStreamlineInViewCollection::VisualizationMode::ANIMATION ) { streamline.incrementAnimationIndex( streamlineCollection->animationSpeed() ); startIndex = streamline.getAnimationIndex(); // Make sure we have an even animation index, as this index is used to define start of a line // segment startIndex /= 2; startIndex *= 2; endIndex = std::min( endIndex, startIndex + streamlineCollection->tracerLength() ); } else { endIndex = std::min( endIndex, streamlineCollection->animationIndex() * 2 ); } primitiveSet->setScope( startIndex, endIndex - startIndex ); } } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivStreamlinesPartMgr::createPart( const RimStreamlineInViewCollection& streamlineCollection, Streamline& streamline ) { cvf::ref displayCordXf = m_rimReservoirView->displayCoordTransform(); std::vector indices; // Each point is used twice except the first and the last one indices.reserve( streamline.countTracerPoints() * 2 - 2 ); std::vector vertices; vertices.reserve( streamline.countTracerPoints() * 2 - 2 ); uint count = 0; for ( size_t i = 0; i < streamline.countTracerPoints(); i++ ) { vertices.push_back( cvf::Vec3f( displayCordXf->transformToDisplayCoord( streamline.getTracerPoint( i ) ) ) ); indices.push_back( count++ ); if ( i > 0 && i < streamline.countTracerPoints() - 1 ) { vertices.push_back( cvf::Vec3f( displayCordXf->transformToDisplayCoord( streamline.getTracerPoint( i ) ) ) ); indices.push_back( count++ ); } } cvf::ref indexedUIntLine = new cvf::PrimitiveSetIndexedUIntScoped( cvf::PrimitiveType::PT_LINES ); cvf::ref indexedArrayLine = new cvf::UIntArray( indices ); cvf::ref drawable = new cvf::DrawableGeo(); indexedUIntLine->setIndices( indexedArrayLine.p(), 0, 0 ); drawable->addPrimitiveSet( indexedUIntLine.p() ); cvf::ref vertexArray = new cvf::Vec3fArray( vertices ); drawable->setVertexArray( vertexArray.p() ); cvf::ref lineTexCoords = const_cast( drawable->textureCoordArray() ); if ( lineTexCoords.isNull() ) { lineTexCoords = new cvf::Vec2fArray; } cvf::ref effect; const cvf::ScalarMapper* activeScalarMapper = streamlineCollection.legendConfig()->scalarMapper(); createResultColorTextureCoords( lineTexCoords.p(), streamline, activeScalarMapper ); caf::ScalarMapperMeshEffectGenerator meshEffGen( activeScalarMapper ); effect = meshEffGen.generateCachedEffect(); drawable->setTextureCoordArray( lineTexCoords.p() ); cvf::ref part = new cvf::Part; part->setName( "RivStreamlinesPartMgr" ); part->setDrawable( drawable.p() ); part->setEffect( effect.p() ); part->updateBoundingBox(); streamline.setPart( part ); return part; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::createResultColorTextureCoords( cvf::Vec2fArray* textureCoords, const Streamline& streamline, const cvf::ScalarMapper* mapper ) { CVF_ASSERT( textureCoords ); CVF_ASSERT( mapper ); RimStreamlineInViewCollection* streamlineCollection = m_rimReservoirView->streamlineCollection(); CVF_ASSERT( streamlineCollection != nullptr ); size_t vertexCount = streamline.countTracerPoints() * 2 - 2; if ( textureCoords->capacity() != vertexCount ) textureCoords->reserve( vertexCount ); for ( size_t i = 0; i < streamline.countTracerPoints(); i++ ) { cvf::Vec2f texCoord = mapper->mapToTextureCoord( streamline.getAbsVelocity( i ) ); if ( streamlineCollection->colorMode() == RimStreamlineInViewCollection::ColorMode::PHASE_COLORS ) { double phaseValue = 0.0; auto phase = streamline.getPhase( i ); if ( phase == RiaDefines::PhaseType::GAS_PHASE ) { phaseValue = 1.0; } else if ( phase == RiaDefines::PhaseType::OIL_PHASE ) { phaseValue = 0.5; } else if ( phase == RiaDefines::PhaseType::WATER_PHASE ) { phaseValue = 0.0; } texCoord.x() = phaseValue; } textureCoords->add( texCoord ); if ( i > 0 && i < streamline.countTracerPoints() - 1 ) { textureCoords->add( texCoord ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::setAlpha( cvf::ref part, float alpha ) { if ( part.notNull() ) { caf::SurfaceEffectGenerator surfaceGen( cvf::Color4f( alpha, alpha, alpha, 1 ), caf::PO_1 ); surfaceGen.enableLighting( false ); cvf::ref effect = surfaceGen.generateCachedEffect(); part->setEffect( effect.p() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::Streamline::appendTracerPoint( cvf::Vec3d point ) { tracerPoints.push_back( point ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::Streamline::appendAbsVelocity( double velocity ) { absVelocities.push_back( velocity ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::Streamline::appendPhase( RiaDefines::PhaseType phase ) { dominantPhases.push_back( phase ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::Streamline::clear() { tracerPoints.clear(); absVelocities.clear(); dominantPhases.clear(); delete part.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivStreamlinesPartMgr::Streamline::getPart() { return part; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Vec3d RivStreamlinesPartMgr::Streamline::getTracerPoint( size_t index ) const { return tracerPoints[index]; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RivStreamlinesPartMgr::Streamline::getAbsVelocity( size_t index ) const { return absVelocities[index]; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiaDefines::PhaseType RivStreamlinesPartMgr::Streamline::getPhase( size_t index ) const { return dominantPhases[index]; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RivStreamlinesPartMgr::Streamline::countTracerPoints() const { return tracerPoints.size(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::Streamline::setPart( cvf::ref part ) { this->part = part; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RivStreamlinesPartMgr::Streamline::getAnimationIndex() const { return animIndex; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::Streamline::incrementAnimationIndex( size_t increment ) { animIndex += increment; // Make sure we have an even animation index, as this index is used to define start of a line segment animIndex /= 2; animIndex *= 2; if ( animIndex >= tracerPoints.size() * 2 - 2 ) { animIndex = 0.0; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivStreamlinesPartMgr::Streamline::setAnimationIndex( size_t index ) { animIndex = index; if ( animIndex >= tracerPoints.size() * 2 - 2 ) { animIndex = tracerPoints.size() * 2 - 2; } }