@faicad/faijs 0.33.2 → 0.35.8

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 (429) hide show
  1. package/dist/api/api-namespace.d.ts +14 -14
  2. package/dist/api/api-namespace.d.ts.map +1 -1
  3. package/dist/api/api-namespace.js +40 -14
  4. package/dist/api/api-namespace.js.map +1 -1
  5. package/dist/api/appearance.d.ts +47 -6
  6. package/dist/api/appearance.d.ts.map +1 -1
  7. package/dist/api/appearance.js.map +1 -1
  8. package/dist/api/assembly/entities.js +14 -4
  9. package/dist/api/assembly/entities.js.map +1 -1
  10. package/dist/api/assembly/solve-tree.d.ts +1 -0
  11. package/dist/api/assembly/solve-tree.d.ts.map +1 -1
  12. package/dist/api/assembly/solve-tree.js +42 -17
  13. package/dist/api/assembly/solve-tree.js.map +1 -1
  14. package/dist/api/assembly/solve.d.ts +1 -0
  15. package/dist/api/assembly/solve.d.ts.map +1 -1
  16. package/dist/api/assembly/solve.js.map +1 -1
  17. package/dist/api/assembly/solvers/global-solver.d.ts.map +1 -1
  18. package/dist/api/assembly/solvers/global-solver.js +130 -23
  19. package/dist/api/assembly/solvers/global-solver.js.map +1 -1
  20. package/dist/api/assembly/solvers/pose-from-delta.d.ts +9 -0
  21. package/dist/api/assembly/solvers/pose-from-delta.d.ts.map +1 -1
  22. package/dist/api/assembly/solvers/pose-from-delta.js +23 -0
  23. package/dist/api/assembly/solvers/pose-from-delta.js.map +1 -1
  24. package/dist/api/assembly/solvers/types.d.ts +20 -2
  25. package/dist/api/assembly/solvers/types.d.ts.map +1 -1
  26. package/dist/api/assembly/solvers/types.js.map +1 -1
  27. package/dist/api/chamfer.d.ts +7 -4
  28. package/dist/api/chamfer.d.ts.map +1 -1
  29. package/dist/api/chamfer.js +57 -13
  30. package/dist/api/chamfer.js.map +1 -1
  31. package/dist/api/draft.d.ts +7 -4
  32. package/dist/api/draft.d.ts.map +1 -1
  33. package/dist/api/draft.js +11 -6
  34. package/dist/api/draft.js.map +1 -1
  35. package/dist/api/edge-ref.d.ts +4 -4
  36. package/dist/api/edge-ref.js +4 -4
  37. package/dist/api/edge-ref.js.map +1 -1
  38. package/dist/api/extrude.d.ts +10 -6
  39. package/dist/api/extrude.d.ts.map +1 -1
  40. package/dist/api/extrude.js +54 -26
  41. package/dist/api/extrude.js.map +1 -1
  42. package/dist/api/face-ref.d.ts +4 -4
  43. package/dist/api/face-ref.js +4 -4
  44. package/dist/api/face-ref.js.map +1 -1
  45. package/dist/api/feature-repair.d.ts +6 -3
  46. package/dist/api/feature-repair.d.ts.map +1 -1
  47. package/dist/api/feature-repair.js +12 -7
  48. package/dist/api/feature-repair.js.map +1 -1
  49. package/dist/api/fillet-variable.d.ts +6 -2
  50. package/dist/api/fillet-variable.d.ts.map +1 -1
  51. package/dist/api/fillet-variable.js +24 -6
  52. package/dist/api/fillet-variable.js.map +1 -1
  53. package/dist/api/fillet.d.ts +7 -4
  54. package/dist/api/fillet.d.ts.map +1 -1
  55. package/dist/api/fillet.js +92 -12
  56. package/dist/api/fillet.js.map +1 -1
  57. package/dist/api/generated/script-face-manifest.js +1 -1
  58. package/dist/api/generated/script-face-manifest.js.map +1 -1
  59. package/dist/api/generated/topology.js +1 -1
  60. package/dist/api/generated/topology.js.map +1 -1
  61. package/dist/api/helix.d.ts +13 -13
  62. package/dist/api/helix.d.ts.map +1 -1
  63. package/dist/api/helix.js +19 -24
  64. package/dist/api/helix.js.map +1 -1
  65. package/dist/api/import-brep.d.ts +10 -18
  66. package/dist/api/import-brep.d.ts.map +1 -1
  67. package/dist/api/import-brep.js +17 -25
  68. package/dist/api/import-brep.js.map +1 -1
  69. package/dist/api/import-step.d.ts +10 -15
  70. package/dist/api/import-step.d.ts.map +1 -1
  71. package/dist/api/import-step.js +24 -29
  72. package/dist/api/import-step.js.map +1 -1
  73. package/dist/api/index.js +2 -2
  74. package/dist/api/index.js.map +1 -1
  75. package/dist/api/internal/export-members.js.map +1 -1
  76. package/dist/api/loft-advanced.d.ts +4 -0
  77. package/dist/api/loft-advanced.d.ts.map +1 -1
  78. package/dist/api/loft-advanced.js +4 -0
  79. package/dist/api/loft-advanced.js.map +1 -1
  80. package/dist/api/loft.d.ts +5 -3
  81. package/dist/api/loft.d.ts.map +1 -1
  82. package/dist/api/loft.js +5 -3
  83. package/dist/api/loft.js.map +1 -1
  84. package/dist/api/meta.d.ts +42 -6
  85. package/dist/api/meta.d.ts.map +1 -1
  86. package/dist/api/meta.js.map +1 -1
  87. package/dist/api/primitives.d.ts +3 -2
  88. package/dist/api/primitives.d.ts.map +1 -1
  89. package/dist/api/primitives.js +3 -2
  90. package/dist/api/primitives.js.map +1 -1
  91. package/dist/api/punch-hole.d.ts +5 -2
  92. package/dist/api/punch-hole.d.ts.map +1 -1
  93. package/dist/api/punch-hole.js +4 -1
  94. package/dist/api/punch-hole.js.map +1 -1
  95. package/dist/api/replicate.d.ts +4 -5
  96. package/dist/api/replicate.d.ts.map +1 -1
  97. package/dist/api/replicate.js +4 -5
  98. package/dist/api/replicate.js.map +1 -1
  99. package/dist/api/selectors-to-refs.d.ts +83 -0
  100. package/dist/api/selectors-to-refs.d.ts.map +1 -0
  101. package/dist/api/selectors-to-refs.js +211 -0
  102. package/dist/api/selectors-to-refs.js.map +1 -0
  103. package/dist/api/shell.d.ts +17 -8
  104. package/dist/api/shell.d.ts.map +1 -1
  105. package/dist/api/shell.js +45 -15
  106. package/dist/api/shell.js.map +1 -1
  107. package/dist/api/sketch-on-face.d.ts +12 -6
  108. package/dist/api/sketch-on-face.d.ts.map +1 -1
  109. package/dist/api/sketch-on-face.js +31 -4
  110. package/dist/api/sketch-on-face.js.map +1 -1
  111. package/dist/api/sketch-on-plane.d.ts +3 -0
  112. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  113. package/dist/api/sketch-on-plane.js +3 -0
  114. package/dist/api/sketch-on-plane.js.map +1 -1
  115. package/dist/api/sketch-on-surface.d.ts +4 -1
  116. package/dist/api/sketch-on-surface.d.ts.map +1 -1
  117. package/dist/api/sketch-on-surface.js +4 -1
  118. package/dist/api/sketch-on-surface.js.map +1 -1
  119. package/dist/api/surface/arg-spec.d.ts.map +1 -1
  120. package/dist/api/surface/arg-spec.js +5 -6
  121. package/dist/api/surface/arg-spec.js.map +1 -1
  122. package/dist/api/topo-resolve.d.ts.map +1 -1
  123. package/dist/api/topo-resolve.js +24 -5
  124. package/dist/api/topo-resolve.js.map +1 -1
  125. package/dist/api/view/view-projection.d.ts.map +1 -1
  126. package/dist/api/view/view-projection.js +9 -2
  127. package/dist/api/view/view-projection.js.map +1 -1
  128. package/dist/brep/brep-chain.js +2 -2
  129. package/dist/brep/brep-chain.js.map +1 -1
  130. package/dist/brep/brep-ops.d.ts +1 -1
  131. package/dist/brep/brep-ops.js +1 -1
  132. package/dist/brep/brep-ops.js.map +1 -1
  133. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  134. package/dist/brep/engine/adapters/brep-mock.js +45 -0
  135. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  136. package/dist/brep/engine/primitives.d.ts +87 -3
  137. package/dist/brep/engine/primitives.d.ts.map +1 -1
  138. package/dist/brep/engine/primitives.js +1 -1
  139. package/dist/brep/engine/primitives.js.map +1 -1
  140. package/dist/brep/engine/registry.d.ts +33 -7
  141. package/dist/brep/engine/registry.d.ts.map +1 -1
  142. package/dist/brep/engine/registry.js +47 -16
  143. package/dist/brep/engine/registry.js.map +1 -1
  144. package/dist/brep/handle-bridge.d.ts +14 -15
  145. package/dist/brep/handle-bridge.d.ts.map +1 -1
  146. package/dist/brep/handle-bridge.js +35 -15
  147. package/dist/brep/handle-bridge.js.map +1 -1
  148. package/dist/brep/primitives-brep.js +2 -2
  149. package/dist/brep/primitives-brep.js.map +1 -1
  150. package/dist/brep/text/text-to-solid.d.ts +40 -3
  151. package/dist/brep/text/text-to-solid.d.ts.map +1 -1
  152. package/dist/brep/text/text-to-solid.js +104 -24
  153. package/dist/brep/text/text-to-solid.js.map +1 -1
  154. package/dist/brepkit-kernel/brepkitKernel.d.ts +2 -2
  155. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  156. package/dist/brepkit-kernel/brepkitKernel.js +328 -38
  157. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  158. package/dist/brepkit-kernel/brepkitWasm.d.ts +3 -1
  159. package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
  160. package/dist/brepkit-kernel/brepkitWasm.js +13 -9
  161. package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
  162. package/dist/brepkit-kernel/multi-version-test.d.ts +2 -2
  163. package/dist/brepkit-kernel/multi-version-test.d.ts.map +1 -1
  164. package/dist/brepkit-kernel/multi-version-test.js +6 -6
  165. package/dist/brepkit-kernel/multi-version-test.js.map +1 -1
  166. package/dist/browser.d.ts +2 -3
  167. package/dist/browser.d.ts.map +1 -1
  168. package/dist/browser.js +1 -2
  169. package/dist/browser.js.map +1 -1
  170. package/dist/cad-runtime/admit-compat-lib.d.ts +9 -1
  171. package/dist/cad-runtime/admit-compat-lib.d.ts.map +1 -1
  172. package/dist/cad-runtime/admit-compat-lib.js +11 -1
  173. package/dist/cad-runtime/admit-compat-lib.js.map +1 -1
  174. package/dist/cad-runtime/browser-lib-loader.d.ts +16 -11
  175. package/dist/cad-runtime/browser-lib-loader.d.ts.map +1 -1
  176. package/dist/cad-runtime/browser-lib-loader.js +16 -8
  177. package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
  178. package/dist/cad-runtime/direct-executor.d.ts +62 -5
  179. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  180. package/dist/cad-runtime/direct-executor.js +617 -42
  181. package/dist/cad-runtime/direct-executor.js.map +1 -1
  182. package/dist/cad-runtime/interp/closure.d.ts +3 -2
  183. package/dist/cad-runtime/interp/closure.d.ts.map +1 -1
  184. package/dist/cad-runtime/interp/closure.js.map +1 -1
  185. package/dist/cad-runtime/interp/env.d.ts +9 -6
  186. package/dist/cad-runtime/interp/env.d.ts.map +1 -1
  187. package/dist/cad-runtime/interp/env.js +4 -2
  188. package/dist/cad-runtime/interp/env.js.map +1 -1
  189. package/dist/cad-runtime/lib-decl.d.ts +121 -0
  190. package/dist/cad-runtime/lib-decl.d.ts.map +1 -0
  191. package/dist/cad-runtime/lib-decl.js +100 -0
  192. package/dist/cad-runtime/lib-decl.js.map +1 -0
  193. package/dist/cad-runtime/ports.d.ts +12 -0
  194. package/dist/cad-runtime/ports.d.ts.map +1 -1
  195. package/dist/cad-runtime/ports.js.map +1 -1
  196. package/dist/cad-runtime/runtime.d.ts +59 -5
  197. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  198. package/dist/cad-runtime/runtime.js +252 -20
  199. package/dist/cad-runtime/runtime.js.map +1 -1
  200. package/dist/extra/browser.d.ts +9 -0
  201. package/dist/extra/browser.d.ts.map +1 -0
  202. package/dist/extra/browser.js +9 -0
  203. package/dist/extra/browser.js.map +1 -0
  204. package/dist/extra/editor-ops.d.ts +22 -0
  205. package/dist/extra/editor-ops.d.ts.map +1 -0
  206. package/dist/extra/editor-ops.js +21 -0
  207. package/dist/extra/editor-ops.js.map +1 -0
  208. package/dist/extra/extras/svg-extrude.d.ts +45 -0
  209. package/dist/extra/extras/svg-extrude.d.ts.map +1 -0
  210. package/dist/extra/extras/svg-extrude.js +110 -0
  211. package/dist/extra/extras/svg-extrude.js.map +1 -0
  212. package/dist/extra/extras/text-cjk.d.ts +36 -0
  213. package/dist/extra/extras/text-cjk.d.ts.map +1 -0
  214. package/dist/extra/extras/text-cjk.js +86 -0
  215. package/dist/extra/extras/text-cjk.js.map +1 -0
  216. package/dist/extra/extras/text-geometry.d.ts +69 -0
  217. package/dist/extra/extras/text-geometry.d.ts.map +1 -0
  218. package/dist/extra/extras/text-geometry.js +188 -0
  219. package/dist/extra/extras/text-geometry.js.map +1 -0
  220. package/dist/extra/index.d.ts +40 -0
  221. package/dist/extra/index.d.ts.map +1 -0
  222. package/dist/extra/index.js +40 -0
  223. package/dist/extra/index.js.map +1 -0
  224. package/dist/extra/mesh/drill-hole/DrillHoleCore.d.ts +94 -0
  225. package/dist/extra/mesh/drill-hole/DrillHoleCore.d.ts.map +1 -0
  226. package/dist/extra/mesh/drill-hole/DrillHoleCore.js +282 -0
  227. package/dist/extra/mesh/drill-hole/DrillHoleCore.js.map +1 -0
  228. package/dist/extra/mesh/drill-hole/drill-types.d.ts +34 -0
  229. package/dist/extra/mesh/drill-hole/drill-types.d.ts.map +1 -0
  230. package/dist/extra/mesh/drill-hole/drill-types.js +7 -0
  231. package/dist/extra/mesh/drill-hole/drill-types.js.map +1 -0
  232. package/dist/extra/mesh/engrave-decoration.d.ts +42 -0
  233. package/dist/extra/mesh/engrave-decoration.d.ts.map +1 -0
  234. package/dist/extra/mesh/engrave-decoration.js +39 -0
  235. package/dist/extra/mesh/engrave-decoration.js.map +1 -0
  236. package/dist/extra/mesh/fai_drill.d.ts +21 -0
  237. package/dist/extra/mesh/fai_drill.d.ts.map +1 -0
  238. package/dist/extra/mesh/fai_drill.js +89 -0
  239. package/dist/extra/mesh/fai_drill.js.map +1 -0
  240. package/dist/extra/mesh/fai_extrude.d.ts +24 -0
  241. package/dist/extra/mesh/fai_extrude.d.ts.map +1 -0
  242. package/dist/extra/mesh/fai_extrude.js +42 -0
  243. package/dist/extra/mesh/fai_extrude.js.map +1 -0
  244. package/dist/extra/mesh/fai_split.d.ts +164 -0
  245. package/dist/extra/mesh/fai_split.d.ts.map +1 -0
  246. package/dist/extra/mesh/fai_split.js +269 -0
  247. package/dist/extra/mesh/fai_split.js.map +1 -0
  248. package/dist/extra/mesh/primitives.d.ts +29 -0
  249. package/dist/extra/mesh/primitives.d.ts.map +1 -0
  250. package/dist/extra/mesh/primitives.js +41 -0
  251. package/dist/extra/mesh/primitives.js.map +1 -0
  252. package/dist/extra/op-names.d.ts +37 -0
  253. package/dist/extra/op-names.d.ts.map +1 -0
  254. package/dist/extra/op-names.js +46 -0
  255. package/dist/extra/op-names.js.map +1 -0
  256. package/dist/extra/ops/compound.d.ts +140 -0
  257. package/dist/extra/ops/compound.d.ts.map +1 -0
  258. package/dist/extra/ops/compound.js +167 -0
  259. package/dist/extra/ops/compound.js.map +1 -0
  260. package/dist/extra/ops/copy.d.ts +40 -0
  261. package/dist/extra/ops/copy.d.ts.map +1 -0
  262. package/dist/extra/ops/copy.js +83 -0
  263. package/dist/extra/ops/copy.js.map +1 -0
  264. package/dist/extra/ops/fai_drill.d.ts +51 -0
  265. package/dist/extra/ops/fai_drill.d.ts.map +1 -0
  266. package/dist/extra/ops/fai_drill.js +233 -0
  267. package/dist/extra/ops/fai_drill.js.map +1 -0
  268. package/dist/extra/ops/fai_extrude.d.ts +36 -0
  269. package/dist/extra/ops/fai_extrude.d.ts.map +1 -0
  270. package/dist/extra/ops/fai_extrude.js +84 -0
  271. package/dist/extra/ops/fai_extrude.js.map +1 -0
  272. package/dist/extra/ops/fai_split.d.ts +46 -0
  273. package/dist/extra/ops/fai_split.d.ts.map +1 -0
  274. package/dist/extra/ops/fai_split.js +235 -0
  275. package/dist/extra/ops/fai_split.js.map +1 -0
  276. package/dist/extra/ops/load.d.ts +49 -0
  277. package/dist/extra/ops/load.d.ts.map +1 -0
  278. package/dist/extra/ops/load.js +423 -0
  279. package/dist/extra/ops/load.js.map +1 -0
  280. package/dist/extra/ops/svg-extrude.d.ts +32 -0
  281. package/dist/extra/ops/svg-extrude.d.ts.map +1 -0
  282. package/dist/extra/ops/svg-extrude.js +74 -0
  283. package/dist/extra/ops/svg-extrude.js.map +1 -0
  284. package/dist/extra/ops/text.d.ts +34 -0
  285. package/dist/extra/ops/text.d.ts.map +1 -0
  286. package/dist/extra/ops/text.js +100 -0
  287. package/dist/extra/ops/text.js.map +1 -0
  288. package/dist/geometry2d/bridge/lift-on-plane.d.ts +8 -5
  289. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
  290. package/dist/geometry2d/bridge/lift-on-plane.js +8 -5
  291. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
  292. package/dist/index.d.ts +6 -2
  293. package/dist/index.d.ts.map +1 -1
  294. package/dist/index.js +8 -2
  295. package/dist/index.js.map +1 -1
  296. package/dist/lang/symbol-table.d.ts +3 -3
  297. package/dist/lang/symbol-table.generated.d.ts +10 -0
  298. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  299. package/dist/lang/symbol-table.generated.js +10 -0
  300. package/dist/lang/symbol-table.generated.js.map +1 -1
  301. package/dist/lang/symbol-table.js +3 -3
  302. package/dist/lang/symbol-table.js.map +1 -1
  303. package/dist/math3d/index.d.ts +1 -1
  304. package/dist/math3d/index.js +1 -1
  305. package/dist/math3d/index.js.map +1 -1
  306. package/dist/mesh/engrave.d.ts +2 -3
  307. package/dist/mesh/engrave.d.ts.map +1 -1
  308. package/dist/mesh/engrave.js +4 -11
  309. package/dist/mesh/engrave.js.map +1 -1
  310. package/dist/mesh/index.d.ts +0 -2
  311. package/dist/mesh/index.d.ts.map +1 -1
  312. package/dist/mesh/index.js +0 -2
  313. package/dist/mesh/index.js.map +1 -1
  314. package/dist/mesh/primitives.d.ts +7 -5
  315. package/dist/mesh/primitives.d.ts.map +1 -1
  316. package/dist/mesh/primitives.js +16 -9
  317. package/dist/mesh/primitives.js.map +1 -1
  318. package/dist/mesh/types.d.ts +4 -3
  319. package/dist/mesh/types.d.ts.map +1 -1
  320. package/dist/mesh/types.js.map +1 -1
  321. package/dist/node-host/cli.d.ts +11 -4
  322. package/dist/node-host/cli.d.ts.map +1 -1
  323. package/dist/node-host/cli.js +53 -28
  324. package/dist/node-host/cli.js.map +1 -1
  325. package/dist/node-host/execute-script.d.ts.map +1 -1
  326. package/dist/node-host/execute-script.js +3 -4
  327. package/dist/node-host/execute-script.js.map +1 -1
  328. package/dist/node-host/lib-package-json.d.ts +36 -0
  329. package/dist/node-host/lib-package-json.d.ts.map +1 -0
  330. package/dist/node-host/lib-package-json.js +73 -0
  331. package/dist/node-host/lib-package-json.js.map +1 -0
  332. package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
  333. package/dist/occt-kernel/occt-primitives.js +41 -0
  334. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  335. package/dist/occt-kernel/occtKernel.d.ts +1 -1
  336. package/dist/occt-kernel/occtKernel.js +1 -1
  337. package/dist/occt-kernel/occtKernel.js.map +1 -1
  338. package/dist/primitives/brep-primitives.d.ts.map +1 -1
  339. package/dist/primitives/brep-primitives.js +39 -12
  340. package/dist/primitives/brep-primitives.js.map +1 -1
  341. package/dist/runtime-state.d.ts +28 -1
  342. package/dist/runtime-state.d.ts.map +1 -1
  343. package/dist/runtime-state.js +14 -1
  344. package/dist/runtime-state.js.map +1 -1
  345. package/dist/sdk.d.ts +2 -2
  346. package/dist/sdk.d.ts.map +1 -1
  347. package/dist/sdk.js +11 -2
  348. package/dist/sdk.js.map +1 -1
  349. package/dist/sketch/bspline.d.ts +58 -0
  350. package/dist/sketch/bspline.d.ts.map +1 -0
  351. package/dist/sketch/bspline.js +104 -0
  352. package/dist/sketch/bspline.js.map +1 -0
  353. package/dist/sketch/canonical.d.ts +239 -0
  354. package/dist/sketch/canonical.d.ts.map +1 -0
  355. package/dist/sketch/canonical.js +17 -0
  356. package/dist/sketch/canonical.js.map +1 -0
  357. package/dist/sketch/contour.d.ts +43 -0
  358. package/dist/sketch/contour.d.ts.map +1 -0
  359. package/dist/sketch/contour.js +202 -0
  360. package/dist/sketch/contour.js.map +1 -0
  361. package/dist/sketch/dim-spec.d.ts +32 -0
  362. package/dist/sketch/dim-spec.d.ts.map +1 -0
  363. package/dist/sketch/dim-spec.js +112 -0
  364. package/dist/sketch/dim-spec.js.map +1 -0
  365. package/dist/sketch/faces.d.ts +45 -0
  366. package/dist/sketch/faces.d.ts.map +1 -0
  367. package/dist/sketch/faces.js +108 -0
  368. package/dist/sketch/faces.js.map +1 -0
  369. package/dist/sketch/fcstd-types.d.ts +194 -0
  370. package/dist/sketch/fcstd-types.d.ts.map +1 -0
  371. package/dist/sketch/fcstd-types.js +67 -0
  372. package/dist/sketch/fcstd-types.js.map +1 -0
  373. package/dist/sketch/index.d.ts +46 -0
  374. package/dist/sketch/index.d.ts.map +1 -0
  375. package/dist/sketch/index.js +39 -0
  376. package/dist/sketch/index.js.map +1 -0
  377. package/dist/sketch/node.d.ts +14 -0
  378. package/dist/sketch/node.d.ts.map +1 -0
  379. package/dist/sketch/node.js +43 -0
  380. package/dist/sketch/node.js.map +1 -0
  381. package/dist/sketch/op.d.ts +111 -0
  382. package/dist/sketch/op.d.ts.map +1 -0
  383. package/dist/sketch/op.js +185 -0
  384. package/dist/sketch/op.js.map +1 -0
  385. package/dist/sketch/planegcs-backend.d.ts +69 -0
  386. package/dist/sketch/planegcs-backend.d.ts.map +1 -0
  387. package/dist/sketch/planegcs-backend.js +812 -0
  388. package/dist/sketch/planegcs-backend.js.map +1 -0
  389. package/dist/sketch/project.d.ts +176 -0
  390. package/dist/sketch/project.d.ts.map +1 -0
  391. package/dist/sketch/project.js +656 -0
  392. package/dist/sketch/project.js.map +1 -0
  393. package/dist/sketch/shapes.d.ts +370 -0
  394. package/dist/sketch/shapes.d.ts.map +1 -0
  395. package/dist/sketch/shapes.js +959 -0
  396. package/dist/sketch/shapes.js.map +1 -0
  397. package/dist/sketch/solve.d.ts +21 -0
  398. package/dist/sketch/solve.d.ts.map +1 -0
  399. package/dist/sketch/solve.js +144 -0
  400. package/dist/sketch/solve.js.map +1 -0
  401. package/dist/sketch/solver-loader.d.ts +47 -0
  402. package/dist/sketch/solver-loader.d.ts.map +1 -0
  403. package/dist/sketch/solver-loader.js +77 -0
  404. package/dist/sketch/solver-loader.js.map +1 -0
  405. package/dist/sketch/solver.d.ts +63 -0
  406. package/dist/sketch/solver.d.ts.map +1 -0
  407. package/dist/sketch/solver.js +28 -0
  408. package/dist/sketch/solver.js.map +1 -0
  409. package/dist/sketch/verify.d.ts +53 -0
  410. package/dist/sketch/verify.d.ts.map +1 -0
  411. package/dist/sketch/verify.js +71 -0
  412. package/dist/sketch/verify.js.map +1 -0
  413. package/dist/topology/naming/geom-hint.d.ts +12 -0
  414. package/dist/topology/naming/geom-hint.d.ts.map +1 -1
  415. package/dist/topology/naming/geom-hint.js +1 -1
  416. package/dist/topology/naming/geom-hint.js.map +1 -1
  417. package/dist/topology/naming/lineage.d.ts +1 -0
  418. package/dist/topology/naming/lineage.d.ts.map +1 -1
  419. package/dist/topology/naming/lineage.js +37 -1
  420. package/dist/topology/naming/lineage.js.map +1 -1
  421. package/dist/topology/naming/resolve-face.d.ts +13 -2
  422. package/dist/topology/naming/resolve-face.d.ts.map +1 -1
  423. package/dist/topology/naming/resolve-face.js +18 -2
  424. package/dist/topology/naming/resolve-face.js.map +1 -1
  425. package/dist/weapp.d.ts +1 -1
  426. package/dist/weapp.d.ts.map +1 -1
  427. package/dist/weapp.js +1 -1
  428. package/dist/weapp.js.map +1 -1
  429. package/package.json +43 -11
