qwc2 2026.2.27 → 2026.3.18

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 (85) hide show
  1. package/components/AppMenu.js +13 -8
  2. package/components/CoordinateDisplayer.js +5 -3
  3. package/components/IdentifyViewer.js +2 -1
  4. package/components/QtDesignerForm.js +1 -1
  5. package/components/SideBar.js +2 -2
  6. package/components/map/OlMap.js +7 -1
  7. package/components/map3d/Map3D.js +83 -38
  8. package/components/map3d/MapControls3D.js +2 -3
  9. package/components/map3d/drawtool/CreateTool3D.js +2 -1
  10. package/components/map3d/drawtool/EditTool3D.js +224 -13
  11. package/components/map3d/utils/FirstPersonControls3D.js +1 -0
  12. package/components/map3d/utils/MiscUtils3D.js +187 -24
  13. package/components/style/App.css +1 -0
  14. package/components/style/AppMenu.css +6 -0
  15. package/components/style/DefaultStyleScheme.css +4 -0
  16. package/components/style/MessageBar.css +1 -0
  17. package/components/style/PluginsContainer.css +3 -0
  18. package/components/style/QtDesignerForm.css +5 -0
  19. package/components/style/ResizeableWindow.css +4 -1
  20. package/components/style/SearchBox.css +2 -0
  21. package/components/style/SideBar.css +1 -0
  22. package/components/style/ThemeList.css +3 -1
  23. package/components/widgets/ColorButton.js +6 -1
  24. package/components/widgets/style/InputContainer.css +2 -0
  25. package/components/widgets/style/ListInput.css +4 -1
  26. package/icons/measureobj.svg +58 -0
  27. package/icons/snap_3d.svg +105 -0
  28. package/package.json +4 -1
  29. package/plugins/API.js +9 -1
  30. package/plugins/Editing.js +25 -2
  31. package/plugins/FeatureSearch.js +42 -41
  32. package/plugins/LayerTree.js +113 -59
  33. package/plugins/LocateButton.js +1 -1
  34. package/plugins/Map.js +1 -0
  35. package/plugins/MapFilter.js +10 -45
  36. package/plugins/MapLegend.js +10 -2
  37. package/plugins/ObliqueView.js +4 -4
  38. package/plugins/Panoramax.js +5 -5
  39. package/plugins/TopBar.js +3 -0
  40. package/plugins/map/MeasurementSupport.js +19 -0
  41. package/plugins/map3d/Draw3D.js +32 -4
  42. package/plugins/map3d/ExportObjects3D.js +24 -21
  43. package/plugins/map3d/HideObjects3D.js +45 -35
  44. package/plugins/map3d/Identify3D.js +9 -14
  45. package/plugins/map3d/MeasureObjects3D.js +362 -0
  46. package/plugins/map3d/style/MeasureObjects3D.css +34 -0
  47. package/plugins/style/BottomBar.css +5 -0
  48. package/plugins/style/FeatureSearch.css +0 -5
  49. package/plugins/style/LayerTree.css +2 -1
  50. package/plugins/style/ObliqueView.css +2 -2
  51. package/plugins/style/TopBar.css +1 -0
  52. package/resources/panoramax-cursor.svg +20 -0
  53. package/resources/target.svg +6 -0
  54. package/scripts/themesConfig.js +1 -0
  55. package/scripts/themesConfig.py +2 -0
  56. package/static/translations/bg-BG.json +22 -2
  57. package/static/translations/ca-ES.json +78 -58
  58. package/static/translations/cs-CZ.json +22 -2
  59. package/static/translations/de-CH.json +23 -3
  60. package/static/translations/de-DE.json +23 -3
  61. package/static/translations/en-US.json +24 -4
  62. package/static/translations/es-ES.json +62 -42
  63. package/static/translations/fi-FI.json +22 -2
  64. package/static/translations/fr-FR.json +47 -27
  65. package/static/translations/hu-HU.json +22 -2
  66. package/static/translations/it-IT.json +46 -26
  67. package/static/translations/ja-JP.json +22 -2
  68. package/static/translations/nl-NL.json +22 -2
  69. package/static/translations/no-NO.json +22 -2
  70. package/static/translations/pl-PL.json +22 -2
  71. package/static/translations/pt-BR.json +22 -2
  72. package/static/translations/pt-PT.json +22 -2
  73. package/static/translations/ro-RO.json +22 -2
  74. package/static/translations/ru-RU.json +22 -2
  75. package/static/translations/sv-SE.json +22 -2
  76. package/static/translations/tr-TR.json +22 -2
  77. package/static/translations/tsconfig.json +19 -1
  78. package/static/translations/uk-UA.json +22 -2
  79. package/utils/DataServiceExprUtils.js +167 -0
  80. package/utils/FeatureSnapIndex.js +293 -0
  81. package/utils/FeatureStyles.js +4 -0
  82. package/utils/IdentifyUtils.js +2 -0
  83. package/utils/LayerUtils.js +36 -37
  84. package/utils/SearchProviders.js +55 -21
  85. package/utils/ThemeUtils.js +2 -0
