brepjs 8.4.0 → 8.7.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 (114) hide show
  1. package/dist/2d.cjs +2 -2
  2. package/dist/2d.js +13 -13
  3. package/dist/{Blueprint-zgFe_5Qj.cjs → Blueprint-BcbOBF-9.cjs} +11 -99
  4. package/dist/{Blueprint-Bp45tnh0.js → Blueprint-Cmh8lKc4.js} +29 -117
  5. package/dist/{boolean2D-CfEbRMPF.cjs → boolean2D-CqacqjME.cjs} +24 -25
  6. package/dist/{boolean2D-DN6ETTCq.js → boolean2D-D94Axs3i.js} +23 -24
  7. package/dist/{booleanFns-C-M6qqvB.js → booleanFns-DdjtpcM6.js} +306 -12
  8. package/dist/{booleanFns-5dDG0jpA.cjs → booleanFns-NtKxkiXn.cjs} +299 -5
  9. package/dist/brepjs.cjs +1619 -71
  10. package/dist/brepjs.js +1880 -333
  11. package/dist/core/errors.d.ts +18 -0
  12. package/dist/core/errors.d.ts.map +1 -1
  13. package/dist/core.cjs +4 -4
  14. package/dist/core.js +4 -4
  15. package/dist/{cornerFinder-CC_MunIh.js → cornerFinder-BBOYfsXl.js} +1 -1
  16. package/dist/{cornerFinder-BQ-_VJx0.cjs → cornerFinder-Bqy8Lw2p.cjs} +1 -1
  17. package/dist/{curveFns-ZuQUBZvd.js → curveFns-B85Glnfo.js} +19 -17
  18. package/dist/{curveFns-VMxgfkqw.cjs → curveFns-BXCbASW-.cjs} +6 -4
  19. package/dist/{drawFns-BbhX1IUq.js → drawFns-B-gJ2WUc.js} +47 -21
  20. package/dist/{drawFns-CKaHgGSK.cjs → drawFns-CAmFEqd1.cjs} +63 -37
  21. package/dist/{errors-CSYOlCCR.js → errors-Coh_5_19.js} +26 -1
  22. package/dist/{errors-D13q2HCk.cjs → errors-eRQu29oc.cjs} +26 -1
  23. package/dist/{faceFns-CfJIbHY3.js → faceFns-CltrEfOo.js} +109 -12
  24. package/dist/{faceFns-es3GENII.cjs → faceFns-DcndPHWm.cjs} +103 -6
  25. package/dist/{helpers-C0q_FVxq.cjs → helpers-CC21GeAr.cjs} +8 -9
  26. package/dist/{helpers-CmVkMubc.js → helpers-SksQIreB.js} +16 -17
  27. package/dist/index.d.ts +18 -3
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/io/dxfImportFns.d.ts +17 -0
  30. package/dist/io/dxfImportFns.d.ts.map +1 -0
  31. package/dist/io/objImportFns.d.ts +19 -0
  32. package/dist/io/objImportFns.d.ts.map +1 -0
  33. package/dist/io/threemfImportFns.d.ts +19 -0
  34. package/dist/io/threemfImportFns.d.ts.map +1 -0
  35. package/dist/io.cjs +5 -5
  36. package/dist/io.js +5 -5
  37. package/dist/kernel/hullOps.d.ts +1 -0
  38. package/dist/kernel/hullOps.d.ts.map +1 -1
  39. package/dist/kernel/occtAdapter.d.ts +5 -0
  40. package/dist/kernel/occtAdapter.d.ts.map +1 -1
  41. package/dist/kernel/solverAdapter.d.ts +39 -0
  42. package/dist/kernel/solverAdapter.d.ts.map +1 -0
  43. package/dist/kernel/types.d.ts +5 -0
  44. package/dist/kernel/types.d.ts.map +1 -1
  45. package/dist/{loft-B-UCPW9P.cjs → loft-BcyyvWCj.cjs} +28 -28
  46. package/dist/{loft-oJq2OD3A.js → loft-CJMPx1NQ.js} +16 -16
  47. package/dist/{measurement-Cf_SoIiR.js → measurement-ByOztLxb.js} +3 -3
  48. package/dist/{measurement-CYmT-C77.cjs → measurement-DU3ry-0Q.cjs} +3 -3
  49. package/dist/measurement.cjs +1 -1
  50. package/dist/measurement.js +1 -1
  51. package/dist/{meshFns-CqNwW0PO.js → meshFns-D2gLyLFt.js} +3 -3
  52. package/dist/{meshFns-DDC_2U81.cjs → meshFns-DawUwI3W.cjs} +3 -3
  53. package/dist/{occtBoundary-D_gjqgzo.js → occtBoundary-CWzWqBCm.js} +17 -5
  54. package/dist/{occtBoundary-CocN2VKx.cjs → occtBoundary-DH2VO-rq.cjs} +12 -0
  55. package/dist/operations/assemblyFns.d.ts +1 -0
  56. package/dist/operations/assemblyFns.d.ts.map +1 -1
  57. package/dist/operations/guidedSweepFns.d.ts +25 -0
  58. package/dist/operations/guidedSweepFns.d.ts.map +1 -0
  59. package/dist/operations/mateFns.d.ts +50 -0
  60. package/dist/operations/mateFns.d.ts.map +1 -0
  61. package/dist/operations/multiSweepFns.d.ts +32 -0
  62. package/dist/operations/multiSweepFns.d.ts.map +1 -0
  63. package/dist/operations/roofFns.d.ts +16 -0
  64. package/dist/operations/roofFns.d.ts.map +1 -0
  65. package/dist/operations/straightSkeleton.d.ts +28 -0
  66. package/dist/operations/straightSkeleton.d.ts.map +1 -0
  67. package/dist/{operations-BQeW_DSM.cjs → operations-CdELWxgv.cjs} +7 -7
  68. package/dist/{operations-6hdpuYmY.js → operations-DiXo_4t9.js} +15 -15
  69. package/dist/operations.cjs +2 -2
  70. package/dist/operations.js +13 -13
  71. package/dist/query.cjs +5 -5
  72. package/dist/query.js +7 -7
  73. package/dist/result.cjs +1 -1
  74. package/dist/result.js +1 -1
  75. package/dist/{shapeFns-B0zSdO9c.cjs → shapeFns-3RYtsUVY.cjs} +54 -21
  76. package/dist/{shapeFns-k1YHFwmB.js → shapeFns-4ioRrhih.js} +52 -19
  77. package/dist/{shapeTypes-BxVxLdiD.cjs → shapeTypes-CMjrTv36.cjs} +1 -1
  78. package/dist/{shapeTypes-c-_pgYCx.js → shapeTypes-D0vfRxWb.js} +13 -13
  79. package/dist/sketching.cjs +2 -2
  80. package/dist/sketching.js +2 -2
  81. package/dist/{curveBuilders-BREwqvuc.js → surfaceBuilders-B7Jxob8g.js} +106 -13
  82. package/dist/{curveBuilders-BkEJ-RVn.cjs → surfaceBuilders-Xx9DRRxs.cjs} +96 -3
  83. package/dist/text/textBlueprints.d.ts +38 -0
  84. package/dist/text/textBlueprints.d.ts.map +1 -1
  85. package/dist/topology/api.d.ts +5 -0
  86. package/dist/topology/api.d.ts.map +1 -1
  87. package/dist/topology/booleanFns.d.ts +10 -1
  88. package/dist/topology/booleanFns.d.ts.map +1 -1
  89. package/dist/topology/colorFns.d.ts +38 -0
  90. package/dist/topology/colorFns.d.ts.map +1 -0
  91. package/dist/topology/curveFns.d.ts +1 -1
  92. package/dist/topology/curveFns.d.ts.map +1 -1
  93. package/dist/topology/faceTagFns.d.ts +44 -0
  94. package/dist/topology/faceTagFns.d.ts.map +1 -0
  95. package/dist/topology/modifierFns.d.ts.map +1 -1
  96. package/dist/topology/polyhedronFns.d.ts +8 -0
  97. package/dist/topology/polyhedronFns.d.ts.map +1 -0
  98. package/dist/topology/shapeFns.d.ts +4 -0
  99. package/dist/topology/shapeFns.d.ts.map +1 -1
  100. package/dist/topology/surfaceBuilders.d.ts +7 -0
  101. package/dist/topology/surfaceBuilders.d.ts.map +1 -1
  102. package/dist/topology/surfaceFns.d.ts +38 -0
  103. package/dist/topology/surfaceFns.d.ts.map +1 -0
  104. package/dist/{topology-CycEc6Oe.cjs → topology-D-nGjCzV.cjs} +19 -20
  105. package/dist/{topology-tMKHJgw2.js → topology-DRP9zreU.js} +8 -9
  106. package/dist/topology.cjs +13 -14
  107. package/dist/topology.js +51 -52
  108. package/dist/{vectors-DE0XriuQ.js → vectors-CZV4ZrTz.js} +2 -2
  109. package/dist/{vectors-DVmHF4zt.cjs → vectors-DwFeX0Ja.cjs} +2 -2
  110. package/dist/vectors.cjs +2 -2
  111. package/dist/vectors.js +2 -2
  112. package/package.json +4 -3
  113. package/dist/cast-CPNOTNFm.cjs +0 -102
  114. package/dist/cast-Cerqtxtb.js +0 -103
package/dist/brepjs.cjs CHANGED
@@ -1,30 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const occtBoundary = require("./occtBoundary-CocN2VKx.cjs");
4
- const errors = require("./errors-D13q2HCk.cjs");
5
- const shapeTypes = require("./shapeTypes-BxVxLdiD.cjs");
3
+ const occtBoundary = require("./occtBoundary-DH2VO-rq.cjs");
4
+ const errors = require("./errors-eRQu29oc.cjs");
5
+ const shapeTypes = require("./shapeTypes-CMjrTv36.cjs");
6
6
  const vecOps = require("./vecOps-CjRL1jau.cjs");
7
- const Blueprint = require("./Blueprint-zgFe_5Qj.cjs");
8
- const curveFns = require("./curveFns-VMxgfkqw.cjs");
9
- const loft$2 = require("./loft-B-UCPW9P.cjs");
10
- const operations = require("./operations-BQeW_DSM.cjs");
11
- const boolean2D = require("./boolean2D-CfEbRMPF.cjs");
7
+ const Blueprint = require("./Blueprint-BcbOBF-9.cjs");
8
+ const curveFns = require("./curveFns-BXCbASW-.cjs");
9
+ const loft$2 = require("./loft-BcyyvWCj.cjs");
10
+ const operations = require("./operations-CdELWxgv.cjs");
11
+ const boolean2D = require("./boolean2D-CqacqjME.cjs");
12
12
  const _2d = require("./2d.cjs");
13
- const helpers = require("./helpers-C0q_FVxq.cjs");
13
+ const helpers = require("./helpers-CC21GeAr.cjs");
14
14
  const io = require("./io.cjs");
15
- const drawFns = require("./drawFns-CKaHgGSK.cjs");
16
- const vectors = require("./vectors-DVmHF4zt.cjs");
17
- const shapeFns = require("./shapeFns-B0zSdO9c.cjs");
18
- const topology = require("./topology-CycEc6Oe.cjs");
19
- const faceFns = require("./faceFns-es3GENII.cjs");
20
- const meshFns = require("./meshFns-DDC_2U81.cjs");
21
- const booleanFns = require("./booleanFns-5dDG0jpA.cjs");
22
- const measurement = require("./measurement-CYmT-C77.cjs");
23
- const curveBuilders = require("./curveBuilders-BkEJ-RVn.cjs");
24
- const cast = require("./cast-CPNOTNFm.cjs");
15
+ const drawFns = require("./drawFns-CAmFEqd1.cjs");
16
+ const vectors = require("./vectors-DwFeX0Ja.cjs");
17
+ const shapeFns = require("./shapeFns-3RYtsUVY.cjs");
18
+ const booleanFns = require("./booleanFns-NtKxkiXn.cjs");
19
+ const topology = require("./topology-D-nGjCzV.cjs");
20
+ const faceFns = require("./faceFns-DcndPHWm.cjs");
21
+ const meshFns = require("./meshFns-DawUwI3W.cjs");
22
+ const measurement = require("./measurement-DU3ry-0Q.cjs");
23
+ const surfaceBuilders = require("./surfaceBuilders-Xx9DRRxs.cjs");
25
24
  const query = require("./query.cjs");
26
25
  const result = require("./result.cjs");
27
- const cornerFinder = require("./cornerFinder-BQ-_VJx0.cjs");
26
+ const cornerFinder = require("./cornerFinder-Bqy8Lw2p.cjs");
28
27
  const worker = require("./worker.cjs");