@@ -25,36 +25,45 @@
25
25
  import { solidToShape } from '../brep/brep-ops.js';
26
26
  import { chamferWithRoleTable, identityEvolution } from '../brep/face-evolution.js';
27
27
  import { getBrepApi } from '../brep/handle-bridge.js';
28
- import { getCurrentStmt } from '../runtime-state.js';
28
+ import { getCurrentStmt, nameOf, setName } from '../runtime-state.js';
29
29
  import { hasNativeHistory } from '../brep/engine/native-history.js';
30
- import { fromBrep, brepOf, inputRoleTable } from '../shape.js';
30
+ import { fromBrep, brepOf, inputRoleTable, resolveCompoundMember, replaceCompoundMember } from '../shape.js';
31
31
  import { defineOp } from '../sdk.js';
32
32
  import { resolveTopoRef, facesForQualifier, TopoRefError } from '../topology/naming/index.js';
33
33
  import { buildEdgeResolutionContext, buildEdgeContextFromSolid } from './topo-resolve.js';
34
+ import { expandEdgeSelectorRefs } from './selectors-to-refs.js';
34
35
  import { OpError } from './internal/result-unwrap.js';
35
36
  import { meshKernelFailure, meshSolidEntry, meshSolidProduct, resolveMeshEdges } from './internal/mesh-solid-op.js';
36
37
  import { angleBetweenNormals, materialDihedralFromNormalAngle, chamferAngleFromDistances } from './chamfer-math.js';
37
38
  // ── 参数自校验(api 层被直接 import 时的防御层)──
38
39
  /**
39
40
  * Validate chamfer parameters: `edges` must be a non-empty array of EdgeTopoRef,
40
- * each with kind key "edge" and a two-entry faces pair — or of 1-based ordinals
41
- * when `opts.allowOrdinals` (the mesh chain, which has no role layer to match
42
- * edges against).
41
+ * each with kind key "edge" and a two-entry faces pair — or of selector strings
42
+ * (`"|Z"` etc., precision chain) — or of 1-based ordinals when
43
+ * `opts.allowOrdinals` (the mesh chain, which has no role layer to match
44
+ * edges against). A top-level selector string is also accepted.
43
45
  * @param params the raw chamfer operation parameters.
44
46
  * @param opts the selector-form options (mesh chain allows ordinals).
45
47
  */
