Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 减少经纬度点数的最快方法_C#_Performance_Algorithm - Fatal编程技术网

C# 减少经纬度点数的最快方法

C# 减少经纬度点数的最快方法,c#,performance,algorithm,C#,Performance,Algorithm,我试图减少并合并一些点到这些位置的中心点。现在,我通过寻找最接近的一对,组合它们并重复,直到我将其减少到我的目标(旁注:实际上,我通过排序(lat*lat+long*long)来减少问题,然后在每个点的任一侧搜索10%,在我的测试中,总是找到该范围内的最短距离) 例如,我想将4000点减少到1000点,理想情况下将最近点合并到这些最近点的中心。基本上是构建反映该区域地址数量的标记点 有没有更好的算法能给我尽可能精确的结果?还是更快的距离算法?我想它只需要在短距离内精确 现在我正在寻找距离(维基

我试图减少并合并一些点到这些位置的中心点。现在,我通过寻找最接近的一对,组合它们并重复,直到我将其减少到我的目标(旁注:实际上,我通过排序
(lat*lat+long*long)
来减少问题,然后在每个点的任一侧搜索10%,在我的测试中,总是找到该范围内的最短距离)

例如,我想将4000点减少到1000点,理想情况下将最近点合并到这些最近点的中心。基本上是构建反映该区域地址数量的标记点

有没有更好的算法能给我尽可能精确的结果?还是更快的距离算法?我想它只需要在短距离内精确


现在我正在寻找距离(维基百科在“球形地球投影到平面”下有它):

我曾考虑过将彼此相距x距离内的所有点分组,然后扩展x,直到达到最终点的目标数量,但我不确定如何使其精确到我的完美主义者想要的程度。这就是我所能想到的所有方法,根据输入点列表的顺序略有不同


编辑以描述我当前的算法是如何处理的(这是找到我想要的结果的理想方法,但是一个更快的近似值是值得的):

