diff --git a/CHANGES.md b/CHANGES.md index 5e8fd07ee03e..8385176fecc5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,7 @@ - Improved performance when removing primitives. [#3018](https://github.com/CesiumGS/cesium/pull/3018) - Improved performance of terrain Quadtree handling of custom data [#12907](https://github.com/CesiumGS/cesium/pull/12907) - Fixed picking of `GroundPrimitive` with multiple `PolygonGeometry` instances selecting the wrong instance. [#12978](https://github.com/CesiumGS/cesium/pull/12978) +- Fixed WMS GetFeatureInfo requests to correctly projects the results based on schema projection. [#12993](https://github.com/CesiumGS/cesium/pull/12993) ## 1.134.1 - 2025-10-10 diff --git a/Specs/Data/WMS/GetFeatureInfo-GeoJSON-mercator.json b/Specs/Data/WMS/GetFeatureInfo-GeoJSON-mercator.json new file mode 100644 index 000000000000..410a4ea6ab65 --- /dev/null +++ b/Specs/Data/WMS/GetFeatureInfo-GeoJSON-mercator.json @@ -0,0 +1,34 @@ +{ + "type": "FeatureCollection", + "features": [{ + "type": "Feature", + "id": "bores.641", + "geometry": { + "type": "Point", + "coordinates": [1406877.9886, 5326443.0126] + }, + "geometry_name": "the_geom", + "properties": { + "OBJECTID": 2956, + "FEATTYPE": "Bore", + "NAME": "TOP TANK", + "FEATREL": "1980-12-31T13:00:00Z", + "ATTRREL": "1980-12-31T13:00:00Z", + "PLANACC": 100, + "SOURCE": "GEOSCIENCE AUSTRALIA", + "CREATED": "2006-05-08T14:00:00Z", + "RETIRED": null, + "PID": 527738, + "SYMBOL": 11, + "FEATWIDTH": 0, + "ORIENTATN": 0, + "TEXTNOTE": "" + } + }], + "crs": { + "type": "EPSG", + "properties": { + "code": "3857" + } + } +} \ No newline at end of file diff --git a/packages/engine/Source/Scene/GetFeatureInfoFormat.js b/packages/engine/Source/Scene/GetFeatureInfoFormat.js index 0d9b392bae22..e6db71aac368 100644 --- a/packages/engine/Source/Scene/GetFeatureInfoFormat.js +++ b/packages/engine/Source/Scene/GetFeatureInfoFormat.js @@ -1,6 +1,8 @@ +import Cartesian3 from "../Core/Cartesian3.js"; import Cartographic from "../Core/Cartographic.js"; import defined from "../Core/defined.js"; import DeveloperError from "../Core/DeveloperError.js"; +import GeographicProjection from "../Core/GeographicProjection.js"; import RuntimeError from "../Core/RuntimeError.js"; import ImageryLayerFeatureInfo from "./ImageryLayerFeatureInfo.js"; @@ -70,8 +72,7 @@ function GetFeatureInfoFormat(type, format, callback) { this.callback = callback; } - -function geoJsonToFeatureInfo(json) { +function geoJsonToFeatureInfo(json, projection) { const result = []; const features = json.features; @@ -86,9 +87,16 @@ function geoJsonToFeatureInfo(json) { // If this is a point feature, use the coordinates of the point. if (defined(feature.geometry) && feature.geometry.type === "Point") { - const longitude = feature.geometry.coordinates[0]; - const latitude = feature.geometry.coordinates[1]; - featureInfo.position = Cartographic.fromDegrees(longitude, latitude); + const x = feature.geometry.coordinates[0]; + const y = feature.geometry.coordinates[1]; + + if (!defined(projection) || projection instanceof GeographicProjection) { + featureInfo.position = Cartographic.fromDegrees(x, y); + } else { + const positionProjected = new Cartesian3(x, y, 0); + const cartographic = projection.unproject(positionProjected); + featureInfo.position = cartographic; + } } result.push(featureInfo); diff --git a/packages/engine/Source/Scene/UrlTemplateImageryProvider.js b/packages/engine/Source/Scene/UrlTemplateImageryProvider.js index 6910b5a73fba..43f91b33850f 100644 --- a/packages/engine/Source/Scene/UrlTemplateImageryProvider.js +++ b/packages/engine/Source/Scene/UrlTemplateImageryProvider.js @@ -588,11 +588,26 @@ UrlTemplateImageryProvider.prototype.pickFeatures = function ( ++formatIndex; if (format.type === "json") { - return resource.fetchJson().then(format.callback).catch(doRequest); + return resource + .fetchJson() + .then((response) => + format.callback(response, that.tilingScheme.projection), + ) + .catch(doRequest); } else if (format.type === "xml") { - return resource.fetchXML().then(format.callback).catch(doRequest); + return resource + .fetchXML() + .then((response) => + format.callback(response, that.tilingScheme.projection), + ) + .catch(doRequest); } else if (format.type === "text" || format.type === "html") { - return resource.fetchText().then(format.callback).catch(doRequest); + return resource + .fetchText() + .then((response) => + format.callback(response, that.tilingScheme.projection), + ) + .catch(doRequest); } return resource .fetch({ diff --git a/packages/engine/Specs/Scene/WebMapServiceImageryProviderSpec.js b/packages/engine/Specs/Scene/WebMapServiceImageryProviderSpec.js index 70835d7063b5..e1281131d3cd 100644 --- a/packages/engine/Specs/Scene/WebMapServiceImageryProviderSpec.js +++ b/packages/engine/Specs/Scene/WebMapServiceImageryProviderSpec.js @@ -25,6 +25,8 @@ import { } from "../../index.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; +import WebMercatorProjection from "../../Source/Core/WebMercatorProjection.js"; +import Cartesian3 from "../../Source/Core/Cartesian3.js"; describe("Scene/WebMapServiceImageryProvider", function () { beforeEach(function () { @@ -965,6 +967,50 @@ describe("Scene/WebMapServiceImageryProvider", function () { }); }); + it("works with GeoJSON responses in mercator projection", function () { + const provider = new WebMapServiceImageryProvider({ + url: "made/up/wms/server", + layers: "someLayer", + tilingScheme: new WebMercatorTilingScheme(), + }); + + Resource._Implementations.loadWithXhr = function ( + url, + responseType, + method, + data, + headers, + deferred, + overrideMimeType, + ) { + expect(url).toContain("GetFeatureInfo"); + Resource._DefaultImplementations.loadWithXhr( + "Data/WMS/GetFeatureInfo-GeoJSON-mercator.json", + responseType, + method, + data, + headers, + deferred, + overrideMimeType, + ); + }; + const projection = new WebMercatorProjection(); + + return provider + .pickFeatures(0, 0, 0, 0.5, 0.5) + .then(function (pickResult) { + expect(pickResult.length).toBe(1); + + const firstResult = pickResult[0]; + expect(firstResult).toBeInstanceOf(ImageryLayerFeatureInfo); + expect(firstResult.name).toBe("TOP TANK"); + expect(firstResult.description).toContain("GEOSCIENCE AUSTRALIA"); + expect(firstResult.position).toEqual( + projection.unproject(new Cartesian3(1406877.9886, 5326443.0126, 0)), + ); + }); + }); + it("works with MapInfo MXP responses", function () { const provider = new WebMapServiceImageryProvider({ url: "made/up/wms/server",