awv3
Version:
⚡ AWV3 embedded CAD
302 lines (256 loc) • 15.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 _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;