@willcgage/module-schematic 0.35.0 → 0.36.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
@@ -435,6 +435,68 @@ declare function sectionSpans(doc: {
435
435
  fromPos: number;
436
436
  toPos: number;
437
437
  }[];
438
+ /** A position expressed against the board it sits on, rather than as inches
439
+ * from endplate A (#109). */
440
+ interface SectionRelativePos {
441
+ sectionId: string;
442
+ /** Inches from that section's own west end. */
443
+ offsetInches: number;
444
+ }
445
+ /**
446
+ * Section spans that ALWAYS cover the whole module. The owner's insight is
447
+ * what makes #109 tractable: every module has at least one section, even if
448
+ * that one section IS the whole module. So a module with no authored sections
449
+ * gets a single implicit span 0→length, every position falls inside exactly
450
+ * one span, and absolute ↔ relative becomes a total, lossless mapping with no
451
+ * un-convertible module and no orphan positions.
452
+ *
453
+ * The last span is also stretched to the module length when the sections come
454
+ * up short, so a position past the end still lands somewhere real.
455
+ */
456
+ declare function sectionSpansOrWhole(doc: {
457
+ sections?: SchematicSection[] | null;
458
+ } | null | undefined, lengthInches: number): {
459
+ id: string;
460
+ name?: string;
461
+ fromPos: number;
462
+ toPos: number;
463
+ }[];
464
+ /** The id a module with no authored sections uses for its single implicit one. */
465
+ declare const WHOLE_MODULE_SECTION_ID = "module";
466
+ /**
467
+ * Absolute inches → the board it sits on plus an offset along it (#109).
468
+ * Total: given spans from `sectionSpansOrWhole`, every position resolves.
469
+ *
470
+ * A position exactly ON a joint is assigned to the section that STARTS there,
471
+ * at offset 0 — a joint is the west end of the next board, and that keeps the
472
+ * mapping single-valued. The module's own east end is the exception: nothing
473
+ * starts there, so it belongs to the last board.
474
+ */
475
+ declare function toSectionRelative(pos: number, spans: {
476
+ id: string;
477
+ fromPos: number;
478
+ toPos: number;
479
+ }[]): SectionRelativePos | null;
480
+ /** …and back. Null when the section is gone — which is the caller's cue that
481
+ * the thing it positioned has lost its board (#96 phase 3). */
482
+ declare function fromSectionRelative(rel: SectionRelativePos, spans: {
483
+ id: string;
484
+ fromPos: number;
485
+ toPos: number;
486
+ }[]): number | null;
487
+ /** Re-derive an absolute position after the sections have moved: read it
488
+ * against the OLD spans, write it against the NEW ones. This is the whole
489
+ * point of #109 — reorder or resize a board and everything on it comes along
490
+ * instead of silently pointing at a different board. */
491
+ declare function remapPos(pos: number, before: {
492
+ id: string;
493
+ fromPos: number;
494
+ toPos: number;
495
+ }[], after: {
496
+ id: string;
497
+ fromPos: number;
498
+ toPos: number;
499
+ }[]): number | null;
438
500
  /** The joints implied by the sections — the interior boundaries, in inches from
439
501
  * endplate A. Replaces the authored `sectionBreaks` for a sectioned module. */
440
502
  declare function sectionBreaksFromSections(doc: {
@@ -1000,4 +1062,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
1000
1062
  heading: number;
1001
1063
  }>;
1002
1064
 
1003
- 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 SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionFootprint, 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, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, trackPath };
1065
+ 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 SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionFootprint, type SectionRelativePos, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, fromSectionRelative, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, remapPos, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackPath };
package/dist/index.d.ts CHANGED
@@ -435,6 +435,68 @@ declare function sectionSpans(doc: {
435
435
  fromPos: number;
436
436
  toPos: number;
437
437
  }[];
438
+ /** A position expressed against the board it sits on, rather than as inches
439
+ * from endplate A (#109). */
440
+ interface SectionRelativePos {
441
+ sectionId: string;
442
+ /** Inches from that section's own west end. */
443
+ offsetInches: number;
444
+ }
445
+ /**
446
+ * Section spans that ALWAYS cover the whole module. The owner's insight is
447
+ * what makes #109 tractable: every module has at least one section, even if
448
+ * that one section IS the whole module. So a module with no authored sections
449
+ * gets a single implicit span 0→length, every position falls inside exactly
450
+ * one span, and absolute ↔ relative becomes a total, lossless mapping with no
451
+ * un-convertible module and no orphan positions.
452
+ *
453
+ * The last span is also stretched to the module length when the sections come
454
+ * up short, so a position past the end still lands somewhere real.
455
+ */
456
+ declare function sectionSpansOrWhole(doc: {
457
+ sections?: SchematicSection[] | null;
458
+ } | null | undefined, lengthInches: number): {
459
+ id: string;
460
+ name?: string;
461
+ fromPos: number;
462
+ toPos: number;
463
+ }[];
464
+ /** The id a module with no authored sections uses for its single implicit one. */
465
+ declare const WHOLE_MODULE_SECTION_ID = "module";
466
+ /**
467
+ * Absolute inches → the board it sits on plus an offset along it (#109).
468
+ * Total: given spans from `sectionSpansOrWhole`, every position resolves.
469
+ *
470
+ * A position exactly ON a joint is assigned to the section that STARTS there,
471
+ * at offset 0 — a joint is the west end of the next board, and that keeps the
472
+ * mapping single-valued. The module's own east end is the exception: nothing
473
+ * starts there, so it belongs to the last board.
474
+ */
475
+ declare function toSectionRelative(pos: number, spans: {
476
+ id: string;
477
+ fromPos: number;
478
+ toPos: number;
479
+ }[]): SectionRelativePos | null;
480
+ /** …and back. Null when the section is gone — which is the caller's cue that
481
+ * the thing it positioned has lost its board (#96 phase 3). */
482
+ declare function fromSectionRelative(rel: SectionRelativePos, spans: {
483
+ id: string;
484
+ fromPos: number;
485
+ toPos: number;
486
+ }[]): number | null;
487
+ /** Re-derive an absolute position after the sections have moved: read it
488
+ * against the OLD spans, write it against the NEW ones. This is the whole
489
+ * point of #109 — reorder or resize a board and everything on it comes along
490
+ * instead of silently pointing at a different board. */
491
+ declare function remapPos(pos: number, before: {
492
+ id: string;
493
+ fromPos: number;
494
+ toPos: number;
495
+ }[], after: {
496
+ id: string;
497
+ fromPos: number;
498
+ toPos: number;
499
+ }[]): number | null;
438
500
  /** The joints implied by the sections — the interior boundaries, in inches from
439
501
  * endplate A. Replaces the authored `sectionBreaks` for a sectioned module. */
440
502
  declare function sectionBreaksFromSections(doc: {
@@ -1000,4 +1062,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
1000
1062
  heading: number;
1001
1063
  }>;
1002
1064
 
1003
- 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 SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionFootprint, 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, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, trackPath };
1065
+ 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 SchematicSection, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SectionAdjacency, type SectionFootprint, type SectionRelativePos, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, fromSectionRelative, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, remapPos, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackPath };
package/dist/index.js CHANGED
@@ -205,6 +205,35 @@ function sectionSpans(doc) {
205
205
  }
