使用Google地图API查找最近的位置

21

你好,我正在编写一款显示附近自行车站点的应用程序。我已经从服务中获得了每个自行车站点的纬度和经度位置列表。

我可以标记我的当前位置或任何其他地址。如何在地图上显示所有靠近我的位置的自行车站点?我应该先获取距离当前位置最近的Google位置,然后访问自行车位置数据库并在地图上标记吗?什么是最佳方法?

4个回答

27

如果您已经拥有自行车站的坐标并且信任这些数据,则可以使用它来绘制您的标记。现在,您需要定义“附近”的含义。

您有不同的解决方案。要么选择在地图范围内绘制所有自行车站的标记(根据缩放级别,可能需要绘制许多标记,或者必须防止脚本在达到某个缩放级别之前绘制标记),要么可以在距离位置(可以是用户位置、地图中心坐标等)n公里内绘制标记。

对于第二个解决方案,如果您正在将自行车站存储在MySQL数据库中,可以执行以下查询:

$sql = "SELECT *, ( 6371 * acos( cos( radians(" . $db->real_escape_string($lat) . ") ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(" . $db->real_escape_string($lng) . ") ) + sin( radians(" . $db->real_escape_string($lat) . ") ) * sin( radians( lat ) ) ) ) AS distance FROM your_table_name HAVING distance < 15";

$lat$lng是您的中心坐标。

latlng是您的MySQL列名。

15是以公里为单位围绕您坐标的半径。

这使用了Haversine公式。有关详细信息,请查看此处

希望这可以帮助您,但我们不知道您在应用程序中如何组织数据。如果您需要更多帮助,请给我们提供更多信息!


谢谢你提供的 SQL 查询。我已经获取了所有自行车站点的位置、纬度和经度,从一个服务中拉取并可以存储在 SQL 表中。我将尝试使用你的解决方案。我看到有人说,可以将所有的纬度和经度放入数组中,并使用 Haversine 公式。我有近 3000 条记录,不想将它们全部加载到数组中并搜索最近的一个。我想我会尝试你的第二个解决方案,并在这里更新哪个方案有效。干杯! - Geoplex
如果我有3K条记录,我会使用那种方法。这很好。我正在处理超过150K的记录,它运行得非常好。使用AJAX!你将拥有一个伟大的应用程序! :-) - MrUpsidown
非常感谢。帮了我很多。 - Bishal Paudel
它也帮助了我 :) - user3668438

15

以防万一,如果有人在2016年寻找正确答案。

谷歌创建了一个非常有用的,几何库有许多不同的方法可以帮助解决这个问题:

computeDistanceBetween()

这个答案详细解释了如何使用它。

通常会计算传递的两个LatLng对象之间的距离。

所以你可以简单地:

  • 获取所有自行车站点的位置。
  • 将它们存储在数组中。
  • 找到用户当前位置。
  • 循环你的数组,并使用上述方法将位置转换为距离。
  • 对数组进行排序以获得最小距离。

距离结果以米为单位表示。

前面的算法可能没有优化,因为我们中的一些人可能有数千个坐标的数组,这就是方法containsLocation()变得方便的地方,因为您可以通过指定一个多边形来缩小您的搜索区域。

这可能不是寻找最近位置的最佳方法,但我相信如果您的数据库中有合理数量的站点,它将能够胜任该工作。

你还应该考虑性能和API调用/配额。当OP提到他正在处理几千个位置时,我认为这不是一个合适的答案,特别是当你可以通过一个单一的数据库查询完成所有操作。 - MrUpsidown
@MrUpsidown,希望您在评论之前仔细阅读答案 :) - ProllyGeek
哪一部分?这两种方法都需要为每个点调用API。我错了吗? - MrUpsidown

5

我有同样的任务,使用haversine公式解决了问题。这是我的PHP示例:

private function distance($latA, $lngA,$latB, $lngB) {
    $R = 6371000;
    $radiansLAT_A = deg2rad($latA);
    $radiansLAT_B = deg2rad($latB);
    $variationLAT = deg2rad($latB - $latA);
    $variationLNG = deg2rad($lngB - $lngA);

    $a = sin($variationLAT/2) * sin($variationLAT/2) 
                + cos($radiansLAT_A) * cos($radiansLAT_B) * sin($variationLNG/2) * sin($variationLNG/2);

    $c = 2 * atan2(sqrt($a), sqrt(1-$a));

    $d = $R * $c;

    return $d;
}  

为了测试,我使用了以下坐标

$distance = $this->distance(-12.0972,-77.0267,-13.160616,-74.227440);

结果应该是 325932.546518 米。如果您想以公里为单位,请将 325932.546518/1000 = 325.932546518km
同样的公式可以按照指南 haversine 转换为 JavaScript。

1
这个数据 $R = 6371000; 是做什么用的?是静态的吗? - Dimas Adi Andrea
1
@DimasAdiAndrea $R 是地球半径 ;) - Rolly
1
我已经将这个公式与Google Maps的computeDistanceBetween函数进行了比较,同时将两者都设置为6378137地球半径。这个公式的结果为812.3261185522,而Google Maps函数的结果为812.3261185526761,这对我来说是可以接受的精度。因此,最终我选择在我的项目中使用这个公式。谢谢。 - Baim Wrong

4

谷歌可能已经有了这些结果,但如果您已经知道地点的坐标,直接绘制点似乎更为简单明了。


谢谢你的回答。看起来我需要另一个谷歌地点API密钥。我已经在使用Android Maps密钥来访问Maps API,这对我来说有点困惑,我需要多读一些资料。 - Geoplex
是的,你说得对。虽然谷歌可以提供很多有用的数据,但如果你能使用其他可信赖的来源(自己的数据、其他供应商等),就尽量使用它们吧!这样你就不会依赖谷歌进行数据更新(这可能很困难),在许多情况下你也无法依赖它。 - MrUpsidown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接