@faicad/faijs 0.22.2 → 0.29.3

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 (448) hide show
  1. package/LICENSE +202 -28
  2. package/dist/api/api-namespace.d.ts +5 -5
  3. package/dist/api/api-namespace.d.ts.map +1 -1
  4. package/dist/api/api-namespace.js +4 -4
  5. package/dist/api/api-namespace.js.map +1 -1
  6. package/dist/api/assert.d.ts +2 -2
  7. package/dist/api/assert.js +8 -8
  8. package/dist/api/assert.js.map +1 -1
  9. package/dist/api/asset.d.ts +1 -1
  10. package/dist/api/asset.js +2 -2
  11. package/dist/api/asset.js.map +1 -1
  12. package/dist/api/boolean.d.ts +1 -1
  13. package/dist/api/boolean.d.ts.map +1 -1
  14. package/dist/api/boolean.js +128 -16
  15. package/dist/api/boolean.js.map +1 -1
  16. package/dist/api/cadquery-selectors/borrow-bridge.d.ts +14 -0
  17. package/dist/api/cadquery-selectors/borrow-bridge.d.ts.map +1 -0
  18. package/dist/api/cadquery-selectors/borrow-bridge.js +52 -0
  19. package/dist/api/cadquery-selectors/borrow-bridge.js.map +1 -0
  20. package/dist/api/cadquery-selectors/edge.d.ts +40 -0
  21. package/dist/api/cadquery-selectors/edge.d.ts.map +1 -0
  22. package/dist/api/cadquery-selectors/edge.js +70 -0
  23. package/dist/api/cadquery-selectors/edge.js.map +1 -0
  24. package/dist/api/cadquery-selectors/entity.d.ts +121 -0
  25. package/dist/api/cadquery-selectors/entity.d.ts.map +1 -0
  26. package/dist/api/cadquery-selectors/entity.js +167 -0
  27. package/dist/api/cadquery-selectors/entity.js.map +1 -0
  28. package/dist/api/cadquery-selectors/face.d.ts +33 -0
  29. package/dist/api/cadquery-selectors/face.d.ts.map +1 -0
  30. package/dist/api/cadquery-selectors/face.js +353 -0
  31. package/dist/api/cadquery-selectors/face.js.map +1 -0
  32. package/dist/api/cadquery-selectors/grammar.d.ts +50 -0
  33. package/dist/api/cadquery-selectors/grammar.d.ts.map +1 -0
  34. package/dist/api/cadquery-selectors/grammar.js +345 -0
  35. package/dist/api/cadquery-selectors/grammar.js.map +1 -0
  36. package/dist/api/cadquery-selectors/index.d.ts +18 -0
  37. package/dist/api/cadquery-selectors/index.d.ts.map +1 -0
  38. package/dist/api/cadquery-selectors/index.js +17 -0
  39. package/dist/api/cadquery-selectors/index.js.map +1 -0
  40. package/dist/api/cadquery-selectors/predicates.d.ts +76 -0
  41. package/dist/api/cadquery-selectors/predicates.d.ts.map +1 -0
  42. package/dist/api/cadquery-selectors/predicates.js +85 -0
  43. package/dist/api/cadquery-selectors/predicates.js.map +1 -0
  44. package/dist/api/cadquery-selectors/resolve.d.ts +41 -0
  45. package/dist/api/cadquery-selectors/resolve.d.ts.map +1 -0
  46. package/dist/api/cadquery-selectors/resolve.js +243 -0
  47. package/dist/api/cadquery-selectors/resolve.js.map +1 -0
  48. package/dist/api/cadquery-selectors/types.d.ts +96 -0
  49. package/dist/api/cadquery-selectors/types.d.ts.map +1 -0
  50. package/dist/api/cadquery-selectors/types.js +11 -0
  51. package/dist/api/cadquery-selectors/types.js.map +1 -0
  52. package/dist/api/chamfer.d.ts +13 -5
  53. package/dist/api/chamfer.d.ts.map +1 -1
  54. package/dist/api/chamfer.js +63 -7
  55. package/dist/api/chamfer.js.map +1 -1
  56. package/dist/api/compound-geom.d.ts +1 -1
  57. package/dist/api/compound-geom.js +1 -1
  58. package/dist/api/compound-geom.js.map +1 -1
  59. package/dist/api/draft.d.ts +1 -1
  60. package/dist/api/draft.js +1 -1
  61. package/dist/api/draft.js.map +1 -1
  62. package/dist/api/edge-ref.d.ts +1 -1
  63. package/dist/api/edge-ref.d.ts.map +1 -1
  64. package/dist/api/edge-ref.js +11 -3
  65. package/dist/api/edge-ref.js.map +1 -1
  66. package/dist/api/engrave.d.ts +1 -1
  67. package/dist/api/engrave.js +7 -7
  68. package/dist/api/engrave.js.map +1 -1
  69. package/dist/api/extrude.d.ts +6 -1
  70. package/dist/api/extrude.d.ts.map +1 -1
  71. package/dist/api/extrude.js +59 -5
  72. package/dist/api/extrude.js.map +1 -1
  73. package/dist/api/face-ref.d.ts +1 -1
  74. package/dist/api/face-ref.js +1 -1
  75. package/dist/api/face-ref.js.map +1 -1
  76. package/dist/api/feature-repair.d.ts +1 -1
  77. package/dist/api/feature-repair.js +1 -1
  78. package/dist/api/feature-repair.js.map +1 -1
  79. package/dist/api/fillet-variable.d.ts +1 -1
  80. package/dist/api/fillet-variable.js +1 -1
  81. package/dist/api/fillet-variable.js.map +1 -1
  82. package/dist/api/fillet.d.ts +28 -8
  83. package/dist/api/fillet.d.ts.map +1 -1
  84. package/dist/api/fillet.js +64 -9
  85. package/dist/api/fillet.js.map +1 -1
  86. package/dist/api/geom.d.ts +1 -1
  87. package/dist/api/geom.js +1 -1
  88. package/dist/api/geom.js.map +1 -1
  89. package/dist/api/helix.d.ts +1 -1
  90. package/dist/api/helix.js +1 -1
  91. package/dist/api/helix.js.map +1 -1
  92. package/dist/api/import-brep.d.ts +20 -2
  93. package/dist/api/import-brep.d.ts.map +1 -1
  94. package/dist/api/import-brep.js +28 -3
  95. package/dist/api/import-brep.js.map +1 -1
  96. package/dist/api/import-step.d.ts +17 -2
  97. package/dist/api/import-step.d.ts.map +1 -1
  98. package/dist/api/import-step.js +23 -3
  99. package/dist/api/import-step.js.map +1 -1
  100. package/dist/api/index.d.ts +2 -1
  101. package/dist/api/index.d.ts.map +1 -1
  102. package/dist/api/index.js +5 -2
  103. package/dist/api/index.js.map +1 -1
  104. package/dist/api/internal/compat-op.js +1 -1
  105. package/dist/api/internal/compat-op.js.map +1 -1
  106. package/dist/api/internal/mesh-solid-op.d.ts +236 -0
  107. package/dist/api/internal/mesh-solid-op.d.ts.map +1 -0
  108. package/dist/api/internal/mesh-solid-op.js +352 -0
  109. package/dist/api/internal/mesh-solid-op.js.map +1 -0
  110. package/dist/api/internal/svg-asset-resolver.d.ts +1 -1
  111. package/dist/api/internal/svg-asset-resolver.js +1 -1
  112. package/dist/api/internal/svg-asset-resolver.js.map +1 -1
  113. package/dist/api/knurl.d.ts +1 -1
  114. package/dist/api/knurl.js +2 -2
  115. package/dist/api/knurl.js.map +1 -1
  116. package/dist/api/loft.d.ts +1 -1
  117. package/dist/api/loft.js +1 -1
  118. package/dist/api/loft.js.map +1 -1
  119. package/dist/api/measurement/index.d.ts +9 -5
  120. package/dist/api/measurement/index.d.ts.map +1 -1
  121. package/dist/api/measurement/index.js +47 -20
  122. package/dist/api/measurement/index.js.map +1 -1
  123. package/dist/api/pattern.d.ts +5 -3
  124. package/dist/api/pattern.d.ts.map +1 -1
  125. package/dist/api/pattern.js +32 -4
  126. package/dist/api/pattern.js.map +1 -1
  127. package/dist/api/place.d.ts +1 -1
  128. package/dist/api/place.js +1 -1
  129. package/dist/api/place.js.map +1 -1
  130. package/dist/api/primitives.d.ts +1 -1
  131. package/dist/api/primitives.js +2 -2
  132. package/dist/api/primitives.js.map +1 -1
  133. package/dist/api/profile.d.ts +39 -12
  134. package/dist/api/profile.d.ts.map +1 -1
  135. package/dist/api/profile.js +4 -4
  136. package/dist/api/profile.js.map +1 -1
  137. package/dist/api/reconcile.d.ts +1 -1
  138. package/dist/api/reconcile.js +1 -1
  139. package/dist/api/reconcile.js.map +1 -1
  140. package/dist/api/replicate.d.ts.map +1 -1
  141. package/dist/api/replicate.js +122 -1
  142. package/dist/api/replicate.js.map +1 -1
  143. package/dist/api/screw.d.ts +1 -1
  144. package/dist/api/screw.js +3 -3
  145. package/dist/api/screw.js.map +1 -1
  146. package/dist/api/sdf.d.ts +1 -1
  147. package/dist/api/sdf.js +2 -2
  148. package/dist/api/sdf.js.map +1 -1
  149. package/dist/api/section-by-plane.d.ts +1 -1
  150. package/dist/api/section-by-plane.d.ts.map +1 -1
  151. package/dist/api/section-by-plane.js +2 -1
  152. package/dist/api/section-by-plane.js.map +1 -1
  153. package/dist/api/shell.d.ts +11 -4
  154. package/dist/api/shell.d.ts.map +1 -1
  155. package/dist/api/shell.js +53 -7
  156. package/dist/api/shell.js.map +1 -1
  157. package/dist/api/sketch-on-face.d.ts +41 -0
  158. package/dist/api/sketch-on-face.d.ts.map +1 -1
  159. package/dist/api/sketch-on-face.js +100 -1
  160. package/dist/api/sketch-on-face.js.map +1 -1
  161. package/dist/api/sketch-on-plane.d.ts +7 -5
  162. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  163. package/dist/api/sketch-on-plane.js +6 -7
  164. package/dist/api/sketch-on-plane.js.map +1 -1
  165. package/dist/api/split-by-plane.d.ts +1 -1
  166. package/dist/api/split-by-plane.d.ts.map +1 -1
  167. package/dist/api/split-by-plane.js +2 -1
  168. package/dist/api/split-by-plane.js.map +1 -1
  169. package/dist/api/split.d.ts +1 -1
  170. package/dist/api/split.js +2 -2
  171. package/dist/api/split.js.map +1 -1
  172. package/dist/api/sweep.d.ts +1 -1
  173. package/dist/api/sweep.js +1 -1
  174. package/dist/api/sweep.js.map +1 -1
  175. package/dist/api/thicken.d.ts +1 -1
  176. package/dist/api/thicken.js +1 -1
  177. package/dist/api/thicken.js.map +1 -1
  178. package/dist/api/topo-resolve.d.ts +74 -1
  179. package/dist/api/topo-resolve.d.ts.map +1 -1
  180. package/dist/api/topo-resolve.js +180 -2
  181. package/dist/api/topo-resolve.js.map +1 -1
  182. package/dist/api/transform.d.ts +5 -1
  183. package/dist/api/transform.d.ts.map +1 -1
  184. package/dist/api/transform.js +62 -11
  185. package/dist/api/transform.js.map +1 -1
  186. package/dist/api/wire.d.ts +1 -1
  187. package/dist/api/wire.js +1 -1
  188. package/dist/api/wire.js.map +1 -1
  189. package/dist/brep/brep-ops.d.ts +9 -7
  190. package/dist/brep/brep-ops.d.ts.map +1 -1
  191. package/dist/brep/brep-ops.js +23 -24
  192. package/dist/brep/brep-ops.js.map +1 -1
  193. package/dist/brep/brep-topology.d.ts +5 -4
  194. package/dist/brep/brep-topology.d.ts.map +1 -1
  195. package/dist/brep/brep-topology.js +6 -5
  196. package/dist/brep/brep-topology.js.map +1 -1
  197. package/dist/brep/effective-deflection.d.ts +35 -0
  198. package/dist/brep/effective-deflection.d.ts.map +1 -0
  199. package/dist/brep/effective-deflection.js +49 -0
  200. package/dist/brep/effective-deflection.js.map +1 -0
  201. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  202. package/dist/brep/engine/adapters/brep-mock.js +27 -0
  203. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  204. package/dist/brep/engine/adapters/brepkit.d.ts +18 -0
  205. package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
  206. package/dist/brep/engine/adapters/brepkit.js +46 -1
  207. package/dist/brep/engine/adapters/brepkit.js.map +1 -1
  208. package/dist/brep/engine/adapters/occt.d.ts +1 -1
  209. package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
  210. package/dist/brep/engine/adapters/occt.js +3 -1
  211. package/dist/brep/engine/adapters/occt.js.map +1 -1
  212. package/dist/brep/engine/primitives.d.ts +29 -7
  213. package/dist/brep/engine/primitives.d.ts.map +1 -1
  214. package/dist/brep/engine/primitives.js.map +1 -1
  215. package/dist/brep/engine/registry.d.ts +24 -1
  216. package/dist/brep/engine/registry.d.ts.map +1 -1
  217. package/dist/brep/engine/registry.js +24 -0
  218. package/dist/brep/engine/registry.js.map +1 -1
  219. package/dist/brep/engine/types.d.ts +54 -3
  220. package/dist/brep/engine/types.d.ts.map +1 -1
  221. package/dist/brep/engine/types.js +10 -0
  222. package/dist/brep/engine/types.js.map +1 -1
  223. package/dist/brep/export/export-model.d.ts.map +1 -1
  224. package/dist/brep/export/export-model.js +6 -5
  225. package/dist/brep/export/export-model.js.map +1 -1
  226. package/dist/brep/face-evolution.d.ts +1 -1
  227. package/dist/brep/face-evolution.d.ts.map +1 -1
  228. package/dist/brep/face-evolution.js +20 -1
  229. package/dist/brep/face-evolution.js.map +1 -1
  230. package/dist/brep/handle-bridge.d.ts +1 -1
  231. package/dist/brep/handle-bridge.js +1 -1
  232. package/dist/brep/handle-bridge.js.map +1 -1
  233. package/dist/brep/mesh-solid.d.ts +218 -0
  234. package/dist/brep/mesh-solid.d.ts.map +1 -0
  235. package/dist/brep/mesh-solid.js +229 -0
  236. package/dist/brep/mesh-solid.js.map +1 -0
  237. package/dist/brep/text/fontRegistry.d.ts +32 -1
  238. package/dist/brep/text/fontRegistry.d.ts.map +1 -1
  239. package/dist/brep/text/fontRegistry.js +51 -1
  240. package/dist/brep/text/fontRegistry.js.map +1 -1
  241. package/dist/brep/text/text-to-solid.d.ts.map +1 -1
  242. package/dist/brep/text/text-to-solid.js +8 -3
  243. package/dist/brep/text/text-to-solid.js.map +1 -1
  244. package/dist/brepkit-kernel/brepkitKernel.d.ts +18 -2
  245. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  246. package/dist/brepkit-kernel/brepkitKernel.js +449 -123
  247. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  248. package/dist/brepkit-kernel/brepkitWasm.d.ts +8 -0
  249. package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
  250. package/dist/brepkit-kernel/brepkitWasm.js +10 -0
  251. package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
  252. package/dist/browser-host/browser-font-provider.d.ts +12 -0
  253. package/dist/browser-host/browser-font-provider.d.ts.map +1 -1
  254. package/dist/browser-host/browser-font-provider.js +25 -0
  255. package/dist/browser-host/browser-font-provider.js.map +1 -1
  256. package/dist/browser.d.ts +6 -3
  257. package/dist/browser.d.ts.map +1 -1
  258. package/dist/browser.js +10 -3
  259. package/dist/browser.js.map +1 -1
  260. package/dist/cad-runtime/backend-dispatch.d.ts +28 -3
  261. package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
  262. package/dist/cad-runtime/backend-dispatch.js +119 -4
  263. package/dist/cad-runtime/backend-dispatch.js.map +1 -1
  264. package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
  265. package/dist/cad-runtime/direct-executor.d.ts +15 -3
  266. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  267. package/dist/cad-runtime/direct-executor.js +33 -1
  268. package/dist/cad-runtime/direct-executor.js.map +1 -1
  269. package/dist/cad-runtime/ports.d.ts +3 -3
  270. package/dist/cad-runtime/ports.d.ts.map +1 -1
  271. package/dist/cad-runtime/ports.js.map +1 -1
  272. package/dist/cad-runtime/preview-exec.d.ts +4 -4
  273. package/dist/cad-runtime/preview-exec.js +2 -2
  274. package/dist/cad-runtime/preview-exec.js.map +1 -1
  275. package/dist/cad-runtime/runtime.d.ts +42 -7
  276. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  277. package/dist/cad-runtime/runtime.js +68 -5
  278. package/dist/cad-runtime/runtime.js.map +1 -1
  279. package/dist/define-op.d.ts +15 -1
  280. package/dist/define-op.d.ts.map +1 -1
  281. package/dist/define-op.js +10 -1
  282. package/dist/define-op.js.map +1 -1
  283. package/dist/env-agnostic.d.ts +2 -2
  284. package/dist/env-agnostic.d.ts.map +1 -1
  285. package/dist/env-agnostic.js +1 -1
  286. package/dist/env-agnostic.js.map +1 -1
  287. package/dist/geometry2d/adapt.d.ts +39 -4
  288. package/dist/geometry2d/adapt.d.ts.map +1 -1
  289. package/dist/geometry2d/adapt.js +14 -3
  290. package/dist/geometry2d/adapt.js.map +1 -1
  291. package/dist/geometry2d/blueprint.d.ts +2 -2
  292. package/dist/geometry2d/blueprint.js +2 -2
  293. package/dist/geometry2d/blueprint.js.map +1 -1
  294. package/dist/geometry2d/bridge/lift-on-plane.d.ts +18 -8
  295. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
  296. package/dist/geometry2d/bridge/lift-on-plane.js +65 -12
  297. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
  298. package/dist/geometry2d/bridge/plane.d.ts +17 -0
  299. package/dist/geometry2d/bridge/plane.d.ts.map +1 -1
  300. package/dist/geometry2d/bridge/plane.js +22 -0
  301. package/dist/geometry2d/bridge/plane.js.map +1 -1
  302. package/dist/geometry2d/curve2d.d.ts +25 -0
  303. package/dist/geometry2d/curve2d.d.ts.map +1 -1
  304. package/dist/geometry2d/curve2d.js +41 -5
  305. package/dist/geometry2d/curve2d.js.map +1 -1
  306. package/dist/index.d.ts +6 -2
  307. package/dist/index.d.ts.map +1 -1
  308. package/dist/index.js +10 -3
  309. package/dist/index.js.map +1 -1
  310. package/dist/io/bytes-node.d.ts +11 -0
  311. package/dist/io/bytes-node.d.ts.map +1 -0
  312. package/dist/io/bytes-node.js +28 -0
  313. package/dist/io/bytes-node.js.map +1 -0
  314. package/dist/io/bytes.d.ts +33 -0
  315. package/dist/io/bytes.d.ts.map +1 -0
  316. package/dist/io/bytes.js +41 -0
  317. package/dist/io/bytes.js.map +1 -0
  318. package/dist/io/fai-zip/container-read.d.ts +102 -0
  319. package/dist/io/fai-zip/container-read.d.ts.map +1 -0
  320. package/dist/io/fai-zip/container-read.js +305 -0
  321. package/dist/io/fai-zip/container-read.js.map +1 -0
  322. package/dist/io/fai-zip/container-write.d.ts +70 -0
  323. package/dist/io/fai-zip/container-write.d.ts.map +1 -0
  324. package/dist/io/fai-zip/container-write.js +186 -0
  325. package/dist/io/fai-zip/container-write.js.map +1 -0
  326. package/dist/io/fai-zip/container.d.ts +107 -0
  327. package/dist/io/fai-zip/container.d.ts.map +1 -0
  328. package/dist/io/fai-zip/container.js +89 -0
  329. package/dist/io/fai-zip/container.js.map +1 -0
  330. package/dist/io/fai-zip/index.d.ts +18 -0
  331. package/dist/io/fai-zip/index.d.ts.map +1 -0
  332. package/dist/io/fai-zip/index.js +4 -0
  333. package/dist/io/fai-zip/index.js.map +1 -0
  334. package/dist/io/index.d.ts +10 -0
  335. package/dist/io/index.d.ts.map +1 -0
  336. package/dist/io/index.js +13 -0
  337. package/dist/io/index.js.map +1 -0
  338. package/dist/io/zip.d.ts +68 -0
  339. package/dist/io/zip.d.ts.map +1 -0
  340. package/dist/io/zip.js +147 -0
  341. package/dist/io/zip.js.map +1 -0
  342. package/dist/lang/code-to-args.d.ts +1 -1
  343. package/dist/lang/code-to-args.js +1 -1
  344. package/dist/lang/code-to-args.js.map +1 -1
  345. package/dist/lang/statement-summary.d.ts +1 -1
  346. package/dist/lang/statement-summary.js +1 -1
  347. package/dist/lang/statement-summary.js.map +1 -1
  348. package/dist/lang/types.d.ts +1 -1
  349. package/dist/lang/types.js +1 -1
  350. package/dist/lang/types.js.map +1 -1
  351. package/dist/mesh/index.d.ts +2 -1
  352. package/dist/mesh/index.d.ts.map +1 -1
  353. package/dist/mesh/index.js +2 -1
  354. package/dist/mesh/index.js.map +1 -1
  355. package/dist/mesh/io.d.ts +7 -0
  356. package/dist/mesh/io.d.ts.map +1 -1
  357. package/dist/mesh/io.js +14 -17
  358. package/dist/mesh/io.js.map +1 -1
  359. package/dist/mesh/reconcile.d.ts +1 -1
  360. package/dist/mesh/reconcile.js +1 -1
  361. package/dist/mesh/reconcile.js.map +1 -1
  362. package/dist/mesh/rigid-transform.d.ts +3 -3
  363. package/dist/mesh/rigid-transform.js +3 -3
  364. package/dist/mesh/rigid-transform.js.map +1 -1
  365. package/dist/mesh/stl-unit.d.ts +24 -0
  366. package/dist/mesh/stl-unit.d.ts.map +1 -0
  367. package/dist/mesh/stl-unit.js +17 -0
  368. package/dist/mesh/stl-unit.js.map +1 -0
  369. package/dist/mesh/threemf-bambu.d.ts +142 -0
  370. package/dist/mesh/threemf-bambu.d.ts.map +1 -0
  371. package/dist/mesh/threemf-bambu.js +334 -0
  372. package/dist/mesh/threemf-bambu.js.map +1 -0
  373. package/dist/mesh/threemf-loader.d.ts +42 -7
  374. package/dist/mesh/threemf-loader.d.ts.map +1 -1
  375. package/dist/mesh/threemf-loader.js +565 -100
  376. package/dist/mesh/threemf-loader.js.map +1 -1
  377. package/dist/mesh/threemf-view.d.ts +71 -0
  378. package/dist/mesh/threemf-view.d.ts.map +1 -0
  379. package/dist/mesh/threemf-view.js +100 -0
  380. package/dist/mesh/threemf-view.js.map +1 -0
  381. package/dist/node-host/cli.d.ts +44 -6
  382. package/dist/node-host/cli.d.ts.map +1 -1
  383. package/dist/node-host/cli.js +76 -26
  384. package/dist/node-host/cli.js.map +1 -1
  385. package/dist/node-host/font-family-index.d.ts +93 -0
  386. package/dist/node-host/font-family-index.d.ts.map +1 -0
  387. package/dist/node-host/font-family-index.js +273 -0
  388. package/dist/node-host/font-family-index.js.map +1 -0
  389. package/dist/node-host/fs-asset-resolver.d.ts +8 -3
  390. package/dist/node-host/fs-asset-resolver.d.ts.map +1 -1
  391. package/dist/node-host/fs-asset-resolver.js +13 -5
  392. package/dist/node-host/fs-asset-resolver.js.map +1 -1
  393. package/dist/node-host/index.d.ts +8 -0
  394. package/dist/node-host/index.d.ts.map +1 -1
  395. package/dist/node-host/index.js +1 -0
  396. package/dist/node-host/index.js.map +1 -1
  397. package/dist/node-host/node-font-provider.d.ts +28 -0
  398. package/dist/node-host/node-font-provider.d.ts.map +1 -1
  399. package/dist/node-host/node-font-provider.js +49 -0
  400. package/dist/node-host/node-font-provider.js.map +1 -1
  401. package/dist/node.d.ts +1 -0
  402. package/dist/node.d.ts.map +1 -1
  403. package/dist/node.js +1 -0
  404. package/dist/node.js.map +1 -1
  405. package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
  406. package/dist/occt-kernel/occt-primitives.js +35 -2
  407. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  408. package/dist/occt-kernel/occtKernel.d.ts +18 -13
  409. package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
  410. package/dist/occt-kernel/occtKernel.js +18 -31
  411. package/dist/occt-kernel/occtKernel.js.map +1 -1
  412. package/dist/occt-kernel/stepColorParser.d.ts +18 -0
  413. package/dist/occt-kernel/stepColorParser.d.ts.map +1 -1
  414. package/dist/occt-kernel/stepColorParser.js +38 -0
  415. package/dist/occt-kernel/stepColorParser.js.map +1 -1
  416. package/dist/occt-kernel/topologyExt.d.ts +1 -1
  417. package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
  418. package/dist/occt-kernel/topologyExt.js +4 -5
  419. package/dist/occt-kernel/topologyExt.js.map +1 -1
  420. package/dist/primitives/text/cjk-font.d.ts +2 -15
  421. package/dist/primitives/text/cjk-font.d.ts.map +1 -1
  422. package/dist/primitives/text/cjk-font.js +13 -1
  423. package/dist/primitives/text/cjk-font.js.map +1 -1
  424. package/dist/runtime-state.d.ts +85 -9
  425. package/dist/runtime-state.d.ts.map +1 -1
  426. package/dist/runtime-state.js +72 -2
  427. package/dist/runtime-state.js.map +1 -1
  428. package/dist/sdk.d.ts +3 -3
  429. package/dist/sdk.d.ts.map +1 -1
  430. package/dist/sdk.js +5 -5
  431. package/dist/sdk.js.map +1 -1
  432. package/dist/shape.d.ts +97 -2
  433. package/dist/shape.d.ts.map +1 -1
  434. package/dist/shape.js +126 -1
  435. package/dist/shape.js.map +1 -1
  436. package/dist/topology/naming/lineage.d.ts +6 -0
  437. package/dist/topology/naming/lineage.d.ts.map +1 -1
  438. package/dist/topology/naming/lineage.js +8 -0
  439. package/dist/topology/naming/lineage.js.map +1 -1
  440. package/dist/topology/naming/resolve-edge.d.ts +20 -1
  441. package/dist/topology/naming/resolve-edge.d.ts.map +1 -1
  442. package/dist/topology/naming/resolve-edge.js +54 -20
  443. package/dist/topology/naming/resolve-edge.js.map +1 -1
  444. package/dist/weapp.d.ts +6 -2
  445. package/dist/weapp.d.ts.map +1 -1
  446. package/dist/weapp.js +7 -1
  447. package/dist/weapp.js.map +1 -1
  448. package/package.json +18 -2
