@willcgage/module-schematic 0.91.0 → 0.92.1

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 CHANGED
@@ -5,6 +5,8 @@ var FREEMO_ENDPLATE_WIDTH_MIN_INCHES = 12;
5
5
  var FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES = 24;
6
6
  var FREEMO_TRACK_SPACING_INCHES = 1.125;
7
7
  var FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES = 4;
8
+ var FREEMO_MAIN_MIN_RADIUS_INCHES = 22;
9
+ var FREEMO_REVERSE_CURVE_STRAIGHT_INCHES = 6;
8
10
  var PINCH_EASE_INCHES = 3;
9
11
  function laneOffsetAt(lane, pos, pinches, spacingInches = FREEMO_TRACK_SPACING_INCHES) {
10
12
  const base = (lane ?? 0) * spacingInches;
@@ -2268,8 +2270,16 @@ function pieceRoutePaths(piece, library = BUILT_IN_TRACK_PARTS) {
2268
2270
  const b = at(route[1]);
2269
2271
  if (!a || !b) continue;
2270
2272
  const ends = [{ x: a.x, y: a.y }, { x: b.x, y: b.y }];
2273
+ if (part.kind === "flex") {
2274
+ const pts2 = flexRunPoints(piece.lengthInches ?? 0, piece.radiusInches).map(
2275
+ (q) => place(q.x, q.y)
2276
+ );
2277
+ pts2[pts2.length - 1] = { x: b.x, y: b.y };
2278
+ out.push({ route, points: pts2 });
2279
+ continue;
2280
+ }
2271
2281
  const diverging = route.some((r) => r === "diverge" || r === "legA" || r === "legB");
2272
- if (!diverging || part.kind === "flex") {
2282
+ if (!diverging) {
2273
2283
  out.push({ route, points: ends });
2274
2284
  continue;
2275
2285
  }
@@ -2308,6 +2318,25 @@ function partsPlaceable(library = BUILT_IN_TRACK_PARTS) {
2308
2318
  return { placeable, blocked };
2309
2319
  }
2310
2320
  var JOINT_SNAP_INCHES = 0.01;
2321
+ function flexRunEnd(lengthInches, radiusInches) {
2322
+ const L = lengthInches;
2323
+ const R = radiusInches;
2324
+ if (!R || !Number.isFinite(R) || Math.abs(R) < 1e-6)
2325
+ return { x: L, y: 0, headingDeg: 0 };
2326
+ const theta = L / R;
2327
+ return {
2328
+ x: Math.abs(R) * Math.sin(Math.abs(theta)) * Math.sign(L || 1),
2329
+ y: R * (1 - Math.cos(theta)),
2330
+ headingDeg: theta * 180 / Math.PI
2331
+ };
2332
+ }
2333
+ function flexRunPoints(lengthInches, radiusInches, steps = 16) {
2334
+ if (!radiusInches || !Number.isFinite(radiusInches) || Math.abs(radiusInches) < 1e-6)
2335
+ return [{ x: 0, y: 0 }, { x: lengthInches, y: 0 }];
2336
+ const out = [];
2337
+ for (let i = 0; i <= steps; i++) out.push(flexRunEnd(lengthInches * i / steps, radiusInches));
2338
+ return out.map((p) => ({ x: p.x, y: p.y }));
2339
+ }
2311
2340
  function placedJoints(pieces, library = BUILT_IN_TRACK_PARTS) {
2312
2341
  const out = [];
2313
2342
  const RAD = Math.PI / 180;
@@ -2318,10 +2347,13 @@ function placedJoints(pieces, library = BUILT_IN_TRACK_PARTS) {
2318
2347
  if (!geo) continue;
2319
2348
  const c = Math.cos(p.rotationDeg * RAD);
2320
2349
  const s = Math.sin(p.rotationDeg * RAD);
2350
+ const run = part.kind === "flex" ? flexRunEnd(p.lengthInches ?? 0, p.radiusInches) : null;
2321
2351
  for (const j of geo.joints) {
2322
- const lx = part.kind === "flex" && j.id === "b" ? p.lengthInches ?? 0 : j.x;
2323
- const ly = p.flipped ? -j.y : j.y;
2324
- const h = (p.flipped ? -j.angleDeg : j.angleDeg) + p.rotationDeg;
2352
+ const far = run && j.id === "b";
2353
+ const lx = far ? run.x : j.x;
2354
+ const ly = p.flipped ? -(far ? run.y : j.y) : far ? run.y : j.y;
2355
+ const local = far ? run.headingDeg : j.angleDeg;
2356
+ const h = (p.flipped ? -local : local) + p.rotationDeg;
2325
2357
  out.push({
2326
2358
  key: `${p.id}.${j.id}`,
2327
2359
  piece: p.id,
@@ -2427,7 +2459,15 @@ function walkTrackGraph(graph, pieces, startAt, library = BUILT_IN_TRACK_PARTS)
2427
2459
  const part = partOf(pid);
2428
2460
  return part ? partGeometry(part, library) : null;
2429
2461
  };
2430
- const gap = (a, b) => a && b ? Math.hypot(a.x - b.x, a.y - b.y) : 0;
2462
+ const gap = (a, b) => {
2463
+ if (!a || !b) return 0;
2464
+ if (a.piece === b.piece) {
2465
+ const piece = pieceById.get(a.piece);
2466
+ const part = piece ? partOf(a.piece) : void 0;
2467
+ if (piece && part?.kind === "flex") return piece.lengthInches ?? 0;
2468
+ }
2469
+ return Math.hypot(a.x - b.x, a.y - b.y);
2470
+ };
2431
2471
  const routes = [];
2432
2472
  const turnouts = [];
2433
2473
  const warnings = [];
@@ -3340,6 +3380,8 @@ exports.FLEX_TRACK_PARTS = FLEX_TRACK_PARTS;
3340
3380
  exports.FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES = FREEMO_ENDPLATE_TRACK_FASCIA_CLEARANCE_INCHES;
3341
3381
  exports.FREEMO_ENDPLATE_WIDTH_MIN_INCHES = FREEMO_ENDPLATE_WIDTH_MIN_INCHES;
3342
3382
  exports.FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES;
3383
+ exports.FREEMO_MAIN_MIN_RADIUS_INCHES = FREEMO_MAIN_MIN_RADIUS_INCHES;
3384
+ exports.FREEMO_REVERSE_CURVE_STRAIGHT_INCHES = FREEMO_REVERSE_CURVE_STRAIGHT_INCHES;
3343
3385
  exports.FREEMO_TRACK_SPACING_INCHES = FREEMO_TRACK_SPACING_INCHES;
3344
3386
  exports.JOINT_SNAP_INCHES = JOINT_SNAP_INCHES;
3345
3387
  exports.MAIN2_TRACK_ID = MAIN2_TRACK_ID;
@@ -3378,6 +3420,7 @@ exports.endplateWidthInches = endplateWidthInches;
3378
3420
  exports.flexPartFor = flexPartFor;
3379
3421
  exports.flexParts = flexParts;
3380
3422
  exports.flexPieces = flexPieces;
3423
+ exports.flexRunEnd = flexRunEnd;
3381
3424
  exports.flexUsage = flexUsage;
3382
3425
  exports.frogCasting = frogCasting;
3383
3426
  exports.frogNumberFromName = frogNumberFromName;