@vcmap/core 6.0.0-rc.4 → 6.0.0-rc.6

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 (209) hide show
  1. package/dist/cesium.d.ts +11 -0
  2. package/dist/index.d.ts +23 -16
  3. package/dist/index.js +21 -14
  4. package/dist/index.js.map +1 -1
  5. package/dist/ol.d.ts +15 -2
  6. package/dist/src/layer/cesium/clusterContext.d.ts +8 -14
  7. package/dist/src/layer/cesium/clusterContext.js +62 -41
  8. package/dist/src/layer/cesium/clusterContext.js.map +1 -1
  9. package/dist/src/layer/cesium/vectorCesiumImpl.d.ts +2 -3
  10. package/dist/src/layer/cesium/vectorCesiumImpl.js +16 -10
  11. package/dist/src/layer/cesium/vectorCesiumImpl.js.map +1 -1
  12. package/dist/src/layer/cesium/vectorContext.d.ts +10 -53
  13. package/dist/src/layer/cesium/vectorContext.js +88 -172
  14. package/dist/src/layer/cesium/vectorContext.js.map +1 -1
  15. package/dist/src/layer/geojsonHelpers.d.ts +1 -1
  16. package/dist/src/layer/geojsonHelpers.js +5 -10
  17. package/dist/src/layer/geojsonHelpers.js.map +1 -1
  18. package/dist/src/layer/oblique/obliqueHelpers.js +6 -6
  19. package/dist/src/layer/oblique/obliqueHelpers.js.map +1 -1
  20. package/dist/src/layer/vectorLayer.d.ts +0 -37
  21. package/dist/src/layer/vectorLayer.js.map +1 -1
  22. package/dist/src/layer/vectorProperties.d.ts +8 -3
  23. package/dist/src/layer/vectorProperties.js +30 -5
  24. package/dist/src/layer/vectorProperties.js.map +1 -1
  25. package/dist/src/map/baseOLMap.js +1 -1
  26. package/dist/src/map/baseOLMap.js.map +1 -1
  27. package/dist/src/map/obliqueMap.d.ts +3 -0
  28. package/dist/src/map/obliqueMap.js +27 -6
  29. package/dist/src/map/obliqueMap.js.map +1 -1
  30. package/dist/src/map/vcsMap.d.ts +8 -0
  31. package/dist/src/map/vcsMap.js +11 -0
  32. package/dist/src/map/vcsMap.js.map +1 -1
  33. package/dist/src/oblique/helpers.js +5 -5
  34. package/dist/src/oblique/helpers.js.map +1 -1
  35. package/dist/src/oblique/obliqueDataSet.js +4 -4
  36. package/dist/src/oblique/obliqueDataSet.js.map +1 -1
  37. package/dist/src/ol/geom/geometryCollection.js +19 -2
  38. package/dist/src/ol/geom/geometryCollection.js.map +1 -1
  39. package/dist/src/style/arcStyle.js +1 -0
  40. package/dist/src/style/arcStyle.js.map +1 -1
  41. package/dist/src/util/editor/createFeatureSession.d.ts +5 -1
  42. package/dist/src/util/editor/createFeatureSession.js +48 -4
  43. package/dist/src/util/editor/createFeatureSession.js.map +1 -1
  44. package/dist/src/util/editor/editFeaturesSession.d.ts +10 -4
  45. package/dist/src/util/editor/editFeaturesSession.js +74 -37
  46. package/dist/src/util/editor/editFeaturesSession.js.map +1 -1
  47. package/dist/src/util/editor/editGeometrySession.d.ts +5 -1
  48. package/dist/src/util/editor/editGeometrySession.js +77 -55
  49. package/dist/src/util/editor/editGeometrySession.js.map +1 -1
  50. package/dist/src/util/editor/editorHelpers.d.ts +12 -6
  51. package/dist/src/util/editor/editorHelpers.js +47 -20
  52. package/dist/src/util/editor/editorHelpers.js.map +1 -1
  53. package/dist/src/util/editor/editorSessionHelpers.d.ts +5 -0
  54. package/dist/src/util/editor/editorSessionHelpers.js +1 -0
  55. package/dist/src/util/editor/editorSessionHelpers.js.map +1 -1
  56. package/dist/src/util/editor/editorSymbols.d.ts +1 -1
  57. package/dist/src/util/editor/editorSymbols.js +1 -1
  58. package/dist/src/util/editor/editorSymbols.js.map +1 -1
  59. package/dist/src/util/editor/interactions/createBBoxInteraction.d.ts +1 -0
  60. package/dist/src/util/editor/interactions/createBBoxInteraction.js +20 -16
  61. package/dist/src/util/editor/interactions/createBBoxInteraction.js.map +1 -1
  62. package/dist/src/util/editor/interactions/createCircleInteraction.js +1 -1
  63. package/dist/src/util/editor/interactions/createCircleInteraction.js.map +1 -1
  64. package/dist/src/util/editor/interactions/createLineStringInteraction.js +3 -3
  65. package/dist/src/util/editor/interactions/createLineStringInteraction.js.map +1 -1
  66. package/dist/src/util/editor/interactions/createPointInteraction.js +1 -1
  67. package/dist/src/util/editor/interactions/createPointInteraction.js.map +1 -1
  68. package/dist/src/util/editor/interactions/createPolygonInteraction.d.ts +4 -0
  69. package/dist/src/util/editor/interactions/createPolygonInteraction.js +9 -3
  70. package/dist/src/util/editor/interactions/createPolygonInteraction.js.map +1 -1
  71. package/dist/src/util/editor/interactions/creationSnapping.d.ts +26 -0
  72. package/dist/src/util/editor/interactions/creationSnapping.js +139 -0
  73. package/dist/src/util/editor/interactions/creationSnapping.js.map +1 -0
  74. package/dist/src/util/editor/interactions/editGeometryMouseOverInteraction.js +3 -2
  75. package/dist/src/util/editor/interactions/editGeometryMouseOverInteraction.js.map +1 -1
  76. package/dist/src/util/editor/interactions/insertVertexInteraction.d.ts +3 -1
  77. package/dist/src/util/editor/interactions/insertVertexInteraction.js +14 -6
  78. package/dist/src/util/editor/interactions/insertVertexInteraction.js.map +1 -1
  79. package/dist/src/util/editor/interactions/layerSnapping.d.ts +19 -0
  80. package/dist/src/util/editor/interactions/layerSnapping.js +87 -0
  81. package/dist/src/util/editor/interactions/layerSnapping.js.map +1 -0
  82. package/dist/src/util/editor/interactions/translateVertexInteraction.js +2 -2
  83. package/dist/src/util/editor/interactions/translateVertexInteraction.js.map +1 -1
  84. package/dist/src/util/editor/interactions/translationSnapping.d.ts +25 -0
  85. package/dist/src/util/editor/interactions/translationSnapping.js +179 -0
  86. package/dist/src/util/editor/interactions/translationSnapping.js.map +1 -0
  87. package/dist/src/util/editor/snappingHelpers.d.ts +44 -0
  88. package/dist/src/util/editor/snappingHelpers.js +329 -0
  89. package/dist/src/util/editor/snappingHelpers.js.map +1 -0
  90. package/dist/src/util/editor/transformation/create2DHandlers.js +26 -26
  91. package/dist/src/util/editor/transformation/create2DHandlers.js.map +1 -1
  92. package/dist/src/util/editor/transformation/create3DHandlers.js +65 -14
  93. package/dist/src/util/editor/transformation/create3DHandlers.js.map +1 -1
  94. package/dist/src/util/editor/transformation/scaleInteraction.js +27 -5
  95. package/dist/src/util/editor/transformation/scaleInteraction.js.map +1 -1
  96. package/dist/src/util/editor/transformation/transformationHandler.js +56 -38
  97. package/dist/src/util/editor/transformation/transformationHandler.js.map +1 -1
  98. package/dist/src/util/editor/transformation/transformationTypes.d.ts +2 -0
  99. package/dist/src/util/editor/transformation/transformationTypes.js +4 -0
  100. package/dist/src/util/editor/transformation/transformationTypes.js.map +1 -1
  101. package/dist/src/util/featureconverter/arcToCesium.d.ts +5 -19
  102. package/dist/src/util/featureconverter/arcToCesium.js +15 -42
  103. package/dist/src/util/featureconverter/arcToCesium.js.map +1 -1
  104. package/dist/src/util/featureconverter/circleToCesium.d.ts +2 -27
  105. package/dist/src/util/featureconverter/circleToCesium.js +84 -63
  106. package/dist/src/util/featureconverter/circleToCesium.js.map +1 -1
  107. package/dist/src/util/featureconverter/clampedPrimitive.d.ts +2 -0
  108. package/dist/src/util/featureconverter/clampedPrimitive.js +29 -0
  109. package/dist/src/util/featureconverter/clampedPrimitive.js.map +1 -0
  110. package/dist/src/util/featureconverter/convert.d.ts +26 -7
  111. package/dist/src/util/featureconverter/convert.js +221 -44
  112. package/dist/src/util/featureconverter/convert.js.map +1 -1
  113. package/dist/src/util/featureconverter/extent3D.d.ts +4 -3
  114. package/dist/src/util/featureconverter/extent3D.js +4 -3
  115. package/dist/src/util/featureconverter/extent3D.js.map +1 -1
  116. package/dist/src/util/featureconverter/lineStringToCesium.d.ts +12 -27
  117. package/dist/src/util/featureconverter/lineStringToCesium.js +85 -107
  118. package/dist/src/util/featureconverter/lineStringToCesium.js.map +1 -1
  119. package/dist/src/util/featureconverter/pointHelpers.d.ts +8 -11
  120. package/dist/src/util/featureconverter/pointHelpers.js +134 -120
  121. package/dist/src/util/featureconverter/pointHelpers.js.map +1 -1
  122. package/dist/src/util/featureconverter/pointToCesium.d.ts +14 -17
  123. package/dist/src/util/featureconverter/pointToCesium.js +47 -96
  124. package/dist/src/util/featureconverter/pointToCesium.js.map +1 -1
  125. package/dist/src/util/featureconverter/polygonToCesium.d.ts +2 -26
  126. package/dist/src/util/featureconverter/polygonToCesium.js +62 -72
  127. package/dist/src/util/featureconverter/polygonToCesium.js.map +1 -1
  128. package/dist/src/util/featureconverter/storeyHelpers.d.ts +17 -0
  129. package/dist/src/util/featureconverter/storeyHelpers.js +78 -0
  130. package/dist/src/util/featureconverter/storeyHelpers.js.map +1 -0
  131. package/dist/src/util/featureconverter/vectorGeometryFactory.d.ts +54 -0
  132. package/dist/src/util/featureconverter/vectorGeometryFactory.js +278 -0
  133. package/dist/src/util/featureconverter/vectorGeometryFactory.js.map +1 -0
  134. package/dist/src/util/featureconverter/vectorHeightInfo.d.ts +86 -0
  135. package/dist/src/util/featureconverter/vectorHeightInfo.js +242 -0
  136. package/dist/src/util/featureconverter/vectorHeightInfo.js.map +1 -0
  137. package/dist/src/util/geometryHelpers.d.ts +22 -1
  138. package/dist/src/util/geometryHelpers.js +65 -2
  139. package/dist/src/util/geometryHelpers.js.map +1 -1
  140. package/dist/src/util/mapCollection.js +8 -0
  141. package/dist/src/util/mapCollection.js.map +1 -1
  142. package/dist/src/util/math.d.ts +6 -2
  143. package/dist/src/util/math.js +34 -12
  144. package/dist/src/util/math.js.map +1 -1
  145. package/dist/tests/unit/helpers/cesiumHelpers.js +3 -1
  146. package/dist/tests/unit/helpers/cesiumHelpers.js.map +1 -1
  147. package/dist/tests/unit/helpers/helpers.d.ts +2 -9
  148. package/dist/tests/unit/helpers/helpers.js +2 -8
  149. package/dist/tests/unit/helpers/helpers.js.map +1 -1
  150. package/index.ts +74 -35
  151. package/package.json +3 -3
  152. package/src/cesium/cesium.d.ts +11 -0
  153. package/src/layer/cesium/clusterContext.ts +82 -91
  154. package/src/layer/cesium/vectorCesiumImpl.ts +17 -11
  155. package/src/layer/cesium/vectorContext.ts +120 -348
  156. package/src/layer/geojsonHelpers.ts +9 -12
  157. package/src/layer/oblique/obliqueHelpers.ts +6 -6
  158. package/src/layer/vectorLayer.ts +0 -71
  159. package/src/layer/vectorProperties.ts +46 -9
  160. package/src/map/baseOLMap.ts +1 -1
  161. package/src/map/obliqueMap.ts +46 -6
  162. package/src/map/vcsMap.ts +20 -2
  163. package/src/oblique/helpers.ts +11 -5
  164. package/src/oblique/obliqueDataSet.ts +4 -4
  165. package/src/ol/geom/geometryCollection.js +21 -2
  166. package/src/ol/ol.d.ts +15 -2
  167. package/src/style/arcStyle.ts +1 -0
  168. package/src/util/editor/createFeatureSession.ts +64 -6
  169. package/src/util/editor/editFeaturesSession.ts +105 -39
  170. package/src/util/editor/editGeometrySession.ts +118 -75
  171. package/src/util/editor/editorHelpers.ts +78 -30
  172. package/src/util/editor/editorSessionHelpers.ts +7 -0
  173. package/src/util/editor/editorSymbols.ts +1 -1
  174. package/src/util/editor/interactions/createBBoxInteraction.ts +25 -16
  175. package/src/util/editor/interactions/createCircleInteraction.ts +1 -1
  176. package/src/util/editor/interactions/createLineStringInteraction.ts +9 -3
  177. package/src/util/editor/interactions/createPointInteraction.ts +1 -1
  178. package/src/util/editor/interactions/createPolygonInteraction.ts +16 -3
  179. package/src/util/editor/interactions/creationSnapping.ts +226 -0
  180. package/src/util/editor/interactions/editGeometryMouseOverInteraction.ts +3 -2
  181. package/src/util/editor/interactions/insertVertexInteraction.ts +27 -7
  182. package/src/util/editor/interactions/layerSnapping.ts +136 -0
  183. package/src/util/editor/interactions/translateVertexInteraction.ts +8 -2
  184. package/src/util/editor/interactions/translationSnapping.ts +302 -0
  185. package/src/util/editor/snappingHelpers.ts +490 -0
  186. package/src/util/editor/transformation/create2DHandlers.ts +38 -26
  187. package/src/util/editor/transformation/create3DHandlers.ts +84 -22
  188. package/src/util/editor/transformation/scaleInteraction.ts +28 -5
  189. package/src/util/editor/transformation/transformationHandler.ts +72 -41
  190. package/src/util/editor/transformation/transformationTypes.ts +5 -0
  191. package/src/util/featureconverter/arcToCesium.ts +25 -95
  192. package/src/util/featureconverter/circleToCesium.ts +127 -113
  193. package/src/util/featureconverter/clampedPrimitive.ts +70 -0
  194. package/src/util/featureconverter/convert.ts +446 -114
  195. package/src/util/featureconverter/extent3D.ts +13 -6
  196. package/src/util/featureconverter/lineStringToCesium.ts +132 -179
  197. package/src/util/featureconverter/pointHelpers.ts +271 -214
  198. package/src/util/featureconverter/pointToCesium.ts +111 -175
  199. package/src/util/featureconverter/polygonToCesium.ts +98 -117
  200. package/src/util/featureconverter/storeyHelpers.ts +104 -0
  201. package/src/util/featureconverter/vectorGeometryFactory.ts +601 -0
  202. package/src/util/featureconverter/vectorHeightInfo.ts +393 -0
  203. package/src/util/geometryHelpers.ts +79 -5
  204. package/src/util/mapCollection.ts +8 -0
  205. package/src/util/math.ts +59 -12
  206. package/dist/src/util/featureconverter/featureconverterHelper.d.ts +0 -35
  207. package/dist/src/util/featureconverter/featureconverterHelper.js +0 -404
  208. package/dist/src/util/featureconverter/featureconverterHelper.js.map +0 -1
  209. package/src/util/featureconverter/featureconverterHelper.ts +0 -672