@@ -123,6 +123,7 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
123
123
  "appmenu-submenu": true,
124
124
  "appmenu-submenu-expanded": expanded
125
125
  });
126
+ var label = item.title ? LocaleUtils.tr(item.title) : LocaleUtils.tr("appmenu.items." + item.key);
126
127
  return [/*#__PURE__*/React.createElement("div", {
127
128
  className: className,
128
129
  key: (_item$key = item.key) !== null && _item$key !== void 0 ? _item$key : item.title,
@@ -136,13 +137,14 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
136
137
  tabIndex: 0
137
138
  }, /*#__PURE__*/React.createElement(Icon, {
138
139
  icon: item.icon,
139
- size: "xlarge"
140
- }), item.title ? LocaleUtils.tr(item.title) : LocaleUtils.tr("appmenu.items." + item.key)), subitems];
140
+ size: "xlarge",
141
+ title: _this.props.menuIconOnly ? label : null
142
+ }), !_this.props.menuIconOnly ? label : null), subitems];
141
143
  } else {
142
144
  var trargs = item.trargs || [];
143
- var label = item.title ? LocaleUtils.tr.apply(LocaleUtils, [item.title].concat(_toConsumableArray(trargs))) : LocaleUtils.tr.apply(LocaleUtils, ["appmenu.items." + item.key + (item.mode || "")].concat(_toConsumableArray(trargs)));
145
+ var _label = item.title ? LocaleUtils.tr.apply(LocaleUtils, [item.title].concat(_toConsumableArray(trargs))) : LocaleUtils.tr.apply(LocaleUtils, ["appmenu.items." + item.key + (item.mode || "")].concat(_toConsumableArray(trargs)));
144
146
  var comment = item.comment ? LocaleUtils.tr.apply(LocaleUtils, ["appmenu.items." + item.key + (item.mode || "") + "_comment"].concat(_toConsumableArray(trargs))) : "";
145
- if (!filter || removeDiacritics(label.toLowerCase()).match(filter) || comment && removeDiacritics(comment.toLowerCase()).match(filter)) {
147
+ if (!filter || removeDiacritics(_label.toLowerCase()).match(filter) || comment && removeDiacritics(comment.toLowerCase()).match(filter)) {
146
148
  var _className = classnames({
147
149
  "appmenu-menu-item": true,
148
150
  "appmenu-menu-item-nested": submenu
@@ -160,12 +162,13 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
160
162
  tabIndex: 0
161
163
  }, /*#__PURE__*/React.createElement(Icon, {
162
164
  icon: item.icon,
163
- size: "xlarge"
164
- }), /*#__PURE__*/React.createElement("span", {
165
+ size: "xlarge",
166
+ title: _this.props.menuIconOnly ? _label : null
167
+ }), !_this.props.menuIconOnly ? /*#__PURE__*/React.createElement("span", {
165
168
  className: "appmenu-menu-item-label"
166
- }, label, comment ? /*#__PURE__*/React.createElement("div", {
169
+ }, _label, comment ? /*#__PURE__*/React.createElement("div", {
167
170
  className: "appmenu-menu-item-comment"
168
- }, comment) : null));
171
+ }, comment) : null) : null);
169
172
  }
170
173
  return null;
171
174
  }
@@ -284,6 +287,7 @@ var AppMenu = /*#__PURE__*/function (_React$Component) {
284
287
  "appmenu-blocked": this.props.currentTaskBlocked,
285
288
  "appmenu-visible": visible,
286
289
  "appmenu-compact": this.props.menuCompact,
290
+ "appmenu-icononly": this.props.menuIconOnly,
287
291
  "appmenu-nolabel": !showLabel
288
292
  });
