brepjs 8.2.0 → 8.4.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.
Files changed (85) hide show
  1. package/dist/2d/lib/Curve2D.d.ts.map +1 -1
  2. package/dist/2d.cjs +2 -2
  3. package/dist/2d.js +3 -3
  4. package/dist/{Blueprint-D_luVeES.js → Blueprint-Bp45tnh0.js} +16 -12
  5. package/dist/{Blueprint-CTAwjJMN.cjs → Blueprint-zgFe_5Qj.cjs} +17 -13
  6. package/dist/{boolean2D-B5axNhjN.cjs → boolean2D-CfEbRMPF.cjs} +11 -11
  7. package/dist/{boolean2D-vw76Gayn.js → boolean2D-DN6ETTCq.js} +11 -11
  8. package/dist/{booleanFns-Yc3EBxdm.cjs → booleanFns-5dDG0jpA.cjs} +46 -9
  9. package/dist/{booleanFns-BhqXpQoZ.js → booleanFns-C-M6qqvB.js} +46 -9
  10. package/dist/brepjs.cjs +364 -109
  11. package/dist/brepjs.js +433 -177
  12. package/dist/{cast-C107o5ow.cjs → cast-CPNOTNFm.cjs} +3 -3
  13. package/dist/{cast-D0OhP1nV.js → cast-Cerqtxtb.js} +3 -3
  14. package/dist/core/errors.d.ts +7 -0
  15. package/dist/core/errors.d.ts.map +1 -1
  16. package/dist/core.cjs +4 -4
  17. package/dist/core.js +4 -4
  18. package/dist/{cornerFinder-DuStF5jK.cjs → cornerFinder-BQ-_VJx0.cjs} +1 -1
  19. package/dist/{cornerFinder-CPm2baSJ.js → cornerFinder-CC_MunIh.js} +1 -1
  20. package/dist/{curveBuilders-CN72XaIQ.js → curveBuilders-BREwqvuc.js} +3 -3
  21. package/dist/{curveBuilders-Du03_Yyf.cjs → curveBuilders-BkEJ-RVn.cjs} +3 -3
  22. package/dist/curveFns-VMxgfkqw.cjs +177 -0
  23. package/dist/curveFns-ZuQUBZvd.js +178 -0
  24. package/dist/{drawFns-CzBbcoXA.js → drawFns-BbhX1IUq.js} +19 -15
  25. package/dist/{drawFns-CiNxPu6J.cjs → drawFns-CKaHgGSK.cjs} +22 -18
  26. package/dist/{errors-wGhcJMpB.js → errors-CSYOlCCR.js} +10 -1
  27. package/dist/{errors-DK1VAdP4.cjs → errors-D13q2HCk.cjs} +10 -1
  28. package/dist/{faceFns-ub3CugDN.js → faceFns-CfJIbHY3.js} +4 -4
  29. package/dist/{faceFns-D1Sqnlu6.cjs → faceFns-es3GENII.cjs} +4 -4
  30. package/dist/{helpers-Dje6wrKi.cjs → helpers-C0q_FVxq.cjs} +10 -10
  31. package/dist/{helpers-BSQfs538.js → helpers-CmVkMubc.js} +7 -7
  32. package/dist/index.d.ts +3 -1
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/io.cjs +5 -5
  35. package/dist/io.js +5 -5
  36. package/dist/kernel/hullOps.d.ts +22 -0
  37. package/dist/kernel/hullOps.d.ts.map +1 -0
  38. package/dist/kernel/occtAdapter.d.ts +6 -0
  39. package/dist/kernel/occtAdapter.d.ts.map +1 -1
  40. package/dist/kernel/types.d.ts +6 -0
  41. package/dist/kernel/types.d.ts.map +1 -1
  42. package/dist/{loft-PMRx9iMG.cjs → loft-B-UCPW9P.cjs} +5 -5
  43. package/dist/{loft-BHn7GKm8.js → loft-oJq2OD3A.js} +5 -5
  44. package/dist/{measurement-B06hNs89.cjs → measurement-CYmT-C77.cjs} +3 -3
  45. package/dist/{measurement-BfhEneUl.js → measurement-Cf_SoIiR.js} +3 -3
  46. package/dist/measurement.cjs +1 -1
  47. package/dist/measurement.js +1 -1
  48. package/dist/{meshFns-BKSPaPXS.js → meshFns-CqNwW0PO.js} +6 -3
  49. package/dist/{meshFns-CFVxKBlE.cjs → meshFns-DDC_2U81.cjs} +6 -3
  50. package/dist/{occtBoundary-BFAaUtA7.cjs → occtBoundary-CocN2VKx.cjs} +419 -2
  51. package/dist/{occtBoundary-CoXB2xvx.js → occtBoundary-D_gjqgzo.js} +419 -2
  52. package/dist/{operations-CjQHEu1h.js → operations-6hdpuYmY.js} +6 -6
  53. package/dist/{operations-CdGb6IBU.cjs → operations-BQeW_DSM.cjs} +6 -6
  54. package/dist/operations.cjs +2 -2
  55. package/dist/operations.js +2 -2
  56. package/dist/query.cjs +5 -5
  57. package/dist/query.js +6 -6
  58. package/dist/result.cjs +1 -1
  59. package/dist/result.js +1 -1
  60. package/dist/{curveFns-ByeCqutv.cjs → shapeFns-B0zSdO9c.cjs} +98 -177
  61. package/dist/{curveFns-C5gSZ5EY.js → shapeFns-k1YHFwmB.js} +117 -196
  62. package/dist/{shapeTypes-UqVCIO_T.cjs → shapeTypes-BxVxLdiD.cjs} +1 -1
  63. package/dist/{shapeTypes-BU2LKv2S.js → shapeTypes-c-_pgYCx.js} +1 -1
  64. package/dist/sketching.cjs +2 -2
  65. package/dist/sketching.js +2 -2
  66. package/dist/text/textBlueprints.d.ts.map +1 -1
  67. package/dist/topology/booleanFns.d.ts.map +1 -1
  68. package/dist/topology/hullFns.d.ts +16 -0
  69. package/dist/topology/hullFns.d.ts.map +1 -0
  70. package/dist/topology/meshFns.d.ts +1 -0
  71. package/dist/topology/meshFns.d.ts.map +1 -1
  72. package/dist/topology/minkowskiFns.d.ts +20 -0
  73. package/dist/topology/minkowskiFns.d.ts.map +1 -0
  74. package/dist/topology/modifierFns.d.ts.map +1 -1
  75. package/dist/topology/shapeFns.d.ts +30 -0
  76. package/dist/topology/shapeFns.d.ts.map +1 -1
  77. package/dist/{topology-D8Au8q4i.cjs → topology-CycEc6Oe.cjs} +14 -13
  78. package/dist/{topology-BFB3LI_y.js → topology-tMKHJgw2.js} +9 -8
  79. package/dist/topology.cjs +34 -33
  80. package/dist/topology.js +59 -58
  81. package/dist/{vectors-BhfKwL9J.js → vectors-DE0XriuQ.js} +2 -2
  82. package/dist/{vectors-t1XG4LpL.cjs → vectors-DVmHF4zt.cjs} +2 -2
  83. package/dist/vectors.cjs +2 -2
  84. package/dist/vectors.js +2 -2
  85. package/package.json +5 -5
