@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.
Files changed (146) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +44 -0
  3. package/build/postinstall.js +44 -0
  4. package/index.js +139 -0
  5. package/package.json +92 -0
  6. package/src/cesium/cesium3DTileFeature.js +9 -0
  7. package/src/cesium/cesium3DTilePointFeature.js +9 -0
  8. package/src/cesium/cesiumVcsCameraPrimitive.js +146 -0
  9. package/src/cesium/wallpaperMaterial.js +64 -0
  10. package/src/ol/feature.js +47 -0
  11. package/src/ol/geom/circle.js +24 -0
  12. package/src/ol/geom/geometryCollection.js +33 -0
  13. package/src/ol/render/canvas/canvasTileRenderer.js +179 -0
  14. package/src/ol/source/ClusterEnhancedVectorSource.js +39 -0
  15. package/src/ol/source/VcsCluster.js +37 -0
  16. package/src/vcs/vcm/classRegistry.js +106 -0
  17. package/src/vcs/vcm/event/vcsEvent.js +89 -0
  18. package/src/vcs/vcm/globalCollections.js +11 -0
  19. package/src/vcs/vcm/interaction/abstractInteraction.js +149 -0
  20. package/src/vcs/vcm/interaction/coordinateAtPixel.js +102 -0
  21. package/src/vcs/vcm/interaction/eventHandler.js +425 -0
  22. package/src/vcs/vcm/interaction/featureAtPixelInteraction.js +286 -0
  23. package/src/vcs/vcm/interaction/featureProviderInteraction.js +54 -0
  24. package/src/vcs/vcm/interaction/interactionChain.js +124 -0
  25. package/src/vcs/vcm/interaction/interactionType.js +114 -0
  26. package/src/vcs/vcm/layer/buildings.js +17 -0
  27. package/src/vcs/vcm/layer/cesium/cesiumTilesetCesium.js +359 -0
  28. package/src/vcs/vcm/layer/cesium/clusterContext.js +95 -0
  29. package/src/vcs/vcm/layer/cesium/dataSourceCesium.js +171 -0
  30. package/src/vcs/vcm/layer/cesium/openStreetMapCesium.js +29 -0
  31. package/src/vcs/vcm/layer/cesium/pointCloudCesium.js +58 -0
  32. package/src/vcs/vcm/layer/cesium/rasterLayerCesium.js +110 -0
  33. package/src/vcs/vcm/layer/cesium/singleImageCesium.js +49 -0
  34. package/src/vcs/vcm/layer/cesium/terrainCesium.js +80 -0
  35. package/src/vcs/vcm/layer/cesium/tmsCesium.js +54 -0
  36. package/src/vcs/vcm/layer/cesium/vectorCesium.js +255 -0
  37. package/src/vcs/vcm/layer/cesium/vectorContext.js +167 -0
  38. package/src/vcs/vcm/layer/cesium/vectorRasterTileCesium.js +116 -0
  39. package/src/vcs/vcm/layer/cesium/vectorTileImageryProvider.js +246 -0
  40. package/src/vcs/vcm/layer/cesium/wmsCesium.js +71 -0
  41. package/src/vcs/vcm/layer/cesium/wmtsCesium.js +101 -0
  42. package/src/vcs/vcm/layer/cesium/x3dmHelper.js +22 -0
  43. package/src/vcs/vcm/layer/cesiumTileset.js +376 -0
  44. package/src/vcs/vcm/layer/czml.js +141 -0
  45. package/src/vcs/vcm/layer/dataSource.js +259 -0
  46. package/src/vcs/vcm/layer/featureLayer.js +261 -0
  47. package/src/vcs/vcm/layer/featureStore.js +647 -0
  48. package/src/vcs/vcm/layer/featureStoreChanges.js +360 -0
  49. package/src/vcs/vcm/layer/featureStoreState.js +19 -0
  50. package/src/vcs/vcm/layer/featureVisibility.js +435 -0
  51. package/src/vcs/vcm/layer/geojson.js +185 -0
  52. package/src/vcs/vcm/layer/geojsonHelpers.js +450 -0
  53. package/src/vcs/vcm/layer/globalHider.js +157 -0
  54. package/src/vcs/vcm/layer/layer.js +752 -0
  55. package/src/vcs/vcm/layer/layerImplementation.js +102 -0
  56. package/src/vcs/vcm/layer/layerState.js +17 -0
  57. package/src/vcs/vcm/layer/layerSymbols.js +6 -0
  58. package/src/vcs/vcm/layer/oblique/layerOblique.js +76 -0
  59. package/src/vcs/vcm/layer/oblique/obliqueHelpers.js +175 -0
  60. package/src/vcs/vcm/layer/oblique/vectorOblique.js +469 -0
  61. package/src/vcs/vcm/layer/openStreetMap.js +194 -0
  62. package/src/vcs/vcm/layer/openlayers/layerOpenlayers.js +79 -0
  63. package/src/vcs/vcm/layer/openlayers/openStreetMapOpenlayers.js +27 -0
  64. package/src/vcs/vcm/layer/openlayers/rasterLayerOpenlayers.js +121 -0
  65. package/src/vcs/vcm/layer/openlayers/singleImageOpenlayers.js +49 -0
  66. package/src/vcs/vcm/layer/openlayers/tileDebugOpenlayers.js +39 -0
  67. package/src/vcs/vcm/layer/openlayers/tmsOpenlayers.js +62 -0
  68. package/src/vcs/vcm/layer/openlayers/vectorOpenlayers.js +118 -0
  69. package/src/vcs/vcm/layer/openlayers/vectorTileOpenlayers.js +177 -0
  70. package/src/vcs/vcm/layer/openlayers/wmsOpenlayers.js +55 -0
  71. package/src/vcs/vcm/layer/openlayers/wmtsOpenlayers.js +141 -0
  72. package/src/vcs/vcm/layer/pointCloud.js +162 -0
  73. package/src/vcs/vcm/layer/rasterLayer.js +294 -0
  74. package/src/vcs/vcm/layer/singleImage.js +119 -0
  75. package/src/vcs/vcm/layer/terrain.js +122 -0
  76. package/src/vcs/vcm/layer/terrainHelpers.js +123 -0
  77. package/src/vcs/vcm/layer/tileLoadedHelper.js +72 -0
  78. package/src/vcs/vcm/layer/tileProvider/mvtTileProvider.js +104 -0
  79. package/src/vcs/vcm/layer/tileProvider/staticGeojsonTileProvider.js +67 -0
  80. package/src/vcs/vcm/layer/tileProvider/tileProvider.js +584 -0
  81. package/src/vcs/vcm/layer/tileProvider/tileProviderFactory.js +28 -0
  82. package/src/vcs/vcm/layer/tileProvider/urlTemplateTileProvider.js +106 -0
  83. package/src/vcs/vcm/layer/tms.js +121 -0
  84. package/src/vcs/vcm/layer/vector.js +632 -0
  85. package/src/vcs/vcm/layer/vectorHelpers.js +206 -0
  86. package/src/vcs/vcm/layer/vectorProperties.js +1391 -0
  87. package/src/vcs/vcm/layer/vectorSymbols.js +40 -0
  88. package/src/vcs/vcm/layer/vectorTile.js +480 -0
  89. package/src/vcs/vcm/layer/wfs.js +165 -0
  90. package/src/vcs/vcm/layer/wms.js +270 -0
  91. package/src/vcs/vcm/layer/wmsHelpers.js +65 -0
  92. package/src/vcs/vcm/layer/wmts.js +235 -0
  93. package/src/vcs/vcm/maps/baseOLMap.js +257 -0
  94. package/src/vcs/vcm/maps/cameraLimiter.js +219 -0
  95. package/src/vcs/vcm/maps/cesium.js +1192 -0
  96. package/src/vcs/vcm/maps/map.js +511 -0
  97. package/src/vcs/vcm/maps/mapState.js +17 -0
  98. package/src/vcs/vcm/maps/oblique.js +536 -0
  99. package/src/vcs/vcm/maps/openlayers.js +205 -0
  100. package/src/vcs/vcm/object.js +92 -0
  101. package/src/vcs/vcm/oblique/ObliqueCollection.js +572 -0
  102. package/src/vcs/vcm/oblique/ObliqueDataSet.js +357 -0
  103. package/src/vcs/vcm/oblique/ObliqueImage.js +247 -0
  104. package/src/vcs/vcm/oblique/ObliqueImageMeta.js +126 -0
  105. package/src/vcs/vcm/oblique/ObliqueProvider.js +433 -0
  106. package/src/vcs/vcm/oblique/ObliqueView.js +130 -0
  107. package/src/vcs/vcm/oblique/ObliqueViewDirection.js +40 -0
  108. package/src/vcs/vcm/oblique/helpers.js +483 -0
  109. package/src/vcs/vcm/oblique/parseImageJson.js +248 -0
  110. package/src/vcs/vcm/util/clipping/clippingObject.js +386 -0
  111. package/src/vcs/vcm/util/clipping/clippingObjectManager.js +312 -0
  112. package/src/vcs/vcm/util/clipping/clippingPlaneHelper.js +413 -0
  113. package/src/vcs/vcm/util/collection.js +193 -0
  114. package/src/vcs/vcm/util/dateTime.js +60 -0
  115. package/src/vcs/vcm/util/exclusiveManager.js +135 -0
  116. package/src/vcs/vcm/util/extent.js +124 -0
  117. package/src/vcs/vcm/util/featureProvider/abstractFeatureProvider.js +196 -0
  118. package/src/vcs/vcm/util/featureProvider/featureProviderHelpers.js +51 -0
  119. package/src/vcs/vcm/util/featureProvider/featureProviderSymbols.js +11 -0
  120. package/src/vcs/vcm/util/featureProvider/tileProviderFeatureProvider.js +62 -0
  121. package/src/vcs/vcm/util/featureProvider/wmsFeatureProvider.js +280 -0
  122. package/src/vcs/vcm/util/featureconverter/circleToCesium.js +215 -0
  123. package/src/vcs/vcm/util/featureconverter/convert.js +83 -0
  124. package/src/vcs/vcm/util/featureconverter/extent3d.js +154 -0
  125. package/src/vcs/vcm/util/featureconverter/featureconverterHelper.js +591 -0
  126. package/src/vcs/vcm/util/featureconverter/lineStringToCesium.js +171 -0
  127. package/src/vcs/vcm/util/featureconverter/pointToCesium.js +359 -0
  128. package/src/vcs/vcm/util/featureconverter/polygonToCesium.js +229 -0
  129. package/src/vcs/vcm/util/geometryHelpers.js +172 -0
  130. package/src/vcs/vcm/util/indexedCollection.js +158 -0
  131. package/src/vcs/vcm/util/isMobile.js +12 -0
  132. package/src/vcs/vcm/util/layerCollection.js +216 -0
  133. package/src/vcs/vcm/util/locale.js +53 -0
  134. package/src/vcs/vcm/util/mapCollection.js +363 -0
  135. package/src/vcs/vcm/util/math.js +71 -0
  136. package/src/vcs/vcm/util/projection.js +348 -0
  137. package/src/vcs/vcm/util/splitScreen.js +233 -0
  138. package/src/vcs/vcm/util/style/declarativeStyleItem.js +631 -0
  139. package/src/vcs/vcm/util/style/shapesCategory.js +67 -0
  140. package/src/vcs/vcm/util/style/styleFactory.js +48 -0
  141. package/src/vcs/vcm/util/style/styleHelpers.js +555 -0
  142. package/src/vcs/vcm/util/style/styleItem.js +226 -0
  143. package/src/vcs/vcm/util/style/vectorStyleItem.js +927 -0
  144. package/src/vcs/vcm/util/style/writeStyle.js +48 -0
  145. package/src/vcs/vcm/util/urlHelpers.js +16 -0
  146. package/src/vcs/vcm/util/viewpoint.js +333 -0
