Переназначить матрицу вращения на другую систему координат

Я использую адаптированную версию Android getRotationMatrix в программе на C++, которая считывает данные датчика телефона по сети и вычисляет матрицу устройства.

Функция работает нормально и вычисляет ориентацию устройства. К сожалению, Ogre3d имеет другую систему координат, чем устройство. Таким образом, хотя вращение вокруг оси x работает нормально, оси y и z неверны. Держа устройство горизонтально и указывая на север (матрица идентичности). Когда я делаю подачу, вращение правильное. Но когда я кренюсь и рыскаю, вращения чередуются. Roll — это рыскание в Ogre3d и наоборот.

    (Ogre3d)                         ([Device][5])

   ^ +y-axis                       ^ +z-axis                                  
   *                               *                                 
   *                               *                                 
   *                               *    ^ +y-axis                             
   *                               *   *                               
   *                               *  *                                
   *                               * *                                 
   ************> + x-axis          ************> +x-axis                      
  *                                                                   
 *                                                                    
v +z-axis                                                                     

Быстрый взгляд на двухосную систему выглядит так: система Огра (слева) — это, по сути, система устройства, повернутая на 90 градусов против часовой стрелки вокруг оси X.

Я пытался поэкспериментировать с различными комбинациями, когда сначала назначал значения датчиков до расчета матрицы, но ни одна комбинация не работала правильно. Как мне убедиться, что матрица вращения getRotationMatrix() корректно отображает изображения в Ogre3D?

Для справки вот функция, которая вычисляет матрицу:

bool getRotationMatrix() {
    //sensor data coming through the network are 
    //stored in accel(accelerometer) and mag(geomagnetic)
    //vars which the function has access to
    float Ax = accel[0]; float Ay = accel[1];   float Az = accel[2];
    float Ex = mag[0];   float Ey = mag[1];     float Ez = mag[2];

    float Hx = Ey * Az - Ez * Ay;
    float Hy = Ez * Ax - Ex * Az;
    float Hz = Ex * Ay - Ey * Ax;
    float normH = (float) Math::Sqrt(Hx * Hx + Hy * Hy + Hz * Hz);
    if (normH < 0.1f) {
        // device is close to free fall (or in space?), or close to
        // magnetic north pole. Typical values are  > 100.
        return false;
    }
    float invH = 1.0f / normH;
    Hx *= invH;
    Hy *= invH;
    Hz *= invH;
    float invA = 1.0f / (float) Math::Sqrt(Ax * Ax + Ay * Ay + Az * Az);
    Ax *= invA;
    Ay *= invA;
    Az *= invA;
    float Mx = Ay * Hz - Az * Hy;
    float My = Az * Hx - Ax * Hz;
    float Mz = Ax * Hy - Ay * Hx;

    //ogre3d's matrix3 is column-major whereas getrotatinomatrix produces
    //a row-major matrix thus i have tranposed it here
    orientation[0][0] = Hx; orientation[0][2] = Mx; orientation[0][2] = Ax;
    orientation[1][0] = Hy; orientation[1][3] = My; orientation[1][2] = Ay;
    orientation[2][0] = Hz; orientation[2][4] = Mz; orientation[2][2] = Az;

    return true;
}

person Jubei    schedule 01.05.2011    source источник
comment
Просто интересно, законно ли использовать такой код, перенесенный с Android? Хотел бы я понять смысл математики (которая, как я полагаю, не является IP), чтобы я мог написать ее самостоятельно.   -  person Plumenator    schedule 31.05.2011
comment
Конечно, это законно. acc = данные акселерометра ma = данные магнитного датчика. Вот функции Ogre3D, они довольно просты: Vector3 H = ma.crossProduct(acc); float normH = (float) H.length(); float invH = 1,0f/normH; H *= инвH; float invA = 1.0f / (float) acc.length(); акк *= инвА; Vector3 M = acc.crossProduct(H); ориентация[0][0] = H.x; ориентация[0][1] = H.y; ориентация[0][2] = Гц; ориентация[1][0] = М.х; ориентация[1][1] = M.y; ориентация[1][2] = M.z; ориентация[2][0] = соотв.x; ориентация[2][1] = согл.у; ориентация[2][2] = соотв.z;   -  person Jubei    schedule 08.06.2011
comment
Верно, но мы просто взяли код Java из Android и преобразовали его в C++. Это законно? Разве мы не должны были написать код с нуля или придумали его полностью сами?   -  person Plumenator    schedule 08.06.2011
comment
Но это очень известный метод определения ориентации на основе двух известных векторов 1968 года. Google не владеет никакими патентами или правами на этот метод. en.wikipedia.org/wiki/Triad_Method   -  person Jubei    schedule 10.06.2011
comment
Проблема не в методе. Дело в том, что код получен из кода, принадлежащего Google.   -  person Plumenator    schedule 10.06.2011
comment
Google ничего не имеет. Android является открытым исходным кодом под лицензией Apache v2 с открытым исходным кодом.   -  person Jubei    schedule 25.06.2011


Ответы (3)


Почему бы просто не добавить одно дополнительное вращение, которое вы уже определили, прежде чем использовать его в людоеде?

person Jay    schedule 02.05.2011

Я нашел проблему. В моей функции единичные векторы, рассчитанные после перекрестных произведений, я помещаю их в столбцы, тогда как я должен помещать их в строки в назначенных им ячейках matrix3, как обычно. Что-то в отношении строк и столбцов смутило меня, хотя я имел в виду элементы в 2d [][].

умножение результата функции вычисления матрицы на эту матрицу:

1 0 0

0 0 1

0 -1 0

Затем изменение всего результата еще на p/2 вокруг оси решило проблему переназначения, но я боюсь, что моя геометрия перевернута.

person Jubei    schedule 04.05.2011

Я мало что знаю о Вращении Матрицы, но если Системы вращаются так, как вы показываете, я думаю, вам следует сделать следующее:

Ось X остается прежней, поэтому:

float Ax = accel[0];
float Ex = mag[0];

Ось Y в (Ogre3d) — это ось Z в ([Device][5]), поэтому:

float Ay = accel[2];
float Ey = mag[2];

Ось Z в (Ogre3d) противоположна оси Y в ([Device][5]), поэтому:

float Az = accel[1] * (-1);
float Ez = mag[1] * (-1);

Попробуй это

person J-Rou    schedule 01.05.2011
comment
Я уже пробовал это. Я попробовал еще раз, и, к сожалению, это не работает: / Он переключает y на z, но вращение по оси z меняется на противоположное, и какую бы комбинацию я ни пробовал, я не могу сделать это правильно (пытаюсь уже несколько дней) . Однако, спасибо! Я ценю помощь. - person Jubei; 01.05.2011