@faicad/faijs 0.30.9 → 0.31.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 (284) hide show
  1. package/dist/api/align/index.d.ts +64 -0
  2. package/dist/api/align/index.d.ts.map +1 -0
  3. package/dist/api/align/index.js +101 -0
  4. package/dist/api/align/index.js.map +1 -0
  5. package/dist/api/api-namespace.d.ts +5 -4
  6. package/dist/api/api-namespace.d.ts.map +1 -1
  7. package/dist/api/api-namespace.js +36 -4
  8. package/dist/api/api-namespace.js.map +1 -1
  9. package/dist/api/boolean-op/index.d.ts +65 -0
  10. package/dist/api/boolean-op/index.d.ts.map +1 -0
  11. package/dist/api/boolean-op/index.js +113 -0
  12. package/dist/api/boolean-op/index.js.map +1 -0
  13. package/dist/api/boolean.d.ts.map +1 -1
  14. package/dist/api/boolean.js +15 -27
  15. package/dist/api/boolean.js.map +1 -1
  16. package/dist/api/brep-operations/healingFns.d.ts +13 -0
  17. package/dist/api/brep-operations/healingFns.d.ts.map +1 -1
  18. package/dist/api/brep-operations/healingFns.js +28 -1
  19. package/dist/api/brep-operations/healingFns.js.map +1 -1
  20. package/dist/api/brep-operations/topologyFns.d.ts +27 -6
  21. package/dist/api/brep-operations/topologyFns.d.ts.map +1 -1
  22. package/dist/api/brep-operations/topologyFns.js +46 -22
  23. package/dist/api/brep-operations/topologyFns.js.map +1 -1
  24. package/dist/api/chamfer.d.ts +5 -4
  25. package/dist/api/chamfer.d.ts.map +1 -1
  26. package/dist/api/chamfer.js +12 -11
  27. package/dist/api/chamfer.js.map +1 -1
  28. package/dist/api/curve-sketch/index.d.ts.map +1 -1
  29. package/dist/api/curve-sketch/index.js +9 -3
  30. package/dist/api/curve-sketch/index.js.map +1 -1
  31. package/dist/api/draft.d.ts.map +1 -1
  32. package/dist/api/draft.js +1 -3
  33. package/dist/api/draft.js.map +1 -1
  34. package/dist/api/engrave.d.ts.map +1 -1
  35. package/dist/api/engrave.js +3 -13
  36. package/dist/api/engrave.js.map +1 -1
  37. package/dist/api/export-3mf.d.ts +73 -0
  38. package/dist/api/export-3mf.d.ts.map +1 -0
  39. package/dist/api/export-3mf.js +121 -0
  40. package/dist/api/export-3mf.js.map +1 -0
  41. package/dist/api/export-brep.d.ts +6 -0
  42. package/dist/api/export-brep.d.ts.map +1 -1
  43. package/dist/api/export-brep.js +11 -2
  44. package/dist/api/export-brep.js.map +1 -1
  45. package/dist/api/export-step.d.ts +67 -0
  46. package/dist/api/export-step.d.ts.map +1 -0
  47. package/dist/api/export-step.js +98 -0
  48. package/dist/api/export-step.js.map +1 -0
  49. package/dist/api/export-stl.d.ts +8 -0
  50. package/dist/api/export-stl.d.ts.map +1 -1
  51. package/dist/api/export-stl.js +23 -8
  52. package/dist/api/export-stl.js.map +1 -1
  53. package/dist/api/feature-repair.d.ts +1 -1
  54. package/dist/api/feature-repair.d.ts.map +1 -1
  55. package/dist/api/feature-repair.js +1 -7
  56. package/dist/api/feature-repair.js.map +1 -1
  57. package/dist/api/fillet-variable.d.ts.map +1 -1
  58. package/dist/api/fillet-variable.js +0 -1
  59. package/dist/api/fillet-variable.js.map +1 -1
  60. package/dist/api/fillet.d.ts +3 -3
  61. package/dist/api/fillet.d.ts.map +1 -1
  62. package/dist/api/fillet.js +3 -4
  63. package/dist/api/fillet.js.map +1 -1
  64. package/dist/api/generated/operations.js +6 -6
  65. package/dist/api/generated/operations.js.map +1 -1
  66. package/dist/api/generated/script-face-manifest.d.ts +1 -1
  67. package/dist/api/generated/script-face-manifest.js +3 -3
  68. package/dist/api/generated/script-face-manifest.js.map +1 -1
  69. package/dist/api/generated/script-face.d.ts +1 -1
  70. package/dist/api/generated/script-face.js +1 -1
  71. package/dist/api/generated/script-face.js.map +1 -1
  72. package/dist/api/generated/sketching.js +1 -1
  73. package/dist/api/generated/sketching.js.map +1 -1
  74. package/dist/api/generated/topology.js +10 -10
  75. package/dist/api/generated/topology.js.map +1 -1
  76. package/dist/api/helix.d.ts +1 -1
  77. package/dist/api/helix.js +1 -1
  78. package/dist/api/helix.js.map +1 -1
  79. package/dist/api/index.d.ts +4 -1
  80. package/dist/api/index.d.ts.map +1 -1
  81. package/dist/api/index.js +16 -4
  82. package/dist/api/index.js.map +1 -1
  83. package/dist/api/internal/compat-op.d.ts +6 -6
  84. package/dist/api/internal/compat-op.d.ts.map +1 -1
  85. package/dist/api/internal/compat-op.js +7 -9
  86. package/dist/api/internal/compat-op.js.map +1 -1
  87. package/dist/api/internal/export-members.d.ts +80 -0
  88. package/dist/api/internal/export-members.d.ts.map +1 -0
  89. package/dist/api/internal/export-members.js +104 -0
  90. package/dist/api/internal/export-members.js.map +1 -0
  91. package/dist/api/internal/l3-bridge.d.ts +17 -0
  92. package/dist/api/internal/l3-bridge.d.ts.map +1 -1
  93. package/dist/api/internal/l3-bridge.js +23 -1
  94. package/dist/api/internal/l3-bridge.js.map +1 -1
  95. package/dist/api/measure-query/index.d.ts +262 -0
  96. package/dist/api/measure-query/index.d.ts.map +1 -0
  97. package/dist/api/measure-query/index.js +390 -0
  98. package/dist/api/measure-query/index.js.map +1 -0
  99. package/dist/api/pattern.d.ts.map +1 -1
  100. package/dist/api/pattern.js +0 -3
  101. package/dist/api/pattern.js.map +1 -1
  102. package/dist/api/primitives.d.ts +6 -6
  103. package/dist/api/primitives.d.ts.map +1 -1
  104. package/dist/api/primitives.js +12 -11
  105. package/dist/api/primitives.js.map +1 -1
  106. package/dist/api/profile.d.ts.map +1 -1
  107. package/dist/api/profile.js +0 -1
  108. package/dist/api/profile.js.map +1 -1
  109. package/dist/api/punch-hole.d.ts.map +1 -1
  110. package/dist/api/punch-hole.js +0 -1
  111. package/dist/api/punch-hole.js.map +1 -1
  112. package/dist/api/replicate.d.ts +5 -7
  113. package/dist/api/replicate.d.ts.map +1 -1
  114. package/dist/api/replicate.js +18 -56
  115. package/dist/api/replicate.js.map +1 -1
  116. package/dist/api/section-by-plane.d.ts.map +1 -1
  117. package/dist/api/section-by-plane.js +0 -1
  118. package/dist/api/section-by-plane.js.map +1 -1
  119. package/dist/api/shell.d.ts +1 -1
  120. package/dist/api/shell.d.ts.map +1 -1
  121. package/dist/api/shell.js +11 -2
  122. package/dist/api/shell.js.map +1 -1
  123. package/dist/api/sketch-on-face.d.ts +3 -3
  124. package/dist/api/sketch-on-face.d.ts.map +1 -1
  125. package/dist/api/sketch-on-face.js +6 -4
  126. package/dist/api/sketch-on-face.js.map +1 -1
  127. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  128. package/dist/api/sketch-on-plane.js +0 -1
  129. package/dist/api/sketch-on-plane.js.map +1 -1
  130. package/dist/api/split-by-plane.d.ts.map +1 -1
  131. package/dist/api/split-by-plane.js +0 -1
  132. package/dist/api/split-by-plane.js.map +1 -1
  133. package/dist/api/split.d.ts +1 -1
  134. package/dist/api/split.js +1 -1
  135. package/dist/api/split.js.map +1 -1
  136. package/dist/api/surface/arg-spec.d.ts +3 -12
  137. package/dist/api/surface/arg-spec.d.ts.map +1 -1
  138. package/dist/api/surface/arg-spec.js +19 -26
  139. package/dist/api/surface/arg-spec.js.map +1 -1
  140. package/dist/api/sweep.d.ts +15 -3
  141. package/dist/api/sweep.d.ts.map +1 -1
  142. package/dist/api/sweep.js +5 -3
  143. package/dist/api/sweep.js.map +1 -1
  144. package/dist/api/thicken.d.ts.map +1 -1
  145. package/dist/api/thicken.js +11 -2
  146. package/dist/api/thicken.js.map +1 -1
  147. package/dist/api/transform.d.ts +3 -3
  148. package/dist/api/transform.d.ts.map +1 -1
  149. package/dist/api/transform.js +47 -17
  150. package/dist/api/transform.js.map +1 -1
  151. package/dist/boolean/index.d.ts +23 -0
  152. package/dist/boolean/index.d.ts.map +1 -0
  153. package/dist/boolean/index.js +27 -0
  154. package/dist/boolean/index.js.map +1 -0
  155. package/dist/brep/brep-chain.d.ts +1 -19
  156. package/dist/brep/brep-chain.d.ts.map +1 -1
  157. package/dist/brep/brep-chain.js +0 -1
  158. package/dist/brep/brep-chain.js.map +1 -1
  159. package/dist/brep/brep-ops.d.ts +4 -1
  160. package/dist/brep/brep-ops.d.ts.map +1 -1
  161. package/dist/brep/brep-ops.js +9 -5
  162. package/dist/brep/brep-ops.js.map +1 -1
  163. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  164. package/dist/brep/engine/adapters/brep-mock.js +0 -3
  165. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  166. package/dist/brep/engine/adapters/brepkit.d.ts +4 -3
  167. package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
  168. package/dist/brep/engine/adapters/brepkit.js +4 -98
  169. package/dist/brep/engine/adapters/brepkit.js.map +1 -1
  170. package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
  171. package/dist/brep/engine/adapters/occt.js +0 -144
  172. package/dist/brep/engine/adapters/occt.js.map +1 -1
  173. package/dist/brep/engine/native-history.d.ts +27 -0
  174. package/dist/brep/engine/native-history.d.ts.map +1 -0
  175. package/dist/brep/engine/native-history.js +54 -0
  176. package/dist/brep/engine/native-history.js.map +1 -0
  177. package/dist/brep/engine/registry.d.ts +2 -4
  178. package/dist/brep/engine/registry.d.ts.map +1 -1
  179. package/dist/brep/engine/registry.js +1 -1
  180. package/dist/brep/engine/registry.js.map +1 -1
  181. package/dist/brep/engine/types.d.ts +35 -77
  182. package/dist/brep/engine/types.d.ts.map +1 -1
  183. package/dist/brep/engine/types.js.map +1 -1
  184. package/dist/brep/export/export-model.d.ts +21 -0
  185. package/dist/brep/export/export-model.d.ts.map +1 -1
  186. package/dist/brep/export/export-model.js +171 -73
  187. package/dist/brep/export/export-model.js.map +1 -1
  188. package/dist/brep/export/step.d.ts +17 -1
  189. package/dist/brep/export/step.d.ts.map +1 -1
  190. package/dist/brep/export/step.js +133 -0
  191. package/dist/brep/export/step.js.map +1 -1
  192. package/dist/brep/export/stl.d.ts +22 -1
  193. package/dist/brep/export/stl.d.ts.map +1 -1
  194. package/dist/brep/export/stl.js +58 -10
  195. package/dist/brep/export/stl.js.map +1 -1
  196. package/dist/brep/export/transform12.d.ts +47 -0
  197. package/dist/brep/export/transform12.d.ts.map +1 -0
  198. package/dist/brep/export/transform12.js +87 -0
  199. package/dist/brep/export/transform12.js.map +1 -0
  200. package/dist/brep/face-evolution.d.ts +53 -0
  201. package/dist/brep/face-evolution.d.ts.map +1 -1
  202. package/dist/brep/face-evolution.js +65 -0
  203. package/dist/brep/face-evolution.js.map +1 -1
  204. package/dist/browser-host/index.d.ts +4 -1
  205. package/dist/browser-host/index.d.ts.map +1 -1
  206. package/dist/browser-host/index.js +7 -1
  207. package/dist/browser-host/index.js.map +1 -1
  208. package/dist/browser.d.ts +4 -8
  209. package/dist/browser.d.ts.map +1 -1
  210. package/dist/browser.js +4 -26
  211. package/dist/browser.js.map +1 -1
  212. package/dist/cad-runtime/backend-dispatch.d.ts +13 -58
  213. package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
  214. package/dist/cad-runtime/backend-dispatch.js +22 -80
  215. package/dist/cad-runtime/backend-dispatch.js.map +1 -1
  216. package/dist/cad-runtime/content-key.d.ts +3 -3
  217. package/dist/cad-runtime/content-key.js +3 -3
  218. package/dist/cad-runtime/content-key.js.map +1 -1
  219. package/dist/cad-runtime/ports.d.ts +28 -0
  220. package/dist/cad-runtime/ports.d.ts.map +1 -1
  221. package/dist/cad-runtime/ports.js.map +1 -1
  222. package/dist/cad-runtime/runtime.d.ts +33 -12
  223. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  224. package/dist/cad-runtime/runtime.js +44 -48
  225. package/dist/cad-runtime/runtime.js.map +1 -1
  226. package/dist/define-op.d.ts +6 -11
  227. package/dist/define-op.d.ts.map +1 -1
  228. package/dist/define-op.js +3 -20
  229. package/dist/define-op.js.map +1 -1
  230. package/dist/env-agnostic.d.ts +2 -2
  231. package/dist/env-agnostic.d.ts.map +1 -1
  232. package/dist/env-agnostic.js +1 -1
  233. package/dist/env-agnostic.js.map +1 -1
  234. package/dist/index.d.ts +13 -64
  235. package/dist/index.d.ts.map +1 -1
  236. package/dist/index.js +17 -75
  237. package/dist/index.js.map +1 -1
  238. package/dist/lang/symbol-table.generated.d.ts +17 -0
  239. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  240. package/dist/lang/symbol-table.generated.js +17 -0
  241. package/dist/lang/symbol-table.generated.js.map +1 -1
  242. package/dist/mesh/index.d.ts +18 -23
  243. package/dist/mesh/index.d.ts.map +1 -1
  244. package/dist/mesh/index.js +18 -20
  245. package/dist/mesh/index.js.map +1 -1
  246. package/dist/mesh/io.d.ts +42 -14
  247. package/dist/mesh/io.d.ts.map +1 -1
  248. package/dist/mesh/io.js +77 -13
  249. package/dist/mesh/io.js.map +1 -1
  250. package/dist/mesh/threemf-loader.d.ts +38 -4
  251. package/dist/mesh/threemf-loader.d.ts.map +1 -1
  252. package/dist/mesh/threemf-loader.js +115 -34
  253. package/dist/mesh/threemf-loader.js.map +1 -1
  254. package/dist/mesh/types.d.ts +30 -0
  255. package/dist/mesh/types.d.ts.map +1 -1
  256. package/dist/mesh/types.js.map +1 -1
  257. package/dist/node-host/execute-script.d.ts +2 -1
  258. package/dist/node-host/execute-script.d.ts.map +1 -1
  259. package/dist/node-host/execute-script.js +5 -4
  260. package/dist/node-host/execute-script.js.map +1 -1
  261. package/dist/node-host/index.d.ts +1 -0
  262. package/dist/node-host/index.d.ts.map +1 -1
  263. package/dist/node-host/index.js +4 -0
  264. package/dist/node-host/index.js.map +1 -1
  265. package/dist/primitives/index.d.ts +19 -0
  266. package/dist/primitives/index.d.ts.map +1 -0
  267. package/dist/primitives/index.js +21 -0
  268. package/dist/primitives/index.js.map +1 -0
  269. package/dist/runtime-state.d.ts +63 -29
  270. package/dist/runtime-state.d.ts.map +1 -1
  271. package/dist/runtime-state.js +57 -0
  272. package/dist/runtime-state.js.map +1 -1
  273. package/dist/sdf/index.d.ts +12 -0
  274. package/dist/sdf/index.d.ts.map +1 -0
  275. package/dist/sdf/index.js +13 -0
  276. package/dist/sdf/index.js.map +1 -0
  277. package/dist/sdk.d.ts +0 -1
  278. package/dist/sdk.d.ts.map +1 -1
  279. package/dist/sdk.js.map +1 -1
  280. package/dist/weapp.d.ts +2 -2
  281. package/dist/weapp.d.ts.map +1 -1
  282. package/dist/weapp.js +1 -1
  283. package/dist/weapp.js.map +1 -1
  284. package/package.json +276 -35
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-3mf.js","sourceRoot":"","sources":["../../src/api/export-3mf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAMH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAoB,MAAM,6BAA6B,CAAA;AAC/E,OAAO,EAAE,YAAY,EAAyB,MAAM,2BAA2B,CAAA;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAYpD,wBAAwB;AACxB,SAAS,SAAS,CAAC,IAAsB;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,SAAS,CAAA;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,OAAO,CAAA;IACnC,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAA;IAC5C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IACpE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;AAC/B,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,IAAsB;IACzC,IAAI,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAC1B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,2CAA2C;QAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAA2B,CAAA;QAC3D,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,EAAE,MAAM,CAAC,CAAA;YAC9C,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,IAAI,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAA;QACvF,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAgB,EAAE,CAAA;IAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;IACnD,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IACtD,IAAI,IAAI,CAAC,SAAS;QAAE,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;IACpD,IAAI,IAAI;QAAE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAA;IAC3B,IAAI,IAAI,CAAC,QAAQ,EAAE,MAAM;QAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAC1E,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,SAAS,CAAC,KAA4B,EAAE,OAA0B;IAChF,uDAAuD;IACvD,aAAa,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IACpC,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC;SAChC,GAAG,CAAC,WAAW,CAAC;SAChB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACvE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,4GAA4G,CAAC,CAAA;IAC/H,CAAC;IACD,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IAChH,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAA;IACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;IACrE,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["/**\n * api export3mf — 3MF 导出(脚本面薄壳:宿主门 + 库面序列化器)\n *\n * §2.6 定式 1「薄壳 + 门禁,不重写格式逻辑」:本体只做三件事——宿主门\n * (`assertHostFor`)→ 把入参转成 `ExportEntry[]` → 调库面序列化器\n * `exportModelSync(entries, '3mf', { unit })`。因此脚本面与库面**天然逐字节同源**\n * (矩阵 B14)。\n *\n * **无引擎门**(与 `exportStep` 的差别):faijs 的 3MF 写出器是纯 XML + ZIP\n * (`build3mfModelXml` + `writeZipEntries`),与引擎身份无关;只有「活句柄 → 三角\n * 载荷」这一条兜底路径需要内核,且它对 occt / brepkit 一视同仁(走 `getBrepApi()`\n * 的当前引擎,不做身份断言)。\n *\n * **宿主门**:与其余导出命令同轴(§2.5),仅 `'node'` 宿主开放。理由:`.fai.js` 可\n * 由 AI 生成任意代码、属不受信输入,导出把「往哪写、写几份、写什么」的决定权交给\n * 脚本文本;浏览器 / 小程序里要导出模型必须由宿主入口发起。断言写在函数体第一行,\n * 所以脚本面 `cad.*` 与 TS 直连同一函数都被同一门禁覆盖。\n *\n * **条目必须是 `mesh`,且不得是空 mesh**(定式 4 / P8):`build3mfModelXml` 对无\n * `mesh` 的条目**静默跳过**(`export-model.ts:330` 的 `if (!e.mesh) return`),只给\n * `solid` 会产出「ZIP 合法但对象为空」的假成功。故本 op 只交 `mesh` 条目,且三角数\n * 为 0 的成员视为不可导出;全体不可导出时**显式报错**,不落空文件。\n *\n * **三角载荷取自 Shape 自身,而非二次三角化**(对 §2.6 定式 4 措辞的按证据修正):\n * 定式 4 原话是「3mf 先 `solidToShape` 三角化再给 `mesh`」,但其依据是\n * `cli.ts#writeOutput` 的 `brepSolid` 分支——那里 solid 来自独立快照表、`shape` 可能\n * 只有 mesh,故必须先三角化。本 op 的入参 Shape 由执行链产出时**已带当前显示 mesh**\n * (mesh 链由构造器填、brep 链由 `fromHandle` → `meshHandle` 填)。再走一遍\n * `solidToShape` 会**二次三角化**并换掉默认精度:`meshHandle` 缺省 segments=32\n * (`brep/handle-bridge.ts:125`),`solidToShape` 缺省 2π/64(`brep/brep-ops.ts:68`),\n * 两者产出的是**两份不同的 mesh**——违反「导出所用 mesh 必须是用户看到的 mesh」\n * (规则 1),与 `api/export-stl.ts` 拒绝走原生二次三角化是同一取舍。故只在 Shape\n * 自带的三角载荷缺席 / 为空时(例如只有 BREP 槽的跨库产物)才用 `solidToShape` 兜底。\n */\n\nimport type { Shape } from '../mesh/types'\nimport type { CompoundShape } from '../shape'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { UnitName } from '../units'\nimport { brepOf } from '../shape'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { solidToShape } from '../brep/brep-ops'\nimport { exportModelSync, type ExportEntry } from '../brep/export/export-model'\nimport { exportTreeOf, type ExportMemberNode } from './internal/export-members'\nimport { assertHostFor } from './internal/l3-bridge'\n\n/** `cad.export3mf` 选项。 */\nexport interface Export3mfOptions {\n /**\n * 文件里声明的长度单位(缺省 `'mm'`)。语义与库面 `ExportOptions.unit` 一致:\n * 实现负责把坐标换算到该刻度,并与 `<model unit>` 成对写出(§10.3 规则 3);\n * `yard` 无 3MF 枚举值,库面成对回落到 mm(§10.3 规则 2)。\n */\n unit?: UnitName\n}\n\n/** 节点自带的三角载荷(非空才算数)。 */\nfunction ownMeshOf(node: ExportMemberNode): { positions: Float32Array; indices: Uint32Array } | undefined {\n const positions = node.shape?.positions\n const indices = node.shape?.indices\n if (!positions || !indices) return undefined\n if (positions.length === 0 || indices.length === 0) return undefined\n return { positions, indices }\n}\n\n/**\n * 一个成员树节点 → 3mf 条目:递归携带 children(装配层级 → `<components>`)。\n * 只产出带非空 `mesh` 的节点,或带 children 的容器(无 mesh 的节点会被写出器静默\n * 跳过,故容器节点若无 mesh 仅以 `<components>` 表达层级,符合 3MF Core 规范)。\n */\nfunction entryOfNode(node: ExportMemberNode): ExportEntry {\n let mesh = ownMeshOf(node)\n if (!mesh) {\n // 兜底:Shape 只有 BREP 槽(跨库产物)时现场三角化一次;引擎身份中立。\n const handle = brepOf(node.shape) as BrepHandle | undefined\n if (handle) {\n const tri = solidToShape(getBrepApi(), handle)\n if (tri.indices.length > 0) mesh = { positions: tri.positions, indices: tri.indices }\n }\n }\n const entry: ExportEntry = {}\n if (node.name !== undefined) entry.name = node.name\n if (node.color !== undefined) entry.color = node.color\n if (node.transform) entry.transform = node.transform\n if (mesh) entry.mesh = mesh\n if (node.children?.length) entry.children = node.children.map(entryOfNode)\n return entry\n}\n\n/**\n * 导出 3MF(ZIP 容器字节)。\n * @group 导出\n * @inputs 1\n * @async false\n * @qual ok\n * @name export3mf\n * @note 薄壳 op:条目构造后一律交库面 `exportModelSync(entries,'3mf',{unit})` 序列化,\n * 故同一入参下脚本面字节与库面**逐字节一致**(同一真源)。返回 **ZIP 字节**\n * (`Uint8Array`),由宿主写入 `.3mf` 文件——内核不 import fs。`unit` 只声明单位\n * (写 `<model unit>`),坐标随之换算,两者同源(缺省 mm)。\n * 入参可为单件 Shape 或装配 compound;compound 逐成员导出并带上成员名与\n * `memberColors`(basematerials)。条目**只交 mesh**:无 mesh 的条目会被写出器\n * 静默跳过、产出「ZIP 合法但对象为空」的假成功,故三角数为 0 的成员视为不可导出,\n * 全体不可导出时显式报 E_EXPORT_3MF_EMPTY。\n * **宿主门**:仅 `'node'` 宿主可执行;browser / weapp / 未声明宿主报\n * E_HOST_UNSUPPORTED(门在读取载荷之前)。无引擎门——写出器是纯 XML + ZIP,\n * 与引擎身份无关。\n * @returns Uint8Array 3MF(ZIP)字节。\n * @param shape - 目标几何(单件 Shape 或装配 compound)。type:Shape|CompoundShape required:true\n * @param options.unit - 文件里声明的长度单位,缺省 mm(坐标随之换算)。type:UnitName\n * @example\n * const bytes = cad.export3mf(part0)\n * const asmBytes = cad.export3mf(asm1)\n */\nexport function export3mf(shape: Shape | CompoundShape, options?: Export3mfOptions): Uint8Array {\n // 宿主门在实现体最前:非 node 宿主先报 E_HOST_UNSUPPORTED,不读取载荷、不产字节。\n assertHostFor('export3mf', ['node'])\n const entries = exportTreeOf(shape)\n .map(entryOfNode)\n .filter((e) => e.mesh !== undefined || (e.children?.length ?? 0) > 0)\n if (entries.length === 0) {\n throw new Error('E_EXPORT_3MF_EMPTY: export3mf input has no exportable member (empty assembly or members without triangles)')\n }\n const buffer = exportModelSync(entries, '3mf', options?.unit === undefined ? undefined : { unit: options.unit })\n const bytes = new Uint8Array(buffer)\n if (bytes.length === 0) {\n throw new Error('E_EXPORT_3MF_EMPTY: 3MF writer produced no bytes')\n }\n return bytes\n}\n"]}
@@ -15,6 +15,10 @@
15
15
  * (与 dispatchPath 的差异:`assertEngineFor` **不含** D11-3 的 `brep_mock` 豁免——
16
16
  * mock 句柄不是 occt 句柄,放行只会拿到错形状,故这里如实拦截。)
