brepjs 20.2.0 → 20.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/dist/2d.cjs +7 -7
  2. package/dist/2d.js +7 -7
  3. package/dist/{adjacencyFns-DZsPfYIq.cjs → adjacencyFns-1rxgJ6Hw.cjs} +3 -3
  4. package/dist/{adjacencyFns-k4GWh4n7.js → adjacencyFns-DeyXahej.js} +3 -3
  5. package/dist/{blueprint-CJuRunkd.cjs → blueprint-Yyoiz-U1.cjs} +7 -7
  6. package/dist/{blueprint-Dsp4t2ul.js → blueprint-rwJjYPzo.js} +7 -7
  7. package/dist/{blueprintFns-BRceCeZp.cjs → blueprintFns-Ce6OoPSX.cjs} +3 -3
  8. package/dist/{blueprintFns-DNyUtopT.js → blueprintFns-Q3Sq-Fse.js} +3 -3
  9. package/dist/{blueprintSketcher-DRXOTYuD.cjs → blueprintSketcher-CzKbxeTk.cjs} +4 -4
  10. package/dist/{blueprintSketcher-kV7aFwRS.js → blueprintSketcher-FywUpRiV.js} +4 -4
  11. package/dist/{boolean2D-DmPqFj_V.cjs → boolean2D-BzZ9iBSn.cjs} +5 -5
  12. package/dist/{boolean2D-TdJfMS8F.js → boolean2D-D8igCYc9.js} +5 -5
  13. package/dist/brepjs.cjs +35 -32
  14. package/dist/brepjs.js +35 -33
  15. package/dist/{cameraFns-u08iOn7p.js → cameraFns-Cs6v3bWQ.js} +4 -4
  16. package/dist/{cameraFns-B8Ai6b3Q.cjs → cameraFns-RHCb1F1s.cjs} +4 -4
  17. package/dist/core/errors.d.ts +3 -0
  18. package/dist/core.cjs +4 -4
  19. package/dist/core.js +4 -4
  20. package/dist/{cornerFinder-BVUuCBX-.cjs → cornerFinder-Cji_BK-R.cjs} +1 -1
  21. package/dist/{cornerFinder-DfoRecV-.js → cornerFinder-Dlae8IX5.js} +1 -1
  22. package/dist/{curveFns-DciWOppG.cjs → curveFns-6-ULFrEB.cjs} +2 -2
  23. package/dist/{curveFns-D5V4jm7S.js → curveFns-KS1BWGhF.js} +2 -2
  24. package/dist/{drawFns-BzuxoLHh.js → drawFns-3yRVBDgI.js} +14 -14
  25. package/dist/{drawFns-DeUXFpjR.cjs → drawFns-Ddlgp9gQ.cjs} +14 -14
  26. package/dist/{errors-CDSezF9z.js → errors-Zb3jBa0u.js} +3 -0
  27. package/dist/{errors-gG-7hA7k.cjs → errors-jwhfQJZK.cjs} +3 -0
  28. package/dist/{faceFns-DhdweJGk.js → faceFns-CTlJC5IY.js} +3 -3
  29. package/dist/{faceFns-DaXVpMr5.cjs → faceFns-CZeHWke7.cjs} +3 -3
  30. package/dist/faceRoleFns-CWU1-Pm8.js +37 -0
  31. package/dist/faceRoleFns-CtH_48MO.cjs +60 -0
  32. package/dist/{healingFns-HekFOO_s.js → healingFns-Ct3gEMvk.js} +5 -5
  33. package/dist/{healingFns-C_f03IV6.cjs → healingFns-DwSpJZfg.cjs} +5 -5
  34. package/dist/{helpers-BWNXoJz0.js → helpers-BN1mVMuZ.js} +7 -7
  35. package/dist/{helpers-Dh4qTGcQ.cjs → helpers-NRZVshPb.cjs} +7 -7
  36. package/dist/{importFns-DGnmgb9G.js → importFns-0kHGg-b8.js} +3 -3
  37. package/dist/{importFns-CKfKRdiq.cjs → importFns-BEi-HsSw.cjs} +3 -3
  38. package/dist/index.d.ts +1 -0
  39. package/dist/io.cjs +2 -2
  40. package/dist/io.js +2 -2
  41. package/dist/kernel/interfaces/measureOps.d.ts +19 -0
  42. package/dist/kernel/occtWasm/measureOps.d.ts +2 -1
  43. package/dist/kernel/occtWasm/occtWasmAdapter.cjs +1 -1
  44. package/dist/kernel/occtWasm/occtWasmAdapter.d.ts +2 -1
  45. package/dist/kernel/occtWasm/occtWasmAdapter.js +1 -1
  46. package/dist/kernel/occtWasm/occtWasmTypes.d.ts +2 -0
  47. package/dist/{loftFns-DE1GYW9g.js → loftFns-B5mq1WDh.js} +2 -2
  48. package/dist/{loftFns-CI8uJc1D.cjs → loftFns-DL9UsQhd.cjs} +2 -2
  49. package/dist/{measureFns-BoA-Fmwy.js → measureFns-CyDVZomf.js} +5 -5
  50. package/dist/{measureFns-B8Yj_BMz.cjs → measureFns-D_GpQw5z.cjs} +16 -4
  51. package/dist/measurement/measureCache.d.ts +2 -1
  52. package/dist/measurement/measureTypes.d.ts +9 -0
  53. package/dist/measurement/principalBoxFns.d.ts +33 -0
  54. package/dist/measurement.cjs +3 -1
  55. package/dist/measurement.d.ts +1 -0
  56. package/dist/measurement.js +3 -2
  57. package/dist/{meshFns-BT7W4b1c.cjs → meshFns-CAxkaRTm.cjs} +4 -4
  58. package/dist/{meshFns-o9MnZeir.js → meshFns-COlno8TY.js} +4 -4
  59. package/dist/ns/measurement.d.ts +1 -0
  60. package/dist/{occtWasmAdapter-D4I0n537.js → occtWasmAdapter-BX10fyla.js} +21 -0
  61. package/dist/{occtWasmAdapter-wCKnmevS.cjs → occtWasmAdapter-CA6PmIIj.cjs} +21 -0
  62. package/dist/operations/extrudeFns.d.ts +4 -0
  63. package/dist/operations.cjs +2 -2
  64. package/dist/operations.js +2 -2
  65. package/dist/{originTrackingFns-B3-1bBED.cjs → originTrackingFns-CWo6NWHK.cjs} +2 -2
  66. package/dist/{originTrackingFns-BFmhk_Up.js → originTrackingFns-DiHy5BZC.js} +2 -2
  67. package/dist/{planeOps-BO6nvRja.js → planeOps-Cxws4Tiu.js} +1 -1
  68. package/dist/{planeOps-DqGSxcMr.cjs → planeOps-DJuclNxa.cjs} +1 -1
  69. package/dist/{primitiveFns-DfhjU_X9.js → primitiveFns-CGJzS4MO.js} +5 -5
  70. package/dist/{primitiveFns-Ke-n8Bib.cjs → primitiveFns-ZV3aMbqG.cjs} +5 -5
  71. package/dist/principalBoxFns-5FSbxAj-.cjs +212 -0
  72. package/dist/principalBoxFns-BJgGEoik.js +207 -0
  73. package/dist/projection.cjs +1 -1
  74. package/dist/projection.js +1 -1
  75. package/dist/query.cjs +2 -2
  76. package/dist/query.js +2 -2
  77. package/dist/{refResolveFns-C-6Xa_8k.js → refResolveFns-CpVZoeOT.js} +30 -12
  78. package/dist/{refResolveFns-BPqbBoxy.cjs → refResolveFns-Ct52Uw7R.cjs} +30 -12
  79. package/dist/result.cjs +1 -1
  80. package/dist/result.js +1 -1
  81. package/dist/{shapeFns-CUTM2ZDR.js → shapeFns--1wNlcc_.js} +3 -3
  82. package/dist/{shapeFns-CmJNoPsh.cjs → shapeFns-C2j6oZ2u.cjs} +3 -3
  83. package/dist/shapeRef.cjs +1 -1
  84. package/dist/shapeRef.js +1 -1
  85. package/dist/{shapeTypes-DVpJHhgk.js → shapeTypes-CqNJoSam.js} +1 -1
  86. package/dist/{shapeTypes-BWsKDxzf.cjs → shapeTypes-DH2ShBU_.cjs} +1 -1
  87. package/dist/sketching.cjs +3 -3
  88. package/dist/sketching.js +3 -3
  89. package/dist/{solidBuilders-B8t5h68e.cjs → solidBuilders-CgicU3le.cjs} +12 -10
  90. package/dist/{solidBuilders-p_ppeTkc.js → solidBuilders-IstbiWju.js} +12 -10
  91. package/dist/{surfaceBuilders-Dccm2kQX.js → surfaceBuilders-8nLk2PWk.js} +4 -4
  92. package/dist/{surfaceBuilders-Bn-c9xVR.cjs → surfaceBuilders-vYgSvgI6.cjs} +4 -4
  93. package/dist/text.cjs +2 -2
  94. package/dist/text.js +2 -2
  95. package/dist/{textBlueprints-bFsyNLkO.js → textBlueprints-C13NAA3C.js} +169 -10
  96. package/dist/{textBlueprints-DQi920gG.cjs → textBlueprints-fa7VHJZz.cjs} +168 -9
  97. package/dist/{textMetrics-DhysRMr7.cjs → textMetrics--cikHkGX.cjs} +2 -2
  98. package/dist/{textMetrics-CvTwh4tR.js → textMetrics-Dcc63qRm.js} +2 -2
  99. package/dist/{threadFns-DlGXBSK7.js → threadFns-3U9x4v_M.js} +8 -8
  100. package/dist/{threadFns-DAKMitvE.cjs → threadFns-BUQPg_vI.cjs} +8 -8
  101. package/dist/topology/metadata/faceRoleFns.d.ts +15 -0
  102. package/dist/topology/metadata/metadataPropagation.d.ts +2 -2
  103. package/dist/topology/shapeRef/extrudeRoleFns.d.ts +9 -0
  104. package/dist/topology/shapeRef/refResolveFns.d.ts +2 -1
  105. package/dist/topology/shapeRef/shapeRefFns.d.ts +8 -2
  106. package/dist/topology.cjs +9 -9
  107. package/dist/topology.js +9 -9
  108. package/dist/{topologyQueryFns-fNWsM4Lr.js → topologyQueryFns-DnfjQgP7.js} +3 -3
  109. package/dist/{topologyQueryFns-CI4j3NTE.cjs → topologyQueryFns-q2bGyuEV.cjs} +8 -2
  110. package/dist/{validityTypes-D9oxhu4U.cjs → validityTypes-r0A2YdNq.cjs} +2 -2
  111. package/dist/{validityTypes-2DNKAPEw.js → validityTypes-t7JpS0Ki.js} +2 -2
  112. package/dist/vectors.cjs +1 -1
  113. package/dist/vectors.js +1 -1
  114. package/package.json +1 -1
