brepjs 18.116.0 → 18.116.1

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
@@ -17,7 +17,7 @@ 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
19
  const require_healingFns = require("./healingFns-xLJ6Cp_O.cjs");
20
- const require_threadFns = require("./threadFns-KrG_i9_w.cjs");
20
+ const require_threadFns = require("./threadFns-BqWHWpea.cjs");
21
21
  const require_blueprintSketcher = require("./blueprintSketcher-RK-cH6ps.cjs");
22
22
  const require_helpers = require("./helpers-BSLPCflF.cjs");
23
23
  const require_drawFns = require("./drawFns-DNxs7PAT.cjs");
@@ -5837,48 +5837,144 @@ function cacheKey(node, env, kernelId, tolerance) {
5837
5837
  const tolHash = tolerance === void 0 ? "d" : fnvMixNumber(fnvInit(), tolerance).toString(16);
5838
5838
  return `${toHex(node.structuralHash)}:${kernelId}:${toHex(projHash)}:${tolHash}`;
5839
5839
  }
5840
+ var IDENTITY_QUAT = [
5841
+ 1,
5842
+ 0,
5843
+ 0,
5844
+ 0
5845
+ ];
5846
+ /** Resolve a Rotate node's angle/axis/center in `env`, applying the same
5847
+ * defaults as the evaluator (Z axis, origin pivot). Null if any free param
5848
+ * can't be evaluated, so the caller stops peeling there. */
5849
+ function evalRotateParams(node, env) {
5850
+ const a = evalScalar(node.angle, env, "evaluateMesh.peelRigid");
5851
+ if (!a.ok) return null;
5852
+ const axis = node.axis ? evalVec3(node.axis, env, "evaluateMesh.peelRigid") : require_errors.ok([
5853
+ 0,
5854
+ 0,
5855
+ 1
5856
+ ]);
5857
+ if (!axis.ok) return null;
5858
+ const center = node.at ? evalVec3(node.at, env, "evaluateMesh.peelRigid") : require_errors.ok([
5859
+ 0,
5860
+ 0,
5861
+ 0
5862
+ ]);
5863
+ if (!center.ok) return null;
5864
+ return {
5865
+ angle: a.value,
5866
+ axis: axis.value,
5867
+ center: center.value
5868
+ };
5869
+ }
5840
5870
  /**
5841
- * Peel outer Translate nodes off `node`, accumulating their env-evaluated
5842
- * offsets. Pure translations compose by addition, so the inner geometry is
5843
- * placement-independent: it meshes once and the cached mesh is shifted per
5844
- * placement instead of re-tessellating. Stops at the first non-Translate node
5845
- * (or one whose offset can't be evaluated in `env`).
5871
+ * Peel outer rigid-motion nodes (Translate / Rotate) off `node`, composing them
5872
+ * into a single rotation + translation. A rigid motion shares its inner
5873
+ * geometry's tessellation the shape path re-tags it via `locate` (#1633) — so
5874
+ * the inner meshes once and the cached mesh is moved per placement instead of
5875
+ * re-tessellating. Stops at the first non-rigid node (Scale/Mirror/boolean/…) or
5876
+ * one whose parameters can't be evaluated in `env`.
5877
+ *
5878
+ * Composition is outer∘inner: peeling outward, each node's local transform acts
5879
+ * on points the inner nodes already placed, so it post-multiplies the
5880
+ * accumulator. A pure-translation chain keeps the identity rotation, so the mesh
5881
+ * move below degenerates to the exact vertex-shift fast path (normals untouched).
5846
5882
  */
