UNPKG

qwc2

Version:
428 lines (425 loc) 23.5 kB
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /** * Copyright 2024 Sourcepole AG * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import { Group, Plane, Raycaster, Vector2, Vector3 } from 'three'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader'; import { setCurrentTask } from '../../actions/task'; import Icon from '../../components/Icon'; import MessageBar from '../../components/MessageBar'; import SideBar from '../../components/SideBar'; import NumberInput from '../../components/widgets/NumberInput'; import arrowModel from '../../resources/arrow.glb'; import LocaleUtils from '../../utils/LocaleUtils'; import './style/Compare3D.css'; /** * Split-screen and compare objects in the 3D map. */ var Compare3D = /*#__PURE__*/function (_React$Component) { function Compare3D() { var _this; _classCallCheck(this, Compare3D); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _callSuper(this, Compare3D, [].concat(args)); _defineProperty(_this, "state", { enabled: false, clippedObjects: {}, planeX: 0, planeY: 0, planeA: 0 }); _defineProperty(_this, "updateClippingPlane", function () { var point = new Vector3(_this.state.planeX, _this.state.planeY, 0); var alpha = _this.state.planeA / 180 * Math.PI; var normal = new Vector3(Math.sin(alpha), Math.cos(alpha), 0); var leftPlane = new Plane(); var rightPlane = new Plane(); leftPlane.setFromNormalAndCoplanarPoint(normal, point); rightPlane.setFromNormalAndCoplanarPoint(normal.multiplyScalar(-1), point); Object.entries(_this.state.clippedObjects).forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), objectId = _ref2[0], config = _ref2[1]; var planes = []; if (config.left) { planes.push(leftPlane); } if (config.right) { planes.push(rightPlane); } if (objectId === "__terrain") { _this.props.sceneContext.map.clippingPlanes = planes; } else { var object = _this.props.sceneContext.getSceneObject(objectId); object.clippingPlanes = planes; object.traverse(function (child) { if (child.material) { child.material.clippingPlanes = planes; child.material.clipShadows = true; } }); } }); _this.props.sceneContext.scene.notifyChange(); _this.positionArrows(_this.state.planeX, _this.state.planeY, _this.state.planeA); }); _defineProperty(_this, "clearClippingPlane", function () { Object.keys(_this.state.clippedObjects).forEach(function (objectId) { if (objectId === "__terrain") { _this.props.sceneContext.map.clippingPlanes = []; } else { var object = _this.props.sceneContext.getSceneObject(objectId); object.clippingPlanes = []; object.traverse(function (child) { if (child.material) { child.material.clippingPlanes = []; child.material.clipShadows = false; } }); } }); if (_this.props.active) { _this.disableArrows(); } _this.props.sceneContext.scene.notifyChange(); }); _defineProperty(_this, "enableArrows", function () { _this.props.sceneContext.addSceneObject("__compareArrows", _this.arrows); _this.props.sceneContext.scene.view.controls.addEventListener('change', _this.centerArrowsInView); var renderer = _this.props.sceneContext.scene.renderer; renderer.domElement.addEventListener("pointerdown", _this.dragArrows); _this.centerArrowsInView(); }); _defineProperty(_this, "disableArrows", function () { var _this$props$sceneCont, _this$props$sceneCont2; (_this$props$sceneCont = _this.props.sceneContext.scene.view.controls) === null || _this$props$sceneCont === void 0 || (_this$props$sceneCont2 = _this$props$sceneCont.removeEventListener) === null || _this$props$sceneCont2 === void 0 || _this$props$sceneCont2.call(_this$props$sceneCont, 'change', _this.centerArrowsInView); _this.props.sceneContext.removeSceneObject("__compareArrows"); _this.props.sceneContext.scene.renderer.domElement.removeEventListener("pointerdown", _this.dragArrows); }); _defineProperty(_this, "dragArrows", function (ev) { var mousePos = function mousePos(event) { var rect = event.target.getBoundingClientRect(); var x = (event.clientX - rect.left) / rect.width * 2 - 1; var y = -((event.clientY - rect.top) / rect.height) * 2 + 1; return new Vector2(x, y); }; var camera = _this.props.sceneContext.scene.view.camera; var raycaster = new Raycaster(); raycaster.setFromCamera(mousePos(ev), camera); var intersects = raycaster.intersectObject(_this.arrows).length > 0; if (!intersects) { return; } var plane = new Plane().setFromNormalAndCoplanarPoint(new Vector3(0, 0, 1), _this.arrows.position); var startPos = raycaster.ray.intersectPlane(plane, new Vector3()); var planePos = new Vector2(_this.state.planeX, _this.state.planeY); var alpha = _this.state.planeA / 180 * Math.PI; var planeNormal = new Vector3(Math.sin(alpha), Math.cos(alpha), 0); var moveArrows = function moveArrows(event) { raycaster.setFromCamera(mousePos(event), camera); plane.setFromNormalAndCoplanarPoint(new Vector3(0, 0, 1), _this.arrows.position); var pos = raycaster.ray.intersectPlane(plane, new Vector3()); var delta = planeNormal.clone().multiplyScalar(new Vector3().copy(pos.sub(startPos)).dot(planeNormal)); _this.setState({ planeX: planePos.x + delta.x, planeY: planePos.y + delta.y }); _this.positionArrows(planePos.x + delta.x, planePos.y + delta.y, _this.state.planeA); }; _this.props.sceneContext.scene.view.controls.enabled = false; ev.view.addEventListener("pointermove", moveArrows); ev.view.addEventListener("pointerup", function () { _this.props.sceneContext.scene.view.controls.enabled = true; ev.view.removeEventListener("pointermove", moveArrows); }, { once: true }); }); _defineProperty(_this, "centerArrowsInView", function () { var _inter$point; var inter = _this.props.sceneContext.getSceneIntersection(0, 0); var center = (_inter$point = inter === null || inter === void 0 ? void 0 : inter.point) !== null && _inter$point !== void 0 ? _inter$point : _this.props.sceneContext.scene.view.controls.target.clone(); var alpha = _this.state.planeA / 180 * Math.PI; var dir = new Vector3(Math.cos(alpha), -Math.sin(alpha), 0); var curPos = new Vector3(_this.state.planeX, _this.state.planeY, 0); var newPos = curPos.add(dir.multiplyScalar(center.sub(curPos).dot(dir))); _this.setState({ planeX: newPos.x, planeY: newPos.y }); _this.positionArrows(newPos.x, newPos.y, _this.state.planeA); }); _defineProperty(_this, "positionArrows", function (x, y, alpha) { var _this$props$sceneCont3; var target = new Vector3(x, y, 0); var distance = _this.props.sceneContext.scene.view.camera.position.distanceTo(target); var scale = Math.max(1, distance / 200); var z = (_this$props$sceneCont3 = _this.props.sceneContext.getTerrainHeightFromMap([x, y])) !== null && _this$props$sceneCont3 !== void 0 ? _this$props$sceneCont3 : 0; _this.arrows.position.x = target.x; _this.arrows.position.y = target.y; _this.arrows.position.z = z; _this.arrows.rotation.z = -alpha / 180 * Math.PI; _this.arrows.scale.set(scale, scale, scale); _this.arrows.updateMatrixWorld(); }); _defineProperty(_this, "renderBody", function () { var sceneContext = _this.props.sceneContext; var objects = _objectSpread({ __terrain: { layertree: true, title: LocaleUtils.tr("map3d.terrain") } }, sceneContext.sceneObjects); var objectIds = Object.keys(objects).filter(function (objectId) { return objects[objectId].layertree; }); return /*#__PURE__*/React.createElement("div", { className: "compare3d-body", role: "body" }, /*#__PURE__*/React.createElement("div", { className: "compare3d-title", onClick: _this.toggleCompare }, /*#__PURE__*/React.createElement(Icon, { icon: _this.state.enabled ? "checked" : "unchecked" }), /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("compare3d.compare_objects"))), /*#__PURE__*/React.createElement("div", { className: "compare3d-objects" }, ["left", "right"].map(function (section) { var clipState = _this.state.clippedObjects; var toggleAllIcon = "checked"; var toggleAllValue = true; var toggleAllState = objectIds.reduce(function (res, id) { var _clipState$id; return res + ((_clipState$id = clipState[id]) === null || _clipState$id === void 0 ? void 0 : _clipState$id[section]); }, 0); if (toggleAllState === objectIds.length) { toggleAllIcon = "unchecked"; toggleAllValue = false; } else if (toggleAllState > 0) { toggleAllIcon = "tristate"; } return /*#__PURE__*/React.createElement("div", { className: "compare3d-section", key: "compare-" + section }, /*#__PURE__*/React.createElement("div", { className: "compare3d-item compare3d-item-toggleall", onClick: _this.state.enabled ? function () { return _this.toggleAllObjects(section, objectIds, toggleAllValue); } : null, title: LocaleUtils.tr("compare3d.toggleall") }, /*#__PURE__*/React.createElement(Icon, { className: "compare3d-item-checkbox", disabled: !_this.state.enabled, icon: toggleAllIcon }), /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("compare3d.toggleall"))), objectIds.map(function (objectId) { var _objects$objectId$tit, _clipState$objectId, _objects$objectId$tit2; return /*#__PURE__*/React.createElement("div", { className: "compare3d-item", key: objectId, onClick: _this.state.enabled ? function () { return _this.toggleObject(section, objectId); } : null, title: (_objects$objectId$tit = objects[objectId].title) !== null && _objects$objectId$tit !== void 0 ? _objects$objectId$tit : objectId }, /*#__PURE__*/React.createElement(Icon, { className: "compare3d-item-checkbox", disabled: !_this.state.enabled, icon: (_clipState$objectId = clipState[objectId]) !== null && _clipState$objectId !== void 0 && _clipState$objectId[section] ? "unchecked" : "checked" }), /*#__PURE__*/React.createElement("span", null, (_objects$objectId$tit2 = objects[objectId].title) !== null && _objects$objectId$tit2 !== void 0 ? _objects$objectId$tit2 : objectId)); })); })), /*#__PURE__*/React.createElement("div", { className: "compare3d-title" }, LocaleUtils.tr("compare3d.clipplane")), /*#__PURE__*/React.createElement("table", { className: "compare3d-planeconfig" }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "x"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(NumberInput, { disabled: !_this.state.enabled, onChange: function onChange(x) { return _this.setState({ planeX: x }); }, value: _this.state.planeX }))), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "y"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(NumberInput, { disabled: !_this.state.enabled, onChange: function onChange(y) { return _this.setState({ planeY: y }); }, value: _this.state.planeY }))), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, "\u03B1"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(NumberInput, { disabled: !_this.state.enabled, onChange: function onChange(a) { return _this.setState({ planeA: a }); }, suffix: "\xB0", value: _this.state.planeA })))))); }); _defineProperty(_this, "toggleCompare", function () { _this.setState(function (state) { var newState = { enabled: !state.enabled }; if (newState.enabled) { // Position plane in current view newState.planeX = _this.props.sceneContext.scene.view.controls.target.x; newState.planeY = _this.props.sceneContext.scene.view.controls.target.y; newState.planeA = -_this.props.sceneContext.scene.view.controls.getAzimuthalAngle() / Math.PI * 180 + 90; } return newState; }); }); _defineProperty(_this, "toggleObject", function (section, objectId) { _this.setState(function (state) { var _state$clippedObjects; return { clippedObjects: _objectSpread(_objectSpread({}, state.clippedObjects), {}, _defineProperty({}, objectId, _objectSpread(_objectSpread({}, state.clippedObjects[objectId]), {}, _defineProperty({}, section, !((_state$clippedObjects = state.clippedObjects[objectId]) !== null && _state$clippedObjects !== void 0 && _state$clippedObjects[section]))))) }; }); }); _defineProperty(_this, "toggleAllObjects", function (section, objectIds, value) { _this.setState(function (state) { return { clippedObjects: objectIds.reduce(function (res, objectId) { return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, objectId, _objectSpread(_objectSpread({}, state.clippedObjects[objectId]), {}, _defineProperty({}, section, value)))); }, {}) }; }); }); return _this; } _inherits(Compare3D, _React$Component); return _createClass(Compare3D, [{ key: "componentDidMount", value: function componentDidMount() { var _this2 = this; var loader = new GLTFLoader(); loader.load(arrowModel, function (gltf) { gltf.scene.traverse(function (object) { if (object.isMesh) { object.material.depthTest = false; // Ignores depth buffer object.material.depthWrite = false; // Prevents modifying depth buffer } }); gltf.scene.renderOrder = 9999999; // Ensures it is rendered last var leftArrow = gltf.scene.clone(); leftArrow.position.y = -4; leftArrow.rotation.z = -0.5 * Math.PI; var rightArrow = gltf.scene.clone(); rightArrow.position.y = 4; rightArrow.rotation.z = 0.5 * Math.PI; _this2.arrows = new Group(); _this2.arrows.add(leftArrow); _this2.arrows.add(rightArrow); }); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.clearClippingPlane(); if (this.arrows) { this.arrows.traverse(function (obj) { var _obj$dispose; return (_obj$dispose = obj.dispose) === null || _obj$dispose === void 0 ? void 0 : _obj$dispose.call(obj); }); } } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps, prevState) { if (this.state.enabled && this.props.active && !prevProps.active) { this.enableArrows(); } else if (this.state.enabled && !this.props.active && prevProps.active) { this.disableArrows(); } if (this.state.enabled && this.state !== prevState) { if (this.props.active && !prevState.enabled) { this.enableArrows(); } // Recompute clipping plane this.updateClippingPlane(); } else if (!this.state.enabled && prevState.enabled) { this.clearClippingPlane(); } if (this.props.sceneContext.sceneObjects !== prevProps.sceneContext.sceneObjects) { var sceneObjects = this.props.sceneContext.sceneObjects; this.setState(function (state) { return { clippedObjects: Object.fromEntries(Object.entries(state.clippedObjects).filter(function (_ref3) { var _ref4 = _slicedToArray(_ref3, 2), objectId = _ref4[0], entry = _ref4[1]; return objectId in sceneObjects; })) }; }); } } }, { key: "render", value: function render() { var _this3 = this; return [/*#__PURE__*/React.createElement(SideBar, { icon: "layers", id: "Compare3D", key: "SideBar", title: LocaleUtils.tr("appmenu.items.Compare3D"), width: "20em" }, function () { return { body: _this3.renderBody() }; }), this.state.enabled ? /*#__PURE__*/React.createElement(MessageBar, null, /*#__PURE__*/React.createElement("div", { role: "body" }, LocaleUtils.tr("compare3d.info_message"), "\xA0", /*#__PURE__*/React.createElement("button", { className: "button", onClick: function onClick() { return _this3.props.setCurrentTask("Compare3D"); } }, LocaleUtils.tr("compare3d.modify")))) : null]; } }]); }(React.Component); _defineProperty(Compare3D, "propTypes", { active: PropTypes.bool, sceneContext: PropTypes.object, setCurrentTask: PropTypes.func }); export default connect(function (state) { return { active: state.task.id === "Compare3D" }; }, { setCurrentTask: setCurrentTask })(Compare3D);