"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = exports.CONTROL_EVENTS = void 0;

var THREE = _interopRequireWildcard(require("three"));

var _AnimationPlayer = _interopRequireWildcard(require("../Core/AnimationPlayer"));

var _Coordinates = _interopRequireDefault(require("../Core/Geographic/Coordinates"));

var _Ellipsoid = require("../Core/Math/Ellipsoid");

var _CameraUtils = _interopRequireDefault(require("../Utils/CameraUtils"));

var _StateControl = _interopRequireDefault(require("./StateControl"));

// private members
var EPS = 0.000001; // Orbit

var rotateStart = new THREE.Vector2();
var rotateEnd = new THREE.Vector2();
var rotateDelta = new THREE.Vector2();
var spherical = new THREE.Spherical(1.0, 0.01, 0);
var sphericalDelta = new THREE.Spherical(1.0, 0, 0);
var orbitScale = 1.0; // Pan

var panStart = new THREE.Vector2();
var panEnd = new THREE.Vector2();
var panDelta = new THREE.Vector2();
var panOffset = new THREE.Vector3(); // Dolly

var dollyStart = new THREE.Vector2();
var dollyEnd = new THREE.Vector2();
var dollyDelta = new THREE.Vector2(); // Globe move

var moveAroundGlobe = new THREE.Quaternion();
var cameraTarget = new THREE.Object3D();
cameraTarget.matrixWorldInverse = new THREE.Matrix4();
var xyz = new _Coordinates["default"]('EPSG:4978', 0, 0, 0);
var c = new _Coordinates["default"]('EPSG:4326', 0, 0, 0); // Position object on globe

function positionObject(newPosition, object) {
  xyz.setFromVector3(newPosition).as('EPSG:4326', c);
  object.position.copy(newPosition);
  object.lookAt(c.geodesicNormal.add(newPosition));
  object.rotateX(Math.PI * 0.5);
  object.updateMatrixWorld(true);
} // Save the last time of mouse move for damping


var lastTimeMouseMove = 0; // Animations and damping

var enableAnimation = true;
var player = null;
var dampingFactor = 0.25;
var dampingMove = new THREE.Quaternion(0, 0, 0, 1);
var animationDampingMove = new _AnimationPlayer.Animation({
  duration: 120,
  name: 'damping-move'
});
var animationDampingOrbital = new _AnimationPlayer.Animation({
  duration: 60,
  name: 'damping-orbit'
}); // Pan Move

var panVector = new THREE.Vector3(); // Save last transformation

var lastPosition = new THREE.Vector3();
var lastQuaternion = new THREE.Quaternion(); // Tangent sphere to ellipsoid

var pickSphere = new THREE.Sphere();
var pickingPoint = new THREE.Vector3(); // Sphere intersection

var intersection = new THREE.Vector3(); // Set to true to enable target helper

var enableTargetHelper = false;
var helpers = {};
// current downed key
var currentKey;
/**
 * Globe control pan event. Fires after camera pan
 * @event GlobeControls#pan-changed
 * @property target {GlobeControls} dispatched on controls
 * @property type {string} orientation-changed
 */

/**
 * Globe control orientation event. Fires when camera's orientation change
 * @event GlobeControls#orientation-changed
 * @property new {object}
 * @property new.tilt {number} the new value of the tilt of the camera
 * @property new.heading {number} the new value of the heading of the camera
 * @property previous {object}
 * @property previous.tilt {number} the previous value of the tilt of the camera
 * @property previous.heading {number} the previous value of the heading of the camera
 * @property target {GlobeControls} dispatched on controls
 * @property type {string} orientation-changed
 */

/**
 * Globe control range event. Fires when camera's range to target change
 * @event GlobeControls#range-changed
 * @property new {number} the new value of the range
 * @property previous {number} the previous value of the range
 * @property target {GlobeControls} dispatched on controls
 * @property type {string} range-changed
 */

/**
 * Globe control camera's target event. Fires when camera's target change
 * @event GlobeControls#camera-target-changed
 * @property new {object}
 * @property new {Coordinates} the new camera's target coordinates
 * @property previous {Coordinates} the previous camera's target coordinates
 * @property target {GlobeControls} dispatched on controls
 * @property type {string} camera-target-changed
 */

/**
 * globe controls events
 * @property PAN_CHANGED {string} Fires after camera pan
 * @property ORIENTATION_CHANGED {string} Fires when camera's orientation change
 * @property RANGE_CHANGED {string} Fires when camera's range to target change
 * @property CAMERA_TARGET_CHANGED {string} Fires when camera's target change
 */

var CONTROL_EVENTS = {
  PAN_CHANGED: 'pan-changed',
  ORIENTATION_CHANGED: 'orientation-changed',
  RANGE_CHANGED: 'range-changed',
  CAMERA_TARGET_CHANGED: 'camera-target-changed'
};
exports.CONTROL_EVENTS = CONTROL_EVENTS;
var previous;
/**
 * GlobeControls is a camera controller
 *
 * @class      GlobeControls
 * @param      {GlobeView}  view the view where the control will be used
 * @param      {Coordinates}  targetCoordinate the target looked by camera, at initialization
 * @param      {number}  range distance between the target looked and camera, at initialization
 * @param      {number}  globeRadius The globe's radius
 * @param      {object}  options
 * @param      {number}  options.zoomSpeed Speed zoom with mouse
 * @param      {number}  options.rotateSpeed Speed camera rotation in orbit and panoramic mode
 * @param      {number}  options.minDistance Minimum distance between ground and camera
 * @param      {number}  options.maxDistance Maximum distance between ground and camera
 * @param      {bool}  options.handleCollision enable collision camera with ground
 * @property   {bool} enabled enable control
 * @property   {number} minDistance Minimum distance between ground and camera
 * @property   {number} maxDistance Maximum distance between ground and camera
 * @property   {number} zoomSpeed Speed zoom with mouse
 * @property   {number} rotateSpeed Speed camera rotation in orbit and panoramic mode
 * @property   {number} minDistanceCollision Minimum distance collision between ground and camera
 * @property   {bool} enableDamping enable camera damping, if it's disabled the camera immediately when the mouse button is released.
 * If it's enabled, the camera movement is decelerate.
 */

