brepjs 20.3.0 → 20.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/brepjs.cjs +8 -8
  2. package/dist/brepjs.js +8 -8
  3. package/dist/{drawFns-BD5OqwLF.js → drawFns-3yRVBDgI.js} +1 -1
  4. package/dist/{drawFns-Dcvgj3Xg.cjs → drawFns-Ddlgp9gQ.cjs} +1 -1
  5. package/dist/faceRoleFns-CWU1-Pm8.js +37 -0
  6. package/dist/faceRoleFns-CtH_48MO.cjs +60 -0
  7. package/dist/{healingFns-BDkAwJNy.js → healingFns-Ct3gEMvk.js} +1 -1
  8. package/dist/{healingFns-DziPRwmh.cjs → healingFns-DwSpJZfg.cjs} +1 -1
  9. package/dist/operations/extrudeFns.d.ts +4 -0
  10. package/dist/operations.cjs +1 -1
  11. package/dist/operations.js +1 -1
  12. package/dist/{primitiveFns-CcaoYdzl.js → primitiveFns-CGJzS4MO.js} +1 -1
  13. package/dist/{primitiveFns-DayTOw7C.cjs → primitiveFns-ZV3aMbqG.cjs} +1 -1
  14. package/dist/{refResolveFns-C0_Wx7nM.js → refResolveFns-CpVZoeOT.js} +24 -6
  15. package/dist/{refResolveFns-BJG5h8ce.cjs → refResolveFns-Ct52Uw7R.cjs} +24 -6
  16. package/dist/shapeRef.cjs +1 -1
  17. package/dist/shapeRef.js +1 -1
  18. package/dist/sketching.cjs +2 -2
  19. package/dist/sketching.js +2 -2
  20. package/dist/{solidBuilders-6eLtWBLM.cjs → solidBuilders-CgicU3le.cjs} +5 -3
  21. package/dist/{solidBuilders-BwOF7M-p.js → solidBuilders-IstbiWju.js} +5 -3
  22. package/dist/text.cjs +2 -2
  23. package/dist/text.js +2 -2
  24. package/dist/{textBlueprints-3jLY3G3u.js → textBlueprints-C13NAA3C.js} +161 -2
  25. package/dist/{textBlueprints-BE9lHH5V.cjs → textBlueprints-fa7VHJZz.cjs} +160 -1
  26. package/dist/{textMetrics-DMhzyYGs.cjs → textMetrics--cikHkGX.cjs} +1 -1
  27. package/dist/{textMetrics-cyLUdKx1.js → textMetrics-Dcc63qRm.js} +1 -1
  28. package/dist/{threadFns-CJT2NW3G.js → threadFns-3U9x4v_M.js} +3 -3
  29. package/dist/{threadFns-Bc1QOMeh.cjs → threadFns-BUQPg_vI.cjs} +3 -3
  30. package/dist/topology/metadata/faceRoleFns.d.ts +15 -0
  31. package/dist/topology/metadata/metadataPropagation.d.ts +2 -2
  32. package/dist/topology/shapeRef/extrudeRoleFns.d.ts +9 -0
  33. package/dist/topology/shapeRef/refResolveFns.d.ts +2 -1
  34. package/dist/topology/shapeRef/shapeRefFns.d.ts +8 -2
  35. package/dist/topology.cjs +3 -3
  36. package/dist/topology.js +3 -3
  37. package/package.json +1 -1
package/dist/brepjs.cjs CHANGED
@@ -12,30 +12,30 @@ const require_vecOps = require("./vecOps-CCnJt-yH.cjs");
12
12
  const require_planeOps = require("./planeOps-DJuclNxa.cjs");
13
13
  const require_faceFns = require("./faceFns-CZeHWke7.cjs");
14
14
  const require_originTrackingFns = require("./originTrackingFns-CWo6NWHK.cjs");
15
- const require_solidBuilders = require("./solidBuilders-6eLtWBLM.cjs");
16
- const require_primitiveFns = require("./primitiveFns-DayTOw7C.cjs");
15
+ const require_solidBuilders = require("./solidBuilders-CgicU3le.cjs");
16
+ const require_primitiveFns = require("./primitiveFns-ZV3aMbqG.cjs");
17
17
  const require_shapeFns = require("./shapeFns-C2j6oZ2u.cjs");
18
18
  const require_curveFns = require("./curveFns-6-ULFrEB.cjs");
19
19
  const require_meshFns = require("./meshFns-CAxkaRTm.cjs");
20
20
  const require_arrayAccess = require("./arrayAccess-e4H9cBfh.cjs");
21
21
  const require_surfaceBuilders = require("./surfaceBuilders-vYgSvgI6.cjs");
22
- const require_healingFns = require("./healingFns-DziPRwmh.cjs");
23
- const require_threadFns = require("./threadFns-Bc1QOMeh.cjs");
22
+ const require_healingFns = require("./healingFns-DwSpJZfg.cjs");
23
+ const require_threadFns = require("./threadFns-BUQPg_vI.cjs");
24
24
  const require_blueprintSketcher = require("./blueprintSketcher-CzKbxeTk.cjs");
25
25
  const require_helpers = require("./helpers-NRZVshPb.cjs");
26
26
  const require_blueprint = require("./blueprint-Yyoiz-U1.cjs");
27
- const require_drawFns = require("./drawFns-Dcvgj3Xg.cjs");
27
+ const require_drawFns = require("./drawFns-Ddlgp9gQ.cjs");
28
28
  const require_measureFns = require("./measureFns-D_GpQw5z.cjs");
29
29
  const require_cornerFinder = require("./cornerFinder-Cji_BK-R.cjs");
30
30
  const require_boolean2D = require("./boolean2D-BzZ9iBSn.cjs");
31
31
  const require_blueprintFns = require("./blueprintFns-Ce6OoPSX.cjs");
32
32
  const require_importFns = require("./importFns-BEi-HsSw.cjs");
33
+ const require_textBlueprints = require("./textBlueprints-fa7VHJZz.cjs");
33
34
  const require_loftFns = require("./loftFns-DL9UsQhd.cjs");
34
- const require_textBlueprints = require("./textBlueprints-BE9lHH5V.cjs");
35
- const require_refResolveFns = require("./refResolveFns-BJG5h8ce.cjs");
35
+ const require_refResolveFns = require("./refResolveFns-Ct52Uw7R.cjs");
36
36
  const require_adjacencyFns = require("./adjacencyFns-1rxgJ6Hw.cjs");
37
37
  const require_cameraFns = require("./cameraFns-RHCb1F1s.cjs");
38
- const require_textMetrics = require("./textMetrics-DMhzyYGs.cjs");
38
+ const require_textMetrics = require("./textMetrics--cikHkGX.cjs");
39
39
  const require_principalBoxFns = require("./principalBoxFns-5FSbxAj-.cjs");
40
40
  const require_workerPool = require("./workerPool-D30NsiIW.cjs");
41
41
  //#region src/kernel/types.ts
