@vcmap/core 5.0.0-rc.23 → 5.0.0-rc.25

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 (65) hide show
  1. package/index.d.ts +824 -200
  2. package/index.js +24 -10
  3. package/package.json +2 -2
  4. package/src/category/category.js +1 -1
  5. package/src/featureProvider/abstractFeatureProvider.js +1 -18
  6. package/src/interaction/eventHandler.js +14 -0
  7. package/src/layer/cesium/cesiumTilesetCesiumImpl.js +4 -19
  8. package/src/layer/cesium/clusterContext.js +18 -0
  9. package/src/layer/cesium/vectorCesiumImpl.js +17 -2
  10. package/src/layer/cesium/vectorContext.js +187 -11
  11. package/src/layer/cesium/vectorRasterTileCesiumImpl.js +0 -1
  12. package/src/layer/cesiumTilesetLayer.js +1 -63
  13. package/src/layer/czmlLayer.js +1 -1
  14. package/src/layer/dataSourceLayer.js +1 -53
  15. package/src/layer/featureLayer.js +42 -38
  16. package/src/layer/featureStoreLayer.js +0 -15
  17. package/src/layer/layer.js +6 -11
  18. package/src/layer/layerSymbols.js +2 -1
  19. package/src/layer/oblique/vectorObliqueImpl.js +6 -0
  20. package/src/layer/openStreetMapLayer.js +6 -0
  21. package/src/layer/openlayers/layerOpenlayersImpl.js +69 -4
  22. package/src/layer/openlayers/rasterLayerOpenlayersImpl.js +0 -80
  23. package/src/layer/rasterLayer.js +1 -1
  24. package/src/layer/vectorHelpers.js +0 -85
  25. package/src/layer/vectorLayer.js +1 -9
  26. package/src/layer/vectorProperties.js +150 -8
  27. package/src/layer/vectorTileLayer.js +0 -9
  28. package/src/map/baseOLMap.js +17 -0
  29. package/src/map/cesiumMap.js +46 -8
  30. package/src/map/vcsMap.js +23 -5
  31. package/src/style/arcStyle.js +316 -0
  32. package/src/style/arrowStyle.js +269 -0
  33. package/src/util/editor/createFeatureSession.js +3 -1
  34. package/src/util/editor/editFeaturesSession.js +315 -0
  35. package/src/util/editor/editGeometrySession.js +5 -1
  36. package/src/util/editor/editorHelpers.js +118 -14
  37. package/src/util/editor/editorSessionHelpers.js +12 -0
  38. package/src/util/editor/editorSymbols.js +6 -0
  39. package/src/util/editor/interactions/editFeaturesMouseOverInteraction.js +120 -0
  40. package/src/util/editor/interactions/editGeometryMouseOverInteraction.js +1 -3
  41. package/src/util/editor/interactions/ensureHandlerSelectionInteraction.js +48 -0
  42. package/src/util/editor/interactions/mapInteractionController.js +5 -2
  43. package/src/util/editor/interactions/selectMultiFeatureInteraction.js +146 -0
  44. package/src/util/editor/interactions/translateVertexInteraction.js +2 -2
  45. package/src/util/editor/transformation/create2DHandlers.js +294 -0
  46. package/src/util/editor/transformation/create3DHandlers.js +575 -0
  47. package/src/util/editor/transformation/extrudeInteraction.js +91 -0
  48. package/src/util/editor/transformation/rotateInteraction.js +188 -0
  49. package/src/util/editor/transformation/scaleInteraction.js +185 -0
  50. package/src/util/editor/transformation/transformationHandler.js +168 -0
  51. package/src/util/editor/transformation/transformationTypes.js +83 -0
  52. package/src/util/editor/transformation/translateInteraction.js +209 -0
  53. package/src/util/featureconverter/arcToCesium.js +87 -0
  54. package/src/util/featureconverter/convert.js +7 -1
  55. package/src/util/featureconverter/extent3D.js +64 -1
  56. package/src/util/featureconverter/lineStringToCesium.js +103 -2
  57. package/src/util/featureconverter/pointHelpers.js +341 -0
  58. package/src/util/featureconverter/pointToCesium.js +27 -76
  59. package/src/util/geometryHelpers.js +11 -8
  60. package/src/util/mapCollection.js +30 -24
  61. package/src/util/math.js +99 -2
  62. package/tests/unit/helpers/cesiumHelpers.js +14 -4
  63. package/tests/unit/helpers/helpers.js +13 -0
  64. package/src/featureProvider/featureProviderHelpers.js +0 -50
  65. package/src/util/splitScreen.js +0 -233