function GlobeControls(view, targetCoordinate, range, globeRadius) {
  var _this = this;

  var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
  player = new _AnimationPlayer["default"]();
  this._view = view;
  this.camera = view.camera.camera3D;
  this.domElement = view.mainLoop.gfxEngine.renderer.domElement; // State control

  var state;
  var states = new _StateControl["default"]();
  state = states.NONE;

  this.getStates = function () {
    return states;
  };

  this.isPaused = function () {
    return state == states.NONE;
  }; // Set to false to disable this control


  this.enabled = true; // This option actually enables dollying in and out; left as "zoom" for
  // backwards compatibility

  this.zoomSpeed = options.zoomSpeed || 2.0; // Limits to how far you can dolly in and out ( PerspectiveCamera only )

  this.minDistance = options.minDistance || 250;
  this.maxDistance = options.maxDistance || globeRadius * 8.0; // Limits to how far you can zoom in and out ( OrthographicCamera only )

  this.minZoom = 0;
  this.maxZoom = Infinity; // Set to true to disable this control

  this.rotateSpeed = options.rotateSpeed || 0.25; // Set to true to disable this control

  this.keyPanSpeed = 7.0; // pixels moved per arrow key push
  // How far you can orbit vertically, upper and lower limits.
  // Range is 0 to Math.PI radians.
  // TODO Warning minPolarAngle = 0.01 -> it isn't possible to be perpendicular on Globe

  this.minPolarAngle = THREE.Math.degToRad(0.5); // radians

  this.maxPolarAngle = THREE.Math.degToRad(86); // radians
  // How far you can orbit horizontally, upper and lower limits.
  // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].

  this.minAzimuthAngle = -Infinity; // radians

  this.maxAzimuthAngle = Infinity; // radians
  // Set collision options

  this.handleCollision = typeof options.handleCollision !== 'undefined' ? options.handleCollision : true;
  this.minDistanceCollision = 60; // Set to true to disable use of the keys

  this.enableKeys = true; // Enable Damping

  this.enableDamping = true;
  this.startEvent = {
    type: 'start'
  };
  this.endEvent = {
    type: 'end'
  };

  this.getDollyScale = function () {
    return Math.pow(0.95, this.zoomSpeed);
  };

  this.rotateLeft = function () {
    var angle = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
    sphericalDelta.theta -= angle;
  };

  this.rotateUp = function () {
    var angle = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
    sphericalDelta.phi -= angle;
  }; // pass in distance in world space to move left


  this.panLeft = function (distance) {
    var te = this.camera.matrix.elements; // get X column of matrix

    panOffset.fromArray(te);
    panOffset.multiplyScalar(-distance);
    panVector.add(panOffset);
  }; // pass in distance in world space to move up


  this.panUp = function (distance) {
    var te = this.camera.matrix.elements; // get Y column of matrix

    panOffset.fromArray(te, 4);
    panOffset.multiplyScalar(distance);
    panVector.add(panOffset);
  }; // pass in x,y of change desired in pixel space,
  // right and down are positive


  this._mouseToPan = function (deltaX, deltaY) {
    var gfx = view.mainLoop.gfxEngine;
    state = states.PAN;

    if (this.camera.isPerspectiveCamera) {
      var targetDistance = this.camera.position.distanceTo(this.getCameraTargetPosition()); // half of the fov is center to top of screen

      targetDistance *= 2 * Math.tan(THREE.Math.degToRad(this.camera.fov * 0.5)); // we actually don't use screenWidth, since perspective camera is fixed to screen height

      this.panLeft(deltaX * targetDistance / gfx.width * this.camera.aspect);
      this.panUp(deltaY * targetDistance / gfx.height);
    } else if (this.camera.isOrthographicCamera) {
      // orthographic
      this.panLeft(deltaX * (this.camera.right - this.camera.left) / gfx.width);
      this.panUp(deltaY * (this.camera.top - this.camera.bottom) / gfx.height);
    }
  };

  this.dollyIn = function (dollyScale) {
    if (dollyScale === undefined) {
      dollyScale = this.getDollyScale();
    }

    if (this.camera.isPerspectiveCamera) {
      orbitScale /= dollyScale;
    } else if (this.camera.isOrthographicCamera) {
      this.camera.zoom = THREE.Math.clamp(this.camera.zoom * dollyScale, this.minZoom, this.maxZoom);
      this.camera.updateProjectionMatrix();
      view.notifyChange(this.camera);
    }
  };

  this.dollyOut = function (dollyScale) {
    if (dollyScale === undefined) {
      dollyScale = this.getDollyScale();
    }

    if (this.camera.isPerspectiveCamera) {
      orbitScale *= dollyScale;
    } else if (this.camera.isOrthographicCamera) {
      this.camera.zoom = THREE.Math.clamp(this.camera.zoom / dollyScale, this.minZoom, this.maxZoom);
      this.camera.updateProjectionMatrix();
      view.notifyChange(this.camera);
    }
  };

  var quaterPano = new THREE.Quaternion();
  var quaterAxis = new THREE.Quaternion();
  var axisX = new THREE.Vector3(1, 0, 0);
  var minDistanceZ = Infinity;

  var getMinDistanceCameraBoundingSphereObbsUp = function (tile) {
    if (tile.level > 10 && tile.children.length == 1 && tile.geometry) {
      var obb = tile.obb;
      var sphereCamera = {
        position: _this.camera.position.clone(),
        radius: _this.minDistanceCollision
      };

      if (obb.isSphereAboveXYBox(sphereCamera)) {
        minDistanceZ = Math.min(sphereCamera.position.z - obb.box3D.max.z, minDistanceZ);
      }
    }
  };

  var lastNormalizedIntersection = new THREE.Vector3();
  var normalizedIntersection = new THREE.Vector3();

  var update = function () {
    // We compute distance between camera's bounding sphere and geometry's obb up face
    if (_this.handleCollision) {
      // We check distance to the ground/surface geometry
      // add minDistanceZ between camera's bounding and tiles's oriented bounding box (up face only)
      // Depending on the distance of the camera with obbs, we add a slowdown or constrain to the movement.
      // this constraint or deceleration is suitable for two types of movement MOVE_GLOBE and ORBIT.
      // This constraint or deceleration inversely proportional to the camera/obb distance
      if (view.tileLayer) {
        minDistanceZ = Infinity;
        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
          for (var _iterator = view.tileLayer.level0Nodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var tile = _step.value;
            tile.traverse(getMinDistanceCameraBoundingSphereObbsUp);
          }
        } catch (err) {
          _didIteratorError = true;
          _iteratorError = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion && _iterator["return"] != null) {
              _iterator["return"]();
            }
          } finally {
            if (_didIteratorError) {
              throw _iteratorError;
            }
          }
        }
      }
    }

    switch (state) {
      // MOVE_GLOBE Rotate globe with mouse
      case states.MOVE_GLOBE:
        if (minDistanceZ < 0) {
          cameraTarget.translateY(-minDistanceZ);

          _this.camera.position.setLength(_this.camera.position.length() - minDistanceZ);
        } else if (minDistanceZ < _this.minDistanceCollision) {
          var translate = _this.minDistanceCollision * (1.0 - minDistanceZ / _this.minDistanceCollision);
          cameraTarget.translateY(translate);

          _this.camera.position.setLength(_this.camera.position.length() + translate);
        }

        lastNormalizedIntersection.copy(normalizedIntersection).applyQuaternion(moveAroundGlobe);
        cameraTarget.position.applyQuaternion(moveAroundGlobe);

        _this.camera.position.applyQuaternion(moveAroundGlobe);

        break;
      // PAN Move camera in projection plan

      case states.PAN:
        _this.camera.position.add(panVector);

        cameraTarget.position.add(panVector);
        break;
      // PANORAMIC Move target camera

      case states.PANORAMIC:
        {
          _this.camera.worldToLocal(cameraTarget.position);

          var normal = _this.camera.position.clone().normalize().applyQuaternion(_this.camera.quaternion.clone().inverse());

          quaterPano.setFromAxisAngle(normal, sphericalDelta.theta).multiply(quaterAxis.setFromAxisAngle(axisX, sphericalDelta.phi));
          cameraTarget.position.applyQuaternion(quaterPano);

          _this.camera.localToWorld(cameraTarget.position);

          break;
        }
      // ZOOM/ORBIT Move Camera around the target camera

      default:
        {
          // get camera position in local space of target
          _this.camera.position.applyMatrix4(cameraTarget.matrixWorldInverse); // angle from z-axis around y-axis


          if (sphericalDelta.theta || sphericalDelta.phi) {
            spherical.setFromVector3(_this.camera.position);
          } // far underground


          var dynamicRadius = spherical.radius * Math.sin(_this.minPolarAngle);
          var slowdownLimit = dynamicRadius * 8;
          var contraryLimit = dynamicRadius * 2;
          var minContraintPhi = -0.01;

          if (minDistanceZ < slowdownLimit && minDistanceZ > contraryLimit && sphericalDelta.phi > 0) {
            // slowdown zone : slowdown sphericalDelta.phi
            var slowdownZone = slowdownLimit - contraryLimit; // the deeper the camera is in this zone, the bigger the factor is

            var slowdownFactor = 1 - (slowdownZone - (minDistanceZ - contraryLimit)) / slowdownZone; // apply slowdown factor on tilt mouvement

            sphericalDelta.phi *= slowdownFactor * slowdownFactor;
          } else if (minDistanceZ < contraryLimit && minDistanceZ > -contraryLimit && sphericalDelta.phi > minContraintPhi) {
            // contraint zone : contraint sphericalDelta.phi
            // calculation of the angle of rotation which allows to leave this zone
            var contraryPhi = -Math.asin((contraryLimit - minDistanceZ) * 0.25 / spherical.radius); // clamp contraryPhi to make a less brutal exit

            contraryPhi = THREE.Math.clamp(contraryPhi, minContraintPhi, 0); // the deeper the camera is in this zone, the bigger the factor is

            var contraryFactor = 1 - (contraryLimit - minDistanceZ) / (2 * contraryLimit);
            sphericalDelta.phi = THREE.Math.lerp(sphericalDelta.phi, contraryPhi, contraryFactor);
            minDistanceZ -= Math.sin(sphericalDelta.phi) * spherical.radius;
          }

          spherical.theta += sphericalDelta.theta;
          spherical.phi += sphericalDelta.phi; // restrict spherical.theta to be between desired limits

          spherical.theta = Math.max(_this.minAzimuthAngle, Math.min(_this.maxAzimuthAngle, spherical.theta)); // restrict spherical.phi to be between desired limits

          spherical.phi = Math.max(_this.minPolarAngle, Math.min(_this.maxPolarAngle, spherical.phi));
          spherical.radius = _this.camera.position.length() * orbitScale; // restrict spherical.phi to be betwee EPS and PI-EPS

          spherical.makeSafe(); // restrict radius to be between desired limits

          spherical.radius = Math.max(_this.minDistance, Math.min(_this.maxDistance, spherical.radius));

          _this.camera.position.setFromSpherical(spherical); // if camera is underground, so move up camera


          if (minDistanceZ < 0) {
            _this.camera.position.y -= minDistanceZ;
            spherical.setFromVector3(_this.camera.position);
            sphericalDelta.phi = 0;
          }

          cameraTarget.localToWorld(_this.camera.position);
        }
    }

    _this.camera.up.copy(cameraTarget.position).normalize();

    _this.camera.lookAt(cameraTarget.position);

    if (!_this.enableDamping) {
      sphericalDelta.theta = 0;
      sphericalDelta.phi = 0;
      moveAroundGlobe.set(0, 0, 0, 1);
    } else {
      sphericalDelta.theta *= 1 - dampingFactor;
      sphericalDelta.phi *= 1 - dampingFactor;
      moveAroundGlobe.slerp(dampingMove, dampingFactor * 0.2);
    }

    orbitScale = 1;
    panVector.set(0, 0, 0); // update condition is:
    // min(camera displacement, camera rotation in radians)^2 > EPS
    // using small-angle approximation cos(x/2) = 1 - x^2 / 8

    if (lastPosition.distanceToSquared(_this.camera.position) > EPS || 8 * (1 - lastQuaternion.dot(_this.camera.quaternion)) > EPS) {
      view.notifyChange(_this.camera);
      lastPosition.copy(_this.camera.position);
      lastQuaternion.copy(_this.camera.quaternion);
    } // Launch animationdamping if mouse stops these movements


    if (_this.enableDamping && state === states.ORBIT && player.isStopped() && (sphericalDelta.theta > EPS || sphericalDelta.phi > EPS)) {
      player.playLater(animationDampingOrbital, 2);
    }
  };

  this.update = update; // Update helper

  var updateHelper = enableTargetHelper ? function (position, helper) {
    positionObject(position, helper);
    view.notifyChange(this.camera);
  } : function () {};
  var raycaster = new THREE.Raycaster();

  function onMouseMove(event) {
    if (player.isPlaying()) {
      player.stop();
    }

    if (this.enabled === false) {
      return;
    }

    event.preventDefault();
    var coords = view.eventToViewCoords(event);

    switch (state) {
      case states.ORBIT:
      case states.PANORAMIC:
        {
          rotateEnd.copy(coords);
          rotateDelta.subVectors(rotateEnd, rotateStart);
          var gfx = view.mainLoop.gfxEngine;
          this.rotateLeft(2 * Math.PI * rotateDelta.x / gfx.width * this.rotateSpeed); // rotating up and down along whole screen attempts to go 360, but limited to 180

          this.rotateUp(2 * Math.PI * rotateDelta.y / gfx.height * this.rotateSpeed);
          rotateStart.copy(rotateEnd);
          break;
        }

      case states.DOLLY:
        dollyEnd.copy(coords);
        dollyDelta.subVectors(dollyEnd, dollyStart);

        if (dollyDelta.y > 0) {
          this.dollyIn();
        } else if (dollyDelta.y < 0) {
          this.dollyOut();
        }

        dollyStart.copy(dollyEnd);
        break;

      case states.PAN:
        panEnd.copy(coords);
        panDelta.subVectors(panEnd, panStart);

        this._mouseToPan(panDelta.x, panDelta.y);

        panStart.copy(panEnd);
        break;

      case states.MOVE_GLOBE:
        {
          var normalized = view.viewToNormalizedCoords(coords);
          raycaster.setFromCamera(normalized, this.camera);
          raycaster.ray.intersectSphere(pickSphere, intersection); // If there's intersection then move globe else we stop the move

          if (intersection) {
            normalizedIntersection.copy(intersection).normalize();
            moveAroundGlobe.setFromUnitVectors(normalizedIntersection, lastNormalizedIntersection);
            lastTimeMouseMove = Date.now();
          } else {
            onMouseUp.bind(this)();
          }

          break;
        }

      default:
    }

    if (state !== states.NONE) {
      update();
    }
  }

  var targetPosition = new THREE.Vector3();
  var pickedPosition = new THREE.Vector3();

  var updateTarget = function () {
    // Update camera's target position
    view.getPickingPositionFromDepth(null, pickedPosition);
    var distance = !isNaN(pickedPosition.x) ? _this.camera.position.distanceTo(pickedPosition) : 100;
    targetPosition.set(0, 0, -distance);

    _this.camera.localToWorld(targetPosition); // set new camera target on globe


    positionObject(targetPosition, cameraTarget);
    cameraTarget.matrixWorldInverse.getInverse(cameraTarget.matrixWorld);
    targetPosition.copy(_this.camera.position);
    targetPosition.applyMatrix4(cameraTarget.matrixWorldInverse);
    spherical.setFromVector3(targetPosition);
  };

  var _onMouseMoveListener = onMouseMove.bind(this);

  var _onMouseUpListener = onMouseUp.bind(this);

  function onMouseDown(event) {
    var _this2 = this;

    _CameraUtils["default"].stop(view, this.camera);

    return player.stop().then(function () {
      if (_this2.enabled === false) {
        return;
      }

      event.preventDefault();
      updateTarget();
      previous = _CameraUtils["default"].getTransformCameraLookingAtTarget(view, _this2.camera);
      state = states.inputToState(event.button, currentKey);
      var coords = view.eventToViewCoords(event);

      switch (state) {
        case states.ORBIT:
        case states.PANORAMIC:
          rotateStart.copy(coords);
          break;

        case states.MOVE_GLOBE:
          {
            // update picking on sphere
            if (view.getPickingPositionFromDepth(coords, pickingPoint)) {
              pickSphere.radius = pickingPoint.length();
              lastNormalizedIntersection.copy(pickingPoint).normalize();
              updateHelper.bind(_this2)(pickingPoint, helpers.picking);
            } else {
              state = states.NONE;
            }

            break;
          }

        case states.DOLLY:
          dollyStart.copy(coords);
          break;

        case states.PAN:
          panStart.copy(coords);
          break;

        default:
      }

      if (state != states.NONE) {
        _this2.domElement.addEventListener('mousemove', _onMouseMoveListener, false);

        _this2.domElement.addEventListener('mouseup', _onMouseUpListener, false);

        _this2.domElement.addEventListener('mouseleave', _onMouseUpListener, false);

        _this2.dispatchEvent(_this2.startEvent);
      }
    });
  }

  function ondblclick(event) {
    var _this3 = this;

    if (this.enabled === false || currentKey) {
      return;
    }

    return player.stop().then(function () {
      var point = view.getPickingPositionFromDepth(view.eventToViewCoords(event));

      var range = _this3.getRange();

      if (point && range > _this3.minDistance) {
        _this3.lookAtCoordinate({
          coord: new _Coordinates["default"]('EPSG:4978', point),
          range: range * 0.6,
          time: 1500
        });
      }
    });
  }

  this._handlingEvent = function (current) {
    current = current || _CameraUtils["default"].getTransformCameraLookingAtTarget(view, _this.camera);

    var diff = _CameraUtils["default"].getDiffParams(previous, current);

    if (diff) {
      if (diff.range) {
        _this.dispatchEvent({
          type: CONTROL_EVENTS.RANGE_CHANGED,
          previous: diff.range.previous,
          "new": diff.range["new"]
        });
      }

      if (diff.coord) {
        _this.dispatchEvent({
          type: CONTROL_EVENTS.CAMERA_TARGET_CHANGED,
          previous: diff.coord.previous,
          "new": diff.coord["new"]
        });
      }

      if (diff.tilt || diff.heading) {
        var event = {
          type: CONTROL_EVENTS.ORIENTATION_CHANGED
        };

        if (diff.tilt) {
          event.previous = {
            tilt: diff.tilt.previous
          };
          event["new"] = {
            tilt: diff.tilt["new"]
          };
        }

        if (diff.heading) {
          event.previous = event.previous || {};
          event["new"] = event["new"] || {};
          event["new"].heading = diff.heading["new"];
          event.previous.heading = diff.heading.previous;
        }

        _this.dispatchEvent(event);
      }
    }
  };

  this._onEndingMove = function (current) {
    state = states.NONE;

    _this._handlingEvent(current);
  };

  function onMouseUp() {
    if (this.enabled === false) {
      return;
    }

    this.domElement.removeEventListener('mousemove', _onMouseMoveListener, false);
    this.domElement.removeEventListener('mouseup', _onMouseUpListener, false);
    this.domElement.removeEventListener('mouseleave', _onMouseUpListener, false);
    this.dispatchEvent(this.endEvent);
    player.stop(); // Launch damping movement for :
    //      * states.ORBIT
    //      * states.MOVE_GLOBE

    if (this.enableDamping) {
      if (state === states.ORBIT && (sphericalDelta.theta > EPS || sphericalDelta.phi > EPS)) {
        player.play(animationDampingOrbital).then(this._onEndingMove);
      } else if (state === states.MOVE_GLOBE && Date.now() - lastTimeMouseMove < 50) {
        // animation since mouse up event occurs less than 50ms after the last mouse move
        player.play(animationDampingMove).then(this._onEndingMove);
      } else {
        this._onEndingMove();
      }
    } else {
      this._onEndingMove();
    }
  }

  function onMouseWheel(event) {
    var _this4 = this;

    return player.stop().then(function () {
      if (!_this4.enabled || !states.DOLLY.enable) {
        return;
      }

      _CameraUtils["default"].stop(view, _this4.camera);

      event.preventDefault();
      event.stopPropagation();
      updateTarget();
      var delta = 0; // WebKit / Opera / Explorer 9

      if (event.wheelDelta !== undefined) {
        delta = event.wheelDelta; // Firefox
      } else if (event.detail !== undefined) {
        delta = -event.detail;
      }

      if (delta > 0) {
        _this4.dollyOut();
      } else if (delta < 0) {
        _this4.dollyIn();
      }

      var previousRange = _this4.getRange();

      update();

      var newRange = _this4.getRange();

      if (Math.abs(newRange - previousRange) / previousRange > 0.001) {
        _this4.dispatchEvent({
          type: CONTROL_EVENTS.RANGE_CHANGED,
          previous: previousRange,
          "new": newRange
        });
      }

      _this4.dispatchEvent(_this4.startEvent);

      _this4.dispatchEvent(_this4.endEvent);
    });
  }

  function onKeyUp() {
    if (this.enabled === false || this.enableKeys === false) {
      return;
    }

    currentKey = undefined;
  }

  function onKeyDown(event) {
    var _this5 = this;

    return player.stop().then(function () {
      if (_this5.enabled === false || _this5.enableKeys === false) {
        return;
      }

      currentKey = event.keyCode;

      switch (event.keyCode) {
        case states.PAN.up:
          _this5._mouseToPan(0, _this5.keyPanSpeed);

          state = states.PAN;
          update();
          break;

        case states.PAN.bottom:
          _this5._mouseToPan(0, -_this5.keyPanSpeed);

          state = states.PAN;
          update();
          break;

        case states.PAN.left:
          _this5._mouseToPan(_this5.keyPanSpeed, 0);

          state = states.PAN;
          update();
          break;

        case states.PAN.right:
          _this5._mouseToPan(-_this5.keyPanSpeed, 0);

          state = states.PAN;
          update();
          break;

        default:
      }
    });
  }

  function onTouchStart(event) {
    var _this6 = this;

    // CameraUtils.stop(view);
    return player.stop().then(function () {
      if (_this6.enabled === false) {
        return;
      }

      state = states.touchToState(event.touches.length);
      updateTarget();

      if (state !== states.NONE) {
        switch (state) {
          case states.MOVE_GLOBE:
            {
              var coords = view.eventToViewCoords(event);

              if (view.getPickingPositionFromDepth(coords, pickingPoint)) {
                pickSphere.radius = pickingPoint.length();
                lastNormalizedIntersection.copy(pickingPoint).normalize();
                updateHelper.bind(_this6)(pickingPoint, helpers.picking);
              } else {
                state = states.NONE;
              }

              break;
            }

          case states.ORBIT:
          case states.DOLLY:
            {
              var x = event.touches[0].pageX;
              var y = event.touches[0].pageY;
              var dx = x - event.touches[1].pageX;
              var dy = y - event.touches[1].pageY;
              var distance = Math.sqrt(dx * dx + dy * dy);
              dollyStart.set(0, distance);
              rotateStart.set(x, y);
              break;
            }

          case states.PAN:
            panStart.set(event.touches[0].pageX, event.touches[0].pageY);
            break;

          default:
        }

        _this6.dispatchEvent(_this6.startEvent);
      }
    });
  }

  function onTouchMove(event) {
    if (player.isPlaying()) {
      player.stop();
    }

    if (this.enabled === false) {
      return;
    }

    event.preventDefault();
    event.stopPropagation();

    switch (event.touches.length) {
      case states.MOVE_GLOBE.finger:
        {
          var coords = view.eventToViewCoords(event);
          var normalized = view.viewToNormalizedCoords(coords);
          raycaster.setFromCamera(normalized, this.camera);
          raycaster.ray.intersectSphere(pickSphere, intersection); // If there's intersection then move globe else we stop the move

          if (intersection) {
            normalizedIntersection.copy(intersection).normalize();
            moveAroundGlobe.setFromUnitVectors(normalizedIntersection, lastNormalizedIntersection);
            lastTimeMouseMove = Date.now();
          } else {
            onMouseUp.bind(this)();
          }

          break;
        }

      case states.ORBIT.finger:
      case states.DOLLY.finger:
        {
          var gfx = view.mainLoop.gfxEngine;
          rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
          rotateDelta.subVectors(rotateEnd, rotateStart); // rotating across whole screen goes 360 degrees around

          this.rotateLeft(2 * Math.PI * rotateDelta.x / gfx.width * this.rotateSpeed); // rotating up and down along whole screen attempts to go 360, but limited to 180

          this.rotateUp(2 * Math.PI * rotateDelta.y / gfx.height * this.rotateSpeed);
          rotateStart.copy(rotateEnd);
          var dx = event.touches[0].pageX - event.touches[1].pageX;
          var dy = event.touches[0].pageY - event.touches[1].pageY;
          var distance = Math.sqrt(dx * dx + dy * dy);
          dollyEnd.set(0, distance);
          dollyDelta.subVectors(dollyEnd, dollyStart);

          if (dollyDelta.y > 0) {
            this.dollyOut();
          } else if (dollyDelta.y < 0) {
            this.dollyIn();
          }

          dollyStart.copy(dollyEnd);
          break;
        }

      case states.PAN.finger:
        panEnd.set(event.touches[0].pageX, event.touches[0].pageY);
        panDelta.subVectors(panEnd, panStart);

        this._mouseToPan(panDelta.x, panDelta.y);

        panStart.copy(panEnd);
        break;

      default:
        state = states.NONE;
    }

    if (state !== states.NONE) {
      update();
    }
  }

  var _onMouseDownListener = onMouseDown.bind(this);

  var _onMouseWheelListener = onMouseWheel.bind(this);

  var _ondblclickListener = ondblclick.bind(this);

  var _onTouchStartListener = onTouchStart.bind(this);

  var _onTouchEndListener = function ()
  /* event */
  {
    onMouseUp.bind(this)();
  }.bind(this);

  var _onTouchMoveListener = onTouchMove.bind(this);

  var _onKeyDownListener = onKeyDown.bind(this);

  var _onKeyUpListener = onKeyUp.bind(this);

  var _onContextMenuListener = function (event) {
    event.preventDefault();
  };

  var _updateListener = this.update;

  var _onBlurListener = function () {
    onKeyUp.bind(_this)();
    onMouseUp.bind(_this)();
  };

  this.dispose = function () {
    this.domElement.removeEventListener('contextmenu', _onContextMenuListener, false);
    this.domElement.removeEventListener('mousedown', _onMouseDownListener, false);
    this.domElement.removeEventListener('mousemove', _onMouseMoveListener, false);
    this.domElement.removeEventListener('mousewheel', _onMouseWheelListener, false);
    this.domElement.removeEventListener('DOMMouseScroll', _onMouseWheelListener, false); // firefox

    this.domElement.removeEventListener('mouseup', _onMouseUpListener, false);
    this.domElement.removeEventListener('mouseleave', _onMouseUpListener, false);
    this.domElement.removeEventListener('dblclick', _ondblclickListener, false);
    this.domElement.removeEventListener('touchstart', _onTouchStartListener, false);
    this.domElement.removeEventListener('touchend', _onTouchEndListener, false);
    this.domElement.removeEventListener('touchmove', _onTouchMoveListener, false);
    player.removeEventListener('animation-frame', _updateListener);
    window.removeEventListener('keydown', _onKeyDownListener, false);
    window.removeEventListener('keyup', _onKeyUpListener, false);
    window.removeEventListener('blur', _onBlurListener);
    this.dispatchEvent({
      type: 'dispose'
    });
  }; // Instance all


  this.domElement.addEventListener('contextmenu', _onContextMenuListener, false);
  this.domElement.addEventListener('mousedown', _onMouseDownListener, false);
  this.domElement.addEventListener('mousewheel', _onMouseWheelListener, false);
  this.domElement.addEventListener('dblclick', _ondblclickListener, false);
  this.domElement.addEventListener('DOMMouseScroll', _onMouseWheelListener, false); // firefox

  this.domElement.addEventListener('touchstart', _onTouchStartListener, false);
  this.domElement.addEventListener('touchend', _onTouchEndListener, false);
  this.domElement.addEventListener('touchmove', _onTouchMoveListener, false); // refresh control for each animation's frame

  player.addEventListener('animation-frame', _updateListener); // TODO: Why windows

  window.addEventListener('keydown', _onKeyDownListener, false);
  window.addEventListener('keyup', _onKeyUpListener, false); // Reset key/mouse when window loose focus

  window.addEventListener('blur', _onBlurListener);
  view.scene.add(cameraTarget);

  if (enableTargetHelper) {
    cameraTarget.add(helpers.target);
    view.scene.add(helpers.picking);
    var layerTHREEjs = view.mainLoop.gfxEngine.getUniqueThreejsLayer();
    helpers.target.layers.set(layerTHREEjs);
    helpers.picking.layers.set(layerTHREEjs);
    this.camera.layers.enable(layerTHREEjs);
  }

  positionObject(targetCoordinate.as('EPSG:4978', xyz), cameraTarget);
  this.lookAtCoordinate({
    coord: targetCoordinate,
    tilt: 89.5,
    heading: 0,
    range: range
  }, false);
}

