-
Notifications
You must be signed in to change notification settings - Fork 362
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7146 from TerriaJS/image-server
Add ArcGis ImageServer support
- Loading branch information
Showing
25 changed files
with
2,758 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
230 changes: 230 additions & 0 deletions
230
lib/Map/ImageryProvider/ArcGisImageServerImageryProvider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
import { makeObservable } from "mobx"; | ||
import Cartesian2 from "terriajs-cesium/Source/Core/Cartesian2"; | ||
import Cartographic from "terriajs-cesium/Source/Core/Cartographic"; | ||
import Credit from "terriajs-cesium/Source/Core/Credit"; | ||
import Ellipsoid from "terriajs-cesium/Source/Core/Ellipsoid"; | ||
import CesiumEvent from "terriajs-cesium/Source/Core/Event"; | ||
import GeographicProjection from "terriajs-cesium/Source/Core/GeographicProjection"; | ||
import GeographicTilingScheme from "terriajs-cesium/Source/Core/GeographicTilingScheme"; | ||
import Math from "terriajs-cesium/Source/Core/Math"; | ||
import Rectangle from "terriajs-cesium/Source/Core/Rectangle"; | ||
import Resource from "terriajs-cesium/Source/Core/Resource"; | ||
import TilingScheme from "terriajs-cesium/Source/Core/TilingScheme"; | ||
import DiscardMissingTileImagePolicy from "terriajs-cesium/Source/Scene/DiscardMissingTileImagePolicy"; | ||
import ImageryLayerFeatureInfo from "terriajs-cesium/Source/Scene/ImageryLayerFeatureInfo"; | ||
import ImageryProvider from "terriajs-cesium/Source/Scene/ImageryProvider"; | ||
import TileDiscardPolicy from "terriajs-cesium/Source/Scene/TileDiscardPolicy"; | ||
import { JsonObject } from "../../Core/Json"; | ||
import { ImageServerIdentifyResult } from "../../Models/Catalog/Esri/ArcGisInterfaces"; | ||
|
||
interface Options { | ||
url: string; | ||
token?: string; | ||
minimumLevel?: number; | ||
maximumLevel?: number; | ||
rectangle?: Rectangle; | ||
credit: Credit | string; | ||
enablePickFeatures?: boolean; | ||
usePreCachedTiles?: boolean; | ||
tileWidth?: number; | ||
tileHeight?: number; | ||
tilingScheme?: TilingScheme; | ||
parameters?: JsonObject; | ||
} | ||
|
||
/** This is adapted from Cesium's ArcGisMapServerImageryProvider | ||
* https://github.com/CesiumGS/cesium/blob/51aae2d21014cfc28e948b1719d07f1912df9434/packages/engine/Source/Scene/ArcGisMapServerImageryProvider.js | ||
* Code licensed under the Apache License v2.0. | ||
* For details, see https://github.com/CesiumGS/cesium/blob/main/LICENSE.md | ||
*/ | ||
|
||
export default class ArcGisImageServerImageryProvider { | ||
readonly tilingScheme: TilingScheme; | ||
readonly ellipsoid: Ellipsoid; | ||
readonly tileWidth: number; | ||
readonly tileHeight: number; | ||
readonly minimumLevel: number; | ||
readonly maximumLevel: number; | ||
readonly rectangle: Rectangle; | ||
readonly errorEvent = new CesiumEvent(); | ||
readonly ready = true; | ||
readonly credit: Credit; | ||
|
||
/** Note: this can be set dynamically */ | ||
enablePickFeatures: boolean; | ||
readonly usePreCachedTiles: boolean; | ||
readonly tileDiscardPolicy: TileDiscardPolicy; | ||
readonly baseResource: Resource; | ||
|
||
readonly defaultNightAlpha = undefined; | ||
readonly defaultDayAlpha = undefined; | ||
readonly hasAlphaChannel = true; | ||
readonly defaultAlpha = undefined; | ||
readonly defaultBrightness = undefined; | ||
readonly defaultContrast = undefined; | ||
readonly defaultGamma = undefined; | ||
readonly defaultHue = undefined; | ||
readonly defaultSaturation = undefined; | ||
readonly defaultMagnificationFilter = undefined; | ||
readonly defaultMinificationFilter = undefined; | ||
readonly readyPromise = Promise.resolve(true); | ||
|
||
constructor(options: Options) { | ||
makeObservable(this); | ||
|
||
this.tilingScheme = options.tilingScheme ?? new GeographicTilingScheme(); | ||
|
||
this.rectangle = options.rectangle ?? this.tilingScheme.rectangle; | ||
this.ellipsoid = Ellipsoid.WGS84; | ||
|
||
this.tileWidth = options.tileWidth ?? 256; | ||
this.tileHeight = options.tileHeight ?? 256; | ||
|
||
this.minimumLevel = options.minimumLevel ?? 0; | ||
this.maximumLevel = options.maximumLevel ?? 25; | ||
|
||
this.ready = true; | ||
|
||
this.credit = | ||
typeof options.credit === "string" | ||
? new Credit(options.credit) | ||
: options.credit; | ||
|
||
this.enablePickFeatures = options.enablePickFeatures ?? true; | ||
this.usePreCachedTiles = options.usePreCachedTiles ?? false; | ||
|
||
this.baseResource = new Resource(options.url); | ||
this.baseResource.appendForwardSlash(); | ||
|
||
if (options.parameters) { | ||
this.baseResource.appendQueryParameters(options.parameters); | ||
} | ||
|
||
if (options.token) { | ||
this.baseResource.appendQueryParameters({ | ||
token: options.token | ||
}); | ||
} | ||
|
||
this.tileDiscardPolicy = new DiscardMissingTileImagePolicy({ | ||
missingImageUrl: this.buildImageResource(0, 0, this.maximumLevel).url, | ||
pixelsToCheck: [ | ||
new Cartesian2(0, 0), | ||
new Cartesian2(200, 20), | ||
new Cartesian2(20, 200), | ||
new Cartesian2(80, 110), | ||
new Cartesian2(160, 130) | ||
], | ||
disableCheckIfAllPixelsAreTransparent: true | ||
}); | ||
} | ||
|
||
get proxy() { | ||
return this.baseResource.proxy; | ||
} | ||
|
||
buildImageResource(x: number, y: number, level: number) { | ||
if (this.usePreCachedTiles) { | ||
return this.baseResource.getDerivedResource({ | ||
url: `tile/${level}/${y}/${x}` | ||
}); | ||
} else { | ||
const nativeRectangle = this.tilingScheme.tileXYToNativeRectangle( | ||
x, | ||
y, | ||
level | ||
); | ||
const bbox = `${nativeRectangle.west},${nativeRectangle.south},${nativeRectangle.east},${nativeRectangle.north}`; | ||
|
||
const query: JsonObject = { | ||
bbox: bbox, | ||
size: `${this.tileWidth},${this.tileHeight}`, | ||
format: "png32", | ||
transparent: true, | ||
f: "image" | ||
}; | ||
|
||
if (this.tilingScheme.projection instanceof GeographicProjection) { | ||
query.bboxSR = 4326; | ||
query.imageSR = 4326; | ||
} else { | ||
query.bboxSR = 3857; | ||
query.imageSR = 3857; | ||
} | ||
|
||
return this.baseResource.getDerivedResource({ | ||
url: "exportImage", | ||
queryParameters: query | ||
}); | ||
} | ||
} | ||
|
||
getTileCredits(): Credit[] { | ||
return []; | ||
} | ||
|
||
requestImage(x: number, y: number, level: number): any { | ||
return ImageryProvider.loadImage( | ||
this, | ||
this.buildImageResource(x, y, level) | ||
); | ||
} | ||
|
||
async pickFeatures( | ||
x: number, | ||
y: number, | ||
level: number, | ||
longitude: number, | ||
latitude: number | ||
): Promise<ImageryLayerFeatureInfo[]> { | ||
if (!this.enablePickFeatures) { | ||
return []; | ||
} | ||
|
||
let horizontal; | ||
let vertical; | ||
let sr; | ||
if (this.tilingScheme.projection instanceof GeographicProjection) { | ||
horizontal = Math.toDegrees(longitude); | ||
vertical = Math.toDegrees(latitude); | ||
sr = "4326"; | ||
} else { | ||
const projected = this.tilingScheme.projection.project( | ||
new Cartographic(longitude, latitude, 0.0) | ||
); | ||
horizontal = projected.x; | ||
vertical = projected.y; | ||
sr = "3857"; | ||
} | ||
|
||
const query = { | ||
f: "json", | ||
geometryType: "esriGeometryPoint", | ||
geometry: `{x: ${horizontal}, y: ${vertical}, spatialReference: {wkid: ${sr}}}`, | ||
// Disable catalog items - as we don't use them | ||
returnCatalogItems: false | ||
}; | ||
|
||
const resource = this.baseResource.getDerivedResource({ | ||
url: "identify", | ||
queryParameters: query | ||
}); | ||
|
||
const json = (await resource.fetchJson()) as ImageServerIdentifyResult; | ||
const result: ImageryLayerFeatureInfo[] = []; | ||
|
||
if (json.value) { | ||
const featureInfo = new ImageryLayerFeatureInfo(); | ||
featureInfo.data = json; | ||
featureInfo.name = json.name; | ||
featureInfo.properties = json.properties; | ||
featureInfo.description = json.value; | ||
|
||
result.push(featureInfo); | ||
} | ||
|
||
// Todo: handle json.catalogItems | ||
|
||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.