【问题标题】:In array of coordinates find the point closest to the given在坐标数组中找到最接近给定的点
【发布时间】:2020-07-21 11:13:09
【问题描述】:

我有一个具有 2 个属性的对象 - 纬度和经度。我想通过考虑这两个属性来从对象数组中获得最近的匹配。

obj = {latitude: 55.87, longitude: 4.20}

[
  {
    "latitude": 55.85,
    "longitude": 4.22
  },
  {
    "latitude": 55.89,
    "longitude": 4.16
  },
  {
    "latitude": 55.88,
    "longitude": -4.24
  }
]

我需要得到最接近匹配的数组索引。

【问题讨论】:

  • @alou :您所指的线程是关于 flat 坐标的,当涉及到球面距离(这里就是这种情况)时,您需要一些更复杂的公式
  • 使用haversine公式计算每个点的距离,然后选择距离最短的点。

标签: javascript arrays angular typescript arrayobject


【解决方案1】:

有一个Haversine formula 可以计算您的点与数组中每个点之间的球面距离,例如使用Array.prototype.reduce():

const haversine = ({longitude: lonA, latitude: latA}, {longitude: lonB, latitude: latB}) => {
        const {PI, sin, cos, atan2} = Math,
              r = PI/180,
              R = 6371,
              deltaLat = (latB - latA)*r,
              deltaLon = (lonB - lonA)*r,
              a = sin(deltaLat / 2)**2 + cos(cos(latB*r)*latA*r) * sin(deltaLon /2)**2,
              c = 2 * atan2(a**0.5, (1 - a)**0.5),
              d = R * c
        return d
      },
      
      obj = {latitude: 55.87, longitude: 4.20},

      arr = [{"latitude":55.85,"longitude":4.22},{"latitude":55.89,"longitude":4.16},{"latitude":55.88,"longitude":-4.24}],
      
      {closest} = arr.reduce((r,o) => {
        const distance = haversine(o, obj)
        distance < r.minDistance || !r.closest &&
        (r.closest = o, r.minDistance = distance)
        return r
      }, {closest: null, minDistance: null})
      
console.log(closest)
.as-console-wrapper{min-height:100%;}

【讨论】:

  • 感谢您抽出宝贵时间编写代码 Yevgen。非常感谢您的帮助。是的,我们可以这样做。我发现的另一种选择是在 Angular 中使用 haversine 库,它提供输出...npmjs.com/package/ng2-haversine 但是,是的,就像您提到的那样,我们需要使用 Haversine 公式来获得结果。
  • @SuryaN :这完全取决于你——你是想实现 10 行自己的 Haversine 实现还是维护外部库。
  • 哪一个在性能方面会更好?请告诉我。我是 Angular 的新手。
  • 不幸的是,Angular 不是我的强项(我宁愿来自 React 阵营),所以我不能用一些确切的基准来支持我的观点。但是,我会说该库会产生更多开销,因此它的执行速度可能会稍慢一些,并且可能会减慢一些初始渲染速度。我不建议使用该库的原因是完全不同的:仅出于由 10 行代码实现的一项功能的唯一目的,附加库并维护它的依赖项似乎没有多大意义。
  • 我同意你的看法@Yevgen。很好的解释。
【解决方案2】:

你可以用 JS 做到这一点。你可以用这个piece of code

export class ContentComponent implements OnInit {

  compareTo: any = { latitude: 55.87, longitude: 4.20 };
  data: Array<any> = [
    {
      "latitude": 55.85,
      "longitude": 4.22
    },
    {
      "latitude": 55.89,
      "longitude": 4.16
    },
    {
      "latitude": 55.88,
      "longitude": -4.24
    }
  ];

  // data filtered
  filteredData: Array<any> = [];

  constructor() { }

  ngOnInit() {
    
    var tmpData: Array<any> = [];

    this.data.forEach(x => {
      var res = this.computeDistance(x.latitude, x.longitude, this.compareTo.latitude, this.compareTo.longitude, "K");
      tmpData.push({ distance: res, obj: x });
    });

    tmpData.sort((a, b) => a.distance - b.distance);
    tmpData.forEach(x => this.filteredData.push(x.obj));
    
  }

  computeDistance(lat1, lon1, lat2, lon2, unit) {
    if ((lat1 == lat2) && (lon1 == lon2)) {
      return 0;
    }
    else {
      var radlat1 = Math.PI * lat1/180;
      var radlat2 = Math.PI * lat2/180;
      var theta = lon1-lon2;
      var radtheta = Math.PI * theta/180;
      var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
      if (dist > 1) {
        dist = 1;
      }
      dist = Math.acos(dist);
      dist = dist * 180/Math.PI;
      dist = dist * 60 * 1.1515;
      if (unit=="K") { dist = dist * 1.609344 }
      if (unit=="N") { dist = dist * 0.8684 }
      return dist;
    }
  }
}

【讨论】:

  • 虽然您的代码不太适合直接进行基准测试(因此,我无法确定),但我会说建立距离数组并对其进行排序以找到最接近的距离比在单个循环中找到最近的更昂贵。
【解决方案3】:

使用以下代码获取索引。我遵循与@Meadow 相同的模式。

let points = [{
        "latitude": 55.85,
        "longitude": 4.22
      },
      {
        "latitude": 55.89,
        "longitude": 4.16
      },
      {
        "latitude": 55.88,
        "longitude": -4.24
      },
      {
        "latitude": 55.86,
        "longitude": 4.21
      }
    ];
    let allDistance:any = [];

    points.forEach((x,index)=> {
      var res = this.getDistance(x.latitude, x.longitude, 55.87, 4.20, "km");
      allDistance.push({ distance: res, obj: x,index: index});
    });

    allDistance.sort((a, b) => a.distance - b.distance);
    console.log("Index:"+allDistance[0].index);  
    console.log(allDistance);   

获取距离方法:

  getDistance(markerLat: any, markerLon: any, sourceLat: any, sourceLng: any,unit): any {
    var radlat1 = Math.PI * sourceLat / 180;
    var radlat2 = Math.PI * markerLat / 180;
    var theta = sourceLng - markerLon;
    var radtheta = Math.PI * theta / 180;
    var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
    if (dist > 1) {
      dist = 1;
    }
    dist = Math.acos(dist);
    dist = dist * 180 / Math.PI;
    dist = dist * 60 * 1.1515;
    dist = dist * 1.609344;
    if (unit != 'mi') {
      return isNaN(dist) ? 0 : dist;
    }
    return isNaN(dist * 0.62137) ? 0 : dist * 0.62137;
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-28
    • 1970-01-01
    • 1970-01-01
    • 2018-07-30
    • 1970-01-01
    • 2017-03-09
    相关资源
    最近更新 更多