diff --git a/libs/MeshKernel/include/MeshKernel/CurvilinearGrid/CurvilinearGridLineAttractionRepulsion.hpp b/libs/MeshKernel/include/MeshKernel/CurvilinearGrid/CurvilinearGridLineAttractionRepulsion.hpp index e2ea03f64..481bb14ad 100644 --- a/libs/MeshKernel/include/MeshKernel/CurvilinearGrid/CurvilinearGridLineAttractionRepulsion.hpp +++ b/libs/MeshKernel/include/MeshKernel/CurvilinearGrid/CurvilinearGridLineAttractionRepulsion.hpp @@ -38,7 +38,7 @@ namespace meshkernel /// @brief A class implementing the curvilinear grid line shift. Line is shifted on the new locations. /// and the displacement gets distributed on the influence zone, set with SetBlock /// - /// This option provides the possibility to fit the curvilinear grid’s edges to a land boundary. + /// This option provides the possibility to fit the curvilinear grid's edges to a land boundary. class CurvilinearGridLineAttractionRepulsion : public CurvilinearGridAlgorithm { public: diff --git a/libs/MeshKernel/include/MeshKernel/CurvilinearGrid/CurvilinearGridLineShift.hpp b/libs/MeshKernel/include/MeshKernel/CurvilinearGrid/CurvilinearGridLineShift.hpp index 6aaf1a736..9af796d3a 100644 --- a/libs/MeshKernel/include/MeshKernel/CurvilinearGrid/CurvilinearGridLineShift.hpp +++ b/libs/MeshKernel/include/MeshKernel/CurvilinearGrid/CurvilinearGridLineShift.hpp @@ -40,7 +40,7 @@ namespace meshkernel /// @brief A class implementing the curvilinear grid line shift. Line is shifted on the new locations. /// and the displacement gets distributed on the influence zone, set with SetBlock /// - /// This option provides the possibility to fit the curvilinear grid’s edges to a land boundary. + /// This option provides the possibility to fit the curvilinear grid's edges to a land boundary. class CurvilinearGridLineShift : public CurvilinearGridAlgorithm { public: diff --git a/libs/MeshKernel/src/CurvilinearGrid/CurvilinearGridSnapping.cpp b/libs/MeshKernel/src/CurvilinearGrid/CurvilinearGridSnapping.cpp index e08d88102..456d7c462 100644 --- a/libs/MeshKernel/src/CurvilinearGrid/CurvilinearGridSnapping.cpp +++ b/libs/MeshKernel/src/CurvilinearGrid/CurvilinearGridSnapping.cpp @@ -137,6 +137,7 @@ void meshkernel::CurvilinearGridSnapping::ApplyExpansionToGrid(const Curvilinear meshkernel::UndoActionPtr meshkernel::CurvilinearGridSnapping::Compute() { + // probably can reduce storage required. m_lineStartIndex.m_m and m_lineEndIndex std::unique_ptr undoAction = CurvilinearGridBlockUndoAction::Create(m_grid, {0, 0}, {m_grid.NumN(), m_grid.NumM()}); std::unique_ptr expansionCalculator = AllocateCurvilinearGridMeshExpansionCalculator(); diff --git a/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp b/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp index 589112497..f10c10568 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp @@ -69,21 +69,18 @@ namespace meshkernelapi MKERNEL_API int mkernel_allocate_state(int projectionType, int& meshKernelId); /// @brief Attempt to undo by one undo-action. - /// @param[in] meshKernelId The id of the mesh state. /// @param[out] undone Indicates if the undo action was actually undone /// @returns Error code - MKERNEL_API int mkernel_undo_state(int meshKernelId, bool& undone); + MKERNEL_API int mkernel_undo_state(bool& undone); /// @brief Attempt to redo by one undo-action. - /// @param[in] meshKernelId The id of the mesh state. /// @param[out] redone Indicates if the redo action was actually redone /// @returns Error code - MKERNEL_API int mkernel_redo_state(int meshKernelId, bool& redone); + MKERNEL_API int mkernel_redo_state(bool& redone); /// @brief Clear the undo state. - /// @param[in] meshKernelId The id of the mesh state. /// @returns Error code - MKERNEL_API int mkernel_clear_undo_state(int meshKernelId); + MKERNEL_API int mkernel_clear_undo_state(); /// @brief Computes 1d-2d contacts, where 1d nodes are connected to the closest 2d faces at the boundary (ggeo_make1D2DRiverLinks_dll) /// @@ -1586,18 +1583,6 @@ namespace meshkernelapi int startIndex, int endIndex); - /// @brief Attempt to redo by one undo-action. - /// @param[in] meshKernelId The id of the mesh state. - /// @param[out] redone Indicates if the redo action was actually redone - /// @returns Error code - MKERNEL_API int mkernel_redo_state(int meshKernelId, bool& redone); - - /// @brief Attempt to undo by one undo-action. - /// @param[in] meshKernelId The id of the mesh state. - /// @param[out] undone Indicates if the undo action was actually undone - /// @returns Error code - MKERNEL_API int mkernel_undo_state(int meshKernelId, bool& undone); - #ifdef __cplusplus } #endif diff --git a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp index e9e914f06..db1cb6ce8 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/State.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/State.hpp @@ -35,7 +35,6 @@ #include #include #include -#include namespace meshkernelapi { @@ -71,8 +70,6 @@ namespace meshkernelapi // Exclusively owned state meshkernel::Projection m_projection{meshkernel::Projection::cartesian}; ///< Projection used by the meshes - - meshkernel::UndoActionStack m_undoStack; ///< Stack of undo actions }; } // namespace meshkernelapi diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index 2c15afebd..9bc9bb679 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -106,6 +107,9 @@ namespace meshkernelapi static meshkernel::UInt invalidMeshIndex{0}; static meshkernel::Location invalidMeshLocation{meshkernel::Location::Unknown}; + /// @brief Stack of undo actions + static meshkernel::UndoActionStack meshKernelUndoStack; + static meshkernel::ExitCode HandleException(std::exception_ptr exception_ptr = std::current_exception()) { try @@ -171,19 +175,14 @@ namespace meshkernelapi return lastExitCode; } - MKERNEL_API int mkernel_undo_state(int meshKernelId, bool& undone) + MKERNEL_API int mkernel_undo_state(bool& undone) { lastExitCode = meshkernel::ExitCode::Success; undone = false; try { - if (!meshKernelState.contains(meshKernelId)) - { - throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); - } - - undone = meshKernelState[meshKernelId].m_undoStack.Undo(); + undone = meshKernelUndoStack.Undo(); } catch (...) { @@ -192,19 +191,14 @@ namespace meshkernelapi return lastExitCode; } - MKERNEL_API int mkernel_redo_state(int meshKernelId, bool& redone) + MKERNEL_API int mkernel_redo_state(bool& redone) { lastExitCode = meshkernel::ExitCode::Success; redone = false; try { - if (!meshKernelState.contains(meshKernelId)) - { - throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); - } - - redone = meshKernelState[meshKernelId].m_undoStack.Commit(); + redone = meshKernelUndoStack.Commit(); } catch (...) { @@ -213,18 +207,13 @@ namespace meshkernelapi return lastExitCode; } - MKERNEL_API int mkernel_clear_undo_state(int meshKernelId) + MKERNEL_API int mkernel_clear_undo_state() { lastExitCode = meshkernel::ExitCode::Success; try { - if (!meshKernelState.contains(meshKernelId)) - { - throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); - } - - meshKernelState[meshKernelId].m_undoStack.Clear(); + meshKernelUndoStack.Clear(); } catch (...) { @@ -254,7 +243,7 @@ namespace meshkernelapi const meshkernel::Polygons meshKernelPolygon(polygonPoints, meshKernelState[meshKernelId].m_mesh2d->m_projection); const auto deletionOptionEnum = static_cast(deletionOption); - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_mesh2d->DeleteMesh(meshKernelPolygon, deletionOptionEnum, invertDeletionBool)); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_mesh2d->DeleteMesh(meshKernelPolygon, deletionOptionEnum, invertDeletionBool)); } catch (...) { @@ -308,6 +297,9 @@ namespace meshkernelapi nodes2d, meshKernelState[meshKernelId].m_projection); } + + // No changes to the original mesh can be undone, so clear the undo-stack + meshKernelUndoStack.Clear(); } catch (...) { @@ -387,6 +379,9 @@ namespace meshkernelapi // Do not change the pointer, just the object it is pointing to meshKernelState[meshKernelId].m_mesh1d = std::make_unique(edges1d, nodes1d, meshKernelState[meshKernelId].m_projection); + + // No changes to the original mesh can be undone, so clear the undo-stack + meshKernelUndoStack.Clear(); } catch (...) { @@ -750,13 +745,13 @@ namespace meshkernelapi if (sourceProjection == meshkernel::Projection::cartesian) { meshkernel::ConvertCartesianToSpherical conversion(zoneString); - meshKernelState[meshKernelId].m_undoStack.Add(meshkernel::MeshConversion::Compute(*meshKernelState[meshKernelId].m_mesh2d, conversion)); + meshKernelUndoStack.Add(meshkernel::MeshConversion::Compute(*meshKernelState[meshKernelId].m_mesh2d, conversion)); meshKernelState[meshKernelId].m_projection = conversion.TargetProjection(); } else if (sourceProjection == meshkernel::Projection::spherical) { meshkernel::ConvertSphericalToCartesian conversion(zoneString); - meshKernelState[meshKernelId].m_undoStack.Add(meshkernel::MeshConversion::Compute(*meshKernelState[meshKernelId].m_mesh2d, conversion)); + meshKernelUndoStack.Add(meshkernel::MeshConversion::Compute(*meshKernelState[meshKernelId].m_mesh2d, conversion)); meshKernelState[meshKernelId].m_projection = conversion.TargetProjection(); } else @@ -788,6 +783,9 @@ namespace meshkernelapi meshKernelState[meshKernelId].m_curvilinearGrid = mesh2DToCurvilinear.Compute({xPointCoordinate, yPointCoordinate}); meshKernelState[meshKernelId].m_mesh2d = std::make_unique(meshKernelState[meshKernelId].m_projection); + + // No changes to the original mesh can be undone, so clear the undo-stack + meshKernelUndoStack.Clear(); } catch (...) { @@ -848,7 +846,7 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); } - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_mesh2d->DeleteHangingEdges()); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_mesh2d->DeleteHangingEdges()); } catch (...) { @@ -894,7 +892,7 @@ namespace meshkernelapi std::move(landBoundary), static_cast(projectToLandBoundaryOption), orthogonalizationParameters); - meshKernelState[meshKernelId].m_undoStack.Add(ortogonalization.Initialize()); + meshKernelUndoStack.Add(ortogonalization.Initialize()); ortogonalization.Compute(); } catch (...) @@ -942,7 +940,7 @@ namespace meshkernelapi std::move(landBoundary), static_cast(projectToLandBoundaryOption), orthogonalizationParameters); - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_meshOrthogonalization->Initialize()); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_meshOrthogonalization->Initialize()); } catch (...) { @@ -1310,6 +1308,10 @@ namespace meshkernelapi auto const nodes = curvilinearGrid->ComputeNodes(); auto const edges = curvilinearGrid->ComputeEdges(); *meshKernelState[meshKernelId].m_mesh2d += meshkernel::Mesh2D(edges, nodes, projection); + // No changes to the original mesh can be undone, so clear the undo-stack + meshKernelUndoStack.Clear(); + // Clean up the mesh, by removing any invalid node and edges create for undo state + meshKernelState[meshKernelId].m_mesh2d->DeleteInvalidNodesAndEdges(); } catch (...) { @@ -1337,6 +1339,10 @@ namespace meshkernelapi const auto nodes = curvilinearGrid->ComputeNodes(); *meshKernelState[meshKernelId].m_mesh2d += meshkernel::Mesh2D(edges, nodes, projection); + // No changes to the original mesh can be undone, so clear the undo-stack + meshKernelUndoStack.Clear(); + // Clean up the mesh, by removing any invalid node and edges create for undo state + meshKernelState[meshKernelId].m_mesh2d->DeleteInvalidNodesAndEdges(); } catch (...) { @@ -1363,6 +1369,10 @@ namespace meshkernelapi const auto nodes = curvilinearGrid->ComputeNodes(); *meshKernelState[meshKernelId].m_mesh2d += meshkernel::Mesh2D(edges, nodes, meshKernelState[meshKernelId].m_curvilinearGrid->projection()); + // No changes to the original mesh can be undone, so clear the undo-stack + meshKernelUndoStack.Clear(); + // Clean up the mesh, by removing any invalid node and edges create for undo state + meshKernelState[meshKernelId].m_mesh2d->DeleteInvalidNodesAndEdges(); } catch (...) { @@ -1556,7 +1566,7 @@ namespace meshkernelapi const auto minEdgeLength = meshKernelState[meshKernelId].m_mesh2d->ComputeMinEdgeLength(polygon); const auto searchRadius = std::max(1e-6, minEdgeLength * 0.1); - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_mesh2d->MergeNodesInPolygon(polygon, searchRadius)); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_mesh2d->MergeNodesInPolygon(polygon, searchRadius)); } catch (...) { @@ -1579,7 +1589,7 @@ namespace meshkernelapi const meshkernel::Polygons polygon(polygonVector, meshKernelState[meshKernelId].m_mesh2d->m_projection); - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_mesh2d->MergeNodesInPolygon(polygon, mergingDistance)); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_mesh2d->MergeNodesInPolygon(polygon, mergingDistance)); } catch (...) { @@ -1598,7 +1608,7 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); } - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_mesh2d->MergeTwoNodes(firstNode, secondNode)); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_mesh2d->MergeTwoNodes(firstNode, secondNode)); } catch (...) { @@ -1690,7 +1700,7 @@ namespace meshkernelapi } auto [edgeId, undoAction] = meshKernelState[meshKernelId].m_mesh2d->ConnectNodes(startNode, endNode); - meshKernelState[meshKernelId].m_undoStack.Add(std::move(undoAction)); + meshKernelUndoStack.Add(std::move(undoAction)); new_edge_index = static_cast(edgeId); } @@ -1761,7 +1771,7 @@ namespace meshkernelapi if (edgeId != meshkernel::constants::missing::uintValue) { compoundUndoAction->Add(std::move(action)); - meshKernelState[meshKernelId].m_undoStack.Add(std::move(compoundUndoAction)); + meshKernelUndoStack.Add(std::move(compoundUndoAction)); } edgeIndex = static_cast(edgeId); } @@ -1785,7 +1795,7 @@ namespace meshkernelapi meshkernel::Point const nodeCoordinateVector{xCoordinate, yCoordinate}; auto [nodeId, undoAction] = meshKernelState[meshKernelId].m_mesh2d->InsertNode(nodeCoordinateVector); - meshKernelState[meshKernelId].m_undoStack.Add(std::move(undoAction)); + meshKernelUndoStack.Add(std::move(undoAction)); nodeIndex = static_cast(nodeId); } @@ -1806,7 +1816,7 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); } - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_mesh2d->DeleteNode(nodeIndex)); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_mesh2d->DeleteNode(nodeIndex)); } catch (...) { @@ -1827,7 +1837,7 @@ namespace meshkernelapi meshkernel::Point newPosition{xCoordinate, yCoordinate}; - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_mesh2d->MoveNode(newPosition, nodeIndex)); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_mesh2d->MoveNode(newPosition, nodeIndex)); } catch (...) { @@ -1857,7 +1867,7 @@ namespace meshkernelapi meshkernel::BoundingBox boundingBox{{xLowerLeftBoundingBox, yLowerLeftBoundingBox}, {xUpperRightBoundingBox, yUpperRightBoundingBox}}; const auto edgeIndex = meshKernelState[meshKernelId].m_mesh2d->FindLocationIndex(point, meshkernel::Location::Edges, {}, boundingBox); - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_mesh2d->DeleteEdge(edgeIndex)); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_mesh2d->DeleteEdge(edgeIndex)); } catch (...) { @@ -2077,7 +2087,7 @@ namespace meshkernelapi meshkernel::MeshRefinement meshRefinement(*meshKernelState[meshKernelId].m_mesh2d, std::move(averaging), meshRefinementParameters); - meshKernelState[meshKernelId].m_undoStack.Add(meshRefinement.Compute()); + meshKernelUndoStack.Add(meshRefinement.Compute()); } catch (...) { @@ -2129,7 +2139,7 @@ namespace meshkernelapi meshkernel::MeshRefinement meshRefinement(*meshKernelState[meshKernelId].m_mesh2d, std::move(averaging), meshRefinementParameters); - meshKernelState[meshKernelId].m_undoStack.Add(meshRefinement.Compute()); + meshKernelUndoStack.Add(meshRefinement.Compute()); } catch (...) { @@ -2161,7 +2171,7 @@ namespace meshkernelapi std::move(interpolant), meshRefinementParameters, useNodalRefinement); - meshKernelState[meshKernelId].m_undoStack.Add(meshRefinement.Compute()); + meshKernelUndoStack.Add(meshRefinement.Compute()); } catch (...) { @@ -2191,7 +2201,7 @@ namespace meshkernelapi const auto polygon = meshkernel::Polygons(points, meshKernelState[meshKernelId].m_mesh2d->m_projection); meshkernel::MeshRefinement meshRefinement(*meshKernelState[meshKernelId].m_mesh2d, polygon, meshRefinementParameters); - meshKernelState[meshKernelId].m_undoStack.Add(meshRefinement.Compute()); + meshKernelUndoStack.Add(meshRefinement.Compute()); } catch (...) { @@ -2215,7 +2225,7 @@ namespace meshkernelapi } meshkernel::RemoveDisconnectedRegions removeDisconnectedRegions; - meshKernelState[meshKernelId].m_undoStack.Add(removeDisconnectedRegions.Compute(*meshKernelState[meshKernelId].m_mesh2d)); + meshKernelUndoStack.Add(removeDisconnectedRegions.Compute(*meshKernelState[meshKernelId].m_mesh2d)); } catch (...) { @@ -2345,7 +2355,7 @@ namespace meshkernelapi // Translate origin back to centre of rotation transformation.compose(meshkernel::Translation(meshkernel::Vector(centreX, centreY))); - meshKernelState[meshKernelId].m_undoStack.Add(meshkernel::MeshTransformation::Compute(*meshKernelState[meshKernelId].m_mesh2d, transformation)); + meshKernelUndoStack.Add(meshkernel::MeshTransformation::Compute(*meshKernelState[meshKernelId].m_mesh2d, transformation)); } catch (...) { @@ -2366,7 +2376,7 @@ namespace meshkernelapi } meshkernel::Translation translation(meshkernel::Vector(translationX, translationY)); - meshKernelState[meshKernelId].m_undoStack.Add(meshkernel::MeshTransformation::Compute(*meshKernelState[meshKernelId].m_mesh2d, translation)); + meshKernelUndoStack.Add(meshkernel::MeshTransformation::Compute(*meshKernelState[meshKernelId].m_mesh2d, translation)); } catch (...) { @@ -2386,7 +2396,7 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist."); } - meshKernelState[meshKernelId].m_undoStack.Add(meshkernel::CasulliRefinement::Compute(*meshKernelState[meshKernelId].m_mesh2d)); + meshKernelUndoStack.Add(meshkernel::CasulliRefinement::Compute(*meshKernelState[meshKernelId].m_mesh2d)); } catch (...) { @@ -2751,7 +2761,7 @@ namespace meshkernelapi const meshkernel::FlipEdges flipEdges(*meshKernelState[meshKernelId].m_mesh2d, landBoundary, triangulateFaces, projectToLandBoundary); - meshKernelState[meshKernelId].m_undoStack.Add(flipEdges.Compute()); + meshKernelUndoStack.Add(flipEdges.Compute()); } catch (...) { @@ -2950,7 +2960,7 @@ namespace meshkernelapi std::unique_ptr undoSmallFlowEdges = meshkernel::CompoundUndoAction::Create(); undoSmallFlowEdges->Add(meshKernelState[meshKernelId].m_mesh2d->DeleteSmallFlowEdges(smallFlowEdgesThreshold)); undoSmallFlowEdges->Add(meshKernelState[meshKernelId].m_mesh2d->DeleteSmallTrianglesAtBoundaries(minFractionalAreaTriangles)); - meshKernelState[meshKernelId].m_undoStack.Add(std::move(undoSmallFlowEdges)); + meshKernelUndoStack.Add(std::move(undoSmallFlowEdges)); } catch (...) { @@ -3130,7 +3140,7 @@ namespace meshkernelapi } const auto mergedMeshes = meshkernel::Mesh2D::Merge(*meshKernelState[meshKernelId].m_mesh2d, *meshToConnect); - meshKernelState[meshKernelId].m_undoStack.Add(meshkernel::ConnectMeshes::Compute(*mergedMeshes, searchFraction)); + meshKernelUndoStack.Add(meshkernel::ConnectMeshes::Compute(*mergedMeshes, searchFraction)); meshKernelState[meshKernelId].m_mesh2d->SetNodes(mergedMeshes->Nodes()); meshKernelState[meshKernelId].m_mesh2d->SetEdges(mergedMeshes->Edges()); meshKernelState[meshKernelId].m_mesh2d->m_projection = mergedMeshes->m_projection; @@ -3195,7 +3205,7 @@ namespace meshkernelapi // Execute meshkernel::CurvilinearGridRefinement curvilinearGridRefinement(*meshKernelState[meshKernelId].m_curvilinearGrid, refinement); curvilinearGridRefinement.SetBlock(firstPoint, secondPoint); - meshKernelState[meshKernelId].m_undoStack.Add(curvilinearGridRefinement.Compute()); + meshKernelUndoStack.Add(curvilinearGridRefinement.Compute()); } catch (...) { @@ -3225,7 +3235,7 @@ namespace meshkernelapi meshkernel::CurvilinearGridDeRefinement curvilinearGridDeRefinement(*meshKernelState[meshKernelId].m_curvilinearGrid); curvilinearGridDeRefinement.SetBlock(firstPoint, secondPoint); - meshKernelState[meshKernelId].m_undoStack.Add(curvilinearGridDeRefinement.Compute()); + meshKernelUndoStack.Add(curvilinearGridDeRefinement.Compute()); } catch (...) { @@ -3687,7 +3697,7 @@ namespace meshkernelapi } // Execute - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_curvilinearGridOrthogonalization->Compute()); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_curvilinearGridOrthogonalization->Compute()); } catch (...) { @@ -3754,7 +3764,7 @@ namespace meshkernelapi static_cast(smoothingIterations)); curvilinearGridSmoothing.SetBlock(firstPoint, secondPoint); - meshKernelState[meshKernelId].m_undoStack.Add(curvilinearGridSmoothing.Compute()); + meshKernelUndoStack.Add(curvilinearGridSmoothing.Compute()); } catch (...) { @@ -3892,6 +3902,9 @@ namespace meshkernelapi const auto& projection = meshKernelState[meshKernelId].m_projection; meshKernelState[meshKernelId].m_curvilinearGrid = std::make_unique(curviGridPoints, projection); + + // No changes to the original mesh can be undone, so clear the undo-stack + meshKernelUndoStack.Clear(); } catch (...) { @@ -3941,7 +3954,7 @@ namespace meshkernelapi } meshkernel::Point const fromPoint{xFromCoordinate, yFromCoordinate}; meshkernel::Point const toPoint{xToCoordinate, yToCoordinate}; - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_curvilinearGridLineShift->MoveNode(fromPoint, toPoint)); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_curvilinearGridLineShift->MoveNode(fromPoint, toPoint)); } catch (...) { @@ -3965,7 +3978,7 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("Curvilinear grid line shift algorithm instance is null."); } - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_curvilinearGridLineShift->Compute()); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_curvilinearGridLineShift->Compute()); } catch (...) { @@ -4015,7 +4028,7 @@ namespace meshkernelapi meshkernel::Point const point{xCoordinate, yCoordinate}; - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_curvilinearGrid->InsertFace(point)); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_curvilinearGrid->InsertFace(point)); } catch (...) { @@ -4052,6 +4065,10 @@ namespace meshkernelapi // curvilinear grid must be reset to an empty curvilinear grid meshKernelState[meshKernelId].m_curvilinearGrid = std::make_unique(); + // No changes to the original mesh can be undone, so clear the undo-stack + meshKernelUndoStack.Clear(); + // Clean up the mesh, by removing any invalid node and edges create for undo state + meshKernelState[meshKernelId].m_mesh2d->DeleteInvalidNodesAndEdges(); } catch (...) { @@ -4088,7 +4105,7 @@ namespace meshkernelapi curvilinearDeleteExterior.SetBlock({xFirstPointCoordinate, yFirstPointCoordinate}, {xSecondPointCoordinate, ySecondPointCoordinate}); - meshKernelState[meshKernelId].m_undoStack.Add(curvilinearDeleteExterior.Compute()); + meshKernelUndoStack.Add(curvilinearDeleteExterior.Compute()); } catch (...) { @@ -4125,7 +4142,7 @@ namespace meshkernelapi curvilinearDeleteInterior.SetBlock({xFirstPointCoordinate, yFirstPointCoordinate}, {xSecondPointCoordinate, ySecondPointCoordinate}); - meshKernelState[meshKernelId].m_undoStack.Add(curvilinearDeleteInterior.Compute()); + meshKernelUndoStack.Add(curvilinearDeleteInterior.Compute()); } catch (...) { @@ -4163,7 +4180,7 @@ namespace meshkernelapi meshkernel::Point const upperRight{xUpperRightCorner, yUpperRightCorner}; curvilinearLineAttractionRepulsion.SetBlock(lowerLeft, upperRight); - meshKernelState[meshKernelId].m_undoStack.Add(curvilinearLineAttractionRepulsion.Compute()); + meshKernelUndoStack.Add(curvilinearLineAttractionRepulsion.Compute()); } catch (...) { @@ -4201,7 +4218,7 @@ namespace meshkernelapi curvilinearGridLineMirror.SetLine({xFirstGridLineNode, yFirstGridLineNode}, {xSecondGridLineNode, ySecondGridLineNode}); - meshKernelState[meshKernelId].m_undoStack.Add(curvilinearGridLineMirror.Compute()); + meshKernelUndoStack.Add(curvilinearGridLineMirror.Compute()); } catch (...) { @@ -4232,7 +4249,7 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("Not valid curvilinear grid."); } - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_curvilinearGrid->DeleteNode({xPointCoordinate, yPointCoordinate})); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_curvilinearGrid->DeleteNode({xPointCoordinate, yPointCoordinate})); } catch (...) { @@ -4263,7 +4280,7 @@ namespace meshkernelapi meshkernel::Point const fromPoint{xFromPoint, yFromPoint}; meshkernel::Point const toPoint{xToPoint, yToPoint}; - meshKernelState[meshKernelId].m_undoStack.Add(meshKernelState[meshKernelId].m_curvilinearGrid->MoveNode(fromPoint, toPoint)); + meshKernelUndoStack.Add(meshKernelState[meshKernelId].m_curvilinearGrid->MoveNode(fromPoint, toPoint)); } catch (...) { @@ -4316,7 +4333,7 @@ namespace meshkernelapi //-------------------------------- // Snap curvilinear grid to the land boundary meshkernel::CurvilinearGridSnapGridToLandBoundary gridSnapping(*meshKernelState[meshKernelId].m_curvilinearGrid, landBoundary, controlPoints); - meshKernelState[meshKernelId].m_undoStack.Add(gridSnapping.Compute()); + meshKernelUndoStack.Add(gridSnapping.Compute()); } catch (...) { @@ -4372,7 +4389,7 @@ namespace meshkernelapi // Snap curvilinear grid to the spline meshkernel::CurvilinearGridSnapGridToSpline gridSnapping(*meshKernelState[meshKernelId].m_curvilinearGrid, mkSpline, controlPoints); - meshKernelState[meshKernelId].m_undoStack.Add(gridSnapping.Compute()); + meshKernelUndoStack.Add(gridSnapping.Compute()); } catch (...) { diff --git a/libs/MeshKernelApi/tests/src/ApiTest.cpp b/libs/MeshKernelApi/tests/src/ApiTest.cpp index c608ae6d5..1564ca861 100644 --- a/libs/MeshKernelApi/tests/src/ApiTest.cpp +++ b/libs/MeshKernelApi/tests/src/ApiTest.cpp @@ -3036,6 +3036,9 @@ TEST(Mesh2D, Mesh2DAddEdge) { using namespace meshkernelapi; + int errorCode = mkernel_clear_undo_state(); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); + meshkernel::UInt const num_nodes_x = 4; meshkernel::UInt const num_nodes_y = 4; double const delta = 1.0; @@ -3055,7 +3058,8 @@ TEST(Mesh2D, Mesh2DAddEdge) // allocate state int mk_id = 0; - int errorCode = mkernel_allocate_state(0, mk_id); + errorCode = mkernel_allocate_state(0, mk_id); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); // first initialise using the first mesh, mesh2d errorCode = mkernel_mesh2d_set(mk_id, mesh2d); @@ -3068,13 +3072,13 @@ TEST(Mesh2D, Mesh2DAddEdge) // Should be only a single item on the undo action stack bool undoInsertEdge = false; - errorCode = mkernel_undo_state(mk_id, undoInsertEdge); + errorCode = mkernel_undo_state(undoInsertEdge); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); ASSERT_TRUE(undoInsertEdge); // Should be no items on the undo action stack undoInsertEdge = false; - errorCode = mkernel_undo_state(mk_id, undoInsertEdge); + errorCode = mkernel_undo_state(undoInsertEdge); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); ASSERT_FALSE(undoInsertEdge); } @@ -3083,6 +3087,10 @@ TEST(Mesh2D, Mesh2DInsertNode) { using namespace meshkernelapi; + // Clear the undo stack before starting the test. + int errorCode = mkernel_clear_undo_state(); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); + meshkernel::UInt const num_nodes_x = 4; meshkernel::UInt const num_nodes_y = 4; double const delta = 1.0; @@ -3102,7 +3110,8 @@ TEST(Mesh2D, Mesh2DInsertNode) // allocate state int mk_id = 0; - int errorCode = mkernel_allocate_state(0, mk_id); + errorCode = mkernel_allocate_state(0, mk_id); + ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); // first initialise using the first mesh, mesh2d errorCode = mkernel_mesh2d_set(mk_id, mesh2d); @@ -3117,13 +3126,13 @@ TEST(Mesh2D, Mesh2DInsertNode) // Should be only a single item on the undo action stack bool undoInsertNode = false; - errorCode = mkernel_undo_state(mk_id, undoInsertNode); + errorCode = mkernel_undo_state(undoInsertNode); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); ASSERT_TRUE(undoInsertNode); // Should be zero items on the undo action stack. undoInsertNode = false; - errorCode = mkernel_undo_state(mk_id, undoInsertNode); + errorCode = mkernel_undo_state(undoInsertNode); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); ASSERT_FALSE(undoInsertNode); } diff --git a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp index 6e3f41c94..03aae8920 100644 --- a/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp +++ b/libs/MeshKernelApi/tests/src/CurvilinearGridTests.cpp @@ -1206,7 +1206,7 @@ TEST(CurvilinearGrid, SnapToLandBoundary) bool didUndoOfDeleteNode = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfDeleteNode); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfDeleteNode); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfDeleteNode); @@ -1325,7 +1325,7 @@ TEST(CurvilinearGrid, SnapToSpline) bool didUndoOfDeleteNode = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfDeleteNode); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfDeleteNode); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfDeleteNode); diff --git a/libs/MeshKernelApi/tests/src/CurvilinearGridUndoTests.cpp b/libs/MeshKernelApi/tests/src/CurvilinearGridUndoTests.cpp index ad59de074..e983b20de 100644 --- a/libs/MeshKernelApi/tests/src/CurvilinearGridUndoTests.cpp +++ b/libs/MeshKernelApi/tests/src/CurvilinearGridUndoTests.cpp @@ -72,7 +72,7 @@ TEST(CurvilinearGridUndoTests, DeleteNode) bool didUndoOfDeleteNode = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfDeleteNode); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfDeleteNode); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfDeleteNode); @@ -149,7 +149,7 @@ TEST(CurvilinearGridUndoTests, MoveNode) bool didUndoOfDeleteNode = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfDeleteNode); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfDeleteNode); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfDeleteNode); @@ -252,7 +252,7 @@ TEST(CurvilinearGridUndoTests, Smoothing) bool didUndoOfSmoothing = false; // Undo the smoothing - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfSmoothing); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfSmoothing); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfSmoothing); @@ -335,7 +335,7 @@ TEST(CurvilinearGridUndoTests, SmoothingDirectional) bool didUndoOfSmoothing = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfSmoothing); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfSmoothing); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfSmoothing); @@ -432,7 +432,7 @@ TEST(CurvilinearGridUndoTests, DeleteInterior) bool didUndoOfDeleteInterior = false; // Undo the delete interior block - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfDeleteInterior); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfDeleteInterior); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfDeleteInterior); @@ -531,7 +531,7 @@ TEST(CurvilinearGridUndoTests, DeleteExterior) bool didUndoOfDeleteExterior = false; // Undo the delete exterior - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfDeleteExterior); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfDeleteExterior); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfDeleteExterior); @@ -610,7 +610,7 @@ TEST(CurvilinearGridUndoTests, Refine) bool didUndoOfRefinement = false; // Undo the refinement - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfRefinement); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfRefinement); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfRefinement); @@ -696,7 +696,7 @@ TEST(CurvilinearGridUndoTests, Derefine) bool didUndoOfRefinement = false; // Undo the refinement - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfRefinement); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfRefinement); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfRefinement); @@ -780,7 +780,7 @@ TEST(CurvilinearGridUndoTests, InsertFace) bool didUndoOfRefinement = false; // Undo the refinement - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfRefinement); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfRefinement); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfRefinement); @@ -879,11 +879,11 @@ TEST(CurvilinearGridUndoTests, LineShift) bool didUndoOfLineShift = false; bool didUndoOfMoveNode = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfLineShift); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfLineShift); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfLineShift); - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfMoveNode); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfMoveNode); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfMoveNode); @@ -953,7 +953,7 @@ TEST(CurvilinearGridUndoTests, LineMirror) bool didUndoOfInsertLine = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfInsertLine); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfInsertLine); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfInsertLine); @@ -1027,7 +1027,7 @@ TEST(CurvilinearGridUndoTests, LineAttractionRepulsion) bool didUndoOfInsertLine = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfInsertLine); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfInsertLine); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfInsertLine); @@ -1143,7 +1143,7 @@ TEST(CurvilinearGridUndoTests, OrthogonaliseEntireGrid) bool didUndoOfSmoothing = false; // Undo the orthogonalisation - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndoOfSmoothing); + errorCode = meshkernelapi::mkernel_undo_state(didUndoOfSmoothing); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndoOfSmoothing); @@ -1253,14 +1253,14 @@ TEST(CurvilinearGridUndoTests, RefineAndOrthogonalise) bool didUndo = false; // Undo the orthogonalisation - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndo); + errorCode = meshkernelapi::mkernel_undo_state(didUndo); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndo); didUndo = false; // Undo the orthogonalisation - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndo); + errorCode = meshkernelapi::mkernel_undo_state(didUndo); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndo); @@ -1351,7 +1351,7 @@ TEST(CurvilinearGridUndoTests, RefineUndoThenOrthogonalise) // Undo the refinement bool didUndo = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndo); + errorCode = meshkernelapi::mkernel_undo_state(didUndo); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndo); @@ -1384,7 +1384,7 @@ TEST(CurvilinearGridUndoTests, RefineUndoThenOrthogonalise) didUndo = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndo); + errorCode = meshkernelapi::mkernel_undo_state(didUndo); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndo); @@ -1472,7 +1472,7 @@ TEST(CurvilinearGridUndoTests, InsertFaceUndoThenMirrorLine) bool didUndo = false; // Undo the refinement - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndo); + errorCode = meshkernelapi::mkernel_undo_state(didUndo); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndo); @@ -1497,7 +1497,7 @@ TEST(CurvilinearGridUndoTests, InsertFaceUndoThenMirrorLine) EXPECT_EQ(updatedGrid.num_m, curvilinearGrid.num_m + 1); // Undo the mirror line - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndo); + errorCode = meshkernelapi::mkernel_undo_state(didUndo); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndo); @@ -1596,7 +1596,7 @@ TEST(CurvilinearGridUndoTests, MultiStepUndoTest) // Undo the refinement bool didUndo = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndo); + errorCode = meshkernelapi::mkernel_undo_state(didUndo); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndo); @@ -1622,7 +1622,7 @@ TEST(CurvilinearGridUndoTests, MultiStepUndoTest) ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); didUndo = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndo); + errorCode = meshkernelapi::mkernel_undo_state(didUndo); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndo); @@ -1650,7 +1650,7 @@ TEST(CurvilinearGridUndoTests, MultiStepUndoTest) // Undo the refinement didUndo = false; - errorCode = meshkernelapi::mkernel_undo_state(meshKernelId, didUndo); + errorCode = meshkernelapi::mkernel_undo_state(didUndo); ASSERT_EQ(meshkernel::ExitCode::Success, errorCode); EXPECT_TRUE(didUndo);