UNPKG

awv3

Version:
823 lines (693 loc) 26.6 kB
import _regeneratorRuntime from "@babel/runtime/regenerator"; import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator"; import _extends from "@babel/runtime/helpers/extends"; import _taggedTemplateLiteralLoose from "@babel/runtime/helpers/taggedTemplateLiteralLoose"; import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose"; import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized"; var _templateObject = /*#__PURE__*/ _taggedTemplateLiteralLoose(["connection must be initialized with a session"], ["connection must be initialized with a session"]); import * as THREE from 'three'; import throttle from 'lodash/throttle'; import Lifecycle from './lifecycle.js'; import { arrayDiff, emptyObject, collectNestedIds } from './helpers'; import { actions } from './store/connections'; import { actions as globalActions } from './store/globals'; import { actions as pluginActions, base as pluginBase } from './store/plugins'; import { errUndefined } from '../core/helpers'; import Base from '../communication/base'; /** * @class Connection manages a local or remote connection to a running ClassCAD instances. ClassCAD will then drive the tree-state and cause visual actions, models, meshes, movement, etc. In theory a ClassCAD instance is not needed, results could be fed statically using parse or stream. */ var Connection = /*#__PURE__*/ function (_Lifecycle) { _inheritsLoose(Connection, _Lifecycle); function Connection(session, props) { var _this; if (session === void 0) { session = errUndefined(_templateObject); } _this = _Lifecycle.call(this, session, actions, function (state) { return state.connections[_this.id]; }, _extends({ name: 'Part' }, props, { connected: false, activeFeature: undefined, activeRoot: undefined, defaultFeatureVisibility: false, undo: { count: 0, current: 0 }, messages: [], plugins: [], tree: { '1': { id: 1, name: '', class: '', parent: null, dimensions: [], coordinateSystem: [[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]] }, root: 1 }, managed: false })) || this; Object.defineProperty(_assertThisInitialized(_this), "updateView", { configurable: true, enumerable: true, writable: true, value: throttle(function (_temp) { var _ref = _temp === void 0 ? _this.session.options.updateView : _temp, _ref$focus = _ref.focus, focus = _ref$focus === void 0 ? true : _ref$focus, _ref$zoom = _ref.zoom, zoom = _ref$zoom === void 0 ? true : _ref$zoom, _ref$rotate = _ref.rotate, rotate = _ref$rotate === void 0 ? false : _ref$rotate, _ref$layers = _ref.layers, layers = _ref$layers === void 0 ? false : _ref$layers; _this.pool.viewFound().then(function () { var _this$pool$view$contr; _this.pool.view.updateBounds(); focus && _this.pool.view.controls.focus(); zoom && _this.pool.view.controls.zoom(); rotate && (_this$pool$view$contr = _this.pool.view.controls).rotate.apply(_this$pool$view$contr, rotate); _this.pool.update(); layers && _this.session.showLayer(_this.session.layerNames); _this.session.selector && _this.session.selector.update(); _this.pool.view.invalidate(); _this.pool.view.emit(THREE.Object3D.Events.Lifecycle.Updated); }); }, _this.session.options.throttle) }); window.g_activeConnection = _assertThisInitialized(_this); //TODO: ugly hack. _this.pool = new session.options.pool(_extends({ session: session, name: "connection.pool." + _this.name }, session.options.materials)); _this.primitives = {}; _this.waiting = {}; _this.featurePlugins = {}; _this.sequence = Promise.resolve(); // Observe root _this.observe(function (state) { return state.tree.root; }, function (root, oldRoot) { var old = _this.pool.find(function (item) { var _item$userData; return ((_item$userData = item.userData) === null || _item$userData === void 0 ? void 0 : _item$userData.root) === oldRoot; }); if (old) { old.destroy(); } _this._observeLink(root); }); // Observe active feature _this.observe(function (state) { return state.activeFeature; }, function (feature, oldFeature) { if (oldFeature) { var data = _this.featurePlugins[oldFeature]; if (data) { _this.store.dispatch(pluginActions.update(data.plugin.id, { enabled: false, collapsed: true })); if (!data.pluginPrototype.persistent) { _this._destroyFeatures(oldFeature); } } } if (feature) { var _data = _this.featurePlugins[feature]; if (_data) { if (_data.pluginPrototype.persistent) { _this.store.dispatch(pluginActions.update(_data.plugin.id, { enabled: true, collapsed: false })); _this.activeFeaturePlugin = _data.plugin; } else { _this.activeFeaturePlugin = _this._instanciateFeature(feature); _this.store.dispatch(pluginActions.update(_this.activeFeaturePlugin.id, { enabled: true, collapsed: false })); } } } }); // Connect to server if (_this.session.options.url && _this.session.options.protocol) { _this.connect(_this.session.options.url); } return _this; } var _proto = Connection.prototype; _proto.defer = /*#__PURE__*/ function () { var _defer = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee2(func) { return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: return _context2.abrupt("return", new Promise(function (resolve) { return requestIdleCallback( /*#__PURE__*/ _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee() { return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.t0 = resolve; _context.next = 3; return func(); case 3: _context.t1 = _context.sent; return _context.abrupt("return", (0, _context.t0)(_context.t1)); case 5: case "end": return _context.stop(); } } }, _callee, this); }))); })); case 1: case "end": return _context2.stop(); } } }, _callee2, this); })); return function defer(_x) { return _defer.apply(this, arguments); }; }(); _proto.undo = function undo(factory) { if (factory === void 0) { factory = this.session.options.materials.factory; } return this.store.dispatch(this.actions.request(this.id, undefined, factory, 'undo')); }; _proto.redo = function redo(factory) { if (factory === void 0) { factory = this.session.options.materials.factory; } return this.store.dispatch(this.actions.request(this.id, undefined, factory, 'redo')); }; _proto.request = function request(command, factory) { if (factory === void 0) { factory = this.session.options.materials.factory; } return this.store.dispatch(this.actions.request(this.id, command, factory)); }; _proto.stream = function stream(url, factory) { if (factory === void 0) { factory = this.session.options.materials.factory; } return this.store.dispatch(this.actions.stream(this.id, url, factory)); }; _proto.parse = function parse(blob, factory) { if (factory === void 0) { factory = this.session.options.materials.factory; } return this.store.dispatch(this.actions.parse(this.id, blob, factory)); }; _proto.connect = function connect(url) { return this.store.dispatch(this.actions.connect(this.id, url, this.session.options.protocol)); }; _proto.setTree = function setTree(payload) { this.store.dispatch(actions.destroyTree(this.id)); this.store.dispatch(actions.setTree(this.id, payload)); }; _proto.patchTree = function patchTree(payload) { return this.store.dispatch(this.actions.patchTree(this.id, payload)); }; _proto.removePrimitives = function removePrimitives() { Object.values(this.primitives).forEach(function (item) { return item.destroy(); }); this.primitives = {}; this.updateView(); }; _proto.findSolids = function findSolids(arg) { var _this2 = this; if (typeof arg === 'string') { var primitive = this.primitives[arg]; if (primitive) { return primitive.references; } } else if (typeof arg === 'function') { var key = Object.keys(primitives).find(function (key) { return arg(_this2.primitives[key]); }); if (key) { return this.primitives[key].references; } } }; _proto._observeLink = function _observeLink(id, parent, instance) { var _this3 = this; var tree = this.getState().tree; var object = tree[id]; switch (object.class) { case 'CC_Assembly': var assembly = this._observeAssembly(id, parent, instance); assembly.userData = _extends({}, assembly.userData, { meta: object.meta }); return assembly; case 'CC_Part': case 'CC_SheetPart': var part = this._observePart(id, parent, instance); this.defer(function () { return _this3._observeFeatures(id, part); }); part.userData = _extends({}, part.userData, { meta: object.meta }); return part; } }; _proto._observeAssembly = function _observeAssembly(root, parent, instance) { var _this4 = this; if (parent === void 0) { parent = this.pool; } var instances = {}; var container = new this.session.options.objectPrototype({ session: this.session }); container.name = container.type = 'Assembly'; parent.add(container); var array = collectNestedIds(container).concat([instance || root]); container.userData = { id: instance || root, nestedId: array.join(','), root: root }; this.observe( // selector function (state) { return (state.tree[root] || emptyObject).instances; }, /*#__PURE__*/ // onChange _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee3() { var tree, _len, args, _key, _args3 = arguments; return _regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: tree = _this4.tree; for (_len = _args3.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = _args3[_key]; } _context3.next = 4; return arrayDiff.apply(void 0, args.concat([function (newItems) { return newItems.forEach(function (item) { var instance = tree[item]; var link = undefined; var object = undefined; // Observe changes to it _this4.observe(function (state) { return state.tree[item]; }, function (instance) { // Links should be reactive as well if (instance.link !== link) { if (object) { object.destroy(); delete instances[instance.id]; } object = instances[item] = _this4._observeLink(instance.link, container, item); object.matrixAutoUpdate = false; link = instance.link; } object.userData.name = instance.name; object.name = instance.name; object.visible = typeof instance.visible !== 'undefined' ? instance.visible : true; object.userData = _extends({}, object.userData, { meta: _extends({}, object.userData.meta, instance.meta) }); var csys = instance.coordinateSystem.map(function (entry) { return new (Function.prototype.bind.apply(THREE.Vector3, [null].concat(entry)))(); }); object.matrix = new THREE.Matrix4().makeBasis(csys[1], csys[2], csys[3]).setPosition(csys[0]); _this4.updateView(); //console.log(` moving instance ${instance.name} to ${JSON.stringify(csys[0])}`); }, { fireOnStart: true, unsubscribeOnUndefined: true }); }); }, function (deletedItems) { return deletedItems.forEach(function (item) { var instance = instances[item]; //console.log(` removing instance ${instance.name}`); delete instances[item]; return instance.destroy(); }); }])); case 4: _this4.updateView(); case 5: case "end": return _context3.stop(); } } }, _callee3, this); })), // options { onRemove: function onRemove() { console.log('assembly is gone', container.name); Object.values(instances).forEach(function (item) { return item.destroy(); }); instances = {}; container.destroy(); parent === _this4.pool && _this4.removePrimitives(); }, fireOnStart: true, unsubscribeOnUndefined: true }); return container; }; _proto._observePart = function _observePart(root, parent, instance) { var _this5 = this; if (parent === void 0) { parent = this.pool; } var clones = {}; var container = new this.session.options.objectPrototype({ session: this.session }); container.name = container.type = 'Part'; container.temporary = new THREE.Group(); container.temporary.name = 'Part.temporaray'; container.temporary.updateParentMaterials = false; container.add(container.temporary); parent.add(container); var array = collectNestedIds(container).concat([instance || root]); container.userData = { id: instance || root, nestedId: array.join(','), root: root }; this.observe( // selector function (state) { return (state.tree[root] || emptyObject).solids; }, /*#__PURE__*/ // onChange _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee4() { var part, _len2, args, _key2, _args4 = arguments; return _regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: part = _this5.tree[root]; for (_len2 = _args4.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = _args4[_key2]; } _context4.next = 4; return arrayDiff.apply(void 0, args.concat([function (newItems) { newItems.map(function (item) { var primitive = _this5.primitives[item]; if (!primitive) { // primitive is not yet known // Create bounds representation var mesh; if (part.min && part.max) { var min = part.min; var max = part.max; mesh = new THREE.Mesh(new THREE.BoxBufferGeometry(max[0] - min[0], max[1] - min[1], max[2] - min[2]), new _this5.session.options.meshShader(_extends({ color: new THREE.Color("rgb(" + (part.color ? part.color.join(',') : '190, 190, 190') + ")") }, _this5.session.options.meshShaderOptions))); if (_this5.session.options.materials.shadows) { mesh.castShadow = true; mesh.receiveShadow = true; } mesh.position.set((max[0] + min[0]) / 2, (max[1] + min[1]) / 2, (max[2] + min[2]) / 2); mesh.material.meta = { material: { color: mesh.material.color.clone(), opacity: mesh.material.opacity } }; container.add(mesh.fadeIn({ opacity: 0 })); } // If none exists, create empty waiting list entry from item if (!_this5.waiting[item]) _this5.waiting[item] = []; // Register item on the waiting-list _this5.waiting[item].push(function (primitive) { // Delete bounds mesh && mesh.destroy(); // Create real clone, finally _this5._createClone({ root: root, parent: parent, clones: clones, container: container, primitive: primitive, item: item }); }); } else _this5._createClone({ root: root, parent: parent, clones: clones, container: container, primitive: primitive, item: item }); }); _this5.updateView(); }, function (deletedItems) { return deletedItems.map(function (item) { var clone = clones[item]; // Remove clone from primitives var primitive = _this5.primitives[item]; if (primitive) primitive.references.splice(primitive.references.indexOf(clone), 1); delete clones[item]; return clone.destroy(); }); }])); case 4: case "end": return _context4.stop(); } } }, _callee4, this); })), // options { onRemove: function onRemove() { console.log('part is gone', container.name); Object.values(clones).forEach(function (item) { return item.destroy(); }); clones = {}; container.destroy(); parent === _this5.pool && _this5.removePrimitives(); }, fireOnStart: true, unsubscribeOnUndefined: true }); return container; }; _proto._instanciateFeature = function _instanciateFeature(id, props) { var _featurePlugins$id = this.featurePlugins[id], parent = _featurePlugins$id.parent, feature = _featurePlugins$id.feature, persistent = _featurePlugins$id.persistent, pluginPrototype = _featurePlugins$id.pluginPrototype; // If activeSelection is on we must reset it !persistent && this.session.globals.activeSelection && this.store.dispatch(globalActions.setActiveSelection()); // Each plugin gets a distinct pool to draw into var pool = new THREE.Group(); pool.name = 'Instance'; pool.updateParentMaterials = false; pool.measurable = pluginPrototype.measurable; pool.name = feature.name; parent.add(pool); // Intanciate and link new plugin var plugin = new pluginPrototype(this.session, _extends({ name: feature.name, feature: feature, pool: pool, connection: this }, props)); // Link plugins this.featurePlugins[id].plugin = plugin; this.store.dispatch(actions.linkPlugins(this.id, plugin.id)); return plugin; }; _proto._mapFeatures = function _mapFeatures(parent) { for (var _len3 = arguments.length, features = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { features[_key3 - 1] = arguments[_key3]; } for (var _i = 0; _i < features.length; _i++) { var id = features[_i]; var feature = this.tree[id]; var type = feature.class; var pluginPrototype = this.session.featurePlugins[type]; if (!pluginPrototype && this.session.defaultFeaturePlugin) pluginPrototype = this.session.defaultFeaturePlugin; if (pluginPrototype) { // Skip if already present if (this.featurePlugins[id]) continue; // Map feature plugin this.featurePlugins[id] = { feature: feature, parent: parent.temporary, pluginPrototype: pluginPrototype, persistent: pluginPrototype.persistent }; if (pluginPrototype.persistent) { // Return persistent plugins this._instanciateFeature(id); } } } }; _proto._unmapFeatures = function _unmapFeatures() { var _this6 = this; for (var _len4 = arguments.length, features = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { features[_key4] = arguments[_key4]; } this._destroyFeatures(features); features.forEach(function (id) { return delete _this6.featurePlugins[id]; }); }; _proto._destroyFeatures = function _destroyFeatures() { var _this7 = this; for (var _len5 = arguments.length, features = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { features[_key5] = arguments[_key5]; } var plugins = features.map(function (id) { return _this7.featurePlugins[id]; }).filter(function (data) { return data && data.plugin; }).map(function (data) { return data.plugin.id; }); if (plugins.length > 0) { this.store.dispatch(actions.unlinkPlugins(this.id, plugins)); } features.forEach(function (id) { // Find real plugin class var _ref5 = _this7.featurePlugins[id] || {}, plugin = _ref5.plugin, parent = _ref5.parent, persistent = _ref5.persistent; if (plugin) { if (!persistent) { delete _this7.featurePlugins[id].plugin; } parent.remove(plugin.pool); _this7.defer(function () { return _this7.store.dispatch(pluginActions.unregister(plugin.id)); }); } }); }; _proto._observeFeatures = function _observeFeatures(root, parent) { var _this8 = this; if (parent === void 0) { parent = this.pool; } //console.log("observeFeatures...") return this.observe( // selector function (state) { return (state.tree[root] || emptyObject).features; }, // onChange function () { for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { args[_key6] = arguments[_key6]; } arrayDiff.apply(void 0, args.concat([function (newItems) { return _this8._mapFeatures.apply(_this8, [parent].concat(newItems)); }, function (deletedItems) { return _this8._unmapFeatures.apply(_this8, deletedItems); }])); }, // options { fireOnStart: true, unsubscribeOnUndefined: true }); }; _proto.__onDestroyed = function __onDestroyed() { var _this9 = this; Object.values(this.primitives).forEach(function (item) { return item.destroy(); }); this.primitives = {}; Object.values(this.session.plugins).forEach(function (plugin) { return plugin.connection === _this9.id && _this9.store.dispatch(pluginActions.unregister(plugin.id)); }); if (this.session.globals.activeConnection === this.id) { this.session.dispatch(globalActions.setActiveConnection()); } this.socket && this.socket.disconnect(); }; _proto._createClone = function _createClone(_ref6) { var root = _ref6.root, parent = _ref6.parent, clones = _ref6.clones, container = _ref6.container, primitive = _ref6.primitive, item = _ref6.item; var clone = undefined; if (this.session.options.clone) { (function () { clone = clones[item] = primitive.clone(); var array = collectNestedIds(container).concat([item]); clone.userData.nestedId = array.join(','); // deep clone materials; for (var _iterator = clone.children.keys(), _isArray = Array.isArray(_iterator), _i2 = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { var _ref7; if (_isArray) { if (_i2 >= _iterator.length) break; _ref7 = _iterator[_i2++]; } else { _i2 = _iterator.next(); if (_i2.done) break; _ref7 = _i2.value; } var _child = _ref7; var c = clone.children[_child]; var p = primitive.children[_child]; if (c.material) { var isMultiMaterial = Array.isArray(c.material); if (isMultiMaterial) { c.material = p.material.map(function (pMaterial) { var cMaterial = pMaterial.clone(true); cMaterial.meta = _extends({}, pMaterial.meta, { nestedId: array.concat([pMaterial.meta.id]).join(',') }); return cMaterial; }); } else { c.material = p.material.clone(true); c.material.meta = _extends({}, p.material.meta); } } } })(); } else { clone = clones[item] = primitive; } primitive.references.push(clone); return container.add(clone.fadeIn({ opacity: 0 })); }; return Connection; }(Lifecycle(Base, false)); export { Connection as default };