@willcgage/module-schematic 0.73.0 → 0.75.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 +87 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -1
- package/dist/index.d.ts +75 -1
- package/dist/index.js +85 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -577,6 +577,56 @@ function scaleFeetToInches(feet, ratio = N_SCALE_RATIO) {
|
|
|
577
577
|
return feet * 12 / ratio;
|
|
578
578
|
}
|
|
579
579
|
var N_CAR_LENGTH_INCHES = 3.3;
|
|
580
|
+
var CLEARANCE_SPACING_INCHES = FREEMO_TRACK_SPACING_INCHES;
|
|
581
|
+
function clearancePointPastFrogInches(size, library = BUILT_IN_TRACK_PARTS, clearanceInches = CLEARANCE_SPACING_INCHES) {
|
|
582
|
+
const N = size > 0 ? size : 6;
|
|
583
|
+
const lead = leadInchesForSize(N, library);
|
|
584
|
+
const cl = turnoutClosure(N, { leadInches: lead });
|
|
585
|
+
let lo = 0;
|
|
586
|
+
let hi = Math.max(4 * lead, 4 * clearanceInches * N);
|
|
587
|
+
if (cl.offsetAt(hi) < clearanceInches) return hi - lead;
|
|
588
|
+
for (let i = 0; i < 60; i++) {
|
|
589
|
+
const mid = (lo + hi) / 2;
|
|
590
|
+
if (cl.offsetAt(mid) < clearanceInches) lo = mid;
|
|
591
|
+
else hi = mid;
|
|
592
|
+
}
|
|
593
|
+
return Math.max(0, hi - lead);
|
|
594
|
+
}
|
|
595
|
+
function usableCapacity(input) {
|
|
596
|
+
const lo = Math.min(input.fromPos, input.toPos);
|
|
597
|
+
const hi = Math.max(input.fromPos, input.toPos);
|
|
598
|
+
const drawn = hi - lo;
|
|
599
|
+
const carLen = input.carLengthInches ?? N_CAR_LENGTH_INCHES;
|
|
600
|
+
if (typeof input.measuredUsableInches === "number" && input.measuredUsableInches >= 0) {
|
|
601
|
+
const m = input.measuredUsableInches;
|
|
602
|
+
return {
|
|
603
|
+
fromPos: lo,
|
|
604
|
+
toPos: lo + m,
|
|
605
|
+
usableInches: m,
|
|
606
|
+
drawnInches: drawn,
|
|
607
|
+
givenUpInches: Math.max(0, drawn - m),
|
|
608
|
+
cars: carCapacity(0, m, carLen),
|
|
609
|
+
scaleFeet: Math.round(inchesToScaleFeet(m))
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
let a = lo;
|
|
613
|
+
let b = hi;
|
|
614
|
+
for (const sw of input.governing ?? []) {
|
|
615
|
+
const c = clearancePointPastFrogInches(sw.size ?? 6, input.library);
|
|
616
|
+
if (Math.abs(sw.pos - lo) <= Math.abs(sw.pos - hi)) a = Math.max(a, lo + c);
|
|
617
|
+
else b = Math.min(b, hi - c);
|
|
618
|
+
}
|
|
619
|
+
const usable = Math.max(0, b - a);
|
|
620
|
+
return {
|
|
621
|
+
fromPos: a,
|
|
622
|
+
toPos: Math.max(a, b),
|
|
623
|
+
usableInches: usable,
|
|
624
|
+
drawnInches: drawn,
|
|
625
|
+
givenUpInches: Math.max(0, drawn - usable),
|
|
626
|
+
cars: carCapacity(0, usable, carLen),
|
|
627
|
+
scaleFeet: Math.round(inchesToScaleFeet(usable))
|
|
628
|
+
};
|
|
629
|
+
}
|
|
580
630
|
function spanOverhang(input) {
|
|
581
631
|
const lo = Math.min(input.fromPos, input.toPos);
|
|
582
632
|
const hi = Math.max(input.fromPos, input.toPos);
|
|
@@ -827,7 +877,17 @@ function stateToDoc(state, recordNumber) {
|
|
|
827
877
|
toPos: t.toPos,
|
|
828
878
|
moduleTrackId: t.moduleTrackId,
|
|
829
879
|
trackName: t.trackName || void 0,
|
|
830
|
-
|
|
880
|
+
// ⚠️ USABLE capacity, measured from the governing turnouts' CLEARANCE
|
|
881
|
+
// POINTS (#19) — not the drawn rail-to-rail length, which counts track
|
|
882
|
+
// a car can't stand on without fouling the route it diverged from.
|
|
883
|
+
// FMN-0040's 70″ siding is 21 cars drawn and 17 usable.
|
|
884
|
+
capacityFeet: usableCapacity({
|
|
885
|
+
fromPos: t.fromPos,
|
|
886
|
+
toPos: t.toPos,
|
|
887
|
+
governing: state.turnouts.filter((sw) => sw.divergeTrack === t.id),
|
|
888
|
+
measuredUsableInches: t.measuredUsableInches
|
|
889
|
+
}).scaleFeet,
|
|
890
|
+
...typeof t.measuredUsableInches === "number" && t.measuredUsableInches >= 0 ? { measuredUsableInches: t.measuredUsableInches } : {},
|
|
831
891
|
...state.loop && t.inLoop ? { inLoop: true } : {},
|
|
832
892
|
...t.path && t.path.length >= 2 ? { path: t.path } : {}
|
|
833
893
|
}))
|
|
@@ -926,7 +986,10 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
926
986
|
trackName: t.trackName ?? nameOf(moduleTrackId),
|
|
927
987
|
...t.inLoop ? { inLoop: true } : {},
|
|
928
988
|
// Authored path kept as-drawn (a physical shape, not rescaled with length).
|
|
929
|
-
...trackPath(t.path) ? { path: trackPath(t.path) } : {}
|
|
989
|
+
...trackPath(t.path) ? { path: trackPath(t.path) } : {},
|
|
990
|
+
// A MEASURED length is a real-world fact about the physical track, so it
|
|
991
|
+
// rescales with the module exactly as its positions do (#20).
|
|
992
|
+
...typeof t.measuredUsableInches === "number" && Number.isFinite(t.measuredUsableInches) ? { measuredUsableInches: sc(t.measuredUsableInches) } : {}
|
|
930
993
|
});
|
|
931
994
|
}
|
|
932
995
|
}
|
|
@@ -1301,6 +1364,25 @@ var ATLAS_CODE55_N = [
|
|
|
1301
1364
|
note: "scaled from the measured #7 by frog number \u2014 not measured"
|
|
1302
1365
|
}
|
|
1303
1366
|
},
|
|
1367
|
+
{
|
|
1368
|
+
// Will Gage, 2026-07-26: "2057 is 3.5, 2056 is 2.5" — the two Atlas Code 55
|
|
1369
|
+
// wyes are different FROG NUMBERS, not a left/right pair of one part. The
|
|
1370
|
+
// 2056 half of that confirms the entry above; this is the one we didn't have.
|
|
1371
|
+
//
|
|
1372
|
+
// No lead. The #2.5's is `derived` from a per-frog rule its own note records
|
|
1373
|
+
// as refuted, so it rests on nothing — repeating that for a second part
|
|
1374
|
+
// would be exactly how a number nobody checked becomes two. Without one,
|
|
1375
|
+
// `leadInchesForSize` interpolates across the MEASURED parts at the wye's
|
|
1376
|
+
// effective frog (3.5 × 2 = 7), which lands on the measured #7.
|
|
1377
|
+
id: "atlas-c55-n-wye-35",
|
|
1378
|
+
manufacturer: "Atlas",
|
|
1379
|
+
line: "Code 55",
|
|
1380
|
+
scale: "N",
|
|
1381
|
+
name: "#3.5 Wye",
|
|
1382
|
+
kind: "wye",
|
|
1383
|
+
partNumbers: { single: "2057" },
|
|
1384
|
+
frogNumber: 3.5
|
|
1385
|
+
},
|
|
1304
1386
|
{
|
|
1305
1387
|
id: "atlas-c55-n-curved-21-15",
|
|
1306
1388
|
manufacturer: "Atlas",
|
|
@@ -2345,6 +2427,7 @@ function poseOverridesFromDoc(doc) {
|
|
|
2345
2427
|
|
|
2346
2428
|
exports.ATLAS_CODE55_N = ATLAS_CODE55_N;
|
|
2347
2429
|
exports.BUILT_IN_TRACK_PARTS = BUILT_IN_TRACK_PARTS;
|
|
2430
|
+
exports.CLEARANCE_SPACING_INCHES = CLEARANCE_SPACING_INCHES;
|
|
2348
2431
|
exports.CODE55_RAIL_HEIGHT_INCHES = CODE55_RAIL_HEIGHT_INCHES;
|
|
2349
2432
|
exports.DEFAULT_FLEX_PART_ID = DEFAULT_FLEX_PART_ID;
|
|
2350
2433
|
exports.ENDPLATE_FASCIA_CLEAR_INCHES = ENDPLATE_FASCIA_CLEAR_INCHES;
|
|
@@ -2370,6 +2453,7 @@ exports.buildPassingSiding = buildPassingSiding;
|
|
|
2370
2453
|
exports.buildTransition = buildTransition;
|
|
2371
2454
|
exports.carCapacity = carCapacity;
|
|
2372
2455
|
exports.checkEndplateWidth = checkEndplateWidth;
|
|
2456
|
+
exports.clearancePointPastFrogInches = clearancePointPastFrogInches;
|
|
2373
2457
|
exports.deriveEndplatePoses = deriveEndplatePoses;
|
|
2374
2458
|
exports.divergeSideForHand = divergeSideForHand;
|
|
2375
2459
|
exports.docToState = docToState;
|
|
@@ -2439,5 +2523,6 @@ exports.turnoutClosure = turnoutClosure;
|
|
|
2439
2523
|
exports.turnoutFacing = turnoutFacing;
|
|
2440
2524
|
exports.turnoutOccupiedSpan = turnoutOccupiedSpan;
|
|
2441
2525
|
exports.turnoutPartForSize = turnoutPartForSize;
|
|
2526
|
+
exports.usableCapacity = usableCapacity;
|
|
2442
2527
|
//# sourceMappingURL=index.cjs.map
|
|
2443
2528
|
//# sourceMappingURL=index.cjs.map
|