测试代码如下:
// LocationViewCtrl.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface LocationViewCtrl : UIViewController <CLLocationManagerDelegate>{
CLLocationManager *man;
}
@property(nonatomic, retain) CLLocationManager *man;
@end
LocationViewCtrl.m
#import "LocationViewCtrl.h"
#import <CoreLocation/CoreLocation.h>
@implementation LocationViewCtrl
@synthesize man;
- (void)viewDidLoad {
[super viewDidLoad];
man = [[CLLocationManager alloc] init];
// 如果可以利用本地服务时
if([man locationServicesEnabled]){
// 接收事件的实例
man.delegate = self;
// 发生事件的的最小距离间隔(缺省是不指定)
man.distanceFilter = kCLDistanceFilterNone;
// 精度 (缺省是Best)
man.desiredAccuracy = kCLLocationAccuracyBest;
// 开始测量
[man startUpdatingLocation];
}
}
// 如果GPS测量成果以下的函数被调用
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{
// 取得经纬度
CLLocationCoordinate2D coordinate = newLocation.coordinate;
CLLocationDegrees latitude = coordinate.latitude;
CLLocationDegrees longitude = coordinate.longitude;
// 取得精度
CLLocationAccuracy horizontal = newLocation.horizontalAccuracy;
CLLocationAccuracy vertical = newLocation.verticalAccuracy;
// 取得高度
CLLocationDistance altitude = newLocation.altitude;
// 取得时刻
NSDate *timestamp = [newLocation timestamp];
// 以下面的格式输出 format: <latitude>, <longitude>> +/- <accuracy>m @ <date-time>
NSLog([newLocation description]);
// 与上次测量地点的间隔距离
if(oldLocation != nil){
CLLocationDistance d = [newLocation getDistanceFrom:oldLocation];
NSLog([NSString stringWithFormat:@"%f", d]);
}
}
// 如果GPS测量失败了,下面的函数被调用
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error{
NSLog([error localizedDescription]);
}
...
测量精度有以下几类,精度越高越消耗电力。
kCLLocationAccuracyNearestTenMeters | 10m |
kCLLocationAccuracyHundredMeters | 100m |
kCLLocationAccuracyKilometer | 1km |
kCLLocationAccuracyThreeKilometers | 3km |
因为在模拟器上不能设置经纬度,所以只能在实际设备中测试你的GPS程序
Core Location主要应用了GPS, 蜂窝基站三角网以及Wi_Fi(WPS)三种技术。
想得到定点的信息,需要涉及到几个类,CLLocationManager, CLLocation, CLLocationManagerdelegate协议,CLLocationCoodinate2D, CLLocationDegrees。
<一>先实例化一个CLLocationManager,同时设置委托及精确度等。
CCLocationManager *manager = [[CLLocationManager alloc] init];//初始化定位器 [manager setDelegate: self];//设置代理 [manager setDesiredAccuracy: kCLLocationAccuracyBest];//设置精确度
其中desiredAccuracy属性表示精确度,有5种选择如下:
desiredAccuracy属性 |
描述 |
kCLLocationAccuracyBest |
精确度最佳 |
kCLLocationAccuracynearestTenMeters |
精确度10m以内 |
kCLLocationAccuracyHundredMeters |
精确度100m以内 |
kCLLocationAccuracyKilometer |
精确度1000m以内 |
kCLLocationAccuracyThreeKilometers |
精确度3000m以内 |
NOTE:精确度越高,用点越多,就要根据实际情况而定。
manager.distanceFilter = 250;//这个表示在地图上每隔250m才更新一次定位信息。
[manager startUpdateLocation]; 启动定位器,如果不用的时候就必须调用stopUpdateLocation以关闭定位功能。
<二>CCLocation对像中包含着定点的相关信息数据。其属性主要包括coordinate, altitude,horizontalAccuracy,verticalAccuracy, timestamp等,分别如下:
coordinate 用来存储地理位置的latitude和longitude,分别表示纬度和经度,都是float类型.如可这样: float latitude = location.coordinat.latitude; location是CCLocation的实例。这里也把上面提到的CLLocationDegrees,它其实是一个double类型,在core Location框架中是用来储存CLLocationCoordinate2D实例coordinate的latitude 和longitude,
typedef double CLLocationDegrees;
typedef struct
{CLLocationDegrees latitude;
CLLocationDegrees longitude} CLLocationCoordinate2D;
altitude 表示位置的海拔高度,这个值是极不准确的。
horizontalAccuracy 表示水平准确度,这么理解,它是以coordinate为圆心的半径,返回的值越小,证明准确度越好,如果是负数,则表示core location定位失败。
verticalAccuracy表示垂直准确度,它的返回值与altitude相关,所以不准确。
Timestamp 返回的是定位时的时间,是NSDate类型。
<三>CLLocationMangerDelegate协议
我们只需实现两个方法就可以了,如下:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation ;
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
上面第一个是定位时候回访调,后者定位出错时被调。
<四>现在可以去实现定位了:
新建一个view-based application模板的工程,假设项目名称为coreLocation.我们在contronller的头文件和源文件中的代码大概有如下:
.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface CoreLocationViewController : UIViewController
<CLLocationManagerDelegate>{
CLLocationManager *locManager;
}
@property (nonatomic, retain) CLLocationManager *locManager;
@end
.m
#import "CoreLocationViewController.h"
@implementation CoreLocationViewController
@synthesize locManager;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
locManager.desiredAccuracy = kCLLocationAccuracyBest;
[locManager startUpdatingLocation];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[locManager stopUpdatingLocation];
[locManager release];
[textView release];
[super dealloc];
}
#pragma mark -
#pragma mark CoreLocation Delegate Methods
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
CLLocationCoordinate2D locat = [newLocation coordinate];
float lattitude = locat.latitude;
float longitude = locat.longitude;
float horizon = newLocation.horizontalAccuracy;
float vertical = newLocation.verticalAccuracy;
NSString *strShow = [[NSString alloc] initWithFormat:
@"currentpos: 经度=%f 维度=%f 水平准确读=%f 垂直准确度=%f ",
lattitude, longitude, horizon, vertical];
UIAlertView *show = [[UIAlertView alloc] initWithTitle:@"coreLoacation"
message:strShow delegate:nil cancelButtonTitle:@"i got it"
otherButtonTitles:nil];
[show show];
[show release];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error{
NSString *errorMessage;
if ([error code] == kCLErrorDenied){
errorMessage = @"你的访问被拒绝";}
if ([error code] == kCLErrorLocationUnknown) {
errorMessage = @"无法定位到你的位置!";}
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:nil message:errorMessage
delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alert show];
[alert release];
}
@end
//根据经纬度计算两点的距离
#define PI 3.1415926
double LantitudeLongitudeDist(double lon1,double lat1,
double lon2,double lat2)
{
double er = 6378137; // 6378700.0f;
//ave. radius = 6371.315 (someone said more accurate is 6366.707)
//equatorial radius = 6378.388
//nautical mile = 1.15078
double radlat1 = PI*lat1/180.0f;
double radlat2 = PI*lat2/180.0f;
//now long.
double radlong1 = PI*lon1/180.0f;
double radlong2 = PI*lon2/180.0f;
if( radlat1 < 0 ) radlat1 = PI/2 + fabs(radlat1);// south
if( radlat1 > 0 ) radlat1 = PI/2 - fabs(radlat1);// north
if( radlong1 < 0 ) radlong1 = PI*2 - fabs(radlong1);//west
if( radlat2 < 0 ) radlat2 = PI/2 + fabs(radlat2);// south
if( radlat2 > 0 ) radlat2 = PI/2 - fabs(radlat2);// north
if( radlong2 < 0 ) radlong2 = PI*2 - fabs(radlong2);// west
//spherical coordinates x=r*cos(ag)sin(at), y=r*sin(ag)*sin(at), z=r*cos(at)
//zero ag is up so reverse lat
double x1 = er * cos(radlong1) * sin(radlat1);
double y1 = er * sin(radlong1) * sin(radlat1);
double z1 = er * cos(radlat1);
double x2 = er * cos(radlong2) * sin(radlat2);
double y2 = er * sin(radlong2) * sin(radlat2);
double z2 = er * cos(radlat2);
double d = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));
//side, side, side, law of cosines and arccos
double theta = acos((er*er+er*er-d*d)/(2*er*er));
double dist = theta*er;
return dist;
}