From 737f3a5066bef26fec7a45fae181e77978f0d168 Mon Sep 17 00:00:00 2001 From: mike-000 <49240900+mike-000@users.noreply.github.com> Date: Mon, 24 Feb 2020 21:53:53 +0000 Subject: [PATCH] Handle view projections crossing dateline Use custom toLonLat transform to return wrapped longitudes for extents if view projection crosses the dateline. Enhance the validation for center and extents to avoid proj4 errors. --- src/ol/layer/Graticule.js | 71 +++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/src/ol/layer/Graticule.js b/src/ol/layer/Graticule.js index 31e0f5aaee..6c17962753 100644 --- a/src/ol/layer/Graticule.js +++ b/src/ol/layer/Graticule.js @@ -12,10 +12,18 @@ import VectorSource from '../source/Vector.js'; import { equivalent as equivalentProjection, get as getProjection, - getTransform, - transformExtent + getTransform } from '../proj.js'; -import {getCenter, getHeight, getWidth, intersects, equals, getIntersection, isEmpty} from '../extent.js'; +import { + applyTransform, + equals, + getCenter, + getHeight, + getIntersection, + getWidth, + intersects, + isEmpty +} from '../extent.js'; import {clamp} from '../math.js'; import Style from '../style/Style.js'; import Feature from '../Feature.js'; @@ -665,24 +673,30 @@ class Graticule extends VectorLayer { return; } - const centerLonLat = this.toLonLatTransform_(center); + const validCenter = [ + clamp(center[0], this.minLonP_, this.maxLonP_), + clamp(center[1], this.minLatP_, this.maxLatP_) + ]; + + const centerLonLat = this.toLonLatTransform_(validCenter); let centerLon = centerLonLat[0]; let centerLat = centerLonLat[1]; const maxLines = this.maxLines_; let cnt, idx, lat, lon; let validExtent = [ - Math.max(extent[0], this.minLonP_), - Math.max(extent[1], this.minLatP_), - Math.min(extent[2], this.maxLonP_), - Math.min(extent[3], this.maxLatP_) + clamp(extent[0], this.minLonP_, this.maxLonP_), + clamp(extent[1], this.minLatP_, this.maxLatP_), + clamp(extent[2], this.minLonP_, this.maxLonP_), + clamp(extent[3], this.minLatP_, this.maxLatP_) ]; - validExtent = transformExtent(validExtent, this.projection_, 'EPSG:4326', 8); - const maxLat = validExtent[3]; - const maxLon = validExtent[2]; - const minLat = validExtent[1]; - const minLon = validExtent[0]; + validExtent = applyTransform(validExtent, this.toLonLatTransform_, undefined, 8); + + const maxLat = Math.min(validExtent[3], this.maxLat_); + const maxLon = Math.min(validExtent[2], this.maxLon_); + const minLat = Math.max(validExtent[1], this.minLat_); + const minLon = Math.max(validExtent[0], this.minLon_); // Create meridians @@ -897,22 +911,43 @@ class Graticule extends VectorLayer { const epsg4326Projection = getProjection('EPSG:4326'); const worldExtent = projection.getWorldExtent(); - const worldExtentP = transformExtent(worldExtent, epsg4326Projection, projection, 8); this.maxLat_ = worldExtent[3]; this.maxLon_ = worldExtent[2]; this.minLat_ = worldExtent[1]; this.minLon_ = worldExtent[0]; + const toLonLatTransform = getTransform(projection, epsg4326Projection); + if (this.minLon_ < this.maxLon_) { + this.toLonLatTransform_ = toLonLatTransform; + } else { + const split = this.minLon_ + this.maxLon_ / 2; + this.maxLon_ += 360; + this.toLonLatTransform_ = function(coordinates, opt_output, opt_dimension) { + const dimension = opt_dimension || 2; + const lonLatCoordinates = toLonLatTransform(coordinates, opt_output, dimension); + for (let i = 0, l = lonLatCoordinates.length; i < l; i += dimension) { + if (lonLatCoordinates[i] < split) { + lonLatCoordinates[i] += 360; + } + } + return lonLatCoordinates; + }; + } + + this.fromLonLatTransform_ = getTransform(epsg4326Projection, projection); + const worldExtentP = applyTransform( + [this.minLon_, this.minLat_, this.maxLon_, this.maxLat_], + this.fromLonLatTransform_, + undefined, + 8 + ); + this.maxLatP_ = worldExtentP[3]; this.maxLonP_ = worldExtentP[2]; this.minLatP_ = worldExtentP[1]; this.minLonP_ = worldExtentP[0]; - this.fromLonLatTransform_ = getTransform(epsg4326Projection, projection); - - this.toLonLatTransform_ = getTransform(projection, epsg4326Projection); - this.projectionCenterLonLat_ = this.toLonLatTransform_(getCenter(projection.getExtent())); this.projection_ = projection;