kopia lustrzana https://github.com/robhawkes/vizicities
216 wiersze
5.0 KiB
JavaScript
Executable File
216 wiersze
5.0 KiB
JavaScript
Executable File
import {point as Point} from '../../geo/Point';
|
||
import {latLon as LatLon} from '../../geo/LatLon';
|
||
import * as THREE from 'three';
|
||
|
||
// TODO: Make sure nothing is left behind in the heap after calling destroy()
|
||
|
||
// Manages a single tile and its layers
|
||
|
||
var r2d = 180 / Math.PI;
|
||
|
||
var tileURLRegex = /\{([szxy])\}/g;
|
||
|
||
class Tile {
|
||
constructor(quadcode, path, layer) {
|
||
this._layer = layer;
|
||
this._world = layer._world;
|
||
this._quadcode = quadcode;
|
||
this._path = path;
|
||
|
||
this._ready = false;
|
||
this._aborted = false;
|
||
|
||
this._tile = this._quadcodeToTile(quadcode);
|
||
|
||
// Bottom-left and top-right bounds in WGS84 coordinates
|
||
this._boundsLatLon = this._tileBoundsWGS84(this._tile);
|
||
|
||
// Bottom-left and top-right bounds in world coordinates
|
||
this._boundsWorld = this._tileBoundsFromWGS84(this._boundsLatLon);
|
||
|
||
// Tile center in world coordinates
|
||
this._center = this._boundsToCenter(this._boundsWorld);
|
||
|
||
// Tile center in projected coordinates
|
||
this._centerLatlon = this._world.pointToLatLon(Point(this._center[0], this._center[1]));
|
||
|
||
// Length of a tile side in world coorindates
|
||
this._side = this._getSide(this._boundsWorld);
|
||
|
||
// Point scale for tile (for unit conversion)
|
||
this._pointScale = this._world.pointScale(this._centerLatlon);
|
||
}
|
||
|
||
// Returns true if the tile mesh and texture are ready to be used
|
||
// Otherwise, returns false
|
||
isReady() {
|
||
return this._ready;
|
||
}
|
||
|
||
isAborted() {
|
||
return this._aborted;
|
||
}
|
||
|
||
// Request data for the tile
|
||
requestTileAsync() {}
|
||
|
||
getQuadcode() {
|
||
return this._quadcode;
|
||
}
|
||
|
||
getBounds() {
|
||
return this._boundsWorld;
|
||
}
|
||
|
||
getCenter() {
|
||
return this._center;
|
||
}
|
||
|
||
getSide() {
|
||
return this._side;
|
||
}
|
||
|
||
getMesh() {
|
||
return this._mesh;
|
||
}
|
||
|
||
getPickingMesh() {
|
||
return this._pickingMesh;
|
||
}
|
||
|
||
// Destroys the tile and removes it from the layer and memory
|
||
//
|
||
// Ensure that this leaves no trace of the tile – no textures, no meshes,
|
||
// nothing in memory or the GPU
|
||
destroy() {
|
||
// console.log('Destroying tile', this._quadcode);
|
||
|
||
// Delete reference to layer and world
|
||
this._layer = null;
|
||
this._world = null;
|
||
|
||
// Delete location references
|
||
this._boundsLatLon = null;
|
||
this._boundsWorld = null;
|
||
this._center = null;
|
||
|
||
// Done if no mesh
|
||
if (!this._mesh && !this._pickingMesh) {
|
||
return;
|
||
}
|
||
|
||
this.destroyMesh(this._mesh);
|
||
this.destroyMesh(this._pickingMesh);
|
||
|
||
this._mesh = null;
|
||
this._pickingMesh = null;
|
||
}
|
||
|
||
destroyMesh(mesh, dispose = true) {
|
||
if (mesh) {
|
||
if (mesh.children) {
|
||
mesh.children.forEach((child) => {
|
||
mesh.remove(child);
|
||
this.destroyMesh(child);
|
||
});
|
||
}
|
||
|
||
if (dispose) {
|
||
if (mesh.geometry) {
|
||
mesh.geometry.dispose();
|
||
mesh.geometry = null;
|
||
}
|
||
|
||
if (mesh.material) {
|
||
if (mesh.material.map) {
|
||
mesh.material.map.dispose();
|
||
mesh.material.map = null;
|
||
}
|
||
|
||
mesh.material.dispose();
|
||
mesh.material = null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
_createMesh() {}
|
||
_createDebugMesh() {}
|
||
|
||
_getTileURL(urlParams) {
|
||
if (!urlParams.s) {
|
||
// Default to a random choice of a, b or c
|
||
urlParams.s = String.fromCharCode(97 + Math.floor(Math.random() * 3));
|
||
}
|
||
|
||
tileURLRegex.lastIndex = 0;
|
||
return this._path.replace(tileURLRegex, function(value, key) {
|
||
// Replace with paramter, otherwise keep existing value
|
||
return urlParams[key];
|
||
});
|
||
}
|
||
|
||
// Convert from quadcode to TMS tile coordinates
|
||
_quadcodeToTile(quadcode) {
|
||
var x = 0;
|
||
var y = 0;
|
||
var z = quadcode.length;
|
||
|
||
for (var i = z; i > 0; i--) {
|
||
var mask = 1 << (i - 1);
|
||
var q = +quadcode[z - i];
|
||
if (q === 1) {
|
||
x |= mask;
|
||
}
|
||
if (q === 2) {
|
||
y |= mask;
|
||
}
|
||
if (q === 3) {
|
||
x |= mask;
|
||
y |= mask;
|
||
}
|
||
}
|
||
|
||
return [x, y, z];
|
||
}
|
||
|
||
// Convert WGS84 tile bounds to world coordinates
|
||
_tileBoundsFromWGS84(boundsWGS84) {
|
||
var sw = this._layer._world.latLonToPoint(LatLon(boundsWGS84[1], boundsWGS84[0]));
|
||
var ne = this._layer._world.latLonToPoint(LatLon(boundsWGS84[3], boundsWGS84[2]));
|
||
|
||
return [sw.x, sw.y, ne.x, ne.y];
|
||
}
|
||
|
||
// Get tile bounds in WGS84 coordinates
|
||
_tileBoundsWGS84(tile) {
|
||
var e = this._tile2lon(tile[0] + 1, tile[2]);
|
||
var w = this._tile2lon(tile[0], tile[2]);
|
||
var s = this._tile2lat(tile[1] + 1, tile[2]);
|
||
var n = this._tile2lat(tile[1], tile[2]);
|
||
return [w, s, e, n];
|
||
}
|
||
|
||
_tile2lon(x, z) {
|
||
return x / Math.pow(2, z) * 360 - 180;
|
||
}
|
||
|
||
_tile2lat(y, z) {
|
||
var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
|
||
return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
|
||
}
|
||
|
||
_boundsToCenter(bounds) {
|
||
var x = bounds[0] + (bounds[2] - bounds[0]) / 2;
|
||
var y = bounds[1] + (bounds[3] - bounds[1]) / 2;
|
||
|
||
return [x, y];
|
||
}
|
||
|
||
_getSide(bounds) {
|
||
return (new THREE.Vector3(bounds[0], 0, bounds[3])).sub(new THREE.Vector3(bounds[0], 0, bounds[1])).length();
|
||
}
|
||
}
|
||
|
||
export default Tile;
|