Javascript 这种用于地理位置搜索的经纬度边界框算法有什么问题?

Javascript 这种用于地理位置搜索的经纬度边界框算法有什么问题?,javascript,typescript,math,geolocation,calculation,Javascript,Typescript,Math,Geolocation,Calculation,我有一小段代码,我正在使用它来查找一个位置的边界框,以便在半径范围内搜索用户配置文件。它几乎像我想要的那样工作,但不幸的是最终值有点失真。例如,如果我将50英里传递到函数中,我得到的点可能距离原点70英里,而不是50英里。我想这和我正在计算的一个常数有点偏离有关 常数: const RAD_CON = Math.PI / 180; // Radian conversion constant const R_EARTH = 6378; // Radius of the earth in Km co

我有一小段代码,我正在使用它来查找一个位置的边界框,以便在半径范围内搜索用户配置文件。它几乎像我想要的那样工作,但不幸的是最终值有点失真。例如,如果我将50英里传递到函数中,我得到的点可能距离原点70英里,而不是50英里。我想这和我正在计算的一个常数有点偏离有关

常数:

const RAD_CON = Math.PI / 180; // Radian conversion constant
const R_EARTH = 6378; // Radius of the earth in Km
const KM_PER_MILE = 1.609344; // Km/mile conversion constant

// I think this might be wrong
const METER_DEGREES = (1 / ((2 * Math.PI / 360) * R_EARTH)) / 1000; // Meters per degree lat/lng
违规代码:

_getBoundingCoords(location: Location, miles: number) {
    const meters = miles * KM_PER_MILE * 1000;

    const latNorth = location.lat + (meters * METER_DEGREES);
    const latSouth = location.lat - (meters * METER_DEGREES);
    const lngWest = location.lng + (meters * METER_DEGREES) / Math.cos(location.lat * RAD_CON);
    const lngEast = location.lng - (meters * METER_DEGREES) / Math.cos(location.lat * RAD_CON);

    return [latNorth, latSouth, lngWest, lngEast];
}
如果您想知道我是如何使用它的,我将使用返回的值为mongodb集合构建一个查询。已查询的数据的格式为

{
  lat: number;
  lng: number;
}
查询:

const query = {
  $and: [{
    'location.lat': {
      $lte: latNorth,
      $gte: latSouth,
    },
  }, {
    'location.lng': {
      $lte: lngWest,
      $gte: lngEast,
    },
  }],
};
有很多数学与计算纬度和经度坐标,非常详细的解释在

. 幸运的是,您不必将其转换为Javascript,因为有一个很好的资源可以在

为了帮助您开始使用这些函数,下面是一个快速示例,使用其中一些函数

计算两个坐标之间的距离,以及 计算给定起始坐标、方位和距离(以米为单位)的坐标。本例中使用的值取自上文标题为“终点-给定距离和方位-起点”一节中的第一个参考值。 导入LatLon,{Dms}from'https://cdn.jsdelivr.net/npm/geodesy@最新/latlon Spheremic.min.js'; Dms.separator=; //计算两点之间的距离。 设d=new LatLon 52.205,0.119。与new LatLon的距离为48.857,2.351; console.log d; //计算给定起点、距离和方位的终点。 设p1=new-LatLon-Dms.parse 053°19′14〃,Dms.parse-001°43′47〃; 设brng=Dms.096°01′18〃; 设dist=124.8*1000;//以米为单位的距离。 设p2=p1.destinationPoint距离,brng;//53°11′18〃北纬,000°08′00〃东经 console.log p2; console.log[Dms.toDms p2.lat,'Dms',Dms.toDms p2.lon,'Dms']; 有很多数学与计算纬度和经度坐标,非常详细的解释在

. 幸运的是,您不必将其转换为Javascript,因为有一个很好的资源可以在

为了帮助您开始使用这些函数,下面是一个快速示例,使用其中一些函数

计算两个坐标之间的距离,以及 计算给定起始坐标、方位和距离(以米为单位)的坐标。本例中使用的值取自上文标题为“终点-给定距离和方位-起点”一节中的第一个参考值。 导入LatLon,{Dms}from'https://cdn.jsdelivr.net/npm/geodesy@最新/latlon Spheremic.min.js'; Dms.separator=; //计算两点之间的距离。 设d=new LatLon 52.205,0.119。与new LatLon的距离为48.857,2.351; console.log d; //计算给定起点、距离和方位的终点。 设p1=new-LatLon-Dms.parse 053°19′14〃,Dms.parse-001°43′47〃; 设brng=Dms.096°01′18〃; 设dist=124.8*1000;//以米为单位的距离。 设p2=p1.destinationPoint距离,brng;//53°11′18〃北纬,000°08′00〃东经 console.log p2; console.log[Dms.toDms p2.lat,'Dms',Dms.toDms p2.lon,'Dms'];
正如乔恩·特伦特(Jon Trent)所建议的那样,虽然您最好使用大地测量库,但快速破解可能会改进您的代码

这是利用一个事实,在给定的纬度上,一个经度值,作为一个距离,等于一个纬度值。所以在赤道,它们大致相同,但当你接近两极时,经度的距离会越来越小


如果你的边界框在几英里之外相当小,那么你可以通过使用中间纬度的余弦作为比例因子来获得合理的精度。

正如乔恩·特伦特所建议的那样,虽然你最好使用大地测量库,但快速的破解可能会改进你的代码

这是利用一个事实,在给定的纬度上,一个经度值,作为一个距离,等于一个纬度值。所以在赤道,它们大致相同,但当你接近两极时,经度的距离会越来越小

