Skip to content

Commit

Permalink
Merge pull request #562 from openlayers/client_side_raster_reprojection
Browse files Browse the repository at this point in the history
Add client side raster reprojection support
  • Loading branch information
gberaudo authored May 2, 2018
2 parents f4dc6c7 + 8a43c2e commit 22bc888
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 36 deletions.
7 changes: 6 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Changelog

# v 1.36
# v 1.37

* Changes
* Add client side raster reprojection, see the example to see how to enable it.

# v 1.36 - 2018-04-18

* Changes
* Rework the autorenderloop using Cesium RenderMode.
Expand Down
2 changes: 1 addition & 1 deletion Cesium.externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2133,7 +2133,7 @@ Cesium.ImageryProvider.prototype.getTileCredits = function(x, y, level) {};
* @param {number} x The tile X coordinate.
* @param {number} y The tile Y coordinate.
* @param {number} level The tile level.
* @return {Object|undefined}
* @return {Promise<?>|undefined}
*/
Cesium.ImageryProvider.prototype.requestImage = function(x, y, level) {};

Expand Down
17 changes: 17 additions & 0 deletions examples/reprojection.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="index, all" />
<title>ol3cesium example</title>
<link rel="stylesheet" href="../node_modules/openlayers/css/ol.css" type="text/css">
</head>
<body>
<div id="map" style="width:600px;height:400px;"></div>
<input type="button" value="Enable/disable" onclick="javascript:ol3d.setEnabled(!ol3d.getEnabled())" />
<script src="inject_ol_cesium.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.6/proj4.js" integrity="sha384-M06Wz+wp7/Hfi8Ks7DJtWxAFDqihGPCsNmjmWhnUQ8vBTSwd/1Os0uhf2hcYXt2t" crossorigin="anonymous"></script>
<script src="reprojection.js"></script>
</body>
</html>
59 changes: 59 additions & 0 deletions examples/reprojection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* eslint googshift/valid-provide-and-module: 0 */

goog.provide('examples.reprojection');

goog.require('olcs.OLCesium');
goog.require('ol.View');
goog.require('ol.Map');
goog.require('ol.Attribution');
goog.require('ol.proj');
goog.require('ol.layer.Tile');
goog.require('ol.source.TileWMS');
goog.require('olcs.core.OLImageryProvider');

olcs.core.OLImageryProvider.ENABLE_RASTER_REPROJECTION = true;

proj4.defs('EPSG:21781', '+proj=somerc +lat_0=46.95240555555556 ' +
'+lon_0=7.439583333333333 +k_0=1 +x_0=600000 +y_0=200000 +ellps=bessel ' +
'+towgs84=674.4,15.1,405.3,0,0,0,0 +units=m +no_defs');
const proj21781 = ol.proj.get('EPSG:21781');
proj21781.setExtent([485071.54, 75346.36, 828515.78, 299941.84]);

const source = new ol.source.TileWMS({
attributions: [new ol.Attribution({
html: '&copy; ' +
'<a href="http://www.geo.admin.ch/internet/geoportal/' +
'en/home.html">' +
'Pixelmap 1:1000000 / geo.admin.ch</a>'
})],
crossOrigin: 'anonymous',
params: {
'LAYERS': 'ch.swisstopo.pixelkarte-farbe-pk1000.noscale',
'FORMAT': 'image/jpeg'
},
url: 'http://wms.geo.admin.ch/',
projection: 'EPSG:21781'
});


const ol2d = new ol.Map({
layers: [
new ol.layer.Tile({
source
})
],
target: 'map',
view: new ol.View({
projection: 'EPSG:21781',
center: ol.proj.transform([6.56273, 46.51781], 'EPSG:4326', 'EPSG:21781'),
zoom: 6
})
});

const ol3d = new olcs.OLCesium({map: ol2d});
const scene = ol3d.getCesiumScene();
const terrainProvider = new Cesium.CesiumTerrainProvider({
url: '//assets.agi.com/stk-terrain/world'
});
scene.terrainProvider = terrainProvider;
ol3d.setEnabled(true);
7 changes: 5 additions & 2 deletions src/olcs/core.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
goog.provide('olcs.core');
goog.require('ol.easing');

goog.require('goog.asserts');

goog.require('ol');
goog.require('ol.easing');
goog.require('ol.layer.Tile');
goog.require('ol.layer.Image');
goog.require('ol.proj');
goog.require('ol.source.Image');
goog.require('ol.source.ImageWMS');
goog.require('ol.source.TileImage');
goog.require('ol.source.TileWMS');

goog.require('olcs.core.OLImageryProvider');
goog.require('olcs.util');

Expand Down Expand Up @@ -393,7 +396,7 @@ olcs.core.tileLayerToImageryLayer = function(olLayer, viewProj) {
projection = viewProj;
}

