@faicad/faijs 0.13.1 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/dist/api/api-namespace.d.ts.map +1 -1
  2. package/dist/api/api-namespace.js +30 -4
  3. package/dist/api/api-namespace.js.map +1 -1
  4. package/dist/api/boolean.d.ts +19 -0
  5. package/dist/api/boolean.d.ts.map +1 -1
  6. package/dist/api/boolean.js +51 -10
  7. package/dist/api/boolean.js.map +1 -1
  8. package/dist/api/chamfer.d.ts.map +1 -1
  9. package/dist/api/chamfer.js +8 -7
  10. package/dist/api/chamfer.js.map +1 -1
  11. package/dist/api/compound-geom.d.ts +45 -0
  12. package/dist/api/compound-geom.d.ts.map +1 -0
  13. package/dist/api/compound-geom.js +85 -0
  14. package/dist/api/compound-geom.js.map +1 -0
  15. package/dist/api/compound.d.ts +2 -0
  16. package/dist/api/compound.d.ts.map +1 -1
  17. package/dist/api/compound.js +2 -0
  18. package/dist/api/compound.js.map +1 -1
  19. package/dist/api/copy.d.ts +1 -0
  20. package/dist/api/copy.d.ts.map +1 -1
  21. package/dist/api/copy.js +4 -2
  22. package/dist/api/copy.js.map +1 -1
  23. package/dist/api/edge-ref.d.ts +3 -2
  24. package/dist/api/edge-ref.d.ts.map +1 -1
  25. package/dist/api/edge-ref.js +10 -6
  26. package/dist/api/edge-ref.js.map +1 -1
  27. package/dist/api/engrave.d.ts.map +1 -1
  28. package/dist/api/engrave.js +1 -0
  29. package/dist/api/engrave.js.map +1 -1
  30. package/dist/api/extrude.d.ts.map +1 -1
  31. package/dist/api/extrude.js +131 -3
  32. package/dist/api/extrude.js.map +1 -1
  33. package/dist/api/face-ref.d.ts.map +1 -1
  34. package/dist/api/face-ref.js +7 -4
  35. package/dist/api/face-ref.js.map +1 -1
  36. package/dist/api/fai_drill.d.ts +1 -1
  37. package/dist/api/fai_drill.d.ts.map +1 -1
  38. package/dist/api/fai_drill.js +31 -18
  39. package/dist/api/fai_drill.js.map +1 -1
  40. package/dist/api/fai_extrude.d.ts +1 -1
  41. package/dist/api/fai_extrude.d.ts.map +1 -1
  42. package/dist/api/fai_extrude.js +2 -1
  43. package/dist/api/fai_extrude.js.map +1 -1
  44. package/dist/api/fai_split.d.ts +1 -1
  45. package/dist/api/fai_split.d.ts.map +1 -1
  46. package/dist/api/fai_split.js +2 -1
  47. package/dist/api/fai_split.js.map +1 -1
  48. package/dist/api/fillet.d.ts.map +1 -1
  49. package/dist/api/fillet.js +6 -5
  50. package/dist/api/fillet.js.map +1 -1
  51. package/dist/api/generated/operations.js +16 -16
  52. package/dist/api/generated/operations.js.map +1 -1
  53. package/dist/api/generated/script-face-manifest.d.ts.map +1 -1
  54. package/dist/api/generated/script-face-manifest.js +0 -1
  55. package/dist/api/generated/script-face-manifest.js.map +1 -1
  56. package/dist/api/generated/script-face.d.ts +1 -4
  57. package/dist/api/generated/script-face.d.ts.map +1 -1
  58. package/dist/api/generated/script-face.js +2 -3
  59. package/dist/api/generated/script-face.js.map +1 -1
  60. package/dist/api/generated/sketching.js +1 -1
  61. package/dist/api/generated/sketching.js.map +1 -1
  62. package/dist/api/generated/topology.d.ts +0 -48
  63. package/dist/api/generated/topology.d.ts.map +1 -1
  64. package/dist/api/generated/topology.js +20 -62
  65. package/dist/api/generated/topology.js.map +1 -1
  66. package/dist/api/import-brep.d.ts +36 -0
  67. package/dist/api/import-brep.d.ts.map +1 -0
  68. package/dist/api/import-brep.js +72 -0
  69. package/dist/api/import-brep.js.map +1 -0
  70. package/dist/api/import-step.d.ts +28 -0
  71. package/dist/api/import-step.d.ts.map +1 -0
  72. package/dist/api/import-step.js +57 -0
  73. package/dist/api/import-step.js.map +1 -0
  74. package/dist/api/index.d.ts +7 -2
  75. package/dist/api/index.d.ts.map +1 -1
  76. package/dist/api/index.js +19 -5
  77. package/dist/api/index.js.map +1 -1
  78. package/dist/api/internal/compat-op.d.ts +2 -0
  79. package/dist/api/internal/compat-op.d.ts.map +1 -1
  80. package/dist/api/internal/compat-op.js +10 -2
  81. package/dist/api/internal/compat-op.js.map +1 -1
  82. package/dist/api/knurl.d.ts.map +1 -1
  83. package/dist/api/knurl.js +1 -0
  84. package/dist/api/knurl.js.map +1 -1
  85. package/dist/api/load.d.ts +3 -1
  86. package/dist/api/load.d.ts.map +1 -1
  87. package/dist/api/load.js +3 -1
  88. package/dist/api/load.js.map +1 -1
  89. package/dist/api/pattern.d.ts +32 -0
  90. package/dist/api/pattern.d.ts.map +1 -0
  91. package/dist/api/pattern.js +121 -0
  92. package/dist/api/pattern.js.map +1 -0
  93. package/dist/api/place.d.ts +35 -0
  94. package/dist/api/place.d.ts.map +1 -0
  95. package/dist/api/place.js +113 -0
  96. package/dist/api/place.js.map +1 -0
  97. package/dist/api/primitives.d.ts.map +1 -1
  98. package/dist/api/primitives.js +10 -3
  99. package/dist/api/primitives.js.map +1 -1
  100. package/dist/api/screw.d.ts.map +1 -1
  101. package/dist/api/screw.js +1 -0
  102. package/dist/api/screw.js.map +1 -1
  103. package/dist/api/sdf.d.ts.map +1 -1
  104. package/dist/api/sdf.js +1 -0
  105. package/dist/api/sdf.js.map +1 -1
  106. package/dist/api/sketch.d.ts.map +1 -1
  107. package/dist/api/sketch.js +1 -0
  108. package/dist/api/sketch.js.map +1 -1
  109. package/dist/api/split.d.ts +31 -0
  110. package/dist/api/split.d.ts.map +1 -0
  111. package/dist/api/split.js +96 -0
  112. package/dist/api/split.js.map +1 -0
  113. package/dist/api/surface/arg-spec.d.ts +9 -0
  114. package/dist/api/surface/arg-spec.d.ts.map +1 -1
  115. package/dist/api/surface/arg-spec.js +49 -30
  116. package/dist/api/surface/arg-spec.js.map +1 -1
  117. package/dist/api/svgExtrude.d.ts.map +1 -1
  118. package/dist/api/svgExtrude.js +1 -0
  119. package/dist/api/svgExtrude.js.map +1 -1
  120. package/dist/api/text.d.ts.map +1 -1
  121. package/dist/api/text.js +1 -0
  122. package/dist/api/text.js.map +1 -1
  123. package/dist/api/topo-resolve.d.ts.map +1 -1
  124. package/dist/api/topo-resolve.js +65 -3
  125. package/dist/api/topo-resolve.js.map +1 -1
  126. package/dist/api/transform.d.ts +4 -0
  127. package/dist/api/transform.d.ts.map +1 -1
  128. package/dist/api/transform.js +44 -12
  129. package/dist/api/transform.js.map +1 -1
  130. package/dist/brep/brep-ops.d.ts +34 -1
  131. package/dist/brep/brep-ops.d.ts.map +1 -1
  132. package/dist/brep/brep-ops.js +62 -22
  133. package/dist/brep/brep-ops.js.map +1 -1
  134. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  135. package/dist/brep/engine/adapters/brep-mock.js +8 -0
  136. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  137. package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
  138. package/dist/brep/engine/adapters/brepkit.js +6 -1
  139. package/dist/brep/engine/adapters/brepkit.js.map +1 -1
  140. package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
  141. package/dist/brep/engine/adapters/occt.js +24 -1
  142. package/dist/brep/engine/adapters/occt.js.map +1 -1
  143. package/dist/brep/engine/primitives.d.ts +17 -0
  144. package/dist/brep/engine/primitives.d.ts.map +1 -1
  145. package/dist/brep/engine/primitives.js.map +1 -1
  146. package/dist/brep/engine/types.d.ts +49 -6
  147. package/dist/brep/engine/types.d.ts.map +1 -1
  148. package/dist/brep/engine/types.js.map +1 -1
  149. package/dist/brep/export/step.d.ts.map +1 -1
  150. package/dist/brep/export/step.js +6 -1
  151. package/dist/brep/export/step.js.map +1 -1
  152. package/dist/brep/face-evolution.d.ts +78 -8
  153. package/dist/brep/face-evolution.d.ts.map +1 -1
  154. package/dist/brep/face-evolution.js +130 -17
  155. package/dist/brep/face-evolution.js.map +1 -1
  156. package/dist/brepkit-kernel/brepkitKernel.d.ts +1 -1
  157. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  158. package/dist/brepkit-kernel/brepkitKernel.js +27 -1
  159. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  160. package/dist/browser.d.ts +0 -2
  161. package/dist/browser.d.ts.map +1 -1
  162. package/dist/browser.js +2 -2
  163. package/dist/browser.js.map +1 -1
  164. package/dist/cad-runtime/admit-compat-lib.d.ts +19 -1
  165. package/dist/cad-runtime/admit-compat-lib.d.ts.map +1 -1
  166. package/dist/cad-runtime/admit-compat-lib.js +21 -1
  167. package/dist/cad-runtime/admit-compat-lib.js.map +1 -1
  168. package/dist/cad-runtime/backend-dispatch.d.ts +44 -3
  169. package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
  170. package/dist/cad-runtime/backend-dispatch.js +46 -3
  171. package/dist/cad-runtime/backend-dispatch.js.map +1 -1
  172. package/dist/cad-runtime/browser-lib-loader.d.ts +2 -0
  173. package/dist/cad-runtime/browser-lib-loader.d.ts.map +1 -1
  174. package/dist/cad-runtime/browser-lib-loader.js +9 -1
  175. package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
  176. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  177. package/dist/cad-runtime/direct-executor.js +14 -4
  178. package/dist/cad-runtime/direct-executor.js.map +1 -1
  179. package/dist/cad-runtime/module-registry.d.ts +3 -1
  180. package/dist/cad-runtime/module-registry.d.ts.map +1 -1
  181. package/dist/cad-runtime/module-registry.js +13 -1
  182. package/dist/cad-runtime/module-registry.js.map +1 -1
  183. package/dist/cad-runtime/ports.d.ts +7 -0
  184. package/dist/cad-runtime/ports.d.ts.map +1 -1
  185. package/dist/cad-runtime/ports.js.map +1 -1
  186. package/dist/cad-runtime/runtime-concurrent-error.d.ts +38 -0
  187. package/dist/cad-runtime/runtime-concurrent-error.d.ts.map +1 -0
  188. package/dist/cad-runtime/runtime-concurrent-error.js +43 -0
  189. package/dist/cad-runtime/runtime-concurrent-error.js.map +1 -0
  190. package/dist/cad-runtime/runtime.d.ts +54 -2
  191. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  192. package/dist/cad-runtime/runtime.js +186 -10
  193. package/dist/cad-runtime/runtime.js.map +1 -1
  194. package/dist/define-op.d.ts +22 -0
  195. package/dist/define-op.d.ts.map +1 -1
  196. package/dist/define-op.js +82 -12
  197. package/dist/define-op.js.map +1 -1
  198. package/dist/fcstd/attachment.d.ts +72 -0
  199. package/dist/fcstd/attachment.d.ts.map +1 -0
  200. package/dist/fcstd/attachment.js +93 -0
  201. package/dist/fcstd/attachment.js.map +1 -0
  202. package/dist/fcstd/build-fai-zip.d.ts +11 -0
  203. package/dist/fcstd/build-fai-zip.d.ts.map +1 -1
  204. package/dist/fcstd/build-fai-zip.js +21 -8
  205. package/dist/fcstd/build-fai-zip.js.map +1 -1
  206. package/dist/fcstd/cli.d.ts +3 -0
  207. package/dist/fcstd/cli.d.ts.map +1 -0
  208. package/dist/fcstd/cli.js +37 -0
  209. package/dist/fcstd/cli.js.map +1 -0
  210. package/dist/fcstd/codegen.d.ts +23 -1
  211. package/dist/fcstd/codegen.d.ts.map +1 -1
  212. package/dist/fcstd/codegen.js +159 -48
  213. package/dist/fcstd/codegen.js.map +1 -1
  214. package/dist/fcstd/container.d.ts +16 -1
  215. package/dist/fcstd/container.d.ts.map +1 -1
  216. package/dist/fcstd/container.js +12 -1
  217. package/dist/fcstd/container.js.map +1 -1
  218. package/dist/fcstd/contour.d.ts +9 -1
  219. package/dist/fcstd/contour.d.ts.map +1 -1
  220. package/dist/fcstd/contour.js +28 -18
  221. package/dist/fcstd/contour.js.map +1 -1
  222. package/dist/fcstd/convert.d.ts +31 -2
  223. package/dist/fcstd/convert.d.ts.map +1 -1
  224. package/dist/fcstd/convert.js +73 -22
  225. package/dist/fcstd/convert.js.map +1 -1
  226. package/dist/fcstd/document.d.ts +8 -1
  227. package/dist/fcstd/document.d.ts.map +1 -1
  228. package/dist/fcstd/document.js +4 -1
  229. package/dist/fcstd/document.js.map +1 -1
  230. package/dist/fcstd/expressions.d.ts +14 -1
  231. package/dist/fcstd/expressions.d.ts.map +1 -1
  232. package/dist/fcstd/expressions.js +11 -1
  233. package/dist/fcstd/expressions.js.map +1 -1
  234. package/dist/fcstd/external-geo.d.ts +27 -2
  235. package/dist/fcstd/external-geo.d.ts.map +1 -1
  236. package/dist/fcstd/external-geo.js +23 -2
  237. package/dist/fcstd/external-geo.js.map +1 -1
  238. package/dist/fcstd/feature-translate.d.ts +85 -3
  239. package/dist/fcstd/feature-translate.d.ts.map +1 -1
  240. package/dist/fcstd/feature-translate.js +189 -9
  241. package/dist/fcstd/feature-translate.js.map +1 -1
  242. package/dist/fcstd/index.d.ts +23 -0
  243. package/dist/fcstd/index.d.ts.map +1 -0
  244. package/dist/fcstd/index.js +19 -0
  245. package/dist/fcstd/index.js.map +1 -0
  246. package/dist/fcstd/placement.d.ts +49 -6
  247. package/dist/fcstd/placement.d.ts.map +1 -1
  248. package/dist/fcstd/placement.js +46 -6
  249. package/dist/fcstd/placement.js.map +1 -1
  250. package/dist/fcstd/planegcs-backend.d.ts +16 -1
  251. package/dist/fcstd/planegcs-backend.d.ts.map +1 -1
  252. package/dist/fcstd/planegcs-backend.js +16 -1
  253. package/dist/fcstd/planegcs-backend.js.map +1 -1
  254. package/dist/fcstd/sketch-parse.d.ts +43 -0
  255. package/dist/fcstd/sketch-parse.d.ts.map +1 -1
  256. package/dist/fcstd/sketch-parse.js +26 -0
  257. package/dist/fcstd/sketch-parse.js.map +1 -1
  258. package/dist/fcstd/sketch-solver.d.ts +20 -2
  259. package/dist/fcstd/sketch-solver.d.ts.map +1 -1
  260. package/dist/fcstd/sketch-solver.js +6 -1
  261. package/dist/fcstd/sketch-solver.js.map +1 -1
  262. package/dist/fcstd/sketch-verify.d.ts +19 -1
  263. package/dist/fcstd/sketch-verify.d.ts.map +1 -1
  264. package/dist/fcstd/sketch-verify.js +14 -1
  265. package/dist/fcstd/sketch-verify.js.map +1 -1
  266. package/dist/fcstd/structural-types.d.ts +83 -0
  267. package/dist/fcstd/structural-types.d.ts.map +1 -0
  268. package/dist/fcstd/structural-types.js +116 -0
  269. package/dist/fcstd/structural-types.js.map +1 -0
  270. package/dist/fcstd/unpack.d.ts +21 -2
  271. package/dist/fcstd/unpack.d.ts.map +1 -1
  272. package/dist/fcstd/unpack.js +11 -2
  273. package/dist/fcstd/unpack.js.map +1 -1
  274. package/dist/fcstd-convert.d.ts +30 -0
  275. package/dist/fcstd-convert.d.ts.map +1 -0
  276. package/dist/fcstd-convert.js +27 -0
  277. package/dist/fcstd-convert.js.map +1 -0
  278. package/dist/index.d.ts +1 -0
  279. package/dist/index.d.ts.map +1 -1
  280. package/dist/index.js.map +1 -1
  281. package/dist/lang/determinism-scanner.d.ts +62 -0
  282. package/dist/lang/determinism-scanner.d.ts.map +1 -0
  283. package/dist/lang/determinism-scanner.js +619 -0
  284. package/dist/lang/determinism-scanner.js.map +1 -0
  285. package/dist/lang/symbol-table.generated.d.ts +7 -3
  286. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  287. package/dist/lang/symbol-table.generated.js +7 -3
  288. package/dist/lang/symbol-table.generated.js.map +1 -1
  289. package/dist/mesh/index.d.ts.map +1 -1
  290. package/dist/mesh/index.js +3 -2
  291. package/dist/mesh/index.js.map +1 -1
  292. package/dist/node-host/cli.d.ts.map +1 -1
  293. package/dist/node-host/cli.js +56 -2
  294. package/dist/node-host/cli.js.map +1 -1
  295. package/dist/runtime-state.d.ts +18 -6
  296. package/dist/runtime-state.d.ts.map +1 -1
  297. package/dist/runtime-state.js +9 -1
  298. package/dist/runtime-state.js.map +1 -1
  299. package/dist/shape.d.ts +15 -0
  300. package/dist/shape.d.ts.map +1 -1
  301. package/dist/shape.js +26 -3
  302. package/dist/shape.js.map +1 -1
  303. package/dist/topology/naming/build-naming.d.ts +14 -30
  304. package/dist/topology/naming/build-naming.d.ts.map +1 -1
  305. package/dist/topology/naming/build-naming.js +21 -54
  306. package/dist/topology/naming/build-naming.js.map +1 -1
  307. package/dist/topology/naming/capture-topo-ref.d.ts.map +1 -1
  308. package/dist/topology/naming/capture-topo-ref.js +5 -0
  309. package/dist/topology/naming/capture-topo-ref.js.map +1 -1
  310. package/dist/topology/naming/index.d.ts +3 -0
  311. package/dist/topology/naming/index.d.ts.map +1 -1
  312. package/dist/topology/naming/index.js +3 -0
  313. package/dist/topology/naming/index.js.map +1 -1
  314. package/dist/topology/naming/lineage-resolve.d.ts +80 -0
  315. package/dist/topology/naming/lineage-resolve.d.ts.map +1 -0
  316. package/dist/topology/naming/lineage-resolve.js +120 -0
  317. package/dist/topology/naming/lineage-resolve.js.map +1 -0
  318. package/dist/topology/naming/lineage.d.ts +349 -0
  319. package/dist/topology/naming/lineage.d.ts.map +1 -0
  320. package/dist/topology/naming/lineage.js +398 -0
  321. package/dist/topology/naming/lineage.js.map +1 -0
  322. package/dist/topology/naming/migrate.d.ts +41 -0
  323. package/dist/topology/naming/migrate.d.ts.map +1 -0
  324. package/dist/topology/naming/migrate.js +88 -0
  325. package/dist/topology/naming/migrate.js.map +1 -0
  326. package/dist/topology/naming/role-name.d.ts +176 -0
  327. package/dist/topology/naming/role-name.d.ts.map +1 -0
  328. package/dist/topology/naming/role-name.js +344 -0
  329. package/dist/topology/naming/role-name.js.map +1 -0
  330. package/dist/topology/naming/roles.d.ts +20 -22
  331. package/dist/topology/naming/roles.d.ts.map +1 -1
  332. package/dist/topology/naming/roles.js +51 -49
  333. package/dist/topology/naming/roles.js.map +1 -1
  334. package/dist/topology/naming/types.d.ts +65 -18
  335. package/dist/topology/naming/types.d.ts.map +1 -1
  336. package/dist/topology/naming/types.js.map +1 -1
  337. package/dist/weapp.d.ts +22 -0
  338. package/dist/weapp.d.ts.map +1 -0
  339. package/dist/weapp.js +23 -0
  340. package/dist/weapp.js.map +1 -0
  341. package/package.json +18 -5
