"use strict";

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

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

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

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

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

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

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

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

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

var _core = require("@math.gl/core");

var _viewport = _interopRequireDefault(require("./viewport"));

var _constants = require("../lib/constants");

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }

function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }

var DEGREES_TO_RADIANS = Math.PI / 180;
var RADIANS_TO_DEGREES = 180 / Math.PI;
var EARTH_RADIUS = 6370972;
var GLOBE_RADIUS = 256;

function getDistanceScales() {
  var unitsPerMeter = GLOBE_RADIUS / EARTH_RADIUS;
  var unitsPerDegree = Math.PI / 180 * GLOBE_RADIUS;
  return {
    unitsPerMeter: [unitsPerMeter, unitsPerMeter, unitsPerMeter],
    unitsPerMeter2: [0, 0, 0],
    metersPerUnit: [1 / unitsPerMeter, 1 / unitsPerMeter, 1 / unitsPerMeter],
    unitsPerDegree: [unitsPerDegree, unitsPerDegree, unitsPerMeter],
    unitsPerDegree2: [0, 0, 0],
    degreesPerUnit: [1 / unitsPerDegree, 1 / unitsPerDegree, 1 / unitsPerMeter]
  };
}

var GlobeViewport = function (_Viewport) {
  (0, _inherits2.default)(GlobeViewport, _Viewport);

  var _super = _createSuper(GlobeViewport);

  function GlobeViewport() {
    var _this;

    var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    (0, _classCallCheck2.default)(this, GlobeViewport);
    var _opts$latitude = opts.latitude,
        latitude = _opts$latitude === void 0 ? 0 : _opts$latitude,
        _opts$longitude = opts.longitude,
        longitude = _opts$longitude === void 0 ? 0 : _opts$longitude,
        _opts$zoom = opts.zoom,
        zoom = _opts$zoom === void 0 ? 0 : _opts$zoom,
        _opts$nearZMultiplier = opts.nearZMultiplier,
        nearZMultiplier = _opts$nearZMultiplier === void 0 ? 0.1 : _opts$nearZMultiplier,
        _opts$farZMultiplier = opts.farZMultiplier,
        farZMultiplier = _opts$farZMultiplier === void 0 ? 2 : _opts$farZMultiplier,
        _opts$resolution = opts.resolution,
        resolution = _opts$resolution === void 0 ? 10 : _opts$resolution;
    var height = opts.height,
        _opts$altitude = opts.altitude,
        altitude = _opts$altitude === void 0 ? 1.5 : _opts$altitude;
    height = height || 1;
    altitude = Math.max(0.75, altitude);
    var viewMatrix = new _core.Matrix4().lookAt({
      eye: [0, -altitude, 0],
      up: [0, 0, 1]
    });
    var scale = Math.pow(2, zoom);
    viewMatrix.rotateX(latitude * DEGREES_TO_RADIANS);
    viewMatrix.rotateZ(-longitude * DEGREES_TO_RADIANS);
    viewMatrix.scale(scale / height);
    var halfFov = Math.atan(0.5 / altitude);
    var relativeScale = GLOBE_RADIUS * 2 * scale / height;
    _this = _super.call(this, _objectSpread(_objectSpread({}, opts), {}, {
      height: height,
      viewMatrix: viewMatrix,
      longitude: longitude,
      latitude: latitude,
      zoom: zoom,
      distanceScales: getDistanceScales(),
      fovyRadians: halfFov * 2,
      focalDistance: altitude,
      near: nearZMultiplier,
      far: Math.min(2, 1 / relativeScale + 1) * altitude * farZMultiplier
    }));
    _this.longitude = void 0;
    _this.latitude = void 0;
    _this.resolution = void 0;
    _this.latitude = latitude;
    _this.longitude = longitude;
    _this.resolution = resolution;
    return _this;
  }

  var _proto = GlobeViewport.prototype;

  _proto.getDistanceScales = function getDistanceScales() {
    return this.distanceScales;
  };

  _proto.getBounds = function getBounds() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var unprojectOption = {
      targetZ: options.z || 0
    };
    var left = this.unproject([0, this.height / 2], unprojectOption);
    var top = this.unproject([this.width / 2, 0], unprojectOption);
    var right = this.unproject([this.width, this.height / 2], unprojectOption);
    var bottom = this.unproject([this.width / 2, this.height], unprojectOption);
    if (right[0] < this.longitude) right[0] += 360;
    if (left[0] > this.longitude) left[0] -= 360;
    return [Math.min(left[0], right[0], top[0], bottom[0]), Math.min(left[1], right[1], top[1], bottom[1]), Math.max(left[0], right[0], top[0], bottom[0]), Math.max(left[1], right[1], top[1], bottom[1])];
  };

  _proto.unproject = function unproject(xyz) {
    var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
        _ref$topLeft = _ref.topLeft,
        topLeft = _ref$topLeft === void 0 ? true : _ref$topLeft,
        targetZ = _ref.targetZ;

    var _xyz = (0, _slicedToArray2.default)(xyz, 3),
        x = _xyz[0],
        y = _xyz[1],
        z = _xyz[2];

    var y2 = topLeft ? y : this.height - y;
    var pixelUnprojectionMatrix = this.pixelUnprojectionMatrix;
    var coord;

    if (Number.isFinite(z)) {
      coord = transformVector(pixelUnprojectionMatrix, [x, y2, z, 1]);
    } else {
      var coord0 = transformVector(pixelUnprojectionMatrix, [x, y2, -1, 1]);
      var coord1 = transformVector(pixelUnprojectionMatrix, [x, y2, 1, 1]);
      var lt = ((targetZ || 0) / EARTH_RADIUS + 1) * GLOBE_RADIUS;

      var lSqr = _core.vec3.sqrLen(_core.vec3.sub([], coord0, coord1));

      var l0Sqr = _core.vec3.sqrLen(coord0);

      var l1Sqr = _core.vec3.sqrLen(coord1);

      var sSqr = (4 * l0Sqr * l1Sqr - Math.pow(lSqr - l0Sqr - l1Sqr, 2)) / 16;
      var dSqr = 4 * sSqr / lSqr;
      var r0 = Math.sqrt(l0Sqr - dSqr);
      var dr = Math.sqrt(Math.max(0, lt * lt - dSqr));
      var t = (r0 - dr) / Math.sqrt(lSqr);
      coord = _core.vec3.lerp([], coord0, coord1, t);
    }

    var _this$unprojectPositi = this.unprojectPosition(coord),
        _this$unprojectPositi2 = (0, _slicedToArray2.default)(_this$unprojectPositi, 3),
        X = _this$unprojectPositi2[0],
        Y = _this$unprojectPositi2[1],
        Z = _this$unprojectPositi2[2];

    if (Number.isFinite(z)) {
      return [X, Y, Z];
    }

    return Number.isFinite(targetZ) ? [X, Y, targetZ] : [X, Y];
  };

  _proto.projectPosition = function projectPosition(xyz) {
    var _xyz2 = (0, _slicedToArray2.default)(xyz, 3),
        lng = _xyz2[0],
        lat = _xyz2[1],
        _xyz2$ = _xyz2[2],
        Z = _xyz2$ === void 0 ? 0 : _xyz2$;

    var lambda = lng * DEGREES_TO_RADIANS;
    var phi = lat * DEGREES_TO_RADIANS;
    var cosPhi = Math.cos(phi);
    var D = (Z / EARTH_RADIUS + 1) * GLOBE_RADIUS;
    return [Math.sin(lambda) * cosPhi * D, -Math.cos(lambda) * cosPhi * D, Math.sin(phi) * D];
  };

  _proto.unprojectPosition = function unprojectPosition(xyz) {
    var _xyz3 = (0, _slicedToArray2.default)(xyz, 3),
        x = _xyz3[0],
        y = _xyz3[1],
        z = _xyz3[2];

    var D = _core.vec3.len(xyz);

    var phi = Math.asin(z / D);
    var lambda = Math.atan2(x, -y);
    var lng = lambda * RADIANS_TO_DEGREES;
    var lat = phi * RADIANS_TO_DEGREES;
    var Z = (D / GLOBE_RADIUS - 1) * EARTH_RADIUS;
    return [lng, lat, Z];
  };

  _proto.projectFlat = function projectFlat(xyz) {
    return xyz;
  };

  _proto.unprojectFlat = function unprojectFlat(xyz) {
    return xyz;
  };

  _proto.panByPosition = function panByPosition(coords, pixel) {
    var fromPosition = this.unproject(pixel);
    return {
      longitude: coords[0] - fromPosition[0] + this.longitude,
      latitude: coords[1] - fromPosition[1] + this.latitude
    };
  };

  (0, _createClass2.default)(GlobeViewport, [{
    key: "projectionMode",
    get: function get() {
      return _constants.PROJECTION_MODE.GLOBE;
    }
  }]);
  return GlobeViewport;
}(_viewport.default);

exports.default = GlobeViewport;

function transformVector(matrix, vector) {
  var result = _core.vec4.transformMat4([], vector, matrix);

  _core.vec4.scale(result, result, 1 / result[3]);

  return result;
}
//# sourceMappingURL=globe-viewport.js.map