From 9557a3eb0b61f0644093cb0983858be2c4a6cce4 Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Mon, 11 Nov 2024 15:42:36 -0500 Subject: [PATCH 01/17] Add option to select which geocoder is used --- .../engine/Source/Core/IonGeocodeProvider.js | 33 ++++++++++ .../engine/Source/Core/IonGeocoderService.js | 62 +++++++++++++++++++ .../Specs/Core/IonGeocoderServiceSpec.js | 46 ++++++++++++++ packages/widgets/Source/Viewer/Viewer.js | 12 +++- packages/widgets/Specs/Viewer/ViewerSpec.js | 15 +++++ 5 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 packages/engine/Source/Core/IonGeocodeProvider.js diff --git a/packages/engine/Source/Core/IonGeocodeProvider.js b/packages/engine/Source/Core/IonGeocodeProvider.js new file mode 100644 index 000000000000..bd61230859df --- /dev/null +++ b/packages/engine/Source/Core/IonGeocodeProvider.js @@ -0,0 +1,33 @@ +/** + * Underlying geocoding services that can be used via Cesium ion. + * + * @enum {string} + */ +const IonGeocodeProvider = Object.freeze({ + /** + * Google geocoder, for use with Google data. + * + * @type {string} + * @constant + */ + GOOGLE: "GOOGLE", + + /** + * Bing geocoder, for use with Bing data. + * + * @type {string} + * @constant + */ + BING: "BING", + + /** + * Use the default geocoder as set on the server. Used when neither Bing or + * Google data is used. + * + * @type {string} + * @constant + */ + DEFAULT: "DEFAULT", +}); + +export default IonGeocodeProvider; diff --git a/packages/engine/Source/Core/IonGeocoderService.js b/packages/engine/Source/Core/IonGeocoderService.js index 81da96b7dbba..f19bf7aca7c7 100644 --- a/packages/engine/Source/Core/IonGeocoderService.js +++ b/packages/engine/Source/Core/IonGeocoderService.js @@ -2,10 +2,43 @@ import Check from "./Check.js"; import Credit from "./Credit.js"; import defaultValue from "./defaultValue.js"; import defined from "./defined.js"; +import DeveloperError from "./DeveloperError.js"; import Ion from "./Ion.js"; +import IonGeocodeProvider from "./IonGeocodeProvider.js"; import PeliasGeocoderService from "./PeliasGeocoderService.js"; import Resource from "./Resource.js"; +/** + * @param {*} geocodeProvider + * @throws {DeveloperError} + * @private + */ +function validateIonGeocodeProvider(geocodeProvider) { + if ( + !Object.values(IonGeocodeProvider).some( + (value) => value === geocodeProvider, + ) + ) { + throw new DeveloperError(`Invalid geocodeProvider: "${geocodeProvider}"`); + } +} + +const providerToParameterMap = Object.freeze({ + [IonGeocodeProvider.GOOGLE]: "google", + [IonGeocodeProvider.BING]: "bing", + [IonGeocodeProvider.DEFAULT]: undefined, +}); + +function providerToQueryParameter(provider) { + return providerToParameterMap[provider]; +} + +function queryParameterToProvider(parameter) { + return Object.entries(providerToParameterMap).find( + (entry) => entry[1] === parameter, + )[0]; +} + /** * Provides geocoding through Cesium ion. * @alias IonGeocoderService @@ -15,6 +48,7 @@ import Resource from "./Resource.js"; * @param {Scene} options.scene The scene * @param {string} [options.accessToken=Ion.defaultAccessToken] The access token to use. * @param {string|Resource} [options.server=Ion.defaultServer] The resource to the Cesium ion API server. + * @param {IonGeocodeProvider} [options.geocodeProvider=IonGeocodeProvider.DEFAULT] The geocoder the Cesium ion API server should use to fulfill this request. * * @see Ion */ @@ -25,6 +59,12 @@ function IonGeocoderService(options) { Check.typeOf.object("options.scene", options.scene); //>>includeEnd('debug'); + const geocodeProvider = defaultValue( + options.geocodeProvider, + IonGeocodeProvider.DEFAULT, + ); + validateIonGeocodeProvider(geocodeProvider); + const accessToken = defaultValue(options.accessToken, Ion.defaultAccessToken); const server = Resource.createIfNeeded( defaultValue(options.server, Ion.defaultServer), @@ -40,6 +80,9 @@ function IonGeocoderService(options) { const searchEndpoint = server.getDerivedResource({ url: "v1/geocode", + queryParameters: { + geocoder: providerToQueryParameter(geocodeProvider), + }, }); if (defined(accessToken)) { @@ -64,6 +107,25 @@ Object.defineProperties(IonGeocoderService.prototype, { return undefined; }, }, + /** + * @memberof IonGeocoderService.prototype + * @type {IonGeocodeProvider} + */ + geocodeProvider: { + get: function () { + return queryParameterToProvider( + this._pelias.url.queryParameters["geocoder"], + ); + }, + set: function (geocodeProvider) { + validateIonGeocodeProvider(geocodeProvider); + const query = { + ...this._pelias.url.queryParameters, + geocoder: providerToQueryParameter(geocodeProvider), + }; + this._pelias.url.setQueryParameters(query); + }, + }, }); /** diff --git a/packages/engine/Specs/Core/IonGeocoderServiceSpec.js b/packages/engine/Specs/Core/IonGeocoderServiceSpec.js index 17951c615c02..c38574084f41 100644 --- a/packages/engine/Specs/Core/IonGeocoderServiceSpec.js +++ b/packages/engine/Specs/Core/IonGeocoderServiceSpec.js @@ -1,7 +1,9 @@ import { + DeveloperError, GeocoderService, GeocodeType, Ion, + IonGeocodeProvider, IonGeocoderService, } from "../../index.js"; @@ -26,20 +28,24 @@ describe("Core/IonGeocoderService", function () { expect(service._accessToken).toEqual(Ion.defaultAccessToken); expect(service._server.url).toEqual(Ion.defaultServer.url); + expect(service.geocodeProvider).toEqual(IonGeocodeProvider.DEFAULT); }); it("creates with specified parameters", function () { const accessToken = "123456"; const server = "http://not.ion.invalid/"; + const geocodeProvider = IonGeocodeProvider.GOOGLE; const service = new IonGeocoderService({ accessToken: accessToken, server: server, scene: scene, + geocodeProvider, }); expect(service._accessToken).toEqual(accessToken); expect(service._server.url).toEqual(server); + expect(service.geocodeProvider).toEqual(geocodeProvider); }); it("calls inner geocoder and returns result", async function () { @@ -64,4 +70,44 @@ describe("Core/IonGeocoderService", function () { expect(service.credit).toBeUndefined(); }); + + it("setting geocodeProvider updates _pelias.url for GOOGLE", function () { + const service = new IonGeocoderService({ + scene, + geocoder: IonGeocodeProvider.DEFAULT, + }); + + service.geocodeProvider = IonGeocodeProvider.GOOGLE; + expect(service._pelias.url.queryParameters["geocoder"]).toEqual("google"); + }); + + it("setting geocodeProvider updates _pelias.url for BING", function () { + const service = new IonGeocoderService({ + scene, + geocoder: IonGeocodeProvider.DEFAULT, + }); + + service.geocodeProvider = IonGeocodeProvider.BING; + expect(service._pelias.url.queryParameters["geocoder"]).toEqual("bing"); + }); + + it("setting geocodeProvider updates _pelias.url for DEFAULT", function () { + const service = new IonGeocoderService({ + scene, + geocoder: IonGeocodeProvider.GOOGLE, + }); + + service.geocodeProvider = IonGeocodeProvider.DEFAULT; + expect(service._pelias.url.queryParameters["geocoder"]).toBeUndefined(); + }); + + it("throws if setting invalid geocodeProvider", function () { + expect( + () => new IonGeocoderService({ scene, geocodeProvider: "junk" }), + ).toThrowError(DeveloperError, /Invalid geocodeProvider/); + expect(() => { + const service = new IonGeocoderService({ scene }); + service.geocodeProvider = "junk"; + }).toThrowError(DeveloperError, /Invalid geocodeProvider/); + }); }); diff --git a/packages/widgets/Source/Viewer/Viewer.js b/packages/widgets/Source/Viewer/Viewer.js index 4574ef6aadc7..f7503b537d15 100644 --- a/packages/widgets/Source/Viewer/Viewer.js +++ b/packages/widgets/Source/Viewer/Viewer.js @@ -18,6 +18,7 @@ import { Math as CesiumMath, Property, ScreenSpaceEventType, + IonGeocoderService, } from "@cesium/engine"; import Animation from "../Animation/Animation.js"; import AnimationViewModel from "../Animation/AnimationViewModel.js"; @@ -280,7 +281,7 @@ function enableVRUI(viewer, enabled) { * @property {boolean} [baseLayerPicker=true] If set to false, the BaseLayerPicker widget will not be created. * @property {boolean} [fullscreenButton=true] If set to false, the FullscreenButton widget will not be created. * @property {boolean} [vrButton=false] If set to true, the VRButton widget will be created. - * @property {boolean|GeocoderService[]} [geocoder=true] If set to false, the Geocoder widget will not be created. + * @property {boolean|IonGeocodeProvider|GeocoderService[]} [geocoder=IonGeocodeProvider.DEFAULT] If set to false, the Geocoder widget will not be created. * @property {boolean} [homeButton=true] If set to false, the HomeButton widget will not be created. * @property {boolean} [infoBox=true] If set to false, the InfoBox widget will not be created. * @property {boolean} [sceneModePicker=true] If set to false, the SceneModePicker widget will not be created. @@ -557,7 +558,14 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to geocoderContainer.className = "cesium-viewer-geocoderContainer"; toolbar.appendChild(geocoderContainer); let geocoderService; - if (defined(options.geocoder) && typeof options.geocoder !== "boolean") { + if (typeof options.geocoder === "string") { + geocoderService = [ + new IonGeocoderService({ scene, geocodeProvider: options.geocoder }), + ]; + } else if ( + defined(options.geocoder) && + typeof options.geocoder !== "boolean" + ) { geocoderService = Array.isArray(options.geocoder) ? options.geocoder : [options.geocoder]; diff --git a/packages/widgets/Specs/Viewer/ViewerSpec.js b/packages/widgets/Specs/Viewer/ViewerSpec.js index 49df43f46eb2..8bb508d100b7 100644 --- a/packages/widgets/Specs/Viewer/ViewerSpec.js +++ b/packages/widgets/Specs/Viewer/ViewerSpec.js @@ -18,6 +18,8 @@ import { ImageryLayerCollection, SceneMode, ShadowMode, + IonGeocodeProvider, + IonGeocoderService, } from "@cesium/engine"; import { @@ -354,6 +356,19 @@ describe( expect(viewer.geocoder.viewModel._geocoderServices.length).toBe(1); }); + it("constructs geocoder with IonGeocodeProvider", function () { + viewer = createViewer(container, { + geocoder: IonGeocodeProvider.GOOGLE, + }); + expect(viewer.geocoder).toBeDefined(); + expect(viewer.geocoder.viewModel._geocoderServices.length).toBe(1); + const geocoderService = viewer.geocoder.viewModel._geocoderServices[0]; + expect(geocoderService).toBeInstanceOf(IonGeocoderService); + expect(geocoderService.geocodeProvider).toEqual( + IonGeocodeProvider.GOOGLE, + ); + }); + it("constructs geocoder with geocoder service option", function () { const service = new CartographicGeocoderService(); viewer = createViewer(container, { From 3bd5d7297213067e67d8dea313ab90ccaf4af846 Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Mon, 11 Nov 2024 16:50:54 -0500 Subject: [PATCH 02/17] Fix bug with gecoder:undefined getting passed in the query --- packages/engine/Source/Core/IonGeocoderService.js | 8 +++++--- packages/engine/Specs/Core/IonGeocoderServiceSpec.js | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/engine/Source/Core/IonGeocoderService.js b/packages/engine/Source/Core/IonGeocoderService.js index f19bf7aca7c7..eb5d5a973ae0 100644 --- a/packages/engine/Source/Core/IonGeocoderService.js +++ b/packages/engine/Source/Core/IonGeocoderService.js @@ -80,9 +80,6 @@ function IonGeocoderService(options) { const searchEndpoint = server.getDerivedResource({ url: "v1/geocode", - queryParameters: { - geocoder: providerToQueryParameter(geocodeProvider), - }, }); if (defined(accessToken)) { @@ -92,6 +89,7 @@ function IonGeocoderService(options) { this._accessToken = accessToken; this._server = server; this._pelias = new PeliasGeocoderService(searchEndpoint); + this.geocodeProvider = geocodeProvider; } Object.defineProperties(IonGeocoderService.prototype, { @@ -123,6 +121,10 @@ Object.defineProperties(IonGeocoderService.prototype, { ...this._pelias.url.queryParameters, geocoder: providerToQueryParameter(geocodeProvider), }; + // Delete the geocoder parameter to prevent sending &geocoder=undefined in the query + if (!defined(query.geocoder)) { + delete query.geocoder; + } this._pelias.url.setQueryParameters(query); }, }, diff --git a/packages/engine/Specs/Core/IonGeocoderServiceSpec.js b/packages/engine/Specs/Core/IonGeocoderServiceSpec.js index c38574084f41..0bdc02b18692 100644 --- a/packages/engine/Specs/Core/IonGeocoderServiceSpec.js +++ b/packages/engine/Specs/Core/IonGeocoderServiceSpec.js @@ -98,7 +98,10 @@ describe("Core/IonGeocoderService", function () { }); service.geocodeProvider = IonGeocodeProvider.DEFAULT; - expect(service._pelias.url.queryParameters["geocoder"]).toBeUndefined(); + const queryParameters = service._pelias.url.queryParameters; + expect(queryParameters.geocoder).toBeUndefined(); + // Make sure that it isn't 'geocoder: undefined' + expect(queryParameters.hasOwnProperty("geocoder")).toBeFalse(); }); it("throws if setting invalid geocodeProvider", function () { From 5f849b1f1da94460d36432a2d777f5169df4df57 Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Mon, 11 Nov 2024 16:57:41 -0500 Subject: [PATCH 03/17] Update documentation --- .../gallery/3D Tiles Vertical Exaggeration.html | 1 + Apps/Sandcastle/gallery/AEC Clipping.html | 1 + Apps/Sandcastle/gallery/Bing Maps Labels Only.html | 1 + Apps/Sandcastle/gallery/Clamp Entities to Ground.html | 1 + Apps/Sandcastle/gallery/Globe Interior.html | 1 + ...ogle Photorealistic 3D Tiles with Building Insert.html | 1 + .../gallery/Google Photorealistic 3D Tiles.html | 1 + Apps/Sandcastle/gallery/Imagery Color To Alpha.html | 4 +++- Apps/Sandcastle/gallery/Imagery Layers Manipulation.html | 1 + .../Source/Scene/createGooglePhotorealistic3DTileset.js | 8 ++++++-- 10 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html b/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html index 4e636b2f001c..36f9cba9d603 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html +++ b/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html @@ -78,6 +78,7 @@

Loading...

animation: false, sceneModePicker: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProvider.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, diff --git a/Apps/Sandcastle/gallery/AEC Clipping.html b/Apps/Sandcastle/gallery/AEC Clipping.html index 0fa60bf14964..6c5ba834e71c 100644 --- a/Apps/Sandcastle/gallery/AEC Clipping.html +++ b/Apps/Sandcastle/gallery/AEC Clipping.html @@ -32,6 +32,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProvider.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, diff --git a/Apps/Sandcastle/gallery/Bing Maps Labels Only.html b/Apps/Sandcastle/gallery/Bing Maps Labels Only.html index f4c12739f24f..8bebfcd63b1a 100644 --- a/Apps/Sandcastle/gallery/Bing Maps Labels Only.html +++ b/Apps/Sandcastle/gallery/Bing Maps Labels Only.html @@ -67,6 +67,7 @@ baseLayer: false, baseLayerPicker: false, infoBox: false, + geocoder: Cesium.IonGeocodeProvider.BING, }); const layers = viewer.imageryLayers; diff --git a/Apps/Sandcastle/gallery/Clamp Entities to Ground.html b/Apps/Sandcastle/gallery/Clamp Entities to Ground.html index 0a048fbe0d93..52b7bbef1fa9 100644 --- a/Apps/Sandcastle/gallery/Clamp Entities to Ground.html +++ b/Apps/Sandcastle/gallery/Clamp Entities to Ground.html @@ -41,6 +41,7 @@ timeline: false, animation: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProvider.GOOGLE, }); const scene = viewer.scene; scene.globe.depthTestAgainstTerrain = true; diff --git a/Apps/Sandcastle/gallery/Globe Interior.html b/Apps/Sandcastle/gallery/Globe Interior.html index 0deb07a51e34..2c02fa55daf3 100644 --- a/Apps/Sandcastle/gallery/Globe Interior.html +++ b/Apps/Sandcastle/gallery/Globe Interior.html @@ -34,6 +34,7 @@ //Sandcastle_Begin const viewer = new Cesium.Viewer("cesiumContainer", { orderIndependentTranslucency: false, + geocoder: Cesium.IonGeocodeProvider.BING, }); const scene = viewer.scene; diff --git a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html index 6437a2fb7c19..feafc0983b21 100644 --- a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html +++ b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html @@ -32,6 +32,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocoderProvider.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, diff --git a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html index d4d68c1c97d6..93d337b076a0 100644 --- a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html +++ b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html @@ -32,6 +32,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProvider.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, diff --git a/Apps/Sandcastle/gallery/Imagery Color To Alpha.html b/Apps/Sandcastle/gallery/Imagery Color To Alpha.html index 8fa3ed032883..202c13ddfc3b 100644 --- a/Apps/Sandcastle/gallery/Imagery Color To Alpha.html +++ b/Apps/Sandcastle/gallery/Imagery Color To Alpha.html @@ -51,7 +51,9 @@ window.startup = async function (Cesium) { "use strict"; //Sandcastle_Begin - const viewer = new Cesium.Viewer("cesiumContainer"); + const viewer = new Cesium.Viewer("cesiumContainer", { + geocoder: Cesium.IonGeocodeProvider.BING, + }); const layers = viewer.scene.imageryLayers; diff --git a/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html b/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html index 4e309a339dd7..49df7fd5c6d5 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html @@ -106,6 +106,7 @@ //Sandcastle_Begin const viewer = new Cesium.Viewer("cesiumContainer", { baseLayerPicker: false, + geocoder: Cesium.IonGeocodeProvider.BING, }); const imageryLayers = viewer.imageryLayers; diff --git a/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js b/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js index f762d748dc36..ef35c0c38e31 100644 --- a/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js +++ b/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js @@ -17,7 +17,9 @@ import Resource from "../Core/Resource.js"; * @see GoogleMaps * * @example - * const viewer = new Cesium.Viewer("cesiumContainer"); + * const viewer = new Cesium.Viewer("cesiumContainer", { + * geocoder: Cesium.IonGeocodeProvider.GOOGLE + * }); * * try { * const tileset = await Cesium.createGooglePhotorealistic3DTileset(); @@ -30,7 +32,9 @@ import Resource from "../Core/Resource.js"; * // Use your own Google Maps API key * Cesium.GoogleMaps.defaultApiKey = "your-api-key"; * - * const viewer = new Cesium.Viewer("cesiumContainer"); + * const viewer = new Cesium.Viewer("cesiumContainer". { + * geocoder: Cesium.IonGeocodeProvider.GOOGLE + * }); * * try { * const tileset = await Cesium.createGooglePhotorealistic3DTileset(); From 096e67b07e374f7727c68d9675c27d0a223ac5c2 Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Tue, 12 Nov 2024 13:01:48 -0500 Subject: [PATCH 04/17] Fix documentation for IonGeocodeProvider --- packages/engine/Source/Core/IonGeocodeProvider.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/engine/Source/Core/IonGeocodeProvider.js b/packages/engine/Source/Core/IonGeocodeProvider.js index bd61230859df..e78d1dce3139 100644 --- a/packages/engine/Source/Core/IonGeocodeProvider.js +++ b/packages/engine/Source/Core/IonGeocodeProvider.js @@ -3,7 +3,7 @@ * * @enum {string} */ -const IonGeocodeProvider = Object.freeze({ +const IonGeocodeProvider = { /** * Google geocoder, for use with Google data. * @@ -28,6 +28,6 @@ const IonGeocodeProvider = Object.freeze({ * @constant */ DEFAULT: "DEFAULT", -}); +}; -export default IonGeocodeProvider; +export default Object.freeze(IonGeocodeProvider); From 0b2e65ebaf0835eb49acae3bcf2d0739f91e2605 Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Tue, 12 Nov 2024 13:04:11 -0500 Subject: [PATCH 05/17] IonGeocoderProvider -> IonGeocodeProvider --- .../Google Photorealistic 3D Tiles with Building Insert.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html index feafc0983b21..18c384a7b4d0 100644 --- a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html +++ b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html @@ -32,7 +32,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, - geocoder: Cesium.IonGeocoderProvider.GOOGLE, + geocoder: Cesium.IonGeocodeProvider.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, From 79cb58b927ad80222968359dc1160f08aad22026 Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Tue, 12 Nov 2024 14:11:52 -0500 Subject: [PATCH 06/17] Add GoogleGeocoderService --- .../Source/Core/GoogleGeocoderService.js | 107 ++++++++++++++++++ .../Specs/Core/GoogleGeocoderServicesSpec.js | 84 ++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 packages/engine/Source/Core/GoogleGeocoderService.js create mode 100644 packages/engine/Specs/Core/GoogleGeocoderServicesSpec.js diff --git a/packages/engine/Source/Core/GoogleGeocoderService.js b/packages/engine/Source/Core/GoogleGeocoderService.js new file mode 100644 index 000000000000..b8eab86dba4e --- /dev/null +++ b/packages/engine/Source/Core/GoogleGeocoderService.js @@ -0,0 +1,107 @@ +import Check from "./Check.js"; +import Credit from "./Credit.js"; +import defaultValue from "./defaultValue.js"; +import Rectangle from "./Rectangle.js"; +import Resource from "./Resource.js"; +import defined from "./defined.js"; +import DeveloperError from "./DeveloperError.js"; + +const API_URL = "https://maps.googleapis.com/maps/api/geocode/json"; +const CREDIT_HTML = `Google`; + +/** + * Provides geocoding through Google. + * + * @see {@link https://developers.google.com/maps/documentation/geocoding/policies|Google Geocoding Policies} + * @alias GoogleGeocoderService + * @constructor + * + * @param {object} options Object with the following properties: + * @param {string} options.key An API key to use with the Google geocoding service + */ +function GoogleGeocoderService(options) { + options = defaultValue(options, defaultValue.EMPTY_OBJECT); + const key = options.key; + //>>includeStart('debug', pragmas.debug); + if (!defined(key)) { + throw new DeveloperError("options.key is required."); + } + //>>includeEnd('debug'); + + this._resource = new Resource({ + url: API_URL, + queryParameters: { key }, + }); + + this._credit = new Credit(CREDIT_HTML, true); +} + +Object.defineProperties(GoogleGeocoderService.prototype, { + /** + * Gets the credit to display after a geocode is performed. Typically this is used to credit + * the geocoder service. + * @memberof GoogleGeocoderService.prototype + * @type {Credit|undefined} + * @readonly + */ + credit: { + get: function () { + return this._credit; + }, + }, +}); + +/** + * @function + * + * @param {string} query The query to be sent to the geocoder service + * @returns {Promise} + * @throws {Error} If the services returns a status other than OK or ZERO_RESULTS + */ +GoogleGeocoderService.prototype.geocode = async function (query) { + // See API documentation at https://developers.google.com/maps/documentation/geocoding/requests-geocoding + + //>>includeStart('debug', pragmas.debug); + Check.typeOf.string("query", query); + //>>includeEnd('debug'); + + const resource = this._resource.getDerivedResource({ + queryParameters: { + address: query, + }, + }); + + const response = await resource.fetchJson(); + + if (response.status === "ZERO_RESULTS") { + return []; + } + + if (response.status !== "OK") { + throw new Error( + `GoogleGeocoderService got a bad response ${response.status}: ${response.error_message}`, + ); + } + + const results = response.results.map((result) => { + const southWest = result.geometry.viewport.southwest; + const northEast = result.geometry.viewport.northeast; + return { + displayName: result.formatted_address, + destination: Rectangle.fromDegrees( + southWest.lng, + southWest.lat, + northEast.lng, + northEast.lat, + ), + attribution: { + html: CREDIT_HTML, + collapsible: false, + }, + }; + }); + + return results; +}; + +export default GoogleGeocoderService; diff --git a/packages/engine/Specs/Core/GoogleGeocoderServicesSpec.js b/packages/engine/Specs/Core/GoogleGeocoderServicesSpec.js new file mode 100644 index 000000000000..5260dc265742 --- /dev/null +++ b/packages/engine/Specs/Core/GoogleGeocoderServicesSpec.js @@ -0,0 +1,84 @@ +import { + createGuid, + GeocoderService, + GoogleGeocoderService, + Resource, + Rectangle, +} from "../../index.js"; + +describe("Core/GoogleGeocoderService", function () { + it("conforms to GeocoderService interface", function () { + expect(GoogleGeocoderService).toConformToInterface(GeocoderService); + }); + + it("constructor throws without key", function () { + expect(function () { + return new GoogleGeocoderService({}); + }).toThrowDeveloperError(); + }); + + it("constructor sets key on _resource", function () { + const key = createGuid(); + const service = new GoogleGeocoderService({ key }); + expect(service._resource.toString()).toEqual( + `https://maps.googleapis.com/maps/api/geocode/json?key=${key}`, + ); + }); + + it("geocode returns results for status=OK", async function () { + const key = createGuid(); + const query = createGuid(); + const service = new GoogleGeocoderService({ key }); + + spyOn(Resource.prototype, "fetchJson").and.resolveTo({ + results: [ + { + formatted_address: + "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA", + geometry: { + viewport: { + northeast: { + lat: 37.4237349802915, + lng: -122.083183169709, + }, + southwest: { + lat: 37.4210370197085, + lng: -122.085881130292, + }, + }, + }, + }, + ], + status: "OK", + }); + + const results = await service.geocode(query); + + expect(results).toEqual([ + { + displayName: "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA", + destination: Rectangle.fromDegrees( + -122.085881130292, + 37.4210370197085, + -122.083183169709, + 37.4237349802915, + ), + attribution: { + html: `Google`, + collapsible: false, + }, + }, + ]); + }); + + it("returns empty array for status=ZERO_RESULTS", async function () { + const service = new GoogleGeocoderService({ key: "key" }); + + spyOn(Resource.prototype, "fetchJson").and.resolveTo({ + status: "ZERO_RESULTS", + }); + + const results = await service.geocode("test"); + expect(results).toEqual([]); + }); +}); From fa0da08b3f8d22b9ec4fcd3f516ccf7d4f24c67f Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Tue, 12 Nov 2024 14:16:57 -0500 Subject: [PATCH 07/17] Update for Google Geocoder --- CHANGES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index e3107c706259..21757139473e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # Change Log +### 1.124 - 2024-12-01 + +##### Additions :tada: + +- Ability to choose between Bing and Google geocoders. Adds `GoogleGeocoderService` for standalone usage of Google geocoder. Updates `Viewer` constructor to also accept `IonGeocoderProvider` [#12299](https://github.com/CesiumGS/cesium/pull/12299) + ### 1.123.1 - 2024-11-07 #### @cesium/engine From f04ee84a9bdbb7e96a097e2c7ee71e43ae599513 Mon Sep 17 00:00:00 2001 From: Mark Dane <48362463+angrycat9000@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:15:47 -0500 Subject: [PATCH 08/17] Update CHANGES.md Co-authored-by: Gabby Getz --- CHANGES.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 21757139473e..aaaaef20aecd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,9 +2,17 @@ ### 1.124 - 2024-12-01 +#### @cesium/engine + +##### Additions :tada: + +- Added `GoogleGeocoderService` for standalone usage of Google geocoder. [#12299](https://github.com/CesiumGS/cesium/pull/12299) + +#### @cesium/widgets + ##### Additions :tada: -- Ability to choose between Bing and Google geocoders. Adds `GoogleGeocoderService` for standalone usage of Google geocoder. Updates `Viewer` constructor to also accept `IonGeocoderProvider` [#12299](https://github.com/CesiumGS/cesium/pull/12299) +- Added the ability to choose between Bing and Google geocoders. Updated `Viewer` constructor to also accept `IonGeocoderProvider` [#12299](https://github.com/CesiumGS/cesium/pull/12299) ### 1.123.1 - 2024-11-07 From 4e91c995ab980092e0cd62ca6435c8d3594b942a Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Thu, 14 Nov 2024 10:19:59 -0500 Subject: [PATCH 09/17] Minor PR feedback --- CHANGES.md | 2 +- packages/engine/Source/Core/GoogleGeocoderService.js | 7 +++++-- packages/engine/Source/Core/IonGeocoderService.js | 2 ++ packages/widgets/Source/Viewer/Viewer.js | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index aaaaef20aecd..3c05703f0a0e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,7 +6,7 @@ ##### Additions :tada: -- Added `GoogleGeocoderService` for standalone usage of Google geocoder. [#12299](https://github.com/CesiumGS/cesium/pull/12299) +- Added `GoogleGeocoderService` for standalone usage of Google geocoder. [#12299](https://github.com/CesiumGS/cesium/pull/12299) #### @cesium/widgets diff --git a/packages/engine/Source/Core/GoogleGeocoderService.js b/packages/engine/Source/Core/GoogleGeocoderService.js index b8eab86dba4e..67326e496e1c 100644 --- a/packages/engine/Source/Core/GoogleGeocoderService.js +++ b/packages/engine/Source/Core/GoogleGeocoderService.js @@ -5,6 +5,7 @@ import Rectangle from "./Rectangle.js"; import Resource from "./Resource.js"; import defined from "./defined.js"; import DeveloperError from "./DeveloperError.js"; +import RuntimeError from "./RuntimeError.js"; const API_URL = "https://maps.googleapis.com/maps/api/geocode/json"; const CREDIT_HTML = `Google`; @@ -52,11 +53,13 @@ Object.defineProperties(GoogleGeocoderService.prototype, { }); /** + * Get a list of possible locations that match a search string. + * * @function * * @param {string} query The query to be sent to the geocoder service * @returns {Promise} - * @throws {Error} If the services returns a status other than OK or ZERO_RESULTS + * @throws {RuntimeError} If the services returns a status other than OK or ZERO_RESULTS */ GoogleGeocoderService.prototype.geocode = async function (query) { // See API documentation at https://developers.google.com/maps/documentation/geocoding/requests-geocoding @@ -78,7 +81,7 @@ GoogleGeocoderService.prototype.geocode = async function (query) { } if (response.status !== "OK") { - throw new Error( + throw new RuntimeError( `GoogleGeocoderService got a bad response ${response.status}: ${response.error_message}`, ); } diff --git a/packages/engine/Source/Core/IonGeocoderService.js b/packages/engine/Source/Core/IonGeocoderService.js index eb5d5a973ae0..008ef8b0680b 100644 --- a/packages/engine/Source/Core/IonGeocoderService.js +++ b/packages/engine/Source/Core/IonGeocoderService.js @@ -106,8 +106,10 @@ Object.defineProperties(IonGeocoderService.prototype, { }, }, /** + * The geocoding service that Cesium ion API server should use to fulfill geocding requests. * @memberof IonGeocoderService.prototype * @type {IonGeocodeProvider} + * @default IonGeocodeProvider.DEFAULT */ geocodeProvider: { get: function () { diff --git a/packages/widgets/Source/Viewer/Viewer.js b/packages/widgets/Source/Viewer/Viewer.js index f7503b537d15..44e32292f0ab 100644 --- a/packages/widgets/Source/Viewer/Viewer.js +++ b/packages/widgets/Source/Viewer/Viewer.js @@ -281,7 +281,7 @@ function enableVRUI(viewer, enabled) { * @property {boolean} [baseLayerPicker=true] If set to false, the BaseLayerPicker widget will not be created. * @property {boolean} [fullscreenButton=true] If set to false, the FullscreenButton widget will not be created. * @property {boolean} [vrButton=false] If set to true, the VRButton widget will be created. - * @property {boolean|IonGeocodeProvider|GeocoderService[]} [geocoder=IonGeocodeProvider.DEFAULT] If set to false, the Geocoder widget will not be created. + * @property {boolean|IonGeocodeProvider|GeocoderService[]} [geocoder=IonGeocodeProvider.DEFAULT] The geocoding service or services to use when searching with the Geocoder widget. If set to false, the Geocoder widget will not be created. * @property {boolean} [homeButton=true] If set to false, the HomeButton widget will not be created. * @property {boolean} [infoBox=true] If set to false, the InfoBox widget will not be created. * @property {boolean} [sceneModePicker=true] If set to false, the SceneModePicker widget will not be created. From a78112116b3b32976424c1244dda7491811301e4 Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Thu, 14 Nov 2024 10:32:37 -0500 Subject: [PATCH 10/17] Rename IonGeocodeProvder -> IonGeocodeProviderType --- .../3D Tiles Vertical Exaggeration.html | 2 +- Apps/Sandcastle/gallery/AEC Clipping.html | 2 +- .../gallery/Bing Maps Labels Only.html | 2 +- .../gallery/Clamp Entities to Ground.html | 2 +- Apps/Sandcastle/gallery/Globe Interior.html | 2 +- ...alistic 3D Tiles with Building Insert.html | 2 +- .../Google Photorealistic 3D Tiles.html | 2 +- .../gallery/Imagery Color To Alpha.html | 2 +- .../gallery/Imagery Layers Manipulation.html | 2 +- ...eProvider.js => IonGeocodeProviderType.js} | 4 ++-- .../engine/Source/Core/IonGeocoderService.js | 24 +++++++++---------- .../createGooglePhotorealistic3DTileset.js | 4 ++-- .../Specs/Core/IonGeocoderServiceSpec.js | 18 +++++++------- packages/widgets/Source/Viewer/Viewer.js | 2 +- packages/widgets/Specs/Viewer/ViewerSpec.js | 8 +++---- 15 files changed, 39 insertions(+), 39 deletions(-) rename packages/engine/Source/Core/{IonGeocodeProvider.js => IonGeocodeProviderType.js} (85%) diff --git a/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html b/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html index 36f9cba9d603..292e07945f11 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html +++ b/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html @@ -78,7 +78,7 @@

