awv3
Version:
⚡ AWV3 embedded CAD
518 lines (438 loc) • 20.2 kB
JavaScript
'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;