首先 Cesium 中如果绘制三维物体,都需要将不同的坐标转换为笛卡尔坐标系,也就是 Cartesian3 类型的数据;这是 Cesium 的基础数据类型。Cesium 中常见的坐标系有 wgs84 经纬度坐标系、wgs84 弧度坐标系(Cartographic,弧度= π/180 × 经纬度角度)、笛卡尔空间直角坐标系(Cartesian3)、平面坐标系(Cartesian2)、4D 笛卡坐标系(Cartesian4),下面是列举了我们常见的一些坐标系转换为 Cartesian3 类型数据以及一些坐标的互转。
需要注意的是 cesium 目前支持两种坐标系,wgs84 以及 WebMercator(笛卡尔坐标系)
# 坐标系
# 笛卡尔坐标系(Cartesian3)
- 笛卡尔坐标系以米为单位;
- 坐标系原点是地球几何中心;
- xz 平面是中央经线和 180 度经线组成的平面,其中 x 轴正方向指向的是中央经线,x 轴负方向指向 180 度经线;
- y 轴正方向指向东经 90 度经线,负方向指向西经 90 度经线。
# 平面坐标系(Cartesian2)
与 Cartesian3 相比少了一个 z 的分量;
# 坐标系转换
# 经纬度转换为 Cartesian3 类型
- Cesium.Cartesian3.fromRadians:从给定的经度和弧度值返回 Cartesian3。注意这里的经纬度是 wgs84 转换成弧度的经纬度。
Cartesian3.fromRadians = function ( longitude, latitude, height, ellipsoid, result ) {
// 检验经纬度是否符合标准
Check.typeOf.number("longitude", longitude);
Check.typeOf.number("latitude", latitude);
// 如果高度为空,默认为 0
height = defaultValue(height, 0.0);
// 如果为传入参考椭球体,默认使用 wgs 84 坐标系下进行转换
var radiiSquared = defined(ellipsoid)
? ellipsoid.radiiSquared
: wgs84RadiiSquared;
var cosLatitude = Math.cos(latitude);
scratchN.x = cosLatitude * Math.cos(longitude);
scratchN.y = cosLatitude * Math.sin(longitude);
scratchN.z = Math.sin(latitude);
scratchN = Cartesian3.normalize(scratchN, scratchN);
Cartesian3.multiplyComponents(radiiSquared, scratchN, scratchK);
var gamma = Math.sqrt(Cartesian3.dot(scratchN, scratchK));
scratchK = Cartesian3.divideByScalar(scratchK, gamma, scratchK);
scratchN = Cartesian3.multiplyByScalar(scratchN, height, scratchN);
if (!defined(result)) {
result = new Cartesian3();
}
return Cartesian3.add(scratchK, scratchN, result);
};
示例:
var position = Cesium.Cartesian3.fromRadians(-2.007, 0.645)
# 经纬度和弧度的转换
具体看官方文档 https://cesium.com/docs/cesiumjs-ref-doc/Math.html?classFilter=Math
- 经纬度转弧度
const radians = Cesium.Math.toRadians(degrees)
- 弧度转经纬度
const degrees = Cesium.Math.toDegrees(radians)
# wgs84 经纬度坐标和 wgs84 弧度坐标系(Cartographic)的转换
- 第一种方法就是先将角度用上面的方法转换为弧度,再进行转换
const longitude = Cesium.Math.toRadians(longitude1) // 其中 longitude1 为角度
const latitude= Cesium.Math.toRadians(latitude1) // 其中 latitude1 为角度
const cartographic = new Cesium.Cartographic(longitude, latitude, height)
- 第二种方法:直接转换
// longitude 和 latitude 为角度
const cartographic= Cesium.Cartographic.fromDegrees(longitude, latitude, height)
- 第三种
// longitude 和 latitude 为弧度
const cartographic= Cesium.Cartographic.fromRadians(longitude, latitude, height)
# wgs84 坐标系和笛卡尔空间直角坐标系(Cartesian3)的转换
下面是经纬度坐标转换为空间直角坐标系(Cartesian3):
// 高度默认值为 0,可以不用填写,longitude 和 latitude 为角度
const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
// coordinates 为不带高度的数组。例如:[113.0, 37.0, 113.0, 23]
const positions = Cesium.Cartesian3.fromDegreesArray(coordinates)
// coordinates 为带有高度的数组。例如:[-115.0, 37.0, 100000.0, -107.0, 33.0, 150000.0]
const positions = Cesium.Cartesian3.fromDegreesArrayHeights(coordinates)
对应的,有通过弧度转化的方法,具体有 Cesium.Cartesian3.fromRadians,Cesium.Cartesian3.fromRadiansArray,Cesium.Cartesian3.fromRadiansArrayHeights 等方法,用法跟上面相同。
需要注意的是,上面转换函数中最后均有一个默认参数 ellipsoid(默认值为 Ellipsoid.WGS84)这个是参考椭球体。
# 笛卡尔空间直角坐标系(Cartesian3)转换为 wgs84
- 第一种:直接转换,转换为弧度
const cartographic = Cesium.Cartographic.fromCartesian(cartesian3)
- 第二种:间接转化,转换为角度
const ellipsoid = viewer.scene.globe.ellipsoid
const cartesian3 = new Cesium.cartesian3(x,y,z)
const cartographic = ellipsoid.cartesianToCartographic(cartesian3)
const lat = Cesium.Math.toDegrees(cartograhphic.latitude)
const lng = Cesium.Math.toDegrees(cartograhpinc.longitude)
const alt = cartographic.height
# 屏幕坐标和笛卡尔空间直角坐标系(Cartesian3)的转换
- 屏幕转笛卡尔空间直角坐标系(Cartesian3):
const pick1 = new Cesium.Cartesian2(0, 0)
const cartesian3 = viewer.scene.globe.pick(viewer.camera.getPickRay(pick1), viewer.scene)
注意这里屏幕坐标一定要在球上,否则生成出的 cartesian 对象是 undefined
- 笛卡尔空间直角坐标系(Cartesian3)转屏幕坐标:
const cartesian2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, cartesian3)
结果是 Cartesian2 对象,取出 X, Y 即为屏幕坐标;
# Cartesian3 转为 Cartesian2
const cartesian2 = Cesium.Cartesian2.fromCartesian3(cartesian, result)
# 其他方法
# 计算两个三维坐标系之间的距离
// pick1、pick3 都是三维坐标系
const d = Cesium.Cartesian3.distance(
new Cesium.Cartesian3(pick1.x, pick1.y, pick1.z),
new Cesium.Cartesian3(pick3.x, pick3.y, pick3.z)
)
# 笛卡尔坐标系转换的一些 API
API | 说明 |
---|---|
Cesium.Cartesian3.abs(cartesian, result) | 计算绝对值 |
Cesium.Cartesian3.add(left, right, result) | 计算两个笛卡尔的分量和 |
Cesium.Cartesian3.angleBetween(left, right) | 计算角度(弧度制) |
Cesium.Cartesian3.cross(left, right, result) | 计算叉积 |
Cesium.Cartesian3.distance(left, right) | 计算两点距离 |
Cesium.Cartesian3.distanceSquared(left, right) | 计算两点平方距离 |
Cesium.Cartesian3.divideByScalar(cartesian, scalar, result) | 计算标量除法 |
Cesium.Cartesian3.divideComponents(left, right, result) | 计算两点除法 |
Cesium.Cartesian3.dot(left, right) | 计算点乘 |
Cesium.Cartesian3.equals(left, right) | 比较两点是否相等 |
Cesium.Cartesian3.fromArray(array, startingIndex, result) | 从数组中提取3个数构建笛卡尔坐标 |
Cesium.Cartesian3.fromDegrees(longitude, latitude, height, ellipsoid, result) | 将将纬度转换为笛卡尔坐标(单位是度°) |
Cesium.Cartesian3.fromDegreesArray(coordinates, ellipsoid, result) | 返回给定经度和纬度值数组(以度为单位)的笛卡尔位置数组。 |
Cesium.Cartesian3.fromDegreesArrayHeights(coordinates, ellipsoid, result) | 返回给定经度,纬度和高度的笛卡尔位置数组 |
Cesium.Cartesian3.fromElements(x, y, z, result) 创建一个新的笛卡尔坐标 | |
Cesium.Cartesian3.fromRadians(longitude, latitude, height, ellipsoid, result) | 返回笛卡尔坐标以弧度制的经纬度 |
Cesium.Cartesian3.fromRadiansArray(coordinates, ellipsoid, result) | 返回笛卡尔坐标以弧度制的经纬度数组 |
Cesium.Cartesian3.fromRadiansArrayHeights(coordinates, ellipsoid, result) | 返回笛卡尔坐标以弧度制的经纬度高度数组 |
Cesium.Cartesian3.fromSpherical(spherical, result) | 将提供的球面转换为笛卡尔系 |
Cesium.Cartesian3.lerp(start, end, t, result) | 使用提供的笛卡尔数来计算t处的线性插值或外推。 |
Cesium.Cartesian3.magnitude(cartesian) | 计算笛卡尔长度 |
Cesium.Cartesian3.magnitudeSquared(cartesian) | 计算提供的笛卡尔平方量级 |
Cesium.Cartesian3.maximumByComponent(first, second, result) | 比较两个笛卡尔并计算包含所提供笛卡尔最大成分的笛卡尔。 |
Cesium.Cartesian3.maximumComponent(cartesian) | 计算所提供笛卡尔坐标系的最大分量的值 |
Cesium.Cartesian3.midpoint(left, right, result) | 计算右笛卡尔和左笛卡尔之间的中点 |
Cesium.Cartesian3.minimumByComponent(first, second, result) | 比较两个笛卡尔并计算包含所提供笛卡尔的最小分量的笛卡尔 |
Cesium.Cartesian3.minimumComponent(cartesian) | 计算所提供笛卡尔坐标系的最小分量的值 |
Cesium.Cartesian3.mostOrthogonalAxis(cartesian, result) | 返回与提供的笛卡尔坐标最正交的轴 |
Cesium.Cartesian3.multiplyByScalar(cartesian, scalar, result) | 将提供的笛卡尔分量乘以提供的标量 |
Cesium.Cartesian3.multiplyComponents(left, right, result) | 计算两个笛卡尔的分量积 |
Cesium.Cartesian3.normalize(cartesian, result) | 计算所提供笛卡尔的规范化形式 |
Cesium.Cartesian3.pack(value, array, startingIndex) | 将提供的实例存储到提供的数组中 |
Cesium.Cartesian3.projectVector(a, b, result) | 将向量a投影到向量 b 上 |
Cesium.Cartesian3.subtract(left, right, result) | 计算两个笛卡尔分量差 |
Cesium.Cartesian3.unpack(array, startingIndex, result) | 从压缩的数组中检索实例 |
Cesium.Cartesian3.unpackArray(array, result) | 将笛卡尔分量数组解包为笛卡尔数组 |
# HeadingPitchRoll
HeadingPitchRoll 表示朝向。
# Camera 一些常用方法
Camera.setView(options) : 立即设置相机位置和朝向。
Camera.zoomIn(amount) : 沿着相机方向移动相机。
Camera.zoomOut(amount) : 沿着相机方向远离
Camera.flyTo(options) : 创建从一个位置到另一个位置的相机飞行动画。
Camera.lookAt(target, offset) : 依据目标偏移来设置相机位置和朝向。
Camera.move(direction, amount) : 沿着direction方向移动相机。
Camera.rotate(axis, angle) : 绕着任意轴旋转相机。
# scene 中时间的配置
Cesium 使用 JulianDate 描述某个时刻。
// 设置时钟和时间线
viewer.clock.shouldAnimate = true; // 当 viewer 开启后,启动动画
viewer.clock.startTime = Cesium.JulianDate.fromIso8601("2017-07-11T16:00:00Z")
viewer.clock.stopTime = Cesium.JulianDate.fromIso8601("2017-07-11T16:20:00Z")
viewer.clock.currentTime = Cesium.JulianDate.fromIso8601("2017-07-11T16:00:00Z")
viewer.clock.multiplier = 2 // 设置加速倍率
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP // 循环播放
viewer.timeline.zoomTo(viewer.clock.startTime, viewer.clock.stopTime) // 设置时间的可见范围
# Cesium 加载其他数据
Cesium 支持 GeoJson 和 KML 等格式的数据,同时也支持自定义格式 CZML。无论最初是什么格式,所有的空间矢量数据在 Cesium 里都是使用 Entity 相关 API 去展示的, Entity是 一种对几何图形做空间和时间展示的数据对象。
下面代码是加载 kml 数据并解析展示对应数据:
// 使用 KmlDataSource.load(optinos) 来从 KML 文件中读取点位数据
const kmlOptions = {
camera: viewer.scene.camera,
canvas: viewer.scene.canvas,
clampToGround: true // 控制数据是否贴地
}
// 加载数据
const geocachePromise = Cesium.KmlDataSource.load('./Source/sample.kml', kmlOptions)
geocachePromise.then(function(dataSource) {
// 把所有 entities 添加到 viewer 中显示
viewer.dataSources.add(dataSource)
// 获得 entity 列表
const geocacheEntities = dataSource.entities.values
for (let i = 0; i < geocacheEntities.length; i++) {
const entity = geocacheEntities[i];
if (Cesium.defined(entity.billboard)) {
// 对这个 entity 设置样式
}
}
})
← cesium常见问题 threejs笔记 →