查找iOS设备的法线向量

Fra*_*y I 26 ios gyroscope core-motion

我想用CMAttitude来了解iPad/iPhone屏幕玻璃的正常向量(相对于地面).因此,我会得到以下矢量:

在此输入图像描述

请注意,这与方向不同,因为我不关心设备如何围绕z轴旋转.因此,如果我把iPad放在我的头顶朝下,它会读取(0,-1,0),即使我将它旋转到我头顶上方(如直升机),它仍将继续读取(0, - 1,0):

在此输入图像描述

我觉得这可能很简单,但由于我是四元数的新手,并且不完全理解设备运动的参考框架选项,所以它一整天都在躲避我.

Kay*_*Kay 22

  1. 在你的情况下,我们可以说设备的旋转等于设备法线的旋转(围绕法线本身的旋转就像你指定的那样被忽略)
  2. CMAttitude你可以得到通过 CMMotionManager.deviceMotion提供旋转 相对于参考帧.它的属性四元数,旋转矩阵和欧拉角只是不同的表示.
  3. 使用CMMotionManager的startDeviceMotionUpdatesUsingReferenceFrame方法启动设备运动更新时,可以指定参考框架.在iOS 4之前,你必须使用multiplyByInverseOfAttitude

将这些放在一起,当设备面朝上放在桌子上时,你必须以正确的方式将四元数与法线向量相乘.现在我们需要这种表示旋转的四元数乘法的正确方法:根据旋转向量,这可以通过以下方式完成:

n = q*e*q'其中q是由CMAttitude [w,(x,y,z)]传递的四元数,q'是它的共轭[w,( - x,-y,-z)],e是面向正常[4,(0,0,1)]的四元数表示.不幸的是,Apple的CMQuaternion是struct,因此你需要一个小帮手类.

Quaternion e = [[Quaternion alloc] initWithValues:0 y:0 z:1 w:0];
CMQuaternion cm = deviceMotion.attitude.quaternion;
Quaternion quat = [[Quaternion alloc] initWithValues:cm.x y:cm.y z:cm.z w: cm.w];
Quaternion quatConjugate = [[Quaternion alloc] initWithValues:-cm.x y:-cm.y z:-cm.z w: cm.w];
[quat multiplyWithRight:e];
[quat multiplyWithRight:quatConjugate];
// quat.x, .y, .z contain your normal
Run Code Online (Sandbox Code Playgroud)

Quaternion.h:

@interface Quaternion : NSObject {
    double w;
    double x;
    double y;
    double z;
}

@property(readwrite, assign)double w;
@property(readwrite, assign)double x;
@property(readwrite, assign)double y;
@property(readwrite, assign)double z;
Run Code Online (Sandbox Code Playgroud)

Quaternion.m:

- (Quaternion*) multiplyWithRight:(Quaternion*)q {
    double newW = w*q.w - x*q.x - y*q.y - z*q.z;
    double newX = w*q.x + x*q.w + y*q.z - z*q.y;
    double newY = w*q.y + y*q.w + z*q.x - x*q.z;
    double newZ = w*q.z + z*q.w + x*q.y - y*q.x;
    w = newW;
    x = newX;
    y = newY;
    z = newZ;
    // one multiplication won't denormalise but when multipling again and again 
    // we should assure that the result is normalised
    return self;
}

- (id) initWithValues:(double)w2 x:(double)x2 y:(double)y2 z:(double)z2 {
        if ((self = [super init])) {
            x = x2; y = y2; z = z2; w = w2;
        }
        return self;
}
Run Code Online (Sandbox Code Playgroud)

我知道四元数在开始时有点奇怪,但是一旦你有了一个想法它们真的很棒.它帮助我将四元数想象为围绕向量(x,y,z)的旋转,w是角度的(余弦).

如果您需要对它们做更多的工作,请查看cocoamath开源项目.Quaternion类及其扩展QuaternionOperations是一个很好的起点.

为了完整起见,是的,您也可以使用矩阵乘法:

n = M*e

但我更喜欢四元数方式,它可以为您节省所有三角函数的麻烦并且表现更好.