将Point3D列表转换为坐标数组
本文关键字:坐标 数组 转换 Point3D 列表 | 更新日期: 2023-09-27 18:21:36
我使用NetTopologySuite来简化线条。
我面临的问题是,我有自己的类,存储Point3D(System.Windows.Media)的列表NetTopology有自己的Coordinate类,具有几乎相同的属性和功能。
要将point3D列表转换为坐标阵列,我使用以下功能:
public static GeoApiInterfaces.ICoordinate[] ToCoordinateArray(this IEnumerable<Point3D> listToClone,
bool isClosed = false)
{
// if geometry is to be closed the size of array will be one more than the
// current point count
var coordinateList = new GeoApiInterfaces.ICoordinate[isClosed ?
listToClone.Count() + 1
: listToClone.Count()];
// loop through all the point in the list to create the array
int elementIndex = 0;
foreach (var point in listToClone)
{
var coordinate = new GeoApiGeometries.Coordinate(point.X,
point.Y,
point.Z);
coordinateList[elementIndex] = coordinate;
elementIndex++;
} // foreach
// if geometry is closed the add the first point to the last
if (isClosed)
{
var coordinate = new GeoApiGeometries.Coordinate(listToClone.ElementAt(0).X,
listToClone.ElementAt(0).Y,
listToClone.ElementAt(0).Z);
coordinateList[elementIndex] = coordinate;
} // if isClosed
return coordinateList;
}
一切都很好,但当我分析我的代码时,这个函数几乎占用了95%的时间。我想知道,有没有其他方法可以将System.Windows.Media.Point3D的列表转换为Coordinate[]。
从一个类到另一个类的转换也是如此。
更新如果集合是List<>
,那么我们可以对底层数组进行一次反射,如
static FieldInfo f_items = typeof(List<Point3D>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance);
static FieldInfo f_size = typeof(List<Point3D>).GetField("_size", BindingFlags.NonPublic | BindingFlags.Instance);
然后每次我们想像这个一样将其转换为List<Point3D>
和Point3D
时都使用它的代码
Point3D[] array = f_items.GetValue(list) as Point3D[];
int size= (int)f_size.GetValue(list);
然后您可以继续执行下面的代码。如果IEnumerable<>
集合有所不同,那么您需要首先找到元素是如何在内部存储的。
原始
我认为,如果你能把自己限制在阵列上,而不是IEnumerable<>
,那么你就能获得更快的速度。
这里是一个紧凑的示例代码,应该尽可能快地工作。
public struct Point3D
{
public double x, y, z;
}
public static class Extensions
{
public static ICoordinate[] ToCoord(this Point3D[] points, int size)
{
size = Math.Min(points.Length,size); //make sure there are enough points
ICoordinate[] res = new ICoordinate[size];
for (int i = 0; i < size; i++)
{
res[i] = new Coordinate(points[i].x, points[i].y, points[i].z);
}
return res;
}
}
class Program
{
static void Main(string[] args)
{
Point3D[] array1 = new Point3D[N];
// Fill the array ..
ICoordinate[] array2 = array1.ToCoord();
}
}
没有办法让这个方法更快。您可以在最后一个块中缓冲listToClone.ElementAt(0),但这与长列表的总体性能几乎无关。
如果源&目标坐标是等价的值类型,您可以尝试使用指针直接复制它们的数据。但遗憾的是,GeoApiGeometries.Coordinate是一种引用类型,可能是因为库是从Java移植的,所以你必须手动分配每个新元素,就像现在一样。
我在foreach中调用了这个函数,它将foreach替换为for,从而提高了性能。我本应该公布整个代码的。