diff --git a/libs/MeshKernel/CMakeLists.txt b/libs/MeshKernel/CMakeLists.txt
index e210c0800..93f10084b 100644
--- a/libs/MeshKernel/CMakeLists.txt
+++ b/libs/MeshKernel/CMakeLists.txt
@@ -48,6 +48,7 @@ set(
${SRC_DIR}/MeshEdgeLength.cpp
${SRC_DIR}/Mesh1D.cpp
${SRC_DIR}/Mesh2D.cpp
+ ${SRC_DIR}/Mesh2DFaceBounds.cpp
${SRC_DIR}/Mesh2DGenerateGlobal.cpp
${SRC_DIR}/Mesh2DIntersections.cpp
${SRC_DIR}/Mesh2DToCurvilinear.cpp
@@ -182,6 +183,7 @@ set(
${DOMAIN_INC_DIR}/MeshEdgeLength.hpp
${DOMAIN_INC_DIR}/Mesh1D.hpp
${DOMAIN_INC_DIR}/Mesh2D.hpp
+ ${DOMAIN_INC_DIR}/Mesh2DFaceBounds.hpp
${DOMAIN_INC_DIR}/Mesh2DGenerateGlobal.hpp
${DOMAIN_INC_DIR}/Mesh2DIntersections.hpp
${DOMAIN_INC_DIR}/Mesh2DToCurvilinear.hpp
diff --git a/libs/MeshKernel/include/MeshKernel/Definitions.hpp b/libs/MeshKernel/include/MeshKernel/Definitions.hpp
index 1608910ea..503c86dd8 100644
--- a/libs/MeshKernel/include/MeshKernel/Definitions.hpp
+++ b/libs/MeshKernel/include/MeshKernel/Definitions.hpp
@@ -159,7 +159,8 @@ namespace meshkernel
Orthogonality = 0,
EdgeLength = 1,
FaceCircumcenter = 2,
- NetlinkContourPolygon = 3
+ NetlinkContourPolygon = 3,
+ FaceBounds = 4
};
/// \brief Describe how the circumcentre should be computed.
diff --git a/libs/MeshKernel/include/MeshKernel/Mesh.hpp b/libs/MeshKernel/include/MeshKernel/Mesh.hpp
index 31a351b15..eeacb859f 100644
--- a/libs/MeshKernel/include/MeshKernel/Mesh.hpp
+++ b/libs/MeshKernel/include/MeshKernel/Mesh.hpp
@@ -369,6 +369,9 @@ namespace meshkernel
/// is false then the edge is in-valid.
bool IsValidEdge(const UInt edgeId) const;
+ /// @brief Indicate if the face-id is a valid face
+ bool IsValidFace(const UInt faceId) const;
+
/// @brief Apply the reset node action
void CommitAction(const ResetNodeAction& undoAction);
diff --git a/libs/MeshKernel/include/MeshKernel/Mesh2DFaceBounds.hpp b/libs/MeshKernel/include/MeshKernel/Mesh2DFaceBounds.hpp
new file mode 100644
index 000000000..d7121f3a0
--- /dev/null
+++ b/libs/MeshKernel/include/MeshKernel/Mesh2DFaceBounds.hpp
@@ -0,0 +1,53 @@
+//---- GPL ---------------------------------------------------------------------
+//
+// Copyright (C) Stichting Deltares, 2011-2026.
+//
+// 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/Constants.hpp"
+#include "MeshKernel/Definitions.hpp"
+#include "MeshKernel/Mesh.hpp"
+#include "MeshKernel/Point.hpp"
+
+namespace meshkernel::algo
+{
+
+ /// @brief Compute the nodes for each face in the grid, will be saved as facebounds
+ class Mesh2DFaceBounds
+ {
+ public:
+ /// @brief Compute the nodes for each face in the grid
+ static std::vector Compute(const Mesh& mesh);
+
+ private:
+ /// @brief Compute the face bounds for a single face
+ static void ComputeBoundsForFace(const Mesh& mesh, UInt faceId, std::span faceBounds);
+ };
+
+} // namespace meshkernel::algo
diff --git a/libs/MeshKernel/src/Mesh.cpp b/libs/MeshKernel/src/Mesh.cpp
index c659220fa..496631828 100644
--- a/libs/MeshKernel/src/Mesh.cpp
+++ b/libs/MeshKernel/src/Mesh.cpp
@@ -1190,6 +1190,25 @@ bool Mesh::IsValidEdge(const UInt edgeId) const
m_nodes[m_edges[edgeId].first].IsValid() && m_nodes[m_edges[edgeId].second].IsValid();
}
+bool Mesh::IsValidFace(const UInt faceId) const
+{
+ if (faceId >= GetNumFaces())
+ {
+ throw ConstraintError("The face index is out of bounds. {} >= {}.", faceId, GetNumFaces());
+ }
+
+ for (UInt edgeId : m_facesEdges[faceId])
+ {
+
+ if (!IsValidEdge(edgeId))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
void Mesh::BuildTree(Location location, const BoundingBox& boundingBox)
{
switch (location)
diff --git a/libs/MeshKernel/src/Mesh2DFaceBounds.cpp b/libs/MeshKernel/src/Mesh2DFaceBounds.cpp
new file mode 100644
index 000000000..7251164f0
--- /dev/null
+++ b/libs/MeshKernel/src/Mesh2DFaceBounds.cpp
@@ -0,0 +1,72 @@
+//---- GPL ---------------------------------------------------------------------
+//
+// Copyright (C) Stichting Deltares, 2011-2026.
+//
+// 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 "MeshKernel/Mesh2DFaceBounds.hpp"
+
+#include
+
+#include "MeshKernel/Constants.hpp"
+#include "MeshKernel/MeshFaceCenters.hpp"
+#include "MeshKernel/Operations.hpp"
+
+std::vector meshkernel::algo::Mesh2DFaceBounds::Compute(const Mesh& mesh)
+{
+ std::vector meshFaceBounds(constants::geometric::maximumNumberOfNodesPerFace * mesh.GetNumFaces());
+
+#pragma omp parallel for
+ for (int face = 0; face < static_cast(mesh.GetNumFaces()); ++face)
+ {
+ const UInt pointCount = constants::geometric::maximumNumberOfNodesPerFace * static_cast(face);
+
+ std::span faceBounds(meshFaceBounds.data() + pointCount, meshFaceBounds.data() + pointCount + constants::geometric::maximumNumberOfNodesPerFace);
+ ComputeBoundsForFace(mesh, static_cast(face), faceBounds);
+ }
+
+ return meshFaceBounds;
+}
+
+void meshkernel::algo::Mesh2DFaceBounds::ComputeBoundsForFace(const Mesh& mesh, UInt faceId, std::span faceBounds)
+{
+ if (mesh.IsValidFace(faceId))
+ {
+ UInt numNodes = static_cast(mesh.m_numFacesNodes[faceId]);
+
+ for (UInt i = 0; i < numNodes; ++i)
+ {
+ faceBounds[i] = mesh.Node(mesh.m_facesNodes[faceId][i]);
+ }
+
+ for (UInt i = numNodes; i < constants::geometric::maximumNumberOfNodesPerFace; ++i)
+ {
+ faceBounds[i] = Point{constants::missing::doubleValue, constants::missing::doubleValue};
+ }
+ }
+ else
+ {
+ std::ranges::fill(faceBounds, Point{constants::missing::doubleValue, constants::missing::doubleValue});
+ }
+}
diff --git a/libs/MeshKernel/tests/src/Mesh2DTest.cpp b/libs/MeshKernel/tests/src/Mesh2DTest.cpp
index e9c5da3f3..b0717f25e 100644
--- a/libs/MeshKernel/tests/src/Mesh2DTest.cpp
+++ b/libs/MeshKernel/tests/src/Mesh2DTest.cpp
@@ -34,6 +34,7 @@
#include "MeshKernel/Entities.hpp"
#include "MeshKernel/Mesh.hpp"
#include "MeshKernel/Mesh2D.hpp"
+#include "MeshKernel/Mesh2DFaceBounds.hpp"
#include "MeshKernel/Mesh2DIntersections.hpp"
#include "MeshKernel/Mesh2DToCurvilinear.hpp"
#include "MeshKernel/MeshEdgeLength.hpp"
@@ -1862,3 +1863,29 @@ TEST(Mesh2D, ComputeEdgeNetlinkContourPolygonsSpherical)
++expectedNodeCount;
}
}
+
+TEST(Mesh2D, ComputeMesh2DFaceBounds)
+{
+ std::vector meshPoints{{10.0, 0.0}, {20.0, 10.0}, {10.0, 20.0}, {0.0, 10.0}, {30.0, 20.0}, {0.0, 30.0}, {20.0, 30.0}, {30.0, 30.0}};
+ std::vector meshEdges{{0, 1}, {1, 2}, {2, 3}, {3, 0}, {1, 4}, {3, 5}, {5, 6}, {6, 7}, {2, 5}, {2, 6}, {4, 7}};
+
+ meshkernel::Mesh2D mesh(meshEdges, meshPoints, meshkernel::Projection::cartesian);
+ mesh.Administrate();
+
+ meshkernel::algo::Mesh2DFaceBounds mesh2dFaceBounds;
+
+ auto faceBoundPoints(mesh2dFaceBounds.Compute(mesh));
+
+ std::vector expectedXs{10.0, 20.0, 0.0, -999.0, -999.0, -999.0, 10.0, 0.0, 0.0, -999.0, -999.0, -999.0, 10.0, 20.0, 10.0, 0.0, -999.0, -999.0, 20.0, 30.0, 30.0, 20.0, 10.0, -999.0};
+ std::vector expectedYs{20.0, 30.0, 30.0, -999.0, -999.0, -999.0, 20.0, 30.0, 10.0, -999.0, -999.0, -999.0, 0.0, 10.0, 20.0, 10.0, -999.0, -999.0, 10.0, 20.0, 30.0, 30.0, 20.0, -999.0};
+
+ constexpr double tolerance = 1.0e-10;
+
+ ASSERT_EQ(faceBoundPoints.size(), expectedXs.size());
+
+ for (size_t i = 0; i < faceBoundPoints.size(); ++i)
+ {
+ EXPECT_NEAR(faceBoundPoints[i].x, expectedXs[i], tolerance);
+ EXPECT_NEAR(faceBoundPoints[i].y, expectedYs[i], tolerance);
+ }
+}
diff --git a/libs/MeshKernelApi/CMakeLists.txt b/libs/MeshKernelApi/CMakeLists.txt
index 92c2cde91..56beb6522 100644
--- a/libs/MeshKernelApi/CMakeLists.txt
+++ b/libs/MeshKernelApi/CMakeLists.txt
@@ -28,6 +28,7 @@ set(SRC_LIST
${SRC_DIR}/PropertyCalculator.cpp
${SRC_DIR}/EdgeLengthPropertyCalculator.cpp
${SRC_DIR}/FaceCircumcenterPropertyCalculator.cpp
+ ${SRC_DIR}/Mesh2DFaceBoundsPropertyCalculator.cpp
${SRC_DIR}/NetlinkContourPolygonPropertyCalculator.cpp
${SRC_DIR}/OrthogonalityPropertyCalculator.cpp
${SRC_DIR}/InterpolatedSamplePropertyCalculator.cpp
@@ -65,6 +66,7 @@ set(
${DOMAIN_INC_DIR}/PropertyCalculator.hpp
${DOMAIN_INC_DIR}/EdgeLengthPropertyCalculator.hpp
${DOMAIN_INC_DIR}/FaceCircumcenterPropertyCalculator.hpp
+ ${DOMAIN_INC_DIR}/Mesh2DFaceBoundsPropertyCalculator.hpp
${DOMAIN_INC_DIR}/NetlinkContourPolygonPropertyCalculator.hpp
${DOMAIN_INC_DIR}/OrthogonalityPropertyCalculator.hpp
${DOMAIN_INC_DIR}/InterpolatedSamplePropertyCalculator.hpp
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/Mesh2DFaceBoundsPropertyCalculator.hpp b/libs/MeshKernelApi/include/MeshKernelApi/Mesh2DFaceBoundsPropertyCalculator.hpp
new file mode 100644
index 000000000..5671e7a4b
--- /dev/null
+++ b/libs/MeshKernelApi/include/MeshKernelApi/Mesh2DFaceBoundsPropertyCalculator.hpp
@@ -0,0 +1,56 @@
+//---- GPL ---------------------------------------------------------------------
+//
+// Copyright (C) Stichting Deltares, 2011-2026.
+//
+// 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 "MeshKernel/Definitions.hpp"
+#include "MeshKernel/Parameters.hpp"
+#include "MeshKernel/SampleInterpolator.hpp"
+
+#include "MeshKernelApi/GeometryList.hpp"
+#include "MeshKernelApi/PropertyCalculator.hpp"
+
+namespace meshkernelapi
+{
+
+ /// @brief Calculator for the face bounds values for a mesh
+ class Mesh2DFaceBoundsPropertyCalculator : public PropertyCalculator
+ {
+ public:
+ /// @brief Determine is the calculator can compute the desired results correctly.
+ ///
+ /// This has a default of checking that the mesh2d is valid and the location is at faces
+ bool IsValid(const MeshKernelState& state, const meshkernel::Location location) const override;
+
+ /// @brief Calculate the face bounds values for a mesh
+ void Calculate(const MeshKernelState& state, const meshkernel::Location location, const GeometryList& geometryList) const override;
+
+ /// @brief Determine the size of the face bounds array (for all faces) required
+ int Size(const MeshKernelState& state, const meshkernel::Location location) const override;
+ };
+
+} // namespace meshkernelapi
diff --git a/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp b/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp
index 44cf15f29..34d57f7f0 100644
--- a/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp
+++ b/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp
@@ -1250,6 +1250,11 @@ namespace meshkernelapi
/// @returns Error code
MKERNEL_API int mkernel_mesh2d_get_netlink_contour_polygon_property_type(int& type);
+ /// @brief Gets an int indicating the face bounds property type for mesh2d
+ /// @param[out] type The int indicating the face bounds property type
+ /// @returns Error code
+ MKERNEL_API int mkernel_mesh2d_get_face_bounds_property_type(int& type);
+
/// @brief Gets the Mesh2D inner boundary polygons data
///
/// @param[in] meshKernelId The id of the mesh state
diff --git a/libs/MeshKernelApi/src/Mesh2DFaceBoundsPropertyCalculator.cpp b/libs/MeshKernelApi/src/Mesh2DFaceBoundsPropertyCalculator.cpp
new file mode 100644
index 000000000..0a67a6db8
--- /dev/null
+++ b/libs/MeshKernelApi/src/Mesh2DFaceBoundsPropertyCalculator.cpp
@@ -0,0 +1,70 @@
+//---- GPL ---------------------------------------------------------------------
+//
+// Copyright (C) Stichting Deltares, 2011-2026.
+//
+// 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/Mesh2DFaceBoundsPropertyCalculator.hpp"
+#include "MeshKernelApi/PropertyCalculator.hpp"
+#include "MeshKernelApi/State.hpp"
+
+#include "MeshKernel/Mesh2DFaceBounds.hpp"
+
+bool meshkernelapi::Mesh2DFaceBoundsPropertyCalculator::IsValid(const MeshKernelState& state, const meshkernel::Location location) const
+{
+ return state.m_mesh2d != nullptr && state.m_mesh2d->GetNumNodes() > 0 && location == meshkernel::Location::Faces;
+}
+
+void meshkernelapi::Mesh2DFaceBoundsPropertyCalculator::Calculate(const MeshKernelState& state, const meshkernel::Location location, const GeometryList& geometryList) const
+{
+ if (geometryList.num_coordinates < static_cast(meshkernel::constants::geometric::maximumNumberOfNodesPerFace * state.m_mesh2d->GetNumFaces()))
+ {
+ throw meshkernel::ConstraintError("GeometryList with wrong dimensions, {} must be greater than or equal to {}",
+ geometryList.num_coordinates, Size(state, location));
+ }
+
+ std::vector faceBounds(meshkernel::algo::Mesh2DFaceBounds::Compute(*state.m_mesh2d));
+
+ size_t size = static_cast(Size(state, location));
+ std::span xCoord(geometryList.coordinates_x, size);
+ std::span yCoord(geometryList.coordinates_y, size);
+
+ for (size_t i = 0; i < faceBounds.size(); ++i)
+ {
+ xCoord[i] = faceBounds[i].x;
+ yCoord[i] = faceBounds[i].y;
+ }
+}
+
+int meshkernelapi::Mesh2DFaceBoundsPropertyCalculator::Size(const MeshKernelState& state, const meshkernel::Location location) const
+{
+ int size = -1;
+
+ if (location == meshkernel::Location::Faces)
+ {
+ size = meshkernel::constants::geometric::maximumNumberOfNodesPerFace * static_cast(state.m_mesh2d->GetNumFaces());
+ }
+
+ return size;
+}
diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp
index 4164cf4d5..7d3f9504d 100644
--- a/libs/MeshKernelApi/src/MeshKernel.cpp
+++ b/libs/MeshKernelApi/src/MeshKernel.cpp
@@ -107,6 +107,7 @@
#include "MeshKernelApi/EdgeLengthPropertyCalculator.hpp"
#include "MeshKernelApi/FaceCircumcenterPropertyCalculator.hpp"
#include "MeshKernelApi/InterpolatedSamplePropertyCalculator.hpp"
+#include "MeshKernelApi/Mesh2DFaceBoundsPropertyCalculator.hpp"
#include "MeshKernelApi/NetlinkContourPolygonPropertyCalculator.hpp"
#include "MeshKernelApi/OrthogonalityPropertyCalculator.hpp"
#include "MeshKernelApi/PropertyCalculator.hpp"
@@ -144,7 +145,7 @@ namespace meshkernelapi
int GeneratePropertyId()
{
// The current property id, initialised with a value equal to the last enum in Mesh2D:::Property enum values
- static int currentPropertyId = static_cast(meshkernel::Property::NetlinkContourPolygon);
+ static int currentPropertyId = static_cast(meshkernel::Property::FaceBounds);
// Increment and return the current property id value.
return ++currentPropertyId;
@@ -166,6 +167,9 @@ namespace meshkernelapi
propertyId = static_cast(meshkernel::Property::NetlinkContourPolygon);
propertyMap.emplace(propertyId, std::make_shared());
+ propertyId = static_cast(meshkernel::Property::FaceBounds);
+ propertyMap.emplace(propertyId, std::make_shared());
+
return propertyMap;
}
@@ -1025,6 +1029,13 @@ namespace meshkernelapi
return lastExitCode;
}
+ MKERNEL_API int mkernel_mesh2d_get_face_bounds_property_type(int& type)
+ {
+ lastExitCode = meshkernel::ExitCode::Success;
+ type = static_cast(meshkernel::Property::FaceBounds);
+ return lastExitCode;
+ }
+
MKERNEL_API int mkernel_mesh1d_get_dimensions(int meshKernelId, Mesh1D& mesh1d)
{
lastExitCode = meshkernel::ExitCode::Success;
diff --git a/libs/MeshKernelApi/src/NetlinkContourPolygonPropertyCalculator.cpp b/libs/MeshKernelApi/src/NetlinkContourPolygonPropertyCalculator.cpp
index e5bc66078..df60b1167 100644
--- a/libs/MeshKernelApi/src/NetlinkContourPolygonPropertyCalculator.cpp
+++ b/libs/MeshKernelApi/src/NetlinkContourPolygonPropertyCalculator.cpp
@@ -39,7 +39,7 @@ bool meshkernelapi::NetlinkContourPolygonPropertyCalculator::IsValid(const MeshK
void meshkernelapi::NetlinkContourPolygonPropertyCalculator::Calculate(const MeshKernelState& state, const meshkernel::Location location, const GeometryList& geometryList) const
{
- if (static_cast(geometryList.num_coordinates) < state.m_mesh2d->GetNumEdges())
+ if (static_cast(geometryList.num_coordinates) < 4u * state.m_mesh2d->GetNumEdges())
{
throw meshkernel::ConstraintError("GeometryList with wrong dimensions, {} must be greater than or equal to {}",
geometryList.num_coordinates, Size(state, location));
diff --git a/libs/MeshKernelApi/tests/src/Mesh2DTests.cpp b/libs/MeshKernelApi/tests/src/Mesh2DTests.cpp
index 75d183834..9e5391ac4 100644
--- a/libs/MeshKernelApi/tests/src/Mesh2DTests.cpp
+++ b/libs/MeshKernelApi/tests/src/Mesh2DTests.cpp
@@ -1825,3 +1825,57 @@ TEST(Mesh2DTests, Mesh2D_ShouldComputeNetlinkPolygon)
errorCode = meshkernelapi::mkernel_mesh2d_get_property_dimension(meshkernelId, propertyId, nodesLocation, dimension);
ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
}
+
+TEST(Mesh2DTests, Mesh2D_ShouldComputeFaceBounds)
+{
+ int meshkernelId = 0;
+ int errorCode = meshkernelapi::mkernel_allocate_state(0, meshkernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+ errorCode = GenerateUnstructuredMesh(meshkernelId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ int dimension = -1;
+ int propertyId = -1;
+ errorCode = meshkernelapi::mkernel_mesh2d_get_face_bounds_property_type(propertyId);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ // Execute
+ int facesLocation = static_cast(meshkernel::Location::Faces);
+ errorCode = meshkernelapi::mkernel_mesh2d_get_property_dimension(meshkernelId, propertyId, facesLocation, dimension);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ ASSERT_EQ(dimension, 6 * 6); // 2x3 quadrilateral elements => 6 * 6 nodes (the maximum number of nodes an element can have is 6)
+
+ std::vector xCoords(dimension);
+ std::vector yCoords(dimension);
+
+ meshkernelapi::GeometryList polygons{};
+
+ polygons.num_coordinates = dimension;
+ polygons.coordinates_x = xCoords.data();
+ polygons.coordinates_y = yCoords.data();
+
+ errorCode = meshkernelapi::mkernel_mesh2d_get_property(meshkernelId, propertyId, facesLocation, polygons);
+ ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
+
+ std::vector expectedX{0.0, 1.0, 1.0, 0.0, -999.0, -999.0, 0.0, 1.0, 1.0, 0.0, -999.0, -999.0, 1.0, 2.0, 2.0, 1.0, -999.0, -999.0, 1.0, 2.0, 2.0, 1.0, -999.0, -999.0, 2.0, 3.0, 3.0, 2.0, -999.0, -999.0, 2.0, 3.0, 3.0, 2.0, -999.0, -999.0};
+ std::vector expectedY{0.0, 0.0, 1.0, 1.0, -999.0, -999.0, 1.0, 1.0, 2.0, 2.0, -999.0, -999.0, 0.0, 0.0, 1.0, 1.0, -999.0, -999.0, 1.0, 1.0, 2.0, 2.0, -999.0, -999.0, 0.0, 0.0, 1.0, 1.0, -999.0, -999.0, 1.0, 1.0, 2.0, 2.0, -999.0, -999.0};
+
+ constexpr double tolerance = 1.0e-10;
+
+ for (size_t i = 0; i < xCoords.size(); ++i)
+ {
+ EXPECT_NEAR(xCoords[i], expectedX[i], tolerance);
+ EXPECT_NEAR(yCoords[i], expectedY[i], tolerance);
+ }
+
+ // Try to access the dimension for an invalid location id (faces in this case) for netlink contours, should return non-success error code
+ int edgesLocation = static_cast(meshkernel::Location::Edges);
+ errorCode = meshkernelapi::mkernel_mesh2d_get_property_dimension(meshkernelId, propertyId, edgesLocation, dimension);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+
+ // Try to access the dimension for an invalid location id (node in this case) for netlink contours, should return non-success error code
+ int nodesLocation = static_cast(meshkernel::Location::Nodes);
+ errorCode = meshkernelapi::mkernel_mesh2d_get_property_dimension(meshkernelId, propertyId, nodesLocation, dimension);
+ ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode);
+}