计算移动设备的实际行驶距离

时间:2015-12-31 20:24:25

标签: java android ios objective-c google-maps

我想计算移动(iOS和Android)的实际行进距离。我知道通过谷歌地图API,我们可以找到2个坐标之间的最佳路线距离。但我想计算距离,实际路径移动(在车辆中)已覆盖。

我知道的一个Algo是在x秒后保存坐标,比如说在5或10秒之后,然后计算连续坐标之间的距离,总和将给出总距离。

我想讨论其解决方案的更好方法,有没有更好的解决方案?

编辑:像耐克运行应用程序和优步的应用程序如何工作?

10 个答案:

答案 0 :(得分:18)

------------------的更新 --------------------- -

你的问题有两点。

1)获取电话坐标(已在此响应的第一部分处理过)

2)计算这两个坐标之间的实际距离

恕我直言,微积分可以通过网络服务完成:仅基于计算 两个坐标之间的距离可能会导致真正错误的结果。

以下是此类Web服务的示例 https://graphhopper.com/#directions-api

演示应用:https://graphhopper.com/api/1/examples/

它基于流量(这些工具很多) 所以你必须小心坐标的顺序 因为它可能带来错误的结果。

例如,正确的顺序有两点: enter image description here

这会产生良好的效果

但是如果你给出错误的订单(使用相同的坐标) enter image description here

对于相同的坐标,可能会导致极为不同的结果。

因此对于坐标ABCD(按照时间顺序) 你需要这样做:

A-> B B-> C C-> D

Graphhopper似乎能够进行离线距离演算

以下是iOS和Android上的lib

https://github.com/graphhopper/graphhopper-ios/

https://github.com/graphhopper/graphhopper/tree/master/android

<强> -------------------------------------------- -------

您必须定义应用的工作方式。前景或背景?

如其他回复中所述,您必须每隔X秒获取一次用户位置。然后计算距离。

适用于iOS:

  1. 您可以使用本网站上的信息:http://mobileoop.com/
  2. 它讨论了当应用在后台时在iOS上跟踪用户位置。

    1. 这是github:https://github.com/voyage11/Location
    2. 然后你必须转换点

      CLLocationDistance distance = [aCLLocationA distanceFromLocation:aCLLocationB];
      

      您也可以查看此内容(来自Apple doc)https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html

        

      确保位置管理器的pausesLocationUpdatesAutomatically属性设置为YES。当此属性设置为YES时,只要有意义,Core Location就会暂停位置更新(并关闭位置硬件),例如当用户不太可能正在移动时。 (核心位置在无法获取位置修复时也会暂停更新。)

           

      为位置管理器的activityType属性分配适当的值。此属性中的值有助于位置管理员确定何时可以安全地暂停位置更新。对于提供逐向导航汽车导航的应用程序,将属性设置为CLActivityTypeAutomotiveNavigation会导致位置管理器仅在用户未在一段时间内移动较长距离时暂停事件。

      CLActivityTypeAutomotiveNavigation 确保您获得在路上的位置。

      适用于Android:

      1. 您可以使用此项目: https://github.com/quentin7b/android-location-tracker
      2. 这可以轻松帮助您通过时间获得用户的位置 感谢TrackerSettings对象

        TrackerSettings settings =
                new TrackerSettings()
                    .setUseGPS(true)
                    .setUseNetwork(true)
                    .setUsePassive(true)
                    .setTimeBetweenUpdates(30 * 60 * 1000)
                    .setMetersBetweenUpdates(100);
        
        1. 要查找Android上两点之间的距离,您可以查看以下内容: Get the distance between two geo points
        2. 两个操作系统

          根据每X秒拾取一次的位置,您必须缩短选择位置数据之间的时间,以提高准确性。

          如果您想计算道路环境中的距离,请在导航模式中设置位置管理器,此模式为您提供在路上的坐标。

          <强>最后

          如果您想提高距离演算的准确度, 你可以使用谷歌API: https://developers.google.com/maps/documentation/distance-matrix/intro

          设置正确的 模式 参数:

            

          可选参数

               

          模式(默认为驾驶) - 指定计算距离时要使用的传输模式。有效值和其他请求详细信息在本文档的“旅行模式”部分中指定。

答案 1 :(得分:8)

我在Andoriod上做过类似的事情,但iOS的主要内容也是如此:

  1. 对于每个GPS样本,请检查其准确性。如果超过某个阈值(比如20米) - 忽略它。
  2. 请记住,即使移动设备是静态的,根据准确性,不同的GPS样本也会为您提供不同的位置。在交通信号灯中长时间静止的汽车将显示您已经推进了几十米,所以添加一种方法来检测移动设备是否静止。我通过读取加速度计实现了这一点 - 如果两个读数之间的差值大于某个阈值 - 设备正在移动。如果它太小 - 忽略GPS。
  3. 如果您打算在汽车中使用它,只要有新的读数,您就可以阅读GPS(在Android中使用onLocationChanged方法)。如果您将它用于跑步/步行,请考虑到您的速度很慢 - 两个连续的读数将相对接近,但由于GPS的准确性,您可以获得相当大的距离。它可以通过增加两次连续读数之间的时间来固定,或者忽略其中一些读数(即只考虑每次读数的10次)。
  4. 使用Haversine formula计算两个连续读数之间的距离。在Android中,可以使用Location.distanceTo()方法完成。
  5. 您必须根据汽车里程表对其进行测试,并调整加速度计的阈值。

