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