简介
cesium 各种坐标转换记录 主要坐标类型说明:
-
笛卡尔平面坐标(屏幕坐标)
-
笛卡尔三维空间坐标
-
wgs84 经纬度坐标
-
wgs84 弧度坐标
-
大地2000 坐标系
弧度与角度相互转换
// 角度转弧度
const radius = Cesium.Math.toRadius(degress)
// 弧度转角度
const degress = Cesium.Math.toDegress(radius)
wgs84 经纬度转笛卡尔坐标
1、直接通过经纬度转换
// wgs84经纬度转笛卡尔坐标
// 角度制与笛卡尔转换
// 格式:[113.21, 25.61, 100.0],高度默认为0,可以不写
let cartesian3 = Cesium.Cartesian3.fromDegrees(lon, lat, height);
// 格式:[113.21, 25.61, 113.54, 25.24],不带高度格式的数组
let cartesian3s = Cesium.Cartesian3.fromDegreesArray(coordinates);
// 格式:[113.21, 25.61, 100.0, 113.54, 25.24, 200.0],带高度格式的数组
let cartesian3s = Cesium.Cartesian3.fromDegreesArrayHeights(coordinates);
// 弧度制也类似,使用Cesium.Cartesian3.fromRadians, Cesium.Cartesian3.fromRadiansArray, Cesium.Cartesian3.fromRadiansArrayHeights
2、使用椭球体转换
let position = Cesium.Cartographic.fromDegrees(lon, lat, height);
// 单个坐标
let cartesian3 = Cesium.Ellipsoid.WGS84.cartographicToCartesian(position);
// 多个坐标
let cartesian3s =
Cesium.Ellipsoid.WGS84.cartographicArrayToCartesianArray(positions);
屏幕转笛卡尔(Cartesian2 转 Cartesian3)
1、屏幕转椭球面笛卡尔坐标,不包含地形、模型等的坐标,由于不包含材质这里的坐标误差较大
let cartesain3 = viewer.scene.camera.pickEllipsoid(cartesian2);
2、屏幕转场景坐标,包含地形和模型等的场景空间坐标, 拾取点击模型表面的坐标
let cartesian3 = viewer.scene.pickPosition(cartesian2);
3、获取点击处地球表面的世界坐标(有地形),注意:不包括模型、倾斜摄影表面。
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (event) {
var ray = viewer.camera.getPickRay(event.position);
var position = viewer.scene.globe.pick(ray, viewer.scene);
console.log("获取到的坐标:", position);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
4、屏幕转场景坐标,获取当前位置所有对象列表,适用于多个对象重叠在一个位置,并且要获取到多个对象的情况
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (event) {
var pickedObjects = scene.drillPick(event.position);
// pickedObjects 使用for循环 可以拿到所有entity
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
笛卡尔转屏幕(Cartesian3转Cartesian2)
let cartesian2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, cartesian3);
椭球笛卡尔坐标与局部笛卡尔坐标
笛卡尔坐标系都是默认指以椭球中心为原点的空间直角坐标系,在绘图时使用。
而在建立模型或者局部计算时,则需要在计算时使用局部坐标,再转换为椭球笛卡尔坐标后绘图。
1、建立转换矩阵
使用Transforms的eastNorthUpToFixedFrame方法建立转换矩阵,API:传送门
则该点为局部坐标系的中心,坐标为(0, 0, 0),x轴指向东方向,y轴指向北方向,z轴指穿过该位置的椭球曲面法线方向。
// 新建局部坐标系
let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(cartesian3);
2、局部转椭球笛卡尔
基于上文建立四维转换矩阵,使用Matrix4中的multiplyByPoint方法将局部坐标转换为椭球笛卡尔坐标。API参考:传送门
// point:局部坐标;result:椭球笛卡尔坐标
let result = Cesium.Matrix4.multiplyByPoint(modelMatrix, point, new Cesium.Cartesian3());
经纬度转大地2000
/**
* _lon: 表示中央子午线,根据实际情况配置
* 这里是102E
*/
function WGS84ToCGCS2000(lon, lat, _lon) {
let iPI = 0.0174532925199433; //3.1415926575898/180.0
let a = 6378137.0; //长半轴
let f = 1 / 298.257222101; //扁率
let _lon2rad = _lon * iPI; //中央子午线转为弧度
let lon2rad = lon * iPI; //经度转为弧度
let lat2rad = lat * iPI; //纬度转为弧度
//计算椭圆偏心率
const e = 2 * f - f * f;
const ee = e * (1 - e);
//计算曲率半径
const NN = a / Math.sqrt(1.0 - e * Math.sin(lat2rad) * Math.sin(lat2rad));
const T = Math.tan(lat2rad) * Math.tan(lat2rad);
const C = ee * Math.cos(lat2rad) * Math.cos(lat2rad);
const A = (lon2rad - _lon2rad) * Math.cos(lat2rad);
//计算子午线弧长
const M =
a *
((1 - e / 4 - (3 * e * e) / 64 - (5 * Math.pow(e, 3)) / 256) * lat2rad -
((3 * e) / 8 + (3 * e * e) / 32 + (45 * Math.pow(e, 3)) / 1024) *
Math.sin(2 * lat2rad) +
((15 * e * e) / 256 + (45 * Math.pow(e, 3)) / 1024) *
Math.sin(4 * lat2rad) -
((35 * Math.pow(e, 3)) / 3072) * Math.sin(6 * lat2rad));
let xval =
NN *
(A +
((1 - T + C) * Math.pow(A, 3)) / 6 +
((5 - 18 * T + T * T + 72 * C - 58 * ee) * Math.pow(A, 5)) / 120);
const yval =
M +
NN *
Math.tan(lat2rad) *
((A * A) / 2 +
((5 - T + 9 * C + 4 * C * C) * Math.pow(A, 4)) / 24 +
((61 - 58 * T + T * T + 600 * C - 330 * ee) * Math.pow(A, 6)) /
720);
const X0 = 500000;
const Y0 = 0;
xval = xval + X0;
console.log('经纬度坐标转大地2000坐标',[lon, lat],[xval, yval])
return [xval, yval];
}
大地2000转经纬度
function CGCS2000ToWGS84(X, Y, _lon) {
let L0 = 102; //中央子午线需根据实际情况设置
let lat, lon;
X -= 500000;
let result = [];
let iPI = 0.0174532925199433; //pi/180
let a = 6378137.0; //长半轴 m
let b = 6356752.31414; //短半轴 m
let f = 1 / 298.257222101; //扁率 a-b/a
let e = 0.0818191910428; //第一偏心率 Math.sqrt(5)
let ee = Math.sqrt(a * a - b * b) / b; //第二偏心率
let bf = 0; //底点纬度
let a0 =
1 +
(3 * e * e) / 4 +
(45 * Math.pow(e, 4)) / 64 +
(175 * Math.pow(e, 6)) / 256 +
(11025 * Math.pow(e, 8)) / 16384 +
(43659 * Math.pow(e, 10)) / 65536;
let b0 = Y / (a * (1 - e * e) * a0);
let c1 =
(3 * e * e) / 8 +
(3 * Math.pow(e, 4)) / 16 +
(213 * Math.pow(e, 6)) / 2048 +
(255 * Math.pow(e, 8)) / 4096;
let c2 =
(21 * Math.pow(e, 4)) / 256 +
(21 * Math.pow(e, 6)) / 256 +
(533 * Math.pow(e, 8)) / 8192;
let c3 = (151 * Math.pow(e, 8)) / 6144 + (151 * Math.pow(e, 8)) / 4096;
let c4 = (1097 * Math.pow(e, 8)) / 131072;
bf =
b0 +
c1 * Math.sin(2 * b0) +
c2 * Math.sin(4 * b0) +
c3 * Math.sin(6 * b0) +
c4 * Math.sin(8 * b0); // bf =b0+c1*sin2b0 + c2*sin4b0 + c3*sin6b0 +c4*sin8b0 +...
let tf = Math.tan(bf);
let n2 = ee * ee * Math.cos(bf) * Math.cos(bf); //第二偏心率平方成bf余弦平方
let c = (a * a) / b;
let v = Math.sqrt(1 + ee * ee * Math.cos(bf) * Math.cos(bf));
let mf = c / (v * v * v); //子午圈半径
let nf = c / v; //卯酉圈半径
//纬度计算
lat =
bf -
(tf / (2 * mf)) *
X *
(X / nf) *
(1 -
(1 / 12) *
(5 + 3 * tf * tf + n2 - 9 * n2 * tf * tf) *
((X * X) / (nf * nf)) +
(1 / 360) *
(61 + 90 * tf * tf + 45 * Math.pow(tf, 4)) *
(Math.pow(X, 4) / Math.pow(nf, 4)));
//经度偏差
lon =
(1 / (nf * Math.cos(bf))) * X -
(1 / (6 * Math.pow(nf, 3) * Math.cos(bf))) *
(1 + 2 * tf * tf + n2) *
Math.pow(X, 3) +
(1 / (120 * Math.pow(nf, 5) * Math.cos(bf))) *
(5 + 28 * tf * tf + 24 * Math.pow(tf, 4)) *
Math.pow(X, 5);
// result[0] = lat / iPI;
// result[1] = formatby6(L0 + lon / iPI);
const lng1=(L0 + lon / iPI).toFixed(6);
const lat1= (lat / iPI).toFixed(6);
console.log('大地两千CGCS2000转经纬度WGS84',[X, Y],[lng1,lat1])
return [lng1,lat1];
}