proj4js空间坐标转换入门

proj4js是一个用于地理空间坐标转换的JavaScript库。可以很方便的在浏览器和nodejs环境下完成坐标转换,能在一定程度上弥补当前很多web gis引擎对坐标系支持能力不足的短板(大多数web端的gis引擎只支持WGS 84和Web墨卡托两种坐标系)。

proj4js源于另一个开源项目PROJ,虽然目前功能已经相对完善,开源社区也比较活跃,但是文档还有不少欠缺,想要了解完整的参数和用法还是得查阅PROJ的文档。

坐标系描述

在proj4中可以通过下表所列的常用参数组合成一个描述坐标系信息的字符串,在proj4js中称为proj-string。本文对其中几个重要的参数进行介绍。

参数 描述
+a 椭球长轴的半径
+axis 轴的方向
+b 椭球短轴的半径
+ellps 地球椭球
+datum 大地基准面
+k 缩放系数(已废弃)
+k_0 缩放系数
+lat_0 纬度的起算点(默认以度为单位)
+lat_ts 有效纬度范围
+lon_0 中央经线(默认以度为单位)
+lon_wrap 定义经度范围的一种方式(+lon_wrap=180 表示 [ 0, 360] )
+over 允许经度超出[ -180, 180 ]的范围
+pm 自定义子午线(通常是城市名称)
+proj 投影名称
+units 水平坐标系单位(米、美制测量英尺等)
+vunits 垂直坐标系单位
+x_0 东偏移量(始终以米为单位)
+y_0 北偏移量(始终以米为单位)
+no_defs 不从默认的proj_def.dat读取默认参数
+zone 指定UTM区域

常用坐标系定义参数 

投影名称

使用+proj指定投影名称,常用可选值如下

坐标系名称 意义
merc 墨卡托投影
utm UTM(横轴墨卡托)投影
longlat 坐标值输入为 [ 经度, 纬度 ] 的地理坐标系
latlong 坐标值输入为 [ 纬度, 经度 ] 的地理坐标系

 常用投影名称

示例: 

+proj=merc +lat_ts=56.5 +ellps=GRS80

+proj=utm +zone=50 +datum=WGS84 +units=m +no_defs +type=crs

单位

坐标系水平方向单位用+units参数定义,垂直方向的单位通过+vunits参数定义。

示例: 

坐标单位为度

+proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees

坐标单位为米(投影坐标系默认单位是米)

+proj=gnom +lat_0=90 +lon_0=0 +x_0=6300000 +y_0=6300000 +ellps=WGS84 +datum=WGS84 +units=m +no_defs

偏移量

坐标系允许存在东偏移量 (+x_0) 和北偏移 (+y_0)。即使坐标系是其他单位,偏移量也始终以米表示。

示例: 

+proj=tmerc +lat_0=0 +lon_0=75 +k=1 +x_0=13500000 +y_0=0 +a=6378140 +b=6356755.288157528 +units=m +no_defs

经度范围

经度范围默认被限制在 [ -180, 180 ],如果使用了+over参数,则经度范围可以忽略这个限制

示例: 

 +proj=merc +a=6371200 +b=6371200 +units=meters +no_defs + lon_1=110 +lon_2=-109.129 +lat_ts=20 +lon_wrap=180 +over

本初子午线

使用+pm参数可以自定义坐标系的本初子午线。proj4js有一组预定义的子午线名称。

子午线 经度
greenwich(默认) 0dE
lisbon 9d07'54.862"W
paris 2d20'14.025"E
bogota 74d04'51.3"E
madrid 3d41'16.48"W
rome 12d27'8.4"E
bern 7d26'22.5"E
jakarta 106d48'27.79"E
ferro 17d40'W
brussels 4d22'4.71"E
stockholm 18d3'29.8"E
athens 23d42'58.815"E
oslo 10d43'22.5"E

 proj4预定义子午线

示例:

+proj=lcc +lat_1=46.8 +lat_0=46.8 +lon_0=0 +k_0=0.99987742 +x_0=600000 +y_0=2200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs

+proj=latlong +datum=WGS84 +pm=madrid

坐标轴方向

+axis参数用于控制坐标系的轴方向,默认方向是“东、北、上”,或者由以下字母自由组合

  • "e" - 东
  • "w" - 西
  • "n" - 北
  • "s" - 南
  • "u" - 上
  • "d" - 下

例如以下几种组合方式

  • +axis=enu :默认的ENU(东、北、上)坐标系;
  • +axis=neu :通常用于 "纬度 / 经度" 形式的地理坐标或者南向横轴墨卡托投影(south orientated transverse mercator);
  • +axis=wnu :用于一些以西为正方向的行星坐标系

