这个问题有点令人困惑,因为至少有两种不同的方式来考虑 Yaw。一种是从手机的角度,一种是从世界的角度。
我将使用Apple 的这张图片来进一步解释:
如果手机平放在桌子上:
- 沿手机偏航(或 Z 轴)旋转:更改指南针航向。
- 沿手机的滚动(或 Y 轴)旋转:不要更改指南针航向。
- 沿手机的俯仰(或 X 轴)旋转:不要更改罗盘航向。
如果手机平贴在墙上:
- 沿手机偏航(或 Z 轴)旋转:更改指南针航向。
- 沿手机滚动(或 Y 轴)旋转:更改指南针航向。
- 沿手机的俯仰(或 X 轴)旋转:不要更改罗盘航向。
对于这个答案的其余部分,我将假设手机是直立的,并且偏航、俯仰和滚动指的是上面照片中的内容。
偏航
您需要像本例atan2
中那样使用和检查重力。
let yaw = -Angle(radians: .pi - atan2(motion.gravity.x, motion.gravity.y))
沥青
与上面类似,我主要只是交换了 x 和 z ,它似乎返回了正确的值:
let pitch = Angle(radians: .pi - atan2(motion.gravity.z, motion.gravity.y))
滚动(又名指南针航向)
使用上面 blkhp19 的代码总结了偏航和滚动的姿态。如果您 import SwiftUI
,您可以利用该Angle
结构使弧度 + 度数转换更容易:
func roll(motion: CMDeviceMotion) -> Angle {
let attitudeYaw = Angle(radians: motion.attitude.yaw)
let attitudeRoll = Angle(radians: motion.attitude.roll)
var compassHeading: Angle = attitudeYaw + attitudeRoll
if attitudeRoll.degrees < 0 && attitudeYaw.degrees < 0 {
compassHeading = Angle(degrees: 360 - (-1 * compassHeading.degrees))
}
return compassHeading
}
另请注意,如果您不需要实际角度,而您只需要关系(例如 isPhoneUpright),您可以简单地读取这些的重力值。
extension CMDeviceMotion {
var yaw: Angle {
-Angle(radians: .pi - atan2(gravity.x, gravity.y))
}
var pitch: Angle {
Angle(radians: .pi - atan2(gravity.z, gravity.y))
}
var roll: Angle {
let attitudeYaw = Angle(radians: attitude.yaw)
let attitudeRoll = Angle(radians: attitude.roll)
var compassHeading: Angle = attitudeYaw + attitudeRoll
if attitudeRoll.degrees < 0 && attitudeYaw.degrees < 0 {
compassHeading = Angle(degrees: 360 - (-1 * compassHeading.degrees))
}
return compassHeading
}
}