Arm*_*enB 6 javascript rotation linear-algebra quaternions cesiumjs
我将 Cesium 的模型之一加载到场景中,并且我想使用两个点来计算模型的方向,这是我创建的函数。
// calculate the direction which the model is facing
calculateOrientation({ position, nextPosition }) {
let dir = new Cesium.Cartesian3();
let normalizedDir = new Cesium.Cartesian3();
Cesium.Cartesian3.subtract(nextPosition, position, dir);
Cesium.Cartesian3.normalize(dir, normalizedDir);
var heading = Math.acos(normalizedDir.x);
var pitch = Math.acos(normalizedDir.y);
var roll = 0;
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
return orientation;
}
Run Code Online (Sandbox Code Playgroud)
但我得到的轮换没有任何意义。我的数学错了吗?
在@Keshet 给出第一个答案后,我查找了如何找到平面和向量之间的角度。我想如果我找到每个平面的法线和 -90 之间的角度,我应该得到正确的角度,但我不确定这是否正确。
另外我不知道Cesium Axis是如何工作的,也找不到任何描述它的文档。例如XY平面等。
let dir = new Cesium.Cartesian3();
let xyNormal = new Cesium.Cartesian3(0,0,1);
let xzNormal = new Cesium.Cartesian3(0,1,0);
let yzNormal = new Cesium.Cartesian3(1,0,0);
Cesium.Cartesian3.subtract(nextPosition, position, dir);
let xyAngle = Cesium.Math.PI_OVER_TWO - Cesium.Cartesian3.angleBetween(dir, xyNormal);
let xzAngle = Cesium.Math.PI_OVER_TWO - Cesium.Cartesian3.angleBetween(dir, xzNormal);
let yzAngle = Cesium.Math.PI_OVER_TWO - Cesium.Cartesian3.angleBetween(dir, yzNormal);
Run Code Online (Sandbox Code Playgroud)
遵循使用 atan2 的 @IIan 建议,代码如下:
Cesium.Cartesian3.subtract(position, nextPosition, dir);
// create the mapped to plane vectors, and get the
// normalized versions
let xyMappedVectorNormalized = new Cesium.Cartesian3(0, 0, 0);
let xyMappedVector = new Cesium.Cartesian3(dir.x, dir.y, 0);
let xzMappedVectorNormalized = new Cesium.Cartesian3(0, 0, 0);
let xzMappedVector = new Cesium.Cartesian3(dir.x, 0, dir.z);
let yzMappedVectorNormalized = new Cesium.Cartesian3(0, 0, 0);
let yzMappedVector = new Cesium.Cartesian3(0, dir.y, dir.z);
Cesium.Cartesian3.normalize(xyMappedVector, xyMappedVectorNormalized);
Cesium.Cartesian3.normalize(xzMappedVector, xzMappedVectorNormalized);
Cesium.Cartesian3.normalize(yzMappedVector, yzMappedVectorNormalized);
// calculate the angles
let xyAngle = Math.atan2(xyMappedVectorNormalized.y, xyMappedVectorNormalized.x);
let xzAngle = Math.atan2(xzMappedVectorNormalized.z, xzMappedVectorNormalized.x);
let yzAngle = Math.atan2(yzMappedVectorNormalized.z, yzMappedVectorNormalized.y);
Run Code Online (Sandbox Code Playgroud)
首先,我们需要解释一下航向角、俯仰角和横滚角代表什么。
您不能简单地使用 x / y 来计算航向/俯仰
var heading = Math.acos(normalizedDir.x);
var pitch = Math.acos(normalizedDir.y);
Run Code Online (Sandbox Code Playgroud)
您需要获得每个平面上的总角度。
在 XY 平面上,您将使用归一化的 |(X, Y)| 在 XZ 平面上,您将使用归一化 |(X, Z)| 在 YZ 平面上,您将使用归一化 |(Y, Z)|
更新
|(X,Y)| 表示单位圆上的一个点。
其中 (sin(theta), cos(theta)) = |(X, Y)|
即当 theta = 0 时,|(X, Y)| = (1, 0) 当 theta = PI/2 时,|(X, Y)| = (0, 1)
这个 theta 将是您用于航向的角度
然后,您可以调用 arctan2 函数来计算相对于平面的角度。
atan2(y, x) = theta 其中 [x, y] 是使用相应的归一化二维向量从上面计算出来的
注意:atan2 给出以 (-PI, PI] 为界的角度
例子
如果您的 3D 矢量是 (1, 2, 3) - 在 XY 平面上 X = 1,Y = 2。
那么如果你标准化 (1, 2) => (1 / sqrt(5), 2 / sqrt(5))
然后您可以使用 atan2(2 / sqrt(5), 1 / sqrt(5) 计算航向的角度(以弧度为单位)