@willcgage/module-schematic 0.20.0 → 0.21.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
@@ -149,16 +149,27 @@ type IndustryLabelMode = "none" | "cars" | "inches";
149
149
  * offset to `side`. The span length gives its car capacity; the dispatcher and
150
150
  * crews read where cars set out. Mirrors a `freemon_industries` row.
151
151
  */
152
+ /** One car-spot span of an industry on a track — an industry may have several
153
+ * (a house track serving one customer across multiple spot tracks, #54). */
154
+ interface IndustrySpot {
155
+ track: string;
156
+ fromPos: number;
157
+ toPos: number;
158
+ side?: SignalSide;
159
+ }
152
160
  interface SchematicIndustry {
153
161
  id: string;
154
162
  name: string;
155
163
  /** Industry type value from the lookup (e.g. "team_track", "grain"). */
156
164
  type?: string | null;
157
- /** The track this industry spots cars on (a spur/siding id, or the main). */
165
+ /** The primary track this industry spots cars on (a spur/siding id or main).
166
+ * Additional spots (other tracks) live in `spots`. */
158
167
  track: string;
159
- /** The car-spot span along that track, inches from endplate A. */
168
+ /** The primary car-spot span along `track`, inches from endplate A. */
160
169
  fromPos: number;
161
170
  toPos: number;
171
+ /** Extra car-spot spans on other tracks — the industry's house-track spots. */
172
+ spots?: IndustrySpot[];
162
173
  /** Which side of the track the building + label sit on. */
163
174
  side?: SignalSide;
164
175
  /** Secondary readout at the label — a car count, a length, or none. */
@@ -375,6 +386,8 @@ interface EditorIndustry {
375
386
  track: string;
376
387
  fromPos: number;
377
388
  toPos: number;
389
+ /** Extra car-spot spans on other tracks (house-track spots, #54). */
390
+ spots: IndustrySpot[];
378
391
  side: SignalSide;
379
392
  labelMode: IndustryLabelMode;
380
393
  carTypes: string[];
@@ -709,4 +722,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
709
722
  heading: number;
710
723
  }>;
711
724
 
712
- 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, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, type IndustryLabelMode, 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, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
725
+ 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, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_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, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
package/dist/index.d.ts CHANGED
@@ -149,16 +149,27 @@ type IndustryLabelMode = "none" | "cars" | "inches";
149
149
  * offset to `side`. The span length gives its car capacity; the dispatcher and
150
150
  * crews read where cars set out. Mirrors a `freemon_industries` row.
151
151
  */
152
+ /** One car-spot span of an industry on a track — an industry may have several
153
+ * (a house track serving one customer across multiple spot tracks, #54). */
154
+ interface IndustrySpot {
155
+ track: string;
156
+ fromPos: number;
157
+ toPos: number;
158
+ side?: SignalSide;
159
+ }
152
160
  interface SchematicIndustry {
153
161
  id: string;
154
162
  name: string;
155
163
  /** Industry type value from the lookup (e.g. "team_track", "grain"). */
156
164
  type?: string | null;
157
- /** The track this industry spots cars on (a spur/siding id, or the main). */
165
+ /** The primary track this industry spots cars on (a spur/siding id or main).
166
+ * Additional spots (other tracks) live in `spots`. */
158
167
  track: string;
159
- /** The car-spot span along that track, inches from endplate A. */
168
+ /** The primary car-spot span along `track`, inches from endplate A. */
160
169
  fromPos: number;
161
170
  toPos: number;
171
+ /** Extra car-spot spans on other tracks — the industry's house-track spots. */
172
+ spots?: IndustrySpot[];
162
173
  /** Which side of the track the building + label sit on. */
163
174
  side?: SignalSide;
164
175
  /** Secondary readout at the label — a car count, a length, or none. */
@@ -375,6 +386,8 @@ interface EditorIndustry {
375
386
  track: string;
376
387
  fromPos: number;
377
388
  toPos: number;
389
+ /** Extra car-spot spans on other tracks (house-track spots, #54). */
390
+ spots: IndustrySpot[];
378
391
  side: SignalSide;
379
392
  labelMode: IndustryLabelMode;
380
393
  carTypes: string[];
@@ -709,4 +722,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
709
722
  heading: number;
710
723
  }>;
711
724
 
712
- 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, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, type IndustryLabelMode, 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, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
725
+ 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, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_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, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, samplePath, scaleFeetToInches, stateToDoc, trackPath };
package/dist/index.js CHANGED
@@ -397,6 +397,7 @@ function stateToDoc(state, recordNumber) {
397
397
  track: ind.track,
398
398
  fromPos: ind.fromPos,
399
399
  toPos: ind.toPos,
400
+ ...ind.spots?.length ? { spots: ind.spots } : {},
400
401
  side: ind.side,
401
402
  ...ind.labelMode && ind.labelMode !== "none" ? { labelMode: ind.labelMode } : {},
402
403
  ...ind.carTypes.length ? { carTypes: ind.carTypes } : {},
@@ -531,6 +532,12 @@ function docToState(doc, fallbackLength, moduleTracks = []) {
531
532
  track: ind.track,
532
533
  fromPos: sc(ind.fromPos ?? 0),
533
534
  toPos: ind.toPos != null ? sc(ind.toPos) : len,
535
+ spots: (ind.spots ?? []).map((s) => ({
536
+ track: s.track,
537
+ fromPos: sc(s.fromPos ?? 0),
538
+ toPos: s.toPos != null ? sc(s.toPos) : len,
539
+ ...s.side ? { side: s.side } : {}
540
+ })),
534
541
  side: ind.side ?? "above",
535
542
  labelMode: ind.labelMode ?? "none",
536
543
  carTypes: Array.isArray(ind.carTypes) ? ind.carTypes : [],
@@ -834,21 +841,27 @@ function moduleFeatures(doc) {
834
841
  posFrac: clampFrac(e.at.pos),
835
842
  side: e.at.side === "down" ? "down" : "up"
836
843
  }));
837
- const industries = (doc.industries ?? []).map((ind) => {
838
- const from = ind.fromPos ?? 0;
839
- const to = ind.toPos ?? len;
840
- return {
841
- id: ind.id,
842
- name: ind.name ?? "",
843
- type: ind.type ?? null,
844
- fromFrac: clampFrac(Math.min(from, to)),
845
- toFrac: clampFrac(Math.max(from, to)),
846
- lane: trackLane.get(ind.track) ?? 0,
847
- side: ind.side ?? "above",
848
- labelMode: ind.labelMode ?? "none",
849
- cars: carCapacity(from, to),
850
- carTypes: Array.isArray(ind.carTypes) ? ind.carTypes : []
851
- };
844
+ const industries = (doc.industries ?? []).flatMap((ind) => {
845
+ const spots = [
846
+ { track: ind.track, fromPos: ind.fromPos, toPos: ind.toPos, side: ind.side },
847
+ ...ind.spots ?? []
848
+ ];
849
+ return spots.map((sp, i) => {
850
+ const from = sp.fromPos ?? 0;
851
+ const to = sp.toPos ?? len;
852
+ return {
853
+ id: i === 0 ? ind.id : `${ind.id}-s${i}`,
854
+ name: ind.name ?? "",
855
+ type: ind.type ?? null,
856
+ fromFrac: clampFrac(Math.min(from, to)),
857
+ toFrac: clampFrac(Math.max(from, to)),
858
+ lane: trackLane.get(sp.track) ?? 0,
859
+ side: sp.side ?? "above",
860
+ labelMode: ind.labelMode ?? "none",
861
+ cars: carCapacity(from, to),
862
+ carTypes: Array.isArray(ind.carTypes) ? ind.carTypes : []
863
+ };
864
+ });
852
865
  });
853
866
  const allLanes = [
854
867
  0,