17
17
  *
18
+ * 宿主门在引擎门之前(`assertHostFor('exportBrep', ['node'])`):导出命令只在 node
19
+ * 宿主开放,browser / weapp / 未声明宿主先报 `E_HOST_UNSUPPORTED`。理由见
20
+ * `cad-runtime/ports.ts#HostEnv`。
21
+ *
18
22
  * §9.5 降级路径(记录在案):brepkit 的 wasm 面**自带 `toBREP`**
19
23
  * (`api/surface/brepkit-wasm-surface.json` 的 `methods` 含 `toBREP`),只是尚未接进
20
24
  * L1 契约。一旦契约新增导出成员且两侧适配器同时落地,本函数删掉 `assertEngineFor`
@@ -32,6 +36,8 @@ import type { Shape } from '../mesh/types.js';
32
36
  * 执行前报 E_BREP_UNSUPPORTED;brep_mock 不拦截(引擎身份判定读
33
37
  * `config.brepEngineId`)。返回**纯文本**,由宿主写入 `.brep` 文件;
34
38
  * 经 `import_brep` / L1 `fromBREP` 可无损回读(精确 BREP,非 mesh 回填)。
39
+ * **宿主门**:仅 `'node'` 宿主可执行,且宿主门先于引擎门——browser / weapp /
40
+ * 未声明宿主报 E_HOST_UNSUPPORTED(不读 BREP 槽、不触碰内核)。
35
41
  * @returns string OCCT BREP 文本。
