diff --git a/map/framework.cpp b/map/framework.cpp index 81294aa5aa..3c80975d63 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -239,22 +239,19 @@ void FrameWork::AddRedrawCommandSure() template void FrameWork::OnGpsUpdate(location::GpsInfo const & info) { - if (info.m_timestamp < location::POSITION_TIMEOUT_SECONDS) - { - // notify GUI that we received gps position - if (!(m_locationState & location::State::EGps) && m_locationObserver) - m_locationObserver(); + // notify GUI that we received gps position + if (!(m_locationState & location::State::EGps) && m_locationObserver) + m_locationObserver(); - m_locationState.UpdateGps(info); - if (m_centeringMode == ECenterAndScale) - { - CenterAndScaleViewport(); - m_centeringMode = ECenterOnly; - } - else if (m_centeringMode == ECenterOnly) - CenterViewport(m_locationState.Position()); - UpdateNow(); + m_locationState.UpdateGps(info); + if (m_centeringMode == ECenterAndScale) + { + CenterAndScaleViewport(); + m_centeringMode = ECenterOnly; } + else if (m_centeringMode == ECenterOnly) + CenterViewport(m_locationState.Position()); + UpdateNow(); } template diff --git a/platform/apple_location_service.mm b/platform/apple_location_service.mm index 64d89d7a61..4df406cef5 100644 --- a/platform/apple_location_service.mm +++ b/platform/apple_location_service.mm @@ -137,7 +137,8 @@ public: info.m_verticalAccuracy = location.verticalAccuracy; info.m_latitude = location.coordinate.latitude; info.m_longitude = location.coordinate.longitude; - info.m_timestamp = -[location.timestamp timeIntervalSinceNow]; + info.m_timestamp = [location.timestamp timeIntervalSince1970]; + info.m_source = location::EAppleNative; } - (void)locationManager:(CLLocationManager *)manager @@ -160,7 +161,7 @@ public: newInfo.m_x = newHeading.x; newInfo.m_y = newHeading.y; newInfo.m_z = newHeading.z; - newInfo.m_timestamp = -[newHeading.timestamp timeIntervalSinceNow]; + newInfo.m_timestamp = [location.timestamp timeIntervalSince1970]; m_service->OnHeadingUpdate(newInfo); } #endif @@ -173,6 +174,8 @@ public: { GpsInfo info; info.m_status = EDisabledByUser; + info.m_source = location::EAppleNative; + info.m_timestamp = [[NSDate date] timeIntervalSince1970]; m_service->OnLocationUpdate(info); } } diff --git a/platform/location.hpp b/platform/location.hpp index 839475eedf..3409bf6a7c 100644 --- a/platform/location.hpp +++ b/platform/location.hpp @@ -17,13 +17,20 @@ namespace location EAccurateMode, ERoughMode //!< in this mode compass is turned off }; + enum TLocationSource + { + EAppleNative, + EWindowsNative, + EGoogle + }; /// @note always check m_status before using this structure class GpsInfo { public: + TLocationSource m_source; TLocationStatus m_status; - double m_timestamp; //!< how many seconds ago the position was retrieved + double m_timestamp; //!< seconds from 1st Jan 1970 double m_latitude; //!< degrees double m_longitude; //!< degrees double m_horizontalAccuracy; //!< metres diff --git a/platform/location_manager.cpp b/platform/location_manager.cpp index 205314af8a..f85e47c1a3 100644 --- a/platform/location_manager.cpp +++ b/platform/location_manager.cpp @@ -4,12 +4,43 @@ #include "../std/vector.hpp" #include "../std/bind.hpp" +double ApproxDistanceSquareInMetres(double lat1, double lon1, double lat2, double lon2) +{ + double const m1 = (lat1 - lat2) / 111111.; + double const m2 = (lon1 - lon2) / 111111.; + return m1 * m1 + m2 * m2; +} + /// Chooses most accurate data from different position services class PositionFilter { + location::GpsInfo * m_prevLocation; public: - location::GpsInfo const & MostNewAndAccuratePosition() + PositionFilter() : m_prevLocation(NULL) {} + ~PositionFilter() { delete m_prevLocation; } + /// @return true if location should be sent to observers + bool Passes(location::GpsInfo const & newLocation) { + if (time(NULL) - newLocation.m_timestamp > location::POSITION_TIMEOUT_SECONDS) + return false; + + bool passes = true; + if (m_prevLocation) + { + if (newLocation.m_timestamp < m_prevLocation->m_timestamp) + passes = false; + else if (newLocation.m_source != m_prevLocation->m_source + && newLocation.m_horizontalAccuracy > m_prevLocation->m_horizontalAccuracy + && ApproxDistanceSquareInMetres(newLocation.m_latitude, + newLocation.m_longitude, + m_prevLocation->m_latitude, + m_prevLocation->m_longitude) + > newLocation.m_horizontalAccuracy * newLocation.m_horizontalAccuracy) + passes = false; + } + else + m_prevLocation = new location::GpsInfo(newLocation); + return true; } }; @@ -18,10 +49,12 @@ namespace location class LocationManager : public LocationService { vector m_services; + PositionFilter m_filter; void OnGpsUpdate(GpsInfo const & info) { - NotifyGpsObserver(info); + if (m_filter.Passes(info)) + NotifyGpsObserver(info); } void OnCompassUpdate(CompassInfo const & info) diff --git a/platform/wifi_info_mac.mm b/platform/wifi_info_mac.mm index 2b904c4d18..625fe0223d 100644 --- a/platform/wifi_info_mac.mm +++ b/platform/wifi_info_mac.mm @@ -69,11 +69,12 @@ static string AppendZeroIfNeeded(string const & macAddrPart) { utils::TokenizeIterator tokIt(rawBssid, ":"); apn.m_bssid = AppendZeroIfNeeded(*tokIt); - while (!(++tokIt).is_last()) + do { + ++tokIt; apn.m_bssid += "-"; apn.m_bssid += AppendZeroIfNeeded(*tokIt); - } + } while (!tokIt.is_last()); } m_accessPoints.push_back(apn); } diff --git a/platform/wifi_location_service.cpp b/platform/wifi_location_service.cpp index a3f9a3803c..1befdd6c72 100644 --- a/platform/wifi_location_service.cpp +++ b/platform/wifi_location_service.cpp @@ -37,7 +37,9 @@ namespace location info.m_longitude = json_real_value(lon); info.m_horizontalAccuracy = json_real_value(acc); // @TODO introduce flags to mark valid values - info.m_status = ERoughMode; + info.m_status = EAccurateMode; + info.m_timestamp = time(NULL); + info.m_source = location::EGoogle; NotifyGpsObserver(info); } }