@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,248 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import proj4 from 'proj4';
3
+ import { register } from 'ol/proj/proj4.js';
4
+ import { get as getProjection } from 'ol/proj.js';
5
+ import { Matrix3, Cartesian3, Matrix4 } from '@vcmap/cesium';
6
+ import ObliqueImage from './ObliqueImage.js';
7
+ import { obliqueViewDirectionNames } from './ObliqueViewDirection.js';
8
+ import ImageMeta from './ObliqueImageMeta.js';
9
+
10
+ /**
11
+ * @param {Object} json
12
+ * @returns {ObliqueVersion} version
13
+ */
14
+ export function getVersionFromImageJson(json) {
15
+ const version = {
16
+ version: null,
17
+ buildNumber: null,
18
+ };
19
+
20
+ if (json.version) {
21
+ const number = json.version.match(/\d+\.\d+/);
22
+ if (number) {
23
+ version.version = Number(number[0]);
24
+ }
25
+ const buildNumber = json.version.match(/-\d+-/);
26
+ if (buildNumber) {
27
+ version.buildNumber = Number(buildNumber[0].match(/\d+/)[0]);
28
+ }
29
+ }
30
+ return version;
31
+ }
32
+
33
+ /**
34
+ * @param {ObliqueImageJson} json
35
+ * @param {string} url
36
+ * @param {(import("ol/proj/Projection").default|null)=} projection
37
+ * @param {import("@vcmap/cesium").CesiumTerrainProvider=} terrainProvider
38
+ * @returns {Array<import("@vcmap/core").ObliqueImageMeta>}
39
+ */
40
+ export function parseImageMeta(json, url, projection, terrainProvider) {
41
+ let size;
42
+ if (json.generalImageInfo.width && json.generalImageInfo.height) {
43
+ size = /** @type {import("ol/size").Size} */ ([json.generalImageInfo.width, json.generalImageInfo.height]);
44
+ }
45
+ const tileResolution = json.generalImageInfo['tile-resolution'];
46
+ const tileSize = /** @type {import("ol/size").Size} */ ([json.generalImageInfo['tile-width'], json.generalImageInfo['tile-height']]);
47
+ let imageProjection = projection;
48
+ const imageMetas = [];
49
+ if (!imageProjection && json.generalImageInfo.crs) {
50
+ const crsUuid = uuidv4();
51
+ proj4.defs(crsUuid, json.generalImageInfo.crs);
52
+ register(proj4);
53
+ imageProjection = getProjection(crsUuid);
54
+ }
55
+
56
+ const defaultOptions = {
57
+ size,
58
+ tileResolution,
59
+ tileSize,
60
+ projection: imageProjection,
61
+ url,
62
+ terrainProvider,
63
+ };
64
+
65
+ if (json.generalImageInfo.cameraParameter) {
66
+ if (Array.isArray(json.generalImageInfo.cameraParameter)) {
67
+ json.generalImageInfo.cameraParameter.forEach((cameraOption) => {
68
+ imageMetas.push(new ImageMeta({ ...defaultOptions, ...cameraOption }));
69
+ });
70
+ } else if (typeof json.generalImageInfo.cameraParameter === 'object') {
71
+ Object.entries(json.generalImageInfo.cameraParameter).forEach(([name, cameraOption]) => {
72
+ imageMetas.push(new ImageMeta({ name, ...defaultOptions, ...cameraOption }));
73
+ });
74
+ }
75
+ }
76
+
77
+ if (imageMetas.length === 0) {
78
+ imageMetas.push(new ImageMeta({ name: 'default', ...defaultOptions }));
79
+ }
80
+ return imageMetas;
81
+ }
82
+
83
+ /**
84
+ * @param {ObliqueImageJson} json
85
+ * @param {Array<import("@vcmap/core").ObliqueImageMeta>} imageMetas
86
+ * @returns {Array<ObliqueImage>}
87
+ */
88
+ export function parseImageData(json, imageMetas) {
89
+ const imagesHeader = json.images[0];
90
+ const indices = {
91
+ name: imagesHeader.indexOf('name'),
92
+ width: imagesHeader.indexOf('width'),
93
+ height: imagesHeader.indexOf('height'),
94
+ tileResolution: imagesHeader.indexOf('tile-resolution'),
95
+ viewDirection: imagesHeader.indexOf('view-direction'),
96
+ viewDirectionAngle: imagesHeader.indexOf('view-direction-angle'),
97
+ groundCoordinates: imagesHeader.indexOf('groundCoordinates'),
98
+ centerPointOnGround: imagesHeader.indexOf('centerPointOnGround'),
99
+ cameraIndex: imagesHeader.indexOf('camera-index'),
100
+ projectionCenter: imagesHeader.indexOf('projection-center'),
101
+ pToRealworld: imagesHeader.indexOf('p-to-realworld'),
102
+ pToImage: imagesHeader.indexOf('p-to-image'),
103
+ };
104
+
105
+ const images = new Array(json.images.length - 1);
106
+ json.images.forEach((img, index) => {
107
+ if (index === 0) { // skip header image
108
+ return;
109
+ }
110
+ const coordsArrayPToRealworld = [];
111
+ if (img[indices.pToRealworld]) {
112
+ img[indices.pToRealworld].forEach((value) => {
113
+ coordsArrayPToRealworld.push(...value);
114
+ });
115
+ }
116
+ const pToRealworld = img[indices.pToRealworld] ? new Matrix3(...coordsArrayPToRealworld) : null;
117
+
118
+ const coordsArrayPToImage = [];
119
+ if (img[indices.pToImage]) {
120
+ img[indices.pToImage].forEach((value) => {
121
+ coordsArrayPToImage.push(...value);
122
+ });
123
+ coordsArrayPToImage.push(0, 0, 0, 1);
124
+ }
125
+ const projectionCenter = img[indices.projectionCenter] ?
126
+ Cartesian3.fromArray(img[indices.projectionCenter]) :
127
+ null;
128
+ const pToImage = img[indices.pToImage] ? new Matrix4(...coordsArrayPToImage) : null;
129
+
130
+ const meta = imageMetas[img[indices.cameraIndex] || 0];
131
+ if (!meta.size) {
132
+ if (img[indices.height] && img[indices.width]) {
133
+ meta.size = [img[indices.width], img[indices.height]];
134
+ } else {
135
+ // eslint-disable-next-line no-console
136
+ console.error('missing image meta size');
137
+ }
138
+ }
139
+
140
+ if (!meta.tileResolution) {
141
+ if (img[indices.tileResolution]) {
142
+ meta.tileResolution = img[indices.tileResolution];
143
+ } else {
144
+ // eslint-disable-next-line no-console
145
+ console.error('missing image meta tileResolution');
146
+ }
147
+ }
148
+
149
+ images[index - 1] = new ObliqueImage({
150
+ name: img[indices.name],
151
+ viewDirection: img[indices.viewDirection],
152
+ viewDirectionAngle: img[indices.viewDirectionAngle],
153
+ groundCoordinates: img[indices.groundCoordinates],
154
+ centerPointOnGround: img[indices.centerPointOnGround],
155
+ meta,
156
+ projectionCenter,
157
+ pToRealworld,
158
+ pToImage,
159
+ });
160
+ });
161
+
162
+ return images;
163
+ }
164
+
165
+ /**
166
+ * @param {ObliqueImageJson} json
167
+ * @param {Array<import("@vcmap/core").ObliqueImageMeta>} imageMetas
168
+ * @returns {Array<ObliqueImage>}
169
+ */
170
+ export function parseLegacyImageData(json, imageMetas) {
171
+ const { cameraParameter } = json.generalImageInfo;
172
+ const { version, buildNumber } = getVersionFromImageJson(json);
173
+ return /** @type {Array<*>} */ (json.images).map((img) => {
174
+ const viewDirection = obliqueViewDirectionNames[img['view-direction']];
175
+ const viewDirectionAngle = version >= 3.4 && buildNumber >= 18 ?
176
+ img['view-directionAngle'] :
177
+ undefined;
178
+ const projectionCenter = img['projection-center'];
179
+ const { name, groundCoordinates, centerPointOnGround } = img;
180
+
181
+ const cameraName = img['camera-name'];
182
+ const imageMeta = imageMetas.find(value => value.name === cameraName);
183
+ const meta = imageMeta || imageMetas[0];
184
+ if (!meta.size) {
185
+ if (img.height && img.width) {
186
+ meta.size = [img.width, img.height];
187
+ } else {
188
+ // eslint-disable-next-line no-console
189
+ console.error('missing image meta size');
190
+ }
191
+ }
192
+
193
+ if (!meta.tileResolution) {
194
+ if (img.tileResolution) {
195
+ meta.tileResolution = img.tileResolution;
196
+ } else {
197
+ // eslint-disable-next-line no-console
198
+ console.error('missing image meta tileResolution');
199
+ }
200
+ }
201
+
202
+ const imageOptions = {
203
+ name,
204
+ meta,
205
+ viewDirection,
206
+ viewDirectionAngle,
207
+ groundCoordinates,
208
+ centerPointOnGround,
209
+ };
210
+
211
+ if (imageMeta && cameraName) {
212
+ const cameraOptions = cameraParameter[cameraName];
213
+ const cameraMatrix = Matrix3.fromRowMajorArray([].concat(...cameraOptions['camera-matrix']));
214
+ const cameraMatrixInverse = Matrix3.inverse(cameraMatrix, new Matrix3());
215
+ const rotationMatrix = Matrix3.fromRowMajorArray([].concat(...img['rotation-matrix']));
216
+ const rotationMatrixTransposed = Matrix3.transpose(rotationMatrix, new Matrix3());
217
+ const focalLength = cameraOptions['focal-length'] * (-1);
218
+ Matrix3.multiplyByScalar(cameraMatrixInverse, focalLength, cameraMatrixInverse);
219
+ const pToRealworld = Matrix3.multiply(rotationMatrixTransposed, cameraMatrixInverse, new Matrix3());
220
+
221
+ const cameraMatrix4 = Matrix4.fromRotationTranslation(
222
+ cameraMatrix,
223
+ Cartesian3.ZERO,
224
+ new Matrix4(),
225
+ );
226
+ const projectionCenterCartesian = Cartesian3.fromArray(projectionCenter);
227
+ const e = Matrix4.fromTranslation(
228
+ Cartesian3.multiplyByScalar(projectionCenterCartesian, -1, new Cartesian3()),
229
+ new Matrix4(),
230
+ );
231
+ const rotationMatrix4 = Matrix4.fromRotationTranslation(
232
+ rotationMatrix,
233
+ Cartesian3.ZERO,
234
+ new Matrix4(),
235
+ );
236
+ const pToImage = Matrix4.multiply(
237
+ cameraMatrix4,
238
+ Matrix4.multiply(rotationMatrix4, e, new Matrix4()),
239
+ new Matrix4(),
240
+ );
241
+ imageOptions.projectionCenter = projectionCenterCartesian;
242
+ imageOptions.pToRealworld = pToRealworld;
243
+ imageOptions.pToImage = pToImage;
244
+ }
245
+ return new ObliqueImage(imageOptions);
246
+ });
247
+ }
248
+
@@ -0,0 +1,386 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import { Cesium3DTileset } from '@vcmap/cesium';
3
+
4
+ import { check } from '@vcsuite/check';
5
+ import { parseBoolean } from '@vcsuite/parsers';
6
+ import { getLogger as getLoggerByName } from '@vcsuite/logger';
7
+ import CesiumMap from '../../maps/cesium.js';
8
+ import VcsEvent from '../../event/vcsEvent.js';
9
+ import LayerCollection from '../layerCollection.js';
10
+
11
+ /**
12
+ * @namespace clipping
13
+ * @export
14
+ * @api
15
+ */
16
+
17
+ /**
18
+ * Object to define an entity which is clipped by this ClippingObject
19
+ * @typedef {Object} ClippingObjectEntityOption
20
+ * @property {string} layerName
21
+ * @property {string} entityId
22
+ * @api
23
+ */
24
+
25
+ /**
26
+ * @typedef {Object} ClippingObjectOptions
27
+ * @property {Array<string>|undefined} layerNames
28
+ * @property {Array<ClippingObjectEntityOption>|undefined} entities
29
+ * @property {import("@vcmap/cesium").ClippingPlaneCollection|undefined} clippingPlaneCollection
30
+ * @property {boolean} [terrain=false]
31
+ * @property {boolean} [local=false] - if not local, coordinates are expected in ECEF
32
+ * @api
33
+ */
34
+
35
+ /**
36
+ * @returns {import("@vcsuite/logger").Logger}
37
+ */
38
+ function getLogger() {
39
+ return getLoggerByName('vcs.vcm.util.clipping.ClippingObject');
40
+ }
41
+
42
+ const globeSymbol = Symbol('ClippingObjectGlobe');
43
+
44
+ /**
45
+ * The ClippingObject is a container for a Cesium.ClippingPlaneCollection. The container holds information on the
46
+ * targeted Cesium objects, based on layerNames (for [CesiumTileset]{@link CesiumTileset}) or
47
+ * layerName and entity id for Cesium.DataSource which are part of an [DataSource]{@link DataSource} layer.
48
+ * Adding a ClippingObject to the [ClippingObjectManager]{@link ClippingObjectManager} applies the
49
+ * objects Cesium.ClippingPlaneCollection where applicable. Once added, changes to the targets of the object are tracked.
50
+ * To update the Cesium.ClippingPlaneCollection or its definitions, you must trigger an update by setting the clippingPlaneCollection
51
+ * property to the new definition.
52
+ * @class
53
+ * @export
54
+ * @api stable
55
+ */
56
+ class ClippingObject {
57
+ /**
58
+ * @param {ClippingObjectOptions=} options
59
+ */
60
+ constructor(options = {}) {
61
+ /** @type {string} */
62
+ this.id = uuidv4();
63
+
64
+ /**
65
+ * The current layerNames. Use add/removeimport("@vcmap/core").Layer to manipulate.
66
+ * @type {Array<string>}
67
+ * @readonly
68
+ * @api
69
+ */
70
+ this.layerNames = options.layerNames || [];
71
+
72
+ /**
73
+ * The current entities and their respective layerNames. Use add/removeEntity to manipulate
74
+ * @type {Array<ClippingObjectEntityOption>}
75
+ * @readonly
76
+ * @api
77
+ */
78
+ this.entities = options.entities || [];
79
+
80
+ /**
81
+ * Key is a semantic identifier, eg. layerName or layerName-entitiyId, depending on the target. Targets
82
+ * represent Cesium Object which support the clippingPlanes API
83
+ * @type {Map<(string|symbol), import("@vcmap/cesium").Entity|import("@vcmap/cesium").Cesium3DTileset|import("@vcmap/cesium").Globe>}
84
+ */
85
+ this.targets = new Map();
86
+
87
+ /**
88
+ * @type {import("@vcmap/cesium").ClippingPlaneCollection|null}
89
+ * @private
90
+ */
91
+ this._clippingPlaneCollection = options.clippingPlaneCollection || null;
92
+ /**
93
+ * @type {boolean}
94
+ * @private
95
+ */
96
+ this._terrain = parseBoolean(options.terrain, false);
97
+ /**
98
+ * @type {boolean}
99
+ * @private
100
+ */
101
+ this._local = parseBoolean(options.local, false);
102
+
103
+ /**
104
+ * Event, raised on a change of targets
105
+ * @type {VcsEvent<void>}
106
+ * @api
107
+ */
108
+ this.targetsUpdated = new VcsEvent();
109
+
110
+ /**
111
+ * Event, raised on changes to the clippingPlaneCollection property
112
+ * @type {VcsEvent<void>}
113
+ * @api
114
+ */
115
+ this.clippingPlaneUpdated = new VcsEvent();
116
+
117
+ /**
118
+ * @type {Set<import("@vcmap/core").FeatureStore>}
119
+ * @private
120
+ */
121
+ this._cachedFeatureStoreLayers = new Set();
122
+ this._activeMap = null;
123
+ this._layerCollection = null;
124
+ }
125
+
126
+ /**
127
+ * The current Cesium.ClippingPlaneCollection. To update the collection, set this property to the new definition.
128
+ * @api
129
+ * @type {import("@vcmap/cesium").ClippingPlaneCollection|null}
130
+ */
131
+ get clippingPlaneCollection() { return this._clippingPlaneCollection; }
132
+
133
+ /**
134
+ * @param {import("@vcmap/cesium").ClippingPlaneCollection} clippingPlaneCollection
135
+ */
136
+ set clippingPlaneCollection(clippingPlaneCollection) {
137
+ this._clippingPlaneCollection = clippingPlaneCollection;
138
+ this.clippingPlaneUpdated.raiseEvent();
139
+ }
140
+
141
+ /**
142
+ * Flag to indicate whether the globe/terrain is part of the targets.
143
+ * @api
144
+ * @type {boolean}
145
+ */
146
+ get terrain() { return this._terrain; }
147
+
148
+ /**
149
+ * @param {boolean} terrain
150
+ */
151
+ set terrain(terrain) {
152
+ check(terrain, Boolean);
153
+
154
+ if (this._terrain !== terrain) {
155
+ this._terrain = terrain;
156
+ this.handleMapChanged(this._activeMap);
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Flag to indicate, whether this ClippingObject represents coordinates in a local frame. If false,
162
+ * Plane coordiantes are assumed to be in ECEF or have an appropriate model matrix
163
+ * applied to the Cesium.ClippingPlaneCollection.
164
+ * @api
165
+ * @type {boolean}
166
+ */
167
+ get local() { return this._local; }
168
+
169
+ /**
170
+ * @param {boolean} local
171
+ */
172
+ set local(local) {
173
+ check(local, Boolean);
174
+
175
+ if (this._local !== local) {
176
+ this._local = local;
177
+ this.clippingPlaneUpdated.raiseEvent();
178
+ }
179
+ }
180
+
181
+ /**
182
+ * @param {import("@vcmap/core").LayerCollection} layerCollection
183
+ */
184
+ setLayerCollection(layerCollection) {
185
+ check(layerCollection, LayerCollection);
186
+
187
+ if (this._layerCollection && this._layerCollection !== layerCollection) {
188
+ throw new Error('layerCollection has already been set');
189
+ }
190
+ this._layerCollection = layerCollection;
191
+ [...this._layerCollection].forEach((l) => {
192
+ this.handleLayerChanged(l);
193
+ });
194
+ }
195
+
196
+ /**
197
+ * @param {import("@vcmap/core").Layer} layer
198
+ */
199
+ handleLayerChanged(layer) {
200
+ const map = this._activeMap;
201
+ if (map instanceof CesiumMap) {
202
+ if (this.layerNames.includes(layer.name)) {
203
+ if (layer.active) {
204
+ const visualisations = map.getVisualizationsForLayer(layer);
205
+ const tilesets = visualisations ?
206
+ [...visualisations]
207
+ .filter(v => v instanceof Cesium3DTileset) :
208
+ [];
209
+
210
+ if (tilesets.length > 0) {
211
+ tilesets.forEach(/** @param {import("@vcmap/cesium").Cesium3DTileset} tileset */ (tileset) => {
212
+ tileset.readyPromise.then((cesium3DTileset) => {
213
+ if (this.layerNames.includes(layer.name) && layer.active) {
214
+ this.targets.set(layer.name, cesium3DTileset);
215
+ this.targetsUpdated.raiseEvent();
216
+ }
217
+ });
218
+ });
219
+ } else {
220
+ const index = this.layerNames.indexOf(layer.name);
221
+ getLogger().warning(`layer ${layer.name} cannot have a ClippingObject applied`);
222
+ this.layerNames.splice(index, 1);
223
+ }
224
+ } else if (this.targets.has(layer.name)) {
225
+ this.targets.delete(layer.name);
226
+ this.targetsUpdated.raiseEvent();
227
+ }
228
+ } else if (this.entities.find(eo => eo.layerName === layer.name)) {
229
+ let raise = false;
230
+ const visualisations = map.getVisualizationsForLayer(layer);
231
+ const dataSource = visualisations ?
232
+ [...visualisations][0] :
233
+ null;
234
+
235
+ if (!dataSource) {
236
+ const index = this.layerNames.indexOf(layer.name);
237
+ getLogger().warning(`layer ${layer.name} cannot have a ClippingObject applied`);
238
+ this.layerNames.splice(index, 1);
239
+ return;
240
+ }
241
+
242
+ this.entities
243
+ .filter(eo => eo.layerName === layer.name)
244
+ .forEach((eo) => {
245
+ const key = `${eo.layerName}-${eo.entityId}`;
246
+ if (layer.active) {
247
+ const entity = /** @type {import("@vcmap/cesium").CustomDataSource} */ (dataSource)
248
+ .entities.getById(eo.entityId);
249
+ if (entity) {
250
+ this.targets.set(key, entity);
251
+ raise = true;
252
+ } else {
253
+ const index = this.entities.indexOf(eo);
254
+ getLogger().warning(`could not find entity with id ${eo.entityId} in layer ${eo.layerName}`);
255
+ this.entities.splice(index, 1);
256
+ }
257
+ } else if (this.targets.has(key)) {
258
+ this.targets.delete(key);
259
+ raise = true;
260
+ }
261
+ });
262
+
263
+ if (raise) {
264
+ this.targetsUpdated.raiseEvent();
265
+ }
266
+ }
267
+ } else if (this.layerNames.includes(layer.name) && layer.className === 'vcs.vcm.layer.FeatureStore') {
268
+ if (layer.active) {
269
+ this._cachedFeatureStoreLayers.add(/** @type {import("@vcmap/core").FeatureStore} */ (layer));
270
+ } else if (this._cachedFeatureStoreLayers.has(/** @type {import("@vcmap/core").FeatureStore} */ (layer))) {
271
+ this._cachedFeatureStoreLayers.delete(/** @type {import("@vcmap/core").FeatureStore} */ (layer));
272
+ }
273
+ }
274
+ }
275
+
276
+ /**
277
+ * @param {import("@vcmap/core").VcsMap|null} map
278
+ */
279
+ handleMapChanged(map) {
280
+ if (map instanceof CesiumMap) {
281
+ const { globe } = map.getScene();
282
+ let raise = false;
283
+ if (this._terrain && !this.targets.has(globeSymbol)) {
284
+ this.targets.set(globeSymbol, globe);
285
+ raise = true;
286
+ } else if (!this._terrain && this.targets.has(globeSymbol)) {
287
+ this.targets.delete(globeSymbol);
288
+ raise = true;
289
+ }
290
+
291
+ if (raise) {
292
+ this.targetsUpdated.raiseEvent();
293
+ }
294
+
295
+ if (this._cachedFeatureStoreLayers.size > 0) {
296
+ this._cachedFeatureStoreLayers.forEach((layer) => { this.handleLayerChanged(layer); });
297
+ this._cachedFeatureStoreLayers.clear();
298
+ }
299
+ }
300
+ this._activeMap = map;
301
+ }
302
+
303
+ /**
304
+ * add a layer name to the ClippingObject's layerNames array
305
+ * @api
306
+ * @param {string} layerName
307
+ */
308
+ addLayer(layerName) {
309
+ check(layerName, String);
310
+
311
+ if (!this.layerNames.includes(layerName)) {
312
+ this.layerNames.push(layerName);
313
+ const layer = this._layerCollection ?
314
+ this._layerCollection.getByKey(layerName) :
315
+ null;
316
+ // XXX active state is not part of this yet
317
+ if (layer && layer.active) {
318
+ this.handleLayerChanged(layer);
319
+ }
320
+ }
321
+ }
322
+
323
+ /**
324
+ * removes a layer from the ClippingObject's layerNames array
325
+ * @api
326
+ * @param {string} layerName
327
+ */
328
+ removeLayer(layerName) {
329
+ check(layerName, String);
330
+
331
+ const index = this.layerNames.indexOf(layerName);
332
+ if (index > -1) {
333
+ this.layerNames.splice(index, 1);
334
+ }
335
+
336
+ if (this.targets.has(layerName)) {
337
+ this.targets.delete(layerName);
338
+ this.targetsUpdated.raiseEvent();
339
+ }
340
+ }
341
+
342
+ /**
343
+ * add an entity to the ClippingObject's entities array
344
+ * @api
345
+ * @param {string} layerName
346
+ * @param {string} entityId
347
+ */
348
+ addEntity(layerName, entityId) {
349
+ check(layerName, String);
350
+ check(entityId, String);
351
+
352
+ if (!this.entities.find(eo => eo.layerName === layerName && eo.entityId === entityId)) {
353
+ this.entities.push({ layerName, entityId });
354
+ const layer = this._layerCollection ?
355
+ this._layerCollection.getByKey(layerName) :
356
+ null;
357
+ if (layer && layer.active) {
358
+ this.handleLayerChanged(layer);
359
+ }
360
+ }
361
+ }
362
+
363
+ /**
364
+ * remove entity from the ClippingObject's entities array
365
+ * @api
366
+ * @param {string} layerName
367
+ * @param {string} entityId
368
+ */
369
+ removeEntity(layerName, entityId) {
370
+ check(layerName, String);
371
+ check(entityId, String);
372
+
373
+ const index = this.entities.findIndex(c => c.layerName === layerName && c.entityId === entityId);
374
+ if (index > -1) {
375
+ this.entities.splice(index, 1);
376
+ }
377
+
378
+ const targetId = `${layerName}-${entityId}`;
379
+ if (this.targets.has(targetId)) {
380
+ this.targets.delete(targetId);
381
+ this.targetsUpdated.raiseEvent();
382
+ }
383
+ }
384
+ }
385
+
386
+ export default ClippingObject;