椭球体

椭球体是一个数学意义上的表面,它近似于大地水准面。由于地球是一个不规则的椭球体,于是地图投影中产生了多种多样的椭球体定义。每个地区都有最适合当地地形的地球椭球体。

椭球体包含尺寸(size)和形状(shape )两部分概念。具体由尺寸参数、形状参数和球谐参数指定。(如果使用了+R参数指定为标准球体,那么形状参数和球谐参数都会被忽略)

参数 意义
+R= 球体的半径(定义为球体时使用)
+a= 椭球的长半轴

尺寸参数 

参数 意义
+rf= 椭球扁率的倒数(Reverse flattening)
+f= 椭球扁率
+es= 偏心率的平方
+e= 偏心率
+b= 短半轴

形状参数 

参数 意义
+R_A 与椭球体表面积相同的球体
+R_V 与椭球体体积相同的球体
+R_C 半径为共形球体(conformal sphere)\phi _{0}处半径的球体
+R_a 半径R为 (a + b) / 2 的球体(算数平均数)
+R_g 半径R为 \sqrt{ab}的球体(几何平均数)
+R_h 半径R为 2ab / (a + b)的球体(调和平均数)
+R_lat_a= 半径为相应椭球在纬度\varnothing处的算数平均数的球体
+R_lat_g= 半径为相应椭球在纬度\varnothing处的几何平均数的球体

 球谐参数

用户可以自定义椭球体,但更多的还是使用+ellps参数选用proj4内置的椭球体

椭球 参数 测量基准
GRS80(默认) a=6378137.0 rf=298.257222101 GRS 1980(IUGG, 1980)
airy a=6377563.396 b=6356256.910 Airy 1830
bessel a=6377397.155 rf=299.1528128 Bessel 1841
clrk66 a=6378206.4 b=6356583.8 Clarke 1866
intl a=6378388.0 rf=297. International 1909 (Hayford)
WGS60 a=6378165.0 rf=298.3 WGS 60
WGS66 a=6378145.0 rf=298.25 WGS 66
WGS72 a=6378135.0 rf=298.26 WGS 72
WGS84 a=6378137.0 rf=298.257223563 WGS 84
sphere a=6370997.0 b=6370997.0 Normal Sphere (r=6370997)

 proj4预定义椭球体

示例:

GRS80椭球

+proj=merc +lat_ts=56.5 +ellps=GRS80

通过半长轴和扁率的倒数自定义椭球

+proj=latlon +a=6378137.0 +rf=298.25 

和定义的椭球体体积相同的球体

+proj=latlon +a=6378137.0 +rf=298.25 +R_V 

常用坐标系定义

 WGS 84地理坐标系统 (EPSG:4326)

+proj=longlat +datum=WGS84 +no_defs

 Web Mercator (EPSG:3857)

+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs

 中国国家2000地理坐标系统 (EPSG:4490)

定义和WGS 84一样(CGCS2000椭球和WGS84椭球极为相似,偏差仅有0.11mm,完全可以兼容使用)

+proj=longlat +ellps=GRS80 +no_defs

 北京54坐标系 (EPSG:4214)

+proj=longlat +ellps=krass +towgs84=15.8,-154.4,-82.3,0,0,0,0 +no_defs

 西安80坐标系 (EPSG:4610)

+proj=longlat +a=6378140 +b=6356755.288157528 +no_defs

 UTM 50号带 / UTM zone 50N (EPSG:32650)

中国国境跨UTM带号为43-53,根据需要更改+zone后面的数字即可

+proj=utm +zone=50 +datum=WGS84 +units=m +no_defs

API使用介绍

proj4js主要的函数是proj4,函数签名如下所示:

    proj4([fromProjection, ]toProjection[, coordinates])

应用举例 

 下面的用例用到两个坐标系定义

    var firstProjection = 'PROJCS["NAD83 / Massachusetts Mainland",GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4269"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Lambert_Conformal_Conic_2SP"],PARAMETER["standard_parallel_1",42.68333333333333],PARAMETER["standard_parallel_2",41.71666666666667],PARAMETER["latitude_of_origin",41],PARAMETER["central_meridian",-71.5],PARAMETER["false_easting",200000],PARAMETER["false_northing",750000],AUTHORITY["EPSG","26986"],AXIS["X",EAST],AXIS["Y",NORTH]]';
    var secondProjection = "+proj=gnom +lat_0=90 +lon_0=0 +x_0=6300000 +y_0=6300000 +ellps=WGS84 +datum=WGS84 +units=m +no_defs";

