简体   繁体   English

如何在JavaScript中有效地计算最近的2D点?

[英]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相比的表现

Heap Code 堆密码

js fiddle 小提琴

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));

On jsFiddle jsFiddle上

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 distanceHaversine 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));

On jsFiddle jsFiddle上

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 Javascript 中计算 2D 中的旋转 - How to calculate rotation in 2D in Javascript 如何有效地删除Javascript中的2D数组中的空列 - How to remove empty columns in 2D Array in Javascript efficiently 如何在javascript中计算两个三角形之间的二维变换矩阵 - How to calculate the 2D transformation matrix between two triangles in javascript 计算二维旋转 javascript HTML canvas - Calculate 2D rotation javascript HTML canvas JavaScript:根据输入有效地创建空的2D数组 - JavaScript: efficiently create empty 2D array based on input 有效地将二维数组转换为 object 擦除 JavaScript 中的重复项 - Efficiently converting 2D array to an object erasing duplicates in JavaScript 获取二维数组JavaScript中两点之间的距离 - Getting distance between two points inside a 2d array JavaScript 如果在Javascript中指定了十进制时间,如何计算最接近的整个时间单位 - How to calculate nearest whole time unit if a decimal time is specified in Javascript 使用 JavaScript 从二维数组计算加权平均值 - Calculate the weighted average with JavaScript from a 2d array 如何用 JavaScript 中的 2D Smaller 数组填充 2D 数组 - How to fill an 2D array with a 2D Smaller array in JavaScript
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM