在这个神奇的国度里,我们总得学习一些有中国特色的东东,例如“火星坐标”。也许有人还不知道这是什么玩意,我就简要介绍一下吧。      如果你有带GPS模块的智能手机,打开定位功能,然后访问Google地图。只要你身处中国大陆,你就会发现定位不准,大概有几百米的偏差。然而运行一些导航软件,你又会发现定位很准确,说明手机的GPS模块确实是正常的。

     这种现象是怎么造成的呢?答案是人为造成的。简单来说,GPS模块获取到的坐标是WGS84坐标系的,中国政府出于种种目的的考虑,不允许中国的地图使用国际通用的WGS84坐标系,而非要加上一些偏移,这样的坐标系就俗称“火星坐标系”。而Google地图采用的也是加偏移过的火星坐标系,但GPS模块传给它的坐标却没有加偏移,于是就出现几百米的偏差了。这样的后果就是没法做需要很高精度的地理位置的应用了,就像那个悲剧的Google地图一样,你迷路时无法指望它告诉你正确的位置。

     经过不懈的努力, 终于发现一位牛人用C语言写了一个算法, 不过他要用到一个数据文件, 而且比较大, 放在手机客户端一跑就内存崩溃了, 所以觉得不可取, 于是把他的C代码转化为C#的WebService服务. 代码如下, 供大家参考.希望对大家有所帮助!

 

C#代码

 

1. class Program  
2. {  
3. const double M_PI = 3.14159265358979323846264338327950288;  
4. const double M_E = 2.71828182845904523536028747135266250;  
5.   
6. public class MapCoord  
7. {  
8. public int lng { set; get; }    //12151表示121.51  
9. public int lat { set; get; }    //3130表示31.30  
10. public int x_off { set; get; }  //地图x轴偏移像素值  
11. public int y_off { set; get; }  //地图y轴偏移像素值  
12. }  
13.   
14. /// <summary>  
15. /// 自定义比较类  
16. /// </summary>  
17. public class myReverserClass : IComparer  
18. {  
19. public int Compare(object x, object y)  
20.     {  
21.         MapCoord data1 = (MapCoord)x, data2 = (MapCoord)y;  
22. int det_lng = data1.lng - data2.lng;  
23. if (det_lng != 0)  
24. return det_lng;  
25. else  
26. return data1.lat - data2.lat;  
27.     }  
28. }  
29.   
30. //这就需要一个把经纬度转换成地图xy轴坐标的算法:  
31.   
32. private static double lngToPixel(double lng, int zoom)  
33. {  
34. return (lng + 180) * (256L << zoom) / 360;  
35. }  
36.   
37. private static double latToPixel(double lat, int zoom)  
38. {  
39. double siny = Math.Sin(lat * M_PI / 180);  
40. double y = Math.Log((1 + siny) / (1 - siny));  
41. return (128 << zoom) * (1 - y / (2 * M_PI));  
42. }  
43.   
44.   
45. //xy轴坐标加上对应的地图xy轴的偏移量,最后还要反过来将最终正确的地图xy轴坐标转换成正确的经纬度  
46. private static double pixelToLng(double pixelX, int zoom)  
47. {  
48. return pixelX * 360 / (256L << zoom) - 180;  
49. }  
50.   
51. private static double pixelToLat(double pixelY, int zoom)  
52. {  
53. double y = 2 * M_PI * (1 - pixelY / (128 << zoom));  
54. double z = Math.Pow(M_E, y);  
55. double siny = (z - 1) / (z + 1);  
56. return Math.Asin(siny) * 180 / M_PI;  
57. }  
58.   
59. /// <summary>  
60. /// 将字节转化为具体的数据对象  
61. /// </summary>  
62. /// <param name="buf"></param>  
63. /// <returns></returns>  
64. private static MapCoord getMapCoordFromBytes(byte[] buf)  
65. {  
66. //数据文档结构是八字节为一个坐标及其偏移量,分别为经度,纬度,x偏移量,y偏移量; 每两字节为一个数据  
67. new MapCoord();  
68. byte[] b1 = new byte[2], b2 = new byte[2], b3 = new byte[2], b4 = new byte[2];  
69.     Array.Copy(buf, 0, b1, 0, 2);  
70.     Array.Copy(buf, 2, b2, 0, 2);  
71.     Array.Copy(buf, 4, b3, 0, 2);  
72.     Array.Copy(buf, 6, b4, 0, 2);  
73.     coord.lng = System.BitConverter.ToInt16(b1, 0);  
74.     coord.lat = System.BitConverter.ToInt16(b2, 0);  
75.     coord.x_off = System.BitConverter.ToInt16(b3, 0);  
76.     coord.y_off = System.BitConverter.ToInt16(b4, 0);  
77. return coord;  
78. }  
79.   
80. /// <summary>  
81. /// WGS84(GPS)坐标转火星坐标  
82. /// </summary>  
83. /// <param name="lat">纬度</param>  
84. /// <param name="lng">经度</param>  
85. public static void WGS2Mars(double lat, double lng)  
86. {  
87. //读取数据文件  
88. //这里读取文件的地方可以单独提出来, 读一次之后保存到内存里, 读取时比较耗时间. 或者放到数据库中去.  
89. new FileStream("offset.dat", FileMode.OpenOrCreate, FileAccess.Read);  
90. new BinaryReader(fs);  
91. int size = (int)fs.Length / 8;  
92. new ArrayList();  
93. for (int i = 0; i < size; i ++)  
94.     {  
95. //按八个字节八个字节来读取, 放在MapCoord对象中,并添加到ArrayList中  
96. byte[] source = br.ReadBytes(8);  
97.         array.Add(getMapCoordFromBytes(source));  
98.     }  
99.     br.Close();  
100.     fs.Close();  
101. //将要查找的坐标放置在MapCoord对象中  
102. new MapCoord();  
103. int)(lat * 100);  
104. int)(lng * 100);  
105.   
106. new myReverserClass();  
107. //执行查找, 查询结果将返回array中的索引值  
108. int x = array.BinarySearch(0, array.Count, search, rc);  
109. //取得查找到的结果并进行计算  
110.     MapCoord ret = (MapCoord)array[x];  
111. double pixY = latToPixel(lat, 18);  
112. double pixX = lngToPixel(lng, 18);  
113.   
114.     pixY += ret.y_off;  
115.     pixX += ret.x_off;  
116.     lat = pixelToLat(pixY, 18);  
117.     lng = pixelToLng(pixX, 18);  
118. //输出校正后的结果  
119. "欢迎来到火星,坐标: lat:{0},lng:{1} !!!", lat, lng);  
120. }  
121.   
122. static void Main(string[] args)  
123. {  
124. //测试一下  
125.     WGS2Mars(30.283780,120.116356);  
126.     Console.ReadLine();  
127. }  
128.   
129.  }

 

OK,大功告成,火星人民欢迎您!!