diff --git a/libs/MeshKernelApi/CMakeLists.txt b/libs/MeshKernelApi/CMakeLists.txt
index 041a7024e..c23cab058 100644
--- a/libs/MeshKernelApi/CMakeLists.txt
+++ b/libs/MeshKernelApi/CMakeLists.txt
@@ -28,6 +28,7 @@ set(SRC_LIST
${SRC_DIR}/MeshKernel.cpp
${SRC_DIR}/NodeInPolygonCache.cpp
${SRC_DIR}/PolygonRefinementCache.cpp
+ ${SRC_DIR}/SmallFlowEdgeCentreCache.cpp
)
# list of target headers
@@ -47,6 +48,7 @@ set(
${DOMAIN_INC_DIR}/MeshKernel.hpp
${DOMAIN_INC_DIR}/NodeInPolygonCache.hpp
${DOMAIN_INC_DIR}/PolygonRefinementCache.hpp
+ ${DOMAIN_INC_DIR}/SmallFlowEdgeCentreCache.hpp
${DOMAIN_INC_DIR}/State.hpp
${DOMAIN_INC_DIR}/Utils.hpp
${VERSION_INC_DIR}/Version/Version.hpp
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/SmallFlowEdgeCentreCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/SmallFlowEdgeCentreCache.hpp
new file mode 100644
index 000000000..f5e9b9fcf
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/SmallFlowEdgeCentreCache.hpp
@@ -0,0 +1,57 @@
+//---- GPL ---------------------------------------------------------------------
+//
+// Copyright (C) Stichting Deltares, 2011-2024.
+//
+// This program 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 version 3.
+//
+// This program 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 for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// contact: delft3d.support@deltares.nl
+// Stichting Deltares
+// P.O. Box 177
+// 2600 MH Delft, The Netherlands
+//
+// All indications and logos of, and references to, "Delft3D" and "Deltares"
+// are registered trademarks of Stichting Deltares, and remain the property of
+// Stichting Deltares. All rights reserved.
+//
+//------------------------------------------------------------------------------
+
+#pragma once
+
+#include
+#include
+
+#include "MeshKernel/Point.hpp"
+
+#include "MeshKernelApi/CachedPointValues.hpp"
+#include "MeshKernelApi/GeometryList.hpp"
+
+namespace meshkernelapi
+{
+
+ /// @brief Cache centre of edges
+ class SmallFlowEdgeCentreCache : public CachedPointValues
+ {
+ public:
+ /// @brief Constructor
+ SmallFlowEdgeCentreCache(const double lengthThreshold,
+ const std::vector& edgeCentres);
+
+ /// @brief Determine if current options match those used to construct the object
+ bool ValidOptions(const double lengthThreshold) const;
+
+ private:
+ /// @brief Threshold for small edge length
+ double m_lengthThreshold;
+ };
+
+} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp
index ba44c1b8d..64e470509 100644
--- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp
+++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp
@@ -43,6 +43,7 @@
#include "MeshKernelApi/FacePolygonPropertyCache.hpp"
#include "MeshKernelApi/NodeInPolygonCache.hpp"
#include "MeshKernelApi/PolygonRefinementCache.hpp"
+#include "MeshKernelApi/SmallFlowEdgeCentreCache.hpp"
namespace meshkernelapi
{
@@ -85,6 +86,7 @@ namespace meshkernelapi
std::shared_ptr m_boundariesAsPolygonCache; ///< Cache
std::shared_ptr m_polygonRefinementCache; ///< Cache for polygon refinement
std::shared_ptr m_nodeInPolygonCache; ///< Cache for node in polygon
+ std::shared_ptr m_smallFlowEdgeCentreCache; ///< Cache for small flow edge centres
};
} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp
index ffd564407..6f1879671 100644
--- a/libs/MeshKernelApi/src/MeshKernel.cpp
+++ b/libs/MeshKernelApi/src/MeshKernel.cpp
@@ -3426,10 +3426,19 @@ namespace meshkernelapi
{
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
+
+ if (meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache != nullptr)
+ {
+ meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache.reset();
+ throw meshkernel::ConstraintError("Small flow edge data has already been cached. Cached values will be deleted.");
+ }
+
const auto edgesCrossingSmallFlowEdges = meshKernelState[meshKernelId].m_mesh2d->GetEdgesCrossingSmallFlowEdges(smallFlowEdgesLengthThreshold);
const auto smallFlowEdgeCenters = meshKernelState[meshKernelId].m_mesh2d->GetFlowEdgesCenters(edgesCrossingSmallFlowEdges);
- numSmallFlowEdges = static_cast(smallFlowEdgeCenters.size());
+ meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache = std::make_shared(smallFlowEdgesLengthThreshold, smallFlowEdgeCenters);
+
+ numSmallFlowEdges = meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache->Size();
}
catch (...)
{
@@ -3448,10 +3457,19 @@ namespace meshkernelapi
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
- const auto edgesCrossingSmallFlowEdges = meshKernelState[meshKernelId].m_mesh2d->GetEdgesCrossingSmallFlowEdges(smallFlowEdgesThreshold);
- const auto smallFlowEdgeCenters = meshKernelState[meshKernelId].m_mesh2d->GetFlowEdgesCenters(edgesCrossingSmallFlowEdges);
+ if (meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache == nullptr)
+ {
+ throw meshkernel::ConstraintError("Small flow edge data has not been cached");
+ }
+
+ if (!meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache->ValidOptions(smallFlowEdgesThreshold))
+ {
+ meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache.reset();
+ throw meshkernel::ConstraintError("Given small flow edge options are incompatible with the cached values. Cached values will be deleted.");
+ }
- ConvertPointVectorToGeometryList(smallFlowEdgeCenters, result);
+ meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache->Copy(result);
+ meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache.reset();
}
catch (...)
{
diff --git a/libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp b/libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp
new file mode 100644
index 000000000..4ee8fc9fa
--- /dev/null
+++ b/libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp
@@ -0,0 +1,37 @@
+//---- GPL ---------------------------------------------------------------------
+//
+// Copyright (C) Stichting Deltares, 2011-2024.
+//
+// This program 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 version 3.
+//
+// This program 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 for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// contact: delft3d.support@deltares.nl
+// Stichting Deltares
+// P.O. Box 177
+// 2600 MH Delft, The Netherlands
+//
+// All indications and logos of, and references to, "Delft3D" and "Deltares"
+// are registered trademarks of Stichting Deltares, and remain the property of
+// Stichting Deltares. All rights reserved.
+//
+//------------------------------------------------------------------------------
+
+#include "MeshKernelApi/SmallFlowEdgeCentreCache.hpp"
+
+meshkernelapi::SmallFlowEdgeCentreCache::SmallFlowEdgeCentreCache(const double lengthThreshold,
+ const std::vector& edgeCentres)
+ : CachedPointValues(edgeCentres), m_lengthThreshold(lengthThreshold) {}
+
+bool meshkernelapi::SmallFlowEdgeCentreCache::ValidOptions(const double lengthThreshold) const
+{
+ return lengthThreshold == m_lengthThreshold;
+}
diff --git a/libs/MeshKernelApi/tests/src/ApiTest.cpp b/libs/MeshKernelApi/tests/src/ApiTest.cpp
index c24e7da03..9ef18bde7 100644
--- a/libs/MeshKernelApi/tests/src/ApiTest.cpp
+++ b/libs/MeshKernelApi/tests/src/ApiTest.cpp
@@ -1761,6 +1761,65 @@ TEST_F(CartesianApiTestFixture, GetSmallFlowEdges_OnMesh2D_ShouldGetSmallFlowEdg
ASSERT_NEAR(result.coordinates_y[0], 0.0, tolerance);
}
+TEST_F(CartesianApiTestFixture, GetSmallFlowEdges_OnMesh2D_GetSmallFlowEdgesFailures)
+{
+ // Prepare a mesh with two triangles
+ meshkernelapi::Mesh2D mesh2d;
+
+ std::vector node_x{0.0, 1.0, 1.0, 1.0};
+ std::vector node_y{0.0, 0.0, 0.3, -0.3};
+ std::vector edge_nodes{0, 3, 3, 1, 1, 0, 1, 2, 2, 0};
+
+ mesh2d.node_x = node_x.data();
+ mesh2d.node_y = node_y.data();
+ mesh2d.edge_nodes = edge_nodes.data();
+ mesh2d.num_edges = static_cast(edge_nodes.size() * 0.5);
+ mesh2d.num_nodes = static_cast(node_x.size());
+
+ // Get the meshkernel id
+ auto const meshKernelId = GetMeshKernelId();
+ double const smallFlowEdgesThreshold = 100.0;
+ meshkernelapi::GeometryList result{};
+
+ auto errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // Execute
+ errorCode = mkernel_mesh2d_set(meshKernelId, mesh2d);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ int numSmallFlowEdges;
+ errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges);
+
+ // Assert
+ std::vector coordinates_x(numSmallFlowEdges);
+ std::vector coordinates_y(numSmallFlowEdges);
+ result.coordinates_x = coordinates_x.data();
+ result.coordinates_y = coordinates_y.data();
+ result.num_coordinates = numSmallFlowEdges;
+
+ errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Cache has been deleted
+ errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // Re-cache values
+ errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Get values with different set of options
+ errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, 2.0 * smallFlowEdgesThreshold, result);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // Re-cache values
+ errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ // Attempt at getting the size again will cause an error
+ errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+}
+
TEST_F(CartesianApiTestFixture, CountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ShouldCountObtuseTriangles)
{
// Prepare a mesh with one obtuse triangle