///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron 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 "RivWellHeadPartMgr.h" #include "RiaGuiApplication.h" #include "RigActiveCellInfo.h" #include "RigCell.h" #include "RigEclipseCaseData.h" #include "RigMainGrid.h" #include "RigSimWellData.h" #include "RigWellResultPoint.h" #include "RimEclipseCase.h" #include "RimEclipseView.h" #include "RimSimWellInView.h" #include "RimSimWellInViewCollection.h" #include "RivPartPriority.h" #include "RivPipeGeometryGenerator.h" #include "RivSectionFlattener.h" #include "RivSimWellPipeSourceInfo.h" #include "RivTextLabelSourceInfo.h" #include "cafDisplayCoordTransform.h" #include "cafEffectGenerator.h" #include "cvfArrowGenerator.h" #include "cvfDrawableGeo.h" #include "cvfDrawableText.h" #include "cvfGeometryBuilderFaceList.h" #include "cvfModelBasicList.h" #include "cvfPart.h" #include "cvfTransform.h" #include "cvfqtUtils.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivWellHeadPartMgr::RivWellHeadPartMgr( RimSimWellInView* well ) : m_rimWell( well ) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivWellHeadPartMgr::~RivWellHeadPartMgr() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellHeadPartMgr::buildWellHeadParts( size_t frameIndex, const caf::DisplayCoordTransform* displayXf, bool doFlatten, double xOffset ) { clearAllGeometry(); if ( !viewWithSettings() ) return; RimSimWellInView* well = m_rimWell; double characteristicCellSize = viewWithSettings()->ownerCase()->characteristicCellSize(); cvf::Vec3d whEndPos; cvf::Vec3d whStartPos; { well->wellHeadTopBottomPosition( static_cast( frameIndex ), &whEndPos, &whStartPos ); if ( doFlatten ) { whEndPos.x() = xOffset; whEndPos.y() = 0.0; whStartPos.x() = xOffset; whStartPos.y() = 0.0; whEndPos = displayXf->scaleToDisplaySize( whEndPos ); whStartPos = displayXf->scaleToDisplaySize( whStartPos ); whEndPos.z() += characteristicCellSize; } else { whEndPos = displayXf->transformToDisplayCoord( whEndPos ); whStartPos = displayXf->transformToDisplayCoord( whStartPos ); whEndPos.z() += characteristicCellSize; } } if ( !well->simWellData()->hasWellResult( frameIndex ) ) return; const RigWellResultFrame* wellResultFrame = well->simWellData()->wellResultFrame( frameIndex ); double pipeRadius = m_rimWell->pipeRadius(); int pipeCrossSectionVxCount = m_rimWell->pipeCrossSectionVertexCount(); if ( wellResultFrame->m_isOpen ) { // Use slightly larger well head arrow when well is open pipeRadius *= 1.1; } // Upper part of simulation well pipe is defined to use branch index 0 cvf::ref sourceInfo = new RivSimWellPipeSourceInfo( m_rimWell, 0 ); cvf::Vec3d arrowPosition = whEndPos; arrowPosition.z() += pipeRadius; // Well head pipe geometry { cvf::ref wellHeadPipeCoords = new cvf::Vec3dArray; wellHeadPipeCoords->resize( 2 ); wellHeadPipeCoords->set( 0, whStartPos ); wellHeadPipeCoords->set( 1, whEndPos ); cvf::ref pipeGeomGenerator = new RivPipeGeometryGenerator; pipeGeomGenerator->setPipeCenterCoords( wellHeadPipeCoords.p() ); pipeGeomGenerator->setCrossSectionVertexCount( pipeCrossSectionVxCount ); pipeGeomGenerator->setRadius( pipeRadius ); cvf::ref pipeSurface = pipeGeomGenerator->createPipeSurface(); cvf::ref centerLineDrawable = pipeGeomGenerator->createCenterLine(); if ( pipeSurface.notNull() ) { cvf::ref part = new cvf::Part; part->setName( "RivWellHeadPartMgr: surface " + cvfqt::Utils::toString( well->name() ) ); part->setDrawable( pipeSurface.p() ); caf::SurfaceEffectGenerator surfaceGen( cvf::Color4f( well->wellPipeColor() ), caf::PO_1 ); if ( viewWithSettings() && viewWithSettings()->isLightingDisabled() ) { surfaceGen.enableLighting( false ); } cvf::ref eff = surfaceGen.generateCachedEffect(); part->setEffect( eff.p() ); part->setSourceInfo( sourceInfo.p() ); m_wellHeadPipeSurfacePart = part; } if ( centerLineDrawable.notNull() ) { cvf::ref part = new cvf::Part; part->setName( "RivWellHeadPartMgr: centerline " + cvfqt::Utils::toString( well->name() ) ); part->setDrawable( centerLineDrawable.p() ); caf::MeshEffectGenerator meshGen( well->wellPipeColor() ); cvf::ref eff = meshGen.generateCachedEffect(); part->setEffect( eff.p() ); part->setSourceInfo( sourceInfo.p() ); m_wellHeadPipeCenterPart = part; part->updateBoundingBox(); CVF_ASSERT( part->boundingBox().isValid() ); } } double arrowLength = characteristicCellSize * simWellInViewCollection()->wellHeadScaleFactor() * m_rimWell->wellHeadScaleFactor(); if ( wellResultFrame->m_isOpen ) { // Use slightly larger well head arrow when well is open arrowLength = 1.1 * arrowLength; } cvf::Vec3d textPosition = arrowPosition; textPosition.z() += 1.2 * arrowLength; cvf::Mat4f matr; if ( wellResultFrame->m_productionType != RiaDefines::WellProductionType::PRODUCER ) { matr = cvf::Mat4f::fromRotation( cvf::Vec3f( 1.0f, 0.0f, 0.0f ), cvf::Math::toRadians( 180.0f ) ); } double ijScaleFactor = arrowLength / 6; if ( wellResultFrame->m_isOpen ) { ijScaleFactor *= 1.1; } matr( 0, 0 ) *= ijScaleFactor; matr( 1, 1 ) *= ijScaleFactor; matr( 2, 2 ) *= arrowLength; if ( wellResultFrame->m_productionType != RiaDefines::WellProductionType::PRODUCER ) { arrowPosition.z() += arrowLength; } matr.setTranslation( cvf::Vec3f( arrowPosition ) ); cvf::GeometryBuilderFaceList builder; cvf::ArrowGenerator gen; gen.setShaftRelativeRadius( 0.5f ); gen.setHeadRelativeRadius( 1.0f ); gen.setHeadRelativeLength( 0.4f ); gen.setNumSlices( pipeCrossSectionVxCount ); gen.generate( &builder ); cvf::ref vertices = builder.vertices(); cvf::ref faceList = builder.faceList(); size_t i; for ( i = 0; i < vertices->size(); i++ ) { cvf::Vec3f v = vertices->get( i ); v.transformPoint( matr ); vertices->set( i, v ); } cvf::ref geo1 = new cvf::DrawableGeo; geo1->setVertexArray( vertices.p() ); geo1->setFromFaceList( *faceList ); geo1->computeNormals(); { cvf::ref part = new cvf::Part; part->setName( "RivWellHeadPartMgr: arrow " + cvfqt::Utils::toString( well->name() ) ); part->setDrawable( geo1.p() ); cvf::Color4f headColor( cvf::Color3::GRAY ); RimSimWellInViewCollection* wellColl = nullptr; if ( m_rimWell ) { m_rimWell->firstAncestorOrThisOfType( wellColl ); } if ( wellColl && wellColl->showConnectionStatusColors() ) { if ( wellResultFrame->m_isOpen ) { if ( wellResultFrame->m_productionType == RiaDefines::WellProductionType::PRODUCER ) { headColor = cvf::Color4f( cvf::Color3::GREEN ); } else if ( wellResultFrame->m_productionType == RiaDefines::WellProductionType::OIL_INJECTOR ) { headColor = cvf::Color4f( cvf::Color3::ORANGE ); } else if ( wellResultFrame->m_productionType == RiaDefines::WellProductionType::GAS_INJECTOR ) { headColor = cvf::Color4f( cvf::Color3::RED ); } else if ( wellResultFrame->m_productionType == RiaDefines::WellProductionType::WATER_INJECTOR ) { headColor = cvf::Color4f( cvf::Color3::BLUE ); } } } else { headColor = cvf::Color4f( m_rimWell->wellPipeColor() ); } caf::SurfaceEffectGenerator surfaceGen( headColor, caf::PO_1 ); if ( viewWithSettings() && viewWithSettings()->isLightingDisabled() ) { surfaceGen.enableLighting( false ); } cvf::ref eff = surfaceGen.generateCachedEffect(); part->setEffect( eff.p() ); part->setSourceInfo( sourceInfo.p() ); m_wellHeadArrowPart = part; } // Show labels for well heads only when well disks are disabled: // well disk labels are preferred since they have more info. if ( well->showWellLabel() && !well->name().isEmpty() && !well->showWellDisks() ) { cvf::Font* font = RiaGuiApplication::instance()->defaultWellLabelFont(); cvf::ref drawableText = new cvf::DrawableText; drawableText->setFont( font ); drawableText->setCheckPosVisible( false ); drawableText->setDrawBorder( false ); drawableText->setDrawBackground( false ); drawableText->setVerticalAlignment( cvf::TextDrawer::CENTER ); drawableText->setTextColor( simWellInViewCollection()->wellLabelColor() ); cvf::String cvfString = cvfqt::Utils::toString( m_rimWell->name() ); cvf::Vec3f textCoord( textPosition ); drawableText->addText( cvfString, textCoord ); cvf::ref part = new cvf::Part; part->setName( "RivWellHeadPartMgr: text " + cvfString ); part->setDrawable( drawableText.p() ); cvf::ref eff = new cvf::Effect; part->setEffect( eff.p() ); part->setPriority( RivPartPriority::PartType::Text ); part->setSourceInfo( new RivTextLabelSourceInfo( m_rimWell, cvfString, textCoord ) ); m_wellHeadLabelPart = part; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellHeadPartMgr::clearAllGeometry() { m_wellHeadArrowPart = nullptr; m_wellHeadLabelPart = nullptr; m_wellHeadPipeCenterPart = nullptr; m_wellHeadPipeSurfacePart = nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellHeadPartMgr::appendDynamicGeometryPartsToModel( cvf::ModelBasicList* model, size_t frameIndex, const caf::DisplayCoordTransform* displayXf ) { if ( m_rimWell.isNull() ) return; if ( !viewWithSettings() ) return; if ( !m_rimWell->isWellPipeVisible( frameIndex ) ) return; buildWellHeadParts( frameIndex, displayXf, false, 0.0 ); // Always add pipe part of well head if ( m_wellHeadPipeCenterPart.notNull() ) model->addPart( m_wellHeadPipeCenterPart.p() ); if ( m_wellHeadPipeSurfacePart.notNull() ) model->addPart( m_wellHeadPipeSurfacePart.p() ); if ( m_rimWell->showWellLabel() && m_wellHeadLabelPart.notNull() ) { model->addPart( m_wellHeadLabelPart.p() ); } if ( m_rimWell->showWellHead() && m_wellHeadArrowPart.notNull() ) { model->addPart( m_wellHeadArrowPart.p() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellHeadPartMgr::appendFlattenedDynamicGeometryPartsToModel( cvf::ModelBasicList* model, size_t frameIndex, const caf::DisplayCoordTransform* displayXf, double xOffset ) { if ( m_rimWell.isNull() ) return; if ( !viewWithSettings() ) return; if ( !m_rimWell->isWellPipeVisible( frameIndex ) ) return; buildWellHeadParts( frameIndex, displayXf, true, xOffset ); // Always add pipe part of well head if ( m_wellHeadPipeCenterPart.notNull() ) model->addPart( m_wellHeadPipeCenterPart.p() ); if ( m_wellHeadPipeSurfacePart.notNull() ) model->addPart( m_wellHeadPipeSurfacePart.p() ); if ( m_rimWell->showWellLabel() && m_wellHeadLabelPart.notNull() ) { model->addPart( m_wellHeadLabelPart.p() ); } if ( m_rimWell->showWellHead() && m_wellHeadArrowPart.notNull() ) { model->addPart( m_wellHeadArrowPart.p() ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- Rim3dView* RivWellHeadPartMgr::viewWithSettings() { Rim3dView* view = nullptr; if ( m_rimWell ) m_rimWell->firstAncestorOrThisOfType( view ); return view; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimSimWellInViewCollection* RivWellHeadPartMgr::simWellInViewCollection() { RimSimWellInViewCollection* wellCollection = nullptr; if ( m_rimWell ) m_rimWell->firstAncestorOrThisOfType( wellCollection ); return wellCollection; }