From e9faf39f0ecdcc4390117938d6b1c6ba8bd0ee7f Mon Sep 17 00:00:00 2001 From: BillSenior Date: Wed, 16 Oct 2024 18:23:05 +0200 Subject: [PATCH 01/17] GRIDEDIT-1336 Passing to other computer --- .../include/MeshKernelApi/State.hpp | 18 +++ .../include/MeshKernelApi/Utils.hpp | 4 +- libs/MeshKernelApi/src/MeshKernel.cpp | 115 +++++++++++++++--- .../tests/src/CurvilinearGridTests.cpp | 81 ++++++++++++ libs/MeshKernelApi/tests/src/Mesh2DTests.cpp | 88 ++++++++++++++ 5 files changed, 287 insertions(+), 19 deletions(-) diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index 74024f930..5474c58a0 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -73,6 +73,24 @@ namespace meshkernelapi // Exclusively owned state meshkernel::Projection m_projection{meshkernel::Projection::cartesian}; ///< Projection used by the meshes + + std::vector m_facePolygonsCoordsX; + std::vector m_facePolygonsCoordsY; + + int m_facePolygonsPropertyValue = 0; + double m_facePolygonsMinValue = -999.0; + double m_facePolygonsMaxValue = -999.0; + bool m_facePolygonsCoordsCached = false; + + std::vector m_boundaryPolygonsCoordsX; + std::vector m_boundaryPolygonsCoordsY; + + int m_lowerLeftNValue = -1; + int m_lowerLeftMValue = -1; + int m_upperRightNValue = -1; + int m_upperRightMValue = -1; + + bool m_boundaryPolygonsCoordsCached = false; }; } // namespace meshkernelapi diff --git a/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp b/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp index 1eb993851..46055aa28 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp @@ -486,7 +486,9 @@ namespace meshkernelapi const meshkernel::Projection& projection) { meshkernel::CurvilinearGridRectangular grid(projection); - + std::cout << "grid.Compute: " << makeGridParameters.num_columns << " " << makeGridParameters.num_rows << " " + << makeGridParameters.origin_x << " " << makeGridParameters.origin_y << " " + << makeGridParameters.angle << " " << makeGridParameters.block_size_x << " " << makeGridParameters.block_size_y << std::endl; return grid.Compute(makeGridParameters.num_columns, makeGridParameters.num_rows, makeGridParameters.origin_x, diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index 643584742..91fc7fe0a 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -945,19 +945,40 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("Invalid curvilinear grid"); } - auto lowerLeftNUnsigned = static_cast(lowerLeftN); - auto lowerLeftMUnsigned = static_cast(lowerLeftM); - auto upperRightNUnsigned = static_cast(upperRightN); - auto upperRightMUnsigned = static_cast(upperRightM); + if (!meshKernelState[meshKernelId].m_boundaryPolygonsCoordsCached) + { + throw meshkernel::MeshKernelError("Polygon data has not been cached"); + } - 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 (lowerLeftN != meshKernelState[meshKernelId].m_lowerLeftNValue || + lowerLeftM != meshKernelState[meshKernelId].m_lowerLeftMValue || + upperRightN != meshKernelState[meshKernelId].m_upperRightNValue || + upperRightM != meshKernelState[meshKernelId].m_upperRightMValue) + { + throw meshkernel::ConstraintError("Given polygon ranges are incompatible with the cached values"); + } - const auto boundaryPolygon = meshKernelState[meshKernelId].m_curvilinearGrid->ComputeBoundaryPolygons({minN, minM}, - {maxN, maxM}); - ConvertPointVectorToGeometryList(boundaryPolygon, boundaryPolygons); + if (boundaryPolygons.coordinates_x == nullptr || boundaryPolygons.coordinates_y == nullptr) + { + throw meshkernel::ConstraintError("Boundary polygon array are null"); + } + + if (boundaryPolygons.num_coordinates != static_cast(meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.size())) + { + throw meshkernel::ConstraintError("Incompatible boundary polygon size (user-size /= cached-size): {} /= {}", + boundaryPolygons.num_coordinates, + meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.size()); + } + + size_t valueCount = sizeof(double) * meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.size(); + + std::memcpy(boundaryPolygons.coordinates_x, meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.data(), valueCount); + std::memcpy(boundaryPolygons.coordinates_y, meshKernelState[meshKernelId].m_boundaryPolygonsCoordsY.data(), valueCount); + + // Now reset the vectors + meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.clear(); + meshKernelState[meshKernelId].m_boundaryPolygonsCoordsY.clear(); + meshKernelState[meshKernelId].m_boundaryPolygonsCoordsCached = false; } catch (...) { @@ -981,6 +1002,10 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("Invalid curvilinear grid"); } + meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.clear(); + meshKernelState[meshKernelId].m_boundaryPolygonsCoordsY.clear(); + meshKernelState[meshKernelId].m_boundaryPolygonsCoordsCached = false; + const auto lowerLeftNUnsigned = static_cast(lowerLeftN); const auto lowerLeftMUnsigned = static_cast(lowerLeftM); const auto upperRightNUnsigned = static_cast(upperRightN); @@ -994,6 +1019,21 @@ namespace meshkernelapi const auto boundaryPolygon = meshKernelState[meshKernelId].m_curvilinearGrid->ComputeBoundaryPolygons({minN, minM}, {maxN, maxM}); numberOfPolygonNodes = static_cast(boundaryPolygon.size()); + + meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.resize(boundaryPolygon.size()); + meshKernelState[meshKernelId].m_boundaryPolygonsCoordsY.resize(boundaryPolygon.size()); + meshKernelState[meshKernelId].m_boundaryPolygonsCoordsCached = true; + + meshKernelState[meshKernelId].m_lowerLeftNValue = lowerLeftN; + meshKernelState[meshKernelId].m_lowerLeftMValue = lowerLeftM; + meshKernelState[meshKernelId].m_upperRightNValue = upperRightN; + meshKernelState[meshKernelId].m_upperRightMValue = upperRightM; + + GeometryList boundaryPolygons; + boundaryPolygons.num_coordinates = boundaryPolygon.size(); + boundaryPolygons.coordinates_x = meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.data(); + boundaryPolygons.coordinates_y = meshKernelState[meshKernelId].m_boundaryPolygonsCoordsY.data(); + ConvertPointVectorToGeometryList(boundaryPolygon, boundaryPolygons); } catch (...) { @@ -2488,12 +2528,19 @@ namespace meshkernelapi { throw meshkernel::ConstraintError("The 2d mesh contains no nodes."); } + + meshKernelState[meshKernelId].m_facePolygonsCoordsX.clear(); + meshKernelState[meshKernelId].m_facePolygonsCoordsY.clear(); + meshKernelState[meshKernelId].m_facePolygonsCoordsCached = false; + 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]) @@ -2503,9 +2550,23 @@ namespace meshkernelapi const auto faceNumEdges = static_cast(meshKernelState[meshKernelId].m_mesh2d->m_facesNodes[f].size()); geometryListDimension += faceNumEdges + 2; } + if (geometryListDimension > 0) { geometryListDimension -= 1; + meshKernelState[meshKernelId].m_facePolygonsCoordsX.resize(static_cast(geometryListDimension)); + meshKernelState[meshKernelId].m_facePolygonsCoordsY.resize(static_cast(geometryListDimension)); + GeometryList facePolygons; + + facePolygons.coordinates_x = meshKernelState[meshKernelId].m_facePolygonsCoordsX.data(); + facePolygons.coordinates_y = meshKernelState[meshKernelId].m_facePolygonsCoordsY.data(); + + meshKernelState[meshKernelId].m_facePolygonsPropertyValue = propertyValue; + meshKernelState[meshKernelId].m_facePolygonsMinValue = minValue; + meshKernelState[meshKernelId].m_facePolygonsMaxValue = maxValue; + + FillFacePolygons(meshKernelState[meshKernelId].m_mesh2d, filterMask, facePolygons); + meshKernelState[meshKernelId].m_facePolygonsCoordsCached = true; } } catch (...) @@ -2533,12 +2594,30 @@ 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_facePolygonsCoordsCached) + { + throw meshkernel::ConstraintError("Filtered data has not been calculated"); + } + + if (propertyValue != meshKernelState[meshKernelId].m_facePolygonsPropertyValue || + minValue != meshKernelState[meshKernelId].m_facePolygonsMinValue || + maxValue != meshKernelState[meshKernelId].m_facePolygonsMaxValue) + { + throw meshkernel::ConstraintError("Given filter properties are incompatible with the cached values: property value: {} <=> {}, min value: {} <=> {}, max value {} <=> {}", + propertyValue, meshKernelState[meshKernelId].m_facePolygonsPropertyValue, + minValue, meshKernelState[meshKernelId].m_facePolygonsMinValue, + maxValue, meshKernelState[meshKernelId].m_facePolygonsMaxValue); + } + + size_t valueCount = sizeof(double) * meshKernelState[meshKernelId].m_facePolygonsCoordsX.size(); + + std::memcpy(facePolygons.coordinates_x, meshKernelState[meshKernelId].m_facePolygonsCoordsX.data(), valueCount); + std::memcpy(facePolygons.coordinates_y, meshKernelState[meshKernelId].m_facePolygonsCoordsY.data(), valueCount); + + // Now reset the vectors + meshKernelState[meshKernelId].m_facePolygonsCoordsX.clear(); + meshKernelState[meshKernelId].m_facePolygonsCoordsY.clear(); + meshKernelState[meshKernelId].m_facePolygonsCoordsCached = false; } catch (...) { diff --git a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp index 3d8f3bbae..292445807 100644 --- a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp +++ b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp @@ -1490,6 +1490,87 @@ TEST_P(CurvilineartBoundariesAsPolygonsTests, GetLocationIndex_OnACurvilinearGri ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); } +TEST(CurvilineartGrid, GetLocationIndex_OnACurvilinearGrid_GetLocationIdexFailures) +{ + 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; + + std::cout << "here 0 " << std::endl; + + errorCode = meshkernelapi::mkernel_curvilinear_compute_rectangular_grid(meshKernelId, makeGridParameters); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); + + int numberOfPolygonNodes; + + meshkernelapi::GeometryList boundaryPolygon; + 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; + + std::cout << "here 1 " << std::endl; + + // Get before being cached + errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, boundaryPolygon); + ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode); + + std::cout << "here 2 " << std::endl; + + errorCode = meshkernelapi::mkernel_curvilinear_count_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, numberOfPolygonNodes); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); + + std::cout << "here 3 " << std::endl; + + // Check working version + errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, boundaryPolygon); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); + + std::cout << "here 4 " << std::endl; + + // Different lowerLeftN + errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN + 1, lowerLeftM, upperRightN, upperRightM, boundaryPolygon); + ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); + + std::cout << "here 5 " << std::endl; + + // Different lowerLeftM + errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM + 1, upperRightN, upperRightM, boundaryPolygon); + ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); + + std::cout << "here 6 " << std::endl; + + // Different upperRightN + errorCode = mkernel_curvilinear_get_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN + 1, upperRightM, boundaryPolygon); + ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); + + // Different upperRightM + 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/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); +} From 232714d643ddd7d538f30f88fe2ee1028b930777 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Thu, 17 Oct 2024 09:37:52 +0200 Subject: [PATCH 02/17] GRIDEDIT-1336 Removed debugging cout statements. Fixed unit test --- .../include/MeshKernelApi/Utils.hpp | 3 --- .../tests/src/CurvilinearGridTests.cpp | 27 ++++++++----------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp b/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp index 46055aa28..2b131a56b 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp @@ -486,9 +486,6 @@ namespace meshkernelapi const meshkernel::Projection& projection) { meshkernel::CurvilinearGridRectangular grid(projection); - std::cout << "grid.Compute: " << makeGridParameters.num_columns << " " << makeGridParameters.num_rows << " " - << makeGridParameters.origin_x << " " << makeGridParameters.origin_y << " " - << makeGridParameters.angle << " " << makeGridParameters.block_size_x << " " << makeGridParameters.block_size_y << std::endl; return grid.Compute(makeGridParameters.num_columns, makeGridParameters.num_rows, makeGridParameters.origin_x, diff --git a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp index 292445807..78332c385 100644 --- a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp +++ b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp @@ -1490,7 +1490,7 @@ TEST_P(CurvilineartBoundariesAsPolygonsTests, GetLocationIndex_OnACurvilinearGri ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); } -TEST(CurvilineartGrid, GetLocationIndex_OnACurvilinearGrid_GetLocationIdexFailures) +TEST(CurvilineartGrid, GetLocationIndex_OnACurvilinearGrid_GetLocationIndexFailures) { const int lowerLeftN = 1; const int lowerLeftM = 1; @@ -1512,8 +1512,6 @@ TEST(CurvilineartGrid, GetLocationIndex_OnACurvilinearGrid_GetLocationIdexFailur makeGridParameters.block_size_x = 10.0; makeGridParameters.block_size_y = 10.0; - std::cout << "here 0 " << std::endl; - errorCode = meshkernelapi::mkernel_curvilinear_compute_rectangular_grid(meshKernelId, makeGridParameters); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); @@ -1528,42 +1526,39 @@ TEST(CurvilineartGrid, GetLocationIndex_OnACurvilinearGrid_GetLocationIdexFailur boundaryPolygon.num_coordinates = numberOfPolygonNodes; boundaryPolygon.geometry_separator = constants::missing::doubleValue; - std::cout << "here 1 " << std::endl; - - // Get before being cached + // 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); - std::cout << "here 2 " << std::endl; - errorCode = meshkernelapi::mkernel_curvilinear_count_boundaries_as_polygons(meshKernelId, lowerLeftN, lowerLeftM, upperRightN, upperRightM, numberOfPolygonNodes); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); - std::cout << "here 3 " << std::endl; - // 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); - std::cout << "here 4 " << std::endl; - // 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); - std::cout << "here 5 " << std::endl; - // 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); - std::cout << "here 6 " << std::endl; - // 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); From 7a7f8492fb325cbfed928d52b3a98e61986cf19c Mon Sep 17 00:00:00 2001 From: BillSenior Date: Thu, 17 Oct 2024 16:21:35 +0200 Subject: [PATCH 03/17] GRIDEDIT-1336 Added caching for polygon refinement --- libs/MeshKernelApi/CMakeLists.txt | 8 + .../BoundariesAsPolygonCache.hpp | 66 +++++++ .../MeshKernelApi/CachedPointValues.hpp | 70 +++++++ .../FacePolygonPropertyCache.hpp | 62 +++++++ .../include/MeshKernelApi/MeshKernel.hpp | 8 + .../MeshKernelApi/PolygonRefinementCache.hpp | 61 +++++++ .../include/MeshKernelApi/State.hpp | 27 +-- .../include/MeshKernelApi/Utils.hpp | 16 +- .../src/BoundariesAsPolygonCache.cpp | 52 ++++++ libs/MeshKernelApi/src/CachedPointValues.cpp | 57 ++++++ .../src/FacePolygonPropertyCache.cpp | 63 +++++++ libs/MeshKernelApi/src/MeshKernel.cpp | 172 +++++++++--------- .../src/PolygonRefinementCache.cpp | 24 +++ .../tests/src/Mesh2DRefinmentTests.cpp | 2 +- 14 files changed, 577 insertions(+), 111 deletions(-) create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/BoundariesAsPolygonCache.hpp create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/CachedPointValues.hpp create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/FacePolygonPropertyCache.hpp create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/PolygonRefinementCache.hpp create mode 100644 libs/MeshKernelApi/src/BoundariesAsPolygonCache.cpp create mode 100644 libs/MeshKernelApi/src/CachedPointValues.cpp create mode 100644 libs/MeshKernelApi/src/FacePolygonPropertyCache.cpp create mode 100644 libs/MeshKernelApi/src/PolygonRefinementCache.cpp diff --git a/libs/MeshKernelApi/CMakeLists.txt b/libs/MeshKernelApi/CMakeLists.txt index 1be63d013..0560e930b 100644 --- a/libs/MeshKernelApi/CMakeLists.txt +++ b/libs/MeshKernelApi/CMakeLists.txt @@ -21,22 +21,30 @@ set(VERSION_INC_DIR ${CMAKE_SOURCE_DIR}/tools) # list of target sources set(SRC_LIST + ${SRC_DIR}/BoundariesAsPolygonCache.cpp + ${SRC_DIR}/CachedPointValues.cpp + ${SRC_DIR}/FacePolygonPropertyCache.cpp ${SRC_DIR}/MKStateUndoAction.cpp ${SRC_DIR}/MeshKernel.cpp + ${SRC_DIR}/PolygonRefinementCache.cpp ) # list of target headers set( INC_LIST + ${DOMAIN_INC_DIR}/BoundariesAsPolygonCache.hpp ${DOMAIN_INC_DIR}/BoundingBox.hpp + ${DOMAIN_INC_DIR}/CachedPointValues.hpp ${DOMAIN_INC_DIR}/Contacts.hpp ${DOMAIN_INC_DIR}/CurvilinearGrid.hpp + ${DOMAIN_INC_DIR}/FacePolygonPropertyCache.hpp ${DOMAIN_INC_DIR}/GeometryList.hpp ${DOMAIN_INC_DIR}/GriddedSamples.hpp ${DOMAIN_INC_DIR}/MKStateUndoAction.hpp ${DOMAIN_INC_DIR}/Mesh1D.hpp ${DOMAIN_INC_DIR}/Mesh2D.hpp ${DOMAIN_INC_DIR}/MeshKernel.hpp + ${DOMAIN_INC_DIR}/PolygonRefinementCache.hpp ${DOMAIN_INC_DIR}/State.hpp ${DOMAIN_INC_DIR}/Utils.hpp ${VERSION_INC_DIR}/Version/Version.hpp diff --git a/libs/MeshKernelApi/include/MeshKernelApi/BoundariesAsPolygonCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/BoundariesAsPolygonCache.hpp new file mode 100644 index 000000000..9e0bfc44d --- /dev/null +++ b/libs/MeshKernelApi/include/MeshKernelApi/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/CachedPointValues.hpp" +#include "MeshKernelApi/GeometryList.hpp" +#include "MeshKernelApi/Utils.hpp" + +namespace meshkernelapi +{ + + /// @brief Boundary 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/CachedPointValues.hpp b/libs/MeshKernelApi/include/MeshKernelApi/CachedPointValues.hpp new file mode 100644 index 000000000..098245439 --- /dev/null +++ b/libs/MeshKernelApi/include/MeshKernelApi/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/FacePolygonPropertyCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/FacePolygonPropertyCache.hpp new file mode 100644 index 000000000..d05a44408 --- /dev/null +++ b/libs/MeshKernelApi/include/MeshKernelApi/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/CachedPointValues.hpp" + +namespace meshkernelapi +{ + /// @brief + class FacePolygonPropertyCache : public CachedPointValues + { + + public: + /// @brief Constuctor + 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/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/PolygonRefinementCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/PolygonRefinementCache.hpp new file mode 100644 index 000000000..4d24ec463 --- /dev/null +++ b/libs/MeshKernelApi/include/MeshKernelApi/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/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/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index 5474c58a0..d8aa22bb8 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -38,6 +38,12 @@ #include #include +#include "MeshKernelApi/BoundariesAsPolygonCache.hpp" +#include "MeshKernelApi/CachedPointValues.hpp" +#include "MeshKernelApi/FacePolygonPropertyCache.hpp" +#include "MeshKernelApi/PolygonRefinementCache.hpp" + + namespace meshkernelapi { @@ -74,23 +80,10 @@ namespace meshkernelapi // Exclusively owned state meshkernel::Projection m_projection{meshkernel::Projection::cartesian}; ///< Projection used by the meshes - std::vector m_facePolygonsCoordsX; - std::vector m_facePolygonsCoordsY; - - int m_facePolygonsPropertyValue = 0; - double m_facePolygonsMinValue = -999.0; - double m_facePolygonsMaxValue = -999.0; - bool m_facePolygonsCoordsCached = false; - - std::vector m_boundaryPolygonsCoordsX; - std::vector m_boundaryPolygonsCoordsY; - - int m_lowerLeftNValue = -1; - int m_lowerLeftMValue = -1; - int m_upperRightNValue = -1; - int m_upperRightMValue = -1; - - bool m_boundaryPolygonsCoordsCached = false; + // Cached values, used when dimensions are computed first, followed by values beign retrieved in a separate call + std::shared_ptr m_facePropertyCache; ///< Cache for + std::shared_ptr m_boundariesAsPolygonCache; ///< Cache + std::shared_ptr m_polygonRefinementCache; ///< Cache for polygon refinement }; } // namespace meshkernelapi diff --git a/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp b/libs/MeshKernelApi/include/MeshKernelApi/Utils.hpp index 2b131a56b..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 @@ -582,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/BoundariesAsPolygonCache.cpp b/libs/MeshKernelApi/src/BoundariesAsPolygonCache.cpp new file mode 100644 index 000000000..900a25c64 --- /dev/null +++ b/libs/MeshKernelApi/src/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/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/CachedPointValues.cpp b/libs/MeshKernelApi/src/CachedPointValues.cpp new file mode 100644 index 000000000..186b71d74 --- /dev/null +++ b/libs/MeshKernelApi/src/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/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/FacePolygonPropertyCache.cpp b/libs/MeshKernelApi/src/FacePolygonPropertyCache.cpp new file mode 100644 index 000000000..dda3ec840 --- /dev/null +++ b/libs/MeshKernelApi/src/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/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/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index 91fc7fe0a..ecc122a4f 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -935,51 +935,39 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); } - if (!meshKernelState.contains(meshKernelId)) - { - throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); - } - if (!meshKernelState[meshKernelId].m_curvilinearGrid->IsValid()) { throw meshkernel::MeshKernelError("Invalid curvilinear grid"); } - if (!meshKernelState[meshKernelId].m_boundaryPolygonsCoordsCached) + if (boundaryPolygons.coordinates_x == nullptr || boundaryPolygons.coordinates_y == nullptr) { - throw meshkernel::MeshKernelError("Polygon data has not been cached"); + throw meshkernel::MeshKernelError("Boundary polygon array are null"); } - if (lowerLeftN != meshKernelState[meshKernelId].m_lowerLeftNValue || - lowerLeftM != meshKernelState[meshKernelId].m_lowerLeftMValue || - upperRightN != meshKernelState[meshKernelId].m_upperRightNValue || - upperRightM != meshKernelState[meshKernelId].m_upperRightMValue) + if (meshKernelState[meshKernelId].m_boundariesAsPolygonCache == nullptr) { - throw meshkernel::ConstraintError("Given polygon ranges are incompatible with the cached values"); + throw meshkernel::MeshKernelError("Polygon data has not been cached"); } - if (boundaryPolygons.coordinates_x == nullptr || boundaryPolygons.coordinates_y == nullptr) + if (!meshKernelState[meshKernelId].m_boundariesAsPolygonCache->ValidOptions(lowerLeftN, lowerLeftM, upperRightN, upperRightM)) { - throw meshkernel::ConstraintError("Boundary polygon array are null"); + meshKernelState[meshKernelId].m_boundariesAsPolygonCache.reset(); + throw meshkernel::ConstraintError("Given polygon ranges are incompatible with the cached values. Cached values will be deleted."); } - if (boundaryPolygons.num_coordinates != static_cast(meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.size())) + if (boundaryPolygons.num_coordinates != meshKernelState[meshKernelId].m_boundariesAsPolygonCache->Size()) { - throw meshkernel::ConstraintError("Incompatible boundary polygon size (user-size /= cached-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_boundaryPolygonsCoordsX.size()); + meshKernelState[meshKernelId].m_boundariesAsPolygonCache->Size()); } - size_t valueCount = sizeof(double) * meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.size(); - - std::memcpy(boundaryPolygons.coordinates_x, meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.data(), valueCount); - std::memcpy(boundaryPolygons.coordinates_y, meshKernelState[meshKernelId].m_boundaryPolygonsCoordsY.data(), valueCount); - - // Now reset the vectors - meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.clear(); - meshKernelState[meshKernelId].m_boundaryPolygonsCoordsY.clear(); - meshKernelState[meshKernelId].m_boundaryPolygonsCoordsCached = false; + meshKernelState[meshKernelId].m_boundariesAsPolygonCache->Copy(boundaryPolygons); + meshKernelState[meshKernelId].m_boundariesAsPolygonCache.reset(); } + catch (...) { lastExitCode = HandleException(); @@ -1002,9 +990,11 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("Invalid curvilinear grid"); } - meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.clear(); - meshKernelState[meshKernelId].m_boundaryPolygonsCoordsY.clear(); - meshKernelState[meshKernelId].m_boundaryPolygonsCoordsCached = false; + if (meshKernelState[meshKernelId].m_boundariesAsPolygonCache != nullptr) + { + std::cout << "Polygon data has already been cached" << std::endl; + throw meshkernel::MeshKernelError("Polygon data has already been cached"); + } const auto lowerLeftNUnsigned = static_cast(lowerLeftN); const auto lowerLeftMUnsigned = static_cast(lowerLeftM); @@ -1019,21 +1009,7 @@ namespace meshkernelapi const auto boundaryPolygon = meshKernelState[meshKernelId].m_curvilinearGrid->ComputeBoundaryPolygons({minN, minM}, {maxN, maxM}); numberOfPolygonNodes = static_cast(boundaryPolygon.size()); - - meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.resize(boundaryPolygon.size()); - meshKernelState[meshKernelId].m_boundaryPolygonsCoordsY.resize(boundaryPolygon.size()); - meshKernelState[meshKernelId].m_boundaryPolygonsCoordsCached = true; - - meshKernelState[meshKernelId].m_lowerLeftNValue = lowerLeftN; - meshKernelState[meshKernelId].m_lowerLeftMValue = lowerLeftM; - meshKernelState[meshKernelId].m_upperRightNValue = upperRightN; - meshKernelState[meshKernelId].m_upperRightMValue = upperRightM; - - GeometryList boundaryPolygons; - boundaryPolygons.num_coordinates = boundaryPolygon.size(); - boundaryPolygons.coordinates_x = meshKernelState[meshKernelId].m_boundaryPolygonsCoordsX.data(); - boundaryPolygons.coordinates_y = meshKernelState[meshKernelId].m_boundaryPolygonsCoordsY.data(); - ConvertPointVectorToGeometryList(boundaryPolygon, boundaryPolygons); + meshKernelState[meshKernelId].m_boundariesAsPolygonCache = std::make_shared(lowerLeftN, lowerLeftM, upperRightN, upperRightM, boundaryPolygon); } catch (...) { @@ -1976,12 +1952,25 @@ 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"); + } + 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); + meshKernelState[meshKernelId].m_polygonRefinementCache->Copy(refinedPolygon); + meshKernelState[meshKernelId].m_polygonRefinementCache.reset(); } catch (...) { @@ -2000,14 +1989,21 @@ 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"); + } + 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); + meshKernelState[meshKernelId].m_polygonRefinementCache->Copy(refinedPolygon); + meshKernelState[meshKernelId].m_polygonRefinementCache.reset(); } catch (...) { @@ -2031,12 +2027,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 (...) @@ -2056,13 +2061,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 (...) @@ -2469,7 +2484,7 @@ namespace meshkernelapi validFace[f] = true; } } - FillFacePolygons(meshKernelState[meshKernelId].m_mesh2d, validFace, facePolygons); + FillFacePolygons(*meshKernelState[meshKernelId].m_mesh2d, validFace, facePolygons); } catch (...) { @@ -2524,14 +2539,18 @@ 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."); } - meshKernelState[meshKernelId].m_facePolygonsCoordsX.clear(); - meshKernelState[meshKernelId].m_facePolygonsCoordsY.clear(); - meshKernelState[meshKernelId].m_facePolygonsCoordsCached = false; + 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); @@ -2547,6 +2566,7 @@ namespace meshkernelapi { continue; } + const auto faceNumEdges = static_cast(meshKernelState[meshKernelId].m_mesh2d->m_facesNodes[f].size()); geometryListDimension += faceNumEdges + 2; } @@ -2554,19 +2574,10 @@ namespace meshkernelapi if (geometryListDimension > 0) { geometryListDimension -= 1; - meshKernelState[meshKernelId].m_facePolygonsCoordsX.resize(static_cast(geometryListDimension)); - meshKernelState[meshKernelId].m_facePolygonsCoordsY.resize(static_cast(geometryListDimension)); - GeometryList facePolygons; - - facePolygons.coordinates_x = meshKernelState[meshKernelId].m_facePolygonsCoordsX.data(); - facePolygons.coordinates_y = meshKernelState[meshKernelId].m_facePolygonsCoordsY.data(); - - meshKernelState[meshKernelId].m_facePolygonsPropertyValue = propertyValue; - meshKernelState[meshKernelId].m_facePolygonsMinValue = minValue; - meshKernelState[meshKernelId].m_facePolygonsMaxValue = maxValue; - - FillFacePolygons(meshKernelState[meshKernelId].m_mesh2d, filterMask, facePolygons); - meshKernelState[meshKernelId].m_facePolygonsCoordsCached = true; + meshKernelState[meshKernelId].m_facePropertyCache = std::make_shared(propertyValue, minValue, maxValue, + *meshKernelState[meshKernelId].m_mesh2d, + geometryListDimension, + filterMask); } } catch (...) @@ -2594,30 +2605,19 @@ namespace meshkernelapi throw meshkernel::ConstraintError("The 2d mesh contains no nodes."); } - if (!meshKernelState[meshKernelId].m_facePolygonsCoordsCached) + if (meshKernelState[meshKernelId].m_facePropertyCache == nullptr) { - throw meshkernel::ConstraintError("Filtered data has not been calculated"); + throw meshkernel::ConstraintError("Filtered data has not been cached"); } - if (propertyValue != meshKernelState[meshKernelId].m_facePolygonsPropertyValue || - minValue != meshKernelState[meshKernelId].m_facePolygonsMinValue || - maxValue != meshKernelState[meshKernelId].m_facePolygonsMaxValue) + if (!meshKernelState[meshKernelId].m_facePropertyCache->ValidOptions(propertyValue, minValue, maxValue)) { - throw meshkernel::ConstraintError("Given filter properties are incompatible with the cached values: property value: {} <=> {}, min value: {} <=> {}, max value {} <=> {}", - propertyValue, meshKernelState[meshKernelId].m_facePolygonsPropertyValue, - minValue, meshKernelState[meshKernelId].m_facePolygonsMinValue, - maxValue, meshKernelState[meshKernelId].m_facePolygonsMaxValue); + meshKernelState[meshKernelId].m_facePropertyCache.reset(); + throw meshkernel::ConstraintError("Given filter properties are incompatible with the cached values. Cached values will be deleted."); } - size_t valueCount = sizeof(double) * meshKernelState[meshKernelId].m_facePolygonsCoordsX.size(); - - std::memcpy(facePolygons.coordinates_x, meshKernelState[meshKernelId].m_facePolygonsCoordsX.data(), valueCount); - std::memcpy(facePolygons.coordinates_y, meshKernelState[meshKernelId].m_facePolygonsCoordsY.data(), valueCount); - - // Now reset the vectors - meshKernelState[meshKernelId].m_facePolygonsCoordsX.clear(); - meshKernelState[meshKernelId].m_facePolygonsCoordsY.clear(); - meshKernelState[meshKernelId].m_facePolygonsCoordsCached = false; + meshKernelState[meshKernelId].m_facePropertyCache->Copy(facePolygons); + meshKernelState[meshKernelId].m_facePropertyCache.reset(); } catch (...) { diff --git a/libs/MeshKernelApi/src/PolygonRefinementCache.cpp b/libs/MeshKernelApi/src/PolygonRefinementCache.cpp new file mode 100644 index 000000000..e61015a6e --- /dev/null +++ b/libs/MeshKernelApi/src/PolygonRefinementCache.cpp @@ -0,0 +1,24 @@ +#include "MeshKernelApi/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/tests/src/Mesh2DRefinmentTests.cpp b/libs/MeshKernelApi/tests/src/Mesh2DRefinmentTests.cpp index c8c59fec1..6f73e5fe3 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 From 443bdc1e284d1625ccc4cd5abfa73d0752b9c6fb Mon Sep 17 00:00:00 2001 From: BillSenior Date: Thu, 17 Oct 2024 16:38:06 +0200 Subject: [PATCH 04/17] GRIDEDIT-1336 Fixed clang formatting, doxygen spelling warnings and window build --- .../MeshKernelApi/BoundariesAsPolygonCache.hpp | 2 +- .../MeshKernelApi/FacePolygonPropertyCache.hpp | 4 ++-- libs/MeshKernelApi/include/MeshKernelApi/State.hpp | 1 - .../MeshKernelApi/tests/src/CurvilinearGridTests.cpp | 12 +++++++++++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libs/MeshKernelApi/include/MeshKernelApi/BoundariesAsPolygonCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/BoundariesAsPolygonCache.hpp index 9e0bfc44d..8020babd0 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/BoundariesAsPolygonCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/BoundariesAsPolygonCache.hpp @@ -39,7 +39,7 @@ namespace meshkernelapi { - /// @brief Boundary points + /// @brief Cache boundary polygon points class BoundariesAsPolygonCache : public CachedPointValues { public: diff --git a/libs/MeshKernelApi/include/MeshKernelApi/FacePolygonPropertyCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/FacePolygonPropertyCache.hpp index d05a44408..699126482 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/FacePolygonPropertyCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/FacePolygonPropertyCache.hpp @@ -35,12 +35,12 @@ namespace meshkernelapi { - /// @brief + /// @brief Cache node values of faces class FacePolygonPropertyCache : public CachedPointValues { public: - /// @brief Constuctor + /// @brief Constructor FacePolygonPropertyCache(const int propertyValue, const double minValue, const double maxValue, diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index d8aa22bb8..315db357d 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -43,7 +43,6 @@ #include "MeshKernelApi/FacePolygonPropertyCache.hpp" #include "MeshKernelApi/PolygonRefinementCache.hpp" - namespace meshkernelapi { diff --git a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp index 78332c385..0677bebfc 100644 --- a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp +++ b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp @@ -1515,9 +1515,11 @@ TEST(CurvilineartGrid, GetLocationIndex_OnACurvilinearGrid_GetLocationIndexFailu errorCode = meshkernelapi::mkernel_curvilinear_compute_rectangular_grid(meshKernelId, makeGridParameters); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); - int numberOfPolygonNodes; + // 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); @@ -1533,6 +1535,14 @@ TEST(CurvilineartGrid, GetLocationIndex_OnACurvilinearGrid_GetLocationIndexFailu 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); From 67b4abb15205cdad86654e6f6755d63527bdbe21 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Thu, 17 Oct 2024 17:31:42 +0200 Subject: [PATCH 05/17] GRIDEDIT-1336 Added unit tests for failing cases --- .../tests/src/Mesh2DRefinmentTests.cpp | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/libs/MeshKernelApi/tests/src/Mesh2DRefinmentTests.cpp b/libs/MeshKernelApi/tests/src/Mesh2DRefinmentTests.cpp index 6f73e5fe3..8cb748984 100644 --- a/libs/MeshKernelApi/tests/src/Mesh2DRefinmentTests.cpp +++ b/libs/MeshKernelApi/tests/src/Mesh2DRefinmentTests.cpp @@ -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 From c3f7acc31cf2b9bbf7e3d1ad001721279d887267 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Thu, 17 Oct 2024 17:54:50 +0200 Subject: [PATCH 06/17] GRIDEDIT-1336 Added some comments --- libs/MeshKernelApi/src/MeshKernel.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index ecc122a4f..4e2aafab2 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -964,7 +964,9 @@ namespace meshkernelapi 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(); } @@ -1969,7 +1971,9 @@ namespace meshkernelapi const meshkernel::Polygons polygon(polygonVector, meshKernelState[meshKernelId].m_projection); auto const refinementResult = polygon.RefineFirstPolygon(firstNodeIndex, secondNodeIndex, targetEdgeLength); + // 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 (...) @@ -2002,7 +2006,9 @@ namespace meshkernelapi throw meshkernel::ConstraintError("Given refinement properties are incompatible with the cached values. Cached values will be deleted."); } + // 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 (...) @@ -2616,7 +2622,9 @@ namespace meshkernelapi 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 (...) From 1b1d00b66ff18901802ef3f2794a9c34905c4da9 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Mon, 21 Oct 2024 12:56:19 +0200 Subject: [PATCH 07/17] GRIDEDIT-1336 Cached values for mesh point in polygon --- libs/MeshKernelApi/CMakeLists.txt | 2 + .../MeshKernelApi/NodeInPolygonCache.hpp | 69 ++++++++++++++++++ .../include/MeshKernelApi/State.hpp | 2 + libs/MeshKernelApi/src/MeshKernel.cpp | 63 ++++++++++------- libs/MeshKernelApi/src/NodeInPolygonCache.cpp | 70 +++++++++++++++++++ libs/MeshKernelApi/tests/src/ApiTest.cpp | 57 +++++++++++++++ .../tests/src/CurvilinearGridTests.cpp | 2 +- 7 files changed, 238 insertions(+), 27 deletions(-) create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp create mode 100644 libs/MeshKernelApi/src/NodeInPolygonCache.cpp diff --git a/libs/MeshKernelApi/CMakeLists.txt b/libs/MeshKernelApi/CMakeLists.txt index 0560e930b..041a7024e 100644 --- a/libs/MeshKernelApi/CMakeLists.txt +++ b/libs/MeshKernelApi/CMakeLists.txt @@ -26,6 +26,7 @@ set(SRC_LIST ${SRC_DIR}/FacePolygonPropertyCache.cpp ${SRC_DIR}/MKStateUndoAction.cpp ${SRC_DIR}/MeshKernel.cpp + ${SRC_DIR}/NodeInPolygonCache.cpp ${SRC_DIR}/PolygonRefinementCache.cpp ) @@ -44,6 +45,7 @@ set( ${DOMAIN_INC_DIR}/Mesh1D.hpp ${DOMAIN_INC_DIR}/Mesh2D.hpp ${DOMAIN_INC_DIR}/MeshKernel.hpp + ${DOMAIN_INC_DIR}/NodeInPolygonCache.hpp ${DOMAIN_INC_DIR}/PolygonRefinementCache.hpp ${DOMAIN_INC_DIR}/State.hpp ${DOMAIN_INC_DIR}/Utils.hpp diff --git a/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp new file mode 100644 index 000000000..f23ec95f4 --- /dev/null +++ b/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp @@ -0,0 +1,69 @@ +//---- 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 +{ + + class NodeInPolygonCache + { + public: + NodeInPolygonCache(const std::vector& nodeMask, + const std::vector& polygonPoints, + const int inside); + + bool ValidOptions(const std::vector& polygonPoints, const int inside) const; + + int Size() const; + + void Copy(int* selectedNodes) 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; + + /// &brief Indices of nodes in the polygon + std::vector m_nodeIndices; + }; + +} // namespace meshkernelapi + +inline int meshkernelapi::NodeInPolygonCache::Size() const +{ + return static_cast(m_nodeIndices.size()); +} diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index 315db357d..ba44c1b8d 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -41,6 +41,7 @@ #include "MeshKernelApi/BoundariesAsPolygonCache.hpp" #include "MeshKernelApi/CachedPointValues.hpp" #include "MeshKernelApi/FacePolygonPropertyCache.hpp" +#include "MeshKernelApi/NodeInPolygonCache.hpp" #include "MeshKernelApi/PolygonRefinementCache.hpp" namespace meshkernelapi @@ -83,6 +84,7 @@ namespace meshkernelapi std::shared_ptr m_facePropertyCache; ///< Cache for std::shared_ptr m_boundariesAsPolygonCache; ///< Cache std::shared_ptr m_polygonRefinementCache; ///< Cache for polygon refinement + std::shared_ptr m_nodeInPolygonCache; ///< Cache for node in polygon }; } // namespace meshkernelapi diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index 4e2aafab2..ffd564407 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -89,10 +89,15 @@ #include #include -#include -#include -#include -#include +#include "MeshKernelApi/BoundariesAsPolygonCache.hpp" +#include "MeshKernelApi/CachedPointValues.hpp" +#include "MeshKernelApi/FacePolygonPropertyCache.hpp" +#include "MeshKernelApi/MKStateUndoAction.hpp" +#include "MeshKernelApi/MeshKernel.hpp" +#include "MeshKernelApi/NodeInPolygonCache.hpp" +#include "MeshKernelApi/PolygonRefinementCache.hpp" +#include "MeshKernelApi/State.hpp" +#include "MeshKernelApi/Utils.hpp" #include @@ -994,8 +999,8 @@ namespace meshkernelapi if (meshKernelState[meshKernelId].m_boundariesAsPolygonCache != nullptr) { - std::cout << "Polygon data has already been cached" << std::endl; - throw meshkernel::MeshKernelError("Polygon data has already been cached"); + meshKernelState[meshKernelId].m_boundariesAsPolygonCache.reset(); + throw meshkernel::MeshKernelError("Polygon data has already been cached, deleting cached data"); } const auto lowerLeftNUnsigned = static_cast(lowerLeftN); @@ -2174,22 +2179,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"); + } - 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 (...) { @@ -2210,21 +2220,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 (...) { diff --git a/libs/MeshKernelApi/src/NodeInPolygonCache.cpp b/libs/MeshKernelApi/src/NodeInPolygonCache.cpp new file mode 100644 index 000000000..d8e74d70d --- /dev/null +++ b/libs/MeshKernelApi/src/NodeInPolygonCache.cpp @@ -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. +// +//------------------------------------------------------------------------------ + +#include +#include +#include + +#include "MeshKernel/Exceptions.hpp" + +#include "MeshKernelApi/NodeInPolygonCache.hpp" + +meshkernelapi::NodeInPolygonCache::NodeInPolygonCache(const std::vector& nodeMask, + const std::vector& polygonPoints, + const int inside) + : m_polygonPoints(polygonPoints), m_inside(inside) +{ + + m_nodeIndices.reserve(m_polygonPoints.size()); + + for (size_t i = 0; i < nodeMask.size(); ++i) + { + if (nodeMask[i] > 0) + { + m_nodeIndices.push_back(static_cast(i)); + } + } +} + +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()); +} + +void meshkernelapi::NodeInPolygonCache::Copy(int* selectedNodes) const +{ + if (selectedNodes == nullptr) + { + throw meshkernel::MeshKernelError("Selected nodes array is null."); + } + + size_t valueCount = sizeof(int) * m_nodeIndices.size(); + + std::memcpy(selectedNodes, m_nodeIndices.data(), valueCount); +} diff --git a/libs/MeshKernelApi/tests/src/ApiTest.cpp b/libs/MeshKernelApi/tests/src/ApiTest.cpp index 6166d10ca..c24e7da03 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, @@ -1522,6 +1532,53 @@ TEST_F(CartesianApiTestFixture, CountNodesInPolygonMesh2D_OnMesh2D_ShouldCountAl ASSERT_EQ(12, numNodes); } +TEST_F(CartesianApiTestFixture, GetNodesInPolygonMesh2D_OnMesh2D_NodeInPolygonFailures) +{ + // Prepare + MakeMesh(); + auto const meshKernelId = GetMeshKernelId(); + + // By using an empty list, all nodes will be selected + const meshkernelapi::GeometryList geometryListIn{}; + + meshkernelapi::Mesh2D mesh2d{}; + auto 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); +} + TEST_F(CartesianApiTestFixture, InsertNodeAndEdge_OnMesh2D_ShouldInsertNodeAndEdge) { // Prepare diff --git a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp index 0677bebfc..349a89b83 100644 --- a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp +++ b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp @@ -1490,7 +1490,7 @@ TEST_P(CurvilineartBoundariesAsPolygonsTests, GetLocationIndex_OnACurvilinearGri ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); } -TEST(CurvilineartGrid, GetLocationIndex_OnACurvilinearGrid_GetLocationIndexFailures) +TEST(CurvilinearGrid, GetLocationIndex_OnACurvilinearGrid_GetLocationIndexFailures) { const int lowerLeftN = 1; const int lowerLeftM = 1; From de07dca53c586ba38f69c87094e5094636f62b99 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Mon, 21 Oct 2024 12:59:22 +0200 Subject: [PATCH 08/17] GRIDEDIT-1336 Added doxygen comments --- .../include/MeshKernelApi/NodeInPolygonCache.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp index f23ec95f4..9e8843c3b 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp @@ -37,17 +37,22 @@ namespace meshkernelapi { + /// @brief Cache node indices contained in a polygon class NodeInPolygonCache { 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; + /// @brief Get the number of values being cached. int Size() const; + /// @brief Copy cached values to array void Copy(int* selectedNodes) const; private: From eff8e3f9d45e40493db3e15274977b33f00b5232 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Mon, 21 Oct 2024 12:59:48 +0200 Subject: [PATCH 09/17] GRIDEDIT-1336 Corrected doxygen comments --- .../include/MeshKernelApi/NodeInPolygonCache.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp index 9e8843c3b..bb4bfa185 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp @@ -56,13 +56,13 @@ namespace meshkernelapi void Copy(int* selectedNodes) const; private: - /// &brief Points making up the polygon + /// @brief Points making up the polygon std::vector m_polygonPoints; - /// &brief Indicates if the points are inside or outside of the polygon + /// @brief Indicates if the points are inside or outside of the polygon int m_inside = -1; - /// &brief Indices of nodes in the polygon + /// @brief Indices of nodes in the polygon std::vector m_nodeIndices; }; From 781e34c11931ec1d63f37589febe6132d1f28026 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Mon, 21 Oct 2024 14:54:33 +0200 Subject: [PATCH 10/17] GRIDEDIT-1336 Added cache for small flow edges --- libs/MeshKernelApi/CMakeLists.txt | 2 + .../SmallFlowEdgeCentreCache.hpp | 57 ++++++++++++++++++ .../include/MeshKernelApi/State.hpp | 2 + libs/MeshKernelApi/src/MeshKernel.cpp | 26 ++++++-- .../src/SmallFlowEdgeCentreCache.cpp | 37 ++++++++++++ libs/MeshKernelApi/tests/src/ApiTest.cpp | 59 +++++++++++++++++++ 6 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/SmallFlowEdgeCentreCache.hpp create mode 100644 libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp diff --git a/libs/MeshKernelApi/CMakeLists.txt b/libs/MeshKernelApi/CMakeLists.txt index 041a7024e..c23cab058 100644 --- a/libs/MeshKernelApi/CMakeLists.txt +++ b/libs/MeshKernelApi/CMakeLists.txt @@ -28,6 +28,7 @@ set(SRC_LIST ${SRC_DIR}/MeshKernel.cpp ${SRC_DIR}/NodeInPolygonCache.cpp ${SRC_DIR}/PolygonRefinementCache.cpp + ${SRC_DIR}/SmallFlowEdgeCentreCache.cpp ) # list of target headers @@ -47,6 +48,7 @@ set( ${DOMAIN_INC_DIR}/MeshKernel.hpp ${DOMAIN_INC_DIR}/NodeInPolygonCache.hpp ${DOMAIN_INC_DIR}/PolygonRefinementCache.hpp + ${DOMAIN_INC_DIR}/SmallFlowEdgeCentreCache.hpp ${DOMAIN_INC_DIR}/State.hpp ${DOMAIN_INC_DIR}/Utils.hpp ${VERSION_INC_DIR}/Version/Version.hpp diff --git a/libs/MeshKernelApi/include/MeshKernelApi/SmallFlowEdgeCentreCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/SmallFlowEdgeCentreCache.hpp new file mode 100644 index 000000000..f5e9b9fcf --- /dev/null +++ b/libs/MeshKernelApi/include/MeshKernelApi/SmallFlowEdgeCentreCache.hpp @@ -0,0 +1,57 @@ +//---- GPL --------------------------------------------------------------------- +// +// Copyright (C) Stichting Deltares, 2011-2024. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation version 3. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// contact: delft3d.support@deltares.nl +// Stichting Deltares +// P.O. Box 177 +// 2600 MH Delft, The Netherlands +// +// All indications and logos of, and references to, "Delft3D" and "Deltares" +// are registered trademarks of Stichting Deltares, and remain the property of +// Stichting Deltares. All rights reserved. +// +//------------------------------------------------------------------------------ + +#pragma once + +#include +#include + +#include "MeshKernel/Point.hpp" + +#include "MeshKernelApi/CachedPointValues.hpp" +#include "MeshKernelApi/GeometryList.hpp" + +namespace meshkernelapi +{ + + /// @brief Cache centre of edges + class SmallFlowEdgeCentreCache : public CachedPointValues + { + public: + /// @brief Constructor + SmallFlowEdgeCentreCache(const double lengthThreshold, + const std::vector& edgeCentres); + + /// @brief Determine if current options match those used to construct the object + bool ValidOptions(const double lengthThreshold) const; + + private: + /// @brief Threshold for small edge length + double m_lengthThreshold; + }; + +} // namespace meshkernelapi diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index ba44c1b8d..64e470509 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -43,6 +43,7 @@ #include "MeshKernelApi/FacePolygonPropertyCache.hpp" #include "MeshKernelApi/NodeInPolygonCache.hpp" #include "MeshKernelApi/PolygonRefinementCache.hpp" +#include "MeshKernelApi/SmallFlowEdgeCentreCache.hpp" namespace meshkernelapi { @@ -85,6 +86,7 @@ namespace meshkernelapi std::shared_ptr m_boundariesAsPolygonCache; ///< Cache std::shared_ptr m_polygonRefinementCache; ///< Cache for polygon refinement std::shared_ptr m_nodeInPolygonCache; ///< Cache for node in polygon + std::shared_ptr m_smallFlowEdgeCentreCache; ///< Cache for small flow edge centres }; } // namespace meshkernelapi diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index ffd564407..6f1879671 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -3426,10 +3426,19 @@ namespace meshkernelapi { throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); } + + if (meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache != nullptr) + { + meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache.reset(); + throw meshkernel::ConstraintError("Small flow edge data has already been cached. Cached values will be deleted."); + } + const auto edgesCrossingSmallFlowEdges = meshKernelState[meshKernelId].m_mesh2d->GetEdgesCrossingSmallFlowEdges(smallFlowEdgesLengthThreshold); const auto smallFlowEdgeCenters = meshKernelState[meshKernelId].m_mesh2d->GetFlowEdgesCenters(edgesCrossingSmallFlowEdges); - numSmallFlowEdges = static_cast(smallFlowEdgeCenters.size()); + meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache = std::make_shared(smallFlowEdgesLengthThreshold, smallFlowEdgeCenters); + + numSmallFlowEdges = meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache->Size(); } catch (...) { @@ -3448,10 +3457,19 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); } - const auto edgesCrossingSmallFlowEdges = meshKernelState[meshKernelId].m_mesh2d->GetEdgesCrossingSmallFlowEdges(smallFlowEdgesThreshold); - const auto smallFlowEdgeCenters = meshKernelState[meshKernelId].m_mesh2d->GetFlowEdgesCenters(edgesCrossingSmallFlowEdges); + if (meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache == nullptr) + { + throw meshkernel::ConstraintError("Small flow edge data has not been cached"); + } + + if (!meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache->ValidOptions(smallFlowEdgesThreshold)) + { + meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache.reset(); + throw meshkernel::ConstraintError("Given small flow edge options are incompatible with the cached values. Cached values will be deleted."); + } - ConvertPointVectorToGeometryList(smallFlowEdgeCenters, result); + meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache->Copy(result); + meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache.reset(); } catch (...) { diff --git a/libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp b/libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp new file mode 100644 index 000000000..4ee8fc9fa --- /dev/null +++ b/libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp @@ -0,0 +1,37 @@ +//---- GPL --------------------------------------------------------------------- +// +// Copyright (C) Stichting Deltares, 2011-2024. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation version 3. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// contact: delft3d.support@deltares.nl +// Stichting Deltares +// P.O. Box 177 +// 2600 MH Delft, The Netherlands +// +// All indications and logos of, and references to, "Delft3D" and "Deltares" +// are registered trademarks of Stichting Deltares, and remain the property of +// Stichting Deltares. All rights reserved. +// +//------------------------------------------------------------------------------ + +#include "MeshKernelApi/SmallFlowEdgeCentreCache.hpp" + +meshkernelapi::SmallFlowEdgeCentreCache::SmallFlowEdgeCentreCache(const double lengthThreshold, + const std::vector& edgeCentres) + : CachedPointValues(edgeCentres), m_lengthThreshold(lengthThreshold) {} + +bool meshkernelapi::SmallFlowEdgeCentreCache::ValidOptions(const double lengthThreshold) const +{ + return lengthThreshold == m_lengthThreshold; +} diff --git a/libs/MeshKernelApi/tests/src/ApiTest.cpp b/libs/MeshKernelApi/tests/src/ApiTest.cpp index c24e7da03..9ef18bde7 100644 --- a/libs/MeshKernelApi/tests/src/ApiTest.cpp +++ b/libs/MeshKernelApi/tests/src/ApiTest.cpp @@ -1761,6 +1761,65 @@ TEST_F(CartesianApiTestFixture, GetSmallFlowEdges_OnMesh2D_ShouldGetSmallFlowEdg ASSERT_NEAR(result.coordinates_y[0], 0.0, tolerance); } +TEST_F(CartesianApiTestFixture, GetSmallFlowEdges_OnMesh2D_GetSmallFlowEdgesFailures) +{ + // Prepare a mesh with two triangles + meshkernelapi::Mesh2D mesh2d; + + std::vector node_x{0.0, 1.0, 1.0, 1.0}; + std::vector node_y{0.0, 0.0, 0.3, -0.3}; + std::vector edge_nodes{0, 3, 3, 1, 1, 0, 1, 2, 2, 0}; + + mesh2d.node_x = node_x.data(); + mesh2d.node_y = node_y.data(); + mesh2d.edge_nodes = edge_nodes.data(); + mesh2d.num_edges = static_cast(edge_nodes.size() * 0.5); + mesh2d.num_nodes = static_cast(node_x.size()); + + // Get the meshkernel id + auto const meshKernelId = GetMeshKernelId(); + double const smallFlowEdgesThreshold = 100.0; + meshkernelapi::GeometryList result{}; + + auto errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result); + ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); + + // Execute + errorCode = mkernel_mesh2d_set(meshKernelId, mesh2d); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); + int numSmallFlowEdges; + errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges); + + // Assert + std::vector coordinates_x(numSmallFlowEdges); + std::vector coordinates_y(numSmallFlowEdges); + result.coordinates_x = coordinates_x.data(); + result.coordinates_y = coordinates_y.data(); + result.num_coordinates = numSmallFlowEdges; + + errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); + + // Cache has been deleted + errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result); + ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); + + // Re-cache values + errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); + + // Get values with different set of options + errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, 2.0 * smallFlowEdgesThreshold, result); + ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); + + // Re-cache values + errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); + // Attempt at getting the size again will cause an error + errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges); + ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); +} + TEST_F(CartesianApiTestFixture, CountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ShouldCountObtuseTriangles) { // Prepare a mesh with one obtuse triangle From 216d248ccc25155d10ff2f0c71267e2365bb0cd2 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Mon, 21 Oct 2024 15:34:12 +0200 Subject: [PATCH 11/17] GRIDEDIT-1336 Added cache for hanging edges --- libs/MeshKernelApi/CMakeLists.txt | 4 +++ .../MeshKernelApi/NodeInPolygonCache.hpp | 17 ++--------- .../include/MeshKernelApi/State.hpp | 2 ++ libs/MeshKernelApi/src/MeshKernel.cpp | 19 +++++++++--- libs/MeshKernelApi/src/NodeInPolygonCache.cpp | 19 ++++-------- libs/MeshKernelApi/tests/src/ApiTest.cpp | 30 +++++++++++++++++++ 6 files changed, 58 insertions(+), 33 deletions(-) diff --git a/libs/MeshKernelApi/CMakeLists.txt b/libs/MeshKernelApi/CMakeLists.txt index c23cab058..78374792f 100644 --- a/libs/MeshKernelApi/CMakeLists.txt +++ b/libs/MeshKernelApi/CMakeLists.txt @@ -22,8 +22,10 @@ set(VERSION_INC_DIR ${CMAKE_SOURCE_DIR}/tools) # list of target sources set(SRC_LIST ${SRC_DIR}/BoundariesAsPolygonCache.cpp + ${SRC_DIR}/CachedIntegerValues.cpp ${SRC_DIR}/CachedPointValues.cpp ${SRC_DIR}/FacePolygonPropertyCache.cpp + ${SRC_DIR}/HangingEdgeCache.cpp ${SRC_DIR}/MKStateUndoAction.cpp ${SRC_DIR}/MeshKernel.cpp ${SRC_DIR}/NodeInPolygonCache.cpp @@ -36,12 +38,14 @@ set( INC_LIST ${DOMAIN_INC_DIR}/BoundariesAsPolygonCache.hpp ${DOMAIN_INC_DIR}/BoundingBox.hpp + ${DOMAIN_INC_DIR}/CachedIntegerValues.hpp ${DOMAIN_INC_DIR}/CachedPointValues.hpp ${DOMAIN_INC_DIR}/Contacts.hpp ${DOMAIN_INC_DIR}/CurvilinearGrid.hpp ${DOMAIN_INC_DIR}/FacePolygonPropertyCache.hpp ${DOMAIN_INC_DIR}/GeometryList.hpp ${DOMAIN_INC_DIR}/GriddedSamples.hpp + ${DOMAIN_INC_DIR}/HangingEdgeCache.hpp ${DOMAIN_INC_DIR}/MKStateUndoAction.hpp ${DOMAIN_INC_DIR}/Mesh1D.hpp ${DOMAIN_INC_DIR}/Mesh2D.hpp diff --git a/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp index bb4bfa185..c0c1fbfa5 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp @@ -32,13 +32,14 @@ #include "MeshKernel/Point.hpp" +#include "MeshKernelApi/CachedIntegerValues.hpp" #include "MeshKernelApi/GeometryList.hpp" namespace meshkernelapi { /// @brief Cache node indices contained in a polygon - class NodeInPolygonCache + class NodeInPolygonCache : public CachedIntegerValues { public: /// @brief Constructor @@ -49,26 +50,12 @@ namespace meshkernelapi /// @brief Determine if current options match those used to construct the object bool ValidOptions(const std::vector& polygonPoints, const int inside) const; - /// @brief Get the number of values being cached. - int Size() const; - - /// @brief Copy cached values to array - void Copy(int* selectedNodes) 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; - - /// @brief Indices of nodes in the polygon - std::vector m_nodeIndices; }; } // namespace meshkernelapi - -inline int meshkernelapi::NodeInPolygonCache::Size() const -{ - return static_cast(m_nodeIndices.size()); -} diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index 64e470509..55eac4ba0 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -41,6 +41,7 @@ #include "MeshKernelApi/BoundariesAsPolygonCache.hpp" #include "MeshKernelApi/CachedPointValues.hpp" #include "MeshKernelApi/FacePolygonPropertyCache.hpp" +#include "MeshKernelApi/HangingEdgeCache.hpp" #include "MeshKernelApi/NodeInPolygonCache.hpp" #include "MeshKernelApi/PolygonRefinementCache.hpp" #include "MeshKernelApi/SmallFlowEdgeCentreCache.hpp" @@ -87,6 +88,7 @@ namespace meshkernelapi std::shared_ptr m_polygonRefinementCache; ///< Cache for polygon refinement std::shared_ptr m_nodeInPolygonCache; ///< Cache for node in polygon std::shared_ptr m_smallFlowEdgeCentreCache; ///< Cache for small flow edge centres + std::shared_ptr m_hangingEdgeCache; ///< Cache for hanging edge ids }; } // namespace meshkernelapi diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index 6f1879671..ab98d18b7 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -1173,9 +1173,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 (...) { @@ -1193,11 +1201,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 (...) { diff --git a/libs/MeshKernelApi/src/NodeInPolygonCache.cpp b/libs/MeshKernelApi/src/NodeInPolygonCache.cpp index d8e74d70d..df5564af4 100644 --- a/libs/MeshKernelApi/src/NodeInPolygonCache.cpp +++ b/libs/MeshKernelApi/src/NodeInPolygonCache.cpp @@ -38,16 +38,19 @@ meshkernelapi::NodeInPolygonCache::NodeInPolygonCache(const std::vector& no const int inside) : m_polygonPoints(polygonPoints), m_inside(inside) { + std::vector nodeIndices; - m_nodeIndices.reserve(m_polygonPoints.size()); + nodeIndices.reserve(m_polygonPoints.size()); for (size_t i = 0; i < nodeMask.size(); ++i) { if (nodeMask[i] > 0) { - m_nodeIndices.push_back(static_cast(i)); + nodeIndices.push_back(static_cast(i)); } } + + Reset(std::move(nodeIndices)); } bool meshkernelapi::NodeInPolygonCache::ValidOptions(const std::vector& polygonPoints, const int inside) const @@ -56,15 +59,3 @@ bool meshkernelapi::NodeInPolygonCache::ValidOptions(const 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); +} + TEST_F(CartesianApiTestFixture, DeleteHangingEdgesMesh2D_WithOneHangingEdges_ShouldDeleteOneHangingEdges) { // Prepare From 269fa62189141693faaea6d67fb7fb1a7e3fe305 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Mon, 21 Oct 2024 16:04:54 +0200 Subject: [PATCH 12/17] GRIDEDIT-1336 Added cache for obtuse triangles and some files missing in last commit --- libs/MeshKernelApi/CMakeLists.txt | 2 + .../MeshKernelApi/CachedIntegerValues.hpp | 64 +++++++++++++++++++ .../MeshKernelApi/HangingEdgeCache.hpp | 48 ++++++++++++++ .../ObtuseTriangleCentreCache.hpp | 48 ++++++++++++++ .../include/MeshKernelApi/State.hpp | 14 ++-- .../MeshKernelApi/src/CachedIntegerValues.cpp | 46 +++++++++++++ libs/MeshKernelApi/src/HangingEdgeCache.cpp | 46 +++++++++++++ libs/MeshKernelApi/src/MeshKernel.cpp | 17 ++++- .../src/ObtuseTriangleCentreCache.cpp | 31 +++++++++ libs/MeshKernelApi/tests/src/ApiTest.cpp | 61 ++++++++++++++++++ 10 files changed, 368 insertions(+), 9 deletions(-) create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/CachedIntegerValues.hpp create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/HangingEdgeCache.hpp create mode 100644 libs/MeshKernelApi/include/MeshKernelApi/ObtuseTriangleCentreCache.hpp create mode 100644 libs/MeshKernelApi/src/CachedIntegerValues.cpp create mode 100644 libs/MeshKernelApi/src/HangingEdgeCache.cpp create mode 100644 libs/MeshKernelApi/src/ObtuseTriangleCentreCache.cpp diff --git a/libs/MeshKernelApi/CMakeLists.txt b/libs/MeshKernelApi/CMakeLists.txt index 78374792f..554d97868 100644 --- a/libs/MeshKernelApi/CMakeLists.txt +++ b/libs/MeshKernelApi/CMakeLists.txt @@ -29,6 +29,7 @@ set(SRC_LIST ${SRC_DIR}/MKStateUndoAction.cpp ${SRC_DIR}/MeshKernel.cpp ${SRC_DIR}/NodeInPolygonCache.cpp + ${SRC_DIR}/ObtuseTriangleCentreCache.cpp ${SRC_DIR}/PolygonRefinementCache.cpp ${SRC_DIR}/SmallFlowEdgeCentreCache.cpp ) @@ -51,6 +52,7 @@ set( ${DOMAIN_INC_DIR}/Mesh2D.hpp ${DOMAIN_INC_DIR}/MeshKernel.hpp ${DOMAIN_INC_DIR}/NodeInPolygonCache.hpp + ${DOMAIN_INC_DIR}/ObtuseTriangleCentreCache.hpp ${DOMAIN_INC_DIR}/PolygonRefinementCache.hpp ${DOMAIN_INC_DIR}/SmallFlowEdgeCentreCache.hpp ${DOMAIN_INC_DIR}/State.hpp diff --git a/libs/MeshKernelApi/include/MeshKernelApi/CachedIntegerValues.hpp b/libs/MeshKernelApi/include/MeshKernelApi/CachedIntegerValues.hpp new file mode 100644 index 000000000..daa887f05 --- /dev/null +++ b/libs/MeshKernelApi/include/MeshKernelApi/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/HangingEdgeCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/HangingEdgeCache.hpp new file mode 100644 index 000000000..b8090f802 --- /dev/null +++ b/libs/MeshKernelApi/include/MeshKernelApi/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/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/ObtuseTriangleCentreCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ObtuseTriangleCentreCache.hpp new file mode 100644 index 000000000..6b6c174c8 --- /dev/null +++ b/libs/MeshKernelApi/include/MeshKernelApi/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/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/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index 55eac4ba0..b9078f612 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -43,6 +43,7 @@ #include "MeshKernelApi/FacePolygonPropertyCache.hpp" #include "MeshKernelApi/HangingEdgeCache.hpp" #include "MeshKernelApi/NodeInPolygonCache.hpp" +#include "MeshKernelApi/ObtuseTriangleCentreCache.hpp" #include "MeshKernelApi/PolygonRefinementCache.hpp" #include "MeshKernelApi/SmallFlowEdgeCentreCache.hpp" @@ -83,12 +84,13 @@ namespace meshkernelapi meshkernel::Projection m_projection{meshkernel::Projection::cartesian}; ///< Projection used by the meshes // Cached values, used when dimensions are computed first, followed by values beign retrieved in a separate call - std::shared_ptr m_facePropertyCache; ///< Cache for - std::shared_ptr m_boundariesAsPolygonCache; ///< Cache - std::shared_ptr m_polygonRefinementCache; ///< Cache for polygon refinement - std::shared_ptr m_nodeInPolygonCache; ///< Cache for node in polygon - std::shared_ptr m_smallFlowEdgeCentreCache; ///< Cache for small flow edge centres - std::shared_ptr m_hangingEdgeCache; ///< Cache for hanging edge ids + std::shared_ptr m_facePropertyCache; ///< Cache for + std::shared_ptr m_boundariesAsPolygonCache; ///< Cache + std::shared_ptr m_polygonRefinementCache; ///< Cache for polygon refinement + std::shared_ptr m_nodeInPolygonCache; ///< Cache for node in polygon + std::shared_ptr m_smallFlowEdgeCentreCache; ///< Cache for small flow edge centres + std::shared_ptr m_hangingEdgeCache; ///< Cache for hanging edge ids + std::shared_ptr m_obtuseTriangleCentreCache; ///< Cache for the centre of obtuse triangles }; } // namespace meshkernelapi diff --git a/libs/MeshKernelApi/src/CachedIntegerValues.cpp b/libs/MeshKernelApi/src/CachedIntegerValues.cpp new file mode 100644 index 000000000..2a61c9b9a --- /dev/null +++ b/libs/MeshKernelApi/src/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/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/HangingEdgeCache.cpp b/libs/MeshKernelApi/src/HangingEdgeCache.cpp new file mode 100644 index 000000000..23b88f11c --- /dev/null +++ b/libs/MeshKernelApi/src/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/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/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index ab98d18b7..28a398501 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -3591,9 +3591,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 (...) { @@ -3612,9 +3619,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/src/ObtuseTriangleCentreCache.cpp b/libs/MeshKernelApi/src/ObtuseTriangleCentreCache.cpp new file mode 100644 index 000000000..ec065d682 --- /dev/null +++ b/libs/MeshKernelApi/src/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/ObtuseTriangleCentreCache.hpp" + +meshkernelapi::ObtuseTriangleCentreCache::ObtuseTriangleCentreCache(const std::vector& triangleCentres) + : CachedPointValues(triangleCentres) {} diff --git a/libs/MeshKernelApi/tests/src/ApiTest.cpp b/libs/MeshKernelApi/tests/src/ApiTest.cpp index d19c5f882..acf8fbeee 100644 --- a/libs/MeshKernelApi/tests/src/ApiTest.cpp +++ b/libs/MeshKernelApi/tests/src/ApiTest.cpp @@ -1873,6 +1873,67 @@ 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, CountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ObtuseTrianglesFailures) +{ + // Prepare a mesh with one obtuse triangle + 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()); + auto const meshKernelId = GetMeshKernelId(); + + // Execute + auto 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); } TEST_F(CartesianApiTestFixture, Mesh2DCountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ShouldGetObtuseTriangle) From 91a701110cda0d6ea57c300e0cab691032d6b8a0 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Mon, 21 Oct 2024 16:38:40 +0200 Subject: [PATCH 13/17] GRIDEDIT-1336 Small change to doxygen comment --- libs/MeshKernelApi/include/MeshKernelApi/State.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index b9078f612..e7c468dbf 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -84,13 +84,13 @@ namespace meshkernelapi meshkernel::Projection m_projection{meshkernel::Projection::cartesian}; ///< Projection used by the meshes // Cached values, used when dimensions are computed first, followed by values beign retrieved in a separate call - std::shared_ptr m_facePropertyCache; ///< Cache for - std::shared_ptr m_boundariesAsPolygonCache; ///< Cache - std::shared_ptr m_polygonRefinementCache; ///< Cache for polygon refinement - std::shared_ptr m_nodeInPolygonCache; ///< Cache for node in polygon - std::shared_ptr m_smallFlowEdgeCentreCache; ///< Cache for small flow edge centres - std::shared_ptr m_hangingEdgeCache; ///< Cache for hanging edge ids - std::shared_ptr m_obtuseTriangleCentreCache; ///< Cache for the centre of obtuse triangles + 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 From 2b8b2104cac8186d1e55a924f4eed6b8c6029f77 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Mon, 21 Oct 2024 17:03:40 +0200 Subject: [PATCH 14/17] GRIDEDIT-1336 Corrected spelling in doxygen comment --- libs/MeshKernelApi/include/MeshKernelApi/State.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index e7c468dbf..b10f67aa3 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -83,7 +83,7 @@ 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 beign retrieved in a separate call + // 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 From d2292feee56c096c2cedb1d7c39218373b0b9f4d Mon Sep 17 00:00:00 2001 From: BillSenior Date: Wed, 30 Oct 2024 15:51:26 +0100 Subject: [PATCH 15/17] GRIDEDIT-1336 Moved cache classes to sub directory --- libs/MeshKernelApi/CMakeLists.txt | 57 ++++++++++++------- .../BoundariesAsPolygonCache.hpp | 2 +- .../{ => ApiCache}/CachedIntegerValues.hpp | 0 .../{ => ApiCache}/CachedPointValues.hpp | 0 .../FacePolygonPropertyCache.hpp | 2 +- .../{ => ApiCache}/HangingEdgeCache.hpp | 2 +- .../{ => ApiCache}/NodeInPolygonCache.hpp | 2 +- .../ObtuseTriangleCentreCache.hpp | 2 +- .../{ => ApiCache}/PolygonRefinementCache.hpp | 2 +- .../SmallFlowEdgeCentreCache.hpp | 2 +- .../include/MeshKernelApi/State.hpp | 16 +++--- .../BoundariesAsPolygonCache.cpp | 2 +- .../{ => ApiCache}/CachedIntegerValues.cpp | 2 +- .../src/{ => ApiCache}/CachedPointValues.cpp | 2 +- .../FacePolygonPropertyCache.cpp | 2 +- .../src/{ => ApiCache}/HangingEdgeCache.cpp | 2 +- .../src/{ => ApiCache}/NodeInPolygonCache.cpp | 2 +- .../ObtuseTriangleCentreCache.cpp | 2 +- .../{ => ApiCache}/PolygonRefinementCache.cpp | 29 +++++++++- .../SmallFlowEdgeCentreCache.cpp | 2 +- libs/MeshKernelApi/src/MeshKernel.cpp | 13 +++-- 21 files changed, 94 insertions(+), 51 deletions(-) rename libs/MeshKernelApi/include/MeshKernelApi/{ => ApiCache}/BoundariesAsPolygonCache.hpp (97%) rename libs/MeshKernelApi/include/MeshKernelApi/{ => ApiCache}/CachedIntegerValues.hpp (100%) rename libs/MeshKernelApi/include/MeshKernelApi/{ => ApiCache}/CachedPointValues.hpp (100%) rename libs/MeshKernelApi/include/MeshKernelApi/{ => ApiCache}/FacePolygonPropertyCache.hpp (97%) rename libs/MeshKernelApi/include/MeshKernelApi/{ => ApiCache}/HangingEdgeCache.hpp (96%) rename libs/MeshKernelApi/include/MeshKernelApi/{ => ApiCache}/NodeInPolygonCache.hpp (97%) rename libs/MeshKernelApi/include/MeshKernelApi/{ => ApiCache}/ObtuseTriangleCentreCache.hpp (96%) rename libs/MeshKernelApi/include/MeshKernelApi/{ => ApiCache}/PolygonRefinementCache.hpp (97%) rename libs/MeshKernelApi/include/MeshKernelApi/{ => ApiCache}/SmallFlowEdgeCentreCache.hpp (97%) rename libs/MeshKernelApi/src/{ => ApiCache}/BoundariesAsPolygonCache.cpp (97%) rename libs/MeshKernelApi/src/{ => ApiCache}/CachedIntegerValues.cpp (96%) rename libs/MeshKernelApi/src/{ => ApiCache}/CachedPointValues.cpp (97%) rename libs/MeshKernelApi/src/{ => ApiCache}/FacePolygonPropertyCache.cpp (97%) rename libs/MeshKernelApi/src/{ => ApiCache}/HangingEdgeCache.cpp (96%) rename libs/MeshKernelApi/src/{ => ApiCache}/NodeInPolygonCache.cpp (97%) rename libs/MeshKernelApi/src/{ => ApiCache}/ObtuseTriangleCentreCache.cpp (95%) rename libs/MeshKernelApi/src/{ => ApiCache}/PolygonRefinementCache.cpp (52%) rename libs/MeshKernelApi/src/{ => ApiCache}/SmallFlowEdgeCentreCache.cpp (96%) diff --git a/libs/MeshKernelApi/CMakeLists.txt b/libs/MeshKernelApi/CMakeLists.txt index 554d97868..9a605c463 100644 --- a/libs/MeshKernelApi/CMakeLists.txt +++ b/libs/MeshKernelApi/CMakeLists.txt @@ -13,64 +13,77 @@ 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 set(SRC_LIST - ${SRC_DIR}/BoundariesAsPolygonCache.cpp - ${SRC_DIR}/CachedIntegerValues.cpp - ${SRC_DIR}/CachedPointValues.cpp - ${SRC_DIR}/FacePolygonPropertyCache.cpp - ${SRC_DIR}/HangingEdgeCache.cpp ${SRC_DIR}/MKStateUndoAction.cpp ${SRC_DIR}/MeshKernel.cpp - ${SRC_DIR}/NodeInPolygonCache.cpp - ${SRC_DIR}/ObtuseTriangleCentreCache.cpp - ${SRC_DIR}/PolygonRefinementCache.cpp - ${SRC_DIR}/SmallFlowEdgeCentreCache.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 - ${DOMAIN_INC_DIR}/BoundariesAsPolygonCache.hpp ${DOMAIN_INC_DIR}/BoundingBox.hpp - ${DOMAIN_INC_DIR}/CachedIntegerValues.hpp - ${DOMAIN_INC_DIR}/CachedPointValues.hpp ${DOMAIN_INC_DIR}/Contacts.hpp ${DOMAIN_INC_DIR}/CurvilinearGrid.hpp - ${DOMAIN_INC_DIR}/FacePolygonPropertyCache.hpp ${DOMAIN_INC_DIR}/GeometryList.hpp ${DOMAIN_INC_DIR}/GriddedSamples.hpp - ${DOMAIN_INC_DIR}/HangingEdgeCache.hpp ${DOMAIN_INC_DIR}/MKStateUndoAction.hpp ${DOMAIN_INC_DIR}/Mesh1D.hpp ${DOMAIN_INC_DIR}/Mesh2D.hpp ${DOMAIN_INC_DIR}/MeshKernel.hpp - ${DOMAIN_INC_DIR}/NodeInPolygonCache.hpp - ${DOMAIN_INC_DIR}/ObtuseTriangleCentreCache.hpp - ${DOMAIN_INC_DIR}/PolygonRefinementCache.hpp - ${DOMAIN_INC_DIR}/SmallFlowEdgeCentreCache.hpp ${DOMAIN_INC_DIR}/State.hpp ${DOMAIN_INC_DIR}/Utils.hpp ${VERSION_INC_DIR}/Version/Version.hpp ) +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 @@ -106,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/BoundariesAsPolygonCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp similarity index 97% rename from libs/MeshKernelApi/include/MeshKernelApi/BoundariesAsPolygonCache.hpp rename to libs/MeshKernelApi/include/MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp index 8020babd0..f6d424139 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/BoundariesAsPolygonCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp @@ -32,7 +32,7 @@ #include #include -#include "MeshKernelApi/CachedPointValues.hpp" +#include "MeshKernelApi/ApiCache/CachedPointValues.hpp" #include "MeshKernelApi/GeometryList.hpp" #include "MeshKernelApi/Utils.hpp" diff --git a/libs/MeshKernelApi/include/MeshKernelApi/CachedIntegerValues.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedIntegerValues.hpp similarity index 100% rename from libs/MeshKernelApi/include/MeshKernelApi/CachedIntegerValues.hpp rename to libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedIntegerValues.hpp diff --git a/libs/MeshKernelApi/include/MeshKernelApi/CachedPointValues.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedPointValues.hpp similarity index 100% rename from libs/MeshKernelApi/include/MeshKernelApi/CachedPointValues.hpp rename to libs/MeshKernelApi/include/MeshKernelApi/ApiCache/CachedPointValues.hpp diff --git a/libs/MeshKernelApi/include/MeshKernelApi/FacePolygonPropertyCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp similarity index 97% rename from libs/MeshKernelApi/include/MeshKernelApi/FacePolygonPropertyCache.hpp rename to libs/MeshKernelApi/include/MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp index 699126482..e0ecf2e15 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/FacePolygonPropertyCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp @@ -31,7 +31,7 @@ #include "MeshKernel/Mesh2D.hpp" -#include "MeshKernelApi/CachedPointValues.hpp" +#include "MeshKernelApi/ApiCache/CachedPointValues.hpp" namespace meshkernelapi { diff --git a/libs/MeshKernelApi/include/MeshKernelApi/HangingEdgeCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/HangingEdgeCache.hpp similarity index 96% rename from libs/MeshKernelApi/include/MeshKernelApi/HangingEdgeCache.hpp rename to libs/MeshKernelApi/include/MeshKernelApi/ApiCache/HangingEdgeCache.hpp index b8090f802..0e00e9536 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/HangingEdgeCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/HangingEdgeCache.hpp @@ -32,7 +32,7 @@ #include "MeshKernel/Point.hpp" -#include "MeshKernelApi/CachedIntegerValues.hpp" +#include "MeshKernelApi/ApiCache/CachedIntegerValues.hpp" namespace meshkernelapi { diff --git a/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/NodeInPolygonCache.hpp similarity index 97% rename from libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp rename to libs/MeshKernelApi/include/MeshKernelApi/ApiCache/NodeInPolygonCache.hpp index c0c1fbfa5..0303238ba 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/NodeInPolygonCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/NodeInPolygonCache.hpp @@ -32,7 +32,7 @@ #include "MeshKernel/Point.hpp" -#include "MeshKernelApi/CachedIntegerValues.hpp" +#include "MeshKernelApi/ApiCache/CachedIntegerValues.hpp" #include "MeshKernelApi/GeometryList.hpp" namespace meshkernelapi diff --git a/libs/MeshKernelApi/include/MeshKernelApi/ObtuseTriangleCentreCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/ObtuseTriangleCentreCache.hpp similarity index 96% rename from libs/MeshKernelApi/include/MeshKernelApi/ObtuseTriangleCentreCache.hpp rename to libs/MeshKernelApi/include/MeshKernelApi/ApiCache/ObtuseTriangleCentreCache.hpp index 6b6c174c8..90b004f22 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/ObtuseTriangleCentreCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/ObtuseTriangleCentreCache.hpp @@ -32,7 +32,7 @@ #include "MeshKernel/Point.hpp" -#include "MeshKernelApi/CachedPointValues.hpp" +#include "MeshKernelApi/ApiCache/CachedPointValues.hpp" namespace meshkernelapi { diff --git a/libs/MeshKernelApi/include/MeshKernelApi/PolygonRefinementCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/PolygonRefinementCache.hpp similarity index 97% rename from libs/MeshKernelApi/include/MeshKernelApi/PolygonRefinementCache.hpp rename to libs/MeshKernelApi/include/MeshKernelApi/ApiCache/PolygonRefinementCache.hpp index 4d24ec463..20067c07b 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/PolygonRefinementCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/PolygonRefinementCache.hpp @@ -29,7 +29,7 @@ #include -#include "MeshKernelApi/CachedPointValues.hpp" +#include "MeshKernelApi/ApiCache/CachedPointValues.hpp" namespace meshkernelapi { diff --git a/libs/MeshKernelApi/include/MeshKernelApi/SmallFlowEdgeCentreCache.hpp b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/SmallFlowEdgeCentreCache.hpp similarity index 97% rename from libs/MeshKernelApi/include/MeshKernelApi/SmallFlowEdgeCentreCache.hpp rename to libs/MeshKernelApi/include/MeshKernelApi/ApiCache/SmallFlowEdgeCentreCache.hpp index f5e9b9fcf..de19e3e4d 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/SmallFlowEdgeCentreCache.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/ApiCache/SmallFlowEdgeCentreCache.hpp @@ -32,7 +32,7 @@ #include "MeshKernel/Point.hpp" -#include "MeshKernelApi/CachedPointValues.hpp" +#include "MeshKernelApi/ApiCache/CachedPointValues.hpp" #include "MeshKernelApi/GeometryList.hpp" namespace meshkernelapi diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index b10f67aa3..d662b132e 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -38,14 +38,14 @@ #include #include -#include "MeshKernelApi/BoundariesAsPolygonCache.hpp" -#include "MeshKernelApi/CachedPointValues.hpp" -#include "MeshKernelApi/FacePolygonPropertyCache.hpp" -#include "MeshKernelApi/HangingEdgeCache.hpp" -#include "MeshKernelApi/NodeInPolygonCache.hpp" -#include "MeshKernelApi/ObtuseTriangleCentreCache.hpp" -#include "MeshKernelApi/PolygonRefinementCache.hpp" -#include "MeshKernelApi/SmallFlowEdgeCentreCache.hpp" +#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 { diff --git a/libs/MeshKernelApi/src/BoundariesAsPolygonCache.cpp b/libs/MeshKernelApi/src/ApiCache/BoundariesAsPolygonCache.cpp similarity index 97% rename from libs/MeshKernelApi/src/BoundariesAsPolygonCache.cpp rename to libs/MeshKernelApi/src/ApiCache/BoundariesAsPolygonCache.cpp index 900a25c64..8df414cfd 100644 --- a/libs/MeshKernelApi/src/BoundariesAsPolygonCache.cpp +++ b/libs/MeshKernelApi/src/ApiCache/BoundariesAsPolygonCache.cpp @@ -25,7 +25,7 @@ // //------------------------------------------------------------------------------ -#include "MeshKernelApi/BoundariesAsPolygonCache.hpp" +#include "MeshKernelApi/ApiCache/BoundariesAsPolygonCache.hpp" meshkernelapi::BoundariesAsPolygonCache::BoundariesAsPolygonCache(const int lowerLeftN, const int lowerLeftM, diff --git a/libs/MeshKernelApi/src/CachedIntegerValues.cpp b/libs/MeshKernelApi/src/ApiCache/CachedIntegerValues.cpp similarity index 96% rename from libs/MeshKernelApi/src/CachedIntegerValues.cpp rename to libs/MeshKernelApi/src/ApiCache/CachedIntegerValues.cpp index 2a61c9b9a..444f96327 100644 --- a/libs/MeshKernelApi/src/CachedIntegerValues.cpp +++ b/libs/MeshKernelApi/src/ApiCache/CachedIntegerValues.cpp @@ -28,7 +28,7 @@ #include #include -#include "MeshKernelApi/CachedIntegerValues.hpp" +#include "MeshKernelApi/ApiCache/CachedIntegerValues.hpp" meshkernelapi::CachedIntegerValues::CachedIntegerValues(const std::vector& values) : m_values(values) {} diff --git a/libs/MeshKernelApi/src/CachedPointValues.cpp b/libs/MeshKernelApi/src/ApiCache/CachedPointValues.cpp similarity index 97% rename from libs/MeshKernelApi/src/CachedPointValues.cpp rename to libs/MeshKernelApi/src/ApiCache/CachedPointValues.cpp index 186b71d74..8354518df 100644 --- a/libs/MeshKernelApi/src/CachedPointValues.cpp +++ b/libs/MeshKernelApi/src/ApiCache/CachedPointValues.cpp @@ -28,7 +28,7 @@ #include #include -#include "MeshKernelApi/CachedPointValues.hpp" +#include "MeshKernelApi/ApiCache/CachedPointValues.hpp" meshkernelapi::CachedPointValues::CachedPointValues(const std::vector& coordinates) : m_coordsX(coordinates.size()), diff --git a/libs/MeshKernelApi/src/FacePolygonPropertyCache.cpp b/libs/MeshKernelApi/src/ApiCache/FacePolygonPropertyCache.cpp similarity index 97% rename from libs/MeshKernelApi/src/FacePolygonPropertyCache.cpp rename to libs/MeshKernelApi/src/ApiCache/FacePolygonPropertyCache.cpp index dda3ec840..8d9b31201 100644 --- a/libs/MeshKernelApi/src/FacePolygonPropertyCache.cpp +++ b/libs/MeshKernelApi/src/ApiCache/FacePolygonPropertyCache.cpp @@ -27,7 +27,7 @@ #include -#include "MeshKernelApi/FacePolygonPropertyCache.hpp" +#include "MeshKernelApi/ApiCache/FacePolygonPropertyCache.hpp" #include "MeshKernelApi/Utils.hpp" meshkernelapi::FacePolygonPropertyCache::FacePolygonPropertyCache(const int propertyValue, diff --git a/libs/MeshKernelApi/src/HangingEdgeCache.cpp b/libs/MeshKernelApi/src/ApiCache/HangingEdgeCache.cpp similarity index 96% rename from libs/MeshKernelApi/src/HangingEdgeCache.cpp rename to libs/MeshKernelApi/src/ApiCache/HangingEdgeCache.cpp index 23b88f11c..0b0a09771 100644 --- a/libs/MeshKernelApi/src/HangingEdgeCache.cpp +++ b/libs/MeshKernelApi/src/ApiCache/HangingEdgeCache.cpp @@ -31,7 +31,7 @@ #include "MeshKernel/Exceptions.hpp" -#include "MeshKernelApi/HangingEdgeCache.hpp" +#include "MeshKernelApi/ApiCache/HangingEdgeCache.hpp" meshkernelapi::HangingEdgeCache::HangingEdgeCache(const std::vector& edgeId) { diff --git a/libs/MeshKernelApi/src/NodeInPolygonCache.cpp b/libs/MeshKernelApi/src/ApiCache/NodeInPolygonCache.cpp similarity index 97% rename from libs/MeshKernelApi/src/NodeInPolygonCache.cpp rename to libs/MeshKernelApi/src/ApiCache/NodeInPolygonCache.cpp index df5564af4..5c572b463 100644 --- a/libs/MeshKernelApi/src/NodeInPolygonCache.cpp +++ b/libs/MeshKernelApi/src/ApiCache/NodeInPolygonCache.cpp @@ -31,7 +31,7 @@ #include "MeshKernel/Exceptions.hpp" -#include "MeshKernelApi/NodeInPolygonCache.hpp" +#include "MeshKernelApi/ApiCache/NodeInPolygonCache.hpp" meshkernelapi::NodeInPolygonCache::NodeInPolygonCache(const std::vector& nodeMask, const std::vector& polygonPoints, diff --git a/libs/MeshKernelApi/src/ObtuseTriangleCentreCache.cpp b/libs/MeshKernelApi/src/ApiCache/ObtuseTriangleCentreCache.cpp similarity index 95% rename from libs/MeshKernelApi/src/ObtuseTriangleCentreCache.cpp rename to libs/MeshKernelApi/src/ApiCache/ObtuseTriangleCentreCache.cpp index ec065d682..5f8f3c1f6 100644 --- a/libs/MeshKernelApi/src/ObtuseTriangleCentreCache.cpp +++ b/libs/MeshKernelApi/src/ApiCache/ObtuseTriangleCentreCache.cpp @@ -25,7 +25,7 @@ // //------------------------------------------------------------------------------ -#include "MeshKernelApi/ObtuseTriangleCentreCache.hpp" +#include "MeshKernelApi/ApiCache/ObtuseTriangleCentreCache.hpp" meshkernelapi::ObtuseTriangleCentreCache::ObtuseTriangleCentreCache(const std::vector& triangleCentres) : CachedPointValues(triangleCentres) {} diff --git a/libs/MeshKernelApi/src/PolygonRefinementCache.cpp b/libs/MeshKernelApi/src/ApiCache/PolygonRefinementCache.cpp similarity index 52% rename from libs/MeshKernelApi/src/PolygonRefinementCache.cpp rename to libs/MeshKernelApi/src/ApiCache/PolygonRefinementCache.cpp index e61015a6e..d01a88d95 100644 --- a/libs/MeshKernelApi/src/PolygonRefinementCache.cpp +++ b/libs/MeshKernelApi/src/ApiCache/PolygonRefinementCache.cpp @@ -1,4 +1,31 @@ -#include "MeshKernelApi/PolygonRefinementCache.hpp" +//---- 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, diff --git a/libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp b/libs/MeshKernelApi/src/ApiCache/SmallFlowEdgeCentreCache.cpp similarity index 96% rename from libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp rename to libs/MeshKernelApi/src/ApiCache/SmallFlowEdgeCentreCache.cpp index 4ee8fc9fa..7ab932225 100644 --- a/libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp +++ b/libs/MeshKernelApi/src/ApiCache/SmallFlowEdgeCentreCache.cpp @@ -25,7 +25,7 @@ // //------------------------------------------------------------------------------ -#include "MeshKernelApi/SmallFlowEdgeCentreCache.hpp" +#include "MeshKernelApi/ApiCache/SmallFlowEdgeCentreCache.hpp" meshkernelapi::SmallFlowEdgeCentreCache::SmallFlowEdgeCentreCache(const double lengthThreshold, const std::vector& edgeCentres) diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index 28a398501..8ab7ddb82 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -89,13 +89,16 @@ #include #include -#include "MeshKernelApi/BoundariesAsPolygonCache.hpp" -#include "MeshKernelApi/CachedPointValues.hpp" -#include "MeshKernelApi/FacePolygonPropertyCache.hpp" +#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/NodeInPolygonCache.hpp" -#include "MeshKernelApi/PolygonRefinementCache.hpp" #include "MeshKernelApi/State.hpp" #include "MeshKernelApi/Utils.hpp" From 16887b61bbda01abb5f41eb67b72678a54bebf37 Mon Sep 17 00:00:00 2001 From: BillSenior Date: Wed, 30 Oct 2024 17:34:13 +0100 Subject: [PATCH 16/17] GRIDEDIT-1336 Changes from review Added comment indicating that a caching function must be called before getting the results of the cache Moved some api tests to a separate file. --- libs/MeshKernelApi/src/MeshKernel.cpp | 14 +- libs/MeshKernelApi/tests/CMakeLists.txt | 1 + libs/MeshKernelApi/tests/src/ApiCacheTest.cpp | 255 ++++++++++++++++++ libs/MeshKernelApi/tests/src/ApiTest.cpp | 186 ------------- 4 files changed, 263 insertions(+), 193 deletions(-) create mode 100644 libs/MeshKernelApi/tests/src/ApiCacheTest.cpp diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index 8ab7ddb82..4b4cb5111 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -955,7 +955,7 @@ namespace meshkernelapi if (meshKernelState[meshKernelId].m_boundariesAsPolygonCache == nullptr) { - throw meshkernel::MeshKernelError("Polygon data has not been cached"); + throw meshkernel::MeshKernelError("Polygon data has not been cached, mkernel_curvilinear_count_boundaries_as_polygons must be called before"); } if (!meshKernelState[meshKernelId].m_boundariesAsPolygonCache->ValidOptions(lowerLeftN, lowerLeftM, upperRightN, upperRightM)) @@ -1003,7 +1003,7 @@ namespace meshkernelapi if (meshKernelState[meshKernelId].m_boundariesAsPolygonCache != nullptr) { meshKernelState[meshKernelId].m_boundariesAsPolygonCache.reset(); - throw meshkernel::MeshKernelError("Polygon data has already been cached, deleting cached data"); + throw meshkernel::MeshKernelError("Polygon data has already been cached, deleting cached data, "); } const auto lowerLeftNUnsigned = static_cast(lowerLeftN); @@ -1976,7 +1976,7 @@ namespace meshkernelapi if (meshKernelState[meshKernelId].m_polygonRefinementCache == nullptr) { - throw meshkernel::MeshKernelError("Polygon data has not been cached"); + throw meshkernel::MeshKernelError("Polygon data has not been cached, mkernel_polygon_count_refine must be called before"); } auto const polygonVector = ConvertGeometryListToPointVector(polygonToRefine); @@ -2014,7 +2014,7 @@ namespace meshkernelapi if (meshKernelState[meshKernelId].m_polygonRefinementCache == nullptr) { - throw meshkernel::MeshKernelError("Polygon data has not been cached"); + throw meshkernel::MeshKernelError("Polygon data has not been cached, mkernel_polygon_count_linear_refine must be called before"); } auto const polygonVector = ConvertGeometryListToPointVector(polygonToRefine); @@ -2195,7 +2195,7 @@ namespace meshkernelapi if (meshKernelState[meshKernelId].m_nodeInPolygonCache == nullptr) { - throw meshkernel::MeshKernelError("Node in polygon data has not been cached"); + throw meshkernel::MeshKernelError("Node in polygon data has not been cached, mkernel_mesh2d_count_nodes_in_polygons must be called before"); } auto const polygonVector = ConvertGeometryListToPointVector(geometryListIn); @@ -2638,7 +2638,7 @@ namespace meshkernelapi if (meshKernelState[meshKernelId].m_facePropertyCache == nullptr) { - throw meshkernel::ConstraintError("Filtered data has not been cached"); + 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)) @@ -3473,7 +3473,7 @@ namespace meshkernelapi if (meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache == nullptr) { - throw meshkernel::ConstraintError("Small flow edge data has not been cached"); + 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)) 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..d65d3a0a5 --- /dev/null +++ b/libs/MeshKernelApi/tests/src/ApiCacheTest.cpp @@ -0,0 +1,255 @@ +#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 acf8fbeee..c816b9fe1 100644 --- a/libs/MeshKernelApi/tests/src/ApiTest.cpp +++ b/libs/MeshKernelApi/tests/src/ApiTest.cpp @@ -1358,36 +1358,6 @@ TEST_F(CartesianApiTestFixture, GetHangingEdgesMesh2D_WithOneHangingEdges_Should ASSERT_EQ(hangingEdges[0], 9); } -TEST_F(CartesianApiTestFixture, GetHangingEdgesMesh2D_WithOneHangingEdges_GetOneHangingEdgesFailures) -{ - // Prepare - MakeMesh(); - auto const meshKernelId = GetMeshKernelId(); - - // delete an edge at the lower left corner to create a new hanging edge - auto 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); -} - TEST_F(CartesianApiTestFixture, DeleteHangingEdgesMesh2D_WithOneHangingEdges_ShouldDeleteOneHangingEdges) { // Prepare @@ -1562,53 +1532,6 @@ TEST_F(CartesianApiTestFixture, CountNodesInPolygonMesh2D_OnMesh2D_ShouldCountAl ASSERT_EQ(12, numNodes); } -TEST_F(CartesianApiTestFixture, GetNodesInPolygonMesh2D_OnMesh2D_NodeInPolygonFailures) -{ - // Prepare - MakeMesh(); - auto const meshKernelId = GetMeshKernelId(); - - // By using an empty list, all nodes will be selected - const meshkernelapi::GeometryList geometryListIn{}; - - meshkernelapi::Mesh2D mesh2d{}; - auto 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); -} - TEST_F(CartesianApiTestFixture, InsertNodeAndEdge_OnMesh2D_ShouldInsertNodeAndEdge) { // Prepare @@ -1791,65 +1714,6 @@ TEST_F(CartesianApiTestFixture, GetSmallFlowEdges_OnMesh2D_ShouldGetSmallFlowEdg ASSERT_NEAR(result.coordinates_y[0], 0.0, tolerance); } -TEST_F(CartesianApiTestFixture, GetSmallFlowEdges_OnMesh2D_GetSmallFlowEdgesFailures) -{ - // Prepare a mesh with two triangles - meshkernelapi::Mesh2D mesh2d; - - std::vector node_x{0.0, 1.0, 1.0, 1.0}; - std::vector node_y{0.0, 0.0, 0.3, -0.3}; - std::vector edge_nodes{0, 3, 3, 1, 1, 0, 1, 2, 2, 0}; - - mesh2d.node_x = node_x.data(); - mesh2d.node_y = node_y.data(); - mesh2d.edge_nodes = edge_nodes.data(); - mesh2d.num_edges = static_cast(edge_nodes.size() * 0.5); - mesh2d.num_nodes = static_cast(node_x.size()); - - // Get the meshkernel id - auto const meshKernelId = GetMeshKernelId(); - double const smallFlowEdgesThreshold = 100.0; - meshkernelapi::GeometryList result{}; - - auto errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result); - ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); - - // Execute - errorCode = mkernel_mesh2d_set(meshKernelId, mesh2d); - ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); - int numSmallFlowEdges; - errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges); - - // Assert - std::vector coordinates_x(numSmallFlowEdges); - std::vector coordinates_y(numSmallFlowEdges); - result.coordinates_x = coordinates_x.data(); - result.coordinates_y = coordinates_y.data(); - result.num_coordinates = numSmallFlowEdges; - - errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result); - ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); - - // Cache has been deleted - errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result); - ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); - - // Re-cache values - errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges); - ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); - - // Get values with different set of options - errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, 2.0 * smallFlowEdgesThreshold, result); - ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); - - // Re-cache values - errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges); - ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); - // Attempt at getting the size again will cause an error - errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges); - ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); -} - TEST_F(CartesianApiTestFixture, CountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ShouldCountObtuseTriangles) { // Prepare a mesh with one obtuse triangle @@ -1886,56 +1750,6 @@ TEST_F(CartesianApiTestFixture, CountObtuseTriangles_OnMesh2DWithOneObtuseTriang ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); } -TEST_F(CartesianApiTestFixture, CountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ObtuseTrianglesFailures) -{ - // Prepare a mesh with one obtuse triangle - 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()); - auto const meshKernelId = GetMeshKernelId(); - - // Execute - auto 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); -} - TEST_F(CartesianApiTestFixture, Mesh2DCountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ShouldGetObtuseTriangle) { // Prepare a mesh with one obtuse triangle From 82cfaf075736b78de66e8f0ffa8dde9ca57c266b Mon Sep 17 00:00:00 2001 From: BillSenior Date: Wed, 30 Oct 2024 17:47:14 +0100 Subject: [PATCH 17/17] GRIDEDIT-1336 Corrected clang formatting warnings --- libs/MeshKernelApi/src/MeshKernel.cpp | 2 +- libs/MeshKernelApi/tests/src/ApiCacheTest.cpp | 32 +++++++++---------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index 4b4cb5111..521a5552d 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -2195,7 +2195,7 @@ namespace meshkernelapi 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"); + throw meshkernel::MeshKernelError("Node in polygon data has not been cached, mkernel_mesh2d_count_nodes_in_polygons must be called before"); } auto const polygonVector = ConvertGeometryListToPointVector(geometryListIn); diff --git a/libs/MeshKernelApi/tests/src/ApiCacheTest.cpp b/libs/MeshKernelApi/tests/src/ApiCacheTest.cpp index d65d3a0a5..79e6d266d 100644 --- a/libs/MeshKernelApi/tests/src/ApiCacheTest.cpp +++ b/libs/MeshKernelApi/tests/src/ApiCacheTest.cpp @@ -23,19 +23,18 @@ 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; -} + // 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) { @@ -71,7 +70,7 @@ TEST(ApiCacheTest, GetHangingEdgesMesh2D_WithOneHangingEdges_GetOneHangingEdgesF errorCode = meshkernelapi::mkernel_mesh2d_get_hanging_edges(meshKernelId, hangingEdges.data()); ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode); - errorCode = meshkernelapi::mkernel_expunge_state (meshKernelId); + errorCode = meshkernelapi::mkernel_expunge_state(meshKernelId); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); } @@ -125,7 +124,7 @@ TEST(ApiCacheTest, GetNodesInPolygonMesh2D_OnMesh2D_NodeInPolygonFailures) errorCode = mkernel_mesh2d_get_nodes_in_polygons(meshKernelId, geometryListIn, 1, nullArray); ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode); - errorCode = meshkernelapi::mkernel_expunge_state (meshKernelId); + errorCode = meshkernelapi::mkernel_expunge_state(meshKernelId); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); } @@ -192,11 +191,10 @@ TEST(ApiCacheTest, GetSmallFlowEdges_OnMesh2D_GetSmallFlowEdgesFailures) errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges); ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode); - errorCode = meshkernelapi::mkernel_expunge_state (meshKernelId); + errorCode = meshkernelapi::mkernel_expunge_state(meshKernelId); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); } - TEST(ApiCacheTest, CountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ObtuseTrianglesFailures) { // Prepare a mesh with one obtuse triangle @@ -250,6 +248,6 @@ TEST(ApiCacheTest, CountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ObtuseTria errorCode = mkernel_mesh2d_get_obtuse_triangles_mass_centers(meshKernelId, geometryList); ASSERT_EQ(meshkernel::ExitCode::MeshKernelErrorCode, errorCode); - errorCode = meshkernelapi::mkernel_expunge_state (meshKernelId); + errorCode = meshkernelapi::mkernel_expunge_state(meshKernelId); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); }