GlobeControls.prototype = Object.create(THREE.EventDispatcher.prototype);
GlobeControls.prototype.constructor = GlobeControls;

function getRangeFromScale(scale, pitch, fov, height) {
  // Screen pitch, in millimeters
  pitch = (pitch || 0.28) / 1000;
  fov = THREE.Math.degToRad(fov); // Invert one unit projection (see getDollyScale)

  var range = pitch * height / (scale * 2 * Math.tan(fov * 0.5));
  return range;
}
/**
 * Changes the tilt of the current camera, in degrees.
 * @param {number}  tilt
 * @param {boolean} isAnimated
 * @return {Promise<void>}
 */


GlobeControls.prototype.setTilt = function (tilt, isAnimated) {
  return this.lookAtCoordinate({
    tilt: tilt
  }, isAnimated);
};
/**
 * Changes the heading of the current camera, in degrees.
 * @param {number} heading
 * @param {boolean} isAnimated
 * @return {Promise<void>}
 */


GlobeControls.prototype.setHeading = function (heading, isAnimated) {
  return this.lookAtCoordinate({
    heading: heading
  }, isAnimated);
};
/**
 * Sets the "range": the distance in meters between the camera and the current central point on the screen.
 * @param {number} range
 * @param {boolean} isAnimated
 * @return {Promise<void>}
 */


