Cesium是一个具有真实地理坐标的三维球体,而用户是通过二维屏幕和Cesium进行交互查询。所以Cesium中离不开地理坐标与屏幕坐标的转换。
3.2.1 坐标系
我们先来列举下Cesium中的坐标系:WGS84经纬度坐标系(没有实际的对象)、WGS84弧度坐标系(Cartographic)、笛卡尔空间直角坐标系(Cartesian3)、平面坐标系(Cartesian2),4D笛卡尔坐标系(Cartesian4)
Cesium开发中经常遇到的坐标系主要有三个。屏幕坐标系、笛卡尔空间直角坐标系、地理坐标系。屏幕坐标系是二维坐标,空间直角坐标系是三维坐标,地理坐标系是球面经纬度坐标。
- 屏幕坐标系(Cartesian2)
屏幕坐标系又叫平面坐标系,是二维笛卡尔坐标系。Cesium中一般用Cartesian2来描述,构造函数是new Cesium.Cartesian2(x, y)
。一般是以canvas左上角为原点(0,0),水平方向为X轴,向右为正,垂直方向为Y轴,向下为正。
笛卡尔空间直角坐标系(Cartesian3)
又称世界坐标系。以空间中O为原点,建立三条两两垂直的数轴;X轴(横坐标)、Y轴(纵坐标)、Z轴(竖坐标),建立起来空间直角坐标系O-XYZ。笛卡尔空间直角坐标的原点就是椭球的中心,再计算机上进行绘图时,不方便使用经纬度直接绘图,一般会将坐标系转换为笛卡尔坐标系,使用计算机图形学中的知识进行绘图。构造函数是
new Cesium.Cartesian3(x, y, z)
WGS84地理坐标系
WGS84坐标系是地理信息数据最常用的坐标系,基于参考椭球体使用大地经度、大地纬度和大地高三个参数表示具体的空间点位。 在二维GIS中地理数据的参考系通常用地理坐标系和投影坐标系两种,但在三维中一般都使用WGS84地理坐标系,所以在加载本地地理数据的时候,一定要先将本地的数据坐标系设置为WGS84,若设置成WGS84-Web Mercator或其他坐标系,则会产生偏差,使得数据无法叠加到一起。
在表示经纬度的时候,有度数制和弧度制两种,在开发过程中,经常要进行相互转换。Cesium中使用Cartographic表示弧度制的WGS84地理坐标系。
其本身是为GPS全球定位系统使用而建立的坐标系统,坐标原点为地球质心,其地心空间直角坐标系的Z轴指向BIH (国际时间服务机构)1984.O定义的协议地球极(CTP)方向,X轴指向BIH 1984.0的零子午面和CTP赤道的交点,Y轴与Z轴、X轴垂直构成右手坐标系。我们平常手机上的指南针显示的经纬度就是这个坐标系下当前的坐标,进度范围[-180,180],纬度范围[-90,90]。
我们都知道Cesium目前支持两种坐标系WGS84和WebMercator,但是在Cesium中没有实际的对象来描述WGS84坐标,都是以弧度的方式来进行运用的也就是Cartographic类:new Cesium.Cartographic(longitude, latitude, height),这里的参数也叫longitude、latitude,就是经度和纬度,计算方法:弧度= π/180×经纬度角度。
4D笛卡尔坐标系(Cartesian4)
暂时我还没用到过。
WebGL坐标系
Cesium使用WebGL进行图形渲染,因此WebGL坐标系也必须了解。在进行自定义渲染时需要用到WebGL坐标系,WebGL坐标系也是右手坐标系,X轴水平,正方向为右;Y轴垂直,正方向为上;Z轴垂直与屏幕,正方向为外。
3.2.2 坐标转换
Cesium 其实是一个封装好的 WebGL 库,当然这里面就牵扯到好几套坐标问题:屏幕坐标、三维空间坐标、投影坐标。而且坐标转换肯定是我们在开发任何地理信息系统中经常会碰到的问题,也比较复杂,简单总结了几种转换方式:
坐标系
平面坐标系(Cartesian2)
new Cesium.Cartesian2(1,1) //表示一个二维笛卡尔坐标系,也就是直角坐标系(屏幕坐标系)
笛卡尔空间直角坐标系-世界坐标系(Cartesian3)
new Cesium.Cartesian3(1,1,1) //表示一个三维笛卡尔坐标系,也是直角坐标系(就是真实世界的坐标系)
弧度(Cartographic)
new Cesium.Cartographic(longitude, latitude, height)
注:这里的经纬度是用弧度表示的,经纬度其实就是角度, 弧度即角度对应弧长是半径的倍数。
角度转弧度: π / 180 × 角度
弧度变角度: 180 / π × 弧度
经纬度(longitude, latitude)
地理坐标系,坐标原点在椭球的质心。
经度:参考椭球面上某点的大地子午面与本初子午面间的两面角。东正西负。
纬度:参考椭球面上某点的法线与赤道平面的夹角。北正南负。
地理坐标系弧度与经纬度转换
经纬度转弧度:var radians=Cesium.CesiumMath.toRadians(degrees)
弧度转经纬度:var degrees=Cesium.CesiumMath.toDegrees(radians)
我们来看下Cesium中源码的转换方法,其实就是:弧度= π/180×经纬度角度;经纬度角度=180/π×弧度。
CesiumMath.RADIANS_PER_DEGREE = Math.PI / 180.0;
CesiumMath.DEGREES_PER_RADIAN = 180.0 / Math.PI;
CesiumMath.toRadians = function(degrees) {
//>>includeStart('debug', pragmas.debug);
if (!defined(degrees)) {
throw new DeveloperError('degrees is required.');
}
//>>includeEnd('debug');
return degrees * CesiumMath.RADIANS_PER_DEGREE; };
CesiumMath.toDegrees = function(radians) { //>>includeStart('debug', pragmas.debug);
if (!defined(radians)) {
throw new DeveloperError('radians is required.');
}
//>>includeEnd('debug');
return radians * CesiumMath.DEGREES_PER_RADIAN;
};
经纬度坐标转换为笛卡尔空间直角坐标
经纬度坐标(WGS84)→ Cartesian3
第一种方式:直接转换:
Cesium.Cartesian3.fromDegrees(longitude, latitude, height, ellipsoid, result) //height为大地高度
Cesium.Cartesian3.fromDegreesArray(coordinates, ellipsoid, result) // coordinates未不带高度的数组
Cesium.Cartesian3.fromDegreesArrayHeights(coordinates, ellipsoid, result) // coordinates为带高度的数组
第二种方式:先转换成弧度再转换
var ellipsoid = viewer.scene.globe.ellipsoid; //var ellipsoid = Cesium.Ellipsoid.WGS84
var cartographic = Cesium.Cartographic.fromDegrees(lng,lat,alt);
var cartesian3 = ellipsoid.cartographicToCartesian(cartographic);
var cartesian3s = ellipsoid.cartographicArrayToCartesianArray(cartographics, result) //cartographics是cartographic数组
以上都是通过角度的经纬度进行转换,同理也可以使用弧度形式的经纬度,采用如下函数:
弧度坐标→ Cartesia
Cesium.Cartesian3.fromRadians(longitude, latitude, height, ellipsoid, result)
Cesium.Cartesian3.fromRadiansArray(coordinates, ellipsoid, result)
Cesium.Cartesian3.fromRadiansArrayHeights(coordinates, ellipsoid, result)
笛卡尔空间直角坐标系转经纬度
- 直接转换法
Cesium.Cartographic.fromCartesian(cartesian3, ellipsoid, result)
注意:转换得到是弧度坐标 ,需要经纬度自己在转一下
- 通过椭球体转换。可以根据椭球参数,将笛卡尔空间直角坐标转为wgs84坐标或者其他椭球下的经纬度坐标。以wgs84椭球为例:
Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian3, result)
Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(cartesians3, result)
屏幕坐标和笛卡尔空间直角坐标的转换
屏幕坐标转笛卡尔空间直角坐标常用于三维开发,Cesium根据不同场景设定三类屏幕坐标转笛卡尔坐标:
- 屏幕坐标转场景空间直角坐标,这里的场景坐标包含地形、倾斜摄影、测量模型等其他三维模型的坐标。目前IE浏览器不支持深度拾取,所以不适用此方法。
var cartesian3 = viewer.scene.pickPosition(Cartesian2)
- 屏幕坐标转地表笛卡尔空间坐标,包含地形在内,但是不包括倾斜摄影测量模型等其他三维模型的坐标。
var cartesian3 = viewer.scene.globe.pick(viewer.camera.getPickRay(Cartesian2),viewer.scene)
注意:屏幕坐标一定要在球上,否则生成的cartesian对象是undefined
- 屏幕坐标转椭球面笛卡尔空间坐标,不包含地形,倾斜摄影测量模型等其他三维模型的坐标。
var cartesian3 = viewer.scene.pickEllipsoid(Cartesian2)
笛卡尔空间直角坐标转屏幕坐标
Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, Cartesian3);
结果是Cartesian2对象,取出X,Y即为屏幕坐标。
Cartesian3->Cartesian2
Cesium.Cartesian2.fromCartesian3(cartesian, result)→ Cartesian2
计算两个三维坐标系之间的距离
var d = Cesium.Cartesian3.distance(
new Cesium.Cartesian3(pick1.x, pick1.y, pick1.z),
new Cesium.Cartesian3(pick3.x, pick3.y, pick3.z)
);
//pick1、pick3都是三维坐标系