From 14b874151375512d24f1311b08a0ab01d375f576 Mon Sep 17 00:00:00 2001 From: Tiffany Lu Date: Fri, 23 Oct 2015 00:11:42 -0400 Subject: [PATCH 01/32] implemented TMS in terms of UrlTemplateImageryProvider, changed TMSSpec floating point comparisons to toBeCloseTo, added async checks --- Source/Scene/TileMapServiceImageryProvider.js | 87 +++++++++---------- .../TileMapServiceImageryProviderSpec.js | 26 ++++-- 2 files changed, 59 insertions(+), 54 deletions(-) diff --git a/Source/Scene/TileMapServiceImageryProvider.js b/Source/Scene/TileMapServiceImageryProvider.js index 979af6b16c45..cdc8df06a747 100644 --- a/Source/Scene/TileMapServiceImageryProvider.js +++ b/Source/Scene/TileMapServiceImageryProvider.js @@ -15,7 +15,7 @@ define([ '../Core/TileProviderError', '../Core/WebMercatorTilingScheme', '../ThirdParty/when', - './ImageryProvider' + './UrlTemplateImageryProvider' ], function( appendForwardSlash, Cartesian2, @@ -32,7 +32,7 @@ define([ TileProviderError, WebMercatorTilingScheme, when, - ImageryProvider) { + UrlTemplateImageryProvider) { "use strict"; /** @@ -99,24 +99,11 @@ define([ this._url = url; this._ready = false; - this._proxy = options.proxy; - this._tileDiscardPolicy = options.tileDiscardPolicy; this._errorEvent = new Event(); - this._fileExtension = options.fileExtension; - this._tileWidth = options.tileWidth; - this._tileHeight = options.tileHeight; - this._minimumLevel = options.minimumLevel; - this._maximumLevel = options.maximumLevel; this._rectangle = Rectangle.clone(options.rectangle); this._tilingScheme = options.tilingScheme; - var credit = options.credit; - if (typeof credit === 'string') { - credit = new Credit(credit); - } - this._credit = credit; - var that = this; var metadataError; @@ -153,11 +140,11 @@ define([ } } - that._fileExtension = defaultValue(that._fileExtension, format.getAttribute('extension')); - that._tileWidth = defaultValue(that._tileWidth, parseInt(format.getAttribute('width'), 10)); - that._tileHeight = defaultValue(that._tileHeight, parseInt(format.getAttribute('height'), 10)); - that._minimumLevel = defaultValue(that._minimumLevel, parseInt(tilesetsList[0].getAttribute('order'), 10)); - that._maximumLevel = defaultValue(that._maximumLevel, parseInt(tilesetsList[tilesetsList.length - 1].getAttribute('order'), 10)); + that._fileExtension = defaultValue(options.fileExtension, format.getAttribute('extension')); + that._tileWidth = defaultValue(options.tileWidth, parseInt(format.getAttribute('width'), 10)); + that._tileHeight = defaultValue(options.tileHeight, parseInt(format.getAttribute('height'), 10)); + that._minimumLevel = defaultValue(options.minimumLevel, parseInt(tilesetsList[0].getAttribute('order'), 10)); + that._maximumLevel = defaultValue(options.maximumLevel, parseInt(tilesetsList[tilesetsList.length - 1].getAttribute('order'), 10)); // Determine based on the profile attribute if this tileset was generated by gdal2tiles.py ('mercator' or 'geodetic' profile, in which // case X is latitude and Y is longitude) or by a tool compliant with the TMS standard ('global-mercator' or 'global-geodetic' profile, @@ -241,6 +228,7 @@ define([ that._tilingScheme = tilingScheme; that._ready = true; + buildImageryProvider(); } function metadataFailure(error) { @@ -253,11 +241,12 @@ define([ that._tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); that._rectangle = defaultValue(options.rectangle, that._tilingScheme.rectangle); that._ready = true; + buildImageryProvider(); } function requestMetadata() { var resourceUrl = url + 'tilemapresource.xml'; - var proxy = that._proxy; + var proxy = options.proxy; if (defined(proxy)) { resourceUrl = proxy.getURL(resourceUrl); } @@ -265,21 +254,24 @@ define([ when(loadXML(resourceUrl), metadataSuccess, metadataFailure); } - requestMetadata(); - }; - - function buildImageUrl(imageryProvider, x, y, level) { - var yTiles = imageryProvider._tilingScheme.getNumberOfYTilesAtLevel(level); - var url = imageryProvider._url + level + '/' + x + '/' + (yTiles - y - 1) + '.' + imageryProvider._fileExtension; - - var proxy = imageryProvider._proxy; - if (defined(proxy)) { - url = proxy.getURL(url); + function buildImageryProvider() { + var templateUrl = url + '{z}/{x}/{reverseY}.' + that._fileExtension; + that._imageryProvider = new UrlTemplateImageryProvider({ + url : templateUrl, + tilingScheme : that._tilingScheme, + rectangle : that._rectangle, + tileWidth : that._tileWidth, + tileHeight : that._tileHeight, + minimumLevel : that._minimumLevel, + maximumLevel : that._maximumLevel, + proxy : options.proxy, + tileDiscardPolicy : options.tileDiscardPolicy, + credit: options.credit + }); } - return url; - } - + requestMetadata(); + }; defineProperties(TileMapServiceImageryProvider.prototype, { /** @@ -302,7 +294,7 @@ define([ */ proxy : { get : function() { - return this._proxy; + return this._imageryProvider.proxy; } }, @@ -321,7 +313,7 @@ define([ } //>>includeEnd('debug'); - return this._tileWidth; + return this._imageryProvider.tileWidth; } }, @@ -340,7 +332,7 @@ define([ } //>>includeEnd('debug'); - return this._tileHeight; + return this._imageryProvider.tileHeight; } }, @@ -359,7 +351,7 @@ define([ } //>>includeEnd('debug'); - return this._maximumLevel; + return this._imageryProvider.maximumLevel; } }, @@ -378,7 +370,7 @@ define([ } //>>includeEnd('debug'); - return this._minimumLevel; + return this._imageryProvider.minimumLevel; } }, @@ -397,7 +389,7 @@ define([ } //>>includeEnd('debug'); - return this._tilingScheme; + return this._imageryProvider.tilingScheme; } }, @@ -416,7 +408,7 @@ define([ } //>>includeEnd('debug'); - return this._rectangle; + return this._imageryProvider.rectangle; } }, @@ -437,7 +429,7 @@ define([ } //>>includeEnd('debug'); - return this._tileDiscardPolicy; + return this._imageryProvider.tileDiscardPolicy; } }, @@ -476,7 +468,13 @@ define([ */ credit : { get : function() { - return this._credit; + //>>includeStart('debug', pragmas.debug); + if (!this._ready) { + throw new DeveloperError('credit must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + + return this._imageryProvider.credit; } }, @@ -530,8 +528,7 @@ define([ } //>>includeEnd('debug'); - var url = buildImageUrl(this, x, y, level); - return ImageryProvider.loadImage(this, url); + return this._imageryProvider.requestImage(x, y, level); }; /** diff --git a/Specs/Scene/TileMapServiceImageryProviderSpec.js b/Specs/Scene/TileMapServiceImageryProviderSpec.js index 06845062e95f..491b4f86133f 100644 --- a/Specs/Scene/TileMapServiceImageryProviderSpec.js +++ b/Specs/Scene/TileMapServiceImageryProviderSpec.js @@ -146,7 +146,11 @@ defineSuite([ var provider = new TileMapServiceImageryProvider({ url : 'made/up/tms/server' }); - expect(provider.credit).toBeUndefined(); + return pollToPromise(function() { + return provider.ready; + }).then(function() { + expect(provider.credit).toBeUndefined(); + }); }); it('turns the supplied credit into a logo', function() { @@ -154,7 +158,11 @@ defineSuite([ url : 'made/up/gms/server', credit : 'Thanks to our awesome made up source of this imagery!' }); - expect(providerWithCredit.credit).toBeDefined(); + return pollToPromise(function() { + return providerWithCredit.ready; + }).then(function() { + expect(providerWithCredit.credit).toBeDefined(); + }); }); it('routes resource request through a proxy if one is specified', function() { @@ -459,7 +467,7 @@ defineSuite([ expect(provider.rectangle.west).toEqual(expectedSW.longitude); expect(provider.rectangle.south).toEqual(expectedSW.latitude); - expect(provider.rectangle.east).toEqual(expectedNE.longitude); + expect(provider.rectangle.east).toBeCloseTo(expectedNE.longitude, 0.00000000001); expect(provider.rectangle.north).toEqual(expectedNE.latitude); }); }); @@ -498,9 +506,9 @@ defineSuite([ var expectedSW = Cartographic.fromDegrees(-123.0, -10.0); var expectedNE = Cartographic.fromDegrees(-110.0, 11.0); - expect(provider.rectangle.west).toEqual(expectedSW.longitude); + expect(provider.rectangle.west).toBeCloseTo(expectedSW.longitude, 0.00000000001); expect(provider.rectangle.south).toEqual(expectedSW.latitude); - expect(provider.rectangle.east).toEqual(expectedNE.longitude); + expect(provider.rectangle.east).toBeCloseTo(expectedNE.longitude, 0.00000000001); expect(provider.rectangle.north).toEqual(expectedNE.latitude); }); }); @@ -539,9 +547,9 @@ defineSuite([ var expectedSW = Cartographic.fromDegrees(-123.0, -10.0); var expectedNE = Cartographic.fromDegrees(-110.0, 11.0); - expect(provider.rectangle.west).toEqual(expectedSW.longitude); + expect(provider.rectangle.west).toBeCloseTo(expectedSW.longitude, 0.00000000001); expect(provider.rectangle.south).toEqual(expectedSW.latitude); - expect(provider.rectangle.east).toEqual(expectedNE.longitude); + expect(provider.rectangle.east).toBeCloseTo(expectedNE.longitude, 0.00000000001); expect(provider.rectangle.north).toEqual(expectedNE.latitude); }); }); @@ -580,9 +588,9 @@ defineSuite([ var expectedSW = Cartographic.fromDegrees(-123.0, -10.0); var expectedNE = Cartographic.fromDegrees(-110.0, 11.0); - expect(provider.rectangle.west).toEqual(expectedSW.longitude); + expect(provider.rectangle.west).toBeCloseTo(expectedSW.longitude, 0.00000000001); expect(provider.rectangle.south).toEqual(expectedSW.latitude); - expect(provider.rectangle.east).toEqual(expectedNE.longitude); + expect(provider.rectangle.east).toBeCloseTo(expectedNE.longitude, 0.00000000001); expect(provider.rectangle.north).toEqual(expectedNE.latitude); }); }); From 680b0c820aa242fe184f19e276a1ad27f98ab160 Mon Sep 17 00:00:00 2001 From: Tiffany Lu Date: Fri, 30 Oct 2015 00:11:13 -0400 Subject: [PATCH 02/32] construct UrlTemplateImageryProvider from local variables --- Source/Scene/TileMapServiceImageryProvider.js | 164 +++++++----------- 1 file changed, 62 insertions(+), 102 deletions(-) diff --git a/Source/Scene/TileMapServiceImageryProvider.js b/Source/Scene/TileMapServiceImageryProvider.js index cdc8df06a747..b1cf72cfdf89 100644 --- a/Source/Scene/TileMapServiceImageryProvider.js +++ b/Source/Scene/TileMapServiceImageryProvider.js @@ -101,9 +101,6 @@ define([ this._ready = false; this._errorEvent = new Event(); - this._rectangle = Rectangle.clone(options.rectangle); - this._tilingScheme = options.tilingScheme; - var that = this; var metadataError; @@ -140,11 +137,11 @@ define([ } } - that._fileExtension = defaultValue(options.fileExtension, format.getAttribute('extension')); - that._tileWidth = defaultValue(options.tileWidth, parseInt(format.getAttribute('width'), 10)); - that._tileHeight = defaultValue(options.tileHeight, parseInt(format.getAttribute('height'), 10)); - that._minimumLevel = defaultValue(options.minimumLevel, parseInt(tilesetsList[0].getAttribute('order'), 10)); - that._maximumLevel = defaultValue(options.maximumLevel, parseInt(tilesetsList[tilesetsList.length - 1].getAttribute('order'), 10)); + var fileExtension = defaultValue(options.fileExtension, format.getAttribute('extension')); + var tileWidth = defaultValue(options.tileWidth, parseInt(format.getAttribute('width'), 10)); + var tileHeight = defaultValue(options.tileHeight, parseInt(format.getAttribute('height'), 10)); + var minimumLevel = defaultValue(options.minimumLevel, parseInt(tilesetsList[0].getAttribute('order'), 10)); + var maximumLevel = defaultValue(options.maximumLevel, parseInt(tilesetsList[tilesetsList.length - 1].getAttribute('order'), 10)); // Determine based on the profile attribute if this tileset was generated by gdal2tiles.py ('mercator' or 'geodetic' profile, in which // case X is latitude and Y is longitude) or by a tool compliant with the TMS standard ('global-mercator' or 'global-geodetic' profile, @@ -156,11 +153,13 @@ define([ flipXY = true; } - if (!defined(that._tilingScheme)) { + var tilingScheme = options.tilingScheme; + + if (!defined(tilingScheme)) { if (tilingSchemeName === 'geodetic' || tilingSchemeName === 'global-geodetic') { - that._tilingScheme = new GeographicTilingScheme({ ellipsoid : options.ellipsoid }); + tilingScheme = new GeographicTilingScheme({ ellipsoid : options.ellipsoid }); } else if (tilingSchemeName === 'mercator' || tilingSchemeName === 'global-mercator') { - that._tilingScheme = new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); + tilingScheme = new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); } else { var message = url + 'tilemapresource.xml specifies an unsupported profile attribute, ' + tilingSchemeName + '.'; metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); @@ -168,10 +167,10 @@ define([ } } - var tilingScheme = that._tilingScheme; - // rectangle handling - if (!defined(that._rectangle)) { + var rectangle = Rectangle.clone(options.rectangle); + + if (!defined(rectangle)) { var swXY; var neXY; var sw; @@ -188,60 +187,85 @@ define([ swXY = new Cartesian2(parseFloat(bbox.getAttribute('minx')), parseFloat(bbox.getAttribute('miny'))); neXY = new Cartesian2(parseFloat(bbox.getAttribute('maxx')), parseFloat(bbox.getAttribute('maxy'))); - if (that._tilingScheme instanceof GeographicTilingScheme) { + if (tilingScheme instanceof GeographicTilingScheme) { sw = Cartographic.fromDegrees(swXY.x, swXY.y); ne = Cartographic.fromDegrees(neXY.x, neXY.y); } else { - var projection = that._tilingScheme.projection; + var projection = tilingScheme.projection; sw = projection.unproject(swXY); ne = projection.unproject(neXY); } } - that._rectangle = new Rectangle(sw.longitude, sw.latitude, ne.longitude, ne.latitude); + rectangle = new Rectangle(sw.longitude, sw.latitude, ne.longitude, ne.latitude); } // The rectangle must not be outside the bounds allowed by the tiling scheme. - if (that._rectangle.west < tilingScheme.rectangle.west) { - that._rectangle.west = tilingScheme.rectangle.west; + if (rectangle.west < tilingScheme.rectangle.west) { + rectangle.west = tilingScheme.rectangle.west; } - if (that._rectangle.east > tilingScheme.rectangle.east) { - that._rectangle.east = tilingScheme.rectangle.east; + if (rectangle.east > tilingScheme.rectangle.east) { + rectangle.east = tilingScheme.rectangle.east; } - if (that._rectangle.south < tilingScheme.rectangle.south) { - that._rectangle.south = tilingScheme.rectangle.south; + if (rectangle.south < tilingScheme.rectangle.south) { + rectangle.south = tilingScheme.rectangle.south; } - if (that._rectangle.north > tilingScheme.rectangle.north) { - that._rectangle.north = tilingScheme.rectangle.north; + if (rectangle.north > tilingScheme.rectangle.north) { + rectangle.north = tilingScheme.rectangle.north; } // Check the number of tiles at the minimum level. If it's more than four, // try requesting the lower levels anyway, because starting at the higher minimum // level will cause too many tiles to be downloaded and rendered. - var swTile = tilingScheme.positionToTileXY(Rectangle.southwest(that._rectangle), that._minimumLevel); - var neTile = tilingScheme.positionToTileXY(Rectangle.northeast(that._rectangle), that._minimumLevel); + var swTile = tilingScheme.positionToTileXY(Rectangle.southwest(rectangle), minimumLevel); + var neTile = tilingScheme.positionToTileXY(Rectangle.northeast(rectangle), minimumLevel); var tileCount = (Math.abs(neTile.x - swTile.x) + 1) * (Math.abs(neTile.y - swTile.y) + 1); if (tileCount > 4) { - that._minimumLevel = 0; + minimumLevel = 0; } - that._tilingScheme = tilingScheme; that._ready = true; - buildImageryProvider(); + + var templateUrl = url + '{z}/{x}/{reverseY}.' + fileExtension; + that._imageryProvider = new UrlTemplateImageryProvider({ + url : templateUrl, + tilingScheme : tilingScheme, + rectangle : rectangle, + tileWidth : tileWidth, + tileHeight : tileHeight, + minimumLevel : minimumLevel, + maximumLevel : maximumLevel, + proxy : options.proxy, + tileDiscardPolicy : options.tileDiscardPolicy, + credit: options.credit + }); } function metadataFailure(error) { // Can't load XML, still allow options and defaults - that._fileExtension = defaultValue(options.fileExtension, 'png'); - that._tileWidth = defaultValue(options.tileWidth, 256); - that._tileHeight = defaultValue(options.tileHeight, 256); - that._minimumLevel = defaultValue(options.minimumLevel, 0); - that._maximumLevel = options.maximumLevel; - that._tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); - that._rectangle = defaultValue(options.rectangle, that._tilingScheme.rectangle); + var fileExtension = defaultValue(options.fileExtension, 'png'); + var tileWidth = defaultValue(options.tileWidth, 256); + var tileHeight = defaultValue(options.tileHeight, 256); + var minimumLevel = defaultValue(options.minimumLevel, 0); + var maximumLevel = options.maximumLevel; + var tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); + var rectangle = defaultValue(options.rectangle, tilingScheme.rectangle); that._ready = true; - buildImageryProvider(); + + var templateUrl = url + '{z}/{x}/{reverseY}.' + fileExtension; + that._imageryProvider = new UrlTemplateImageryProvider({ + url : templateUrl, + tilingScheme : tilingScheme, + rectangle : rectangle, + tileWidth : tileWidth, + tileHeight : tileHeight, + minimumLevel : minimumLevel, + maximumLevel : maximumLevel, + proxy : options.proxy, + tileDiscardPolicy : options.tileDiscardPolicy, + credit: options.credit + }); } function requestMetadata() { @@ -254,22 +278,6 @@ define([ when(loadXML(resourceUrl), metadataSuccess, metadataFailure); } - function buildImageryProvider() { - var templateUrl = url + '{z}/{x}/{reverseY}.' + that._fileExtension; - that._imageryProvider = new UrlTemplateImageryProvider({ - url : templateUrl, - tilingScheme : that._tilingScheme, - rectangle : that._rectangle, - tileWidth : that._tileWidth, - tileHeight : that._tileHeight, - minimumLevel : that._minimumLevel, - maximumLevel : that._maximumLevel, - proxy : options.proxy, - tileDiscardPolicy : options.tileDiscardPolicy, - credit: options.credit - }); - } - requestMetadata(); }; @@ -307,12 +315,6 @@ define([ */ tileWidth : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - return this._imageryProvider.tileWidth; } }, @@ -326,12 +328,6 @@ define([ */ tileHeight: { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - return this._imageryProvider.tileHeight; } }, @@ -345,12 +341,6 @@ define([ */ maximumLevel : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - return this._imageryProvider.maximumLevel; } }, @@ -364,12 +354,6 @@ define([ */ minimumLevel : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - return this._imageryProvider.minimumLevel; } }, @@ -383,12 +367,6 @@ define([ */ tilingScheme : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - return this._imageryProvider.tilingScheme; } }, @@ -402,12 +380,6 @@ define([ */ rectangle : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('rectangle must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - return this._imageryProvider.rectangle; } }, @@ -423,12 +395,6 @@ define([ */ tileDiscardPolicy : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - return this._imageryProvider.tileDiscardPolicy; } }, @@ -468,12 +434,6 @@ define([ */ credit : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('credit must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - return this._imageryProvider.credit; } }, From 1c80bdd8ce509f9d14215930ab2b867c9b329af8 Mon Sep 17 00:00:00 2001 From: Tiffany Lu Date: Fri, 30 Oct 2015 01:46:54 -0400 Subject: [PATCH 03/32] moved TMSSpec changes to a separate branch (tmsSpec) --- .../TileMapServiceImageryProviderSpec.js | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/Specs/Scene/TileMapServiceImageryProviderSpec.js b/Specs/Scene/TileMapServiceImageryProviderSpec.js index 491b4f86133f..2eb396bb6f6b 100644 --- a/Specs/Scene/TileMapServiceImageryProviderSpec.js +++ b/Specs/Scene/TileMapServiceImageryProviderSpec.js @@ -114,6 +114,28 @@ defineSuite([ }); }); + it('supports a query string at the end of the URL', function() { + var provider = new TileMapServiceImageryProvider({ + url : 'made/up/tms/server/?a=some&b=query' + }); + + return pollToPromise(function() { + return provider.ready; + }).then(function() { + spyOn(loadImage, 'createImage').and.callFake(function(url, crossOrigin, deferred) { + expect(url).not.toContain('//'); + + // Just return any old image. + loadImage.defaultCreateImage('Data/Images/Red16x16.png', crossOrigin, deferred); + }); + + return provider.requestImage(0, 0, 0).then(function(image) { + expect(loadImage.createImage).toHaveBeenCalled(); + expect(image).toBeInstanceOf(Image); + }); + }); + }); + it('requestImage returns a promise for an image and loads it for cross-origin use', function() { var provider = new TileMapServiceImageryProvider({ url : 'made/up/tms/server/' @@ -146,11 +168,7 @@ defineSuite([ var provider = new TileMapServiceImageryProvider({ url : 'made/up/tms/server' }); - return pollToPromise(function() { - return provider.ready; - }).then(function() { - expect(provider.credit).toBeUndefined(); - }); + expect(provider.credit).toBeUndefined(); }); it('turns the supplied credit into a logo', function() { @@ -158,11 +176,7 @@ defineSuite([ url : 'made/up/gms/server', credit : 'Thanks to our awesome made up source of this imagery!' }); - return pollToPromise(function() { - return providerWithCredit.ready; - }).then(function() { - expect(providerWithCredit.credit).toBeDefined(); - }); + expect(providerWithCredit.credit).toBeDefined(); }); it('routes resource request through a proxy if one is specified', function() { @@ -467,7 +481,7 @@ defineSuite([ expect(provider.rectangle.west).toEqual(expectedSW.longitude); expect(provider.rectangle.south).toEqual(expectedSW.latitude); - expect(provider.rectangle.east).toBeCloseTo(expectedNE.longitude, 0.00000000001); + expect(provider.rectangle.east).toEqual(expectedNE.longitude); expect(provider.rectangle.north).toEqual(expectedNE.latitude); }); }); @@ -506,9 +520,9 @@ defineSuite([ var expectedSW = Cartographic.fromDegrees(-123.0, -10.0); var expectedNE = Cartographic.fromDegrees(-110.0, 11.0); - expect(provider.rectangle.west).toBeCloseTo(expectedSW.longitude, 0.00000000001); + expect(provider.rectangle.west).toEqual(expectedSW.longitude); expect(provider.rectangle.south).toEqual(expectedSW.latitude); - expect(provider.rectangle.east).toBeCloseTo(expectedNE.longitude, 0.00000000001); + expect(provider.rectangle.east).toEqual(expectedNE.longitude); expect(provider.rectangle.north).toEqual(expectedNE.latitude); }); }); @@ -547,9 +561,9 @@ defineSuite([ var expectedSW = Cartographic.fromDegrees(-123.0, -10.0); var expectedNE = Cartographic.fromDegrees(-110.0, 11.0); - expect(provider.rectangle.west).toBeCloseTo(expectedSW.longitude, 0.00000000001); + expect(provider.rectangle.west).toEqual(expectedSW.longitude); expect(provider.rectangle.south).toEqual(expectedSW.latitude); - expect(provider.rectangle.east).toBeCloseTo(expectedNE.longitude, 0.00000000001); + expect(provider.rectangle.east).toEqual(expectedNE.longitude); expect(provider.rectangle.north).toEqual(expectedNE.latitude); }); }); @@ -588,9 +602,9 @@ defineSuite([ var expectedSW = Cartographic.fromDegrees(-123.0, -10.0); var expectedNE = Cartographic.fromDegrees(-110.0, 11.0); - expect(provider.rectangle.west).toBeCloseTo(expectedSW.longitude, 0.00000000001); + expect(provider.rectangle.west).toEqual(expectedSW.longitude); expect(provider.rectangle.south).toEqual(expectedSW.latitude); - expect(provider.rectangle.east).toBeCloseTo(expectedNE.longitude, 0.00000000001); + expect(provider.rectangle.east).toEqual(expectedNE.longitude); expect(provider.rectangle.north).toEqual(expectedNE.latitude); }); }); From 2dff53a9ed29a95095a16c8e2088fe1aff48eed2 Mon Sep 17 00:00:00 2001 From: Tiffany Lu Date: Fri, 30 Oct 2015 02:05:54 -0400 Subject: [PATCH 04/32] rebased onto master --- Source/Scene/TileMapServiceImageryProvider.js | 203 +++++++----------- 1 file changed, 80 insertions(+), 123 deletions(-) diff --git a/Source/Scene/TileMapServiceImageryProvider.js b/Source/Scene/TileMapServiceImageryProvider.js index c2fac96f305c..b1cf72cfdf89 100644 --- a/Source/Scene/TileMapServiceImageryProvider.js +++ b/Source/Scene/TileMapServiceImageryProvider.js @@ -1,5 +1,6 @@ /*global define*/ define([ + '../Core/appendForwardSlash', '../Core/Cartesian2', '../Core/Cartographic', '../Core/Credit', @@ -9,14 +10,14 @@ define([ '../Core/DeveloperError', '../Core/Event', '../Core/GeographicTilingScheme', - '../Core/joinUrls', '../Core/loadXML', '../Core/Rectangle', '../Core/TileProviderError', '../Core/WebMercatorTilingScheme', '../ThirdParty/when', - './ImageryProvider' + './UrlTemplateImageryProvider' ], function( + appendForwardSlash, Cartesian2, Cartographic, Credit, @@ -26,13 +27,12 @@ define([ DeveloperError, Event, GeographicTilingScheme, - joinUrls, loadXML, Rectangle, TileProviderError, WebMercatorTilingScheme, when, - ImageryProvider) { + UrlTemplateImageryProvider) { "use strict"; /** @@ -95,28 +95,12 @@ define([ } //>>includeEnd('debug'); - var url = options.url; + var url = appendForwardSlash(options.url); this._url = url; this._ready = false; - this._proxy = options.proxy; - this._tileDiscardPolicy = options.tileDiscardPolicy; this._errorEvent = new Event(); - this._fileExtension = options.fileExtension; - this._tileWidth = options.tileWidth; - this._tileHeight = options.tileHeight; - this._minimumLevel = options.minimumLevel; - this._maximumLevel = options.maximumLevel; - this._rectangle = Rectangle.clone(options.rectangle); - this._tilingScheme = options.tilingScheme; - - var credit = options.credit; - if (typeof credit === 'string') { - credit = new Credit(credit); - } - this._credit = credit; - var that = this; var metadataError; @@ -153,11 +137,11 @@ define([ } } - that._fileExtension = defaultValue(that._fileExtension, format.getAttribute('extension')); - that._tileWidth = defaultValue(that._tileWidth, parseInt(format.getAttribute('width'), 10)); - that._tileHeight = defaultValue(that._tileHeight, parseInt(format.getAttribute('height'), 10)); - that._minimumLevel = defaultValue(that._minimumLevel, parseInt(tilesetsList[0].getAttribute('order'), 10)); - that._maximumLevel = defaultValue(that._maximumLevel, parseInt(tilesetsList[tilesetsList.length - 1].getAttribute('order'), 10)); + var fileExtension = defaultValue(options.fileExtension, format.getAttribute('extension')); + var tileWidth = defaultValue(options.tileWidth, parseInt(format.getAttribute('width'), 10)); + var tileHeight = defaultValue(options.tileHeight, parseInt(format.getAttribute('height'), 10)); + var minimumLevel = defaultValue(options.minimumLevel, parseInt(tilesetsList[0].getAttribute('order'), 10)); + var maximumLevel = defaultValue(options.maximumLevel, parseInt(tilesetsList[tilesetsList.length - 1].getAttribute('order'), 10)); // Determine based on the profile attribute if this tileset was generated by gdal2tiles.py ('mercator' or 'geodetic' profile, in which // case X is latitude and Y is longitude) or by a tool compliant with the TMS standard ('global-mercator' or 'global-geodetic' profile, @@ -169,22 +153,24 @@ define([ flipXY = true; } - if (!defined(that._tilingScheme)) { + var tilingScheme = options.tilingScheme; + + if (!defined(tilingScheme)) { if (tilingSchemeName === 'geodetic' || tilingSchemeName === 'global-geodetic') { - that._tilingScheme = new GeographicTilingScheme({ ellipsoid : options.ellipsoid }); + tilingScheme = new GeographicTilingScheme({ ellipsoid : options.ellipsoid }); } else if (tilingSchemeName === 'mercator' || tilingSchemeName === 'global-mercator') { - that._tilingScheme = new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); + tilingScheme = new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); } else { - var message = joinUrls(url, 'tilemapresource.xml') + 'specifies an unsupported profile attribute, ' + tilingSchemeName + '.'; + var message = url + 'tilemapresource.xml specifies an unsupported profile attribute, ' + tilingSchemeName + '.'; metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); return; } } - var tilingScheme = that._tilingScheme; - // rectangle handling - if (!defined(that._rectangle)) { + var rectangle = Rectangle.clone(options.rectangle); + + if (!defined(rectangle)) { var swXY; var neXY; var sw; @@ -201,63 +187,90 @@ define([ swXY = new Cartesian2(parseFloat(bbox.getAttribute('minx')), parseFloat(bbox.getAttribute('miny'))); neXY = new Cartesian2(parseFloat(bbox.getAttribute('maxx')), parseFloat(bbox.getAttribute('maxy'))); - if (that._tilingScheme instanceof GeographicTilingScheme) { + if (tilingScheme instanceof GeographicTilingScheme) { sw = Cartographic.fromDegrees(swXY.x, swXY.y); ne = Cartographic.fromDegrees(neXY.x, neXY.y); } else { - var projection = that._tilingScheme.projection; + var projection = tilingScheme.projection; sw = projection.unproject(swXY); ne = projection.unproject(neXY); } } - that._rectangle = new Rectangle(sw.longitude, sw.latitude, ne.longitude, ne.latitude); + rectangle = new Rectangle(sw.longitude, sw.latitude, ne.longitude, ne.latitude); } // The rectangle must not be outside the bounds allowed by the tiling scheme. - if (that._rectangle.west < tilingScheme.rectangle.west) { - that._rectangle.west = tilingScheme.rectangle.west; + if (rectangle.west < tilingScheme.rectangle.west) { + rectangle.west = tilingScheme.rectangle.west; } - if (that._rectangle.east > tilingScheme.rectangle.east) { - that._rectangle.east = tilingScheme.rectangle.east; + if (rectangle.east > tilingScheme.rectangle.east) { + rectangle.east = tilingScheme.rectangle.east; } - if (that._rectangle.south < tilingScheme.rectangle.south) { - that._rectangle.south = tilingScheme.rectangle.south; + if (rectangle.south < tilingScheme.rectangle.south) { + rectangle.south = tilingScheme.rectangle.south; } - if (that._rectangle.north > tilingScheme.rectangle.north) { - that._rectangle.north = tilingScheme.rectangle.north; + if (rectangle.north > tilingScheme.rectangle.north) { + rectangle.north = tilingScheme.rectangle.north; } // Check the number of tiles at the minimum level. If it's more than four, // try requesting the lower levels anyway, because starting at the higher minimum // level will cause too many tiles to be downloaded and rendered. - var swTile = tilingScheme.positionToTileXY(Rectangle.southwest(that._rectangle), that._minimumLevel); - var neTile = tilingScheme.positionToTileXY(Rectangle.northeast(that._rectangle), that._minimumLevel); + var swTile = tilingScheme.positionToTileXY(Rectangle.southwest(rectangle), minimumLevel); + var neTile = tilingScheme.positionToTileXY(Rectangle.northeast(rectangle), minimumLevel); var tileCount = (Math.abs(neTile.x - swTile.x) + 1) * (Math.abs(neTile.y - swTile.y) + 1); if (tileCount > 4) { - that._minimumLevel = 0; + minimumLevel = 0; } - that._tilingScheme = tilingScheme; that._ready = true; + + var templateUrl = url + '{z}/{x}/{reverseY}.' + fileExtension; + that._imageryProvider = new UrlTemplateImageryProvider({ + url : templateUrl, + tilingScheme : tilingScheme, + rectangle : rectangle, + tileWidth : tileWidth, + tileHeight : tileHeight, + minimumLevel : minimumLevel, + maximumLevel : maximumLevel, + proxy : options.proxy, + tileDiscardPolicy : options.tileDiscardPolicy, + credit: options.credit + }); } function metadataFailure(error) { // Can't load XML, still allow options and defaults - that._fileExtension = defaultValue(options.fileExtension, 'png'); - that._tileWidth = defaultValue(options.tileWidth, 256); - that._tileHeight = defaultValue(options.tileHeight, 256); - that._minimumLevel = defaultValue(options.minimumLevel, 0); - that._maximumLevel = options.maximumLevel; - that._tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); - that._rectangle = defaultValue(options.rectangle, that._tilingScheme.rectangle); + var fileExtension = defaultValue(options.fileExtension, 'png'); + var tileWidth = defaultValue(options.tileWidth, 256); + var tileHeight = defaultValue(options.tileHeight, 256); + var minimumLevel = defaultValue(options.minimumLevel, 0); + var maximumLevel = options.maximumLevel; + var tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); + var rectangle = defaultValue(options.rectangle, tilingScheme.rectangle); that._ready = true; + + var templateUrl = url + '{z}/{x}/{reverseY}.' + fileExtension; + that._imageryProvider = new UrlTemplateImageryProvider({ + url : templateUrl, + tilingScheme : tilingScheme, + rectangle : rectangle, + tileWidth : tileWidth, + tileHeight : tileHeight, + minimumLevel : minimumLevel, + maximumLevel : maximumLevel, + proxy : options.proxy, + tileDiscardPolicy : options.tileDiscardPolicy, + credit: options.credit + }); } function requestMetadata() { - var resourceUrl = joinUrls(url, 'tilemapresource.xml'); - var proxy = that._proxy; + var resourceUrl = url + 'tilemapresource.xml'; + var proxy = options.proxy; if (defined(proxy)) { resourceUrl = proxy.getURL(resourceUrl); } @@ -268,19 +281,6 @@ define([ requestMetadata(); }; - function buildImageUrl(imageryProvider, x, y, level) { - var yTiles = imageryProvider._tilingScheme.getNumberOfYTilesAtLevel(level); - var url = joinUrls(imageryProvider._url, level + '/' + x + '/' + (yTiles - y - 1) + '.' + imageryProvider._fileExtension); - - var proxy = imageryProvider._proxy; - if (defined(proxy)) { - url = proxy.getURL(url); - } - - return url; - } - - defineProperties(TileMapServiceImageryProvider.prototype, { /** * Gets the URL of the service hosting the imagery. @@ -302,7 +302,7 @@ define([ */ proxy : { get : function() { - return this._proxy; + return this._imageryProvider.proxy; } }, @@ -315,13 +315,7 @@ define([ */ tileWidth : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._tileWidth; + return this._imageryProvider.tileWidth; } }, @@ -334,13 +328,7 @@ define([ */ tileHeight: { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._tileHeight; + return this._imageryProvider.tileHeight; } }, @@ -353,13 +341,7 @@ define([ */ maximumLevel : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._maximumLevel; + return this._imageryProvider.maximumLevel; } }, @@ -372,13 +354,7 @@ define([ */ minimumLevel : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._minimumLevel; + return this._imageryProvider.minimumLevel; } }, @@ -391,13 +367,7 @@ define([ */ tilingScheme : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._tilingScheme; + return this._imageryProvider.tilingScheme; } }, @@ -410,13 +380,7 @@ define([ */ rectangle : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('rectangle must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._rectangle; + return this._imageryProvider.rectangle; } }, @@ -431,13 +395,7 @@ define([ */ tileDiscardPolicy : { get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._tileDiscardPolicy; + return this._imageryProvider.tileDiscardPolicy; } }, @@ -476,7 +434,7 @@ define([ */ credit : { get : function() { - return this._credit; + return this._imageryProvider.credit; } }, @@ -530,8 +488,7 @@ define([ } //>>includeEnd('debug'); - var url = buildImageUrl(this, x, y, level); - return ImageryProvider.loadImage(this, url); + return this._imageryProvider.requestImage(x, y, level); }; /** From 49cba9c225554069cfacc09e84f5aea9afb8ae5b Mon Sep 17 00:00:00 2001 From: Tiffany Lu Date: Fri, 23 Oct 2015 00:11:42 -0400 Subject: [PATCH 05/32] implemented TMS in terms of UrlTemplateImageryProvider, changed TMSSpec floating point comparisons to toBeCloseTo, added async checks --- Source/Scene/TileMapServiceImageryProvider.js | 408 ++++-------------- Source/Scene/UrlTemplateImageryProvider.js | 165 +++++-- 2 files changed, 196 insertions(+), 377 deletions(-) diff --git a/Source/Scene/TileMapServiceImageryProvider.js b/Source/Scene/TileMapServiceImageryProvider.js index 8233fcb7a975..2ab55f3274d2 100644 --- a/Source/Scene/TileMapServiceImageryProvider.js +++ b/Source/Scene/TileMapServiceImageryProvider.js @@ -1,5 +1,6 @@ /*global define*/ define([ + '../Core/appendForwardSlash', '../Core/Cartesian2', '../Core/Cartographic', '../Core/Credit', @@ -9,15 +10,15 @@ define([ '../Core/DeveloperError', '../Core/Event', '../Core/GeographicTilingScheme', - '../Core/joinUrls', '../Core/loadXML', '../Core/Rectangle', '../Core/RuntimeError', '../Core/TileProviderError', '../Core/WebMercatorTilingScheme', '../ThirdParty/when', - './ImageryProvider' + './UrlTemplateImageryProvider' ], function( + appendForwardSlash, Cartesian2, Cartographic, Credit, @@ -27,14 +28,13 @@ define([ DeveloperError, Event, GeographicTilingScheme, - joinUrls, loadXML, Rectangle, RuntimeError, TileProviderError, WebMercatorTilingScheme, when, - ImageryProvider) { + UrlTemplateImageryProvider) { "use strict"; /** @@ -97,28 +97,13 @@ define([ } //>>includeEnd('debug'); - var url = options.url; - + var url = appendForwardSlash(options.url); this._url = url; - this._ready = false; this._readyPromise = when.defer(); - this._proxy = options.proxy; - this._tileDiscardPolicy = options.tileDiscardPolicy; - this._errorEvent = new Event(); - - this._fileExtension = options.fileExtension; - this._tileWidth = options.tileWidth; - this._tileHeight = options.tileHeight; - this._minimumLevel = options.minimumLevel; - this._maximumLevel = options.maximumLevel; - this._rectangle = Rectangle.clone(options.rectangle); - this._tilingScheme = options.tilingScheme; - var credit = options.credit; - if (typeof credit === 'string') { - credit = new Credit(credit); - } - this._credit = credit; + var imageryProvider = new UrlTemplateImageryProvider({ + deferReadiness: true + }); var that = this; var metadataError; @@ -156,11 +141,11 @@ define([ } } - that._fileExtension = defaultValue(that._fileExtension, format.getAttribute('extension')); - that._tileWidth = defaultValue(that._tileWidth, parseInt(format.getAttribute('width'), 10)); - that._tileHeight = defaultValue(that._tileHeight, parseInt(format.getAttribute('height'), 10)); - that._minimumLevel = defaultValue(that._minimumLevel, parseInt(tilesetsList[0].getAttribute('order'), 10)); - that._maximumLevel = defaultValue(that._maximumLevel, parseInt(tilesetsList[tilesetsList.length - 1].getAttribute('order'), 10)); + var fileExtension = defaultValue(options.fileExtension, format.getAttribute('extension')); + var tileWidth = defaultValue(options.tileWidth, parseInt(format.getAttribute('width'), 10)); + var tileHeight = defaultValue(options.tileHeight, parseInt(format.getAttribute('height'), 10)); + var minimumLevel = defaultValue(options.minimumLevel, parseInt(tilesetsList[0].getAttribute('order'), 10)); + var maximumLevel = defaultValue(options.maximumLevel, parseInt(tilesetsList[tilesetsList.length - 1].getAttribute('order'), 10)); // Determine based on the profile attribute if this tileset was generated by gdal2tiles.py ('mercator' or 'geodetic' profile, in which // case X is latitude and Y is longitude) or by a tool compliant with the TMS standard ('global-mercator' or 'global-geodetic' profile, @@ -172,23 +157,25 @@ define([ flipXY = true; } - if (!defined(that._tilingScheme)) { + var tilingScheme = options.tilingScheme; + + if (!defined(tilingScheme)) { if (tilingSchemeName === 'geodetic' || tilingSchemeName === 'global-geodetic') { - that._tilingScheme = new GeographicTilingScheme({ ellipsoid : options.ellipsoid }); + tilingScheme = new GeographicTilingScheme({ ellipsoid : options.ellipsoid }); } else if (tilingSchemeName === 'mercator' || tilingSchemeName === 'global-mercator') { - that._tilingScheme = new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); + tilingScheme = new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); } else { var message = joinUrls(url, 'tilemapresource.xml') + 'specifies an unsupported profile attribute, ' + tilingSchemeName + '.'; - metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); + metadataError = TileProviderError.handleError(metadataError, imageryProvider, imageryProvider.errorEvent, message, undefined, undefined, undefined, requestMetadata); that._readyPromise.reject(new RuntimeError(message)); return; } } - var tilingScheme = that._tilingScheme; - // rectangle handling - if (!defined(that._rectangle)) { + var rectangle = Rectangle.clone(options.rectangle); + + if (!defined(rectangle)) { var swXY; var neXY; var sw; @@ -205,65 +192,89 @@ define([ swXY = new Cartesian2(parseFloat(bbox.getAttribute('minx')), parseFloat(bbox.getAttribute('miny'))); neXY = new Cartesian2(parseFloat(bbox.getAttribute('maxx')), parseFloat(bbox.getAttribute('maxy'))); - if (that._tilingScheme instanceof GeographicTilingScheme) { + if (tilingScheme instanceof GeographicTilingScheme) { sw = Cartographic.fromDegrees(swXY.x, swXY.y); ne = Cartographic.fromDegrees(neXY.x, neXY.y); } else { - var projection = that._tilingScheme.projection; + var projection = tilingScheme.projection; sw = projection.unproject(swXY); ne = projection.unproject(neXY); } } - that._rectangle = new Rectangle(sw.longitude, sw.latitude, ne.longitude, ne.latitude); + rectangle = new Rectangle(sw.longitude, sw.latitude, ne.longitude, ne.latitude); } - // The rectangle must not be outside the bounds allowed by the tiling scheme. - if (that._rectangle.west < tilingScheme.rectangle.west) { - that._rectangle.west = tilingScheme.rectangle.west; + if (rectangle.west < tilingScheme.rectangle.west) { + rectangle.west = tilingScheme.rectangle.west; } - if (that._rectangle.east > tilingScheme.rectangle.east) { - that._rectangle.east = tilingScheme.rectangle.east; + if (rectangle.east > tilingScheme.rectangle.east) { + rectangle.east = tilingScheme.rectangle.east; } - if (that._rectangle.south < tilingScheme.rectangle.south) { - that._rectangle.south = tilingScheme.rectangle.south; + if (rectangle.south < tilingScheme.rectangle.south) { + rectangle.south = tilingScheme.rectangle.south; } - if (that._rectangle.north > tilingScheme.rectangle.north) { - that._rectangle.north = tilingScheme.rectangle.north; + if (rectangle.north > tilingScheme.rectangle.north) { + rectangle.north = tilingScheme.rectangle.north; } // Check the number of tiles at the minimum level. If it's more than four, // try requesting the lower levels anyway, because starting at the higher minimum // level will cause too many tiles to be downloaded and rendered. - var swTile = tilingScheme.positionToTileXY(Rectangle.southwest(that._rectangle), that._minimumLevel); - var neTile = tilingScheme.positionToTileXY(Rectangle.northeast(that._rectangle), that._minimumLevel); + var swTile = tilingScheme.positionToTileXY(Rectangle.southwest(rectangle), minimumLevel); + var neTile = tilingScheme.positionToTileXY(Rectangle.northeast(rectangle), minimumLevel); var tileCount = (Math.abs(neTile.x - swTile.x) + 1) * (Math.abs(neTile.y - swTile.y) + 1); if (tileCount > 4) { - that._minimumLevel = 0; + minimumLevel = 0; } - that._tilingScheme = tilingScheme; - that._ready = true; + var templateUrl = url + '{z}/{x}/{reverseY}.' + fileExtension; + that._readyPromise.resolve(true); + + imageryProvider.reinitialize({ + url : templateUrl, + tilingScheme : tilingScheme, + rectangle : rectangle, + tileWidth : tileWidth, + tileHeight : tileHeight, + minimumLevel : minimumLevel, + maximumLevel : maximumLevel, + proxy : options.proxy, + tileDiscardPolicy : options.tileDiscardPolicy, + credit: options.credit + }); } function metadataFailure(error) { // Can't load XML, still allow options and defaults - that._fileExtension = defaultValue(options.fileExtension, 'png'); - that._tileWidth = defaultValue(options.tileWidth, 256); - that._tileHeight = defaultValue(options.tileHeight, 256); - that._minimumLevel = defaultValue(options.minimumLevel, 0); - that._maximumLevel = options.maximumLevel; - that._tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); - that._rectangle = defaultValue(options.rectangle, that._tilingScheme.rectangle); - that._ready = true; - that._readyPromise.resolve(true); + var fileExtension = defaultValue(options.fileExtension, 'png'); + var tileWidth = defaultValue(options.tileWidth, 256); + var tileHeight = defaultValue(options.tileHeight, 256); + var minimumLevel = defaultValue(options.minimumLevel, 0); + var maximumLevel = options.maximumLevel; + var tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new WebMercatorTilingScheme({ ellipsoid : options.ellipsoid }); + var rectangle = defaultValue(options.rectangle, tilingScheme.rectangle); + + var templateUrl = url + '{z}/{x}/{reverseY}.' + fileExtension; + imageryProvider.reinitialize({ + url : templateUrl, + tilingScheme : tilingScheme, + rectangle : rectangle, + tileWidth : tileWidth, + tileHeight : tileHeight, + minimumLevel : minimumLevel, + maximumLevel : maximumLevel, + proxy : options.proxy, + tileDiscardPolicy : options.tileDiscardPolicy, + credit: options.credit + }); } function requestMetadata() { - var resourceUrl = joinUrls(url, 'tilemapresource.xml'); - var proxy = that._proxy; + var resourceUrl = url + 'tilemapresource.xml'; + var proxy = options.proxy; if (defined(proxy)) { resourceUrl = proxy.getURL(resourceUrl); } @@ -272,21 +283,9 @@ define([ } requestMetadata(); + return imageryProvider; }; - function buildImageUrl(imageryProvider, x, y, level) { - var yTiles = imageryProvider._tilingScheme.getNumberOfYTilesAtLevel(level); - var url = joinUrls(imageryProvider._url, level + '/' + x + '/' + (yTiles - y - 1) + '.' + imageryProvider._fileExtension); - - var proxy = imageryProvider._proxy; - if (defined(proxy)) { - url = proxy.getURL(url); - } - - return url; - } - - defineProperties(TileMapServiceImageryProvider.prototype, { /** * Gets the URL of the service hosting the imagery. @@ -300,179 +299,6 @@ define([ } }, - /** - * Gets the proxy used by this provider. - * @memberof TileMapServiceImageryProvider.prototype - * @type {Proxy} - * @readonly - */ - proxy : { - get : function() { - return this._proxy; - } - }, - - /** - * Gets the width of each tile, in pixels. This function should - * not be called before {@link TileMapServiceImageryProvider#ready} returns true. - * @memberof TileMapServiceImageryProvider.prototype - * @type {Number} - * @readonly - */ - tileWidth : { - get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._tileWidth; - } - }, - - /** - * Gets the height of each tile, in pixels. This function should - * not be called before {@link TileMapServiceImageryProvider#ready} returns true. - * @memberof TileMapServiceImageryProvider.prototype - * @type {Number} - * @readonly - */ - tileHeight: { - get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._tileHeight; - } - }, - - /** - * Gets the maximum level-of-detail that can be requested. This function should - * not be called before {@link TileMapServiceImageryProvider#ready} returns true. - * @memberof TileMapServiceImageryProvider.prototype - * @type {Number} - * @readonly - */ - maximumLevel : { - get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._maximumLevel; - } - }, - - /** - * Gets the minimum level-of-detail that can be requested. This function should - * not be called before {@link TileMapServiceImageryProvider#ready} returns true. - * @memberof TileMapServiceImageryProvider.prototype - * @type {Number} - * @readonly - */ - minimumLevel : { - get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._minimumLevel; - } - }, - - /** - * Gets the tiling scheme used by this provider. This function should - * not be called before {@link TileMapServiceImageryProvider#ready} returns true. - * @memberof TileMapServiceImageryProvider.prototype - * @type {TilingScheme} - * @readonly - */ - tilingScheme : { - get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._tilingScheme; - } - }, - - /** - * Gets the rectangle, in radians, of the imagery provided by this instance. This function should - * not be called before {@link TileMapServiceImageryProvider#ready} returns true. - * @memberof TileMapServiceImageryProvider.prototype - * @type {Rectangle} - * @readonly - */ - rectangle : { - get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('rectangle must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._rectangle; - } - }, - - /** - * Gets the tile discard policy. If not undefined, the discard policy is responsible - * for filtering out "missing" tiles via its shouldDiscardImage function. If this function - * returns undefined, no tiles are filtered. This function should - * not be called before {@link TileMapServiceImageryProvider#ready} returns true. - * @memberof TileMapServiceImageryProvider.prototype - * @type {TileDiscardPolicy} - * @readonly - */ - tileDiscardPolicy : { - get : function() { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - return this._tileDiscardPolicy; - } - }, - - /** - * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing - * to the event, you will be notified of the error and can potentially recover from it. Event listeners - * are passed an instance of {@link TileProviderError}. - * @memberof TileMapServiceImageryProvider.prototype - * @type {Event} - * @readonly - */ - errorEvent : { - get : function() { - return this._errorEvent; - } - }, - - /** - * Gets a value indicating whether or not the provider is ready for use. - * @memberof TileMapServiceImageryProvider.prototype - * @type {Boolean} - * @readonly - */ - ready : { - get : function() { - return this._ready; - } - }, - /** * Gets a promise that resolves to true when the provider is ready for use. * @memberof TileMapServiceImageryProvider.prototype @@ -484,91 +310,7 @@ define([ return this._readyPromise.promise; } }, - - /** - * Gets the credit to display when this imagery provider is active. Typically this is used to credit - * the source of the imagery. This function should not be called before {@link TileMapServiceImageryProvider#ready} returns true. - * @memberof TileMapServiceImageryProvider.prototype - * @type {Credit} - * @readonly - */ - credit : { - get : function() { - return this._credit; - } - }, - - /** - * Gets a value indicating whether or not the images provided by this imagery provider - * include an alpha channel. If this property is false, an alpha channel, if present, will - * be ignored. If this property is true, any images without an alpha channel will be treated - * as if their alpha is 1.0 everywhere. When this property is false, memory usage - * and texture upload time are reduced. - * @memberof TileMapServiceImageryProvider.prototype - * @type {Boolean} - * @readonly - */ - hasAlphaChannel : { - get : function() { - return true; - } - } }); - /** - * Gets the credits to be displayed when a given tile is displayed. - * - * @param {Number} x The tile X coordinate. - * @param {Number} y The tile Y coordinate. - * @param {Number} level The tile level; - * @returns {Credit[]} The credits to be displayed when the tile is displayed. - * - * @exception {DeveloperError} getTileCredits must not be called before the imagery provider is ready. - */ - TileMapServiceImageryProvider.prototype.getTileCredits = function(x, y, level) { - return undefined; - }; - - /** - * Requests the image for a given tile. This function should - * not be called before {@link TileMapServiceImageryProvider#ready} returns true. - * - * @param {Number} x The tile X coordinate. - * @param {Number} y The tile Y coordinate. - * @param {Number} level The tile level. - * @returns {Promise.|undefined} A promise for the image that will resolve when the image is available, or - * undefined if there are too many active requests to the server, and the request - * should be retried later. The resolved image may be either an - * Image or a Canvas DOM object. - */ - TileMapServiceImageryProvider.prototype.requestImage = function(x, y, level) { - //>>includeStart('debug', pragmas.debug); - if (!this._ready) { - throw new DeveloperError('requestImage must not be called before the imagery provider is ready.'); - } - //>>includeEnd('debug'); - - var url = buildImageUrl(this, x, y, level); - return ImageryProvider.loadImage(this, url); - }; - - /** - * Picking features is not currently supported by this imagery provider, so this function simply returns - * undefined. - * - * @param {Number} x The tile X coordinate. - * @param {Number} y The tile Y coordinate. - * @param {Number} level The tile level. - * @param {Number} longitude The longitude at which to pick features. - * @param {Number} latitude The latitude at which to pick features. - * @return {Promise.|undefined} A promise for the picked features that will resolve when the asynchronous - * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo} - * instances. The array may be empty if no features are found at the given location. - * It may also be undefined if picking is not supported. - */ - TileMapServiceImageryProvider.prototype.pickFeatures = function() { - return undefined; - }; - return TileMapServiceImageryProvider; }); diff --git a/Source/Scene/UrlTemplateImageryProvider.js b/Source/Scene/UrlTemplateImageryProvider.js index 8e874bdd3ff0..a9b5c0f754d1 100644 --- a/Source/Scene/UrlTemplateImageryProvider.js +++ b/Source/Scene/UrlTemplateImageryProvider.js @@ -54,7 +54,7 @@ define([ * @constructor * * @param {Object} [options] Object with the following properties: - * @param {String} [options.url] The URL template to use to request tiles. It has the following keywords: + * @param {String} options.url The URL template to use to request tiles. It has the following keywords: *