GlobeControls.prototype.setRange = function (range, isAnimated) {
  return this.lookAtCoordinate({
    range: range
  }, isAnimated);
};
/**
 * Returns the {@linkcode Coordinates} of the globe point targeted by the camera in EPSG:4978 projection. See {@linkcode Coordinates} for conversion
 * @return {THREE.Vector3} position
 */


GlobeControls.prototype.getCameraTargetPosition = function () {
  return cameraTarget.position;
};
/**
 * Returns the "range": the distance in meters between the camera and the current central point on the screen.
 * @return {number} number
 */


GlobeControls.prototype.getRange = function () {
  return _CameraUtils["default"].getTransformCameraLookingAtTarget(this._view, this.camera).range;
};
/**
 * Returns the tilt of the current camera in degrees.
 * @return {Angle} number - The angle of the rotation in degrees.
 */


GlobeControls.prototype.getTilt = function () {
  return _CameraUtils["default"].getTransformCameraLookingAtTarget(this._view, this.camera).tilt;
};
/**
 * Returns the heading of the current camera in degrees.
 * @return {Angle} number - The angle of the rotation in degrees.
 */


GlobeControls.prototype.getHeading = function () {
  return _CameraUtils["default"].getTransformCameraLookingAtTarget(this._view, this.camera).heading;
};
/**
 * Displaces the central point to a specific amount of pixels from its current position.
 * The view flies to the desired coordinate, i.e.is not teleported instantly. Note : The results can be strange in some cases, if ever possible, when e.g.the camera looks horizontally or if the displaced center would not pick the ground once displaced.
 * @param      {vector}  pVector  The vector
 * @return {Promise}
 */


