【问题标题】:Get the shortest distance from a point得到一个点的最短距离
【发布时间】:2013-08-24 15:58:05
【问题描述】:

我在 sqlite 中有这张表

Locations
ID
Lat ( latitude)
Lon ( longitude) 
Type
Name
City

例如,我有 100 条记录 我需要的是获取(使用我自己的坐标)我表中最近的点。

我所做的是获取当前点与表中每个点之间的最短距离,并返回最短的点,但我正在寻找更好的解决方案

谢谢

【问题讨论】:

  • 更新了我的答案。很乐意在不放弃任何来之不易的声誉的情况下提供更多详细信息 - 只要问:)

标签: android sql sqlite gps location


【解决方案1】:

一种可能的解决方案是为您感兴趣的整个地图使用网格,并将点预分配给特定的行/列。那么:

  1. 计算新点的网格位置 - 为此在数据库中添加一列。
  2. 计算当前网格中所有坐标的距离 - 如果存在的话
  3. 您仍然需要计算下一个网格中的所有距离(您不太可能在当前方格中完全居中,您始终需要检查与您的最佳匹配所在的格子之间的一个网格距离。)李>

应该大大减少您需要执行的计算次数。

如果您希望始终在 X 距离内找到一个位置,您可以查询该范围内的 x/y 坐标,您的坐标 +/- x KM(正方形),然后计算它们是否落在 xKM 圆内你的点,然后选择最短的。

更新 - 网格选项

我假设您已经在计算两点之间的距离,并且不会对此进行描述。

如果您手头有地图集,则可以通过在索引中查找位置来查看示例。它会给你一个页面和一个网格位置,如 M5。如果您转到该页面,它将具有标有数字和字母的行和列,如果您查看 M 行和第 5 列相交的正方形,您会在那里找到城市。要为您的系统执行此操作,您需要:

  1. 确定您的网格应该有多大(您的点有多密集 - 拥有一个大网格并且您的所有点都落在一个正方形上是不好的)。
  2. 为每个点计算它所在的网格。如果您的多边形很复杂,那么多边形代码中有大量的点需要复制。如果(如我的示例)您只使用正方形,则只需确定每个点位于哪一行/哪一列。
  3. 查看地图了解用户位置和最近点示例:

因此,如果用户是绿色标记,他将在 C4 中。您将搜索 C4 中的所有其他点并确定最接近的是 #2。然后你还必须检查一个网格以确保没有比你找到的更接近的项目,所以这包括正方形:B3、B4、B5、C3、C5、D3、D4、D5 .当你这样做时,你将从 C3 中选择 #3,然后你就完成了。

如果用户在没有其他点的正方形 D2 中,您会在 C2 中找到您的第一个匹配项。检查 C1、C2、C3、D1、D3、E1、E2、E3 时。一旦找到,您将再次需要检查另一个半径,即:B0-4、C0、C4、D0、D4、E0、E4、F0-4。等等。您可以看到,网格选择对于使其尽可能高效非常重要。

另请注意,这假设您的网格与我的手绘示例不同。

选项 2:

如果您希望在 X 公里范围内得到结果,并且您希望您的数据库能够快速计算,您可以这样做:

LatMin = currentLatCoord-radiusValInDegrees
LatMax = currentLatCoord+radiusValInDegrees
LonMin = currentLonCoord-radiusValInDegrees
LonMax = currentLonCoord+radiusValInDegrees

SELECT * 
From Locations 
WHERE Lat BETWEEN LatMin AND LatMax
  AND Lon BETWEEN LonMin AND LonMax

现在这会将所有结果显示在一个正方形中。然后检查它们实际上是否在圆圈中很重要 - 您需要在角落放下任何东西,因为实际上可能比圆圈边缘的坐标更接近。因此,对于每个点,首先检查它是否在圆内(Equation for testing if a point is inside a circle),然后计算距离并保持最近的距离。如果没有得到结果,请扩大圈子。

同样,选择合适的半径将取决于您的数据。