289
293
  var filter = this.state.filter ? new RegExp(removeDiacritics(this.state.filter).replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&"), "i") : null;
@@ -360,6 +364,7 @@ _defineProperty(AppMenu, "propTypes", {
360
364
  currentTaskBlocked: PropTypes.bool,
361
365
  keepMenuOpen: PropTypes.bool,
362
366
  menuCompact: PropTypes.bool,
367
+ menuIconOnly: PropTypes.bool,
363
368
  menuItems: PropTypes.array,
364
369
  onMenuToggled: PropTypes.func,
365
370
  openExternalUrl: PropTypes.func,
@@ -37,9 +37,11 @@ var CoordinateDisplayer = /*#__PURE__*/function (_React$Component) {
37
37
  mousePos: null
38
38
  });
39
39
  _defineProperty(_this, "getMapMousePos", function (ev) {
40
- _this.setState({
41
- mousePos: ev.coordinate
42
- });
40
+ if (ev.coordinate) {
41
+ _this.setState({
42
+ mousePos: ev.coordinate
43
+ });
44
+ }
43
45
  });
44
46
  return _this;
45
47
  }
@@ -1154,7 +1154,8 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1154
1154
  text = DOMPurify.sanitize(text, {
1155
1155
  ADD_ATTR: ['target'],
1156
1156
  ADD_TAGS: ["iframe"],
1157
- FORCE_BODY: true
1157
+ FORCE_BODY: true,
1158
+ ALLOW_UNKNOWN_PROTOCOLS: true
1158
1159
  }).replace('&#10;', '<br />');
1159
1160
  var options = {
1160
1161
  replace: function replace(node) {
@@ -572,7 +572,7 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
572
572
  }, inputConstraints, {
573
573
  style: fontStyle,
574
574
  type: "date",
575
- value: value
575
+ value: value.split("T")[0]
576
576
  }));