@@ -1,9 +1,10 @@
1
- import { g as disposeTransientSubShape, o as castShapeWithKnownType, q as getKernel } from "./shapeTypes-DVpJHhgk.js";
2
- import { C as vertexPosition, c as getFaces } from "./topologyQueryFns-fNWsM4Lr.js";
3
- import { i as faceGeomType, l as normalAt, r as faceCenter } from "./faceFns-DhdweJGk.js";
4
- import { n as getHashCode } from "./shapeFns-CUTM2ZDR.js";
5
- import { n as measureArea, s as measureLength } from "./measureFns-BoA-Fmwy.js";
6
- import { a as facesOfVertex, c as verticesOfFace, i as facesOfEdge, o as sharedEdges, s as verticesOfEdge, t as adjacentFaceHashes } from "./adjacencyFns-k4GWh4n7.js";
1
+ import { g as disposeTransientSubShape, o as castShapeWithKnownType, q as getKernel } from "./shapeTypes-CqNJoSam.js";
2
+ import { c as getFaces, w as vertexPosition } from "./topologyQueryFns-DnfjQgP7.js";
3
+ import { i as faceGeomType, l as normalAt, r as faceCenter } from "./faceFns-CTlJC5IY.js";
4
+ import { t as getFaceRoles } from "./faceRoleFns-CWU1-Pm8.js";
5
+ import { n as getHashCode } from "./shapeFns--1wNlcc_.js";
6
+ import { n as measureArea, s as measureLength } from "./measureFns-CyDVZomf.js";
7
+ import { a as facesOfVertex, c as verticesOfFace, i as facesOfEdge, o as sharedEdges, s as verticesOfEdge, t as adjacentFaceHashes } from "./adjacencyFns-DeyXahej.js";
7
8
  //#region src/topology/shapeRef/scoring.ts
