GIS map coordinate system conversion method, quickly collect it

 The most annoying thing when developing maps is that different map tools and data source coordinate systems cause offsets and even errors. The following is a summary of some map coordinate conversions. One file can handle all situations directly.

 1. Classification of map coordinate systems

Common map technologies: openlayers, cesium, Amap, Baidu, etc. Different map frame maps have slightly different coordinate systems.

  • WGS84 (GPS): Generally, the coordinates obtained from international standard GPS devices are WGS84, and the coordinate system used by international map providers, such as ArcGIS and Bing's basemap, is the WGS84 coordinate system.

  • GCJ02: The coordinate system released by the National Survey Bureau in 2002, also known as "Mars coordinates". In China, WGS84 cannot be used directly and requires encryption from the National Bureau of Surveying and Mapping. For example, Google China, AutoNavi, and Tencent are all using this coordinate system.

  • BD09 Baidu standard, encryption algorithm is different.

 The following is a method encapsulation for the coordinate conversion of Amap
 

export default class CoorsOffset {
  constructor () {
    this.x_pi = (3.14159265358979324 * 3000.0) / 180.0;
    this.pi = 3.14159265358979324;
    this.a = 6378245.0;
    this.ee = 0.00669342162296594323;
  }

  /**
   * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
   * 即 百度 转 谷歌、高德
   * @param {*} DBLon
   * @param {*} DBLat
   * @returns {*[longitude, latitude]}
   */
  bd09togcj02 = (DBLon, DBLat) => {
    const x = DBLon - 0.0065;
    const y = DBLat - 0.006;
    const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * this.x_pi);
    const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * this.x_pi);
    const lon = z * Math.cos(theta);
    const lat = z * Math.sin(theta);

    return [lon, lat];
  }

  /**
   * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
   * 即谷歌、高德 转 百度
   * @param lng
   * @param lat
   * @returns {*[longitude, latitude]}
   */
  gcj02tobd09 = (lng, lat) => {
    const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * this.x_pi);
    const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * this.x_pi);
    const BDLng = z * Math.cos(theta) + 0.0065;
    const DBLat = z * Math.sin(theta) + 0.006;

    return [BDLng, DBLat];
  }

  /**
   * WGS84转GCj02
   * @param lng
   * @param lat
   * @returns {*[longitude, latitude]}
   */
  wgs84togcj02 = (lng, lat) => {
    const radlat = (lat / 180.0) * this.pi;
    const magic = 1 - this.ee * Math.sin(radlat) * Math.sin(radlat);
    const sqrtmagic = Math.sqrt(magic);

    let dlat = this.transformlat(lng - 105.0, lat - 35.0);

    let dlng = this.transformlng(lng - 105.0, lat - 35.0);

    dlat = (dlat * 180.0) / (((this.a * (1 - this.ee)) / (magic * sqrtmagic)) * this.pi);
    dlng = (dlng * 180.0) / ((this.a / sqrtmagic) * Math.cos(radlat) * this.pi);
    let mglat = lat + dlat;

    let mglng = lng + dlng;

    return [mglng, mglat];
  }

  /**
   * GCJ02 转换为 WGS84
   * @param lng
   * @param lat
   * @returns {*[longitude, latitude]}
   */
  gcj02towgs84 = (lng, lat) => {
    var dlat = this.transformlat(lng - 105.0, lat - 35.0);
    var dlng = this.transformlng(lng - 105.0, lat - 35.0);
    const radlat = (lat / 180.0) * this.pi;
    const magic = 1 - this.ee * Math.sin(radlat) * Math.sin(radlat);
    const sqrtmagic = Math.sqrt(magic);

    dlat = (dlat * 180.0) / (((this.a * (1 - this.ee)) / (magic * sqrtmagic)) * this.pi);
    dlng = (dlng * 180.0) / ((this.a / sqrtmagic) * Math.cos(radlat) * this.pi);

    const mglat = lat + dlat;
    const mglng = lng + dlng;

    return [lng * 2 - mglng, lat * 2 - mglat];
  }

  transformlat = (lng, lat) => {
    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 * this.pi) + 20.0 *Math.sin(2.0 * lng * this.pi)) * (2.0 / 3.0);
    ret += (20.0 * Math.sin(lat * this.pi) + 40.0 * Math.sin((lat / 3.0) * this.pi)) * (2.0 / 3.0);
    ret += (160.0 * Math.sin((lat / 12.0) * this.pi) + 320 * Math.sin((lat * this.pi) / 30.0)) * (2.0 / 3.0);

    return ret;
  }

  transformlng = (lng, lat) => {
    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 * this.pi) + 20.0 * Math.sin(2.0 * lng * this.pi)) * (2.0 / 3.0);
    ret += (20.0 * Math.sin(lng * this.pi) + 40.0 * Math.sin((lng / 3.0) * this.pi)) * (2.0 / 3.0);
    ret += (150.0 * Math.sin((lng / 12.0) * this.pi) + 300.0 * Math.sin((lng / 30.0) * this.pi)) * (2.0 / 3.0);

    return ret;
  }
}

