brepjs 20.12.6 → 20.12.8

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 (96) hide show
  1. package/dist/2d/blueprints/booleanHelpers.d.ts +0 -5
  2. package/dist/2d/blueprints/intersectionSegments.d.ts +6 -5
  3. package/dist/2d.cjs +6 -6
  4. package/dist/2d.js +6 -6
  5. package/dist/{adjacencyFns-BFJfaUwX.cjs → adjacencyFns-BfgFo-Rh.cjs} +3 -3
  6. package/dist/{adjacencyFns--KmBIKYJ.js → adjacencyFns-Bl109A3Z.js} +3 -3
  7. package/dist/{blueprint-D83DDDPb.cjs → blueprint-DTDSztfd.cjs} +5 -5
  8. package/dist/{blueprint-BhIk9Pvm.js → blueprint-RqemOtg5.js} +5 -5
  9. package/dist/{blueprintFns-eULVgkq9.js → blueprintFns-B9_PhTr8.js} +2 -2
  10. package/dist/{blueprintFns-C4TQn-x_.cjs → blueprintFns-C7E5R89N.cjs} +2 -2
  11. package/dist/{blueprintSketcher-D_Faf0GO.js → blueprintSketcher-B15522Kr.js} +3 -3
  12. package/dist/{blueprintSketcher-Di376t-0.cjs → blueprintSketcher-Brj4lXjj.cjs} +3 -3
  13. package/dist/{boolean2D-CNZFI_y8.cjs → boolean2D-DZ8aJbI-.cjs} +42 -50
  14. package/dist/{boolean2D-DqpCF72W.js → boolean2D-_eiIiNw1.js} +42 -50
  15. package/dist/{solidBuilders-iS5DDwg8.cjs → booleanFns-D5nQ1nWS.cjs} +11 -217
  16. package/dist/{solidBuilders-DT1gpVWM.js → booleanFns-cNfXGqMX.js} +10 -156
  17. package/dist/brepjs.cjs +325 -168
  18. package/dist/brepjs.js +282 -125
  19. package/dist/{cameraFns-RqraCXIc.cjs → cameraFns-6Er2lhp5.cjs} +3 -3
  20. package/dist/{cameraFns-CrClIkmV.js → cameraFns-YhB7A_Zc.js} +3 -3
  21. package/dist/core.cjs +2 -2
  22. package/dist/core.js +2 -2
  23. package/dist/{cornerFinder-CdOe1Wrb.cjs → cornerFinder-D9Wx3DWu.cjs} +1 -1
  24. package/dist/{cornerFinder-BZuQkRp2.js → cornerFinder-G1WkSkVl.js} +1 -1
  25. package/dist/{curveFns-CyIvQNYT.cjs → curveFns-B5_N-gMj.cjs} +1 -1
  26. package/dist/{curveFns-BP3srCfK.js → curveFns-C4CqthJp.js} +1 -1
  27. package/dist/{drawFns-DxDwJ5zZ.js → drawFns-DU5fewKl.js} +12 -12
  28. package/dist/{drawFns-71cOhWD-.cjs → drawFns-UPbO2heB.cjs} +12 -12
  29. package/dist/{faceFns-iVPbTxki.js → faceFns-BgRNa5vx.js} +2 -2
  30. package/dist/{faceFns-B7MiDYj1.cjs → faceFns-C4NOGZBg.cjs} +2 -2
  31. package/dist/{healingFns-BhP8zfp1.js → healingFns-BzOo0yyz.js} +5 -5
  32. package/dist/{healingFns-DWljGTNR.cjs → healingFns-i5gV3BMG.cjs} +29 -29
  33. package/dist/{helpers-DKEVm6Hu.cjs → helpers-DJQeDf_5.cjs} +6 -6
  34. package/dist/{helpers-D2hANLRu.js → helpers-DPHQt2Kr.js} +6 -6
  35. package/dist/{importFns-KEPAgbjj.cjs → importFns-BiRpt227.cjs} +319 -14
  36. package/dist/{importFns-DUzIkns7.js → importFns-CwrJsNvg.js} +314 -15
  37. package/dist/io/igesSupport.d.ts +6 -0
  38. package/dist/io/importFns.d.ts +15 -5
  39. package/dist/io/ioUtils.d.ts +15 -3
  40. package/dist/io/meshNesting.d.ts +11 -0
  41. package/dist/io/threemfImportFns.d.ts +6 -3
  42. package/dist/io.cjs +2 -2
  43. package/dist/io.js +2 -2
  44. package/dist/kernel/occtWasm/occtWasmAdapter.cjs +1 -1
  45. package/dist/kernel/occtWasm/occtWasmAdapter.js +1 -1
  46. package/dist/kernel/occtWasm/occtWasmTypes.d.ts +4 -2
  47. package/dist/{loftFns-D5AvfCGG.cjs → loftFns-DgkK4Kj_.cjs} +1 -1
  48. package/dist/{loftFns-D5NJpHLZ.js → loftFns-lwzTh1fI.js} +1 -1
  49. package/dist/{measureFns-CZHNWkiA.cjs → measureFns-D_RRjCZg.cjs} +3 -3
  50. package/dist/{measureFns-mxBdPiWa.js → measureFns-Q3K25IfN.js} +3 -3
  51. package/dist/measurement.cjs +2 -2
  52. package/dist/measurement.js +2 -2
  53. package/dist/{meshFns-DmjMzNbH.js → meshFns-BGoJU6_P.js} +20 -6
  54. package/dist/{meshFns-Czlt-GBJ.cjs → meshFns-Djbb4PUC.cjs} +25 -5
  55. package/dist/{occtWasmAdapter-B9d0Q0Vl.js → occtWasmAdapter-BCCwaYkq.js} +103 -40
  56. package/dist/{occtWasmAdapter-DVxLkjlJ.cjs → occtWasmAdapter-UcYZRi-w.cjs} +103 -40
  57. package/dist/operations.cjs +2 -2
  58. package/dist/operations.js +2 -2
  59. package/dist/{primitiveFns-BVeBEaa4.cjs → primitiveFns-CfSnex9P.cjs} +19 -18
  60. package/dist/{primitiveFns-DeNl60Rw.js → primitiveFns-D-aYcwt2.js} +5 -4
  61. package/dist/{principalBoxFns-3mW_hA6z.js → principalBoxFns-Dcp9gg5e.js} +3 -3
  62. package/dist/{principalBoxFns-CG6kG7vT.cjs → principalBoxFns-IY8FfPVj.cjs} +3 -3
  63. package/dist/projection.cjs +1 -1
  64. package/dist/projection.js +1 -1
  65. package/dist/query.cjs +2 -2
  66. package/dist/query.js +2 -2
  67. package/dist/{refResolveFns-DHx1Y3GG.js → refResolveFns-BPge7T5w.js} +6 -6
  68. package/dist/{refResolveFns-BAs4p9z7.cjs → refResolveFns-gZQ1o5XK.cjs} +6 -6
  69. package/dist/{shapeFns-C0w8vvfb.cjs → shapeFns-Bs92VrZh.cjs} +2 -2
  70. package/dist/{shapeFns-CgqKICF_.js → shapeFns-TWdr4Dv4.js} +2 -2
  71. package/dist/shapeRef.cjs +1 -1
  72. package/dist/shapeRef.js +1 -1
  73. package/dist/{shapeTypes-DwvQUp9M.js → shapeTypes-CIH-8d_a.js} +1 -1
  74. package/dist/{shapeTypes-Dc7j-MYg.cjs → shapeTypes-DmThK_oa.cjs} +1 -1
  75. package/dist/sketching.cjs +3 -3
  76. package/dist/sketching.js +3 -3
  77. package/dist/{originTrackingFns-CHymOLLm.cjs → solidBuilders-DGskMugU.cjs} +209 -2
  78. package/dist/{originTrackingFns-CBnyKLm7.js → solidBuilders-q_hwYsdo.js} +150 -3
  79. package/dist/{surfaceBuilders-CPLe0bbk.js → surfaceBuilders-DXo4N7wQ.js} +3 -3
  80. package/dist/{surfaceBuilders-BvwSgD3C.cjs → surfaceBuilders-DeSLKg73.cjs} +3 -3
  81. package/dist/text.cjs +2 -2
  82. package/dist/text.js +2 -2
  83. package/dist/{textBlueprints-BU0Rhk54.js → textBlueprints-BYWZho_c.js} +8 -7
  84. package/dist/{textBlueprints-CNPCPJix.cjs → textBlueprints-Dz6wNgve.cjs} +9 -8
  85. package/dist/{textMetrics-C71g4TmO.cjs → textMetrics-bKoFTj3m.cjs} +1 -1
  86. package/dist/{textMetrics-Df9aLYK2.js → textMetrics-k_rGqib2.js} +1 -1
  87. package/dist/{threadFns-DESH7lcs.js → threadFns-BeB8s0tA.js} +7 -7
  88. package/dist/{threadFns-CzXEnnmo.cjs → threadFns-CoGAFHHt.cjs} +9 -9
  89. package/dist/topology/meshFns.d.ts +3 -0
  90. package/dist/topology.cjs +11 -11
  91. package/dist/topology.js +9 -9
  92. package/dist/{topologyQueryFns-5Frx8Y-0.cjs → topologyQueryFns-CXbCFaU2.cjs} +1 -1
  93. package/dist/{topologyQueryFns-LXV1nTaS.js → topologyQueryFns-Cp0yekBh.js} +1 -1
  94. package/dist/{validityTypes-DM-Iwe8N.js → validityTypes-DlrWkrSR.js} +1 -1
  95. package/dist/{validityTypes-C6rROGTP.cjs → validityTypes-m6eLRTYE.cjs} +1 -1
  96. package/package.json +1 -1
