Skip to content

Commit

Permalink
GRIDEDIT-1536 Small refactoring and fixing of unit test
Browse files Browse the repository at this point in the history
Added api unit functions and unit test, though the test does not yet work correctly
  • Loading branch information
BillSenior committed Nov 21, 2024
1 parent dc3de28 commit d6a93fa
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 70 deletions.
26 changes: 16 additions & 10 deletions libs/MeshKernel/include/MeshKernel/MeshTriangulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,16 @@ namespace meshkernel
class MeshTriangulation
{
public:
/// @brief Constructor
/// @brief Constructor with array of points
template <class PointVector>
MeshTriangulation(const PointVector& nodes);
MeshTriangulation(const PointVector& nodes,
const Projection projection);

/// @brief Constructor
/// @brief Constructor with separate arrays of x- and y-coordinates
template <class VectorType>
MeshTriangulation(const VectorType& xNodes,
const VectorType& yNodes);
const VectorType& yNodes,
const Projection projection);

/// @brief Get the projection type used in the triangulation
Projection GetProjection() const;
Expand Down Expand Up @@ -119,10 +121,12 @@ inline meshkernel::Projection meshkernel::MeshTriangulation::GetProjection() con
}

template <class PointVector>
meshkernel::MeshTriangulation::MeshTriangulation(const PointVector& nodes)
: m_nodes(nodes.begin(), nodes.end())
meshkernel::MeshTriangulation::MeshTriangulation(const PointVector& nodes,
const Projection projection)
: m_nodes(nodes.begin(), nodes.end()),
m_projection(projection)
{
if (nodes.size() < constants::gemetric::numNodesInTriangle)
if (nodes.size() < constants::geometric::numNodesInTriangle)
{
throw ConstraintError("Not enough nodes for a single triangle: {}", nodes.size());
}
Expand All @@ -145,10 +149,12 @@ meshkernel::MeshTriangulation::MeshTriangulation(const PointVector& nodes)

template <class VectorType>
inline meshkernel::MeshTriangulation::MeshTriangulation(const VectorType& xNodes,
const VectorType& yNodes)
: m_nodes(xNodes.size())
const VectorType& yNodes,
const Projection projection)
: m_nodes(xNodes.size()),
m_projection(projection)
{
if (xNodes.size() < constants::gemetric::numNodesInTriangle)
if (xNodes.size() < constants::geometric::numNodesInTriangle)
{
throw ConstraintError("Not enough nodes for a single triangle: {}", xNodes.size());
}
Expand Down
12 changes: 11 additions & 1 deletion libs/MeshKernel/include/MeshKernel/SampleInterpolator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ namespace meshkernel
{
public:
template <class VectorType>
SampleInterpolator(const VectorType& xNodes, const VectorType& yNodes) : m_triangulation(xNodes, yNodes) {}
SampleInterpolator(const VectorType& xNodes, const VectorType& yNodes,
const Projection projection)
: m_triangulation(xNodes, yNodes, projection) {}

/// @brief Get the number of nodes of size of the sample data.
UInt Size() const;

/// @brief Set sample data
template <class VectorType>
Expand All @@ -73,6 +78,11 @@ namespace meshkernel

} // namespace meshkernel

inline meshkernel::UInt meshkernel::SampleInterpolator::Size() const
{
return m_triangulation.NumberOfNodes();
}

inline bool meshkernel::SampleInterpolator::Contains(const std::string& name) const
{
return m_sampleData.contains(name);
Expand Down
16 changes: 0 additions & 16 deletions libs/MeshKernel/include/MeshKernel/TriangulationWrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,22 +226,6 @@ namespace meshkernel
return m_edgesFaces[edgeIndex][faceIndex];
}

/// @brief Retrieves the x coordinate of a triangulated node
/// @param nodeIndex The index of the node to retrieve
/// @return const reference to the x coordinate
[[nodiscard]] double GetXCoord(const UInt nodeIndex) const
{
return m_xCoordFlat[nodeIndex];
}

/// @brief Retrieves the y coordinate of a triangulated node
/// @param nodeIndex The index of the node to retrieve
/// @return const reference to the y coordinate
[[nodiscard]] double GetYCoord(const UInt nodeIndex) const
{
return m_yCoordFlat[nodeIndex];
}

/// @brief Retrieves the (x,y) coordinate of a triangulated node
/// @param nodeIndex The index of the node to retrieve
/// @return Point
Expand Down
57 changes: 14 additions & 43 deletions libs/MeshKernel/tests/src/MeshPropertyTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,44 +21,20 @@

namespace mk = meshkernel;

TEST(MeshPropertyTests, TriangulationTest)
TEST(MeshPropertyTests, SimpleSampleInterpolationTest)
{
const double tolerance = 1.0e-13;

std::vector<double> xValues{0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0};
std::vector<double> yValues{0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0};
// std::vector<double> xValues{0.0, 1.0, 2.0, 0.0, 1.0, 2.0, 0.0, 1.0, 2.0};
// std::vector<double> yValues{0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0};

std::vector<mk::Point> nodes{{0.25, 0.25}, {1.25, 0.25}, {2.25, 0.25}, {0.25, 1.25}, {1.25, 1.25}, {2.25, 1.25}, {0.25, 2.25}, {1.25, 2.25}, {2.25, 2.25}};
std::vector<double> interpolated(nodes.size(), 0.0);

mk::MeshTriangulation triangulation(xValues, yValues);
mk::SampleInterpolator properties(xValues, yValues, mk::Projection::cartesian);

// std::cout << "nullId = 4294967295;" << std::endl;
// std::cout << "nullValue = -999.0;" << std::endl;
// std::cout << "nodex = zeros (" << triangulation.NumberOfNodes() << ", 1);" << std::endl;
// std::cout << "nodey = zeros (" << triangulation.NumberOfNodes() << ", 1);" << std::endl;
// std::cout << "edges = zeros (" << triangulation.NumberOfEdges() << ", 2);" << std::endl;

// for (mk::UInt i = 0; i < triangulation.NumberOfNodes(); ++i)
// {
// std::cout << "nodex (" << i + 1 << ") = " << triangulation.GetNode(i).x << std::endl;
// }

// for (mk::UInt i = 0; i < triangulation.NumberOfNodes(); ++i)
// {
// std::cout << "nodey (" << i + 1 << ") = " << triangulation.GetNode(i).y << std::endl;
// }

// for (mk::UInt i = 0; i < triangulation.NumberOfEdges(); ++i)
// {
// std::cout << "edge (" << i + 1 << ", 1) = " << triangulation.GetEdge(i).first << std::endl;
// std::cout << "edge (" << i + 1 << ", 2) = " << triangulation.GetEdge(i).second << std::endl;
// }

// return;

mk::SampleInterpolator properties(xValues, yValues);
std::vector<double> expectedXDepths{0.25, 1.25, 2.25, 0.25, 1.25, 2.25, 0.25, 1.25, 2.25};
std::vector<double> expectedYDepths{0.25, 0.25, 0.25, 1.25, 1.25, 1.25, 2.25, 2.25, 2.25};

properties.SetData("xdepth", std::vector{0.0, 1.0, 2.0, 3.0,
0.0, 1.0, 2.0, 3.0,
Expand All @@ -70,35 +46,30 @@ TEST(MeshPropertyTests, TriangulationTest)
2.0, 2.0, 2.0, 2.0,
3.0, 3.0, 3.0, 3.0});

// properties.SetData("xdepth", std::vector{0.0, 1.0, 2.0,
// 0.0, 1.0, 2.0,
// 0.0, 1.0, 2.0});

// properties.SetData("ydepth", std::vector{0.0, 0.0, 0.0,
// 1.0, 1.0, 1.0,
// 2.0, 2.0, 2.0});

properties.Interpolate("xdepth", nodes, interpolated);

for (size_t i = 0; i < nodes.size(); ++i)
for (size_t i = 0; i < interpolated.size(); ++i)
{
std::cout << "xdepth interpolated " << interpolated[i] << std::endl;
EXPECT_NEAR(interpolated[i], expectedXDepths[i], tolerance);
}

std::span interpolatedData(interpolated.data(), interpolated.size());

properties.Interpolate("ydepth", nodes, interpolatedData);

for (size_t i = 0; i < nodes.size(); ++i)
for (size_t i = 0; i < interpolated.size(); ++i)
{
std::cout << "ydepth interpolated " << interpolatedData[i] << std::endl;
EXPECT_NEAR(interpolatedData[i], expectedYDepths[i], tolerance);
}
}

TEST(MeshPropertyTests, AveragePointTest)
{
std::vector<mk::Point> pnts{{1.0, 1.0}, {-999.0, -999.0}, {1.0, 1.0}, {1.0, 1.0}};
const double tolerance = 1.0e-13;

std::vector<mk::Point> pnts{{1.0, 2.0}, {-999.0, -999.0}, {1.0, 2.0}, {1.0, 2.0}};
mk::Point average = mk::ComputeAverageCoordinate(pnts, mk::Projection::sphericalAccurate);

std::cout << "average: " << average.x << ", " << average.y << std::endl;
EXPECT_NEAR(average.x, 1.0, tolerance);
EXPECT_NEAR(average.y, 2.0, tolerance);
}
18 changes: 18 additions & 0 deletions libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,18 @@ namespace meshkernelapi
const GeometryList& selectingPolygon,
const GeometryList& landBoundaries);

