2020-06-11关于WGS84 高德坐标 百度坐标的相互转换

在地图学中,一般将坐标分为投影坐标和地理坐标。地理坐标和投影坐标的联系和区别对于一般的地图使用者而言可能并不需要掌握的非常清楚。通俗一点来说,地理坐标是一个球体的坐标,而投影坐标是一个平面的坐标。常用的GPS、百度地图、高德地图等都是采用的地理坐标。
确定了地理坐标之后,常见的地图应用分别采用的都是什么坐标系呢?一般来说,国外的一些地图,都是采用WGS84坐标系,比如谷歌地图、OMS地图、Bing地图(非中国区域)等。而国内的地图,处于保密需求,大多采用火星坐标系,在WGS84的基础上作了一些偏移,如高德地图、腾讯地图等。而百度又在火星坐标系的基础上又作了一定偏移,生成了自己的百度坐标系。

WGS84:谷歌地图 OMS
火星坐标系:高德地图 腾讯地图
百度坐标系:百度地图

这些加密算法,一般是无法准确还原的,但是在小范围内的数据,可以通过一定的变换相互转化。具体的C#代码如下

 public struct Cor
    {
        public double lng;
        public double lat;
    }
    public class Transformer
    {
        const double x_pi = 3.14159265358979324 * 3000.0 / 180.0;
        const double pi = 3.1415926535897932384626; // π
        const double a = 6378245.0;// 长半轴
        const double ee = 0.00669342162296594323; // 扁率

        //火星转百度
        public static Cor gcj02tobd09(Cor HxCor)
        {
            double z = Math.Sqrt(HxCor.lng * HxCor.lng + HxCor.lat * HxCor.lat) + 0.00002 * Math.Sin(HxCor.lat * x_pi);
            double theta = Math.Atan2(HxCor.lat, HxCor.lng) + 0.000003 * Math.Cos(HxCor.lng * x_pi);
            Cor BaiduCor;
            BaiduCor.lng = z * Math.Cos(theta) + 0.0065;
            BaiduCor.lat = z * Math.Sin(theta) + 0.006;
            return BaiduCor;
        }

        //百度转火星
        public static Cor bd09togcj02(Cor Bd)
        {
            double x = Bd.lng - 0.0065;
            double y = Bd.lat - 0.006;
            double z = Math.Sqrt(x * x + y * y) - 0.00002 * Math.Sin(y * x_pi);
            double theta = Math.Atan2(y, x) - .000003 * Math.Cos(x * x_pi);
            Cor hx;
            hx.lng = z * Math.Cos(theta);
            hx.lat = z * Math.Sin(theta);
            return hx;
        }

        //WGS84转火星
        public static Cor wgs84togcj02(Cor wgs84)
        {
            if (OutOfChina(wgs84))
            {
                return wgs84;
            }
            double dlat = transformlat(wgs84.lng - 105.0, wgs84.lat - 35.0);
            double dlng = transformlng(wgs84.lng - 105.0, wgs84.lat - 35.0);
            double radlat = wgs84.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);
            dlng = (dlng * 180.0) / (a / sqrtmagic * Math.Cos(radlat) * pi);
            Cor hx;
            hx.lat = wgs84.lat + dlat;
            hx.lng = wgs84.lng + dlng;
            return hx;
        }


        //火星转84
        public static Cor gcj02towgs84(Cor hx)
        {
            if (OutOfChina(hx))
            {
                return hx;
            }
            double dlat = transformlat(hx.lng - 105.0, hx.lat - 35.0);
            double dlng = transformlng(hx.lng - 105.0, hx.lat - 35.0);
            double radlat = hx.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);
            dlng = (dlng * 180.0) / (a / sqrtmagic * Math.Cos(radlat) * pi);
            Cor wgs84;
            double mglat = hx.lat + dlat;
            double mglng = hx.lng + dlng;
            wgs84.lat = hx.lat * 2 -mglat;
            wgs84.lng = hx.lng *2-mglng;
            return wgs84;
        }
        
        //百度转84
        public static Cor bd09towgs84(Cor bd)
        {
            Cor hx = bd09togcj02(bd);
            Cor wgs84 = gcj02towgs84(hx);
            return wgs84;
        }

        //84转百度
        public static Cor wgs84tobd09(Cor wgs84)
        {
            Cor hx = wgs84togcj02(wgs84);
            Cor bd = gcj02tobd09(hx);
            return bd;
        }
        /*辅助函数*/
        //判断是否在国内
        private static Boolean OutOfChina(Cor wgs84)
        {
            if (wgs84.lng < 72.004 || wgs84.lng > 137.8347)
            {
                return true;
            }
            if (wgs84.lat < 0.8293 || wgs84.lat > 55.8271)
            {
                return true;
            }
            return false;
        }

        /*辅助函数*/
        //转换lat
        private static double transformlat(double lng, double lat)
        {
            double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat +
        0.1 * lng * lat + 0.2 * Math.Sqrt(Math.Abs(lng));
    ret += (20.0 * Math.Sin(6.0 * lng * pi) + 20.0 *
            Math.Sin(2.0 * lng * pi)) * 2.0 / 3.0;
    ret += (20.0 * Math.Sin(lat * pi) + 40.0 *
            Math.Sin(lat / 3.0 * pi)) * 2.0 / 3.0;
    ret += (160.0 * Math.Sin(lat / 12.0 * pi) + 320 *
            Math.Sin(lat * pi / 30.0)) * 2.0 / 3.0;
            return ret;
        }

        /*辅助函数*/
        //转换lng
        private static double transformlng(double lng, double lat)
        {
            double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng +
        0.1 * lng * lat + 0.1 * Math.Sqrt(Math.Abs(lng));
            ret += (20.0 * Math.Sin(6.0 * lng * pi) + 20.0 *
                    Math.Sin(2.0 * lng * pi)) * 2.0 / 3.0;
            ret += (20.0 * Math.Sin(lng * pi) + 40.0 *
                    Math.Sin(lng / 3.0 * pi)) * 2.0 / 3.0;
            ret += (150.0 * Math.Sin(lng / 12.0 * pi) + 300.0 *
                    Math.Sin(lng / 30.0 * pi)) * 2.0 / 3.0;
            return ret;
        }

        // 按类计算
        public static   Cor transform(Cor corOld,string transType)
        {
            switch (transType)
            {
                case "百度转火星":   
                        return Transformer.bd09togcj02(corOld);
                case "百度转84":
                        return Transformer.bd09towgs84(corOld);
                case "火星转84":    
                        return Transformer.gcj02towgs84(corOld);
                case "84转火星":
                        return Transformer.wgs84togcj02(corOld);
                case "火星转百度":
                        return Transformer.gcj02tobd09(corOld);
                case "84转百度":
                        return Transformer.wgs84tobd09(corOld);
                default:
                    return corOld;
            }
            
        }
    }

完整可编译的源码在https://github.com/njupt-shao/coordinate-transformation
示例程序下载链接:https://pan.baidu.com/s/1bAkJK_-ra96eG_70DRnudw
提取码:cbr5

单个转换

文件转换

CSV文件格式,一行一个坐标,半角逗号隔开经纬度

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351