UNPKG

awv3

Version:
518 lines (438 loc) 20.2 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = undefined; var _from = require('babel-runtime/core-js/array/from'); var _from2 = _interopRequireDefault(_from); var _getIterator2 = require('babel-runtime/core-js/get-iterator'); var _getIterator3 = _interopRequireDefault(_getIterator2); var _map = require('babel-runtime/core-js/map'); var _map2 = _interopRequireDefault(_map); var _set = require('babel-runtime/core-js/set'); var _set2 = _interopRequireDefault(_set); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _freeze = require('babel-runtime/core-js/object/freeze'); var _freeze2 = _interopRequireDefault(_freeze); var _three = require('three'); var THREE = _interopRequireWildcard(_three); var _object = require('../../../three/object3'); var _object2 = _interopRequireDefault(_object); var _ccref = require('../ccref'); var _ccref2 = _interopRequireDefault(_ccref); var _geomutils = require('../geomutils'); var _constraint = require('../graphics/constraint'); var _constraint2 = _interopRequireDefault(_constraint); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var Mode = (0, _freeze2.default)({ Never: 0, Hover: 1, Always: 2 }); function uniNorm2(vec) { return Math.max(Math.abs(vec.x), Math.abs(vec.y)); } function sqr(x) { return x * x; } var Visualizer = function () { function Visualizer(sketcher, textures) { (0, _classCallCheck3.default)(this, Visualizer); this.mode = Mode.Hover; this.sketcher = sketcher; // Set of constraint ids to avoid iterating and filtering sketch.children this.constraints = new _set2.default(); // Reverse mapping from entities to constraints this.entityFor = new _map2.default(); // For each constraint, its based entity is stored (where icon is rendered) this.baseEntityFor = new _map2.default(); // If set to true, constraints would be repositioned next frame this.graphicsDirty = false; } (0, _createClass3.default)(Visualizer, [{ key: 'refresh', value: function refresh() { this.graphicsDirty = true; this.sketcher.refresh(); } }, { key: 'isSelected', value: function isSelected(id) { return this.sketcher.selector.getSelectedIds().indexOf(id) !== -1; } }, { key: 'setVisibility', value: function setVisibility(id) { var newValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; if (newValue === undefined) newValue = this.mode === Mode.Always; //note: we forbid hiding selected constraints if (!newValue && this.isSelected(id)) return; new _ccref2.default(this.sketcher, id).graphics.visible = newValue; } }, { key: 'addConstraint', value: function addConstraint(constraint) { if (!(constraint.graphics instanceof _constraint2.default)) return; this.constraints.add(constraint.id); this.baseEntityFor.set(constraint.id, undefined); var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = (0, _getIterator3.default)(constraint.entities), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var entity = _step.value; if (!this.entityFor.has(entity.id)) this.entityFor.set(entity.id, []); this.entityFor.get(entity.id).push(constraint.id); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } this.setVisibility(constraint.id); this.refresh(); } }, { key: 'removeConstraint', value: function removeConstraint(constraint) { var state = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : constraint.state; if (!(constraint.graphics instanceof _constraint2.default)) return; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = (0, _getIterator3.default)(state.members.entities.members), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var _ref2 = _step2.value; var id = _ref2.value; var constraints = this.entityFor.get(id); constraints.splice(constraints.indexOf(constraint.id), 1); if (constraints.length === 0) this.entityFor.delete(id); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } this.constraints.delete(constraint.id); this.baseEntityFor.delete(constraint.id); this.refresh(); } //note: must be called if constraint has changed }, { key: 'updateConstraint', value: function updateConstraint(constraint) { this.refresh(); } //note: must be called if entity of constraint has changed }, { key: 'updateEntity', value: function updateEntity(entity) { if (!this.entityFor.has(entity.id)) return; this.refresh(); } }, { key: 'hover', value: function hover(entity, first) { if (this.mode !== Mode.Hover) return; if (entity.isConstraint()) return; if (first) this.unhoverAll(); var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = (0, _getIterator3.default)(this.entityFor.get(entity.id) || []), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var id = _step3.value; this.setVisibility(id, true); if (!this.isSelected(id)) this.baseEntityFor.set(id, entity.id); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } this.refresh(); } }, { key: 'unhover', value: function unhover(entity, first) { if (this.mode !== Mode.Hover) return; if (entity.isConstraint()) return; // do nothing } }, { key: 'unhoverAll', value: function unhoverAll() { if (this.mode !== Mode.Hover) return; var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = (0, _getIterator3.default)(this.constraints.keys()), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var id = _step4.value; this.setVisibility(id, false); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } this.refresh(); } //called when constraint visualizer mode changes + on init }, { key: 'updateAll', value: function updateAll() { var mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.mode; this.mode = mode; var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = (0, _getIterator3.default)(this.constraints.keys()), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var id = _step5.value; this.setVisibility(id); } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } this.refresh(); } //note: called before each frame is rendered //sets proper positions for all constraint graphics }, { key: 'render', value: function render() { var _this = this; if (!this.graphicsDirty) return; this.graphicsDirty = false; var iconSize = 3 * this.sketcher.graphicScale; //determine for each base entity the array of all constraints drawn near it var perEntityLists = new _map2.default(); var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for (var _iterator6 = (0, _getIterator3.default)(this.constraints.keys()), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { var conId = _step6.value; var constr = new _ccref2.default(this.sketcher, conId); if (!constr.graphics.visible) continue; var baseId = this.getBaseEntityId(conId); if (!perEntityLists.has(baseId)) perEntityLists.set(baseId, []); perEntityLists.get(baseId).push(conId); } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } if (perEntityLists.size === 0) return; //create rectangle filled with constraints icons for each base entity var rectangles = (0, _from2.default)(perEntityLists.keys()).map(function (id) { return { id: id, keyPos: _this.getKeyPosition(id), cnt: perEntityLists.get(id).length }; }); //sort base entities (for stability) rectangles.sort(function (a, b) { return a.id - b.id; }); //minimal distance between rectangles (in iconSize units) var colEps = 0.5; //minimal vertical distance from key position to rectangle's center (in iconSize units) var minOffsetH = 0.75; //set positions for all entity lists (each one is rectangle) for (var i = 0; i < rectangles.length; i++) { var newRect = rectangles[i]; //position of rectangle center, which is closest to key point var bestDistSqr = 1e+50; var bestX = void 0, bestY = void 0; rectanglePlaceLoop: for (var vk = 0;; vk++) { for (var vs = 1; vs >= -1; vs -= 2) { //try to put into the vertical slice: var cy = newRect.keyPos.y + vs * (minOffsetH + vk * (1 + colEps)) * iconSize; //loop termination criterion if (sqr(cy - newRect.keyPos.y) >= bestDistSqr) break rectanglePlaceLoop; //try both direction for horizontal moving for (var hs = 1; hs >= -1; hs -= 2) { var cx = newRect.keyPos.x; do { var moved = false; for (var j = 0; j < i; j++) { var obstRect = rectangles[j]; //check if rectangles collide if (Math.abs(cy - obstRect.ctrPos.y) >= (1 + colEps) * iconSize - 1e-9) continue; if (Math.abs(cx - obstRect.ctrPos.x) >= ((newRect.cnt + obstRect.cnt) * 0.5 + colEps) * iconSize - 1e-9) continue; //do minimal horizontal movement which avoids collision var newSide = cx + hs * iconSize * newRect.cnt * 0.5; var obstSide = obstRect.ctrPos.x - hs * iconSize * obstRect.cnt * 0.5; var diff = newSide - obstSide + hs * colEps * iconSize; cx += diff; moved = true; } //note: if something has moved, then we have to recheck everything for collisions } while (moved); var distSqr = sqr(cx - newRect.keyPos.x) + sqr(cy - newRect.keyPos.y); if (bestDistSqr > distSqr) { bestDistSqr = distSqr; bestX = cx;bestY = cy; } //early cutoff: if no horizontal movement happened if (cx === newRect.keyPos.x) break rectanglePlaceLoop; } } } //place rectangle into found position (not changed later) newRect.ctrPos = new THREE.Vector3(bestX, bestY, 0.0); } //set positions for all constraint icons var _iteratorNormalCompletion7 = true; var _didIteratorError7 = false; var _iteratorError7 = undefined; try { for (var _iterator7 = (0, _getIterator3.default)(rectangles), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { var _ref4 = _step7.value; var id = _ref4.id, ctrPos = _ref4.ctrPos, cnt = _ref4.cnt; var conList = perEntityLists.get(id); //sort constraint lists (for stability) conList.sort(function (a, b) { return a - b; }); for (var _i = 0; _i < cnt; _i++) { var pos = ctrPos.clone().add(new THREE.Vector3(_i - 0.5 * (cnt - 1), 0, 0).multiplyScalar(iconSize)); var _conId = conList[_i]; var _constr = new _ccref2.default(this.sketcher, _conId); _constr.graphics.localMesh.position.copy(pos); _constr.graphics.localMesh.scale.set(iconSize, iconSize, 1); } } } catch (err) { _didIteratorError7 = true; _iteratorError7 = err; } finally { try { if (!_iteratorNormalCompletion7 && _iterator7.return) { _iterator7.return(); } } finally { if (_didIteratorError7) { throw _iteratorError7; } } } } }, { key: 'getKeyPosition', value: function getKeyPosition(entity) { if (typeof entity === "number") entity = new _ccref2.default(this.sketcher, entity); var gp = entity.geomParams; switch (entity.class) { case 'CC_Point': return gp.start.clone(); case 'CC_Line': return new THREE.Vector3().lerpVectors(gp.start, gp.end, 0.5); case 'CC_Arc': return (0, _geomutils.getArcAngles)(gp).mid.clone(); case 'CC_Circle': return new THREE.Vector3(0.6, 0.8).multiplyScalar(gp.radius).add(gp.center); default: return new THREE.Vector3(0, 0, 0); } } }, { key: 'getBaseEntityId', value: function getBaseEntityId(constraint) { if (typeof constraint === "number") constraint = new _ccref2.default(this.sketcher, constraint); var res = this.baseEntityFor.get(constraint.id); if (res !== undefined) return res; var _iteratorNormalCompletion8 = true; var _didIteratorError8 = false; var _iteratorError8 = undefined; try { for (var _iterator8 = (0, _getIterator3.default)(constraint.entities), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) { var entity = _step8.value; if (['CC_Point', 'CC_Line', 'CC_Arc', 'CC_Circle'].indexOf(entity.class) !== -1) return entity.id; } } catch (err) { _didIteratorError8 = true; _iteratorError8 = err; } finally { try { if (!_iteratorNormalCompletion8 && _iterator8.return) { _iterator8.return(); } } finally { if (_didIteratorError8) { throw _iteratorError8; } } } return constraint.entities[0].id; } }]); return Visualizer; }(); exports.default = Visualizer;