GlobeControls.prototype.pan = function (pVector) {
  this._mouseToPan(pVector.x, pVector.y);

  this.update();
  return Promise.resolve();
};
/**
 * Returns the orientation angles of the current camera, in degrees.
 * @return {Array<number>}
 */


GlobeControls.prototype.getCameraOrientation = function () {
  return [this.getTilt(), this.getHeading()];
};
/**
 * Returns the camera location projected on the ground in lat,lon. See {@linkcode Coordinates} for conversion.
 * @return {Coordinates} position
 */


GlobeControls.prototype.getCameraCoordinate = function () {
  return new _Coordinates["default"]('EPSG:4978', this.camera.position).as('EPSG:4326');
};
/**
 * @deprecated
 * Returns the {@linkcode Coordinates} of the central point on screen in lat,lon. See {@linkcode Coordinates} for conversion.
 * @return {Position} position
 */


GlobeControls.prototype.getCameraTargetGeoPosition = function () {
  console.warn('getCameraTargetGeoPosition has been deprecated, use getLookAtCoordinate');
  return this.getLookAtCoordinate();
};
/**
 * Returns the {@linkcode Coordinates} of the central point on screen in lat,lon. See {@linkcode Coordinates} for conversion.
 * @return {Coordinates} coordinate
 */


