From 0a58be0d7ebfcd4ff1cde7d4e0276992ecf9955d Mon Sep 17 00:00:00 2001
From: BillSenior <89970704+BillSenior@users.noreply.github.com>
Date: Thu, 31 Oct 2024 14:50:43 +0100
Subject: [PATCH] Avoid double computations (#378 | gridedit 1336)
---
libs/MeshKernelApi/CMakeLists.txt | 39 ++-
.../ApiCache/BoundariesAsPolygonCache.hpp | 66 +++++
.../ApiCache/CachedIntegerValues.hpp | 64 +++++
.../ApiCache/CachedPointValues.hpp | 70 +++++
.../ApiCache/FacePolygonPropertyCache.hpp | 62 ++++
.../ApiCache/HangingEdgeCache.hpp | 48 ++++
.../ApiCache/NodeInPolygonCache.hpp | 61 ++++
.../ApiCache/ObtuseTriangleCentreCache.hpp | 48 ++++
.../ApiCache/PolygonRefinementCache.hpp | 61 ++++
.../ApiCache/SmallFlowEdgeCentreCache.hpp | 57 ++++
.../include/MeshKernelApi/MeshKernel.hpp | 8 +
.../include/MeshKernelApi/State.hpp | 18 ++
.../include/MeshKernelApi/Utils.hpp | 17 +-
.../src/ApiCache/BoundariesAsPolygonCache.cpp | 52 ++++
.../src/ApiCache/CachedIntegerValues.cpp | 46 +++
.../src/ApiCache/CachedPointValues.cpp | 57 ++++
.../src/ApiCache/FacePolygonPropertyCache.cpp | 63 ++++
.../src/ApiCache/HangingEdgeCache.cpp | 46 +++
.../src/ApiCache/NodeInPolygonCache.cpp | 61 ++++
.../ApiCache/ObtuseTriangleCentreCache.cpp | 31 ++
.../src/ApiCache/PolygonRefinementCache.cpp | 51 ++++
.../src/ApiCache/SmallFlowEdgeCentreCache.cpp | 37 +++
libs/MeshKernelApi/src/MeshKernel.cpp | 271 +++++++++++++-----
libs/MeshKernelApi/tests/CMakeLists.txt | 1 +
libs/MeshKernelApi/tests/src/ApiCacheTest.cpp | 253 ++++++++++++++++
libs/MeshKernelApi/tests/src/ApiTest.cpp | 21 ++
.../tests/src/CurvilinearGridTests.cpp | 86 ++++++
.../tests/src/Mesh2DRefinmentTests.cpp | 124 +++++++-
libs/MeshKernelApi/tests/src/Mesh2DTests.cpp | 88 ++++++
29 files changed, 1829 insertions(+), 78 deletions(-)
create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp
create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedIntegerValues.hpp
create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedPointValues.hpp
create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp
create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/ApiCache/HangingEdgeCache.hpp
create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/ApiCache/NodeInPolygonCache.hpp
create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/ApiCache/ObtuseTriangleCentreCache.hpp
create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/ApiCache/PolygonRefinementCache.hpp
create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/ApiCache/SmallFlowEdgeCentreCache.hpp
create mode 100644 libs/MeshKernelApi/src/ApiCache/BoundariesAsPolygonCache.cpp
create mode 100644 libs/MeshKernelApi/src/ApiCache/CachedIntegerValues.cpp
create mode 100644 libs/MeshKernelApi/src/ApiCache/CachedPointValues.cpp
create mode 100644 libs/MeshKernelApi/src/ApiCache/FacePolygonPropertyCache.cpp
create mode 100644 libs/MeshKernelApi/src/ApiCache/HangingEdgeCache.cpp
create mode 100644 libs/MeshKernelApi/src/ApiCache/NodeInPolygonCache.cpp
create mode 100644 libs/MeshKernelApi/src/ApiCache/ObtuseTriangleCentreCache.cpp
create mode 100644 libs/MeshKernelApi/src/ApiCache/PolygonRefinementCache.cpp
create mode 100644 libs/MeshKernelApi/src/ApiCache/SmallFlowEdgeCentreCache.cpp
create mode 100644 libs/MeshKernelApi/tests/src/ApiCacheTest.cpp
diff --git a/libs/MeshKernelApi/CMakeLists.txt b/libs/MeshKernelApi/CMakeLists.txt
index 1be63d013..9a605c463 100644
--- a/libs/MeshKernelApi/CMakeLists.txt
+++ b/libs/MeshKernelApi/CMakeLists.txt
@@ -13,10 +13,12 @@ add_library(${TARGET_NAME} SHARED ${CMAKE_BINARY_DIR}/version.rc)
# source directory
set(SRC_DIR ${PROJECT_SOURCE_DIR}/src)
+set(CACHE_SRC_DIR ${SRC_DIR}/ApiCache)
# include directory
set(INC_DIR ${PROJECT_SOURCE_DIR}/include)
set(DOMAIN_INC_DIR ${INC_DIR}/MeshKernelApi)
+set(CACHE_INC_DIR ${DOMAIN_INC_DIR}/ApiCache)
set(VERSION_INC_DIR ${CMAKE_SOURCE_DIR}/tools)
# list of target sources
@@ -25,6 +27,19 @@ set(SRC_LIST
${SRC_DIR}/MeshKernel.cpp
)
+set(CACHE_SRC_LIST
+ ${CACHE_SRC_DIR}/BoundariesAsPolygonCache.cpp
+ ${CACHE_SRC_DIR}/CachedIntegerValues.cpp
+ ${CACHE_SRC_DIR}/CachedPointValues.cpp
+ ${CACHE_SRC_DIR}/FacePolygonPropertyCache.cpp
+ ${CACHE_SRC_DIR}/HangingEdgeCache.cpp
+ ${CACHE_SRC_DIR}/NodeInPolygonCache.cpp
+ ${CACHE_SRC_DIR}/ObtuseTriangleCentreCache.cpp
+ ${CACHE_SRC_DIR}/PolygonRefinementCache.cpp
+ ${CACHE_SRC_DIR}/SmallFlowEdgeCentreCache.cpp
+)
+
+
# list of target headers
set(
INC_LIST
@@ -42,17 +57,33 @@ set(
${VERSION_INC_DIR}/Version/Version.hpp
)
+set(
+ CACHE_INC_LIST
+ ${CACHE_INC_DIR}/BoundariesAsPolygonCache.hpp
+ ${CACHE_INC_DIR}/CachedIntegerValues.hpp
+ ${CACHE_INC_DIR}/CachedPointValues.hpp
+ ${CACHE_INC_DIR}/FacePolygonPropertyCache.hpp
+ ${CACHE_INC_DIR}/HangingEdgeCache.hpp
+ ${CACHE_INC_DIR}/NodeInPolygonCache.hpp
+ ${CACHE_INC_DIR}/ObtuseTriangleCentreCache.hpp
+ ${CACHE_INC_DIR}/PolygonRefinementCache.hpp
+ ${CACHE_INC_DIR}/SmallFlowEdgeCentreCache.hpp
+)
+
+
# add sources to target
target_sources(
${TARGET_NAME}
PRIVATE
- ${SRC_LIST}
+ ${SRC_LIST}
+ ${CACHE_SRC_LIST}
PUBLIC
FILE_SET HEADERS
BASE_DIRS
${INC_DIR} ${VERSION_INC_DIR}
FILES
- ${INC_LIST}
+ ${INC_LIST}
+ ${CACHE_INC_LIST}
)
# Expose the interface of the shared lib
@@ -88,10 +119,10 @@ target_precompile_headers(
install(TARGETS ${TARGET_NAME} FILE_SET HEADERS DESTINATION "include")
# group the sources in IDE tree
-source_group("Source Files" FILES ${SRC_LIST})
+source_group("Source Files" FILES ${SRC_LIST} ${CACHE_SRC_LIST})
# group the headers in IDE tree
-source_group("Header Files" FILES ${INC_LIST})
+source_group("Header Files" FILES ${INC_LIST} ${CACHE_INC_LIST})
# Add unit tests
if(ENABLE_UNIT_TESTING)
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp
new file mode 100644
index 000000000..f6d424139
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp
@@ -0,0 +1,66 @@
+//---- 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
+#include
+
+#include "MeshKernelApi/ApiCache/CachedPointValues.hpp"
+#include "MeshKernelApi/GeometryList.hpp"
+#include "MeshKernelApi/Utils.hpp"
+
+namespace meshkernelapi
+{
+
+ /// @brief Cache boundary polygon points
+ class BoundariesAsPolygonCache : public CachedPointValues
+ {
+ public:
+ /// @brief Constructor
+ BoundariesAsPolygonCache(const int lowerLeftN,
+ const int lowerLeftM,
+ const int upperRightN,
+ const int upperRightM,
+ const std::vector& boundaryPoints);
+
+ /// @brief Determine if current options match those used to construct the object
+ bool ValidOptions(const int lowerLeftN,
+ const int lowerLeftM,
+ const int upperRightN,
+ const int upperRightM) const;
+
+ private:
+ int m_lowerLeftNValue = -1; ///< Initial lower left N value
+ int m_lowerLeftMValue = -1; ///< Initial lower left M value
+ int m_upperRightNValue = -1; ///< Initial upper right N value
+ int m_upperRightMValue = -1; ///< Initial upper right M value
+ };
+
+} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedIntegerValues.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedIntegerValues.hpp
new file mode 100644
index 000000000..daa887f05
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedIntegerValues.hpp
@@ -0,0 +1,64 @@
+//---- 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
+
+namespace meshkernelapi
+{
+ /// @brief Caches x- and y-coordinate values for various algorithms
+ class CachedIntegerValues
+ {
+ public:
+ /// @brief Default constructor
+ CachedIntegerValues() {}
+
+ /// @brief Construct with point values
+ CachedIntegerValues(const std::vector& values);
+
+ /// @brief Destructor
+ virtual ~CachedIntegerValues() = default;
+
+ /// @brief Number of points saved
+ int Size() const
+ {
+ return static_cast(m_values.size());
+ }
+
+ /// @brief Copy cached points to geometry
+ void Copy(int* buffer) const;
+
+ protected:
+ /// @brief Reset the saved integer values.
+ void Reset(std::vector&& values);
+
+ private:
+ std::vector m_values; ///< integer values
+ };
+} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedPointValues.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedPointValues.hpp
new file mode 100644
index 000000000..098245439
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedPointValues.hpp
@@ -0,0 +1,70 @@
+//---- 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/GeometryList.hpp"
+
+namespace meshkernelapi
+{
+ /// @brief Caches x- and y-coordinate values for various algorithms
+ class CachedPointValues
+ {
+ public:
+ /// @brief Default constructor
+ CachedPointValues() {}
+
+ /// @brief Construct with point values
+ CachedPointValues(const std::vector& coordinates);
+
+ /// @brief Destructor
+ virtual ~CachedPointValues() = default;
+
+ /// @brief Number of points saved
+ int Size() const
+ {
+ return static_cast(m_coordsX.size());
+ }
+
+ /// @brief Copy cached points to geometry
+ void Copy(const GeometryList& geometry) const;
+
+ protected:
+ /// @brief Reset the saved coordinate values.
+ void Reset(std::vector&& xValues,
+ std::vector&& yValues);
+
+ private:
+ std::vector m_coordsX; ///< x-coordinate values
+ std::vector m_coordsY; ///< y-coordinate values
+ };
+} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp
new file mode 100644
index 000000000..e0ecf2e15
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp
@@ -0,0 +1,62 @@
+//---- 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 "MeshKernel/Mesh2D.hpp"
+
+#include "MeshKernelApi/ApiCache/CachedPointValues.hpp"
+
+namespace meshkernelapi
+{
+ /// @brief Cache node values of faces
+ class FacePolygonPropertyCache : public CachedPointValues
+ {
+
+ public:
+ /// @brief Constructor
+ FacePolygonPropertyCache(const int propertyValue,
+ const double minValue,
+ const double maxValue,
+ const meshkernel::Mesh2D& mesh,
+ const int validSize,
+ const std::vector& filterMask);
+
+ /// @brief Determine if current options match those used to construct the object
+ bool ValidOptions(const int propertyValue,
+ const double minValue,
+ const double maxValue) const;
+
+ private:
+ int m_propertyValue = 0; ///< Initial property value
+ double m_minimumValue = meshkernel::constants::missing::doubleValue; ///< Initial minimum value
+ double m_maximumValue = meshkernel::constants::missing::doubleValue; ///< Initial maximum value
+ };
+
+} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/HangingEdgeCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/HangingEdgeCache.hpp
new file mode 100644
index 000000000..0e00e9536
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/HangingEdgeCache.hpp
@@ -0,0 +1,48 @@
+//---- 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/ApiCache/CachedIntegerValues.hpp"
+
+namespace meshkernelapi
+{
+
+ /// @brief Cache edge indices for hanging nodes/edges
+ class HangingEdgeCache : public CachedIntegerValues
+ {
+ public:
+ /// @brief Constructor
+ HangingEdgeCache(const std::vector& edgeIds);
+ };
+
+} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/NodeInPolygonCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/NodeInPolygonCache.hpp
new file mode 100644
index 000000000..0303238ba
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/NodeInPolygonCache.hpp
@@ -0,0 +1,61 @@
+//---- 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/ApiCache/CachedIntegerValues.hpp"
+#include "MeshKernelApi/GeometryList.hpp"
+
+namespace meshkernelapi
+{
+
+ /// @brief Cache node indices contained in a polygon
+ class NodeInPolygonCache : public CachedIntegerValues
+ {
+ public:
+ /// @brief Constructor
+ NodeInPolygonCache(const std::vector& nodeMask,
+ const std::vector& polygonPoints,
+ const int inside);
+
+ /// @brief Determine if current options match those used to construct the object
+ bool ValidOptions(const std::vector& polygonPoints, const int inside) const;
+
+ private:
+ /// @brief Points making up the polygon
+ std::vector m_polygonPoints;
+
+ /// @brief Indicates if the points are inside or outside of the polygon
+ int m_inside = -1;
+ };
+
+} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/ObtuseTriangleCentreCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/ObtuseTriangleCentreCache.hpp
new file mode 100644
index 000000000..90b004f22
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/ObtuseTriangleCentreCache.hpp
@@ -0,0 +1,48 @@
+//---- 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/ApiCache/CachedPointValues.hpp"
+
+namespace meshkernelapi
+{
+
+ /// @brief Cache centre of edges
+ class ObtuseTriangleCentreCache : public CachedPointValues
+ {
+ public:
+ /// @brief Constructor
+ ObtuseTriangleCentreCache(const std::vector& triangleCentres);
+ };
+
+} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/PolygonRefinementCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/PolygonRefinementCache.hpp
new file mode 100644
index 000000000..20067c07b
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/PolygonRefinementCache.hpp
@@ -0,0 +1,61 @@
+//---- 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 "MeshKernelApi/ApiCache/CachedPointValues.hpp"
+
+namespace meshkernelapi
+{
+ /// @brief Refined polygon point values
+ class PolygonRefinementCache : public CachedPointValues
+ {
+
+ public:
+ /// @brief Constructor
+ PolygonRefinementCache(const std::vector& polyPoints,
+ const int firstIndex,
+ const int secondIndex,
+ const double edgeLength,
+ const std::vector& refinedPoints);
+
+ /// @brief Determine if current options match those used to construct the object
+ bool ValidOptions(const std::vector& polyPoints,
+ const int firstIndex,
+ const int secondIndex,
+ const double edgeLength) const;
+
+ private:
+ std::vector m_polygonPoints; ///< Initial polygon points
+ int m_firstNodeIndex = meshkernel::constants::missing::intValue; ///< Initial first node index value
+ int m_secondNodeIndex = meshkernel::constants::missing::intValue; ///< Initial second node index value
+ double m_targetEdgeLength = meshkernel::constants::missing::doubleValue; ///< Initial edge length, may be missing value.
+ };
+
+} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/SmallFlowEdgeCentreCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/SmallFlowEdgeCentreCache.hpp
new file mode 100644
index 000000000..de19e3e4d
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/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/ApiCache/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/MeshKernel.hpp b/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp
index 514638850..e8e429f04 100644
--- a/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp
+++ b/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp
@@ -351,6 +351,7 @@ namespace meshkernelapi
/// @param[in] upperRightM The m index of the upper right corner
/// @param[out] boundaryPolygons The geometry list containing the boundary polygons
/// @returns Error code
+ /// @note Values are retrieved from the cache, cached values are deleted after copying
MKERNEL_API int mkernel_curvilinear_get_boundaries_as_polygons(int meshKernelId, int lowerLeftN, int lowerLeftM, int upperRightN, int upperRightM, GeometryList& boundaryPolygons);
/// @brief Count the number of nodes in curvilinear grid boundary polygons.
@@ -362,6 +363,7 @@ namespace meshkernelapi
/// @param[in] upperRightM The m index of the upper right corner
/// @param[out] numberOfPolygonNodes The number of polygon nodes
/// @returns Error code
+ /// @note Refined boundary polygon values are cached, so that they can be copied
MKERNEL_API int mkernel_curvilinear_count_boundaries_as_polygons(int meshKernelId, int lowerLeftN, int lowerLeftM, int upperRightN, int upperRightM, int& numberOfPolygonNodes);
/// @brief Gets the curvilinear grid dimensions as a CurvilinearGrid struct (converted as set of edges and nodes).
@@ -1261,6 +1263,7 @@ namespace meshkernelapi
/// @param[out] geometryListDimension The output parameter that will store the dimension (size) of the geometry list
/// containing the polygons that match the filtering criteria.
/// @returns An error code indicating the success or failure of the operation.
+ /// @note property values are cached, so that they can be copied
MKERNEL_API int mkernel_mesh2d_get_filtered_face_polygons_dimension(int meshKernelId,
int propertyValue,
double minValue,
@@ -1275,6 +1278,7 @@ namespace meshkernelapi
/// @param[in] maxValue The maximum value of the property.
/// @param[out] facePolygons The geometry list containing the filtered locations.
/// @returns Error code
+ /// @note Values are retrieved from the cache, cached values are deleted after copying
MKERNEL_API int mkernel_mesh2d_get_filtered_face_polygons(int meshKernelId,
int propertyValue,
double minValue,
@@ -1697,6 +1701,7 @@ namespace meshkernelapi
/// @param[in] distance The target interval edge length
/// @param[out] numberOfPolygonNodes The number of nodes after refinement
/// @returns Error code
+ /// @note Refined polygon values are cached, so that they can be copied in the mkernel_polygon_refine
MKERNEL_API int mkernel_polygon_count_refine(int meshKernelId,
const GeometryList& polygonToRefine,
int firstIndex,
@@ -1713,6 +1718,7 @@ namespace meshkernelapi
/// @param[in] secondIndex The second index of the refinement interval
/// @param[out] numberOfPolygonNodes The number of nodes after refinement
/// @returns Error code
+ /// @note Refined polygon values are cached, so that they can be copied in the mkernel_polygon_linear_refine
MKERNEL_API int mkernel_polygon_count_linear_refine(int meshKernelId,
const GeometryList& polygonToRefine,
int firstIndex,
@@ -1756,6 +1762,7 @@ namespace meshkernelapi
/// @param[in] targetEdgeLength The target interval edge length
/// @param[out] refinedPolygon The refined polygon
/// @returns Error code
+ /// @note Values are retrieved from the cache, cached values are cleared after copying
MKERNEL_API int mkernel_polygon_refine(int meshKernelId,
const GeometryList& polygonToRefine,
int firstNodeIndex,
@@ -1771,6 +1778,7 @@ namespace meshkernelapi
/// @param[in] secondNodeIndex The second index of the refinement interval
/// @param[out] refinedPolygon The refined polygon
/// @returns Error code
+ /// @note Values are retrieved from the cache, cached values are cleared after copying
MKERNEL_API int mkernel_polygon_linear_refine(int meshKernelId,
const GeometryList& polygonToRefine,
int firstNodeIndex,
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp
index 74024f930..d662b132e 100644
--- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp
+++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp
@@ -38,6 +38,15 @@
#include
#include
+#include "MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp"
+#include "MeshKernelApi/ApiCache/CachedPointValues.hpp"
+#include "MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp"
+#include "MeshKernelApi/ApiCache/HangingEdgeCache.hpp"
+#include "MeshKernelApi/ApiCache/NodeInPolygonCache.hpp"
+#include "MeshKernelApi/ApiCache/ObtuseTriangleCentreCache.hpp"
+#include "MeshKernelApi/ApiCache/PolygonRefinementCache.hpp"
+#include "MeshKernelApi/ApiCache/SmallFlowEdgeCentreCache.hpp"
+
namespace meshkernelapi
{
@@ -73,6 +82,15 @@ namespace meshkernelapi
// Exclusively owned state
meshkernel::Projection m_projection{meshkernel::Projection::cartesian}; ///< Projection used by the meshes
+
+ // Cached values, used when dimensions are computed first, followed by values being retrieved in a separate call
+ std::shared_ptr m_facePropertyCache; ///< face property cache
+ std::shared_ptr m_boundariesAsPolygonCache; ///< boundaries as polygon cache
+ std::shared_ptr m_polygonRefinementCache; ///< polygon refinement cache
+ std::shared_ptr m_nodeInPolygonCache; ///< node in polygon cache
+ std::shared_ptr m_smallFlowEdgeCentreCache; ///< small flow edge centres cache
+ std::shared_ptr m_hangingEdgeCache; ///< hanging edge id cache
+ std::shared_ptr m_obtuseTriangleCentreCache; ///< centre of obtuse triangles cache
};
} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp b/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp
index 1eb993851..98f5bbf49 100644
--- a/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp
+++ b/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp
@@ -44,6 +44,8 @@
#include "MeshKernel/BilinearInterpolationOnGriddedSamples.hpp"
#include
+#include "MeshKernelApi/CurvilinearGrid.hpp"
+
#include
#include
#include
@@ -486,7 +488,6 @@ namespace meshkernelapi
const meshkernel::Projection& projection)
{
meshkernel::CurvilinearGridRectangular grid(projection);
-
return grid.Compute(makeGridParameters.num_columns,
makeGridParameters.num_rows,
makeGridParameters.origin_x,
@@ -583,34 +584,34 @@ namespace meshkernelapi
}
}
- static void FillFacePolygons(std::shared_ptr mesh2d,
+ static void FillFacePolygons(const meshkernel::Mesh2D& mesh2d,
const std::vector& facesInPolygon,
const GeometryList& facePolygons)
{
meshkernel::UInt count = 0;
- for (meshkernel::UInt f = 0; f < mesh2d->GetNumFaces(); ++f)
+ for (meshkernel::UInt f = 0; f < mesh2d.GetNumFaces(); ++f)
{
if (!facesInPolygon[f])
{
continue;
}
- const auto& faceNodes = mesh2d->m_facesNodes[f];
+ const auto& faceNodes = mesh2d.m_facesNodes[f];
if (count != 0)
{
- facePolygons.coordinates_x[count] = missing::doubleValue;
- facePolygons.coordinates_y[count] = missing::doubleValue;
+ facePolygons.coordinates_x[count] = meshkernel::constants::missing::doubleValue;
+ facePolygons.coordinates_y[count] = meshkernel::constants::missing::doubleValue;
count++;
}
for (meshkernel::UInt n = 0u; n < faceNodes.size(); ++n)
{
- const auto& currentNode = mesh2d->Node(faceNodes[n]);
+ const auto& currentNode = mesh2d.Node(faceNodes[n]);
facePolygons.coordinates_x[count] = currentNode.x;
facePolygons.coordinates_y[count] = currentNode.y;
count++;
}
- const auto& currentNode = mesh2d->Node(faceNodes[0]);
+ const auto& currentNode = mesh2d.Node(faceNodes[0]);
facePolygons.coordinates_x[count] = currentNode.x;
facePolygons.coordinates_y[count] = currentNode.y;
count++;
diff --git a/libs/MeshKernelApi/src/ApiCache/BoundariesAsPolygonCache.cpp b/libs/MeshKernelApi/src/ApiCache/BoundariesAsPolygonCache.cpp
new file mode 100644
index 000000000..8df414cfd
--- /dev/null
+++ b/libs/MeshKernelApi/src/ApiCache/BoundariesAsPolygonCache.cpp
@@ -0,0 +1,52 @@
+//---- 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/ApiCache/BoundariesAsPolygonCache.hpp"
+
+meshkernelapi::BoundariesAsPolygonCache::BoundariesAsPolygonCache(const int lowerLeftN,
+ const int lowerLeftM,
+ const int upperRightN,
+ const int upperRightM,
+ const std::vector& boundaryPoints)
+ : CachedPointValues(boundaryPoints),
+ m_lowerLeftNValue(lowerLeftN),
+ m_lowerLeftMValue(lowerLeftM),
+ m_upperRightNValue(upperRightN),
+ m_upperRightMValue(upperRightM)
+{
+}
+
+bool meshkernelapi::BoundariesAsPolygonCache::ValidOptions(const int lowerLeftN,
+ const int lowerLeftM,
+ const int upperRightN,
+ const int upperRightM) const
+{
+ return lowerLeftN == m_lowerLeftNValue &&
+ lowerLeftM == m_lowerLeftMValue &&
+ upperRightN == m_upperRightNValue &&
+ upperRightM == m_upperRightMValue;
+}
diff --git a/libs/MeshKernelApi/src/ApiCache/CachedIntegerValues.cpp b/libs/MeshKernelApi/src/ApiCache/CachedIntegerValues.cpp
new file mode 100644
index 000000000..444f96327
--- /dev/null
+++ b/libs/MeshKernelApi/src/ApiCache/CachedIntegerValues.cpp
@@ -0,0 +1,46 @@
+//---- 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
+#include
+
+#include "MeshKernelApi/ApiCache/CachedIntegerValues.hpp"
+
+meshkernelapi::CachedIntegerValues::CachedIntegerValues(const std::vector& values)
+ : m_values(values) {}
+
+void meshkernelapi::CachedIntegerValues::Copy(int* values) const
+{
+ size_t valueCount = sizeof(int) * m_values.size();
+
+ std::memcpy(values, m_values.data(), valueCount);
+}
+
+void meshkernelapi::CachedIntegerValues::Reset(std::vector&& values)
+{
+ m_values = std::move(values);
+}
diff --git a/libs/MeshKernelApi/src/ApiCache/CachedPointValues.cpp b/libs/MeshKernelApi/src/ApiCache/CachedPointValues.cpp
new file mode 100644
index 000000000..8354518df
--- /dev/null
+++ b/libs/MeshKernelApi/src/ApiCache/CachedPointValues.cpp
@@ -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.
+//
+//------------------------------------------------------------------------------
+
+#include
+#include
+
+#include "MeshKernelApi/ApiCache/CachedPointValues.hpp"
+
+meshkernelapi::CachedPointValues::CachedPointValues(const std::vector& coordinates)
+ : m_coordsX(coordinates.size()),
+ m_coordsY(coordinates.size())
+{
+ for (size_t i = 0; i < coordinates.size(); ++i)
+ {
+ m_coordsX[i] = coordinates[i].x;
+ m_coordsY[i] = coordinates[i].y;
+ }
+}
+
+void meshkernelapi::CachedPointValues::Copy(const GeometryList& geometry) const
+{
+ size_t valueCount = sizeof(double) * m_coordsX.size();
+
+ std::memcpy(geometry.coordinates_x, m_coordsX.data(), valueCount);
+ std::memcpy(geometry.coordinates_y, m_coordsY.data(), valueCount);
+}
+
+void meshkernelapi::CachedPointValues::Reset(std::vector&& xValues,
+ std::vector&& yValues)
+{
+ m_coordsX = std::move(xValues);
+ m_coordsY = std::move(yValues);
+}
diff --git a/libs/MeshKernelApi/src/ApiCache/FacePolygonPropertyCache.cpp b/libs/MeshKernelApi/src/ApiCache/FacePolygonPropertyCache.cpp
new file mode 100644
index 000000000..8d9b31201
--- /dev/null
+++ b/libs/MeshKernelApi/src/ApiCache/FacePolygonPropertyCache.cpp
@@ -0,0 +1,63 @@
+//---- 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
+
+#include "MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp"
+#include "MeshKernelApi/Utils.hpp"
+
+meshkernelapi::FacePolygonPropertyCache::FacePolygonPropertyCache(const int propertyValue,
+ const double minValue,
+ const double maxValue,
+ const meshkernel::Mesh2D& mesh,
+ const int validSize,
+ const std::vector& filterMask)
+ : m_propertyValue(propertyValue),
+ m_minimumValue(minValue),
+ m_maximumValue(maxValue)
+{
+ std::vector xCoordinates(validSize);
+ std::vector yCoordinates(validSize);
+
+ GeometryList facePolygons;
+
+ facePolygons.coordinates_x = xCoordinates.data();
+ facePolygons.coordinates_y = yCoordinates.data();
+
+ FillFacePolygons(mesh, filterMask, facePolygons);
+
+ CachedPointValues::Reset(std::move(xCoordinates), std::move(yCoordinates));
+}
+
+bool meshkernelapi::FacePolygonPropertyCache::ValidOptions(const int propertyValue,
+ const double minValue,
+ const double maxValue) const
+{
+ return propertyValue == m_propertyValue &&
+ minValue == m_minimumValue &&
+ maxValue == m_maximumValue;
+}
diff --git a/libs/MeshKernelApi/src/ApiCache/HangingEdgeCache.cpp b/libs/MeshKernelApi/src/ApiCache/HangingEdgeCache.cpp
new file mode 100644
index 000000000..0b0a09771
--- /dev/null
+++ b/libs/MeshKernelApi/src/ApiCache/HangingEdgeCache.cpp
@@ -0,0 +1,46 @@
+//---- 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
+#include
+#include
+
+#include "MeshKernel/Exceptions.hpp"
+
+#include "MeshKernelApi/ApiCache/HangingEdgeCache.hpp"
+
+meshkernelapi::HangingEdgeCache::HangingEdgeCache(const std::vector& edgeId)
+{
+ std::vector edgeIdInt(edgeId.size());
+
+ for (size_t i = 0; i < edgeId.size(); ++i)
+ {
+ edgeIdInt[i] = edgeId[i];
+ }
+
+ Reset(std::move(edgeIdInt));
+}
diff --git a/libs/MeshKernelApi/src/ApiCache/NodeInPolygonCache.cpp b/libs/MeshKernelApi/src/ApiCache/NodeInPolygonCache.cpp
new file mode 100644
index 000000000..5c572b463
--- /dev/null
+++ b/libs/MeshKernelApi/src/ApiCache/NodeInPolygonCache.cpp
@@ -0,0 +1,61 @@
+//---- 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
+#include
+#include
+
+#include "MeshKernel/Exceptions.hpp"
+
+#include "MeshKernelApi/ApiCache/NodeInPolygonCache.hpp"
+
+meshkernelapi::NodeInPolygonCache::NodeInPolygonCache(const std::vector& nodeMask,
+ const std::vector& polygonPoints,
+ const int inside)
+ : m_polygonPoints(polygonPoints), m_inside(inside)
+{
+ std::vector nodeIndices;
+
+ nodeIndices.reserve(m_polygonPoints.size());
+
+ for (size_t i = 0; i < nodeMask.size(); ++i)
+ {
+ if (nodeMask[i] > 0)
+ {
+ nodeIndices.push_back(static_cast(i));
+ }
+ }
+
+ Reset(std::move(nodeIndices));
+}
+
+bool meshkernelapi::NodeInPolygonCache::ValidOptions(const std::vector& polygonPoints, const int inside) const
+{
+ return inside == m_inside &&
+ polygonPoints.size() == m_polygonPoints.size() &&
+ std::equal(polygonPoints.begin(), polygonPoints.end(), m_polygonPoints.begin());
+}
diff --git a/libs/MeshKernelApi/src/ApiCache/ObtuseTriangleCentreCache.cpp b/libs/MeshKernelApi/src/ApiCache/ObtuseTriangleCentreCache.cpp
new file mode 100644
index 000000000..5f8f3c1f6
--- /dev/null
+++ b/libs/MeshKernelApi/src/ApiCache/ObtuseTriangleCentreCache.cpp
@@ -0,0 +1,31 @@
+//---- 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/ApiCache/ObtuseTriangleCentreCache.hpp"
+
+meshkernelapi::ObtuseTriangleCentreCache::ObtuseTriangleCentreCache(const std::vector& triangleCentres)
+ : CachedPointValues(triangleCentres) {}
diff --git a/libs/MeshKernelApi/src/ApiCache/PolygonRefinementCache.cpp b/libs/MeshKernelApi/src/ApiCache/PolygonRefinementCache.cpp
new file mode 100644
index 000000000..d01a88d95
--- /dev/null
+++ b/libs/MeshKernelApi/src/ApiCache/PolygonRefinementCache.cpp
@@ -0,0 +1,51 @@
+//---- 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/ApiCache/PolygonRefinementCache.hpp"
+
+meshkernelapi::PolygonRefinementCache::PolygonRefinementCache(const std::vector& polyPoints,
+ const int firstIndex,
+ const int secondIndex,
+ const double edgeLength,
+ const std::vector& refinedPoints)
+ : CachedPointValues(refinedPoints),
+ m_polygonPoints(polyPoints),
+ m_firstNodeIndex(firstIndex),
+ m_secondNodeIndex(secondIndex),
+ m_targetEdgeLength(edgeLength) {}
+
+bool meshkernelapi::PolygonRefinementCache::ValidOptions(const std::vector& polyPoints,
+ const int firstIndex,
+ const int secondIndex,
+ const double edgeLength) const
+{
+ return firstIndex == m_firstNodeIndex &&
+ secondIndex == m_secondNodeIndex &&
+ edgeLength == m_targetEdgeLength &&
+ polyPoints.size() == m_polygonPoints.size() &&
+ std::equal(polyPoints.begin(), polyPoints.end(), m_polygonPoints.begin());
+}
diff --git a/libs/MeshKernelApi/src/ApiCache/SmallFlowEdgeCentreCache.cpp b/libs/MeshKernelApi/src/ApiCache/SmallFlowEdgeCentreCache.cpp
new file mode 100644
index 000000000..7ab932225
--- /dev/null
+++ b/libs/MeshKernelApi/src/ApiCache/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/ApiCache/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/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp
index 643584742..521a5552d 100644
--- a/libs/MeshKernelApi/src/MeshKernel.cpp
+++ b/libs/MeshKernelApi/src/MeshKernel.cpp
@@ -89,10 +89,18 @@
#include
#include
-#include
-#include
-#include
-#include
+#include "MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp"
+#include "MeshKernelApi/ApiCache/CachedPointValues.hpp"
+#include "MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp"
+#include "MeshKernelApi/ApiCache/HangingEdgeCache.hpp"
+#include "MeshKernelApi/ApiCache/NodeInPolygonCache.hpp"
+#include "MeshKernelApi/ApiCache/ObtuseTriangleCentreCache.hpp"
+#include "MeshKernelApi/ApiCache/PolygonRefinementCache.hpp"
+#include "MeshKernelApi/ApiCache/SmallFlowEdgeCentreCache.hpp"
+#include "MeshKernelApi/MKStateUndoAction.hpp"
+#include "MeshKernelApi/MeshKernel.hpp"
+#include "MeshKernelApi/State.hpp"
+#include "MeshKernelApi/Utils.hpp"
#include
@@ -935,30 +943,41 @@ namespace meshkernelapi
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
- if (!meshKernelState.contains(meshKernelId))
+ if (!meshKernelState[meshKernelId].m_curvilinearGrid->IsValid())
{
- throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
+ throw meshkernel::MeshKernelError("Invalid curvilinear grid");
}
- if (!meshKernelState[meshKernelId].m_curvilinearGrid->IsValid())
+ if (boundaryPolygons.coordinates_x == nullptr || boundaryPolygons.coordinates_y == nullptr)
{
- throw meshkernel::MeshKernelError("Invalid curvilinear grid");
+ throw meshkernel::MeshKernelError("Boundary polygon array are null");
}
- auto lowerLeftNUnsigned = static_cast(lowerLeftN);
- auto lowerLeftMUnsigned = static_cast(lowerLeftM);
- auto upperRightNUnsigned = static_cast(upperRightN);
- auto upperRightMUnsigned = static_cast(upperRightM);
+ if (meshKernelState[meshKernelId].m_boundariesAsPolygonCache == nullptr)
+ {
+ throw meshkernel::MeshKernelError("Polygon data has not been cached, mkernel_curvilinear_count_boundaries_as_polygons must be called before");
+ }
- const auto minN = std::min(lowerLeftNUnsigned, upperRightNUnsigned);
- const auto maxN = std::max(lowerLeftNUnsigned, upperRightNUnsigned);
- const auto minM = std::min(lowerLeftMUnsigned, upperRightMUnsigned);
- const auto maxM = std::max(lowerLeftMUnsigned, upperRightMUnsigned);
+ if (!meshKernelState[meshKernelId].m_boundariesAsPolygonCache->ValidOptions(lowerLeftN, lowerLeftM, upperRightN, upperRightM))
+ {
+ meshKernelState[meshKernelId].m_boundariesAsPolygonCache.reset();
+ throw meshkernel::ConstraintError("Given polygon ranges are incompatible with the cached values. Cached values will be deleted.");
+ }
- const auto boundaryPolygon = meshKernelState[meshKernelId].m_curvilinearGrid->ComputeBoundaryPolygons({minN, minM},
- {maxN, maxM});
- ConvertPointVectorToGeometryList(boundaryPolygon, boundaryPolygons);
+ if (boundaryPolygons.num_coordinates != meshKernelState[meshKernelId].m_boundariesAsPolygonCache->Size())
+ {
+ meshKernelState[meshKernelId].m_boundariesAsPolygonCache.reset();
+ throw meshkernel::ConstraintError("Incompatible boundary polygon size (user-size /= cached-size): {} /= {}. Cached values will be deleted.",
+ boundaryPolygons.num_coordinates,
+ meshKernelState[meshKernelId].m_boundariesAsPolygonCache->Size());
+ }
+
+ // Retrieve cached values
+ meshKernelState[meshKernelId].m_boundariesAsPolygonCache->Copy(boundaryPolygons);
+ // Clear the cache now that the values have been retrieved
+ meshKernelState[meshKernelId].m_boundariesAsPolygonCache.reset();
}
+
catch (...)
{
lastExitCode = HandleException();
@@ -981,6 +1000,12 @@ namespace meshkernelapi
throw meshkernel::MeshKernelError("Invalid curvilinear grid");
}
+ if (meshKernelState[meshKernelId].m_boundariesAsPolygonCache != nullptr)
+ {
+ meshKernelState[meshKernelId].m_boundariesAsPolygonCache.reset();
+ throw meshkernel::MeshKernelError("Polygon data has already been cached, deleting cached data, ");
+ }
+
const auto lowerLeftNUnsigned = static_cast(lowerLeftN);
const auto lowerLeftMUnsigned = static_cast(lowerLeftM);
const auto upperRightNUnsigned = static_cast(upperRightN);
@@ -994,6 +1019,7 @@ namespace meshkernelapi
const auto boundaryPolygon = meshKernelState[meshKernelId].m_curvilinearGrid->ComputeBoundaryPolygons({minN, minM},
{maxN, maxM});
numberOfPolygonNodes = static_cast(boundaryPolygon.size());
+ meshKernelState[meshKernelId].m_boundariesAsPolygonCache = std::make_shared(lowerLeftN, lowerLeftM, upperRightN, upperRightM, boundaryPolygon);
}
catch (...)
{
@@ -1150,9 +1176,17 @@ namespace meshkernelapi
{
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
+
+ if (meshKernelState[meshKernelId].m_hangingEdgeCache != nullptr)
+ {
+ meshKernelState[meshKernelId].m_hangingEdgeCache.reset();
+ throw meshkernel::MeshKernelError("Polygon Hanging edge has already been cached. Cached values will be delelted.");
+ }
+
meshKernelState[meshKernelId].m_mesh2d->Administrate();
const auto hangingEdges = meshKernelState[meshKernelId].m_mesh2d->GetHangingEdges();
- numHangingEdges = static_cast(hangingEdges.size());
+ meshKernelState[meshKernelId].m_hangingEdgeCache = std::make_shared(hangingEdges);
+ numHangingEdges = meshKernelState[meshKernelId].m_hangingEdgeCache->Size();
}
catch (...)
{
@@ -1170,11 +1204,14 @@ namespace meshkernelapi
{
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
- const auto hangingEdges = meshKernelState[meshKernelId].m_mesh2d->GetHangingEdges();
- for (size_t i = 0; i < hangingEdges.size(); ++i)
+
+ if (meshKernelState[meshKernelId].m_hangingEdgeCache == nullptr)
{
- edges[i] = static_cast(hangingEdges[i]);
+ throw meshkernel::MeshKernelError("Hanging edge data has not been cached");
}
+
+ meshKernelState[meshKernelId].m_hangingEdgeCache->Copy(edges);
+ meshKernelState[meshKernelId].m_hangingEdgeCache.reset();
}
catch (...)
{
@@ -1936,12 +1973,27 @@ namespace meshkernelapi
{
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
+
+ if (meshKernelState[meshKernelId].m_polygonRefinementCache == nullptr)
+ {
+ throw meshkernel::MeshKernelError("Polygon data has not been cached, mkernel_polygon_count_refine must be called before");
+ }
+
auto const polygonVector = ConvertGeometryListToPointVector(polygonToRefine);
+ if (!meshKernelState[meshKernelId].m_polygonRefinementCache->ValidOptions(polygonVector, firstNodeIndex, secondNodeIndex, targetEdgeLength))
+ {
+ meshKernelState[meshKernelId].m_polygonRefinementCache.reset();
+ throw meshkernel::ConstraintError("Given refinement properties are incompatible with the cached values. Cached values will be deleted.");
+ }
+
const meshkernel::Polygons polygon(polygonVector, meshKernelState[meshKernelId].m_projection);
auto const refinementResult = polygon.RefineFirstPolygon(firstNodeIndex, secondNodeIndex, targetEdgeLength);
- ConvertPointVectorToGeometryList(refinementResult, refinedPolygon);
+ // Retrieve cached values
+ meshKernelState[meshKernelId].m_polygonRefinementCache->Copy(refinedPolygon);
+ // Clear the cache now that the values have been retrieved
+ meshKernelState[meshKernelId].m_polygonRefinementCache.reset();
}
catch (...)
{
@@ -1960,14 +2012,23 @@ namespace meshkernelapi
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
+ if (meshKernelState[meshKernelId].m_polygonRefinementCache == nullptr)
+ {
+ throw meshkernel::MeshKernelError("Polygon data has not been cached, mkernel_polygon_count_linear_refine must be called before");
+ }
+
auto const polygonVector = ConvertGeometryListToPointVector(polygonToRefine);
- const meshkernel::Polygons polygon(polygonVector, meshKernelState[meshKernelId].m_projection);
- const auto firstNodeIndexUnsigned = static_cast(firstNodeIndex);
- const auto secondNodeUnsigned = static_cast(secondNodeIndex);
- const auto refinementResult = polygon.LinearRefinePolygon(0, firstNodeIndexUnsigned, secondNodeUnsigned);
+ if (!meshKernelState[meshKernelId].m_polygonRefinementCache->ValidOptions(polygonVector, firstNodeIndex, secondNodeIndex, meshkernel::constants::missing::doubleValue))
+ {
+ meshKernelState[meshKernelId].m_polygonRefinementCache.reset();
+ throw meshkernel::ConstraintError("Given refinement properties are incompatible with the cached values. Cached values will be deleted.");
+ }
- ConvertPointVectorToGeometryList(refinementResult, refinedPolygon);
+ // Retrieve cached values
+ meshKernelState[meshKernelId].m_polygonRefinementCache->Copy(refinedPolygon);
+ // Clear the cache now that the values have been retrieved
+ meshKernelState[meshKernelId].m_polygonRefinementCache.reset();
}
catch (...)
{
@@ -1991,12 +2052,21 @@ namespace meshkernelapi
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
+ if (meshKernelState[meshKernelId].m_polygonRefinementCache != nullptr)
+ {
+ meshKernelState[meshKernelId].m_polygonRefinementCache.reset();
+ throw meshkernel::MeshKernelError("Polygon data has already been cached. Cached values will be delelted.");
+ }
+
auto const polygonVector = ConvertGeometryListToPointVector(polygonToRefine);
const meshkernel::Polygons polygon(polygonVector, meshKernelState[meshKernelId].m_projection);
const auto refinedPolygon = polygon.RefineFirstPolygon(firstIndex, secondIndex, distance);
+ // Cache refinedPolygon
+ meshKernelState[meshKernelId].m_polygonRefinementCache = std::make_shared(polygonVector, firstIndex, secondIndex, distance, refinedPolygon);
+
numberOfPolygonNodes = static_cast(refinedPolygon.size());
}
catch (...)
@@ -2016,13 +2086,23 @@ namespace meshkernelapi
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
- auto const polygonVector = ConvertGeometryListToPointVector(polygonToRefine);
+ if (meshKernelState[meshKernelId].m_polygonRefinementCache != nullptr)
+ {
+ meshKernelState[meshKernelId].m_polygonRefinementCache.reset();
+ throw meshkernel::MeshKernelError("Polygon data has already been cached. Cached values will be delelted.");
+ }
+ auto const polygonVector = ConvertGeometryListToPointVector(polygonToRefine);
const meshkernel::Polygons polygon(polygonVector, meshKernelState[meshKernelId].m_projection);
const auto firstNodeIndexUnsigned = static_cast(firstNodeIndex);
const auto secondNodeUnsigned = static_cast(secondNodeIndex);
const auto refinementResult = polygon.LinearRefinePolygon(0, firstNodeIndexUnsigned, secondNodeUnsigned);
+ // Cache refinedPolygon
+ meshKernelState[meshKernelId].m_polygonRefinementCache = std::make_shared(polygonVector, firstNodeIndex, secondNodeIndex,
+ meshkernel::constants::missing::doubleValue,
+ refinementResult);
+
numberOfPolygonNodes = static_cast(refinementResult.size());
}
catch (...)
@@ -2113,22 +2193,27 @@ namespace meshkernelapi
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
- auto const polygonVector = ConvertGeometryListToPointVector(geometryListIn);
+ if (meshKernelState[meshKernelId].m_nodeInPolygonCache == nullptr)
+ {
+ throw meshkernel::MeshKernelError("Node in polygon data has not been cached, mkernel_mesh2d_count_nodes_in_polygons must be called before");
+ }
- const meshkernel::Polygons polygon(polygonVector, meshKernelState[meshKernelId].m_mesh2d->m_projection);
+ auto const polygonVector = ConvertGeometryListToPointVector(geometryListIn);
- const bool selectInside = inside == 1 ? true : false;
- const auto nodeMask = meshKernelState[meshKernelId].m_mesh2d->NodeMaskFromPolygon(polygon, selectInside);
+ if (!meshKernelState[meshKernelId].m_nodeInPolygonCache->ValidOptions(polygonVector, inside))
+ {
+ meshKernelState[meshKernelId].m_nodeInPolygonCache.reset();
+ throw meshkernel::ConstraintError("Given polygon data and inside flag are incompatible with the cached values. Cached values will be deleted.");
+ }
- int index = 0;
- for (size_t i = 0; i < meshKernelState[meshKernelId].m_mesh2d->GetNumNodes(); ++i)
+ if (selectedNodes == nullptr)
{
- if (nodeMask[i] > 0)
- {
- selectedNodes[index] = static_cast(i);
- index++;
- }
+ meshKernelState[meshKernelId].m_nodeInPolygonCache.reset();
+ throw meshkernel::MeshKernelError("Selected node array is null");
}
+
+ meshKernelState[meshKernelId].m_nodeInPolygonCache->Copy(selectedNodes);
+ meshKernelState[meshKernelId].m_nodeInPolygonCache.reset();
}
catch (...)
{
@@ -2149,21 +2234,22 @@ namespace meshkernelapi
{
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
+
+ if (meshKernelState[meshKernelId].m_nodeInPolygonCache != nullptr)
+ {
+ meshKernelState[meshKernelId].m_nodeInPolygonCache.reset();
+ throw meshkernel::MeshKernelError("Node in polygon data has already been cached, deleting cached data");
+ }
+
auto const polygonVector = ConvertGeometryListToPointVector(geometryListIn);
const meshkernel::Polygons polygon(polygonVector, meshKernelState[meshKernelId].m_mesh2d->m_projection);
- const bool selectInside = inside == 1 ? true : false;
+ const bool selectInside = inside == 1;
const auto nodeMask = meshKernelState[meshKernelId].m_mesh2d->NodeMaskFromPolygon(polygon, selectInside);
- numberOfMeshNodes = 0;
- for (size_t i = 0; i < meshKernelState[meshKernelId].m_mesh2d->GetNumNodes(); ++i)
- {
- if (nodeMask[i] > 0)
- {
- numberOfMeshNodes++;
- }
- }
+ meshKernelState[meshKernelId].m_nodeInPolygonCache = std::make_shared(nodeMask, polygonVector, inside);
+ numberOfMeshNodes = meshKernelState[meshKernelId].m_nodeInPolygonCache->Size();
}
catch (...)
{
@@ -2429,7 +2515,7 @@ namespace meshkernelapi
validFace[f] = true;
}
}
- FillFacePolygons(meshKernelState[meshKernelId].m_mesh2d, validFace, facePolygons);
+ FillFacePolygons(*meshKernelState[meshKernelId].m_mesh2d, validFace, facePolygons);
}
catch (...)
{
@@ -2484,28 +2570,45 @@ namespace meshkernelapi
{
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
+
if (meshKernelState[meshKernelId].m_mesh2d->GetNumNodes() <= 0)
{
throw meshkernel::ConstraintError("The 2d mesh contains no nodes.");
}
+
+ if (meshKernelState[meshKernelId].m_facePropertyCache != nullptr)
+ {
+ meshKernelState[meshKernelId].m_facePropertyCache.reset();
+ throw meshkernel::ConstraintError("Filtered data has already been cached. Cached values will be deleted.");
+ }
+
+ geometryListDimension = 0;
+
const auto filterEnum = static_cast(propertyValue);
const auto filterMask = meshKernelState[meshKernelId].m_mesh2d->FilterBasedOnMetric(meshkernel::Location::Faces,
filterEnum,
minValue,
maxValue);
- geometryListDimension = 0;
+
+ // Now compute the size of the arrays required
for (meshkernel::UInt f = 0; f < filterMask.size(); ++f)
{
if (!filterMask[f])
{
continue;
}
+
const auto faceNumEdges = static_cast(meshKernelState[meshKernelId].m_mesh2d->m_facesNodes[f].size());
geometryListDimension += faceNumEdges + 2;
}
+
if (geometryListDimension > 0)
{
geometryListDimension -= 1;
+ meshKernelState[meshKernelId].m_facePropertyCache = std::make_shared(propertyValue, minValue, maxValue,
+ *meshKernelState[meshKernelId].m_mesh2d,
+ geometryListDimension,
+ filterMask);
}
}
catch (...)
@@ -2533,12 +2636,21 @@ namespace meshkernelapi
throw meshkernel::ConstraintError("The 2d mesh contains no nodes.");
}
- const auto filterEnum = static_cast(propertyValue);
- const auto filterMask = meshKernelState[meshKernelId].m_mesh2d->FilterBasedOnMetric(meshkernel::Location::Faces,
- filterEnum,
- minValue,
- maxValue);
- FillFacePolygons(meshKernelState[meshKernelId].m_mesh2d, filterMask, facePolygons);
+ if (meshKernelState[meshKernelId].m_facePropertyCache == nullptr)
+ {
+ throw meshkernel::ConstraintError("Filtered data has not been cached, mkernel_mesh2d_get_filtered_face_polygons_dimension must be called before");
+ }
+
+ if (!meshKernelState[meshKernelId].m_facePropertyCache->ValidOptions(propertyValue, minValue, maxValue))
+ {
+ meshKernelState[meshKernelId].m_facePropertyCache.reset();
+ throw meshkernel::ConstraintError("Given filter properties are incompatible with the cached values. Cached values will be deleted.");
+ }
+
+ // Retrieve cached values
+ meshKernelState[meshKernelId].m_facePropertyCache->Copy(facePolygons);
+ // Clear the cache now that the values have been retrieved
+ meshKernelState[meshKernelId].m_facePropertyCache.reset();
}
catch (...)
{
@@ -3328,10 +3440,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 (...)
{
@@ -3350,10 +3471,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, mkernel_mesh2d_count_small_flow_edge_centers must be called before");
+ }
+
+ 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 (...)
{
@@ -3464,9 +3594,16 @@ namespace meshkernelapi
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
+ if (meshKernelState[meshKernelId].m_obtuseTriangleCentreCache != nullptr)
+ {
+ meshKernelState[meshKernelId].m_obtuseTriangleCentreCache.reset();
+ throw meshkernel::MeshKernelError("Obtuse triangle centre data has already been cached, deleting cached data");
+ }
+
const auto obtuseTriangles = meshKernelState[meshKernelId].m_mesh2d->GetObtuseTrianglesCenters();
+ meshKernelState[meshKernelId].m_obtuseTriangleCentreCache = std::make_shared(obtuseTriangles);
- numObtuseTriangles = static_cast(obtuseTriangles.size());
+ numObtuseTriangles = meshKernelState[meshKernelId].m_obtuseTriangleCentreCache->Size();
}
catch (...)
{
@@ -3485,9 +3622,13 @@ namespace meshkernelapi
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}
- const auto obtuseTriangles = meshKernelState[meshKernelId].m_mesh2d->GetObtuseTrianglesCenters();
+ if (meshKernelState[meshKernelId].m_obtuseTriangleCentreCache == nullptr)
+ {
+ throw meshkernel::MeshKernelError("Obtuse triangle centre data has not been cached");
+ }
- ConvertPointVectorToGeometryList(obtuseTriangles, result);
+ meshKernelState[meshKernelId].m_obtuseTriangleCentreCache->Copy(result);
+ meshKernelState[meshKernelId].m_obtuseTriangleCentreCache.reset();
}
catch (...)
{
diff --git a/libs/MeshKernelApi/tests/CMakeLists.txt b/libs/MeshKernelApi/tests/CMakeLists.txt
index 21b9ec864..37f3051e4 100644
--- a/libs/MeshKernelApi/tests/CMakeLists.txt
+++ b/libs/MeshKernelApi/tests/CMakeLists.txt
@@ -12,6 +12,7 @@ set(INC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
# list of target sources
set(SRC_LIST
+ ${SRC_DIR}/ApiCacheTest.cpp
${SRC_DIR}/ApiTest.cpp
${SRC_DIR}/CurvilinearGridTests.cpp
${SRC_DIR}/CurvilinearGridUndoTests.cpp
diff --git a/libs/MeshKernelApi/tests/src/ApiCacheTest.cpp b/libs/MeshKernelApi/tests/src/ApiCacheTest.cpp
new file mode 100644
index 000000000..79e6d266d
--- /dev/null
+++ b/libs/MeshKernelApi/tests/src/ApiCacheTest.cpp
@@ -0,0 +1,253 @@
+#include
+#include
+
+#include "MeshKernel/MeshTransformation.hpp"
+#include "MeshKernel/Parameters.hpp"
+
+#include "MeshKernelApi/BoundingBox.hpp"
+#include "MeshKernelApi/GeometryList.hpp"
+#include "MeshKernelApi/Mesh1D.hpp"
+#include "MeshKernelApi/Mesh2D.hpp"
+#include "MeshKernelApi/MeshKernel.hpp"
+#include "Version/Version.hpp"
+
+#include "TestUtils/Definitions.hpp"
+#include "TestUtils/MakeCurvilinearGrids.hpp"
+#include "TestUtils/MakeMeshes.hpp"
+#include "TestUtils/SampleFileReader.hpp"
+
+#include
+#include
+
+// Create mesh and return the meshkernel id
+int MakeUnstructuredMesh(int meshKernelId, meshkernel::UInt numRows = 2, meshkernel::UInt numColumns = 3, double delta = 1.0)
+{
+
+ // Set-up new mesh
+ auto [num_nodes, num_edges, node_x, node_y, edge_nodes] = MakeRectangularMeshForApiTesting(numRows, numColumns, delta);
+ meshkernelapi::Mesh2D mesh2d{};
+ mesh2d.num_edges = static_cast(num_edges);
+ mesh2d.num_nodes = static_cast(num_nodes);
+ mesh2d.node_x = node_x.data();
+ mesh2d.node_y = node_y.data();
+ mesh2d.edge_nodes = edge_nodes.data();
+ int errorCode = meshkernelapi::mkernel_mesh2d_set(meshKernelId, mesh2d);
+
+ return errorCode;
+}
+
+TEST(ApiCacheTest, GetHangingEdgesMesh2D_WithOneHangingEdges_GetOneHangingEdgesFailures)
+{
+ int meshKernelId = 0;
+
+ int errorCode = meshkernelapi::mkernel_allocate_state(0, meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Prepare
+ errorCode = MakeUnstructuredMesh(meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // delete an edge at the lower left corner to create a new hanging edge
+ errorCode = meshkernelapi::mkernel_mesh2d_delete_edge(meshKernelId, 0.5, 0.0, 0.0, 0.0, 1.0, 1.0);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ int numHangingEdges;
+ errorCode = meshkernelapi::mkernel_mesh2d_count_hanging_edges(meshKernelId, numHangingEdges);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Already cached
+ errorCode = meshkernelapi::mkernel_mesh2d_count_hanging_edges(meshKernelId, numHangingEdges);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ // Re-cache
+ errorCode = meshkernelapi::mkernel_mesh2d_count_hanging_edges(meshKernelId, numHangingEdges);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ std::vector hangingEdges(numHangingEdges);
+ errorCode = meshkernelapi::mkernel_mesh2d_get_hanging_edges(meshKernelId, hangingEdges.data());
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ errorCode = meshkernelapi::mkernel_mesh2d_get_hanging_edges(meshKernelId, hangingEdges.data());
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ errorCode = meshkernelapi::mkernel_expunge_state(meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+}
+
+TEST(ApiCacheTest, GetNodesInPolygonMesh2D_OnMesh2D_NodeInPolygonFailures)
+{
+ int meshKernelId = 0;
+
+ int errorCode = meshkernelapi::mkernel_allocate_state(0, meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ errorCode = MakeUnstructuredMesh(meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // By using an empty list, all nodes will be selected
+ const meshkernelapi::GeometryList geometryListIn{};
+
+ meshkernelapi::Mesh2D mesh2d{};
+ errorCode = mkernel_mesh2d_get_dimensions(meshKernelId, mesh2d);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ int numberOfNodes = -1;
+ // Execute
+ std::vector selectedNodes(mesh2d.num_nodes);
+
+ // No daata has been cached.
+ errorCode = mkernel_mesh2d_get_nodes_in_polygons(meshKernelId, geometryListIn, 0, selectedNodes.data());
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ errorCode = mkernel_mesh2d_count_nodes_in_polygons(meshKernelId, geometryListIn, 1, numberOfNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ ASSERT_EQ(numberOfNodes, mesh2d.num_nodes);
+
+ // Values have been cached already
+ errorCode = mkernel_mesh2d_count_nodes_in_polygons(meshKernelId, geometryListIn, 1, numberOfNodes);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ // Re-cache data
+ errorCode = mkernel_mesh2d_count_nodes_in_polygons(meshKernelId, geometryListIn, 1, numberOfNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Incorrect parameters, should be the same as the call to count (which does the cahcing)
+ errorCode = mkernel_mesh2d_get_nodes_in_polygons(meshKernelId, geometryListIn, 0, selectedNodes.data());
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // Re-cache data
+ errorCode = mkernel_mesh2d_count_nodes_in_polygons(meshKernelId, geometryListIn, 1, numberOfNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Incorrect parameters, should be the same as the call to count (which does the cahcing)
+ int* nullArray = nullptr;
+ errorCode = mkernel_mesh2d_get_nodes_in_polygons(meshKernelId, geometryListIn, 1, nullArray);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ errorCode = meshkernelapi::mkernel_expunge_state(meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+}
+
+TEST(ApiCacheTest, GetSmallFlowEdges_OnMesh2D_GetSmallFlowEdgesFailures)
+{
+ // Prepare a mesh with two triangles
+ meshkernelapi::Mesh2D mesh2d;
+ int meshKernelId = 0;
+
+ int errorCode = meshkernelapi::mkernel_allocate_state(0, meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ errorCode = MakeUnstructuredMesh(meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ 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());
+
+ const double smallFlowEdgesThreshold = 100.0;
+ meshkernelapi::GeometryList result{};
+
+ 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);
+
+ errorCode = meshkernelapi::mkernel_expunge_state(meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+}
+
+TEST(ApiCacheTest, CountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ObtuseTrianglesFailures)
+{
+ // Prepare a mesh with one obtuse triangle
+ int meshKernelId = 0;
+
+ int errorCode = meshkernelapi::mkernel_allocate_state(0, meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ meshkernelapi::Mesh2D mesh2d;
+ std::vector coordinatesX{0.0, 3.0, -1.0, 1.5};
+ std::vector coordinatesY{0.0, 0.0, 2.0, -2.0};
+ std::vector edge_nodes{0, 1, 1, 2, 2, 0, 0, 3, 3, 1};
+ mesh2d.node_x = coordinatesX.data();
+ mesh2d.node_y = coordinatesY.data();
+ mesh2d.edge_nodes = edge_nodes.data();
+ mesh2d.num_edges = static_cast(edge_nodes.size() * 0.5);
+ mesh2d.num_nodes = static_cast(coordinatesX.size());
+
+ // Execute
+ errorCode = mkernel_mesh2d_set(meshKernelId, mesh2d);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Need to clear the obtuse triangle cache for the next tests
+ meshkernelapi::GeometryList geometryList{};
+
+ // Data has not yet been cached
+ errorCode = mkernel_mesh2d_get_obtuse_triangles_mass_centers(meshKernelId, geometryList);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ int numObtuseTriangles;
+ errorCode = meshkernelapi::mkernel_mesh2d_count_obtuse_triangles(meshKernelId, numObtuseTriangles);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Already cached, cached data will be deleted
+ errorCode = meshkernelapi::mkernel_mesh2d_count_obtuse_triangles(meshKernelId, numObtuseTriangles);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ // Re-cache data.
+ errorCode = meshkernelapi::mkernel_mesh2d_count_obtuse_triangles(meshKernelId, numObtuseTriangles);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ std::vector coordinatesObtuseTrianglesX(numObtuseTriangles);
+ std::vector coordinatesObtuseTrianglesY(numObtuseTriangles);
+ geometryList.coordinates_x = coordinatesObtuseTrianglesX.data();
+ geometryList.coordinates_y = coordinatesObtuseTrianglesY.data();
+ geometryList.num_coordinates = numObtuseTriangles;
+ errorCode = mkernel_mesh2d_get_obtuse_triangles_mass_centers(meshKernelId, geometryList);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Cache has been deleted in the last call
+ errorCode = mkernel_mesh2d_get_obtuse_triangles_mass_centers(meshKernelId, geometryList);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ errorCode = meshkernelapi::mkernel_expunge_state(meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+}
diff --git a/libs/MeshKernelApi/tests/src/ApiTest.cpp b/libs/MeshKernelApi/tests/src/ApiTest.cpp
index 6166d10ca..c816b9fe1 100644
--- a/libs/MeshKernelApi/tests/src/ApiTest.cpp
+++ b/libs/MeshKernelApi/tests/src/ApiTest.cpp
@@ -1485,8 +1485,18 @@ TEST_F(CartesianApiTestFixture, GetNodesInPolygonMesh2D_OnMesh2D_ShouldGetAllNod
auto errorCode = mkernel_mesh2d_get_dimensions(meshKernelId, mesh2d);
ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ int numberOfNodes = -1;
+
+ errorCode = mkernel_mesh2d_count_nodes_in_polygons(meshKernelId,
+ geometryListIn,
+ 1,
+ numberOfNodes);
+
+ ASSERT_EQ(numberOfNodes, mesh2d.num_nodes);
+
// Execute
std::vector selectedNodes(mesh2d.num_nodes);
+
errorCode = mkernel_mesh2d_get_nodes_in_polygons(meshKernelId,
geometryListIn,
1,
@@ -1727,6 +1737,17 @@ TEST_F(CartesianApiTestFixture, CountObtuseTriangles_OnMesh2DWithOneObtuseTriang
// Assert
ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
ASSERT_EQ(1, numObtuseTriangles);
+
+ // Need to clear the obtuse triangle cache for the next tests
+ meshkernelapi::GeometryList geometryList{};
+
+ std::vector coordinatesObtuseTrianglesX(numObtuseTriangles);
+ std::vector coordinatesObtuseTrianglesY(numObtuseTriangles);
+ geometryList.coordinates_x = coordinatesObtuseTrianglesX.data();
+ geometryList.coordinates_y = coordinatesObtuseTrianglesY.data();
+ geometryList.num_coordinates = numObtuseTriangles;
+ errorCode = mkernel_mesh2d_get_obtuse_triangles_mass_centers(meshKernelId, geometryList);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
}
TEST_F(CartesianApiTestFixture, Mesh2DCountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ShouldGetObtuseTriangle)
diff --git a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp
index 3d8f3bbae..349a89b83 100644
--- a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp
+++ b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp
@@ -1490,6 +1490,92 @@ TEST_P(CurvilineartBoundariesAsPolygonsTests, GetLocationIndex_OnACurvilinearGri
ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
}
+TEST(CurvilinearGrid, GetLocationIndex_OnACurvilinearGrid_GetLocationIndexFailures)
+{
+ const int lowerLeftN = 1;
+ const int lowerLeftM = 1;
+ const int upperRightN = 8;
+ const int upperRightM = 8;
+
+ // Prepare
+ int meshKernelId;
+ auto errorCode = meshkernelapi::mkernel_allocate_state(0, meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ MakeGridParameters makeGridParameters;
+
+ makeGridParameters.num_columns = 10;
+ makeGridParameters.num_rows = 10;
+ makeGridParameters.angle = 0.0;
+ makeGridParameters.origin_x = 0.0;
+ makeGridParameters.origin_y = 0.0;
+ makeGridParameters.block_size_x = 10.0;
+ makeGridParameters.block_size_y = 10.0;
+
+ errorCode = meshkernelapi::mkernel_curvilinear_compute_rectangular_grid(meshKernelId, makeGridParameters);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Initialise with a temporary size value
+ int numberOfPolygonNodes = 1000;
+
+ meshkernelapi::GeometryList boundaryPolygon;
+ // Set coordinate arrays with temporary size for first test
+ std::vector coordinates_x(numberOfPolygonNodes);
+ std::vector coordinates_y(numberOfPolygonNodes);
+
+ boundaryPolygon.coordinates_x = coordinates_x.data();
+ boundaryPolygon.coordinates_y = coordinates_y.data();
+ boundaryPolygon.num_coordinates = numberOfPolygonNodes;
+ boundaryPolygon.geometry_separator = constants::missing::doubleValue;
+
+ // Try to get before being cached
+ errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, boundaryPolygon);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ errorCode = meshkernelapi::mkernel_curvilinear_count_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, numberOfPolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Resize coordinate array with correct size
+ coordinates_x.resize(numberOfPolygonNodes);
+ coordinates_y.resize(numberOfPolygonNodes);
+
+ boundaryPolygon.coordinates_x = coordinates_x.data();
+ boundaryPolygon.coordinates_y = coordinates_y.data();
+ boundaryPolygon.num_coordinates = numberOfPolygonNodes;
+
+ // Check working version
+ boundaryPolygon.num_coordinates = numberOfPolygonNodes;
+ errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, boundaryPolygon);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Different lowerLeftN
+ errorCode = meshkernelapi::mkernel_curvilinear_count_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, numberOfPolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN + 1, lowerLeftM, upperRightN, upperRightM, boundaryPolygon);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // Different lowerLeftM
+ errorCode = meshkernelapi::mkernel_curvilinear_count_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, numberOfPolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM + 1, upperRightN, upperRightM, boundaryPolygon);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // Different upperRightN
+ errorCode = meshkernelapi::mkernel_curvilinear_count_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, numberOfPolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN + 1, upperRightM, boundaryPolygon);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // Different upperRightM
+ errorCode = meshkernelapi::mkernel_curvilinear_count_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, numberOfPolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM + 1, boundaryPolygon);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ errorCode = meshkernelapi::mkernel_expunge_state(meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+}
+
INSTANTIATE_TEST_SUITE_P(CurvilineartBoundariesAsPolygonsTests, CurvilineartBoundariesAsPolygonsTests, ::testing::ValuesIn(CurvilineartBoundariesAsPolygonsTests::GetData()));
TEST(CurvilinearGrid, MakeCircularGrid_CartesianCoordinate_ShouldMakeCurvilinearGrid)
diff --git a/libs/MeshKernelApi/tests/src/Mesh2DRefinmentTests.cpp b/libs/MeshKernelApi/tests/src/Mesh2DRefinmentTests.cpp
index c8c59fec1..8cb748984 100644
--- a/libs/MeshKernelApi/tests/src/Mesh2DRefinmentTests.cpp
+++ b/libs/MeshKernelApi/tests/src/Mesh2DRefinmentTests.cpp
@@ -53,7 +53,7 @@ TEST_F(CartesianApiTestFixture, RefineAPolygonThroughApi)
geometryListOut.coordinates_x = xCoordinatesOut.data();
geometryListOut.coordinates_y = yCoordinatesOut.data();
geometryListOut.values = valuesOut.data();
- errorCode = mkernel_polygon_refine(meshKernelId, geometryListIn, false, 0, 2, geometryListOut);
+ errorCode = mkernel_polygon_refine(meshKernelId, geometryListIn, 0, 2, 40, geometryListOut);
ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
// Assert
@@ -62,6 +62,73 @@ TEST_F(CartesianApiTestFixture, RefineAPolygonThroughApi)
ASSERT_NEAR(92.626556, geometryListOut.coordinates_y[0], tolerance);
}
+TEST_F(CartesianApiTestFixture, RefineAPolygonThroughApiFailures)
+{
+ // Prepare
+ MakeMesh();
+ auto const meshKernelId = GetMeshKernelId();
+
+ meshkernelapi::GeometryList geometryListIn;
+ geometryListIn.geometry_separator = meshkernel::constants::missing::doubleValue;
+
+ std::vector xCoordinatesIn{76.251099, 498.503723, 505.253784, 76.251099};
+ std::vector yCoordinatesIn{92.626556, 91.126541, 490.130554, 92.626556};
+ std::vector valuesIn{0.0, 0.0, 0.0, 0.0};
+
+ geometryListIn.coordinates_x = xCoordinatesIn.data();
+ geometryListIn.coordinates_y = yCoordinatesIn.data();
+ geometryListIn.values = valuesIn.data();
+ geometryListIn.num_coordinates = static_cast(xCoordinatesIn.size());
+
+ // Execute
+ meshkernelapi::GeometryList geometryListOut;
+ // Should fail due to the values not yet being cached.
+ auto errorCode = mkernel_polygon_refine(meshKernelId, geometryListIn, 0, 2, 40, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ int numberOfpolygonNodes;
+ // cache the values
+ errorCode = mkernel_polygon_count_refine(meshKernelId, geometryListIn, 0, 2, 40, numberOfpolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ geometryListOut.num_coordinates = numberOfpolygonNodes;
+ geometryListOut.geometry_separator = meshkernel::constants::missing::doubleValue;
+ std::vector xCoordinatesOut(numberOfpolygonNodes);
+ std::vector yCoordinatesOut(numberOfpolygonNodes);
+ std::vector valuesOut(numberOfpolygonNodes);
+ geometryListOut.coordinates_x = xCoordinatesOut.data();
+ geometryListOut.coordinates_y = yCoordinatesOut.data();
+ geometryListOut.values = valuesOut.data();
+ errorCode = mkernel_polygon_refine(meshKernelId, geometryListIn, 0, 2, 40, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Should fail due to the values have been deleted in the last call
+ errorCode = mkernel_polygon_refine(meshKernelId, geometryListIn, 0, 2, 40, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ // re-cache the values
+ errorCode = mkernel_polygon_count_refine(meshKernelId, geometryListIn, 0, 2, 40, numberOfpolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Should fail due to different parameters
+ errorCode = mkernel_polygon_refine(meshKernelId, geometryListIn, 1, 2, 40, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // re-cache the values
+ errorCode = mkernel_polygon_count_refine(meshKernelId, geometryListIn, 0, 2, 40, numberOfpolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ // Should fail due to different parameters
+ errorCode = mkernel_polygon_refine(meshKernelId, geometryListIn, 0, 3, 40, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // re-cache the values
+ errorCode = mkernel_polygon_count_refine(meshKernelId, geometryListIn, 0, 2, 40, numberOfpolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ // Should fail due to different parameters
+ errorCode = mkernel_polygon_refine(meshKernelId, geometryListIn, 0, 2, 41, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+}
+
TEST_F(CartesianApiTestFixture, LinearRefineAPolygonThroughApi)
{
// Prepare
@@ -106,6 +173,61 @@ TEST_F(CartesianApiTestFixture, LinearRefineAPolygonThroughApi)
ASSERT_NEAR(8.281492376, geometryListOut.coordinates_y[4], tolerance);
}
+TEST_F(CartesianApiTestFixture, LinearRefineAPolygonThroughApiFailures)
+{
+ // Prepare
+ MakeMesh();
+ auto const meshKernelId = GetMeshKernelId();
+
+ meshkernelapi::GeometryList geometryListIn;
+ geometryListIn.geometry_separator = meshkernel::constants::missing::doubleValue;
+
+ std::vector xCoordinatesIn{0.0, 1.0, 3.0, 11.0, 11.0, 0.0, 0.0};
+ std::vector yCoordinatesIn{10.0, 10.0, 10.0, 10.0, 0.0, 0.0, 10.0};
+
+ geometryListIn.coordinates_x = xCoordinatesIn.data();
+ geometryListIn.coordinates_y = yCoordinatesIn.data();
+ geometryListIn.num_coordinates = static_cast(xCoordinatesIn.size());
+
+ // Execute
+ meshkernelapi::GeometryList geometryListOut;
+ auto errorCode = mkernel_polygon_linear_refine(meshKernelId, geometryListIn, 1, 4, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ int expectedNumberOfpolygonNodes;
+ // cache the values
+ errorCode = mkernel_polygon_count_linear_refine(meshKernelId, geometryListIn, 1, 4, expectedNumberOfpolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ geometryListOut.num_coordinates = expectedNumberOfpolygonNodes;
+ geometryListOut.geometry_separator = meshkernel::constants::missing::doubleValue;
+ std::vector xCoordinatesOut(expectedNumberOfpolygonNodes);
+ std::vector yCoordinatesOut(expectedNumberOfpolygonNodes);
+ geometryListOut.coordinates_x = xCoordinatesOut.data();
+ geometryListOut.coordinates_y = yCoordinatesOut.data();
+
+ errorCode = mkernel_polygon_linear_refine(meshKernelId, geometryListIn, 1, 4, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Should fail due to the values have been deleted in the last call
+ errorCode = mkernel_polygon_linear_refine(meshKernelId, geometryListIn, 1, 4, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ // re-cache the values
+ errorCode = mkernel_polygon_count_linear_refine(meshKernelId, geometryListIn, 1, 4, expectedNumberOfpolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ // Should fail due to different parameters
+ errorCode = mkernel_polygon_linear_refine(meshKernelId, geometryListIn, 2, 4, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // re-cache the values
+ errorCode = mkernel_polygon_count_linear_refine(meshKernelId, geometryListIn, 1, 4, expectedNumberOfpolygonNodes);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ // Should fail due to different parameters
+ errorCode = mkernel_polygon_linear_refine(meshKernelId, geometryListIn, 1, 5, geometryListOut);
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+}
+
TEST_F(CartesianApiTestFixture, RefineBasedOnSamplesWaveCourant_OnAUniformMesh_shouldRefineMesh)
{
// Prepare
diff --git a/libs/MeshKernelApi/tests/src/Mesh2DTests.cpp b/libs/MeshKernelApi/tests/src/Mesh2DTests.cpp
index b65690cc1..5cf9abc79 100644
--- a/libs/MeshKernelApi/tests/src/Mesh2DTests.cpp
+++ b/libs/MeshKernelApi/tests/src/Mesh2DTests.cpp
@@ -259,3 +259,91 @@ TEST(Mesh2DTests, GetPolygonsOfDeletedFaces_WithPolygon_ShouldGetPolygonOfDelete
ASSERT_NEAR(expectedFacePolygonsY[i], yfacePolygons[i], 1e-6);
}
}
+
+TEST(Mesh2DTests, GetPolygonsOfDeletedFaces_WithPolygon_FailureTests)
+{
+ meshkernel::MakeGridParameters makeGridParameters;
+
+ makeGridParameters.origin_x = 0.0;
+ makeGridParameters.origin_y = 0.0;
+ makeGridParameters.block_size_x = 1.0;
+ makeGridParameters.block_size_y = 1.0;
+ makeGridParameters.num_columns = 20;
+ makeGridParameters.num_rows = 20;
+
+ int meshKernelId = 0;
+ const int projectionType = 0;
+ auto errorCode = meshkernelapi::mkernel_allocate_state(projectionType, meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ errorCode = meshkernelapi::mkernel_curvilinear_compute_rectangular_grid(meshKernelId, makeGridParameters);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ errorCode = mkapi::mkernel_curvilinear_convert_to_mesh2d(meshKernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ //
+
+ int propertyType = -1;
+ errorCode = meshkernelapi::mkernel_mesh2d_get_orthogonality_property_type(propertyType);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ double minValue = -1.0;
+ double maxValue = 1.0;
+
+ meshkernelapi::GeometryList facePolygons{};
+
+ // face data not yet cached
+ errorCode = mkernel_mesh2d_get_filtered_face_polygons(meshKernelId,
+ propertyType + 1,
+ minValue,
+ maxValue,
+ facePolygons);
+
+ // Assert
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // Execute
+ int geometryListDimension = -1;
+ errorCode = meshkernelapi::mkernel_mesh2d_get_filtered_face_polygons_dimension(meshKernelId,
+ propertyType,
+ minValue,
+ maxValue,
+ geometryListDimension);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ facePolygons.num_coordinates = geometryListDimension;
+ facePolygons.geometry_separator = meshkernel::constants::missing::doubleValue;
+ std::vector xfacePolygons(geometryListDimension);
+ std::vector yfacePolygons(geometryListDimension);
+ facePolygons.coordinates_x = xfacePolygons.data();
+ facePolygons.coordinates_y = yfacePolygons.data();
+
+ // Check different property type
+ errorCode = mkernel_mesh2d_get_filtered_face_polygons(meshKernelId,
+ propertyType + 1,
+ minValue,
+ maxValue,
+ facePolygons);
+
+ // Assert
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+
+ // Check different minimum value
+ errorCode = mkernel_mesh2d_get_filtered_face_polygons(meshKernelId,
+ propertyType,
+ minValue + 0.5,
+ maxValue,
+ facePolygons);
+
+ // Assert
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+ // Check different minimum value
+ errorCode = mkernel_mesh2d_get_filtered_face_polygons(meshKernelId,
+ propertyType,
+ minValue,
+ maxValue + 0.5,
+ facePolygons);
+
+ // Assert
+ ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
+}