brepjs 18.35.3 → 18.35.4

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 (84) hide show
  1. package/dist/2d.cjs +6 -6
  2. package/dist/2d.js +6 -6
  3. package/dist/{blueprint-BZtQ37hZ.cjs → blueprint-C9feKfjM.cjs} +5 -5
  4. package/dist/{blueprint-BugZrlJZ.js → blueprint-PV2EbBko.js} +5 -5
  5. package/dist/{blueprintFns-DZreBQDw.js → blueprintFns-CohoA3Ly.js} +2 -2
  6. package/dist/{blueprintFns-Cd6RX-3U.cjs → blueprintFns-Diu8oFPr.cjs} +2 -2
  7. package/dist/{blueprintSketcher-CeUtlreY.cjs → blueprintSketcher-B1TC4tuf.cjs} +3 -3
  8. package/dist/{blueprintSketcher-Br9S5j8n.js → blueprintSketcher-BC22SEkZ.js} +3 -3
  9. package/dist/{boolean2D-B30MyM5A.cjs → boolean2D-CHza20uz.cjs} +4 -4
  10. package/dist/{boolean2D-jMwDLuLK.js → boolean2D-D42Z6h-L.js} +4 -4
  11. package/dist/{booleanFns-NkgP7bZA.cjs → booleanFns-CCJFmZf6.cjs} +4 -4
  12. package/dist/{booleanFns-BPWMgD1t.js → booleanFns-D7A-hqSP.js} +4 -4
  13. package/dist/brepjs.cjs +25 -25
  14. package/dist/brepjs.js +25 -25
  15. package/dist/{cameraFns-B5FrSRRP.js → cameraFns-BvZw_Bje.js} +2 -2
  16. package/dist/{cameraFns-Bb5fmsNi.cjs → cameraFns-D79etXJw.cjs} +2 -2
  17. package/dist/core.cjs +1 -1
  18. package/dist/core.js +1 -1
  19. package/dist/{cornerFinder-NT0nEY2D.js → cornerFinder-BPz7nFlt.js} +1 -1
  20. package/dist/{cornerFinder-Nd00yMHA.cjs → cornerFinder-D3m1OkXN.cjs} +1 -1
  21. package/dist/{curveFns-D1IaRpWu.js → curveFns-BJNwNm66.js} +1 -1
  22. package/dist/{curveFns-tBJhB6jA.cjs → curveFns-CiI0h04W.cjs} +1 -1
  23. package/dist/{drawFns-C9WFdiAW.cjs → drawFns-Cx7RJEdL.cjs} +12 -12
  24. package/dist/{drawFns-BetA5msk.js → drawFns-E68sfFlE.js} +12 -12
  25. package/dist/{extrudeFns-DWeYb6cu.js → extrudeFns-D49C5SBL.js} +1 -1
  26. package/dist/{extrudeFns-Bg-IXT_O.cjs → extrudeFns-DympFQua.cjs} +1 -1
  27. package/dist/{faceFns-ThsHosgU.cjs → faceFns-3HqgY1VN.cjs} +2 -2
  28. package/dist/{faceFns-DBEEcVC-.js → faceFns-DLjTsZIu.js} +2 -2
  29. package/dist/{helpers-D6XMORWy.cjs → helpers-BSU8Ilxm.cjs} +6 -6
  30. package/dist/{helpers-D2RrISk0.js → helpers-DI2r-O_h.js} +6 -6
  31. package/dist/{historyFns-BSSA9qoA.js → historyFns-D89ZUO18.js} +4 -4
  32. package/dist/{historyFns-DrjICLPB.cjs → historyFns-DoMVl9Wf.cjs} +4 -4
  33. package/dist/{importFns-Cq-bKeDn.js → importFns-CpKXeRz6.js} +2 -2
  34. package/dist/{importFns-B7nffQNd.cjs → importFns-SQNeOpGa.cjs} +2 -2
  35. package/dist/io.cjs +2 -2
  36. package/dist/io.js +2 -2
  37. package/dist/kernel/hullGeometry.d.ts +22 -0
  38. package/dist/kernel/occt/hullOps.d.ts +1 -6
  39. package/dist/kernel/occtWasm/hullOps.d.ts +1 -5
  40. package/dist/kernel/occtWasm/kernel2dOps.d.ts +7 -1
  41. package/dist/kernel/occtWasm/occtWasmAdapter.cjs +1 -1
  42. package/dist/kernel/occtWasm/occtWasmAdapter.d.ts +1 -1
  43. package/dist/kernel/occtWasm/occtWasmAdapter.js +1 -1
  44. package/dist/{measureFns-BTn_t0LK.js → measureFns-BMSt38re.js} +3 -3
  45. package/dist/{measureFns-BT_G8lXZ.cjs → measureFns-CG36omJ5.cjs} +3 -3
  46. package/dist/measurement.cjs +1 -1
  47. package/dist/measurement.js +1 -1
  48. package/dist/{meshFns-BcYvu4zj.cjs → meshFns-B08Sq0xg.cjs} +3 -3
  49. package/dist/{meshFns-CR68GwS8.js → meshFns-B6dmwjJL.js} +3 -3
  50. package/dist/{occtWasmAdapter-DUruQhFF.js → occtWasmAdapter-DfdUU9UU.js} +353 -131
  51. package/dist/{occtWasmAdapter-R8zCS1h7.cjs → occtWasmAdapter-ZiJfgmS1.cjs} +358 -130
  52. package/dist/operations.cjs +2 -2
  53. package/dist/operations.js +2 -2
  54. package/dist/{primitiveFns-BjeLfI12.js → primitiveFns-BD6YZbCJ.js} +7 -7
  55. package/dist/{primitiveFns-DtY84t7q.cjs → primitiveFns-DFnQlGVV.cjs} +7 -7
  56. package/dist/projection.cjs +1 -1
  57. package/dist/projection.js +1 -1
  58. package/dist/query.cjs +2 -2
  59. package/dist/query.js +2 -2
  60. package/dist/{shapeFns-oS8Us7JQ.js → shapeFns-C8pitNme.js} +2 -2
  61. package/dist/{shapeFns-lDEvCF5Q.cjs → shapeFns-CnNKfmw8.cjs} +2 -2
  62. package/dist/shapeRef.cjs +1 -1
  63. package/dist/shapeRef.js +1 -1
  64. package/dist/{shapeRefFns-C2DbyKEO.js → shapeRefFns-BQlYDeCD.js} +4 -4
  65. package/dist/{shapeRefFns-DHioZfFV.cjs → shapeRefFns-DtCBv52A.cjs} +4 -4
  66. package/dist/{shapeTypes-BH-9bXON.js → shapeTypes-BKeiP62J.js} +3 -241
  67. package/dist/{shapeTypes-BiX2PjaO.cjs → shapeTypes-D5Nua1z1.cjs} +5 -243
  68. package/dist/sketching.cjs +3 -3
  69. package/dist/sketching.js +3 -3
  70. package/dist/{solidBuilders-DR3oU7Fb.cjs → solidBuilders-0ZZGbPt3.cjs} +2 -2
  71. package/dist/{solidBuilders-BiduNSRx.js → solidBuilders-DjPCyWCd.js} +2 -2
  72. package/dist/{surfaceBuilders-s2Uo2ard.cjs → surfaceBuilders-6QimO9vi.cjs} +2 -2
  73. package/dist/{surfaceBuilders-xmm7fFbW.js → surfaceBuilders-d4o4OoWy.js} +2 -2
  74. package/dist/text.cjs +2 -2
  75. package/dist/text.js +2 -2
  76. package/dist/{textBlueprints-Ca1NcWQg.cjs → textBlueprints-BUkh-dID.cjs} +7 -7
  77. package/dist/{textBlueprints-DRh48_Fo.js → textBlueprints-DOPJs2t6.js} +7 -7
  78. package/dist/{textMetrics-CGN19mAp.cjs → textMetrics-DNQplzf7.cjs} +1 -1
  79. package/dist/{textMetrics-BU6Ow8mb.js → textMetrics-h6jI-oL_.js} +1 -1
  80. package/dist/topology.cjs +7 -7
  81. package/dist/topology.js +7 -7
  82. package/dist/{topologyQueryFns-BoMkI1jZ.cjs → topologyQueryFns-BNv_2PHm.cjs} +1 -1
  83. package/dist/{topologyQueryFns-B8uqQlEU.js → topologyQueryFns-DhdAOL0M.js} +1 -1
  84. package/package.json +1 -1
