CoreMotion - 在iPhone上横向移动,自下而上

jpu*_*til 7 accelerometer ios core-motion swift

我正在制作一个能够在风景中制作全景视频的应用程序.在横向上,它支持两个方向:从左到右,从下到上.

因此,当用户从左向右移动手机或向右旋转时,我想从左向右移动箭头.当垂直向上移动设备时,也希望将箭头从底部移到顶部.在具有全景选项的原生iPhone相机应用程序中,我们可以看到正确的模拟,

我的问题是1)我怎么知道用户正在从左到右或从右到左移动手机.因为像iPhone全景,我想在用户搬回时停止录制.

另外2)我怎么知道用户正在垂直向上移动手机


补充:2017年11月10日:我确实在AppStore中看到了一个名为Spincle的应用程序.从左向右旋转设备时,它会移动箭头以拍摄360度图像.我只是设法使用俯仰和滚动来实现这一点(参见下面的代码).但是,如果我们将设备放在地板或屋顶上,这将无法工作.

import UIKit
import CoreMotion
class ViewController: UIViewController {
    private let motionManager = CMMotionManager()
    let arrowView = UIView()
    func startMotion() {
        var initialAttitude: CMAttitude?
        motionManager.deviceMotionUpdateInterval = 1
        let queue = OperationQueue.current!
        let statusBarOrientation = UIApplication.shared.statusBarOrientation
        motionManager.startDeviceMotionUpdates(using: CMAttitudeReferenceFrame.xArbitraryZVertical, to: queue) { (motiondata, err) in
            guard let data = motiondata else { return }
            if initialAttitude == nil {
                initialAttitude = data.attitude
            } else {
                let attitude = data.attitude
                // translate the attitude
                attitude.multiply(byInverseOf: initialAttitude!)
                // calculate pitch and roll of the change from our initial attitude
                let pitch = self.radiansToDegrees(attitude.pitch)
                let roll = self.radiansToDegrees(attitude.roll)
                print("\nroll = \(roll), pitch = \(pitch), yaw = \(self.radiansToDegrees(attitude.yaw))")
                print("x = \(data.userAcceleration.x), y = \(data.userAcceleration.y), z = \(data.userAcceleration.z)")
                DispatchQueue.main.async {
                    var rect = self.arrowView.frame
                    var addXPixel = self.view.frame.size.width/45
                    var addYPixel = self.view.frame.size.height/45
                    if statusBarOrientation == .landscapeRight {
                        addXPixel *= -1
                    } else {
                        addYPixel *= -1
                    }
                    rect.origin.x = (CGFloat(pitch) * addXPixel)
                    rect.origin.y = (self.view.frame.size.height/2 - 20) + (CGFloat(roll) * addYPixel)
                    self.arrowView.frame = rect
                }
            }
        }
    }
    func stopMotion() {
        motionManager.stopDeviceMotionUpdates()
    }
    func radiansToDegrees(_ radian: Double) -> Float {
        return Float(radian * 180.0/Double.pi)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(arrowView)
        arrowView.backgroundColor = UIColor.red
    }
    @IBAction func tappedButton() {
        arrowView.frame = CGRect(x: 0, y: self.view.frame.size.height/2 - 20, width: 40, height: 40)
        startMotion()
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是它会向左右移动,箭头向上或向下移动

jpu*_*til 0

我在横向模式下使用该应用程序,所以这个答案是基于此的。也许需要一点点改变才能使其适用于肖像。

我们将使用以下代码获取设备的 X、Y 和 Z 旋转。这里我们存储了初始值来获取与起始位置的角度差。

var initialAttitude: CMAttitude?
    var initialRoll: Float?
    var initialRotation: Float?//+20171219
    func startMotion() {
        initialAttitude = nil
        initialRoll = nil
        initialRotation = nil
        //leaving first two values to confirm we are starting from corect
        var counter = 0
        motionManager.deviceMotionUpdateInterval = 0.001//+20180206
        let queue = OperationQueue.current!
        //
        motionManager.startDeviceMotionUpdates(using: CMAttitudeReferenceFrame.xArbitraryZVertical, to: queue) { [weak self] (motiondata, _) in
            guard let strongSelf = self, let data = motiondata else { return }
            if strongSelf.initialAttitude == nil || counter < 2 {
                strongSelf.initialAttitude = data.attitude
                //initialize roll for horixontal rail
                let myRoll = data.attitude.roll.toDegree()
                strongSelf.initialRoll = abs(myRoll)
                //initialize yaw for vertical rail
                let rotation = (atan2(data.gravity.x, data.gravity.y) - Double.pi).toDegree()
                strongSelf.initialRotation = abs(rotation)
                //printDebug("myRoll = \(myRoll), myYaw = \(myYaw)")
                globalMainQueue.async {
                    strongSelf.delegate?.updatedMotion(roll: 0, pitch: 0, yaw: 0)
                }
                counter += 1
            } else {
                let attitude = data.attitude
                let myRoll = attitude.roll.toDegree()
                let rotation = (atan2(data.gravity.x, data.gravity.y) - Double.pi).toDegree()
                // translate the attitude
                attitude.multiply(byInverseOf: strongSelf.initialAttitude!)
                // calculate pitch and roll of the change from our initial attitude
                let quat = attitude.quaternion
                let pitch = (atan2(2*(quat.x*quat.w + quat.y*quat.z), 1 - 2*quat.x*quat.x - 2*quat.z*quat.z)).toDegree()
                //printDebug("x = \(data.userAcceleration.x), y = \(data.userAcceleration.y), z = \(data.userAcceleration.z)")
                let absRoll = abs(myRoll)
                var newAbsRoll = abs(absRoll - strongSelf.initialRoll!)
                if absRoll < strongSelf.initialRoll! {
                    newAbsRoll *= -1
                }
                printDebug("rotation = \(rotation)")
                let absRotation = abs(rotation)
                var newAbsRotation = abs(absRotation - strongSelf.initialRotation!)
                if absRotation > strongSelf.initialRotation! {
                    newAbsRotation *= -1
                }
                //printDebug("newAbsRoll = \(newAbsRoll), pitch = \(pitch), newAbsRotation = \(newAbsRotation)")
                globalMainQueue.async {
                    strongSelf.delegate?.updatedMotion(roll: newAbsRoll, pitch: pitch, yaw: newAbsRotation)
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

如果需要任何澄清,请随时询问。