我正在尝试减少并将多个点组合到这些位置的中心点。现在我通过寻找最接近的一对来强制它,将它们组合并重复直到我将它减少到我的目标(旁注:实际上我通过排序减少了问题) (lat*lat+long*long)
然后在每个点的两侧搜索10%,我的测试总是找到该范围内的最短距离)。
举个例子,我想将4000点减少到1000点,理想情况下将最近点组合到最近点的中心。基本上是构建反映该区域中地址数量的标记点。
有没有更好的算法可以给我尽可能准确的结果?或者更快的距离算法?我想它只需要在短距离内准确
现在我找到了距离(维基百科在“投射到飞机上的球形地球”下):
double dLat = pos2.LatitudeR - pos1.LatitudeR;
double dLon = pos2.LongitudeR - pos1.LongitudeR;
double cosLatM = Math.Cos((pos2.LatitudeR + pos1.LatitudeR)/2) * dLon;
double a = dLat*dLat + cosLatM*cosLatM;
我已经考虑过将所有点分组在彼此的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-Cluster算法(参见我对该答案的评论)并没有像我想的那样将它们组合在一起,它最终得到了地图中心附近的大量点和边缘的几点。所以除非我能纠正我正在使用的算法慢一些。
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;
}