qwc2 2026.2.25 → 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 (87) 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 +100 -44
  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 +63 -10
  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/TaskButton.js +1 -0
  40. package/plugins/TopBar.js +3 -0
  41. package/plugins/map/MeasurementSupport.js +19 -0
  42. package/plugins/map3d/Draw3D.js +32 -4
  43. package/plugins/map3d/ExportObjects3D.js +24 -21
  44. package/plugins/map3d/HideObjects3D.js +45 -35
  45. package/plugins/map3d/Identify3D.js +9 -14
  46. package/plugins/map3d/MeasureObjects3D.js +362 -0
  47. package/plugins/map3d/style/MeasureObjects3D.css +34 -0
  48. package/plugins/style/BottomBar.css +5 -0
  49. package/plugins/style/FeatureSearch.css +0 -5
  50. package/plugins/style/LayerTree.css +2 -1
  51. package/plugins/style/ObliqueView.css +2 -2
  52. package/plugins/style/TopBar.css +1 -0
  53. package/resources/panoramax-cursor.svg +20 -0
  54. package/resources/target.svg +6 -0
  55. package/scripts/gen-plugin-docs.js +1 -1
  56. package/scripts/themesConfig.js +1 -0
  57. package/scripts/themesConfig.py +2 -0
  58. package/static/translations/bg-BG.json +22 -2
  59. package/static/translations/ca-ES.json +78 -58
  60. package/static/translations/cs-CZ.json +22 -2
  61. package/static/translations/de-CH.json +23 -3
  62. package/static/translations/de-DE.json +23 -3
  63. package/static/translations/en-US.json +24 -4
  64. package/static/translations/es-ES.json +62 -42
  65. package/static/translations/fi-FI.json +22 -2
  66. package/static/translations/fr-FR.json +47 -27
  67. package/static/translations/hu-HU.json +22 -2
  68. package/static/translations/it-IT.json +46 -26
  69. package/static/translations/ja-JP.json +22 -2
  70. package/static/translations/nl-NL.json +22 -2
  71. package/static/translations/no-NO.json +22 -2
  72. package/static/translations/pl-PL.json +22 -2
  73. package/static/translations/pt-BR.json +22 -2
  74. package/static/translations/pt-PT.json +22 -2
  75. package/static/translations/ro-RO.json +22 -2
  76. package/static/translations/ru-RU.json +22 -2
  77. package/static/translations/sv-SE.json +22 -2
  78. package/static/translations/tr-TR.json +22 -2
  79. package/static/translations/tsconfig.json +19 -1
  80. package/static/translations/uk-UA.json +22 -2
  81. package/utils/DataServiceExprUtils.js +167 -0
  82. package/utils/FeatureSnapIndex.js +293 -0
  83. package/utils/FeatureStyles.js +4 -0
  84. package/utils/IdentifyUtils.js +2 -0
  85. package/utils/LayerUtils.js +36 -37
  86. package/utils/SearchProviders.js +55 -21
  87. 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) {},
@@ -170,14 +180,16 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
170
180
  var _this2$state$sceneCon;
171
181
  var currentBaseLayer = ((_this2$state$sceneCon = _this2.state.sceneContext.baseLayers.find(function (l) {
172
182
  return l.visibility === true;
173
- })) === null || _this2$state$sceneCon === void 0 ? void 0 : _this2$state$sceneCon.name) || "";
183
+ })) === null || _this2$state$sceneCon === void 0 ? void 0 : _this2$state$sceneCon.name) || null;
174
184
  if (visibility && layer.name === currentBaseLayer) {
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), {}, {
@@ -594,7 +618,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
594
618
  }
595
619
  // Ensure labels are removed
596
620
  object.traverse(function (c) {
597
- if (c.isCSS2DObject) {
621
+ if (c.isCSS2DObject && c.element.parentNode) {
598
622
  c.element.parentNode.removeChild(c.element);
599
623
  }
600
624
  });
@@ -645,6 +669,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
645
669
  });
646
670
  _defineProperty(_this2, "applySceneObjectState", function (objectId, options, prevOptions, objectTree) {
647
671
  var object = _this2.objectMap[objectId];
672
+ if (!object) {
673
+ return;
674
+ }
648
675
  var changed = false;
649
676
  if (options.visibility !== prevOptions.visibility || options.opacity !== (prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.opacity)) {
650
677
  var _objectTree$options$p;
@@ -746,6 +773,15 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
746
773
  _this2.state.sceneContext.setViewToExtent(bounds, 0);
747
774
  }
748
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
+ });
749
785
  _defineProperty(_this2, "getMap", function () {
750
786
  return _this2.map;
751
787
  });