/// @brief Get the bathymetry data
/// @param[in] meshKernelId The id of the mesh state
/// @param[out] sampleData The mesh2d bathymetry data
/// @returns Error code
MKERNEL_API int mkernel_mesh2d_get_bathymetry_data(int meshKernelId, GeometryList& sampleData);

/// @brief get the bathymetry data size
/// @param[in] meshKernelId The id of the mesh state
/// @param[out] sampleDataSize The mesh2d bathymetry data size
/// @returns Error code
MKERNEL_API int mkernel_mesh2d_get_bathymetry_dimension(int meshKernelId, int& sampleDataSize);

/// @brief Gets the closest mesh2d node coordinates to a point, searching within a radius.
/// @param[in] meshKernelId Id of the grid state
/// @param[in] xCoordinateIn The x coordinate of the node to insert
Expand Down Expand Up @@ -1607,6 +1619,12 @@ namespace meshkernelapi
/// @returns Error code
MKERNEL_API int mkernel_mesh2d_set(int meshKernelId, const Mesh2D& mesh2d);

/// @brief Sets the bathymetry data for the mesh
/// @param[in] meshKernelId The id of the mesh state
/// @param[in] sampleData The mesh2d bathymetry data
/// @returns Error code
MKERNEL_API int mkernel_mesh2d_set_bathymetry_data(int meshKernelId, const GeometryList& sampleData);

