just so much groundwork
This commit is contained in:
105
math/path.ts
105
math/path.ts
@@ -1,7 +1,6 @@
|
||||
import { Vector } from "doodler";
|
||||
import { Vector } from "@bearmetal/doodler";
|
||||
|
||||
export class ComplexPath {
|
||||
|
||||
points: Vector[] = [];
|
||||
|
||||
radius = 50;
|
||||
@@ -22,10 +21,10 @@ export class ComplexPath {
|
||||
|
||||
ctx.save();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.strokeStyle = 'white';
|
||||
ctx.setLineDash([21, 6])
|
||||
ctx.strokeStyle = "white";
|
||||
ctx.setLineDash([21, 6]);
|
||||
|
||||
let last = this.points[this.points.length - 1]
|
||||
let last = this.points[this.points.length - 1];
|
||||
|
||||
for (const point of this.points) {
|
||||
ctx.beginPath();
|
||||
@@ -39,8 +38,7 @@ export class ComplexPath {
|
||||
}
|
||||
|
||||
export class PathSegment {
|
||||
points: [Vector, Vector, Vector, Vector]
|
||||
ctx?: CanvasRenderingContext2D;
|
||||
points: [Vector, Vector, Vector, Vector];
|
||||
|
||||
length: number;
|
||||
|
||||
@@ -49,44 +47,23 @@ export class PathSegment {
|
||||
this.length = this.calculateApproxLength(100);
|
||||
}
|
||||
|
||||
setContext(ctx: CanvasRenderingContext2D) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
draw() {
|
||||
const [a, b, c, d] = this.points;
|
||||
doodler.drawBezier(a, b, c, d, {
|
||||
strokeColor: '#ffffff50'
|
||||
})
|
||||
// if (!this.ctx) return;
|
||||
// const ctx = this.ctx;
|
||||
|
||||
// ctx.save();
|
||||
// ctx.beginPath();
|
||||
// ctx.moveTo(this.points[0].x, this.points[0].y);
|
||||
|
||||
// ctx.bezierCurveTo(
|
||||
// this.points[1].x,
|
||||
// this.points[1].y,
|
||||
// this.points[2].x,
|
||||
// this.points[2].y,
|
||||
// this.points[3].x,
|
||||
// this.points[3].y,
|
||||
// );
|
||||
|
||||
// ctx.strokeStyle = '#ffffff50';
|
||||
// ctx.lineWidth = 2;
|
||||
// ctx.stroke();
|
||||
// ctx.restore();
|
||||
}
|
||||
|
||||
getPointAtT(t: number) {
|
||||
const [a, b, c, d] = this.points;
|
||||
const res = a.copy();
|
||||
|
||||
res.add(Vector.add(a.copy().mult(-3), b.copy().mult(3)).mult(t))
|
||||
res.add(Vector.add(Vector.add(a.copy().mult(3), b.copy().mult(-6)), c.copy().mult(3)).mult(Math.pow(t, 2)));
|
||||
res.add(Vector.add(Vector.add(a.copy().mult(-1), b.copy().mult(3)), Vector.add(c.copy().mult(-3), d.copy())).mult(Math.pow(t, 3)));
|
||||
res.add(Vector.add(a.copy().mult(-3), b.copy().mult(3)).mult(t));
|
||||
res.add(
|
||||
Vector.add(
|
||||
Vector.add(a.copy().mult(3), b.copy().mult(-6)),
|
||||
c.copy().mult(3),
|
||||
).mult(Math.pow(t, 2)),
|
||||
);
|
||||
res.add(
|
||||
Vector.add(
|
||||
Vector.add(a.copy().mult(-1), b.copy().mult(3)),
|
||||
Vector.add(c.copy().mult(-3), d.copy()),
|
||||
).mult(Math.pow(t, 3)),
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -123,15 +100,20 @@ export class PathSegment {
|
||||
points.push([i * resolution, this]);
|
||||
}
|
||||
}
|
||||
return points
|
||||
return points;
|
||||
}
|
||||
|
||||
tangent(t: number) {
|
||||
// dP(t) / dt = -3(1-t)^2 * P0 + 3(1-t)^2 * P1 - 6t(1-t) * P1 - 3t^2 * P2 + 6t(1-t) * P2 + 3t^2 * P3
|
||||
// dP(t) / dt = -3(1-t)^2 * P0 + 3(1-t)^2 * P1 - 6t(1-t) * P1 - 3t^2 * P2 + 6t(1-t) * P2 + 3t^2 * P3
|
||||
const [a, b, c, d] = this.points;
|
||||
|
||||
const res = Vector.sub(b, a).mult(3 * Math.pow(1 - t, 2));
|
||||
res.add(Vector.add(Vector.sub(c, b).mult(6 * (1 - t) * t), Vector.sub(d, c).mult(3 * Math.pow(t, 2))));
|
||||
res.add(
|
||||
Vector.add(
|
||||
Vector.sub(c, b).mult(6 * (1 - t) * t),
|
||||
Vector.sub(d, c).mult(3 * Math.pow(t, 2)),
|
||||
),
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -158,12 +140,12 @@ export class PathSegment {
|
||||
|
||||
let dist;
|
||||
if (k <= 0.0) {
|
||||
dist = Vector.hypot2(v, a)
|
||||
dist = Vector.hypot2(v, a);
|
||||
} else if (k >= 1.0) {
|
||||
dist = Vector.hypot2(v, b)
|
||||
dist = Vector.hypot2(v, b);
|
||||
}
|
||||
|
||||
dist = Vector.hypot2(v, d)
|
||||
dist = Vector.hypot2(v, d);
|
||||
|
||||
if (dist < distance) {
|
||||
distance = dist;
|
||||
@@ -179,27 +161,28 @@ export class PathSegment {
|
||||
|
||||
calculateApproxLength(resolution = 25) {
|
||||
const stepSize = 1 / resolution;
|
||||
const points: Vector[] = []
|
||||
const points: Vector[] = [];
|
||||
for (let i = 0; i <= resolution; i++) {
|
||||
const current = stepSize * i;
|
||||
points.push(this.getPointAtT(current))
|
||||
points.push(this.getPointAtT(current));
|
||||
}
|
||||
this.length = points.reduce((acc: { prev?: Vector, length: number }, cur) => {
|
||||
const prev = acc.prev;
|
||||
acc.prev = cur;
|
||||
if (!prev) return acc;
|
||||
acc.length += cur.dist(prev);
|
||||
return acc;
|
||||
}, { prev: undefined, length: 0 }).length
|
||||
this.length =
|
||||
points.reduce((acc: { prev?: Vector; length: number }, cur) => {
|
||||
const prev = acc.prev;
|
||||
acc.prev = cur;
|
||||
if (!prev) return acc;
|
||||
acc.length += cur.dist(prev);
|
||||
return acc;
|
||||
}, { prev: undefined, length: 0 }).length;
|
||||
return this.length;
|
||||
}
|
||||
|
||||
calculateEvenlySpacedPoints(spacing: number, resolution = 1) {
|
||||
const points: Vector[] = []
|
||||
const points: Vector[] = [];
|
||||
|
||||
points.push(this.points[0]);
|
||||
let prev = points[0];
|
||||
let distSinceLastEvenPoint = 0
|
||||
let distSinceLastEvenPoint = 0;
|
||||
|
||||
let t = 0;
|
||||
|
||||
@@ -209,10 +192,12 @@ export class PathSegment {
|
||||
const point = this.getPointAtT(t);
|
||||
distSinceLastEvenPoint += prev.dist(point);
|
||||
|
||||
|
||||
if (distSinceLastEvenPoint >= spacing) {
|
||||
const overshoot = distSinceLastEvenPoint - spacing;
|
||||
const evenPoint = Vector.add(point, Vector.sub(point, prev).normalize().mult(overshoot))
|
||||
const evenPoint = Vector.add(
|
||||
point,
|
||||
Vector.sub(point, prev).normalize().mult(overshoot),
|
||||
);
|
||||
distSinceLastEvenPoint = overshoot;
|
||||
points.push(evenPoint);
|
||||
prev = evenPoint;
|
||||
|
Reference in New Issue
Block a user