---
title: Openlayers投影与坐标转换
date: 2020-12-25
author: ac
sidebar: false
tags:
- Openlayers
categories:
- GIS
---
## 投影
在初始化`map`实例时,如果不在`view`中用`projection`参数指定投影坐标系,则将会使用默认的空间参考`EPSG:3857`(Web 墨卡托投影)。后续叠加的图层,都会将数据进行投影转换,确保`map`在同一个空间参考内。
> `EPSG`(European Petroleum Survey Group,欧洲石油调查组织)负责维护并发布坐标参照系统的数据集参数,以及坐标转换描述。它将已有的椭球体,投影坐标系等及其不同组合都对应着不同的ID号,这个号在`EPSG`中被称为`EPSG code`,它代表特定的椭球体、单位、地理坐标系或投影坐标系等信息。
`Openlayers`中的指定空间参考可以直接使用`EPSG code`指定,如`EPSG:4326`,因为`ol.proj.Projection`已经帮我们定义好`EPSG:4326`和`EPSG:3857`这两个空间参考的参数,同时也为这两个空间参考定义了一些别名,如`EPSG:3857`的`EPSG:102100`、`EPSG:102113`、`EPSG:900913`这些曾用名,也有用于识别`GML`要素的` http://www.opengis.net/gml/srs/epsg.xml#3857`和`urn:ogc:def:crs:EPSG:6.18:3:3857`。
空间参考的别名可以使用`proj4js`的`defs()`方法添加:
```javascript
proj4.defs('urn:x-ogc:def:crs:EPSG:4326', proj4.defs('EPSG:4326'));
```
`ol`对于其他空间参考,可以使用`proj4js`进行自定义。`defs()`方法定义,`register()`方法进行注册。
> `proj4js`是一个JavaScript库,是一个强大的通用坐标转换引擎,可以同时进行大规模地图投影和高精密度的坐标转换。
```javascript
proj4.defs(
'EPSG:21781',
'+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 ' +
'+x_0=600000 +y_0=200000 +ellps=bessel ' +
'+towgs84=660.077,13.551,369.344,2.484,1.783,2.939,5.66 +units=m +no_defs'
);
register(proj4);
```
自定义的投影必须是在[https://epsg.io/](https://epsg.io/)可以找到的才有效。


**常用参数列表**:
| 参数 | 描述 |
| :-------- | ------------------------------------------------------------ |
| +proj | 投影名称,安装`proj`后可以使用`proj - l `命令查看支持的投影名称 |
| +lat_0 | 维度起点 |
| +lon_0 | 中央经线 |
| +x_0 | 东(伪)偏移量 |
| +y_0 | 北(伪)偏移量 |
| +ellps | 椭球体名称,使用`proj -le` 命令查看支持哪些椭球体 |
| +units | 水平单位,meters(米)。使用`proj -lu `命令查看`PROJ`支持的单位 |
| +lat_ts | 有效纬度范围 |
| +a | 椭球体长半轴长度 |
| +b | 椭球体短半轴长度 |
| +k | 比例系数(比例因子),旧版本,不赞成使用 |
| +k_0 | 比例系数(比例因子) |
| +vunits | 垂直单位 |
| +datum | 基准面名称,使用`proj -ld`命令查看支持的基准面 |
| +towgs84 | 3参数或7参数基面转换 |
| +to_meter | 将水平单位转换为米计算输出转换参数,如:1英尺= |
| +no_defs | 不要使用`proj`库中的缺省定义文件。 |
下面使用`OSM`地图作为示例图层,定义`CGCS2000`的空间参考。
```html
OpenLayers example
Projection CGCS2000(EPSG:4490)
```
可以将瓦片图层`SOM`当做底图,再往上叠加图层。
## 坐标转换
对于矢量数据可以使用`ol.proj`命名空间下的方法,在客户端进行坐标转换,如:
```javascript
//将坐标coordinate从“EPSG:3857”转换到“EPSG:4490”
ol.proj.transform([12686109.88955285,2572810.705991532],"EPSG:3857","EPSG:4490");
//添加坐标转换函数
ol.proj.addCoordinateTransforms("EPSG:3857","EPSG:4490",function (coordinate) {
return proj4("EPSG:3857","EPSG:4490",coordinate);
},function (coordinate) {
return proj4("EPSG:4490","EPSG:3857",coordinate);
})
//将经纬度的coordinate转换到目标空间参考下的坐标,默认是EPSG:3857
ol.proj.fromLonLat([113.958334, 22.535640],cgcs2000)
//将coordinate转换成经纬度
ol.proj.toLonLat([12686109.88955285,2572810.705991532])
```
上述是对单个coordinate的转换,对于几何要素Geometry及其子类(点、线、面等)可以使用`ol.geom.Geometry`中的`transform()`方法转换几何对象中的每组坐标。像`GeoJSON`、`KML`、`gpx`类型的文件可以选择在解析器解析完成得到要素集合后,对每个要素进行转化。
示例:
```html
OpenLayers example
Projection CGCS2000(EPSG:4490)
```

`test.json`数据文件
```json
{
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:EPSG:3857"
}
},
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
12686109.88955285,
2572810.705991532
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [
12683644.795390654,
2568835.9805207034
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[
12673134.704001442,
2577473.364716928
],
[
12671453.089379169,
2571625.932053112
],
[
12689186.479941329,
2580358.8625346934
],
[
12677606.270156125,
2580435.2995629786
]
]
}
}
]
}
```
对于服务类型的数据,像`WFS`、`WMS`服务可以在请求中使用`srsname`或`CRS`参数指定返回要素的空间参考,将坐标转换的工作在服务端完成。
示例:
```html
OpenLayers example
Projection:加载GeoServer的WFS服务
```

```javascript
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Tile({
source: new ol.source.TileWMS({
url: 'http://localhost:8080/geoserver/tiger/ows',
params: {
//WIDTH, HEIGHT, BBOX and CRS (SRS for WMS version < 1.3.0) 将被动态设置.
'LAYERS': 'tiger:tiger_roads',
'TILED': false,
'VERSION':'1.1.0',
'TRANSPARENT':true,//
'CRS':"EPSG:4490"
},
//远程WMS服务器的类型
serverType: 'geoserver',
// 用于渲染的不透明度过渡的持续时间。要禁用不透明过渡,设置transition为: 0
transition: 0
})
})
],
target: document.getElementById('map'),
view: new ol.View({
center: nyc,
maxZoom: 19,
zoom: 12,
projection: cgcs2000
})
});
```
