问题描述

当项目需要对接GIS图层时,发现它的坐标系为EPSG:4490,而mapbox支持的坐标系是EPSG:3857。mapbox对接wms时bbox截取的地图块的经纬度范围,在对接时可将其EPSG:3857通过拦截请求转换为EPSG:4490的坐标系,获取得到GIS对应的图层瓦片。

  • EPSG:4326
    大地坐标系,WGS84
  • EPSG:4490
    大地坐标系,cgcs2000
  • EPSG:3857
    投影坐标系,墨卡托投影

方式1: 通过全局拦截fetch请求的方式

function injectFetch() {
  const newFetch = Object.getOwnPropertyDescriptor(window, 'fetch');
  Object.defineProperty(window, 'fetch', {
    value(a, b) {
      if (a instanceof Request && a.url.includes('/GISServices/')) {
        const u = new URL(a.url);
        // 解析 bbox 参数
        const bbox = u.searchParams.get('bbox') ?? '';
        const [lon1, lat1, lon2, lat2] = bbox.split(',');
        // 坐标系转换 : 墨卡托->GPS
        const p1 = mercator2LonLat([Number(lon1), Number(lat1)]);
        const p2 = mercator2LonLat([Number(lon2), Number(lat2)]);
        const newBBOX = p1.concat(p2).join(',');
        u.searchParams.set('bbox', newBBOX);
        Object.defineProperty(a, 'url', {
          value: decodeURIComponent(u.toString()),
        });
      }
      return newFetch.value.apply(this, [a, b]);
    },
  });
}

代理拦截请求的方式

  • 可通过node写一个代理服务,拦截瓦片请求服务。参考webpack的配置代理服务的方式,通过http-proxy-middleware来实现,然后可通过把node服务打包为exe后部署服务器来实现。

坐标系简介

通常有两种坐标系 地理坐标系(geographic coordinate systems) 和 投影坐标系(projected coordinate systems)

地理坐标系

坐标系简介
WGS-84坐标系地心坐标系,GPS原始坐标体系
GCJ-02 坐标系国测局坐标,火星坐标系,使用:高德、腾讯、Google中国地图
CGCS2000坐标系国家大地坐标系
BD-09坐标系百度地图所采用的坐标系,由GCJ-02进行进一步的偏移算法得到

投影坐标系(Projected coordinate systems)

地理坐标系是三维的,我们要在地图或者屏幕上显示就需要转化为二维,这被称为投影(Map projection)。显而易见的是,从三维到二维的转化,必然会导致变形和失真,失真是不可避免的,但是不同投影下会有不同的失真,这让我们可以有得选择。常用的投影有等矩矩形投影(Platte Carre)和墨卡托投影(Mercator)

  • 墨卡托投影: 投影后仍然是圆形,但是在高纬度时物体被严重放大了
  • 等距投影: 物体的大小变化不是那么明显,但是图像被拉长了

墨卡托坐标系与GPS坐标系转换工具方法

// 墨卡托坐标转GPS坐标
function mercator2LonLat(mercator) {
  const x = (mercator[0] / 20037508.34) * 180;
  let y = (mercator[1] / 20037508.34) * 180;
  y = (180 / Math.PI) * (2 * Math.atan(Math.exp((y * Math.PI) / 180)) - Math.PI / 2);
  return [x, y];
}

// GPS坐标转墨卡托坐标
function lonLat2Mercator(lonlat) {
  const x = (lonlat[0] * 20037508.34) / 180;
  let y = Math.log(Math.tan(((90 + lonlat[1]) * Math.PI) / 360)) / (Math.PI / 180);
  y = (y * 20037508.34) / 180;
  return [x, y];
}

坚果面包
21 声望0 粉丝

引用和评论

0 条评论