//-------------------------------------------------------------------------------------------------- /// Create mask for the parts outside the grid cells of the reservoir //-------------------------------------------------------------------------------------------------- cvf::ref<cvf::Part> RivWellFracturePartMgr::createMaskOfFractureOutsideGrid(const RimEclipseView& activeView) { cvf::Mat4d frMx = m_rimFracture->transformMatrix(); std::vector<cvf::Vec3f> maskTriangles; auto displCoordTrans = activeView.displayCoordTransform(); for (const auto& visibleFracturePolygon : m_visibleFracturePolygons) { std::vector<cvf::Vec3d> borderOfFractureCellPolygonLocalCsd; cvf::BoundingBox frBBox; for (const auto& pv : visibleFracturePolygon) { cvf::Vec3d pvd(pv); borderOfFractureCellPolygonLocalCsd.push_back(pvd); pvd.transformPoint(frMx); frBBox.add(pvd); } std::vector<std::vector<cvf::Vec3d>> clippedPolygons; std::vector<size_t> cellCandidates; activeView.mainGrid()->findIntersectingCells(frBBox, &cellCandidates); if (cellCandidates.empty()) { clippedPolygons.push_back(borderOfFractureCellPolygonLocalCsd); } else { // Check if fracture polygon is fully inside the grid bool allPointsInsideGrid = true; for (const auto& v : borderOfFractureCellPolygonLocalCsd) { auto pointInDomainCoords = v.getTransformedPoint(frMx); bool pointInsideGrid = false; RigMainGrid* mainGrid = activeView.mainGrid(); std::array<cvf::Vec3d, 8> corners; for (size_t cellIndex : cellCandidates) { mainGrid->cellCornerVertices(cellIndex, corners.data()); if (RigHexIntersectionTools::isPointInCell(pointInDomainCoords, corners.data())) { pointInsideGrid = true; break; } } if (!pointInsideGrid) { allPointsInsideGrid = false; break; } } if (!allPointsInsideGrid) { std::vector<std::vector<cvf::Vec3d>> allEclCellPolygons; for (size_t resCellIdx : cellCandidates) { // Calculate Eclipse cell intersection with fracture plane std::array<cvf::Vec3d, 8> corners; activeView.mainGrid()->cellCornerVertices(resCellIdx, corners.data()); std::vector<std::vector<cvf::Vec3d>> eclCellPolygons; bool hasIntersection = RigHexIntersectionTools::planeHexIntersectionPolygons(corners, frMx, eclCellPolygons); if (!hasIntersection || eclCellPolygons.empty()) continue; // Transform eclCell - plane intersection onto fracture cvf::Mat4d invertedTransformMatrix = frMx.getInverted(); for (std::vector<cvf::Vec3d>& eclCellPolygon : eclCellPolygons) { for (cvf::Vec3d& v : eclCellPolygon) { v.transformPoint(invertedTransformMatrix); } allEclCellPolygons.push_back(eclCellPolygon); } } { std::vector<std::vector<cvf::Vec3d>> polys = RigCellGeometryTools::subtractPolygons(borderOfFractureCellPolygonLocalCsd, allEclCellPolygons); for (const auto& polygon : polys) { clippedPolygons.push_back(polygon); } } } } for (auto& clippedPolygon : clippedPolygons) { for (auto& point : clippedPolygon) { point.transformPoint(frMx); } } // Create triangles from the clipped polygons cvf::Vec3d fractureNormal = cvf::Vec3d(frMx.col(2)); for (const auto& clippedPolygon : clippedPolygons) { cvf::EarClipTesselator tess; tess.setNormal(fractureNormal); cvf::Vec3dArray cvfNodes(clippedPolygon); tess.setGlobalNodeArray(cvfNodes); std::vector<size_t> polyIndexes; for (size_t idx = 0; idx < clippedPolygon.size(); ++idx) polyIndexes.push_back(idx); tess.setPolygonIndices(polyIndexes); std::vector<size_t> triangleIndices; tess.calculateTriangles(&triangleIndices); for (size_t idx : triangleIndices) { maskTriangles.push_back(cvf::Vec3f(displCoordTrans->transformToDisplayCoord(clippedPolygon[idx]))); } } } if (maskTriangles.size() >= 3) { cvf::ref<cvf::DrawableGeo> maskTriangleGeo = new cvf::DrawableGeo; maskTriangleGeo->setVertexArray(new cvf::Vec3fArray(maskTriangles)); cvf::ref<cvf::PrimitiveSetDirect> primitives = new cvf::PrimitiveSetDirect(cvf::PT_TRIANGLES); primitives->setIndexCount(maskTriangles.size()); maskTriangleGeo->addPrimitiveSet(primitives.p()); maskTriangleGeo->computeNormals(); cvf::ref<cvf::Part> containmentMaskPart = new cvf::Part(0, "FractureContainmentMaskPart"); containmentMaskPart->setDrawable(maskTriangleGeo.p()); containmentMaskPart->setSourceInfo(new RivObjectSourceInfo(m_rimFracture)); cvf::Color4f maskColor = cvf::Color4f(cvf::Color3f(cvf::Color3::GRAY)); caf::SurfaceEffectGenerator surfaceGen(maskColor, caf::PO_NONE); cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect(); containmentMaskPart->setEffect(eff.p()); return containmentMaskPart; } return nullptr; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref<cvf::Part> RivWellFracturePartMgr::createContainmentMaskPart(const RimEclipseView& activeView) { std::vector<cvf::Vec3d> borderPolygonLocalCS = fractureBorderPolygon(); cvf::Mat4d frMx = m_rimFracture->transformMatrix(); cvf::BoundingBox frBBox; std::vector<cvf::Vec3d> borderPolygonLocalCsd; for (const auto& pv : borderPolygonLocalCS) { cvf::Vec3d pvd(pv); borderPolygonLocalCsd.push_back(pvd); pvd.transformPoint(frMx); frBBox.add(pvd); } std::vector<size_t> cellCandidates; activeView.mainGrid()->findIntersectingCells(frBBox, &cellCandidates); auto displCoordTrans = activeView.displayCoordTransform(); std::vector<cvf::Vec3f> maskTriangles; RimEclipseCase* eclipseCase = nullptr; activeView.firstAncestorOrThisOfType(eclipseCase); auto reservoirCellIndicesOpenForFlow = RimFractureContainmentTools::reservoirCellIndicesOpenForFlow(eclipseCase, m_rimFracture); for (size_t resCellIdx : cellCandidates) { if (!m_rimFracture->isEclipseCellOpenForFlow(activeView.mainGrid(), reservoirCellIndicesOpenForFlow, resCellIdx)) { // Calculate Eclipse cell intersection with fracture plane std::array<cvf::Vec3d, 8> corners; activeView.mainGrid()->cellCornerVertices(resCellIdx, corners.data()); std::vector<std::vector<cvf::Vec3d>> eclCellPolygons; bool hasIntersection = RigHexIntersectionTools::planeHexIntersectionPolygons(corners, frMx, eclCellPolygons); if (!hasIntersection || eclCellPolygons.empty()) continue; // Transform eclCell - plane intersection onto fracture cvf::Mat4d invertedTransformMatrix = frMx.getInverted(); for (std::vector<cvf::Vec3d>& eclCellPolygon : eclCellPolygons) { for (cvf::Vec3d& v : eclCellPolygon) { v.transformPoint(invertedTransformMatrix); } } cvf::Vec3d fractureNormal = cvf::Vec3d(frMx.col(2)); for (const std::vector<cvf::Vec3d>& eclCellPolygon : eclCellPolygons) { // Clip Eclipse cell polygon with fracture border std::vector<std::vector<cvf::Vec3d>> clippedPolygons = RigCellGeometryTools::intersectPolygons(eclCellPolygon, borderPolygonLocalCsd); for (auto& clippedPolygon : clippedPolygons) { for (auto& v : clippedPolygon) { v.transformPoint(frMx); } } // Create triangles from the clipped polygons for (auto& clippedPolygon : clippedPolygons) { cvf::EarClipTesselator tess; tess.setNormal(fractureNormal); cvf::Vec3dArray cvfNodes(clippedPolygon); tess.setGlobalNodeArray(cvfNodes); std::vector<size_t> polyIndexes; for (size_t idx = 0; idx < clippedPolygon.size(); ++idx) polyIndexes.push_back(idx); tess.setPolygonIndices(polyIndexes); std::vector<size_t> triangleIndices; tess.calculateTriangles(&triangleIndices); for (size_t idx : triangleIndices) { maskTriangles.push_back(cvf::Vec3f(displCoordTrans->transformToDisplayCoord(clippedPolygon[idx]))); } } } } } if (maskTriangles.size() >= 3) { cvf::ref<cvf::DrawableGeo> maskTriangleGeo = new cvf::DrawableGeo; maskTriangleGeo->setVertexArray(new cvf::Vec3fArray(maskTriangles)); cvf::ref<cvf::PrimitiveSetDirect> primitives = new cvf::PrimitiveSetDirect(cvf::PT_TRIANGLES); primitives->setIndexCount(maskTriangles.size()); maskTriangleGeo->addPrimitiveSet(primitives.p()); maskTriangleGeo->computeNormals(); cvf::ref<cvf::Part> containmentMaskPart = new cvf::Part(0, "FractureContainmentMaskPart"); containmentMaskPart->setDrawable(maskTriangleGeo.p()); containmentMaskPart->setSourceInfo(new RivObjectSourceInfo(m_rimFracture)); cvf::Color4f maskColor = cvf::Color4f(cvf::Color3f(cvf::Color3::GRAY)); caf::SurfaceEffectGenerator surfaceGen(maskColor, caf::PO_NONE); cvf::ref<cvf::Effect> eff = surfaceGen.generateCachedEffect(); containmentMaskPart->setEffect(eff.p()); return containmentMaskPart; } return nullptr; }