if (olcs.core.isCesiumProjection(projection)) {
if (olcs.core.isCesiumProjection(projection) || ol.ENABLE_RASTER_REPROJECTION) {
provider = new olcs.core.OLImageryProvider(source, viewProj);
}
// Projection not supported by Cesium
Expand Down
99 changes: 67 additions & 32 deletions src/olcs/core/olimageryprovider.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
goog.provide('olcs.core.OLImageryProvider');

goog.require('ol');
goog.require('ol.events');
goog.require('ol.proj');
goog.require('ol.TileState');

goog.require('olcs.util');



/**
* Special class derived from Cesium.ImageryProvider
* that is connected to the given ol.source.TileImage.
* Special class derived from Cesium.ImageryProvider that is connected to the given ol.source.TileImage.
* @param {!ol.source.TileImage} source
* @param {ol.proj.Projection=} opt_fallbackProj Projection to assume if the
* projection of the source
* is not defined.
* @param {ol.proj.Projection=} opt_fallbackProj Projection to assume if the projection of the source is not defined.
* @constructor
* @struct
* @extends {Cesium.ImageryProvider}
Expand All @@ -34,34 +35,34 @@ olcs.core.OLImageryProvider = function(source, opt_fallbackProj) {
this.projection_ = null;

/**
* @type {?ol.proj.Projection}
* @type {Cesium.Rectangle|undefined}
* @private
*/
this.fallbackProj_ = opt_fallbackProj || null;
this.rectangle_ = undefined;

/**
* @type {boolean}
* @type {Cesium.TilingScheme|undefined}
* @private
*/
this.ready_ = false;
this.tilingScheme_ = undefined;

/**
* @type {?Cesium.Credit}
* @type {Cesium.Credit|undefined}
* @private
*/
this.credit_ = null;
this.credit_ = undefined;

/**
* @type {?Cesium.TilingScheme}
* @type {?ol.proj.Projection}
* @private
*/
this.tilingScheme_ = null;
this.fallbackProj_ = opt_fallbackProj || null;

/**
* @type {?Cesium.Rectangle}
* @type {boolean}
* @private
*/
this.rectangle_ = null;
this.ready_ = false;

const proxy = this.source_.get('olcs.proxy');
if (proxy) {
Expand Down Expand Up @@ -182,9 +183,14 @@ olcs.core.OLImageryProvider.prototype.handleSourceChanged_ = function() {
this.tilingScheme_ = new Cesium.GeographicTilingScheme();
} else if (this.projection_ == ol.proj.get('EPSG:3857')) {
this.tilingScheme_ = new Cesium.WebMercatorTilingScheme();
} else if (ol.ENABLE_RASTER_REPROJECTION && olcs.core.OLImageryProvider.ENABLE_RASTER_REPROJECTION) {
this.tilingScheme_ = new Cesium.GeographicTilingScheme();
this.projection_ = ol.proj.get('EPSG:4326'); // reproject
} else {
return;
}

// FIXME: should intersect with the source extent
this.rectangle_ = this.tilingScheme_.rectangle;

this.credit_ = olcs.core.OLImageryProvider.createCreditForSource(this.source_);
Expand Down Expand Up @@ -230,23 +236,52 @@ olcs.core.OLImageryProvider.prototype.getTileCredits = function(x, y, level) {
* @override
*/
olcs.core.OLImageryProvider.prototype.requestImage = function(x, y, level) {
const tileUrlFunction = this.source_.getTileUrlFunction();
if (tileUrlFunction && this.projection_) {

// Perform mapping of Cesium tile coordinates to OpenLayers tile coordinates:
// 1) Cesium zoom level 0 is OpenLayers zoom level 1 for EPSG:4326
const z_ = this.tilingScheme_ instanceof Cesium.GeographicTilingScheme ? level + 1 : level;
// 2) OpenLayers tile coordinates increase from bottom to top
const y_ = -y - 1;

let url = tileUrlFunction.call(this.source_,
[z_, x, y_], 1, this.projection_);
if (this.proxy_) {
url = this.proxy_.getURL(url);
}
return url ? Cesium.ImageryProvider.loadImage(this, url) : this.emptyCanvas_;
// Perform mapping of Cesium tile coordinates to ol3 tile coordinates:
// 1) Cesium zoom level 0 is OpenLayers zoom level 1 for EPSG:4326
const z_ = this.tilingScheme_ instanceof Cesium.GeographicTilingScheme ? level + 1 : level;
// 2) OpenLayers tile coordinates increase from bottom to top
const y_ = -y - 1;

const tilegrid = this.source_.getTileGridForProjection(this.projection_);
if (z_ < tilegrid.getMinZoom() || z_ > tilegrid.getMaxZoom()) {
return Promise.resolve(this.emptyCanvas_); // no data
}

const tile = this.source_.getTile(z_, x, y_, 1, this.projection_);

tile.load();

// not yet loaded!
// const image = tile.getImage();
// if (!image || !image.src) {
// return Promise.resolve(this.emptyCanvas_); // no data
// }


const state = tile.getState();
if (state === ol.TileState.LOADED || state === ol.TileState.EMPTY) {
return Promise.resolve(tile.getImage()) || undefined;
} else if (state === ol.TileState.ERROR) {
return undefined; // let Cesium continue retrieving later
} else {
// return empty canvas to stop Cesium from retrying later
return this.emptyCanvas_;
const promise = new Promise((resolve, reject) => {
const unlisten = ol.events.listen(tile, 'change', (evt) => {
const state = tile.getState();
if (state === ol.TileState.LOADED || state === ol.TileState.EMPTY) {
resolve(tile.getImage() || undefined);
ol.events.unlistenByKey(unlisten);
} else if (state === ol.TileState.ERROR) {
resolve(undefined); // let Cesium continue retrieving later
ol.events.unlistenByKey(unlisten);
}
});
});
return promise;
}
};

/**
* @type {boolean}
* @export
*/
olcs.core.OLImageryProvider.ENABLE_RASTER_REPROJECTION = false;

0 comments on commit 22bc888

Please sign in to comment.