2

Currently I meet a problem on iOS platform. Basically, I load an arrow which points to east in 2D environment (upside is north, leftside is west, rightside is east and downside is south). I expect it can point to real east in 3D environment so that it will automatically rotates to the right direction. I draw a picture to describe my situation precisely. (The dotted arrow is my loaded arrow and the solid arrow is what I want if I use core motion data)

enter image description here

Now I did

let motionManager = CMMotionManager()
    motionManager.deviceMotionUpdateInterval = 1.0 / 60.0
    if motionManager.isDeviceMotionAvailable {
        motionManager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: { (devMotion, error) -> Void in
                parent_arrows[0].orientation = SCNQuaternion(-CGFloat((motionManager.deviceMotion?.attitude.quaternion.x)!), -CGFloat((motionManager.deviceMotion?.attitude.quaternion.y)!), -CGFloat((motionManager.deviceMotion?.attitude.quaternion.z)!), CGFloat((motionManager.deviceMotion?.attitude.quaternion.w)!))

        })}

The snippet can't automatically make the arrow rotate to the right direction. My idea is to get the angle between the device and the north and then apply this angle to the arrow's orientation. But how can I add the angle to a quaternion? And is there any other idea to achieve this?

OtakuFitness
  • 542
  • 7
  • 20
  • What is the actual problem? Is `parent_arrows[0]` being updated, and the update isn't showing? Is `parent_arrows[0]` not updating? Is it updating & showing but showing the wrong orientation? – Grimxn Feb 15 '17 at 11:52
  • Make the question simple, I load a 3D arrow and I want this arrow to point to the direction(for example: east). I answered what I got below but it seems gimbal lock comes out. – OtakuFitness Feb 17 '17 at 09:28

1 Answers1

1

This thread enlightens me.

 let motionManager = CMMotionManager()
    motionManager.deviceMotionUpdateInterval = 1.0 / 60.0
    if motionManager.isDeviceMotionAvailable {
        motionManager.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: { (devMotion, error) -> Void in
            parent_arrows[0].orientation = self.orient(q: (motionManager.deviceMotion?.attitude.quaternion)!)

        })}
}

func orient(q:CMQuaternion) -> SCNQuaternion{
    let gq1: GLKQuaternion = GLKQuaternionMakeWithAngleAndAxis(GLKMathDegreesToRadians(-heading), 0, 0, 1)
    // add a rotation of the yaw and the heading relative to true north
    let gq2: GLKQuaternion = GLKQuaternionMake(Float(q.x), Float(q.y), Float(q.z), Float(q.w))
    // the current orientation
    let qp: GLKQuaternion = GLKQuaternionMultiply(gq1, gq2)
    // get the "new" orientation
    var rq = CMQuaternion()
    rq.x = Double(qp.x)
    rq.y = Double(qp.y)
    rq.z = Double(qp.z)
    rq.w = Double(qp.w)
    return SCNVector4Make(-Float(rq.x), -Float(rq.y), -Float(rq.z), Float(rq.w))
}

After doing this, the arrow will point to the right direction at the beginning. However, it brings another problem I asked in another thread. The final answer is in this

Community
  • 1
  • 1
OtakuFitness
  • 542
  • 7
  • 20
  • This snippet doesn't work so perfectly. When I hold up the iPhone, the arrow can just rotate in X & Y axis. Z axis rotation disappear. – OtakuFitness Feb 17 '17 at 09:31