UNPKG

awv3

Version:
302 lines (256 loc) 15.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 _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray'); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _class, _temp; var _highlevel = require('./command/highlevel'); var _lowlevel = require('./command/lowlevel'); var _type = require('./constraint/type'); var Constraints = _interopRequireWildcard(_type); var _geomutils = require('./geomutils'); 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 FilletProcessor = (_temp = _class = function () { function FilletProcessor(sketch) { (0, _classCallCheck3.default)(this, FilletProcessor); this.sketch = sketch; } // check if the given position is at the angle that can be filleted // return full information about the angle or null (0, _createClass3.default)(FilletProcessor, [{ key: 'recognizeFilletableAngle', value: function recognizeFilletableAngle(pos) { // find exactly matching points - children of lines var samePoints = this.findPointsAt(pos); // exactly two curves must end at pos if (samePoints.length !== 2) return null; //both of them must be lines var lines = samePoints.map(function (pnt) { return pnt.parent; }); if (!lines.every(function (ln) { return ln && ln.isLine(); })) return null; // these two points must be marked as incident var incidenceConstr = this.findConstraints(Constraints.incidence.type, samePoints[0], samePoints[1]); if (incidenceConstr.length !== 1) return null; // check that parent lines are not collinear var dirA = (0, _geomutils.getTangent)(lines[0].geomParams), dirB = (0, _geomutils.getTangent)(lines[1].geomParams); if (Math.abs(dirA.cross(dirB).z) <= FilletProcessor.angularTolerance) return null; // find outer endpoints of the lines var lineEnds = []; for (var i = 0; i < 2; i++) { var vertexAtStart = lines[i].startPoint.id === samePoints[i].id; lineEnds[i] = vertexAtStart ? lines[i].endPoint : lines[i].startPoint; } //return all the found data return { lines: lines, lineStarts: samePoints, lineEnds: lineEnds, incidence: incidenceConstr[0], control: pos }; } // checks if the given arc is a part of a correct fillet // return full information about the fillet or null }, { key: 'recognizeFilletByArcOrEdge', value: function recognizeFilletByArcOrEdge(obj) { var res = { obj: obj, objEnds: [], lines: [], lineStarts: [], lineEnds: [], vertex: null }; var lineDirs = []; var _arr = [obj.startPoint, obj.endPoint]; for (var _i = 0; _i < _arr.length; _i++) { var objEnd = _arr[_i]; // find incident line var samePoints = this.findPointsAt(objEnd.pos); samePoints = samePoints.filter(function (point) { return point.parent.id !== obj.id && point.parent.state.class === 'CC_Line'; }); if (samePoints.length !== 1) return null; var lineStart = samePoints[0]; var line = lineStart.parent; var lineEnd = line.startPoint.id === lineStart.id ? line.endPoint : line.startPoint; // check that all constraints are in objEnd if (this.findConstraints(Constraints.incidence.type, objEnd, lineStart).length !== 1) return null; if (obj.state.class === 'CC_Arc' && this.findConstraints(Constraints.tangency.type, obj, line).length !== 1) return null; // check that a line is tangent at a common point var lineDir = lineEnd.pos.sub(lineStart.pos).normalize(); if (obj.state.class === 'CC_Arc') { var arcDir = (0, _geomutils.getTangent)(obj.geomParams, objEnd.pos); if (objEnd.state.name === 'startPoint') arcDir.negate(); if (lineDir.distanceTo(arcDir) > FilletProcessor.angularTolerance) return null; } // save found objects res.objEnds.push(objEnd); res.lines.push(line); res.lineStarts.push(lineStart); res.lineEnds.push(lineEnd); lineDirs.push(lineDir); } // check that the fillet angle is in range (0; pi) if (obj.state.class === 'CC_Arc' && Math.abs(obj.state.members.bulge.value) >= 1.0) return null; //arc's angle > pi var angle = lineDirs[0].angleTo(lineDirs[1]); if (angle <= FilletProcessor.angularTolerance || angle >= Math.PI - FilletProcessor.angularTolerance) return null; // calculate the location of the fillet's vertex var vertexPos = (0, _geomutils.intersectLines)(res.lineStarts[0].pos, lineDirs[0], res.lineStarts[1].pos, lineDirs[1], FilletProcessor.angularTolerance); if (!vertexPos) return null; // check for a point there var vertices = this.findPointsAt(vertexPos); if (vertices.length !== 1) return null; res.vertex = vertices[0]; res.control = res.vertex.pos; // check incidence of the vertex to lines for (var i = 0; i < 2; ++i) { if (this.findConstraints(Constraints.incidence.type, res.vertex, res.lines[i]).length !== 1) return null; }return res; } }, { key: 'getAngle', value: function getAngle(info) { var dirs = []; for (var i = 0; i < 2; i++) { dirs[i] = info.lineEnds[i].pos.sub(info.lineStarts[i].pos).normalize(); }return dirs[0].angleTo(dirs[1]); } }, { key: 'offsetToRadius', value: function offsetToRadius(info, offset) { var angle = this.getAngle(info); return offset * Math.tan(angle / 2); } }, { key: 'radiusToOffset', value: function radiusToOffset(info, radius) { var angle = this.getAngle(info); return radius / Math.tan(angle / 2); } // calculate the filleting arc params (center, touch points) by specified radius }, { key: 'calculateFilletParams', value: function calculateFilletParams(info, options) { var touch = this.getTouchPoints(info, options.radius, options.offset); if (!touch) return null; return (0, _extends3.default)({}, (0, _geomutils.drawArcBy_S_E_CP)([].concat((0, _toConsumableArray3.default)(touch), [info.control]), {}), { control: info.control }); } }, { key: 'calculateChamferParams', value: function calculateChamferParams(info, options) { var touch = this.getTouchPoints(info, options.radius, options.offset); if (!touch) return null; return { start: touch[0], end: touch[1], control: info.control }; } }, { key: 'findPointsAt', value: function findPointsAt(pos) { var samePoints = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = (0, _getIterator3.default)(this.sketch.descendants), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var obj = _step.value; if (obj.state.class === 'CC_Point' && obj.pos.distanceTo(pos) <= FilletProcessor.linearTolerance) samePoints.push(obj); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return samePoints; } }, { key: 'findConstraints', value: function findConstraints(type, objA, objB) { return this.sketch.children.filter(function (constr) { return constr.state.class === type && (constr.entities[0].id === objA.id && constr.entities[1].id === objB.id || constr.entities[0].id === objB.id && constr.entities[1].id === objA.id); }); } }, { key: 'getTouchPoints', value: function getTouchPoints(info, radius, distance) { var vertexPos = info.control; var dirs = [], maxDists = []; for (var i = 0; i < 2; i++) { var dir = info.lineEnds[i].pos.sub(info.lineStarts[i].pos).normalize(); var maxDist = info.lineEnds[i].pos.distanceTo(vertexPos); dirs.push(dir); maxDists.push(maxDist); } var angle = dirs[0].angleTo(dirs[1]); var dist = distance !== undefined ? distance : radius / Math.tan(angle / 2); if (dist + FilletProcessor.linearTolerance >= Math.min(maxDists[0], maxDists[1])) return null; // too large fillet return dirs.map(function (dir) { return dir.clone().multiplyScalar(dist).add(vertexPos); }); } }, { key: 'createNewFilletStatement', value: function createNewFilletStatement(info, params) { var vertex = (0, _lowlevel.Variable)(), curve = (0, _lowlevel.Variable)(); return _lowlevel.Sequence.apply(undefined, (0, _toConsumableArray3.default)((0, _highlevel.removeCommands)(this.sketch, info.incidence)).concat([(0, _highlevel.updateCommand)(this.sketch, info.lineStarts[0], { start: params.start }), (0, _highlevel.updateCommand)(this.sketch, info.lineStarts[1], { start: params.end }), (0, _lowlevel.Assign)(vertex, (0, _highlevel.addCommand)(this.sketch, { start: info.control })), (0, _lowlevel.Assign)(curve, (0, _highlevel.addCommand)(this.sketch, params)), (0, _lowlevel.ReplaceEntityInConstraints)(this.sketch, undefined, info.lineStarts[0], vertex), (0, _lowlevel.ReplaceEntityInConstraints)(this.sketch, undefined, info.lineStarts[1], vertex), (0, _highlevel.addCommand)(this.sketch, { class: Constraints.incidence.type, entities: [info.lines[0], vertex], value: {} }), (0, _highlevel.addCommand)(this.sketch, { class: Constraints.incidence.type, entities: [info.lines[1], vertex], value: {} }), (0, _highlevel.addCommand)(this.sketch, { class: Constraints.incidence.type, entities: [info.lineStarts[0], (0, _lowlevel.Member)(curve, 'startPoint')], value: {} }), (0, _highlevel.addCommand)(this.sketch, { class: Constraints.incidence.type, entities: [info.lineStarts[1], (0, _lowlevel.Member)(curve, 'endPoint')], value: {} }), (0, _highlevel.addCommand)(this.sketch, { class: Constraints.tangency.type, entities: [info.lines[0], curve], value: {} }), (0, _highlevel.addCommand)(this.sketch, { class: Constraints.tangency.type, entities: [info.lines[1], curve], value: {} }), (0, _highlevel.addCommand)(this.sketch, { class: Constraints.radius.type, entities: [curve], value: {} })])); } }, { key: 'deleteFilletStatement', value: function deleteFilletStatement(info) { var constraints = (0, _from2.default)(this.sketch.descendants).filter(function (obj) { return obj.isConstraint(); }); //note: when moving constraints from fillet's vertex to the resulting angle's vertex, //ignore everything that involves removed geometry, filleting lines and their closer endpoints //the ignored constraints would be removed automatically var blacklist = [].concat((0, _toConsumableArray3.default)(info.lines), (0, _toConsumableArray3.default)(info.lineStarts), [info.obj, info.obj.startPoint, info.obj.endPoint, info.obj.center]); var involves = function involves(constr, obj) { return constr.entities.some(function (e) { return e.id === obj.id; }); }; constraints = constraints.filter(function (constr) { return !blacklist.some(function (t) { return involves(constr, t); }); }); return _lowlevel.Sequence.apply(undefined, (0, _toConsumableArray3.default)((0, _highlevel.removeCommands)(this.sketch, info.obj)).concat([(0, _lowlevel.ReplaceEntityInConstraints)(this.sketch, constraints, info.vertex, info.lineStarts[0])], (0, _toConsumableArray3.default)((0, _highlevel.removeCommands)(this.sketch, info.vertex)), [(0, _highlevel.updateCommand)(this.sketch, info.lineStarts[0], { start: info.vertex.pos }), (0, _highlevel.updateCommand)(this.sketch, info.lineStarts[1], { start: info.vertex.pos }), (0, _highlevel.addCommand)(this.sketch, { class: Constraints.incidence.type, entities: [info.lineStarts[0], info.lineStarts[1]], value: {} })])); } }, { key: 'updateFilletStatement', value: function updateFilletStatement(info, params) { return (0, _lowlevel.Sequence)((0, _highlevel.updateCommand)(this.sketch, info.lineStarts[0], { start: params.start }), (0, _highlevel.updateCommand)(this.sketch, info.lineStarts[1], { start: params.end }), (0, _highlevel.updateCommand)(this.sketch, info.obj, params)); } }]); return FilletProcessor; }(), _class.linearTolerance = 1e-3, _class.angularTolerance = 1e-3, _temp); exports.default = FilletProcessor;