5847
- function peelTranslate(node, env) {
5883
+ function peelRigid(node, env) {
5848
5884
  let inner = node;
5849
- let ox = 0;
5850
- let oy = 0;
5851
- let oz = 0;
5852
- while (inner.kind === "Translate") {
5853
- const v = evalVec3(inner.vector, env, "evaluateMesh.peelTranslate");
5885
+ let rot = IDENTITY_QUAT;
5886
+ let trans = [
5887
+ 0,
5888
+ 0,
5889
+ 0
5890
+ ];
5891
+ for (;;) if (inner.kind === "Translate") {
5892
+ const v = evalVec3(inner.vector, env, "evaluateMesh.peelRigid");
5854
5893
  if (!v.ok) break;
5855
- ox += v.value[0];
5856
- oy += v.value[1];
5857
- oz += v.value[2];
5894
+ const rv = require_threadFns.quatRotate(rot, v.value);
5895
+ trans = [
5896
+ trans[0] + rv[0],
5897
+ trans[1] + rv[1],
5898
+ trans[2] + rv[2]
5899
+ ];
5858
5900
  inner = inner.target;
5859
- }
5901
+ } else if (inner.kind === "Rotate") {
5902
+ const p = evalRotateParams(inner, env);
5903
+ if (!p) break;
5904
+ const r = require_threadFns.quatFromAxisAngle(p.axis, p.angle * Math.PI / 180);
5905
+ const newRot = require_threadFns.quatMultiply(rot, r);
5906
+ const rotC = require_threadFns.quatRotate(rot, p.center);
5907
+ const newRotC = require_threadFns.quatRotate(newRot, p.center);
5908
+ trans = [
5909
+ trans[0] + rotC[0] - newRotC[0],
5910
+ trans[1] + rotC[1] - newRotC[1],
5911
+ trans[2] + rotC[2] - newRotC[2]
5912
+ ];
5913
+ rot = newRot;
5914
+ inner = inner.target;
5915
+ } else break;
5860
5916
  return {
5861
5917
  inner,
5862
- offset: [
5863
- ox,
5864
- oy,
5865
- oz
5866
- ]
5918
+ rot,
5919
+ trans
5867
5920
  };
5868
5921
  }
5869
- /** Shift every vertex of a mesh by `offset`; normals, UVs and triangles are unchanged. */
5870
- function translateMesh(m, offset) {
5871
- const [dx, dy, dz] = offset;
5872
- if (dx === 0 && dy === 0 && dz === 0) return m;
5873
- const vertices = new Float32Array(m.vertices.length);
5874
- for (let i = 0; i < m.vertices.length; i += 3) {
5875
- vertices[i] = (m.vertices[i] ?? 0) + dx;
5876
- vertices[i + 1] = (m.vertices[i + 1] ?? 0) + dy;
5877
- vertices[i + 2] = (m.vertices[i + 2] ?? 0) + dz;
5922
+ function isIdentityQuat(q) {
5923
+ return q[0] === 1 && q[1] === 0 && q[2] === 0 && q[3] === 0;
5924
+ }
5925
+ /**
5926
+ * Write `src` (flat xyz) rigidly transformed by quaternion (qw,qx,qy,qz) then
5927
+ * translation (tx,ty,tz) into `dst`. The quaternion-rotate math is inlined with
5928
+ * scalar locals no per-vertex array allocation — because this runs once per
5929
+ * mesh vertex/normal and helper-allocated vector math regressed the gridfinity
5930
+ * benchmark 17% (see `utils/vec3.ts`). Pass zero translation for normals.
5931
+ */
5932
+ function rotateXyzBuffer(dst, src, qw, qx, qy, qz, tx, ty, tz) {
5933
+ for (let i = 0; i < src.length; i += 3) {
5934
+ const vx = src[i] ?? 0;
5935
+ const vy = src[i + 1] ?? 0;
5936
+ const vz = src[i + 2] ?? 0;
5937
+ const cx = 2 * (qy * vz - qz * vy);
5938
+ const cy = 2 * (qz * vx - qx * vz);
5939
+ const cz = 2 * (qx * vy - qy * vx);
5940
+ dst[i] = vx + qw * cx + (qy * cz - qz * cy) + tx;
5941
+ dst[i + 1] = vy + qw * cy + (qz * cx - qx * cz) + ty;
5942
+ dst[i + 2] = vz + qw * cz + (qx * cy - qy * cx) + tz;
5878
5943
  }
5944
+ }
5945
+ /**
5946
+ * Apply a rigid motion to a mesh: vertices get the rotation then translation,
5947
+ * normals get the rotation only (a unit rotation preserves length, so no
5948
+ * renormalization). UVs and triangles are motion-invariant. A pure translation
5949
+ * (identity rotation) keeps the source normals array by reference and only
5950
+ * shifts vertices — the exact previous translation-only fast path.
5951
+ */
5952
+ function transformMeshRigid(m, rot, trans) {
5953
+ const [tx, ty, tz] = trans;
5954
+ const pureTranslation = isIdentityQuat(rot);
5955
+ if (pureTranslation && tx === 0 && ty === 0 && tz === 0) return m;
5956
+ const src = m.vertices;
5957
+ const vertices = new Float32Array(src.length);
5958
+ if (pureTranslation) {
5959
+ for (let i = 0; i < src.length; i += 3) {
5960
+ vertices[i] = (src[i] ?? 0) + tx;
5961
+ vertices[i + 1] = (src[i + 1] ?? 0) + ty;
5962
+ vertices[i + 2] = (src[i + 2] ?? 0) + tz;
5963
+ }
5964
+ return {
5965
+ ...m,
5966
+ vertices
5967
+ };
5968
+ }
5969
+ const [qw, qx, qy, qz] = rot;
5970
+ rotateXyzBuffer(vertices, src, qw, qx, qy, qz, tx, ty, tz);
5971
+ const sn = m.normals;
5972
+ const normals = new Float32Array(sn.length);
5973
+ rotateXyzBuffer(normals, sn, qw, qx, qy, qz, 0, 0, 0);
5879
5974
  return {
5880
5975
  ...m,
5881
- vertices
5976
+ vertices,
5977
+ normals
5882
5978
  };
5883
5979
  }
5884
5980
  /**
@@ -5886,8 +5982,8 @@ function translateMesh(m, offset) {
5886
5982
  * moved faces location-dependent hashes, so the inner mesh's `faceId`s describe
5887
5983
  * the *unplaced* shape; remap them to the placed faces (1:1 by iteration order,
5888
5984
  * since `locate` shares the source TShape) so face picking and metadata lookup
5889
- * resolve against the placed mesh. Origins are translation-invariant, so only
5890
- * `faceId` changes.
5985
+ * resolve against the placed mesh. Origins are boolean-lineage tags, invariant
5986
+ * under any rigid motion, so only `faceId` changes.
5891
5987
  *
5892
5988
  * Takes pre-captured hash arrays (not shapes): a bounded shape cache can evict
5893
5989
  * and dispose one shape while the other is being evaluated, so the caller reads
@@ -5983,7 +6079,7 @@ var Evaluator = class {
5983
6079
  }
5984
6080
  return require_errors.ok(cached);
5985
6081
  }
5986
- const { inner, offset } = peelTranslate(node, env);
6082
+ const { inner, rot, trans } = peelRigid(node, env);
5987
6083
  if (inner !== node) {
5988
6084
  const innerMesh = this.evaluateMesh(inner, env, meshOpts);
5989
6085
  if (!innerMesh.ok) return innerMesh;
@@ -5993,7 +6089,7 @@ var Evaluator = class {
5993
6089
  const placedShape = this.evaluate(node, env);
5994
6090
  if (!placedShape.ok) return placedShape;
5995
6091
  const placedHashes = require_topologyQueryFns.getFaces(placedShape.value).map(require_shapeFns.getHashCode);
5996
- const moved = translateMesh(innerMesh.value, offset);
6092
+ const moved = transformMeshRigid(innerMesh.value, rot, trans);
5997
6093
  const faceGroups = relocateFaceGroups(moved.faceGroups, innerHashes, placedHashes);
5998
6094
  const placedSet = new Set(placedHashes);
5999
6095
  if (faceGroups.every((g) => placedSet.has(g.faceId))) {
package/dist/brepjs.js CHANGED
@@ -15,7 +15,7 @@ import { n as getAtOrThrow, r as lastOrThrow, t as firstOrThrow } from "./arrayA
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
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
17
  import { A as toBufferGeometryData, C as shellWithEvolution, D as getNurbsCurveData, E as fuseAllBisect, M as toLODGeometryData, N as toLODGeometryLevels, O as getNurbsSurfaceData, P as toLineGeometryData, 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 toGroupedBufferGeometryData, k as chamferDistAngle, 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 } from "./healingFns-2TJHHDg5.js";
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-Dgr2qyJv.js";
18
+ import { A as setJointValue, B as createAssemblyNode, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, F as quatMultiply, G as circularPattern, H as removeChild, I as quatRotate, J as exportAssemblySTEP, K as gridPattern, L as addChild, M as sphericalJoint, N as quatFromAxisAngle, O as prismaticJoint, P as quatFromTo, R as collectShapes, S as addJoint, T as jointTransform, U as updateNode, V as findNode, W as walkAssembly, Y as createAssembly, _ 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 linearPattern, 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 countNodes } from "./threadFns-KbYZu7Q9.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";
21
21
  import { A as sketchEllipse, D as makeBaseBox, E as deserializeDrawing, F as sketchRectangle, I as sketchRoundedRectangle, L as FaceSketcher, M as sketchHelix, N as sketchParametricFunction, O as polysideInnerRadius, P as sketchPolysides, R as Sketcher, S as drawText, _ as drawPolysides, a as drawingIntersect, b as drawSingleCircle, c as rotateDrawing, d as drawFaceOutline, f as drawProjection, g as drawPointsInterpolation, h as drawParametricFunction, i as drawingFuse, j as sketchFaceOffset, k as sketchCircle, l as scaleDrawing, m as drawEllipse, n as drawingCut, o as drawingToSketchOnPlane, p as drawCircle, r as drawingFillet, s as mirrorDrawing, t as drawingChamfer, u as translateDrawing, v as drawRectangle, w as draw, x as drawSingleEllipse, y as drawRoundedRectangle } from "./drawFns-SQIBls6p.js";
@@ -5840,48 +5840,144 @@ function cacheKey(node, env, kernelId, tolerance) {
5840
5840
  const tolHash = tolerance === void 0 ? "d" : fnvMixNumber(fnvInit(), tolerance).toString(16);
5841
5841
  return `${toHex(node.structuralHash)}:${kernelId}:${toHex(projHash)}:${tolHash}`;
5842
5842
  }
5843
+ var IDENTITY_QUAT = [
5844
+ 1,
5845
+ 0,
5846
+ 0,
5847
+ 0
5848
+ ];
5849
+ /** Resolve a Rotate node's angle/axis/center in `env`, applying the same
5850
+ * defaults as the evaluator (Z axis, origin pivot). Null if any free param
5851
+ * can't be evaluated, so the caller stops peeling there. */
5852
+ function evalRotateParams(node, env) {
5853
+ const a = evalScalar(node.angle, env, "evaluateMesh.peelRigid");
5854
+ if (!a.ok) return null;
5855
+ const axis = node.axis ? evalVec3(node.axis, env, "evaluateMesh.peelRigid") : ok([
5856
+ 0,
5857
+ 0,
5858
+ 1
5859
+ ]);
5860
+ if (!axis.ok) return null;
5861
+ const center = node.at ? evalVec3(node.at, env, "evaluateMesh.peelRigid") : ok([
5862
+ 0,
5863
+ 0,
5864
+ 0
5865
+ ]);
5866
+ if (!center.ok) return null;
5867
+ return {
5868
+ angle: a.value,
5869
+ axis: axis.value,
5870
+ center: center.value
5871
+ };
5872
+ }
5843
5873
  /**
5844
- * Peel outer Translate nodes off `node`, accumulating their env-evaluated
5845
- * offsets. Pure translations compose by addition, so the inner geometry is
5846
- * placement-independent: it meshes once and the cached mesh is shifted per
5847
- * placement instead of re-tessellating. Stops at the first non-Translate node
5848
- * (or one whose offset can't be evaluated in `env`).
5874
+ * Peel outer rigid-motion nodes (Translate / Rotate) off `node`, composing them
5875
+ * into a single rotation + translation. A rigid motion shares its inner
5876
+ * geometry's tessellation the shape path re-tags it via `locate` (#1633) — so
5877
+ * the inner meshes once and the cached mesh is moved per placement instead of
5878
+ * re-tessellating. Stops at the first non-rigid node (Scale/Mirror/boolean/…) or
5879
+ * one whose parameters can't be evaluated in `env`.
5880
+ *
5881
+ * Composition is outer∘inner: peeling outward, each node's local transform acts
5882
+ * on points the inner nodes already placed, so it post-multiplies the
5883
+ * accumulator. A pure-translation chain keeps the identity rotation, so the mesh
5884
+ * move below degenerates to the exact vertex-shift fast path (normals untouched).
5849
5885
  */
5850
- function peelTranslate(node, env) {
5886
+ function peelRigid(node, env) {
5851
5887
  let inner = node;
5852
- let ox = 0;
5853
- let oy = 0;
5854
- let oz = 0;
5855
- while (inner.kind === "Translate") {
5856
- const v = evalVec3(inner.vector, env, "evaluateMesh.peelTranslate");
5888
+ let rot = IDENTITY_QUAT;
5889
+ let trans = [
5890
+ 0,
5891
+ 0,
5892
+ 0
5893
+ ];
5894
+ for (;;) if (inner.kind === "Translate") {
5895
+ const v = evalVec3(inner.vector, env, "evaluateMesh.peelRigid");
5857
5896
  if (!v.ok) break;
5858
- ox += v.value[0];
5859
- oy += v.value[1];
5860
- oz += v.value[2];
5897
+ const rv = quatRotate(rot, v.value);
5898
+ trans = [
5899
+ trans[0] + rv[0],
5900
+ trans[1] + rv[1],
5901
+ trans[2] + rv[2]
5902
+ ];
5861
5903
  inner = inner.target;
5862
- }
5904
+ } else if (inner.kind === "Rotate") {
5905
+ const p = evalRotateParams(inner, env);
5906
+ if (!p) break;
5907
+ const r = quatFromAxisAngle(p.axis, p.angle * Math.PI / 180);
5908
+ const newRot = quatMultiply(rot, r);
5909
+ const rotC = quatRotate(rot, p.center);
5910
+ const newRotC = quatRotate(newRot, p.center);
5911
+ trans = [
5912
+ trans[0] + rotC[0] - newRotC[0],
5913
+ trans[1] + rotC[1] - newRotC[1],
5914
+ trans[2] + rotC[2] - newRotC[2]
5915
+ ];
5916
+ rot = newRot;
5917
+ inner = inner.target;
5918
+ } else break;
5863
5919
  return {
5864
5920
  inner,
5865
- offset: [
5866
- ox,
5867
- oy,
5868
- oz
5869
- ]
5921
+ rot,
5922
+ trans
5870
5923
  };
5871
5924
  }
5872
- /** Shift every vertex of a mesh by `offset`; normals, UVs and triangles are unchanged. */
5873
- function translateMesh(m, offset) {
5874
- const [dx, dy, dz] = offset;
5875
- if (dx === 0 && dy === 0 && dz === 0) return m;
5876
- const vertices = new Float32Array(m.vertices.length);
5877
- for (let i = 0; i < m.vertices.length; i += 3) {
5878
- vertices[i] = (m.vertices[i] ?? 0) + dx;
5879
- vertices[i + 1] = (m.vertices[i + 1] ?? 0) + dy;
5880
- vertices[i + 2] = (m.vertices[i + 2] ?? 0) + dz;
5925
+ function isIdentityQuat(q) {
5926
+ return q[0] === 1 && q[1] === 0 && q[2] === 0 && q[3] === 0;
5927
+ }
5928
+ /**
5929
+ * Write `src` (flat xyz) rigidly transformed by quaternion (qw,qx,qy,qz) then
5930
+ * translation (tx,ty,tz) into `dst`. The quaternion-rotate math is inlined with
5931
+ * scalar locals no per-vertex array allocation — because this runs once per
5932
+ * mesh vertex/normal and helper-allocated vector math regressed the gridfinity
5933
+ * benchmark 17% (see `utils/vec3.ts`). Pass zero translation for normals.
5934
+ */
5935
+ function rotateXyzBuffer(dst, src, qw, qx, qy, qz, tx, ty, tz) {
5936
+ for (let i = 0; i < src.length; i += 3) {
5937
+ const vx = src[i] ?? 0;
5938
+ const vy = src[i + 1] ?? 0;
5939
+ const vz = src[i + 2] ?? 0;
5940
+ const cx = 2 * (qy * vz - qz * vy);
5941
+ const cy = 2 * (qz * vx - qx * vz);
5942
+ const cz = 2 * (qx * vy - qy * vx);
5943
+ dst[i] = vx + qw * cx + (qy * cz - qz * cy) + tx;
5944
+ dst[i + 1] = vy + qw * cy + (qz * cx - qx * cz) + ty;
5945
+ dst[i + 2] = vz + qw * cz + (qx * cy - qy * cx) + tz;
5881
5946
  }
5947
+ }
5948
+ /**
5949
+ * Apply a rigid motion to a mesh: vertices get the rotation then translation,
5950
+ * normals get the rotation only (a unit rotation preserves length, so no
5951
+ * renormalization). UVs and triangles are motion-invariant. A pure translation
5952
+ * (identity rotation) keeps the source normals array by reference and only
5953
+ * shifts vertices — the exact previous translation-only fast path.
5954
+ */
5955
+ function transformMeshRigid(m, rot, trans) {
5956
+ const [tx, ty, tz] = trans;
5957
+ const pureTranslation = isIdentityQuat(rot);
5958
+ if (pureTranslation && tx === 0 && ty === 0 && tz === 0) return m;
5959
+ const src = m.vertices;
5960
+ const vertices = new Float32Array(src.length);
5961
+ if (pureTranslation) {
5962
+ for (let i = 0; i < src.length; i += 3) {
5963
+ vertices[i] = (src[i] ?? 0) + tx;
5964
+ vertices[i + 1] = (src[i + 1] ?? 0) + ty;
5965
+ vertices[i + 2] = (src[i + 2] ?? 0) + tz;
5966
+ }
5967
+ return {
5968
+ ...m,
5969
+ vertices
5970
+ };
5971
+ }
5972
+ const [qw, qx, qy, qz] = rot;
5973
+ rotateXyzBuffer(vertices, src, qw, qx, qy, qz, tx, ty, tz);
5974
+ const sn = m.normals;
5975
+ const normals = new Float32Array(sn.length);
5976
+ rotateXyzBuffer(normals, sn, qw, qx, qy, qz, 0, 0, 0);
5882
5977
  return {
5883
5978
  ...m,
5884
- vertices
5979
+ vertices,
5980
+ normals
5885
5981
  };
5886
5982
  }
5887
5983
  /**
@@ -5889,8 +5985,8 @@ function translateMesh(m, offset) {
5889
5985
  * moved faces location-dependent hashes, so the inner mesh's `faceId`s describe
5890
5986
  * the *unplaced* shape; remap them to the placed faces (1:1 by iteration order,
5891
5987
  * since `locate` shares the source TShape) so face picking and metadata lookup
5892
- * resolve against the placed mesh. Origins are translation-invariant, so only
5893
- * `faceId` changes.
5988
+ * resolve against the placed mesh. Origins are boolean-lineage tags, invariant
5989
+ * under any rigid motion, so only `faceId` changes.
5894
5990
  *
5895
5991
  * Takes pre-captured hash arrays (not shapes): a bounded shape cache can evict
5896
5992
  * and dispose one shape while the other is being evaluated, so the caller reads
@@ -5986,7 +6082,7 @@ var Evaluator = class {
5986
6082
  }
5987
6083
  return ok(cached);
5988
6084
  }
5989
- const { inner, offset } = peelTranslate(node, env);
6085
+ const { inner, rot, trans } = peelRigid(node, env);
5990
6086
  if (inner !== node) {
5991
6087
  const innerMesh = this.evaluateMesh(inner, env, meshOpts);
5992
6088
  if (!innerMesh.ok) return innerMesh;
@@ -5996,7 +6092,7 @@ var Evaluator = class {
5996
6092
  const placedShape = this.evaluate(node, env);
5997
6093
  if (!placedShape.ok) return placedShape;
5998
6094
  const placedHashes = getFaces(placedShape.value).map(getHashCode);
5999
- const moved = translateMesh(innerMesh.value, offset);
6095
+ const moved = transformMeshRigid(innerMesh.value, rot, trans);
6000
6096
  const faceGroups = relocateFaceGroups(moved.faceGroups, innerHashes, placedHashes);
6001
6097
  const placedSet = new Set(placedHashes);
6002
6098
  if (faceGroups.every((g) => placedSet.has(g.faceId))) {
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_threadFns = require("./threadFns-KrG_i9_w.cjs");
2
+ const require_threadFns = require("./threadFns-BqWHWpea.cjs");
3
3
  const require_loftFns = require("./loftFns-fpTmrIdd.cjs");
4
4
  exports.addChild = require_threadFns.addChild;
5
5
  exports.addJoint = require_threadFns.addJoint;
@@ -1,3 +1,3 @@
1
- import { A as setJointValue, B as findNode, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, G as gridPattern, H as updateNode, I as addChild, J as createAssembly, K as linearPattern, L as collectShapes, M as sphericalJoint, O as prismaticJoint, R as countNodes, S as addJoint, T as jointTransform, U as walkAssembly, V as removeChild, W as circularPattern, _ as exportURDF, 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, 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-Dgr2qyJv.js";
1
+ import { A as setJointValue, B as createAssemblyNode, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, G as circularPattern, H as removeChild, J as exportAssemblySTEP, K as gridPattern, L as addChild, M as sphericalJoint, O as prismaticJoint, R as collectShapes, S as addJoint, T as jointTransform, U as updateNode, V as findNode, W as walkAssembly, Y as createAssembly, _ as exportURDF, 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, q as linearPattern, 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 countNodes } from "./threadFns-KbYZu7Q9.js";
2
2
  import { d as twistExtrude, l as supportExtrude, o as complexExtrude, u as sweep } from "./loftFns-CmShFQlv.js";
3
3
  export { addChild, addJoint, addStep, circularPattern, collectShapes, complexExtrude, countNodes, createAssembly, createAssemblyNode, createHistory, createRegistry, cylindricalJoint, exportAssemblySTEP, exportURDF, findNode, findStep, forwardKinematics, getShape as getHistoryShape, gridPattern, importURDF, inverseKinematics, jointTrajectory, jointTransform, jointsFromDH, linearPattern, mechanismDOF, modifyStep, planarJoint, prismaticJoint, registerOperation, registerShape, removeChild, replayFrom, replayHistory, revoluteJoint, setJointValue, setJointValues, sphericalJoint, stepCount, stepsFrom, supportExtrude, sweep, thread, twistExtrude, undoLast, updateNode, walkAssembly };
@@ -1699,6 +1699,12 @@ Object.defineProperty(exports, "quatFromTo", {
1699
1699
  return quatFromTo;
1700
1700
  }
1701
1701
  });
1702
+ Object.defineProperty(exports, "quatMultiply", {
1703
+ enumerable: true,
1704
+ get: function() {
1705
+ return quatMultiply;
1706
+ }
1707
+ });
1702
1708
  Object.defineProperty(exports, "quatRotate", {
1703
1709
  enumerable: true,
1704
1710
  get: function() {
@@ -1513,4 +1513,4 @@ function thread(options) {
1513
1513
  }
1514
1514
  }
1515
1515
  //#endregion
1516
- export { setJointValue as A, findNode as B, cylindricalJoint as C, planarJoint as D, mechanismDOF as E, quatRotate as F, gridPattern as G, updateNode as H, addChild as I, createAssembly as J, linearPattern as K, collectShapes as L, sphericalJoint as M, quatFromAxisAngle as N, prismaticJoint as O, quatFromTo as P, countNodes as R, addJoint as S, jointTransform as T, walkAssembly as U, removeChild as V, circularPattern as W, exportURDF as _, deserializeHistory as a, inverseKinematics as b, modifyStep as c, replayFrom as d, replayHistory as f, undoLast as g, stepsFrom as h, createRegistry as i, setJointValues as j, revoluteJoint as k, registerOperation as l, stepCount as m, addStep as n, findStep as o, serializeHistory as p, exportAssemblySTEP as q, createHistory as r, getShape as s, thread as t, registerShape as u, importURDF as v, forwardKinematics as w, jointTrajectory as x, jointsFromDH as y, createAssemblyNode as z };
1516
+ export { setJointValue as A, createAssemblyNode as B, cylindricalJoint as C, planarJoint as D, mechanismDOF as E, quatMultiply as F, circularPattern as G, removeChild as H, quatRotate as I, exportAssemblySTEP as J, gridPattern as K, addChild as L, sphericalJoint as M, quatFromAxisAngle as N, prismaticJoint as O, quatFromTo as P, collectShapes as R, addJoint as S, jointTransform as T, updateNode as U, findNode as V, walkAssembly as W, createAssembly as Y, exportURDF as _, deserializeHistory as a, inverseKinematics as b, modifyStep as c, replayFrom as d, replayHistory as f, undoLast as g, stepsFrom as h, createRegistry as i, setJointValues as j, revoluteJoint as k, registerOperation as l, stepCount as m, addStep as n, findStep as o, serializeHistory as p, linearPattern as q, createHistory as r, getShape as s, thread as t, registerShape as u, importURDF as v, forwardKinematics as w, jointTrajectory as x, jointsFromDH as y, countNodes as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brepjs",
3
- "version": "18.116.0",
3
+ "version": "18.116.1",
4
4
  "description": "Web CAD library with pluggable geometry kernel",
5
5
  "keywords": [
6
6
  "cad",