vizicities/src/client/Grid.js

249 wiersze
7.1 KiB
JavaScript

/* globals window, _, VIZI, Q, THREE */
(function() {
"use strict";
VIZI.Grid = (function() {
var Grid = function() {
VIZI.Log("Inititialising grid manager");
_.extend(this, VIZI.Mediator);
// Reference to geo class
this.geo = VIZI.Geo.getInstance();
// Location of grid center
this.pos2d = new THREE.Vector2();
this.centerTile = [];
// Tile size and zoom level comes from VIZI.Geo
// Tiles per direction for high detail
this.tilesPerDirectionHigh = 1;
// Tiles per direction for low detail
this.tilesPerDirectionLow = 3;
// Calculated pixel tile size
this.tileSize = 0;
// Grid bounds for high detail (in TMS values)
this.boundsHigh = {};
// Grid bounds for high detail (lon, lat)
this.boundsHighLonLat = {};
// Grid bounds for low detail (in TMS values)
this.boundsLow = {};
// Grid bounds for low detail (lon, lat)
this.boundsLowLonLat = {};
// Debug grid model
this.gridModel = new THREE.Object3D();
this.subscribe("centerPositionChanged", this.onCenterChanged);
};
Grid.prototype.init = function(coords) {
var projCoords = this.geo.projection(coords);
this.pos2d.x = projCoords[0];
this.pos2d.y = projCoords[1];
this.centerTile = this.lonlat2tile(coords[0], coords[1], this.geo.tileZoom, true);
this.boundsHigh = this.getBounds(this.tilesPerDirectionHigh);
this.boundsLow = this.getBounds(this.tilesPerDirectionLow);
this.boundsHighLonLat = this.getBoundsLonLat(this.boundsHigh);
this.boundsLowLonLat = this.getBoundsLonLat(this.boundsLow);
// Create debug model for grid
this.createDebug();
this.publish("addToScene", this.gridModel);
return Q.fcall(function() {});
};
Grid.prototype.update = function() {
// Store old position and bounds
var oldPos2d = this.pos2d.clone();
var oldBoundsHigh = {
n: this.boundsHigh.n,
e: this.boundsHigh.e,
s: this.boundsHigh.s,
w: this.boundsHigh.w
};
var oldBoundsLow = {
n: this.boundsLow.n,
e: this.boundsLow.e,
s: this.boundsLow.s,
w: this.boundsLow.w
};
// Update central position
// Calculate bounds
};
Grid.prototype.getBounds = function(tileDistance) {
var bounds = {
n: Math.floor(this.centerTile[1]) - tileDistance,
e: Math.ceil(this.centerTile[0]) + tileDistance,
s: Math.ceil(this.centerTile[1]) + tileDistance,
w: Math.floor(this.centerTile[0]) - tileDistance
};
return bounds;
};
Grid.prototype.getBoundsLonLat = function(bounds) {
var max = this.tile2lonlat(bounds.e, bounds.n, this.geo.tileZoom);
var min = this.tile2lonlat(bounds.w, bounds.s, this.geo.tileZoom);
var boundsLonLat = {
n: this.geo.decimalPlaces(max[1]),
e: this.geo.decimalPlaces(max[0]),
s: this.geo.decimalPlaces(min[1]),
w: this.geo.decimalPlaces(min[0])
};
return boundsLonLat;
};
Grid.prototype.onCenterChanged = function(centerPixels, centerLonLat, bounds) {
var centerTile = this.lonlat2tile(centerLonLat[0], centerLonLat[1], this.geo.tileZoom, true);
var gridDiff = [
Math.floor(centerTile[0]) - Math.floor(this.centerTile[0]),
Math.floor(centerTile[1]) - Math.floor(this.centerTile[1])
];
if (Math.abs(gridDiff[0]) > 0 || Math.abs(gridDiff[1]) > 0) {
VIZI.Log("Update grid", gridDiff);
this.pos2d.x = centerPixels[0];
this.pos2d.y = centerPixels[1];
this.centerTile = centerTile;
this.boundsHigh = this.getBounds(this.tilesPerDirectionHigh);
this.boundsLow = this.getBounds(this.tilesPerDirectionLow);
this.boundsHighLonLat = this.getBoundsLonLat(this.boundsHigh);
this.boundsLowLonLat = this.getBoundsLonLat(this.boundsLow);
this.gridModel.position.x += this.tileSize * gridDiff[0];
this.gridModel.position.z += this.tileSize * gridDiff[1];
this.publish("gridUpdated");
}
};
Grid.prototype.createDebug = function() {
var lonLatMin = this.tile2lonlat(Math.floor(this.centerTile[0]), Math.floor(this.centerTile[1]), this.geo.tileZoom);
var lonLatMax = this.tile2lonlat(Math.floor(this.centerTile[0])+1, Math.floor(this.centerTile[1])+1, this.geo.tileZoom);
// Why is this tilesize so random?
this.tileSize = this.geo.projection(lonLatMax)[0] - this.geo.projection(lonLatMin)[0];
var tileLineMatHigh = new THREE.LineBasicMaterial( { color: 0xcc0000, linewidth: 6 } );
var tileLineMatLow = new THREE.LineBasicMaterial( { color: 0x0000cc, linewidth: 6 } );
var tileLineGeom = new THREE.Geometry();
var vertices = tileLineGeom.vertices;
vertices.push(new THREE.Vector3(0, 0, 0));
vertices.push(new THREE.Vector3(this.tileSize, 0, 0));
vertices.push(new THREE.Vector3(this.tileSize, 0, this.tileSize));
vertices.push(new THREE.Vector3(0, 0, this.tileSize));
vertices.push(new THREE.Vector3(0, 0, 0));
tileLineGeom.computeLineDistances();
var i, j, tileCoords, position, tileLine;
// High
var tileCountHigh = [this.boundsHigh.e-this.boundsHigh.w, this.boundsHigh.s-this.boundsHigh.n];
// Rows
for (i = 0; i < tileCountHigh[0]; i++) {
// Columns
for (j = 0; j < tileCountHigh[1]; j++) {
tileCoords = [this.boundsHigh.w + j, this.boundsHigh.n + i];
position = this.geo.projection(this.tile2lonlat(tileCoords[0], tileCoords[1], this.geo.tileZoom));
tileLine = new THREE.Line(tileLineGeom, tileLineMatHigh);
tileLine.position.y = 2;
tileLine.position.x = position[0];
tileLine.position.z = position[1];
this.gridModel.add(tileLine);
}
}
// Low
var tileCountLow = [this.boundsLow.e-this.boundsLow.w, this.boundsLow.s-this.boundsLow.n];
// Rows
for (i = 0; i < tileCountLow[0]; i++) {
// Columns
for (j = 0; j < tileCountLow[1]; j++) {
tileCoords = [this.boundsLow.w + j, this.boundsLow.n + i];
position = this.geo.projection(this.tile2lonlat(tileCoords[0], tileCoords[1], this.geo.tileZoom));
tileLine = new THREE.Line(tileLineGeom, tileLineMatLow);
tileLine.position.y = 0.1;
tileLine.position.x = position[0];
tileLine.position.z = position[1];
this.gridModel.add(tileLine);
}
}
};
Grid.prototype.lonlat2tile = function(lon, lat, zoom, float) {
lon = Number(lon);
var tx, ty;
if (float) {
tx = ((lon+180)/360*Math.pow(2,zoom));
ty = ((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom));
} else {
tx = (Math.floor((lon+180)/360*Math.pow(2,zoom)));
ty = (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom)));
}
return [tx, ty];
};
Grid.prototype.tile2lonlat = function(x, y, z) {
var lon = (x/Math.pow(2,z)*360-180);
var n = Math.PI-2*Math.PI*y/Math.pow(2,z);
var lat = (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
return [lon, lat];
};
var instance;
// an emulation of static variables and methods
var _static = {
name: "VIZI.Grid",
// Method for getting an instance. It returns
// a singleton instance of a singleton object
getInstance: function() {
if ( instance === undefined ) {
instance = new Grid();
}
return instance;
}
};
return _static;
}());
}());