///////////////////////////////////////////////////////////////////////////////// // // 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 "RivNNCGeometryGenerator.h" #include #include "RigCell.h" #include "RigMainGrid.h" #include "RigNNCData.h" #include "cvfDrawableGeo.h" #include "cvfPrimitiveSetIndexedUInt.h" #include "cvfScalarMapper.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivNNCGeometryGenerator::RivNNCGeometryGenerator( bool includeAllan, RigNNCData* nncData, const cvf::Vec3d& offset, const std::vector& nncIndexes ) : m_includeAllanDiagramGeometry( includeAllan ) , m_nncData( nncData ) , m_nncIndexes( nncIndexes ) , m_offset( offset ) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivNNCGeometryGenerator::~RivNNCGeometryGenerator() { } //-------------------------------------------------------------------------------------------------- /// Generate surface drawable geo from the specified region //-------------------------------------------------------------------------------------------------- cvf::ref RivNNCGeometryGenerator::generateSurface() { computeArrays(); CVF_ASSERT( m_vertices.notNull() ); if ( m_vertices->size() == 0 ) return nullptr; cvf::ref geo = new cvf::DrawableGeo; geo->setFromTriangleVertexArray( m_vertices.p() ); return geo; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivNNCGeometryGenerator::computeArrays() { std::vector vertices; std::vector triangleToNNC; const cvf::Vec3f offset( m_offset ); long long numConnections = static_cast( m_nncIndexes.empty() ? m_nncData->allConnections().size() : m_nncIndexes.size() ); bool isVisibilityCalcActive = m_cellVisibility.notNull() && m_grid.notNull(); RigMainGrid* mainGrid = nullptr; if ( isVisibilityCalcActive ) { mainGrid = m_grid->mainGrid(); } #pragma omp parallel for ordered for ( long long nIdx = 0; nIdx < numConnections; ++nIdx ) { size_t conIdx = m_nncIndexes.empty() ? nIdx : m_nncIndexes[nIdx]; if ( !m_includeAllanDiagramGeometry && conIdx >= m_nncData->eclipseConnectionCount() ) { continue; } const RigConnection& conn = m_nncData->allConnections()[conIdx]; if ( !conn.polygon().empty() ) { bool isVisible = true; if ( isVisibilityCalcActive ) { bool cell1Visible = false; bool cell2Visible = false; if ( mainGrid->cell( conn.c1GlobIdx() ).hostGrid() == m_grid.p() ) { size_t cell1GridLocalIdx = mainGrid->cell( conn.c1GlobIdx() ).gridLocalCellIndex(); cell1Visible = ( *m_cellVisibility )[cell1GridLocalIdx]; } if ( mainGrid->cell( conn.c2GlobIdx() ).hostGrid() == m_grid.p() ) { size_t cell2GridLocalIdx = mainGrid->cell( conn.c2GlobIdx() ).gridLocalCellIndex(); cell2Visible = ( *m_cellVisibility )[cell2GridLocalIdx]; } isVisible = cell1Visible || cell2Visible; } if ( isVisible ) { cvf::Vec3f vx1 = conn.polygon()[0] - offset; cvf::Vec3f vx2; cvf::Vec3f vx3 = conn.polygon()[1] - offset; for ( size_t vxIdx = 2; vxIdx < conn.polygon().size(); ++vxIdx ) { vx2 = vx3; vx3 = conn.polygon()[vxIdx] - offset; #pragma omp critical( critical_section_RivNNCGeometryGenerator_computeArrays ) { vertices.push_back( vx1 ); vertices.push_back( vx2 ); vertices.push_back( vx3 ); triangleToNNC.push_back( conIdx ); } } } } } m_vertices = new cvf::Vec3fArray; m_vertices->assign( vertices ); m_triangleIndexToNNCIndex = new cvf::Array; m_triangleIndexToNNCIndex->assign( triangleToNNC ); } //-------------------------------------------------------------------------------------------------- /// Calculates the texture coordinates in a "nearly" one dimensional texture. /// Undefined values are coded with a y-texture coordinate value of 1.0 instead of the normal 0.5 //-------------------------------------------------------------------------------------------------- void RivNNCGeometryGenerator::textureCoordinates( cvf::Vec2fArray* textureCoords, const cvf::ScalarMapper* mapper, RiaDefines::ResultCatType resultType, const RigEclipseResultAddress& resVarAddr, size_t nativeTimeStepIndex ) const { size_t numVertices = m_vertices->size(); textureCoords->resize( numVertices ); cvf::Vec2f* rawPtr = textureCoords->ptr(); const std::vector* nncResultVals = nullptr; if ( resultType == RiaDefines::ResultCatType::STATIC_NATIVE || resultType == RiaDefines::ResultCatType::FORMATION_NAMES || resultType == RiaDefines::ResultCatType::ALLAN_DIAGRAMS ) { nncResultVals = m_nncData->staticConnectionScalarResult( resVarAddr ); } else if ( resultType == RiaDefines::ResultCatType::DYNAMIC_NATIVE ) { nncResultVals = m_nncData->dynamicConnectionScalarResult( resVarAddr, nativeTimeStepIndex ); } else if ( resultType == RiaDefines::ResultCatType::GENERATED ) { nncResultVals = m_nncData->generatedConnectionScalarResult( resVarAddr, nativeTimeStepIndex ); } if ( !nncResultVals || nncResultVals->empty() ) { textureCoords->setAll( cvf::Vec2f( 0.0f, 1.0f ) ); return; } #pragma omp parallel for for ( int tIdx = 0; tIdx < static_cast( m_triangleIndexToNNCIndex->size() ); tIdx++ ) { double cellScalarValue = HUGE_VAL; size_t resultIndex = ( *m_triangleIndexToNNCIndex )[tIdx]; // The nnc connections can have more connections than reported from Eclipse, clamp the result index to Eclipse // Results if ( resultIndex < nncResultVals->size() ) { cellScalarValue = ( *nncResultVals )[resultIndex]; } cvf::Vec2f texCoord = mapper->mapToTextureCoord( cellScalarValue ); if ( cellScalarValue == HUGE_VAL || cellScalarValue != cellScalarValue ) // a != a is true for NAN's { texCoord[1] = 1.0f; } size_t j; for ( j = 0; j < 3; j++ ) { rawPtr[tIdx * 3 + j] = texCoord; } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivNNCGeometryGenerator::setCellVisibility( const cvf::UByteArray* cellVisibility, const RigGridBase* grid ) { m_cellVisibility = cellVisibility; m_grid = grid; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref> RivNNCGeometryGenerator::triangleToNNCIndex() const { return m_triangleIndexToNNCIndex; }