8
9
  /**
9
10
  * Default face scorer combining surface type, normal alignment, centroid proximity,
@@ -108,24 +109,40 @@ var ROLE_ASSIGNERS = {
108
109
  * - `cylinder`/`cone` (Z-axis): 'top'/'bottom' caps + 'lateral' wall.
109
110
  * - `sphere`: 'sphere:surface'.
110
111
  *
112
+ * Faces whose roles an operation recorded on the shape take those names when
113
+ * the namespace matches `operationType`. `extrude` records 'extrude:start',
114
+ * 'extrude:end', 'extrude:side:<i>' and 'extrude:hole<j>:side:<i>', which
115
+ * survive later moves and booleans.
116
+ *
111
117
  * Faces a primitive namer doesn't recognize (a rotated box's non-cardinal faces),
112
118
  * and every face of any other operation type, fall back to positional names
113
119
  * ('opType:face_0', 'opType:face_1', ...) — so each face always gets a role.
114
120
  *
115
- * @returns Map from role name to its face hash codes (one at assignment time;
116
- * a role accrues more hashes only later, when `updateRoles` tracks a split).
121
+ * @returns Map from role name to its face hash codes (one per role, except a
122
+ * recorded role whose face a later operation split; `updateRoles` adds more
123
+ * when it tracks a split).
117
124
  */
