Commit 9512e0d8 authored by Adrien Maglo's avatar Adrien Maglo Committed by Carola Nitz

DeviceMotion: Limit the axis and handle touch in combination with devicemotion better

The behavior is now in sync with youtube by limiting pitch to -90 and 90
This fixes issues were the user would experience jumps while panning
parent a44cec5c
......@@ -17,78 +17,56 @@ import CoreMotion
@objc(VLCDeviceMotionDelegate)
protocol DeviceMotionDelegate: NSObjectProtocol {
func deviceMotionHasAttitude(deviceMotion: DeviceMotion, pitch: Double, yaw: Double, roll: Double)
func deviceMotionHasAttitude(deviceMotion: DeviceMotion, pitch: Double, yaw: Double)
}
struct EulerAngles {
var yaw: Double = 0
var pitch: Double = 0
var roll: Double = 0
}
@objc(VLCDeviceMotion)
class DeviceMotion: NSObject {
let motion = CMMotionManager()
let sqrt2 = 0.5.squareRoot()
var lastEulerAngle: EulerAngles? = nil
var beginningQuaternion: CMQuaternion? = nil
@objc weak var delegate: DeviceMotionDelegate? = nil
@objc var yaw: CGFloat = 0
@objc var pitch: CGFloat {
//limiting the axis
set { _pitch = min(max(newValue, -90), 90) }
get { return _pitch }
}
var _pitch: CGFloat = 0
private let motion = CMMotionManager()
private let sqrt2 = 0.5.squareRoot()
private var lastEulerAngle: EulerAngles? = nil
private func multQuaternion(q1: CMQuaternion, q2: CMQuaternion) -> CMQuaternion {
var ret = CMQuaternion()
ret.x = q1.x * q2.x - q1.y * q2.y - q1.z * q2.z - q1.w * q2.w
ret.y = q1.x * q2.y + q1.y * q2.x + q1.z * q2.w - q1.w * q2.z
ret.z = q1.x * q2.z + q1.z * q2.x - q1.y * q2.w + q1.w * q2.y
ret.w = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y
ret.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
ret.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y
ret.y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x
ret.z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x - q1.z * q2.w
return ret
}
private func quaternionToEuler(qIn: CMQuaternion) -> EulerAngles {
// Change the axes
var q = CMQuaternion(x:qIn.y, y:qIn.z, z:qIn.x, w:qIn.w)
// Rotation of 90°
let qRot = CMQuaternion(x: 0, y: 0, z: -sqrt2 / 2, w: sqrt2 / 2)
// Rotationquaternion of 90°
let qRot = CMQuaternion(x: -sqrt2 / 2, y: 0, z: 0, w: sqrt2 / 2)
// Perform the rotation
q = multQuaternion(q1:qRot, q2:q)
// Now, we can perform the conversion and manage ourself the singularities
let sqx = q.x * q.x
let sqy = q.y * q.y
let sqz = q.z * q.z
let sqw = q.w * q.w
let q = multQuaternion(q1:qRot, q2:qIn)
let unit = sqx + sqy + sqz + sqw // if normalised is one, otherwise is correction factor
let test = q.x * q.y + q.z * q.w
let squaredNorm = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w
let test = q.y * q.z - q.w * q.x
//roll is 0 and we convert to degrees
var vp = EulerAngles()
if test > 0.499 * unit {
// singularity at north pole
vp.yaw = 2 * atan2(q.x, q.w)
vp.pitch = Double.pi / 2
vp.roll = 0
} else if test < -0.499 * unit {
// singularity at south pole
vp.yaw = -2 * atan2(q.x, q.w)
vp.pitch = -Double.pi / 2
vp.roll = 0
} else {
vp.yaw = atan2(2 * q.y * q.w - 2 * q.x * q.z, sqx - sqy - sqz + sqw)
vp.pitch = asin(2 * test / unit)
vp.roll = atan2(2 * q.x * q.w - 2 * q.y * q.z, -sqx + sqy - sqz + sqw)
}
vp.yaw = -vp.yaw * 180 / Double.pi
vp.pitch = vp.pitch * 180 / Double.pi
vp.roll = vp.roll * 180 / Double.pi
vp.yaw = 2 * atan2(-q.y, q.w) * 180 / Double.pi
vp.pitch = asin(2 * test / squaredNorm) * 180 / Double.pi
return vp
}
......@@ -101,42 +79,24 @@ class DeviceMotion: NSObject {
guard let strongSelf = self, let data = data else {
return
}
//get the first quaternion that we started with
if strongSelf.beginningQuaternion == nil {
strongSelf.beginningQuaternion = data.attitude.quaternion
}
var currentEuler = strongSelf.quaternionToEuler(qIn: data.attitude.quaternion)
let currentEuler = strongSelf.quaternionToEuler(qIn: data.attitude.quaternion)
// if we panned we will have a lastEuler value that we need to take as beginning angle
if let lastEulerAngle = strongSelf.lastEulerAngle {
//we get the devicemotion diff between start and currentangle
let beginningEuler = strongSelf.quaternionToEuler(qIn: strongSelf.beginningQuaternion!)
let diffYaw = currentEuler.yaw - beginningEuler.yaw
let diffPitch = currentEuler.pitch - beginningEuler.pitch
let diffRoll = currentEuler.roll - beginningEuler.roll
//and add that to the angle that we had after we lifted our finger
currentEuler.yaw = lastEulerAngle.yaw + diffYaw
currentEuler.pitch = lastEulerAngle.pitch + diffPitch
currentEuler.roll = lastEulerAngle.roll + diffRoll
let diffYaw = currentEuler.yaw - lastEulerAngle.yaw
let diffPitch = currentEuler.pitch - lastEulerAngle.pitch
strongSelf.delegate?.deviceMotionHasAttitude(deviceMotion:strongSelf, pitch:diffPitch, yaw:diffYaw)
}
strongSelf.delegate?.deviceMotionHasAttitude(deviceMotion:strongSelf, pitch:currentEuler.pitch, yaw:currentEuler.yaw, roll:currentEuler.roll)
}
}
}
@objc func lastAngle(yaw: Double, pitch: Double, roll: Double) {
if lastEulerAngle == nil {
lastEulerAngle = EulerAngles()
strongSelf.lastEulerAngle = currentEuler
}
}
lastEulerAngle?.yaw = yaw
lastEulerAngle?.pitch = pitch
lastEulerAngle?.roll = roll
}
@objc func stopDeviceMotion() {
if motion.isDeviceMotionActive {
beginningQuaternion = nil
lastEulerAngle = nil
motion.stopDeviceMotionUpdates()
}
......
......@@ -882,10 +882,19 @@ typedef NS_ENUM(NSInteger, VLCPanType) {
}
}
- (void)deviceMotionHasAttitudeWithDeviceMotion:(VLCDeviceMotion *)deviceMotion pitch:(double)pitch yaw:(double)yaw roll:(double)roll
- (void)applyYaw:(CGFloat)diffYaw pitch:(CGFloat)diffPitch;
{
//Add and limit new pitch and yaw
self.deviceMotion.yaw += diffYaw;
self.deviceMotion.pitch += diffPitch;
[_vpc updateViewpoint:self.deviceMotion.yaw pitch:self.deviceMotion.pitch roll:0 fov:_fov absolute:YES];
}
- (void)deviceMotionHasAttitudeWithDeviceMotion:(VLCDeviceMotion *)deviceMotion pitch:(double)pitch yaw:(double)yaw
{
if (_panRecognizer.state != UIGestureRecognizerStateChanged || UIGestureRecognizerStateBegan) {
[_vpc updateViewpoint:yaw pitch:pitch roll:roll fov:_fov absolute:YES];
[self applyYaw:yaw pitch:pitch];
}
}
#pragma mark - controls
......@@ -1435,7 +1444,6 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
if (panRecognizer.state == UIGestureRecognizerStateEnded) {
_currentPanType = VLCPanTypeNone;
if ([_vpc currentMediaIs360Video]) {
[_deviceMotion lastAngleWithYaw:_vpc.yaw pitch:_vpc.pitch roll:_vpc.roll];
[_deviceMotion startDeviceMotion];
}
}
......@@ -1450,13 +1458,10 @@ currentMediaHasTrackToChooseFrom:(BOOL)currentMediaHasTrackToChooseFrom
_saveLocation = newLocationInView;
//screenSizePixel width is used twice to get a constant speed on the movement.
CGFloat yaw = _fov * -diffX / _screenPixelSize.width;
CGFloat pitch = _fov * -diffY / _screenPixelSize.width;
CGFloat newYaw = _vpc.yaw + yaw;
CGFloat newPitch = _vpc.pitch + pitch;
CGFloat diffYaw = _fov * -diffX / _screenPixelSize.width;
CGFloat diffPitch = _fov * -diffY / _screenPixelSize.width;
[_vpc updateViewpoint:newYaw pitch:newPitch roll:_vpc.roll fov:_vpc.fov absolute:YES];
[self applyYaw:diffYaw pitch:diffPitch];
}
- (void)swipeRecognized:(UISwipeGestureRecognizer*)swipeRecognizer
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment