@willcgage/module-schematic 0.16.0 → 0.17.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 +76 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +73 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -191,6 +191,45 @@ declare function sampleBenchworkOutline(pts: BenchworkPoint[], segsPerArc?: numb
|
|
|
191
191
|
x: number;
|
|
192
192
|
y: number;
|
|
193
193
|
}[];
|
|
194
|
+
interface ModuleFootprintInput {
|
|
195
|
+
/** Mainline length (falls back to footprint length), inches. */
|
|
196
|
+
lengthInches: number;
|
|
197
|
+
geometryType?: string | null;
|
|
198
|
+
geometryDegrees?: number | null;
|
|
199
|
+
geometryOffsetInches?: number | null;
|
|
200
|
+
/** Authored endplate face widths by id ("A"/"B"…), inches; default recommended. */
|
|
201
|
+
endplateWidths?: Record<string, number>;
|
|
202
|
+
/** Authored benchwork outline (module-local inches), or absent for the band. */
|
|
203
|
+
outline?: BenchworkPoint[] | null;
|
|
204
|
+
}
|
|
205
|
+
interface OutlineFace {
|
|
206
|
+
/** The endplate face's two corners + midpoint (the track point). */
|
|
207
|
+
p1: BenchworkPoint;
|
|
208
|
+
p2: BenchworkPoint;
|
|
209
|
+
mid: BenchworkPoint;
|
|
210
|
+
}
|
|
211
|
+
interface ModuleFootprint {
|
|
212
|
+
/** Main track centre-line A→B (arcs sampled). */
|
|
213
|
+
centerline: BenchworkPoint[];
|
|
214
|
+
/** Derived benchwork band (endplate-width ribbon); the outline fallback. */
|
|
215
|
+
band: BenchworkPoint[];
|
|
216
|
+
/** Endplate faces: [A end, B end]. */
|
|
217
|
+
endplateFaces: OutlineFace[];
|
|
218
|
+
/** Authored outline (arc-sampled closed ring) or null → render the band. */
|
|
219
|
+
outline: BenchworkPoint[] | null;
|
|
220
|
+
}
|
|
221
|
+
/** Module-local main track centre-line (A→B), sampling arcs for curves/corners. */
|
|
222
|
+
declare function moduleCenterline(input: ModuleFootprintInput): BenchworkPoint[];
|
|
223
|
+
/** Benchwork band: the centre-line offset ±half-width, tapering widthA→widthB. */
|
|
224
|
+
declare function benchworkBand(center: BenchworkPoint[], widthA?: number, widthB?: number): BenchworkPoint[];
|
|
225
|
+
/** The two endplate faces (the band's flat ends): [A end at widthA, B end at widthB]. */
|
|
226
|
+
declare function endplateFaceSegments(center: BenchworkPoint[], widthA?: number, widthB?: number): OutlineFace[];
|
|
227
|
+
/**
|
|
228
|
+
* The full single-module physical footprint: centre-line + derived band +
|
|
229
|
+
* endplate faces + the authored outline (arc-sampled), all in module-local
|
|
230
|
+
* inches. Renderers draw `outline ?? band`.
|
|
231
|
+
*/
|
|
232
|
+
declare function moduleFootprint(input: ModuleFootprintInput): ModuleFootprint;
|
|
194
233
|
/** Whether a doc is a single-endplate turnback (explicit flag or one endplate). */
|
|
195
234
|
declare function isLoopDoc(doc: ModuleSchematicDoc): boolean;
|
|
196
235
|
declare const MAIN_TRACK_ID = "main";
|
|
@@ -559,4 +598,4 @@ declare function poseOverridesFromDoc(doc: ModuleSchematicDoc): Record<string, {
|
|
|
559
598
|
heading: number;
|
|
560
599
|
}>;
|
|
561
600
|
|
|
562
|
-
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_SCALE_RATIO, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleFeatures, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, scaleFeetToInches, stateToDoc };
|
|
601
|
+
export { type BenchworkPoint, type BranchConnector, type DrawCrossing, type DrawCrossover, type DrawSignal, type DrawTrack, type DrawTurnout, type EditorBranch, type EditorControlPoint, type EditorCpSignal, type EditorCrossing, type EditorState, type EditorTrack, type EditorTurnout, type EndplateBConfig, type EndplatePose, FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, type GeometryType, MAIN2_TRACK_ID, MAIN_TRACK_ID, type ModuleFeatures, type ModuleFootprint, type ModuleFootprintInput, type ModuleGeometryInput, type ModuleSchematicDoc, type ModuleTrackRow, N_SCALE_RATIO, type OutlineFace, type SchematicBlock, type SchematicControlPoint, type SchematicCrossing, type SchematicEndplate, type SchematicEndplateTrack, type SchematicSignal, type SchematicTrack, type SchematicTurnout, type SignalFacing, type SignalSide, type TrackConfig, type TrackRole, type TurnoutKind, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, scaleFeetToInches, stateToDoc };
|
package/dist/index.js
CHANGED
|
@@ -63,6 +63,78 @@ function arcSweep(a0, a1, am) {
|
|
|
63
63
|
const one = norm(a1);
|
|
64
64
|
return m <= one ? one : one - 2 * Math.PI;
|
|
65
65
|
}
|
|
66
|
+
var DEG_FP = Math.PI / 180;
|
|
67
|
+
function moduleCenterline(input) {
|
|
68
|
+
const L = input.lengthInches > 0 ? input.lengthInches : 24;
|
|
69
|
+
const gt = input.geometryType;
|
|
70
|
+
if (gt === "dead_end") return [{ x: 0, y: 0 }];
|
|
71
|
+
if (gt === "offset") return [{ x: 0, y: 0 }, { x: L, y: input.geometryOffsetInches ?? 0 }];
|
|
72
|
+
const turn = gt === "corner_45" ? 45 : gt === "corner_90" ? 90 : gt === "curve" ? input.geometryDegrees ?? 0 : 0;
|
|
73
|
+
if (turn === 0) return [{ x: 0, y: 0 }, { x: L, y: 0 }];
|
|
74
|
+
const t = turn * DEG_FP;
|
|
75
|
+
const r = L / t;
|
|
76
|
+
const steps = 12;
|
|
77
|
+
const pts = [];
|
|
78
|
+
for (let i = 0; i <= steps; i++) {
|
|
79
|
+
const a = t * i / steps;
|
|
80
|
+
pts.push({ x: r * Math.sin(a), y: r * (1 - Math.cos(a)) });
|
|
81
|
+
}
|
|
82
|
+
return pts;
|
|
83
|
+
}
|
|
84
|
+
function centerlineNormals(center) {
|
|
85
|
+
return center.map((_, i) => {
|
|
86
|
+
const a = center[Math.max(0, i - 1)];
|
|
87
|
+
const b = center[Math.min(center.length - 1, i + 1)];
|
|
88
|
+
let dx = b.x - a.x;
|
|
89
|
+
let dy = b.y - a.y;
|
|
90
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
91
|
+
dx /= len;
|
|
92
|
+
dy /= len;
|
|
93
|
+
return { x: -dy, y: dx };
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function centerlineFractions(center) {
|
|
97
|
+
const cum = [0];
|
|
98
|
+
for (let i = 1; i < center.length; i++)
|
|
99
|
+
cum.push(cum[i - 1] + Math.hypot(center[i].x - center[i - 1].x, center[i].y - center[i - 1].y));
|
|
100
|
+
const total = cum[cum.length - 1] || 1;
|
|
101
|
+
return cum.map((d) => d / total);
|
|
102
|
+
}
|
|
103
|
+
function benchworkBand(center, widthA = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, widthB = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES) {
|
|
104
|
+
if (center.length < 2) return [];
|
|
105
|
+
const n = centerlineNormals(center);
|
|
106
|
+
const f = centerlineFractions(center);
|
|
107
|
+
const half = (i) => (widthA * (1 - f[i]) + widthB * f[i]) / 2;
|
|
108
|
+
const left = center.map((p, i) => ({ x: p.x + n[i].x * half(i), y: p.y + n[i].y * half(i) }));
|
|
109
|
+
const right = center.map((p, i) => ({ x: p.x - n[i].x * half(i), y: p.y - n[i].y * half(i) }));
|
|
110
|
+
return [...left, ...right.reverse()];
|
|
111
|
+
}
|
|
112
|
+
function endplateFaceSegments(center, widthA = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, widthB = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES) {
|
|
113
|
+
if (center.length < 2) return [];
|
|
114
|
+
const n = centerlineNormals(center);
|
|
115
|
+
const face = (i, w) => ({
|
|
116
|
+
p1: { x: center[i].x + n[i].x * (w / 2), y: center[i].y + n[i].y * (w / 2) },
|
|
117
|
+
p2: { x: center[i].x - n[i].x * (w / 2), y: center[i].y - n[i].y * (w / 2) },
|
|
118
|
+
mid: { x: center[i].x, y: center[i].y }
|
|
119
|
+
});
|
|
120
|
+
return [face(0, widthA), face(center.length - 1, widthB)];
|
|
121
|
+
}
|
|
122
|
+
function moduleFootprint(input) {
|
|
123
|
+
const centerline = moduleCenterline(input);
|
|
124
|
+
const widthA = endplateWidthFor(input.endplateWidths, "A");
|
|
125
|
+
const widthB = endplateWidthFor(input.endplateWidths, "B");
|
|
126
|
+
const authored = benchworkOutline(input);
|
|
127
|
+
return {
|
|
128
|
+
centerline,
|
|
129
|
+
band: benchworkBand(centerline, widthA, widthB),
|
|
130
|
+
endplateFaces: endplateFaceSegments(centerline, widthA, widthB),
|
|
131
|
+
outline: authored ? sampleBenchworkOutline(authored) : null
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function endplateWidthFor(widths, id) {
|
|
135
|
+
const w = widths?.[id];
|
|
136
|
+
return typeof w === "number" && w > 0 ? w : FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES;
|
|
137
|
+
}
|
|
66
138
|
function isLoopDoc(doc) {
|
|
67
139
|
return doc.loop === true || doc.endplates.length === 1;
|
|
68
140
|
}
|
|
@@ -820,6 +892,6 @@ function poseOverridesFromDoc(doc) {
|
|
|
820
892
|
return out;
|
|
821
893
|
}
|
|
822
894
|
|
|
823
|
-
export { FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_SCALE_RATIO, asModuleSchematic, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleFeatures, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, scaleFeetToInches, stateToDoc };
|
|
895
|
+
export { FREEMO_ENDPLATE_WIDTH_MIN_INCHES, FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, MAIN2_TRACK_ID, MAIN_TRACK_ID, N_SCALE_RATIO, asModuleSchematic, benchworkBand, benchworkOutline, buildCrossover, buildPassingSiding, buildTransition, deriveEndplatePoses, divergeSideForHand, docToState, emptyEditorState, endplateFaceSegments, endplateWidthInches, geometryTurnDegrees, inchesToScaleFeet, isLoopDoc, isTransitionTurnout, moduleCenterline, moduleFeatures, moduleFootprint, nextId, poseNeedsManual, poseOverridesFromDoc, sampleBenchworkOutline, scaleFeetToInches, stateToDoc };
|
|
824
896
|
//# sourceMappingURL=index.js.map
|
|
825
897
|
//# sourceMappingURL=index.js.map
|