@@ -1 +1 @@
1
- {"version":3,"file":"chamfer.js","sourceRoot":"","sources":["../../src/api/chamfer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * stdlib chamfer — chamfer 倒角库函数(BREP-only,directEdit 能力)\n *\n * 平台分层(2026-09-26 B 批降级):**中立 op**(不再声明 `engines:['occt']`)。\n * equal 分支按引擎能力**静态定轨**(与 intersect 同构,读 `dispatchPath` 同源的能力集):\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 { getBackends, getCurrentStmt } from '../runtime-state'\nimport { engineCapabilitySet } from '../cad-runtime/backend-dispatch'\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 { angleBetweenNormals, materialDihedralFromNormalAngle, chamferAngleFromDistances } from './chamfer-math'\n\n// ── 参数自校验(stdlib 被直接 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.\n * @param params the raw chamfer operation parameters.\n */\nexport function assertChamferParams(params: Record<string, unknown>): 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 (!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) throw new Error('[stdlib/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 面演化核函数(读与 dispatchPath\n // 同源的能力集,非运行时探测)。occt 声明 → equal 走 chamferWithRoleTable 历史路径;\n // brepkit 未声明(裸 kernel.chamfer 真实现但无 *WithHistory)→ L1 裸调用,\n // 不伪造面演化/roleTable(与 intersect 降级同构)。\n const useHistory = engineCapabilitySet(getBackends().config.brepCapabilities).has('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 * 在几何体上倒角(等距 / 双距 / 距角)。仅 BREP 可用。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name chamfer\n * @note 倒角是 BREP-only:非 BREP 输入抛 E_MESH_UNSUPPORTED。参考面由内核自选,`width1` 沿 faces[0] 侧、`width2` 沿 faces[1] 侧。\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 */\nexport const chamfer = defineOp({\n // 中立 op(2026-09-26 B 批):不再声明 engines——equal 路径按引擎能力静态分派\n // (occt→chamferWithHistory 历史路径;brepkit→裸 kernel.chamfer 无演化降级)。\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"]}
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 同构,读 `dispatchPath` 同源的能力集):\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 { getBackends, getCurrentStmt } from '../runtime-state'\nimport { engineCapabilitySet } from '../cad-runtime/backend-dispatch'\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) 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 面演化核函数(读与 dispatchPath\n // 同源的能力集,非运行时探测)。occt 声明 → equal 走 chamferWithRoleTable 历史路径;\n // brepkit 未声明(裸 kernel.chamfer 真实现但无 *WithHistory)→ L1 裸调用,\n // 不伪造面演化/roleTable(与 intersect 降级同构)。\n const useHistory = engineCapabilitySet(getBackends().config.brepCapabilities).has('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"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * stdlib compound — 平台几何复合体 op(H11 / 方案 §4.2)
2
+ * api compound — 平台几何复合体 op(H11 / 方案 §4.2)
3
3
  *
4
4
  *
5
5
  * 与编辑器 `cad.group`(`api/compound.ts`)的区别:
@@ -1,5 +1,5 @@
1
1
  /**
2
- * stdlib compound — 平台几何复合体 op(H11 / 方案 §4.2)
2
+ * api compound — 平台几何复合体 op(H11 / 方案 §4.2)
3
3
  *
4
4
  *
5
5
  * 与编辑器 `cad.group`(`api/compound.ts`)的区别:
@@ -1 +1 @@
1
- {"version":3,"file":"compound-geom.js","sourceRoot":"","sources":["../../src/api/compound-geom.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * stdlib compound — 平台几何复合体 op(H11 / 方案 §4.2)\n *\n *\n * 与编辑器 `cad.group`(`api/compound.ts`)的区别:\n * - `group` 是 ../3d_editor 的「结构分组」op:产出 `{kind:'compound', children}`\n * 结构壳(无 OCCT 句柄),意义是层级/画布结构,不可变换、不可导出为实体。\n * - 本 op 是 faijs **平台**几何 op:把多个成员聚成一个**几何复合体**\n * (OCCT `TopoDS_Compound`,持句柄),可被放置、导出、作为后续 op 的输入。\n *\n * 路径:\n * - brep 路径:`kernel.makeCompound(handles)`(收任意 BrepHandle,含非实体)\n * → `solidToShape` 三角化 → `fromBrep` 登记句柄。\n * - mesh 路径:合并成员 mesh(结构 compound 子节点展平;纯线框无面成员不贡献网格)。\n *\n * 成员不 keep:复合体是单一几何输出,成员作为子形被吸入,不单独作为终端显示。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { isCompoundLike, brepOf, fromBrep, type CompoundShape } from '../shape'\nimport { getBackends, BrepUnsupportedError } from '../runtime-state'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { solidToShape } from '../brep/brep-ops'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { BrepHandle } from '../brep/engine/types'\n\n/** 把任意成员(Shape 或结构 compound)展平为若干子 mesh。 */\nfunction collectSubMeshes(s: Shape | CompoundShape): Shape[] {\n if (isCompoundLike(s)) {\n const out: Shape[] = []\n for (const c of s.children) out.push(...collectSubMeshes(c))\n return out\n }\n if (s.positions && s.indices) return [s]\n return []\n}\n\n/**\n * mesh 路径:合并成员 mesh(展平结构 compound 子节点)。\n *\n * @param members - 待合并的成员(结构 compound 递归展平)。\n * @returns 合并后的单一 mesh Shape。\n */\nexport function mergeMeshes(members: Array<Shape | CompoundShape>): Shape {\n const positions: number[] = []\n const indices: number[] = []\n for (const m of members) {\n for (const sub of collectSubMeshes(m)) {\n const base = positions.length / 3\n positions.push(...sub.positions)\n for (let i = 0; i < sub.indices.length; i++) indices.push(sub.indices[i] + base)\n }\n }\n return { positions: new Float32Array(positions), indices: new Uint32Array(indices) }\n}\n\n/**\n * `cad.compound({ members, name? })` → 几何复合体 Shape(持 OCCT 句柄)。\n *\n * @group 结构\n * @inputs 1\n * @qual ok\n * @name compound\n * @param params.members - 成员数组(Shape 或结构 compound;编译产物 ctx.<var> 引用)。type:Shape[]\n * @param params.name - 可选名称。type:string\n * @note 成员经 `params.members` 传入,不是位置参数。与编辑器 `cad.group` 的区别:本 op 产出**几何**复合体(持 OCCT 句柄,可放置/导出),`group` 是结构壳(无句柄)。平台侧不要用 `group`。\n * @returns Shape 几何复合体(brep 路径持句柄,可变换/可导出)。\n * @example\n * const c = cad.compound({ members: [part0, part1] })\n */\nexport function compound(params: { members?: Array<Shape | CompoundShape>; name?: string }): Shape {\n const members = params.members ?? []\n const { config } = getBackends()\n // D12 中立取核;引擎未初始化(纯 mesh 场景)→ null 容忍走 mesh 路径。\n let kernel: BrepEngineApi | null = null\n try { kernel = getBrepApi() } catch { /* no engine -> mesh path */ }\n\n // 结构 compound 是结构壳(无 OCCT 句柄):不在 BREP 链上 → 视为无句柄成员。\n const handles = members.map((m) => (isCompoundLike(m) ? undefined : brepOf(m)))\n const allBrep = !!kernel && handles.every((h) => h !== undefined)\n\n if (config.mode === 'brep' && !allBrep) {\n throw new BrepUnsupportedError(\n 'E_BREP_UNSUPPORTED: compound members are not all on the BREP chain',\n )\n }\n\n // brep 路径:合并为 TopoDS_Compound 并登记句柄\n if (allBrep && config.mode !== 'mesh') {\n const compoundHandle = kernel!.makeCompound(handles as BrepHandle[])\n const mesh = solidToShape(kernel!, compoundHandle)\n return fromBrep(mesh, { solid: compoundHandle })\n }\n\n // mesh 路径:合并成员 mesh\n return mergeMeshes(members)\n}\n"]}
1
+ {"version":3,"file":"compound-geom.js","sourceRoot":"","sources":["../../src/api/compound-geom.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api compound — 平台几何复合体 op(H11 / 方案 §4.2)\n *\n *\n * 与编辑器 `cad.group`(`api/compound.ts`)的区别:\n * - `group` 是 ../3d_editor 的「结构分组」op:产出 `{kind:'compound', children}`\n * 结构壳(无 OCCT 句柄),意义是层级/画布结构,不可变换、不可导出为实体。\n * - 本 op 是 faijs **平台**几何 op:把多个成员聚成一个**几何复合体**\n * (OCCT `TopoDS_Compound`,持句柄),可被放置、导出、作为后续 op 的输入。\n *\n * 路径:\n * - brep 路径:`kernel.makeCompound(handles)`(收任意 BrepHandle,含非实体)\n * → `solidToShape` 三角化 → `fromBrep` 登记句柄。\n * - mesh 路径:合并成员 mesh(结构 compound 子节点展平;纯线框无面成员不贡献网格)。\n *\n * 成员不 keep:复合体是单一几何输出,成员作为子形被吸入,不单独作为终端显示。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { isCompoundLike, brepOf, fromBrep, type CompoundShape } from '../shape'\nimport { getBackends, BrepUnsupportedError } from '../runtime-state'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { solidToShape } from '../brep/brep-ops'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { BrepHandle } from '../brep/engine/types'\n\n/** 把任意成员(Shape 或结构 compound)展平为若干子 mesh。 */\nfunction collectSubMeshes(s: Shape | CompoundShape): Shape[] {\n if (isCompoundLike(s)) {\n const out: Shape[] = []\n for (const c of s.children) out.push(...collectSubMeshes(c))\n return out\n }\n if (s.positions && s.indices) return [s]\n return []\n}\n\n/**\n * mesh 路径:合并成员 mesh(展平结构 compound 子节点)。\n *\n * @param members - 待合并的成员(结构 compound 递归展平)。\n * @returns 合并后的单一 mesh Shape。\n */\nexport function mergeMeshes(members: Array<Shape | CompoundShape>): Shape {\n const positions: number[] = []\n const indices: number[] = []\n for (const m of members) {\n for (const sub of collectSubMeshes(m)) {\n const base = positions.length / 3\n positions.push(...sub.positions)\n for (let i = 0; i < sub.indices.length; i++) indices.push(sub.indices[i] + base)\n }\n }\n return { positions: new Float32Array(positions), indices: new Uint32Array(indices) }\n}\n\n/**\n * `cad.compound({ members, name? })` → 几何复合体 Shape(持 OCCT 句柄)。\n *\n * @group 结构\n * @inputs 1\n * @qual ok\n * @name compound\n * @param params.members - 成员数组(Shape 或结构 compound;编译产物 ctx.<var> 引用)。type:Shape[]\n * @param params.name - 可选名称。type:string\n * @note 成员经 `params.members` 传入,不是位置参数。与编辑器 `cad.group` 的区别:本 op 产出**几何**复合体(持 OCCT 句柄,可放置/导出),`group` 是结构壳(无句柄)。平台侧不要用 `group`。\n * @returns Shape 几何复合体(brep 路径持句柄,可变换/可导出)。\n * @example\n * const c = cad.compound({ members: [part0, part1] })\n */\nexport function compound(params: { members?: Array<Shape | CompoundShape>; name?: string }): Shape {\n const members = params.members ?? []\n const { config } = getBackends()\n // D12 中立取核;引擎未初始化(纯 mesh 场景)→ null 容忍走 mesh 路径。\n let kernel: BrepEngineApi | null = null\n try { kernel = getBrepApi() } catch { /* no engine -> mesh path */ }\n\n // 结构 compound 是结构壳(无 OCCT 句柄):不在 BREP 链上 → 视为无句柄成员。\n const handles = members.map((m) => (isCompoundLike(m) ? undefined : brepOf(m)))\n const allBrep = !!kernel && handles.every((h) => h !== undefined)\n\n if (config.mode === 'brep' && !allBrep) {\n throw new BrepUnsupportedError(\n 'E_BREP_UNSUPPORTED: compound members are not all on the BREP chain',\n )\n }\n\n // brep 路径:合并为 TopoDS_Compound 并登记句柄\n if (allBrep && config.mode !== 'mesh') {\n const compoundHandle = kernel!.makeCompound(handles as BrepHandle[])\n const mesh = solidToShape(kernel!, compoundHandle)\n return fromBrep(mesh, { solid: compoundHandle })\n }\n\n // mesh 路径:合并成员 mesh\n return mergeMeshes(members)\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * stdlib draft — 拔模:对选定面施加拔模斜度(手写**平台** op,Phase 5)
2
+ * api draft — 拔模:对选定面施加拔模斜度(手写**平台** op,Phase 5)
3
3
  *
4
4
  * `engines: ['occt']` —— 但**不是平台依赖**(实现只经 L1 契约面 `getBrepApi()`,
5
5
  * 见下选面口径),而是**实证收窄**:brepkit 的 L1 `draft` 实测产出错误几何,
package/dist/api/draft.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * stdlib draft — 拔模:对选定面施加拔模斜度(手写**平台** op,Phase 5)
2
+ * api draft — 拔模:对选定面施加拔模斜度(手写**平台** op,Phase 5)
3
3
  *
4
4
  * `engines: ['occt']` —— 但**不是平台依赖**(实现只经 L1 契约面 `getBrepApi()`,
5
5
  * 见下选面口径),而是**实证收窄**: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 * stdlib 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) 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 capabilities: ['directEdit'],\n // 实证收窄(2026-09-24):brepkit 的 L1 draft 产出错误几何(破坏对称性 / 静默无操作),\n // 声明 occt 白名单让静态门在执行前拒绝 —— 与 capabilities 并存合法(两条正交轴,\n // engines 先判、能力门在引擎匹配后再求交)。\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"]}
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) 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 capabilities: ['directEdit'],\n // 实证收窄(2026-09-24):brepkit 的 L1 draft 产出错误几何(破坏对称性 / 静默无操作),\n // 声明 occt 白名单让静态门在执行前拒绝 —— 与 capabilities 并存合法(两条正交轴,\n // engines 先判、能力门在引擎匹配后再求交)。\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"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * stdlib edge-ref — 边引用查询:把「边序号」解析成 `EdgeTopoRef`(1 起)
2
+ * api edge-ref — 边引用查询:把「边序号」解析成 `EdgeTopoRef`(1 起)
3
3
  *
4
4
  * fillet / chamfer 的选边参数是 `EdgeTopoRef`(相邻两面的 role 对,见
5
5
  * `topology/naming`);而外部格式(FCStd / STEP 编辑器 / 上游特征文件)通常只给
@@ -1 +1 @@
1
- {"version":3,"file":"edge-ref.d.ts","sourceRoot":"","sources":["../../src/api/edge-ref.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAK1C,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,oBAAoB,CAAA;AAGpE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,WAAW,CA2DnE"}
1
+ {"version":3,"file":"edge-ref.d.ts","sourceRoot":"","sources":["../../src/api/edge-ref.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAM1C,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,oBAAoB,CAAA;AAGpE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,WAAW,CAiEnE"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * stdlib edge-ref — 边引用查询:把「边序号」解析成 `EdgeTopoRef`(1 起)
2
+ * api edge-ref — 边引用查询:把「边序号」解析成 `EdgeTopoRef`(1 起)
3
3
  *
4
4
  * fillet / chamfer 的选边参数是 `EdgeTopoRef`(相邻两面的 role 对,见
5
5
  * `topology/naming`);而外部格式(FCStd / STEP 编辑器 / 上游特征文件)通常只给
@@ -22,8 +22,9 @@
22
22
  */
23
23
  import { getBrepApi } from '../brep/handle-bridge.js';
24
24
  import { brepOf } from '../shape.js';
25
+ import { nameOf } from '../runtime-state.js';
25
26
  import { captureEdgeHint, findOriginRole, TopoRefError } from '../topology/naming/index.js';
26
- import { buildEdgeResolutionContext } from './topo-resolve.js';
27
+ import { buildEdgeResolutionContext, recoverEdgeFaceRole } from './topo-resolve.js';
27
28
  /**
28
29
  * 查询几何体第 N 条边的 `EdgeTopoRef`,供 `cad.fillet` / `cad.chamfer` 的 `edges` 使用:
29
30
  * `cad.fillet(base, { edges: [cad.edgeRef(base, 17)], radius: 2 })`。
@@ -81,7 +82,14 @@ export function edgeRef(of, edgeOrdinal) {
81
82
  const ordinalToHash = ctx.faces.map((f) => f.hash ?? 0);
82
83
  const quals = [];
83
84
  for (const fo of faceOrdinals.slice(0, 2)) {
84
- const found = findOriginRole(table, ordinalToHash, fo);
85
+ let found = findOriginRole(table, ordinalToHash, fo);
86
+ if (!found) {
87
+ // 1.10 前置③ 推广到边路径:目标 part 的 roleTable 缓存残缺,但根节点(名字
88
+ // 诞生处)的表完整、血缘可回走 → 遍历候选 (origin,role) 重算 hash 集找回身份。
89
+ const part = nameOf(of);
90
+ if (part)
91
+ found = recoverEdgeFaceRole(kernel, part, fo, ordinalToHash);
92
+ }
85
93
  if (!found) {
86
94
  throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `edgeRef: adjacent face ordinal ${fo} has no role lineage`);
87
95
  }
@@ -1 +1 @@
1
- {"version":3,"file":"edge-ref.js","sourceRoot":"","sources":["../../src/api/edge-ref.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * stdlib 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 { brepOf } from '../shape'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { captureEdgeHint, findOriginRole, TopoRefError } from '../topology/naming'\nimport type { EdgeTopoRef, RoleQualifier } from '../topology/naming'\nimport { buildEdgeResolutionContext } 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 (!brepOf(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 const found = findOriginRole(table, ordinalToHash, fo)\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 { brepOf } 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 (!brepOf(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,5 +1,5 @@
1
1
  /**
2
- * stdlib engrave — 雕刻库函数
2
+ * api engrave — 雕刻库函数
3
3
  *
4
4
  *
5
5
  * dispatchPath 静态判定 brep/mesh。
@@ -1,5 +1,5 @@
1
1
  /**
2
- * stdlib engrave — 雕刻库函数
2
+ * api engrave — 雕刻库函数
3
3
  *
4
4
  *
5
5
  * dispatchPath 静态判定 brep/mesh。
@@ -18,7 +18,7 @@ import { getBrepApi } from '../brep/handle-bridge.js';
18
18
  import { fromBrep, brepOf } from '../shape.js';
19
19
  import { defineOp } from '../sdk.js';
20
20
  import { assertPositiveNumber } from './assert.js';
21
- // ── per-op 参数自校验(Phase 2.2;stdlib 被直接 import 时的防御层) ──
21
+ // ── per-op 参数自校验(Phase 2.2;api 层被直接 import 时的防御层) ──
22
22
  /**
23
23
  * Validate engrave parameters: at least one of `text` or `svg` must be
24
24
  * provided, and `depth` (if provided) must be a positive number.
@@ -28,7 +28,7 @@ export function assertEngraveParams(params) {
28
28
  const hasText = params.text !== undefined && params.text !== null && params.text !== '';
29
29
  const hasSvg = params.svg !== undefined && params.svg !== null;
30
30
  if (!hasText && !hasSvg) {
31
- throw new Error('[stdlib] engrave requires either "text" or "svg"');
31
+ throw new Error('[api/engrave] requires either "text" or "svg"');
32
32
  }
33
33
  if (params.depth !== undefined && params.depth !== null) {
34
34
  assertPositiveNumber(params.depth, 'engrave.depth');
@@ -83,7 +83,7 @@ async function engraveBrepPath(input, params, svgText) {
83
83
  const kernel = getBrepApi();
84
84
  const inputSolid = brepOf(input);
85
85
  if (!inputSolid)
86
- throw new Error('[stdlib/engrave] input is not BREP');
86
+ throw new Error('[api/engrave] input is not BREP');
87
87
  const depth = params.depth;
88
88
  const mode = params.mode ?? 'concave';
89
89
  const text = params.text;
@@ -101,7 +101,7 @@ async function engraveBrepPath(input, params, svgText) {
101
101
  });
102
102
  }
103
103
  else {
104
- throw new Error('[stdlib/engrave] neither text nor svg provided');
104
+ throw new Error('[api/engrave] neither text nor svg provided');
105
105
  }
106
106
  // 2. 居中到原点
107
107
  decorationSolid = centerSolidAtOrigin(kernel, decorationSolid);
@@ -183,7 +183,7 @@ async function resolveEngraveSvg(params) {
183
183
  export const engrave = defineOp({
184
184
  mesh: async (input, params) => {
185
185
  if (!input)
186
- throw new Error('[stdlib/engrave] no input geometry');
186
+ throw new Error('[api/engrave] no input geometry');
187
187
  assertEngraveParams(params);
188
188
  const svgText = await resolveEngraveSvg(params);
189
189
  // mesh 路径
@@ -205,7 +205,7 @@ export const engrave = defineOp({
205
205
  },
206
206
  brep: async (input, params) => {
207
207
  if (!input)
208
- throw new Error('[stdlib/engrave] no input geometry');
208
+ throw new Error('[api/engrave] no input geometry');
209
209
  assertEngraveParams(params);
210
210
  const svgText = await resolveEngraveSvg(params);
211
211
  return engraveBrepPath(input, params, svgText);
@@ -1 +1 @@
1
- {"version":3,"file":"engrave.js","sourceRoot":"","sources":["../../src/api/engrave.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * stdlib engrave — 雕刻库函数\n *\n *\n * dispatchPath 静态判定 brep/mesh。\n * BREP 路径:textToSolid/svgToSolid + boolean(cut/fuse)。\n */\n\nimport type { Shape, Vec3 } from '../mesh/types'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { AssetResolver } from '../cad-runtime/ports'\nimport { cad } from '../mesh'\nimport { parseSvgNaturalSize } from '../primitives/parse-svg-size'\nimport { textToSolid } from '../brep/text/text-to-solid'\nimport { svgToSolid } from '../brep/svg/svg-to-solid'\nimport { ensureDefaultFont } from '../brep/text/fontRegistry'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getSolidBoundingBox } from '../brep/brep-utils'\nimport { resolveSvgArg } from './internal/svg-asset-resolver'\nimport { getBackends } from '../runtime-state'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { fromBrep, brepOf } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { assertPositiveNumber } from './assert'\n\n// ── per-op 参数自校验(Phase 2.2;stdlib 被直接 import 时的防御层) ──\n\n/**\n * Validate engrave parameters: at least one of `text` or `svg` must be\n * provided, and `depth` (if provided) must be a positive number.\n * @param params - the raw engrave operation parameters.\n */\nexport function assertEngraveParams(params: Record<string, unknown>): void {\n const hasText = params.text !== undefined && params.text !== null && params.text !== ''\n const hasSvg = params.svg !== undefined && params.svg !== null\n if (!hasText && !hasSvg) {\n throw new Error('[stdlib] engrave requires either \"text\" or \"svg\"')\n }\n if (params.depth !== undefined && params.depth !== null) {\n assertPositiveNumber(params.depth, 'engrave.depth')\n }\n}\n\n/** 世界坐标 → BREP solid 局部坐标。 */\nfunction worldToLocalPosition(\n worldPos: Vec3,\n partTransform: { position?: [number, number, number] } | undefined,\n): Vec3 {\n const offset = partTransform?.position\n if (!offset) return worldPos\n return [\n worldPos[0] - offset[0],\n worldPos[1] - offset[1],\n worldPos[2] - offset[2],\n ]\n}\n\n/** 计算将 +Z 轴对齐到目标法向量的 3x4 仿射变换矩阵(仅旋转,无平移,Rodrigues 公式)。 */\nfunction alignZToNormal(normal: Vec3): number[] {\n const [nx, ny, nz] = normal\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz)\n if (len < 1e-10) {\n return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]\n }\n const ux = nx / len, uy = ny / len, uz = nz / len\n\n if (Math.abs(ux) < 1e-10 && Math.abs(uy) < 1e-10) {\n if (uz > 0) return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]\n return [1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0]\n }\n\n const s = Math.sqrt(ux * ux + uy * uy)\n const c = uz\n const t = 1 - c\n const ax = -uy / s, ay = ux / s\n\n return [\n c + ax * ax * t, ax * ay * t, ay * s, 0,\n ax * ay * t, c + ay * ay * t, -ax * s, 0,\n -ay * s, ax * s, c, 0,\n ]\n}\n\n/** 将 solid 居中到原点(基于包围盒中心,与 mesh 路径语义一致)。 */\nfunction centerSolidAtOrigin(kernel: BrepEngineApi, solid: BrepHandle): BrepHandle {\n const bb = getSolidBoundingBox(kernel, solid)\n const cx = (bb.min[0] + bb.max[0]) / 2\n const cy = (bb.min[1] + bb.max[1]) / 2\n const cz = (bb.min[2] + bb.max[2]) / 2\n const centered = kernel.translate(solid, -cx, -cy, -cz)\n kernel.release(solid)\n return centered\n}\n\n/** BREP 路径:textToSolid/svgToSolid + boolean(cut/fuse)。 */\nasync function engraveBrepPath(input: Shape, params: Record<string, unknown>, svgText?: string): Promise<Shape> {\n const kernel = getBrepApi()\n const inputSolid = brepOf(input) as BrepHandle | undefined\n if (!inputSolid) throw new Error('[stdlib/engrave] input is not BREP')\n\n const depth = params.depth as number\n const mode = (params.mode as 'convex' | 'concave' | undefined) ?? 'concave'\n const text = params.text as string | undefined\n\n // 1. 创建装饰 solid(文字或 SVG),depth 与 mesh 路径一致\n let decorationSolid: BrepHandle\n if (text) {\n await ensureDefaultFont()\n const textSize = (params.textSize as number) ?? 10\n decorationSolid = textToSolid(kernel, text, { fontSize: textSize, depth })\n } else if (svgText) {\n decorationSolid = svgToSolid(kernel, svgText, {\n depth,\n targetLongSide: (params.svgSize as number) ?? 20,\n })\n } else {\n throw new Error('[stdlib/engrave] neither text nor svg provided')\n }\n\n // 2. 居中到原点\n decorationSolid = centerSolidAtOrigin(kernel, decorationSolid)\n\n // 3. 旋转 +Z 对齐面法向\n const worldFaceNormal: Vec3 = (params.faceNormal as Vec3) ?? [0, 0, 1]\n const rotMatrix = alignZToNormal(worldFaceNormal)\n const rotated = kernel.transform(decorationSolid, rotMatrix)\n kernel.release(decorationSolid)\n\n // 4. 沿法向偏移 + 平移到面中心(凸 offset=+depth/2,凹 offset=-depth/2;加 0.01 避免共面)\n const worldFaceCenter: Vec3 = (params.faceCenter as Vec3) ?? [0, 0, 0]\n const localFaceCenter = worldToLocalPosition(worldFaceCenter, getBackends().config.partTransform)\n const offset = mode === 'convex' ? depth / 2 : -depth / 2\n const epsilon = 0.01\n const tx = localFaceCenter[0] + worldFaceNormal[0] * (offset + epsilon)\n const ty = localFaceCenter[1] + worldFaceNormal[1] * (offset + epsilon)\n const tz = localFaceCenter[2] + worldFaceNormal[2] * (offset + epsilon)\n const positioned = kernel.translate(rotated, tx, ty, tz)\n kernel.release(rotated)\n\n // 5. 布尔运算(凸=fuse,凹=cut)\n const isRaised = mode === 'convex'\n let result: BrepHandle\n if (isRaised) {\n result = kernel.fuse(inputSolid, positioned)\n } else {\n result = kernel.cut(inputSolid, positioned)\n }\n kernel.release(positioned)\n\n // 5b. cut 可能分裂成多个 solid(compound),用 fuseAll 合并回单一 solid\n try {\n const subSolids = kernel.getSubShapes(result, 'solid')\n if (subSolids.length > 1) {\n const fused = kernel.fuseAll(subSolids)\n for (const s of subSolids) {\n try { kernel.release(s) } catch { /* 已释放 */ }\n }\n try { kernel.release(result) } catch { /* 已释放 */ }\n result = fused\n }\n } catch {\n // getSubShapes 失败说明结果不是 compound,无需处理\n }\n\n return fromBrep(solidToShape(kernel, result), { solid: result })\n}\n\n/** 解析 SVG 资产引用(AssetRef → SVG 文本),两条路径共享;无 svg 返回 undefined。 */\nasync function resolveEngraveSvg(params: Record<string, unknown>): Promise<string | undefined> {\n return params.svg !== undefined && params.svg !== null\n ? await resolveSvgArg(params.svg, { assets: getBackends().assets as AssetResolver | undefined })\n : undefined\n}\n\n/**\n * 在几何表面雕刻文字或 SVG(文字分支与 logo 分支都可用)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name engrave\n * @returns Shape 雕刻后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.mode - 雕刻方式:concave 凹陷(减法)/ convex 凸出(加法)。type:'concave' | 'convex' 默认 'concave'\n * @param params.depth - 深度 / 凸出高度(mm)。type:number 默认 0\n * @param params.text - 文字内容(与 svg 二选一)。type:string\n * @param params.textSize - 字号(mm)。type:number 默认 10\n * @param params.svg - SVG 资产引用(与 text 二选一;经 cad.asset 解析)。type:string\n * @param params.svgSize - SVG 长边目标尺寸。type:number\n * @param params.faceCenter - 面位置(绝对坐标)。type:[x,y,z] 默认 [0,0,0]\n * @param params.faceNormal - 面法向。type:[x,y,z] 默认 [0,0,1]\n * @note 早期 logo 分支用 `svgText`(整份 XML 拷贝 + `svgSize` 文本导出丢失,往返失真);现已改为 `svg` 资产引用,`engravingType` 冗余键已移除。faceCenter/faceNormal 目前是绝对坐标快照。\n * @example\n * const p = await cad.engrave(part0, { mode: 'concave', depth: 2, text: 'Hello', textSize: 10, faceCenter: [0, 0, 0], faceNormal: [0, 0, -1] })\n */\nexport const engrave = defineOp({\n mesh: async (input: Shape, params: Record<string, unknown>) => {\n if (!input) throw new Error('[stdlib/engrave] no input geometry')\n assertEngraveParams(params)\n const svgText = await resolveEngraveSvg(params)\n // mesh 路径\n const faceCenter: Vec3 = (params.faceCenter as Vec3) ?? [0, 0, 0]\n const faceNormal: Vec3 = (params.faceNormal as Vec3) ?? [0, 0, 1]\n const { naturalWidth, naturalHeight } = svgText ? parseSvgNaturalSize(svgText) : { naturalWidth: 0, naturalHeight: 0 }\n const hasText = !!(params.text as string | undefined)\n\n return cad.engrave(input, {\n mode: (params.mode as 'convex' | 'concave' | undefined) ?? 'concave',\n depth: params.depth as number,\n face: { center: faceCenter, normal: faceNormal },\n text: hasText ? (params.text as string) : undefined,\n textSize: params.textSize as number | undefined,\n svg: svgText,\n svgNaturalWidth: naturalWidth,\n svgNaturalHeight: naturalHeight,\n svgSize: params.svgSize as number | undefined,\n })\n },\n brep: async (input: Shape, params: Record<string, unknown>) => {\n if (!input) throw new Error('[stdlib/engrave] no input geometry')\n assertEngraveParams(params)\n const svgText = await resolveEngraveSvg(params)\n return engraveBrepPath(input, params, svgText)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n})\n"]}
1
+ {"version":3,"file":"engrave.js","sourceRoot":"","sources":["../../src/api/engrave.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api engrave — 雕刻库函数\n *\n *\n * dispatchPath 静态判定 brep/mesh。\n * BREP 路径:textToSolid/svgToSolid + boolean(cut/fuse)。\n */\n\nimport type { Shape, Vec3 } from '../mesh/types'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { AssetResolver } from '../cad-runtime/ports'\nimport { cad } from '../mesh'\nimport { parseSvgNaturalSize } from '../primitives/parse-svg-size'\nimport { textToSolid } from '../brep/text/text-to-solid'\nimport { svgToSolid } from '../brep/svg/svg-to-solid'\nimport { ensureDefaultFont } from '../brep/text/fontRegistry'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getSolidBoundingBox } from '../brep/brep-utils'\nimport { resolveSvgArg } from './internal/svg-asset-resolver'\nimport { getBackends } from '../runtime-state'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { fromBrep, brepOf } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { assertPositiveNumber } from './assert'\n\n// ── per-op 参数自校验(Phase 2.2;api 层被直接 import 时的防御层) ──\n\n/**\n * Validate engrave parameters: at least one of `text` or `svg` must be\n * provided, and `depth` (if provided) must be a positive number.\n * @param params - the raw engrave operation parameters.\n */\nexport function assertEngraveParams(params: Record<string, unknown>): void {\n const hasText = params.text !== undefined && params.text !== null && params.text !== ''\n const hasSvg = params.svg !== undefined && params.svg !== null\n if (!hasText && !hasSvg) {\n throw new Error('[api/engrave] requires either \"text\" or \"svg\"')\n }\n if (params.depth !== undefined && params.depth !== null) {\n assertPositiveNumber(params.depth, 'engrave.depth')\n }\n}\n\n/** 世界坐标 → BREP solid 局部坐标。 */\nfunction worldToLocalPosition(\n worldPos: Vec3,\n partTransform: { position?: [number, number, number] } | undefined,\n): Vec3 {\n const offset = partTransform?.position\n if (!offset) return worldPos\n return [\n worldPos[0] - offset[0],\n worldPos[1] - offset[1],\n worldPos[2] - offset[2],\n ]\n}\n\n/** 计算将 +Z 轴对齐到目标法向量的 3x4 仿射变换矩阵(仅旋转,无平移,Rodrigues 公式)。 */\nfunction alignZToNormal(normal: Vec3): number[] {\n const [nx, ny, nz] = normal\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz)\n if (len < 1e-10) {\n return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]\n }\n const ux = nx / len, uy = ny / len, uz = nz / len\n\n if (Math.abs(ux) < 1e-10 && Math.abs(uy) < 1e-10) {\n if (uz > 0) return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]\n return [1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0]\n }\n\n const s = Math.sqrt(ux * ux + uy * uy)\n const c = uz\n const t = 1 - c\n const ax = -uy / s, ay = ux / s\n\n return [\n c + ax * ax * t, ax * ay * t, ay * s, 0,\n ax * ay * t, c + ay * ay * t, -ax * s, 0,\n -ay * s, ax * s, c, 0,\n ]\n}\n\n/** 将 solid 居中到原点(基于包围盒中心,与 mesh 路径语义一致)。 */\nfunction centerSolidAtOrigin(kernel: BrepEngineApi, solid: BrepHandle): BrepHandle {\n const bb = getSolidBoundingBox(kernel, solid)\n const cx = (bb.min[0] + bb.max[0]) / 2\n const cy = (bb.min[1] + bb.max[1]) / 2\n const cz = (bb.min[2] + bb.max[2]) / 2\n const centered = kernel.translate(solid, -cx, -cy, -cz)\n kernel.release(solid)\n return centered\n}\n\n/** BREP 路径:textToSolid/svgToSolid + boolean(cut/fuse)。 */\nasync function engraveBrepPath(input: Shape, params: Record<string, unknown>, svgText?: string): Promise<Shape> {\n const kernel = getBrepApi()\n const inputSolid = brepOf(input) as BrepHandle | undefined\n if (!inputSolid) throw new Error('[api/engrave] input is not BREP')\n\n const depth = params.depth as number\n const mode = (params.mode as 'convex' | 'concave' | undefined) ?? 'concave'\n const text = params.text as string | undefined\n\n // 1. 创建装饰 solid(文字或 SVG),depth 与 mesh 路径一致\n let decorationSolid: BrepHandle\n if (text) {\n await ensureDefaultFont()\n const textSize = (params.textSize as number) ?? 10\n decorationSolid = textToSolid(kernel, text, { fontSize: textSize, depth })\n } else if (svgText) {\n decorationSolid = svgToSolid(kernel, svgText, {\n depth,\n targetLongSide: (params.svgSize as number) ?? 20,\n })\n } else {\n throw new Error('[api/engrave] neither text nor svg provided')\n }\n\n // 2. 居中到原点\n decorationSolid = centerSolidAtOrigin(kernel, decorationSolid)\n\n // 3. 旋转 +Z 对齐面法向\n const worldFaceNormal: Vec3 = (params.faceNormal as Vec3) ?? [0, 0, 1]\n const rotMatrix = alignZToNormal(worldFaceNormal)\n const rotated = kernel.transform(decorationSolid, rotMatrix)\n kernel.release(decorationSolid)\n\n // 4. 沿法向偏移 + 平移到面中心(凸 offset=+depth/2,凹 offset=-depth/2;加 0.01 避免共面)\n const worldFaceCenter: Vec3 = (params.faceCenter as Vec3) ?? [0, 0, 0]\n const localFaceCenter = worldToLocalPosition(worldFaceCenter, getBackends().config.partTransform)\n const offset = mode === 'convex' ? depth / 2 : -depth / 2\n const epsilon = 0.01\n const tx = localFaceCenter[0] + worldFaceNormal[0] * (offset + epsilon)\n const ty = localFaceCenter[1] + worldFaceNormal[1] * (offset + epsilon)\n const tz = localFaceCenter[2] + worldFaceNormal[2] * (offset + epsilon)\n const positioned = kernel.translate(rotated, tx, ty, tz)\n kernel.release(rotated)\n\n // 5. 布尔运算(凸=fuse,凹=cut)\n const isRaised = mode === 'convex'\n let result: BrepHandle\n if (isRaised) {\n result = kernel.fuse(inputSolid, positioned)\n } else {\n result = kernel.cut(inputSolid, positioned)\n }\n kernel.release(positioned)\n\n // 5b. cut 可能分裂成多个 solid(compound),用 fuseAll 合并回单一 solid\n try {\n const subSolids = kernel.getSubShapes(result, 'solid')\n if (subSolids.length > 1) {\n const fused = kernel.fuseAll(subSolids)\n for (const s of subSolids) {\n try { kernel.release(s) } catch { /* 已释放 */ }\n }\n try { kernel.release(result) } catch { /* 已释放 */ }\n result = fused\n }\n } catch {\n // getSubShapes 失败说明结果不是 compound,无需处理\n }\n\n return fromBrep(solidToShape(kernel, result), { solid: result })\n}\n\n/** 解析 SVG 资产引用(AssetRef → SVG 文本),两条路径共享;无 svg 返回 undefined。 */\nasync function resolveEngraveSvg(params: Record<string, unknown>): Promise<string | undefined> {\n return params.svg !== undefined && params.svg !== null\n ? await resolveSvgArg(params.svg, { assets: getBackends().assets as AssetResolver | undefined })\n : undefined\n}\n\n/**\n * 在几何表面雕刻文字或 SVG(文字分支与 logo 分支都可用)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name engrave\n * @returns Shape 雕刻后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.mode - 雕刻方式:concave 凹陷(减法)/ convex 凸出(加法)。type:'concave' | 'convex' 默认 'concave'\n * @param params.depth - 深度 / 凸出高度(mm)。type:number 默认 0\n * @param params.text - 文字内容(与 svg 二选一)。type:string\n * @param params.textSize - 字号(mm)。type:number 默认 10\n * @param params.svg - SVG 资产引用(与 text 二选一;经 cad.asset 解析)。type:string\n * @param params.svgSize - SVG 长边目标尺寸。type:number\n * @param params.faceCenter - 面位置(绝对坐标)。type:[x,y,z] 默认 [0,0,0]\n * @param params.faceNormal - 面法向。type:[x,y,z] 默认 [0,0,1]\n * @note 早期 logo 分支用 `svgText`(整份 XML 拷贝 + `svgSize` 文本导出丢失,往返失真);现已改为 `svg` 资产引用,`engravingType` 冗余键已移除。faceCenter/faceNormal 目前是绝对坐标快照。\n * @example\n * const p = await cad.engrave(part0, { mode: 'concave', depth: 2, text: 'Hello', textSize: 10, faceCenter: [0, 0, 0], faceNormal: [0, 0, -1] })\n */\nexport const engrave = defineOp({\n mesh: async (input: Shape, params: Record<string, unknown>) => {\n if (!input) throw new Error('[api/engrave] no input geometry')\n assertEngraveParams(params)\n const svgText = await resolveEngraveSvg(params)\n // mesh 路径\n const faceCenter: Vec3 = (params.faceCenter as Vec3) ?? [0, 0, 0]\n const faceNormal: Vec3 = (params.faceNormal as Vec3) ?? [0, 0, 1]\n const { naturalWidth, naturalHeight } = svgText ? parseSvgNaturalSize(svgText) : { naturalWidth: 0, naturalHeight: 0 }\n const hasText = !!(params.text as string | undefined)\n\n return cad.engrave(input, {\n mode: (params.mode as 'convex' | 'concave' | undefined) ?? 'concave',\n depth: params.depth as number,\n face: { center: faceCenter, normal: faceNormal },\n text: hasText ? (params.text as string) : undefined,\n textSize: params.textSize as number | undefined,\n svg: svgText,\n svgNaturalWidth: naturalWidth,\n svgNaturalHeight: naturalHeight,\n svgSize: params.svgSize as number | undefined,\n })\n },\n brep: async (input: Shape, params: Record<string, unknown>) => {\n if (!input) throw new Error('[api/engrave] no input geometry')\n assertEngraveParams(params)\n const svgText = await resolveEngraveSvg(params)\n return engraveBrepPath(input, params, svgText)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n})\n"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * stdlib extrude — `cad.extrude`(平台 parity op,BREP-only)
2
+ * api extrude — `cad.extrude`(平台 parity op,BREP-only)
3
3
  *
4
4
  * 归属(分层红线):`cad.extrude` 是「面 → 棱柱」的**平台** op,FCStd Pad/Pocket
5
5
  * 链路与 TS 面共用它(docs/plans/2026-09-15-fcstd-to-faijs-port-plan.md M4.6:
@@ -56,6 +56,11 @@ export interface ExtrudeOptions {
56
56
  * up-to 模式(`upTo`)与长度模式(`length`)二选一;长度模式委托生成投影
57
57
  * (vendored extrude 为唯一引擎),up-to 模式走半空间组合。
58
58
  *
59
+ * **网格链**(`meshEngines: ['brepkit']`,方案 2026-10-01 §4 Phase 3):输入是
60
+ * `cad.sketchOnFace` 在网格实体识别面上铺出的网格链面时,本 op 沿同一份方向语义
61
+ * 拉伸出**一个新的网格零件**。网格链上不支持 `upTo`
62
+ * (需精度链求交裁切)——会以 `E_MESH_SOLID_UNSUPPORTED` 明确拒绝,不静默当定长拉伸。
63
+ *
59
64
  * @group 特征
60
65
  * @inputs 1
61
66
  * @async true
@@ -1 +1 @@
1
- {"version":3,"file":"extrude.d.ts","sourceRoot":"","sources":["../../src/api/extrude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAcH,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;AA2OD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,OAAO;;CAoElB,CAAA"}
1
+ {"version":3,"file":"extrude.d.ts","sourceRoot":"","sources":["../../src/api/extrude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;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;;CAwElB,CAAA"}