@willcgage/module-schematic 0.27.0 → 0.28.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.d.cts CHANGED
@@ -48,6 +48,15 @@ interface SchematicEndplate {
48
48
  * recommended. Absent = the recommended default (modules may differ end to
49
49
  * end, e.g. a transition). */
50
50
  widthInches?: number | null;
51
+ /** Where this end's PRIMARY track (Main 1) crosses, as a signed distance from
52
+ * the plate's CENTRE in inches — the standard's own framing ("each track
53
+ * 0.5625 inches from the center of the endplate"). §2.0 requires only that
54
+ * every track stay ≥4″ from either fascia; centring is a recommendation the
55
+ * 20220628 revision relaxed, so an offset is legal — a transition SECTION
56
+ * commonly offsets its single-track end so the through main lines up with one
57
+ * of the two tracks at its double end. Absent = the recommended default
58
+ * (single centred; double straddling at ∓ half the track spacing). */
59
+ trackOffsetInches?: number | null;
51
60
  }
52
61
  /** Free-moN endplate face width, inches — the connection interface size. */
53
62
  declare const FREEMO_ENDPLATE_WIDTH_MIN_INCHES = 12;
@@ -337,7 +346,14 @@ declare function moduleFootprint(input: ModuleFootprintInput): ModuleFootprint;
337
346
  * side of the plate centre (§2.0 RP), and Main 1 sits on the centre-line, so the
338
347
  * plate centre is half a track spacing up. A single track crosses at the centre.
339
348
  */
340
- declare function endplateTrackOffsetFor(config: TrackConfig | "none" | undefined): number;
349
+ declare function endplateTrackOffsetFor(config: TrackConfig | "none" | undefined, authoredTrackOffset?: number | null): number;
350
+ /**
351
+ * Where an endplate's PRIMARY track (Main 1) crosses, as a signed distance from
352
+ * the plate's CENTRE — the standard's own framing. Authored value wins; absent
353
+ * falls back to the §2.0 recommendations: a single track centred (0), a double
354
+ * straddling so its two tracks land ∓ half the track spacing (Main 1 low).
355
+ */
356
+ declare function endplateTrackOffsetInches(authored: number | null | undefined, config: TrackConfig | "none" | undefined): number;
341
357
  /** A Free-moN conformance problem with an endplate's width/track placement. */