1、将一个坐标点从一个坐标系转换到另一个坐标系

    // ...
    // [-2690575.447893817, 36622916.8071244564]
    proj4(firstProjection, secondProjection, [-122.305887, 58.9465872]); 

2、转换带高程值的坐标(高程值会原样保留)

    // ...
    // [-2690575.447893817, 36622916.8071244564, 10]
    proj4(firstProjection,secondProjection,[-122.305887, 58.9465872,10]);

3、如果只提供一个坐标系,这个坐标系会被认为是目标坐标系(toProjection),源坐标系(fromProjection)默认为WGS84

    // ...
    // 坐标从WGS 84转换到 firstProjection
    // [242075.00535055372, 750123.32090043]
    proj4(firstProjection, [-71, 41]);

4、如果proj4函数中只传入了坐标系,没有传入待转换的坐标。那么proj4函数返回一个包含 forward 和 inverse 两个函数的对象。

  • forward :从第一个坐标系参数转换到第二个坐标系参数
  • inverse :从第二个坐标系参数转换到第一个坐标系参数
	// firstProjection 转换到 secondProjection
    // [-2690575.447893817, 36622916.8071244564]
	proj4(firstProjection, secondProjection).forward([-122.305887, 58.9465872]);
	// firstProjection 转换到 secondProjection
    // [-2690575.447893817, 36622916.8071244564]
    proj4(secondProjection, firstProjection).inverse([-122.305887, 58.9465872]);

5、只给出一个坐标系,并且没有坐标,那么原始坐标系被认为是wgs84

    // wgs84转换到firstProjection
    // [242075.00535055372, 750123.32090043]
    proj4(firstProjection).forward([-71,41])
    // 因为是inverse,所以把坐标从firstProjection转换到wgs84
    // [-71, 40.99999999999986]
    proj4(firstProjection).inverse([242075.00535055372, 750123.32090043]);

投影命名

proj4js允许用户通过defs函数自定义坐标系名称,并在后续引用

    proj4.defs([
      [
        'EPSG:4326',
        '+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees'],
      [
        'EPSG:4269',
        '+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees'
      ]
    ]);
    // 从secondProjection转换到自定义的'EPSG:4326'
    // [-163.48520399669096, 11.401530800453495, 10]
    proj4(secondProjection, 'EPSG:4326', [-2690575.447893817, 36622916.8071244564, 10]);

proj4js内置了一些预定义的坐标系名称

坐标系名称 别名
EPSG:4326 WGS84
EPSG:4269
EPSG:3857 EPSG:3785 或 GOOGLE 或 EPSG:900913 或 EPSG:102113

proj4预定义坐标系及别名 

    // 使用预定义坐标系
    proj4(secondProjection, 'EPSG:3785', [-2690575.447893817, 36622916.8071244564, 10]);
    proj4(secondProjection, 'EPSG:900913', [-2690575.447893817, 36622916.8071244564, 10])

使用proj4js预定义的坐标系 

反转坐标轴顺序

默认情况下,proj4中投影坐标系使用 [x, y] 的坐标轴顺序,地理坐标系使用 [x = longitude, y = latitude] 的坐标轴顺序。可以按以下方式设置enforceAxis参数以反转默认的坐标轴顺序。

proj4(fromProjection, toProjection).forward(coordinate, enforceAxis);
proj4(fromProjection, toProjection).inverse(coordinate, enforceAxis);

	// enforceAxis默认值为false
    // [-71, 40.99999999999986]
    proj4('+proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees +axis=neu', firstProjection).inverse([242075.00535055372, 750123.32090043]);

    // 显示指定enforceAxis为true,反转坐标轴
	// [40.99999999999986, -71]
    proj4('+proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees +axis=neu', firstProjection).inverse([242075.00535055372, 750123.32090043], true);
	// 不设置enforceAxis
    // [39078917.71700995, -2076788.7936424324]
    proj4('+proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees +axis=neu', firstProjection).forward([41, -71]);
	
    // enforceAxis设置为true
	// [242075.00535055372, 750123.32090043]
    proj4('+proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees +axis=neu', firstProjection).forward([41, -71], true);

结语

这篇文章只是总结了proj4js涉及的基本概念以及使用方法,并不能囊括所有proj4js的细节。同时地图投影的内容很多,还有很多理论和概念是我不了解的,有待后续不断学习和总结!

你可能感兴趣的:(gis,图形渲染)