Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions src/MeshKernelNET/Api/DisposableSplineIntersections.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using MeshKernelNET.Helpers;
using MeshKernelNET.Native;
using ProtoBuf;

namespace MeshKernelNET.Api
{
[ProtoContract(AsReferenceDefault = true)]
public sealed class DisposableSplineIntersections : DisposableNativeObject<SplineIntersectionsNative>
{
[ProtoMember(1)]
Comment thread
RStolkerDeltares marked this conversation as resolved.
private int numIntersections;

[ProtoMember(2)]
private int[] splineIndex;

[ProtoMember(3)]
private double[] intersectionAngle;

[ProtoMember(4)]
private double[] intersectionX;

[ProtoMember(5)]
private double[] intersectionY;

public DisposableSplineIntersections()
{
}

public DisposableSplineIntersections(int numIntersections)
{
this.numIntersections = numIntersections;
splineIndex = new int[numIntersections];
intersectionAngle = new double[numIntersections];
intersectionX = new double[numIntersections];
intersectionY = new double[numIntersections];
}

~DisposableSplineIntersections()
{
Dispose(false);
}

public int NumIntersections
{
get => numIntersections;
set => numIntersections = value;
}

public int[] SplineIndex
{
get => splineIndex;
set => splineIndex = value;
}

public double[] IntersectionAngle
{
get => intersectionAngle;
set => intersectionAngle = value;
}

public double[] IntersectionX
{
get => intersectionX;
set => intersectionX = value;
}

public double[] IntersectionY
{
get => intersectionY;
set => intersectionY = value;
}

protected override void SetNativeObject(ref SplineIntersectionsNative nativeObject)
{
nativeObject.NumIntersections = numIntersections;
nativeObject.SplineIndex = GetPinnedObjectPointer(splineIndex);
nativeObject.IntersectionAngle = GetPinnedObjectPointer(intersectionAngle);
nativeObject.IntersectionX = GetPinnedObjectPointer(intersectionX);
nativeObject.IntersectionY = GetPinnedObjectPointer(intersectionY);
}

public void UpdateFromNativeObject(ref SplineIntersectionsNative nativeObject)
{
numIntersections = nativeObject.NumIntersections;
splineIndex = nativeObject.SplineIndex.CreateValueArray<int>(nativeObject.NumIntersections);
intersectionAngle = nativeObject.IntersectionAngle.CreateValueArray<double>(nativeObject.NumIntersections);
intersectionX = nativeObject.IntersectionX.CreateValueArray<double>(nativeObject.NumIntersections);
intersectionY = nativeObject.IntersectionY.CreateValueArray<double>(nativeObject.NumIntersections);
}
}
}
25 changes: 25 additions & 0 deletions src/MeshKernelNET/Api/IMeshKernelApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1823,6 +1823,31 @@ int SplinesToLandBoundary(int meshKernelId,
ref DisposableGeometryList splines,
int firstIndex,
int secondIndex);

/// <summary>
/// Initializes spline intersection checking with a set of cached splines for subsequent intersection checks.
/// Must be called before <see cref="GetSplineIntersections"/>.
/// </summary>
/// <param name="meshKernelId">The id of the mesh state</param>
/// <param name="crossSplines">The set of splines to cache for intersection checking</param>
/// <returns>Error code</returns>
int SplineIntersectionsInitialize(int meshKernelId, DisposableGeometryList crossSplines);

/// <summary>
/// Checks the given spline for intersections with the previously cached splines.
/// </summary>
/// <param name="meshKernelId">The id of the mesh state</param>
/// <param name="spline">The spline to check for intersections</param>
/// <param name="intersections">The intersection data containing all found intersections</param>
/// <returns>Error code</returns>
int GetSplineIntersections(int meshKernelId, DisposableGeometryList spline, out DisposableSplineIntersections intersections);

/// <summary>
/// Finalizes and cleans up the spline intersection checking.
/// </summary>
/// <param name="meshKernelId">The id of the mesh state</param>
/// <returns>Error code</returns>
int SplineIntersectionsFinalize(int meshKernelId);

/// <summary>
/// Redo editing action
Expand Down
40 changes: 40 additions & 0 deletions src/MeshKernelNET/Api/MeshKernelApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1718,6 +1718,46 @@ public int SplinesToLandBoundary(int meshKernelId,
GeometryListNative polygonNative = splines.CreateNativeObject();
return MeshKernelDll.SplinesToLandBoundary(meshKernelId, ref landboundariesNative, ref polygonNative, firstIndex, secondIndex);
}

/// <inheritdoc/>
public int SplineIntersectionsInitialize(int meshKernelId, DisposableGeometryList crossSplines)
{
GeometryListNative crossSplinesNative = crossSplines.CreateNativeObject();
return MeshKernelDll.InitializeSplineIntersection(meshKernelId, ref crossSplinesNative);
}

/// <inheritdoc/>
public int GetSplineIntersections(int meshKernelId, DisposableGeometryList spline, out DisposableSplineIntersections intersections)
{
intersections = new DisposableSplineIntersections();
GeometryListNative splineNative = spline.CreateNativeObject();

var numberOfIntersections = 0;
int exitCode = MeshKernelDll.CheckSplineIntersection(meshKernelId, ref splineNative, ref numberOfIntersections);
if (exitCode != 0)
{
return exitCode;
}

using (var exchangeIntersections = new DisposableSplineIntersections(numberOfIntersections))
{
SplineIntersectionsNative intersectionsNative = exchangeIntersections.CreateNativeObject();
exitCode = MeshKernelDll.GetSplineIntersectionData(meshKernelId, ref intersectionsNative);
if (exitCode != 0)
{
return exitCode;
}

intersections.UpdateFromNativeObject(ref intersectionsNative);
return exitCode;
}
}

