根据坐标在数组中查找对象

Find object in array based on coordinates

本文关键字:查找 对象 数组 坐标      更新时间:2023-09-26

假设我有一个如下格式的数组:

var arr = [{lat: 123.123, lng: 321.321}, {lat: 567.567, lng: 765.765}]

基于一些地图坐标,我如何才能最有效地找到与地图坐标最接近的坐标的对象?

一个简单的解决方法是:

var getClosestPoint = function(coord, coordArray) {
  var bestDistance = null;
  var bestCoord = null;
  for (var i = 0; i < coordArray.length; ++i) {
    var currentCoord = coordArray[i];
    var distance = getDistance(coord, currentCoord);
    if ((bestDistance == null) || (distance < bestDistance)) {
      bestDistance = distance;
      bestCoord = currentCoord;
    }
  }
  return {'distance': bestDistance, 'coord':bestCoord};
 };
 // Based on the solution here:
 // http://stackoverflow.com/questions/365826/calculate-distance-between-2-gps-coordinates
 var getDistance = function(coordA, coordB) {
   var R = 6371; // km
   var dLat = (coordB.lat-coordA.lat).toRad();
   var dLon = (coordB.lng-coordA.lng).toRad();
   var lat1 = coordA.lat.toRad();
   var lat2 = coordB.lat.toRad();
   var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
           Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
   var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
   var d = R * c;
   return d;
 };

换句话说,朴素解就是迭代所有的点,更新当前的最佳距离和相应的坐标。如果你列出的要点很少,这样做可能是合理的。然而,更有效的解决方案是使用树结构,其中树中的每个内部节点由该节点下所有点的平均坐标表示。然后,您通过使用最近的平均坐标的节点降序搜索树,直到您到达叶节点。这种方法允许您在每次迭代中抛出更多的候选点,从而给出对数解。

换句话说,更有效的解决方案是:

var getClosestPoint = function(coord, coordNode) {
  var children = coordNode.getChildren();
  if (children.length == 0) {
    return coordNode.getCenterCoord();
  }
  var closestChild = null;
  var bestDistance = 0.0;
  for (var i = 0; i < children.length; ++i) {
    var currentCoord = children[i].getCenterCoord();
    var distance = getDistance(coord, currentCoord);
    if ((closestChild == null) || (distance < bestDistance)) {
      closestChild = children[i];
      bestDistance = distance;
    }
  }
  return getClosestPoint(coord, closestChild);
}

当然,这假设您首先构建了这样一个树。如果您使用相同的点集重复运行"getClosestPoint()",那么构建这样的结构可能是值得的(如果您只对任何给定的点集执行一次"getClosestPoint()",那么朴素的解决方案可能是合理的)。关于K-D树和四叉树的文章可能会对进一步阅读这种一般方法以及如何在这些树中建立和划分点感兴趣。

我相信这应该在方形网格上工作。如果数值在某个点后重置,如在地球上,则需要对该解决方案进行一些调整。

function calculateDistance(x1, x2, y1, y2){
  return Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2));
}
var retrievedCoords = {lat: 12234, lng: 135};
var closestPoint = arr[0];
var distanceToClosestPoint = calculateDistance(retrievedCoords.lat, arr[0].lat, retrievedCoords.lng, arr[0].lng);
for (var i = 1; i < arr.length; i++){
  var tempDist = calculateDistance(retrievedCoords.lat, arr[i].lat, retrievedCoords.lng, arr[i].lng);
  if (tempDist > distanceToClosestPoint){
    closestPoint = arr[i];
    distanceToClosestPoint = tempDist;
  }
}