转自:http://xcodev.com/131.html
在做iOS开发时,用到一个获取当前位置周边商家的功能。当时每次我在获取从iPhone里GPS返回过来的数据到Google Place API上获取时总是发现,获取的商家并不是最近的,而是几百米以外的。经多次尝试,确实是这样。我在网上搜索一下,发现原来是相关部门和谐掉了。相关部门规定:为了保证国家安全,所有的地图公司提供的地图必须对实际的GPS坐标进行一定的偏移,偏移后的GPS坐标系俗称火星坐标系,而这个偏移是不固定的,具体的算法是国家机密。悲催了,在网上找了很久,终于找到了一个解决方案:网上已经有人根据Google的相关接口,每隔0.1个经纬度获取一个地图偏移像素,把中国区的所有经纬度都转换了,组成一个数据文件。此数据文件是一个连续的结构数组:
1
2
3
4
5
6
|
typedef
struct
offset_data
{ int16_t
lng ;
//12151表示121.51 int16_t
lat ;
//3130表示31.30 int16_t
x_off ;
//地图x轴偏移像素值 int16_t
y_off ;
//地图y轴偏移像素值 } offset_data ; |
然而这个偏移量是地图图片偏移的像素值,而我们需要的是实际上偏移的经纬度。这就需要一个把经纬度转换成地图xy轴坐标的算法:
1
2
3
4
5
6
7
8
|
static
double
lngToPixel( double
lng, int
zoom) { return
(lng + 180) * (256L << zoom) / 360; } static
double
latToPixel( double
lat, int
zoom) { double
siny = sin (lat
* M_PI / 180); double
y = log ((1
+ siny) / (1 - siny)); return
(128 << zoom) * (1 - y / (2 * M_PI)); } |
然后把这个地图xy轴坐标加上对应的地图xy轴的偏移量,最后还要反过来将最终正确的地图xy轴坐标转换成正确的经纬度:
1
2
3
4
5
|
static double pixelToLng( double pixelX, int zoom)
{ return pixelX
* 360 / (256L << zoom) - 180; } static double pixelToLat( double pixelY, int zoom)
{ double y
= 2 * M_PI * (1 - pixelY / (128 << zoom)); double z
= pow (M_E,
y); double siny
= (z - 1) / (z + 1); return asin (siny)
* 180 / M_PI; } |
我写了WGS2Mars方法,他的参数是经度和维度的地址,同时将转换好的经纬度传递回来。由于数据库的结构完全是按照顺序的,所以我用了c标准库的折半查找算法,你需要包含一下<stdlib.h>这个头文件。
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
|
static
int
compare_offset_data(offset_data *data1, offset_data *data2){ int
det_lng = (data1->lng)-(data2->lng); if
(det_lng!=0) { return
det_lng; } else { return
(data1->lat)-(data2->lat); } } void
WGS2Mars( double
*lat, double
*lng){ //NSData
*offsetFileData = [NSData dataWithContentsOfFile:@"offset.dat"]; //推荐使用文件-内存映射模式,减少内存消耗。 NSData
*offsetFileData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@ "offset"
ofType:@ "dat" ]
options:NSDataReadingMappedIfSafe error:NULL]; const
void
*buf = [offsetFileData bytes]; //byte
buf for content of file "offset.dat" long
long
buflen = [offsetFileData length]; //length
of byte buf for content of file "offset.dat" offset_data
search_data; search_data.lat
= ( int )(*lat*100); search_data.lng
= ( int )(*lng*100); offset_data
*ret = bsearch (&search_data,
buf, buflen/ sizeof (offset_data),
sizeof (offset_data),
( int
(*)( const
void
*, const
void
*))compare_offset_data); //折半查找 double
pixY = latToPixel(*lat, 18); double
pixX = lngToPixel(*lng, 18); pixY
+= ret->y_off; pixX
+= ret->x_off; *lat
= pixelToLat(pixY, 18); *lng
= pixelToLng(pixX, 18); } |