/// @brief Snaps a mesh to a land boundary.
/// @param[in] meshKernelId The id of the mesh state
/// @param[in] selectingPolygon The polygon where to perform the snapping
Expand Down
3 changes: 3 additions & 0 deletions libs/MeshKernelApi/include/MeshKernelApi/State.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <MeshKernel/Mesh1D.hpp>
#include <MeshKernel/Mesh2D.hpp>
#include <MeshKernel/OrthogonalizationAndSmoothing.hpp>
#include <MeshKernel/SampleInterpolator.hpp>

#include "MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp"
#include "MeshKernelApi/ApiCache/CachedPointValues.hpp"
Expand Down Expand Up @@ -83,6 +84,8 @@ namespace meshkernelapi
// Exclusively owned state
meshkernel::Projection m_projection{meshkernel::Projection::cartesian}; ///< Projection used by the meshes

std::shared_ptr<meshkernel::SampleInterpolator> m_sampleInterpolator; ///< Associated samples and interpolator

// Cached values, used when dimensions are computed first, followed by values being retrieved in a separate call
std::shared_ptr<FacePolygonPropertyCache> m_facePropertyCache; ///< face property cache
std::shared_ptr<BoundariesAsPolygonCache> m_boundariesAsPolygonCache; ///< boundaries as polygon cache
Expand Down
97 changes: 97 additions & 0 deletions libs/MeshKernelApi/src/MeshKernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
#include <Version/Version.hpp>

#include <cstring>
#include <span>
#include <unordered_map>
#include <vector>

