function courseAngle(lng_a, lat_a, lng_b, lat_b) {
//以a點爲原點建立局部座標系(東方向爲x軸,北方向爲y軸,垂直於地面爲z軸),得到一個局部座標到世界座標轉換的變換矩陣
var localToWorld_Matrix = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(lng_a, lat_a));
//求世界座標到局部座標的變換矩陣
var worldToLocal_Matrix = Cesium.Matrix4.inverse(localToWorld_Matrix, new Cesium.Matrix4());
//a點在局部座標的位置,其實就是局部座標原點
var localPosition_A = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_a, lat_a), new Cesium.Cartesian3());
//B點在以A點爲原點的局部的座標位置
var localPosition_B = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_b, lat_b), new Cesium.Cartesian3());
//弧度
var angle = Math.atan2((localPosition_B.y-localPosition_A.y), (localPosition_B.x-localPosition_A.x))
//角度
var theta = angle*(180/Math.PI);
if (theta < 0) {
theta = theta + 360;
}
return theta;
}
function coursePitchAngle(lng_a, lat_a, alt_a, lng_b, lat_b, alt_b) {
//以a點爲原點建立局部座標系(東方向爲x軸,北方向爲y軸,垂直於地面爲z軸),得到一個局部座標到世界座標轉換的變換矩陣
var localToWorld_Matrix = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(lng_a, lat_a, alt_a));
//求世界座標到局部座標的變換矩陣
var worldToLocal_Matrix = Cesium.Matrix4.inverse(localToWorld_Matrix, new Cesium.Matrix4());
//a點在局部座標的位置,其實就是局部座標原點
var localPosition_A = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_a, lat_a, alt_a), new Cesium.Cartesian3());
//B點在以A點爲原點的局部的座標位置
var localPosition_B = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_b, lat_b, alt_b), new Cesium.Cartesian3());
//弧度
var angle = Math.atan2((localPosition_B.z-localPosition_A.z), (localPosition_B.x-localPosition_A.x))
//角度
var theta = angle*(180/Math.PI);
if (theta < 0) {
theta = theta + 360;
}
return theta;
}
function updateOrientation(targetEntity){
var pathPosition = targetEntity.pathPosition;
// 前一個座標點
var preIndex = 0;
if(pathPosition.length > 1){
preIndex = pathPosition.length-2;
}
var prevPosition = Cesium.Cartesian3.fromDegrees(pathPosition[preIndex][0], pathPosition[preIndex][1], pathPosition[preIndex][2]);
// 當前座標點
var currentIndex = pathPosition.length-1;
var currentPosition = Cesium.Cartesian3.fromDegrees(pathPosition[currentIndex][0], pathPosition[currentIndex][1], pathPosition[currentIndex][2]);
// 計算a點和b點的角度(偏行角)
var angle = courseAngle(pathPosition[preIndex][0], pathPosition[preIndex][1],pathPosition[currentIndex][0], pathPosition[currentIndex][1]);
angle = 360 - Number(angle.toFixed(0));
// 計算a點和b點的角度(俯仰角)
var pitchAngle = coursePitchAngle(pathPosition[currentIndex][0], pathPosition[currentIndex][1], pathPosition[currentIndex][2], pathPosition[preIndex][0], pathPosition[preIndex][1], pathPosition[preIndex][2]);
pitchAngle = Number(pitchAngle.toFixed(0));
if(pitchAngle > 180){
pitchAngle = 360 - pitchAngle;
}else{
pitchAngle = 180 + pitchAngle;
}
// 根據“俯仰角、偏行角、滾轉角”得到目標方位
var gheading = Cesium.Math.toRadians(angle);
var gpitch = Cesium.Math.toRadians(pitchAngle);
var groll = Cesium.Math.toRadians(0);
var hpr = new Cesium.HeadingPitchRoll(gheading, gpitch, groll);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(prevPosition, hpr);
targetEntity.orientation = orientation;
}
// 計算四元數
var _angle = targetEntity.orientation.getValue(viewer.clock.currentTime);
// 計算旋轉角(弧度)
var hpr = Cesium.HeadingPitchRoll.fromQuaternion(_angle);
// 得到角度
var heading = Cesium.Math.toDegrees(hpr.heading);
var pitch = Cesium.Math.toDegrees(hpr.pitch);
var roll = Cesium.Math.toDegrees(hpr.roll);
console.log('heading : ' + heading, 'pitch : ' + pitch, 'roll : ' + roll);
注:
- pitch是圍繞X軸旋轉,也叫做俯仰角
- heading(yaw)是圍繞Y軸旋轉,也叫偏航角,(平行於z軸,就是水平旋轉的,其他同理)
- roll是圍繞Z軸旋轉,也叫翻滾角