118
125
  function assignRoles(shape, operationType) {
119
126
  const roles = /* @__PURE__ */ new Map();
120
127
  const assigner = ROLE_ASSIGNERS[operationType];
128
+ const recorded = getFaceRoles(shape);
129
+ const namespace = `${operationType}:`;
121
130
  const kernel = getKernel();
122
131
  let index = 0;
123
132
  for (const raw of kernel.iterShapes(shape.wrapped, "face")) {
124
133
  const face = castShapeWithKnownType(raw, "face");
125
134
  try {
126
- const semantic = assigner?.(face);
127
- const role = semantic !== void 0 && !roles.has(semantic) ? semantic : `${operationType}:face_${index}`;
128
- roles.set(role, [getHashCode(face)]);
135
+ const hash = getHashCode(face);
136
+ const stored = recorded?.get(hash);
137
+ if (stored?.startsWith(namespace) === true) {
138
+ const hashes = roles.get(stored);
139
+ if (hashes) hashes.push(hash);
140
+ else roles.set(stored, [hash]);
141
+ } else {
142
+ const semantic = assigner?.(face);
143
+ const role = semantic !== void 0 && !roles.has(semantic) ? semantic : `${operationType}:face_${index}`;
144
+ roles.set(role, [hash]);
145
+ }
129
146
  index++;
130
147
  } finally {
131
148
  disposeTransientSubShape(face, raw);
@@ -744,7 +761,8 @@ function rolesFor(ref, shape, cache) {
744
761
  * Resolve a lineage ref against a freshly rebuilt `shape` with no maintained
745
762
  * role table, re-deriving roles via `assignRoles(shape, ref.origin)`. The ref's
746
763
  * `origin` must therefore be the role-assignment scheme (e.g. `'box'`), and
747
- * stability is bounded by that scheme — `'box'` names faces semantically
764
+ * stability is bounded by that scheme. The primitives (`'box'`, `'cylinder'`,
765
+ * `'cone'`, `'sphere'`) and `'extrude'` name faces semantically
748
766
  * (rebuild-stable); other schemes fall back to positional `face_N`.
749
767
  */
750
768
  function resolveRefIn(ref, shape) {
@@ -1,9 +1,10 @@
1
- const require_shapeTypes = require("./shapeTypes-BWsKDxzf.cjs");
2
- const require_topologyQueryFns = require("./topologyQueryFns-CI4j3NTE.cjs");
3
- const require_faceFns = require("./faceFns-DaXVpMr5.cjs");
4
- const require_shapeFns = require("./shapeFns-CmJNoPsh.cjs");
5
- const require_measureFns = require("./measureFns-B8Yj_BMz.cjs");
6
- const require_adjacencyFns = require("./adjacencyFns-DZsPfYIq.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-DH2ShBU_.cjs");
2
+ const require_topologyQueryFns = require("./topologyQueryFns-q2bGyuEV.cjs");
3
+ const require_faceFns = require("./faceFns-CZeHWke7.cjs");
4
+ const require_faceRoleFns = require("./faceRoleFns-CtH_48MO.cjs");
5
+ const require_shapeFns = require("./shapeFns-C2j6oZ2u.cjs");
6
+ const require_measureFns = require("./measureFns-D_GpQw5z.cjs");
7
+ const require_adjacencyFns = require("./adjacencyFns-1rxgJ6Hw.cjs");
7
8
  //#region src/topology/shapeRef/scoring.ts
8
9
  /**
9
10
  * Default face scorer combining surface type, normal alignment, centroid proximity,
@@ -108,24 +109,40 @@ var ROLE_ASSIGNERS = {
108
109
  * - `cylinder`/`cone` (Z-axis): 'top'/'bottom' caps + 'lateral' wall.
109
110
  * - `sphere`: 'sphere:surface'.
110
111
  *
112
+ * Faces whose roles an operation recorded on the shape take those names when
113
+ * the namespace matches `operationType`. `extrude` records 'extrude:start',
114
+ * 'extrude:end', 'extrude:side:<i>' and 'extrude:hole<j>:side:<i>', which
115
+ * survive later moves and booleans.
116
+ *
111
117
  * Faces a primitive namer doesn't recognize (a rotated box's non-cardinal faces),
112
118
  * and every face of any other operation type, fall back to positional names
113
119
  * ('opType:face_0', 'opType:face_1', ...) — so each face always gets a role.
114
120
  *
115
- * @returns Map from role name to its face hash codes (one at assignment time;
116
- * a role accrues more hashes only later, when `updateRoles` tracks a split).
121
+ * @returns Map from role name to its face hash codes (one per role, except a
122
+ * recorded role whose face a later operation split; `updateRoles` adds more
123
+ * when it tracks a split).
117
124
  */
118
125
  function assignRoles(shape, operationType) {
119
126
  const roles = /* @__PURE__ */ new Map();
120
127
  const assigner = ROLE_ASSIGNERS[operationType];
128
+ const recorded = require_faceRoleFns.getFaceRoles(shape);
129
+ const namespace = `${operationType}:`;
121
130
  const kernel = require_shapeTypes.getKernel();
122
131
  let index = 0;
123
132
  for (const raw of kernel.iterShapes(shape.wrapped, "face")) {
124
133
  const face = require_shapeTypes.castShapeWithKnownType(raw, "face");
125
134
  try {
126
- const semantic = assigner?.(face);
127
- const role = semantic !== void 0 && !roles.has(semantic) ? semantic : `${operationType}:face_${index}`;
128
- roles.set(role, [require_shapeFns.getHashCode(face)]);
135
+ const hash = require_shapeFns.getHashCode(face);
136
+ const stored = recorded?.get(hash);
137
+ if (stored?.startsWith(namespace) === true) {
138
+ const hashes = roles.get(stored);
139
+ if (hashes) hashes.push(hash);
140
+ else roles.set(stored, [hash]);
141
+ } else {
142
+ const semantic = assigner?.(face);
143
+ const role = semantic !== void 0 && !roles.has(semantic) ? semantic : `${operationType}:face_${index}`;
144
+ roles.set(role, [hash]);
145
+ }
129
146
  index++;
130
147
  } finally {
131
148
  require_shapeTypes.disposeTransientSubShape(face, raw);
@@ -744,7 +761,8 @@ function rolesFor(ref, shape, cache) {
744
761
  * Resolve a lineage ref against a freshly rebuilt `shape` with no maintained
745
762
  * role table, re-deriving roles via `assignRoles(shape, ref.origin)`. The ref's
746
763
  * `origin` must therefore be the role-assignment scheme (e.g. `'box'`), and
747
- * stability is bounded by that scheme — `'box'` names faces semantically
764
+ * stability is bounded by that scheme. The primitives (`'box'`, `'cylinder'`,
765
+ * `'cone'`, `'sphere'`) and `'extrude'` name faces semantically
748
766
  * (rebuild-stable); other schemes fall back to positional `face_N`.
749
767
  */
750
768
  function resolveRefIn(ref, shape) {
package/dist/result.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_bug = require("./bug-O02CsAmt.cjs");
3
- const require_errors = require("./errors-gG-7hA7k.cjs");
3
+ const require_errors = require("./errors-jwhfQJZK.cjs");
4
4
  exports.BrepBugError = require_bug.BrepBugError;
5
5
  exports.BrepErrorCode = require_errors.BrepErrorCode;
6
6
  exports.OK = require_errors.OK;
package/dist/result.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { n as bug, t as BrepBugError } from "./bug-BdOHwn_e.js";
2
- import { E as ok, F as unwrapErr, I as unwrapOr, L as unwrapOrElse, M as tryCatch, N as tryCatchAsync, P as unwrap, S as map, T as match, _ as flatMap, a as moduleInitError, b as isErr, c as sketcherStateError, d as validationError, f as OK, g as err, h as collect, i as kernelError, k as pipeline, l as typeCastError, m as andThen, n as computationError, o as queryError, r as ioError, t as BrepErrorCode, w as mapErr, x as isOk } from "./errors-CDSezF9z.js";
2
+ import { E as ok, F as unwrapErr, I as unwrapOr, L as unwrapOrElse, M as tryCatch, N as tryCatchAsync, P as unwrap, S as map, T as match, _ as flatMap, a as moduleInitError, b as isErr, c as sketcherStateError, d as validationError, f as OK, g as err, h as collect, i as kernelError, k as pipeline, l as typeCastError, m as andThen, n as computationError, o as queryError, r as ioError, t as BrepErrorCode, w as mapErr, x as isOk } from "./errors-Zb3jBa0u.js";
3
3
  export { BrepBugError, BrepErrorCode, OK, andThen, bug, collect, computationError, err, flatMap, ioError, isErr, isOk, kernelError, map, mapErr, match, moduleInitError, ok, pipeline, queryError, sketcherStateError, tryCatch, tryCatchAsync, typeCastError, unwrap, unwrapErr, unwrapOr, unwrapOrElse, validationError };
@@ -1,6 +1,6 @@
1
- import { q as getKernel } from "./shapeTypes-DVpJHhgk.js";
2
- import { t as BrepErrorCode } from "./errors-CDSezF9z.js";
3
- import { T as kernelCallRaw, w as kernelCall } from "./topologyQueryFns-fNWsM4Lr.js";
1
+ import { q as getKernel } from "./shapeTypes-CqNJoSam.js";
2
+ import { t as BrepErrorCode } from "./errors-Zb3jBa0u.js";
3
+ import { E as kernelCallRaw, T as kernelCall } from "./topologyQueryFns-DnfjQgP7.js";
4
4
  import { n as HASH_CODE_MAX } from "./constants-ITRzCnCp.js";
5
5
  //#region src/topology/shapeFns.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
- const require_shapeTypes = require("./shapeTypes-BWsKDxzf.cjs");
2
- const require_errors = require("./errors-gG-7hA7k.cjs");
3
- const require_topologyQueryFns = require("./topologyQueryFns-CI4j3NTE.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-DH2ShBU_.cjs");
2
+ const require_errors = require("./errors-jwhfQJZK.cjs");
3
+ const require_topologyQueryFns = require("./topologyQueryFns-q2bGyuEV.cjs");
4
4
  const require_constants = require("./constants-BOVyEYGH.cjs");
5
5
  //#region src/topology/shapeFns.ts
6
6
  /**
package/dist/shapeRef.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_refResolveFns = require("./refResolveFns-BPqbBoxy.cjs");
2
+ const require_refResolveFns = require("./refResolveFns-Ct52Uw7R.cjs");
3
3
  exports.assignRoles = require_refResolveFns.assignRoles;
4
4
  exports.captureHint = require_refResolveFns.captureHint;
5
5
  exports.createDerivedFaceRef = require_refResolveFns.createDerivedFaceRef;
package/dist/shapeRef.js CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as createRef, a as isVertexRef, b as defaultScorer, c as resolveRefParams, d as createVertexRef, f as resolveVertexRef, g as captureHint, h as assignRoles, i as isLineageRef, l as createDerivedFaceRef, m as resolveEdgeRef, n as isEdgeRef, o as resolveLineageRef, p as createEdgeRef, r as isFaceRef, s as resolveRefIn, t as isDerivedFaceRef, u as resolveDerivedFaceRef, v as resolveRef, y as updateRoles } from "./refResolveFns-C-6Xa_8k.js";
1
+ import { _ as createRef, a as isVertexRef, b as defaultScorer, c as resolveRefParams, d as createVertexRef, f as resolveVertexRef, g as captureHint, h as assignRoles, i as isLineageRef, l as createDerivedFaceRef, m as resolveEdgeRef, n as isEdgeRef, o as resolveLineageRef, p as createEdgeRef, r as isFaceRef, s as resolveRefIn, t as isDerivedFaceRef, u as resolveDerivedFaceRef, v as resolveRef, y as updateRoles } from "./refResolveFns-CpVZoeOT.js";
2
2
  export { assignRoles, captureHint, createDerivedFaceRef, createEdgeRef, createRef, createVertexRef, defaultScorer, isDerivedFaceRef, isEdgeRef, isFaceRef, isLineageRef, isVertexRef, resolveDerivedFaceRef, resolveEdgeRef, resolveLineageRef, resolveRef, resolveRefIn, resolveRefParams, resolveVertexRef, updateRoles };
@@ -1,4 +1,4 @@
1
- import { A as EXACT_BREP_CAPABILITIES, C as serializeCurve2d$2, D as UnsupportedKernelOperationError, E as quickHull, O as isUnsupportedKernelOperationError, S as scaleCurve2d$2, T as translateCurve2d$2, _ as makeEllipse2d$2, a as buildBinarySTL, b as mirrorAtPoint, c as curveBounds, d as evaluateCurve2d$2, f as intersectCurves2dFn, g as makeCircle2d$2, h as makeBezier2d$2, i as buildAsciiSTL, l as curveTypeName, m as makeArc2dThreePoints, n as DEFAULT_STL_ANGULAR_TOLERANCE, o as addCurveToBBox, p as makeArc2dTangent, r as DEFAULT_STL_TOLERANCE, s as createBBox2d, t as OcctWasmAdapter, u as deserializeCurve2d$2, v as makeLine2d$2, w as tangentCurve2d, x as rotateCurve2d$2, y as mirrorAcrossAxis } from "./occtWasmAdapter-D4I0n537.js";
1
+ import { A as EXACT_BREP_CAPABILITIES, C as serializeCurve2d$2, D as UnsupportedKernelOperationError, E as quickHull, O as isUnsupportedKernelOperationError, S as scaleCurve2d$2, T as translateCurve2d$2, _ as makeEllipse2d$2, a as buildBinarySTL, b as mirrorAtPoint, c as curveBounds, d as evaluateCurve2d$2, f as intersectCurves2dFn, g as makeCircle2d$2, h as makeBezier2d$2, i as buildAsciiSTL, l as curveTypeName, m as makeArc2dThreePoints, n as DEFAULT_STL_ANGULAR_TOLERANCE, o as addCurveToBBox, p as makeArc2dTangent, r as DEFAULT_STL_TOLERANCE, s as createBBox2d, t as OcctWasmAdapter, u as deserializeCurve2d$2, v as makeLine2d$2, w as tangentCurve2d, x as rotateCurve2d$2, y as mirrorAcrossAxis } from "./occtWasmAdapter-BX10fyla.js";
2
2
  import { i as wasmIndex, r as vec3At } from "./bug-BdOHwn_e.js";
3
3
  //#region src/kernel/quality.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- const require_occtWasmAdapter = require("./occtWasmAdapter-wCKnmevS.cjs");
1
+ const require_occtWasmAdapter = require("./occtWasmAdapter-CA6PmIIj.cjs");
2
2
  const require_bug = require("./bug-O02CsAmt.cjs");
3
3
  //#region src/kernel/quality.ts
4
4
  /**
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_blueprintSketcher = require("./blueprintSketcher-DRXOTYuD.cjs");
3
- const require_drawFns = require("./drawFns-DeUXFpjR.cjs");
4
- const require_textBlueprints = require("./textBlueprints-DQi920gG.cjs");
2
+ const require_blueprintSketcher = require("./blueprintSketcher-CzKbxeTk.cjs");
3
+ const require_drawFns = require("./drawFns-Ddlgp9gQ.cjs");
4
+ const require_textBlueprints = require("./textBlueprints-fa7VHJZz.cjs");
5
5
  //#region 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-kV7aFwRS.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-BzuxoLHh.js";
3
- import { a as Sketch, c as compoundSketchLoft, d as sketchFace, f as sketchLoft, h as sketchWires, i as Sketches, l as compoundSketchRevolve, m as sketchSweep, o as compoundSketchExtrude, p as sketchRevolve, s as compoundSketchFace, u as sketchExtrude, v as CompoundSketch } from "./textBlueprints-bFsyNLkO.js";
1
+ import { n as BaseSketcher2d, t as BlueprintSketcher } from "./blueprintSketcher-FywUpRiV.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-3yRVBDgI.js";
3
+ import { a as Sketch, c as compoundSketchLoft, d as sketchFace, f as sketchLoft, h as sketchWires, i as Sketches, l as compoundSketchRevolve, m as sketchSweep, o as compoundSketchExtrude, p as sketchRevolve, s as compoundSketchFace, u as sketchExtrude, v as CompoundSketch } from "./textBlueprints-C13NAA3C.js";
4
4
  //#region src/sketching.ts
5
5
  /**
6
6
  * brepjs/sketching — Sketcher, Drawing, and sketch-to-shape operations.
@@ -1,13 +1,14 @@
1
- const require_shapeTypes = require("./shapeTypes-BWsKDxzf.cjs");
2
- const require_errors = require("./errors-gG-7hA7k.cjs");
3
- const require_topologyQueryFns = require("./topologyQueryFns-CI4j3NTE.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-DH2ShBU_.cjs");
2
+ const require_errors = require("./errors-jwhfQJZK.cjs");
3
+ const require_topologyQueryFns = require("./topologyQueryFns-q2bGyuEV.cjs");
4
4
  const require_constants = require("./constants-BOVyEYGH.cjs");
5
5
  const require_vecOps = require("./vecOps-CCnJt-yH.cjs");
6
- const require_planeOps = require("./planeOps-DqGSxcMr.cjs");
7
- const require_faceFns = require("./faceFns-DaXVpMr5.cjs");
8
- const require_originTrackingFns = require("./originTrackingFns-B3-1bBED.cjs");
6
+ const require_planeOps = require("./planeOps-DJuclNxa.cjs");
7
+ const require_faceFns = require("./faceFns-CZeHWke7.cjs");
8
+ const require_originTrackingFns = require("./originTrackingFns-CWo6NWHK.cjs");
9
+ const require_faceRoleFns = require("./faceRoleFns-CtH_48MO.cjs");
9
10
  const require_arrayAccess = require("./arrayAccess-e4H9cBfh.cjs");
10
- const require_surfaceBuilders = require("./surfaceBuilders-Bn-c9xVR.cjs");
11
+ const require_surfaceBuilders = require("./surfaceBuilders-vYgSvgI6.cjs");
11
12
  //#region src/topology/metadata/faceTagFns.ts
12
13
  var shapeTagStore = /* @__PURE__ */ new WeakMap();
13
14
  var tagMetadataStore = /* @__PURE__ */ new WeakMap();
@@ -239,11 +240,11 @@ function propagateColorsFromEvolution(evolution, inputs, result) {
239
240
  */
240
241
  /**
241
242
  * O(1) check: does a shape carry any propagatable metadata (face origins,
242
- * tags, or colors)? Lets callers skip both expensive face iteration and
243
+ * tags, colors, or recorded roles)? Lets callers skip both expensive face iteration and
243
244
  * metadata-preserving slow paths when there's nothing to preserve.
244
245
  */
245
246
  function hasAnyMetadata(shape) {
246
- return require_originTrackingFns.getFaceOrigins(shape) !== void 0 || hasFaceTags(shape) || hasColorMetadata(shape);
247
+ return require_originTrackingFns.getFaceOrigins(shape) !== void 0 || hasFaceTags(shape) || hasColorMetadata(shape) || require_faceRoleFns.hasFaceRoles(shape);
247
248
  }
248
249
  function collectInputFaceHashes(inputs) {
249
250
  if (!inputs.some(hasAnyMetadata)) return [];
@@ -252,7 +253,7 @@ function collectInputFaceHashes(inputs) {
252
253
  return hashes;
253
254
  }
254
255
  /**
255
- * Propagate all metadata (origins, tags, colors) from inputs to result
256
+ * Propagate all metadata (origins, tags, colors, recorded roles) from inputs to result
256
257
  * using a kernel-provided ShapeEvolution record.
257
258
  *
258
259
  * This is the standard pipeline for any operation that returns
@@ -262,6 +263,7 @@ function propagateAllMetadata(evolution, inputs, result) {
262
263
  require_originTrackingFns.propagateOriginsFromEvolution(evolution, inputs, result);
263
264
  propagateFaceTagsFromEvolution(evolution, inputs, result);
264
265
  propagateColorsFromEvolution(evolution, inputs, result);
266
+ require_faceRoleFns.propagateFaceRolesFromEvolution(evolution, inputs, result);
265
267
  }
266
268
  /**
267
269
  * Fallback metadata propagation when no ShapeEvolution is available.
@@ -1,13 +1,14 @@
1
- import { C as isSolid, D as getShapeKind, E as GeometryCleanupError, 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-DVpJHhgk.js";
2
- import { E as ok, P as unwrap, b as isErr, d as validationError, g as err, i as kernelError, l as typeCastError, m as andThen, t as BrepErrorCode } from "./errors-CDSezF9z.js";
3
- import { S as subShapeHashes, c as getFaces, f as getVertices, p as getWires, s as getEdges } from "./topologyQueryFns-fNWsM4Lr.js";
1
+ import { C as isSolid, D as getShapeKind, E as GeometryCleanupError, 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-CqNJoSam.js";
2
+ import { E as ok, P as unwrap, b as isErr, d as validationError, g as err, i as kernelError, l as typeCastError, m as andThen, t as BrepErrorCode } from "./errors-Zb3jBa0u.js";
3
+ import { C as subShapeHashes, c as getFaces, f as getVertices, p as getWires, s as getEdges } from "./topologyQueryFns-DnfjQgP7.js";
4
4
  import { n as HASH_CODE_MAX } from "./constants-ITRzCnCp.js";
5
5
  import { a as vecDot, g as vecSub, h as vecScale, t as vecAdd } from "./vecOps-SKPRvPH-.js";
6
- import { o as resolvePlane } from "./planeOps-BO6nvRja.js";
7
- import { _ as cast, y as downcast } from "./faceFns-DhdweJGk.js";
8
- import { n as propagateOriginsByHash, r as propagateOriginsFromEvolution, t as getFaceOrigins } from "./originTrackingFns-BFmhk_Up.js";
6
+ import { o as resolvePlane } from "./planeOps-Cxws4Tiu.js";
7
+ import { _ as cast, y as downcast } from "./faceFns-CTlJC5IY.js";
8
+ import { n as propagateOriginsByHash, r as propagateOriginsFromEvolution, t as getFaceOrigins } from "./originTrackingFns-DiHy5BZC.js";
9
+ import { n as hasFaceRoles, r as propagateFaceRolesFromEvolution } from "./faceRoleFns-CWU1-Pm8.js";
9
10
  import { n as getAtOrThrow, t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
10
- import { r as makeFace } from "./surfaceBuilders-Dccm2kQX.js";
11
+ import { r as makeFace } from "./surfaceBuilders-8nLk2PWk.js";
11
12
  //#region src/topology/metadata/faceTagFns.ts
12
13
  var shapeTagStore = /* @__PURE__ */ new WeakMap();
13
14
  var tagMetadataStore = /* @__PURE__ */ new WeakMap();
@@ -239,11 +240,11 @@ function propagateColorsFromEvolution(evolution, inputs, result) {
239
240
  */
240
241
  /**
241
242
  * O(1) check: does a shape carry any propagatable metadata (face origins,
242
- * tags, or colors)? Lets callers skip both expensive face iteration and
243
+ * tags, colors, or recorded roles)? Lets callers skip both expensive face iteration and
243
244
  * metadata-preserving slow paths when there's nothing to preserve.
244
245
  */
245
246
  function hasAnyMetadata(shape) {
246
- return getFaceOrigins(shape) !== void 0 || hasFaceTags(shape) || hasColorMetadata(shape);
247
+ return getFaceOrigins(shape) !== void 0 || hasFaceTags(shape) || hasColorMetadata(shape) || hasFaceRoles(shape);
247
248
  }
248
249
  function collectInputFaceHashes(inputs) {
249
250
  if (!inputs.some(hasAnyMetadata)) return [];
@@ -252,7 +253,7 @@ function collectInputFaceHashes(inputs) {
252
253
  return hashes;
253
254
  }
254
255
  /**
255
- * Propagate all metadata (origins, tags, colors) from inputs to result
256
+ * Propagate all metadata (origins, tags, colors, recorded roles) from inputs to result
256
257
  * using a kernel-provided ShapeEvolution record.
257
258
  *
258
259
  * This is the standard pipeline for any operation that returns
@@ -262,6 +263,7 @@ function propagateAllMetadata(evolution, inputs, result) {
262
263
  propagateOriginsFromEvolution(evolution, inputs, result);
263
264
  propagateFaceTagsFromEvolution(evolution, inputs, result);
264
265
  propagateColorsFromEvolution(evolution, inputs, result);
266
+ propagateFaceRolesFromEvolution(evolution, inputs, result);
265
267
  }
266
268
  /**
267
269
  * Fallback metadata propagation when no ShapeEvolution is available.
@@ -1,7 +1,7 @@
1
- import { G as _usingCtx, N as DisposalScope, c as createEdge, l as createFace, p as createWire, q as getKernel, y as isFace } from "./shapeTypes-DVpJHhgk.js";
2
- import { E as ok, d as validationError, g as err, i as kernelError, m as andThen } from "./errors-CDSezF9z.js";
3
- import { a as isPlanarFace } from "./validityTypes-2DNKAPEw.js";
4
- import { _ as cast, u as outerWire } from "./faceFns-DhdweJGk.js";
1
+ import { G as _usingCtx, N as DisposalScope, c as createEdge, l as createFace, p as createWire, q as getKernel, y as isFace } from "./shapeTypes-CqNJoSam.js";
2
+ import { E as ok, d as validationError, g as err, i as kernelError, m as andThen } from "./errors-Zb3jBa0u.js";
3
+ import { a as isPlanarFace } from "./validityTypes-t7JpS0Ki.js";
4
+ import { _ as cast, u as outerWire } from "./faceFns-CTlJC5IY.js";
5
5
  //#region src/utils/range.ts
6
6
  /** Generate an array of integers `[0, 1, …, len - 1]`. */
7
7
  function range(len) {
@@ -1,7 +1,7 @@
1
- const require_shapeTypes = require("./shapeTypes-BWsKDxzf.cjs");
2
- const require_errors = require("./errors-gG-7hA7k.cjs");
3
- const require_validityTypes = require("./validityTypes-D9oxhu4U.cjs");
4
- const require_faceFns = require("./faceFns-DaXVpMr5.cjs");
1
+ const require_shapeTypes = require("./shapeTypes-DH2ShBU_.cjs");
2
+ const require_errors = require("./errors-jwhfQJZK.cjs");
3
+ const require_validityTypes = require("./validityTypes-r0A2YdNq.cjs");
4
+ const require_faceFns = require("./faceFns-CZeHWke7.cjs");
5
5
  //#region src/utils/range.ts
6
6
  /** Generate an array of integers `[0, 1, …, len - 1]`. */
7
7
  function range(len) {
package/dist/text.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_textBlueprints = require("./textBlueprints-DQi920gG.cjs");
3
- const require_textMetrics = require("./textMetrics-DhysRMr7.cjs");
2
+ const require_textBlueprints = require("./textBlueprints-fa7VHJZz.cjs");
3
+ const require_textMetrics = require("./textMetrics--cikHkGX.cjs");
4
4
  exports.fontMetrics = require_textMetrics.fontMetrics;
5
5
  exports.getFont = require_textBlueprints.getFont;
6
6
  exports.loadFont = require_textBlueprints.loadFont;
package/dist/text.js CHANGED
@@ -1,3 +1,3 @@
1
- import { n as getFont, r as loadFont, t as textBlueprints } from "./textBlueprints-bFsyNLkO.js";
2
- import { n as textMetrics, r as sketchText, t as fontMetrics } from "./textMetrics-CvTwh4tR.js";
1
+ import { n as getFont, r as loadFont, t as textBlueprints } from "./textBlueprints-C13NAA3C.js";
2
+ import { n as textMetrics, r as sketchText, t as fontMetrics } from "./textMetrics-Dcc63qRm.js";
3
3
  export { fontMetrics, getFont, loadFont, sketchText, textBlueprints, textMetrics };
@@ -1,17 +1,171 @@
1
- import { d as createSolid, h as disposeResultShape, l as createFace, m as disposeDowncastSource, n as castResultShape, p as createWire, q as getKernel, x as isShape3D } from "./shapeTypes-DVpJHhgk.js";
1
+ import { d as createSolid, h as disposeResultShape, l as createFace, m as disposeDowncastSource, n as castResultShape, p as createWire, q as getKernel, x as isShape3D } from "./shapeTypes-CqNJoSam.js";
2
2
  import { n as bug } from "./bug-BdOHwn_e.js";
3
- import { E as ok, P as unwrap, d as validationError, g as err, i as kernelError, l as typeCastError, r as ioError, t as BrepErrorCode } from "./errors-CDSezF9z.js";
3
+ import { E as ok, P as unwrap, d as validationError, g as err, i as kernelError, l as typeCastError, r as ioError, t as BrepErrorCode } from "./errors-Zb3jBa0u.js";
4
+ import { n as HASH_CODE_MAX } from "./constants-ITRzCnCp.js";
4
5
  import { r as toVec3 } from "./types-D24Y27N0.js";
5
- import { c as vecLength, d as vecNormalize, h as vecScale, r as vecCross } from "./vecOps-SKPRvPH-.js";
6
- import { n as createPlane } from "./planeOps-BO6nvRja.js";
7
- import { v as copyShape } from "./faceFns-DhdweJGk.js";
8
- import { o as makeSolid, p as cutAll, t as makeCompound } from "./solidBuilders-p_ppeTkc.js";
9
- import { l as curveStartPoint, u as curveTangentAt } from "./curveFns-D5V4jm7S.js";
6
+ import { c as vecLength, d as vecNormalize, h as vecScale, i as vecDistance, r as vecCross, t as vecAdd } from "./vecOps-SKPRvPH-.js";
7
+ import { n as createPlane } from "./planeOps-Cxws4Tiu.js";
8
+ import { v as copyShape } from "./faceFns-CTlJC5IY.js";
9
+ import { o as makeSolid, p as cutAll, t as makeCompound } from "./solidBuilders-IstbiWju.js";
10
+ import { i as setFaceRoles } from "./faceRoleFns-CWU1-Pm8.js";
11
+ import { l as curveStartPoint, u as curveTangentAt } from "./curveFns-KS1BWGhF.js";
10
12
  import { n as getAtOrThrow, t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
11
- import { i as makeNewFaceWithinFace, r as makeFace, t as addHolesInFace } from "./surfaceBuilders-Dccm2kQX.js";
12
- import { r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-kV7aFwRS.js";
13
- import { c as twistExtrude, r as complexExtrude, s as sweep, t as loft } from "./loftFns-DE1GYW9g.js";
13
+ import { i as makeNewFaceWithinFace, r as makeFace, t as addHolesInFace } from "./surfaceBuilders-8nLk2PWk.js";
14
+ import { r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-FywUpRiV.js";
15
+ import { c as twistExtrude, r as complexExtrude, s as sweep, t as loft } from "./loftFns-B5mq1WDh.js";
14
16
  import opentype from "opentype.js";
17
+ //#region src/topology/shapeRef/extrudeRoleFns.ts
18
+ /** Match tolerance as a fraction of the extrusion's size. */
19
+ var RELATIVE_TOLERANCE = 1e-6;
20
+ function centerOf({ min, max }) {
21
+ return [
22
+ (min[0] + max[0]) / 2,
23
+ (min[1] + max[1]) / 2,
24
+ (min[2] + max[2]) / 2
25
+ ];
26
+ }
27
+ function boxCenter(shape) {
28
+ return centerOf(getKernel().boundingBox(shape));
29
+ }
30
+ function edgeCenters(wire) {
31
+ const kernel = getKernel();
32
+ const centers = [];
33
+ for (const edge of kernel.iterShapes(wire, "edge")) try {
34
+ centers.push(boxCenter(edge));
35
+ } finally {
36
+ kernel.dispose(edge);
37
+ }
38
+ return centers;
39
+ }
40
+ /**
41
+ * Where each role's face sits, as a bounding-box center. A face swept from an
42
+ * edge is the edge's Minkowski sum with the segment [0, vector], so its box
43
+ * center is the edge's box center + vector / 2; the caps are translated copies
44
+ * of the profile. This holds for exact boxes (OCCT) and vertex boxes (brepkit)
45
+ * alike, so predicted and actual centers agree to rounding.
46
+ */
47
+ function anchorsFor(profile, start, vector) {
48
+ const kernel = getKernel();
49
+ const anchors = [{
50
+ role: "extrude:start",
51
+ point: start
52
+ }, {
53
+ role: "extrude:end",
54
+ point: vecAdd(start, vector)
55
+ }];
56
+ const halfVector = vecScale(vector, .5);
57
+ const outer = kernel.outerWire(profile);
58
+ try {
59
+ let hole = 0;
60
+ for (const wire of kernel.iterShapes(profile, "wire")) try {
61
+ const prefix = kernel.isSame(wire, outer) ? "extrude:side" : `extrude:hole${hole++}:side`;
62
+ edgeCenters(wire).forEach((center, i) => {
63
+ anchors.push({
64
+ role: `${prefix}:${i}`,
65
+ point: vecAdd(center, halfVector)
66
+ });
67
+ });
68
+ } finally {
69
+ kernel.dispose(wire);
70
+ }
71
+ } finally {
72
+ kernel.dispose(outer);
73
+ }
74
+ return anchors;
75
+ }
76
+ function locateFaces(solid) {
77
+ const kernel = getKernel();
78
+ const located = [];
79
+ for (const face of kernel.iterShapes(solid, "face")) try {
80
+ located.push({
81
+ hash: kernel.hashCode(face, HASH_CODE_MAX),
82
+ point: boxCenter(face)
83
+ });
84
+ } finally {
85
+ kernel.dispose(face);
86
+ }
87
+ return located;
88
+ }
89
+ function lowerBound(sortedKeys, key) {
90
+ let lo = 0;
91
+ let hi = sortedKeys.length;
92
+ while (lo < hi) {
93
+ const mid = lo + hi >>> 1;
94
+ if ((sortedKeys[mid] ?? Infinity) < key) lo = mid + 1;
95
+ else hi = mid;
96
+ }
97
+ return lo;
98
+ }
99
+ /** The coordinate axis along which `points` spread furthest. */
100
+ function widestAxis(points) {
101
+ let axis = 0;
102
+ let widest = -Infinity;
103
+ for (const candidate of [
104
+ 0,
105
+ 1,
106
+ 2
107
+ ]) {
108
+ let min = Infinity;
109
+ let max = -Infinity;
110
+ for (const p of points) {
111
+ min = Math.min(min, p[candidate]);
112
+ max = Math.max(max, p[candidate]);
113
+ }
114
+ if (max - min > widest) {
115
+ axis = candidate;
116
+ widest = max - min;
117
+ }
118
+ }
119
+ return axis;
120
+ }
121
+ /**
122
+ * Pair each anchor with its nearest face within `tolerance`. Returns undefined
123
+ * unless the pairing is one-to-one over every face, so an unexpected topology
124
+ * records nothing rather than wrong names. Candidates are windowed along the
125
+ * axis the face centers spread furthest on: a profile in the YZ plane puts
126
+ * every side face at one X, which would make a fixed X window scan them all.
127
+ */
128
+ function matchAnchors(anchors, faces, tolerance) {
129
+ if (anchors.length !== faces.length) return void 0;
130
+ const axis = widestAxis(faces.map((f) => f.point));
131
+ const sorted = [...faces].sort((a, b) => a.point[axis] - b.point[axis]);
132
+ const keys = sorted.map((f) => f.point[axis]);
133
+ const claimed = /* @__PURE__ */ new Set();
134
+ const roles = /* @__PURE__ */ new Map();
135
+ for (const { role, point } of anchors) {
136
+ let best = -1;
137
+ let bestDistance = tolerance;
138
+ for (let i = lowerBound(keys, point[axis] - tolerance); i < sorted.length; i++) {
139
+ const face = sorted[i];
140
+ if (face === void 0 || face.point[axis] > point[axis] + tolerance) break;
141
+ const d = vecDistance(face.point, point);
142
+ if (d <= bestDistance) {
143
+ best = i;
144
+ bestDistance = d;
145
+ }
146
+ }
147
+ const match = best < 0 ? void 0 : sorted[best];
148
+ if (match === void 0 || claimed.has(best)) return void 0;
149
+ claimed.add(best);
150
+ roles.set(match.hash, role);
151
+ }
152
+ return roles;
153
+ }
154
+ /**
155
+ * Record `extrude:*` face roles on `solid`, the extrusion of `profile` along
156
+ * `vector`, for `assignRoles(solid, 'extrude')` to read. Records nothing on a
157
+ * mesh kernel, or when the faces don't pair one-to-one with the profile's caps
158
+ * and edges; `assignRoles` then falls back to positional names.
159
+ */
160
+ function recordExtrudeRoles(solid, profile, vector) {
161
+ const kernel = getKernel();
162
+ if (!kernel.capabilities.exact) return;
163
+ const profileBox = kernel.boundingBox(profile.wrapped);
164
+ const size = vecDistance(profileBox.min, profileBox.max) + vecLength(vector);
165
+ const roles = matchAnchors(anchorsFor(profile.wrapped, centerOf(profileBox), vector), locateFaces(solid.wrapped), RELATIVE_TOLERANCE * size);
166
+ if (roles) setFaceRoles(solid, roles);
167
+ }
168
+ //#endregion
15
169
  //#region src/operations/extrudeFns.ts
16
170
  /**
17
171
  * Basic extrusion operations — extrude and revolve.
@@ -22,6 +176,10 @@ import opentype from "opentype.js";
22
176
  /**
23
177
  * Extrude a face along a vector to produce a solid.
24
178
  *
179
+ * The result carries semantic face roles (`extrude:start`, `extrude:end`,
180
+ * `extrude:side:<i>`, `extrude:hole<j>:side:<i>`) that
181
+ * `assignRoles(solid, 'extrude')` returns in place of positional names.
182
+ *
25
183
  * @param face - The planar face to extrude.
26
184
  * @param extrusionVec - Direction and magnitude of the extrusion as `[x, y, z]`.
27
185
  * @returns `Result` containing the extruded solid, or an error if validation or operation fails.
@@ -37,6 +195,7 @@ function extrude(face, extrusionVec) {
37
195
  const downcastShape = kernel.downcast(shape, "solid");
38
196
  const solid = createSolid(downcastShape);
39
197
  disposeDowncastSource(shape, solid);
198
+ recordExtrudeRoles(solid, face, extrusionVec);
40
199
  return ok(solid);
41
200
  } catch (e) {
42
201
  return err(kernelError("EXTRUDE_FAILED", "Extrusion operation failed", e, {