awv3
Version:
⚡ AWV3 embedded CAD
335 lines (292 loc) • 13.5 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _assign = require('babel-runtime/core-js/object/assign');
var _assign2 = _interopRequireDefault(_assign);
exports.drawArcBy_S_T_E = drawArcBy_S_T_E;
exports.drawArcBy_S_E_Ch = drawArcBy_S_E_Ch;
exports.drawArcBy_S_E_CPh = drawArcBy_S_E_CPh;
exports.drawArcBy_S_E_M = drawArcBy_S_E_M;
exports.drawArcBy_Angle_M = drawArcBy_Angle_M;
exports.drawLineBy_Angle_M = drawLineBy_Angle_M;
exports.getArcAngles = getArcAngles;
exports.intersectLines = intersectLines;
exports.getTangent = getTangent;
exports.move = move;
var _three = require('three');
var THREE = _interopRequireWildcard(_three);
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 }; }
function cross2d(a, b) {
return a.x * b.y - a.y * b.x;
}
function drawArcBy_S_T_E(startPos, startTangent, endPos) {
//should we create a line or an arc
var dir = endPos.clone().sub(startPos);
var onLine = startPos.clone().add(dir.clone().projectOnVector(startTangent));
var height = onLine.distanceTo(endPos);
var isLinear = height <= dir.length() * 1e-3 + 1e-3;
if (isLinear) return { start: startPos, end: endPos };else {
//the ugly math of getting center point and orientation
var normal = endPos.clone().sub(onLine).normalize();
var dist = endPos.distanceToSquared(startPos) / (2 * height);
var cross = cross2d(normal, startTangent);
var ctr = normal.clone().multiplyScalar(dist).add(startPos);
return { start: startPos, end: endPos, center: ctr, clockwise: cross > 0.0 };
}
}
//Note: position of center is only partly used and may change
function drawArcBy_S_E_Ch(startPos, endPos, centerPosHint, takeLarger) {
var mid = endPos.clone().add(startPos).divideScalar(2);
var dir = endPos.clone().sub(startPos);
var per = new THREE.Vector3(-dir.y, dir.x, 0.0);
var dirMidPos = centerPosHint.clone().sub(mid);
var ctr = dirMidPos.clone().projectOnVector(per).add(mid);
var dot = dirMidPos.dot(per);
var clockwise = dot < 0.0 != !!takeLarger;
return { start: startPos, end: endPos, center: ctr, clockwise: clockwise };
}
//Note: position of control point is only partly used and may change
function drawArcBy_S_E_CPh(startPos, endPos, controlPointHint) {
var mid = endPos.clone().add(startPos).divideScalar(2);
var dir = endPos.clone().sub(startPos);
var per = new THREE.Vector3(-dir.y, dir.x, 0.0);
var dirMidPos = controlPointHint.clone().sub(mid);
var dirMidCtrl = dirMidPos.clone().projectOnVector(per);
var height = dirMidCtrl.length();
if (height <= 1e-3) return { start: startPos, end: endPos };
var halfDist = dir.length() / 2.0;
var coeff = -(halfDist * halfDist) / (height * height);
var ctr = dirMidCtrl.clone().multiplyScalar(coeff).add(mid);
var dot = dirMidPos.dot(per);
var clockwise = dot > 0.0;
return { start: startPos, end: endPos, center: ctr, clockwise: clockwise };
}
//Note: middle point should be within circlewith diameter [SE], otherwise it would be corrected
function drawArcBy_S_E_M(startPos, endPos, middlePos) {
//since vector math is a huge pain in JS, we do it in a stupid way
var lSE = startPos.distanceTo(endPos);
var lSM = startPos.distanceTo(middlePos);
var lEM = endPos.distanceTo(middlePos);
var sArea = cross2d(endPos.clone().sub(startPos), middlePos.clone().sub(startPos)) / 2.0;
var area = Math.abs(sArea);
if (area <= 1e-3 * lSE + 1e-3) return { start: startPos, end: endPos };
//getting radius with school math
var radius = lSE * lSM * lEM / (4.0 * area);
radius = Math.max(radius, (0.5 + 1e-9) * lSE);
var height = Math.sqrt(radius * radius - lSE * lSE / 4.0);
//copy-pasting middle perpendicular
var mid = endPos.clone().add(startPos).divideScalar(2);
var dir = endPos.clone().sub(startPos);
var per = new THREE.Vector3(-dir.y, dir.x, 0.0).normalize();
//getting center (choose best of two cases)
var ctr,
dist = 1e+50;
for (var i = 0; i < 2; i++) {
var tCtr = per.clone().multiplyScalar(height * (i ? 1 : -1)).add(mid);
var tDist = Math.abs(tCtr.distanceTo(middlePos) - radius);
if (dist > tDist) {
dist = tDist;
ctr = tCtr;
}
}
//get polar angles of all points
var getAngle = function getAngle(pos) {
var dir = pos.clone().sub(ctr);
return Math.atan2(dir.y, dir.x);
};
var startAng = getAngle(startPos);
var endAng = getAngle(endPos);
var middleAng = getAngle(middlePos);
//check which part of circle to take
if (endAng < startAng) endAng += 2 * Math.PI;
if (middleAng < startAng) middleAng += 2 * Math.PI;
var clockwise = middleAng > endAng;
return { start: startPos, end: endPos, center: ctr, clockwise: clockwise };
}
function drawArcBy_Angle_M(vertexPos, startDir, endDir, middlePos) {
// to return
var len = undefined;
var center = new THREE.Vector3(0, 0, 0);
var centerDir = startDir.clone().add(endDir).multiplyScalar(0.5).normalize();
var vertexToMiddle = middlePos.clone().sub(vertexPos);
// if radius is too small or middlepos and its projection to centerDir is out of filletAngle
if (vertexToMiddle.length() < 1e-2 || vertexToMiddle.dot(centerDir) < 0) return null;
// if middlepos is out of filletAngle but its projection to centerDir isn't
var alpha = endDir.angleTo(startDir);
var angleMidToStart = vertexToMiddle.angleTo(startDir);
var angleMidToEnd = vertexToMiddle.angleTo(endDir);
// project middlepos onto one of the directions if it is out of filletAngle
var maxAngle = Math.max(angleMidToStart, angleMidToEnd, alpha);
if (maxAngle !== alpha) {
if (angleMidToStart === maxAngle) {
len = vertexToMiddle.dot(endDir);
} else if (angleMidToEnd === maxAngle) {
len = vertexToMiddle.dot(startDir);
}
}
if (len) {
center = vertexPos.clone().add(centerDir.clone().multiplyScalar(len / Math.cos(alpha / 2))); // fillet angle < 180 => cos(alpha/2) != 0
return {
start: vertexPos.clone().add(startDir.clone().multiplyScalar(len)),
end: vertexPos.clone().add(endDir.clone().multiplyScalar(len)),
center: center,
clockwise: true
};
}
var middleNew = middlePos.clone().sub(vertexPos);
var sinA2Sq = Math.pow(Math.sin(alpha / 2), 2);
var cosA2Sq = 1 - sinA2Sq;
var A0 = middleNew.lengthSq();
var A1 = -2 * middleNew.x;
var A2 = -2 * middleNew.y;
//if (centerDir.x === 0) {
// var sign = centerDir.dot(new THREE.Vector3(0,1,0));
// var discr = Math.pow(A2, 2) - 4 * cosA2Sq * A0;
// var Oy = (-A2 + sign * Math.sqrt(discr)) / (2 * cosA2Sq);
//
// center.x = 0;
// center.y = Oy;
//} else
if (centerDir.y === 0) {
var sign = centerDir.dot(new THREE.Vector3(1, 0, 0));
var discr = Math.pow(A1, 2) - 4 * cosA2Sq * A0;
var Ox = (-A1 + sign * Math.sqrt(discr)) / (2 * cosA2Sq);
center.x = Ox;
center.y = 0;
} else {
var sign = centerDir.dot(new THREE.Vector3(0, 1, 0));
var proportion = centerDir.x / centerDir.y;
var A = (proportion * proportion + 1) * cosA2Sq;
var B = A1 * proportion + A2;
var C = A0;
var discr = Math.pow(B, 2) - 4 * A * C;
var Oy = (-B + sign * Math.sqrt(discr)) / (2 * A);
center.x = Oy * proportion;
center.y = Oy;
}
var len = center.length() * Math.cos(alpha / 2);
center.add(vertexPos);
return {
start: vertexPos.clone().add(startDir.clone().multiplyScalar(len)),
end: vertexPos.clone().add(endDir.clone().multiplyScalar(len)),
center: center,
clockwise: true
};
}
function drawLineBy_Angle_M(vertexPos, startDir, endDir, middlePos) {
"use strict";
var centerDir = startDir.clone().add(endDir).multiplyScalar(0.5).normalize();
var vertexToMiddle = middlePos.clone().sub(vertexPos);
// if radius is too small or middlepos and its projection to centerDir is out of filletAngle
if (vertexToMiddle.length() < 1e-2 || vertexToMiddle.dot(centerDir) < 0) return null;
var alpha = endDir.angleTo(startDir);
var len = vertexToMiddle.dot(centerDir) / Math.cos(alpha / 2); // we have appropriate fillet angle so cos != 0
return {
start: vertexPos.clone().add(startDir.clone().multiplyScalar(len)),
end: vertexPos.clone().add(endDir.clone().multiplyScalar(len))
};
}
//converting arc from "three-points+flag" to "center+radius+angles" representation
function getArcAngles(params) {
var vecStart = params.start.clone().sub(params.center);
var vecEnd = params.end.clone().sub(params.center);
var startAngle = Math.atan2(vecStart.y, vecStart.x);
var endAngle = Math.atan2(vecEnd.y, vecEnd.x);
var radius = 0.5 * (vecStart.length() + vecEnd.length());
if (params.clockwise) {
if (startAngle < endAngle) startAngle += 2 * Math.PI;
} else {
if (startAngle > endAngle) endAngle += 2 * Math.PI;
}
var midAngle = (startAngle + endAngle) / 2;
var vecMid = new THREE.Vector3(Math.cos(midAngle), Math.sin(midAngle), 0);
var mid = params.center.clone().addScaledVector(vecMid, radius);
return {
center: params.center.clone(),
mid: mid,
radius: radius,
start: startAngle,
end: endAngle
};
}
//returns intersection point of given two lines
//if angularTolerance is set, then null is returned when lines are parallel
function intersectLines(pntA, dirA, pntB, dirB, angularTolerance) {
angularTolerance = angularTolerance || 1e-15; //mach.eps. by default
dirA = dirA.clone().normalize();
dirB = dirB.clone().normalize();
if (dirA.length() < 0.9 || dirB.length() < 0.9) //must be 1
return null;
var PxQ = cross2d(dirA, dirB);
if (Math.abs(PxQ) <= angularTolerance) return null;
var BmAxQ = cross2d(pntB.clone().sub(pntA), dirB);
var BmAxP = cross2d(pntB.clone().sub(pntA), dirA);
var paramA = BmAxQ / PxQ;
var paramB = BmAxP / PxQ;
var intersA = dirA.clone().multiplyScalar(paramA).add(pntA);
var intersB = dirB.clone().multiplyScalar(paramB).add(pntB);
var inters = intersA.clone().add(intersB).multiplyScalar(0.5);
return inters;
}
// calculate a tangent of a line or an arc at a point as a normalized (possibly zero) vector
function getTangent(geomParams, point) {
if (geomParams.center) {
var radVec = point.clone().sub(geomParams.center).normalize();
var tangVec = new THREE.Vector3(-radVec.y, radVec.x, 0);
if (geomParams.clockwise) tangVec.negate();
return tangVec;
} else if (geomParams.end) {
return geomParams.end.clone().sub(geomParams.start).normalize();
}
}
// modify geomParams inplace to represent movement of a subObject by the displacement
// subType can be either 'start', 'end', 'center' or '' (for object itself)
function move(geomParams, subType, displacement) {
switch (subType) {
case 'start':
reverseCurve(geomParams);
// fallthrough
case 'end':
geomParams.end.add(displacement);
if (geomParams.center) {
var tangent = getTangent(geomParams, geomParams.start);
if (tangent.lengthSq() === 0) // singular arc
tangent.set(1, 0, 0);
var newParams = drawArcBy_S_T_E(geomParams.start, tangent, geomParams.end);
if (newParams.center) {
// only if the arc is still an arc
(0, _assign2.default)(geomParams, newParams);
geomParams.radius = geomParams.center.distanceTo(geomParams.start);
}
}
if (subType === 'start') reverseCurve(geomParams);
break;
case 'center':
// center point must stay on the middle perpendicular line
var mid = geomParams.end.clone().add(geomParams.start).multiplyScalar(0.5);
var dir = geomParams.end.clone().sub(geomParams.start);
geomParams.center.add(displacement).sub(mid).projectOnVector(new THREE.Vector3(-dir.y, dir.x, 0)).add(mid);
geomParams.radius = geomParams.center.distanceTo(geomParams.start);
break;
case '':
if (geomParams.start) geomParams.start.add(displacement);
if (geomParams.end) geomParams.end.add(displacement);
if (geomParams.center) geomParams.center.add(displacement);
break;
}
return geomParams;
}
// modify params inplace for reversed curve
function reverseCurve(geomParams) {
if (geomParams.end !== undefined) {
// Line, Arc
;
var _ref = [geomParams.end, geomParams.start];
geomParams.start = _ref[0];
geomParams.end = _ref[1];
}if (geomParams.clockwise !== undefined) //Arc
geomParams.clockwise = !geomParams.clockwise;
return geomParams;
}