package/src/util/math.js CHANGED
@@ -1,4 +1,5 @@
1
- import { Math as CesiumMath, Cartesian3 } from '@vcmap/cesium';
1
+ import { Math as CesiumMath, Cartesian3, Cartographic } from '@vcmap/cesium';
2
+ import Projection from './projection.js';
2
3
 
3
4
  /**
4
5
  * returns a new coordinate ([lon, lat] in degrees) from a distance, bearing and starting coordinate
@@ -21,7 +22,6 @@ export function coordinateAtDistance(coord, d, brng) {
21
22
  return [parseFloat(CesiumMath.toDegrees(lon2).toFixed(5)), parseFloat(CesiumMath.toDegrees(lat2).toFixed(5))];
22
23
  }
23
24
 
24
-
25
25
  /**
26
26
  * returns the initial bearing in degrees (0-360) between two coordinates
27
27
  * @param {Array.<number>} coords1 [lon, lat] in degrees
@@ -45,6 +45,16 @@ export function initialBearingBetweenCoords(coords1, coords2) {
45
45
  return brng;
46
46
  }
47
47
 
48
+ /**
49
+ * @param {import("ol/coordinate").Coordinate} p1 - mercator
50
+ * @param {import("ol/coordinate").Coordinate} p2 - mercator
51
+ * @returns {number} in radians
52
+ */
53
+ export function getCartesianBearing(p1, p2) {
54
+ let theta = Math.atan2(p2[0] - p1[0], p2[1] - p1[1]);
55
+ theta = theta < 0 ? theta + CesiumMath.TWO_PI : theta;
56
+ return theta;
57
+ }
48
58
 
