@willcgage/module-schematic 0.97.1 → 0.98.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +79 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -1
- package/dist/index.d.ts +36 -1
- package/dist/index.js +79 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -229,7 +229,7 @@ function moduleCenterline(input) {
|
|
|
229
229
|
if (drawn) return samplePath(drawn);
|
|
230
230
|
const chained = sectionedCenterline(input);
|
|
231
231
|
if (chained.length >= 2) return chained;
|
|
232
|
-
if (!input.geometryType) return [];
|
|
232
|
+
if (!input.geometryType && !input.hasPlacedTrack) return [];
|
|
233
233
|
const L = input.lengthInches > 0 ? input.lengthInches : 24;
|
|
234
234
|
const gt = input.geometryType;
|
|
235
235
|
if (gt === "dead_end") return [{ x: 0, y: 0 }];
|
|
@@ -2553,6 +2553,83 @@ function fitFlexBetween(piece, others, library = BUILT_IN_TRACK_PARTS, withinInc
|
|
|
2553
2553
|
lengthInches: Math.round(len * 1e3) / 1e3
|
|
2554
2554
|
};
|
|
2555
2555
|
}
|
|
2556
|
+
function insertIntoRun(pieces, fresh, at, library = BUILT_IN_TRACK_PARTS, withinInches = 1) {
|
|
2557
|
+
let host = null;
|
|
2558
|
+
let bestD = Infinity;
|
|
2559
|
+
for (const piece of pieces) {
|
|
2560
|
+
const part = library.find((x) => x.id === piece.partId);
|
|
2561
|
+
if (part?.kind !== "flex") continue;
|
|
2562
|
+
for (const { points } of pieceRoutePaths(piece, library))
|
|
2563
|
+
for (let i = 1; i < points.length; i++) {
|
|
2564
|
+
const d = distanceToSegment(at, points[i - 1], points[i]);
|
|
2565
|
+
if (d < bestD) {
|
|
2566
|
+
bestD = d;
|
|
2567
|
+
host = piece;
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
if (!host || bestD > withinInches) return null;
|
|
2572
|
+
const L = host.lengthInches ?? 0;
|
|
2573
|
+
const R = host.radiusInches;
|
|
2574
|
+
const steps = 200;
|
|
2575
|
+
let s = 0;
|
|
2576
|
+
let closest = Infinity;
|
|
2577
|
+
for (let i = 0; i <= steps; i++) {
|
|
2578
|
+
const t = L * i / steps;
|
|
2579
|
+
const local = flexRunEnd(t, R);
|
|
2580
|
+
const world = placeLocal(host, local.x, local.y);
|
|
2581
|
+
const d = Math.hypot(world.x - at.x, world.y - at.y);
|
|
2582
|
+
if (d < closest) {
|
|
2583
|
+
closest = d;
|
|
2584
|
+
s = t;
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
const cutLocal = flexRunEnd(s, R);
|
|
2588
|
+
const cut = placeLocal(host, cutLocal.x, cutLocal.y);
|
|
2589
|
+
const heading = norm360(host.rotationDeg + (host.flipped ? -cutLocal.headingDeg : cutLocal.headingDeg));
|
|
2590
|
+
const placed = { ...fresh, x: cut.x, y: cut.y, rotationDeg: heading };
|
|
2591
|
+
const js = placedJoints([placed], library);
|
|
2592
|
+
const entry = js.find((j) => j.joint === "throat" || j.joint === "a");
|
|
2593
|
+
const exit = js.find((j) => j.joint === "through" || j.joint === "b");
|
|
2594
|
+
if (!entry || !exit) return null;
|
|
2595
|
+
const body = Math.hypot(exit.x - entry.x, exit.y - entry.y);
|
|
2596
|
+
const rest = L - s - body;
|
|
2597
|
+
if (s < 0 || rest < 0) return null;
|
|
2598
|
+
const ids = new Set(pieces.map((p) => p.id));
|
|
2599
|
+
let n = 1;
|
|
2600
|
+
while (ids.has(`${host.id}b${n}`)) n += 1;
|
|
2601
|
+
const tail = {
|
|
2602
|
+
...host,
|
|
2603
|
+
id: `${host.id}b${n}`,
|
|
2604
|
+
x: exit.x,
|
|
2605
|
+
y: exit.y,
|
|
2606
|
+
rotationDeg: exit.headingDeg,
|
|
2607
|
+
lengthInches: rest
|
|
2608
|
+
};
|
|
2609
|
+
const out = pieces.map((p) => p.id === host.id ? { ...p, lengthInches: s } : p);
|
|
2610
|
+
const kept = out.filter((p) => p.id !== host.id || s > 0);
|
|
2611
|
+
return {
|
|
2612
|
+
pieces: [...kept, placed, ...rest > 0 ? [tail] : []],
|
|
2613
|
+
hostId: host.id,
|
|
2614
|
+
insertedId: placed.id
|
|
2615
|
+
};
|
|
2616
|
+
}
|
|
2617
|
+
function placeLocal(piece, x, y) {
|
|
2618
|
+
const rad = piece.rotationDeg * Math.PI / 180;
|
|
2619
|
+
const ly = piece.flipped ? -y : y;
|
|
2620
|
+
return {
|
|
2621
|
+
x: piece.x + x * Math.cos(rad) - ly * Math.sin(rad),
|
|
2622
|
+
y: piece.y + x * Math.sin(rad) + ly * Math.cos(rad)
|
|
2623
|
+
};
|
|
2624
|
+
}
|
|
2625
|
+
function distanceToSegment(p, a, b) {
|
|
2626
|
+
const vx = b.x - a.x;
|
|
2627
|
+
const vy = b.y - a.y;
|
|
2628
|
+
const len2 = vx * vx + vy * vy;
|
|
2629
|
+
if (len2 === 0) return Math.hypot(p.x - a.x, p.y - a.y);
|
|
2630
|
+
const t = Math.max(0, Math.min(1, ((p.x - a.x) * vx + (p.y - a.y) * vy) / len2));
|
|
2631
|
+
return Math.hypot(p.x - (a.x + t * vx), p.y - (a.y + t * vy));
|
|
2632
|
+
}
|
|
2556
2633
|
var danglingDivergeWarning = (id) => `the route diverging at ${id} is not connected to anything`;
|
|
2557
2634
|
var unreachedWarning = (id) => `${id} is not reachable from the endplate \u2014 nothing connects it`;
|
|
2558
2635
|
function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS) {
|
|
@@ -3630,6 +3707,7 @@ exports.graphToDoc = graphToDoc;
|
|
|
3630
3707
|
exports.hasNoFarEndplate = hasNoFarEndplate;
|
|
3631
3708
|
exports.importedPartToTrackPart = importedPartToTrackPart;
|
|
3632
3709
|
exports.inchesToScaleFeet = inchesToScaleFeet;
|
|
3710
|
+
exports.insertIntoRun = insertIntoRun;
|
|
3633
3711
|
exports.isLoopDoc = isLoopDoc;
|
|
3634
3712
|
exports.isTransitionTurnout = isTransitionTurnout;
|
|
3635
3713
|
exports.laneOffsetAt = laneOffsetAt;
|