///////////////////////////////////////////////////////////////////////////////// // // 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 "RivSurfacePartMgr.h" #include "RigSurface.h" #include "RimSurface.h" #include "RimSurfaceInView.h" #include "RigHexIntersectionTools.h" #include "RigResultAccessor.h" #include "RigResultAccessorFactory.h" #include "RimCase.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" #include "RimEclipseResultDefinition.h" #include "RimEclipseView.h" #include "RimGeoMechCellColors.h" #include "RimGeoMechResultDefinition.h" #include "RimGeoMechView.h" #include "RimRegularLegendConfig.h" #include "RimTernaryLegendConfig.h" #include "RivHexGridIntersectionTools.h" #include "RivScalarMapperUtils.h" #include "RivTernaryScalarMapper.h" #include "cafEffectGenerator.h" #include "cvfDrawableGeo.h" #include "cvfModelBasicList.h" #include "cvfPart.h" #include "cvfPrimitiveSetIndexedUInt.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivSurfacePartMgr::RivSurfacePartMgr( RimSurfaceInView* surface ) : m_surfaceInView( surface ) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivSurfacePartMgr::appendNativeGeometryPartsToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform ) { if ( m_nativeTrianglesPart.isNull() || m_surfaceInView->surface()->surfaceData() != m_usedSurfaceData.p() ) { generateNativePartGeometry(); } if ( m_nativeTrianglesPart.notNull() ) { m_nativeTrianglesPart->setTransform( scaleTransform ); this->applySingleColor(); model->addPart( m_nativeTrianglesPart.p() ); if ( m_nativeMeshLinesPart.notNull() ) { m_nativeMeshLinesPart->setTransform( scaleTransform ); model->addPart( m_nativeMeshLinesPart.p() ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivSurfacePartMgr::updateCellResultColor( size_t timeStepIndex ) { if ( !m_vertexToCellIndexMap.size() ) { generateVertexToCellIndexMap(); } RimGridView* gridView = nullptr; m_surfaceInView->firstAncestorOrThisOfType( gridView ); if ( !gridView ) return; bool isLightingDisabled = gridView->isLightingDisabled(); RimEclipseResultDefinition* eclipseResDef = nullptr; RimGeoMechResultDefinition* geomResultDef = nullptr; const cvf::ScalarMapper* scalarColorMapper = nullptr; const RivTernaryScalarMapper* ternaryColorMapper = nullptr; // Ordinary result if ( !eclipseResDef && !geomResultDef ) { RimEclipseView* eclipseView = nullptr; m_surfaceInView->firstAncestorOrThisOfType( eclipseView ); if ( eclipseView ) { eclipseResDef = eclipseView->cellResult(); if ( !scalarColorMapper ) scalarColorMapper = eclipseView->cellResult()->legendConfig()->scalarMapper(); if ( !ternaryColorMapper ) ternaryColorMapper = eclipseView->cellResult()->ternaryLegendConfig()->scalarMapper(); } RimGeoMechView* geoView; m_surfaceInView->firstAncestorOrThisOfType( geoView ); if ( geoView ) { geomResultDef = geoView->cellResult(); if ( !scalarColorMapper ) scalarColorMapper = geoView->cellResult()->legendConfig()->scalarMapper(); } } cvf::ref intersectionFacesTextureCoords = new cvf::Vec2fArray(); if ( eclipseResDef ) { if ( !eclipseResDef->isTernarySaturationSelected() ) { RigEclipseCaseData* eclipseCaseData = eclipseResDef->eclipseCase()->eclipseCaseData(); cvf::ref resultAccessor; if ( !RiaDefines::isPerCellFaceResult( eclipseResDef->resultVariable() ) ) { resultAccessor = RigResultAccessorFactory::createFromResultDefinition( eclipseCaseData, 0, timeStepIndex, eclipseResDef ); } if ( resultAccessor.isNull() ) { resultAccessor = new RigHugeValResultAccessor; } RivSurfacePartMgr::calculateVertexTextureCoordinates( intersectionFacesTextureCoords.p(), m_vertexToCellIndexMap, resultAccessor.p(), scalarColorMapper ); RivScalarMapperUtils::applyTextureResultsToPart( m_nativeTrianglesPart.p(), intersectionFacesTextureCoords.p(), scalarColorMapper, 1.0, caf::FC_NONE, isLightingDisabled ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivSurfacePartMgr::applySingleColor() { if ( m_nativeTrianglesPart.notNull() ) { caf::SurfaceEffectGenerator surfaceGen( cvf::Color4f( m_surfaceInView->surface()->color() ), caf::PO_1 ); cvf::ref eff = surfaceGen.generateCachedEffect(); m_nativeTrianglesPart->setEffect( eff.p() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivSurfacePartMgr::generateNativePartGeometry() { RimCase* ownerCase; m_surfaceInView->firstAncestorOrThisOfTypeAsserted( ownerCase ); cvf::Vec3d displayModOffsett = ownerCase->displayModelOffset(); m_usedSurfaceData = m_surfaceInView->surface()->surfaceData(); const std::vector& vertices = m_usedSurfaceData->vertices(); cvf::ref cvfVertices = new cvf::Vec3fArray( vertices.size() ); for ( size_t i = 0; i < vertices.size(); ++i ) { ( *cvfVertices )[i] = cvf::Vec3f( vertices[i] - displayModOffsett ); } const std::vector& triangleIndices = m_usedSurfaceData->triangleIndices(); cvf::ref cvfIndices = new cvf::UIntArray( triangleIndices ); cvf::ref indexSet = new cvf::PrimitiveSetIndexedUInt( cvf::PT_TRIANGLES ); indexSet->setIndices( cvfIndices.p() ); cvf::ref drawGeo = new cvf::DrawableGeo; drawGeo->addPrimitiveSet( indexSet.p() ); drawGeo->setVertexArray( cvfVertices.p() ); drawGeo->computeNormals(); m_nativeTrianglesPart = new cvf::Part(); m_nativeTrianglesPart->setDrawable( drawGeo.p() ); m_vertexToCellIndexMap.clear(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivSurfacePartMgr::generateVertexToCellIndexMap() { cvf::ref hexGrid = m_surfaceInView->createHexGridInterface(); const std::vector& vertices = m_usedSurfaceData->vertices(); m_vertexToCellIndexMap.resize( vertices.size(), -1 ); for ( size_t vxIdx = 0; vxIdx < vertices.size(); ++vxIdx ) { cvf::BoundingBox box; box.add( vertices[vxIdx] ); std::vector cellCandidates; hexGrid->findIntersectingCells( box, &cellCandidates ); for ( size_t cellIdx : cellCandidates ) { cvf::Vec3d cellCorners[8]; hexGrid->cellCornerVertices( cellIdx, cellCorners ); if ( RigHexIntersectionTools::isPointInCell( vertices[vxIdx], cellCorners ) ) { m_vertexToCellIndexMap[vxIdx] = cellIdx; break; } } } } //-------------------------------------------------------------------------------------------------- /// Calculates the texture coordinates in a "nearly" one dimensional texture. /// Undefined values are coded with a y-texturecoordinate value of 1.0 instead of the normal 0.5 //-------------------------------------------------------------------------------------------------- void RivSurfacePartMgr::calculateVertexTextureCoordinates( cvf::Vec2fArray* textureCoords, const std::vector& vertexToCellIdxMap, const RigResultAccessor* resultAccessor, const cvf::ScalarMapper* mapper ) { if ( !resultAccessor ) return; size_t numVertices = vertexToCellIdxMap.size(); textureCoords->resize( numVertices ); cvf::Vec2f* rawPtr = textureCoords->ptr(); #pragma omp parallel for for ( int vxIdx = 0; vxIdx < numVertices; vxIdx++ ) { double cellScalarValue = resultAccessor->cellScalarGlobIdx( vertexToCellIdxMap[vxIdx] ); cvf::Vec2f texCoord = mapper->mapToTextureCoord( cellScalarValue ); if ( cellScalarValue == HUGE_VAL || cellScalarValue != cellScalarValue ) // a != a is true for NAN's { texCoord[1] = 1.0f; } rawPtr[vxIdx] = texCoord; } }