From cd94dc9fa8a40a2d9db2f289d77b4906b0506236 Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Tue, 21 Jun 2016 14:52:18 -0400 Subject: [PATCH 1/2] Refactor `this.worldSize` out of xLng, latY, etc. --- js/geo/transform.js | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/js/geo/transform.js b/js/geo/transform.js index 0ac47a8100a..c5f3989b5d3 100644 --- a/js/geo/transform.js +++ b/js/geo/transform.js @@ -143,48 +143,50 @@ Transform.prototype = { project: function(lnglat, worldSize) { return new Point( - this.lngX(lnglat.lng, worldSize), - this.latY(lnglat.lat, worldSize)); + this.lngX(lnglat.lng, worldSize || this.worldSize), + this.latY(lnglat.lat, worldSize || this.worldSize)); }, unproject: function(point, worldSize) { return new LngLat( - this.xLng(point.x, worldSize), - this.yLat(point.y, worldSize)); + this.xLng(point.x, worldSize || this.worldSize), + this.yLat(point.y, worldSize || this.worldSize)); }, - get x() { return this.lngX(this.center.lng); }, - get y() { return this.latY(this.center.lat); }, + get x() { return this.lngX(this.center.lng, this.worldSize); }, + get y() { return this.latY(this.center.lat, this.worldSize); }, get point() { return new Point(this.x, this.y); }, /** * latitude to absolute x coord * @param {number} lon - * @param {number} [worldSize=this.worldSize] + * @param {number} worldSize * @returns {number} pixel coordinate * @private */ lngX: function(lng, worldSize) { - return (180 + lng) * (worldSize || this.worldSize) / 360; + return (180 + lng) * worldSize / 360; }, + /** * latitude to absolute y coord * @param {number} lat - * @param {number} [worldSize=this.worldSize] + * @param {number} worldSize * @returns {number} pixel coordinate * @private */ latY: function(lat, worldSize) { var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360)); - return (180 - y) * (worldSize || this.worldSize) / 360; + return (180 - y) * worldSize / 360; }, xLng: function(x, worldSize) { - return x * 360 / (worldSize || this.worldSize) - 180; + return x * 360 / worldSize - 180; }, + yLat: function(y, worldSize) { - var y2 = 180 - y * 360 / (worldSize || this.worldSize); + var y2 = 180 - y * 360 / worldSize; return 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90; }, @@ -235,8 +237,8 @@ Transform.prototype = { ll = LngLat.convert(lnglat); return new Coordinate( - this.lngX(ll.lng) * k, - this.latY(ll.lat) * k, + this.lngX(ll.lng, this.worldSize) * k, + this.latY(ll.lat, this.worldSize) * k, this.tileZoom); }, @@ -247,7 +249,7 @@ Transform.prototype = { * @private */ coordinateLocation: function(coord) { - var worldSize = this.zoomScale(coord.zoom); + var worldSize = this.zoomScale(coord.zoom) || this.worldSize; return new LngLat( this.xLng(coord.column, worldSize), this.yLat(coord.row, worldSize)); @@ -335,14 +337,14 @@ Transform.prototype = { unmodified = this._unmodified; if (this.latRange) { - minY = this.latY(this.latRange[1]); - maxY = this.latY(this.latRange[0]); + minY = this.latY(this.latRange[1], this.worldSize); + maxY = this.latY(this.latRange[0], this.worldSize); sy = maxY - minY < size.y ? size.y / (maxY - minY) : 0; } if (this.lngRange) { - minX = this.lngX(this.lngRange[0]); - maxX = this.lngX(this.lngRange[1]); + minX = this.lngX(this.lngRange[0], this.worldSize); + maxX = this.lngX(this.lngRange[1], this.worldSize); sx = maxX - minX < size.x ? size.x / (maxX - minX) : 0; } From ac92d09b0a3b649da660433aa09e2f9be15919ac Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Wed, 22 Jun 2016 18:27:47 -0400 Subject: [PATCH 2/2] Accept custom project,unproject --- debug/projection.html | 172 ++++++++++++++++++++++++++++++++++++++++++ js/geo/transform.js | 94 +++++++++++------------ js/ui/map.js | 2 +- 3 files changed, 216 insertions(+), 52 deletions(-) create mode 100644 debug/projection.html diff --git a/debug/projection.html b/debug/projection.html new file mode 100644 index 00000000000..705c2440ae7 --- /dev/null +++ b/debug/projection.html @@ -0,0 +1,172 @@ + + + + Mapbox GL JS debug page + + + + + + + + +
+
+
+
+
+ +
+ + + + + + + + + + + diff --git a/js/geo/transform.js b/js/geo/transform.js index c5f3989b5d3..16a6abaae6b 100644 --- a/js/geo/transform.js +++ b/js/geo/transform.js @@ -3,6 +3,7 @@ var LngLat = require('./lng_lat'), Point = require('point-geometry'), Coordinate = require('./coordinate'), + util = require('../util/util'), wrap = require('../util/util').wrap, interp = require('../util/interpolate'), TileCoord = require('../source/tile_coord'), @@ -23,7 +24,7 @@ module.exports = Transform; * @param {number} maxZoom * @private */ -function Transform(minZoom, maxZoom) { +function Transform(minZoom, maxZoom, projection) { this.tileSize = 512; // constant this._minZoom = minZoom || 0; @@ -31,6 +32,14 @@ function Transform(minZoom, maxZoom) { this.latRange = [-85.05113, 85.05113]; + if (projection) { + util.extend(this, util.pick(projection, [ + 'project', + 'unproject', + 'latRange' + ])); + } + this.width = 0; this.height = 0; this._center = new LngLat(0, 0); @@ -142,52 +151,26 @@ Transform.prototype = { scaleZoom: function(scale) { return Math.log(scale) / Math.LN2; }, project: function(lnglat, worldSize) { - return new Point( - this.lngX(lnglat.lng, worldSize || this.worldSize), - this.latY(lnglat.lat, worldSize || this.worldSize)); + worldSize = worldSize || this.worldSize; + var x = (180 + lnglat.lng) * worldSize / 360; + var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lnglat.lat * Math.PI / 360)); + y = (180 - y) * worldSize / 360; + return new Point(x, y); }, unproject: function(point, worldSize) { - return new LngLat( - this.xLng(point.x, worldSize || this.worldSize), - this.yLat(point.y, worldSize || this.worldSize)); + worldSize = worldSize || this.worldSize; + var lng = point.x * 360 / worldSize - 180; + var y2 = 180 - point.y * 360 / worldSize; + var lat = 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90; + return new LngLat(lng, lat); }, - get x() { return this.lngX(this.center.lng, this.worldSize); }, - get y() { return this.latY(this.center.lat, this.worldSize); }, - - get point() { return new Point(this.x, this.y); }, + get x () { return this.point.x; }, + get y () { return this.point.y; }, - /** - * latitude to absolute x coord - * @param {number} lon - * @param {number} worldSize - * @returns {number} pixel coordinate - * @private - */ - lngX: function(lng, worldSize) { - return (180 + lng) * worldSize / 360; - }, - - /** - * latitude to absolute y coord - * @param {number} lat - * @param {number} worldSize - * @returns {number} pixel coordinate - * @private - */ - latY: function(lat, worldSize) { - var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360)); - return (180 - y) * worldSize / 360; - }, - - xLng: function(x, worldSize) { - return x * 360 / worldSize - 180; - }, - - yLat: function(y, worldSize) { - var y2 = 180 - y * 360 / worldSize; - return 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90; + get point() { + return this.project(this.center); }, panBy: function(offset) { @@ -234,11 +217,11 @@ Transform.prototype = { */ locationCoordinate: function(lnglat) { var k = this.zoomScale(this.tileZoom) / this.worldSize, - ll = LngLat.convert(lnglat); + pt = this.project(LngLat.convert(lnglat)); return new Coordinate( - this.lngX(ll.lng, this.worldSize) * k, - this.latY(ll.lat, this.worldSize) * k, + pt.x * k, + pt.y * k, this.tileZoom); }, @@ -250,9 +233,7 @@ Transform.prototype = { */ coordinateLocation: function(coord) { var worldSize = this.zoomScale(coord.zoom) || this.worldSize; - return new LngLat( - this.xLng(coord.column, worldSize), - this.yLat(coord.row, worldSize)); + return this.unproject(new Point(coord.column, coord.row), worldSize); }, pointCoordinate: function(p) { @@ -329,6 +310,7 @@ Transform.prototype = { _constrain: function() { if (!this.center || !this.width || !this.height || this._constraining) return; + if (!this.latRange && !this.lngRange) return; this._constraining = true; @@ -336,15 +318,25 @@ Transform.prototype = { size = this.size, unmodified = this._unmodified; + var ul = this.project(LngLat.convert([ + this.lngRange ? this.lngRange[0] : 0, + this.latRange ? this.latRange[1] : 0 + ])); + + var lr = this.project(LngLat.convert([ + this.lngRange ? this.lngRange[1] : 0, + this.latRange ? this.latRange[0] : 0 + ])); + if (this.latRange) { - minY = this.latY(this.latRange[1], this.worldSize); - maxY = this.latY(this.latRange[0], this.worldSize); + minY = ul.y; + maxY = lr.y; sy = maxY - minY < size.y ? size.y / (maxY - minY) : 0; } if (this.lngRange) { - minX = this.lngX(this.lngRange[0], this.worldSize); - maxX = this.lngX(this.lngRange[1], this.worldSize); + minX = ul.x; + maxX = lr.x; sx = maxX - minX < size.x ? size.x / (maxX - minX) : 0; } diff --git a/js/ui/map.js b/js/ui/map.js index 5949d10dd9f..69ba6a7096e 100755 --- a/js/ui/map.js +++ b/js/ui/map.js @@ -129,7 +129,7 @@ var Map = module.exports = function(options) { } this.animationLoop = new AnimationLoop(); - this.transform = new Transform(options.minZoom, options.maxZoom); + this.transform = new Transform(options.minZoom, options.maxZoom, options.projection); if (options.maxBounds) { this.setMaxBounds(options.maxBounds);