577
577
  } else if (widget["class"] === "QTimeEdit") {
578
578
  return /*#__PURE__*/React.createElement("input", _extends({
@@ -157,11 +157,11 @@ var SideBar = /*#__PURE__*/function (_React$Component) {
157
157
  onPointerDown: this.startSidebarResize
158
158
  }), /*#__PURE__*/React.createElement("div", {
159
159
  className: "sidebar-titlebar"
160
- }, this.state.render ? this.props.extraBeforeContent : null, /*#__PURE__*/React.createElement(Icon, {
160
+ }, this.state.render ? this.props.extraBeforeContent : null, this.props.icon ? /*#__PURE__*/React.createElement(Icon, {
161
161
  className: "sidebar-titlebar-icon",
162
162
  icon: this.props.icon,
163
163
  size: "large"
164
- }), /*#__PURE__*/React.createElement("span", {
164
+ }) : null, /*#__PURE__*/React.createElement("span", {
165
165
  className: "sidebar-titlebar-title"
166
166
  }, this.props.title), this.state.render ? this.props.extraTitlebarContent : null, /*#__PURE__*/React.createElement("span", {
167
167
  className: "sidebar-titlebar-spacer"
@@ -185,7 +185,8 @@ var OlMap = /*#__PURE__*/function (_React$Component) {
185
185
  constrainRotation: false,
186
186
  enableRotation: enableRotation !== false,
187
187
  rotation: MapUtils.degreesToRadians(rotation) || 0,
188
- extent: extent
188
+ extent: extent,
189
+ constrainOnlyCenter: _this.props.mapOptions.constrainOnlyCenter || false
189
190
  };
190
191
  return new ol.View(viewOptions);
191
192
  });
@@ -320,6 +321,11 @@ var OlMap = /*#__PURE__*/function (_React$Component) {
320
321
  if (prevProps.bbox.rotation !== this.props.bbox.rotation) {
321
322
  view.setRotation(this.props.bbox.rotation);
322
323
  }
324
+ if (prevProps.fullExtent !== this.props.fullExtent) {
325
+ this.setState({
326
+ rebuildView: true
327
+ });
328
+ }
323
329
  }
324
330
  if (this.state.rebuildView) {
325
331
  this.setState({
@@ -51,7 +51,9 @@ import axios from 'axios';
51
51
  import { fromUrl } from "geotiff";
52
52
  import isEmpty from 'lodash.isempty';
53
53
  import PropTypes from 'prop-types';
54
- import { Vector2, CubeTextureLoader, Group, Raycaster, Mesh, Box3, Vector3, Matrix4 } from 'three';
54
+ import * as THREE from 'three';
55
+ import { Vector2, CubeTextureLoader, Group, Raycaster, Mesh, Box3, Vector3, Matrix4, EventDispatcher } from 'three';
56
+ import { computeBoundsTree, disposeBoundsTree, computeBatchedBoundsTree, disposeBatchedBoundsTree, acceleratedRaycast } from 'three-mesh-bvh';
55
57
  import { GLTFExporter } from 'three/addons/exporters/GLTFExporter.js';
56
58
  import { GLTFLoader } from 'three/addons/loaders/GLTFLoader';
57
59
  import { v4 as uuidv4 } from 'uuid';
@@ -73,6 +75,12 @@ import MapControls3D from './MapControls3D';
73
75
  import { updateObjectLabel } from './utils/MiscUtils3D';
74
76
  import Tiles3DStyle from './utils/Tiles3DStyle';
75
77
  import './style/Map3D.css';
78
+ THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
79
+ THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
80
+ THREE.Mesh.prototype.raycast = acceleratedRaycast;
81
+ THREE.BatchedMesh.prototype.computeBoundsTree = computeBatchedBoundsTree;
82
+ THREE.BatchedMesh.prototype.disposeBoundsTree = disposeBatchedBoundsTree;
83
+ THREE.BatchedMesh.prototype.raycast = acceleratedRaycast;
76
84
 
77
85
  // Ensures onUnload is called *after* all other children have unmounted
78
86
  var UnloadWrapper = /*#__PURE__*/function (_React$Component) {
@@ -138,7 +146,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
138
146
  removeSceneObject: function removeSceneObject(objectId) {},
139
147
  updateSceneObject: function updateSceneObject(objectId, options, flags) {},
140
148
  zoomToObject: function zoomToObject(objectId) {},
149
+ objectIsVisible: function objectIsVisible(objectId) {},
141
150
  getMap: function getMap() {},
151
+ computeBoundsTree: function computeBoundsTree(object) {},
142
152
  setViewToExtent: function setViewToExtent(bounds, angle) {},
143
153
  getTerrainHeightFromDTM: function getTerrainHeightFromDTM(scenePos) {},
144
154
  getTerrainHeightFromMap: function getTerrainHeightFromMap(scenePos) {},
@@ -175,9 +185,11 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
175
185
  // Nothing changed
176
186
  return;
177
187
  }
178
- var dtm = _this2.getLayer("__dtm");
179
- if (visibility !== dtm.visible) {
180
- dtm.visible = visibility;
188
+ if (visibility !== !!_this2.map.backgroundOpacity) {
189
+ var dtm = _this2.getLayer("__dtm");
190
+ if (dtm) {
191
+ dtm.visible = visibility;
192
+ }
181
193
  _this2.map.receiveShadow = visibility;
182
194
  _this2.map.backgroundOpacity = visibility ? 1 : 0;
183
195
  _this2.instance.notifyChange(_this2.map);
@@ -477,6 +489,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
477
489
  scene.userData.tilesetName = objectId;
478
490
  scene.userData.featureIdAttr = "id";
479
491
  Tiles3DStyle.applyTileStyle(scene, tiles.userData, _this2.state.sceneContext);
492
+ _this2.computeBoundsTree(scene);
480
493
  _this2.instance.notifyChange(tiles);
481
494
  });
482
495
  // Show/hide labels when tile visibility changes
@@ -500,12 +513,16 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
500
513
  var callback = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
501
514
  var loader = new GLTFLoader();
502
515
  var processor = function processor(gltf) {
516
+ var root = gltf.scene;
517
+ if (root.children.length === 1 && root.children[0].isGroup) {
518
+ root = root.children[0];
519
+ }
503
520
  // GLTF is Y-UP, we need Z-UP
504
- gltf.scene.rotation.x = Math.PI / 2;
505
- gltf.scene.updateMatrixWorld(true);
506
- gltf.scene.castShadow = true;
507
- gltf.scene.receiveShadow = true;
508
- gltf.scene.traverse(function (c) {
521
+ root.rotation.x += Math.PI / 2;
522
+ root.updateMatrixWorld(true);
523
+ root.castShadow = true;
524
+ root.receiveShadow = true;
525
+ root.traverse(function (c) {
509
526
  if (c.geometry) {
510
527
  c.castShadow = true;
511
528
  c.receiveShadow = true;
@@ -514,19 +531,18 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
514
531
  });
515
532
 
516
533
  // Shift root position to center of object
517
- gltf.scene.updateMatrixWorld(true);
518
- var box = new Box3().setFromObject(gltf.scene);
534
+ var box = new Box3().setFromObject(root);
519
535
  var centerWorld = box.getCenter(new Vector3());
520
536
  centerWorld.z = box.min.z;
521
- var centerLocal = gltf.scene.worldToLocal(centerWorld.clone());
522
- gltf.scene.position.add(centerWorld);
537
+ var centerLocal = root.worldToLocal(centerWorld.clone());
538
+ root.position.add(centerWorld);
523
539
 
524
540
  // Offset children back so the world positions remain unchanged
525
- gltf.scene.children.forEach(function (child) {
541
+ root.children.forEach(function (child) {
526
542
  child.position.sub(centerLocal);
527
543
  });
528
- gltf.scene.updateMatrixWorld(true);
529
- _this2.addSceneObject(objectId, gltf.scene, addToLayerTree, treeOptions, showEditTool);
544
+ root.updateMatrixWorld(true);
545
+ _this2.addSceneObject(objectId, root, addToLayerTree, treeOptions, showEditTool);
530
546
  callback === null || callback === void 0 || callback();
531
547
  };
532
548
  if (typeof dataOrUrl === 'string') {
@@ -541,6 +557,12 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
541
557
  });
542
558
  }
543
559
  });
560
+ _defineProperty(_this2, "computeBoundsTree", function (group) {
561
+ group.traverse(function (c) {
562
+ var _c$geometry, _c$geometry$computeBo;
563
+ (_c$geometry = c.geometry) === null || _c$geometry === void 0 || (_c$geometry$computeBo = _c$geometry.computeBoundsTree) === null || _c$geometry$computeBo === void 0 || _c$geometry$computeBo.call(_c$geometry);
564
+ });
565
+ });
544
566
  _defineProperty(_this2, "addSceneObject", function (objectId, object) {
545
567
  var addToLayerTree = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
546
568
  var treeOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
@@ -553,6 +575,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
553
575
  _this2.objectMap[objectId] = object;
554
576
  _this2.instance.notifyChange(object);
555
577
  if (addToLayerTree) {
578
+ _this2.computeBoundsTree(object);
556
579
  _this2.setState(function (state) {
557
580
  var newObjectTree = _objectSpread({}, state.sceneContext.objectTree);
558
581
  newObjectTree["null"] = _objectSpread(_objectSpread({}, newObjectTree["null"]), {}, {
@@ -562,7 +585,8 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
562
585
  objectId: objectId,
563
586
  parent: null,
564
587
  visibility: true,
565
- opacity: 255
588
+ opacity: 255,
589
+ snap: true
566
590
  }, treeOptions);
567
591
  return {
568
592
  sceneContext: _objectSpread(_objectSpread({}, state.sceneContext), {}, {
@@ -749,6 +773,15 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
749
773
  _this2.state.sceneContext.setViewToExtent(bounds, 0);
750
774
  }
751
775
  });
776
+ _defineProperty(_this2, "objectIsVisible", function (objectId) {
777
+ var objectTree = _this2.state.sceneContext.objectTree;
778
+ var options = objectTree[objectId];
779
+ var isVisible = options.opacity > 0 && options.visibility;
780
+ for (var curId = options.parent; isVisible && curId !== undefined; curId = objectTree[curId].parent) {
781
+ isVisible && (isVisible = objectTree[curId].visibility);
782
+ }
783
+ return isVisible;
784
+ });
752
785
  _defineProperty(_this2, "getMap", function () {
753
786
  return _this2.map;
754
787
  });
@@ -770,7 +803,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
770
803
  }
771
804
  });
772
805
  _defineProperty(_this2, "setupInstance", function () {
773
- var _this2$props$theme$ma, _this2$props$theme$ma2, _this2$props$theme$ma3, _this2$props$theme$ma4, _this2$props$theme$ma5, _this2$props$theme$ma8, _this2$props$theme$ma9, _this2$props$theme$ma0, _this2$props$theme$ma1;
806
+ var _this2$props$theme$ma, _this2$props$theme$ma2, _this2$props$theme$ma3, _this2$props$theme$ma4, _this2$props$theme$ma7;
774
807
  if (_this2.instance) {
775
808
  _this2.disposeInstance();
776
809
  }
@@ -794,7 +827,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
794
827
  _this2.instance.add(_this2.sceneObjectGroup);
795
828
 
796
829
  // Setup map
797
- var initialBbox = (_this2$props$theme$ma = (_this2$props$theme$ma2 = _this2.props.theme.map3d) === null || _this2$props$theme$ma2 === void 0 ? void 0 : _this2$props$theme$ma2.extent) !== null && _this2$props$theme$ma !== void 0 ? _this2$props$theme$ma : _this2.props.theme.initialBbox;
830
+ var initialBbox = (_this2$props$theme$ma = _this2.props.theme.map3d.extent) !== null && _this2$props$theme$ma !== void 0 ? _this2$props$theme$ma : _this2.props.theme.initialBbox;
798
831
  var bounds = CoordinatesUtils.reprojectBbox(initialBbox.bounds, initialBbox.crs, projection);
799
832
  var extent = new Extent(crs, bounds[0], bounds[2], bounds[1], bounds[3]);
800
833
  _this2.map = new Map({
@@ -819,16 +852,16 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
819
852
  _this2.instance.scene.background = cubeTexture;
820
853
 
821
854
  // Setup elevation
822
- var demUrl = MiscUtils.resolveAssetsPath((_this2$props$theme$ma3 = (_this2$props$theme$ma4 = _this2.props.theme.map3d) === null || _this2$props$theme$ma4 === void 0 || (_this2$props$theme$ma4 = _this2$props$theme$ma4.dtm) === null || _this2$props$theme$ma4 === void 0 ? void 0 : _this2$props$theme$ma4.url) !== null && _this2$props$theme$ma3 !== void 0 ? _this2$props$theme$ma3 : "");
823
- var demCrs = CoordinateSystem.fromSrid(((_this2$props$theme$ma5 = _this2.props.theme.map3d) === null || _this2$props$theme$ma5 === void 0 || (_this2$props$theme$ma5 = _this2$props$theme$ma5.dtm) === null || _this2$props$theme$ma5 === void 0 ? void 0 : _this2$props$theme$ma5.crs) || "EPSG:3857");
855
+ var demUrl = MiscUtils.resolveAssetsPath((_this2$props$theme$ma2 = (_this2$props$theme$ma3 = _this2.props.theme.map3d.dtm) === null || _this2$props$theme$ma3 === void 0 ? void 0 : _this2$props$theme$ma3.url) !== null && _this2$props$theme$ma2 !== void 0 ? _this2$props$theme$ma2 : "");
856
+ var demCrs = CoordinateSystem.fromSrid(((_this2$props$theme$ma4 = _this2.props.theme.map3d.dtm) === null || _this2$props$theme$ma4 === void 0 ? void 0 : _this2$props$theme$ma4.crs) || "EPSG:3857");
824
857
  if (demUrl) {
825
- var _this2$props$theme$ma6, _this2$props$theme$ma7;
858
+ var _this2$props$theme$ma5, _this2$props$theme$ma6;
826
859
  var demSource = new GeoTIFFSource({
827
860
  url: demUrl,
828
861
  crs: demCrs
829
862
  });
830
- var demMin = (_this2$props$theme$ma6 = _this2.props.theme.map3d.dtm.min) !== null && _this2$props$theme$ma6 !== void 0 ? _this2$props$theme$ma6 : undefined;
831
- var demMax = (_this2$props$theme$ma7 = _this2.props.theme.map3d.dtm.max) !== null && _this2$props$theme$ma7 !== void 0 ? _this2$props$theme$ma7 : undefined;
863
+ var demMin = (_this2$props$theme$ma5 = _this2.props.theme.map3d.dtm.min) !== null && _this2$props$theme$ma5 !== void 0 ? _this2$props$theme$ma5 : undefined;
864
+ var demMax = (_this2$props$theme$ma6 = _this2.props.theme.map3d.dtm.max) !== null && _this2$props$theme$ma6 !== void 0 ? _this2$props$theme$ma6 : undefined;
832
865
  var elevationLayer = new ElevationLayer({
833
866
  name: 'dem',
834
867
  extent: extent,
@@ -843,7 +876,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
843
876
 
844
877
  // Collect baselayers
845
878
  var externalLayers = {};
846
- var baseLayers = ThemeUtils.createThemeBackgroundLayers(((_this2$props$theme$ma8 = _this2.props.theme.map3d) === null || _this2$props$theme$ma8 === void 0 ? void 0 : _this2$props$theme$ma8.basemaps) || [], _this2.props.themes, null, externalLayers);
879
+ var baseLayers = ThemeUtils.createThemeBackgroundLayers(_this2.props.theme.map3d.basemaps || [], _this2.props.themes, null, externalLayers);
847
880
  baseLayers.push({
848
881
  type: "blank",
849
882
  name: "",
@@ -872,14 +905,14 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
872
905
  // Collect color layers
873
906
  var colorLayers = _this2.collectColorLayers([], []);
874
907
  _this2.objectMap = {};
875
- var objects = ((_this2$props$theme$ma9 = _this2.props.theme.map3d) === null || _this2$props$theme$ma9 === void 0 ? void 0 : _this2$props$theme$ma9.objects) || [];
908
+ var objects = _toConsumableArray((_this2$props$theme$ma7 = _this2.props.theme.map3d.objects) !== null && _this2$props$theme$ma7 !== void 0 ? _this2$props$theme$ma7 : []);
876
909
  // Convert legacy flat lists to tree
877
- (((_this2$props$theme$ma0 = _this2.props.theme.map3d) === null || _this2$props$theme$ma0 === void 0 ? void 0 : _this2$props$theme$ma0.tiles3d) || []).forEach(function (entry) {
910
+ (_this2.props.theme.map3d.tiles3d || []).forEach(function (entry) {
878
911
  objects.push(_objectSpread(_objectSpread({}, entry), {}, {
879
912
  type: "tiles3d"
880
913
  }));
881
914
  });
882
- (((_this2$props$theme$ma1 = _this2.props.theme.map3d) === null || _this2$props$theme$ma1 === void 0 ? void 0 : _this2$props$theme$ma1.objects3d) || []).forEach(function (entry) {
915
+ (_this2.props.theme.map3d.objects3d || []).forEach(function (entry) {
883
916
  objects.push(_objectSpread(_objectSpread({}, entry), {}, {
884
917
  type: "object3d"
885
918
  }));
@@ -908,12 +941,13 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
908
941
  objectTree[groupId].children = _buildObjectTree(entry.items, groupId);
909
942
  nodeIds.push(groupId);
910
943
  } else if (entry.type === "tiles3d") {
911
- var _entry$title, _entry$visibility2;
944
+ var _entry$title, _entry$visibility2, _entry$snap;
912
945
  objectTree[entry.name] = {
913
946
  objectId: entry.name,
914
947
  parent: parentId,
915
948
  title: (_entry$title = entry.title) !== null && _entry$title !== void 0 ? _entry$title : entry.name,
916
949
  visibility: (_entry$visibility2 = entry.visibility) !== null && _entry$visibility2 !== void 0 ? _entry$visibility2 : true,
950
+ snap: (_entry$snap = entry.snap) !== null && _entry$snap !== void 0 ? _entry$snap : true,
917
951
  opacity: 255,
918
952
  styles: entry.styles || {},
919
953
  style: entry.style || Object.keys(entry.styles || {})[0] || null
@@ -930,12 +964,13 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
930
964
  _this2.applySceneObjectState(entry.name, objectTree[entry.name], {}, objectTree);
931
965
  nodeIds.push(entry.name);
932
966
  } else if (entry.type === "object3d") {
933
- var _entry$title2, _entry$visibility3;
967
+ var _entry$title2, _entry$visibility3, _entry$snap2;
934
968
  objectTree[entry.name] = {
935
969
  objectId: entry.name,
936
970
  parent: parentId,
937
971
  title: (_entry$title2 = entry.title) !== null && _entry$title2 !== void 0 ? _entry$title2 : entry.name,
938
972
  visibility: (_entry$visibility3 = entry.visibility) !== null && _entry$visibility3 !== void 0 ? _entry$visibility3 : true,
973
+ snap: (_entry$snap2 = entry.snap) !== null && _entry$snap2 !== void 0 ? _entry$snap2 : true,
939
974
  opacity: 255
940
975
  };
941
976
  _this2.importObject3D(MiscUtils.resolveAssetsPath(entry.url), entry.name, false, {}, false, function () {
@@ -1319,6 +1354,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
1319
1354
  _this2.sceneObjectGroup = null;
1320
1355
  _this2.objectMap = {};
1321
1356
  _this2.tilesetStyles = {};
1357
+ _this2.state.sceneContext.eventDispatcher = new EventDispatcher();
1322
1358
  _this2.state.sceneContext.addLayer = _this2.addLayer;
1323
1359
  _this2.state.sceneContext.getLayer = _this2.getLayer;
1324
1360
  _this2.state.sceneContext.removeLayer = _this2.removeLayer;
@@ -1331,7 +1367,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
1331
1367
  _this2.state.sceneContext.removeSceneObject = _this2.removeSceneObject;
1332
1368
  _this2.state.sceneContext.updateSceneObject = _this2.updateSceneObject;
1333
1369
  _this2.state.sceneContext.zoomToObject = _this2.zoomToObject;
1370
+ _this2.state.sceneContext.objectIsVisible = _this2.objectIsVisible;
1334
1371
  _this2.state.sceneContext.getMap = _this2.getMap;
1372
+ _this2.state.computeBoundsTree = _this2.computeBoundsTree;
1335
1373
  _this2.state.sceneContext.getTerrainHeightFromDTM = _this2.getTerrainHeightFromDTM;
1336
1374
  _this2.state.sceneContext.getTerrainHeightFromMap = _this2.getTerrainHeightFromMap;
1337
1375
  _this2.state.sceneContext.getSceneIntersection = _this2.getSceneIntersection;
@@ -1389,16 +1427,22 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
1389
1427
  this.setState(function (state) {
1390
1428
  return {
1391
1429
  sceneContext: _objectSpread(_objectSpread({}, state.sceneContext), {}, {
1392
- collisionObjects: Object.entries(state.sceneContext.objectTree).reduce(function (res, _ref12) {
1430
+ collisionObjects: Object.keys(state.sceneContext.objectTree).reduce(function (res, objectId) {
1431
+ var obj = _this3.objectMap[objectId];
1432
+ if (obj !== null && obj !== void 0 && obj.visible) {
1433
+ var _obj$tiles$group, _obj$tiles;
1434
+ res.push((_obj$tiles$group = (_obj$tiles = obj.tiles) === null || _obj$tiles === void 0 ? void 0 : _obj$tiles.group) !== null && _obj$tiles$group !== void 0 ? _obj$tiles$group : obj);
1435
+ }
1436
+ return res;
1437
+ }, []),
1438
+ snapObjects: Object.entries(state.sceneContext.objectTree).reduce(function (res, _ref12) {
1393
1439
  var _ref13 = _slicedToArray(_ref12, 2),
1394
- objectid = _ref13[0],
1440
+ objectId = _ref13[0],
1395
1441
  entry = _ref13[1];
1396
- if (entry.visibility && entry.opacity > 0) {
1397
- var obj = _this3.objectMap[entry.objectId];
1398
- if (obj) {
1399
- var _obj$tiles$group, _obj$tiles;
1400
- res.push((_obj$tiles$group = (_obj$tiles = obj.tiles) === null || _obj$tiles === void 0 ? void 0 : _obj$tiles.group) !== null && _obj$tiles$group !== void 0 ? _obj$tiles$group : obj);
1401
- }
1442
+ var obj = _this3.objectMap[objectId];
1443
+ if (obj !== null && obj !== void 0 && obj.visible && entry.snap) {
1444
+ var _obj$tiles$group2, _obj$tiles2;
1445
+ res.push((_obj$tiles$group2 = (_obj$tiles2 = obj.tiles) === null || _obj$tiles2 === void 0 ? void 0 : _obj$tiles2.group) !== null && _obj$tiles$group2 !== void 0 ? _obj$tiles$group2 : obj);
1402
1446
  }
1403
1447
  return res;
1404
1448
  }, [])
@@ -1487,6 +1531,7 @@ _defineProperty(Map3D, "defaultSceneState", {
1487
1531
  colorLayers: {},
1488
1532
  objectTree: {},
1489
1533
  collisionObjects: [],
1534
+ snapObjects: [],
1490
1535
  settings: {
1491
1536
  fov: 30,
1492
1537
  sceneQuality: 100
@@ -33,7 +33,7 @@ import { connect } from 'react-redux';
33
33
  import classNames from 'classnames';
34
34
  import PropTypes from 'prop-types';
35
35
  import { MOUSE, Vector3 } from 'three';
36
- import ConfigUtils from '../../utils/ConfigUtils';
36
+ import personSvg from '../../resources/person.svg';
37
37
  import { UrlParams } from '../../utils/PermaLinkUtils';
38
38
  import Icon from '../Icon';
39
39
  import { MapButtonPortalContext } from '../PluginsContainer';
@@ -85,8 +85,7 @@ var MapControls3D = /*#__PURE__*/function (_React$Component) {
85
85
  _this.props.sceneContext.scene.domElement.addEventListener('click', _this.setupFirstPerson, {
86
86
  once: true
87
87
  });
88
- var cursor = ConfigUtils.getAssetsPath() + "/img/person.svg";
89
- _this.props.sceneContext.scene.domElement.style.cursor = "url(".concat(cursor, "), pointer");
88
+ _this.props.sceneContext.scene.domElement.style.cursor = "url(".concat(personSvg, "), pointer");
90
89
  _this.setState({
91
90
  pickingFirstPerson: true
92
91
  });
@@ -108,12 +108,13 @@ var CreateTool3D = /*#__PURE__*/function (_React$Component) {
108
108
  var mesh = new Mesh(geometry, material);
109
109
  mesh.castShadow = true;
110
110
  mesh.receiveShadow = true;
111
- drawGroup.add(mesh);
112
111
  var pos = _this.drawCursor.points[0];
113
112
  mesh.position.copy(new Vector3(Math.round(pos.x), Math.round(pos.y), Math.floor(pos.z + 0.5 * s)));
114
113
  mesh.updateMatrixWorld();
114
+ drawGroup.attach(mesh);
115
115
  _this.props.sceneContext.scene.notifyChange();
116
116
  _this.props.objectCreated(mesh);
117
+ _this.props.sceneContext.computeBoundsTree(mesh);
117
118
  }
118
119
  });
119
120
  return _this;