@willcgage/module-schematic 0.96.0 → 0.97.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
@@ -2019,14 +2019,14 @@ function storedPartToTrackPart(row) {
2019
2019
  source: points.source === "measured" && frog.source === "measured" ? "measured" : "derived",
2020
2020
  ...note ? { note } : {}
2021
2021
  } : dim(row.leadInches, row.leadSource);
2022
- const kind = row.kind;
2022
+ const kind = TRACK_PART_KINDS.includes(row.kind) ? row.kind : "turnout";
2023
2023
  const part = {
2024
2024
  id: row.slug,
2025
2025
  manufacturer: row.manufacturer,
2026
2026
  line: row.line,
2027
2027
  scale: "N",
2028
2028
  name: row.name,
2029
- kind: kind === "wye" || kind === "curved-turnout" || kind === "crossing" ? kind : "turnout"
2029
+ kind
2030
2030
  };
2031
2031
  const numbers = {
2032
2032
  ...row.partNumberLeft ? { left: row.partNumberLeft } : {},
@@ -2061,6 +2061,9 @@ function storedPartToTrackPart(row) {
2061
2061
  const inner = dim(row.innerRadiusInches, row.radiusSource);
2062
2062
  if (outer) part.outerRadius = outer;
2063
2063
  if (inner) part.innerRadius = inner;
2064
+ const radius = dim(row.radiusInches, row.radiusSource);
2065
+ if (radius) part.radius = radius;
2066
+ if (typeof row.arcDegrees === "number") part.arcDegrees = row.arcDegrees;
2064
2067
  if (typeof row.actualAngleDeg === "number")
2065
2068
  part.actualAngle = {
2066
2069
  deg: row.actualAngleDeg,
@@ -2174,6 +2177,13 @@ function turnoutClosure(size, opts = {}) {
2174
2177
  function partGeometryGap(part) {
2175
2178
  if (part.kind === "flex") return null;
2176
2179
  if (part.kind === "bumper") return null;
2180
+ if (part.kind === "straight")
2181
+ return part.overallLength ? null : "no overall length \u2014 a sectional straight IS its length";
2182
+ if (part.kind === "curve") {
2183
+ if (!part.radius) return "no radius \u2014 a sectional curve is a radius and an arc";
2184
+ if (part.arcDegrees == null) return "no arc \u2014 the radius alone does not say how far it turns";
2185
+ return null;
2186
+ }
2177
2187
  if (part.kind === "crossover")
2178
2188
  return "a crossover fixture builds one HALF of the assembly (piecesPerAssembly), so its published lengths describe a piece, not the finished part \u2014 the geometry of the whole crossover is not yet derivable from them";
2179
2189
  if (part.kind === "crossing") return "crossing geometry is not modelled yet";
@@ -2187,6 +2197,18 @@ function partGeometryGap(part) {
2187
2197
  }
2188
2198
  function partGeometry(part, library = BUILT_IN_TRACK_PARTS) {
2189
2199
  if (partGeometryGap(part)) return null;
2200
+ if (part.kind === "straight" || part.kind === "curve") {
2201
+ const end = part.kind === "curve" ? flexRunEnd(sectionalArcInches(part), part.radius.inches) : { x: part.overallLength.inches, y: 0, headingDeg: 0 };
2202
+ return {
2203
+ joints: [
2204
+ { id: "a", role: "throat", x: 0, y: 0, angleDeg: 180 },
2205
+ { id: "b", role: "through", x: end.x, y: end.y, angleDeg: end.headingDeg }
2206
+ ],
2207
+ routes: [["a", "b"]],
2208
+ source: (part.kind === "curve" ? part.radius : part.overallLength)?.source ?? "unverified",
2209
+ divergingEndMeasured: false
2210
+ };
2211
+ }
2190
2212
  if (part.kind === "bumper") {
2191
2213
  return {
2192
2214
  joints: [{ id: "a", role: "throat", x: 0, y: 0, angleDeg: 180 }],
@@ -2354,7 +2376,22 @@ function partsPlaceable(library = BUILT_IN_TRACK_PARTS) {
2354
2376
  return { placeable, blocked };
2355
2377
  }
2356
2378
  var JOINT_SNAP_INCHES = 0.01;
2379
+ var TRACK_PART_KINDS = [
2380
+ "turnout",
2381
+ "wye",
2382
+ "curved-turnout",
2383
+ "crossover",
2384
+ "crossing",
2385
+ "flex",
2386
+ "straight",
2387
+ "curve",
2388
+ "bumper"
2389
+ ];
2357
2390
  var BUMPER_DRAWN_INCHES = 0.75;
2391
+ function sectionalArcInches(part) {
2392
+ if (part.kind !== "curve" || !part.radius || part.arcDegrees == null) return 0;
2393
+ return part.radius.inches * Math.abs(part.arcDegrees) * Math.PI / 180;
2394
+ }
2358
2395
  function flexRunEnd(lengthInches, radiusInches) {
2359
2396
  const L = lengthInches;
2360
2397
  const R = radiusInches;
@@ -2530,6 +2567,7 @@ function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS)
2530
2567
  const piece = pieceById.get(a.piece);
2531
2568
  const part = piece ? partOf(a.piece) : void 0;
2532
2569
  if (piece && part?.kind === "flex") return piece.lengthInches ?? 0;
2570
+ if (part?.kind === "curve") return sectionalArcInches(part);
2533
2571
  }
2534
2572
  return Math.hypot(a.x - b.x, a.y - b.y);
2535
2573
  };
@@ -3541,6 +3579,7 @@ exports.N_SCALE_RATIO = N_SCALE_RATIO;
3541
3579
  exports.PINCH_EASE_INCHES = PINCH_EASE_INCHES;
3542
3580
  exports.RAIL_GAUGE_INCHES = RAIL_GAUGE_INCHES;
3543
3581
  exports.TIE_HALF_LENGTH_INCHES = TIE_HALF_LENGTH_INCHES;
3582
+ exports.TRACK_PART_KINDS = TRACK_PART_KINDS;
3544
3583
  exports.TURNOUT_LEAD_INCHES_PER_FROG = TURNOUT_LEAD_INCHES_PER_FROG;
3545
3584
  exports.WHOLE_MODULE_SECTION_ID = WHOLE_MODULE_SECTION_ID;
3546
3585
  exports.asModuleSchematic = asModuleSchematic;
@@ -3625,6 +3664,7 @@ exports.sectionFootprints = sectionFootprints;
3625
3664
  exports.sectionNeighbours = sectionNeighbours;
3626
3665
  exports.sectionSpans = sectionSpans;
3627
3666
  exports.sectionSpansOrWhole = sectionSpansOrWhole;
3667
+ exports.sectionalArcInches = sectionalArcInches;
3628
3668
  exports.sectionedCenterline = sectionedCenterline;
3629
3669
  exports.sectionedEndPose = sectionedEndPose;
3630
3670
  exports.sliceCenterline = sliceCenterline;