Loading...

animation: false, sceneModePicker: false, baseLayerPicker: false, - geocoder: Cesium.IonGeocodeProvider.GOOGLE, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, diff --git a/Apps/Sandcastle/gallery/AEC Clipping.html b/Apps/Sandcastle/gallery/AEC Clipping.html index 6c5ba834e71c..57c381068f9d 100644 --- a/Apps/Sandcastle/gallery/AEC Clipping.html +++ b/Apps/Sandcastle/gallery/AEC Clipping.html @@ -32,7 +32,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, - geocoder: Cesium.IonGeocodeProvider.GOOGLE, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, diff --git a/Apps/Sandcastle/gallery/Bing Maps Labels Only.html b/Apps/Sandcastle/gallery/Bing Maps Labels Only.html index 8bebfcd63b1a..7f92188196ba 100644 --- a/Apps/Sandcastle/gallery/Bing Maps Labels Only.html +++ b/Apps/Sandcastle/gallery/Bing Maps Labels Only.html @@ -67,7 +67,7 @@ baseLayer: false, baseLayerPicker: false, infoBox: false, - geocoder: Cesium.IonGeocodeProvider.BING, + geocoder: Cesium.IonGeocodeProviderType.BING, }); const layers = viewer.imageryLayers; diff --git a/Apps/Sandcastle/gallery/Clamp Entities to Ground.html b/Apps/Sandcastle/gallery/Clamp Entities to Ground.html index 52b7bbef1fa9..07b1f9afd3d9 100644 --- a/Apps/Sandcastle/gallery/Clamp Entities to Ground.html +++ b/Apps/Sandcastle/gallery/Clamp Entities to Ground.html @@ -41,7 +41,7 @@ timeline: false, animation: false, baseLayerPicker: false, - geocoder: Cesium.IonGeocodeProvider.GOOGLE, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, }); const scene = viewer.scene; scene.globe.depthTestAgainstTerrain = true; diff --git a/Apps/Sandcastle/gallery/Globe Interior.html b/Apps/Sandcastle/gallery/Globe Interior.html index 2c02fa55daf3..9a4ff467d784 100644 --- a/Apps/Sandcastle/gallery/Globe Interior.html +++ b/Apps/Sandcastle/gallery/Globe Interior.html @@ -34,7 +34,7 @@ //Sandcastle_Begin const viewer = new Cesium.Viewer("cesiumContainer", { orderIndependentTranslucency: false, - geocoder: Cesium.IonGeocodeProvider.BING, + geocoder: Cesium.IonGeocodeProviderType.BING, }); const scene = viewer.scene; diff --git a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html index 18c384a7b4d0..d93b4085a064 100644 --- a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html +++ b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html @@ -32,7 +32,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, - geocoder: Cesium.IonGeocodeProvider.GOOGLE, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, diff --git a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html index 93d337b076a0..59eec45e543f 100644 --- a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html +++ b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html @@ -32,7 +32,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, - geocoder: Cesium.IonGeocodeProvider.GOOGLE, + geocoder: Cesium.IonGeocodeProviderType.GOOGLE, // The globe does not need to be displayed, // since the Photorealistic 3D Tiles include terrain globe: false, diff --git a/Apps/Sandcastle/gallery/Imagery Color To Alpha.html b/Apps/Sandcastle/gallery/Imagery Color To Alpha.html index 202c13ddfc3b..c28533a3c4a9 100644 --- a/Apps/Sandcastle/gallery/Imagery Color To Alpha.html +++ b/Apps/Sandcastle/gallery/Imagery Color To Alpha.html @@ -52,7 +52,7 @@ "use strict"; //Sandcastle_Begin const viewer = new Cesium.Viewer("cesiumContainer", { - geocoder: Cesium.IonGeocodeProvider.BING, + geocoder: Cesium.IonGeocodeProviderType.BING, }); const layers = viewer.scene.imageryLayers; diff --git a/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html b/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html index 49df7fd5c6d5..48a3efc177ab 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html @@ -106,7 +106,7 @@ //Sandcastle_Begin const viewer = new Cesium.Viewer("cesiumContainer", { baseLayerPicker: false, - geocoder: Cesium.IonGeocodeProvider.BING, + geocoder: Cesium.IonGeocodeProviderType.BING, }); const imageryLayers = viewer.imageryLayers; diff --git a/packages/engine/Source/Core/IonGeocodeProvider.js b/packages/engine/Source/Core/IonGeocodeProviderType.js similarity index 85% rename from packages/engine/Source/Core/IonGeocodeProvider.js rename to packages/engine/Source/Core/IonGeocodeProviderType.js index e78d1dce3139..2dc9bf35d775 100644 --- a/packages/engine/Source/Core/IonGeocodeProvider.js +++ b/packages/engine/Source/Core/IonGeocodeProviderType.js @@ -3,7 +3,7 @@ * * @enum {string} */ -const IonGeocodeProvider = { +const IonGeocodeProviderType = { /** * Google geocoder, for use with Google data. * @@ -30,4 +30,4 @@ const IonGeocodeProvider = { DEFAULT: "DEFAULT", }; -export default Object.freeze(IonGeocodeProvider); +export default Object.freeze(IonGeocodeProviderType); diff --git a/packages/engine/Source/Core/IonGeocoderService.js b/packages/engine/Source/Core/IonGeocoderService.js index 008ef8b0680b..db0cfe3dfc81 100644 --- a/packages/engine/Source/Core/IonGeocoderService.js +++ b/packages/engine/Source/Core/IonGeocoderService.js @@ -4,7 +4,7 @@ import defaultValue from "./defaultValue.js"; import defined from "./defined.js"; import DeveloperError from "./DeveloperError.js"; import Ion from "./Ion.js"; -import IonGeocodeProvider from "./IonGeocodeProvider.js"; +import IonGeocodeProviderType from "./IonGeocodeProviderType.js"; import PeliasGeocoderService from "./PeliasGeocoderService.js"; import Resource from "./Resource.js"; @@ -13,9 +13,9 @@ import Resource from "./Resource.js"; * @throws {DeveloperError} * @private */ -function validateIonGeocodeProvider(geocodeProvider) { +function validateIonGeocodeProviderType(geocodeProvider) { if ( - !Object.values(IonGeocodeProvider).some( + !Object.values(IonGeocodeProviderType).some( (value) => value === geocodeProvider, ) ) { @@ -24,9 +24,9 @@ function validateIonGeocodeProvider(geocodeProvider) { } const providerToParameterMap = Object.freeze({ - [IonGeocodeProvider.GOOGLE]: "google", - [IonGeocodeProvider.BING]: "bing", - [IonGeocodeProvider.DEFAULT]: undefined, + [IonGeocodeProviderType.GOOGLE]: "google", + [IonGeocodeProviderType.BING]: "bing", + [IonGeocodeProviderType.DEFAULT]: undefined, }); function providerToQueryParameter(provider) { @@ -48,7 +48,7 @@ function queryParameterToProvider(parameter) { * @param {Scene} options.scene The scene * @param {string} [options.accessToken=Ion.defaultAccessToken] The access token to use. * @param {string|Resource} [options.server=Ion.defaultServer] The resource to the Cesium ion API server. - * @param {IonGeocodeProvider} [options.geocodeProvider=IonGeocodeProvider.DEFAULT] The geocoder the Cesium ion API server should use to fulfill this request. + * @param {IonGeocodeProviderType} [options.geocodeProvider=IonGeocodeProviderType.DEFAULT] The geocoder the Cesium ion API server should use to fulfill this request. * * @see Ion */ @@ -61,9 +61,9 @@ function IonGeocoderService(options) { const geocodeProvider = defaultValue( options.geocodeProvider, - IonGeocodeProvider.DEFAULT, + IonGeocodeProviderType.DEFAULT, ); - validateIonGeocodeProvider(geocodeProvider); + validateIonGeocodeProviderType(geocodeProvider); const accessToken = defaultValue(options.accessToken, Ion.defaultAccessToken); const server = Resource.createIfNeeded( @@ -108,8 +108,8 @@ Object.defineProperties(IonGeocoderService.prototype, { /** * The geocoding service that Cesium ion API server should use to fulfill geocding requests. * @memberof IonGeocoderService.prototype - * @type {IonGeocodeProvider} - * @default IonGeocodeProvider.DEFAULT + * @type {IonGeocodeProviderType} + * @default IonGeocodeProviderType.DEFAULT */ geocodeProvider: { get: function () { @@ -118,7 +118,7 @@ Object.defineProperties(IonGeocoderService.prototype, { ); }, set: function (geocodeProvider) { - validateIonGeocodeProvider(geocodeProvider); + validateIonGeocodeProviderType(geocodeProvider); const query = { ...this._pelias.url.queryParameters, geocoder: providerToQueryParameter(geocodeProvider), diff --git a/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js b/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js index ef35c0c38e31..8378df0050d5 100644 --- a/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js +++ b/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js @@ -18,7 +18,7 @@ import Resource from "../Core/Resource.js"; * * @example * const viewer = new Cesium.Viewer("cesiumContainer", { - * geocoder: Cesium.IonGeocodeProvider.GOOGLE + * geocoder: Cesium.IonGeocodeProviderType.GOOGLE * }); * * try { @@ -33,7 +33,7 @@ import Resource from "../Core/Resource.js"; * Cesium.GoogleMaps.defaultApiKey = "your-api-key"; * * const viewer = new Cesium.Viewer("cesiumContainer". { - * geocoder: Cesium.IonGeocodeProvider.GOOGLE + * geocoder: Cesium.IonGeocodeProviderType.GOOGLE * }); * * try { diff --git a/packages/engine/Specs/Core/IonGeocoderServiceSpec.js b/packages/engine/Specs/Core/IonGeocoderServiceSpec.js index 0bdc02b18692..d2254501bf59 100644 --- a/packages/engine/Specs/Core/IonGeocoderServiceSpec.js +++ b/packages/engine/Specs/Core/IonGeocoderServiceSpec.js @@ -3,7 +3,7 @@ import { GeocoderService, GeocodeType, Ion, - IonGeocodeProvider, + IonGeocodeProviderType, IonGeocoderService, } from "../../index.js"; @@ -28,13 +28,13 @@ describe("Core/IonGeocoderService", function () { expect(service._accessToken).toEqual(Ion.defaultAccessToken); expect(service._server.url).toEqual(Ion.defaultServer.url); - expect(service.geocodeProvider).toEqual(IonGeocodeProvider.DEFAULT); + expect(service.geocodeProvider).toEqual(IonGeocodeProviderType.DEFAULT); }); it("creates with specified parameters", function () { const accessToken = "123456"; const server = "http://not.ion.invalid/"; - const geocodeProvider = IonGeocodeProvider.GOOGLE; + const geocodeProvider = IonGeocodeProviderType.GOOGLE; const service = new IonGeocoderService({ accessToken: accessToken, @@ -74,30 +74,30 @@ describe("Core/IonGeocoderService", function () { it("setting geocodeProvider updates _pelias.url for GOOGLE", function () { const service = new IonGeocoderService({ scene, - geocoder: IonGeocodeProvider.DEFAULT, + geocoder: IonGeocodeProviderType.DEFAULT, }); - service.geocodeProvider = IonGeocodeProvider.GOOGLE; + service.geocodeProvider = IonGeocodeProviderType.GOOGLE; expect(service._pelias.url.queryParameters["geocoder"]).toEqual("google"); }); it("setting geocodeProvider updates _pelias.url for BING", function () { const service = new IonGeocoderService({ scene, - geocoder: IonGeocodeProvider.DEFAULT, + geocoder: IonGeocodeProviderType.DEFAULT, }); - service.geocodeProvider = IonGeocodeProvider.BING; + service.geocodeProvider = IonGeocodeProviderType.BING; expect(service._pelias.url.queryParameters["geocoder"]).toEqual("bing"); }); it("setting geocodeProvider updates _pelias.url for DEFAULT", function () { const service = new IonGeocoderService({ scene, - geocoder: IonGeocodeProvider.GOOGLE, + geocoder: IonGeocodeProviderType.GOOGLE, }); - service.geocodeProvider = IonGeocodeProvider.DEFAULT; + service.geocodeProvider = IonGeocodeProviderType.DEFAULT; const queryParameters = service._pelias.url.queryParameters; expect(queryParameters.geocoder).toBeUndefined(); // Make sure that it isn't 'geocoder: undefined' diff --git a/packages/widgets/Source/Viewer/Viewer.js b/packages/widgets/Source/Viewer/Viewer.js index 44e32292f0ab..a1d1cbd970e6 100644 --- a/packages/widgets/Source/Viewer/Viewer.js +++ b/packages/widgets/Source/Viewer/Viewer.js @@ -281,7 +281,7 @@ function enableVRUI(viewer, enabled) { * @property {boolean} [baseLayerPicker=true] If set to false, the BaseLayerPicker widget will not be created. * @property {boolean} [fullscreenButton=true] If set to false, the FullscreenButton widget will not be created. * @property {boolean} [vrButton=false] If set to true, the VRButton widget will be created. - * @property {boolean|IonGeocodeProvider|GeocoderService[]} [geocoder=IonGeocodeProvider.DEFAULT] The geocoding service or services to use when searching with the Geocoder widget. If set to false, the Geocoder widget will not be created. + * @property {boolean|IonGeocodeProviderType|GeocoderService[]} [geocoder=IonGeocodeProviderType.DEFAULT] The geocoding service or services to use when searching with the Geocoder widget. If set to false, the Geocoder widget will not be created. * @property {boolean} [homeButton=true] If set to false, the HomeButton widget will not be created. * @property {boolean} [infoBox=true] If set to false, the InfoBox widget will not be created. * @property {boolean} [sceneModePicker=true] If set to false, the SceneModePicker widget will not be created. diff --git a/packages/widgets/Specs/Viewer/ViewerSpec.js b/packages/widgets/Specs/Viewer/ViewerSpec.js index 8bb508d100b7..01eff7afc8b9 100644 --- a/packages/widgets/Specs/Viewer/ViewerSpec.js +++ b/packages/widgets/Specs/Viewer/ViewerSpec.js @@ -18,7 +18,7 @@ import { ImageryLayerCollection, SceneMode, ShadowMode, - IonGeocodeProvider, + IonGeocodeProviderType, IonGeocoderService, } from "@cesium/engine"; @@ -356,16 +356,16 @@ describe( expect(viewer.geocoder.viewModel._geocoderServices.length).toBe(1); }); - it("constructs geocoder with IonGeocodeProvider", function () { + it("constructs geocoder with IonGeocodeProviderType", function () { viewer = createViewer(container, { - geocoder: IonGeocodeProvider.GOOGLE, + geocoder: IonGeocodeProviderType.GOOGLE, }); expect(viewer.geocoder).toBeDefined(); expect(viewer.geocoder.viewModel._geocoderServices.length).toBe(1); const geocoderService = viewer.geocoder.viewModel._geocoderServices[0]; expect(geocoderService).toBeInstanceOf(IonGeocoderService); expect(geocoderService.geocodeProvider).toEqual( - IonGeocodeProvider.GOOGLE, + IonGeocodeProviderType.GOOGLE, ); }); From b511f59965055dc1de363647e8ca078287300e47 Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Tue, 19 Nov 2024 16:24:29 -0500 Subject: [PATCH 11/17] Remove geocoder from sandcastles with non bing/google map data --- Apps/Sandcastle/gallery/Imagery Layers Manipulation.html | 2 +- Apps/Sandcastle/gallery/Imagery Layers Split.html | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html b/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html index 48a3efc177ab..9b1f026cdbab 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Manipulation.html @@ -106,7 +106,7 @@ //Sandcastle_Begin const viewer = new Cesium.Viewer("cesiumContainer", { baseLayerPicker: false, - geocoder: Cesium.IonGeocodeProviderType.BING, + geocoder: false, }); const imageryLayers = viewer.imageryLayers; diff --git a/Apps/Sandcastle/gallery/Imagery Layers Split.html b/Apps/Sandcastle/gallery/Imagery Layers Split.html index 37927116fc29..15375661bb5f 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Split.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Split.html @@ -58,6 +58,7 @@ ), baseLayerPicker: false, infoBox: false, + geocoder: false, }); const layers = viewer.imageryLayers; From 5014ecb0052f1123f87bf92bfda14f386c3ff3fe Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Wed, 20 Nov 2024 10:56:23 -0500 Subject: [PATCH 12/17] Add links to terms of service --- packages/engine/Source/Core/BingMapsGeocoderService.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/engine/Source/Core/BingMapsGeocoderService.js b/packages/engine/Source/Core/BingMapsGeocoderService.js index 647658fcd2d3..bd299d874026 100644 --- a/packages/engine/Source/Core/BingMapsGeocoderService.js +++ b/packages/engine/Source/Core/BingMapsGeocoderService.js @@ -10,6 +10,8 @@ const url = "https://dev.virtualearth.net/REST/v1/Locations"; /** * Provides geocoding through Bing Maps. + * + * @see {@link https://www.microsoft.com/en-us/maps/bing-maps/product|Microsoft Bing Maps Platform APIs Terms Of Use} * @alias BingMapsGeocoderService * @constructor * From c05d122b36581becdd047db6c8282558435bd99b Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Wed, 20 Nov 2024 10:56:44 -0500 Subject: [PATCH 13/17] More renames of geocodeProvider -> geocodeProviderType --- .../engine/Source/Core/IonGeocoderService.js | 30 +++++++++++-------- .../Specs/Core/IonGeocoderServiceSpec.js | 30 +++++++++---------- packages/widgets/Source/Viewer/Viewer.js | 5 +++- packages/widgets/Specs/Viewer/ViewerSpec.js | 2 +- 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/packages/engine/Source/Core/IonGeocoderService.js b/packages/engine/Source/Core/IonGeocoderService.js index db0cfe3dfc81..c91785229f04 100644 --- a/packages/engine/Source/Core/IonGeocoderService.js +++ b/packages/engine/Source/Core/IonGeocoderService.js @@ -9,17 +9,19 @@ import PeliasGeocoderService from "./PeliasGeocoderService.js"; import Resource from "./Resource.js"; /** - * @param {*} geocodeProvider + * @param {*} geocodeProviderType * @throws {DeveloperError} * @private */ -function validateIonGeocodeProviderType(geocodeProvider) { +function validateIonGeocodeProviderType(geocodeProviderType) { if ( !Object.values(IonGeocodeProviderType).some( - (value) => value === geocodeProvider, + (value) => value === geocodeProviderType, ) ) { - throw new DeveloperError(`Invalid geocodeProvider: "${geocodeProvider}"`); + throw new DeveloperError( + `Invalid geocodeProviderType: "${geocodeProviderType}"`, + ); } } @@ -48,7 +50,7 @@ function queryParameterToProvider(parameter) { * @param {Scene} options.scene The scene * @param {string} [options.accessToken=Ion.defaultAccessToken] The access token to use. * @param {string|Resource} [options.server=Ion.defaultServer] The resource to the Cesium ion API server. - * @param {IonGeocodeProviderType} [options.geocodeProvider=IonGeocodeProviderType.DEFAULT] The geocoder the Cesium ion API server should use to fulfill this request. + * @param {IonGeocodeProviderType} [options.geocodeProviderType=IonGeocodeProviderType.DEFAULT] The geocoder the Cesium ion API server should use to fulfill this request. * * @see Ion */ @@ -59,11 +61,11 @@ function IonGeocoderService(options) { Check.typeOf.object("options.scene", options.scene); //>>includeEnd('debug'); - const geocodeProvider = defaultValue( - options.geocodeProvider, + const geocodeProviderType = defaultValue( + options.geocodeProviderType, IonGeocodeProviderType.DEFAULT, ); - validateIonGeocodeProviderType(geocodeProvider); + validateIonGeocodeProviderType(geocodeProviderType); const accessToken = defaultValue(options.accessToken, Ion.defaultAccessToken); const server = Resource.createIfNeeded( @@ -89,7 +91,9 @@ function IonGeocoderService(options) { this._accessToken = accessToken; this._server = server; this._pelias = new PeliasGeocoderService(searchEndpoint); - this.geocodeProvider = geocodeProvider; + // geocoderProviderType isn't stored here directly but instead relies on the + // query parameters of this._pelias.url. Use the setter logic to update value. + this.geocodeProviderType = geocodeProviderType; } Object.defineProperties(IonGeocoderService.prototype, { @@ -111,17 +115,17 @@ Object.defineProperties(IonGeocoderService.prototype, { * @type {IonGeocodeProviderType} * @default IonGeocodeProviderType.DEFAULT */ - geocodeProvider: { + geocodeProviderType: { get: function () { return queryParameterToProvider( this._pelias.url.queryParameters["geocoder"], ); }, - set: function (geocodeProvider) { - validateIonGeocodeProviderType(geocodeProvider); + set: function (geocodeProviderType) { + validateIonGeocodeProviderType(geocodeProviderType); const query = { ...this._pelias.url.queryParameters, - geocoder: providerToQueryParameter(geocodeProvider), + geocoder: providerToQueryParameter(geocodeProviderType), }; // Delete the geocoder parameter to prevent sending &geocoder=undefined in the query if (!defined(query.geocoder)) { diff --git a/packages/engine/Specs/Core/IonGeocoderServiceSpec.js b/packages/engine/Specs/Core/IonGeocoderServiceSpec.js index d2254501bf59..719a762daffc 100644 --- a/packages/engine/Specs/Core/IonGeocoderServiceSpec.js +++ b/packages/engine/Specs/Core/IonGeocoderServiceSpec.js @@ -28,24 +28,24 @@ describe("Core/IonGeocoderService", function () { expect(service._accessToken).toEqual(Ion.defaultAccessToken); expect(service._server.url).toEqual(Ion.defaultServer.url); - expect(service.geocodeProvider).toEqual(IonGeocodeProviderType.DEFAULT); + expect(service.geocodeProviderType).toEqual(IonGeocodeProviderType.DEFAULT); }); it("creates with specified parameters", function () { const accessToken = "123456"; const server = "http://not.ion.invalid/"; - const geocodeProvider = IonGeocodeProviderType.GOOGLE; + const geocodeProviderType = IonGeocodeProviderType.GOOGLE; const service = new IonGeocoderService({ accessToken: accessToken, server: server, scene: scene, - geocodeProvider, + geocodeProviderType, }); expect(service._accessToken).toEqual(accessToken); expect(service._server.url).toEqual(server); - expect(service.geocodeProvider).toEqual(geocodeProvider); + expect(service.geocodeProviderType).toEqual(geocodeProviderType); }); it("calls inner geocoder and returns result", async function () { @@ -71,46 +71,46 @@ describe("Core/IonGeocoderService", function () { expect(service.credit).toBeUndefined(); }); - it("setting geocodeProvider updates _pelias.url for GOOGLE", function () { + it("setting geocodeProviderType updates _pelias.url for GOOGLE", function () { const service = new IonGeocoderService({ scene, geocoder: IonGeocodeProviderType.DEFAULT, }); - service.geocodeProvider = IonGeocodeProviderType.GOOGLE; + service.geocodeProviderType = IonGeocodeProviderType.GOOGLE; expect(service._pelias.url.queryParameters["geocoder"]).toEqual("google"); }); - it("setting geocodeProvider updates _pelias.url for BING", function () { + it("setting geocodeProviderType updates _pelias.url for BING", function () { const service = new IonGeocoderService({ scene, geocoder: IonGeocodeProviderType.DEFAULT, }); - service.geocodeProvider = IonGeocodeProviderType.BING; + service.geocodeProviderType = IonGeocodeProviderType.BING; expect(service._pelias.url.queryParameters["geocoder"]).toEqual("bing"); }); - it("setting geocodeProvider updates _pelias.url for DEFAULT", function () { + it("setting geocodeProviderType updates _pelias.url for DEFAULT", function () { const service = new IonGeocoderService({ scene, geocoder: IonGeocodeProviderType.GOOGLE, }); - service.geocodeProvider = IonGeocodeProviderType.DEFAULT; + service.geocodeProviderType = IonGeocodeProviderType.DEFAULT; const queryParameters = service._pelias.url.queryParameters; expect(queryParameters.geocoder).toBeUndefined(); // Make sure that it isn't 'geocoder: undefined' expect(queryParameters.hasOwnProperty("geocoder")).toBeFalse(); }); - it("throws if setting invalid geocodeProvider", function () { + it("throws if setting invalid geocodeProviderType", function () { expect( - () => new IonGeocoderService({ scene, geocodeProvider: "junk" }), - ).toThrowError(DeveloperError, /Invalid geocodeProvider/); + () => new IonGeocoderService({ scene, geocodeProviderType: "junk" }), + ).toThrowError(DeveloperError, /Invalid geocodeProviderType/); expect(() => { const service = new IonGeocoderService({ scene }); - service.geocodeProvider = "junk"; - }).toThrowError(DeveloperError, /Invalid geocodeProvider/); + service.geocodeProviderType = "junk"; + }).toThrowError(DeveloperError, /Invalid geocodeProviderType/); }); }); diff --git a/packages/widgets/Source/Viewer/Viewer.js b/packages/widgets/Source/Viewer/Viewer.js index ae39c71dfe8a..b00646389215 100644 --- a/packages/widgets/Source/Viewer/Viewer.js +++ b/packages/widgets/Source/Viewer/Viewer.js @@ -570,7 +570,10 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to let geocoderService; if (typeof options.geocoder === "string") { geocoderService = [ - new IonGeocoderService({ scene, geocodeProvider: options.geocoder }), + new IonGeocoderService({ + scene, + geocodeProviderType: options.geocoder, + }), ]; } else if ( defined(options.geocoder) && diff --git a/packages/widgets/Specs/Viewer/ViewerSpec.js b/packages/widgets/Specs/Viewer/ViewerSpec.js index f40e3bba1b32..822df41c034b 100644 --- a/packages/widgets/Specs/Viewer/ViewerSpec.js +++ b/packages/widgets/Specs/Viewer/ViewerSpec.js @@ -364,7 +364,7 @@ describe( expect(viewer.geocoder.viewModel._geocoderServices.length).toBe(1); const geocoderService = viewer.geocoder.viewModel._geocoderServices[0]; expect(geocoderService).toBeInstanceOf(IonGeocoderService); - expect(geocoderService.geocodeProvider).toEqual( + expect(geocoderService.geocodeProviderType).toEqual( IonGeocodeProviderType.GOOGLE, ); }); From 2ca3ae7aac6e139da3249d8e03d296bf5c60a428 Mon Sep 17 00:00:00 2001 From: "jerome.fayot" Date: Tue, 19 Nov 2024 07:23:23 +0100 Subject: [PATCH 14/17] feat: added TrackingReferenceFrame.ENU --- Apps/Sandcastle/gallery/Entity tracking.html | 7 +++++++ Apps/Sandcastle/gallery/Interpolation.html | 2 +- .../engine/Source/Core/TrackingReferenceFrame.js | 9 +++++++++ packages/engine/Source/DataSources/EntityView.js | 10 ++++++---- .../engine/Specs/DataSources/EntityViewSpec.js | 15 +++++++++++++++ 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/Apps/Sandcastle/gallery/Entity tracking.html b/Apps/Sandcastle/gallery/Entity tracking.html index f5f21aa22a47..6e894c642e9d 100644 --- a/Apps/Sandcastle/gallery/Entity tracking.html +++ b/Apps/Sandcastle/gallery/Entity tracking.html @@ -94,6 +94,13 @@ drone.trackingReferenceFrame = Cesium.TrackingReferenceFrame.VELOCITY; }, }, + { + text: "Tracking reference frame: East-North-Up", + onselect: function () { + satellite.trackingReferenceFrame = Cesium.TrackingReferenceFrame.ENU; + drone.trackingReferenceFrame = Cesium.TrackingReferenceFrame.ENU; + }, + }, ]); //Sandcastle_End }; diff --git a/Apps/Sandcastle/gallery/Interpolation.html b/Apps/Sandcastle/gallery/Interpolation.html index 567ec12627ea..f21a5dd259c3 100644 --- a/Apps/Sandcastle/gallery/Interpolation.html +++ b/Apps/Sandcastle/gallery/Interpolation.html @@ -158,7 +158,7 @@ { text: "Tracking reference frame: East-North-Up", onselect: function () { - entity.trackingReferenceFrame = Cesium.TrackingReferenceFrame.EAST_NORTH_UP; + entity.trackingReferenceFrame = Cesium.TrackingReferenceFrame.ENU; }, }, { diff --git a/packages/engine/Source/Core/TrackingReferenceFrame.js b/packages/engine/Source/Core/TrackingReferenceFrame.js index 4ad418e96b7a..a7e735b8e1e5 100644 --- a/packages/engine/Source/Core/TrackingReferenceFrame.js +++ b/packages/engine/Source/Core/TrackingReferenceFrame.js @@ -36,5 +36,14 @@ const TrackingReferenceFrame = { * @constant */ VELOCITY: 2, + + /** + * The entity's local East-North-Up reference frame. + * When selected, the auto-detect algorithm is overridden. + * + * @type {number} + * @constant + */ + ENU: 3, }; export default Object.freeze(TrackingReferenceFrame); diff --git a/packages/engine/Source/DataSources/EntityView.js b/packages/engine/Source/DataSources/EntityView.js index bc759b53dbd6..9e7ae33234b5 100644 --- a/packages/engine/Source/DataSources/EntityView.js +++ b/packages/engine/Source/DataSources/EntityView.js @@ -269,7 +269,12 @@ function updateTransform( rotationScratch, ); Matrix4.fromRotationTranslation(rotation, cartesian, transform); - } else if (hasBasis) { + } else if ( + trackingReferenceFrame === TrackingReferenceFrame.ENU || + !hasBasis + ) { + Transforms.eastNorthUpToFixedFrame(cartesian, ellipsoid, transform); + } else { transform[0] = xBasis.x; transform[1] = xBasis.y; transform[2] = xBasis.z; @@ -286,9 +291,6 @@ function updateTransform( transform[13] = cartesian.y; transform[14] = cartesian.z; transform[15] = 0.0; - } else { - // Stationary or slow-moving, low-altitude objects use East-North-Up. - Transforms.eastNorthUpToFixedFrame(cartesian, ellipsoid, transform); } camera._setTransform(transform); diff --git a/packages/engine/Specs/DataSources/EntityViewSpec.js b/packages/engine/Specs/DataSources/EntityViewSpec.js index 2aa12913f9e5..61223cc1dd0b 100644 --- a/packages/engine/Specs/DataSources/EntityViewSpec.js +++ b/packages/engine/Specs/DataSources/EntityViewSpec.js @@ -83,6 +83,10 @@ describe( entity.trackingReferenceFrame = TrackingReferenceFrame.VELOCITY; view.update(JulianDate.now()); expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.ENU; + view.update(JulianDate.now()); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); }); it("uses entity bounding sphere", function () { @@ -115,6 +119,13 @@ describe( new BoundingSphere(new Cartesian3(3, 4, 5), 6), ); expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.ENU; + view.update( + JulianDate.now(), + new BoundingSphere(new Cartesian3(3, 4, 5), 6), + ); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); }); it("uses entity viewFrom if available and boundingsphere is supplied", function () { @@ -140,6 +151,10 @@ describe( entity.trackingReferenceFrame = TrackingReferenceFrame.VELOCITY; view.update(JulianDate.now()); expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); + + entity.trackingReferenceFrame = TrackingReferenceFrame.ENU; + view.update(JulianDate.now()); + expect(view.scene.camera.position).toEqualEpsilon(sampleOffset, 1e-10); }); it("update throws without time parameter", function () { From 2715500bf1981e9aeae4595d9c98b342c70f5411 Mon Sep 17 00:00:00 2001 From: "jerome.fayot" Date: Thu, 21 Nov 2024 07:20:05 +0100 Subject: [PATCH 15/17] doc: updated CHANGES.md and TrackingReferenceFrame documentation --- CHANGES.md | 6 +++++- .../Source/Core/TrackingReferenceFrame.js | 20 ++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6553014c59d6..8b86cea1cf1d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,7 +7,11 @@ ##### Additions :tada: - Added `getSample` to `SampledProperty` to get the time of samples. [#12253](https://github.com/CesiumGS/cesium/pull/12253) -- Added `Entity.trackingReferenceFrame` property to allow tracking entities in their own inertial reference frame. [#12194](https://github.com/CesiumGS/cesium/pull/12194) +- Added `Entity.trackingReferenceFrame` property to allow tracking entities in various reference frames. [#12194](https://github.com/CesiumGS/cesium/pull/12194), [#12314](https://github.com/CesiumGS/cesium/pull/12314) + - `TrackingReferenceFrame.AUTODETECT` (default): uses either VVLH or ENU dependeding on entity's dynamic. Use `TrackingReferenceFrame.ENU` if your camera orientation flips abruptly from time to time. + - `TrackingReferenceFrame.ENU`: uses the entity's local East-North-Up reference frame. + - `TrackingReferenceFrame.INERTIAL`: uses the entity's inertial reference frame. + - `TrackingReferenceFrame.VELOCITY`: uses entity's `VelocityOrientationProperty` as orientation. ##### Fixes :wrench: diff --git a/packages/engine/Source/Core/TrackingReferenceFrame.js b/packages/engine/Source/Core/TrackingReferenceFrame.js index a7e735b8e1e5..d16be08b853b 100644 --- a/packages/engine/Source/Core/TrackingReferenceFrame.js +++ b/packages/engine/Source/Core/TrackingReferenceFrame.js @@ -17,33 +17,29 @@ const TrackingReferenceFrame = { AUTODETECT: 0, /** - * The entity's inertial reference frame. If entity has no defined orientation - * property, a {@link VelocityOrientationProperty} is used instead, thus - * falling back to TrackingReferenceFrame.VELOCITY. - * When selected, the auto-detect algorithm is overridden. + * The entity's local East-North-Up reference frame. * * @type {number} * @constant */ - INERTIAL: 1, + ENU: 1, /** - * The entity's inertial reference frame with orientation fixed to its - * {@link VelocityOrientationProperty}, ignoring its own orientation. - * When selected, the auto-detect algorithm is overridden. + * The entity's inertial reference frame. If entity has no defined orientation + * property, it falls back to auto-detect algorithm. * * @type {number} * @constant */ - VELOCITY: 2, + INERTIAL: 2, /** - * The entity's local East-North-Up reference frame. - * When selected, the auto-detect algorithm is overridden. + * The entity's inertial reference frame with orientation fixed to its + * {@link VelocityOrientationProperty}, ignoring its own orientation. * * @type {number} * @constant */ - ENU: 3, + VELOCITY: 3, }; export default Object.freeze(TrackingReferenceFrame); From 8a20ef041ac72e720a80fbfd59e611ce248ffa61 Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Thu, 21 Nov 2024 16:59:58 -0500 Subject: [PATCH 16/17] Add one time warning and deprecation --- .../3D Tiles Vertical Exaggeration.html | 5 +- Apps/Sandcastle/gallery/AEC Clipping.html | 5 +- .../gallery/Clamp Entities to Ground.html | 5 +- Apps/Sandcastle/gallery/Clipping Regions.html | 5 +- ...alistic 3D Tiles with Building Insert.html | 5 +- .../Google Photorealistic 3D Tiles.html | 5 +- .../gallery/development/3D Tiles Picking.html | 5 +- CHANGES.md | 4 ++ .../createGooglePhotorealistic3DTileset.js | 63 ++++++++++++++----- 9 files changed, 81 insertions(+), 21 deletions(-) diff --git a/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html b/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html index 292e07945f11..41f67a60a1b6 100644 --- a/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html +++ b/Apps/Sandcastle/gallery/3D Tiles Vertical Exaggeration.html @@ -105,7 +105,10 @@

