Skip to content

Commit 9125bea

Browse files
Brakebeingkjohnson
andauthored
Adds support for external imagery providers in CesiumIonOverlay (#1385)
* Adds support for external imagery providers Extends CesiumIonOverlay to support external imagery providers like Google Maps and Bing Maps, fetching metadata and adjusting tile URL structures accordingly. Updates the example to showcase this new feature by adding base map options for different map providers. * update ImageOverlayPlugin based on PR review * Small cleanup * Fix lint * Separate quad key file --------- Co-authored-by: Garrett Johnson <garrett.kjohnson@gmail.com>
1 parent 0e5eab5 commit 9125bea

3 files changed

Lines changed: 139 additions & 15 deletions

File tree

example/quantMeshOverlays.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const params = {
2626
enableCacheDisplay: false,
2727
enableRendererStats: false,
2828
enableTileSplitting: true,
29-
mapBase: false,
29+
mapBase: 3954,
3030
errorTarget: 2,
3131
opacity: 1.0,
3232
color: '#ffffff',
@@ -114,7 +114,14 @@ function init() {
114114
gui.add( params, 'enableCacheDisplay' );
115115
gui.add( params, 'enableRendererStats' );
116116
gui.add( params, 'enableTileSplitting' );
117-
gui.add( params, 'mapBase' ).name( 'OpenStreetMap' ).onChange( updateBaseOverlay );
117+
gui.add( params, 'mapBase', {
118+
'Sentinel-2': 3954,
119+
OpenStreetMap: 0,
120+
'Google Maps Satellite': 3830183,
121+
'Google Maps Roadmap': 3830184,
122+
'Bing Maps Aerial': 3,
123+
'Bing Maps Road': 4,
124+
} ).name( 'Base map' ).onChange( updateBaseOverlay );
118125
gui.add( params, 'errorTarget', 1, 30, 1 );
119126

120127
const washingtonFolder = gui.addFolder( 'Washington DC Layer' );
@@ -146,7 +153,7 @@ function updateBaseOverlay() {
146153

147154
}
148155

149-
if ( params.mapBase ) {
156+
if ( params.mapBase === 0 ) {
150157

151158
baseOverlay = new XYZTilesOverlay( {
152159
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
@@ -155,7 +162,7 @@ function updateBaseOverlay() {
155162
} else {
156163

157164
baseOverlay = new CesiumIonOverlay( {
158-
assetId: '3954',
165+
assetId: params.mapBase,
159166
apiToken: import.meta.env.VITE_ION_KEY,
160167
} );
161168

src/three/plugins/images/ImageOverlayPlugin.js

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { PriorityQueue } from '3d-tiles-renderer/core';
33
import { CesiumIonAuth, GoogleCloudAuth } from '3d-tiles-renderer/core/plugins';
44
import { TiledTextureComposer } from './overlays/TiledTextureComposer.js';
55
import { XYZImageSource } from './sources/XYZImageSource.js';
6+
import { QuadKeyImageSource } from './sources/QuadKeyImageSource.js';
67
import { TMSImageSource } from './sources/TMSImageSource.js';
78
import { forEachTileInBounds, getMeshesCartographicRange, getMeshesPlanarRange } from './overlays/utils.js';
89
import { wrapOverlaysMaterial } from './overlays/wrapOverlaysMaterial.js';
@@ -969,14 +970,19 @@ export class ImageOverlayPlugin {
969970

970971
if ( ! overlay.isInitialized ) {
971972

972-
overlay.imageSource.fetchData = ( ...args ) => tiles
973-
.downloadQueue
974-
.add( { priority: - performance.now() }, () => {
973+
overlay.init();
975974

976-
return overlay.fetch( ...args );
975+
overlay.whenReady().then( () => {
977976

978-
} );
979-
overlay.init();
977+
overlay.imageSource.fetchData = ( ...args ) => tiles
978+
.downloadQueue
979+
.add( { priority: - performance.now() }, () => {
980+
981+
return overlay.fetch( ...args );
982+
983+
} );
984+
985+
} );
980986

981987
}
982988

@@ -1622,30 +1628,85 @@ export class CesiumIonOverlay extends ImageOverlay {
16221628
super( options );
16231629

16241630
const { apiToken, autoRefreshToken, assetId } = options;
1631+
this.options = options;
16251632
this.assetId = assetId;
16261633
this.auth = new CesiumIonAuth( { apiToken, autoRefreshToken } );
1627-
this.imageSource = new TMSImageSource( options );
16281634

16291635
this.auth.authURL = `https://api.cesium.com/v1/assets/${ assetId }/endpoint`;
1630-
this.imageSource.fetchData = ( ...args ) => this.fetch( ...args );
16311636
this._attributions = [];
16321637

1638+
this.externalType = false;
1639+
16331640
}
16341641

16351642
init() {
16361643

16371644
this._whenReady = this
16381645
.auth
16391646
.refreshToken()
1640-
.then( json => {
1647+
.then( async ( json ) => {
16411648

16421649
this._attributions = json.attributions.map( att => ( {
16431650
value: att.html,
16441651
type: 'html',
16451652
collapsible: att.collapsible,
16461653
} ) );
16471654

1648-
this.imageSource.url = json.url;
1655+
if ( json.type !== 'IMAGERY' ) {
1656+
1657+
throw new Error( 'CesiumIonOverlay: Only IMAGERY is supported as overlay type.' );
1658+
1659+
}
1660+
1661+
this.externalType = Boolean( json.externalType );
1662+
1663+
switch ( json.externalType ) {
1664+
1665+
case 'GOOGLE_2D_MAPS': {
1666+
1667+
const { url, session, key, tileWidth } = json.options;
1668+
const xyzUrl = `${ url }/v1/2dtiles/{z}/{x}/{y}?session=${ session }&key=${ key }`;
1669+
this.imageSource = new XYZImageSource( {
1670+
...this.options,
1671+
url: xyzUrl,
1672+
tileDimension: tileWidth,
1673+
1674+
// Google maps tiles have a fixed depth of 22
1675+
// https://developers.google.com/maps/documentation/tile/2d-tiles-overview
1676+
levels: 22,
1677+
} );
1678+
break;
1679+
1680+
}
1681+
1682+
case 'BING': {
1683+
1684+
const { url, mapStyle, key } = json.options;
1685+
const metadataUrl = `${ url }/REST/v1/Imagery/Metadata/${ mapStyle }?incl=ImageryProviders&key=${ key }&uriScheme=https`;
1686+
const response = await fetch( metadataUrl ).then( res => res.json() );
1687+
const metadata = response.resourceSets[ 0 ].resources[ 0 ];
1688+
1689+
this.imageSource = new QuadKeyImageSource( {
1690+
...this.options,
1691+
url: metadata.imageUrl,
1692+
subdomains: metadata.imageUrlSubdomains,
1693+
tileDimension: metadata.tileWidth,
1694+
levels: metadata.zoomMax,
1695+
} );
1696+
break;
1697+
1698+
}
1699+
1700+
default:
1701+
this.imageSource = new TMSImageSource( {
1702+
...this.options,
1703+
url: json.url,
1704+
} );
1705+
1706+
}
1707+
1708+
this.imageSource.fetchData = ( ...args ) => this.fetch( ...args );
1709+
16491710
return this.imageSource.init();
16501711

16511712
} );
@@ -1656,7 +1717,8 @@ export class CesiumIonOverlay extends ImageOverlay {
16561717

16571718
fetch( ...args ) {
16581719

1659-
return this.auth.fetch( ...args );
1720+
// bypass auth fetch if asset is external type to prevent CORS error due to wrong bearer token
1721+
return this.externalType ? super.fetch( ...args ) : this.auth.fetch( ...args );
16601722

16611723
}
16621724

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { XYZImageSource } from './XYZImageSource.js';
2+
3+
// Bing Maps Tile System
4+
// https://learn.microsoft.com/en-us/bingmaps/articles/bing-maps-tile-system
5+
export class QuadKeyImageSource extends XYZImageSource {
6+
7+
constructor( options = {} ) {
8+
9+
const {
10+
subdomains = [ 't0' ],
11+
...rest
12+
} = options;
13+
14+
super( rest );
15+
16+
this.subdomains = subdomains;
17+
this.subDomainIndex = 0;
18+
19+
}
20+
21+
getUrl( x, y, level ) {
22+
23+
return this.url
24+
.replace( /{\s*subdomain\s*}/gi, this._getSubdomain() )
25+
.replace( /{\s*quadkey\s*}/gi, this._tileToQuadKey( x, y, level ) );
26+
27+
}
28+
29+
_tileToQuadKey( x, y, level ) {
30+
31+
let quadKey = '';
32+
for ( let i = level; i > 0; i -- ) {
33+
34+
let digit = 0;
35+
const mask = 1 << ( i - 1 );
36+
if ( ( x & mask ) !== 0 ) digit += 1;
37+
if ( ( y & mask ) !== 0 ) digit += 2;
38+
quadKey += digit.toString();
39+
40+
}
41+
42+
return quadKey;
43+
44+
}
45+
46+
_getSubdomain() {
47+
48+
// Spread requests among different subdomains to circumvent browser URL request limits per domain
49+
// https://learn.microsoft.com/en-us/bingmaps/rest-services/directly-accessing-the-bing-maps-tiles
50+
this.subDomainIndex = ( this.subDomainIndex + 1 ) % this.subdomains.length;
51+
return this.subdomains[ this.subDomainIndex ];
52+
53+
}
54+
55+
}

0 commit comments

Comments
 (0)