Skip to content

Instantly share code, notes, and snippets.

@lf94
Created January 9, 2022 04:13
Show Gist options
  • Save lf94/ea83c238e90fb91857d9d955308bb7ee to your computer and use it in GitHub Desktop.
Save lf94/ea83c238e90fb91857d9d955308bb7ee to your computer and use it in GitHub Desktop.
const X = 0;
const Y = 0;
const diff2 = ([Ax, Ay], [Bx, By]) => [ Bx - Ax, By - Ay ];
const add2 = ([Ax, Ay], [Bx, By]) => [ Bx + Ax, By + Ay ];
const cis = (angle) => [Math.cos(angle), Math.sin(angle)];
const length_of_line = ([Px, Py]) => Math.sqrt(Px**2 + Py**2);
const mag = length_of_line;
const radians_from_two_lines = ([A1, A2], [B1, B2]) => {
const [Ax, Ay] = diff2(A2, A1);
const [Bx, By] = diff2(B2, B1);
return Math.acos(
(Ax*Bx + Ay*By)
/ (length_of_line([Ax, Ay])*length_of_line([Bx,By]))
);
}
const workplane = () => ({
pos: [0,0], // Current position of the "pen"
pts: [[0,0]], // List of points to draw the polygon / straight lines
stk: [], // Stack of additional shapes to union such as arc and spline
nrm: [0,0] // The normal of the previous edge
});
const line = (point_relative, plane) => {
const p = plane.pos + point_relative;
return { ...plane, pos: p, pts: concat [plane.pts, [p]] };
};
const line_to = (point_absolute, plane) => {
const p = point_absolute;
return { ...plane, pos: p, pts: concat [plane.pts, [p]] };
};
const v_line = (y_relative, plane) => {
const p = [plane.pos[X], plane.pos[Y] + y_relative];
return { ...plane, pos: p, pts: concat [plane.pts, [p]], nrm: [0, Math.sign(y_relative)] };
};
const v_line_to = (y_absolute, plane) => {
const p = [plane.pos[X], y_absolute];
return { ...plane, pos: p, pts: concat [plane.pts, [p]], nrm: [0, Math.sign(y_absolute)] };
};
const h_line = (x_relative, plane) => {
const p = [plane.pos[X] + x_relative, plane.pos[Y]];
return { ...plane, pos: p, pts: concat [plane.pts, [p]], nrm: [Math.sign(x_relative), 0] };
};
const h_line_to = (x_absolute, plane) => {
const p = [x_absolute, plane.pos[Y]];
return { ...plane, pos: p, pts: concat [plane.pts, [p]], nrm: [Math.sign(x_absolute), 0]};
};
const polar_line = ({ distance, angle }, plane) => {
const nrm = cis(angle);
const p = plane.pos + (nrm * distance);
return { ...plane, pos: p, pts: concat [plane.pts, [p]], nrm: nrm };
};
const polar_line_to = ({ distance, angle }, plane) => {
const nrm = cis(angle);
const p = nrm * distance;
return { ...plane, pos: p, pts: concat [plane.pts, [p]], nrm: nrm };
};
const move_rel = (point_relative, plane) => {
const p = plane.pos + point_relative;
return { ...plane, pos: p, pts: plane.pts };
};
const move_abs = (point_absolute, plane) => {
const p = plane.pos + point_absolute;
return { ...plane, pos: p, pts: plane.pts };
};
//
// The math is too computationally heavy for a single threePointArc circle.
// threePointArc [point_middle, point_end_relative] plane
//
const arc = (diameter, radians) => {
const radius = diameter / 2;
const segments = 10; // TODO: Calculate properly.
const angle_per_segment = radians / segments;
return (new Array(segments)).fill([]).map((e, i) => [
Math.cos(angle_per_segment * i) * radius,
Math.sin(angle_per_segment * i) * radius
]);
};
const sagitta_arc = ([sag, point_end_relative], plane) =>
sagitta_arc_to([sag, add2(point_end_relative, plane.pos)], plane);
const sagitta_arc_to = ([sag, point_end_absolute], plane) => {
let p = point_end_absolute;
let pn = diff2(plane.pos, p);
let chord = mag(pn);
let nrm = [pn[0] / chord, pn[1] / chord];
let pm1 = add2(plane.pos, p);
let pm = [pm1[0] / 2, pm1[1] / 2];
let l = chord / 2;
let r = (sag**2 + l**2) / (2*sag);
let v = [-pn[Y], pn[X]];
let vl = length_of_line(v);
let vn = [v[0]/vl, v[1]/vl];
let o = add2(pm, [-vn[0] * (r-sag), -vn[1] * (r-sag)]);
let l1 = [plane.pos, o];
let l2 = [o, point_end_absolute];
let angle = radians_from_two_lines(l1, l2);
let arc_points = arc(r*2, angle);
let points_moved_to_correct_position = arc_points.map(([x,y]) => [
x + (point_end_absolute[0] - r),
y + point_end_absolute[1]
]);
let pts = points_moved_to_correct_position;
return {
...plane,
pos: p,
pts: plane.pts.concat(pts),
stk: plane.stk,
nrm: nrm
};
};
const radius_arc = ([r, point_end_relative], plane) =>
radius_arc_to([r, point_end_relative + plane.pos], plane);
const radius_arc_to = ([r, point_end_absolute], plane) => {
const chord = mag(diff2(plane.pos, point_end_absolute));
const l = chord / 2;
const sag = r - Math.sqrt(r**2 - l**2);
return sagitta_arc([sag, point_end_absolute], plane);
};
const tangent_arc_point = (point_end_relative, plane) =>
tangent_arc_point_to((point_end_relative + plane.pos), plane);
const tangent_arc_point_to = (point_end_absolute, plane) => {
let p = point_end_absolute;
let Pa = plane.pos;
let Pb = point_end_absolute;
let PaPb = Pb - Pa;
let nrm = PaPb / mag(PaPb);
let T = plane.nrm;
let s = dot[T, nrm];
let d = mag(PaPb / Math.cos(Math.asin(s)));
let r = d/2;
let n = Math.sign(mag(T) * mag(nrm) * s);
let cn = n >= 0 ? [-T[Y], T[X]] : T;
let c = Pa + (cn * n *r);
let vn = -[-nrm[Y], nrm[X]];
let l = mag(PaPb) / 2;
let nrm_next = (Pb - c) / mag(Pb - c);
let sag = r - sqrt(r^2 - l^2);
// TODO: how to pass this along
// let shape = circle d
// >> move [...c, 0]
// >> into difference [
// half_plane { d: r - sag, normal: vn } >> move [...c, 0]
// ];
return {
...plane,
pos: p,
pts: concat [plane.pts, [p]],
stk: concat [plane.stk, [shape]],
nrm: -[-nrm_next[Y], nrm_next[X]]
};
};
const bezier4 = (points, step) => {
const steps = 1.0 / step;
const steps_l = (new Array(steps)).fill(0).map((e, i) => i * step);
return steps_l.map(t =>
( ((1 - t) ^ 3) * points[0])
+ (3 * ((1 - t) ^ 2) * (t ^ 1) * points[1])
+ (3 * ((1 - t) ^ 1) * (t ^ 2) * points[2])
+ ( (t ^ 3) * points[3])
);
};
const spline = (list_of_triples_relative, plane) =>
spline_to (list_of_triples_relative.map(t => t.map(p => p + plane.pos)), plane);
const spline_to = (list_of_triples, plane) => {
let l = list_of_triples;
let pts = (new Array(list_of_triples.length)).fill(0).map((e, i) => {
const p_prev = i == 0 ? plane.pos : l[i-1][2];
return bezier4([p_prev, l[i][0], l[i][1], l[i][2]], 0.05) /* todo: calc steps */
}).reduce((a, c) => a.concat(c), []);
let lfst = pts[pts.length - 1];
let lsnd = pts[pts.length - 2];
let lln = lsnd - lfst;
let nrm = lln / mag(lln);
return {
...plane,
pos: l[l.length - 1][2],
pts: plane.pts.concat(pts),
nrm: -[nrm[X], nrm[Y]]
};
};
const polyline = (list_of_tuples, plane) => {
let p = list_of_tuples[list_of_tuples.length - 1];
let p2 = list_of_tuples[list_of_tuples.length - 2];
let nrm = (p-p2) / mag(p-p2);
return {
...plane,
pos: p,
pts: concat [plane.pts, list_of_tuples],
nrm: nrm
};
}
const close = (plane) => plane.pts;
module.exports = {
workplane,
length_of_line,
sagitta_arc_to,
radius_arc_to,
close
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment