在这个神奇的国度里,我们总得学习一些有中国特色的东东,例如“火星坐标”。也许有人还不知道这是什么玩意,我就简要介绍一下吧。
如果你有带GPS模块的智能手机,打开定位功能,然后访问Google地图。只要你身处中国大陆,你就会发现定位不准,大概有几百米的偏差。然而运行一些导航软件,你又会发现定位很准确,说明手机的GPS模块确实是正常的。
这种现象是怎么造成的呢?答案是人为造成的。简单来说,GPS模块获取到的坐标是WGS84坐标系的,中国政府出于种种目的的考虑,不允许中国的地图使用国际通用的WGS84坐标系,而非要加上一些偏移,这样的坐标系就俗称“火星坐标系”。而Google地图采用的也是加偏移过的火星坐标系,但GPS模块传给它的坐标却没有加偏移,于是就出现几百米的偏差了。
这样的后果就是没法做需要很高精度的地理位置的应用了,就像那个悲剧的Google地图一样,你迷路时无法指望它告诉你正确的位置。
不过上有政策,下有对策。首先要说的是不加偏的地图肯定是没有的,就算有也是机密,只能掌握在美国佬手里。所以只能考虑如何将WGS84坐标转换成火星坐标了。遗憾的是这种转换不是线性的,没有一个简单的换算公式,而且每个地图提供商采用的加偏算法都不相同(也就是有很多种火星坐标系)。
然而勤劳智慧的中国屁民们很快就找到了解决办法:用大量的采样点覆盖这960万平方公里的土地,把对应的WGS84坐标和火星坐标一一记录起来,做成一个偏移数据库,然后直接查询即可。缺点就是统计麻烦,随着精度的提高,数据库占用的空间也会增大,而且地图商一换坐标系(一般几年一次),数据库就失效了。
还有一些更聪明的人就用matlab来分析这些采样点,拟合出了加偏函数的曲线,然后直接计算即可。
不过我属于那种很懒又不会matlab的人,所以上述方案都被我否决了(还有个原因就是那样做是违法的)。
后来我无意中想起Google地图的数据来自MapABC,何不去MapABC看看呢?于是搜索了一下,发现了MapABC地图API。在MapABC API for iOS文档里我找到了GPSToOffSetByPoint:方法,用途就是查询偏移后的坐标!
于是赶紧注册账号,获取移动版API KEY,并下载iOS API SDK和文档。搞定这些后就可以开启Xcode来试验了。
先做个获取WGS84坐标的应用出来:
// MapDemoViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface MapDemoViewController : UIViewController <CLLocationManagerDelegate> {
UITextField *wgsText;
UITextField *marsText;
CLLocationManager *locationManager;
}
@property (nonatomic, retain) IBOutlet UITextField *wgsText;
@property (nonatomic, retain) IBOutlet UITextField *marsText;
@property (nonatomic, retain) CLLocationManager *locationManager;
@end
// MapDemoViewController.m
#import "MapDemoViewController.h"
@implementation MapDemoViewController
@synthesize wgsText;
@synthesize marsText;
@synthesize locationManager;
- (void)viewDidLoad {
[super viewDidLoad];
if ([CLLocationManager locationServicesEnabled]) { // 检查定位服务是否可用
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation]; // 开始定位
}
}
// 定位成功时调用
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
CLLocationCoordinate2D coordinate = newLocation.coordinate;
CLLocationDegrees latitude = coordinate.latitude;
CLLocationDegrees longitude = coordinate.longitude;
wgsText.text = [NSString stringWithFormat:@"%f,%f", latitude, longitude];
}
// 定位失败时调用
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
wgsText.text = [error localizedDescription];
marsText.text = @"";
}
- (void)viewDidUnload {
self.wgsText = nil;
self.marsText = nil;
self.locationManager = nil;
}
- (void)dealloc {
[wgsText release];
[marsText release];
[locationManager release];
[super dealloc];
}
@end
构建前别忘了在Framework里加上CoreLocation.framework。这个例子只能在真机上运行,因为模拟器没有定位功能,肯定会失败。
如果没出现什么差错的话,你可以看到wgsText对应的文本框里会显示你的WGS84坐标了,不过marsText还是空白。
接下来把SDK中的include文件夹复制到项目的Classes文件夹下,再创建一个lib文件夹,把libiMapSDKLib.a复制进去(因为模拟器没用,所以直接复制release版的),再将这些文件全部添加到项目里。
接着在Framework里加上libstdc++.dylib(一共有5个,貌似随便选一个即可)。
然后打开项目设置,把“Other Linker Flag”设为“-liMapSDKLib”(也就是去掉库文件名前后的lib和.a,并在前面加上-l参数)。再将“Header Search Path”设为“$(SRCROOT)/include”,Recursive打钩;“Library Search Path”设为“$(SRCROOT)/lib”。
这样设置就完成了,build一下,如果没error就表示正常。
接下来要创建一个MSearch对象,由于需要持久存在,将其作为MapDemoViewController的属性。
而这个对象的delegate属性需要实现MSearchDelegate和GPSToOffsetByPoint_Delegate协议,于是也给MapDemoViewController加上。
GPSToOffsetByPoint_Delegate协议还包含了MLONLAT poiXY和MCOORDINATESEARCHOPTIONS options这2个属性(都是结构,无需retain),因此也得加上。
最后别忘了加上“#import "MSearch.h"”。
定义完成后,就可以开始创建MSearch对象了。这个对象初始化时需要与MapABC服务器通信,验证API KEY是否有效。
这个验证过程是异步的,当验证完成后才能使用它,因此当检查到定位服务可用时,就可以立刻创建它了:
self.search = [MSearch MSearchWithKey:@"你申请的API KEY" delegate:self];
而在获取到WGS84坐标后,就可以查询火星坐标了:
poiXY.X = longitude; // 经度
poiXY.Y = latitude; // 维度
[search GPSToOffSetByPoint:self];
这里不需要设置options属性,使用初始值即可。GPSToOffSetByPoint:方法会返回SEARCH_THREAD_ID,由于不需要停止线程,因此无视。
当获取到火星坐标后,就会调用GPSToOffsetResponse:方法了。这个方法的lonlat参数就是火星坐标了:
-(void) GPSToOffsetResponse:(MLONLAT)lonlat {
marsText.text = [NSString stringWithFormat:@"%f,%f", lonlat.Y, lonlat.X];
}
现在build一下,你会发现出来一堆error了。一看发现是无法识别template语法,于是把2个.m文件重命名成.mm文件,使其可以混用C++。
再次build,仍然会出现“___restore_vfp_d8_d15_regs”之类完全看不懂的error。不过最后一行有提到“symbol(s) not found for architecture armv6”什么的,于是在项目设置里改成只编译ARMv7的,这下终于成功了。(支持ARMv6的解决办法暂时没找到,不知道是不是这库的限制。)
于是立刻尝试了一番,检验是否有效。
先用iPhone自带的地图应用定位,位置准确:
再用刚写的应用来定位,找到火星坐标:
最后到Google地图搜索这个火星坐标,与地图应用的定位吻合:
OK,大功告成,欢迎来到火星~
2011年11月27日更新:
刚发现MKLocationManager这个私有类有个_applyChinaLocationShift方法可以解决偏移,于是尝试了一番:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@class MKLocationManager;
@interface ViewController : UIViewController <CLLocationManagerDelegate> {
UITextField *wgsText;
UITextField *marsText;
CLLocationManager *locationManager;
MKLocationManager *shiftLocationManager;
}
@property (nonatomic, retain) IBOutlet UITextField *wgsText;
@property (nonatomic, retain) IBOutlet UITextField *marsText;
@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, retain) MKLocationManager *shiftLocationManager;
@end
#import <MapKit/MapKit.h>
#import "ViewController.h"
@interface MKLocationManager : NSObject
- (CLLocation*)_applyChinaLocationShift:(CLLocation*)arg;
- (BOOL)chinaShiftEnabled;
+ (id)sharedLocationManager;
@end
@implementation ViewController
@synthesize wgsText;
@synthesize marsText;
@synthesize locationManager;
@synthesize shiftLocationManager;
- (void)viewDidLoad
{
[super viewDidLoad];
if ([CLLocationManager locationServicesEnabled]) {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
self.shiftLocationManager = MKLocationManager.sharedLocationManager;
if (shiftLocationManager.chinaShiftEnabled) {
[[[MKMapView alloc] init] release]; // 必须初始化一个MKMapView对象,否则调用_applyChinaLocationShift:时会出错
} else {
self.shiftLocationManager = nil;
}
}
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
CLLocationCoordinate2D coordinate = newLocation.coordinate;
wgsText.text = [NSString stringWithFormat:@"%f,%f", coordinate.latitude, coordinate.longitude];
if (shiftLocationManager) {
newLocation = [shiftLocationManager _applyChinaLocationShift:newLocation]; // 获得偏移后的坐标
coordinate = newLocation.coordinate;
marsText.text = [NSString stringWithFormat:@"%f,%f", coordinate.latitude, coordinate.longitude];
}
}
// ...
@end
接着添加CoreLocation和MapKit这2个框架,就可以构建了。
测试时发现这个函数也需要联网,否则拿到的坐标为{0.0,0.0};不过获取到一次后,就可以断开网络了,这时候也能正常地偏移,而且不是线性的,看来是有内置的算法。经嗅探发现是要往http://www.google.cn/glm/mmap发送2次POST请求,不过都是二进制的数据,看不懂。
不过和其他私有API一样,模拟器上是没法用的,而且要冒被Apple拒绝的危险。
最后,据说iOS 5上要改用GEOLocationShiftProvider,不过我找不到相应资料,完全不会用…而且因为要使用GMM这个私有框架,很容易被Apple查出来。
http://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&sensor=true&language=zh-CN
申请开发者帐号
http://www.cnblogs.com/waitingsnow/archive/2012/04/09/2439415.html
留备注
转自http://www.keakon.net/category/iOS%E5%BC%80%E5%8F%91
- 大小: 914.2 KB
- 大小: 53 KB
- 大小: 348.4 KB
分享到:
相关推荐
Umi-OCR-main.zip
基于springboot+Web的毕业设计选题系统源码数据库文档.zip
基于springboot校外兼职教师考勤管理系统源码数据库文档.zip
58商铺全新UI试客试用平台网站源码
基于springboot大学生就业信息管理系统源码数据库文档.zip
基于SpringBoot的口腔诊所系统源码数据库文档.zip
数据存放网盘,txt文件内包含下载链接及提取码,永久有效。失效会第一时间进行补充。样例数据及详细介绍参见文章:https://blog.csdn.net/T0620514/article/details/143956923
3-240P2162218.zip
网络安全 基于Qt创建的Linux系统下的浏览器.zip
C++ 类和对象:多态-练习题目2(制作咖啡和茶叶)
基于springboot+J2EE在线项目管理与任务分配中的应用源码数据库文档.zip
简介本项目提供了一个在51单片机上运行的简单操作系统,旨在帮助学习者深入理解操作系统的基本原理和任务调度机制。该操作系统通过汇编和C语言编写,实现了任务调度、中断处理等核心功能,并提供了详细的源代码和注释,方便学习和实践。
本文将深度卷积神经网络(CNN)设计实现一个复杂结构的生成模型,旨在通过多阶段的编码器-解码器结构,能够有效地将灰度图像转换为彩色图像。最后,本文将实现一个简单的Web应用,用户可以通过上传灰度图像,应用会使用预训练的Caffe模型对其进行颜色化,并将结果返回给用户。 1.模型设计:模型由多个卷积层、ReLU激活函数和批归一化层组成,通过前向传播函数将输入的灰度图像(L通道)转换为彩色图像(ab通道)。如果指定了 pretrained=True,则会自动下载并加载预训练的模型权重。 2. 系统通过Flask框架提供了一个Web应用,用户可以上传灰度图像,系统会自动将其转换为彩色图像,并在网页上显示结果。整个过程包括文件验证、图像处理、颜色化预测和结果展示,具有较高的实用性和用户体验。
一个JAVA图形化的、联网的五子棋游戏.zip javaweb
KWDB 是一款面向 【AIoT 场景】的【分布式多模数据库】,支持在同一实例同时建立时序库和关系库并融合处理多模数据,具备千万级设备接入、百万级数据秒级写入、亿级数据秒级读取等时序数据高效处理能力,具有稳定安全、高可用、易运维等特点。
页面数量:7页 网页主题:网站模板、酒店网站模板、官方网站模板 网页页面:首页、关于我们、相关服务、服务详情、在线博客、博客详情、在线留言 页面实现元素:加载动画、滚动加载、主题切换、导航栏 、轮播图、图文列表、图片切换、 文字列表、 按钮悬停、图片悬停、表单 实现技术:HTML、CSS 、JQuery 源码样式及js文件均分开存放,所有内容仅供初学者学习参考
内容概要:本文档提供了详细的 Neo4j 安装与配置指南,涵盖 Windows、Linux 和 Mac 系统的安装步骤。具体包括下载、安装、启动服务、修改配置文件(如端口配置、远程访问和内存限制)、设置管理员密码以及基本的 Cypher 查询语言使用方法。同时,还提供了一些常见问题及其解决方案。 适合人群:数据库管理员、软件开发人员、系统管理员。 使用场景及目标:①帮助初学者快速掌握 Neo4j 的安装与配置;②适用于需要搭建和使用图数据库的项目;③为已有用户解决常见问题。 其他说明:本文档不仅包含了基础的安装和配置流程,还提供了实际操作中可能遇到的问题及其解决方法,有助于提高使用者的实际操作能力。
基于SpringBoot+Vue的软件产品展示销售系统源码数据库文档.zip
《书戴嵩画牛》教学课件.pptx
20届智能车 【项目资源】:包含前端、后端、移动开发、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源,毕业设计等各种技术项目的源码。包括C++、Java、python、web、C#、EDA等项目的源码。 【适用人群】:适用于希望学习不同技术领域的初学者或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。