all files / src/ orbit-orientation-controls.js

0% Statements 0/50
0% Branches 0/18
0% Functions 0/6
0% Lines 0/50
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119                                                                                                                                                                                                                                             
import * as THREE from 'three';
import { OrbitControls } from './OrbitControls.js';
import { DeviceOrientationControls } from './DeviceOrientationControls.js';
 
/**
 * Convert a quaternion to an angle
 *
 * Taken from https://stackoverflow.com/a/35448946
 * Thanks P. Ellul
 */
function Quat2Angle(x, y, z, w) {
    const test = x * y + z * w;
 
    // singularity at north pole
    if (test > 0.499) {
        const yaw = 2 * Math.atan2(x, w);
        const pitch = Math.PI / 2;
        const roll = 0;
 
        return new THREE.Vector3(pitch, roll, yaw);
    }
 
    // singularity at south pole
    if (test < -0.499) {
        const yaw = -2 * Math.atan2(x, w);
        const pitch = -Math.PI / 2;
        const roll = 0;
 
        return new THREE.Vector3(pitch, roll, yaw);
    }
 
    const sqx = x * x;
    const sqy = y * y;
    const sqz = z * z;
    const yaw = Math.atan2(2 * y * w - 2 * x * z, 1 - 2 * sqy - 2 * sqz);
    const pitch = Math.asin(2 * test);
    const roll = Math.atan2(2 * x * w - 2 * y * z, 1 - 2 * sqx - 2 * sqz);
 
    return new THREE.Vector3(pitch, roll, yaw);
}
 
class OrbitOrientationControls {
    constructor(options) {
        this.object = options.camera;
        this.domElement = options.canvas;
        this.orbit = new OrbitControls(this.object, this.domElement);
 
        this.speed = 0.5;
        this.orbit.target.set(0, 1, -1);
        this.orbit.enableZoom = true;
        this.orbit.enablePan = false;
        this.orbit.rotateSpeed = -this.speed;
 
        // if orientation is supported
        if (options.orientation) {
            this.orientation = new DeviceOrientationControls(this.object);
        }
 
        // if projection is not full view
        // limit the rotation angle in order to not display back half view
        if (options.halfView) {
            this.orbit.minAzimuthAngle = -Math.PI / 4;
            this.orbit.maxAzimuthAngle = Math.PI / 4;
        }
    }
 
    update() {
        // orientation updates the camera using quaternions and
        // orbit updates the camera using angles. They are incompatible
        // and one update overrides the other. So before
        // orbit overrides orientation we convert our quaternion changes to
        // an angle change. Then save the angle into orbit so that
        // it will take those into account when it updates the camera and overrides
        // our changes
        if (this.orientation) {
            this.orientation.update();
 
            const quat = this.orientation.object.quaternion;
            const currentAngle = Quat2Angle(quat.x, quat.y, quat.z, quat.w);
 
            // we also have to store the last angle since quaternions are b
            if (typeof this.lastAngle_ === 'undefined') {
                this.lastAngle_ = currentAngle;
            }
 
            this.orbit.rotateLeft((this.lastAngle_.z - currentAngle.z) * (1 + this.speed));
            this.orbit.rotateUp((this.lastAngle_.y - currentAngle.y) * (1 + this.speed));
            this.lastAngle_ = currentAngle;
        }
 
        this.orbit.update();
    }
 
    dispose() {
        this.orbit.dispose();
 
        if (this.orientation) {
            this.orientation.dispose();
        }
    }
 
    enable() {
        this.orbit.enabled = true;
 
        if (this.orientation)
            this.orientation.enabled = true;
    }
 
    disable() {
        this.orbit.enabled = false;
 
        if (this.orientation)
            this.orientation.enabled = false;
    }
 
}
 
export default OrbitOrientationControls;