///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) Statoil ASA // Copyright (C) Ceetron Solutions AS // // 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 "RivSingleCellPartGenerator.h" #include "RiaPreferencesGrid.h" #include "RigCell.h" #include "RigEclipseCaseData.h" #include "RigFemPartCollection.h" #include "RigGeoMechCaseData.h" #include "RigGridBase.h" #include "RigReservoirGridTools.h" #include "RimEclipseCase.h" #include "RimGeoMechCase.h" #include "RivFemPartGeometryGenerator.h" #include "RivPartPriority.h" #include "cafEffectGenerator.h" #include "cvfPart.h" #include "cvfPrimitiveSetIndexedUInt.h" #include "cvfRenderStateDepth.h" #include "cvfStructGridGeometryGenerator.h" using namespace cvf; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivSingleCellPartGenerator::RivSingleCellPartGenerator( RigEclipseCaseData* rigCaseData, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& displayModelOffset ) : m_rigCaseData( rigCaseData ) , m_gridIndex( gridIndex ) , m_cellIndex( cellIndex ) , m_geoMechCase( nullptr ) , m_displayModelOffset( displayModelOffset ) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivSingleCellPartGenerator::RivSingleCellPartGenerator( RimGeoMechCase* rimGeoMechCase, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& displayModelOffset ) : m_geoMechCase( rimGeoMechCase ) , m_gridIndex( gridIndex ) , m_cellIndex( cellIndex ) , m_rigCaseData( nullptr ) , m_displayModelOffset( displayModelOffset ) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivSingleCellPartGenerator::setShowLgrMeshLines( bool enable ) { m_showLgrMeshLines = enable; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivSingleCellPartGenerator::setDisplacementData( double scaleFactor, const std::vector& displacements ) { m_displacementScaleFactor = scaleFactor; m_displacements = displacements; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivSingleCellPartGenerator::createPart( const cvf::Color3f color ) { cvf::ref part = new cvf::Part; part->setName( cvf::String( "Highlight part for cell index " ) + cvf::String( (cvf::int64)m_cellIndex ) ); part->setDrawable( createMeshDrawable().p() ); cvf::ref eff; caf::MeshEffectGenerator effGen( color ); eff = effGen.generateUnCachedEffect(); cvf::ref depth = new cvf::RenderStateDepth; depth->enableDepthTest( false ); eff->setRenderState( depth.p() ); part->setEffect( eff.p() ); part->setPriority( RivPartPriority::PartType::Highlight ); return part; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivSingleCellPartGenerator::createMeshLinesOfParentGridCells( RigGridBase const* grid, std::vector& localGridCellIndices, const cvf::Vec3d& displayModelOffset ) { if ( !grid ) return nullptr; // create a map with parent cell index as key and vector of local grid cell indices as value std::map> parentCellToLocalGridCellsMap; for ( auto cellIndex : localGridCellIndices ) { const auto cell = grid->cell( cellIndex ); auto parentCellIndex = cell.parentCellIndex(); parentCellToLocalGridCellsMap[parentCellIndex].push_back( cellIndex ); } std::vector quadVertices; std::vector lineVertexPairs; for ( const auto& [cellIndexInMainGrid, lgrCellIndices] : parentCellToLocalGridCellsMap ) { for ( auto cellIndex : lgrCellIndices ) { std::array cornerVerts = grid->cellCornerVertices( cellIndex ); cvf::ubyte faceConn[4]; // Show grid lines for vertical lines along the radius of the cylinder segment RigGridBase::cellFaceVertexIndices( cvf::StructGridInterface::NEG_I, faceConn ); lineVertexPairs.push_back( cornerVerts[faceConn[1]] ); lineVertexPairs.push_back( cornerVerts[faceConn[2]] ); lineVertexPairs.push_back( cornerVerts[faceConn[3]] ); lineVertexPairs.push_back( cornerVerts[faceConn[0]] ); // Show grid lines for vertical lines along the radius of the cylinder segment RigGridBase::cellFaceVertexIndices( cvf::StructGridInterface::POS_I, faceConn ); lineVertexPairs.push_back( cornerVerts[faceConn[0]] ); lineVertexPairs.push_back( cornerVerts[faceConn[1]] ); lineVertexPairs.push_back( cornerVerts[faceConn[2]] ); lineVertexPairs.push_back( cornerVerts[faceConn[3]] ); // Show quad lines for min/max J faces if ( cellIndex == lgrCellIndices.back() ) { RigGridBase::cellFaceVertexIndices( cvf::StructGridInterface::POS_J, faceConn ); quadVertices.push_back( cornerVerts[faceConn[0]] ); quadVertices.push_back( cornerVerts[faceConn[1]] ); quadVertices.push_back( cornerVerts[faceConn[2]] ); quadVertices.push_back( cornerVerts[faceConn[3]] ); } if ( cellIndex == lgrCellIndices.front() ) { RigGridBase::cellFaceVertexIndices( cvf::StructGridInterface::NEG_J, faceConn ); quadVertices.push_back( cornerVerts[faceConn[0]] ); quadVertices.push_back( cornerVerts[faceConn[1]] ); quadVertices.push_back( cornerVerts[faceConn[2]] ); quadVertices.push_back( cornerVerts[faceConn[3]] ); } } } std::vector displayVertices; for ( const auto& v : quadVertices ) { displayVertices.push_back( cvf::Vec3f( v - displayModelOffset ) ); } cvf::ref cvfVertices = new cvf::Vec3fArray; cvfVertices->assign( displayVertices ); if ( !cvfVertices.notNull() || cvfVertices->size() == 0 ) return nullptr; ref indices = StructGridGeometryGenerator::lineIndicesFromQuadVertexArray( cvfVertices.p() ); // Add vertex pairs as lines const auto quadVertexCount = cvfVertices->size(); const auto indicesCount = indices->size(); cvfVertices->resize( quadVertexCount + lineVertexPairs.size() ); indices->resize( indicesCount + lineVertexPairs.size() ); size_t iIndex = indicesCount; size_t vIndex = quadVertexCount; for ( const auto& v : lineVertexPairs ) { indices->set( iIndex++, static_cast( vIndex ) ); cvfVertices->set( vIndex++, cvf::Vec3f( v - displayModelOffset ) ); } ref geo = new DrawableGeo; geo->setVertexArray( cvfVertices.p() ); ref prim = new PrimitiveSetIndexedUInt( PT_LINES ); prim->setIndices( indices.p() ); geo->addPrimitiveSet( prim.p() ); return geo; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivSingleCellPartGenerator::createMeshDrawable() { if ( m_rigCaseData && m_cellIndex != cvf::UNDEFINED_SIZE_T ) { auto mainGrid = m_rigCaseData->mainGrid(); if ( !mainGrid ) return nullptr; if ( m_gridIndex >= mainGrid->gridCount() ) return nullptr; auto grid = m_rigCaseData->grid( m_gridIndex ); if ( !grid ) return nullptr; // The selection can be stale after the case data has been reloaded, and the cell index can be out of bounds if ( m_cellIndex >= grid->cellCount() ) return nullptr; if ( m_showLgrMeshLines && RiaPreferencesGrid::current()->radialGridMode() == RiaGridDefines::RadialGridMode::CYLINDRICAL ) { return createMeshDrawableFromLgrGridCells(); } else { return cvf::StructGridGeometryGenerator::createMeshDrawableFromSingleCell( grid, m_cellIndex, m_displayModelOffset ); } } else if ( m_geoMechCase && m_cellIndex != cvf::UNDEFINED_SIZE_T ) { CAF_ASSERT( m_geoMechCase->geoMechData() ); CAF_ASSERT( m_geoMechCase->geoMechData()->femParts()->partCount() > static_cast( m_gridIndex ) ); RigFemPart* femPart = m_geoMechCase->geoMechData()->femParts()->part( m_gridIndex ); CAF_ASSERT( femPart ); return RivFemPartGeometryGenerator::createMeshDrawableFromSingleElement( femPart, m_cellIndex, m_displayModelOffset, m_displacements, m_displacementScaleFactor ); } return nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivSingleCellPartGenerator::createMeshDrawableFromLgrGridCells() { if ( !m_rigCaseData ) return nullptr; if ( m_cellIndex == cvf::UNDEFINED_SIZE_T ) return nullptr; auto mainGrid = m_rigCaseData->mainGrid(); if ( !mainGrid ) return nullptr; if ( mainGrid->gridCount() < 2 ) return nullptr; auto lgrGrid = m_rigCaseData->grid( 1 ); if ( !lgrGrid ) return nullptr; std::vector lgrCellIndices; for ( size_t i = 0; i < lgrGrid->cellCount(); i++ ) { const auto cell = lgrGrid->cell( i ); auto parentCellIndex = cell.parentCellIndex(); if ( parentCellIndex == m_cellIndex ) { lgrCellIndices.push_back( i ); } } return createMeshLinesOfParentGridCells( lgrGrid, lgrCellIndices, m_displayModelOffset ); }