Permalink
Browse files

Added geo components and tests

  • Loading branch information...
robhawkes committed Feb 13, 2016
1 parent d745b5a commit 54e01566610cbc633fd0b209457c08eddfa2a640
View
@@ -1,3 +1,5 @@
tmp/
# Created by https://www.gitignore.io/api/node,osx,windows
### Node ###
View
@@ -64,9 +64,9 @@ return /******/ (function(modules) { // webpackBootstrap
var _World2 = _interopRequireDefault(_World);
var _controlsControls = __webpack_require__(8);
var _controlsIndex = __webpack_require__(8);
var _controlsControls2 = _interopRequireDefault(_controlsControls);
var _controlsIndex2 = _interopRequireDefault(_controlsIndex);
var _layerEnvironmentEnvironmentLayer = __webpack_require__(11);
@@ -77,7 +77,7 @@ return /******/ (function(modules) { // webpackBootstrap
// Public API
World: _World2['default'],
Controls: _controlsControls2['default'],
Controls: _controlsIndex2['default'],
EnvironmentLayer: _layerEnvironmentEnvironmentLayer2['default']
};

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -156,6 +156,10 @@ function testBrowser() {
output: {
filename: '__spec-build.js'
},
externals: {
// Proxy the global THREE variable to require('three')
'three': 'THREE'
},
module: {
loaders: [
// This is what allows us to author in future JavaScript
View
@@ -80,6 +80,8 @@
},
"dependencies": {
"eventemitter3": "^1.1.1",
"lodash.assign": "^4.0.2",
"proj4": "^2.3.12",
"three-orbit-controls": "github:robhawkes/three-orbit-controls"
}
}
File renamed without changes.
@@ -0,0 +1,32 @@
/*
* CRS.EPSG3395 (WGS 84 / World Mercator) CRS implementation.
*
* Based on:
* https://github.com/Leaflet/Leaflet/blob/master/src/geo/crs/CRS.EPSG3395.js
*/
import extend from 'lodash.assign';
import Earth from './CRS.Earth';
import Mercator from '../projection/Projection.Mercator';
import Transformation from '../../util/Transformation';
var _EPSG3395 = {
code: 'EPSG:3395',
projection: Mercator,
// Work out how to de-dupe this (scoping issue)
transformScale: 1 / (Math.PI * Mercator.R),
// Scale and transformation inputs changed to account for central origin in
// WebGL, instead of top-left origin used in Leaflet
transformation: (function() {
// TODO: Cannot use this.transformScale due to scope
var scale = 1 / (Math.PI * Mercator.R);
return new Transformation(scale, 0, -scale, 0);
}())
};
const EPSG3395 = extend({}, Earth, _EPSG3395);
export default EPSG3395;
@@ -0,0 +1,38 @@
/*
* CRS.EPSG3857 (WGS 84 / Pseudo-Mercator) CRS implementation.
*
* Based on:
* https://github.com/Leaflet/Leaflet/blob/master/src/geo/crs/CRS.EPSG3857.js
*/
import extend from 'lodash.assign';
import Earth from './CRS.Earth';
import SphericalMercator from '../projection/Projection.SphericalMercator';
import Transformation from '../../util/Transformation';
var _EPSG3857 = {
code: 'EPSG:3857',
projection: SphericalMercator,
// Work out how to de-dupe this (scoping issue)
transformScale: 1 / (Math.PI * SphericalMercator.R),
// Scale and transformation inputs changed to account for central origin in
// WebGL, instead of top-left origin used in Leaflet
transformation: (function() {
// TODO: Cannot use this.transformScale due to scope
var scale = 1 / (Math.PI * SphericalMercator.R);
return new Transformation(scale, 0, -scale, 0);
}())
};
const EPSG3857 = extend({}, Earth, _EPSG3857);
const EPSG900913 = extend({}, EPSG3857, {
code: 'EPSG:900913'
});
export {EPSG900913};
export default EPSG3857;
@@ -0,0 +1,29 @@
/*
* CRS.EPSG4326 is a CRS popular among advanced GIS specialists.
*
* Based on:
* https://github.com/Leaflet/Leaflet/blob/master/src/geo/crs/CRS.EPSG4326.js
*/
import extend from 'lodash.assign';
import Earth from './CRS.Earth';
import LatLon from '../projection/Projection.LatLon';
import Transformation from '../../util/Transformation';
var _EPSG4326 = {
code: 'EPSG:4326',
projection: LatLon,
// Work out how to de-dupe this (scoping issue)
transformScale: 1 / 180,
// Scale and transformation inputs changed to account for central origin in
// WebGL, instead of top-left origin used in Leaflet
//
// TODO: Cannot use this.transformScale due to scope
transformation: new Transformation(1 / 180, 0, -1 / 180, 0)
};
const EPSG4326 = extend({}, Earth, _EPSG4326);
export default EPSG4326;
View
@@ -0,0 +1,121 @@
/*
* CRS.Earth is the base class for all CRS representing Earth.
*
* Based on:
* https://github.com/Leaflet/Leaflet/blob/master/src/geo/crs/CRS.Earth.js
*/
import extend from 'lodash.assign';
import CRS from './CRS';
const Earth = {
wrapLon: [-180, 180],
R: 6378137,
// Distance between two geographical points using spherical law of cosines
// approximation or Haversine
//
// See: http://www.movable-type.co.uk/scripts/latlong.html
distance: function(latlon1, latlon2, accurate) {
var rad = Math.PI / 180;
var lat1;
var lat2;
var a;
if (!accurate) {
lat1 = latlon1[0] * rad;
lat2 = latlon2[0] * rad;
a = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos((latlon2[1] - latlon1[1]) * rad);
return this.R * Math.acos(Math.min(a, 1));
} else {
lat1 = latlon1[0] * rad;
lat2 = latlon2[0] * rad;
var lon1 = latlon1[1] * rad;
var lon2 = latlon2[1] * rad;
var deltaLat = lat2 - lat1;
var deltaLon = lon2 - lon1;
var halfDeltaLat = deltaLat / 2;
var halfDeltaLon = deltaLon / 2;
a = Math.sin(halfDeltaLat) * Math.sin(halfDeltaLat) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(halfDeltaLon) * Math.sin(halfDeltaLon);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return this.R * c;
}
},
// Scale factor for converting between real metres and projected metres
//
// projectedMetres = realMetres * pointScale
// realMetres = projectedMetres / pointScale
//
// Defaults to a scale factor of 1 if no calculation method exists
//
// Probably need to run this through the CRS transformation or similar so the
// resulting scale is relative to the dimensions of the world space
// Eg. 1 metre in projected space is likly scaled up or down to some other
// number
pointScale: function(latlon, accurate) {
return (this.projection.pointScale) ? this.projection.pointScale(latlon, accurate) : [1, 1];
},
// Convert real metres to projected units
//
// Latitude scale is chosen because it fluctuates more than longitude
metresToProjected: function(metres, pointScale) {
return metres * pointScale[1];
},
// Convert projected units to real metres
//
// Latitude scale is chosen because it fluctuates more than longitude
projectedToMetres: function(projectedUnits, pointScale) {
return projectedUnits / pointScale[1];
},
// Convert real metres to a value in world (WebGL) units
metresToWorld: function(metres, pointScale, zoom) {
// Transform metres to projected metres using the latitude point scale
//
// Latitude scale is chosen because it fluctuates more than longitude
var projectedMetres = this.metresToProjected(metres, pointScale);
var scale = this.scale(zoom);
// Half scale if using zoom as WebGL origin is in the centre, not top left
if (zoom) {
scale /= 2;
}
// Scale projected metres
var scaledMetres = (scale * (this.transformScale * projectedMetres)) / pointScale[1];
return scaledMetres;
},
// Convert world (WebGL) units to a value in real metres
worldToMetres: function(worldUnits, pointScale, zoom) {
var scale = this.scale(zoom);
// Half scale if using zoom as WebGL origin is in the centre, not top left
if (zoom) {
scale /= 2;
}
var projectedUnits = ((worldUnits / scale) / this.transformScale) * pointScale[1];
var realMetres = this.projectedToMetres(projectedUnits, pointScale);
return realMetres;
}
};
export default extend({}, CRS, Earth);
View
@@ -0,0 +1,50 @@
/*
* CRS.Proj4 for any Proj4-supported CRS.
*/
import extend from 'lodash.assign';
import Earth from './CRS.Earth';
import Proj4Projection from '../projection/Projection.Proj4';
import Transformation from '../../util/Transformation';
var _Proj4 = function(code, def, bounds) {
var projection = Proj4Projection(def, bounds);
// Transformation calcuations
var diffX = projection.bounds[1][0] - projection.bounds[0][0];
var diffY = projection.bounds[1][1] - projection.bounds[0][1];
var halfX = diffX / 2;
var halfY = diffY / 2;
// This is the raw scale factor
var scaleX = 1 / halfX;
var scaleY = 1 / halfY;
// Find the minimum scale factor
//
// The minimum scale factor comes from the largest side and is the one
// you want to use for both axis so they stay relative in dimension
var scale = Math.min(scaleX, scaleY);
// Find amount to offset each axis by to make the central point lie on
// the [0,0] origin
var offsetX = scale * (projection.bounds[0][0] + halfX);
var offsetY = scale * (projection.bounds[0][1] + halfY);
return {
code: code,
projection: projection,
transformScale: scale,
// Map the input to a [-1,1] range with [0,0] in the centre
transformation: new Transformation(scale, -offsetX, -scale, offsetY)
};
};
const Proj4 = function(code, def, bounds) {
return extend({}, Earth, _Proj4(code, def, bounds));
};
export default Proj4;
View
@@ -0,0 +1,47 @@
/*
* A simple CRS that can be used for flat non-Earth maps like panoramas or game
* maps.
*
* Based on:
* https://github.com/Leaflet/Leaflet/blob/master/src/geo/crs/CRS.Simple.js
*/
import extend from 'lodash.assign';
import CRS from './CRS';
import LatLon from '../projection/Projection.LatLon';
import Transformation from '../../util/Transformation';
var _Simple = {
projection: LatLon,
// Straight 1:1 mapping (-1, -1 would be top-left)
transformation: new Transformation(1, 0, 1, 0),
scale: function(zoom) {
// If zoom is provided then return scale based on map tile zoom
if (zoom) {
return Math.pow(2, zoom);
// Else, make no change to scale – may need to increase this or make it a
// user-definable variable
} else {
return 1;
}
},
zoom: function(scale) {
return Math.log(scale) / Math.LN2;
},
distance: function(latlon1, latlon2) {
var dx = latlon2[1] - latlon1[1];
var dy = latlon2[0] - latlon1[0];
return Math.sqrt(dx * dx + dy * dy);
},
infinite: true
};
const Simple = extend({}, CRS, _Simple);
export default Simple;
Oops, something went wrong.

0 comments on commit 54e0156

Please sign in to comment.