@willcgage/module-schematic 0.30.0 → 0.32.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 +162 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -18
- package/dist/index.d.ts +69 -18
- package/dist/index.js +158 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -35,12 +35,26 @@ function moduleSections(doc) {
|
|
|
35
35
|
};
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
-
function sectionFootprints(doc) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
function sectionFootprints(doc, derive) {
|
|
39
|
+
const spans = derive ? sectionSpans(doc) : [];
|
|
40
|
+
const spanOf = new Map(spans.map((sp) => [sp.id, sp]));
|
|
41
|
+
return moduleSections(doc).map((sec) => {
|
|
42
|
+
const name = sec.name ? { name: sec.name } : {};
|
|
43
|
+
if (sec.outline)
|
|
44
|
+
return { id: sec.id, ...name, outline: sampleBenchworkOutline(sec.outline), derived: false };
|
|
45
|
+
const sp = spanOf.get(sec.id);
|
|
46
|
+
if (!sp || !derive) return null;
|
|
47
|
+
const band = sectionBand(
|
|
48
|
+
derive.centerline,
|
|
49
|
+
sp.fromPos,
|
|
50
|
+
sp.toPos,
|
|
51
|
+
derive.widthA,
|
|
52
|
+
derive.widthB,
|
|
53
|
+
derive.offsetA,
|
|
54
|
+
derive.offsetB
|
|
55
|
+
);
|
|
56
|
+
return band.length >= 3 ? { id: sec.id, ...name, outline: band, derived: true } : null;
|
|
57
|
+
}).filter((x) => x !== null);
|
|
44
58
|
}
|
|
45
59
|
function sampleBenchworkOutline(pts, segsPerArc = 20) {
|
|
46
60
|
const n = pts.length;
|
|
@@ -256,6 +270,136 @@ function benchworkBand(center, widthA = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES
|
|
|
256
270
|
}));
|
|
257
271
|
return [...left, ...right.reverse()];
|
|
258
272
|
}
|
|
273
|
+
function sliceCenterline(center, fromPos, toPos) {
|
|
274
|
+
if (center.length < 2) return [];
|
|
275
|
+
const cum = [0];
|
|
276
|
+
for (let i = 1; i < center.length; i++)
|
|
277
|
+
cum.push(cum[i - 1] + Math.hypot(center[i].x - center[i - 1].x, center[i].y - center[i - 1].y));
|
|
278
|
+
const total = cum[cum.length - 1];
|
|
279
|
+
const a = Math.max(0, Math.min(total, Math.min(fromPos, toPos)));
|
|
280
|
+
const b = Math.max(0, Math.min(total, Math.max(fromPos, toPos)));
|
|
281
|
+
if (b - a <= 0) return [];
|
|
282
|
+
const at = (d) => {
|
|
283
|
+
for (let i = 1; i < center.length; i++) {
|
|
284
|
+
if (d <= cum[i] || i === center.length - 1) {
|
|
285
|
+
const seg = cum[i] - cum[i - 1] || 1;
|
|
286
|
+
const t = Math.max(0, Math.min(1, (d - cum[i - 1]) / seg));
|
|
287
|
+
return {
|
|
288
|
+
x: center[i - 1].x + (center[i].x - center[i - 1].x) * t,
|
|
289
|
+
y: center[i - 1].y + (center[i].y - center[i - 1].y) * t
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return center[center.length - 1];
|
|
294
|
+
};
|
|
295
|
+
const out = [at(a)];
|
|
296
|
+
for (let i = 0; i < center.length; i++) {
|
|
297
|
+
if (cum[i] > a && cum[i] < b) out.push({ x: center[i].x, y: center[i].y });
|
|
298
|
+
}
|
|
299
|
+
out.push(at(b));
|
|
300
|
+
return out;
|
|
301
|
+
}
|
|
302
|
+
function sectionBand(center, fromPos, toPos, widthA = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, widthB = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, offsetA = 0, offsetB = 0) {
|
|
303
|
+
const slice = sliceCenterline(center, fromPos, toPos);
|
|
304
|
+
if (slice.length < 2) return [];
|
|
305
|
+
let total = 0;
|
|
306
|
+
for (let i = 1; i < center.length; i++)
|
|
307
|
+
total += Math.hypot(center[i].x - center[i - 1].x, center[i].y - center[i - 1].y);
|
|
308
|
+
total = total || 1;
|
|
309
|
+
const lo = Math.min(fromPos, toPos);
|
|
310
|
+
let acc = 0;
|
|
311
|
+
const fr = [0];
|
|
312
|
+
for (let i = 1; i < slice.length; i++) {
|
|
313
|
+
acc += Math.hypot(slice[i].x - slice[i - 1].x, slice[i].y - slice[i - 1].y);
|
|
314
|
+
fr.push(acc);
|
|
315
|
+
}
|
|
316
|
+
const f = fr.map((d) => Math.max(0, Math.min(1, (lo + d) / total)));
|
|
317
|
+
const n = centerlineNormals(slice);
|
|
318
|
+
const half = (i) => (widthA * (1 - f[i]) + widthB * f[i]) / 2;
|
|
319
|
+
const off = (i) => offsetA * (1 - f[i]) + offsetB * f[i];
|
|
320
|
+
const left = slice.map((p, i) => ({
|
|
321
|
+
x: p.x + n[i].x * (off(i) + half(i)),
|
|
322
|
+
y: p.y + n[i].y * (off(i) + half(i))
|
|
323
|
+
}));
|
|
324
|
+
const right = slice.map((p, i) => ({
|
|
325
|
+
x: p.x + n[i].x * (off(i) - half(i)),
|
|
326
|
+
y: p.y + n[i].y * (off(i) - half(i))
|
|
327
|
+
}));
|
|
328
|
+
return [...left, ...right.reverse()];
|
|
329
|
+
}
|
|
330
|
+
function ringEdges(pts) {
|
|
331
|
+
const out = [];
|
|
332
|
+
for (let i = 0; i < pts.length; i++) out.push([pts[i], pts[(i + 1) % pts.length]]);
|
|
333
|
+
return out;
|
|
334
|
+
}
|
|
335
|
+
function sharedEdgeLength(e1, e2, gap, angleDeg) {
|
|
336
|
+
const ux = e1[1].x - e1[0].x;
|
|
337
|
+
const uy = e1[1].y - e1[0].y;
|
|
338
|
+
const ul = Math.hypot(ux, uy);
|
|
339
|
+
const vx = e2[1].x - e2[0].x;
|
|
340
|
+
const vy = e2[1].y - e2[0].y;
|
|
341
|
+
const vl = Math.hypot(vx, vy);
|
|
342
|
+
if (ul < 1e-6 || vl < 1e-6) return 0;
|
|
343
|
+
const dx = ux / ul;
|
|
344
|
+
const dy = uy / ul;
|
|
345
|
+
const cross = Math.abs((dx * vy - dy * vx) / vl);
|
|
346
|
+
if (cross > Math.sin(angleDeg * Math.PI / 180)) return 0;
|
|
347
|
+
const perp = (q) => Math.abs((q.x - e1[0].x) * -dy + (q.y - e1[0].y) * dx);
|
|
348
|
+
if (perp(e2[0]) > gap || perp(e2[1]) > gap) return 0;
|
|
349
|
+
const proj = (q) => (q.x - e1[0].x) * dx + (q.y - e1[0].y) * dy;
|
|
350
|
+
const t1 = proj(e2[0]);
|
|
351
|
+
const t2 = proj(e2[1]);
|
|
352
|
+
return Math.max(0, Math.min(ul, Math.max(t1, t2)) - Math.max(0, Math.min(t1, t2)));
|
|
353
|
+
}
|
|
354
|
+
function sectionAdjacency(footprints, opts) {
|
|
355
|
+
const gap = opts?.gapInches ?? 0.5;
|
|
356
|
+
const angle = opts?.angleDegrees ?? 3;
|
|
357
|
+
const min = opts?.minOverlapInches ?? 1;
|
|
358
|
+
const edges = footprints.map((f) => ringEdges(f.outline));
|
|
359
|
+
const out = [];
|
|
360
|
+
for (let i = 0; i < footprints.length; i++) {
|
|
361
|
+
for (let j = i + 1; j < footprints.length; j++) {
|
|
362
|
+
let total = 0;
|
|
363
|
+
for (const e1 of edges[i])
|
|
364
|
+
for (const e2 of edges[j]) total += sharedEdgeLength(e1, e2, gap, angle);
|
|
365
|
+
if (total >= min)
|
|
366
|
+
out.push({
|
|
367
|
+
a: footprints[i].id,
|
|
368
|
+
b: footprints[j].id,
|
|
369
|
+
lengthInches: Math.round(total * 1e3) / 1e3
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return out;
|
|
374
|
+
}
|
|
375
|
+
function sectionNeighbours(id, adj) {
|
|
376
|
+
return adj.filter((x) => x.a === id || x.b === id).map((x) => x.a === id ? x.b : x.a);
|
|
377
|
+
}
|
|
378
|
+
function sectionComponents(ids, adj) {
|
|
379
|
+
const parent = new Map(ids.map((id) => [id, id]));
|
|
380
|
+
const find = (x) => {
|
|
381
|
+
let r = x;
|
|
382
|
+
while (parent.get(r) !== r) r = parent.get(r);
|
|
383
|
+
while (parent.get(x) !== r) {
|
|
384
|
+
const nx = parent.get(x);
|
|
385
|
+
parent.set(x, r);
|
|
386
|
+
x = nx;
|
|
387
|
+
}
|
|
388
|
+
return r;
|
|
389
|
+
};
|
|
390
|
+
for (const { a, b } of adj) {
|
|
391
|
+
if (!parent.has(a) || !parent.has(b)) continue;
|
|
392
|
+
const ra = find(a);
|
|
393
|
+
const rb = find(b);
|
|
394
|
+
if (ra !== rb) parent.set(ra, rb);
|
|
395
|
+
}
|
|
396
|
+
const groups = /* @__PURE__ */ new Map();
|
|
397
|
+
for (const id of ids) {
|
|
398
|
+
const r = find(id);
|
|
399
|
+
groups.set(r, [...groups.get(r) ?? [], id]);
|
|
400
|
+
}
|
|
401
|
+
return [...groups.values()];
|
|
402
|
+
}
|
|
259
403
|
function endplateFaceSegments(center, widthA = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, widthB = FREEMO_ENDPLATE_WIDTH_RECOMMENDED_INCHES, offsetA = 0, offsetB = 0) {
|
|
260
404
|
if (center.length < 2) return [];
|
|
261
405
|
const n = centerlineNormals(center);
|
|
@@ -273,7 +417,13 @@ function moduleFootprint(input) {
|
|
|
273
417
|
const authored = benchworkOutline(input);
|
|
274
418
|
const offA = input.endplateTrackOffsets?.["A"] ?? 0;
|
|
275
419
|
const offB = input.endplateTrackOffsets?.["B"] ?? 0;
|
|
276
|
-
const sectionOutlines = sectionFootprints(input
|
|
420
|
+
const sectionOutlines = sectionFootprints(input, {
|
|
421
|
+
centerline,
|
|
422
|
+
widthA,
|
|
423
|
+
widthB,
|
|
424
|
+
offsetA: offA,
|
|
425
|
+
offsetB: offB
|
|
426
|
+
});
|
|
277
427
|
return {
|
|
278
428
|
centerline,
|
|
279
429
|
band: benchworkBand(centerline, widthA, widthB, offA, offB),
|
|
@@ -1233,10 +1383,15 @@ exports.poseOverridesFromDoc = poseOverridesFromDoc;
|
|
|
1233
1383
|
exports.sampleBenchworkOutline = sampleBenchworkOutline;
|
|
1234
1384
|
exports.samplePath = samplePath;
|
|
1235
1385
|
exports.scaleFeetToInches = scaleFeetToInches;
|
|
1386
|
+
exports.sectionAdjacency = sectionAdjacency;
|
|
1387
|
+
exports.sectionBand = sectionBand;
|
|
1236
1388
|
exports.sectionBreaksFromSections = sectionBreaksFromSections;
|
|
1389
|
+
exports.sectionComponents = sectionComponents;
|
|
1237
1390
|
exports.sectionFootprints = sectionFootprints;
|
|
1391
|
+
exports.sectionNeighbours = sectionNeighbours;
|
|
1238
1392
|
exports.sectionSpans = sectionSpans;
|
|
1239
1393
|
exports.sectionedCenterline = sectionedCenterline;
|
|
1394
|
+
exports.sliceCenterline = sliceCenterline;
|
|
1240
1395
|
exports.stateToDoc = stateToDoc;
|
|
1241
1396
|
exports.trackPath = trackPath;
|
|
1242
1397
|
//# sourceMappingURL=index.cjs.map
|