@@ -1,4 +1,255 @@
1
1
  const require_vec3 = require("./vec3-CFwOI0ZI.cjs");
2
+ //#region src/kernel/hullGeometry.ts
3
+ function sub(a, b) {
4
+ return {
5
+ x: a.x - b.x,
6
+ y: a.y - b.y,
7
+ z: a.z - b.z
8
+ };
9
+ }
10
+ function cross(a, b) {
11
+ return {
12
+ x: a.y * b.z - a.z * b.y,
13
+ y: a.z * b.x - a.x * b.z,
14
+ z: a.x * b.y - a.y * b.x
15
+ };
16
+ }
17
+ function dot(a, b) {
18
+ return a.x * b.x + a.y * b.y + a.z * b.z;
19
+ }
20
+ function lengthVec(v) {
21
+ return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
22
+ }
23
+ function distSq(a, b) {
24
+ const dx = a.x - b.x;
25
+ const dy = a.y - b.y;
26
+ const dz = a.z - b.z;
27
+ return dx * dx + dy * dy + dz * dz;
28
+ }
29
+ /** Safe array access — throws on out-of-bounds instead of returning undefined. */
30
+ function at(arr, i) {
31
+ const v = arr[i];
32
+ if (v === void 0) throw new Error(`Index ${i} out of bounds`);
33
+ return v;
34
+ }
35
+ /** Safe number array access. */
36
+ function atN(arr, i) {
37
+ const v = arr[i];
38
+ if (v === void 0) throw new Error(`Index ${i} out of bounds`);
39
+ return v;
40
+ }
41
+ function makeFace$1(points, a, b, c) {
42
+ const normal = cross(sub(at(points, b), at(points, a)), sub(at(points, c), at(points, a)));
43
+ const len = lengthVec(normal);
44
+ const n = len > 1e-14 ? {
45
+ x: normal.x / len,
46
+ y: normal.y / len,
47
+ z: normal.z / len
48
+ } : normal;
49
+ return {
50
+ a,
51
+ b,
52
+ c,
53
+ normal: n,
54
+ offset: dot(n, at(points, a)),
55
+ alive: true,
56
+ outsidePoints: []
57
+ };
58
+ }
59
+ function signedDist(face, point) {
60
+ return dot(face.normal, point) - face.offset;
61
+ }
62
+ function deduplicatePoints(points, tolerance) {
63
+ const tolSq = tolerance * tolerance;
64
+ const result = [];
65
+ for (const p of points) {
66
+ let isDuplicate = false;
67
+ for (const q of result) if (distSq(p, q) < tolSq) {
68
+ isDuplicate = true;
69
+ break;
70
+ }
71
+ if (!isDuplicate) result.push(p);
72
+ }
73
+ return result;
74
+ }
75
+ function findInitialTetrahedron(points) {
76
+ const n = points.length;
77
+ if (n < 4) return null;
78
+ let i0 = 0;
79
+ let i1 = 1;
80
+ let maxDist = distSq(at(points, 0), at(points, 1));
81
+ for (let i = 0; i < n; i++) for (let j = i + 1; j < n; j++) {
82
+ const d = distSq(at(points, i), at(points, j));
83
+ if (d > maxDist) {
84
+ maxDist = d;
85
+ i0 = i;
86
+ i1 = j;
87
+ }
88
+ }
89
+ if (maxDist < 1e-20) return null;
90
+ const lineDir = sub(at(points, i1), at(points, i0));
91
+ let i2 = -1;
92
+ let maxLineDist = -1;
93
+ for (let i = 0; i < n; i++) {
94
+ if (i === i0 || i === i1) continue;
95
+ const c = cross(lineDir, sub(at(points, i), at(points, i0)));
96
+ const d = dot(c, c);
97
+ if (d > maxLineDist) {
98
+ maxLineDist = d;
99
+ i2 = i;
100
+ }
101
+ }
102
+ if (i2 === -1 || maxLineDist < 1e-20) return null;
103
+ const planeNormal = cross(sub(at(points, i1), at(points, i0)), sub(at(points, i2), at(points, i0)));
104
+ const planeLen = lengthVec(planeNormal);
105
+ if (planeLen < 1e-14) return null;
106
+ const pn = {
107
+ x: planeNormal.x / planeLen,
108
+ y: planeNormal.y / planeLen,
109
+ z: planeNormal.z / planeLen
110
+ };
111
+ const planeOffset = dot(pn, at(points, i0));
112
+ let i3 = -1;
113
+ let maxPlaneDist = -1;
114
+ for (let i = 0; i < n; i++) {
115
+ if (i === i0 || i === i1 || i === i2) continue;
116
+ const d = Math.abs(dot(pn, at(points, i)) - planeOffset);
117
+ if (d > maxPlaneDist) {
118
+ maxPlaneDist = d;
119
+ i3 = i;
120
+ }
121
+ }
122
+ if (i3 === -1 || maxPlaneDist < 1e-14) return null;
123
+ if (dot(pn, at(points, i3)) - planeOffset > 0) return [
124
+ i0,
125
+ i2,
126
+ i1,
127
+ i3
128
+ ];
129
+ return [
130
+ i0,
131
+ i1,
132
+ i2,
133
+ i3
134
+ ];
135
+ }
136
+ /**
137
+ * Compute the 3D convex hull of a point set.
138
+ *
139
+ * @throws if fewer than 4 non-coincident, non-coplanar points are supplied.
140
+ */
141
+ function quickHull(inputPoints, tolerance) {
142
+ const points = deduplicatePoints(inputPoints, tolerance);
143
+ if (points.length < 4) throw new Error(points.length === 0 ? "No points provided for convex hull" : "Fewer than 4 non-coincident points; cannot form a 3D convex hull");
144
+ const tet = findInitialTetrahedron(points);
145
+ if (tet === null) throw new Error("All points are coplanar; cannot form a 3D convex hull");
146
+ const [t0, t1, t2, t3] = tet;
147
+ const centroid = {
148
+ x: (at(points, t0).x + at(points, t1).x + at(points, t2).x + at(points, t3).x) / 4,
149
+ y: (at(points, t0).y + at(points, t1).y + at(points, t2).y + at(points, t3).y) / 4,
150
+ z: (at(points, t0).z + at(points, t1).z + at(points, t2).z + at(points, t3).z) / 4
151
+ };
152
+ function makeOutwardFace(a, b, c) {
153
+ const face = makeFace$1(points, a, b, c);
154
+ const toCentroid = sub(centroid, {
155
+ x: (at(points, a).x + at(points, b).x + at(points, c).x) / 3,
156
+ y: (at(points, a).y + at(points, b).y + at(points, c).y) / 3,
157
+ z: (at(points, a).z + at(points, b).z + at(points, c).z) / 3
158
+ });
159
+ if (dot(face.normal, toCentroid) > 0) return makeFace$1(points, a, c, b);
160
+ return face;
161
+ }
162
+ const faces = [
163
+ makeOutwardFace(t0, t1, t2),
164
+ makeOutwardFace(t0, t2, t3),
165
+ makeOutwardFace(t0, t3, t1),
166
+ makeOutwardFace(t1, t3, t2)
167
+ ];
168
+ const tetSet = new Set([
169
+ t0,
170
+ t1,
171
+ t2,
172
+ t3
173
+ ]);
174
+ const epsilon = 1e-10;
175
+ for (let i = 0; i < points.length; i++) {
176
+ if (tetSet.has(i)) continue;
177
+ for (const face of faces) if (signedDist(face, at(points, i)) > epsilon) {
178
+ face.outsidePoints.push(i);
179
+ break;
180
+ }
181
+ }
182
+ for (let iteration = 0; iteration < points.length * 4; iteration++) {
183
+ let currentFace = null;
184
+ for (const face of faces) if (face.alive && face.outsidePoints.length > 0) {
185
+ currentFace = face;
186
+ break;
187
+ }
188
+ if (currentFace === null) break;
189
+ let furthestIdx = atN(currentFace.outsidePoints, 0);
190
+ let furthestDist = signedDist(currentFace, at(points, furthestIdx));
191
+ for (let i = 1; i < currentFace.outsidePoints.length; i++) {
192
+ const idx = atN(currentFace.outsidePoints, i);
193
+ const d = signedDist(currentFace, at(points, idx));
194
+ if (d > furthestDist) {
195
+ furthestDist = d;
196
+ furthestIdx = idx;
197
+ }
198
+ }
199
+ const visibleFaces = [];
200
+ for (const face of faces) if (face.alive && signedDist(face, at(points, furthestIdx)) > epsilon) visibleFaces.push(face);
201
+ const edgeCount = /* @__PURE__ */ new Map();
202
+ for (const face of visibleFaces) {
203
+ const edges = [
204
+ [face.a, face.b],
205
+ [face.b, face.c],
206
+ [face.c, face.a]
207
+ ];
208
+ for (const [ea, eb] of edges) {
209
+ const key = ea < eb ? `${ea}-${eb}` : `${eb}-${ea}`;
210
+ const entry = edgeCount.get(key);
211
+ if (entry) entry.count++;
212
+ else edgeCount.set(key, {
213
+ a: ea,
214
+ b: eb,
215
+ count: 1
216
+ });
217
+ }
218
+ }
219
+ const horizonEdges = [];
220
+ for (const entry of edgeCount.values()) if (entry.count === 1) horizonEdges.push({
221
+ a: entry.a,
222
+ b: entry.b
223
+ });
224
+ const orphanedPoints = [];
225
+ for (const face of visibleFaces) {
226
+ for (const idx of face.outsidePoints) if (idx !== furthestIdx) orphanedPoints.push(idx);
227
+ face.alive = false;
228
+ face.outsidePoints = [];
229
+ }
230
+ const newFaces = [];
231
+ for (const edge of horizonEdges) {
232
+ const newFaceObj = makeFace$1(points, edge.a, edge.b, furthestIdx);
233
+ newFaces.push(newFaceObj);
234
+ faces.push(newFaceObj);
235
+ }
236
+ for (const idx of orphanedPoints) for (const face of newFaces) if (signedDist(face, at(points, idx)) > epsilon) {
237
+ face.outsidePoints.push(idx);
238
+ break;
239
+ }
240
+ }
241
+ const resultFaces = [];
242
+ for (const face of faces) if (face.alive) resultFaces.push([
243
+ face.a,
244
+ face.b,
245
+ face.c
246
+ ]);
247
+ return {
248
+ faces: resultFaces,
249
+ points
250
+ };
251
+ }
252
+ //#endregion
2
253
  //#region src/kernel/geometry2d.ts
