///////////////////////////////////////////////////////////////////////////////// // // 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 "RivFaultGeometryGenerator.h" #include #include "cvfDrawableGeo.h" #include "cvfOutlineEdgeExtractor.h" #include "cvfPrimitiveSetIndexedUInt.h" #include "cvfStructGridGeometryGenerator.h" #include "cvfScalarMapper.h" #include "RigFault.h" #include "RigNNCData.h" #include "RigNncConnection.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivFaultGeometryGenerator::RivFaultGeometryGenerator( const cvf::StructGridInterface* grid, const RigFault* fault, RigNNCData* nncData, bool computeNativeFaultFaces ) : m_grid( grid ) , m_fault( fault ) , m_computeNativeFaultFaces( computeNativeFaultFaces ) , m_nncData( nncData ) { m_quadMapper = new cvf::StructGridQuadToCellFaceMapper; m_triangleMapper = new cvf::StuctGridTriangleToCellFaceMapper( m_quadMapper.p() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivFaultGeometryGenerator::~RivFaultGeometryGenerator() { } //-------------------------------------------------------------------------------------------------- /// Generate surface drawable geo from the specified region //-------------------------------------------------------------------------------------------------- cvf::ref RivFaultGeometryGenerator::generateSurface( bool onlyShowFacesWithDefinedNeighbors ) { computeArrays( onlyShowFacesWithDefinedNeighbors ); CVF_ASSERT( m_vertices.notNull() ); if ( m_vertices->size() == 0 ) return nullptr; cvf::ref geo = new cvf::DrawableGeo; geo->setFromQuadVertexArray( m_vertices.p() ); return geo; } //-------------------------------------------------------------------------------------------------- /// Generates simplified mesh as line drawing /// Must call generateSurface first //-------------------------------------------------------------------------------------------------- cvf::ref RivFaultGeometryGenerator::createMeshDrawable() { if ( !( m_vertices.notNull() && m_vertices->size() != 0 ) ) return nullptr; cvf::ref geo = new cvf::DrawableGeo; geo->setVertexArray( m_vertices.p() ); cvf::ref indices = cvf::StructGridGeometryGenerator::lineIndicesFromQuadVertexArray( m_vertices.p() ); cvf::ref prim = new cvf::PrimitiveSetIndexedUInt( cvf::PT_LINES ); prim->setIndices( indices.p() ); geo->addPrimitiveSet( prim.p() ); return geo; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivFaultGeometryGenerator::createOutlineMeshDrawable( double creaseAngle ) { if ( !( m_vertices.notNull() && m_vertices->size() != 0 ) ) return nullptr; cvf::OutlineEdgeExtractor ee( creaseAngle, *m_vertices ); cvf::ref indices = cvf::StructGridGeometryGenerator::lineIndicesFromQuadVertexArray( m_vertices.p() ); ee.addPrimitives( 4, *indices ); cvf::ref lineIndices = ee.lineIndices(); if ( lineIndices->size() == 0 ) { return nullptr; } cvf::ref prim = new cvf::PrimitiveSetIndexedUInt( cvf::PT_LINES ); prim->setIndices( lineIndices.p() ); cvf::ref geo = new cvf::DrawableGeo; geo->setVertexArray( m_vertices.p() ); geo->addPrimitiveSet( prim.p() ); return geo; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RivFaultGeometryGenerator::hasConnection( size_t cellIdx, cvf::StructGridInterface::FaceType face, const RigConnectionContainer& conns, const std::vector& nncConnectionIndices ) { cvf::StructGridInterface::FaceType oppositeFace = cvf::StructGridInterface::oppositeFace( face ); for ( auto i : nncConnectionIndices ) { if ( i >= conns.size() ) continue; const auto& r = conns[i]; if ( ( r.c1GlobIdx() == cellIdx ) && ( r.face() == face ) && r.hasCommonArea() ) return true; if ( ( r.c2GlobIdx() == cellIdx ) && ( r.face() == oppositeFace ) && r.hasCommonArea() ) return true; } return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivFaultGeometryGenerator::computeArrays( bool onlyShowFacesWithDefinedNeighbors ) { std::vector vertices; m_quadMapper->quadToCellIndexMap().clear(); m_quadMapper->quadToCellFaceMap().clear(); cvf::Vec3d offset = m_grid->displayModelOffset(); if ( onlyShowFacesWithDefinedNeighbors ) { // Make sure the connection polygon is computed, as this is used as criteria for visibility m_nncData->ensureAllConnectionDataIsProcessed(); } auto connIndices = m_fault->connectionIndices(); auto& connections = m_nncData->availableConnections(); const std::vector& faultFaces = m_fault->faultFaces(); #pragma omp parallel for for ( int fIdx = 0; fIdx < static_cast( faultFaces.size() ); fIdx++ ) { size_t cellIndex = faultFaces[fIdx].m_nativeReservoirCellIndex; cvf::StructGridInterface::FaceType face = faultFaces[fIdx].m_nativeFace; if ( !m_computeNativeFaultFaces ) { cellIndex = faultFaces[fIdx].m_oppositeReservoirCellIndex; face = cvf::StructGridInterface::oppositeFace( face ); } if ( cellIndex >= m_cellVisibility->size() ) continue; if ( !( *m_cellVisibility )[cellIndex] ) continue; if ( onlyShowFacesWithDefinedNeighbors && !hasConnection( cellIndex, face, connections, connIndices ) ) continue; cvf::Vec3d cornerVerts[8]; m_grid->cellCornerVertices( cellIndex, cornerVerts ); cvf::ubyte faceConn[4]; m_grid->cellFaceVertexIndices( face, faceConn ); // Critical section to avoid two threads accessing the arrays at the same time. #pragma omp critical( critical_section_RivFaultGeometryGenerator_computeArrays ) { int n; for ( n = 0; n < 4; n++ ) { vertices.push_back( cvf::Vec3f( cornerVerts[faceConn[n]] - offset ) ); } // Keep track of the source cell index per quad m_quadMapper->quadToCellIndexMap().push_back( cellIndex ); m_quadMapper->quadToCellFaceMap().push_back( face ); } } m_vertices = new cvf::Vec3fArray; m_vertices->assign( vertices ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivFaultGeometryGenerator::setCellVisibility( const cvf::UByteArray* cellVisibility ) { m_cellVisibility = cellVisibility; }