three-slippy-map-globe
Version:
Tiled maps on a globe as a ThreeJS reusable 3D object
608 lines (586 loc) • 24.2 kB
JavaScript
import { Camera, Vector3, Group, Mesh, SphereGeometry, MeshBasicMaterial, Frustum, Matrix4, MeshLambertMaterial, TextureLoader, SRGBColorSpace } from 'three';
import { octree } from 'd3-octree';
import { scaleLinear } from 'd3-scale';
import { geoMercatorRaw } from 'd3-geo';
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
return n;
}
function _arrayWithHoles(r) {
if (Array.isArray(r)) return r;
}
function _arrayWithoutHoles(r) {
if (Array.isArray(r)) return _arrayLikeToArray(r);
}
function _assertClassBrand(e, t, n) {
if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
throw new TypeError("Private element is not present on this object");
}
function _assertThisInitialized(e) {
if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
return e;
}
function _callSuper(t, o, e) {
return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, [], _getPrototypeOf(t).constructor) : o.apply(t, e));
}
function _checkPrivateRedeclaration(e, t) {
if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
}
function _classCallCheck(a, n) {
if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
}
function _classPrivateFieldGet2(s, a) {
return s.get(_assertClassBrand(s, a));
}
function _classPrivateFieldInitSpec(e, t, a) {
_checkPrivateRedeclaration(e, t), t.set(e, a);
}
function _classPrivateFieldSet2(s, a, r) {
return s.set(_assertClassBrand(s, a), r), r;
}
function _classPrivateMethodInitSpec(e, a) {
_checkPrivateRedeclaration(e, a), a.add(e);
}
function _defineProperties(e, r) {
for (var t = 0; t < r.length; t++) {
var o = r[t];
o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o);
}
}
function _createClass(e, r, t) {
return r && _defineProperties(e.prototype, r), Object.defineProperty(e, "prototype", {
writable: false
}), e;
}
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: true,
configurable: true,
writable: true
}) : e[r] = t, e;
}
function _getPrototypeOf(t) {
return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
return t.__proto__ || Object.getPrototypeOf(t);
}, _getPrototypeOf(t);
}
function _inherits(t, e) {
if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
t.prototype = Object.create(e && e.prototype, {
constructor: {
value: t,
writable: true,
configurable: true
}
}), Object.defineProperty(t, "prototype", {
writable: false
}), e && _setPrototypeOf(t, e);
}
function _isNativeReflectConstruct() {
try {
var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
} catch (t) {}
return (_isNativeReflectConstruct = function () {
return !!t;
})();
}
function _iterableToArray(r) {
if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
}
function _iterableToArrayLimit(r, l) {
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (null != t) {
var e,
n,
i,
u,
a = [],
f = true,
o = false;
try {
if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
} catch (r) {
o = true, n = r;
} finally {
try {
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
} finally {
if (o) throw n;
}
}
return a;
}
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _possibleConstructorReturn(t, e) {
if (e && ("object" == typeof e || "function" == typeof e)) return e;
if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
return _assertThisInitialized(t);
}
function _setPrototypeOf(t, e) {
return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
return t.__proto__ = e, t;
}, _setPrototypeOf(t, e);
}
function _slicedToArray(r, e) {
return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
}
function _toConsumableArray(r) {
return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
}
function _toPrimitive(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r);
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (String )(t);
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : i + "";
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) return _arrayLikeToArray(r, a);
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
var _materialDispose = function materialDispose(material) {
if (material instanceof Array) {
material.forEach(_materialDispose);
} else {
if (material.map) {
material.map.dispose();
}
material.dispose();
}
};
var _deallocate = function deallocate(obj) {
if (obj.geometry) {
obj.geometry.dispose();
}
if (obj.material) {
_materialDispose(obj.material);
}
if (obj.texture) {
obj.texture.dispose();
}
if (obj.children) {
obj.children.forEach(_deallocate);
}
};
function polar2Cartesian(lat, lng, r) {
var phi = (90 - lat) * Math.PI / 180;
var theta = (90 - lng) * Math.PI / 180;
return {
x: r * Math.sin(phi) * Math.cos(theta),
y: r * Math.cos(phi),
z: r * Math.sin(phi) * Math.sin(theta)
};
}
function cartesian2Polar(_ref) {
var x = _ref.x,
y = _ref.y,
z = _ref.z;
var r = Math.sqrt(x * x + y * y + z * z);
var phi = Math.acos(y / r);
var theta = Math.atan2(z, x);
return {
lat: 90 - phi * 180 / Math.PI,
lng: 90 - theta * 180 / Math.PI - (theta < -Math.PI / 2 ? 360 : 0),
// keep within [-180, 180] boundaries
r: r
};
}
function deg2Rad(deg) {
return deg * Math.PI / 180;
}
var yMercatorScale = function yMercatorScale(y) {
return 1 - (geoMercatorRaw(0, (0.5 - y) * Math.PI)[1] / Math.PI + 1) / 2;
};
var yMercatorScaleClamped = function yMercatorScaleClamped(y) {
return Math.max(0, Math.min(1, yMercatorScale(y)));
};
var yMercatorScaleInvert = function yMercatorScaleInvert(y) {
return 0.5 - geoMercatorRaw.invert(0, (2 * (1 - y) - 1) * Math.PI)[1] / Math.PI;
};
var convertMercatorUV = function convertMercatorUV(uvs) {
var y0 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var y1 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
var offsetScale = scaleLinear().domain([1, 0]).range([y0, y1]).clamp(true);
var revOffsetScale = scaleLinear().domain([yMercatorScaleClamped(y0), yMercatorScaleClamped(y1)]).range([1, 0]).clamp(true);
var scale = function scale(v) {
return revOffsetScale(yMercatorScaleClamped(offsetScale(v)));
};
var arr = uvs.array;
for (var i = 0, len = arr.length; i < len; i += 2) {
arr[i + 1] = scale(arr[i + 1]);
}
uvs.needsUpdate = true;
};
var findTileXY = function findTileXY(level, isMercator, lng, lat) {
var gridSize = Math.pow(2, level);
var x = Math.max(0, Math.min(gridSize - 1, Math.floor((lng + 180) * gridSize / 360)));
var relY = (90 - lat) / 180;
isMercator && (relY = Math.max(0, Math.min(1, yMercatorScale(relY))));
var y = Math.floor(relY * gridSize);
return [x, y];
};
var genTilesCoords = function genTilesCoords(level, isMercator) {
var x0 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var y0 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
var _x1 = arguments.length > 4 ? arguments[4] : undefined;
var _y1 = arguments.length > 5 ? arguments[5] : undefined;
var tiles = [];
var gridSize = Math.pow(2, level);
var tileLngLen = 360 / gridSize;
var regTileLatLen = 180 / gridSize;
var x1 = _x1 === undefined ? gridSize - 1 : _x1;
var y1 = _y1 === undefined ? gridSize - 1 : _y1;
for (var x = x0, maxX = Math.min(gridSize - 1, x1); x <= maxX; x++) {
for (var y = y0, maxY = Math.min(gridSize - 1, y1); y <= maxY; y++) {
var reproY = y,
tileLatLen = regTileLatLen;
if (isMercator) {
// lat needs reprojection, but stretch to cover poles
reproY = y === 0 ? y : yMercatorScaleInvert(y / gridSize) * gridSize;
var reproYEnd = y + 1 === gridSize ? y + 1 : yMercatorScaleInvert((y + 1) / gridSize) * gridSize;
tileLatLen = (reproYEnd - reproY) * 180 / gridSize;
}
// tile centroid coordinates
var lng = -180 + (x + 0.5) * tileLngLen;
var lat = 90 - (reproY * 180 / gridSize + tileLatLen / 2);
var latLen = tileLatLen; // lng is always constant among all tiles
tiles.push({
x: x,
y: y,
lng: lng,
lat: lat,
latLen: latLen
});
}
}
return tiles;
};
var MAX_LEVEL_TO_RENDER_ALL_TILES = 6; // level 6 = 4096 tiles
var MAX_LEVEL_TO_BUILD_LOOKUP_OCTREE = 7; // octrees consume too much memory on higher levels, generate tiles on demand for those (based on globe surface distance) as the distortion is negligible
var TILE_SEARCH_RADIUS_CAMERA_DISTANCE = 3; // Euclidean distance factor, in units of camera distance to surface
var TILE_SEARCH_RADIUS_SURFACE_DISTANCE = 90; // in degrees on the globe surface, relative to camera altitude in globe radius units
var _radius = /*#__PURE__*/new WeakMap();
var _isMercator = /*#__PURE__*/new WeakMap();
var _tileUrl = /*#__PURE__*/new WeakMap();
var _level = /*#__PURE__*/new WeakMap();
var _tilesMeta = /*#__PURE__*/new WeakMap();
var _isInView = /*#__PURE__*/new WeakMap();
var _camera = /*#__PURE__*/new WeakMap();
var _innerBackLayer = /*#__PURE__*/new WeakMap();
var _ThreeSlippyMapGlobe_brand = /*#__PURE__*/new WeakSet();
var ThreeSlippyMapGlobe = /*#__PURE__*/function (_Group) {
function ThreeSlippyMapGlobe(radius) {
var _this;
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
tileUrl = _ref.tileUrl,
_ref$minLevel = _ref.minLevel,
minLevel = _ref$minLevel === void 0 ? 0 : _ref$minLevel,
_ref$maxLevel = _ref.maxLevel,
maxLevel = _ref$maxLevel === void 0 ? 17 : _ref$maxLevel,
_ref$mercatorProjecti = _ref.mercatorProjection,
mercatorProjection = _ref$mercatorProjecti === void 0 ? true : _ref$mercatorProjecti;
_classCallCheck(this, ThreeSlippyMapGlobe);
_this = _callSuper(this, ThreeSlippyMapGlobe);
// Private methods
_classPrivateMethodInitSpec(_this, _ThreeSlippyMapGlobe_brand);
// Private attributes
_classPrivateFieldInitSpec(_this, _radius, void 0);
_classPrivateFieldInitSpec(_this, _isMercator, void 0);
_classPrivateFieldInitSpec(_this, _tileUrl, void 0);
_classPrivateFieldInitSpec(_this, _level, void 0);
_classPrivateFieldInitSpec(_this, _tilesMeta, {});
_classPrivateFieldInitSpec(_this, _isInView, void 0);
_classPrivateFieldInitSpec(_this, _camera, void 0);
_classPrivateFieldInitSpec(_this, _innerBackLayer, void 0);
_defineProperty(_this, "minLevel", void 0);
_defineProperty(_this, "maxLevel", void 0);
_defineProperty(_this, "thresholds", _toConsumableArray(new Array(30)).map(function (_, idx) {
return 8 / Math.pow(2, idx);
}));
// in terms of radius units
_defineProperty(_this, "curvatureResolution", 5);
// in degrees, affects number of vertices in tiles
_defineProperty(_this, "tileMargin", 0);
_defineProperty(_this, "clearTiles", function () {
Object.values(_classPrivateFieldGet2(_tilesMeta, _this)).forEach(function (l) {
l.forEach(function (d) {
if (d.obj) {
_this.remove(d.obj);
_deallocate(d.obj);
delete d.obj;
}
});
});
_classPrivateFieldSet2(_tilesMeta, _this, {});
});
_classPrivateFieldSet2(_radius, _this, radius);
_this.tileUrl = tileUrl;
_classPrivateFieldSet2(_isMercator, _this, mercatorProjection);
_this.minLevel = minLevel;
_this.maxLevel = maxLevel;
_this.level = 0;
// Add protective black sphere just below surface to prevent any depth buffer anomalies
_this.add(_classPrivateFieldSet2(_innerBackLayer, _this, new Mesh(new SphereGeometry(_classPrivateFieldGet2(_radius, _this) * 0.99, 180, 90), new MeshBasicMaterial({
color: 0x0
}))));
_classPrivateFieldGet2(_innerBackLayer, _this).visible = false;
_classPrivateFieldGet2(_innerBackLayer, _this).material.polygonOffset = true;
_classPrivateFieldGet2(_innerBackLayer, _this).material.polygonOffsetUnits = 3;
_classPrivateFieldGet2(_innerBackLayer, _this).material.polygonOffsetFactor = 1;
return _this;
}
_inherits(ThreeSlippyMapGlobe, _Group);
return _createClass(ThreeSlippyMapGlobe, [{
key: "tileUrl",
get:
// Public attributes
function get() {
return _classPrivateFieldGet2(_tileUrl, this);
},
set: function set(tileUrl) {
_classPrivateFieldSet2(_tileUrl, this, tileUrl);
this.updatePov(_classPrivateFieldGet2(_camera, this)); // update current view
}
}, {
key: "level",
get: function get() {
return _classPrivateFieldGet2(_level, this);
},
set: function set(level) {
var _classPrivateFieldGet2$1,
_this2 = this;
if (!_classPrivateFieldGet2(_tilesMeta, this)[level]) _assertClassBrand(_ThreeSlippyMapGlobe_brand, this, _buildMetaLevel).call(this, level);
var prevLevel = _classPrivateFieldGet2(_level, this);
_classPrivateFieldSet2(_level, this, level);
if (level === prevLevel || prevLevel === undefined) return; // nothing else to do
// Activate back layer for levels > 0, when there's !depthWrite tiles
_classPrivateFieldGet2(_innerBackLayer, this).visible = level > 0;
// Bring layer to front
_classPrivateFieldGet2(_tilesMeta, this)[level].forEach(function (d) {
return d.obj && (d.obj.material.depthWrite = true);
});
// push lower layers to background
prevLevel < level && ((_classPrivateFieldGet2$1 = _classPrivateFieldGet2(_tilesMeta, this)[prevLevel]) === null || _classPrivateFieldGet2$1 === void 0 ? void 0 : _classPrivateFieldGet2$1.forEach(function (d) {
return d.obj && (d.obj.material.depthWrite = false);
}));
// Remove upper layers
if (prevLevel > level) {
for (var l = level + 1; l <= prevLevel; l++) {
_classPrivateFieldGet2(_tilesMeta, this)[l] && _classPrivateFieldGet2(_tilesMeta, this)[l].forEach(function (d) {
if (d.obj) {
_this2.remove(d.obj);
_deallocate(d.obj);
delete d.obj;
}
});
}
}
_assertClassBrand(_ThreeSlippyMapGlobe_brand, this, _fetchNeededTiles).call(this);
}
// Public methods
}, {
key: "updatePov",
value: function updatePov(camera) {
var _this3 = this;
if (!camera || !(camera instanceof Camera)) return;
_classPrivateFieldSet2(_camera, this, camera);
var frustum;
_classPrivateFieldSet2(_isInView, this, function (d) {
if (!d.hullPnts) {
// cached for next time to improve performance
var lngLen = 360 / Math.pow(2, _this3.level);
var lng = d.lng,
lat = d.lat,
latLen = d.latLen;
var lng0 = lng - lngLen / 2;
var lng1 = lng + lngLen / 2;
var lat0 = lat - latLen / 2;
var lat1 = lat + latLen / 2;
d.hullPnts = [[lat, lng], [lat0, lng0], [lat1, lng0], [lat0, lng1], [lat1, lng1]].map(function (_ref2) {
var _ref3 = _slicedToArray(_ref2, 2),
lat = _ref3[0],
lng = _ref3[1];
return polar2Cartesian(lat, lng, _classPrivateFieldGet2(_radius, _this3));
}).map(function (_ref4) {
var x = _ref4.x,
y = _ref4.y,
z = _ref4.z;
return new Vector3(x, y, z);
});
}
if (!frustum) {
frustum = new Frustum();
camera.updateMatrix();
camera.updateMatrixWorld();
frustum.setFromProjectionMatrix(new Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
}
return d.hullPnts.some(function (pos) {
return frustum.containsPoint(pos.clone().applyMatrix4(_this3.matrixWorld));
});
});
if (this.tileUrl) {
var pov = camera.position.clone();
var distToGlobeCenter = pov.distanceTo(this.getWorldPosition(new Vector3()));
var cameraDistance = (distToGlobeCenter - _classPrivateFieldGet2(_radius, this)) / _classPrivateFieldGet2(_radius, this); // in units of globe radius
var idx = this.thresholds.findIndex(function (t) {
return t && t <= cameraDistance;
});
this.level = Math.min(this.maxLevel, Math.max(this.minLevel, idx < 0 ? this.thresholds.length : idx));
_assertClassBrand(_ThreeSlippyMapGlobe_brand, this, _fetchNeededTiles).call(this);
}
}
}]);
}(Group);
function _buildMetaLevel(level) {
var _this4 = this;
if (level > MAX_LEVEL_TO_BUILD_LOOKUP_OCTREE) {
// Generate meta dynamically
_classPrivateFieldGet2(_tilesMeta, this)[level] = [];
return;
}
// Generate distance lookup octree
var levelMeta = _classPrivateFieldGet2(_tilesMeta, this)[level] = genTilesCoords(level, _classPrivateFieldGet2(_isMercator, this));
levelMeta.forEach(function (d) {
return d.centroid = polar2Cartesian(d.lat, d.lng, _classPrivateFieldGet2(_radius, _this4));
});
levelMeta.octree = octree().x(function (d) {
return d.centroid.x;
}).y(function (d) {
return d.centroid.y;
}).z(function (d) {
return d.centroid.z;
}).addAll(levelMeta);
}
function _fetchNeededTiles() {
var _this5 = this;
if (!this.tileUrl || this.level === undefined || !_classPrivateFieldGet2(_tilesMeta, this).hasOwnProperty(this.level)) return;
// Safety if can't check in view tiles for higher levels
if (!_classPrivateFieldGet2(_isInView, this) && this.level > MAX_LEVEL_TO_RENDER_ALL_TILES) return;
var tiles = _classPrivateFieldGet2(_tilesMeta, this)[this.level];
if (_classPrivateFieldGet2(_camera, this)) {
// Pre-select tiles close to the camera
var povPos = this.worldToLocal(_classPrivateFieldGet2(_camera, this).position.clone());
if (tiles.octree) {
var _tiles$octree;
// Octree based on 3d positions is more accurate
var _povPos = this.worldToLocal(_classPrivateFieldGet2(_camera, this).position.clone());
var searchRadius = (_povPos.length() - _classPrivateFieldGet2(_radius, this)) * TILE_SEARCH_RADIUS_CAMERA_DISTANCE;
tiles = (_tiles$octree = tiles.octree).findAllWithinRadius.apply(_tiles$octree, _toConsumableArray(_povPos).concat([searchRadius]));
} else {
// tiles populated dynamically
var povCoords = cartesian2Polar(povPos);
var searchRadiusLat = (povCoords.r / _classPrivateFieldGet2(_radius, this) - 1) * TILE_SEARCH_RADIUS_SURFACE_DISTANCE;
var searchRadiusLng = searchRadiusLat / Math.cos(deg2Rad(povCoords.lat)); // Distances in longitude degrees shrink towards the poles
var lngRange = [povCoords.lng - searchRadiusLng, povCoords.lng + searchRadiusLng];
var latRange = [povCoords.lat + searchRadiusLat, povCoords.lat - searchRadiusLat];
var _findTileXY = findTileXY(this.level, _classPrivateFieldGet2(_isMercator, this), lngRange[0], latRange[0]),
_findTileXY2 = _slicedToArray(_findTileXY, 2),
x0 = _findTileXY2[0],
y0 = _findTileXY2[1];
var _findTileXY3 = findTileXY(this.level, _classPrivateFieldGet2(_isMercator, this), lngRange[1], latRange[1]),
_findTileXY4 = _slicedToArray(_findTileXY3, 2),
x1 = _findTileXY4[0],
y1 = _findTileXY4[1];
!tiles.record && (tiles.record = {}); // Index gen tiles by XY
var r = tiles.record;
if (!r.hasOwnProperty("".concat(Math.round((x0 + x1) / 2), "_").concat(Math.round((y0 + y1) / 2)))) {
// gen all found tiles if middle one is not in record
tiles = genTilesCoords(this.level, _classPrivateFieldGet2(_isMercator, this), x0, y0, x1, y1).map(function (d) {
var k = "".concat(d.x, "_").concat(d.y);
if (r.hasOwnProperty(k)) return r[k];
r[k] = d;
tiles.push(d);
return d;
});
} else {
// gen only those missing, one by one
var selTiles = [];
for (var x = x0; x <= x1; x++) {
for (var y = y0; y <= y1; y++) {
var k = "".concat(x, "_").concat(y);
if (!r.hasOwnProperty(k)) {
r[k] = genTilesCoords(this.level, _classPrivateFieldGet2(_isMercator, this), x, y, x, y)[0];
tiles.push(r[k]);
}
selTiles.push(r[k]);
}
}
tiles = selTiles;
}
}
}
/*
console.log({
level: this.level,
totalObjs: this.children.length,
tilesFound: tiles.length,
tilesInView: tiles.filter(this.#isInView || (() => true)).length,
levelTiles: this.#tilesMeta[this.level].length,
fetched: this.#tilesMeta[this.level].filter(d => d.obj).length,
loading: this.#tilesMeta[this.level].filter(d => d.loading).length,
});
*/
tiles.filter(function (d) {
return !d.obj;
}).filter(_classPrivateFieldGet2(_isInView, this) || function () {
return true;
}).forEach(function (d) {
var x = d.x,
y = d.y,
lng = d.lng,
lat = d.lat,
latLen = d.latLen;
var lngLen = 360 / Math.pow(2, _this5.level);
if (!d.obj) {
var width = lngLen * (1 - _this5.tileMargin);
var height = latLen * (1 - _this5.tileMargin);
var rotLng = deg2Rad(lng);
var rotLat = deg2Rad(-lat);
var tile = new Mesh(new SphereGeometry(_classPrivateFieldGet2(_radius, _this5), Math.ceil(width / _this5.curvatureResolution), Math.ceil(height / _this5.curvatureResolution), deg2Rad(90 - width / 2) + rotLng, deg2Rad(width), deg2Rad(90 - height / 2) + rotLat, deg2Rad(height)), new MeshLambertMaterial());
if (_classPrivateFieldGet2(_isMercator, _this5)) {
var _map = [lat + latLen / 2, lat - latLen / 2].map(function (lat) {
return 0.5 - lat / 180;
}),
_map2 = _slicedToArray(_map, 2),
_y = _map2[0],
_y2 = _map2[1];
convertMercatorUV(tile.geometry.attributes.uv, _y, _y2);
}
d.obj = tile;
}
if (!d.loading) {
d.loading = true;
// Fetch tile image
new TextureLoader().load(_this5.tileUrl(x, y, _this5.level), function (texture) {
var tile = d.obj;
if (tile) {
texture.colorSpace = SRGBColorSpace;
tile.material.map = texture;
tile.material.color = null;
tile.material.needsUpdate = true;
_this5.add(tile);
}
d.loading = false;
});
}
});
}
export { ThreeSlippyMapGlobe as default };