From 1c20e772a03de88e947e3bf7328973dd2cbf3149 Mon Sep 17 00:00:00 2001 From: Alex Zolotarev Date: Sat, 23 Apr 2011 22:46:43 +0200 Subject: [PATCH] Refactored gps location system: - Moved all code to crossplatform framework - OS-dependent location services are implemented in platform - Added my position button to desktops --- iphone/Maps/Classes/MapViewController.h | 12 +- iphone/Maps/Classes/MapViewController.mm | 75 ++----- iphone/Maps/Classes/UserLocationController.h | 33 --- iphone/Maps/Classes/UserLocationController.mm | 93 -------- iphone/Maps/IPhoneLocator.h | 57 ----- iphone/Maps/IPhoneLocator.mm | 112 ---------- iphone/Maps/Maps.xcodeproj/project.pbxproj | 16 +- map/framework.hpp | 199 ++++++++---------- map/information_display.cpp | 158 ++++---------- map/information_display.hpp | 34 +-- map/location_state.cpp | 66 ++++++ map/location_state.hpp | 55 +++++ map/locator.cpp | 54 ----- map/locator.hpp | 64 ------ map/map.pro | 4 +- omim.pro | 1 + platform/apple_location_service.mm | 47 +++-- platform/location.cpp | 52 ----- platform/location.hpp | 50 +++-- platform/platform.pro | 17 +- platform/platform_tests/platform_tests.pro | 5 + qt/draw_widget.cpp | 10 + qt/draw_widget.hpp | 3 + qt/mainwindow.cpp | 26 +++ qt/mainwindow.hpp | 5 + qt/qt.pro | 2 + 26 files changed, 410 insertions(+), 840 deletions(-) delete mode 100644 iphone/Maps/Classes/UserLocationController.h delete mode 100644 iphone/Maps/Classes/UserLocationController.mm delete mode 100644 iphone/Maps/IPhoneLocator.h delete mode 100644 iphone/Maps/IPhoneLocator.mm create mode 100644 map/location_state.cpp create mode 100644 map/location_state.hpp delete mode 100644 map/locator.cpp delete mode 100644 map/locator.hpp delete mode 100644 platform/location.cpp diff --git a/iphone/Maps/Classes/MapViewController.h b/iphone/Maps/Classes/MapViewController.h index 71be446ef6..b296c882b9 100644 --- a/iphone/Maps/Classes/MapViewController.h +++ b/iphone/Maps/Classes/MapViewController.h @@ -1,5 +1,4 @@ #import -#import "UserLocationController.h" #include "../../geometry/point2d.hpp" #include "../../yg/texture.hpp" @@ -9,7 +8,6 @@ #include "../../map/navigator.hpp" #include "../../map/feature_vec_model.hpp" #include "../../std/shared_ptr.hpp" -#include "../../map/locator.hpp" @interface MapViewController : UIViewController { @@ -20,7 +18,6 @@ SCALING } m_CurrentAction; - bool m_isDirtyPosition; bool m_isSticking; size_t m_StickyThreshold; int m_iconSequenceNumber; @@ -37,14 +34,7 @@ - (void) ZoomToRect: (m2::RectD const &) rect; -- (void) UpdateIcon: (NSTimer *)theTimer; -- (void) OnUpdateLocation: (m2::PointD const &) mercatorPoint - withErrorRadius: (double) errorRadius - withLocTimeStamp: (double) locTimeStamp - withCurTimeStamp: (double) curTimeStamp; - -- (void) OnChangeLocatorMode: (Locator::EMode) oldMode - withNewMode: (Locator::EMode) newMode; +//- (void) UpdateIcon: (NSTimer *)theTimer; - (void) onResize: (GLint)width withHeight: (GLint)height; - (void) onPaint; diff --git a/iphone/Maps/Classes/MapViewController.mm b/iphone/Maps/Classes/MapViewController.mm index 00b8afd5d4..ad4434316e 100644 --- a/iphone/Maps/Classes/MapViewController.mm +++ b/iphone/Maps/Classes/MapViewController.mm @@ -4,7 +4,6 @@ #import "EAGLView.h" #import "WindowHandle.h" #import "../Settings/SettingsManager.h" -#import "IPhoneLocator.h" #include "RenderContext.hpp" #include "../../geometry/rect2d.hpp" @@ -23,7 +22,6 @@ typedef FrameWork framework_t; // @TODO Make m_framework and m_storage MapsAppDelegate properties instead of global variables. framework_t * m_framework = NULL; -shared_ptr m_locator; storage::Storage m_storage; - (void) ZoomToRect: (m2::RectD const &) rect @@ -53,52 +51,28 @@ storage::Storage m_storage; */ } +- (void)OnLocationUpdated +{ + m_myPositionButton.image = [UIImage imageNamed:@"location.png"]; +} + - (IBAction)OnMyPositionClicked:(id)sender { - if (m_locator->isRunning()) - { - m_locator->stop(); - m_framework->StopLocator(); - ((UIBarButtonItem*) sender).style = UIBarButtonItemStyleBordered; - } - else - { - m_framework->StartLocator(Locator::EPreciseMode); - m_locator->start(Locator::EPreciseMode); - m_isDirtyPosition = true; - - ((UIBarButtonItem*)sender).style = UIBarButtonItemStyleDone; - ((UIBarButtonItem*)sender).image = [UIImage imageNamed:@"location-search.png"]; - } -} - -- (void) OnChangeLocatorMode:(Locator::EMode) oldMode - withNewMode:(Locator::EMode) newMode -{ - if (newMode == Locator::ERoughMode) + if (((UIBarButtonItem *)sender).style == UIBarButtonItemStyleBordered) { - m_myPositionButton.image = [UIImage imageNamed:@"location.png"]; -// m_myPositionButton.style = UIBarButtonItemStyleBordered; + typedef void (*OnLocationUpdatedFunc)(id, SEL); + SEL onLocUpdatedSel = @selector(OnLocationUpdated); + OnLocationUpdatedFunc locUpdatedImpl = (OnLocationUpdatedFunc)[self methodForSelector:onLocUpdatedSel]; + + m_framework->StartLocationService(bind(locUpdatedImpl, self, onLocUpdatedSel)); + ((UIBarButtonItem *)sender).style = UIBarButtonItemStyleDone; + ((UIBarButtonItem *)sender).image = [UIImage imageNamed:@"location-search.png"]; } -} - -- (void) OnUpdateLocation: (m2::PointD const &) mercatorPoint - withErrorRadius: (double) errorRadius - withLocTimeStamp: (double) locTimeStamp - withCurTimeStamp: (double) curTimeStamp -{ - if (m_isDirtyPosition && (curTimeStamp - locTimeStamp <= 10) && (m_locator->mode() == Locator::EPreciseMode)) + else { -/* - if (m_iconTimer != nil) - { - [m_iconTimer invalidate]; - m_iconTimer = nil; - } - */ + m_framework->StopLocationService(); + ((UIBarButtonItem *)sender).style = UIBarButtonItemStyleBordered; m_myPositionButton.image = [UIImage imageNamed:@"location.png"]; - m_myPositionButton.style = UIBarButtonItemStyleDone; - m_isDirtyPosition = false; } } @@ -130,7 +104,6 @@ storage::Storage m_storage; - (void) dealloc { - m_locator.reset(); delete m_framework; [super dealloc]; } @@ -145,28 +118,12 @@ storage::Storage m_storage; shared_ptr windowHandle = [(EAGLView*)self.view windowHandle]; shared_ptr resourceManager = [(EAGLView*)self.view resourceManager]; - - m_locator = shared_ptr(new iphone::Locator()); - // tricky boost::bind for objC class methods - typedef void (*TUpdateLocationFunc)(id, SEL, m2::PointD const &, double, double, double); - SEL updateLocationSel = @selector(OnUpdateLocation:withErrorRadius:withLocTimeStamp:withCurTimeStamp:); - TUpdateLocationFunc updateLocationImpl = (TUpdateLocationFunc)[self methodForSelector:updateLocationSel]; - - typedef void (*TChangeModeFunc)(id, SEL, Locator::EMode, Locator::EMode); - SEL changeModeSel = @selector(OnChangeLocatorMode:withNewMode:); - TChangeModeFunc changeModeImpl = (TChangeModeFunc)[self methodForSelector:changeModeSel]; - - m_locator->addOnUpdateLocationFn(boost::bind(updateLocationImpl, self, updateLocationSel, _1, _2, _3, _4)); - m_locator->addOnChangeModeFn(boost::bind(changeModeImpl, self, changeModeSel, _1, _2)); - m_framework = new framework_t(windowHandle, 40); m_framework->InitStorage(m_storage); - m_framework->InitLocator(m_locator); m_StickyThreshold = 10; m_CurrentAction = NOTHING; - m_isDirtyPosition = false; // initialize with currently active screen orientation [self didRotateFromInterfaceOrientation: self.interfaceOrientation]; diff --git a/iphone/Maps/Classes/UserLocationController.h b/iphone/Maps/Classes/UserLocationController.h deleted file mode 100644 index 90e564ca56..0000000000 --- a/iphone/Maps/Classes/UserLocationController.h +++ /dev/null @@ -1,33 +0,0 @@ -#import -#import - -#include "../../../geometry/point2d.hpp" - -@protocol UserLocationControllerDelegate - -@required -- (void) OnLocation: (m2::PointD const &) mercatorPoint - withErrorRadius: (double) errorRadius - withTimestamp: (NSDate *) timestamp; -- (void) OnHeading: (CLHeading *)heading; -- (void) OnLocationError: (NSString *) errorDescription; -@end - -@interface UserLocationController : NSObject -{ -//@private -// CLLocationManager * m_locationManager; - -@public - id delegate; -// BOOL active; -} - -@property (nonatomic, assign) id delegate; -@property (nonatomic, assign) CLLocationManager * locationManager; -/// YES means that location manager is active -//@property (nonatomic, assign) BOOL active; - -- (id) initWithDelegate: (id) locationDelegate; - -@end diff --git a/iphone/Maps/Classes/UserLocationController.mm b/iphone/Maps/Classes/UserLocationController.mm deleted file mode 100644 index ebf9305f02..0000000000 --- a/iphone/Maps/Classes/UserLocationController.mm +++ /dev/null @@ -1,93 +0,0 @@ -#import "UserLocationController.h" - -#include "../../../indexer/mercator.hpp" - -@implementation UserLocationController - -@synthesize delegate; -//@synthesize active; -@synthesize locationManager; - -- (id) init -{ - self = [super init]; - if (self != nil) - { - self.locationManager = [[CLLocationManager alloc] init]; - self.locationManager.delegate = self; -// active = NO; - } - return self; -} - -- (id) initWithDelegate: (id) locationDelegate -{ - delegate = locationDelegate; - return [self init]; -} - -- (void) dealloc -{ -// [self Stop]; - [self.locationManager release]; - [super dealloc]; -} - -/*- (void) Start -{ -// active = YES; - [self.locationManager startUpdatingLocation]; - self.locationManager.distanceFilter = kCLDistanceFilterNone; - if ([CLLocationManager headingAvailable]) - { - self.locationManager.headingFilter = 1; - [self.locationManager startUpdatingHeading]; - } - else - NSLog(@"heading information is not available"); -} - -- (void) Stop -{ - [self.locationManager stopUpdatingLocation]; - [self.locationManager stopUpdatingHeading]; -// active = NO; -}*/ - -- (void) locationManager: (CLLocationManager *) manager - didUpdateHeading: (CLHeading *) newHeading -{ - [self.delegate OnHeading: newHeading]; -} - -- (void) locationManager: (CLLocationManager *) manager - didUpdateToLocation: (CLLocation *) newLocation - fromLocation: (CLLocation *) oldLocation -{ -// NSLog(@"NewLocation: %@", [newLocation description]); - m2::PointD mercPoint(MercatorBounds::LonToX(newLocation.coordinate.longitude), - MercatorBounds::LatToY(newLocation.coordinate.latitude)); - - m2::RectD errorRectXY = MercatorBounds::MetresToXY(newLocation.coordinate.longitude, - newLocation.coordinate.latitude, - newLocation.horizontalAccuracy); - - double errorRadiusXY = sqrt((errorRectXY.SizeX() * errorRectXY.SizeX() - + errorRectXY.SizeY() * errorRectXY.SizeY()) / 4); - - [self.delegate OnLocation: mercPoint withErrorRadius: errorRadiusXY withTimestamp: newLocation.timestamp]; -} - -- (void) locationManager: (CLLocationManager *) manager - didFailWithError: (NSError *) error -{ - [self.delegate OnLocationError: [error localizedDescription]]; - if ([error code] == kCLErrorDenied) - { - // @TODO display some warning to the user about disabled location services, - // probably allow him to enable them by going to the settings - - } -} - -@end diff --git a/iphone/Maps/IPhoneLocator.h b/iphone/Maps/IPhoneLocator.h deleted file mode 100644 index 4db831532e..0000000000 --- a/iphone/Maps/IPhoneLocator.h +++ /dev/null @@ -1,57 +0,0 @@ -// -// IPhoneLocator.h -// Maps -// -// Created by Siarhei Rachytski on 3/28/11. -// Copyright 2011 MapsWithMe. All rights reserved. -// - -#include "../../map/locator.hpp" -#include "UserLocationController.h" - -namespace iphone -{ - class Locator; -} - -@interface LocatorThunk : NSObject -{ - iphone::Locator * m_locator; -} - -@property (nonatomic, assign) iphone::Locator * locator; - -- (void) initWithLocator : (iphone::Locator*) locator; - -- (void) OnLocation: (m2::PointD const &) mercatorPoint - withErrorRadius: (double) errorRadius - withTimestamp: (NSDate *) timestamp; -- (void) OnHeading: (CLHeading *)heading; -- (void) OnLocationError: (NSString *) errorDescription; - -@end - -namespace iphone -{ - class Locator : public ::Locator - { - private: - - LocatorThunk * m_thunk; - UserLocationController * m_locationController; - - public: - - Locator(); - ~Locator(); - - void start(EMode mode); - void stop(); - void setMode(EMode mode); - - void locationUpdate(m2::PointD const & pt, double errorRadius, double locTimeStamp, double curTimeStamp); - void headingUpdate(double trueHeading, double magneticHeading, double accuracy); - }; -} - - diff --git a/iphone/Maps/IPhoneLocator.mm b/iphone/Maps/IPhoneLocator.mm deleted file mode 100644 index 3af9b74b1e..0000000000 --- a/iphone/Maps/IPhoneLocator.mm +++ /dev/null @@ -1,112 +0,0 @@ -// -// IPhoneLocator.mm -// Maps -// -// Created by Siarhei Rachytski on 3/28/11. -// Copyright 2011 MapsWithMe. All rights reserved. -// - -#include "IPhoneLocator.h" -#import - -@implementation LocatorThunk - -@synthesize locator; - -- (void) initWithLocator : (iphone::Locator *) loc -{ - self.locator = loc; -} - -- (void) OnLocation: (m2::PointD const &) mercatorPoint - withErrorRadius: (double) errorRadius - withTimestamp: (NSDate *) timestamp; -{ - self.locator->locationUpdate(mercatorPoint, - errorRadius, - [timestamp timeIntervalSince1970], - [[NSDate date] timeIntervalSince1970]); -} - -- (void) OnHeading: (CLHeading*) heading -{ - self.locator->headingUpdate(heading.trueHeading, - heading.magneticHeading, - heading.headingAccuracy); -} - -- (void) OnLocationError: (NSString*) error -{ - NSLog(@"Error : %@", error); -} - -@end - -namespace iphone -{ - Locator::Locator() - { - m_thunk = [LocatorThunk alloc]; - [m_thunk initWithLocator:this]; - m_locationController = [[UserLocationController alloc] initWithDelegate:m_thunk]; - } - - Locator::~Locator() - { - stop(); - [m_locationController release]; - [m_thunk release]; - } - - void Locator::start(EMode mode) - { - ::Locator::setMode(mode); - - [m_locationController.locationManager startUpdatingLocation]; - - if (mode == ERoughMode) - m_locationController.locationManager.distanceFilter = 100; - else - m_locationController.locationManager.distanceFilter = kCLDistanceFilterNone; - - if ([CLLocationManager headingAvailable]) - { - m_locationController.locationManager.headingFilter = 1; - [m_locationController.locationManager startUpdatingHeading]; - } - - ::Locator::start(mode); - } - - void Locator::stop() - { - ::Locator::stop(); - [m_locationController.locationManager stopUpdatingLocation]; - - if ([CLLocationManager headingAvailable]) - [m_locationController.locationManager stopUpdatingHeading]; - } - - void Locator::setMode(EMode mode) - { - EMode oldMode = ::Locator::mode(); - ::Locator::setMode(mode); - callOnChangeModeFns(oldMode, mode); - - if (mode == ERoughMode) - m_locationController.locationManager.distanceFilter = 100; - else - m_locationController.locationManager.distanceFilter = kCLDistanceFilterNone; - } - - void Locator::locationUpdate(m2::PointD const & pt, double errorRadius, double locTimeStamp, double curTimeStamp) - { - callOnUpdateLocationFns(pt, errorRadius, locTimeStamp, curTimeStamp); - } - - void Locator::headingUpdate(double trueHeading, double magneticHeading, double accuracy) - { - callOnUpdateHeadingFns(trueHeading, magneticHeading, accuracy); - } -} - diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj index 25bd35a543..9e066c677a 100644 --- a/iphone/Maps/Maps.xcodeproj/project.pbxproj +++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj @@ -45,7 +45,6 @@ EE7F29811219ECA300EB67A9 /* RenderBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = EE7F297D1219ECA300EB67A9 /* RenderBuffer.mm */; }; EE7F29821219ECA300EB67A9 /* RenderContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = EE7F297E1219ECA300EB67A9 /* RenderContext.mm */; }; EE7F29831219ECA300EB67A9 /* WindowHandle.mm in Sources */ = {isa = PBXBuildFile; fileRef = EE7F29801219ECA300EB67A9 /* WindowHandle.mm */; }; - EE9588BC134114F50056F2D5 /* IPhoneLocator.mm in Sources */ = {isa = PBXBuildFile; fileRef = EE9588BB134114F50056F2D5 /* IPhoneLocator.mm */; }; EEA61601134C496A003A9827 /* 01_dejavusans.ttf in Resources */ = {isa = PBXBuildFile; fileRef = EEA615E5134C4968003A9827 /* 01_dejavusans.ttf */; }; EEA61602134C496A003A9827 /* 02_wqy-microhei.ttf in Resources */ = {isa = PBXBuildFile; fileRef = EEA615E6134C4968003A9827 /* 02_wqy-microhei.ttf */; }; EEA61603134C496A003A9827 /* 03_jomolhari-id-a3d.ttf in Resources */ = {isa = PBXBuildFile; fileRef = EEA615E7134C4968003A9827 /* 03_jomolhari-id-a3d.ttf */; }; @@ -54,7 +53,6 @@ EEAF65E5134BCBD500A81C82 /* location-search.png in Resources */ = {isa = PBXBuildFile; fileRef = EEAF65E3134BCBD500A81C82 /* location-search.png */; }; EEAF65E6134BCBD500A81C82 /* location-search@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EEAF65E4134BCBD500A81C82 /* location-search@2x.png */; }; EEB7E22211E9079400080A68 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EEB7E22111E9079400080A68 /* CoreLocation.framework */; }; - EEB7E30911E9094F00080A68 /* UserLocationController.mm in Sources */ = {isa = PBXBuildFile; fileRef = EEB7E30811E9094F00080A68 /* UserLocationController.mm */; }; EED10A4511F78D120095FAD4 /* MapViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = EED10A4411F78D120095FAD4 /* MapViewController.mm */; }; EEE4C93E1298A2F3007231A9 /* symbols_24.png in Resources */ = {isa = PBXBuildFile; fileRef = EEE4C93D1298A2F3007231A9 /* symbols_24.png */; }; EEE4C9401298A303007231A9 /* symbols_48.png in Resources */ = {isa = PBXBuildFile; fileRef = EEE4C93F1298A303007231A9 /* symbols_48.png */; }; @@ -69,6 +67,7 @@ FA0660001286167A00FEA989 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = FA065FFE1286167A00FEA989 /* Default.png */; }; FA0660031286168700FEA989 /* Default-Portrait.png in Resources */ = {isa = PBXBuildFile; fileRef = FA0660011286168700FEA989 /* Default-Portrait.png */; }; FA0660041286168700FEA989 /* Default-Landscape.png in Resources */ = {isa = PBXBuildFile; fileRef = FA0660021286168700FEA989 /* Default-Landscape.png */; }; + FA2EF9C713630C3B00E3E484 /* libplatform.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FA2EF9C613630C3B00E3E484 /* libplatform.a */; }; FA34BECA1338D72F00FFB2A7 /* CustomAlertView.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA34BEC81338D72F00FFB2A7 /* CustomAlertView.mm */; }; FA4135EA120A263C0062D5B4 /* CountriesViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA4135E2120A263C0062D5B4 /* CountriesViewController.mm */; }; FA4135ED120A263C0062D5B4 /* SettingsManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA4135E7120A263C0062D5B4 /* SettingsManager.mm */; }; @@ -145,7 +144,6 @@ EE7F297E1219ECA300EB67A9 /* RenderContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = RenderContext.mm; path = Classes/RenderContext.mm; sourceTree = SOURCE_ROOT; }; EE7F297F1219ECA300EB67A9 /* WindowHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = WindowHandle.h; path = Classes/WindowHandle.h; sourceTree = SOURCE_ROOT; }; EE7F29801219ECA300EB67A9 /* WindowHandle.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = WindowHandle.mm; path = Classes/WindowHandle.mm; sourceTree = SOURCE_ROOT; }; - EE9588BB134114F50056F2D5 /* IPhoneLocator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = IPhoneLocator.mm; sourceTree = ""; }; EEA615E5134C4968003A9827 /* 01_dejavusans.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = 01_dejavusans.ttf; path = ../../data/01_dejavusans.ttf; sourceTree = SOURCE_ROOT; }; EEA615E6134C4968003A9827 /* 02_wqy-microhei.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "02_wqy-microhei.ttf"; path = "../../data/02_wqy-microhei.ttf"; sourceTree = SOURCE_ROOT; }; EEA615E7134C4968003A9827 /* 03_jomolhari-id-a3d.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "03_jomolhari-id-a3d.ttf"; path = "../../data/03_jomolhari-id-a3d.ttf"; sourceTree = SOURCE_ROOT; }; @@ -154,13 +152,10 @@ EEAF65E3134BCBD500A81C82 /* location-search.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "location-search.png"; sourceTree = ""; }; EEAF65E4134BCBD500A81C82 /* location-search@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "location-search@2x.png"; sourceTree = ""; }; EEB7E22111E9079400080A68 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; - EEB7E30711E9094F00080A68 /* UserLocationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = UserLocationController.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; - EEB7E30811E9094F00080A68 /* UserLocationController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = UserLocationController.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; EED10A4411F78D120095FAD4 /* MapViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = MapViewController.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; EEE4C93D1298A2F3007231A9 /* symbols_24.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = symbols_24.png; path = ../../data/symbols_24.png; sourceTree = SOURCE_ROOT; }; EEE4C93F1298A303007231A9 /* symbols_48.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = symbols_48.png; path = ../../data/symbols_48.png; sourceTree = SOURCE_ROOT; }; EEE4C9411298A31B007231A9 /* basic_highres.skn */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = basic_highres.skn; path = ../../data/basic_highres.skn; sourceTree = SOURCE_ROOT; }; - EEE8F9C2134106AB001DC91A /* IPhoneLocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IPhoneLocator.h; sourceTree = ""; }; EEF5745412DE1AD50082F472 /* libfribidi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libfribidi.a; sourceTree = SOURCE_ROOT; }; EEFE7C1212F8C9E1006AF8C3 /* fonts_blacklist.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fonts_blacklist.txt; path = ../../data/fonts_blacklist.txt; sourceTree = ""; }; EEFE7C1312F8C9E1006AF8C3 /* fonts_whitelist.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fonts_whitelist.txt; path = ../../data/fonts_whitelist.txt; sourceTree = ""; }; @@ -170,6 +165,7 @@ FA065FFE1286167A00FEA989 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = SOURCE_ROOT; }; FA0660011286168700FEA989 /* Default-Portrait.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait.png"; sourceTree = SOURCE_ROOT; }; FA0660021286168700FEA989 /* Default-Landscape.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape.png"; sourceTree = SOURCE_ROOT; }; + FA2EF9C613630C3B00E3E484 /* libplatform.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libplatform.a; path = libplatform.a; sourceTree = SOURCE_ROOT; }; FA34BEC81338D72F00FFB2A7 /* CustomAlertView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CustomAlertView.mm; sourceTree = ""; }; FA34BEC91338D72F00FFB2A7 /* CustomAlertView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomAlertView.h; sourceTree = ""; }; FA4135E1120A263C0062D5B4 /* CountriesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = CountriesViewController.h; path = Settings/CountriesViewController.h; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; @@ -224,6 +220,7 @@ FA8F8938132D5DB00048E3FE /* libtomcrypt.a in Frameworks */, 49DE1CA413437D7A00A93417 /* libbzip2.a in Frameworks */, 49DE1CA513437D7A00A93417 /* libwords.a in Frameworks */, + FA2EF9C713630C3B00E3E484 /* libplatform.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -245,8 +242,6 @@ 1D3623250D0F684500981E51 /* MapsAppDelegate.mm */, 46F8A2EB10EB63040045521A /* MapViewController.h */, EED10A4411F78D120095FAD4 /* MapViewController.mm */, - EEB7E30711E9094F00080A68 /* UserLocationController.h */, - EEB7E30811E9094F00080A68 /* UserLocationController.mm */, 49DD2B4E132FA8880031D82E /* GuideViewController.h */, 49DD2B4F132FA8880031D82E /* GuideViewController.mm */, ); @@ -400,6 +395,7 @@ FA1DE68411E15D4E00C6D69A /* Static Libraries */ = { isa = PBXGroup; children = ( + FA2EF9C613630C3B00E3E484 /* libplatform.a */, 49DE1CA213437D7A00A93417 /* libbzip2.a */, 49DE1CA313437D7A00A93417 /* libwords.a */, FA8F8937132D5DB00048E3FE /* libtomcrypt.a */, @@ -449,8 +445,6 @@ FAF37EFA126DCE6F005EA154 /* IPhoneDownload.mm */, FAF37EFE126DCE6F005EA154 /* IPhonePlatform.hpp */, FAF37EFD126DCE6F005EA154 /* IPhonePlatform.mm */, - EEE8F9C2134106AB001DC91A /* IPhoneLocator.h */, - EE9588BB134114F50056F2D5 /* IPhoneLocator.mm */, ); name = Platform; sourceTree = ""; @@ -561,7 +555,6 @@ 1D60589B0D05DD56006BFB54 /* main.mm in Sources */, 1D3623260D0F684500981E51 /* MapsAppDelegate.mm in Sources */, 46F26CD810F623BA00ECCA39 /* EAGLView.mm in Sources */, - EEB7E30911E9094F00080A68 /* UserLocationController.mm in Sources */, EED10A4511F78D120095FAD4 /* MapViewController.mm in Sources */, FA4135EA120A263C0062D5B4 /* CountriesViewController.mm in Sources */, FA4135ED120A263C0062D5B4 /* SettingsManager.mm in Sources */, @@ -574,7 +567,6 @@ 49DD2B51132FA8880031D82E /* GuideViewController.mm in Sources */, FAFCB63613366E78001A5C59 /* WebViewController.mm in Sources */, FA34BECA1338D72F00FFB2A7 /* CustomAlertView.mm in Sources */, - EE9588BC134114F50056F2D5 /* IPhoneLocator.mm in Sources */, 4938BB3B1343716500E0815A /* ArticleVC.mm in Sources */, 4938BB3C1343716500E0815A /* PerfCount.mm in Sources */, 4938BB3D1343716500E0815A /* SearchVC.mm in Sources */, diff --git a/map/framework.hpp b/map/framework.hpp index 842d126ca5..e9d2641cce 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -4,8 +4,8 @@ #include "drawer_yg.hpp" #include "render_queue.hpp" #include "information_display.hpp" -#include "locator.hpp" #include "window_handle.hpp" +#include "location_state.hpp" #include "../defines.hpp" @@ -16,6 +16,7 @@ #include "../indexer/feature.hpp" #include "../platform/platform.hpp" +#include "../platform/location.hpp" #include "../yg/defines.hpp" #include "../yg/screen.hpp" @@ -40,8 +41,6 @@ #include "../std/target_os.hpp" #include "../std/fstream.hpp" -#include "../base/start_mem_debug.hpp" - //#define DRAW_TOUCH_POINTS namespace di { class DrawInfo; } @@ -86,6 +85,8 @@ namespace fwork } +typedef boost::function LocationRetrievedCallbackT; + template < class TModel, @@ -101,7 +102,6 @@ class FrameWork model_t m_model; navigator_t m_navigator; shared_ptr m_windowHandle; - shared_ptr m_locator; bool m_isBenchmarking; bool m_isBenchmarkInitialized; @@ -118,7 +118,17 @@ class FrameWork bool m_isRedrawEnabled; double m_metresMinWidth; int m_minRulerWidth; - bool m_doCenterViewport; + + + enum TGpsCenteringMode + { + EDoNothing, + ECenterAndScale, + ECenterOnly + }; + TGpsCenteringMode m_centeringMode; + LocationRetrievedCallbackT m_locationObserver; + location::State m_locationState; void AddRedrawCommandSure() { @@ -155,6 +165,35 @@ class FrameWork m_model.RemoveMap(datFile); } + void 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(); + + m_locationState.UpdateGps(info); + if (m_centeringMode == ECenterAndScale) + { + CenterAndScaleViewport(); + m_centeringMode = ECenterOnly; + } + else if (m_centeringMode == ECenterOnly) + CenterViewport(m_locationState.Position()); + UpdateNow(); + } + } + + void OnCompassUpdate(location::CompassInfo const & info) + { + if (info.m_timestamp < location::POSITION_TIMEOUT_SECONDS) + { + m_locationState.UpdateCompass(info); + UpdateNow(); + } + } + public: FrameWork(shared_ptr windowHandle, size_t bottomShift) @@ -163,10 +202,6 @@ public: m_isBenchmarkInitialized(false), m_currentBenchmark(0), m_bgColor(0xEE, 0xEE, 0xDD, 0xFF), -// m_bgColor(0xF4 / 17 * 17, 0xFC / 17 * 17, 0xE8 / 17 * 17, 0xFF), -// m_bgColor(0xF2 / 17 * 17, 0xF2 / 17 * 17, 0xEE / 17 * 17, 0xFF), -// m_bgColor(0xF1 / 17 * 17, 0xF2 / 17 * 17, 0xEB / 17 * 17, 0xFF), -// m_bgColor(187, 187, 187, 255), m_renderQueue(GetPlatform().SkinName(), GetPlatform().IsMultiSampled(), GetPlatform().DoPeriodicalUpdate(), @@ -177,7 +212,7 @@ public: m_isRedrawEnabled(true), m_metresMinWidth(20), m_minRulerWidth(97), - m_doCenterViewport(false) + m_centeringMode(EDoNothing) { m_informationDisplay.setBottomShift(bottomShift); #ifdef DRAW_TOUCH_POINTS @@ -204,6 +239,12 @@ public: m_informationDisplay.setVisualScale(GetPlatform().VisualScale()); m_renderQueue.AddWindowHandle(m_windowHandle); + + // initialize gps and compass subsystem + GetLocationService().SetGpsObserver( + boost::bind(&this_type::OnGpsUpdate, this, _1)); + GetLocationService().SetCompassObserver( + boost::bind(&this_type::OnCompassUpdate, this, _1)); } void InitBenchmark() @@ -246,30 +287,24 @@ public: LOG(LINFO, ("Storage initialized")); } - void InitLocator(shared_ptr const & locator) + void StartLocationService(LocationRetrievedCallbackT observer) { - m_locator = locator; - m_locator->addOnUpdateLocationFn(bind(&this_type::UpdateLocation, this, _1, _2, _3, _4)); - m_locator->addOnUpdateHeadingFn(bind(&this_type::UpdateHeading, this, _1, _2, _3)); - m_locator->addOnChangeModeFn(bind(&this_type::ChangeLocatorMode, this, _1, _2)); -// m_locator->start(Locator::ERoughMode); + m_locationObserver = observer; + m_centeringMode = ECenterAndScale; + // by default, we always start in accurate mode + GetLocationService().StartUpdate(true); } - void StartLocator(Locator::EMode mode) + void StopLocationService() { - if (mode == Locator::EPreciseMode) - m_doCenterViewport = true; - } - - void StopLocator() - { - m_informationDisplay.enablePosition(false); - m_informationDisplay.enableHeading(false); - m_doCenterViewport = false; + // reset callback + m_locationObserver.clear(); + m_centeringMode = EDoNothing; + GetLocationService().StopUpdate(); + m_locationState.TurnOff(); Invalidate(); } - bool IsEmptyModel() { return m_model.GetWorldRect() == m2::RectD::GetEmptyRect(); @@ -352,16 +387,10 @@ public: void SetOrientation(EOrientation orientation) { m_navigator.SetOrientation(orientation); - m_informationDisplay.setOrientation(orientation); + m_locationState.SetOrientation(orientation); UpdateNow(); } - /// By VNG: I think, you don't need such selectors! - //ScreenBase const & Screen() const - //{ - // return m_navigator.Screen(); - //} - int GetCurrentScale() const { m2::PointD textureCenter(m_renderQueue.renderState().m_textureWidth / 2, @@ -487,6 +516,8 @@ public: m_informationDisplay.doDraw(pDrawer); + InformationDisplay::DrawMyPosition(*pDrawer, m_navigator.Screen(), m_locationState); + e->drawer()->screen()->endFrame(); OGLCHECK(glPopMatrix()); @@ -494,44 +525,6 @@ public: } } -/* void DisableMyPositionAndHeading() - { - m_informationDisplay.enablePosition(false); - m_informationDisplay.enableHeading(false); - - UpdateNow(); - }*/ - - void UpdateLocation(m2::PointD const & mercatorPos, double errorRadius, double locTimeStamp, double curTimeStamp) - { - m_informationDisplay.setPosition(mercatorPos, errorRadius); - if ((m_locator->mode() == Locator::EPreciseMode) - && (curTimeStamp - locTimeStamp >= 0) - && (curTimeStamp - locTimeStamp < 60 * 5)) - { - if (m_doCenterViewport) - { - m_informationDisplay.setLocatorMode(Locator::EPreciseMode); - CenterAndScaleViewport(); - m_doCenterViewport = false; - } - else - CenterViewport(mercatorPos); - } - UpdateNow(); - } - - void ChangeLocatorMode(Locator::EMode oldMode, Locator::EMode newMode) - { - if (newMode != Locator::EPreciseMode) - m_informationDisplay.setLocatorMode(newMode); - - /// in precise mode we'll update informationDisplay.locatorMode on the - /// first "fresh" position recieved. - m_doCenterViewport = true; - Invalidate(); - } - void CenterViewport(m2::PointD const & pt) { m_navigator.CenterViewport(pt); @@ -561,46 +554,41 @@ public: { } + /// @TODO refactor to accept point and min visible length void CenterAndScaleViewport() { - m2::PointD pt = m_informationDisplay.position(); + m2::PointD const pt = m_locationState.Position(); m_navigator.CenterViewport(pt); - m2::RectD ClipRect = m_navigator.Screen().ClipRect(); + m2::RectD clipRect = m_navigator.Screen().ClipRect(); - double errorRadius = m_informationDisplay.errorRadius(); - - double xMinSize = 6 * max(errorRadius, MercatorBounds::ConvertMetresToX(pt.x, m_metresMinWidth)); - double yMinSize = 6 * max(errorRadius, MercatorBounds::ConvertMetresToY(pt.y, m_metresMinWidth)); + double const xMinSize = 6 * max(m_locationState.ErrorRadius(), + MercatorBounds::ConvertMetresToX(pt.x, m_metresMinWidth)); + double const yMinSize = 6 * max(m_locationState.ErrorRadius(), + MercatorBounds::ConvertMetresToY(pt.y, m_metresMinWidth)); bool needToScale = false; - if (ClipRect.SizeX() < ClipRect.SizeY()) - needToScale = ClipRect.SizeX() > xMinSize * 3; + if (clipRect.SizeX() < clipRect.SizeY()) + needToScale = clipRect.SizeX() > xMinSize * 3; else - needToScale = ClipRect.SizeY() > yMinSize * 3; + needToScale = clipRect.SizeY() > yMinSize * 3; /* if ((ClipRect.SizeX() < 3 * errorRadius) || (ClipRect.SizeY() < 3 * errorRadius)) needToScale = true;*/ if (needToScale) { - double k = max(xMinSize / ClipRect.SizeX(), - yMinSize / ClipRect.SizeY()); + double const k = max(xMinSize / clipRect.SizeX(), + yMinSize / clipRect.SizeY()); - ClipRect.Scale(k); - m_navigator.SetFromRect(ClipRect); + clipRect.Scale(k); + m_navigator.SetFromRect(clipRect); } UpdateNow(); } - void UpdateHeading(double trueHeading, double magneticHeading, double accuracy) - { - m_informationDisplay.setHeading(trueHeading, magneticHeading, accuracy); - Invalidate(); - } - /// Show all model by it's world rect. void ShowAll() { @@ -642,14 +630,12 @@ public: } void DoDrag(DragEvent const & e) { - if (m_locator && (m_locator->mode() == Locator::EPreciseMode) && (!m_doCenterViewport)) - m_locator->setMode(Locator::ERoughMode); + m_centeringMode = EDoNothing; m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(true); m2::PointD pos = m_navigator.OrientPoint(e.Pos()) + ptShift; - m_navigator.DoDrag(pos, - GetPlatform().TimeInSec()); + m_navigator.DoDrag(pos, GetPlatform().TimeInSec()); #ifdef DRAW_TOUCH_POINTS m_informationDisplay.setDebugPoint(0, pos); @@ -657,6 +643,7 @@ public: Invalidate(); } + void StopDrag(DragEvent const & e) { m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(true); @@ -685,16 +672,11 @@ public: //@{ void ScaleToPoint(ScaleToPointEvent const & e) { - m2::PointD ptShift = m_renderQueue.renderState().coordSystemShift(true); + m2::PointD const pt = (m_centeringMode == EDoNothing) + ? m_navigator.OrientPoint(e.Pt()) + m_renderQueue.renderState().coordSystemShift(true) + : m_navigator.Screen().PixelRect().Center(); - m2::PointD pt = m_navigator.OrientPoint(e.Pt()) + ptShift; - - if ((m_locator) && (m_locator->mode() == Locator::EPreciseMode)) - pt = m_navigator.Screen().PixelRect().Center(); - - m_navigator.ScaleToPoint(pt, - e.ScaleFactor(), - GetPlatform().TimeInSec()); + m_navigator.ScaleToPoint(pt, e.ScaleFactor(), GetPlatform().TimeInSec()); UpdateNow(); } @@ -717,7 +699,7 @@ public: m2::PointD pt1 = m_navigator.OrientPoint(e.Pt1()) + ptShift; m2::PointD pt2 = m_navigator.OrientPoint(e.Pt2()) + ptShift; - if ((m_locator) && (m_locator->mode() == Locator::EPreciseMode) && (!m_doCenterViewport)) + if ((m_locationState & location::State::EGps) && (m_centeringMode == ECenterOnly)) { m2::PointD ptC = (pt1 + pt2) / 2; m2::PointD ptDiff = m_navigator.Screen().PixelRect().Center() - ptC; @@ -742,7 +724,7 @@ public: m2::PointD pt1 = m_navigator.OrientPoint(e.Pt1()) + ptShift; m2::PointD pt2 = m_navigator.OrientPoint(e.Pt2()) + ptShift; - if ((m_locator) && (m_locator->mode() == Locator::EPreciseMode) && (!m_doCenterViewport)) + if ((m_locationState & location::State::EGps) && (m_centeringMode == ECenterOnly)) { m2::PointD ptC = (pt1 + pt2) / 2; m2::PointD ptDiff = m_navigator.Screen().PixelRect().Center() - ptC; @@ -767,8 +749,7 @@ public: m2::PointD pt1 = m_navigator.OrientPoint(e.Pt1()) + ptShift; m2::PointD pt2 = m_navigator.OrientPoint(e.Pt2()) + ptShift; - - if ((m_locator) && (m_locator->mode() == Locator::EPreciseMode) && (!m_doCenterViewport)) + if ((m_locationState & location::State::EGps) && (m_centeringMode == ECenterOnly)) { m2::PointD ptC = (pt1 + pt2) / 2; m2::PointD ptDiff = m_navigator.Screen().PixelRect().Center() - ptC; @@ -787,5 +768,3 @@ public: } //@} }; - -#include "../base/stop_mem_debug.hpp" diff --git a/map/information_display.cpp b/map/information_display.cpp index 1fe6e9a096..fb48ee2a74 100644 --- a/map/information_display.cpp +++ b/map/information_display.cpp @@ -2,6 +2,7 @@ #include "information_display.hpp" #include "drawer_yg.hpp" +#include "location_state.hpp" #include "../indexer/mercator.hpp" #include "../yg/defines.hpp" @@ -15,12 +16,12 @@ #include "../base/logging.hpp" #include "../base/mutex.hpp" +#include + +using namespace location; + InformationDisplay::InformationDisplay() - : m_headingOrientation(-math::pi / 2), - m_mode(Locator::ERoughMode) { - enablePosition(false); - enableHeading(false); enableDebugPoints(false); enableRuler(false); enableCenter(false); @@ -44,122 +45,49 @@ void InformationDisplay::setBottomShift(double bottomShift) m_bottomShift = bottomShift; } -void InformationDisplay::setOrientation(EOrientation orientation) -{ - switch (orientation) - { - case EOrientation0: - m_headingOrientation = -math::pi / 2; - break; - case EOrientation90: - m_headingOrientation = math::pi; - break; - case EOrientation180: - m_headingOrientation = math::pi / 2; - break; - case EOrientation270: - m_headingOrientation = 0; - break; - } -} - void InformationDisplay::setDisplayRect(m2::RectI const & rect) { m_displayRect = rect; } -void InformationDisplay::enablePosition(bool doEnable) +void InformationDisplay::DrawMyPosition(DrawerYG & drawer, + ScreenBase const & screen, + location::State const & state) { - m_isPositionEnabled = doEnable; -} + double pxErrorRadius; + m2::PointD pxPosition; + if ((state & State::EGps) || (state & State::ECompass)) + { + pxPosition = screen.GtoP(state.Position()); + pxErrorRadius = pxPosition.Length(screen.GtoP(state.Position() + + m2::PointD(state.ErrorRadius(), 0))); + } -void InformationDisplay::setPosition(m2::PointD const & mercatorPos, double errorRadius) -{ - enablePosition(true); - m_position = mercatorPos; - m_errorRadius = errorRadius; -} - -m2::PointD const & InformationDisplay::position() const -{ - return m_position; -} - -double InformationDisplay::errorRadius() const -{ - return m_errorRadius; -} - -void InformationDisplay::drawPosition(DrawerYG * pDrawer) -{ - /// Drawing position and heading - m2::PointD pxPosition = m_screen.GtoP(m_position); - pDrawer->drawSymbol(pxPosition, "current-position", yg::EPosCenter, yg::maxDepth); - - double pxErrorRadius = pxPosition.Length(m_screen.GtoP(m_position + m2::PointD(m_errorRadius, 0))); - - // pDrawer->screen()->drawArc(pxPosition, 0, math::pi * 2, pxErrorRadius, yg::Color(0, 0, 255, m_mode == Locator::EPreciseMode ? 64 : 32), yg::maxDepth - 2); - pDrawer->screen()->fillSector(pxPosition, 0, math::pi * 2, pxErrorRadius, yg::Color(0, 0, 255, m_mode == Locator::EPreciseMode ? 64 : 32), yg::maxDepth - 3); -} - -void InformationDisplay::setLocatorMode(Locator::EMode mode) -{ - m_mode = mode; -} - -void InformationDisplay::enableHeading(bool doEnable) -{ - m_isHeadingEnabled = doEnable; -} - -void InformationDisplay::setHeading(double trueHeading, double magneticHeading, double accuracy) -{ - enableHeading(true); - m_trueHeading = trueHeading; - m_magneticHeading = magneticHeading; - m_headingAccuracy = accuracy; -} - -void InformationDisplay::drawHeading(DrawerYG *pDrawer) -{ - if (m_mode == Locator::ERoughMode) - return; - - double trueHeadingRad = m_trueHeading / 180 * math::pi; - double headingAccuracyRad = m_headingAccuracy / 180 * math::pi; - - m2::PointD pxPosition = m_screen.GtoP(m_position); - - double pxErrorRadius = pxPosition.Length(m_screen.GtoP(m_position + m2::PointD(m_errorRadius, 0))); - - /// true heading - pDrawer->screen()->drawSector(pxPosition, - trueHeadingRad + m_headingOrientation - headingAccuracyRad, - trueHeadingRad + m_headingOrientation + headingAccuracyRad, - pxErrorRadius, - yg::Color(255, 255, 255, 192), - yg::maxDepth); - pDrawer->screen()->fillSector(pxPosition, - trueHeadingRad + m_headingOrientation - headingAccuracyRad, - trueHeadingRad + m_headingOrientation + headingAccuracyRad, - pxErrorRadius, - yg::Color(255, 255, 255, 96), - yg::maxDepth - 1); - /* /// magnetic heading - double magneticHeadingRad = m_magneticHeading / 180 * math::pi; - pDrawer->screen()->drawSector(pxPosition, - magneticHeadingRad + m_headingOrientation - headingAccuracyRad, - magneticHeadingRad + m_headingOrientation + headingAccuracyRad, - pxErrorRadius, - yg::Color(0, 255, 0, 64), - yg::maxDepth); - pDrawer->screen()->fillSector(pxPosition, - magneticHeadingRad + m_headingOrientation - headingAccuracyRad, - magneticHeadingRad + m_headingOrientation + headingAccuracyRad, - pxErrorRadius, - yg::Color(0, 255, 0, 32), - yg::maxDepth - 1); - */ + if (state & State::EGps) + { + // my position symbol + drawer.drawSymbol(pxPosition, "current-position", yg::EPosCenter, yg::maxDepth); + // my position circle + drawer.screen()->fillSector(pxPosition, 0, math::pi * 2, pxErrorRadius, + yg::Color(0, 0, 255, (state & State::EPreciseMode) ? 32 : 16), + yg::maxDepth - 3); + // display compass only if position is available + if (state & State::ECompass) + { + drawer.screen()->drawSector(pxPosition, + state.Heading() - state.HeadingAccuracy(), + state.Heading() + state.HeadingAccuracy(), + pxErrorRadius, + yg::Color(255, 255, 255, 192), + yg::maxDepth); + drawer.screen()->fillSector(pxPosition, + state.Heading() - state.HeadingAccuracy(), + state.Heading() + state.HeadingAccuracy(), + pxErrorRadius, + yg::Color(255, 255, 255, 96), + yg::maxDepth - 1); + } + } } void InformationDisplay::enableDebugPoints(bool doEnable) @@ -644,10 +572,6 @@ void InformationDisplay::drawBenchmarkInfo(DrawerYG * pDrawer) void InformationDisplay::doDraw(DrawerYG *drawer) { m_yOffset = 0; - if (m_isPositionEnabled) - drawPosition(drawer); - if (m_isHeadingEnabled) - drawHeading(drawer); if (m_isDebugPointsEnabled) drawDebugPoints(drawer); if (m_isRulerEnabled) diff --git a/map/information_display.hpp b/map/information_display.hpp index 69fe6ca414..5cd5ba6cea 100644 --- a/map/information_display.hpp +++ b/map/information_display.hpp @@ -1,13 +1,17 @@ #pragma once #include "window_handle.hpp" -#include "locator.hpp" #include "../geometry/point2d.hpp" #include "../geometry/rect2d.hpp" #include "../geometry/screenbase.hpp" #include "../base/timer.hpp" #include "../base/logging.hpp" +namespace location +{ + class State; +} + class DrawerYG; /// Class, which displays additional information on the primary layer. @@ -20,18 +24,6 @@ private: m2::RectI m_displayRect; int m_yOffset; - double m_headingOrientation; - - bool m_isHeadingEnabled; - double m_trueHeading; - double m_magneticHeading; - double m_headingAccuracy; - - bool m_isPositionEnabled; - Locator::EMode m_mode; - m2::PointD m_position; - double m_errorRadius; - /// for debugging purposes /// up to 10 debugging points bool m_isDebugPointsEnabled; @@ -81,22 +73,14 @@ public: InformationDisplay(); + static void DrawMyPosition(DrawerYG & drawer, + ScreenBase const & screen, + location::State const & state); + void setScreen(ScreenBase const & screen); void setDisplayRect(m2::RectI const & rect); void setBottomShift(double bottomShift); void setVisualScale(double visualScale); - void setOrientation(EOrientation orientation); - - void enablePosition(bool doEnable); - void setPosition(m2::PointD const & mercatorPos, double errorRadius); - void setLocatorMode(Locator::EMode mode); - m2::PointD const & position() const; - double errorRadius() const; - void drawPosition(DrawerYG * pDrawer); - - void enableHeading(bool doEnable); - void setHeading(double trueHeading, double magneticHeading, double accuracy); - void drawHeading(DrawerYG * pDrawer); void enableDebugPoints(bool doEnable); void setDebugPoint(int pos, m2::PointD const & pt); diff --git a/map/location_state.cpp b/map/location_state.cpp new file mode 100644 index 0000000000..5b97a2f731 --- /dev/null +++ b/map/location_state.cpp @@ -0,0 +1,66 @@ +#include "location_state.hpp" + +#include "../platform/location.hpp" + +#include "../indexer/mercator.hpp" + +namespace location +{ + + State::State() : m_deviceOrientation(-math::pi / 2), m_type(ENone) + { + } + + void State::UpdateGps(GpsInfo const & info) + { + if (info.m_status == EAccurateMode + || info.m_status == ERoughMode) + { + m_type |= EGps; + if (info.m_status == EAccurateMode) + m_type |= EPreciseMode; + else + m_type &= !EPreciseMode; + + m_positionMercator = m2::PointD(MercatorBounds::LonToX(info.m_longitude), + MercatorBounds::LatToY(info.m_latitude)); + m2::RectD const errorRectXY = + MercatorBounds::MetresToXY(info.m_longitude, info.m_latitude, + info.m_horizontalAccuracy); + m_errorRadiusMercator = sqrt((errorRectXY.SizeX() * errorRectXY.SizeX() + + errorRectXY.SizeY() * errorRectXY.SizeY()) / 4); + } + else + { + m_type &= !EGps; + } + } + + void State::UpdateCompass(CompassInfo const & info) + { + m_type |= ECompass; + + m_headingRad = ((info.m_trueHeading >= 0.0) ? info.m_trueHeading : info.m_magneticHeading) + / 180 * math::pi; + m_headingAccuracyRad = info.m_accuracy / 180 * math::pi; + } + + void State::SetOrientation(EOrientation orientation) + { + switch (orientation) + { + case EOrientation0: + m_deviceOrientation = -math::pi / 2; + break; + case EOrientation90: + m_deviceOrientation = math::pi; + break; + case EOrientation180: + m_deviceOrientation = math::pi / 2; + break; + case EOrientation270: + m_deviceOrientation = 0; + break; + } + } +} diff --git a/map/location_state.hpp b/map/location_state.hpp new file mode 100644 index 0000000000..15d38fbe5d --- /dev/null +++ b/map/location_state.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "../geometry/point2d.hpp" +#include "../geometry/screenbase.hpp" + +namespace location +{ + class GpsInfo; + class CompassInfo; + + class State + { + double m_errorRadiusMercator; + m2::PointD m_positionMercator; + + double m_deviceOrientation; + double m_headingRad; + double m_headingAccuracyRad; + + public: + enum SymbolType + { + ENone = 0x0, + EGps = 0x1, + EPreciseMode = 0x2, + ECompass = 0x4, + }; + + State(); + + /// @return GPS error radius in mercator + double ErrorRadius() const { return m_errorRadiusMercator; } + /// @return GPS center point in mercator + m2::PointD Position() const { return m_positionMercator; } + /// takes into account device's orientation + /// @return angle in radians + double Heading() const { return m_deviceOrientation + m_headingRad; } + /// @return angle in radians + double HeadingAccuracy() const { return m_headingAccuracyRad; } + + void TurnOff() { m_type = ENone; } + void UpdateGps(GpsInfo const & info); + void UpdateCompass(CompassInfo const & info); + void SetOrientation(EOrientation orientation); + + operator int() const + { + return m_type; + } + + private: + /// stores flags from SymbolType + int m_type; + }; +} diff --git a/map/locator.cpp b/map/locator.cpp deleted file mode 100644 index a5bcf15d70..0000000000 --- a/map/locator.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "../base/SRC_FIRST.hpp" -#include "locator.hpp" - -Locator::Locator() : m_isRunning(false) -{} - -Locator::~Locator() -{} - -void Locator::setMode(EMode mode) -{ - m_mode = mode; -} - -Locator::EMode Locator::mode() const -{ - return m_mode; -} - -void Locator::start(Locator::EMode /*mode*/) -{ - m_isRunning = true; -} - -void Locator::stop() -{ - m_isRunning = false; -} - -bool Locator::isRunning() const -{ - return m_isRunning; -} - -void Locator::callOnChangeModeFns(EMode oldMode, EMode newMode) -{ - list handlers = m_onChangeModeFns; - for (list::iterator it = handlers.begin(); it != handlers.end(); ++it) - (*it)(oldMode, newMode); -} - -void Locator::callOnUpdateLocationFns(m2::PointD const & pt, double errorRadius, double locTimeStamp, double curTimeStamp) -{ - list handlers = m_onUpdateLocationFns; - for (list::iterator it = handlers.begin(); it != handlers.end(); ++it) - (*it)(pt, errorRadius, locTimeStamp, curTimeStamp); -} - -void Locator::callOnUpdateHeadingFns(double trueHeading, double magneticHeading, double accuracy) -{ - list handlers = m_onUpdateHeadingFns; - for (list::iterator it = handlers.begin(); it != handlers.end(); ++it) - (*it)(trueHeading, magneticHeading, accuracy); -} diff --git a/map/locator.hpp b/map/locator.hpp deleted file mode 100644 index 9df37791a6..0000000000 --- a/map/locator.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include "../std/list.hpp" -#include "../std/function.hpp" -#include "../geometry/point2d.hpp" - -/// Base class for OS-dependent implementation of locator -class Locator -{ -public: - - enum EMode - { - ERoughMode, //< monitor only significant place changes, saves battery. - EPreciseMode //< monitor place changes with the maximum available accuracy - }; - - typedef function onUpdateLocationFn; - typedef function onUpdateHeadingFn; - typedef function onChangeModeFn; - -private: - - list m_onUpdateLocationFns; - list m_onUpdateHeadingFns; - list m_onChangeModeFns; - - EMode m_mode; - - bool m_isRunning; - -public: - - Locator(); - virtual ~Locator(); - - bool isRunning() const; - virtual void start(EMode mode) = 0; - virtual void stop() = 0; - virtual void setMode(EMode mode) = 0; - EMode mode() const; - - template - void addOnUpdateLocationFn(Fn fn) - { - m_onUpdateLocationFns.push_back(fn); - } - - template - void addOnUpdateHeadingFn(Fn fn) - { - m_onUpdateHeadingFns.push_back(fn); - } - - template - void addOnChangeModeFn(Fn fn) - { - m_onChangeModeFns.push_back(fn); - } - - void callOnUpdateLocationFns(m2::PointD const & pt, double errorRadius, double locTimeStamp, double curTimeStamp); - void callOnUpdateHeadingFns(double trueHeading, double magneticHeading, double accuracy); - void callOnChangeModeFns(EMode oldMode, EMode newMode); -}; diff --git a/map/map.pro b/map/map.pro index 154f122af1..9fee22cc98 100644 --- a/map/map.pro +++ b/map/map.pro @@ -22,7 +22,7 @@ HEADERS += \ render_queue_routine.hpp \ information_display.hpp \ settings.hpp \ - locator.hpp + location_state.hpp \ SOURCES += \ feature_vec_model.cpp \ @@ -34,7 +34,7 @@ SOURCES += \ render_queue_routine.cpp \ information_display.cpp \ settings.cpp \ - locator.cpp + location_state.cpp \ !iphone*:!bada* { HEADERS += qgl_render_context.hpp diff --git a/omim.pro b/omim.pro index bbdd834431..de10a1b9c3 100644 --- a/omim.pro +++ b/omim.pro @@ -35,6 +35,7 @@ SUBDIRS = 3party \ base \ coding \ geometry \ + platform \ yg \ indexer \ version \ diff --git a/platform/apple_location_service.mm b/platform/apple_location_service.mm index a507af0985..216436daec 100644 --- a/platform/apple_location_service.mm +++ b/platform/apple_location_service.mm @@ -41,7 +41,12 @@ public: void OnLocationUpdate(GpsInfo & newLocation) { newLocation.m_status = m_status; - NotifySubscribers(newLocation); + NotifyGpsObserver(newLocation); + } + + void OnHeadingUpdate(CompassInfo & newHeading) + { + NotifyCompassObserver(newHeading); } // virtual bool IsServiceSupported() @@ -71,7 +76,7 @@ public: m_status = EDisabledByUser; GpsInfo info; info.m_status = m_status; - NotifySubscribers(info); + NotifyGpsObserver(info); } else { @@ -79,23 +84,21 @@ public: { m_status = EAccurateMode; m_locationManager.desiredAccuracy = kCLLocationAccuracyBest; - // also enable compass -#ifdef OMIM_OS_IPHONE - if ([CLLocationManager headingAvailable]) - [m_locationManager startHeadingUpdate]; -#endif } else { m_status = ERoughMode; m_locationManager.desiredAccuracy = ROUGH_ACCURACY; - // also disable compass -#ifdef OMIM_OS_IPHONE - if ([CLLocationManager headingAvailable]) - [m_locationManager stopHeadingUpdate]; -#endif } [m_locationManager startUpdatingLocation]; + // enable compass +#ifdef OMIM_OS_IPHONE + if ([CLLocationManager headingAvailable]) + { + m_locationManager.headingFilter = 1.0; + [m_locationManager startUpdatingHeading]; + } +#endif } } @@ -103,7 +106,7 @@ public: { #ifdef OMIM_OS_IPHONE if ([CLLocationManager headingAvailable]) - [m_locationManager stopHeadingUpdate]; + [m_locationManager stopUpdatingHeading]; #endif [m_locationManager stopUpdatingLocation]; } @@ -134,7 +137,7 @@ public: info.m_verticalAccuracy = location.verticalAccuracy; info.m_latitude = location.coordinate.latitude; info.m_longitude = location.coordinate.longitude; - info.m_timestamp = [location.timestamp timeIntervalSince1970]; + info.m_timestamp = -[location.timestamp timeIntervalSinceNow]; } - (void)locationManager:(CLLocationManager *)manager @@ -146,6 +149,22 @@ public: m_service->OnLocationUpdate(newInfo); } +#ifdef OMIM_OS_IPHONE +- (void)locationManager:(CLLocationManager *)manager + didUpdateHeading:(CLHeading *)newHeading +{ + CompassInfo newInfo; + newInfo.m_magneticHeading = newHeading.magneticHeading; + newInfo.m_trueHeading = newHeading.trueHeading; + newInfo.m_accuracy = newHeading.headingAccuracy; + newInfo.m_x = newHeading.x; + newInfo.m_y = newHeading.y; + newInfo.m_z = newHeading.z; + newInfo.m_timestamp = -[newHeading.timestamp timeIntervalSinceNow]; + m_service->OnHeadingUpdate(newInfo); +} +#endif + - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { diff --git a/platform/location.cpp b/platform/location.cpp deleted file mode 100644 index ef93075b04..0000000000 --- a/platform/location.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "location.hpp" - -#include "../std/algorithm.hpp" - -#include - -namespace location -{ - void LocationService::NotifySubscribers(GpsInfo const & info) - { - for (GpsObserversT::iterator it = m_gpsObservers.begin(); - it != m_gpsObservers.end(); ++it) - (*it)(info); - } - - void LocationService::NotifySubscribers(CompassInfo const & info) - { - for (CompassObserversT::iterator it = m_compassObservers.begin(); - it != m_compassObservers.end(); ++it) - (*it)(info); - } - - void LocationService::SubscribeToGpsUpdates(TGpsCallback observer) - { -// if (std::find(m_gpsObservers.begin(), m_gpsObservers.end(), boost::bind(&observer)) -// == m_gpsObservers.end()) - m_gpsObservers.push_back(observer); - } - - void LocationService::SubscribeToCompassUpdates(TCompassCallback observer) - { -// if (std::find(m_compassObservers.begin(), m_compassObservers.end(), observer) -// == m_compassObservers.end()) - m_compassObservers.push_back(observer); - } - -// void LocationService::Unsubscribe(TGpsCallback observer) -// { -// GpsObserversT::iterator found = -// std::find(m_gpsObservers.begin(), m_gpsObservers.end(), observer); -// if (found != m_gpsObservers.end()) -// m_gpsObservers.erase(found); -// } - -// void LocationService::Unsubscribe(TCompassCallback observer) -// { -// CompassObserversT::iterator found = -// std::find(m_compassObservers.begin(), m_compassObservers.end(), observer); -// if (found != m_compassObservers.end()) -// m_compassObservers.erase(found); -// } -} diff --git a/platform/location.hpp b/platform/location.hpp index c9cf3d148a..bf7325ab7c 100644 --- a/platform/location.hpp +++ b/platform/location.hpp @@ -7,6 +7,9 @@ namespace location { + /// after this period we cont position as "too old" + static double const POSITION_TIMEOUT_SECONDS = 300.0; + enum TLocationStatus { ENotSupported, //!< GpsInfo fields are not valid with this value @@ -19,9 +22,9 @@ namespace location struct GpsInfo { TLocationStatus m_status; - double m_timestamp; //!< seconds from 01/01/1970 - double m_latitude; //!< degrees @TODO mercator - double m_longitude; //!< degrees @TODO mercator + double m_timestamp; //!< how many seconds ago the position was retrieved + double m_latitude; //!< degrees + double m_longitude; //!< degrees double m_horizontalAccuracy; //!< metres double m_altitude; //!< metres double m_verticalAccuracy; //!< metres @@ -29,9 +32,10 @@ namespace location double m_speed; //!< metres per second }; + /// @note always check m_status before using this structure struct CompassInfo { - double m_timestamp; //!< seconds from 01/01/1970 + double m_timestamp; //!< how many seconds ago the heading was retrieved double m_magneticHeading; //!< positive degrees from the magnetic North double m_trueHeading; //!< positive degrees from the true North double m_accuracy; //!< offset from magnetic to true North @@ -40,29 +44,39 @@ namespace location int m_z; }; - typedef boost::function1 TGpsCallback; - typedef boost::function1 TCompassCallback; + typedef boost::function TGpsCallback; + typedef boost::function TCompassCallback; class LocationService { - typedef vector GpsObserversT; - GpsObserversT m_gpsObservers; - typedef vector CompassObserversT; - CompassObserversT m_compassObservers; + TGpsCallback m_gpsObserver; + TCompassCallback m_compassObserver; protected: - void NotifySubscribers(GpsInfo const & info); - void NotifySubscribers(CompassInfo const & info); + void NotifyGpsObserver(GpsInfo const & info) + { + if (m_gpsObserver) + m_gpsObserver(info); + } + void NotifyCompassObserver(CompassInfo const & info) + { + if (m_compassObserver) + m_compassObserver(info); + } public: - /// @note unsubscribe doesn't work with boost::function - void SubscribeToGpsUpdates(TGpsCallback observer); - void SubscribeToCompassUpdates(TCompassCallback observer); -// void Unsubscribe(TGpsCallback observer); -// void Unsubscribe(TCompassCallback observer); + void SetGpsObserver(TGpsCallback observer) + { + m_gpsObserver = observer; + } + + void SetCompassObserver(TCompassCallback observer) + { + m_compassObserver = observer; + } /// to change active accuracy mode just call it again - /// @param useAccurateMode if true also enables compass if it's available + /// @note also enables compass if it's available virtual void StartUpdate(bool useAccurateMode) = 0; virtual void StopUpdate() = 0; }; diff --git a/platform/platform.pro b/platform/platform.pro index ccbac00b5e..f9e8c040ca 100644 --- a/platform/platform.pro +++ b/platform/platform.pro @@ -11,17 +11,20 @@ include($$ROOT_DIR/common.pri) QT *= core network -SOURCES += \ - qtplatform.cpp \ - qt_download_manager.cpp \ - qt_download.cpp \ - location.cpp \ +!iphone* { + SOURCES += \ + qtplatform.cpp \ + qt_download_manager.cpp \ + qt_download.cpp \ + + HEADERS += \ + qt_download_manager.hpp \ + qt_download.hpp \ +} HEADERS += \ platform.hpp \ download_manager.hpp \ - qt_download_manager.hpp \ - qt_download.hpp \ location.hpp \ mac|iphone* { diff --git a/platform/platform_tests/platform_tests.pro b/platform/platform_tests/platform_tests.pro index 5e68170e64..5262ee63a6 100644 --- a/platform/platform_tests/platform_tests.pro +++ b/platform/platform_tests/platform_tests.pro @@ -14,6 +14,11 @@ win32 { LIBS += -lShell32 } +mac { + LIBS += -framework CoreLocation -framework Foundation +} + + SOURCES += \ ../../testing/testingmain.cpp \ platform_test.cpp \ diff --git a/qt/draw_widget.cpp b/qt/draw_widget.cpp index dbae4ef454..efcb03597d 100644 --- a/qt/draw_widget.cpp +++ b/qt/draw_widget.cpp @@ -71,6 +71,16 @@ namespace qt // m_framework.ShowFeature(p); //} + void DrawWidget::OnEnableMyPosition(LocationRetrievedCallbackT observer) + { + m_framework.StartLocationService(observer); + } + + void DrawWidget::OnDisableMyPosition() + { + m_framework.StopLocationService(); + } + void DrawWidget::MoveLeft() { m_framework.Move(math::pi, 0.5); diff --git a/qt/draw_widget.hpp b/qt/draw_widget.hpp index d6df4e02c3..8d7ada771c 100644 --- a/qt/draw_widget.hpp +++ b/qt/draw_widget.hpp @@ -56,6 +56,9 @@ namespace qt void SetScaleControl(QSlider * pScale); + void OnEnableMyPosition(LocationRetrievedCallbackT observer); + void OnDisableMyPosition(); + //model_t * GetModel() { return &(m_framework.get_model()); } //void ShowFeature(Feature const & p); diff --git a/qt/mainwindow.cpp b/qt/mainwindow.cpp index 2643b71639..3ae3d2d991 100644 --- a/qt/mainwindow.cpp +++ b/qt/mainwindow.cpp @@ -232,6 +232,13 @@ void MainWindow::CreateNavigationBar() pBar->setIconSize(QSize(32, 32)); { + // add my position button with "checked" behavior + m_pMyPosition = pBar->addAction(QIcon(":/navig64/plus.png"), + tr("My Position"), + this, + SLOT(OnMyPosition())); + m_pMyPosition->setCheckable(true); + // add view actions 1 button_t arr[] = { { tr("Left"), ":/navig64/left.png", SLOT(MoveLeft()) }, @@ -333,4 +340,23 @@ void MainWindow::OnPreferences() Settings::Set("AutomaticUpdateCheck", autoUpdatesEnabled); } +void MainWindow::OnLocationFound() +{ + // @TODO change button icon to "found location" +} + +void MainWindow::OnMyPosition() +{ + if (m_pMyPosition->isChecked()) + { + // @TODO change button icon to "searching location" + m_pDrawWidget->OnEnableMyPosition(boost::bind(&MainWindow::OnLocationFound, this)); + } + else + { + // @TODO change + m_pDrawWidget->OnDisableMyPosition(); + } +} + } diff --git a/qt/mainwindow.hpp b/qt/mainwindow.hpp index 1d20e99c0b..4c7ba1d4d9 100644 --- a/qt/mainwindow.hpp +++ b/qt/mainwindow.hpp @@ -16,6 +16,7 @@ namespace qt class MainWindow : public QMainWindow { + QAction * m_pMyPosition; DrawWidget * m_pDrawWidget; QDockWidget * m_Docks[2]; //FindTableWnd * m_pFindTable; @@ -34,6 +35,9 @@ namespace qt void SaveState(); void LoadState(); + private: + void OnLocationFound(); + protected: void CreatePanelImpl(size_t i, QString const & name, QKeySequence const & hotkey, char const * slot); @@ -56,6 +60,7 @@ namespace qt void ShowGuidePanel(); void OnAbout(); void OnPreferences(); + void OnMyPosition(); }; } diff --git a/qt/qt.pro b/qt/qt.pro index ebda16a133..9479b837a6 100644 --- a/qt/qt.pro +++ b/qt/qt.pro @@ -15,6 +15,8 @@ win32 { } macx { + LIBS += -framework CoreLocation -framework Foundation + ICON = res/mac.icns PLIST_FILE = Info.plist # path to original plist, which will be processed by qmake and later by us