@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.cjs
CHANGED
|
@@ -65,6 +65,78 @@ function arcSweep(a0, a1, am) {
|
|
|
65
65
|
const one = norm(a1);
|
|
66
66
|
return m <= one ? one : one - 2 * Math.PI;
|
|
67
67
|
}
|
|
68
|
+
var DEG_FP = Math.PI / 180;
|
|
69
|
+
function moduleCenterline(input) {
|
|
70
|
+
const L = input.lengthInches > 0 ? input.lengthInches : 24;
|
|
71
|
+
const gt = input.geometryType;
|
|
72
|
+
if (gt === "dead_end") return [{ x: 0, y: 0 }];
|
|
73
|
+
if (gt === "offset") return [{ x: 0, y: 0 }, { x: L, y: input.geometryOffsetInches ?? 0 }];
|
|
74
|
+
const turn = gt === "corner_45" ? 45 : gt === "corner_90" ? 90 : gt === "curve" ? input.geometryDegrees ?? 0 : 0;
|
|
75
|
+
if (turn === 0) return [{ x: 0, y: 0 }, { x: L, y: 0 }];
|
|
76
|
+
const t = turn * DEG_FP;
|
|
77
|
+
const r = L / t;
|
|
78
|
+
const steps = 12;
|
|
79
|
+
const pts = [];
|
|
80
|
+
for (let i = 0; i <= steps; i++) {
|
|
81
|
+
const a = t * i / steps;
|
|
82
|
+
pts.push({ x: r * Math.sin(a), y: r * (1 - Math.cos(a)) });
|
|
83
|
+
}
|
|
84
|
+
return pts;
|
|
85
|
+
}
|
|
86
|
+
function centerlineNormals(center) {
|
|
87
|
+
return center.map((_, i) => {
|
|
88
|
+
const a = center[Math.max(0, i - 1)];
|
|
89
|
+
const b = center[Math.min(center.length - 1, i + 1)];
|
|
90
|
+
let dx = b.x - a.x;
|
|
91
|
+
let dy = b.y - a.y;
|
|
92
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
93
|
+
dx /= len;
|
|
94
|
+
dy /= len;
|
|
95
|
+
return { x: -dy, y: dx };
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function centerlineFractions(center) {
|
|
99
|
+
const cum = [0];
|
|
100
|
+
for (let i = 1; i < center.length; i++)
|
|
101
|
+
cum.push(cum[i - 1] + Math.hypot(center[i].x - center[i - 1].x, center[i].y - center[i - 1].y));
|
|
102
|
+
const total = cum[cum.length - 1] || 1;
|
|
103
|
+
return cum.map((d) => d / total);
|
|
104
|
+
}
|
|
105
|
+
function benchworkBand(center, widthA = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, widthB = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES) {
|
|
106
|
+
if (center.length < 2) return [];
|
|
107
|
+
const n = centerlineNormals(center);
|
|
108
|
+
const f = centerlineFractions(center);
|
|
109
|
+
const half = (i) => (widthA * (1 - f[i]) + widthB * f[i]) / 2;
|
|
110
|
+
const left = center.map((p, i) => ({ x: p.x + n[i].x * half(i), y: p.y + n[i].y * half(i) }));
|
|
111
|
+
const right = center.map((p, i) => ({ x: p.x - n[i].x * half(i), y: p.y - n[i].y * half(i) }));
|
|
112
|
+
return [...left, ...right.reverse()];
|
|
113
|
+
}
|
|
114
|
+
function endplateFaceSegments(center, widthA = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, widthB = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES) {
|
|
115
|
+
if (center.length < 2) return [];
|
|
116
|
+
const n = centerlineNormals(center);
|
|
117
|
+
const face = (i, w) => ({
|
|
118
|
+
p1: { x: center[i].x + n[i].x * (w / 2), y: center[i].y + n[i].y * (w / 2) },
|
|
119
|
+
p2: { x: center[i].x - n[i].x * (w / 2), y: center[i].y - n[i].y * (w / 2) },
|
|
120
|
+
mid: { x: center[i].x, y: center[i].y }
|
|
121
|
+
});
|
|
122
|
+
return [face(0, widthA), face(center.length - 1, widthB)];
|
|
123
|
+
}
|
|
124
|
+
function moduleFootprint(input) {
|
|
125
|
+
const centerline = moduleCenterline(input);
|
|
126
|
+
const widthA = endplateWidthFor(input.endplateWidths, "A");
|
|
127
|
+
const widthB = endplateWidthFor(input.endplateWidths, "B");
|
|
128
|
+
const authored = benchworkOutline(input);
|
|
129
|
+
return {
|
|
130
|
+
centerline,
|
|
131
|
+
band: benchworkBand(centerline, widthA, widthB),
|
|
132
|
+
endplateFaces: endplateFaceSegments(centerline, widthA, widthB),
|
|
133
|
+
outline: authored ? sampleBenchworkOutline(authored) : null
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function endplateWidthFor(widths, id) {
|
|
137
|
+
const w = widths?.[id];
|
|
138
|
+
return typeof w === "number" && w > 0 ? w : FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES;
|
|
139
|
+
}
|
|
68
140
|
function isLoopDoc(doc) {
|
|
69
141
|
return doc.loop === true || doc.endplates.length === 1;
|
|
70
142
|
}
|
|
@@ -828,6 +900,7 @@ exports.MAIN2_TRACK_ID = MAIN2_TRACK_ID;
|
|
|
828
900
|
exports.MAIN_TRACK_ID = MAIN_TRACK_ID;
|
|
829
901
|
exports.N_SCALE_RATIO = N_SCALE_RATIO;
|
|
830
902
|
exports.asModuleSchematic = asModuleSchematic;
|
|
903
|
+
exports.benchworkBand = benchworkBand;
|
|
831
904
|
exports.benchworkOutline = benchworkOutline;
|
|
832
905
|
exports.buildCrossover = buildCrossover;
|
|
833
906
|
exports.buildPassingSiding = buildPassingSiding;
|
|
@@ -836,12 +909,15 @@ exports.deriveEndplatePoses = deriveEndplatePoses;
|
|
|
836
909
|
exports.divergeSideForHand = divergeSideForHand;
|
|
837
910
|
exports.docToState = docToState;
|
|
838
911
|
exports.emptyEditorState = emptyEditorState;
|
|
912
|
+
exports.endplateFaceSegments = endplateFaceSegments;
|
|
839
913
|
exports.endplateWidthInches = endplateWidthInches;
|
|
840
914
|
exports.geometryTurnDegrees = geometryTurnDegrees;
|
|
841
915
|
exports.inchesToScaleFeet = inchesToScaleFeet;
|
|
842
916
|
exports.isLoopDoc = isLoopDoc;
|
|
843
917
|
exports.isTransitionTurnout = isTransitionTurnout;
|
|
918
|
+
exports.moduleCenterline = moduleCenterline;
|
|
844
919
|
exports.moduleFeatures = moduleFeatures;
|
|
920
|
+
exports.moduleFootprint = moduleFootprint;
|
|
845
921
|
exports.nextId = nextId;
|
|
846
922
|
exports.poseNeedsManual = poseNeedsManual;
|
|
847
923
|
exports.poseOverridesFromDoc = poseOverridesFromDoc;
|