@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,572 @@
|
|
|
1
|
+
import RBush from 'rbush';
|
|
2
|
+
import knn from 'rbush-knn';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { getTransform } from 'ol/proj.js';
|
|
5
|
+
import { createXYZ } from 'ol/tilegrid.js';
|
|
6
|
+
import Feature from 'ol/Feature.js';
|
|
7
|
+
import Polygon, { fromExtent } from 'ol/geom/Polygon.js';
|
|
8
|
+
import Vector from 'ol/source/Vector.js';
|
|
9
|
+
import { boundingExtent, buffer, containsCoordinate, getCenter } from 'ol/extent.js';
|
|
10
|
+
import { Event as CesiumEvent } from '@vcmap/cesium';
|
|
11
|
+
import { DataState, getStateFromStatesArray } from './ObliqueDataSet.js';
|
|
12
|
+
import { ObliqueViewDirection } from './ObliqueViewDirection.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} ObliqueCameraOptions
|
|
16
|
+
* @property {string} name
|
|
17
|
+
* @property {!import("ol/coordinate").Coordinate} "principal-point"
|
|
18
|
+
* @property {import("ol/coordinate").Coordinate|undefined} "pixel-size"
|
|
19
|
+
* @property {Array<number>|undefined} "radial-distorsion-expected-2-found"
|
|
20
|
+
* @property {Array<number>|undefined} "radial-distorsion-found-2-expected"
|
|
21
|
+
* @property {import("ol/size").Size|undefined} size
|
|
22
|
+
* @api
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {Object} ObliqueGeneralImageInfo
|
|
27
|
+
* @property {number} width
|
|
28
|
+
* @property {number} height
|
|
29
|
+
* @property {Array<number>} "tile-resolution"
|
|
30
|
+
* @property {number} "tile-width"
|
|
31
|
+
* @property {number} "tile-height"
|
|
32
|
+
* @property {Array<ObliqueCameraOptions>|undefined} cameraParameter
|
|
33
|
+
* @property {string} crs
|
|
34
|
+
* @api
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The data within an image.json
|
|
39
|
+
* @typedef {Object} ObliqueImageJson
|
|
40
|
+
* @property {ObliqueGeneralImageInfo} generalImageInfo
|
|
41
|
+
* @property {number|undefined} tileLevel
|
|
42
|
+
* @property {Array<Array<*>>|undefined} images
|
|
43
|
+
* @property {Array<string>|undefined} availableTiles
|
|
44
|
+
* @api
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {Object} ObliqueVersion
|
|
49
|
+
* @property {number} version
|
|
50
|
+
* @property {number} buildNumber
|
|
51
|
+
* @api
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @typedef {Object} ObliqueCollectionOptions
|
|
56
|
+
* @property {string|undefined} name
|
|
57
|
+
* @property {Array<import("@vcmap/core").ObliqueDataSet>} dataSets
|
|
58
|
+
* @property {number|undefined} maxZoom
|
|
59
|
+
* @property {number|undefined} minZoom
|
|
60
|
+
* @property {number|undefined} [scaleFactor=4]
|
|
61
|
+
* @property {number|undefined} hideLevels
|
|
62
|
+
* @api
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {Array<import("@vcmap/core").ObliqueImage>} images
|
|
67
|
+
* @returns {Array<import("ol").Feature<import("ol/geom/Geometry").default>>}
|
|
68
|
+
*/
|
|
69
|
+
function getImageFeatures(images) {
|
|
70
|
+
return images.map((image) => {
|
|
71
|
+
const transform = getTransform(image.meta.projection, 'EPSG:3857');
|
|
72
|
+
const feature = new Feature({
|
|
73
|
+
geometry: new Polygon([image.groundCoordinates.map(c => transform(c.slice(0, 2)))]),
|
|
74
|
+
viewDirection: image.viewDirection,
|
|
75
|
+
});
|
|
76
|
+
feature.setId(image.name);
|
|
77
|
+
return feature;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @param {Object<string, DataState>} tiles
|
|
83
|
+
* @returns {Array<import("ol").Feature<import("ol/geom/Geometry").default>>}
|
|
84
|
+
*/
|
|
85
|
+
function getTileFeatures(tiles) {
|
|
86
|
+
const tileGrid = createXYZ();
|
|
87
|
+
return Object.entries(tiles)
|
|
88
|
+
.map(([stringTileCoord, state]) => {
|
|
89
|
+
const tileCoord = stringTileCoord.split('/')
|
|
90
|
+
.map(tc => Number.parseInt(tc, 10));
|
|
91
|
+
|
|
92
|
+
const extent = tileGrid.getTileCoordExtent(tileCoord);
|
|
93
|
+
const feature = new Feature({
|
|
94
|
+
geometry: fromExtent(extent),
|
|
95
|
+
state,
|
|
96
|
+
});
|
|
97
|
+
feature.setId(stringTileCoord);
|
|
98
|
+
return feature;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @class
|
|
104
|
+
* @export
|
|
105
|
+
*/
|
|
106
|
+
class ObliqueCollection {
|
|
107
|
+
/**
|
|
108
|
+
* @param {ObliqueCollectionOptions} options
|
|
109
|
+
*/
|
|
110
|
+
constructor(options) {
|
|
111
|
+
/**
|
|
112
|
+
* The unique name of the collection
|
|
113
|
+
* @type {string}
|
|
114
|
+
* @api
|
|
115
|
+
*/
|
|
116
|
+
this.name = options.name || uuidv4();
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Maps each direction to an RTree
|
|
120
|
+
* @type {Map<import("@vcmap/core").ObliqueViewDirection, RBush>}
|
|
121
|
+
* @private
|
|
122
|
+
*/
|
|
123
|
+
this._directionTrees = new Map();
|
|
124
|
+
/**
|
|
125
|
+
* Maps image name to image
|
|
126
|
+
* @type {Map<string, import("@vcmap/core").ObliqueImage>}
|
|
127
|
+
* @private
|
|
128
|
+
*/
|
|
129
|
+
this._images = new Map();
|
|
130
|
+
/**
|
|
131
|
+
* Maps urls to general infos & cameras
|
|
132
|
+
* @type {Array<import("@vcmap/core").ObliqueDataSet>}
|
|
133
|
+
* @private
|
|
134
|
+
*/
|
|
135
|
+
this._dataSets = [];
|
|
136
|
+
|
|
137
|
+
/** @type {ObliqueViewOptions} */
|
|
138
|
+
this.viewOptions = {
|
|
139
|
+
maxZoom: options.maxZoom || 0,
|
|
140
|
+
minZoom: options.minZoom || 0,
|
|
141
|
+
scaleFactor: options.scaleFactor || 4,
|
|
142
|
+
hideLevels: options.hideLevels || 0,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/** @type {boolean} */
|
|
146
|
+
this._loaded = false;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Event raised when images are loaded. Is passed an Array of ObliqueImages as its only argument.
|
|
150
|
+
* @type {import("@vcmap/cesium").Event}
|
|
151
|
+
* @api
|
|
152
|
+
*/
|
|
153
|
+
this.imagesLoaded = new CesiumEvent();
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @type {import("ol/source").Vector<import("ol/geom/Geometry").default>|null}
|
|
157
|
+
* @private
|
|
158
|
+
*/
|
|
159
|
+
this._tileFeatureSource = null;
|
|
160
|
+
/**
|
|
161
|
+
* @type {import("ol/source").Vector<import("ol/geom/Geometry").default>|null}
|
|
162
|
+
* @private
|
|
163
|
+
*/
|
|
164
|
+
this._imageFeatureSource = null;
|
|
165
|
+
if (Array.isArray(options.dataSets)) {
|
|
166
|
+
options.dataSets.forEach((dataSet) => {
|
|
167
|
+
this._addDataSet(dataSet);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @type {Array<import("@vcmap/core").ObliqueDataSet>}
|
|
174
|
+
* @api
|
|
175
|
+
* @readonly
|
|
176
|
+
*/
|
|
177
|
+
get dataSets() {
|
|
178
|
+
return this._dataSets.slice();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Indicates, that this collection has been loaded
|
|
183
|
+
* @type {boolean}
|
|
184
|
+
* @api
|
|
185
|
+
*/
|
|
186
|
+
get loaded() {
|
|
187
|
+
return this._loaded;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* A vector source of all tiles available to this collection in mercator. The feature have a "state" property,
|
|
192
|
+
* the id is the string tile coordinate "z/x/y" of the tile
|
|
193
|
+
* @type {import("ol/source/Vector").default<import("ol/geom/Geometry").default>}
|
|
194
|
+
* @api
|
|
195
|
+
* @readonly
|
|
196
|
+
*/
|
|
197
|
+
get tileFeatureSource() {
|
|
198
|
+
if (!this._tileFeatureSource) {
|
|
199
|
+
this._tileFeatureSource = this._createTileFeatureSource();
|
|
200
|
+
}
|
|
201
|
+
return this._tileFeatureSource;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* A vector source of all image currently loaded for this collection in mercator.
|
|
206
|
+
* The id is the image name. The feature has a "viewDirection" property.
|
|
207
|
+
* @type {import("ol/source/Vector").default<import("ol/geom/Geometry").default>}
|
|
208
|
+
* @api
|
|
209
|
+
* @readonly
|
|
210
|
+
*/
|
|
211
|
+
get imageFeatureSource() {
|
|
212
|
+
if (!this._imageFeatureSource) {
|
|
213
|
+
this._imageFeatureSource = this._createImageFeatureSource();
|
|
214
|
+
}
|
|
215
|
+
return this._imageFeatureSource;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* All currently loaded images
|
|
220
|
+
* @type {Array<import("@vcmap/core").ObliqueImage>}
|
|
221
|
+
* @api
|
|
222
|
+
* @readonly
|
|
223
|
+
*/
|
|
224
|
+
get images() {
|
|
225
|
+
return [...this._images.values()];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* @returns {import("ol/source/Vector").default<import("ol/geom/Geometry").default>}
|
|
230
|
+
* @private
|
|
231
|
+
*/
|
|
232
|
+
_createTileFeatureSource() {
|
|
233
|
+
const features = getTileFeatures(this.getTiles());
|
|
234
|
+
const source = new Vector();
|
|
235
|
+
source.addFeatures(features);
|
|
236
|
+
return source;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @returns {import("ol/source/Vector").default<import("ol/geom/Geometry").default>}
|
|
241
|
+
* @private
|
|
242
|
+
*/
|
|
243
|
+
_createImageFeatureSource() {
|
|
244
|
+
const features = getImageFeatures([...this._images.values()]);
|
|
245
|
+
const source = new Vector();
|
|
246
|
+
source.addFeatures(features);
|
|
247
|
+
return source;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @param {import("@vcmap/core").ObliqueDataSet} dataSet
|
|
252
|
+
* @returns {Promise<void>}
|
|
253
|
+
* @private
|
|
254
|
+
*/
|
|
255
|
+
async _loadDataSet(dataSet) {
|
|
256
|
+
await dataSet.load();
|
|
257
|
+
if (this._tileFeatureSource) {
|
|
258
|
+
const features = getTileFeatures(dataSet.getTiles());
|
|
259
|
+
this._tileFeatureSource.addFeatures(features);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Adds an oblique data set to this collection.
|
|
265
|
+
* @param {import("@vcmap/core").ObliqueDataSet} dataSet
|
|
266
|
+
* @private
|
|
267
|
+
*/
|
|
268
|
+
_addDataSet(dataSet) {
|
|
269
|
+
dataSet.imagesLoaded.addEventListener((images, tileCoordinate) => {
|
|
270
|
+
this._loadImages(images, tileCoordinate);
|
|
271
|
+
});
|
|
272
|
+
this._loadImages(dataSet.images);
|
|
273
|
+
this._dataSets.push(dataSet);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Adds an oblique data set to this collection.
|
|
278
|
+
* @param {import("@vcmap/core").ObliqueDataSet} dataSet
|
|
279
|
+
* @returns {Promise<void>}
|
|
280
|
+
* @api
|
|
281
|
+
*/
|
|
282
|
+
async addDataSet(dataSet) {
|
|
283
|
+
if (this._loadingPromise) {
|
|
284
|
+
await this._loadingPromise;
|
|
285
|
+
await this._loadDataSet(dataSet);
|
|
286
|
+
}
|
|
287
|
+
this._addDataSet(dataSet);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Loads all meta data associated with this collection
|
|
292
|
+
* @returns {Promise<void>}
|
|
293
|
+
* @api
|
|
294
|
+
*/
|
|
295
|
+
async load() {
|
|
296
|
+
if (!this._loadingPromise) {
|
|
297
|
+
this._loadingPromise = Promise.all(this._dataSets.map(i => this._loadDataSet(i)));
|
|
298
|
+
await this._loadingPromise;
|
|
299
|
+
this._loaded = true;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
await this._loadingPromise;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* @param {Array<import("@vcmap/core").ObliqueImage>} images
|
|
307
|
+
* @param {string=} tileCoordinate
|
|
308
|
+
* @private
|
|
309
|
+
*/
|
|
310
|
+
_loadImages(images, tileCoordinate) {
|
|
311
|
+
if (tileCoordinate && this._tileFeatureSource) {
|
|
312
|
+
const tileFeature = this._tileFeatureSource.getFeatureById(tileCoordinate);
|
|
313
|
+
if (tileFeature) {
|
|
314
|
+
tileFeature.set('state', DataState.READY);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const directions = new Map();
|
|
319
|
+
images.forEach((image) => {
|
|
320
|
+
this._images.set(image.name, image);
|
|
321
|
+
if (!directions.has(image.viewDirection)) {
|
|
322
|
+
directions.set(image.viewDirection, []);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const transform = getTransform(image.meta.projection, 'EPSG:3857');
|
|
326
|
+
const coord = image.centerPointOnGround.slice(0, 2);
|
|
327
|
+
transform(coord, coord);
|
|
328
|
+
directions.get(image.viewDirection).push({
|
|
329
|
+
minX: coord[0],
|
|
330
|
+
minY: coord[1],
|
|
331
|
+
maxX: coord[0],
|
|
332
|
+
maxY: coord[1],
|
|
333
|
+
name: image.name,
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
directions.forEach((imageItems, direction) => {
|
|
338
|
+
if (!this._directionTrees.get(direction)) {
|
|
339
|
+
this._directionTrees.set(direction, new RBush());
|
|
340
|
+
}
|
|
341
|
+
this._directionTrees.get(direction).load(imageItems);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
if (this._imageFeatureSource) {
|
|
345
|
+
const features = getImageFeatures(images);
|
|
346
|
+
this._imageFeatureSource.addFeatures(features);
|
|
347
|
+
}
|
|
348
|
+
this.imagesLoaded.raiseEvent(images);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Gets all available tile coordinates across all data sets, including their loaded state. Return value is
|
|
353
|
+
* an object, where the key is the tile coordinate in z/x/y and the value is the data state
|
|
354
|
+
* @returns {Object<string, DataState>}
|
|
355
|
+
* @api
|
|
356
|
+
*/
|
|
357
|
+
getTiles() {
|
|
358
|
+
/** @type {Object<string, DataState>} */
|
|
359
|
+
const tiles = {};
|
|
360
|
+
this._dataSets.forEach((dataSet) => {
|
|
361
|
+
Object.entries(dataSet.getTiles())
|
|
362
|
+
.forEach(([tileCoord, state]) => {
|
|
363
|
+
if (tiles[tileCoord]) {
|
|
364
|
+
tiles[tileCoord] = getStateFromStatesArray([state, tiles[tileCoord]]);
|
|
365
|
+
} else {
|
|
366
|
+
tiles[tileCoord] = state;
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
return tiles;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Returns an image by its name, if it has been loaded
|
|
376
|
+
* @param {string} name
|
|
377
|
+
* @returns {import("@vcmap/core").ObliqueImage}
|
|
378
|
+
* @api
|
|
379
|
+
*/
|
|
380
|
+
getImageByName(name) {
|
|
381
|
+
return this._images.get(name);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Returns a list of viewDirections which a currently available in this collection
|
|
386
|
+
* @returns {Array<ObliqueViewDirection>}
|
|
387
|
+
* @api
|
|
388
|
+
*/
|
|
389
|
+
getAvailableViewDirections() {
|
|
390
|
+
return [...this._directionTrees.keys()];
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Returns the state of the data for a given location an all underlying data sources
|
|
395
|
+
* @param {import("ol/coordinate").Coordinate} mercatorCoordinate - coordinate in web mercator
|
|
396
|
+
* @returns {DataState}
|
|
397
|
+
* @api
|
|
398
|
+
*/
|
|
399
|
+
getDataStateForCoordinate(mercatorCoordinate) {
|
|
400
|
+
const states = this._dataSets.map(i => i.getDataStateForCoordinate(mercatorCoordinate));
|
|
401
|
+
return getStateFromStatesArray(states);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Returns the state of the data for a given location an all underlying data sources
|
|
406
|
+
* @param {import("ol/coordinate").Coordinate} extent - coordinate in web mercator
|
|
407
|
+
* @returns {DataState}
|
|
408
|
+
* @api
|
|
409
|
+
*/
|
|
410
|
+
getDataStateForExtent(extent) {
|
|
411
|
+
const states = this._dataSets.map(i => i.getDataStateForExtent(extent));
|
|
412
|
+
return getStateFromStatesArray(states);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Loads data for a given mercator Coordinate
|
|
417
|
+
* @param {import("ol/coordinate").Coordinate} mercatorCoordinate - coordinate in web mercator
|
|
418
|
+
* @returns {Promise<void>}
|
|
419
|
+
* @api
|
|
420
|
+
*/
|
|
421
|
+
async loadDataForCoordinate(mercatorCoordinate) {
|
|
422
|
+
await Promise.all(this._dataSets.map(i => i.loadDataForCoordinate(mercatorCoordinate)));
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Loads all data tiles in the given extent
|
|
427
|
+
* @param {import("ol/extent").Extent} extent
|
|
428
|
+
* @returns {Promise<void>}
|
|
429
|
+
* @api
|
|
430
|
+
*/
|
|
431
|
+
async loadDataForExtent(extent) {
|
|
432
|
+
await Promise.all(this._dataSets.map(i => i.loadDataForExtent(extent)));
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* @param {import("ol/coordinate").Coordinate} mercatorCoordinate
|
|
437
|
+
* @param {import("@vcmap/core").ObliqueViewDirection} direction
|
|
438
|
+
* @returns {import("@vcmap/core").ObliqueImage|undefined}
|
|
439
|
+
* @private
|
|
440
|
+
*/
|
|
441
|
+
_getNextImageForCoordinate(mercatorCoordinate, direction) {
|
|
442
|
+
const tree = this._directionTrees.get(direction);
|
|
443
|
+
if (tree) {
|
|
444
|
+
const candidates = knn(tree, mercatorCoordinate[0], mercatorCoordinate[1], 1);
|
|
445
|
+
if (candidates.length === 1 && candidates[0].name) {
|
|
446
|
+
return this.getImageByName(candidates[0].name);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return undefined;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Returns the <i>closest</i> image for the given location and direction (location and image extent must not overlap).
|
|
454
|
+
* Returns undefined, if there are no images for the given direction
|
|
455
|
+
* @param {import("ol/coordinate").Coordinate} mercatorCoordinate - coordinate in web mercator
|
|
456
|
+
* @param {import("@vcmap/core").ObliqueViewDirection} direction - the preferred direction if no image in that direction can be found, other direction will be queried
|
|
457
|
+
* @returns {import("@vcmap/core").ObliqueImage|undefined}
|
|
458
|
+
* @api
|
|
459
|
+
*/
|
|
460
|
+
getImageForCoordinate(mercatorCoordinate, direction) {
|
|
461
|
+
const directions = [direction, ...Object.values(ObliqueViewDirection).filter(d => d !== direction)];
|
|
462
|
+
for (let i = 0; i < directions.length; i++) {
|
|
463
|
+
const image = this._getNextImageForCoordinate(mercatorCoordinate, directions[i]);
|
|
464
|
+
if (image) {
|
|
465
|
+
return image;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return undefined;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Loads all data for a location and then returns the <i>closest</i> image for the given location and direction (location and image extent must not overlap).
|
|
473
|
+
* Returns undefined, if there are no images for the given direction
|
|
474
|
+
* @param {import("ol/coordinate").Coordinate} mercatorCoordinate - coordinate in web mercator
|
|
475
|
+
* @param {import("@vcmap/core").ObliqueViewDirection} direction
|
|
476
|
+
* @returns {Promise<import("@vcmap/core").ObliqueImage|undefined>}
|
|
477
|
+
* @api
|
|
478
|
+
*/
|
|
479
|
+
async loadImageForCoordinate(mercatorCoordinate, direction) {
|
|
480
|
+
await this.loadDataForCoordinate(mercatorCoordinate);
|
|
481
|
+
return this.getImageForCoordinate(mercatorCoordinate, direction);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Checks, if an image exists for a given coordinated
|
|
486
|
+
* @param {import("ol/coordinate").Coordinate} mercatorCoordinate - coordinate in web mercator
|
|
487
|
+
* @param {import("@vcmap/core").ObliqueViewDirection} direction
|
|
488
|
+
* @returns {Promise<boolean>}
|
|
489
|
+
* @api
|
|
490
|
+
*/
|
|
491
|
+
async hasImageAtCoordinate(mercatorCoordinate, direction) {
|
|
492
|
+
const image = await this.loadImageForCoordinate(mercatorCoordinate, direction);
|
|
493
|
+
if (image) {
|
|
494
|
+
const transform = getTransform('EPSG:3857', image.meta.projection);
|
|
495
|
+
const internalCoordinates = mercatorCoordinate.slice(0, 2);
|
|
496
|
+
transform(internalCoordinates, internalCoordinates);
|
|
497
|
+
const extent = boundingExtent(image.groundCoordinates);
|
|
498
|
+
return containsCoordinate(extent, internalCoordinates);
|
|
499
|
+
}
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Loads the image adjacent to a given image in a certain direction from the provided image.
|
|
505
|
+
* Returns undefined if there are no images in that direction or there are no images for the direction
|
|
506
|
+
* of the provided image.
|
|
507
|
+
* @param {import("@vcmap/core").ObliqueImage} image
|
|
508
|
+
* @param {number} heading - 0 = east, PI / 2 = north, PI = west and PI * 1.5 = south
|
|
509
|
+
* @param {number=} [deviation=PI/4]
|
|
510
|
+
* @returns {Promise<import("@vcmap/core").ObliqueImage|undefined>}
|
|
511
|
+
* @api
|
|
512
|
+
*/
|
|
513
|
+
async loadAdjacentImage(image, heading, deviation = Math.PI / 4) {
|
|
514
|
+
const tree = this._directionTrees.get(image.viewDirection);
|
|
515
|
+
if (tree) {
|
|
516
|
+
const transform = getTransform(image.meta.projection, 'EPSG:3857');
|
|
517
|
+
const coords = image.groundCoordinates.map(c => transform(c.slice(0, 2)));
|
|
518
|
+
const extent = boundingExtent(coords);
|
|
519
|
+
await this.loadDataForExtent(buffer(extent, 200));
|
|
520
|
+
const center = getCenter(extent);
|
|
521
|
+
const neighbors = knn(tree, center[0], center[1], 20);
|
|
522
|
+
const found = neighbors.find((neighbour) => {
|
|
523
|
+
if (neighbour.name !== image.name) {
|
|
524
|
+
let angle = Math.atan2(neighbour.minY - center[1], neighbour.minX - center[0]);
|
|
525
|
+
if (angle <= 0) {
|
|
526
|
+
angle += Math.PI * 2;
|
|
527
|
+
}
|
|
528
|
+
let differenceAngle = angle - heading;
|
|
529
|
+
if (differenceAngle > Math.PI) {
|
|
530
|
+
differenceAngle -= (Math.PI * 2);
|
|
531
|
+
} else if (differenceAngle < -Math.PI) {
|
|
532
|
+
differenceAngle += (Math.PI * 2);
|
|
533
|
+
}
|
|
534
|
+
if (differenceAngle <= deviation && differenceAngle >= -deviation) {
|
|
535
|
+
return neighbour;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return false;
|
|
539
|
+
});
|
|
540
|
+
if (found) {
|
|
541
|
+
return this.getImageByName(found.name);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return undefined;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Destroys all data sets and all images and any image/tile features for this collection
|
|
549
|
+
* @api
|
|
550
|
+
*/
|
|
551
|
+
destroy() {
|
|
552
|
+
this._dataSets.forEach((ds) => { ds.destroy(); });
|
|
553
|
+
this._dataSets = [];
|
|
554
|
+
|
|
555
|
+
[...this._directionTrees.values()].forEach((tree) => { tree.clear(); });
|
|
556
|
+
this._directionTrees.clear();
|
|
557
|
+
|
|
558
|
+
this._images.clear();
|
|
559
|
+
|
|
560
|
+
if (this._tileFeatureSource) {
|
|
561
|
+
this._tileFeatureSource.clear(true);
|
|
562
|
+
this._tileFeatureSource = null;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (this._imageFeatureSource) {
|
|
566
|
+
this._imageFeatureSource.clear(true);
|
|
567
|
+
this._imageFeatureSource = null;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
export default ObliqueCollection;
|