【讨论】:

  • “最近的一对点”在一个点已知时没有用。另外,他目前正在使用 O(n) 解决方案,因此建议使用 O(nlogn) 解决方案是一个奇怪的选择。它的其余部分是正确的,但它开始有点误导。
  • @Geobits 谢谢 - 当我重新阅读他的问题并第一次扩展问题时,我实际上以为我删除了那部分。现在走了。
  • 这是有道理的。它肯定看起来很贴切,就像两个完全不同的答案。先生,为您 +1。
  • @Geobits 如果你曾经在该地区,我会带你去钓鱼@B7 - 很棒的地方:)
【解决方案2】:

您是否查看过此站点以了解如何计算distance between two points on Earth

但请记住,它给出的距离基于地球表面,而不是基于到达该位置的实际路径。因此,如果您想根据到达该位置的实际路径来计算距离,那么您可以使用 Google MAP API 来获取它。

Google Maps API根据实际路径给出两点之间的距离。

希望这些信息对您有所帮助。

享受编码... :)

【讨论】:

  • 感谢@Peril 接受回答。喜欢帮助你。如果您还有其他问题,请告诉我。
【解决方案3】:

两点之间的距离:((x1 - x2) ^ 2 + (y1 - y2) ^ 2) ^ 0.5。但是,这些点之间的距离是直线。最有可能的是,存在诸如本地与高速公路之类的变量,更不用说单向街道和水路了,您需要在其中找到最近的桥梁。因此,我建议使用 Google 和 Bing 地图 api。搜索次数有限。

【讨论】:

  • 我正在使用离线 osmdroid 地图,所以我无法使用 Google api,但我的积分非常有限,比如我必须搜索最多 200 分
  • +1 用于使用路线 API。当乌鸦飞过时,距离在现实场景中没有多大意义。
【解决方案4】:

Query to get records based on Radius in SQLite? 有一个相当聪明的解决方案 基于在插入行时预先计算每个位置的一些三角函数值,然后您可以仅使用算术函数计算查询中的距离。

我已经在自己的代码中非常成功地使用了它

【讨论】:

    【解决方案5】:

    让我确保这是正确的:你有一个点 a,还有一个点表 a[]。目前,您执行以下操作:

    • 循环遍历b[]
      • b[i] 获取distancea
      • 如果distance 小于minimumDistance
        • 设置minimumDistance = distance
        • 设置closestPoint = i
    • 返回closestPoint

    如果是这样,您将在O(n) 时间找到它,这实际上无法改进。您必须检查所有点以查看最接近的点。

    但是,正如 Matthew 指出的那样,您可以通过将点分配给网格来修剪 n。这可以大大减少需要比较的点数。代价是一些时间预处理,以及稍微复杂的逻辑。如果你有很长的点列表(或者distance() 函数需要很长时间),你肯定会想做这样的事情。

    【讨论】:

      【解决方案6】:

      取决于你在两极附近时对正确性的关心程度

      如果最接近的勾股距离足够好,您可以在 sql 的 orderby 中使用它

      例如。 SELECT * FROM locations ORDERBY (Lat-myLat)*(Lat-myLat) + (Lon-myLon)*(Lon-myLon) LIMIT 1

      技术上不是最正确的,但省去了从数据库中获取所有位置并循环访问它们,让 sqlite 为你做这件事

      【讨论】:

        【解决方案7】:

        你可以使用我的php类希尔伯特曲线@phpclasses.org。它使用怪物曲线和四键来找到最短距离。要搜索四键,您可以使用任何深度。

        【讨论】:

          【解决方案8】:

          虽然这不是最佳选择。
          让您试图找出在 N 英里/公里范围内的最短距离,用于固定的位置数/您的位置表数据不会定期更改。
          添加另一列 Distance_Index (DI) 自多引用键 ArrayType。一旦运行一个程序并根据与该 DI 的距离以升序更新带有 ID 的 DI。 现在从下一次开始,距离与您同在。只需查询数据库并使用它。

          现在,在您的问题中,N 内的位置没有更少,那么 DI 不会太长。只是作为一种意见。

          【讨论】:

            猜你喜欢
            • 2010-10-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-10-27
            • 1970-01-01
            • 2023-02-07
            • 2012-04-10
            相关资源
            最近更新 更多