├── src
├── MeshKernelNET
│ ├── Api
│ │ ├── CurvilinearDirectionOptions.cs
│ │ ├── StringBufferSizeAttribute.cs
│ │ ├── ProjectionOptions.cs
│ │ ├── InterpolationType.cs
│ │ ├── IntArrayWrapper.cs
│ │ ├── DeleteMeshInsidePolygonOptions.cs
│ │ ├── GridTypeOptions.cs
│ │ ├── ProjectToLandBoundaryOptions.cs
│ │ ├── IRemoteApiProxyProvider.cs
│ │ ├── MeshRefinementTypes.cs
│ │ ├── RemoteMeshKernelApi.cs
│ │ ├── BoundingBox.cs
│ │ ├── CurvilinearParameters.cs
│ │ ├── OrthogonalizationParameters.cs
│ │ ├── DisposableContacts.cs
│ │ ├── IReadOnly2DMesh.cs
│ │ ├── MeshRefinementParameters.cs
│ │ ├── SplinesToCurvilinearParameters.cs
│ │ ├── DisposableMesh1D.cs
│ │ ├── DisposableGeometryList.cs
│ │ ├── DisposableCurvilinearGrid.cs
│ │ ├── DisposableNativeObject.cs
│ │ ├── DisposableGriddedSamples.cs
│ │ ├── MakeGridParameters.cs
│ │ └── DisposableMesh2D.cs
│ ├── Native
│ │ ├── ContactsNative.cs
│ │ ├── BoundingBoxNative.cs
│ │ ├── CurvilinearGridNative.cs
│ │ ├── CurvilinearParametersNative.cs
│ │ ├── GeometryListNative.cs
│ │ ├── Mesh1DNative.cs
│ │ ├── OrthogonalizationParametersNative.cs
│ │ ├── GriddedSamplesNative.cs
│ │ ├── MakeGridParametersNative.cs
│ │ ├── SplinesToCurvilinearParametersNative.cs
│ │ ├── MeshRefinementParametersNative.cs
│ │ └── Mesh2DNative.cs
│ ├── MeshKernelNET.csproj
│ └── Helpers
│ │ ├── IntPtrExtensions.cs
│ │ ├── StringUtilityExtensions.cs
│ │ ├── NativeLibrary.cs
│ │ └── NativeStructConversionExtensions.cs
└── MeshKernelNET.Generators
│ ├── MeshKernelNET.Generators.csproj
│ └── RemoteApiGenerator.cs
├── README.md
├── Directory.Build.props
├── test
└── MeshKernelNETTest
│ ├── Api
│ ├── CurvilinearParametersTest.cs
│ ├── DisposableContactsTest.cs
│ ├── DisposableCurvilinearGridTest.cs
│ ├── DisposableMesh1DTest.cs
│ ├── MeshKernelMesh2DTest.cs
│ ├── MeshKernelSerializationTest.cs
│ ├── DisposableGeometryListTest.cs
│ ├── MeshKernelNetwork1dTest.cs
│ ├── DisposableMesh2DTest.cs
│ ├── MeshKernelTestUtils.cs
│ ├── MeshKernelTestUtilsTest.cs
│ └── DisposableGriddedSamplesTest.cs
│ ├── MeshKernelNETTest.csproj
│ └── Native
│ └── NativeStructConversionExtensionsTest.cs
├── Directory.Packages.props
├── MeshKernelNET.targets
├── nuget
└── MeshKernelNET.nuspec
├── MeshKernelNET.sln.DotSettings
├── MeshKernelNET.sln
├── tools
└── gather_to_sign_dll.py
└── .gitignore
/src/MeshKernelNET/Api/CurvilinearDirectionOptions.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | public enum CurvilinearDirectionOptions
6 | {
7 | [Description("M-direction")]
8 | M = 0,
9 |
10 | [Description("N-direction")]
11 | N = 1
12 | }
13 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/StringBufferSizeAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 |
4 | [assembly: InternalsVisibleTo("MeshKernelNETTest")]
5 |
6 | namespace MeshKernelNET.Api
7 | {
8 | internal class StringBufferSizeAttribute : Attribute
9 | {
10 | public int BufferSize { get; set; }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/ProjectionOptions.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | public enum ProjectionOptions
6 | {
7 | [Description("Cartesian")]
8 | Cartesian = 0,
9 |
10 | [Description("Spherical")]
11 | Spherical = 1,
12 |
13 | [Description("Spherical Accurate")]
14 | SphericalAccurate = 2
15 | }
16 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/InterpolationType.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | public enum InterpolationType
6 | {
7 | [Description("Short")]
8 | Short = 0,
9 |
10 | [Description("Float")]
11 | Float = 1,
12 |
13 | [Description("Int")]
14 | Int = 2,
15 |
16 | [Description("Double")]
17 | Double = 3
18 | }
19 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/IntArrayWrapper.cs:
--------------------------------------------------------------------------------
1 | using ProtoBuf;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | [ProtoContract]
6 | public sealed class IntArrayWrapper
7 | {
8 | public IntArrayWrapper()
9 | {
10 | }
11 |
12 | public IntArrayWrapper(int size)
13 | {
14 | Values = new int[size];
15 | }
16 |
17 | [ProtoMember(1)]
18 | public int[] Values { get; set; }
19 | }
20 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MeshKernelNET
2 | .NET wrapper for the MeshKernel library
3 | `MeshKernelNET` is a small C# wrapper around the `MeshKernel`. `MeskKernel` is a library for creating and editing meshes. It supports 1D and 2D unstructured meshes.
4 | The underlying C++ library `MeshKernel` can be found [here](https://github.com/Deltares/MeshKernel).
5 |
6 | # Installation
7 | `MeshKernelNET` provides a nuspec file to generate a nuget package. This nuget package can be used in your solution.
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/DeleteMeshInsidePolygonOptions.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | public enum DeleteMeshInsidePolygonOptions
6 | {
7 | [Description("Not intersecting")]
8 | NotIntersecting = 0,
9 |
10 | [Description("Intersecting")]
11 | Intersecting = 1,
12 |
13 | [Description("Faces with included circumcenters")]
14 | FacesWithIncludedCircumcenters = 2
15 | }
16 | }
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | Deltares
4 | Copyright © Deltares $([System.DateTime]::Now.Year)
5 | $(MSBuildProjectName)
6 | $(MSBuildProjectName)
7 |
8 | 0
9 | 8.2.2
10 | $(MeshKernelNETVersion).$(BuildNumber)
11 | $(Version)
12 |
13 |
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/GridTypeOptions.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | public enum GridTypeOptions
6 | {
7 | [Description("Square grid")]
8 | Square = 0,
9 |
10 | [Description("Wiber grid")]
11 | Wieber = 1,
12 |
13 | [Description("Hexagonal grid type one")]
14 | HexagonalTypeOne = 2,
15 |
16 | [Description("Hexagonal grid type two")]
17 | HexagonalTypeTwo = 3,
18 |
19 | [Description("Triangular grid")]
20 | Triangular = 4
21 | }
22 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/ContactsNative.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace MeshKernelNET.Native
5 | {
6 | /// @brief A struct used to describe contacts between a 1d and a 2d mesh
7 | [StructLayout(LayoutKind.Sequential)]
8 | public struct ContactsNative
9 | {
10 | ///
11 | /// The indices of the 1d mesh
12 | ///
13 | public IntPtr mesh1d_indices;
14 |
15 | ///
16 | /// The indices of the 2d face
17 | ///
18 | public IntPtr mesh2d_indices;
19 |
20 | ///
21 | /// The number of contacts
22 | ///
23 | public int num_contacts;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/ProjectToLandBoundaryOptions.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | public enum ProjectToLandBoundaryOptions
6 | {
7 | [Description("Do not project to land boundary")]
8 | No = 0,
9 |
10 | [Description("To original net-boundary")]
11 | ToOriginalNetBoundary = 1,
12 |
13 | [Description("Net-boundary to landBoundary")]
14 | NetBoundaryToLandBoundary = 2,
15 |
16 | [Description("Net-boundary to land boundary and inner to land")]
17 | NetBoundaryToLandBoundaryAndInnerToLand = 3,
18 |
19 | [Description("Whole net")]
20 | WholeNet = 4,
21 |
22 | [Description("Ok")]
23 | Ok = 5
24 | }
25 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/IRemoteApiProxyProvider.cs:
--------------------------------------------------------------------------------
1 | namespace MeshKernelNET.Api
2 | {
3 | ///
4 | /// Provides a way to create and release remote API proxy instances.
5 | ///
6 | public interface IRemoteApiProxyProvider
7 | {
8 | ///
9 | /// Creates a new API proxy instance.
10 | ///
11 | IMeshKernelApi CreateProxy();
12 |
13 | ///
14 | /// Releases or disposes of the API proxy instance.
15 | ///
16 | void ReleaseProxy(IMeshKernelApi proxy);
17 |
18 | ///
19 | /// Checks whether the API proxy instance is still alive.
20 | ///
21 | bool IsProxyAlive(IMeshKernelApi proxy);
22 | }
23 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET.Generators/MeshKernelNET.Generators.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | latest
6 |
7 | false
8 | Analyzer
9 | CS
10 | true
11 |
12 | true
13 | true
14 |
15 | MeshKernelNET.Generators
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/BoundingBoxNative.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace MeshKernelNET.Native
4 | {
5 | [StructLayout(LayoutKind.Sequential)]
6 | public struct BoundingBoxNative
7 | {
8 | ///
9 | /// The bounding box lower left x coordinate
10 | ///
11 | public double xLowerLeft;
12 |
13 | ///
14 | /// The bounding box lower left y coordinate
15 | ///
16 | public double yLowerLeft;
17 |
18 | ///
19 | /// The bounding box upper right x coordinate
20 | ///
21 | public double xUpperRight;
22 |
23 | ///
24 | /// The bounding box upper right y coordinate
25 | ///
26 | public double yUpperRight;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/Api/CurvilinearParametersTest.cs:
--------------------------------------------------------------------------------
1 | using MeshKernelNET.Api;
2 | using NUnit.Framework;
3 |
4 | namespace MeshKernelNETTest.Api
5 | {
6 | [TestFixture]
7 | public class CurvilinearParametersTest
8 | {
9 | [Test]
10 | public void CreateDefault_ReturnsCorrectCurvilinearParameters()
11 | {
12 | // Call
13 | var parameters = CurvilinearParameters.CreateDefault();
14 |
15 | // Assert
16 | Assert.That(parameters.MRefinement, Is.EqualTo(2000));
17 | Assert.That(parameters.NRefinement, Is.EqualTo(40));
18 | Assert.That(parameters.SmoothingIterations, Is.EqualTo(10));
19 | Assert.That(parameters.SmoothingParameter, Is.EqualTo(0.5));
20 | Assert.That(parameters.AttractionParameter, Is.EqualTo(0.0));
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/CurvilinearGridNative.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace MeshKernelNET.Native
5 | {
6 | /// @brief A struct used to describe the values of a curvilinear grid in a C-compatible manner
7 | [StructLayout(LayoutKind.Sequential)]
8 | public struct CurvilinearGridNative
9 | {
10 | ///
11 | /// The x-coordinates of network1d nodes
12 | ///
13 | public IntPtr node_x;
14 |
15 | ///
16 | /// The y-coordinates of network1d nodes
17 | ///
18 | public IntPtr node_y;
19 |
20 | ///
21 | /// The number of curvilinear grid nodes along m
22 | ///
23 | public int num_m;
24 |
25 | ///
26 | /// The number of curvilinear grid nodes along n
27 | ///
28 | public int num_n;
29 | }
30 | }
--------------------------------------------------------------------------------
/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/MeshKernelNET.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <_FilesToCopyMeshKernel Include="$(MSBuildThisFileDirectory)..\..\content\native\**\*"/>
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | <_OriginalFilesMeshKernel Include="$(MSBuildThisFileDirectory)..\..\content\native\**\*"/>
14 | <_FilesToCleanIONetCDF Include="$(OutDir)\win-x64\native\%(_OriginalFilesMeshKernel.RecursiveDir)%(_OriginalFilesMeshKernel.FileName)%(_OriginalFilesMeshKernel.Extension)"/>
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/MeshKernelNET/MeshKernelNET.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | $(SolutionDir)\bin
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | <_Parameter1>MeshKernelNETTest
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/CurvilinearParametersNative.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace MeshKernelNET.Native
4 | {
5 | [StructLayout(LayoutKind.Sequential)]
6 | public struct CurvilinearParametersNative
7 | {
8 | ///
9 | /// *M-refinement factor for regular grid generation (2000)
10 | ///
11 | public int MRefinement;
12 |
13 | ///
14 | /// *N-refinement factor for regular grid generation (40)
15 | ///
16 | public int NRefinement;
17 |
18 | ///
19 | /// Nr. of inner iterations in regular grid smoothing (10).
20 | ///
21 | public int SmoothingIterations;
22 |
23 | ///
24 | /// * Smoothing parameter (0.5).
25 | ///
26 | public double SmoothingParameter;
27 |
28 | ///
29 | /// *Attraction/repulsion parameter (0).
30 | ///
31 | public double AttractionParameter;
32 | }
33 | }
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/MeshKernelNETTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net48
5 | $(SolutionDir)\bin
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/MeshRefinementTypes.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | ///
6 | /// Specifies the different types of mesh refinement techniques
7 | /// available in the mesh kernel.
8 | ///
9 | public enum MeshRefinementTypes
10 | {
11 | ///
12 | /// Mesh refinement based on wave Courant numbers,
13 | /// typically used in coastal and wave modeling applications.
14 | ///
15 | [Description("Wave courant")]
16 | WaveCourant = 1,
17 |
18 | ///
19 | /// Mesh refinement using specified levels to control
20 | /// resolution across different areas of the mesh.
21 | ///
22 | [Description("Refinement levels")]
23 | RefinementLevels = 2,
24 |
25 | ///
26 | /// Mesh refinement based on ridge detection algorithms,
27 | /// often used to better capture bathymetric features.
28 | ///
29 | [Description("Ridge detection")]
30 | RidgeDetection = 3
31 | }
32 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/GeometryListNative.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace MeshKernelNET.Native
5 | {
6 | [StructLayout(LayoutKind.Sequential)]
7 | public struct GeometryListNative
8 | {
9 | ///
10 | /// The value used as separator in coordinates_x, coordinates_y and values
11 | ///
12 | public double geometrySeperator;
13 |
14 | ///
15 | /// The value used to separate the inner part of a polygon from its outer part
16 | ///
17 | public double innerOuterSeperator;
18 |
19 | ///
20 | /// The number of coordinate values present
21 | ///
22 | public int numberOfCoordinates;
23 |
24 | ///
25 | /// The x coordinate values
26 | ///
27 | public IntPtr xCoordinates;
28 |
29 | ///
30 | /// The y coordinate values
31 | ///
32 | public IntPtr yCoordinates;
33 |
34 | ///
35 | /// The values at the point
36 | ///
37 | public IntPtr zCoordinates;
38 | }
39 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/RemoteMeshKernelApi.cs:
--------------------------------------------------------------------------------
1 | namespace MeshKernelNET.Api
2 | {
3 | ///
4 | /// Remote wrapper for that executes operations in a separate process.
5 | ///
6 | public sealed partial class RemoteMeshKernelApi : IMeshKernelApi
7 | {
8 | private readonly IRemoteApiProxyProvider provider;
9 | private IMeshKernelApi api;
10 |
11 | ///
12 | /// Initializes a new instance of the class.
13 | ///
14 | /// Provides remote API proxy instances.
15 | public RemoteMeshKernelApi(IRemoteApiProxyProvider provider)
16 | {
17 | this.provider = provider;
18 | api = provider.CreateProxy();
19 | }
20 |
21 | ///
22 | public void Dispose()
23 | {
24 | if (api == null)
25 | {
26 | return;
27 | }
28 |
29 | if (provider.IsProxyAlive(api))
30 | {
31 | api.Dispose();
32 | }
33 |
34 | provider.ReleaseProxy(api);
35 | api = null;
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Helpers/IntPtrExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace MeshKernelNET.Helpers
5 | {
6 | internal static class IntPtrExtensions
7 | {
8 | public static T[] CreateValueArray(this IntPtr pointer, int size, int stringSize = 0)
9 | {
10 | var array = new T[size];
11 |
12 | if (typeof(T) == typeof(double))
13 | {
14 | Marshal.Copy(pointer, array as double[], 0, size);
15 | }
16 | else if (typeof(T) == typeof(int))
17 | {
18 | Marshal.Copy(pointer, array as int[], 0, size);
19 | }
20 | else if (typeof(T) == typeof(string))
21 | {
22 | int totalByteSize = size * stringSize;
23 | var byteArray = new byte[totalByteSize];
24 |
25 | Marshal.Copy(pointer, byteArray, 0, totalByteSize);
26 |
27 | byteArray.GetStringArrayFromFlattenedAsciiCodedStringArray(size).CopyTo(array, 0);
28 | }
29 | else
30 | {
31 | throw new NotSupportedException("Currently only double, int and string are supported");
32 | }
33 |
34 | return array;
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/Api/DisposableContactsTest.cs:
--------------------------------------------------------------------------------
1 | using MeshKernelNET.Api;
2 | using MeshKernelNET.Native;
3 | using NUnit.Framework;
4 |
5 | namespace MeshKernelNETTest.Api
6 | {
7 | [TestFixture]
8 | public class DisposableContactsTest
9 | {
10 | [Test]
11 | public void UpdateFromNativeObjectShouldPopulateContacts()
12 | {
13 | // Arrange
14 | var managedContacts = new DisposableContacts();
15 | var nativeContacts = new DisposableContacts
16 | {
17 | Mesh1dIndices = new[] { 1, 2, 3 },
18 | Mesh2dIndices = new[] { 4, 5, 6 },
19 | NumContacts = 3,
20 | };
21 |
22 | using (nativeContacts)
23 | {
24 | ContactsNative nativeObject = nativeContacts.CreateNativeObject();
25 |
26 | // Act
27 | managedContacts.UpdateFromNativeObject(ref nativeObject);
28 |
29 | // Assert
30 | Assert.That(managedContacts.Mesh1dIndices, Is.EqualTo(new[] { 1, 2, 3 }));
31 | Assert.That(managedContacts.Mesh2dIndices, Is.EqualTo(new[] { 4, 5, 6 }));
32 | Assert.That(managedContacts.NumContacts, Is.EqualTo(3));
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/Mesh1DNative.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace MeshKernelNET.Native
5 | {
6 | /// @brief A struct used to describe the values of a mesh 1d in a C-compatible manner
7 | [StructLayout(LayoutKind.Sequential)]
8 | public struct Mesh1DNative
9 | {
10 | ///
11 | /// The nodes composing each mesh 1d edge
12 | ///
13 | public IntPtr edge_nodes;
14 |
15 | ///
16 | /// The x-coordinates of the mesh nodes
17 | ///
18 | public IntPtr node_x;
19 |
20 | ///
21 | /// The y-coordinates of the mesh nodes
22 | ///
23 | public IntPtr node_y;
24 |
25 | ///
26 | /// The number of 1d nodes
27 | ///
28 | public int num_nodes;
29 |
30 | ///
31 | /// The number of 1d valid nodes
32 | ///
33 | public int num_valid_nodes;
34 |
35 | ///
36 | /// The number of 1d edges
37 | ///
38 | public int num_edges;
39 |
40 | ///
41 | /// The number of 1d valid edges
42 | ///
43 | public int num_valid_edges;
44 | }
45 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/BoundingBox.cs:
--------------------------------------------------------------------------------
1 | using ProtoBuf;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | [ProtoContract(AsReferenceDefault = true)]
6 | public class BoundingBox
7 | {
8 | public static BoundingBox CreateDefault()
9 | {
10 | return new BoundingBox
11 | {
12 | xLowerLeft = double.MinValue,
13 | yLowerLeft = double.MinValue,
14 | xUpperRight = double.MaxValue,
15 | yUpperRight = double.MaxValue
16 | };
17 | }
18 |
19 | ///
20 | /// The bounding box lower left x coordinate
21 | ///
22 | [ProtoMember(1)]
23 | public double xLowerLeft { get; set; }
24 |
25 | ///
26 | /// The bounding box lower left y coordinate
27 | ///
28 | [ProtoMember(2)]
29 | public double yLowerLeft { get; set; }
30 |
31 | ///
32 | /// The bounding box upper right x coordinate
33 | ///
34 | [ProtoMember(3)]
35 | public double xUpperRight { get; set; }
36 |
37 | ///
38 | /// The bounding box upper right y coordinate
39 | ///
40 | [ProtoMember(4)]
41 | public double yUpperRight { get; set; }
42 | }
43 | }
--------------------------------------------------------------------------------
/nuget/MeshKernelNET.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MeshKernelNET
5 | 8.2.2
6 | Deltares meshing library
7 | Deltares
8 | Deltares
9 | false
10 | This is a package containing a managed dll wrapping around the native dll of MeshKernel. This native dll is a library containing functionality to generate and edit 1D, 2D meshes.
11 | Copyright © Deltares $copyrightYear$
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/Api/DisposableCurvilinearGridTest.cs:
--------------------------------------------------------------------------------
1 | using MeshKernelNET.Api;
2 | using MeshKernelNET.Native;
3 | using NUnit.Framework;
4 |
5 | namespace MeshKernelNETTest.Api
6 | {
7 | [TestFixture]
8 | public class DisposableCurvilinearGridTest
9 | {
10 | [Test]
11 | public void UpdateFromNativeObjectShouldPopulateCurvilinearGrid()
12 | {
13 | // Arrange
14 | var managedGrid = new DisposableCurvilinearGrid();
15 | var nativeGrid = new DisposableCurvilinearGrid(3, 3)
16 | {
17 | NodeX = new[] { 1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0 },
18 | NodeY = new[] { 4.0, 5.0, 6.0, 4.0, 5.0, 6.0, 4.0, 5.0, 6.0 }
19 | };
20 |
21 | using (nativeGrid)
22 | {
23 | CurvilinearGridNative nativeObject = nativeGrid.CreateNativeObject();
24 |
25 | // Act
26 | managedGrid.UpdateFromNativeObject(ref nativeObject);
27 |
28 | // Assert
29 | Assert.That(managedGrid.NodeX, Is.EqualTo(new[] { 1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0 }));
30 | Assert.That(managedGrid.NodeY, Is.EqualTo(new[] { 4.0, 5.0, 6.0, 4.0, 5.0, 6.0, 4.0, 5.0, 6.0 }));
31 | Assert.That(managedGrid.NumM, Is.EqualTo(3));
32 | Assert.That(managedGrid.NumN, Is.EqualTo(3));
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/OrthogonalizationParametersNative.cs:
--------------------------------------------------------------------------------
1 | namespace MeshKernelNET.Native
2 | {
3 | ///
4 | /// All orthogonalization options
5 | ///
6 | public struct OrthogonalizationParametersNative
7 | {
8 | ///
9 | /// *Number of outer iterations in orthogonalization. Increase this parameter for complex grids (2)
10 | ///
11 | public int OuterIterations { get; set; }
12 |
13 | ///
14 | /// *Number of boundary iterations in grid/net orthogonalization within itatp (25)
15 | ///
16 | public int BoundaryIterations { get; set; }
17 |
18 | ///
19 | /// *Number of inner iterations in grid/net orthogonalization within itbnd (25)
20 | ///
21 | public int InnerIterations { get; set; }
22 |
23 | ///
24 | /// *Factor from 0 to 1. between grid smoothing and grid orthogonality (0.975)
25 | ///
26 | public double OrthogonalizationToSmoothingFactor { get; set; }
27 |
28 | ///
29 | /// Minimum ATPF on the boundary (1.0)
30 | ///
31 | public double OrthogonalizationToSmoothingFactorAtBoundary { get; set; }
32 |
33 | ///
34 | /// Factor between smoother 1d0 and area-homogenizer 0d0 (1.0)
35 | ///
36 | public double ArealToAngleSmoothingFactor { get; set; }
37 | }
38 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/CurvilinearParameters.cs:
--------------------------------------------------------------------------------
1 | using ProtoBuf;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | [ProtoContract(AsReferenceDefault = true)]
6 | public class CurvilinearParameters
7 | {
8 | public static CurvilinearParameters CreateDefault()
9 | {
10 | return new CurvilinearParameters
11 | {
12 | MRefinement = 2000,
13 | NRefinement = 40,
14 | SmoothingIterations = 10,
15 | SmoothingParameter = 0.5,
16 | AttractionParameter = 0.0
17 | };
18 | }
19 |
20 | ///
21 | /// *M-refinement factor for regular grid generation (2000)
22 | ///
23 | [ProtoMember(1)]
24 | public int MRefinement { get; set; }
25 |
26 | ///
27 | /// *N-refinement factor for regular grid generation (40)
28 | ///
29 | [ProtoMember(2)]
30 | public int NRefinement { get; set; }
31 |
32 | ///
33 | /// *Nr. of inner iterations in regular grid smoothing (10).
34 | ///
35 | [ProtoMember(3)]
36 | public int SmoothingIterations { get; set; }
37 |
38 | ///
39 | /// * Smoothing parameter (0.5).
40 | ///
41 | [ProtoMember(4)]
42 | public double SmoothingParameter { get; set; }
43 |
44 | ///
45 | /// *Attraction/repulsion parameter (0.0).
46 | ///
47 | [ProtoMember(5)]
48 | public double AttractionParameter { get; set; }
49 | }
50 | }
--------------------------------------------------------------------------------
/MeshKernelNET.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | ..\D-HYDRO.DotSettings
3 | True
4 | True
5 | 1
6 | True
7 | True
8 | True
9 | True
10 | True
11 | True
12 | True
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/Api/DisposableMesh1DTest.cs:
--------------------------------------------------------------------------------
1 | using MeshKernelNET.Api;
2 | using MeshKernelNET.Native;
3 | using NUnit.Framework;
4 |
5 | namespace MeshKernelNETTest.Api
6 | {
7 | [TestFixture]
8 | public class DisposableMesh1DTest
9 | {
10 | [Test]
11 | public void UpdateFromNativeObjectShouldPopulateMesh1D()
12 | {
13 | // Arrange
14 | var managedMesh = new DisposableMesh1D();
15 | var nativeMesh = new DisposableMesh1D(4, 3)
16 | {
17 | NodeX = new[] { 0.0, 1.0, 2.0, 3.0 },
18 | NodeY = new[] { 0.0, 0.0, 0.0, 0.0 },
19 | EdgeNodes = new[] { 0, 1, 1, 2, 2, 3 },
20 | NumNodes = 4,
21 | NumEdges = 3,
22 | NumValidNodes = 4,
23 | NumValidEdges = 3
24 | };
25 |
26 | using (nativeMesh)
27 | {
28 | Mesh1DNative nativeObject = nativeMesh.CreateNativeObject();
29 |
30 | // Act
31 | managedMesh.UpdateFromNativeObject(ref nativeObject);
32 |
33 | // Assert
34 | Assert.That(managedMesh.NodeX, Is.EqualTo(new[] { 0.0, 1.0, 2.0, 3.0 }));
35 | Assert.That(managedMesh.NodeY, Is.EqualTo(new[] { 0.0, 0.0, 0.0, 0.0 }));
36 | Assert.That(managedMesh.EdgeNodes, Is.EqualTo(new[] { 0, 1, 1, 2, 2, 3 }));
37 | Assert.That(managedMesh.NumNodes, Is.EqualTo(4));
38 | Assert.That(managedMesh.NumEdges, Is.EqualTo(3));
39 | Assert.That(managedMesh.NumValidNodes, Is.EqualTo(4));
40 | Assert.That(managedMesh.NumValidEdges, Is.EqualTo(3));
41 | }
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/GriddedSamplesNative.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace MeshKernelNET.Native
5 | {
6 | /// @brief A struct describing gridded samples
7 | [StructLayout(LayoutKind.Sequential)]
8 | public struct GriddedSamplesNative
9 | {
10 | ///
11 | /// Number of x gridded samples coordinates
12 | ///
13 | public int num_x;
14 |
15 | ///
16 | /// Number of y gridded samples coordinates
17 | ///
18 | public int num_y;
19 |
20 | ///
21 | /// X coordinate of the grid origin (lower left corner)
22 | ///
23 | public double origin_x;
24 |
25 | ///
26 | /// Y coordinate of the grid origin (lower left corner)
27 | ///
28 | public double origin_y;
29 |
30 | ///
31 | /// Constant grid cell size
32 | ///
33 | public double cell_size;
34 |
35 | ///
36 | /// If not nullptr, coordinates for non-uniform grid spacing in x direction
37 | ///
38 | public IntPtr coordinates_x;
39 |
40 | ///
41 | /// If not nullptr, coordinates for non-uniform grid spacing in y direction
42 | ///
43 | public IntPtr coordinates_y;
44 |
45 | ///
46 | /// Sample values
47 | ///
48 | public IntPtr values;
49 |
50 | ///
51 | /// The numeric representation of the values (0 = short, 1 = float, 2 = int and 3 = double)
52 | ///
53 | public int value_type;
54 | }
55 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/MakeGridParametersNative.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace MeshKernelNET.Native
4 | {
5 | [StructLayout(LayoutKind.Sequential)]
6 | public struct MakeGridParametersNative
7 | {
8 | ///
9 | /// * The number of columns in x direction (3)
10 | ///
11 | public int NumberOfColumns;
12 |
13 | ///
14 | /// * The number of columns in y direction (3)
15 | ///
16 | public int NumberOfRows;
17 |
18 | ///
19 | /// * The grid angle (0.0)
20 | ///
21 | public double GridAngle;
22 |
23 | ///
24 | /// * The x coordinate of the origin, located at the bottom left corner (0.0)
25 | ///
26 | public double OriginXCoordinate;
27 |
28 | ///
29 | /// * The y coordinate of the origin, located at the bottom left corner (0.0)
30 | ///
31 | public double OriginYCoordinate;
32 |
33 | ///
34 | /// * The grid block size in x dimension, used only for squared grids (10.0)
35 | ///
36 | public double XGridBlockSize;
37 |
38 | ///
39 | /// * The grid block size in y dimension, used only for squared grids (10.0)
40 | ///
41 | public double YGridBlockSize;
42 |
43 | ///
44 | /// * The x coordinate of the upper right corner (0.0)
45 | ///
46 | public double UpperRightCornerXCoordinate;
47 |
48 | ///
49 | /// * The y coordinate of the upper right corner (0.0)
50 | ///
51 | public double UpperRightCornerYCoordinate;
52 | }
53 | }
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/Api/MeshKernelMesh2DTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace MeshKernelNETTest.Api
4 | {
5 | [TestFixture]
6 | public class MeshKernelMesh2DTest
7 | {
8 | [Test]
9 | public void Mesh2D_GetNodeXY_AccessesNodeXY()
10 | {
11 | int numRows = 3;
12 | int numColumns = 4;
13 | using (var mesh = TestUtilityFunctions.CreateMesh2D(numRows,numColumns, 15.0, 4.0, 2.0, 3.0))
14 | {
15 | for (int row = 0; row < numRows; ++row)
16 | {
17 | for (int column = 0; column < numColumns; ++column)
18 | {
19 | int index = row * numColumns + column;
20 | Assert.That(mesh.NodeX[index], Is.EqualTo(mesh.GetNodeX(index)));
21 | Assert.That(mesh.NodeY[index], Is.EqualTo(mesh.GetNodeY(index)));
22 | }
23 | }
24 | }
25 | }
26 |
27 | [TestCase(5,3,5*3)]
28 | [TestCase(15,42,15*42)]
29 | public void Mesh2D_GetNodeCount_CountsAllNodes(int nodesInRow, int nodesInColumn, int count)
30 | {
31 | using (var grid = TestUtilityFunctions.CreateMesh2D(nodesInRow,nodesInColumn, 15.0, 4.0, 2.0, 3.0))
32 | {
33 | Assert.That(grid.NodeCount(), Is.EqualTo(count));
34 | }
35 | }
36 |
37 | [TestCase(5,3,4*3+5*2)]
38 | [TestCase(15,42,15*41+14*42)]
39 | public void Mesh2D_GetEdgeCount_CountsRowOrientedAndColumnOrientedEdges(int nodesInRow, int nodesInColumn, int count)
40 | {
41 | using (var grid = TestUtilityFunctions.CreateMesh2D(nodesInRow,nodesInColumn, 15.0, 4.0, 2.0, 3.0))
42 | {
43 | Assert.That(grid.EdgeCount(), Is.EqualTo(count));
44 | }
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/SplinesToCurvilinearParametersNative.cs:
--------------------------------------------------------------------------------
1 | namespace MeshKernelNET.Native
2 | {
3 | public struct SplinesToCurvilinearParametersNative
4 | {
5 | ///
6 | /// * Aspect ratio (0.1)
7 | ///
8 | public double AspectRatio { get; set; }
9 |
10 | ///
11 | /// * Grow factor of aspect ratio (1.1)
12 | ///
13 | public double AspectRatioGrowFactor { get; set; }
14 |
15 | ///
16 | /// * Average mesh width on center spline (500.0)
17 | ///
18 | public double AverageWidth { get; set; }
19 |
20 | ///
21 | /// * Curvature adapted grid spacing, 1 or not 0 (1)
22 | ///
23 | public int CurvatureAdaptedGridSpacing { get; set; }
24 |
25 | ///
26 | /// * Grow the grid outside the prescribed grid height (1)
27 | ///
28 | public int GrowGridOutside { get; set; }
29 |
30 | ///
31 | /// * Maximum number of layers in the uniform part (5)
32 | ///
33 | public int MaximumNumberOfGridCellsInTheUniformPart { get; set; }
34 |
35 | ///
36 | /// * On-top-of-each-other tolerance (0.0001)
37 | ///
38 | public double GridsOnTopOfEachOtherTolerance { get; set; }
39 |
40 | ///
41 | /// * Minimum allowed absolute value of crossing-angle cosine (0.95)
42 | ///
43 | public double MinimumCosineOfCrossingAngles { get; set; }
44 |
45 | ///
46 | /// * Check for collisions with other parts of the front, 1 or not 0 (0)
47 | ///
48 | public int CheckFrontCollisions { get; set; }
49 |
50 | ///
51 | /// * Remove skinny triangles (1)
52 | ///
53 | public int RemoveSkinnyTriangles { get; set; }
54 | }
55 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/OrthogonalizationParameters.cs:
--------------------------------------------------------------------------------
1 | using ProtoBuf;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | [ProtoContract(AsReferenceDefault = true)]
6 | public class OrthogonalizationParameters
7 | {
8 | public static OrthogonalizationParameters CreateDefault()
9 | {
10 | return new OrthogonalizationParameters
11 | {
12 | OuterIterations = 2,
13 | BoundaryIterations = 25,
14 | InnerIterations = 25,
15 | OrthogonalizationToSmoothingFactor = 0.975,
16 | OrthogonalizationToSmoothingFactorAtBoundary = 1.0,
17 | ArealToAngleSmoothingFactor = 1.0,
18 | };
19 | }
20 |
21 | ///
22 | /// *Number of outer iterations in orthogonalization. Increase this parameter for complex grids (2)
23 | ///
24 | [ProtoMember(1)]
25 | public int OuterIterations { get; set; }
26 |
27 | ///
28 | /// *Number of boundary iterations in grid/net orthogonalization within itatp (25)
29 | ///
30 | [ProtoMember(2)]
31 | public int BoundaryIterations { get; set; }
32 |
33 | ///
34 | /// Number of inner iterations in grid/net orthogonalization within itbnd (25)
35 | ///
36 | [ProtoMember(3)]
37 | public int InnerIterations { get; set; }
38 |
39 | ///
40 | /// Factor from 0 to 1. between grid smoothing and grid orthogonality (0.975)
41 | ///
42 | [ProtoMember(4)]
43 | public double OrthogonalizationToSmoothingFactor { get; set; }
44 |
45 | ///
46 | /// Minimum ATPF on the boundary (1.0)
47 | ///
48 | [ProtoMember(5)]
49 | public double OrthogonalizationToSmoothingFactorAtBoundary { get; set; }
50 |
51 | ///
52 | /// Factor between smoother 1d0 and area-homogenizer 0d0 (1.0)
53 | ///
54 | [ProtoMember(6)]
55 | public double ArealToAngleSmoothingFactor { get; set; }
56 | }
57 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/DisposableContacts.cs:
--------------------------------------------------------------------------------
1 | using MeshKernelNET.Helpers;
2 | using MeshKernelNET.Native;
3 | using ProtoBuf;
4 |
5 | namespace MeshKernelNET.Api
6 | {
7 | [ProtoContract(AsReferenceDefault = true)]
8 | public sealed class DisposableContacts : DisposableNativeObject
9 | {
10 | [ProtoMember(1)]
11 | private int[] mesh1dIndices;
12 |
13 | [ProtoMember(2)]
14 | private int[] mesh2dIndices;
15 |
16 | [ProtoMember(3)]
17 | private int numContacts;
18 |
19 | public DisposableContacts()
20 | {
21 | }
22 |
23 | public DisposableContacts(int nContacts)
24 | {
25 | NumContacts = nContacts;
26 | Mesh1dIndices = new int[NumContacts];
27 | Mesh2dIndices = new int[NumContacts];
28 | }
29 |
30 | ~DisposableContacts()
31 | {
32 | Dispose(false);
33 | }
34 |
35 | public int[] Mesh1dIndices
36 | {
37 | get { return mesh1dIndices; }
38 | set { mesh1dIndices = value; }
39 | }
40 |
41 | public int[] Mesh2dIndices
42 | {
43 | get { return mesh2dIndices; }
44 | set { mesh2dIndices = value; }
45 | }
46 |
47 | public int NumContacts
48 | {
49 | get { return numContacts; }
50 | set { numContacts = value; }
51 | }
52 |
53 | protected override void SetNativeObject(ref ContactsNative nativeObject)
54 | {
55 | nativeObject.mesh1d_indices = GetPinnedObjectPointer(Mesh1dIndices);
56 | nativeObject.mesh2d_indices = GetPinnedObjectPointer(Mesh2dIndices);
57 | nativeObject.num_contacts = NumContacts;
58 | }
59 |
60 | public void UpdateFromNativeObject(ref ContactsNative nativeObject)
61 | {
62 | Mesh1dIndices = nativeObject.mesh1d_indices.CreateValueArray(nativeObject.num_contacts);
63 | Mesh2dIndices = nativeObject.mesh2d_indices.CreateValueArray(nativeObject.num_contacts);
64 | NumContacts = nativeObject.num_contacts;
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/MeshRefinementParametersNative.cs:
--------------------------------------------------------------------------------
1 | namespace MeshKernelNET.Native
2 | {
3 | ///
4 | /// A struct used to describe the mesh refinement parameters in a C-compatible manner
5 | ///
6 | public struct MeshRefinementParametersNative
7 | {
8 | ///
9 | /// Maximum number of refinement iterations, set to 1 if only one refinement is wanted (10)
10 | ///
11 | public int MaxNumRefinementIterations { get; set; }
12 |
13 | ///
14 | /// Whether to compute faces intersected by polygon (yes=1/no=0)
15 | ///
16 | public int RefineIntersected { get; set; }
17 |
18 | ///
19 | /// Whether to use the mass center when splitting a face in the refinement process (yes=1/no=0)
20 | ///
21 | public int UseMassCenterWhenRefining { get; set; }
22 |
23 | ///
24 | /// Minimum edge size
25 | ///
26 | public double MinEdgeSize { get; set; }
27 |
28 | ///
29 | /// Refinement criterion type
30 | ///
31 | public int RefinementType { get; set; }
32 |
33 | ///
34 | /// Connect hanging nodes at the end of the iteration, 1 yes or 0 no
35 | ///
36 | public int ConnectHangingNodes { get; set; }
37 |
38 | ///
39 | /// Take samples outside face into account , 1 yes 0 no
40 | ///
41 | public int AccountForSamplesOutside { get; set; }
42 |
43 | ///
44 | /// The number of smoothing iterations
45 | ///
46 | public int SmoothingIterations { get; set; }
47 |
48 | ///
49 | /// Maximum courant time in seconds
50 | ///
51 | public double MaxCourantTime { get; set; }
52 |
53 | ///
54 | /// Directional refinement, cannot be used when the number of smoothing iterations is larger than 0
55 | ///
56 | public int DirectionalRefinement { get; set; }
57 | }
58 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/IReadOnly2DMesh.cs:
--------------------------------------------------------------------------------
1 | namespace MeshKernelNET.Api
2 | {
3 | ///
4 | /// Topology and node locations of a general 2D mesh
5 | ///
6 | public interface IReadOnly2DMesh
7 | {
8 | ///
9 | /// The number of cells
10 | ///
11 | /// a nonnegative number representing the number of cells
12 | int CellCount();
13 |
14 | ///
15 | /// The number of edges of a cell
16 | ///
17 | /// the index of the cell
18 | /// a nonnegative number representing the number of edges of the cell
19 | int GetCellEdgeCount(int cellIndex);
20 |
21 | ///
22 | /// The total number of edges in the mesh
23 | ///
24 | /// a nonnegative number representing the number of edges
25 | int EdgeCount();
26 |
27 | ///
28 | /// The index of the first node of an edge
29 | ///
30 | /// a nonnegative number representing the node index
31 | int GetFirstNode(int edgeIndex);
32 |
33 | ///
34 | /// The index of the second node of an edge
35 | ///
36 | /// the index of the cell
37 | /// a nonnegative number representing the node index
38 | int GetLastNode(int edgeIndex);
39 |
40 |
41 | ///
42 | /// The total number of nodes in the mesh
43 | ///
44 | /// a nonnegative number representing the number of nodes
45 | int NodeCount();
46 |
47 | ///
48 | /// The x coordinate of a node
49 | ///
50 | /// the index of the cell
51 | /// the x-coordinate value of the node
52 | double GetNodeX(int nodeIndex);
53 |
54 | ///
55 | /// The y coordinate of a node
56 | ///
57 | /// the index of the cell
58 | /// the y-coordinate value of the node
59 | double GetNodeY(int nodeIndex);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/MeshKernelNET/Helpers/StringUtilityExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reflection;
4 | using System.Text;
5 | using MeshKernelNET.Api;
6 |
7 | namespace MeshKernelNET.Helpers
8 | {
9 | internal static class StringUtilityExtensions
10 | {
11 | private const char FillChar = ' ';
12 |
13 | public static byte[] GetFlattenedAsciiCodedStringArray(this string[] strings, int bufferSize)
14 | {
15 | string flattenedAsciiCodedStringArray = string.Join("", strings.Select(s => s.ToFixedLengthString(bufferSize)));
16 |
17 | return Encoding.Convert(Encoding.Unicode, Encoding.ASCII,
18 | Encoding.Unicode.GetBytes(flattenedAsciiCodedStringArray));
19 | }
20 |
21 | public static string[] GetStringArrayFromFlattenedAsciiCodedStringArray(this byte[] byteArray, int bufferSize)
22 | {
23 | string asciiString = Encoding.ASCII.GetString(byteArray);
24 | int blokSize = byteArray.Length / bufferSize;
25 | string[] strings = Enumerable.Range(0, bufferSize)
26 | .Select(i => asciiString.Substring(i * blokSize, blokSize)).ToArray();
27 |
28 | return strings.ConvertFixedLengthArray();
29 | }
30 |
31 | public static string[] GetFixedLengthStringArray(this string[] strings, int bufferSize)
32 | {
33 | for (var index = 0; index < strings.Length; index++)
34 | {
35 | strings[index] = strings[index].ToFixedLengthString(bufferSize);
36 | }
37 |
38 | return strings;
39 | }
40 |
41 | internal static string ToFixedLengthString(this string s, int bufferSize)
42 | {
43 | if (s == null)
44 | {
45 | return new string(FillChar, bufferSize);
46 | }
47 |
48 | return s.Length > bufferSize
49 | ? s.Substring(0, bufferSize) // truncate
50 | : s.PadRight(bufferSize, FillChar); // pad
51 | }
52 |
53 | public static string[] ConvertFixedLengthArray(this string[] strings)
54 | {
55 | return strings.Select(s => s.TrimEnd(FillChar)).ToArray();
56 | }
57 |
58 | internal static int GetBufferSize(this Type type, string fieldName)
59 | {
60 | return type.GetField(fieldName)?.GetCustomAttribute()?.BufferSize ?? 0;
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/Api/MeshKernelSerializationTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using MeshKernelNET.Api;
7 | using NUnit.Framework;
8 | using ProtoBuf;
9 |
10 | namespace MeshKernelNETTest.Api
11 | {
12 | [TestFixture]
13 | public class MeshKernelSerializationTest
14 | {
15 | [TestCaseSource(nameof(GetProtoContractTypes))]
16 | public void TypeWithProtoContract_HasDefaultConstructor(Type type)
17 | {
18 | ConstructorInfo defaultConstructor = type.GetConstructor(Type.EmptyTypes);
19 |
20 | Assert.That(defaultConstructor, Is.Not.Null,
21 | $"Type '{type.Name}' with proto contract must have a public parameterless constructor for protobuf serialization.");
22 | }
23 |
24 | [TestCaseSource(nameof(GetProtoContractTypes))]
25 | public void TypeWithProtoContract_CanBeInstantiated(Type type)
26 | {
27 | object instance = Activator.CreateInstance(type);
28 |
29 | Assert.That(instance, Is.Not.Null,
30 | $"Should be able to create instance of '{type.Name}' for protobuf serialization.");
31 | }
32 |
33 | [TestCaseSource(nameof(GetProtoContractTypes))]
34 | public void TypeWithProtoContract_CanBeSerializedAndDeserialized(Type type)
35 | {
36 | using (var stream = new MemoryStream())
37 | {
38 | object instance = Activator.CreateInstance(type);
39 |
40 | Serializer.Serialize(stream, instance);
41 | stream.Position = 0;
42 | object deserialized = Serializer.Deserialize(type, stream);
43 |
44 | Assert.That(deserialized, Is.Not.Null, $"Should be able to deserialize '{type.Name}'.");
45 | Assert.That(deserialized, Is.TypeOf(type), $"Deserialized object should be of type '{type.Name}'.");
46 | }
47 | }
48 |
49 | private static IEnumerable GetProtoContractTypes()
50 | {
51 | Assembly assembly = typeof(MeshKernelApi).Assembly;
52 |
53 | List protoContractTypes = assembly.GetTypes()
54 | .Where(t => t.GetCustomAttribute() != null)
55 | .OrderBy(t => t.Name)
56 | .ToList();
57 |
58 | foreach (Type type in protoContractTypes)
59 | {
60 | yield return new TestCaseData(type).SetName($"{type.Name}");
61 | }
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Native/Mesh2DNative.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace MeshKernelNET.Native
5 | {
6 | ///
7 | /// Data object for defining a 2D grid. This object will be
8 | /// used for communicating with the MeshKernel.
9 | ///
10 | [StructLayout(LayoutKind.Sequential)]
11 | public struct Mesh2DNative
12 | {
13 | ///
14 | /// The left and right face indices of each face
15 | ///
16 | public IntPtr edge_faces;
17 |
18 | ///
19 | /// The nodes composing each mesh 2d edge
20 | ///
21 | public IntPtr edge_nodes;
22 |
23 | ///
24 | /// The edges composing each face
25 | ///
26 | public IntPtr face_edges;
27 |
28 | ///
29 | /// The nodes composing each mesh 2d face
30 | ///
31 | public IntPtr face_nodes;
32 |
33 | ///
34 | /// The number of nodes for each mesh 2d face
35 | ///
36 | public IntPtr nodes_per_face;
37 |
38 | ///
39 | /// The x-coordinates of network1d nodes
40 | ///
41 | public IntPtr node_x;
42 |
43 | ///
44 | /// The y-coordinates of network1d nodes
45 | ///
46 | public IntPtr node_y;
47 |
48 | ///
49 | /// The x-coordinates of the mesh edges middle points
50 | ///
51 | public IntPtr edge_x;
52 |
53 | ///
54 | /// The y-coordinates of the mesh edges middle points
55 | ///
56 | public IntPtr edge_y;
57 |
58 | ///
59 | /// The x-coordinates of the mesh faces mass centers
60 | ///
61 | public IntPtr face_x;
62 |
63 | ///
64 | /// The y-coordinates of the mesh faces mass centers
65 | ///
66 | public IntPtr face_y;
67 |
68 | ///
69 | /// The number of mesh nodes
70 | ///
71 | public int num_nodes;
72 |
73 | ///
74 | /// The number of valid mesh nodes
75 | ///
76 | public int num_valid_nodes;
77 |
78 | ///
79 | /// The number of edges
80 | ///
81 | public int num_edges;
82 |
83 | ///
84 | /// The number of valid edges
85 | ///
86 | public int num_valid_edges;
87 |
88 | ///
89 | /// The number of faces
90 | ///
91 | public int num_faces;
92 |
93 | ///
94 | /// The total number of nodes composing the mesh 2d faces
95 | ///
96 | public int num_face_nodes;
97 | }
98 | }
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/Api/DisposableGeometryListTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using MeshKernelNET.Api;
3 | using MeshKernelNET.Native;
4 | using NUnit.Framework;
5 |
6 | namespace MeshKernelNETTest.Api
7 | {
8 | [TestFixture]
9 | public class DisposableGeometryListTest
10 | {
11 | [Test]
12 | public void WhenCallingCreateGeometryListNative_AGeometryListNativeShouldBeCreated()
13 | {
14 | //Arrange
15 | var list = new DisposableGeometryList
16 | {
17 | XCoordinates = new[] { 0.0, 1.0, 2.0, -999.0, 0.0, 1.0, 2.0 },
18 | YCoordinates = new[] { 0.0, 1.0, 2.0, -999.0, 0.0, 1.0, 2.0 },
19 | Values = new[] { 0.0, 1.0, 2.0, -999.0, 0.0, 1.0, 2.0 },
20 | NumberOfCoordinates = 7,
21 | GeometrySeparator = -999.0
22 | };
23 |
24 | using (list)
25 | {
26 | // Act
27 | GeometryListNative nativeGeometryList = list.CreateNativeObject();
28 |
29 | // Assert
30 |
31 | Assert.That(nativeGeometryList.numberOfCoordinates, Is.EqualTo(list.NumberOfCoordinates));
32 | Assert.That(nativeGeometryList.xCoordinates, Is.Not.EqualTo(IntPtr.Zero));
33 | Assert.That(nativeGeometryList.yCoordinates, Is.Not.EqualTo(IntPtr.Zero));
34 | Assert.That(nativeGeometryList.zCoordinates, Is.Not.EqualTo(IntPtr.Zero));
35 | }
36 | }
37 |
38 | [Test]
39 | public void UpdateFromNativeObjectShouldPopulateGeometryList()
40 | {
41 | // Arrange
42 | var managedList = new DisposableGeometryList();
43 | var nativeList = new DisposableGeometryList
44 | {
45 | XCoordinates = new[] { 1.0, 2.0, 3.0 },
46 | YCoordinates = new[] { 4.0, 5.0, 6.0 },
47 | Values = new[] { 7.0, 8.0, 9.0 },
48 | NumberOfCoordinates = 3,
49 | GeometrySeparator = -999.0,
50 | InnerOuterSeparator = -998.0
51 | };
52 |
53 | using (nativeList)
54 | {
55 | GeometryListNative nativeObject = nativeList.CreateNativeObject();
56 |
57 | // Act
58 | managedList.UpdateFromNativeObject(ref nativeObject);
59 |
60 | // Assert
61 | Assert.That(managedList.XCoordinates, Is.EqualTo(new[] { 1.0, 2.0, 3.0 }));
62 | Assert.That(managedList.YCoordinates, Is.EqualTo(new[] { 4.0, 5.0, 6.0 }));
63 | Assert.That(managedList.Values, Is.EqualTo(new[] { 7.0, 8.0, 9.0 }));
64 | Assert.That(managedList.NumberOfCoordinates, Is.EqualTo(3));
65 | Assert.That(managedList.GeometrySeparator, Is.EqualTo(-999.0));
66 | Assert.That(managedList.InnerOuterSeparator, Is.EqualTo(-998.0));
67 | }
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/MeshRefinementParameters.cs:
--------------------------------------------------------------------------------
1 | using ProtoBuf;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | [ProtoContract(AsReferenceDefault = true)]
6 | public class MeshRefinementParameters
7 | {
8 | public static MeshRefinementParameters CreateDefault()
9 | {
10 | return new MeshRefinementParameters
11 | {
12 | MaxNumRefinementIterations = 10,
13 | RefineIntersected = false,
14 | UseMassCenterWhenRefining = true,
15 | MinEdgeSize = 0.5,
16 | RefinementType = MeshRefinementTypes.RefinementLevels,
17 | ConnectHangingNodes = true,
18 | AccountForSamplesOutside = false,
19 | SmoothingIterations = 5,
20 | MaxCourantTime = 120.0,
21 | DirectionalRefinement = false
22 | };
23 | }
24 |
25 | ///
26 | /// Maximum number of refinement iterations, set to 1 if only one refinement is wanted (10)
27 | ///
28 | [ProtoMember(1)]
29 | public int MaxNumRefinementIterations { get; set; }
30 |
31 | ///
32 | /// Whether to compute faces intersected by polygon (yes=1/no=0)
33 | ///
34 | [ProtoMember(2)]
35 | public bool RefineIntersected { get; set; }
36 |
37 | ///
38 | /// Whether to use the mass center when splitting a face in the refinement process (yes=1/no=0)
39 | ///
40 | [ProtoMember(3)]
41 | public bool UseMassCenterWhenRefining { get; set; }
42 |
43 | ///
44 | /// Minimum edge size
45 | ///
46 | [ProtoMember(4)]
47 | public double MinEdgeSize { get; set; }
48 |
49 | ///
50 | /// Refinement criterion type
51 | ///
52 | [ProtoMember(5)]
53 | public MeshRefinementTypes RefinementType { get; set; }
54 |
55 | ///
56 | /// Connect hanging nodes at the end of the iteration, 1 yes or 0 no
57 | ///
58 | [ProtoMember(6)]
59 | public bool ConnectHangingNodes { get; set; }
60 |
61 | ///
62 | /// Take samples outside face into account , 1 yes 0 no
63 | ///
64 | [ProtoMember(7)]
65 | public bool AccountForSamplesOutside { get; set; }
66 |
67 | ///
68 | /// The number of smoothing iterations
69 | ///
70 | [ProtoMember(8)]
71 | public int SmoothingIterations { get; set; }
72 |
73 | ///
74 | /// Maximum courant time in seconds
75 | ///
76 | [ProtoMember(9)]
77 | public double MaxCourantTime { get; set; }
78 |
79 | ///
80 | /// Directional refinement, cannot be used when the number of smoothing iterations is larger than 0
81 | ///
82 | [ProtoMember(10)]
83 | public bool DirectionalRefinement { get; set; }
84 | }
85 | }
--------------------------------------------------------------------------------
/MeshKernelNET.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31402.337
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MeshKernelNET", "src\MeshKernelNET\MeshKernelNET.csproj", "{BC6B4877-9099-4959-AB56-BE28538FB539}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D13A0EA4-B770-4003-A8E5-6ECEF1591740}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{6E2D9D61-87C3-43CB-954F-D4D6D02BC6D2}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeshKernelNETTest", "test\MeshKernelNETTest\MeshKernelNETTest.csproj", "{CCABD237-C42C-4A32-8C52-E6B4B0BE6EAA}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution items", "{FB4DB790-09C4-4844-ABE9-4FB1C34119B9}"
15 | ProjectSection(SolutionItems) = preProject
16 | Directory.Build.props = Directory.Build.props
17 | Directory.Packages.props = Directory.Packages.props
18 | EndProjectSection
19 | EndProject
20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeshKernelNET.Generators", "src\MeshKernelNET.Generators\MeshKernelNET.Generators.csproj", "{C9A9F408-CC49-4E5D-9F53-E92E1B44BC45}"
21 | EndProject
22 | Global
23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
24 | Debug|Any CPU = Debug|Any CPU
25 | Release|Any CPU = Release|Any CPU
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {BC6B4877-9099-4959-AB56-BE28538FB539}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {BC6B4877-9099-4959-AB56-BE28538FB539}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {BC6B4877-9099-4959-AB56-BE28538FB539}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {BC6B4877-9099-4959-AB56-BE28538FB539}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {CCABD237-C42C-4A32-8C52-E6B4B0BE6EAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {CCABD237-C42C-4A32-8C52-E6B4B0BE6EAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {CCABD237-C42C-4A32-8C52-E6B4B0BE6EAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {CCABD237-C42C-4A32-8C52-E6B4B0BE6EAA}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {C9A9F408-CC49-4E5D-9F53-E92E1B44BC45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {C9A9F408-CC49-4E5D-9F53-E92E1B44BC45}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {C9A9F408-CC49-4E5D-9F53-E92E1B44BC45}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {C9A9F408-CC49-4E5D-9F53-E92E1B44BC45}.Release|Any CPU.Build.0 = Release|Any CPU
40 | EndGlobalSection
41 | GlobalSection(SolutionProperties) = preSolution
42 | HideSolutionNode = FALSE
43 | EndGlobalSection
44 | GlobalSection(NestedProjects) = preSolution
45 | {BC6B4877-9099-4959-AB56-BE28538FB539} = {D13A0EA4-B770-4003-A8E5-6ECEF1591740}
46 | {CCABD237-C42C-4A32-8C52-E6B4B0BE6EAA} = {6E2D9D61-87C3-43CB-954F-D4D6D02BC6D2}
47 | {C9A9F408-CC49-4E5D-9F53-E92E1B44BC45} = {D13A0EA4-B770-4003-A8E5-6ECEF1591740}
48 | EndGlobalSection
49 | GlobalSection(ExtensibilityGlobals) = postSolution
50 | SolutionGuid = {95422719-9EC8-468E-A6B3-42F5DDA562E8}
51 | EndGlobalSection
52 | EndGlobal
53 |
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/SplinesToCurvilinearParameters.cs:
--------------------------------------------------------------------------------
1 | using ProtoBuf;
2 |
3 | namespace MeshKernelNET.Api
4 | {
5 | [ProtoContract(AsReferenceDefault = true)]
6 | public class SplinesToCurvilinearParameters
7 | {
8 | public static SplinesToCurvilinearParameters CreateDefault()
9 | {
10 | return new SplinesToCurvilinearParameters
11 | {
12 | AspectRatio = 0.1,
13 | AspectRatioGrowFactor = 1.1,
14 | AverageWidth = 500.0,
15 | CurvatureAdaptedGridSpacing = true,
16 | GrowGridOutside = true,
17 | MaximumNumberOfGridCellsInTheUniformPart = 5,
18 | GridsOnTopOfEachOtherTolerance = 0.0001,
19 | MinimumCosineOfCrossingAngles = 0.95,
20 | CheckFrontCollisions = false,
21 | UniformGridSize = 0.0,
22 | RemoveSkinnyTriangles = true,
23 | };
24 | }
25 |
26 | ///
27 | /// * Aspect ratio (0.1)
28 | ///
29 | [ProtoMember(1)]
30 | public double AspectRatio { get; set; }
31 |
32 | ///
33 | /// * Grow factor of aspect ratio (1.1)
34 | ///
35 | [ProtoMember(2)]
36 | public double AspectRatioGrowFactor { get; set; }
37 |
38 | ///
39 | /// * Average mesh width on center spline (0.005)
40 | ///
41 | [ProtoMember(3)]
42 | public double AverageWidth { get; set; }
43 |
44 | ///
45 | /// * Curvature adapted grid spacing, 1 or not 0 (1)
46 | ///
47 | [ProtoMember(4)]
48 | public bool CurvatureAdaptedGridSpacing { get; set; }
49 |
50 | ///
51 | /// * Grow the grid outside the prescribed grid height (1)
52 | ///
53 | [ProtoMember(5)]
54 | public bool GrowGridOutside { get; set; }
55 |
56 | ///
57 | /// * Maximum number of layers in the uniform part (5)
58 | ///
59 | [ProtoMember(6)]
60 | public int MaximumNumberOfGridCellsInTheUniformPart { get; set; }
61 |
62 | ///
63 | /// * On-top-of-each-other tolerance (0.0001)
64 | ///
65 | [ProtoMember(7)]
66 | public double GridsOnTopOfEachOtherTolerance { get; set; }
67 |
68 | ///
69 | /// * Minimum allowed absolute value of crossing-angle cosine (0.95)
70 | ///
71 | [ProtoMember(8)]
72 | public double MinimumCosineOfCrossingAngles { get; set; }
73 |
74 | ///
75 | /// * Check for collisions with other parts of the front, 1 or not 0 (0)
76 | ///
77 | [ProtoMember(9)]
78 | public bool CheckFrontCollisions { get; set; }
79 |
80 | ///
81 | /// * Uniform grid size, netboundary to grid only (0.0)
82 | ///
83 | [ProtoMember(10)]
84 | public double UniformGridSize { get; set; }
85 |
86 | ///
87 | /// * Remove skinny triangles (1)
88 | ///
89 | [ProtoMember(11)]
90 | public bool RemoveSkinnyTriangles { get; set; }
91 | }
92 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Helpers/NativeLibrary.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.IO;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 |
7 | namespace MeshKernelNET.Helpers
8 | {
9 | ///
10 | /// Helper functions for loading native libraries
11 | ///
12 | internal static class NativeLibrary
13 | {
14 | [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
15 | private static extern IntPtr LoadLibrary(string lpFileName);
16 |
17 | ///
18 | /// Loads the provided native dll ( and )
19 | /// for the current process.
20 | ///
21 | ///
22 | /// Call this from a static constructor in a class that has DllImport external methods. This
23 | /// method uses LoadLibrary to load the correct dll for the current process (32bit or 64bit)
24 | /// before DllImport has the chance to resolve the external calls. As long as the dll name is
25 | /// the same this works.
26 | ///
27 | /// The dll file to load.
28 | /// The directory to load the dll from.
29 | public static void LoadNativeDll(string dllFileName, string directory)
30 | {
31 | using (new SwitchDllSearchDirectoryHelper(directory))
32 | {
33 | // attempt to load the library
34 | IntPtr ptr = LoadLibrary(dllFileName);
35 | if (ptr != IntPtr.Zero)
36 | {
37 | return;
38 | }
39 |
40 | int error = Marshal.GetLastWin32Error();
41 | var exception = new Win32Exception(error);
42 |
43 | var messageCouldNotFind = $"Could not find / load {dllFileName}";
44 | var messageError = $"Error: {error} - {exception.Message}";
45 | var messageFile = $"{"File"}: {directory}\\{dllFileName}";
46 |
47 | throw new FileNotFoundException(string.Join(Environment.NewLine, messageCouldNotFind, messageError, messageFile));
48 | }
49 | }
50 |
51 | private sealed class SwitchDllSearchDirectoryHelper : IDisposable
52 | {
53 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
54 | private static extern int GetDllDirectory(int nBufferLength, StringBuilder lpPathName);
55 |
56 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
57 | private static extern void SetDllDirectory(string lpPathName);
58 |
59 | private readonly string oldDirectory;
60 |
61 | public SwitchDllSearchDirectoryHelper(string dllDirectory)
62 | {
63 | oldDirectory = GetDllDirectory();
64 | SetDllDirectory(dllDirectory);
65 | }
66 |
67 | public void Dispose()
68 | {
69 | SetDllDirectory(oldDirectory);
70 | }
71 |
72 | private static string GetDllDirectory()
73 | {
74 | var tmp = new StringBuilder(4096);
75 | GetDllDirectory(4096, tmp);
76 | return tmp.ToString();
77 | }
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET.Generators/RemoteApiGenerator.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics.CodeAnalysis;
2 | using System.Linq;
3 | using System.Text;
4 | using Microsoft.CodeAnalysis;
5 | using Microsoft.CodeAnalysis.CSharp.Syntax;
6 |
7 | namespace MeshKernelNET.Generators;
8 |
9 | [Generator]
10 | [ExcludeFromCodeCoverage]
11 | public class RemoteApiGenerator : IIncrementalGenerator
12 | {
13 | private const string interfaceName = "IMeshKernelApi";
14 | private const string implementationName = "RemoteMeshKernelApi";
15 |
16 | private static readonly SymbolDisplayFormat typeNameOnlyFormat = new(
17 | typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly,
18 | genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
19 | miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes
20 | );
21 |
22 | public void Initialize(IncrementalGeneratorInitializationContext context)
23 | {
24 | var interfaceDeclaration = context.SyntaxProvider.CreateSyntaxProvider(
25 | predicate: (node, _) => node is InterfaceDeclarationSyntax { Identifier.Text: interfaceName },
26 | transform: (ctx, _) => (InterfaceDeclaration: (InterfaceDeclarationSyntax)ctx.Node, ctx.SemanticModel)
27 | );
28 |
29 | context.RegisterSourceOutput(interfaceDeclaration, (spc, data) =>
30 | {
31 | var (interfaceSyntax, semanticModel) = data;
32 |
33 | if (semanticModel.GetDeclaredSymbol(interfaceSyntax) is not INamedTypeSymbol typeSymbol)
34 | return;
35 |
36 | var sb = new StringBuilder();
37 |
38 | sb.AppendLine("using System;");
39 | sb.AppendLine("using System.Diagnostics.CodeAnalysis;");
40 | sb.AppendLine();
41 | sb.AppendLine($"namespace {typeSymbol.ContainingNamespace}");
42 | sb.AppendLine("{");
43 | sb.AppendLine(" /// ");
44 | sb.AppendLine($" /// Remote wrapper for that executes operations in a separate process.");
45 | sb.AppendLine(" /// ");
46 | sb.AppendLine(" [ExcludeFromCodeCoverage]");
47 | sb.AppendLine($" public sealed partial class {implementationName}");
48 | sb.AppendLine(" {");
49 |
50 | foreach (IMethodSymbol method in typeSymbol.GetMembers().OfType())
51 | {
52 | if (method.MethodKind != MethodKind.Ordinary)
53 | continue;
54 |
55 | string methodName = method.Name;
56 | string returnType = method.ReturnType.ToDisplayString(typeNameOnlyFormat);
57 |
58 | string parameters = string.Join(", ", method.Parameters.Select(p =>
59 | $"{GetRefModifier(p.RefKind)}{p.Type.ToDisplayString(typeNameOnlyFormat)} {p.Name}"));
60 |
61 | string arguments = string.Join(", ", method.Parameters.Select(p =>
62 | $"{GetRefModifier(p.RefKind)}{p.Name}"));
63 |
64 | sb.AppendLine(" /// ");
65 | sb.AppendLine($" public {returnType} {methodName}({parameters}) => api.{methodName}({arguments});");
66 | }
67 |
68 | sb.AppendLine(" }");
69 | sb.AppendLine("}");
70 |
71 | spc.AddSource($"{implementationName}.g.cs", sb.ToString());
72 | });
73 | }
74 |
75 | private static string GetRefModifier(RefKind refKind) =>
76 | refKind == RefKind.None ? "" : refKind.ToString().ToLower() + " ";
77 | }
78 |
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/DisposableMesh1D.cs:
--------------------------------------------------------------------------------
1 | using MeshKernelNET.Helpers;
2 | using MeshKernelNET.Native;
3 | using ProtoBuf;
4 |
5 | namespace MeshKernelNET.Api
6 | {
7 | [ProtoContract(AsReferenceDefault = true)]
8 | public sealed class DisposableMesh1D : DisposableNativeObject
9 | {
10 | [ProtoMember(1)]
11 | private int[] edgeNodes;
12 |
13 | [ProtoMember(2)]
14 | private double[] nodeX;
15 |
16 | [ProtoMember(3)]
17 | private double[] nodeY;
18 |
19 | [ProtoMember(4)]
20 | private int numNodes;
21 |
22 | [ProtoMember(5)]
23 | private int numValidNodes;
24 |
25 | [ProtoMember(6)]
26 | private int numEdges;
27 |
28 | [ProtoMember(7)]
29 | private int numValidEdges;
30 |
31 | public DisposableMesh1D()
32 | {
33 | }
34 |
35 | public DisposableMesh1D(int nNodes, int nEdges)
36 | {
37 | NumNodes = nNodes;
38 | NumEdges = nEdges;
39 |
40 | EdgeNodes = new int[NumEdges * 2];
41 | NodeX = new double[NumNodes];
42 | NodeY = new double[NumNodes];
43 | }
44 |
45 | ~DisposableMesh1D()
46 | {
47 | Dispose(false);
48 | }
49 |
50 | public int[] EdgeNodes
51 | {
52 | get { return edgeNodes; }
53 | set { edgeNodes = value; }
54 | }
55 |
56 | public double[] NodeX
57 | {
58 | get { return nodeX; }
59 | set { nodeX = value; }
60 | }
61 |
62 | public double[] NodeY
63 | {
64 | get { return nodeY; }
65 | set { nodeY = value; }
66 | }
67 |
68 | public int NumNodes
69 | {
70 | get { return numNodes; }
71 | set { numNodes = value; }
72 | }
73 |
74 | public int NumValidNodes
75 | {
76 | get { return numValidNodes; }
77 | set { numValidNodes = value; }
78 | }
79 |
80 | public int NumEdges
81 | {
82 | get { return numEdges; }
83 | set { numEdges = value; }
84 | }
85 |
86 | public int NumValidEdges
87 | {
88 | get { return numValidEdges; }
89 | set { numValidEdges = value; }
90 | }
91 |
92 | protected override void SetNativeObject(ref Mesh1DNative nativeObject)
93 | {
94 | nativeObject.edge_nodes = GetPinnedObjectPointer(EdgeNodes);
95 | nativeObject.node_x = GetPinnedObjectPointer(NodeX);
96 | nativeObject.node_y = GetPinnedObjectPointer(NodeY);
97 | nativeObject.num_valid_nodes = numValidNodes;
98 | nativeObject.num_nodes = NumNodes;
99 | nativeObject.num_edges = NumEdges;
100 | nativeObject.num_valid_edges = numValidEdges;
101 | }
102 |
103 | public void UpdateFromNativeObject(ref Mesh1DNative nativeObject)
104 | {
105 | EdgeNodes = nativeObject.edge_nodes.CreateValueArray(nativeObject.num_edges * 2);
106 | NodeX = nativeObject.node_x.CreateValueArray(nativeObject.num_nodes);
107 | NodeY = nativeObject.node_y.CreateValueArray(nativeObject.num_nodes);
108 | NumValidNodes = nativeObject.num_valid_nodes;
109 | NumNodes = nativeObject.num_nodes;
110 | NumEdges = nativeObject.num_edges;
111 | NumValidEdges = nativeObject.num_valid_edges;
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/Api/MeshKernelNetwork1dTest.cs:
--------------------------------------------------------------------------------
1 | using MeshKernelNET.Api;
2 | using NUnit.Framework;
3 |
4 | namespace MeshKernelNETTest.Api
5 | {
6 | [TestFixture]
7 | public class MeshKernelNETNetwork1DTests
8 | {
9 | [Test]
10 | public void Network1dComputeFixedChainagesThroughAPI()
11 | {
12 | // Setup
13 | using (var api = new MeshKernelApi())
14 | using (var network1d = new DisposableGeometryList())
15 | {
16 | var id = 0;
17 | var mesh1D = new DisposableMesh1D();
18 | try
19 | {
20 | id = api.AllocateState(0);
21 |
22 | double separator = api.GetSeparator();
23 | network1d.XCoordinates = new[] { 0.0, 10.0, 20.0, separator, 10.0, 10.0, 10.0 };
24 | network1d.YCoordinates = new[] { 0.0, 0.0, 0.0, separator, -10.0, 0.0, 10.0 };
25 | network1d.GeometrySeparator = separator;
26 | network1d.NumberOfCoordinates = 7;
27 |
28 | Assert.That(api.Network1dSet(id, network1d), Is.EqualTo(0));
29 |
30 | double[] fixedChainages = { 5.0, separator, 5.0 };
31 | var minFaceSize = 0.01;
32 | var fixedChainagesOffset = 10.0;
33 |
34 | Assert.That(api.Network1dComputeFixedChainages(id, fixedChainages, minFaceSize, fixedChainagesOffset), Is.EqualTo(0));
35 | Assert.That(api.Network1dToMesh1d(id, minFaceSize), Is.EqualTo(0));
36 |
37 | Assert.That(api.Mesh1dGetData(id, out mesh1D), Is.EqualTo(0));
38 |
39 | Assert.That(mesh1D.NumNodes, Is.EqualTo(6));
40 | Assert.That(mesh1D.NumEdges, Is.EqualTo(4));
41 | }
42 | finally
43 | {
44 | api.ClearState();
45 | mesh1D.Dispose();
46 | }
47 | }
48 | }
49 |
50 | [Test]
51 | public void Network1dComputeOffsettedChainagesThroughAPI()
52 | {
53 | // Setup
54 | using (var api = new MeshKernelApi())
55 | using (var network1d = new DisposableGeometryList())
56 | {
57 | var id = 0;
58 | var mesh1D = new DisposableMesh1D();
59 | try
60 | {
61 | id = api.AllocateState(0);
62 |
63 | double separator = api.GetSeparator();
64 | network1d.XCoordinates = new[] { 0.0, 10.0, 20.0, separator, 10.0, 10.0, 10.0 };
65 | network1d.YCoordinates = new[] { 0.0, 0.0, 0.0, separator, -10.0, 0.0, 10.0 };
66 | network1d.GeometrySeparator = separator;
67 | network1d.NumberOfCoordinates = 7;
68 |
69 | Assert.That(api.Network1dSet(id, network1d), Is.EqualTo(0));
70 |
71 | var minFaceSize = 0.01;
72 | var fixedChainagesOffset = 1.0;
73 |
74 | Assert.That(api.Network1dComputeOffsettedChainages(id, fixedChainagesOffset), Is.EqualTo(0));
75 | Assert.That(api.Network1dToMesh1d(id, minFaceSize), Is.EqualTo(0));
76 | Assert.That(api.Mesh1dGetData(id, out mesh1D), Is.EqualTo(0));
77 |
78 | Assert.That(mesh1D.NumEdges, Is.EqualTo(40));
79 | Assert.That(mesh1D.NumValidNodes, Is.EqualTo(41));
80 | }
81 | finally
82 | {
83 | api.ClearState();
84 | mesh1D.Dispose();
85 | }
86 | }
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/Api/DisposableMesh2DTest.cs:
--------------------------------------------------------------------------------
1 | using MeshKernelNET.Api;
2 | using MeshKernelNET.Native;
3 | using NUnit.Framework;
4 |
5 | namespace MeshKernelNETTest.Api
6 | {
7 | [TestFixture]
8 | public class DisposableMesh2DTest
9 | {
10 | [Test]
11 | public void UpdateFromNativeObjectShouldPopulateMesh2D()
12 | {
13 | // Arrange
14 | var managedMesh = new DisposableMesh2D();
15 | var nativeMesh = new DisposableMesh2D(4, 4, 1, 4, 4, 4)
16 | {
17 | NodeX = new[] { 0.0, 1.0, 1.0, 0.0 },
18 | NodeY = new[] { 0.0, 0.0, 1.0, 1.0 },
19 | EdgeNodes = new[] { 0, 1, 1, 2, 2, 3, 3, 0 },
20 | EdgeX = new[] { 0.5, 1.0, 0.5, 0.0 },
21 | EdgeY = new[] { 0.0, 0.5, 1.0, 0.5 },
22 | FaceX = new[] { 0.5 },
23 | FaceY = new[] { 0.5 },
24 | FaceNodes = new[] { 0, 1, 2, 3 },
25 | NodesPerFace = new[] { 4 },
26 | NumValidNodes = 4,
27 | NumValidEdges = 4
28 | };
29 |
30 | using (nativeMesh)
31 | {
32 | Mesh2DNative nativeObject = nativeMesh.CreateNativeObject();
33 |
34 | // Act
35 | managedMesh.UpdateFromNativeObject(ref nativeObject, true);
36 |
37 | // Assert
38 | Assert.That(managedMesh.NodeX, Is.EqualTo(new[] { 0.0, 1.0, 1.0, 0.0 }));
39 | Assert.That(managedMesh.NodeY, Is.EqualTo(new[] { 0.0, 0.0, 1.0, 1.0 }));
40 | Assert.That(managedMesh.EdgeNodes, Is.EqualTo(new[] { 0, 1, 1, 2, 2, 3, 3, 0 }));
41 | Assert.That(managedMesh.FaceX, Is.EqualTo(new[] { 0.5 }));
42 | Assert.That(managedMesh.FaceY, Is.EqualTo(new[] { 0.5 }));
43 | Assert.That(managedMesh.FaceNodes, Is.EqualTo(new[] { 0, 1, 2, 3 }));
44 | Assert.That(managedMesh.NodesPerFace, Is.EqualTo(new[] { 4 }));
45 | Assert.That(managedMesh.NumNodes, Is.EqualTo(4));
46 | Assert.That(managedMesh.NumEdges, Is.EqualTo(4));
47 | Assert.That(managedMesh.NumFaces, Is.EqualTo(1));
48 | Assert.That(managedMesh.NumValidNodes, Is.EqualTo(4));
49 | Assert.That(managedMesh.NumValidEdges, Is.EqualTo(4));
50 | }
51 | }
52 |
53 | [Test]
54 | public void UpdateFromNativeObjectWithoutCellInformationShouldNotPopulateFaceData()
55 | {
56 | // Arrange
57 | var managedMesh = new DisposableMesh2D();
58 | var nativeMesh = new DisposableMesh2D(4, 4, 1, 4, 4, 4)
59 | {
60 | NodeX = new[] { 0.0, 1.0, 1.0, 0.0 },
61 | NodeY = new[] { 0.0, 0.0, 1.0, 1.0 },
62 | EdgeNodes = new[] { 0, 1, 1, 2, 2, 3, 3, 0 },
63 | EdgeX = new[] { 0.5, 1.0, 0.5, 0.0 },
64 | EdgeY = new[] { 0.0, 0.5, 1.0, 0.5 },
65 | FaceX = new[] { 0.5 },
66 | FaceY = new[] { 0.5 },
67 | FaceNodes = new[] { 0, 1, 2, 3 },
68 | NodesPerFace = new[] { 4 },
69 | NumValidNodes = 4,
70 | NumValidEdges = 4
71 | };
72 |
73 | using (nativeMesh)
74 | {
75 | Mesh2DNative nativeObject = nativeMesh.CreateNativeObject();
76 |
77 | // Act
78 | managedMesh.UpdateFromNativeObject(ref nativeObject, false);
79 |
80 | // Assert
81 | Assert.That(managedMesh.NodeX, Is.EqualTo(new[] { 0.0, 1.0, 1.0, 0.0 }));
82 | Assert.That(managedMesh.NodeY, Is.EqualTo(new[] { 0.0, 0.0, 1.0, 1.0 }));
83 | Assert.That(managedMesh.EdgeNodes, Is.EqualTo(new[] { 0, 1, 1, 2, 2, 3, 3, 0 }));
84 | Assert.That(managedMesh.NumNodes, Is.EqualTo(4));
85 | Assert.That(managedMesh.NumEdges, Is.EqualTo(4));
86 | Assert.That(managedMesh.FaceNodes, Is.Null);
87 | Assert.That(managedMesh.NodesPerFace, Is.Null);
88 | }
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/DisposableGeometryList.cs:
--------------------------------------------------------------------------------
1 | using MeshKernelNET.Helpers;
2 | using MeshKernelNET.Native;
3 | using ProtoBuf;
4 |
5 | namespace MeshKernelNET.Api
6 | {
7 | [ProtoContract(AsReferenceDefault = true)]
8 | public sealed class DisposableGeometryList : DisposableNativeObject
9 | {
10 | [ProtoMember(1)]
11 | private double geometrySeparator;
12 |
13 | [ProtoMember(2)]
14 | private double innerOuterSeparator;
15 |
16 | [ProtoMember(3)]
17 | private int numberOfCoordinates;
18 |
19 | [ProtoMember(4)]
20 | private double[] xCoordinates;
21 |
22 | [ProtoMember(5)]
23 | private double[] yCoordinates;
24 |
25 | [ProtoMember(6)]
26 | private double[] values;
27 |
28 | public DisposableGeometryList()
29 | {
30 | }
31 |
32 | public DisposableGeometryList(int numberOfCoordinates)
33 | {
34 | NumberOfCoordinates = numberOfCoordinates;
35 | XCoordinates = new double[numberOfCoordinates];
36 | YCoordinates = new double[numberOfCoordinates];
37 | Values = new double[numberOfCoordinates];
38 | }
39 |
40 | ~DisposableGeometryList()
41 | {
42 | Dispose(false);
43 | }
44 |
45 | ///
46 | /// Separator used for separating multiple geometries
47 | ///
48 | public double GeometrySeparator
49 | {
50 | get { return geometrySeparator; }
51 | set { geometrySeparator = value; }
52 | }
53 |
54 | ///
55 | /// Separator used for separating the outer and inner rings of a polygon geometry
56 | ///
57 | public double InnerOuterSeparator
58 | {
59 | get { return innerOuterSeparator; }
60 | set { innerOuterSeparator = value; }
61 | }
62 |
63 | ///
64 | /// Total number of coordinates (including separators)
65 | ///
66 | public int NumberOfCoordinates
67 | {
68 | get { return numberOfCoordinates; }
69 | set { numberOfCoordinates = value; }
70 | }
71 |
72 | ///
73 | /// The x coordinates of the geometries
74 | ///
75 | public double[] XCoordinates
76 | {
77 | get { return xCoordinates; }
78 | set { xCoordinates = value; }
79 | }
80 |
81 | ///
82 | /// The y coordinates of the geometries
83 | ///
84 | public double[] YCoordinates
85 | {
86 | get { return yCoordinates; }
87 | set { yCoordinates = value; }
88 | }
89 |
90 | ///
91 | /// The values for the coordinates of the geometries
92 | ///
93 | public double[] Values
94 | {
95 | get { return values; }
96 | set { values = value; }
97 | }
98 |
99 | protected override void SetNativeObject(ref GeometryListNative nativeObject)
100 | {
101 | nativeObject.xCoordinates = GetPinnedObjectPointer(XCoordinates);
102 | nativeObject.yCoordinates = GetPinnedObjectPointer(YCoordinates);
103 | nativeObject.zCoordinates = GetPinnedObjectPointer(Values);
104 | nativeObject.numberOfCoordinates = NumberOfCoordinates;
105 | nativeObject.geometrySeperator = GeometrySeparator;
106 | nativeObject.innerOuterSeperator = InnerOuterSeparator;
107 | }
108 |
109 | public void UpdateFromNativeObject(ref GeometryListNative nativeObject)
110 | {
111 | XCoordinates = nativeObject.xCoordinates.CreateValueArray(nativeObject.numberOfCoordinates);
112 | YCoordinates = nativeObject.yCoordinates.CreateValueArray(nativeObject.numberOfCoordinates);
113 | Values = nativeObject.zCoordinates.CreateValueArray(nativeObject.numberOfCoordinates);
114 | NumberOfCoordinates = nativeObject.numberOfCoordinates;
115 | GeometrySeparator = nativeObject.geometrySeperator;
116 | InnerOuterSeparator = nativeObject.innerOuterSeperator;
117 | }
118 | }
119 | }
--------------------------------------------------------------------------------
/test/MeshKernelNETTest/Api/MeshKernelTestUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Globalization;
5 | using System.Linq;
6 | using MeshKernelNET.Api;
7 |
8 | namespace MeshKernelNETTest.Api
9 | {
10 | public static class TestUtilityFunctions
11 | {
12 | public static DisposableMesh2D CreateMesh2D(
13 | int numbOfNodesHorizontal,
14 | int numbOfNodesVertical,
15 | double cellWidth,
16 | double cellHeight,
17 | double xOffset = 0.0,
18 | double yOffset = 0.0)
19 | {
20 | var result = new DisposableMesh2D();
21 |
22 | var indicesValues = new int[numbOfNodesVertical, numbOfNodesHorizontal];
23 | result.NodeX = new double[numbOfNodesHorizontal * numbOfNodesVertical];
24 | result.NodeY = new double[numbOfNodesHorizontal * numbOfNodesVertical];
25 | result.NumNodes = numbOfNodesHorizontal * numbOfNodesVertical;
26 |
27 | var nodeIndex = 0;
28 | for (var v = 0; v < numbOfNodesVertical; ++v)
29 | {
30 | for (var h = 0; h < numbOfNodesHorizontal; ++h)
31 | {
32 | indicesValues[v, h] = (v * numbOfNodesHorizontal) + h;
33 | result.NodeX[nodeIndex] = xOffset + (h * cellWidth);
34 | result.NodeY[nodeIndex] = yOffset + (v * cellHeight);
35 | nodeIndex++;
36 | }
37 | }
38 |
39 | result.NumEdges = ((numbOfNodesHorizontal - 1) * numbOfNodesVertical) +
40 | (numbOfNodesHorizontal * (numbOfNodesVertical - 1));
41 | result.EdgeNodes = new int[result.NumEdges * 2];
42 | var edgeIndex = 0;
43 | for (var v = 0; v < numbOfNodesVertical - 1; ++v)
44 | {
45 | for (var h = 0; h < numbOfNodesHorizontal; ++h)
46 | {
47 | result.EdgeNodes[edgeIndex] = indicesValues[v,h];
48 | edgeIndex++;
49 | result.EdgeNodes[edgeIndex] = indicesValues[v + 1, h];
50 | edgeIndex++;
51 | }
52 | }
53 |
54 | for (var v = 0; v < numbOfNodesVertical; ++v)
55 | {
56 | for (var h = 0; h < numbOfNodesHorizontal - 1; ++h)
57 | {
58 | result.EdgeNodes[edgeIndex] = indicesValues[v, h];
59 | edgeIndex++;
60 | result.EdgeNodes[edgeIndex] = indicesValues[v, h + 1];
61 | edgeIndex++;
62 | }
63 | }
64 |
65 | return result;
66 | }
67 |
68 | public static DisposableCurvilinearGrid CreateCurvilinearGrid(
69 | int numbOfRows = 3,
70 | int numbOfColumns = 3,
71 | double cellWidth = 1.0,
72 | double cellHeight = 1.0)
73 | {
74 | var result = new DisposableCurvilinearGrid(numbOfRows, numbOfColumns);
75 |
76 | var nodeIndex = 0;
77 | for (var v = 0; v < result.NumN; ++v)
78 | {
79 | for (var h = 0; h < result.NumM; ++h)
80 | {
81 | result.NodeX[nodeIndex] = h * cellWidth;
82 | result.NodeY[nodeIndex] = v * cellHeight;
83 | nodeIndex++;
84 | }
85 | }
86 |
87 | return result;
88 | }
89 |
90 | public static void GetTiming(Stopwatch stopwatch, string actionName, Action action)
91 | {
92 | stopwatch.Restart();
93 |
94 | action();
95 |
96 | stopwatch.Stop();
97 | Console.WriteLine($"{stopwatch.Elapsed} -- {actionName}");
98 | }
99 |
100 | public static string AsString(IEnumerable sequence)
101 | {
102 | return "[" + string.Join(",", sequence.Select(x =>
103 | {
104 | if (x is IFormattable formattable)
105 | {
106 | return formattable.ToString(null, CultureInfo.InvariantCulture);
107 | }
108 | return x?.ToString();
109 | })) + "]";
110 | }
111 |
112 | }
113 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/DisposableCurvilinearGrid.cs:
--------------------------------------------------------------------------------
1 | using MeshKernelNET.Helpers;
2 | using MeshKernelNET.Native;
3 | using ProtoBuf;
4 |
5 | namespace MeshKernelNET.Api
6 | {
7 | [ProtoContract(AsReferenceDefault = true)]
8 | public sealed class DisposableCurvilinearGrid : DisposableNativeObject, IReadOnly2DMesh
9 | {
10 | [ProtoMember(1)]
11 | private double[] nodeX;
12 |
13 | [ProtoMember(2)]
14 | private double[] nodeY;
15 |
16 | [ProtoMember(3)]
17 | private int numM;
18 |
19 | [ProtoMember(4)]
20 | private int numN;
21 |
22 | public DisposableCurvilinearGrid()
23 | {
24 | }
25 |
26 | public DisposableCurvilinearGrid(int nN, int nM)
27 | {
28 | numM = nM;
29 | numN = nN;
30 | int NumNodes = numM * numN;
31 |
32 | NodeX = new double[NumNodes];
33 | NodeY = new double[NumNodes];
34 | }
35 |
36 | ~DisposableCurvilinearGrid()
37 | {
38 | Dispose(false);
39 | }
40 |
41 | public double[] NodeX
42 | {
43 | get { return nodeX; }
44 | set { nodeX = value; }
45 | }
46 |
47 | public double[] NodeY
48 | {
49 | get { return nodeY; }
50 | set { nodeY = value; }
51 | }
52 |
53 | public int NumM
54 | {
55 | get { return numM; }
56 | set { numM = value; }
57 | }
58 |
59 | public int NumN
60 | {
61 | get { return numN; }
62 | set { numN = value; }
63 | }
64 |
65 | #region IReadOnly2DMesh
66 | ///
67 | public int CellCount()
68 | {
69 | return (NumM - 1) * (NumN-1);
70 | }
71 |
72 | ///
73 | /// Note that there is no trivial relationship between cell index and edge indexes
74 | public int GetCellEdgeCount(int cellIndex)
75 | {
76 | return 4;
77 | }
78 |
79 | ///
80 | public int EdgeCount()
81 | {
82 | return (NumM-1)*NumN + // row-oriented edges
83 | NumM*(NumN - 1); // column-oriented edges
84 | }
85 |
86 | /// The edge numbering is equal to CurvilinearGrid::ConvertCurvilinearToNodesAndEdges.
87 | /// First column-oriented edges, then row-oriented edges, in row major order
88 | private (int first, int last) GetEdgeNodes(int edgeIndex)
89 | {
90 | int numNodesInRow = NumM;
91 | int numNodesInColumn = NumN;
92 | int numColumnOrientedEdges = numNodesInRow * (numNodesInColumn - 1);
93 | if (edgeIndex < numColumnOrientedEdges)
94 | {
95 | return (edgeIndex, edgeIndex + numNodesInRow);
96 | }
97 |
98 | edgeIndex -= numColumnOrientedEdges;
99 |
100 | int numRowOrientedEdgesInRow = (numNodesInRow - 1);
101 | int row = edgeIndex / numRowOrientedEdgesInRow;
102 | int first = row*numNodesInRow + edgeIndex % numRowOrientedEdgesInRow;
103 | return (first, first + 1);
104 | }
105 |
106 | ///
107 | public int GetFirstNode(int edgeIndex)
108 | {
109 | return GetEdgeNodes(edgeIndex).first;
110 | }
111 |
112 | ///
113 | public int GetLastNode(int edgeIndex)
114 | {
115 | return GetEdgeNodes(edgeIndex).last;
116 | }
117 |
118 | ///
119 | public int NodeCount()
120 | {
121 | return NumM*NumN;
122 | }
123 |
124 | ///
125 | public double GetNodeX(int nodeIndex)
126 | {
127 | return NodeX[nodeIndex];
128 | }
129 |
130 | ///
131 | public double GetNodeY(int nodeIndex)
132 | {
133 | return NodeY[nodeIndex];
134 | }
135 | #endregion
136 |
137 | protected override void SetNativeObject(ref CurvilinearGridNative nativeObject)
138 | {
139 | nativeObject.node_x = GetPinnedObjectPointer(NodeX);
140 | nativeObject.node_y = GetPinnedObjectPointer(NodeY);
141 | nativeObject.num_m = numM;
142 | nativeObject.num_n = numN;
143 | }
144 |
145 | public void UpdateFromNativeObject(ref CurvilinearGridNative nativeObject)
146 | {
147 | NumM = nativeObject.num_m;
148 | NumN = nativeObject.num_n;
149 | NodeX = nativeObject.node_x.CreateValueArray(nativeObject.num_m * nativeObject.num_n);
150 | NodeY = nativeObject.node_y.CreateValueArray(nativeObject.num_m * nativeObject.num_n);
151 | }
152 | }
153 | }
--------------------------------------------------------------------------------
/src/MeshKernelNET/Api/DisposableNativeObject.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Runtime.InteropServices;
6 | using MeshKernelNET.Helpers;
7 |
8 | namespace MeshKernelNET.Api
9 | {
10 | ///
11 | /// Base class for disposable mesh objects. Provides pinning of arrays in memory for exchange with native calls.
12 | ///
13 | public abstract class DisposableNativeObject : IDisposable where TNative : new()
14 | {
15 | private readonly Dictionary