diff --git a/bundle.js b/bundle.js index 973ca78..9fee195 100644 --- a/bundle.js +++ b/bundle.js @@ -606,6 +606,28 @@ class PathSegment { length: 0 }).length; } + calculateEvenlySpacedPoints(spacing, resolution = 1) { + const points = []; + points.push(this.points[0]); + let prev = points[0]; + let distSinceLastEvenPoint = 0; + let t = 0; + const div = Math.ceil(this.length * resolution * 10); + while(t < 1){ + t += 1 / div; + 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)); + distSinceLastEvenPoint = overshoot; + points.push(evenPoint); + prev = evenPoint; + } + prev = point; + } + return points; + } } class Mover { position; @@ -849,6 +871,7 @@ class TrainCar extends Train { super.move(); } else { this.draw(); + this.follower?.draw(); } } } @@ -929,8 +952,10 @@ class Track extends PathSegment { class Spline { segments = []; ctx; + evenPoints; constructor(segs){ this.segments = segs; + this.evenPoints = this.calculateEvenlySpacedPoints(3); } setContext(ctx) { this.ctx = ctx; @@ -943,6 +968,19 @@ class Spline { segment.draw(); } } + calculateEvenlySpacedPoints(spacing, resolution = 1) { + return this.segments.flatMap((s)=>s.calculateEvenlySpacedPoints(spacing, resolution)); + } + followEvenPoints(t) { + const i = Math.floor(t); + const a = this.evenPoints[i]; + const b = this.evenPoints[(i + 1) % this.evenPoints.length]; + try { + return Vector.lerp(a, b, t % 1); + } catch { + console.log(t, i, a, b); + } + } } const generateSquareTrack = ()=>{ const first = new Track([ @@ -1025,39 +1063,24 @@ init({ }); const path = generateSquareTrack(); let t = 0; -let currentSeg = 0; const trains = Array(1).fill(null).map((_, i)=>new Train(path.segments[i % path.segments.length], 5)); doodler.createLayer(()=>{ path.draw(); - for (const train of trains){ - train.move(); + for (const p of path.evenPoints){ + p.drawDot(); } - const seg = path.segments[currentSeg]; - const tMod = 1 / seg.length; - const start = seg.getPointAtT(t); - const tan = seg.tangent(t).normalize().mult(25); - doodler.line(start, new Vector(start.x + tan.x, start.y + tan.y), { - color: 'red' + const point = path.followEvenPoints(t); + point && doodler.drawCircle(point, 5, { + strokeColor: 'green' }); - t += tMod; - if (t > 1) { - t -= 1; - currentSeg = (currentSeg + 1) % path.segments.length; - } + t = (t + 1 / 3) % path.evenPoints.length; }); document.addEventListener('keyup', (e)=>{ - if (e.key === 'd') { - console.log(trains); - console.log(path.segments.reduce((a, b)=>a + b.calculateApproxLength(1000), 0)); - } - if (e.key === 'ArrowUp') { - for (const train of trains){ - train.speed += .1; - } - } + if (e.key === 'd') {} + if (e.key === 'ArrowUp') {} if (e.key === 'ArrowDown') { - for (const train1 of trains){ - train1.speed -= .1; + for (const train of trains){ + train.speed -= .1; } } if (e.key === 'e') { diff --git a/main.ts b/main.ts index 362c0dc..7aa7721 100644 --- a/main.ts +++ b/main.ts @@ -38,37 +38,44 @@ const trains = Array(trainCount).fill(null).map((_, i) => new Train(path.segment doodler.createLayer(() => { path.draw(); - - for (const train of trains) { - train.move(); - } - + + // for (const train of trains) { + // train.move(); + // } + // ctx.strokeStyle = 'red'; // ctx.lineWidth = 4; - const seg = path.segments[currentSeg]; - const tMod = speed/seg.length; - const start = seg.getPointAtT(t); - const tan = seg.tangent(t).normalize().mult(25); - doodler.line(start, new Vector(start.x + tan.x, start.y + tan.y), {color: 'red'}); - - t += tMod; - if (t > 1) { - t -= 1; - currentSeg = (currentSeg + 1) % path.segments.length; + // const seg = path.segments[currentSeg]; + // const start = seg.getPointAtT(t); + // const tan = seg.tangent(t).normalize().mult(25); + // const tan = seg.tangent(t); + + for (const p of path.evenPoints) { + p.drawDot(); } + // doodler.line(start, new Vector(start.x + tan.x, start.y + tan.y), {color: 'blue'}); + // doodler.fillCircle(start, 5, {fillColor: 'blue'}) + + const point = path.followEvenPoints(t); + point && + doodler.drawCircle(point, 5, {strokeColor: 'green'}) + + t = (t + (1 / 3)) % path.evenPoints.length; + // path.segments.forEach(s => s.calculateApproxLength(10000)) }) document.addEventListener('keyup', e => { if (e.key === 'd') { - console.log(trains) - console.log(path.segments.reduce((a,b) => a + b.calculateApproxLength(1000), 0)) + // console.log(trains) + // console.log(path.segments.reduce((a,b) => a + b.calculateApproxLength(1000), 0)) + // console.log(path.evenPoints); } if (e.key === 'ArrowUp') { - for (const train of trains) { - train.speed += .1; - } + // for (const train of trains) { + // train.speed += .1; + // } } if (e.key === 'ArrowDown') { for (const train of trains) { @@ -81,9 +88,9 @@ document.addEventListener('keyup', e => { t.editable = !t.editable; for (const p of t.points) { if (t.editable) - doodler.registerDraggable(p, 10) + doodler.registerDraggable(p, 10) else - doodler.unregisterDraggable(p) + doodler.unregisterDraggable(p) } } } diff --git a/math/path.ts b/math/path.ts index 3b3023f..618e057 100644 --- a/math/path.ts +++ b/math/path.ts @@ -54,8 +54,8 @@ export class PathSegment { } draw() { - const [a,b,c,d] = this.points; - doodler.drawBezier(a,b,c,d, { + const [a, b, c, d] = this.points; + doodler.drawBezier(a, b, c, d, { strokeColor: '#ffffff50' }) // if (!this.ctx) return; @@ -120,7 +120,7 @@ export class PathSegment { const point = this.getPointAtT(i * resolution); const distance = v.dist(point); if (distance < r) { - points.push([i * resolution,this]); + points.push([i * resolution, this]); } } return points @@ -178,18 +178,48 @@ export class PathSegment { } calculateApproxLength(resolution = 25) { - const stepSize = 1/resolution; + const stepSize = 1 / resolution; const points: Vector[] = [] for (let i = 0; i <= resolution; i++) { - const current = stepSize*i; + const current = stepSize * i; points.push(this.getPointAtT(current)) } - return points.reduce((acc:{prev?: Vector, length: number}, cur) => { + return 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 + }, { prev: undefined, length: 0 }).length + } + + calculateEvenlySpacedPoints(spacing: number, resolution = 1) { + const points: Vector[] = [] + + points.push(this.points[0]); + let prev = points[0]; + let distSinceLastEvenPoint = 0 + + let t = 0; + + const div = Math.ceil(this.length * resolution * 10); + while (t < 1) { + t += 1 / div; + 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)) + distSinceLastEvenPoint = overshoot; + points.push(evenPoint); + prev = evenPoint; + } + + prev = point; + } + + return points; } } diff --git a/track.ts b/track.ts index 2124c81..84c1ee8 100644 --- a/track.ts +++ b/track.ts @@ -95,8 +95,11 @@ export class Track extends PathSegment { export class Spline { segments: T[] = []; ctx?: CanvasRenderingContext2D; + + evenPoints: Vector[]; constructor(segs: T[]) { this.segments = segs; + this.evenPoints = this.calculateEvenlySpacedPoints(3); } setContext(ctx: CanvasRenderingContext2D) { @@ -111,6 +114,52 @@ export class Spline { segment.draw(); } } + + calculateEvenlySpacedPoints(spacing: number, resolution = 1) { + return this.segments.flatMap(s => s.calculateEvenlySpacedPoints(spacing, resolution)); + // const points: Vector[] = [] + + // points.push(this.segments[0].points[0]); + // let prev = points[0]; + // let distSinceLastEvenPoint = 0 + // for (const seg of this.segments) { + + // let t = 0; + + // const div = Math.ceil(seg.length * resolution * 10); + // while (t < 1) { + // t += 1 / div; + // const point = seg.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)) + // distSinceLastEvenPoint = overshoot; + // points.push(evenPoint); + // prev = evenPoint; + // } + + // prev = point + // } + // } + + // return points; + } + + followEvenPoints(t: number) { + const i = Math.floor(t); + const a = this.evenPoints[i] + const b = this.evenPoints[(i + 1) % this.evenPoints.length] + + try { + return Vector.lerp(a, b, t % 1); + + } catch { + console.log(t, i, a, b); + } + } } export const generateSquareTrack = () => { diff --git a/train.ts b/train.ts index 308243a..4926429 100644 --- a/train.ts +++ b/train.ts @@ -178,6 +178,7 @@ class TrainCar extends Train { super.move(); } else { this.draw() + this.follower?.draw(); } } // this.draw()