@@ -2,12 +2,12 @@ import { getLogger } from '@vcsuite/logger';
2
2
  import { unByKey } from 'ol/Observable.js';
3
3
  import type { Feature } from 'ol/index.js';
4
4
  import type {
5
- LineString,
6
5
  Circle,
7
- Polygon,
8
- Point,
9
- LinearRing,
10
6
  Geometry,
7
+ LinearRing,
8
+ LineString,
9
+ Point,
10
+ Polygon,
11
11
  } from 'ol/geom.js';
12
12
  import { EventsKey } from 'ol/events.js';
13
13
  import {
@@ -26,8 +26,9 @@ import RemoveVertexInteraction from './interactions/removeVertexInteraction.js';
26
26
  import {
27
27
  createVertex,
28
28
  geometryChangeKeys,
29
+ getCoordinatesAndLayoutFromVertices,
29
30
  getOlcsPropsFromFeature,
30
- vectorPropertyChangeKeys,
31
+ syncScratchLayerVectorProperties,
31
32
  } from './editorHelpers.js';
32
33
  import InsertVertexInteraction from './interactions/insertVertexInteraction.js';
33
34
  import EditGeometryMouseOverInteraction from './interactions/editGeometryMouseOverInteraction.js';
@@ -37,15 +38,18 @@ import geometryIsValid from './validateGeoemetry.js';
37
38
  import MapInteractionController from './interactions/mapInteractionController.js';
38
39
  import type VectorLayer from '../../layer/vectorLayer.js';
39
40
  import type VcsApp from '../../vcsApp.js';
40
- import type {
41
- // eslint-disable-next-line import/no-named-default
42
- default as VectorProperties,
43
- PropertyChangedKey,
44
- } from '../../layer/vectorProperties.js';
41
+ // eslint-disable-next-line import/no-named-default
42
+ import type { default as VectorProperties } from '../../layer/vectorProperties.js';
43
+ import TranslationSnapping from './interactions/translationSnapping.js';
44
+ import { vertexIndexSymbol } from './editorSymbols.js';
45
+ import LayerSnapping from './interactions/layerSnapping.js';
46
+ import { EventType } from '../../interaction/interactionType.js';
47
+ import { SnapType, snapTypes } from './snappingHelpers.js';
45
48
 
46
49
  export type EditGeometrySession = EditorSession<SessionType.EDIT_GEOMETRY> & {
47
50
  setFeature(feature?: Feature): void;
48
51
  feature: Feature | null;
52
+ snapToLayers: VectorLayer[];
49
53
  };
50
54
 
51
55
  type EditGeometryInteraction = {
@@ -53,51 +57,52 @@ type EditGeometryInteraction = {
53
57
  destroy(): void;
54
58
  };
55
59
 
56
- function assignVectorProperty<
57
- K extends PropertyChangedKey,
58
- V extends VectorProperties[K],
59
- >(props: VectorProperties, key: K, value: V): void {
60
- props[key] = value;
61
- }
62
-
63
60
  type EditGeometrySessionOptions = {
64
61
  denyInsertion?: boolean;
65
62
  denyRemoval?: boolean;
63
+ initialSnapToLayers?: VectorLayer[];
64
+ snapTo?: SnapType[];
66
65
  };
67
66
 
68
- /**
69
- * Create the editing interaction for a feature with a line geometry
70
- * @param feature
71
- * @param scratchLayer
72
- * @group Editor
73
- */
74
67
  function createEditLineStringGeometryInteraction(
75
68
  feature: Feature<LineString>,
76
69
  scratchLayer: VectorLayer,
70
+ vectorProperties: VectorProperties,
77
71
  options: EditGeometrySessionOptions,
72
+ snapTo: SnapType[],
78
73
  ): EditGeometryInteraction {
79
74
  const geometry =
80
75
  feature[obliqueGeometry] ?? (feature.getGeometry() as LineString);
81
76
  const olcsProps = getOlcsPropsFromFeature(feature);
82
77
  const vertices = geometry
83
78
  .getCoordinates()
84
- .map((c) => createVertex(c, olcsProps));
79
+ .map((c, i) => createVertex(c, olcsProps, i));
85
80
  scratchLayer.addFeatures(vertices);
86
81
  const resetGeometry = (): void => {
87
- geometry.setCoordinates(
88
- vertices.map((f) => f.getGeometry()!.getCoordinates()),
89
- );
82
+ const { coordinates, layout } =
83
+ getCoordinatesAndLayoutFromVertices(vertices);
84
+ geometry.setCoordinates(coordinates, layout);
90
85
  };
91
86
  const translateVertex = new TranslateVertexInteraction(feature);
92
87
  translateVertex.vertexChanged.addEventListener(resetGeometry);
93
88
 
94
- const interactions: AbstractInteraction[] = [translateVertex];
89
+ const interactions: AbstractInteraction[] = [
90
+ new TranslationSnapping(scratchLayer, geometry, snapTo),
91
+ translateVertex,
92
+ ];
95
93
 
96
94
  if (!options.denyInsertion) {
97
- const insertVertex = new InsertVertexInteraction(feature, geometry);
95
+ const insertVertex = new InsertVertexInteraction(
96
+ feature,
97
+ geometry,
98
+ vectorProperties,
99
+ );
98
100
  insertVertex.vertexInserted.addEventListener(({ vertex, index }) => {
99
101
  scratchLayer.addFeatures([vertex]);
100
102
  vertices.splice(index, 0, vertex);
103
+ vertices.forEach((v, i) => {
104
+ v[vertexIndexSymbol] = i;
105
+ });
101
106
  resetGeometry();
102
107
  });
103
108
  interactions.push(insertVertex);
@@ -138,7 +143,7 @@ function createEditCircleGeometryInteraction(
138
143
  const olcsProps = getOlcsPropsFromFeature(feature);
139
144
  const vertices = geometry
140
145
  .getCoordinates()
141
- .map((c) => createVertex(c, olcsProps));
146
+ .map((c, i) => createVertex(c, olcsProps, i));
142
147
  scratchLayer.addFeatures(vertices);
143
148
 
144
149
  const translateVertex = new TranslateVertexInteraction(feature);
@@ -151,8 +156,13 @@ function createEditCircleGeometryInteraction(
151
156
  const newRadius = cartesian2DDistance(coords[0], coords[1]);
152
157
  geometry.setRadius(newRadius);
153
158
  } else {
154
- geometry.setCenter(vertex.getGeometry()!.getCoordinates());
155
- vertices[1].getGeometry()!.setCoordinates(geometry.getCoordinates()[1]);
159
+ const { coordinates, layout } = getCoordinatesAndLayoutFromVertices([
160
+ vertex,
161
+ ]);
162
+ geometry.setCenterAndRadius(coordinates[0], geometry.getRadius(), layout);
163
+ vertices[1]
164
+ .getGeometry()!
165
+ .setCoordinates(geometry.getCoordinates()[1], layout);
156
166
  }
157
167
  suspend = false;
158
168
  });
@@ -188,16 +198,16 @@ function createEditBBoxGeometryInteraction(
188
198
  const olcsProps = getOlcsPropsFromFeature(feature);
189
199
  const vertices = geometry
190
200
  .getCoordinates()[0]
191
- .map((c) => createVertex(c, olcsProps));
201
+ .map((c, i) => createVertex(c, olcsProps, i));
192
202
 
193
203
  scratchLayer.addFeatures(vertices);
194
204
  let suspend = false;
195
205
  const translateVertex = new TranslateVertexInteraction(feature);
196
206
  translateVertex.vertexChanged.addEventListener((vertex) => {
197
- const vertexIndex = vertices.indexOf(vertex);
198
- const originIndex = modulo(vertexIndex + 2, 4);
199
- const rightOfIndex = modulo(vertexIndex + 1, 4);
200
- const leftOfIndex = modulo(vertexIndex - 1, 4);
207
+ const index = vertices.indexOf(vertex);
208
+ const originIndex = modulo(index + 2, 4);
209
+ const rightOfIndex = modulo(index + 1, 4);
210
+ const leftOfIndex = modulo(index - 1, 4);
201
211
 
202
212
  const originCoords = vertices[originIndex].getGeometry()!.getCoordinates();
203
213
  const vertexCoords = vertex.getGeometry()!.getCoordinates();
@@ -231,16 +241,17 @@ function createEditBBoxGeometryInteraction(
231
241
  updateOtherVertex(leftOfIndex);
232
242
 
233
243
  suspend = true;
234
- geometry.setCoordinates([
235
- vertices.map((f) => f.getGeometry()!.getCoordinates()),
236
- ]);
244
+ const { coordinates, layout } =
245
+ getCoordinatesAndLayoutFromVertices(vertices);
246
+ geometry.setCoordinates([coordinates], layout);
237
247
  suspend = false;
238
248
  });
239
249
 
240
250
  const geometryListener = geometry.on('change', () => {
241
251
  if (!suspend) {
252
+ const layout = geometry.getLayout();
242
253
  geometry.getCoordinates()[0].forEach((c, index) => {
243
- vertices[index].getGeometry()!.setCoordinates(c);
254
+ vertices[index].getGeometry()!.setCoordinates(c, layout);
244
255
  });
245
256
  }
246
257
  });
@@ -261,7 +272,9 @@ function createEditBBoxGeometryInteraction(
261
272
  function createEditSimplePolygonInteraction(
262
273
  feature: Feature<Polygon>,
263
274
  scratchLayer: VectorLayer,
275
+ vectorProperties: VectorProperties,
264
276
  options: EditGeometrySessionOptions,
277
+ snapTo: SnapType[],
265
278
  ): EditGeometryInteraction {
266
279
  const geometry =
267
280
  feature[obliqueGeometry] ?? (feature.getGeometry() as Polygon);
@@ -270,26 +283,35 @@ function createEditSimplePolygonInteraction(
270
283
 
271
284
  const vertices = linearRing
272
285
  .getCoordinates()
273
- .map((c) => createVertex(c, olcsProps));
286
+ .map((c, i) => createVertex(c, olcsProps, i));
274
287
  scratchLayer.addFeatures(vertices);
275
288
  const resetGeometry = (): void => {
276
- const coordinates = vertices.map((f) => f.getGeometry()!.getCoordinates());
277
- linearRing.setCoordinates(coordinates); // update linear ring for proper vertex insertion
278
- geometry.setCoordinates([
279
- vertices.map((f) => f.getGeometry()!.getCoordinates()),
280
- ]); // update actual geometry, since linear ring is a clone and not a ref
289
+ const { coordinates, layout } =
290
+ getCoordinatesAndLayoutFromVertices(vertices);
291
+ linearRing.setCoordinates(coordinates, layout); // update linear ring for proper vertex insertion
292
+ geometry.setCoordinates([coordinates], layout); // update actual geometry, since linear ring is a clone and not a ref
281
293
  };
282
294
 
283
295
  const translateVertex = new TranslateVertexInteraction(feature);
284
296
  translateVertex.vertexChanged.addEventListener(resetGeometry);
285
297
 
286
- const interactions: AbstractInteraction[] = [translateVertex];
298
+ const interactions: AbstractInteraction[] = [
299
+ new TranslationSnapping(scratchLayer, geometry, snapTo),
300
+ translateVertex,
301
+ ];
287
302
 
288
303
  if (!options.denyInsertion) {
289
- const insertVertex = new InsertVertexInteraction(feature, linearRing);
304
+ const insertVertex = new InsertVertexInteraction(
305
+ feature,
306
+ linearRing,
307
+ vectorProperties,
308
+ );
290
309
  insertVertex.vertexInserted.addEventListener(({ vertex, index }) => {
291
310
  scratchLayer.addFeatures([vertex]);
292
311
  vertices.splice(index, 0, vertex);
312
+ vertices.forEach((v, i) => {
313
+ v[vertexIndexSymbol] = i;
314
+ });
293
315
  resetGeometry();
294
316
  });
295
317
  interactions.push(insertVertex);
@@ -329,7 +351,7 @@ function createEditPointInteraction(
329
351
  const geometry = feature[obliqueGeometry] ?? (feature.getGeometry() as Point);
330
352
  const olcsProps = getOlcsPropsFromFeature(feature);
331
353
 
332
- const vertex = createVertex(geometry.getCoordinates(), olcsProps);
354
+ const vertex = createVertex(geometry.getCoordinates(), olcsProps, 0);
333
355
  const featureIdArray = [feature.getId() as string];
334
356
  layer.featureVisibility.hideObjects(featureIdArray);
335
357
  vertex[createSync] = true;
@@ -338,13 +360,18 @@ function createEditPointInteraction(
338
360
  let suspend = false;
339
361
  translateVertex.vertexChanged.addEventListener(() => {
340
362
  suspend = true;
341
- geometry.setCoordinates(vertex.getGeometry()!.getCoordinates());
363
+ const { coordinates, layout } = getCoordinatesAndLayoutFromVertices([
364
+ vertex,
365
+ ]);
366
+ geometry.setCoordinates(coordinates[0], layout);
342
367
  suspend = false;
343
368
  });
344
369
 
345
370
  const geometryListener = geometry.on('change', () => {
346
371
  if (!suspend) {
347
- vertex.getGeometry()!.setCoordinates(geometry.getCoordinates());
372
+ vertex
373
+ .getGeometry()!
374
+ .setCoordinates(geometry.getCoordinates(), geometry.getLayout());
348
375
  }
349
376
  });
350
377
 
@@ -365,7 +392,7 @@ function createEditPointInteraction(
365
392
  * Creates the edit geometry session.
366
393
  * @param app
367
394
  * @param layer
368
- * @param [interactionId] id for registering mutliple exclusive interaction. Needed to run a selection session at the same time as a edit features session.
395
+ * @param [interactionId] id for registering multiple exclusive interaction. Needed to run a selection session at the same time as a edit features session.
369
396
  * @param [editVertexOptions={}]
370
397
  */
371
398
  function startEditGeometrySession(
@@ -396,38 +423,28 @@ function startEditGeometrySession(
396
423
  * The feature that is set for the edit session.
397
424
  */
398
425
  let currentFeature: Feature | null = null;
426
+ let layerSnappingInteraction: LayerSnapping | null = null;
427
+ let snapToLayers: VectorLayer[] =
428
+ editVertexOptions?.initialSnapToLayers?.slice() ?? [layer];
429
+
430
+ const snapTo = editVertexOptions?.snapTo ?? [...snapTypes];
399
431
 
400
432
  const pickingBehavior = createPickingBehavior(app);
401
433
  const altitudeModeChanged = (): void => {
402
434
  const altitudeMode = currentFeature
403
435
  ? layer.vectorProperties.getAltitudeMode(currentFeature)
404
436
  : layer.vectorProperties.altitudeMode;
437
+
438
+ scratchLayer.vectorProperties.altitudeMode = altitudeMode;
405
439
  pickingBehavior.setForAltitudeMode(altitudeMode);
406
440
  };
407
441
  altitudeModeChanged();
408
- vectorPropertyChangeKeys.forEach((key) => {
409
- assignVectorProperty(
410
- scratchLayer.vectorProperties,
411
- key,
412
- layer.vectorProperties[key],
413
- );
414
- });
415
442
 
416
- const vectorPropertiesChangedListener =
417
- layer.vectorProperties.propertyChanged.addEventListener((props) => {
418
- vectorPropertyChangeKeys.forEach((key) => {
419
- if (props.includes(key)) {
420
- assignVectorProperty(
421
- scratchLayer.vectorProperties,
422
- key,
423
- layer.vectorProperties[key],
424
- );
425
- if (key === 'altitudeMode') {
426
- altitudeModeChanged();
427
- }
428
- }
429
- });
430
- });
443
+ const vectorPropertiesChangedListener = syncScratchLayerVectorProperties(
444
+ scratchLayer,
445
+ layer,
446
+ altitudeModeChanged,
447
+ );
431
448
 
432
449
  const destroyCurrentInteractionSet = (): void => {
433
450
  if (currentInteractionSet) {
@@ -436,6 +453,7 @@ function startEditGeometrySession(
436
453
  );
437
454
  currentInteractionSet.destroy();
438
455
  currentInteractionSet = null;
456
+ layerSnappingInteraction = null; // destroyed in current interaction set
439
457
  }
440
458
 
441
459
  if (currentFeature) {
@@ -483,14 +501,18 @@ function startEditGeometrySession(
483
501
  currentInteractionSet = createEditSimplePolygonInteraction(
484
502
  feature as Feature<Polygon>,
485
503
  scratchLayer,
504
+ layer.vectorProperties,
486
505
  editVertexOptions,
506
+ snapTo,
487
507
  );
488
508
  }
489
509
  } else if (geometryType === GeometryType.LineString) {
490
510
  currentInteractionSet = createEditLineStringGeometryInteraction(
491
511
  feature as Feature<LineString>,
492
512
  scratchLayer,
513
+ layer.vectorProperties,
493
514
  editVertexOptions,
515
+ snapTo,
494
516
  );
495
517
  } else if (geometryType === GeometryType.Point) {
496
518
  currentInteractionSet = createEditPointInteraction(
@@ -506,6 +528,17 @@ function startEditGeometrySession(
506
528
  }
507
529
 
508
530
  if (currentInteractionSet) {
531
+ layerSnappingInteraction = new LayerSnapping(
532
+ snapToLayers,
533
+ scratchLayer,
534
+ (f) => f !== feature,
535
+ snapTo,
536
+ EventType.DRAGEVENTS,
537
+ );
538
+ currentInteractionSet.interactionChain.addInteraction(
539
+ layerSnappingInteraction,
540
+ 0,
541
+ );
509
542
  interactionChain.addInteraction(currentInteractionSet.interactionChain);
510
543
  altitudeModeChanged();
511
544
  } else {
@@ -529,6 +562,7 @@ function startEditGeometrySession(
529
562
 
530
563
  const stop = (): void => {
531
564
  app.layers.remove(scratchLayer);
565
+ scratchLayer.destroy();
532
566
  if (featureListener) {
533
567
  unByKey(featureListener);
534
568
  }
@@ -554,6 +588,15 @@ function startEditGeometrySession(
554
588
  get feature(): Feature | null {
555
589
  return currentFeature;
556
590
  },
591
+ get snapToLayers(): VectorLayer[] {
592
+ return snapToLayers.slice();
593
+ },
594
+ set snapToLayers(layers: VectorLayer[]) {
595
+ snapToLayers = layers.slice();
596
+ if (layerSnappingInteraction) {
597
+ layerSnappingInteraction.layers = snapToLayers;
598
+ }
599
+ },
557
600
  };
558
601
  }
559
602
 
@@ -2,6 +2,7 @@ import Point from 'ol/geom/Point.js';
2
2
  import Feature from 'ol/Feature.js';
3
3
  import type { Coordinate } from 'ol/coordinate.js';
4
4
  import type { Geometry } from 'ol/geom.js';
5
+ import { GeometryLayout } from 'ol/geom/Geometry.js';
5
6
 
6
7
  import {
7
8
  Cartesian2,
@@ -11,7 +12,6 @@ import {
11
12
  Ray,
12
13
  IntersectionTests,
13
14
  Cartographic,
14
- HeightReference,
15
15
  Cesium3DTileFeature,
16
16
  type Scene,
17
17
  type Camera,
@@ -20,17 +20,19 @@ import {
20
20
  import { mercatorToCartesian } from '../math.js';
21
21
  import { getFlatCoordinatesFromGeometry } from '../geometryHelpers.js';
22
22
  import CesiumMap from '../../map/cesiumMap.js';
23
- import { vertexSymbol } from './editorSymbols.js';
23
+ import { vertexIndexSymbol, vertexSymbol } from './editorSymbols.js';
24
24
  import {
25
25
  alreadyTransformedToImage,
26
26
  createSync,
27
27
  doNotTransform,
28
28
  } from '../../layer/vectorSymbols.js';
29
- import type VectorLayer from '../../layer/vectorLayer.js';
30
29
  import type VcsMap from '../../map/vcsMap.js';
31
- import { PropertyChangedKey } from '../../layer/vectorProperties.js';
30
+ import VectorProperties, {
31
+ PropertyChangedKey,
32
+ } from '../../layer/vectorProperties.js';
33
+ import VectorLayer from '../../layer/vectorLayer.js';
32
34
 
33
- export type Vertex = Feature<Point>;
35
+ export type Vertex = Feature<Point> & { [vertexIndexSymbol]: number };
34
36
 
35
37
  export type SelectableFeatureType = Feature | Cesium3DTileFeature;
36
38
  export interface SelectFeatureInteraction {
@@ -53,6 +55,42 @@ export const vectorPropertyChangeKeys: PropertyChangedKey[] = [
53
55
  'heightAboveGround',
54
56
  ];
55
57
 
58
+ function assignVectorProperty<
59
+ K extends PropertyChangedKey,
60
+ V extends VectorProperties[K],
61
+ >(props: VectorProperties, key: K, value: V): void {
62
+ props[key] = value;
63
+ }
64
+
65
+ export function syncScratchLayerVectorProperties(
66
+ scratchLayer: VectorLayer,
67
+ layer: VectorLayer,
68
+ altitudeModeChanged?: () => void,
69
+ ): () => void {
70
+ vectorPropertyChangeKeys.forEach((key) => {
71
+ assignVectorProperty(
72
+ scratchLayer.vectorProperties,
73
+ key,
74
+ layer.vectorProperties[key],
75
+ );
76
+ });
77
+
78
+ return layer.vectorProperties.propertyChanged.addEventListener((props) => {
79
+ vectorPropertyChangeKeys.forEach((key) => {
80
+ if (props.includes(key)) {
81
+ assignVectorProperty(
82
+ scratchLayer.vectorProperties,
83
+ key,
84
+ layer.vectorProperties[key],
85
+ );
86
+ if (key === 'altitudeMode') {
87
+ altitudeModeChanged?.();
88
+ }
89
+ }
90
+ });
91
+ });
92
+ }
93
+
56
94
  export function getOlcsPropsFromFeature(
57
95
  feature: Feature,
58
96
  ): Record<string, number | string> {
@@ -70,19 +108,50 @@ export function getOlcsPropsFromFeature(
70
108
  export function createVertex(
71
109
  coordinate: Coordinate,
72
110
  olcsProps: Record<string, number | string>,
111
+ index: number,
73
112
  ): Vertex {
74
113
  const geometry = new Point(coordinate);
75
114
  geometry[alreadyTransformedToImage] = true;
76
115
  const vertex = new Feature({
77
116
  geometry,
78
117
  ...olcsProps,
79
- });
118
+ }) as Vertex;
80
119
  vertex[vertexSymbol] = true;
120
+ vertex[vertexIndexSymbol] = index;
81
121
  vertex[doNotTransform] = true;
82
122
  vertex[createSync] = true;
83
123
  return vertex;
84
124
  }
85
125
 
126
+ export function getCoordinatesAndLayoutFromVertices(vertices: Vertex[]): {
127
+ coordinates: Coordinate[];
128
+ layout: GeometryLayout;
129
+ } {
130
+ let is2D = false;
131
+ const flatCoordinates = new Array<number>(vertices.length * 3);
132
+ vertices.forEach((v, i) => {
133
+ const vertexCoordinates = v.getGeometry()!.getCoordinates();
134
+ is2D = is2D || vertexCoordinates.length === 2;
135
+ flatCoordinates[i * 3] = vertexCoordinates[0];
136
+ flatCoordinates[i * 3 + 1] = vertexCoordinates[1];
137
+ flatCoordinates[i * 3 + 2] = vertexCoordinates[2];
138
+ });
139
+
140
+ const coordinates = new Array<Coordinate>(vertices.length);
141
+ for (let i = 0; i < vertices.length; i++) {
142
+ const coordinate = [flatCoordinates[i * 3], flatCoordinates[i * 3 + 1]];
143
+ if (!is2D) {
144
+ coordinate[2] = flatCoordinates[i * 3 + 2];
145
+ }
146
+ coordinates[i] = coordinate;
147
+ }
148
+
149
+ return {
150
+ coordinates,
151
+ layout: is2D ? 'XY' : 'XYZ',
152
+ };
153
+ }
154
+
86
155
  let scratchCartesian21 = new Cartesian2();
87
156
  let scratchCartesian22 = new Cartesian2();
88
157
  let scratchCartesian23 = new Cartesian2();
@@ -124,6 +193,7 @@ export function getClosestPointOn2DLine(
124
193
  lambda,
125
194
  scratchCartesian21,
126
195
  );
196
+
127
197
  return [
128
198
  scratchCartesian21.x + start[0],
129
199
  scratchCartesian21.y + start[1],
@@ -297,7 +367,7 @@ export async function drapeGeometryOnTerrain(
297
367
  const coordinates = geometry.getCoordinates() as any[];
298
368
  const flats = getFlatCoordinatesFromGeometry(geometry, coordinates);
299
369
  await map.getHeightFromTerrain(flats);
300
- geometry.setCoordinates(coordinates);
370
+ geometry.setCoordinates(coordinates, 'XYZ');
301
371
  }
302
372
  }
303
373
 
@@ -323,28 +393,6 @@ export async function placeGeometryOnTerrain(
323
393
  flats.forEach((coord) => {
324
394
  coord[2] = minHeight;
325
395
  });
326
- geometry.setCoordinates(coordinates);
327
- }
328
- }
329
-
330
- export async function ensureFeatureAbsolute(
331
- feature: Feature,
332
- layer: VectorLayer,
333
- cesiumMap: CesiumMap,
334
- ): Promise<void> {
335
- // XXX this does not ensure 3D coordinates
336
- const layerIsClamped =
337
- layer.vectorProperties.altitudeMode === HeightReference.CLAMP_TO_GROUND;
338
- const altitudeMode = feature.get('olcs_altitudeMode') as string;
339
- if (altitudeMode === 'clampToGround' || (!altitudeMode && layerIsClamped)) {
340
- feature.set('olcs_altitudeMode', 'absolute', true);
341
- const geometry = feature.getGeometry();
342
- if (geometry) {
343
- await placeGeometryOnTerrain(geometry, cesiumMap);
344
- }
396
+ geometry.setCoordinates(coordinates, 'XYZ');
345
397
  }
346
398
  }
347
-
348
- export function clampFeature(feature: import('ol').Feature): void {
349
- feature.set('olcs_altitudeMode', 'clampToGround');
350
- }
@@ -10,6 +10,13 @@ import { markVolatile } from '../../vcsModule.js';
10
10
  import { PrimitiveOptionsType } from '../../layer/vectorProperties.js';
11
11
  import EventHandler from '../../interaction/eventHandler.js';
12
12
  import type VcsApp from '../../vcsApp.js';
13
+ import { InteractionEvent } from '../../interaction/abstractInteraction.js';
14
+
15
+ export const alreadySnapped = Symbol('alreadySnapped');
16
+
17
+ export type SnappingInteractionEvent = InteractionEvent & {
18
+ [alreadySnapped]?: boolean;
19
+ };
13
20
 
14
21
  export enum SessionType {
15
22
  CREATE = 'create',
@@ -5,7 +5,7 @@ export const vertexSymbol = Symbol('Vertex');
5
5
  /**
6
6
  * Symbol to denote the vertexes index in the vertices array. This is important for snapping & bbox operations
7
7
  */
8
- export const vertexIndex = Symbol('VertexIndex');
8
+ export const vertexIndexSymbol = Symbol('VertexIndex');
9
9
  /**
10
10
  * Symbol added to primitives and features to denote that these are handlers. It is expected, that the value of the symobl is
11
11
  * equal to an {@link AxisAndPlanes}
@@ -13,6 +13,7 @@ import {
13
13
  } from '../../../layer/vectorSymbols.js';
14
14
  import ObliqueMap from '../../../map/obliqueMap.js';
15
15
  import type { CreateInteraction } from '../createFeatureSession.js';
16
+ import { is2DLayout } from '../../geometryHelpers.js';
16
17
 
17
18
  /**
18
19
  * Offset to prevent bbox from collapsing
@@ -32,6 +33,8 @@ class CreateBBoxInteraction
32
33
 
33
34
  private _lastCoordinate: Coordinate | null = null;
34
35
 
36
+ private _is3D = false;
37
+
35
38
  finished = new VcsEvent<Polygon | null>();
36
39
 
37
40
  created = new VcsEvent<Polygon>();
@@ -56,27 +59,32 @@ class CreateBBoxInteraction
56
59
  this._lastCoordinate[1] += precisionOffset;
57
60
  }
58
61
 
59
- this._lastCoordinate[2] = this._origin[2];
60
- let ringCoordinates;
62
+ if (this._is3D) {
63
+ this._lastCoordinate[2] = this._origin[2];
64
+ }
65
+
66
+ let lowerRight: Coordinate;
67
+ let upperLeft: Coordinate;
68
+
61
69
  if (
62
70
  (originXHigher && originYHigher) ||
63
71
  (!originXHigher && !originYHigher)
64
72
  ) {
65
- ringCoordinates = [
66
- this._origin,
67
- [this._lastCoordinate[0], this._origin[1], this._origin[2]],
68
- this._lastCoordinate,
69
- [this._origin[0], this._lastCoordinate[1], this._origin[2]],
70
- ];
73
+ lowerRight = [this._lastCoordinate[0], this._origin[1]];
74
+ upperLeft = [this._origin[0], this._lastCoordinate[1]];
71
75
  } else {
72
- ringCoordinates = [
73
- this._origin,
74
- [this._origin[0], this._lastCoordinate[1], this._origin[2]],
75
- this._lastCoordinate,
76
- [this._lastCoordinate[0], this._origin[1], this._origin[2]],
77
- ];
76
+ lowerRight = [this._origin[0], this._lastCoordinate[1]];
77
+ upperLeft = [this._lastCoordinate[0], this._origin[1]];
78
78
  }
79
- this._geometry.setCoordinates([ringCoordinates]);
79
+
80
+ if (this._is3D) {
81
+ lowerRight.push(this._origin[2]);
82
+ upperLeft.push(this._origin[2]);
83
+ }
84
+
85
+ this._geometry.setCoordinates([
86
+ [this._origin, lowerRight, this._lastCoordinate, upperLeft],
87
+ ]);
80
88
  }
81
89
  }
82
90
 
@@ -94,8 +102,9 @@ class CreateBBoxInteraction
94
102
  if (this._geometry) {
95
103
  this.finish();
96
104
  } else {
97
- this._geometry = new Polygon([[event.positionOrPixel.slice()]], 'XYZ');
105
+ this._geometry = new Polygon([[event.positionOrPixel.slice()]]);
98
106
  this._geometry.set('_vcsGeomType', GeometryType.BBox);
107
+ this._is3D = !is2DLayout(this._geometry.getLayout());
99
108
  if (event.map instanceof ObliqueMap) {
100
109
  this._geometry[alreadyTransformedToImage] = true;
101
110
  } else {
@@ -60,7 +60,7 @@ class CreateCircleInteraction
60
60
  if (this._geometry) {
61
61
  this.finish();
62
62
  } else {
63
- this._geometry = new Circle(event.positionOrPixel, 20, 'XYZ');
63
+ this._geometry = new Circle(event.positionOrPixel, 20);
64
64
  this._geometry[actuallyIsCircle] = event.map instanceof ObliqueMap;
65
65
  if (event.map instanceof ObliqueMap) {
66
66
  this._geometry[alreadyTransformedToImage] = true;