brepjs 18.76.0 → 18.78.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/2d.cjs +6 -6
- package/dist/2d.js +6 -6
- package/dist/{blueprint-BHyTsY5E.cjs → blueprint-BE93BNYE.cjs} +5 -5
- package/dist/{blueprint-DuT3LJGx.js → blueprint-BVe9JU-L.js} +5 -5
- package/dist/{blueprintFns-dPHJgrqC.cjs → blueprintFns-B_7kKwEZ.cjs} +2 -2
- package/dist/{blueprintFns-qaEV4X2R.js → blueprintFns-DWinspVK.js} +2 -2
- package/dist/{blueprintSketcher-Th4H1tao.cjs → blueprintSketcher-D75tuXkF.cjs} +3 -3
- package/dist/{blueprintSketcher-IY1gJ613.js → blueprintSketcher-DL-wgnVs.js} +3 -3
- package/dist/{boolean2D-BGK18W_l.cjs → boolean2D-C4Txi8U1.cjs} +4 -4
- package/dist/{boolean2D-DUDg_dMv.js → boolean2D-OtHT7POp.js} +4 -4
- package/dist/brepjs.cjs +153 -152
- package/dist/brepjs.js +26 -26
- package/dist/{cameraFns-Ctxe8ev-.js → cameraFns-DCXqzH_m.js} +2 -2
- package/dist/{cameraFns-G2lc5c9M.cjs → cameraFns-DfSRnD1k.cjs} +2 -2
- package/dist/core.cjs +1 -1
- package/dist/core.js +1 -1
- package/dist/{cornerFinder-DamaTij5.js → cornerFinder-DPkLU1Of.js} +1 -1
- package/dist/{cornerFinder-CxqA_AYe.cjs → cornerFinder-KuLU-4pQ.cjs} +1 -1
- package/dist/{curveFns-CwOY58kC.js → curveFns-B4KEYU1M.js} +1 -1
- package/dist/{curveFns-B8UdENpg.cjs → curveFns-C0oCmjV2.cjs} +1 -1
- package/dist/{drawFns-CcR9_01X.js → drawFns-C6h_w03r.js} +12 -12
- package/dist/{drawFns-BwfhGs8Z.cjs → drawFns-DxjMxRpE.cjs} +12 -12
- package/dist/{faceFns-BJ0mbRh5.js → faceFns-BJ2hzXJp.js} +2 -2
- package/dist/{faceFns-CZvemlPW.cjs → faceFns-p0lyVuyw.cjs} +2 -2
- package/dist/{primitiveFns-FudrSXrp.cjs → healingFns-B7dElsC4.cjs} +9 -466
- package/dist/{primitiveFns-B6Q6lx9-.js → healingFns-DS_nK9KF.js} +8 -303
- package/dist/{helpers-DsaGpuUh.js → helpers-C78MY-s6.js} +6 -6
- package/dist/{helpers-90SKWHEY.cjs → helpers-DTBDjbdR.cjs} +6 -6
- package/dist/{importFns-CXH2OmJ6.cjs → importFns-CUAiLgt_.cjs} +2 -2
- package/dist/{importFns-B02-HKco.js → importFns-Rv22QSn6.js} +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/io.cjs +2 -2
- package/dist/io.js +2 -2
- package/dist/kernel/occt/geometryQueryOps.d.ts +5 -1
- package/dist/kernel/occtWasm/occtWasmAdapter.cjs +1 -1
- package/dist/kernel/occtWasm/occtWasmAdapter.js +1 -1
- package/dist/kernel/occtWasm/surfaceOps.d.ts +5 -1
- package/dist/{extrudeFns-msxcCUm2.js → loftFns-DuxEscJB.js} +93 -2
- package/dist/{extrudeFns-b7JHaMsv.cjs → loftFns-DycLH1Pq.cjs} +104 -1
- package/dist/{measureFns-DYeTPyHr.js → measureFns-C8c6xRUE.js} +3 -3
- package/dist/{measureFns-CRS3U8gj.cjs → measureFns-DnxobCbD.cjs} +3 -3
- package/dist/measurement.cjs +1 -1
- package/dist/measurement.js +1 -1
- package/dist/{meshFns-CvmTzMPL.cjs → meshFns-BawS1xNA.cjs} +3 -3
- package/dist/{meshFns-CLQL2D95.js → meshFns-CuYzpojl.js} +3 -3
- package/dist/{occtWasmAdapter-m4Nua92H.js → occtWasmAdapter-BrTkhQYK.js} +83 -6
- package/dist/{occtWasmAdapter-DdghAlnN.cjs → occtWasmAdapter-W86SRBpi.cjs} +83 -6
- package/dist/operations/threadFns.d.ts +39 -0
- package/dist/operations.cjs +33 -32
- package/dist/operations.d.ts +1 -0
- package/dist/operations.js +3 -3
- package/dist/{booleanFns-Cu-J1THp.js → primitiveFns-BxH5omw3.js} +301 -7
- package/dist/{booleanFns-DxnTjP19.cjs → primitiveFns-JRmXxbRr.cjs} +460 -4
- package/dist/projection.cjs +1 -1
- package/dist/projection.js +1 -1
- package/dist/query.cjs +2 -2
- package/dist/query.js +2 -2
- package/dist/{shapeFns-CQmd2W5F.cjs → shapeFns-D5WNrq3s.cjs} +2 -2
- package/dist/{shapeFns-CQRGTifg.js → shapeFns-DZ6poxP7.js} +2 -2
- package/dist/shapeRef.cjs +1 -1
- package/dist/shapeRef.js +1 -1
- package/dist/{shapeRefFns-DoPplxoN.cjs → shapeRefFns-BOWP8n4j.cjs} +4 -4
- package/dist/{shapeRefFns-DvIvS0do.js → shapeRefFns-ClsyeZp4.js} +4 -4
- package/dist/{shapeTypes-C4cMKLoj.cjs → shapeTypes-CxSqNvHA.cjs} +55 -26
- package/dist/{shapeTypes-VCBsDI43.js → shapeTypes-CyTY0prh.js} +55 -26
- package/dist/sketching.cjs +3 -3
- package/dist/sketching.js +3 -3
- package/dist/{solidBuilders-DBsHetmI.js → solidBuilders-BtEFUFQ9.js} +2 -2
- package/dist/{solidBuilders-B0Hzin8a.cjs → solidBuilders-diw2zyyN.cjs} +2 -2
- package/dist/{surfaceBuilders-QK_Cnn_u.cjs → surfaceBuilders-CPHOXRLE.cjs} +2 -2
- package/dist/{surfaceBuilders-DllH3kXs.js → surfaceBuilders-Do0rypyD.js} +2 -2
- package/dist/text.cjs +2 -2
- package/dist/text.js +2 -2
- package/dist/{textBlueprints-C_ThSDVg.js → textBlueprints-C3IbySW_.js} +9 -99
- package/dist/{textBlueprints-8lNMcsUv.cjs → textBlueprints-SKuamOmI.cjs} +17 -119
- package/dist/{textMetrics-CxdhimFF.js → textMetrics--BwiJH2B.js} +1 -1
- package/dist/{textMetrics-Bn5VPcTV.cjs → textMetrics-Bzbkal_A.cjs} +1 -1
- package/dist/{historyFns-BV5sQxft.js → threadFns-D8-zfJ0b.js} +73 -6
- package/dist/{historyFns-xUNAdUYV.cjs → threadFns-aWgxzqmT.cjs} +79 -6
- package/dist/topology/booleanFns.d.ts +9 -1
- package/dist/topology.cjs +39 -39
- package/dist/topology.js +7 -7
- package/dist/{topologyQueryFns-BtfhAVY2.js → topologyQueryFns-BomrmBie.js} +1 -1
- package/dist/{topologyQueryFns-Bj5wpC75.cjs → topologyQueryFns-Dzxrwn-E.cjs} +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
const require_shapeTypes = require("./shapeTypes-
|
|
1
|
+
const require_shapeTypes = require("./shapeTypes-CxSqNvHA.cjs");
|
|
2
2
|
const require_errors = require("./errors-CXJtc4I7.cjs");
|
|
3
|
+
const require_types = require("./types-KjA8tY4Y.cjs");
|
|
3
4
|
const require_vecOps = require("./vecOps-CCnJt-yH.cjs");
|
|
4
5
|
//#region src/operations/extrudeUtils.ts
|
|
5
6
|
/**
|
|
@@ -370,6 +371,96 @@ function extrudeAll(entries) {
|
|
|
370
371
|
}
|
|
371
372
|
}
|
|
372
373
|
//#endregion
|
|
374
|
+
//#region src/operations/loftFns.ts
|
|
375
|
+
/**
|
|
376
|
+
* Functional loft operation using branded shape types.
|
|
377
|
+
*/
|
|
378
|
+
/**
|
|
379
|
+
* Loft through a set of wire profiles to create a 3D shape.
|
|
380
|
+
*
|
|
381
|
+
* Builds a `BRepOffsetAPI_ThruSections` surface through the given wires,
|
|
382
|
+
* optionally starting and/or ending at point vertices. Produces a solid
|
|
383
|
+
* by default, or a shell when `returnShell` is `true`.
|
|
384
|
+
*
|
|
385
|
+
* @param wires - Ordered wire profiles to loft through.
|
|
386
|
+
* @param config - Loft configuration (ruled interpolation, start/end points).
|
|
387
|
+
* @param returnShell - When `true`, return a shell instead of a solid.
|
|
388
|
+
* @returns `Result` containing the lofted 3D shape, or an error on failure.
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```ts
|
|
392
|
+
* const result = loft([bottomWire, topWire], { ruled: false });
|
|
393
|
+
* ```
|
|
394
|
+
*
|
|
395
|
+
* @see {@link loft!loft | loft} for the OOP API equivalent.
|
|
396
|
+
*/
|
|
397
|
+
function loft(wires, { ruled = true, startPoint, endPoint, tolerance = 1e-6 } = {}, returnShell = false) {
|
|
398
|
+
if (wires.length === 0 && !startPoint && !endPoint) return require_errors.err(require_errors.validationError("LOFT_EMPTY", "Loft requires at least one wire or start/end point"));
|
|
399
|
+
const kernel = require_shapeTypes.getKernel();
|
|
400
|
+
const startVertex = startPoint ? kernel.makeVertex(...require_types.toVec3(startPoint)) : void 0;
|
|
401
|
+
const endVertex = endPoint ? kernel.makeVertex(...require_types.toVec3(endPoint)) : void 0;
|
|
402
|
+
try {
|
|
403
|
+
const result = require_shapeTypes.castShape(kernel.loftAdvanced(wires.map((w) => w.wrapped), {
|
|
404
|
+
solid: !returnShell,
|
|
405
|
+
ruled,
|
|
406
|
+
tolerance,
|
|
407
|
+
...startVertex ? { startVertex } : {},
|
|
408
|
+
...endVertex ? { endVertex } : {}
|
|
409
|
+
}));
|
|
410
|
+
if (!require_shapeTypes.isShape3D(result)) return require_errors.err(require_errors.typeCastError("LOFT_NOT_3D", "Loft did not produce a 3D shape"));
|
|
411
|
+
return require_errors.ok(result);
|
|
412
|
+
} catch (e) {
|
|
413
|
+
return require_errors.err(require_errors.kernelError("LOFT_FAILED", "Loft operation failed", e, void 0, "Common causes: wire profiles with different edge counts, self-intersecting result, or profiles too far apart. Ensure profiles are compatible and ordered."));
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Batch loft: build N independent lofts in a single kernel call.
|
|
418
|
+
*
|
|
419
|
+
* Uses the C++ LoftBatch extractor when available (single WASM call),
|
|
420
|
+
* falling back to N individual loft operations otherwise.
|
|
421
|
+
*
|
|
422
|
+
* @returns Array of 3D shapes, one per entry.
|
|
423
|
+
*/
|
|
424
|
+
function loftAll(entries) {
|
|
425
|
+
if (entries.length === 0) return require_errors.ok([]);
|
|
426
|
+
const kernel = require_shapeTypes.getKernel();
|
|
427
|
+
const verticesToDelete = [];
|
|
428
|
+
const kernelEntries = entries.map((e) => {
|
|
429
|
+
const startVertex = e.startPoint ? kernel.makeVertex(...require_types.toVec3(e.startPoint)) : void 0;
|
|
430
|
+
const endVertex = e.endPoint ? kernel.makeVertex(...require_types.toVec3(e.endPoint)) : void 0;
|
|
431
|
+
if (startVertex) verticesToDelete.push(startVertex);
|
|
432
|
+
if (endVertex) verticesToDelete.push(endVertex);
|
|
433
|
+
return {
|
|
434
|
+
wires: e.wires.map((w) => w.wrapped),
|
|
435
|
+
solid: true,
|
|
436
|
+
ruled: e.ruled ?? true,
|
|
437
|
+
tolerance: e.tolerance ?? 1e-6,
|
|
438
|
+
startVertex,
|
|
439
|
+
endVertex
|
|
440
|
+
};
|
|
441
|
+
});
|
|
442
|
+
try {
|
|
443
|
+
const shapes = kernel.loftBatch?.(kernelEntries) ?? kernelEntries.map((e) => kernel.loftAdvanced(e.wires, {
|
|
444
|
+
solid: e.solid,
|
|
445
|
+
ruled: e.ruled,
|
|
446
|
+
tolerance: e.tolerance,
|
|
447
|
+
startVertex: e.startVertex,
|
|
448
|
+
endVertex: e.endVertex
|
|
449
|
+
}));
|
|
450
|
+
const results = [];
|
|
451
|
+
for (const shape of shapes) {
|
|
452
|
+
const cast = require_shapeTypes.castShape(shape);
|
|
453
|
+
if (!require_shapeTypes.isShape3D(cast)) return require_errors.err(require_errors.typeCastError("LOFT_ALL_NOT_3D", "Batch loft entry did not produce a 3D shape"));
|
|
454
|
+
results.push(cast);
|
|
455
|
+
}
|
|
456
|
+
return require_errors.ok(results);
|
|
457
|
+
} catch (e) {
|
|
458
|
+
return require_errors.err(require_errors.kernelError("LOFT_ALL_FAILED", "Batch loft operation failed", e));
|
|
459
|
+
} finally {
|
|
460
|
+
for (const v of verticesToDelete) kernel.dispose(v);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
//#endregion
|
|
373
464
|
Object.defineProperty(exports, "complexExtrude", {
|
|
374
465
|
enumerable: true,
|
|
375
466
|
get: function() {
|
|
@@ -394,6 +485,18 @@ Object.defineProperty(exports, "guidedSweep", {
|
|
|
394
485
|
return guidedSweep;
|
|
395
486
|
}
|
|
396
487
|
});
|
|
488
|
+
Object.defineProperty(exports, "loft", {
|
|
489
|
+
enumerable: true,
|
|
490
|
+
get: function() {
|
|
491
|
+
return loft;
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
Object.defineProperty(exports, "loftAll", {
|
|
495
|
+
enumerable: true,
|
|
496
|
+
get: function() {
|
|
497
|
+
return loftAll;
|
|
498
|
+
}
|
|
499
|
+
});
|
|
397
500
|
Object.defineProperty(exports, "multiSectionSweep", {
|
|
398
501
|
enumerable: true,
|
|
399
502
|
get: function() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Z as getKernel } from "./shapeTypes-
|
|
1
|
+
import { Z as getKernel } from "./shapeTypes-CyTY0prh.js";
|
|
2
2
|
import { A as ok, b as err, d as validationError, t as BrepErrorCode } from "./errors-DNWJsfVU.js";
|
|
3
|
-
import { w as kernelCallRaw } from "./topologyQueryFns-
|
|
4
|
-
import { m as uvBounds } from "./faceFns-
|
|
3
|
+
import { w as kernelCallRaw } from "./topologyQueryFns-BomrmBie.js";
|
|
4
|
+
import { m as uvBounds } from "./faceFns-BJ2hzXJp.js";
|
|
5
5
|
//#region src/measurement/measureCache.ts
|
|
6
6
|
var cache = /* @__PURE__ */ new WeakMap();
|
|
7
7
|
function getCachedMeasurement(shape, key) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const require_shapeTypes = require("./shapeTypes-
|
|
1
|
+
const require_shapeTypes = require("./shapeTypes-CxSqNvHA.cjs");
|
|
2
2
|
const require_errors = require("./errors-CXJtc4I7.cjs");
|
|
3
|
-
const require_topologyQueryFns = require("./topologyQueryFns-
|
|
4
|
-
const require_faceFns = require("./faceFns-
|
|
3
|
+
const require_topologyQueryFns = require("./topologyQueryFns-Dzxrwn-E.cjs");
|
|
4
|
+
const require_faceFns = require("./faceFns-p0lyVuyw.cjs");
|
|
5
5
|
//#region src/measurement/measureCache.ts
|
|
6
6
|
var cache = /* @__PURE__ */ new WeakMap();
|
|
7
7
|
function getCachedMeasurement(shape, key) {
|
package/dist/measurement.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_measureFns = require("./measureFns-
|
|
2
|
+
const require_measureFns = require("./measureFns-DnxobCbD.cjs");
|
|
3
3
|
exports.createDistanceQuery = require_measureFns.createDistanceQuery;
|
|
4
4
|
exports.measureArea = require_measureFns.measureArea;
|
|
5
5
|
exports.measureDistance = require_measureFns.measureDistance;
|
package/dist/measurement.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as measureDistance, c as measureLinearProps, d as measureVolumeProps, l as measureSurfaceProps, n as measureArea, o as measureDistanceProps, s as measureLength, t as createDistanceQuery, u as measureVolume } from "./measureFns-
|
|
1
|
+
import { a as measureDistance, c as measureLinearProps, d as measureVolumeProps, l as measureSurfaceProps, n as measureArea, o as measureDistanceProps, s as measureLength, t as createDistanceQuery, u as measureVolume } from "./measureFns-C8c6xRUE.js";
|
|
2
2
|
export { createDistanceQuery, measureArea, measureDistance, measureDistanceProps, measureLength, measureLinearProps, measureSurfaceProps, measureVolume, measureVolumeProps };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const require_shapeTypes = require("./shapeTypes-
|
|
1
|
+
const require_shapeTypes = require("./shapeTypes-CxSqNvHA.cjs");
|
|
2
2
|
const require_errors = require("./errors-CXJtc4I7.cjs");
|
|
3
|
-
const require_topologyQueryFns = require("./topologyQueryFns-
|
|
4
|
-
const require_shapeFns = require("./shapeFns-
|
|
3
|
+
const require_topologyQueryFns = require("./topologyQueryFns-Dzxrwn-E.cjs");
|
|
4
|
+
const require_shapeFns = require("./shapeFns-D5WNrq3s.cjs");
|
|
5
5
|
//#region src/topology/meshCache.ts
|
|
6
6
|
/**
|
|
7
7
|
* Build a parameter key for the inner cache map (excludes shape identity).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Z as getKernel, gt as qualityDeflection } from "./shapeTypes-
|
|
1
|
+
import { Z as getKernel, gt as qualityDeflection } from "./shapeTypes-CyTY0prh.js";
|
|
2
2
|
import { A as ok, b as err, r as ioError } from "./errors-DNWJsfVU.js";
|
|
3
|
-
import { d as getSolids, n as getBounds } from "./topologyQueryFns-
|
|
4
|
-
import { O as getFaceOrigins } from "./shapeFns-
|
|
3
|
+
import { d as getSolids, n as getBounds } from "./topologyQueryFns-BomrmBie.js";
|
|
4
|
+
import { O as getFaceOrigins } from "./shapeFns-DZ6poxP7.js";
|
|
5
5
|
//#region src/topology/meshCache.ts
|
|
6
6
|
/**
|
|
7
7
|
* Build a parameter key for the inner cache map (excludes shape identity).
|
|
@@ -1842,13 +1842,90 @@ function deriveCylinder(k, face) {
|
|
|
1842
1842
|
isDirect: (shapeOrientation(k, face) === "reversed" ? -1 : 1) * dotV(n1, subV(p1, origin)) > 0
|
|
1843
1843
|
};
|
|
1844
1844
|
}
|
|
1845
|
-
/**
|
|
1845
|
+
/** Circumcenter of three points (the center of the unique circle through them). */
|
|
1846
|
+
function circumcenter(a, p, q) {
|
|
1847
|
+
const ab = subV(p, a);
|
|
1848
|
+
const ac = subV(q, a);
|
|
1849
|
+
const m = crossV(ab, ac);
|
|
1850
|
+
const mSq = dotV(m, m);
|
|
1851
|
+
if (mSq < 1e-18) return null;
|
|
1852
|
+
const abSq = dotV(ab, ab);
|
|
1853
|
+
const acSq = dotV(ac, ac);
|
|
1854
|
+
const dxm = crossV([
|
|
1855
|
+
abSq * ac[0] - acSq * ab[0],
|
|
1856
|
+
abSq * ac[1] - acSq * ab[1],
|
|
1857
|
+
abSq * ac[2] - acSq * ab[2]
|
|
1858
|
+
], m);
|
|
1859
|
+
const inv = 1 / (2 * mSq);
|
|
1860
|
+
return [
|
|
1861
|
+
a[0] + dxm[0] * inv,
|
|
1862
|
+
a[1] + dxm[1] * inv,
|
|
1863
|
+
a[2] + dxm[2] * inv
|
|
1864
|
+
];
|
|
1865
|
+
}
|
|
1866
|
+
/** Center of the iso-v circle at height v (three u-samples → circumcenter). */
|
|
1867
|
+
function isoCircleCenter(k, face, uMin, uMax, v) {
|
|
1868
|
+
return circumcenter(pointOnSurface(k, face, uMin + .1 * (uMax - uMin), v), pointOnSurface(k, face, uMin + .45 * (uMax - uMin), v), pointOnSurface(k, face, uMin + .8 * (uMax - uMin), v));
|
|
1869
|
+
}
|
|
1870
|
+
/**
|
|
1871
|
+
* Axis of a surface of revolution (cone, torus, general revolution) by sampling.
|
|
1872
|
+
* occt-wasm exposes no analytic accessor for these. Their U parameter is the
|
|
1873
|
+
* angle of revolution, so the iso-v curve at a fixed v is a circle centered on
|
|
1874
|
+
* the axis; two such centers at different heights span the axis.
|
|
1875
|
+
*
|
|
1876
|
+
* Samples three v-levels and uses the farthest-apart pair of centers. Two levels
|
|
1877
|
+
* suffice for a cone or general revolution (v is monotonic along the axis), but
|
|
1878
|
+
* a torus parameterizes v as the tube angle: on a v-symmetric partial torus (a
|
|
1879
|
+
* half-torus, v in [0, pi]) two symmetric samples land at equal heights and
|
|
1880
|
+
* their centers coincide. A third level breaks that symmetry. Avoids the v
|
|
1881
|
+
* extremes so a cone apex (a degenerate zero-radius circle) is not sampled.
|
|
1882
|
+
*/
|
|
1883
|
+
function deriveAxisBySampling(k, face) {
|
|
1884
|
+
const b = uvBounds(k, face);
|
|
1885
|
+
const centers = [
|
|
1886
|
+
.2,
|
|
1887
|
+
.5,
|
|
1888
|
+
.8
|
|
1889
|
+
].map((f) => isoCircleCenter(k, face, b.uMin, b.uMax, b.vMin + f * (b.vMax - b.vMin))).filter((c) => c !== null);
|
|
1890
|
+
if (centers.length < 2) return null;
|
|
1891
|
+
let best = null;
|
|
1892
|
+
let bestLen = 1e-9;
|
|
1893
|
+
for (let i = 0; i < centers.length; i++) for (let j = i + 1; j < centers.length; j++) {
|
|
1894
|
+
const ci = centers[i];
|
|
1895
|
+
const cj = centers[j];
|
|
1896
|
+
if (!ci || !cj) continue;
|
|
1897
|
+
const d = subV(cj, ci);
|
|
1898
|
+
const len = lenV(d);
|
|
1899
|
+
if (len > bestLen) {
|
|
1900
|
+
bestLen = len;
|
|
1901
|
+
best = {
|
|
1902
|
+
origin: ci,
|
|
1903
|
+
direction: [
|
|
1904
|
+
d[0] / len,
|
|
1905
|
+
d[1] / len,
|
|
1906
|
+
d[2] / len
|
|
1907
|
+
]
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
return best;
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Axis of symmetry (point on axis + unit direction) for an analytic face that
|
|
1915
|
+
* has one. Cylinders use the exact normal-cross derivation; cones, tori, and
|
|
1916
|
+
* surfaces of revolution fall back to circle-center sampling. Null otherwise.
|
|
1917
|
+
*/
|
|
1846
1918
|
function getSurfaceAxis(k, face) {
|
|
1847
|
-
const
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1919
|
+
const type = surfaceType(k, face);
|
|
1920
|
+
if (type === "cylinder") {
|
|
1921
|
+
const cyl = deriveCylinder(k, face);
|
|
1922
|
+
return cyl ? {
|
|
1923
|
+
origin: cyl.origin,
|
|
1924
|
+
direction: cyl.direction
|
|
1925
|
+
} : null;
|
|
1926
|
+
}
|
|
1927
|
+
if (type === "cone" || type === "torus" || type === "revolution") return deriveAxisBySampling(k, face);
|
|
1928
|
+
return null;
|
|
1852
1929
|
}
|
|
1853
1930
|
/** Cylinder radius + handedness for a cylindrical surface. Null for non-cylinders. */
|
|
1854
1931
|
function getSurfaceCylinderData(k, surface) {
|
|
@@ -1842,13 +1842,90 @@ function deriveCylinder(k, face) {
|
|
|
1842
1842
|
isDirect: (shapeOrientation(k, face) === "reversed" ? -1 : 1) * dotV(n1, subV(p1, origin)) > 0
|
|
1843
1843
|
};
|
|
1844
1844
|
}
|
|
1845
|
-
/**
|
|
1845
|
+
/** Circumcenter of three points (the center of the unique circle through them). */
|
|
1846
|
+
function circumcenter(a, p, q) {
|
|
1847
|
+
const ab = subV(p, a);
|
|
1848
|
+
const ac = subV(q, a);
|
|
1849
|
+
const m = crossV(ab, ac);
|
|
1850
|
+
const mSq = dotV(m, m);
|
|
1851
|
+
if (mSq < 1e-18) return null;
|
|
1852
|
+
const abSq = dotV(ab, ab);
|
|
1853
|
+
const acSq = dotV(ac, ac);
|
|
1854
|
+
const dxm = crossV([
|
|
1855
|
+
abSq * ac[0] - acSq * ab[0],
|
|
1856
|
+
abSq * ac[1] - acSq * ab[1],
|
|
1857
|
+
abSq * ac[2] - acSq * ab[2]
|
|
1858
|
+
], m);
|
|
1859
|
+
const inv = 1 / (2 * mSq);
|
|
1860
|
+
return [
|
|
1861
|
+
a[0] + dxm[0] * inv,
|
|
1862
|
+
a[1] + dxm[1] * inv,
|
|
1863
|
+
a[2] + dxm[2] * inv
|
|
1864
|
+
];
|
|
1865
|
+
}
|
|
1866
|
+
/** Center of the iso-v circle at height v (three u-samples → circumcenter). */
|
|
1867
|
+
function isoCircleCenter(k, face, uMin, uMax, v) {
|
|
1868
|
+
return circumcenter(pointOnSurface(k, face, uMin + .1 * (uMax - uMin), v), pointOnSurface(k, face, uMin + .45 * (uMax - uMin), v), pointOnSurface(k, face, uMin + .8 * (uMax - uMin), v));
|
|
1869
|
+
}
|
|
1870
|
+
/**
|
|
1871
|
+
* Axis of a surface of revolution (cone, torus, general revolution) by sampling.
|
|
1872
|
+
* occt-wasm exposes no analytic accessor for these. Their U parameter is the
|
|
1873
|
+
* angle of revolution, so the iso-v curve at a fixed v is a circle centered on
|
|
1874
|
+
* the axis; two such centers at different heights span the axis.
|
|
1875
|
+
*
|
|
1876
|
+
* Samples three v-levels and uses the farthest-apart pair of centers. Two levels
|
|
1877
|
+
* suffice for a cone or general revolution (v is monotonic along the axis), but
|
|
1878
|
+
* a torus parameterizes v as the tube angle: on a v-symmetric partial torus (a
|
|
1879
|
+
* half-torus, v in [0, pi]) two symmetric samples land at equal heights and
|
|
1880
|
+
* their centers coincide. A third level breaks that symmetry. Avoids the v
|
|
1881
|
+
* extremes so a cone apex (a degenerate zero-radius circle) is not sampled.
|
|
1882
|
+
*/
|
|
1883
|
+
function deriveAxisBySampling(k, face) {
|
|
1884
|
+
const b = uvBounds(k, face);
|
|
1885
|
+
const centers = [
|
|
1886
|
+
.2,
|
|
1887
|
+
.5,
|
|
1888
|
+
.8
|
|
1889
|
+
].map((f) => isoCircleCenter(k, face, b.uMin, b.uMax, b.vMin + f * (b.vMax - b.vMin))).filter((c) => c !== null);
|
|
1890
|
+
if (centers.length < 2) return null;
|
|
1891
|
+
let best = null;
|
|
1892
|
+
let bestLen = 1e-9;
|
|
1893
|
+
for (let i = 0; i < centers.length; i++) for (let j = i + 1; j < centers.length; j++) {
|
|
1894
|
+
const ci = centers[i];
|
|
1895
|
+
const cj = centers[j];
|
|
1896
|
+
if (!ci || !cj) continue;
|
|
1897
|
+
const d = subV(cj, ci);
|
|
1898
|
+
const len = lenV(d);
|
|
1899
|
+
if (len > bestLen) {
|
|
1900
|
+
bestLen = len;
|
|
1901
|
+
best = {
|
|
1902
|
+
origin: ci,
|
|
1903
|
+
direction: [
|
|
1904
|
+
d[0] / len,
|
|
1905
|
+
d[1] / len,
|
|
1906
|
+
d[2] / len
|
|
1907
|
+
]
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
return best;
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Axis of symmetry (point on axis + unit direction) for an analytic face that
|
|
1915
|
+
* has one. Cylinders use the exact normal-cross derivation; cones, tori, and
|
|
1916
|
+
* surfaces of revolution fall back to circle-center sampling. Null otherwise.
|
|
1917
|
+
*/
|
|
1846
1918
|
function getSurfaceAxis(k, face) {
|
|
1847
|
-
const
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1919
|
+
const type = surfaceType(k, face);
|
|
1920
|
+
if (type === "cylinder") {
|
|
1921
|
+
const cyl = deriveCylinder(k, face);
|
|
1922
|
+
return cyl ? {
|
|
1923
|
+
origin: cyl.origin,
|
|
1924
|
+
direction: cyl.direction
|
|
1925
|
+
} : null;
|
|
1926
|
+
}
|
|
1927
|
+
if (type === "cone" || type === "torus" || type === "revolution") return deriveAxisBySampling(k, face);
|
|
1928
|
+
return null;
|
|
1852
1929
|
}
|
|
1853
1930
|
/** Cylinder radius + handedness for a cylindrical surface. Null for non-cylinders. */
|
|
1854
1931
|
function getSurfaceCylinderData(k, surface) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Shape3D } from '../core/shapeTypes.js';
|
|
2
|
+
import { Result } from '../core/result.js';
|
|
3
|
+
/** Configuration for {@link thread}. Units are mm; angles derive from pitch. */
|
|
4
|
+
export interface ThreadOptions {
|
|
5
|
+
/** Core radius (external) or nominal hole radius (internal), at the thread root. */
|
|
6
|
+
radius: number;
|
|
7
|
+
/** Axial distance per full turn. */
|
|
8
|
+
pitch: number;
|
|
9
|
+
/** Total thread length along the axis. Turn count = `height / pitch`. */
|
|
10
|
+
height: number;
|
|
11
|
+
/** Radial thread height (crest minus root). Defaults to `0.6 * pitch` (≈ISO 60° V). */
|
|
12
|
+
depth?: number;
|
|
13
|
+
/** Axial half-width of the V tooth. Defaults to `0.42 * pitch`. */
|
|
14
|
+
toothHalfWidth?: number;
|
|
15
|
+
/** Loft sections per turn — higher is smoother but slower. Defaults to `20`. */
|
|
16
|
+
sectionsPerTurn?: number;
|
|
17
|
+
/** Left-handed thread. Defaults to `false` (right-handed). */
|
|
18
|
+
lefthand?: boolean;
|
|
19
|
+
/** Point the tooth toward the axis (for an internal thread to `cut` from a bore). */
|
|
20
|
+
inward?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build a helical screw-thread ridge by lofting rotated tooth sections.
|
|
24
|
+
*
|
|
25
|
+
* @param options - {@link ThreadOptions}.
|
|
26
|
+
* @returns `Result` with the thread-ridge solid, or an error.
|
|
27
|
+
*
|
|
28
|
+
* @example External thread (Ø12 rod, 2.5 mm pitch):
|
|
29
|
+
* ```ts
|
|
30
|
+
* const ridge = thread({ radius: 6, pitch: 2.5, height: 7.5 });
|
|
31
|
+
* const rod = fuse(cylinder(6.15, 7.5), unwrap(ridge));
|
|
32
|
+
* ```
|
|
33
|
+
* @example Internal thread (tapped Ø6 hole):
|
|
34
|
+
* ```ts
|
|
35
|
+
* const ridge = thread({ radius: 3, pitch: 1, height: 6, inward: true });
|
|
36
|
+
* const nut = cut(boredBlock, unwrap(ridge));
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function thread(options: ThreadOptions): Result<Shape3D>;
|
package/dist/operations.cjs
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
exports.addChild =
|
|
5
|
-
exports.addStep =
|
|
6
|
-
exports.circularPattern =
|
|
7
|
-
exports.collectShapes =
|
|
8
|
-
exports.complexExtrude =
|
|
9
|
-
exports.countNodes =
|
|
10
|
-
exports.createAssembly =
|
|
11
|
-
exports.createAssemblyNode =
|
|
12
|
-
exports.createHistory =
|
|
13
|
-
exports.createRegistry =
|
|
14
|
-
exports.exportAssemblySTEP =
|
|
15
|
-
exports.findNode =
|
|
16
|
-
exports.findStep =
|
|
17
|
-
exports.getHistoryShape =
|
|
18
|
-
exports.gridPattern =
|
|
19
|
-
exports.linearPattern =
|
|
20
|
-
exports.modifyStep =
|
|
21
|
-
exports.registerOperation =
|
|
22
|
-
exports.registerShape =
|
|
23
|
-
exports.removeChild =
|
|
24
|
-
exports.replayFrom =
|
|
25
|
-
exports.replayHistory =
|
|
26
|
-
exports.stepCount =
|
|
27
|
-
exports.stepsFrom =
|
|
28
|
-
exports.supportExtrude =
|
|
29
|
-
exports.sweep =
|
|
30
|
-
exports.
|
|
31
|
-
exports.
|
|
32
|
-
exports.
|
|
33
|
-
exports.
|
|
2
|
+
const require_threadFns = require("./threadFns-aWgxzqmT.cjs");
|
|
3
|
+
const require_loftFns = require("./loftFns-DycLH1Pq.cjs");
|
|
4
|
+
exports.addChild = require_threadFns.addChild;
|
|
5
|
+
exports.addStep = require_threadFns.addStep;
|
|
6
|
+
exports.circularPattern = require_threadFns.circularPattern;
|
|
7
|
+
exports.collectShapes = require_threadFns.collectShapes;
|
|
8
|
+
exports.complexExtrude = require_loftFns.complexExtrude;
|
|
9
|
+
exports.countNodes = require_threadFns.countNodes;
|
|
10
|
+
exports.createAssembly = require_threadFns.createAssembly;
|
|
11
|
+
exports.createAssemblyNode = require_threadFns.createAssemblyNode;
|
|
12
|
+
exports.createHistory = require_threadFns.createHistory;
|
|
13
|
+
exports.createRegistry = require_threadFns.createRegistry;
|
|
14
|
+
exports.exportAssemblySTEP = require_threadFns.exportAssemblySTEP;
|
|
15
|
+
exports.findNode = require_threadFns.findNode;
|
|
16
|
+
exports.findStep = require_threadFns.findStep;
|
|
17
|
+
exports.getHistoryShape = require_threadFns.getShape;
|
|
18
|
+
exports.gridPattern = require_threadFns.gridPattern;
|
|
19
|
+
exports.linearPattern = require_threadFns.linearPattern;
|
|
20
|
+
exports.modifyStep = require_threadFns.modifyStep;
|
|
21
|
+
exports.registerOperation = require_threadFns.registerOperation;
|
|
22
|
+
exports.registerShape = require_threadFns.registerShape;
|
|
23
|
+
exports.removeChild = require_threadFns.removeChild;
|
|
24
|
+
exports.replayFrom = require_threadFns.replayFrom;
|
|
25
|
+
exports.replayHistory = require_threadFns.replayHistory;
|
|
26
|
+
exports.stepCount = require_threadFns.stepCount;
|
|
27
|
+
exports.stepsFrom = require_threadFns.stepsFrom;
|
|
28
|
+
exports.supportExtrude = require_loftFns.supportExtrude;
|
|
29
|
+
exports.sweep = require_loftFns.sweep;
|
|
30
|
+
exports.thread = require_threadFns.thread;
|
|
31
|
+
exports.twistExtrude = require_loftFns.twistExtrude;
|
|
32
|
+
exports.undoLast = require_threadFns.undoLast;
|
|
33
|
+
exports.updateNode = require_threadFns.updateNode;
|
|
34
|
+
exports.walkAssembly = require_threadFns.walkAssembly;
|
package/dist/operations.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* ```
|
|
8
8
|
*/
|
|
9
9
|
export { sweep, supportExtrude, complexExtrude, twistExtrude, type SweepOptions, type ExtrusionProfile, } from './operations/extrudeFns.js';
|
|
10
|
+
export { thread, type ThreadOptions } from './operations/threadFns.js';
|
|
10
11
|
export { linearPattern, circularPattern, gridPattern } from './operations/patternFns.js';
|
|
11
12
|
export { createAssemblyNode, addChild, removeChild, updateNode, findNode, walkAssembly, countNodes, collectShapes, type AssemblyNode, type AssemblyNodeOptions, } from './operations/assemblyFns.js';
|
|
12
13
|
export { exportAssemblySTEP, type ShapeOptions, type SupportedUnit, } from './operations/exporterFns.js';
|
package/dist/operations.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
import {
|
|
3
|
-
export { addChild, addStep, circularPattern, collectShapes, complexExtrude, countNodes, createAssembly, createAssemblyNode, createHistory, createRegistry, exportAssemblySTEP, findNode, findStep, getShape as getHistoryShape, gridPattern, linearPattern, modifyStep, registerOperation, registerShape, removeChild, replayFrom, replayHistory, stepCount, stepsFrom, supportExtrude, sweep, twistExtrude, undoLast, updateNode, walkAssembly };
|
|
1
|
+
import { C as updateNode, D as linearPattern, E as gridPattern, O as exportAssemblySTEP, S as removeChild, T as circularPattern, _ as addChild, b as createAssemblyNode, c as modifyStep, d as replayFrom, f as replayHistory, g as undoLast, h as stepsFrom, i as createRegistry, k as createAssembly, l as registerOperation, m as stepCount, n as addStep, o as findStep, r as createHistory, s as getShape, t as thread, u as registerShape, v as collectShapes, w as walkAssembly, x as findNode, y as countNodes } from "./threadFns-D8-zfJ0b.js";
|
|
2
|
+
import { d as twistExtrude, l as supportExtrude, o as complexExtrude, u as sweep } from "./loftFns-DuxEscJB.js";
|
|
3
|
+
export { addChild, addStep, circularPattern, collectShapes, complexExtrude, countNodes, createAssembly, createAssemblyNode, createHistory, createRegistry, exportAssemblySTEP, findNode, findStep, getShape as getHistoryShape, gridPattern, linearPattern, modifyStep, registerOperation, registerShape, removeChild, replayFrom, replayHistory, stepCount, stepsFrom, supportExtrude, sweep, thread, twistExtrude, undoLast, updateNode, walkAssembly };
|