Cesium中高德、百度地图的偏移矫正

Cesium中高德、百度地图的偏移矫正

一、坐标系介绍

不同地图的坐标系
(1)WGS84(cesium GPS)
即GPS原始坐标系,也是当今三维开发中最普遍使用的坐标系。
(2)GCJ-02:火星坐标系(高德)
由国测局发布的加密坐标系,是国内互联网地图最广泛使用的坐标系,包括高德、腾讯。
(3)BD-09(百度地图)
百度地图所采用的坐标系,即在火星坐标系上进一步偏移得到,与高德地图相差不大。
(4)CGCS2000(天地图)
又称2000国家大地坐标系,由西安80坐标系发展而来,一般使用高斯克吕格投影,用于国内土地调查等坐标参考系。天地图采用此坐标系.

二、实现效果

底图为Cesium中默认的必应地图,上面是高德地图的注记地图。
在这里插入图片描述

二、实现方法

(1)添加坐标转换的js文件 CoordTransform.js;

const BD_FACTOR = (3.14159265358979324 * 3000.0) / 180.0; // 百度坐标系的修正因子
const PI = 3.1415926535897932384626; // 圆周率
const RADIUS = 6378245.0; // 地球半径
const EE = 0.00669342162296594323; // 椭球的偏心率平方

class CoordTransform {
  /**
   * BD-09(百度坐标系) To GCJ-02(火星坐标系) 的转换方法
   * @param lng 经度
   * @param lat 纬度
   * @returns {number[]} 返回经纬度数组
   */
  static BD09ToGCJ02(lng, lat) {
    let x = +lng - 0.0065; // 经度修正
    let y = +lat - 0.006; // 纬度修正
    let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * BD_FACTOR); // z 值修正
    let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * BD_FACTOR); // theta 值修正
    let gg_lng = z * Math.cos(theta); // 修正后的经度
    let gg_lat = z * Math.sin(theta); // 修正后的纬度
    return [gg_lng, gg_lat];
  }

  /**
   * GCJ-02(火星坐标系) To BD-09(百度坐标系) 的转换方法
   * @param lng 经度
   * @param lat 纬度
   * @returns {number[]} 返回经纬度数组
   */
  static GCJ02ToBD09(lng, lat) {
    lat = +lat;
    lng = +lng;
    let z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * BD_FACTOR); // z 值修正
    let theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * BD_FACTOR); // theta 值修正
    let bd_lng = z * Math.cos(theta) + 0.0065; // 修正后的经度
    let bd_lat = z * Math.sin(theta) + 0.006; // 修正后的纬度
    return [bd_lng, bd_lat];
  }

  /**
   * WGS-84(世界大地坐标系) To GCJ-02(火星坐标系) 的转换方法
   * @param lng 经度
   * @param lat 纬度
   * @returns {number[]} 返回经纬度数组
   */
  static WGS84ToGCJ02(lng, lat) {
    lat = +lat;
    lng = +lng;
    if (this.out_of_china(lng, lat)) { // 如果在中国境内
      return [lng, lat];
    } else {
      let d = this.delta(lng, lat); // 计算经纬度偏移值
      return [lng + d[0], lat + d[1]]; // 返回修正后的经纬度
    }
  }

  /**
   * GCJ-02(火星坐标系) To WGS-84(世界大地坐标系) 的转换方法
   * @param lng 经度
   * @param lat 纬度
   * @returns {number[]} 返回经纬度数组
   */
  static GCJ02ToWGS84(lng, lat) {
    lat = +lat;
    lng = +lng;
    if (this.out_of_china(lng, lat)) { // 如果在中国境内
      return [lng, lat];
    } else {
      let d = this.delta(lng, lat); // 计算经纬度偏移值
      let mgLng = lng + d[0];
      let mgLat = lat + d[1];
      return [lng * 2 - mgLng, lat * 2 - mgLat]; // 返回修正后的经纬度
    }
  }

  /**
   * 计算经纬度偏移值的方法
   * @param lng 经度
   * @param lat 纬度
   * @returns {number[]} 返回经纬度偏移值数组
   */
  static delta(lng, lat) {
    let dLng = this.transformLng(lng - 105, lat - 35); // 经度偏移值
    let dLat = this.transformLat(lng - 105, lat - 35); // 纬度偏移值
    const radLat = (lat / 180) * PI;
    let magic = Math.sin(radLat);
    magic = 1 - EE * magic * magic;
    const sqrtMagic = Math.sqrt(magic);
    dLng = (dLng * 180) / ((RADIUS / sqrtMagic) * Math.cos(radLat) * PI);
    dLat = (dLat * 180) / (((RADIUS * (1 - EE)) / (magic * sqrtMagic)) * PI);
    return [dLng, dLat];
  }
    static transformLng(lng, lat) {
    lat = +lat;
    lng = +lng;
    let 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;
  }

  /**
   *
   * @param lng
   * @param lat
   * @returns {number}
   */
  static transformLat(lng, lat) {
    lat = +lat;
    lng = +lng;
    let 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;
  }

  /**
   * 判断是否在国内。不在国内不做偏移
   * @param lng
   * @param lat
   * @returns {boolean}
   */
  static out_of_china(lng,lat) {
    lat = +lat;
    lng = +lng;
    return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
  }
}
export default CoordTransform;

