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)
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?
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