@@ -1,8 +1,12 @@
1
- const require_shapeTypes = require("./shapeTypes-Dc7j-MYg.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-DmThK_oa.cjs");
2
2
  const require_bug = require("./bug-CBcpIPuf.cjs");
3
3
  const require_errors = require("./errors-O_blYTWT.cjs");
4
+ const require_topologyQueryFns = require("./topologyQueryFns-CXbCFaU2.cjs");
5
+ const require_constants = require("./constants-oee0S_x6.cjs");
6
+ const require_solidBuilders = require("./solidBuilders-DGskMugU.cjs");
7
+ const require_meshFns = require("./meshFns-Djbb4PUC.cjs");
4
8
  const require_arrayAccess = require("./arrayAccess-DpJYARwv.cjs");
5
- const require_blueprint = require("./blueprint-D83DDDPb.cjs");
9
+ const require_blueprint = require("./blueprint-DTDSztfd.cjs");
6
10
  // src/io/objExportFns.ts
7
11
  /** Read a vec3 from a typed array at the given vertex index. */
8
12
  function vec3At(arr, i) {
@@ -1248,13 +1252,17 @@ function importSVGPathD(pathD) {
1248
1252
  */
1249
1253
  function importSVG(svgString) {
1250
1254
  try {
1251
- const dAttrRe = /\bd\s*=\s*(?:"([^"]*)"|'([^']*)')/;
1255
+ const dAttrRe = /\sd\s*=\s*(?:"([^"]*)"|'([^']*)')/;
1252
1256
  const blueprints = [];
1253
1257
  const lower = svgString.toLowerCase();
1254
1258
  let pos = 0;
1255
1259
  while (pos < lower.length) {
1256
- const tagStart = lower.indexOf("<path ", pos);
1260
+ const tagStart = lower.indexOf("<path", pos);
1257
1261
  if (tagStart === -1) break;
1262
+ if (!/\s/.test(lower.charAt(tagStart + 5))) {
1263
+ pos = tagStart + 5;
1264
+ continue;
1265
+ }
1258
1266
  const tagEnd = svgString.indexOf(">", tagStart);
1259
1267
  if (tagEnd === -1) break;
1260
1268
  const tag = svgString.slice(tagStart, tagEnd + 1);
@@ -1297,6 +1305,275 @@ function exportSTEPConfigured(parts, options) {
1297
1305
  return require_errors.err(require_errors.ioError(require_errors.BrepErrorCode.STEP_EXPORT_CONFIGURED_FAILED, "Configured STEP export failed", e));
1298
1306
  }
1299
1307
  }
1308
+ // src/io/meshNesting.ts
1309
+ /**
1310
+ * Cavities in sewn mesh bodies.
1311
+ *
1312
+ * A hollow mesh is an outer shell plus inward-facing inner shells, and sewing makes
1313
+ * each of them a closed body of its own. A cavity is a shell whose triangles face
1314
+ * inward (negative signed volume, read before solidifying reorients it) that lies
1315
+ * inside another body; it is cut from the innermost body around it. An outward-facing
1316
+ * shell inside another is a separate part and stays one. Containment comes from ray
1317
+ * casts against each body's tessellation, because no kernel here can classify a
1318
+ * point against a solid.
1319
+ */
1320
+ var RAY_LENGTH = Math.hypot(.5389, .6213, .5689);
1321
+ var RAY = [
1322
+ .5389 / RAY_LENGTH,
1323
+ .6213 / RAY_LENGTH,
1324
+ .5689 / RAY_LENGTH
1325
+ ];
1326
+ /**
1327
+ * The parts to keep: `bodies` (each built from the same-index shell of `shells`)
1328
+ * with every cavity cut from the body around it and left out. Cut results are
1329
+ * pushed to `owned` for the caller to dispose; no input is disposed here.
1330
+ *
1331
+ * @throws When meshing or a cut fails, rather than leave a cavity filled.
1332
+ */
1333
+ function carveCavities(bodies, shells, owned) {
1334
+ const solids = bodies.flatMap((body, i) => require_shapeTypes.isSolid(body) ? [{
1335
+ body,
1336
+ shell: shells[i]
1337
+ }] : []);
1338
+ if (solids.length < 2) return [...bodies];
1339
+ const voids = findVoids(solids);
1340
+ const carved = /* @__PURE__ */ new Map();
1341
+ for (const [body, inner] of voids) {
1342
+ const result = cutVoids(body, inner);
1343
+ owned.push(result);
1344
+ carved.set(body, result);
1345
+ }
1346
+ const consumed = new Set([...carved.keys()].flatMap((body) => voids.get(body) ?? []));
1347
+ return bodies.filter((body) => !consumed.has(body)).map((body) => carved.get(body) ?? body);
1348
+ }
1349
+ /** The cavities of each body that has any, keyed by that body. */
1350
+ function findVoids(solids) {
1351
+ const kernel = require_shapeTypes.getKernel();
1352
+ const boxes = solids.map(({ body }) => kernel.boundingBox(body.wrapped));
1353
+ const meshes = /* @__PURE__ */ new Map();
1354
+ const meshOf = (i) => {
1355
+ let mesh = meshes.get(i);
1356
+ if (mesh === void 0) {
1357
+ mesh = meshShape(solids[i].body, boxes[i]);
1358
+ meshes.set(i, mesh);
1359
+ }
1360
+ return mesh;
1361
+ };
1362
+ const containers = solids.map((_inner, j) => solids.map((_outer, i) => i).filter((i) => i !== j && boxInside(boxes[j], boxes[i]) && insideMesh(firstVertex(meshOf(j)), meshOf(i))));
1363
+ const isVoid = containers.map((around, j) => {
1364
+ const shell = solids[j]?.shell;
1365
+ return around.length > 0 && shell !== void 0 && facesInward(shell, boxes[j]);
1366
+ });
1367
+ const voids = /* @__PURE__ */ new Map();
1368
+ containers.forEach((around, j) => {
1369
+ if (!isVoid[j]) return;
1370
+ const bodiesAround = around.filter((i) => !isVoid[i]);
1371
+ if (bodiesAround.length === 0) return;
1372
+ const body = solids[bodiesAround.reduce((a, b) => (containers[b]?.length ?? 0) > (containers[a]?.length ?? 0) ? b : a)].body;
1373
+ voids.set(body, [...voids.get(body) ?? [], solids[j].body]);
1374
+ });
1375
+ return voids;
1376
+ }
1377
+ /** Whether a closed shell's triangles face inward, by the sign of its enclosed volume. */
1378
+ function facesInward(shell, box) {
1379
+ const mesh = meshShape(shell, box);
1380
+ const t = mesh.triangles;
1381
+ let volume = 0;
1382
+ for (let i = 0; i + 2 < t.length; i += 3) {
1383
+ const a = vertexAt(mesh, t[i]);
1384
+ volume += dot(a, cross(vertexAt(mesh, t[i + 1]), vertexAt(mesh, t[i + 2])));
1385
+ }
1386
+ return volume < 0;
1387
+ }
1388
+ function cutVoids(body, voids) {
1389
+ const kernel = require_shapeTypes.getKernel();
1390
+ let current = body;
1391
+ for (const inner of voids) try {
1392
+ const next = require_shapeTypes.castResultShape(kernel.cut(current.wrapped, inner.wrapped));
1393
+ if (current !== body) current[Symbol.dispose]();
1394
+ current = next;
1395
+ } catch (e) {
1396
+ if (current !== body) current[Symbol.dispose]();
1397
+ throw e;
1398
+ }
1399
+ return current;
1400
+ }
1401
+ function meshShape(shape, box) {
1402
+ const diagonal = Math.hypot(...box.max.map((v, i) => v - (box.min[i] ?? 0)));
1403
+ return require_shapeTypes.getKernel().mesh(shape.wrapped, {
1404
+ tolerance: Math.max(diagonal * .001, 1e-6),
1405
+ angularTolerance: .5,
1406
+ skipNormals: true
1407
+ });
1408
+ }
1409
+ function boxInside(inner, outer) {
1410
+ return inner.min.every((v, i) => v >= (outer.min[i] ?? 0) && (inner.max[i] ?? 0) <= (outer.max[i] ?? 0));
1411
+ }
1412
+ function firstVertex(mesh) {
1413
+ return [
1414
+ mesh.vertices[0] ?? 0,
1415
+ mesh.vertices[1] ?? 0,
1416
+ mesh.vertices[2] ?? 0
1417
+ ];
1418
+ }
1419
+ function vertexAt(mesh, index) {
1420
+ const i = (index ?? 0) * 3;
1421
+ return [
1422
+ mesh.vertices[i] ?? 0,
1423
+ mesh.vertices[i + 1] ?? 0,
1424
+ mesh.vertices[i + 2] ?? 0
1425
+ ];
1426
+ }
1427
+ /** Whether `p` is inside the closed mesh, by the parity of a ray's crossings. */
1428
+ function insideMesh(p, mesh) {
1429
+ const t = mesh.triangles;
1430
+ let crossings = 0;
1431
+ for (let i = 0; i + 2 < t.length; i += 3) if (rayHits(p, vertexAt(mesh, t[i]), vertexAt(mesh, t[i + 1]), vertexAt(mesh, t[i + 2]))) crossings++;
1432
+ return crossings % 2 === 1;
1433
+ }
1434
+ var sub = (a, b) => [
1435
+ a[0] - b[0],
1436
+ a[1] - b[1],
1437
+ a[2] - b[2]
1438
+ ];
1439
+ var dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
1440
+ var cross = (a, b) => [
1441
+ a[1] * b[2] - a[2] * b[1],
1442
+ a[2] * b[0] - a[0] * b[2],
1443
+ a[0] * b[1] - a[1] * b[0]
1444
+ ];
1445
+ /** Moller-Trumbore: does the ray from `p` along RAY cross triangle abc ahead of `p`? */
1446
+ function rayHits(p, a, b, c) {
1447
+ const e1 = sub(b, a);
1448
+ const e2 = sub(c, a);
1449
+ const h = cross(RAY, e2);
1450
+ const det = dot(e1, h);
1451
+ if (det === 0) return false;
1452
+ const s = sub(p, a);
1453
+ const u = dot(s, h) / det;
1454
+ if (u < 0 || u > 1) return false;
1455
+ const q = cross(s, e1);
1456
+ const v = dot(RAY, q) / det;
1457
+ if (v < 0 || u + v > 1) return false;
1458
+ return dot(e2, q) / det > 0;
1459
+ }
1460
+ // src/io/ioUtils.ts
1461
+ /**
1462
+ * Shared mesh-to-solid sewing utilities for mesh importers.
1463
+ *
1464
+ * Builds triangular B-Rep faces from vertex/index data and sews them into one
1465
+ * solid per closed body, keeping any open body as a shell.
1466
+ */
1467
+ /**
1468
+ * Sew faces into one solid per closed body.
1469
+ *
1470
+ * A single body comes back on its own: a `Solid` when closed, a `Shell` when
1471
+ * open. Several bodies come back as a `Compound` holding a `Solid` per closed
1472
+ * body, a `Shell` per open one, and any face that joined no shell. An
1473
+ * inward-facing closed shell inside another body is a cavity, cut from that
1474
+ * body. The caller keeps ownership of `faces`.
1475
+ *
1476
+ * @throws When the kernel cannot sew the faces at all.
1477
+ */
1478
+ function sewFacesIntoSolids(faces, tolerance) {
1479
+ try {
1480
+ var _usingCtx$2 = require_shapeTypes._usingCtx();
1481
+ const kernel = require_shapeTypes.getKernel();
1482
+ const solid = solidify(faces, tolerance);
1483
+ if (solid !== null) return solid;
1484
+ const sewn = require_shapeTypes.castResultShape(kernel.sew(faces, tolerance));
1485
+ const shells = require_topologyQueryFns.getShells(sewn);
1486
+ const hasLooseFaces = shells.reduce((n, shell) => n + require_topologyQueryFns.subShapeCount(shell, "face"), 0) !== require_topologyQueryFns.subShapeCount(sewn, "face");
1487
+ if (shells.length === 0 || shells.length === 1 && !hasLooseFaces) return sewn;
1488
+ _usingCtx$2.u(sewn);
1489
+ const owned = [];
1490
+ try {
1491
+ const parts = carveCavities(shells.map((shell) => {
1492
+ const body = solidifyShell(shell.wrapped, tolerance);
1493
+ owned.push(body);
1494
+ return body;
1495
+ }), shells, owned);
1496
+ if (hasLooseFaces) for (const face of facesOutsideShells(sewn, shells)) {
1497
+ const copy = require_shapeTypes.castResultShape(kernel.copyShape(face.wrapped));
1498
+ owned.push(copy);
1499
+ parts.push(copy);
1500
+ }
1501
+ return require_solidBuilders.makeCompound(parts);
1502
+ } finally {
1503
+ for (const shape of owned) shape[Symbol.dispose]();
1504
+ }
1505
+ } catch (_) {
1506
+ _usingCtx$2.e = _;
1507
+ } finally {
1508
+ _usingCtx$2.d();
1509
+ }
1510
+ }
1511
+ function facesOutsideShells(sewn, shells) {
1512
+ const kernel = require_shapeTypes.getKernel();
1513
+ const inShells = /* @__PURE__ */ new Map();
1514
+ for (const shell of shells) for (const face of require_topologyQueryFns.getFaces(shell)) {
1515
+ const hash = kernel.hashCode(face.wrapped, require_constants.HASH_CODE_MAX);
1516
+ const bucket = inShells.get(hash);
1517
+ if (bucket) bucket.push(face.wrapped);
1518
+ else inShells.set(hash, [face.wrapped]);
1519
+ }
1520
+ return require_topologyQueryFns.getFaces(sewn).filter((face) => {
1521
+ return !inShells.get(kernel.hashCode(face.wrapped, require_constants.HASH_CODE_MAX))?.some((other) => kernel.isSame(face.wrapped, other));
1522
+ });
1523
+ }
1524
+ /**
1525
+ * `sewAndSolidify` when it yields a single solid, else `null`. Kernels signal
1526
+ * "not one closed body" differently: occt-wasm's solid downcast throws (and
1527
+ * castResultShape releases the slot), while opencascade.js returns the sewn
1528
+ * shell or compound, so the result's type decides.
1529
+ */
1530
+ function solidify(faces, tolerance) {
1531
+ let shape;
1532
+ try {
1533
+ shape = require_shapeTypes.castResultShape(require_shapeTypes.getKernel().sewAndSolidify(faces, tolerance));
1534
+ } catch {
1535
+ return null;
1536
+ }
1537
+ if (require_shapeTypes.isSolid(shape)) return shape;
1538
+ shape[Symbol.dispose]();
1539
+ return null;
1540
+ }
1541
+ function solidifyShell(shell, tolerance) {
1542
+ const kernel = require_shapeTypes.getKernel();
1543
+ const faces = kernel.iterShapes(shell, "face");
1544
+ try {
1545
+ return solidify(faces, tolerance) ?? require_shapeTypes.castResultShape(kernel.copyShape(shell));
1546
+ } finally {
1547
+ for (const face of faces) kernel.dispose(face);
1548
+ }
1549
+ }
1550
+ /**
1551
+ * Build triangular B-Rep faces from vertex data and sew them into solids.
1552
+ *
1553
+ * For each triple of vertex coordinates, calls `kernel.buildTriFace` to create
1554
+ * a planar triangular face, then sews them with {@link sewFacesIntoSolids}.
1555
+ *
1556
+ * @param triangles - Array of vertex triples, each triple being three [x,y,z] tuples.
1557
+ * @param errorCode - The error code to use in any returned errors.
1558
+ * @param tolerance - Sewing tolerance (default 1e-6).
1559
+ * @returns A `Result` wrapping the sewn shape, or an error.
1560
+ */
1561
+ function sewMeshToSolid(triangles, errorCode, tolerance = 1e-6) {
1562
+ const kernel = require_shapeTypes.getKernel();
1563
+ const triFaces = [];
1564
+ for (const [va, vb, vc] of triangles) {
1565
+ const triFace = kernel.buildTriFace(va, vb, vc);
1566
+ if (triFace !== null) triFaces.push(triFace);
1567
+ }
1568
+ if (triFaces.length === 0) return require_errors.err(require_errors.ioError(errorCode, "No valid triangular faces could be built"));
1569
+ try {
1570
+ return require_errors.ok(sewFacesIntoSolids(triFaces, tolerance));
1571
+ } catch (e) {
1572
+ return require_errors.err(require_errors.ioError(errorCode, "Failed to sew triangular faces", e));
1573
+ } finally {
1574
+ for (const triFace of triFaces) kernel.dispose(triFace);
1575
+ }
1576
+ }
1300
1577
  // src/io/importFns.ts
1301
1578
  /**
1302
1579
  * Functional file import operations using branded shape types.
@@ -1333,16 +1610,25 @@ async function importSTEP(blob) {
1333
1610
  return require_errors.err(require_errors.ioError("STEP_IMPORT_FAILED", "Failed to load STEP file", e));
1334
1611
  }
1335
1612
  }
1613
+ var STL_SEW_TOLERANCE = 1e-6;
1336
1614
  /**
1337
1615
  * Import an STL file from a Blob.
1338
1616
  *
1339
- * Reads the mesh, unifies same-domain faces with `ShapeUpgrade_UnifySameDomain`,
1340
- * and wraps the result as a solid.
1617
+ * Reads the triangle mesh and sews its facets together. A closed mesh becomes a
1618
+ * `Solid` (one planar face per facet), so booleans and volume measurement work on
1619
+ * it directly. An open mesh has no interior, so it comes back as a sewn `Shell`.
1620
+ * A file with several bodies comes back as a `Compound` holding a `Solid` per
1621
+ * closed body and a `Shell` per open one.
1341
1622
  *
1342
1623
  * @param blob - A Blob or File containing STL data (binary or ASCII).
1343
- * @returns A `Result` wrapping the imported solid, or an error if parsing fails.
1624
+ * @returns A `Result` wrapping the imported solid (a shell for an open mesh, a
1625
+ * compound for several bodies), or an error if parsing fails.
1344
1626
  *
1345
- * @remarks The temporary file on the WASM FS is cleaned up automatically.
1627
+ * @remarks Every triangle becomes its own B-Rep face, so import time grows with
1628
+ * the triangle count: on the default occt-wasm kernel, roughly 2.5 seconds per
1629
+ * 10,000 triangles (about 15 seconds for 50,000), and up to about twice that
1630
+ * when the file holds several bodies. The temporary file on the WASM FS is
1631
+ * cleaned up automatically.
1346
1632
  *
1347
1633
  * @example
1348
1634
  * ```ts
@@ -1351,10 +1637,21 @@ async function importSTEP(blob) {
1351
1637
  */
1352
1638
  async function importSTL(blob) {
1353
1639
  try {
1354
- const data = await blob.arrayBuffer();
1355
- const shape = require_shapeTypes.getKernel().importSTL(data);
1356
- if (shape.IsNull()) return require_errors.err(require_errors.ioError("STL_IMPORT_FAILED", "Failed to create solid from STL mesh"));
1357
- return require_errors.ok(require_shapeTypes.castResultShape(shape));
1640
+ try {
1641
+ var _usingCtx$1 = require_shapeTypes._usingCtx();
1642
+ const data = await blob.arrayBuffer();
1643
+ const raw = require_shapeTypes.getKernel().importSTL(data);
1644
+ if (raw.IsNull()) return require_errors.err(require_errors.ioError("STL_IMPORT_FAILED", "Failed to create solid from STL mesh"));
1645
+ const shape = require_shapeTypes.castResultShape(raw);
1646
+ if (require_shapeTypes.isSolid(shape)) return require_errors.ok(shape);
1647
+ const facets = _usingCtx$1.u(shape);
1648
+ const faces = require_topologyQueryFns.getFaces(facets).map((f) => f.wrapped);
1649
+ return require_errors.ok(sewFacesIntoSolids(faces, STL_SEW_TOLERANCE));
1650
+ } catch (_) {
1651
+ _usingCtx$1.e = _;
1652
+ } finally {
1653
+ _usingCtx$1.d();
1654
+ }
1358
1655
  } catch (e) {
1359
1656
  return require_errors.err(require_errors.ioError("STL_IMPORT_FAILED", "Failed to load STL file", e));
1360
1657
  }
@@ -1365,7 +1662,9 @@ async function importSTL(blob) {
1365
1662
  * @param blob - A Blob or File containing IGES data (.iges / .igs).
1366
1663
  * @returns A `Result` wrapping the imported shape, or an error if parsing fails.
1367
1664
  *
1368
- * @remarks The temporary file on the WASM FS is cleaned up automatically.
1665
+ * @remarks The temporary file on the WASM FS is cleaned up automatically. The
1666
+ * default occt-wasm kernel is built without an IGES translator, so there this
1667
+ * returns an `UNSUPPORTED_CAPABILITY` error; import STEP instead.
1369
1668
  *
1370
1669
  * @example
1371
1670
  * ```ts
@@ -1383,7 +1682,7 @@ async function importIGES(blob) {
1383
1682
  }
1384
1683
  return require_errors.ok(require_shapeTypes.castResultShape(shapes[0]));
1385
1684
  } catch (e) {
1386
- return require_errors.err(require_errors.ioError("IGES_IMPORT_FAILED", "Failed to load IGES file", e));
1685
+ return require_errors.err(require_meshFns.igesUnsupportedError("importIGES", e) ?? require_errors.ioError("IGES_IMPORT_FAILED", "Failed to load IGES file", e));
1387
1686
  }
1388
1687
  }
1389
1688
  Object.defineProperty(exports, "blueprintToDXF", {
@@ -1458,3 +1757,9 @@ Object.defineProperty(exports, "importSVGPathD", {
1458
1757
  return importSVGPathD;
1459
1758
  }
1460
1759
  });
1760
+ Object.defineProperty(exports, "sewMeshToSolid", {
1761
+ enumerable: true,
1762
+ get: function() {
1763
+ return sewMeshToSolid;
1764
+ }
1765
+ });