brepjs 20.13.3 → 20.13.5

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 (86) hide show
  1. package/dist/2d.cjs +6 -6
  2. package/dist/2d.js +6 -6
  3. package/dist/{adjacencyFns-BBugwmvl.cjs → adjacencyFns-B1ZWTkxw.cjs} +2 -2
  4. package/dist/{adjacencyFns-V29Gvfs9.js → adjacencyFns-XdjXKCXE.js} +2 -2
  5. package/dist/{blueprint-BO8zuqoy.cjs → blueprint-DzhzGFy2.cjs} +5 -5
  6. package/dist/{blueprint-CDmOJybf.js → blueprint-WAucCqwY.js} +5 -5
  7. package/dist/{blueprintFns-CEKZsu4N.js → blueprintFns-C8gt4OYm.js} +2 -2
  8. package/dist/{blueprintFns-Cki-iwEl.cjs → blueprintFns-DnzHyTjv.cjs} +2 -2
  9. package/dist/{blueprintSketcher-DG_2zJg7.js → blueprintSketcher-CeMrC8k-.js} +3 -3
  10. package/dist/{blueprintSketcher-Bxkp-vjK.cjs → blueprintSketcher-JoLn4vSB.cjs} +3 -3
  11. package/dist/{boolean2D-C_sEMz0u.cjs → boolean2D-Cwc_4mU8.cjs} +4 -4
  12. package/dist/{boolean2D-DqCcYA2X.js → boolean2D-D8_6vKh_.js} +4 -4
  13. package/dist/{booleanFns-CA9tvtqr.cjs → booleanFns-BhW5eybV.cjs} +5 -5
  14. package/dist/{booleanFns-CopMFBLS.js → booleanFns-aGRfk4ud.js} +5 -5
  15. package/dist/brepjs.cjs +29 -29
  16. package/dist/brepjs.js +29 -29
  17. package/dist/{cameraFns-BIIpsfds.js → cameraFns-CBc6tpRl.js} +3 -3
  18. package/dist/{cameraFns-BJ35ht2H.cjs → cameraFns-DhgM5-Nl.cjs} +3 -3
  19. package/dist/core/disposal.d.ts +4 -1
  20. package/dist/core.cjs +2 -2
  21. package/dist/core.js +2 -2
  22. package/dist/{cornerFinder-C8VCstc3.js → cornerFinder-ChkO3EOO.js} +1 -1
  23. package/dist/{cornerFinder-D83OLL_I.cjs → cornerFinder-xI6O0ZCv.cjs} +1 -1
  24. package/dist/{curveFns--TqXOi8f.js → curveFns-Cnh0Hljx.js} +1 -1
  25. package/dist/{curveFns-B29Eot3K.cjs → curveFns-Dz36SOE6.cjs} +1 -1
  26. package/dist/{drawFns-Bqs4HPzo.cjs → drawFns-BrRyiHKp.cjs} +12 -12
  27. package/dist/{drawFns-g9FrZ_P4.js → drawFns-RuUOUlSC.js} +12 -12
  28. package/dist/{faceFns-BeSpw0Dz.cjs → faceFns-DfEUZlnf.cjs} +2 -2
  29. package/dist/{faceFns-BzHfvPea.js → faceFns-Dz3eRgNR.js} +2 -2
  30. package/dist/{healingFns-DtefNa-x.js → healingFns-CCRPtrvE.js} +6 -6
  31. package/dist/{healingFns-BtZg6i3J.cjs → healingFns-D7LTrPO8.cjs} +6 -6
  32. package/dist/{helpers-CFEuQ0ok.cjs → helpers-C0MoldOO.cjs} +6 -6
  33. package/dist/{helpers-CHUowMmV.js → helpers-D3oo0Zfs.js} +6 -6
  34. package/dist/{importFns-BLaneR8r.js → importFns-BVcmm3T0.js} +5 -5
  35. package/dist/{importFns-BX0866c6.cjs → importFns-Sp5phi5Y.cjs} +5 -5
  36. package/dist/io.cjs +2 -2
  37. package/dist/io.js +2 -2
  38. package/dist/kernel/brepkit/brepkitWasmTypes.d.ts +20 -18
  39. package/dist/kernel/brepkit/helpers.d.ts +25 -4
  40. package/dist/{loftFns-Byjbneme.cjs → loftFns-BoGWrMPg.cjs} +1 -1
  41. package/dist/{loftFns-Cth8Le9X.js → loftFns-oH6dldzO.js} +1 -1
  42. package/dist/{measureFns-CLsSuByu.js → measureFns-6mHYvqUc.js} +3 -3
  43. package/dist/{measureFns-BlS2xJcn.cjs → measureFns-CmKNZ0gC.cjs} +3 -3
  44. package/dist/measurement.cjs +2 -2
  45. package/dist/measurement.js +2 -2
  46. package/dist/{meshFns-ECQqx-8Q.cjs → meshFns-BFgQZGty.cjs} +3 -3
  47. package/dist/{meshFns-CzpP9SBf.js → meshFns-D29JHTr6.js} +3 -3
  48. package/dist/operations.cjs +2 -2
  49. package/dist/operations.js +2 -2
  50. package/dist/{primitiveFns-CzhQz02F.cjs → primitiveFns-Dovused4.cjs} +5 -5
  51. package/dist/{primitiveFns-Kph3YP3A.js → primitiveFns-uywjJ06V.js} +5 -5
  52. package/dist/{principalBoxFns-C8ZmZNxJ.js → principalBoxFns-CTVc4f8W.js} +3 -3
  53. package/dist/{principalBoxFns-Ck9rR3Op.cjs → principalBoxFns-KvlaTxMs.cjs} +3 -3
  54. package/dist/projection.cjs +1 -1
  55. package/dist/projection.js +1 -1
  56. package/dist/query.cjs +2 -2
  57. package/dist/query.js +2 -2
  58. package/dist/{refResolveFns-CVUSuVee.cjs → refResolveFns-BFws5K2t.cjs} +6 -6
  59. package/dist/{refResolveFns-Cf16q6AH.js → refResolveFns-DZoPfglj.js} +6 -6
  60. package/dist/{shapeFns-BEwoFgq2.cjs → shapeFns-C9P1KmqH.cjs} +2 -2
  61. package/dist/{shapeFns-Bepwarf3.js → shapeFns-CHsoXWeu.js} +2 -2
  62. package/dist/shapeRef.cjs +1 -1
  63. package/dist/shapeRef.js +1 -1
  64. package/dist/{shapeTypes-CIw6-GFy.cjs → shapeTypes-BK53GmLC.cjs} +401 -59
  65. package/dist/{shapeTypes-hLHmANUz.js → shapeTypes-Ckz9bpYW.js} +401 -59
  66. package/dist/sketching.cjs +3 -3
  67. package/dist/sketching.js +3 -3
  68. package/dist/{solidBuilders-BVHK-era.cjs → solidBuilders-CETSjBW2.cjs} +3 -3
  69. package/dist/{solidBuilders-IA8xNuxJ.js → solidBuilders-DMfqtfIG.js} +3 -3
  70. package/dist/{surfaceBuilders-BYwkPzfM.js → surfaceBuilders-BeHgAqDx.js} +3 -3
  71. package/dist/{surfaceBuilders-DIM5GSAT.cjs → surfaceBuilders-vKXtKSqY.cjs} +3 -3
  72. package/dist/text.cjs +2 -2
  73. package/dist/text.js +2 -2
  74. package/dist/{textBlueprints-B4w-_4_D.js → textBlueprints-CLwy1uWM.js} +8 -8
  75. package/dist/{textBlueprints-CPJ6sBZZ.cjs → textBlueprints-DSiQKpe8.cjs} +8 -8
  76. package/dist/{textMetrics-na1BYw65.js → textMetrics-1e-VHhTX.js} +1 -1
  77. package/dist/{textMetrics-Dfr_9G6g.cjs → textMetrics-CzSpui4K.cjs} +1 -1
  78. package/dist/{threadFns-CAsRIX6c.cjs → threadFns-BEopBSv3.cjs} +7 -7
  79. package/dist/{threadFns-BEO0-PP6.js → threadFns-DveRUJwK.js} +7 -7
  80. package/dist/topology.cjs +9 -9
  81. package/dist/topology.js +9 -9
  82. package/dist/{topologyQueryFns-BNDmjz7x.cjs → topologyQueryFns--p_-tywe.cjs} +1 -1
  83. package/dist/{topologyQueryFns-BYqsNs6q.js → topologyQueryFns-SINsBrMe.js} +1 -1
  84. package/dist/{validityTypes-BYhzdgTM.js → validityTypes-BCZ8XRzO.js} +1 -1
  85. package/dist/{validityTypes-Gd5B_HcL.cjs → validityTypes-DPAkV5rC.cjs} +1 -1
  86. package/package.json +2 -2