@@ -767,7 +803,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
767
803
  }
768
804
  });
769
805
  _defineProperty(_this2, "setupInstance", function () {
770
- 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;
771
807
  if (_this2.instance) {
772
808
  _this2.disposeInstance();
773
809
  }
@@ -791,7 +827,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
791
827
  _this2.instance.add(_this2.sceneObjectGroup);
792
828
 
793
829
  // Setup map
794
- 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;
795
831
  var bounds = CoordinatesUtils.reprojectBbox(initialBbox.bounds, initialBbox.crs, projection);
796
832
  var extent = new Extent(crs, bounds[0], bounds[2], bounds[1], bounds[3]);
797
833
  _this2.map = new Map({
@@ -816,16 +852,16 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
816
852
  _this2.instance.scene.background = cubeTexture;
817
853
 
818
854
  // Setup elevation
819
- 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 : "");
820
- 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");
821
857
  if (demUrl) {
822
- var _this2$props$theme$ma6, _this2$props$theme$ma7;
858
+ var _this2$props$theme$ma5, _this2$props$theme$ma6;
823
859
  var demSource = new GeoTIFFSource({
824
860
  url: demUrl,
825
861
  crs: demCrs
826
862
  });
827
- var demMin = (_this2$props$theme$ma6 = _this2.props.theme.map3d.dtm.min) !== null && _this2$props$theme$ma6 !== void 0 ? _this2$props$theme$ma6 : undefined;
828
- 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;
829
865
  var elevationLayer = new ElevationLayer({
830
866
  name: 'dem',
831
867
  extent: extent,
@@ -840,7 +876,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
840
876
 
841
877
  // Collect baselayers
842
878
  var externalLayers = {};
843
- 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);
844
880
  baseLayers.push({
845
881
  type: "blank",
846
882
  name: "",
@@ -869,14 +905,14 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
869
905
  // Collect color layers
870
906
  var colorLayers = _this2.collectColorLayers([], []);
871
907
  _this2.objectMap = {};
872
- 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 : []);
873
909
  // Convert legacy flat lists to tree
874
- (((_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) {
875
911
  objects.push(_objectSpread(_objectSpread({}, entry), {}, {
876
912
  type: "tiles3d"
877
913
  }));
878
914
  });
879
- (((_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) {
880
916
  objects.push(_objectSpread(_objectSpread({}, entry), {}, {
881
917
  type: "object3d"
882
918
  }));
@@ -905,12 +941,13 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
905
941
  objectTree[groupId].children = _buildObjectTree(entry.items, groupId);
906
942
  nodeIds.push(groupId);
907
943
  } else if (entry.type === "tiles3d") {
908
- var _entry$title, _entry$visibility2;
944
+ var _entry$title, _entry$visibility2, _entry$snap;
909
945
  objectTree[entry.name] = {
910
946
  objectId: entry.name,
911
947
  parent: parentId,
912
948
  title: (_entry$title = entry.title) !== null && _entry$title !== void 0 ? _entry$title : entry.name,
913
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,
914
951
  opacity: 255,
915
952
  styles: entry.styles || {},
916
953
  style: entry.style || Object.keys(entry.styles || {})[0] || null
@@ -927,15 +964,16 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
927
964
  _this2.applySceneObjectState(entry.name, objectTree[entry.name], {}, objectTree);
928
965
  nodeIds.push(entry.name);
929
966
  } else if (entry.type === "object3d") {
930
- var _entry$title2, _entry$visibility3;
967
+ var _entry$title2, _entry$visibility3, _entry$snap2;
931
968
  objectTree[entry.name] = {
932
969
  objectId: entry.name,
933
970
  parent: parentId,
934
971
  title: (_entry$title2 = entry.title) !== null && _entry$title2 !== void 0 ? _entry$title2 : entry.name,
935
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,
936
974
  opacity: 255
937
975
  };
938
- _this2.importObject3D(entry, entry.name, false, {}, false, function () {
976
+ _this2.importObject3D(MiscUtils.resolveAssetsPath(entry.url), entry.name, false, {}, false, function () {
939
977
  _this2.applySceneObjectState(entry.name, objectTree[entry.name], {}, objectTree);
940
978
  });
941
979
  nodeIds.push(entry.name);
@@ -1300,10 +1338,13 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
1300
1338
  }
1301
1339
  });
1302
1340
  _this2.state.sceneContext.restoreView(data);
1303
- var bl3d = (_data$baseLayer = data.baseLayer) !== null && _data$baseLayer !== void 0 ? _data$baseLayer : "";
1304
- _this2.setBaseLayer({
1305
- name: bl3d
1306
- }, bl3d !== "null");
1341
+ if (((_data$baseLayer = data.baseLayer) !== null && _data$baseLayer !== void 0 ? _data$baseLayer : null) !== null) {
1342
+ var _data$baseLayer2;
1343
+ var bl3d = (_data$baseLayer2 = data.baseLayer) !== null && _data$baseLayer2 !== void 0 ? _data$baseLayer2 : "";
1344
+ _this2.setBaseLayer({
1345
+ name: bl3d
1346
+ }, bl3d !== "null");
1347
+ }
1307
1348
  _this2.state.sceneContext.scene.notifyChange();
1308
1349
  });
1309
1350
  _this2.container = null;
@@ -1313,6 +1354,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
1313
1354
  _this2.sceneObjectGroup = null;
1314
1355
  _this2.objectMap = {};
1315
1356
  _this2.tilesetStyles = {};
1357
+ _this2.state.sceneContext.eventDispatcher = new EventDispatcher();
1316
1358
  _this2.state.sceneContext.addLayer = _this2.addLayer;
1317
1359
  _this2.state.sceneContext.getLayer = _this2.getLayer;
1318
1360
  _this2.state.sceneContext.removeLayer = _this2.removeLayer;
@@ -1325,7 +1367,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
1325
1367
  _this2.state.sceneContext.removeSceneObject = _this2.removeSceneObject;
1326
1368
  _this2.state.sceneContext.updateSceneObject = _this2.updateSceneObject;
1327
1369
  _this2.state.sceneContext.zoomToObject = _this2.zoomToObject;
1370
+ _this2.state.sceneContext.objectIsVisible = _this2.objectIsVisible;
1328
1371
  _this2.state.sceneContext.getMap = _this2.getMap;
1372
+ _this2.state.computeBoundsTree = _this2.computeBoundsTree;
1329
1373
  _this2.state.sceneContext.getTerrainHeightFromDTM = _this2.getTerrainHeightFromDTM;
1330
1374
  _this2.state.sceneContext.getTerrainHeightFromMap = _this2.getTerrainHeightFromMap;
1331
1375
  _this2.state.sceneContext.getSceneIntersection = _this2.getSceneIntersection;
@@ -1383,13 +1427,24 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
1383
1427
  this.setState(function (state) {
1384
1428
  return {
1385
1429
  sceneContext: _objectSpread(_objectSpread({}, state.sceneContext), {}, {
1386
- collisionObjects: Object.entries(state.sceneContext.objectTree).reduce(function (res, entry) {
1387
- if (entry.visibility && entry.opacity > 0) {
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) {
1388
1433
  var _obj$tiles$group, _obj$tiles;
1389
- var obj = _this3.objectMap[entry.objectId];
1390
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);
1391
1435
  }
1392
1436
  return res;
1437
+ }, []),
1438
+ snapObjects: Object.entries(state.sceneContext.objectTree).reduce(function (res, _ref12) {
1439
+ var _ref13 = _slicedToArray(_ref12, 2),
1440
+ objectId = _ref13[0],
1441
+ entry = _ref13[1];
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);
1446
+ }
1447
+ return res;
1393
1448
  }, [])
1394
1449
  })
1395
1450
  };
@@ -1428,10 +1483,10 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
1428
1483
  sceneContext: this.state.sceneContext
1429
1484
  }), /*#__PURE__*/React.createElement(ViewSwitcher, {
1430
1485
  position: 1
1431
- }), Object.entries(this.props.plugins3d).map(function (_ref12) {
1432
- var _ref13 = _slicedToArray(_ref12, 2),
1433
- name = _ref13[0],
1434
- Component = _ref13[1];
1486
+ }), Object.entries(this.props.plugins3d).map(function (_ref14) {
1487
+ var _ref15 = _slicedToArray(_ref14, 2),
1488
+ name = _ref15[0],
1489
+ Component = _ref15[1];
1435
1490
  return /*#__PURE__*/React.createElement(Suspense, {
1436
1491
  key: name
1437
1492
  }, /*#__PURE__*/React.createElement(Component, _extends({
@@ -1476,6 +1531,7 @@ _defineProperty(Map3D, "defaultSceneState", {
1476
1531
  colorLayers: {},
1477
1532
  objectTree: {},
1478
1533
  collisionObjects: [],
1534
+ snapObjects: [],
1479
1535
  settings: {
1480
1536
  fov: 30,
1481
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;