@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,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;
|