@@ -5401,14 +5401,13 @@ var TAU$1 = 2 * Math.PI;
5401
5401
  /**
5402
5402
  * The frame of an analytic circle or ellipse edge, evaluated at t as
5403
5403
  * center + U·cos t + V·sin t, recovered from its points at 0, π/2 and π.
5404
- * brepkit reports such an edge's domain as exactly [0, 2π]; a NURBS edge that
5405
- * happens to be a circle reports its knot domain and gets no frame.
5404
+ * A NURBS edge that happens to be a circle reports CIRCLE too but runs over
5405
+ * its knots, so it gets no frame; only an analytic edge has no NURBS data.
5406
5406
  */
5407
5407
  function conicFrame(bk, edgeId) {
5408
- const params = bk.getEdgeCurveParameters(edgeId);
5409
- if (wasmIndex(params, 0) !== 0 || wasmIndex(params, 1) !== TAU$1) return void 0;
5410
5408
  const curveType = bk.getEdgeCurveType(edgeId);
5411
5409
  if (curveType !== "CIRCLE" && curveType !== "ELLIPSE") return void 0;
5410
+ if (bk.getEdgeNurbsData(edgeId) !== null) return void 0;
5412
5411
  const at = (t) => {
5413
5412
  const p = bk.evaluateEdgeCurve(edgeId, t);
5414
5413
  return [
@@ -5452,10 +5451,11 @@ function edgeEnds(bk, edgeId) {
5452
5451
  ]];
5453
5452
  }
5454
5453
  /**
5455
- * The curve parameters an edge spans. brepkit reports a circle or ellipse edge's
5456
- * domain as the whole [0, 2π] even for an arc; the arc runs counterclockwise
5457
- * about the curve's axis from the angle of its start vertex to that of its end
5458
- * vertex (brepkit's own `circle_param_range`), angles read off the curve's frame.
5454
+ * The curve parameters an edge spans. brepkit before 4.5.10 reports a circle or
5455
+ * ellipse edge's domain as the whole [0, 2π] even for an arc, so an arc's span
5456
+ * is read off the curve's frame on every kernel: it runs counterclockwise about
5457
+ * the curve's axis from the angle of its start vertex to that of its end vertex
5458
+ * (brepkit's own `circle_param_range`).
5459
5459
  */
5460
5460
  function edgeParamRange(bk, edgeId) {
5461
5461
  const params = bk.getEdgeCurveParameters(edgeId);
@@ -5717,6 +5717,35 @@ function nextSyntheticId() {
5717
5717
  }
5718
5718
  /** JS-side storage for compound children (wires, faces, edges). */
5719
5719
  var syntheticCompounds = /* @__PURE__ */ new Map();
5720
+ /**
5721
+ * Each solid's piece ids, per kernel. getSolidPieces builds new solids and
5722
+ * shells for a solid in several pieces on every call, and the arena frees
5723
+ * nothing one handle at a time, so a solid is split once and its pieces keep
5724
+ * one identity until the solid changes in place or the arena rolls back.
5725
+ */
5726
+ var solidPiecesByKernel = /* @__PURE__ */ new WeakMap();
5727
+ /** A solid's piece ids, from `split` the first time they are asked for. */
5728
+ function cachedSolidPieces(bk, solidId, split) {
5729
+ let known = solidPiecesByKernel.get(bk);
5730
+ if (!known) {
5731
+ known = /* @__PURE__ */ new Map();
5732
+ solidPiecesByKernel.set(bk, known);
5733
+ }
5734
+ const cached = known.get(solidId);
5735
+ if (cached) return cached;
5736
+ const pieces = split();
5737
+ known.set(solidId, pieces);
5738
+ for (const piece of pieces) if (!known.has(piece)) known.set(piece, [piece]);
5739
+ return pieces;
5740
+ }
5741
+ /**
5742
+ * Forget one solid's pieces after the kernel changes it in place, or every
5743
+ * solid's after the arena rolls back and its ids can name new entities.
5744
+ */
5745
+ function forgetSolidPieces(bk, solidId) {
5746
+ if (solidId === void 0) solidPiecesByKernel.delete(bk);
5747
+ else solidPiecesByKernel.get(bk)?.delete(solidId);
5748
+ }
5720
5749
  var _warned = /* @__PURE__ */ new Set();
5721
5750
  /** Emit a console.warn once per key per session. */
5722
5751
  function warnOnce(key, message) {
@@ -5764,17 +5793,35 @@ function resolveUniformAngle(faces, angleDeg) {
5764
5793
  return uniform;
5765
5794
  }
5766
5795
  // src/kernel/brepkit/topologyOps.ts
5796
+ /**
5797
+ * One solid per separate piece of material in a solid: a boolean can leave
5798
+ * several pieces in one kernel solid, all in one shell. A solid in one piece
5799
+ * keeps its own handle, since the kernel answers a solid whose cavity shares
5800
+ * its shell with a rebuilt one.
5801
+ */
5802
+ function solidPieces(bk, solid) {
5803
+ if (typeof bk.getSolidPieces !== "function") return [solid];
5804
+ const id = unwrap$1(solid, "solid");
5805
+ const pieces = cachedSolidPieces(bk, id, () => {
5806
+ const found = toArray(bk.getSolidPieces(id));
5807
+ return found.length > 1 ? found : [id];
5808
+ });
5809
+ return pieces.length > 1 ? pieces.map(solidHandle) : [solid];
5810
+ }
5767
5811
  function iterCompound(bk, h, type) {
5768
5812
  const children = syntheticCompounds.get(h);
5769
- if (children) return children.flatMap((child) => child.type === type ? [child] : iterShapes$1(bk, child, type));
5770
- if (type === "solid") return toArray(bk.getCompoundSolids(h)).map(solidHandle);
5813
+ if (children) return children.flatMap((child) => {
5814
+ if (child.type === "solid" && type === "solid") return solidPieces(bk, child);
5815
+ return child.type === type ? [child] : iterShapes$1(bk, child, type);
5816
+ });
5817
+ if (type === "solid") return toArray(bk.getCompoundSolids(h)).flatMap((id) => solidPieces(bk, solidHandle(id)));
5771
5818
  if (type === "face" || type === "edge" || type === "vertex" || type === "wire") return toArray(bk.getCompoundSolids(h)).map(solidHandle).flatMap((s) => iterShapes$1(bk, s, type));
5772
5819
  return [];
5773
5820
  }
5774
5821
  function iterSolid(bk, shape, h, type) {
5775
5822
  switch (type) {
5776
- case "solid": return [shape];
5777
- case "shell": return toArray(bk.getSolidShells(h)).map(shellHandle);
5823
+ case "solid": return solidPieces(bk, shape);
5824
+ case "shell": return solidPieces(bk, shape).flatMap((piece) => toArray(bk.getSolidShells(unwrap$1(piece, "solid"))).map(shellHandle));
5778
5825
  case "face": return toArray(bk.getSolidFaces(h)).map(faceHandle);
5779
5826
  case "edge": return toArray(bk.getSolidEdges(h)).map(edgeHandle);
5780
5827
  case "vertex": return toArray(bk.getSolidVertices(h)).map(vertexHandle);
@@ -5910,12 +5957,23 @@ function faceIdsForSew(bk, shape) {
5910
5957
  function sew(bk, shapes, tolerance) {
5911
5958
  const faceIds = shapes.flatMap((s) => faceIdsForSew(bk, s));
5912
5959
  const tol = tolerance ?? 1e-7;
5960
+ let solidId;
5913
5961
  try {
5914
- return shellHandle(bk.weldShellsAndFaces(faceIds, tol));
5962
+ solidId = bk.weldShellsAndFaces(faceIds, tol);
5915
5963
  } catch (e) {
5916
5964
  console.warn("brepkit: weldShellsAndFaces failed, falling back to sewFaces:", e);
5965
+ solidId = bk.sewFaces(faceIds, tol);
5917
5966
  }
5918
- return shellHandle(bk.sewFaces(faceIds, tol));
5967
+ return sewnShell(bk, solidId);
5968
+ }
5969
+ /**
5970
+ * Both sewing bindings wrap the one shell they sew in a solid and return the
5971
+ * solid's handle; the shell has its own, which shell queries need.
5972
+ */
5973
+ function sewnShell(bk, solidId) {
5974
+ const [shellId] = toArray(bk.getSolidShells(solidId));
5975
+ if (shellId === void 0) throw new Error("brepkit: sewing returned a solid with no shell");
5976
+ return shellHandle(shellId);
5919
5977
  }
5920
5978
  /** Co-located factory: returns the topology-iteration slice of {@link KernelAdapter} bound to `bk`. */
5921
5979
  function makeTopologyOps$1(bk) {
@@ -6174,33 +6232,76 @@ function recognizeFeatures(bk, shape, tolerance) {
6174
6232
  const solidId = unwrapSolidOrThrow(shape, "recognizeFeatures");
6175
6233
  return bk.recognizeFeatures(solidId, tolerance);
6176
6234
  }
6177
- function projectEdges(bk, shape, cameraOrigin, cameraDirection, cameraXAxis) {
6178
- const solidId = unwrap$1(shape);
6179
- const [ox, oy, oz] = cameraOrigin;
6180
- const [dx, dy, dz] = cameraDirection;
6181
- const [xx, xy, xz] = cameraXAxis ?? [
6182
- 1,
6183
- 0,
6184
- 0
6235
+ /** The solids whose edges a projection draws: a solid itself, or every solid of a compound. */
6236
+ function projectedSolidIds(bk, shape) {
6237
+ const h = shape;
6238
+ if (h.type === "solid") return [h.id];
6239
+ const ids = h.type === "compound" ? iterShapes$1(bk, shape, "solid").map((s) => unwrap$1(s)) : [];
6240
+ if (ids.length === 0) throw new Error(`brepkit: projectEdges needs a solid or a compound of solids, got ${h.type}`);
6241
+ return ids;
6242
+ }
6243
+ /**
6244
+ * brepkit returns polyline approximations of the projection, so tie the
6245
+ * tessellation deflection to model scale (1/1000 of the bbox diagonal) to
6246
+ * stay resolution-independent across part sizes.
6247
+ */
6248
+ function projectionDeflection(bk, solidIds) {
6249
+ const min = [
6250
+ Infinity,
6251
+ Infinity,
6252
+ Infinity
6253
+ ];
6254
+ const max = [
6255
+ -Infinity,
6256
+ -Infinity,
6257
+ -Infinity
6185
6258
  ];
6186
- let deflection = .1;
6187
6259
  try {
6188
- const bb = bk.boundingBox(solidId);
6189
- const [minX, minY, minZ] = vec3At(bb, 0);
6190
- const [maxX, maxY, maxZ] = vec3At(bb, 3);
6191
- const diag = dist3(minX, minY, minZ, maxX, maxY, maxZ);
6192
- if (diag > 0) deflection = Math.max(diag * .001, 1e-6);
6193
- } catch {}
6194
- const json = bk.projectEdges(solidId, ox, oy, oz, dx, dy, dz, xx, xy, xz, true, deflection);
6195
- let parsed;
6260
+ for (const id of solidIds) {
6261
+ const bb = bk.boundingBox(id);
6262
+ for (let k = 0; k < 3; k++) {
6263
+ min[k] = Math.min(wasmIndex(min, k), wasmIndex(bb, k));
6264
+ max[k] = Math.max(wasmIndex(max, k), wasmIndex(bb, k + 3));
6265
+ }
6266
+ }
6267
+ } catch {
6268
+ return .1;
6269
+ }
6270
+ const diag = dist3(...min, ...max);
6271
+ return diag > 0 ? Math.max(diag * .001, 1e-6) : .1;
6272
+ }
6273
+ function parseProjection(json) {
6196
6274
  try {
6197
- parsed = JSON.parse(json);
6275
+ return JSON.parse(json);
6198
6276
  } catch {
6199
- parsed = {
6277
+ return {
6200
6278
  visible: [],
6201
6279
  hidden: []
6202
6280
  };
6203
6281
  }
6282
+ }
6283
+ /** Each solid's edges, hidden wherever any of the solids lies in front of them. */
6284
+ function projectSolids(bk, solidIds, view) {
6285
+ const deflection = projectionDeflection(bk, solidIds);
6286
+ const [only, ...others] = solidIds;
6287
+ if (only !== void 0 && others.length === 0) return parseProjection(bk.projectEdges(only, ...view, true, deflection));
6288
+ if (typeof bk.projectSolidsEdges === "function") return parseProjection(bk.projectSolidsEdges(solidIds, ...view, true, deflection));
6289
+ const parts = solidIds.map((id) => parseProjection(bk.projectEdges(id, ...view, true, deflection)));
6290
+ return {
6291
+ visible: parts.flatMap((p) => p.visible),
6292
+ hidden: parts.flatMap((p) => p.hidden)
6293
+ };
6294
+ }
6295
+ function projectEdges(bk, shape, cameraOrigin, cameraDirection, cameraXAxis) {
6296
+ const parsed = projectSolids(bk, projectedSolidIds(bk, shape), [
6297
+ ...cameraOrigin,
6298
+ ...cameraDirection,
6299
+ ...cameraXAxis ?? [
6300
+ 1,
6301
+ 0,
6302
+ 0
6303
+ ]
6304
+ ]);
6204
6305
  const polylinesToCompound = (polylines) => {
6205
6306
  const edges = [];
6206
6307
  for (const poly of polylines) for (let i = 0; i + 3 < poly.length; i += 2) {
@@ -6592,6 +6693,7 @@ function isValidStrict(bk, shape) {
6592
6693
  function healSolid(bk, shape) {
6593
6694
  const h = shape;
6594
6695
  if (h.type !== "solid") throw new Error(`brepkit: healSolid requires a solid, got ${h.type}. Consider using makeCompound() to combine shapes first.`);
6696
+ forgetSolidPieces(bk, h.id);
6595
6697
  try {
6596
6698
  const remaining = bk.repairSolid(unwrap$1(shape));
6597
6699
  if (remaining > 0) console.warn(`brepkit: repairSolid left ${remaining} error(s) on solid.`);
@@ -6614,19 +6716,25 @@ function healWire(_bk, wire, _face) {
6614
6716
  }
6615
6717
  function mergeCoincidentVertices(bk, shape, tolerance) {
6616
6718
  const solidId = unwrapSolidOrThrow(shape, "mergeCoincidentVertices");
6719
+ forgetSolidPieces(bk, solidId);
6617
6720
  return bk.mergeCoincidentVertices(solidId, tolerance);
6618
6721
  }
6619
6722
  function removeDegenerateEdges(bk, shape, tolerance) {
6620
6723
  const solidId = unwrapSolidOrThrow(shape, "removeDegenerateEdges");
6724
+ forgetSolidPieces(bk, solidId);
6621
6725
  return bk.removeDegenerateEdges(solidId, tolerance);
6622
6726
  }
6623
6727
  function fixFaceOrientations(bk, shape) {
6624
6728
  const solidId = unwrapSolidOrThrow(shape, "fixFaceOrientations");
6729
+ forgetSolidPieces(bk, solidId);
6625
6730
  return bk.fixFaceOrientations(solidId);
6626
6731
  }
6627
6732
  function fixShape(bk, shape) {
6628
6733
  const h = shape;
6629
- if (h.type === "solid") bk.healSolid(h.id);
6734
+ if (h.type === "solid") {
6735
+ forgetSolidPieces(bk, h.id);
6736
+ bk.healSolid(h.id);
6737
+ }
6630
6738
  return shape;
6631
6739
  }
6632
6740
  function fixSelfIntersection(_bk, wire) {
@@ -6973,7 +7081,7 @@ function makeWire(bk, edges) {
6973
7081
  if (h.type === "wire") for (const childEdgeId of toArray(bk.getWireEdges(h.id))) edgeIds.push(childEdgeId);
6974
7082
  else edgeIds.push(unwrap$1(e, "edge"));
6975
7083
  }
6976
- return wireHandle(bk.makeWire(edgeIds, true));
7084
+ return wireHandle(bk.makeWire(chainEdges$1(bk, edgeIds), true));
6977
7085
  }
6978
7086
  function makeFace(bk, wire, planar) {
6979
7087
  const h = wire;
@@ -7197,10 +7305,110 @@ function makeWireFromMixed(bk, items) {
7197
7305
  else if (h.type === "wire") for (const childEdgeId of toArray(bk.getWireEdges(h.id))) edgeIds.push(childEdgeId);
7198
7306
  }
7199
7307
  if (edgeIds.length === 0) throw new Error("brepkit: makeWireFromMixed requires at least one edge");
7200
- return wireHandle(bk.makeWire(edgeIds, chainCloses(bk, edgeIds)));
7308
+ const chain = chainEdges$1(bk, edgeIds);
7309
+ return wireHandle(bk.makeWire(chain, chainCloses(bk, chain)));
7201
7310
  }
7202
7311
  /** Matches the 1e-7 linear tolerance brepkit's makeWire welds vertices within. */
7203
7312
  var WIRE_CLOSE_TOLERANCE = 1e-7;
7313
+ /**
7314
+ * The edges in an order where each starts where the one before ends, any edge
7315
+ * running the other way rebuilt to run on. brepkit's makeWire takes each edge
7316
+ * as it runs and a face refuses a wire whose edges do not run end to end, so a
7317
+ * profile closed by its mirror image, whose edges leave from the first half's
7318
+ * start, needs that half turned round. Edges that make no single chain, or
7319
+ * that cannot be rebuilt, come back as given.
7320
+ */
7321
+ function chainEdges$1(bk, edgeIds) {
7322
+ const [first, ...left] = edgeIds;
7323
+ if (first === void 0 || left.length === 0) return edgeIds;
7324
+ const ends = new Map(left.map((id) => [id, edgeEnds(bk, id)]));
7325
+ let [head, tail] = edgeEnds(bk, first);
7326
+ const chain = [first];
7327
+ while (left.length > 0) {
7328
+ const after = takeLink(bk, left, ends, tail, "start");
7329
+ if (after) {
7330
+ chain.push(after.id);
7331
+ tail = after.free;
7332
+ continue;
7333
+ }
7334
+ const before = takeLink(bk, left, ends, head, "end");
7335
+ if (!before) return edgeIds;
7336
+ chain.unshift(before.id);
7337
+ head = before.free;
7338
+ }
7339
+ return chain;
7340
+ }
7341
+ /**
7342
+ * Take from `left` the first edge with an end at `at`, to join the chain there
7343
+ * by its `side` end; an edge that meets `at` with its other end is rebuilt to
7344
+ * run the other way. Returns the joining edge and the end it leaves free.
7345
+ */
7346
+ function takeLink(bk, left, ends, at, side) {
7347
+ const touches = (p) => dist3(...p, ...at) < WIRE_CLOSE_TOLERANCE;
7348
+ for (const [i, id] of left.entries()) {
7349
+ const edge = ends.get(id);
7350
+ if (!edge) continue;
7351
+ const [start, end] = edge;
7352
+ const [joins, free] = side === "start" ? [start, end] : [end, start];
7353
+ if (touches(joins)) {
7354
+ left.splice(i, 1);
7355
+ return {
7356
+ id,
7357
+ free
7358
+ };
7359
+ }
7360
+ if (touches(free)) {
7361
+ const turned = reversedEdge(bk, id, start, end);
7362
+ if (turned === void 0) return void 0;
7363
+ left.splice(i, 1);
7364
+ return {
7365
+ id: turned,
7366
+ free: joins
7367
+ };
7368
+ }
7369
+ }
7370
+ }
7371
+ /**
7372
+ * A new edge on the same curve, running from `end` to `start`, or `undefined`
7373
+ * for a curve the adapter cannot rebuild.
7374
+ */
7375
+ function reversedEdge(bk, id, start, end) {
7376
+ const nurbs = bk.getEdgeNurbsData(id);
7377
+ if (nurbs !== null) return reversedNurbsEdge(bk, nurbs, start, end);
7378
+ const curveType = bk.getEdgeCurveType(id);
7379
+ if (curveType === "LINE") return bk.makeLineEdge(...end, ...start);
7380
+ const frame = conicFrame(bk, id);
7381
+ if (!frame) return void 0;
7382
+ const { center, u, v } = frame;
7383
+ const n = [
7384
+ v[1] * u[2] - v[2] * u[1],
7385
+ v[2] * u[0] - v[0] * u[2],
7386
+ v[0] * u[1] - v[1] * u[0]
7387
+ ];
7388
+ const nLen = Math.hypot(...n);
7389
+ const axis = [
7390
+ n[0] / nLen,
7391
+ n[1] / nLen,
7392
+ n[2] / nLen
7393
+ ];
7394
+ if (curveType === "CIRCLE") return bk.makeCircleArc3d(...end, ...start, ...center, ...axis);
7395
+ const major = Math.hypot(...u);
7396
+ const ref = [
7397
+ u[0] / major,
7398
+ u[1] / major,
7399
+ u[2] / major
7400
+ ];
7401
+ return bk.makeEllipseArc3d(...end, ...start, ...center, ...axis, ...ref, major, Math.hypot(...v));
7402
+ }
7403
+ function reversedNurbsEdge(bk, json, start, end) {
7404
+ const data = JSON.parse(json);
7405
+ const lo = wasmIndex(data.knots, 0);
7406
+ const hi = wasmIndex(data.knots, data.knots.length - 1);
7407
+ const knots = data.knots.map((k) => lo + hi - k).reverse();
7408
+ const poles = [];
7409
+ for (let i = data.controlPoints.length - 3; i >= 0; i -= 3) poles.push(...data.controlPoints.slice(i, i + 3));
7410
+ return bk.makeNurbsEdge(...end, ...start, data.degree, knots, poles, [...data.weights].reverse());
7411
+ }
7204
7412
  function chainCloses(bk, edgeIds) {
7205
7413
  const first = bk.getEdgeVertices(wasmIndex(edgeIds, 0));
7206
7414
  const last = bk.getEdgeVertices(wasmIndex(edgeIds, edgeIds.length - 1));
@@ -7239,15 +7447,7 @@ function makeBoxFromCorners(bk, p1, p2) {
7239
7447
  return box;
7240
7448
  }
7241
7449
  function solidFromShell(bk, shell) {
7242
- const h = shell;
7243
- if (h.type === "solid") return shell;
7244
- if (h.type === "shell") {
7245
- try {
7246
- bk.getSolidFaces(h.id);
7247
- return solidHandle(h.id);
7248
- } catch {}
7249
- return solidHandle(bk.solidFromShell(h.id));
7250
- }
7450
+ if (shell.type === "solid") return shell;
7251
7451
  return solidHandle(bk.solidFromShell(unwrap$1(shell, "shell")));
7252
7452
  }
7253
7453
  function makeNonPlanarFace(bk, wire) {
@@ -7941,10 +8141,13 @@ function offsetWire2D(bk, wire, offsetVal, joinType) {
7941
8141
  return wireHandle(bk.makePolygonWire(coords3d));
7942
8142
  }
7943
8143
  function simplify$1(bk, shape) {
7944
- if (shape.type === "solid") try {
7945
- bk.healSolid(unwrap$1(shape));
7946
- } catch (e) {
7947
- console.warn("brepkit: healing failed in simplify:", e);
8144
+ if (shape.type === "solid") {
8145
+ forgetSolidPieces(bk, unwrap$1(shape));
8146
+ try {
8147
+ bk.healSolid(unwrap$1(shape));
8148
+ } catch (e) {
8149
+ console.warn("brepkit: healing failed in simplify:", e);
8150
+ }
7948
8151
  }
7949
8152
  return shape;
7950
8153
  }
@@ -10190,7 +10393,7 @@ function area$1(bk, shape) {
10190
10393
  const h = shape;
10191
10394
  if (h.type === "face") return bk.faceArea(unwrap$1(shape), DEFAULT_DEFLECTION);
10192
10395
  if (h.type === "solid") return bk.surfaceArea(unwrap$1(shape), DEFAULT_DEFLECTION);
10193
- if (h.type === "compound") {
10396
+ if (h.type === "compound" || h.type === "shell") {
10194
10397
  const faces = iterShapes$1(bk, shape, "face");
10195
10398
  let total = 0;
10196
10399
  for (const face of faces) total += bk.faceArea(unwrap$1(face), DEFAULT_DEFLECTION);
@@ -10275,9 +10478,10 @@ function boundingBox$1(bk, shape) {
10275
10478
  };
10276
10479
  }
10277
10480
  /**
10278
- * Points whose bounding box is the shape's: a solid's own box corners, and for
10279
- * anything else the box points of its edges (see `edgeBoxPoints`), so an arc's
10280
- * bulge counts and not just its end vertices.
10481
+ * Points whose bounding box is the shape's: a solid's own box corners, a
10482
+ * face's or shell's face box points (see `faceBoxPoints`), and for anything
10483
+ * else the box points of its edges (see `edgeBoxPoints`), so an arc's bulge
10484
+ * counts and not just its end vertices.
10281
10485
  */
10282
10486
  function boxPoints(bk, h) {
10283
10487
  switch (h.type) {
@@ -10287,13 +10491,141 @@ function boxPoints(bk, h) {
10287
10491
  }
10288
10492
  case "vertex": return [vec3At(bk.getVertexPosition(h.id))];
10289
10493
  case "edge": return edgeBoxPoints(bk, h.id);
10494
+ case "face": return faceBoxPoints(bk, h);
10495
+ case "shell": return iterShapes$1(bk, h, "face").flatMap((f) => faceBoxPoints(bk, f));
10290
10496
  case "compound": return (syntheticCompounds.get(h.id) ?? compoundSolidIds(bk, h.id).map(solidHandle)).flatMap((child) => boxPoints(bk, child));
10291
- default: {
10292
- const edges = iterShapes$1(bk, h, "edge");
10293
- if (edges.length > 0) return edges.flatMap((e) => edgeBoxPoints(bk, unwrap$1(e)));
10294
- return iterShapes$1(bk, h, "vertex").map((v) => vertexPosition(bk, v));
10497
+ default: return boundaryBoxPoints(bk, h);
10498
+ }
10499
+ }
10500
+ function boundaryBoxPoints(bk, h) {
10501
+ const edges = iterShapes$1(bk, h, "edge");
10502
+ if (edges.length > 0) return edges.flatMap((e) => edgeBoxPoints(bk, unwrap$1(e)));
10503
+ return iterShapes$1(bk, h, "vertex").map((v) => vertexPosition(bk, v));
10504
+ }
10505
+ /**
10506
+ * A face's extreme along an axis lies on its boundary or at a point inside it
10507
+ * where that coordinate peaks on the surface. Planes, cylinders, and cones have
10508
+ * no such interior peak (a straight line through any inner point runs to the
10509
+ * boundary), so their edges bound them. A sphere or torus adds the surface's
10510
+ * peak points that lie on the face, which bounds it exactly; any other surface
10511
+ * adds the vertices of its tessellation, which bound it to within the
10512
+ * deflection.
10513
+ */
10514
+ function faceBoxPoints(bk, face) {
10515
+ const points = boundaryBoxPoints(bk, face);
10516
+ const surfaceType = bk.getSurfaceType(face.id);
10517
+ if (surfaceType === "plane" || surfaceType === "cylinder" || surfaceType === "cone") return points;
10518
+ const peaks = surfacePeaks(bk, face.id);
10519
+ if (peaks) {
10520
+ const tolerance = ON_FACE_TOLERANCE * Math.max(1, peaks.size);
10521
+ const onFace = (p) => wasmIndex(bk.pointToFaceDistance(p[0], p[1], p[2], face.id), 0) <= tolerance;
10522
+ return [...points, ...peaks.points.filter(onFace)];
10523
+ }
10524
+ const { positions } = bk.tessellateFace(face.id, MESH_BOX_DEFLECTION * (diagonal(points) || 1));
10525
+ const vertices = [];
10526
+ for (let i = 0; i + 2 < positions.length; i += 3) vertices.push(vec3At(positions, i));
10527
+ return [...points, ...vertices];
10528
+ }
10529
+ var ON_FACE_TOLERANCE = 1e-7;
10530
+ var MESH_BOX_DEFLECTION = .001;
10531
+ var TORUS_CIRCLE_SAMPLES = 64;
10532
+ var AXES = [
10533
+ [
10534
+ 1,
10535
+ 0,
10536
+ 0
10537
+ ],
10538
+ [
10539
+ 0,
10540
+ 1,
10541
+ 0
10542
+ ],
10543
+ [
10544
+ 0,
10545
+ 0,
10546
+ 1
10547
+ ]
10548
+ ];
10549
+ function diagonal(points) {
10550
+ if (points.length === 0) return 0;
10551
+ const span = [
10552
+ 0,
10553
+ 1,
10554
+ 2
10555
+ ].map((k) => {
10556
+ const values = points.map((p) => wasmIndex(p, k));
10557
+ return Math.max(...values) - Math.min(...values);
10558
+ });
10559
+ return Math.hypot(...span);
10560
+ }
10561
+ var add$1 = (a, b, s = 1) => [
10562
+ a[0] + s * b[0],
10563
+ a[1] + s * b[1],
10564
+ a[2] + s * b[2]
10565
+ ];
10566
+ var dot$1 = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
10567
+ /**
10568
+ * The points where a coordinate peaks on a sphere or torus surface, with the
10569
+ * surface's size for the on-face tolerance; undefined for any other surface or
10570
+ * a torus whose frame does not read back as orthonormal.
10571
+ */
10572
+ function surfacePeaks(bk, faceId) {
10573
+ let params;
10574
+ try {
10575
+ params = JSON.parse(bk.getAnalyticSurfaceParams(faceId));
10576
+ } catch {
10577
+ return;
10578
+ }
10579
+ const c = params.center;
10580
+ if (c?.length !== 3) return void 0;
10581
+ if (params.type === "sphere" && typeof params.radius === "number") {
10582
+ const r = params.radius;
10583
+ return {
10584
+ points: AXES.flatMap((e) => [add$1(c, e, r), add$1(c, e, -r)]),
10585
+ size: r
10586
+ };
10587
+ }
10588
+ if (params.type === "torus" && typeof params.majorRadius === "number" && typeof params.minorRadius === "number") return torusPeaks(bk, faceId, c, params.majorRadius, params.minorRadius);
10589
+ }
10590
+ /**
10591
+ * brepkit's torus params carry no axis, so the frame is read off the surface,
10592
+ * which brepkit parametrizes as c + (R + r cos v)(cos u X + sin u Y) + r sin v Z.
10593
+ * Along a direction d with a component w across the axis, the coordinate peaks
10594
+ * at c ± (R w/|w| + r d). Along the axis it peaks on the whole circle at c ± r Z,
10595
+ * which is sampled.
10596
+ */
10597
+ function torusPeaks(bk, faceId, c, majorR, minorR) {
10598
+ const at = (u, v) => vec3At(bk.evaluateSurface(faceId, u, v));
10599
+ const x = add$1(at(0, 0), c, -1).map((n) => n / (majorR + minorR));
10600
+ const z = add$1(add$1(at(0, Math.PI / 2), c, -1), x, -majorR).map((n) => n / minorR);
10601
+ const unit = (p) => Math.abs(Math.hypot(...p) - 1) < 1e-6;
10602
+ if (!unit(x) || !unit(z) || Math.abs(dot$1(x, z)) > 1e-6) return void 0;
10603
+ const y = [
10604
+ z[1] * x[2] - z[2] * x[1],
10605
+ z[2] * x[0] - z[0] * x[2],
10606
+ z[0] * x[1] - z[1] * x[0]
10607
+ ];
10608
+ const points = [];
10609
+ for (const d of AXES) {
10610
+ const across = add$1(d, z, -dot$1(d, z));
10611
+ const len = Math.hypot(...across);
10612
+ if (len > 1e-9) {
10613
+ const peak = add$1(across.map((n) => n * majorR / len), d, minorR);
10614
+ points.push(add$1(c, peak), add$1(c, peak, -1));
10615
+ continue;
10616
+ }
10617
+ for (const side of [1, -1]) {
10618
+ const rim = add$1(c, z, side * minorR);
10619
+ for (let i = 0; i < TORUS_CIRCLE_SAMPLES; i++) {
10620
+ const t = 2 * Math.PI * i / TORUS_CIRCLE_SAMPLES;
10621
+ points.push(add$1(add$1(rim, x, majorR * Math.cos(t)), y, majorR * Math.sin(t)));
10622
+ }
10295
10623
  }
10296
10624
  }
10625
+ return {
10626
+ points,
10627
+ size: majorR + minorR
10628
+ };
10297
10629
  }
10298
10630
  /**
10299
10631
  * Minimum distance between two shapes. brepkit-wasm measures from a point to a
@@ -10738,11 +11070,18 @@ function makeSweepOps$1(bk) {
10738
11070
  function makeCoreOps$1(bk) {
10739
11071
  return {
10740
11072
  dispose: () => {},
10741
- executeBatch: (json) => bk.executeBatch(json),
11073
+ executeBatch: (json) => {
11074
+ try {
11075
+ return bk.executeBatch(json);
11076
+ } finally {
11077
+ forgetSolidPieces(bk);
11078
+ }
11079
+ },
10742
11080
  checkpoint: () => bk.checkpoint(),
10743
11081
  checkpointCount: () => bk.checkpointCount(),
10744
11082
  restoreCheckpoint: (cp) => {
10745
11083
  bk.restore(cp);
11084
+ forgetSolidPieces(bk);
10746
11085
  },
10747
11086
  discardCheckpoint: (cp) => {
10748
11087
  bk.discardCheckpoint(cp);
@@ -17106,7 +17445,10 @@ function createBorrowedHandle(ocShape) {
17106
17445
  * frees *every* slot allocated after the checkpoint, so a live shape handle in
17107
17446
  * the return value would dangle. Use for data-returning batch analysis over many
17108
17447
  * bodies; never to wrap a shape builder. Inputs allocated before the call are
17109
- * untouched (restore only frees from the mark forward).
17448
+ * untouched (restore only frees from the mark forward), but `fn` must not query
17449
+ * their cached topology (`getFaces`, `getSolids`, adjacency): the cache keeps the
17450
+ * sub-shape handles it allocates, and the restore would leave it holding freed
17451
+ * slots.
17110
17452
  *
17111
17453
  * No-op wrapper on kernels without arena checkpoints (occt/manifold): `fn` runs
17112
17454
  * directly and those kernels' own disposal applies.
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_blueprintSketcher = require("./blueprintSketcher-Bxkp-vjK.cjs");
3
- const require_drawFns = require("./drawFns-Bqs4HPzo.cjs");
4
- const require_textBlueprints = require("./textBlueprints-CPJ6sBZZ.cjs");
2
+ const require_blueprintSketcher = require("./blueprintSketcher-JoLn4vSB.cjs");
3
+ const require_drawFns = require("./drawFns-BrRyiHKp.cjs");
4
+ const require_textBlueprints = require("./textBlueprints-DSiQKpe8.cjs");
5
5
  // src/sketching.ts
6
6
  /**
7
7
  * brepjs/sketching — Sketcher, Drawing, and sketch-to-shape operations.
package/dist/sketching.js CHANGED
@@ -1,6 +1,6 @@
1
- import { n as BaseSketcher2d, t as BlueprintSketcher } from "./blueprintSketcher-DG_2zJg7.js";
2
- import { A as sketchEllipse, C as DrawingPen, D as makeBaseBox, E as deserializeDrawing, F as sketchRectangle, I as sketchRoundedRectangle, L as FaceSketcher, M as sketchHelix, N as sketchParametricFunction, O as polysideInnerRadius, P as sketchPolysides, R as Sketcher, S as drawText, T as Drawing, _ as drawPolysides, a as drawingIntersect, b as drawSingleCircle, c as rotateDrawing, d as drawFaceOutline, f as drawProjection, g as drawPointsInterpolation, h as drawParametricFunction, i as drawingFuse, j as sketchFaceOffset, k as sketchCircle, l as scaleDrawing, m as drawEllipse, n as drawingCut, o as drawingToSketchOnPlane, p as drawCircle, r as drawingFillet, s as mirrorDrawing, t as drawingChamfer, u as translateDrawing, v as drawRectangle, w as draw, x as drawSingleEllipse, y as drawRoundedRectangle } from "./drawFns-g9FrZ_P4.js";
3
- import { a as Sketches, c as compoundSketchFace, d as sketchExtrude, f as sketchFace, g as sketchWires, h as sketchSweep, l as compoundSketchLoft, m as sketchRevolve, o as Sketch, p as sketchLoft, s as compoundSketchExtrude, u as compoundSketchRevolve, y as CompoundSketch } from "./textBlueprints-B4w-_4_D.js";
1
+ import { n as BaseSketcher2d, t as BlueprintSketcher } from "./blueprintSketcher-CeMrC8k-.js";
2
+ import { A as sketchEllipse, C as DrawingPen, D as makeBaseBox, E as deserializeDrawing, F as sketchRectangle, I as sketchRoundedRectangle, L as FaceSketcher, M as sketchHelix, N as sketchParametricFunction, O as polysideInnerRadius, P as sketchPolysides, R as Sketcher, S as drawText, T as Drawing, _ as drawPolysides, a as drawingIntersect, b as drawSingleCircle, c as rotateDrawing, d as drawFaceOutline, f as drawProjection, g as drawPointsInterpolation, h as drawParametricFunction, i as drawingFuse, j as sketchFaceOffset, k as sketchCircle, l as scaleDrawing, m as drawEllipse, n as drawingCut, o as drawingToSketchOnPlane, p as drawCircle, r as drawingFillet, s as mirrorDrawing, t as drawingChamfer, u as translateDrawing, v as drawRectangle, w as draw, x as drawSingleEllipse, y as drawRoundedRectangle } from "./drawFns-RuUOUlSC.js";
3
+ import { a as Sketches, c as compoundSketchFace, d as sketchExtrude, f as sketchFace, g as sketchWires, h as sketchSweep, l as compoundSketchLoft, m as sketchRevolve, o as Sketch, p as sketchLoft, s as compoundSketchExtrude, u as compoundSketchRevolve, y as CompoundSketch } from "./textBlueprints-CLwy1uWM.js";
4
4
  // src/sketching.ts
5
5
  /**
6
6
  * brepjs/sketching — Sketcher, Drawing, and sketch-to-shape operations.
@@ -1,8 +1,8 @@
1
- const require_shapeTypes = require("./shapeTypes-CIw6-GFy.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-BK53GmLC.cjs");
2
2
  const require_errors = require("./errors-O_blYTWT.cjs");
3
- const require_topologyQueryFns = require("./topologyQueryFns-BNDmjz7x.cjs");
3
+ const require_topologyQueryFns = require("./topologyQueryFns--p_-tywe.cjs");
4
4
  const require_constants = require("./constants-oee0S_x6.cjs");
5
- const require_faceFns = require("./faceFns-BeSpw0Dz.cjs");
5
+ const require_faceFns = require("./faceFns-DfEUZlnf.cjs");
6
6
  // src/topology/metadata/originTrackingFns.ts
7
7
  /**
8
8
  * Face origin tracking — tag faces with integer origins and propagate
@@ -1,8 +1,8 @@
1
- import { C as isSolid, G as _usingCtx, S as isShell, d as createSolid, f as createVertex, h as disposeResultShape, n as castResultShape, q as getKernel, s as createCompound, x as isShape3D } from "./shapeTypes-hLHmANUz.js";
1
+ import { C as isSolid, G as _usingCtx, S as isShell, d as createSolid, f as createVertex, h as disposeResultShape, n as castResultShape, q as getKernel, s as createCompound, x as isShape3D } from "./shapeTypes-Ckz9bpYW.js";
2
2
  import { E as ok, g as err, l as typeCastError, m as andThen } from "./errors-BTccWbtE.js";
3
- import { C as subShapeHashes, c as getFaces, l as getOrCreateCache, r as getCacheEntry } from "./topologyQueryFns-BYqsNs6q.js";
3
+ import { C as subShapeHashes, c as getFaces, l as getOrCreateCache, r as getCacheEntry } from "./topologyQueryFns-SINsBrMe.js";
4
4
  import { n as HASH_CODE_MAX } from "./constants-iraOnb2p.js";
5
- import { _ as cast, y as downcast } from "./faceFns-BzHfvPea.js";
5
+ import { _ as cast, y as downcast } from "./faceFns-Dz3eRgNR.js";
6
6
  // src/topology/metadata/originTrackingFns.ts
7
7
  /**
8
8
  * Face origin tracking — tag faces with integer origins and propagate