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

相关推荐
乘风gg2 小时前
还在养虾吗?虾王已诞生:微信龙虾 ClawBot
前端·ai编程·claude
小小小小宇2 小时前
LLM 长期记忆构建
前端
lichenyang4533 小时前
从 Express 老项目到 NestJS + Docker:一次车辆管理系统的渐进式重构
前端
Momo__4 小时前
VueUse createReusableTemplate —— 单文件组件内的模板复用神器
前端·vue.js
程序员小富4 小时前
我开源了一个开发者专属的智能 JSON 工具,得到了媳妇高度认可
前端·vue.js·后端
小小小小宇4 小时前
程序员如何给 LLM 装工具以及看懂推理过程
前端
写代码的皮筏艇4 小时前
React中的forwardRef
前端·react.js·面试
槑有老呆4 小时前
花三个月工资请了个 AI 程序员,结果它连青岛啤酒股价都查不了
前端
风骏时光牛马4 小时前
Verilog开发常见问题汇总解析
前端
子兮曰4 小时前
AI Coding Method Map:一张图看懂 AI 编程的完整链路
前端·人工智能·后端