brepjs 13.4.0 → 14.1.2
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/2d.cjs +15 -14
- package/dist/2d.js +6 -5
- package/dist/arrayAccess-CmulMesb.cjs +40 -0
- package/dist/arrayAccess-xxcB3YNq.js +23 -0
- package/dist/{blueprint-CB_85Lz_.js → blueprint-B3A5x7P9.js} +9 -9
- package/dist/{blueprint-CDnBM-tA.cjs → blueprint-D0XChcek.cjs} +13 -13
- package/dist/{blueprintFns-DVDommWB.js → blueprintFns-BwAMXY3t.js} +4 -125
- package/dist/{blueprintFns-D4YucGaQ.cjs → blueprintFns-COrEYX29.cjs} +3 -142
- package/dist/{boolean2D-lqfKJKUY.cjs → boolean2D-BPsyKImE.cjs} +19 -18
- package/dist/{boolean2D-Mzp-0g7o.js → boolean2D-D_Te-6N6.js} +12 -11
- package/dist/{booleanFns-Bw8sAMgI.cjs → booleanFns-B6M6Lm0V.cjs} +24 -22
- package/dist/{booleanFns-B46fgObh.js → booleanFns-CgsaJFBf.js} +8 -6
- package/dist/brepjs.cjs +301 -90
- package/dist/brepjs.js +189 -26
- package/dist/constants-B9u763C3.js +9 -0
- package/dist/constants-unWN8k4c.cjs +26 -0
- package/dist/core/errors.d.ts +5 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/kernelCall.d.ts.map +1 -1
- package/dist/core/kernelErrorTranslation.d.ts +2 -0
- package/dist/core/kernelErrorTranslation.d.ts.map +1 -1
- package/dist/core.cjs +8 -7
- package/dist/core.js +5 -4
- package/dist/{cornerFinder-aBLykolI.js → cornerFinder-AEFnAxt4.js} +3 -3
- package/dist/{cornerFinder-BszIcLqj.cjs → cornerFinder-DTt_SvtC.cjs} +4 -4
- package/dist/{curveFns-DY4dFcP-.js → curveFns-CcInoOEA.js} +2 -2
- package/dist/{curveFns-CZszKLQB.cjs → curveFns-DCEcwcpd.cjs} +2 -2
- package/dist/{drawFns-BHNDF8hb.cjs → drawFns-BOwBIzPa.cjs} +34 -17
- package/dist/{drawFns-l5CY2s-l.js → drawFns-n9qif7QN.js} +16 -14
- package/dist/{errors-BlC5ZWv4.cjs → errors-9zQcQK1H.cjs} +28 -0
- package/dist/{errors-BVOlxlIA.js → errors-C-cgQA3w.js} +23 -1
- package/dist/{extrudeFns-b0uLn4E4.js → extrudeFns-DrDr9-nU.js} +3 -3
- package/dist/{extrudeFns-GpCB_Uzs.cjs → extrudeFns-Rcut7h8S.cjs} +3 -3
- package/dist/{faceFns-Cat-4X74.js → faceFns-TSH54pPQ.js} +93 -3
- package/dist/{faceFns-BywUjlJ7.cjs → faceFns-cE2WxY6I.cjs} +110 -2
- package/dist/{helpers-1iCCEElA.cjs → helpers-DZje6XWE.cjs} +18 -17
- package/dist/{helpers-DgX1UucG.js → helpers-XrXlKm8D.js} +8 -7
- package/dist/{historyFns-BFwp8NLX.js → historyFns-2hCWrX_X.js} +10 -10
- package/dist/{historyFns-DqxDtXIZ.cjs → historyFns-BiQ9dmzp.cjs} +10 -10
- package/dist/{importFns-ChXEJAvu.cjs → importFns-DGE5nCSW.cjs} +4 -4
- package/dist/{importFns-Cb8fcldB.js → importFns-m0xyj0Zt.js} +4 -4
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/io.cjs +2 -2
- package/dist/io.js +2 -2
- package/dist/kernel/brepkit/brepkitAdapter.d.ts +149 -242
- package/dist/kernel/brepkit/brepkitAdapter.d.ts.map +1 -1
- package/dist/kernel/brepkit/evolutionOps.d.ts +1 -0
- package/dist/kernel/brepkit/evolutionOps.d.ts.map +1 -1
- package/dist/kernel/index.d.ts +1 -1
- package/dist/kernel/index.d.ts.map +1 -1
- package/dist/{measureFns-D3rAp1X1.js → measureFns-DHByqdmn.js} +9 -16
- package/dist/{measureFns-Bx-kl7_g.cjs → measureFns-D_QKZ5yg.cjs} +9 -16
- package/dist/measurement/measureFns.d.ts.map +1 -1
- package/dist/measurement.cjs +1 -1
- package/dist/measurement.js +1 -1
- package/dist/{meshFns-D3KAZ_ma.cjs → meshFns-CVe3Kc77.cjs} +4 -4
- package/dist/{meshFns-BPi0bhm9.js → meshFns-DL4Djz3w.js} +3 -3
- package/dist/ns/booleans.d.ts +10 -0
- package/dist/ns/booleans.d.ts.map +1 -0
- package/dist/ns/construction.d.ts +10 -0
- package/dist/ns/construction.d.ts.map +1 -0
- package/dist/ns/ioNs.d.ts +18 -0
- package/dist/ns/ioNs.d.ts.map +1 -0
- package/dist/ns/measurement.d.ts +6 -0
- package/dist/ns/measurement.d.ts.map +1 -0
- package/dist/ns/modifiers.d.ts +6 -0
- package/dist/ns/modifiers.d.ts.map +1 -0
- package/dist/ns/patterns.d.ts +5 -0
- package/dist/ns/patterns.d.ts.map +1 -0
- package/dist/ns/primitives.d.ts +7 -0
- package/dist/ns/primitives.d.ts.map +1 -0
- package/dist/ns/query.d.ts +6 -0
- package/dist/ns/query.d.ts.map +1 -0
- package/dist/ns/transforms.d.ts +5 -0
- package/dist/ns/transforms.d.ts.map +1 -0
- package/dist/operations.cjs +2 -2
- package/dist/operations.js +2 -2
- package/dist/{planeOps-BqLav0Ir.cjs → planeOps-6Wu7dMDN.cjs} +4 -3
- package/dist/{planeOps-D88tfyJs.js → planeOps-gTOEarV2.js} +3 -2
- package/dist/{primitiveFns-BGh9A9jR.cjs → primitiveFns-CRPGjIFg.cjs} +69 -69
- package/dist/{primitiveFns-CnZkW6Bi.js → primitiveFns-CeKiYSSW.js} +7 -7
- package/dist/query.cjs +2 -2
- package/dist/query.js +2 -2
- package/dist/result.cjs +1 -1
- package/dist/result.js +1 -1
- package/dist/{arrayAccess-B5LgmXBo.js → shapeFns-DCi9O27X.js} +8 -30
- package/dist/{arrayAccess-t2dlxGSK.cjs → shapeFns-aEeSHNqX.cjs} +24 -64
- package/dist/shapeRef.cjs +8 -0
- package/dist/shapeRef.d.ts +5 -0
- package/dist/shapeRef.d.ts.map +1 -0
- package/dist/shapeRef.js +2 -0
- package/dist/shapeRefFns-B1TODUMl.js +194 -0
- package/dist/shapeRefFns-CVdS6jWS.cjs +229 -0
- package/dist/{shapeTypes-Di6GlhPk.js → shapeTypes-BO1aiDhi.js} +2642 -2546
- package/dist/{shapeTypes-8eK48l-X.cjs → shapeTypes-BqWQlrYE.cjs} +2642 -2546
- package/dist/sketching.cjs +2 -2
- package/dist/sketching.js +2 -2
- package/dist/{solidBuilders-D9KYP9sL.cjs → solidBuilders-0iVdiZUw.cjs} +3 -3
- package/dist/{solidBuilders-ctO_wFrm.js → solidBuilders-jk7HfWs8.js} +3 -3
- package/dist/{surfaceBuilders-CZzipftq.cjs → surfaceBuilders-C_8rs79F.cjs} +3 -3
- package/dist/{surfaceBuilders-BaqeZa0x.js → surfaceBuilders-DE5e6bp8.js} +3 -3
- package/dist/topology/api.d.ts +3 -3
- package/dist/topology/api.d.ts.map +1 -1
- package/dist/topology/shapeFns.d.ts +4 -3
- package/dist/topology/shapeFns.d.ts.map +1 -1
- package/dist/topology/shapeRef/index.d.ts +7 -0
- package/dist/topology/shapeRef/index.d.ts.map +1 -0
- package/dist/topology/shapeRef/scoring.d.ts +16 -0
- package/dist/topology/shapeRef/scoring.d.ts.map +1 -0
- package/dist/topology/shapeRef/shapeRefFns.d.ts +47 -0
- package/dist/topology/shapeRef/shapeRefFns.d.ts.map +1 -0
- package/dist/topology/shapeRef/shapeRefTypes.d.ts +40 -0
- package/dist/topology/shapeRef/shapeRefTypes.d.ts.map +1 -0
- package/dist/topology.cjs +20 -20
- package/dist/topology.js +6 -6
- package/dist/{vecOps-DKGelwGL.cjs → vecOps-BXvBYIor.cjs} +0 -26
- package/dist/{vecOps-DFfUfsmc.js → vecOps-D9etjPgV.js} +1 -9
- package/dist/vectors.cjs +5 -4
- package/dist/vectors.js +3 -2
- package/dist/worker.cjs +1 -1
- package/dist/worker.js +1 -1
- package/package.json +14 -4
- /package/dist/{workerHandler-nLkvSOKX.cjs → workerHandler-C-7OUJsa.cjs} +0 -0
- /package/dist/{workerHandler-BrOTzYRI.js → workerHandler-o2xzAfFk.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const require_shapeTypes = require("./shapeTypes-
|
|
2
|
-
const require_errors = require("./errors-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
1
|
+
const require_shapeTypes = require("./shapeTypes-BqWQlrYE.cjs");
|
|
2
|
+
const require_errors = require("./errors-9zQcQK1H.cjs");
|
|
3
|
+
const require_faceFns = require("./faceFns-cE2WxY6I.cjs");
|
|
4
|
+
const require_constants = require("./constants-unWN8k4c.cjs");
|
|
5
5
|
//#region src/topology/topologyQueryFns.ts
|
|
6
6
|
/**
|
|
7
7
|
* Topology query functions — extract sub-shapes, compute bounds, and
|
|
@@ -145,7 +145,7 @@ function vertexPosition(vertex) {
|
|
|
145
145
|
function setShapeOrigin(shape, origin) {
|
|
146
146
|
const cache = getOrCreateCache(shape);
|
|
147
147
|
const map = /* @__PURE__ */ new Map();
|
|
148
|
-
for (const f of getFaces(shape)) map.set(require_shapeTypes.getKernel().hashCode(f.wrapped,
|
|
148
|
+
for (const f of getFaces(shape)) map.set(require_shapeTypes.getKernel().hashCode(f.wrapped, require_constants.HASH_CODE_MAX), origin);
|
|
149
149
|
cache.faceOrigins = map;
|
|
150
150
|
}
|
|
151
151
|
/**
|
|
@@ -222,7 +222,7 @@ function propagateOriginsByHash(inputs, result) {
|
|
|
222
222
|
const resultMap = /* @__PURE__ */ new Map();
|
|
223
223
|
const resultFaces = getFaces(result);
|
|
224
224
|
for (const f of resultFaces) {
|
|
225
|
-
const hash = kernel.hashCode(f.wrapped,
|
|
225
|
+
const hash = kernel.hashCode(f.wrapped, require_constants.HASH_CODE_MAX);
|
|
226
226
|
const origin = lookup.get(hash);
|
|
227
227
|
if (origin !== void 0) resultMap.set(hash, origin);
|
|
228
228
|
}
|
|
@@ -233,7 +233,7 @@ function propagateOriginsByHash(inputs, result) {
|
|
|
233
233
|
const origins = getFaceOrigins(input);
|
|
234
234
|
if (!origins) continue;
|
|
235
235
|
for (const f of getFaces(input)) {
|
|
236
|
-
const hash = kernel.hashCode(f.wrapped,
|
|
236
|
+
const hash = kernel.hashCode(f.wrapped, require_constants.HASH_CODE_MAX);
|
|
237
237
|
const origin = origins.get(hash);
|
|
238
238
|
if (origin === void 0) continue;
|
|
239
239
|
try {
|
|
@@ -249,7 +249,7 @@ function propagateOriginsByHash(inputs, result) {
|
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
251
|
if (inputSigs.length > 0) for (const f of resultFaces) {
|
|
252
|
-
const hash = kernel.hashCode(f.wrapped,
|
|
252
|
+
const hash = kernel.hashCode(f.wrapped, require_constants.HASH_CODE_MAX);
|
|
253
253
|
try {
|
|
254
254
|
const outBounds = kernel.uvBounds(f.wrapped);
|
|
255
255
|
const bestOrigin = findBestOriginMatch(kernel.surfaceNormal(f.wrapped, .5 * (outBounds.uMin + outBounds.uMax), .5 * (outBounds.vMin + outBounds.vMax)), kernel.surfaceCenterOfMass(f.wrapped), inputSigs);
|
|
@@ -299,7 +299,7 @@ function tagFaces(shape, selector, tag) {
|
|
|
299
299
|
const faces = Array.isArray(selector) ? selector : getFaces(shape).filter(selector);
|
|
300
300
|
const tagMap = getTagMap(shape);
|
|
301
301
|
const existing = tagMap.get(tag) ?? /* @__PURE__ */ new Set();
|
|
302
|
-
for (const face of faces) existing.add(require_shapeTypes.getKernel().hashCode(face.wrapped,
|
|
302
|
+
for (const face of faces) existing.add(require_shapeTypes.getKernel().hashCode(face.wrapped, require_constants.HASH_CODE_MAX));
|
|
303
303
|
tagMap.set(tag, existing);
|
|
304
304
|
return shape;
|
|
305
305
|
}
|
|
@@ -316,7 +316,7 @@ function findFacesByTag(shape, tag) {
|
|
|
316
316
|
if (!hashes || hashes.size === 0) return [];
|
|
317
317
|
const result = [];
|
|
318
318
|
for (const face of getFaces(shape)) {
|
|
319
|
-
const hash = require_shapeTypes.getKernel().hashCode(face.wrapped,
|
|
319
|
+
const hash = require_shapeTypes.getKernel().hashCode(face.wrapped, require_constants.HASH_CODE_MAX);
|
|
320
320
|
if (hashes.has(hash)) result.push(face);
|
|
321
321
|
}
|
|
322
322
|
return result;
|
|
@@ -330,7 +330,7 @@ function getFaceTags(shape) {
|
|
|
330
330
|
if (!tagMap) return result;
|
|
331
331
|
const faces = getFaces(shape);
|
|
332
332
|
const faceByHash = /* @__PURE__ */ new Map();
|
|
333
|
-
for (const face of faces) faceByHash.set(require_shapeTypes.getKernel().hashCode(face.wrapped,
|
|
333
|
+
for (const face of faces) faceByHash.set(require_shapeTypes.getKernel().hashCode(face.wrapped, require_constants.HASH_CODE_MAX), face);
|
|
334
334
|
for (const [tag, hashes] of tagMap) {
|
|
335
335
|
const taggedFaces = [];
|
|
336
336
|
for (const hash of hashes) {
|
|
@@ -442,7 +442,7 @@ function colorShape(shape, color) {
|
|
|
442
442
|
function colorFaces(shape, faces, color) {
|
|
443
443
|
const parsed = parseColor(color);
|
|
444
444
|
const map = getFaceColorMap(shape);
|
|
445
|
-
for (const face of faces) map.set(require_shapeTypes.getKernel().hashCode(face.wrapped,
|
|
445
|
+
for (const face of faces) map.set(require_shapeTypes.getKernel().hashCode(face.wrapped, require_constants.HASH_CODE_MAX), parsed);
|
|
446
446
|
return shape;
|
|
447
447
|
}
|
|
448
448
|
/**
|
|
@@ -457,7 +457,7 @@ function getShapeColor(shape) {
|
|
|
457
457
|
function getFaceColor(shape, face) {
|
|
458
458
|
const map = faceColorStore.get(shape.wrapped);
|
|
459
459
|
if (!map) return void 0;
|
|
460
|
-
return map.get(require_shapeTypes.getKernel().hashCode(face.wrapped,
|
|
460
|
+
return map.get(require_shapeTypes.getKernel().hashCode(face.wrapped, require_constants.HASH_CODE_MAX));
|
|
461
461
|
}
|
|
462
462
|
/**
|
|
463
463
|
* Propagate colors from input shapes to a result shape using a
|
|
@@ -497,7 +497,7 @@ function collectInputFaceHashes(inputs) {
|
|
|
497
497
|
const hashes = [];
|
|
498
498
|
for (const input of inputs) {
|
|
499
499
|
const faces = kernel.iterShapes(input.wrapped, "face");
|
|
500
|
-
for (const face of faces) hashes.push(kernel.hashCode(face,
|
|
500
|
+
for (const face of faces) hashes.push(kernel.hashCode(face, require_constants.HASH_CODE_MAX));
|
|
501
501
|
}
|
|
502
502
|
return hashes;
|
|
503
503
|
}
|
|
@@ -536,7 +536,7 @@ function propagateMetadataByHash(inputs, result) {
|
|
|
536
536
|
/** Translate a shape by a vector. Returns a new shape. */
|
|
537
537
|
function translate(shape, v) {
|
|
538
538
|
const inputFaceHashes = collectInputFaceHashes([shape]);
|
|
539
|
-
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().translateWithHistory(shape.wrapped, v[0], v[1], v[2], inputFaceHashes,
|
|
539
|
+
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().translateWithHistory(shape.wrapped, v[0], v[1], v[2], inputFaceHashes, require_constants.HASH_CODE_MAX);
|
|
540
540
|
const result = require_shapeTypes.castShape(resultShape);
|
|
541
541
|
propagateAllMetadata(evolution, [shape], result);
|
|
542
542
|
return result;
|
|
@@ -552,7 +552,7 @@ function rotate(shape, angle, position = [
|
|
|
552
552
|
1
|
|
553
553
|
]) {
|
|
554
554
|
const inputFaceHashes = collectInputFaceHashes([shape]);
|
|
555
|
-
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().rotateWithHistory(shape.wrapped, angle *
|
|
555
|
+
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().rotateWithHistory(shape.wrapped, angle * require_constants.DEG2RAD, inputFaceHashes, require_constants.HASH_CODE_MAX, direction, position);
|
|
556
556
|
const result = require_shapeTypes.castShape(resultShape);
|
|
557
557
|
propagateAllMetadata(evolution, [shape], result);
|
|
558
558
|
return result;
|
|
@@ -568,7 +568,7 @@ function mirror(shape, planeNormal = [
|
|
|
568
568
|
0
|
|
569
569
|
]) {
|
|
570
570
|
const inputFaceHashes = collectInputFaceHashes([shape]);
|
|
571
|
-
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().mirrorWithHistory(shape.wrapped, planeOrigin, planeNormal, inputFaceHashes,
|
|
571
|
+
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().mirrorWithHistory(shape.wrapped, planeOrigin, planeNormal, inputFaceHashes, require_constants.HASH_CODE_MAX);
|
|
572
572
|
const result = require_shapeTypes.castShape(resultShape);
|
|
573
573
|
propagateAllMetadata(evolution, [shape], result);
|
|
574
574
|
return result;
|
|
@@ -580,7 +580,7 @@ function scale(shape, factor, center = [
|
|
|
580
580
|
0
|
|
581
581
|
]) {
|
|
582
582
|
const inputFaceHashes = collectInputFaceHashes([shape]);
|
|
583
|
-
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().scaleWithHistory(shape.wrapped, center, factor, inputFaceHashes,
|
|
583
|
+
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().scaleWithHistory(shape.wrapped, center, factor, inputFaceHashes, require_constants.HASH_CODE_MAX);
|
|
584
584
|
const result = require_shapeTypes.castShape(resultShape);
|
|
585
585
|
propagateAllMetadata(evolution, [shape], result);
|
|
586
586
|
return result;
|
|
@@ -682,7 +682,7 @@ function applyMatrix(shape, matrix) {
|
|
|
682
682
|
if (Math.abs(d) < 1e-12) return require_errors.err(require_errors.validationError(require_errors.BrepErrorCode.VALIDATION_FAILED, "applyMatrix: singular matrix (determinant ≈ 0). Cannot apply a non-invertible transform."));
|
|
683
683
|
if (isOrthogonalMatrix(linear)) {
|
|
684
684
|
const inputFaceHashes = collectInputFaceHashes([shape]);
|
|
685
|
-
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().generalTransformWithHistory(shape.wrapped, linear, translation, true, inputFaceHashes,
|
|
685
|
+
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().generalTransformWithHistory(shape.wrapped, linear, translation, true, inputFaceHashes, require_constants.HASH_CODE_MAX);
|
|
686
686
|
const result = require_shapeTypes.castShape(resultShape);
|
|
687
687
|
propagateAllMetadata(evolution, [shape], result);
|
|
688
688
|
return require_errors.ok(result);
|
|
@@ -724,7 +724,7 @@ function composeTransforms(ops) {
|
|
|
724
724
|
*/
|
|
725
725
|
function transformCopy(shape, composed) {
|
|
726
726
|
const inputFaceHashes = collectInputFaceHashes([shape]);
|
|
727
|
-
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().applyComposedTransformWithHistory(shape.wrapped, composed.trsf, inputFaceHashes,
|
|
727
|
+
const { shape: resultShape, evolution } = require_shapeTypes.getKernel().applyComposedTransformWithHistory(shape.wrapped, composed.trsf, inputFaceHashes, require_constants.HASH_CODE_MAX);
|
|
728
728
|
const result = require_shapeTypes.castShape(resultShape);
|
|
729
729
|
propagateAllMetadata(evolution, [shape], result);
|
|
730
730
|
return result;
|
|
@@ -741,15 +741,15 @@ function transformCopy(shape, composed) {
|
|
|
741
741
|
*/
|
|
742
742
|
/** Clone a shape (deep copy via kernel topology downcast). */
|
|
743
743
|
function clone(shape) {
|
|
744
|
-
return
|
|
744
|
+
return require_faceFns.kernelCall(() => require_shapeTypes.getKernel().downcast(shape.wrapped), require_errors.BrepErrorCode.CLONE_FAILED, "Failed to clone shape");
|
|
745
745
|
}
|
|
746
746
|
/** Serialize a shape to BREP string format. */
|
|
747
747
|
function toBREP(shape) {
|
|
748
|
-
return require_shapeTypes.getKernel().toBREP(shape.wrapped);
|
|
748
|
+
return require_faceFns.kernelCallRaw(() => require_shapeTypes.getKernel().toBREP(shape.wrapped), require_errors.BrepErrorCode.TO_BREP_FAILED, "Failed to serialize shape to BREP");
|
|
749
749
|
}
|
|
750
750
|
/** Get the topology hash code of a shape. */
|
|
751
751
|
function getHashCode(shape) {
|
|
752
|
-
return require_shapeTypes.getKernel().hashCode(shape.wrapped,
|
|
752
|
+
return require_shapeTypes.getKernel().hashCode(shape.wrapped, require_constants.HASH_CODE_MAX);
|
|
753
753
|
}
|
|
754
754
|
/** Check if a shape is null. */
|
|
755
755
|
function isEmpty(shape) {
|
|
@@ -765,29 +765,7 @@ function isEqualShape(a, b) {
|
|
|
765
765
|
}
|
|
766
766
|
/** Simplify a shape by merging same-domain faces/edges. Returns a new shape. */
|
|
767
767
|
function simplify(shape) {
|
|
768
|
-
return
|
|
769
|
-
}
|
|
770
|
-
//#endregion
|
|
771
|
-
//#region src/utils/arrayAccess.ts
|
|
772
|
-
/**
|
|
773
|
-
* Safe array access utilities.
|
|
774
|
-
* Replaces `arr[i]!` patterns where TypeScript's `noUncheckedIndexedAccess` requires
|
|
775
|
-
* a non-null assertion but bounds are proven by surrounding code.
|
|
776
|
-
*/
|
|
777
|
-
/** Access element by index, throwing if out of bounds. Use when bounds are logically guaranteed. */
|
|
778
|
-
function getAtOrThrow(arr, index, msg) {
|
|
779
|
-
if (index < 0 || index >= arr.length) throw new Error(msg ?? `Index ${index} out of bounds (length ${arr.length})`);
|
|
780
|
-
return arr[index];
|
|
781
|
-
}
|
|
782
|
-
/** Get the first element of a non-empty array, throwing if empty. */
|
|
783
|
-
function firstOrThrow(arr, msg) {
|
|
784
|
-
if (arr.length === 0) throw new Error(msg ?? "Expected non-empty array");
|
|
785
|
-
return arr[0];
|
|
786
|
-
}
|
|
787
|
-
/** Get the last element of a non-empty array, throwing if empty. */
|
|
788
|
-
function lastOrThrow(arr, msg) {
|
|
789
|
-
if (arr.length === 0) throw new Error(msg ?? "Expected non-empty array");
|
|
790
|
-
return arr[arr.length - 1];
|
|
768
|
+
return require_faceFns.kernelCall(() => require_shapeTypes.getKernel().simplify(shape.wrapped), require_errors.BrepErrorCode.SIMPLIFY_FAILED, "Failed to simplify shape");
|
|
791
769
|
}
|
|
792
770
|
//#endregion
|
|
793
771
|
Object.defineProperty(exports, "applyMatrix", {
|
|
@@ -838,18 +816,6 @@ Object.defineProperty(exports, "findFacesByTag", {
|
|
|
838
816
|
return findFacesByTag;
|
|
839
817
|
}
|
|
840
818
|
});
|
|
841
|
-
Object.defineProperty(exports, "firstOrThrow", {
|
|
842
|
-
enumerable: true,
|
|
843
|
-
get: function() {
|
|
844
|
-
return firstOrThrow;
|
|
845
|
-
}
|
|
846
|
-
});
|
|
847
|
-
Object.defineProperty(exports, "getAtOrThrow", {
|
|
848
|
-
enumerable: true,
|
|
849
|
-
get: function() {
|
|
850
|
-
return getAtOrThrow;
|
|
851
|
-
}
|
|
852
|
-
});
|
|
853
819
|
Object.defineProperty(exports, "getBounds", {
|
|
854
820
|
enumerable: true,
|
|
855
821
|
get: function() {
|
|
@@ -970,12 +936,6 @@ Object.defineProperty(exports, "iterWires", {
|
|
|
970
936
|
return iterWires;
|
|
971
937
|
}
|
|
972
938
|
});
|
|
973
|
-
Object.defineProperty(exports, "lastOrThrow", {
|
|
974
|
-
enumerable: true,
|
|
975
|
-
get: function() {
|
|
976
|
-
return lastOrThrow;
|
|
977
|
-
}
|
|
978
|
-
});
|
|
979
939
|
Object.defineProperty(exports, "mirror", {
|
|
980
940
|
enumerable: true,
|
|
981
941
|
get: function() {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_shapeRefFns = require("./shapeRefFns-CVdS6jWS.cjs");
|
|
3
|
+
exports.assignRoles = require_shapeRefFns.assignRoles;
|
|
4
|
+
exports.captureHint = require_shapeRefFns.captureHint;
|
|
5
|
+
exports.createRef = require_shapeRefFns.createRef;
|
|
6
|
+
exports.defaultScorer = require_shapeRefFns.defaultScorer;
|
|
7
|
+
exports.resolveRef = require_shapeRefFns.resolveRef;
|
|
8
|
+
exports.updateRoles = require_shapeRefFns.updateRoles;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* brepjs/shapeRef — Stable face references for parametric replay.
|
|
3
|
+
*/
|
|
4
|
+
export { type GeometricHint, type ShapeRef, type RoleTable, type ResolvedRef, type BrokenRef, type FaceScorer, defaultScorer, captureHint, assignRoles, createRef, updateRoles, resolveRef, } from './topology/shapeRef/index.js';
|
|
5
|
+
//# sourceMappingURL=shapeRef.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapeRef.d.ts","sourceRoot":"","sources":["../src/shapeRef.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,aAAa,EACb,WAAW,EACX,WAAW,EACX,SAAS,EACT,WAAW,EACX,UAAU,GACX,MAAM,8BAA8B,CAAC"}
|
package/dist/shapeRef.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { c as normalAt, n as faceCenter, r as faceGeomType } from "./faceFns-TSH54pPQ.js";
|
|
2
|
+
import { N as getFaces, n as getHashCode } from "./shapeFns-DCi9O27X.js";
|
|
3
|
+
import { n as measureArea } from "./measureFns-DHByqdmn.js";
|
|
4
|
+
//#region src/topology/shapeRef/scoring.ts
|
|
5
|
+
/**
|
|
6
|
+
* Default face scorer combining surface type, normal alignment, centroid proximity,
|
|
7
|
+
* and area similarity.
|
|
8
|
+
*
|
|
9
|
+
* Scoring breakdown:
|
|
10
|
+
* - Surface type match: +1.0 (mismatch when both defined: -Infinity)
|
|
11
|
+
* - Normal dot product: weighted contribution (rejected if < 0.707)
|
|
12
|
+
* - Centroid distance: quadratic penalty (rejected if distSq > 100)
|
|
13
|
+
* - Area ratio: penalized if |log(hintArea / faceArea)| > 1.0
|
|
14
|
+
*/
|
|
15
|
+
function defaultScorer(hint, face) {
|
|
16
|
+
let score = 0;
|
|
17
|
+
const faceType = faceGeomType(face);
|
|
18
|
+
if (hint.surfaceType !== void 0) if (faceType === hint.surfaceType) score += 1;
|
|
19
|
+
else return -Infinity;
|
|
20
|
+
if (hint.normal !== void 0) {
|
|
21
|
+
const faceNormal = normalAt(face);
|
|
22
|
+
const dot = hint.normal[0] * faceNormal[0] + hint.normal[1] * faceNormal[1] + hint.normal[2] * faceNormal[2];
|
|
23
|
+
if (dot < .707) return -Infinity;
|
|
24
|
+
score += dot;
|
|
25
|
+
}
|
|
26
|
+
if (hint.centroid !== void 0) {
|
|
27
|
+
const faceCentroid = faceCenter(face);
|
|
28
|
+
const dx = hint.centroid[0] - faceCentroid[0];
|
|
29
|
+
const dy = hint.centroid[1] - faceCentroid[1];
|
|
30
|
+
const dz = hint.centroid[2] - faceCentroid[2];
|
|
31
|
+
const distSq = dx * dx + dy * dy + dz * dz;
|
|
32
|
+
if (distSq > 100) return -Infinity;
|
|
33
|
+
score -= distSq / 100;
|
|
34
|
+
}
|
|
35
|
+
if (hint.area !== void 0 && hint.area > 0) {
|
|
36
|
+
const areaResult = measureArea(face);
|
|
37
|
+
if (areaResult.ok && areaResult.value > 0) {
|
|
38
|
+
const logRatio = Math.abs(Math.log(hint.area / areaResult.value));
|
|
39
|
+
if (logRatio > 1) score -= logRatio;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return score;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/topology/shapeRef/shapeRefFns.ts
|
|
46
|
+
/** Snapshot the geometric properties of a face for later matching. */
|
|
47
|
+
function captureHint(face) {
|
|
48
|
+
const surfaceType = faceGeomType(face);
|
|
49
|
+
const normal = normalAt(face);
|
|
50
|
+
const centroid = faceCenter(face);
|
|
51
|
+
const areaResult = measureArea(face);
|
|
52
|
+
return {
|
|
53
|
+
entityType: "face",
|
|
54
|
+
surfaceType,
|
|
55
|
+
normal,
|
|
56
|
+
centroid,
|
|
57
|
+
area: areaResult.ok ? areaResult.value : void 0
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Threshold for dominant-axis detection (abs(component) > 0.9). */
|
|
61
|
+
var AXIS_THRESHOLD = .9;
|
|
62
|
+
/** Determine the cardinal role name for a box face from its outward normal. */
|
|
63
|
+
function boxRoleFromNormal(n) {
|
|
64
|
+
if (n[2] > AXIS_THRESHOLD) return "box:top";
|
|
65
|
+
if (n[2] < -AXIS_THRESHOLD) return "box:bottom";
|
|
66
|
+
if (n[1] > AXIS_THRESHOLD) return "box:back";
|
|
67
|
+
if (n[1] < -AXIS_THRESHOLD) return "box:front";
|
|
68
|
+
if (n[0] > AXIS_THRESHOLD) return "box:right";
|
|
69
|
+
if (n[0] < -AXIS_THRESHOLD) return "box:left";
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Auto-assign role names to the faces of a shape based on operation type.
|
|
73
|
+
*
|
|
74
|
+
* For 'box': uses face normals to assign cardinal names
|
|
75
|
+
* ('box:top', 'box:bottom', 'box:front', 'box:back', 'box:left', 'box:right').
|
|
76
|
+
* **Note:** Box role detection assumes axis-aligned faces (normal within 0.9 of
|
|
77
|
+
* a cardinal axis). Rotated boxes may receive fewer than 6 named roles; remaining
|
|
78
|
+
* faces fall through to sequential naming.
|
|
79
|
+
*
|
|
80
|
+
* For other types: sequential naming ('opType:face_0', 'opType:face_1', ...).
|
|
81
|
+
*
|
|
82
|
+
* @returns Map from role name to face hash code
|
|
83
|
+
*/
|
|
84
|
+
function assignRoles(shape, operationType) {
|
|
85
|
+
const faces = getFaces(shape);
|
|
86
|
+
const roles = /* @__PURE__ */ new Map();
|
|
87
|
+
if (operationType === "box") {
|
|
88
|
+
for (const face of faces) {
|
|
89
|
+
const role = boxRoleFromNormal(normalAt(face));
|
|
90
|
+
if (role !== void 0 && !roles.has(role)) roles.set(role, getHashCode(face));
|
|
91
|
+
}
|
|
92
|
+
return roles;
|
|
93
|
+
}
|
|
94
|
+
let index = 0;
|
|
95
|
+
for (const face of faces) {
|
|
96
|
+
roles.set(`${operationType}:face_${index}`, getHashCode(face));
|
|
97
|
+
index++;
|
|
98
|
+
}
|
|
99
|
+
return roles;
|
|
100
|
+
}
|
|
101
|
+
/** Create a ShapeRef from an origin ID, role name, and face. */
|
|
102
|
+
function createRef(origin, role, face) {
|
|
103
|
+
return {
|
|
104
|
+
origin,
|
|
105
|
+
role,
|
|
106
|
+
hint: captureHint(face)
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Propagate a role table through a ShapeEvolution record.
|
|
111
|
+
* Returns a new RoleTable with hashes updated according to the evolution.
|
|
112
|
+
*
|
|
113
|
+
* - Deleted faces: role removed
|
|
114
|
+
* - Modified faces: hash updated to first result hash
|
|
115
|
+
* - Unchanged faces: hash preserved
|
|
116
|
+
*
|
|
117
|
+
* **Limitation:** When a face splits (1→many in `evolution.modified`), only the
|
|
118
|
+
* first successor hash is tracked. The geometric fallback in `resolveRef` handles
|
|
119
|
+
* cases where this picks the "wrong" successor. A future version may return
|
|
120
|
+
* multi-hash mappings for split-aware resolution.
|
|
121
|
+
*/
|
|
122
|
+
function updateRoles(roles, origin, evolution) {
|
|
123
|
+
const originRoles = roles.get(origin);
|
|
124
|
+
if (!originRoles) return roles;
|
|
125
|
+
const updatedOriginRoles = /* @__PURE__ */ new Map();
|
|
126
|
+
for (const [role, hash] of originRoles) {
|
|
127
|
+
if (evolution.deleted.has(hash)) continue;
|
|
128
|
+
const modifiedHashes = evolution.modified.get(hash);
|
|
129
|
+
if (modifiedHashes && modifiedHashes.length > 0) updatedOriginRoles.set(role, modifiedHashes[0]);
|
|
130
|
+
else updatedOriginRoles.set(role, hash);
|
|
131
|
+
}
|
|
132
|
+
const newRoles = /* @__PURE__ */ new Map();
|
|
133
|
+
for (const [key, value] of roles) if (key === origin) newRoles.set(key, updatedOriginRoles);
|
|
134
|
+
else newRoles.set(key, value);
|
|
135
|
+
return newRoles;
|
|
136
|
+
}
|
|
137
|
+
/** Ambiguity threshold: if two scores are within this range, it's ambiguous. */
|
|
138
|
+
var AMBIGUITY_THRESHOLD = .1;
|
|
139
|
+
/** Minimum score for geometric fallback to accept a match. */
|
|
140
|
+
var MIN_SCORE = .5;
|
|
141
|
+
/**
|
|
142
|
+
* Resolve a ShapeRef to a face in the current shape.
|
|
143
|
+
*
|
|
144
|
+
* Resolution strategy:
|
|
145
|
+
* 1. Exact lookup via role table hash match
|
|
146
|
+
* 2. Geometric fallback using scorer against all faces
|
|
147
|
+
* 3. Ambiguous if multiple faces score within threshold
|
|
148
|
+
* 4. Not-found if no match above minimum score
|
|
149
|
+
*/
|
|
150
|
+
function resolveRef(ref, roles, currentShape, scorer) {
|
|
151
|
+
const faces = getFaces(currentShape);
|
|
152
|
+
const scoreFn = scorer ?? defaultScorer;
|
|
153
|
+
const targetHash = roles.get(ref.origin)?.get(ref.role);
|
|
154
|
+
if (targetHash !== void 0) {
|
|
155
|
+
for (const face of faces) if (getHashCode(face) === targetHash) return {
|
|
156
|
+
face,
|
|
157
|
+
confidence: "exact"
|
|
158
|
+
};
|
|
159
|
+
return {
|
|
160
|
+
ref,
|
|
161
|
+
reason: "deleted"
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
let bestScore = -Infinity;
|
|
165
|
+
let bestFace;
|
|
166
|
+
let secondBestScore = -Infinity;
|
|
167
|
+
const scored = [];
|
|
168
|
+
for (const face of faces) {
|
|
169
|
+
const score = scoreFn(ref.hint, face);
|
|
170
|
+
if (score > MIN_SCORE) scored.push([face, score]);
|
|
171
|
+
if (score > bestScore) {
|
|
172
|
+
secondBestScore = bestScore;
|
|
173
|
+
bestScore = score;
|
|
174
|
+
bestFace = face;
|
|
175
|
+
} else if (score > secondBestScore) secondBestScore = score;
|
|
176
|
+
}
|
|
177
|
+
if (bestFace !== void 0 && bestScore > MIN_SCORE) {
|
|
178
|
+
if (bestScore - secondBestScore < AMBIGUITY_THRESHOLD && scored.length > 1) return {
|
|
179
|
+
ref,
|
|
180
|
+
reason: "ambiguous",
|
|
181
|
+
candidates: scored.filter(([, s]) => s >= bestScore - AMBIGUITY_THRESHOLD).map(([f]) => f)
|
|
182
|
+
};
|
|
183
|
+
return {
|
|
184
|
+
face: bestFace,
|
|
185
|
+
confidence: "geometric-fallback"
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
ref,
|
|
190
|
+
reason: "not-found"
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
export { updateRoles as a, resolveRef as i, captureHint as n, defaultScorer as o, createRef as r, assignRoles as t };
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
const require_faceFns = require("./faceFns-cE2WxY6I.cjs");
|
|
2
|
+
const require_shapeFns = require("./shapeFns-aEeSHNqX.cjs");
|
|
3
|
+
const require_measureFns = require("./measureFns-D_QKZ5yg.cjs");
|
|
4
|
+
//#region src/topology/shapeRef/scoring.ts
|
|
5
|
+
/**
|
|
6
|
+
* Default face scorer combining surface type, normal alignment, centroid proximity,
|
|
7
|
+
* and area similarity.
|
|
8
|
+
*
|
|
9
|
+
* Scoring breakdown:
|
|
10
|
+
* - Surface type match: +1.0 (mismatch when both defined: -Infinity)
|
|
11
|
+
* - Normal dot product: weighted contribution (rejected if < 0.707)
|
|
12
|
+
* - Centroid distance: quadratic penalty (rejected if distSq > 100)
|
|
13
|
+
* - Area ratio: penalized if |log(hintArea / faceArea)| > 1.0
|
|
14
|
+
*/
|
|
15
|
+
function defaultScorer(hint, face) {
|
|
16
|
+
let score = 0;
|
|
17
|
+
const faceType = require_faceFns.faceGeomType(face);
|
|
18
|
+
if (hint.surfaceType !== void 0) if (faceType === hint.surfaceType) score += 1;
|
|
19
|
+
else return -Infinity;
|
|
20
|
+
if (hint.normal !== void 0) {
|
|
21
|
+
const faceNormal = require_faceFns.normalAt(face);
|
|
22
|
+
const dot = hint.normal[0] * faceNormal[0] + hint.normal[1] * faceNormal[1] + hint.normal[2] * faceNormal[2];
|
|
23
|
+
if (dot < .707) return -Infinity;
|
|
24
|
+
score += dot;
|
|
25
|
+
}
|
|
26
|
+
if (hint.centroid !== void 0) {
|
|
27
|
+
const faceCentroid = require_faceFns.faceCenter(face);
|
|
28
|
+
const dx = hint.centroid[0] - faceCentroid[0];
|
|
29
|
+
const dy = hint.centroid[1] - faceCentroid[1];
|
|
30
|
+
const dz = hint.centroid[2] - faceCentroid[2];
|
|
31
|
+
const distSq = dx * dx + dy * dy + dz * dz;
|
|
32
|
+
if (distSq > 100) return -Infinity;
|
|
33
|
+
score -= distSq / 100;
|
|
34
|
+
}
|
|
35
|
+
if (hint.area !== void 0 && hint.area > 0) {
|
|
36
|
+
const areaResult = require_measureFns.measureArea(face);
|
|
37
|
+
if (areaResult.ok && areaResult.value > 0) {
|
|
38
|
+
const logRatio = Math.abs(Math.log(hint.area / areaResult.value));
|
|
39
|
+
if (logRatio > 1) score -= logRatio;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return score;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/topology/shapeRef/shapeRefFns.ts
|
|
46
|
+
/** Snapshot the geometric properties of a face for later matching. */
|
|
47
|
+
function captureHint(face) {
|
|
48
|
+
const surfaceType = require_faceFns.faceGeomType(face);
|
|
49
|
+
const normal = require_faceFns.normalAt(face);
|
|
50
|
+
const centroid = require_faceFns.faceCenter(face);
|
|
51
|
+
const areaResult = require_measureFns.measureArea(face);
|
|
52
|
+
return {
|
|
53
|
+
entityType: "face",
|
|
54
|
+
surfaceType,
|
|
55
|
+
normal,
|
|
56
|
+
centroid,
|
|
57
|
+
area: areaResult.ok ? areaResult.value : void 0
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Threshold for dominant-axis detection (abs(component) > 0.9). */
|
|
61
|
+
var AXIS_THRESHOLD = .9;
|
|
62
|
+
/** Determine the cardinal role name for a box face from its outward normal. */
|
|
63
|
+
function boxRoleFromNormal(n) {
|
|
64
|
+
if (n[2] > AXIS_THRESHOLD) return "box:top";
|
|
65
|
+
if (n[2] < -AXIS_THRESHOLD) return "box:bottom";
|
|
66
|
+
if (n[1] > AXIS_THRESHOLD) return "box:back";
|
|
67
|
+
if (n[1] < -AXIS_THRESHOLD) return "box:front";
|
|
68
|
+
if (n[0] > AXIS_THRESHOLD) return "box:right";
|
|
69
|
+
if (n[0] < -AXIS_THRESHOLD) return "box:left";
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Auto-assign role names to the faces of a shape based on operation type.
|
|
73
|
+
*
|
|
74
|
+
* For 'box': uses face normals to assign cardinal names
|
|
75
|
+
* ('box:top', 'box:bottom', 'box:front', 'box:back', 'box:left', 'box:right').
|
|
76
|
+
* **Note:** Box role detection assumes axis-aligned faces (normal within 0.9 of
|
|
77
|
+
* a cardinal axis). Rotated boxes may receive fewer than 6 named roles; remaining
|
|
78
|
+
* faces fall through to sequential naming.
|
|
79
|
+
*
|
|
80
|
+
* For other types: sequential naming ('opType:face_0', 'opType:face_1', ...).
|
|
81
|
+
*
|
|
82
|
+
* @returns Map from role name to face hash code
|
|
83
|
+
*/
|
|
84
|
+
function assignRoles(shape, operationType) {
|
|
85
|
+
const faces = require_shapeFns.getFaces(shape);
|
|
86
|
+
const roles = /* @__PURE__ */ new Map();
|
|
87
|
+
if (operationType === "box") {
|
|
88
|
+
for (const face of faces) {
|
|
89
|
+
const role = boxRoleFromNormal(require_faceFns.normalAt(face));
|
|
90
|
+
if (role !== void 0 && !roles.has(role)) roles.set(role, require_shapeFns.getHashCode(face));
|
|
91
|
+
}
|
|
92
|
+
return roles;
|
|
93
|
+
}
|
|
94
|
+
let index = 0;
|
|
95
|
+
for (const face of faces) {
|
|
96
|
+
roles.set(`${operationType}:face_${index}`, require_shapeFns.getHashCode(face));
|
|
97
|
+
index++;
|
|
98
|
+
}
|
|
99
|
+
return roles;
|
|
100
|
+
}
|
|
101
|
+
/** Create a ShapeRef from an origin ID, role name, and face. */
|
|
102
|
+
function createRef(origin, role, face) {
|
|
103
|
+
return {
|
|
104
|
+
origin,
|
|
105
|
+
role,
|
|
106
|
+
hint: captureHint(face)
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Propagate a role table through a ShapeEvolution record.
|
|
111
|
+
* Returns a new RoleTable with hashes updated according to the evolution.
|
|
112
|
+
*
|
|
113
|
+
* - Deleted faces: role removed
|
|
114
|
+
* - Modified faces: hash updated to first result hash
|
|
115
|
+
* - Unchanged faces: hash preserved
|
|
116
|
+
*
|
|
117
|
+
* **Limitation:** When a face splits (1→many in `evolution.modified`), only the
|
|
118
|
+
* first successor hash is tracked. The geometric fallback in `resolveRef` handles
|
|
119
|
+
* cases where this picks the "wrong" successor. A future version may return
|
|
120
|
+
* multi-hash mappings for split-aware resolution.
|
|
121
|
+
*/
|
|
122
|
+
function updateRoles(roles, origin, evolution) {
|
|
123
|
+
const originRoles = roles.get(origin);
|
|
124
|
+
if (!originRoles) return roles;
|
|
125
|
+
const updatedOriginRoles = /* @__PURE__ */ new Map();
|
|
126
|
+
for (const [role, hash] of originRoles) {
|
|
127
|
+
if (evolution.deleted.has(hash)) continue;
|
|
128
|
+
const modifiedHashes = evolution.modified.get(hash);
|
|
129
|
+
if (modifiedHashes && modifiedHashes.length > 0) updatedOriginRoles.set(role, modifiedHashes[0]);
|
|
130
|
+
else updatedOriginRoles.set(role, hash);
|
|
131
|
+
}
|
|
132
|
+
const newRoles = /* @__PURE__ */ new Map();
|
|
133
|
+
for (const [key, value] of roles) if (key === origin) newRoles.set(key, updatedOriginRoles);
|
|
134
|
+
else newRoles.set(key, value);
|
|
135
|
+
return newRoles;
|
|
136
|
+
}
|
|
137
|
+
/** Ambiguity threshold: if two scores are within this range, it's ambiguous. */
|
|
138
|
+
var AMBIGUITY_THRESHOLD = .1;
|
|
139
|
+
/** Minimum score for geometric fallback to accept a match. */
|
|
140
|
+
var MIN_SCORE = .5;
|
|
141
|
+
/**
|
|
142
|
+
* Resolve a ShapeRef to a face in the current shape.
|
|
143
|
+
*
|
|
144
|
+
* Resolution strategy:
|
|
145
|
+
* 1. Exact lookup via role table hash match
|
|
146
|
+
* 2. Geometric fallback using scorer against all faces
|
|
147
|
+
* 3. Ambiguous if multiple faces score within threshold
|
|
148
|
+
* 4. Not-found if no match above minimum score
|
|
149
|
+
*/
|
|
150
|
+
function resolveRef(ref, roles, currentShape, scorer) {
|
|
151
|
+
const faces = require_shapeFns.getFaces(currentShape);
|
|
152
|
+
const scoreFn = scorer ?? defaultScorer;
|
|
153
|
+
const targetHash = roles.get(ref.origin)?.get(ref.role);
|
|
154
|
+
if (targetHash !== void 0) {
|
|
155
|
+
for (const face of faces) if (require_shapeFns.getHashCode(face) === targetHash) return {
|
|
156
|
+
face,
|
|
157
|
+
confidence: "exact"
|
|
158
|
+
};
|
|
159
|
+
return {
|
|
160
|
+
ref,
|
|
161
|
+
reason: "deleted"
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
let bestScore = -Infinity;
|
|
165
|
+
let bestFace;
|
|
166
|
+
let secondBestScore = -Infinity;
|
|
167
|
+
const scored = [];
|
|
168
|
+
for (const face of faces) {
|
|
169
|
+
const score = scoreFn(ref.hint, face);
|
|
170
|
+
if (score > MIN_SCORE) scored.push([face, score]);
|
|
171
|
+
if (score > bestScore) {
|
|
172
|
+
secondBestScore = bestScore;
|
|
173
|
+
bestScore = score;
|
|
174
|
+
bestFace = face;
|
|
175
|
+
} else if (score > secondBestScore) secondBestScore = score;
|
|
176
|
+
}
|
|
177
|
+
if (bestFace !== void 0 && bestScore > MIN_SCORE) {
|
|
178
|
+
if (bestScore - secondBestScore < AMBIGUITY_THRESHOLD && scored.length > 1) return {
|
|
179
|
+
ref,
|
|
180
|
+
reason: "ambiguous",
|
|
181
|
+
candidates: scored.filter(([, s]) => s >= bestScore - AMBIGUITY_THRESHOLD).map(([f]) => f)
|
|
182
|
+
};
|
|
183
|
+
return {
|
|
184
|
+
face: bestFace,
|
|
185
|
+
confidence: "geometric-fallback"
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
ref,
|
|
190
|
+
reason: "not-found"
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
Object.defineProperty(exports, "assignRoles", {
|
|
195
|
+
enumerable: true,
|
|
196
|
+
get: function() {
|
|
197
|
+
return assignRoles;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
Object.defineProperty(exports, "captureHint", {
|
|
201
|
+
enumerable: true,
|
|
202
|
+
get: function() {
|
|
203
|
+
return captureHint;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
Object.defineProperty(exports, "createRef", {
|
|
207
|
+
enumerable: true,
|
|
208
|
+
get: function() {
|
|
209
|
+
return createRef;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
Object.defineProperty(exports, "defaultScorer", {
|
|
213
|
+
enumerable: true,
|
|
214
|
+
get: function() {
|
|
215
|
+
return defaultScorer;
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
Object.defineProperty(exports, "resolveRef", {
|
|
219
|
+
enumerable: true,
|
|
220
|
+
get: function() {
|
|
221
|
+
return resolveRef;
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
Object.defineProperty(exports, "updateRoles", {
|
|
225
|
+
enumerable: true,
|
|
226
|
+
get: function() {
|
|
227
|
+
return updateRoles;
|
|
228
|
+
}
|
|
229
|
+
});
|