答案 2 :(得分:7)

  

结合以下策略,您可以获得更高的准确度。

  1. 如其他答案中所述,您可以 存储移动设备的位置 每隔X秒 (比如10秒)使用GPS测量 点之间的连续时间。

  2. 此外,当用户快速转弯时,请务必阅读 使用磁传感器值也是如此,因此在这种情况下, 减少了 &#34;位置存储和#34;之间的时间安排说1-2秒 (准确性需要)

  3. 最后一步, 使用地图数据 (例如Google地图等)确保 正在被正确跟踪(如果在路上)。

  4. 然后总结所有值以获得准确的距离。

    P.S。我提供了有关策略的信息,因为我不确定它在Android(或iOS)中的实现。

    希望这会有所帮助:)

答案 3 :(得分:6)

4年前,我刚刚创建了一个名为Landsurvayor的应用程序,用于计算Google地图上绘制的两个地理点的实际距离。我不知道这可能会对您有所帮助,但有一个名为 Haversine公式的公式可以计算两个地理点之间的实际距离。您可以尝试一下,看看它是否对您有用。以下是Haversine公式的示例代码:

public double CalculationByDistance(double initialLat, double initialLong,
                            double finalLat, double finalLong){
int R = 6371; // km
double dLat = toRadians(finalLat-initialLat);
double dLon = toRadians(finalLong-initialLong);
lat1 = toRadians(lat1);
lat2 = toRadians(lat2);

double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
        Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
return R * c;
}

public double toRadians(deg) {
  return deg * (Math.PI/180)
}

有关Haversine公式的更多信息: https://en.wikipedia.org/wiki/Haversine_formula

还有另一种简单的Android SDK内置方法来计算两个lat之间的距离,lng:

Location locationA = new Location("point A");     
locationA.setLatitude(latA); 
locationA.setLongitude(lngA);
Location locationB = new Location("point B");
locationB.setLatitude(latB); 
LocationB.setLongitude(lngB);
distance = locationA.distanceTo(locationB) ;

我希望它对你有所帮助。

答案 4 :(得分:3)

如果您正在寻找精确(或接近精确)的距离信息,则需要跟踪所遵循的路径,这意味着每隔几秒检查一次坐标(取决于预期的行驶速度)。您可以在计算每个段后丢弃旧坐标并仅存储当前行进的距离来节省空间。

答案 5 :(得分:3)

Android :: how to calculate distance while walking in android?

  

有不同的方法可以做到这一点:

     

1.GPS:每X秒(比如10秒)继续增加2点之间的GPS距离。检查Android Location.distanceTo或distanceBetween。校验   My Tracks应用程序,它是开源的。 GPS在室内无法使用   如果用户非常频繁地改变方向会有错误(阅读   每1-2秒)   2.Accelerometer:使用加速度计查找用于步进检测的代码/库。距离来自加速度的双重整合,   错误可以很快加起来。   3.Step探测器:内置于Nexus 5.Google必须尽可能地处理加速度计误差。这是基于硬件的   计算,消耗更少的电池,但在大多数情况下不可用   截至日期的手机。

第二个选项看起来与你的建议非常相似,我认为它是实现它的最佳方式,因为iOS和Android推迟了代码和功能,实现它的最佳方法是保存 currentLocation previousLocation 在一个while循环中 .sleep(),只需将整个循环与行进的距离相加。 更大的问题是,这个应用程序是一个距离总结应用程序?它只是一个小功能吗?你如何决定何时停止计算距离?

答案 6 :(得分:3)

使用GPS坐标的一个问题是它们(显然)不准确。如果您以直线行驶,GPS坐标可能会显示您在之字形路径上行驶,因此返回的行驶距离比真实距离更远。即使具有良好的GPS精度,该误差也可能很大。使用较少的坐标可以实现更准确的计算。

您需要的是一种平滑GPS路径的方法,同时充分考虑您所需的精度(再次权衡)。

我的第一个想法是将点分成小组,并为每个组拟合线段(查找&#34;线性回归&#34;)。然后找到每个连续线对重叠的位置以定义每个线段。然后简单地将线段长度相加。

您可以对曲线进行曲线拟合,但数学上更加强烈,并且可能无法产生更好的结果(以及使用哪种曲线公式?)。可能有更好的数学方法,我不知道。

希望这会有所帮助。

答案 7 :(得分:3)

使用GPS获取两个地方的纬度,然后将两者传递给下方法。它将以km为单位返回距离

public static double getDistanceFromLatLonInKm(double lat1, double lon1,
        double lat2, double lon2) {



    double R = 6371; // Radius of the earth in km
    double dLat = deg2rad(lat2 - lat1); // deg2rad below
    double dLon = deg2rad(lon2 - lon1);
    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
            + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2))
            * Math.sin(dLon / 2) * Math.sin(dLon / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double d = R * c; // Distance in km


    return d;

}

public static double deg2rad(double deg) {
    return deg * (Math.PI / 180);
}

}

答案 8 :(得分:3)

如果准确性至关重要,您可以使用加速度计和陀螺仪的数据。您可以找到解决简单电影任务的非常简单的公式,以便在全局轴上获得acc。比你只需要使用积分两次(首先获得速度,而不是获得位置)。 只是为了展示另一种观点。

答案 9 :(得分:2)

每x秒记录一次点数(可能是2-3?),并在每个记录点使用下面的距离公式。

Distance = sqrt((x2−x1)^2+(y2−y1)^2)

总结一下,你得到距离