| 76 | } |
| 77 | |
| 78 | bool AreCoordsGoodForExtrapolation(location::GpsInfo const & info1, location::GpsInfo const & info2) |
| 79 | { |
| 80 | if (!info1.IsValid() || !info2.IsValid()) |
| 81 | return false; |
| 82 | |
| 83 | double const distM = ms::DistanceOnEarth(info1.m_latitude, info1.m_longitude, info2.m_latitude, info2.m_longitude); |
| 84 | |
| 85 | double const timeS = info2.m_timestamp - info1.m_timestamp; |
| 86 | if (timeS <= 0.0) |
| 87 | return false; |
| 88 | |
| 89 | // |maxDistAfterExtrapolationM| is maximum possible distance from |info2| to |
| 90 | // the furthest extrapolated point. |
| 91 | double const maxDistAfterExtrapolationM = distM * (Extrapolator::kMaxExtrapolationTimeMs / 1000.0) / timeS; |
| 92 | // |maxDistForAllExtrapolationsM| is maximum possible distance from |info2| to |
| 93 | // all extrapolated points in any cases. |
| 94 | double const maxDistForAllExtrapolationsM = kMaxExtrapolationSpeedMPS * kMaxExtrapolationTimeSeconds; |
| 95 | double const distLastGpsInfoToMeridian180 = |
| 96 | ms::DistanceOnEarth(info2.m_latitude, info2.m_longitude, info2.m_latitude, 180.0 /* lon2Deg */); |
| 97 | // Switching off extrapolation if |info2| are so close to meridian 180 that extrapolated |
| 98 | // points may cross meridian 180 or if |info1| and |info2| are located on |
| 99 | // different sides of meridian 180. |
| 100 | if (distLastGpsInfoToMeridian180 < maxDistAfterExtrapolationM || |
| 101 | (distLastGpsInfoToMeridian180 < maxDistForAllExtrapolationsM && info2.m_longitude * info1.m_longitude < 0.0) || |
| 102 | ms::DistanceOnEarth(info2.m_latitude, info2.m_longitude, 90.0 /* lat2Deg */, info2.m_longitude) < |
| 103 | maxDistAfterExtrapolationM || |
| 104 | ms::DistanceOnEarth(info2.m_latitude, info2.m_longitude, -90.0 /* lat2Deg */, info2.m_longitude) < |
| 105 | maxDistAfterExtrapolationM) |
| 106 | { |
| 107 | return false; |
| 108 | } |
| 109 | |
| 110 | // Note. |timeS| may be less than zero. (info1.m_timestampS >= |
| 111 | // info2.m_timestampS) It may happen in rare cases because GpsInfo::m_timestampS is not |
| 112 | // monotonic generally. Please see comment in declaration of class GpsInfo for details. |
| 113 | |
| 114 | // @TODO(bykoianko) Switching off extrapolation based on acceleration should be implemented. |
| 115 | // Switching off extrapolation based on speed, distance and time. |
| 116 | return distM / timeS <= kMaxExtrapolationSpeedMPS && distM <= kMaxExtrapolationDistMeters && |
| 117 | timeS <= kMaxExtrapolationTimeSeconds; |
| 118 | } |
| 119 | |
| 120 | // Extrapolator ------------------------------------------------------------------------------------ |
| 121 | Extrapolator::Extrapolator(ExtrapolatedLocationUpdateFn const & update) |