Loading...

// Add Photorealistic 3D Tiles try { - const tileset = await Cesium.createGooglePhotorealistic3DTileset(); + const tileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); scene.primitives.add(tileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/AEC Clipping.html b/Apps/Sandcastle/gallery/AEC Clipping.html index 57c381068f9d..d373bd2a589a 100644 --- a/Apps/Sandcastle/gallery/AEC Clipping.html +++ b/Apps/Sandcastle/gallery/AEC Clipping.html @@ -49,7 +49,10 @@ // Add Photorealistic 3D Tiles let googleTileset; try { - googleTileset = await Cesium.createGooglePhotorealistic3DTileset(); + googleTileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); viewer.scene.primitives.add(googleTileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/Clamp Entities to Ground.html b/Apps/Sandcastle/gallery/Clamp Entities to Ground.html index 07b1f9afd3d9..e38e8709c464 100644 --- a/Apps/Sandcastle/gallery/Clamp Entities to Ground.html +++ b/Apps/Sandcastle/gallery/Clamp Entities to Ground.html @@ -57,7 +57,10 @@ let worldTileset; try { - worldTileset = await Cesium.createGooglePhotorealistic3DTileset(); + worldTileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); viewer.scene.primitives.add(worldTileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/Clipping Regions.html b/Apps/Sandcastle/gallery/Clipping Regions.html index 97dba26b3ce9..8f15df8f3c44 100644 --- a/Apps/Sandcastle/gallery/Clipping Regions.html +++ b/Apps/Sandcastle/gallery/Clipping Regions.html @@ -60,7 +60,10 @@ let worldTileset; try { - worldTileset = await Cesium.createGooglePhotorealistic3DTileset(); + worldTileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); scene.primitives.add(worldTileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html index d93b4085a064..a75c993a8afa 100644 --- a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html +++ b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles with Building Insert.html @@ -43,7 +43,10 @@ // Add Photorealistic 3D Tiles try { - const googleTileset = await Cesium.createGooglePhotorealistic3DTileset(); + const googleTileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); viewer.scene.primitives.add(googleTileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html index 59eec45e543f..2f9da653dc9c 100644 --- a/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html +++ b/Apps/Sandcastle/gallery/Google Photorealistic 3D Tiles.html @@ -43,7 +43,10 @@ // Add Photorealistic 3D Tiles try { - const tileset = await Cesium.createGooglePhotorealistic3DTileset(); + const tileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); viewer.scene.primitives.add(tileset); } catch (error) { console.log(`Error loading Photorealistic 3D Tiles tileset. diff --git a/Apps/Sandcastle/gallery/development/3D Tiles Picking.html b/Apps/Sandcastle/gallery/development/3D Tiles Picking.html index 10c3b2367a66..3cfdf92c9102 100644 --- a/Apps/Sandcastle/gallery/development/3D Tiles Picking.html +++ b/Apps/Sandcastle/gallery/development/3D Tiles Picking.html @@ -44,7 +44,10 @@ onselect: async () => { scene.primitives.remove(tileset); try { - tileset = await Cesium.createGooglePhotorealistic3DTileset(); + tileset = await Cesium.createGooglePhotorealistic3DTileset({ + // Only the Google Geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of the viewer constructor options to IonGeocodeProviderType.GOOGLE. + onlyUsingWithGoogleGeocoder: true, + }); scene.primitives.add(tileset); } catch (error) { console.log(error); diff --git a/CHANGES.md b/CHANGES.md index 454c7f67a5f0..4c9228255cea 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,10 @@ - Fix label rendering bug in WebGL1 contexts. [#12301](https://github.com/CesiumGS/cesium/pull/12301) - Added `GoogleGeocoderService` for standalone usage of Google geocoder. [#12299](https://github.com/CesiumGS/cesium/pull/12299) +##### Deprecated :hourglass_flowing_sand: + +- `createGooglePhotorealistic3DTileset(key)` has been deprecated. Use `createGooglePhotorealistic3DTileset({key})` instead. It will be removed in 1.126. + #### @cesium/widgets ##### Additions :tada: diff --git a/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js b/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js index 8378df0050d5..9c7bad99e30d 100644 --- a/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js +++ b/packages/engine/Source/Scene/createGooglePhotorealistic3DTileset.js @@ -4,14 +4,24 @@ import defined from "../Core/defined.js"; import IonResource from "../Core/IonResource.js"; import GoogleMaps from "../Core/GoogleMaps.js"; import Resource from "../Core/Resource.js"; +import oneTimeWarning from "../Core/oneTimeWarning.js"; +import deprecationWarning from "../Core/deprecationWarning.js"; /** - * Creates a {@link Cesium3DTileset} instance for the Google Photorealistic 3D Tiles tileset. + * Creates a {@link Cesium3DTileset} instance for the Google Photorealistic 3D + * Tiles tileset. + * + * Google Photorealistic 3D Tiles can only be used with the Google geocoder. To + * confirm that you are aware of this restriction pass + * `usingOnlyWithGoogleGeocoder: true` to the apiOptions. Otherwise a one time + * warning will be displayed when this function is called. * * @function * - * @param {string} [key=GoogleMaps.defaultApiKey] Your API key to access Google Photorealistic 3D Tiles. See {@link https://developers.google.com/maps/documentation/javascript/get-api-key} for instructions on how to create your own key. - * @param {Cesium3DTileset.ConstructorOptions} [options] An object describing initialization options. + * @param {object} [apiOptions] + * @param {string} [apiOptions.key=GoogleMaps.defaultApiKey] Your API key to access Google Photorealistic 3D Tiles. See {@link https://developers.google.com/maps/documentation/javascript/get-api-key} for instructions on how to create your own key. + * @param {true} [apiOptions.onlyUsingWithGoogleGeocoder] Confirmation that this tileset will only be used with the Google geocoder. + * @param {Cesium3DTileset.ConstructorOptions} [tilesetOptions] An object describing initialization options. * @returns {Promise} * * @see GoogleMaps @@ -22,7 +32,9 @@ import Resource from "../Core/Resource.js"; * }); * * try { - * const tileset = await Cesium.createGooglePhotorealistic3DTileset(); + * const tileset = await Cesium.createGooglePhotorealistic3DTileset({ + * onlyUsingWithGoogleGeocoder: true, + * }); * viewer.scene.primitives.add(tileset)); * } catch (error) { * console.log(`Error creating tileset: ${error}`); @@ -37,24 +49,47 @@ import Resource from "../Core/Resource.js"; * }); * * try { - * const tileset = await Cesium.createGooglePhotorealistic3DTileset(); + * const tileset = await Cesium.createGooglePhotorealistic3DTileset({ + * onlyUsingWithGoogleGeocoder: true, + * }); * viewer.scene.primitives.add(tileset)); * } catch (error) { * console.log(`Error creating tileset: ${error}`); * } */ -async function createGooglePhotorealistic3DTileset(key, options) { - options = defaultValue(options, {}); - options.cacheBytes = defaultValue(options.cacheBytes, 1536 * 1024 * 1024); - options.maximumCacheOverflowBytes = defaultValue( - options.maximumCacheOverflowBytes, +async function createGooglePhotorealistic3DTileset(apiOptions, tilesetOptions) { + tilesetOptions = defaultValue(tilesetOptions, {}); + tilesetOptions.cacheBytes = defaultValue( + tilesetOptions.cacheBytes, + 1536 * 1024 * 1024, + ); + tilesetOptions.maximumCacheOverflowBytes = defaultValue( + tilesetOptions.maximumCacheOverflowBytes, 1024 * 1024 * 1024, ); - options.enableCollision = defaultValue(options.enableCollision, true); + tilesetOptions.enableCollision = defaultValue( + tilesetOptions.enableCollision, + true, + ); - key = defaultValue(key, GoogleMaps.defaultApiKey); + apiOptions = defaultValue(apiOptions, defaultValue.EMPTY_OBJECT); + if (typeof apiOptions === "string") { + deprecationWarning( + "createGooglePhotorealistic3DTileset(key)", + "createGooglePhotorealistic3DTileset(key) has been deprecated. It is replaced by createGooglePhotorealistic3DTileset({key}). It will be removed in Cesium 1.126.", + ); + apiOptions = { key: apiOptions }; + } + if (!apiOptions.onlyUsingWithGoogleGeocoder) { + oneTimeWarning( + "google-tiles-with-google-geocoder", + "Only the Google geocoder can be used with Google Photorealistic 3D Tiles. Set the `geocode` property of Viewer constructor options. You can set additionalOptions.onlyUsingWithGoogleGeocoder to hide this warning once you have configured the geocoder.", + ); + } + + const key = defaultValue(apiOptions.key, GoogleMaps.defaultApiKey); if (!defined(key)) { - return requestCachedIonTileset(options); + return requestCachedIonTileset(tilesetOptions); } let credits; @@ -71,7 +106,7 @@ async function createGooglePhotorealistic3DTileset(key, options) { credits: credits, }); - return Cesium3DTileset.fromUrl(resource, options); + return Cesium3DTileset.fromUrl(resource, tilesetOptions); } const metadataCache = {}; From 154c7051dca5088e711123bdf08308899bd5d8fe Mon Sep 17 00:00:00 2001 From: Mark Dane Date: Fri, 22 Nov 2024 10:11:12 -0500 Subject: [PATCH 17/17] Minor PR feedback --- Apps/Sandcastle/gallery/Clipping Regions.html | 1 + Apps/Sandcastle/gallery/development/3D Tiles Picking.html | 1 + packages/engine/Source/Core/IonGeocoderService.js | 2 ++ 3 files changed, 4 insertions(+) diff --git a/Apps/Sandcastle/gallery/Clipping Regions.html b/Apps/Sandcastle/gallery/Clipping Regions.html index 8f15df8f3c44..b7116fc29f17 100644 --- a/Apps/Sandcastle/gallery/Clipping Regions.html +++ b/Apps/Sandcastle/gallery/Clipping Regions.html @@ -43,6 +43,7 @@ animation: false, sceneModePicker: false, baseLayerPicker: false, + geocoder: Cesium.IonGeocoderProviderType.GOOGLE, }); const scene = viewer.scene; diff --git a/Apps/Sandcastle/gallery/development/3D Tiles Picking.html b/Apps/Sandcastle/gallery/development/3D Tiles Picking.html index 3cfdf92c9102..ce77a1cc5f35 100644 --- a/Apps/Sandcastle/gallery/development/3D Tiles Picking.html +++ b/Apps/Sandcastle/gallery/development/3D Tiles Picking.html @@ -34,6 +34,7 @@ animation: false, baseLayerPicker: false, globe: false, + geocoder: false, }); const scene = viewer.scene; diff --git a/packages/engine/Source/Core/IonGeocoderService.js b/packages/engine/Source/Core/IonGeocoderService.js index c91785229f04..f473d80005b3 100644 --- a/packages/engine/Source/Core/IonGeocoderService.js +++ b/packages/engine/Source/Core/IonGeocoderService.js @@ -65,7 +65,9 @@ function IonGeocoderService(options) { options.geocodeProviderType, IonGeocodeProviderType.DEFAULT, ); + //>>includeStart('debug', pragmas.debug); validateIonGeocodeProviderType(geocodeProviderType); + //>>includeEnd('debug'); const accessToken = defaultValue(options.accessToken, Ion.defaultAccessToken); const server = Resource.createIfNeeded(