46
48
  export function assertChamferParams(params, opts) {
47
49
  const edges = params.edges;
48
- if (!Array.isArray(edges) || edges.length === 0) {
50
+ const list = typeof edges === 'string' ? [edges] : edges;
51
+ if (typeof edges !== 'string' && (!Array.isArray(edges) || list.length === 0)) {
49
52
  throw new Error('E_CHAMFER_NO_EDGES: chamfer requires at least one edge');
50
53
  }
51
- for (const e of edges) {
54
+ for (const e of list) {
52
55
  if (opts?.allowOrdinals && typeof e === 'number') {
53
56
  if (!Number.isInteger(e) || e < 1) {
54
57
  throw new Error('E_CHAMFER_BAD_EDGE_REF: an edge ordinal must be a positive integer (1-based)');
55
58
  }
56
59
  continue;
57
60
  }
61
+ if (typeof e === 'string') {
62
+ if (e.trim() === '') {
63
+ throw new Error('E_CHAMFER_BAD_EDGE_REF: an edge selector string must not be empty');
64
+ }
65
+ continue;
66
+ }
58
67
  if (!e || typeof e !== 'object' || e.kind !== 'edge') {
59
68
  throw new Error('E_CHAMFER_BAD_EDGE_REF: every edge entry must be an EdgeTopoRef with kind:"edge"');
60
69
  }
@@ -195,6 +204,8 @@ function chamferBrep(input, params) {
195
204
  const ctx = buildEdgeResolutionContext(kernel, input);
196
205
  if (!ctx)
197
206
  throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', 'input has no edge naming context');
207
+ // 展开选择器字符串 → EdgeTopoRef[](顶层字符串或数组元素字符串)
208
+ const edgeRefs = expandEdgeSelectorRefs(input, (edges ?? []));
198
209
  // 输入 roleTable + outStmt(与 boolean.ts / fillet.ts 同构)。Phase 1.6:origin=StmtId。
199
210
  const inputTable = inputRoleTable(input);
200
211
  const outStmt = String(getCurrentStmt()?.id ?? '');
@@ -208,7 +219,7 @@ function chamferBrep(input, params) {
208
219
  let roleTable;
209
220
  switch (type) {
210
221
  case 'equal': {
211
- const edgeHandles = edges.map((e) => resolveEdge(ctx, e).handle);
222
+ const edgeHandles = edgeRefs.map((e) => resolveEdge(ctx, e).handle);
212
223
  if (useHistory) {
213
224
  // occt 历史路径(P5:chamferWithHistory + roleTable 传播,§3.2 末段)
214
225
  const r = chamferWithRoleTable(kernel, solid, edgeHandles, params.width, inputTable ?? new Map(), outStmt);
@@ -225,7 +236,7 @@ function chamferBrep(input, params) {
225
236
  break;
226
237
  }
227
238
  case 'distanceAngle':
228
- resultSolid = kernel.chamferDistAngle(solid, edges.map((e) => resolveEdge(ctx, e).handle), params.width, params.angle);
239
+ resultSolid = kernel.chamferDistAngle(solid, edgeRefs.map((e) => resolveEdge(ctx, e).handle), params.width, params.angle);
229
240
  if (useHistory) {
230
241
  // occt:chamferDistAngle 无 WithHistory 版本——用恒等面演化 + 原表(既有行为)。
231
242
  faceEvolution = identityEvolution(kernel, resultSolid);
@@ -238,7 +249,7 @@ function chamferBrep(input, params) {
238
249
  }
239
250
  break;
240
251
  case 'twoDistances':
241
- resultSolid = chamferTwoDistances(kernel, edges, ctx, solid, params.width1, params.width2);
252
+ resultSolid = chamferTwoDistances(kernel, edgeRefs, ctx, solid, params.width1, params.width2);
242
253
  if (useHistory) {
243
254
  faceEvolution = identityEvolution(kernel, resultSolid);
244
255
  roleTable = inputTable;
@@ -277,6 +288,10 @@ function chamferMeshSolid(input, params) {
277
288
  'carries width1/width2; a mesh solid has no role layer — use type:"equal" or "distanceAngle"');
278
289
  }
279
290
  const entry = meshSolidEntry(input, 'chamfer');
291
+ // 选择器字符串只服务精度链(网格零件无 role 层);网格链用 1 起序号。
292
+ if (typeof edges === 'string' || (Array.isArray(edges) && edges.some((e) => typeof e === 'string'))) {
293
+ throw new TopoRefError('E_TOPO_MESH_UNSUPPORTED', 'edge', 'chamfer: selector strings are precision-chain only — mesh solids have no role layer (use 1-based edge ordinals)');
294
+ }
280
295
  const edgeHandles = resolveMeshEdges(entry, edges, 'chamfer');
281
296
  let result;
282
297
  try {
@@ -289,6 +304,23 @@ function chamferMeshSolid(input, params) {
289
304
  }
290
305
  return meshSolidProduct(entry, result);
291
306
  }
307
+ /**
308
+ * 多零件 load 的 compound 成员是匿名 Shape:其面 role(`imported:<memberIdx>:<i>`)
309
+ * 记录在父 compound 变量名(part 键)的合并表里,成员自身没有 part 名。解包后
310
+ * 若直接把匿名 target 喂给 chamferBrep,`buildEdgeResolutionContext` 经
311
+ * `nameOf(target)` 查 part 键表会得到 undefined → E_TOPO_NOT_FOUND。
312
+ *
313
+ * 这里让 target 继承父 part 名(仅当 target 尚未命名时),使其 part 键表命中父
314
+ * compound 的合并表——合并表包含该成员全部面的 role→hash,几何上正确。单零件
315
+ * 路径 input===target 且 target 已被执行器命名,`!nameOf(target)` 守卫使其空转。
316
+ */
317
+ function adoptParentPartName(input, target) {
318
+ if (target === input)
319
+ return;
320
+ const parentName = nameOf(input);
321
+ if (parentName && !nameOf(target))
322
+ setName(target, parentName);
323
+ }
292
324
  /**
293
325
  * 在几何体上倒角(等距 / 双距 / 距角)。
294
326
  * @group 特征
@@ -301,7 +333,7 @@ function chamferMeshSolid(input, params) {
301
333
  * `width1` 沿 faces[0] 侧、`width2` 沿 faces[1] 侧(BREP 路径)。
302
334
  * @returns Shape 倒角后的几何。
303
335
  * @param input - 目标几何。type:Shape required:true
304
- * @param params.edges - 参与倒角的边(EdgeTopoRef[],条目为相邻两面的 role 线路)。type:EdgeTopoRef[] required:true
336
+ * @param params.edges - 参与倒角的边:CadQuery 边选择器字符串(如 "|Z",AI 生成)或相邻两面的 role 线路(EdgeTopoRef[],UI 拾取产物)。type:EdgeTopoRef[]|string required:true
305
337
  * @param params.type - 倒角类型(equal | twoDistances | distanceAngle)。type:string required:true
306
338
  * @param params.width - type=equal: 倒角宽度(mm)。type:number 默认 1
307
339
  * @param params.width1 - type=twoDistances: 沿 faces[0] 侧距离(mm)。type:number
@@ -309,6 +341,8 @@ function chamferMeshSolid(input, params) {
309
341
  * @param params.angle - type=distanceAngle: 与参考面夹角(度,(0,90))。type:number
310
342
  * @example
311
343
  * const p = await cad.chamfer(part0, { edges: [{ kind:'edge', faces:[{ origin:'box', role:'box:top' }, { origin:'box', role:'box:front' }], hint:{ kind:'edge' } }], type:'equal', width:1 })
344
+ * // AI 生成可写 CadQuery 边选择器字符串
345
+ * const p2 = await cad.chamfer(part0, { edges: "|Z", type:'equal', width:1 })
312
346
  * const q = await cad.chamfer(meshPart, { edges: [3], type:'equal', width:1 })
313
347
  */
314
348
  export const chamfer = defineOp({
@@ -318,11 +352,21 @@ export const chamfer = defineOp({
318
352
  meshEngines: ['brepkit'],
319
353
  mesh(input, params) {
320
354
  assertChamferParams(params, { allowOrdinals: true });
321
- return chamferMeshSolid(input, params);
355
+ // P2:多零件 load 输入是 compound——按 partIndex 取目标成员,结果替换回原
356
+ // compound(其余 children 原样),与 fai_extrude/fai_drill 同构。
357
+ const target = resolveCompoundMember(input, params.partIndex, 'chamfer');
358
+ const result = chamferMeshSolid(target, params);
359
+ return replaceCompoundMember(input, params.partIndex, result);
322
360
  },
323
361
  brep(input, params) {
324
362
  assertChamferParams(params);
325
- return chamferBrep(input, params);
363
+ const target = resolveCompoundMember(input, params.partIndex, 'chamfer');
364
+ // 多零件 load 的成员匿名:其面 role 记录在父 compound 的 part 键合并表里。
365
+ // 解包后让 target 继承父 part 名,buildEdgeResolutionContext/inputRoleTable
366
+ // 才能按 part 名查到表(单零件 input===target 且已命名,无副作用)。
367
+ adoptParentPartName(input, target);
368
+ const result = chamferBrep(target, params);
369
+ return replaceCompoundMember(input, params.partIndex, result);
326
370
  },
327
371
  naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } },
328
372
  paramDims: {},
@@ -1 +1 @@
1
- {"version":3,"file":"chamfer.js","sourceRoot":"","sources":["../../src/api/chamfer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api chamfer — chamfer 倒角库函数(BREP-only,directEdit 族)\n *\n * 平台分层(2026-09-26 B 批降级):**中立 op**(不再声明 `engines:['occt']`)。\n * equal 分支按引擎事实**静态定轨**(与 intersect 同构,读 `hasNativeHistory`——\n * 引擎身份是唯一判据,没有能力集可读):\n * - occt(原生有 `chamferWithHistory`)→ `chamferWithRoleTable`(→ face-evolution.ts 的\n * occt 原生 `chamferWithHistory`,D3 面演化 + roleTable 传播)——历史路径,不回退;\n * - brepkit(无 `chamferWithHistory`,但裸 `kernel.chamfer` 是真实现)→ L1 裸\n * `kernel.chamfer(solid, edges, width)`:几何正确,**无面演化、无 roleTable 传播**\n * (如实降级,不伪造恒等映射)。\n * distanceAngle / twoDistances 分支本就走 L1 `kernel.chamferDistAngle`(brepkit 真实现,\n * 度→弧度方言在 brepkitKernel 内消化);occt 上仍挂 identityEvolution + 原 roleTable\n * (既有行为,零回退),brepkit 上同样不伪造演化。\n *\n * 与 drill/engrave 的差异:没有 mesh 实现(defineOp({ brep })),输入非 BREP\n * 时由 dispatchPath 抛 E_MESH_UNSUPPORTED。\n *\n * 类型:\n * - equal(对称):occt→chamferWithHistory;brepkit→kernel.chamfer(solid, edges, width)\n * - distanceAngle:kernel.chamferDistAngle(solid, edges, width, angle)\n * - twoDistances(双距):逐边按 §3.5 换算(width1,width2 + β → dF, θ),\n * per-edge 调 kernel.chamferDistAngle;凹棱(β ≥ 180°)→ E_CHAMFER_REFLEX_EDGE。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { chamferWithRoleTable, identityEvolution } from '../brep/face-evolution'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { getCurrentStmt } from '../runtime-state'\nimport { hasNativeHistory } from '../brep/engine/native-history'\nimport { fromBrep, brepOf, inputRoleTable } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { EdgeTopoRef, ResolutionContext } from '../topology/naming'\nimport { resolveTopoRef, facesForQualifier, TopoRefError } from '../topology/naming'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { buildEdgeResolutionContext, buildEdgeContextFromSolid } from './topo-resolve'\nimport { OpError } from './internal/result-unwrap'\nimport { meshKernelFailure, meshSolidEntry, meshSolidProduct, resolveMeshEdges } from './internal/mesh-solid-op'\nimport { angleBetweenNormals, materialDihedralFromNormalAngle, chamferAngleFromDistances } from './chamfer-math'\n\n// ── 参数自校验(api 层被直接 import 时的防御层)──\n\n/**\n * Validate chamfer parameters: `edges` must be a non-empty array of EdgeTopoRef,\n * each with kind key \"edge\" and a two-entry faces pair — or of 1-based ordinals\n * when `opts.allowOrdinals` (the mesh chain, which has no role layer to match\n * edges against).\n * @param params the raw chamfer operation parameters.\n * @param opts the selector-form options (mesh chain allows ordinals).\n */\nexport function assertChamferParams(\n params: Record<string, unknown>,\n opts?: { readonly allowOrdinals?: boolean },\n): void {\n const edges = params.edges\n if (!Array.isArray(edges) || edges.length === 0) {\n throw new Error('E_CHAMFER_NO_EDGES: chamfer requires at least one edge')\n }\n for (const e of edges) {\n if (opts?.allowOrdinals && typeof e === 'number') {\n if (!Number.isInteger(e) || e < 1) {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: an edge ordinal must be a positive integer (1-based)')\n }\n continue\n }\n if (!e || typeof e !== 'object' || (e as { kind?: unknown }).kind !== 'edge') {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: every edge entry must be an EdgeTopoRef with kind:\"edge\"')\n }\n const faces = (e as { faces?: unknown }).faces\n if (!Array.isArray(faces) || faces.length !== 2) {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: EdgeTopoRef.faces must be a two-entry RoleQualifier pair')\n }\n }\n const type = params.type\n if (type !== 'equal' && type !== 'twoDistances' && type !== 'distanceAngle') {\n throw new Error('E_CHAMFER_BAD_TYPE: type must be equal | twoDistances | distanceAngle')\n }\n if (type === 'equal' || type === 'distanceAngle') {\n const width = params.width\n if (typeof width !== 'number' || !Number.isFinite(width) || width <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width must be a positive number')\n }\n if (type === 'distanceAngle') {\n const angle = params.angle\n if (typeof angle !== 'number' || !Number.isFinite(angle) || angle <= 0 || angle >= 90) {\n throw new Error('E_CHAMFER_BAD_ANGLE: chamfer.angle must be in (0, 90) degrees')\n }\n }\n } else {\n const w1 = params.width1\n const w2 = params.width2\n if (typeof w1 !== 'number' || !Number.isFinite(w1) || w1 <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width1 must be a positive number')\n }\n if (typeof w2 !== 'number' || !Number.isFinite(w2) || w2 <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width2 must be a positive number')\n }\n }\n}\n\n// ── §3.5 几何换算 ──\n\n/** 面中心外法向(与 captureFaceHint 同口径)。 */\nfunction faceMidNormal(kernel: BrepEngineApi, face: BrepHandle): [number, number, number] {\n const uv = kernel.uvBounds(face)\n const n = kernel.surfaceNormal(face, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2)\n return [n.x, n.y, n.z]\n}\n\nfunction dot3(a: readonly number[], b: readonly number[]): number {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\n}\n\nfunction radToDeg(rad: number): number {\n return (rad * 180) / Math.PI\n}\n\n/** 复刻 occt-wasm 的双层枚举(config.rs:517-527):返回内核选用的参考面在\n * `faceHandles`(getSubShapes(solid,'face'))数组中的下标(0 起);找不到 → null。 */\nfunction refFaceIndex(kernel: BrepEngineApi, faceHandles: BrepHandle[], edge: BrepHandle): number | null {\n for (let fi = 0; fi < faceHandles.length; fi++) {\n for (const fe of kernel.getSubShapes(faceHandles[fi], 'edge')) {\n if (kernel.isSame(fe, edge)) return fi\n }\n }\n return null\n}\n\n/** 两邻面 outer-normal 夹角 → β(材料侧二面角,弧度)。 */\nfunction materialDihedralRad(kernel: BrepEngineApi, ctx: ResolutionContext, a: number, b: number): number {\n const ha = ctx.faces[a - 1]?.handle\n const hb = ctx.faces[b - 1]?.handle\n if (ha === undefined || hb === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `chamfer: adjacent face ${a}/${b} has no live handle`)\n }\n const gamma = angleBetweenNormals(dot3(faceMidNormal(kernel, ha), faceMidNormal(kernel, hb)))\n return materialDihedralFromNormalAngle(gamma)\n}\n\n/**\n * twoDistances 单边换算:width1/width2 + β(§3.5)→ (dF, θ) 供一次 chamferDistAngle。\n * 参考面由内核自选(refOrdinal 的面);width1 对应 faces[0] 侧、width2 对应 faces[1] 侧。\n *\n * @param kernel the OCCT kernel.\n * @param ctx the edge resolution context (faces with live handles).\n * @param refAOrdinal resolved ordinal of `EdgeTopoRef.faces[0]` (1-based).\n * @param refBOrdinal resolved ordinal of `EdgeTopoRef.faces[1]` (1-based).\n * @param refOrdinal the kernel reference face ordinal (1-based; the F in §3.5).\n * @param width1 the `width1` argument.\n * @param width2 the `width2` argument.\n * @returns { dF, angleDeg } for a single `kernel.chamferDistAngle` call.\n */\nexport function twoDistParams(\n kernel: BrepEngineApi,\n ctx: ResolutionContext,\n refAOrdinal: number,\n refBOrdinal: number,\n refOrdinal: number,\n width1: number,\n width2: number,\n): { distance: number; angleDeg: number } {\n const betaRad = materialDihedralRad(kernel, ctx, refAOrdinal, refBOrdinal)\n // dF/dO:§3.5 —— 内核参考面 == faces[0] → width1,== faces[1] → width2。\n let dF: number\n let dO: number\n if (refOrdinal === refAOrdinal) {\n dF = width1\n dO = width2\n } else if (refOrdinal === refBOrdinal) {\n dF = width2\n dO = width1\n } else {\n throw new Error(`E_CHAMFER_EDGE_MISMATCH: kernel ref face ordinal ${refOrdinal} not in [${refAOrdinal}, ${refBOrdinal}]`)\n }\n const angleRad = chamferAngleFromDistances(dF, dO, betaRad)\n return { distance: dF, angleDeg: radToDeg(angleRad) }\n}\n\n/** 解析一条 EdgeTopoRef → (ordinal, handle);失败抛命名层 TopoRefError。 */\nfunction resolveEdge(ctx: ResolutionContext, ref: EdgeTopoRef): { ordinal: number; handle: BrepHandle } {\n const r = resolveTopoRef(ref, ctx)\n if (r.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `chamfer: edge resolved without handle (${ref.faces[0].role}/${ref.faces[1].role})`)\n }\n return { ordinal: r.ordinal, handle: r.handle as BrepHandle }\n}\n\n/** twoDistances 逐边构建(§3.6 V1):每条边一次 chamferDistAngle。 */\nfunction chamferTwoDistances(\n kernel: BrepEngineApi,\n edges: EdgeTopoRef[],\n startCtx: ResolutionContext,\n solid: BrepHandle,\n width1: number,\n width2: number,\n): BrepHandle {\n let resultSolid = solid\n for (const ref of edges) {\n const ctx = resultSolid === solid ? startCtx : buildEdgeContextFromSolid(kernel, resultSolid, startCtx.roleTable)\n const entity = resolveEdge(ctx, ref)\n const faces = resultSolid === solid ? startCtx.faces : ctx.faces\n const idx = refFaceIndex(kernel, faces.map((f) => f.handle).filter((h): h is BrepHandle => h !== undefined), entity.handle)\n if (idx === null) {\n throw new Error('E_CHAMFER_EDGE_MISMATCH: kernel cannot locate ref face (bug)')\n }\n const a = facesForQualifier(ref.faces[0], ctx)[0]\n const b = facesForQualifier(ref.faces[1], ctx)[0]\n const refOrdinal = idx + 1\n const p = twoDistParams(kernel, ctx, a?.ordinal ?? -1, b?.ordinal ?? -1, refOrdinal, width1, width2)\n resultSolid = kernel.chamferDistAngle(resultSolid, [entity.handle], p.distance, p.angleDeg)\n }\n return resultSolid\n}\n\n/** BREP-only 主入口(§3.6 flow)。 */\nfunction chamferBrep(input: Shape, params: Record<string, unknown>): Shape {\n // L1 面:chamferDistAngle/枚举/命名(D12)。equal 分支经 face-evolution 走 occt 平台面。\n const kernel = getBrepApi()\n const solid = brepOf(input) as BrepHandle | undefined\n if (solid === undefined) throw new Error('[api/chamfer] E_CHAMFER_NO_BREP: input is not BREP')\n\n const edges = (params.edges as unknown as EdgeTopoRef[] | undefined) ?? []\n const type = params.type as string\n const ctx = buildEdgeResolutionContext(kernel, input as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', 'input has no edge naming context')\n\n // 输入 roleTable + outStmt(与 boolean.ts / fillet.ts 同构)。Phase 1.6:origin=StmtId。\n const inputTable = inputRoleTable(input) as ReadonlyMap<unknown, unknown> | undefined\n const outStmt = String(getCurrentStmt()?.id ?? '')\n\n // 静态定轨:当前引擎是否原生实现 chamferWithHistory 面演化核函数(引擎事实,非运行时\n // 探测)。occt 有 → equal 走 chamferWithRoleTable 历史路径;brepkit 没有\n // (裸 kernel.chamfer 是真实现,但无 *WithHistory)→ L1 裸调用,\n // 不伪造面演化/roleTable(与 intersect 降级同构)。\n const useHistory = hasNativeHistory('chamferWithHistory')\n\n let resultSolid: BrepHandle\n let faceEvolution: Map<number, number[]> | undefined\n let roleTable: ReadonlyMap<unknown, unknown> | undefined\n\n switch (type) {\n case 'equal': {\n const edgeHandles = edges.map((e) => resolveEdge(ctx, e).handle)\n if (useHistory) {\n // occt 历史路径(P5:chamferWithHistory + roleTable 传播,§3.2 末段)\n const r = chamferWithRoleTable(\n kernel,\n solid,\n edgeHandles,\n params.width as number,\n inputTable ?? new Map(),\n outStmt,\n )\n resultSolid = r.result\n faceEvolution = r.faceEvolution\n roleTable = r.roleTable\n } else {\n // brepkit 裸降级:kernel.chamfer(solid, edges, width)——几何正确,无面演化。\n resultSolid = kernel.chamfer(solid, edgeHandles, params.width as number)\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n }\n case 'distanceAngle':\n resultSolid = kernel.chamferDistAngle(solid, edges.map((e) => resolveEdge(ctx, e).handle), params.width as number, params.angle as number)\n if (useHistory) {\n // occt:chamferDistAngle 无 WithHistory 版本——用恒等面演化 + 原表(既有行为)。\n faceEvolution = identityEvolution(kernel, resultSolid)\n roleTable = inputTable\n } else {\n // brepkit:不伪造演化/roleTable。\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n case 'twoDistances':\n resultSolid = chamferTwoDistances(kernel, edges, ctx, solid, params.width1 as number, params.width2 as number)\n if (useHistory) {\n faceEvolution = identityEvolution(kernel, resultSolid)\n roleTable = inputTable\n } else {\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n default:\n throw new Error('E_CHAMFER_BAD_TYPE')\n }\n\n return fromBrep(\n solidToShape(kernel, resultSolid),\n faceEvolution ? { solid: resultSolid, faceEvolution, roleTable } : { solid: resultSolid, roleTable },\n )\n}\n\n/**\n * 网格实体路径:对近似拓扑里识别出的边倒角(方案 2026-10-01 §3.5 三明治)。\n *\n * 支持的形态与 BREP 路径的差异:\n * - `equal` → L1 裸 `kernel.chamfer`;`distanceAngle` → `kernel.chamferDistAngle`;\n * - `twoDistances` **不支持**:它要把 `faces[0]/faces[1]` 两个 role 限定符解析到面,\n * 再由内核选中的参考面决定 width1/width2 各归哪一侧。近似拓扑没有 role 层,\n * 这两个限定符无从解析——如实拒绝,不猜一个参考面(猜错 = 倒角落在错误的一侧)。\n *\n * 与 fillet 同一条 GOTCHA:一次请求里的全部边交给内核会在共面边链上被整体拒绝,\n * 本实现如实失败,不自动拆成逐边重试。\n *\n * @param input - the mesh-solid input.\n * @param params - the validated chamfer parameters.\n * @returns the chamfered mesh solid as a new mesh part.\n */\nfunction chamferMeshSolid(input: Shape, params: Record<string, unknown>): Shape {\n const type = params.type as string\n const edges = (params.edges as unknown as (number | EdgeTopoRef)[] | undefined) ?? []\n if (type === 'twoDistances') {\n throw new OpError(\n 'chamfer',\n 'E_MESH_SOLID_UNSUPPORTED',\n '[api/chamfer] twoDistances needs role-resolvable adjacent faces to decide which side ' +\n 'carries width1/width2; a mesh solid has no role layer — use type:\"equal\" or \"distanceAngle\"',\n )\n }\n const entry = meshSolidEntry(input, 'chamfer')\n const edgeHandles = resolveMeshEdges(entry, edges, 'chamfer')\n\n let result: BrepHandle\n try {\n result = type === 'distanceAngle'\n ? entry.kernel.chamferDistAngle(entry.solid, edgeHandles, params.width as number, params.angle as number)\n : entry.kernel.chamfer(entry.solid, edgeHandles, params.width as number)\n } catch (cause) {\n throw meshKernelFailure(\n 'chamfer',\n 'E_CHAMFER_FAILED',\n `chamfer(type=${type}) on ${edgeHandles.length} edge(s)`,\n cause,\n )\n }\n return meshSolidProduct(entry, result)\n}\n\n/**\n * 在几何体上倒角(等距 / 双距 / 距角)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name chamfer\n * @note BREP 输入走完整三形态;**网格实体**输入只支持 `equal` / `distanceAngle`\n * (`twoDistances` 需要 role 可解析的邻面,近似拓扑没有 role)。\n * `width1` 沿 faces[0] 侧、`width2` 沿 faces[1] 侧(BREP 路径)。\n * @returns Shape 倒角后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.edges - 参与倒角的边(EdgeTopoRef[],条目为相邻两面的 role 线路)。type:EdgeTopoRef[] required:true\n * @param params.type - 倒角类型(equal | twoDistances | distanceAngle)。type:string required:true\n * @param params.width - type=equal: 倒角宽度(mm)。type:number 默认 1\n * @param params.width1 - type=twoDistances: 沿 faces[0] 侧距离(mm)。type:number\n * @param params.width2 - type=twoDistances: 沿 faces[1] 侧距离(mm)。type:number\n * @param params.angle - type=distanceAngle: 与参考面夹角(度,(0,90))。type:number\n * @example\n * const p = await cad.chamfer(part0, { edges: [{ kind:'edge', faces:[{ origin:'box', role:'box:top' }, { origin:'box', role:'box:front' }], hint:{ kind:'edge' } }], type:'equal', width:1 })\n * const q = await cad.chamfer(meshPart, { edges: [3], type:'equal', width:1 })\n */\nexport const chamfer = defineOp({\n // 中立 op(2026-09-26 B 批):不再声明 engines——equal 路径按引擎事实静态分派\n // (occt→chamferWithHistory 历史路径;brepkit→裸 kernel.chamfer 无演化降级)。\n // meshEngines:网格实体路径由 brepkit 网格后端提供(方案 2026-10-01 §3.4)。\n meshEngines: ['brepkit'],\n mesh(input: Shape, params: Record<string, unknown>) {\n assertChamferParams(params, { allowOrdinals: true })\n return chamferMeshSolid(input, params)\n },\n brep(input: Shape, params: Record<string, unknown>) {\n assertChamferParams(params)\n return chamferBrep(input, params)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n\n paramDims: {},\n})\n"]}
1
+ {"version":3,"file":"chamfer.js","sourceRoot":"","sources":["../../src/api/chamfer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api chamfer — chamfer 倒角库函数(BREP-only,directEdit 族)\n *\n * 平台分层(2026-09-26 B 批降级):**中立 op**(不再声明 `engines:['occt']`)。\n * equal 分支按引擎事实**静态定轨**(与 intersect 同构,读 `hasNativeHistory`——\n * 引擎身份是唯一判据,没有能力集可读):\n * - occt(原生有 `chamferWithHistory`)→ `chamferWithRoleTable`(→ face-evolution.ts 的\n * occt 原生 `chamferWithHistory`,D3 面演化 + roleTable 传播)——历史路径,不回退;\n * - brepkit(无 `chamferWithHistory`,但裸 `kernel.chamfer` 是真实现)→ L1 裸\n * `kernel.chamfer(solid, edges, width)`:几何正确,**无面演化、无 roleTable 传播**\n * (如实降级,不伪造恒等映射)。\n * distanceAngle / twoDistances 分支本就走 L1 `kernel.chamferDistAngle`(brepkit 真实现,\n * 度→弧度方言在 brepkitKernel 内消化);occt 上仍挂 identityEvolution + 原 roleTable\n * (既有行为,零回退),brepkit 上同样不伪造演化。\n *\n * 与 drill/engrave 的差异:没有 mesh 实现(defineOp({ brep })),输入非 BREP\n * 时由 dispatchPath 抛 E_MESH_UNSUPPORTED。\n *\n * 类型:\n * - equal(对称):occt→chamferWithHistory;brepkit→kernel.chamfer(solid, edges, width)\n * - distanceAngle:kernel.chamferDistAngle(solid, edges, width, angle)\n * - twoDistances(双距):逐边按 §3.5 换算(width1,width2 + β → dF, θ),\n * per-edge 调 kernel.chamferDistAngle;凹棱(β ≥ 180°)→ E_CHAMFER_REFLEX_EDGE。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { chamferWithRoleTable, identityEvolution } from '../brep/face-evolution'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { getCurrentStmt, nameOf, setName } from '../runtime-state'\nimport { hasNativeHistory } from '../brep/engine/native-history'\nimport { fromBrep, brepOf, inputRoleTable, resolveCompoundMember, replaceCompoundMember } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { EdgeTopoRef, ResolutionContext } from '../topology/naming'\nimport { resolveTopoRef, facesForQualifier, TopoRefError } from '../topology/naming'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { buildEdgeResolutionContext, buildEdgeContextFromSolid } from './topo-resolve'\nimport { expandEdgeSelectorRefs } from './selectors-to-refs'\nimport { OpError } from './internal/result-unwrap'\nimport { meshKernelFailure, meshSolidEntry, meshSolidProduct, resolveMeshEdges } from './internal/mesh-solid-op'\nimport { angleBetweenNormals, materialDihedralFromNormalAngle, chamferAngleFromDistances } from './chamfer-math'\n\n// ── 参数自校验(api 层被直接 import 时的防御层)──\n\n/**\n * Validate chamfer parameters: `edges` must be a non-empty array of EdgeTopoRef,\n * each with kind key \"edge\" and a two-entry faces pair — or of selector strings\n * (`\"|Z\"` etc., precision chain) — or of 1-based ordinals when\n * `opts.allowOrdinals` (the mesh chain, which has no role layer to match\n * edges against). A top-level selector string is also accepted.\n * @param params the raw chamfer operation parameters.\n * @param opts the selector-form options (mesh chain allows ordinals).\n */\nexport function assertChamferParams(\n params: Record<string, unknown>,\n opts?: { readonly allowOrdinals?: boolean },\n): void {\n const edges = params.edges\n const list = typeof edges === 'string' ? [edges] : (edges as unknown[])\n if (typeof edges !== 'string' && (!Array.isArray(edges) || list.length === 0)) {\n throw new Error('E_CHAMFER_NO_EDGES: chamfer requires at least one edge')\n }\n for (const e of list) {\n if (opts?.allowOrdinals && typeof e === 'number') {\n if (!Number.isInteger(e) || e < 1) {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: an edge ordinal must be a positive integer (1-based)')\n }\n continue\n }\n if (typeof e === 'string') {\n if (e.trim() === '') {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: an edge selector string must not be empty')\n }\n continue\n }\n if (!e || typeof e !== 'object' || (e as { kind?: unknown }).kind !== 'edge') {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: every edge entry must be an EdgeTopoRef with kind:\"edge\"')\n }\n const faces = (e as { faces?: unknown }).faces\n if (!Array.isArray(faces) || faces.length !== 2) {\n throw new Error('E_CHAMFER_BAD_EDGE_REF: EdgeTopoRef.faces must be a two-entry RoleQualifier pair')\n }\n }\n const type = params.type\n if (type !== 'equal' && type !== 'twoDistances' && type !== 'distanceAngle') {\n throw new Error('E_CHAMFER_BAD_TYPE: type must be equal | twoDistances | distanceAngle')\n }\n if (type === 'equal' || type === 'distanceAngle') {\n const width = params.width\n if (typeof width !== 'number' || !Number.isFinite(width) || width <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width must be a positive number')\n }\n if (type === 'distanceAngle') {\n const angle = params.angle\n if (typeof angle !== 'number' || !Number.isFinite(angle) || angle <= 0 || angle >= 90) {\n throw new Error('E_CHAMFER_BAD_ANGLE: chamfer.angle must be in (0, 90) degrees')\n }\n }\n } else {\n const w1 = params.width1\n const w2 = params.width2\n if (typeof w1 !== 'number' || !Number.isFinite(w1) || w1 <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width1 must be a positive number')\n }\n if (typeof w2 !== 'number' || !Number.isFinite(w2) || w2 <= 0) {\n throw new Error('E_CHAMFER_BAD_WIDTH: chamfer.width2 must be a positive number')\n }\n }\n}\n\n// ── §3.5 几何换算 ──\n\n/** 面中心外法向(与 captureFaceHint 同口径)。 */\nfunction faceMidNormal(kernel: BrepEngineApi, face: BrepHandle): [number, number, number] {\n const uv = kernel.uvBounds(face)\n const n = kernel.surfaceNormal(face, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2)\n return [n.x, n.y, n.z]\n}\n\nfunction dot3(a: readonly number[], b: readonly number[]): number {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\n}\n\nfunction radToDeg(rad: number): number {\n return (rad * 180) / Math.PI\n}\n\n/** 复刻 occt-wasm 的双层枚举(config.rs:517-527):返回内核选用的参考面在\n * `faceHandles`(getSubShapes(solid,'face'))数组中的下标(0 起);找不到 → null。 */\nfunction refFaceIndex(kernel: BrepEngineApi, faceHandles: BrepHandle[], edge: BrepHandle): number | null {\n for (let fi = 0; fi < faceHandles.length; fi++) {\n for (const fe of kernel.getSubShapes(faceHandles[fi], 'edge')) {\n if (kernel.isSame(fe, edge)) return fi\n }\n }\n return null\n}\n\n/** 两邻面 outer-normal 夹角 → β(材料侧二面角,弧度)。 */\nfunction materialDihedralRad(kernel: BrepEngineApi, ctx: ResolutionContext, a: number, b: number): number {\n const ha = ctx.faces[a - 1]?.handle\n const hb = ctx.faces[b - 1]?.handle\n if (ha === undefined || hb === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `chamfer: adjacent face ${a}/${b} has no live handle`)\n }\n const gamma = angleBetweenNormals(dot3(faceMidNormal(kernel, ha), faceMidNormal(kernel, hb)))\n return materialDihedralFromNormalAngle(gamma)\n}\n\n/**\n * twoDistances 单边换算:width1/width2 + β(§3.5)→ (dF, θ) 供一次 chamferDistAngle。\n * 参考面由内核自选(refOrdinal 的面);width1 对应 faces[0] 侧、width2 对应 faces[1] 侧。\n *\n * @param kernel the OCCT kernel.\n * @param ctx the edge resolution context (faces with live handles).\n * @param refAOrdinal resolved ordinal of `EdgeTopoRef.faces[0]` (1-based).\n * @param refBOrdinal resolved ordinal of `EdgeTopoRef.faces[1]` (1-based).\n * @param refOrdinal the kernel reference face ordinal (1-based; the F in §3.5).\n * @param width1 the `width1` argument.\n * @param width2 the `width2` argument.\n * @returns { dF, angleDeg } for a single `kernel.chamferDistAngle` call.\n */\nexport function twoDistParams(\n kernel: BrepEngineApi,\n ctx: ResolutionContext,\n refAOrdinal: number,\n refBOrdinal: number,\n refOrdinal: number,\n width1: number,\n width2: number,\n): { distance: number; angleDeg: number } {\n const betaRad = materialDihedralRad(kernel, ctx, refAOrdinal, refBOrdinal)\n // dF/dO:§3.5 —— 内核参考面 == faces[0] → width1,== faces[1] → width2。\n let dF: number\n let dO: number\n if (refOrdinal === refAOrdinal) {\n dF = width1\n dO = width2\n } else if (refOrdinal === refBOrdinal) {\n dF = width2\n dO = width1\n } else {\n throw new Error(`E_CHAMFER_EDGE_MISMATCH: kernel ref face ordinal ${refOrdinal} not in [${refAOrdinal}, ${refBOrdinal}]`)\n }\n const angleRad = chamferAngleFromDistances(dF, dO, betaRad)\n return { distance: dF, angleDeg: radToDeg(angleRad) }\n}\n\n/** 解析一条 EdgeTopoRef → (ordinal, handle);失败抛命名层 TopoRefError。 */\nfunction resolveEdge(ctx: ResolutionContext, ref: EdgeTopoRef): { ordinal: number; handle: BrepHandle } {\n const r = resolveTopoRef(ref, ctx)\n if (r.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `chamfer: edge resolved without handle (${ref.faces[0].role}/${ref.faces[1].role})`)\n }\n return { ordinal: r.ordinal, handle: r.handle as BrepHandle }\n}\n\n/** twoDistances 逐边构建(§3.6 V1):每条边一次 chamferDistAngle。 */\nfunction chamferTwoDistances(\n kernel: BrepEngineApi,\n edges: EdgeTopoRef[],\n startCtx: ResolutionContext,\n solid: BrepHandle,\n width1: number,\n width2: number,\n): BrepHandle {\n let resultSolid = solid\n for (const ref of edges) {\n const ctx = resultSolid === solid ? startCtx : buildEdgeContextFromSolid(kernel, resultSolid, startCtx.roleTable)\n const entity = resolveEdge(ctx, ref)\n const faces = resultSolid === solid ? startCtx.faces : ctx.faces\n const idx = refFaceIndex(kernel, faces.map((f) => f.handle).filter((h): h is BrepHandle => h !== undefined), entity.handle)\n if (idx === null) {\n throw new Error('E_CHAMFER_EDGE_MISMATCH: kernel cannot locate ref face (bug)')\n }\n const a = facesForQualifier(ref.faces[0], ctx)[0]\n const b = facesForQualifier(ref.faces[1], ctx)[0]\n const refOrdinal = idx + 1\n const p = twoDistParams(kernel, ctx, a?.ordinal ?? -1, b?.ordinal ?? -1, refOrdinal, width1, width2)\n resultSolid = kernel.chamferDistAngle(resultSolid, [entity.handle], p.distance, p.angleDeg)\n }\n return resultSolid\n}\n\n/** BREP-only 主入口(§3.6 flow)。 */\nfunction chamferBrep(input: Shape, params: Record<string, unknown>): Shape {\n // L1 面:chamferDistAngle/枚举/命名(D12)。equal 分支经 face-evolution 走 occt 平台面。\n const kernel = getBrepApi()\n const solid = brepOf(input) as BrepHandle | undefined\n if (solid === undefined) throw new Error('[api/chamfer] E_CHAMFER_NO_BREP: input is not BREP')\n\n const edges = (params.edges as unknown as EdgeTopoRef[] | string | undefined) ?? []\n const type = params.type as string\n const ctx = buildEdgeResolutionContext(kernel, input as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', 'input has no edge naming context')\n\n // 展开选择器字符串 → EdgeTopoRef[](顶层字符串或数组元素字符串)\n const edgeRefs = expandEdgeSelectorRefs(input, (edges ?? []) as EdgeTopoRef[] | string)\n\n // 输入 roleTable + outStmt(与 boolean.ts / fillet.ts 同构)。Phase 1.6:origin=StmtId。\n const inputTable = inputRoleTable(input) as ReadonlyMap<unknown, unknown> | undefined\n const outStmt = String(getCurrentStmt()?.id ?? '')\n\n // 静态定轨:当前引擎是否原生实现 chamferWithHistory 面演化核函数(引擎事实,非运行时\n // 探测)。occt 有 → equal 走 chamferWithRoleTable 历史路径;brepkit 没有\n // (裸 kernel.chamfer 是真实现,但无 *WithHistory)→ L1 裸调用,\n // 不伪造面演化/roleTable(与 intersect 降级同构)。\n const useHistory = hasNativeHistory('chamferWithHistory')\n\n let resultSolid: BrepHandle\n let faceEvolution: Map<number, number[]> | undefined\n let roleTable: ReadonlyMap<unknown, unknown> | undefined\n\n switch (type) {\n case 'equal': {\n const edgeHandles = edgeRefs.map((e) => resolveEdge(ctx, e).handle)\n if (useHistory) {\n // occt 历史路径(P5:chamferWithHistory + roleTable 传播,§3.2 末段)\n const r = chamferWithRoleTable(\n kernel,\n solid,\n edgeHandles,\n params.width as number,\n inputTable ?? new Map(),\n outStmt,\n )\n resultSolid = r.result\n faceEvolution = r.faceEvolution\n roleTable = r.roleTable\n } else {\n // brepkit 裸降级:kernel.chamfer(solid, edges, width)——几何正确,无面演化。\n resultSolid = kernel.chamfer(solid, edgeHandles, params.width as number)\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n }\n case 'distanceAngle':\n resultSolid = kernel.chamferDistAngle(solid, edgeRefs.map((e) => resolveEdge(ctx, e).handle), params.width as number, params.angle as number)\n if (useHistory) {\n // occt:chamferDistAngle 无 WithHistory 版本——用恒等面演化 + 原表(既有行为)。\n faceEvolution = identityEvolution(kernel, resultSolid)\n roleTable = inputTable\n } else {\n // brepkit:不伪造演化/roleTable。\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n case 'twoDistances':\n resultSolid = chamferTwoDistances(kernel, edgeRefs, ctx, solid, params.width1 as number, params.width2 as number)\n if (useHistory) {\n faceEvolution = identityEvolution(kernel, resultSolid)\n roleTable = inputTable\n } else {\n faceEvolution = undefined\n roleTable = undefined\n }\n break\n default:\n throw new Error('E_CHAMFER_BAD_TYPE')\n }\n\n return fromBrep(\n solidToShape(kernel, resultSolid),\n faceEvolution ? { solid: resultSolid, faceEvolution, roleTable } : { solid: resultSolid, roleTable },\n )\n}\n\n/**\n * 网格实体路径:对近似拓扑里识别出的边倒角(方案 2026-10-01 §3.5 三明治)。\n *\n * 支持的形态与 BREP 路径的差异:\n * - `equal` → L1 裸 `kernel.chamfer`;`distanceAngle` → `kernel.chamferDistAngle`;\n * - `twoDistances` **不支持**:它要把 `faces[0]/faces[1]` 两个 role 限定符解析到面,\n * 再由内核选中的参考面决定 width1/width2 各归哪一侧。近似拓扑没有 role 层,\n * 这两个限定符无从解析——如实拒绝,不猜一个参考面(猜错 = 倒角落在错误的一侧)。\n *\n * 与 fillet 同一条 GOTCHA:一次请求里的全部边交给内核会在共面边链上被整体拒绝,\n * 本实现如实失败,不自动拆成逐边重试。\n *\n * @param input - the mesh-solid input.\n * @param params - the validated chamfer parameters.\n * @returns the chamfered mesh solid as a new mesh part.\n */\nfunction chamferMeshSolid(input: Shape, params: Record<string, unknown>): Shape {\n const type = params.type as string\n const edges = (params.edges as unknown as (number | string | EdgeTopoRef)[] | string | undefined) ?? []\n if (type === 'twoDistances') {\n throw new OpError(\n 'chamfer',\n 'E_MESH_SOLID_UNSUPPORTED',\n '[api/chamfer] twoDistances needs role-resolvable adjacent faces to decide which side ' +\n 'carries width1/width2; a mesh solid has no role layer — use type:\"equal\" or \"distanceAngle\"',\n )\n }\n const entry = meshSolidEntry(input, 'chamfer')\n // 选择器字符串只服务精度链(网格零件无 role 层);网格链用 1 起序号。\n if (typeof edges === 'string' || (Array.isArray(edges) && edges.some((e) => typeof e === 'string'))) {\n throw new TopoRefError(\n 'E_TOPO_MESH_UNSUPPORTED',\n 'edge',\n 'chamfer: selector strings are precision-chain only — mesh solids have no role layer (use 1-based edge ordinals)',\n )\n }\n const edgeHandles = resolveMeshEdges(entry, edges as (number | EdgeTopoRef)[], 'chamfer')\n\n let result: BrepHandle\n try {\n result = type === 'distanceAngle'\n ? entry.kernel.chamferDistAngle(entry.solid, edgeHandles, params.width as number, params.angle as number)\n : entry.kernel.chamfer(entry.solid, edgeHandles, params.width as number)\n } catch (cause) {\n throw meshKernelFailure(\n 'chamfer',\n 'E_CHAMFER_FAILED',\n `chamfer(type=${type}) on ${edgeHandles.length} edge(s)`,\n cause,\n )\n }\n return meshSolidProduct(entry, result)\n}\n\n/**\n * 多零件 load 的 compound 成员是匿名 Shape:其面 role(`imported:<memberIdx>:<i>`)\n * 记录在父 compound 变量名(part 键)的合并表里,成员自身没有 part 名。解包后\n * 若直接把匿名 target 喂给 chamferBrep,`buildEdgeResolutionContext` 经\n * `nameOf(target)` 查 part 键表会得到 undefined → E_TOPO_NOT_FOUND。\n *\n * 这里让 target 继承父 part 名(仅当 target 尚未命名时),使其 part 键表命中父\n * compound 的合并表——合并表包含该成员全部面的 role→hash,几何上正确。单零件\n * 路径 input===target 且 target 已被执行器命名,`!nameOf(target)` 守卫使其空转。\n */\nfunction adoptParentPartName(input: Shape, target: Shape): void {\n if (target === input) return\n const parentName = nameOf(input)\n if (parentName && !nameOf(target)) setName(target, parentName)\n}\n\n/**\n * 在几何体上倒角(等距 / 双距 / 距角)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name chamfer\n * @note BREP 输入走完整三形态;**网格实体**输入只支持 `equal` / `distanceAngle`\n * (`twoDistances` 需要 role 可解析的邻面,近似拓扑没有 role)。\n * `width1` 沿 faces[0] 侧、`width2` 沿 faces[1] 侧(BREP 路径)。\n * @returns Shape 倒角后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.edges - 参与倒角的边:CadQuery 边选择器字符串(如 \"|Z\",AI 生成)或相邻两面的 role 线路(EdgeTopoRef[],UI 拾取产物)。type:EdgeTopoRef[]|string required:true\n * @param params.type - 倒角类型(equal | twoDistances | distanceAngle)。type:string required:true\n * @param params.width - type=equal: 倒角宽度(mm)。type:number 默认 1\n * @param params.width1 - type=twoDistances: 沿 faces[0] 侧距离(mm)。type:number\n * @param params.width2 - type=twoDistances: 沿 faces[1] 侧距离(mm)。type:number\n * @param params.angle - type=distanceAngle: 与参考面夹角(度,(0,90))。type:number\n * @example\n * const p = await cad.chamfer(part0, { edges: [{ kind:'edge', faces:[{ origin:'box', role:'box:top' }, { origin:'box', role:'box:front' }], hint:{ kind:'edge' } }], type:'equal', width:1 })\n * // AI 生成可写 CadQuery 边选择器字符串\n * const p2 = await cad.chamfer(part0, { edges: \"|Z\", type:'equal', width:1 })\n * const q = await cad.chamfer(meshPart, { edges: [3], type:'equal', width:1 })\n */\nexport const chamfer = defineOp({\n // 中立 op(2026-09-26 B 批):不再声明 engines——equal 路径按引擎事实静态分派\n // (occt→chamferWithHistory 历史路径;brepkit→裸 kernel.chamfer 无演化降级)。\n // meshEngines:网格实体路径由 brepkit 网格后端提供(方案 2026-10-01 §3.4)。\n meshEngines: ['brepkit'],\n mesh(input: Shape, params: Record<string, unknown>) {\n assertChamferParams(params, { allowOrdinals: true })\n // P2:多零件 load 输入是 compound——按 partIndex 取目标成员,结果替换回原\n // compound(其余 children 原样),与 fai_extrude/fai_drill 同构。\n const target = resolveCompoundMember(input, params.partIndex, 'chamfer')\n const result = chamferMeshSolid(target, params)\n return replaceCompoundMember(input, params.partIndex, result)\n },\n brep(input: Shape, params: Record<string, unknown>) {\n assertChamferParams(params)\n const target = resolveCompoundMember(input, params.partIndex, 'chamfer')\n // 多零件 load 的成员匿名:其面 role 记录在父 compound 的 part 键合并表里。\n // 解包后让 target 继承父 part 名,buildEdgeResolutionContext/inputRoleTable\n // 才能按 part 名查到表(单零件 input===target 且已命名,无副作用)。\n adoptParentPartName(input, target)\n const result = chamferBrep(target, params)\n return replaceCompoundMember(input, params.partIndex, result)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n\n paramDims: {},\n})\n"]}
@@ -24,8 +24,8 @@ import type { FaceTopoRef } from '../topology/naming/index.js';
24
24
  type Vec3 = [number, number, number];
25
25
  /** `cad.draft` 参数。 */
26
26
  export interface DraftParams {
27
- /** 拔模面(FaceTopoRef[],`cad.faceRef` 产物)。 */
28
- faces: FaceTopoRef[];
27
+ /** 拔模面:面选择器字符串(如 "|Z",AI 生成)或 FaceTopoRef[](UI 拾取产物字面量)。 */
28
+ faces: FaceTopoRef[] | string;
29
29
  /** 拔模角(度)。 */
30
30
  angleDeg: number;
31
31
  /** 拔模方向(默认 +Z)。 */
@@ -55,12 +55,15 @@ export interface DraftParams {
55
55
  * `pull` + 面上一点建模。仅 BREP 可用(mesh 输入执行前报错)。
56
56
  * @returns Shape 拔模后的几何。
57
57
  * @param input - 目标几何。type:Shape required:true
58
- * @param params.faces - 拔模面(FaceTopoRef[],cad.faceRef 产物)。type:FaceTopoRef[] required:true
58
+ * @param params.faces - 拔模面:面选择器字符串(如 "|Z",AI 生成)或 FaceTopoRef[](UI 拾取产物字面量;禁止 cad.faceRef 序号)。type:FaceTopoRef[]|string required:true
59
59
  * @param params.angleDeg - 拔模角(度,≠0)。type:number required:true
60
60
  * @param params.pull - 拔模方向(默认 +Z)。type:Vec3 required:false
61
61
  * @param params.neutral - 中性面**点**({point};normal 无消费者)。type:{point:Vec3,normal?:Vec3} required:false
62
62
  * @example
63
- * const d = await cad.draft(part0, { faces: [cad.faceRef(part0, 3)], angleDeg: 3 })
63
+ * // faces 取 UI 拾取产物的 FaceTopoRef 字面量;❌ 禁止 cad.faceRef 序号(跨内核不可移植)
64
+ * const d = await cad.draft(part0, { faces: pickedFaces, angleDeg: 3 })
65
+ * // AI 生成可写 CadQuery 面选择器字符串("|Z" 法向平行 Z 的面)
66
+ * const d2 = await cad.draft(part0, { faces: "|Z", angleDeg: 3 })
64
67
  */
65
68
  export declare const draft: ((input: Shape, params: DraftParams) => Promise<Shape>) & {
66
69
  __faijs__dualOp?: import("../define-op.js").DualOpMeta;
@@ -1 +1 @@
1
- {"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/api/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAM1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAKrD,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAEpC,sBAAsB;AACtB,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,cAAc;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,mBAAmB;IACnB,IAAI,CAAC,EAAE,IAAI,CAAA;IACX;;;;OAIG;IACH,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,IAAI,CAAA;KAAE,CAAA;CACzC;AAwDD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,KAAK;;CAUhB,CAAA"}
1
+ {"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/api/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAM1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAMrD,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAEpC,sBAAsB;AACtB,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,CAAA;IAC7B,cAAc;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,mBAAmB;IACnB,IAAI,CAAC,EAAE,IAAI,CAAA;IACX;;;;OAIG;IACH,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,IAAI,CAAA;KAAE,CAAA;CACzC;AAyDD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,KAAK;;CAUhB,CAAA"}
package/dist/api/draft.js CHANGED
@@ -25,11 +25,12 @@ import { brepOf, fromBrep } from '../shape.js';
25
25
  import { defineOp } from '../sdk.js';
26
26
  import { resolveTopoRef, TopoRefError } from '../topology/naming/index.js';
27
27
  import { buildEdgeResolutionContext } from './topo-resolve.js';
28
+ import { expandFaceSelectorRefs } from './selectors-to-refs.js';
28
29
  /** BREP 路径:解析面引用 → L1 draft → 收养。 */
29
30
  function draftBrep(input, params) {
30
31
  const { faces, angleDeg } = params ?? {};
31
- if (!Array.isArray(faces) || faces.length === 0) {
32
- throw new Error('E_DRAFT_NO_FACES: draft requires at least one FaceTopoRef in faces');
32
+ if ((typeof faces !== 'string' && (!Array.isArray(faces) || faces.length === 0))) {
33
+ throw new Error('E_DRAFT_NO_FACES: draft requires at least one FaceTopoRef or a face selector string in faces');
33
34
  }
34
35
  if (typeof angleDeg !== 'number' || !Number.isFinite(angleDeg) || angleDeg === 0) {
35
36
  throw new Error('E_DRAFT_BAD_ANGLE: draft.angleDeg must be a non-zero number (degrees)');
@@ -41,9 +42,10 @@ function draftBrep(input, params) {
41
42
  const ctx = buildEdgeResolutionContext(kernel, input);
42
43
  if (!ctx)
43
44
  throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'draft: input has no BREP naming context');
44
- const faceHandles = faces.map((ref) => {
45
+ // 展开选择器字符串 → FaceTopoRef[],再逐 ref 解析句柄
46
+ const faceHandles = expandFaceSelectorRefs(input, faces).map((ref) => {
45
47
  if (!ref || ref.kind !== 'face') {
46
- throw new Error('E_DRAFT_BAD_FACE_REF: every faces entry must be a FaceTopoRef (cad.faceRef)');
48
+ throw new Error('E_DRAFT_BAD_FACE_REF: every faces entry must be a FaceTopoRef (cad.faceRef) or a selector string');
47
49
  }
48
50
  const r = resolveTopoRef(ref, ctx);
49
51
  if (r.handle === undefined) {
@@ -88,12 +90,15 @@ function draftBrep(input, params) {
88
90
  * `pull` + 面上一点建模。仅 BREP 可用(mesh 输入执行前报错)。
89
91
  * @returns Shape 拔模后的几何。
90
92
  * @param input - 目标几何。type:Shape required:true
91
- * @param params.faces - 拔模面(FaceTopoRef[],cad.faceRef 产物)。type:FaceTopoRef[] required:true
93
+ * @param params.faces - 拔模面:面选择器字符串(如 "|Z",AI 生成)或 FaceTopoRef[](UI 拾取产物字面量;禁止 cad.faceRef 序号)。type:FaceTopoRef[]|string required:true
92
94
  * @param params.angleDeg - 拔模角(度,≠0)。type:number required:true
93
95
  * @param params.pull - 拔模方向(默认 +Z)。type:Vec3 required:false
94
96
  * @param params.neutral - 中性面**点**({point};normal 无消费者)。type:{point:Vec3,normal?:Vec3} required:false
95
97
  * @example
96
- * const d = await cad.draft(part0, { faces: [cad.faceRef(part0, 3)], angleDeg: 3 })
98
+ * // faces 取 UI 拾取产物的 FaceTopoRef 字面量;❌ 禁止 cad.faceRef 序号(跨内核不可移植)
99
+ * const d = await cad.draft(part0, { faces: pickedFaces, angleDeg: 3 })
100
+ * // AI 生成可写 CadQuery 面选择器字符串("|Z" 法向平行 Z 的面)
101
+ * const d2 = await cad.draft(part0, { faces: "|Z", angleDeg: 3 })
97
102
  */
98
103
  export const draft = defineOp({
99
104
  // 实证收窄(2026-09-24):brepkit 的 L1 draft 产出错误几何(破坏对称性 / 静默无操作),
@@ -1 +1 @@
1
- {"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/api/draft.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api draft — 拔模:对选定面施加拔模斜度(手写**平台** op,Phase 5)\n *\n * `engines: ['occt']` —— 但**不是平台依赖**(实现只经 L1 契约面 `getBrepApi()`,\n * 见下选面口径),而是**实证收窄**:brepkit 的 L1 `draft` 实测产出错误几何,\n * 必须让静态门在执行前拒绝(红线:BREP 链可用性执行前静态判定,不允许\n * 「门说能、内核说不能」;也不允许静默产出错几何)。\n *\n * 实证(同脚本、box(20,20,10)、angleDeg=3,两引擎同一次运行):\n * - occt:4 个侧面(faceRef ordinal 1–4)**都给一致 delta = −52.4078**\n * —— 对称输入 ⇒ 对称输出,几何自洽;⊥ pull 的端面由内核报 KERNEL_ERROR。\n * - brepkit:ordinal 1–5 给 +60.29 / 0 / 0 / +17.47 / 0 —— **对称性被破坏**\n * (对称 box 上对单个侧面拔模,四个侧面不可能给出不同结果),其中三个是\n * **静默无操作**(体积与 bbox 均不变),而 ⊥ pull 的端面反而把 x/y 凸包各撑大\n * 0.524(= 10·tan 3°)。序号错配不能解释:破坏对称性与序号无关。\n *\n * 选面口径(设计原则 4):`faces: FaceTopoRef[]`(`cad.faceRef` 产物)。\n * `neutral` 用 `{point, normal}` 平面参数——不给 face 引用(方案 §7 建议 2)。\n *\n * 回归守卫:`api/feature-family.test.ts` 的「brepkit 下 draft 静态拒绝」用例。\n */\n\nimport type { Shape } from '../mesh/types'\nimport type { BrepHandle, BrepVec3 } from '../brep/engine/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { brepOf, fromBrep } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { FaceTopoRef } from '../topology/naming'\nimport { resolveTopoRef, TopoRefError } from '../topology/naming'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { buildEdgeResolutionContext } from './topo-resolve'\n\ntype Vec3 = [number, number, number]\n\n/** `cad.draft` 参数。 */\nexport interface DraftParams {\n /** 拔模面(FaceTopoRef[],`cad.faceRef` 产物)。 */\n faces: FaceTopoRef[]\n /** 拔模角(度)。 */\n angleDeg: number\n /** 拔模方向(默认 +Z)。 */\n pull?: Vec3\n /**\n * 中性平面:**只有点的语义**(内核把该点所在高度视为 0° 基准;省略取原点)。\n * `normal` 无任何内核消费者(occt-wasm 原生 `draft` 无 neutral 形参,brepkit\n * 只收点),传了会显式报 `E_DRAFT_NEUTRAL_NORMAL_UNUSED`。\n */\n neutral?: { point: Vec3; normal?: Vec3 }\n}\n\n/** BREP 路径:解析面引用 → L1 draft → 收养。 */\nfunction draftBrep(input: Shape, params: DraftParams): Shape {\n const { faces, angleDeg } = params ?? ({} as DraftParams)\n if (!Array.isArray(faces) || faces.length === 0) {\n throw new Error('E_DRAFT_NO_FACES: draft requires at least one FaceTopoRef in faces')\n }\n if (typeof angleDeg !== 'number' || !Number.isFinite(angleDeg) || angleDeg === 0) {\n throw new Error('E_DRAFT_BAD_ANGLE: draft.angleDeg must be a non-zero number (degrees)')\n }\n const kernel = getBrepApi()\n const solid = brepOf(input) as BrepHandle | undefined\n if (solid === undefined) throw new Error('E_DRAFT_NO_BREP: draft input is not BREP')\n\n const ctx = buildEdgeResolutionContext(kernel, input as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'draft: input has no BREP naming context')\n const faceHandles = faces.map((ref) => {\n if (!ref || (ref as { kind?: unknown }).kind !== 'face') {\n throw new Error('E_DRAFT_BAD_FACE_REF: every faces entry must be a FaceTopoRef (cad.faceRef)')\n }\n const r = resolveTopoRef(ref, ctx)\n if (r.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', `draft: face resolved without handle (${ref.origin}/${ref.role})`)\n }\n return r.handle as BrepHandle\n })\n\n // GOTCHA-1(Phase 5 实测):L1 的向量形参是 `BrepVec3 = {x,y,z}` **对象**,不是元组。\n // 传 `[0,0,1]` 会被内核读成零向量 ⇒ occt 抛空文案 KERNEL_ERROR、brepkit 抛\n // \"cannot normalize zero vector\",两边都不可用。必须显式转对象(同 pattern.ts:41)。\n const [px, py, pz] = params.pull ?? [0, 0, 1]\n const pullVec: BrepVec3 = { x: px, y: py, z: pz }\n\n // 中性面缺省:中性点取原点(内核语义为「该点处角度为 0」)。\n const nPoint = params.neutral?.point\n const neutralVec: BrepVec3 = nPoint\n ? { x: nPoint[0], y: nPoint[1], z: nPoint[2] }\n : { x: 0, y: 0, z: 0 }\n\n // GOTCHA-2(Phase 5 实测):L1 draft 的 neutral 只有**点**语义(occt-wasm 原生\n // `draft(shape, face, angleRad, direction)` 根本没有 neutral 形参,brepkit 也只收\n // 点:brepkitKernel.ts:669-676)。故 `neutral.normal` 无任何消费者——按项目约定\n // (occt-primitives.ts interpolatePoints「拒绝而非静默产出错几何」)显式报错,\n // 不静默丢弃。\n if (params.neutral?.normal) {\n throw new Error(\n 'E_DRAFT_NEUTRAL_NORMAL_UNUSED: L1 draft takes a neutral POINT only (no plane normal) — ' +\n 'drop neutral.normal, or model the plane via pull + a point on it',\n )\n }\n\n const result = kernel.draft(solid, faceHandles, pullVec, neutralVec, angleDeg)\n return fromBrep(solidToShape(kernel, result), { solid: result })\n}\n\n/**\n * 拔模:对选定面施加拔模斜度(铸造/注塑出模角)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name draft\n * @note **occt-only**(`engines: ['occt']`;实证收窄,非平台依赖——见文件头实证:\n * brepkit 破坏对称性且部分 ordinal 静默无操作)。`neutral`(中性点)**只支持\n * 原点**:occt-wasm 原生 `draft(shape, face, angleRad, direction)` 没有 neutral\n * 形参,传非原点中性点会显式报错(不静默产出错几何);brepkit 已被静态拒绝,\n * 故非原点 `neutral` 当前**没有任何可用引擎**——需要该语义时请改用\n * `pull` + 面上一点建模。仅 BREP 可用(mesh 输入执行前报错)。\n * @returns Shape 拔模后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.faces - 拔模面(FaceTopoRef[],cad.faceRef 产物)。type:FaceTopoRef[] required:true\n * @param params.angleDeg - 拔模角(度,≠0)。type:number required:true\n * @param params.pull - 拔模方向(默认 +Z)。type:Vec3 required:false\n * @param params.neutral - 中性面**点**({point};normal 无消费者)。type:{point:Vec3,normal?:Vec3} required:false\n * @example\n * const d = await cad.draft(part0, { faces: [cad.faceRef(part0, 3)], angleDeg: 3 })\n */\nexport const draft = defineOp({\n // 实证收窄(2026-09-24):brepkit 的 L1 draft 产出错误几何(破坏对称性 / 静默无操作),\n // 声明 occt 白名单让静态门在执行前拒绝(引擎身份是 op 侧唯一的收窄轴)。\n engines: ['occt'],\n brep(input: Shape, params: DraftParams) {\n return draftBrep(input, params)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n\n paramDims: {},\n})\n"]}
1
+ {"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/api/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAEjC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAA;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAoB5D,qCAAqC;AACrC,SAAS,SAAS,CAAC,KAAY,EAAE,MAAmB;IAClD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAK,EAAkB,CAAA;IACzD,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,8FAA8F,CAAC,CAAA;IACjH,CAAC;IACD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAA;IAC1F,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAA2B,CAAA;IACrD,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;IAEpF,MAAM,GAAG,GAAG,0BAA0B,CAAC,MAAM,EAAE,KAAe,CAAC,CAAA;IAC/D,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,YAAY,CAAC,kBAAkB,EAAE,MAAM,EAAE,yCAAyC,CAAC,CAAA;IACvG,uCAAuC;IACvC,MAAM,WAAW,GAAG,sBAAsB,CAAC,KAAK,EAAE,KAA+B,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC7F,IAAI,CAAC,GAAG,IAAK,GAA0B,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,kGAAkG,CAAC,CAAA;QACrH,CAAC;QACD,MAAM,CAAC,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QAClC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,YAAY,CAAC,kBAAkB,EAAE,MAAM,EAAE,wCAAwC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAA;QACvH,CAAC;QACD,OAAO,CAAC,CAAC,MAAoB,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,mEAAmE;IACnE,2DAA2D;IAC3D,kEAAkE;IAClE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAC7C,MAAM,OAAO,GAAa,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAA;IAEjD,iCAAiC;IACjC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,KAAK,CAAA;IACpC,MAAM,UAAU,GAAa,MAAM;QACjC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE;QAC9C,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;IAExB,iEAAiE;IACjE,wEAAwE;IACxE,+DAA+D;IAC/D,2DAA2D;IAC3D,SAAS;IACT,IAAI,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,yFAAyF;YACvF,kEAAkE,CACrE,CAAA;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;IAC9E,OAAO,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;AAClE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,QAAQ,CAAC;IAC5B,6DAA6D;IAC7D,2CAA2C;IAC3C,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,IAAI,CAAC,KAAY,EAAE,MAAmB;QACpC,OAAO,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IACjC,CAAC;IACD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,EAAgB;IAE1E,SAAS,EAAE,EAAE;CACd,CAAC,CAAA","sourcesContent":["/**\n * api draft — 拔模:对选定面施加拔模斜度(手写**平台** op,Phase 5)\n *\n * `engines: ['occt']` —— 但**不是平台依赖**(实现只经 L1 契约面 `getBrepApi()`,\n * 见下选面口径),而是**实证收窄**:brepkit 的 L1 `draft` 实测产出错误几何,\n * 必须让静态门在执行前拒绝(红线:BREP 链可用性执行前静态判定,不允许\n * 「门说能、内核说不能」;也不允许静默产出错几何)。\n *\n * 实证(同脚本、box(20,20,10)、angleDeg=3,两引擎同一次运行):\n * - occt:4 个侧面(faceRef ordinal 1–4)**都给一致 delta = −52.4078**\n * —— 对称输入 ⇒ 对称输出,几何自洽;⊥ pull 的端面由内核报 KERNEL_ERROR。\n * - brepkit:ordinal 1–5 给 +60.29 / 0 / 0 / +17.47 / 0 —— **对称性被破坏**\n * (对称 box 上对单个侧面拔模,四个侧面不可能给出不同结果),其中三个是\n * **静默无操作**(体积与 bbox 均不变),而 ⊥ pull 的端面反而把 x/y 凸包各撑大\n * 0.524(= 10·tan 3°)。序号错配不能解释:破坏对称性与序号无关。\n *\n * 选面口径(设计原则 4):`faces: FaceTopoRef[]`(`cad.faceRef` 产物)。\n * `neutral` 用 `{point, normal}` 平面参数——不给 face 引用(方案 §7 建议 2)。\n *\n * 回归守卫:`api/feature-family.test.ts` 的「brepkit 下 draft 静态拒绝」用例。\n */\n\nimport type { Shape } from '../mesh/types'\nimport type { BrepHandle, BrepVec3 } from '../brep/engine/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { brepOf, fromBrep } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { FaceTopoRef } from '../topology/naming'\nimport { resolveTopoRef, TopoRefError } from '../topology/naming'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { buildEdgeResolutionContext } from './topo-resolve'\nimport { expandFaceSelectorRefs } from './selectors-to-refs'\n\ntype Vec3 = [number, number, number]\n\n/** `cad.draft` 参数。 */\nexport interface DraftParams {\n /** 拔模面:面选择器字符串(如 \"|Z\",AI 生成)或 FaceTopoRef[](UI 拾取产物字面量)。 */\n faces: FaceTopoRef[] | string\n /** 拔模角(度)。 */\n angleDeg: number\n /** 拔模方向(默认 +Z)。 */\n pull?: Vec3\n /**\n * 中性平面:**只有点的语义**(内核把该点所在高度视为 0° 基准;省略取原点)。\n * `normal` 无任何内核消费者(occt-wasm 原生 `draft` 无 neutral 形参,brepkit\n * 只收点),传了会显式报 `E_DRAFT_NEUTRAL_NORMAL_UNUSED`。\n */\n neutral?: { point: Vec3; normal?: Vec3 }\n}\n\n/** BREP 路径:解析面引用 → L1 draft → 收养。 */\nfunction draftBrep(input: Shape, params: DraftParams): Shape {\n const { faces, angleDeg } = params ?? ({} as DraftParams)\n if ((typeof faces !== 'string' && (!Array.isArray(faces) || faces.length === 0))) {\n throw new Error('E_DRAFT_NO_FACES: draft requires at least one FaceTopoRef or a face selector string in faces')\n }\n if (typeof angleDeg !== 'number' || !Number.isFinite(angleDeg) || angleDeg === 0) {\n throw new Error('E_DRAFT_BAD_ANGLE: draft.angleDeg must be a non-zero number (degrees)')\n }\n const kernel = getBrepApi()\n const solid = brepOf(input) as BrepHandle | undefined\n if (solid === undefined) throw new Error('E_DRAFT_NO_BREP: draft input is not BREP')\n\n const ctx = buildEdgeResolutionContext(kernel, input as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'draft: input has no BREP naming context')\n // 展开选择器字符串 → FaceTopoRef[],再逐 ref 解析句柄\n const faceHandles = expandFaceSelectorRefs(input, faces as FaceTopoRef[] | string).map((ref) => {\n if (!ref || (ref as { kind?: unknown }).kind !== 'face') {\n throw new Error('E_DRAFT_BAD_FACE_REF: every faces entry must be a FaceTopoRef (cad.faceRef) or a selector string')\n }\n const r = resolveTopoRef(ref, ctx)\n if (r.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', `draft: face resolved without handle (${ref.origin}/${ref.role})`)\n }\n return r.handle as BrepHandle\n })\n\n // GOTCHA-1(Phase 5 实测):L1 的向量形参是 `BrepVec3 = {x,y,z}` **对象**,不是元组。\n // 传 `[0,0,1]` 会被内核读成零向量 ⇒ occt 抛空文案 KERNEL_ERROR、brepkit 抛\n // \"cannot normalize zero vector\",两边都不可用。必须显式转对象(同 pattern.ts:41)。\n const [px, py, pz] = params.pull ?? [0, 0, 1]\n const pullVec: BrepVec3 = { x: px, y: py, z: pz }\n\n // 中性面缺省:中性点取原点(内核语义为「该点处角度为 0」)。\n const nPoint = params.neutral?.point\n const neutralVec: BrepVec3 = nPoint\n ? { x: nPoint[0], y: nPoint[1], z: nPoint[2] }\n : { x: 0, y: 0, z: 0 }\n\n // GOTCHA-2(Phase 5 实测):L1 draft 的 neutral 只有**点**语义(occt-wasm 原生\n // `draft(shape, face, angleRad, direction)` 根本没有 neutral 形参,brepkit 也只收\n // 点:brepkitKernel.ts:669-676)。故 `neutral.normal` 无任何消费者——按项目约定\n // (occt-primitives.ts interpolatePoints「拒绝而非静默产出错几何」)显式报错,\n // 不静默丢弃。\n if (params.neutral?.normal) {\n throw new Error(\n 'E_DRAFT_NEUTRAL_NORMAL_UNUSED: L1 draft takes a neutral POINT only (no plane normal) — ' +\n 'drop neutral.normal, or model the plane via pull + a point on it',\n )\n }\n\n const result = kernel.draft(solid, faceHandles, pullVec, neutralVec, angleDeg)\n return fromBrep(solidToShape(kernel, result), { solid: result })\n}\n\n/**\n * 拔模:对选定面施加拔模斜度(铸造/注塑出模角)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name draft\n * @note **occt-only**(`engines: ['occt']`;实证收窄,非平台依赖——见文件头实证:\n * brepkit 破坏对称性且部分 ordinal 静默无操作)。`neutral`(中性点)**只支持\n * 原点**:occt-wasm 原生 `draft(shape, face, angleRad, direction)` 没有 neutral\n * 形参,传非原点中性点会显式报错(不静默产出错几何);brepkit 已被静态拒绝,\n * 故非原点 `neutral` 当前**没有任何可用引擎**——需要该语义时请改用\n * `pull` + 面上一点建模。仅 BREP 可用(mesh 输入执行前报错)。\n * @returns Shape 拔模后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.faces - 拔模面:面选择器字符串(如 \"|Z\",AI 生成)或 FaceTopoRef[](UI 拾取产物字面量;禁止 cad.faceRef 序号)。type:FaceTopoRef[]|string required:true\n * @param params.angleDeg - 拔模角(度,≠0)。type:number required:true\n * @param params.pull - 拔模方向(默认 +Z)。type:Vec3 required:false\n * @param params.neutral - 中性面**点**({point};normal 无消费者)。type:{point:Vec3,normal?:Vec3} required:false\n * @example\n * // faces 取 UI 拾取产物的 FaceTopoRef 字面量;❌ 禁止 cad.faceRef 序号(跨内核不可移植)\n * const d = await cad.draft(part0, { faces: pickedFaces, angleDeg: 3 })\n * // AI 生成可写 CadQuery 面选择器字符串(\"|Z\" 法向平行 Z 的面)\n * const d2 = await cad.draft(part0, { faces: \"|Z\", angleDeg: 3 })\n */\nexport const draft = defineOp({\n // 实证收窄(2026-09-24):brepkit 的 L1 draft 产出错误几何(破坏对称性 / 静默无操作),\n // 声明 occt 白名单让静态门在执行前拒绝(引擎身份是 op 侧唯一的收窄轴)。\n engines: ['occt'],\n brep(input: Shape, params: DraftParams) {\n return draftBrep(input, params)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n\n paramDims: {},\n})\n"]}
@@ -23,8 +23,9 @@
23
23
  import type { Shape } from '../mesh/types.js';
24
24
  import type { EdgeTopoRef } from '../topology/naming/index.js';
25
25
  /**
26
- * 查询几何体第 N 条边的 `EdgeTopoRef`,供 `cad.fillet` / `cad.chamfer` 的 `edges` 使用:
27
- * `cad.fillet(base, { edges: [cad.edgeRef(base, 17)], radius: 2 })`。
26
+ * 查询几何体第 N 条边的 `EdgeTopoRef`(1 起),供按 role 线路选边(`cad.fillet` /
27
+ * `cad.chamfer` 的 `edges` 等)使用。**查询用途,不用于脚本生成**——序号是内核
28
+ * 枚举序,跨内核/跨特征会漂移;本 API 仅供 FCStd 移植桥与网格链等无 role 层场景使用。
28
29
  *
29
30
  * 定不了案(无 BREP / 序号越界 / 邻面不足两面 / 邻面无 role 血统)抛 `TopoRefError`。
30
31
  * @group 查询
@@ -35,9 +36,8 @@ import type { EdgeTopoRef } from '../topology/naming/index.js';
35
36
  * @returns EdgeTopoRef 该边的拓扑引用(相邻两面 role 对 + length/midpoint hint)。
36
37
  * @param of - 目标几何(BREP 实体所在的 Shape)。type:Shape required:true
37
38
  * @param edgeOrdinal - 边序号(1 起;等于 FreeCAD 的 `EdgeN`)。type:number required:true
39
+ * @note ⚠️ 查询用途,不用于脚本生成:序号跨内核不可移植(同实体 occt 与 brepkit 枚举序不同)。生成脚本应使用 TopoRef 字面量(UI 拾取产物)或 CadQuery 选择器字符串(AI 生成)。
38
40
  * @note 序号 1 起,与命名层 `TopoRef.ordinal` 及 FreeCAD `EdgeN` 同序(`getSubShapes(solid,'edge')` 用 TopExp::MapShapes + IndexedMap 枚举)。
39
- * @example
40
- * const part1 = cad.fillet(part0, { edges: [cad.edgeRef(part0, 1)], radius: 2 })
41
41
  */
42
42
  export declare function edgeRef(of: Shape, edgeOrdinal: number): EdgeTopoRef;
43
43
  //# sourceMappingURL=edge-ref.d.ts.map
@@ -26,8 +26,9 @@ import { nameOf } from '../runtime-state.js';
26
26
  import { captureEdgeHint, findOriginRole, TopoRefError } from '../topology/naming/index.js';
27
27
  import { buildEdgeResolutionContext, recoverEdgeFaceRole } from './topo-resolve.js';
28
28
  /**
29
- * 查询几何体第 N 条边的 `EdgeTopoRef`,供 `cad.fillet` / `cad.chamfer` 的 `edges` 使用:
30
- * `cad.fillet(base, { edges: [cad.edgeRef(base, 17)], radius: 2 })`。
29
+ * 查询几何体第 N 条边的 `EdgeTopoRef`(1 起),供按 role 线路选边(`cad.fillet` /
30
+ * `cad.chamfer` 的 `edges` 等)使用。**查询用途,不用于脚本生成**——序号是内核
31
+ * 枚举序,跨内核/跨特征会漂移;本 API 仅供 FCStd 移植桥与网格链等无 role 层场景使用。
31
32
  *
32
33
  * 定不了案(无 BREP / 序号越界 / 邻面不足两面 / 邻面无 role 血统)抛 `TopoRefError`。
33
34
  * @group 查询
@@ -38,9 +39,8 @@ import { buildEdgeResolutionContext, recoverEdgeFaceRole } from './topo-resolve.
38
39
  * @returns EdgeTopoRef 该边的拓扑引用(相邻两面 role 对 + length/midpoint hint)。
39
40
  * @param of - 目标几何(BREP 实体所在的 Shape)。type:Shape required:true
40
41
  * @param edgeOrdinal - 边序号(1 起;等于 FreeCAD 的 `EdgeN`)。type:number required:true
42
+ * @note ⚠️ 查询用途,不用于脚本生成:序号跨内核不可移植(同实体 occt 与 brepkit 枚举序不同)。生成脚本应使用 TopoRef 字面量(UI 拾取产物)或 CadQuery 选择器字符串(AI 生成)。
41
43
  * @note 序号 1 起,与命名层 `TopoRef.ordinal` 及 FreeCAD `EdgeN` 同序(`getSubShapes(solid,'edge')` 用 TopExp::MapShapes + IndexedMap 枚举)。
42
- * @example
43
- * const part1 = cad.fillet(part0, { edges: [cad.edgeRef(part0, 1)], radius: 2 })
44
44
  */
45
45
  export function edgeRef(of, edgeOrdinal) {
46
46
  if (!Number.isInteger(edgeOrdinal) || edgeOrdinal < 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"edge-ref.js","sourceRoot":"","sources":["../../src/api/edge-ref.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api edge-ref — 边引用查询:把「边序号」解析成 `EdgeTopoRef`(1 起)\n *\n * fillet / chamfer 的选边参数是 `EdgeTopoRef`(相邻两面的 role 对,见\n * `topology/naming`);而外部格式(FCStd / STEP 编辑器 / 上游特征文件)通常只给\n * 「第 N 条边」。本模块是两者之间的桥:在内核现场枚举里取第 N 条边,再由输入\n * Shape 的命名槽(RoleTable + subShapeHashes)反查它两邻面的 `{origin, role}`,\n * 合成可直接喂给 `cad.fillet` / `cad.chamfer` 的 `EdgeTopoRef`。\n *\n * 序号语义(GOTCHA):faijs 的 `getSubShapes(solid,'edge')` 与 `wireframe()` 同用\n * `TopExp::MapShapes` + `NCollection_IndexedMap`(`occt-kernel/topologyExt.ts` 已\n * 记档),故第 N 条边 == FreeCAD 的 `EdgeN`(fcstd-port/test/FreeCAD 的\n * external-geo corpus 测试实测 `wireframe.edgeGroups[k] == FreeCAD \"Edge(k+1)\"`;\n * 2026-09-20 随语料依赖测试迁至 fcstd-port)。这是 FCStd 移植选边的锚点。\n *\n * 与 `faceNormal`(`api/geom.ts`)的差异:`faceNormal` 的 `ordinal` 是 0 起\n * (直接下标 `faces[ordinal]`),而本函数是 1 起——与命名层 `TopoRef` 序号\n * (`ordinal` 1 起,见 `topology/naming/types.ts`)及 FreeCAD `EdgeN` 一致。\n *\n * 纯查询:同步、无副作用、不改 Shape;定不了案一律抛 `TopoRefError`(三态错误码),\n * 绝不静默拿序号硬取。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { hasBrep } from '../shape'\nimport { nameOf } from '../runtime-state'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { captureEdgeHint, findOriginRole, TopoRefError } from '../topology/naming'\nimport type { EdgeTopoRef, RoleQualifier } from '../topology/naming'\nimport { buildEdgeResolutionContext, recoverEdgeFaceRole } from './topo-resolve'\n\n/**\n * 查询几何体第 N 条边的 `EdgeTopoRef`,供 `cad.fillet` / `cad.chamfer` 的 `edges` 使用:\n * `cad.fillet(base, { edges: [cad.edgeRef(base, 17)], radius: 2 })`。\n *\n * 定不了案(无 BREP / 序号越界 / 邻面不足两面 / 邻面无 role 血统)抛 `TopoRefError`。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name edgeRef\n * @returns EdgeTopoRef 该边的拓扑引用(相邻两面 role 对 + length/midpoint hint)。\n * @param of - 目标几何(BREP 实体所在的 Shape)。type:Shape required:true\n * @param edgeOrdinal - 边序号(1 起;等于 FreeCAD 的 `EdgeN`)。type:number required:true\n * @note 序号 1 起,与命名层 `TopoRef.ordinal` 及 FreeCAD `EdgeN` 同序(`getSubShapes(solid,'edge')` 用 TopExp::MapShapes + IndexedMap 枚举)。\n * @example\n * const part1 = cad.fillet(part0, { edges: [cad.edgeRef(part0, 1)], radius: 2 })\n */\nexport function edgeRef(of: Shape, edgeOrdinal: number): EdgeTopoRef {\n if (!Number.isInteger(edgeOrdinal) || edgeOrdinal < 1) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `edgeRef: edgeOrdinal must be an integer >= 1 (got ${edgeOrdinal})`)\n }\n const kernel = getBrepApi()\n // Phase 1.9(D6/§3):mesh 路径不支持拓扑引用——静态判定、显式抛错,不静默降级\n if (!kernel) {\n throw new TopoRefError('E_TOPO_MESH_UNSUPPORTED', 'edge', 'edgeRef: topology references are BREP-only (mesh path unsupported)')\n }\n if (!hasBrep(of)) {\n throw new TopoRefError('E_TOPO_MESH_UNSUPPORTED', 'edge', 'edgeRef: input shape has no BREP solid (mesh shapes do not carry topology identity)')\n }\n\n const ctx = buildEdgeResolutionContext(kernel, of as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', 'edgeRef: input has no BREP naming context')\n\n const edge = ctx.edges?.find((e) => e.ordinal === edgeOrdinal)\n if (!edge || edge.handle === undefined) {\n throw new TopoRefError(\n 'E_TOPO_NOT_FOUND',\n 'edge',\n `edgeRef: edge ordinal ${edgeOrdinal} out of range [1, ${ctx.edges?.length ?? 0}]`,\n )\n }\n const handle = edge.handle\n\n // 该边的相邻面(现场:逐面枚举其边,与 handle 同体者即邻面)——不依赖\n // ctx.edgeFaceAdjacency 的数组下标对齐(那里按 liveEdges 过滤后建表)。\n const faceOrdinals: number[] = []\n for (const f of ctx.faces) {\n if (f.handle === undefined) continue\n if (kernel.getSubShapes(f.handle, 'edge').some((eh) => kernel.isSame(eh, handle))) {\n faceOrdinals.push(f.ordinal)\n }\n }\n if (faceOrdinals.length < 2) {\n throw new TopoRefError(\n 'E_TOPO_NOT_FOUND',\n 'edge',\n `edgeRef: edge ${edgeOrdinal} has ${faceOrdinals.length} adjacent face(s); an EdgeTopoRef needs a two-face pair`,\n )\n }\n\n const table = ctx.roleTable\n if (!table) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', 'edgeRef: input shape has no role table (nameless shape)')\n }\n const ordinalToHash = ctx.faces.map((f) => f.hash ?? 0)\n const quals: RoleQualifier[] = []\n for (const fo of faceOrdinals.slice(0, 2)) {\n let found = findOriginRole(table, ordinalToHash, fo)\n if (!found) {\n // 1.10 前置③ 推广到边路径:目标 part 的 roleTable 缓存残缺,但根节点(名字\n // 诞生处)的表完整、血缘可回走 → 遍历候选 (origin,role) 重算 hash 集找回身份。\n const part = nameOf(of as object)\n if (part) found = recoverEdgeFaceRole(kernel, part, fo, ordinalToHash)\n }\n if (!found) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `edgeRef: adjacent face ordinal ${fo} has no role lineage`)\n }\n quals.push({ origin: found.origin, role: found.role })\n }\n\n const [qa, qb] = quals as [RoleQualifier, RoleQualifier]\n return { kind: 'edge', faces: [qa, qb], hint: captureEdgeHint(kernel, handle as BrepHandle) }\n}\n"]}
1
+ {"version":3,"file":"edge-ref.js","sourceRoot":"","sources":["../../src/api/edge-ref.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api edge-ref — 边引用查询:把「边序号」解析成 `EdgeTopoRef`(1 起)\n *\n * fillet / chamfer 的选边参数是 `EdgeTopoRef`(相邻两面的 role 对,见\n * `topology/naming`);而外部格式(FCStd / STEP 编辑器 / 上游特征文件)通常只给\n * 「第 N 条边」。本模块是两者之间的桥:在内核现场枚举里取第 N 条边,再由输入\n * Shape 的命名槽(RoleTable + subShapeHashes)反查它两邻面的 `{origin, role}`,\n * 合成可直接喂给 `cad.fillet` / `cad.chamfer` 的 `EdgeTopoRef`。\n *\n * 序号语义(GOTCHA):faijs 的 `getSubShapes(solid,'edge')` 与 `wireframe()` 同用\n * `TopExp::MapShapes` + `NCollection_IndexedMap`(`occt-kernel/topologyExt.ts` 已\n * 记档),故第 N 条边 == FreeCAD 的 `EdgeN`(fcstd-port/test/FreeCAD 的\n * external-geo corpus 测试实测 `wireframe.edgeGroups[k] == FreeCAD \"Edge(k+1)\"`;\n * 2026-09-20 随语料依赖测试迁至 fcstd-port)。这是 FCStd 移植选边的锚点。\n *\n * 与 `faceNormal`(`api/geom.ts`)的差异:`faceNormal` 的 `ordinal` 是 0 起\n * (直接下标 `faces[ordinal]`),而本函数是 1 起——与命名层 `TopoRef` 序号\n * (`ordinal` 1 起,见 `topology/naming/types.ts`)及 FreeCAD `EdgeN` 一致。\n *\n * 纯查询:同步、无副作用、不改 Shape;定不了案一律抛 `TopoRefError`(三态错误码),\n * 绝不静默拿序号硬取。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { hasBrep } from '../shape'\nimport { nameOf } from '../runtime-state'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { captureEdgeHint, findOriginRole, TopoRefError } from '../topology/naming'\nimport type { EdgeTopoRef, RoleQualifier } from '../topology/naming'\nimport { buildEdgeResolutionContext, recoverEdgeFaceRole } from './topo-resolve'\n\n/**\n * 查询几何体第 N 条边的 `EdgeTopoRef`(1 起),供按 role 线路选边(`cad.fillet` /\n * `cad.chamfer` 的 `edges` 等)使用。**查询用途,不用于脚本生成**——序号是内核\n * 枚举序,跨内核/跨特征会漂移;本 API 仅供 FCStd 移植桥与网格链等无 role 层场景使用。\n *\n * 定不了案(无 BREP / 序号越界 / 邻面不足两面 / 邻面无 role 血统)抛 `TopoRefError`。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name edgeRef\n * @returns EdgeTopoRef 该边的拓扑引用(相邻两面 role 对 + length/midpoint hint)。\n * @param of - 目标几何(BREP 实体所在的 Shape)。type:Shape required:true\n * @param edgeOrdinal - 边序号(1 起;等于 FreeCAD 的 `EdgeN`)。type:number required:true\n * @note ⚠️ 查询用途,不用于脚本生成:序号跨内核不可移植(同实体 occt 与 brepkit 枚举序不同)。生成脚本应使用 TopoRef 字面量(UI 拾取产物)或 CadQuery 选择器字符串(AI 生成)。\n * @note 序号 1 起,与命名层 `TopoRef.ordinal` 及 FreeCAD `EdgeN` 同序(`getSubShapes(solid,'edge')` 用 TopExp::MapShapes + IndexedMap 枚举)。\n */\nexport function edgeRef(of: Shape, edgeOrdinal: number): EdgeTopoRef {\n if (!Number.isInteger(edgeOrdinal) || edgeOrdinal < 1) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `edgeRef: edgeOrdinal must be an integer >= 1 (got ${edgeOrdinal})`)\n }\n const kernel = getBrepApi()\n // Phase 1.9(D6/§3):mesh 路径不支持拓扑引用——静态判定、显式抛错,不静默降级\n if (!kernel) {\n throw new TopoRefError('E_TOPO_MESH_UNSUPPORTED', 'edge', 'edgeRef: topology references are BREP-only (mesh path unsupported)')\n }\n if (!hasBrep(of)) {\n throw new TopoRefError('E_TOPO_MESH_UNSUPPORTED', 'edge', 'edgeRef: input shape has no BREP solid (mesh shapes do not carry topology identity)')\n }\n\n const ctx = buildEdgeResolutionContext(kernel, of as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', 'edgeRef: input has no BREP naming context')\n\n const edge = ctx.edges?.find((e) => e.ordinal === edgeOrdinal)\n if (!edge || edge.handle === undefined) {\n throw new TopoRefError(\n 'E_TOPO_NOT_FOUND',\n 'edge',\n `edgeRef: edge ordinal ${edgeOrdinal} out of range [1, ${ctx.edges?.length ?? 0}]`,\n )\n }\n const handle = edge.handle\n\n // 该边的相邻面(现场:逐面枚举其边,与 handle 同体者即邻面)——不依赖\n // ctx.edgeFaceAdjacency 的数组下标对齐(那里按 liveEdges 过滤后建表)。\n const faceOrdinals: number[] = []\n for (const f of ctx.faces) {\n if (f.handle === undefined) continue\n if (kernel.getSubShapes(f.handle, 'edge').some((eh) => kernel.isSame(eh, handle))) {\n faceOrdinals.push(f.ordinal)\n }\n }\n if (faceOrdinals.length < 2) {\n throw new TopoRefError(\n 'E_TOPO_NOT_FOUND',\n 'edge',\n `edgeRef: edge ${edgeOrdinal} has ${faceOrdinals.length} adjacent face(s); an EdgeTopoRef needs a two-face pair`,\n )\n }\n\n const table = ctx.roleTable\n if (!table) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', 'edgeRef: input shape has no role table (nameless shape)')\n }\n const ordinalToHash = ctx.faces.map((f) => f.hash ?? 0)\n const quals: RoleQualifier[] = []\n for (const fo of faceOrdinals.slice(0, 2)) {\n let found = findOriginRole(table, ordinalToHash, fo)\n if (!found) {\n // 1.10 前置③ 推广到边路径:目标 part 的 roleTable 缓存残缺,但根节点(名字\n // 诞生处)的表完整、血缘可回走 → 遍历候选 (origin,role) 重算 hash 集找回身份。\n const part = nameOf(of as object)\n if (part) found = recoverEdgeFaceRole(kernel, part, fo, ordinalToHash)\n }\n if (!found) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `edgeRef: adjacent face ordinal ${fo} has no role lineage`)\n }\n quals.push({ origin: found.origin, role: found.role })\n }\n\n const [qa, qb] = quals as [RoleQualifier, RoleQualifier]\n return { kind: 'edge', faces: [qa, qb], hint: captureEdgeHint(kernel, handle as BrepHandle) }\n}\n"]}
@@ -28,10 +28,11 @@ export interface UpToPlaneSpec {
28
28
  /** 平面法向(世界坐标,方向仅定半空间语义,截断取两侧之一)。type:[x,y,z] */
29
29
  normal: Vec3;
30
30
  }
31
- /** up-to 目标:显式面引用 / 显式平面 / 支持体沿拉伸方向的远端(last)/近端(first)端面。 */
31
+ /** up-to 目标:显式面引用 / 显式平面 / 支持体沿拉伸方向的远端(last)/近端(first)端面 /
32
+ * CadQuery 面选择器字符串(在 baseFeature 上解析,如 `">Z"`,多面命中抛错)。 */
32
33
  export type ExtrudeUpTo = FaceTopoRef | 'last' | 'first' | {
33
34
  plane: UpToPlaneSpec;
34
- };
35
+ } | string;
35
36
  /** `cad.extrude` 的对象形态参数(位置形态由 {@link normalizeExtrudeOptions} 归一到这里)。 */
36
37
  export interface ExtrudeOptions {
37
38
  /** 拉伸量(mm,>0)。up-to 模式下无需给。 */
@@ -40,7 +41,7 @@ export interface ExtrudeOptions {
40
41
  normal?: Vec3;
41
42
  /** 沿 normal 的前进方向;缺省 'forward'('backward' 等价于方向取反)。 */
42
43
  mode?: 'forward' | 'backward';
43
- /** 拉伸到面 / 到支持体端面;提供时忽略 length。 */
44
+ /** 拉伸到面 / 到支持体端面;提供时忽略 length。字符串 `'last'`/`'first'` 取支持体端面;其它字符串为 CadQuery 面选择器(在 baseFeature 上解析,多面命中抛错)。 */
44
45
  upTo?: ExtrudeUpTo;
45
46
  /** upTo 'last'/'first' 的支持体(累积支持体,由转换器显式传入)。 */
46
47
  baseFeature?: Shape;
@@ -68,14 +69,17 @@ export interface ExtrudeOptions {
68
69
  * @param params.length - 总拉伸量(mm,>0)。up-to 模式下无需给。type:number
69
70
  * @param params.normal - 拉伸方向(世界坐标)。type:[x,y,z] 默认 [0,0,1]
70
71
  * @param params.mode - 沿 normal 的前进方向:forward 正向 / backward 反向。type:'forward' | 'backward' 默认 'forward'
71
- * @param params.upTo - 拉伸到面:FaceTopoRef 指定面 / 'last' 支持体远端面 / 'first' 近端面(需 baseFeature)。提供时忽略 length。type:'last' | 'first' | FaceTopoRef
72
- * @param params.baseFeature - upTo 'last'/'first' 的支持体几何(累积支持体)。type:Shape
72
+ * @param params.upTo - 拉伸到面:FaceTopoRef(UI 拾取产物字面量)指定面 / 'last' 支持体远端面 / 'first' 近端面 / 面选择器字符串(如 ">Z",在 baseFeature 上解析,多面命中抛错)。提供时忽略 length。❌ 禁止 cad.faceRef 序号。type:'last' | 'first' | FaceTopoRef | string
73
+ * @param params.baseFeature - upTo 'last'/'first'/面选择器的支持体几何(累积支持体)。type:Shape
73
74
  * @param params.offset - 截断面沿其法向的偏移(mm)。type:number 默认 0
74
75
  * @example
75
76
  * const p = await cad.extrude(part0, [0, 0, 10])
76
77
  * const p = await cad.extrude(part0, { length: 10 })
77
- * const p = await cad.extrude(sk, { upTo: cad.faceRef(part0, 3) })
78
+ * // upTo 接受 FaceTopoRef(UI 拾取产物字面量);❌ 禁止 cad.faceRef 序号(跨内核不可移植)
79
+ * const p = await cad.extrude(sk, { upTo: pickedUpToFace })
78
80
  * const p = await cad.extrude(sk, { upTo: 'last', baseFeature: part0 })
81
+ * // AI 生成可写 CadQuery 面选择器字符串(在 baseFeature 上解析)
82
+ * const p = await cad.extrude(sk, { upTo: '>Z', baseFeature: part0 })
79
83
  */
80
84
  export declare const extrude: ((input: Shape, params: unknown) => Promise<Shape>) & {
81
85
  __faijs__dualOp?: import("../define-op.js").DualOpMeta;
@@ -1 +1 @@
1
- {"version":3,"file":"extrude.d.ts","sourceRoot":"","sources":["../../src/api/extrude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAeH,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AAGhD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AA2IrD,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,+BAA+B;IAC/B,KAAK,EAAE,IAAI,CAAA;IACX,gDAAgD;IAChD,MAAM,EAAE,IAAI,CAAA;CACb;AAED,6DAA6D;AAC7D,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,CAAA;AAEnF,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6BAA6B;IAC7B,MAAM,CAAC,EAAE,IAAI,CAAA;IACb,uDAAuD;IACvD,IAAI,CAAC,EAAE,SAAS,GAAG,UAAU,CAAA;IAC7B,kCAAkC;IAClC,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,gDAAgD;IAChD,WAAW,CAAC,EAAE,KAAK,CAAA;IACnB,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAmSD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,OAAO;;CA0ElB,CAAA"}
1
+ {"version":3,"file":"extrude.d.ts","sourceRoot":"","sources":["../../src/api/extrude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAgBH,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AAGhD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AA2IrD,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,+BAA+B;IAC/B,KAAK,EAAE,IAAI,CAAA;IACX,gDAAgD;IAChD,MAAM,EAAE,IAAI,CAAA;CACb;AAED;0DAC0D;AAC1D,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,GAAG,MAAM,CAAA;AAE5F,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6BAA6B;IAC7B,MAAM,CAAC,EAAE,IAAI,CAAA;IACb,uDAAuD;IACvD,IAAI,CAAC,EAAE,SAAS,GAAG,UAAU,CAAA;IAC7B,+GAA+G;IAC/G,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,gDAAgD;IAChD,WAAW,CAAC,EAAE,KAAK,CAAA;IACnB,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AA0TD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,OAAO;;CA6ElB,CAAA"}