pick and place editing working, saving and loading working
This commit is contained in:
@@ -12,3 +12,37 @@ export class StraightTrack extends TrackSegment {
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
export class SBendLeft extends StraightTrack {
|
||||
constructor(start?: Vector) {
|
||||
start = start || new Vector(100, 100);
|
||||
super(start);
|
||||
this.points[2].add(0, -25);
|
||||
this.points[3].add(0, -25);
|
||||
}
|
||||
}
|
||||
export class SBendRight extends StraightTrack {
|
||||
constructor(start?: Vector) {
|
||||
start = start || new Vector(100, 100);
|
||||
super(start);
|
||||
this.points[2].add(0, 25);
|
||||
this.points[3].add(0, 25);
|
||||
}
|
||||
}
|
||||
|
||||
export class BankLeft extends StraightTrack {
|
||||
constructor(start?: Vector) {
|
||||
start = start || new Vector(100, 100);
|
||||
super(start);
|
||||
this.points[2].add(0, -25);
|
||||
this.points[3].add(0, 25);
|
||||
}
|
||||
}
|
||||
export class BankRight extends StraightTrack {
|
||||
constructor(start?: Vector) {
|
||||
start = start || new Vector(100, 100);
|
||||
super(start);
|
||||
this.points[2].add(0, 25);
|
||||
this.points[3].add(0, -25);
|
||||
}
|
||||
}
|
||||
|
182
track/system.ts
182
track/system.ts
@@ -1,4 +1,4 @@
|
||||
import { Doodler, Vector } from "@bearmetal/doodler";
|
||||
import { Doodler, Point, Vector } from "@bearmetal/doodler";
|
||||
import { PathSegment } from "../math/path.ts";
|
||||
import { getContextItem, setDefaultContext } from "../lib/context.ts";
|
||||
|
||||
@@ -25,57 +25,74 @@ export class TrackSystem {
|
||||
segment.setTrack(this);
|
||||
this.segments.set(segment.id, segment);
|
||||
}
|
||||
unregisterSegment(segment: TrackSegment) {
|
||||
this.segments.delete(segment.id);
|
||||
for (const s of this.segments.values()) {
|
||||
s.backNeighbours = s.backNeighbours.filter((n) => n !== segment);
|
||||
s.frontNeighbours = s.frontNeighbours.filter((n) => n !== segment);
|
||||
}
|
||||
}
|
||||
|
||||
draw(showControls = false) {
|
||||
for (const segment of this.segments.values()) {
|
||||
segment.draw(showControls);
|
||||
}
|
||||
|
||||
try {
|
||||
if (getContextItem<boolean>("showEnds")) {
|
||||
const ends = this.findEnds();
|
||||
for (const end of ends) {
|
||||
this.doodler.fillCircle(end.pos, 2, {
|
||||
color: "red",
|
||||
// weight: 3,
|
||||
});
|
||||
if (getContextItem<boolean>("debug")) {
|
||||
this.doodler.line(
|
||||
end.pos,
|
||||
end.pos.copy().add(end.tangent.copy().mult(20)),
|
||||
{
|
||||
color: "blue",
|
||||
// weight: 3,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
setDefaultContext({ showEnds: false });
|
||||
}
|
||||
// try {
|
||||
// if (getContextItem<boolean>("showEnds")) {
|
||||
// const ends = this.findEnds();
|
||||
// for (const end of ends) {
|
||||
// this.doodler.fillCircle(end.pos, 2, {
|
||||
// color: "red",
|
||||
// // weight: 3,
|
||||
// });
|
||||
// if (getContextItem<boolean>("debug")) {
|
||||
// this.doodler.line(
|
||||
// end.pos,
|
||||
// end.pos.copy().add(end.tangent.copy().mult(20)),
|
||||
// {
|
||||
// color: "blue",
|
||||
// // weight: 3,
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } catch {
|
||||
// setDefaultContext({ showEnds: false });
|
||||
// }
|
||||
}
|
||||
|
||||
ends: Map<TrackSegment, [End, End]> = new Map();
|
||||
endArray: End[] = [];
|
||||
|
||||
findEnds() {
|
||||
const ends: { pos: Vector; segment: TrackSegment; tangent: Vector }[] = [];
|
||||
for (const segment of this.segments.values()) {
|
||||
const [a, b, c, d] = segment.points;
|
||||
{
|
||||
const tangent = Vector.sub(a, b).normalize();
|
||||
const pos = a.copy();
|
||||
ends.push({ pos, segment, tangent });
|
||||
}
|
||||
{
|
||||
const tangent = Vector.sub(d, c).normalize();
|
||||
const pos = d.copy();
|
||||
ends.push({ pos, segment, tangent });
|
||||
}
|
||||
if (this.ends.has(segment)) continue;
|
||||
const ends: [End, End] = [
|
||||
{
|
||||
pos: segment.points[0],
|
||||
segment,
|
||||
tangent: Vector.sub(segment.points[1], segment.points[0]).normalize(),
|
||||
frontOrBack: "back",
|
||||
},
|
||||
{
|
||||
pos: segment.points[3],
|
||||
segment,
|
||||
tangent: Vector.sub(segment.points[3], segment.points[2]).normalize(),
|
||||
frontOrBack: "front",
|
||||
},
|
||||
];
|
||||
this.ends.set(segment, ends);
|
||||
this.endArray.push(...ends);
|
||||
}
|
||||
return ends;
|
||||
return this.endArray;
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return this.segments.values().map((s) => s.serialize()).toArray();
|
||||
return JSON.stringify(
|
||||
this.segments.values().map((s) => s.serialize()).toArray(),
|
||||
);
|
||||
}
|
||||
|
||||
copy() {
|
||||
@@ -107,6 +124,12 @@ export class TrackSystem {
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
||||
translate(v: Vector) {
|
||||
for (const segment of this.segments.values()) {
|
||||
segment.translate(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type VectorSet = [Vector, Vector, Vector, Vector];
|
||||
@@ -142,22 +165,18 @@ export class TrackSegment extends PathSegment {
|
||||
},
|
||||
);
|
||||
if (showControls) {
|
||||
// this.doodler.drawCircle(this.points[0], 4, {
|
||||
// color: "red",
|
||||
// weight: 3,
|
||||
// });
|
||||
this.doodler.drawCircle(this.points[1], 4, {
|
||||
this.doodler.fillCircle(this.points[0], 1, {
|
||||
color: "red",
|
||||
weight: 3,
|
||||
});
|
||||
this.doodler.drawCircle(this.points[2], 4, {
|
||||
this.doodler.fillCircle(this.points[1], 1, {
|
||||
color: "red",
|
||||
});
|
||||
this.doodler.fillCircle(this.points[2], 1, {
|
||||
color: "red",
|
||||
});
|
||||
this.doodler.fillCircle(this.points[3], 1, {
|
||||
color: "red",
|
||||
weight: 3,
|
||||
});
|
||||
// this.doodler.drawCircle(this.points[3], 4, {
|
||||
// color: "red",
|
||||
// weight: 3,
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,30 +196,26 @@ export class TrackSegment extends PathSegment {
|
||||
);
|
||||
}
|
||||
|
||||
propagate() {
|
||||
const [_, __, p3, p4] = this.points;
|
||||
const tangent = Vector.sub(p4, p3);
|
||||
cleanCopy() {
|
||||
return new TrackSegment(
|
||||
this.points.map((p) => p.copy()) as VectorSet,
|
||||
);
|
||||
}
|
||||
|
||||
propagateTranslation(v: Vector) {
|
||||
for (const fNeighbour of this.frontNeighbours) {
|
||||
fNeighbour.receivePropagation(tangent);
|
||||
fNeighbour.receivePropagation(v);
|
||||
}
|
||||
for (const bNeighbour of this.backNeighbours) {
|
||||
bNeighbour.receivePropagation(v);
|
||||
}
|
||||
}
|
||||
|
||||
lastHeading?: number;
|
||||
|
||||
receivePropagation(tangent: Vector) {
|
||||
const [p1, p2, p3, p4] = this.points;
|
||||
// const angle = tangent.heading() - (this.lastHeading ?? 0);
|
||||
// this.lastHeading = tangent.heading();
|
||||
// const newP2 = Vector.add(p1, tangent);
|
||||
// const p2ToP3 = Vector.sub(p3, p2);
|
||||
// p2ToP3.rotate(angle);
|
||||
// p3.set(Vector.add(newP2, p2ToP3));
|
||||
// const p2Top4 = Vector.sub(p4, p2);
|
||||
// p2Top4.rotate(angle);
|
||||
// p4.set(Vector.add(newP2, p2Top4));
|
||||
// p2.set(newP2);
|
||||
this.rotate(tangent);
|
||||
this.propagate();
|
||||
receivePropagation(v: Vector) {
|
||||
this.translate(v);
|
||||
this.propagateTranslation(v);
|
||||
}
|
||||
|
||||
// TODO: this duplicates receivePropagation, but for some reason it doesn't work when called from receivePropagation
|
||||
@@ -231,4 +246,35 @@ export class TrackSegment extends PathSegment {
|
||||
data.id,
|
||||
);
|
||||
}
|
||||
|
||||
setPositionByPoint(pos: Vector, point: Vector) {
|
||||
if (!this.points.includes(point)) return;
|
||||
point = point.copy();
|
||||
this.points.forEach((p, i) => {
|
||||
const relativePoint = Vector.sub(p, point);
|
||||
p.set(pos);
|
||||
p.add(relativePoint);
|
||||
});
|
||||
}
|
||||
|
||||
rotateAboutPoint(angle: number, point: Vector) {
|
||||
if (!this.points.includes(point)) return;
|
||||
point = point.copy();
|
||||
this.points.forEach((p, i) => {
|
||||
const relativePoint = Vector.sub(p, point);
|
||||
relativePoint.rotate(angle);
|
||||
p.set(Vector.add(point, relativePoint));
|
||||
});
|
||||
}
|
||||
|
||||
// resetRotation() {
|
||||
// const angle = this.tangent(0).heading();
|
||||
// this.rotateAboutPoint(-angle, this.points[0]);
|
||||
// }
|
||||
|
||||
translate(v: Point) {
|
||||
this.points.forEach((p) => {
|
||||
p.add(v.x, v.y);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user