brepjs 18.108.0 → 18.110.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/2d.cjs +6 -6
- package/dist/2d.js +6 -6
- package/dist/{blueprint-D5ArjKiA.cjs → blueprint-BwkD2qeC.cjs} +5 -5
- package/dist/{blueprint-CF12Nceg.js → blueprint-Dw0QqImu.js} +5 -5
- package/dist/{blueprintFns-CcCfkbyd.cjs → blueprintFns-B-aybpEo.cjs} +2 -2
- package/dist/{blueprintFns-BuPAK4OB.js → blueprintFns-BowWsZgJ.js} +2 -2
- package/dist/{blueprintSketcher-CEQ8s7TD.js → blueprintSketcher-7rtwqUHZ.js} +3 -3
- package/dist/{blueprintSketcher-DCttG3KS.cjs → blueprintSketcher-RK-cH6ps.cjs} +3 -3
- package/dist/{boolean2D-BCqDjg0y.cjs → boolean2D-CZUEOoAh.cjs} +4 -4
- package/dist/{boolean2D-8rB2sUzj.js → boolean2D-y0SSZfe2.js} +4 -4
- package/dist/brepjs.cjs +64 -27
- package/dist/brepjs.js +64 -27
- package/dist/{cameraFns-Bu6jgTKc.js → cameraFns-bk9e0F-T.js} +2 -2
- package/dist/{cameraFns-S7YbAxfg.cjs → cameraFns-uo1sZbBT.cjs} +2 -2
- package/dist/core.cjs +1 -1
- package/dist/core.js +1 -1
- package/dist/{cornerFinder-Ci2NbbAW.cjs → cornerFinder-B4q88TRb.cjs} +1 -1
- package/dist/{cornerFinder-COqoeY--.js → cornerFinder-DUGeBIvD.js} +1 -1
- package/dist/{curveFns-CG05Jygr.js → curveFns-CcSn4-Rf.js} +1 -1
- package/dist/{curveFns-Dx7_wMut.cjs → curveFns-DgUJpH4z.cjs} +1 -1
- package/dist/{drawFns-DYkjT_hx.cjs → drawFns-DNxs7PAT.cjs} +12 -12
- package/dist/{drawFns-CsXPFyDe.js → drawFns-SQIBls6p.js} +12 -12
- package/dist/{faceFns-mo4ThIHz.js → faceFns-B86WGqDg.js} +2 -2
- package/dist/{faceFns-DKg2St8b.cjs → faceFns-BV0GnTlt.cjs} +2 -2
- package/dist/{healingFns-OL0bBSSY.cjs → healingFns-C4UE1ZyM.cjs} +5 -5
- package/dist/{healingFns-C5AomW4j.js → healingFns-CPm_VFck.js} +5 -5
- package/dist/{helpers-8zxf2gkc.cjs → helpers-BSLPCflF.cjs} +6 -6
- package/dist/{helpers-DT44wBAD.js → helpers-DhJwFrkC.js} +6 -6
- package/dist/{importFns-B6hw9Nhx.cjs → importFns-CgMQIi0z.cjs} +2 -2
- package/dist/{importFns-CEczwPdN.js → importFns-nR9lEx22.js} +2 -2
- package/dist/io.cjs +2 -2
- package/dist/io.js +2 -2
- package/dist/kernel/brepkit/transformOps.d.ts +1 -0
- package/dist/kernel/interfaces/transformOps.d.ts +10 -0
- package/dist/kernel/occt/transformOps.d.ts +8 -0
- package/dist/kernel/occtWasm/occtWasmAdapter.cjs +1 -1
- package/dist/kernel/occtWasm/occtWasmAdapter.d.ts +1 -0
- package/dist/kernel/occtWasm/occtWasmAdapter.js +1 -1
- package/dist/kernel/occtWasm/occtWasmTypes.d.ts +7 -0
- package/dist/kernel/occtWasm/transformOps.d.ts +7 -0
- package/dist/{loftFns-DyNuD9XL.js → loftFns-CmShFQlv.js} +1 -1
- package/dist/{loftFns-DaRDYpfB.cjs → loftFns-fpTmrIdd.cjs} +1 -1
- package/dist/{measureFns-Q2dnokUU.cjs → measureFns-DblG0Yaz.cjs} +3 -3
- package/dist/{measureFns-Dkh_DmrE.js → measureFns-a5Vx25or.js} +3 -3
- package/dist/measurement.cjs +1 -1
- package/dist/measurement.js +1 -1
- package/dist/{meshFns-JwMEfMvC.cjs → meshFns-1hQSn1p2.cjs} +3 -3
- package/dist/{meshFns-DeGn7mQ4.js → meshFns-DbmidUzH.js} +3 -3
- package/dist/{occtWasmAdapter-DDZELjlB.cjs → occtWasmAdapter-B2TEQOjs.cjs} +38 -10
- package/dist/{occtWasmAdapter-BDEPveZs.js → occtWasmAdapter-CKwtxwNH.js} +38 -10
- package/dist/operations.cjs +2 -2
- package/dist/operations.js +2 -2
- package/dist/{primitiveFns-62SO4ti5.js → primitiveFns-CBrOyk5S.js} +4 -4
- package/dist/{primitiveFns-BAWtMd9H.cjs → primitiveFns-DLIWtQWA.cjs} +4 -4
- package/dist/projection.cjs +1 -1
- package/dist/projection.js +1 -1
- package/dist/query.cjs +2 -2
- package/dist/query.js +2 -2
- package/dist/{shapeFns-DyBbhU30.js → shapeFns-DrZOVwHX.js} +44 -4
- package/dist/{shapeFns-L4a8kH_A.cjs → shapeFns-ybo0INGL.cjs} +55 -3
- package/dist/shapeRef.cjs +1 -1
- package/dist/shapeRef.js +1 -1
- package/dist/{shapeRefFns-Cn4WNb3q.js → shapeRefFns-ChMnsOAF.js} +101 -49
- package/dist/{shapeRefFns-Dij41NuC.cjs → shapeRefFns-CuepnFOm.cjs} +101 -49
- package/dist/{shapeTypes-Bwgm5N6R.cjs → shapeTypes-BTTwjHy5.cjs} +18 -1
- package/dist/{shapeTypes-C4lPfrc2.js → shapeTypes-Dpu6mD3m.js} +18 -1
- package/dist/sketching.cjs +3 -3
- package/dist/sketching.js +3 -3
- package/dist/{solidBuilders-Biwv2cW3.js → solidBuilders-C32wXQWG.js} +5 -5
- package/dist/{solidBuilders-CgRmJEdn.cjs → solidBuilders-DiUv_mD0.cjs} +5 -5
- package/dist/{surfaceBuilders-FLnYYA70.cjs → surfaceBuilders-UyyfZy8w.cjs} +2 -2
- package/dist/{surfaceBuilders-Bww4jhBo.js → surfaceBuilders-rkE-jE90.js} +2 -2
- package/dist/text.cjs +2 -2
- package/dist/text.js +2 -2
- package/dist/{textBlueprints-CEzTC9vX.js → textBlueprints-BnkWAqwS.js} +7 -7
- package/dist/{textBlueprints-08NcMO9T.cjs → textBlueprints-D5lsZswr.cjs} +7 -7
- package/dist/{textMetrics-CBbDQ5QW.js → textMetrics-COGYk0LE.js} +1 -1
- package/dist/{textMetrics-W-H6jUDj.cjs → textMetrics-IC_IoI7l.cjs} +1 -1
- package/dist/{threadFns-DGYdomjN.cjs → threadFns-C8bErjVC.cjs} +6 -6
- package/dist/{threadFns-8rKpQXiR.js → threadFns-bCOhVQLb.js} +6 -6
- package/dist/topology/metadata/metadataPropagation.d.ts +21 -0
- package/dist/topology/shapeRef/shapeRefFns.d.ts +19 -13
- package/dist/topology/shapeRef/shapeRefTypes.d.ts +6 -2
- package/dist/topology.cjs +8 -8
- package/dist/topology.js +8 -8
- package/dist/{topologyQueryFns-Do8E4EXj.js → topologyQueryFns-BeKaWpNm.js} +1 -1
- package/dist/{topologyQueryFns-ygBBXxnP.cjs → topologyQueryFns-CoXVHuN7.cjs} +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Z as getKernel, t as castShape } from "./shapeTypes-
|
|
1
|
+
import { Z as getKernel, t as castShape } from "./shapeTypes-Dpu6mD3m.js";
|
|
2
2
|
import { A as ok, b as err, d as validationError, t as BrepErrorCode } from "./errors-DNWJsfVU.js";
|
|
3
|
-
import { C as kernelCall, c as getFaces, l as getOrCreateCache, r as getCacheEntry, w as kernelCallRaw } from "./topologyQueryFns-
|
|
3
|
+
import { C as kernelCall, c as getFaces, l as getOrCreateCache, r as getCacheEntry, w as kernelCallRaw } from "./topologyQueryFns-BeKaWpNm.js";
|
|
4
4
|
import { n as HASH_CODE_MAX, t as DEG2RAD } from "./constants-ITRzCnCp.js";
|
|
5
5
|
//#region src/topology/metadata/originTrackingFns.ts
|
|
6
6
|
/**
|
|
@@ -376,8 +376,16 @@ function propagateColorsFromEvolution(evolution, inputs, result) {
|
|
|
376
376
|
* Fast-path: returns empty array when no inputs have any metadata (origins,
|
|
377
377
|
* tags, or colors), avoiding expensive WASM topology exploration.
|
|
378
378
|
*/
|
|
379
|
+
/**
|
|
380
|
+
* O(1) check: does a shape carry any propagatable metadata (face origins,
|
|
381
|
+
* tags, or colors)? Lets callers skip both expensive face iteration and
|
|
382
|
+
* metadata-preserving slow paths when there's nothing to preserve.
|
|
383
|
+
*/
|
|
384
|
+
function hasAnyMetadata(shape) {
|
|
385
|
+
return getFaceOrigins(shape) !== void 0 || hasFaceTags(shape) || hasColorMetadata(shape);
|
|
386
|
+
}
|
|
379
387
|
function collectInputFaceHashes(inputs) {
|
|
380
|
-
if (!inputs.some(
|
|
388
|
+
if (!inputs.some(hasAnyMetadata)) return [];
|
|
381
389
|
const kernel = getKernel();
|
|
382
390
|
const hashes = [];
|
|
383
391
|
for (const input of inputs) {
|
|
@@ -412,6 +420,38 @@ function propagateAllMetadata(evolution, inputs, result) {
|
|
|
412
420
|
function propagateMetadataByHash(inputs, result) {
|
|
413
421
|
propagateOriginsByHash(inputs, result);
|
|
414
422
|
}
|
|
423
|
+
/**
|
|
424
|
+
* Propagate all metadata through a *rigid relocation* (a `locate` re-tag).
|
|
425
|
+
*
|
|
426
|
+
* A relocated shape shares the source's TShape, so its faces correspond 1:1 to
|
|
427
|
+
* the source faces in iteration order — but carry new, location-dependent
|
|
428
|
+
* hashes, so the hash-keyed metadata must be re-keyed rather than left as-is.
|
|
429
|
+
* This synthesizes a 1:1 `modified` evolution (source face hash → moved face
|
|
430
|
+
* hash) and runs the standard propagation pipeline, so origins, tags, and
|
|
431
|
+
* colors all survive a move at `locate` cost (O(faces)), not a full copy.
|
|
432
|
+
*
|
|
433
|
+
* Callers should gate on {@link hasAnyMetadata} first: with no metadata this
|
|
434
|
+
* does pointless face iteration. The face counts always match for a rigid
|
|
435
|
+
* relocation; the length guard is purely defensive.
|
|
436
|
+
*/
|
|
437
|
+
function propagateMetadataThroughRelocation(source, moved) {
|
|
438
|
+
const kernel = getKernel();
|
|
439
|
+
const srcFaces = [...kernel.iterShapes(source.wrapped, "face")];
|
|
440
|
+
const movedFaces = [...kernel.iterShapes(moved.wrapped, "face")];
|
|
441
|
+
if (srcFaces.length !== movedFaces.length) return;
|
|
442
|
+
const modified = /* @__PURE__ */ new Map();
|
|
443
|
+
for (let i = 0; i < srcFaces.length; i++) {
|
|
444
|
+
const sf = srcFaces[i];
|
|
445
|
+
const mf = movedFaces[i];
|
|
446
|
+
if (sf === void 0 || mf === void 0) continue;
|
|
447
|
+
modified.set(kernel.hashCode(sf, HASH_CODE_MAX), [kernel.hashCode(mf, HASH_CODE_MAX)]);
|
|
448
|
+
}
|
|
449
|
+
propagateAllMetadata({
|
|
450
|
+
modified,
|
|
451
|
+
generated: /* @__PURE__ */ new Map(),
|
|
452
|
+
deleted: /* @__PURE__ */ new Set()
|
|
453
|
+
}, [source], moved);
|
|
454
|
+
}
|
|
415
455
|
//#endregion
|
|
416
456
|
//#region src/topology/transformFns.ts
|
|
417
457
|
/**
|
|
@@ -653,4 +693,4 @@ function simplify(shape) {
|
|
|
653
693
|
return kernelCall(() => getKernel().simplify(shape.wrapped), BrepErrorCode.SIMPLIFY_FAILED, "Failed to simplify shape");
|
|
654
694
|
}
|
|
655
695
|
//#endregion
|
|
656
|
-
export {
|
|
696
|
+
export { getFaceOrigins as A, getFaceColor as C, getTagMetadata as D, getFaceTags as E, setTagMetadata as O, colorShape as S, findFacesByTag as T, hasAnyMetadata as _, isSameShape as a, propagateMetadataThroughRelocation as b, applyMatrix as c, resize as d, rotate as f, collectInputFaceHashes as g, translate as h, isEqualShape as i, setShapeOrigin as j, tagFaces as k, composeTransforms as l, transformCopy as m, getHashCode as n, simplify as o, scale as p, isEmpty as r, toBREP as s, clone as t, mirror as u, propagateAllMetadata as v, getShapeColor as w, colorFaces as x, propagateMetadataByHash as y };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const require_shapeTypes = require("./shapeTypes-
|
|
1
|
+
const require_shapeTypes = require("./shapeTypes-BTTwjHy5.cjs");
|
|
2
2
|
const require_errors = require("./errors-CXJtc4I7.cjs");
|
|
3
|
-
const require_topologyQueryFns = require("./topologyQueryFns-
|
|
3
|
+
const require_topologyQueryFns = require("./topologyQueryFns-CoXVHuN7.cjs");
|
|
4
4
|
const require_constants = require("./constants-BOVyEYGH.cjs");
|
|
5
5
|
//#region src/topology/metadata/originTrackingFns.ts
|
|
6
6
|
/**
|
|
@@ -376,8 +376,16 @@ function propagateColorsFromEvolution(evolution, inputs, result) {
|
|
|
376
376
|
* Fast-path: returns empty array when no inputs have any metadata (origins,
|
|
377
377
|
* tags, or colors), avoiding expensive WASM topology exploration.
|
|
378
378
|
*/
|
|
379
|
+
/**
|
|
380
|
+
* O(1) check: does a shape carry any propagatable metadata (face origins,
|
|
381
|
+
* tags, or colors)? Lets callers skip both expensive face iteration and
|
|
382
|
+
* metadata-preserving slow paths when there's nothing to preserve.
|
|
383
|
+
*/
|
|
384
|
+
function hasAnyMetadata(shape) {
|
|
385
|
+
return getFaceOrigins(shape) !== void 0 || hasFaceTags(shape) || hasColorMetadata(shape);
|
|
386
|
+
}
|
|
379
387
|
function collectInputFaceHashes(inputs) {
|
|
380
|
-
if (!inputs.some(
|
|
388
|
+
if (!inputs.some(hasAnyMetadata)) return [];
|
|
381
389
|
const kernel = require_shapeTypes.getKernel();
|
|
382
390
|
const hashes = [];
|
|
383
391
|
for (const input of inputs) {
|
|
@@ -412,6 +420,38 @@ function propagateAllMetadata(evolution, inputs, result) {
|
|
|
412
420
|
function propagateMetadataByHash(inputs, result) {
|
|
413
421
|
propagateOriginsByHash(inputs, result);
|
|
414
422
|
}
|
|
423
|
+
/**
|
|
424
|
+
* Propagate all metadata through a *rigid relocation* (a `locate` re-tag).
|
|
425
|
+
*
|
|
426
|
+
* A relocated shape shares the source's TShape, so its faces correspond 1:1 to
|
|
427
|
+
* the source faces in iteration order — but carry new, location-dependent
|
|
428
|
+
* hashes, so the hash-keyed metadata must be re-keyed rather than left as-is.
|
|
429
|
+
* This synthesizes a 1:1 `modified` evolution (source face hash → moved face
|
|
430
|
+
* hash) and runs the standard propagation pipeline, so origins, tags, and
|
|
431
|
+
* colors all survive a move at `locate` cost (O(faces)), not a full copy.
|
|
432
|
+
*
|
|
433
|
+
* Callers should gate on {@link hasAnyMetadata} first: with no metadata this
|
|
434
|
+
* does pointless face iteration. The face counts always match for a rigid
|
|
435
|
+
* relocation; the length guard is purely defensive.
|
|
436
|
+
*/
|
|
437
|
+
function propagateMetadataThroughRelocation(source, moved) {
|
|
438
|
+
const kernel = require_shapeTypes.getKernel();
|
|
439
|
+
const srcFaces = [...kernel.iterShapes(source.wrapped, "face")];
|
|
440
|
+
const movedFaces = [...kernel.iterShapes(moved.wrapped, "face")];
|
|
441
|
+
if (srcFaces.length !== movedFaces.length) return;
|
|
442
|
+
const modified = /* @__PURE__ */ new Map();
|
|
443
|
+
for (let i = 0; i < srcFaces.length; i++) {
|
|
444
|
+
const sf = srcFaces[i];
|
|
445
|
+
const mf = movedFaces[i];
|
|
446
|
+
if (sf === void 0 || mf === void 0) continue;
|
|
447
|
+
modified.set(kernel.hashCode(sf, require_constants.HASH_CODE_MAX), [kernel.hashCode(mf, require_constants.HASH_CODE_MAX)]);
|
|
448
|
+
}
|
|
449
|
+
propagateAllMetadata({
|
|
450
|
+
modified,
|
|
451
|
+
generated: /* @__PURE__ */ new Map(),
|
|
452
|
+
deleted: /* @__PURE__ */ new Set()
|
|
453
|
+
}, [source], moved);
|
|
454
|
+
}
|
|
415
455
|
//#endregion
|
|
416
456
|
//#region src/topology/transformFns.ts
|
|
417
457
|
/**
|
|
@@ -731,6 +771,12 @@ Object.defineProperty(exports, "getTagMetadata", {
|
|
|
731
771
|
return getTagMetadata;
|
|
732
772
|
}
|
|
733
773
|
});
|
|
774
|
+
Object.defineProperty(exports, "hasAnyMetadata", {
|
|
775
|
+
enumerable: true,
|
|
776
|
+
get: function() {
|
|
777
|
+
return hasAnyMetadata;
|
|
778
|
+
}
|
|
779
|
+
});
|
|
734
780
|
Object.defineProperty(exports, "isEmpty", {
|
|
735
781
|
enumerable: true,
|
|
736
782
|
get: function() {
|
|
@@ -767,6 +813,12 @@ Object.defineProperty(exports, "propagateMetadataByHash", {
|
|
|
767
813
|
return propagateMetadataByHash;
|
|
768
814
|
}
|
|
769
815
|
});
|
|
816
|
+
Object.defineProperty(exports, "propagateMetadataThroughRelocation", {
|
|
817
|
+
enumerable: true,
|
|
818
|
+
get: function() {
|
|
819
|
+
return propagateMetadataThroughRelocation;
|
|
820
|
+
}
|
|
821
|
+
});
|
|
770
822
|
Object.defineProperty(exports, "resize", {
|
|
771
823
|
enumerable: true,
|
|
772
824
|
get: function() {
|
package/dist/shapeRef.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_shapeRefFns = require("./shapeRefFns-
|
|
2
|
+
const require_shapeRefFns = require("./shapeRefFns-CuepnFOm.cjs");
|
|
3
3
|
exports.assignRoles = require_shapeRefFns.assignRoles;
|
|
4
4
|
exports.captureHint = require_shapeRefFns.captureHint;
|
|
5
5
|
exports.createRef = require_shapeRefFns.createRef;
|
package/dist/shapeRef.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as updateRoles, i as resolveRef, n as captureHint, o as defaultScorer, r as createRef, t as assignRoles } from "./shapeRefFns-
|
|
1
|
+
import { a as updateRoles, i as resolveRef, n as captureHint, o as defaultScorer, r as createRef, t as assignRoles } from "./shapeRefFns-ChMnsOAF.js";
|
|
2
2
|
export { assignRoles, captureHint, createRef, defaultScorer, resolveRef, updateRoles };
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as
|
|
5
|
-
import { n as measureArea } from "./measureFns-Dkh_DmrE.js";
|
|
1
|
+
import { c as getFaces } from "./topologyQueryFns-BeKaWpNm.js";
|
|
2
|
+
import { i as faceGeomType, l as normalAt, r as faceCenter } from "./faceFns-B86WGqDg.js";
|
|
3
|
+
import { n as getHashCode } from "./shapeFns-DrZOVwHX.js";
|
|
4
|
+
import { n as measureArea } from "./measureFns-a5Vx25or.js";
|
|
6
5
|
//#region src/topology/shapeRef/scoring.ts
|
|
7
6
|
/**
|
|
8
7
|
* Default face scorer combining surface type, normal alignment, centroid proximity,
|
|
@@ -81,7 +80,8 @@ function boxRoleFromNormal(n) {
|
|
|
81
80
|
*
|
|
82
81
|
* For other types: sequential naming ('opType:face_0', 'opType:face_1', ...).
|
|
83
82
|
*
|
|
84
|
-
* @returns Map from role name to face hash
|
|
83
|
+
* @returns Map from role name to its face hash codes (one at assignment time;
|
|
84
|
+
* a role accrues more hashes only later, when `updateRoles` tracks a split).
|
|
85
85
|
*/
|
|
86
86
|
function assignRoles(shape, operationType) {
|
|
87
87
|
const faces = getFaces(shape);
|
|
@@ -89,13 +89,13 @@ function assignRoles(shape, operationType) {
|
|
|
89
89
|
if (operationType === "box") {
|
|
90
90
|
for (const face of faces) {
|
|
91
91
|
const role = boxRoleFromNormal(normalAt(face));
|
|
92
|
-
if (role !== void 0 && !roles.has(role)) roles.set(role, getHashCode(face));
|
|
92
|
+
if (role !== void 0 && !roles.has(role)) roles.set(role, [getHashCode(face)]);
|
|
93
93
|
}
|
|
94
94
|
return roles;
|
|
95
95
|
}
|
|
96
96
|
let index = 0;
|
|
97
97
|
for (const face of faces) {
|
|
98
|
-
roles.set(`${operationType}:face_${index}`, getHashCode(face));
|
|
98
|
+
roles.set(`${operationType}:face_${index}`, [getHashCode(face)]);
|
|
99
99
|
index++;
|
|
100
100
|
}
|
|
101
101
|
return roles;
|
|
@@ -109,31 +109,47 @@ function createRef(origin, role, face) {
|
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
|
+
* Advance a role's face hashes through one evolution: drop deleted faces,
|
|
113
|
+
* replace a modified face with *all* its successors (a 1→many split keeps every
|
|
114
|
+
* fragment), and keep unchanged faces. Deduped so a shared successor isn't
|
|
115
|
+
* doubled.
|
|
116
|
+
*/
|
|
117
|
+
function nextHashes(hashes, evolution) {
|
|
118
|
+
const successors = [];
|
|
119
|
+
for (const hash of hashes) {
|
|
120
|
+
if (evolution.deleted.has(hash)) continue;
|
|
121
|
+
const modified = evolution.modified.get(hash);
|
|
122
|
+
const targets = modified && modified.length > 0 ? modified : [hash];
|
|
123
|
+
for (const h of targets) if (!successors.includes(h)) successors.push(h);
|
|
124
|
+
}
|
|
125
|
+
return successors;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
112
128
|
* Propagate a role table through a ShapeEvolution record.
|
|
113
129
|
* Returns a new RoleTable with hashes updated according to the evolution.
|
|
114
130
|
*
|
|
115
|
-
* - Deleted faces: role removed
|
|
116
|
-
* - Modified faces: hash
|
|
117
|
-
*
|
|
131
|
+
* - Deleted faces: hash dropped (role removed once all its hashes are gone).
|
|
132
|
+
* - Modified faces: hash replaced by **all** successor hashes — so a 1→many
|
|
133
|
+
* split keeps every fragment, and `resolveRef` disambiguates among them.
|
|
134
|
+
* - Unchanged faces: hash preserved.
|
|
118
135
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
136
|
+
* Note: `evolution.generated` is intentionally not consumed here — on the OCCT
|
|
137
|
+
* kernels its hashes refer to an intermediate shape, not the final result, so
|
|
138
|
+
* naming generated faces produces roles that never resolve (verified: 0 live
|
|
139
|
+
* generated hashes across cut/fuse on occt-wasm). Stable names for generated
|
|
140
|
+
* geometry (fillet rounds, boolean seams) need history-fidelity work tracked
|
|
141
|
+
* separately.
|
|
123
142
|
*/
|
|
124
143
|
function updateRoles(roles, origin, evolution) {
|
|
125
144
|
const originRoles = roles.get(origin);
|
|
126
145
|
if (!originRoles) return roles;
|
|
127
146
|
const updatedOriginRoles = /* @__PURE__ */ new Map();
|
|
128
|
-
for (const [role,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (modifiedHashes && modifiedHashes.length > 0) updatedOriginRoles.set(role, wasmIndex(modifiedHashes, 0));
|
|
132
|
-
else updatedOriginRoles.set(role, hash);
|
|
147
|
+
for (const [role, hashes] of originRoles) {
|
|
148
|
+
const successors = nextHashes(hashes, evolution);
|
|
149
|
+
if (successors.length > 0) updatedOriginRoles.set(role, successors);
|
|
133
150
|
}
|
|
134
151
|
const newRoles = /* @__PURE__ */ new Map();
|
|
135
|
-
for (const [key, value] of roles)
|
|
136
|
-
else newRoles.set(key, value);
|
|
152
|
+
for (const [key, value] of roles) newRoles.set(key, key === origin ? updatedOriginRoles : value);
|
|
137
153
|
return newRoles;
|
|
138
154
|
}
|
|
139
155
|
/** Ambiguity threshold: if two scores are within this range, it's ambiguous. */
|
|
@@ -141,34 +157,19 @@ var AMBIGUITY_THRESHOLD = .1;
|
|
|
141
157
|
/** Minimum score for geometric fallback to accept a match. */
|
|
142
158
|
var MIN_SCORE = .5;
|
|
143
159
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* 3. Ambiguous if multiple faces score within threshold
|
|
150
|
-
* 4. Not-found if no match above minimum score
|
|
160
|
+
* Score `candidates` against `hint`, returning the best match, a tie within
|
|
161
|
+
* {@link AMBIGUITY_THRESHOLD}, or nothing above {@link MIN_SCORE}. Scoping the
|
|
162
|
+
* candidates to a role's tracked successors (rather than every face) is what
|
|
163
|
+
* makes split-face disambiguation reliable — the fragments compete only with
|
|
164
|
+
* each other, not with unrelated geometry.
|
|
151
165
|
*/
|
|
152
|
-
function
|
|
153
|
-
const faces = getFaces(currentShape);
|
|
154
|
-
const scoreFn = scorer ?? defaultScorer;
|
|
155
|
-
const targetHash = roles.get(ref.origin)?.get(ref.role);
|
|
156
|
-
if (targetHash !== void 0) {
|
|
157
|
-
for (const face of faces) if (getHashCode(face) === targetHash) return {
|
|
158
|
-
face,
|
|
159
|
-
confidence: "exact"
|
|
160
|
-
};
|
|
161
|
-
return {
|
|
162
|
-
ref,
|
|
163
|
-
reason: "deleted"
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
+
function scoreFaces(hint, candidates, scoreFn) {
|
|
166
167
|
let bestScore = -Infinity;
|
|
167
168
|
let bestFace;
|
|
168
169
|
let secondBestScore = -Infinity;
|
|
169
170
|
const scored = [];
|
|
170
|
-
for (const face of
|
|
171
|
-
const score = scoreFn(
|
|
171
|
+
for (const face of candidates) {
|
|
172
|
+
const score = scoreFn(hint, face);
|
|
172
173
|
if (score > MIN_SCORE) scored.push([face, score]);
|
|
173
174
|
if (score > bestScore) {
|
|
174
175
|
secondBestScore = bestScore;
|
|
@@ -178,15 +179,66 @@ function resolveRef(ref, roles, currentShape, scorer) {
|
|
|
178
179
|
}
|
|
179
180
|
if (bestFace !== void 0 && bestScore > MIN_SCORE) {
|
|
180
181
|
if (bestScore - secondBestScore < AMBIGUITY_THRESHOLD && scored.length > 1) return {
|
|
181
|
-
|
|
182
|
-
reason: "ambiguous",
|
|
182
|
+
kind: "ambiguous",
|
|
183
183
|
candidates: scored.filter(([, s]) => s >= bestScore - AMBIGUITY_THRESHOLD).map(([f]) => f)
|
|
184
184
|
};
|
|
185
185
|
return {
|
|
186
|
-
|
|
187
|
-
|
|
186
|
+
kind: "match",
|
|
187
|
+
face: bestFace
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
return { kind: "none" };
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Resolve a ShapeRef to a face in the current shape.
|
|
194
|
+
*
|
|
195
|
+
* Resolution strategy:
|
|
196
|
+
* 1. Exact: the role's tracked successor hashes. One survivor → exact match;
|
|
197
|
+
* several survivors (a face that split) → disambiguate among *only those*
|
|
198
|
+
* fragments; none survive → deleted.
|
|
199
|
+
* 2. Geometric fallback over the whole shape when the role isn't tracked (or a
|
|
200
|
+
* scoped score turned up nothing): best-scoring face, else ambiguous /
|
|
201
|
+
* not-found.
|
|
202
|
+
*/
|
|
203
|
+
function resolveRef(ref, roles, currentShape, scorer) {
|
|
204
|
+
const faces = getFaces(currentShape);
|
|
205
|
+
const scoreFn = scorer ?? defaultScorer;
|
|
206
|
+
const targetHashes = roles.get(ref.origin)?.get(ref.role);
|
|
207
|
+
if (targetHashes !== void 0 && targetHashes.length > 0) {
|
|
208
|
+
const survivors = faces.filter((f) => targetHashes.includes(getHashCode(f)));
|
|
209
|
+
if (survivors.length === 1) {
|
|
210
|
+
const [only] = survivors;
|
|
211
|
+
if (only !== void 0) return {
|
|
212
|
+
face: only,
|
|
213
|
+
confidence: "exact"
|
|
214
|
+
};
|
|
215
|
+
} else if (survivors.length === 0) return {
|
|
216
|
+
ref,
|
|
217
|
+
reason: "deleted"
|
|
188
218
|
};
|
|
219
|
+
else {
|
|
220
|
+
const outcome = scoreFaces(ref.hint, survivors, scoreFn);
|
|
221
|
+
if (outcome.kind === "match") return {
|
|
222
|
+
face: outcome.face,
|
|
223
|
+
confidence: "geometric-fallback"
|
|
224
|
+
};
|
|
225
|
+
if (outcome.kind === "ambiguous") return {
|
|
226
|
+
ref,
|
|
227
|
+
reason: "ambiguous",
|
|
228
|
+
candidates: outcome.candidates
|
|
229
|
+
};
|
|
230
|
+
}
|
|
189
231
|
}
|
|
232
|
+
const outcome = scoreFaces(ref.hint, faces, scoreFn);
|
|
233
|
+
if (outcome.kind === "match") return {
|
|
234
|
+
face: outcome.face,
|
|
235
|
+
confidence: "geometric-fallback"
|
|
236
|
+
};
|
|
237
|
+
if (outcome.kind === "ambiguous") return {
|
|
238
|
+
ref,
|
|
239
|
+
reason: "ambiguous",
|
|
240
|
+
candidates: outcome.candidates
|
|
241
|
+
};
|
|
190
242
|
return {
|
|
191
243
|
ref,
|
|
192
244
|
reason: "not-found"
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const require_measureFns = require("./measureFns-Q2dnokUU.cjs");
|
|
1
|
+
const require_topologyQueryFns = require("./topologyQueryFns-CoXVHuN7.cjs");
|
|
2
|
+
const require_faceFns = require("./faceFns-BV0GnTlt.cjs");
|
|
3
|
+
const require_shapeFns = require("./shapeFns-ybo0INGL.cjs");
|
|
4
|
+
const require_measureFns = require("./measureFns-DblG0Yaz.cjs");
|
|
6
5
|
//#region src/topology/shapeRef/scoring.ts
|
|
7
6
|
/**
|
|
8
7
|
* Default face scorer combining surface type, normal alignment, centroid proximity,
|
|
@@ -81,7 +80,8 @@ function boxRoleFromNormal(n) {
|
|
|
81
80
|
*
|
|
82
81
|
* For other types: sequential naming ('opType:face_0', 'opType:face_1', ...).
|
|
83
82
|
*
|
|
84
|
-
* @returns Map from role name to face hash
|
|
83
|
+
* @returns Map from role name to its face hash codes (one at assignment time;
|
|
84
|
+
* a role accrues more hashes only later, when `updateRoles` tracks a split).
|
|
85
85
|
*/
|
|
86
86
|
function assignRoles(shape, operationType) {
|
|
87
87
|
const faces = require_topologyQueryFns.getFaces(shape);
|
|
@@ -89,13 +89,13 @@ function assignRoles(shape, operationType) {
|
|
|
89
89
|
if (operationType === "box") {
|
|
90
90
|
for (const face of faces) {
|
|
91
91
|
const role = boxRoleFromNormal(require_faceFns.normalAt(face));
|
|
92
|
-
if (role !== void 0 && !roles.has(role)) roles.set(role, require_shapeFns.getHashCode(face));
|
|
92
|
+
if (role !== void 0 && !roles.has(role)) roles.set(role, [require_shapeFns.getHashCode(face)]);
|
|
93
93
|
}
|
|
94
94
|
return roles;
|
|
95
95
|
}
|
|
96
96
|
let index = 0;
|
|
97
97
|
for (const face of faces) {
|
|
98
|
-
roles.set(`${operationType}:face_${index}`, require_shapeFns.getHashCode(face));
|
|
98
|
+
roles.set(`${operationType}:face_${index}`, [require_shapeFns.getHashCode(face)]);
|
|
99
99
|
index++;
|
|
100
100
|
}
|
|
101
101
|
return roles;
|
|
@@ -109,31 +109,47 @@ function createRef(origin, role, face) {
|
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
|
+
* Advance a role's face hashes through one evolution: drop deleted faces,
|
|
113
|
+
* replace a modified face with *all* its successors (a 1→many split keeps every
|
|
114
|
+
* fragment), and keep unchanged faces. Deduped so a shared successor isn't
|
|
115
|
+
* doubled.
|
|
116
|
+
*/
|
|
117
|
+
function nextHashes(hashes, evolution) {
|
|
118
|
+
const successors = [];
|
|
119
|
+
for (const hash of hashes) {
|
|
120
|
+
if (evolution.deleted.has(hash)) continue;
|
|
121
|
+
const modified = evolution.modified.get(hash);
|
|
122
|
+
const targets = modified && modified.length > 0 ? modified : [hash];
|
|
123
|
+
for (const h of targets) if (!successors.includes(h)) successors.push(h);
|
|
124
|
+
}
|
|
125
|
+
return successors;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
112
128
|
* Propagate a role table through a ShapeEvolution record.
|
|
113
129
|
* Returns a new RoleTable with hashes updated according to the evolution.
|
|
114
130
|
*
|
|
115
|
-
* - Deleted faces: role removed
|
|
116
|
-
* - Modified faces: hash
|
|
117
|
-
*
|
|
131
|
+
* - Deleted faces: hash dropped (role removed once all its hashes are gone).
|
|
132
|
+
* - Modified faces: hash replaced by **all** successor hashes — so a 1→many
|
|
133
|
+
* split keeps every fragment, and `resolveRef` disambiguates among them.
|
|
134
|
+
* - Unchanged faces: hash preserved.
|
|
118
135
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
136
|
+
* Note: `evolution.generated` is intentionally not consumed here — on the OCCT
|
|
137
|
+
* kernels its hashes refer to an intermediate shape, not the final result, so
|
|
138
|
+
* naming generated faces produces roles that never resolve (verified: 0 live
|
|
139
|
+
* generated hashes across cut/fuse on occt-wasm). Stable names for generated
|
|
140
|
+
* geometry (fillet rounds, boolean seams) need history-fidelity work tracked
|
|
141
|
+
* separately.
|
|
123
142
|
*/
|
|
124
143
|
function updateRoles(roles, origin, evolution) {
|
|
125
144
|
const originRoles = roles.get(origin);
|
|
126
145
|
if (!originRoles) return roles;
|
|
127
146
|
const updatedOriginRoles = /* @__PURE__ */ new Map();
|
|
128
|
-
for (const [role,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (modifiedHashes && modifiedHashes.length > 0) updatedOriginRoles.set(role, require_vec3.wasmIndex(modifiedHashes, 0));
|
|
132
|
-
else updatedOriginRoles.set(role, hash);
|
|
147
|
+
for (const [role, hashes] of originRoles) {
|
|
148
|
+
const successors = nextHashes(hashes, evolution);
|
|
149
|
+
if (successors.length > 0) updatedOriginRoles.set(role, successors);
|
|
133
150
|
}
|
|
134
151
|
const newRoles = /* @__PURE__ */ new Map();
|
|
135
|
-
for (const [key, value] of roles)
|
|
136
|
-
else newRoles.set(key, value);
|
|
152
|
+
for (const [key, value] of roles) newRoles.set(key, key === origin ? updatedOriginRoles : value);
|
|
137
153
|
return newRoles;
|
|
138
154
|
}
|
|
139
155
|
/** Ambiguity threshold: if two scores are within this range, it's ambiguous. */
|
|
@@ -141,34 +157,19 @@ var AMBIGUITY_THRESHOLD = .1;
|
|
|
141
157
|
/** Minimum score for geometric fallback to accept a match. */
|
|
142
158
|
var MIN_SCORE = .5;
|
|
143
159
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* 3. Ambiguous if multiple faces score within threshold
|
|
150
|
-
* 4. Not-found if no match above minimum score
|
|
160
|
+
* Score `candidates` against `hint`, returning the best match, a tie within
|
|
161
|
+
* {@link AMBIGUITY_THRESHOLD}, or nothing above {@link MIN_SCORE}. Scoping the
|
|
162
|
+
* candidates to a role's tracked successors (rather than every face) is what
|
|
163
|
+
* makes split-face disambiguation reliable — the fragments compete only with
|
|
164
|
+
* each other, not with unrelated geometry.
|
|
151
165
|
*/
|
|
152
|
-
function
|
|
153
|
-
const faces = require_topologyQueryFns.getFaces(currentShape);
|
|
154
|
-
const scoreFn = scorer ?? defaultScorer;
|
|
155
|
-
const targetHash = roles.get(ref.origin)?.get(ref.role);
|
|
156
|
-
if (targetHash !== void 0) {
|
|
157
|
-
for (const face of faces) if (require_shapeFns.getHashCode(face) === targetHash) return {
|
|
158
|
-
face,
|
|
159
|
-
confidence: "exact"
|
|
160
|
-
};
|
|
161
|
-
return {
|
|
162
|
-
ref,
|
|
163
|
-
reason: "deleted"
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
+
function scoreFaces(hint, candidates, scoreFn) {
|
|
166
167
|
let bestScore = -Infinity;
|
|
167
168
|
let bestFace;
|
|
168
169
|
let secondBestScore = -Infinity;
|
|
169
170
|
const scored = [];
|
|
170
|
-
for (const face of
|
|
171
|
-
const score = scoreFn(
|
|
171
|
+
for (const face of candidates) {
|
|
172
|
+
const score = scoreFn(hint, face);
|
|
172
173
|
if (score > MIN_SCORE) scored.push([face, score]);
|
|
173
174
|
if (score > bestScore) {
|
|
174
175
|
secondBestScore = bestScore;
|
|
@@ -178,15 +179,66 @@ function resolveRef(ref, roles, currentShape, scorer) {
|
|
|
178
179
|
}
|
|
179
180
|
if (bestFace !== void 0 && bestScore > MIN_SCORE) {
|
|
180
181
|
if (bestScore - secondBestScore < AMBIGUITY_THRESHOLD && scored.length > 1) return {
|
|
181
|
-
|
|
182
|
-
reason: "ambiguous",
|
|
182
|
+
kind: "ambiguous",
|
|
183
183
|
candidates: scored.filter(([, s]) => s >= bestScore - AMBIGUITY_THRESHOLD).map(([f]) => f)
|
|
184
184
|
};
|
|
185
185
|
return {
|
|
186
|
-
|
|
187
|
-
|
|
186
|
+
kind: "match",
|
|
187
|
+
face: bestFace
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
return { kind: "none" };
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Resolve a ShapeRef to a face in the current shape.
|
|
194
|
+
*
|
|
195
|
+
* Resolution strategy:
|
|
196
|
+
* 1. Exact: the role's tracked successor hashes. One survivor → exact match;
|
|
197
|
+
* several survivors (a face that split) → disambiguate among *only those*
|
|
198
|
+
* fragments; none survive → deleted.
|
|
199
|
+
* 2. Geometric fallback over the whole shape when the role isn't tracked (or a
|
|
200
|
+
* scoped score turned up nothing): best-scoring face, else ambiguous /
|
|
201
|
+
* not-found.
|
|
202
|
+
*/
|
|
203
|
+
function resolveRef(ref, roles, currentShape, scorer) {
|
|
204
|
+
const faces = require_topologyQueryFns.getFaces(currentShape);
|
|
205
|
+
const scoreFn = scorer ?? defaultScorer;
|
|
206
|
+
const targetHashes = roles.get(ref.origin)?.get(ref.role);
|
|
207
|
+
if (targetHashes !== void 0 && targetHashes.length > 0) {
|
|
208
|
+
const survivors = faces.filter((f) => targetHashes.includes(require_shapeFns.getHashCode(f)));
|
|
209
|
+
if (survivors.length === 1) {
|
|
210
|
+
const [only] = survivors;
|
|
211
|
+
if (only !== void 0) return {
|
|
212
|
+
face: only,
|
|
213
|
+
confidence: "exact"
|
|
214
|
+
};
|
|
215
|
+
} else if (survivors.length === 0) return {
|
|
216
|
+
ref,
|
|
217
|
+
reason: "deleted"
|
|
188
218
|
};
|
|
219
|
+
else {
|
|
220
|
+
const outcome = scoreFaces(ref.hint, survivors, scoreFn);
|
|
221
|
+
if (outcome.kind === "match") return {
|
|
222
|
+
face: outcome.face,
|
|
223
|
+
confidence: "geometric-fallback"
|
|
224
|
+
};
|
|
225
|
+
if (outcome.kind === "ambiguous") return {
|
|
226
|
+
ref,
|
|
227
|
+
reason: "ambiguous",
|
|
228
|
+
candidates: outcome.candidates
|
|
229
|
+
};
|
|
230
|
+
}
|
|
189
231
|
}
|
|
232
|
+
const outcome = scoreFaces(ref.hint, faces, scoreFn);
|
|
233
|
+
if (outcome.kind === "match") return {
|
|
234
|
+
face: outcome.face,
|
|
235
|
+
confidence: "geometric-fallback"
|
|
236
|
+
};
|
|
237
|
+
if (outcome.kind === "ambiguous") return {
|
|
238
|
+
ref,
|
|
239
|
+
reason: "ambiguous",
|
|
240
|
+
candidates: outcome.candidates
|
|
241
|
+
};
|
|
190
242
|
return {
|
|
191
243
|
ref,
|
|
192
244
|
reason: "not-found"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_occtWasmAdapter = require("./occtWasmAdapter-
|
|
1
|
+
const require_occtWasmAdapter = require("./occtWasmAdapter-B2TEQOjs.cjs");
|
|
2
2
|
const require_vec3 = require("./vec3-CFwOI0ZI.cjs");
|
|
3
3
|
const require_errors = require("./errors-CXJtc4I7.cjs");
|
|
4
4
|
//#region src/kernel/quality.ts
|
|
@@ -2215,6 +2215,20 @@ function transform$3(oc, shape, trsf) {
|
|
|
2215
2215
|
return result;
|
|
2216
2216
|
}
|
|
2217
2217
|
/**
|
|
2218
|
+
* Apply a rigid transform as a location re-tag. Passing copy=false makes
|
|
2219
|
+
* BRepBuilderAPI_Transform share the source TShape under a new location for a
|
|
2220
|
+
* rigid motion, instead of the deep topology copy {@link transform} (copy=true)
|
|
2221
|
+
* performs. Use only for rigid `trsf` (rotation + translation).
|
|
2222
|
+
*/
|
|
2223
|
+
function locate(oc, shape, trsf) {
|
|
2224
|
+
const transformer = new oc.BRepBuilderAPI_Transform_2(shape, trsf, false, false);
|
|
2225
|
+
try {
|
|
2226
|
+
return transformer.ModifiedShape(shape);
|
|
2227
|
+
} finally {
|
|
2228
|
+
transformer.delete();
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
/**
|
|
2218
2232
|
* Translates a shape by the given offset.
|
|
2219
2233
|
*/
|
|
2220
2234
|
function translate$2(oc, shape, x, y, z) {
|
|
@@ -2322,6 +2336,7 @@ function simplify$2(oc, shape) {
|
|
|
2322
2336
|
function makeTransformOps$2(oc) {
|
|
2323
2337
|
return {
|
|
2324
2338
|
transform: (shape, trsf) => transform$3(oc, shape, trsf),
|
|
2339
|
+
locate: (shape, trsf) => locate(oc, shape, trsf),
|
|
2325
2340
|
translate: (shape, x, y, z) => translate$2(oc, shape, x, y, z),
|
|
2326
2341
|
rotate: (shape, angle, axis, center) => rotate$2(oc, shape, angle, axis, center),
|
|
2327
2342
|
mirror: (shape, origin, normal) => mirror$2(oc, shape, origin, normal),
|
|
@@ -6250,6 +6265,7 @@ function transformBatch$1(bk, entries) {
|
|
|
6250
6265
|
function makeTransformOps$1(bk) {
|
|
6251
6266
|
return {
|
|
6252
6267
|
transform: (shape, trsf) => transform$2(bk, shape, trsf),
|
|
6268
|
+
locate: (shape, trsf) => transform$2(bk, shape, trsf),
|
|
6253
6269
|
translate: (shape, x, y, z) => translate$1(bk, shape, x, y, z),
|
|
6254
6270
|
rotate: (shape, angle, axis, center) => rotate$1(bk, shape, angle, axis, center),
|
|
6255
6271
|
mirror: (shape, origin, normal) => mirror$1(bk, shape, origin, normal),
|
|
@@ -10492,6 +10508,7 @@ function makeTransformOps(module) {
|
|
|
10492
10508
|
return {
|
|
10493
10509
|
composeTransform,
|
|
10494
10510
|
transform: transform$1,
|
|
10511
|
+
locate: transform$1,
|
|
10495
10512
|
translate,
|
|
10496
10513
|
rotate,
|
|
10497
10514
|
mirror,
|