Cesium中的坐标系及其转换

Cesium中的坐标系及其转换

引言

Cesium作为一款强大的三维地球和地图可视化引擎,其核心魅力在于能够在虚拟空间中精准地表达地理信息。而这一切的基础,正是Cesium中精心设计的坐标系系统。无论是放置一个标记、绘制一条航线,还是模拟卫星运动,都离不开对坐标系的理解和运用。本文将系统介绍Cesium中的主要坐标系,并详细说明它们之间的转换方法,帮助你在开发中游刃有余地处理各种空间数据。

一、Cesium中的主要坐标系

Cesium涉及四类核心坐标系,它们分别服务于不同的应用场景。

1.1 屏幕坐标(Cartesian2)

屏幕坐标是二维笛卡尔坐标系,以像素为单位描述屏幕上的位置。其原点位于屏幕(Canvas)的左上角,水平向右为X轴正方向,垂直向下为Y轴正方向。

javascript 复制代码
// 创建一个屏幕坐标点 (x=100, y=200)
const screenPosition = new Cesium.Cartesian2(100, 200);

屏幕坐标常用于处理鼠标交互,例如获取鼠标点击位置的像素坐标。

1.2 笛卡尔空间直角坐标(Cartesian3)

笛卡尔空间直角坐标,又称世界坐标,是Cesium中最核心的坐标系。它以地球几何中心为原点,使用 作为单位,通过Cesium.Cartesian3(x, y, z)表示。

在这个坐标系中:

  • X轴:指向本初子午线与赤道的交点
  • Y轴:指向东经90度经线与赤道的交点
  • Z轴:指向北极
javascript 复制代码
// 创建一个笛卡尔坐标点
const worldPosition = new Cesium.Cartesian3(1215000.0, -4736000.0, 4081000.0);

重要提示:Cesium平台内所有用到坐标的地方,核心都是Cartesian3对象。无论是实体位置、相机位置,还是模型变换,最终都会转换为Cartesian3进行计算。

1.3 地理坐标(Cartographic)

地理坐标是更符合人类认知的坐标系,它基于WGS84椭球体模型,使用经度、纬度、高度 来描述位置。但在Cesium内部,地理坐标的经度和纬度是以弧度而非角度存储的。

javascript 复制代码
// 创建地理坐标(弧度制)
const cartographic = new Cesium.Cartographic(
    Cesium.Math.toRadians(116.3975), // 经度:116.3975度转弧度
    Cesium.Math.toRadians(39.9075),  // 纬度:39.9075度转弧度
    50.0                              // 高度:50米
);

由于弧度值对人不直观,我们通常通过工具函数进行度和弧度的转换:

javascript 复制代码
// 度转弧度
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(国际天文参考坐标系)。在这个框架中,星空是静止的,地球自身在旋转。它对于需要精确模拟天体运动和卫星轨道的场景至关重要。

javascript 复制代码
// 在CZML中指定使用惯性参考系
{
    id: "satellite",
    position: {
        referenceFrame: "INERTIAL", // 设置为惯性系
        cartesian: [x, y, z]        // 惯性系下的坐标
    }
}

二、坐标系之间的转换

理解了各类坐标系后,掌握它们之间的转换方法同样重要。Cesium提供了丰富的API来完成这些转换。

2.1 WGS84地理坐标 ↔ 笛卡尔坐标

这是开发中最常用的转换。Cesium提供了便捷的静态方法,可以直接将经纬度(度)转换为笛卡尔坐标。

javascript 复制代码
// 经纬度(度)→ 笛卡尔坐标
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
]);

逆向转换(笛卡尔 → 地理坐标)同样简单:

javascript 复制代码
// 笛卡尔坐标 → 地理坐标(弧度制)
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 屏幕坐标 ↔ 笛卡尔坐标

屏幕坐标与笛卡尔坐标的转换常用于实现鼠标拾取功能。

屏幕坐标 → 笛卡尔坐标有三种层次:

javascript 复制代码
// 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工具:

javascript 复制代码
// 将世界坐标转换为窗口坐标(像素位置)
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使用地固系(地球静止)。如果要观察卫星在惯性系中的运动,需要将相机固定在惯性系中,让地球旋转起来:

javascript 复制代码
// 每一帧更新时,将相机固定在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计算月球在惯性系中的位置:

javascript 复制代码
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来精确表达你的空间数据。

相关推荐
小付学代码2 小时前
香港地图可编辑版
前端
兆子龙2 小时前
TypeScript高级类型编程:从入门到精通
前端·后端
SuperEugene2 小时前
Vue3 模板语法规范实战:v-if/v-for 不混用 + 表达式精简,避坑指南|Vue 组件与模板规范篇
开发语言·前端·javascript·vue.js·前端框架
IT_陈寒2 小时前
Python开发者的效率革命:这5个技巧让你的代码提速50%!
前端·人工智能·后端
Luna-player2 小时前
Vue 3 + Vue Router 的路由配置,简单示例
前端·javascript·vue.js
用户69371750013842 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
xiaotao1312 小时前
03. 原子化 CSS 思想
前端·css·tailwind
小小亮012 小时前
qiankun的面试题
前端