ios 如何实现乘姿态倒数(CMAttitude类)?

km0tfn4u  于 2023-02-10  发布在  iOS
关注(0)|答案(2)|浏览(118)

我需要实现与CMAttitude iOS类中multiplyByInverseOfAttitude相同的行为。请注意,我不能直接使用它,但我有正确的CMAttitude对象。有人能给我指出正确的方向吗?

eanckbw9

eanckbw91#

因为你不允许自己创建CMAttitude的示例,唯一的方法是创建一个新的四元数,并将其用于任何进一步的计算。我建议使用你自己定制的四元数类,而不是简单的结构CMQuaternion。一个好的起点是cocoamath项目,在那里你可以将Quaternion.m,trunk中的Quaternion. h和QuaternionOperations.m,我将在此示例代码中使用它们。
首先,您必须保存参考四元数(取自CMAttitude.quaternion)复共轭的示例,以用于所有后续乘法,即
MyClass.h

Quaternion* inverseReferenceQuaternion;

MyClass.c

// initialising code run only once after each call to [motionManager startDeviceMotionUpdates];
CMAttitude firstAttitude = [motionManager deviceMotion].attitude;
CMQuaternion q = firstAttitude.quaternion;
inverseReferenceQuaternion = [[Quaternion alloc] initWithRe:q.w i:-q.x j:-q.y k:-q.z];

在计时器循环(或处理程序块)中,需要四元数乘法:

// on every update
CMAttitude attitude = [motionManager deviceMotion].attitude;
CMQuaternion current = attitude.quaternion;
Quaternion currentMultiplied = initAsProductOf:inverseReferenceQuaternion And:current

现在currentMultiplied应该包含您要查找的内容。
如果你是这个主题的新手,四元数是很漂亮的,但是值得阅读一些教程,比如OpenGL:Tutorials:Using Quaternions to represent rotationQuaternion Powers

mpbci0fu

mpbci0fu2#

最近我有同样的问题,目前的答案不满意我,因为我仍然需要学习很多东西。所以这里是我的下降在这个问题的答案。
假设我们有这样的代码:

let firstAttitude: CMAttitude = ...
let attitude: CMAttitude = ...

attitude.multiply(byInverseOf: firstAttitude)

print("pitch: \(attitude.pitch); roll: \(attitude.roll); yaw: \(attitude.yaw)")

结构定义:

// structures for representing euler angles
struct EulerAngles {
    var pitch: Double
    var roll: Double
    var yaw: Double

    // base c-tor
    init(pitch: Double, roll: Double, yaw: Double) {
        self.pitch = pitch
        self.roll = roll
        self.yaw = yaw
    }
}

// structure for representing quaternions
struct Quaternion {
    var w: Double
    var x: Double
    var y: Double
    var z: Double

    // base c-tor
    init(w: Double, x: Double, y: Double, z: Double) {
        self.w = w
        self.x = x
        self.y = y
        self.z = z
    }

    // c-tor using CMQuaternion from CoreMotion
    init(_ quaternion: CMQuaternion) {
        self.w = quaternion.w
        self.x = quaternion.x
        self.y = quaternion.y
        self.z = quaternion.z
    }

    var inverse: Quaternion {
        return Quaternion(w: w, x: -x, y: -y, z: -z)
    }

    static func * (lhs: Quaternion, rhs: Quaternion) -> Quaternion {
        return Quaternion(
            w: lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z,
            x: lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y,
            y: lhs.w * rhs.y - lhs.x * rhs.z + lhs.y * rhs.w + lhs.z * rhs.x,
            z: lhs.w * rhs.z + lhs.x * rhs.y - lhs.y * rhs.x + lhs.z * rhs.w
        )
    }

    // convert to euler angles
    var eulerAngles: EulerAngles {
        return EulerAngles(
            pitch: atan2(2.0 * (w * x + y * z), 1.0 - 2.0 * (x * x + y * y)), 
            roll: asin(2.0 * (w * y - z * x)), 
            yaw: atan2(2.0 * (w * z + x * y), 1.0 - 2.0 * (y * y + z * z))
        )
    }
}

用法:

let inverseReferenceQuaternion = Quaternion(firstAttitude.quaternion).inverse
let currentMultiplied = inverseReferenceQuaternion * Quaternion(attitude.quaternion)
let angles = currentMultiplied.eulerAngles
print("pitch: \(angles.pitch); roll: \(angles.roll); yaw: \(angles.yaw)")
// output must be the same as after `multiply(byInverseOf:`

相关问题