将Point3D列表转换为坐标数组

时间:2012-01-28 11:40:49

标签: c# list generics type-conversion

我正在使用NetTopologySuite进行一些简化线路。

我面临的问题是我有自己的类存储Point3D列表(System.Windows.Media) 和NetTopology有自己的Coordinate类,具有几乎相同的属性和功能。

要将point3D列表转换为coorinate数组,我正在使用此函数:

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

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

3 个答案:

答案 0 :(得分:1)

<强>更新 如果集合是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();
    }
}

答案 1 :(得分:0)

没有办法让这种方法更快。您可以在最后一个块中缓冲listToClone.ElementAt(0),但这与长列表的整体性能几乎无关。

如果来源&amp;目标坐标是等价值类型,您可以尝试使用指针直接复制数据。但遗憾的是GeoApiGeometries.Coordinate是一个引用类型,可能是因为库是从Java移植的,所以你必须手动分配每个新元素,就像现在一样。

答案 2 :(得分:0)

我在foreach中调用了这个函数,它取代了foreach for for,它改善了性能。我应该发布整个代码。