@@ -0,0 +1,584 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import RBush from 'rbush';
3
+ import { Rectangle, Math as CesiumMath, WebMercatorTilingScheme, Cartographic } from '@vcmap/cesium';
4
+ import LRUCache from 'ol/structs/LRUCache.js';
5
+ import { buffer, createOrUpdateFromCoordinate } from 'ol/extent.js';
6
+ import { parseBoolean, parseInteger } from '@vcsuite/parsers';
7
+ import {
8
+ mercatorProjection,
9
+ mercatorToWgs84Transformer,
10
+ wgs84Projection,
11
+ wgs84ToMercatorTransformer,
12
+ } from '../../util/projection.js';
13
+ import VcsObject from '../../object.js';
14
+ import VcsEvent from '../../event/vcsEvent.js';
15
+
16
+ /**
17
+ * @typedef {Object} tileProviderRTreeEntry
18
+ * @property {number} minX
19
+ * @property {number} minY
20
+ * @property {number} maxX
21
+ * @property {number} maxY
22
+ * @property {import("ol").Feature<import("ol/geom/Geometry").default>} value
23
+ */
24
+
25
+ /**
26
+ * resolutions to levels
27
+ * @type {Array<number>}
28
+ */
29
+ export const mercatorResolutionsToLevel = new Array(25);
30
+ for (let i = 0; i < mercatorResolutionsToLevel.length; i++) {
31
+ mercatorResolutionsToLevel[i] = (20037508.3427892 * 2) / 256 / 2 ** (i + 1);
32
+ }
33
+
34
+ /**
35
+ * transforms cesium geographic rectangle to mercator extent
36
+ * @param {import("@vcmap/cesium").Rectangle} rectangle in wgs84 radians
37
+ * @returns {import("ol/extent").Extent} extent in mercator
38
+ */
39
+ export function rectangleToExtent(rectangle) {
40
+ const baseSouthWestLevel = Rectangle.southwest(rectangle);
41
+ const baseNorthEastLevel = Rectangle.northeast(rectangle);
42
+ const baseSouthWestWGS84 = [
43
+ CesiumMath.toDegrees(baseSouthWestLevel.longitude),
44
+ CesiumMath.toDegrees(baseSouthWestLevel.latitude),
45
+ ];
46
+ const baseNorthEastWGS84 = [
47
+ CesiumMath.toDegrees(baseNorthEastLevel.longitude),
48
+ CesiumMath.toDegrees(baseNorthEastLevel.latitude),
49
+ ];
50
+ const baseSouthWestMercator = wgs84ToMercatorTransformer(baseSouthWestWGS84);
51
+ const baseNorthEastMercator = wgs84ToMercatorTransformer(baseNorthEastWGS84);
52
+ return [...baseSouthWestMercator, ...baseNorthEastMercator];
53
+ }
54
+
55
+ /**
56
+ * @typedef {VcsObjectOptions} TileProviderOptions
57
+ * @property {number} [tileCacheSize=50] size of the LRU (least recently used) tileCache per baseLevel
58
+ * @property {Array<number>} [baseLevels=[15]] baseLevels (these levels will be requested by the loader, all other child levels will be interpolated
59
+ * @property {boolean} [trackFeaturesToTiles=true] tracks in which tile each feature exists. (features without an ID will be ignored). Better performance if deactivated, but does not allow for featureVisibility. Should be set to false if not unique featureID is provided.
60
+ * @property {boolean} [allowTileAggregation=true] allows aggregation of tiles if requested minLevel is lower than provided baseLevels ( if true, allows for aggregating up to two levels (16 child tiles) into a tile)
61
+ * @api
62
+ */
63
+
64
+ /**
65
+ * @typedef {Object} TileLoadedEvent
66
+ * @property {string} tileId id of the tile
67
+ * @property {import("rbush").default<tileProviderRTreeEntry>} rtree rbush rTree with the features, use rtree.all().map(item => item.value);
68
+ * @api
69
+ */
70
+
71
+
72
+ /**
73
+ * TileProvider class
74
+ *
75
+ * @class
76
+ * @extends {VcsObject}
77
+ * @export
78
+ * @api
79
+ */
80
+ class TileProvider extends VcsObject {
81
+ /**
82
+ * @readonly
83
+ * @returns {string}
84
+ */
85
+ static get className() { return 'vcs.vcm.layer.tileProvider.TileProvider'; }
86
+
87
+ /**
88
+ * @returns {TileProviderOptions}
89
+ */
90
+ static getDefaultOptions() {
91
+ return {
92
+ tileCacheSize: 50,
93
+ baseLevels: [15],
94
+ trackFeaturesToTiles: true,
95
+ allowTileAggregation: true,
96
+ };
97
+ }
98
+
99
+ /**
100
+ * @param {TileProviderOptions} options
101
+ */
102
+ constructor(options) {
103
+ super(options);
104
+ const defaultOptions = TileProvider.getDefaultOptions();
105
+
106
+ /**
107
+ * Cesium Webmercator TilingScheme
108
+ * @type {import("@vcmap/cesium").WebMercatorTilingScheme}
109
+ * @api
110
+ * @readonly
111
+ */
112
+ this.tilingScheme = new WebMercatorTilingScheme();
113
+
114
+ /**
115
+ * @type {number}
116
+ * @private
117
+ */
118
+ this._tileCacheSize = parseInteger(options.tileCacheSize, defaultOptions.tileCacheSize);
119
+
120
+
121
+ const baseLevels = Array.isArray(options.baseLevels) ?
122
+ options.baseLevels.slice() :
123
+ defaultOptions.baseLevels.slice();
124
+ baseLevels.sort((a, b) => { return b - a; });
125
+
126
+ /**
127
+ * sorted baseLevels, maximumLevel first example: [18,17,16]
128
+ * @type {Array<number>}
129
+ * @api
130
+ * @readonly
131
+ */
132
+ this.baseLevels = [...new Set(baseLevels)];
133
+
134
+ /**
135
+ * cache of tiles for each baseLevel
136
+ * @type {Map<number, LRUCache<Promise<import("rbush").default<tileProviderRTreeEntry>>>>}
137
+ * @api
138
+ */
139
+ this.cache = new Map();
140
+
141
+ this.baseLevels.forEach((baseLevel) => {
142
+ this.cache.set(baseLevel, new LRUCache(this.tileCacheSize));
143
+ });
144
+
145
+ /**
146
+ * Caches the loaded rTrees for quick Access to all features.
147
+ * @type {Map<string, import("rbush").default<tileProviderRTreeEntry>>}
148
+ * @api
149
+ */
150
+ this.rtreeCache = new Map();
151
+
152
+ /**
153
+ * @type {boolean}
154
+ * @api
155
+ * @readonly
156
+ */
157
+ this.trackFeaturesToTiles = parseBoolean(options.trackFeaturesToTiles, defaultOptions.trackFeaturesToTiles);
158
+
159
+ /**
160
+ * @type {boolean}
161
+ * @api
162
+ */
163
+ this.allowTileAggregation = parseBoolean(options.allowTileAggregation, defaultOptions.allowTileAggregation);
164
+
165
+ /**
166
+ * set of currently loaded featureIds with the corresponding tileIds
167
+ * @type {Map<string, Set<string>>}
168
+ * @api
169
+ * @readonly
170
+ */
171
+ this.featureIdToTileIds = new Map();
172
+
173
+ /**
174
+ * is raised for each loaded Tile; has the tileId and a rtree as parameters
175
+ * @type {VcsEvent<TileLoadedEvent>}
176
+ * @api
177
+ */
178
+ this.tileLoadedEvent = new VcsEvent();
179
+ }
180
+
181
+ /**
182
+ * use setTileCacheSize to change
183
+ * @type {number}
184
+ * @api
185
+ * @readonly
186
+ */
187
+ get tileCacheSize() {
188
+ return this._tileCacheSize;
189
+ }
190
+
191
+ /**
192
+ * @param {number} value
193
+ * @returns {Promise<*>}
194
+ */
195
+ setTileCacheSize(value) {
196
+ const promises = [];
197
+ this._tileCacheSize = value;
198
+ this.cache.forEach((lru, baseLevel) => {
199
+ lru.setSize(this._tileCacheSize);
200
+ while (lru.canExpireCache()) {
201
+ promises.push(this._removeLastTileFromCache(baseLevel));
202
+ }
203
+ });
204
+ return Promise.all(promises);
205
+ }
206
+
207
+ /**
208
+ * tracks Features if the features have ids.
209
+ * @param {Array<import("ol").Feature<import("ol/geom/Geometry").default>>} features
210
+ * @param {string} tileId
211
+ * @private
212
+ */
213
+ _trackFeatures(features, tileId) {
214
+ if (this.trackFeaturesToTiles) {
215
+ features.forEach((f) => {
216
+ const featureId = f.getId();
217
+ if (featureId) {
218
+ if (!this.featureIdToTileIds.has(String(featureId))) {
219
+ this.featureIdToTileIds.set(String(featureId), new Set());
220
+ }
221
+ this.featureIdToTileIds.get(String(featureId)).add(tileId);
222
+ }
223
+ });
224
+ }
225
+ }
226
+
227
+ /**
228
+ * untracks Features
229
+ * @param {Array<import("ol").Feature<import("ol/geom/Geometry").default>>} features
230
+ * @param {string} tileId
231
+ * @private
232
+ */
233
+ _unTrackFeatures(features, tileId) {
234
+ if (this.trackFeaturesToTiles) {
235
+ features.forEach((f) => {
236
+ const featureId = f.getId();
237
+ if (featureId) {
238
+ if (this.featureIdToTileIds.has(String(featureId))) {
239
+ const tileIdSet = this.featureIdToTileIds.get(String(featureId));
240
+ tileIdSet.delete(tileId);
241
+ if (tileIdSet.size === 0) {
242
+ this.featureIdToTileIds.delete(String(featureId));
243
+ }
244
+ }
245
+ }
246
+ });
247
+ }
248
+ }
249
+
250
+ /**
251
+ * @param {Promise<Array<import("ol").Feature<import("ol/geom/Geometry").default>>>} featuresPromise
252
+ * @param {number} baseLevel
253
+ * @param {string} tileId
254
+ * @returns {Promise<*>}
255
+ * @private
256
+ */
257
+ _addTilePromiseToCache(featuresPromise, baseLevel, tileId) {
258
+ const rtreePromise = featuresPromise.then((features) => {
259
+ features.forEach((feature) => {
260
+ if (!feature.getId()) {
261
+ feature.setId(uuidv4());
262
+ }
263
+ });
264
+ const rtree = new RBush(features.length);
265
+ rtree.load(features.map((feature) => {
266
+ const geometry = feature.getGeometry();
267
+ if (geometry) {
268
+ const extent = geometry.getExtent();
269
+ const item = {
270
+ minX: extent[0],
271
+ minY: extent[1],
272
+ maxX: extent[2],
273
+ maxY: extent[3],
274
+ value: feature,
275
+ };
276
+ return item;
277
+ }
278
+ return null;
279
+ }).filter(item => item));
280
+ this.tileLoadedEvent.raiseEvent({ tileId, rtree });
281
+ this._trackFeatures(features, tileId);
282
+ this.rtreeCache.set(tileId, rtree);
283
+ return rtree;
284
+ }).catch(() => {
285
+ // Discussion, do we want to go on on tileLoadFailure ?
286
+ this.getLogger().warning(`Could not load Tile ${tileId}`);
287
+ const rtree = new RBush();
288
+ this.rtreeCache.set(tileId, rtree);
289
+ return rtree;
290
+ });
291
+
292
+ this.cache.get(baseLevel).set(tileId, rtreePromise);
293
+ if (this.cache.get(baseLevel).canExpireCache()) {
294
+ return Promise.all([rtreePromise, this._removeLastTileFromCache(baseLevel)]);
295
+ }
296
+ return rtreePromise;
297
+ }
298
+
299
+ /**
300
+ * @param {number} baseLevel
301
+ * @returns {Promise<*>|undefined}
302
+ * @private
303
+ */
304
+ _removeLastTileFromCache(baseLevel) {
305
+ const tileIdToRemove = this.cache.get(baseLevel).peekLastKey();
306
+ const rtreePromise = this.cache.get(baseLevel).pop();
307
+ if (rtreePromise) {
308
+ return rtreePromise.then((rtree) => {
309
+ if (rtree) {
310
+ this.rtreeCache.delete(tileIdToRemove);
311
+ setTimeout(() => {
312
+ this._unTrackFeatures(rtree.all().map(item => item.value), tileIdToRemove);
313
+ rtree.clear();
314
+ }, 0);
315
+ }
316
+ });
317
+ }
318
+ return undefined;
319
+ }
320
+
321
+ /**
322
+ * returns the closest baseLevel for the given resolution
323
+ * @param {number} resolution
324
+ * @param {number} latitude in radians
325
+ * @returns {number}
326
+ * @api
327
+ */
328
+ getBaseLevelForResolution(resolution, latitude) {
329
+ const scaledResolution = resolution / Math.cos(latitude);
330
+ let currentLevel = 0;
331
+ for (let i = 0; i < mercatorResolutionsToLevel.length; i++) {
332
+ currentLevel = i;
333
+ if (scaledResolution >= mercatorResolutionsToLevel[i]) {
334
+ break;
335
+ }
336
+ }
337
+ const baseLevel = this.getBaseLevel(currentLevel);
338
+ return baseLevel === undefined ? this.baseLevels[this.baseLevels.length - 1] : baseLevel;
339
+ }
340
+
341
+ /**
342
+ * returns the nearest parent BaseLevel or undefined if no parent baseLevel is found
343
+ * @param {number} level
344
+ * @returns {number|undefined}
345
+ * @api
346
+ */
347
+ getBaseLevel(level) {
348
+ return this.baseLevels.find((baseLevel) => {
349
+ return level >= baseLevel;
350
+ });
351
+ }
352
+
353
+ /**
354
+ *
355
+ * @param {number} x
356
+ * @param {number} y
357
+ * @param {number} level
358
+ * @returns {string}
359
+ * @api
360
+ */
361
+ // eslint-disable-next-line class-methods-use-this
362
+ getCacheKey(x, y, level) {
363
+ return `${level}/${x}/${y}`;
364
+ }
365
+
366
+ /**
367
+ * @param {number} baseLevel
368
+ * @param {import("@vcmap/cesium").Cartographic} tileCenter
369
+ * @returns {Promise<import("rbush").default<tileProviderRTreeEntry>|null>}
370
+ * @private
371
+ */
372
+ async _getRtreeForBaseTile(baseLevel, tileCenter) {
373
+ const baseTile = this.tilingScheme.positionToTileXY(tileCenter, baseLevel);
374
+ const baseTileCacheKey = this.getCacheKey(baseTile.x, baseTile.y, baseLevel);
375
+ if (this.cache.has(baseLevel)) {
376
+ if (!this.cache.get(baseLevel).containsKey(baseTileCacheKey)) {
377
+ const featuresPromise = this.loader(baseTile.x, baseTile.y, baseLevel);
378
+ this._addTilePromiseToCache(featuresPromise, baseLevel, baseTileCacheKey);
379
+ }
380
+ return this.cache.get(baseLevel).get(baseTileCacheKey);
381
+ }
382
+ return null;
383
+ }
384
+
385
+ /**
386
+ * returns the features intersecting this coordinate. Depending on the resolution a buffer around the coordinate is requested.
387
+ * The Buffer has the size of the resolution.
388
+ * @param {import("ol/coordinate").Coordinate} coordinate in mercator
389
+ * @param {number} resolution in m per pixel
390
+ * @returns {Promise<Array<import("ol").Feature<import("ol/geom/Geometry").default>>>}
391
+ * @api
392
+ */
393
+ async getFeaturesByCoordinate(coordinate, resolution) {
394
+ const extent = createOrUpdateFromCoordinate(coordinate);
395
+ buffer(extent, resolution, extent);
396
+ const wgs84Coordinate = mercatorToWgs84Transformer(coordinate);
397
+ const cartographic = Cartographic.fromDegrees(wgs84Coordinate[0], wgs84Coordinate[1]);
398
+ const baseLevel = this.getBaseLevelForResolution(resolution, cartographic.latitude);
399
+ const rtree = await this._getRtreeForBaseTile(baseLevel, cartographic);
400
+ if (rtree) {
401
+ const features = rtree.search({
402
+ minX: extent[0],
403
+ minY: extent[1],
404
+ maxX: extent[2],
405
+ maxY: extent[3],
406
+ }).map(item => item.value);
407
+ return features;
408
+ }
409
+ return [];
410
+ }
411
+
412
+ /**
413
+ * returns features for the requested Tile.
414
+ * @param {number} x
415
+ * @param {number} y
416
+ * @param {number} level - if the level is not a base level, will use the closest match
417
+ * @returns {Promise<Array<import("ol").Feature<import("ol/geom/Geometry").default>>>}
418
+ * @api
419
+ */
420
+ async getFeaturesForTile(x, y, level) {
421
+ const rectangle = this.tilingScheme.tileXYToRectangle(x, y, level);
422
+ const tileCenter = Rectangle.center(rectangle);
423
+ const baseLevel = this.getBaseLevel(level);
424
+ if (baseLevel != null) {
425
+ const rtree = await this._getRtreeForBaseTile(baseLevel, tileCenter);
426
+ if (rtree) {
427
+ if (level === baseLevel) {
428
+ return rtree.all().map(item => item.value);
429
+ } else {
430
+ const extent = rectangleToExtent(rectangle);
431
+ const features = rtree.search({
432
+ minX: extent[0],
433
+ minY: extent[1],
434
+ maxX: extent[2],
435
+ maxY: extent[3],
436
+ }).map(item => item.value);
437
+ return features;
438
+ }
439
+ }
440
+ } else if (this.allowTileAggregation && (this.baseLevels[this.baseLevels.length - 1] - level) <= 2) {
441
+ // tile aggregation, only allowed for 2 levels
442
+ const childLevel = level + 1;
443
+ const childNorth = x * 2;
444
+ const childWest = y * 2;
445
+ return [
446
+ ...await this.getFeaturesForTile(childNorth, childWest, childLevel),
447
+ ...await this.getFeaturesForTile(childNorth + 1, childWest, childLevel),
448
+ ...await this.getFeaturesForTile(childNorth + 1, childWest + 1, childLevel),
449
+ ...await this.getFeaturesForTile(childNorth, childWest + 1, childLevel),
450
+ ];
451
+ }
452
+ return [];
453
+ }
454
+
455
+ /**
456
+ * Retrieves all features which intersect the given extent. Will load all intersecting tiles.
457
+ * @param {import("@vcmap/core").Extent} extent
458
+ * @param {number=} level - Optional level to request. Will use highest level if omitted. If the provided level is not a base level, will use the closest match.
459
+ * @returns {Promise<Array<import("ol").Feature<import("ol/geom/Geometry").default>>>}
460
+ * @api
461
+ */
462
+ async getFeaturesForExtent(extent, level) {
463
+ let usedLevel = level != null ? level : this.baseLevels[0];
464
+ usedLevel = this.getBaseLevel(usedLevel);
465
+ const [minx, miny, maxx, maxy] = extent.getCoordinatesInProjection(wgs84Projection);
466
+ const topLeft = this.tilingScheme.positionToTileXY(Cartographic.fromDegrees(minx, maxy), usedLevel);
467
+ const bottomRight = this.tilingScheme.positionToTileXY(Cartographic.fromDegrees(maxx, miny), usedLevel);
468
+ const tileCoordinates = [];
469
+ for (let { x } = topLeft; x <= bottomRight.x; x++) {
470
+ for (let { y } = topLeft; y <= bottomRight.y; y++) {
471
+ tileCoordinates.push([x, y]);
472
+ }
473
+ }
474
+
475
+ const features = await Promise.all(tileCoordinates.map(([x, y]) => this.getFeaturesForTile(x, y, usedLevel)));
476
+ const mercatorExtent = extent.getCoordinatesInProjection(mercatorProjection);
477
+ return features
478
+ .flat()
479
+ .filter((f) => {
480
+ const geometry = f.getGeometry();
481
+ return geometry && geometry.intersectsExtent(mercatorExtent);
482
+ });
483
+ }
484
+
485
+ /**
486
+ * calls the given Function for Each feature currently in the cache
487
+ * @param {function(import("ol").Feature<import("ol/geom/Geometry").default>): void} callback
488
+ * @api
489
+ */
490
+ forEachFeature(callback) {
491
+ this.rtreeCache.forEach((rtree) => {
492
+ rtree.all().map(item => item.value).forEach(callback);
493
+ });
494
+ }
495
+
496
+ /**
497
+ * Public API to load features from a source (for example a rest API, or WFS)
498
+ *
499
+ * Can be used to write custom TileProvider to provide an interface to a "feature Source"
500
+ * Can also be used to manipulate the features, for example setting an ID Prefix or filter the features.
501
+ *
502
+ * @example to request Geojson from a rest API:
503
+ * const rectangle = this.tilingScheme.tileXYToRectangle(x, y, z);
504
+ * const southwest = Rectangle.southwest(rectangle);
505
+ * const northeast = Rectangle.northeast(rectangle);
506
+ * const minx = CesiumMath.toDegrees(southwest.longitude);
507
+ * const miny = CesiumMath.toDegrees(southwest.latitude);
508
+ * const maxx = CesiumMath.toDegrees(northeast.longitude);
509
+ * const maxy = CesiumMath.toDegrees(northeast.latitude);
510
+ * const url = `http://myFeatureSource/layer/getFeatures?minx=${minx}&miny=${miny}&maxx=${maxx}&maxy=${maxy}`
511
+ *
512
+ * return fetch.get(url)
513
+ * .then(response => response.json())
514
+ * .then((data) => {
515
+ * const { features } = GeoJSONparseGeoJSON(data.data, { dynamicStyle: true });
516
+ * return features;
517
+ * });
518
+ * @param {number} x
519
+ * @param {number} y
520
+ * @param {number} z
521
+ * @returns {Promise<Array<import("ol").Feature<import("ol/geom/Geometry").default>>>}
522
+ */
523
+ // eslint-disable-next-line class-methods-use-this,no-unused-vars
524
+ async loader(x, y, z) {
525
+ return [];
526
+ }
527
+
528
+ /**
529
+ * @inheritDoc
530
+ * @returns {TileProviderOptions}
531
+ * @api
532
+ */
533
+ getConfigObject() {
534
+ const config = /** @type {TileProviderOptions} */ (super.getConfigObject());
535
+ const defaultOptions = TileProvider.getDefaultOptions();
536
+
537
+ if (defaultOptions.tileCacheSize !== this.tileCacheSize) {
538
+ config.tileCacheSize = this.tileCacheSize;
539
+ }
540
+
541
+ if (defaultOptions.baseLevels !== this.baseLevels) {
542
+ config.baseLevels = this.baseLevels.slice();
543
+ }
544
+
545
+ if (defaultOptions.trackFeaturesToTiles !== this.trackFeaturesToTiles) {
546
+ config.trackFeaturesToTiles = this.trackFeaturesToTiles;
547
+ }
548
+ return config;
549
+ }
550
+
551
+ /**
552
+ * clears the cache and removes all entries
553
+ * @api
554
+ */
555
+ async clearCache() {
556
+ const rtreePromises = [];
557
+ this.cache.forEach((lruCache) => {
558
+ lruCache.forEach((rtreePromise) => {
559
+ rtreePromises.push(rtreePromise);
560
+ });
561
+ lruCache.clear();
562
+ });
563
+ await Promise.all(rtreePromises);
564
+ this.rtreeCache.forEach((rtree) => {
565
+ rtree.clear();
566
+ });
567
+ this.rtreeCache.clear();
568
+ this.featureIdToTileIds.clear();
569
+ }
570
+
571
+ /**
572
+ * @inheritDoc
573
+ * @api
574
+ */
575
+ destroy() {
576
+ super.destroy();
577
+ this.clearCache();
578
+ this.cache.clear();
579
+ this.isDestroyed = true;
580
+ this.tileLoadedEvent.destroy();
581
+ }
582
+ }
583
+
584
+ export default TileProvider;
@@ -0,0 +1,28 @@
1
+ import { VcsClassRegistry } from '../../classRegistry.js';
2
+ import TileProvider from './tileProvider.js';
3
+ import URLTemplateTileProvider from './urlTemplateTileProvider.js';
4
+ import StaticGeojsonTileProvider from './staticGeojsonTileProvider.js';
5
+ import MVTTileProvider from './mvtTileProvider.js';
6
+
7
+ VcsClassRegistry.registerClass(TileProvider.className, TileProvider);
8
+ VcsClassRegistry.registerClass(URLTemplateTileProvider.className, URLTemplateTileProvider);
9
+ VcsClassRegistry.registerClass(StaticGeojsonTileProvider.className, StaticGeojsonTileProvider);
10
+ VcsClassRegistry.registerClass(MVTTileProvider.className, MVTTileProvider);
11
+
12
+ /**
13
+ * TileProvider
14
+ * @namespace tileProvider
15
+ * @api stable
16
+ */
17
+
18
+ /**
19
+ * @param {Object} options
20
+ * @returns {Promise<TileProvider>}
21
+ * @api
22
+ * @export
23
+ */
24
+ function factory(options) {
25
+ return VcsClassRegistry.create(options.type, options);
26
+ }
27
+
28
+ export default factory;