@willcgage/module-schematic 0.50.0 → 0.52.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 CHANGED
@@ -831,7 +831,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
831
831
  const len = fallbackLength > 0 ? fallbackLength : hasDoc ? d.lengthInches : 24;
832
832
  const docLen = hasDoc && d.lengthInches > 0 ? d.lengthInches : len;
833
833
  const scale = docLen > 0 ? len / docLen : 1;
834
- const sc = (p) => Math.round(p * scale);
834
+ const sc = (p) => Math.round(p * scale * 100) / 100;
835
835
  const nameOf = (id) => {
836
836
  const mt = id != null ? moduleTracks.find((m) => m.id === id) : void 0;
837
837
  return mt?.track_name ?? "";
@@ -1092,6 +1092,160 @@ function buildCrossover(state) {
1092
1092
  }
1093
1093
  var RAIL_GAUGE_INCHES = 0.354;
1094
1094
  var TURNOUT_LEAD_INCHES_PER_FROG = 0.482;
1095
+ var CODE55_RAIL_HEIGHT_INCHES = 0.055;
1096
+ var ATLAS_CODE55_N = [
1097
+ {
1098
+ id: "atlas-c55-n-5",
1099
+ manufacturer: "Atlas",
1100
+ line: "Code 55",
1101
+ scale: "N",
1102
+ name: "#5 Turnout",
1103
+ kind: "turnout",
1104
+ partNumbers: { left: "2050", right: "2051" },
1105
+ frogNumber: 5,
1106
+ lead: {
1107
+ inches: 5 * TURNOUT_LEAD_INCHES_PER_FROG,
1108
+ source: "derived",
1109
+ note: "scaled from the measured #7 by frog number \u2014 not measured"
1110
+ }
1111
+ },
1112
+ {
1113
+ id: "atlas-c55-n-7",
1114
+ manufacturer: "Atlas",
1115
+ line: "Code 55",
1116
+ scale: "N",
1117
+ name: "#7 Turnout",
1118
+ kind: "turnout",
1119
+ partNumbers: { left: "2052", right: "2053" },
1120
+ frogNumber: 7,
1121
+ lead: {
1122
+ inches: 3.375,
1123
+ source: "measured",
1124
+ note: "Steve Branton, physical Atlas code 55 #7, 3\u215C\u2033 points\u2192frog (#173)"
1125
+ }
1126
+ },
1127
+ {
1128
+ id: "atlas-c55-n-10",
1129
+ manufacturer: "Atlas",
1130
+ line: "Code 55",
1131
+ scale: "N",
1132
+ name: "#10 Turnout",
1133
+ kind: "turnout",
1134
+ partNumbers: { left: "2054", right: "2055" },
1135
+ frogNumber: 10,
1136
+ lead: {
1137
+ inches: 10 * TURNOUT_LEAD_INCHES_PER_FROG,
1138
+ source: "derived",
1139
+ note: "scaled from the measured #7 by frog number \u2014 not measured"
1140
+ }
1141
+ },
1142
+ {
1143
+ id: "atlas-c55-n-wye",
1144
+ manufacturer: "Atlas",
1145
+ line: "Code 55",
1146
+ scale: "N",
1147
+ name: "#2.5 Wye",
1148
+ kind: "wye",
1149
+ partNumbers: { single: "2056" },
1150
+ frogNumber: 2.5,
1151
+ lead: {
1152
+ inches: 2.5 * TURNOUT_LEAD_INCHES_PER_FROG,
1153
+ source: "derived",
1154
+ note: "scaled from the measured #7 by frog number \u2014 not measured"
1155
+ }
1156
+ },
1157
+ {
1158
+ id: "atlas-c55-n-curved-21-15",
1159
+ manufacturer: "Atlas",
1160
+ line: "Code 55",
1161
+ scale: "N",
1162
+ name: 'Curved Turnout 21\xBC" / 15"',
1163
+ kind: "curved-turnout",
1164
+ partNumbers: { left: "2058", right: "2059" },
1165
+ outerRadius: { inches: 21.25, source: "manufacturer", note: "Atlas product listing" },
1166
+ innerRadius: { inches: 15, source: "manufacturer", note: "Atlas product listing" }
1167
+ }
1168
+ ];
1169
+ var BUILT_IN_TRACK_PARTS = [...ATLAS_CODE55_N];
1170
+ function trackPart(id, library = BUILT_IN_TRACK_PARTS) {
1171
+ return library.find((p) => p.id === id) ?? null;
1172
+ }
1173
+ function turnoutPartForSize(size, library = BUILT_IN_TRACK_PARTS) {
1174
+ const turnouts = library.filter((p) => p.kind === "turnout" && p.frogNumber != null);
1175
+ if (!turnouts.length) return null;
1176
+ return turnouts.reduce(
1177
+ (best, p) => Math.abs(p.frogNumber - size) < Math.abs(best.frogNumber - size) ? p : best
1178
+ );
1179
+ }
1180
+ function leadInchesForSize(size, library = BUILT_IN_TRACK_PARTS) {
1181
+ const part = turnoutPartForSize(size, library);
1182
+ if (part?.lead && part.frogNumber === size) return part.lead.inches;
1183
+ return size * TURNOUT_LEAD_INCHES_PER_FROG;
1184
+ }
1185
+ function parseXtpLibrary(text) {
1186
+ const parts = [];
1187
+ let cur = null;
1188
+ for (const raw of text.split(/\r?\n/)) {
1189
+ const line = raw.trim();
1190
+ if (!line || line.startsWith("#")) continue;
1191
+ if (line.startsWith("TURNOUT")) {
1192
+ const quoted = line.match(/"([^"]*)"/);
1193
+ const scale = line.split(/\s+/)[1];
1194
+ const title = quoted?.[1] ?? "";
1195
+ const bits = title.split(" ").map((s) => s.trim()).filter(Boolean);
1196
+ cur = {
1197
+ title,
1198
+ scale,
1199
+ manufacturer: bits[0],
1200
+ name: bits[1],
1201
+ partNumber: bits[2],
1202
+ ends: [],
1203
+ segments: []
1204
+ };
1205
+ continue;
1206
+ }
1207
+ if (!cur) continue;
1208
+ if (line === "END") {
1209
+ if (cur.ends.length || cur.segments.length) parts.push(cur);
1210
+ cur = null;
1211
+ continue;
1212
+ }
1213
+ const n = line.split(/\s+/);
1214
+ const num = (i) => Number(n[i]);
1215
+ if (n[0] === "E" && n.length >= 4) {
1216
+ cur.ends.push({ x: num(1), y: num(2), angleDeg: num(3) });
1217
+ } else if (n[0] === "S" && n.length >= 7) {
1218
+ cur.segments.push({ kind: "straight", x0: num(3), y0: num(4), x1: num(5), y1: num(6) });
1219
+ } else if (n[0] === "C" && n.length >= 8) {
1220
+ cur.segments.push({
1221
+ kind: "curve",
1222
+ radius: num(3),
1223
+ cx: num(4),
1224
+ cy: num(5),
1225
+ startDeg: num(6),
1226
+ extentDeg: num(7)
1227
+ });
1228
+ }
1229
+ }
1230
+ return parts;
1231
+ }
1232
+ function samplePartSegments(segments, stepsPerCurve = 16) {
1233
+ return segments.map((s) => {
1234
+ if (s.kind === "straight") {
1235
+ return [
1236
+ { x: s.x0, y: s.y0 },
1237
+ { x: s.x1, y: s.y1 }
1238
+ ];
1239
+ }
1240
+ const r = Math.abs(s.radius);
1241
+ const out = [];
1242
+ for (let i = 0; i <= stepsPerCurve; i++) {
1243
+ const a = (s.startDeg + s.extentDeg * i / stepsPerCurve) * Math.PI / 180;
1244
+ out.push({ x: s.cx + r * Math.sin(a), y: s.cy + r * Math.cos(a) });
1245
+ }
1246
+ return out;
1247
+ });
1248
+ }
1095
1249
  function turnoutClosure(size, opts = {}) {
1096
1250
  const N = size > 0 ? size : 6;
1097
1251
  const g = opts.gaugeInches ?? RAIL_GAUGE_INCHES;
@@ -1621,6 +1775,9 @@ function poseOverridesFromDoc(doc) {
1621
1775
  return out;
1622
1776
  }
1623
1777
 
1778
+ exports.ATLAS_CODE55_N = ATLAS_CODE55_N;
1779
+ exports.BUILT_IN_TRACK_PARTS = BUILT_IN_TRACK_PARTS;
1780
+ exports.CODE55_RAIL_HEIGHT_INCHES = CODE55_RAIL_HEIGHT_INCHES;
1624
1781
  exports.ENDPLATE_FASCIA_CLEAR_INCHES = ENDPLATE_FASCIA_CLEAR_INCHES;
1625
1782
  exports.ENDPLATE_LEAD_INCHES = ENDPLATE_LEAD_INCHES;
1626
1783
  exports.FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES = FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES;
@@ -1656,17 +1813,20 @@ exports.geometryTurnDegrees = geometryTurnDegrees;
1656
1813
  exports.inchesToScaleFeet = inchesToScaleFeet;
1657
1814
  exports.isLoopDoc = isLoopDoc;
1658
1815
  exports.isTransitionTurnout = isTransitionTurnout;
1816
+ exports.leadInchesForSize = leadInchesForSize;
1659
1817
  exports.moduleCenterline = moduleCenterline;
1660
1818
  exports.moduleFeatures = moduleFeatures;
1661
1819
  exports.moduleFootprint = moduleFootprint;
1662
1820
  exports.moduleLengthFromSections = moduleLengthFromSections;
1663
1821
  exports.moduleSections = moduleSections;
1664
1822
  exports.nextId = nextId;
1823
+ exports.parseXtpLibrary = parseXtpLibrary;
1665
1824
  exports.poseNeedsManual = poseNeedsManual;
1666
1825
  exports.poseOverridesFromDoc = poseOverridesFromDoc;
1667
1826
  exports.remapPos = remapPos;
1668
1827
  exports.returnLoop = returnLoop;
1669
1828
  exports.sampleBenchworkOutline = sampleBenchworkOutline;
1829
+ exports.samplePartSegments = samplePartSegments;
1670
1830
  exports.samplePath = samplePath;
1671
1831
  exports.scaleFeetToInches = scaleFeetToInches;
1672
1832
  exports.sectionAdjacency = sectionAdjacency;
@@ -1683,7 +1843,9 @@ exports.sliceCenterline = sliceCenterline;
1683
1843
  exports.stateToDoc = stateToDoc;
1684
1844
  exports.toSectionRelative = toSectionRelative;
1685
1845
  exports.trackMeetsEndplateIssues = trackMeetsEndplateIssues;
1846
+ exports.trackPart = trackPart;
1686
1847
  exports.trackPath = trackPath;
1687
1848
  exports.turnoutClosure = turnoutClosure;
1849
+ exports.turnoutPartForSize = turnoutPartForSize;
1688
1850
  //# sourceMappingURL=index.cjs.map
1689
1851
  //# sourceMappingURL=index.cjs.map