diff --git a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake index 13f97b648e..b5d0e2f21c 100644 --- a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake @@ -46,12 +46,14 @@ ${CEE_CURRENT_LIST_DIR}RigEclipseNativeStatCalc.h ${CEE_CURRENT_LIST_DIR}RigEclipseNativeVisibleCellsStatCalc.h ${CEE_CURRENT_LIST_DIR}RigEclipseMultiPropertyStatCalc.h ${CEE_CURRENT_LIST_DIR}RigWellLogCurveData.h +${CEE_CURRENT_LIST_DIR}RigWellLogExtractionTools.h ${CEE_CURRENT_LIST_DIR}RigTimeHistoryResultAccessor.h ${CEE_CURRENT_LIST_DIR}RigCurveDataTools.h ${CEE_CURRENT_LIST_DIR}RigSummaryCaseData.h ${CEE_CURRENT_LIST_DIR}RigLasFileExporter.h ${CEE_CURRENT_LIST_DIR}RigSimulationWellCoordsAndMD.h ${CEE_CURRENT_LIST_DIR}RigFishbonesGeometry.h +${CEE_CURRENT_LIST_DIR}RigWellPathIntersectionTools.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -98,6 +100,7 @@ ${CEE_CURRENT_LIST_DIR}RigSummaryCaseData.cpp ${CEE_CURRENT_LIST_DIR}RigLasFileExporter.cpp ${CEE_CURRENT_LIST_DIR}RigSimulationWellCoordsAndMD.cpp ${CEE_CURRENT_LIST_DIR}RigFishbonesGeometry.cpp +${CEE_CURRENT_LIST_DIR}RigWellPathIntersectionTools.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ReservoirDataModel/RigWellPathIntersectionTools.cpp b/ApplicationCode/ReservoirDataModel/RigWellPathIntersectionTools.cpp new file mode 100644 index 0000000000..9dd270db65 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigWellPathIntersectionTools.cpp @@ -0,0 +1,311 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RigWellPathIntersectionTools.h" + +#include "RiaLogging.h" + +#include "RigWellPath.h" +#include "RigMainGrid.h" +#include "RigEclipseCaseData.h" +#include "RigWellLogExtractionTools.h" + +#include "cvfGeometryTools.h" +#include "cvfMatrix3.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigWellPathIntersectionTools::findCellsIntersectedByPath(const RigEclipseCaseData* caseData, const std::vector& coords, bool includeStartCell, bool includeEndCell) +{ + std::vector intersectionInfo; + const RigMainGrid* grid = caseData->mainGrid(); + + if (coords.size() < 2) return intersectionInfo; + + std::vector intersections = getIntersectedCells(grid, coords); + removeEnteringIntersections(&intersections); + + if (intersections.empty()) return intersectionInfo; + + cvf::Vec3d startPoint; + cvf::Vec3d endPoint; + size_t cellIndex; + WellPathCellDirection direction; + + auto& intersection = intersections.cbegin(); + + if (includeStartCell) + { + startPoint = coords[0]; + endPoint = intersection->m_intersectionPoint; + cellIndex = findCellFromCoords(grid, startPoint); + direction = calculateDirectionInCell(grid, cellIndex, startPoint, endPoint); + intersectionInfo.push_back(WellPathCellIntersectionInfo(cellIndex, direction, startPoint, endPoint)); + } + + startPoint = intersection->m_intersectionPoint; + cellIndex = intersection->m_hexIndex; + + ++intersection; + + while (intersection != intersections.cend()) + { + endPoint = intersection->m_intersectionPoint; + direction = calculateDirectionInCell(grid, cellIndex, startPoint, endPoint); + intersectionInfo.push_back(WellPathCellIntersectionInfo(cellIndex, direction, startPoint, endPoint)); + + startPoint = endPoint; + cellIndex = intersection->m_hexIndex; + ++intersection; + } + + if (includeEndCell) + { + endPoint = coords[coords.size() - 1]; + direction = calculateDirectionInCell(grid, cellIndex, startPoint, endPoint); + intersectionInfo.push_back(WellPathCellIntersectionInfo(cellIndex, direction, startPoint, endPoint)); + } + + return intersectionInfo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigWellPathIntersectionTools::getIntersectedCells(const RigMainGrid* grid, const std::vector& coords) +{ + const std::vector& nodeCoords = grid->nodes(); + std::vector intersections; + for (size_t i = 0; i < coords.size() - 1; ++i) + { + cvf::BoundingBox bb; + bb.add(coords[i]); + bb.add(coords[i + 1]); + + std::vector closeCells = findCloseCells(grid, bb); + + cvf::Vec3d hexCorners[8]; + + for (size_t closeCell : closeCells) + { + const RigCell& cell = grid->globalCellArray()[closeCell]; + if (cell.isInvalid()) continue; + + setHexCorners(cell, nodeCoords, hexCorners); + + RigHexIntersector::lineHexCellIntersection(coords[i], coords[i + 1], hexCorners, closeCell, &intersections); + } + } + + return intersections; +} + +//-------------------------------------------------------------------------------------------------- +/// Calculates direction vectors for each axis in the cell. +//-------------------------------------------------------------------------------------------------- +void RigWellPathIntersectionTools::calculateCellMainAxisVectors(const std::array& hexCorners, cvf::Vec3d* iAxisDirection, cvf::Vec3d* jAxisDirection, cvf::Vec3d* kAxisDirection) +{ + for (auto vec : hexCorners) + { + RiaLogging::debug(QString("%1, %2, %3").arg(vec.x()).arg(vec.y()).arg(vec.z())); + } + *iAxisDirection = calculateCellMainAxisVector(hexCorners, cvf::StructGridInterface::NEG_I, cvf::StructGridInterface::POS_I); + *jAxisDirection = calculateCellMainAxisVector(hexCorners, cvf::StructGridInterface::NEG_J, cvf::StructGridInterface::POS_J); + *kAxisDirection = calculateCellMainAxisVector(hexCorners, cvf::StructGridInterface::NEG_K, cvf::StructGridInterface::POS_K); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RigWellPathIntersectionTools::calculateCellMainAxisVector(const std::array& hexCorners, + cvf::StructGridInterface::FaceType negativeFace, + cvf::StructGridInterface::FaceType positiveFace) +{ + cvf::ubyte negativeFaceVertexIndices[4]; + cvf::StructGridInterface::cellFaceVertexIndices(negativeFace, negativeFaceVertexIndices); + cvf::Vec3d negativeFaceCenter = cvf::GeometryTools::computeFaceCenter(hexCorners[negativeFaceVertexIndices[0]], + hexCorners[negativeFaceVertexIndices[1]], + hexCorners[negativeFaceVertexIndices[2]], + hexCorners[negativeFaceVertexIndices[3]]); + + cvf::ubyte positiveFaceVertexIndices[4]; + cvf::StructGridInterface::cellFaceVertexIndices(positiveFace, positiveFaceVertexIndices); + cvf::Vec3d positiveFaceCenter = cvf::GeometryTools::computeFaceCenter(hexCorners[positiveFaceVertexIndices[0]], + hexCorners[positiveFaceVertexIndices[1]], + hexCorners[positiveFaceVertexIndices[2]], + hexCorners[positiveFaceVertexIndices[3]]); + + return positiveFaceCenter - negativeFaceCenter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +WellPathCellDirection RigWellPathIntersectionTools::calculateDirectionInCell(const std::array& hexCorners, const cvf::Vec3d& startPoint, const cvf::Vec3d& endPoint) +{ + cvf::Vec3d vec = endPoint - startPoint; + + cvf::Vec3d iAxisVector; + cvf::Vec3d jAxisVector; + cvf::Vec3d kAxisVector; + calculateCellMainAxisVectors(hexCorners, &iAxisVector, &jAxisVector, &kAxisVector); + + cvf::Vec3d iAxisDirection = iAxisVector.getNormalized(); + cvf::Vec3d jAxisDirection = jAxisVector.getNormalized(); + cvf::Vec3d kAxisDirection = kAxisVector.getNormalized(); + + cvf::Mat3d localCellCoordinateSystem(iAxisDirection.x(), jAxisDirection.x(), kAxisDirection.x(), + iAxisDirection.y(), jAxisDirection.y(), kAxisDirection.y(), + iAxisDirection.z(), jAxisDirection.z(), kAxisDirection.z()); + + cvf::Vec3d localCellCoordinateVec = vec.getTransformedVector(localCellCoordinateSystem.getInverted()); + + double iLengthFraction = abs(localCellCoordinateVec.x() / iAxisVector.length()); + double jLengthFraction = abs(localCellCoordinateVec.y() / jAxisVector.length()); + double kLengthFraction = abs(localCellCoordinateVec.z() / kAxisVector.length()); + + if (iLengthFraction > jLengthFraction && iLengthFraction > kLengthFraction) + { + WellPathCellDirection direction = POS_I; + if (localCellCoordinateVec.x() < 0) + { + direction = NEG_I; + } + return direction; + } + else if (jLengthFraction > iLengthFraction && jLengthFraction > kLengthFraction) + { + WellPathCellDirection direction = POS_J; + if (localCellCoordinateVec.y() < 0) + { + direction = NEG_J; + } + return direction; + } + else + { + WellPathCellDirection direction = POS_K; + if (localCellCoordinateVec.z() < 0) + { + direction = NEG_K; + } + return direction; + } + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +WellPathCellDirection RigWellPathIntersectionTools::calculateDirectionInCell(const RigMainGrid* grid, size_t cellIndex, const cvf::Vec3d& startPoint, const cvf::Vec3d& endPoint) +{ + std::array hexCorners = getCellHexCorners(grid, cellIndex); + + return calculateDirectionInCell(hexCorners, startPoint, endPoint); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigWellPathIntersectionTools::findCloseCells(const RigMainGrid* grid, const cvf::BoundingBox& bb) +{ + std::vector closeCells; + grid->findIntersectingCells(bb, &closeCells); + return closeCells; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RigWellPathIntersectionTools::findCellFromCoords(const RigMainGrid* grid, const cvf::Vec3d& coords) +{ + const std::vector& nodeCoords = grid->nodes(); + + cvf::BoundingBox bb; + bb.add(coords); + std::vector closeCells = findCloseCells(grid, bb); + cvf::Vec3d hexCorners[8]; + + for (size_t closeCell : closeCells) + { + const RigCell& cell = grid->globalCellArray()[closeCell]; + if (cell.isInvalid()) continue; + + setHexCorners(cell, nodeCoords, hexCorners); + + if (RigHexIntersector::isPointInCell(coords, hexCorners, closeCell)) + { + return closeCell; + } + } + + // Coordinate is outside any cells? + CVF_ASSERT(false); + return 0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::array RigWellPathIntersectionTools::getCellHexCorners(const RigMainGrid* grid, size_t cellIndex) +{ + const std::vector& nodeCoords = grid->nodes(); + std::array corners; + const RigCell& cell = grid->globalCellArray()[cellIndex]; + setHexCorners(cell, nodeCoords, corners.data()); + + return corners; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigWellPathIntersectionTools::setHexCorners(const RigCell& cell, const std::vector& nodeCoords, cvf::Vec3d* hexCorners) +{ + const caf::SizeTArray8& cornerIndices = cell.cornerIndices(); + + hexCorners[0] = nodeCoords[cornerIndices[0]]; + hexCorners[1] = nodeCoords[cornerIndices[1]]; + hexCorners[2] = nodeCoords[cornerIndices[2]]; + hexCorners[3] = nodeCoords[cornerIndices[3]]; + hexCorners[4] = nodeCoords[cornerIndices[4]]; + hexCorners[5] = nodeCoords[cornerIndices[5]]; + hexCorners[6] = nodeCoords[cornerIndices[6]]; + hexCorners[7] = nodeCoords[cornerIndices[7]]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigWellPathIntersectionTools::removeEnteringIntersections(std::vector* intersections) +{ + for (auto it = intersections->begin(); it != intersections->end();) + { + if (it->m_isIntersectionEntering) + { + it = intersections->erase(it); + } + else + { + ++it; + } + } +} + diff --git a/ApplicationCode/ReservoirDataModel/RigWellPathIntersectionTools.h b/ApplicationCode/ReservoirDataModel/RigWellPathIntersectionTools.h new file mode 100644 index 0000000000..2d4b72bbcb --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigWellPathIntersectionTools.h @@ -0,0 +1,85 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RigCell.h" + +#include "RigWellLogExtractionTools.h" + +#include "cvfVector3.h" + +#include + +class RigWellPath; +class RigMainGrid; +class RigEclipseCaseData; + +//================================================================================================== +/// +//================================================================================================== +enum WellPathCellDirection { + POS_I, + NEG_I, + POS_J, + NEG_J, + POS_K, + NEG_K +}; + +//================================================================================================== +/// +//================================================================================================== +struct WellPathCellIntersectionInfo { + WellPathCellIntersectionInfo(size_t cellIndex, WellPathCellDirection direction, cvf::Vec3d startPoint, cvf::Vec3d endPoint) + : cellIndex(cellIndex), + direction(direction), + startPoint(startPoint), + endPoint(endPoint) + {} + + size_t cellIndex; + WellPathCellDirection direction; + cvf::Vec3d startPoint; + cvf::Vec3d endPoint; +}; + +//================================================================================================== +/// +//================================================================================================== +class RigWellPathIntersectionTools : public cvf::Object +{ +public: + static std::vector findCellsIntersectedByPath(const RigEclipseCaseData* caseData, const std::vector& coords, bool includeStartCell = true, bool includeEndCell = true); + + static std::vector getIntersectedCells(const RigMainGrid* grid, const std::vector& coords); + + // Calculate direction + static void calculateCellMainAxisVectors(const std::array& hexCorners, cvf::Vec3d* iAxisDirection, cvf::Vec3d* jAxisDirection, cvf::Vec3d* kAxisDirection); + static cvf::Vec3d calculateCellMainAxisVector(const std::array& hexCorners, cvf::StructGridInterface::FaceType startFace, cvf::StructGridInterface::FaceType endFace); + static WellPathCellDirection calculateDirectionInCell(const std::array& hexCorners, const cvf::Vec3d& startPoint, const cvf::Vec3d& endPoint); + static WellPathCellDirection calculateDirectionInCell(const RigMainGrid* grid, size_t cellIndex, const cvf::Vec3d& startPoint, const cvf::Vec3d& endPoint); + + static std::vector findCloseCells(const RigMainGrid* grid, const cvf::BoundingBox& bb); + static size_t findCellFromCoords(const RigMainGrid* caseData, const cvf::Vec3d& coords); + + static std::array getCellHexCorners(const RigMainGrid* grid, size_t cellIndex); + static void setHexCorners(const RigCell& cell, const std::vector& nodeCoords, cvf::Vec3d* hexCorners); + + static void removeEnteringIntersections(std::vector* intersections); +}; diff --git a/ApplicationCode/UnitTests/CMakeLists_files.cmake b/ApplicationCode/UnitTests/CMakeLists_files.cmake index 49274a271f..e3c73d10d1 100644 --- a/ApplicationCode/UnitTests/CMakeLists_files.cmake +++ b/ApplicationCode/UnitTests/CMakeLists_files.cmake @@ -16,6 +16,7 @@ ${CEE_CURRENT_LIST_DIR}RifReaderEclipseSummary-Test.cpp ${CEE_CURRENT_LIST_DIR}RigActiveCellInfo-Test.cpp ${CEE_CURRENT_LIST_DIR}RigReservoir-Test.cpp ${CEE_CURRENT_LIST_DIR}RigStatisticsMath-Test.cpp +${CEE_CURRENT_LIST_DIR}RigWellPathIntersectionTools-Test.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogExtractionCurveImpl-Test.cpp ${CEE_CURRENT_LIST_DIR}RivPipeGeometryGenerator-Test.cpp ${CEE_CURRENT_LIST_DIR}RivTernaryScalarMapper-Test.cpp diff --git a/ApplicationCode/UnitTests/RigWellPathIntersectionTools-Test.cpp b/ApplicationCode/UnitTests/RigWellPathIntersectionTools-Test.cpp new file mode 100644 index 0000000000..a71e126cc9 --- /dev/null +++ b/ApplicationCode/UnitTests/RigWellPathIntersectionTools-Test.cpp @@ -0,0 +1,140 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "gtest/gtest.h" + +#include "RigWellPathIntersectionTools.h" + +#include "cvfStructGrid.h" + + +TEST(RigWellPathIntersectionTools, TestCalculateMainAxisVector) +{ + std::array hexCorners = { + cvf::Vec3d(0.0, 0.0, 0.0), + cvf::Vec3d(10.0, 0.0, 0.0), + cvf::Vec3d(10.0, 10.0, 0.0), + cvf::Vec3d(0.0, 10.0, 0.0), + cvf::Vec3d(0.0, 0.0, 10.0), + cvf::Vec3d(10.0, 0.0, 10.0), + cvf::Vec3d(10.0, 10.0, 10.0), + cvf::Vec3d(0.0, 10.0, 10.0), + }; + + cvf::Vec3d iMainAxisVector = RigWellPathIntersectionTools::calculateCellMainAxisVector(hexCorners, cvf::StructGridInterface::NEG_I, cvf::StructGridInterface::POS_I); + EXPECT_EQ(10, iMainAxisVector.x()); + EXPECT_EQ(0, iMainAxisVector.y()); + EXPECT_EQ(0, iMainAxisVector.z()); + + cvf::Vec3d jMainAxisVector = RigWellPathIntersectionTools::calculateCellMainAxisVector(hexCorners, cvf::StructGridInterface::NEG_J, cvf::StructGridInterface::POS_J); + EXPECT_EQ(0 , jMainAxisVector.x()); + EXPECT_EQ(10, jMainAxisVector.y()); + EXPECT_EQ(0, jMainAxisVector.z()); + + cvf::Vec3d kMainAxisVector = RigWellPathIntersectionTools::calculateCellMainAxisVector(hexCorners, cvf::StructGridInterface::NEG_K, cvf::StructGridInterface::POS_K); + EXPECT_EQ(0, kMainAxisVector.x()); + EXPECT_EQ(0, kMainAxisVector.y()); + EXPECT_EQ(10, kMainAxisVector.z()); +} + +TEST(RigWellPathIntersectionTools, TestCalculateMainAxisVectors) +{ + std::array hexCorners = { + cvf::Vec3d(0.0, 0.0, 0.0), + cvf::Vec3d(10.0, 0.0, 0.0), + cvf::Vec3d(10.0, 10.0, 0.0), + cvf::Vec3d(0.0, 10.0, 0.0), + cvf::Vec3d(0.0, 0.0, 10.0), + cvf::Vec3d(10.0, 0.0, 10.0), + cvf::Vec3d(10.0, 10.0, 10.0), + cvf::Vec3d(0.0, 10.0, 10.0), + }; + + + cvf::Vec3d iMainAxisVector; + cvf::Vec3d jMainAxisVector; + cvf::Vec3d kMainAxisVector; + RigWellPathIntersectionTools::calculateCellMainAxisVectors(hexCorners, &iMainAxisVector, &jMainAxisVector, &kMainAxisVector); + + EXPECT_EQ(10, iMainAxisVector.x()); + EXPECT_EQ(0, iMainAxisVector.y()); + EXPECT_EQ(0, iMainAxisVector.z()); + + EXPECT_EQ(0 , jMainAxisVector.x()); + EXPECT_EQ(10, jMainAxisVector.y()); + EXPECT_EQ(0, jMainAxisVector.z()); + + EXPECT_EQ(0, kMainAxisVector.x()); + EXPECT_EQ(0, kMainAxisVector.y()); + EXPECT_EQ(10, kMainAxisVector.z()); +} + +TEST(RigWellPathIntersectionTools, TestCalculateDirectionInCellThroughCellCenters) +{ + std::array hexCorners = { + cvf::Vec3d(0.0, 0.0, 0.0), + cvf::Vec3d(10.0, 0.0, 0.0), + cvf::Vec3d(10.0, 10.0, 0.0), + cvf::Vec3d(0.0, 10.0, 0.0), + cvf::Vec3d(0.0, 0.0, 10.0), + cvf::Vec3d(10.0, 0.0, 10.0), + cvf::Vec3d(10.0, 10.0, 10.0), + cvf::Vec3d(0.0, 10.0, 10.0), + }; + + { + cvf::Vec3d startPoint(0, 5, 5); + cvf::Vec3d endPoint(10, 5, 5); + WellPathCellDirection direction = RigWellPathIntersectionTools::calculateDirectionInCell(hexCorners, startPoint, endPoint); + EXPECT_EQ(POS_I, direction); + } + + { + cvf::Vec3d startPoint(5, 0, 5); + cvf::Vec3d endPoint(5, 10, 5); + WellPathCellDirection direction = RigWellPathIntersectionTools::calculateDirectionInCell(hexCorners, startPoint, endPoint); + EXPECT_EQ(POS_J, direction); + } + + { + cvf::Vec3d startPoint(5, 5, 0); + cvf::Vec3d endPoint(5, 5, 10); + WellPathCellDirection direction = RigWellPathIntersectionTools::calculateDirectionInCell(hexCorners, startPoint, endPoint); + EXPECT_EQ(POS_K, direction); + } +} + +TEST(RigWellPathIntersectionTools, TestCalculateJDirectionThroughCells) +{ + std::array hexCorners = { + cvf::Vec3d(402380, 7.21315e+06, -4219.43), + cvf::Vec3d(402475, 7.21311e+06, -4226.57), + cvf::Vec3d(402510, 7.2132e+06, -4226.75), + cvf::Vec3d(402414, 7.21324e+06, -4222.8), + cvf::Vec3d(402385, 7.21314e+06, -4232.71), + cvf::Vec3d(402480, 7.2131e+06, -4239.88), + cvf::Vec3d(402515, 7.2132e+06, -4239.94), + cvf::Vec3d(402419, 7.21323e+06, -4235.84), + }; + + cvf::Vec3d startPoint(402428, 7.21323e+06, -4223.35); + cvf::Vec3d endPoint(402399, 7.21314e+06, -4224.48); + WellPathCellDirection direction = RigWellPathIntersectionTools::calculateDirectionInCell(hexCorners, startPoint, endPoint); + + EXPECT_EQ(NEG_J, direction); +}