@willcgage/module-schematic 0.82.0 → 0.83.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 +47 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -1
- package/dist/index.d.ts +73 -1
- package/dist/index.js +45 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -5,6 +5,46 @@ var FREEMO_ENDPLATE_WIDTH_MIN_INCHES = 12;
|
|
|
5
5
|
var FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES = 24;
|
|
6
6
|
var FREEMO_TRACK_SPACING_INCHES = 1.125;
|
|
7
7
|
var FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES = 4;
|
|
8
|
+
var PINCH_EASE_INCHES = 3;
|
|
9
|
+
function laneOffsetAt(lane, pos, pinches, spacingInches = FREEMO_TRACK_SPACING_INCHES) {
|
|
10
|
+
const base = (lane ?? 0) * spacingInches;
|
|
11
|
+
if (!lane || !pinches?.length) return base;
|
|
12
|
+
const sign = Math.sign(lane);
|
|
13
|
+
const smooth = (t) => t * t * (3 - 2 * t);
|
|
14
|
+
let off = base;
|
|
15
|
+
for (const p of pinches) {
|
|
16
|
+
if (p.lane !== lane) continue;
|
|
17
|
+
const a = Math.min(p.fromPos, p.toPos);
|
|
18
|
+
const b = Math.max(p.fromPos, p.toPos);
|
|
19
|
+
const target = base - sign * (spacingInches * Math.abs(lane) - p.spacingInches);
|
|
20
|
+
const e = PINCH_EASE_INCHES;
|
|
21
|
+
let t = null;
|
|
22
|
+
if (pos >= a && pos <= b) t = 1;
|
|
23
|
+
else if (pos > a - e && pos < a) t = smooth((pos - (a - e)) / e);
|
|
24
|
+
else if (pos > b && pos < b + e) t = smooth(1 - (pos - b) / e);
|
|
25
|
+
if (t == null) continue;
|
|
26
|
+
const candidate = base + (target - base) * t;
|
|
27
|
+
if (Math.abs(candidate - base) > Math.abs(off - base)) off = candidate;
|
|
28
|
+
}
|
|
29
|
+
return off;
|
|
30
|
+
}
|
|
31
|
+
function crossoverPinches(tracks, library = BUILT_IN_TRACK_PARTS, spacingInches = FREEMO_TRACK_SPACING_INCHES) {
|
|
32
|
+
const out = [];
|
|
33
|
+
for (const t of tracks) {
|
|
34
|
+
if (t.role !== "crossover" || !t.crossoverPartId) continue;
|
|
35
|
+
const part = library.find((p) => p.id === t.crossoverPartId);
|
|
36
|
+
const s = part?.trackSpacing?.inches;
|
|
37
|
+
if (typeof s !== "number" || !Number.isFinite(s) || s <= 0) continue;
|
|
38
|
+
if (Math.abs(s - spacingInches) < 1e-9) continue;
|
|
39
|
+
const lane = t.lane ?? 1;
|
|
40
|
+
if (!lane) continue;
|
|
41
|
+
const a = t.fromPos ?? 0;
|
|
42
|
+
const b = t.toPos ?? 0;
|
|
43
|
+
if (!Number.isFinite(a) || !Number.isFinite(b) || Math.abs(b - a) < 1e-9) continue;
|
|
44
|
+
out.push({ lane, fromPos: Math.min(a, b), toPos: Math.max(a, b), spacingInches: s });
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
8
48
|
function endplateWidthInches(ep) {
|
|
9
49
|
const w = ep?.widthInches;
|
|
10
50
|
return typeof w === "number" && w > 0 ? w : FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES;
|
|
@@ -943,6 +983,7 @@ function stateToDoc(state, recordNumber) {
|
|
|
943
983
|
}).scaleFeet,
|
|
944
984
|
...typeof t.measuredUsableInches === "number" && t.measuredUsableInches >= 0 ? { measuredUsableInches: t.measuredUsableInches } : {},
|
|
945
985
|
...state.loop && t.inLoop ? { inLoop: true } : {},
|
|
986
|
+
...t.crossoverPartId ? { crossoverPartId: t.crossoverPartId } : {},
|
|
946
987
|
...t.path && t.path.length >= 2 ? { path: t.path } : {}
|
|
947
988
|
}))
|
|
948
989
|
]),
|
|
@@ -1039,6 +1080,9 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
|
|
|
1039
1080
|
moduleTrackId,
|
|
1040
1081
|
trackName: t.trackName ?? nameOf(moduleTrackId),
|
|
1041
1082
|
...t.inLoop ? { inLoop: true } : {},
|
|
1083
|
+
// The crossover product this connector was built from — what makes the
|
|
1084
|
+
// physical view draw the pair at the spacing it was really built to.
|
|
1085
|
+
...typeof t.crossoverPartId === "string" && t.crossoverPartId ? { crossoverPartId: t.crossoverPartId } : {},
|
|
1042
1086
|
// Authored path kept as-drawn (a physical shape, not rescaled with length).
|
|
1043
1087
|
...trackPath(t.path) ? { path: trackPath(t.path) } : {},
|
|
1044
1088
|
// A MEASURED length is a real-world fact about the physical track, so it
|
|
@@ -2672,6 +2716,7 @@ exports.MAIN2_TRACK_ID = MAIN2_TRACK_ID;
|
|
|
2672
2716
|
exports.MAIN_TRACK_ID = MAIN_TRACK_ID;
|
|
2673
2717
|
exports.N_CAR_LENGTH_INCHES = N_CAR_LENGTH_INCHES;
|
|
2674
2718
|
exports.N_SCALE_RATIO = N_SCALE_RATIO;
|
|
2719
|
+
exports.PINCH_EASE_INCHES = PINCH_EASE_INCHES;
|
|
2675
2720
|
exports.RAIL_GAUGE_INCHES = RAIL_GAUGE_INCHES;
|
|
2676
2721
|
exports.TIE_HALF_LENGTH_INCHES = TIE_HALF_LENGTH_INCHES;
|
|
2677
2722
|
exports.TURNOUT_LEAD_INCHES_PER_FROG = TURNOUT_LEAD_INCHES_PER_FROG;
|
|
@@ -2687,6 +2732,7 @@ exports.buildTransition = buildTransition;
|
|
|
2687
2732
|
exports.carCapacity = carCapacity;
|
|
2688
2733
|
exports.checkEndplateWidth = checkEndplateWidth;
|
|
2689
2734
|
exports.clearancePointPastFrogInches = clearancePointPastFrogInches;
|
|
2735
|
+
exports.crossoverPinches = crossoverPinches;
|
|
2690
2736
|
exports.deriveEndplatePoses = deriveEndplatePoses;
|
|
2691
2737
|
exports.divergeSideForHand = divergeSideForHand;
|
|
2692
2738
|
exports.docToState = docToState;
|
|
@@ -2709,6 +2755,7 @@ exports.importedPartToTrackPart = importedPartToTrackPart;
|
|
|
2709
2755
|
exports.inchesToScaleFeet = inchesToScaleFeet;
|
|
2710
2756
|
exports.isLoopDoc = isLoopDoc;
|
|
2711
2757
|
exports.isTransitionTurnout = isTransitionTurnout;
|
|
2758
|
+
exports.laneOffsetAt = laneOffsetAt;
|
|
2712
2759
|
exports.leadInchesForSize = leadInchesForSize;
|
|
2713
2760
|
exports.maxFlexPieceInches = maxFlexPieceInches;
|
|
2714
2761
|
exports.mergeImportedParts = mergeImportedParts;
|