地图坐标转换 -- 火星坐标与GPS坐标

第一次处理地理位置的数据的人,没什么经验,往往掉入很多坑浪费不少时间。我也是刚刚从坑里爬出来。这篇博文主要是把入门GPS轨迹分析的经验总结一下,以方便大家少走些弯路。

(1)可视化 GPS 路径

刚拿到一堆GPS轨迹数据,想看看它长什么样?于是先想办法把它们可视化出来。有很多地图的API可以用,如果不是想搞演示,只是为了快速随便看一眼的话,推荐用百度的在线示例API  http://developer.baidu.com/map/jsdemo.htm#c1_3  里面有比较详细的例子,很丰富的操作,修改代码也比较简单。 当然也可以把源代码copy下来在本地操作。

(2) 坐标格式

一般从GPS得到的数据是经纬度。经纬度有多种表示方法。
  1.) ddd.ddddd, 度 . 度的十进制小数部分(5位)例如:31.12035º
  2.) ddd.mm.mmm,度 . 分 . 分的十进制小数部分(3位)例如 31º10.335'
  3.)   ddd.mm.ss, 度 . 分 . 秒 例如 31º12'42"

在应用程序中基本都用格式1),所以首先要确定你的原始数据格式是否是格式1),如果不是,需要转换,方法比较简单。 一个从2)转换成1)的程序如下:

复制代码
public Point(double longitude, double latitude )
        {           
            int degree = (int)(longitude);
            this.longitude = (longitude - degree) * 100 / 60 + degree;

            degree = (int)(latitude);
            this.latitude = (latitude - degree) *100 / 60 + degree;

        }
复制代码

(3)坐标纠偏

刚拿到GPS轨迹数据的时候,直接print到地图上,发现路线比较奇怪,没有和道路完全吻合,很像偏移了一些,甚至会穿越没有道路的地方。 起初以为是GPS精度的问题。后来经人提醒,GPS坐标是有好几套标准的。 有兴趣的同学可以阅读更多资料例如 http://yanue.net/post-121.html , 这里简单的说明什么是坐标偏移:

天朝为了保卫国家安全,对真实坐标系统进行人为的加偏处理,把真实的坐标加密成虚假的坐标,称为火星坐标。这种偏移是非线性的,偏移方向也不确定。  除了火星坐标系统,不同的地图数据商也可能使用自己的坐标系统,例如百度。 国内各地图API坐标系统比较详情请见http://www.cnblogs.com/Tangf/archive/2012/03/15/2398397.html 。  所以天朝所有准许上市的地图类产品都不是真实坐标系统。要想在某个地图API上正确的显示GPS轨迹,必须要先把数据转换成它的坐标系统。

这里还是以百度地图为例。假如我有原始(真实的)GPS数据,要在百度地图上正确显示,就需要先变成百度坐标系。 坐标转换的API说明在 http://lbsyun.baidu.com/index.php?title=webapi/guide/changeposition  可以看到,这个API支持从很多种不同的坐标系统转换到百度坐标系(但是不支持转换到百度坐标系以外的模式,吐槽一下)。 自己写个程序批量地转换,速度有点慢,一次只能发10个点左右。  在线演示在http://developer.baidu.com/map/jsdemo.htm#c1_3 

把其中的坐标改成你自己的数据,再找到这行代码:

convertor.translate(pointArr, 3, 5, translateCallback)

其中的3,5表示从火星坐标转换到百度坐标; 如果改成1 , 5 则是从原始坐标转换到百度坐标,点击运行。

在我自己的数据上的效果如下:

很明显经过处理之后,路径才是正确的。

另外,高德地图采用的是火星坐标,也可以玩玩 http://lbs.amap.com/api/javascript-api/example/marker/marker-content/

原始坐标和火星坐标是可以相互转换的,需要一个小型辅助数据库,这里就不贴代码了,如有需要请留言。

这里附上百度坐标和火星坐标的c#转换代码:

复制代码
        public static Point Baidu2Mars(Point a)
        {
            Point b = new Point();
            double x = a.longitude - 0.0065;
            double y= a.latitude - 0.006;

            double z = Math.Sqrt(x * x + y * y) - 0.00002 * Math.Sin(y * Math.PI / 180);
            double theta = Math.Atan2(y, x) - 0.000003 * Math.Cos(x * Math.PI / 180);

            b.longitude = z * Math.Cos(theta);
            b.latitude = z * Math.Sin(theta);
            return b;
        }

        public static Point Mars2Baidu(Point a){
            Point b = new Point();
            double x = a.longitude;
            double y= a.latitude;

            double z = Math.Sqrt(x * x + y * y) + 0.00002 * Math.Sin(y * Math.PI / 180);
            double theta = Math.Atan2(y, x) + 0.000003 * Math.Cos(x * Math.PI / 180);

            b.longitude = z * Math.Cos(theta) + 0.0065;
            b.latitude = z * Math.Sin(theta) + 0.006;
            return b;
        }
复制代码

最后顺便贴一个求两个GPS点间距离的代码:

复制代码
        public static double Degree2Radian(double degree)
        {
            double radian = degree * Math.PI / 180;
            return radian;
        }

        //http://www.movable-type.co.uk/scripts/latlong.html
        public static double Distance(Point a, Point b)
        {
            double R = 6371000;

            double phi1 = Degree2Radian(a.latitude);
            double phi2 = Degree2Radian(b.latitude);

            double deltaPhi = Degree2Radian(a.latitude - b.latitude);
            double deltaLam = Degree2Radian(a.longitude - b.longitude);

            double aa = Math.Sin(deltaPhi / 2) * Math.Sin(deltaPhi / 2) + Math.Cos(phi1) * Math.Cos(phi2) * Math.Sin(deltaLam / 2) * Math.Sin(deltaLam / 2);

            double c = 2 * Math.Atan2(Math.Sqrt(aa), Math.Sqrt(1 - aa));

            double d = R * c;

            return d;
        }
复制代码

package com.map; public class GPSConverterUtils { public static final String BAIDU_LBS_TYPE = "bd09ll"; public static double pi = 3.1415926535897932384626; public static double a = 6378245.0; public static double ee = 0.00669342162296594323; /** * 84 to 火星坐标系 (GCJ-02) World Geodetic System ==> Mars Geodetic System * 天地图火星 * @param lat * @param lon */ public static GPS gps84_To_Gcj02(double lat, double lon) { if (outOfChina(lat, lon)) { return null; } double dLat = transformLat(lon - 105.0, lat - 35.0); double dLon = transformLon(lon - 105.0, lat - 35.0); double radLat = lat / 180.0 * pi; double magic = Math.sin(radLat); magic = 1 - ee * magic * magic; double sqrtMagic = Math.sqrt(magic); dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); double mgLat = lat + dLat; double mgLon = lon + dLon; return new GPS(mgLat, mgLon); } /** * * 火星坐标系 (GCJ-02) to 84 * * @param lon * @param lat * @return *火星转天地图 */ public static GPS gcj_To_Gps84(double lat, double lon) { GPS gps = transform(lat, lon); double lontitude = lon * 2 - gps.getLon(); double latitude = lat * 2 - gps.getLat(); return new GPS(latitude, lontitude); } /** * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标 *火星转百度 * @param gg_lat * @param gg_lon */ public static GPS gcj02_To_Bd09(double gg_lat, double gg_lon) { double x = gg_lon, y = gg_lat; double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * pi); double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * pi); double bd_lon = z * Math.cos(theta) + 0.0065; double bd_lat = z * Math.sin(theta) + 0.006;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值