///////////////////////////////////////////////////////////////////////////////// // // 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 "RivIntersectionPartMgr.h" #include "RiaGuiApplication.h" #include "RiaOffshoreSphericalCoords.h" #include "RiaPreferences.h" #include "RigCaseCellResultsData.h" #include "RigFemPartCollection.h" #include "RigFemPartResultsCollection.h" #include "RigGeoMechCaseData.h" #include "RigResultAccessor.h" #include "RigResultAccessorFactory.h" #include "Rim2dIntersectionView.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" #include "RimEclipseView.h" #include "RimFaultInView.h" #include "RimFaultInViewCollection.h" #include "RimGeoMechCase.h" #include "RimGeoMechCellColors.h" #include "RimGeoMechView.h" #include "RimIntersection.h" #include "RimRegularLegendConfig.h" #include "RimSimWellInView.h" #include "RimSimWellInViewCollection.h" #include "RimTernaryLegendConfig.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" #include "RiuGeoMechXfTensorResultAccessor.h" #include "RivHexGridIntersectionTools.h" #include "RivIntersectionGeometryGenerator.h" #include "RivIntersectionResultsColoringTools.h" #include "RivIntersectionSourceInfo.h" #include "RivMeshLinesSourceInfo.h" #include "RivObjectSourceInfo.h" #include "RivPartPriority.h" #include "RivPipeGeometryGenerator.h" #include "RivResultToTextureMapper.h" #include "RivScalarMapperUtils.h" #include "RivSimWellPipeSourceInfo.h" #include "RivTernaryScalarMapper.h" #include "RivTernaryTextureCoordsCreator.h" #include "RivWellPathSourceInfo.h" #include "cafTensor3.h" #include "cvfDrawableGeo.h" #include "cvfDrawableText.h" #include "cvfGeometryTools.h" #include "cvfModelBasicList.h" #include "cvfPart.h" #include "cvfPrimitiveSetDirect.h" #include "cvfRenderStateDepth.h" #include "cvfRenderStatePoint.h" #include "cvfRenderState_FF.h" #include "cvfStructGridGeometryGenerator.h" #include "cvfTransform.h" #include "cvfqtUtils.h" #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivIntersectionPartMgr::RivIntersectionPartMgr( RimIntersection* rimCrossSection, bool isFlattened ) : m_rimCrossSection( rimCrossSection ) , m_isFlattened( isFlattened ) { CVF_ASSERT( m_rimCrossSection ); m_crossSectionFacesTextureCoords = new cvf::Vec2fArray; cvf::Vec3d flattenedPolylineStartPoint; std::vector> polyLines = m_rimCrossSection->polyLines( &flattenedPolylineStartPoint ); if ( polyLines.size() > 0 ) { cvf::Vec3d direction = m_rimCrossSection->extrusionDirection(); cvf::ref hexGrid = m_rimCrossSection->createHexGridInterface(); m_crossSectionGenerator = new RivIntersectionGeometryGenerator( m_rimCrossSection, polyLines, direction, hexGrid.p(), m_isFlattened, flattenedPolylineStartPoint ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivIntersectionPartMgr::applySingleColorEffect() { if ( m_crossSectionGenerator.isNull() ) return; caf::SurfaceEffectGenerator geometryEffgen( cvf::Color3f::OLIVE, caf::PO_1 ); cvf::ref geometryOnlyEffect = geometryEffgen.generateCachedEffect(); if ( m_crossSectionFaces.notNull() ) { m_crossSectionFaces->setEffect( geometryOnlyEffect.p() ); } // Update mesh colors as well, in case of change RiaPreferences* prefs = RiaApplication::instance()->preferences(); if ( m_crossSectionGridLines.notNull() ) { cvf::ref eff; caf::MeshEffectGenerator CrossSectionEffGen( prefs->defaultGridLineColors() ); eff = CrossSectionEffGen.generateCachedEffect(); m_crossSectionGridLines->setEffect( eff.p() ); } if ( m_crossSectionFaultGridLines.notNull() ) { cvf::ref eff; caf::MeshEffectGenerator CrossSectionEffGen( prefs->defaultFaultGridLineColors() ); eff = CrossSectionEffGen.generateCachedEffect(); m_crossSectionFaultGridLines->setEffect( eff.p() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivIntersectionPartMgr::updateCellResultColor( size_t timeStepIndex, const cvf::ScalarMapper* scalarColorMapper, const RivTernaryScalarMapper* ternaryColorMapper ) { RivIntersectionResultsColoringTools::updateCellResultColorStatic( timeStepIndex, m_rimCrossSection, m_crossSectionGenerator.p(), scalarColorMapper, ternaryColorMapper, m_crossSectionFaces.p(), m_crossSectionFacesTextureCoords.p() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivIntersectionResultsColoringTools::calculateNodeOrElementNodeBasedGeoMechTextureCoords( cvf::Vec2fArray* textureCoords, const std::vector& vertexWeights, const std::vector& resultValues, bool isElementNodalResult, const RigFemPart* femPart, const cvf::ScalarMapper* mapper ) { textureCoords->resize( vertexWeights.size() ); if ( resultValues.size() == 0 ) { textureCoords->setAll( cvf::Vec2f( 0.0, 1.0f ) ); } else { cvf::Vec2f* rawPtr = textureCoords->ptr(); int vxCount = static_cast( vertexWeights.size() ); #pragma omp parallel for schedule( dynamic ) for ( int triangleVxIdx = 0; triangleVxIdx < vxCount; ++triangleVxIdx ) { float resValue = 0; int weightCount = vertexWeights[triangleVxIdx].size(); for ( int wIdx = 0; wIdx < weightCount; ++wIdx ) { size_t resIdx; if ( isElementNodalResult ) { resIdx = vertexWeights[triangleVxIdx].vxId( wIdx ); } else { resIdx = femPart->nodeIdxFromElementNodeResultIdx( vertexWeights[triangleVxIdx].vxId( wIdx ) ); } resValue += resultValues[resIdx] * vertexWeights[triangleVxIdx].weight( wIdx ); } if ( resValue == HUGE_VAL || resValue != resValue ) // a != a is true for NAN's { rawPtr[triangleVxIdx][1] = 1.0f; } else { rawPtr[triangleVxIdx] = mapper->mapToTextureCoord( resValue ); } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivIntersectionPartMgr::generatePartGeometry() { if ( m_crossSectionGenerator.isNull() ) return; bool useBufferObjects = true; // Surface geometry { cvf::ref geo = m_crossSectionGenerator->generateSurface(); if ( geo.notNull() ) { geo->computeNormals(); if ( useBufferObjects ) { geo->setRenderMode( cvf::DrawableGeo::BUFFER_OBJECT ); } cvf::ref part = new cvf::Part; part->setName( "Cross Section" ); part->setDrawable( geo.p() ); // Set mapping from triangle face index to cell index cvf::ref si = new RivIntersectionSourceInfo( m_crossSectionGenerator.p() ); part->setSourceInfo( si.p() ); part->updateBoundingBox(); part->setEnableMask( intersectionCellFaceBit ); part->setPriority( RivPartPriority::PartType::Intersection ); m_crossSectionFaces = part; } } // Cell Mesh geometry { cvf::ref geoMesh = m_crossSectionGenerator->createMeshDrawable(); if ( geoMesh.notNull() ) { if ( useBufferObjects ) { geoMesh->setRenderMode( cvf::DrawableGeo::BUFFER_OBJECT ); } cvf::ref part = new cvf::Part; part->setName( "Cross Section mesh" ); part->setDrawable( geoMesh.p() ); part->updateBoundingBox(); part->setEnableMask( intersectionCellMeshBit ); part->setPriority( RivPartPriority::PartType::MeshLines ); part->setSourceInfo( new RivMeshLinesSourceInfo( m_rimCrossSection ) ); m_crossSectionGridLines = part; } } // Fault Mesh geometry { cvf::ref geoMesh = m_crossSectionGenerator->createFaultMeshDrawable(); if ( geoMesh.notNull() ) { if ( useBufferObjects ) { geoMesh->setRenderMode( cvf::DrawableGeo::BUFFER_OBJECT ); } cvf::ref part = new cvf::Part; part->setName( "Cross Section faultmesh" ); part->setDrawable( geoMesh.p() ); part->updateBoundingBox(); part->setEnableMask( intersectionFaultMeshBit ); part->setPriority( RivPartPriority::PartType::FaultMeshLines ); part->setSourceInfo( new RivMeshLinesSourceInfo( m_rimCrossSection ) ); m_crossSectionFaultGridLines = part; } } createPolyLineParts( useBufferObjects ); createExtrusionDirParts( useBufferObjects ); if ( m_isFlattened ) createFaultLabelParts( m_crossSectionGenerator->faultMeshLabelAndAnchorPositions() ); applySingleColorEffect(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivIntersectionPartMgr::createFaultLabelParts( const std::vector>& labelAndAnchors ) { m_faultMeshLabels = nullptr; m_faultMeshLabelLines = nullptr; if ( !labelAndAnchors.size() ) return; RimEclipseView* eclipseView = nullptr; m_rimCrossSection->firstAncestorOrThisOfType( eclipseView ); RimFaultInViewCollection* faultInViewColl = eclipseView->faultCollection(); if ( !( eclipseView && faultInViewColl->showFaultLabel() ) ) return; cvf::Color3f faultLabelColor = faultInViewColl->faultLabelColor(); cvf::Font* font = RiaGuiApplication::instance()->defaultSceneFont(); std::vector lineVertices; cvf::ref drawableText = new cvf::DrawableText; { drawableText->setFont( font ); drawableText->setCheckPosVisible( false ); drawableText->setDrawBorder( false ); drawableText->setDrawBackground( false ); drawableText->setVerticalAlignment( cvf::TextDrawer::BASELINE ); drawableText->setTextColor( faultLabelColor ); } cvf::BoundingBox bb = m_crossSectionFaces->boundingBox(); double labelZOffset = bb.extent().z() / 10; int visibleFaultNameCount = 0; for ( const auto& labelAndAnchorPair : labelAndAnchors ) { RimFaultInView* fault = faultInViewColl->findFaultByName( labelAndAnchorPair.first ); if ( !( fault && fault->showFault() ) ) continue; cvf::String cvfString = cvfqt::Utils::toString( labelAndAnchorPair.first ); cvf::Vec3f textCoord( labelAndAnchorPair.second ); textCoord.z() += labelZOffset; drawableText->addText( cvfString, textCoord ); lineVertices.push_back( cvf::Vec3f( labelAndAnchorPair.second ) ); lineVertices.push_back( textCoord ); visibleFaultNameCount++; } if ( visibleFaultNameCount == 0 ) return; // Labels part { cvf::ref part = new cvf::Part; part->setName( "Fault mesh label : text " ); part->setDrawable( drawableText.p() ); cvf::ref eff = new cvf::Effect; part->setEffect( eff.p() ); part->setPriority( RivPartPriority::PartType::Text ); part->updateBoundingBox(); m_faultMeshLabels = part; } // Lines to labels part { cvf::ref vertices = new cvf::Vec3fArray; vertices->assign( lineVertices ); cvf::ref geo = new cvf::DrawableGeo; geo->setVertexArray( vertices.p() ); cvf::ref primSet = new cvf::PrimitiveSetDirect( cvf::PT_LINES ); primSet->setStartIndex( 0 ); primSet->setIndexCount( vertices->size() ); geo->addPrimitiveSet( primSet.p() ); cvf::ref part = new cvf::Part; part->setName( "Anchor lines for fault mesh labels" ); part->setDrawable( geo.p() ); part->updateBoundingBox(); caf::MeshEffectGenerator gen( RiaApplication::instance()->preferences()->defaultFaultGridLineColors() ); cvf::ref eff = gen.generateCachedEffect(); part->setEffect( eff.p() ); m_faultMeshLabelLines = part; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivIntersectionPartMgr::createPolyLineParts( bool useBufferObjects ) { // Highlight line m_highlightLineAlongPolyline = nullptr; m_highlightPointsForPolyline = nullptr; if ( m_rimCrossSection->type == RimIntersection::CS_POLYLINE || m_rimCrossSection->type == RimIntersection::CS_AZIMUTHLINE ) { { cvf::ref polylineGeo = m_crossSectionGenerator->createLineAlongPolylineDrawable(); if ( polylineGeo.notNull() ) { if ( useBufferObjects ) { polylineGeo->setRenderMode( cvf::DrawableGeo::BUFFER_OBJECT ); } cvf::ref part = new cvf::Part; part->setName( "Cross Section Polyline" ); part->setDrawable( polylineGeo.p() ); part->updateBoundingBox(); part->setPriority( RivPartPriority::PartType::Highlight ); // Always show this part, also when mesh is turned off // part->setEnableMask(meshFaultBit); cvf::ref eff; caf::MeshEffectGenerator lineEffGen( cvf::Color3::MAGENTA ); eff = lineEffGen.generateUnCachedEffect(); cvf::ref depth = new cvf::RenderStateDepth; depth->enableDepthTest( false ); eff->setRenderState( depth.p() ); part->setEffect( eff.p() ); m_highlightLineAlongPolyline = part; } } cvf::ref polylinePointsGeo = m_crossSectionGenerator->createPointsFromPolylineDrawable(); if ( polylinePointsGeo.notNull() ) { if ( useBufferObjects ) { polylinePointsGeo->setRenderMode( cvf::DrawableGeo::BUFFER_OBJECT ); } cvf::ref part = new cvf::Part; part->setName( "Cross Section Polyline" ); part->setDrawable( polylinePointsGeo.p() ); part->updateBoundingBox(); part->setPriority( RivPartPriority::PartType::Highlight ); // Always show this part, also when mesh is turned off // part->setEnableMask(meshFaultBit); cvf::ref eff; caf::MeshEffectGenerator lineEffGen( cvf::Color3::MAGENTA ); eff = lineEffGen.generateUnCachedEffect(); cvf::ref depth = new cvf::RenderStateDepth; depth->enableDepthTest( false ); eff->setRenderState( depth.p() ); cvf::ref pointRendState = new cvf::RenderStatePoint( cvf::RenderStatePoint::FIXED_SIZE ); pointRendState->setSize( 5.0f ); eff->setRenderState( pointRendState.p() ); part->setEffect( eff.p() ); m_highlightPointsForPolyline = part; } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivIntersectionPartMgr::createExtrusionDirParts( bool useBufferObjects ) { m_highlightLineAlongExtrusionDir = nullptr; m_highlightPointsForExtrusionDir = nullptr; if ( m_rimCrossSection->direction() == RimIntersection::CS_TWO_POINTS ) { { cvf::ref polylineGeo = m_crossSectionGenerator->createLineAlongExtrusionLineDrawable( m_rimCrossSection->polyLinesForExtrusionDirection() ); if ( polylineGeo.notNull() ) { if ( useBufferObjects ) { polylineGeo->setRenderMode( cvf::DrawableGeo::BUFFER_OBJECT ); } cvf::ref part = new cvf::Part; part->setName( "Cross Section Polyline" ); part->setDrawable( polylineGeo.p() ); part->updateBoundingBox(); part->setPriority( RivPartPriority::PartType::Highlight ); // Always show this part, also when mesh is turned off // part->setEnableMask(meshFaultBit); cvf::ref eff; caf::MeshEffectGenerator lineEffGen( cvf::Color3::MAGENTA ); eff = lineEffGen.generateUnCachedEffect(); cvf::ref depth = new cvf::RenderStateDepth; depth->enableDepthTest( false ); eff->setRenderState( depth.p() ); part->setEffect( eff.p() ); m_highlightLineAlongExtrusionDir = part; } } cvf::ref polylinePointsGeo = m_crossSectionGenerator->createPointsFromExtrusionLineDrawable( m_rimCrossSection->polyLinesForExtrusionDirection() ); if ( polylinePointsGeo.notNull() ) { if ( useBufferObjects ) { polylinePointsGeo->setRenderMode( cvf::DrawableGeo::BUFFER_OBJECT ); } cvf::ref part = new cvf::Part; part->setName( "Cross Section Polyline" ); part->setDrawable( polylinePointsGeo.p() ); part->updateBoundingBox(); part->setPriority( RivPartPriority::PartType::Highlight ); // Always show this part, also when mesh is turned off // part->setEnableMask(meshFaultBit); cvf::ref eff; caf::MeshEffectGenerator lineEffGen( cvf::Color3::MAGENTA ); eff = lineEffGen.generateUnCachedEffect(); cvf::ref depth = new cvf::RenderStateDepth; depth->enableDepthTest( false ); eff->setRenderState( depth.p() ); cvf::ref pointRendState = new cvf::RenderStatePoint( cvf::RenderStatePoint::FIXED_SIZE ); pointRendState->setSize( 5.0f ); eff->setRenderState( pointRendState.p() ); part->setEffect( eff.p() ); m_highlightPointsForExtrusionDir = part; } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivIntersectionPartMgr::appendNativeCrossSectionFacesToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform ) { if ( m_crossSectionFaces.isNull() ) { generatePartGeometry(); } if ( m_crossSectionFaces.notNull() ) { m_crossSectionFaces->setTransform( scaleTransform ); model->addPart( m_crossSectionFaces.p() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivIntersectionPartMgr::appendMeshLinePartsToModel( cvf::ModelBasicList* model, cvf::Transform* scaleTransform ) { if ( m_crossSectionGridLines.isNull() ) { generatePartGeometry(); } if ( m_crossSectionGridLines.notNull() ) { m_crossSectionGridLines->setTransform( scaleTransform ); model->addPart( m_crossSectionGridLines.p() ); } if ( m_crossSectionFaultGridLines.notNull() ) { m_crossSectionFaultGridLines->setTransform( scaleTransform ); model->addPart( m_crossSectionFaultGridLines.p() ); } if ( m_faultMeshLabelLines.notNull() ) { m_faultMeshLabelLines->setTransform( scaleTransform ); model->addPart( m_faultMeshLabelLines.p() ); } if ( m_faultMeshLabels.notNull() ) { m_faultMeshLabels->setTransform( scaleTransform ); model->addPart( m_faultMeshLabels.p() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivIntersectionPartMgr::appendPolylinePartsToModel( Rim3dView& view, cvf::ModelBasicList* model, cvf::Transform* scaleTransform ) { Rim2dIntersectionView* curr2dView = dynamic_cast( &view ); if ( m_rimCrossSection->inputPolyLineFromViewerEnabled || ( curr2dView && curr2dView->showDefiningPoints() ) ) { if ( m_highlightLineAlongPolyline.notNull() ) { m_highlightLineAlongPolyline->setTransform( scaleTransform ); model->addPart( m_highlightLineAlongPolyline.p() ); } if ( m_highlightPointsForPolyline.notNull() ) { m_highlightPointsForPolyline->setTransform( scaleTransform ); model->addPart( m_highlightPointsForPolyline.p() ); } } if ( m_rimCrossSection->inputExtrusionPointsFromViewerEnabled ) { if ( m_highlightLineAlongExtrusionDir.notNull() ) { m_highlightLineAlongExtrusionDir->setTransform( scaleTransform ); model->addPart( m_highlightLineAlongExtrusionDir.p() ); } if ( m_highlightPointsForExtrusionDir.notNull() ) { m_highlightPointsForExtrusionDir->setTransform( scaleTransform ); model->addPart( m_highlightPointsForExtrusionDir.p() ); } } if ( m_rimCrossSection->inputTwoAzimuthPointsFromViewerEnabled || ( curr2dView && curr2dView->showDefiningPoints() ) ) { if ( m_highlightLineAlongPolyline.notNull() ) { m_highlightLineAlongPolyline->setTransform( scaleTransform ); model->addPart( m_highlightLineAlongPolyline.p() ); } if ( m_highlightPointsForPolyline.notNull() ) { m_highlightPointsForPolyline->setTransform( scaleTransform ); model->addPart( m_highlightPointsForPolyline.p() ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const RimIntersection* RivIntersectionPartMgr::intersection() const { return m_rimCrossSection.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Mat4d RivIntersectionPartMgr::unflattenTransformMatrix( const cvf::Vec3d& intersectionPointFlat ) { return m_crossSectionGenerator->unflattenTransformMatrix( intersectionPointFlat ); }