如果你有
x=1,4,5,6,10,20,22

  • 它将组合4+5=4.5[它找到的第一个1.0距离]
  • (4.5*2+6)/3=5--
    x=1,5,10,20,22
    [1.5距离]
  • 20+22=21--
    x=1,5,10,21
    [2.0距离]
  • (5*3+1)/4=4--
    x=4,10,21
    [4.0距离]
  • (4*4+10)/5.2——因此您将得到
    x=5.2,21
    。(它跟踪CombineCount,以便通过这种方式找到正确的平均中心)

  • 结果: 这是我当前的距离函数,为cos^2生成查找表。没有时间检查我的点之间的距离,因此没有执行Joey关于近似cos^2的建议,但这可能会提高查找表的速度

    我尝试过的K-聚类算法(参见我对答案的评论)并没有按照我的意愿将它们结合在一起,结果在地图中心附近有大量点,而在边缘有少量点。所以除非我能纠正,否则我使用的是较慢的算法

    public static double Distance(AddressCoords pos1, AddressCoords pos2, DistanceType type)
    {
        if (LookupTable == null) LookupTable = BuildLookup();
    
        double R = (type == DistanceType.Miles) ? 3960 : 6371;
    
        double dLat = pos2.LatitudeR - pos1.LatitudeR;
        double dLon = pos2.LongitudeR - pos1.LongitudeR;
    
        double LatM = ((pos2.LatitudeR + pos1.LatitudeR)/2);
        if (LatM < 0) LatM = -LatM; //Don't allow any negative radian values
        double cosLatM2 = LookupTable[(int)(LatM * _cacheStepInverse)];
        double a = dLat*dLat + cosLatM2 * dLon*dLon;
    
        //a = Math.Sqrt(a);
    
        double d = a * R;
    
        return d;
    }
    
    private const double _cacheStep = 0.00002;
    private const double _cacheStepInverse = 50000;
    
    private static double[] LookupTable = null;
    
    public static double[] BuildLookup()
    {
        // set up array
        double maxRadian = Math.PI*2;
        int elements = (int)(maxRadian * _cacheStepInverse) + 1;
    
        double[] _arrayedCos2 = new double[elements];
        int i = 0;
        for (double angleRadians = 0; angleRadians <= maxRadian;
            angleRadians += _cacheStep)
        {
            double cos = Math.Cos(angleRadians);
            _arrayedCos2[i] = cos*cos;
            i++;
        }
        return _arrayedCos2;
    }
    
    公共静态双距离(AddressCoords pos1、AddressCoords pos2、DistanceType)
    {
    if(LookupTable==null)LookupTable=BuildLookup();
    双R=(类型==距离类型.Miles)?3960:6371;
    双dLat=pos2.LatitudeR-pos1.LatitudeR;
    双dLon=pos2.LongitudeR-pos1.LongitudeR;
    双LatM=((pos2.LatitudeR+pos1.LatitudeR)/2);
    if(LatM<0)LatM=-LatM;//不允许任何负弧度值
    双余latm2=可查找[(int)(LatM*_cachestepreverse)];
    双a=dLat*dLat+cosLatM2*dLon*dLon;
    //a=数学Sqrt(a);
    双d=a*R;
    返回d;
    }
    private const double_cacheStep=0.00002;
    私有常量double\u cacheStepReverse=50000;
    私有静态双[]LookupTable=null;
    公共静态双[]BuildLookup()
    {
    //设置阵列
    double maxRadian=数学PI*2;
    int元素=(int)(最大弧度*_);
    double[]_arrayedCos2=新的double[元素];
    int i=0;
    
    对于(double angleRadians=0;angleRadians作为一种有效的方法,您是否考虑过在地图上放置一个网格,然后将每个点指定给网格中相应的单元?这应该具有良好的性能

    更好(更慢)方法是使用动态单元格,而不是像上面建议的那样使用固定单元格。您一开始根本没有单元格。然后删除地图中的第一个点,并定义一个具有预定尺寸的单元格。然后删除地图上的下一个点。如果它落在上一个单元格内,则将其添加到其中,并可能重新居中单元格环绕两个点。如果点落在单元格外,则为其创建第二个单元格。现在,将第三个点添加到地图中,并与两个单元格进行对比。此过程将继续,直到将所有点添加到地图中。我希望您能理解。我想您可以通过更改细胞的大小


    编辑(基于rrenaud的评论):您可以开始使用较大的单元格大小,然后应用上述算法之一。如果最终得到的单元格数量太少,则可以在每个单元格上重复该算法并进一步细分。虽然这不允许您精确地减少到固定数量的点,但您可以非常接近。

    加快计算距离点与点之间的ces:

    如果你做一些初等代数,你会得到:

    D = R*Sqrt(Lat2^2 + Lat1^2 - 2*Lat1*Lat2 + cos^2((Lat2 + Lat1) /2)(Lon2^2 + Lon1^2 - 2*Lon1*Lon2))
    
    要加快速度,您可以做的第一件事是将地球半径(R)归一化,并比较平方距离而不是距离,从而避免平方根和R项,每次比较节省2次计算。留下:

    valToCompare = Lat2^2 + Lat1^2 - 2*Lat1*Lat2 + cos^2((Lat2 + Lat1) /2)(Lon2^2 + Lon1^2 - 2*Lon1*Lon2)
    
    您可以做的另一件事是为每个坐标预先计算Lat^2和Lon^2,将每次比较的计算数量减少4

    此外,如果这些点在纬度上都相对接近,则可以通过使用随机点的纬度或所有点的平均纬度(而不是被比较的两个点的平均纬度)预先计算cos^2项,从而获得近似值。这减少了每次比较的计算数量n再增加4

    最后,您可以为每个点预先计算2*Lat和2*Lon,为每个比较再进行2次计算

    这些都不能改善你的算法本身,但它应该使我
    valToCompare = Lat2^2 + Lat1^2 - 2*Lat1*Lat2 + cos^2((Lat2 + Lat1) /2)(Lon2^2 + Lon1^2 - 2*Lon1*Lon2)