diff --git a/examples/reprojection.html b/examples/reprojection.html
new file mode 100644
index 000000000..ce62651c6
--- /dev/null
+++ b/examples/reprojection.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ Reprojection example
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/reprojection.js b/examples/reprojection.js
new file mode 100644
index 000000000..c2b399f50
--- /dev/null
+++ b/examples/reprojection.js
@@ -0,0 +1,59 @@
+/**
+ * @module examples.reprojection
+ */
+const exports = {};
+
+import proj4 from 'proj4';
+import {register} from 'ol/proj/proj4.js';
+import {get as getProjection} from 'ol/proj.js';
+import olTileWMS from 'ol/source/TileWMS.js';
+import olMap from 'ol/Map.js';
+import olLayerTile from 'ol/layer/Tile.js';
+import olView from 'ol/View.js';
+import OLCesium from 'olcs/OLCesium.js';
+import olSourceOSM from 'ol/source/OSM.js';
+
+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');
+register(proj4);
+const proj21781 = getProjection('EPSG:21781');
+proj21781.setExtent([485071.54, 75346.36, 828515.78, 299941.84]);
+const source = new olTileWMS({
+ attributions: ['© ' +
+ '' +
+ 'Pixelmap 1:1000000 / geo.admin.ch'],
+ 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 olMap({
+ layers: [
+ new olLayerTile({source: new olSourceOSM()}),
+ new olLayerTile({
+ source
+ })
+ ],
+ target: 'map',
+ view: new olView({
+ projection: 'EPSG:4326',
+ center: [6.56273, 46.51781],
+ zoom: 6
+ })
+});
+const ol3d = new 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);
+
+document.getElementById('enable').addEventListener('click', () => ol3d.setEnabled(!ol3d.getEnabled()));
+
+export default exports;
diff --git a/src/olcs/core.js b/src/olcs/core.js
index a36cd97eb..294fc2982 100644
--- a/src/olcs/core.js
+++ b/src/olcs/core.js
@@ -12,6 +12,7 @@ import olSourceTileWMS from 'ol/source/TileWMS.js';
import {defaultImageLoadFunction} from 'ol/source/Image.js';
import olcsCoreOLImageryProvider from './core/OLImageryProvider.js';
import olcsUtil from './util.js';
+import {ENABLE_RASTER_REPROJECTION} from 'ol/reproj/common.js';
const exports = {};
@@ -421,7 +422,7 @@ exports.tileLayerToImageryLayer = function(olMap, olLayer, viewProj) {
projection = viewProj;
}
- if (exports.isCesiumProjection(projection)) {
+ if (exports.isCesiumProjection(projection) || ENABLE_RASTER_REPROJECTION) {
provider = new olcsCoreOLImageryProvider(olMap, source, viewProj);
}
// Projection not supported by Cesium
diff --git a/src/olcs/core/OLImageryProvider.js b/src/olcs/core/OLImageryProvider.js
index 46a4c947e..ba8286684 100644
--- a/src/olcs/core/OLImageryProvider.js
+++ b/src/olcs/core/OLImageryProvider.js
@@ -3,6 +3,9 @@
*/
import {get as getProjection} from 'ol/proj.js';
import olcsUtil from '../util.js';
+import {ENABLE_RASTER_REPROJECTION} from 'ol/reproj/common.js';
+import olTileState from 'ol/TileState.js';
+import {listen, unlistenByKey} from 'ol/events.js';
import {Tile as TileSource} from 'ol/source.js';
@@ -110,6 +113,9 @@ class OLImageryProvider /* should not extend Cesium.ImageryProvider */ {
this.tilingScheme_ = new Cesium.GeographicTilingScheme();
} else if (this.projection_ == getProjection('EPSG:3857')) {
this.tilingScheme_ = new Cesium.WebMercatorTilingScheme();
+ } else if (ENABLE_RASTER_REPROJECTION) {
+ this.tilingScheme_ = new Cesium.GeographicTilingScheme();
+ this.projection_ = getProjection('EPSG:4326');
} else {
return;
}
@@ -152,25 +158,52 @@ class OLImageryProvider /* should not extend Cesium.ImageryProvider */ {
* @override
*/
requestImage(x, y, level) {
- const tileUrlFunction = this.source_.getTileUrlFunction();
- if (tileUrlFunction && this.projection_) {
+ // 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
+
+ let y_ = y;
+ if (!olUseNewCoordinates) {
+ // OpenLayers version 3 to 5 tile coordinates increase from bottom to top
+ y_ = -y - 1;
+ }
- // Cesium zoom level 0 is OpenLayers zoom level 1 for EPSG:4326
- const z_ = this.tilingScheme_ instanceof Cesium.GeographicTilingScheme ? level + 1 : level;
+ const tilegrid = this.source_.getTileGridForProjection(this.projection_);
+ if (z_ < tilegrid.getMinZoom() || z_ > tilegrid.getMaxZoom()) {
+ return Promise.resolve(this.emptyCanvas_); // no data
+ }
- let y_ = y;
- if (!olUseNewCoordinates) {
- // OpenLayers version 3 to 5 tile coordinates increase from bottom to top
- 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_;
+ 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 this.emptyCanvas_; // no data
+ // }
+
+
+ const state = tile.getState();
+ if (state === olTileState.LOADED || state === olTileState.EMPTY) {
+ return Promise.resolve(tile.getImage()) || undefined;
+ } else if (state === olTileState.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 = listen(tile, 'change', (evt) => {
+ const state = tile.getState();
+ if (state === olTileState.LOADED || state === olTileState.EMPTY) {
+ resolve(tile.getImage() || undefined);
+ unlistenByKey(unlisten);
+ } else if (state === olTileState.ERROR) {
+ resolve(undefined); // let Cesium continue retrieving later
+ unlistenByKey(unlisten);
+ }
+ });
+ });
+ return promise;
}
}
}
@@ -180,54 +213,54 @@ class OLImageryProvider /* should not extend Cesium.ImageryProvider */ {
Object.defineProperties(OLImageryProvider.prototype, {
'ready': {
'get': /** @this {olcs.core.OLImageryProvider} */
- function() {return this.ready_;}
+ function() {return this.ready_;}
},
'rectangle': {
'get': /** @this {olcs.core.OLImageryProvider} */
- function() {return this.rectangle_;}
+ function() {return this.rectangle_;}
},
'tileWidth': {
'get': /** @this {olcs.core.OLImageryProvider} */
- function() {
- const tg = this.source_.getTileGrid();
- return tg ? (Array.isArray(tg.getTileSize(0)) ? tg.getTileSize(0)[0] : tg.getTileSize(0)) : 256;
- }
+ function() {
+ const tg = this.source_.getTileGrid();
+ return tg ? (Array.isArray(tg.getTileSize(0)) ? tg.getTileSize(0)[0] : tg.getTileSize(0)) : 256;
+ }
},
'tileHeight': {
'get': /** @this {olcs.core.OLImageryProvider} */
- function() {
- const tg = this.source_.getTileGrid();
- return tg ? (Array.isArray(tg.getTileSize(0)) ? tg.getTileSize(0)[1] : tg.getTileSize(0)) : 256;
- }
+ function() {
+ const tg = this.source_.getTileGrid();
+ return tg ? (Array.isArray(tg.getTileSize(0)) ? tg.getTileSize(0)[1] : tg.getTileSize(0)) : 256;
+ }
},
'maximumLevel': {
'get': /** @this {olcs.core.OLImageryProvider} */
- function() {
- const tg = this.source_.getTileGrid();
- return tg ? tg.getMaxZoom() : 18;
- }
+ function() {
+ const tg = this.source_.getTileGrid();
+ return tg ? tg.getMaxZoom() : 18;
+ }
},
'minimumLevel': {
'get': /** @this {olcs.core.OLImageryProvider} */
- function() {
- // WARNING: Do not use the minimum level (at least until the extent is
- // properly set). Cesium assumes the minimumLevel to contain only
- // a few tiles and tries to load them all at once -- this can
- // freeze and/or crash the browser !
- return 0;
- //var tg = this.source_.getTileGrid();
- //return tg ? tg.getMinZoom() : 0;
- }
+ function() {
+ // WARNING: Do not use the minimum level (at least until the extent is
+ // properly set). Cesium assumes the minimumLevel to contain only
+ // a few tiles and tries to load them all at once -- this can
+ // freeze and/or crash the browser !
+ return 0;
+ //var tg = this.source_.getTileGrid();
+ //return tg ? tg.getMinZoom() : 0;
+ }
},
'tilingScheme': {
'get': /** @this {olcs.core.OLImageryProvider} */
- function() {return this.tilingScheme_;}
+ function() {return this.tilingScheme_;}
},
'tileDiscardPolicy': {
@@ -236,12 +269,12 @@ Object.defineProperties(OLImageryProvider.prototype, {
'errorEvent': {
'get': /** @this {olcs.core.OLImageryProvider} */
- function() {return this.errorEvent_;}
+ function() {return this.errorEvent_;}
},
'proxy': {
'get': /** @this {olcs.core.OLImageryProvider} */
- function() {return this.proxy_;}
+ function() {return this.proxy_;}
},
'hasAlphaChannel': {