2011-12-29 1 views
17

Я хочу, чтобы иметь возможность менять рамочную систему Device Motion Manager (для гироскопа), чтобы у меня был вектор гравитации по оси Y.Как создать новую опорную рамку CMAttitude, чтобы заставить гравитацию быть на оси Y

Обычно, когда вы запускаете обновления Device Motion Manager, у вас будет только ось z телефона, выровненная с силой тяжести.

Вы можете изменить это, чтобы использовать магнитометр, чтобы ось x была выровнена с магнитным или истинным северным полюсом. При этом у меня есть ось X, указывающая север и ось Z, указывающая вниз.

Я хочу, чтобы моя ось Y (отрицательная) указывала вниз (так, чтобы она выровнялась с силой тяжести), а также моя ось X, указывающая на истинный магнитный полюс.

В результате я хочу, чтобы при стоянии телефона в вертикальной (портретной) ориентации правая сторона телефона была выровнена с северным полюсом, и все мои показания (рулон, шаг, рыскание) будут считаться как 0. Тогда с этим, если я поверну свой телефон по оси X, шаг изменится, и если я повернусь вокруг оси Y, то рывок изменится.

До сих пор я знаю, что могу установить свой собственный референтный фрейм, если умножу на обратное отношение к ранее сохраненному отношению (например, я мог бы установить свой телефон в этой ориентации ВРУЧНУЮ, сохранить это отношение и просто продолжать умножать новое отношение обратного к этому сохраненному, и все мои чтения будут точно такими, какие я хочу).

Но настройка вручную не является вариантом, так как я могу сделать это программно?

Я не думаю, что есть функция, чтобы создать свою собственную систему координат отношения, или если по крайней мере была функция, чтобы умножить отношение по матрице вращения, я мог бы, вероятно, решить эту проблему. (потому что я бы просто умножал все отношения на 90 градусов в поле).

Я надеюсь, что я объяснил себе четко,

Я признателен за любые предложения. благодаря

PD: Они являются iPhone Ориентация координаты:

enter image description here

+0

Вы знаете, как относиться к истинному северу на iOS4? У iOS5 есть хорошие методы для этого. – vale4674

+0

не жаль, не знаю, вот почему я не могу создать свое собственное отношение ... – Pochi

+0

Для такого материала нет хорошего материала .. слишком плохо. – vale4674

ответ

-1

I hope this will help you

Вы можете изменить систему отсчета, используемую экземпляром CMAttitude. Для этого кешируйте объект отношения, который содержит этот опорный кадр, и передайте его как аргумент multiplyByInverseOfAttitude :. Аргумент отношения, получающий сообщение, изменяется для представления изменения отношения к этой системе отсчета.

Чтобы узнать, как это может быть полезно, рассмотрите игру в бейсбол, в которой пользователь поворачивает устройство на качели. Обычно, в начале поля, летучая мышь была бы в некоторой спокойной ориентации. После этого летучая мышь будет отображаться с ориентацией, определяемой тем, как отношение устройства изменилось с того места, где оно находилось в начале подачи.

-(void) startPitch { 

// referenceAttitude is an instance variable 

referenceAttitude = [motionManager.deviceMotion.attitude retain]; 

}

- (void)drawView { 

CMAttitude *currentAttitude = motionManager.deviceMotion.attitude; 

[currentAttitude multiplyByInverseOfAttitude: referenceAttitude]; 

// render bat using currentAttitude ..... 

[self updateModelsWithAttitude:currentAttitude]; 

[renderer render]; 

}

Дополнительные Посмотрите на ссылку ниже, что то же самое, что вы хотите.

http://db-in.com/blog/2011/04/cameras-on-opengl-es-2-x/

+2

Это не решит проблему. это из документов apple dev, конечно, я мог бы кэшировать эту ссылку, но если вы проверите метод, для которого требуется время выполнения, так как он вызывает текущее отношение с помощью движения устройства, я хочу знать, как создать свою собственную систему координат отношения так, чтобы я могу «начать» его в другой ориентации. – Pochi

+1

Это плагиат с сайта Apple без каких-либо атрибуций. – aledalgrande

4

Псевдо код:

  1. запуск обновление движения устройства
  2. начать просмотр камеры в фоновом режиме;)
  3. захвата тока гравитации чтения с устройства в качестве CMAcceleration .. когда у вас есть гравитация, сохраните его в локальной переменной.
  4. Затем вам нужно взять 2 вектора и получить угол между ними, в этом случае гравитация устройства (0,0, -1) и вектор реальной гравитации ...
  5. Затем мы поворачиваем тэта в thetaPrime ... преобразование, которое соответствует базовой ориентации CoreMotion.
  6. Настройка таймера для анимации ....
  7. во время анимации получить обратную сторону вращенияMatrix свойства motionManager deviceMotion.
  8. Примените Трансформации в правильном порядке, чтобы отразить текущее отношение устройства (рыскание, тангаж, крен в эйлеровом режиме или вращениях устройства кватернионов ... 3 способа сказать то же самое, в принципе)

Здесь это код:

- (void) initMotionCapture 
{ 
    firstGravityReading = NO; 
    referenceAttitude = nil; 

    if (motionManager == nil) 
    { 
     self.motionManager = [CMMotionManager new]; 
    } 
    motionManager.deviceMotionUpdateInterval = 0.01; 
    self.gravityTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 target:self selector:@selector(getFirstGravityReading) userInfo:nil repeats:YES]; 
} 


