[英]How to Efficiently Calculate Nearest 2D points in JavaScript?
I have a set of locations that I want to display to a user in proximity order - closest to farthest - based on their current coordinates. 我有一组位置,我希望以接近顺序显示给用户 - 最接近最远 - 基于它们的当前坐标。 Assume we have ~100 data points of locations which includes each one's latitude and longitude (in some kind of object or array), and we know the user's lat and long.
假设我们有大约100个位置的数据点,包括每个位置的纬度和经度(在某种对象或数组中),我们知道用户的lat和long。 The goal is to display an ordered list of locations -- and it is beneficial if we can get and display to the user the nearest 8-10 locations while we calculate then display the remaining distances.
目标是显示一个有序的位置列表 - 如果我们能够在计算时向用户显示最近的8-10个位置,然后显示剩余的距离,这将是有益的。
I know the brute-force solution is to loop through all locations, calculate the distance from the user, put them in order, then display them all to the user. 我知道蛮力解决方案是遍历所有位置,计算与用户的距离,将它们按顺序排列,然后将它们全部显示给用户。 But this is too slow.
但这太慢了。
A better solution is this one: https://stackoverflow.com/a/2466908/1766230 where you check within a bounded box first, expanding if necessary, then do the rest. 一个更好的解决方案就是这个: https : //stackoverflow.com/a/2466908/1766230 ,首先在有界框内检查,必要时进行扩展,然后完成剩下的工作。
I've also seen there are other algorithms out there - like FLANN and other methods - but I haven't seen any examples written in JavaScript. 我还看到有其他算法 - 比如FLANN和其他方法 - 但我还没有看到用JavaScript编写的任何示例。
So the question: What is the fastest way to calculate (and display in order) nearest points in JavaScript? 所以问题是:在JavaScript中计算(并按顺序显示)最近点的最快方法是什么?
So, if you are starting out with that list of points, drawing a small bounding box won't cut down very much, because you still do an O(n) check against all points for their location. 因此,如果您开始使用该点列表,绘制一个小的边界框将不会减少很多,因为您仍然针对其位置对所有点进行O(n)检查。
I would advise using a max-length heap or some other form of partial sort while iterating through all of the points. 我建议在迭代所有点时使用最大长度堆或其他形式的局部排序。 This lets you keep track of a small subset of approximately maximum/minimal points (as described by the length), so you can render those quickly before dealing with the rest.
这使您可以跟踪大约最大/最小点的一小部分(如长度所述),因此您可以在处理其余部分之前快速渲染它们。 If you need more explanation about what I'm saying precisely, let me know.
如果您需要更多关于我所说的内容的解释,请告诉我。
Also what are you making this for that has such stringent performance issues? 你也正在为此制作这样严格的性能问题? Typically computation like this shouldn't be a stress point, barring that you have 100k+ points.
通常这样的计算不应该是一个压力点,除非你有100k +点。 DOM manipulation is usually the most expensive spot
DOM操作通常是最昂贵的点
var points = [];
for (i = 0; i < 100; i++) {
var point = [getRandomInt(0, 999), getRandomInt(0, 999)];
point.len = distanceBetweenPoints(point, [499,499]);
points.push(point);
}
console.log(Heap.nsmallest(points, 10, function (a, b) {
return a.len < b.len;
}));
Here is the performance for it compared to bruteforce 这是与bruteforce相比的表现
Using the method I described, and a prebuilt heap another person wrote, I compared our methods. 使用我描述的方法和另一个人写的预构建堆,我比较了我们的方法。 I think you will be happy!
我想你会很开心! It performed 8,586 ops/sec compared to the 566 in the brute force technique!
与蛮力技术中的566相比,它执行了8,586次操作/秒!
Well this is my attempt at sorting an array of points by distance to a given point. 那么这是我尝试按距离到给定点对点阵列进行排序。 This is brute-force as far as I understand.
据我所知,这是一种蛮力。 Then I
slice
the array to give you the 10 closest points. 然后我
slice
数组,给你10个最近的点。
Javascript 使用Javascript
function distanceBetweenPoints(p1, p2) {
return Math.abs(Math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])));
}
function sortByDistance(location, arrayOfPoints) {
arrayOfPoints.sort(function (a, b) {
a.distance = distanceBetweenPoints(location, a);
b.distance = distanceBetweenPoints(location, b);
return a.distance - b.distance;
});
return arrayOfPoints;
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var points = [];
for (i = 0; i < 100; i += 1) {
points.push([getRandomInt(-90, 90), getRandomInt(-180, 180)]);
}
console.log(sortByDistance([0, 0], points).slice(0, 10));
This will at least give you something to test algorithms against. 这至少会给你一些测试算法的东西。 And here is a jsPerf for the above, so you can add other routines to it and do some real performance comparisons.
这里有一个jsPerf ,所以你可以添加其他例程并进行一些真正的性能比较。
Note: This does not take into consideration that the Earth is a sphere! 注意:这没有考虑到地球是一个球体! This is calculating
Euclidean distance
and not Geodesic distance. 这是计算
Euclidean distance
而不是测地距离。 This is fine if the points, are for example, in the same town (or close proximity) but not if they are in different countries/continents. 如果这些点位于同一个城镇(或非常接近),但是如果它们位于不同的国家/大陆,那么这是很好的。 It also assumes that you have converted your longitude and latitude to a decimal representation.
它还假定您已将经度和纬度转换为十进制表示。
Otherwise you will need to look at things like Great-circle distance
and Haversine formula
否则你需要看看像
Great-circle distance
和Haversine formula
In fact, the earth is very slightly ellipsoidal; 事实上,地球是非常略微椭圆形的; using a spherical model gives errors typically up to 0.3%
使用球形模型给出的误差通常高达0.3%
Javascript 使用Javascript
function toRadians(degrees) {
return (degrees * Math.PI) / 180;
}
// Haversine formula
function distanceBetweenPoints(p1, p2) {
var R = 6371, // mean earth radius in km
lat1 = toRadians(p1[0]),
lon1 = toRadians(p1[1]),
lat2 = toRadians(p2[0]),
lon2 = toRadians(p2[1]),
dLat = lat2 - lat1,
dLon = lon2 - lon1,
a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2),
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)),
d = R * c;
return d;
}
function sortByDistance(location, arrayOfPoints) {
arrayOfPoints.sort(function (a, b) {
a.distance = distanceBetweenPoints(location, a);
b.distance = distanceBetweenPoints(location, b);
return a.distance - b.distance;
});
return arrayOfPoints;
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var points = [];
for (i = 0; i < 100; i += 1) {
points.push([getRandomInt(-90, 90), getRandomInt(-180, 180)]);
}
console.log(sortByDistance([0, 0], points).slice(0, 10));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.