diff --git a/Directory.Packages.props b/Directory.Packages.props
index 94b4042..ef9d810 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,7 +3,7 @@
true
-
+
diff --git a/src/MeshKernelNET/Api/DisposableMesh1D.cs b/src/MeshKernelNET/Api/DisposableMesh1D.cs
index d22dfee..83e0cc5 100644
--- a/src/MeshKernelNET/Api/DisposableMesh1D.cs
+++ b/src/MeshKernelNET/Api/DisposableMesh1D.cs
@@ -19,13 +19,13 @@ public sealed class DisposableMesh1D : DisposableNativeObject
private int numNodes;
[ProtoMember(5)]
- private readonly int numValidNodes;
+ private int numValidNodes;
[ProtoMember(6)]
private int numEdges;
[ProtoMember(7)]
- private readonly int numValidEdges;
+ private int numValidEdges;
public DisposableMesh1D()
{
@@ -70,7 +70,11 @@ public int NumNodes
set { numNodes = value; }
}
- public int NumValidNodes => numValidNodes;
+ public int NumValidNodes
+ {
+ get { return numValidNodes; }
+ set { numValidNodes = value; }
+ }
public int NumEdges
{
@@ -78,8 +82,12 @@ public int NumEdges
set { numEdges = value; }
}
- public int NumValidEdges => numValidEdges;
-
+ public int NumValidEdges
+ {
+ get { return numValidEdges; }
+ set { numValidEdges = value; }
+ }
+
protected override void SetNativeObject(ref Mesh1DNative nativeObject)
{
nativeObject.edge_nodes = GetPinnedObjectPointer(EdgeNodes);
diff --git a/src/MeshKernelNET/Api/DisposableMesh2D.cs b/src/MeshKernelNET/Api/DisposableMesh2D.cs
index 1ca1060..8cb1d0a 100644
--- a/src/MeshKernelNET/Api/DisposableMesh2D.cs
+++ b/src/MeshKernelNET/Api/DisposableMesh2D.cs
@@ -43,29 +43,30 @@ public sealed class DisposableMesh2D : DisposableNativeObject, IRe
private int numNodes;
[ProtoMember(13)]
- private readonly int numValidNodes;
+ private int numValidNodes;
[ProtoMember(14)]
private int numEdges;
[ProtoMember(15)]
- private readonly int numValidEdges;
+ private int numValidEdges;
[ProtoMember(16)]
private int numFaces;
[ProtoMember(17)]
- private readonly int numFaceNodes;
+ private int numFaceNodes;
public DisposableMesh2D()
{
}
- public DisposableMesh2D(int nNodes, int nEdges, int nFaces)
+ public DisposableMesh2D(int nNodes, int nEdges, int nFaces, int nFaceNodes)
{
NumNodes = nNodes;
NumEdges = nEdges;
NumFaces = nFaces;
+ NumFaceNodes = nFaceNodes;
EdgeFaces = new int[NumEdges * 2];
EdgeNodes = new int[NumEdges * 2];
@@ -157,7 +158,11 @@ public int NumNodes
set { numNodes = value; }
}
- public int NumValidNodes => numValidNodes;
+ public int NumValidNodes
+ {
+ get { return numValidNodes; }
+ set { numValidNodes = value; }
+ }
public int NumEdges
{
@@ -165,7 +170,11 @@ public int NumEdges
set { numEdges = value; }
}
- public int NumValidEdges => numValidEdges;
+ public int NumValidEdges
+ {
+ get { return numValidEdges; }
+ set { numValidEdges = value; }
+ }
public int NumFaces
{
@@ -173,7 +182,11 @@ public int NumFaces
set { numFaces = value; }
}
- public int NumFaceNodes => numFaceNodes;
+ public int NumFaceNodes
+ {
+ get { return numFaceNodes; }
+ set { numFaceNodes = value; }
+ }
#region IReadOnly2DMesh
///
diff --git a/src/MeshKernelNET/Api/IMeshKernelApi.cs b/src/MeshKernelNET/Api/IMeshKernelApi.cs
index 5086fb6..d90a414 100644
--- a/src/MeshKernelNET/Api/IMeshKernelApi.cs
+++ b/src/MeshKernelNET/Api/IMeshKernelApi.cs
@@ -14,6 +14,13 @@ public interface IMeshKernelApi : IDisposable
/// Generated meshKernelId
int AllocateState(int projectionType);
+ ///
+ /// Clear the undo state
+ ///
+ /// Id of the grid state
+ /// Error code
+ int ClearUndoState(int meshKernelId);
+
///
/// Computes 1d-2d contacts, where 1d nodes are connected to the closest 2d faces at the boundary
/// (ggeo_make1D2DRiverLinks_dll)
@@ -1376,5 +1383,21 @@ int PolygonGetOffset(int meshKernelId,
/// Error code
int PolygonRefine(int meshKernelId, in DisposableGeometryList disposableGeometryListIn, int firstIndex,
int secondIndex, double distance, ref DisposableGeometryList disposableGeometryListOut);
+
+ ///
+ /// Redo editing action
+ ///
+ /// Id of the grid state
+ /// If the editing action has been re-done
+ /// Error code
+ int RedoState(int meshKernelId, ref bool redone);
+
+ ///
+ /// Undo editing action
+ ///
+ /// Id of the grid state
+ /// If the editing action has been un-done
+ /// Error code
+ int UndoState(int meshKernelId, ref bool undone);
}
}
\ No newline at end of file
diff --git a/src/MeshKernelNET/Api/MeshKernelApi.cs b/src/MeshKernelNET/Api/MeshKernelApi.cs
index d730e46..2d4a26b 100644
--- a/src/MeshKernelNET/Api/MeshKernelApi.cs
+++ b/src/MeshKernelNET/Api/MeshKernelApi.cs
@@ -20,6 +20,12 @@ public int AllocateState(int projectionType)
return meshKernelId;
}
+ ///
+ public int ClearUndoState(int meshKernelId)
+ {
+ return MeshKernelDll.ClearUndoState(meshKernelId);
+ }
+
public int ContactsComputeBoundary(int meshKernelId, in IntPtr oneDNodeMask, in DisposableGeometryList polygons, double searchRadius)
{
GeometryListNative polygonsNative = polygons.CreateNativeObject();
@@ -797,7 +803,8 @@ public int Mesh2dGetData(int meshKernelId, out DisposableMesh2D disposableMesh2D
disposableMesh2D = new DisposableMesh2D(newMesh2D.num_nodes,
newMesh2D.num_edges,
- newMesh2D.num_faces);
+ newMesh2D.num_faces,
+ newMesh2D.num_face_nodes);
newMesh2D = disposableMesh2D.CreateNativeObject();
@@ -1245,6 +1252,18 @@ public int PolygonRefine(int meshKernelId, in DisposableGeometryList disposableG
return MeshKernelDll.PolygonRefine(meshKernelId, ref geometryListNativeIn, firstIndex, secondIndex, distance, ref geometryListNativeOut);
}
+ ///
+ public int RedoState(int meshKernelId, ref bool redone)
+ {
+ return MeshKernelDll.RedoState(meshKernelId, ref redone);
+ }
+
+ ///
+ public int UndoState(int meshKernelId, ref bool undone)
+ {
+ return MeshKernelDll.UndoState(meshKernelId, ref undone);
+ }
+
private DisposableMesh2D CreateDisposableMesh2D(Mesh2DNative newMesh2DNative, bool addCellInformation = false)
{
var disposableMesh2D = new DisposableMesh2D
@@ -1253,7 +1272,9 @@ private DisposableMesh2D CreateDisposableMesh2D(Mesh2DNative newMesh2DNative, bo
NodeY = newMesh2DNative.node_y.CreateValueArray(newMesh2DNative.num_nodes),
EdgeNodes = newMesh2DNative.edge_nodes.CreateValueArray(newMesh2DNative.num_edges * 2).ToArray(),
NumEdges = newMesh2DNative.num_edges,
- NumNodes = newMesh2DNative.num_nodes
+ NumNodes = newMesh2DNative.num_nodes,
+ NumValidNodes = newMesh2DNative.num_valid_nodes,
+ NumValidEdges = newMesh2DNative.num_valid_edges
};
if (addCellInformation && newMesh2DNative.num_faces > 0)
@@ -1277,7 +1298,9 @@ private DisposableMesh1D CreateDisposableMesh1d(Mesh1DNative newMesh1DNative)
NodeX = newMesh1DNative.node_x.CreateValueArray(newMesh1DNative.num_nodes),
NodeY = newMesh1DNative.node_y.CreateValueArray(newMesh1DNative.num_nodes),
NumNodes = newMesh1DNative.num_nodes,
- NumEdges = newMesh1DNative.num_edges
+ NumEdges = newMesh1DNative.num_edges,
+ NumValidNodes = newMesh1DNative.num_valid_nodes,
+ NumValidEdges = newMesh1DNative.num_valid_edges,
};
return disposableMesh1D;
}
diff --git a/src/MeshKernelNET/Native/MeshKernelDll.cs b/src/MeshKernelNET/Native/MeshKernelDll.cs
index 5f94cce..0c7784d 100644
--- a/src/MeshKernelNET/Native/MeshKernelDll.cs
+++ b/src/MeshKernelNET/Native/MeshKernelDll.cs
@@ -29,6 +29,14 @@ static MeshKernelDll()
[DllImport(MeshKernelDllName, EntryPoint = "mkernel_allocate_state", CallingConvention = CallingConvention.Cdecl)]
internal static extern int AllocateState([In] int projectionType, [In][Out] ref int meshKernelId);
+ ///
+ /// Clear the undo state
+ ///
+ /// The id of the mesh state
+ /// Error code
+ [DllImport(MeshKernelDllName, EntryPoint = "mkernel_clear_undo_state", CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int ClearUndoState([In] int meshKernelId);
+
///
/// Computes 1d-2d contacts, where 1d nodes are connected to the closest 2d faces at the boundary
/// (ggeo_make1D2DRiverLinks_dll)
@@ -1652,5 +1660,21 @@ internal static extern int PolygonCountOffset([In] int meshKernelId,
/// Error code
[DllImport(MeshKernelDllName, EntryPoint = "mkernel_polygon_refine", CallingConvention = CallingConvention.Cdecl)]
internal static extern int PolygonRefine([In] int meshKernelId, [In] ref GeometryListNative geometryListIn, [In] int firstIndex, [In] int secondIndex, [In] double distance, [In][Out] ref GeometryListNative geometryListOut);
+
+ ///
+ /// Redo editing action
+ ///
+ /// Id of the mesh state
+ /// Error code
+ [DllImport(MeshKernelDllName, EntryPoint = "mkernel_redo_state", CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int RedoState(int meshKernelId, [In][Out] ref bool redone);
+
+ ///
+ /// Redo editing action
+ ///
+ /// Id of the mesh state
+ /// Error code
+ [DllImport(MeshKernelDllName, EntryPoint = "mkernel_undo_state", CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int UndoState(int meshKernelId, [In][Out] ref bool undone);
}
}
\ No newline at end of file
diff --git a/test/MeshKernelNETTest/Api/MeshKernelCurvilinearTest.cs b/test/MeshKernelNETTest/Api/MeshKernelCurvilinearTest.cs
index 285e902..3856052 100644
--- a/test/MeshKernelNETTest/Api/MeshKernelCurvilinearTest.cs
+++ b/test/MeshKernelNETTest/Api/MeshKernelCurvilinearTest.cs
@@ -969,5 +969,39 @@ public void CurvilinearGrid_EdgeNodesSerialization(int numM, int numN, IList<(in
new object[] { 2, 3, new[] { (0, 2), (1, 3), (2, 4), (3, 5), (0, 1), (2, 3), (4, 5) } },
new object[] { 3, 2, new[] { (0, 3), (1, 4), (2, 5), (0, 1), (1, 2), (3, 4), (4, 5) } }
};
+
+ [Test]
+ public void CurvilinearSetAndCovertThroughApi()
+ {
+
+ // Setup
+ using (var api = new MeshKernelApi())
+ using (DisposableCurvilinearGrid grid = CreateCurvilinearGrid(5, 5, 10, 10))
+ {
+ var id = 0;
+ DisposableCurvilinearGrid curvilinearGrid = null;
+ var mesh2d = new DisposableMesh2D();
+ {
+ try
+ {
+ // Prepare
+ id = api.AllocateState(0);
+ Assert.AreEqual(0, api.CurvilinearSet(id, grid));
+ Assert.AreEqual(0, api.CurvilinearConvertToMesh2D(id));
+ Assert.AreEqual(0, api.Mesh2dGetData(id, out mesh2d));
+
+ // Assert
+ Assert.AreEqual(25, mesh2d.NumNodes);
+ }
+ finally
+ {
+ api.DeallocateState(id);
+ curvilinearGrid?.Dispose();
+ mesh2d.Dispose();
+ }
+ }
+ }
+ }
+
}
}
diff --git a/test/MeshKernelNETTest/Api/MeshKernelTest.cs b/test/MeshKernelNETTest/Api/MeshKernelTest.cs
index 8e8e0be..41f59ce 100644
--- a/test/MeshKernelNETTest/Api/MeshKernelTest.cs
+++ b/test/MeshKernelNETTest/Api/MeshKernelTest.cs
@@ -2467,7 +2467,7 @@ public void Mesh2dDeleteInsidePolygon(DeleteMeshInsidePolygonOptions deleteMeshI
}
[Test]
- public void Mesh2dMakeGlobaThroughApi()
+ public void Mesh2dMakeGlobalThroughApi()
{
// Generates a mesh in spherical coordinates around the globe
@@ -2493,5 +2493,56 @@ public void Mesh2dMakeGlobaThroughApi()
}
}
}
+
+
+ [Test]
+ public void Mesh2dUndoTwoDeleteNodesThroughApi()
+ {
+ // Setup
+ using (DisposableMesh2D mesh = CreateMesh2D(4, 4, 100, 200))
+ using (var api = new MeshKernelApi())
+ {
+ var id = 0;
+ var mesh2d = new DisposableMesh2D();
+ try
+ {
+ int numberOfVerticesBefore = mesh.NumNodes;
+ id = api.AllocateState(0);
+
+ Assert.AreEqual(0, api.Mesh2dSet(id, mesh));
+
+ // Do
+ Assert.AreEqual(0, api.Mesh2dDeleteNode(id, 0));
+ Assert.AreEqual(0, api.Mesh2dGetData(id, out mesh2d));
+ Assert.AreEqual(-999.0, mesh2d.NodeX[0]);
+ Assert.AreEqual(0, api.Mesh2dDeleteNode(id, 6));
+ Assert.AreEqual(0, api.Mesh2dGetData(id, out mesh2d));
+ Assert.AreEqual(-999.0, mesh2d.NodeX[6]);
+
+ // Un-do
+ bool undone = false;
+ Assert.AreEqual(0, api.UndoState(id, ref undone));
+ Assert.AreEqual(true, undone);
+ Assert.AreEqual(0, api.Mesh2dGetData(id, out mesh2d));
+ Assert.AreEqual(100.0, mesh2d.NodeX[6]);
+ Assert.AreEqual(numberOfVerticesBefore - 1, mesh2d.NumValidNodes);
+
+ undone = false;
+ Assert.AreEqual(0, api.UndoState(id, ref undone));
+ Assert.AreEqual(true, undone);
+
+ Assert.AreEqual(0, api.Mesh2dGetData(id, out mesh2d));
+ Assert.AreEqual(0.0, mesh2d.NodeX[0]);
+ Assert.AreEqual(numberOfVerticesBefore, mesh2d.NumValidNodes);
+ }
+ finally
+ {
+ api.DeallocateState(id);
+ mesh2d.Dispose();
+ }
+ }
+ }
+
+
}
}
\ No newline at end of file