将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[]。

从一个类到另一个类的转换也是如此。

将Point3D列表转换为坐标数组

更新如果集合是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,从而提高了性能。我本应该公布整个代码的。