@@ -0,0 +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 { 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, kernel: kernels } = getBackends()\n const kernel = kernels.brep as BrepEngineApi | null\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"]}
@@ -74,6 +74,7 @@ export interface AssemblyBehavior {
74
74
  * @async false
75
75
  * @qual ok
76
76
  * @name group
77
+ * @deprecated **`../3d_editor` 消费面**(原 `@deprecated` 措辞已于 2026-09-22 校正):该 op 为编辑器应用提供(无几何输出,服务于编辑器画布与时间线),不属 faijs 平台面,但**不是废弃项**——它服务真实负载。**变更其 API 形态必须同步更新 `../3d_editor`**(见 `docs/plans/2026-09-22-topology-identity-development-plan.md` §2)。**平台侧需要几何复合体请用 `cad.compound`**(内核 `makeCompound`,持 OCCT 句柄,可变换/可导出)。
77
78
  * @returns CompoundShape 复合几何(kind='compound',children 为成员 Shape 引用)。
78
79
  * @param params.name - 组名。type:string
79
80
  * @param params.members - 成员(编译产物 ctx.<var> 引用;结构语句里是裸变量引用,非字符串数组)。type:Shape[]
@@ -92,6 +93,7 @@ export declare function group(params: GroupParams): CompoundShape;
92
93
  * @async false
93
94
  * @qual warn
94
95
  * @name assembly
96
+ * @deprecated **`../3d_editor` 消费面**(原 `@deprecated` 措辞已于 2026-09-22 校正):该 op 为编辑器应用提供(成员以编辑器结构语句形态声明,服务于画布与时间线),不属 faijs 平台面,但**不是废弃项**——它服务真实负载。**变更其 API 形态必须同步更新 `../3d_editor`**(见 `docs/plans/2026-09-22-topology-identity-development-plan.md` §2)。faijs 平台面不提供等价 op(需要时须按平台需求另行设计,不得直接搬用本 op)。
95
97
  * @returns CompoundShape + AssemblyBehavior(含 do_assemble / solve 方法)。
96
98
  * @note 约束类型(a=参考、b=从动,移动 b 去贴合 a):`mate` 面对面贴合(法向反向+面中心重合,遗留 face_mate 的新名,求解降级为 concentric + 轴编码);`align` 同向对齐(法向同向+面中心重合);`coincident` 共面/共点/共线(保留面内 2 个平移 DOF);`concentric` 轴重合(孔轴配合,圆柱/圆锥面需 hint.axis,直边/圆边需 EdgeHint.axis);`distance` 定距(mm,带 value);`angle` 夹角(deg,带 value);`parallel`/`perpendicular` 平行/垂直(angle 0°/90° 语法糖);`fixed` 锚定部件(地基);`face_mate` 为遗留别名(规范化为 mate,新代码不再使用)。
97
99
  * @note EntityRef 四种形态:`{ part, face: { topoRef } | { surfaceType?, center, normal } }`、`{ part, edge: { topoRef } | { axis: { origin, direction } } }`、`{ part, point: [x,y,z] }`、`{ part, faceIndex }`(1 起,仅调试简写)。
@@ -1 +1 @@
1
- {"version":3,"file":"compound.d.ts","sourceRoot":"","sources":["../../src/api/compound.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAwC,KAAK,aAAa,EAAE,MAAM,UAAU,CAAA;AACnF,OAAO,EAA4E,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACnI,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAEvF,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAI3D,wFAAwF;AACxF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,+EAA+E;IAC/E,OAAO,CAAC,EAAE,KAAK,EAAE,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,6FAA6F;AAC7F,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAClC,kDAAkD;IAClD,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;IACpB,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;IACzC,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACvD,6EAA6E;IAC7E,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAID,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,OAAO,EACP,OAAO,EACP,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACvB,eAAe,EACf,oBAAoB,EACpB,YAAY,GACb,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAQ3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAIxD,uFAAuF;AACvF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,WAAW,EAAE,kBAAkB,EAAE,CAAA;IACjC,gCAAgC;IAChC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;IACpB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;IACzC,iCAAiC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACvD,eAAe;IACf,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,mDAAmD;IACnD,KAAK,IAAI,iBAAiB,EAAE,CAAA;IAC5B,4FAA4F;IAC5F,aAAa,IAAI,mBAAmB,CAAA;CACrC;AAyCD;;;;;GAKG;AACH;;;;;;;;;;;;;;IAcI;AACJ,wBAAgB,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,CAcxD;AAED;;;;;;;;;;;;;;;;;;;;IAoBI;AACJ,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,aAAa,CAqD9D"}
1
+ {"version":3,"file":"compound.d.ts","sourceRoot":"","sources":["../../src/api/compound.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAwC,KAAK,aAAa,EAAE,MAAM,UAAU,CAAA;AACnF,OAAO,EAA4E,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACnI,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAEvF,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAI3D,wFAAwF;AACxF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,+EAA+E;IAC/E,OAAO,CAAC,EAAE,KAAK,EAAE,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,6FAA6F;AAC7F,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAClC,kDAAkD;IAClD,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;IACpB,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;IACzC,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACvD,6EAA6E;IAC7E,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAID,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,OAAO,EACP,OAAO,EACP,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACvB,eAAe,EACf,oBAAoB,EACpB,YAAY,GACb,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAQ3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAIxD,uFAAuF;AACvF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,WAAW,EAAE,kBAAkB,EAAE,CAAA;IACjC,gCAAgC;IAChC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;IACpB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;IACzC,iCAAiC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACvD,eAAe;IACf,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,mDAAmD;IACnD,KAAK,IAAI,iBAAiB,EAAE,CAAA;IAC5B,4FAA4F;IAC5F,aAAa,IAAI,mBAAmB,CAAA;CACrC;AAyCD;;;;;GAKG;AACH;;;;;;;;;;;;;;;IAeI;AACJ,wBAAgB,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,CAcxD;AAED;;;;;;;;;;;;;;;;;;;;;IAqBI;AACJ,wBAAgB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,aAAa,CAqD9D"}
@@ -68,6 +68,7 @@ function memberNamesOf(params, members) {
68
68
  * @async false
69
69
  * @qual ok
70
70
  * @name group
71
+ * @deprecated **`../3d_editor` 消费面**(原 `@deprecated` 措辞已于 2026-09-22 校正):该 op 为编辑器应用提供(无几何输出,服务于编辑器画布与时间线),不属 faijs 平台面,但**不是废弃项**——它服务真实负载。**变更其 API 形态必须同步更新 `../3d_editor`**(见 `docs/plans/2026-09-22-topology-identity-development-plan.md` §2)。**平台侧需要几何复合体请用 `cad.compound`**(内核 `makeCompound`,持 OCCT 句柄,可变换/可导出)。
71
72
  * @returns CompoundShape 复合几何(kind='compound',children 为成员 Shape 引用)。
72
73
  * @param params.name - 组名。type:string
73
74
  * @param params.members - 成员(编译产物 ctx.<var> 引用;结构语句里是裸变量引用,非字符串数组)。type:Shape[]
@@ -101,6 +102,7 @@ export function group(params) {
101
102
  * @async false
102
103
  * @qual warn
103
104
  * @name assembly
105
+ * @deprecated **`../3d_editor` 消费面**(原 `@deprecated` 措辞已于 2026-09-22 校正):该 op 为编辑器应用提供(成员以编辑器结构语句形态声明,服务于画布与时间线),不属 faijs 平台面,但**不是废弃项**——它服务真实负载。**变更其 API 形态必须同步更新 `../3d_editor`**(见 `docs/plans/2026-09-22-topology-identity-development-plan.md` §2)。faijs 平台面不提供等价 op(需要时须按平台需求另行设计,不得直接搬用本 op)。
104
106
  * @returns CompoundShape + AssemblyBehavior(含 do_assemble / solve 方法)。
105
107
  * @note 约束类型(a=参考、b=从动,移动 b 去贴合 a):`mate` 面对面贴合(法向反向+面中心重合,遗留 face_mate 的新名,求解降级为 concentric + 轴编码);`align` 同向对齐(法向同向+面中心重合);`coincident` 共面/共点/共线(保留面内 2 个平移 DOF);`concentric` 轴重合(孔轴配合,圆柱/圆锥面需 hint.axis,直边/圆边需 EdgeHint.axis);`distance` 定距(mm,带 value);`angle` 夹角(deg,带 value);`parallel`/`perpendicular` 平行/垂直(angle 0°/90° 语法糖);`fixed` 锚定部件(地基);`face_mate` 为遗留别名(规范化为 mate,新代码不再使用)。
106
108
  * @note EntityRef 四种形态:`{ part, face: { topoRef } | { surfaceType?, center, normal } }`、`{ part, edge: { topoRef } | { axis: { origin, direction } } }`、`{ part, point: [x,y,z] }`、`{ part, faceIndex }`(1 起,仅调试简写)。
@@ -1 +1 @@
1
- {"version":3,"file":"compound.js","sourceRoot":"","sources":["../../src/api/compound.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * stdlib compound — group/assembly 库函数(compound Shape + AssemblyBehavior)\n *\n *\n * 从 src/ops/assemble.ts 迁出并改写为 stdlib 形态:\n * - `group(params)` → compound Shape(kind='compound',children 为成员 Shape 引用)\n * - `assembly(params)` → compound Shape + AssemblyBehavior(约束列表 + solve 方法)\n * - 装配求解(P1 起)委派 api/assembly/(brepjs solverAdapter 内核):\n * do_assemble/solve 触发求解 → 引擎应用\n * (mesh 顶点烘焙 + BREP 刚体变换 + 下游传播)。\n * P2-f5:旧装配算法与自有四元数实现已删除,求解全链路走 api/assembly。\n *\n * compound 自身无独立 mesh——几何由 children 承载,意义是结构(层级)。\n * do_assemble 编译为 `await ctx.<asm>.do_assemble()`:调用 compound 的求解方法,\n * 对约束定位的成员施加装配变换(mesh 顶点烘焙 + BREP 刚体变换 + 下游传播)。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { compound as makeCompound, ensureSlot, type CompoundShape } from '../shape'\nimport { keep, nameOf, setPendingAssemblyTransforms, setPendingAssemblyKinematics, type AssemblyTransform } from '../runtime-state'\nimport { solveAssemblyAndKinematics, type AssemblySolveResult } from './assembly/solve'\nimport { validateConstraints } from './assembly/validate'\nimport { buildKinematicTree, type JointSpec } from './assembly/joints'\nimport type { AssemblyConstraint } from './assembly/types'\nimport type { SolverStyle } from './assembly/solvers/types'\n\n// ── 参数类型(keep-syntax 设计 §2.5:成员保留由函数体 keep() 显式声明,不再靠类型标注) ──\n\n/** Parameters for the `group` stdlib function: an optional name and ordered members. */\nexport interface GroupParams {\n name?: string\n /** Compound members: read-only references, never mutated by group/assembly. */\n members?: Shape[]\n memberNames?: string[]\n}\n\n/** Parameters for the `assembly` stdlib function: group params plus assembly constraints. */\nexport interface AssemblyParams extends GroupParams {\n constraints?: AssemblyConstraint[]\n /** P3:运动副声明(可选;parent/child 必须是 members 里的名字)。 */\n joints?: JointSpec[]\n /** P3:驱动值覆盖(键 = child 成员名;值 = 主 DOF 数值或多 DOF 数组)。 */\n drive?: Record<string, number | number[]>\n /** cq-compat:成员颜色(sRGB 0..1),导出 STEP 时写入 XCAF。 */\n memberColors?: Record<string, [number, number, number]>\n /** P1:求解风格。'chain'(默认,vendored brepjs 解析链式)| 'global'(CadQuery 兼容全局最小二乘)。 */\n solver?: SolverStyle\n}\n\n// ── 约束类型(P1 起定义收口在 api/assembly/types,此处 re-export 保持既有导出面) ──\n\nexport type {\n AssemblyConstraint,\n FaceMateConstraint,\n FaceMateFace,\n EntityRef,\n FaceRef,\n EdgeRef,\n MateConstraint,\n AlignConstraint,\n CoincidentConstraint,\n ConcentricConstraint,\n DistanceConstraint,\n AngleConstraint,\n ParallelConstraint,\n PerpendicularConstraint,\n FixedConstraint,\n StructuralConstraint,\n AssemblyVec3,\n} from './assembly/types'\nexport type { AssemblySolveResult } from './assembly/solve'\n\n// ── 求解器 ──\n// P2-f5:旧装配算法与自有四元数实现已整体删除——旋转计算一律走\n// brepjs utils/quaternion.ts,输出经 api/assembly/pose.ts fromBrepjsQuat 重排。\n\n// 应用变换(mesh 顶点烘焙)下沉到引擎侧 src/mesh/rigid-transform.ts(E-b:\n// 引擎不得 import stdlib/compound;公共 API 经本 re-export 保持)。\nexport { applyTransform } from '../mesh/rigid-transform'\n\n// ── AssemblyBehavior ──\n\n/** Behavior attached to an assembly compound: its members, constraints, and solver. */\nexport interface AssemblyBehavior {\n name?: string\n memberNames: string[]\n constraints: AssemblyConstraint[]\n /** P3:运动副声明(无 joints 时为空数组)。 */\n joints?: JointSpec[]\n /** P3:驱动值覆盖(键 = child 成员名;缺省 undefined = 用 joint 存储值)。 */\n drive?: Record<string, number | number[]>\n /** cq-compat:成员颜色(sRGB 0..1)。 */\n memberColors?: Record<string, [number, number, number]>\n /** P1:求解风格。 */\n solver?: SolverStyle\n /** 只求解(P6):返回\"成员下标 → 变换\"列表。不改写入参、不传播;可重复调用(幂等)。 */\n solve(): AssemblyTransform[]\n /** 只求解并带诊断量(P1):transforms + dof/converged/unsupported(方案 P1⑤);P3 增 kinematics/warnings。 */\n solveDetailed(): AssemblySolveResult\n}\n\n/**\n * 纯求解(P6:求解 ≠ 传播):委派 api/assembly/solveAssembly(P1 起)。\n * 不修改任何输入、不触碰引擎状态——引擎负责应用变换并让下游失效重算(F2)。\n *\n * 约束形态(方案 §5):\n * - 遗留 face_mate:规范化为 mate 后降级为 brepjs concentric + 轴编码求解(§3.7.2);\n * - 新形态 mate/align/coincident/concentric/distance/angle/parallel/perpendicular/fixed;\n * - 面参数 `{ topoRef }` 执行期解析(BREP 现场/mesh 行快照),旧 `{ center, normal }`\n * 快照直接使用(兼容已持久化的历史脚本);\n * - 输出为 per-member 终态(L6 修复),锚定成员不输出变换。\n */\nfunction solveTransforms(members: Shape[], behavior: AssemblyBehavior): AssemblyTransform[] {\n return solveAssemblyAndKinematics(\n members,\n behavior.memberNames,\n behavior.constraints,\n behavior.joints ?? [],\n behavior.drive,\n { solver: behavior.solver, name: behavior.name },\n ).transforms\n}\n\n// ── group / assembly 库函数 ──\n\n/**\n * 成员名推导:显式 memberNames 兼容旧手工构造 IR;否则经 keep() 反查\n * (P3 起经 keep()/nameOfShapes 反查成员名——库不再访问执行上下文,F1)。\n */\nfunction memberNamesOf(params: { memberNames?: unknown }, members: Shape[]): string[] {\n if (Array.isArray(params.memberNames) && params.memberNames.length > 0) {\n return params.memberNames as string[]\n }\n return members.map((m) => {\n // 兼容字符串形态的 members(历史 IR 直传 partName):字符串本身就是名字\n if (typeof m === 'string') return m\n return String(nameOf(m) ?? '')\n })\n}\n\n/**\n * `cad.group({ name, members })` → compound Shape。\n * members 是成员 Shape(编译产物 ctx.<var> 引用),成员名经 keep() 反查。\n *\n * 函数体 keep 声明(keep-syntax 设计 §2.5):group 保留其成员且可见(R6)。\n */\n/**\n * 分组:零约束,保持当前布局。结构语句,无几何输出,成员用变量名引用。\n * @group 结构\n * @inputs 1\n * @async false\n * @qual ok\n * @name group\n * @returns CompoundShape 复合几何(kind='compound',children 为成员 Shape 引用)。\n * @param params.name - 组名。type:string\n * @param params.members - 成员(编译产物 ctx.<var> 引用;结构语句里是裸变量引用,非字符串数组)。type:Shape[]\n * @note members 在 .fai.js 里是裸变量引用(编译为 ctx.<var>),字符串数组形态的成员名经 keep() 反查兼容历史 IR。\n * @example\n * const part0 = cad.box(30, 20, 10, { centered: true })\n * cad.group({ name: '底板组', members: [part0] })\n */\nexport function group(params: GroupParams): CompoundShape {\n const members = (params.members as Shape[] | undefined) ?? []\n if (members.length > 0) keep(...members)\n const memberNames = memberNamesOf(params, members)\n const c = makeCompound(members)\n // 挂最小 behavior(memberNames 供 ExecutionResult.compounds 结构输出;group 无约束)\n ensureSlot(c).behavior = {\n memberNames,\n constraints: [],\n joints: [],\n solve: () => [],\n solveDetailed: () => ({ transforms: [], dof: 0, converged: true, unsupported: [] }),\n }\n return c\n}\n\n/**\n * 装配:成员 + 约束。结构语句,无几何输出,成员用变量名引用、实体用 EntityRef / 拓扑引用。\n * 求解内核复用 vendored brepjs solverAdapter.solveConstraints(链式拓扑调度 / DOF / converged /\n * unsupported 诊断);输出为 per-member 终态变换(每成员一条,恒等位姿不输出)。\n * @group 结构\n * @inputs 1\n * @async false\n * @qual warn\n * @name assembly\n * @returns CompoundShape + AssemblyBehavior(含 do_assemble / solve 方法)。\n * @note 约束类型(a=参考、b=从动,移动 b 去贴合 a):`mate` 面对面贴合(法向反向+面中心重合,遗留 face_mate 的新名,求解降级为 concentric + 轴编码);`align` 同向对齐(法向同向+面中心重合);`coincident` 共面/共点/共线(保留面内 2 个平移 DOF);`concentric` 轴重合(孔轴配合,圆柱/圆锥面需 hint.axis,直边/圆边需 EdgeHint.axis);`distance` 定距(mm,带 value);`angle` 夹角(deg,带 value);`parallel`/`perpendicular` 平行/垂直(angle 0°/90° 语法糖);`fixed` 锚定部件(地基);`face_mate` 为遗留别名(规范化为 mate,新代码不再使用)。\n * @note EntityRef 四种形态:`{ part, face: { topoRef } | { surfaceType?, center, normal } }`、`{ part, edge: { topoRef } | { axis: { origin, direction } } }`、`{ part, point: [x,y,z] }`、`{ part, faceIndex }`(1 起,仅调试简写)。\n * @note 不收敛(实体类型不匹配/环/参考不可达)→ 抛错并带 unsupported 明细;成员名为空串 → 求解前抛错;mesh 快照缺 axis 的圆柱/圆锥面作轴实体 → E_TOPO_NOT_FOUND(绝不静默降级)。`mate`(中心重合)与 `coincident`(只共面)是两种不同语义,不互相映射。\n * @note 早期文档/示例曾用 `fixedPartId`/`movingPartId`/`faceRowIndex`/`faceId`/`invalid`——这些键在代码中不存在。真实契约是 `fixedPartName`/`movingPartName` + `fixedFace`/`movingFace`(遗留 face_mate)。`faceId` 字段随 §6.2 移除,不再写入。\n * @param params.name - 装配名。type:string\n * @param params.members - 成员(裸变量引用)。type:Shape[]\n * @param params.constraints - 约束数组(遗留 face_mate 形态或上述新形态 { type, a, b })。type:AssemblyConstraint[]\n * @example\n * let asm1 = cad.assembly({ name: '主轴组件', members: [part0, part1, part2], constraints: [ { type: 'fixed', part: 'part0' }, { type: 'mate', a: { part: 'part0', face: { topoRef: { kind: 'face', origin: 'part0', role: 'box:top', hint: { kind: 'face', surfaceType: 'plane' } } } }, b: { part: 'part1', face: { topoRef: { kind: 'face', origin: 'part1', role: 'box:bottom', hint: { kind: 'face', surfaceType: 'plane' } } } } }, { type: 'concentric', a: { part: 'part1', face: { topoRef: { kind: 'face', origin: 'part1', role: '', hint: { kind: 'face', surfaceType: 'cylinder' } } } }, b: { part: 'part2', face: { topoRef: { kind: 'face', origin: 'part2', role: 'cylinder:lateral', hint: { kind: 'face', surfaceType: 'cylinder' } } } } } ] })\n * asm1.solve()\n */\nexport function assembly(params: AssemblyParams): CompoundShape {\n const members = (params.members as Shape[] | undefined) ?? []\n const constraints = (params.constraints as AssemblyConstraint[] | undefined) ?? []\n const joints = (params.joints as JointSpec[] | undefined) ?? []\n const drive = params.drive as Record<string, number | number[]> | undefined\n\n // P2-f1:约束参数运行期校验(keep() 之前,fail-fast;规则见 api/assembly/validate.ts V1–V6)\n const memberNames = memberNamesOf(params, members)\n validateConstraints(constraints, memberNames)\n // P3:运动副构造期 fail-fast——parent/child ∈ members、child 唯一驱动、多 DOF 类型\n // 在 assembly() 构造时暴露(buildJoint/buildKinematicTree 复用同一份校验实现)\n if (joints.length > 0) buildKinematicTree(memberNames, joints)\n\n if (members.length > 0) keep(...members)\n const c = makeCompound(members)\n const behavior: AssemblyBehavior = {\n name: params.name as string | undefined,\n memberNames,\n constraints,\n joints,\n drive,\n memberColors: params.memberColors,\n solver: params.solver,\n solve: () => solveTransforms(members, behavior),\n solveDetailed: () =>\n solveAssemblyAndKinematics(\n members,\n behavior.memberNames,\n behavior.constraints,\n behavior.joints ?? [],\n behavior.drive,\n { solver: behavior.solver, name: behavior.name },\n ),\n }\n ensureSlot(c).behavior = behavior\n // solve / do_assemble 完全同义(方案 §5.5 D2:solve 为新名,do_assemble 保留为别名)\n const solveAndRegister = (): void => {\n // P6:只求解并登记待应用变换;应用与下游失效由引擎做(F2:库不查询/修改 DAG)\n // P3:约束 + 运动副在库侧一次合并(solveAssemblyAndKinematics),transforms 与\n // kinematics 一起登记(禁止引擎侧两次求解/两次登记)\n const result = behavior.solveDetailed()\n if (result.transforms.length > 0) setPendingAssemblyTransforms(c, result.transforms)\n if (result.kinematics) setPendingAssemblyKinematics(c, result.kinematics)\n }\n ;(c as CompoundShape & { do_assemble?: () => void }).do_assemble = solveAndRegister\n ;(c as CompoundShape & { solve?: () => void }).solve = solveAndRegister\n // 统一成员调用 ABI:add_constraint 是 no-op(现状语义:约束由 assembly 语句 args.constraints 读取,\n // 编译产物机械发射 `ctx.<asm>.add_constraint({...})`,调用此方法不崩)\n ;(c as CompoundShape & { add_constraint?: () => void }).add_constraint = () => {\n // Phase 1 semantics: constraints are read from the assembly statement's args.constraints;\n // add_constraint is intentionally a no-op (kept for ABI uniformity).\n }\n return c\n}\n"]}
1
+ {"version":3,"file":"compound.js","sourceRoot":"","sources":["../../src/api/compound.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * stdlib compound — group/assembly 库函数(compound Shape + AssemblyBehavior)\n *\n *\n * 从 src/ops/assemble.ts 迁出并改写为 stdlib 形态:\n * - `group(params)` → compound Shape(kind='compound',children 为成员 Shape 引用)\n * - `assembly(params)` → compound Shape + AssemblyBehavior(约束列表 + solve 方法)\n * - 装配求解(P1 起)委派 api/assembly/(brepjs solverAdapter 内核):\n * do_assemble/solve 触发求解 → 引擎应用\n * (mesh 顶点烘焙 + BREP 刚体变换 + 下游传播)。\n * P2-f5:旧装配算法与自有四元数实现已删除,求解全链路走 api/assembly。\n *\n * compound 自身无独立 mesh——几何由 children 承载,意义是结构(层级)。\n * do_assemble 编译为 `await ctx.<asm>.do_assemble()`:调用 compound 的求解方法,\n * 对约束定位的成员施加装配变换(mesh 顶点烘焙 + BREP 刚体变换 + 下游传播)。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { compound as makeCompound, ensureSlot, type CompoundShape } from '../shape'\nimport { keep, nameOf, setPendingAssemblyTransforms, setPendingAssemblyKinematics, type AssemblyTransform } from '../runtime-state'\nimport { solveAssemblyAndKinematics, type AssemblySolveResult } from './assembly/solve'\nimport { validateConstraints } from './assembly/validate'\nimport { buildKinematicTree, type JointSpec } from './assembly/joints'\nimport type { AssemblyConstraint } from './assembly/types'\nimport type { SolverStyle } from './assembly/solvers/types'\n\n// ── 参数类型(keep-syntax 设计 §2.5:成员保留由函数体 keep() 显式声明,不再靠类型标注) ──\n\n/** Parameters for the `group` stdlib function: an optional name and ordered members. */\nexport interface GroupParams {\n name?: string\n /** Compound members: read-only references, never mutated by group/assembly. */\n members?: Shape[]\n memberNames?: string[]\n}\n\n/** Parameters for the `assembly` stdlib function: group params plus assembly constraints. */\nexport interface AssemblyParams extends GroupParams {\n constraints?: AssemblyConstraint[]\n /** P3:运动副声明(可选;parent/child 必须是 members 里的名字)。 */\n joints?: JointSpec[]\n /** P3:驱动值覆盖(键 = child 成员名;值 = 主 DOF 数值或多 DOF 数组)。 */\n drive?: Record<string, number | number[]>\n /** cq-compat:成员颜色(sRGB 0..1),导出 STEP 时写入 XCAF。 */\n memberColors?: Record<string, [number, number, number]>\n /** P1:求解风格。'chain'(默认,vendored brepjs 解析链式)| 'global'(CadQuery 兼容全局最小二乘)。 */\n solver?: SolverStyle\n}\n\n// ── 约束类型(P1 起定义收口在 api/assembly/types,此处 re-export 保持既有导出面) ──\n\nexport type {\n AssemblyConstraint,\n FaceMateConstraint,\n FaceMateFace,\n EntityRef,\n FaceRef,\n EdgeRef,\n MateConstraint,\n AlignConstraint,\n CoincidentConstraint,\n ConcentricConstraint,\n DistanceConstraint,\n AngleConstraint,\n ParallelConstraint,\n PerpendicularConstraint,\n FixedConstraint,\n StructuralConstraint,\n AssemblyVec3,\n} from './assembly/types'\nexport type { AssemblySolveResult } from './assembly/solve'\n\n// ── 求解器 ──\n// P2-f5:旧装配算法与自有四元数实现已整体删除——旋转计算一律走\n// brepjs utils/quaternion.ts,输出经 api/assembly/pose.ts fromBrepjsQuat 重排。\n\n// 应用变换(mesh 顶点烘焙)下沉到引擎侧 src/mesh/rigid-transform.ts(E-b:\n// 引擎不得 import stdlib/compound;公共 API 经本 re-export 保持)。\nexport { applyTransform } from '../mesh/rigid-transform'\n\n// ── AssemblyBehavior ──\n\n/** Behavior attached to an assembly compound: its members, constraints, and solver. */\nexport interface AssemblyBehavior {\n name?: string\n memberNames: string[]\n constraints: AssemblyConstraint[]\n /** P3:运动副声明(无 joints 时为空数组)。 */\n joints?: JointSpec[]\n /** P3:驱动值覆盖(键 = child 成员名;缺省 undefined = 用 joint 存储值)。 */\n drive?: Record<string, number | number[]>\n /** cq-compat:成员颜色(sRGB 0..1)。 */\n memberColors?: Record<string, [number, number, number]>\n /** P1:求解风格。 */\n solver?: SolverStyle\n /** 只求解(P6):返回\"成员下标 → 变换\"列表。不改写入参、不传播;可重复调用(幂等)。 */\n solve(): AssemblyTransform[]\n /** 只求解并带诊断量(P1):transforms + dof/converged/unsupported(方案 P1⑤);P3 增 kinematics/warnings。 */\n solveDetailed(): AssemblySolveResult\n}\n\n/**\n * 纯求解(P6:求解 ≠ 传播):委派 api/assembly/solveAssembly(P1 起)。\n * 不修改任何输入、不触碰引擎状态——引擎负责应用变换并让下游失效重算(F2)。\n *\n * 约束形态(方案 §5):\n * - 遗留 face_mate:规范化为 mate 后降级为 brepjs concentric + 轴编码求解(§3.7.2);\n * - 新形态 mate/align/coincident/concentric/distance/angle/parallel/perpendicular/fixed;\n * - 面参数 `{ topoRef }` 执行期解析(BREP 现场/mesh 行快照),旧 `{ center, normal }`\n * 快照直接使用(兼容已持久化的历史脚本);\n * - 输出为 per-member 终态(L6 修复),锚定成员不输出变换。\n */\nfunction solveTransforms(members: Shape[], behavior: AssemblyBehavior): AssemblyTransform[] {\n return solveAssemblyAndKinematics(\n members,\n behavior.memberNames,\n behavior.constraints,\n behavior.joints ?? [],\n behavior.drive,\n { solver: behavior.solver, name: behavior.name },\n ).transforms\n}\n\n// ── group / assembly 库函数 ──\n\n/**\n * 成员名推导:显式 memberNames 兼容旧手工构造 IR;否则经 keep() 反查\n * (P3 起经 keep()/nameOfShapes 反查成员名——库不再访问执行上下文,F1)。\n */\nfunction memberNamesOf(params: { memberNames?: unknown }, members: Shape[]): string[] {\n if (Array.isArray(params.memberNames) && params.memberNames.length > 0) {\n return params.memberNames as string[]\n }\n return members.map((m) => {\n // 兼容字符串形态的 members(历史 IR 直传 partName):字符串本身就是名字\n if (typeof m === 'string') return m\n return String(nameOf(m) ?? '')\n })\n}\n\n/**\n * `cad.group({ name, members })` → compound Shape。\n * members 是成员 Shape(编译产物 ctx.<var> 引用),成员名经 keep() 反查。\n *\n * 函数体 keep 声明(keep-syntax 设计 §2.5):group 保留其成员且可见(R6)。\n */\n/**\n * 分组:零约束,保持当前布局。结构语句,无几何输出,成员用变量名引用。\n * @group 结构\n * @inputs 1\n * @async false\n * @qual ok\n * @name group\n * @deprecated **`../3d_editor` 消费面**(原 `@deprecated` 措辞已于 2026-09-22 校正):该 op 为编辑器应用提供(无几何输出,服务于编辑器画布与时间线),不属 faijs 平台面,但**不是废弃项**——它服务真实负载。**变更其 API 形态必须同步更新 `../3d_editor`**(见 `docs/plans/2026-09-22-topology-identity-development-plan.md` §2)。**平台侧需要几何复合体请用 `cad.compound`**(内核 `makeCompound`,持 OCCT 句柄,可变换/可导出)。\n * @returns CompoundShape 复合几何(kind='compound',children 为成员 Shape 引用)。\n * @param params.name - 组名。type:string\n * @param params.members - 成员(编译产物 ctx.<var> 引用;结构语句里是裸变量引用,非字符串数组)。type:Shape[]\n * @note members 在 .fai.js 里是裸变量引用(编译为 ctx.<var>),字符串数组形态的成员名经 keep() 反查兼容历史 IR。\n * @example\n * const part0 = cad.box(30, 20, 10, { centered: true })\n * cad.group({ name: '底板组', members: [part0] })\n */\nexport function group(params: GroupParams): CompoundShape {\n const members = (params.members as Shape[] | undefined) ?? []\n if (members.length > 0) keep(...members)\n const memberNames = memberNamesOf(params, members)\n const c = makeCompound(members)\n // 挂最小 behavior(memberNames 供 ExecutionResult.compounds 结构输出;group 无约束)\n ensureSlot(c).behavior = {\n memberNames,\n constraints: [],\n joints: [],\n solve: () => [],\n solveDetailed: () => ({ transforms: [], dof: 0, converged: true, unsupported: [] }),\n }\n return c\n}\n\n/**\n * 装配:成员 + 约束。结构语句,无几何输出,成员用变量名引用、实体用 EntityRef / 拓扑引用。\n * 求解内核复用 vendored brepjs solverAdapter.solveConstraints(链式拓扑调度 / DOF / converged /\n * unsupported 诊断);输出为 per-member 终态变换(每成员一条,恒等位姿不输出)。\n * @group 结构\n * @inputs 1\n * @async false\n * @qual warn\n * @name assembly\n * @deprecated **`../3d_editor` 消费面**(原 `@deprecated` 措辞已于 2026-09-22 校正):该 op 为编辑器应用提供(成员以编辑器结构语句形态声明,服务于画布与时间线),不属 faijs 平台面,但**不是废弃项**——它服务真实负载。**变更其 API 形态必须同步更新 `../3d_editor`**(见 `docs/plans/2026-09-22-topology-identity-development-plan.md` §2)。faijs 平台面不提供等价 op(需要时须按平台需求另行设计,不得直接搬用本 op)。\n * @returns CompoundShape + AssemblyBehavior(含 do_assemble / solve 方法)。\n * @note 约束类型(a=参考、b=从动,移动 b 去贴合 a):`mate` 面对面贴合(法向反向+面中心重合,遗留 face_mate 的新名,求解降级为 concentric + 轴编码);`align` 同向对齐(法向同向+面中心重合);`coincident` 共面/共点/共线(保留面内 2 个平移 DOF);`concentric` 轴重合(孔轴配合,圆柱/圆锥面需 hint.axis,直边/圆边需 EdgeHint.axis);`distance` 定距(mm,带 value);`angle` 夹角(deg,带 value);`parallel`/`perpendicular` 平行/垂直(angle 0°/90° 语法糖);`fixed` 锚定部件(地基);`face_mate` 为遗留别名(规范化为 mate,新代码不再使用)。\n * @note EntityRef 四种形态:`{ part, face: { topoRef } | { surfaceType?, center, normal } }`、`{ part, edge: { topoRef } | { axis: { origin, direction } } }`、`{ part, point: [x,y,z] }`、`{ part, faceIndex }`(1 起,仅调试简写)。\n * @note 不收敛(实体类型不匹配/环/参考不可达)→ 抛错并带 unsupported 明细;成员名为空串 → 求解前抛错;mesh 快照缺 axis 的圆柱/圆锥面作轴实体 → E_TOPO_NOT_FOUND(绝不静默降级)。`mate`(中心重合)与 `coincident`(只共面)是两种不同语义,不互相映射。\n * @note 早期文档/示例曾用 `fixedPartId`/`movingPartId`/`faceRowIndex`/`faceId`/`invalid`——这些键在代码中不存在。真实契约是 `fixedPartName`/`movingPartName` + `fixedFace`/`movingFace`(遗留 face_mate)。`faceId` 字段随 §6.2 移除,不再写入。\n * @param params.name - 装配名。type:string\n * @param params.members - 成员(裸变量引用)。type:Shape[]\n * @param params.constraints - 约束数组(遗留 face_mate 形态或上述新形态 { type, a, b })。type:AssemblyConstraint[]\n * @example\n * let asm1 = cad.assembly({ name: '主轴组件', members: [part0, part1, part2], constraints: [ { type: 'fixed', part: 'part0' }, { type: 'mate', a: { part: 'part0', face: { topoRef: { kind: 'face', origin: 'part0', role: 'box:top', hint: { kind: 'face', surfaceType: 'plane' } } } }, b: { part: 'part1', face: { topoRef: { kind: 'face', origin: 'part1', role: 'box:bottom', hint: { kind: 'face', surfaceType: 'plane' } } } } }, { type: 'concentric', a: { part: 'part1', face: { topoRef: { kind: 'face', origin: 'part1', role: '', hint: { kind: 'face', surfaceType: 'cylinder' } } } }, b: { part: 'part2', face: { topoRef: { kind: 'face', origin: 'part2', role: 'cylinder:lateral', hint: { kind: 'face', surfaceType: 'cylinder' } } } } } ] })\n * asm1.solve()\n */\nexport function assembly(params: AssemblyParams): CompoundShape {\n const members = (params.members as Shape[] | undefined) ?? []\n const constraints = (params.constraints as AssemblyConstraint[] | undefined) ?? []\n const joints = (params.joints as JointSpec[] | undefined) ?? []\n const drive = params.drive as Record<string, number | number[]> | undefined\n\n // P2-f1:约束参数运行期校验(keep() 之前,fail-fast;规则见 api/assembly/validate.ts V1–V6)\n const memberNames = memberNamesOf(params, members)\n validateConstraints(constraints, memberNames)\n // P3:运动副构造期 fail-fast——parent/child ∈ members、child 唯一驱动、多 DOF 类型\n // 在 assembly() 构造时暴露(buildJoint/buildKinematicTree 复用同一份校验实现)\n if (joints.length > 0) buildKinematicTree(memberNames, joints)\n\n if (members.length > 0) keep(...members)\n const c = makeCompound(members)\n const behavior: AssemblyBehavior = {\n name: params.name as string | undefined,\n memberNames,\n constraints,\n joints,\n drive,\n memberColors: params.memberColors,\n solver: params.solver,\n solve: () => solveTransforms(members, behavior),\n solveDetailed: () =>\n solveAssemblyAndKinematics(\n members,\n behavior.memberNames,\n behavior.constraints,\n behavior.joints ?? [],\n behavior.drive,\n { solver: behavior.solver, name: behavior.name },\n ),\n }\n ensureSlot(c).behavior = behavior\n // solve / do_assemble 完全同义(方案 §5.5 D2:solve 为新名,do_assemble 保留为别名)\n const solveAndRegister = (): void => {\n // P6:只求解并登记待应用变换;应用与下游失效由引擎做(F2:库不查询/修改 DAG)\n // P3:约束 + 运动副在库侧一次合并(solveAssemblyAndKinematics),transforms 与\n // kinematics 一起登记(禁止引擎侧两次求解/两次登记)\n const result = behavior.solveDetailed()\n if (result.transforms.length > 0) setPendingAssemblyTransforms(c, result.transforms)\n if (result.kinematics) setPendingAssemblyKinematics(c, result.kinematics)\n }\n ;(c as CompoundShape & { do_assemble?: () => void }).do_assemble = solveAndRegister\n ;(c as CompoundShape & { solve?: () => void }).solve = solveAndRegister\n // 统一成员调用 ABI:add_constraint 是 no-op(现状语义:约束由 assembly 语句 args.constraints 读取,\n // 编译产物机械发射 `ctx.<asm>.add_constraint({...})`,调用此方法不崩)\n ;(c as CompoundShape & { add_constraint?: () => void }).add_constraint = () => {\n // Phase 1 semantics: constraints are read from the assembly statement's args.constraints;\n // add_constraint is intentionally a no-op (kept for ABI uniformity).\n }\n return c\n}\n"]}
@@ -28,6 +28,7 @@ import type { Shape } from '../mesh/types.js';
28
28
  * @async false
29
29
  * @qual ok
30
30
  * @name copy
31
+ * @deprecated **`../3d_editor` 消费面**(原 `@deprecated` 措辞已于 2026-09-22 校正):该 op 为编辑器应用提供(语义含编辑器画布显示——源与副本各显示一份),不属 faijs 平台面,但**不是废弃项**——它服务真实负载。**变更其 API 形态必须同步更新 `../3d_editor`**(见 `docs/plans/2026-09-22-topology-identity-development-plan.md` §2)。faijs 平台面不提供等价 op(需要时须按平台需求另行设计,不得直接搬用本 op)。
31
32
  * @param input - 源几何。type:Shape required:true
32
33
  * @returns Shape 源几何的深拷贝。copy 不消费其源(画布显示 box 和副本两份),改副本不影响源。
33
34
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../src/api/copy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAmC1C;;;;;;;;GAQG;AACH;;;;;;;;;;;IAWI;AACJ,eAAO,MAAM,IAAI;;CAef,CAAA"}
1
+ {"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../src/api/copy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAoC1C;;;;;;;;GAQG;AACH;;;;;;;;;;;;IAYI;AACJ,eAAO,MAAM,IAAI;;CAgBf,CAAA"}
package/dist/api/copy.js CHANGED
@@ -14,7 +14,7 @@
14
14
  import { solidToShape } from '../brep/brep-ops.js';
15
15
  import { identityEvolution, identityHashEvolution } from '../brep/face-evolution.js';
16
16
  import { getBackends, keep } from '../runtime-state.js';
17
- import { fromBrep, brepOf, getSlot } from '../shape.js';
17
+ import { fromBrep, brepOf, inputRoleTable } from '../shape.js';
18
18
  import { propagateAllOrigins } from '../topology/naming/roles.js';
19
19
  import { defineOp } from '../sdk.js';
20
20
  /** BREP 路径:kernel.copy 深拷贝实体 + 恒等面演化 + 恒等 roleTable 传播 + fromBrep 一次登记。 */
@@ -27,7 +27,7 @@ function copyBrep(input) {
27
27
  throw new Error('[stdlib/copy] input is not BREP');
28
28
  const copiedSolid = kernel.copy(inputSolid);
29
29
  // §2.4/§3.3:copy 面 1:1 保留——hash 恒等传播 roleTable(所有 origin)
30
- const inputTable = getSlot(input)?.roleTable;
30
+ const inputTable = inputRoleTable(input);
31
31
  let roleTable;
32
32
  if (inputTable && inputTable.size > 0) {
33
33
  roleTable = propagateAllOrigins(inputTable, identityHashEvolution(kernel, inputSolid, copiedSolid));
@@ -55,6 +55,7 @@ function copyBrep(input) {
55
55
  * @async false
56
56
  * @qual ok
57
57
  * @name copy
58
+ * @deprecated **`../3d_editor` 消费面**(原 `@deprecated` 措辞已于 2026-09-22 校正):该 op 为编辑器应用提供(语义含编辑器画布显示——源与副本各显示一份),不属 faijs 平台面,但**不是废弃项**——它服务真实负载。**变更其 API 形态必须同步更新 `../3d_editor`**(见 `docs/plans/2026-09-22-topology-identity-development-plan.md` §2)。faijs 平台面不提供等价 op(需要时须按平台需求另行设计,不得直接搬用本 op)。
58
59
  * @param input - 源几何。type:Shape required:true
59
60
  * @returns Shape 源几何的深拷贝。copy 不消费其源(画布显示 box 和副本两份),改副本不影响源。
60
61
  * @example
@@ -77,5 +78,6 @@ export const copy = defineOp({
77
78
  keep(input);
78
79
  return copyBrep(input);
79
80
  },
81
+ naming: { kind: 'identity' },
80
82
  });
81
83
  //# sourceMappingURL=copy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"copy.js","sourceRoot":"","sources":["../../src/api/copy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACjF,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAE9D,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAIjC,2EAA2E;AAC3E,SAAS,QAAQ,CAAC,KAAY;IAC5B,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC,MAAM,CAAC,IAA4B,CAAA;IAChE,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;IAC5D,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAA2B,CAAA;IAC1D,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IAEnE,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAE3C,0DAA0D;IAC1D,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,SAAkC,CAAA;IACrE,IAAI,SAAgC,CAAA;IACpC,IAAI,UAAU,IAAI,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACtC,SAAS,GAAG,mBAAmB,CAAC,UAAU,EAAE,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAAA;IACrG,CAAC;IAED,OAAO,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE;QACjD,KAAK,EAAE,WAAW;QAClB,0BAA0B;QAC1B,aAAa,EAAE,iBAAiB,CAAC,MAAM,EAAE,WAAW,CAAC;QACrD,SAAS;KACV,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH;;;;;;;;;;;IAWI;AACJ,MAAM,CAAC,MAAM,IAAI,GAAG,QAAQ,CAAC;IAC3B,IAAI,EAAE,CAAC,KAAY,EAAE,EAAE;QACrB,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;QAC9D,IAAI,CAAC,KAAK,CAAC,CAAA;QACX,oCAAoC;QACpC,OAAO;YACL,SAAS,EAAE,IAAI,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC;YAC5C,OAAO,EAAE,IAAI,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC;SACxC,CAAA;IACH,CAAC;IACD,IAAI,EAAE,CAAC,KAAY,EAAE,EAAE;QACrB,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;QAC9D,IAAI,CAAC,KAAK,CAAC,CAAA;QACX,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAA;IACxB,CAAC;CACF,CAAC,CAAA","sourcesContent":["/**\n * stdlib copy — 深拷贝几何(方案 B:独立新对象,源不变)\n *\n *\n * copy 是\"共享读取\"(克隆出新对象,源不变),与 drill/transform 的\"独占改写\"本质不同:\n * - **copy 不消费其源**(从消费方排除,与 group/assembly 同级)\n * - copy 输出是独立新对象 → 归\"新名\"类(allocate-id.ts 不保名)\n * - **源显示**(part0=box; part1=copy(part0) → 画布显示 box 和副本两份)\n *\n * 双链路:\n * - mesh 路径:深拷贝 positions/indices 到新数组\n * - BREP 路径:kernel.copy(inputSolid) → solidToShape → fromBrep 登记\n */\n\nimport type { Shape } from '../mesh/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { identityEvolution, identityHashEvolution } from '../brep/face-evolution'\nimport { getBackends, keep } from '../runtime-state'\nimport { fromBrep, brepOf, getSlot } from '../shape'\nimport { propagateAllOrigins } from '../topology/naming/roles'\nimport type { RoleTable } from '../topology/naming/types'\nimport { defineOp } from '../sdk'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\n\n/** BREP 路径:kernel.copy 深拷贝实体 + 恒等面演化 + 恒等 roleTable 传播 + fromBrep 一次登记。 */\nfunction copyBrep(input: Shape): Shape {\n const kernel = getBackends().kernel.brep as BrepEngineApi | null\n if (!kernel) throw new Error('[stdlib/copy] no OCCT kernel')\n const inputSolid = brepOf(input) as BrepHandle | undefined\n if (!inputSolid) throw new Error('[stdlib/copy] input is not BREP')\n\n const copiedSolid = kernel.copy(inputSolid)\n\n // §2.4/§3.3:copy 面 1:1 保留——hash 恒等传播 roleTable(所有 origin)\n const inputTable = getSlot(input)?.roleTable as RoleTable | undefined\n let roleTable: RoleTable | undefined\n if (inputTable && inputTable.size > 0) {\n roleTable = propagateAllOrigins(inputTable, identityHashEvolution(kernel, inputSolid, copiedSolid))\n }\n\n return fromBrep(solidToShape(kernel, copiedSolid), {\n solid: copiedSolid,\n // copy 不改变拓扑,面 ordinal 不变\n faceEvolution: identityEvolution(kernel, copiedSolid),\n roleTable,\n })\n}\n\n/**\n * `cad.copy(input)` → 深拷贝 Shape。\n *\n * 函数体 keep 声明(keep-syntax 设计 §2.5):copy 保留其源(可见)——\n * keep(input) 使源变量保持终端(画布显示 box 和副本两份)。\n *\n * mesh 路径:positions/indices 复制到新数组(改副本不影响源)。\n * BREP 路径:kernel.copy 产出独立 ShapeHandle。\n */\n/**\n * 深拷贝几何为独立新对象(源不变,源与副本都显示)。\n * @group 特征\n * @inputs 1\n * @async false\n * @qual ok\n * @name copy\n * @param input - 源几何。type:Shape required:true\n * @returns Shape 源几何的深拷贝。copy 不消费其源(画布显示 box 和副本两份),改副本不影响源。\n * @example\n * const part1 = cad.copy(part0)\n */\nexport const copy = defineOp({\n mesh: (input: Shape) => {\n if (!input) throw new Error('[stdlib/copy] no input geometry')\n keep(input)\n // mesh 路径:深拷贝到新 TypedArray(改副本不影响源)\n return {\n positions: new Float32Array(input.positions),\n indices: new Uint32Array(input.indices),\n }\n },\n brep: (input: Shape) => {\n if (!input) throw new Error('[stdlib/copy] no input geometry')\n keep(input)\n return copyBrep(input)\n },\n})\n"]}
1
+ {"version":3,"file":"copy.js","sourceRoot":"","sources":["../../src/api/copy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACjF,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAG9D,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAIjC,2EAA2E;AAC3E,SAAS,QAAQ,CAAC,KAAY;IAC5B,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC,MAAM,CAAC,IAA4B,CAAA;IAChE,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;IAC5D,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAA2B,CAAA;IAC1D,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IAEnE,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAE3C,0DAA0D;IAC1D,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAA0B,CAAA;IACjE,IAAI,SAAgC,CAAA;IACpC,IAAI,UAAU,IAAI,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACtC,SAAS,GAAG,mBAAmB,CAAC,UAAU,EAAE,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAAA;IACrG,CAAC;IAED,OAAO,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE;QACjD,KAAK,EAAE,WAAW;QAClB,0BAA0B;QAC1B,aAAa,EAAE,iBAAiB,CAAC,MAAM,EAAE,WAAW,CAAC;QACrD,SAAS;KACV,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH;;;;;;;;;;;;IAYI;AACJ,MAAM,CAAC,MAAM,IAAI,GAAG,QAAQ,CAAC;IAC3B,IAAI,EAAE,CAAC,KAAY,EAAE,EAAE;QACrB,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;QAC9D,IAAI,CAAC,KAAK,CAAC,CAAA;QACX,oCAAoC;QACpC,OAAO;YACL,SAAS,EAAE,IAAI,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC;YAC5C,OAAO,EAAE,IAAI,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC;SACxC,CAAA;IACH,CAAC;IACD,IAAI,EAAE,CAAC,KAAY,EAAE,EAAE;QACrB,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;QAC9D,IAAI,CAAC,KAAK,CAAC,CAAA;QACX,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAA;IACxB,CAAC;IACD,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAgB;CAC3C,CAAC,CAAA","sourcesContent":["/**\n * stdlib copy — 深拷贝几何(方案 B:独立新对象,源不变)\n *\n *\n * copy 是\"共享读取\"(克隆出新对象,源不变),与 drill/transform 的\"独占改写\"本质不同:\n * - **copy 不消费其源**(从消费方排除,与 group/assembly 同级)\n * - copy 输出是独立新对象 → 归\"新名\"类(allocate-id.ts 不保名)\n * - **源显示**(part0=box; part1=copy(part0) → 画布显示 box 和副本两份)\n *\n * 双链路:\n * - mesh 路径:深拷贝 positions/indices 到新数组\n * - BREP 路径:kernel.copy(inputSolid) → solidToShape → fromBrep 登记\n */\n\nimport type { Shape } from '../mesh/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { identityEvolution, identityHashEvolution } from '../brep/face-evolution'\nimport { getBackends, keep } from '../runtime-state'\nimport { fromBrep, brepOf, inputRoleTable } from '../shape'\nimport { propagateAllOrigins } from '../topology/naming/roles'\nimport type { RoleTable } from '../topology/naming/types'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { defineOp } from '../sdk'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\n\n/** BREP 路径:kernel.copy 深拷贝实体 + 恒等面演化 + 恒等 roleTable 传播 + fromBrep 一次登记。 */\nfunction copyBrep(input: Shape): Shape {\n const kernel = getBackends().kernel.brep as BrepEngineApi | null\n if (!kernel) throw new Error('[stdlib/copy] no OCCT kernel')\n const inputSolid = brepOf(input) as BrepHandle | undefined\n if (!inputSolid) throw new Error('[stdlib/copy] input is not BREP')\n\n const copiedSolid = kernel.copy(inputSolid)\n\n // §2.4/§3.3:copy 面 1:1 保留——hash 恒等传播 roleTable(所有 origin)\n const inputTable = inputRoleTable(input) as RoleTable | undefined\n let roleTable: RoleTable | undefined\n if (inputTable && inputTable.size > 0) {\n roleTable = propagateAllOrigins(inputTable, identityHashEvolution(kernel, inputSolid, copiedSolid))\n }\n\n return fromBrep(solidToShape(kernel, copiedSolid), {\n solid: copiedSolid,\n // copy 不改变拓扑,面 ordinal 不变\n faceEvolution: identityEvolution(kernel, copiedSolid),\n roleTable,\n })\n}\n\n/**\n * `cad.copy(input)` → 深拷贝 Shape。\n *\n * 函数体 keep 声明(keep-syntax 设计 §2.5):copy 保留其源(可见)——\n * keep(input) 使源变量保持终端(画布显示 box 和副本两份)。\n *\n * mesh 路径:positions/indices 复制到新数组(改副本不影响源)。\n * BREP 路径:kernel.copy 产出独立 ShapeHandle。\n */\n/**\n * 深拷贝几何为独立新对象(源不变,源与副本都显示)。\n * @group 特征\n * @inputs 1\n * @async false\n * @qual ok\n * @name copy\n * @deprecated **`../3d_editor` 消费面**(原 `@deprecated` 措辞已于 2026-09-22 校正):该 op 为编辑器应用提供(语义含编辑器画布显示——源与副本各显示一份),不属 faijs 平台面,但**不是废弃项**——它服务真实负载。**变更其 API 形态必须同步更新 `../3d_editor`**(见 `docs/plans/2026-09-22-topology-identity-development-plan.md` §2)。faijs 平台面不提供等价 op(需要时须按平台需求另行设计,不得直接搬用本 op)。\n * @param input - 源几何。type:Shape required:true\n * @returns Shape 源几何的深拷贝。copy 不消费其源(画布显示 box 和副本两份),改副本不影响源。\n * @example\n * const part1 = cad.copy(part0)\n */\nexport const copy = defineOp({\n mesh: (input: Shape) => {\n if (!input) throw new Error('[stdlib/copy] no input geometry')\n keep(input)\n // mesh 路径:深拷贝到新 TypedArray(改副本不影响源)\n return {\n positions: new Float32Array(input.positions),\n indices: new Uint32Array(input.indices),\n }\n },\n brep: (input: Shape) => {\n if (!input) throw new Error('[stdlib/copy] no input geometry')\n keep(input)\n return copyBrep(input)\n },\n naming: { kind: 'identity' } as Provenance,\n})\n"]}
@@ -9,8 +9,9 @@
9
9
  *
10
10
  * 序号语义(GOTCHA):faijs 的 `getSubShapes(solid,'edge')` 与 `wireframe()` 同用
11
11
  * `TopExp::MapShapes` + `NCollection_IndexedMap`(`occt-kernel/topologyExt.ts` 已
12
- * 记档),故第 N 条边 == FreeCAD 的 `EdgeN`(`fcstd/external-geo.test.ts` 实测
13
- * `wireframe.edgeGroups[k] == FreeCAD "Edge(k+1)"`)。这是 FCStd 移植选边的锚点。
12
+ * 记档),故第 N 条边 == FreeCAD 的 `EdgeN`(fcstd-port/test/FreeCAD 的
13
+ * external-geo corpus 测试实测 `wireframe.edgeGroups[k] == FreeCAD "Edge(k+1)"`;
14
+ * 2026-09-20 随语料依赖测试迁至 fcstd-port)。这是 FCStd 移植选边的锚点。
14
15
  *
15
16
  * 与 `faceNormal`(`api/geom.ts`)的差异:`faceNormal` 的 `ordinal` 是 0 起
16
17
  * (直接下标 `faces[ordinal]`),而本函数是 1 起——与命名层 `TopoRef` 序号
@@ -1 +1 @@
1
- {"version":3,"file":"edge-ref.d.ts","sourceRoot":"","sources":["../../src/api/edge-ref.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;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,CAsDnE"}
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,CA2DnE"}
@@ -9,8 +9,9 @@
9
9
  *
10
10
  * 序号语义(GOTCHA):faijs 的 `getSubShapes(solid,'edge')` 与 `wireframe()` 同用
11
11
  * `TopExp::MapShapes` + `NCollection_IndexedMap`(`occt-kernel/topologyExt.ts` 已
12
- * 记档),故第 N 条边 == FreeCAD 的 `EdgeN`(`fcstd/external-geo.test.ts` 实测
13
- * `wireframe.edgeGroups[k] == FreeCAD "Edge(k+1)"`)。这是 FCStd 移植选边的锚点。
12
+ * 记档),故第 N 条边 == FreeCAD 的 `EdgeN`(fcstd-port/test/FreeCAD 的
13
+ * external-geo corpus 测试实测 `wireframe.edgeGroups[k] == FreeCAD "Edge(k+1)"`;
14
+ * 2026-09-20 随语料依赖测试迁至 fcstd-port)。这是 FCStd 移植选边的锚点。
14
15
  *
15
16
  * 与 `faceNormal`(`api/geom.ts`)的差异:`faceNormal` 的 `ordinal` 是 0 起
16
17
  * (直接下标 `faces[ordinal]`),而本函数是 1 起——与命名层 `TopoRef` 序号
@@ -45,10 +46,13 @@ export function edgeRef(of, edgeOrdinal) {
45
46
  throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', `edgeRef: edgeOrdinal must be an integer >= 1 (got ${edgeOrdinal})`);
46
47
  }
47
48
  const kernel = getBackends().kernel.brep;
48
- if (!kernel)
49
- throw new Error('[edgeRef] no BREP kernel (edge references are BREP-only)');
50
- if (!brepOf(of))
51
- throw new Error('[edgeRef] E_EDGE_REF_NO_BREP: input shape has no BREP solid');
49
+ // Phase 1.9(D6/§3):mesh 路径不支持拓扑引用——静态判定、显式抛错,不静默降级
50
+ if (!kernel) {
51
+ throw new TopoRefError('E_TOPO_MESH_UNSUPPORTED', 'edge', 'edgeRef: topology references are BREP-only (mesh path unsupported)');
52
+ }
53
+ if (!brepOf(of)) {
54
+ throw new TopoRefError('E_TOPO_MESH_UNSUPPORTED', 'edge', 'edgeRef: input shape has no BREP solid (mesh shapes do not carry topology identity)');
55
+ }
52
56
  const ctx = buildEdgeResolutionContext(kernel, of);
53
57
  if (!ctx)
54
58
  throw new TopoRefError('E_TOPO_NOT_FOUND', 'edge', 'edgeRef: input has no BREP naming context');
@@ -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/external-geo.test.ts` 实测\n * `wireframe.edgeGroups[k] == FreeCAD \"Edge(k+1)\"`)。这是 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 { getBackends } from '../runtime-state'\nimport { brepOf } from '../shape'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\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 = getBackends().kernel.brep as BrepEngineApi | null\n if (!kernel) throw new Error('[edgeRef] no BREP kernel (edge references are BREP-only)')\n if (!brepOf(of)) throw new Error('[edgeRef] E_EDGE_REF_NO_BREP: input shape has no BREP solid')\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 * 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 { getBackends } from '../runtime-state'\nimport { brepOf } from '../shape'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\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 = getBackends().kernel.brep as BrepEngineApi | null\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 +1 @@
1
- {"version":3,"file":"engrave.d.ts","sourceRoot":"","sources":["../../src/api/engrave.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAQ,MAAM,eAAe,CAAA;AAmBhD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CASzE;AAsID;;;;;;;;;;;;;;;;;;;;IAoBI;AACJ,eAAO,MAAM,OAAO;;CA6BlB,CAAA"}
1
+ {"version":3,"file":"engrave.d.ts","sourceRoot":"","sources":["../../src/api/engrave.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAQ,MAAM,eAAe,CAAA;AAoBhD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CASzE;AAsID;;;;;;;;;;;;;;;;;;;;IAoBI;AACJ,eAAO,MAAM,OAAO;;CA8BlB,CAAA"}
@@ -211,5 +211,6 @@ export const engrave = defineOp({
211
211
  const svgText = await resolveEngraveSvg(params);
212
212
  return engraveBrepPath(input, params, svgText);
213
213
  },
214
+ naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } },
214
215
  });
215
216
  //# sourceMappingURL=engrave.js.map
@@ -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 { fromBrep, brepOf } from '../shape'\nimport { defineOp } from '../sdk'\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 = getBackends().kernel.brep as BrepEngineApi | null\n if (!kernel) throw new Error('[stdlib/engrave] no OCCT kernel')\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})\n"]}
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 { 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 = getBackends().kernel.brep as BrepEngineApi | null\n if (!kernel) throw new Error('[stdlib/engrave] no OCCT kernel')\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 +1 @@
1
- {"version":3,"file":"extrude.d.ts","sourceRoot":"","sources":["../../src/api/extrude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAUH,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AAGhD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAGrD,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;;CAsBlB,CAAA"}
1
+ {"version":3,"file":"extrude.d.ts","sourceRoot":"","sources":["../../src/api/extrude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAYH,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AAGhD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAsGrD,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;;CAwClB,CAAA"}
@@ -26,11 +26,121 @@ import { extrude as projectedExtrude } from './generated/operations.js';
26
26
  import * as THREE from 'three';
27
27
  import { solidToShape, matrixToArray } from '../brep/brep-ops.js';
28
28
  import { getSolidBoundingBox } from '../brep/brep-utils.js';
29
- import { getBackends } from '../runtime-state.js';
29
+ import { getBackends, getCurrentStmt } from '../runtime-state.js';
30
30
  import { fromBrep, brepOf } from '../shape.js';
31
+ import { formatRoleName, semantic, wall } from '../topology/naming/role-name.js';
31
32
  import { defineOp } from '../sdk.js';
32
33
  import { assertPositiveNumber } from './assert.js';
33
34
  import { TopoRefError } from '../topology/naming/index.js';
35
+ /**
36
+
37
+ * extrude 的 construct 词汇表(计划 §4.4):`cap:bottom` / `cap:top` / `wall:<i>`。
38
+ *
39
+ * 判定口径:
40
+ * - 拉伸方向取自一对平面端面法向的**带符号差**(两法向指向相反)——不依赖脚本
41
+ * 怎么写方向,现场几何是唯一真值;
42
+ * - 面法向与拉伸轴 |cos| ≈ 1 → 端面:中心沿轴分量小者 `cap:bottom`、大者 `cap:top`;
43
+ * - 面法向与拉伸轴 |cos| ≈ 0 → 侧面 `wall:<i>`,i = 该面在侧面枚举中的相对序
44
+ * (OCCT prism 的侧面顺序 = profile wire 的边序——makeWire 按构造顺序收边,
45
+ * prism 不重排;G3-L1 改参重放依赖该稳定性);
46
+ * - 非平面/无法向的面不进表:缺身份是显式状态(naming 行 role=null),不伪造。
47
+ *
48
+ * @param kernel - the OCCT kernel.
49
+ * @param solid - the extruded solid.
50
+ * @returns role(线格式串)→ hash 子表。
51
+ */
52
+ function extrudeConstructRoles(kernel, solid) {
53
+ const roles = new Map();
54
+ const faceHandles = kernel.getSubShapes(solid, 'face');
55
+ try {
56
+ const hashes = kernel.subShapeHashes(solid, 'face', 2147483647);
57
+ // 每面的法向(仅平面;侧面可能是圆柱/其它——wall 只挂平面侧面的前提是
58
+ // 直拉伸,斜面/圆柱侧面留待 3.1 的完整枚举器)
59
+ const normals = faceHandles.map((f) => {
60
+ if (kernel.surfaceType(f) !== 'plane')
61
+ return undefined;
62
+ const uv = kernel.uvBounds(f);
63
+ const n = kernel.surfaceNormal(f, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2);
64
+ return [n.x, n.y, n.z];
65
+ });
66
+ const centers = faceHandles.map((f) => {
67
+ const c = kernel.getSurfaceCenterOfMass(f);
68
+ return [c.x, c.y, c.z];
69
+ });
70
+ // 拉伸轴:找一对 |cos| ≈ 1 的反平行平面法向 → 带符号单位方向
71
+ let axis;
72
+ for (let i = 0; i < normals.length && !axis; i++) {
73
+ const a = normals[i];
74
+ if (!a)
75
+ continue;
76
+ for (let j = i + 1; j < normals.length; j++) {
77
+ const b = normals[j];
78
+ if (!b)
79
+ continue;
80
+ const lenA = Math.hypot(a[0], a[1], a[2]);
81
+ const lenB = Math.hypot(b[0], b[1], b[2]);
82
+ if (lenA < 1e-9 || lenB < 1e-9)
83
+ continue;
84
+ const cos = (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]) / (lenA * lenB);
85
+ if (Math.abs(cos) > 0.999) {
86
+ // b 反向即「从 i 面指向 j 面」的方向
87
+ axis = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
88
+ break;
89
+ }
90
+ }
91
+ }
92
+ const axisLen = axis ? Math.hypot(axis[0], axis[1], axis[2]) : 0;
93
+ if (axis && axisLen > 1e-9) {
94
+ const ax = [axis[0] / axisLen, axis[1] / axisLen, axis[2] / axisLen];
95
+ // 端面:沿轴投影最小者 = cap:bottom,最大者 = cap:top
96
+ const capCandidates = [];
97
+ for (let i = 0; i < normals.length; i++) {
98
+ const n = normals[i];
99
+ if (!n)
100
+ continue;
101
+ const len = Math.hypot(n[0], n[1], n[2]) || 1;
102
+ const cos = Math.abs(n[0] * ax[0] + n[1] * ax[1] + n[2] * ax[2]) / len;
103
+ if (cos > 0.999) {
104
+ capCandidates.push({ idx: i, t: centers[i][0] * ax[0] + centers[i][1] * ax[1] + centers[i][2] * ax[2] });
105
+ }
106
+ }
107
+ if (capCandidates.length >= 2) {
108
+ capCandidates.sort((p, q) => p.t - q.t);
109
+ const bottom = capCandidates[0];
110
+ const top = capCandidates[capCandidates.length - 1];
111
+ // 端面词汇用 semantic('bottom'/'top'——与 box 同形)。计划 §4.4 写的
112
+ // `cap:<name>` 前缀形态与 RoleName 契约冲突(semantic 名不允许 ':',
113
+ // role-name.ts SEMANTIC_NAME_RE),落地以契约为准:semantic 直名。
114
+ if (hashes[bottom.idx] !== undefined)
115
+ roles.set(formatRoleName(semantic('bottom')), [hashes[bottom.idx]]);
116
+ if (hashes[top.idx] !== undefined)
117
+ roles.set(formatRoleName(semantic('top')), [hashes[top.idx]]);
118
+ }
119
+ // 侧面:|cos| ≈ 0,按枚举序编号(= profile 边序)
120
+ let wallIdx = 0;
121
+ for (let i = 0; i < normals.length; i++) {
122
+ const n = normals[i];
123
+ if (!n || hashes[i] === undefined)
124
+ continue;
125
+ const len = Math.hypot(n[0], n[1], n[2]) || 1;
126
+ const cos = Math.abs(n[0] * ax[0] + n[1] * ax[1] + n[2] * ax[2]) / len;
127
+ if (cos < 0.001) {
128
+ roles.set(formatRoleName(wall(wallIdx)), [hashes[i]]);
129
+ wallIdx++;
130
+ }
131
+ }
132
+ }
133
+ return roles;
134
+ }
135
+ finally {
136
+ for (const h of faceHandles) {
137
+ try {
138
+ kernel.release(h);
139
+ }
140
+ catch { /* 已释放 */ }
141
+ }
142
+ }
143
+ }
34
144
  /** 判定是否为朴素对象(对象形态判别器,避免误吞 Shape / 数组)。 */
35
145
  function isPlainObject(v) {
36
146
  return v !== null && typeof v === 'object' && !Array.isArray(v) && Object.getPrototypeOf(v) === Object.prototype;
@@ -287,13 +397,31 @@ export const extrude = defineOp({
287
397
  if (!inputSolid)
288
398
  throw new Error('[stdlib/extrude] input is not BREP');
289
399
  const clipped = extrudeUpToSolid(kernel, inputSolid, o);
290
- return fromBrep(solidToShape(kernel, clipped), { solid: clipped });
400
+ // 3.2: inlined registerExtrudeRoles — origin = StmtId, roles from construct enumerator
401
+ const origin = String(getCurrentStmt()?.id ?? '');
402
+ return fromBrep(solidToShape(kernel, clipped), {
403
+ solid: clipped,
404
+ roleTable: new Map([[origin, extrudeConstructRoles(kernel, clipped)]]),
405
+ });
291
406
  }
292
407
  // 长度形态:委托生成投影(生成投影自带借入 / Result 翻转 / 收养)
293
408
  const normal = new THREE.Vector3(...(o.normal ?? [0, 0, 1])).normalize();
294
409
  const sign = o.mode === 'backward' ? -1 : 1;
295
410
  const v = [normal.x * o.length * sign, normal.y * o.length * sign, normal.z * o.length * sign];
296
- return (await projectedExtrude(input, v));
411
+ const result = (await projectedExtrude(input, v));
412
+ // E3 后续:委托路径同样要建链根表(投影只给几何,命名是 faijs 语义)。
413
+ // 3.2: inlined registerExtrudeRoles — origin = StmtId, roles from construct enumerator
414
+ const kernel = getBackends().kernel.brep;
415
+ const solid = kernel ? brepOf(result) : undefined;
416
+ if (kernel && solid) {
417
+ const origin = String(getCurrentStmt()?.id ?? '');
418
+ return fromBrep(solidToShape(kernel, solid), {
419
+ solid,
420
+ roleTable: new Map([[origin, extrudeConstructRoles(kernel, solid)]]),
421
+ });
422
+ }
423
+ return result;
297
424
  },
425
+ naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [{ kind: 'semantic', name: 'top' }, { kind: 'semantic', name: 'bottom' }, { kind: 'wall', index: 0 }] } },
298
426
  });
299
427
  //# sourceMappingURL=extrude.js.map