Added evenly spaced points to paths
This commit is contained in:
parent
ae0575875f
commit
9b03e6c2cb
73
bundle.js
73
bundle.js
@ -606,6 +606,28 @@ class PathSegment {
|
|||||||
length: 0
|
length: 0
|
||||||
}).length;
|
}).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 {
|
class Mover {
|
||||||
position;
|
position;
|
||||||
@ -849,6 +871,7 @@ class TrainCar extends Train {
|
|||||||
super.move();
|
super.move();
|
||||||
} else {
|
} else {
|
||||||
this.draw();
|
this.draw();
|
||||||
|
this.follower?.draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -929,8 +952,10 @@ class Track extends PathSegment {
|
|||||||
class Spline {
|
class Spline {
|
||||||
segments = [];
|
segments = [];
|
||||||
ctx;
|
ctx;
|
||||||
|
evenPoints;
|
||||||
constructor(segs){
|
constructor(segs){
|
||||||
this.segments = segs;
|
this.segments = segs;
|
||||||
|
this.evenPoints = this.calculateEvenlySpacedPoints(3);
|
||||||
}
|
}
|
||||||
setContext(ctx) {
|
setContext(ctx) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
@ -943,6 +968,19 @@ class Spline {
|
|||||||
segment.draw();
|
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 generateSquareTrack = ()=>{
|
||||||
const first = new Track([
|
const first = new Track([
|
||||||
@ -1025,39 +1063,24 @@ init({
|
|||||||
});
|
});
|
||||||
const path = generateSquareTrack();
|
const path = generateSquareTrack();
|
||||||
let t = 0;
|
let t = 0;
|
||||||
let currentSeg = 0;
|
|
||||||
const trains = Array(1).fill(null).map((_, i)=>new Train(path.segments[i % path.segments.length], 5));
|
const trains = Array(1).fill(null).map((_, i)=>new Train(path.segments[i % path.segments.length], 5));
|
||||||
doodler.createLayer(()=>{
|
doodler.createLayer(()=>{
|
||||||
path.draw();
|
path.draw();
|
||||||
for (const train of trains){
|
for (const p of path.evenPoints){
|
||||||
train.move();
|
p.drawDot();
|
||||||
}
|
}
|
||||||
const seg = path.segments[currentSeg];
|
const point = path.followEvenPoints(t);
|
||||||
const tMod = 1 / seg.length;
|
point && doodler.drawCircle(point, 5, {
|
||||||
const start = seg.getPointAtT(t);
|
strokeColor: 'green'
|
||||||
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;
|
t = (t + 1 / 3) % path.evenPoints.length;
|
||||||
if (t > 1) {
|
|
||||||
t -= 1;
|
|
||||||
currentSeg = (currentSeg + 1) % path.segments.length;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
document.addEventListener('keyup', (e)=>{
|
document.addEventListener('keyup', (e)=>{
|
||||||
if (e.key === 'd') {
|
if (e.key === 'd') {}
|
||||||
console.log(trains);
|
if (e.key === 'ArrowUp') {}
|
||||||
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 === 'ArrowDown') {
|
if (e.key === 'ArrowDown') {
|
||||||
for (const train1 of trains){
|
for (const train of trains){
|
||||||
train1.speed -= .1;
|
train.speed -= .1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (e.key === 'e') {
|
if (e.key === 'e') {
|
||||||
|
51
main.ts
51
main.ts
@ -38,37 +38,44 @@ const trains = Array(trainCount).fill(null).map((_, i) => new Train(path.segment
|
|||||||
|
|
||||||
doodler.createLayer(() => {
|
doodler.createLayer(() => {
|
||||||
path.draw();
|
path.draw();
|
||||||
|
|
||||||
for (const train of trains) {
|
// for (const train of trains) {
|
||||||
train.move();
|
// train.move();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// ctx.strokeStyle = 'red';
|
// ctx.strokeStyle = 'red';
|
||||||
// ctx.lineWidth = 4;
|
// ctx.lineWidth = 4;
|
||||||
const seg = path.segments[currentSeg];
|
// const seg = path.segments[currentSeg];
|
||||||
const tMod = speed/seg.length;
|
// const start = seg.getPointAtT(t);
|
||||||
const start = seg.getPointAtT(t);
|
// const tan = seg.tangent(t).normalize().mult(25);
|
||||||
const tan = seg.tangent(t).normalize().mult(25);
|
// const tan = seg.tangent(t);
|
||||||
doodler.line(start, new Vector(start.x + tan.x, start.y + tan.y), {color: 'red'});
|
|
||||||
|
for (const p of path.evenPoints) {
|
||||||
t += tMod;
|
p.drawDot();
|
||||||
if (t > 1) {
|
|
||||||
t -= 1;
|
|
||||||
currentSeg = (currentSeg + 1) % path.segments.length;
|
|
||||||
}
|
}
|
||||||
|
// 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))
|
// path.segments.forEach(s => s.calculateApproxLength(10000))
|
||||||
})
|
})
|
||||||
|
|
||||||
document.addEventListener('keyup', e => {
|
document.addEventListener('keyup', e => {
|
||||||
if (e.key === 'd') {
|
if (e.key === 'd') {
|
||||||
console.log(trains)
|
// console.log(trains)
|
||||||
console.log(path.segments.reduce((a,b) => a + b.calculateApproxLength(1000), 0))
|
// console.log(path.segments.reduce((a,b) => a + b.calculateApproxLength(1000), 0))
|
||||||
|
// console.log(path.evenPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.key === 'ArrowUp') {
|
if (e.key === 'ArrowUp') {
|
||||||
for (const train of trains) {
|
// for (const train of trains) {
|
||||||
train.speed += .1;
|
// train.speed += .1;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
if (e.key === 'ArrowDown') {
|
if (e.key === 'ArrowDown') {
|
||||||
for (const train of trains) {
|
for (const train of trains) {
|
||||||
@ -81,9 +88,9 @@ document.addEventListener('keyup', e => {
|
|||||||
t.editable = !t.editable;
|
t.editable = !t.editable;
|
||||||
for (const p of t.points) {
|
for (const p of t.points) {
|
||||||
if (t.editable)
|
if (t.editable)
|
||||||
doodler.registerDraggable(p, 10)
|
doodler.registerDraggable(p, 10)
|
||||||
else
|
else
|
||||||
doodler.unregisterDraggable(p)
|
doodler.unregisterDraggable(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
math/path.ts
44
math/path.ts
@ -54,8 +54,8 @@ export class PathSegment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
const [a,b,c,d] = this.points;
|
const [a, b, c, d] = this.points;
|
||||||
doodler.drawBezier(a,b,c,d, {
|
doodler.drawBezier(a, b, c, d, {
|
||||||
strokeColor: '#ffffff50'
|
strokeColor: '#ffffff50'
|
||||||
})
|
})
|
||||||
// if (!this.ctx) return;
|
// if (!this.ctx) return;
|
||||||
@ -120,7 +120,7 @@ export class PathSegment {
|
|||||||
const point = this.getPointAtT(i * resolution);
|
const point = this.getPointAtT(i * resolution);
|
||||||
const distance = v.dist(point);
|
const distance = v.dist(point);
|
||||||
if (distance < r) {
|
if (distance < r) {
|
||||||
points.push([i * resolution,this]);
|
points.push([i * resolution, this]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return points
|
return points
|
||||||
@ -178,18 +178,48 @@ export class PathSegment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
calculateApproxLength(resolution = 25) {
|
calculateApproxLength(resolution = 25) {
|
||||||
const stepSize = 1/resolution;
|
const stepSize = 1 / resolution;
|
||||||
const points: Vector[] = []
|
const points: Vector[] = []
|
||||||
for (let i = 0; i <= resolution; i++) {
|
for (let i = 0; i <= resolution; i++) {
|
||||||
const current = stepSize*i;
|
const current = stepSize * i;
|
||||||
points.push(this.getPointAtT(current))
|
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;
|
const prev = acc.prev;
|
||||||
acc.prev = cur;
|
acc.prev = cur;
|
||||||
if (!prev) return acc;
|
if (!prev) return acc;
|
||||||
acc.length += cur.dist(prev);
|
acc.length += cur.dist(prev);
|
||||||
return acc;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
49
track.ts
49
track.ts
@ -95,8 +95,11 @@ export class Track extends PathSegment {
|
|||||||
export class Spline<T extends PathSegment = PathSegment> {
|
export class Spline<T extends PathSegment = PathSegment> {
|
||||||
segments: T[] = [];
|
segments: T[] = [];
|
||||||
ctx?: CanvasRenderingContext2D;
|
ctx?: CanvasRenderingContext2D;
|
||||||
|
|
||||||
|
evenPoints: Vector[];
|
||||||
constructor(segs: T[]) {
|
constructor(segs: T[]) {
|
||||||
this.segments = segs;
|
this.segments = segs;
|
||||||
|
this.evenPoints = this.calculateEvenlySpacedPoints(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
setContext(ctx: CanvasRenderingContext2D) {
|
setContext(ctx: CanvasRenderingContext2D) {
|
||||||
@ -111,6 +114,52 @@ export class Spline<T extends PathSegment = PathSegment> {
|
|||||||
segment.draw();
|
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 = () => {
|
export const generateSquareTrack = () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user