@willcgage/module-schematic 0.90.0 → 0.92.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 +51 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -2
- package/dist/index.d.ts +38 -2
- package/dist/index.js +51 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2268,8 +2268,16 @@ function pieceRoutePaths(piece, library = BUILT_IN_TRACK_PARTS) {
|
|
|
2268
2268
|
const b = at(route[1]);
|
|
2269
2269
|
if (!a || !b) continue;
|
|
2270
2270
|
const ends = [{ x: a.x, y: a.y }, { x: b.x, y: b.y }];
|
|
2271
|
+
if (part.kind === "flex") {
|
|
2272
|
+
const pts2 = flexRunPoints(piece.lengthInches ?? 0, piece.radiusInches).map(
|
|
2273
|
+
(q) => place(q.x, q.y)
|
|
2274
|
+
);
|
|
2275
|
+
pts2[pts2.length - 1] = { x: b.x, y: b.y };
|
|
2276
|
+
out.push({ route, points: pts2 });
|
|
2277
|
+
continue;
|
|
2278
|
+
}
|
|
2271
2279
|
const diverging = route.some((r) => r === "diverge" || r === "legA" || r === "legB");
|
|
2272
|
-
if (!diverging
|
|
2280
|
+
if (!diverging) {
|
|
2273
2281
|
out.push({ route, points: ends });
|
|
2274
2282
|
continue;
|
|
2275
2283
|
}
|
|
@@ -2308,6 +2316,25 @@ function partsPlaceable(library = BUILT_IN_TRACK_PARTS) {
|
|
|
2308
2316
|
return { placeable, blocked };
|
|
2309
2317
|
}
|
|
2310
2318
|
var JOINT_SNAP_INCHES = 0.01;
|
|
2319
|
+
function flexRunEnd(lengthInches, radiusInches) {
|
|
2320
|
+
const L = lengthInches;
|
|
2321
|
+
const R = radiusInches;
|
|
2322
|
+
if (!R || !Number.isFinite(R) || Math.abs(R) < 1e-6)
|
|
2323
|
+
return { x: L, y: 0, headingDeg: 0 };
|
|
2324
|
+
const theta = L / R;
|
|
2325
|
+
return {
|
|
2326
|
+
x: Math.abs(R) * Math.sin(Math.abs(theta)) * Math.sign(L || 1),
|
|
2327
|
+
y: R * (1 - Math.cos(theta)),
|
|
2328
|
+
headingDeg: theta * 180 / Math.PI
|
|
2329
|
+
};
|
|
2330
|
+
}
|
|
2331
|
+
function flexRunPoints(lengthInches, radiusInches, steps = 16) {
|
|
2332
|
+
if (!radiusInches || !Number.isFinite(radiusInches) || Math.abs(radiusInches) < 1e-6)
|
|
2333
|
+
return [{ x: 0, y: 0 }, { x: lengthInches, y: 0 }];
|
|
2334
|
+
const out = [];
|
|
2335
|
+
for (let i = 0; i <= steps; i++) out.push(flexRunEnd(lengthInches * i / steps, radiusInches));
|
|
2336
|
+
return out.map((p) => ({ x: p.x, y: p.y }));
|
|
2337
|
+
}
|
|
2311
2338
|
function placedJoints(pieces, library = BUILT_IN_TRACK_PARTS) {
|
|
2312
2339
|
const out = [];
|
|
2313
2340
|
const RAD = Math.PI / 180;
|
|
@@ -2318,10 +2345,13 @@ function placedJoints(pieces, library = BUILT_IN_TRACK_PARTS) {
|
|
|
2318
2345
|
if (!geo) continue;
|
|
2319
2346
|
const c = Math.cos(p.rotationDeg * RAD);
|
|
2320
2347
|
const s = Math.sin(p.rotationDeg * RAD);
|
|
2348
|
+
const run = part.kind === "flex" ? flexRunEnd(p.lengthInches ?? 0, p.radiusInches) : null;
|
|
2321
2349
|
for (const j of geo.joints) {
|
|
2322
|
-
const
|
|
2323
|
-
const
|
|
2324
|
-
const
|
|
2350
|
+
const far = run && j.id === "b";
|
|
2351
|
+
const lx = far ? run.x : j.x;
|
|
2352
|
+
const ly = p.flipped ? -(far ? run.y : j.y) : far ? run.y : j.y;
|
|
2353
|
+
const local = far ? run.headingDeg : j.angleDeg;
|
|
2354
|
+
const h = (p.flipped ? -local : local) + p.rotationDeg;
|
|
2325
2355
|
out.push({
|
|
2326
2356
|
key: `${p.id}.${j.id}`,
|
|
2327
2357
|
piece: p.id,
|
|
@@ -2410,6 +2440,7 @@ function snapPiece(moving, others, library = BUILT_IN_TRACK_PARTS, withinInches
|
|
|
2410
2440
|
to: best.t.key
|
|
2411
2441
|
};
|
|
2412
2442
|
}
|
|
2443
|
+
var danglingDivergeWarning = (id) => `the route diverging at ${id} is not connected to anything`;
|
|
2413
2444
|
function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS) {
|
|
2414
2445
|
const byKey = new Map(graph.joints.map((j) => [j.key, j]));
|
|
2415
2446
|
const pieceById = new Map(pieces.map((p) => [p.id, p]));
|
|
@@ -2426,10 +2457,19 @@ function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS)
|
|
|
2426
2457
|
const part = partOf(pid);
|
|
2427
2458
|
return part ? partGeometry(part, library) : null;
|
|
2428
2459
|
};
|
|
2429
|
-
const gap = (a, b) =>
|
|
2460
|
+
const gap = (a, b) => {
|
|
2461
|
+
if (!a || !b) return 0;
|
|
2462
|
+
if (a.piece === b.piece) {
|
|
2463
|
+
const piece = pieceById.get(a.piece);
|
|
2464
|
+
const part = piece ? partOf(a.piece) : void 0;
|
|
2465
|
+
if (piece && part?.kind === "flex") return piece.lengthInches ?? 0;
|
|
2466
|
+
}
|
|
2467
|
+
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
2468
|
+
};
|
|
2430
2469
|
const routes = [];
|
|
2431
2470
|
const turnouts = [];
|
|
2432
2471
|
const warnings = [];
|
|
2472
|
+
const danglingDiverges = [];
|
|
2433
2473
|
const queued = /* @__PURE__ */ new Set();
|
|
2434
2474
|
const pending = [];
|
|
2435
2475
|
const walk = (startKey, startPos, id, bornAt) => {
|
|
@@ -2520,7 +2560,8 @@ function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS)
|
|
|
2520
2560
|
const b = pending.shift();
|
|
2521
2561
|
const start = link.get(b.joint);
|
|
2522
2562
|
if (!start) {
|
|
2523
|
-
warnings.push(
|
|
2563
|
+
warnings.push(danglingDivergeWarning(b.from));
|
|
2564
|
+
danglingDiverges.push(b.from);
|
|
2524
2565
|
continue;
|
|
2525
2566
|
}
|
|
2526
2567
|
const already = routes.find((r2) => r2.pieces.includes(byKey.get(start).piece));
|
|
@@ -2541,7 +2582,7 @@ function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS)
|
|
|
2541
2582
|
if (!reached.has(p.id) && !graph.unplaceable.some((u) => u.piece === p.id))
|
|
2542
2583
|
warnings.push(`${p.id} is not reachable from the endplate \u2014 nothing connects it`);
|
|
2543
2584
|
for (const c of graph.conflicts) warnings.push(c.reason);
|
|
2544
|
-
return { routes, turnouts, warnings };
|
|
2585
|
+
return { routes, turnouts, warnings, danglingDiverges };
|
|
2545
2586
|
}
|
|
2546
2587
|
function resolveGraphAnchor(anchor, walk, pieces, library = BUILT_IN_TRACK_PARTS) {
|
|
2547
2588
|
const piece = pieces.find((p) => p.id === anchor.piece);
|
|
@@ -2562,7 +2603,8 @@ function graphToDoc(pieces, input) {
|
|
|
2562
2603
|
const library = input.library ?? BUILT_IN_TRACK_PARTS;
|
|
2563
2604
|
const graph = buildTrackGraph(pieces, library);
|
|
2564
2605
|
const walk = walkTrackGraph(graph, pieces, input.startAt, library);
|
|
2565
|
-
const
|
|
2606
|
+
const dangling = new Set(walk.danglingDiverges.map(danglingDivergeWarning));
|
|
2607
|
+
const warnings = walk.warnings.filter((w) => !dangling.has(w));
|
|
2566
2608
|
const round = (n) => Math.round(n * 100) / 100;
|
|
2567
2609
|
const base = input.base ?? {};
|
|
2568
2610
|
const endplates = base.endplates && base.endplates.length ? base.endplates : [{ id: "A", label: "West" }, { id: "B", label: "East" }];
|
|
@@ -3374,6 +3416,7 @@ exports.endplateWidthInches = endplateWidthInches;
|
|
|
3374
3416
|
exports.flexPartFor = flexPartFor;
|
|
3375
3417
|
exports.flexParts = flexParts;
|
|
3376
3418
|
exports.flexPieces = flexPieces;
|
|
3419
|
+
exports.flexRunEnd = flexRunEnd;
|
|
3377
3420
|
exports.flexUsage = flexUsage;
|
|
3378
3421
|
exports.frogCasting = frogCasting;
|
|
3379
3422
|
exports.frogNumberFromName = frogNumberFromName;
|