/// <inheritdoc/>
public int SplineIntersectionsFinalize(int meshKernelId)
{
return MeshKernelDll.FinalizeSplineIntersection(meshKernelId);
}

/// <inheritdoc/>
public int RedoState(ref bool redone, ref int meshKernelId)
Expand Down
36 changes: 36 additions & 0 deletions src/MeshKernelNET/Native/MeshKernelDll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2094,6 +2094,42 @@ internal static extern int SplinesToLandBoundary([In] int meshKernelId,
[In] int startSplineIndex,
[In] int endSplineIndex);

/// <summary>
/// Initialize the spline intersection calculation
/// </summary>
/// <param name="meshKernelId">The id of the mesh state</param>
/// <param name="crossSplines">A set of splines to check against</param>
/// <returns>Error code</returns>
[DllImport(MeshKernelDllName, EntryPoint = "mkernel_initialise_spline_intersection", CallingConvention = CallingConvention.Cdecl)]
internal static extern int InitializeSplineIntersection([In] int meshKernelId, [In] ref GeometryListNative crossSplines);

/// <summary>
/// Compute the intersections of a spline with the cached splines and return the number of intersections found
/// </summary>
/// <param name="meshKernelId">The id of the mesh state</param>
/// <param name="spline">A single spline to check for intersections</param>
/// <param name="numberOfIntersections">The number of spline intersections computed</param>
/// <returns>Error code</returns>
[DllImport(MeshKernelDllName, EntryPoint = "mkernel_check_spline_intersection", CallingConvention = CallingConvention.Cdecl)]
internal static extern int CheckSplineIntersection([In] int meshKernelId, [In] ref GeometryListNative spline, [In][Out] ref int numberOfIntersections);

/// <summary>
/// Get the spline intersection data
/// </summary>
/// <param name="meshKernelId">The id of the mesh state</param>
/// <param name="intersectionData">The spline intersection data</param>
/// <returns>Error code</returns>
[DllImport(MeshKernelDllName, EntryPoint = "mkernel_get_spline_intersection_data", CallingConvention = CallingConvention.Cdecl)]
internal static extern int GetSplineIntersectionData([In] int meshKernelId, [In][Out] ref SplineIntersectionsNative intersectionData);

/// <summary>
/// Finalize the spline intersection calculation
/// </summary>
/// <param name="meshKernelId">The id of the mesh state</param>
/// <returns>Error code</returns>
[DllImport(MeshKernelDllName, EntryPoint = "mkernel_finalise_spline_intersection", CallingConvention = CallingConvention.Cdecl)]
internal static extern int FinalizeSplineIntersection([In] int meshKernelId);

/// <summary>
/// Redo editing action
/// </summary>
Expand Down
37 changes: 37 additions & 0 deletions src/MeshKernelNET/Native/SplineIntersectionsNative.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Runtime.InteropServices;

namespace MeshKernelNET.Native
{
/// <summary>
/// A struct used to describe the intersection points of a spline with a number of other splines.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct SplineIntersectionsNative
{
/// <summary>
/// The number of spline intersections
/// </summary>
public int NumIntersections { get; set; }

/// <summary>
/// The index of the intersected spline
/// </summary>
public IntPtr SplineIndex { get; set; }

/// <summary>
/// The angle of the intersection
/// </summary>
public IntPtr IntersectionAngle { get; set; }

/// <summary>
/// The x coordinate of the intersection point
/// </summary>
public IntPtr IntersectionX { get; set; }

/// <summary>
/// The y coordinate of the intersection point
/// </summary>
public IntPtr IntersectionY { get; set; }
}
}
28 changes: 28 additions & 0 deletions test/MeshKernelNETTest/Api/DisposableGriddedSamplesTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using MeshKernelNET.Api;
using MeshKernelNET.Native;
using NUnit.Framework;

namespace MeshKernelNETTest.Api
Expand Down Expand Up @@ -282,5 +283,32 @@ public void Constructor_WithNegativeCellSize_WorksCorrectly()

Assert.That(samples.CellSize, Is.EqualTo(-1.5));
}

[Test]
public void CreateNativeObject_CreatesValidNativeStructure()
{
var samples = new DisposableGriddedSamples(3, 4, 1.0, 2.0, 0.5, InterpolationType.Float)
{
FloatValues = new[] { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f, 7.7f, 8.8f, 9.9f, 10.1f, 11.1f, 12.2f }
};

using (samples)
{
GriddedSamplesNative nativeSamples = samples.CreateNativeObject();

using (Assert.EnterMultipleScope())
{
Assert.That(nativeSamples.num_x, Is.EqualTo(3));
Assert.That(nativeSamples.num_y, Is.EqualTo(4));
Assert.That(nativeSamples.origin_x, Is.EqualTo(1.0));
Assert.That(nativeSamples.origin_y, Is.EqualTo(2.0));
Assert.That(nativeSamples.cell_size, Is.EqualTo(0.5));
Assert.That(nativeSamples.coordinates_x, Is.Not.EqualTo(IntPtr.Zero));
Assert.That(nativeSamples.coordinates_y, Is.Not.EqualTo(IntPtr.Zero));
Assert.That(nativeSamples.values, Is.Not.EqualTo(IntPtr.Zero));
Assert.That(nativeSamples.value_type, Is.EqualTo((int)InterpolationType.Float));
}
}
}
}
}
Loading