49
59
  /**
50
60
  * returns distance between two coordinates
@@ -78,3 +88,90 @@ export function cartesian3DDistance(p1, p2) {
78
88
  export function modulo(n, m) {
79
89
  return ((n % m) + m) % m;
80
90
  }
91
+
92
+ /**
93
+ * @param {import("@vcmap/cesium").Cartographic} cartographic
94
+ * @returns {number[]}
95
+ */
96
+ export function cartographicToWgs84(cartographic) {
97
+ return [
98
+ CesiumMath.toDegrees(cartographic.longitude),
99
+ CesiumMath.toDegrees(cartographic.latitude),
100
+ cartographic.height,
101
+ ];
102
+ }
103
+
104
+ /**
105
+ * @param {import("ol/coordinate").Coordinate} mercatorCoordinates
106
+ * @param {import("@vcmap/cesium").Cartesian3=} result
107
+ * @returns {import("@vcmap/cesium").Cartesian3}
108
+ */
109
+ export function mercatorToCartesian(mercatorCoordinates, result) {
110
+ const wgs84Coords = Projection.mercatorToWgs84(mercatorCoordinates);
111
+ return Cartesian3.fromDegrees(wgs84Coords[0], wgs84Coords[1], wgs84Coords[2], null, result ?? new Cartesian3());
112
+ }
113
+
114
+ /**
115
+ * @param {import("@vcmap/cesium").Cartesian3} cartesian
116
+ * @returns {import("ol/coordinate").Coordinate}
117
+ */
118
+ export function cartesianToMercator(cartesian) {
119
+ const cartographic = Cartographic.fromCartesian(cartesian);
120
+ const wgs84 = cartographicToWgs84(cartographic);
121
+ return Projection.wgs84ToMercator(wgs84);
122
+ }
123
+
124
+ /**
125
+ * @param {import("ol/coordinate").Coordinate} p1
126
+ * @param {import("ol/coordinate").Coordinate} p2
127
+ * @returns {import("ol/coordinate").Coordinate}
128
+ */
129
+ export function getMidPoint(p1, p2) {
130
+ if (p1.length < 3 && p2.length < 3) {
131
+ return [
132
+ p1[0] + ((p2[0] - p1[0]) / 2),
133
+ p1[1] + ((p2[1] - p1[1]) / 2),
134
+ 0,
135
+ ];
136
+ }
137
+ return [
138
+ p1[0] + ((p2[0] - p1[0]) / 2),
139
+ p1[1] + ((p2[1] - p1[1]) / 2),
140
+ p1[2] + ((p2[2] - p1[2]) / 2),
141
+ ];
142
+ }
143
+
144
+ /**
145
+ * Gets the pitch between two points in degrees.
146
+ * @param {import("ol/coordinate").Coordinate} p1 - mercator
147
+ * @param {import("ol/coordinate").Coordinate} p2 - mercator
148
+ * @returns {number} in degrees
149
+ */
150
+ export function getCartesianPitch(p1, p2) {
151
+ let thirdPoint;
152
+ if (p1[2] > p2[2]) {
153
+ thirdPoint = p1.slice();
154
+ thirdPoint[2] = p2[2];
155
+ } else {
156
+ thirdPoint = p2.slice();
157
+ thirdPoint[2] = p1[2];
158
+ }
159
+ const scratch1 = mercatorToCartesian(p1);
160
+ const scratch2 = mercatorToCartesian(p2);
161
+ const scratch3 = mercatorToCartesian(thirdPoint);
162
+
163
+ Cartesian3.subtract(scratch2, scratch1, scratch2);
164
+ Cartesian3.subtract(scratch3, scratch1, scratch3);
165
+
166
+ Cartesian3.normalize(scratch2, scratch2);
167
+ Cartesian3.normalize(scratch3, scratch3);
168
+
169
+ let pitch;
170
+ if (p1[2] > p2[2]) {
171
+ pitch = CesiumMath.toDegrees(Math.acos(Cartesian3.dot(scratch2, scratch3))) - 90;
172
+ } else {
173
+ pitch = CesiumMath.toDegrees(Math.acos(Cartesian3.dot(scratch2, scratch3)));
174
+ }
175
+
176
+ return pitch;
177
+ }
@@ -19,6 +19,7 @@ import {
19
19
  import CesiumTilesetLayer from '../../../src/layer/cesiumTilesetLayer.js';
20
20
  import DataSourceLayer from '../../../src/layer/dataSourceLayer.js';
21
21
  import CesiumMap from '../../../src/map/cesiumMap.js';
22
+ import { Viewpoint } from '../../../index.js';
22
23
 
23
24
  export const tilesetJSON = {
24
25
  asset: {
@@ -110,12 +111,12 @@ export function createEntities(numberOfEntities = 1) {
110
111
  }
111
112
 
112
113
  /**
113
- * @param {sinon.sandbox} sandbox
114
- * @param {Cesium/Event} event
114
+ * @param {import("@vcmap/core").VcsEvent} event
115
+ * @param {sinon.sandbox} [sandbox]
115
116
  * @returns {sinon.spy}
116
117
  */
117
- export function getCesiumEventSpy(sandbox, event) {
118
- const spy = sandbox.spy();
118
+ export function getVcsEventSpy(event, sandbox) {
119
+ const spy = (sandbox ?? sinon).spy();
119
120
  const listener = event.addEventListener(function callback() {
120
121
  listener();
121
122
  // eslint-disable-next-line prefer-rest-params
@@ -162,6 +163,7 @@ export function getMockScene() {
162
163
  },
163
164
  pick() {},
164
165
  pickPosition() {},
166
+ drillPick() { return []; },
165
167
  destroy() {
166
168
  this.primitives.destroy();
167
169
  this.groundPrimitives.destroy();
@@ -210,6 +212,14 @@ export function getCesiumMap(mapOptions) {
210
212
  },
211
213
  };
212
214
  map.initialized = true;
215
+ const originalGetViewpointSync = map.getViewpointSync.bind(map);
216
+ map.getViewpointSync = function patchedGetVPSync() {
217
+ const vp = originalGetViewpointSync();
218
+ if (vp) {
219
+ return vp;
220
+ }
221
+ return new Viewpoint({});
222
+ };
213
223
 
214
224
  return map;
215
225
  }
@@ -1,3 +1,5 @@
1
+ import { Math as CesiumMath } from '@vcmap/cesium';
2
+
1
3
  /**
2
4
  * helper function to wait for a timeout use: await timeout(1);
3
5
  * @param {number} ms
@@ -9,3 +11,14 @@ export function timeout(ms) {
9
11
  setTimeout(resolve, ms);
10
12
  });
11
13
  }
14
+
15
+ /**
16
+ * @param {Array<number>} numbers
17
+ * @param {Array<number>} expectedNumbers
18
+ * @param {number} [epsilon=CesiumMath.EPSILON8]
19
+ */
20
+ export function arrayCloseTo(numbers, expectedNumbers, epsilon = CesiumMath.EPSILON8) {
21
+ numbers.forEach((c, index) => {
22
+ expect(c).to.be.closeTo(expectedNumbers[index], epsilon, `Array at index ${index}`);
23
+ });
24
+ }
@@ -1,50 +0,0 @@
1
- import { getCenter } from 'ol/extent.js';
2
- import Projection from '../util/projection.js';
3
- import Extent3D from '../util/featureconverter/extent3D.js';
4
-
5
- /**
6
- * @param {VectorClickedObject} feature
7
- * @param {import("@vcmap/core").Layer} layer
8
- * @returns {?GenericFeature}
9
- */
10
- // eslint-disable-next-line import/prefer-default-export
11
- export function getGenericFeatureFromProvidedFeature(feature, layer) {
12
- const attributes = feature.getProperties();
13
- delete attributes[feature.getGeometryName()];
14
-
15
- let { clickedPosition } = feature;
16
- const geometry = feature.getGeometry();
17
- const isModel = feature.get('olcs_modelUrl');
18
- if (
19
- geometry &&
20
- (
21
- (geometry.getType() === 'Point' && !isModel) ||
22
- (clickedPosition && !clickedPosition.exactPosition) ||
23
- (!clickedPosition && geometry)
24
- )
25
- ) {
26
- const center = getCenter(geometry.getExtent());
27
- if (center) {
28
- Projection.mercatorToWgs84(center, true);
29
- clickedPosition = { longitude: center[0], latitude: center[1] };
30
- }
31
- }
32
-
33
- let heightOffset = clickedPosition.height;
34
- if (!isModel) {
35
- const extent = Extent3D.fromGeometry(geometry);
36
- heightOffset = Number.isFinite(extent.maxZ) ? extent.maxZ : 0;
37
- }
38
- const relativeToGround = !isModel && feature.get('olcs_altitudeMode') === 'relativeToGround';
39
-
40
- delete attributes.clickedPosition;
41
- return {
42
- layerName: layer.name,
43
- layerClass: layer.className,
44
- attributes,
45
- longitude: clickedPosition.longitude,
46
- latitude: clickedPosition.latitude,
47
- height: heightOffset,
48
- relativeToGround,
49
- };
50
- }
@@ -1,233 +0,0 @@
1
- import {
2
- Cartesian3,
3
- Matrix4,
4
- Plane,
5
- ClippingPlane,
6
- ClippingPlaneCollection,
7
- SplitDirection,
8
- } from '@vcmap/cesium';
9
-
10
- import { check } from '@vcsuite/check';
11
- import CesiumMap from '../map/cesiumMap.js';
12
- import ClippingObject from './clipping/clippingObject.js';
13
- import OpenlayersMap from '../map/openlayersMap.js';
14
-
15
- /**
16
- * @class
17
- * @api
18
- */
19
- class SplitScreen {
20
- /**
21
- * @param {import("@vcmap/core").ClippingObjectManager} clippingObjectManager
22
- */
23
- constructor(clippingObjectManager) {
24
- /**
25
- * @type {number}
26
- * @private
27
- */
28
- this._position = 0.5;
29
- /**
30
- * @type {import("@vcmap/cesium").Scene|null}
31
- */
32
- this.scene = null;
33
- /**
34
- * @type {import("ol/Map").default|null}
35
- */
36
- this.olMap = null;
37
- /**
38
- * @type {boolean}
39
- * @api
40
- */
41
- this.initialized = false;
42
- /**
43
- * @type {ClippingObject}
44
- */
45
- this.leftScreenClippingObject = new ClippingObject();
46
- /**
47
- * @type {ClippingObject}
48
- */
49
- this.rightScreenClippingObject = new ClippingObject();
50
- /**
51
- * @type {Function|null}
52
- * @private
53
- */
54
- this._cameraListener = null;
55
- /**
56
- * @type {number|null}
57
- */
58
- this.originalCameraPercentageChanged = null;
59
- /**
60
- * @type {Array<Function>}
61
- * @private
62
- */
63
- this._targetsChangedListeners = [];
64
-
65
- this._targetsChangedListeners = [
66
- this.rightScreenClippingObject.targetsUpdated.addEventListener(() => { this._targetsChanged(); }),
67
- this.leftScreenClippingObject.targetsUpdated.addEventListener(() => { this._targetsChanged(); }),
68
- ];
69
-
70
- /**
71
- * @type {import("@vcmap/core").ClippingObjectManager}
72
- * @private
73
- */
74
- this._clippingObjectManager = clippingObjectManager;
75
- this._clippingObjectManager.addClippingObject(this.rightScreenClippingObject);
76
- this._clippingObjectManager.addClippingObject(this.leftScreenClippingObject);
77
- }
78
-
79
- /**
80
- * @type {number}
81
- * @api
82
- */
83
- get position() { return this._position; }
84
-
85
- /**
86
- * @param {number} position
87
- */
88
- set position(position) {
89
- check(position, Number);
90
- if (position < 0 || position > 1) {
91
- throw new Error('Position must be between 0 and 1');
92
- }
93
-
94
- if (Math.abs(this._position - position) > 0.0001) {
95
- this._updatePosition(position);
96
- }
97
- }
98
-
99
- _targetsChanged() {
100
- if (this.scene) {
101
- const numTargets = this.rightScreenClippingObject.targets.size + this.leftScreenClippingObject.targets.size;
102
- const { camera } = this.scene;
103
-
104
- if (this._cameraListener && numTargets === 0) {
105
- this._cameraListener();
106
- this._cameraListener = null;
107
- camera.percentageChanged = this.originalCameraPercentageChanged;
108
- } else if (!this._cameraListener && numTargets > 0) {
109
- this.originalCameraPercentageChanged = camera.percentageChanged;
110
- camera.percentageChanged = 0;
111
- this._cameraListener = camera.changed.addEventListener(this._updateClippingPlanes.bind(this));
112
- this._updateClippingPlanes();
113
- }
114
- }
115
- }
116
-
117
- /**
118
- * @param {number} position
119
- * @private
120
- */
121
- _updatePosition(position) {
122
- this._position = position;
123
- if (this.scene) {
124
- this.scene.splitPosition = position;
125
- this._updateClippingPlanes();
126
- } else if (this.olMap) {
127
- this.olMap.render();
128
- }
129
- }
130
-
131
- /**
132
- * @param {import("@vcmap/core").VcsMap} map
133
- */
134
- mapActivated(map) {
135
- if (map instanceof CesiumMap) {
136
- this.scene = map.getScene();
137
- this.olMap = null;
138
- this._targetsChanged();
139
- } else if (map instanceof OpenlayersMap) {
140
- this.scene = null;
141
- this.olMap = map.olMap;
142
- }
143
- this._updatePosition(this.position);
144
- }
145
-
146
- /**
147
- * calculate a clipping plane from the current swipe position for the given Cesium3DTileset
148
- * @returns {import("@vcmap/cesium").ClippingPlane}
149
- * @private
150
- */
151
- _calcClippingPlane() {
152
- const { camera } = this.scene;
153
- const { fov, near } = /** @type {import("@vcmap/cesium").PerspectiveFrustum} */ (camera.frustum);
154
- const screenWidth = this.scene.canvas.width || 1;
155
- const screenHeight = this.scene.canvas.height || 1;
156
- let pixelSize;
157
- if (screenHeight > screenWidth) {
158
- pixelSize = (near * Math.tan(0.5 * fov) * 2.0) / screenHeight;
159
- } else {
160
- pixelSize = (near * Math.tan(0.5 * fov) * 2.0) / screenWidth;
161
- }
162
-
163
- // extract 3 points lying on swipe plane
164
- const screenX = (screenWidth * this.position) - (screenWidth / 2);
165
- const screenY = screenHeight / 2;
166
- const p1 = new Cartesian3(pixelSize * screenX, pixelSize * screenY, -1 * near);
167
- const p2 = new Cartesian3(pixelSize * screenX, -1 * pixelSize * screenY, -1 * near);
168
- Matrix4.multiplyByPoint(camera.inverseViewMatrix, p1, p1);
169
- Matrix4.multiplyByPoint(camera.inverseViewMatrix, p2, p2);
170
- const p3WC = camera.positionWC;
171
-
172
- Cartesian3.subtract(p3WC, p1, p1);
173
- Cartesian3.subtract(p3WC, p2, p2);
174
- const normal = Cartesian3.cross(p1, p2, new Cartesian3());
175
- Cartesian3.normalize(normal, normal);
176
- const planeInFixedFrame = Plane.fromPointNormal(p3WC, normal);
177
-
178
- return ClippingPlane.fromPlane(planeInFixedFrame);
179
- }
180
-
181
- /**
182
- * update the clipping planes for all Cesium3DTilesets loaded in the vcMap
183
- * @private
184
- */
185
- _updateClippingPlanes() {
186
- const plane = this._calcClippingPlane();
187
- this.leftScreenClippingObject.clippingPlaneCollection = new ClippingPlaneCollection({ planes: [plane] });
188
- const revClippingPlane = ClippingPlane.clone(plane);
189
- revClippingPlane.normal = Cartesian3.negate(revClippingPlane.normal, revClippingPlane.normal);
190
- revClippingPlane.distance *= -1;
191
- this.rightScreenClippingObject.clippingPlaneCollection =
192
- new ClippingPlaneCollection({ planes: [revClippingPlane] });
193
- }
194
-
195
- /**
196
- * Gets the clipping object for a split direction
197
- * @param {import("@vcmap/cesium").SplitDirection} splitDirection
198
- * @returns {ClippingObject|null}
199
- * @api
200
- */
201
- getClippingObjectForDirection(splitDirection) {
202
- check(splitDirection, [
203
- SplitDirection.LEFT,
204
- SplitDirection.RIGHT,
205
- SplitDirection.NONE,
206
- ]);
207
-
208
- if (splitDirection === SplitDirection.LEFT) {
209
- return this.leftScreenClippingObject;
210
- }
211
- if (splitDirection === SplitDirection.RIGHT) {
212
- return this.rightScreenClippingObject;
213
- }
214
-
215
- return null;
216
- }
217
-
218
- destroy() {
219
- if (this._clippingObjectManager) {
220
- this._clippingObjectManager.removeClippingObject(this.rightScreenClippingObject);
221
- this._clippingObjectManager.removeClippingObject(this.leftScreenClippingObject);
222
- }
223
- this._targetsChangedListeners.forEach((cb) => { cb(); });
224
- this._targetsChangedListeners = [];
225
- this._clippingObjectManager = null;
226
- if (this._cameraListener) {
227
- this._cameraListener();
228
- this._cameraListener = null;
229
- }
230
- }
231
- }
232
-
233
- export default SplitScreen;