GlobeControls.prototype.getLookAtCoordinate = function () {
  return _CameraUtils["default"].getTransformCameraLookingAtTarget(this._view, this.camera).coord;
};
/**
 * Sets the animation enabled.
 * @param      {boolean}  enable  enable
 */


GlobeControls.prototype.setAnimationEnabled = function (enable) {
  enableAnimation = enable;
};
/**
 * Determines if animation enabled.
 * @return     {boolean}  True if animation enabled, False otherwise.
 */


GlobeControls.prototype.isAnimationEnabled = function () {
  return enableAnimation;
};
/**
 * Returns the actual zoom. The zoom will always be between the [getMinZoom(), getMaxZoom()].
 * @return     {number}  The zoom .
 */


GlobeControls.prototype.getZoom = function () {
  return this._view.tileLayer.computeTileZoomFromDistanceCamera(this.getRange(), this._view.camera);
};
/**
 * Sets the current zoom, which is an index in the logical scales predefined for the application.
 * The higher the zoom, the closer to the ground.
 * The zoom is always in the [getMinZoom(), getMaxZoom()] range.
 * @param      {number}  zoom    The zoom
 * @param      {boolean}  isAnimated  Indicates if animated
 * @return     {Promise}
 */


GlobeControls.prototype.setZoom = function (zoom, isAnimated) {
  return this.lookAtCoordinate({
    zoom: zoom
  }, isAnimated);
};
/**
 * Return the current zoom scale at the central point of the view.
 * This function compute the scale of a map
 * @param      {number}  pitch   Screen pitch, in millimeters ; 0.28 by default
 * @return     {number}  The zoom scale.
 */


