///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil 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 "RivWellFracturePartMgr.h" #include "RiaApplication.h" #include "RimEclipseView.h" #include "RimEclipseWell.h" #include "RimFracture.h" #include "RimFractureTemplate.h" #include "RimLegendConfig.h" #include "RigStimPlanCell.h" #include "RimStimPlanColors.h" #include "RimStimPlanFractureTemplate.h" #include "RivFaultGeometryGenerator.h" #include "RivPartPriority.h" #include "RivObjectSourceInfo.h" #include "cafDisplayCoordTransform.h" #include "cafEffectGenerator.h" #include "cvfDrawableGeo.h" #include "cvfModelBasicList.h" #include "cvfPart.h" #include "cvfPrimitiveSet.h" #include "cvfPrimitiveSetIndexedUInt.h" #include "cvfScalarMapperContinuousLinear.h" #include "cvfRenderStateDepth.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivWellFracturePartMgr::RivWellFracturePartMgr(RimFracture* fracture) : m_rimFracture(fracture) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RivWellFracturePartMgr::~RivWellFracturePartMgr() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellFracturePartMgr::updatePartGeometry(caf::DisplayCoordTransform* displayCoordTransform) { if (m_part.notNull()) return; if (!displayCoordTransform) return; if (m_rimFracture) { if (!m_rimFracture->hasValidGeometry()) { m_rimFracture->computeGeometry(); } if (!m_rimFracture->hasValidGeometry()) return; const std::vector& nodeCoords = m_rimFracture->nodeCoords(); const std::vector& triangleIndices = m_rimFracture->triangleIndices(); std::vector displayCoords; for (size_t i = 0; i < nodeCoords.size(); i++) { cvf::Vec3d nodeCoordsDouble = static_cast(nodeCoords[i]); cvf::Vec3d displayCoordsDouble = displayCoordTransform->transformToDisplayCoord(nodeCoordsDouble); displayCoords.push_back(static_cast(displayCoordsDouble)); } cvf::ref geo = createGeo(triangleIndices, displayCoords); m_part = new cvf::Part; m_part->setDrawable(geo.p()); cvf::Color4f fractureColor = cvf::Color4f(cvf::Color3f(cvf::Color3::BROWN)); RimEclipseView* activeView = dynamic_cast(RiaApplication::instance()->activeReservoirView()); if (activeView) { fractureColor = cvf::Color4f(activeView->stimPlanColors->defaultColor()); } caf::SurfaceEffectGenerator surfaceGen(fractureColor, caf::PO_1); cvf::ref eff = surfaceGen.generateCachedEffect(); m_part->setEffect(eff.p()); m_part->setSourceInfo(new RivObjectSourceInfo(m_rimFracture)); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellFracturePartMgr::updatePartGeometryTexture(caf::DisplayCoordTransform* displayCoordTransform) { if (m_part.notNull()) return; if (!displayCoordTransform) return; if (m_rimFracture) { if (!m_rimFracture->hasValidGeometry()) { m_rimFracture->computeGeometry(); } if (!m_rimFracture->hasValidGeometry()) return; RimLegendConfig* legendConfig = nullptr; RimEclipseView* activeView = dynamic_cast(RiaApplication::instance()->activeReservoirView()); if (activeView && activeView->stimPlanColors()) { if (activeView->stimPlanColors()->isChecked()) { legendConfig = activeView->stimPlanColors()->activeLegend(); } } // Note : If no legend is found, draw geo using a single color RimFractureTemplate * fracTemplate = m_rimFracture->attachedFractureDefinition(); RimStimPlanFractureTemplate* stimPlanFracTemplate; if (dynamic_cast(fracTemplate)) { stimPlanFracTemplate = dynamic_cast(fracTemplate); } else return; int timeStepIndex = m_rimFracture->stimPlanTimeIndexToPlot; std::vector > dataToPlot = stimPlanFracTemplate->getDataAtTimeIndex(activeView->stimPlanColors->resultName(), activeView->stimPlanColors->unit(), timeStepIndex); const std::vector& nodeCoords = m_rimFracture->nodeCoords(); const std::vector& triangleIndices = m_rimFracture->triangleIndices(); std::vector displayCoords; for (size_t i = 0; i < nodeCoords.size(); i++) { cvf::Vec3d nodeCoordsDouble = static_cast(nodeCoords[i]); cvf::Vec3d displayCoordsDouble = displayCoordTransform->transformToDisplayCoord(nodeCoordsDouble); displayCoords.push_back(static_cast(displayCoordsDouble)); } cvf::ref geo = createGeo(triangleIndices, displayCoords); m_part = new cvf::Part; m_part->setDrawable(geo.p()); generateFractureOutlinePolygonPart(displayCoordTransform); generateStimPlanMeshPart(displayCoordTransform); float opacityLevel = activeView->stimPlanColors->opacityLevel(); if (legendConfig) { cvf::ScalarMapper* scalarMapper = legendConfig->scalarMapper(); cvf::ref textureCoords = new cvf::Vec2fArray; textureCoords->resize(nodeCoords.size()); int i = 0; for (std::vector depthData : dataToPlot) { std::vector mirroredValuesAtDepth = mirrorDataAtSingleDepth(depthData); for (double gridXdata : mirroredValuesAtDepth) { cvf::Vec2f texCoord = scalarMapper->mapToTextureCoord(gridXdata); if (gridXdata > 1e-7) { texCoord[1] = 0; // Set the Y texture coordinate to the opaque line in the texture } textureCoords->set(i, texCoord); i++; } } geo->setTextureCoordArray(textureCoords.p()); caf::ScalarMapperEffectGenerator effGen(scalarMapper, caf::PO_1); effGen.setOpacityLevel(0.5); effGen.discardTransparentFragments(true); if (activeView && activeView->isLightingDisabled()) { effGen.disableLighting(true); } cvf::ref eff = effGen.generateCachedEffect(); m_part->setEffect(eff.p()); } else { cvf::Color4f fractureColor = cvf::Color4f(activeView->stimPlanColors->defaultColor(), 1.0); caf::SurfaceEffectGenerator surfaceGen(fractureColor, caf::PO_1); cvf::ref eff = surfaceGen.generateCachedEffect(); m_part->setEffect(eff.p()); } m_part->setPriority(RivPartPriority::PartType::Transparent); m_part->setSourceInfo(new RivObjectSourceInfo(m_rimFracture)); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellFracturePartMgr::generateFractureOutlinePolygonPart(caf::DisplayCoordTransform* displayCoordTransform) { cvf::ref polygonGeo = createPolygonDrawable(displayCoordTransform); m_polygonPart = new cvf::Part; m_polygonPart->setDrawable(polygonGeo.p()); m_polygonPart->updateBoundingBox(); m_polygonPart->setPriority(RivPartPriority::PartType::TransparentMeshLines); caf::MeshEffectGenerator lineEffGen(cvf::Color3::MAGENTA); lineEffGen.setLineWidth(3.0f); cvf::ref eff = lineEffGen.generateCachedEffect(); m_polygonPart->setEffect(eff.p()); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellFracturePartMgr::generateStimPlanMeshPart(caf::DisplayCoordTransform* displayCoordTransform) { if (!m_rimFracture->attachedFractureDefinition()) return; RimStimPlanFractureTemplate* stimPlanFracTemplate = dynamic_cast(m_rimFracture->attachedFractureDefinition()); if (!stimPlanFracTemplate) return; cvf::ref stimPlanMeshGeo = createStimPlanMeshDrawable(stimPlanFracTemplate, displayCoordTransform); // From cvf::ref RivFaultGeometryGenerator::createMeshDrawable() m_StimPlanMeshPart = new cvf::Part; m_StimPlanMeshPart->setDrawable(stimPlanMeshGeo.p()); m_StimPlanMeshPart->updateBoundingBox(); m_StimPlanMeshPart->setPriority(RivPartPriority::PartType::TransparentMeshLines); caf::MeshEffectGenerator lineEffGen(cvf::Color3::BLACK); lineEffGen.setLineWidth(1.0f); cvf::ref eff = lineEffGen.generateCachedEffect(); m_StimPlanMeshPart->setEffect(eff.p()); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivWellFracturePartMgr::createStimPlanMeshDrawable(RimStimPlanFractureTemplate* stimPlanFracTemplate, caf::DisplayCoordTransform* displayCoordTransform) { std::vector stimPlanCells = stimPlanFracTemplate->getStimPlanCells(); std::vector stimPlanMeshVertices; for (RigStimPlanCell stimPlanCell : stimPlanCells) { if (stimPlanCell.getDisplayValue() > 1e-7) { std::vector stimPlanCellPolygon = stimPlanCell.getPolygon(); for (cvf::Vec3d cellCorner : stimPlanCellPolygon) { stimPlanMeshVertices.push_back(static_cast(cellCorner)); } } } cvf::Mat4f m = m_rimFracture->transformMatrix(); std::vector stimPlanMeshVerticesDisplayCoords = transfromToFractureDisplayCoords(stimPlanMeshVertices, m, displayCoordTransform); cvf::Vec3fArray* stimPlanMeshVertexList; stimPlanMeshVertexList = new cvf::Vec3fArray; stimPlanMeshVertexList->assign(stimPlanMeshVerticesDisplayCoords); cvf::ref stimPlanMeshGeo = new cvf::DrawableGeo; stimPlanMeshGeo->setVertexArray(stimPlanMeshVertexList); cvf::ref indices = RivFaultGeometryGenerator::lineIndicesFromQuadVertexArray(stimPlanMeshVertexList); cvf::ref prim = new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES); prim->setIndices(indices.p()); stimPlanMeshGeo->addPrimitiveSet(prim.p()); return stimPlanMeshGeo; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellFracturePartMgr::getPolygonBB(float &polygonXmin, float &polygonXmax, float &polygonYmin, float &polygonYmax) { std::vector polygon = m_rimFracture->attachedFractureDefinition()->fracturePolygon(m_rimFracture->fractureUnit); if (polygon.size() > 1) { polygonXmin = polygon[0].x(); polygonXmax = polygon[0].x(); polygonYmin = polygon[0].y(); polygonYmax = polygon[0].y(); } for (cvf::Vec3f v : polygon) { if (v.x() < polygonXmin) polygonXmin = v.x(); if (v.x() > polygonXmax) polygonXmax = v.x(); if (v.y() < polygonYmin) polygonYmin = v.y(); if (v.y() > polygonYmax) polygonYmax = v.y(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivWellFracturePartMgr::createPolygonDrawable(caf::DisplayCoordTransform* displayCoordTransform) { std::vector polygon = m_rimFracture->attachedFractureDefinition()->fracturePolygon(m_rimFracture->fractureUnit); cvf::Mat4f m = m_rimFracture->transformMatrix(); std::vector polygonDisplayCoords = transfromToFractureDisplayCoords(polygon, m, displayCoordTransform); std::vector lineIndices; std::vector vertices; for (size_t i = 0; i < polygonDisplayCoords.size(); ++i) { vertices.push_back(cvf::Vec3f(polygonDisplayCoords[i])); if (i < polygonDisplayCoords.size() - 1) { lineIndices.push_back(static_cast(i)); lineIndices.push_back(static_cast(i + 1)); } } if (vertices.size() == 0) return NULL; cvf::ref vx = new cvf::Vec3fArray; vx->assign(vertices); cvf::ref idxes = new cvf::UIntArray; idxes->assign(lineIndices); cvf::ref prim = new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES); prim->setIndices(idxes.p()); cvf::ref polygonGeo = new cvf::DrawableGeo; polygonGeo->setVertexArray(vx.p()); polygonGeo->addPrimitiveSet(prim.p()); return polygonGeo; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RivWellFracturePartMgr::transfromToFractureDisplayCoords(std::vector coordinatesVector, cvf::Mat4f m, caf::DisplayCoordTransform* displayCoordTransform) { std::vector polygonInDisplayCoords; for (cvf::Vec3f v : coordinatesVector) { v.transformPoint(m); cvf::Vec3d nodeCoordsDouble = static_cast(v); cvf::Vec3d displayCoordsDouble = displayCoordTransform->transformToDisplayCoord(nodeCoordsDouble); polygonInDisplayCoords.push_back(static_cast(displayCoordsDouble)); } return polygonInDisplayCoords; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RivWellFracturePartMgr::mirrorDataAtSingleDepth(std::vector depthData) { std::vector mirroredValuesAtGivenDepth; mirroredValuesAtGivenDepth.push_back(depthData[0]); for (int i = 1; i < (depthData.size()); i++) //starting at 1 since we don't want center value twice { double valueAtGivenX = depthData[i]; mirroredValuesAtGivenDepth.insert(mirroredValuesAtGivenDepth.begin(), valueAtGivenX); mirroredValuesAtGivenDepth.push_back(valueAtGivenX); } return mirroredValuesAtGivenDepth; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellFracturePartMgr::appendGeometryPartsToModel(cvf::ModelBasicList* model, caf::DisplayCoordTransform* displayCoordTransform) { clearGeometryCache(); if (!m_rimFracture->isChecked()) return; if (m_part.isNull()) { if (m_rimFracture->attachedFractureDefinition()) { if (dynamic_cast(m_rimFracture->attachedFractureDefinition())) { updatePartGeometryTexture(displayCoordTransform); RimStimPlanFractureTemplate* stimPlanFracTemplate = dynamic_cast(m_rimFracture->attachedFractureDefinition()); if (stimPlanFracTemplate->showStimPlanMesh() && m_StimPlanMeshPart.notNull()) { model->addPart(m_StimPlanMeshPart.p()); } } else { updatePartGeometry(displayCoordTransform); } } } if (m_part.notNull()) { model->addPart(m_part.p()); } if (m_rimFracture->showPolygonFractureOutline() && m_polygonPart.notNull()) { model->addPart(m_polygonPart.p()); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RivWellFracturePartMgr::clearGeometryCache() { m_part = nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivWellFracturePartMgr::createGeo(const std::vector& triangleIndices, const std::vector& nodeCoords) { cvf::ref geo = new cvf::DrawableGeo; cvf::ref indices = new cvf::UIntArray(triangleIndices); cvf::ref vertices = new cvf::Vec3fArray(nodeCoords); geo->setVertexArray(vertices.p()); geo->addPrimitiveSet(new cvf::PrimitiveSetIndexedUInt(cvf::PT_TRIANGLES, indices.p())); geo->computeNormals(); return geo; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RivWellFracturePartMgr::stimPlanCellTouchesPolygon(const std::vector& polygon, double xMin, double xMax, double yMin, double yMax, float polygonXmin, float polygonXmax, float polygonYmin, float polygonYmax) { if (static_cast(xMin) > polygonXmin && static_cast(xMax) < polygonXmax) { if (static_cast(yMin) > polygonYmin && static_cast(yMax) < polygonYmax) { return true; } } //std::vector polygon = m_rimFracture->attachedFractureDefinition()->fracturePolygon(m_rimFracture->fractureUnit); for (cvf::Vec3f v : polygon) { if (v.x() > xMin && v.x() < xMax) { if (v.y() > yMin && v.y() < yMax) { return true; } } } return false; }