@willcgage/module-schematic 0.46.0 → 0.48.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 CHANGED
@@ -474,7 +474,9 @@ function moduleFootprint(input) {
474
474
  return {
475
475
  centerline,
476
476
  band: benchworkBand(centerline, widthA, widthB, offA, offB),
477
- endplateFaces: endplateFaceSegments(centerline, widthA, widthB, offA, offB),
477
+ // A loop's centre-line ends at the throat, not a far endplate — keep only
478
+ // endplate A's face (the far face would be a spurious plate at the throat).
479
+ endplateFaces: input.loop ? endplateFaceSegments(centerline, widthA, widthB, offA, offB).slice(0, 1) : endplateFaceSegments(centerline, widthA, widthB, offA, offB),
478
480
  outline: sectionOutlines.length || !authored ? null : sampleBenchworkOutline(authored),
479
481
  sectionOutlines
480
482
  };
@@ -1320,6 +1322,83 @@ function moduleFeatures(doc) {
1320
1322
  laneMax: Math.max(...allLanes)
1321
1323
  };
1322
1324
  }
1325
+ function returnLoop(shape, opts) {
1326
+ const L = Math.max(1, opts.leadInches);
1327
+ const R = Math.max(1, opts.radius);
1328
+ const hw = Math.min(opts.boardHalfWidth ?? 6, R - 1);
1329
+ const T = { x: L, y: 0 };
1330
+ const r2 = (v) => Math.round(v * 100) / 100;
1331
+ const rd = (pts) => pts.map((p) => ({ x: r2(p.x), y: r2(p.y) }));
1332
+ const arc = (cx, cy, r, a0, a12, steps) => {
1333
+ const out = [];
1334
+ for (let i = 0; i <= steps; i++) out.push({ x: cx + r * Math.cos(a0 + (a12 - a0) * i / steps), y: cy + r * Math.sin(a0 + (a12 - a0) * i / steps) });
1335
+ return out;
1336
+ };
1337
+ if (shape === "square") {
1338
+ const s = 2 * R;
1339
+ const loop2 = [
1340
+ { x: L, y: 0 },
1341
+ { x: L, y: R },
1342
+ { x: L + s, y: R },
1343
+ { x: L + s, y: -R },
1344
+ { x: L, y: -R },
1345
+ { x: L, y: 0 }
1346
+ ];
1347
+ return {
1348
+ throat: T,
1349
+ loop: rd(loop2),
1350
+ wyeLegs: [rd([T, { x: L, y: R }]), rd([T, { x: L, y: -R }])],
1351
+ wyeHalfAngleDeg: 90,
1352
+ outlineOuter: rd([
1353
+ { x: 0, y: hw },
1354
+ { x: L + s + hw, y: hw },
1355
+ { x: L + s + hw, y: -R - hw },
1356
+ { x: 0, y: -R - hw }
1357
+ ]),
1358
+ outlineInner: rd([
1359
+ { x: L + hw, y: R - hw },
1360
+ { x: L + s - hw, y: R - hw },
1361
+ { x: L + s - hw, y: -R + hw },
1362
+ { x: L + hw, y: -R + hw }
1363
+ ])
1364
+ };
1365
+ }
1366
+ const D = shape === "circle" ? R * 1.15 : R * 1.6;
1367
+ const offY = shape === "offset-teardrop" ? R * 0.7 : 0;
1368
+ const C = { x: L + D, y: offY };
1369
+ const dist = Math.hypot(C.x - T.x, C.y - T.y);
1370
+ const ac = Math.acos(Math.min(1, R / dist));
1371
+ const base = Math.atan2(T.y - C.y, T.x - C.x);
1372
+ const a1 = base + ac;
1373
+ const a2 = base - ac;
1374
+ const P1 = { x: C.x + R * Math.cos(a1), y: C.y + R * Math.sin(a1) };
1375
+ const P2 = { x: C.x + R * Math.cos(a2), y: C.y + R * Math.sin(a2) };
1376
+ const loop = [T, P1, ...arc(C.x, C.y, R, a1, a2 + 2 * Math.PI, 64).slice(1), T];
1377
+ const legDir = (P) => Math.atan2(P.y - T.y, P.x - T.x);
1378
+ const half = Math.abs((legDir(P1) - legDir(P2) + Math.PI) % (2 * Math.PI) - Math.PI) / 2;
1379
+ const ringOuter = (rr) => {
1380
+ const xTop = C.x - Math.sqrt(Math.max(0, rr * rr - (hw - C.y) ** 2));
1381
+ const xBot = C.x - Math.sqrt(Math.max(0, rr * rr - (-hw - C.y) ** 2));
1382
+ const tTop = Math.atan2(hw - C.y, xTop - C.x);
1383
+ const tBot = Math.atan2(-hw - C.y, xBot - C.x);
1384
+ return [
1385
+ { x: 0, y: hw },
1386
+ { x: xTop, y: hw },
1387
+ ...arc(C.x, C.y, rr, tTop, tBot - 2 * Math.PI, 48).slice(1, -1),
1388
+ { x: xBot, y: -hw },
1389
+ { x: 0, y: -hw }
1390
+ ];
1391
+ };
1392
+ const Ri = R - hw;
1393
+ return {
1394
+ throat: T,
1395
+ loop: rd(loop),
1396
+ wyeLegs: [rd([T, P1]), rd([T, P2])],
1397
+ wyeHalfAngleDeg: r2(half * 180 / Math.PI),
1398
+ outlineOuter: rd(ringOuter(R + hw)),
1399
+ outlineInner: Ri > 2 ? rd(arc(C.x, C.y, Ri, 0, 2 * Math.PI, 40)) : []
1400
+ };
1401
+ }
1323
1402
  function geometryTurnDegrees(geometryType, geometryDegrees) {
1324
1403
  switch (geometryType) {
1325
1404
  case "corner_45":
@@ -1533,6 +1612,7 @@ exports.nextId = nextId;
1533
1612
  exports.poseNeedsManual = poseNeedsManual;
1534
1613
  exports.poseOverridesFromDoc = poseOverridesFromDoc;
1535
1614
  exports.remapPos = remapPos;
1615
+ exports.returnLoop = returnLoop;
1536
1616
  exports.sampleBenchworkOutline = sampleBenchworkOutline;
1537
1617
  exports.samplePath = samplePath;
1538
1618
  exports.scaleFeetToInches = scaleFeetToInches;