iOS自带地图纠偏问题
…………纠偏 篇…………..
1. 涉及接口:<CoreLocation/CoreLocation.h>
2. 核心代码解读:
if ([CLLocationManager locationServicesEnabled]) {
[self.locationManager setDelegate:self];
[self.locationManager setDistanceFilter:200];
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager startUpdatingLocation];
} // 开始定位
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation;
//此代理方法可以实现新位置更新,即一定距离(200) 则更新一次当前位置,保持经纬度始终为最新
self.coordinate = [newLocation coordinate];
self.coordinate.longitude,self.coordinate.latitude // 更新后的经纬度
TIPS:虽然上面方法中获取到了目前的经纬度,但是这个经纬度并不是真实的经纬度,而是火星经纬度,理所当然,下面就是考虑如何纠偏了,因为直接用这个经纬度去获取周边信息,基本不算定位,属于分身之术。
经过又一轮的查询相关资料和询问相关人士,居然小小纠偏却蕴藏很大商机,很多公司都有自己的一套纠偏方案,或者是购买第三方纠偏数据库,没有办法,只能再找,最后发现,我们的国产互联网巨头百度老大居然提供一个纠偏接口,真是感动啊,开动纠偏程序:
————————
NSString *rectificationURL=[NSString stringWithFormat:@"http://api.map.baidu.com/ag/coord/convert?from=0&to=2&x=%f&y=%f",self.coordinate.longitude,self.coordinate.latitude]; // 带上经纬度开始纠偏,对API有疑问,请自觉百度一下
纠偏结果如下:
{“error”:0,
“x”:”MTE2LjQzNTM1NDU0NjQ0″,
“y”:”MzkuOTEzNzAwOTAwNjA4″
} // 0 即为正确纠偏,后面的太不厚道了,居然用GTMBase64 加密,还好,费一番功夫下载Google 的”GTMBase64.h” 代码顺利解密,汗…
结果如下:
{
error: 0,
x: “MTE2LjQzNTM1NDU0NjQ0″, 116.43535454644
y: “MzkuOTEzNzAwOTAwNjA4″ 39.913700900608
}
再次感谢百度,接下来当然是带上经度,带上纬度,开始取周边地理信息,关键代码如下:
NSString *url = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&language=%@&sensor=false", aCoordinate.latitude, aCoordinate.longitude,NSLocalizedStringFromTable(@"signLanguage", @"sign", nil)]; //获取用户当前具体地理位置
NSString *url = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=%@&types=%@&sensor=true&key=%@&language=%@", aCoordinate.latitude, aCoordinate.longitude, [NSString stringWithFormat:@"%i", RADIUS], @”", kGOOGLE_API_KEY,NSLocalizedStringFromTable(@”signLanguage”, @”sign”, nil)]; //获取用户周边地理位置
Tips:若对上述API 有疑问,请自觉前往:https://developers.google.com/places/documentation/#Authentication 其中涉及的具体参数都有说明,请自动取舍,切记先申请 kGOOGLE_API_KEY.
注:此外,还有一些导入的bug在这里说明一下:
1.首先是下载了GTMBase64.h(GTMBase64.h下载地址),因为这个GTMBase64是MRC的,所以要设置一下,可以在Build Phases中的Compile Sources中需要设置兼容的文件后面加入编译标记-fno-objc-arc,这样就不会报MRC和ARC兼容的错了
2.这个下载的GTMBase64文件在设置兼容mrc后还是会报错:Implicit declaration of function 'CC_MD5' is invalid in C99,所以还要设置一下,在GTMBase64.m文件import一个头文件:#import <CommonCrypto/CommonDigest.h>,至此这些坑都填好了
---------------------华丽的分割线--------------------------
其原理是这样的:保密局开发了一个系统,能将实际的坐标转换成虚拟的坐标。所有在中国销售的数字地图必须使用这个系统进行坐标转换之后方可上市。这是生产环节,这种电子地图被称为火星地图。在使用环节,GPS终端设备必须集成保密局提供的加密算法(集成工作由保密局完成),把从GPS卫星那里得到的坐标转换成虚拟坐标,然后再去火星地图上查找,这样就在火星坐标系上完成了地图的匹配。 所以大家所用的百度,高德等地图定位准是偏差几百米
名词总结:
地球坐标:指WGS84坐标系统
火星坐标:指使用国家保密插件人为偏移后的坐标
地球地图:指与地球坐标对应的客观真实的地图
火星地图:指经过加密偏移后的,与火星坐标对应的地图
坐标系转换算法
1.GCJ-02(火星坐标系)和BD-09转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// GCJ-02 坐标转换成 BD-09 坐标 + (CLLocationCoordinate2D)MarsGS2BaiduGS:(CLLocationCoordinate2D)coordinate { double x_pi = PI * 3000.0 / 180.0; double x = coordinate.longitude, y = coordinate.latitude; double z = sqrt (x * x + y * y) + 0.00002 * sin (y * x_pi); double theta = atan2 (y, x) + 0.000003 * cos (x * x_pi); double bd_lon = z * cos (theta) + 0.0065; double bd_lat = z * sin (theta) + 0.006; return CLLocationCoordinate2DMake(bd_lat, bd_lon); } // BD-09 坐标转换成 GCJ-02 坐标 + (CLLocationCoordinate2D)BaiduGS2MarsGS:(CLLocationCoordinate2D)coordinate { double x_pi = PI * 3000.0 / 180.0; double x = coordinate.longitude - 0.0065, y = coordinate.latitude - 0.006; double z = sqrt (x * x + y * y) - 0.00002 * sin (y * x_pi); double theta = atan2 (y, x) - 0.000003 * cos (x * x_pi); double gg_lon = z * cos (theta); double gg_lat = z * sin (theta); return CLLocationCoordinate2DMake(gg_lat, gg_lon); } |
2WGS-84(地球坐标系)和BD-09(百度坐标)转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// WGS-84 坐标转换成 BD-09 坐标 + (CLLocationCoordinate2D)WorldGS2BaiduGS:(CLLocationCoordinate2D)coordinate { CLLocationCoordinate2D mars = [ALDGeocoder WorldGS2MarsGS:coordinate]; CLLocationCoordinate2D baidu = [ALDGeocoder MarsGS2BaiduGS:mars]; return baidu; } // BD-09 坐标转换成 WGS-84 坐标 + (CLLocationCoordinate2D)BaiduGS2WorldGS:(CLLocationCoordinate2D)coordinate { CLLocationCoordinate2D mars = [ALDGeocoder BaiduGS2MarsGS:coordinate]; CLLocationCoordinate2D world = [ALDGeocoder MarsGS2WorldGS:mars]; return world; } |
3.WGS-84和sogou坐标转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
// WGS-84 坐标转换成 Sogou 坐标 + (CLLocationCoordinate2D)WorldGS2SogouGS:(CLLocationCoordinate2D)coordinate { const double ee = 0.082271854224939184; double lon = coordinate.longitude; double lat = coordinate.latitude; double dlon = [ALDGeocoder rad:CLIP(lon, -360, 360)]; double dlat = [ALDGeocoder rad:CLIP(lat, -90, 90)]; dlon = 6378206.4 * dlon; double sinphi = sin (dlat); double temp1, temp2; if ((temp1 = 1.0 + sinphi) == 0.0){ dlat = -1000000000; } else if ((temp2 = 1.0 - sinphi) == 0.0){ dlat = 1000000000; } else { double esinphi = ee * sinphi; dlat = 3189103.2000000002 * log ((temp1 / temp2) * pow ((1.0 - esinphi) / (1.0 + esinphi), ee)); } return CLLocationCoordinate2DMake(dlat, dlon); } // Sogou 坐标转换成 WGS-84 坐标 + (CLLocationCoordinate2D)SogouGS2WorldGS:(CLLocationCoordinate2D)coordinate { const double ee = 1.5707963267948966; const double aa = 0.0033938814110493522; double lon = coordinate.longitude; double lat = coordinate.latitude; double dlon = lon / 6378206.4; double temp = -lat / 6378206.4; double chi; if (temp < -307){ chi = ee; } else if (temp > 308){ chi = -ee; } else { chi = ee - 2 * atan ( exp (temp)); } double chi2 = 2 * chi; double coschi2 = cos (chi2); double dlat = chi + sin (chi2) * (aa + coschi2 * (1.3437644537757259E-005 + coschi2 * (7.2964865099246009E-008 + coschi2 * 4.4551470401894685E-010))); double rlon = CLIP([ALDGeocoder deg:dlon], -360, 360); double rlat = CLIP([ALDGeocoder deg:dlat], -90, 90); return CLLocationCoordinate2DMake(rlat, rlon); } |
4火星坐标和地球坐标转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
// World Geodetic System ==> Mars Geodetic System + (CLLocationCoordinate2D)WorldGS2MarsGS:(CLLocationCoordinate2D)coordinate { // a = 6378245.0, 1/f = 298.3 // b = a * (1 - f) // ee = (a^2 - b^2) / a^2; const double a = 6378245.0; const double ee = 0.00669342162296594323; if (outOfChina(coordinate.latitude, coordinate.longitude)) { return coordinate; } double wgLat = coordinate.latitude; double wgLon = coordinate.longitude; double dLat = transformLat(wgLon - 105.0, wgLat - 35.0); double dLon = transformLon(wgLon - 105.0, wgLat - 35.0); double radLat = wgLat / 180.0 * PI; double magic = sin (radLat); magic = 1 - ee * magic * magic; double sqrtMagic = sqrt (magic); dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI); dLon = (dLon * 180.0) / (a / sqrtMagic * cos (radLat) * PI); return CLLocationCoordinate2DMake(wgLat + dLat, wgLon + dLon); } // Mars Geodetic System ==> World Geodetic System + (CLLocationCoordinate2D)MarsGS2WorldGS:(CLLocationCoordinate2D)coordinate { double gLat = coordinate.latitude; double gLon = coordinate.longitude; CLLocationCoordinate2D marsCoor = [ALDGeocoder WorldGS2MarsGS:coordinate]; double dLat = marsCoor.latitude - gLat; double dLon = marsCoor.longitude - gLon; return CLLocationCoordinate2DMake(gLat - dLat, gLon - dLon); } |
5WGS-84 和 墨卡托 坐标转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//WGS-84 坐标转换成 墨卡托 坐标 + (CLLocationCoordinate2D)WorldGS2Mercator:(CLLocationCoordinate2D)coordinate { double lon = coordinate.longitude*20037508.34/180; double lat = log ( tan ((90+coordinate.latitude)*M_PI/360))/(M_PI/180); lat = lat*20037508.34/180; return CLLocationCoordinate2DMake(lat, lon); } //墨卡托 坐标转换成 WGS-84 坐标 + (CLLocationCoordinate2D)Mercator2WorldGS:(CLLocationCoordinate2D)mercator { double lon = mercator.longitude/20037508.34*180; double lat = mercator.latitude/20037508.34*180; lat = 180/M_PI*(2* atan ( exp (lat*M_PI/180))-M_PI/2); return CLLocationCoordinate2DMake(lat, lon); } |
开发时所面临的现状
获取经纬度(GPS)
火星坐标
MKMapView
地球坐标
CLLocationManager
显示经纬度(地图)
火星坐标
iOS 地图
Gogole地图
搜搜、阿里云、高德地图
地球坐标
Google 卫星地图(国外地图应该都是……)
百度坐标
百度地图
推荐的解决方案:
既然是在国内,存储一律用火星坐标,这样在使用国内地图显示时最方便(用百度地图显示时可以一次转换取得)
CLLocationManager 拿到的 CLLocation 转为火星坐标,MKMapView 不用处理
使用地图 API 进行 地址解析/逆地址解析(Geocoding) 时注意相应使用相应地图商的坐标系
部分地图商支持多个坐标系输入,如高德支持地球、火星坐标(这个一直有变动,具体只能参考厂商最新文档了
引用地址:iOS地图定位纠偏1
iOS自带地图纠偏问题的更多相关文章
- ios开发中如何调用苹果自带地图导航
前段时间一直在赶项目,在外包公司工作就是命苦,天天加班不说,工作都是和工期合同挂钩的,稍微逾期就有可能被扣奖金,不谈这些伤脑筋的事情了,让我们说说iOS开发中如何调用苹果手机自带的地图. 学习如逆水行 ...
- iOS开发系列--地图与定位
概览 现在很多社交.电商.团购应用都引入了地图和定位功能,似乎地图功能不再是地图应用和导航应用所特有的.的确,有了地图和定位功能确实让我们的生活更加丰富多彩,极大的改变了我们的生活方式.例如你到了一个 ...
- iOS开发----调用地图导航
注意:本文章下的代码有个别变量未知,所以是不能直接跑通的,我也是转别人的 在IOS6.0系统后,兼容iOS5.0与iOS6.0地图导航,需要分两个步骤 #define SYSTEM_VERSION_L ...
- iOS中的地图和定位
文章摘自http://www.cnblogs.com/kenshincui/p/4125570.html#location 如有侵权,请联系删除. 概览 现在很多社交.电商.团购应用都引入了地图和定 ...
- 转-iOS开发系列--地图与定位
来自: http://www.cnblogs.com/kenshincui/p/4125570.html#autoid-3-4-0 概览 现在很多社交.电商.团购应用都引入了地图和定位功能,似乎地图功 ...
- iOS进阶_地图上定位的标志——大头针
一.添加大头针 地图使用的框架是MapKit 大头针走的是MKAnnotation协议 /* 注意:因为是满足协议MKAnnotation,所以没有MKAnnotation的系统大头针类,必须自定义大 ...
- iOS进阶_地图定位
一.定位步骤 1.Xcode自带地图,直接先引入头文件 #import <CoreLocation/CoreLocation.h> 2.CLLocation框架中的CLLocationMa ...
- iOS定位 (一) 地图定位
带地图的定位方法#import <CoreLocation/CoreLocation.h> #import <MapKit/MapKit.h> <MKMapViewDel ...
- iOS开发中地图开发的简单应用
iOS上使用地图比Android要方便,只需要新建一个MKMapView,addSubView即可.这次要实现的效果如下: 有标注(大头针),定位,地图. 1.添加地图 1.1 新一个Single V ...
随机推荐
- js的基本数据类型有哪些?
js的基本数据类型有哪些? ECMAScript中有5中简单数据类型(也称为基本数据类型): Undefined.Null.Boolean.Number和String.还有1中复杂的数据类型----O ...
- 一台电脑存放多个git账户的多个rsa秘钥
未命名.html div.oembedall-githubrepos{border:1px solid #DDD;border-radius:4px;list-style-type:none;marg ...
- DevExpress.XtraGrid.Views 设置指定行的背景颜色 .
如需要将指定行的背景设置颜色,可参考以下示例 1.事件:CustomDrawCell 2.示例: private void gridView1_CustomDrawCell(object sender ...
- Mybatis学习记录(六)----Mybatis的高级映射
1.一对多查询 1.1 需求 查询订单及订单明细的信息. 1.2 sql语句 确定主查询表:订单表 确定关联查询表:订单明细表 在一对一查询基础上添加订单明细表关联即可. SELECT orders. ...
- JAVA基础学习day20--IO流二-缓冲流、字节流
一.缓冲流 1.1.字符流的缓冲区 缓冲区的出现是为了提高IO的读写效率 对应类 BufferedReader BufferedWriter 缓冲区要结合流才可以使用 在流的基础上对流的功能进行了增强 ...
- [android] 手机卫士自定义控件的属性
上一节完成的自定义组合控件,灵活性不够,控件的显示信息上,仿照系统属性,自定义自己的属性 上一节组合控件SettingItemView中有三个控件,分别是TextView大标题,TextView描述, ...
- iOS 自定义Actionsheet
自定义的Actionsheet效果如下 自定义的思路 1.在window上添加两个图层,背景层和功能层,如下图 2.设置背景层的背景色和透明度,并在背景层上添加点击事件 3.将自定义的view添加为功 ...
- win7操作技巧
Q : 打开文件夹默认最大化A :随便打开一个文件夹 鼠标移动到左上角 然后点击鼠标左键 选择“最大化” 后关闭 之后每次打开就是最大化了
- 原生JS获取各种高度宽度、浏览器窗口滚动条的位置、元素的几何尺寸名
1)关于 pageX, clienX,offsetX,layerX pageX:鼠标在页面上的位置,从页面左上角开始,即是以页面为参考点,不随滑动条移动而变化 clientX:鼠标在页面上可视区域的位 ...
- CentOS6.5下RPM方式安装mysql5.6.33
1.mysql下载 下载地址:https://dev.mysql.com/downloads/mysql/5.6.html下载以下安装包: MySQL-client-5.6.33-1.el6.x86_ ...