(2)重写 WebMercatorProjection 的 project 方法,实现从 WGS84 坐标系转换到 GCJ02 坐标系,再进行墨卡托投影,新建AmapMercatorTilingScheme.js

import { WebMercatorProjection, WebMercatorTilingScheme, Math, Cartographic, Cartesian2 } from 'cesium'; // 导入所需的 Cesium 模块

import CoordTransform from './CoordTransform'; // 导入坐标转换工具类

class AmapMercatorTilingScheme extends WebMercatorTilingScheme {
  constructor() {
    super(); 

    let projection = new WebMercatorProjection(); // 创建 WebMercatorProjection 对象用于进行投影转换

    // 重写 WebMercatorProjection 的 project 方法,实现从 WGS84 坐标系转换到 GCJ02 坐标系,再进行墨卡托投影
    this._projection.project = function (cartographic, result) {
      // 调用坐标转换工具类的 WGS84ToGCJ02 方法将经纬度转换为 GCJ02 坐标系下的经纬度
      result = CoordTransform.WGS84ToGCJ02(
        Math.toDegrees(cartographic.longitude),
        Math.toDegrees(cartographic.latitude)
      );
      // 将转换后的 GCJ02 坐标系下的经纬度转换为弧度,并进行墨卡托投影
      result = projection.project(new Cartographic(Math.toRadians(result[0]), Math.toRadians(result[1])));
      return new Cartesian2(result.x, result.y); // 返回墨卡托投影后的结果
    };

    // 重写 WebMercatorProjection 的 unproject 方法,实现从墨卡托投影转换回 WGS84 坐标系
    this._projection.unproject = function (cartesian, result) {
      // 将墨卡托投影的坐标转换为经纬度
      let cartographic = projection.unproject(cartesian);
      // 调用坐标转换工具类的 GCJ02ToWGS84 方法将 GCJ02 坐标系下的经纬度转换为 WGS84 坐标系下的经纬度
      result = CoordTransform.GCJ02ToWGS84(
        Math.toDegrees(cartographic.longitude),
        Math.toDegrees(cartographic.latitude)
      );
      return new Cartographic(Math.toRadians(result[0]), Math.toRadians(result[1])); // 返回 WGS84 坐标系下的结果
    };
  }
}

export default AmapMercatorTilingScheme; // 导出自定义的高德地图墨卡托投影切片方案

(3)在引入高德地图的地方

  const  tdtLayer = new Cesium.UrlTemplateImageryProvider({
                url: "http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
                minimumLevel: 3,
                maximumLevel: 18,
                tilingScheme: new AmapMercatorTilingScheme(),//坐标矫正
            })
  viewer.imageryLayers.addImageryProvider(tdtLayer);

三、总结

第一次写还有些生疏,以后也会多多记录,此篇博客也是借鉴前人的,并加以注释修改,地址如下:https://juejin.cn/post/7049681493685174286
百度、天地图转换方法也类似。

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Cesium是一个开源的地球可视化引擎,高德地图国主要的地图服务提供商。在Cesium使用高德地图图层时,可能会出现一些偏移的问题。 这种偏移问题主要是由于不同地图服务提供商使用了自己的坐标系统或投影方式,导致不同地图之间存在一定的地理坐标偏移。在使用高德地图图层时,也会遇到类似的偏移情况。 为了解决这个问题,可以尝试以下两种方法来进行偏移修正。 第一种方法是手动修正。在Cesium,我们可以通过手动调整图层的位置,使其与其他图层或实际地图上的特定位置对齐。调整的方法可以根据实际情况选择,在代码设置图层的位置坐标。 第二种方法是使用坐标转换库。可以使用一些开源的坐标转换库,如Proj4js、Coordinate Transformations for Cesium等,将高德地图的坐标转换到与Cesium相同的坐标系或投影系统。通过使用这些坐标转换库,可以将高德地图的坐标进行转换,以解决偏移问题。 需要注意的是,每个地图服务提供商可能会采用不同的坐标系统、投影方式或坐标转换方法。因此,在使用高德地图图层时,需要根据实际情况选择适合的坐标转换方法,并进行相应的调整。 总之,在Cesium使用高德地图图层时存在一定的偏移问题,可以通过手动修正或使用坐标转换库来解决。根据实际情况选择适合的方法,进行相应的调整,以实现准确的地图显示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值