2018-07-23 11:44:34 +00:00
|
|
|
import point from "./point";
|
2018-07-29 15:16:26 +02:00
|
|
|
import path from "./path";
|
|
|
|
import Bezier from "bezier-js";
|
2018-07-14 16:04:39 +00:00
|
|
|
|
2018-07-23 11:12:06 +00:00
|
|
|
/** Returns internal hook name for a macro */
|
2018-07-23 11:44:34 +00:00
|
|
|
export function macroName(name) {
|
2018-07-23 11:12:06 +00:00
|
|
|
return `_macro_${name}`;
|
2018-07-12 12:53:49 +00:00
|
|
|
}
|
|
|
|
|
2018-07-14 16:04:39 +00:00
|
|
|
/** Find intersection of two (endless) lines */
|
2018-07-23 11:44:34 +00:00
|
|
|
export function beamsCross(a1, a2, b1, b2) {
|
2018-07-14 16:04:39 +00:00
|
|
|
let slopeA = a1.slope(a2);
|
|
|
|
let slopeB = b1.slope(b2);
|
2018-07-23 11:44:34 +00:00
|
|
|
if (slopeA === slopeB) return false; // Parallel lines
|
2018-07-14 16:04:39 +00:00
|
|
|
|
2018-07-23 11:44:34 +00:00
|
|
|
if (a1.x === a2.x)
|
|
|
|
return new point(a1.x, slopeB * a1.x + (b1.y - slopeB * b1.x));
|
|
|
|
// Vertical line A
|
|
|
|
else if (b1.x === b2.x)
|
|
|
|
return new point(b1.x, slopeA * b1.x + (a1.y - slopeA * a1.x));
|
|
|
|
// Vertical line B
|
2018-07-14 16:04:39 +00:00
|
|
|
else {
|
|
|
|
// Swap points if line A or B goes from right to left
|
2018-07-23 11:44:34 +00:00
|
|
|
if (a1.x > a2.x) {
|
2018-07-14 16:04:39 +00:00
|
|
|
let tmp = a1.copy();
|
|
|
|
a1 = a2.copy();
|
|
|
|
a2 = tmp;
|
|
|
|
}
|
2018-07-23 11:44:34 +00:00
|
|
|
if (b1.x > b2.x) {
|
2018-07-14 16:04:39 +00:00
|
|
|
let tmp = b1.copy();
|
|
|
|
b1 = b2.copy();
|
|
|
|
b2 = tmp;
|
|
|
|
}
|
|
|
|
// Find y intercept
|
2018-07-23 11:44:34 +00:00
|
|
|
let iA = a1.y - slopeA * a1.x;
|
|
|
|
let iB = b1.y - slopeB * b1.x;
|
2018-07-14 16:04:39 +00:00
|
|
|
|
|
|
|
// Find intersection
|
|
|
|
let x = (iB - iA) / (slopeA - slopeB);
|
2018-07-15 17:15:56 +02:00
|
|
|
let y = slopeA * x + iA;
|
2018-07-14 16:04:39 +00:00
|
|
|
|
2018-07-23 11:12:06 +00:00
|
|
|
return new point(x, y);
|
2018-07-14 16:04:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Find intersection of two line segments */
|
2018-07-23 11:44:34 +00:00
|
|
|
export function linesCross(a1, a2, b1, b2) {
|
|
|
|
let p = beamsCross(a1, a2, b1, b2);
|
|
|
|
if (p) {
|
2018-07-14 16:04:39 +00:00
|
|
|
let lenA = a1.dist(a2);
|
|
|
|
let lenB = b1.dist(b2);
|
|
|
|
let lenC = a1.dist(p) + p.dist(a2);
|
|
|
|
let lenD = b1.dist(p) + p.dist(b2);
|
|
|
|
if (round(lenA) == round(lenC) && round(lenB) == round(lenD)) return p;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-07-19 14:02:04 +00:00
|
|
|
/** Find where an (endless) line crosses a certain Y-value */
|
2018-07-23 11:44:34 +00:00
|
|
|
export function beamCrossesY(from, to, y) {
|
|
|
|
if (from.y === to.y) return false; // Horizontal line
|
|
|
|
let left = new point(-10, y);
|
|
|
|
let right = new point(10, y);
|
2018-07-19 14:02:04 +00:00
|
|
|
|
|
|
|
return beamsCross(from, to, left, right);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns an object with shorthand access for pattern design */
|
2018-07-25 14:53:10 +00:00
|
|
|
export function shorthand(part) {
|
|
|
|
let final = part.context.settings.mode === "draft" ? true : false;
|
|
|
|
let paperless = part.context.settings.paperless === true ? true : false;
|
2018-07-19 14:02:04 +00:00
|
|
|
return {
|
2018-08-01 14:55:54 +02:00
|
|
|
sa: part.context.settings.sa || 0,
|
2018-07-25 14:53:10 +00:00
|
|
|
measurements: part.context.settings.measurements || {},
|
|
|
|
options: part.context.options || {},
|
2018-08-05 16:32:38 +02:00
|
|
|
store: part.context.store,
|
2018-07-19 14:02:04 +00:00
|
|
|
points: part.points || {},
|
|
|
|
paths: part.paths || {},
|
|
|
|
snippets: part.snippets || {},
|
2018-07-21 12:54:29 +02:00
|
|
|
macro: part.macroRunner(),
|
2018-07-26 23:31:29 +02:00
|
|
|
point: part.point,
|
|
|
|
path: part.path,
|
|
|
|
snippet: part.snippet,
|
2018-07-19 14:02:04 +00:00
|
|
|
final,
|
|
|
|
paperless
|
2018-07-23 11:44:34 +00:00
|
|
|
};
|
2018-07-19 14:02:04 +00:00
|
|
|
}
|
2018-07-26 13:43:12 +00:00
|
|
|
|
|
|
|
/** Offsets a path by distance */
|
|
|
|
export function pathOffset(path, distance) {
|
|
|
|
let offset = [];
|
|
|
|
let current;
|
2018-07-29 15:16:26 +02:00
|
|
|
let start = false;
|
|
|
|
let closed = false;
|
2018-07-26 13:43:12 +00:00
|
|
|
for (let i in path.ops) {
|
|
|
|
let op = path.ops[i];
|
|
|
|
if (op.type === "line") {
|
|
|
|
offset.push(offsetLine(current, op.to, distance));
|
|
|
|
} else if (op.type === "curve") {
|
2018-07-29 15:16:26 +02:00
|
|
|
let b = new Bezier(
|
|
|
|
{ x: current.x, y: current.y },
|
|
|
|
{ x: op.cp1.x, y: op.cp1.y },
|
|
|
|
{ x: op.cp2.x, y: op.cp2.y },
|
|
|
|
{ x: op.to.x, y: op.to.y }
|
|
|
|
);
|
|
|
|
for (let bezier of b.offset(distance)) {
|
|
|
|
offset.push(asPath(bezier));
|
|
|
|
}
|
|
|
|
} else if (op.type === "close") {
|
|
|
|
// offset.push(offsetLine(current, start, distance));
|
|
|
|
closed = true;
|
2018-07-26 13:43:12 +00:00
|
|
|
}
|
2018-07-29 15:16:26 +02:00
|
|
|
if (op.to) current = op.to;
|
|
|
|
if (!start) start = current;
|
2018-07-26 13:43:12 +00:00
|
|
|
}
|
2018-07-29 15:16:26 +02:00
|
|
|
|
|
|
|
return joinPaths(offset, closed);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Offsets a line by distance */
|
|
|
|
export function offsetLine(from, to, distance) {
|
|
|
|
if (from.x === to.x && from.y === to.y) {
|
|
|
|
throw "Cannot offset line that starts and ends in the same point";
|
|
|
|
}
|
|
|
|
let angle = from.angle(to) - 90;
|
|
|
|
|
|
|
|
return new path()
|
|
|
|
.move(from.shift(angle, distance))
|
|
|
|
.line(to.shift(angle, distance));
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Converts a bezier-js instance to a path */
|
|
|
|
export function asPath(bezier) {
|
|
|
|
return new path()
|
|
|
|
.move(new point(bezier.points[0].x, bezier.points[0].y))
|
|
|
|
.curve(
|
|
|
|
new point(bezier.points[1].x, bezier.points[1].y),
|
|
|
|
new point(bezier.points[2].x, bezier.points[2].y),
|
|
|
|
new point(bezier.points[3].x, bezier.points[3].y)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Joins path segments together into one path */
|
|
|
|
export function joinPaths(paths, closed = false) {
|
|
|
|
let joint = new path().move(paths[0].ops[0].to);
|
|
|
|
for (let p of paths) {
|
|
|
|
for (let op of p.ops) {
|
|
|
|
if (op.type === "curve") {
|
|
|
|
joint.curve(op.cp1, op.cp2, op.to);
|
|
|
|
} else if (op.type !== "close") {
|
|
|
|
joint.line(op.to);
|
|
|
|
} else {
|
|
|
|
throw "Close op not handled";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (closed) joint.close();
|
|
|
|
|
|
|
|
return joint;
|
2018-07-26 13:43:12 +00:00
|
|
|
}
|
2018-08-01 14:55:54 +02:00
|
|
|
|
|
|
|
/** Convert value in mm to cm or imperial units */
|
|
|
|
export function units(value, to = "metric") {
|
|
|
|
if (to === "imperial") return round(value / 25.4) + '"';
|
|
|
|
else return round(value / 10) + "cm";
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Rounds a value to 2 decimals */
|
|
|
|
export function round(value) {
|
|
|
|
return Math.round(value * 1e2) / 1e2;
|
|
|
|
}
|