@willcgage/module-schematic 0.81.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 +57 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +121 -11
- package/dist/index.d.ts +121 -11
- package/dist/index.js +55 -4
- 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
|
|
@@ -1588,11 +1632,12 @@ var FAST_TRACKS_N_ME55_CROSSOVERS = [
|
|
|
1588
1632
|
manufacturer: "Fast Tracks",
|
|
1589
1633
|
line: "Code 55",
|
|
1590
1634
|
scale: "N",
|
|
1591
|
-
name: `#${n} Crossover`,
|
|
1635
|
+
name: `#${n} Double Crossover`,
|
|
1592
1636
|
kind: "crossover",
|
|
1593
1637
|
partNumbers: { single: `AF-N-C-${n}-ME55` },
|
|
1594
1638
|
frogNumber: n,
|
|
1595
1639
|
buildable: true,
|
|
1640
|
+
piecesPerAssembly: 2,
|
|
1596
1641
|
actualAngle: { deg, source: manufacturer, note: `${spec}. atan(1/${n}) exactly.` },
|
|
1597
1642
|
secondaryFrogAngle: {
|
|
1598
1643
|
deg: second,
|
|
@@ -1602,9 +1647,13 @@ var FAST_TRACKS_N_ME55_CROSSOVERS = [
|
|
|
1602
1647
|
overallLength: {
|
|
1603
1648
|
inches: dflt,
|
|
1604
1649
|
source: manufacturer,
|
|
1605
|
-
note: `${spec}.
|
|
1650
|
+
note: `${spec}. \u26A0\uFE0F ONE HALF, NOT THE FINISHED CROSSOVER \u2014 the fixture builds a symmetrical half, which you build twice and butt together after turning the second 180\xB0. Fast Tracks gloss it as "the length of the turnout on the QuickSticks", i.e. the piece in the jig. The DEFAULT for that piece; it is a fixture, so the builder chooses.`
|
|
1651
|
+
},
|
|
1652
|
+
minimumLength: {
|
|
1653
|
+
inches: min,
|
|
1654
|
+
source: manufacturer,
|
|
1655
|
+
note: `${spec}. The shortest ONE HALF can be built \u2014 see the overall length's note.`
|
|
1606
1656
|
},
|
|
1607
|
-
minimumLength: { inches: min, source: manufacturer, note: spec },
|
|
1608
1657
|
trackSpacing: {
|
|
1609
1658
|
inches: spacing,
|
|
1610
1659
|
source: manufacturer,
|
|
@@ -1953,6 +2002,8 @@ function storedPartToTrackPart(row) {
|
|
|
1953
2002
|
...note ? { note } : {}
|
|
1954
2003
|
};
|
|
1955
2004
|
if (row.buildable) part.buildable = true;
|
|
2005
|
+
if (typeof row.piecesPerAssembly === "number" && row.piecesPerAssembly > 1)
|
|
2006
|
+
part.piecesPerAssembly = row.piecesPerAssembly;
|
|
1956
2007
|
if (lead) part.lead = lead;
|
|
1957
2008
|
const outer = dim(row.outerRadiusInches, row.radiusSource);
|
|
1958
2009
|
const inner = dim(row.innerRadiusInches, row.radiusSource);
|
|
@@ -2665,6 +2716,7 @@ exports.MAIN2_TRACK_ID = MAIN2_TRACK_ID;
|
|
|
2665
2716
|
exports.MAIN_TRACK_ID = MAIN_TRACK_ID;
|
|
2666
2717
|
exports.N_CAR_LENGTH_INCHES = N_CAR_LENGTH_INCHES;
|
|
2667
2718
|
exports.N_SCALE_RATIO = N_SCALE_RATIO;
|
|
2719
|
+
exports.PINCH_EASE_INCHES = PINCH_EASE_INCHES;
|
|
2668
2720
|
exports.RAIL_GAUGE_INCHES = RAIL_GAUGE_INCHES;
|
|
2669
2721
|
exports.TIE_HALF_LENGTH_INCHES = TIE_HALF_LENGTH_INCHES;
|
|
2670
2722
|
exports.TURNOUT_LEAD_INCHES_PER_FROG = TURNOUT_LEAD_INCHES_PER_FROG;
|
|
@@ -2680,6 +2732,7 @@ exports.buildTransition = buildTransition;
|
|
|
2680
2732
|
exports.carCapacity = carCapacity;
|
|
2681
2733
|
exports.checkEndplateWidth = checkEndplateWidth;
|
|
2682
2734
|
exports.clearancePointPastFrogInches = clearancePointPastFrogInches;
|
|
2735
|
+
exports.crossoverPinches = crossoverPinches;
|
|
2683
2736
|
exports.deriveEndplatePoses = deriveEndplatePoses;
|
|
2684
2737
|
exports.divergeSideForHand = divergeSideForHand;
|
|
2685
2738
|
exports.docToState = docToState;
|
|
@@ -2702,6 +2755,7 @@ exports.importedPartToTrackPart = importedPartToTrackPart;
|
|
|
2702
2755
|
exports.inchesToScaleFeet = inchesToScaleFeet;
|
|
2703
2756
|
exports.isLoopDoc = isLoopDoc;
|
|
2704
2757
|
exports.isTransitionTurnout = isTransitionTurnout;
|
|
2758
|
+
exports.laneOffsetAt = laneOffsetAt;
|
|
2705
2759
|
exports.leadInchesForSize = leadInchesForSize;
|
|
2706
2760
|
exports.maxFlexPieceInches = maxFlexPieceInches;
|
|
2707
2761
|
exports.mergeImportedParts = mergeImportedParts;
|