Permalink
Browse files

Added geo components and tests

  • Loading branch information...
1 parent d745b5a commit 54e01566610cbc633fd0b209457c08eddfa2a640 @robhawkes robhawkes committed Feb 13, 2016
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']
};
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;
@@ -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);
@@ -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;
@@ -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.