我怎样才能得到iOS设备CMDeviceMotion的标题
我正在开发一个使用陀螺仪的AR应用程序。 我使用苹果代码示例pARk。 它使用旋转matrix来计算坐标的位置,它确实做得很好,但是现在我试图实现一个“雷达”,我需要在设备标题的函数中旋转它。 我正在使用CLLocationManager标题,但它不正确。
问题是,如何使用CMAttitude获取设备的标题以准确反映屏幕上显示的内容?
我是新的旋转matrix和那种东西。
这是用于计算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;
我也用俯仰angular旋转视图。 运动更新开始使用北方:
[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical];
所以我认为,必须有可能在任何位置(任何音高和偏航)获得设备的“滚动”/标题,但我不知道如何。
有几种方法可以从CMDeviceMotion返回的旋转matrix中计算标题。 这假设你使用苹果指南针的相同定义,其中指向正北的+ y方向(iPhone的顶部)返回标题0,并且向右旋转iPhone增加标题,所以东为90,南为180等等。
首先,当你开始更新时,一定要检查以确保标题是可用的:
if (([CMMotionManager availableAttitudeReferenceFrames] & CMAttitudeReferenceFrameXTrueNorthZVertical) != 0) { ... }
接下来,当您启动运动pipe理器时,请求态度为从X指向真北(或者由于某种原因需要磁北)的旋转:
[motionManager startDeviceMotionUpdatesUsingReferenceFrame: CMAttitudeReferenceFrameXTrueNorthZVertical toQueue: self.motionQueue withHandler: dmHandler];
当运动pipe理器报告运动更新时,您需要了解设备在XY平面中旋转了多less。 因为我们对iPhone的顶部感兴趣,所以我们将在这个方向上select一个点,并使用返回的旋转matrix来旋转它以获得旋转后的点:
[m11 m12 m13] [0] [m12] [m21 m22 m23] [1] = [m22] [m31 m32 m33] [0] [m32]
时髦的括号是matrix; 这是我能用ASCII做的最好的。 🙂
标题是旋转点和真北之间的angular度。 我们可以使用旋转点的X和Y坐标来提取反正切,从而得到该点和X轴之间的angular度。 这实际上与我们想要的相差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是零,或者非常接近它。 您需要决定这对您的应用意味着什么,并相应地处理这种情况。 例如,当m12 * m12 + m22 * m22接近零时,您可能会切换到基于-Z轴(iPhone后面)的标题。
这一切都假设你想旋转XY平面,正如苹果通常为他们的指南针所做的那样。 这是因为您正在使用运动pipe理器返回的旋转matrix来旋转沿Y轴指向的向量,即此matrix:
[0] [1] [0]
要旋转一个不同的vector – 比方说,一个指向-Z的 – 使用一个不同的matrix,就像
[0] [0] [-1]
当然,你也必须在不同的平面上采取反正切,所以不是
double heading = PI + atan2(rm.m22, rm.m12);
你会用
double heading = PI + atan2(-rm.m33, -rm.m13);
在XZ平面上旋转。