@@ -1041,7 +1041,7 @@ function makeWire(oc, edges) {
1041
1041
  progress.delete();
1042
1042
  return wire;
1043
1043
  }
1044
- function makeFace(oc, wire, planar = true) {
1044
+ function makeFace$1(oc, wire, planar = true) {
1045
1045
  if (planar) {
1046
1046
  const builder2 = new oc.BRepBuilderAPI_MakeFace_15(wire, false);
1047
1047
  const face = builder2.Face();
@@ -1440,6 +1440,412 @@ function approximatePoints(oc, points, options = {}) {
1440
1440
  splineBuilder.delete();
1441
1441
  return edge;
1442
1442
  }
1443
+ function sub(a, b) {
1444
+ return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
1445
+ }
1446
+ function cross(a, b) {
1447
+ return {
1448
+ x: a.y * b.z - a.z * b.y,
1449
+ y: a.z * b.x - a.x * b.z,
1450
+ z: a.x * b.y - a.y * b.x
1451
+ };
1452
+ }
1453
+ function dot(a, b) {
1454
+ return a.x * b.x + a.y * b.y + a.z * b.z;
1455
+ }
1456
+ function lengthVec(v) {
1457
+ return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
1458
+ }
1459
+ function distSq(a, b) {
1460
+ const dx = a.x - b.x;
1461
+ const dy = a.y - b.y;
1462
+ const dz = a.z - b.z;
1463
+ return dx * dx + dy * dy + dz * dz;
1464
+ }
1465
+ function at(arr, i) {
1466
+ const v = arr[i];
1467
+ if (v === void 0) throw new Error(`Index ${i} out of bounds`);
1468
+ return v;
1469
+ }
1470
+ function atN(arr, i) {
1471
+ const v = arr[i];
1472
+ if (v === void 0) throw new Error(`Index ${i} out of bounds`);
1473
+ return v;
1474
+ }
1475
+ function makeFace(points, a, b, c) {
1476
+ const normal = cross(sub(at(points, b), at(points, a)), sub(at(points, c), at(points, a)));
1477
+ const len = lengthVec(normal);
1478
+ const n = len > 1e-14 ? { x: normal.x / len, y: normal.y / len, z: normal.z / len } : normal;
1479
+ return {
1480
+ a,
1481
+ b,
1482
+ c,
1483
+ normal: n,
1484
+ offset: dot(n, at(points, a)),
1485
+ alive: true,
1486
+ outsidePoints: []
1487
+ };
1488
+ }
1489
+ function signedDist(face, point) {
1490
+ return dot(face.normal, point) - face.offset;
1491
+ }
1492
+ function deduplicatePoints(points, tolerance) {
1493
+ const tolSq = tolerance * tolerance;
1494
+ const result = [];
1495
+ for (const p of points) {
1496
+ let isDuplicate = false;
1497
+ for (const q of result) {
1498
+ if (distSq(p, q) < tolSq) {
1499
+ isDuplicate = true;
1500
+ break;
1501
+ }
1502
+ }
1503
+ if (!isDuplicate) result.push(p);
1504
+ }
1505
+ return result;
1506
+ }
1507
+ function findInitialTetrahedron(points) {
1508
+ const n = points.length;
1509
+ if (n < 4) return null;
1510
+ let i0 = 0;
1511
+ let i1 = 1;
1512
+ let maxDist = distSq(at(points, 0), at(points, 1));
1513
+ for (let i = 0; i < n; i++) {
1514
+ for (let j = i + 1; j < n; j++) {
1515
+ const d = distSq(at(points, i), at(points, j));
1516
+ if (d > maxDist) {
1517
+ maxDist = d;
1518
+ i0 = i;
1519
+ i1 = j;
1520
+ }
1521
+ }
1522
+ }
1523
+ if (maxDist < 1e-20) return null;
1524
+ const lineDir = sub(at(points, i1), at(points, i0));
1525
+ let i2 = -1;
1526
+ let maxLineDist = -1;
1527
+ for (let i = 0; i < n; i++) {
1528
+ if (i === i0 || i === i1) continue;
1529
+ const v = sub(at(points, i), at(points, i0));
1530
+ const c = cross(lineDir, v);
1531
+ const d = dot(c, c);
1532
+ if (d > maxLineDist) {
1533
+ maxLineDist = d;
1534
+ i2 = i;
1535
+ }
1536
+ }
1537
+ if (i2 === -1 || maxLineDist < 1e-20) return null;
1538
+ const planeNormal = cross(
1539
+ sub(at(points, i1), at(points, i0)),
1540
+ sub(at(points, i2), at(points, i0))
1541
+ );
1542
+ const planeLen = lengthVec(planeNormal);
1543
+ if (planeLen < 1e-14) return null;
1544
+ const pn = {
1545
+ x: planeNormal.x / planeLen,
1546
+ y: planeNormal.y / planeLen,
1547
+ z: planeNormal.z / planeLen
1548
+ };
1549
+ const planeOffset = dot(pn, at(points, i0));
1550
+ let i3 = -1;
1551
+ let maxPlaneDist = -1;
1552
+ for (let i = 0; i < n; i++) {
1553
+ if (i === i0 || i === i1 || i === i2) continue;
1554
+ const d = Math.abs(dot(pn, at(points, i)) - planeOffset);
1555
+ if (d > maxPlaneDist) {
1556
+ maxPlaneDist = d;
1557
+ i3 = i;
1558
+ }
1559
+ }
1560
+ if (i3 === -1 || maxPlaneDist < 1e-14) return null;
1561
+ const sd = dot(pn, at(points, i3)) - planeOffset;
1562
+ if (sd > 0) {
1563
+ return [i0, i2, i1, i3];
1564
+ }
1565
+ return [i0, i1, i2, i3];
1566
+ }
1567
+ function quickHull(inputPoints, tolerance) {
1568
+ const points = deduplicatePoints(inputPoints, tolerance);
1569
+ if (points.length < 4) {
1570
+ throw new Error(
1571
+ points.length === 0 ? "No points provided for convex hull" : "Fewer than 4 non-coincident points; cannot form a 3D convex hull"
1572
+ );
1573
+ }
1574
+ const tet = findInitialTetrahedron(points);
1575
+ if (tet === null) {
1576
+ throw new Error("All points are coplanar; cannot form a 3D convex hull");
1577
+ }
1578
+ const [t0, t1, t2, t3] = tet;
1579
+ const centroid = {
1580
+ x: (at(points, t0).x + at(points, t1).x + at(points, t2).x + at(points, t3).x) / 4,
1581
+ y: (at(points, t0).y + at(points, t1).y + at(points, t2).y + at(points, t3).y) / 4,
1582
+ z: (at(points, t0).z + at(points, t1).z + at(points, t2).z + at(points, t3).z) / 4
1583
+ };
1584
+ function makeOutwardFace(a, b, c) {
1585
+ const face = makeFace(points, a, b, c);
1586
+ const faceCenter = {
1587
+ x: (at(points, a).x + at(points, b).x + at(points, c).x) / 3,
1588
+ y: (at(points, a).y + at(points, b).y + at(points, c).y) / 3,
1589
+ z: (at(points, a).z + at(points, b).z + at(points, c).z) / 3
1590
+ };
1591
+ const toCentroid = sub(centroid, faceCenter);
1592
+ if (dot(face.normal, toCentroid) > 0) {
1593
+ return makeFace(points, a, c, b);
1594
+ }
1595
+ return face;
1596
+ }
1597
+ const faces = [
1598
+ makeOutwardFace(t0, t1, t2),
1599
+ makeOutwardFace(t0, t2, t3),
1600
+ makeOutwardFace(t0, t3, t1),
1601
+ makeOutwardFace(t1, t3, t2)
1602
+ ];
1603
+ const tetSet = /* @__PURE__ */ new Set([t0, t1, t2, t3]);
1604
+ const epsilon = 1e-10;
1605
+ for (let i = 0; i < points.length; i++) {
1606
+ if (tetSet.has(i)) continue;
1607
+ for (const face of faces) {
1608
+ if (signedDist(face, at(points, i)) > epsilon) {
1609
+ face.outsidePoints.push(i);
1610
+ break;
1611
+ }
1612
+ }
1613
+ }
1614
+ for (let iteration = 0; iteration < points.length * 4; iteration++) {
1615
+ let currentFace = null;
1616
+ for (const face of faces) {
1617
+ if (face.alive && face.outsidePoints.length > 0) {
1618
+ currentFace = face;
1619
+ break;
1620
+ }
1621
+ }
1622
+ if (currentFace === null) break;
1623
+ let furthestIdx = atN(currentFace.outsidePoints, 0);
1624
+ let furthestDist = signedDist(currentFace, at(points, furthestIdx));
1625
+ for (let i = 1; i < currentFace.outsidePoints.length; i++) {
1626
+ const idx = atN(currentFace.outsidePoints, i);
1627
+ const d = signedDist(currentFace, at(points, idx));
1628
+ if (d > furthestDist) {
1629
+ furthestDist = d;
1630
+ furthestIdx = idx;
1631
+ }
1632
+ }
1633
+ const visibleFaces = [];
1634
+ for (const face of faces) {
1635
+ if (face.alive && signedDist(face, at(points, furthestIdx)) > epsilon) {
1636
+ visibleFaces.push(face);
1637
+ }
1638
+ }
1639
+ const edgeCount = /* @__PURE__ */ new Map();
1640
+ for (const face of visibleFaces) {
1641
+ const edges = [
1642
+ [face.a, face.b],
1643
+ [face.b, face.c],
1644
+ [face.c, face.a]
1645
+ ];
1646
+ for (const [ea, eb] of edges) {
1647
+ const key = ea < eb ? `${ea}-${eb}` : `${eb}-${ea}`;
1648
+ const entry = edgeCount.get(key);
1649
+ if (entry) {
1650
+ entry.count++;
1651
+ } else {
1652
+ edgeCount.set(key, { a: ea, b: eb, count: 1 });
1653
+ }
1654
+ }
1655
+ }
1656
+ const horizonEdges = [];
1657
+ for (const entry of edgeCount.values()) {
1658
+ if (entry.count === 1) {
1659
+ horizonEdges.push({ a: entry.a, b: entry.b });
1660
+ }
1661
+ }
1662
+ const orphanedPoints = [];
1663
+ for (const face of visibleFaces) {
1664
+ for (const idx of face.outsidePoints) {
1665
+ if (idx !== furthestIdx) {
1666
+ orphanedPoints.push(idx);
1667
+ }
1668
+ }
1669
+ face.alive = false;
1670
+ face.outsidePoints = [];
1671
+ }
1672
+ const newFaces = [];
1673
+ for (const edge of horizonEdges) {
1674
+ const newFaceObj = makeFace(points, edge.a, edge.b, furthestIdx);
1675
+ newFaces.push(newFaceObj);
1676
+ faces.push(newFaceObj);
1677
+ }
1678
+ for (const idx of orphanedPoints) {
1679
+ for (const face of newFaces) {
1680
+ if (signedDist(face, at(points, idx)) > epsilon) {
1681
+ face.outsidePoints.push(idx);
1682
+ break;
1683
+ }
1684
+ }
1685
+ }
1686
+ }
1687
+ const resultFaces = [];
1688
+ for (const face of faces) {
1689
+ if (face.alive) {
1690
+ resultFaces.push([face.a, face.b, face.c]);
1691
+ }
1692
+ }
1693
+ return { faces: resultFaces, points };
1694
+ }
1695
+ function extractVertices(oc, shapes, tolerance) {
1696
+ const vertices = [];
1697
+ const meshDeflection = Math.max(tolerance, 1);
1698
+ for (const shape of shapes) {
1699
+ const mesh2 = new oc.BRepMesh_IncrementalMesh_2(
1700
+ shape,
1701
+ meshDeflection,
1702
+ false,
1703
+ meshDeflection * 0.5,
1704
+ false
1705
+ );
1706
+ const progress = new oc.Message_ProgressRange_1();
1707
+ mesh2.Perform(progress);
1708
+ progress.delete();
1709
+ mesh2.delete();
1710
+ const explorer = new oc.TopExp_Explorer_2(
1711
+ shape,
1712
+ oc.TopAbs_ShapeEnum.TopAbs_FACE,
1713
+ oc.TopAbs_ShapeEnum.TopAbs_SHAPE
1714
+ );
1715
+ while (explorer.More()) {
1716
+ const face = oc.TopoDS.Face_1(explorer.Current());
1717
+ const location = new oc.TopLoc_Location_1();
1718
+ const tri = oc.BRep_Tool.Triangulation(face, location, 0);
1719
+ if (!tri.IsNull()) {
1720
+ const trsf = location.Transformation();
1721
+ const nbNodes = tri.get().NbNodes();
1722
+ for (let i = 1; i <= nbNodes; i++) {
1723
+ const node = tri.get().Node(i);
1724
+ const transformed = node.Transformed(trsf);
1725
+ vertices.push({
1726
+ x: transformed.X(),
1727
+ y: transformed.Y(),
1728
+ z: transformed.Z()
1729
+ });
1730
+ transformed.delete();
1731
+ node.delete();
1732
+ }
1733
+ trsf.delete();
1734
+ }
1735
+ location.delete();
1736
+ explorer.Next();
1737
+ }
1738
+ explorer.delete();
1739
+ }
1740
+ return vertices;
1741
+ }
1742
+ function buildTriFace(oc, pa, pb, pc) {
1743
+ const gpA = new oc.gp_Pnt_3(pa.x, pa.y, pa.z);
1744
+ const gpB = new oc.gp_Pnt_3(pb.x, pb.y, pb.z);
1745
+ const gpC = new oc.gp_Pnt_3(pc.x, pc.y, pc.z);
1746
+ const e1 = new oc.BRepBuilderAPI_MakeEdge_3(gpA, gpB);
1747
+ const e2 = new oc.BRepBuilderAPI_MakeEdge_3(gpB, gpC);
1748
+ const e3 = new oc.BRepBuilderAPI_MakeEdge_3(gpC, gpA);
1749
+ const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
1750
+ wireBuilder.Add_1(e1.Edge());
1751
+ wireBuilder.Add_1(e2.Edge());
1752
+ wireBuilder.Add_1(e3.Edge());
1753
+ let face = null;
1754
+ if (wireBuilder.IsDone()) {
1755
+ const makeFaceBuilder = new oc.BRepBuilderAPI_MakeFace_15(wireBuilder.Wire(), false);
1756
+ if (makeFaceBuilder.IsDone()) {
1757
+ face = makeFaceBuilder.Face();
1758
+ }
1759
+ makeFaceBuilder.delete();
1760
+ }
1761
+ wireBuilder.delete();
1762
+ e1.delete();
1763
+ e2.delete();
1764
+ e3.delete();
1765
+ gpA.delete();
1766
+ gpB.delete();
1767
+ gpC.delete();
1768
+ return face;
1769
+ }
1770
+ function reconstructBrep(oc, hullResult, tolerance) {
1771
+ const { faces: hullFaces, points } = hullResult;
1772
+ const ocFaces = [];
1773
+ for (const [ia, ib, ic] of hullFaces) {
1774
+ const face = buildTriFace(oc, at(points, ia), at(points, ib), at(points, ic));
1775
+ if (face !== null) {
1776
+ ocFaces.push(face);
1777
+ }
1778
+ }
1779
+ if (ocFaces.length < 4) {
1780
+ throw new Error(`hull: only ${ocFaces.length} faces built, need at least 4 for a solid`);
1781
+ }
1782
+ const sewTolerance = Math.max(tolerance, 1e-4);
1783
+ const sewing = new oc.BRepBuilderAPI_Sewing(sewTolerance, true, true, true, false);
1784
+ for (const face of ocFaces) {
1785
+ sewing.Add(face);
1786
+ }
1787
+ const sewProgress = new oc.Message_ProgressRange_1();
1788
+ sewing.Perform(sewProgress);
1789
+ sewProgress.delete();
1790
+ const sewn = sewing.SewedShape();
1791
+ sewing.delete();
1792
+ const shellExplorer = new oc.TopExp_Explorer_2(
1793
+ sewn,
1794
+ oc.TopAbs_ShapeEnum.TopAbs_SHELL,
1795
+ oc.TopAbs_ShapeEnum.TopAbs_SHAPE
1796
+ );
1797
+ if (shellExplorer.More()) {
1798
+ const shell2 = oc.TopoDS.Shell_1(shellExplorer.Current());
1799
+ shellExplorer.delete();
1800
+ const solidMaker = new oc.BRepBuilderAPI_MakeSolid_1();
1801
+ solidMaker.Add(shell2);
1802
+ const solidProgress = new oc.Message_ProgressRange_1();
1803
+ solidMaker.Build(solidProgress);
1804
+ solidProgress.delete();
1805
+ if (solidMaker.IsDone()) {
1806
+ const solid = solidMaker.Solid();
1807
+ solidMaker.delete();
1808
+ shell2.delete();
1809
+ const props = new oc.GProp_GProps_1();
1810
+ oc.BRepGProp.VolumeProperties_1(solid, props, false, false, false);
1811
+ const vol = props.Mass();
1812
+ props.delete();
1813
+ if (vol < 0) {
1814
+ solid.Complement();
1815
+ }
1816
+ return solid;
1817
+ }
1818
+ shell2.delete();
1819
+ solidMaker.delete();
1820
+ return sewn;
1821
+ }
1822
+ shellExplorer.delete();
1823
+ return sewn;
1824
+ }
1825
+ function hull(oc, shapes, tolerance) {
1826
+ if (shapes.length === 0) {
1827
+ throw new Error("hull: no shapes provided");
1828
+ }
1829
+ const vertices = extractVertices(oc, shapes, tolerance);
1830
+ if (vertices.length < 4) {
1831
+ throw new Error("hull: fewer than 4 vertices extracted from input shapes");
1832
+ }
1833
+ const hullResult = quickHull(vertices, tolerance);
1834
+ if (hullResult.faces.length < 4) {
1835
+ throw new Error("hull: degenerate hull (fewer than 4 faces)");
1836
+ }
1837
+ return reconstructBrep(oc, hullResult, tolerance);
1838
+ }
1839
+ function hullFromPoints(oc, points, tolerance) {
1840
+ if (points.length < 4) {
1841
+ throw new Error("hullFromPoints: fewer than 4 points");
1842
+ }
1843
+ const hullResult = quickHull(points, tolerance);
1844
+ if (hullResult.faces.length < 4) {
1845
+ throw new Error("hullFromPoints: degenerate hull (fewer than 4 faces)");
1846
+ }
1847
+ return reconstructBrep(oc, hullResult, tolerance);
1848
+ }
1443
1849
  class OCCTAdapter {
1444
1850
  oc;
1445
1851
  constructor(oc) {
@@ -1464,6 +1870,17 @@ class OCCTAdapter {
1464
1870
  cutAll(shape, tools, options = {}) {
1465
1871
  return cutAll(this.oc, shape, tools, options);
1466
1872
  }
1873
+ // --- Convex hull ---
1874
+ hull(shapes, tolerance) {
1875
+ return hull(this.oc, shapes, tolerance);
1876
+ }
1877
+ hullFromPoints(points, tolerance) {
1878
+ return hullFromPoints(
1879
+ this.oc,
1880
+ points.map((p) => ({ x: p.x, y: p.y, z: p.z })),
1881
+ tolerance
1882
+ );
1883
+ }
1467
1884
  // --- Shape construction (delegates to constructorOps.ts) ---
1468
1885
  makeVertex(x, y, z) {
1469
1886
  return makeVertex(this.oc, x, y, z);
@@ -1475,7 +1892,7 @@ class OCCTAdapter {
1475
1892
  return makeWire(this.oc, edges);
1476
1893
  }
1477
1894
  makeFace(wire, planar = true) {
1478
- return makeFace(this.oc, wire, planar);
1895
+ return makeFace$1(this.oc, wire, planar);
1479
1896
  }
1480
1897
  makeBox(width, height, depth) {
1481
1898
  return makeBox(this.oc, width, height, depth);
@@ -1,10 +1,10 @@
1
- import { g as getKernel, c as toOcVec, b as toOcPnt, d as makeOcAx3, u as uniqueIOFilename } from "./occtBoundary-CoXB2xvx.js";
1
+ import { g as getKernel, c as toOcVec, b as toOcPnt, d as makeOcAx3, u as uniqueIOFilename } from "./occtBoundary-D_gjqgzo.js";
2
2
  import { g as vecLength, v as vecAdd, D as DEG2RAD, f as vecIsZero, j as vecNormalize, n as vecScale } from "./vecOps-ZDdZWbwT.js";
3
- import { b as createOcHandle, c as castShape, h as isShape3D, m as isWire, p as gcWithScope, s as createSolid } from "./shapeTypes-BU2LKv2S.js";
4
- import { d as downcast } from "./cast-D0OhP1nV.js";
5
- import { e as err, x as validationError, u as unwrap, p as typeCastError, l as ok, B as BrepErrorCode, d as isErr, o as occtError, i as ioError, b as computationError } from "./errors-wGhcJMpB.js";
6
- import { n as buildLawFromProfile } from "./loft-BHn7GKm8.js";
7
- import { d as fuseAll } from "./booleanFns-BhqXpQoZ.js";
3
+ import { b as createOcHandle, c as castShape, h as isShape3D, m as isWire, p as gcWithScope, s as createSolid } from "./shapeTypes-c-_pgYCx.js";
4
+ import { d as downcast } from "./cast-Cerqtxtb.js";
5
+ import { e as err, x as validationError, u as unwrap, p as typeCastError, l as ok, B as BrepErrorCode, d as isErr, o as occtError, i as ioError, b as computationError } from "./errors-CSYOlCCR.js";
6
+ import { n as buildLawFromProfile } from "./loft-oJq2OD3A.js";
7
+ import { d as fuseAll } from "./booleanFns-C-M6qqvB.js";
8
8
  function uuidv() {
9
9
  return (String([1e7]) + String(-1e3) + String(-4e3) + String(-8e3) + String(-1e11)).replace(
10
10
  /[018]/g,
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
- const occtBoundary = require("./occtBoundary-BFAaUtA7.cjs");
2
+ const occtBoundary = require("./occtBoundary-CocN2VKx.cjs");
3
3
  const vecOps = require("./vecOps-CjRL1jau.cjs");
4
- const shapeTypes = require("./shapeTypes-UqVCIO_T.cjs");
5
- const cast = require("./cast-C107o5ow.cjs");
6
- const errors = require("./errors-DK1VAdP4.cjs");
7
- const loft = require("./loft-PMRx9iMG.cjs");
8
- const booleanFns = require("./booleanFns-Yc3EBxdm.cjs");
4
+ const shapeTypes = require("./shapeTypes-BxVxLdiD.cjs");
5
+ const cast = require("./cast-CPNOTNFm.cjs");
6
+ const errors = require("./errors-D13q2HCk.cjs");
7
+ const loft = require("./loft-B-UCPW9P.cjs");
8
+ const booleanFns = require("./booleanFns-5dDG0jpA.cjs");
9
9
  function uuidv() {
10
10
  return (String([1e7]) + String(-1e3) + String(-4e3) + String(-8e3) + String(-1e11)).replace(
11
11
  /[018]/g,
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const operations = require("./operations-CdGb6IBU.cjs");
4
- const loft = require("./loft-PMRx9iMG.cjs");
3
+ const operations = require("./operations-BQeW_DSM.cjs");
4
+ const loft = require("./loft-B-UCPW9P.cjs");
5
5
  exports.addChild = operations.addChild;
6
6
  exports.addStep = operations.addStep;
7
7
  exports.circularPattern = operations.circularPattern;
@@ -1,5 +1,5 @@
1
- import { a, b, c, d, f, g, h, i, j, k, m, n, o, p, l, q, t, u, v, w, x, y, z, A, s, B, C, D, E } from "./operations-CjQHEu1h.js";
2
- import { i as i2, j as j2, l as l2, r } from "./loft-BHn7GKm8.js";
1
+ import { a, b, c, d, f, g, h, i, j, k, m, n, o, p, l, q, t, u, v, w, x, y, z, A, s, B, C, D, E } from "./operations-6hdpuYmY.js";
2
+ import { i as i2, j as j2, l as l2, r } from "./loft-oJq2OD3A.js";
3
3
  export {
4
4
  a as addChild,
5
5
  b as addStep,
package/dist/query.cjs CHANGED
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const helpers = require("./helpers-Dje6wrKi.cjs");
4
- const cornerFinder = require("./cornerFinder-DuStF5jK.cjs");
5
- const occtBoundary = require("./occtBoundary-BFAaUtA7.cjs");
6
- const shapeTypes = require("./shapeTypes-UqVCIO_T.cjs");
3
+ const helpers = require("./helpers-C0q_FVxq.cjs");
4
+ const cornerFinder = require("./cornerFinder-BQ-_VJx0.cjs");
5
+ const occtBoundary = require("./occtBoundary-CocN2VKx.cjs");
6
+ const shapeTypes = require("./shapeTypes-BxVxLdiD.cjs");
7
7
  const vecOps = require("./vecOps-CjRL1jau.cjs");
8
- const curveFns = require("./curveFns-ByeCqutv.cjs");
8
+ const curveFns = require("./curveFns-VMxgfkqw.cjs");
9
9
  function edgeDirectionFilter(dir, angle) {
10
10
  const d = vecOps.vecNormalize(helpers.resolveDir(dir));
11
11
  return (edge) => {
package/dist/query.js CHANGED
@@ -1,10 +1,10 @@
1
- import { c as createTypedFinder, o as distanceFromPointFilter, q as resolveDir } from "./helpers-BSQfs538.js";
2
- import { f, g } from "./helpers-BSQfs538.js";
3
- import { c } from "./cornerFinder-CPm2baSJ.js";
4
- import { g as getKernel } from "./occtBoundary-CoXB2xvx.js";
5
- import { p as gcWithScope } from "./shapeTypes-BU2LKv2S.js";
1
+ import { c as createTypedFinder, o as distanceFromPointFilter, q as resolveDir } from "./helpers-CmVkMubc.js";
2
+ import { f, g } from "./helpers-CmVkMubc.js";
3
+ import { c } from "./cornerFinder-CC_MunIh.js";
4
+ import { g as getKernel } from "./occtBoundary-D_gjqgzo.js";
5
+ import { p as gcWithScope } from "./shapeTypes-c-_pgYCx.js";
6
6
  import { j as vecNormalize, d as vecDot, D as DEG2RAD } from "./vecOps-ZDdZWbwT.js";
7
- import { F as getCurveType, w as curveLength } from "./curveFns-C5gSZ5EY.js";
7
+ import { l as getCurveType, f as curveLength } from "./curveFns-ZuQUBZvd.js";
8
8
  function edgeDirectionFilter(dir, angle) {
9
9
  const d = vecNormalize(resolveDir(dir));
10
10
  return (edge) => {
package/dist/result.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const errors = require("./errors-DK1VAdP4.cjs");
3
+ const errors = require("./errors-D13q2HCk.cjs");
4
4
  class BrepBugError extends Error {
5
5
  location;
6
6
  constructor(location, message) {
package/dist/result.js CHANGED
@@ -1,4 +1,4 @@
1
- import { B, O, a, c, b, e, f, i, d, g, m, h, j, k, o, l, z, q, s, t, n, p, u, r, v, w, x } from "./errors-wGhcJMpB.js";
1
+ import { B, O, a, c, b, e, f, i, d, g, m, h, j, k, o, l, z, q, s, t, n, p, u, r, v, w, x } from "./errors-CSYOlCCR.js";
2
2
  class BrepBugError extends Error {
3
3
  location;
4
4
  constructor(location, message) {