Cesium中的坐标系及其转换
引言
Cesium作为一款强大的三维地球和地图可视化引擎,其核心魅力在于能够在虚拟空间中精准地表达地理信息。而这一切的基础,正是Cesium中精心设计的坐标系系统。无论是放置一个标记、绘制一条航线,还是模拟卫星运动,都离不开对坐标系的理解和运用。本文将系统介绍Cesium中的主要坐标系,并详细说明它们之间的转换方法,帮助你在开发中游刃有余地处理各种空间数据。
一、Cesium中的主要坐标系
Cesium涉及四类核心坐标系,它们分别服务于不同的应用场景。
1.1 屏幕坐标(Cartesian2)
屏幕坐标是二维笛卡尔坐标系,以像素为单位描述屏幕上的位置。其原点位于屏幕(Canvas)的左上角,水平向右为X轴正方向,垂直向下为Y轴正方向。
// 创建一个屏幕坐标点 (x=100, y=200)
const screenPosition = new Cesium.Cartesian2(100, 200);
屏幕坐标常用于处理鼠标交互,例如获取鼠标点击位置的像素坐标。
1.2 笛卡尔空间直角坐标(Cartesian3)
笛卡尔空间直角坐标,又称世界坐标,是Cesium中最核心的坐标系。它以地球几何中心为原点,使用米作为单位,通过Cesium.Cartesian3(x, y, z)表示。
在这个坐标系中:
- X轴:指向本初子午线与赤道的交点
- Y轴:指向东经90度经线与赤道的交点
- Z轴:指向北极
// 创建一个笛卡尔坐标点
const worldPosition = new Cesium.Cartesian3(1215000.0, -4736000.0, 4081000.0);
重要提示:Cesium平台内所有用到坐标的地方,核心都是Cartesian3对象。无论是实体位置、相机位置,还是模型变换,最终都会转换为Cartesian3进行计算。
1.3 地理坐标(Cartographic)
地理坐标是更符合人类认知的坐标系,它基于WGS84椭球体模型,使用经度、纬度、高度来描述位置。但在Cesium内部,地理坐标的经度和纬度是以弧度而非角度存储的。
// 创建地理坐标(弧度制)
const cartographic = new Cesium.Cartographic(
Cesium.Math.toRadians(116.3975), // 经度:116.3975度转弧度
Cesium.Math.toRadians(39.9075), // 纬度:39.9075度转弧度
50.0 // 高度:50米
);
由于弧度值对人不直观,我们通常通过工具函数进行度和弧度的转换:
// 度转弧度
const radians = Cesium.Math.toRadians(degrees);
// 弧度转度
const degrees = Cesium.Math.toDegrees(radians);
1.4 参考框架:地固系与地惯系
除了上述基础坐标系,Cesium还提供了两个重要的参考框架概念,用于处理动态的空间关系。
地固系(FIXED / ECEF)
地固系(Earth-Centered, Earth-Fixed)是Cesium的默认参考框架。在这个框架中,地球本身是静止的,星空围绕地球旋转。它适用于大多数需要将物体固定在地球表面上的场景,如标记城市、绘制道路等。
地惯系(INERTIAL / ICRF)
地惯系(Earth-Centered Inertial),在Cesium中称为ICRF(国际天文参考坐标系)。在这个框架中,星空是静止的,地球自身在旋转。它对于需要精确模拟天体运动和卫星轨道的场景至关重要。
// 在CZML中指定使用惯性参考系
{
id: "satellite",
position: {
referenceFrame: "INERTIAL", // 设置为惯性系
cartesian: [x, y, z] // 惯性系下的坐标
}
}
二、坐标系之间的转换
理解了各类坐标系后,掌握它们之间的转换方法同样重要。Cesium提供了丰富的API来完成这些转换。
2.1 WGS84地理坐标 ↔ 笛卡尔坐标
这是开发中最常用的转换。Cesium提供了便捷的静态方法,可以直接将经纬度(度)转换为笛卡尔坐标。
// 经纬度(度)→ 笛卡尔坐标
const position = Cesium.Cartesian3.fromDegrees(
116.3975, // 经度
39.9075, // 纬度
50.0 // 高度(米)
);
// 批量转换多个点(不带高度)
const positions = Cesium.Cartesian3.fromDegreesArray([
116.3975, 39.9075,
121.4737, 31.2304
]);
// 批量转换多个点(带高度)
const positionsWithHeight = Cesium.Cartesian3.fromDegreesArrayHeights([
116.3975, 39.9075, 50.0,
121.4737, 31.2304, 20.0
]);
逆向转换(笛卡尔 → 地理坐标)同样简单:
// 笛卡尔坐标 → 地理坐标(弧度制)
const cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
// 或使用椭球体方法
const cartographic2 = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian3);
// 弧度制转角度制
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
2.2 屏幕坐标 ↔ 笛卡尔坐标
屏幕坐标与笛卡尔坐标的转换常用于实现鼠标拾取功能。
屏幕坐标 → 笛卡尔坐标有三种层次:
// 1. 获取包含地形、模型、倾斜摄影的坐标
const pickPosition = viewer.scene.pickPosition(screenCoord);
// 2. 获取地球表面坐标(包含地形,不包含模型)
const globePosition = viewer.scene.globe.pick(
viewer.camera.getPickRay(screenCoord),
viewer.scene
);
// 3. 获取参考椭球面坐标(不包含地形和模型)
const ellipsoidPosition = viewer.scene.camera.pickEllipsoid(screenCoord);
笛卡尔坐标 → 屏幕坐标使用SceneTransforms工具:
// 将世界坐标转换为窗口坐标(像素位置)
const windowCoord = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
viewer.scene,
worldPosition
);
// 如果需要考虑高分屏适配,可使用wgs84ToDrawingBufferCoordinates
const drawingBufferCoord = Cesium.SceneTransforms.wgs84ToDrawingBufferCoordinates(
viewer.scene,
worldPosition
);
2.3 空间位置变换
坐标转换的最终目的往往是为了进行空间变换。Cesium提供了强大的数学工具支持:
| 工具类 | 用途 |
|---|---|
Cesium.Cartesian3 | 表示三维点、向量 |
Cesium.Matrix3 | 3x3矩阵,描述旋转变换 |
Cesium.Matrix4 | 4x4矩阵,描述旋转+平移变换 |
Cesium.Quaternion | 四元数,描述绕任意轴的旋转 |
Cesium.Transforms | 参考系转换工具 |
重要原则:所有空间变换(平移、旋转、缩放)都需要在笛卡尔坐标系(Cartesian3)中进行。
三、参考框架转换实战
3.1 将相机固定在惯性系
默认情况下Cesium使用地固系(地球静止)。如果要观察卫星在惯性系中的运动,需要将相机固定在惯性系中,让地球旋转起来:
// 每一帧更新时,将相机固定在ICRF惯性系(需要开启动画(shouldAnimate)及加快倍速更明显)
function icrf(scene, time) {
if (scene.mode !== Cesium.SceneMode.SCENE3D) {
return;
}
// 计算ICRF到地固系的旋转矩阵
const icrfToFixed = Cesium.Transforms.computeIcrfToFixedMatrix(time);
if (Cesium.defined(icrfToFixed)) {
const camera = viewer.camera;
const offset = Cesium.Cartesian3.clone(camera.position);
const transform = Cesium.Matrix4.fromRotationTranslation(icrfToFixed);
camera.lookAtTransform(transform, offset);
}
}
// 添加帧更新监听
viewer.scene.postUpdate.addEventListener(icrf);
这段代码的效果是:星空和卫星轨道保持静止,而地球在画面中缓慢旋转。
3.2 在惯性系中计算月球位置
对于需要精确模拟天体运动的场景,可以使用Simon1994PlanetaryPositions计算月球在惯性系中的位置:
const time = Cesium.JulianDate.now();
const moonPosition = new Cesium.Cartesian3();
Cesium.Simon1994PlanetaryPositions.computeMoonPositionInEarthInertialFrame(
time,
moonPosition
);
console.log('月球在惯性系中的位置:', moonPosition);
总结
Cesium的坐标系系统可以归纳为三个层次:
| 坐标系类型 | 表示方式 | 单位 | 应用场景 |
|---|---|---|---|
| 屏幕坐标 | Cartesian2 | 像素 | 鼠标交互、UI定位 |
| 笛卡尔坐标 | Cartesian3 | 米 | 空间计算、模型变换 |
| 地理坐标 | Cartographic | 弧度/米 | 数据输入输出 |
| 参考框架 | FIXED/INERTIAL | - | 动态场景模拟 |
掌握这些坐标系及其转换方法,是高效开发Cesium应用的基础。无论是简单的地理标记,还是复杂的卫星轨道模拟,你都能找到合适的工具和API来精确表达你的空间数据。