GlobeControls.prototype.getScale = function (pitch) {
  // TODO: Why error div size height in Chrome?
  // Screen pitch, in millimeters
  pitch = (pitch || 0.28) / 1000;
  var fov = THREE.Math.degToRad(this.camera.fov); // projection one unit on screen

  var gfx = this._view.mainLoop.gfxEngine;
  var unitProjection = gfx.height / (2 * this.getRange() * Math.tan(fov * 0.5));
  return pitch * unitProjection;
};
/**
 * To convert the projection in meters on the globe of a number of pixels of screen
 * @param      {number} pixels count pixels to project
 * @param      {number} pixelPitch Screen pixel pitch, in millimeters (default = 0.28 mm / standard pixel size of 0.28 millimeters as defined by the OGC)
 * @return     {number} projection in meters on globe
 */


GlobeControls.prototype.pixelsToMeters = function (pixels) {
  var pixelPitch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.28;
  var scaled = this.getScale(pixelPitch);
  return pixels * pixelPitch / scaled / 1000;
};
/**
 * To convert the projection a number of horizontal pixels of screen to longitude degree WGS84 on the globe
 * @param      {number} pixels count pixels to project
 * @param      {number} pixelPitch Screen pixel pitch, in millimeters (default = 0.28 mm / standard pixel size of 0.28 millimeters as defined by the OGC)
 * @return     {number} projection in degree on globe
 */


GlobeControls.prototype.pixelsToDegrees = function (pixels) {
  var pixelPitch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.28;
  var chord = this.pixelsToMeters(pixels, pixelPitch);
  return THREE.Math.radToDeg(2 * Math.asin(chord / (2 * _Ellipsoid.ellipsoidSizes.x)));
};
/**
 * Projection on screen in pixels of length in meter on globe
 * @param      {number}  value Length in meter on globe
 * @param      {number}  pixelPitch Screen pixel pitch, in millimeters (default = 0.28 mm / standard pixel size of 0.28 millimeters as defined by the OGC)
 * @return     {number}  projection in pixels on screen
 */


GlobeControls.prototype.metersToPixels = function (value) {
  var pixelPitch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.28;
  var scaled = this.getScale(pixelPitch);
  pixelPitch /= 1000;
  return value * scaled / pixelPitch;
};
/**
 * Changes the zoom of the central point of screen so that screen acts as a map with a specified scale.
 *  The view flies to the desired zoom scale;
 * @param      {number}  scale  The scale
 * @param      {number}  pitch  The pitch
 * @param      {boolean}  isAnimated  Indicates if animated
 * @return     {Promise}
 */