29
28
  const errorFactories = {
30
29
  OCCT_OPERATION: (code, message, cause) => ({ kind: "OCCT_OPERATION", code, message, cause }),
@@ -82,7 +81,7 @@ function buildWireFinder(filters) {
82
81
  isOpen: () => withFilter((wire2) => !curveFns.curveIsClosed(wire2)),
83
82
  ofEdgeCount: (count) => withFilter((wire2) => {
84
83
  let edgeCount = 0;
85
- for (const _raw of cast.iterTopo(wire2.wrapped, "edge")) {
84
+ for (const _raw of faceFns.iterTopo(wire2.wrapped, "edge")) {
86
85
  edgeCount++;
87
86
  }
88
87
  return edgeCount === count;
@@ -145,6 +144,261 @@ function buildVertexFinder(filters) {
145
144
  function vertexFinder() {
146
145
  return buildVertexFinder([]);
147
146
  }
147
+ function surfaceFromGrid(heights, options = {}) {
148
+ if (heights.length < 2) {
149
+ return errors.err(
150
+ errors.validationError(
151
+ errors.BrepErrorCode.SURFACE_GRID_TOO_SMALL,
152
+ `surfaceFromGrid: need at least 2 rows, got ${heights.length}`
153
+ )
154
+ );
155
+ }
156
+ const rows = heights.length;
157
+ const cols = heights[0]?.length ?? 0;
158
+ if (cols < 2) {
159
+ return errors.err(
160
+ errors.validationError(
161
+ errors.BrepErrorCode.SURFACE_GRID_TOO_SMALL,
162
+ `surfaceFromGrid: need at least 2 columns, got ${cols}`
163
+ )
164
+ );
165
+ }
166
+ for (let r = 0; r < rows; r++) {
167
+ const row = heights[r];
168
+ if (!row || row.length !== cols) {
169
+ return errors.err(
170
+ errors.validationError(
171
+ errors.BrepErrorCode.SURFACE_GRID_JAGGED,
172
+ `surfaceFromGrid: row ${r} has ${row?.length ?? 0} columns, expected ${cols}`
173
+ )
174
+ );
175
+ }
176
+ }
177
+ const { width = cols - 1, depth = rows - 1, scaleZ = 1 } = options;
178
+ const dx = width / (cols - 1);
179
+ const dy = depth / (rows - 1);
180
+ try {
181
+ return buildBSplineSurface(heights, rows, cols, dx, dy, scaleZ);
182
+ } catch {
183
+ }
184
+ try {
185
+ return buildTriangulatedSurface(heights, rows, cols, dx, dy, scaleZ);
186
+ } catch (e) {
187
+ const raw = e instanceof Error ? e.message : String(e);
188
+ return errors.err(errors.occtError(errors.BrepErrorCode.SURFACE_FAILED, `surfaceFromGrid failed: ${raw}`, e));
189
+ }
190
+ }
191
+ function buildBSplineSurface(heights, rows, cols, dx, dy, scaleZ) {
192
+ const oc = occtBoundary.getKernel().oc;
193
+ const OC = oc;
194
+ const pntArray = new OC.TColgp_Array2OfPnt_2(1, rows, 1, cols);
195
+ try {
196
+ for (let r = 0; r < rows; r++) {
197
+ for (let c = 0; c < cols; c++) {
198
+ const row = heights[r];
199
+ const z = (row ? row[c] ?? 0 : 0) * scaleZ;
200
+ const pnt = new oc.gp_Pnt_3(c * dx, r * dy, z);
201
+ pntArray.SetValue(r + 1, c + 1, pnt);
202
+ pnt.delete();
203
+ }
204
+ }
205
+ const fitter = new OC.GeomAPI_PointsToBSplineSurface_2(pntArray, 3, 8, 0, 1e-3);
206
+ const surface = fitter.Surface();
207
+ const faceMaker = new OC.BRepBuilderAPI_MakeFace_8(surface, 1e-6);
208
+ let result2;
209
+ if (faceMaker.IsDone()) {
210
+ const shape2 = shapeTypes.castShape(faceMaker.Face());
211
+ if (shapeTypes.isFace(shape2)) {
212
+ result2 = errors.ok(shape2);
213
+ } else {
214
+ shape2[Symbol.dispose]();
215
+ result2 = errors.err(
216
+ errors.occtError(errors.BrepErrorCode.SURFACE_FAILED, "B-spline surface did not produce a face")
217
+ );
218
+ }
219
+ } else {
220
+ result2 = errors.err(
221
+ errors.occtError(
222
+ errors.BrepErrorCode.SURFACE_FAILED,
223
+ "BRepBuilderAPI_MakeFace failed for B-spline surface"
224
+ )
225
+ );
226
+ }
227
+ faceMaker.delete();
228
+ fitter.delete();
229
+ return result2;
230
+ } finally {
231
+ pntArray.delete();
232
+ }
233
+ }
234
+ function buildTriangulatedSurface(heights, rows, cols, dx, dy, scaleZ) {
235
+ const oc = occtBoundary.getKernel().oc;
236
+ function pt(r, c) {
237
+ const row = heights[r];
238
+ const z = (row ? row[c] ?? 0 : 0) * scaleZ;
239
+ return { x: c * dx, y: r * dy, z };
240
+ }
241
+ function buildTriFace2(a, b, c) {
242
+ const gpA = new oc.gp_Pnt_3(a.x, a.y, a.z);
243
+ const gpB = new oc.gp_Pnt_3(b.x, b.y, b.z);
244
+ const gpC = new oc.gp_Pnt_3(c.x, c.y, c.z);
245
+ const e1 = new oc.BRepBuilderAPI_MakeEdge_3(gpA, gpB);
246
+ const e2 = new oc.BRepBuilderAPI_MakeEdge_3(gpB, gpC);
247
+ const e3 = new oc.BRepBuilderAPI_MakeEdge_3(gpC, gpA);
248
+ const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
249
+ wireBuilder.Add_1(e1.Edge());
250
+ wireBuilder.Add_1(e2.Edge());
251
+ wireBuilder.Add_1(e3.Edge());
252
+ let face2 = null;
253
+ if (wireBuilder.IsDone()) {
254
+ const makeFace = new oc.BRepBuilderAPI_MakeFace_15(wireBuilder.Wire(), false);
255
+ if (makeFace.IsDone()) {
256
+ face2 = makeFace.Face();
257
+ }
258
+ makeFace.delete();
259
+ }
260
+ wireBuilder.delete();
261
+ e1.delete();
262
+ e2.delete();
263
+ e3.delete();
264
+ gpA.delete();
265
+ gpB.delete();
266
+ gpC.delete();
267
+ return face2;
268
+ }
269
+ const sewing = new oc.BRepBuilderAPI_Sewing(1e-6, true, true, true, false);
270
+ let faceCount = 0;
271
+ try {
272
+ for (let r = 0; r < rows - 1; r++) {
273
+ for (let c = 0; c < cols - 1; c++) {
274
+ const p00 = pt(r, c);
275
+ const p10 = pt(r + 1, c);
276
+ const p11 = pt(r + 1, c + 1);
277
+ const p01 = pt(r, c + 1);
278
+ const f1 = buildTriFace2(p00, p10, p11);
279
+ if (f1 !== null) {
280
+ sewing.Add(f1);
281
+ faceCount++;
282
+ }
283
+ const f2 = buildTriFace2(p00, p11, p01);
284
+ if (f2 !== null) {
285
+ sewing.Add(f2);
286
+ faceCount++;
287
+ }
288
+ }
289
+ }
290
+ if (faceCount === 0) {
291
+ sewing.delete();
292
+ return errors.err(
293
+ errors.occtError(errors.BrepErrorCode.SURFACE_FAILED, "surfaceFromGrid: no valid triangular faces built")
294
+ );
295
+ }
296
+ const sewProgress = new oc.Message_ProgressRange_1();
297
+ sewing.Perform(sewProgress);
298
+ sewProgress.delete();
299
+ const sewn = sewing.SewedShape();
300
+ const shape2 = shapeTypes.castShape(sewn);
301
+ if (shapeTypes.isFace(shape2)) {
302
+ return errors.ok(shape2);
303
+ }
304
+ if (shapeTypes.isShell(shape2)) {
305
+ return errors.ok(shape2);
306
+ }
307
+ shape2[Symbol.dispose]();
308
+ return errors.err(
309
+ errors.occtError(errors.BrepErrorCode.SURFACE_FAILED, "surfaceFromGrid: unexpected shape type from sewing")
310
+ );
311
+ } finally {
312
+ sewing.delete();
313
+ }
314
+ }
315
+ async function surfaceFromImage(blob, options = {}) {
316
+ const channel = options.channel ?? "luminance";
317
+ const downsample = Math.max(1, Math.round(options.downsample ?? 1));
318
+ if (typeof createImageBitmap !== "function") {
319
+ return errors.err(
320
+ errors.ioError(
321
+ errors.BrepErrorCode.SURFACE_FAILED,
322
+ "surfaceFromImage requires createImageBitmap (not available in this environment)"
323
+ )
324
+ );
325
+ }
326
+ let bitmap;
327
+ try {
328
+ bitmap = await createImageBitmap(blob);
329
+ } catch (e) {
330
+ return errors.err(
331
+ errors.ioError(
332
+ errors.BrepErrorCode.SURFACE_FAILED,
333
+ `surfaceFromImage: failed to decode image — ${e instanceof Error ? e.message : String(e)}`
334
+ )
335
+ );
336
+ }
337
+ const w = bitmap.width;
338
+ const h = bitmap.height;
339
+ if (w < 2 || h < 2) {
340
+ bitmap.close();
341
+ return errors.err(
342
+ errors.validationError(
343
+ errors.BrepErrorCode.SURFACE_GRID_TOO_SMALL,
344
+ `surfaceFromImage: image too small (${w}x${h}), need at least 2x2`
345
+ )
346
+ );
347
+ }
348
+ if (typeof OffscreenCanvas !== "function") {
349
+ bitmap.close();
350
+ return errors.err(
351
+ errors.ioError(
352
+ errors.BrepErrorCode.SURFACE_FAILED,
353
+ "surfaceFromImage requires OffscreenCanvas (not available in this environment)"
354
+ )
355
+ );
356
+ }
357
+ const canvas = new OffscreenCanvas(w, h);
358
+ const ctx = canvas.getContext("2d");
359
+ if (!ctx) {
360
+ bitmap.close();
361
+ return errors.err(
362
+ errors.ioError(errors.BrepErrorCode.SURFACE_FAILED, "surfaceFromImage: could not get 2D canvas context")
363
+ );
364
+ }
365
+ ctx.drawImage(bitmap, 0, 0);
366
+ bitmap.close();
367
+ const imageData = ctx.getImageData(0, 0, w, h);
368
+ const data = imageData.data;
369
+ const rows = [];
370
+ for (let y = 0; y < h; y += downsample) {
371
+ const row = [];
372
+ for (let x = 0; x < w; x += downsample) {
373
+ const idx = (y * w + x) * 4;
374
+ const r = data[idx] ?? 0;
375
+ const g = data[idx + 1] ?? 0;
376
+ const b = data[idx + 2] ?? 0;
377
+ let value;
378
+ switch (channel) {
379
+ case "r":
380
+ value = r / 255;
381
+ break;
382
+ case "g":
383
+ value = g / 255;
384
+ break;
385
+ case "b":
386
+ value = b / 255;
387
+ break;
388
+ default:
389
+ value = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
390
+ break;
391
+ }
392
+ row.push(value);
393
+ }
394
+ rows.push(row);
395
+ }
396
+ const gridOpts = {};
397
+ if (options.width !== void 0) gridOpts.width = options.width;
398
+ if (options.depth !== void 0) gridOpts.depth = options.depth;
399
+ if (options.scaleZ !== void 0) gridOpts.scaleZ = options.scaleZ;
400
+ return surfaceFromGrid(rows, gridOpts);
401
+ }
148
402
  function validateNotNull$1(shape2, label) {
149
403
  if (shape2.wrapped.IsNull()) {
150
404
  return errors.err(errors.validationError(errors.BrepErrorCode.NULL_SHAPE_INPUT, `${label} is a null shape`));
@@ -172,13 +426,13 @@ function hull(shapes, options = {}) {
172
426
  const kernel = occtBoundary.getKernel();
173
427
  const ocShapes = shapes.map((s) => s.wrapped);
174
428
  const resultOc = kernel.hull(ocShapes, tolerance);
175
- const cast2 = shapeTypes.castShape(resultOc);
176
- if (!shapeTypes.isSolid(cast2)) {
429
+ const cast = shapeTypes.castShape(resultOc);
430
+ if (!shapeTypes.isSolid(cast)) {
177
431
  return errors.err(
178
432
  errors.occtError(errors.BrepErrorCode.HULL_NOT_3D, "Hull result is not a solid; input may be degenerate")
179
433
  );
180
434
  }
181
- return errors.ok(cast2);
435
+ return errors.ok(cast);
182
436
  } catch (e) {
183
437
  const raw = e instanceof Error ? e.message : String(e);
184
438
  if (raw.includes("coplanar") || raw.includes("fewer than") || raw.includes("degenerate")) {
@@ -309,6 +563,809 @@ function minkowski(shape2, tool, options = {}) {
309
563
  }
310
564
  return minkowskiGeneral(shape2, tool, tolerance);
311
565
  }
566
+ function polyhedron(points, faces, options = {}) {
567
+ const { tolerance = 1e-6 } = options;
568
+ if (points.length < 4) {
569
+ return errors.err(
570
+ errors.validationError(
571
+ errors.BrepErrorCode.POLYHEDRON_INSUFFICIENT_POINTS,
572
+ `polyhedron: need at least 4 points, got ${points.length}`
573
+ )
574
+ );
575
+ }
576
+ if (faces.length < 4) {
577
+ return errors.err(
578
+ errors.validationError(
579
+ errors.BrepErrorCode.POLYHEDRON_INSUFFICIENT_FACES,
580
+ `polyhedron: need at least 4 faces, got ${faces.length}`
581
+ )
582
+ );
583
+ }
584
+ const triangles = [];
585
+ for (const [fi, face2] of faces.entries()) {
586
+ for (const idx of face2) {
587
+ if (idx < 0 || idx >= points.length) {
588
+ return errors.err(
589
+ errors.validationError(
590
+ errors.BrepErrorCode.POLYHEDRON_INVALID_INDEX,
591
+ `polyhedron: face ${fi} has out-of-range index ${idx} (${points.length} points)`
592
+ )
593
+ );
594
+ }
595
+ }
596
+ if (face2.length < 3) continue;
597
+ const v0 = face2[0];
598
+ for (let i = 1; i < face2.length - 1; i++) {
599
+ triangles.push([v0, face2[i], face2[i + 1]]);
600
+ }
601
+ }
602
+ try {
603
+ const kernel = occtBoundary.getKernel();
604
+ const ptObjs = points.map(([x, y, z]) => ({ x, y, z }));
605
+ const resultOc = kernel.buildSolidFromFaces(ptObjs, triangles, tolerance);
606
+ const cast = shapeTypes.castShape(resultOc);
607
+ if (!shapeTypes.isSolid(cast)) {
608
+ cast[Symbol.dispose]();
609
+ return errors.err(errors.occtError(errors.BrepErrorCode.POLYHEDRON_FAILED, "Polyhedron did not produce a solid"));
610
+ }
611
+ return errors.ok(cast);
612
+ } catch (e) {
613
+ const raw = e instanceof Error ? e.message : String(e);
614
+ return errors.err(errors.occtError(errors.BrepErrorCode.POLYHEDRON_FAILED, `Polyhedron failed: ${raw}`, e));
615
+ }
616
+ }
617
+ function multiSectionSweep(sections, spine, options) {
618
+ if (sections.length < 2) {
619
+ return errors.err(
620
+ errors.validationError(
621
+ errors.BrepErrorCode.MULTI_SWEEP_INSUFFICIENT_SECTIONS,
622
+ `Multi-section sweep requires at least 2 sections, got ${sections.length}`
623
+ )
624
+ );
625
+ }
626
+ const { solid: solid2 = true, ruled = false, tolerance = 1e-6 } = options ?? {};
627
+ try {
628
+ const oc = occtBoundary.getKernel().oc;
629
+ const r = shapeTypes.gcWithScope();
630
+ const adaptor = r(new oc.BRepAdaptor_CompCurve_2(spine.wrapped, false));
631
+ const uFirst = Number(adaptor.FirstParameter());
632
+ const uLast = Number(adaptor.LastParameter());
633
+ const uRange = uLast - uFirst;
634
+ const params = sections.map((s, i) => {
635
+ if (s.location !== void 0) {
636
+ return uFirst + s.location * uRange;
637
+ }
638
+ return uFirst + i / (sections.length - 1) * uRange;
639
+ });
640
+ const builder = r(new oc.BRepOffsetAPI_ThruSections(solid2, ruled, tolerance));
641
+ for (let i = 0; i < sections.length; i++) {
642
+ const param = params[i];
643
+ const section2 = sections[i];
644
+ if (param === void 0 || section2 === void 0) continue;
645
+ const pnt = r(new oc.gp_Pnt_1());
646
+ const tangent = r(new oc.gp_Vec_1());
647
+ adaptor.D1(param, pnt, tangent);
648
+ const tangentDir = r(new oc.gp_Dir_2(tangent));
649
+ const toAx3 = r(new oc.gp_Ax3_4(pnt, tangentDir));
650
+ const trsf = r(new oc.gp_Trsf_1());
651
+ trsf.SetTransformation_2(toAx3);
652
+ trsf.Invert();
653
+ const transformer = r(new oc.BRepBuilderAPI_Transform_2(section2.wire.wrapped, trsf, true));
654
+ const transformedShape = transformer.Shape();
655
+ const transformedWire = oc.TopoDS.Wire_1(transformedShape);
656
+ builder.AddWire(transformedWire);
657
+ }
658
+ const progress = r(new oc.Message_ProgressRange_1());
659
+ builder.Build(progress);
660
+ if (!builder.IsDone()) {
661
+ return errors.err(errors.occtError(errors.BrepErrorCode.MULTI_SWEEP_FAILED, "Multi-section sweep build failed"));
662
+ }
663
+ const result2 = shapeTypes.castShape(builder.Shape());
664
+ if (!shapeTypes.isShape3D(result2)) {
665
+ return errors.err(
666
+ errors.typeCastError("MULTI_SWEEP_NOT_3D", "Multi-section sweep did not produce a 3D shape")
667
+ );
668
+ }
669
+ return errors.ok(result2);
670
+ } catch (e) {
671
+ const raw = e instanceof Error ? e.message : String(e);
672
+ return errors.err(
673
+ errors.occtError(errors.BrepErrorCode.MULTI_SWEEP_FAILED, `Multi-section sweep failed: ${raw}`, e)
674
+ );
675
+ }
676
+ }
677
+ function guidedSweep(profile, spine, guides, options = {}) {
678
+ const { transition = "transformed", solid: solid2 = true, tolerance } = options;
679
+ try {
680
+ const oc = occtBoundary.getKernel().oc;
681
+ const r = shapeTypes.gcWithScope();
682
+ const builder = r(new oc.BRepOffsetAPI_MakePipeShell(spine.wrapped));
683
+ const modeMap = {
684
+ transformed: oc.BRepBuilderAPI_TransitionMode.BRepBuilderAPI_Transformed,
685
+ round: oc.BRepBuilderAPI_TransitionMode.BRepBuilderAPI_RoundCorner,
686
+ right: oc.BRepBuilderAPI_TransitionMode.BRepBuilderAPI_RightCorner
687
+ };
688
+ builder.SetTransitionMode(modeMap[transition]);
689
+ if (tolerance !== void 0) {
690
+ builder.SetTolerance(tolerance, tolerance, 1e-7);
691
+ }
692
+ if (guides.length > 0) {
693
+ const firstGuide = guides[0];
694
+ builder.SetMode_5(firstGuide.wrapped, false, oc.BRepFill_TypeOfContact.BRepFill_NoContact);
695
+ }
696
+ builder.Add_1(profile.wrapped, false, false);
697
+ const progress = r(new oc.Message_ProgressRange_1());
698
+ builder.Build(progress);
699
+ if (!builder.IsDone()) {
700
+ return errors.err(errors.occtError(errors.BrepErrorCode.GUIDED_SWEEP_FAILED, "Guided sweep build failed"));
701
+ }
702
+ if (solid2) {
703
+ builder.MakeSolid();
704
+ }
705
+ const result2 = shapeTypes.castShape(builder.Shape());
706
+ if (!shapeTypes.isShape3D(result2)) {
707
+ return errors.err(errors.typeCastError("GUIDED_SWEEP_NOT_3D", "Guided sweep did not produce a 3D shape"));
708
+ }
709
+ return errors.ok(result2);
710
+ } catch (e) {
711
+ const raw = e instanceof Error ? e.message : String(e);
712
+ return errors.err(errors.occtError(errors.BrepErrorCode.GUIDED_SWEEP_FAILED, `Guided sweep failed: ${raw}`, e));
713
+ }
714
+ }
715
+ const EPS = 1e-10;
716
+ function cross2(ax, ay, bx, by) {
717
+ return ax * by - ay * bx;
718
+ }
719
+ function dot2(ax, ay, bx, by) {
720
+ return ax * bx + ay * by;
721
+ }
722
+ function len2(x, y) {
723
+ return Math.sqrt(x * x + y * y);
724
+ }
725
+ function polyAt(poly, i) {
726
+ const p = poly[(i % poly.length + poly.length) % poly.length];
727
+ if (!p) throw new Error(`Invalid polygon index ${i} for length ${poly.length}`);
728
+ return p;
729
+ }
730
+ function ensureCCW(poly) {
731
+ let area = 0;
732
+ for (let i = 0; i < poly.length; i++) {
733
+ const cur = polyAt(poly, i);
734
+ const nxt = polyAt(poly, i + 1);
735
+ area += cur.x * nxt.y - nxt.x * cur.y;
736
+ }
737
+ if (area < 0) return [...poly].reverse();
738
+ return poly;
739
+ }
740
+ function bisector(poly, i) {
741
+ const prev = polyAt(poly, i - 1);
742
+ const cur = polyAt(poly, i);
743
+ const next = polyAt(poly, i + 1);
744
+ const e1x = cur.x - prev.x;
745
+ const e1y = cur.y - prev.y;
746
+ const e1l = len2(e1x, e1y);
747
+ const e2x = next.x - cur.x;
748
+ const e2y = next.y - cur.y;
749
+ const e2l = len2(e2x, e2y);
750
+ if (e1l < EPS || e2l < EPS) return { dx: 0, dy: 0 };
751
+ const n1x = -e1y / e1l;
752
+ const n1y = e1x / e1l;
753
+ const n2x = -e2y / e2l;
754
+ const n2y = e2x / e2l;
755
+ let bx = n1x + n2x;
756
+ let by = n1y + n2y;
757
+ const bl = len2(bx, by);
758
+ if (bl < EPS) {
759
+ return { dx: n1x, dy: n1y };
760
+ }
761
+ bx /= bl;
762
+ by /= bl;
763
+ const cosHalf = dot2(bx, by, n1x, n1y);
764
+ const speed = Math.abs(cosHalf) > EPS ? 1 / cosHalf : 1;
765
+ return { dx: bx * speed, dy: by * speed };
766
+ }
767
+ function isLavNodeReflex(node) {
768
+ const prev = node.prev;
769
+ const next = node.next;
770
+ return cross2(node.x - prev.x, node.y - prev.y, next.x - node.x, next.y - node.y) < -EPS;
771
+ }
772
+ function createLav(poly) {
773
+ const nodes = poly.map((p, i) => {
774
+ const b = bisector(poly, i);
775
+ return {
776
+ x: p.x,
777
+ y: p.y,
778
+ bx: b.dx,
779
+ by: b.dy,
780
+ origIdx: i,
781
+ prev: null,
782
+ next: null,
783
+ active: true
784
+ };
785
+ });
786
+ for (let i = 0; i < nodes.length; i++) {
787
+ const node = nodes[i];
788
+ const prevNode = nodes[(i - 1 + nodes.length) % nodes.length];
789
+ const nextNode = nodes[(i + 1) % nodes.length];
790
+ if (node && prevNode && nextNode) {
791
+ node.prev = prevNode;
792
+ node.next = nextNode;
793
+ }
794
+ }
795
+ return nodes;
796
+ }
797
+ function lavSize(start) {
798
+ let count = 1;
799
+ let cur = start.next;
800
+ while (cur !== start) {
801
+ count++;
802
+ cur = cur.next;
803
+ if (count > 1e4) break;
804
+ }
805
+ return count;
806
+ }
807
+ function bisectorIntersectTime(a, b) {
808
+ const ddx = a.bx - b.bx;
809
+ const ddy = a.by - b.by;
810
+ const dxp = b.x - a.x;
811
+ const dyp = b.y - a.y;
812
+ if (Math.abs(ddx) < EPS && Math.abs(ddy) < EPS) return null;
813
+ let t;
814
+ if (Math.abs(ddx) > Math.abs(ddy)) {
815
+ t = dxp / ddx;
816
+ } else {
817
+ t = dyp / ddy;
818
+ }
819
+ if (t < EPS) return null;
820
+ const otherDd = Math.abs(ddx) > Math.abs(ddy) ? ddy : ddx;
821
+ const otherDp = Math.abs(ddx) > Math.abs(ddy) ? dyp : dxp;
822
+ if (Math.abs(otherDd) > EPS) {
823
+ const t2 = otherDp / otherDd;
824
+ if (Math.abs(t - t2) > 1e-4 * Math.max(1, Math.abs(t))) return null;
825
+ }
826
+ return t;
827
+ }
828
+ function raySplitTime(node, eA, eB) {
829
+ const edx = eB.x - eA.x;
830
+ const edy = eB.y - eA.y;
831
+ const el = len2(edx, edy);
832
+ if (el < EPS) return null;
833
+ const enx = -edy / el;
834
+ const eny = edx / el;
835
+ const d0 = (node.x - eA.x) * enx + (node.y - eA.y) * eny;
836
+ const relBx = node.bx - (eA.bx + eB.bx) / 2;
837
+ const relBy = node.by - (eA.by + eB.by) / 2;
838
+ const dRate = relBx * enx + relBy * eny;
839
+ if (Math.abs(dRate) < EPS) return null;
840
+ const t = -d0 / dRate;
841
+ if (t < EPS) return null;
842
+ const px = node.x + t * node.bx;
843
+ const py = node.y + t * node.by;
844
+ const ax = eA.x + t * eA.bx;
845
+ const ay = eA.y + t * eA.by;
846
+ const bxx = eB.x + t * eB.bx;
847
+ const byy = eB.y + t * eB.by;
848
+ const segDx = bxx - ax;
849
+ const segDy = byy - ay;
850
+ const segL = len2(segDx, segDy);
851
+ if (segL < EPS) return t;
852
+ const s = dot2(px - ax, py - ay, segDx, segDy) / (segL * segL);
853
+ if (s < -0.01 || s > 1.01) return null;
854
+ return t;
855
+ }
856
+ function computeEvents(lavNodes) {
857
+ const events = [];
858
+ for (const node of lavNodes) {
859
+ if (!node.active) continue;
860
+ const t = bisectorIntersectTime(node, node.next);
861
+ if (t !== null && t > EPS) {
862
+ const x = node.x + t * node.bx;
863
+ const y = node.y + t * node.by;
864
+ events.push({ time: t, x, y, nodeA: node, nodeB: node.next, type: "edge" });
865
+ }
866
+ if (isLavNodeReflex(node)) {
867
+ let cur = node.next.next;
868
+ let count = 0;
869
+ while (cur !== node.prev && cur !== node && count < 1e3) {
870
+ const st = raySplitTime(node, cur, cur.next);
871
+ if (st !== null && st > EPS) {
872
+ const x = node.x + st * node.bx;
873
+ const y = node.y + st * node.by;
874
+ events.push({ time: st, x, y, nodeA: node, nodeB: cur, type: "split" });
875
+ }
876
+ cur = cur.next;
877
+ count++;
878
+ }
879
+ }
880
+ }
881
+ events.sort((a, b) => a.time - b.time);
882
+ return events;
883
+ }
884
+ function computeStraightSkeleton(polygon2) {
885
+ if (polygon2.length < 3) {
886
+ return { nodes: [], faces: [] };
887
+ }
888
+ const poly = ensureCCW(polygon2);
889
+ const n = poly.length;
890
+ const skeletonNodes = [];
891
+ const vertexToSkelNodes = Array.from({ length: n }, () => []);
892
+ const lavNodes = createLav(poly);
893
+ let iterations = 0;
894
+ const maxIter = n * n * 2;
895
+ while (iterations < maxIter) {
896
+ iterations++;
897
+ const activeStart = lavNodes.find((nd) => nd.active);
898
+ if (!activeStart) break;
899
+ const sz = lavSize(activeStart);
900
+ if (sz <= 3) {
901
+ if (sz === 3) {
902
+ const a = activeStart;
903
+ const b = a.next;
904
+ const c = b.next;
905
+ const t = bisectorIntersectTime(a, b);
906
+ const time = t !== null && t > EPS ? t : 0;
907
+ const mx = (a.x + b.x + c.x) / 3 + time * (a.bx + b.bx + c.bx) / 3;
908
+ const my = (a.y + b.y + c.y) / 3 + time * (a.by + b.by + c.by) / 3;
909
+ const nodeIdx = skeletonNodes.length;
910
+ skeletonNodes.push({ x: mx, y: my, height: time });
911
+ const aNodes = vertexToSkelNodes[a.origIdx];
912
+ const bNodes = vertexToSkelNodes[b.origIdx];
913
+ const cNodes = vertexToSkelNodes[c.origIdx];
914
+ if (aNodes) aNodes.push(nodeIdx);
915
+ if (bNodes) bNodes.push(nodeIdx);
916
+ if (cNodes) cNodes.push(nodeIdx);
917
+ a.active = false;
918
+ b.active = false;
919
+ c.active = false;
920
+ } else {
921
+ let cur = activeStart;
922
+ for (let i = 0; i < sz; i++) {
923
+ cur.active = false;
924
+ cur = cur.next;
925
+ }
926
+ }
927
+ continue;
928
+ }
929
+ const activeNodes = lavNodes.filter((nd) => nd.active);
930
+ const events = computeEvents(activeNodes);
931
+ if (events.length === 0) {
932
+ for (const nd of activeNodes) {
933
+ nd.active = false;
934
+ }
935
+ break;
936
+ }
937
+ const ev = events[0];
938
+ if (!ev) break;
939
+ if (ev.type === "edge") {
940
+ const a = ev.nodeA;
941
+ const b = ev.nodeB;
942
+ if (!a.active || !b.active) continue;
943
+ const nodeIdx = skeletonNodes.length;
944
+ skeletonNodes.push({ x: ev.x, y: ev.y, height: ev.time });
945
+ const aNodes = vertexToSkelNodes[a.origIdx];
946
+ const bNodes = vertexToSkelNodes[b.origIdx];
947
+ if (aNodes) aNodes.push(nodeIdx);
948
+ if (bNodes) bNodes.push(nodeIdx);
949
+ a.x = ev.x;
950
+ a.y = ev.y;
951
+ a.next = b.next;
952
+ b.next.prev = a;
953
+ b.active = false;
954
+ const lavPoly = [];
955
+ let cur = a;
956
+ do {
957
+ lavPoly.push({ x: cur.x, y: cur.y });
958
+ cur = cur.next;
959
+ } while (cur !== a);
960
+ const bDir = bisector(lavPoly, 0);
961
+ a.bx = bDir.dx;
962
+ a.by = bDir.dy;
963
+ } else {
964
+ const a = ev.nodeA;
965
+ const b = ev.nodeB;
966
+ if (!a.active || !b.active) continue;
967
+ const nodeIdx = skeletonNodes.length;
968
+ skeletonNodes.push({ x: ev.x, y: ev.y, height: ev.time });
969
+ const aNodes = vertexToSkelNodes[a.origIdx];
970
+ if (aNodes) aNodes.push(nodeIdx);
971
+ const bNodes = vertexToSkelNodes[b.origIdx];
972
+ if (bNodes) bNodes.push(nodeIdx);
973
+ const aCopy = {
974
+ x: ev.x,
975
+ y: ev.y,
976
+ bx: 0,
977
+ by: 0,
978
+ origIdx: a.origIdx,
979
+ prev: null,
980
+ next: null,
981
+ active: true
982
+ };
983
+ lavNodes.push(aCopy);
984
+ a.x = ev.x;
985
+ a.y = ev.y;
986
+ const aNext = a.next;
987
+ const bNext = b.next;
988
+ a.next = bNext;
989
+ bNext.prev = a;
990
+ aCopy.next = aNext;
991
+ aNext.prev = aCopy;
992
+ aCopy.prev = b;
993
+ b.next = aCopy;
994
+ const buildLavPoly = (start) => {
995
+ const poly2 = [];
996
+ let c = start;
997
+ do {
998
+ poly2.push({ x: c.x, y: c.y });
999
+ c = c.next;
1000
+ } while (c !== start);
1001
+ return poly2;
1002
+ };
1003
+ const lav1Poly = buildLavPoly(a);
1004
+ const bDir1 = bisector(lav1Poly, 0);
1005
+ a.bx = bDir1.dx;
1006
+ a.by = bDir1.dy;
1007
+ const lav2Poly = buildLavPoly(aCopy);
1008
+ const bDir2 = bisector(lav2Poly, 0);
1009
+ aCopy.bx = bDir2.dx;
1010
+ aCopy.by = bDir2.dy;
1011
+ }
1012
+ }
1013
+ const faces = [];
1014
+ for (let i = 0; i < n; i++) {
1015
+ const j = (i + 1) % n;
1016
+ const pi = polyAt(poly, i);
1017
+ const pj = polyAt(poly, j);
1018
+ const faceVerts = [pi, pj];
1019
+ const faceHeights = [0, 0];
1020
+ const jNodes = vertexToSkelNodes[j];
1021
+ const iNodes = vertexToSkelNodes[i];
1022
+ if (jNodes) {
1023
+ for (const ni of jNodes) {
1024
+ const sn = skeletonNodes[ni];
1025
+ if (sn) {
1026
+ faceVerts.push({ x: sn.x, y: sn.y });
1027
+ faceHeights.push(sn.height);
1028
+ }
1029
+ }
1030
+ }
1031
+ if (iNodes) {
1032
+ for (let k = iNodes.length - 1; k >= 0; k--) {
1033
+ const idx = iNodes[k];
1034
+ if (idx === void 0) continue;
1035
+ const sn = skeletonNodes[idx];
1036
+ if (!sn) continue;
1037
+ const lastVert = faceVerts[faceVerts.length - 1];
1038
+ if (!lastVert) continue;
1039
+ const dist = len2(sn.x - lastVert.x, sn.y - lastVert.y);
1040
+ if (dist > EPS) {
1041
+ faceVerts.push({ x: sn.x, y: sn.y });
1042
+ faceHeights.push(sn.height);
1043
+ }
1044
+ }
1045
+ }
1046
+ if (faceVerts.length >= 3) {
1047
+ faces.push({ vertices: faceVerts, heights: faceHeights });
1048
+ }
1049
+ }
1050
+ const uniqueNodes = [];
1051
+ for (const sn of skeletonNodes) {
1052
+ const exists = uniqueNodes.some(
1053
+ (un) => Math.abs(un.x - sn.x) < 0.01 && Math.abs(un.y - sn.y) < 0.01
1054
+ );
1055
+ if (!exists) {
1056
+ uniqueNodes.push(sn);
1057
+ }
1058
+ }
1059
+ return { nodes: uniqueNodes, faces };
1060
+ }
1061
+ function extractPolygon(w) {
1062
+ const edges = shapeFns.getEdges(w);
1063
+ const pts = edges.map((e) => {
1064
+ const pt = curveFns.curveStartPoint(e);
1065
+ return { x: pt[0], y: pt[1] };
1066
+ });
1067
+ const first = pts[0];
1068
+ const last = pts[pts.length - 1];
1069
+ if (pts.length > 1 && first && last && Math.abs(first.x - last.x) < 1e-10 && Math.abs(first.y - last.y) < 1e-10) {
1070
+ pts.pop();
1071
+ }
1072
+ return pts;
1073
+ }
1074
+ function fanTriangulate(count) {
1075
+ const tris = [];
1076
+ for (let i = 1; i < count - 1; i++) {
1077
+ tris.push([0, i, i + 1]);
1078
+ }
1079
+ return tris;
1080
+ }
1081
+ function buildTriFace$2(oc, a, b, c) {
1082
+ const gpA = new oc.gp_Pnt_3(a[0], a[1], a[2]);
1083
+ const gpB = new oc.gp_Pnt_3(b[0], b[1], b[2]);
1084
+ const gpC = new oc.gp_Pnt_3(c[0], c[1], c[2]);
1085
+ const e1 = new oc.BRepBuilderAPI_MakeEdge_3(gpA, gpB);
1086
+ const e2 = new oc.BRepBuilderAPI_MakeEdge_3(gpB, gpC);
1087
+ const e3 = new oc.BRepBuilderAPI_MakeEdge_3(gpC, gpA);
1088
+ const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
1089
+ wireBuilder.Add_1(e1.Edge());
1090
+ wireBuilder.Add_1(e2.Edge());
1091
+ wireBuilder.Add_1(e3.Edge());
1092
+ let face2 = null;
1093
+ if (wireBuilder.IsDone()) {
1094
+ const makeFace = new oc.BRepBuilderAPI_MakeFace_15(wireBuilder.Wire(), false);
1095
+ if (makeFace.IsDone()) {
1096
+ face2 = makeFace.Face();
1097
+ }
1098
+ makeFace.delete();
1099
+ }
1100
+ wireBuilder.delete();
1101
+ e1.delete();
1102
+ e2.delete();
1103
+ e3.delete();
1104
+ gpA.delete();
1105
+ gpB.delete();
1106
+ gpC.delete();
1107
+ return face2;
1108
+ }
1109
+ function roof(w, options) {
1110
+ const angle = (options?.angle ?? 45) * (Math.PI / 180);
1111
+ const tanAngle = Math.tan(angle);
1112
+ try {
1113
+ const polygon2 = extractPolygon(w);
1114
+ if (polygon2.length < 3) {
1115
+ return errors.err(
1116
+ errors.occtError(errors.BrepErrorCode.ROOF_FAILED, "Wire must have at least 3 edges for roof generation")
1117
+ );
1118
+ }
1119
+ const skeleton = computeStraightSkeleton(polygon2);
1120
+ if (skeleton.faces.length === 0) {
1121
+ return errors.err(
1122
+ errors.occtError(errors.BrepErrorCode.ROOF_FAILED, "Straight skeleton computation produced no faces")
1123
+ );
1124
+ }
1125
+ const oc = occtBoundary.getKernel().oc;
1126
+ const sewing = new oc.BRepBuilderAPI_Sewing(1e-6, true, true, true, false);
1127
+ let faceCount = 0;
1128
+ try {
1129
+ for (const skFace of skeleton.faces) {
1130
+ const verts3d = skFace.vertices.map(
1131
+ (v, i) => [
1132
+ v.x,
1133
+ v.y,
1134
+ (skFace.heights[i] ?? 0) * tanAngle
1135
+ ]
1136
+ );
1137
+ const tris = fanTriangulate(verts3d.length);
1138
+ for (const [ai, bi, ci] of tris) {
1139
+ const va = verts3d[ai];
1140
+ const vb = verts3d[bi];
1141
+ const vc = verts3d[ci];
1142
+ if (!va || !vb || !vc) continue;
1143
+ const abx = vb[0] - va[0];
1144
+ const aby = vb[1] - va[1];
1145
+ const abz = vb[2] - va[2];
1146
+ const acx = vc[0] - va[0];
1147
+ const acy = vc[1] - va[1];
1148
+ const acz = vc[2] - va[2];
1149
+ const nx = aby * acz - abz * acy;
1150
+ const ny = abz * acx - abx * acz;
1151
+ const nz = abx * acy - aby * acx;
1152
+ const areaSq = nx * nx + ny * ny + nz * nz;
1153
+ if (areaSq < 1e-20) continue;
1154
+ const triFace = buildTriFace$2(oc, va, vb, vc);
1155
+ if (triFace !== null) {
1156
+ sewing.Add(triFace);
1157
+ faceCount++;
1158
+ }
1159
+ }
1160
+ }
1161
+ const p0 = polygon2[0];
1162
+ if (p0) {
1163
+ for (let i = 1; i < polygon2.length - 1; i++) {
1164
+ const pi = polygon2[i];
1165
+ const pi1 = polygon2[i + 1];
1166
+ if (!pi || !pi1) continue;
1167
+ const va = [p0.x, p0.y, 0];
1168
+ const vb = [pi.x, pi.y, 0];
1169
+ const vc = [pi1.x, pi1.y, 0];
1170
+ const triFace = buildTriFace$2(oc, va, vc, vb);
1171
+ if (triFace !== null) {
1172
+ sewing.Add(triFace);
1173
+ faceCount++;
1174
+ }
1175
+ }
1176
+ }
1177
+ if (faceCount === 0) {
1178
+ return errors.err(
1179
+ errors.occtError(errors.BrepErrorCode.ROOF_FAILED, "No valid triangular faces could be built")
1180
+ );
1181
+ }
1182
+ const progress = new oc.Message_ProgressRange_1();
1183
+ sewing.Perform(progress);
1184
+ progress.delete();
1185
+ const sewn = sewing.SewedShape();
1186
+ const fixer = new oc.ShapeFix_Solid_1();
1187
+ try {
1188
+ const shell2 = oc.TopoDS.Shell_1(sewn);
1189
+ const solid2 = fixer.SolidFromShell(shell2);
1190
+ const shapeFixer = new oc.ShapeFix_Shape_1(solid2);
1191
+ const shapeFixProgress = new oc.Message_ProgressRange_1();
1192
+ try {
1193
+ shapeFixer.Perform(shapeFixProgress);
1194
+ const fixed = shapeFixer.Shape();
1195
+ return errors.ok(shapeTypes.createSolid(fixed));
1196
+ } finally {
1197
+ shapeFixProgress.delete();
1198
+ shapeFixer.delete();
1199
+ }
1200
+ } catch {
1201
+ return errors.ok(shapeTypes.castShape(sewn));
1202
+ } finally {
1203
+ fixer.delete();
1204
+ }
1205
+ } finally {
1206
+ sewing.delete();
1207
+ }
1208
+ } catch (e) {
1209
+ const msg = e instanceof Error ? e.message : String(e);
1210
+ return errors.err(errors.occtError(errors.BrepErrorCode.ROOF_FAILED, `Roof generation failed: ${msg}`, e));
1211
+ }
1212
+ }
1213
+ function solveConstraints(nodes, constraints) {
1214
+ const transforms = /* @__PURE__ */ new Map();
1215
+ for (const node of nodes) {
1216
+ transforms.set(node, {
1217
+ position: [0, 0, 0],
1218
+ rotation: [1, 0, 0, 0]
1219
+ });
1220
+ }
1221
+ for (const c of constraints) {
1222
+ if (c.type === "coincident" && c.entityA && c.entityB) {
1223
+ const a = c.entityA;
1224
+ const b = c.entityB;
1225
+ if (a.entity.type === "plane" && b.entity.type === "plane") {
1226
+ const aNormal = a.entity.normal ?? [0, 0, 1];
1227
+ const aOrigin = a.entity.origin;
1228
+ const bOrigin = b.entity.origin;
1229
+ const dot = aNormal[0] * (aOrigin[0] - bOrigin[0]) + aNormal[1] * (aOrigin[1] - bOrigin[1]) + aNormal[2] * (aOrigin[2] - bOrigin[2]);
1230
+ const pos = [dot * aNormal[0], dot * aNormal[1], dot * aNormal[2]];
1231
+ transforms.set(b.node, { position: pos, rotation: [1, 0, 0, 0] });
1232
+ }
1233
+ }
1234
+ if (c.type === "distance" && c.entityA && c.entityB && c.value !== void 0) {
1235
+ const a = c.entityA;
1236
+ const b = c.entityB;
1237
+ if (a.entity.type === "plane" && b.entity.type === "plane") {
1238
+ const aNormal = a.entity.normal ?? [0, 0, 1];
1239
+ const aOrigin = a.entity.origin;
1240
+ const bOrigin = b.entity.origin;
1241
+ const currentDist = aNormal[0] * (aOrigin[0] - bOrigin[0]) + aNormal[1] * (aOrigin[1] - bOrigin[1]) + aNormal[2] * (aOrigin[2] - bOrigin[2]);
1242
+ const offset2 = currentDist + c.value;
1243
+ const pos = [offset2 * aNormal[0], offset2 * aNormal[1], offset2 * aNormal[2]];
1244
+ transforms.set(b.node, { position: pos, rotation: [1, 0, 0, 0] });
1245
+ }
1246
+ }
1247
+ }
1248
+ return { transforms, dof: 0, converged: true };
1249
+ }
1250
+ function extractEntity(mate) {
1251
+ if (mate.face) {
1252
+ const origin = faceFns.faceCenter(mate.face);
1253
+ const normal = faceFns.normalAt(mate.face);
1254
+ return { type: "plane", origin, normal };
1255
+ }
1256
+ if (mate.point) {
1257
+ return { type: "point", origin: mate.point };
1258
+ }
1259
+ return null;
1260
+ }
1261
+ function addMate(assembly, constraint) {
1262
+ const existing = assembly.mates ?? [];
1263
+ return { ...assembly, mates: [...existing, constraint] };
1264
+ }
1265
+ function solveAssembly(assembly) {
1266
+ const mates = assembly.mates;
1267
+ if (!mates || mates.length === 0) {
1268
+ return errors.err(
1269
+ errors.validationError(errors.BrepErrorCode.ASSEMBLY_MATE_INVALID, "solveAssembly: no mates defined")
1270
+ );
1271
+ }
1272
+ try {
1273
+ const nodes = [];
1274
+ operations.walkAssembly(assembly, (node) => {
1275
+ nodes.push(node.name);
1276
+ });
1277
+ const solverConstraints = [];
1278
+ for (const mate of mates) {
1279
+ if (mate.type === "fixed") {
1280
+ solverConstraints.push({
1281
+ type: "fixed",
1282
+ entityA: { node: mate.entity.node, entity: { type: "point", origin: [0, 0, 0] } }
1283
+ });
1284
+ continue;
1285
+ }
1286
+ if (mate.type === "coincident") {
1287
+ const entA = extractEntity(mate.entityA);
1288
+ const entB = extractEntity(mate.entityB);
1289
+ if (!entA || !entB) {
1290
+ return errors.err(
1291
+ errors.validationError(
1292
+ errors.BrepErrorCode.ASSEMBLY_MATE_INVALID,
1293
+ "solveAssembly: could not extract geometry from mate entities"
1294
+ )
1295
+ );
1296
+ }
1297
+ solverConstraints.push({
1298
+ type: "coincident",
1299
+ entityA: { node: mate.entityA.node, entity: entA },
1300
+ entityB: { node: mate.entityB.node, entity: entB }
1301
+ });
1302
+ }
1303
+ if (mate.type === "distance") {
1304
+ const entA = extractEntity(mate.entityA);
1305
+ const entB = extractEntity(mate.entityB);
1306
+ if (!entA || !entB) {
1307
+ return errors.err(
1308
+ errors.validationError(
1309
+ errors.BrepErrorCode.ASSEMBLY_MATE_INVALID,
1310
+ "solveAssembly: could not extract geometry from mate entities"
1311
+ )
1312
+ );
1313
+ }
1314
+ solverConstraints.push({
1315
+ type: "distance",
1316
+ entityA: { node: mate.entityA.node, entity: entA },
1317
+ entityB: { node: mate.entityB.node, entity: entB },
1318
+ value: mate.distance
1319
+ });
1320
+ }
1321
+ if (mate.type === "angle") {
1322
+ const entA = extractEntity(mate.entityA);
1323
+ const entB = extractEntity(mate.entityB);
1324
+ if (!entA || !entB) {
1325
+ return errors.err(
1326
+ errors.validationError(
1327
+ errors.BrepErrorCode.ASSEMBLY_MATE_INVALID,
1328
+ "solveAssembly: could not extract geometry from mate entities"
1329
+ )
1330
+ );
1331
+ }
1332
+ solverConstraints.push({
1333
+ type: "angle",
1334
+ entityA: { node: mate.entityA.node, entity: entA },
1335
+ entityB: { node: mate.entityB.node, entity: entB },
1336
+ value: mate.angle
1337
+ });
1338
+ }
1339
+ if (mate.type === "concentric") {
1340
+ const entA = extractEntity(mate.axisA);
1341
+ const entB = extractEntity(mate.axisB);
1342
+ if (!entA || !entB) {
1343
+ return errors.err(
1344
+ errors.validationError(
1345
+ errors.BrepErrorCode.ASSEMBLY_MATE_INVALID,
1346
+ "solveAssembly: could not extract geometry from mate entities"
1347
+ )
1348
+ );
1349
+ }
1350
+ solverConstraints.push({
1351
+ type: "concentric",
1352
+ entityA: { node: mate.axisA.node, entity: entA },
1353
+ entityB: { node: mate.axisB.node, entity: entB }
1354
+ });
1355
+ }
1356
+ }
1357
+ const result2 = solveConstraints(nodes, solverConstraints);
1358
+ if (!result2.converged) ;
1359
+ return errors.ok({
1360
+ transforms: result2.transforms,
1361
+ dof: result2.dof,
1362
+ converged: result2.converged
1363
+ });
1364
+ } catch (e) {
1365
+ const raw = e instanceof Error ? e.message : String(e);
1366
+ return errors.err(errors.occtError(errors.BrepErrorCode.ASSEMBLY_SOLVE_FAILED, `Assembly solve failed: ${raw}`, e));
1367
+ }
1368
+ }
312
1369
  function checkInterference(shape1, shape2, tolerance = 1e-6) {
313
1370
  if (shape1.wrapped.IsNull()) {
314
1371
  return errors.err(
@@ -346,6 +1403,458 @@ function checkAllInterferences(shapes, tolerance = 1e-6) {
346
1403
  });
347
1404
  return pairs;
348
1405
  }
1406
+ function parseEntities(text) {
1407
+ const lines = text.split(/\r?\n/);
1408
+ const entities = [];
1409
+ let inEntities = false;
1410
+ let current;
1411
+ for (let i = 0; i < lines.length - 1; i += 2) {
1412
+ const codeLine = lines[i];
1413
+ const valueLine = lines[i + 1];
1414
+ if (codeLine === void 0 || valueLine === void 0) continue;
1415
+ const code = parseInt(codeLine.trim(), 10);
1416
+ const value = valueLine.trim();
1417
+ if (isNaN(code)) continue;
1418
+ if (code === 2 && value === "ENTITIES") {
1419
+ inEntities = true;
1420
+ continue;
1421
+ }
1422
+ if (!inEntities) continue;
1423
+ if (code === 0) {
1424
+ if (value === "ENDSEC" || value === "EOF") {
1425
+ if (current) entities.push(current);
1426
+ break;
1427
+ }
1428
+ if (current) entities.push(current);
1429
+ current = { type: value, layer: "0", data: /* @__PURE__ */ new Map() };
1430
+ continue;
1431
+ }
1432
+ if (current) {
1433
+ if (code === 8) {
1434
+ current.layer = value;
1435
+ } else {
1436
+ current.data.set(code, value);
1437
+ }
1438
+ }
1439
+ }
1440
+ return entities;
1441
+ }
1442
+ function getNum(data, code, fallback = 0) {
1443
+ const v = data.get(code);
1444
+ if (v === void 0) return fallback;
1445
+ const n = parseFloat(v);
1446
+ return isNaN(n) ? fallback : n;
1447
+ }
1448
+ function entityToEdge(entity, oc) {
1449
+ const { type, data } = entity;
1450
+ if (type === "LINE") {
1451
+ const p1 = new oc.gp_Pnt_3(getNum(data, 10), getNum(data, 20), getNum(data, 30));
1452
+ const p2 = new oc.gp_Pnt_3(getNum(data, 11), getNum(data, 21), getNum(data, 31));
1453
+ try {
1454
+ const builder = new oc.BRepBuilderAPI_MakeEdge_3(p1, p2);
1455
+ const edge = builder.Edge();
1456
+ builder.delete();
1457
+ return edge;
1458
+ } finally {
1459
+ p1.delete();
1460
+ p2.delete();
1461
+ }
1462
+ }
1463
+ if (type === "CIRCLE") {
1464
+ const cx = getNum(data, 10);
1465
+ const cy = getNum(data, 20);
1466
+ const cz = getNum(data, 30);
1467
+ const radius = getNum(data, 40);
1468
+ const center = new oc.gp_Pnt_3(cx, cy, cz);
1469
+ const dir = new oc.gp_Dir_4(0, 0, 1);
1470
+ const ax2 = new oc.gp_Ax2_3(center, dir);
1471
+ const circ = new oc.gp_Circ_2(ax2, radius);
1472
+ try {
1473
+ const builder = new oc.BRepBuilderAPI_MakeEdge_8(circ);
1474
+ const edge = builder.Edge();
1475
+ builder.delete();
1476
+ return edge;
1477
+ } finally {
1478
+ center.delete();
1479
+ dir.delete();
1480
+ ax2.delete();
1481
+ circ.delete();
1482
+ }
1483
+ }
1484
+ if (type === "ARC") {
1485
+ const cx = getNum(data, 10);
1486
+ const cy = getNum(data, 20);
1487
+ const cz = getNum(data, 30);
1488
+ const radius = getNum(data, 40);
1489
+ const startAngleDeg = getNum(data, 50);
1490
+ const endAngleDeg = getNum(data, 51);
1491
+ const startAngle = startAngleDeg * Math.PI / 180;
1492
+ const endAngle = endAngleDeg * Math.PI / 180;
1493
+ const center = new oc.gp_Pnt_3(cx, cy, cz);
1494
+ const dir = new oc.gp_Dir_4(0, 0, 1);
1495
+ const ax2 = new oc.gp_Ax2_3(center, dir);
1496
+ const circ = new oc.gp_Circ_2(ax2, radius);
1497
+ try {
1498
+ const builder = new oc.BRepBuilderAPI_MakeEdge_9(circ, startAngle, endAngle);
1499
+ const edge = builder.Edge();
1500
+ builder.delete();
1501
+ return edge;
1502
+ } finally {
1503
+ center.delete();
1504
+ dir.delete();
1505
+ ax2.delete();
1506
+ circ.delete();
1507
+ }
1508
+ }
1509
+ return void 0;
1510
+ }
1511
+ async function importDXF(blob, options) {
1512
+ const oc = occtBoundary.getKernel().oc;
1513
+ let text;
1514
+ try {
1515
+ text = await blob.text();
1516
+ } catch (cause) {
1517
+ return errors.err(errors.ioError(errors.BrepErrorCode.DXF_IMPORT_FAILED, "Failed to read DXF blob", cause));
1518
+ }
1519
+ const allEntities = parseEntities(text);
1520
+ const entities = options?.layer !== void 0 ? allEntities.filter((e) => e.layer === options.layer) : allEntities;
1521
+ if (entities.length === 0) {
1522
+ return errors.ok([]);
1523
+ }
1524
+ const edges = [];
1525
+ try {
1526
+ for (const entity of entities) {
1527
+ const edge = entityToEdge(entity, oc);
1528
+ if (edge !== void 0) {
1529
+ edges.push(edge);
1530
+ }
1531
+ }
1532
+ if (edges.length === 0) {
1533
+ return errors.ok([]);
1534
+ }
1535
+ const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
1536
+ try {
1537
+ for (const edge of edges) {
1538
+ wireBuilder.Add_1(edge);
1539
+ }
1540
+ if (wireBuilder.IsDone()) {
1541
+ const wire2 = wireBuilder.Wire();
1542
+ return errors.ok([shapeTypes.createWire(wire2)]);
1543
+ }
1544
+ return errors.err(
1545
+ errors.ioError(errors.BrepErrorCode.DXF_IMPORT_FAILED, "Failed to assemble DXF edges into a wire")
1546
+ );
1547
+ } finally {
1548
+ wireBuilder.delete();
1549
+ }
1550
+ } catch (cause) {
1551
+ return errors.err(
1552
+ errors.ioError(errors.BrepErrorCode.DXF_IMPORT_FAILED, "Failed to convert DXF entities to geometry", cause)
1553
+ );
1554
+ } finally {
1555
+ for (const edge of edges) {
1556
+ edge.delete();
1557
+ }
1558
+ }
1559
+ }
1560
+ async function importOBJ(blob) {
1561
+ const text = await blob.text();
1562
+ const lines = text.split("\n");
1563
+ const vertices = [];
1564
+ const faces = [];
1565
+ for (const raw of lines) {
1566
+ const line2 = raw.trim();
1567
+ if (line2.startsWith("v ")) {
1568
+ const parts = line2.split(/\s+/);
1569
+ const x = parseFloat(parts[1] ?? "");
1570
+ const y = parseFloat(parts[2] ?? "");
1571
+ const z = parseFloat(parts[3] ?? "");
1572
+ if (isNaN(x) || isNaN(y) || isNaN(z)) continue;
1573
+ vertices.push([x, y, z]);
1574
+ } else if (line2.startsWith("f ")) {
1575
+ const parts = line2.split(/\s+/).slice(1);
1576
+ const indices = [];
1577
+ for (const p of parts) {
1578
+ const idx = parseInt(p.split("/")[0] ?? "", 10);
1579
+ if (!isNaN(idx)) indices.push(idx);
1580
+ }
1581
+ if (indices.length >= 3) faces.push(indices);
1582
+ }
1583
+ }
1584
+ if (vertices.length === 0 || faces.length === 0) {
1585
+ return errors.err(errors.ioError(errors.BrepErrorCode.OBJ_IMPORT_FAILED, "OBJ file contains no valid geometry"));
1586
+ }
1587
+ try {
1588
+ return buildSolidFromMesh$1(vertices, faces);
1589
+ } catch (e) {
1590
+ const msg = e instanceof Error ? e.message : String(e);
1591
+ return errors.err(errors.ioError(errors.BrepErrorCode.OBJ_IMPORT_FAILED, `OBJ import failed: ${msg}`, e));
1592
+ }
1593
+ }
1594
+ function buildSolidFromMesh$1(vertices, faces) {
1595
+ const oc = occtBoundary.getKernel().oc;
1596
+ const sewing = new oc.BRepBuilderAPI_Sewing(1e-6, true, true, true, false);
1597
+ let faceCount = 0;
1598
+ try {
1599
+ for (const face2 of faces) {
1600
+ for (let i = 1; i < face2.length - 1; i++) {
1601
+ const rawA = face2[0] ?? 0;
1602
+ const rawB = face2[i] ?? 0;
1603
+ const rawC = face2[i + 1] ?? 0;
1604
+ const ai = rawA > 0 ? rawA - 1 : vertices.length + rawA;
1605
+ const bi = rawB > 0 ? rawB - 1 : vertices.length + rawB;
1606
+ const ci = rawC > 0 ? rawC - 1 : vertices.length + rawC;
1607
+ const va = vertices[ai];
1608
+ const vb = vertices[bi];
1609
+ const vc = vertices[ci];
1610
+ if (!va || !vb || !vc) continue;
1611
+ const triFace = buildTriFace$1(oc, va, vb, vc);
1612
+ if (triFace !== null) {
1613
+ sewing.Add(triFace);
1614
+ faceCount++;
1615
+ }
1616
+ }
1617
+ }
1618
+ if (faceCount === 0) {
1619
+ return errors.err(
1620
+ errors.ioError(errors.BrepErrorCode.OBJ_IMPORT_FAILED, "No valid triangular faces could be built")
1621
+ );
1622
+ }
1623
+ const progress = new oc.Message_ProgressRange_1();
1624
+ sewing.Perform(progress);
1625
+ progress.delete();
1626
+ const sewn = sewing.SewedShape();
1627
+ const fixer = new oc.ShapeFix_Solid_1();
1628
+ try {
1629
+ const shell2 = oc.TopoDS.Shell_1(sewn);
1630
+ const solid2 = fixer.SolidFromShell(shell2);
1631
+ return errors.ok(shapeTypes.castShape(solid2));
1632
+ } catch {
1633
+ return errors.ok(shapeTypes.castShape(sewn));
1634
+ } finally {
1635
+ fixer.delete();
1636
+ }
1637
+ } finally {
1638
+ sewing.delete();
1639
+ }
1640
+ }
1641
+ function buildTriFace$1(oc, a, b, c) {
1642
+ const gpA = new oc.gp_Pnt_3(a[0], a[1], a[2]);
1643
+ const gpB = new oc.gp_Pnt_3(b[0], b[1], b[2]);
1644
+ const gpC = new oc.gp_Pnt_3(c[0], c[1], c[2]);
1645
+ const e1 = new oc.BRepBuilderAPI_MakeEdge_3(gpA, gpB);
1646
+ const e2 = new oc.BRepBuilderAPI_MakeEdge_3(gpB, gpC);
1647
+ const e3 = new oc.BRepBuilderAPI_MakeEdge_3(gpC, gpA);
1648
+ const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
1649
+ wireBuilder.Add_1(e1.Edge());
1650
+ wireBuilder.Add_1(e2.Edge());
1651
+ wireBuilder.Add_1(e3.Edge());
1652
+ let face2 = null;
1653
+ if (wireBuilder.IsDone()) {
1654
+ const makeFace = new oc.BRepBuilderAPI_MakeFace_15(wireBuilder.Wire(), false);
1655
+ if (makeFace.IsDone()) {
1656
+ face2 = makeFace.Face();
1657
+ }
1658
+ makeFace.delete();
1659
+ }
1660
+ wireBuilder.delete();
1661
+ e1.delete();
1662
+ e2.delete();
1663
+ e3.delete();
1664
+ gpA.delete();
1665
+ gpB.delete();
1666
+ gpC.delete();
1667
+ return face2;
1668
+ }
1669
+ function extractFromZip(data, target) {
1670
+ let eocdOffset = -1;
1671
+ for (let i = data.length - 22; i >= 0; i--) {
1672
+ if (data[i] === 80 && data[i + 1] === 75 && data[i + 2] === 5 && data[i + 3] === 6) {
1673
+ eocdOffset = i;
1674
+ break;
1675
+ }
1676
+ }
1677
+ if (eocdOffset < 0) return null;
1678
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
1679
+ const cdOffset = view.getUint32(eocdOffset + 16, true);
1680
+ const cdSize = view.getUint32(eocdOffset + 12, true);
1681
+ const cdEnd = cdOffset + cdSize;
1682
+ let pos = cdOffset;
1683
+ const decoder = new TextDecoder();
1684
+ while (pos < cdEnd) {
1685
+ const sig = view.getUint32(pos, true);
1686
+ if (sig !== 33639248) break;
1687
+ const nameLen = view.getUint16(pos + 28, true);
1688
+ const extraLen = view.getUint16(pos + 30, true);
1689
+ const commentLen = view.getUint16(pos + 32, true);
1690
+ const localOffset = view.getUint32(pos + 42, true);
1691
+ const name = decoder.decode(data.subarray(pos + 46, pos + 46 + nameLen));
1692
+ if (name === target) {
1693
+ const compressionMethod = view.getUint16(localOffset + 8, true);
1694
+ if (compressionMethod !== 0) {
1695
+ return null;
1696
+ }
1697
+ const localNameLen = view.getUint16(localOffset + 26, true);
1698
+ const localExtraLen = view.getUint16(localOffset + 28, true);
1699
+ const compressedSize = view.getUint32(localOffset + 18, true);
1700
+ const dataStart = localOffset + 30 + localNameLen + localExtraLen;
1701
+ return data.subarray(dataStart, dataStart + compressedSize);
1702
+ }
1703
+ pos += 46 + nameLen + extraLen + commentLen;
1704
+ }
1705
+ return null;
1706
+ }
1707
+ function isAttrChar(code) {
1708
+ return code >= 97 && code <= 122 || // a-z
1709
+ code >= 65 && code <= 90 || // A-Z
1710
+ code >= 48 && code <= 57 || // 0-9
1711
+ code === 95;
1712
+ }
1713
+ function parseTagAttrs(tag) {
1714
+ const attrs = {};
1715
+ let pos = 0;
1716
+ while (pos < tag.length) {
1717
+ const eq = tag.indexOf('="', pos);
1718
+ if (eq < 0) break;
1719
+ let nameStart = eq;
1720
+ while (nameStart > 0 && isAttrChar(tag.charCodeAt(nameStart - 1))) nameStart--;
1721
+ if (nameStart === eq) {
1722
+ pos = eq + 2;
1723
+ continue;
1724
+ }
1725
+ const name = tag.slice(nameStart, eq);
1726
+ const valStart = eq + 2;
1727
+ const closeQuote = tag.indexOf('"', valStart);
1728
+ if (closeQuote < 0) break;
1729
+ attrs[name] = tag.slice(valStart, closeQuote);
1730
+ pos = closeQuote + 1;
1731
+ }
1732
+ return attrs;
1733
+ }
1734
+ function findTags(xml, tagName) {
1735
+ const tags = [];
1736
+ const needle = `<${tagName} `;
1737
+ let pos = 0;
1738
+ while (pos < xml.length) {
1739
+ const start = xml.indexOf(needle, pos);
1740
+ if (start < 0) break;
1741
+ const end = xml.indexOf(">", start);
1742
+ if (end < 0) break;
1743
+ tags.push(xml.slice(start, end + 1));
1744
+ pos = end + 1;
1745
+ }
1746
+ return tags;
1747
+ }
1748
+ function parseModelXml(xml) {
1749
+ const vertices = [];
1750
+ const triangles = [];
1751
+ for (const tag of findTags(xml, "vertex")) {
1752
+ const a = parseTagAttrs(tag);
1753
+ if (a["x"] !== void 0 && a["y"] !== void 0 && a["z"] !== void 0) {
1754
+ vertices.push([parseFloat(a["x"]), parseFloat(a["y"]), parseFloat(a["z"])]);
1755
+ }
1756
+ }
1757
+ for (const tag of findTags(xml, "triangle")) {
1758
+ const a = parseTagAttrs(tag);
1759
+ if (a["v1"] !== void 0 && a["v2"] !== void 0 && a["v3"] !== void 0) {
1760
+ triangles.push([parseInt(a["v1"], 10), parseInt(a["v2"], 10), parseInt(a["v3"], 10)]);
1761
+ }
1762
+ }
1763
+ return { vertices, triangles };
1764
+ }
1765
+ function buildTriFace(oc, a, b, c) {
1766
+ const gpA = new oc.gp_Pnt_3(a[0], a[1], a[2]);
1767
+ const gpB = new oc.gp_Pnt_3(b[0], b[1], b[2]);
1768
+ const gpC = new oc.gp_Pnt_3(c[0], c[1], c[2]);
1769
+ const e1 = new oc.BRepBuilderAPI_MakeEdge_3(gpA, gpB);
1770
+ const e2 = new oc.BRepBuilderAPI_MakeEdge_3(gpB, gpC);
1771
+ const e3 = new oc.BRepBuilderAPI_MakeEdge_3(gpC, gpA);
1772
+ const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
1773
+ wireBuilder.Add_1(e1.Edge());
1774
+ wireBuilder.Add_1(e2.Edge());
1775
+ wireBuilder.Add_1(e3.Edge());
1776
+ let face2 = null;
1777
+ if (wireBuilder.IsDone()) {
1778
+ const makeFace = new oc.BRepBuilderAPI_MakeFace_15(wireBuilder.Wire(), false);
1779
+ if (makeFace.IsDone()) {
1780
+ face2 = makeFace.Face();
1781
+ }
1782
+ makeFace.delete();
1783
+ }
1784
+ wireBuilder.delete();
1785
+ e1.delete();
1786
+ e2.delete();
1787
+ e3.delete();
1788
+ gpA.delete();
1789
+ gpB.delete();
1790
+ gpC.delete();
1791
+ return face2;
1792
+ }
1793
+ function buildSolidFromMesh(mesh2) {
1794
+ const oc = occtBoundary.getKernel().oc;
1795
+ const sewing = new oc.BRepBuilderAPI_Sewing(1e-6, true, true, true, false);
1796
+ let faceCount = 0;
1797
+ try {
1798
+ for (const [v1, v2, v3] of mesh2.triangles) {
1799
+ const va = mesh2.vertices[v1];
1800
+ const vb = mesh2.vertices[v2];
1801
+ const vc = mesh2.vertices[v3];
1802
+ if (!va || !vb || !vc) continue;
1803
+ const triFace = buildTriFace(oc, va, vb, vc);
1804
+ if (triFace !== null) {
1805
+ sewing.Add(triFace);
1806
+ faceCount++;
1807
+ }
1808
+ }
1809
+ if (faceCount === 0) {
1810
+ return errors.err(
1811
+ errors.ioError(errors.BrepErrorCode.THREEMF_IMPORT_FAILED, "No valid triangular faces could be built")
1812
+ );
1813
+ }
1814
+ const progress = new oc.Message_ProgressRange_1();
1815
+ sewing.Perform(progress);
1816
+ progress.delete();
1817
+ const sewn = sewing.SewedShape();
1818
+ const fixer = new oc.ShapeFix_Solid_1();
1819
+ try {
1820
+ const shell2 = oc.TopoDS.Shell_1(sewn);
1821
+ const solid2 = fixer.SolidFromShell(shell2);
1822
+ return errors.ok(shapeTypes.castShape(solid2));
1823
+ } catch {
1824
+ return errors.ok(shapeTypes.castShape(sewn));
1825
+ } finally {
1826
+ fixer.delete();
1827
+ }
1828
+ } finally {
1829
+ sewing.delete();
1830
+ }
1831
+ }
1832
+ async function importThreeMF(blob) {
1833
+ try {
1834
+ const arrayBuf = await blob.arrayBuffer();
1835
+ const data = new Uint8Array(arrayBuf);
1836
+ const modelData = extractFromZip(data, "3D/3dmodel.model");
1837
+ if (!modelData) {
1838
+ return errors.err(
1839
+ errors.ioError(
1840
+ errors.BrepErrorCode.THREEMF_IMPORT_FAILED,
1841
+ "3MF archive does not contain 3D/3dmodel.model (or uses unsupported compression)"
1842
+ )
1843
+ );
1844
+ }
1845
+ const xml = new TextDecoder().decode(modelData);
1846
+ const parsed = parseModelXml(xml);
1847
+ if (parsed.vertices.length === 0 || parsed.triangles.length === 0) {
1848
+ return errors.err(
1849
+ errors.ioError(errors.BrepErrorCode.THREEMF_IMPORT_FAILED, "3MF model contains no valid geometry")
1850
+ );
1851
+ }
1852
+ return buildSolidFromMesh(parsed);
1853
+ } catch (e) {
1854
+ const msg = e instanceof Error ? e.message : String(e);
1855
+ return errors.err(errors.ioError(errors.BrepErrorCode.THREEMF_IMPORT_FAILED, `3MF import failed: ${msg}`, e));
1856
+ }
1857
+ }
349
1858
  function resolve(s) {
350
1859
  if ("__wrapped" in s) {
351
1860
  return s.val;
@@ -412,18 +1921,18 @@ function ellipsoid(rx, ry, rz, options) {
412
1921
  return solid2;
413
1922
  }
414
1923
  function line(from, to) {
415
- return curveBuilders.makeLine(from, to);
1924
+ return surfaceBuilders.makeLine(from, to);
416
1925
  }
417
1926
  function circle(radius, options) {
418
1927
  const axisDir = options?.axis ?? [0, 0, 1];
419
- return curveBuilders.makeCircle(radius, options?.at ?? [0, 0, 0], axisDir);
1928
+ return surfaceBuilders.makeCircle(radius, options?.at ?? [0, 0, 0], axisDir);
420
1929
  }
421
1930
  function ellipse(majorRadius, minorRadius, options) {
422
1931
  const axisDir = options?.axis ?? [0, 0, 1];
423
- return curveBuilders.makeEllipse(majorRadius, minorRadius, options?.at ?? [0, 0, 0], axisDir, options?.xDir);
1932
+ return surfaceBuilders.makeEllipse(majorRadius, minorRadius, options?.at ?? [0, 0, 0], axisDir, options?.xDir);
424
1933
  }
425
1934
  function helix(pitch, height, radius, options) {
426
- return curveBuilders.makeHelix(
1935
+ return surfaceBuilders.makeHelix(
427
1936
  pitch,
428
1937
  height,
429
1938
  radius,
@@ -433,11 +1942,11 @@ function helix(pitch, height, radius, options) {
433
1942
  );
434
1943
  }
435
1944
  function threePointArc(p1, p2, p3) {
436
- return curveBuilders.makeThreePointArc(p1, p2, p3);
1945
+ return surfaceBuilders.makeThreePointArc(p1, p2, p3);
437
1946
  }
438
1947
  function ellipseArc(majorRadius, minorRadius, startAngle, endAngle, options) {
439
1948
  const axisDir = options?.axis ?? [0, 0, 1];
440
- return curveBuilders.makeEllipseArc(
1949
+ return surfaceBuilders.makeEllipseArc(
441
1950
  majorRadius,
442
1951
  minorRadius,
443
1952
  startAngle * vecOps.DEG2RAD,
@@ -448,28 +1957,28 @@ function ellipseArc(majorRadius, minorRadius, startAngle, endAngle, options) {
448
1957
  );
449
1958
  }
450
1959
  function bsplineApprox(points, config) {
451
- return curveBuilders.makeBSplineApproximation(points, config);
1960
+ return surfaceBuilders.makeBSplineApproximation(points, config);
452
1961
  }
453
1962
  function bezier(points) {
454
- return curveBuilders.makeBezierCurve(points);
1963
+ return surfaceBuilders.makeBezierCurve(points);
455
1964
  }
456
1965
  function tangentArc(startPoint, startTgt, endPoint) {
457
- return curveBuilders.makeTangentArc(startPoint, startTgt, endPoint);
1966
+ return surfaceBuilders.makeTangentArc(startPoint, startTgt, endPoint);
458
1967
  }
459
1968
  function wire(listOfEdges) {
460
- return curveBuilders.assembleWire(listOfEdges);
1969
+ return surfaceBuilders.assembleWire(listOfEdges);
461
1970
  }
462
1971
  function face(w, holes) {
463
- return Blueprint.makeFace(w, holes);
1972
+ return surfaceBuilders.makeFace(w, holes);
464
1973
  }
465
1974
  function filledFace(w) {
466
- return Blueprint.makeNonPlanarFace(w);
1975
+ return surfaceBuilders.makeNonPlanarFace(w);
467
1976
  }
468
1977
  function subFace(originFace, w) {
469
- return Blueprint.makeNewFaceWithinFace(originFace, w);
1978
+ return surfaceBuilders.makeNewFaceWithinFace(originFace, w);
470
1979
  }
471
1980
  function polygon(points) {
472
- return Blueprint.makePolygon(points);
1981
+ return surfaceBuilders.makePolygon(points);
473
1982
  }
474
1983
  function vertex(point) {
475
1984
  return loft$2.makeVertex(point);
@@ -487,7 +1996,7 @@ function sewShells(facesOrShells, ignoreType) {
487
1996
  return loft$2.weldShellsAndFaces(facesOrShells, ignoreType);
488
1997
  }
489
1998
  function addHoles(f, holes) {
490
- return Blueprint.addHolesInFace(f, holes);
1999
+ return surfaceBuilders.addHolesInFace(f, holes);
491
2000
  }
492
2001
  function validateNotNull(shape2, label) {
493
2002
  if (shape2.wrapped.IsNull()) {
@@ -506,9 +2015,11 @@ function thicken$1(shape2, thickness) {
506
2015
  const progress = r(new oc.Message_ProgressRange_1());
507
2016
  builder.Build(progress);
508
2017
  const resultOc = builder.Shape();
509
- const cast2 = shapeTypes.castShape(resultOc);
510
- shapeFns.propagateOrigins(builder, [shape2], cast2);
511
- return errors.ok(cast2);
2018
+ const cast = shapeTypes.castShape(resultOc);
2019
+ shapeFns.propagateOrigins(builder, [shape2], cast);
2020
+ booleanFns.propagateFaceTags(builder, [shape2], cast);
2021
+ booleanFns.propagateColors(builder, [shape2], cast);
2022
+ return errors.ok(cast);
512
2023
  } catch (e) {
513
2024
  const raw = e instanceof Error ? e.message : String(e);
514
2025
  return errors.err(errors.occtError("THICKEN_FAILED", `Thicken operation failed: ${raw}`, e));
@@ -567,12 +2078,14 @@ function fillet$1(shape2, edges, radius) {
567
2078
  }
568
2079
  }
569
2080
  const resultOc = builder.Shape();
570
- const cast2 = shapeTypes.castShape(resultOc);
571
- if (!shapeTypes.isShape3D(cast2)) {
2081
+ const cast = shapeTypes.castShape(resultOc);
2082
+ if (!shapeTypes.isShape3D(cast)) {
572
2083
  return errors.err(errors.occtError("FILLET_RESULT_NOT_3D", "Fillet result is not a 3D shape"));
573
2084
  }
574
- shapeFns.propagateOrigins(builder, [shape2], cast2);
575
- return errors.ok(cast2);
2085
+ shapeFns.propagateOrigins(builder, [shape2], cast);
2086
+ booleanFns.propagateFaceTags(builder, [shape2], cast);
2087
+ booleanFns.propagateColors(builder, [shape2], cast);
2088
+ return errors.ok(cast);
576
2089
  } catch (e) {
577
2090
  const raw = e instanceof Error ? e.message : String(e);
578
2091
  return errors.err(
@@ -661,12 +2174,14 @@ function chamfer$1(shape2, edges, distance) {
661
2174
  }
662
2175
  }
663
2176
  const resultOc = builder.Shape();
664
- const cast2 = shapeTypes.castShape(resultOc);
665
- if (!shapeTypes.isShape3D(cast2)) {
2177
+ const cast = shapeTypes.castShape(resultOc);
2178
+ if (!shapeTypes.isShape3D(cast)) {
666
2179
  return errors.err(errors.occtError("CHAMFER_RESULT_NOT_3D", "Chamfer result is not a 3D shape"));
667
2180
  }
668
- shapeFns.propagateOrigins(builder, [shape2], cast2);
669
- return errors.ok(cast2);
2181
+ shapeFns.propagateOrigins(builder, [shape2], cast);
2182
+ booleanFns.propagateFaceTags(builder, [shape2], cast);
2183
+ booleanFns.propagateColors(builder, [shape2], cast);
2184
+ return errors.ok(cast);
670
2185
  } catch (e) {
671
2186
  const raw = e instanceof Error ? e.message : String(e);
672
2187
  return errors.err(
@@ -709,12 +2224,14 @@ function shell$1(shape2, faces, thickness, tolerance = 1e-3) {
709
2224
  progress
710
2225
  );
711
2226
  const resultOc = builder.Shape();
712
- const cast2 = shapeTypes.castShape(resultOc);
713
- if (!shapeTypes.isShape3D(cast2)) {
2227
+ const cast = shapeTypes.castShape(resultOc);
2228
+ if (!shapeTypes.isShape3D(cast)) {
714
2229
  return errors.err(errors.occtError("SHELL_RESULT_NOT_3D", "Shell result is not a 3D shape"));
715
2230
  }
716
- shapeFns.propagateOrigins(builder, [shape2], cast2);
717
- return errors.ok(cast2);
2231
+ shapeFns.propagateOrigins(builder, [shape2], cast);
2232
+ booleanFns.propagateFaceTags(builder, [shape2], cast);
2233
+ booleanFns.propagateColors(builder, [shape2], cast);
2234
+ return errors.ok(cast);
718
2235
  } catch (e) {
719
2236
  const raw = e instanceof Error ? e.message : String(e);
720
2237
  return errors.err(
@@ -749,12 +2266,14 @@ function offset$1(shape2, distance, tolerance = 1e-6) {
749
2266
  progress
750
2267
  );
751
2268
  const resultOc = builder.Shape();
752
- const cast2 = shapeTypes.castShape(resultOc);
753
- if (!shapeTypes.isShape3D(cast2)) {
2269
+ const cast = shapeTypes.castShape(resultOc);
2270
+ if (!shapeTypes.isShape3D(cast)) {
754
2271
  return errors.err(errors.occtError("OFFSET_RESULT_NOT_3D", "Offset result is not a 3D shape"));
755
2272
  }
756
- shapeFns.propagateOrigins(builder, [shape2], cast2);
757
- return errors.ok(cast2);
2273
+ shapeFns.propagateOrigins(builder, [shape2], cast);
2274
+ booleanFns.propagateFaceTags(builder, [shape2], cast);
2275
+ booleanFns.propagateColors(builder, [shape2], cast);
2276
+ return errors.ok(cast);
758
2277
  } catch (e) {
759
2278
  const raw = e instanceof Error ? e.message : String(e);
760
2279
  return errors.err(errors.occtError("OFFSET_FAILED", `Offset operation failed: ${raw}`, e));
@@ -795,6 +2314,9 @@ function intersect(a, b, options) {
795
2314
  function section(shape2, plane, options) {
796
2315
  return booleanFns.section(resolve(shape2), plane, options);
797
2316
  }
2317
+ function sectionToFace(shape2, plane, options) {
2318
+ return booleanFns.sectionToFace(resolve(shape2), plane, options);
2319
+ }
798
2320
  function split(shape2, tools) {
799
2321
  return booleanFns.split(resolve(shape2), tools);
800
2322
  }
@@ -904,7 +2426,7 @@ function toBREP(shape2) {
904
2426
  return shapeFns.toBREP(resolve(shape2));
905
2427
  }
906
2428
  function fromBREP(data) {
907
- return cast.fromBREP(data);
2429
+ return faceFns.fromBREP(data);
908
2430
  }
909
2431
  function isValid(shape2) {
910
2432
  return topology.isValid(resolve(shape2));
@@ -1029,7 +2551,7 @@ function pocket(shape2, options) {
1029
2551
  const targetFace = resolveTargetFace(s, options.face);
1030
2552
  const normal = faceFns.normalAt(targetFace);
1031
2553
  const w = toWire(profile);
1032
- const faceResult = Blueprint.makeFace(w);
2554
+ const faceResult = surfaceBuilders.makeFace(w);
1033
2555
  if (errors.isErr(faceResult)) return faceResult;
1034
2556
  const extDir = vecOps.vecScale(vecOps.vecNormalize(normal), -depth);
1035
2557
  const toolResult = operations.extrude(faceResult.value, extDir);
@@ -1045,7 +2567,7 @@ function boss(shape2, options) {
1045
2567
  const targetFace = resolveTargetFace(s, options.face);
1046
2568
  const normal = faceFns.normalAt(targetFace);
1047
2569
  const w = toWire(profile);
1048
- const faceResult = Blueprint.makeFace(w);
2570
+ const faceResult = surfaceBuilders.makeFace(w);
1049
2571
  if (errors.isErr(faceResult)) return faceResult;
1050
2572
  const extDir = vecOps.vecScale(vecOps.vecNormalize(normal), height);
1051
2573
  const toolResult = operations.extrude(faceResult.value, extDir);
@@ -1471,6 +2993,7 @@ exports.drawingFillet = drawFns.drawingFillet;
1471
2993
  exports.drawingFuse = drawFns.drawingFuse;
1472
2994
  exports.drawingIntersect = drawFns.drawingIntersect;
1473
2995
  exports.drawingToSketchOnPlane = drawFns.drawingToSketchOnPlane;
2996
+ exports.fontMetrics = drawFns.fontMetrics;
1474
2997
  exports.getFont = drawFns.getFont;
1475
2998
  exports.isProjectionPlane = drawFns.isProjectionPlane;
1476
2999
  exports.loadFont = drawFns.loadFont;
@@ -1497,6 +3020,7 @@ exports.sketchSweep = drawFns.sketchSweep;
1497
3020
  exports.sketchText = drawFns.sketchText;
1498
3021
  exports.sketchWires = drawFns.sketchWires;
1499
3022
  exports.textBlueprints = drawFns.textBlueprints;
3023
+ exports.textMetrics = drawFns.textMetrics;
1500
3024
  exports.translateDrawing = drawFns.translateDrawing;
1501
3025
  exports.createNamedPlane = vectors.createNamedPlane;
1502
3026
  exports.createPlane = vectors.createPlane;
@@ -1517,8 +3041,21 @@ exports.iterEdges = shapeFns.iterEdges;
1517
3041
  exports.iterFaces = shapeFns.iterFaces;
1518
3042
  exports.iterVertices = shapeFns.iterVertices;
1519
3043
  exports.iterWires = shapeFns.iterWires;
3044
+ exports.resize = shapeFns.resize;
1520
3045
  exports.setShapeOrigin = shapeFns.setShapeOrigin;
1521
3046
  exports.vertexPosition = shapeFns.vertexPosition;
3047
+ exports.applyGlue = booleanFns.applyGlue;
3048
+ exports.colorFaces = booleanFns.colorFaces;
3049
+ exports.colorShape = booleanFns.colorShape;
3050
+ exports.cutAll = booleanFns.cutAll;
3051
+ exports.findFacesByTag = booleanFns.findFacesByTag;
3052
+ exports.fuseAll = booleanFns.fuseAll;
3053
+ exports.getFaceColor = booleanFns.getFaceColor;
3054
+ exports.getFaceTags = booleanFns.getFaceTags;
3055
+ exports.getShapeColor = booleanFns.getShapeColor;
3056
+ exports.getTagMetadata = booleanFns.getTagMetadata;
3057
+ exports.setTagMetadata = booleanFns.setTagMetadata;
3058
+ exports.tagFaces = booleanFns.tagFaces;
1522
3059
  exports.adjacentFaces = topology.adjacentFaces;
1523
3060
  exports.autoHeal = topology.autoHeal;
1524
3061
  exports.chamferDistAngleShape = topology.chamferDistAngle;
@@ -1533,17 +3070,24 @@ exports.toGroupedBufferGeometryData = topology.toGroupedBufferGeometryData;
1533
3070
  exports.toLineGeometryData = topology.toLineGeometryData;
1534
3071
  exports.verticesOfEdge = topology.verticesOfEdge;
1535
3072
  exports.wiresOfFace = topology.wiresOfFace;
3073
+ exports.asTopo = faceFns.asTopo;
3074
+ exports.cast = faceFns.cast;
1536
3075
  exports.classifyPointOnFace = faceFns.classifyPointOnFace;
3076
+ exports.deserializeShape = faceFns.fromBREP;
3077
+ exports.downcast = faceFns.downcast;
1537
3078
  exports.faceCenter = faceFns.faceCenter;
1538
3079
  exports.faceGeomType = faceFns.faceGeomType;
1539
3080
  exports.faceOrientation = faceFns.faceOrientation;
1540
3081
  exports.flipFaceOrientation = faceFns.flipFaceOrientation;
1541
3082
  exports.getSurfaceType = faceFns.getSurfaceType;
1542
3083
  exports.innerWires = faceFns.innerWires;
3084
+ exports.isCompSolid = faceFns.isCompSolid;
3085
+ exports.iterTopo = faceFns.iterTopo;
1543
3086
  exports.normalAt = faceFns.normalAt;
1544
3087
  exports.outerWire = faceFns.outerWire;
1545
3088
  exports.pointOnSurface = faceFns.pointOnSurface;
1546
3089
  exports.projectPointOnFace = faceFns.projectPointOnFace;
3090
+ exports.shapeType = faceFns.shapeType;
1547
3091
  exports.uvBounds = faceFns.uvBounds;
1548
3092
  exports.uvCoordinates = faceFns.uvCoordinates;
1549
3093
  exports.clearMeshCache = meshFns.clearMeshCache;
@@ -1551,9 +3095,6 @@ exports.createMeshCache = meshFns.createMeshCache;
1551
3095
  exports.exportIGES = meshFns.exportIGES;
1552
3096
  exports.exportSTEP = meshFns.exportSTEP;
1553
3097
  exports.exportSTL = meshFns.exportSTL;
1554
- exports.applyGlue = booleanFns.applyGlue;
1555
- exports.cutAll = booleanFns.cutAll;
1556
- exports.fuseAll = booleanFns.fuseAll;
1557
3098
  exports.createDistanceQuery = measurement.createDistanceQuery;
1558
3099
  exports.measureArea = measurement.measureArea;
1559
3100
  exports.measureCurvatureAt = measurement.measureCurvatureAt;
@@ -1564,13 +3105,7 @@ exports.measureLinearProps = measurement.measureLinearProps;
1564
3105
  exports.measureSurfaceProps = measurement.measureSurfaceProps;
1565
3106
  exports.measureVolume = measurement.measureVolume;
1566
3107
  exports.measureVolumeProps = measurement.measureVolumeProps;
1567
- exports.asTopo = cast.asTopo;
1568
- exports.cast = cast.cast;
1569
- exports.deserializeShape = cast.fromBREP;
1570
- exports.downcast = cast.downcast;
1571
- exports.isCompSolid = cast.isCompSolid;
1572
- exports.iterTopo = cast.iterTopo;
1573
- exports.shapeType = cast.shapeType;
3108
+ exports.fill = surfaceBuilders.fill;
1574
3109
  exports.edgeFinder = query.edgeFinder;
1575
3110
  exports.BrepBugError = result.BrepBugError;
1576
3111
  exports.bug = result.bug;
@@ -1592,6 +3127,7 @@ exports.registerHandler = worker.registerHandler;
1592
3127
  exports.rejectAll = worker.rejectAll;
1593
3128
  exports.BrepWrapperError = BrepWrapperError;
1594
3129
  exports.addHoles = addHoles;
3130
+ exports.addMate = addMate;
1595
3131
  exports.applyMatrix = applyMatrix;
1596
3132
  exports.bezier = bezier;
1597
3133
  exports.boss = boss;
@@ -1603,6 +3139,7 @@ exports.checkInterference = checkInterference;
1603
3139
  exports.circle = circle;
1604
3140
  exports.clone = clone;
1605
3141
  exports.compound = compound;
3142
+ exports.computeStraightSkeleton = computeStraightSkeleton;
1606
3143
  exports.cone = cone;
1607
3144
  exports.cut = cut;
1608
3145
  exports.cylinder = cylinder;
@@ -1617,9 +3154,13 @@ exports.filledFace = filledFace;
1617
3154
  exports.fillet = fillet;
1618
3155
  exports.fromBREP = fromBREP;
1619
3156
  exports.fuse = fuse;
3157
+ exports.guidedSweep = guidedSweep;
1620
3158
  exports.heal = heal;
1621
3159
  exports.helix = helix;
1622
3160
  exports.hull = hull;
3161
+ exports.importDXF = importDXF;
3162
+ exports.importOBJ = importOBJ;
3163
+ exports.importThreeMF = importThreeMF;
1623
3164
  exports.intersect = intersect;
1624
3165
  exports.isChamferRadius = isChamferRadius;
1625
3166
  exports.isEmpty = isEmpty;
@@ -1635,26 +3176,33 @@ exports.meshEdges = meshEdges;
1635
3176
  exports.minkowski = minkowski;
1636
3177
  exports.mirror = mirror;
1637
3178
  exports.mirrorJoin = mirrorJoin;
3179
+ exports.multiSectionSweep = multiSectionSweep;
1638
3180
  exports.offset = offset;
1639
3181
  exports.offsetFace = offsetFace;
1640
3182
  exports.pocket = pocket;
1641
3183
  exports.polygon = polygon;
3184
+ exports.polyhedron = polyhedron;
1642
3185
  exports.rectangularPattern = rectangularPattern;
1643
3186
  exports.resolve = resolve;
1644
3187
  exports.resolve3D = resolve3D;
1645
3188
  exports.revolve = revolve;
3189
+ exports.roof = roof;
1646
3190
  exports.rotate = rotate;
1647
3191
  exports.scale = scale;
1648
3192
  exports.section = section;
3193
+ exports.sectionToFace = sectionToFace;
1649
3194
  exports.sewShells = sewShells;
1650
3195
  exports.shape = shape;
1651
3196
  exports.shell = shell;
1652
3197
  exports.simplify = simplify;
1653
3198
  exports.slice = slice;
1654
3199
  exports.solid = solid;
3200
+ exports.solveAssembly = solveAssembly;
1655
3201
  exports.sphere = sphere;
1656
3202
  exports.split = split;
1657
3203
  exports.subFace = subFace;
3204
+ exports.surfaceFromGrid = surfaceFromGrid;
3205
+ exports.surfaceFromImage = surfaceFromImage;
1658
3206
  exports.tangentArc = tangentArc;
1659
3207
  exports.thicken = thicken;
1660
3208
  exports.threePointArc = threePointArc;