206
206
  return out;
207
207
  }
208
+ function sectionSpansOrWhole(doc, lengthInches) {
209
+ const L = lengthInches > 0 ? lengthInches : 0;
210
+ const spans = sectionSpans(doc);
211
+ if (!spans.length) return [{ id: WHOLE_MODULE_SECTION_ID, fromPos: 0, toPos: L }];
212
+ const out = spans.map((sp) => ({ ...sp }));
213
+ const last = out[out.length - 1];
214
+ if (L > last.toPos) last.toPos = L;
215
+ return out;
216
+ }
217
+ var WHOLE_MODULE_SECTION_ID = "module";
218
+ function toSectionRelative(pos, spans) {
219
+ if (!spans.length) return null;
220
+ const p = Math.max(spans[0].fromPos, Math.min(spans[spans.length - 1].toPos, pos));
221
+ for (const sp of spans) {
222
+ if (p >= sp.fromPos && p < sp.toPos)
223
+ return { sectionId: sp.id, offsetInches: round3(p - sp.fromPos) };
224
+ }
225
+ const last = spans[spans.length - 1];
226
+ return { sectionId: last.id, offsetInches: round3(last.toPos - last.fromPos) };
227
+ }
228
+ function fromSectionRelative(rel, spans) {
229
+ const sp = spans.find((x) => x.id === rel.sectionId);
230
+ if (!sp) return null;
231
+ return round3(sp.fromPos + Math.max(0, Math.min(sp.toPos - sp.fromPos, rel.offsetInches)));
232
+ }
233
+ function remapPos(pos, before, after) {
234
+ const rel = toSectionRelative(pos, before);
235
+ return rel ? fromSectionRelative(rel, after) : null;
236
+ }
208
237
  function sectionBreaksFromSections(doc) {
209
238
  const spans = sectionSpans(doc);
210
239
  return spans.slice(0, -1).map((sp) => sp.toPos);
@@ -481,6 +510,7 @@ function checkEndplateWidth(input) {
481
510
  return issues;
482
511
  }
483
512
  var round2 = (n) => Math.round(n * 100) / 100;
513
+ var round3 = (n) => Math.round(n * 1e3) / 1e3;
484
514
  function endplateWidthFor(widths, id) {
485
515
  const w = widths?.[id];
486
516
  return typeof w === "number" && w > 0 ? w : FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES;
@@ -1383,6 +1413,6 @@ function poseOverridesFromDoc(doc) {
1383
1413
  return out;
1384
1414
  }
1385
1415
 
1386
- 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, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, trackPath };
1416
+ 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, WHOLE_MODULE_SECTION_ID, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, carCapacity, checkEndplateWidth, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateTrackOffsetFor, endplateTrackOffsetInches, endplateWidthInches, fromSectionRelative, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, moduleLengthFromSections, moduleSections, nextId, poseNeedsManual, poseOverridesFromDoc, remapPos, sampleBenchworkOutline, samplePath, scaleFeetToInches, sectionAdjacency, sectionBand, sectionBreaksFromSections, sectionComponents, sectionFootprints, sectionNeighbours, sectionSpans, sectionSpansOrWhole, sectionedCenterline, sectionedEndPose, sliceCenterline, stateToDoc, toSectionRelative, trackPath };
1387
1417
  //# sourceMappingURL=index.js.map
1388
1418
  //# sourceMappingURL=index.js.map