GlobeControls.prototype.setScale = function (scale, pitch, isAnimated) {
  return this.lookAtCoordinate({
    scale: scale,
    pitch: pitch
  }, isAnimated);
};
/**
 * @deprecated
 * Changes the center of the scene on screen to the specified in lat, lon. See {@linkcode Coordinates} for conversion.
 * @function
 * @memberOf GlobeControls
 * @param {Object} coordinates - The globe coordinates in EPSG_4326 projection to aim to
 * @param {number} coordinates.latitude
 * @param {number} coordinates.longitude
 * @param {number} coordinates.range
 * @param {boolean}  isAnimated - if the movement should be animated
 * @return {Promise} A promise that resolves when the next 'globe initilazed' event fires.
 */


GlobeControls.prototype.setCameraTargetGeoPosition = function (coordinates, isAnimated) {
  console.warn('setCameraTargetGeoPosition has been deprecated, use lookAtCoordinate');
  return this.lookAtCoordinate(new _Coordinates["default"]('EPSG:4326', coordinates.longitude, coordinates.latitude, 0), isAnimated);
};
/**
 * Changes the center of the scene on screen to the specified in lat, lon. See {@linkcode Coordinates} for conversion.
 * This function allows to change the central position, the zoom, the range, the scale and the camera orientation at the same time.
 * The zoom has to be between the [getMinZoom(), getMaxZoom()].
 * Zoom parameter is ignored if range is set
 * The tilt's interval is between 4 and 89.5 degree
 *
 * @param      {CameraUtils~CameraTransformOptions}   params camera transformation to apply
 * @param      {number}   [params.zoom]   zoom
 * @param      {number}   [params.scale]   scale
 * @param      {boolean}  isAnimated  Indicates if animated
 * @return     {Promise}  A promise that resolves when transformation is oppered
 */


GlobeControls.prototype.lookAtCoordinate = function () {
  var _this7 = this;

  var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  var isAnimated = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.isAnimationEnabled();

  if (params.zoom) {
    params.range = this._view.tileLayer.computeDistanceCameraFromTileZoom(params.zoom, this._view.camera);
  } else if (params.scale) {
    var gfx = this._view.mainLoop.gfxEngine;
    params.range = getRangeFromScale(params.scale, params.pitch, this.camera.fov, gfx.height);

    if (params.range < this.minDistance || params.range > this.maxDistance) {
      // eslint-disable-next-line no-console
      console.warn("This scale ".concat(params.scale, " can not be reached"));
      params.range = THREE.Math.clamp(params.range, this.minDistance, this.maxDistance);
    }
  }

  if (params.tilt !== undefined) {
    var minTilt = 90 - THREE.Math.radToDeg(this.maxPolarAngle);
    var maxTilt = 90 - THREE.Math.radToDeg(this.minPolarAngle);

    if (params.tilt < minTilt || params.tilt > maxTilt) {
      params.tilt = THREE.Math.clamp(params.tilt, minTilt, maxTilt); // eslint-disable-next-line no-console

      console.warn('Tilt was clamped to ', params.tilt, " the interval is between ".concat(minTilt, " and ").concat(maxTilt, " degree"));
    }
  }

  previous = _CameraUtils["default"].getTransformCameraLookingAtTarget(this._view, this.camera);

  if (isAnimated) {
    params.callback = function (r) {
      return cameraTarget.position.copy(r.targetWorldPosition);
    };

    this.dispatchEvent({
      type: 'animation-started'
    });
    return _CameraUtils["default"].animateCameraToLookAtTarget(this._view, this.camera, params).then(function (result) {
      _this7.dispatchEvent({
        type: 'animation-ended'
      });

      _this7._handlingEvent(result);

      return result;
    });
  } else {
    return _CameraUtils["default"].transformCameraToLookAtTarget(this._view, this.camera, params).then(function (result) {
      cameraTarget.position.copy(result.targetWorldPosition);

      _this7._handlingEvent(result);

      return result;
    });
  }
};
/**
 * @deprecated
 * Changes the center of the scene on screen to the specified in lat, lon. See {@linkcode Coordinates} for conversion.
 * This function allows to change the central position, the zoom, the range, the scale and the camera orientation at the same time.
 * The zoom has to be between the [getMinZoom(), getMaxZoom()].
 * Zoom parameter is ignored if range is set
 * @param {Position} position
 * @param {number}  position.longitude  Coordinate longitude WGS84 in degree
 * @param {number}  position.latitude  Coordinate latitude WGS84 in degree
 * @param {number}  [position.tilt]  Camera tilt in degree
 * @param {number}  [position.heading]  Camera heading in degree
 * @param {number}  [position.range]  The camera distance to the target center
 * @param {number}  [position.zoom]  zoom,  ignored if range is set
 * @param {number}  [position.scale]  scale,  ignored if the zoom or range is set. For a scale of 1/500 it is necessary to write 0,002.
 * @param {boolean}  isAnimated  Indicates if animated
 * @return {Promise}
 */


GlobeControls.prototype.setCameraTargetGeoPositionAdvanced = function (position, isAnimated) {
  console.warn('setCameraTargetGeoPositionAdvanced has been deprecated, use lookAtCoordinate');
  position.coord = new _Coordinates["default"]('EPSG:4326', position.longitude, position.latitude, 0);
  return this.lookAtCoordinate(position, isAnimated);
};
/**
 * @deprecated
 * Sets orientation angles of the current camera, in degrees.
 * <iframe width="100%" height="400" src="http://jsfiddle.net/iTownsIGN/9qr2mogh/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
 * @param {{tilt:number,heading:number,range:number}} position
 * @param {boolean}  isAnimated
 * @return {Promise} A promise that resolves when transformation is oppered
 */


GlobeControls.prototype.setOrbitalPosition = function (position, isAnimated) {
  console.warn('setOrbitalPosition has been deprecated, use lookAtCoordinate');
  return this.lookAtCoordinate(position, isAnimated);
};
/**
 * Pick a position on the globe at the given position in lat,lon. See {@linkcode Coordinates} for conversion.
 * @param {Vector2} windowCoords - window coordinates
 * @param {number=} y - The y-position inside the Globe element.
 * @return {Coordinates} position
 */


GlobeControls.prototype.pickGeoPosition = function (windowCoords) {
  var pickedPosition = this._view.getPickingPositionFromDepth(windowCoords);

  if (!pickedPosition) {
    return;
  }

  return new _Coordinates["default"]('EPSG:4978', pickedPosition).as('EPSG:4326');
};

var _default = GlobeControls;
exports["default"] = _default;