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

Но вращения, которые я получаю, не имеют никакого смысла. Моя математика неверна?

ОБНОВИТЬ

После первого ответа @Keshet я посмотрел, как найти угол между плоскостью и вектором. Я подумал, что если я найду угол между нормалью каждой плоскости и -90, я должен получить правильный угол, но я не уверен, что это правильно.

Также я не знаю, как работает цезиевая ось, и я не могу найти документ, описывающий ее. Например, плоскость 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);

person ArmenB    schedule 23.06.2018    source источник
comment
Отрицательный голос не дает отзыва о том, как можно улучшить этот вопрос.   -  person ArmenB    schedule 23.06.2018


Ответы (1)


Во-первых, нам нужно объяснить, что представляют собой углы курса, тангажа и крена.

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


Обновить

|(Х, Y)| представляет собой точку на единичном круге.

где (sin(theta), cos(theta)) = |(X, Y)|

IE, когда тета = 0, |(X, Y)| = (1, 0), когда тета = PI/2, |(X, Y)| = (0, 1)

эта тета будет тогда углом, который вы используете для заголовка


затем впоследствии вы можете вызвать функцию arctan2 для вычисления угла относительно плоскости.

atan2(y, x) = theta, где [x, y] вычисляются сверху с использованием соответствующего нормализованного двумерного вектора

Примечание: atan2 дает углы, ограниченные (-PI, PI]

Пример

Если ваш трехмерный вектор (1, 2, 3) -- на плоскости XY X = 1, Y = 2.

Затем, если вы нормализуете (1, 2) => (1 / sqrt (5), 2 / sqrt (5))

Затем вы можете использовать atan2(2/sqrt(5), 1/sqrt(5) для вычисления угла в радианах для заголовка.

person Ilan Keshet    schedule 23.06.2018
comment
@IIanKeshet, какая величина |(X, Y)| представляет? моя линейная алгебра заржавела, что такое (X, Y)? - person ArmenB; 25.06.2018
comment
Я привел пример в вопросе. Посмотрите еще раз на ответ - person Ilan Keshet; 25.06.2018
comment
Кроме того, я определил, что X, Y представляют - person Ilan Keshet; 26.06.2018
comment
так в основном atan2(normalizedDir.x, normalizedDir.y) ? - person ArmenB; 26.06.2018
comment
да, но не нормализованный 3D-вектор, а нормализованный 2D-вектор. И это наоборот. atan2(y, x) -- именно так работает функция - person Ilan Keshet; 26.06.2018
comment
Вы должны быть немного осторожны, потому что нормализация (0, 0) -- не определена и не будет работать. - person Ilan Keshet; 26.06.2018
comment
Я добавил код, отражающий то, что вы сказали, но он не работает - person ArmenB; 26.06.2018
comment
Может быть хорошей идеей показать картинку, почему это неправильно. -- Может случиться так, что ваш восходящий вектор на самом деле Y, а не Z. Я бы рекомендовал показать изображение того, что он делает. Чтобы проверить, является ли получившийся кватернион правильным: умножьте Q * (1, 0, 0) -- этот результат должен быть |(nextPosition - position)| - person Ilan Keshet; 26.06.2018