- (void) getFirstGravityReading 
{ 
    CMAcceleration currentGravity; 

    CMDeviceMotion *dm = motionManager.deviceMotion; 
    referenceAttitude = dm.attitude; 
    currentGravity = dm.gravity; 

    [motionManager startDeviceMotionUpdates]; 

    if (currentGravity.x !=0 && currentGravity.y !=0 && currentGravity.z !=0) 
    { 
     NSLog(@"Gravity = (%f,%f,%f)", currentGravity.x, currentGravity.y, currentGravity.z); 

     firstGravityReading = YES; 
     [gravityTimer invalidate]; 
     self.gravityTimer = nil; 
     [self setupCompass]; 
    } 
} 

- (void) setupCompass 
{ 
    //Draw your cube... I am using a quartz 3D perspective hack! 
    CATransform3D initialTransform = perspectiveTransformedLayer.sublayerTransform; 
    initialTransform.m34 = 1.0/-10000; 


    //HERE IS WHAT YOU GUYS NEED... the vector equations! 
    NSLog(@"Gravity = (%f,%f,%f)", currentGravity.x, currentGravity.y, currentGravity.z); 

    //we have current gravity vector and our device gravity vector of (0, 0, -1) 
    // get the dot product 
    float dotProduct = currentGravity.x*0 + currentGravity.y*0 + currentGravity.z*-1; 
    float innerMagnitudeProduct = currentGravity.x*currentGravity.x + currentGravity.y + currentGravity.y + currentGravity.z*currentGravity.z; 
    float magnitudeCurrentGravity = sqrt(innerMagnitudeProduct); 
    float magnitudeDeviceVector = 1; //since (0,0,-1) computes to: 0*0 + 0*0 + -1*-1 = 1 

    thetaOffset = acos(dotProduct/(magnitudeCurrentGravity*magnitudeDeviceVector)); 
    NSLog(@"theta(degrees) = %f", thetaOffset*180.0/M_PI); 

    //Now we have the device angle to the gravity vector (0,0,-1) 
    //We must transform these coordinates to match our 
    //device's attitude by transforming to theta prime 
    float theta_deg = thetaOffset*180.0/M_PI; 
    float thetaPrime_deg = -theta_deg + 90; // ThetaPrime = -Theta + 90 <==> y=mx+b 

    NSLog(@"thetaPrime(degrees) = %f", thetaOffset*180.0/M_PI); 

    deviceOffsetRotation = CATransform3DMakeRotation((thetaPrime_deg) * M_PI/180.0, 1, 0, 0); 
    initialTransform = CATransform3DConcat(deviceOffsetRotation, initialTransform); 

    perspectiveTransformedLayer.sublayerTransform = initialTransform; 

    self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 target:self selector:@selector(tick) userInfo:nil repeats:YES]; 

} 

- (void) tick 
{ 
    CMRotationMatrix rotation; 

    CMDeviceMotion *deviceMotion = motionManager.deviceMotion; 
    CMAttitude *attitude = deviceMotion.attitude; 

    if (referenceAttitude != nil) 
    { 
     [attitude multiplyByInverseOfAttitude:referenceAttitude]; 
    } 
    rotation = attitude.rotationMatrix; 

    CATransform3D rotationalTransform = perspectiveTransformedLayer.sublayerTransform; 

    //inverse (or called the transpose) of the attitude.rotationalMatrix 
    rotationalTransform.m11 = rotation.m11; 
    rotationalTransform.m12 = rotation.m21; 
    rotationalTransform.m13 = rotation.m31; 

    rotationalTransform.m21 = rotation.m12; 
    rotationalTransform.m22 = rotation.m22; 
    rotationalTransform.m23 = rotation.m32; 

    rotationalTransform.m31 = rotation.m13; 
    rotationalTransform.m32 = rotation.m23; 
    rotationalTransform.m33 = rotation.m33; 

    rotationalTransform = CATransform3DConcat(deviceOffsetRotation, rotationalTransform); 
    rotationalTransform = CATransform3DConcat(rotationalTransform, CATransform3DMakeScale(1.0, -1.0, 1.0)); 


    perspectiveTransformedLayer.sublayerTransform = rotationalTransform; 
} 
+0

Это правильно, другими словами: при запуске приложения контрольная рамка CM устанавливается в соответствии с текущим отношением iPhone. то есть значения валка, рыскания и высоты тона не гарантируются одинаковыми, если телефон удерживается под одним углом. Однако, читая исходные данные акселерометра, вы можете получить преобразование, которое дает истинную ориентацию устройства относительно силы тяжести при применении к свойству deviceMotion.attitude. –

+0

Для тех, кто менее сведущих в векторах, то это должно быть эквивалентно преобразованием начальной тяжести чтение к набору из трех углов Эйлера - фактическая ориентация устройства по сравнению с <вашего выбора опорного кадра, например, [0,0, -1 ]>. Вызовите разницу между этими углами и теми, которые поставляются одновременно mgr.deviceMotion.отношение «разность ориентаций». При вычислении мгновенного фактического положения устройства, тогда вы можете просто добавить разницу ориентации к углам в deviceMotion.attitude. –

+0

Да, это правильно. – Orbitus007

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