坐标转换——GCJ-02

WGS84(World Geodetic System 1984),是为GPS 全球定位系统 使用而建立的坐标系统
GCJ-02,我国在WGS84的基础上加密得到
BD-09,百度坐标在GCJ-02基础上,进行了BD-09二次加密
火星坐标与百度坐标(GCJ-02----BD-09)转换
国际经纬度坐标标准为WGS-84,国内必须至少使用国测局制定的GCJ-02,对地理位置进行首次加密。
百度坐标在此基础上,进行了BD-09二次加密措施,更加保护了个人隐私。
百度对外接口的坐标系并不是GPS采集的真实经纬度,需要通过坐标转换接口进行转换。

百度坐标与火星坐标的相互转换:

        public class Coor
        {
            const double x_pi = 3.14159265358979324 * 3000.0 / 180.0;//定义常量
            /// <summary>
            /// 将 GCJ-02 坐标转换成 BD-09 坐标
            /// </summary>
            /// <param name="gg_lat">火星X坐标</param>
            /// <param name="gg_lon">火星Y坐标</param>
            /// <param name="XX">百度X坐标</param>
            /// <param name="YY">百度Y坐标</param>
            public void bd_encrypt(double gg_lat, double gg_lon, out double XX, out double YY)
            {
                double x = gg_lon, y = gg_lat;
                double z = Math.Sqrt(x * x + y * y) + 0.00002 * Math.Sin(y * x_pi);
                double theta = Math.Atan2(y, x) + 0.000003 * Math.Cos(x * x_pi);
                XX = z * Math.Cos(theta) + 0.0065;
                YY = z * Math.Sin(theta) + 0.006;
            }
            /// <summary>
            /// 将 BD-09 坐标转换成  GCJ-02坐标
            /// </summary>
            /// <param name="bd_lat">百度X坐标</param>
            /// <param name="bd_lon">百度Y坐标</param>
            /// <param name="XX">火星X坐标</param>
            /// <param name="YY">火星Y坐标</param>
            public void bd_decrypt(double bd_lat, double bd_lon, out double XX, out double YY)
            {
                double x = bd_lon - 0.0065, 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) - 0.000003 * Math.Cos(x * x_pi);
                XX = z * Math.Cos(theta);
                YY = z * Math.Sin(theta);
            }
        }

火星坐标到WGS-84的转换:

        //GCJ-02 到 WGS-84 的转换(即 GPS 纠偏)
        public class EvilTransform
        {
            const double pi = 3.14159265358979324;
            const double a = 6378245.0;
            const double ee = 0.00669342162296594323;
            public void transform(double wgLat, double wgLon, out double mgLat, out double mgLon)
            {
                if (outOfChina(wgLat, wgLon))
                {
                    mgLat = wgLat;
                    mgLon = wgLon;
                    return;
                }
                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 = 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);
                mgLat = wgLat + dLat;
                mgLon = wgLon + dLon;
            }

            static bool outOfChina(double lat, double lon)
            {
                if (lon < 72.004 || lon > 137.8347)
                    return true;
                if (lat < 0.8293 || lat > 55.8271)
                    return true;
                return false;
            }

            static double transformLat(double x, double y)
            {
                double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.Sqrt(Math.Abs(x));
                ret += (20.0 * Math.Sin(6.0 * x * pi) + 20.0 * Math.Sin(2.0 * x * pi)) * 2.0 / 3.0;
                ret += (20.0 * Math.Sin(y * pi) + 40.0 * Math.Sin(y / 3.0 * pi)) * 2.0 / 3.0;
                ret += (160.0 * Math.Sin(y / 12.0 * pi) + 320 * Math.Sin(y * pi / 30.0)) * 2.0 / 3.0;
                return ret;
            }

            static double transformLon(double x, double y)
            {
                double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.Sqrt(Math.Abs(x));
                ret += (20.0 * Math.Sin(6.0 * x * pi) + 20.0 * Math.Sin(2.0 * x * pi)) * 2.0 / 3.0;
                ret += (20.0 * Math.Sin(x * pi) + 40.0 * Math.Sin(x / 3.0 * pi)) * 2.0 / 3.0;
                ret += (150.0 * Math.Sin(x / 12.0 * pi) + 300.0 * Math.Sin(x / 30.0 * pi)) * 2.0 / 3.0;
                return ret;
            }
        }

 源码下载

转载于:https://www.cnblogs.com/ytwy/p/5515553.html