2. Commonly used coordinate classifications in cesium three-dimensional maps

  • WGS84 coordinates: longitude and latitude coordinates, the coordinate origin is, longitude range [-180, 180], latitude range [-90, 90].
  • WGS84 radian coordinates (Cartographic): The geographical coordinate unit in Cesium defaults to radian system
  •  Cartesian space rectangular coordinates (Cartesian3): world coordinates, the origin is the center of the ellipsoid, coordinates (x, y, z)
  • -Screen coordinates (Cartesian2): Plane Cartesian coordinate system, a two-dimensional Cartesian coordinate system, the coordinates are (x, y)

The following is a method encapsulation for cesium map coordinate conversion

 /**
   * 坐标转换 84转笛卡尔
   * @param {Position} position 位置
   * @param {number} alt 高度
   * @returns {any} 笛卡尔坐标
   */
  transformWGS84ToCartesian = (position, alt = 0) => (position ?
    Cesium.Cartesian3.fromDegrees(
      position.lon,
      position.lat,
      alt || position.alt,
      Cesium.Ellipsoid.WGS84
    ) :
    Cesium.Cartesian3.ZERO)

  /**
   * 坐标转换 笛卡尔转84
   * @param {Object} cartesian 三维位置坐标
   * @return {Object} {lon,lat,alt} 地理坐标
   */
  transformCartesianToWGS84 = (cartesian) => {
    const ellipsoid = Cesium.Ellipsoid.WGS84;
    const cartographic = ellipsoid.cartesianToCartographic(cartesian);

    return {
      lon: Cesium.Math.toDegrees(cartographic.longitude),
      lat: Cesium.Math.toDegrees(cartographic.latitude),
      alt: cartographic.height,
    };
  }

  /**
   * 84坐标转弧度坐标
   * @param {Object} position wgs84
   * @return {Object} Cartographic 弧度坐标
   */
  transformWGS84ToCartographic = (position) => (position ?
    Cesium.Cartographic.fromDegrees(
      position.lon || position.lon,
      position.lat,
      position.alt
    ) :
    Cesium.Cartographic.ZERO)
   
   
   /**
   * 经纬度转Cartesian2。
   * 注意这里的 Cartesian2 是屏幕坐标,不能直接使用 Cartesian2.fromCartesian3
   * @param {number} lon 经度
   * @param {number} lat 纬度
   * @returns {void}
   */
  lonLatToCartesian2 = (lon: number, lat: number): any => {
    const Cartesian3Result = Cesium.Cartesian3.fromDegrees(lon, lat);
    const Cartesian2Result = Cesium.SceneTransforms.wgs84ToWindowCoordinates(this.scene, Cartesian3Result);

    return Cartesian2Result;
  }

Guess you like

Origin blog.csdn.net/layliangbo/article/details/126759666