brepjs 18.111.0 → 18.113.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.
package/dist/brepjs.cjs CHANGED
@@ -16,7 +16,7 @@ const require_meshFns = require("./meshFns-1hQSn1p2.cjs");
16
16
  const require_arrayAccess = require("./arrayAccess-e4H9cBfh.cjs");
17
17
  const require_surfaceBuilders = require("./surfaceBuilders-UyyfZy8w.cjs");
18
18
  const require_solidBuilders = require("./solidBuilders-DiUv_mD0.cjs");
19
- const require_healingFns = require("./healingFns-C4UE1ZyM.cjs");
19
+ const require_healingFns = require("./healingFns-x1sHV-HO.cjs");
20
20
  const require_threadFns = require("./threadFns-C8bErjVC.cjs");
21
21
  const require_blueprintSketcher = require("./blueprintSketcher-RK-cH6ps.cjs");
22
22
  const require_helpers = require("./helpers-BSLPCflF.cjs");
@@ -1175,9 +1175,16 @@ function withKernelDir(v, fn) {
1175
1175
  }
1176
1176
  }
1177
1177
  //#endregion
1178
- //#region src/topology/shapeRef/edgeRefFns.ts
1179
- /** Midpoint of an edge's endpoint vertices (a closed edge collapses to one). */
1180
- function endpointMidpoint(verts) {
1178
+ //#region src/topology/shapeRef/roleLookup.ts
1179
+ /** Euclidean distance between two points. */
1180
+ function distance(a, b) {
1181
+ const dx = a[0] - b[0];
1182
+ const dy = a[1] - b[1];
1183
+ const dz = a[2] - b[2];
1184
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
1185
+ }
1186
+ /** Mean of a set of vertices' positions (e.g. an edge's endpoints). */
1187
+ function vertexCentroid(verts) {
1181
1188
  if (verts.length === 0) return void 0;
1182
1189
  let x = 0;
1183
1190
  let y = 0;
@@ -1195,33 +1202,29 @@ function endpointMidpoint(verts) {
1195
1202
  z / n
1196
1203
  ];
1197
1204
  }
1198
- function distance(a, b) {
1199
- const dx = a[0] - b[0];
1200
- const dy = a[1] - b[1];
1201
- const dz = a[2] - b[2];
1202
- return Math.sqrt(dx * dx + dy * dy + dz * dz);
1203
- }
1204
- function captureEdgeHint(edge) {
1205
- const lengthResult = require_measureFns.measureLength(edge);
1206
- return {
1207
- entityType: "edge",
1208
- length: lengthResult.ok ? lengthResult.value : void 0,
1209
- midpoint: endpointMidpoint(require_healingFns.verticesOfEdge(edge))
1210
- };
1211
- }
1212
- /** Reverse the role table: the role whose tracked hashes include this face. */
1205
+ /** The role whose tracked hashes include this face (reverse lookup). */
1213
1206
  function roleOfFace(face, origin, roles) {
1214
1207
  const originRoles = roles.get(origin);
1215
1208
  if (!originRoles) return void 0;
1216
1209
  const hash = require_shapeFns.getHashCode(face);
1217
1210
  for (const [role, hashes] of originRoles) if (hashes.includes(hash)) return role;
1218
1211
  }
1219
- /** Current faces a role resolves to (its tracked successors present in `shape`). */
1212
+ /** Current faces a role resolves to its tracked successors present in `shape`. */
1220
1213
  function facesForRole(shape, origin, role, roles) {
1221
1214
  const hashes = roles.get(origin)?.get(role);
1222
1215
  if (hashes === void 0 || hashes.length === 0) return [];
1223
1216
  return require_topologyQueryFns.getFaces(shape).filter((f) => hashes.includes(require_shapeFns.getHashCode(f)));
1224
1217
  }
1218
+ //#endregion
1219
+ //#region src/topology/shapeRef/edgeRefFns.ts
1220
+ function captureEdgeHint(edge) {
1221
+ const lengthResult = require_measureFns.measureLength(edge);
1222
+ return {
1223
+ entityType: "edge",
1224
+ length: lengthResult.ok ? lengthResult.value : void 0,
1225
+ midpoint: vertexCentroid(require_healingFns.verticesOfEdge(edge))
1226
+ };
1227
+ }
1225
1228
  function dedupeEdges(edges) {
1226
1229
  const seen = /* @__PURE__ */ new Set();
1227
1230
  const out = [];
@@ -1235,7 +1238,7 @@ function dedupeEdges(edges) {
1235
1238
  return out;
1236
1239
  }
1237
1240
  /** Hint scores closer than this are treated as indistinguishable (→ ambiguous). */
1238
- var HINT_MARGIN = 1e-6;
1241
+ var HINT_MARGIN$2 = 1e-6;
1239
1242
  /**
1240
1243
  * Pick the candidate edge closest to the hint (length + endpoint midpoint).
1241
1244
  * Returns undefined when it genuinely can't discriminate — the hint carries no
@@ -1254,7 +1257,7 @@ function bestByHint(candidates, hint) {
1254
1257
  if (len.ok) score += Math.abs(len.value - hint.length);
1255
1258
  }
1256
1259
  if (hint.midpoint !== void 0) {
1257
- const mid = endpointMidpoint(require_healingFns.verticesOfEdge(edge));
1260
+ const mid = vertexCentroid(require_healingFns.verticesOfEdge(edge));
1258
1261
  if (mid !== void 0) score += distance(hint.midpoint, mid);
1259
1262
  }
1260
1263
  if (score < bestScore) {
@@ -1263,7 +1266,7 @@ function bestByHint(candidates, hint) {
1263
1266
  best = edge;
1264
1267
  } else if (score < secondScore) secondScore = score;
1265
1268
  }
1266
- if (best === void 0 || secondScore - bestScore < HINT_MARGIN) return void 0;
1269
+ if (best === void 0 || secondScore - bestScore < HINT_MARGIN$2) return void 0;
1267
1270
  return best;
1268
1271
  }
1269
1272
  /**
@@ -1325,6 +1328,237 @@ function resolveEdgeRef(ref, roles, shape) {
1325
1328
  };
1326
1329
  }
1327
1330
  //#endregion
1331
+ //#region src/topology/shapeRef/vertexRefFns.ts
1332
+ /** A corner needs at least this many faces to pin a unique point. */
1333
+ var MIN_VERTEX_FACES = 3;
1334
+ /** Hint distances closer than this are indistinguishable (→ ambiguous). */
1335
+ var HINT_MARGIN$1 = 1e-6;
1336
+ /** Hashes of all vertices across `faces`, recording one handle per hash. */
1337
+ function vertexHashes(faces, handles) {
1338
+ const hashes = /* @__PURE__ */ new Set();
1339
+ for (const f of faces) for (const v of require_healingFns.verticesOfFace(f)) {
1340
+ const h = require_shapeFns.getHashCode(v);
1341
+ hashes.add(h);
1342
+ if (!handles.has(h)) handles.set(h, v);
1343
+ }
1344
+ return hashes;
1345
+ }
1346
+ function intersect$2(a, b) {
1347
+ const out = /* @__PURE__ */ new Set();
1348
+ for (const h of a) if (b.has(h)) out.add(h);
1349
+ return out;
1350
+ }
1351
+ /** Vertices present in (a face of) every face-set — the shared corner(s). */
1352
+ function commonVertices(faceSets) {
1353
+ const handles = /* @__PURE__ */ new Map();
1354
+ let common;
1355
+ for (const faces of faceSets) {
1356
+ const hashes = vertexHashes(faces, handles);
1357
+ common = common === void 0 ? hashes : intersect$2(common, hashes);
1358
+ }
1359
+ if (common === void 0) return [];
1360
+ const result = [];
1361
+ for (const h of common) {
1362
+ const v = handles.get(h);
1363
+ if (v !== void 0) result.push(v);
1364
+ }
1365
+ return result;
1366
+ }
1367
+ /** Nearest candidate to the hint position; undefined if no signal or a tie. */
1368
+ function nearestToHint(vertices, hint) {
1369
+ if (hint.position === void 0) return void 0;
1370
+ let best;
1371
+ let bestDist = Infinity;
1372
+ let secondDist = Infinity;
1373
+ for (const v of vertices) {
1374
+ const d = distance(require_topologyQueryFns.vertexPosition(v), hint.position);
1375
+ if (d < bestDist) {
1376
+ secondDist = bestDist;
1377
+ bestDist = d;
1378
+ best = v;
1379
+ } else if (d < secondDist) secondDist = d;
1380
+ }
1381
+ if (best === void 0 || secondDist - bestDist < HINT_MARGIN$1) return void 0;
1382
+ return best;
1383
+ }
1384
+ /**
1385
+ * Capture a lineage-based reference to `vertex`: the roles of the ≥3 faces
1386
+ * meeting at it, plus a position hint. Returns undefined when fewer than three
1387
+ * named faces meet there (a 2-face "vertex" is ambiguous — an edge has two).
1388
+ */
1389
+ function createVertexRef(origin, vertex, shape, roles) {
1390
+ const faces = require_healingFns.facesOfVertex(shape, vertex);
1391
+ if (faces.length < MIN_VERTEX_FACES) return void 0;
1392
+ const roleSet = /* @__PURE__ */ new Set();
1393
+ for (const f of faces) {
1394
+ const role = roleOfFace(f, origin, roles);
1395
+ if (role !== void 0) roleSet.add(role);
1396
+ }
1397
+ if (roleSet.size < MIN_VERTEX_FACES) return void 0;
1398
+ return {
1399
+ origin,
1400
+ faceRoles: [...roleSet].sort(),
1401
+ hint: {
1402
+ entityType: "vertex",
1403
+ position: require_topologyQueryFns.vertexPosition(vertex)
1404
+ }
1405
+ };
1406
+ }
1407
+ /**
1408
+ * Resolve a VertexRef in `shape`: gather the current faces of each role, then
1409
+ * return the vertex common to all of them. One common vertex → exact; several →
1410
+ * disambiguate by hint position; none, or a missing role → broken.
1411
+ */
1412
+ function resolveVertexRef(ref, roles, shape) {
1413
+ const faceSets = [];
1414
+ for (const role of ref.faceRoles) {
1415
+ const faces = facesForRole(shape, ref.origin, role, roles);
1416
+ if (faces.length === 0) return {
1417
+ ref,
1418
+ reason: "not-found"
1419
+ };
1420
+ faceSets.push(faces);
1421
+ }
1422
+ const common = commonVertices(faceSets);
1423
+ if (common.length === 1) {
1424
+ const [only] = common;
1425
+ if (only !== void 0) return {
1426
+ vertex: only,
1427
+ confidence: "exact"
1428
+ };
1429
+ }
1430
+ if (common.length > 1) {
1431
+ const best = nearestToHint(common, ref.hint);
1432
+ if (best !== void 0) return {
1433
+ vertex: best,
1434
+ confidence: "geometric-fallback"
1435
+ };
1436
+ return {
1437
+ ref,
1438
+ reason: "ambiguous",
1439
+ candidates: common
1440
+ };
1441
+ }
1442
+ return {
1443
+ ref,
1444
+ reason: "not-found"
1445
+ };
1446
+ }
1447
+ //#endregion
1448
+ //#region src/topology/shapeRef/derivedFaceRefFns.ts
1449
+ /** A face re-derives a bridged face when its normal is nearly identical. */
1450
+ var NORMAL_MATCH = .99;
1451
+ /** A generated face's normal has a positive component along BOTH bridged normals. */
1452
+ var BLEND_THRESHOLD = .1;
1453
+ /** Tiebreak distances closer than this are indistinguishable (→ ambiguous). */
1454
+ var HINT_MARGIN = 1e-6;
1455
+ function normalDot(a, b) {
1456
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
1457
+ }
1458
+ /** Faces whose outward normal nearly matches `normal` (re-derives a bridged face). */
1459
+ function facesByNormal(shape, normal) {
1460
+ return require_topologyQueryFns.getFaces(shape).filter((f) => normalDot(require_faceFns.normalAt(f), normal) > NORMAL_MATCH);
1461
+ }
1462
+ /**
1463
+ * Faces adjacent to BOTH face sets, excluding the sets themselves. Uses the
1464
+ * cached edge→faces adjacency (`adjacentFaces`) rather than an O(F·N) per-pair
1465
+ * `sharedEdges` scan.
1466
+ */
1467
+ function betweenFaces(shape, aFaces, bFaces) {
1468
+ const exclude = new Set([...aFaces, ...bFaces].map(require_shapeFns.getHashCode));
1469
+ const adjacentToA = /* @__PURE__ */ new Set();
1470
+ for (const a of aFaces) for (const f of require_healingFns.adjacentFaces(shape, a)) adjacentToA.add(require_shapeFns.getHashCode(f));
1471
+ const result = [];
1472
+ const seen = /* @__PURE__ */ new Set();
1473
+ for (const b of bFaces) for (const f of require_healingFns.adjacentFaces(shape, b)) {
1474
+ const h = require_shapeFns.getHashCode(f);
1475
+ if (exclude.has(h) || seen.has(h) || !adjacentToA.has(h)) continue;
1476
+ seen.add(h);
1477
+ result.push(f);
1478
+ }
1479
+ return result;
1480
+ }
1481
+ /** Face whose center is nearest `point`; undefined on a tie (→ ambiguous). */
1482
+ function nearestFace(faces, point) {
1483
+ let best;
1484
+ let bestDist = Infinity;
1485
+ let secondDist = Infinity;
1486
+ for (const f of faces) {
1487
+ const d = distance(require_faceFns.faceCenter(f), point);
1488
+ if (d < bestDist) {
1489
+ secondDist = bestDist;
1490
+ bestDist = d;
1491
+ best = f;
1492
+ } else if (d < secondDist) secondDist = d;
1493
+ }
1494
+ if (best === void 0 || secondDist - bestDist < HINT_MARGIN) return void 0;
1495
+ return best;
1496
+ }
1497
+ /**
1498
+ * Capture a reference to the face an `op` (fillet/chamfer) will generate across
1499
+ * `edge`: the roles of the edge's two faces, their outward normals, and the edge
1500
+ * midpoint. Call this on the PRE-op shape. Returns undefined when the edge
1501
+ * doesn't bound two named faces.
1502
+ */
1503
+ function createDerivedFaceRef(origin, op, edge, preShape, roles) {
1504
+ const [faceA, faceB] = require_healingFns.facesOfEdge(preShape, edge);
1505
+ if (faceA === void 0 || faceB === void 0) return void 0;
1506
+ const roleA = roleOfFace(faceA, origin, roles);
1507
+ const roleB = roleOfFace(faceB, origin, roles);
1508
+ if (roleA === void 0 || roleB === void 0) return void 0;
1509
+ return {
1510
+ origin,
1511
+ op,
1512
+ betweenRoles: [roleA, roleB],
1513
+ hint: {
1514
+ entityType: "derived-face",
1515
+ normalA: require_faceFns.normalAt(faceA),
1516
+ normalB: require_faceFns.normalAt(faceB),
1517
+ edgeMidpoint: vertexCentroid(require_healingFns.verticesOfEdge(edge))
1518
+ }
1519
+ };
1520
+ }
1521
+ /**
1522
+ * Resolve a DerivedFaceRef in the post-op `shape`: re-derive the two bridged
1523
+ * faces (role table, else by captured normal), then return the face adjacent to
1524
+ * both whose normal blends both. One survivor → resolved; several →
1525
+ * nearest-to-edge-midpoint; none → broken.
1526
+ */
1527
+ function resolveDerivedFaceRef(ref, roles, shape) {
1528
+ let aFaces = facesForRole(shape, ref.origin, ref.betweenRoles[0], roles);
1529
+ if (aFaces.length === 0) aFaces = facesByNormal(shape, ref.hint.normalA);
1530
+ let bFaces = facesForRole(shape, ref.origin, ref.betweenRoles[1], roles);
1531
+ if (bFaces.length === 0) bFaces = facesByNormal(shape, ref.hint.normalB);
1532
+ if (aFaces.length === 0 || bFaces.length === 0) return {
1533
+ ref,
1534
+ reason: "not-found"
1535
+ };
1536
+ const blended = betweenFaces(shape, aFaces, bFaces).filter((f) => normalDot(require_faceFns.normalAt(f), ref.hint.normalA) > BLEND_THRESHOLD && normalDot(require_faceFns.normalAt(f), ref.hint.normalB) > BLEND_THRESHOLD);
1537
+ if (blended.length === 1) {
1538
+ const [only] = blended;
1539
+ if (only !== void 0) return {
1540
+ face: only,
1541
+ confidence: "geometric-fallback"
1542
+ };
1543
+ }
1544
+ if (blended.length > 1) {
1545
+ const best = ref.hint.edgeMidpoint && nearestFace(blended, ref.hint.edgeMidpoint);
1546
+ if (best) return {
1547
+ face: best,
1548
+ confidence: "geometric-fallback"
1549
+ };
1550
+ return {
1551
+ ref,
1552
+ reason: "ambiguous",
1553
+ candidates: blended
1554
+ };
1555
+ }
1556
+ return {
1557
+ ref,
1558
+ reason: "not-found"
1559
+ };
1560
+ }
1561
+ //#endregion
1328
1562
  //#region src/topology/surfaceFns.ts
1329
1563
  /**
1330
1564
  * Surface creation functions — generate faces from height-map grids.
@@ -7028,6 +7262,7 @@ exports.createBlueprint = require_blueprintFns.createBlueprint;
7028
7262
  exports.createCamera = require_cameraFns.createCamera;
7029
7263
  exports.createCompound = require_shapeTypes.createCompound;
7030
7264
  exports.createCompoundBlueprint = require_blueprintFns.createCompoundBlueprint;
7265
+ exports.createDerivedFaceRef = createDerivedFaceRef;
7031
7266
  exports.createDistanceQuery = require_measureFns.createDistanceQuery;
7032
7267
  exports.createEdge = require_shapeTypes.createEdge;
7033
7268
  exports.createEdgeRef = createEdgeRef;
@@ -7045,6 +7280,7 @@ exports.createShell = require_shapeTypes.createShell;
7045
7280
  exports.createSolid = require_shapeTypes.createSolid;
7046
7281
  exports.createTaskQueue = require_workerPool.createTaskQueue;
7047
7282
  exports.createVertex = require_shapeTypes.createVertex;
7283
+ exports.createVertexRef = createVertexRef;
7048
7284
  exports.createWire = require_shapeTypes.createWire;
7049
7285
  exports.createWorkerClient = require_workerPool.createWorkerClient;
7050
7286
  exports.createWorkerHandler = require_workerPool.createWorkerHandler;
@@ -7136,6 +7372,7 @@ exports.faceFinder = require_helpers.faceFinder;
7136
7372
  exports.faceGeomType = require_faceFns.faceGeomType;
7137
7373
  exports.faceOrientation = require_faceFns.faceOrientation;
7138
7374
  exports.facesOfEdge = require_healingFns.facesOfEdge;
7375
+ exports.facesOfVertex = require_healingFns.facesOfVertex;
7139
7376
  exports.fieldBoolean = fieldBoolean;
7140
7377
  exports.fieldContour = fieldContour;
7141
7378
  exports.fieldOffset = fieldOffset;
@@ -7417,10 +7654,12 @@ exports.resetPerformanceStats = require_shapeTypes.resetPerformanceStats;
7417
7654
  exports.resize = require_shapeFns.resize;
7418
7655
  exports.resolve = resolve;
7419
7656
  exports.resolve3D = resolve3D;
7657
+ exports.resolveDerivedFaceRef = resolveDerivedFaceRef;
7420
7658
  exports.resolveDirection = require_types.resolveDirection;
7421
7659
  exports.resolveEdgeRef = resolveEdgeRef;
7422
7660
  exports.resolvePlane = require_planeOps.resolvePlane;
7423
7661
  exports.resolveRef = require_shapeRefFns.resolveRef;
7662
+ exports.resolveVertexRef = resolveVertexRef;
7424
7663
  exports.reverseCurve = require_blueprintFns.reverseCurve;
7425
7664
  exports.revoluteJoint = require_threadFns.revoluteJoint;
7426
7665
  exports.revolve = revolve;
@@ -7570,6 +7809,7 @@ exports.vertex = require_primitiveFns.vertex;
7570
7809
  exports.vertexFinder = vertexFinder;
7571
7810
  exports.vertexPosition = require_topologyQueryFns.vertexPosition;
7572
7811
  exports.verticesOfEdge = require_healingFns.verticesOfEdge;
7812
+ exports.verticesOfFace = require_healingFns.verticesOfFace;
7573
7813
  exports.voxelBoolean = voxelBoolean;
7574
7814
  exports.voxelBooleanField = voxelBooleanField;
7575
7815
  exports.voxelBooleanFieldShapes = voxelBooleanFieldShapes;
package/dist/brepjs.js CHANGED
@@ -13,8 +13,8 @@ import { a as curveIsPeriodic, c as curvePointAt, d as flipOrientation, f as get
13
13
  import { a as meshEdges$1, c as meshMultiLOD, d as createMeshCache, i as mesh$1, l as buildMeshCacheKey, n as exportSTEP, o as meshLODs, r as exportSTL, s as meshLODsProgressive, t as exportIGES, u as clearMeshCache } from "./meshFns-DbmidUzH.js";
14
14
  import { n as getAtOrThrow, r as lastOrThrow, t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
15
15
  import { _ as makeThreePointArc, d as makeCircle, h as makeLine, l as makeBSplineInterpolation, n as fill, r as makeFace, s as assembleWire } from "./surfaceBuilders-rkE-jE90.js";
16
- import { _ as section$1, b as split$1, d as booleanPipeline, f as cut$2, g as intersect$2, h as fuseAll$2, m as fuse$2, p as cutAll$2, r as makeCylinder, t as makeCompound, v as sectionToFace$1, y as slice$1 } from "./solidBuilders-C32wXQWG.js";
17
- import { A as edgesOfFace, B as toLineGeometryData, C as shellWithEvolution, D as getNurbsCurveData, E as fuseAllBisect, F as chamferDistAngle, I as toBufferGeometryData, L as toGroupedBufferGeometryData, M as sharedEdges, N as verticesOfEdge, O as getNurbsSurfaceData, P as wiresOfFace, R as toLODGeometryData, S as intersectWithEvolution, T as cutAllBisect, _ as positionOnCurve, a as healFace, b as filletWithEvolution, c as isValid$1, d as draft$1, f as fillet$1, g as variableFillet, h as thicken$1, i as heal$1, j as facesOfEdge, k as adjacentFaces, l as solidFromShell, m as shell$1, n as fixSelfIntersection, o as healSolid, p as offset$1, r as fixShape, s as healWire, t as autoHeal, u as chamfer$1, v as chamferWithEvolution, w as checkBoolean, x as fuseWithEvolution, y as cutWithEvolution, z as toLODGeometryLevels } from "./healingFns-CPm_VFck.js";
16
+ import { _ as section$1, b as split$1, d as booleanPipeline, f as cut$2, g as intersect$3, h as fuseAll$2, m as fuse$2, p as cutAll$2, r as makeCylinder, t as makeCompound, v as sectionToFace$1, y as slice$1 } from "./solidBuilders-C32wXQWG.js";
17
+ import { A as edgesOfFace, B as toLODGeometryData, C as shellWithEvolution, D as getNurbsCurveData, E as fuseAllBisect, F as verticesOfFace, H as toLineGeometryData, I as wiresOfFace, L as chamferDistAngle, M as facesOfVertex, N as sharedEdges, O as getNurbsSurfaceData, P as verticesOfEdge, R as toBufferGeometryData, S as intersectWithEvolution, T as cutAllBisect, V as toLODGeometryLevels, _ as positionOnCurve, a as healFace, b as filletWithEvolution, c as isValid$1, d as draft$1, f as fillet$1, g as variableFillet, h as thicken$1, i as heal$1, j as facesOfEdge, k as adjacentFaces, l as solidFromShell, m as shell$1, n as fixSelfIntersection, o as healSolid, p as offset$1, r as fixShape, s as healWire, t as autoHeal, u as chamfer$1, v as chamferWithEvolution, w as checkBoolean, x as fuseWithEvolution, y as cutWithEvolution, z as toGroupedBufferGeometryData } from "./healingFns-D00TPE9p.js";
18
18
  import { A as setJointValue, B as findNode, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, F as quatRotate, G as gridPattern, H as updateNode, I as addChild, J as createAssembly, K as linearPattern, L as collectShapes, M as sphericalJoint, N as quatFromAxisAngle, O as prismaticJoint, P as quatFromTo, R as countNodes, S as addJoint, T as jointTransform, U as walkAssembly, V as removeChild, W as circularPattern, _ as exportURDF, a as deserializeHistory, b as inverseKinematics, c as modifyStep, d as replayFrom, f as replayHistory, g as undoLast, h as stepsFrom, i as createRegistry, j as setJointValues, k as revoluteJoint, l as registerOperation, m as stepCount, n as addStep, o as findStep, p as serializeHistory, q as exportAssemblySTEP, r as createHistory, s as getShape, t as thread, u as registerShape, v as importURDF, w as forwardKinematics, x as jointTrajectory, y as jointsFromDH, z as createAssemblyNode } from "./threadFns-bCOhVQLb.js";
19
19
  import { n as BaseSketcher2d, r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-7rtwqUHZ.js";
20
20
  import { a as createTypedFinder, i as wireFinder, n as edgeFinder, r as faceFinder, t as getSingleFace } from "./helpers-DhJwFrkC.js";
@@ -1186,9 +1186,16 @@ function withKernelDir(v, fn) {
1186
1186
  }
1187
1187
  }
1188
1188
  //#endregion
1189
- //#region src/topology/shapeRef/edgeRefFns.ts
1190
- /** Midpoint of an edge's endpoint vertices (a closed edge collapses to one). */
1191
- function endpointMidpoint(verts) {
1189
+ //#region src/topology/shapeRef/roleLookup.ts
1190
+ /** Euclidean distance between two points. */
1191
+ function distance(a, b) {
1192
+ const dx = a[0] - b[0];
1193
+ const dy = a[1] - b[1];
1194
+ const dz = a[2] - b[2];
1195
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
1196
+ }
1197
+ /** Mean of a set of vertices' positions (e.g. an edge's endpoints). */
1198
+ function vertexCentroid(verts) {
1192
1199
  if (verts.length === 0) return void 0;
1193
1200
  let x = 0;
1194
1201
  let y = 0;
@@ -1206,33 +1213,29 @@ function endpointMidpoint(verts) {
1206
1213
  z / n
1207
1214
  ];
1208
1215
  }
1209
- function distance(a, b) {
1210
- const dx = a[0] - b[0];
1211
- const dy = a[1] - b[1];
1212
- const dz = a[2] - b[2];
1213
- return Math.sqrt(dx * dx + dy * dy + dz * dz);
1214
- }
1215
- function captureEdgeHint(edge) {
1216
- const lengthResult = measureLength(edge);
1217
- return {
1218
- entityType: "edge",
1219
- length: lengthResult.ok ? lengthResult.value : void 0,
1220
- midpoint: endpointMidpoint(verticesOfEdge(edge))
1221
- };
1222
- }
1223
- /** Reverse the role table: the role whose tracked hashes include this face. */
1216
+ /** The role whose tracked hashes include this face (reverse lookup). */
1224
1217
  function roleOfFace(face, origin, roles) {
1225
1218
  const originRoles = roles.get(origin);
1226
1219
  if (!originRoles) return void 0;
1227
1220
  const hash = getHashCode(face);
1228
1221
  for (const [role, hashes] of originRoles) if (hashes.includes(hash)) return role;
1229
1222
  }
1230
- /** Current faces a role resolves to (its tracked successors present in `shape`). */
1223
+ /** Current faces a role resolves to its tracked successors present in `shape`. */
1231
1224
  function facesForRole(shape, origin, role, roles) {
1232
1225
  const hashes = roles.get(origin)?.get(role);
1233
1226
  if (hashes === void 0 || hashes.length === 0) return [];
1234
1227
  return getFaces(shape).filter((f) => hashes.includes(getHashCode(f)));
1235
1228
  }
1229
+ //#endregion
1230
+ //#region src/topology/shapeRef/edgeRefFns.ts
1231
+ function captureEdgeHint(edge) {
1232
+ const lengthResult = measureLength(edge);
1233
+ return {
1234
+ entityType: "edge",
1235
+ length: lengthResult.ok ? lengthResult.value : void 0,
1236
+ midpoint: vertexCentroid(verticesOfEdge(edge))
1237
+ };
1238
+ }
1236
1239
  function dedupeEdges(edges) {
1237
1240
  const seen = /* @__PURE__ */ new Set();
1238
1241
  const out = [];
@@ -1246,7 +1249,7 @@ function dedupeEdges(edges) {
1246
1249
  return out;
1247
1250
  }
1248
1251
  /** Hint scores closer than this are treated as indistinguishable (→ ambiguous). */
1249
- var HINT_MARGIN = 1e-6;
1252
+ var HINT_MARGIN$2 = 1e-6;
1250
1253
  /**
1251
1254
  * Pick the candidate edge closest to the hint (length + endpoint midpoint).
1252
1255
  * Returns undefined when it genuinely can't discriminate — the hint carries no
@@ -1265,7 +1268,7 @@ function bestByHint(candidates, hint) {
1265
1268
  if (len.ok) score += Math.abs(len.value - hint.length);
1266
1269
  }
1267
1270
  if (hint.midpoint !== void 0) {
1268
- const mid = endpointMidpoint(verticesOfEdge(edge));
1271
+ const mid = vertexCentroid(verticesOfEdge(edge));
1269
1272
  if (mid !== void 0) score += distance(hint.midpoint, mid);
1270
1273
  }
1271
1274
  if (score < bestScore) {
@@ -1274,7 +1277,7 @@ function bestByHint(candidates, hint) {
1274
1277
  best = edge;
1275
1278
  } else if (score < secondScore) secondScore = score;
1276
1279
  }
1277
- if (best === void 0 || secondScore - bestScore < HINT_MARGIN) return void 0;
1280
+ if (best === void 0 || secondScore - bestScore < HINT_MARGIN$2) return void 0;
1278
1281
  return best;
1279
1282
  }
1280
1283
  /**
@@ -1336,6 +1339,237 @@ function resolveEdgeRef(ref, roles, shape) {
1336
1339
  };
1337
1340
  }
1338
1341
  //#endregion
1342
+ //#region src/topology/shapeRef/vertexRefFns.ts
1343
+ /** A corner needs at least this many faces to pin a unique point. */
1344
+ var MIN_VERTEX_FACES = 3;
1345
+ /** Hint distances closer than this are indistinguishable (→ ambiguous). */
1346
+ var HINT_MARGIN$1 = 1e-6;
1347
+ /** Hashes of all vertices across `faces`, recording one handle per hash. */
1348
+ function vertexHashes(faces, handles) {
1349
+ const hashes = /* @__PURE__ */ new Set();
1350
+ for (const f of faces) for (const v of verticesOfFace(f)) {
1351
+ const h = getHashCode(v);
1352
+ hashes.add(h);
1353
+ if (!handles.has(h)) handles.set(h, v);
1354
+ }
1355
+ return hashes;
1356
+ }
1357
+ function intersect$2(a, b) {
1358
+ const out = /* @__PURE__ */ new Set();
1359
+ for (const h of a) if (b.has(h)) out.add(h);
1360
+ return out;
1361
+ }
1362
+ /** Vertices present in (a face of) every face-set — the shared corner(s). */
1363
+ function commonVertices(faceSets) {
1364
+ const handles = /* @__PURE__ */ new Map();
1365
+ let common;
1366
+ for (const faces of faceSets) {
1367
+ const hashes = vertexHashes(faces, handles);
1368
+ common = common === void 0 ? hashes : intersect$2(common, hashes);
1369
+ }
1370
+ if (common === void 0) return [];
1371
+ const result = [];
1372
+ for (const h of common) {
1373
+ const v = handles.get(h);
1374
+ if (v !== void 0) result.push(v);
1375
+ }
1376
+ return result;
1377
+ }
1378
+ /** Nearest candidate to the hint position; undefined if no signal or a tie. */
1379
+ function nearestToHint(vertices, hint) {
1380
+ if (hint.position === void 0) return void 0;
1381
+ let best;
1382
+ let bestDist = Infinity;
1383
+ let secondDist = Infinity;
1384
+ for (const v of vertices) {
1385
+ const d = distance(vertexPosition(v), hint.position);
1386
+ if (d < bestDist) {
1387
+ secondDist = bestDist;
1388
+ bestDist = d;
1389
+ best = v;
1390
+ } else if (d < secondDist) secondDist = d;
1391
+ }
1392
+ if (best === void 0 || secondDist - bestDist < HINT_MARGIN$1) return void 0;
1393
+ return best;
1394
+ }
1395
+ /**
1396
+ * Capture a lineage-based reference to `vertex`: the roles of the ≥3 faces
1397
+ * meeting at it, plus a position hint. Returns undefined when fewer than three
1398
+ * named faces meet there (a 2-face "vertex" is ambiguous — an edge has two).
1399
+ */
1400
+ function createVertexRef(origin, vertex, shape, roles) {
1401
+ const faces = facesOfVertex(shape, vertex);
1402
+ if (faces.length < MIN_VERTEX_FACES) return void 0;
1403
+ const roleSet = /* @__PURE__ */ new Set();
1404
+ for (const f of faces) {
1405
+ const role = roleOfFace(f, origin, roles);
1406
+ if (role !== void 0) roleSet.add(role);
1407
+ }
1408
+ if (roleSet.size < MIN_VERTEX_FACES) return void 0;
1409
+ return {
1410
+ origin,
1411
+ faceRoles: [...roleSet].sort(),
1412
+ hint: {
1413
+ entityType: "vertex",
1414
+ position: vertexPosition(vertex)
1415
+ }
1416
+ };
1417
+ }
1418
+ /**
1419
+ * Resolve a VertexRef in `shape`: gather the current faces of each role, then
1420
+ * return the vertex common to all of them. One common vertex → exact; several →
1421
+ * disambiguate by hint position; none, or a missing role → broken.
1422
+ */
1423
+ function resolveVertexRef(ref, roles, shape) {
1424
+ const faceSets = [];
1425
+ for (const role of ref.faceRoles) {
1426
+ const faces = facesForRole(shape, ref.origin, role, roles);
1427
+ if (faces.length === 0) return {
1428
+ ref,
1429
+ reason: "not-found"
1430
+ };
1431
+ faceSets.push(faces);
1432
+ }
1433
+ const common = commonVertices(faceSets);
1434
+ if (common.length === 1) {
1435
+ const [only] = common;
1436
+ if (only !== void 0) return {
1437
+ vertex: only,
1438
+ confidence: "exact"
1439
+ };
1440
+ }
1441
+ if (common.length > 1) {
1442
+ const best = nearestToHint(common, ref.hint);
1443
+ if (best !== void 0) return {
1444
+ vertex: best,
1445
+ confidence: "geometric-fallback"
1446
+ };
1447
+ return {
1448
+ ref,
1449
+ reason: "ambiguous",
1450
+ candidates: common
1451
+ };
1452
+ }
1453
+ return {
1454
+ ref,
1455
+ reason: "not-found"
1456
+ };
1457
+ }
1458
+ //#endregion
1459
+ //#region src/topology/shapeRef/derivedFaceRefFns.ts
1460
+ /** A face re-derives a bridged face when its normal is nearly identical. */
1461
+ var NORMAL_MATCH = .99;
1462
+ /** A generated face's normal has a positive component along BOTH bridged normals. */
1463
+ var BLEND_THRESHOLD = .1;
1464
+ /** Tiebreak distances closer than this are indistinguishable (→ ambiguous). */
1465
+ var HINT_MARGIN = 1e-6;
1466
+ function normalDot(a, b) {
1467
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
1468
+ }
1469
+ /** Faces whose outward normal nearly matches `normal` (re-derives a bridged face). */
1470
+ function facesByNormal(shape, normal) {
1471
+ return getFaces(shape).filter((f) => normalDot(normalAt(f), normal) > NORMAL_MATCH);
1472
+ }
1473
+ /**
1474
+ * Faces adjacent to BOTH face sets, excluding the sets themselves. Uses the
1475
+ * cached edge→faces adjacency (`adjacentFaces`) rather than an O(F·N) per-pair
1476
+ * `sharedEdges` scan.
1477
+ */
1478
+ function betweenFaces(shape, aFaces, bFaces) {
1479
+ const exclude = new Set([...aFaces, ...bFaces].map(getHashCode));
1480
+ const adjacentToA = /* @__PURE__ */ new Set();
1481
+ for (const a of aFaces) for (const f of adjacentFaces(shape, a)) adjacentToA.add(getHashCode(f));
1482
+ const result = [];
1483
+ const seen = /* @__PURE__ */ new Set();
1484
+ for (const b of bFaces) for (const f of adjacentFaces(shape, b)) {
1485
+ const h = getHashCode(f);
1486
+ if (exclude.has(h) || seen.has(h) || !adjacentToA.has(h)) continue;
1487
+ seen.add(h);
1488
+ result.push(f);
1489
+ }
1490
+ return result;
1491
+ }
1492
+ /** Face whose center is nearest `point`; undefined on a tie (→ ambiguous). */
1493
+ function nearestFace(faces, point) {
1494
+ let best;
1495
+ let bestDist = Infinity;
1496
+ let secondDist = Infinity;
1497
+ for (const f of faces) {
1498
+ const d = distance(faceCenter(f), point);
1499
+ if (d < bestDist) {
1500
+ secondDist = bestDist;
1501
+ bestDist = d;
1502
+ best = f;
1503
+ } else if (d < secondDist) secondDist = d;
1504
+ }
1505
+ if (best === void 0 || secondDist - bestDist < HINT_MARGIN) return void 0;
1506
+ return best;
1507
+ }
1508
+ /**
1509
+ * Capture a reference to the face an `op` (fillet/chamfer) will generate across
1510
+ * `edge`: the roles of the edge's two faces, their outward normals, and the edge
1511
+ * midpoint. Call this on the PRE-op shape. Returns undefined when the edge
1512
+ * doesn't bound two named faces.
1513
+ */
1514
+ function createDerivedFaceRef(origin, op, edge, preShape, roles) {
1515
+ const [faceA, faceB] = facesOfEdge(preShape, edge);
1516
+ if (faceA === void 0 || faceB === void 0) return void 0;
1517
+ const roleA = roleOfFace(faceA, origin, roles);
1518
+ const roleB = roleOfFace(faceB, origin, roles);
1519
+ if (roleA === void 0 || roleB === void 0) return void 0;
1520
+ return {
1521
+ origin,
1522
+ op,
1523
+ betweenRoles: [roleA, roleB],
1524
+ hint: {
1525
+ entityType: "derived-face",
1526
+ normalA: normalAt(faceA),
1527
+ normalB: normalAt(faceB),
1528
+ edgeMidpoint: vertexCentroid(verticesOfEdge(edge))
1529
+ }
1530
+ };
1531
+ }
1532
+ /**
1533
+ * Resolve a DerivedFaceRef in the post-op `shape`: re-derive the two bridged
1534
+ * faces (role table, else by captured normal), then return the face adjacent to
1535
+ * both whose normal blends both. One survivor → resolved; several →
1536
+ * nearest-to-edge-midpoint; none → broken.
1537
+ */
1538
+ function resolveDerivedFaceRef(ref, roles, shape) {
1539
+ let aFaces = facesForRole(shape, ref.origin, ref.betweenRoles[0], roles);
1540
+ if (aFaces.length === 0) aFaces = facesByNormal(shape, ref.hint.normalA);
1541
+ let bFaces = facesForRole(shape, ref.origin, ref.betweenRoles[1], roles);
1542
+ if (bFaces.length === 0) bFaces = facesByNormal(shape, ref.hint.normalB);
1543
+ if (aFaces.length === 0 || bFaces.length === 0) return {
1544
+ ref,
1545
+ reason: "not-found"
1546
+ };
1547
+ const blended = betweenFaces(shape, aFaces, bFaces).filter((f) => normalDot(normalAt(f), ref.hint.normalA) > BLEND_THRESHOLD && normalDot(normalAt(f), ref.hint.normalB) > BLEND_THRESHOLD);
1548
+ if (blended.length === 1) {
1549
+ const [only] = blended;
1550
+ if (only !== void 0) return {
1551
+ face: only,
1552
+ confidence: "geometric-fallback"
1553
+ };
1554
+ }
1555
+ if (blended.length > 1) {
1556
+ const best = ref.hint.edgeMidpoint && nearestFace(blended, ref.hint.edgeMidpoint);
1557
+ if (best) return {
1558
+ face: best,
1559
+ confidence: "geometric-fallback"
1560
+ };
1561
+ return {
1562
+ ref,
1563
+ reason: "ambiguous",
1564
+ candidates: blended
1565
+ };
1566
+ }
1567
+ return {
1568
+ ref,
1569
+ reason: "not-found"
1570
+ };
1571
+ }
1572
+ //#endregion
1339
1573
  //#region src/topology/surfaceFns.ts
1340
1574
  /**
1341
1575
  * Surface creation functions — generate faces from height-map grids.
@@ -3664,7 +3898,7 @@ function cutAll(base, tools, options) {
3664
3898
  }
3665
3899
  /** Compute the intersection of two shapes (boolean common). */
3666
3900
  function intersect(a, b, options) {
3667
- return intersect$2(resolve(a), resolve(b), {
3901
+ return intersect$3(resolve(a), resolve(b), {
3668
3902
  ...options,
3669
3903
  unsafe: true
3670
3904
  });
@@ -5781,7 +6015,7 @@ function evalIntersect(node, ctx) {
5781
6015
  if (!a.ok) return a;
5782
6016
  const b = resolveOperand(ctx, node.b, "Intersect.b");
5783
6017
  if (!b.ok) return b;
5784
- return intersect$2(a.value, b.value, boolOptions(node, ctx));
6018
+ return intersect$3(a.value, b.value, boolOptions(node, ctx));
5785
6019
  }
5786
6020
  function resolveAll(ctx, nodes, where) {
5787
6021
  const out = [];
@@ -6936,4 +7170,4 @@ var csg_exports = /* @__PURE__ */ __exportAll({
6936
7170
  withEvaluator: () => withEvaluator
6937
7171
  });
6938
7172
  //#endregion
6939
- export { BaseSketcher2d, BlueprintSketcher, BrepBugError, BrepErrorCode, BrepWrapperError, BrepkitAdapter, CompoundSketch, DEFAULT_CAPABILITIES, DEG2RAD, DisposalScope, EXACT_BREP_CAPABILITIES, FaceSketcher, HASH_CODE_MAX, OK, OcctWasmAdapter, RAD2DEG, Sketch, Sketcher, Sketches, addChild, addHoles, addJoint, addMate, addStep, adjacentFaces, all, andThen, applyGlue, applyMatrix, approximateCurve, as2D, as3D, asTopo, assignRoles, autoHeal, bezier, blueprintToDXF, booleanPipeline, booleans_exports as booleans, boss, box, bsplineApprox, bug, cameraFromPlane, cameraLookAt, captureHint, cast, castShape, castShape3D, chamfer, chamferDistAngle as chamferDistAngleShape, chamferWithEvolution, checkAllInterferences, checkBoolean, checkInterference, circle, circularPattern, classifyPointOnFace, clearMeshCache, clone, closedWire, collect, collectShapes, colorFaces, colorShape, complexExtrude, composeTransforms, compound, compoundSketchExtrude, compoundSketchFace, compoundSketchLoft, compoundSketchRevolve, computationError, computeStraightSkeleton, cone, construction_exports as construction, convexHull, cornerFinder, countNodes, createAssembly, createAssemblyNode, createBlueprint, createCamera, createCompound, createCompoundBlueprint, createDistanceQuery, createEdge, createEdgeRef, createFace, createHandle, createHistory, createKernelHandle, createMeshCache, createNamedPlane, createOperationRegistry, createPlane, createRef, createRegistry, createShell, createSolid, createTaskQueue, createVertex, createWire, createWorkerClient, createWorkerHandler, createWorkerPool, csg_exports as csg, currentQuality, curve2dBoundingBox, curve2dDistanceFrom, curve2dFirstPoint, curve2dIsOnCurve, curve2dLastPoint, curve2dParameter, curve2dSplitAt, curve2dTangentAt, curveAxis, curveEndPoint, curveIsClosed, curveIsPeriodic, curveLength, curvePeriod, curvePointAt, curveStartPoint, curveTangentAt, cut, cut2D, cutAll, cutAllBisect, cutBlueprints, cutWithEvolution, cylinder, cylindricalJoint, defaultScorer, dequeueTask, describe, deserializeDrawing, deserializeHistory, fromBREP as deserializeShape, downcast, draft, draw, drawCircle, drawEllipse, drawFaceOutline, drawParametricFunction, drawPointsInterpolation, drawPolysides, drawProjection, drawRectangle, drawRoundedRectangle, drawSingleCircle, drawSingleEllipse, drawText, drawingChamfer, drawingCut, drawingFillet, drawingFuse, drawingIntersect, drawingToSketchOnPlane, drill, edgeFinder, edgesOfFace, ellipse, ellipseArc, ellipsoid, enqueueTask, err, exportAssemblySTEP, exportDXF, exportGlb, exportGltf, exportIGES, exportOBJ, exportSTEP, exportSTEPConfigured, exportSTL, exportThreeMF, exportURDF, extrude, extrudeAll, face, faceAxis, faceCenter, faceFinder, faceGeomType, faceOrientation, facesOfEdge, fieldBoolean, fieldContour, fieldOffset, fieldReinit, fieldShell, fill, filledFace, fillet, filletWithEvolution, findFacesByTag, findNode, findStep, fixSelfIntersection, fixShape, flatMap, flatten, flipFaceOrientation, flipOrientation, fontMetrics, forwardKinematics, fromBREP$1 as fromBREP, fromKernelDir, fromKernelPnt, fromKernelVec, fromNullable, fuse, fuse2D, fuseAll, fuseAllBisect, fuseBlueprints, fuseWithEvolution, gearGeometry, getActiveVoxelId, getBounds, getBounds2D, getCompSolids, getCurveType, getDisposalStats, getEdges, getFaceColor, getFaceOrigins, getFaceTags, getFaces, getFont, getHashCode, getShape as getHistoryShape, getKernel, getKernelCapabilities, getKernelTier, getNurbsCurveData, getNurbsSurfaceData, getOrientation, getOrientation2D, getPerformanceStats, getShapeColor, getShapeKind, getShells, getSingleFace, getSolids, getSurfaceType, getTagMetadata, getVertices, getVoxel, getWires, gridPattern, guidedSweep, heal, healFace, healSolid, healWire, helix, hull, importDXF, importGLB, importIGES, importOBJ, importSTEP, importSTL, importSVG, importSVGPathD, importThreeMF, importURDF, init, initFromManifold, initFromOC, initVoxel, innerWires, instance, instanceCount, instanceGrid, instancedMesh, interpolateCurve, intersect, intersect2D, intersectBlueprints, intersectWithEvolution, invalidateShapeCache, inverseKinematics, ioNs_exports as io, ioError, is2D, is3D, isBatchRequest, isChamferRadius, isClosedWire, isCompSolid, isCompound, isDisposeRequest, isEdge, isEmpty, isEqualShape, isErr, isErrorResponse, isFace, isFilletRadius, isInitRequest, isInside2D, isInstanced, isLive, isManifoldShell, isNumber, isOk, isOperationRequest, isOrientedFace, isPlanarFace, isPlanarWire, isProjectionPlane, isEmpty$1 as isQueueEmpty, isSameShape, isShape1D, isShape3D, isShell, isSolid, isSuccessResponse, isValid, isValidSolid, isVertex, isWire, iterCompSolids, iterEdges, iterFaces, iterShells, iterSolids, iterTopo, iterVertices, iterWires, jointTrajectory, jointTransform, jointsFromDH, kernelCall, kernelCallRaw, kernelCallScoped, kernelError, latticeInfill, latticeInfillShape, line, linearPattern, loadFont, loft, loftAll, makeBaseBox, makeExternalGear, makeInternalGear, makePlane, makePlanetaryGear, makeProjectedEdges, manifoldShell, map, mapBoth, mapErr, match, materialize, measureArea, measureCurvatureAt, measureCurvatureAtMid, measureDistance, measureDistanceProps, measureLength, measureLinearProps, measureSurfaceProps, measureVolume, measureVolumeProps, measurement_exports as measurement, mechanismDOF, mesh, meshEdges, meshLODs, meshLODsProgressive, meshMultiLOD, minkowski, mirror, mirror2D, mirrorDrawing, mirrorJoin, modifiers_exports as modifiers, modifyStep, moduleInitError, multiSectionSweep, normalAt, offset, offsetFace, offsetMesh, offsetShape, offsetWire2D, ok, or, orElse, organiseBlueprints, orientedFace, outerWire, patterns_exports as patterns, pendingCount, pipeline, pivotPlane, planarFace, planarJoint, planarWire, planetPlacements, pocket, pointOnSurface, pointsInside, polygon, polyhedron, polysideInnerRadius, polysidesBlueprint, positionOnCurve, prewarm, primitives_exports as primitives, prismaticJoint, projectEdges, projectPointOnFace, query_exports as query, queryError, rectangularPattern, registerHandler, registerKernel, registerKernelTier, registerOperation, registerShape, registerVoxel, rejectAll, removeChild, removeHolesFromFace, repairMesh, replayFrom, replayHistory, resetDisposalStats, resetPerformanceStats, resize, resolve, resolve3D, resolveDirection, resolveEdgeRef, resolvePlane, resolveRef, reverseCurve, revoluteJoint, revolve, roof, rotate, rotate2D, rotateDrawing, roundedRectangleBlueprint, scale, scale2D, scaleDrawing, box$1 as sdfBox, capsule as sdfCapsule, cone$1 as sdfCone, cylinder$1 as sdfCylinder, fieldAxialRamp as sdfFieldAxialRamp, fieldClamp as sdfFieldClamp, fieldConst as sdfFieldConst, fieldFromSdf as sdfFieldFromSdf, fieldRadialRamp as sdfFieldRadialRamp, lattice as sdfLattice, plane as sdfPlane, roundedBox as sdfRoundedBox, sphere as sdfSphere, strutLattice as sdfStrutLattice, sweep as sdfSweep, torus as sdfTorus, section, sectionToFace, serializeHistory, setJointValue, setJointValues, setShapeOrigin, setTagMetadata, sewShells, shape, shapeToMeshInput, shapeType, sharedEdges, shell, shellMesh, shellShape, shellWithEvolution, simplify, sketchCircle, sketchEllipse, sketchExtrude, sketchFace, sketchFaceOffset, sketchHelix, sketchLoft, sketchOnFace2D, sketchOnPlane2D, sketchParametricFunction, sketchPolysides, sketchRectangle, sketchRevolve, sketchRoundedRectangle, sketchSweep, sketchText, sketchWires, sketcherStateError, slice, solid, solidFromShell, solveAssembly, sphere$1 as sphere, sphericalJoint, split, stepCount, stepsFrom, stretch2D, subFace, supportExtrude, supportsConstraintSketch, supportsProjection, surfaceFromGrid, surfaceFromImage, sweep$1 as sweep, tagFaces, tangentArc, tap, tapErr, textBlueprints, textMetrics, thicken, thread, threePointArc, toBREP, toBufferGeometryData, toGroupedBufferGeometryData, toKernelVec, toLODGeometryData, toLODGeometryLevels, toLineGeometryData, toSVGPathD, toVec2, toVec3, torus$1 as torus, tpmsLattice, transformCopy, transforms_exports as transforms, translate, translate2D, translateDrawing, translatePlane, tryCatch, tryCatchAsync, twistExtrude, typeCastError, undoLast, unsupportedError, unwrap, unwrapErr, unwrapOr, unwrapOrElse, updateNode, updateRoles, uvBounds, uvCoordinates, validSolid, validatePlanetary, validationError, variableFillet, vecAdd, vecAngle, vecCross, vecDistance, vecDot, vecEquals, vecIsZero, vecLength, vecLengthSq, vecNegate, vecNormalize, vecProjectToPlane, vecRepr, vecRotate, vecScale, vecSub, vertex, vertexFinder, vertexPosition, verticesOfEdge, voxelBoolean, voxelBooleanField, voxelBooleanFieldShapes, voxelBooleanShapes, voxelField, voxelFieldFromShape, walkAssembly, windingNumbers, wire, wireFinder, wireLoop, wiresOfFace, withKernel, withKernelDir, withKernelPnt, withKernelVec, withQuality, withScope, withScopeResult, withScopeResultAsync, withTier, zip as zipResults };
7173
+ export { BaseSketcher2d, BlueprintSketcher, BrepBugError, BrepErrorCode, BrepWrapperError, BrepkitAdapter, CompoundSketch, DEFAULT_CAPABILITIES, DEG2RAD, DisposalScope, EXACT_BREP_CAPABILITIES, FaceSketcher, HASH_CODE_MAX, OK, OcctWasmAdapter, RAD2DEG, Sketch, Sketcher, Sketches, addChild, addHoles, addJoint, addMate, addStep, adjacentFaces, all, andThen, applyGlue, applyMatrix, approximateCurve, as2D, as3D, asTopo, assignRoles, autoHeal, bezier, blueprintToDXF, booleanPipeline, booleans_exports as booleans, boss, box, bsplineApprox, bug, cameraFromPlane, cameraLookAt, captureHint, cast, castShape, castShape3D, chamfer, chamferDistAngle as chamferDistAngleShape, chamferWithEvolution, checkAllInterferences, checkBoolean, checkInterference, circle, circularPattern, classifyPointOnFace, clearMeshCache, clone, closedWire, collect, collectShapes, colorFaces, colorShape, complexExtrude, composeTransforms, compound, compoundSketchExtrude, compoundSketchFace, compoundSketchLoft, compoundSketchRevolve, computationError, computeStraightSkeleton, cone, construction_exports as construction, convexHull, cornerFinder, countNodes, createAssembly, createAssemblyNode, createBlueprint, createCamera, createCompound, createCompoundBlueprint, createDerivedFaceRef, createDistanceQuery, createEdge, createEdgeRef, createFace, createHandle, createHistory, createKernelHandle, createMeshCache, createNamedPlane, createOperationRegistry, createPlane, createRef, createRegistry, createShell, createSolid, createTaskQueue, createVertex, createVertexRef, createWire, createWorkerClient, createWorkerHandler, createWorkerPool, csg_exports as csg, currentQuality, curve2dBoundingBox, curve2dDistanceFrom, curve2dFirstPoint, curve2dIsOnCurve, curve2dLastPoint, curve2dParameter, curve2dSplitAt, curve2dTangentAt, curveAxis, curveEndPoint, curveIsClosed, curveIsPeriodic, curveLength, curvePeriod, curvePointAt, curveStartPoint, curveTangentAt, cut, cut2D, cutAll, cutAllBisect, cutBlueprints, cutWithEvolution, cylinder, cylindricalJoint, defaultScorer, dequeueTask, describe, deserializeDrawing, deserializeHistory, fromBREP as deserializeShape, downcast, draft, draw, drawCircle, drawEllipse, drawFaceOutline, drawParametricFunction, drawPointsInterpolation, drawPolysides, drawProjection, drawRectangle, drawRoundedRectangle, drawSingleCircle, drawSingleEllipse, drawText, drawingChamfer, drawingCut, drawingFillet, drawingFuse, drawingIntersect, drawingToSketchOnPlane, drill, edgeFinder, edgesOfFace, ellipse, ellipseArc, ellipsoid, enqueueTask, err, exportAssemblySTEP, exportDXF, exportGlb, exportGltf, exportIGES, exportOBJ, exportSTEP, exportSTEPConfigured, exportSTL, exportThreeMF, exportURDF, extrude, extrudeAll, face, faceAxis, faceCenter, faceFinder, faceGeomType, faceOrientation, facesOfEdge, facesOfVertex, fieldBoolean, fieldContour, fieldOffset, fieldReinit, fieldShell, fill, filledFace, fillet, filletWithEvolution, findFacesByTag, findNode, findStep, fixSelfIntersection, fixShape, flatMap, flatten, flipFaceOrientation, flipOrientation, fontMetrics, forwardKinematics, fromBREP$1 as fromBREP, fromKernelDir, fromKernelPnt, fromKernelVec, fromNullable, fuse, fuse2D, fuseAll, fuseAllBisect, fuseBlueprints, fuseWithEvolution, gearGeometry, getActiveVoxelId, getBounds, getBounds2D, getCompSolids, getCurveType, getDisposalStats, getEdges, getFaceColor, getFaceOrigins, getFaceTags, getFaces, getFont, getHashCode, getShape as getHistoryShape, getKernel, getKernelCapabilities, getKernelTier, getNurbsCurveData, getNurbsSurfaceData, getOrientation, getOrientation2D, getPerformanceStats, getShapeColor, getShapeKind, getShells, getSingleFace, getSolids, getSurfaceType, getTagMetadata, getVertices, getVoxel, getWires, gridPattern, guidedSweep, heal, healFace, healSolid, healWire, helix, hull, importDXF, importGLB, importIGES, importOBJ, importSTEP, importSTL, importSVG, importSVGPathD, importThreeMF, importURDF, init, initFromManifold, initFromOC, initVoxel, innerWires, instance, instanceCount, instanceGrid, instancedMesh, interpolateCurve, intersect, intersect2D, intersectBlueprints, intersectWithEvolution, invalidateShapeCache, inverseKinematics, ioNs_exports as io, ioError, is2D, is3D, isBatchRequest, isChamferRadius, isClosedWire, isCompSolid, isCompound, isDisposeRequest, isEdge, isEmpty, isEqualShape, isErr, isErrorResponse, isFace, isFilletRadius, isInitRequest, isInside2D, isInstanced, isLive, isManifoldShell, isNumber, isOk, isOperationRequest, isOrientedFace, isPlanarFace, isPlanarWire, isProjectionPlane, isEmpty$1 as isQueueEmpty, isSameShape, isShape1D, isShape3D, isShell, isSolid, isSuccessResponse, isValid, isValidSolid, isVertex, isWire, iterCompSolids, iterEdges, iterFaces, iterShells, iterSolids, iterTopo, iterVertices, iterWires, jointTrajectory, jointTransform, jointsFromDH, kernelCall, kernelCallRaw, kernelCallScoped, kernelError, latticeInfill, latticeInfillShape, line, linearPattern, loadFont, loft, loftAll, makeBaseBox, makeExternalGear, makeInternalGear, makePlane, makePlanetaryGear, makeProjectedEdges, manifoldShell, map, mapBoth, mapErr, match, materialize, measureArea, measureCurvatureAt, measureCurvatureAtMid, measureDistance, measureDistanceProps, measureLength, measureLinearProps, measureSurfaceProps, measureVolume, measureVolumeProps, measurement_exports as measurement, mechanismDOF, mesh, meshEdges, meshLODs, meshLODsProgressive, meshMultiLOD, minkowski, mirror, mirror2D, mirrorDrawing, mirrorJoin, modifiers_exports as modifiers, modifyStep, moduleInitError, multiSectionSweep, normalAt, offset, offsetFace, offsetMesh, offsetShape, offsetWire2D, ok, or, orElse, organiseBlueprints, orientedFace, outerWire, patterns_exports as patterns, pendingCount, pipeline, pivotPlane, planarFace, planarJoint, planarWire, planetPlacements, pocket, pointOnSurface, pointsInside, polygon, polyhedron, polysideInnerRadius, polysidesBlueprint, positionOnCurve, prewarm, primitives_exports as primitives, prismaticJoint, projectEdges, projectPointOnFace, query_exports as query, queryError, rectangularPattern, registerHandler, registerKernel, registerKernelTier, registerOperation, registerShape, registerVoxel, rejectAll, removeChild, removeHolesFromFace, repairMesh, replayFrom, replayHistory, resetDisposalStats, resetPerformanceStats, resize, resolve, resolve3D, resolveDerivedFaceRef, resolveDirection, resolveEdgeRef, resolvePlane, resolveRef, resolveVertexRef, reverseCurve, revoluteJoint, revolve, roof, rotate, rotate2D, rotateDrawing, roundedRectangleBlueprint, scale, scale2D, scaleDrawing, box$1 as sdfBox, capsule as sdfCapsule, cone$1 as sdfCone, cylinder$1 as sdfCylinder, fieldAxialRamp as sdfFieldAxialRamp, fieldClamp as sdfFieldClamp, fieldConst as sdfFieldConst, fieldFromSdf as sdfFieldFromSdf, fieldRadialRamp as sdfFieldRadialRamp, lattice as sdfLattice, plane as sdfPlane, roundedBox as sdfRoundedBox, sphere as sdfSphere, strutLattice as sdfStrutLattice, sweep as sdfSweep, torus as sdfTorus, section, sectionToFace, serializeHistory, setJointValue, setJointValues, setShapeOrigin, setTagMetadata, sewShells, shape, shapeToMeshInput, shapeType, sharedEdges, shell, shellMesh, shellShape, shellWithEvolution, simplify, sketchCircle, sketchEllipse, sketchExtrude, sketchFace, sketchFaceOffset, sketchHelix, sketchLoft, sketchOnFace2D, sketchOnPlane2D, sketchParametricFunction, sketchPolysides, sketchRectangle, sketchRevolve, sketchRoundedRectangle, sketchSweep, sketchText, sketchWires, sketcherStateError, slice, solid, solidFromShell, solveAssembly, sphere$1 as sphere, sphericalJoint, split, stepCount, stepsFrom, stretch2D, subFace, supportExtrude, supportsConstraintSketch, supportsProjection, surfaceFromGrid, surfaceFromImage, sweep$1 as sweep, tagFaces, tangentArc, tap, tapErr, textBlueprints, textMetrics, thicken, thread, threePointArc, toBREP, toBufferGeometryData, toGroupedBufferGeometryData, toKernelVec, toLODGeometryData, toLODGeometryLevels, toLineGeometryData, toSVGPathD, toVec2, toVec3, torus$1 as torus, tpmsLattice, transformCopy, transforms_exports as transforms, translate, translate2D, translateDrawing, translatePlane, tryCatch, tryCatchAsync, twistExtrude, typeCastError, undoLast, unsupportedError, unwrap, unwrapErr, unwrapOr, unwrapOrElse, updateNode, updateRoles, uvBounds, uvCoordinates, validSolid, validatePlanetary, validationError, variableFillet, vecAdd, vecAngle, vecCross, vecDistance, vecDot, vecEquals, vecIsZero, vecLength, vecLengthSq, vecNegate, vecNormalize, vecProjectToPlane, vecRepr, vecRotate, vecScale, vecSub, vertex, vertexFinder, vertexPosition, verticesOfEdge, verticesOfFace, voxelBoolean, voxelBooleanField, voxelBooleanFieldShapes, voxelBooleanShapes, voxelField, voxelFieldFromShape, walkAssembly, windingNumbers, wire, wireFinder, wireLoop, wiresOfFace, withKernel, withKernelDir, withKernelPnt, withKernelVec, withQuality, withScope, withScopeResult, withScopeResultAsync, withTier, zip as zipResults };
@@ -220,6 +220,30 @@ function getEdgeToFacesMap(parent) {
220
220
  return edgeToFaces;
221
221
  }
222
222
  /**
223
+ * Build or retrieve the cached vertex→faces adjacency map for a parent shape —
224
+ * the vertex analogue of {@link getEdgeToFacesMap}.
225
+ */
226
+ function getVertexToFacesMap(parent) {
227
+ const cache = getOrCreateCache(parent);
228
+ if (cache.vertexToFaces) return cache.vertexToFaces;
229
+ const kernel = getKernel();
230
+ const vertexToFaces = /* @__PURE__ */ new Map();
231
+ for (const f of kernel.iterShapes(parent.wrapped, "face")) for (const v of kernel.iterShapes(f, "vertex")) {
232
+ const hash = kernel.hashCode(v, HASH_CODE_MAX);
233
+ let bucket = vertexToFaces.get(hash);
234
+ if (!bucket) {
235
+ bucket = [];
236
+ vertexToFaces.set(hash, bucket);
237
+ }
238
+ if (!bucket.some((entry) => kernel.isSame(entry.vertex, v) && kernel.isSame(entry.face, f))) bucket.push({
239
+ vertex: v,
240
+ face: f
241
+ });
242
+ }
243
+ cache.vertexToFaces = vertexToFaces;
244
+ return vertexToFaces;
245
+ }
246
+ /**
223
247
  * Get all faces adjacent to a given edge within a parent shape.
224
248
  *
225
249
  * An edge typically borders exactly two faces in a solid, or one face
@@ -251,6 +275,35 @@ function facesOfEdge(parent, edge) {
251
275
  return wrapAll(results, "face");
252
276
  }
253
277
  /**
278
+ * Get all faces meeting at a vertex (≥3 for a solid corner, fewer on a
279
+ * boundary), via the cached vertex→faces map. The vertex equivalent of
280
+ * {@link facesOfEdge}, with the same hash-bucket + isSame verification.
281
+ *
282
+ * @param parent - The parent shape to search within.
283
+ * @param vertex - The vertex whose adjacent faces to find.
284
+ */
285
+ function facesOfVertex(parent, vertex) {
286
+ const kernel = getKernel();
287
+ const vertexToFaces = getVertexToFacesMap(parent);
288
+ const hash = kernel.hashCode(vertex.wrapped, HASH_CODE_MAX);
289
+ const bucket = vertexToFaces.get(hash) ?? [];
290
+ const results = [];
291
+ const seen = /* @__PURE__ */ new Map();
292
+ for (const entry of bucket) {
293
+ if (!kernel.isSame(entry.vertex, vertex.wrapped)) continue;
294
+ const fHash = kernel.hashCode(entry.face, HASH_CODE_MAX);
295
+ const fBucket = seen.get(fHash);
296
+ if (!fBucket) {
297
+ seen.set(fHash, [entry.face]);
298
+ results.push(entry.face);
299
+ } else if (!fBucket.some((r) => kernel.isSame(r, entry.face))) {
300
+ fBucket.push(entry.face);
301
+ results.push(entry.face);
302
+ }
303
+ }
304
+ return wrapAll(results, "face");
305
+ }
306
+ /**
254
307
  * Get all edges bounding a face.
255
308
  *
256
309
  * @param face - The face whose edges to enumerate.
@@ -260,6 +313,14 @@ function edgesOfFace(face) {
260
313
  return deduplicatedSubShapes(face.wrapped, "edge");
261
314
  }
262
315
  /**
316
+ * Get all vertices of a face. The vertex equivalent of {@link edgesOfFace}.
317
+ *
318
+ * @param face - The face whose vertices to enumerate.
319
+ */
320
+ function verticesOfFace(face) {
321
+ return deduplicatedSubShapes(face.wrapped, "vertex");
322
+ }
323
+ /**
263
324
  * Get all wires of a face (outer wire + inner hole wires).
264
325
  * All wires bounding a face are closed by definition.
265
326
  *
@@ -1376,4 +1437,4 @@ function fixSelfIntersection(wire) {
1376
1437
  }
1377
1438
  }
1378
1439
  //#endregion
1379
- export { edgesOfFace as A, toLineGeometryData as B, shellWithEvolution as C, getNurbsCurveData as D, fuseAllBisect as E, chamferDistAngle as F, toBufferGeometryData as I, toGroupedBufferGeometryData as L, sharedEdges as M, verticesOfEdge as N, getNurbsSurfaceData as O, wiresOfFace as P, toLODGeometryData as R, intersectWithEvolution as S, cutAllBisect as T, positionOnCurve as _, healFace as a, filletWithEvolution as b, isValid as c, draft as d, fillet as f, variableFillet as g, thicken as h, heal as i, facesOfEdge as j, adjacentFaces as k, solidFromShell as l, shell as m, fixSelfIntersection as n, healSolid as o, offset as p, fixShape as r, healWire as s, autoHeal as t, chamfer as u, chamferWithEvolution as v, checkBoolean as w, fuseWithEvolution as x, cutWithEvolution as y, toLODGeometryLevels as z };
1440
+ export { edgesOfFace as A, toLODGeometryData as B, shellWithEvolution as C, getNurbsCurveData as D, fuseAllBisect as E, verticesOfFace as F, toLineGeometryData as H, wiresOfFace as I, chamferDistAngle as L, facesOfVertex as M, sharedEdges as N, getNurbsSurfaceData as O, verticesOfEdge as P, toBufferGeometryData as R, intersectWithEvolution as S, cutAllBisect as T, toLODGeometryLevels as V, positionOnCurve as _, healFace as a, filletWithEvolution as b, isValid as c, draft as d, fillet as f, variableFillet as g, thicken as h, heal as i, facesOfEdge as j, adjacentFaces as k, solidFromShell as l, shell as m, fixSelfIntersection as n, healSolid as o, offset as p, fixShape as r, healWire as s, autoHeal as t, chamfer as u, chamferWithEvolution as v, checkBoolean as w, fuseWithEvolution as x, cutWithEvolution as y, toGroupedBufferGeometryData as z };
@@ -220,6 +220,30 @@ function getEdgeToFacesMap(parent) {
220
220
  return edgeToFaces;
221
221
  }
222
222
  /**
223
+ * Build or retrieve the cached vertex→faces adjacency map for a parent shape —
224
+ * the vertex analogue of {@link getEdgeToFacesMap}.
225
+ */
226
+ function getVertexToFacesMap(parent) {
227
+ const cache = require_topologyQueryFns.getOrCreateCache(parent);
228
+ if (cache.vertexToFaces) return cache.vertexToFaces;
229
+ const kernel = require_shapeTypes.getKernel();
230
+ const vertexToFaces = /* @__PURE__ */ new Map();
231
+ for (const f of kernel.iterShapes(parent.wrapped, "face")) for (const v of kernel.iterShapes(f, "vertex")) {
232
+ const hash = kernel.hashCode(v, require_constants.HASH_CODE_MAX);
233
+ let bucket = vertexToFaces.get(hash);
234
+ if (!bucket) {
235
+ bucket = [];
236
+ vertexToFaces.set(hash, bucket);
237
+ }
238
+ if (!bucket.some((entry) => kernel.isSame(entry.vertex, v) && kernel.isSame(entry.face, f))) bucket.push({
239
+ vertex: v,
240
+ face: f
241
+ });
242
+ }
243
+ cache.vertexToFaces = vertexToFaces;
244
+ return vertexToFaces;
245
+ }
246
+ /**
223
247
  * Get all faces adjacent to a given edge within a parent shape.
224
248
  *
225
249
  * An edge typically borders exactly two faces in a solid, or one face
@@ -251,6 +275,35 @@ function facesOfEdge(parent, edge) {
251
275
  return wrapAll(results, "face");
252
276
  }
253
277
  /**
278
+ * Get all faces meeting at a vertex (≥3 for a solid corner, fewer on a
279
+ * boundary), via the cached vertex→faces map. The vertex equivalent of
280
+ * {@link facesOfEdge}, with the same hash-bucket + isSame verification.
281
+ *
282
+ * @param parent - The parent shape to search within.
283
+ * @param vertex - The vertex whose adjacent faces to find.
284
+ */
285
+ function facesOfVertex(parent, vertex) {
286
+ const kernel = require_shapeTypes.getKernel();
287
+ const vertexToFaces = getVertexToFacesMap(parent);
288
+ const hash = kernel.hashCode(vertex.wrapped, require_constants.HASH_CODE_MAX);
289
+ const bucket = vertexToFaces.get(hash) ?? [];
290
+ const results = [];
291
+ const seen = /* @__PURE__ */ new Map();
292
+ for (const entry of bucket) {
293
+ if (!kernel.isSame(entry.vertex, vertex.wrapped)) continue;
294
+ const fHash = kernel.hashCode(entry.face, require_constants.HASH_CODE_MAX);
295
+ const fBucket = seen.get(fHash);
296
+ if (!fBucket) {
297
+ seen.set(fHash, [entry.face]);
298
+ results.push(entry.face);
299
+ } else if (!fBucket.some((r) => kernel.isSame(r, entry.face))) {
300
+ fBucket.push(entry.face);
301
+ results.push(entry.face);
302
+ }
303
+ }
304
+ return wrapAll(results, "face");
305
+ }
306
+ /**
254
307
  * Get all edges bounding a face.
255
308
  *
256
309
  * @param face - The face whose edges to enumerate.
@@ -260,6 +313,14 @@ function edgesOfFace(face) {
260
313
  return deduplicatedSubShapes(face.wrapped, "edge");
261
314
  }
262
315
  /**
316
+ * Get all vertices of a face. The vertex equivalent of {@link edgesOfFace}.
317
+ *
318
+ * @param face - The face whose vertices to enumerate.
319
+ */
320
+ function verticesOfFace(face) {
321
+ return deduplicatedSubShapes(face.wrapped, "vertex");
322
+ }
323
+ /**
263
324
  * Get all wires of a face (outer wire + inner hole wires).
264
325
  * All wires bounding a face are closed by definition.
265
326
  *
@@ -1442,6 +1503,12 @@ Object.defineProperty(exports, "facesOfEdge", {
1442
1503
  return facesOfEdge;
1443
1504
  }
1444
1505
  });
1506
+ Object.defineProperty(exports, "facesOfVertex", {
1507
+ enumerable: true,
1508
+ get: function() {
1509
+ return facesOfVertex;
1510
+ }
1511
+ });
1445
1512
  Object.defineProperty(exports, "fillet", {
1446
1513
  enumerable: true,
1447
1514
  get: function() {
@@ -1610,6 +1677,12 @@ Object.defineProperty(exports, "verticesOfEdge", {
1610
1677
  return verticesOfEdge;
1611
1678
  }
1612
1679
  });
1680
+ Object.defineProperty(exports, "verticesOfFace", {
1681
+ enumerable: true,
1682
+ get: function() {
1683
+ return verticesOfFace;
1684
+ }
1685
+ });
1613
1686
  Object.defineProperty(exports, "wiresOfFace", {
1614
1687
  enumerable: true,
1615
1688
  get: function() {
package/dist/index.d.ts CHANGED
@@ -87,7 +87,7 @@ export { tagFaces, findFacesByTag, getFaceTags, setTagMetadata, getTagMetadata,
87
87
  export { colorFaces, colorShape, getFaceColor, getShapeColor, } from './topology/metadata/colorFns.js';
88
88
  export type { Color, ColorInput } from './topology/metadata/colorFns.js';
89
89
  export { chamferDistAngle as chamferDistAngleShape } from './topology/chamferAngleFns.js';
90
- export { facesOfEdge, edgesOfFace, wiresOfFace, verticesOfEdge, adjacentFaces, sharedEdges, } from './topology/adjacencyFns.js';
90
+ export { facesOfEdge, edgesOfFace, wiresOfFace, verticesOfEdge, verticesOfFace, facesOfVertex, adjacentFaces, sharedEdges, } from './topology/adjacencyFns.js';
91
91
  export { getCurveType, curveStartPoint, curveEndPoint, curvePointAt, curveTangentAt, curveAxis, curveLength, curveIsClosed, curveIsPeriodic, curvePeriod, getOrientation, flipOrientation, offsetWire2D, interpolateCurve, approximateCurve, type InterpolateCurveOptions, type ApproximateCurveOptions, } from './topology/curveFns.js';
92
92
  export { getNurbsCurveData, getNurbsSurfaceData } from './topology/nurbsFns.js';
93
93
  export type { NurbsCurveData, NurbsSurfaceData } from './kernel/types.js';
@@ -102,8 +102,8 @@ export { checkBoolean } from './topology/booleanDiagnosticFns.js';
102
102
  export type { CheckBooleanResult, BooleanIssue, BooleanOpType, BooleanDiagnostics, } from './kernel/types.js';
103
103
  export { fuseWithEvolution, cutWithEvolution, intersectWithEvolution, filletWithEvolution, chamferWithEvolution, shellWithEvolution, type EvolutionResult, } from './topology/evolutionFns.js';
104
104
  export type { ShapeEvolution } from './kernel/types.js';
105
- export { captureHint, assignRoles, createRef, updateRoles, resolveRef, defaultScorer, createEdgeRef, resolveEdgeRef, } from './topology/shapeRef/index.js';
106
- export type { GeometricHint, ShapeRef, RoleTable, ResolvedRef, BrokenRef, FaceScorer, EdgeHint, EdgeRef, ResolvedEdgeRef, BrokenEdgeRef, } from './topology/shapeRef/index.js';
105
+ export { captureHint, assignRoles, createRef, updateRoles, resolveRef, defaultScorer, createEdgeRef, resolveEdgeRef, createVertexRef, resolveVertexRef, createDerivedFaceRef, resolveDerivedFaceRef, } from './topology/shapeRef/index.js';
106
+ export type { GeometricHint, ShapeRef, RoleTable, ResolvedRef, BrokenRef, FaceScorer, EdgeHint, EdgeRef, ResolvedEdgeRef, BrokenEdgeRef, VertexHint, VertexRef, ResolvedVertexRef, BrokenVertexRef, DerivedFaceHint, DerivedFaceRef, ResolvedDerivedFaceRef, BrokenDerivedFaceRef, } from './topology/shapeRef/index.js';
107
107
  export { surfaceFromGrid, surfaceFromImage, type SurfaceFromGridOptions, type SurfaceFromImageOptions, } from './topology/surfaceFns.js';
108
108
  export { hull, type HullOptions } from './topology/hullFns.js';
109
109
  export { convexHull } from './operations/convexHullFns.js';
@@ -10,6 +10,15 @@ import { AnyShape, ClosedWire, Dimension, Edge, Face, Vertex } from '../core/sha
10
10
  * @returns Array of unique faces containing the given edge.
11
11
  */
12
12
  export declare function facesOfEdge<D extends Dimension>(parent: AnyShape<D>, edge: Edge<D>): Face<D>[];
13
+ /**
14
+ * Get all faces meeting at a vertex (≥3 for a solid corner, fewer on a
15
+ * boundary), via the cached vertex→faces map. The vertex equivalent of
16
+ * {@link facesOfEdge}, with the same hash-bucket + isSame verification.
17
+ *
18
+ * @param parent - The parent shape to search within.
19
+ * @param vertex - The vertex whose adjacent faces to find.
20
+ */
21
+ export declare function facesOfVertex<D extends Dimension>(parent: AnyShape<D>, vertex: Vertex<D>): Face<D>[];
13
22
  /**
14
23
  * Get all edges bounding a face.
15
24
  *
@@ -17,6 +26,12 @@ export declare function facesOfEdge<D extends Dimension>(parent: AnyShape<D>, ed
17
26
  * @returns Array of unique edges forming the face boundary.
18
27
  */
19
28
  export declare function edgesOfFace<D extends Dimension>(face: Face<D>): Edge<D>[];
29
+ /**
30
+ * Get all vertices of a face. The vertex equivalent of {@link edgesOfFace}.
31
+ *
32
+ * @param face - The face whose vertices to enumerate.
33
+ */
34
+ export declare function verticesOfFace<D extends Dimension>(face: Face<D>): Vertex<D>[];
20
35
  /**
21
36
  * Get all wires of a face (outer wire + inner hole wires).
22
37
  * All wires bounding a face are closed by definition.
@@ -0,0 +1,16 @@
1
+ import { Edge, Shape3D } from '../../core/shapeTypes.js';
2
+ import { DerivedFaceRef, ResolvedDerivedFaceRef, BrokenDerivedFaceRef, RoleTable } from './shapeRefTypes.js';
3
+ /**
4
+ * Capture a reference to the face an `op` (fillet/chamfer) will generate across
5
+ * `edge`: the roles of the edge's two faces, their outward normals, and the edge
6
+ * midpoint. Call this on the PRE-op shape. Returns undefined when the edge
7
+ * doesn't bound two named faces.
8
+ */
9
+ export declare function createDerivedFaceRef(origin: string, op: 'fillet' | 'chamfer', edge: Edge, preShape: Shape3D, roles: RoleTable): DerivedFaceRef | undefined;
10
+ /**
11
+ * Resolve a DerivedFaceRef in the post-op `shape`: re-derive the two bridged
12
+ * faces (role table, else by captured normal), then return the face adjacent to
13
+ * both whose normal blends both. One survivor → resolved; several →
14
+ * nearest-to-edge-midpoint; none → broken.
15
+ */
16
+ export declare function resolveDerivedFaceRef(ref: DerivedFaceRef, roles: RoleTable, shape: Shape3D): ResolvedDerivedFaceRef | BrokenDerivedFaceRef;
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * ShapeRef — stable, serializable face references for parametric replay.
3
3
  */
4
- export type { GeometricHint, ShapeRef, RoleTable, ResolvedRef, BrokenRef, EdgeHint, EdgeRef, ResolvedEdgeRef, BrokenEdgeRef, } from './shapeRefTypes.js';
4
+ export type { GeometricHint, ShapeRef, RoleTable, ResolvedRef, BrokenRef, EdgeHint, EdgeRef, ResolvedEdgeRef, BrokenEdgeRef, VertexHint, VertexRef, ResolvedVertexRef, BrokenVertexRef, DerivedFaceHint, DerivedFaceRef, ResolvedDerivedFaceRef, BrokenDerivedFaceRef, } from './shapeRefTypes.js';
5
5
  export { type FaceScorer, defaultScorer } from './scoring.js';
6
6
  export { captureHint, assignRoles, createRef, updateRoles, resolveRef } from './shapeRefFns.js';
7
7
  export { createEdgeRef, resolveEdgeRef } from './edgeRefFns.js';
8
+ export { createVertexRef, resolveVertexRef } from './vertexRefFns.js';
9
+ export { createDerivedFaceRef, resolveDerivedFaceRef } from './derivedFaceRefFns.js';
@@ -0,0 +1,11 @@
1
+ import { Face, Shape3D, Vertex } from '../../core/shapeTypes.js';
2
+ import { Vec3 } from '../../core/types.js';
3
+ import { RoleTable } from './shapeRefTypes.js';
4
+ /** Euclidean distance between two points. */
5
+ export declare function distance(a: Vec3, b: Vec3): number;
6
+ /** Mean of a set of vertices' positions (e.g. an edge's endpoints). */
7
+ export declare function vertexCentroid(verts: readonly Vertex[]): Vec3 | undefined;
8
+ /** The role whose tracked hashes include this face (reverse lookup). */
9
+ export declare function roleOfFace(face: Face, origin: string, roles: RoleTable): string | undefined;
10
+ /** Current faces a role resolves to — its tracked successors present in `shape`. */
11
+ export declare function facesForRole(shape: Shape3D, origin: string, role: string, roles: RoleTable): Face[];
@@ -1,6 +1,6 @@
1
1
  import { Vec3 } from '../../core/types.js';
2
2
  import { SurfaceType } from '../faceFns.js';
3
- import { Face, Edge } from '../../core/shapeTypes.js';
3
+ import { Face, Edge, Vertex } from '../../core/shapeTypes.js';
4
4
  /** Geometric snapshot of a face, used for fallback matching when hashes change. */
5
5
  export interface GeometricHint {
6
6
  readonly entityType: 'face';
@@ -76,3 +76,73 @@ export interface BrokenEdgeRef {
76
76
  readonly reason: 'ambiguous' | 'not-found';
77
77
  readonly candidates?: readonly Edge[];
78
78
  }
79
+ /** Geometric snapshot of a vertex — a tiebreaker when several candidates survive. */
80
+ export interface VertexHint {
81
+ readonly entityType: 'vertex';
82
+ readonly position?: Vec3 | undefined;
83
+ }
84
+ /**
85
+ * A stable reference to a vertex, identified by the roles of the faces meeting
86
+ * at it. A solid corner is where **≥3** faces meet at a point; two faces meet
87
+ * along an *edge* (two endpoints → ambiguous), so a vertex needs ≥3 face-roles.
88
+ * Resolves by finding the vertex common to those roles' current faces.
89
+ */
90
+ export interface VertexRef {
91
+ readonly origin: string;
92
+ /** Roles of the ≥3 faces meeting at this vertex (sorted). */
93
+ readonly faceRoles: readonly string[];
94
+ readonly hint: VertexHint;
95
+ }
96
+ /** A successfully resolved vertex reference. */
97
+ export interface ResolvedVertexRef {
98
+ readonly vertex: Vertex;
99
+ readonly confidence: 'exact' | 'geometric-fallback';
100
+ }
101
+ /** A vertex reference that could not be resolved. */
102
+ export interface BrokenVertexRef {
103
+ readonly ref: VertexRef;
104
+ readonly reason: 'ambiguous' | 'not-found';
105
+ readonly candidates?: readonly Vertex[];
106
+ }
107
+ /**
108
+ * Snapshot for re-deriving a generated face. fillet/chamfer evolution is empty
109
+ * on the OCCT kernels, so the role table can't track the bridged faces — they
110
+ * are re-found by their captured outward normals; the edge midpoint breaks ties.
111
+ */
112
+ export interface DerivedFaceHint {
113
+ readonly entityType: 'derived-face';
114
+ readonly normalA: Vec3;
115
+ readonly normalB: Vec3;
116
+ readonly edgeMidpoint?: Vec3 | undefined;
117
+ }
118
+ /**
119
+ * A reference to a *generated* face — a fillet round or chamfer bevel — named by
120
+ * the two faces it bridges. The generated face has no stable hash (it didn't
121
+ * exist at capture time, and fillet evolution is empty), so it's resolved as the
122
+ * face adjacent to both bridged faces whose normal blends both — the orthogonal
123
+ * flanking faces are rejected. Lineage-by-neighbors for geometry created by the
124
+ * very edit being referenced across.
125
+ */
126
+ export interface DerivedFaceRef {
127
+ readonly origin: string;
128
+ /**
129
+ * Which op generated the face — descriptive metadata for consumers. Resolution
130
+ * is op-agnostic (the normal-blend isolates both a fillet round and a chamfer
131
+ * bevel), so the resolver doesn't consult it.
132
+ */
133
+ readonly op: 'fillet' | 'chamfer';
134
+ /** Roles of the two faces the generated face bridges. */
135
+ readonly betweenRoles: readonly [string, string];
136
+ readonly hint: DerivedFaceHint;
137
+ }
138
+ /** A successfully resolved derived-face reference (always geometric). */
139
+ export interface ResolvedDerivedFaceRef {
140
+ readonly face: Face;
141
+ readonly confidence: 'geometric-fallback';
142
+ }
143
+ /** A derived-face reference that could not be resolved. */
144
+ export interface BrokenDerivedFaceRef {
145
+ readonly ref: DerivedFaceRef;
146
+ readonly reason: 'ambiguous' | 'not-found';
147
+ readonly candidates?: readonly Face[];
148
+ }
@@ -0,0 +1,14 @@
1
+ import { Shape3D, Vertex } from '../../core/shapeTypes.js';
2
+ import { VertexRef, ResolvedVertexRef, BrokenVertexRef, RoleTable } from './shapeRefTypes.js';
3
+ /**
4
+ * Capture a lineage-based reference to `vertex`: the roles of the ≥3 faces
5
+ * meeting at it, plus a position hint. Returns undefined when fewer than three
6
+ * named faces meet there (a 2-face "vertex" is ambiguous — an edge has two).
7
+ */
8
+ export declare function createVertexRef(origin: string, vertex: Vertex, shape: Shape3D, roles: RoleTable): VertexRef | undefined;
9
+ /**
10
+ * Resolve a VertexRef in `shape`: gather the current faces of each role, then
11
+ * return the vertex common to all of them. One common vertex → exact; several →
12
+ * disambiguate by hint position; none, or a missing role → broken.
13
+ */
14
+ export declare function resolveVertexRef(ref: VertexRef, roles: RoleTable, shape: Shape3D): ResolvedVertexRef | BrokenVertexRef;
@@ -20,6 +20,11 @@ export interface TopoCacheEntry {
20
20
  edge: KernelShape;
21
21
  face: KernelShape;
22
22
  }>>;
23
+ /** Vertex hash → vertex-face pairs — the vertex analogue of {@link edgeToFaces}. */
24
+ vertexToFaces?: Map<number, Array<{
25
+ vertex: KernelShape;
26
+ face: KernelShape;
27
+ }>>;
23
28
  }
24
29
  /** @internal Get or create a cache entry for a shape. Used by originTrackingFns. */
25
30
  export declare function getOrCreateCache(shape: AnyShape<Dimension>): TopoCacheEntry;
package/dist/topology.cjs CHANGED
@@ -5,7 +5,7 @@ const require_shapeFns = require("./shapeFns-ybo0INGL.cjs");
5
5
  const require_curveFns = require("./curveFns-DgUJpH4z.cjs");
6
6
  const require_meshFns = require("./meshFns-1hQSn1p2.cjs");
7
7
  const require_solidBuilders = require("./solidBuilders-DiUv_mD0.cjs");
8
- const require_healingFns = require("./healingFns-C4UE1ZyM.cjs");
8
+ const require_healingFns = require("./healingFns-x1sHV-HO.cjs");
9
9
  const require_primitiveFns = require("./primitiveFns-DLIWtQWA.cjs");
10
10
  exports.addHoles = require_primitiveFns.addHoles;
11
11
  exports.adjacentFaces = require_healingFns.adjacentFaces;
package/dist/topology.js CHANGED
@@ -4,6 +4,6 @@ import { a as isSameShape, i as isEqualShape, n as getHashCode } from "./shapeFn
4
4
  import { a as curveIsPeriodic, c as curvePointAt, d as flipOrientation, f as getCurveType, h as offsetWire2D, i as curveIsClosed, l as curveStartPoint, m as interpolateCurve, n as curveAxis, o as curveLength, p as getOrientation, r as curveEndPoint, s as curvePeriod, t as approximateCurve, u as curveTangentAt } from "./curveFns-CcSn4-Rf.js";
5
5
  import { d as createMeshCache, n as exportSTEP, r as exportSTL, t as exportIGES, u as clearMeshCache } from "./meshFns-DbmidUzH.js";
6
6
  import { h as fuseAll, p as cutAll } from "./solidBuilders-C32wXQWG.js";
7
- import { A as edgesOfFace, B as toLineGeometryData, C as shellWithEvolution, D as getNurbsCurveData, E as fuseAllBisect, F as chamferDistAngle, I as toBufferGeometryData, L as toGroupedBufferGeometryData, M as sharedEdges, N as verticesOfEdge, O as getNurbsSurfaceData, P as wiresOfFace, S as intersectWithEvolution, T as cutAllBisect, _ as positionOnCurve, a as healFace, b as filletWithEvolution, g as variableFillet, j as facesOfEdge, k as adjacentFaces, l as solidFromShell, n as fixSelfIntersection, o as healSolid, r as fixShape, s as healWire, t as autoHeal, v as chamferWithEvolution, w as checkBoolean, x as fuseWithEvolution, y as cutWithEvolution } from "./healingFns-CPm_VFck.js";
7
+ import { A as edgesOfFace, C as shellWithEvolution, D as getNurbsCurveData, E as fuseAllBisect, H as toLineGeometryData, I as wiresOfFace, L as chamferDistAngle, N as sharedEdges, O as getNurbsSurfaceData, P as verticesOfEdge, R as toBufferGeometryData, S as intersectWithEvolution, T as cutAllBisect, _ as positionOnCurve, a as healFace, b as filletWithEvolution, g as variableFillet, j as facesOfEdge, k as adjacentFaces, l as solidFromShell, n as fixSelfIntersection, o as healSolid, r as fixShape, s as healWire, t as autoHeal, v as chamferWithEvolution, w as checkBoolean, x as fuseWithEvolution, y as cutWithEvolution, z as toGroupedBufferGeometryData } from "./healingFns-D00TPE9p.js";
8
8
  import { C as threePointArc, D as wireLoop, E as wire, S as tangentArc, T as vertex, _ as polygon, a as circle, b as sphere, c as cylinder, d as ellipsoid, f as face, g as offsetFace, h as line, i as bsplineApprox, l as ellipse, m as helix, n as bezier, o as compound, p as filledFace, r as box, s as cone, t as addHoles, u as ellipseArc, v as sewShells, w as torus, x as subFace, y as solid } from "./primitiveFns-CBrOyk5S.js";
9
9
  export { addHoles, adjacentFaces, approximateCurve, asTopo, autoHeal, bezier, box, bsplineApprox, cast, chamferDistAngle as chamferDistAngleShape, chamferWithEvolution, checkBoolean, circle, classifyPointOnFace, clearMeshCache, compound, cone, createMeshCache, curveAxis, curveEndPoint, curveIsClosed, curveIsPeriodic, curveLength, curvePeriod, curvePointAt, curveStartPoint, curveTangentAt, cutAll, cutAllBisect, cutWithEvolution, cylinder, fromBREP as deserializeShape, downcast, edgesOfFace, ellipse, ellipseArc, ellipsoid, exportIGES, exportSTEP, exportSTL, face, faceAxis, faceCenter, faceGeomType, faceOrientation, facesOfEdge, filledFace, filletWithEvolution, fixSelfIntersection, fixShape, flipFaceOrientation, flipOrientation, fuseAll, fuseAllBisect, fuseWithEvolution, getBounds, getCurveType, getEdges, getFaces, getHashCode, getNurbsCurveData, getNurbsSurfaceData, getOrientation, getSurfaceType, getVertices, getWires, healFace, healSolid, healWire, helix, innerWires, interpolateCurve, intersectWithEvolution, invalidateShapeCache, isCompSolid, isEqualShape, isSameShape, iterEdges, iterFaces, iterTopo, iterVertices, iterWires, line, normalAt, offsetFace, offsetWire2D, outerWire, pointOnSurface, polygon, positionOnCurve, projectPointOnFace, sewShells, shapeType, sharedEdges, shellWithEvolution, solid, solidFromShell, sphere, subFace, tangentArc, threePointArc, toBufferGeometryData, toGroupedBufferGeometryData, toLineGeometryData, torus, uvBounds, uvCoordinates, variableFillet, vertex, vertexPosition, verticesOfEdge, wire, wireLoop, wiresOfFace };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brepjs",
3
- "version": "18.111.0",
3
+ "version": "18.113.0",
4
4
  "description": "Web CAD library with pluggable geometry kernel",
5
5
  "keywords": [
6
6
  "cad",