<think>嗯,用户的问题是关于在ArcGIS中处理高德地图使用的GCJ-02坐标系。用户可能是一名GIS专业人员或数据分析师,工作中需要将高德地图数据与其他地理空间数据整合。用户的核心痛点是:如何在ArcGIS环境中解决GCJ-02坐标系与标准WGS84坐标系之间的偏移问题。 用户提到参考站内引用中关于GCJ-02坐标系的内容,说明用户已经意识到该坐标系的特殊性——它本质上是加密偏移坐标系,而非标准地理坐标系。这带来两个技术难点:一是偏移算法不公开(虽然民间有逆向工程),二是ArcGIS原生不支持该坐标系。 从专业角度,解决方案需要分层次考虑:最理想的是从数据源头获取WGS84数据;若必须使用GCJ-02数据,则需要通过外部工具预处理。注意到用户特别强调“ARCGIS如何支持”,因此重点应放在ArcGIS兼容方案上。 技术实现上,Python脚本方案最灵活,但需要用户具备编程基础;Projection Engine扩展方案更易用但依赖第三方。需要提醒用户注意:任何坐标转换都可能引入误差,特别是GCJ-02的偏移算法非线性,城区误差可能达数百米。 用户可能还隐含了数据合规性担忧。引用[1]提到GCJ-02保密效果已丧失,但实际工作中仍需注意:若处理涉密数据,应通过正规渠道获取解密数据而非自行转换。</think>在ArcGIS中处理高德地图的GCJ-02坐标系需要特殊方法,因为ArcGIS原生**不支持**该坐标系。以下是详细解决方案: ### 一、核心问题分析 1. **坐标系冲突** - GCJ-02是中国特有的加密坐标系(火星坐标系),与WGS84存在非线性偏移 - ArcGIS默认坐标系库中无GCJ-02定义,直接加载会导致位置偏移 *公式偏移示例:* $$ \Delta x = f(lat, lon) + \varepsilon_x, \quad \Delta y = g(lat, lon) + \varepsilon_y $$ 其中$\varepsilon$为随机扰动项[^1] 2. **偏移特征** | 坐标系 | 与WGS84偏差 | 适用地图 | |--------|-------------|----------| | GCJ-02 | 100-700米 | 高德/腾讯 | | WGS84 | 0米 | Google地球 | ### 二、专业解决方案 #### ▶ 方法1:Python预处理(推荐) ```python # 安装依赖库:pip install gcj02towgs84 from gcj02towgs84 import gcj2wgs def convert_gcj_to_wgs(feature_class): with arcpy.da.UpdateCursor(feature_class, ['SHAPE@XY']) as cursor: for row in cursor: x, y = row[0] wgs_lon, wgs_lat = gcj2wgs.gcj2wgs(x, y) # 坐标转换 cursor.updateRow([(wgs_lon, wgs_lat)]) ``` **操作流程:** 1. 将高德数据导入ArcGIS(此时位置错误) 2. 运行此脚本转换几何坐标 3. 将图层坐标系定义为WGS84(EPSG:4326) #### ▶ 方法2:Projection Engine扩展 1. 下载第三方投影文件[`gcj02.prj`](https://github.com/Esri/projection-engine-db-doc/tree/master/custom) 2. 复制到ArcGIS安装目录:`...\Coordinate Systems\Projected Coordinate Systems\Custom` 3. 在ArcCatalog中右键数据集 > Properties > Coordinate System > 选择GCJ-02 #### ▶ 方法3:Web地图服务桥接 ```python # 在ArcGIS API for JavaScript中加载高德地图 require(["esri/layers/WebTileLayer"], (WebTileLayer) => { const gaodeLayer = new WebTileLayer({ urlTemplate: "https://webrd0{1-4}.is.autonavi.com?x={col}&y={row}&z={level}", spatialReference: { wkid: 4490 } // 使用CGCS2000近似替代 }); map.add(gaodeLayer); }); ``` ### 三、关键注意事项 1. **精度损失** 逆向转换存在±3米的误差,工程测量需慎用 $$ \delta = \sqrt{ (\Delta x)^2 + (\Delta y)^2 } \leq 3\text{m} $$ 2. **坐标系定义** - 转换后的数据必须显式定义坐标系属性 - 使用地理变换:`WGS_1984_(ITRF00)_To_GCJ_02`(需自定义) 3. **数据合规性** 根据《测绘地理信息管理条例》,公开使用GCJ-02数据需进行脱密处理[^1] > **最佳实践**:优先通过高德开放平台获取API服务,而非直接使用GCJ-02底图数据 --- ### 相关问题 1. **如何验证GCJ-02转WGS84的转换精度?** *建议方法:在已知WGS84坐标的控制点进行残差分析* 2. **ArcGIS Pro是否原生支持GCJ-02?** *现状:截至Pro 3.0仍不支持,需通过相同方案处理* 3. **批量处理Shapefile中的GCJ-02坐标有哪些工具?** *推荐工具:GDAL的`ogr2ogr` + `-s_srs`指定自定义坐标系* 4. **GCJ-02与百度BD-09坐标系转换有何差异?** *核心区别:BD-09在GCJ-02基础上进行了二次加密,偏移算法不同* [^1]: 坐标系加密机制源于国家测绘基准保护需求,但实际应用中存在技术局限。详见《地理信息系统导论》第8章
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值