UNPKG

awv3

Version:
870 lines (716 loc) 31.9 kB
import _extends from "@babel/runtime/helpers/extends"; import _createClass from "@babel/runtime/helpers/createClass"; import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose"; import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized"; var _class, _temp, _initialiseProps; import * as THREE from 'three'; import uniq from 'lodash/uniq'; import merge from 'lodash/merge'; import isEqual from 'lodash/isEqual'; import Events from '../core/events'; import Region from '../three/region'; import Hud from '../core/hud'; import CombinedCamera from '../three/combinedcamera'; var HOVERED = THREE.Object3D.Events.Interaction.Hovered; var UNHOVERED = THREE.Object3D.Events.Interaction.Unhovered; var CLICKED = THREE.Object3D.Events.Interaction.Clicked; var MISSED = THREE.Object3D.Events.Interaction.Missed; var PICKED = THREE.Object3D.Events.Interaction.Picked; var DROPPED = THREE.Object3D.Events.Interaction.Dropped; var DRAGGED = THREE.Object3D.Events.Interaction.Dragged; var RENDERED = THREE.Object3D.Events.Lifecycle.Rendered; var EPSILON = 1e-4; var Selector = (_temp = _class = /*#__PURE__*/ function (_Events) { _inheritsLoose(Selector, _Events); function Selector(session, options) { var _this; _this = _Events.call(this) || this; _initialiseProps.call(_assertThisInitialized(_this)); _this.session = session; _this.last = undefined; _this.map = new Map(); _this.selected = new Map(); _this.options = _extends({ ids: [], target: session.pool, limit: Infinity, types: ['Mesh'], whitelist: ['Region'], pierce: ['Assembly', 'Part', 'Model', 'Workplane'], properties: session.globals.selection, shift: true, duration: 0, recursive: true, first: true, selectObjects: false, priority: 0, createInteraction: true }, options); // Allow undefined target, this will keep selector from creating a interaction-handler if (!_this.options.target) _this.options.target = new THREE.Object3D(); var _this$options = _this.options, ids = _this$options.ids, pierce = _this$options.pierce, types = _this$options.types, recursive = _this$options.recursive, whitelist = _this$options.whitelist, target = _this$options.target, first = _this$options.first, priority = _this$options.priority, limit = _this$options.limit, shift = _this$options.shift, createInteraction = _this$options.createInteraction, selectObjects = _this$options.selectObjects, duration = _this$options.duration; // Save original target _this.originalTarget = target; // Find object.type grouping interfaces that aren't real THREE types (f.i. Assembly, Part, etc.) _this.interfaceSelectors = types.filter(function (t) { return whitelist.indexOf(t) == -1 && (!THREE[t] || !new THREE[t]().material); }); _this.basicSelectors = _this.options.basic || types.filter(function (t) { return _this.interfaceSelectors.indexOf(t) === -1; }); target.viewFound().then(function (view) { var _target$createInterac; _this.view = view; _this.regions = []; if (types.indexOf('Region') >= 0) { // Only activate reagions when the selectors explicitely asks for it target.traverse(function (child) { return child.type === 'Region' && _this.regions.push(child); }); _this.regions.forEach(function (region) { return region.visible = true; }); } if (createInteraction) target.createInteraction({ pierce: pierce, types: types, recursive: recursive, first: first, priority: priority }).on((_target$createInterac = {}, _target$createInterac[HOVERED] = _this.hovered, _target$createInterac[UNHOVERED] = _this.unhovered, _target$createInterac[CLICKED] = _this.clicked, _target$createInterac[MISSED] = _this.missed, _target$createInterac[RENDERED] = _this.rendered, _target$createInterac[PICKED] = function () { var _this2; for (var _len = arguments.length, props = new Array(_len), _key = 0; _key < _len; _key++) { props[_key] = arguments[_key]; } return (_this2 = _this).emit.apply(_this2, [PICKED].concat(props)); }, _target$createInterac[DRAGGED] = function () { var _this3; for (var _len2 = arguments.length, props = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { props[_key2] = arguments[_key2]; } return (_this3 = _this).emit.apply(_this3, [DRAGGED].concat(props)); }, _target$createInterac[DROPPED] = function () { var _this4; for (var _len3 = arguments.length, props = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { props[_key3] = arguments[_key3]; } return (_this4 = _this).emit.apply(_this4, [DROPPED].concat(props)); }, _target$createInterac)); // Pre-select objects from ids if (ids.length > 0) { _this.buildSelected(ids).selectAll(); } var oldState = _this.selectedIds; _this.update(); _this.on(['add', 'remove', 'removeAll'], function () { var state = _this.selectedIds; !isEqual(state, oldState) && _this.emit('changed', state, oldState); oldState = state; }); if (shift) { // SHIFT KEY selection handler _this.shiftHandler = function (event) { var candidates = [], oldIds = []; if (!_this.shiftHandler.handled && event.keyCode === 16) { _this.shiftHandler.handled = true; _this.view.input.debounce = false; _this.view.controls.enabled = false; _this.view.interaction.enabled = false; target.traverseMaterials(function (material, object) { if (object.visible && (object.type === 'RegionPoint' || object.interactive) && material.meta && material.visible) { // project bounding box to view coordinates object.updateMatrixWorld(true); //TODO: get and project all 8 points and not only min and max var minPt, maxPt; if (!material.meta.box) { !object.geometry.boundingBox && object.geometry.computeBoundingBox(); minPt = object.geometry.boundingBox.min.clone(); maxPt = object.geometry.boundingBox.max.clone(); } else { minPt = material.meta.box.min.clone(); maxPt = material.meta.box.max.clone(); } // project to view coordinates var p1 = _this.view.getPoint2(minPt); var p2 = _this.view.getPoint2(maxPt); // bounding box in 2D var bounds = new THREE.Box2(); bounds.setFromPoints([p1, p2]); candidates.push({ object: object, material: material, bounds: bounds }); } }); // init new heads up display, add it to the view _this.hud = new Hud(_this.view); _this.view.addHud(_this.hud); _this.hud.controls = undefined; _this.hud.camera = new CombinedCamera({ near: _this.view.camera.near, far: _this.view.camera.far, fov: _this.view.camera.fov }); _this.view.measure(true); var geom = new THREE.PlaneGeometry(0.001, 0.001); var box = new THREE.Mesh(geom, new THREE.MeshBasicMaterial({ transparent: true, opacity: 0.05, color: new THREE.Color(0) })); _this.hud.scene.add(box); // set up mouse action's handler var clickDown, mousePos, rubberBandLine, clickHud; var handler = function handler(event) { switch (event.type) { case 'mousedown': clickDown = new THREE.Vector2(event.offsetX, event.offsetY); mousePos = new THREE.Vector2(event.offsetX + 1, event.offsetY + 1); clickHud = _this.view.getPoint3({ x: event.offsetX, y: event.offsetY }, _this.hud.camera.display, 0); box.position.copy(clickHud); break; case 'mousemove': if (!clickDown) { return; } // update rectangle var tempPoint = _this.view.getPoint3({ x: event.offsetX, y: event.offsetY }, _this.hud.camera.display, 0); var delta = tempPoint.sub(clickHud); var width = Math.abs(delta.x); var height = Math.abs(delta.y); var halfHeight = height / 2; var halfWidth = width / 2; var halfDeltaX = delta.x / 2; var halfDeltaY = delta.y / 2; geom.vertices[0].set(-halfWidth + halfDeltaX, halfHeight + halfDeltaY, 0); geom.vertices[1].set(width - halfWidth + halfDeltaX, halfHeight + halfDeltaY, 0); geom.vertices[2].set(-halfWidth + halfDeltaX, -(height - halfHeight) + halfDeltaY, 0); geom.vertices[3].set(width - halfWidth + halfDeltaX, -(height - halfHeight) + halfDeltaY, 0); geom.verticesNeedUpdate = true; mousePos = new THREE.Vector2(event.offsetX, event.offsetY); // check intersection with rectangle in display-coordinates var rubberBandRectangle = new THREE.Box2(); rubberBandRectangle.setFromPoints([clickDown, mousePos]); var _ids = [], id = 0; for (var _i = 0; _i < candidates.length; _i++) { var sel = candidates[_i]; id = _this.getHitId(sel); if (_ids.indexOf(id) === -1 && rubberBandRectangle.containsBox(sel.bounds)) { _ids.push(id); if (_ids.length >= limit) break; } } if (!isEqual(_ids, oldIds)) { oldIds = _ids; _this.unselectAll().buildSelected(_ids).selectAll(); } _this.view.invalidate(); break; case 'mouseup': box && box.destroy(); clickDown = undefined; if (rubberBandLine !== undefined) { _this.view.scene.remove(rubberBandLine); rubberBandLine = undefined; } break; } }; _this.view.input.on(['mousedown', 'mousemove', 'mouseup'], handler); _this.tempHandler = function () { // remove and destroy heads up display _this.view.removeHud(_this.hud); _this.hud.destroy(); _this.shiftHandler.handled = false; _this.view.input.removeListener(['mousedown', 'mousemove', 'mouseup'], handler); document.removeEventListener('keyup', _this.tempHandler); _this.view.input.debounce = true; _this.view.controls.enabled = true; _this.view.interaction.enabled = true; }; document.addEventListener('keyup', _this.tempHandler); } }; _this.shiftHandler.handled = false; document.addEventListener('keydown', _this.shiftHandler); } }); return _this; } var _proto = Selector.prototype; _proto.destroy = function destroy() { this.tempHandler && this.tempHandler(); this.tempHandler = undefined; this.shiftHandler && document.removeEventListener('keydown', this.shiftHandler); this.shiftHandler = undefined; this.regions && this.regions.forEach(function (region) { return region.visible = false; }); this.unselectAll().removeAll(false); this.emit('destroy'); this.removeListeners(); this.options.target.removeInteraction(); this.session = undefined; this.last = undefined; this.selected = undefined; this.options = undefined; this.interfaceSelectors = undefined; }; // Creates the internal map (this.selected) from an array of string id's _proto.buildSelected = function buildSelected(ids) { var _this5 = this; var _options = this.options, target = _options.target, properties = _options.properties, types = _options.types, selectObjects = _options.selectObjects; this.selected.clear(); if (!ids.length) this.removeAll(); if (selectObjects) { ids.forEach(function (id) { var object = target.find(function (object) { var _ref, _object$userData$pare, _object$userData, _object$userData2; return ((_ref = (_object$userData$pare = (_object$userData = object.userData) === null || _object$userData === void 0 ? void 0 : _object$userData.parentId) !== null && _object$userData$pare !== void 0 ? _object$userData$pare : (_object$userData2 = object.userData) === null || _object$userData2 === void 0 ? void 0 : _object$userData2.id) !== null && _ref !== void 0 ? _ref : object.id) === id; }); if (object) { var _id = _this5.getHitId({ object: object }); object.traverse(function (child) { return child.material && types.indexOf(child.type) !== -1 && child.mapMaterial(function (childMat) { if (!childMat.meta) return; var previous = _this5.selected.get(_id); _this5.add(_id, { targets: uniq((previous ? previous.targets : []).concat([target])), object: object }); }); }); } }); } else { ids.forEach(function (id) { var hit = target.findMaterial(function (material) { var _material$meta$nested, _material$meta, _material$meta2; return ((_material$meta$nested = material === null || material === void 0 ? void 0 : (_material$meta = material.meta) === null || _material$meta === void 0 ? void 0 : _material$meta.nestedId) !== null && _material$meta$nested !== void 0 ? _material$meta$nested : material === null || material === void 0 ? void 0 : (_material$meta2 = material.meta) === null || _material$meta2 === void 0 ? void 0 : _material$meta2.id) === id; }); if (hit) { var object = hit.object, material = hit.material; if (_this5.interfaceSelectors.length) { _this5.interfaceSelectors.forEach(function (selector) { var target = object.findReverse(function (parent) { return parent.type === selector; }); target && target.traverse(function (child) { return child.material && types.indexOf(child.type) !== -1 && child.mapMaterial(function (childMat) { if (!childMat.meta) return; var previous = _this5.selected.get(childMat.meta.id); if (childMat === material) { _this5.add(material.meta.id, { targets: uniq((previous ? previous.targets : []).concat([target])), object: object, material: material }); } }); }); }); } else if (properties[object.type]) { var _id2 = _this5.getHitId(hit); _this5.add(_id2, { object: object, material: material }); } } }); } return this; }; _proto.target = function target(where) { if (where === void 0) { where = this.originalTarget; } this.options.target = where; return this; }; // Visually selects all items in this.selected _proto.selectAll = function selectAll() { var _this6 = this; var _options2 = this.options, duration = _options2.duration, properties = _options2.properties, types = _options2.types; this.selected.forEach(function (_ref2) { var targets = _ref2.targets, object = _ref2.object, material = _ref2.material; if (material === undefined) { object.traverse(function (child) { return child.material && types.indexOf(child.type) !== -1 && child.animate(child.mapMaterial(function (childMat) { var _properties$object$ty; if (!childMat.meta) return; return childMat.meta.clicked = _extends({}, childMat.meta.clicked, (_properties$object$ty = properties[object.type]) === null || _properties$object$ty === void 0 ? void 0 : _properties$object$ty[CLICKED]); })).start(duration); }); } else if (targets) { targets.forEach(function (target) { return target.traverse(function (child) { child.material && types.indexOf(child.type) !== -1 && child.animate(child.mapMaterial(function (childMat) { var _properties; if (!childMat.meta) return; var clicked = childMat === material || _this6.selected.has(childMat.meta.id); return childMat.meta.clicked = _extends({}, childMat.meta.clicked, (_properties = properties[clicked ? object.type : target.type]) === null || _properties === void 0 ? void 0 : _properties[CLICKED]); })).start(duration); }); }); } else { var _properties$object$ty2; material.meta && material.animate(material.meta.clicked = (_properties$object$ty2 = properties[object.type]) === null || _properties$object$ty2 === void 0 ? void 0 : _properties$object$ty2[CLICKED]).start(duration); } }); this.emit('selectAll'); return this; }; // Visually unselects all objects _proto.unselectAll = function unselectAll() { var _this7 = this; var _options3 = this.options, target = _options3.target, duration = _options3.duration; if (this.interfaceSelectors.length) Array.from(this.map).map(function (_ref3) { var child = _ref3[0]; return child; }).forEach(this._unselectChild);else { target.traverse(this._unselectChild); // Sketcher didn't contains dimensions, // so if target === sketcher, we have to unselect dimensions directly this.selected.forEach(function (el) { if (!el.material || !el.material.meta || !el.object) return; _this7._unselectChild({ material: el.material, mapMaterial: el.object.mapMaterial.bind(el.object), animate: el.object.animate.bind(el.object) }); }); } this.emit('unselectAll'); return this; }; _proto.getHitId = function getHitId(_ref4) { var _ref5, _object$userData$pare2, _object$userData3, _object$userData4, _material$meta$nested2, _material$meta3, _material$meta4; var object = _ref4.object, material = _ref4.material; return this.options.selectObjects ? (_ref5 = (_object$userData$pare2 = (_object$userData3 = object.userData) === null || _object$userData3 === void 0 ? void 0 : _object$userData3.parentId) !== null && _object$userData$pare2 !== void 0 ? _object$userData$pare2 : (_object$userData4 = object.userData) === null || _object$userData4 === void 0 ? void 0 : _object$userData4.id) !== null && _ref5 !== void 0 ? _ref5 : object.id : (_material$meta$nested2 = material === null || material === void 0 ? void 0 : (_material$meta3 = material.meta) === null || _material$meta3 === void 0 ? void 0 : _material$meta3.nestedId) !== null && _material$meta$nested2 !== void 0 ? _material$meta$nested2 : material === null || material === void 0 ? void 0 : (_material$meta4 = material.meta) === null || _material$meta4 === void 0 ? void 0 : _material$meta4.id; }; // Adds selection to the logical map (this.selected) _proto.add = function add(id, props, notify) { if (notify === void 0) { notify = true; } this.selected.set(id, props); this.last = id; notify && this.emit('add', id, props); this.handleCenterPointSelection(props); return this; }; // Removes selection from the logical map (this.selected) _proto.remove = function remove(id, notify) { if (notify === void 0) { notify = true; } this.selected.delete(id); notify && this.emit('remove', id); return this; }; // Removes all selections from the logical map (this.selected) _proto.removeAll = function removeAll(notify) { if (notify === void 0) { notify = true; } this.selected.clear(); notify && this.emit('removeAll'); return this; }; _proto.calculateLinePrecision = function calculateLinePrecision() { var _options4 = this.options, target = _options4.target, types = _options4.types; if (this.view && types.indexOf('LineSegments') !== -1 && target.scene.bounds.sphere) { var center = this.view.getPoint2(target.scene.bounds.sphere.center.clone()); var screenPoint1 = new THREE.Vector3(0, 0, center.z); var screenPoint2 = new THREE.Vector3(0, 0, center.z); screenPoint2.x = 2; var worldPoint1 = this.view.getPoint3(screenPoint1, this.view.camera, screenPoint1.z); var worldPoint2 = this.view.getPoint3(screenPoint2, this.view.camera, screenPoint2.z); this.view.interaction.raycaster.linePrecision = worldPoint1.sub(worldPoint2).length(); } return this; }; _proto.update = function update() { var _this8 = this; var _options5 = this.options, target = _options5.target, shift = _options5.shift; if (this.interfaceSelectors.length) target.traverse(function (object) { if (object.visible && object.interactive && object.material && _this8.basicSelectors.indexOf(object.type) !== -1) { var parents = _this8.interfaceSelectors.map(function (sel) { return object.findReverse(function (p) { return p.type === sel; }); }); _this8.map.set(object, [object].concat(parents).filter(function (a) { return a; })); } }); return this; }; _createClass(Selector, [{ key: "selectedIds", get: function get() { return this.selected ? Array.from(this.selected).map(function (_ref6) { var id = _ref6[0], props = _ref6[1]; return id; }) : []; } }, { key: "selectedMaterials", get: function get() { return this.selected ? Array.from(this.selected).map(function (_ref7) { var id = _ref7[0], material = _ref7[1].material; return material; }) : []; } }, { key: "selectedObjects", get: function get() { return this.selected ? Array.from(this.selected).map(function (_ref8) { var id = _ref8[0], object = _ref8[1].object; return object; }) : []; } }, { key: "selectedItems", get: function get() { return this.selected ? Array.from(this.selected).map(function (_ref9) { var id = _ref9[0], item = _ref9[1]; return item; }) : []; } }]); return Selector; }(Events), _initialiseProps = function _initialiseProps() { var _this9 = this; Object.defineProperty(this, "_unselectChild", { configurable: true, enumerable: true, writable: true, value: function value(child) { return child.material && child.animate(child.mapMaterial(function (material) { return material.meta && (material.meta.clicked = undefined); })).start(_this9.options.duration); } }); Object.defineProperty(this, "hovered", { configurable: true, enumerable: true, writable: true, value: function value(_ref10) { var _properties$object$ty3; var object = _ref10.object, material = _ref10.material; var _this9$options = _this9.options, target = _this9$options.target, properties = _this9$options.properties, duration = _this9$options.duration; if (_this9.interfaceSelectors.length) Array.from(_this9.map).forEach(function (_ref11) { var child = _ref11[0], interfaces = _ref11[1]; var props = interfaces.reduce(function (prev, selector) { var parent = object.findReverse(function (parent) { return parent === selector; }); var result = merge(prev, child.mapMaterial(function (cM) { var _properties2; return parent && cM.meta ? _extends({}, (_properties2 = properties[cM === material ? child.type : selector.type]) === null || _properties2 === void 0 ? void 0 : _properties2[HOVERED]) : null; })); return result; }, {}); child.animate(props).start(duration); });else material.meta && material.animate((_properties$object$ty3 = properties[object.type]) === null || _properties$object$ty3 === void 0 ? void 0 : _properties$object$ty3[HOVERED]).start(0); _this9.emit(HOVERED, { object: object, material: material }); return _this9; } }); Object.defineProperty(this, "unhovered", { configurable: true, enumerable: true, writable: true, value: function value(_ref12) { var object = _ref12.object, material = _ref12.material; var _this9$options2 = _this9.options, target = _this9$options2.target, duration = _this9$options2.duration; if (_this9.interfaceSelectors.length) Array.from(_this9.map).forEach(function (_ref13) { var child = _ref13[0], interfaces = _ref13[1]; var props = child.mapMaterial(function (childMat) { return childMat.meta && childMat.meta.clicked; }); child.animate(props).start(duration); });else material.meta && material.animate(_extends({}, material.meta.material, material.meta.clicked)).start(duration); _this9.emit(UNHOVERED, { object: object, material: material }); return _this9; } }); Object.defineProperty(this, "clicked", { configurable: true, enumerable: true, writable: true, value: function value(props) { var object = props.object, material = props.material; var _this9$options3 = _this9.options, limit = _this9$options3.limit, properties = _this9$options3.properties, types = _this9$options3.types, duration = _this9$options3.duration, selectObjects = _this9$options3.selectObjects; var id = _this9.getHitId(props); // material.meta.id //Some objects shouldn't be highlighted, so check .meta in material before ("none-selectable" objects have material without .meta). if (material.meta && _this9.selected.has(id)) return _this9.unselectAll().remove(id).selectAll(); if (_this9.selected.size >= limit) _this9.unselectAll().remove(_this9.last).selectAll(); if (_this9.interfaceSelectors.length) { Array.from(_this9.map).forEach(function (_ref14, index) { var child = _ref14[0], interfaces = _ref14[1]; var props = interfaces.reduce(function (prev, selector) { var objectParent = object.findReverse(function (parent) { return parent === selector; }); var next = child.mapMaterial(function (childMat) { var _properties3; if (!objectParent || !childMat.meta) return null; var previous = _this9.selected.get(childMat.meta.id); var clicked = childMat === material || previous !== undefined; if (childMat === material) { _this9.add(id, { targets: uniq((previous ? previous.targets : []).concat([selector])), object: object, material: material }); } return childMat.meta.clicked = _extends({}, childMat.meta.clicked, (_properties3 = properties[clicked ? child.type : selector.type]) === null || _properties3 === void 0 ? void 0 : _properties3[CLICKED]); }); return merge(prev, next); }, {}); child.animate(props).start(duration); }); } else if (material.meta && properties[object.type]) { var _properties$object$ty4; _this9.add(id, { object: object, material: material }); material.animate(material.meta.clicked = (_properties$object$ty4 = properties[object.type]) === null || _properties$object$ty4 === void 0 ? void 0 : _properties$object$ty4[CLICKED]).start(duration); } _this9.emit(CLICKED, { object: object, material: material }); return _this9; } }); Object.defineProperty(this, "missed", { configurable: true, enumerable: true, writable: true, value: function value() { if (_this9.selectedIds.length === 0) return _this9; //avoid traversing whole scene per each object with missed callback _this9.unselectAll().removeAll(); _this9.emit(MISSED); return _this9; } }); Object.defineProperty(this, "rendered", { configurable: true, enumerable: true, writable: true, value: function value() { _this9.calculateLinePrecision(); _this9.emit(RENDERED); return _this9; } }); Object.defineProperty(this, "handleCenterPointSelection", { configurable: true, enumerable: true, writable: true, value: function value(_ref15) { var _material$meta5; var object = _ref15.object, material = _ref15.material; switch (material === null || material === void 0 ? void 0 : (_material$meta5 = material.meta) === null || _material$meta5 === void 0 ? void 0 : _material$meta5.type) { // find (or create) a center point inside region when a circle/arc is selected and make it visible case 'circle': case 'arc': var cPos = material.meta.center; _this9.regions.forEach(function (region) { region.points.forEach(function (point, index) { if (region.parent === object.parent) { var _pos = point.meta.position; if (Math.abs(cPos.x - _pos.x) < EPSILON && Math.abs(cPos.y - _pos.y) < EPSILON && Math.abs(cPos.z - _pos.z) < EPSILON) { if (!point.meta.ref) { region.createPoint(point); } point.meta.ref.material.animate({ opacity: 0.3 }).start(0); } } }); }); break; // unselect all circle/arc when a center point is selected case 'point': var pos = material.meta.position; _this9.selected.forEach(function (_ref16) { var object = _ref16.object, material = _ref16.material; if (['circle', 'arc'].includes(material.meta.type)) { var _cPos = material.meta.center; if (Math.abs(_cPos.x - pos.x) < EPSILON && Math.abs(_cPos.y - pos.y) < EPSILON && Math.abs(_cPos.z - pos.z) < EPSILON) { var id = _this9.getHitId({ object: object, material: material }); _this9.unselectAll().remove(id).selectAll(); } } }); break; } } }); }, _temp); export { Selector as default };