用Cesiumjs从向量计算俯仰角、偏航角和方位角

6

我在场景中加载了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;
}

但是我得到的旋转结果没有意义。我的数学有问题吗?

更新

在@Keshet的第一个答案之后,我查找了如何找到平面和向量之间的角度。我认为,如果我找到每个平面的法向量和-90度之间的角度,我应该会得到正确的角度,但我不确定这是否正确。

此外,我不知道Cesium轴线如何工作,并且我找不到任何描述它的文档。例如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);

更新2

根据@IIan的建议,使用atan2,以下是代码:

    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);

2
负面评价并不能提供有关如何改进这个问题的反馈。 - ArmenB
1个回答

0

首先,我们需要解释标题、俯仰和滚转角度代表的含义。

  1. 标题角度代表相对于 XY 平面的弧度角
  2. 俯仰角度代表相对于 XZ 平面的弧度角
  3. 滚转角度代表相对于 YZ 平面的弧度角

您不能简单地使用 x / y 来计算标题 / 俯仰角

var heading = Math.acos(normalizedDir.x);
var pitch = Math.acos(normalizedDir.y);

你需要获取每个平面的总角度。

在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) = θ,其中[x,y]是使用相应的归一化2D向量从上面计算出来的。

请注意: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))来计算航向的弧度角。


@IIanKeshet |(X, Y)| 代表什么大小?我的线性代数有点生疏,(X, Y)是什么? - ArmenB
另外,我定义了X和Y代表什么。 - Ilan Keshet
基本上是 atan2(normalizedDir.x, normalizedDir.y) 吗? - ArmenB
是的,但不是规范化的3D向量,而是规范化的2D向量。而且方向相反。 atan2(y,x) - 这就是函数的工作原理。 - Ilan Keshet
展示一张图片来说明错误可能是个好主意。也许你的up向量实际上是Y而不是Z。我建议展示一张它的运行情况的图片。为了测试结果四元数是否正确:将Q * (1, 0, 0)相乘--这个结果应该是|(nextPosition - position)|。 - Ilan Keshet
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接