342
358
  interface EndplateWidthIssue {
343
359
  /** "narrow" = below the 12″ minimum; "clearance" = a track too near a fascia. */
@@ -505,6 +521,9 @@ interface EditorState {
505
521
  /** Authored endplate face widths by endplate id, inches (Free-moN 12″ min,
506
522
  * 24″ recommended). Absent id = the recommended default. */
507
523
  endplateWidths: Record<string, number>;
524
+ /** Authored per-endplate TRACK offsets by id — the primary track's signed
525
+ * distance from the plate centre, inches. Absent id = the §2.0 default. */
526
+ endplateTrackOffsets: Record<string, number>;
508
527
  /** Benchwork footprint outline — polygon vertices in module-local inches
509
528
  * (endplate A's track point at the origin, mainline +x, perpendicular +y up).
510
529
  * Empty = no authored outline (fall back to the endplate-width band). */
@@ -796,4 +815,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
796
815
  heading: number;
797
816
  }>;
798
817
 
799
- export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateWidthIssue, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type GeometryType, type IndustryLabelMode, type IndustrySpot, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
818
+ export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateWidthIssue, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type GeometryType, type IndustryLabelMode, type IndustrySpot, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
package/dist/index.d.ts CHANGED
@@ -48,6 +48,15 @@ interface SchematicEndplate {
48
48
  * recommended. Absent = the recommended default (modules may differ end to
49
49
  * end, e.g. a transition). */
50
50
  widthInches?: number | null;
51
+ /** Where this end's PRIMARY track (Main 1) crosses, as a signed distance from
52
+ * the plate's CENTRE in inches — the standard's own framing ("each track
53
+ * 0.5625 inches from the center of the endplate"). §2.0 requires only that
54
+ * every track stay ≥4″ from either fascia; centring is a recommendation the
55
+ * 20220628 revision relaxed, so an offset is legal — a transition SECTION
56
+ * commonly offsets its single-track end so the through main lines up with one
57
+ * of the two tracks at its double end. Absent = the recommended default
58
+ * (single centred; double straddling at ∓ half the track spacing). */
59
+ trackOffsetInches?: number | null;
51
60
  }
52
61
  /** Free-moN endplate face width, inches — the connection interface size. */
53
62
  declare const FREEMO_ENDPLATE_WIDTH_MIN_INCHES = 12;
@@ -337,7 +346,14 @@ declare function moduleFootprint(input: ModuleFootprintInput): ModuleFootprint;
337
346
  * side of the plate centre (§2.0 RP), and Main 1 sits on the centre-line, so the
338
347
  * plate centre is half a track spacing up. A single track crosses at the centre.
339
348
  */
340
- declare function endplateTrackOffsetFor(config: TrackConfig | "none" | undefined): number;
349
+ declare function endplateTrackOffsetFor(config: TrackConfig | "none" | undefined, authoredTrackOffset?: number | null): number;
350
+ /**
351
+ * Where an endplate's PRIMARY track (Main 1) crosses, as a signed distance from
352
+ * the plate's CENTRE — the standard's own framing. Authored value wins; absent
353
+ * falls back to the §2.0 recommendations: a single track centred (0), a double
354
+ * straddling so its two tracks land ∓ half the track spacing (Main 1 low).
355
+ */
356
+ declare function endplateTrackOffsetInches(authored: number | null | undefined, config: TrackConfig | "none" | undefined): number;
341
357
  /** A Free-moN conformance problem with an endplate's width/track placement. */
342
358
  interface EndplateWidthIssue {
343
359
  /** "narrow" = below the 12″ minimum; "clearance" = a track too near a fascia. */
@@ -505,6 +521,9 @@ interface EditorState {
505
521
  /** Authored endplate face widths by endplate id, inches (Free-moN 12″ min,
506
522
  * 24″ recommended). Absent id = the recommended default. */
507
523
  endplateWidths: Record<string, number>;
524
+ /** Authored per-endplate TRACK offsets by id — the primary track's signed
525
+ * distance from the plate centre, inches. Absent id = the §2.0 default. */
526
+ endplateTrackOffsets: Record<string, number>;
508
527
  /** Benchwork footprint outline — polygon vertices in module-local inches
509
528
  * (endplate A's track point at the origin, mainline +x, perpendicular +y up).
510
529
  * Empty = no authored outline (fall back to the endplate-width band). */
@@ -796,4 +815,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
796
815
  heading: number;
797
816
  }>;
798
817
 
799
- export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateWidthIssue, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type GeometryType, type IndustryLabelMode, type IndustrySpot, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
818
+ export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawIndustry, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorIndustry, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, type EndplateWidthIssue, FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, type GeometryType, type IndustryLabelMode, type IndustrySpot, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicIndustry, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
package/dist/index.js CHANGED
@@ -184,8 +184,13 @@ function moduleFootprint(input) {
184
184
  outline: authored ? sampleBenchworkOutline(authored) : null
185
185
  };
186
186
  }
187
- function endplateTrackOffsetFor(config) {
188
- return config === "double" ? FREEMO_TRACK_SPACING_INCHES / 2 : 0;
187
+ function endplateTrackOffsetFor(config, authoredTrackOffset) {
188
+ const v = -endplateTrackOffsetInches(authoredTrackOffset, config);
189
+ return v === 0 ? 0 : v;
190
+ }
191
+ function endplateTrackOffsetInches(authored, config) {
192
+ if (typeof authored === "number" && Number.isFinite(authored)) return authored;
193
+ return config === "double" ? -FREEMO_TRACK_SPACING_INCHES / 2 : 0;
189
194
  }
190
195
  function checkEndplateWidth(input) {
191
196
  const width = endplateWidthInches(input);
@@ -254,6 +259,7 @@ function emptyEditorState(lengthInches) {
254
259
  branches: [],
255
260
  poseOverrides: {},
256
261
  endplateWidths: {},
262
+ endplateTrackOffsets: {},
257
263
  outline: [],
258
264
  sectionBreaks: [],
259
265
  controlPoints: [],
@@ -336,10 +342,14 @@ function withPoses(endplates, overrides) {
336
342
  (e) => overrides[e.id] ? { ...e, pose: overrides[e.id] } : e
337
343
  );
338
344
  }
339
- function withWidths(endplates, widths) {
345
+ function withWidths(endplates, widths, offsets = {}) {
340
346
  return endplates.map((e) => {
341
347
  const w = widths[e.id];
342
- return typeof w === "number" && w > 0 ? { ...e, widthInches: w } : e;
348
+ const o = offsets[e.id];
349
+ let out = e;
350
+ if (typeof w === "number" && w > 0) out = { ...out, widthInches: w };
351
+ if (typeof o === "number" && Number.isFinite(o)) out = { ...out, trackOffsetInches: o };
352
+ return out;
343
353
  });
344
354
  }
345
355
  function stateToDoc(state, recordNumber) {
@@ -388,7 +398,8 @@ function stateToDoc(state, recordNumber) {
388
398
  ],
389
399
  state.poseOverrides
390
400
  ),
391
- state.endplateWidths
401
+ state.endplateWidths,
402
+ state.endplateTrackOffsets
392
403
  ),
393
404
  tracks: [
394
405
  state.loop ? (
@@ -547,9 +558,12 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
547
558
  );
548
559
  const poseOverrides = poseOverridesFromDoc(d);
549
560
  const endplateWidths = {};
561
+ const endplateTrackOffsets = {};
550
562
  for (const e of d.endplates ?? []) {
551
563
  if (typeof e.widthInches === "number" && e.widthInches > 0)
552
564
  endplateWidths[e.id] = e.widthInches;
565
+ if (typeof e.trackOffsetInches === "number" && Number.isFinite(e.trackOffsetInches))
566
+ endplateTrackOffsets[e.id] = e.trackOffsetInches;
553
567
  }
554
568
  const outline = (d.outline ?? []).filter((p) => p && Number.isFinite(p.x) && Number.isFinite(p.y)).map((p) => ({
555
569
  x: p.x,
@@ -573,6 +587,7 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
573
587
  })),
574
588
  poseOverrides,
575
589
  endplateWidths,
590
+ endplateTrackOffsets,
576
591
  outline,
577
592
  sectionBreaks: (d.sectionBreaks ?? []).filter((n) => Number.isFinite(n)).map((n) => sc(n)),
578
593
  mainPath,
@@ -1076,6 +1091,6 @@ function poseOverridesFromDoc(doc) {
1076
1091
  return out;
1077
1092
  }
1078
1093
 
1079
- export { FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
1094
+ export { FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, FREEMO_TRACK_SPACING_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_CAR_LENGTH_INCHES, N_SCALE_RATIO, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
1080
1095
  //# sourceMappingURL=index.js.map
1081
1096
  //# sourceMappingURL=index.js.map