package/dist/brepjs.js CHANGED
@@ -10,30 +10,30 @@ import { a as vecDot, c as vecLength, d as vecNormalize, f as vecProjectToPlane,
10
10
  import { i as pivotPlane, n as createPlane, o as resolvePlane, r as makePlane, s as translatePlane, t as createNamedPlane } from "./planeOps-Cxws4Tiu.js";
11
11
  import { C as shapeType, S as iterTopo, _ as cast, a as faceOrientation, b as fromBREP, c as innerWires, d as pointOnSurface, f as projectPointOnFace, g as asTopo, h as uvCoordinates, i as faceGeomType, l as normalAt, m as uvBounds, n as faceAxis, o as flipFaceOrientation, p as removeHolesFromFace, r as faceCenter, s as getSurfaceType, t as classifyPointOnFace, u as outerWire, x as isCompSolid, y as downcast } from "./faceFns-CTlJC5IY.js";
12
12
  import { i as setShapeOrigin, t as getFaceOrigins } from "./originTrackingFns-DiHy5BZC.js";
13
- import { A as parseColor, D as colorShape, E as colorFaces, F as tagFaces, M as getFaceTags, N as getTagMetadata, O as getFaceColor, P as setTagMetadata, S as hasAnyMetadata, T as propagateMetadataThroughRelocation, _ as section$1, b as split$1, d as booleanPipeline, f as cut$2, g as intersect$2, h as fuseAll$2, j as findFacesByTag, k as getShapeColor, m as fuse$2, p as cutAll$2, r as makeCylinder, t as makeCompound, v as sectionToFace$1, y as slice$1 } from "./solidBuilders-BwOF7M-p.js";
14
- import { A as locate$1, C as threePointArc, D as wireLoop, E as wire, F as transformCopy$1, I as translate$2, M as resize, N as rotate$2, O as applyMatrix$1, P as scale$3, S as tangentArc, T as vertex, _ as polygon, a as circle, b as sphere$1, c as cylinder, d as ellipsoid, f as face, g as offsetFace, h as line, i as bsplineApprox, j as mirror$2, k as composeTransforms, l as ellipse, m as helix, n as bezier, o as compound, p as filledFace, r as box, s as cone, t as addHoles, u as ellipseArc, v as sewShells, w as torus$1, x as subFace, y as solid } from "./primitiveFns-CcaoYdzl.js";
13
+ import { A as parseColor, D as colorShape, E as colorFaces, F as tagFaces, M as getFaceTags, N as getTagMetadata, O as getFaceColor, P as setTagMetadata, S as hasAnyMetadata, T as propagateMetadataThroughRelocation, _ as section$1, b as split$1, d as booleanPipeline, f as cut$2, g as intersect$2, h as fuseAll$2, j as findFacesByTag, k as getShapeColor, m as fuse$2, p as cutAll$2, r as makeCylinder, t as makeCompound, v as sectionToFace$1, y as slice$1 } from "./solidBuilders-IstbiWju.js";
14
+ import { A as locate$1, C as threePointArc, D as wireLoop, E as wire, F as transformCopy$1, I as translate$2, M as resize, N as rotate$2, O as applyMatrix$1, P as scale$3, S as tangentArc, T as vertex, _ as polygon, a as circle, b as sphere$1, c as cylinder, d as ellipsoid, f as face, g as offsetFace, h as line, i as bsplineApprox, j as mirror$2, k as composeTransforms, l as ellipse, m as helix, n as bezier, o as compound, p as filledFace, r as box, s as cone, t as addHoles, u as ellipseArc, v as sewShells, w as torus$1, x as subFace, y as solid } from "./primitiveFns-CGJzS4MO.js";
15
15
  import { a as isSameShape, i as isEqualShape, n as getHashCode, o as simplify$1, r as isEmpty$2, s as toBREP$1, t as clone$1 } from "./shapeFns--1wNlcc_.js";
16
16
  import { a as curveIsPeriodic, c as curvePointAt, d as flipOrientation, f as getCurveType, h as offsetWire2D, i as curveIsClosed, l as curveStartPoint, m as interpolateCurve, n as curveAxis, o as curveLength, p as getOrientation, r as curveEndPoint, s as curvePeriod, t as approximateCurve, u as curveTangentAt } from "./curveFns-KS1BWGhF.js";
17
17
  import { a as meshEdges$1, c as meshMultiLOD, d as clearMeshCache, f as createMeshCache, i as mesh$1, l as scaleDefaultTolerance, n as exportSTEP, o as meshLODs, r as exportSTL, s as meshLODsProgressive, t as exportIGES, u as buildMeshCacheKey } from "./meshFns-COlno8TY.js";
18
18
  import { n as getAtOrThrow, r as lastOrThrow, t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
19
19
  import { _ as makeThreePointArc, d as makeCircle, h as makeLine, l as makeBSplineInterpolation, n as fill, p as makeEllipseArc, r as makeFace, s as assembleWire, u as makeBezierCurve } from "./surfaceBuilders-8nLk2PWk.js";
20
- import { A as toBufferGeometryData, C as chamfer$2, D as shell$2, E as offset$1, M as toLODGeometryData, N as toLODGeometryLevels, O as thicken$1, P as toLineGeometryData, S as chamferDistAngle, T as fillet$2, _ as checkBoolean, a as healFace, b as getNurbsCurveData, c as isValid$1, d as chamferWithEvolution, f as cutWithEvolution, g as shellWithEvolution, h as intersectWithEvolution, i as heal$1, j as toGroupedBufferGeometryData, k as variableFillet, l as solidFromShell, m as fuseWithEvolution, n as fixSelfIntersection, o as healSolid, p as filletWithEvolution, r as fixShape, s as healWire, t as autoHeal, u as positionOnCurve, v as cutAllBisect, w as draft$1, x as getNurbsSurfaceData, y as fuseAllBisect } from "./healingFns-BDkAwJNy.js";
21
- import { A as setJointValue, B as walkAssembly, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, F as countNodes, G as quatFromAxisAngle, H as circularPattern, I as createAssemblyNode, J as quatRotate, K as quatFromTo, L as findNode, M as sphericalJoint, N as addChild, O as prismaticJoint, P as collectShapes, R as removeChild, S as addJoint, T as jointTransform, U as gridPattern, V as exportAssemblySTEP, W as linearPattern, 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 quatMultiply, 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 updateNode } from "./threadFns-CJT2NW3G.js";
20
+ import { A as toBufferGeometryData, C as chamfer$2, D as shell$2, E as offset$1, M as toLODGeometryData, N as toLODGeometryLevels, O as thicken$1, P as toLineGeometryData, S as chamferDistAngle, T as fillet$2, _ as checkBoolean, a as healFace, b as getNurbsCurveData, c as isValid$1, d as chamferWithEvolution, f as cutWithEvolution, g as shellWithEvolution, h as intersectWithEvolution, i as heal$1, j as toGroupedBufferGeometryData, k as variableFillet, l as solidFromShell, m as fuseWithEvolution, n as fixSelfIntersection, o as healSolid, p as filletWithEvolution, r as fixShape, s as healWire, t as autoHeal, u as positionOnCurve, v as cutAllBisect, w as draft$1, x as getNurbsSurfaceData, y as fuseAllBisect } from "./healingFns-Ct3gEMvk.js";
21
+ import { A as setJointValue, B as walkAssembly, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, F as countNodes, G as quatFromAxisAngle, H as circularPattern, I as createAssemblyNode, J as quatRotate, K as quatFromTo, L as findNode, M as sphericalJoint, N as addChild, O as prismaticJoint, P as collectShapes, R as removeChild, S as addJoint, T as jointTransform, U as gridPattern, V as exportAssemblySTEP, W as linearPattern, 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 quatMultiply, 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 updateNode } from "./threadFns-3U9x4v_M.js";
22
22
  import { n as BaseSketcher2d, r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-FywUpRiV.js";
23
23
  import { a as createTypedFinder, i as wireFinder, n as edgeFinder, r as faceFinder, t as getSingleFace } from "./helpers-BN1mVMuZ.js";
24
24
  import { _ as approximateAsSvgCompatibleCurve, o as ellipseArcFlags } from "./blueprint-rwJjYPzo.js";
25
- 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-BD5OqwLF.js";
25
+ 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-3yRVBDgI.js";
26
26
  import { a as measureDistance, c as measureLinearProps, d as measureVolumeProps, i as measureCurvatureAtMid, l as measureSurfaceProps, n as measureArea, o as measureDistanceProps, r as measureCurvatureAt, s as measureLength, t as createDistanceQuery, u as measureVolume } from "./measureFns-CyDVZomf.js";
27
27
  import { t as cornerFinder } from "./cornerFinder-Dlae8IX5.js";
28
28
  import { a as fuseBlueprints, c as roundedRectangleBlueprint, i as cutBlueprints, n as fuse2D, o as intersectBlueprints, r as intersect2D, s as polysidesBlueprint, t as cut2D } from "./boolean2D-D8igCYc9.js";
29
29
  import { S as reverseCurve, _ as curve2dIsOnCurve, a as isInside2D, b as curve2dSplitAt, c as scale2D, d as stretch2D, f as toSVGPathD, g as curve2dFirstPoint, h as curve2dDistanceFrom, i as getOrientation2D, l as sketchOnFace2D, m as curve2dBoundingBox, n as createCompoundBlueprint, o as mirror2D, p as translate2D, r as getBounds2D, s as rotate2D, t as createBlueprint, u as sketchOnPlane2D, v as curve2dLastPoint, x as curve2dTangentAt, y as curve2dParameter } from "./blueprintFns-Q3Sq-Fse.js";
30
30
  import { a as importSVG, c as blueprintToDXF, d as exportGltf, f as exportOBJ, i as exportSTEPConfigured, l as exportDXF, n as importSTEP, o as importSVGPathD, r as importSTL, s as exportThreeMF, t as importIGES, u as exportGlb } from "./importFns-0kHGg-b8.js";
31
+ import { a as Sketch, b as extrudeAll, c as compoundSketchLoft, d as sketchFace, f as sketchLoft, h as sketchWires, i as Sketches, l as compoundSketchRevolve, m as sketchSweep, n as getFont, o as compoundSketchExtrude, p as sketchRevolve, r as loadFont, s as compoundSketchFace, t as textBlueprints, u as sketchExtrude, v as CompoundSketch, x as revolve$2, y as extrude$2 } from "./textBlueprints-C13NAA3C.js";
31
32
  import { a as multiSectionSweep, c as twistExtrude, i as guidedSweep, n as loftAll, o as supportExtrude, r as complexExtrude, s as sweep$1, t as loft$2 } from "./loftFns-B5mq1WDh.js";
32
- import { a as Sketch, b as extrudeAll, c as compoundSketchLoft, d as sketchFace, f as sketchLoft, h as sketchWires, i as Sketches, l as compoundSketchRevolve, m as sketchSweep, n as getFont, o as compoundSketchExtrude, p as sketchRevolve, r as loadFont, s as compoundSketchFace, t as textBlueprints, u as sketchExtrude, v as CompoundSketch, x as revolve$2, y as extrude$2 } from "./textBlueprints-3jLY3G3u.js";
33
- import { _ as createRef, a as isVertexRef, b as defaultScorer, c as resolveRefParams, d as createVertexRef, f as resolveVertexRef, g as captureHint, h as assignRoles, i as isLineageRef, l as createDerivedFaceRef, m as resolveEdgeRef, n as isEdgeRef, o as resolveLineageRef, p as createEdgeRef, r as isFaceRef, s as resolveRefIn, t as isDerivedFaceRef, u as resolveDerivedFaceRef, v as resolveRef, y as updateRoles } from "./refResolveFns-C0_Wx7nM.js";
33
+ import { _ as createRef, a as isVertexRef, b as defaultScorer, c as resolveRefParams, d as createVertexRef, f as resolveVertexRef, g as captureHint, h as assignRoles, i as isLineageRef, l as createDerivedFaceRef, m as resolveEdgeRef, n as isEdgeRef, o as resolveLineageRef, p as createEdgeRef, r as isFaceRef, s as resolveRefIn, t as isDerivedFaceRef, u as resolveDerivedFaceRef, v as resolveRef, y as updateRoles } from "./refResolveFns-CpVZoeOT.js";
34
34
  import { a as facesOfVertex, c as verticesOfFace, i as facesOfEdge, l as wiresOfFace, n as adjacentFaces, o as sharedEdges, r as edgesOfFace, s as verticesOfEdge } from "./adjacencyFns-DeyXahej.js";
35
35
  import { a as makeProjectedEdges, i as projectEdges, n as cameraLookAt, r as createCamera, s as isProjectionPlane, t as cameraFromPlane } from "./cameraFns-Cs6v3bWQ.js";
36
- import { n as textMetrics, r as sketchText, t as fontMetrics } from "./textMetrics-cyLUdKx1.js";
36
+ import { n as textMetrics, r as sketchText, t as fontMetrics } from "./textMetrics-Dcc63qRm.js";
37
37
  import { t as principalBoundingBox } from "./principalBoxFns-BJgGEoik.js";
38
38
  import { _ as isSuccessResponse, a as createWorkerClient, c as enqueueTask, d as rejectAll, f as isBatchRequest, g as isOperationRequest, h as isInitRequest, i as registerHandler, l as isEmpty$1, m as isErrorResponse, n as createOperationRegistry, o as createTaskQueue, p as isDisposeRequest, r as createWorkerHandler, s as dequeueTask, t as createWorkerPool, u as pendingCount } from "./workerPool-XcYX2UZ0.js";
39
39
  //#region \0rolldown/runtime.js
@@ -15,7 +15,7 @@ import { b as squareDistance2d, l as add2d, s as PRECISION_OFFSET, v as samePoin
15
15
  import { _ as approximateAsSvgCompatibleCurve, a as edgeToCurve, f as make2dInerpolatedBSplineCurve, i as curvesAsEdgesOnPlane, l as make2dCircle, p as make2dSegmentCurve, s as make2dArcFromCenter, t as Blueprint, u as make2dEllipse, v as Curve2D, x as BoundingBox2d, y as deserializeCurve2D } from "./blueprint-rwJjYPzo.js";
16
16
  import { t as cornerFinder } from "./cornerFinder-Dlae8IX5.js";
17
17
  import { c as roundedRectangleBlueprint, n as fuse2D, r as intersect2D, s as polysidesBlueprint, t as cut2D } from "./boolean2D-D8igCYc9.js";
18
- import { _ as wrapSketchDataArray, a as Sketch, g as wrapSketchData, i as Sketches, t as textBlueprints } from "./textBlueprints-3jLY3G3u.js";
18
+ import { _ as wrapSketchDataArray, a as Sketch, g as wrapSketchData, i as Sketches, t as textBlueprints } from "./textBlueprints-C13NAA3C.js";
19
19
  import { i as projectEdges, t as cameraFromPlane } from "./cameraFns-Cs6v3bWQ.js";
20
20
  //#region src/2d/lib/stitching.ts
21
21
  /**
@@ -15,7 +15,7 @@ const require_helpers = require("./helpers-NRZVshPb.cjs");
15
15
  const require_blueprint = require("./blueprint-Yyoiz-U1.cjs");
16
16
  const require_cornerFinder = require("./cornerFinder-Cji_BK-R.cjs");
17
17
  const require_boolean2D = require("./boolean2D-BzZ9iBSn.cjs");
18
- const require_textBlueprints = require("./textBlueprints-BE9lHH5V.cjs");
18
+ const require_textBlueprints = require("./textBlueprints-fa7VHJZz.cjs");
19
19
  const require_cameraFns = require("./cameraFns-RHCb1F1s.cjs");
20
20
  //#region src/2d/lib/stitching.ts
21
21
  /**
@@ -0,0 +1,37 @@
1
+ //#region src/topology/metadata/faceRoleFns.ts
2
+ var faceRoleStore = /* @__PURE__ */ new WeakMap();
3
+ /** O(1) check whether a shape carries recorded face roles. */
4
+ function hasFaceRoles(shape) {
5
+ return faceRoleStore.has(shape.wrapped);
6
+ }
7
+ /** Record face roles (face hash → role name) on a shape, replacing any it had. */
8
+ function setFaceRoles(shape, roles) {
9
+ if (roles.size === 0) return;
10
+ faceRoleStore.set(shape.wrapped, new Map(roles));
11
+ }
12
+ /** The face roles recorded on a shape (face hash → role name), if any. */
13
+ function getFaceRoles(shape) {
14
+ return faceRoleStore.get(shape.wrapped);
15
+ }
16
+ /**
17
+ * Carry recorded face roles from inputs to a result through a ShapeEvolution:
18
+ * deleted faces drop their role, a modified face passes it to every successor,
19
+ * and an untouched face keeps it. When two inputs' faces land on one result
20
+ * face, the first input's role wins.
21
+ */
22
+ function propagateFaceRolesFromEvolution(evolution, inputs, result) {
23
+ const resultRoles = /* @__PURE__ */ new Map();
24
+ for (const input of inputs) {
25
+ const inputRoles = faceRoleStore.get(input.wrapped);
26
+ if (!inputRoles) continue;
27
+ for (const [hash, role] of inputRoles) {
28
+ if (evolution.deleted.has(hash)) continue;
29
+ const modified = evolution.modified.get(hash);
30
+ const targets = modified && modified.length > 0 ? modified : [hash];
31
+ for (const target of targets) if (!resultRoles.has(target)) resultRoles.set(target, role);
32
+ }
33
+ }
34
+ setFaceRoles(result, resultRoles);
35
+ }
36
+ //#endregion
37
+ export { setFaceRoles as i, hasFaceRoles as n, propagateFaceRolesFromEvolution as r, getFaceRoles as t };
@@ -0,0 +1,60 @@
1
+ //#region src/topology/metadata/faceRoleFns.ts
2
+ var faceRoleStore = /* @__PURE__ */ new WeakMap();
3
+ /** O(1) check whether a shape carries recorded face roles. */
4
+ function hasFaceRoles(shape) {
5
+ return faceRoleStore.has(shape.wrapped);
6
+ }
7
+ /** Record face roles (face hash → role name) on a shape, replacing any it had. */
8
+ function setFaceRoles(shape, roles) {
9
+ if (roles.size === 0) return;
10
+ faceRoleStore.set(shape.wrapped, new Map(roles));
11
+ }
12
+ /** The face roles recorded on a shape (face hash → role name), if any. */
13
+ function getFaceRoles(shape) {
14
+ return faceRoleStore.get(shape.wrapped);
15
+ }
16
+ /**
17
+ * Carry recorded face roles from inputs to a result through a ShapeEvolution:
18
+ * deleted faces drop their role, a modified face passes it to every successor,
19
+ * and an untouched face keeps it. When two inputs' faces land on one result
20
+ * face, the first input's role wins.
21
+ */
22
+ function propagateFaceRolesFromEvolution(evolution, inputs, result) {
23
+ const resultRoles = /* @__PURE__ */ new Map();
24
+ for (const input of inputs) {
25
+ const inputRoles = faceRoleStore.get(input.wrapped);
26
+ if (!inputRoles) continue;
27
+ for (const [hash, role] of inputRoles) {
28
+ if (evolution.deleted.has(hash)) continue;
29
+ const modified = evolution.modified.get(hash);
30
+ const targets = modified && modified.length > 0 ? modified : [hash];
31
+ for (const target of targets) if (!resultRoles.has(target)) resultRoles.set(target, role);
32
+ }
33
+ }
34
+ setFaceRoles(result, resultRoles);
35
+ }
36
+ //#endregion
37
+ Object.defineProperty(exports, "getFaceRoles", {
38
+ enumerable: true,
39
+ get: function() {
40
+ return getFaceRoles;
41
+ }
42
+ });
43
+ Object.defineProperty(exports, "hasFaceRoles", {
44
+ enumerable: true,
45
+ get: function() {
46
+ return hasFaceRoles;
47
+ }
48
+ });
49
+ Object.defineProperty(exports, "propagateFaceRolesFromEvolution", {
50
+ enumerable: true,
51
+ get: function() {
52
+ return propagateFaceRolesFromEvolution;
53
+ }
54
+ });
55
+ Object.defineProperty(exports, "setFaceRoles", {
56
+ enumerable: true,
57
+ get: function() {
58
+ return setFaceRoles;
59
+ }
60
+ });
@@ -3,7 +3,7 @@ import { E as ok, b as isErr, d as validationError, g as err, i as kernelError,
3
3
  import { c as getFaces, i as getCachedIsValid, m as invalidateShapeCache, p as getWires, s as getEdges } from "./topologyQueryFns-DnfjQgP7.js";
4
4
  import { n as HASH_CODE_MAX } from "./constants-ITRzCnCp.js";
5
5
  import { y as downcast } from "./faceFns-CTlJC5IY.js";
6
- import { C as propagateAllMetadata, f as cut, h as fuseAll, m as fuse, p as cutAll, x as collectInputFaceHashes } from "./solidBuilders-BwOF7M-p.js";
6
+ import { C as propagateAllMetadata, f as cut, h as fuseAll, m as fuse, p as cutAll, x as collectInputFaceHashes } from "./solidBuilders-IstbiWju.js";
7
7
  import { t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
8
8
  //#region src/topology/threeHelpers.ts
9
9
  /**
@@ -3,7 +3,7 @@ const require_errors = require("./errors-jwhfQJZK.cjs");
3
3
  const require_topologyQueryFns = require("./topologyQueryFns-q2bGyuEV.cjs");
4
4
  const require_constants = require("./constants-BOVyEYGH.cjs");
5
5
  const require_faceFns = require("./faceFns-CZeHWke7.cjs");
6
- const require_solidBuilders = require("./solidBuilders-6eLtWBLM.cjs");
6
+ const require_solidBuilders = require("./solidBuilders-CgicU3le.cjs");
7
7
  const require_arrayAccess = require("./arrayAccess-e4H9cBfh.cjs");
8
8
  //#region src/topology/threeHelpers.ts
9
9
  /**
@@ -6,6 +6,10 @@ export type { ExtrusionProfile, SweepOptions } from './extrudeUtils.js';
6
6
  /**
7
7
  * Extrude a face along a vector to produce a solid.
8
8
  *
9
+ * The result carries semantic face roles (`extrude:start`, `extrude:end`,
10
+ * `extrude:side:<i>`, `extrude:hole<j>:side:<i>`) that
11
+ * `assignRoles(solid, 'extrude')` returns in place of positional names.
12
+ *
9
13
  * @param face - The planar face to extrude.
10
14
  * @param extrusionVec - Direction and magnitude of the extrusion as `[x, y, z]`.
11
15
  * @returns `Result` containing the extruded solid, or an error if validation or operation fails.
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_threadFns = require("./threadFns-Bc1QOMeh.cjs");
2
+ const require_threadFns = require("./threadFns-BUQPg_vI.cjs");
3
3
  const require_loftFns = require("./loftFns-DL9UsQhd.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 walkAssembly, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, F as countNodes, H as circularPattern, I as createAssemblyNode, L as findNode, M as sphericalJoint, N as addChild, O as prismaticJoint, P as collectShapes, R as removeChild, S as addJoint, T as jointTransform, U as gridPattern, V as exportAssemblySTEP, W as linearPattern, 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, 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 updateNode } from "./threadFns-CJT2NW3G.js";
1
+ import { A as setJointValue, B as walkAssembly, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, F as countNodes, H as circularPattern, I as createAssemblyNode, L as findNode, M as sphericalJoint, N as addChild, O as prismaticJoint, P as collectShapes, R as removeChild, S as addJoint, T as jointTransform, U as gridPattern, V as exportAssemblySTEP, W as linearPattern, 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, 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 updateNode } from "./threadFns-3U9x4v_M.js";
2
2
  import { c as twistExtrude, o as supportExtrude, r as complexExtrude, s as sweep } from "./loftFns-B5mq1WDh.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 };
@@ -2,7 +2,7 @@ import { E as GeometryCleanupError, G as _usingCtx, d as createSolid, n as castR
2
2
  import { E as ok, d as validationError, g as err, m as andThen, t as BrepErrorCode } from "./errors-Zb3jBa0u.js";
3
3
  import { n as isClosedWire } from "./validityTypes-t7JpS0Ki.js";
4
4
  import { n as HASH_CODE_MAX, t as DEG2RAD } from "./constants-ITRzCnCp.js";
5
- import { C as propagateAllMetadata, S as hasAnyMetadata, T as propagateMetadataThroughRelocation, a as makeOffset, c as makeTorus, i as makeEllipsoid, l as makeVertex, n as makeCone, o as makeSolid, r as makeCylinder, s as makeSphere, t as makeCompound, u as weldShellsAndFaces, w as propagateMetadataByHash, x as collectInputFaceHashes } from "./solidBuilders-BwOF7M-p.js";
5
+ import { C as propagateAllMetadata, S as hasAnyMetadata, T as propagateMetadataThroughRelocation, a as makeOffset, c as makeTorus, i as makeEllipsoid, l as makeVertex, n as makeCone, o as makeSolid, r as makeCylinder, s as makeSphere, t as makeCompound, u as weldShellsAndFaces, w as propagateMetadataByHash, x as collectInputFaceHashes } from "./solidBuilders-IstbiWju.js";
6
6
  import { _ as makeThreePointArc, a as makeNonPlanarFace, c as makeBSplineApproximation, d as makeCircle, f as makeEllipse, g as makeTangentArc, h as makeLine, i as makeNewFaceWithinFace, m as makeHelix, o as makePolygon, p as makeEllipseArc, r as makeFace, s as assembleWire, t as addHolesInFace, u as makeBezierCurve } from "./surfaceBuilders-8nLk2PWk.js";
7
7
  //#region src/topology/transformFns.ts
8
8
  /**
@@ -2,7 +2,7 @@ const require_shapeTypes = require("./shapeTypes-DH2ShBU_.cjs");
2
2
  const require_errors = require("./errors-jwhfQJZK.cjs");
3
3
  const require_validityTypes = require("./validityTypes-r0A2YdNq.cjs");
4
4
  const require_constants = require("./constants-BOVyEYGH.cjs");
5
- const require_solidBuilders = require("./solidBuilders-6eLtWBLM.cjs");
5
+ const require_solidBuilders = require("./solidBuilders-CgicU3le.cjs");
6
6
  const require_surfaceBuilders = require("./surfaceBuilders-vYgSvgI6.cjs");
7
7
  //#region src/topology/transformFns.ts
8
8
  /**
@@ -1,6 +1,7 @@
1
1
  import { g as disposeTransientSubShape, o as castShapeWithKnownType, q as getKernel } from "./shapeTypes-CqNJoSam.js";
2
2
  import { c as getFaces, w as vertexPosition } from "./topologyQueryFns-DnfjQgP7.js";
3
3
  import { i as faceGeomType, l as normalAt, r as faceCenter } from "./faceFns-CTlJC5IY.js";
4
+ import { t as getFaceRoles } from "./faceRoleFns-CWU1-Pm8.js";
4
5
  import { n as getHashCode } from "./shapeFns--1wNlcc_.js";
5
6
  import { n as measureArea, s as measureLength } from "./measureFns-CyDVZomf.js";
6
7
  import { a as facesOfVertex, c as verticesOfFace, i as facesOfEdge, o as sharedEdges, s as verticesOfEdge, t as adjacentFaceHashes } from "./adjacencyFns-DeyXahej.js";
@@ -108,24 +109,40 @@ var ROLE_ASSIGNERS = {
108
109
  * - `cylinder`/`cone` (Z-axis): 'top'/'bottom' caps + 'lateral' wall.
109
110
  * - `sphere`: 'sphere:surface'.
110
111
  *
112
+ * Faces whose roles an operation recorded on the shape take those names when
113
+ * the namespace matches `operationType`. `extrude` records 'extrude:start',
114
+ * 'extrude:end', 'extrude:side:<i>' and 'extrude:hole<j>:side:<i>', which
115
+ * survive later moves and booleans.
116
+ *
111
117
  * Faces a primitive namer doesn't recognize (a rotated box's non-cardinal faces),
112
118
  * and every face of any other operation type, fall back to positional names
113
119
  * ('opType:face_0', 'opType:face_1', ...) — so each face always gets a role.
114
120
  *
115
- * @returns Map from role name to its face hash codes (one at assignment time;
116
- * a role accrues more hashes only later, when `updateRoles` tracks a split).
121
+ * @returns Map from role name to its face hash codes (one per role, except a
122
+ * recorded role whose face a later operation split; `updateRoles` adds more
123
+ * when it tracks a split).
117
124
  */
118
125
  function assignRoles(shape, operationType) {
119
126
  const roles = /* @__PURE__ */ new Map();
120
127
  const assigner = ROLE_ASSIGNERS[operationType];
128
+ const recorded = getFaceRoles(shape);
129
+ const namespace = `${operationType}:`;
121
130
  const kernel = getKernel();
122
131
  let index = 0;
123
132
  for (const raw of kernel.iterShapes(shape.wrapped, "face")) {
124
133
  const face = castShapeWithKnownType(raw, "face");
125
134
  try {
126
- const semantic = assigner?.(face);
127
- const role = semantic !== void 0 && !roles.has(semantic) ? semantic : `${operationType}:face_${index}`;
128
- roles.set(role, [getHashCode(face)]);
135
+ const hash = getHashCode(face);
136
+ const stored = recorded?.get(hash);
137
+ if (stored?.startsWith(namespace) === true) {
138
+ const hashes = roles.get(stored);
139
+ if (hashes) hashes.push(hash);
140
+ else roles.set(stored, [hash]);
141
+ } else {
142
+ const semantic = assigner?.(face);
143
+ const role = semantic !== void 0 && !roles.has(semantic) ? semantic : `${operationType}:face_${index}`;
144
+ roles.set(role, [hash]);
145
+ }
129
146
  index++;
130
147
  } finally {
131
148
  disposeTransientSubShape(face, raw);
@@ -744,7 +761,8 @@ function rolesFor(ref, shape, cache) {
744
761
  * Resolve a lineage ref against a freshly rebuilt `shape` with no maintained
745
762
  * role table, re-deriving roles via `assignRoles(shape, ref.origin)`. The ref's
746
763
  * `origin` must therefore be the role-assignment scheme (e.g. `'box'`), and
747
- * stability is bounded by that scheme — `'box'` names faces semantically
764
+ * stability is bounded by that scheme. The primitives (`'box'`, `'cylinder'`,
765
+ * `'cone'`, `'sphere'`) and `'extrude'` name faces semantically
748
766
  * (rebuild-stable); other schemes fall back to positional `face_N`.
749
767
  */
750
768
  function resolveRefIn(ref, shape) {
@@ -1,6 +1,7 @@
1
1
  const require_shapeTypes = require("./shapeTypes-DH2ShBU_.cjs");
2
2
  const require_topologyQueryFns = require("./topologyQueryFns-q2bGyuEV.cjs");
3
3
  const require_faceFns = require("./faceFns-CZeHWke7.cjs");
4
+ const require_faceRoleFns = require("./faceRoleFns-CtH_48MO.cjs");
4
5
  const require_shapeFns = require("./shapeFns-C2j6oZ2u.cjs");
5
6
  const require_measureFns = require("./measureFns-D_GpQw5z.cjs");
6
7
  const require_adjacencyFns = require("./adjacencyFns-1rxgJ6Hw.cjs");
@@ -108,24 +109,40 @@ var ROLE_ASSIGNERS = {
108
109
  * - `cylinder`/`cone` (Z-axis): 'top'/'bottom' caps + 'lateral' wall.
109
110
  * - `sphere`: 'sphere:surface'.
110
111
  *
112
+ * Faces whose roles an operation recorded on the shape take those names when
113
+ * the namespace matches `operationType`. `extrude` records 'extrude:start',
114
+ * 'extrude:end', 'extrude:side:<i>' and 'extrude:hole<j>:side:<i>', which
115
+ * survive later moves and booleans.
116
+ *
111
117
  * Faces a primitive namer doesn't recognize (a rotated box's non-cardinal faces),
112
118
  * and every face of any other operation type, fall back to positional names
113
119
  * ('opType:face_0', 'opType:face_1', ...) — so each face always gets a role.
114
120
  *
115
- * @returns Map from role name to its face hash codes (one at assignment time;
116
- * a role accrues more hashes only later, when `updateRoles` tracks a split).
121
+ * @returns Map from role name to its face hash codes (one per role, except a
122
+ * recorded role whose face a later operation split; `updateRoles` adds more
123
+ * when it tracks a split).
117
124
  */
118
125
  function assignRoles(shape, operationType) {
119
126
  const roles = /* @__PURE__ */ new Map();
120
127
  const assigner = ROLE_ASSIGNERS[operationType];
128
+ const recorded = require_faceRoleFns.getFaceRoles(shape);
129
+ const namespace = `${operationType}:`;
121
130
  const kernel = require_shapeTypes.getKernel();
122
131
  let index = 0;
123
132
  for (const raw of kernel.iterShapes(shape.wrapped, "face")) {
124
133
  const face = require_shapeTypes.castShapeWithKnownType(raw, "face");
125
134
  try {
126
- const semantic = assigner?.(face);
127
- const role = semantic !== void 0 && !roles.has(semantic) ? semantic : `${operationType}:face_${index}`;
128
- roles.set(role, [require_shapeFns.getHashCode(face)]);
135
+ const hash = require_shapeFns.getHashCode(face);
136
+ const stored = recorded?.get(hash);
137
+ if (stored?.startsWith(namespace) === true) {
138
+ const hashes = roles.get(stored);
139
+ if (hashes) hashes.push(hash);
140
+ else roles.set(stored, [hash]);
141
+ } else {
142
+ const semantic = assigner?.(face);
143
+ const role = semantic !== void 0 && !roles.has(semantic) ? semantic : `${operationType}:face_${index}`;
144
+ roles.set(role, [hash]);
145
+ }
129
146
  index++;
130
147
  } finally {
131
148
  require_shapeTypes.disposeTransientSubShape(face, raw);
@@ -744,7 +761,8 @@ function rolesFor(ref, shape, cache) {
744
761
  * Resolve a lineage ref against a freshly rebuilt `shape` with no maintained
745
762
  * role table, re-deriving roles via `assignRoles(shape, ref.origin)`. The ref's
746
763
  * `origin` must therefore be the role-assignment scheme (e.g. `'box'`), and
747
- * stability is bounded by that scheme — `'box'` names faces semantically
764
+ * stability is bounded by that scheme. The primitives (`'box'`, `'cylinder'`,
765
+ * `'cone'`, `'sphere'`) and `'extrude'` name faces semantically
748
766
  * (rebuild-stable); other schemes fall back to positional `face_N`.
749
767
  */
750
768
  function resolveRefIn(ref, shape) {
package/dist/shapeRef.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_refResolveFns = require("./refResolveFns-BJG5h8ce.cjs");
2
+ const require_refResolveFns = require("./refResolveFns-Ct52Uw7R.cjs");
3
3
  exports.assignRoles = require_refResolveFns.assignRoles;
4
4
  exports.captureHint = require_refResolveFns.captureHint;
5
5
  exports.createDerivedFaceRef = require_refResolveFns.createDerivedFaceRef;
package/dist/shapeRef.js CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as createRef, a as isVertexRef, b as defaultScorer, c as resolveRefParams, d as createVertexRef, f as resolveVertexRef, g as captureHint, h as assignRoles, i as isLineageRef, l as createDerivedFaceRef, m as resolveEdgeRef, n as isEdgeRef, o as resolveLineageRef, p as createEdgeRef, r as isFaceRef, s as resolveRefIn, t as isDerivedFaceRef, u as resolveDerivedFaceRef, v as resolveRef, y as updateRoles } from "./refResolveFns-C0_Wx7nM.js";
1
+ import { _ as createRef, a as isVertexRef, b as defaultScorer, c as resolveRefParams, d as createVertexRef, f as resolveVertexRef, g as captureHint, h as assignRoles, i as isLineageRef, l as createDerivedFaceRef, m as resolveEdgeRef, n as isEdgeRef, o as resolveLineageRef, p as createEdgeRef, r as isFaceRef, s as resolveRefIn, t as isDerivedFaceRef, u as resolveDerivedFaceRef, v as resolveRef, y as updateRoles } from "./refResolveFns-CpVZoeOT.js";
2
2
  export { assignRoles, captureHint, createDerivedFaceRef, createEdgeRef, createRef, createVertexRef, defaultScorer, isDerivedFaceRef, isEdgeRef, isFaceRef, isLineageRef, isVertexRef, resolveDerivedFaceRef, resolveEdgeRef, resolveLineageRef, resolveRef, resolveRefIn, resolveRefParams, resolveVertexRef, updateRoles };
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_blueprintSketcher = require("./blueprintSketcher-CzKbxeTk.cjs");
3
- const require_drawFns = require("./drawFns-Dcvgj3Xg.cjs");
4
- const require_textBlueprints = require("./textBlueprints-BE9lHH5V.cjs");
3
+ const require_drawFns = require("./drawFns-Ddlgp9gQ.cjs");
4
+ const require_textBlueprints = require("./textBlueprints-fa7VHJZz.cjs");
5
5
  //#region src/sketching.ts
6
6
  /**
7
7
  * brepjs/sketching — Sketcher, Drawing, and sketch-to-shape operations.
package/dist/sketching.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as BaseSketcher2d, t as BlueprintSketcher } from "./blueprintSketcher-FywUpRiV.js";
2
- import { A as sketchEllipse, C as DrawingPen, D as makeBaseBox, E as deserializeDrawing, F as sketchRectangle, I as sketchRoundedRectangle, L as FaceSketcher, M as sketchHelix, N as sketchParametricFunction, O as polysideInnerRadius, P as sketchPolysides, R as Sketcher, S as drawText, T as Drawing, _ as drawPolysides, a as drawingIntersect, b as drawSingleCircle, c as rotateDrawing, d as drawFaceOutline, f as drawProjection, g as drawPointsInterpolation, h as drawParametricFunction, i as drawingFuse, j as sketchFaceOffset, k as sketchCircle, l as scaleDrawing, m as drawEllipse, n as drawingCut, o as drawingToSketchOnPlane, p as drawCircle, r as drawingFillet, s as mirrorDrawing, t as drawingChamfer, u as translateDrawing, v as drawRectangle, w as draw, x as drawSingleEllipse, y as drawRoundedRectangle } from "./drawFns-BD5OqwLF.js";
3
- import { a as Sketch, c as compoundSketchLoft, d as sketchFace, f as sketchLoft, h as sketchWires, i as Sketches, l as compoundSketchRevolve, m as sketchSweep, o as compoundSketchExtrude, p as sketchRevolve, s as compoundSketchFace, u as sketchExtrude, v as CompoundSketch } from "./textBlueprints-3jLY3G3u.js";
2
+ import { A as sketchEllipse, C as DrawingPen, D as makeBaseBox, E as deserializeDrawing, F as sketchRectangle, I as sketchRoundedRectangle, L as FaceSketcher, M as sketchHelix, N as sketchParametricFunction, O as polysideInnerRadius, P as sketchPolysides, R as Sketcher, S as drawText, T as Drawing, _ as drawPolysides, a as drawingIntersect, b as drawSingleCircle, c as rotateDrawing, d as drawFaceOutline, f as drawProjection, g as drawPointsInterpolation, h as drawParametricFunction, i as drawingFuse, j as sketchFaceOffset, k as sketchCircle, l as scaleDrawing, m as drawEllipse, n as drawingCut, o as drawingToSketchOnPlane, p as drawCircle, r as drawingFillet, s as mirrorDrawing, t as drawingChamfer, u as translateDrawing, v as drawRectangle, w as draw, x as drawSingleEllipse, y as drawRoundedRectangle } from "./drawFns-3yRVBDgI.js";
3
+ import { a as Sketch, c as compoundSketchLoft, d as sketchFace, f as sketchLoft, h as sketchWires, i as Sketches, l as compoundSketchRevolve, m as sketchSweep, o as compoundSketchExtrude, p as sketchRevolve, s as compoundSketchFace, u as sketchExtrude, v as CompoundSketch } from "./textBlueprints-C13NAA3C.js";
4
4
  //#region src/sketching.ts
5
5
  /**
6
6
  * brepjs/sketching — Sketcher, Drawing, and sketch-to-shape operations.
@@ -6,6 +6,7 @@ const require_vecOps = require("./vecOps-CCnJt-yH.cjs");
6
6
  const require_planeOps = require("./planeOps-DJuclNxa.cjs");
7
7
  const require_faceFns = require("./faceFns-CZeHWke7.cjs");
8
8
  const require_originTrackingFns = require("./originTrackingFns-CWo6NWHK.cjs");
9
+ const require_faceRoleFns = require("./faceRoleFns-CtH_48MO.cjs");
9
10
  const require_arrayAccess = require("./arrayAccess-e4H9cBfh.cjs");
10
11
  const require_surfaceBuilders = require("./surfaceBuilders-vYgSvgI6.cjs");
11
12
  //#region src/topology/metadata/faceTagFns.ts
@@ -239,11 +240,11 @@ function propagateColorsFromEvolution(evolution, inputs, result) {
239
240
  */
240
241
  /**
241
242
  * O(1) check: does a shape carry any propagatable metadata (face origins,
242
- * tags, or colors)? Lets callers skip both expensive face iteration and
243
+ * tags, colors, or recorded roles)? Lets callers skip both expensive face iteration and
243
244
  * metadata-preserving slow paths when there's nothing to preserve.
244
245
  */
245
246
  function hasAnyMetadata(shape) {
246
- return require_originTrackingFns.getFaceOrigins(shape) !== void 0 || hasFaceTags(shape) || hasColorMetadata(shape);
247
+ return require_originTrackingFns.getFaceOrigins(shape) !== void 0 || hasFaceTags(shape) || hasColorMetadata(shape) || require_faceRoleFns.hasFaceRoles(shape);
247
248
  }
248
249
  function collectInputFaceHashes(inputs) {
249
250
  if (!inputs.some(hasAnyMetadata)) return [];
@@ -252,7 +253,7 @@ function collectInputFaceHashes(inputs) {
252
253
  return hashes;
253
254
  }
254
255
  /**
255
- * Propagate all metadata (origins, tags, colors) from inputs to result
256
+ * Propagate all metadata (origins, tags, colors, recorded roles) from inputs to result
256
257
  * using a kernel-provided ShapeEvolution record.
257
258
  *
258
259
  * This is the standard pipeline for any operation that returns
@@ -262,6 +263,7 @@ function propagateAllMetadata(evolution, inputs, result) {
262
263
  require_originTrackingFns.propagateOriginsFromEvolution(evolution, inputs, result);
263
264
  propagateFaceTagsFromEvolution(evolution, inputs, result);
264
265
  propagateColorsFromEvolution(evolution, inputs, result);
266
+ require_faceRoleFns.propagateFaceRolesFromEvolution(evolution, inputs, result);
265
267
  }
266
268
  /**
267
269
  * Fallback metadata propagation when no ShapeEvolution is available.
@@ -6,6 +6,7 @@ import { a as vecDot, g as vecSub, h as vecScale, t as vecAdd } from "./vecOps-S
6
6
  import { o as resolvePlane } from "./planeOps-Cxws4Tiu.js";
7
7
  import { _ as cast, y as downcast } from "./faceFns-CTlJC5IY.js";
8
8
  import { n as propagateOriginsByHash, r as propagateOriginsFromEvolution, t as getFaceOrigins } from "./originTrackingFns-DiHy5BZC.js";
9
+ import { n as hasFaceRoles, r as propagateFaceRolesFromEvolution } from "./faceRoleFns-CWU1-Pm8.js";
9
10
  import { n as getAtOrThrow, t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
10
11
  import { r as makeFace } from "./surfaceBuilders-8nLk2PWk.js";
11
12
  //#region src/topology/metadata/faceTagFns.ts
@@ -239,11 +240,11 @@ function propagateColorsFromEvolution(evolution, inputs, result) {
239
240
  */
240
241
  /**
241
242
  * O(1) check: does a shape carry any propagatable metadata (face origins,
242
- * tags, or colors)? Lets callers skip both expensive face iteration and
243
+ * tags, colors, or recorded roles)? Lets callers skip both expensive face iteration and
243
244
  * metadata-preserving slow paths when there's nothing to preserve.
244
245
  */
245
246
  function hasAnyMetadata(shape) {
246
- return getFaceOrigins(shape) !== void 0 || hasFaceTags(shape) || hasColorMetadata(shape);
247
+ return getFaceOrigins(shape) !== void 0 || hasFaceTags(shape) || hasColorMetadata(shape) || hasFaceRoles(shape);
247
248
  }
248
249
  function collectInputFaceHashes(inputs) {
249
250
  if (!inputs.some(hasAnyMetadata)) return [];
@@ -252,7 +253,7 @@ function collectInputFaceHashes(inputs) {
252
253
  return hashes;
253
254
  }
254
255
  /**
255
- * Propagate all metadata (origins, tags, colors) from inputs to result
256
+ * Propagate all metadata (origins, tags, colors, recorded roles) from inputs to result
256
257
  * using a kernel-provided ShapeEvolution record.
257
258
  *
258
259
  * This is the standard pipeline for any operation that returns
@@ -262,6 +263,7 @@ function propagateAllMetadata(evolution, inputs, result) {
262
263
  propagateOriginsFromEvolution(evolution, inputs, result);
263
264
  propagateFaceTagsFromEvolution(evolution, inputs, result);
264
265
  propagateColorsFromEvolution(evolution, inputs, result);
266
+ propagateFaceRolesFromEvolution(evolution, inputs, result);
265
267
  }
266
268
  /**
267
269
  * Fallback metadata propagation when no ShapeEvolution is available.
package/dist/text.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_textBlueprints = require("./textBlueprints-BE9lHH5V.cjs");
3
- const require_textMetrics = require("./textMetrics-DMhzyYGs.cjs");
2
+ const require_textBlueprints = require("./textBlueprints-fa7VHJZz.cjs");
3
+ const require_textMetrics = require("./textMetrics--cikHkGX.cjs");
4
4
  exports.fontMetrics = require_textMetrics.fontMetrics;
5
5
  exports.getFont = require_textBlueprints.getFont;
6
6
  exports.loadFont = require_textBlueprints.loadFont;
package/dist/text.js CHANGED
@@ -1,3 +1,3 @@
1
- import { n as getFont, r as loadFont, t as textBlueprints } from "./textBlueprints-3jLY3G3u.js";
2
- import { n as textMetrics, r as sketchText, t as fontMetrics } from "./textMetrics-cyLUdKx1.js";
1
+ import { n as getFont, r as loadFont, t as textBlueprints } from "./textBlueprints-C13NAA3C.js";
2
+ import { n as textMetrics, r as sketchText, t as fontMetrics } from "./textMetrics-Dcc63qRm.js";
3
3
  export { fontMetrics, getFont, loadFont, sketchText, textBlueprints, textMetrics };
@@ -1,17 +1,171 @@
1
1
  import { d as createSolid, h as disposeResultShape, l as createFace, m as disposeDowncastSource, n as castResultShape, p as createWire, q as getKernel, x as isShape3D } from "./shapeTypes-CqNJoSam.js";
2
2
  import { n as bug } from "./bug-BdOHwn_e.js";
3
3
  import { E as ok, P as unwrap, d as validationError, g as err, i as kernelError, l as typeCastError, r as ioError, t as BrepErrorCode } from "./errors-Zb3jBa0u.js";
4
+ import { n as HASH_CODE_MAX } from "./constants-ITRzCnCp.js";
4
5
  import { r as toVec3 } from "./types-D24Y27N0.js";
5
- import { c as vecLength, d as vecNormalize, h as vecScale, r as vecCross } from "./vecOps-SKPRvPH-.js";
6
+ import { c as vecLength, d as vecNormalize, h as vecScale, i as vecDistance, r as vecCross, t as vecAdd } from "./vecOps-SKPRvPH-.js";
6
7
  import { n as createPlane } from "./planeOps-Cxws4Tiu.js";
7
8
  import { v as copyShape } from "./faceFns-CTlJC5IY.js";
8
- import { o as makeSolid, p as cutAll, t as makeCompound } from "./solidBuilders-BwOF7M-p.js";
9
+ import { o as makeSolid, p as cutAll, t as makeCompound } from "./solidBuilders-IstbiWju.js";
10
+ import { i as setFaceRoles } from "./faceRoleFns-CWU1-Pm8.js";
9
11
  import { l as curveStartPoint, u as curveTangentAt } from "./curveFns-KS1BWGhF.js";
10
12
  import { n as getAtOrThrow, t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
11
13
  import { i as makeNewFaceWithinFace, r as makeFace, t as addHolesInFace } from "./surfaceBuilders-8nLk2PWk.js";
12
14
  import { r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-FywUpRiV.js";
13
15
  import { c as twistExtrude, r as complexExtrude, s as sweep, t as loft } from "./loftFns-B5mq1WDh.js";
14
16
  import opentype from "opentype.js";
17
+ //#region src/topology/shapeRef/extrudeRoleFns.ts
18
+ /** Match tolerance as a fraction of the extrusion's size. */
19
+ var RELATIVE_TOLERANCE = 1e-6;
20
+ function centerOf({ min, max }) {
21
+ return [
22
+ (min[0] + max[0]) / 2,
23
+ (min[1] + max[1]) / 2,
24
+ (min[2] + max[2]) / 2
25
+ ];
26
+ }
27
+ function boxCenter(shape) {
28
+ return centerOf(getKernel().boundingBox(shape));
29
+ }
30
+ function edgeCenters(wire) {
31
+ const kernel = getKernel();
32
+ const centers = [];
33
+ for (const edge of kernel.iterShapes(wire, "edge")) try {
34
+ centers.push(boxCenter(edge));
35
+ } finally {
36
+ kernel.dispose(edge);
37
+ }
38
+ return centers;
39
+ }
40
+ /**
41
+ * Where each role's face sits, as a bounding-box center. A face swept from an
42
+ * edge is the edge's Minkowski sum with the segment [0, vector], so its box
43
+ * center is the edge's box center + vector / 2; the caps are translated copies
44
+ * of the profile. This holds for exact boxes (OCCT) and vertex boxes (brepkit)
45
+ * alike, so predicted and actual centers agree to rounding.
46
+ */
47
+ function anchorsFor(profile, start, vector) {
48
+ const kernel = getKernel();
49
+ const anchors = [{
50
+ role: "extrude:start",
51
+ point: start
52
+ }, {
53
+ role: "extrude:end",
54
+ point: vecAdd(start, vector)
55
+ }];
56
+ const halfVector = vecScale(vector, .5);
57
+ const outer = kernel.outerWire(profile);
58
+ try {
59
+ let hole = 0;
60
+ for (const wire of kernel.iterShapes(profile, "wire")) try {
61
+ const prefix = kernel.isSame(wire, outer) ? "extrude:side" : `extrude:hole${hole++}:side`;
62
+ edgeCenters(wire).forEach((center, i) => {
63
+ anchors.push({
64
+ role: `${prefix}:${i}`,
65
+ point: vecAdd(center, halfVector)
66
+ });
67
+ });
68
+ } finally {
69
+ kernel.dispose(wire);
70
+ }
71
+ } finally {
72
+ kernel.dispose(outer);
73
+ }
74
+ return anchors;
75
+ }
76
+ function locateFaces(solid) {
77
+ const kernel = getKernel();
78
+ const located = [];
79
+ for (const face of kernel.iterShapes(solid, "face")) try {
80
+ located.push({
81
+ hash: kernel.hashCode(face, HASH_CODE_MAX),
82
+ point: boxCenter(face)
83
+ });
84
+ } finally {
85
+ kernel.dispose(face);
86
+ }
87
+ return located;
88
+ }
89
+ function lowerBound(sortedKeys, key) {
90
+ let lo = 0;
91
+ let hi = sortedKeys.length;
92
+ while (lo < hi) {
93
+ const mid = lo + hi >>> 1;
94
+ if ((sortedKeys[mid] ?? Infinity) < key) lo = mid + 1;
95
+ else hi = mid;
96
+ }
97
+ return lo;
98
+ }
99
+ /** The coordinate axis along which `points` spread furthest. */
100
+ function widestAxis(points) {
101
+ let axis = 0;
102
+ let widest = -Infinity;
103
+ for (const candidate of [
104
+ 0,
105
+ 1,
106
+ 2
107
+ ]) {
108
+ let min = Infinity;
109
+ let max = -Infinity;
110
+ for (const p of points) {
111
+ min = Math.min(min, p[candidate]);
112
+ max = Math.max(max, p[candidate]);
113
+ }
114
+ if (max - min > widest) {
115
+ axis = candidate;
116
+ widest = max - min;
117
+ }
118
+ }
119
+ return axis;
120
+ }
121
+ /**
122
+ * Pair each anchor with its nearest face within `tolerance`. Returns undefined
123
+ * unless the pairing is one-to-one over every face, so an unexpected topology
124
+ * records nothing rather than wrong names. Candidates are windowed along the
125
+ * axis the face centers spread furthest on: a profile in the YZ plane puts
126
+ * every side face at one X, which would make a fixed X window scan them all.
127
+ */
128
+ function matchAnchors(anchors, faces, tolerance) {
129
+ if (anchors.length !== faces.length) return void 0;
130
+ const axis = widestAxis(faces.map((f) => f.point));
131
+ const sorted = [...faces].sort((a, b) => a.point[axis] - b.point[axis]);
132
+ const keys = sorted.map((f) => f.point[axis]);
133
+ const claimed = /* @__PURE__ */ new Set();
134
+ const roles = /* @__PURE__ */ new Map();
135
+ for (const { role, point } of anchors) {
136
+ let best = -1;
137
+ let bestDistance = tolerance;
138
+ for (let i = lowerBound(keys, point[axis] - tolerance); i < sorted.length; i++) {
139
+ const face = sorted[i];
140
+ if (face === void 0 || face.point[axis] > point[axis] + tolerance) break;
141
+ const d = vecDistance(face.point, point);
142
+ if (d <= bestDistance) {
143
+ best = i;
144
+ bestDistance = d;
145
+ }
146
+ }
147
+ const match = best < 0 ? void 0 : sorted[best];
148
+ if (match === void 0 || claimed.has(best)) return void 0;
149
+ claimed.add(best);
150
+ roles.set(match.hash, role);
151
+ }
152
+ return roles;
153
+ }
154
+ /**
155
+ * Record `extrude:*` face roles on `solid`, the extrusion of `profile` along
156
+ * `vector`, for `assignRoles(solid, 'extrude')` to read. Records nothing on a
157
+ * mesh kernel, or when the faces don't pair one-to-one with the profile's caps
158
+ * and edges; `assignRoles` then falls back to positional names.
159
+ */
160
+ function recordExtrudeRoles(solid, profile, vector) {
161
+ const kernel = getKernel();
162
+ if (!kernel.capabilities.exact) return;
163
+ const profileBox = kernel.boundingBox(profile.wrapped);
164
+ const size = vecDistance(profileBox.min, profileBox.max) + vecLength(vector);
165
+ const roles = matchAnchors(anchorsFor(profile.wrapped, centerOf(profileBox), vector), locateFaces(solid.wrapped), RELATIVE_TOLERANCE * size);
166
+ if (roles) setFaceRoles(solid, roles);
167
+ }
168
+ //#endregion
15
169
  //#region src/operations/extrudeFns.ts
16
170
  /**
17
171
  * Basic extrusion operations — extrude and revolve.
@@ -22,6 +176,10 @@ import opentype from "opentype.js";
22
176
  /**
23
177
  * Extrude a face along a vector to produce a solid.
24
178
  *
179
+ * The result carries semantic face roles (`extrude:start`, `extrude:end`,
180
+ * `extrude:side:<i>`, `extrude:hole<j>:side:<i>`) that
181
+ * `assignRoles(solid, 'extrude')` returns in place of positional names.
182
+ *
25
183
  * @param face - The planar face to extrude.
26
184
  * @param extrusionVec - Direction and magnitude of the extrusion as `[x, y, z]`.
27
185
  * @returns `Result` containing the extruded solid, or an error if validation or operation fails.
@@ -37,6 +195,7 @@ function extrude(face, extrusionVec) {
37
195
  const downcastShape = kernel.downcast(shape, "solid");
38
196
  const solid = createSolid(downcastShape);
39
197
  disposeDowncastSource(shape, solid);
198
+ recordExtrudeRoles(solid, face, extrusionVec);
40
199
  return ok(solid);
41
200
  } catch (e) {
42
201
  return err(kernelError("EXTRUDE_FAILED", "Extrusion operation failed", e, {
@@ -2,11 +2,13 @@ const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
2
2
  const require_shapeTypes = require("./shapeTypes-DH2ShBU_.cjs");
3
3
  const require_bug = require("./bug-O02CsAmt.cjs");
4
4
  const require_errors = require("./errors-jwhfQJZK.cjs");
5
+ const require_constants = require("./constants-BOVyEYGH.cjs");
5
6
  const require_types = require("./types-KjA8tY4Y.cjs");
6
7
  const require_vecOps = require("./vecOps-CCnJt-yH.cjs");
7
8
  const require_planeOps = require("./planeOps-DJuclNxa.cjs");
8
9
  const require_faceFns = require("./faceFns-CZeHWke7.cjs");
9
- const require_solidBuilders = require("./solidBuilders-6eLtWBLM.cjs");
10
+ const require_solidBuilders = require("./solidBuilders-CgicU3le.cjs");
11
+ const require_faceRoleFns = require("./faceRoleFns-CtH_48MO.cjs");
10
12
  const require_curveFns = require("./curveFns-6-ULFrEB.cjs");
11
13
  const require_arrayAccess = require("./arrayAccess-e4H9cBfh.cjs");
12
14
  const require_surfaceBuilders = require("./surfaceBuilders-vYgSvgI6.cjs");
@@ -14,6 +16,158 @@ const require_blueprintSketcher = require("./blueprintSketcher-CzKbxeTk.cjs");
14
16
  const require_loftFns = require("./loftFns-DL9UsQhd.cjs");
15
17
  let opentype_js = require("opentype.js");
16
18
  opentype_js = require_rolldown_runtime.__toESM(opentype_js, 1);
19
+ //#region src/topology/shapeRef/extrudeRoleFns.ts
20
+ /** Match tolerance as a fraction of the extrusion's size. */
21
+ var RELATIVE_TOLERANCE = 1e-6;
22
+ function centerOf({ min, max }) {
23
+ return [
24
+ (min[0] + max[0]) / 2,
25
+ (min[1] + max[1]) / 2,
26
+ (min[2] + max[2]) / 2
27
+ ];
28
+ }
29
+ function boxCenter(shape) {
30
+ return centerOf(require_shapeTypes.getKernel().boundingBox(shape));
31
+ }
32
+ function edgeCenters(wire) {
33
+ const kernel = require_shapeTypes.getKernel();
34
+ const centers = [];
35
+ for (const edge of kernel.iterShapes(wire, "edge")) try {
36
+ centers.push(boxCenter(edge));
37
+ } finally {
38
+ kernel.dispose(edge);
39
+ }
40
+ return centers;
41
+ }
42
+ /**
43
+ * Where each role's face sits, as a bounding-box center. A face swept from an
44
+ * edge is the edge's Minkowski sum with the segment [0, vector], so its box
45
+ * center is the edge's box center + vector / 2; the caps are translated copies
46
+ * of the profile. This holds for exact boxes (OCCT) and vertex boxes (brepkit)
47
+ * alike, so predicted and actual centers agree to rounding.
48
+ */
49
+ function anchorsFor(profile, start, vector) {
50
+ const kernel = require_shapeTypes.getKernel();
51
+ const anchors = [{
52
+ role: "extrude:start",
53
+ point: start
54
+ }, {
55
+ role: "extrude:end",
56
+ point: require_vecOps.vecAdd(start, vector)
57
+ }];
58
+ const halfVector = require_vecOps.vecScale(vector, .5);
59
+ const outer = kernel.outerWire(profile);
60
+ try {
61
+ let hole = 0;
62
+ for (const wire of kernel.iterShapes(profile, "wire")) try {
63
+ const prefix = kernel.isSame(wire, outer) ? "extrude:side" : `extrude:hole${hole++}:side`;
64
+ edgeCenters(wire).forEach((center, i) => {
65
+ anchors.push({
66
+ role: `${prefix}:${i}`,
67
+ point: require_vecOps.vecAdd(center, halfVector)
68
+ });
69
+ });
70
+ } finally {
71
+ kernel.dispose(wire);
72
+ }
73
+ } finally {
74
+ kernel.dispose(outer);
75
+ }
76
+ return anchors;
77
+ }
78
+ function locateFaces(solid) {
79
+ const kernel = require_shapeTypes.getKernel();
80
+ const located = [];
81
+ for (const face of kernel.iterShapes(solid, "face")) try {
82
+ located.push({
83
+ hash: kernel.hashCode(face, require_constants.HASH_CODE_MAX),
84
+ point: boxCenter(face)
85
+ });
86
+ } finally {
87
+ kernel.dispose(face);
88
+ }
89
+ return located;
90
+ }
91
+ function lowerBound(sortedKeys, key) {
92
+ let lo = 0;
93
+ let hi = sortedKeys.length;
94
+ while (lo < hi) {
95
+ const mid = lo + hi >>> 1;
96
+ if ((sortedKeys[mid] ?? Infinity) < key) lo = mid + 1;
97
+ else hi = mid;
98
+ }
99
+ return lo;
100
+ }
101
+ /** The coordinate axis along which `points` spread furthest. */
102
+ function widestAxis(points) {
103
+ let axis = 0;
104
+ let widest = -Infinity;
105
+ for (const candidate of [
106
+ 0,
107
+ 1,
108
+ 2
109
+ ]) {
110
+ let min = Infinity;
111
+ let max = -Infinity;
112
+ for (const p of points) {
113
+ min = Math.min(min, p[candidate]);
114
+ max = Math.max(max, p[candidate]);
115
+ }
116
+ if (max - min > widest) {
117
+ axis = candidate;
118
+ widest = max - min;
119
+ }
120
+ }
121
+ return axis;
122
+ }
123
+ /**
124
+ * Pair each anchor with its nearest face within `tolerance`. Returns undefined
125
+ * unless the pairing is one-to-one over every face, so an unexpected topology
126
+ * records nothing rather than wrong names. Candidates are windowed along the
127
+ * axis the face centers spread furthest on: a profile in the YZ plane puts
128
+ * every side face at one X, which would make a fixed X window scan them all.
129
+ */
130
+ function matchAnchors(anchors, faces, tolerance) {
131
+ if (anchors.length !== faces.length) return void 0;
132
+ const axis = widestAxis(faces.map((f) => f.point));
133
+ const sorted = [...faces].sort((a, b) => a.point[axis] - b.point[axis]);
134
+ const keys = sorted.map((f) => f.point[axis]);
135
+ const claimed = /* @__PURE__ */ new Set();
136
+ const roles = /* @__PURE__ */ new Map();
137
+ for (const { role, point } of anchors) {
138
+ let best = -1;
139
+ let bestDistance = tolerance;
140
+ for (let i = lowerBound(keys, point[axis] - tolerance); i < sorted.length; i++) {
141
+ const face = sorted[i];
142
+ if (face === void 0 || face.point[axis] > point[axis] + tolerance) break;
143
+ const d = require_vecOps.vecDistance(face.point, point);
144
+ if (d <= bestDistance) {
145
+ best = i;
146
+ bestDistance = d;
147
+ }
148
+ }
149
+ const match = best < 0 ? void 0 : sorted[best];
150
+ if (match === void 0 || claimed.has(best)) return void 0;
151
+ claimed.add(best);
152
+ roles.set(match.hash, role);
153
+ }
154
+ return roles;
155
+ }
156
+ /**
157
+ * Record `extrude:*` face roles on `solid`, the extrusion of `profile` along
158
+ * `vector`, for `assignRoles(solid, 'extrude')` to read. Records nothing on a
159
+ * mesh kernel, or when the faces don't pair one-to-one with the profile's caps
160
+ * and edges; `assignRoles` then falls back to positional names.
161
+ */
162
+ function recordExtrudeRoles(solid, profile, vector) {
163
+ const kernel = require_shapeTypes.getKernel();
164
+ if (!kernel.capabilities.exact) return;
165
+ const profileBox = kernel.boundingBox(profile.wrapped);
166
+ const size = require_vecOps.vecDistance(profileBox.min, profileBox.max) + require_vecOps.vecLength(vector);
167
+ const roles = matchAnchors(anchorsFor(profile.wrapped, centerOf(profileBox), vector), locateFaces(solid.wrapped), RELATIVE_TOLERANCE * size);
168
+ if (roles) require_faceRoleFns.setFaceRoles(solid, roles);
169
+ }
170
+ //#endregion
17
171
  //#region src/operations/extrudeFns.ts
18
172
  /**
19
173
  * Basic extrusion operations — extrude and revolve.
@@ -24,6 +178,10 @@ opentype_js = require_rolldown_runtime.__toESM(opentype_js, 1);
24
178
  /**
25
179
  * Extrude a face along a vector to produce a solid.
26
180
  *
181
+ * The result carries semantic face roles (`extrude:start`, `extrude:end`,
182
+ * `extrude:side:<i>`, `extrude:hole<j>:side:<i>`) that
183
+ * `assignRoles(solid, 'extrude')` returns in place of positional names.
184
+ *
27
185
  * @param face - The planar face to extrude.
28
186
  * @param extrusionVec - Direction and magnitude of the extrusion as `[x, y, z]`.
29
187
  * @returns `Result` containing the extruded solid, or an error if validation or operation fails.
@@ -39,6 +197,7 @@ function extrude(face, extrusionVec) {
39
197
  const downcastShape = kernel.downcast(shape, "solid");
40
198
  const solid = require_shapeTypes.createSolid(downcastShape);
41
199
  require_shapeTypes.disposeDowncastSource(shape, solid);
200
+ recordExtrudeRoles(solid, face, extrusionVec);
42
201
  return require_errors.ok(solid);
43
202
  } catch (e) {
44
203
  return require_errors.err(require_errors.kernelError("EXTRUDE_FAILED", "Extrusion operation failed", e, {
@@ -1,5 +1,5 @@
1
1
  const require_errors = require("./errors-jwhfQJZK.cjs");
2
- const require_textBlueprints = require("./textBlueprints-BE9lHH5V.cjs");
2
+ const require_textBlueprints = require("./textBlueprints-fa7VHJZz.cjs");
3
3
  //#region src/text/sketchText.ts
4
4
  /**
5
5
  * Render text as 3D sketch outlines on a plane.
@@ -1,5 +1,5 @@
1
1
  import { E as ok, d as validationError, g as err, t as BrepErrorCode } from "./errors-Zb3jBa0u.js";
2
- import { g as wrapSketchData, i as Sketches, n as getFont, t as textBlueprints, v as CompoundSketch } from "./textBlueprints-3jLY3G3u.js";
2
+ import { g as wrapSketchData, i as Sketches, n as getFont, t as textBlueprints, v as CompoundSketch } from "./textBlueprints-C13NAA3C.js";
3
3
  //#region src/text/sketchText.ts
4
4
  /**
5
5
  * Render text as 3D sketch outlines on a plane.
@@ -2,11 +2,11 @@ import { F as createKernelHandle, G as _usingCtx, N as DisposalScope, n as castR
2
2
  import { E as ok, d as validationError, g as err, n as computationError, r as ioError, t as BrepErrorCode, x as isOk } from "./errors-Zb3jBa0u.js";
3
3
  import { d as vecNormalize, s as vecIsZero } from "./vecOps-SKPRvPH-.js";
4
4
  import { b as fromBREP } from "./faceFns-CTlJC5IY.js";
5
- import { h as fuseAll } from "./solidBuilders-BwOF7M-p.js";
6
- import { E as wire, h as line } from "./primitiveFns-CcaoYdzl.js";
5
+ import { h as fuseAll } from "./solidBuilders-IstbiWju.js";
6
+ import { E as wire, h as line } from "./primitiveFns-CGJzS4MO.js";
7
7
  import { s as toBREP } from "./shapeFns--1wNlcc_.js";
8
8
  import { t as loft } from "./loftFns-B5mq1WDh.js";
9
- import { c as resolveRefParams } from "./refResolveFns-C0_Wx7nM.js";
9
+ import { c as resolveRefParams } from "./refResolveFns-CpVZoeOT.js";
10
10
  //#region src/utils/uuid.ts
11
11
  /** Generate a v4-style UUID string using `crypto.getRandomValues`. */
12
12
  function uuidv() {
@@ -2,11 +2,11 @@ const require_shapeTypes = require("./shapeTypes-DH2ShBU_.cjs");
2
2
  const require_errors = require("./errors-jwhfQJZK.cjs");
3
3
  const require_vecOps = require("./vecOps-CCnJt-yH.cjs");
4
4
  const require_faceFns = require("./faceFns-CZeHWke7.cjs");
5
- const require_solidBuilders = require("./solidBuilders-6eLtWBLM.cjs");
6
- const require_primitiveFns = require("./primitiveFns-DayTOw7C.cjs");
5
+ const require_solidBuilders = require("./solidBuilders-CgicU3le.cjs");
6
+ const require_primitiveFns = require("./primitiveFns-ZV3aMbqG.cjs");
7
7
  const require_shapeFns = require("./shapeFns-C2j6oZ2u.cjs");
8
8
  const require_loftFns = require("./loftFns-DL9UsQhd.cjs");
9
- const require_refResolveFns = require("./refResolveFns-BJG5h8ce.cjs");
9
+ const require_refResolveFns = require("./refResolveFns-Ct52Uw7R.cjs");
10
10
  //#region src/utils/uuid.ts
11
11
  /** Generate a v4-style UUID string using `crypto.getRandomValues`. */
12
12
  function uuidv() {
@@ -0,0 +1,15 @@
1
+ import { ShapeEvolution } from '../../kernel/types.js';
2
+ import { AnyShape, Dimension } from '../../core/shapeTypes.js';
3
+ /** O(1) check whether a shape carries recorded face roles. */
4
+ export declare function hasFaceRoles(shape: AnyShape<Dimension>): boolean;
5
+ /** Record face roles (face hash → role name) on a shape, replacing any it had. */
6
+ export declare function setFaceRoles(shape: AnyShape<Dimension>, roles: ReadonlyMap<number, string>): void;
7
+ /** The face roles recorded on a shape (face hash → role name), if any. */
8
+ export declare function getFaceRoles(shape: AnyShape<Dimension>): ReadonlyMap<number, string> | undefined;
9
+ /**
10
+ * Carry recorded face roles from inputs to a result through a ShapeEvolution:
11
+ * deleted faces drop their role, a modified face passes it to every successor,
12
+ * and an untouched face keeps it. When two inputs' faces land on one result
13
+ * face, the first input's role wins.
14
+ */
15
+ export declare function propagateFaceRolesFromEvolution(evolution: ShapeEvolution, inputs: readonly AnyShape<Dimension>[], result: AnyShape<Dimension>): void;
@@ -8,13 +8,13 @@ import { AnyShape, Dimension } from '../../core/shapeTypes.js';
8
8
  */
9
9
  /**
10
10
  * O(1) check: does a shape carry any propagatable metadata (face origins,
11
- * tags, or colors)? Lets callers skip both expensive face iteration and
11
+ * tags, colors, or recorded roles)? Lets callers skip both expensive face iteration and
12
12
  * metadata-preserving slow paths when there's nothing to preserve.
13
13
  */
14
14
  export declare function hasAnyMetadata(shape: AnyShape<Dimension>): boolean;
15
15
  export declare function collectInputFaceHashes(inputs: readonly AnyShape<Dimension>[]): number[];
16
16
  /**
17
- * Propagate all metadata (origins, tags, colors) from inputs to result
17
+ * Propagate all metadata (origins, tags, colors, recorded roles) from inputs to result
18
18
  * using a kernel-provided ShapeEvolution record.
19
19
  *
20
20
  * This is the standard pipeline for any operation that returns
@@ -0,0 +1,9 @@
1
+ import { Vec3 } from '../../core/types.js';
2
+ import { Dimension, Face, Shape3D } from '../../core/shapeTypes.js';
3
+ /**
4
+ * Record `extrude:*` face roles on `solid`, the extrusion of `profile` along
5
+ * `vector`, for `assignRoles(solid, 'extrude')` to read. Records nothing on a
6
+ * mesh kernel, or when the faces don't pair one-to-one with the profile's caps
7
+ * and edges; `assignRoles` then falls back to positional names.
8
+ */
9
+ export declare function recordExtrudeRoles(solid: Shape3D, profile: Face<Dimension>, vector: Vec3): void;
@@ -39,7 +39,8 @@ export declare function resolveLineageRef(ref: LineageRef, roles: RoleTable, sha
39
39
  * Resolve a lineage ref against a freshly rebuilt `shape` with no maintained
40
40
  * role table, re-deriving roles via `assignRoles(shape, ref.origin)`. The ref's
41
41
  * `origin` must therefore be the role-assignment scheme (e.g. `'box'`), and
42
- * stability is bounded by that scheme — `'box'` names faces semantically
42
+ * stability is bounded by that scheme. The primitives (`'box'`, `'cylinder'`,
43
+ * `'cone'`, `'sphere'`) and `'extrude'` name faces semantically
43
44
  * (rebuild-stable); other schemes fall back to positional `face_N`.
44
45
  */
45
46
  export declare function resolveRefIn(ref: LineageRef, shape: Shape3D): LineageResolution;
@@ -13,12 +13,18 @@ export declare function captureHint(face: Face): GeometricHint;
13
13
  * - `cylinder`/`cone` (Z-axis): 'top'/'bottom' caps + 'lateral' wall.
14
14
  * - `sphere`: 'sphere:surface'.
15
15
  *
16
+ * Faces whose roles an operation recorded on the shape take those names when
17
+ * the namespace matches `operationType`. `extrude` records 'extrude:start',
18
+ * 'extrude:end', 'extrude:side:<i>' and 'extrude:hole<j>:side:<i>', which
19
+ * survive later moves and booleans.
20
+ *
16
21
  * Faces a primitive namer doesn't recognize (a rotated box's non-cardinal faces),
17
22
  * and every face of any other operation type, fall back to positional names
18
23
  * ('opType:face_0', 'opType:face_1', ...) — so each face always gets a role.
19
24
  *
20
- * @returns Map from role name to its face hash codes (one at assignment time;
21
- * a role accrues more hashes only later, when `updateRoles` tracks a split).
25
+ * @returns Map from role name to its face hash codes (one per role, except a
26
+ * recorded role whose face a later operation split; `updateRoles` adds more
27
+ * when it tracks a split).
22
28
  */
23
29
  export declare function assignRoles(shape: Shape3D, operationType: string): Map<string, number[]>;
24
30
  /** Create a ShapeRef from an origin ID, role name, and face. */
package/dist/topology.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_topologyQueryFns = require("./topologyQueryFns-q2bGyuEV.cjs");
3
3
  const require_faceFns = require("./faceFns-CZeHWke7.cjs");
4
- const require_solidBuilders = require("./solidBuilders-6eLtWBLM.cjs");
5
- const require_primitiveFns = require("./primitiveFns-DayTOw7C.cjs");
4
+ const require_solidBuilders = require("./solidBuilders-CgicU3le.cjs");
5
+ const require_primitiveFns = require("./primitiveFns-ZV3aMbqG.cjs");
6
6
  const require_shapeFns = require("./shapeFns-C2j6oZ2u.cjs");
7
7
  const require_curveFns = require("./curveFns-6-ULFrEB.cjs");
8
8
  const require_meshFns = require("./meshFns-CAxkaRTm.cjs");
9
- const require_healingFns = require("./healingFns-DziPRwmh.cjs");
9
+ const require_healingFns = require("./healingFns-DwSpJZfg.cjs");
10
10
  const require_adjacencyFns = require("./adjacencyFns-1rxgJ6Hw.cjs");
11
11
  exports.addHoles = require_primitiveFns.addHoles;
12
12
  exports.adjacentFaces = require_adjacencyFns.adjacentFaces;
package/dist/topology.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { _ as iterFaces, b as iterVertices, c as getFaces, f as getVertices, g as iterEdges, m as invalidateShapeCache, n as getBounds, p as getWires, s as getEdges, w as vertexPosition, x as iterWires } from "./topologyQueryFns-DnfjQgP7.js";
2
2
  import { C as shapeType, S as iterTopo, _ as cast, a as faceOrientation, b as fromBREP, c as innerWires, d as pointOnSurface, f as projectPointOnFace, g as asTopo, h as uvCoordinates, i as faceGeomType, l as normalAt, m as uvBounds, n as faceAxis, o as flipFaceOrientation, r as faceCenter, s as getSurfaceType, t as classifyPointOnFace, u as outerWire, x as isCompSolid, y as downcast } from "./faceFns-CTlJC5IY.js";
3
- import { h as fuseAll, p as cutAll } from "./solidBuilders-BwOF7M-p.js";
4
- import { C as threePointArc, D as wireLoop, E as wire, S as tangentArc, T as vertex, _ as polygon, a as circle, b as sphere, c as cylinder, d as ellipsoid, f as face, g as offsetFace, h as line, i as bsplineApprox, l as ellipse, m as helix, n as bezier, o as compound, p as filledFace, r as box, s as cone, t as addHoles, u as ellipseArc, v as sewShells, w as torus, x as subFace, y as solid } from "./primitiveFns-CcaoYdzl.js";
3
+ import { h as fuseAll, p as cutAll } from "./solidBuilders-IstbiWju.js";
4
+ import { C as threePointArc, D as wireLoop, E as wire, S as tangentArc, T as vertex, _ as polygon, a as circle, b as sphere, c as cylinder, d as ellipsoid, f as face, g as offsetFace, h as line, i as bsplineApprox, l as ellipse, m as helix, n as bezier, o as compound, p as filledFace, r as box, s as cone, t as addHoles, u as ellipseArc, v as sewShells, w as torus, x as subFace, y as solid } from "./primitiveFns-CGJzS4MO.js";
5
5
  import { a as isSameShape, i as isEqualShape, n as getHashCode } from "./shapeFns--1wNlcc_.js";
6
6
  import { a as curveIsPeriodic, c as curvePointAt, d as flipOrientation, f as getCurveType, h as offsetWire2D, i as curveIsClosed, l as curveStartPoint, m as interpolateCurve, n as curveAxis, o as curveLength, p as getOrientation, r as curveEndPoint, s as curvePeriod, t as approximateCurve, u as curveTangentAt } from "./curveFns-KS1BWGhF.js";
7
7
  import { d as clearMeshCache, f as createMeshCache, n as exportSTEP, r as exportSTL, t as exportIGES } from "./meshFns-COlno8TY.js";
8
- import { A as toBufferGeometryData, P as toLineGeometryData, S as chamferDistAngle, _ as checkBoolean, a as healFace, b as getNurbsCurveData, d as chamferWithEvolution, f as cutWithEvolution, g as shellWithEvolution, h as intersectWithEvolution, j as toGroupedBufferGeometryData, k as variableFillet, l as solidFromShell, m as fuseWithEvolution, n as fixSelfIntersection, o as healSolid, p as filletWithEvolution, r as fixShape, s as healWire, t as autoHeal, u as positionOnCurve, v as cutAllBisect, x as getNurbsSurfaceData, y as fuseAllBisect } from "./healingFns-BDkAwJNy.js";
8
+ import { A as toBufferGeometryData, P as toLineGeometryData, S as chamferDistAngle, _ as checkBoolean, a as healFace, b as getNurbsCurveData, d as chamferWithEvolution, f as cutWithEvolution, g as shellWithEvolution, h as intersectWithEvolution, j as toGroupedBufferGeometryData, k as variableFillet, l as solidFromShell, m as fuseWithEvolution, n as fixSelfIntersection, o as healSolid, p as filletWithEvolution, r as fixShape, s as healWire, t as autoHeal, u as positionOnCurve, v as cutAllBisect, x as getNurbsSurfaceData, y as fuseAllBisect } from "./healingFns-Ct3gEMvk.js";
9
9
  import { i as facesOfEdge, l as wiresOfFace, n as adjacentFaces, o as sharedEdges, r as edgesOfFace, s as verticesOfEdge } from "./adjacencyFns-DeyXahej.js";
10
10
  export { addHoles, adjacentFaces, approximateCurve, asTopo, autoHeal, bezier, box, bsplineApprox, cast, chamferDistAngle as chamferDistAngleShape, chamferWithEvolution, checkBoolean, circle, classifyPointOnFace, clearMeshCache, compound, cone, createMeshCache, curveAxis, curveEndPoint, curveIsClosed, curveIsPeriodic, curveLength, curvePeriod, curvePointAt, curveStartPoint, curveTangentAt, cutAll, cutAllBisect, cutWithEvolution, cylinder, fromBREP as deserializeShape, downcast, edgesOfFace, ellipse, ellipseArc, ellipsoid, exportIGES, exportSTEP, exportSTL, face, faceAxis, faceCenter, faceGeomType, faceOrientation, facesOfEdge, filledFace, filletWithEvolution, fixSelfIntersection, fixShape, flipFaceOrientation, flipOrientation, fuseAll, fuseAllBisect, fuseWithEvolution, getBounds, getCurveType, getEdges, getFaces, getHashCode, getNurbsCurveData, getNurbsSurfaceData, getOrientation, getSurfaceType, getVertices, getWires, healFace, healSolid, healWire, helix, innerWires, interpolateCurve, intersectWithEvolution, invalidateShapeCache, isCompSolid, isEqualShape, isSameShape, iterEdges, iterFaces, iterTopo, iterVertices, iterWires, line, normalAt, offsetFace, offsetWire2D, outerWire, pointOnSurface, polygon, positionOnCurve, projectPointOnFace, sewShells, shapeType, sharedEdges, shellWithEvolution, solid, solidFromShell, sphere, subFace, tangentArc, threePointArc, toBufferGeometryData, toGroupedBufferGeometryData, toLineGeometryData, torus, uvBounds, uvCoordinates, variableFillet, vertex, vertexPosition, verticesOfEdge, wire, wireLoop, wiresOfFace };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brepjs",
3
- "version": "20.3.0",
3
+ "version": "20.4.0",
4
4
  "description": "Web CAD library with pluggable geometry kernel",
5
5
  "keywords": [
6
6
  "cad",