3
254
  function evaluateCurve2d$1(c, t) {
4
255
  switch (c.__bk2d) {
@@ -2974,10 +3225,27 @@ function makeEllipseArc2d(cx, cy, majorRadius, minorRadius, startAngle, endAngle
2974
3225
  function makeBezier2d(points) {
2975
3226
  return c2dWrap(makeBezier2d$1(points));
2976
3227
  }
2977
- function makeBSpline2d(points) {
2978
- if (points.length <= 25) return c2dWrap(makeBezier2d$1(points));
2979
- const step = Math.max(1, Math.floor(points.length / 24));
2980
- return c2dWrap(makeBezier2d$1(points.filter((_, i) => i % step === 0 || i === points.length - 1)));
3228
+ function makeBSpline2d(points, options) {
3229
+ const poles = points;
3230
+ const n = poles.length;
3231
+ const degree = Math.max(1, Math.min(options?.degMax ?? 3, n - 1));
3232
+ const knots = [0];
3233
+ const mults = [degree + 1];
3234
+ const nInternalKnots = n - degree - 1;
3235
+ for (let i = 1; i <= nInternalKnots; i++) {
3236
+ knots.push(i / (nInternalKnots + 1));
3237
+ mults.push(1);
3238
+ }
3239
+ knots.push(1);
3240
+ mults.push(degree + 1);
3241
+ return c2dWrap({
3242
+ __bk2d: "bspline",
3243
+ poles,
3244
+ knots,
3245
+ multiplicities: mults,
3246
+ degree,
3247
+ isPeriodic: false
3248
+ });
2981
3249
  }
2982
3250
  function evaluateCurve2d(curve, param) {
2983
3251
  return evaluateCurve2d$1(c2d(curve), param);
@@ -3222,16 +3490,53 @@ function approximateCurve2dAsBSpline(curve, maxSegments) {
3222
3490
  });
3223
3491
  }
3224
3492
  function decomposeBSpline2dToBeziers(curve) {
3225
- const knots = c2d(curve).knots ?? [];
3226
- if (knots.length < 2) return [curve];
3227
- const result = [];
3228
- for (let i = 0; i < knots.length - 1; i++) {
3229
- const k0 = knots[i];
3230
- const k1 = knots[i + 1];
3231
- if (Math.abs(k1 - k0) < 1e-15) continue;
3232
- result.push(trimCurve2d(curve, k0, k1));
3493
+ let cu = c2d(curve);
3494
+ while (cu.__bk2d === "trimmed" && cu.basis) cu = cu.basis;
3495
+ if (cu.__bk2d !== "bspline") return [curve];
3496
+ const poles = cu.poles;
3497
+ const p = cu.degree;
3498
+ const U = [];
3499
+ for (let i = 0; i < cu.knots.length; i++) for (let j = 0; j < cu.multiplicities[i]; j++) U.push(cu.knots[i]);
3500
+ const m = poles.length - 1 + p + 1;
3501
+ if (p < 1 || U.length !== m + 1) return [c2dWrap(makeBezier2d$1(poles))];
3502
+ const clone = (pt) => [pt[0], pt[1]];
3503
+ const segments = [];
3504
+ let a = p;
3505
+ let b = p + 1;
3506
+ let segPoles = [];
3507
+ for (let i = 0; i <= p; i++) segPoles[i] = clone(poles[i]);
3508
+ let nextPoles = [];
3509
+ while (b < m) {
3510
+ const i0 = b;
3511
+ while (b < m && U[b + 1] === U[b]) b++;
3512
+ const mult = b - i0 + 1;
3513
+ if (mult < p) {
3514
+ const numer = U[b] - U[a];
3515
+ const alphas = [];
3516
+ for (let j = p; j > mult; j--) alphas[j - mult - 1] = numer / (U[a + j] - U[a]);
3517
+ const r = p - mult;
3518
+ for (let j = 1; j <= r; j++) {
3519
+ const save = r - j;
3520
+ const s = mult + j;
3521
+ for (let k = p; k >= s; k--) {
3522
+ const alpha = alphas[k - s];
3523
+ const cur = segPoles[k];
3524
+ const prev = segPoles[k - 1];
3525
+ segPoles[k] = [alpha * cur[0] + (1 - alpha) * prev[0], alpha * cur[1] + (1 - alpha) * prev[1]];
3526
+ }
3527
+ if (b < m) nextPoles[save] = clone(segPoles[p]);
3528
+ }
3529
+ }
3530
+ segments.push(segPoles);
3531
+ if (b < m) {
3532
+ for (let i = p - mult; i <= p; i++) nextPoles[i] = clone(poles[b - p + i]);
3533
+ segPoles = nextPoles;
3534
+ nextPoles = [];
3535
+ a = b;
3536
+ b++;
3537
+ }
3233
3538
  }
3234
- return result.length > 0 ? result : [curve];
3539
+ return segments.map((sp) => c2dWrap(makeBezier2d$1(sp)));
3235
3540
  }
3236
3541
  function createBoundingBox2d() {
3237
3542
  return createBBox2d();
@@ -3684,124 +3989,41 @@ function applyComposedTransformWithHistory(transformFn, iterShapesFn, hashCodeFn
3684
3989
  }
3685
3990
  //#endregion
3686
3991
  //#region src/kernel/occtWasm/hullOps.ts
3687
- function findHorizonEdges(faces, visible) {
3688
- const visSet = new Set(visible);
3689
- const horizon = [];
3690
- for (const fi of visible) {
3691
- const f = faces[fi];
3692
- for (let ei = 0; ei < 3; ei++) {
3693
- const a = f[ei], b = f[(ei + 1) % 3];
3694
- if (faces.some((g, fj) => fj !== fi && !visSet.has(fj) && [
3695
- 0,
3696
- 1,
3697
- 2
3698
- ].some((ej) => g[ej] === b && g[(ej + 1) % 3] === a))) horizon.push([a, b]);
3699
- }
3700
- }
3701
- return horizon;
3992
+ function hullFromPoints(k, Module, points, tolerance) {
3993
+ if (points.length < 4) throw new Error("hullFromPoints: need at least 4 points");
3994
+ const { points: hullPoints, faces } = quickHull(points, tolerance);
3995
+ if (faces.length < 4) throw new Error("hullFromPoints: degenerate hull (fewer than 4 faces)");
3996
+ return buildSolidFromFaces(k, Module, [...hullPoints], [...faces], tolerance);
3702
3997
  }
3703
- function computeConvexHullFaces(pts) {
3704
- const cross = (a, b) => ({
3705
- x: a.y * b.z - a.z * b.y,
3706
- y: a.z * b.x - a.x * b.z,
3707
- z: a.x * b.y - a.y * b.x
3708
- });
3709
- const sub = (a, b) => ({
3710
- x: a.x - b.x,
3711
- y: a.y - b.y,
3712
- z: a.z - b.z
3713
- });
3714
- const dot = (a, b) => a.x * b.x + a.y * b.y + a.z * b.z;
3715
- const n = pts.length;
3716
- const faces = [];
3717
- const p0 = pts[0];
3718
- let i1 = 1;
3719
- while (i1 < n) {
3720
- const p = require_vec3.wasmIndex(pts, i1);
3721
- if (Math.hypot(p.x - p0.x, p.y - p0.y, p.z - p0.z) >= 1e-10) break;
3722
- i1++;
3723
- }
3724
- let i2 = i1 + 1;
3725
- const e01 = sub(pts[i1], p0);
3726
- while (i2 < n) {
3727
- const c = cross(e01, sub(pts[i2], p0));
3728
- if (Math.hypot(c.x, c.y, c.z) > 1e-10) break;
3729
- i2++;
3730
- }
3731
- let i3 = i2 + 1;
3732
- const norm = cross(e01, sub(pts[i2], p0));
3733
- while (i3 < n) {
3734
- if (Math.abs(dot(norm, sub(pts[i3], p0))) > 1e-10) break;
3735
- i3++;
3736
- }
3737
- if (i3 >= n) return [[
3738
- 0,
3739
- 1,
3740
- 2
3741
- ]];
3742
- if (dot(cross(sub(pts[i1], p0), sub(pts[i2], p0)), sub(pts[i3], p0)) > 0) faces.push([
3743
- 0,
3744
- i1,
3745
- i2
3746
- ], [
3747
- 0,
3748
- i2,
3749
- i3
3750
- ], [
3751
- 0,
3752
- i3,
3753
- i1
3754
- ], [
3755
- i1,
3756
- i3,
3757
- i2
3758
- ]);
3759
- else faces.push([
3760
- 0,
3761
- i2,
3762
- i1
3763
- ], [
3764
- 0,
3765
- i3,
3766
- i2
3767
- ], [
3768
- 0,
3769
- i1,
3770
- i3
3771
- ], [
3772
- i2,
3773
- i3,
3774
- i1
3775
- ]);
3776
- const used = new Set([
3777
- 0,
3778
- i1,
3779
- i2,
3780
- i3
3781
- ]);
3782
- for (let pi = 0; pi < n; pi++) {
3783
- if (used.has(pi)) continue;
3784
- const p = pts[pi];
3785
- const visible = [];
3786
- for (let fi = 0; fi < faces.length; fi++) {
3787
- const f = faces[fi];
3788
- if (dot(cross(sub(pts[f[1]], pts[f[0]]), sub(pts[f[2]], pts[f[0]])), sub(p, pts[f[0]])) > 1e-10) visible.push(fi);
3998
+ /**
3999
+ * Sample surface vertices of each shape via tessellation. A coarse deflection
4000
+ * keeps the point count low the convex hull only needs extreme points, and
4001
+ * fine meshes on curved surfaces explode the hull cost.
4002
+ */
4003
+ function extractVertices(k, Module, shapes, tolerance) {
4004
+ const deflection = Math.max(tolerance, 1);
4005
+ const points = [];
4006
+ for (const shape of shapes) {
4007
+ const meshData = k.tessellate(unwrap(shape), deflection, deflection * .5);
4008
+ try {
4009
+ const posCount = meshData.positionCount;
4010
+ const posPtr = meshData.getPositionsPtr() >> 2;
4011
+ for (let i = 0; i < posCount; i += 3) points.push({
4012
+ x: Module.HEAPF32[posPtr + i] ?? 0,
4013
+ y: Module.HEAPF32[posPtr + i + 1] ?? 0,
4014
+ z: Module.HEAPF32[posPtr + i + 2] ?? 0
4015
+ });
4016
+ } finally {
4017
+ meshData.delete();
3789
4018
  }
3790
- if (visible.length === 0) continue;
3791
- const horizon = findHorizonEdges(faces, visible);
3792
- visible.sort((a2, b2) => b2 - a2);
3793
- for (const fi of visible) faces.splice(fi, 1);
3794
- for (const [a, b] of horizon) faces.push([
3795
- a,
3796
- b,
3797
- pi
3798
- ]);
3799
- }
3800
- return faces;
4019
+ }
4020
+ return points;
3801
4021
  }
3802
- function hullFromPoints(k, Module, points, tolerance) {
3803
- if (points.length < 4) throw new Error("hullFromPoints: need at least 4 points");
3804
- return buildSolidFromFaces(k, Module, points, computeConvexHullFaces(points), tolerance);
4022
+ function hull(k, Module, shapes, tolerance) {
4023
+ if (shapes.length === 0) throw new Error("hull: no shapes provided");
4024
+ const points = extractVertices(k, Module, shapes, tolerance);
4025
+ if (points.length < 4) throw new Error("hull: fewer than 4 vertices extracted from input shapes");
4026
+ return hullFromPoints(k, Module, points, tolerance);
3805
4027
  }
3806
4028
  //#endregion
3807
4029
  //#region src/kernel/occtWasm/occtWasmAdapter.ts
@@ -3957,8 +4179,8 @@ var OcctWasmAdapter = class OcctWasmAdapter {
3957
4179
  solidFromShell(shell) {
3958
4180
  return solidFromShell(this.k, shell);
3959
4181
  }
3960
- hull(_shapes, _tolerance) {
3961
- notImplemented("hull");
4182
+ hull(shapes, tolerance) {
4183
+ return hull(this.k, this.Module, shapes, tolerance);
3962
4184
  }
3963
4185
  hullFromPoints(points, tolerance) {
3964
4186
  return hullFromPoints(this.k, this.Module, points, tolerance);
@@ -4704,6 +4926,12 @@ Object.defineProperty(exports, "mirrorAtPoint", {
4704
4926
  return mirrorAtPoint;
4705
4927
  }
4706
4928
  });
4929
+ Object.defineProperty(exports, "quickHull", {
4930
+ enumerable: true,
4931
+ get: function() {
4932
+ return quickHull;
4933
+ }
4934
+ });
4707
4935
  Object.defineProperty(exports, "rotateCurve2d", {
4708
4936
  enumerable: true,
4709
4937
  get: function() {
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_historyFns = require("./historyFns-DrjICLPB.cjs");
3
- const require_extrudeFns = require("./extrudeFns-Bg-IXT_O.cjs");
2
+ const require_historyFns = require("./historyFns-DoMVl9Wf.cjs");
3
+ const require_extrudeFns = require("./extrudeFns-DympFQua.cjs");
4
4
  exports.addChild = require_historyFns.addChild;
5
5
  exports.addStep = require_historyFns.addStep;
6
6
  exports.circularPattern = require_historyFns.circularPattern;
@@ -1,3 +1,3 @@
1
- import { C as walkAssembly, D as exportAssemblySTEP, E as linearPattern, O as createAssembly, S as updateNode, T as gridPattern, _ as collectShapes, a as findStep, b as findNode, c as registerOperation, d as replayHistory, g as addChild, h as undoLast, l as registerShape, m as stepsFrom, n as createHistory, o as getShape, p as stepCount, r as createRegistry, s as modifyStep, t as addStep, u as replayFrom, v as countNodes, w as circularPattern, x as removeChild, y as createAssemblyNode } from "./historyFns-BSSA9qoA.js";
2
- import { c as sweep, i as complexExtrude, l as twistExtrude, s as supportExtrude } from "./extrudeFns-DWeYb6cu.js";
1
+ import { C as walkAssembly, D as exportAssemblySTEP, E as linearPattern, O as createAssembly, S as updateNode, T as gridPattern, _ as collectShapes, a as findStep, b as findNode, c as registerOperation, d as replayHistory, g as addChild, h as undoLast, l as registerShape, m as stepsFrom, n as createHistory, o as getShape, p as stepCount, r as createRegistry, s as modifyStep, t as addStep, u as replayFrom, v as countNodes, w as circularPattern, x as removeChild, y as createAssemblyNode } from "./historyFns-D89ZUO18.js";
2
+ import { c as sweep, i as complexExtrude, l as twistExtrude, s as supportExtrude } from "./extrudeFns-D49C5SBL.js";
3
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,13 +1,13 @@
1
- import { Z as getKernel, _ as isSolid, c as createSolid, h as isShape3D, p as isFace, r as castShapeWithKnownType, t as castShape, x as isClosedWire, y as isWire } from "./shapeTypes-BH-9bXON.js";
1
+ import { Z as getKernel, _ as isSolid, c as createSolid, h as isShape3D, p as isFace, r as castShapeWithKnownType, t as castShape, x as isClosedWire, y as isWire } from "./shapeTypes-BKeiP62J.js";
2
2
  import { A as ok, T as isOk, b as err, d as validationError, i as kernelError, l as typeCastError, t as BrepErrorCode, v as andThen, w as isErr } from "./errors-DNWJsfVU.js";
3
- import { c as getFaces, i as getCachedIsValid, l as getOrCreateCache, m as invalidateShapeCache, p as getWires, s as getEdges } from "./topologyQueryFns-B8uqQlEU.js";
3
+ import { c as getFaces, i as getCachedIsValid, l as getOrCreateCache, m as invalidateShapeCache, p as getWires, s as getEdges } from "./topologyQueryFns-DhdAOL0M.js";
4
4
  import { n as HASH_CODE_MAX, t as DEG2RAD } from "./constants-ITRzCnCp.js";
5
- import { _ as downcast } from "./faceFns-DBEEcVC-.js";
6
- import { _ as propagateAllMetadata, g as collectInputFaceHashes, h as translate } from "./shapeFns-oS8Us7JQ.js";
5
+ import { _ as downcast } from "./faceFns-DLjTsZIu.js";
6
+ import { _ as propagateAllMetadata, g as collectInputFaceHashes, h as translate } from "./shapeFns-C8pitNme.js";
7
7
  import { t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
8
- import { _ as makeThreePointArc, a as makeNonPlanarFace, c as makeBSplineApproximation, d as makeCircle, f as makeEllipse, g as makeTangentArc, h as makeLine, i as makeNewFaceWithinFace, m as makeHelix, o as makePolygon, p as makeEllipseArc, r as makeFace, s as assembleWire, t as addHolesInFace, u as makeBezierCurve } from "./surfaceBuilders-xmm7fFbW.js";
9
- import { a as fuseAll, i as fuse, n as cut, r as cutAll } from "./booleanFns-BPWMgD1t.js";
10
- import { a as makeOffset, c as makeTorus, i as makeEllipsoid, l as makeVertex, n as makeCone, o as makeSolid, r as makeCylinder, s as makeSphere, t as makeCompound, u as weldShellsAndFaces } from "./solidBuilders-BiduNSRx.js";
8
+ import { _ as makeThreePointArc, a as makeNonPlanarFace, c as makeBSplineApproximation, d as makeCircle, f as makeEllipse, g as makeTangentArc, h as makeLine, i as makeNewFaceWithinFace, m as makeHelix, o as makePolygon, p as makeEllipseArc, r as makeFace, s as assembleWire, t as addHolesInFace, u as makeBezierCurve } from "./surfaceBuilders-d4o4OoWy.js";
9
+ import { a as fuseAll, i as fuse, n as cut, r as cutAll } from "./booleanFns-D7A-hqSP.js";
10
+ import { a as makeOffset, c as makeTorus, i as makeEllipsoid, l as makeVertex, n as makeCone, o as makeSolid, r as makeCylinder, s as makeSphere, t as makeCompound, u as weldShellsAndFaces } from "./solidBuilders-DjPCyWCd.js";
11
11
  //#region src/topology/threeHelpers.ts
12
12
  /**
13
13
  * Convert a ShapeMesh into BufferGeometry-compatible typed arrays.
@@ -1,13 +1,13 @@
1
- const require_shapeTypes = require("./shapeTypes-BiX2PjaO.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-D5Nua1z1.cjs");
2
2
  const require_errors = require("./errors-CXJtc4I7.cjs");
3
- const require_topologyQueryFns = require("./topologyQueryFns-BoMkI1jZ.cjs");
3
+ const require_topologyQueryFns = require("./topologyQueryFns-BNv_2PHm.cjs");
4
4
  const require_constants = require("./constants-BOVyEYGH.cjs");
5
- const require_faceFns = require("./faceFns-ThsHosgU.cjs");
6
- const require_shapeFns = require("./shapeFns-lDEvCF5Q.cjs");
5
+ const require_faceFns = require("./faceFns-3HqgY1VN.cjs");
6
+ const require_shapeFns = require("./shapeFns-CnNKfmw8.cjs");
7
7
  const require_arrayAccess = require("./arrayAccess-e4H9cBfh.cjs");
8
- const require_surfaceBuilders = require("./surfaceBuilders-s2Uo2ard.cjs");
9
- const require_booleanFns = require("./booleanFns-NkgP7bZA.cjs");
10
- const require_solidBuilders = require("./solidBuilders-DR3oU7Fb.cjs");
8
+ const require_surfaceBuilders = require("./surfaceBuilders-6QimO9vi.cjs");
9
+ const require_booleanFns = require("./booleanFns-CCJFmZf6.cjs");
10
+ const require_solidBuilders = require("./solidBuilders-0ZZGbPt3.cjs");
11
11
  //#region src/topology/threeHelpers.ts
12
12
  /**
13
13
  * Convert a ShapeMesh into BufferGeometry-compatible typed arrays.
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_cameraFns = require("./cameraFns-Bb5fmsNi.cjs");
2
+ const require_cameraFns = require("./cameraFns-D79etXJw.cjs");
3
3
  exports.PROJECTION_PLANES = require_cameraFns.PROJECTION_PLANES;
4
4
  exports.cameraFromPlane = require_cameraFns.cameraFromPlane;
5
5
  exports.cameraLookAt = require_cameraFns.cameraLookAt;
@@ -1,2 +1,2 @@
1
- import { a as makeProjectedEdges, i as projectEdges, n as cameraLookAt, o as PROJECTION_PLANES, r as createCamera, s as isProjectionPlane, t as cameraFromPlane } from "./cameraFns-B5FrSRRP.js";
1
+ import { a as makeProjectedEdges, i as projectEdges, n as cameraLookAt, o as PROJECTION_PLANES, r as createCamera, s as isProjectionPlane, t as cameraFromPlane } from "./cameraFns-BvZw_Bje.js";
2
2
  export { PROJECTION_PLANES, cameraFromPlane, cameraLookAt, createCamera, isProjectionPlane, makeProjectedEdges, projectEdges };
package/dist/query.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_helpers = require("./helpers-D6XMORWy.cjs");
3
- const require_cornerFinder = require("./cornerFinder-Nd00yMHA.cjs");
2
+ const require_helpers = require("./helpers-BSU8Ilxm.cjs");
3
+ const require_cornerFinder = require("./cornerFinder-D3m1OkXN.cjs");
4
4
  exports.cornerFinder = require_cornerFinder.cornerFinder;
5
5
  exports.edgeFinder = require_helpers.edgeFinder;
6
6
  exports.faceFinder = require_helpers.faceFinder;
package/dist/query.js CHANGED
@@ -1,3 +1,3 @@
1
- import { n as edgeFinder, r as faceFinder, t as getSingleFace } from "./helpers-D2RrISk0.js";
2
- import { t as cornerFinder } from "./cornerFinder-NT0nEY2D.js";
1
+ import { n as edgeFinder, r as faceFinder, t as getSingleFace } from "./helpers-DI2r-O_h.js";
2
+ import { t as cornerFinder } from "./cornerFinder-BPz7nFlt.js";
3
3
  export { cornerFinder, edgeFinder, faceFinder, getSingleFace };
@@ -1,6 +1,6 @@
1
- import { Z as getKernel, t as castShape } from "./shapeTypes-BH-9bXON.js";
1
+ import { Z as getKernel, t as castShape } from "./shapeTypes-BKeiP62J.js";
2
2
  import { A as ok, b as err, d as validationError, t as BrepErrorCode } from "./errors-DNWJsfVU.js";
3
- import { C as kernelCall, c as getFaces, l as getOrCreateCache, r as getCacheEntry, w as kernelCallRaw } from "./topologyQueryFns-B8uqQlEU.js";
3
+ import { C as kernelCall, c as getFaces, l as getOrCreateCache, r as getCacheEntry, w as kernelCallRaw } from "./topologyQueryFns-DhdAOL0M.js";
4
4
  import { n as HASH_CODE_MAX, t as DEG2RAD } from "./constants-ITRzCnCp.js";
5
5
  //#region src/topology/metadata/originTrackingFns.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
- const require_shapeTypes = require("./shapeTypes-BiX2PjaO.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-D5Nua1z1.cjs");
2
2
  const require_errors = require("./errors-CXJtc4I7.cjs");
3
- const require_topologyQueryFns = require("./topologyQueryFns-BoMkI1jZ.cjs");
3
+ const require_topologyQueryFns = require("./topologyQueryFns-BNv_2PHm.cjs");
4
4
  const require_constants = require("./constants-BOVyEYGH.cjs");
5
5
  //#region src/topology/metadata/originTrackingFns.ts
6
6
  /**
package/dist/shapeRef.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_shapeRefFns = require("./shapeRefFns-DHioZfFV.cjs");
2
+ const require_shapeRefFns = require("./shapeRefFns-DtCBv52A.cjs");
3
3
  exports.assignRoles = require_shapeRefFns.assignRoles;
4
4
  exports.captureHint = require_shapeRefFns.captureHint;
5
5
  exports.createRef = require_shapeRefFns.createRef;
package/dist/shapeRef.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as updateRoles, i as resolveRef, n as captureHint, o as defaultScorer, r as createRef, t as assignRoles } from "./shapeRefFns-C2DbyKEO.js";
1
+ import { a as updateRoles, i as resolveRef, n as captureHint, o as defaultScorer, r as createRef, t as assignRoles } from "./shapeRefFns-BQlYDeCD.js";
2
2
  export { assignRoles, captureHint, createRef, defaultScorer, resolveRef, updateRoles };