@faicad/faijs 0.16.1 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +4 -5
- package/NOTICE +5 -6
- package/dist/api/api-namespace.d.ts.map +1 -1
- package/dist/api/api-namespace.js +20 -2
- package/dist/api/api-namespace.js.map +1 -1
- package/dist/api/assembly/entities.d.ts +1 -1
- package/dist/api/assembly/entities.d.ts.map +1 -1
- package/dist/api/assembly/entities.js.map +1 -1
- package/dist/api/assembly/joints.d.ts +2 -2
- package/dist/api/assembly/joints.d.ts.map +1 -1
- package/dist/api/assembly/joints.js +2 -2
- package/dist/api/assembly/joints.js.map +1 -1
- package/dist/api/assembly/lower.d.ts +1 -1
- package/dist/api/assembly/lower.d.ts.map +1 -1
- package/dist/api/assembly/lower.js.map +1 -1
- package/dist/api/assembly/pose.d.ts +3 -3
- package/dist/api/assembly/pose.d.ts.map +1 -1
- package/dist/api/assembly/pose.js +1 -1
- package/dist/api/assembly/pose.js.map +1 -1
- package/dist/api/assembly/preview.d.ts +1 -1
- package/dist/api/assembly/preview.d.ts.map +1 -1
- package/dist/api/assembly/preview.js +1 -1
- package/dist/api/assembly/preview.js.map +1 -1
- package/dist/api/assembly/solve.d.ts.map +1 -1
- package/dist/api/assembly/solve.js +3 -3
- package/dist/api/assembly/solve.js.map +1 -1
- package/dist/api/assembly/solvers/assembly-tree.d.ts +98 -0
- package/dist/api/assembly/solvers/assembly-tree.d.ts.map +1 -0
- package/dist/api/assembly/solvers/assembly-tree.js +130 -0
- package/dist/api/assembly/solvers/assembly-tree.js.map +1 -0
- package/dist/api/assembly/solvers/chain-solver.d.ts +27 -0
- package/dist/api/assembly/solvers/chain-solver.d.ts.map +1 -0
- package/dist/api/assembly/solvers/chain-solver.js +330 -0
- package/dist/api/assembly/solvers/chain-solver.js.map +1 -0
- package/dist/api/assembly/solvers/global-solver.js +2 -2
- package/dist/api/assembly/solvers/global-solver.js.map +1 -1
- package/dist/api/assembly/solvers/joints-kinematics.d.ts +308 -0
- package/dist/api/assembly/solvers/joints-kinematics.d.ts.map +1 -0
- package/dist/api/assembly/solvers/joints-kinematics.js +643 -0
- package/dist/api/assembly/solvers/joints-kinematics.js.map +1 -0
- package/dist/api/assembly/solvers/quat.d.ts +35 -0
- package/dist/api/assembly/solvers/quat.d.ts.map +1 -0
- package/dist/api/assembly/solvers/quat.js +84 -0
- package/dist/api/assembly/solvers/quat.js.map +1 -0
- package/dist/api/assembly/solvers/types.d.ts +33 -0
- package/dist/api/assembly/solvers/types.d.ts.map +1 -1
- package/dist/api/assembly/solvers/types.js.map +1 -1
- package/dist/api/boolean.d.ts.map +1 -1
- package/dist/api/boolean.js +66 -29
- package/dist/api/boolean.js.map +1 -1
- package/dist/api/brep-mirror/booleanFns.d.ts +40 -0
- package/dist/api/brep-mirror/booleanFns.d.ts.map +1 -0
- package/dist/api/brep-mirror/booleanFns.js +104 -0
- package/dist/api/brep-mirror/booleanFns.js.map +1 -0
- package/dist/api/brep-mirror/brepHelpers.d.ts +55 -0
- package/dist/api/brep-mirror/brepHelpers.d.ts.map +1 -0
- package/dist/api/brep-mirror/brepHelpers.js +131 -0
- package/dist/api/brep-mirror/brepHelpers.js.map +1 -0
- package/dist/api/brep-mirror/compoundFns.d.ts +47 -0
- package/dist/api/brep-mirror/compoundFns.d.ts.map +1 -0
- package/dist/api/brep-mirror/compoundFns.js +300 -0
- package/dist/api/brep-mirror/compoundFns.js.map +1 -0
- package/dist/api/brep-mirror/healingFns.d.ts +78 -0
- package/dist/api/brep-mirror/healingFns.d.ts.map +1 -0
- package/dist/api/brep-mirror/healingFns.js +294 -0
- package/dist/api/brep-mirror/healingFns.js.map +1 -0
- package/dist/api/brep-mirror/hullFns.d.ts +20 -0
- package/dist/api/brep-mirror/hullFns.d.ts.map +1 -0
- package/dist/api/brep-mirror/hullFns.js +46 -0
- package/dist/api/brep-mirror/hullFns.js.map +1 -0
- package/dist/api/brep-mirror/patternFns.d.ts +43 -0
- package/dist/api/brep-mirror/patternFns.d.ts.map +1 -0
- package/dist/api/brep-mirror/patternFns.js +178 -0
- package/dist/api/brep-mirror/patternFns.js.map +1 -0
- package/dist/api/brep-mirror/primitiveFns.d.ts +42 -0
- package/dist/api/brep-mirror/primitiveFns.d.ts.map +1 -0
- package/dist/api/brep-mirror/primitiveFns.js +104 -0
- package/dist/api/brep-mirror/primitiveFns.js.map +1 -0
- package/dist/api/brep-mirror/roofFns.d.ts +24 -0
- package/dist/api/brep-mirror/roofFns.d.ts.map +1 -0
- package/dist/api/brep-mirror/roofFns.js +229 -0
- package/dist/api/brep-mirror/roofFns.js.map +1 -0
- package/dist/api/brep-mirror/straightSkeleton.d.ts +36 -0
- package/dist/api/brep-mirror/straightSkeleton.d.ts.map +1 -0
- package/dist/api/brep-mirror/straightSkeleton.js +443 -0
- package/dist/api/brep-mirror/straightSkeleton.js.map +1 -0
- package/dist/api/brep-mirror/sweepFns.d.ts +55 -0
- package/dist/api/brep-mirror/sweepFns.d.ts.map +1 -0
- package/dist/api/brep-mirror/sweepFns.js +200 -0
- package/dist/api/brep-mirror/sweepFns.js.map +1 -0
- package/dist/api/brep-mirror/threadFns.d.ts +15 -0
- package/dist/api/brep-mirror/threadFns.d.ts.map +1 -1
- package/dist/api/brep-mirror/threadFns.js +37 -2
- package/dist/api/brep-mirror/threadFns.js.map +1 -1
- package/dist/api/brep-mirror/topologyFns.d.ts +74 -0
- package/dist/api/brep-mirror/topologyFns.d.ts.map +1 -0
- package/dist/api/brep-mirror/topologyFns.js +276 -0
- package/dist/api/brep-mirror/topologyFns.js.map +1 -0
- package/dist/api/brep-topology.d.ts +190 -0
- package/dist/api/brep-topology.d.ts.map +1 -0
- package/dist/api/brep-topology.js +337 -0
- package/dist/api/brep-topology.js.map +1 -0
- package/dist/api/brepjs-compat/constants.d.ts +11 -0
- package/dist/api/brepjs-compat/constants.d.ts.map +1 -0
- package/dist/api/brepjs-compat/constants.js +11 -0
- package/dist/api/brepjs-compat/constants.js.map +1 -0
- package/dist/api/brepjs-compat/index.d.ts +19 -232
- package/dist/api/brepjs-compat/index.d.ts.map +1 -1
- package/dist/api/brepjs-compat/index.js +19 -286
- package/dist/api/brepjs-compat/index.js.map +1 -1
- package/dist/api/brepjs-compat/planeOps.d.ts +98 -0
- package/dist/api/brepjs-compat/planeOps.d.ts.map +1 -0
- package/dist/api/brepjs-compat/planeOps.js +170 -0
- package/dist/api/brepjs-compat/planeOps.js.map +1 -0
- package/dist/api/brepjs-compat/planeTypes.d.ts +24 -0
- package/dist/api/brepjs-compat/planeTypes.d.ts.map +1 -0
- package/dist/api/brepjs-compat/planeTypes.js +8 -0
- package/dist/api/brepjs-compat/planeTypes.js.map +1 -0
- package/dist/api/brepjs-compat/types.d.ts +64 -0
- package/dist/api/brepjs-compat/types.d.ts.map +1 -0
- package/dist/api/brepjs-compat/types.js +48 -0
- package/dist/api/brepjs-compat/types.js.map +1 -0
- package/dist/api/brepjs-compat/vecOps.d.ts +124 -0
- package/dist/api/brepjs-compat/vecOps.d.ts.map +1 -0
- package/dist/api/brepjs-compat/vecOps.js +202 -0
- package/dist/api/brepjs-compat/vecOps.js.map +1 -0
- package/dist/api/chamfer.d.ts +12 -3
- package/dist/api/chamfer.d.ts.map +1 -1
- package/dist/api/chamfer.js +54 -20
- package/dist/api/chamfer.js.map +1 -1
- package/dist/api/compound-geom.d.ts.map +1 -1
- package/dist/api/compound-geom.js +8 -2
- package/dist/api/compound-geom.js.map +1 -1
- package/dist/api/draft.d.ts +69 -0
- package/dist/api/draft.d.ts.map +1 -0
- package/dist/api/draft.js +109 -0
- package/dist/api/draft.js.map +1 -0
- package/dist/api/edge-ref.d.ts.map +1 -1
- package/dist/api/edge-ref.js +2 -2
- package/dist/api/edge-ref.js.map +1 -1
- package/dist/api/engrave.d.ts.map +1 -1
- package/dist/api/engrave.js +2 -3
- package/dist/api/engrave.js.map +1 -1
- package/dist/api/extrude.d.ts.map +1 -1
- package/dist/api/extrude.js +44 -14
- package/dist/api/extrude.js.map +1 -1
- package/dist/api/face-ref.d.ts.map +1 -1
- package/dist/api/face-ref.js +2 -2
- package/dist/api/face-ref.js.map +1 -1
- package/dist/api/feature-repair.d.ts +137 -0
- package/dist/api/feature-repair.d.ts.map +1 -0
- package/dist/api/feature-repair.js +221 -0
- package/dist/api/feature-repair.js.map +1 -0
- package/dist/api/fillet-variable.d.ts +35 -0
- package/dist/api/fillet-variable.d.ts.map +1 -0
- package/dist/api/fillet-variable.js +71 -0
- package/dist/api/fillet-variable.js.map +1 -0
- package/dist/api/fillet.d.ts +3 -0
- package/dist/api/fillet.d.ts.map +1 -1
- package/dist/api/fillet.js +7 -4
- package/dist/api/fillet.js.map +1 -1
- package/dist/api/generated/2d.d.ts +1 -13
- package/dist/api/generated/2d.d.ts.map +1 -1
- package/dist/api/generated/2d.js +6 -1
- package/dist/api/generated/2d.js.map +1 -1
- package/dist/api/generated/brepjs/index.d.ts +298 -298
- package/dist/api/generated/brepjs/index.d.ts.map +1 -1
- package/dist/api/generated/brepjs/index.js +183 -183
- package/dist/api/generated/brepjs/index.js.map +1 -1
- package/dist/api/generated/core.d.ts +3 -123
- package/dist/api/generated/core.d.ts.map +1 -1
- package/dist/api/generated/core.js +2 -81
- package/dist/api/generated/core.js.map +1 -1
- package/dist/api/generated/gear.d.ts +1 -15
- package/dist/api/generated/gear.d.ts.map +1 -1
- package/dist/api/generated/gear.js +6 -3
- package/dist/api/generated/gear.js.map +1 -1
- package/dist/api/generated/io.d.ts +1 -13
- package/dist/api/generated/io.d.ts.map +1 -1
- package/dist/api/generated/io.js +6 -1
- package/dist/api/generated/io.js.map +1 -1
- package/dist/api/generated/kernel.d.ts +1 -39
- package/dist/api/generated/kernel.d.ts.map +1 -1
- package/dist/api/generated/kernel.js +6 -4
- package/dist/api/generated/kernel.js.map +1 -1
- package/dist/api/generated/measurement.d.ts +53 -97
- package/dist/api/generated/measurement.d.ts.map +1 -1
- package/dist/api/generated/measurement.js +48 -143
- package/dist/api/generated/measurement.js.map +1 -1
- package/dist/api/generated/ns.d.ts +1 -10
- package/dist/api/generated/ns.d.ts.map +1 -1
- package/dist/api/generated/ns.js +2 -10
- package/dist/api/generated/ns.js.map +1 -1
- package/dist/api/generated/operations.d.ts +65 -110
- package/dist/api/generated/operations.d.ts.map +1 -1
- package/dist/api/generated/operations.js +132 -80
- package/dist/api/generated/operations.js.map +1 -1
- package/dist/api/generated/projection.d.ts +1 -8
- package/dist/api/generated/projection.d.ts.map +1 -1
- package/dist/api/generated/projection.js +6 -4
- package/dist/api/generated/projection.js.map +1 -1
- package/dist/api/generated/query.d.ts +1 -9
- package/dist/api/generated/query.d.ts.map +1 -1
- package/dist/api/generated/query.js +6 -1
- package/dist/api/generated/query.js.map +1 -1
- package/dist/api/generated/script-face-manifest.d.ts +2 -0
- package/dist/api/generated/script-face-manifest.d.ts.map +1 -1
- package/dist/api/generated/script-face-manifest.js +22 -10
- package/dist/api/generated/script-face-manifest.js.map +1 -1
- package/dist/api/generated/script-face.d.ts +52 -27
- package/dist/api/generated/script-face.d.ts.map +1 -1
- package/dist/api/generated/script-face.js +18 -4
- package/dist/api/generated/script-face.js.map +1 -1
- package/dist/api/generated/sketching.d.ts +4 -7
- package/dist/api/generated/sketching.d.ts.map +1 -1
- package/dist/api/generated/sketching.js +10 -8
- package/dist/api/generated/sketching.js.map +1 -1
- package/dist/api/generated/text.d.ts +1 -6
- package/dist/api/generated/text.d.ts.map +1 -1
- package/dist/api/generated/text.js +6 -3
- package/dist/api/generated/text.js.map +1 -1
- package/dist/api/generated/topology.d.ts +77 -175
- package/dist/api/generated/topology.d.ts.map +1 -1
- package/dist/api/generated/topology.js +172 -131
- package/dist/api/generated/topology.js.map +1 -1
- package/dist/api/geom.d.ts.map +1 -1
- package/dist/api/geom.js +2 -2
- package/dist/api/geom.js.map +1 -1
- package/dist/api/helix.d.ts +51 -0
- package/dist/api/helix.d.ts.map +1 -0
- package/dist/api/helix.js +63 -0
- package/dist/api/helix.js.map +1 -0
- package/dist/api/import-step.d.ts.map +1 -1
- package/dist/api/import-step.js +6 -2
- package/dist/api/import-step.js.map +1 -1
- package/dist/api/index.d.ts +20 -6
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +30 -13
- package/dist/api/index.js.map +1 -1
- package/dist/api/internal/compat-op.d.ts +10 -0
- package/dist/api/internal/compat-op.d.ts.map +1 -1
- package/dist/api/internal/compat-op.js +9 -3
- package/dist/api/internal/compat-op.js.map +1 -1
- package/dist/api/internal/compat-projection.d.ts +4 -4
- package/dist/api/internal/compat-projection.js +7 -7
- package/dist/api/internal/compat-projection.js.map +1 -1
- package/dist/api/internal/l3-bridge.d.ts +75 -42
- package/dist/api/internal/l3-bridge.d.ts.map +1 -1
- package/dist/api/internal/l3-bridge.js +105 -50
- package/dist/api/internal/l3-bridge.js.map +1 -1
- package/dist/api/internal/profile-wire.d.ts +31 -0
- package/dist/api/internal/profile-wire.d.ts.map +1 -0
- package/dist/api/internal/profile-wire.js +37 -0
- package/dist/api/internal/profile-wire.js.map +1 -0
- package/dist/api/internal/replica-role-table.js +2 -2
- package/dist/api/internal/replica-role-table.js.map +1 -1
- package/dist/api/loft.d.ts +66 -0
- package/dist/api/loft.d.ts.map +1 -0
- package/dist/api/loft.js +111 -0
- package/dist/api/loft.js.map +1 -0
- package/dist/api/measurement/index.d.ts +51 -0
- package/dist/api/measurement/index.d.ts.map +1 -0
- package/dist/api/measurement/index.js +71 -0
- package/dist/api/measurement/index.js.map +1 -0
- package/dist/api/occt-kernel-bridge.d.ts +5 -8
- package/dist/api/occt-kernel-bridge.d.ts.map +1 -1
- package/dist/api/occt-kernel-bridge.js +18 -14
- package/dist/api/occt-kernel-bridge.js.map +1 -1
- package/dist/api/pattern.d.ts.map +1 -1
- package/dist/api/pattern.js +3 -4
- package/dist/api/pattern.js.map +1 -1
- package/dist/api/place.d.ts.map +1 -1
- package/dist/api/place.js +2 -4
- package/dist/api/place.js.map +1 -1
- package/dist/api/primitives.d.ts.map +1 -1
- package/dist/api/primitives.js +3 -4
- package/dist/api/primitives.js.map +1 -1
- package/dist/api/profile.d.ts +89 -0
- package/dist/api/profile.d.ts.map +1 -0
- package/dist/api/profile.js +194 -0
- package/dist/api/profile.js.map +1 -0
- package/dist/api/replicate.d.ts +28 -1
- package/dist/api/replicate.d.ts.map +1 -1
- package/dist/api/replicate.js +34 -23
- package/dist/api/replicate.js.map +1 -1
- package/dist/api/result.d.ts +6 -11
- package/dist/api/result.d.ts.map +1 -1
- package/dist/api/result.js +6 -11
- package/dist/api/result.js.map +1 -1
- package/dist/api/revolve.d.ts.map +1 -1
- package/dist/api/revolve.js +15 -14
- package/dist/api/revolve.js.map +1 -1
- package/dist/api/screw.d.ts +3 -0
- package/dist/api/screw.d.ts.map +1 -1
- package/dist/api/screw.js +9 -4
- package/dist/api/screw.js.map +1 -1
- package/dist/api/sdf.d.ts +1 -1
- package/dist/api/section-by-plane.d.ts +42 -0
- package/dist/api/section-by-plane.d.ts.map +1 -0
- package/dist/api/section-by-plane.js +61 -0
- package/dist/api/section-by-plane.js.map +1 -0
- package/dist/api/shell.d.ts +45 -0
- package/dist/api/shell.d.ts.map +1 -0
- package/dist/api/shell.js +73 -0
- package/dist/api/shell.js.map +1 -0
- package/dist/api/sketch.d.ts +8 -1
- package/dist/api/sketch.d.ts.map +1 -1
- package/dist/api/sketch.js +12 -7
- package/dist/api/sketch.js.map +1 -1
- package/dist/api/split-by-plane.d.ts +41 -0
- package/dist/api/split-by-plane.d.ts.map +1 -0
- package/dist/api/split-by-plane.js +60 -0
- package/dist/api/split-by-plane.js.map +1 -0
- package/dist/api/split.d.ts +6 -1
- package/dist/api/split.d.ts.map +1 -1
- package/dist/api/split.js +23 -9
- package/dist/api/split.js.map +1 -1
- package/dist/api/surface/arg-spec.d.ts +22 -0
- package/dist/api/surface/arg-spec.d.ts.map +1 -1
- package/dist/api/surface/arg-spec.js +729 -477
- package/dist/api/surface/arg-spec.js.map +1 -1
- package/dist/api/sweep.d.ts +55 -0
- package/dist/api/sweep.d.ts.map +1 -0
- package/dist/api/sweep.js +86 -0
- package/dist/api/sweep.js.map +1 -0
- package/dist/api/thicken.d.ts +36 -0
- package/dist/api/thicken.d.ts.map +1 -0
- package/dist/api/thicken.js +55 -0
- package/dist/api/thicken.js.map +1 -0
- package/dist/api/transform.d.ts +8 -0
- package/dist/api/transform.d.ts.map +1 -1
- package/dist/api/transform.js +15 -4
- package/dist/api/transform.js.map +1 -1
- package/dist/api/view/cameraFns.d.ts +48 -0
- package/dist/api/view/cameraFns.d.ts.map +1 -0
- package/dist/api/view/cameraFns.js +75 -0
- package/dist/api/view/cameraFns.js.map +1 -0
- package/dist/api/view/projectionPlanes.d.ts +25 -0
- package/dist/api/view/projectionPlanes.d.ts.map +1 -0
- package/dist/api/view/projectionPlanes.js +30 -0
- package/dist/api/view/projectionPlanes.js.map +1 -0
- package/dist/api/view/view-camera.d.ts +2 -2
- package/dist/api/view/view-camera.d.ts.map +1 -1
- package/dist/api/view/view-camera.js +3 -3
- package/dist/api/view/view-camera.js.map +1 -1
- package/dist/api/view/view-projection.d.ts +9 -6
- package/dist/api/view/view-projection.d.ts.map +1 -1
- package/dist/api/view/view-projection.js +132 -65
- package/dist/api/view/view-projection.js.map +1 -1
- package/dist/api/wire.d.ts +45 -0
- package/dist/api/wire.d.ts.map +1 -0
- package/dist/api/wire.js +96 -0
- package/dist/api/wire.js.map +1 -0
- package/dist/boolean/creased-normals.d.ts +50 -0
- package/dist/boolean/creased-normals.d.ts.map +1 -0
- package/dist/boolean/creased-normals.js +114 -0
- package/dist/boolean/creased-normals.js.map +1 -0
- package/dist/boolean/deriveNormals.d.ts +4 -1
- package/dist/boolean/deriveNormals.d.ts.map +1 -1
- package/dist/boolean/deriveNormals.js +5 -2
- package/dist/boolean/deriveNormals.js.map +1 -1
- package/dist/brep/brep-ops.d.ts +6 -0
- package/dist/brep/brep-ops.d.ts.map +1 -1
- package/dist/brep/brep-ops.js +11 -2
- package/dist/brep/brep-ops.js.map +1 -1
- package/dist/brep/brep-topology.d.ts +4 -0
- package/dist/brep/brep-topology.d.ts.map +1 -1
- package/dist/brep/brep-topology.js +4 -0
- package/dist/brep/brep-topology.js.map +1 -1
- package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brep-mock.js +79 -59
- package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
- package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
- package/dist/brep/engine/adapters/brepkit.js +35 -2
- package/dist/brep/engine/adapters/brepkit.js.map +1 -1
- package/dist/brep/engine/adapters/occt.d.ts +15 -7
- package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
- package/dist/brep/engine/adapters/occt.js +64 -167
- package/dist/brep/engine/adapters/occt.js.map +1 -1
- package/dist/brep/engine/primitives.d.ts +93 -130
- package/dist/brep/engine/primitives.d.ts.map +1 -1
- package/dist/brep/engine/primitives.js +9 -7
- package/dist/brep/engine/primitives.js.map +1 -1
- package/dist/brep/engine/types.d.ts +14 -1
- package/dist/brep/engine/types.d.ts.map +1 -1
- package/dist/brep/engine/types.js +11 -1
- package/dist/brep/engine/types.js.map +1 -1
- package/dist/brep/export/step.d.ts +3 -0
- package/dist/brep/export/step.d.ts.map +1 -1
- package/dist/brep/export/step.js +7 -1
- package/dist/brep/export/step.js.map +1 -1
- package/dist/brep/face-evolution.d.ts +8 -0
- package/dist/brep/face-evolution.d.ts.map +1 -1
- package/dist/brep/face-evolution.js +15 -3
- package/dist/brep/face-evolution.js.map +1 -1
- package/dist/brep/handle-bridge.d.ts +20 -2
- package/dist/brep/handle-bridge.d.ts.map +1 -1
- package/dist/brep/handle-bridge.js +25 -2
- package/dist/brep/handle-bridge.js.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.d.ts +25 -5
- package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
- package/dist/brepkit-kernel/brepkitKernel.js +782 -218
- package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
- package/dist/brepkit-kernel/multi-version-test.d.ts +40 -0
- package/dist/brepkit-kernel/multi-version-test.d.ts.map +1 -0
- package/dist/brepkit-kernel/multi-version-test.js +89 -0
- package/dist/brepkit-kernel/multi-version-test.js.map +1 -0
- package/dist/cad-runtime/admit-compat-lib.d.ts +6 -1
- package/dist/cad-runtime/admit-compat-lib.d.ts.map +1 -1
- package/dist/cad-runtime/admit-compat-lib.js +5 -1
- package/dist/cad-runtime/admit-compat-lib.js.map +1 -1
- package/dist/cad-runtime/backend-dispatch.d.ts +9 -3
- package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
- package/dist/cad-runtime/backend-dispatch.js +32 -2
- package/dist/cad-runtime/backend-dispatch.js.map +1 -1
- package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
- package/dist/cad-runtime/direct-executor.js +8 -2
- package/dist/cad-runtime/direct-executor.js.map +1 -1
- package/dist/cad-runtime/runtime.d.ts +3 -0
- package/dist/cad-runtime/runtime.d.ts.map +1 -1
- package/dist/cad-runtime/runtime.js +3 -1
- package/dist/cad-runtime/runtime.js.map +1 -1
- package/dist/define-op.d.ts +18 -2
- package/dist/define-op.d.ts.map +1 -1
- package/dist/define-op.js +29 -1
- package/dist/define-op.js.map +1 -1
- package/dist/env-agnostic.d.ts +3 -0
- package/dist/env-agnostic.d.ts.map +1 -1
- package/dist/env-agnostic.js +7 -0
- package/dist/env-agnostic.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/lang/symbol-table.generated.d.ts +29 -1
- package/dist/lang/symbol-table.generated.d.ts.map +1 -1
- package/dist/lang/symbol-table.generated.js +30 -2
- package/dist/lang/symbol-table.generated.js.map +1 -1
- package/dist/occt-kernel/highLevelApi.d.ts.map +1 -1
- package/dist/occt-kernel/highLevelApi.js +6 -3
- package/dist/occt-kernel/highLevelApi.js.map +1 -1
- package/dist/occt-kernel/hullGeometry.d.ts +31 -0
- package/dist/occt-kernel/hullGeometry.d.ts.map +1 -0
- package/dist/occt-kernel/hullGeometry.js +319 -0
- package/dist/occt-kernel/hullGeometry.js.map +1 -0
- package/dist/occt-kernel/hullOps.d.ts +24 -0
- package/dist/occt-kernel/hullOps.d.ts.map +1 -0
- package/dist/occt-kernel/hullOps.js +52 -0
- package/dist/occt-kernel/hullOps.js.map +1 -0
- package/dist/occt-kernel/occt-primitives.d.ts +14 -0
- package/dist/occt-kernel/occt-primitives.d.ts.map +1 -0
- package/dist/occt-kernel/occt-primitives.js +351 -0
- package/dist/occt-kernel/occt-primitives.js.map +1 -0
- package/dist/occt-kernel/occtKernel.d.ts +14 -6
- package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
- package/dist/occt-kernel/occtKernel.js +11 -3
- package/dist/occt-kernel/occtKernel.js.map +1 -1
- package/dist/occt-kernel/topologyExt.js +2 -2
- package/dist/occt-kernel/topologyExt.js.map +1 -1
- package/dist/primitives/brep-primitives.d.ts +4 -0
- package/dist/primitives/brep-primitives.d.ts.map +1 -1
- package/dist/primitives/brep-primitives.js +4 -0
- package/dist/primitives/brep-primitives.js.map +1 -1
- package/dist/result/bug.d.ts +22 -0
- package/dist/result/bug.d.ts.map +1 -0
- package/dist/result/bug.js +28 -0
- package/dist/result/bug.js.map +1 -0
- package/dist/result/errors.d.ts +270 -0
- package/dist/result/errors.d.ts.map +1 -0
- package/dist/result/errors.js +317 -0
- package/dist/result/errors.js.map +1 -0
- package/dist/result/kernelErrorTranslation.d.ts +21 -0
- package/dist/result/kernelErrorTranslation.d.ts.map +1 -0
- package/dist/result/kernelErrorTranslation.js +102 -0
- package/dist/result/kernelErrorTranslation.js.map +1 -0
- package/dist/result/result.d.ts +213 -0
- package/dist/result/result.d.ts.map +1 -0
- package/dist/result/result.js +336 -0
- package/dist/result/result.js.map +1 -0
- package/dist/result/vec3.d.ts +12 -0
- package/dist/result/vec3.d.ts.map +1 -0
- package/dist/result/vec3.js +14 -0
- package/dist/result/vec3.js.map +1 -0
- package/dist/runtime-state.d.ts +9 -0
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js.map +1 -1
- package/dist/sdk.d.ts +3 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +2 -1
- package/dist/sdk.js.map +1 -1
- package/dist/shape.d.ts +43 -1
- package/dist/shape.d.ts.map +1 -1
- package/dist/shape.js +57 -1
- package/dist/shape.js.map +1 -1
- package/dist/topology/naming/geom-hint.js +1 -1
- package/dist/topology/naming/geom-hint.js.map +1 -1
- package/dist/topology/naming/score.js +1 -1
- package/dist/topology/naming/score.js.map +1 -1
- package/package.json +6 -16
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* brepkit-kernel/brepkitKernel — brepkit 内核 → faijs BrepEngineApi
|
|
2
|
+
* brepkit-kernel/brepkitKernel — brepkit 内核 → faijs BrepEngineApi 适配器
|
|
3
|
+
*
|
|
4
|
+
* Phase 4(docs/plans/2026-09-24-brep-engine-api-narrowing-native-access.md):
|
|
5
|
+
* 本文件是 L1 契约 `BrepEngineApi` 的 **brepkit 显式对象字面量实现**——与 occt 侧
|
|
6
|
+
* `occt-primitives.ts` 同构:逐方法接线、方言在适配器内消化、零 `unsupported()` 桩。
|
|
7
|
+
*
|
|
8
|
+
* 契约面收窄后 L1 只含 occt/brepkit 双方**语义可对齐**的方法(唯一真源:
|
|
9
|
+
* `api/surface/engine-method-map.json` 的 aligned/dialect 条目)。brepkit 独有
|
|
10
|
+
* 能力(chamfer2d/chamferV2/filletV2/sketch* 族、serializeSolid、meshBoolean、
|
|
11
|
+
* minkowskiSum …)与单方语义(loft、平面 section/split 之外的 splitter 语义…)
|
|
12
|
+
* 都不在本对象里——平台代码经原生面 `getBrepkitKernel()`(D3)访问。
|
|
3
13
|
*
|
|
4
14
|
* 设计要点(对应 3d_editor 项目的 weapp-voice-ai-modeling 设计计划 §5):
|
|
5
15
|
* - 句柄:brepkit u32 句柄与 faijs BrepHandle(number) 同构,直通零转换;
|
|
6
16
|
* - 拓扑红线:meshShape 用 tessellateSolidGrouped 输出 faceGroups,与三角化几何同源;
|
|
7
17
|
* - 面溯源:布尔/倒角走 *WithEvolution,映射为 BrepEvolutionData(hash 编码);
|
|
8
18
|
* - 链纪律:kernel.meshFallbackCount 计数差 > 0 → getMeshFallbackCount 暴露给宿主,
|
|
9
|
-
* 由宿主标记 BREP
|
|
10
|
-
* - v1 白名单之外的方法:显式抛错(报错好于掩盖,禁止空实现假成功)。
|
|
19
|
+
* 由宿主标记 BREP 链中断(不在此层静默处理)。
|
|
11
20
|
*/
|
|
12
21
|
import { initBrepkitWasm } from './brepkitWasm.js';
|
|
13
22
|
// ── 句柄桥接:brepkit number 句柄 ↔ BrepHandle(零运行时成本,与 occt 适配器同构) ──
|
|
14
23
|
const asHandle = (n) => n;
|
|
15
24
|
const asNum = (h) => h;
|
|
16
25
|
const arr = (x) => Array.from(x);
|
|
26
|
+
/** 适配器内部的显式失败(替代旧 unsupported 桩:能力缺失一律在静态判定拦截,不在实现体里伪装)。 */
|
|
27
|
+
function fail(detail) {
|
|
28
|
+
throw new Error(`[brepkit-kernel] ${detail}`);
|
|
29
|
+
}
|
|
17
30
|
/**
|
|
18
31
|
* brepkit 几何查询返回值归一为 number[]。
|
|
19
32
|
*
|
|
@@ -64,10 +77,6 @@ function toNumArray(v) {
|
|
|
64
77
|
}
|
|
65
78
|
return [];
|
|
66
79
|
}
|
|
67
|
-
/** v1 白名单外的方法统一抛错(携带适配器上下文与 v1 范围说明)。 */
|
|
68
|
-
function unsupported(name) {
|
|
69
|
-
throw new Error(`[brepkit-kernel] BrepEngineApi.${name} 不在 brepkit 适配器 v1 白名单内(能力表见设计文档 §5.2)。该操作请在 OCCT 链执行,或等待适配器扩展。`);
|
|
70
|
-
}
|
|
71
80
|
/** 面稳定指纹:解析曲面参数 + 面积 → FNV-1a → 取模上界(跨操作可追溯,与句柄无关)。 */
|
|
72
81
|
function faceFingerprint(kernel, face, upperBound) {
|
|
73
82
|
let params = '';
|
|
@@ -93,21 +102,30 @@ function mapEvolution(kernel, raw, resultHandle, inputFaceHashes, hashUpperBound
|
|
|
93
102
|
// raw: {solid, evolution:{modified:{oldHandle:[newHandles]}, generated:{oldHandle:[new]}, deleted:[oldHandles]}}
|
|
94
103
|
const parsed = JSON.parse(raw);
|
|
95
104
|
const evo = parsed.evolution ?? { modified: {}, generated: {}, deleted: [] };
|
|
96
|
-
const modifiedKeys = new Set(Object.keys(evo.modified ?? {}).map(Number));
|
|
97
105
|
const deletedKeys = new Set((evo.deleted ?? []).map(Number));
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
106
|
+
// registry 登记的是 hash→handle(输入面)。下游 decodeEvolution/decodeHashEvolution 期望
|
|
107
|
+
// modified 为 OCCT 分段格式 [inHash, count, outHash1, outHash2, ...](见 face-evolution.ts),
|
|
108
|
+
// 不是扁平 hash 列表——GOTCHA:曾误返回扁平列表,把 modified[1](一个 hash ~1e9)当成
|
|
109
|
+
// count,导致 decodeHashEvolution 空转 17 亿次 push 抛 "Invalid array length"(2026-09-26 实证)。
|
|
110
|
+
// 故这里反向建 handle→hash 表,逐条目拼出 [inHash, outCount, ...outHashes]。
|
|
101
111
|
const registry = hashRegistry.get(kernel);
|
|
112
|
+
const handleToHash = new Map();
|
|
113
|
+
if (registry)
|
|
114
|
+
for (const [h, handle] of registry)
|
|
115
|
+
handleToHash.set(handle, h);
|
|
102
116
|
const modified = [];
|
|
103
117
|
const deleted = [];
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
118
|
+
for (const oldHandle of deletedKeys) {
|
|
119
|
+
const h = handleToHash.get(oldHandle);
|
|
120
|
+
if (h !== undefined)
|
|
121
|
+
deleted.push(h);
|
|
122
|
+
}
|
|
123
|
+
for (const [oldHandleStr, newHandles] of Object.entries(evo.modified ?? {})) {
|
|
124
|
+
const inHash = handleToHash.get(Number(oldHandleStr));
|
|
125
|
+
if (inHash === undefined)
|
|
126
|
+
continue;
|
|
127
|
+
const outHashes = newHandles.map((nh) => faceFingerprint(kernel, nh, hashUpperBound));
|
|
128
|
+
modified.push(inHash, outHashes.length, ...outHashes);
|
|
111
129
|
}
|
|
112
130
|
// generated:结果实体的新面 hash(数量按 generated 表展开)
|
|
113
131
|
const generated = [];
|
|
@@ -128,9 +146,45 @@ function mapEvolution(kernel, raw, resultHandle, inputFaceHashes, hashUpperBound
|
|
|
128
146
|
}
|
|
129
147
|
/** per-kernel 的 hash↔handle 登记表(fuseWithHistory 溯源对齐用)。 */
|
|
130
148
|
const hashRegistry = new WeakMap();
|
|
149
|
+
/** 三点外接圆(makeArcEdge 方言消化:occt 吃 3 点,brepkit 吃圆心+轴)。 */
|
|
150
|
+
function circumcircle(a, b, c) {
|
|
151
|
+
const abx = b.x - a.x, aby = b.y - a.y, abz = b.z - a.z;
|
|
152
|
+
const acx = c.x - a.x, acy = c.y - a.y, acz = c.z - a.z;
|
|
153
|
+
const nx = aby * acz - abz * acy;
|
|
154
|
+
const ny = abz * acx - abx * acz;
|
|
155
|
+
const nz = abx * acy - aby * acx;
|
|
156
|
+
const n2 = nx * nx + ny * ny + nz * nz;
|
|
157
|
+
if (n2 < 1e-18)
|
|
158
|
+
fail('makeArcEdge: 3 points are collinear (no circumscribed circle)');
|
|
159
|
+
const ab2 = abx * abx + aby * aby + abz * abz;
|
|
160
|
+
const ac2 = acx * acx + acy * acy + acz * acz;
|
|
161
|
+
// center = a + ( ac2·(ab×n) + ab2·(n×ac) ) / (2·n²)
|
|
162
|
+
const abxnx = aby * nz - abz * ny, abxny = abz * nx - abx * nz, abxnz = abx * ny - aby * nx;
|
|
163
|
+
const nxacx = ny * acz - nz * acy, nxacy = nz * acx - nx * acz, nxacz = nx * acy - ny * acx;
|
|
164
|
+
const denom = 2 * n2;
|
|
165
|
+
const len = Math.sqrt(n2);
|
|
166
|
+
return {
|
|
167
|
+
center: {
|
|
168
|
+
x: a.x + (ac2 * abxnx + ab2 * nxacx) / denom,
|
|
169
|
+
y: a.y + (ac2 * abxny + ab2 * nxacy) / denom,
|
|
170
|
+
z: a.z + (ac2 * abxnz + ab2 * nxacz) / denom,
|
|
171
|
+
},
|
|
172
|
+
axis: { x: nx / len, y: ny / len, z: nz / len },
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/** BrepVec3[] → 扁平 Float64Array(brepkit 坐标数组方言)。 */
|
|
176
|
+
function flattenPoints(points) {
|
|
177
|
+
const out = new Float64Array(points.length * 3);
|
|
178
|
+
for (let i = 0; i < points.length; i++) {
|
|
179
|
+
out[i * 3] = points[i].x;
|
|
180
|
+
out[i * 3 + 1] = points[i].y;
|
|
181
|
+
out[i * 3 + 2] = points[i].z;
|
|
182
|
+
}
|
|
183
|
+
return out;
|
|
184
|
+
}
|
|
131
185
|
/**
|
|
132
|
-
* 创建 brepkit BrepEngineApi 实现(
|
|
133
|
-
* 与 occt 的
|
|
186
|
+
* 创建 brepkit BrepEngineApi 实现(L1 契约显式对象字面量)。
|
|
187
|
+
* 与 occt 的 createOcctPrimitives 同位:返回满足引擎契约的原语集合。
|
|
134
188
|
* @returns a promise resolving to the BrepEngineApi implementation plus brepkit-specific
|
|
135
189
|
* diagnostics (`getMeshFallbackCount`).
|
|
136
190
|
*/
|
|
@@ -138,9 +192,45 @@ export async function createBrepkitPrimitives() {
|
|
|
138
192
|
const kernel = await initBrepkitWasm();
|
|
139
193
|
liveKernel = kernel;
|
|
140
194
|
let lastFallbackCount = 0;
|
|
141
|
-
// 已知面句柄集合:getSubShapes(shape,'face')
|
|
142
|
-
//
|
|
195
|
+
// 已知面句柄集合:getSubShapes(shape,'face') / makeRectangle / makeFace / buildTriFace
|
|
196
|
+
// 返回的面在此登记;extrude/revolveVec 的 face 输入断言、getSubShapes 的
|
|
197
|
+
// edge/vertex 分发都据此判定(brepkit 无 shape-type 分类 API,见下方注释)。
|
|
143
198
|
const knownFaces = new Set();
|
|
199
|
+
// GOTCHA(2026-09-26 非实体句柄修复):brepkit 的 tessellateSolidGrouped / getSolidFaces
|
|
200
|
+
// 等 *Solid API 只吃 solid 句柄,传 face/wire/edge/compound 即抛
|
|
201
|
+
// "invalid solid handle: index N out of bounds"。而 brepkit **没有 shape-type 分类 API**
|
|
202
|
+
// (getFaceEdges(solid) 不抛错、会返回某一面的边,不能 try/catch 探测)。故 meshShape
|
|
203
|
+
// 必须靠这组「已知句柄集合」在执行前静态分发,而不是运行时探测:
|
|
204
|
+
// knownFaces → tessellateFace(JsMesh)
|
|
205
|
+
// knownWires → getWireEdges + tessellateEdge 逐边采样成线段
|
|
206
|
+
// knownEdges → tessellateEdge 直接采样成线段(wire.ts smooth 路径 interpolatePoints 返回 edge)
|
|
207
|
+
// knownCompounds→ 逐子句柄按其类型 tessellate 后合并(sectionByPlane 面组 / importStep 多实体)
|
|
208
|
+
// 不在任何集合里的句柄一律按 solid 走 tessellateSolidGrouped(实体创建不入集合,天然落此路径)。
|
|
209
|
+
const knownWires = new Set();
|
|
210
|
+
const knownEdges = new Set();
|
|
211
|
+
// GOTCHA: getSolidFaces returns GLOBAL face indices (0..5, 6..11, ...) that collide
|
|
212
|
+
// with solid handles (per-type namespace). Enumerated sub-faces must NOT pollute
|
|
213
|
+
// knownFaces, else measuring a later solid whose handle number equals an old
|
|
214
|
+
// enumerated face gets mis-tessellated as a face. derivedFaces is consulted ONLY by
|
|
215
|
+
// getSubShapes edge/vertex drilling, never by meshShape/getBoundingBox.
|
|
216
|
+
const derivedFaces = new Set();
|
|
217
|
+
// 虚拟 compound 句柄计数器(非实体子句柄不进内核 makeCompound,见 makeCompound GOTCHA)。
|
|
218
|
+
const knownCompounds = new Map();
|
|
219
|
+
let virtualCompoundCounter = 0;
|
|
220
|
+
// GOTCHA(2026-09-26):brepkit 句柄按**类型分命名空间**——solid/face/wire/edge 各自从 0 计数
|
|
221
|
+
// (实测 edge=wire=face=solid=0 可共存)。因此「某编号 N 在 knownFaces」与「某编号 N 是 solid」
|
|
222
|
+
// 并不互斥:新 solid 恰好复用了早先某 face 的编号时,knownFaces.has(N) 会把 solid 误判成 face
|
|
223
|
+
// (实测 box makeBox 返回 solid 2,撞 profile 早先的 face 2 → cloneShape 走 copyFace 崩溃)。
|
|
224
|
+
// 建 solid 时必须从 knownFaces/knownWires/knownEdges/derivedFaces 抹掉该编号,让默认 solid 路径生效。
|
|
225
|
+
// derivedFaces 也必须清:getSubShapes(solid,'edge') 会查 derivedFaces.has(s) 误走 getFaceEdges。
|
|
226
|
+
const markSolid = (h) => {
|
|
227
|
+
knownFaces.delete(h);
|
|
228
|
+
knownWires.delete(h);
|
|
229
|
+
knownEdges.delete(h);
|
|
230
|
+
knownCompounds.delete(h);
|
|
231
|
+
derivedFaces.delete(h);
|
|
232
|
+
return h;
|
|
233
|
+
};
|
|
144
234
|
const readFallback = () => {
|
|
145
235
|
try {
|
|
146
236
|
return typeof kernel.meshFallbackCount === 'function' ? Number(kernel.meshFallbackCount()) : 0;
|
|
@@ -151,9 +241,174 @@ export async function createBrepkitPrimitives() {
|
|
|
151
241
|
};
|
|
152
242
|
/** 布尔类操作后登记回退计数差(§5.4:宿主每步读取,>0 即链中断)。 */
|
|
153
243
|
const trackFallback = (r) => { lastFallbackCount = readFallback(); return r; };
|
|
244
|
+
const faceCenterOfMass = (face) => {
|
|
245
|
+
// brepkit 无 per-face 质心 API;用 UV 域中点在曲面上求值作为面中心近似
|
|
246
|
+
// (与 OCCT 路径的「面中心用于命名/拾取锚点」语义一致,不追求精确质心)。
|
|
247
|
+
const d = toNumArray(kernel.getSurfaceDomain(asNum(face)));
|
|
248
|
+
const u = ((d[0] ?? 0) + (d[1] ?? 1)) / 2;
|
|
249
|
+
const v = ((d[2] ?? 0) + (d[3] ?? 1)) / 2;
|
|
250
|
+
return vec3Of(toNumArray(kernel.evaluateSurface(asNum(face), u, v)));
|
|
251
|
+
};
|
|
252
|
+
/** 单个 face → BrepMeshResult(tessellateFace)。 */
|
|
253
|
+
const faceMesh = (f, deflection, angular) => {
|
|
254
|
+
const jm = kernel.tessellateFace(f, deflection, angular);
|
|
255
|
+
const positions = arr(jm.positions);
|
|
256
|
+
const normals = arr(jm.normals);
|
|
257
|
+
const indices = arr(jm.indices);
|
|
258
|
+
const triCount = jm.triangleCount > 0 ? jm.triangleCount : indices.length / 3;
|
|
259
|
+
return {
|
|
260
|
+
positions: new Float32Array(positions),
|
|
261
|
+
normals: new Float32Array(normals),
|
|
262
|
+
indices: new Uint32Array(indices),
|
|
263
|
+
vertexCount: positions.length / 3,
|
|
264
|
+
triangleCount: triCount,
|
|
265
|
+
faceGroups: new Int32Array([0, triCount, faceFingerprint(kernel, f, 1e9)]),
|
|
266
|
+
faceCount: 1,
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
/** 一组 edge 句柄 → 线段 mesh(positions 为采样点、indices 为端点对)。 */
|
|
270
|
+
// GOTCHA:tessellateEdge(edge, N) 返回扁平 [x,y,z,...] 采样点(NURBS 才采样 N 点,
|
|
271
|
+
// 直线边只回端点),不是三角网格;wire/curve 显示吃「端点对」索引(与 mesh 路径 wireMesh 同构)。
|
|
272
|
+
const edgesToLineMesh = (edgeHandles, deflection) => {
|
|
273
|
+
const positions = [];
|
|
274
|
+
const indices = [];
|
|
275
|
+
// 采样密度:按 deflection 粗采样即可(1D 线框显示,非精确几何)。
|
|
276
|
+
const nPts = Math.max(12, Math.round(4 / Math.max(deflection, 0.01)));
|
|
277
|
+
for (const e of edgeHandles) {
|
|
278
|
+
const pts = arr(kernel.tessellateEdge(e, nPts));
|
|
279
|
+
const base = positions.length / 3;
|
|
280
|
+
for (let i = 0; i < pts.length; i++)
|
|
281
|
+
positions.push(pts[i]);
|
|
282
|
+
const verts = pts.length / 3;
|
|
283
|
+
for (let i = 0; i < verts - 1; i++)
|
|
284
|
+
indices.push(base + i, base + i + 1);
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
positions: new Float32Array(positions),
|
|
288
|
+
normals: new Float32Array(positions.length),
|
|
289
|
+
indices: new Uint32Array(indices),
|
|
290
|
+
vertexCount: positions.length / 3,
|
|
291
|
+
triangleCount: 0,
|
|
292
|
+
faceGroups: new Int32Array(0),
|
|
293
|
+
faceCount: 0,
|
|
294
|
+
};
|
|
295
|
+
};
|
|
296
|
+
/** wire → 线段 mesh(getWireEdges 取边集后逐边采样)。 */
|
|
297
|
+
const wireMesh = (wire, deflection) => {
|
|
298
|
+
const edges = arr(kernel.getWireEdges(wire));
|
|
299
|
+
return edgesToLineMesh(edges, deflection);
|
|
300
|
+
};
|
|
301
|
+
/** solid → BrepMeshResult(tessellateSolidGrouped,原 meshShape 实体路径抽出)。 */
|
|
302
|
+
const solidMesh = (solid, deflection, angular) => {
|
|
303
|
+
const raw = kernel.tessellateSolidGrouped(solid, deflection, angular);
|
|
304
|
+
const m = JSON.parse(raw);
|
|
305
|
+
// faceOffsets 形如 [start0, start1, ..., totalEnd]:以「索引数组单位」计的每面偏移(2026-09-19 实测),
|
|
306
|
+
// 除以 3 换算为 faijs 契约的三角形单位 [triStart, triCount, faceHash]
|
|
307
|
+
const fo = m.faceOffsets;
|
|
308
|
+
const faceCount = Math.max(0, fo.length - 1);
|
|
309
|
+
const faceHashes = [];
|
|
310
|
+
try {
|
|
311
|
+
const faces = arr(kernel.getSolidFaces(solid));
|
|
312
|
+
for (let i = 0; i < faceCount && i < faces.length; i++)
|
|
313
|
+
faceHashes.push(faceFingerprint(kernel, faces[i], 1e9));
|
|
314
|
+
}
|
|
315
|
+
catch { /* 非实体:faceHash 置 0 */ }
|
|
316
|
+
const faceGroups = new Int32Array(faceCount * 3);
|
|
317
|
+
for (let i = 0; i < faceCount; i++) {
|
|
318
|
+
faceGroups[i * 3] = fo[i] / 3;
|
|
319
|
+
faceGroups[i * 3 + 1] = (fo[i + 1] - fo[i]) / 3;
|
|
320
|
+
faceGroups[i * 3 + 2] = faceHashes[i] ?? 0;
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
positions: new Float32Array(m.positions),
|
|
324
|
+
normals: new Float32Array(m.normals),
|
|
325
|
+
indices: new Uint32Array(m.indices),
|
|
326
|
+
vertexCount: m.positions.length / 3,
|
|
327
|
+
triangleCount: m.indices.length / 3,
|
|
328
|
+
faceGroups,
|
|
329
|
+
faceCount,
|
|
330
|
+
};
|
|
331
|
+
};
|
|
332
|
+
/** compound → 逐子句柄 tessellate 后合并(sectionByPlane 面组 / importStep 多实体)。 */
|
|
333
|
+
const compoundMesh = (children, deflection, angular) => {
|
|
334
|
+
const positions = [];
|
|
335
|
+
const normals = [];
|
|
336
|
+
const indices = [];
|
|
337
|
+
const faceGroups = [];
|
|
338
|
+
let triOffset = 0;
|
|
339
|
+
for (const c of children) {
|
|
340
|
+
let sub;
|
|
341
|
+
if (knownFaces.has(c)) {
|
|
342
|
+
sub = faceMesh(c, deflection, angular);
|
|
343
|
+
}
|
|
344
|
+
else if (knownWires.has(c)) {
|
|
345
|
+
sub = wireMesh(c, deflection);
|
|
346
|
+
}
|
|
347
|
+
else if (knownEdges.has(c)) {
|
|
348
|
+
sub = edgesToLineMesh([c], deflection);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
// 子句柄按 solid 处理(importStep 多实体 / makeCompound(solids))。
|
|
352
|
+
sub = solidMesh(c, deflection, angular);
|
|
353
|
+
}
|
|
354
|
+
const vOffset = positions.length / 3;
|
|
355
|
+
for (let i = 0; i < sub.positions.length; i++)
|
|
356
|
+
positions.push(sub.positions[i]);
|
|
357
|
+
for (let i = 0; i < sub.normals.length; i++)
|
|
358
|
+
normals.push(sub.normals[i] ?? 0);
|
|
359
|
+
for (let i = 0; i < sub.indices.length; i++)
|
|
360
|
+
indices.push(sub.indices[i] + vOffset);
|
|
361
|
+
if (sub.faceGroups) {
|
|
362
|
+
for (let i = 0; i < sub.faceGroups.length; i += 3) {
|
|
363
|
+
faceGroups.push((sub.faceGroups[i] ?? 0) + triOffset, sub.faceGroups[i + 1] ?? 0, sub.faceGroups[i + 2] ?? 0);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
triOffset += sub.triangleCount;
|
|
367
|
+
}
|
|
368
|
+
return {
|
|
369
|
+
positions: new Float32Array(positions),
|
|
370
|
+
normals: new Float32Array(normals),
|
|
371
|
+
indices: new Uint32Array(indices),
|
|
372
|
+
vertexCount: positions.length / 3,
|
|
373
|
+
triangleCount: indices.length / 3,
|
|
374
|
+
faceGroups: new Int32Array(faceGroups),
|
|
375
|
+
faceCount: faceGroups.length / 3,
|
|
376
|
+
};
|
|
377
|
+
};
|
|
378
|
+
// ── 按句柄类型深拷贝(transform/copy 族分发用) ──
|
|
379
|
+
// GOTCHA:brepkit copySolid/copyFace/copyWire 三者入参严格对应 solid/face/wire 句柄,
|
|
380
|
+
// 传错即崩溃;transformSolid/transformFace/transformWire 均为「原地修改」void。
|
|
381
|
+
// place/translate 等会作用在 profile 产出的 face 上(sew 用例 place 两张 face),
|
|
382
|
+
// 故必须按 knownFaces/knownWires 分发,不能一律 copySolid。
|
|
383
|
+
const cloneShape = (shape) => {
|
|
384
|
+
if (knownFaces.has(shape)) {
|
|
385
|
+
const c = kernel.copyFace(shape);
|
|
386
|
+
knownFaces.add(c);
|
|
387
|
+
return c;
|
|
388
|
+
}
|
|
389
|
+
if (knownWires.has(shape)) {
|
|
390
|
+
const c = kernel.copyWire(shape);
|
|
391
|
+
knownWires.add(c);
|
|
392
|
+
return c;
|
|
393
|
+
}
|
|
394
|
+
return markSolid(kernel.copySolid(shape));
|
|
395
|
+
};
|
|
396
|
+
/** 深拷贝 + 原地仿射变换(matrix 已经 toKernelMatrix 归一为 16 元素 4×4)。 */
|
|
397
|
+
const cloneAndTransform = (shape, matrix16) => {
|
|
398
|
+
const c = cloneShape(shape);
|
|
399
|
+
const m = Float64Array.from(matrix16);
|
|
400
|
+
if (knownFaces.has(c))
|
|
401
|
+
kernel.transformFace(c, m);
|
|
402
|
+
else if (knownWires.has(c))
|
|
403
|
+
kernel.transformWire(c, m);
|
|
404
|
+
else
|
|
405
|
+
kernel.transformSolid(c, m);
|
|
406
|
+
return c;
|
|
407
|
+
};
|
|
154
408
|
const api = {
|
|
155
409
|
// ── 生命周期 ──
|
|
156
410
|
release(_shape) { },
|
|
411
|
+
dispose(_shape) { },
|
|
157
412
|
/** 内核级诊断:距上次读取的 mesh 布尔回退计数差(>0 = BREP 链已中断)。 */
|
|
158
413
|
getMeshFallbackCount() {
|
|
159
414
|
const now = readFallback();
|
|
@@ -162,49 +417,125 @@ export async function createBrepkitPrimitives() {
|
|
|
162
417
|
return delta;
|
|
163
418
|
},
|
|
164
419
|
// ── 实体图元 ──
|
|
165
|
-
makeBox(dx, dy, dz) { return asHandle(kernel.makeBox(dx, dy, dz)); },
|
|
420
|
+
makeBox(dx, dy, dz) { return asHandle(markSolid(kernel.makeBox(dx, dy, dz))); },
|
|
166
421
|
makeBoxFromCorners(corner1, corner2) {
|
|
167
422
|
const dx = Math.abs(corner2.x - corner1.x), dy = Math.abs(corner2.y - corner1.y), dz = Math.abs(corner2.z - corner1.z);
|
|
168
|
-
const h = kernel.makeBox(dx, dy, dz);
|
|
169
|
-
|
|
423
|
+
const h = markSolid(kernel.makeBox(dx, dy, dz));
|
|
424
|
+
// ⚠️ transformSolid 是「原地修改、返回 undefined」——makeBox 的句柄本身即新实体,
|
|
425
|
+
// 直接原地变换后返回 h;若写 `asHandle(transformSolid(...))` 会拿到 undefined 句柄
|
|
426
|
+
// (2026-09-25 实证:导致 splitBrep 基于半空间盒的 common/cut 全部失效)。
|
|
427
|
+
kernel.transformSolid(h, toKernelMatrix(translationMatrix(Math.min(corner1.x, corner2.x), Math.min(corner1.y, corner2.y), Math.min(corner1.z, corner2.z))));
|
|
428
|
+
return asHandle(h);
|
|
170
429
|
},
|
|
171
|
-
makeCylinder(radius, height) { return asHandle(kernel.makeCylinder(radius, height)); },
|
|
172
|
-
makeSphere(radius) { return asHandle(kernel.makeSphere(radius, 32)); },
|
|
173
|
-
makeCone(r1, r2, height) { return asHandle(kernel.makeCone(r1, r2, height)); },
|
|
174
|
-
makeRectangle(
|
|
430
|
+
makeCylinder(radius, height) { return asHandle(markSolid(kernel.makeCylinder(radius, height))); },
|
|
431
|
+
makeSphere(radius) { return asHandle(markSolid(kernel.makeSphere(radius, 32))); },
|
|
432
|
+
makeCone(r1, r2, height) { return asHandle(markSolid(kernel.makeCone(r1, r2, height))); },
|
|
433
|
+
makeRectangle(width, height) {
|
|
434
|
+
const f = kernel.makeRectangle(width, height);
|
|
435
|
+
knownFaces.add(f);
|
|
436
|
+
return asHandle(f);
|
|
437
|
+
},
|
|
438
|
+
makeEllipsoid(rx, ry, rz) { return asHandle(markSolid(kernel.makeEllipsoid(rx, ry, rz))); },
|
|
439
|
+
makeTorus(majorRadius, minorRadius) { return asHandle(markSolid(kernel.makeTorus(majorRadius, minorRadius, 64))); },
|
|
440
|
+
makeVertex(x, y, z) { return asHandle(kernel.makeVertex(x, y, z)); },
|
|
175
441
|
// ── 造型运算 ──
|
|
176
|
-
extrude(
|
|
177
|
-
|
|
442
|
+
extrude(shape, dx, dy, dz) {
|
|
443
|
+
// 方言归一(§3.6-1):L1 口径是挤出向量;brepkit 原生吃 (face, dir, distance)。
|
|
444
|
+
const s = asNum(shape);
|
|
445
|
+
if (!knownFaces.has(s)) {
|
|
446
|
+
fail('extrude requires a face input (plan §3.6-1); got a handle that is not a known face');
|
|
447
|
+
}
|
|
448
|
+
const len = Math.hypot(dx, dy, dz);
|
|
449
|
+
if (len === 0)
|
|
450
|
+
fail('extrude: zero-length extrusion vector');
|
|
451
|
+
return asHandle(markSolid(kernel.extrude(s, dx / len, dy / len, dz / len, len)));
|
|
452
|
+
},
|
|
453
|
+
revolveVec(shape, center, direction, angleDeg) {
|
|
454
|
+
// 方言归一:brepkit revolve 只吃 face(与 extrude 同族断言)。
|
|
455
|
+
const s = asNum(shape);
|
|
456
|
+
if (!knownFaces.has(s)) {
|
|
457
|
+
fail('revolveVec requires a face input; got a handle that is not a known face');
|
|
458
|
+
}
|
|
459
|
+
return asHandle(markSolid(kernel.revolve(s, center.x, center.y, center.z, direction.x, direction.y, direction.z, angleDeg)));
|
|
460
|
+
},
|
|
461
|
+
sew(shapesList, tolerance) {
|
|
462
|
+
return asHandle(kernel.sewFaces(Uint32Array.from(shapesList.map(asNum)), tolerance ?? 1e-6));
|
|
463
|
+
},
|
|
464
|
+
sewAndSolidify(faces, _tolerance) {
|
|
465
|
+
// brepkit 的 makeSolid 即「缝合并固化成实体」(sewFaces + 建 solid)。
|
|
466
|
+
return asHandle(markSolid(kernel.makeSolid(Uint32Array.from(faces.map(asNum)))));
|
|
467
|
+
},
|
|
468
|
+
shell(solid, facesToRemove, thickness, _tolerance) {
|
|
469
|
+
// brepkit 参数序 (solid, thickness, open_faces);tolerance 内核固定。
|
|
470
|
+
return asHandle(kernel.shell(asNum(solid), thickness, Uint32Array.from(facesToRemove.map(asNum))));
|
|
471
|
+
},
|
|
472
|
+
hullFromPoints(points, _tolerance) {
|
|
473
|
+
return asHandle(kernel.convexHull(flattenPoints(points)));
|
|
474
|
+
},
|
|
178
475
|
// ── 布尔与分割 ──
|
|
179
|
-
fuse(a, b) { return asHandle(trackFallback(kernel.fuse(asNum(a), asNum(b)))); },
|
|
180
|
-
cut(a, b) { return asHandle(trackFallback(kernel.cut(asNum(a), asNum(b)))); },
|
|
181
|
-
common(a, b) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
476
|
+
fuse(a, b) { return asHandle(markSolid(trackFallback(kernel.fuse(asNum(a), asNum(b))))); },
|
|
477
|
+
cut(a, b) { return asHandle(markSolid(trackFallback(kernel.cut(asNum(a), asNum(b))))); },
|
|
478
|
+
common(a, b) {
|
|
479
|
+
// brepkit 无 `common` 原生名;交集语义由 `intersect` 承担(method-map: dialect)。
|
|
480
|
+
return asHandle(markSolid(trackFallback(kernel.intersect(asNum(a), asNum(b)))));
|
|
481
|
+
},
|
|
482
|
+
intersect(a, b) { return asHandle(trackFallback(kernel.intersect(asNum(a), asNum(b)))); },
|
|
483
|
+
fuseAll(shapesList) {
|
|
484
|
+
return asHandle(markSolid(trackFallback(kernel.fuseAll(Int32Array.from(shapesList.map(asNum))))));
|
|
485
|
+
},
|
|
486
|
+
sectionByPlane(shape, point, normal) {
|
|
487
|
+
// brepkit 原生 section(solid, plane) 返回剖面 face 句柄组(§3.6-2 新中立名)。
|
|
488
|
+
// GOTCHA:brepkit section 返回的是 **face** 句柄(不是 edge/wire),必须登记进 knownFaces,
|
|
489
|
+
// 否则 op 层 makeCompound(这些 face) 后送 meshShape 会按 solid 路径崩溃。
|
|
490
|
+
const s = asNum(shape);
|
|
491
|
+
const faces = arr(kernel.section(s, point.x, point.y, point.z, normal.x, normal.y, normal.z));
|
|
492
|
+
for (const f of faces)
|
|
493
|
+
knownFaces.add(f);
|
|
494
|
+
return faces.map(asHandle);
|
|
495
|
+
},
|
|
496
|
+
splitByPlane(shape, point, normal) {
|
|
497
|
+
const parts = arr(kernel.split(asNum(shape), point.x, point.y, point.z, normal.x, normal.y, normal.z));
|
|
498
|
+
if (parts.length !== 2) {
|
|
499
|
+
fail(`splitByPlane: expected 2 solids, got ${parts.length}`);
|
|
500
|
+
}
|
|
501
|
+
// 法向正侧 = positive(§3.7):按质心在平面法向的投影分类。
|
|
502
|
+
const originDot = point.x * normal.x + point.y * normal.y + point.z * normal.z;
|
|
503
|
+
const side = (h) => {
|
|
504
|
+
const c = toNumArray(kernel.centerOfMass(h, 0.05));
|
|
505
|
+
return (c[0] ?? 0) * normal.x + (c[1] ?? 0) * normal.y + (c[2] ?? 0) * normal.z - originDot;
|
|
506
|
+
};
|
|
507
|
+
const [a, b] = parts;
|
|
508
|
+
markSolid(a);
|
|
509
|
+
markSolid(b);
|
|
510
|
+
return side(a) >= side(b)
|
|
511
|
+
? { positive: asHandle(a), negative: asHandle(b) }
|
|
512
|
+
: { positive: asHandle(b), negative: asHandle(a) };
|
|
513
|
+
},
|
|
514
|
+
// ── 倒角与圆角(Q7:只对齐等距 + 距角两种粒度)──
|
|
188
515
|
chamfer(solid, edges, distance) {
|
|
189
|
-
return asHandle(trackFallback(kernel.chamfer(asNum(solid),
|
|
516
|
+
return asHandle(trackFallback(kernel.chamfer(asNum(solid), Uint32Array.from(edges.map(asNum)), distance)));
|
|
190
517
|
},
|
|
191
518
|
chamferDistAngle(solid, edges, distance, angleDeg) {
|
|
192
|
-
|
|
519
|
+
// 方言映射:L1 chamferDistAngle ↔ brepkit chamferDistanceAngle。
|
|
520
|
+
// ⚠️ 单位方言:L1 口径是**度**(`AddDA(distance, angleDeg, E, F)`),brepkit 内核吃**弧度**
|
|
521
|
+
// (2026-09-25 实证:传 45 抛 "angle must be less than π/2";传 π/4 正常倒角)。
|
|
522
|
+
const angleRad = (angleDeg * Math.PI) / 180;
|
|
523
|
+
return asHandle(trackFallback(kernel.chamferDistanceAngle(asNum(solid), Uint32Array.from(edges.map(asNum)), distance, angleRad)));
|
|
193
524
|
},
|
|
194
525
|
fillet(solid, edges, radius) {
|
|
195
|
-
return asHandle(trackFallback(kernel.fillet(asNum(solid),
|
|
526
|
+
return asHandle(trackFallback(kernel.fillet(asNum(solid), Uint32Array.from(edges.map(asNum)), radius)));
|
|
196
527
|
},
|
|
197
528
|
filletVariable(solid, edge, startRadius, endRadius) {
|
|
198
|
-
|
|
529
|
+
// 方言映射:L1 filletVariable(solid, edge, startRadius, endRadius)(单边变半径)
|
|
530
|
+
// ↔ brepkit filletVariable(solid, json) 吃**序列** `[{edge, radius1, radius2}, ...]`。
|
|
531
|
+
// ⚠️ 直接传 4 个位置参数会触发 wasm memory out of bounds(2026-09-25 实证)。
|
|
532
|
+
const spec = JSON.stringify([{ edge: asNum(edge), radius1: startRadius, radius2: endRadius }]);
|
|
533
|
+
return asHandle(trackFallback(kernel.filletVariable(asNum(solid), spec)));
|
|
199
534
|
},
|
|
200
535
|
filletWithHistory(solid, edges, radius, inputFaceHashes, hashUpperBound) {
|
|
201
536
|
const raw = kernel.filletWithEvolution(asNum(solid), Int32Array.from(edges.map(asNum)), radius);
|
|
202
537
|
return mapEvolution(kernel, raw, JSON.parse(raw).solid, inputFaceHashes, hashUpperBound);
|
|
203
538
|
},
|
|
204
|
-
chamferWithHistory(_solid, _edges, _distance, _inputFaceHashes, _hashUpperBound) {
|
|
205
|
-
// brepkit 无 chamferWithEvolution → 等距倒角演化不支持,诚实报错(能力表 evolution 仅覆盖 fuse/cut/fillet)
|
|
206
|
-
return unsupported('chamferWithHistory');
|
|
207
|
-
},
|
|
208
539
|
// ── 变换 ──
|
|
209
540
|
// ⚠️ brepkit 的 transformSolid 是「原地修改、返回 undefined」——必须先 copySolid
|
|
210
541
|
// 复制出新句柄再变换,否则会篡改调用方手里的原实体(单测 2026-09-19 实证)。
|
|
@@ -212,39 +543,40 @@ export async function createBrepkitPrimitives() {
|
|
|
212
543
|
// brepkit transformSolid 吃 4×4 行主序 16 元素。所有 transformSolid 调用一律经
|
|
213
544
|
// toKernelMatrix 归一(下方唯一转换点),禁止直出 16 元素旁路。
|
|
214
545
|
translate(shape, dx, dy, dz) {
|
|
215
|
-
|
|
216
|
-
kernel.transformSolid(c, toKernelMatrix(translationMatrix(dx, dy, dz)));
|
|
217
|
-
return asHandle(c);
|
|
546
|
+
return asHandle(cloneAndTransform(asNum(shape), toKernelMatrix(translationMatrix(dx, dy, dz))));
|
|
218
547
|
},
|
|
219
548
|
scale(shape, center, factor) {
|
|
220
|
-
|
|
221
|
-
kernel.transformSolid(c, toKernelMatrix(scaleMatrix(center, factor)));
|
|
222
|
-
return asHandle(c);
|
|
549
|
+
return asHandle(cloneAndTransform(asNum(shape), toKernelMatrix(scaleMatrix(center, factor))));
|
|
223
550
|
},
|
|
224
551
|
transform(shape, matrix) {
|
|
225
|
-
|
|
226
|
-
kernel.transformSolid(c, toKernelMatrix(matrix));
|
|
227
|
-
return asHandle(c);
|
|
552
|
+
return asHandle(cloneAndTransform(asNum(shape), toKernelMatrix(matrix)));
|
|
228
553
|
},
|
|
229
554
|
located(shape, matrix) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
555
|
+
return asHandle(cloneAndTransform(asNum(shape), toKernelMatrix(matrix)));
|
|
556
|
+
},
|
|
557
|
+
locate(shape, matrix) {
|
|
558
|
+
return asHandle(cloneAndTransform(asNum(shape), toKernelMatrix(matrix)));
|
|
233
559
|
},
|
|
234
560
|
generalTransform(shape, matrix) {
|
|
235
|
-
|
|
236
|
-
kernel.transformSolid(c, toKernelMatrix(matrix));
|
|
237
|
-
return asHandle(c);
|
|
561
|
+
return asHandle(cloneAndTransform(asNum(shape), toKernelMatrix(matrix)));
|
|
238
562
|
},
|
|
239
|
-
copy(shape) { return asHandle(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
563
|
+
copy(shape) { return asHandle(cloneShape(asNum(shape))); },
|
|
564
|
+
copyShape(shape) { return asHandle(cloneShape(asNum(shape))); },
|
|
565
|
+
composeTransform(m1, m2) {
|
|
566
|
+
// 方言:L1 是 3×4 行主序 12 元素;brepkit composeTransforms 吃/回 4×4 16 元素。
|
|
567
|
+
const r = kernel.composeTransforms(Float64Array.from(toKernelMatrix(m1)), Float64Array.from(toKernelMatrix(m2)));
|
|
568
|
+
return Array.from(r).slice(0, 12);
|
|
569
|
+
},
|
|
570
|
+
mirror(shape, point, normal) {
|
|
571
|
+
return asHandle(kernel.mirror(asNum(shape), point.x, point.y, point.z, normal.x, normal.y, normal.z));
|
|
572
|
+
},
|
|
573
|
+
// ── 阵列 ──
|
|
574
|
+
// brepkit wasm 的 pattern 内核函数都返回 compound(含全部副本)→ 经 getCompoundSolids 拆成数组。
|
|
243
575
|
linearPattern(shape, direction, spacing, count) {
|
|
244
576
|
const compound = kernel.linearPattern(asNum(shape), direction.x, direction.y, direction.z, spacing, count);
|
|
245
577
|
return arr(kernel.getCompoundSolids(compound)).map(asHandle);
|
|
246
578
|
},
|
|
247
|
-
circularPattern(shape,
|
|
579
|
+
circularPattern(shape, _center, axis, _angleStep, count) {
|
|
248
580
|
// ⚠️ brepkit wasm circularPattern(solid, ax, ay, az, count) 无 center/angle 参数:
|
|
249
581
|
// 固定整圆均分(每份 360°/count)。fullAngle=360 时与 vendored/occt 语义一致;
|
|
250
582
|
// 其它角度跨度无法表达(语义限制记录于此,parity 测试用整圆)。
|
|
@@ -256,62 +588,145 @@ export async function createBrepkitPrimitives() {
|
|
|
256
588
|
},
|
|
257
589
|
// ── 曲线构造 ──
|
|
258
590
|
makeLineEdge(start, end) {
|
|
259
|
-
|
|
591
|
+
const e = kernel.makeLineEdge(start.x, start.y, start.z, end.x, end.y, end.z);
|
|
592
|
+
knownEdges.add(e);
|
|
593
|
+
return asHandle(e);
|
|
594
|
+
},
|
|
595
|
+
makeArcEdge(start, mid, end) {
|
|
596
|
+
// 方言消化:occt 吃 3 点;brepkit makeCircleArc3d 吃 (start,end,center,axis)。
|
|
597
|
+
const { center, axis } = circumcircle(start, mid, end);
|
|
598
|
+
const e = kernel.makeCircleArc3d(start.x, start.y, start.z, end.x, end.y, end.z, center.x, center.y, center.z, axis.x, axis.y, axis.z);
|
|
599
|
+
knownEdges.add(e);
|
|
600
|
+
return asHandle(e);
|
|
601
|
+
},
|
|
602
|
+
makeBezierEdge(controlPoints) {
|
|
603
|
+
// 方言消化:L1 吃控制点(Bezier);brepkit 原生 makeNurbsEdge 吃
|
|
604
|
+
// (start,end,degree,knots,control_points,weights)。Bezier = degree n-1 的
|
|
605
|
+
// clamped NURBS,knots = [0]×n + [1]×n,weights 全 1。
|
|
606
|
+
const n = controlPoints.length;
|
|
607
|
+
if (n < 2)
|
|
608
|
+
fail('makeBezierEdge: need at least 2 control points');
|
|
609
|
+
const degree = n - 1;
|
|
610
|
+
const knots = new Float64Array(2 * n);
|
|
611
|
+
for (let i = n; i < 2 * n; i++)
|
|
612
|
+
knots[i] = 1;
|
|
613
|
+
const weights = new Float64Array(n).fill(1);
|
|
614
|
+
const first = controlPoints[0];
|
|
615
|
+
const last = controlPoints[n - 1];
|
|
616
|
+
const e = kernel.makeNurbsEdge(first.x, first.y, first.z, last.x, last.y, last.z, degree, knots, flattenPoints(controlPoints), weights);
|
|
617
|
+
knownEdges.add(e);
|
|
618
|
+
return asHandle(e);
|
|
619
|
+
},
|
|
620
|
+
makeCircleEdge(center, normal, radius) {
|
|
621
|
+
const e = kernel.makeCircleEdge(center.x, center.y, center.z, normal.x, normal.y, normal.z, radius);
|
|
622
|
+
knownEdges.add(e);
|
|
623
|
+
return asHandle(e);
|
|
260
624
|
},
|
|
261
|
-
makeArcEdge(_start, _mid, _end) { return unsupported('makeArcEdge'); },
|
|
262
|
-
makeBezierEdge(_controlPoints) { return unsupported('makeBezierEdge'); },
|
|
263
625
|
// ── 拓扑构造 ──
|
|
264
626
|
makeWire(edges) {
|
|
265
|
-
|
|
627
|
+
const w = kernel.makeWire(Int32Array.from(edges.map(asNum)), false);
|
|
628
|
+
knownWires.add(w);
|
|
629
|
+
return asHandle(w);
|
|
266
630
|
},
|
|
267
|
-
makeFace(wire) {
|
|
268
|
-
|
|
269
|
-
|
|
631
|
+
makeFace(wire) {
|
|
632
|
+
const f = kernel.makeFaceFromWire(asNum(wire));
|
|
633
|
+
knownFaces.add(f);
|
|
634
|
+
return asHandle(f);
|
|
270
635
|
},
|
|
271
|
-
|
|
272
|
-
|
|
636
|
+
makeCompound(shapesList) {
|
|
637
|
+
const kids = arr(shapesList.map(asNum));
|
|
638
|
+
// GOTCHA(2026-09-26):brepkit makeCompound 只接受 **solid** 句柄——把 face/wire
|
|
639
|
+
// (sectionByPlane 截面面组)塞进去即抛 "invalid solid handle"。非实体子句柄时
|
|
640
|
+
// 不调内核,改用高段虚拟句柄(0x80000000+),仅靠 knownCompounds 表分发
|
|
641
|
+
// meshShape/wireframe/getSubShapes/getBoundingBox,不触达内核。
|
|
642
|
+
const hasNonSolid = kids.some((k) => knownFaces.has(k) || knownWires.has(k) || knownEdges.has(k) || knownCompounds.has(k));
|
|
643
|
+
if (hasNonSolid) {
|
|
644
|
+
virtualCompoundCounter++;
|
|
645
|
+
const v = 0x80000000 + virtualCompoundCounter;
|
|
646
|
+
knownCompounds.set(v, kids);
|
|
647
|
+
return asHandle(v);
|
|
648
|
+
}
|
|
649
|
+
const c = kernel.makeCompound(Int32Array.from(kids));
|
|
650
|
+
knownCompounds.set(c, kids);
|
|
651
|
+
return asHandle(c);
|
|
273
652
|
},
|
|
274
|
-
buildTriFace(_a, _b, _c) { return unsupported('buildTriFace'); },
|
|
275
653
|
addHolesInFace(face, holeWires) {
|
|
276
|
-
|
|
654
|
+
// addHolesToFace 返回**新 face 句柄**(同曲面 + 内孔 wire),必须登记进 knownFaces,
|
|
655
|
+
// 否则 profile(op) 带孔面送 meshShape 会落到 solid 路径崩溃。
|
|
656
|
+
const f = kernel.addHolesToFace(asNum(face), Int32Array.from(holeWires.map(asNum)));
|
|
657
|
+
knownFaces.add(f);
|
|
658
|
+
return asHandle(f);
|
|
659
|
+
},
|
|
660
|
+
buildTriFace(a, b, c) {
|
|
661
|
+
const f = kernel.makePolygon(flattenPoints([a, b, c]));
|
|
662
|
+
knownFaces.add(f);
|
|
663
|
+
return asHandle(f);
|
|
277
664
|
},
|
|
278
665
|
// ── 三角化(BREP→mesh 唯一出口) ──
|
|
279
666
|
meshShape(shape, options) {
|
|
280
667
|
const deflection = options?.linearDeflection ?? 0.1;
|
|
281
668
|
const angular = options?.angularDeflection ?? 0.5;
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
//
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
for (let i = 0; i < faceCount; i++) {
|
|
297
|
-
faceGroups[i * 3] = fo[i] / 3;
|
|
298
|
-
faceGroups[i * 3 + 1] = (fo[i + 1] - fo[i]) / 3;
|
|
299
|
-
faceGroups[i * 3 + 2] = faceHashes[i] ?? 0;
|
|
300
|
-
}
|
|
301
|
-
return {
|
|
302
|
-
positions: new Float32Array(m.positions),
|
|
303
|
-
normals: new Float32Array(m.normals),
|
|
304
|
-
indices: new Uint32Array(m.indices),
|
|
305
|
-
vertexCount: m.positions.length / 3,
|
|
306
|
-
triangleCount: m.indices.length / 3,
|
|
307
|
-
faceGroups,
|
|
308
|
-
faceCount,
|
|
309
|
-
};
|
|
669
|
+
const s = asNum(shape);
|
|
670
|
+
// 非实体句柄按已知集合静态分发(见文件头 GOTCHA:brepkit 无 shape-type 分类 API)。
|
|
671
|
+
// 顺序:face → wire → edge → compound → solid。实体创建不入任何集合,天然落 solid 路径。
|
|
672
|
+
if (knownFaces.has(s))
|
|
673
|
+
return faceMesh(s, deflection, angular);
|
|
674
|
+
if (knownWires.has(s))
|
|
675
|
+
return wireMesh(s, deflection);
|
|
676
|
+
if (knownEdges.has(s))
|
|
677
|
+
return edgesToLineMesh([s], deflection);
|
|
678
|
+
const compoundChildren = knownCompounds.get(s);
|
|
679
|
+
if (compoundChildren)
|
|
680
|
+
return compoundMesh(compoundChildren, deflection, angular);
|
|
681
|
+
// solid(或未登记句柄):走原 tessellateSolidGrouped 路径。
|
|
682
|
+
return solidMesh(s, deflection, angular);
|
|
310
683
|
},
|
|
311
684
|
wireframe(shape, deflection) {
|
|
312
685
|
const d = deflection ?? 0.1;
|
|
686
|
+
const s = asNum(shape);
|
|
687
|
+
// GOTCHA:meshEdgesAll 是 solid-only API——buildTopologyFromMesh 会对 face/wire/edge
|
|
688
|
+
// 产物调 wireframe(...),传入非实体句柄即抛 "invalid solid handle"。按已知集合分发:
|
|
689
|
+
// face -> getFaceEdges;wire -> getWireEdges;edge -> [self];否则 solid 走 meshEdgesAll。
|
|
690
|
+
let edgeHandles = null;
|
|
691
|
+
if (knownFaces.has(s))
|
|
692
|
+
edgeHandles = arr(kernel.getFaceEdges(s));
|
|
693
|
+
else if (knownWires.has(s))
|
|
694
|
+
edgeHandles = arr(kernel.getWireEdges(s));
|
|
695
|
+
else if (knownEdges.has(s))
|
|
696
|
+
edgeHandles = [s];
|
|
697
|
+
else if (knownCompounds.has(s)) {
|
|
698
|
+
// compound(sectionByPlane 面组):逐子面收集边。
|
|
699
|
+
edgeHandles = [];
|
|
700
|
+
for (const k of knownCompounds.get(s)) {
|
|
701
|
+
if (knownFaces.has(k))
|
|
702
|
+
edgeHandles.push(...arr(kernel.getFaceEdges(k)));
|
|
703
|
+
else if (knownWires.has(k))
|
|
704
|
+
edgeHandles.push(...arr(kernel.getWireEdges(k)));
|
|
705
|
+
else if (knownEdges.has(k))
|
|
706
|
+
edgeHandles.push(k);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
if (edgeHandles) {
|
|
710
|
+
const nPts = Math.max(12, Math.round(4 / Math.max(d, 0.01)));
|
|
711
|
+
const positions = [];
|
|
712
|
+
const offsets = [0];
|
|
713
|
+
for (const e of edgeHandles) {
|
|
714
|
+
const pts = arr(kernel.tessellateEdge(e, nPts));
|
|
715
|
+
for (const p of pts)
|
|
716
|
+
positions.push(p);
|
|
717
|
+
offsets.push(positions.length / 3);
|
|
718
|
+
}
|
|
719
|
+
const edgeGroups = new Int32Array(edgeHandles.length * 3);
|
|
720
|
+
for (let i = 0; i < edgeHandles.length; i++) {
|
|
721
|
+
edgeGroups[i * 3] = offsets[i] ?? 0;
|
|
722
|
+
edgeGroups[i * 3 + 1] = (offsets[i + 1] ?? positions.length / 3) - (offsets[i] ?? 0);
|
|
723
|
+
edgeGroups[i * 3 + 2] = i;
|
|
724
|
+
}
|
|
725
|
+
return { points: new Float32Array(positions), edgeGroups, pointCount: positions.length / 3, edgeCount: edgeHandles.length };
|
|
726
|
+
}
|
|
727
|
+
// solid(或未登记句柄):走原 meshEdgesAll 路径。
|
|
313
728
|
// JsEdgeLines:edgeCount/offsets/positions 均为属性(offsets/positions 为 TypedArray,2026-09-19 实测)
|
|
314
|
-
const me = kernel.meshEdgesAll(
|
|
729
|
+
const me = kernel.meshEdgesAll(s, d, 0.5);
|
|
315
730
|
const edgeCount = Number(me.edgeCount);
|
|
316
731
|
const offsets = arr(me.offsets);
|
|
317
732
|
const positions = arr(me.positions);
|
|
@@ -334,9 +749,52 @@ export async function createBrepkitPrimitives() {
|
|
|
334
749
|
// edge/vertex 查询时按句柄是否在 knownFaces 里分发到 face 级或 solid 级 API。
|
|
335
750
|
getSubShapes(shape, type) {
|
|
336
751
|
const s = asNum(shape);
|
|
752
|
+
// GOTCHA(2026-09-26 非实体句柄修复):buildTopologyFromMesh 会对**面产物**
|
|
753
|
+
// 调 getSubShapes(face,'face')。brepkit 的 getSolidFaces/getShellFaces 是 solid-only,
|
|
754
|
+
// 对面句柄一个抛 "invalid solid handle"、catch 里再抛 "invalid shell handle"——
|
|
755
|
+
// 两跳都不被捕获即崩溃。brepkit 无 shape-type 分类 API,必须靠已知集合先分发:
|
|
756
|
+
// 输入本身就是 knownFaces 里的一张面时,'face' 返回 [s],edge/vertex 走 face 级 API。
|
|
757
|
+
if (knownFaces.has(s)) {
|
|
758
|
+
if (type === 'face')
|
|
759
|
+
return [asHandle(s)];
|
|
760
|
+
if (type === 'edge') {
|
|
761
|
+
const es = arr(kernel.getFaceEdges(s));
|
|
762
|
+
es.forEach((e) => knownEdges.add(e));
|
|
763
|
+
return es.map(asHandle);
|
|
764
|
+
}
|
|
765
|
+
if (type === 'vertex')
|
|
766
|
+
return arr(kernel.getFaceVertices(s)).map(asHandle);
|
|
767
|
+
return [];
|
|
768
|
+
}
|
|
769
|
+
if (knownWires.has(s)) {
|
|
770
|
+
if (type === 'edge') {
|
|
771
|
+
const es = arr(kernel.getWireEdges(s));
|
|
772
|
+
es.forEach((e) => knownEdges.add(e));
|
|
773
|
+
return es.map(asHandle);
|
|
774
|
+
}
|
|
775
|
+
return [];
|
|
776
|
+
}
|
|
777
|
+
if (knownEdges.has(s)) {
|
|
778
|
+
// input is itself an edge (wire.ts smooth path: interpolatePoints returns edge)
|
|
779
|
+
if (type === 'edge')
|
|
780
|
+
return [asHandle(s)];
|
|
781
|
+
return [];
|
|
782
|
+
}
|
|
783
|
+
const compKids = knownCompounds.get(s);
|
|
784
|
+
if (compKids) {
|
|
785
|
+
// compound(sectionByPlane 面组 / makeCompound 多实体 / importStep 多实体):
|
|
786
|
+
// 'face' 返回子面,'solid' 返回子实体,其余空。
|
|
787
|
+
if (type === 'face')
|
|
788
|
+
return compKids.filter((k) => knownFaces.has(k)).map(asHandle);
|
|
789
|
+
if (type === 'solid')
|
|
790
|
+
return compKids.filter((k) => !knownFaces.has(k) && !knownWires.has(k) && !knownEdges.has(k)).map(asHandle);
|
|
791
|
+
return [];
|
|
792
|
+
}
|
|
337
793
|
let list;
|
|
794
|
+
const isFaceLike = knownFaces.has(s) || derivedFaces.has(s);
|
|
338
795
|
if (type === 'face') {
|
|
339
|
-
// 输入可能是 solid 或 shell
|
|
796
|
+
// 输入可能是 solid 或 shell。枚举到的子面登记到 derivedFaces(不进 knownFaces,
|
|
797
|
+
// 避免与 solid 句柄撞号——见 derivedFaces 注释)。
|
|
340
798
|
try {
|
|
341
799
|
list = arr(kernel.getSolidFaces(s));
|
|
342
800
|
}
|
|
@@ -344,15 +802,15 @@ export async function createBrepkitPrimitives() {
|
|
|
344
802
|
list = arr(kernel.getShellFaces?.(s) ?? []);
|
|
345
803
|
}
|
|
346
804
|
for (const f of list)
|
|
347
|
-
|
|
805
|
+
derivedFaces.add(f);
|
|
348
806
|
}
|
|
349
807
|
else if (type === 'edge') {
|
|
350
|
-
list =
|
|
808
|
+
list = isFaceLike
|
|
351
809
|
? arr(kernel.getFaceEdges(s))
|
|
352
810
|
: arr(kernel.getSolidEdges(s));
|
|
353
811
|
}
|
|
354
812
|
else if (type === 'vertex') {
|
|
355
|
-
list =
|
|
813
|
+
list = isFaceLike
|
|
356
814
|
? arr(kernel.getFaceVertices(s))
|
|
357
815
|
: arr(kernel.getSolidVertices(s));
|
|
358
816
|
}
|
|
@@ -369,24 +827,27 @@ export async function createBrepkitPrimitives() {
|
|
|
369
827
|
}
|
|
370
828
|
}
|
|
371
829
|
else {
|
|
372
|
-
|
|
830
|
+
fail(`getSubShapes(${type}): unsupported sub-shape type`);
|
|
373
831
|
}
|
|
374
832
|
return list.map(asHandle);
|
|
375
833
|
},
|
|
376
|
-
queryBatch(shapes) {
|
|
377
|
-
return shapes.map(h => {
|
|
378
|
-
try {
|
|
379
|
-
return { area: Number(kernel.faceArea(asNum(h))) };
|
|
380
|
-
}
|
|
381
|
-
catch {
|
|
382
|
-
return { area: 0 };
|
|
383
|
-
}
|
|
384
|
-
});
|
|
385
|
-
},
|
|
386
834
|
subShapeHashes(shape, type, hashUpperBound) {
|
|
387
835
|
if (type !== 'face')
|
|
388
|
-
|
|
389
|
-
const
|
|
836
|
+
fail(`subShapeHashes(${type}): only 'face' is supported by brepkit`);
|
|
837
|
+
const s = asNum(shape);
|
|
838
|
+
// GOTCHA:buildTopologyFromMesh 会对面产物调 subShapeHashes(face,'face');
|
|
839
|
+
// getSolidFaces 是 solid-only,对面句柄崩溃。输入本身是已知面时,哈希即其自身指纹。
|
|
840
|
+
if (knownFaces.has(s))
|
|
841
|
+
return [faceFingerprint(kernel, s, hashUpperBound)];
|
|
842
|
+
// wire/edge 无面;compound(sectionByPlane 面组)的子句柄即面。
|
|
843
|
+
if (knownWires.has(s) || knownEdges.has(s))
|
|
844
|
+
return [];
|
|
845
|
+
const compKids = knownCompounds.get(s);
|
|
846
|
+
if (compKids) {
|
|
847
|
+
const faces = compKids.filter((k) => knownFaces.has(k));
|
|
848
|
+
return faces.map((f) => faceFingerprint(kernel, f, hashUpperBound));
|
|
849
|
+
}
|
|
850
|
+
const faces = arr(kernel.getSolidFaces(s));
|
|
390
851
|
const hashes = faces.map(f => faceFingerprint(kernel, f, hashUpperBound));
|
|
391
852
|
// 登记 hash↔handle(fuseWithHistory 溯源对齐依赖此表)
|
|
392
853
|
const reg = hashRegistry.get(kernel) ?? new Map();
|
|
@@ -406,6 +867,16 @@ export async function createBrepkitPrimitives() {
|
|
|
406
867
|
return false;
|
|
407
868
|
}
|
|
408
869
|
},
|
|
870
|
+
shapeType(shape) {
|
|
871
|
+
try {
|
|
872
|
+
const s = arr(kernel.getSolidFaces(asNum(shape)));
|
|
873
|
+
const f = arr(kernel.getFaces(asNum(shape)));
|
|
874
|
+
return s.length > 0 ? 'SOLID' : f.length > 0 ? 'FACE' : 'COMPOUND';
|
|
875
|
+
}
|
|
876
|
+
catch {
|
|
877
|
+
return 'COMPOUND';
|
|
878
|
+
}
|
|
879
|
+
},
|
|
409
880
|
shapeOrientation(shape) {
|
|
410
881
|
try {
|
|
411
882
|
return String(kernel.getShapeOrientation(asNum(shape)));
|
|
@@ -414,6 +885,16 @@ export async function createBrepkitPrimitives() {
|
|
|
414
885
|
return 'forward';
|
|
415
886
|
}
|
|
416
887
|
},
|
|
888
|
+
edgeToFaceMap(shape) {
|
|
889
|
+
// brepkit 返回 JSON 字符串 {"edgeId":[faceId,...]};L1 契约是 unknown(调用方自解析)。
|
|
890
|
+
return kernel.edgeToFaceMap(asNum(shape));
|
|
891
|
+
},
|
|
892
|
+
adjacentFaces(shape, face) {
|
|
893
|
+
return arr(kernel.adjacentFaces(asNum(shape), asNum(face))).map(asHandle);
|
|
894
|
+
},
|
|
895
|
+
sharedEdges(a, b) {
|
|
896
|
+
return arr(kernel.sharedEdges(asNum(a), asNum(b))).map(asHandle);
|
|
897
|
+
},
|
|
417
898
|
// ── 几何求值 ──
|
|
418
899
|
curveType(edge) { return String(kernel.getEdgeCurveType(asNum(edge))); },
|
|
419
900
|
curvePointAtParam(edge, param) {
|
|
@@ -472,12 +953,7 @@ export async function createBrepkitPrimitives() {
|
|
|
472
953
|
const d = toNumArray(kernel.getSurfaceDomain(asNum(face)));
|
|
473
954
|
return { uMin: d[0] ?? 0, uMax: d[1] ?? 1, vMin: d[2] ?? 0, vMax: d[3] ?? 1 };
|
|
474
955
|
},
|
|
475
|
-
|
|
476
|
-
// brepkit 无 per-face 质心 API;用 UV 域中点在曲面上求值作为面中心近似
|
|
477
|
-
// (与 OCCT 路径的「面中心用于命名/拾取锚点」语义一致,不追求精确质心)。
|
|
478
|
-
const b = this.uvBounds(face);
|
|
479
|
-
return this.pointOnSurface(face, (b.uMin + b.uMax) / 2, (b.vMin + b.vMax) / 2);
|
|
480
|
-
},
|
|
956
|
+
surfaceCenterOfMass: faceCenterOfMass,
|
|
481
957
|
getFaceCylinderData(face) {
|
|
482
958
|
try {
|
|
483
959
|
const p = JSON.parse(kernel.getAnalyticSurfaceParams(asNum(face)));
|
|
@@ -496,39 +972,181 @@ export async function createBrepkitPrimitives() {
|
|
|
496
972
|
catch { /* 非 Nurbs 边 */ }
|
|
497
973
|
return null;
|
|
498
974
|
},
|
|
975
|
+
interpolatePoints(points, degree) {
|
|
976
|
+
// GOTCHA:interpolatePoints 返回 **edge** 句柄(不是 wire)——wire.ts smooth 路径把它
|
|
977
|
+
// 直接当 wire 送 solidToShape。登记进 knownEdges,meshShape 才能走 tessellateEdge 路径。
|
|
978
|
+
const e = kernel.interpolatePoints(flattenPoints(points), degree);
|
|
979
|
+
knownEdges.add(e);
|
|
980
|
+
return asHandle(e);
|
|
981
|
+
},
|
|
982
|
+
defeature(shape, faces) {
|
|
983
|
+
return asHandle(kernel.defeature(asNum(shape), Uint32Array.from(faces.map(asNum))));
|
|
984
|
+
},
|
|
985
|
+
draft(shape, faces, pull, neutral, angleDeg) {
|
|
986
|
+
return asHandle(kernel.draft(asNum(shape), Uint32Array.from(faces.map(asNum)), pull.x, pull.y, pull.z, neutral.x, neutral.y, neutral.z, angleDeg));
|
|
987
|
+
},
|
|
988
|
+
removeHolesFromFace(face) {
|
|
989
|
+
// removeHolesFromFace 返回**新 face 句柄**(去掉内孔的同曲面 face),必须登记进 knownFaces。
|
|
990
|
+
const f = kernel.removeHolesFromFace(asNum(face));
|
|
991
|
+
knownFaces.add(f);
|
|
992
|
+
return asHandle(f);
|
|
993
|
+
},
|
|
994
|
+
reverseShape(shape) {
|
|
995
|
+
return asHandle(kernel.reverseShape(asNum(shape)));
|
|
996
|
+
},
|
|
997
|
+
projectEdges(shape, origin, direction, xAxis, hiddenLines, deflection) {
|
|
998
|
+
// brepkit 返回 JSON 字符串 {"visible":[[x,y,…]],"hidden":[[…]]};L1 契约是 unknown。
|
|
999
|
+
return kernel.projectEdges(asNum(shape), origin.x, origin.y, origin.z, direction.x, direction.y, direction.z, xAxis.x, xAxis.y, xAxis.z, hiddenLines, deflection);
|
|
1000
|
+
},
|
|
499
1001
|
// ── 测量 ──
|
|
500
1002
|
getBoundingBox(shape, _useTriangulation) {
|
|
501
|
-
const
|
|
502
|
-
|
|
1003
|
+
const s = asNum(shape);
|
|
1004
|
+
const bboxFromPoints = (pts) => {
|
|
1005
|
+
let xmin = Infinity, ymin = Infinity, zmin = Infinity, xmax = -Infinity, ymax = -Infinity, zmax = -Infinity;
|
|
1006
|
+
for (let i = 0; i + 2 < pts.length; i += 3) {
|
|
1007
|
+
xmin = Math.min(xmin, pts[i]);
|
|
1008
|
+
ymin = Math.min(ymin, pts[i + 1]);
|
|
1009
|
+
zmin = Math.min(zmin, pts[i + 2]);
|
|
1010
|
+
xmax = Math.max(xmax, pts[i]);
|
|
1011
|
+
ymax = Math.max(ymax, pts[i + 1]);
|
|
1012
|
+
zmax = Math.max(zmax, pts[i + 2]);
|
|
1013
|
+
}
|
|
1014
|
+
if (!Number.isFinite(xmin)) {
|
|
1015
|
+
xmin = ymin = zmin = 0;
|
|
1016
|
+
xmax = ymax = zmax = 0;
|
|
1017
|
+
}
|
|
1018
|
+
return { xmin, ymin, zmin, xmax, ymax, zmax };
|
|
1019
|
+
};
|
|
1020
|
+
const solidBbox = (h) => {
|
|
1021
|
+
const b = kernel.boundingBox(h);
|
|
1022
|
+
return { xmin: b[0], ymin: b[1], zmin: b[2], xmax: b[3], ymax: b[4], zmax: b[5] };
|
|
1023
|
+
};
|
|
1024
|
+
const kids = knownCompounds.get(s);
|
|
1025
|
+
if (kids) {
|
|
1026
|
+
let xmin = Infinity, ymin = Infinity, zmin = Infinity, xmax = -Infinity, ymax = -Infinity, zmax = -Infinity;
|
|
1027
|
+
for (const k of kids) {
|
|
1028
|
+
try {
|
|
1029
|
+
let b;
|
|
1030
|
+
if (knownFaces.has(k))
|
|
1031
|
+
b = bboxFromPoints(arr(kernel.tessellateFace(k, 0.1, 1).positions));
|
|
1032
|
+
else if (knownWires.has(k))
|
|
1033
|
+
b = bboxFromPoints(arr(kernel.getWireEdges(k)).flatMap((e) => arr(kernel.tessellateEdge(e, 16))));
|
|
1034
|
+
else if (knownEdges.has(k))
|
|
1035
|
+
b = bboxFromPoints(arr(kernel.tessellateEdge(k, 16)));
|
|
1036
|
+
else
|
|
1037
|
+
b = solidBbox(k);
|
|
1038
|
+
xmin = Math.min(xmin, b.xmin);
|
|
1039
|
+
ymin = Math.min(ymin, b.ymin);
|
|
1040
|
+
zmin = Math.min(zmin, b.zmin);
|
|
1041
|
+
xmax = Math.max(xmax, b.xmax);
|
|
1042
|
+
ymax = Math.max(ymax, b.ymax);
|
|
1043
|
+
zmax = Math.max(zmax, b.zmax);
|
|
1044
|
+
}
|
|
1045
|
+
catch { /* 子项 bbox 查询失败忽略 */ }
|
|
1046
|
+
}
|
|
1047
|
+
if (!Number.isFinite(xmin)) {
|
|
1048
|
+
xmin = ymin = zmin = 0;
|
|
1049
|
+
xmax = ymax = zmax = 0;
|
|
1050
|
+
}
|
|
1051
|
+
return { xmin, ymin, zmin, xmax, ymax, zmax };
|
|
1052
|
+
}
|
|
1053
|
+
// GOTCHA:kernel.boundingBox 是 solid-only。face/wire/edge 句柄必须走 tessellation 采样,
|
|
1054
|
+
// 否则 measure() 对 wire/profile 调 getBoundingBox 即崩 "invalid solid handle"。
|
|
1055
|
+
if (knownFaces.has(s))
|
|
1056
|
+
return bboxFromPoints(arr(kernel.tessellateFace(s, 0.1, 1).positions));
|
|
1057
|
+
if (knownWires.has(s))
|
|
1058
|
+
return bboxFromPoints(arr(kernel.getWireEdges(s)).flatMap((e) => arr(kernel.tessellateEdge(e, 16))));
|
|
1059
|
+
if (knownEdges.has(s))
|
|
1060
|
+
return bboxFromPoints(arr(kernel.tessellateEdge(s, 16)));
|
|
1061
|
+
return solidBbox(s);
|
|
503
1062
|
},
|
|
504
1063
|
getVolume(shape) { return Number(kernel.volume(asNum(shape), 0.05)); },
|
|
505
1064
|
getCenterOfMass(shape) {
|
|
506
1065
|
// centerOfMass 返回 Float64Array [x,y,z](非 JSON 字符串)
|
|
507
1066
|
return vec3Of(toNumArray(kernel.centerOfMass(asNum(shape), 0.05)));
|
|
508
1067
|
},
|
|
1068
|
+
getSurfaceArea(shape) {
|
|
1069
|
+
// 方言映射:L1 getSurfaceArea ↔ brepkit surfaceArea(solid, deflection)。
|
|
1070
|
+
return Number(kernel.surfaceArea(asNum(shape), 0.05));
|
|
1071
|
+
},
|
|
1072
|
+
getLength(shape) {
|
|
1073
|
+
// 方言映射:L1 getLength ↔ brepkit edgeLength(edge) / wireLength(wire)。
|
|
1074
|
+
// wire 与 edge 的入参差异在适配器内判别(D6):edgeLength 只吃 edge 句柄,
|
|
1075
|
+
// 对 wire 会抛错;据此分发,两条路径都失败时如实抛出(不静默返回 0)。
|
|
1076
|
+
const s = asNum(shape);
|
|
1077
|
+
try {
|
|
1078
|
+
kernel.getEdgeCurveType(s);
|
|
1079
|
+
return Number(kernel.edgeLength(s));
|
|
1080
|
+
}
|
|
1081
|
+
catch {
|
|
1082
|
+
return Number(kernel.wireLength(s));
|
|
1083
|
+
}
|
|
1084
|
+
},
|
|
509
1085
|
// ── 校验与修复 ──
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
1086
|
+
// ⚠️ brepkit 的修复类内核函数全部是「**原地修改入参实体 + 返回修复计数**」,不是返回新句柄:
|
|
1087
|
+
// healSolid(solid) → 修复的问题数
|
|
1088
|
+
// fixFaceOrientations(solid) → 修复的面数
|
|
1089
|
+
// unifyFaces(solid) → 合并删除的面数
|
|
1090
|
+
// removeDegenerateEdges(s,tol) → 删除的边数
|
|
1091
|
+
// repairSolid(solid) → 修复后剩余错误数
|
|
1092
|
+
// 直接 `asHandle(kernel.healSolid(...))` 会把计数(常见为 0)当成句柄,得到无效实体
|
|
1093
|
+
// (2026-09-25 实证)。正确适配:先 copySolid 保护调用方原实体,再原地修复副本,返回副本句柄。
|
|
1094
|
+
isValid(shape) {
|
|
1095
|
+
// brepkit validateSolid 返回错误数(0 = 有效)。
|
|
1096
|
+
return Number(kernel.validateSolid(asNum(shape))) === 0;
|
|
1097
|
+
},
|
|
1098
|
+
unifySameDomain(shape) {
|
|
1099
|
+
const c = kernel.copySolid(asNum(shape));
|
|
1100
|
+
kernel.unifyFaces(c);
|
|
1101
|
+
return asHandle(c);
|
|
1102
|
+
},
|
|
1103
|
+
healSolid(shape, _tolerance) {
|
|
1104
|
+
const c = kernel.copySolid(asNum(shape));
|
|
1105
|
+
kernel.healSolid(c);
|
|
1106
|
+
return asHandle(c);
|
|
1107
|
+
},
|
|
1108
|
+
fixShape(shape) {
|
|
1109
|
+
const c = kernel.copySolid(asNum(shape));
|
|
1110
|
+
kernel.healSolid(c);
|
|
1111
|
+
return asHandle(c);
|
|
1112
|
+
},
|
|
1113
|
+
fixFaceOrientations(shape) {
|
|
1114
|
+
const c = kernel.copySolid(asNum(shape));
|
|
1115
|
+
kernel.fixFaceOrientations(c);
|
|
1116
|
+
return asHandle(c);
|
|
1117
|
+
},
|
|
1118
|
+
removeDegenerateEdges(shape, tolerance) {
|
|
1119
|
+
const c = kernel.copySolid(asNum(shape));
|
|
1120
|
+
kernel.removeDegenerateEdges(c, tolerance ?? 1e-6);
|
|
1121
|
+
return asHandle(c);
|
|
1122
|
+
},
|
|
516
1123
|
// ── IO ──
|
|
517
1124
|
importStep(data) {
|
|
518
|
-
|
|
519
|
-
|
|
1125
|
+
// ⚠️ brepkit importStep 吃 **Uint8Array**(不是字符串),返回 **Uint32Array**(文件内可含多个 solid)。
|
|
1126
|
+
// L1 契约是单 BrepHandle:0 个 → fail;1 个 → 直通;多个 → 合成 compound(2026-09-25 实证)。
|
|
1127
|
+
const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data);
|
|
1128
|
+
const solids = arr(kernel.importStep(bytes));
|
|
1129
|
+
if (solids.length === 0)
|
|
1130
|
+
fail('importStep: kernel returned no solid');
|
|
1131
|
+
return asHandle(solids.length === 1 ? solids[0] : kernel.makeCompound(Uint32Array.from(solids)));
|
|
520
1132
|
},
|
|
521
1133
|
exportStep(shape) {
|
|
522
1134
|
// brepkit exportStep 返回 UTF-8 字节(Uint8Array),需解码为 STEP 文本(2026-09-19 实测)
|
|
523
1135
|
const bytes = kernel.exportStep(asNum(shape));
|
|
524
1136
|
return typeof bytes === 'string' ? bytes : new TextDecoder().decode(bytes);
|
|
525
1137
|
},
|
|
526
|
-
importStl(
|
|
1138
|
+
importStl(data) {
|
|
1139
|
+
const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data);
|
|
1140
|
+
return asHandle(kernel.importStl(bytes));
|
|
1141
|
+
},
|
|
527
1142
|
fromBREP(data) {
|
|
528
|
-
|
|
529
|
-
|
|
1143
|
+
// ⚠️ brepkit fromBREP 吃字符串(STEP 文本或 toBREP/toBrepJson 输出,内核自动判别),
|
|
1144
|
+
// 与 serializeSolid/deserializeSolid 的**二进制 arena** 是两套机制。
|
|
1145
|
+
// 旧实现误用 `deserializeSolid(atob(data))`:base64 解码破坏了 STEP 文本 → 往返必失败
|
|
1146
|
+
// (2026-09-25 实证:fromBREP(STEP)、fromBREP(toBREP)、fromBREP(toBrepJson) 均成功)。
|
|
1147
|
+
return asHandle(kernel.fromBREP(data));
|
|
530
1148
|
},
|
|
531
|
-
// ──
|
|
1149
|
+
// ── 面演化(L1 三员 + filletWithHistory,双方都有对齐实现) ──
|
|
532
1150
|
cutWithHistory(a, b, inputFaceHashes, hashUpperBound) {
|
|
533
1151
|
const raw = kernel.cutWithEvolution(asNum(a), asNum(b));
|
|
534
1152
|
return mapEvolution(kernel, raw, JSON.parse(raw).solid, inputFaceHashes, hashUpperBound);
|
|
@@ -537,73 +1155,10 @@ export async function createBrepkitPrimitives() {
|
|
|
537
1155
|
const raw = kernel.fuseWithEvolution(asNum(a), asNum(b));
|
|
538
1156
|
return mapEvolution(kernel, raw, JSON.parse(raw).solid, inputFaceHashes, hashUpperBound);
|
|
539
1157
|
},
|
|
540
|
-
intersectWithHistory(
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
// Phase 0.1 补齐的 7 个:brepkit 适配器 v1 未实现 —— 如实抛错,不伪造。
|
|
544
|
-
// ⚠️ 这些桩**不能**被当作"已实现"来探测:`typeof api.xWithHistory === 'function'`
|
|
545
|
-
// 恒为真。Phase 0.2 起适配器的 `evolution` 是逐核函数**名单**
|
|
546
|
-
// (`adapters/brepkit.ts` = ['fuse','cut','fillet']),名单才是唯一真相来源;
|
|
547
|
-
// 声明多写一项 = 让该 op 静默通过静态判定后死在这些桩上(红线违规)。
|
|
548
|
-
translateWithHistory(_shape, _dx, _dy, _dz, _inputFaceHashes, _hashUpperBound) {
|
|
549
|
-
return unsupported('translateWithHistory');
|
|
550
|
-
},
|
|
551
|
-
rotateWithHistory(_shape, _axis, _angleRad, _inputFaceHashes, _hashUpperBound) {
|
|
552
|
-
return unsupported('rotateWithHistory');
|
|
553
|
-
},
|
|
554
|
-
mirrorWithHistory(_shape, _point, _normal, _inputFaceHashes, _hashUpperBound) {
|
|
555
|
-
return unsupported('mirrorWithHistory');
|
|
556
|
-
},
|
|
557
|
-
scaleWithHistory(_shape, _center, _factor, _inputFaceHashes, _hashUpperBound) {
|
|
558
|
-
return unsupported('scaleWithHistory');
|
|
559
|
-
},
|
|
560
|
-
shellWithHistory(_solid, _faces, _thickness, _tolerance, _inputFaceHashes, _hashUpperBound) {
|
|
561
|
-
return unsupported('shellWithHistory');
|
|
562
|
-
},
|
|
563
|
-
offsetWithHistory(_solid, _distance, _tolerance, _inputFaceHashes, _hashUpperBound) {
|
|
564
|
-
return unsupported('offsetWithHistory');
|
|
565
|
-
},
|
|
566
|
-
thickenWithHistory(_shape, _thickness, _tolerance, _inputFaceHashes, _hashUpperBound) {
|
|
567
|
-
return unsupported('thickenWithHistory');
|
|
1158
|
+
intersectWithHistory(a, b, inputFaceHashes, hashUpperBound) {
|
|
1159
|
+
const raw = kernel.intersectWithEvolution(asNum(a), asNum(b));
|
|
1160
|
+
return mapEvolution(kernel, raw, JSON.parse(raw).solid, inputFaceHashes, hashUpperBound);
|
|
568
1161
|
},
|
|
569
|
-
// ── XCAF 装配(v1 关闭) ──
|
|
570
|
-
createXCAFDocument() { return unsupported('createXCAFDocument'); },
|
|
571
|
-
importXCAFFromSTEP(_stepData) { return unsupported('importXCAFFromSTEP'); },
|
|
572
|
-
// ── Phase 3 登记方法(capability-map 64 方法收口):真实现 3 个(wasm 有对应导出,
|
|
573
|
-
// 命名映射),其余如实 unsupported——能力表不声明,静态判定拦截 ──
|
|
574
|
-
boundingBox(shape) { return kernel.getBoundingBox(asNum(shape)); },
|
|
575
|
-
surfaceCenterOfMass(face) { return kernel.getSurfaceCenterOfMass(asNum(face)); },
|
|
576
|
-
dispose(_shape) { },
|
|
577
|
-
shapeType(_shape) { return unsupported('shapeType'); },
|
|
578
|
-
isNull(_shape) { return unsupported('isNull'); },
|
|
579
|
-
iterShapes(_shape) { return unsupported('iterShapes'); },
|
|
580
|
-
locate(_shape, _matrix) { return unsupported('locate'); },
|
|
581
|
-
copyShape(_shape) { return unsupported('copyShape'); },
|
|
582
|
-
downcast(_shape, _targetType) { return unsupported('downcast'); },
|
|
583
|
-
composeTransform(_m1, _m2) { return unsupported('composeTransform'); },
|
|
584
|
-
buildExtrusionLaw(_profile, _length, _endFactor) { return unsupported('buildExtrusionLaw'); },
|
|
585
|
-
buildEdgeOnSurface(_curve, _surface) { return unsupported('buildEdgeOnSurface'); },
|
|
586
|
-
healFace(_shape, _tolerance) { return unsupported('healFace'); },
|
|
587
|
-
healWire(_shape, _tolerance) { return unsupported('healWire'); },
|
|
588
|
-
fixSelfIntersection(_wire) { return unsupported('fixSelfIntersection'); },
|
|
589
|
-
hullFromPoints(_points, _tolerance) { return unsupported('hullFromPoints'); },
|
|
590
|
-
loftAdvanced(_wires, _options) { return unsupported('loftAdvanced'); },
|
|
591
|
-
makeEllipsoid(rx, ry, rz) { return asHandle(kernel.makeEllipsoid(rx, ry, rz)); }, // Phase 3: wasm 同签名真实现(brepkit-wasm.d.ts:1354)
|
|
592
|
-
makeFaceOnSurface(_face, _wire) { return unsupported('makeFaceOnSurface'); },
|
|
593
|
-
makeTorus(majorRadius, minorRadius) { return asHandle(kernel.makeTorus(majorRadius, minorRadius, 64)); }, // Phase 3: wasm 真实现(segments 固定 64,BrepEngineApi 不暴露)
|
|
594
|
-
makeVertex(x, y, z) { return asHandle(kernel.makeVertex(x, y, z)); }, // Phase 3: wasm 同签名真实现
|
|
595
|
-
makeWireFromMixed(_items) { return unsupported('makeWireFromMixed'); },
|
|
596
|
-
mirror(shape, point, normal) { return asHandle(kernel.mirror(asNum(shape), point.x, point.y, point.z, normal.x, normal.y, normal.z)); }, // Phase 3: wasm 真实现
|
|
597
|
-
revolveVec(_shape, _center, _direction, _angleDeg) { return unsupported('revolveVec'); },
|
|
598
|
-
sew(_shapes, _tolerance) { return unsupported('sew'); },
|
|
599
|
-
shell(solid, facesToRemove, thickness, _tolerance) { return asHandle(kernel.shell(asNum(solid), thickness, Uint32Array.from(facesToRemove.map(asNum)))); }, // Phase 3: wasm 真实现(tolerance 忽略)
|
|
600
|
-
simplePipe(_profile, _spine) { return unsupported('simplePipe'); },
|
|
601
|
-
simplify(_shape) { return unsupported('simplify'); },
|
|
602
|
-
split(_shape, _tools) { return unsupported('split'); }, // ⚠️ wasm split 是平面分割(solid+平面参数),与 BrepEngineApi 工具实体分割语义不匹配 → 保持 unsupported
|
|
603
|
-
sweepPipeShell(_profile, _spine, _freenet, _smooth) { return unsupported('sweepPipeShell'); },
|
|
604
|
-
generalTransformNonOrthogonal(_shape, _matrix) { return unsupported('generalTransformNonOrthogonal'); },
|
|
605
|
-
generalTransformWithHistory(_shape, _matrix, _inputFaceHashes, _hashUpperBound) { return unsupported('generalTransformWithHistory'); },
|
|
606
|
-
applyComposedTransformWithHistory(_shape, _matrix, _inputFaceHashes, _hashUpperBound) { return unsupported('applyComposedTransformWithHistory'); },
|
|
607
1162
|
};
|
|
608
1163
|
return api;
|
|
609
1164
|
}
|
|
@@ -647,14 +1202,23 @@ function vec3Of(p) {
|
|
|
647
1202
|
return { x: p[0], y: p[1], z: p[2] };
|
|
648
1203
|
return { x: Number(p.x), y: Number(p.y), z: Number(p.z) };
|
|
649
1204
|
}
|
|
650
|
-
/**
|
|
651
|
-
function atobPolyfill(s) {
|
|
652
|
-
if (typeof atob === 'function')
|
|
653
|
-
return atob(s);
|
|
654
|
-
return Buffer.from(s, 'base64').toString('binary');
|
|
655
|
-
}
|
|
656
|
-
/** 释放内核单例(测试收尾用;宿主常驻不需调用)。 */
|
|
1205
|
+
/** 已初始化的 brepkit 内核单例(createBrepkitPrimitives 时赋值)。 */
|
|
657
1206
|
let liveKernel = null;
|
|
1207
|
+
/**
|
|
1208
|
+
* 原生 brepkit 内核面(D3):平台特定代码访问 brepkit 独有能力的唯一入口
|
|
1209
|
+
* (chamfer2d/chamferV2/filletV2/sketch* 族、serializeSolid、meshBoolean 等)。
|
|
1210
|
+
*
|
|
1211
|
+
* ⚠️ 这是**平台特定**出口——import 本函数即声明「这段代码只跑在 brepkit 引擎下」。
|
|
1212
|
+
* 可移植代码请用 `getBrepApi()`(L1 契约面)。
|
|
1213
|
+
*
|
|
1214
|
+
* @returns the live brepkit wasm kernel singleton.
|
|
1215
|
+
*/
|
|
1216
|
+
export function getBrepkitKernel() {
|
|
1217
|
+
if (!liveKernel) {
|
|
1218
|
+
throw new Error('[brepkit-kernel] kernel not initialized: call createBrepkitPrimitives() first');
|
|
1219
|
+
}
|
|
1220
|
+
return liveKernel;
|
|
1221
|
+
}
|
|
658
1222
|
/** 释放内核单例(测试收尾用;宿主常驻不需调用)。 */
|
|
659
1223
|
export function disposeBrepkit() {
|
|
660
1224
|
try {
|