36
42
  * @param shape - 目标几何(必须带 BREP 槽;mesh-only 输入报 E_EXPORT_BREP_NO_BREP)。type:Shape required:true
37
43
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"export-brep.d.ts","sourceRoot":"","sources":["../../src/api/export-brep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAoB1C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAE/C"}
1
+ {"version":3,"file":"export-brep.d.ts","sourceRoot":"","sources":["../../src/api/export-brep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAuB1C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAE/C"}
@@ -15,6 +15,10 @@
15
15
  * (与 dispatchPath 的差异:`assertEngineFor` **不含** D11-3 的 `brep_mock` 豁免——
16
16
  * mock 句柄不是 occt 句柄,放行只会拿到错形状,故这里如实拦截。)
17
17
  *
18
+ * 宿主门在引擎门之前(`assertHostFor('exportBrep', ['node'])`):导出命令只在 node
19
+ * 宿主开放,browser / weapp / 未声明宿主先报 `E_HOST_UNSUPPORTED`。理由见
20
+ * `cad-runtime/ports.ts#HostEnv`。
21
+ *
18
22
  * §9.5 降级路径(记录在案):brepkit 的 wasm 面**自带 `toBREP`**
19
23
  * (`api/surface/brepkit-wasm-surface.json` 的 `methods` 含 `toBREP`),只是尚未接进
20
24
  * L1 契约。一旦契约新增导出成员且两侧适配器同时落地,本函数删掉 `assertEngineFor`
@@ -22,9 +26,12 @@
22
26
  */
23
27
  import { brepOf } from '../shape.js';
24
28
  import { getOcctKernel } from '../occt-kernel/occtKernel.js';
25
- import { assertEngineFor } from './internal/l3-bridge.js';
26
- /** BREP 路径:先断言引擎身份 → 借出 brep 句柄 → occt 原生 toBREP 文本。 */
29
+ import { assertEngineFor, assertHostFor } from './internal/l3-bridge.js';
30
+ /** BREP 路径:先宿主门 → 引擎门 → 借出 brep 句柄 → occt 原生 toBREP 文本。 */
27
31
  function exportBrepNative(shape) {
32
+ // 门序固定:宿主门先于引擎门。门在 `brepOf(shape)` 之前,所以非 node 宿主下
33
+ // 不读取 Shape 的 BREP 槽、不触碰任何内核。
34
+ assertHostFor('exportBrep', ['node']);
28
35
  assertEngineFor('exportBrep', ['occt']);
29
36
  const handle = brepOf(shape);
30
37
  if (!handle) {
@@ -47,6 +54,8 @@ function exportBrepNative(shape) {
47
54
  * 执行前报 E_BREP_UNSUPPORTED;brep_mock 不拦截(引擎身份判定读
48
55
  * `config.brepEngineId`)。返回**纯文本**,由宿主写入 `.brep` 文件;
49
56
  * 经 `import_brep` / L1 `fromBREP` 可无损回读(精确 BREP,非 mesh 回填)。
57
+ * **宿主门**:仅 `'node'` 宿主可执行,且宿主门先于引擎门——browser / weapp /
58
+ * 未声明宿主报 E_HOST_UNSUPPORTED(不读 BREP 槽、不触碰内核)。
50
59
  * @returns string OCCT BREP 文本。
51
60
  * @param shape - 目标几何(必须带 BREP 槽;mesh-only 输入报 E_EXPORT_BREP_NO_BREP)。type:Shape required:true
52
61
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"export-brep.js","sourceRoot":"","sources":["../../src/api/export-brep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEtD,wDAAwD;AACxD,SAAS,gBAAgB,CAAC,KAAY;IACpC,eAAe,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAA2B,CAAA;IACtD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAA;IACjG,CAAC;IACD,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC,MAAM,CAAC,MAAe,CAAC,CAAA;IACpD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACtE,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,UAAU,CAAC,KAAY;IACrC,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAA;AAChC,CAAC","sourcesContent":["/**\n * api exportBrep — BREP 文本导出(平台:occt 专属,普通函数形态)\n *\n * @platform occt — 实现直调 occt 原生 `toBREP(shape)`(occt-wasm 有,L1 契约\n * `brep/engine/primitives.ts` **只有 `fromBREP` 导入侧、没有导出成员**)。\n *\n * 为什么不是 `defineOp`:本 op 返回**纯文本**(非 Shape)。`defineOp` 的 brep 包装\n * (`define-op.ts#wrapBrepOne`)把返回值一律收养为 Shape——字符串会落到\n * `fromHandle` 并抛 `E_BAD_HANDLE: ... got string`(实测)。数据型 op 走普通函数是\n * 本仓既有口径(先例:`api/view/view-projection.ts#projectView` 返回 SVG 字符串)。\n *\n * 引擎身份**不能**靠 dispatchPath 门控(普通函数不走那条路)⇒ 按\n * `api/internal/l3-bridge.ts#assertEngineFor` 的既定做法:函数体第一行断言当前\n * 引擎,触碰内核之前报出与 D11-4 同构的 `E_BREP_UNSUPPORTED`,不补桩、不回退。\n * (与 dispatchPath 的差异:`assertEngineFor` **不含** D11-3 的 `brep_mock` 豁免——\n * mock 句柄不是 occt 句柄,放行只会拿到错形状,故这里如实拦截。)\n *\n * §9.5 降级路径(记录在案):brepkit 的 wasm 面**自带 `toBREP`**\n * (`api/surface/brepkit-wasm-surface.json` 的 `methods` 含 `toBREP`),只是尚未接进\n * L1 契约。一旦契约新增导出成员且两侧适配器同时落地,本函数删掉 `assertEngineFor`\n * 并改走 `getBrepApi()`,该方法即从 C2 转入 C1。\n */\n\nimport type { Shape } from '../mesh/types'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { brepOf } from '../shape'\nimport { getOcctKernel } from '../occt-kernel/occtKernel'\nimport { assertEngineFor } from './internal/l3-bridge'\n\n/** BREP 路径:先断言引擎身份 → 借出 brep 句柄 → occt 原生 toBREP 文本。 */\nfunction exportBrepNative(shape: Shape): string {\n assertEngineFor('exportBrep', ['occt'])\n const handle = brepOf(shape) as BrepHandle | undefined\n if (!handle) {\n throw new Error('E_EXPORT_BREP_NO_BREP: exportBrep input has no BREP handle (mesh-only shape)')\n }\n const text = getOcctKernel().toBREP(handle as never)\n if (typeof text !== 'string' || text.length === 0) {\n throw new Error('E_EXPORT_BREP_EMPTY: occt toBREP produced no text')\n }\n return text\n}\n\n/**\n * 导出 BREP 文本(与 `import_brep` 成对的导出侧)。\n * @group 导出\n * @inputs 1\n * @async false\n * @qual ok\n * @name exportBrep\n * @note 平台 op:仅 occt 引擎(原生 toBREP,L1 契约无对应导出成员)。非 occt 引擎\n * 执行前报 E_BREP_UNSUPPORTED;brep_mock 不拦截(引擎身份判定读\n * `config.brepEngineId`)。返回**纯文本**,由宿主写入 `.brep` 文件;\n * 经 `import_brep` / L1 `fromBREP` 可无损回读(精确 BREP,非 mesh 回填)。\n * @returns string OCCT BREP 文本。\n * @param shape - 目标几何(必须带 BREP 槽;mesh-only 输入报 E_EXPORT_BREP_NO_BREP)。type:Shape required:true\n * @example\n * const text = cad.exportBrep(part0)\n */\nexport function exportBrep(shape: Shape): string {\n return exportBrepNative(shape)\n}\n"]}
1
+ {"version":3,"file":"export-brep.js","sourceRoot":"","sources":["../../src/api/export-brep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAErE,2DAA2D;AAC3D,SAAS,gBAAgB,CAAC,KAAY;IACpC,mDAAmD;IACnD,8BAA8B;IAC9B,aAAa,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IACrC,eAAe,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAA2B,CAAA;IACtD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAA;IACjG,CAAC;IACD,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC,MAAM,CAAC,MAAe,CAAC,CAAA;IACpD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACtE,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAY;IACrC,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAA;AAChC,CAAC","sourcesContent":["/**\n * api exportBrep — BREP 文本导出(平台:occt 专属,普通函数形态)\n *\n * @platform occt — 实现直调 occt 原生 `toBREP(shape)`(occt-wasm 有,L1 契约\n * `brep/engine/primitives.ts` **只有 `fromBREP` 导入侧、没有导出成员**)。\n *\n * 为什么不是 `defineOp`:本 op 返回**纯文本**(非 Shape)。`defineOp` 的 brep 包装\n * (`define-op.ts#wrapBrepOne`)把返回值一律收养为 Shape——字符串会落到\n * `fromHandle` 并抛 `E_BAD_HANDLE: ... got string`(实测)。数据型 op 走普通函数是\n * 本仓既有口径(先例:`api/view/view-projection.ts#projectView` 返回 SVG 字符串)。\n *\n * 引擎身份**不能**靠 dispatchPath 门控(普通函数不走那条路)⇒ 按\n * `api/internal/l3-bridge.ts#assertEngineFor` 的既定做法:函数体第一行断言当前\n * 引擎,触碰内核之前报出与 D11-4 同构的 `E_BREP_UNSUPPORTED`,不补桩、不回退。\n * (与 dispatchPath 的差异:`assertEngineFor` **不含** D11-3 的 `brep_mock` 豁免——\n * mock 句柄不是 occt 句柄,放行只会拿到错形状,故这里如实拦截。)\n *\n * 宿主门在引擎门之前(`assertHostFor('exportBrep', ['node'])`):导出命令只在 node\n * 宿主开放,browser / weapp / 未声明宿主先报 `E_HOST_UNSUPPORTED`。理由见\n * `cad-runtime/ports.ts#HostEnv`。\n *\n * §9.5 降级路径(记录在案):brepkit 的 wasm 面**自带 `toBREP`**\n * (`api/surface/brepkit-wasm-surface.json` 的 `methods` 含 `toBREP`),只是尚未接进\n * L1 契约。一旦契约新增导出成员且两侧适配器同时落地,本函数删掉 `assertEngineFor`\n * 并改走 `getBrepApi()`,该方法即从 C2 转入 C1。\n */\n\nimport type { Shape } from '../mesh/types'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { brepOf } from '../shape'\nimport { getOcctKernel } from '../occt-kernel/occtKernel'\nimport { assertEngineFor, assertHostFor } from './internal/l3-bridge'\n\n/** BREP 路径:先宿主门 → 引擎门 → 借出 brep 句柄 → occt 原生 toBREP 文本。 */\nfunction exportBrepNative(shape: Shape): string {\n // 门序固定:宿主门先于引擎门。门在 `brepOf(shape)` 之前,所以非 node 宿主下\n // 不读取 Shape 的 BREP 槽、不触碰任何内核。\n assertHostFor('exportBrep', ['node'])\n assertEngineFor('exportBrep', ['occt'])\n const handle = brepOf(shape) as BrepHandle | undefined\n if (!handle) {\n throw new Error('E_EXPORT_BREP_NO_BREP: exportBrep input has no BREP handle (mesh-only shape)')\n }\n const text = getOcctKernel().toBREP(handle as never)\n if (typeof text !== 'string' || text.length === 0) {\n throw new Error('E_EXPORT_BREP_EMPTY: occt toBREP produced no text')\n }\n return text\n}\n\n/**\n * 导出 BREP 文本(与 `import_brep` 成对的导出侧)。\n * @group 导出\n * @inputs 1\n * @async false\n * @qual ok\n * @name exportBrep\n * @note 平台 op:仅 occt 引擎(原生 toBREP,L1 契约无对应导出成员)。非 occt 引擎\n * 执行前报 E_BREP_UNSUPPORTED;brep_mock 不拦截(引擎身份判定读\n * `config.brepEngineId`)。返回**纯文本**,由宿主写入 `.brep` 文件;\n * 经 `import_brep` / L1 `fromBREP` 可无损回读(精确 BREP,非 mesh 回填)。\n * **宿主门**:仅 `'node'` 宿主可执行,且宿主门先于引擎门——browser / weapp /\n * 未声明宿主报 E_HOST_UNSUPPORTED(不读 BREP 槽、不触碰内核)。\n * @returns string OCCT BREP 文本。\n * @param shape - 目标几何(必须带 BREP 槽;mesh-only 输入报 E_EXPORT_BREP_NO_BREP)。type:Shape required:true\n * @example\n * const text = cad.exportBrep(part0)\n */\nexport function exportBrep(shape: Shape): string {\n return exportBrepNative(shape)\n}\n"]}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * api exportStep — STEP 导出(脚本面薄壳:宿主门 + 引擎门 + 库面序列化器)
3
+ *
4
+ * §2.6 定式 1「薄壳 + 门禁,不重写格式逻辑」:本体只做四件事——宿主门
5
+ * (`assertHostFor`)→ 引擎门(`assertEngineFor`)→ 把入参转成 `ExportEntry[]`
6
+ * (`brep/export/export-model.ts#ExportEntry`)→ 调库面序列化器
7
+ * `exportModelSync(entries, 'step', { unit })`。因此脚本面与库面**天然逐字节同源**
8
+ * (矩阵 B12),单位声明与坐标刻度的成对不变式(§10.3 规则 3:OCCT 恒写
9
+ * SI_UNIT(.MILLI.,.METRE.),坐标预缩放后声明必须跟上)由库面统一保证,op 里不复刻。
10
+ *
11
+ * **引擎门**:STEP 的装配层级走 XCAF,只有 occt 具备(§2.3),故与
12
+ * `api/export-brep.ts:32` 同构地断言 `assertEngineFor('exportStep', ['occt'])`——
13
+ * 在触碰任何句柄之前报出 `E_BREP_UNSUPPORTED` 并带上当前引擎名,不补桩、不回退。
14
+ * 非 occt 引擎下**不得**让调用落进 `getBrepApi()` / `getOcctKernel()` 的未初始化
15
+ * 异常,也不得把 brepkit 句柄交给 occt 内核(句柄不得跨引擎传递)。
16
+ *
17
+ * **宿主门**:与其余导出命令同轴(§2.5),仅 `'node'` 宿主开放,且宿主门在引擎门
18
+ * 之前。理由:`.fai.js` 可由 AI 生成任意代码、属不受信输入,导出把「往哪写、写几份、
19
+ * 写什么」的决定权交给脚本文本;浏览器 / 小程序里要导出模型必须由宿主入口发起。
20
+ * 断言写在函数体第一行,所以脚本面 `cad.*` 与 TS 直连同一函数都被同一门禁覆盖。
21
+ *
22
+ * **层级入口**:入参是 `Shape` 或 `CompoundShape`(§2.1——`cad.assembly` / `cad.group`
23
+ * 的产物),`cad.exportStep(compound)` 即脚本面的层级导出入口;成员拆解口径见
24
+ * `api/internal/export-members.ts`(对齐 `node-host/cli.ts#writeAssemblyStep`)。
25
+ *
26
+ * **条目按格式分派**(定式 4):step 吃 `solid`(保留精确 BREP 拓扑,缺则库面用
27
+ * `mesh` 重建,`brep/export/step.ts:83`),所以活句柄存在就给 `solid`,没有才给
28
+ * `mesh`——与 `cli.ts#writeOutput`(`:744-758`)同口径。空装配**显式报错**,不落
29
+ * 空文件(对齐 `api/export-stl.ts` 的 `E_EXPORT_STL_EMPTY` 口径)。
30
+ */
31
+ import type { Shape } from '../mesh/types.js';
32
+ import type { CompoundShape } from '../shape.js';
33
+ import type { UnitName } from '../units.js';
34
+ /** `cad.exportStep` 选项。 */
35
+ export interface ExportStepOptions {
36
+ /**
37
+ * 文件里声明的长度单位(缺省 `'mm'`)。语义与库面 `ExportOptions.unit` 一致:
38
+ * 实现负责把坐标换算到该刻度,并与声明**成对**写出(`export-model.ts` §10.3)。
39
+ */
40
+ unit?: UnitName;
41
+ }
42
+ /**
43
+ * 导出 STEP 文本(与 `cad.import_step` 成对的导出侧)。
44
+ * @group 导出
45
+ * @inputs 1
46
+ * @async false
47
+ * @qual ok
48
+ * @name exportStep
49
+ * @note 薄壳 op:条目构造后一律交库面 `exportModelSync(entries,'step',{unit})` 序列化,
50
+ * 故同一入参下脚本面文本与库面**逐字节一致**(同一真源,不另起写出通道)。
51
+ * 返回**纯文本**(ISO-10303-21),由宿主写入 `.step` / `.stp` 文件——内核不 import
52
+ * fs。`unit` 只声明单位,坐标换算与声明由库面成对完成(缺省 mm)。
53
+ * 入参可为单件 Shape 或装配 compound(`cad.assembly` / `cad.group` 产物),
54
+ * compound 逐成员导出并带上成员名与 `memberColors`;空装配显式报
55
+ * E_EXPORT_STEP_EMPTY,不落空文件。
56
+ * **双门**:宿主门仅 `'node'`(browser / weapp / 未声明报 E_HOST_UNSUPPORTED),
57
+ * 引擎门仅 `occt`(装配层级走 XCAF;非 occt 报 E_BREP_UNSUPPORTED)。门序固定
58
+ * 为宿主门 → 引擎门 → 实现体,两级都在触碰任何句柄之前。
59
+ * @returns string STEP(ISO-10303-21)文本。
60
+ * @param shape - 目标几何(单件 Shape 或装配 compound)。type:Shape|CompoundShape required:true
61
+ * @param options.unit - 文件里声明的长度单位,缺省 mm(坐标随之换算)。type:UnitName
62
+ * @example
63
+ * const text = cad.exportStep(part0)
64
+ * const asm = cad.exportStep(asm1, { unit: 'inch' })
65
+ */
66
+ export declare function exportStep(shape: Shape | CompoundShape, options?: ExportStepOptions): string;
67
+ //# sourceMappingURL=export-step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-step.d.ts","sourceRoot":"","sources":["../../src/api/export-step.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAMxC,2BAA2B;AAC3B,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAA;CAChB;AAqBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,aAAa,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAkB5F"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * api exportStep — STEP 导出(脚本面薄壳:宿主门 + 引擎门 + 库面序列化器)
3
+ *
4
+ * §2.6 定式 1「薄壳 + 门禁,不重写格式逻辑」:本体只做四件事——宿主门
5
+ * (`assertHostFor`)→ 引擎门(`assertEngineFor`)→ 把入参转成 `ExportEntry[]`
6
+ * (`brep/export/export-model.ts#ExportEntry`)→ 调库面序列化器
7
+ * `exportModelSync(entries, 'step', { unit })`。因此脚本面与库面**天然逐字节同源**
8
+ * (矩阵 B12),单位声明与坐标刻度的成对不变式(§10.3 规则 3:OCCT 恒写
9
+ * SI_UNIT(.MILLI.,.METRE.),坐标预缩放后声明必须跟上)由库面统一保证,op 里不复刻。
10
+ *
11
+ * **引擎门**:STEP 的装配层级走 XCAF,只有 occt 具备(§2.3),故与
12
+ * `api/export-brep.ts:32` 同构地断言 `assertEngineFor('exportStep', ['occt'])`——
13
+ * 在触碰任何句柄之前报出 `E_BREP_UNSUPPORTED` 并带上当前引擎名,不补桩、不回退。
14
+ * 非 occt 引擎下**不得**让调用落进 `getBrepApi()` / `getOcctKernel()` 的未初始化
15
+ * 异常,也不得把 brepkit 句柄交给 occt 内核(句柄不得跨引擎传递)。
16
+ *
17
+ * **宿主门**:与其余导出命令同轴(§2.5),仅 `'node'` 宿主开放,且宿主门在引擎门
18
+ * 之前。理由:`.fai.js` 可由 AI 生成任意代码、属不受信输入,导出把「往哪写、写几份、
19
+ * 写什么」的决定权交给脚本文本;浏览器 / 小程序里要导出模型必须由宿主入口发起。
20
+ * 断言写在函数体第一行,所以脚本面 `cad.*` 与 TS 直连同一函数都被同一门禁覆盖。
21
+ *
22
+ * **层级入口**:入参是 `Shape` 或 `CompoundShape`(§2.1——`cad.assembly` / `cad.group`
23
+ * 的产物),`cad.exportStep(compound)` 即脚本面的层级导出入口;成员拆解口径见
24
+ * `api/internal/export-members.ts`(对齐 `node-host/cli.ts#writeAssemblyStep`)。
25
+ *
26
+ * **条目按格式分派**(定式 4):step 吃 `solid`(保留精确 BREP 拓扑,缺则库面用
27
+ * `mesh` 重建,`brep/export/step.ts:83`),所以活句柄存在就给 `solid`,没有才给
28
+ * `mesh`——与 `cli.ts#writeOutput`(`:744-758`)同口径。空装配**显式报错**,不落
29
+ * 空文件(对齐 `api/export-stl.ts` 的 `E_EXPORT_STL_EMPTY` 口径)。
30
+ */
31
+ import { brepOf } from '../shape.js';
32
+ import { exportModelSync } from '../brep/export/export-model.js';
33
+ import { exportMembersOf } from './internal/export-members.js';
34
+ import { assertEngineFor, assertHostFor } from './internal/l3-bridge.js';
35
+ /** 一个成员 → step 条目:有活句柄给精确 BREP,没有才退回自带三角载荷。 */
36
+ function stepEntryOf(member) {
37
+ const handle = brepOf(member.shape);
38
+ const positions = member.shape?.positions;
39
+ const indices = member.shape?.indices;
40
+ const hasMesh = !!positions && !!indices && positions.length > 0 && indices.length > 0;
41
+ const payload = handle
42
+ ? { solid: handle }
43
+ : hasMesh
44
+ ? { mesh: { positions, indices } }
45
+ : undefined;
46
+ if (!payload)
47
+ return undefined;
48
+ return {
49
+ ...payload,
50
+ ...(member.name === undefined ? {} : { name: member.name }),
51
+ ...(member.color === undefined ? {} : { color: member.color }),
52
+ };
53
+ }
54
+ /**
55
+ * 导出 STEP 文本(与 `cad.import_step` 成对的导出侧)。
56
+ * @group 导出
57
+ * @inputs 1
58
+ * @async false
59
+ * @qual ok
60
+ * @name exportStep
61
+ * @note 薄壳 op:条目构造后一律交库面 `exportModelSync(entries,'step',{unit})` 序列化,
62
+ * 故同一入参下脚本面文本与库面**逐字节一致**(同一真源,不另起写出通道)。
63
+ * 返回**纯文本**(ISO-10303-21),由宿主写入 `.step` / `.stp` 文件——内核不 import
64
+ * fs。`unit` 只声明单位,坐标换算与声明由库面成对完成(缺省 mm)。
65
+ * 入参可为单件 Shape 或装配 compound(`cad.assembly` / `cad.group` 产物),
66
+ * compound 逐成员导出并带上成员名与 `memberColors`;空装配显式报
67
+ * E_EXPORT_STEP_EMPTY,不落空文件。
68
+ * **双门**:宿主门仅 `'node'`(browser / weapp / 未声明报 E_HOST_UNSUPPORTED),
69
+ * 引擎门仅 `occt`(装配层级走 XCAF;非 occt 报 E_BREP_UNSUPPORTED)。门序固定
70
+ * 为宿主门 → 引擎门 → 实现体,两级都在触碰任何句柄之前。
71
+ * @returns string STEP(ISO-10303-21)文本。
72
+ * @param shape - 目标几何(单件 Shape 或装配 compound)。type:Shape|CompoundShape required:true
73
+ * @param options.unit - 文件里声明的长度单位,缺省 mm(坐标随之换算)。type:UnitName
74
+ * @example
75
+ * const text = cad.exportStep(part0)
76
+ * const asm = cad.exportStep(asm1, { unit: 'inch' })
77
+ */
78
+ export function exportStep(shape, options) {
79
+ // 门序固定:宿主门 → 引擎门(都在读 Shape 槽 / 触碰内核之前)。
80
+ assertHostFor('exportStep', ['node']);
81
+ assertEngineFor('exportStep', ['occt']);
82
+ const entries = [];
83
+ for (const member of exportMembersOf(shape)) {
84
+ const entry = stepEntryOf(member);
85
+ if (entry)
86
+ entries.push(entry);
87
+ }
88
+ if (entries.length === 0) {
89
+ throw new Error('E_EXPORT_STEP_EMPTY: exportStep input has no exportable member (empty assembly or payload-less members)');
90
+ }
91
+ const buffer = exportModelSync(entries, 'step', options?.unit === undefined ? undefined : { unit: options.unit });
92
+ const text = new TextDecoder().decode(new Uint8Array(buffer));
93
+ if (text.length === 0) {
94
+ throw new Error('E_EXPORT_STEP_EMPTY: occt produced no STEP text');
95
+ }
96
+ return text;
97
+ }
98
+ //# sourceMappingURL=export-step.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-step.js","sourceRoot":"","sources":["../../src/api/export-step.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,eAAe,EAAoB,MAAM,6BAA6B,CAAA;AAC/E,OAAO,EAAE,eAAe,EAAqB,MAAM,2BAA2B,CAAA;AAC9E,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAWrE,+CAA+C;AAC/C,SAAS,WAAW,CAAC,MAAoB;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAA2B,CAAA;IAC7D,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,EAAE,SAAS,CAAA;IACzC,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,CAAA;IACrC,MAAM,OAAO,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,OAAO,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA;IACtF,MAAM,OAAO,GAA4B,MAAM;QAC7C,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE;QACnB,CAAC,CAAC,OAAO;YACP,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;YAClC,CAAC,CAAC,SAAS,CAAA;IACf,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAA;IAC9B,OAAO;QACL,GAAG,OAAO;QACV,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;QAC3D,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;KAC/D,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,UAAU,CAAC,KAA4B,EAAE,OAA2B;IAClF,wCAAwC;IACxC,aAAa,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IACrC,eAAe,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IACvC,MAAM,OAAO,GAAkB,EAAE,CAAA;IACjC,KAAK,MAAM,MAAM,IAAI,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;QACjC,IAAI,KAAK;YAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAChC,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,yGAAyG,CAAC,CAAA;IAC5H,CAAC;IACD,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IACjH,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;IAC7D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;IACpE,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["/**\n * api exportStep — STEP 导出(脚本面薄壳:宿主门 + 引擎门 + 库面序列化器)\n *\n * §2.6 定式 1「薄壳 + 门禁,不重写格式逻辑」:本体只做四件事——宿主门\n * (`assertHostFor`)→ 引擎门(`assertEngineFor`)→ 把入参转成 `ExportEntry[]`\n * (`brep/export/export-model.ts#ExportEntry`)→ 调库面序列化器\n * `exportModelSync(entries, 'step', { unit })`。因此脚本面与库面**天然逐字节同源**\n * (矩阵 B12),单位声明与坐标刻度的成对不变式(§10.3 规则 3:OCCT 恒写\n * SI_UNIT(.MILLI.,.METRE.),坐标预缩放后声明必须跟上)由库面统一保证,op 里不复刻。\n *\n * **引擎门**:STEP 的装配层级走 XCAF,只有 occt 具备(§2.3),故与\n * `api/export-brep.ts:32` 同构地断言 `assertEngineFor('exportStep', ['occt'])`——\n * 在触碰任何句柄之前报出 `E_BREP_UNSUPPORTED` 并带上当前引擎名,不补桩、不回退。\n * 非 occt 引擎下**不得**让调用落进 `getBrepApi()` / `getOcctKernel()` 的未初始化\n * 异常,也不得把 brepkit 句柄交给 occt 内核(句柄不得跨引擎传递)。\n *\n * **宿主门**:与其余导出命令同轴(§2.5),仅 `'node'` 宿主开放,且宿主门在引擎门\n * 之前。理由:`.fai.js` 可由 AI 生成任意代码、属不受信输入,导出把「往哪写、写几份、\n * 写什么」的决定权交给脚本文本;浏览器 / 小程序里要导出模型必须由宿主入口发起。\n * 断言写在函数体第一行,所以脚本面 `cad.*` 与 TS 直连同一函数都被同一门禁覆盖。\n *\n * **层级入口**:入参是 `Shape` 或 `CompoundShape`(§2.1——`cad.assembly` / `cad.group`\n * 的产物),`cad.exportStep(compound)` 即脚本面的层级导出入口;成员拆解口径见\n * `api/internal/export-members.ts`(对齐 `node-host/cli.ts#writeAssemblyStep`)。\n *\n * **条目按格式分派**(定式 4):step 吃 `solid`(保留精确 BREP 拓扑,缺则库面用\n * `mesh` 重建,`brep/export/step.ts:83`),所以活句柄存在就给 `solid`,没有才给\n * `mesh`——与 `cli.ts#writeOutput`(`:744-758`)同口径。空装配**显式报错**,不落\n * 空文件(对齐 `api/export-stl.ts` 的 `E_EXPORT_STL_EMPTY` 口径)。\n */\n\nimport type { Shape } from '../mesh/types'\nimport type { CompoundShape } from '../shape'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { UnitName } from '../units'\nimport { brepOf } from '../shape'\nimport { exportModelSync, type ExportEntry } from '../brep/export/export-model'\nimport { exportMembersOf, type ExportMember } from './internal/export-members'\nimport { assertEngineFor, assertHostFor } from './internal/l3-bridge'\n\n/** `cad.exportStep` 选项。 */\nexport interface ExportStepOptions {\n /**\n * 文件里声明的长度单位(缺省 `'mm'`)。语义与库面 `ExportOptions.unit` 一致:\n * 实现负责把坐标换算到该刻度,并与声明**成对**写出(`export-model.ts` §10.3)。\n */\n unit?: UnitName\n}\n\n/** 一个成员 → step 条目:有活句柄给精确 BREP,没有才退回自带三角载荷。 */\nfunction stepEntryOf(member: ExportMember): ExportEntry | undefined {\n const handle = brepOf(member.shape) as BrepHandle | undefined\n const positions = member.shape?.positions\n const indices = member.shape?.indices\n const hasMesh = !!positions && !!indices && positions.length > 0 && indices.length > 0\n const payload: ExportEntry | undefined = handle\n ? { solid: handle }\n : hasMesh\n ? { mesh: { positions, indices } }\n : undefined\n if (!payload) return undefined\n return {\n ...payload,\n ...(member.name === undefined ? {} : { name: member.name }),\n ...(member.color === undefined ? {} : { color: member.color }),\n }\n}\n\n/**\n * 导出 STEP 文本(与 `cad.import_step` 成对的导出侧)。\n * @group 导出\n * @inputs 1\n * @async false\n * @qual ok\n * @name exportStep\n * @note 薄壳 op:条目构造后一律交库面 `exportModelSync(entries,'step',{unit})` 序列化,\n * 故同一入参下脚本面文本与库面**逐字节一致**(同一真源,不另起写出通道)。\n * 返回**纯文本**(ISO-10303-21),由宿主写入 `.step` / `.stp` 文件——内核不 import\n * fs。`unit` 只声明单位,坐标换算与声明由库面成对完成(缺省 mm)。\n * 入参可为单件 Shape 或装配 compound(`cad.assembly` / `cad.group` 产物),\n * compound 逐成员导出并带上成员名与 `memberColors`;空装配显式报\n * E_EXPORT_STEP_EMPTY,不落空文件。\n * **双门**:宿主门仅 `'node'`(browser / weapp / 未声明报 E_HOST_UNSUPPORTED),\n * 引擎门仅 `occt`(装配层级走 XCAF;非 occt 报 E_BREP_UNSUPPORTED)。门序固定\n * 为宿主门 → 引擎门 → 实现体,两级都在触碰任何句柄之前。\n * @returns string STEP(ISO-10303-21)文本。\n * @param shape - 目标几何(单件 Shape 或装配 compound)。type:Shape|CompoundShape required:true\n * @param options.unit - 文件里声明的长度单位,缺省 mm(坐标随之换算)。type:UnitName\n * @example\n * const text = cad.exportStep(part0)\n * const asm = cad.exportStep(asm1, { unit: 'inch' })\n */\nexport function exportStep(shape: Shape | CompoundShape, options?: ExportStepOptions): string {\n // 门序固定:宿主门 → 引擎门(都在读 Shape 槽 / 触碰内核之前)。\n assertHostFor('exportStep', ['node'])\n assertEngineFor('exportStep', ['occt'])\n const entries: ExportEntry[] = []\n for (const member of exportMembersOf(shape)) {\n const entry = stepEntryOf(member)\n if (entry) entries.push(entry)\n }\n if (entries.length === 0) {\n throw new Error('E_EXPORT_STEP_EMPTY: exportStep input has no exportable member (empty assembly or payload-less members)')\n }\n const buffer = exportModelSync(entries, 'step', options?.unit === undefined ? undefined : { unit: options.unit })\n const text = new TextDecoder().decode(new Uint8Array(buffer))\n if (text.length === 0) {\n throw new Error('E_EXPORT_STEP_EMPTY: occt produced no STEP text')\n }\n return text\n}\n"]}
@@ -15,6 +15,12 @@
15
15
  * 与既有能力的分工(方案 §4.5 去重表):`import_brep` / `import_step` 是**导入**侧;
16
16
  * 本 op 是导出侧,与宿主 `exportModel('stl')` 同一序列化器,脚本面因此首次拿到
17
17
  * 「导入 ↔ 导出」成对能力。
18
+ *
19
+ * **宿主门**:本 op 只在 `'node'` 宿主开放。`.fai.js` 可由 AI 生成任意代码、属
20
+ * 不受信输入,导出把「往哪写、写几份、写什么」的决定权交给脚本文本;浏览器 /
21
+ * 小程序里要导出模型必须由宿主入口触发(按钮或库面字节通道)。门禁写在函数体
22
+ * 第一行(`assertHostFor`),因此脚本面与库面直连同一函数都被同一门禁覆盖,
23
+ * 且门在读取 Shape 载荷之前。见 `cad-runtime/ports.ts#HostEnv`。
18
24
  */
19
25
  import type { Shape } from '../mesh/types.js';
20
26
  /** `cad.exportStl` 选项。 */
@@ -38,6 +44,8 @@ export interface ExportStlOptions {
38
44
  * 不走原生二次三角化,产物与显示 mesh 逐三角形一致。空 mesh(如
39
45
  * `cad.halfSpace` 产的无界体)显式报 E_EXPORT_STL_EMPTY,不返回空文件。
40
46
  * 返回值是**纯数据**(二进制 `Uint8Array` 或 ASCII 文本),由宿主写入文件。
47
+ * **宿主门**:仅 `'node'` 宿主可执行;browser / weapp / 未声明宿主报
48
+ * E_HOST_UNSUPPORTED(门在读取载荷之前),浏览器与小程序里导出走宿主入口。
41
49
  * @returns Uint8Array 二进制 STL 字节;`options.ascii === true` 时返回 ASCII 文本 string。
42
50
  * @param shape - 目标几何(brep 或 mesh 链路的 Shape)。type:Shape required:true
43
51
  * @param options.ascii - true = ASCII STL 文本,缺省 = 二进制。type:boolean
@@ -1 +1 @@
1
- {"version":3,"file":"export-stl.d.ts","sourceRoot":"","sources":["../../src/api/export-stl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAG1C,0BAA0B;AAC1B,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAmED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,UAAU,GAAG,MAAM,CAOvF"}
1
+ {"version":3,"file":"export-stl.d.ts","sourceRoot":"","sources":["../../src/api/export-stl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAK1C,0BAA0B;AAC1B,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAqED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,UAAU,GAAG,MAAM,CAWvF"}
@@ -15,8 +15,16 @@
15
15
  * 与既有能力的分工(方案 §4.5 去重表):`import_brep` / `import_step` 是**导入**侧;
16
16
  * 本 op 是导出侧,与宿主 `exportModel('stl')` 同一序列化器,脚本面因此首次拿到
17
17
  * 「导入 ↔ 导出」成对能力。
18
+ *
19
+ * **宿主门**:本 op 只在 `'node'` 宿主开放。`.fai.js` 可由 AI 生成任意代码、属
20
+ * 不受信输入,导出把「往哪写、写几份、写什么」的决定权交给脚本文本;浏览器 /
21
+ * 小程序里要导出模型必须由宿主入口触发(按钮或库面字节通道)。门禁写在函数体
22
+ * 第一行(`assertHostFor`),因此脚本面与库面直连同一函数都被同一门禁覆盖,
23
+ * 且门在读取 Shape 载荷之前。见 `cad-runtime/ports.ts#HostEnv`。
18
24
  */
19
- import { buildStlBufferFromMesh } from '../brep/export/stl.js';
25
+ import { buildStlBufferFromMesh, bakeMatrix12ToPositions } from '../brep/export/stl.js';
26
+ import { transformToMatrix12 } from '../brep/export/export-model.js';
27
+ import { assertHostFor } from './internal/l3-bridge.js';
20
28
  /** 校验输入 Shape 带可用的三角载荷。 */
21
29
  function meshOf(shape) {
22
30
  const positions = shape?.positions;
@@ -52,16 +60,17 @@ function facetNormal(positions, ia, ib, ic) {
52
60
  return [nx, ny, nz];
53
61
  }
54
62
  /** ASCII STL 文本(与二进制形态同一批三角形、同一法向规则;坐标以 mm 写出)。 */
55
- function asciiStl(positions, indices, name) {
63
+ function asciiStl(positions, indices, name, transform) {
64
+ const pos = transform ? bakeMatrix12ToPositions(positions, transform) : positions;
56
65
  const out = [`solid ${name}`];
57
66
  for (let i = 0; i < indices.length; i += 3) {
58
67
  const ia = indices[i];
59
68
  const ib = indices[i + 1];
60
69
  const ic = indices[i + 2];
61
- const [nx, ny, nz] = facetNormal(positions, ia, ib, ic);
70
+ const [nx, ny, nz] = facetNormal(pos, ia, ib, ic);
62
71
  out.push(` facet normal ${nx} ${ny} ${nz}`, ' outer loop');
63
72
  for (const v of [ia, ib, ic]) {
64
- out.push(` vertex ${positions[v * 3]} ${positions[v * 3 + 1]} ${positions[v * 3 + 2]}`);
73
+ out.push(` vertex ${pos[v * 3]} ${pos[v * 3 + 1]} ${pos[v * 3 + 2]}`);
65
74
  }
66
75
  out.push(' endloop', ' endfacet');
67
76
  }
@@ -79,6 +88,8 @@ function asciiStl(positions, indices, name) {
79
88
  * 不走原生二次三角化,产物与显示 mesh 逐三角形一致。空 mesh(如
80
89
  * `cad.halfSpace` 产的无界体)显式报 E_EXPORT_STL_EMPTY,不返回空文件。
81
90
  * 返回值是**纯数据**(二进制 `Uint8Array` 或 ASCII 文本),由宿主写入文件。
91
+ * **宿主门**:仅 `'node'` 宿主可执行;browser / weapp / 未声明宿主报
92
+ * E_HOST_UNSUPPORTED(门在读取载荷之前),浏览器与小程序里导出走宿主入口。
82
93
  * @returns Uint8Array 二进制 STL 字节;`options.ascii === true` 时返回 ASCII 文本 string。
83
94
  * @param shape - 目标几何(brep 或 mesh 链路的 Shape)。type:Shape required:true
84
95
  * @param options.ascii - true = ASCII STL 文本,缺省 = 二进制。type:boolean
@@ -88,12 +99,16 @@ function asciiStl(positions, indices, name) {
88
99
  * const text = cad.exportStl(part0, { ascii: true, name: 'bracket' })
89
100
  */
90
101
  export function exportStl(shape, options) {
102
+ // 宿主门在实现体最前:非 node 宿主(browser / weapp / 未声明)一律先报
103
+ // E_HOST_UNSUPPORTED,不读取 Shape 载荷、不产任何字节。
104
+ assertHostFor('exportStl', ['node']);
91
105
  const { positions, indices } = meshOf(shape);
92
106
  const name = options?.name ?? 'Faicad STL';
93
- // 坐标一律以 mm 写出(与宿主 exportModel('stl') 的 unit 语义一致——
94
- // 单位换算在宿主侧按当前文档单位完成,本 op 不做缩放)。
107
+ // 顶点烘焙(方案 §2.1 / §5 步骤 5):Shape.transform 写回的位姿在此烘焙进每个顶点。
108
+ // 坐标仍一律以 mm 写出(与宿主 exportModel('stl') 的 unit 语义一致,单位换算在宿主侧完成)。
109
+ const tf = shape.transform ? transformToMatrix12(shape.transform) : null;
95
110
  if (options?.ascii === true)
96
- return asciiStl(positions, indices, name);
97
- return new Uint8Array(buildStlBufferFromMesh(positions, indices, name));
111
+ return asciiStl(positions, indices, name, tf ?? undefined);
112
+ return new Uint8Array(buildStlBufferFromMesh(positions, indices, name, tf ?? undefined));
98
113
  }
99
114
  //# sourceMappingURL=export-stl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"export-stl.js","sourceRoot":"","sources":["../../src/api/export-stl.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api exportStl — STL 导出(中立 op:纯数据序列化,无内核调用)\n *\n * 中立性的判据(方案 §4.4 决策树):实现**不触达任何引擎** —— 它只读 faijs Shape\n * 自带的三角载荷(`positions` / `indices`),不 import `occt-kernel/*` 或\n * `brepkit-kernel/*`。mesh 链路与 brep 链路的 Shape 都带该载荷(brep 侧由\n * `solidToShape` 即时三角化填好),故两条链路同一份实现,无引擎分支。\n *\n * 为什么不是平台 op:occt-wasm 有原生 `exportStl`,但本仓的 BREP 三角化统一走\n * L1 `meshShape`(`brep/brep-ops.ts` 的 `solidToShape`)——Shape 上的载荷就是当前\n * 用户看到的 mesh(规则 1)。走原生 `exportStl` 会**二次三角化**,产出与显示/拓扑\n * 不一致的第二份 mesh。这里复用现有唯一序列化器\n * `brep/export/stl.ts#buildStlBufferFromMesh`(宿主导出链同一真值来源)。\n *\n * 与既有能力的分工(方案 §4.5 去重表):`import_brep` / `import_step` 是**导入**侧;\n * 本 op 是导出侧,与宿主 `exportModel('stl')` 同一序列化器,脚本面因此首次拿到\n * 「导入 ↔ 导出」成对能力。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { buildStlBufferFromMesh } from '../brep/export/stl'\n\n/** `cad.exportStl` 选项。 */\nexport interface ExportStlOptions {\n /**\n * `true` → 返回 **ASCII** STL 文本;缺省/`false` → 返回 **binary** STL 字节\n * (`Uint8Array`,84 + 50×三角形数 字节)。\n */\n ascii?: boolean\n /** 实体名(ASCII 形态的 `solid <name>` / binary 形态的 80 字节头;缺省 'Faicad STL')。 */\n name?: string\n}\n\n/** 校验输入 Shape 带可用的三角载荷。 */\nfunction meshOf(shape: Shape): { positions: Float32Array; indices: Uint32Array } {\n const positions = shape?.positions\n const indices = shape?.indices\n if (!positions || !indices) {\n throw new Error('E_EXPORT_STL_NO_MESH: exportStl requires a shape carrying mesh payload')\n }\n if (indices.length === 0) {\n throw new Error('E_EXPORT_STL_EMPTY: shape has no triangles to export')\n }\n return { positions, indices }\n}\n\n/** 单位化叉积法向(退化三角形给 0 向量,与二进制形态同一规则)。 */\nfunction facetNormal(\n positions: Float32Array,\n ia: number,\n ib: number,\n ic: number,\n): [number, number, number] {\n const ax = positions[ia * 3]!\n const ay = positions[ia * 3 + 1]!\n const az = positions[ia * 3 + 2]!\n const ux = positions[ib * 3]! - ax\n const uy = positions[ib * 3 + 1]! - ay\n const uz = positions[ib * 3 + 2]! - az\n const vx = positions[ic * 3]! - ax\n const vy = positions[ic * 3 + 1]! - ay\n const vz = positions[ic * 3 + 2]! - az\n let nx = uy * vz - uz * vy\n let ny = uz * vx - ux * vz\n let nz = ux * vy - uy * vx\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz)\n if (len > 0) {\n nx /= len\n ny /= len\n nz /= len\n }\n return [nx, ny, nz]\n}\n\n/** ASCII STL 文本(与二进制形态同一批三角形、同一法向规则;坐标以 mm 写出)。 */\nfunction asciiStl(\n positions: Float32Array,\n indices: Uint32Array,\n name: string,\n): string {\n const out: string[] = [`solid ${name}`]\n for (let i = 0; i < indices.length; i += 3) {\n const ia = indices[i]!\n const ib = indices[i + 1]!\n const ic = indices[i + 2]!\n const [nx, ny, nz] = facetNormal(positions, ia, ib, ic)\n out.push(` facet normal ${nx} ${ny} ${nz}`, ' outer loop')\n for (const v of [ia, ib, ic]) {\n out.push(\n ` vertex ${positions[v * 3]!} ${positions[v * 3 + 1]!} ${positions[v * 3 + 2]!}`,\n )\n }\n out.push(' endloop', ' endfacet')\n }\n out.push(`endsolid ${name}`)\n return out.join('\\n')\n}\n\n/**\n * 导出 STL(二进制 / ASCII 双形态)。\n * @group 导出\n * @inputs 1\n * @async false\n * @qual ok\n * @name exportStl\n * @note 中立 op:只序列化 Shape 自带的三角载荷(brep 与 mesh 链路同一份实现),\n * 不走原生二次三角化,产物与显示 mesh 逐三角形一致。空 mesh(如\n * `cad.halfSpace` 产的无界体)显式报 E_EXPORT_STL_EMPTY,不返回空文件。\n * 返回值是**纯数据**(二进制 `Uint8Array` 或 ASCII 文本),由宿主写入文件。\n * @returns Uint8Array 二进制 STL 字节;`options.ascii === true` 时返回 ASCII 文本 string。\n * @param shape - 目标几何(brep 或 mesh 链路的 Shape)。type:Shape required:true\n * @param options.ascii - true = ASCII STL 文本,缺省 = 二进制。type:boolean\n * @param options.name - 实体名(缺省 'Faicad STL')。type:string\n * @example\n * const bytes = cad.exportStl(part0)\n * const text = cad.exportStl(part0, { ascii: true, name: 'bracket' })\n */\nexport function exportStl(shape: Shape, options?: ExportStlOptions): Uint8Array | string {\n const { positions, indices } = meshOf(shape)\n const name = options?.name ?? 'Faicad STL'\n // 坐标一律以 mm 写出(与宿主 exportModel('stl') 的 unit 语义一致——\n // 单位换算在宿主侧按当前文档单位完成,本 op 不做缩放)。\n if (options?.ascii === true) return asciiStl(positions, indices, name)\n return new Uint8Array(buildStlBufferFromMesh(positions, indices, name))\n}\n"]}
1
+ {"version":3,"file":"export-stl.js","sourceRoot":"","sources":["../../src/api/export-stl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAapD,2BAA2B;AAC3B,SAAS,MAAM,CAAC,KAAY;IAC1B,MAAM,SAAS,GAAG,KAAK,EAAE,SAAS,CAAA;IAClC,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,CAAA;IAC9B,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAA;IAC3F,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;IACzE,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAA;AAC/B,CAAC;AAED,uCAAuC;AACvC,SAAS,WAAW,CAClB,SAAuB,EACvB,EAAU,EACV,EAAU,EACV,EAAU;IAEV,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAE,CAAA;IAC7B,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAE,CAAA;IACjC,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAE,CAAA;IACjC,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAE,GAAG,EAAE,CAAA;IAClC,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAE,GAAG,EAAE,CAAA;IACtC,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAE,GAAG,EAAE,CAAA;IACtC,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAE,GAAG,EAAE,CAAA;IAClC,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAE,GAAG,EAAE,CAAA;IACtC,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAE,GAAG,EAAE,CAAA;IACtC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;IAC1B,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;IAC1B,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;IAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;IAClD,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QACZ,EAAE,IAAI,GAAG,CAAA;QACT,EAAE,IAAI,GAAG,CAAA;QACT,EAAE,IAAI,GAAG,CAAA;IACX,CAAC;IACD,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;AACrB,CAAC;AAED,mDAAmD;AACnD,SAAS,QAAQ,CACf,SAAuB,EACvB,OAAoB,EACpB,IAAY,EACZ,SAAoB;IAEpB,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,uBAAuB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACjF,MAAM,GAAG,GAAa,CAAC,SAAS,IAAI,EAAE,CAAC,CAAA;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAE,CAAA;QACtB,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAE,CAAA;QAC1B,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAE,CAAA;QAC1B,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QACjD,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,gBAAgB,CAAC,CAAA;QAC9D,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7B,GAAG,CAAC,IAAI,CACN,gBAAgB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAE,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE,EAAE,CACpE,CAAA;QACH,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IACvC,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAA;IAC5B,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACvB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,SAAS,CAAC,KAAY,EAAE,OAA0B;IAChE,iDAAiD;IACjD,0CAA0C;IAC1C,aAAa,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IACpC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5C,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,YAAY,CAAA;IAC1C,0DAA0D;IAC1D,+DAA+D;IAC/D,MAAM,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACxE,IAAI,OAAO,EAAE,KAAK,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,SAAS,CAAC,CAAA;IACvF,OAAO,IAAI,UAAU,CAAC,sBAAsB,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,SAAS,CAAC,CAAC,CAAA;AAC1F,CAAC","sourcesContent":["/**\n * api exportStl — STL 导出(中立 op:纯数据序列化,无内核调用)\n *\n * 中立性的判据(方案 §4.4 决策树):实现**不触达任何引擎** —— 它只读 faijs Shape\n * 自带的三角载荷(`positions` / `indices`),不 import `occt-kernel/*` 或\n * `brepkit-kernel/*`。mesh 链路与 brep 链路的 Shape 都带该载荷(brep 侧由\n * `solidToShape` 即时三角化填好),故两条链路同一份实现,无引擎分支。\n *\n * 为什么不是平台 op:occt-wasm 有原生 `exportStl`,但本仓的 BREP 三角化统一走\n * L1 `meshShape`(`brep/brep-ops.ts` 的 `solidToShape`)——Shape 上的载荷就是当前\n * 用户看到的 mesh(规则 1)。走原生 `exportStl` 会**二次三角化**,产出与显示/拓扑\n * 不一致的第二份 mesh。这里复用现有唯一序列化器\n * `brep/export/stl.ts#buildStlBufferFromMesh`(宿主导出链同一真值来源)。\n *\n * 与既有能力的分工(方案 §4.5 去重表):`import_brep` / `import_step` 是**导入**侧;\n * 本 op 是导出侧,与宿主 `exportModel('stl')` 同一序列化器,脚本面因此首次拿到\n * 「导入 ↔ 导出」成对能力。\n *\n * **宿主门**:本 op 只在 `'node'` 宿主开放。`.fai.js` 可由 AI 生成任意代码、属\n * 不受信输入,导出把「往哪写、写几份、写什么」的决定权交给脚本文本;浏览器 /\n * 小程序里要导出模型必须由宿主入口触发(按钮或库面字节通道)。门禁写在函数体\n * 第一行(`assertHostFor`),因此脚本面与库面直连同一函数都被同一门禁覆盖,\n * 且门在读取 Shape 载荷之前。见 `cad-runtime/ports.ts#HostEnv`。\n */\n\nimport type { Shape } from '../mesh/types'\nimport { buildStlBufferFromMesh, bakeMatrix12ToPositions } from '../brep/export/stl'\nimport { transformToMatrix12 } from '../brep/export/export-model'\nimport { assertHostFor } from './internal/l3-bridge'\n\n/** `cad.exportStl` 选项。 */\nexport interface ExportStlOptions {\n /**\n * `true` → 返回 **ASCII** STL 文本;缺省/`false` → 返回 **binary** STL 字节\n * (`Uint8Array`,84 + 50×三角形数 字节)。\n */\n ascii?: boolean\n /** 实体名(ASCII 形态的 `solid <name>` / binary 形态的 80 字节头;缺省 'Faicad STL')。 */\n name?: string\n}\n\n/** 校验输入 Shape 带可用的三角载荷。 */\nfunction meshOf(shape: Shape): { positions: Float32Array; indices: Uint32Array } {\n const positions = shape?.positions\n const indices = shape?.indices\n if (!positions || !indices) {\n throw new Error('E_EXPORT_STL_NO_MESH: exportStl requires a shape carrying mesh payload')\n }\n if (indices.length === 0) {\n throw new Error('E_EXPORT_STL_EMPTY: shape has no triangles to export')\n }\n return { positions, indices }\n}\n\n/** 单位化叉积法向(退化三角形给 0 向量,与二进制形态同一规则)。 */\nfunction facetNormal(\n positions: Float32Array,\n ia: number,\n ib: number,\n ic: number,\n): [number, number, number] {\n const ax = positions[ia * 3]!\n const ay = positions[ia * 3 + 1]!\n const az = positions[ia * 3 + 2]!\n const ux = positions[ib * 3]! - ax\n const uy = positions[ib * 3 + 1]! - ay\n const uz = positions[ib * 3 + 2]! - az\n const vx = positions[ic * 3]! - ax\n const vy = positions[ic * 3 + 1]! - ay\n const vz = positions[ic * 3 + 2]! - az\n let nx = uy * vz - uz * vy\n let ny = uz * vx - ux * vz\n let nz = ux * vy - uy * vx\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz)\n if (len > 0) {\n nx /= len\n ny /= len\n nz /= len\n }\n return [nx, ny, nz]\n}\n\n/** ASCII STL 文本(与二进制形态同一批三角形、同一法向规则;坐标以 mm 写出)。 */\nfunction asciiStl(\n positions: Float32Array,\n indices: Uint32Array,\n name: string,\n transform?: number[],\n): string {\n const pos = transform ? bakeMatrix12ToPositions(positions, transform) : positions\n const out: string[] = [`solid ${name}`]\n for (let i = 0; i < indices.length; i += 3) {\n const ia = indices[i]!\n const ib = indices[i + 1]!\n const ic = indices[i + 2]!\n const [nx, ny, nz] = facetNormal(pos, ia, ib, ic)\n out.push(` facet normal ${nx} ${ny} ${nz}`, ' outer loop')\n for (const v of [ia, ib, ic]) {\n out.push(\n ` vertex ${pos[v * 3]!} ${pos[v * 3 + 1]!} ${pos[v * 3 + 2]!}`,\n )\n }\n out.push(' endloop', ' endfacet')\n }\n out.push(`endsolid ${name}`)\n return out.join('\\n')\n}\n\n/**\n * 导出 STL(二进制 / ASCII 双形态)。\n * @group 导出\n * @inputs 1\n * @async false\n * @qual ok\n * @name exportStl\n * @note 中立 op:只序列化 Shape 自带的三角载荷(brep 与 mesh 链路同一份实现),\n * 不走原生二次三角化,产物与显示 mesh 逐三角形一致。空 mesh(如\n * `cad.halfSpace` 产的无界体)显式报 E_EXPORT_STL_EMPTY,不返回空文件。\n * 返回值是**纯数据**(二进制 `Uint8Array` 或 ASCII 文本),由宿主写入文件。\n * **宿主门**:仅 `'node'` 宿主可执行;browser / weapp / 未声明宿主报\n * E_HOST_UNSUPPORTED(门在读取载荷之前),浏览器与小程序里导出走宿主入口。\n * @returns Uint8Array 二进制 STL 字节;`options.ascii === true` 时返回 ASCII 文本 string。\n * @param shape - 目标几何(brep 或 mesh 链路的 Shape)。type:Shape required:true\n * @param options.ascii - true = ASCII STL 文本,缺省 = 二进制。type:boolean\n * @param options.name - 实体名(缺省 'Faicad STL')。type:string\n * @example\n * const bytes = cad.exportStl(part0)\n * const text = cad.exportStl(part0, { ascii: true, name: 'bracket' })\n */\nexport function exportStl(shape: Shape, options?: ExportStlOptions): Uint8Array | string {\n // 宿主门在实现体最前:非 node 宿主(browser / weapp / 未声明)一律先报\n // E_HOST_UNSUPPORTED,不读取 Shape 载荷、不产任何字节。\n assertHostFor('exportStl', ['node'])\n const { positions, indices } = meshOf(shape)\n const name = options?.name ?? 'Faicad STL'\n // 顶点烘焙(方案 §2.1 / §5 步骤 5):Shape.transform 写回的位姿在此烘焙进每个顶点。\n // 坐标仍一律以 mm 写出(与宿主 exportModel('stl') 的 unit 语义一致,单位换算在宿主侧完成)。\n const tf = shape.transform ? transformToMatrix12(shape.transform) : null\n if (options?.ascii === true) return asciiStl(positions, indices, name, tf ?? undefined)\n return new Uint8Array(buildStlBufferFromMesh(positions, indices, name, tf ?? undefined))\n}\n"]}
@@ -16,7 +16,7 @@
16
16
  * - `reverseShape` 声明 `engines: ['occt']` —— 实证收窄:brepkit 实测在 **op 级**
17
17
  * 失败(`invalid solid handle: index N is out of bounds`,callee = reverseShape,
18
18
  * 非输入构造侧),静态门须在执行前拒绝。
19
- * - 其余五条保持中立(声明 `capabilities: ['directEdit']`,无 engines)。
19
+ * - 其余五条保持中立(无 engines)。
20
20
  * 注意 `unifySameDomain` 在 brepkit 上**可用但语义有差**(会把体重新居中),
21
21
  * 未收窄 —— 缺证据表明它不可用,不擅自扩大范围。
22
22
  *
@@ -1 +1 @@
1
- {"version":3,"file":"feature-repair.d.ts","sourceRoot":"","sources":["../../src/api/feature-repair.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAM1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAgDrD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS;;CAYpB,CAAA;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,YAAY;;CAUvB,CAAA;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe;;CAQ1B,CAAA;AAEF,6CAA6C;AAC7C,MAAM,WAAW,SAAS;IACxB,mBAAmB;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,GAAG;;CAQd,CAAA;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc;;CAQzB,CAAA;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB;;CAU9B,CAAA"}
1
+ {"version":3,"file":"feature-repair.d.ts","sourceRoot":"","sources":["../../src/api/feature-repair.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAM1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAgDrD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS;;CAWpB,CAAA;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,YAAY;;CASvB,CAAA;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe;;CAO1B,CAAA;AAEF,6CAA6C;AAC7C,MAAM,WAAW,SAAS;IACxB,mBAAmB;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,GAAG;;CAOd,CAAA;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc;;CAOzB,CAAA;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB;;CAS9B,CAAA"}
@@ -16,7 +16,7 @@
16
16
  * - `reverseShape` 声明 `engines: ['occt']` —— 实证收窄:brepkit 实测在 **op 级**
17
17
  * 失败(`invalid solid handle: index N is out of bounds`,callee = reverseShape,
18
18
  * 非输入构造侧),静态门须在执行前拒绝。
19
- * - 其余五条保持中立(声明 `capabilities: ['directEdit']`,无 engines)。
19
+ * - 其余五条保持中立(无 engines)。
20
20
  * 注意 `unifySameDomain` 在 brepkit 上**可用但语义有差**(会把体重新居中),
21
21
  * 未收窄 —— 缺证据表明它不可用,不擅自扩大范围。
22
22
  *
@@ -84,7 +84,6 @@ const kernelNaming = { kind: 'kernel', newFaces: { via: 'byAdjacency' } };
84
84
  * const base = await cad.defeature(part0, [cad.faceRef(part0, 5)])
85
85
  */
86
86
  export const defeature = defineOp({
87
- capabilities: ['directEdit'],
88
87
  brep(input, faces) {
89
88
  if (!Array.isArray(faces) || faces.length === 0) {
90
89
  throw new Error('E_DEFEATURE_NO_FACES: defeature requires at least one FaceTopoRef');
@@ -113,7 +112,6 @@ export const defeature = defineOp({
113
112
  * const flipped = await cad.reverseShape(sh)
114
113
  */
115
114
  export const reverseShape = defineOp({
116
- capabilities: ['directEdit'],
117
115
  // 实证收窄(2026-09-24):brepkit op 级失败 → 静态门提前拒绝。
118
116
  engines: ['occt'],
119
117
  brep(input) {
@@ -137,7 +135,6 @@ export const reverseShape = defineOp({
137
135
  * const merged = await cad.unifySameDomain(part0)
138
136
  */
139
137
  export const unifySameDomain = defineOp({
140
- capabilities: ['directEdit'],
141
138
  brep(input) {
142
139
  const kernel = getBrepApi();
143
140
  const solid = requireBrep(input, 'unifySameDomain');
@@ -160,7 +157,6 @@ export const unifySameDomain = defineOp({
160
157
  * const shellShape = await cad.sew([f1, f2, f3], { tolerance: 1e-5 })
161
158
  */
162
159
  export const sew = defineOp({
163
- capabilities: ['directEdit'],
164
160
  brep(shapes, params) {
165
161
  const kernel = getBrepApi();
166
162
  const handles = borrowHandles(shapes, 'sew');
@@ -183,7 +179,6 @@ export const sew = defineOp({
183
179
  * const solid = await cad.sewAndSolidify([f1, f2, f3, f4, f5, f6])
184
180
  */
185
181
  export const sewAndSolidify = defineOp({
186
- capabilities: ['directEdit'],
187
182
  brep(shapes, params) {
188
183
  const kernel = getBrepApi();
189
184
  const handles = borrowHandles(shapes, 'sewAndSolidify');
@@ -206,7 +201,6 @@ export const sewAndSolidify = defineOp({
206
201
  * const plain = await cad.removeHolesFromFace(faceWithHoles)
207
202
  */
208
203
  export const removeHolesFromFace = defineOp({
209
- capabilities: ['directEdit'],
210
204
  brep(face) {
211
205
  if (!face)
212
206
  throw new Error('E_REMOVEHOLES_NO_FACE: removeHolesFromFace requires a face shape');
@@ -1 +1 @@
1
- {"version":3,"file":"feature-repair.js","sourceRoot":"","sources":["../../src/api/feature-repair.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api feature-repair — L1 薄包装族(手写 op,Phase 5)\n *\n * 六条 L1 已有动作的手写薄包装,全部走 `getBrepApi()`(D12):\n * - `defeature(shape, faces)` — 移除特征面(孔/凸台等)\n * - `removeHolesFromFace(face)` — 移除面上的孔\n * - `reverseShape(shape)` — 反转壳体朝向 —— **occt-only**(见下)\n * - `unifySameDomain(shape)` — 合并同域面/边\n * - `sew(shapes, tolerance?)` — 缝合壳\n * - `sewAndSolidify(shapes, tolerance?)` — 缝合并固化为实体\n *\n * 每条都极薄:解析入参 → 直调 L1 → 收养。选面口径与 `shell`/`draft` 一致\n * (FaceTopoRef[],设计原则 4)。\n *\n * 引擎声明(**逐条判定,不整族一刀切**):\n * - `reverseShape` 声明 `engines: ['occt']` —— 实证收窄:brepkit 实测在 **op 级**\n * 失败(`invalid solid handle: index N is out of bounds`,callee = reverseShape,\n * 非输入构造侧),静态门须在执行前拒绝。\n * - 其余五条保持中立(声明 `capabilities: ['directEdit']`,无 engines)。\n * 注意 `unifySameDomain` 在 brepkit 上**可用但语义有差**(会把体重新居中),\n * 未收窄 —— 缺证据表明它不可用,不擅自扩大范围。\n *\n * 未覆盖(诚实留档,本轮未验):`defeature` / `sew` / `sewAndSolidify` /\n * `removeHolesFromFace` 在 brepkit 上的 op 级行为未取得干净证据(探针的面输入\n * 先撞到 faceRef/输入构造侧限制),故不做引擎声明。\n */\n\nimport type { Shape } from '../mesh/types'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { brepOf, fromBrep } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { FaceTopoRef } from '../topology/naming'\nimport { resolveTopoRef, TopoRefError } from '../topology/naming'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { buildEdgeResolutionContext } from './topo-resolve'\n\ntype ProvenanceLike = Provenance\n\n/** BREP 输入守卫:取 BREP 句柄,无则报错。 */\nfunction requireBrep(input: Shape, op: string): BrepHandle {\n const handle = brepOf(input) as BrepHandle | undefined\n if (!handle) throw new Error(`E_${op.toUpperCase()}_NO_BREP: ${op} input is not BREP`)\n return handle\n}\n\n/** 解析 FaceTopoRef[] → 句柄数组(shell/draft 同款口径)。 */\nfunction resolveFaces(kernel: ReturnType<typeof getBrepApi>, input: Shape, refs: FaceTopoRef[], op: string): BrepHandle[] {\n const ctx = buildEdgeResolutionContext(kernel, input as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', `${op}: input has no BREP naming context`)\n return refs.map((ref) => {\n if (!ref || (ref as { kind?: unknown }).kind !== 'face') {\n throw new Error(`E_${op.toUpperCase()}_BAD_FACE_REF: every faces entry must be a FaceTopoRef (cad.faceRef)`)\n }\n const r = resolveTopoRef(ref, ctx)\n if (r.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', `${op}: face resolved without handle (${ref.origin}/${ref.role})`)\n }\n return r.handle as BrepHandle\n })\n}\n\n/** 借入一组输入 Shape → 句柄数组(sew 族)。 */\nfunction borrowHandles(shapes: Shape[], op: string): BrepHandle[] {\n if (!Array.isArray(shapes) || shapes.length === 0) {\n throw new Error(`E_${op.toUpperCase()}_NO_SHAPES: ${op} requires a non-empty array of shapes`)\n }\n return shapes.map((s) => {\n const h = brepOf(s) as BrepHandle | undefined\n if (!h) throw new Error(`E_${op.toUpperCase()}_NO_BREP: ${op} input shape is not BREP`)\n return h\n })\n}\n\nfunction adopt(kernel: ReturnType<typeof getBrepApi>, handle: BrepHandle): Shape {\n return fromBrep(solidToShape(kernel, handle), { solid: handle })\n}\n\nconst kernelNaming = { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as ProvenanceLike\n\n/**\n * 移除特征面(孔/凸台等),恢复基础形状。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name defeature\n * @note 中立 op:L1 defeature 两引擎同实现。仅 BREP 可用。\n * @returns Shape 移除特征后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param faces - 要移除的面(FaceTopoRef[],cad.faceRef 产物)。type:FaceTopoRef[] required:true\n * @example\n * const base = await cad.defeature(part0, [cad.faceRef(part0, 5)])\n */\nexport const defeature = defineOp({\n capabilities: ['directEdit'],\n brep(input: Shape, faces: FaceTopoRef[]) {\n if (!Array.isArray(faces) || faces.length === 0) {\n throw new Error('E_DEFEATURE_NO_FACES: defeature requires at least one FaceTopoRef')\n }\n const kernel = getBrepApi()\n const solid = requireBrep(input, 'defeature')\n const handles = resolveFaces(kernel, input, faces, 'defeature')\n return adopt(kernel, kernel.defeature(solid, handles))\n },\n naming: kernelNaming,\n})\n\n/**\n * 反转壳体朝向(内表面 ↔ 外表面)。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name reverseShape\n * @note **occt-only**(`engines: ['occt']`,实证收窄):brepkit 实测在 op 级抛\n * `invalid solid handle: index N is out of bounds`(非输入侧失败),\n * 故由静态门在执行前拒绝而非等到运行时。产物 `getVolume` 返回**有向**体积\n * (朝向反转 ⇒ 符号翻转)。仅 BREP 可用。\n * @returns Shape 朝向反转后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @example\n * const flipped = await cad.reverseShape(sh)\n */\nexport const reverseShape = defineOp({\n capabilities: ['directEdit'],\n // 实证收窄(2026-09-24):brepkit op 级失败 → 静态门提前拒绝。\n engines: ['occt'],\n brep(input: Shape) {\n const kernel = getBrepApi()\n const solid = requireBrep(input, 'reverseShape')\n return adopt(kernel, kernel.reverseShape(solid))\n },\n naming: kernelNaming,\n})\n\n/**\n * 合并同域面/边(去除被分割成多片的冗余细分)。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name unifySameDomain\n * @note 中立 op:L1 unifySameDomain 两引擎同实现。仅 BREP 可用。\n * @returns Shape 合并后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @example\n * const merged = await cad.unifySameDomain(part0)\n */\nexport const unifySameDomain = defineOp({\n capabilities: ['directEdit'],\n brep(input: Shape) {\n const kernel = getBrepApi()\n const solid = requireBrep(input, 'unifySameDomain')\n return adopt(kernel, kernel.unifySameDomain(solid))\n },\n naming: kernelNaming,\n})\n\n/** `cad.sew` / `cad.sewAndSolidify` 公共参数。 */\nexport interface SewParams {\n /** 缝合容差(mm,可选)。 */\n tolerance?: number\n}\n\n/**\n * 缝合:把一组面/壳沿公共边缝成一张壳。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name sew\n * @note 中立 op:L1 sew 两引擎同实现。产物是壳(不保证闭合);要实体用 sewAndSolidify。\n * @returns Shape 缝合后的壳。\n * @param shapes - 面/壳集合。type:Shape[] required:true\n * @param params.tolerance - 缝合容差(mm)。type:number required:false\n * @example\n * const shellShape = await cad.sew([f1, f2, f3], { tolerance: 1e-5 })\n */\nexport const sew = defineOp({\n capabilities: ['directEdit'],\n brep(shapes: Shape[], params?: SewParams) {\n const kernel = getBrepApi()\n const handles = borrowHandles(shapes, 'sew')\n return adopt(kernel, kernel.sew(handles, params?.tolerance))\n },\n naming: kernelNaming,\n})\n\n/**\n * 缝合并固化为实体:缝合后若闭合则生成 solid。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name sewAndSolidify\n * @note 中立 op:L1 sewAndSolidify 两引擎同实现。仅 BREP 可用。\n * @returns Shape 缝合固化后的实体。\n * @param shapes - 面/壳集合。type:Shape[] required:true\n * @param params.tolerance - 缝合容差(mm)。type:number required:false\n * @example\n * const solid = await cad.sewAndSolidify([f1, f2, f3, f4, f5, f6])\n */\nexport const sewAndSolidify = defineOp({\n capabilities: ['directEdit'],\n brep(shapes: Shape[], params?: SewParams) {\n const kernel = getBrepApi()\n const handles = borrowHandles(shapes, 'sewAndSolidify')\n return adopt(kernel, kernel.sewAndSolidify(handles, params?.tolerance))\n },\n naming: kernelNaming,\n})\n\n/**\n * 移除面(或实体某面)上的孔。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name removeHolesFromFace\n * @note 中立 op:L1 removeHolesFromFace 两引擎同实现。入参为含孔的面 Shape\n * (L1 形参是面句柄;借入输入 Shape 的 BREP 槽位句柄)。\n * @returns Shape 去孔后的面。\n * @param face - 含孔的面几何。type:Shape required:true\n * @example\n * const plain = await cad.removeHolesFromFace(faceWithHoles)\n */\nexport const removeHolesFromFace = defineOp({\n capabilities: ['directEdit'],\n brep(face: Shape) {\n if (!face) throw new Error('E_REMOVEHOLES_NO_FACE: removeHolesFromFace requires a face shape')\n const kernel = getBrepApi()\n const handle = brepOf(face) as BrepHandle | undefined\n if (!handle) throw new Error('E_REMOVEHOLES_NO_BREP: removeHolesFromFace input is not BREP')\n return adopt(kernel, kernel.removeHolesFromFace(handle))\n },\n naming: kernelNaming,\n})\n"]}
1
+ {"version":3,"file":"feature-repair.js","sourceRoot":"","sources":["../../src/api/feature-repair.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api feature-repair — L1 薄包装族(手写 op,Phase 5)\n *\n * 六条 L1 已有动作的手写薄包装,全部走 `getBrepApi()`(D12):\n * - `defeature(shape, faces)` — 移除特征面(孔/凸台等)\n * - `removeHolesFromFace(face)` — 移除面上的孔\n * - `reverseShape(shape)` — 反转壳体朝向 —— **occt-only**(见下)\n * - `unifySameDomain(shape)` — 合并同域面/边\n * - `sew(shapes, tolerance?)` — 缝合壳\n * - `sewAndSolidify(shapes, tolerance?)` — 缝合并固化为实体\n *\n * 每条都极薄:解析入参 → 直调 L1 → 收养。选面口径与 `shell`/`draft` 一致\n * (FaceTopoRef[],设计原则 4)。\n *\n * 引擎声明(**逐条判定,不整族一刀切**):\n * - `reverseShape` 声明 `engines: ['occt']` —— 实证收窄:brepkit 实测在 **op 级**\n * 失败(`invalid solid handle: index N is out of bounds`,callee = reverseShape,\n * 非输入构造侧),静态门须在执行前拒绝。\n * - 其余五条保持中立(无 engines)。\n * 注意 `unifySameDomain` 在 brepkit 上**可用但语义有差**(会把体重新居中),\n * 未收窄 —— 缺证据表明它不可用,不擅自扩大范围。\n *\n * 未覆盖(诚实留档,本轮未验):`defeature` / `sew` / `sewAndSolidify` /\n * `removeHolesFromFace` 在 brepkit 上的 op 级行为未取得干净证据(探针的面输入\n * 先撞到 faceRef/输入构造侧限制),故不做引擎声明。\n */\n\nimport type { Shape } from '../mesh/types'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { brepOf, fromBrep } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { FaceTopoRef } from '../topology/naming'\nimport { resolveTopoRef, TopoRefError } from '../topology/naming'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { buildEdgeResolutionContext } from './topo-resolve'\n\ntype ProvenanceLike = Provenance\n\n/** BREP 输入守卫:取 BREP 句柄,无则报错。 */\nfunction requireBrep(input: Shape, op: string): BrepHandle {\n const handle = brepOf(input) as BrepHandle | undefined\n if (!handle) throw new Error(`E_${op.toUpperCase()}_NO_BREP: ${op} input is not BREP`)\n return handle\n}\n\n/** 解析 FaceTopoRef[] → 句柄数组(shell/draft 同款口径)。 */\nfunction resolveFaces(kernel: ReturnType<typeof getBrepApi>, input: Shape, refs: FaceTopoRef[], op: string): BrepHandle[] {\n const ctx = buildEdgeResolutionContext(kernel, input as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', `${op}: input has no BREP naming context`)\n return refs.map((ref) => {\n if (!ref || (ref as { kind?: unknown }).kind !== 'face') {\n throw new Error(`E_${op.toUpperCase()}_BAD_FACE_REF: every faces entry must be a FaceTopoRef (cad.faceRef)`)\n }\n const r = resolveTopoRef(ref, ctx)\n if (r.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', `${op}: face resolved without handle (${ref.origin}/${ref.role})`)\n }\n return r.handle as BrepHandle\n })\n}\n\n/** 借入一组输入 Shape → 句柄数组(sew 族)。 */\nfunction borrowHandles(shapes: Shape[], op: string): BrepHandle[] {\n if (!Array.isArray(shapes) || shapes.length === 0) {\n throw new Error(`E_${op.toUpperCase()}_NO_SHAPES: ${op} requires a non-empty array of shapes`)\n }\n return shapes.map((s) => {\n const h = brepOf(s) as BrepHandle | undefined\n if (!h) throw new Error(`E_${op.toUpperCase()}_NO_BREP: ${op} input shape is not BREP`)\n return h\n })\n}\n\nfunction adopt(kernel: ReturnType<typeof getBrepApi>, handle: BrepHandle): Shape {\n return fromBrep(solidToShape(kernel, handle), { solid: handle })\n}\n\nconst kernelNaming = { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as ProvenanceLike\n\n/**\n * 移除特征面(孔/凸台等),恢复基础形状。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name defeature\n * @note 中立 op:L1 defeature 两引擎同实现。仅 BREP 可用。\n * @returns Shape 移除特征后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param faces - 要移除的面(FaceTopoRef[],cad.faceRef 产物)。type:FaceTopoRef[] required:true\n * @example\n * const base = await cad.defeature(part0, [cad.faceRef(part0, 5)])\n */\nexport const defeature = defineOp({\n brep(input: Shape, faces: FaceTopoRef[]) {\n if (!Array.isArray(faces) || faces.length === 0) {\n throw new Error('E_DEFEATURE_NO_FACES: defeature requires at least one FaceTopoRef')\n }\n const kernel = getBrepApi()\n const solid = requireBrep(input, 'defeature')\n const handles = resolveFaces(kernel, input, faces, 'defeature')\n return adopt(kernel, kernel.defeature(solid, handles))\n },\n naming: kernelNaming,\n})\n\n/**\n * 反转壳体朝向(内表面 ↔ 外表面)。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name reverseShape\n * @note **occt-only**(`engines: ['occt']`,实证收窄):brepkit 实测在 op 级抛\n * `invalid solid handle: index N is out of bounds`(非输入侧失败),\n * 故由静态门在执行前拒绝而非等到运行时。产物 `getVolume` 返回**有向**体积\n * (朝向反转 ⇒ 符号翻转)。仅 BREP 可用。\n * @returns Shape 朝向反转后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @example\n * const flipped = await cad.reverseShape(sh)\n */\nexport const reverseShape = defineOp({\n // 实证收窄(2026-09-24):brepkit op 级失败 → 静态门提前拒绝。\n engines: ['occt'],\n brep(input: Shape) {\n const kernel = getBrepApi()\n const solid = requireBrep(input, 'reverseShape')\n return adopt(kernel, kernel.reverseShape(solid))\n },\n naming: kernelNaming,\n})\n\n/**\n * 合并同域面/边(去除被分割成多片的冗余细分)。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name unifySameDomain\n * @note 中立 op:L1 unifySameDomain 两引擎同实现。仅 BREP 可用。\n * @returns Shape 合并后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @example\n * const merged = await cad.unifySameDomain(part0)\n */\nexport const unifySameDomain = defineOp({\n brep(input: Shape) {\n const kernel = getBrepApi()\n const solid = requireBrep(input, 'unifySameDomain')\n return adopt(kernel, kernel.unifySameDomain(solid))\n },\n naming: kernelNaming,\n})\n\n/** `cad.sew` / `cad.sewAndSolidify` 公共参数。 */\nexport interface SewParams {\n /** 缝合容差(mm,可选)。 */\n tolerance?: number\n}\n\n/**\n * 缝合:把一组面/壳沿公共边缝成一张壳。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name sew\n * @note 中立 op:L1 sew 两引擎同实现。产物是壳(不保证闭合);要实体用 sewAndSolidify。\n * @returns Shape 缝合后的壳。\n * @param shapes - 面/壳集合。type:Shape[] required:true\n * @param params.tolerance - 缝合容差(mm)。type:number required:false\n * @example\n * const shellShape = await cad.sew([f1, f2, f3], { tolerance: 1e-5 })\n */\nexport const sew = defineOp({\n brep(shapes: Shape[], params?: SewParams) {\n const kernel = getBrepApi()\n const handles = borrowHandles(shapes, 'sew')\n return adopt(kernel, kernel.sew(handles, params?.tolerance))\n },\n naming: kernelNaming,\n})\n\n/**\n * 缝合并固化为实体:缝合后若闭合则生成 solid。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name sewAndSolidify\n * @note 中立 op:L1 sewAndSolidify 两引擎同实现。仅 BREP 可用。\n * @returns Shape 缝合固化后的实体。\n * @param shapes - 面/壳集合。type:Shape[] required:true\n * @param params.tolerance - 缝合容差(mm)。type:number required:false\n * @example\n * const solid = await cad.sewAndSolidify([f1, f2, f3, f4, f5, f6])\n */\nexport const sewAndSolidify = defineOp({\n brep(shapes: Shape[], params?: SewParams) {\n const kernel = getBrepApi()\n const handles = borrowHandles(shapes, 'sewAndSolidify')\n return adopt(kernel, kernel.sewAndSolidify(handles, params?.tolerance))\n },\n naming: kernelNaming,\n})\n\n/**\n * 移除面(或实体某面)上的孔。\n * @group 修复\n * @inputs 1\n * @async true\n * @qual ok\n * @name removeHolesFromFace\n * @note 中立 op:L1 removeHolesFromFace 两引擎同实现。入参为含孔的面 Shape\n * (L1 形参是面句柄;借入输入 Shape 的 BREP 槽位句柄)。\n * @returns Shape 去孔后的面。\n * @param face - 含孔的面几何。type:Shape required:true\n * @example\n * const plain = await cad.removeHolesFromFace(faceWithHoles)\n */\nexport const removeHolesFromFace = defineOp({\n brep(face: Shape) {\n if (!face) throw new Error('E_REMOVEHOLES_NO_FACE: removeHolesFromFace requires a face shape')\n const kernel = getBrepApi()\n const handle = brepOf(face) as BrepHandle | undefined\n if (!handle) throw new Error('E_REMOVEHOLES_NO_BREP: removeHolesFromFace input is not BREP')\n return adopt(kernel, kernel.removeHolesFromFace(handle))\n },\n naming: kernelNaming,\n})\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"fillet-variable.d.ts","sourceRoot":"","sources":["../../src/api/fillet-variable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAM1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAkCrD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,cAAc;;CAMzB,CAAA"}
1
+ {"version":3,"file":"fillet-variable.d.ts","sourceRoot":"","sources":["../../src/api/fillet-variable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAM1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAkCrD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,cAAc;;CAKzB,CAAA"}
@@ -62,7 +62,6 @@ function filletVariableBrep(input, edge, startRadius, endRadius) {
62
62
  * const v = await cad.filletVariable(part0, partEdges[0], 1, 4)
63
63
  */
64
64
  export const filletVariable = defineOp({
65
- capabilities: ['directEdit'],
66
65
  brep(input, edge, r1, r2) {
67
66
  return filletVariableBrep(input, edge, r1, r2);
68
67
  },