2012-02-18 3 views
4

Я разрабатываю AR-приложение, используя гироскоп. Я использую пример кода apple pARk. Он использует матрицу поворота для вычисления положения координаты, и это действительно хорошо, но теперь я пытаюсь реализовать «радар», и мне нужно повернуть его в функции заголовка устройства. Я использую заголовок CLLocationManager, но это неверно.Как я могу получить заголовок устройства с CMDeviceMotion в iOS 5

Вопрос в том, как я могу получить заголовок устройства, используя CMAttitude, чтобы точно отражать то, что я получаю на экране?

Я новый с матрицей вращения и такими вещами.

Это часть кода, используемого для расчета координат AR. Обновление cameraTransform с отношением:

CMDeviceMotion *d = motionManager.deviceMotion; 
if (d != nil) { 
    CMRotationMatrix r = d.attitude.rotationMatrix; 
    transformFromCMRotationMatrix(cameraTransform, &r); 
[self setNeedsDisplay]; 
} 

, а затем в коде DrawRect:

mat4f_t projectionCameraTransform; 
multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform); 

int i = 0; 
for (PlaceOfInterest *poi in [placesOfInterest objectEnumerator]) { 
    vec4f_t v; 
    multiplyMatrixAndVector(v, projectionCameraTransform, placesOfInterestCoordinates[i]); 

    float x = (v[0]/v[3] + 1.0f) * 0.5f; 
    float y = (v[1]/v[3] + 1.0f) * 0.5f; 

Я также повернуть изображение с углом наклона. движений обновления начали использовать север:

[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical]; 

Так что я думаю, что должно быть возможным, чтобы получить «Ролл»/заголовок устройства в любом положении (с любым шагом и рыскания ...), но я не знаю как.

+0

Я не могу найти метод multiplyMatrixAndVector. Можете ли вы сказать мне, что это? – vale4674

+0

Этот код находится в коде pARk для Apple. Во многих других библиотеках это очень часто. – AdrianByv

ответ

15

Существует несколько способов расчета заголовка из матрицы вращения, возвращаемой CMDeviceMotion. Это предполагает, что вы используете то же определение компаса Apple, где направление + y (верхняя часть iPhone), указывающее на север, возвращает заголовок 0, а поворот iPhone вправо увеличивает заголовок, поэтому Восток равен 90, юг - 180 , и так далее.

Во-первых, при запуске обновления, не забудьте проверить, чтобы убедиться, что заголовки доступны:

if (([CMMotionManager availableAttitudeReferenceFrames] & CMAttitudeReferenceFrameXTrueNorthZVertical) != 0) { 
    ... 
} 

Далее, при запуске диспетчера движения, попросите отношение как поворот от X указывая истинный Север (или магнитный север, если вам нужно, что по некоторым причинам):

[motionManager startDeviceMotionUpdatesUsingReferenceFrame: CMAttitudeReferenceFrameXTrueNorthZVertical 
                toQueue: self.motionQueue 
               withHandler: dmHandler]; 

Когда менеджер движения сообщает обновление движения, вы хотите узнать, сколько устройство вращается в плоскости XY. Поскольку мы заинтересованы в верхней части iPhone, мы выберем точку в этом направлении и вращать его с помощью возвращаемой матрицы поворота, чтобы получить точку после вращения:

[m11 m12 m13] [0] [m12] 
    [m21 m22 m23] [1] = [m22] 
    [m31 m32 m33] [0] [m32] 

фанков скобки матрица; это лучшее, что я могу сделать, используя ASCII. :)

Заголовок - это угол между вращающейся точкой и истинным севером. Мы можем использовать координаты X и Y повернутой точки для извлечения тангенса дуги, которая дает угол между точкой и осью X. Это фактически на 180 градусов от того, что мы хотим, поэтому мы должны соответствующим образом отрегулировать. Результирующий код выглядит следующим образом:

CMDeviceMotionHandler dmHandler = ^(CMDeviceMotion *aMotion, NSError *error) { 
    // Check for an error. 
    if (error) { 
     // Add error handling here. 
    } else { 
     // Get the rotation matrix. 
     CMAttitude *attitude = self.motionManager.deviceMotion.attitude; 
     CMRotationMatrix rm = attitude.rotationMatrix; 

     // Get the heading. 
     double heading = PI + atan2(rm.m22, rm.m12); 
     heading = heading*180/PI; 
     printf("Heading: %5.0f\n", heading); 
    } 
}; 

Существует один глюк: Если в верхней части iPhone направлен прямо вверх или вниз, направление не определено. В результате m21 и m22 равны нулю или очень близки к нему. Вам нужно решить, что это означает для вашего приложения и соответствующим образом обрабатывать условие. Например, вы можете переключиться на заголовок, основанный на оси -Z (за iPhone), когда m12 * m12 + m22 * m22 близок к нулю.


Все это предполагает, что вы хотите повернуть вокруг плоскости X-Y, как это обычно делает Apple для их компаса. Это работает, потому что вы используете матрицу вращения, возвращенное менеджера движения вращать вектор направлен вдоль оси Y, что эта матрица:

[0] 
[1] 
[0] 

Чтобы повернуть другой вектор - скажем, один направлен вдоль -Z --use другую матрицу, как

[0] 
[0] 
[-1] 

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

double heading = PI + atan2(rm.m22, rm.m12); 

вы бы использовать

double heading = PI + atan2(-rm.m33, -rm.m13); 

, чтобы получить поворот в плоскости X-Z.

+0

Не могли бы вы прояснить, как использовать матрицу (ту, что вы сказали, с фальшивыми скобками) и о том, как сделать переключение на заголовок на основе оси Z? Я хотел бы, чтобы приложение работало на всех позициях iPhone. Заранее спасибо. – iSeeker

+0

Менеджер вращения возвращает матрицу вращения. Код использует эту матрицу вращения для поворота вектора, направленного вдоль оси Y, а затем смотря на направление результирующего вектора в плоскости X-Y. – Mike

+1

uhm ... зачем вы используете atan2 (rm.m32, rm.m12), чтобы получить поворот в плоскости X-Z? не должно ли оно быть atan2 (-rm.m33, -rm.m13)? –

 Смежные вопросы

  • Нет связанных вопросов^_^