Expand Down Expand Up @@ -484,6 +485,102 @@ namespace meshkernelapi
return lastExitCode;
}

MKERNEL_API int mkernel_mesh2d_set_bathymetry_data(int meshKernelId, const GeometryList& sampleData)
{
lastExitCode = meshkernel::ExitCode::Success;
try
{
if (!meshKernelState.contains(meshKernelId))
{
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}

if (meshKernelState[meshKernelId].m_mesh2d == nullptr)
{
throw meshkernel::MeshKernelError("The selected mesh not exist.");
}

std::span<const double> xNodes(sampleData.coordinates_x, sampleData.num_coordinates);
std::span<const double> yNodes(sampleData.coordinates_y, sampleData.num_coordinates);
meshKernelState[meshKernelId].m_sampleInterpolator = std::make_shared<meshkernel::SampleInterpolator>(xNodes, yNodes, meshKernelState[meshKernelId].m_projection);

std::span<const double> bathymetryData(sampleData.values, sampleData.num_coordinates);
meshKernelState[meshKernelId].m_sampleInterpolator->SetData("depth", bathymetryData);
}
catch (...)
{
lastExitCode = HandleException();
}
return lastExitCode;
}

MKERNEL_API int mkernel_mesh2d_get_bathymetry_data(int meshKernelId, GeometryList& sampleData)
{
lastExitCode = meshkernel::ExitCode::Success;
try
{
if (!meshKernelState.contains(meshKernelId))
{
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}

if (meshKernelState[meshKernelId].m_mesh2d == nullptr)
{
throw meshkernel::MeshKernelError("The selected mesh2d does not exist.");
}

if (meshKernelState[meshKernelId].m_sampleInterpolator == nullptr)
{
throw meshkernel::MeshKernelError("The selected sample interpolator does not exist.");
}

if (sampleData.num_coordinates != static_cast<int>(meshKernelState[meshKernelId].m_mesh2d->GetNumNodes()))
{
throw meshkernel::MeshKernelError("GeometryList has wrong dimensions {} /= {}",
sampleData.num_coordinates,
meshKernelState[meshKernelId].m_mesh2d->GetNumNodes());
}

std::span<double> interpolatedSampleData(sampleData.values, sampleData.num_coordinates);
meshKernelState[meshKernelId].m_sampleInterpolator->Interpolate("depth", meshKernelState[meshKernelId].m_mesh2d->Nodes(), interpolatedSampleData);
}
catch (...)
{
lastExitCode = HandleException();
}
return lastExitCode;
}

MKERNEL_API int mkernel_mesh2d_get_bathymetry_dimension(int meshKernelId, int& sampleDataSize)
{
lastExitCode = meshkernel::ExitCode::Success;
sampleDataSize = -1;
try
{
if (!meshKernelState.contains(meshKernelId))
{
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}

if (meshKernelState[meshKernelId].m_sampleInterpolator == nullptr)
{
throw meshkernel::MeshKernelError("The sample interpolator does not exist.");
}

if (!meshKernelState[meshKernelId].m_sampleInterpolator->Contains("depth"))
{
throw meshkernel::MeshKernelError("The sample interpolator does not contains depth values.");
}

sampleDataSize = static_cast<int>(meshKernelState[meshKernelId].m_mesh2d->GetNumNodes());
}
catch (...)
{
lastExitCode = HandleException();
}
return lastExitCode;
}

MKERNEL_API int mkernel_mesh2d_snap_to_landboundary(int meshKernelId, const GeometryList& selectingPolygon, const GeometryList& landBoundaries)
{
lastExitCode = meshkernel::ExitCode::Success;
Expand Down
1 change: 1 addition & 0 deletions libs/MeshKernelApi/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ set(SRC_LIST
${SRC_DIR}/ErrorHandlingTests.cpp
${SRC_DIR}/Mesh2DRefinmentTests.cpp
${SRC_DIR}/Mesh2DTests.cpp
${SRC_DIR}/MeshPropertyTests.cpp
${SRC_DIR}/PolygonTests.cpp
${SRC_DIR}/UndoTests.cpp
)
Expand Down
Loading

0 comments on commit d6a93fa

Please sign in to comment.