@vcmap/core 5.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +44 -0
- package/build/postinstall.js +44 -0
- package/index.js +139 -0
- package/package.json +92 -0
- package/src/cesium/cesium3DTileFeature.js +9 -0
- package/src/cesium/cesium3DTilePointFeature.js +9 -0
- package/src/cesium/cesiumVcsCameraPrimitive.js +146 -0
- package/src/cesium/wallpaperMaterial.js +64 -0
- package/src/ol/feature.js +47 -0
- package/src/ol/geom/circle.js +24 -0
- package/src/ol/geom/geometryCollection.js +33 -0
- package/src/ol/render/canvas/canvasTileRenderer.js +179 -0
- package/src/ol/source/ClusterEnhancedVectorSource.js +39 -0
- package/src/ol/source/VcsCluster.js +37 -0
- package/src/vcs/vcm/classRegistry.js +106 -0
- package/src/vcs/vcm/event/vcsEvent.js +89 -0
- package/src/vcs/vcm/globalCollections.js +11 -0
- package/src/vcs/vcm/interaction/abstractInteraction.js +149 -0
- package/src/vcs/vcm/interaction/coordinateAtPixel.js +102 -0
- package/src/vcs/vcm/interaction/eventHandler.js +425 -0
- package/src/vcs/vcm/interaction/featureAtPixelInteraction.js +286 -0
- package/src/vcs/vcm/interaction/featureProviderInteraction.js +54 -0
- package/src/vcs/vcm/interaction/interactionChain.js +124 -0
- package/src/vcs/vcm/interaction/interactionType.js +114 -0
- package/src/vcs/vcm/layer/buildings.js +17 -0
- package/src/vcs/vcm/layer/cesium/cesiumTilesetCesium.js +359 -0
- package/src/vcs/vcm/layer/cesium/clusterContext.js +95 -0
- package/src/vcs/vcm/layer/cesium/dataSourceCesium.js +171 -0
- package/src/vcs/vcm/layer/cesium/openStreetMapCesium.js +29 -0
- package/src/vcs/vcm/layer/cesium/pointCloudCesium.js +58 -0
- package/src/vcs/vcm/layer/cesium/rasterLayerCesium.js +110 -0
- package/src/vcs/vcm/layer/cesium/singleImageCesium.js +49 -0
- package/src/vcs/vcm/layer/cesium/terrainCesium.js +80 -0
- package/src/vcs/vcm/layer/cesium/tmsCesium.js +54 -0
- package/src/vcs/vcm/layer/cesium/vectorCesium.js +255 -0
- package/src/vcs/vcm/layer/cesium/vectorContext.js +167 -0
- package/src/vcs/vcm/layer/cesium/vectorRasterTileCesium.js +116 -0
- package/src/vcs/vcm/layer/cesium/vectorTileImageryProvider.js +246 -0
- package/src/vcs/vcm/layer/cesium/wmsCesium.js +71 -0
- package/src/vcs/vcm/layer/cesium/wmtsCesium.js +101 -0
- package/src/vcs/vcm/layer/cesium/x3dmHelper.js +22 -0
- package/src/vcs/vcm/layer/cesiumTileset.js +376 -0
- package/src/vcs/vcm/layer/czml.js +141 -0
- package/src/vcs/vcm/layer/dataSource.js +259 -0
- package/src/vcs/vcm/layer/featureLayer.js +261 -0
- package/src/vcs/vcm/layer/featureStore.js +647 -0
- package/src/vcs/vcm/layer/featureStoreChanges.js +360 -0
- package/src/vcs/vcm/layer/featureStoreState.js +19 -0
- package/src/vcs/vcm/layer/featureVisibility.js +435 -0
- package/src/vcs/vcm/layer/geojson.js +185 -0
- package/src/vcs/vcm/layer/geojsonHelpers.js +450 -0
- package/src/vcs/vcm/layer/globalHider.js +157 -0
- package/src/vcs/vcm/layer/layer.js +752 -0
- package/src/vcs/vcm/layer/layerImplementation.js +102 -0
- package/src/vcs/vcm/layer/layerState.js +17 -0
- package/src/vcs/vcm/layer/layerSymbols.js +6 -0
- package/src/vcs/vcm/layer/oblique/layerOblique.js +76 -0
- package/src/vcs/vcm/layer/oblique/obliqueHelpers.js +175 -0
- package/src/vcs/vcm/layer/oblique/vectorOblique.js +469 -0
- package/src/vcs/vcm/layer/openStreetMap.js +194 -0
- package/src/vcs/vcm/layer/openlayers/layerOpenlayers.js +79 -0
- package/src/vcs/vcm/layer/openlayers/openStreetMapOpenlayers.js +27 -0
- package/src/vcs/vcm/layer/openlayers/rasterLayerOpenlayers.js +121 -0
- package/src/vcs/vcm/layer/openlayers/singleImageOpenlayers.js +49 -0
- package/src/vcs/vcm/layer/openlayers/tileDebugOpenlayers.js +39 -0
- package/src/vcs/vcm/layer/openlayers/tmsOpenlayers.js +62 -0
- package/src/vcs/vcm/layer/openlayers/vectorOpenlayers.js +118 -0
- package/src/vcs/vcm/layer/openlayers/vectorTileOpenlayers.js +177 -0
- package/src/vcs/vcm/layer/openlayers/wmsOpenlayers.js +55 -0
- package/src/vcs/vcm/layer/openlayers/wmtsOpenlayers.js +141 -0
- package/src/vcs/vcm/layer/pointCloud.js +162 -0
- package/src/vcs/vcm/layer/rasterLayer.js +294 -0
- package/src/vcs/vcm/layer/singleImage.js +119 -0
- package/src/vcs/vcm/layer/terrain.js +122 -0
- package/src/vcs/vcm/layer/terrainHelpers.js +123 -0
- package/src/vcs/vcm/layer/tileLoadedHelper.js +72 -0
- package/src/vcs/vcm/layer/tileProvider/mvtTileProvider.js +104 -0
- package/src/vcs/vcm/layer/tileProvider/staticGeojsonTileProvider.js +67 -0
- package/src/vcs/vcm/layer/tileProvider/tileProvider.js +584 -0
- package/src/vcs/vcm/layer/tileProvider/tileProviderFactory.js +28 -0
- package/src/vcs/vcm/layer/tileProvider/urlTemplateTileProvider.js +106 -0
- package/src/vcs/vcm/layer/tms.js +121 -0
- package/src/vcs/vcm/layer/vector.js +632 -0
- package/src/vcs/vcm/layer/vectorHelpers.js +206 -0
- package/src/vcs/vcm/layer/vectorProperties.js +1391 -0
- package/src/vcs/vcm/layer/vectorSymbols.js +40 -0
- package/src/vcs/vcm/layer/vectorTile.js +480 -0
- package/src/vcs/vcm/layer/wfs.js +165 -0
- package/src/vcs/vcm/layer/wms.js +270 -0
- package/src/vcs/vcm/layer/wmsHelpers.js +65 -0
- package/src/vcs/vcm/layer/wmts.js +235 -0
- package/src/vcs/vcm/maps/baseOLMap.js +257 -0
- package/src/vcs/vcm/maps/cameraLimiter.js +219 -0
- package/src/vcs/vcm/maps/cesium.js +1192 -0
- package/src/vcs/vcm/maps/map.js +511 -0
- package/src/vcs/vcm/maps/mapState.js +17 -0
- package/src/vcs/vcm/maps/oblique.js +536 -0
- package/src/vcs/vcm/maps/openlayers.js +205 -0
- package/src/vcs/vcm/object.js +92 -0
- package/src/vcs/vcm/oblique/ObliqueCollection.js +572 -0
- package/src/vcs/vcm/oblique/ObliqueDataSet.js +357 -0
- package/src/vcs/vcm/oblique/ObliqueImage.js +247 -0
- package/src/vcs/vcm/oblique/ObliqueImageMeta.js +126 -0
- package/src/vcs/vcm/oblique/ObliqueProvider.js +433 -0
- package/src/vcs/vcm/oblique/ObliqueView.js +130 -0
- package/src/vcs/vcm/oblique/ObliqueViewDirection.js +40 -0
- package/src/vcs/vcm/oblique/helpers.js +483 -0
- package/src/vcs/vcm/oblique/parseImageJson.js +248 -0
- package/src/vcs/vcm/util/clipping/clippingObject.js +386 -0
- package/src/vcs/vcm/util/clipping/clippingObjectManager.js +312 -0
- package/src/vcs/vcm/util/clipping/clippingPlaneHelper.js +413 -0
- package/src/vcs/vcm/util/collection.js +193 -0
- package/src/vcs/vcm/util/dateTime.js +60 -0
- package/src/vcs/vcm/util/exclusiveManager.js +135 -0
- package/src/vcs/vcm/util/extent.js +124 -0
- package/src/vcs/vcm/util/featureProvider/abstractFeatureProvider.js +196 -0
- package/src/vcs/vcm/util/featureProvider/featureProviderHelpers.js +51 -0
- package/src/vcs/vcm/util/featureProvider/featureProviderSymbols.js +11 -0
- package/src/vcs/vcm/util/featureProvider/tileProviderFeatureProvider.js +62 -0
- package/src/vcs/vcm/util/featureProvider/wmsFeatureProvider.js +280 -0
- package/src/vcs/vcm/util/featureconverter/circleToCesium.js +215 -0
- package/src/vcs/vcm/util/featureconverter/convert.js +83 -0
- package/src/vcs/vcm/util/featureconverter/extent3d.js +154 -0
- package/src/vcs/vcm/util/featureconverter/featureconverterHelper.js +591 -0
- package/src/vcs/vcm/util/featureconverter/lineStringToCesium.js +171 -0
- package/src/vcs/vcm/util/featureconverter/pointToCesium.js +359 -0
- package/src/vcs/vcm/util/featureconverter/polygonToCesium.js +229 -0
- package/src/vcs/vcm/util/geometryHelpers.js +172 -0
- package/src/vcs/vcm/util/indexedCollection.js +158 -0
- package/src/vcs/vcm/util/isMobile.js +12 -0
- package/src/vcs/vcm/util/layerCollection.js +216 -0
- package/src/vcs/vcm/util/locale.js +53 -0
- package/src/vcs/vcm/util/mapCollection.js +363 -0
- package/src/vcs/vcm/util/math.js +71 -0
- package/src/vcs/vcm/util/projection.js +348 -0
- package/src/vcs/vcm/util/splitScreen.js +233 -0
- package/src/vcs/vcm/util/style/declarativeStyleItem.js +631 -0
- package/src/vcs/vcm/util/style/shapesCategory.js +67 -0
- package/src/vcs/vcm/util/style/styleFactory.js +48 -0
- package/src/vcs/vcm/util/style/styleHelpers.js +555 -0
- package/src/vcs/vcm/util/style/styleItem.js +226 -0
- package/src/vcs/vcm/util/style/vectorStyleItem.js +927 -0
- package/src/vcs/vcm/util/style/writeStyle.js +48 -0
- package/src/vcs/vcm/util/urlHelpers.js +16 -0
- package/src/vcs/vcm/util/viewpoint.js +333 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { Event as CesiumEvent } from '@vcmap/cesium';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import { createXYZ } from 'ol/tilegrid.js';
|
|
4
|
+
import { destroyCesiumEvent } from './helpers.js';
|
|
5
|
+
import { cartesian2DDistance } from '../util/math.js';
|
|
6
|
+
import { parseImageData, parseImageMeta, parseLegacyImageData, getVersionFromImageJson } from './parseImageJson.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Enumeration of data set states
|
|
10
|
+
* @enum {number}
|
|
11
|
+
* @property {number} PENDING
|
|
12
|
+
* @property {number} LOADING
|
|
13
|
+
* @property {number} READY
|
|
14
|
+
* @export
|
|
15
|
+
* @api
|
|
16
|
+
*/
|
|
17
|
+
export const DataState = {
|
|
18
|
+
PENDING: 1,
|
|
19
|
+
LOADING: 2,
|
|
20
|
+
READY: 3,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {Array<DataState>} states
|
|
25
|
+
* @returns {DataState}
|
|
26
|
+
*/
|
|
27
|
+
export function getStateFromStatesArray(states) {
|
|
28
|
+
if (states.some(s => s === DataState.PENDING)) {
|
|
29
|
+
return DataState.PENDING;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (states.some(s => s === DataState.LOADING)) {
|
|
33
|
+
return DataState.LOADING;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return DataState.READY;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @class
|
|
41
|
+
* @export
|
|
42
|
+
*/
|
|
43
|
+
class ObliqueDataSet {
|
|
44
|
+
/**
|
|
45
|
+
* @param {string} url
|
|
46
|
+
* @param {import("ol/proj/Projection").default} projection
|
|
47
|
+
* @param {import("@vcmap/cesium").CesiumTerrainProvider=} terrainProvider
|
|
48
|
+
*/
|
|
49
|
+
constructor(url, projection, terrainProvider) {
|
|
50
|
+
/** @type {string} */
|
|
51
|
+
this.url = url;
|
|
52
|
+
if (!/\.json$/.test(this.url)) {
|
|
53
|
+
this.url = this.url.replace(/\/?$/, '/image.json');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** @type {string} */
|
|
57
|
+
this.baseUrl = this.url.replace(/\/?([^/]+\.json)?$/, '');
|
|
58
|
+
/** @type {import("ol/proj/Projection").default} */
|
|
59
|
+
this.projection = projection;
|
|
60
|
+
/** @type {import("@vcmap/cesium").CesiumTerrainProvider|undefined} */
|
|
61
|
+
this.terrainProvider = terrainProvider;
|
|
62
|
+
/**
|
|
63
|
+
* @type {Array<import("@vcmap/core").ObliqueImageMeta>}
|
|
64
|
+
* @private
|
|
65
|
+
*/
|
|
66
|
+
this._imageMetas = [];
|
|
67
|
+
/**
|
|
68
|
+
* Event raised when images are loaded. Is passed an Array of ObliqueImages as the first argument and optionally
|
|
69
|
+
* a string representing the tile coordinate ("z/x/y"), if the images where loaded for a tile.
|
|
70
|
+
* @type {import("@vcmap/cesium").Event}
|
|
71
|
+
* @api
|
|
72
|
+
*/
|
|
73
|
+
this.imagesLoaded = new CesiumEvent();
|
|
74
|
+
/** @type {Map<string, DataState>} */
|
|
75
|
+
this._tiles = new Map();
|
|
76
|
+
/** @type {Map<string, Promise<void>>} */
|
|
77
|
+
this._loadingPromises = new Map();
|
|
78
|
+
this._state = DataState.PENDING;
|
|
79
|
+
/**
|
|
80
|
+
* @type {number|null}
|
|
81
|
+
* @private
|
|
82
|
+
*/
|
|
83
|
+
this._tileLevel = null;
|
|
84
|
+
/** @type {import("ol/tilegrid/TileGrid").default} */
|
|
85
|
+
this._tileGrid = createXYZ();
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @type {Array<import("@vcmap/core").ObliqueImage>}
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
this._images = [];
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @type {CopyrightOptions|undefined}
|
|
95
|
+
* @api
|
|
96
|
+
*/
|
|
97
|
+
this.copyright = undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The loaded images of this DataSet
|
|
102
|
+
* @api
|
|
103
|
+
* @readonly
|
|
104
|
+
* @type {Array<import("@vcmap/core").ObliqueImage>}
|
|
105
|
+
*/
|
|
106
|
+
get images() {
|
|
107
|
+
return this._images.slice();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Gets the state of the meta data information. For tiled data sets, this does not
|
|
112
|
+
* reflect the state of loaded tiles.
|
|
113
|
+
* @type {DataState}
|
|
114
|
+
* @api
|
|
115
|
+
* @readonly
|
|
116
|
+
*/
|
|
117
|
+
get state() {
|
|
118
|
+
return this._state;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Loads the data set.
|
|
123
|
+
* @returns {Promise<void>}
|
|
124
|
+
* @api
|
|
125
|
+
*/
|
|
126
|
+
load() {
|
|
127
|
+
if (!this._loadingPromise) {
|
|
128
|
+
this._state = DataState.LOADING;
|
|
129
|
+
|
|
130
|
+
this._loadingPromise = axios.get(this.url)
|
|
131
|
+
.then(({ data }) => {
|
|
132
|
+
this._initialize(data);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return this._loadingPromise;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Returns all tiles of this data set, including its DataState
|
|
140
|
+
* @returns {Object<string, DataState>}
|
|
141
|
+
* @api
|
|
142
|
+
*/
|
|
143
|
+
getTiles() {
|
|
144
|
+
/** @type {Object<string, DataState>} */
|
|
145
|
+
const tiles = {};
|
|
146
|
+
this._tiles.forEach((state, tile) => {
|
|
147
|
+
tiles[tile] = state;
|
|
148
|
+
});
|
|
149
|
+
return tiles;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* initialize the DataSet with an existing Object.
|
|
154
|
+
* DataSets cannot be initialized more then once.
|
|
155
|
+
* @param {ObliqueImageJson} json
|
|
156
|
+
* @api
|
|
157
|
+
*/
|
|
158
|
+
initialize(json) {
|
|
159
|
+
if (this._state !== DataState.PENDING) {
|
|
160
|
+
throw new Error('DataSet has already been loaded');
|
|
161
|
+
}
|
|
162
|
+
this._loadingPromise = Promise.resolve();
|
|
163
|
+
this._initialize(json);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {ObliqueImageJson} json
|
|
168
|
+
* @private
|
|
169
|
+
*/
|
|
170
|
+
_initialize(json) {
|
|
171
|
+
this._parseMetaData(json);
|
|
172
|
+
this._state = DataState.READY;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @param {ObliqueImageJson} json
|
|
177
|
+
* @private
|
|
178
|
+
*/
|
|
179
|
+
_parseMetaData(json) {
|
|
180
|
+
this._imageMetas = parseImageMeta(json, this.baseUrl, this.projection, this.terrainProvider);
|
|
181
|
+
const { version, buildNumber } = getVersionFromImageJson(json);
|
|
182
|
+
|
|
183
|
+
if (json.tileLevel) {
|
|
184
|
+
this._tileLevel = json.tileLevel;
|
|
185
|
+
json.availableTiles.forEach((tile) => {
|
|
186
|
+
this._tiles.set(tile, DataState.PENDING);
|
|
187
|
+
});
|
|
188
|
+
} else {
|
|
189
|
+
let images = [];
|
|
190
|
+
if (version >= 3.5 || (version === 3.4 && buildNumber > 36)) {
|
|
191
|
+
images = parseImageData(json, this._imageMetas);
|
|
192
|
+
} else if (version >= 3.1 || version === null) {
|
|
193
|
+
images = parseLegacyImageData(json, this._imageMetas);
|
|
194
|
+
}
|
|
195
|
+
if (images.length > 0) {
|
|
196
|
+
this._images = images;
|
|
197
|
+
this.imagesLoaded.raiseEvent(images);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @param {import("ol/coordinate").Coordinate} mercatorCoordinate
|
|
204
|
+
* @returns {import("ol/tilecoord").TileCoord|null}
|
|
205
|
+
* @private
|
|
206
|
+
*/
|
|
207
|
+
_getClosestTileCoordinate(mercatorCoordinate) {
|
|
208
|
+
if (!this._tileLevel) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
const actualTile = this._tileGrid.getTileCoordForCoordAndZ(mercatorCoordinate, this._tileLevel);
|
|
212
|
+
if (this._tiles.has(actualTile.join('/'))) {
|
|
213
|
+
return actualTile;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let minDistance = Infinity;
|
|
217
|
+
let minTile = null;
|
|
218
|
+
[...this._tiles.keys()].forEach((tile) => {
|
|
219
|
+
const tileCoord = tile.split('/').map(Number);
|
|
220
|
+
const dist = cartesian2DDistance([actualTile[1], actualTile[2]], [tileCoord[1], tileCoord[2]]);
|
|
221
|
+
if (dist < minDistance) {
|
|
222
|
+
minDistance = dist;
|
|
223
|
+
minTile = tileCoord;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
return minTile || actualTile;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* @param {import("ol/extent").Extent} extent
|
|
231
|
+
* @returns {Array<string>}
|
|
232
|
+
* @private
|
|
233
|
+
*/
|
|
234
|
+
_getTileCoordinatesForExtent(extent) {
|
|
235
|
+
const topLeft = this._tileGrid.getTileCoordForCoordAndZ([extent[0], extent[3]], this._tileLevel);
|
|
236
|
+
const bottomRight = this._tileGrid.getTileCoordForCoordAndZ([extent[2], extent[1]], this._tileLevel);
|
|
237
|
+
const tileCoordinates = [];
|
|
238
|
+
for (let x = topLeft[1]; x <= bottomRight[1]; x++) {
|
|
239
|
+
for (let y = topLeft[2]; y <= bottomRight[2]; y++) {
|
|
240
|
+
tileCoordinates.push([this._tileLevel, x, y]);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return tileCoordinates
|
|
245
|
+
.map(tc => tc.join('/'))
|
|
246
|
+
.filter((tc) => {
|
|
247
|
+
const state = this._tiles.get(tc);
|
|
248
|
+
return state && state !== DataState.READY;
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Requests the state of data at a certain location. No data is automatically READY.
|
|
254
|
+
* @param {import("ol/coordinate").Coordinate} mercatorCoordinate - coordinate in web mercator
|
|
255
|
+
* @returns {DataState}
|
|
256
|
+
* @api
|
|
257
|
+
*/
|
|
258
|
+
getDataStateForCoordinate(mercatorCoordinate) {
|
|
259
|
+
if (this._state !== DataState.READY || this._tiles.size === 0) {
|
|
260
|
+
return this._state;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const tileCoordinate = this._getClosestTileCoordinate(mercatorCoordinate).join('/');
|
|
264
|
+
return this._tiles.has(tileCoordinate) ? this._tiles.get(tileCoordinate) : DataState.READY;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Loads all the tiles for a given extent.
|
|
269
|
+
* @param {import("ol/extent").Extent} extent
|
|
270
|
+
* @returns {DataState}
|
|
271
|
+
* @api
|
|
272
|
+
*/
|
|
273
|
+
getDataStateForExtent(extent) {
|
|
274
|
+
if (this._state !== DataState.READY || this._tiles.size === 0) {
|
|
275
|
+
return this._state;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const tileCoordinates = this._getTileCoordinatesForExtent(extent);
|
|
279
|
+
const states = tileCoordinates
|
|
280
|
+
.map(tc => this._tiles.get(tc))
|
|
281
|
+
.filter(s => s);
|
|
282
|
+
return getStateFromStatesArray(states);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @param {string} stringTileCoordinates
|
|
287
|
+
* @returns {Promise<void>}
|
|
288
|
+
* @private
|
|
289
|
+
*/
|
|
290
|
+
_loadTile(stringTileCoordinates) {
|
|
291
|
+
if (this._loadingPromises.has(stringTileCoordinates)) {
|
|
292
|
+
return this._loadingPromises.get(stringTileCoordinates);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (this._tiles.get(stringTileCoordinates) !== DataState.PENDING) {
|
|
296
|
+
return Promise.resolve();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
this._tiles.set(stringTileCoordinates, DataState.LOADING);
|
|
300
|
+
const promise = axios
|
|
301
|
+
.get(`${this.baseUrl}/${stringTileCoordinates}.json`)
|
|
302
|
+
.then(({ data }) => {
|
|
303
|
+
const images = parseImageData(data, this._imageMetas);
|
|
304
|
+
if (images.length > 0) {
|
|
305
|
+
this._images = this._images.concat(images);
|
|
306
|
+
this.imagesLoaded.raiseEvent(images, stringTileCoordinates);
|
|
307
|
+
}
|
|
308
|
+
})
|
|
309
|
+
.catch((err) => {
|
|
310
|
+
// eslint-disable-next-line no-console
|
|
311
|
+
console.error(err);
|
|
312
|
+
})
|
|
313
|
+
.finally(() => {
|
|
314
|
+
this._tiles.set(stringTileCoordinates, DataState.READY);
|
|
315
|
+
this._loadingPromises.delete(stringTileCoordinates);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
this._loadingPromises.set(stringTileCoordinates, promise);
|
|
319
|
+
return promise;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Loads the closest data tile for a certain location. Resolves when all data for the location has been loaded.
|
|
324
|
+
* @param {import("ol/coordinate").Coordinate} mercatorCoordinate - coordinate in web mercator
|
|
325
|
+
* @returns {Promise<void>}
|
|
326
|
+
* @api
|
|
327
|
+
*/
|
|
328
|
+
async loadDataForCoordinate(mercatorCoordinate) {
|
|
329
|
+
const tileCoordinate = this._getClosestTileCoordinate(mercatorCoordinate);
|
|
330
|
+
if (tileCoordinate) {
|
|
331
|
+
await this._loadTile(tileCoordinate.join('/'));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Loads all the tiles for a given extent.
|
|
337
|
+
* @param {import("ol/extent").Extent} extent
|
|
338
|
+
* @returns {Promise<void>}
|
|
339
|
+
* @api
|
|
340
|
+
*/
|
|
341
|
+
async loadDataForExtent(extent) {
|
|
342
|
+
const tileCoordinates = this._getTileCoordinatesForExtent(extent);
|
|
343
|
+
await Promise.all(tileCoordinates.map(tc => this._loadTile(tc)));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
destroy() {
|
|
347
|
+
destroyCesiumEvent(this.imagesLoaded);
|
|
348
|
+
this._images = [];
|
|
349
|
+
this._imageMetas = [];
|
|
350
|
+
this._tiles.clear();
|
|
351
|
+
this._loadingPromises.clear();
|
|
352
|
+
this._tileGrid = null;
|
|
353
|
+
this.terrainProvider = null;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export default ObliqueDataSet;
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { Cartesian3, Cartesian4, Matrix3, Matrix4 } from '@vcmap/cesium';
|
|
2
|
+
import { transformCWIFC } from './helpers.js';
|
|
3
|
+
import { getHeightFromTerrainProvider } from '../layer/terrainHelpers.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {Object} ObliqueImageOptions
|
|
7
|
+
* @property {!string} name
|
|
8
|
+
* @property {import("@vcmap/core").ObliqueViewDirection} viewDirection
|
|
9
|
+
* @property {number} viewDirectionAngle
|
|
10
|
+
* @property {!Array<import("ol/coordinate").Coordinate>} groundCoordinates
|
|
11
|
+
* @property {!import("ol/coordinate").Coordinate} centerPointOnGround
|
|
12
|
+
* @property {!import("@vcmap/core").ObliqueImageMeta} meta
|
|
13
|
+
* @property {import("@vcmap/cesium").Cartesian3|undefined} projectionCenter
|
|
14
|
+
* @property {import("@vcmap/cesium").Matrix3|undefined} pToRealworld
|
|
15
|
+
* @property {import("@vcmap/cesium").Matrix4|undefined} pToImage
|
|
16
|
+
* @property {import("ol/proj/Projection").default|undefined} [projection]
|
|
17
|
+
* @property {import("@vcmap/cesium").CesiumTerrainProvider|undefined} terrainProvider
|
|
18
|
+
* @api
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @class
|
|
23
|
+
* @export
|
|
24
|
+
*/
|
|
25
|
+
class ObliqueImage {
|
|
26
|
+
/**
|
|
27
|
+
* @param {ObliqueImageOptions} options
|
|
28
|
+
*/
|
|
29
|
+
constructor(options) {
|
|
30
|
+
/**
|
|
31
|
+
* Name of the image
|
|
32
|
+
* @type {string}
|
|
33
|
+
* @api
|
|
34
|
+
*/
|
|
35
|
+
this.name = options.name;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Meta information shared across multiple images.
|
|
39
|
+
* @type {import("@vcmap/core").ObliqueImageMeta}
|
|
40
|
+
* @api
|
|
41
|
+
*/
|
|
42
|
+
this.meta = options.meta;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* viewDirection
|
|
46
|
+
* @type {import("@vcmap/core").ObliqueViewDirection}
|
|
47
|
+
* @api
|
|
48
|
+
*/
|
|
49
|
+
this.viewDirection = options.viewDirection;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* viewDirectionAngle in radians, where 0 = east, PI / 2 = north, PI = west and PI * 1.5 = south
|
|
53
|
+
* @type {number|null}
|
|
54
|
+
* @api
|
|
55
|
+
*/
|
|
56
|
+
this.viewDirectionAngle = options.viewDirectionAngle;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The ground coordinates of the image corners (in image world projection).
|
|
60
|
+
* @type {Array<import("ol/coordinate").Coordinate>}
|
|
61
|
+
* @api
|
|
62
|
+
*/
|
|
63
|
+
this.groundCoordinates = options.groundCoordinates;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The center point of the image in world coordinates (in image world projection).
|
|
67
|
+
* @type {import("ol/coordinate").Coordinate}
|
|
68
|
+
* @api
|
|
69
|
+
*/
|
|
70
|
+
this.centerPointOnGround = options.centerPointOnGround;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The transformation matrix image to real world (in image world projection).
|
|
74
|
+
* @type {import("@vcmap/cesium").Matrix3}
|
|
75
|
+
* @api
|
|
76
|
+
*/
|
|
77
|
+
this.pToRealworld = options.pToRealworld || null;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The transformation matrix real to image (in image world projection).
|
|
81
|
+
* @type {import("@vcmap/cesium").Matrix4}
|
|
82
|
+
*/
|
|
83
|
+
this.pToImage = options.pToImage || null;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The projection center in image world projection
|
|
87
|
+
* @type {import("@vcmap/cesium").Cartesian3}
|
|
88
|
+
* @api
|
|
89
|
+
*/
|
|
90
|
+
this.projectionCenter = options.projectionCenter || null;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The calculated average height of an image
|
|
94
|
+
* @type {number|null}
|
|
95
|
+
* @private
|
|
96
|
+
*/
|
|
97
|
+
this._averageHeight = null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* returns the averageHeight of the image or 0 if not defined. Be sure to call calculateAverageHeight before hand.
|
|
102
|
+
* @type {number}
|
|
103
|
+
* @readonly
|
|
104
|
+
* @api
|
|
105
|
+
*/
|
|
106
|
+
get averageHeight() {
|
|
107
|
+
return this._averageHeight != null ? this._averageHeight : 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* returns whether this image supports exact Coordinate transformation
|
|
112
|
+
* @type {boolean}
|
|
113
|
+
* @readonly
|
|
114
|
+
* @api
|
|
115
|
+
*/
|
|
116
|
+
get hasCamera() {
|
|
117
|
+
return !!this.meta.principalPoint;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @param {import("ol/coordinate").Coordinate} imageCoordinate
|
|
122
|
+
* @param {number=} optAvgHeight
|
|
123
|
+
* @returns {import("ol/coordinate").Coordinate}
|
|
124
|
+
* @api
|
|
125
|
+
*/
|
|
126
|
+
transformImage2RealWorld(imageCoordinate, optAvgHeight) {
|
|
127
|
+
let distortedCoordinate = imageCoordinate;
|
|
128
|
+
if (!this.meta.principalPoint) {
|
|
129
|
+
return this._transformNoCamera(distortedCoordinate, true, optAvgHeight);
|
|
130
|
+
} else if (this.meta.hasRadial) {
|
|
131
|
+
distortedCoordinate = this.meta.radialDistortionCoordinate(distortedCoordinate, true);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const x = new Cartesian3(distortedCoordinate[0], this.meta.size[1] - distortedCoordinate[1], 1);
|
|
135
|
+
const rayWorld = Matrix3.multiplyByVector(this.pToRealworld, x, new Cartesian3());
|
|
136
|
+
const avgHeight = optAvgHeight || this.averageHeight;
|
|
137
|
+
const centerPointOnGround =
|
|
138
|
+
new Cartesian3(this.centerPointOnGround[0], this.centerPointOnGround[1], avgHeight);
|
|
139
|
+
const w0 = Cartesian3.subtract(this.projectionCenter, centerPointOnGround, new Cartesian3());
|
|
140
|
+
const a = Cartesian3.dot(Cartesian3.UNIT_Z, w0) * (-1);
|
|
141
|
+
const b = Cartesian3.dot(Cartesian3.UNIT_Z, rayWorld);
|
|
142
|
+
|
|
143
|
+
const r = a / b;
|
|
144
|
+
|
|
145
|
+
const intr = Cartesian3.add(
|
|
146
|
+
this.projectionCenter,
|
|
147
|
+
Cartesian3.multiplyByScalar(rayWorld, r, new Cartesian3()),
|
|
148
|
+
new Cartesian3(),
|
|
149
|
+
);
|
|
150
|
+
return [intr.x, intr.y, avgHeight];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @param {import("ol/coordinate").Coordinate} worldCoordinate
|
|
155
|
+
* @param {number=} optAvgHeight
|
|
156
|
+
* @returns {import("ol/coordinate").Coordinate}
|
|
157
|
+
* @api
|
|
158
|
+
*/
|
|
159
|
+
transformRealWorld2Image(worldCoordinate, optAvgHeight) {
|
|
160
|
+
// if we dont have camera parameters
|
|
161
|
+
if (!this.meta.principalPoint) {
|
|
162
|
+
return this._transformNoCamera(worldCoordinate, false, optAvgHeight);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// usage of perspective projection
|
|
166
|
+
// the averaged height is used for projection so far
|
|
167
|
+
const avgHeight = optAvgHeight || this.averageHeight;
|
|
168
|
+
|
|
169
|
+
const P = new Cartesian4(worldCoordinate[0], worldCoordinate[1], avgHeight, 1);
|
|
170
|
+
|
|
171
|
+
const camSys = Matrix4.multiplyByVector(this.pToImage, P, new Cartesian4());
|
|
172
|
+
const respectiveImageCoords = [camSys.x / camSys.z, camSys.y / camSys.z];
|
|
173
|
+
// adjust to ol image coordinates
|
|
174
|
+
const imCoords = [respectiveImageCoords[0], this.meta.size[1] - respectiveImageCoords[1]];
|
|
175
|
+
|
|
176
|
+
return this.meta.radialDistortionCoordinate(imCoords, false);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @param {import("ol/coordinate").Coordinate} coord
|
|
182
|
+
* @param {boolean} isImage
|
|
183
|
+
* @param {number=} optAvgHeight
|
|
184
|
+
* @private
|
|
185
|
+
* @returns {import("ol/coordinate").Coordinate}
|
|
186
|
+
*/
|
|
187
|
+
_transformNoCamera(coord, isImage, optAvgHeight) {
|
|
188
|
+
const imageCoords = [[0, 0], [this.meta.size[0], 0], this.meta.size, [0, this.meta.size[1]]];
|
|
189
|
+
const intrCross = transformCWIFC(
|
|
190
|
+
isImage ? imageCoords : this.groundCoordinates,
|
|
191
|
+
isImage ? this.groundCoordinates : imageCoords,
|
|
192
|
+
isImage,
|
|
193
|
+
coord,
|
|
194
|
+
this.viewDirection,
|
|
195
|
+
);
|
|
196
|
+
const height = optAvgHeight || this.averageHeight;
|
|
197
|
+
// if intersection could not be determined write error and return center
|
|
198
|
+
if (intrCross === null || intrCross.x == null || intrCross.y == null) {
|
|
199
|
+
// eslint-disable-next-line no-console
|
|
200
|
+
console.error('Real world coordinate could not be determined from footprint data, center will be returned');
|
|
201
|
+
const coords = [this.centerPointOnGround[0], this.centerPointOnGround[1]];
|
|
202
|
+
if (isImage) {
|
|
203
|
+
coords.push(height);
|
|
204
|
+
}
|
|
205
|
+
return coords;
|
|
206
|
+
}
|
|
207
|
+
const coords = [intrCross.x, intrCross.y];
|
|
208
|
+
if (isImage) {
|
|
209
|
+
coords.push(height);
|
|
210
|
+
}
|
|
211
|
+
return coords;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* calculates the averageHeight of this image, if a terrainProvider is given the height will be requested
|
|
216
|
+
* @returns {Promise<void>}
|
|
217
|
+
* @api
|
|
218
|
+
*/
|
|
219
|
+
calculateImageAverageHeight() {
|
|
220
|
+
if (this._averageHeight === null) {
|
|
221
|
+
const averageHeight = (
|
|
222
|
+
this.groundCoordinates[0][2] +
|
|
223
|
+
this.groundCoordinates[1][2] +
|
|
224
|
+
this.groundCoordinates[2][2] +
|
|
225
|
+
this.groundCoordinates[3][2]) / 4;
|
|
226
|
+
if (averageHeight === 0 && this.meta.terrainProvider) {
|
|
227
|
+
return getHeightFromTerrainProvider(
|
|
228
|
+
this.meta.terrainProvider,
|
|
229
|
+
[this.centerPointOnGround.slice()],
|
|
230
|
+
this.meta.projection,
|
|
231
|
+
)
|
|
232
|
+
.then((coords) => {
|
|
233
|
+
if (coords[0] && coords[0][2] != null) {
|
|
234
|
+
this._averageHeight = coords[0][2];
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
.catch(() => {
|
|
238
|
+
this._averageHeight = averageHeight;
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
this._averageHeight = averageHeight;
|
|
242
|
+
}
|
|
243
|
+
return Promise.resolve();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export default ObliqueImage;
|