rdp
rdp copied to clipboard
C# Api
I am trying to implement this Rust implementation into c# so far I created FFIArray which holds data to simplify as well as simplified data returned from Rust.
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct FfiArray
{
public required nint data;
public required nuint len;
}
I am converting float[][] array into nint and vice versa using these methods.
public static nint CopyDataFromFloatJaggedArrayToIntPtr(float[][] jaggedArray)
{
int length = jaggedArray.Length;
double[] joinedArray = jaggedArray.Select(coords =>
{
var x = BitConverter.GetBytes(coords[0]);
var y = BitConverter.GetBytes(coords[1]);
return BitConverter.ToDouble([..x, ..y], 0);
}).ToArray();
nint arrayPtr = Marshal.AllocHGlobal(jaggedArray.Length * sizeof(double));
Marshal.Copy(joinedArray, 0, arrayPtr, joinedArray.Length);
return arrayPtr;
}
public static float[][] CopyDataFromIntPtrToFloatJaggedArray(nint ptr, int length, int innerLength = 2)
{
float[][] jaggedArray = new float[length][];
for (int i = 0; i < length; i++)
{
byte[] x = new byte[4];
byte[] y = new byte[4];
Marshal.Copy(ptr + (i * 8), x, 0, 4);
Marshal.Copy(ptr + (i * 8 + 4), y, 0, 4);
jaggedArray[i] = [BitConverter.ToSingle(x), BitConverter.ToSingle(y)];
}
return jaggedArray;
}
public static void FreeIntPtr(nint ptr, int length)
{
for (int i = 0; i < length; i++)
{
nint innerPtr = Marshal.ReadIntPtr(ptr, i * nint.Size);
Marshal.FreeHGlobal(innerPtr);
}
Marshal.FreeHGlobal(ptr);
}
Rust bindings from DLL:
internal class RustBindings
{
[DllImport("RustSimplificationAlgorithms.dll")]
public static extern FfiArray simplify_rdp_ffi(FfiArray array, double precision);
[DllImport("RustSimplificationAlgorithms.dll")]
public static extern FfiArray simplify_rdp_idx_ffi(FfiArray array, double precision);
[DllImport("RustSimplificationAlgorithms.dll")]
public static extern FfiArray simplify_visvalingam_ffi(FfiArray array, double precision);
[DllImport("RustSimplificationAlgorithms.dll")]
public static extern FfiArray simplify_visvalingam_idx_ffi(FfiArray array, double precision);
[DllImport("RustSimplificationAlgorithms.dll")]
public static extern FfiArray simplify_visvalingamp_ffi(FfiArray array, double precision);
[DllImport("RustSimplificationAlgorithms.dll")]
public static extern void drop_float_array(FfiArray ptr);
[DllImport("RustSimplificationAlgorithms.dll")]
public static extern void drop_usize_array(FfiArray ptr);
}
And Public Api looks like this (for testing purposes I am trying to implement only RDP algorithm).
public static float[][] Simplify(float[][] data, double tolerance)
{
FfiArray? dataInArray = null;
FfiArray? simplified = null;
try
{
nint dataForSimplification = MarshalOperations.CopyDataFromFloatJaggedArrayToIntPtr(data);
dataInArray = new FfiArray()
{
data = dataForSimplification,
len = (nuint)data.Length
};
simplified = RustBindings.simplify_rdp_ffi((FfiArray)dataInArray, tolerance);
float[][] result = MarshalOperations.CopyDataFromIntPtrToFloatJaggedArray(((FfiArray)simplified).data, (int)((FfiArray)simplified).len);
return result;
}
finally
{
if (dataInArray is not null)
MarshalOperations.FreeIntPtr(((FfiArray)dataInArray).data, (int)((FfiArray)dataInArray).len);
if (simplified is not null)
RustBindings.drop_float_array((FfiArray)simplified!);
Console.WriteLine("memory freed");
}
}
My problem is that the simplification algorithm always returns different values despite the same values being provided. For checking I am using the Python library which is part of this repository. According to that, I am expecting 26 values but I got only 15 at best. Also when I check the returned values only the first two are valid and the others are junk.
I expect this problem is in bad memory handling.
string[] lines = File.ReadAllLines("generatedValuesSin.csv");
float[][] data = new float[lines.Length - 1][];
for (int i = 1; i < lines.Length; i++) // skip first line
{
data[i - 1] = [(i - 1) * 3600, float.Parse(lines[i], NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture)];
}
float[][] simplified = RdpAlgorithm.Simplify(data, 0.15);
Source code repository: https://github.com/AiwendilsCode/Simplification.NET Python testing code: https://github.com/AiwendilsCode/Simplification.NET/tree/master/Python
As a testing data I am using generated Sin values.
I'm not a C# user, so I can't help you with this.
I successfully implemented a wrapper for C# here.