Cesium中的坐标系及其转换

20 阅读6分钟

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.Matrix33x3矩阵,描述旋转变换
Cesium.Matrix44x4矩阵,描述旋转+平移变换
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来精确表达你的空间数据。