@willcgage/module-schematic 0.83.2 → 0.84.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 +104 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -1
- package/dist/index.d.ts +57 -1
- package/dist/index.js +102 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2128,6 +2128,107 @@ function turnoutClosure(size, opts = {}) {
|
|
|
2128
2128
|
}
|
|
2129
2129
|
};
|
|
2130
2130
|
}
|
|
2131
|
+
function partGeometryGap(part) {
|
|
2132
|
+
if (part.kind === "flex") return null;
|
|
2133
|
+
if (part.kind === "crossover")
|
|
2134
|
+
return "a crossover fixture builds one HALF of the assembly (piecesPerAssembly), so its published lengths describe a piece, not the finished part \u2014 the geometry of the whole crossover is not yet derivable from them";
|
|
2135
|
+
if (part.kind === "crossing") return "crossing geometry is not modelled yet";
|
|
2136
|
+
if (part.kind === "curved-turnout")
|
|
2137
|
+
return "a curved turnout needs both radii AND its points/frog landmarks; only the radii are published";
|
|
2138
|
+
if (!part.pointsOffset)
|
|
2139
|
+
return "no points offset \u2014 without it there is nowhere for the diverging route to begin";
|
|
2140
|
+
if (!part.overallLength) return "no overall length \u2014 the part has no end to put a joint on";
|
|
2141
|
+
if (part.frogNumber == null) return "no frog number \u2014 the diverging angle is unknown";
|
|
2142
|
+
return null;
|
|
2143
|
+
}
|
|
2144
|
+
function partGeometry(part, library = BUILT_IN_TRACK_PARTS) {
|
|
2145
|
+
if (partGeometryGap(part)) return null;
|
|
2146
|
+
if (part.kind === "flex") {
|
|
2147
|
+
return {
|
|
2148
|
+
joints: [
|
|
2149
|
+
{ id: "a", role: "throat", x: 0, y: 0, angleDeg: 180 },
|
|
2150
|
+
{ id: "b", role: "through", x: 0, y: 0, angleDeg: 0 }
|
|
2151
|
+
],
|
|
2152
|
+
routes: [["a", "b"]],
|
|
2153
|
+
source: "derived",
|
|
2154
|
+
divergingEndMeasured: false
|
|
2155
|
+
};
|
|
2156
|
+
}
|
|
2157
|
+
const N = part.frogNumber;
|
|
2158
|
+
const points = part.pointsOffset;
|
|
2159
|
+
const overall = part.overallLength;
|
|
2160
|
+
const frog = part.frogOffset;
|
|
2161
|
+
const lead = part.lead?.inches ?? (frog ? frog.inches - points.inches : void 0);
|
|
2162
|
+
if (lead == null || !(lead > 0)) return null;
|
|
2163
|
+
const isWye = part.kind === "wye";
|
|
2164
|
+
const effN = isWye ? N * 2 : N;
|
|
2165
|
+
const closure = turnoutClosure(effN, { leadInches: lead });
|
|
2166
|
+
const divergingEnd = () => {
|
|
2167
|
+
const frogX = frog ? frog.inches : points.inches + lead;
|
|
2168
|
+
const slope = closure.frogSlope;
|
|
2169
|
+
const dir = 1 / Math.hypot(1, slope);
|
|
2170
|
+
if (part.divergingLength) {
|
|
2171
|
+
const L = part.divergingLength.inches;
|
|
2172
|
+
return {
|
|
2173
|
+
x: frogX + L * dir,
|
|
2174
|
+
y: closure.offsetAt(frogX - points.inches) + L * slope * dir,
|
|
2175
|
+
measured: true
|
|
2176
|
+
};
|
|
2177
|
+
}
|
|
2178
|
+
return {
|
|
2179
|
+
x: overall.inches,
|
|
2180
|
+
y: closure.offsetAt(overall.inches - points.inches),
|
|
2181
|
+
measured: false
|
|
2182
|
+
};
|
|
2183
|
+
};
|
|
2184
|
+
const weakest = (...ds) => {
|
|
2185
|
+
const rank = ["measured", "manufacturer", "derived", "unverified"];
|
|
2186
|
+
let worst = 0;
|
|
2187
|
+
for (const d of ds) if (d) worst = Math.max(worst, rank.indexOf(d.source));
|
|
2188
|
+
return rank[worst];
|
|
2189
|
+
};
|
|
2190
|
+
const de = divergingEnd();
|
|
2191
|
+
const legAngle = Math.atan(closure.frogSlope) * 180 / Math.PI;
|
|
2192
|
+
if (isWye) {
|
|
2193
|
+
return {
|
|
2194
|
+
joints: [
|
|
2195
|
+
{ id: "throat", role: "throat", x: 0, y: 0, angleDeg: 180 },
|
|
2196
|
+
{ id: "legA", role: "diverge", x: de.x, y: de.y, angleDeg: legAngle },
|
|
2197
|
+
{ id: "legB", role: "divergeB", x: de.x, y: -de.y, angleDeg: -legAngle }
|
|
2198
|
+
],
|
|
2199
|
+
routes: [
|
|
2200
|
+
["throat", "legA"],
|
|
2201
|
+
["throat", "legB"]
|
|
2202
|
+
],
|
|
2203
|
+
source: weakest(points, overall, frog, part.divergingLength),
|
|
2204
|
+
divergingEndMeasured: de.measured
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
return {
|
|
2208
|
+
joints: [
|
|
2209
|
+
{ id: "throat", role: "throat", x: 0, y: 0, angleDeg: 180 },
|
|
2210
|
+
{ id: "through", role: "through", x: overall.inches, y: 0, angleDeg: 0 },
|
|
2211
|
+
{ id: "diverge", role: "diverge", x: de.x, y: de.y, angleDeg: legAngle }
|
|
2212
|
+
],
|
|
2213
|
+
routes: [
|
|
2214
|
+
["throat", "through"],
|
|
2215
|
+
["throat", "diverge"]
|
|
2216
|
+
],
|
|
2217
|
+
source: weakest(points, overall, frog, part.divergingLength),
|
|
2218
|
+
divergingEndMeasured: de.measured
|
|
2219
|
+
};
|
|
2220
|
+
}
|
|
2221
|
+
function partsPlaceable(library = BUILT_IN_TRACK_PARTS) {
|
|
2222
|
+
const placeable = [];
|
|
2223
|
+
const blocked = [];
|
|
2224
|
+
for (const p of library) {
|
|
2225
|
+
const why = partGeometryGap(p);
|
|
2226
|
+
if (why) blocked.push({ part: p, why });
|
|
2227
|
+
else if (partGeometry(p, library)) placeable.push(p);
|
|
2228
|
+
else blocked.push({ part: p, why: "dimensions present but inconsistent" });
|
|
2229
|
+
}
|
|
2230
|
+
return { placeable, blocked };
|
|
2231
|
+
}
|
|
2131
2232
|
function frogCasting(cl, opts = {}) {
|
|
2132
2233
|
const g = opts.gaugeInches ?? RAIL_GAUGE_INCHES;
|
|
2133
2234
|
const w = opts.reachInches ?? g * 1.5;
|
|
@@ -2778,7 +2879,10 @@ exports.nextId = nextId;
|
|
|
2778
2879
|
exports.parseXtpLibrary = parseXtpLibrary;
|
|
2779
2880
|
exports.partExtent = partExtent;
|
|
2780
2881
|
exports.partExtentForSize = partExtentForSize;
|
|
2882
|
+
exports.partGeometry = partGeometry;
|
|
2883
|
+
exports.partGeometryGap = partGeometryGap;
|
|
2781
2884
|
exports.partOutlineAtFrog = partOutlineAtFrog;
|
|
2885
|
+
exports.partsPlaceable = partsPlaceable;
|
|
2782
2886
|
exports.pastFrogInchesForSize = pastFrogInchesForSize;
|
|
2783
2887
|
exports.pathLengthInches = pathLengthInches;
|
|
2784
2888
|
exports.poseNeedsManual = poseNeedsManual;
|