Cesium 坐标转换

696 阅读2分钟

Cesium 提供了丰富的坐标转换方法,用于在不同坐标系之间进行转换。以下是 Cesium 中常用的坐标系统及其转换方法:

一、Cesium 常用坐标系

  1. WGS84坐标系 (经纬度高程)

    • 标准地理坐标系
    • 格式: [经度, 纬度, 高度] (单位: 度, 度, 米)
  2. 笛卡尔空间直角坐标系 (Cartesian3)

    • Cesium 内部使用的三维直角坐标系
    • 原点在地球中心
    • 格式: new Cartesian3(x, y, z)
  3. 场景坐标 (屏幕像素坐标)

    • 二维屏幕坐标系
    • 格式: [x, y] (单位: 像素)

二、基本坐标转换方法

1. WGS84 ↔ Cartesian3

// 经纬度高程 → 笛卡尔坐标
const cartesian = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);

// 笛卡尔坐标 → 经纬度高程
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;

2. WGS84弧度 ↔ WGS84角度

// 角度转弧度
const radians = Cesium.Math.toRadians(degrees);

// 弧度转角度
const degrees = Cesium.Math.toDegrees(radians);

3. 屏幕坐标 ↔ 场景坐标

// 屏幕坐标 → 场景坐标(世界坐标)
const pickedObject = viewer.scene.pick(windowPosition);
if (Cesium.defined(pickedObject)) {
    const cartesian = viewer.scene.pickPosition(windowPosition);
}

// 场景坐标 → 屏幕坐标
const screenPosition = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, cartesian);

三、高级坐标转换

1. 坐标系转换(不同参考系)

固定坐标系 :与地球固连的坐标系,随地球一起旋转

惯性坐标系:不随地球旋转的宇宙空间参考系(卫星轨道计算)

// 固定坐标系 → 惯性坐标系
const fixedToInertial = Cesium.Matrix4.fromRotationTranslation(
    Cesium.Quaternion.fromHeadingPitchRoll(heading, pitch, roll),
    position
);

// 惯性坐标系 → 固定坐标系
const inertialToFixed = Cesium.Matrix4.inverse(fixedToInertial, new Cesium.Matrix4());

2. 坐标变换(平移旋转缩放)

// 创建变换矩阵
const transform = Cesium.Matrix4.fromTranslationRotationScale({
    translation: Cesium.Cartesian3.fromElements(x, y, z), 
    rotation: Cesium.Quaternion.fromHeadingPitchRoll(heading, pitch, roll),
    scale: new Cesium.Cartesian3(1.0, 1.0, 1.0)
});

// 变换后的位置
const transformedPosition = Cesium.Matrix4.multiplyByPoint(
    transform, 
    originalPosition, 
    new Cesium.Cartesian3()
);

3. 地形高度采样

// 获取某点的地形高度
const position = Cesium.Cartesian3.fromDegrees(longitude, latitude);
const height = viewer.scene.globe.getHeight(Cesium.Cartographic.fromCartesian(position));

// 或者使用采样方法
const promise = Cesium.sampleTerrain(viewer.terrainProvider, 11, [
    Cesium.Cartographic.fromDegrees(longitude, latitude)
]);
Cesium.when(promise, function(updatedPositions) {
    const height = updatedPositions[0].height;
});

四、实用工具函数

1. 计算两点间距离

const distance = Cesium.Cartesian3.distance(position1, position2);

// 或者计算地表距离
const geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(
    Cesium.Cartographic.fromCartesian(position1),
    Cesium.Cartographic.fromCartesian(position2)
);
const surfaceDistance = geodesic.surfaceDistance;

2. 计算方位角(Heading)

const heading = Cesium.Math.toDegrees(
    Cesium.Cartesian3.angleBetween(
        Cesium.Cartesian3.UNIT_X,
        Cesium.Cartesian3.normalize(position, new Cesium.Cartesian3())
    )
);

3. 坐标插值

// 线性插值
const interpolated = Cesium.Cartesian3.lerp(
    startPosition,
    endPosition,
    t, // 插值系数 [0,1]
    new Cesium.Cartesian3()
);

// 球面线性插值
const interpolated = Cesium.Cartesian3.slerp(
    startPosition,
    endPosition,
    t,
    new Cesium.Cartesian3()
);

五、常见问题解决方案

问题1:pickPosition获取的坐标不准确

// 解决方法1: 开启深度测试
viewer.scene.globe.depthTestAgainstTerrain = true;

// 解决方法2: 使用更精确的pick方法
const ray = viewer.camera.getPickRay(windowPosition);
const position = viewer.scene.globe.pick(ray, viewer.scene);

问题2:坐标转换精度问题

// 使用高精度计算方法
const cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(
    cartesian, 
    new Cesium.Cartographic()
);

问题3:大量坐标转换性能优化

// 重用对象减少内存分配
const scratchCartographic = new Cesium.Cartographic();
const result = new Cesium.Cartesian3();

function convert(cartesian) {
    return Cesium.Ellipsoid.WGS84.cartesianToCartographic(
        cartesian, 
        scratchCartographic
    );
}