去年用wpf弄了个航线规划软件,用于生成无人机喷洒农药的作业航线,里面包含了不少算法。年后这几天将其中的算法移植到C,以便其他同事调用。昨天在用C#调用生成的dll时,遇到一些问题,折腾了好久才解决。这里就其中的一个函数做个记录,或许有人会遇到类似的问题。
C里面相关的结构和函数原型
/** * 平面点、向量 */ typedef struct { double X; double Y; } gPoint, gVector; /** * 平面直线 */ typedef struct gLine { gPoint startPoint; gPoint endPoint; } gLine; /** * 平面多边形 */ typedef struct gPolygon { gPoint *points; int count; } gPolygon;
#define DllExport __declspec(dllexport)
/* 根据反转点用平移直线将多边形分割 */ DllExport int splitPolygon(gPolygon polygon, gLine moveline, gPolygon results[]);
上面的函数,将凹多边形根据切割方向和凹点切割成多个凸多边形,results为输出的凸多边形
下面是C#中的调用方式
[StructLayout(LayoutKind.Sequential)] struct gPoint { public double X; public double Y; } [StructLayout(LayoutKind.Sequential)] struct gLine { public gPoint startPoint; public gPoint endPoint; } [StructLayout(LayoutKind.Sequential)] struct gPolygon { public IntPtr points; public int count; }
使用 Marshal.AllocHGlobal、Marshal.FreeHGlobal来分配、释放非托管内存;使用Marshal.StructureToPtr、Marshal.PtrToStructure来实现对结构体指针的操作
gPoint p1 = new gPoint() { X = 0, Y = 0 }; gPoint p2 = new gPoint() { X = 0, Y = 100 }; gPoint p3 = new gPoint() { X = 100, Y = 100 }; gPoint p4 = new gPoint() { X = 50, Y = 50 }; gPoint p5 = new gPoint() { X = 100, Y = 0 }; gPolygon polygon = new gPolygon() { count = 5 }; gPoint[] array = new gPoint[5] { p1, p2, p3, p4, p5 }; int size = Marshal.SizeOf(typeof(gPoint)); polygon.points = Marshal.AllocHGlobal(size * array.Length); for (int i = 0; i < array.Length; i++) { IntPtr ptr = new IntPtr(polygon.points.ToInt64() + i * size); Marshal.StructureToPtr(array[i], ptr, false); } gLine ml = new gLine() { startPoint = p1, endPoint = p2 }; gPolygon[] results = new gPolygon[array.Length]; for (int i = 0; i < array.Length; i++) results[i].points = Marshal.AllocHGlobal(size * array.Length); int count = splitPolygon(polygon, ml, results); Console.WriteLine("多边形 {0} 可切割成{1}个凸多边形", polygonToString(polygon), count); for (int i = 0; i < count; i++) Console.WriteLine("{0}", polygonToString(results[i])); for (int i = 0; i < array.Length; i++) Marshal.FreeHGlobal(results[i].points); Marshal.FreeHGlobal(polygon.points);
static string polygonToString(gPolygon polygon) { StringBuilder sb = new StringBuilder(); sb.Append('{'); int size = Marshal.SizeOf(typeof(gPoint)); for (int i = 0; i < polygon.count; i++) { IntPtr p = new IntPtr(polygon.points.ToInt64() + size * i); gPoint tempgp = (gPoint)Marshal.PtrToStructure(p, typeof(gPoint)); sb.AppendFormat("({0},{1})", tempgp.X, tempgp.Y); if (i < polygon.count - 1) sb.Append(','); } sb.Append('}'); return sb.ToString(); }
结果如下