如果你的边界框在几英里外相当小,那么你可以使用中间纬度的余弦作为比例因子来获得合理的精度。

参考

…特别是Javascript代码中的“目的地点”一节给出了距离和方向距起点的距离,下面是计算目的地点的公式,给出了纬度、经度、方向、距离和地球半径。请注意,角度以弧度为单位,并且 距离以所需的任何单位表示,即英里、公里、米等

此外,我还创建了两个助手函数,用于将度、分和秒转换为弧度,反之亦然。可能不是最好的界面,但它们很实用

// //将度、分和秒转换为弧度。 // 功能dmsToRad deg,min,sec{ 返回数学符号deg*Math.abs deg+min/60+sec/3600*Math.PI/180; } // //将弧度转换为度、分和秒。四舍五入到1/3600。 // 函数radToDms rad{ 设d=Math.round Math.abs rad*180/Math.PI*3600/3600; 设deg=Math.trunc d; 设余数=d-度*60; 设min=Math.trunc余数; 余数=余数-最小值*60; 设sec=Math.round余数; deg=deg*数学符号rad; 返回{ 度:度,分:分,秒:秒, 漂亮:`${Math.signrad===-1?'-':+'00'+Math.absdeg.slice-3}°${'0'+min.slice-2}'${'0'+sec.slice-2}'` }; } //在给定纬度、经度、方位的情况下计算目标点, //距离和地球半径。请注意,角度以弧度为单位,并且 //距离以所需的任何单位表示,即英里、公里、米等。 // //直接来源于https://www.movable-type.co.uk/scripts/latlong.html // 函数目标点φ1,λ1,brng,d,R{ 常数φ2=Math.asin Math.sinφ1*Math.cos d/R+ Math.cosφ1*Math.sin d/R*Math.cos brng; 常数λ2=λ1+Math.atan2 Math.sin brng*Math.sin d/R*Math.cosφ1, Math.cos d/R——Math.sinφ1*Math.sinφ2; 返回{lat:φ2,lon:λ2}; } // //使用参考网站上的样本数据进行测试。 // 设dest=destinationpointdmstorad 53,19,14,dmsToRad-1,43,47,dmsToRad 96,1,18,124.86371; console.log dest console.log[radToDms dest.lat,radToDms dest.lon];//053°11′18〃000°08′00〃

…特别是Javascript代码中的“目的地点”一节给出了距离和方向距起点的距离,下面是计算目的地点的公式,给出了纬度、经度、方向、距离和地球半径。请注意,角度以弧度为单位,距离以所需的任何单位为单位,即英里、公里、米等

此外,我还创建了两个助手函数,用于将度、分和秒转换为弧度,反之亦然。可能不是最好的界面,但它们很实用

// //将度、分和秒转换为弧度。 // 功能dmsToRad deg,min,sec{ 返回数学符号deg*Math.abs deg+min/60+sec/3600*Math.PI/180; } // //将弧度转换为度、分和秒。四舍五入到1/3600。 // 函数radToDms rad{ 设d=Math.round Math.abs rad*180/Math.PI*3600/3600; 设deg=Math.trunc d; 设余数=d-度*60; 设min=Math.trunc余数; 余数=余数-最小值*60; 设sec=Math.round余数; deg=deg*数学符号rad; 返回{ 度:度,分:分,秒:秒, 漂亮:`${Math.signrad===-1?'-':+'00'+Math.absdeg.slice-3}°${'0'+min.slice-2}'${'0'+sec.slice-2}'` }; } //在给定纬度、经度、方位的情况下计算目标点, //距离和地球半径。请注意,角度以弧度为单位,并且 //距离以所需的任何单位表示,即英里、公里、米等。 // //直接来源于https://www.movable-type.co.uk/scripts/latlong.html // 函数目标点φ1,λ1,brng,d,R{ 常数φ2=Math.asin Math.sinφ1*Math.cos d/R+ Math.cosφ1*Math.sin d/R*Math.cos brng; 常数λ2=λ1+Math.atan2 Math.sin brng*Math.sin d/R*Math.cosφ1, Math.cos d/R——Math.sinφ1*Math.sinφ2; 返回{lat:φ2,lon:λ2}; } // //使用参考网站上的样本数据进行测试。 // 设dest=destinationpointdmstorad 53,19,14,dmsToRad-1,43,47,dmsToRad 96,1,18,124.86371; console.log dest
console.log[radToDms dest.lat,radToDms dest.lon];//053°11′18〃000°08′00〃很酷,谢谢!我希望自己做计算,但如果我对自己的东西不满意,这是一个不错的选择。我不知道为什么我在这个答案上收到了双重的叮当声@我添加了另一个答案,它利用了第一个参考中的函数,因此不需要导入整个库。很酷,谢谢!我希望自己做计算,但如果我对自己的东西不满意,这是一个不错的选择。我不知道为什么我在这个答案上收到了双重的叮当声@泰,我添加了另一个答案,它利用了第一个参考中的函数,因此不需要导入整个库。我将使用您提到的库哈哈。看起来很容易使用。上面的内容看起来比我想了解的更深一点。谢谢你所做的一切@蒂诺w
奥利斯。很高兴我能帮忙。另外,我觉得有点有趣的是,选择了有用评级为-1的回答作为答案…我将使用你提到的图书馆哈哈。看起来很容易使用。上面的内容看起来比我想了解的更深一点。谢谢你所做的一切@别担心。很高兴我能帮忙。另外,我觉得选择有用评级为-1的回答作为答案有点有趣。。。