@faicad/faijs 0.33.1 → 0.35.2

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 (392) hide show
  1. package/dist/api/api-namespace.d.ts +14 -14
  2. package/dist/api/api-namespace.d.ts.map +1 -1
  3. package/dist/api/api-namespace.js +40 -14
  4. package/dist/api/api-namespace.js.map +1 -1
  5. package/dist/api/appearance.d.ts +47 -6
  6. package/dist/api/appearance.d.ts.map +1 -1
  7. package/dist/api/appearance.js.map +1 -1
  8. package/dist/api/assembly/solve-tree.d.ts +1 -0
  9. package/dist/api/assembly/solve-tree.d.ts.map +1 -1
  10. package/dist/api/assembly/solve-tree.js +42 -17
  11. package/dist/api/assembly/solve-tree.js.map +1 -1
  12. package/dist/api/assembly/solve.d.ts +1 -0
  13. package/dist/api/assembly/solve.d.ts.map +1 -1
  14. package/dist/api/assembly/solve.js.map +1 -1
  15. package/dist/api/assembly/solvers/global-solver.d.ts.map +1 -1
  16. package/dist/api/assembly/solvers/global-solver.js +130 -23
  17. package/dist/api/assembly/solvers/global-solver.js.map +1 -1
  18. package/dist/api/assembly/solvers/pose-from-delta.d.ts +9 -0
  19. package/dist/api/assembly/solvers/pose-from-delta.d.ts.map +1 -1
  20. package/dist/api/assembly/solvers/pose-from-delta.js +23 -0
  21. package/dist/api/assembly/solvers/pose-from-delta.js.map +1 -1
  22. package/dist/api/assembly/solvers/types.d.ts +20 -2
  23. package/dist/api/assembly/solvers/types.d.ts.map +1 -1
  24. package/dist/api/assembly/solvers/types.js.map +1 -1
  25. package/dist/api/chamfer.d.ts +7 -4
  26. package/dist/api/chamfer.d.ts.map +1 -1
  27. package/dist/api/chamfer.js +57 -13
  28. package/dist/api/chamfer.js.map +1 -1
  29. package/dist/api/draft.d.ts +7 -4
  30. package/dist/api/draft.d.ts.map +1 -1
  31. package/dist/api/draft.js +11 -6
  32. package/dist/api/draft.js.map +1 -1
  33. package/dist/api/edge-ref.d.ts +4 -4
  34. package/dist/api/edge-ref.js +4 -4
  35. package/dist/api/edge-ref.js.map +1 -1
  36. package/dist/api/extrude.d.ts +10 -6
  37. package/dist/api/extrude.d.ts.map +1 -1
  38. package/dist/api/extrude.js +50 -25
  39. package/dist/api/extrude.js.map +1 -1
  40. package/dist/api/face-ref.d.ts +4 -4
  41. package/dist/api/face-ref.js +4 -4
  42. package/dist/api/face-ref.js.map +1 -1
  43. package/dist/api/feature-repair.d.ts +6 -3
  44. package/dist/api/feature-repair.d.ts.map +1 -1
  45. package/dist/api/feature-repair.js +12 -7
  46. package/dist/api/feature-repair.js.map +1 -1
  47. package/dist/api/fillet-variable.d.ts +6 -2
  48. package/dist/api/fillet-variable.d.ts.map +1 -1
  49. package/dist/api/fillet-variable.js +24 -6
  50. package/dist/api/fillet-variable.js.map +1 -1
  51. package/dist/api/fillet.d.ts +7 -4
  52. package/dist/api/fillet.d.ts.map +1 -1
  53. package/dist/api/fillet.js +45 -12
  54. package/dist/api/fillet.js.map +1 -1
  55. package/dist/api/helix.d.ts +13 -13
  56. package/dist/api/helix.d.ts.map +1 -1
  57. package/dist/api/helix.js +19 -24
  58. package/dist/api/helix.js.map +1 -1
  59. package/dist/api/import-brep.d.ts +10 -18
  60. package/dist/api/import-brep.d.ts.map +1 -1
  61. package/dist/api/import-brep.js +17 -25
  62. package/dist/api/import-brep.js.map +1 -1
  63. package/dist/api/import-step.d.ts +10 -15
  64. package/dist/api/import-step.d.ts.map +1 -1
  65. package/dist/api/import-step.js +24 -29
  66. package/dist/api/import-step.js.map +1 -1
  67. package/dist/api/index.js +2 -2
  68. package/dist/api/index.js.map +1 -1
  69. package/dist/api/internal/export-members.js.map +1 -1
  70. package/dist/api/loft-advanced.d.ts +4 -0
  71. package/dist/api/loft-advanced.d.ts.map +1 -1
  72. package/dist/api/loft-advanced.js +4 -0
  73. package/dist/api/loft-advanced.js.map +1 -1
  74. package/dist/api/loft.d.ts +5 -3
  75. package/dist/api/loft.d.ts.map +1 -1
  76. package/dist/api/loft.js +5 -3
  77. package/dist/api/loft.js.map +1 -1
  78. package/dist/api/meta.d.ts +42 -6
  79. package/dist/api/meta.d.ts.map +1 -1
  80. package/dist/api/meta.js.map +1 -1
  81. package/dist/api/punch-hole.d.ts +5 -2
  82. package/dist/api/punch-hole.d.ts.map +1 -1
  83. package/dist/api/punch-hole.js +4 -1
  84. package/dist/api/punch-hole.js.map +1 -1
  85. package/dist/api/replicate.d.ts +4 -5
  86. package/dist/api/replicate.d.ts.map +1 -1
  87. package/dist/api/replicate.js +4 -5
  88. package/dist/api/replicate.js.map +1 -1
  89. package/dist/api/selectors-to-refs.d.ts +83 -0
  90. package/dist/api/selectors-to-refs.d.ts.map +1 -0
  91. package/dist/api/selectors-to-refs.js +211 -0
  92. package/dist/api/selectors-to-refs.js.map +1 -0
  93. package/dist/api/shell.d.ts +17 -8
  94. package/dist/api/shell.d.ts.map +1 -1
  95. package/dist/api/shell.js +45 -15
  96. package/dist/api/shell.js.map +1 -1
  97. package/dist/api/sketch-on-face.d.ts +12 -6
  98. package/dist/api/sketch-on-face.d.ts.map +1 -1
  99. package/dist/api/sketch-on-face.js +31 -4
  100. package/dist/api/sketch-on-face.js.map +1 -1
  101. package/dist/api/sketch-on-plane.d.ts +3 -0
  102. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  103. package/dist/api/sketch-on-plane.js +3 -0
  104. package/dist/api/sketch-on-plane.js.map +1 -1
  105. package/dist/api/sketch-on-surface.d.ts +4 -1
  106. package/dist/api/sketch-on-surface.d.ts.map +1 -1
  107. package/dist/api/sketch-on-surface.js +4 -1
  108. package/dist/api/sketch-on-surface.js.map +1 -1
  109. package/dist/api/view/view-projection.d.ts.map +1 -1
  110. package/dist/api/view/view-projection.js +9 -2
  111. package/dist/api/view/view-projection.js.map +1 -1
  112. package/dist/brep/brep-chain.js +2 -2
  113. package/dist/brep/brep-chain.js.map +1 -1
  114. package/dist/brep/brep-ops.d.ts +1 -1
  115. package/dist/brep/brep-ops.js +1 -1
  116. package/dist/brep/brep-ops.js.map +1 -1
  117. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  118. package/dist/brep/engine/adapters/brep-mock.js +45 -0
  119. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  120. package/dist/brep/engine/primitives.d.ts +87 -3
  121. package/dist/brep/engine/primitives.d.ts.map +1 -1
  122. package/dist/brep/engine/primitives.js +1 -1
  123. package/dist/brep/engine/primitives.js.map +1 -1
  124. package/dist/brep/engine/registry.d.ts +33 -7
  125. package/dist/brep/engine/registry.d.ts.map +1 -1
  126. package/dist/brep/engine/registry.js +47 -16
  127. package/dist/brep/engine/registry.js.map +1 -1
  128. package/dist/brep/handle-bridge.d.ts +14 -15
  129. package/dist/brep/handle-bridge.d.ts.map +1 -1
  130. package/dist/brep/handle-bridge.js +35 -15
  131. package/dist/brep/handle-bridge.js.map +1 -1
  132. package/dist/brep/primitives-brep.js +2 -2
  133. package/dist/brep/primitives-brep.js.map +1 -1
  134. package/dist/brep/text/text-to-solid.d.ts +40 -3
  135. package/dist/brep/text/text-to-solid.d.ts.map +1 -1
  136. package/dist/brep/text/text-to-solid.js +104 -24
  137. package/dist/brep/text/text-to-solid.js.map +1 -1
  138. package/dist/brepkit-kernel/brepkitKernel.d.ts +2 -2
  139. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  140. package/dist/brepkit-kernel/brepkitKernel.js +315 -36
  141. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  142. package/dist/brepkit-kernel/brepkitWasm.js +7 -7
  143. package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
  144. package/dist/brepkit-kernel/multi-version-test.d.ts +2 -2
  145. package/dist/brepkit-kernel/multi-version-test.d.ts.map +1 -1
  146. package/dist/brepkit-kernel/multi-version-test.js +6 -6
  147. package/dist/brepkit-kernel/multi-version-test.js.map +1 -1
  148. package/dist/browser.d.ts +2 -3
  149. package/dist/browser.d.ts.map +1 -1
  150. package/dist/browser.js +1 -2
  151. package/dist/browser.js.map +1 -1
  152. package/dist/cad-runtime/admit-compat-lib.d.ts +9 -1
  153. package/dist/cad-runtime/admit-compat-lib.d.ts.map +1 -1
  154. package/dist/cad-runtime/admit-compat-lib.js +11 -1
  155. package/dist/cad-runtime/admit-compat-lib.js.map +1 -1
  156. package/dist/cad-runtime/browser-lib-loader.d.ts +16 -11
  157. package/dist/cad-runtime/browser-lib-loader.d.ts.map +1 -1
  158. package/dist/cad-runtime/browser-lib-loader.js +16 -8
  159. package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
  160. package/dist/cad-runtime/direct-executor.d.ts +62 -5
  161. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  162. package/dist/cad-runtime/direct-executor.js +617 -42
  163. package/dist/cad-runtime/direct-executor.js.map +1 -1
  164. package/dist/cad-runtime/interp/closure.d.ts +3 -2
  165. package/dist/cad-runtime/interp/closure.d.ts.map +1 -1
  166. package/dist/cad-runtime/interp/closure.js.map +1 -1
  167. package/dist/cad-runtime/interp/env.d.ts +9 -6
  168. package/dist/cad-runtime/interp/env.d.ts.map +1 -1
  169. package/dist/cad-runtime/interp/env.js +4 -2
  170. package/dist/cad-runtime/interp/env.js.map +1 -1
  171. package/dist/cad-runtime/lib-decl.d.ts +121 -0
  172. package/dist/cad-runtime/lib-decl.d.ts.map +1 -0
  173. package/dist/cad-runtime/lib-decl.js +100 -0
  174. package/dist/cad-runtime/lib-decl.js.map +1 -0
  175. package/dist/cad-runtime/ports.d.ts +12 -0
  176. package/dist/cad-runtime/ports.d.ts.map +1 -1
  177. package/dist/cad-runtime/ports.js.map +1 -1
  178. package/dist/cad-runtime/runtime.d.ts +59 -5
  179. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  180. package/dist/cad-runtime/runtime.js +237 -18
  181. package/dist/cad-runtime/runtime.js.map +1 -1
  182. package/dist/extra/browser.d.ts +9 -0
  183. package/dist/extra/browser.d.ts.map +1 -0
  184. package/dist/extra/browser.js +9 -0
  185. package/dist/extra/browser.js.map +1 -0
  186. package/dist/extra/editor-ops.d.ts +22 -0
  187. package/dist/extra/editor-ops.d.ts.map +1 -0
  188. package/dist/extra/editor-ops.js +21 -0
  189. package/dist/extra/editor-ops.js.map +1 -0
  190. package/dist/extra/extras/svg-extrude.d.ts +45 -0
  191. package/dist/extra/extras/svg-extrude.d.ts.map +1 -0
  192. package/dist/extra/extras/svg-extrude.js +110 -0
  193. package/dist/extra/extras/svg-extrude.js.map +1 -0
  194. package/dist/extra/extras/text-cjk.d.ts +36 -0
  195. package/dist/extra/extras/text-cjk.d.ts.map +1 -0
  196. package/dist/extra/extras/text-cjk.js +86 -0
  197. package/dist/extra/extras/text-cjk.js.map +1 -0
  198. package/dist/extra/extras/text-geometry.d.ts +69 -0
  199. package/dist/extra/extras/text-geometry.d.ts.map +1 -0
  200. package/dist/extra/extras/text-geometry.js +188 -0
  201. package/dist/extra/extras/text-geometry.js.map +1 -0
  202. package/dist/extra/index.d.ts +40 -0
  203. package/dist/extra/index.d.ts.map +1 -0
  204. package/dist/extra/index.js +40 -0
  205. package/dist/extra/index.js.map +1 -0
  206. package/dist/extra/mesh/drill-hole/DrillHoleCore.d.ts +94 -0
  207. package/dist/extra/mesh/drill-hole/DrillHoleCore.d.ts.map +1 -0
  208. package/dist/extra/mesh/drill-hole/DrillHoleCore.js +282 -0
  209. package/dist/extra/mesh/drill-hole/DrillHoleCore.js.map +1 -0
  210. package/dist/extra/mesh/drill-hole/drill-types.d.ts +34 -0
  211. package/dist/extra/mesh/drill-hole/drill-types.d.ts.map +1 -0
  212. package/dist/extra/mesh/drill-hole/drill-types.js +7 -0
  213. package/dist/extra/mesh/drill-hole/drill-types.js.map +1 -0
  214. package/dist/extra/mesh/engrave-decoration.d.ts +42 -0
  215. package/dist/extra/mesh/engrave-decoration.d.ts.map +1 -0
  216. package/dist/extra/mesh/engrave-decoration.js +39 -0
  217. package/dist/extra/mesh/engrave-decoration.js.map +1 -0
  218. package/dist/extra/mesh/fai_drill.d.ts +21 -0
  219. package/dist/extra/mesh/fai_drill.d.ts.map +1 -0
  220. package/dist/extra/mesh/fai_drill.js +89 -0
  221. package/dist/extra/mesh/fai_drill.js.map +1 -0
  222. package/dist/extra/mesh/fai_extrude.d.ts +24 -0
  223. package/dist/extra/mesh/fai_extrude.d.ts.map +1 -0
  224. package/dist/extra/mesh/fai_extrude.js +42 -0
  225. package/dist/extra/mesh/fai_extrude.js.map +1 -0
  226. package/dist/extra/mesh/fai_split.d.ts +164 -0
  227. package/dist/extra/mesh/fai_split.d.ts.map +1 -0
  228. package/dist/extra/mesh/fai_split.js +269 -0
  229. package/dist/extra/mesh/fai_split.js.map +1 -0
  230. package/dist/extra/mesh/primitives.d.ts +29 -0
  231. package/dist/extra/mesh/primitives.d.ts.map +1 -0
  232. package/dist/extra/mesh/primitives.js +41 -0
  233. package/dist/extra/mesh/primitives.js.map +1 -0
  234. package/dist/extra/op-names.d.ts +37 -0
  235. package/dist/extra/op-names.d.ts.map +1 -0
  236. package/dist/extra/op-names.js +46 -0
  237. package/dist/extra/op-names.js.map +1 -0
  238. package/dist/extra/ops/compound.d.ts +140 -0
  239. package/dist/extra/ops/compound.d.ts.map +1 -0
  240. package/dist/extra/ops/compound.js +167 -0
  241. package/dist/extra/ops/compound.js.map +1 -0
  242. package/dist/extra/ops/copy.d.ts +40 -0
  243. package/dist/extra/ops/copy.d.ts.map +1 -0
  244. package/dist/extra/ops/copy.js +83 -0
  245. package/dist/extra/ops/copy.js.map +1 -0
  246. package/dist/extra/ops/fai_drill.d.ts +51 -0
  247. package/dist/extra/ops/fai_drill.d.ts.map +1 -0
  248. package/dist/extra/ops/fai_drill.js +233 -0
  249. package/dist/extra/ops/fai_drill.js.map +1 -0
  250. package/dist/extra/ops/fai_extrude.d.ts +36 -0
  251. package/dist/extra/ops/fai_extrude.d.ts.map +1 -0
  252. package/dist/extra/ops/fai_extrude.js +84 -0
  253. package/dist/extra/ops/fai_extrude.js.map +1 -0
  254. package/dist/extra/ops/fai_split.d.ts +46 -0
  255. package/dist/extra/ops/fai_split.d.ts.map +1 -0
  256. package/dist/extra/ops/fai_split.js +235 -0
  257. package/dist/extra/ops/fai_split.js.map +1 -0
  258. package/dist/extra/ops/load.d.ts +49 -0
  259. package/dist/extra/ops/load.d.ts.map +1 -0
  260. package/dist/extra/ops/load.js +385 -0
  261. package/dist/extra/ops/load.js.map +1 -0
  262. package/dist/extra/ops/svg-extrude.d.ts +32 -0
  263. package/dist/extra/ops/svg-extrude.d.ts.map +1 -0
  264. package/dist/extra/ops/svg-extrude.js +74 -0
  265. package/dist/extra/ops/svg-extrude.js.map +1 -0
  266. package/dist/extra/ops/text.d.ts +34 -0
  267. package/dist/extra/ops/text.d.ts.map +1 -0
  268. package/dist/extra/ops/text.js +100 -0
  269. package/dist/extra/ops/text.js.map +1 -0
  270. package/dist/geometry2d/bridge/lift-on-plane.d.ts +8 -5
  271. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
  272. package/dist/geometry2d/bridge/lift-on-plane.js +8 -5
  273. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
  274. package/dist/index.d.ts +6 -2
  275. package/dist/index.d.ts.map +1 -1
  276. package/dist/index.js +8 -2
  277. package/dist/index.js.map +1 -1
  278. package/dist/lang/symbol-table.d.ts +3 -3
  279. package/dist/lang/symbol-table.generated.d.ts +10 -0
  280. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  281. package/dist/lang/symbol-table.generated.js +10 -0
  282. package/dist/lang/symbol-table.generated.js.map +1 -1
  283. package/dist/lang/symbol-table.js +3 -3
  284. package/dist/lang/symbol-table.js.map +1 -1
  285. package/dist/math3d/index.d.ts +1 -1
  286. package/dist/math3d/index.js +1 -1
  287. package/dist/math3d/index.js.map +1 -1
  288. package/dist/mesh/engrave.d.ts +2 -3
  289. package/dist/mesh/engrave.d.ts.map +1 -1
  290. package/dist/mesh/engrave.js +4 -11
  291. package/dist/mesh/engrave.js.map +1 -1
  292. package/dist/mesh/index.d.ts +0 -2
  293. package/dist/mesh/index.d.ts.map +1 -1
  294. package/dist/mesh/index.js +0 -2
  295. package/dist/mesh/index.js.map +1 -1
  296. package/dist/mesh/primitives.d.ts +1 -1
  297. package/dist/mesh/primitives.js +1 -1
  298. package/dist/mesh/primitives.js.map +1 -1
  299. package/dist/node-host/cli.d.ts +20 -4
  300. package/dist/node-host/cli.d.ts.map +1 -1
  301. package/dist/node-host/cli.js +84 -35
  302. package/dist/node-host/cli.js.map +1 -1
  303. package/dist/node-host/execute-script.d.ts.map +1 -1
  304. package/dist/node-host/execute-script.js +3 -4
  305. package/dist/node-host/execute-script.js.map +1 -1
  306. package/dist/node-host/lib-package-json.d.ts +36 -0
  307. package/dist/node-host/lib-package-json.d.ts.map +1 -0
  308. package/dist/node-host/lib-package-json.js +73 -0
  309. package/dist/node-host/lib-package-json.js.map +1 -0
  310. package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
  311. package/dist/occt-kernel/occt-primitives.js +41 -0
  312. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  313. package/dist/occt-kernel/occtKernel.d.ts +1 -1
  314. package/dist/occt-kernel/occtKernel.js +1 -1
  315. package/dist/occt-kernel/occtKernel.js.map +1 -1
  316. package/dist/runtime-state.d.ts +28 -1
  317. package/dist/runtime-state.d.ts.map +1 -1
  318. package/dist/runtime-state.js +14 -1
  319. package/dist/runtime-state.js.map +1 -1
  320. package/dist/sdk.d.ts +2 -2
  321. package/dist/sdk.d.ts.map +1 -1
  322. package/dist/sdk.js +11 -2
  323. package/dist/sdk.js.map +1 -1
  324. package/dist/sketch/bspline.d.ts +58 -0
  325. package/dist/sketch/bspline.d.ts.map +1 -0
  326. package/dist/sketch/bspline.js +104 -0
  327. package/dist/sketch/bspline.js.map +1 -0
  328. package/dist/sketch/canonical.d.ts +239 -0
  329. package/dist/sketch/canonical.d.ts.map +1 -0
  330. package/dist/sketch/canonical.js +17 -0
  331. package/dist/sketch/canonical.js.map +1 -0
  332. package/dist/sketch/contour.d.ts +43 -0
  333. package/dist/sketch/contour.d.ts.map +1 -0
  334. package/dist/sketch/contour.js +202 -0
  335. package/dist/sketch/contour.js.map +1 -0
  336. package/dist/sketch/dim-spec.d.ts +32 -0
  337. package/dist/sketch/dim-spec.d.ts.map +1 -0
  338. package/dist/sketch/dim-spec.js +112 -0
  339. package/dist/sketch/dim-spec.js.map +1 -0
  340. package/dist/sketch/faces.d.ts +45 -0
  341. package/dist/sketch/faces.d.ts.map +1 -0
  342. package/dist/sketch/faces.js +108 -0
  343. package/dist/sketch/faces.js.map +1 -0
  344. package/dist/sketch/fcstd-types.d.ts +194 -0
  345. package/dist/sketch/fcstd-types.d.ts.map +1 -0
  346. package/dist/sketch/fcstd-types.js +67 -0
  347. package/dist/sketch/fcstd-types.js.map +1 -0
  348. package/dist/sketch/index.d.ts +46 -0
  349. package/dist/sketch/index.d.ts.map +1 -0
  350. package/dist/sketch/index.js +39 -0
  351. package/dist/sketch/index.js.map +1 -0
  352. package/dist/sketch/node.d.ts +14 -0
  353. package/dist/sketch/node.d.ts.map +1 -0
  354. package/dist/sketch/node.js +43 -0
  355. package/dist/sketch/node.js.map +1 -0
  356. package/dist/sketch/op.d.ts +111 -0
  357. package/dist/sketch/op.d.ts.map +1 -0
  358. package/dist/sketch/op.js +185 -0
  359. package/dist/sketch/op.js.map +1 -0
  360. package/dist/sketch/planegcs-backend.d.ts +69 -0
  361. package/dist/sketch/planegcs-backend.d.ts.map +1 -0
  362. package/dist/sketch/planegcs-backend.js +812 -0
  363. package/dist/sketch/planegcs-backend.js.map +1 -0
  364. package/dist/sketch/project.d.ts +176 -0
  365. package/dist/sketch/project.d.ts.map +1 -0
  366. package/dist/sketch/project.js +656 -0
  367. package/dist/sketch/project.js.map +1 -0
  368. package/dist/sketch/shapes.d.ts +370 -0
  369. package/dist/sketch/shapes.d.ts.map +1 -0
  370. package/dist/sketch/shapes.js +959 -0
  371. package/dist/sketch/shapes.js.map +1 -0
  372. package/dist/sketch/solve.d.ts +21 -0
  373. package/dist/sketch/solve.d.ts.map +1 -0
  374. package/dist/sketch/solve.js +144 -0
  375. package/dist/sketch/solve.js.map +1 -0
  376. package/dist/sketch/solver-loader.d.ts +47 -0
  377. package/dist/sketch/solver-loader.d.ts.map +1 -0
  378. package/dist/sketch/solver-loader.js +77 -0
  379. package/dist/sketch/solver-loader.js.map +1 -0
  380. package/dist/sketch/solver.d.ts +63 -0
  381. package/dist/sketch/solver.d.ts.map +1 -0
  382. package/dist/sketch/solver.js +28 -0
  383. package/dist/sketch/solver.js.map +1 -0
  384. package/dist/sketch/verify.d.ts +53 -0
  385. package/dist/sketch/verify.d.ts.map +1 -0
  386. package/dist/sketch/verify.js +71 -0
  387. package/dist/sketch/verify.js.map +1 -0
  388. package/dist/weapp.d.ts +1 -1
  389. package/dist/weapp.d.ts.map +1 -1
  390. package/dist/weapp.js +1 -1
  391. package/dist/weapp.js.map +1 -1
  392. package/package.json +43 -11
@@ -1 +1 @@
1
- {"version":3,"file":"sketch-on-face.js","sourceRoot":"","sources":["../../src/api/sketch-on-face.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `cad.sketchOnFace`: place 2D contours onto a **planar** face of an existing\n * solid (E3 placement), engine-neutral.\n *\n * 2026-10-09 split: `sketchOnFace` now owns the *planar* case only and carries\n * **no `engines` declaration** — it is a common op, available on the OCCT BREP\n * engine, the brepkit BREP engine, and the brepkit mesh backend. The\n * curved / UV-conform capability (map into the face's `(u,v)` domain + snap to\n * the surface via `fixWireOnFace`, which needs OCCT) moved to\n * `cad.sketchOnSurface` (`engines: ['occt']`).\n *\n * For a planar face the contour is laid on the face's own plane frame via\n * `assembleWireOnFace` (identity `original` scale mode, or `bounds`/`native`\n * where the engine exposes a finite UV domain) and wrapped as a face with\n * `makeFace` — exact, no surface snapping needed. Non-planar faces are refused\n * up front with a pointer to `cad.sketchOnSurface`.\n *\n * **Two chains, two mechanisms** (plan 2026-10-01 §4 Phase 3). The BREP branch\n * above maps the contour onto the host face's plane. The **mesh branch**\n * (`buildSketchOnFaceMesh`, `meshEngines: ['brepkit']`) works on a mesh solid's\n * approximate topology and deliberately does NOT use a UV domain: a brepkit\n * plane's domain is ±1e6 (an infinite domain), so \"place the sketch in the face's\n * UV range\" is meaningless there. It places the contour in the face's own plane\n * frame instead (origin = face bbox centre, normal = `surfaceNormal`), which\n * matches `cad.sketchOnPlane`'s semantics. The result is a **mesh-chain face**\n * (`ShapeSlot.meshFace`), ready for the mesh branch of `cad.extrude`.\n *\n * For both chains a planar face is required; curved faces are rejected by the\n * BREP branch (→ `cad.sketchOnSurface`) and by the mesh branch (→\n * `E_MESH_SOLID_UNSUPPORTED`).\n * @module\n */\nimport type { Shape } from '../mesh/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { solidToShape } from '../brep/brep-ops'\nimport { fromBrep, fromBrepCurve, brepOf } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { TopoRefError, resolveTopoRef, type FaceTopoRef } from '../topology/naming'\nimport { buildEdgeResolutionContext } from './topo-resolve'\nimport { Blueprint } from '../geometry2d/blueprint'\nimport { CompoundBlueprint } from '../geometry2d/compound-blueprint'\nimport { organiseBlueprints } from '../geometry2d/organise'\nimport { assembleWireOnFace, type FaceScaleMode } from '../geometry2d/bridge/on-surface'\nimport { assembleWire, type Plane, type Vec3 } from '../geometry2d/bridge/lift-on-plane'\nimport { profileSegToCurve, type ProfileSegLike } from '../geometry2d/adapt'\nimport { assertProfileParams, toContourBlueprints, type ProfileLoop } from './profile'\nimport { MeshUnsupportedError, BrepUnsupportedError, getCurrentStmt, getBackends } from '../runtime-state'\nimport {\n meshBackendOrThrow,\n meshFacePlane,\n meshFaceProduct,\n resolveMeshFaceHandle,\n} from './internal/mesh-solid-op'\n\n/** A face selector on a target solid: a 1-based ordinal (FreeCAD `FaceN`) or a `cad.faceRef` result. */\nexport type FaceSelector = number | FaceTopoRef\n\n/** Contour loops + the target face for `cad.sketchOnFace`. */\nexport interface SketchOnFaceParams {\n /** Ordered 2D closed contours (same shape as `cad.profile` / `cad.sketchOnPlane`). */\n contours: ProfileLoop[]\n /** The target solid on which the host face lives. */\n on: Shape\n /** The host face: a 1-based face ordinal, or a `cad.faceRef(on, n)` result. */\n face: FaceSelector\n /** How 2D coords map onto the face UV space: `'original'` (identity) | `'bounds'`/`'native'` (affine-fit). */\n scaleMode?: FaceScaleMode\n /** Result shape: `'face'` (default) builds a face on the contour; `'wire'` returns the outer-loop wire only. */\n as?: 'face' | 'wire'\n}\n\n/**\n * Resolve a face on `on` to its live BREP handle (1-based ordinal or `cad.faceRef`).\n * @param kernel - the BREP engine surface.\n * @param on - the target solid shape.\n * @param selector - the face ordinal or `cad.faceRef` result.\n * @returns the live face handle.\n */\nexport function resolveFaceHandle(kernel: BrepEngineApi, on: Shape, selector: FaceSelector): BrepHandle {\n const solid = brepOf(on) as BrepHandle | undefined\n if (solid === undefined) {\n throw new TopoRefError('E_TOPO_MESH_UNSUPPORTED', 'face', 'sketchOnFace: target `on` has no BREP solid')\n }\n if (typeof selector === 'number') {\n const faces = kernel.getSubShapes(solid, 'face')\n if (!Number.isInteger(selector) || selector < 1 || selector > faces.length) {\n throw new TopoRefError(\n 'E_TOPO_NOT_FOUND',\n 'face',\n `sketchOnFace: face ordinal ${selector} out of range [1, ${faces.length}]`,\n )\n }\n return faces[selector - 1] as BrepHandle\n }\n if (selector.kind !== 'face') {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'sketchOnFace: selector must be a face ordinal or a face ref')\n }\n const ctx = buildEdgeResolutionContext(kernel, on as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'sketchOnFace: input has no naming context')\n const resolved = resolveTopoRef(selector, ctx)\n if (resolved.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'sketchOnFace: face ref resolved to no live handle')\n }\n return resolved.handle as BrepHandle\n}\n\n/**\n * Make the placed face inherit the host face's outward orientation: surface\n * normals must point the same way, otherwise the resulting face — and any prism\n * extruded from it — carries a reversed shell whose OCCT volume collapses to ~0.\n * @param kernel - the BREP engine surface.\n * @param host - the host face handle (its normal is the reference).\n * @param face - the face built on the host surface.\n * @returns a handle to the (possibly re-oriented) face.\n */\nexport function orientLikeHost(kernel: BrepEngineApi, host: BrepHandle, face: BrepHandle): BrepHandle {\n const a = kernel.surfaceNormal(host, 0, 0)\n const b = kernel.surfaceNormal(face, 0, 0)\n const dot = a.x * b.x + a.y * b.y + a.z * b.z\n return dot < 0 ? kernel.reverseShape(face) : face\n}\n\n/**\n * Build one planar face (outer + optional holes) on the host **planar** face for\n * an organised contour entry. No surface snapping (`fixWireOnFace`) is needed:\n * the wire from `assembleWireOnFace` already lies in the face's plane, so\n * `makeFace` is exact.\n * @param kernel - the BREP engine surface.\n * @param host - the resolved live host face handle.\n * @param mode - the face-scale mode (`original` everywhere; `bounds`/`native` only where the engine exposes a finite UV domain).\n * @param entry - the organised contour entry (outer + optional holes).\n * @returns the built face handle.\n */\nfunction buildPlanarFaceOnHost(\n kernel: BrepEngineApi,\n host: BrepHandle,\n mode: FaceScaleMode,\n entry: Blueprint | CompoundBlueprint,\n): BrepHandle {\n const outerBp = entry instanceof CompoundBlueprint ? entry.blueprints[0]! : entry\n const outerWire = assembleWireOnFace(kernel, host, mode, outerBp).wire\n let face = orientLikeHost(kernel, host, kernel.makeFace(outerWire))\n if (entry instanceof CompoundBlueprint) {\n const holes = entry.blueprints.slice(1).map((h) => assembleWireOnFace(kernel, host, mode, h).wire as never)\n if (holes.length > 0) face = kernel.addHolesInFace(face, holes)\n }\n return face\n}\n\n/**\n * Build a 3D Shape from closed contours placed on the host **planar** face.\n * @param kernel - the BREP engine surface.\n * @param params - contour loops + target solid + face + scale mode.\n * @returns Shape on the target face (face, or the outer wire when `as:'wire'`).\n * @throws {BrepUnsupportedError} when the host face is not planar (use `cad.sketchOnSurface`).\n */\nexport function buildSketchOnFaceWith(kernel: BrepEngineApi, params: SketchOnFaceParams): Shape {\n const host = resolveFaceHandle(kernel, params.on, params.face)\n const mode = params.scaleMode ?? 'original'\n\n // Planar-only gate: the curved / UV-conform capability moved to `cad.sketchOnSurface`.\n const surface = kernel.surfaceType(host)\n if (surface !== 'plane') {\n throw new BrepUnsupportedError(\n `E_BREP_UNSUPPORTED: cad.sketchOnFace only supports planar faces (got surfaceType '${surface}'). ` +\n 'Use cad.sketchOnSurface for curved/UV-conform placement.',\n getCurrentStmt(),\n )\n }\n // brepkit planar faces expose an infinite (±1e6) UV domain, so only the\n // identity 'original' scale mode is meaningful there (mirrors the mesh branch\n // restriction); OCCT planar faces keep full scaleMode support.\n const engineId = getBackends().config.brepEngineId\n if (engineId === 'brepkit' && mode !== 'original') {\n throw new BrepUnsupportedError(\n `E_BREP_UNSUPPORTED: cad.sketchOnFace on a brepkit planar face only supports scaleMode 'original' ` +\n \"(brepkit planar faces have no finite UV domain) — use the default 'original'.\",\n getCurrentStmt(),\n )\n }\n\n const blueprints = params.contours.map(\n (loop) => new Blueprint(loop.segments.map((s) => profileSegToCurve(s as ProfileSegLike))),\n )\n const organised = organiseBlueprints(blueprints)\n\n if (params.as === 'wire') {\n const outer =\n organised.blueprints[0] instanceof CompoundBlueprint\n ? organised.blueprints[0].blueprints[0]!\n : (organised.blueprints[0] as Blueprint)\n const { wire } = assembleWireOnFace(kernel, host, mode, outer)\n return fromBrepCurve(solidToShape(kernel, wire), { solid: wire })\n }\n\n const faces = organised.blueprints.map((entry) => buildPlanarFaceOnHost(kernel, host, mode, entry))\n if (faces.length === 0) throw new Error('sketchOnFace: no contours to place')\n if (faces.length === 1) {\n const f = faces[0]!\n return fromBrep(solidToShape(kernel, f), { solid: f })\n }\n const compound = kernel.makeCompound(faces)\n return fromBrep(solidToShape(kernel, compound), { solid: compound })\n}\n\n/**\n * 把一张平面的法向对齐到参考方向(外部朝向)。网格链上的复制版:BREP 侧的\n * `orientLikeHost` 存在的原因是\"面朝向反了 → 由它拉出的棱柱壳反向 → 体积归零\",\n * 这里同一个道理,只是参考法向来自**平面本身**(`meshFacePlane` 的法向就是从宿主面\n * 的 `surfaceNormal` 取的),不必再回读宿主句柄。\n *\n * @param kernel - the mesh backend's L1 kernel.\n * @param reference - the outward normal the placed face must agree with.\n * @param face - the face built on the plane.\n * @returns a handle to the (possibly re-oriented) face.\n */\nfunction orientFaceTo(kernel: BrepEngineApi, reference: Vec3, face: BrepHandle): BrepHandle {\n const uv = kernel.uvBounds(face)\n const n = kernel.surfaceNormal(face, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2)\n const dot = reference.x * n.x + reference.y * n.y + reference.z * n.z\n return dot < 0 ? kernel.reverseShape(face) : face\n}\n\n/** 一个已归类的轮廓条目(外环 + 可选孔)在平面坐标系里造一张面。 */\nfunction buildFaceOnPlane(\n kernel: BrepEngineApi,\n plane: Plane,\n outward: Vec3,\n entry: Blueprint | CompoundBlueprint,\n): BrepHandle {\n const outerBp = entry instanceof CompoundBlueprint ? entry.blueprints[0]! : entry\n let face = orientFaceTo(kernel, outward, kernel.makeFace(assembleWire(kernel, plane, outerBp)))\n if (entry instanceof CompoundBlueprint) {\n const holes = entry.blueprints.slice(1).map((h) => assembleWire(kernel, plane, h) as never)\n if (holes.length > 0) face = kernel.addHolesInFace(face, holes)\n }\n return face\n}\n\n/**\n * 网格链上的 `cad.sketchOnFace`:在**识别出的平面网格面**上铺 2D 轮廓,产出网格链面\n * (方案 2026-10-01 §4 Phase 3-2),可交给 `cad.extrude` 的网格路径拉伸出新实体。\n *\n * 与 BREP 侧的三点差别,每一点都是\"近似拓扑没有 UV 语义\"的直接后果:\n *\n * 1. **不走 UV 域**。BREP 侧 `assembleWireOnFace` 把 2D 采样点映射进面的 `(u,v)` 域;\n * 而平面在 brepkit 上的域是 ±1e6 的**无限域**(方案 §4 Phase 3-1 实测),拿它当\n * 草图范围毫无意义。这里改用面自己的平面框(原点 = 面包围盒中心、法向 = 面法向),\n * 2D 坐标直接落在平面坐标系里——与 `cad.sketchOnPlane` 的语义一致。\n * 2. **`scaleMode` 只接受 `'original'`**。`'bounds'` / `'native'` 的定义是\"拟合到面的\n * UV 域\",而那个域在这里要么是无限域、要么不存在。静默按 `'original'` 处理会造成\n * \"同一次调用在两条链上得到不同尺寸\"的隐性分歧,所以如实拒绝。\n * 3. **`as:'wire'` 不支持**。网格链上的一根 wire 没有身份槽(面才有),而 sketch 的\n * 下游用途(拉伸)要的正是面。需要 wire 的场景请走 BREP 链。\n *\n * 另外只支持**平面面**:曲面面(STL 圆柱的侧面片)上铺草图需要曲面嵌入,属未开的能力。\n *\n * @param params - contour loops + target mesh solid + face selector + scale mode.\n * @returns the mesh-chain face Shape on the target face.\n * @throws {MeshUnsupportedError} when the target is not a mesh solid, the face is not planar,\n * the scale mode is not `'original'`, `as:'wire'` was requested, or the sketch is multi-island.\n */\nexport function buildSketchOnFaceMesh(params: SketchOnFaceParams): Shape {\n const opLabel = 'sketchOnFace'\n const backend = meshBackendOrThrow(opLabel)\n const kernel = backend.kernel\n\n const mode = params.scaleMode ?? 'original'\n if (mode !== 'original') {\n throw new MeshUnsupportedError(\n `E_MESH_SOLID_UNSUPPORTED: ${opLabel} scaleMode '${mode}' is defined against the face's UV domain, ` +\n 'which a mesh-chain face does not have — use the default \\'original\\' (2D coords live in the face plane)',\n getCurrentStmt(),\n )\n }\n if (params.as === 'wire') {\n throw new MeshUnsupportedError(\n `E_MESH_SOLID_UNSUPPORTED: ${opLabel} as:'wire' has no mesh-chain representation — ` +\n 'a mesh-chain wire has no identity slot; ask for the default as:\\'face\\' instead',\n getCurrentStmt(),\n )\n }\n\n const host = resolveMeshFaceHandle(kernel, params.on, params.face, opLabel)\n const surface = kernel.surfaceType(host)\n if (surface !== 'plane') {\n throw new MeshUnsupportedError(\n `E_MESH_SOLID_UNSUPPORTED: ${opLabel} needs a planar mesh face to sketch on — this face reports ` +\n `surfaceType '${surface}'. Sketches on curved approximate faces are not implemented ` +\n '(an STL cylinder is 32 planar strips, each of which IS usable)',\n getCurrentStmt(),\n )\n }\n\n const plane = meshFacePlane(kernel, host)\n const outward: Vec3 = { x: plane.zDir.x, y: plane.zDir.y, z: plane.zDir.z }\n\n const organised = organiseBlueprints(toContourBlueprints(params.contours))\n if (organised.blueprints.length === 0) throw new Error('sketchOnFace: no contours to place')\n if (organised.blueprints.length > 1) {\n throw new MeshUnsupportedError(\n `E_MESH_SOLID_UNSUPPORTED: ${opLabel} produced ${organised.blueprints.length} disjoint islands — ` +\n 'the mesh backend can only extrude a single face (brepkit extrude takes one face, not a compound). ' +\n 'Sketch and extrude each island separately, then unite them with a boolean',\n getCurrentStmt(),\n )\n }\n\n const face = buildFaceOnPlane(kernel, plane, outward, organised.blueprints[0]!)\n return meshFaceProduct(backend, face)\n}\n\n/**\n * `cad.sketchOnFace`: place 2D contours on a **planar** face of a solid and\n * construct a Shape. Engine-neutral (no `engines` declaration): works on the\n * OCCT BREP engine, the brepkit BREP engine, and the brepkit mesh backend.\n *\n * **网格链**(`meshEngines: ['brepkit']`,方案 2026-10-01 §4 Phase 3):`on` 是网格实体\n * 时,轮廓按面自己的**平面框**铺放(原点 = 面包围盒中心、法向 = 面法向),产物是一张\n * 网格链面,可直接交给 `cad.extrude` 拉伸。该分支只接受平面面、只接受默认\n * `scaleMode`(`'bounds'`/`'native'` 相对 UV 域定义,网格链上没有 UV 域)、只接受\n * `as:'face'`、且只接受单个轮廓岛——每一条越界都以 `E_MESH_SOLID_UNSUPPORTED` 说明原因。\n *\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name sketchOnFace\n * @returns Shape on the target face (face, or a wire curve when `as:'wire'`).\n * @param params.contours - ordered 2D closed contours (same shape as `cad.profile`).type:any[] required:true\n * @param params.on - the target solid on which the face lives.type:Shape required:true\n * @param params.face - the host face: a 1-based ordinal or a `cad.faceRef(on, n)` result.type:any required:true\n * @param params.scaleMode - UV mapping: 'original' (identity) | 'bounds'/'native' (affine-fit; OCCT planar only).type:string required:false\n * @param params.as - `'face'` (default) or `'wire'` (outer loop only).type:string required:false\n */\nexport const sketchOnFace = defineOp({\n meshEngines: ['brepkit'],\n mesh(params: Record<string, unknown>) {\n assertProfileParams(params)\n return buildSketchOnFaceMesh(params as unknown as SketchOnFaceParams)\n },\n brep(params: Record<string, unknown>) {\n assertProfileParams(params)\n return buildSketchOnFaceWith(getBrepApi(), params as unknown as SketchOnFaceParams)\n },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [] } } as Provenance,\n\n paramDims: {},\n})\n"]}
1
+ {"version":3,"file":"sketch-on-face.js","sourceRoot":"","sources":["../../src/api/sketch-on-face.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `cad.sketchOnFace`: place 2D contours onto a **planar** face of an existing\n * solid (E3 placement), engine-neutral.\n *\n * 2026-10-09 split: `sketchOnFace` now owns the *planar* case only and carries\n * **no `engines` declaration** — it is a common op, available on the OCCT BREP\n * engine, the brepkit BREP engine, and the brepkit mesh backend. The\n * curved / UV-conform capability (map into the face's `(u,v)` domain + snap to\n * the surface via `fixWireOnFace`, which needs OCCT) moved to\n * `cad.sketchOnSurface` (`engines: ['occt']`).\n *\n * For a planar face the contour is laid on the face's own plane frame via\n * `assembleWireOnFace` (identity `original` scale mode, or `bounds`/`native`\n * where the engine exposes a finite UV domain) and wrapped as a face with\n * `makeFace` — exact, no surface snapping needed. Non-planar faces are refused\n * up front with a pointer to `cad.sketchOnSurface`.\n *\n * **Two chains, two mechanisms** (plan 2026-10-01 §4 Phase 3). The BREP branch\n * above maps the contour onto the host face's plane. The **mesh branch**\n * (`buildSketchOnFaceMesh`, `meshEngines: ['brepkit']`) works on a mesh solid's\n * approximate topology and deliberately does NOT use a UV domain: a brepkit\n * plane's domain is ±1e6 (an infinite domain), so \"place the sketch in the face's\n * UV range\" is meaningless there. It places the contour in the face's own plane\n * frame instead (origin = face bbox centre, normal = `surfaceNormal`), which\n * matches `cad.sketchOnPlane`'s semantics. The result is a **mesh-chain face**\n * (`ShapeSlot.meshFace`), ready for the mesh branch of `cad.extrude`.\n *\n * For both chains a planar face is required; curved faces are rejected by the\n * BREP branch (→ `cad.sketchOnSurface`) and by the mesh branch (→\n * `E_MESH_SOLID_UNSUPPORTED`).\n * @module\n */\nimport type { Shape } from '../mesh/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { solidToShape } from '../brep/brep-ops'\nimport { fromBrep, fromBrepCurve, brepOf } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { TopoRefError, resolveTopoRef, type FaceTopoRef } from '../topology/naming'\nimport { buildEdgeResolutionContext } from './topo-resolve'\nimport { resolveSelectorToFaceRefs } from './selectors-to-refs'\nimport { Blueprint } from '../geometry2d/blueprint'\nimport { CompoundBlueprint } from '../geometry2d/compound-blueprint'\nimport { organiseBlueprints } from '../geometry2d/organise'\nimport { assembleWireOnFace, type FaceScaleMode } from '../geometry2d/bridge/on-surface'\nimport { assembleWire, type Plane, type Vec3 } from '../geometry2d/bridge/lift-on-plane'\nimport { profileSegToCurve, type ProfileSegLike } from '../geometry2d/adapt'\nimport { assertProfileParams, toContourBlueprints, type ProfileLoop } from './profile'\nimport { MeshUnsupportedError, BrepUnsupportedError, getCurrentStmt, getBackends } from '../runtime-state'\nimport {\n meshBackendOrThrow,\n meshFacePlane,\n meshFaceProduct,\n resolveMeshFaceHandle,\n} from './internal/mesh-solid-op'\n\n/** A face selector on a target solid: a 1-based ordinal (FreeCAD `FaceN`, mesh chain /\n * current kernel snapshot only), a `cad.faceRef` result, or a CadQuery face selector\n * string (e.g. `\">Z\"` — precision chain, resolved on `on`). */\nexport type FaceSelector = number | FaceTopoRef | string\n\n/** Contour loops + the target face for `cad.sketchOnFace`. */\nexport interface SketchOnFaceParams {\n /** Ordered 2D closed contours (same shape as `cad.profile` / `cad.sketchOnPlane`). */\n contours: ProfileLoop[]\n /** The target solid on which the host face lives. */\n on: Shape\n /** The host face: a FaceTopoRef (UI-picked literal), a CadQuery face selector string (e.g. \">Z\", resolved on `on`), or a 1-based face ordinal (mesh chain / current kernel snapshot only). */\n face: FaceSelector\n /** How 2D coords map onto the face UV space: `'original'` (identity) | `'bounds'`/`'native'` (affine-fit). */\n scaleMode?: FaceScaleMode\n /** Result shape: `'face'` (default) builds a face on the contour; `'wire'` returns the outer-loop wire only. */\n as?: 'face' | 'wire'\n}\n\n/**\n * Resolve a face on `on` to its live BREP handle (1-based ordinal, `cad.faceRef`,\n * or CadQuery face selector string resolved on `on`).\n * @param kernel - the BREP engine surface.\n * @param on - the target solid shape.\n * @param selector - the face ordinal, `cad.faceRef` result, or selector string.\n * @returns the live face handle.\n */\nexport function resolveFaceHandle(kernel: BrepEngineApi, on: Shape, selector: FaceSelector): BrepHandle {\n const solid = brepOf(on) as BrepHandle | undefined\n if (solid === undefined) {\n throw new TopoRefError('E_TOPO_MESH_UNSUPPORTED', 'face', 'sketchOnFace: target `on` has no BREP solid')\n }\n if (typeof selector === 'number') {\n const faces = kernel.getSubShapes(solid, 'face')\n if (!Number.isInteger(selector) || selector < 1 || selector > faces.length) {\n throw new TopoRefError(\n 'E_TOPO_NOT_FOUND',\n 'face',\n `sketchOnFace: face ordinal ${selector} out of range [1, ${faces.length}]`,\n )\n }\n return faces[selector - 1] as BrepHandle\n }\n if (typeof selector === 'string') {\n // CadQuery 面选择器字符串(精度链):在 `on` 上解析为单个宿主面。\n const refs = resolveSelectorToFaceRefs(on, selector)\n if (refs.length === 0) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', `sketchOnFace: selector \"${selector}\" matched no face on target`)\n }\n if (refs.length > 1) {\n throw new TopoRefError(\n 'E_TOPO_NOT_FOUND',\n 'face',\n `sketchOnFace: selector \"${selector}\" matched ${refs.length} faces; the host face must be unique`,\n )\n }\n const ctx = buildEdgeResolutionContext(kernel, on as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'sketchOnFace: input has no naming context')\n const resolved = resolveTopoRef(refs[0]!, ctx)\n if (resolved.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'sketchOnFace: selector-resolved face ref resolved to no live handle')\n }\n return resolved.handle as BrepHandle\n }\n if (selector.kind !== 'face') {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'sketchOnFace: selector must be a face ordinal, a selector string, or a face ref')\n }\n const ctx = buildEdgeResolutionContext(kernel, on as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'sketchOnFace: input has no naming context')\n const resolved = resolveTopoRef(selector, ctx)\n if (resolved.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'sketchOnFace: face ref resolved to no live handle')\n }\n return resolved.handle as BrepHandle\n}\n\n/**\n * Make the placed face inherit the host face's outward orientation: surface\n * normals must point the same way, otherwise the resulting face — and any prism\n * extruded from it — carries a reversed shell whose OCCT volume collapses to ~0.\n * @param kernel - the BREP engine surface.\n * @param host - the host face handle (its normal is the reference).\n * @param face - the face built on the host surface.\n * @returns a handle to the (possibly re-oriented) face.\n */\nexport function orientLikeHost(kernel: BrepEngineApi, host: BrepHandle, face: BrepHandle): BrepHandle {\n const a = kernel.surfaceNormal(host, 0, 0)\n const b = kernel.surfaceNormal(face, 0, 0)\n const dot = a.x * b.x + a.y * b.y + a.z * b.z\n return dot < 0 ? kernel.reverseShape(face) : face\n}\n\n/**\n * Build one planar face (outer + optional holes) on the host **planar** face for\n * an organised contour entry. No surface snapping (`fixWireOnFace`) is needed:\n * the wire from `assembleWireOnFace` already lies in the face's plane, so\n * `makeFace` is exact.\n * @param kernel - the BREP engine surface.\n * @param host - the resolved live host face handle.\n * @param mode - the face-scale mode (`original` everywhere; `bounds`/`native` only where the engine exposes a finite UV domain).\n * @param entry - the organised contour entry (outer + optional holes).\n * @returns the built face handle.\n */\nfunction buildPlanarFaceOnHost(\n kernel: BrepEngineApi,\n host: BrepHandle,\n mode: FaceScaleMode,\n entry: Blueprint | CompoundBlueprint,\n): BrepHandle {\n const outerBp = entry instanceof CompoundBlueprint ? entry.blueprints[0]! : entry\n const outerWire = assembleWireOnFace(kernel, host, mode, outerBp).wire\n let face = orientLikeHost(kernel, host, kernel.makeFace(outerWire))\n if (entry instanceof CompoundBlueprint) {\n const holes = entry.blueprints.slice(1).map((h) => assembleWireOnFace(kernel, host, mode, h).wire as never)\n if (holes.length > 0) face = kernel.addHolesInFace(face, holes)\n }\n return face\n}\n\n/**\n * Build a 3D Shape from closed contours placed on the host **planar** face.\n * @param kernel - the BREP engine surface.\n * @param params - contour loops + target solid + face + scale mode.\n * @returns Shape on the target face (face, or the outer wire when `as:'wire'`).\n * @throws {BrepUnsupportedError} when the host face is not planar (use `cad.sketchOnSurface`).\n */\nexport function buildSketchOnFaceWith(kernel: BrepEngineApi, params: SketchOnFaceParams): Shape {\n const host = resolveFaceHandle(kernel, params.on, params.face)\n const mode = params.scaleMode ?? 'original'\n\n // Planar-only gate: the curved / UV-conform capability moved to `cad.sketchOnSurface`.\n const surface = kernel.surfaceType(host)\n if (surface !== 'plane') {\n throw new BrepUnsupportedError(\n `E_BREP_UNSUPPORTED: cad.sketchOnFace only supports planar faces (got surfaceType '${surface}'). ` +\n 'Use cad.sketchOnSurface for curved/UV-conform placement.',\n getCurrentStmt(),\n )\n }\n // brepkit planar faces expose an infinite (±1e6) UV domain, so only the\n // identity 'original' scale mode is meaningful there (mirrors the mesh branch\n // restriction); OCCT planar faces keep full scaleMode support.\n const engineId = getBackends().config.brepEngineId\n if (engineId === 'brepkit' && mode !== 'original') {\n throw new BrepUnsupportedError(\n `E_BREP_UNSUPPORTED: cad.sketchOnFace on a brepkit planar face only supports scaleMode 'original' ` +\n \"(brepkit planar faces have no finite UV domain) — use the default 'original'.\",\n getCurrentStmt(),\n )\n }\n\n const blueprints = params.contours.map(\n (loop) => new Blueprint(loop.segments.map((s) => profileSegToCurve(s as ProfileSegLike))),\n )\n const organised = organiseBlueprints(blueprints)\n\n if (params.as === 'wire') {\n const outer =\n organised.blueprints[0] instanceof CompoundBlueprint\n ? organised.blueprints[0].blueprints[0]!\n : (organised.blueprints[0] as Blueprint)\n const { wire } = assembleWireOnFace(kernel, host, mode, outer)\n return fromBrepCurve(solidToShape(kernel, wire), { solid: wire })\n }\n\n const faces = organised.blueprints.map((entry) => buildPlanarFaceOnHost(kernel, host, mode, entry))\n if (faces.length === 0) throw new Error('sketchOnFace: no contours to place')\n if (faces.length === 1) {\n const f = faces[0]!\n return fromBrep(solidToShape(kernel, f), { solid: f })\n }\n const compound = kernel.makeCompound(faces)\n return fromBrep(solidToShape(kernel, compound), { solid: compound })\n}\n\n/**\n * 把一张平面的法向对齐到参考方向(外部朝向)。网格链上的复制版:BREP 侧的\n * `orientLikeHost` 存在的原因是\"面朝向反了 → 由它拉出的棱柱壳反向 → 体积归零\",\n * 这里同一个道理,只是参考法向来自**平面本身**(`meshFacePlane` 的法向就是从宿主面\n * 的 `surfaceNormal` 取的),不必再回读宿主句柄。\n *\n * @param kernel - the mesh backend's L1 kernel.\n * @param reference - the outward normal the placed face must agree with.\n * @param face - the face built on the plane.\n * @returns a handle to the (possibly re-oriented) face.\n */\nfunction orientFaceTo(kernel: BrepEngineApi, reference: Vec3, face: BrepHandle): BrepHandle {\n const uv = kernel.uvBounds(face)\n const n = kernel.surfaceNormal(face, (uv.uMin + uv.uMax) / 2, (uv.vMin + uv.vMax) / 2)\n const dot = reference.x * n.x + reference.y * n.y + reference.z * n.z\n return dot < 0 ? kernel.reverseShape(face) : face\n}\n\n/** 一个已归类的轮廓条目(外环 + 可选孔)在平面坐标系里造一张面。 */\nfunction buildFaceOnPlane(\n kernel: BrepEngineApi,\n plane: Plane,\n outward: Vec3,\n entry: Blueprint | CompoundBlueprint,\n): BrepHandle {\n const outerBp = entry instanceof CompoundBlueprint ? entry.blueprints[0]! : entry\n let face = orientFaceTo(kernel, outward, kernel.makeFace(assembleWire(kernel, plane, outerBp)))\n if (entry instanceof CompoundBlueprint) {\n const holes = entry.blueprints.slice(1).map((h) => assembleWire(kernel, plane, h) as never)\n if (holes.length > 0) face = kernel.addHolesInFace(face, holes)\n }\n return face\n}\n\n/**\n * 网格链上的 `cad.sketchOnFace`:在**识别出的平面网格面**上铺 2D 轮廓,产出网格链面\n * (方案 2026-10-01 §4 Phase 3-2),可交给 `cad.extrude` 的网格路径拉伸出新实体。\n *\n * 与 BREP 侧的三点差别,每一点都是\"近似拓扑没有 UV 语义\"的直接后果:\n *\n * 1. **不走 UV 域**。BREP 侧 `assembleWireOnFace` 把 2D 采样点映射进面的 `(u,v)` 域;\n * 而平面在 brepkit 上的域是 ±1e6 的**无限域**(方案 §4 Phase 3-1 实测),拿它当\n * 草图范围毫无意义。这里改用面自己的平面框(原点 = 面包围盒中心、法向 = 面法向),\n * 2D 坐标直接落在平面坐标系里——与 `cad.sketchOnPlane` 的语义一致。\n * 2. **`scaleMode` 只接受 `'original'`**。`'bounds'` / `'native'` 的定义是\"拟合到面的\n * UV 域\",而那个域在这里要么是无限域、要么不存在。静默按 `'original'` 处理会造成\n * \"同一次调用在两条链上得到不同尺寸\"的隐性分歧,所以如实拒绝。\n * 3. **`as:'wire'` 不支持**。网格链上的一根 wire 没有身份槽(面才有),而 sketch 的\n * 下游用途(拉伸)要的正是面。需要 wire 的场景请走 BREP 链。\n *\n * 另外只支持**平面面**:曲面面(STL 圆柱的侧面片)上铺草图需要曲面嵌入,属未开的能力。\n *\n * @param params - contour loops + target mesh solid + face selector + scale mode.\n * @returns the mesh-chain face Shape on the target face.\n * @throws {MeshUnsupportedError} when the target is not a mesh solid, the face is not planar,\n * the scale mode is not `'original'`, `as:'wire'` was requested, or the sketch is multi-island.\n */\nexport function buildSketchOnFaceMesh(params: SketchOnFaceParams): Shape {\n const opLabel = 'sketchOnFace'\n const backend = meshBackendOrThrow(opLabel)\n const kernel = backend.kernel\n\n const mode = params.scaleMode ?? 'original'\n if (mode !== 'original') {\n throw new MeshUnsupportedError(\n `E_MESH_SOLID_UNSUPPORTED: ${opLabel} scaleMode '${mode}' is defined against the face's UV domain, ` +\n 'which a mesh-chain face does not have — use the default \\'original\\' (2D coords live in the face plane)',\n getCurrentStmt(),\n )\n }\n if (params.as === 'wire') {\n throw new MeshUnsupportedError(\n `E_MESH_SOLID_UNSUPPORTED: ${opLabel} as:'wire' has no mesh-chain representation — ` +\n 'a mesh-chain wire has no identity slot; ask for the default as:\\'face\\' instead',\n getCurrentStmt(),\n )\n }\n // 选择器字符串只服务精度链(网格零件无 role 层);网格链用 1 起序号。\n if (typeof params.face === 'string') {\n throw new TopoRefError(\n 'E_TOPO_MESH_UNSUPPORTED',\n 'face',\n `sketchOnFace: selector strings are precision-chain only — mesh solids have no role layer (use 1-based face ordinals)`,\n )\n }\n\n const host = resolveMeshFaceHandle(kernel, params.on, params.face, opLabel)\n const surface = kernel.surfaceType(host)\n if (surface !== 'plane') {\n throw new MeshUnsupportedError(\n `E_MESH_SOLID_UNSUPPORTED: ${opLabel} needs a planar mesh face to sketch on — this face reports ` +\n `surfaceType '${surface}'. Sketches on curved approximate faces are not implemented ` +\n '(an STL cylinder is 32 planar strips, each of which IS usable)',\n getCurrentStmt(),\n )\n }\n\n const plane = meshFacePlane(kernel, host)\n const outward: Vec3 = { x: plane.zDir.x, y: plane.zDir.y, z: plane.zDir.z }\n\n const organised = organiseBlueprints(toContourBlueprints(params.contours))\n if (organised.blueprints.length === 0) throw new Error('sketchOnFace: no contours to place')\n if (organised.blueprints.length > 1) {\n throw new MeshUnsupportedError(\n `E_MESH_SOLID_UNSUPPORTED: ${opLabel} produced ${organised.blueprints.length} disjoint islands — ` +\n 'the mesh backend can only extrude a single face (brepkit extrude takes one face, not a compound). ' +\n 'Sketch and extrude each island separately, then unite them with a boolean',\n getCurrentStmt(),\n )\n }\n\n const face = buildFaceOnPlane(kernel, plane, outward, organised.blueprints[0]!)\n return meshFaceProduct(backend, face)\n}\n\n/**\n * `cad.sketchOnFace`: place 2D contours on a **planar** face of a solid and\n * construct a Shape. Engine-neutral (no `engines` declaration): works on the\n * OCCT BREP engine, the brepkit BREP engine, and the brepkit mesh backend.\n *\n * **网格链**(`meshEngines: ['brepkit']`,方案 2026-10-01 §4 Phase 3):`on` 是网格实体\n * 时,轮廓按面自己的**平面框**铺放(原点 = 面包围盒中心、法向 = 面法向),产物是一张\n * 网格链面,可直接交给 `cad.extrude` 拉伸。该分支只接受平面面、只接受默认\n * `scaleMode`(`'bounds'`/`'native'` 相对 UV 域定义,网格链上没有 UV 域)、只接受\n * `as:'face'`、且只接受单个轮廓岛——每一条越界都以 `E_MESH_SOLID_UNSUPPORTED` 说明原因。\n *\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name sketchOnFace\n * @returns Shape on the target face (face, or a wire curve when `as:'wire'`).\n * @param params.contours - ordered 2D closed contours (same shape as `cad.profile`).type:any[] required:true\n * @param params.on - the target solid on which the face lives.type:Shape required:true\n * @param params.face - the host face: FaceTopoRef(UI 拾取产物字面量)| 面选择器字符串(如 \">Z\",在 on 上解析,多面命中抛错)| 1 起序号(仅网格链/当前内核快照,禁止用于生成脚本)。type:any required:true\n * @param params.scaleMode - UV mapping: 'original' (identity) | 'bounds'/'native' (affine-fit; OCCT planar only).type:string required:false\n * @param params.as - `'face'` (default) or `'wire'` (outer loop only).type:string required:false\n * @example\n * // loop = 一个闭合 2D 轮廓:{ segments: [{ kind: 'line', x1, y1, x2, y2 }, ...] }\n * const face = cad.sketchOnFace({ contours: [loop], on: cad.box(20, 20, 10), face: '>Z' })\n */\nexport const sketchOnFace = defineOp({\n meshEngines: ['brepkit'],\n mesh(params: Record<string, unknown>) {\n assertProfileParams(params)\n return buildSketchOnFaceMesh(params as unknown as SketchOnFaceParams)\n },\n brep(params: Record<string, unknown>) {\n assertProfileParams(params)\n return buildSketchOnFaceWith(getBrepApi(), params as unknown as SketchOnFaceParams)\n },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [] } } as Provenance,\n\n paramDims: {},\n})\n"]}
@@ -82,6 +82,9 @@ export declare function buildSketchOnPlaneWith(kernel: BrepEngineApi, params: Sk
82
82
  * @param params.contours - ordered 2D contours (same shape as `cad.profile`: segment loops, or a drawn `Blueprint`).type:any required:true
83
83
  * @param params.plane - named plane (`'XY'` / `'XZ'`…) or `{ origin, normal, xAxis }`.type:any required:true
84
84
  * @param params.as - `'face'` (default) or `'wire'` (outer loop only).type:string required:false
85
+ * @example
86
+ * // loop = 一个闭合 2D 轮廓:{ segments: [{ kind: 'line', x1, y1, x2, y2 }, ...] }
87
+ * const face = cad.sketchOnPlane({ contours: [loop], plane: 'XY' })
85
88
  */
86
89
  export declare const sketchOnPlane: ((params: Record<string, unknown>) => Promise<Shape>) & {
87
90
  __faijs__dualOp?: import("../define-op.js").DualOpMeta;
@@ -1 +1 @@
1
- {"version":3,"file":"sketch-on-plane.d.ts","sourceRoot":"","sources":["../../src/api/sketch-on-plane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAM9D,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAGnD,OAAO,EAAiC,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAEtG,OAAO,EAA4C,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAE1G,wGAAwG;AACxG,MAAM,WAAW,SAAS;IACxB,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,wEAAwE;IACxE,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,yEAAyE;IACzE,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,gFAAgF;IAChF,KAAK,CAAC,EAAE,SAAS,CAAA;CAClB;AAED,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,QAAQ,EAAE,WAAW,EAAE,GAAG,aAAa,CAAA;IACvC,iEAAiE;IACjE,KAAK,EAAE,SAAS,CAAA;IAChB,oGAAoG;IACpG,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,cAAc,GAAE,SAAqB,GAAG,KAAK,CAK/F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,SAAS,EAAE,EACvB,EAAE,GAAE,MAAM,GAAG,MAAe,GAC3B,KAAK,CAgCP;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,mBAAmB,GAAG,KAAK,CAQhG;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa;;CASxB,CAAA"}
1
+ {"version":3,"file":"sketch-on-plane.d.ts","sourceRoot":"","sources":["../../src/api/sketch-on-plane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAM9D,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAGnD,OAAO,EAAiC,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAEtG,OAAO,EAA4C,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAE1G,wGAAwG;AACxG,MAAM,WAAW,SAAS;IACxB,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,wEAAwE;IACxE,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,yEAAyE;IACzE,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,gFAAgF;IAChF,KAAK,CAAC,EAAE,SAAS,CAAA;CAClB;AAED,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,QAAQ,EAAE,WAAW,EAAE,GAAG,aAAa,CAAA;IACvC,iEAAiE;IACjE,KAAK,EAAE,SAAS,CAAA;IAChB,oGAAoG;IACpG,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,cAAc,GAAE,SAAqB,GAAG,KAAK,CAK/F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,SAAS,EAAE,EACvB,EAAE,GAAE,MAAM,GAAG,MAAe,GAC3B,KAAK,CAgCP;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,mBAAmB,GAAG,KAAK,CAQhG;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa;;CASxB,CAAA"}
@@ -93,6 +93,9 @@ export function buildSketchOnPlaneWith(kernel, params) {
93
93
  * @param params.contours - ordered 2D contours (same shape as `cad.profile`: segment loops, or a drawn `Blueprint`).type:any required:true
94
94
  * @param params.plane - named plane (`'XY'` / `'XZ'`…) or `{ origin, normal, xAxis }`.type:any required:true
95
95
  * @param params.as - `'face'` (default) or `'wire'` (outer loop only).type:string required:false
96
+ * @example
97
+ * // loop = 一个闭合 2D 轮廓:{ segments: [{ kind: 'line', x1, y1, x2, y2 }, ...] }
98
+ * const face = cad.sketchOnPlane({ contours: [loop], plane: 'XY' })
96
99
  */
97
100
  export const sketchOnPlane = defineOp({
98
101
  brep(params) {
@@ -1 +1 @@
1
- {"version":3,"file":"sketch-on-plane.js","sourceRoot":"","sources":["../../src/api/sketch-on-plane.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `cad.sketchOnPlane`: lift 2D contours onto an arbitrary plane (E2 placement).\n *\n * This is the shared \"placement\" step of the plan's unified 3D pipeline: any 2D\n * profile source (profile / draw / sketch) that describes contours as\n * `ProfileLoop`s can be placed here, then extruded along the plane normal. The\n * plane is a named plane (`'XY'` / `'XZ'` / `'top'` …) or an explicit frame\n * `{ origin, normal, xAxis }`. The plane lift runs on the geometry2d bridge,\n * which builds exact analytic edges on BOTH engines: full circles via\n * `makeCircleEdge`, arcs via `makeArcEdge` (brepkit's circumcircle defect fixed\n * 2026-09-30). The op therefore carries no engine gate.\n * @module\n */\nimport type { Shape } from '../mesh/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { solidToShape } from '../brep/brep-ops'\nimport { fromBrep, fromBrepCurve } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { Blueprint } from '../geometry2d/blueprint'\nimport { CompoundBlueprint } from '../geometry2d/compound-blueprint'\nimport { organiseBlueprints } from '../geometry2d/organise'\nimport { namedPlane, makePlane, toVec3, type Plane, type Vec3Input } from '../geometry2d/bridge/plane'\nimport { assembleWire } from '../geometry2d/bridge/lift-on-plane'\nimport { assertProfileParams, toContourBlueprints, type DrawnContours, type ProfileLoop } from './profile'\n\n/** A plane given by a named plane and/or an explicit frame (coords accept both array and `{x,y,z}`). */\nexport interface PlaneSpec {\n /** Named plane (`'XY'` / `'XZ'` / `'YZ'` / `'front'` / `'back'` / `'left'` / …). */\n name?: string\n /** The plane origin (default [0,0,0]; array `[x,y,z]` or `{x,y,z}`). */\n origin?: Vec3Input\n /** Explicit normal (used with an explicit frame; array or `{x,y,z}`). */\n normal?: Vec3Input\n /** Explicit in-plane X axis (auto-derived when omitted; array or `{x,y,z}`). */\n xAxis?: Vec3Input\n}\n\n/** Contour loops + a target plane (+ the result mode) for `cad.sketchOnPlane`. */\nexport interface SketchOnPlaneParams {\n /**\n * Contour source: segment loops (`{segments: […]}`) or already-drawn contours\n * (a `Blueprint`, or an array of them). The drawn form is what makes the\n * \"draw → place → extrude\" pipeline real — see {@link DrawnContours}.\n */\n contours: ProfileLoop[] | DrawnContours\n /** Named plane or explicit `{ origin, normal, xAxis }` frame. */\n plane: PlaneSpec\n /** Result shape: 'face' (default) builds a planar face; 'wire' returns the outer-loop wire only. */\n as?: 'face' | 'wire'\n}\n\n/**\n * Resolve a `PlaneSpec` to a plane frame. A named plane wins over an explicit\n * frame; with neither, the XY plane is used.\n * @param planeSpec - the user-facing plane spec (named plane and/or explicit frame).\n * @param fallbackOrigin - the origin used when `planeSpec.origin` is absent (default [0,0,0]).\n * @returns the resolved plane frame.\n */\nexport function resolvePlane(planeSpec: PlaneSpec, fallbackOrigin: Vec3Input = [0, 0, 0]): Plane {\n const o = planeSpec.origin ?? toVec3(fallbackOrigin)\n if (planeSpec.name) return namedPlane(planeSpec.name, o)\n if (planeSpec.normal) return makePlane(o, planeSpec.normal, planeSpec.xAxis)\n return namedPlane('XY', o)\n}\n\n/**\n * Build a 3D Shape (planar face, or outer-loop wire when `as:'wire'`) from a set\n * of classified `Blueprint` contours on a plane. This is the shared placement\n * core for every 2D profile source (`cad.profile` / a drawn contour / sketch): it\n * organises the closed contours (holes vs islands), assembles edge wires on the\n * plane via the geometry2d bridge, and wraps them as a BREP face — ready to be\n * extruded along the plane normal.\n * @param kernel - the BREP engine surface.\n * @param plane - the resolved target plane frame.\n * @param blueprints - ordered closed contours as `Blueprint`s (draw output).\n * @param as - `'face'` (default) or `'wire'` (outer loop only).\n * @returns Shape on the target plane (face, or a wire curve when `as:'wire'`).\n */\nexport function buildShapeFromBlueprints(\n kernel: BrepEngineApi,\n plane: Plane,\n blueprints: Blueprint[],\n as: 'face' | 'wire' = 'face',\n): Shape {\n const organised = organiseBlueprints(blueprints)\n\n if (as === 'wire') {\n const outerBp =\n organised.blueprints[0] instanceof CompoundBlueprint\n ? organised.blueprints[0].blueprints[0]!\n : (organised.blueprints[0] as Blueprint)\n const wire = assembleWire(kernel, plane, outerBp)\n return fromBrepCurve(solidToShape(kernel, wire), { solid: wire })\n }\n\n const faces: ReturnType<BrepEngineApi['makeFace']>[] = []\n for (const entry of organised.blueprints) {\n if (entry instanceof CompoundBlueprint) {\n let face = kernel.makeFace(assembleWire(kernel, plane, entry.blueprints[0]!))\n const holes = entry.blueprints.slice(1).map((h) => assembleWire(kernel, plane, h) as never)\n if (holes.length > 0) {\n face = kernel.addHolesInFace(face, holes)\n }\n faces.push(face)\n } else {\n faces.push(kernel.makeFace(assembleWire(kernel, plane, entry)))\n }\n }\n\n if (faces.length === 1) {\n const f = faces[0]!\n return fromBrep(solidToShape(kernel, f), { solid: f })\n }\n const compound = kernel.makeCompound(faces)\n return fromBrep(solidToShape(kernel, compound), { solid: compound })\n}\n\n/**\n * Build the 2D→3D placement: normalize the contour source (segment loops or a\n * drawn contour) to a classified Blueprint set, assemble a wire on the plane,\n * then wrap as a face (or the outer wire).\n * @param kernel - the BREP engine surface.\n * @param params - contour source + plane + mode.\n * @returns Shape on the target plane (face, or a wire curve when `as:'wire'`).\n */\nexport function buildSketchOnPlaneWith(kernel: BrepEngineApi, params: SketchOnPlaneParams): Shape {\n const plane = resolvePlane(params.plane)\n // 2026-09-28:段环数据与「已绘制轮廓」(`Blueprint`)在此归一。少了这一步,\n // 「draw → sketchOnPlane → extrude」就断了 —— 已绘制轮廓没有 OCCT 句柄,\n // 实测喂 `cad.extrude` 报 `argument carries no BREP handle`、喂 `cad.sweep`\n // 报 `INVALID_SHAPE_ID`,全仓没有第二个能把它变成 Shape 的通道。\n const blueprints = toContourBlueprints(params.contours)\n return buildShapeFromBlueprints(kernel, plane, blueprints, params.as ?? 'face')\n}\n\n/**\n * `cad.sketchOnPlane`: place 2D contours on a plane and construct a Shape.\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name sketchOnPlane\n * @returns Shape on the target plane (face, or a wire curve when `as:'wire'`).\n * @param params.contours - ordered 2D contours (same shape as `cad.profile`: segment loops, or a drawn `Blueprint`).type:any required:true\n * @param params.plane - named plane (`'XY'` / `'XZ'`…) or `{ origin, normal, xAxis }`.type:any required:true\n * @param params.as - `'face'` (default) or `'wire'` (outer loop only).type:string required:false\n */\nexport const sketchOnPlane = defineOp({\n\n brep(params: Record<string, unknown>) {\n assertProfileParams(params)\n return buildSketchOnPlaneWith(getBrepApi(), params as unknown as SketchOnPlaneParams)\n },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [] } } as Provenance,\n\n paramDims: {},\n})"]}
1
+ {"version":3,"file":"sketch-on-plane.js","sourceRoot":"","sources":["../../src/api/sketch-on-plane.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `cad.sketchOnPlane`: lift 2D contours onto an arbitrary plane (E2 placement).\n *\n * This is the shared \"placement\" step of the plan's unified 3D pipeline: any 2D\n * profile source (profile / draw / sketch) that describes contours as\n * `ProfileLoop`s can be placed here, then extruded along the plane normal. The\n * plane is a named plane (`'XY'` / `'XZ'` / `'top'` …) or an explicit frame\n * `{ origin, normal, xAxis }`. The plane lift runs on the geometry2d bridge,\n * which builds exact analytic edges on BOTH engines: full circles via\n * `makeCircleEdge`, arcs via `makeArcEdge` (brepkit's circumcircle defect fixed\n * 2026-09-30). The op therefore carries no engine gate.\n * @module\n */\nimport type { Shape } from '../mesh/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { solidToShape } from '../brep/brep-ops'\nimport { fromBrep, fromBrepCurve } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { Blueprint } from '../geometry2d/blueprint'\nimport { CompoundBlueprint } from '../geometry2d/compound-blueprint'\nimport { organiseBlueprints } from '../geometry2d/organise'\nimport { namedPlane, makePlane, toVec3, type Plane, type Vec3Input } from '../geometry2d/bridge/plane'\nimport { assembleWire } from '../geometry2d/bridge/lift-on-plane'\nimport { assertProfileParams, toContourBlueprints, type DrawnContours, type ProfileLoop } from './profile'\n\n/** A plane given by a named plane and/or an explicit frame (coords accept both array and `{x,y,z}`). */\nexport interface PlaneSpec {\n /** Named plane (`'XY'` / `'XZ'` / `'YZ'` / `'front'` / `'back'` / `'left'` / …). */\n name?: string\n /** The plane origin (default [0,0,0]; array `[x,y,z]` or `{x,y,z}`). */\n origin?: Vec3Input\n /** Explicit normal (used with an explicit frame; array or `{x,y,z}`). */\n normal?: Vec3Input\n /** Explicit in-plane X axis (auto-derived when omitted; array or `{x,y,z}`). */\n xAxis?: Vec3Input\n}\n\n/** Contour loops + a target plane (+ the result mode) for `cad.sketchOnPlane`. */\nexport interface SketchOnPlaneParams {\n /**\n * Contour source: segment loops (`{segments: […]}`) or already-drawn contours\n * (a `Blueprint`, or an array of them). The drawn form is what makes the\n * \"draw → place → extrude\" pipeline real — see {@link DrawnContours}.\n */\n contours: ProfileLoop[] | DrawnContours\n /** Named plane or explicit `{ origin, normal, xAxis }` frame. */\n plane: PlaneSpec\n /** Result shape: 'face' (default) builds a planar face; 'wire' returns the outer-loop wire only. */\n as?: 'face' | 'wire'\n}\n\n/**\n * Resolve a `PlaneSpec` to a plane frame. A named plane wins over an explicit\n * frame; with neither, the XY plane is used.\n * @param planeSpec - the user-facing plane spec (named plane and/or explicit frame).\n * @param fallbackOrigin - the origin used when `planeSpec.origin` is absent (default [0,0,0]).\n * @returns the resolved plane frame.\n */\nexport function resolvePlane(planeSpec: PlaneSpec, fallbackOrigin: Vec3Input = [0, 0, 0]): Plane {\n const o = planeSpec.origin ?? toVec3(fallbackOrigin)\n if (planeSpec.name) return namedPlane(planeSpec.name, o)\n if (planeSpec.normal) return makePlane(o, planeSpec.normal, planeSpec.xAxis)\n return namedPlane('XY', o)\n}\n\n/**\n * Build a 3D Shape (planar face, or outer-loop wire when `as:'wire'`) from a set\n * of classified `Blueprint` contours on a plane. This is the shared placement\n * core for every 2D profile source (`cad.profile` / a drawn contour / sketch): it\n * organises the closed contours (holes vs islands), assembles edge wires on the\n * plane via the geometry2d bridge, and wraps them as a BREP face — ready to be\n * extruded along the plane normal.\n * @param kernel - the BREP engine surface.\n * @param plane - the resolved target plane frame.\n * @param blueprints - ordered closed contours as `Blueprint`s (draw output).\n * @param as - `'face'` (default) or `'wire'` (outer loop only).\n * @returns Shape on the target plane (face, or a wire curve when `as:'wire'`).\n */\nexport function buildShapeFromBlueprints(\n kernel: BrepEngineApi,\n plane: Plane,\n blueprints: Blueprint[],\n as: 'face' | 'wire' = 'face',\n): Shape {\n const organised = organiseBlueprints(blueprints)\n\n if (as === 'wire') {\n const outerBp =\n organised.blueprints[0] instanceof CompoundBlueprint\n ? organised.blueprints[0].blueprints[0]!\n : (organised.blueprints[0] as Blueprint)\n const wire = assembleWire(kernel, plane, outerBp)\n return fromBrepCurve(solidToShape(kernel, wire), { solid: wire })\n }\n\n const faces: ReturnType<BrepEngineApi['makeFace']>[] = []\n for (const entry of organised.blueprints) {\n if (entry instanceof CompoundBlueprint) {\n let face = kernel.makeFace(assembleWire(kernel, plane, entry.blueprints[0]!))\n const holes = entry.blueprints.slice(1).map((h) => assembleWire(kernel, plane, h) as never)\n if (holes.length > 0) {\n face = kernel.addHolesInFace(face, holes)\n }\n faces.push(face)\n } else {\n faces.push(kernel.makeFace(assembleWire(kernel, plane, entry)))\n }\n }\n\n if (faces.length === 1) {\n const f = faces[0]!\n return fromBrep(solidToShape(kernel, f), { solid: f })\n }\n const compound = kernel.makeCompound(faces)\n return fromBrep(solidToShape(kernel, compound), { solid: compound })\n}\n\n/**\n * Build the 2D→3D placement: normalize the contour source (segment loops or a\n * drawn contour) to a classified Blueprint set, assemble a wire on the plane,\n * then wrap as a face (or the outer wire).\n * @param kernel - the BREP engine surface.\n * @param params - contour source + plane + mode.\n * @returns Shape on the target plane (face, or a wire curve when `as:'wire'`).\n */\nexport function buildSketchOnPlaneWith(kernel: BrepEngineApi, params: SketchOnPlaneParams): Shape {\n const plane = resolvePlane(params.plane)\n // 2026-09-28:段环数据与「已绘制轮廓」(`Blueprint`)在此归一。少了这一步,\n // 「draw → sketchOnPlane → extrude」就断了 —— 已绘制轮廓没有 OCCT 句柄,\n // 实测喂 `cad.extrude` 报 `argument carries no BREP handle`、喂 `cad.sweep`\n // 报 `INVALID_SHAPE_ID`,全仓没有第二个能把它变成 Shape 的通道。\n const blueprints = toContourBlueprints(params.contours)\n return buildShapeFromBlueprints(kernel, plane, blueprints, params.as ?? 'face')\n}\n\n/**\n * `cad.sketchOnPlane`: place 2D contours on a plane and construct a Shape.\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name sketchOnPlane\n * @returns Shape on the target plane (face, or a wire curve when `as:'wire'`).\n * @param params.contours - ordered 2D contours (same shape as `cad.profile`: segment loops, or a drawn `Blueprint`).type:any required:true\n * @param params.plane - named plane (`'XY'` / `'XZ'`…) or `{ origin, normal, xAxis }`.type:any required:true\n * @param params.as - `'face'` (default) or `'wire'` (outer loop only).type:string required:false\n * @example\n * // loop = 一个闭合 2D 轮廓:{ segments: [{ kind: 'line', x1, y1, x2, y2 }, ...] }\n * const face = cad.sketchOnPlane({ contours: [loop], plane: 'XY' })\n */\nexport const sketchOnPlane = defineOp({\n\n brep(params: Record<string, unknown>) {\n assertProfileParams(params)\n return buildSketchOnPlaneWith(getBrepApi(), params as unknown as SketchOnPlaneParams)\n },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [] } } as Provenance,\n\n paramDims: {},\n})"]}
@@ -66,9 +66,12 @@ export declare function buildSketchOnSurfaceWith(kernel: BrepEngineApi, params:
66
66
  * @returns Shape on the target face (face, or a wire curve when `as:'wire'`).
67
67
  * @param params.contours - ordered 2D closed contours (same shape as `cad.profile`).type:any[] required:true
68
68
  * @param params.on - the target solid on which the face lives.type:Shape required:true
69
- * @param params.face - the host face: a 1-based ordinal or a `cad.faceRef(on, n)` result.type:any required:true
69
+ * @param params.face - the host face: FaceTopoRef(UI 拾取产物字面量)| 面选择器字符串(如 ">Z",在 on 上解析,多面命中抛错)| 1 起序号(仅网格链/当前内核快照,禁止用于生成脚本)。type:any required:true
70
70
  * @param params.scaleMode - UV mapping: 'original' (identity) | 'bounds'/'native' (affine-fit).type:string required:false
71
71
  * @param params.as - `'face'` (default) or `'wire'` (outer loop only).type:string required:false
72
+ * @example
73
+ * // loop = 一个闭合 2D 轮廓:{ segments: [{ kind: 'line', x1, y1, x2, y2 }, ...] }
74
+ * const sk = cad.sketchOnSurface({ contours: [loop], on: cad.cylinder(20, 30), face: '>Z', scaleMode: 'original' })
72
75
  */
73
76
  export declare const sketchOnSurface: ((params: Record<string, unknown>) => Promise<Shape>) & {
74
77
  __faijs__dualOp?: import("../define-op.js").DualOpMeta;
@@ -1 +1 @@
1
- {"version":3,"file":"sketch-on-surface.d.ts","sourceRoot":"","sources":["../../src/api/sketch-on-surface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAStD,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAA;AAExF,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAEjE,OAAO,EAAqC,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAe7F;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,aAAa,EACnB,QAAQ,EAAE,WAAW,EAAE,GACtB,UAAU,EAAE,CAMd;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,kBAAkB,GAAG,KAAK,CAyBjG;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,eAAe;;CAS1B,CAAA"}
1
+ {"version":3,"file":"sketch-on-surface.d.ts","sourceRoot":"","sources":["../../src/api/sketch-on-surface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAStD,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAA;AAExF,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAEjE,OAAO,EAAqC,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAe7F;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,aAAa,EACnB,QAAQ,EAAE,WAAW,EAAE,GACtB,UAAU,EAAE,CAMd;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,kBAAkB,GAAG,KAAK,CAyBjG;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,eAAe;;CAS1B,CAAA"}
@@ -83,9 +83,12 @@ export function buildSketchOnSurfaceWith(kernel, params) {
83
83
  * @returns Shape on the target face (face, or a wire curve when `as:'wire'`).
84
84
  * @param params.contours - ordered 2D closed contours (same shape as `cad.profile`).type:any[] required:true
85
85
  * @param params.on - the target solid on which the face lives.type:Shape required:true
86
- * @param params.face - the host face: a 1-based ordinal or a `cad.faceRef(on, n)` result.type:any required:true
86
+ * @param params.face - the host face: FaceTopoRef(UI 拾取产物字面量)| 面选择器字符串(如 ">Z",在 on 上解析,多面命中抛错)| 1 起序号(仅网格链/当前内核快照,禁止用于生成脚本)。type:any required:true
87
87
  * @param params.scaleMode - UV mapping: 'original' (identity) | 'bounds'/'native' (affine-fit).type:string required:false
88
88
  * @param params.as - `'face'` (default) or `'wire'` (outer loop only).type:string required:false
89
+ * @example
90
+ * // loop = 一个闭合 2D 轮廓:{ segments: [{ kind: 'line', x1, y1, x2, y2 }, ...] }
91
+ * const sk = cad.sketchOnSurface({ contours: [loop], on: cad.cylinder(20, 30), face: '>Z', scaleMode: 'original' })
89
92
  */
90
93
  export const sketchOnSurface = defineOp({
91
94
  engines: ['occt'],
@@ -1 +1 @@
1
- {"version":3,"file":"sketch-on-surface.js","sourceRoot":"","sources":["../../src/api/sketch-on-surface.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `cad.sketchOnSurface`: place 2D contours onto the UV parameter space of an\n * existing face (E3 placement) — the **curved / UV-conform** sketch op.\n *\n * This is the renamed successor of the old curved-capable `cad.sketchOnFace`\n * (2026-10-09 split). `cad.sketchOnFace` now owns the *planar* face case\n * (engine-neutral, works on OCCT and brepkit BREP as well as mesh solids); this\n * op owns the *surface* case: it maps the contour into the host face's `(u,v)`\n * domain and snaps the resulting wire to the surface via `fixWireOnFace` (occt\n * only), so it is declared `engines: ['occt']`.\n *\n * Unlike `sketchOnPlane` (which lifts a contour onto a whole plane *frame*),\n * `sketchOnSurface` lays the contour on the surface of a specific face of a\n * target solid. Every 2D curve is sampled, the samples mapped into the face's\n * `(u,v)` domain under a scale mode (`original` / `bounds` / `native`), the\n * surface evaluated at those UVs, and a curve edge interpolated through the\n * resulting 3D points (see `geometry2d/bridge/on-surface.ts`). The placed wire\n * then becomes a face (`as:'face'`) ready to be extruded along the face normal,\n * or is returned raw (`as:'wire'`).\n *\n * It is surface-type-independent (plane / cylinder / cone / sphere): for planar\n * host faces `makeFace` is exact, for curved ones the wire is snapped to the\n * surface via `fixWireOnFace` (occt-wasm 5.6) before `makeFace`. The op\n * declares `engines: ['occt']` because that snapping step needs the BREP\n * platform.\n * @module\n */\nimport type { Shape } from '../mesh/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { fromBrep, fromBrepCurve } from '../shape'\nimport { solidToShape } from '../brep/brep-ops'\nimport { defineOp } from '../sdk'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { Blueprint } from '../geometry2d/blueprint'\nimport { CompoundBlueprint } from '../geometry2d/compound-blueprint'\nimport { organiseBlueprints } from '../geometry2d/organise'\nimport { assembleWireOnFace, type FaceScaleMode } from '../geometry2d/bridge/on-surface'\nimport { profileSegToCurve, type ProfileSegLike } from '../geometry2d/adapt'\nimport { assertProfileParams, type ProfileLoop } from './profile'\nimport { fixWireOnFaceBrep } from './brep-operations/healingFns'\nimport { resolveFaceHandle, orientLikeHost, type SketchOnFaceParams } from './sketch-on-face'\n\n/** Build one face (outer + optional holes) on the host face for an organised contour entry (UV-conform). */\nfunction buildOnFace(kernel: BrepEngineApi, host: BrepHandle, mode: FaceScaleMode, entry: Blueprint | CompoundBlueprint): BrepHandle {\n if (entry instanceof CompoundBlueprint) {\n const outerWire = fixWireOnFaceBrep(assembleWireOnFace(kernel, host, mode, entry.blueprints[0]!).wire, host)\n let face = orientLikeHost(kernel, host, kernel.makeFace(outerWire))\n const holes = entry.blueprints.slice(1).map((h) => fixWireOnFaceBrep(assembleWireOnFace(kernel, host, mode, h).wire, host) as never)\n if (holes.length > 0) face = kernel.addHolesInFace(face, holes)\n return face\n }\n const wire = fixWireOnFaceBrep(assembleWireOnFace(kernel, host, mode, entry).wire, host)\n return orientLikeHost(kernel, host, kernel.makeFace(wire))\n}\n\n/**\n * Place `contours` onto the UV space of the host face and return one BREP face\n * per classified contour (each outer + holes folded into a single face). Shared\n * by `cad.sketchOnSurface` (wrap as a Shape) and `cad.punchHole` (extrude → cut).\n * @param kernel - the BREP engine surface.\n * @param host - the resolved live host face handle.\n * @param mode - the face-scale (UV mapping) mode.\n * @param contours - ordered 2D closed contour loops to place.\n * @returns the BREP faces built on the host face (one per organised entry).\n */\nexport function placeContoursOnFace(\n kernel: BrepEngineApi,\n host: BrepHandle,\n mode: FaceScaleMode,\n contours: ProfileLoop[],\n): BrepHandle[] {\n const blueprints = contours.map(\n (loop) => new Blueprint(loop.segments.map((s) => profileSegToCurve(s as ProfileSegLike))),\n )\n const organised = organiseBlueprints(blueprints)\n return organised.blueprints.map((entry) => buildOnFace(kernel, host, mode, entry))\n}\n\n/**\n * Build a 3D Shape from closed contours placed on the host face (UV-conform).\n * @param kernel - the BREP engine surface.\n * @param params - contour loops + target solid + face + scale mode.\n * @returns Shape on the target face (face, or the outer wire when `as:'wire'`).\n */\nexport function buildSketchOnSurfaceWith(kernel: BrepEngineApi, params: SketchOnFaceParams): Shape {\n const host = resolveFaceHandle(kernel, params.on, params.face)\n const mode = params.scaleMode ?? 'original'\n const blueprints = params.contours.map(\n (loop) => new Blueprint(loop.segments.map((s) => profileSegToCurve(s as ProfileSegLike))),\n )\n const organised = organiseBlueprints(blueprints)\n\n if (params.as === 'wire') {\n const outer =\n organised.blueprints[0] instanceof CompoundBlueprint\n ? organised.blueprints[0].blueprints[0]!\n : (organised.blueprints[0] as Blueprint)\n const { wire } = assembleWireOnFace(kernel, host, mode, outer)\n return fromBrepCurve(solidToShape(kernel, wire), { solid: wire })\n }\n\n const faces = placeContoursOnFace(kernel, host, mode, params.contours)\n if (faces.length === 0) throw new Error('sketchOnSurface: no contours to place')\n if (faces.length === 1) {\n const f = faces[0]!\n return fromBrep(solidToShape(kernel, f), { solid: f })\n }\n const compound = kernel.makeCompound(faces)\n return fromBrep(solidToShape(kernel, compound), { solid: compound })\n}\n\n/**\n * `cad.sketchOnSurface`: place 2D contours on a face of a solid via UV-conform\n * placement and construct a Shape.\n *\n * Curved/UV-conform variant of `cad.sketchOnFace` (which is now planar-only and\n * engine-neutral). This op maps the contour into the face's `(u,v)` domain and\n * snaps it to the surface, a step that needs the OCCT BREP platform, hence\n * `engines: ['occt']`.\n *\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name sketchOnSurface\n * @returns Shape on the target face (face, or a wire curve when `as:'wire'`).\n * @param params.contours - ordered 2D closed contours (same shape as `cad.profile`).type:any[] required:true\n * @param params.on - the target solid on which the face lives.type:Shape required:true\n * @param params.face - the host face: a 1-based ordinal or a `cad.faceRef(on, n)` result.type:any required:true\n * @param params.scaleMode - UV mapping: 'original' (identity) | 'bounds'/'native' (affine-fit).type:string required:false\n * @param params.as - `'face'` (default) or `'wire'` (outer loop only).type:string required:false\n */\nexport const sketchOnSurface = defineOp({\n engines: ['occt'],\n brep(params: Record<string, unknown>) {\n assertProfileParams(params)\n return buildSketchOnSurfaceWith(getBrepApi(), params as unknown as SketchOnFaceParams)\n },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [] } } as Provenance,\n\n paramDims: {},\n})\n"]}
1
+ {"version":3,"file":"sketch-on-surface.js","sourceRoot":"","sources":["../../src/api/sketch-on-surface.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `cad.sketchOnSurface`: place 2D contours onto the UV parameter space of an\n * existing face (E3 placement) — the **curved / UV-conform** sketch op.\n *\n * This is the renamed successor of the old curved-capable `cad.sketchOnFace`\n * (2026-10-09 split). `cad.sketchOnFace` now owns the *planar* face case\n * (engine-neutral, works on OCCT and brepkit BREP as well as mesh solids); this\n * op owns the *surface* case: it maps the contour into the host face's `(u,v)`\n * domain and snaps the resulting wire to the surface via `fixWireOnFace` (occt\n * only), so it is declared `engines: ['occt']`.\n *\n * Unlike `sketchOnPlane` (which lifts a contour onto a whole plane *frame*),\n * `sketchOnSurface` lays the contour on the surface of a specific face of a\n * target solid. Every 2D curve is sampled, the samples mapped into the face's\n * `(u,v)` domain under a scale mode (`original` / `bounds` / `native`), the\n * surface evaluated at those UVs, and a curve edge interpolated through the\n * resulting 3D points (see `geometry2d/bridge/on-surface.ts`). The placed wire\n * then becomes a face (`as:'face'`) ready to be extruded along the face normal,\n * or is returned raw (`as:'wire'`).\n *\n * It is surface-type-independent (plane / cylinder / cone / sphere): for planar\n * host faces `makeFace` is exact, for curved ones the wire is snapped to the\n * surface via `fixWireOnFace` (occt-wasm 5.6) before `makeFace`. The op\n * declares `engines: ['occt']` because that snapping step needs the BREP\n * platform.\n * @module\n */\nimport type { Shape } from '../mesh/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { BrepHandle } from '../brep/engine/types'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { fromBrep, fromBrepCurve } from '../shape'\nimport { solidToShape } from '../brep/brep-ops'\nimport { defineOp } from '../sdk'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { Blueprint } from '../geometry2d/blueprint'\nimport { CompoundBlueprint } from '../geometry2d/compound-blueprint'\nimport { organiseBlueprints } from '../geometry2d/organise'\nimport { assembleWireOnFace, type FaceScaleMode } from '../geometry2d/bridge/on-surface'\nimport { profileSegToCurve, type ProfileSegLike } from '../geometry2d/adapt'\nimport { assertProfileParams, type ProfileLoop } from './profile'\nimport { fixWireOnFaceBrep } from './brep-operations/healingFns'\nimport { resolveFaceHandle, orientLikeHost, type SketchOnFaceParams } from './sketch-on-face'\n\n/** Build one face (outer + optional holes) on the host face for an organised contour entry (UV-conform). */\nfunction buildOnFace(kernel: BrepEngineApi, host: BrepHandle, mode: FaceScaleMode, entry: Blueprint | CompoundBlueprint): BrepHandle {\n if (entry instanceof CompoundBlueprint) {\n const outerWire = fixWireOnFaceBrep(assembleWireOnFace(kernel, host, mode, entry.blueprints[0]!).wire, host)\n let face = orientLikeHost(kernel, host, kernel.makeFace(outerWire))\n const holes = entry.blueprints.slice(1).map((h) => fixWireOnFaceBrep(assembleWireOnFace(kernel, host, mode, h).wire, host) as never)\n if (holes.length > 0) face = kernel.addHolesInFace(face, holes)\n return face\n }\n const wire = fixWireOnFaceBrep(assembleWireOnFace(kernel, host, mode, entry).wire, host)\n return orientLikeHost(kernel, host, kernel.makeFace(wire))\n}\n\n/**\n * Place `contours` onto the UV space of the host face and return one BREP face\n * per classified contour (each outer + holes folded into a single face). Shared\n * by `cad.sketchOnSurface` (wrap as a Shape) and `cad.punchHole` (extrude → cut).\n * @param kernel - the BREP engine surface.\n * @param host - the resolved live host face handle.\n * @param mode - the face-scale (UV mapping) mode.\n * @param contours - ordered 2D closed contour loops to place.\n * @returns the BREP faces built on the host face (one per organised entry).\n */\nexport function placeContoursOnFace(\n kernel: BrepEngineApi,\n host: BrepHandle,\n mode: FaceScaleMode,\n contours: ProfileLoop[],\n): BrepHandle[] {\n const blueprints = contours.map(\n (loop) => new Blueprint(loop.segments.map((s) => profileSegToCurve(s as ProfileSegLike))),\n )\n const organised = organiseBlueprints(blueprints)\n return organised.blueprints.map((entry) => buildOnFace(kernel, host, mode, entry))\n}\n\n/**\n * Build a 3D Shape from closed contours placed on the host face (UV-conform).\n * @param kernel - the BREP engine surface.\n * @param params - contour loops + target solid + face + scale mode.\n * @returns Shape on the target face (face, or the outer wire when `as:'wire'`).\n */\nexport function buildSketchOnSurfaceWith(kernel: BrepEngineApi, params: SketchOnFaceParams): Shape {\n const host = resolveFaceHandle(kernel, params.on, params.face)\n const mode = params.scaleMode ?? 'original'\n const blueprints = params.contours.map(\n (loop) => new Blueprint(loop.segments.map((s) => profileSegToCurve(s as ProfileSegLike))),\n )\n const organised = organiseBlueprints(blueprints)\n\n if (params.as === 'wire') {\n const outer =\n organised.blueprints[0] instanceof CompoundBlueprint\n ? organised.blueprints[0].blueprints[0]!\n : (organised.blueprints[0] as Blueprint)\n const { wire } = assembleWireOnFace(kernel, host, mode, outer)\n return fromBrepCurve(solidToShape(kernel, wire), { solid: wire })\n }\n\n const faces = placeContoursOnFace(kernel, host, mode, params.contours)\n if (faces.length === 0) throw new Error('sketchOnSurface: no contours to place')\n if (faces.length === 1) {\n const f = faces[0]!\n return fromBrep(solidToShape(kernel, f), { solid: f })\n }\n const compound = kernel.makeCompound(faces)\n return fromBrep(solidToShape(kernel, compound), { solid: compound })\n}\n\n/**\n * `cad.sketchOnSurface`: place 2D contours on a face of a solid via UV-conform\n * placement and construct a Shape.\n *\n * Curved/UV-conform variant of `cad.sketchOnFace` (which is now planar-only and\n * engine-neutral). This op maps the contour into the face's `(u,v)` domain and\n * snaps it to the surface, a step that needs the OCCT BREP platform, hence\n * `engines: ['occt']`.\n *\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name sketchOnSurface\n * @returns Shape on the target face (face, or a wire curve when `as:'wire'`).\n * @param params.contours - ordered 2D closed contours (same shape as `cad.profile`).type:any[] required:true\n * @param params.on - the target solid on which the face lives.type:Shape required:true\n * @param params.face - the host face: FaceTopoRef(UI 拾取产物字面量)| 面选择器字符串(如 \">Z\",在 on 上解析,多面命中抛错)| 1 起序号(仅网格链/当前内核快照,禁止用于生成脚本)。type:any required:true\n * @param params.scaleMode - UV mapping: 'original' (identity) | 'bounds'/'native' (affine-fit).type:string required:false\n * @param params.as - `'face'` (default) or `'wire'` (outer loop only).type:string required:false\n * @example\n * // loop = 一个闭合 2D 轮廓:{ segments: [{ kind: 'line', x1, y1, x2, y2 }, ...] }\n * const sk = cad.sketchOnSurface({ contours: [loop], on: cad.cylinder(20, 30), face: '>Z', scaleMode: 'original' })\n */\nexport const sketchOnSurface = defineOp({\n engines: ['occt'],\n brep(params: Record<string, unknown>) {\n assertProfileParams(params)\n return buildSketchOnSurfaceWith(getBrepApi(), params as unknown as SketchOnFaceParams)\n },\n naming: { kind: 'construct', newFaces: { via: 'explicit', vocab: [] } } as Provenance,\n\n paramDims: {},\n})\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"view-projection.d.ts","sourceRoot":"","sources":["../../../src/api/view/view-projection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAK7C,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAA;AAU5D,0BAA0B;AAC1B,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sBAAsB;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,oCAAoC;AACpC,MAAM,WAAW,aAAa;IAC5B,kBAAkB;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAA;IACf,8BAA8B;IAC9B,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IAC9C,eAAe;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AA8MD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAE,kBAAuB,GAAG,aAAa,CA2BzG;AAED;;;;;;;;;;;;;;;;;;;IAmBI;AACJ,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAE3F"}
1
+ {"version":3,"file":"view-projection.d.ts","sourceRoot":"","sources":["../../../src/api/view/view-projection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAK7C,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAA;AAU5D,0BAA0B;AAC1B,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sBAAsB;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,oCAAoC;AACpC,MAAM,WAAW,aAAa;IAC5B,kBAAkB;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAA;IACf,8BAA8B;IAC9B,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IAC9C,eAAe;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAqND;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAE,kBAAuB,GAAG,aAAa,CA2BzG;AAED;;;;;;;;;;;;;;;;;;;IAmBI;AACJ,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAE3F"}
@@ -28,8 +28,15 @@ import { brepOf } from '../../shape.js';
28
28
  import { getBrepApi } from '../../brep/handle-bridge.js';
29
29
  import { getBackends } from '../../runtime-state.js';
30
30
  import { resolveCamera } from './view-camera.js';
31
- /** 每条边的 3D 采样点数(直线 2 点;曲线分段近似)。 */
32
- const EDGE_SAMPLES = 5;
31
+ /**
32
+ * 每条边的 3D 采样点数(occt compound 通道的曲线分段近似;brepkit 原生
33
+ * 通道由内核输出折线,不经本参数)。
34
+ *
35
+ * 2026-10-14 修复:5 点时圆/椭圆轮廓被离散成五边形/八边形级折线——web 端
36
+ * 工程图实测圆柱 iso 轴测图呈多面体感、top 俯视图圆环呈菱形。提高到 48 点
37
+ * 后椭圆视觉光滑。直线边多点采样点仍共线,无视觉差异,故不做边类型分流。
38
+ */
39
+ const EDGE_SAMPLES = 48;
33
40
  /** 3D 点 → 相机平面 2D 坐标。
34
41
  *
35
42
  * GOTCHA: occt-wasm 的 HLR projectEdges 已把边投影到相机平面,输出坐标 =
@@ -1 +1 @@
1
- {"version":3,"file":"view-projection.js","sourceRoot":"","sources":["../../../src/api/view/view-projection.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * view-projection — 单视图投影 → SVG 线稿(faijs 视图投影能力,路径 A)\n *\n * projectView(shape, view, opts?) 返回**纯数据 SVG 字符串**(非 Shape):\n * - 直连 core 引擎的 HLR 投影(`BrepEngineApi.projectEdges`,OCCT\n * HLRBRep 隐线消除):可见 / 隐藏两组边(sharp/smooth/outline compound);\n * - 每组边 → 3D 曲线采样折线(`curveParameters` + `curvePointAtParam`)→\n * 投影到相机平面(正交投影,坐标 = 相对 camera.origin 在 xAxis/yAxis 上的分量);\n * - 序列化为一个完整 SVG:可见轮廓实线 + 隐藏线虚线(stroke-dasharray)。\n *\n * 返回字符串绕开 arg-spec 对 projectEdges/makeProjectedEdges 的 skip 障碍\n * (Edge 句柄数组 + compound 生命周期无法静态收养——本 op 只在内部消费,\n * 产物是 2D 纯文本,无收养问题)。\n *\n * 2026-09-25 core-decouple wrapup(§3.1 A 案):不再依赖 brepjs 的 HLR+2D\n * drawing 链——HLR 由 core 引擎原生提供(occt-wasm projectEdges),2D SVG\n * 序列化为本地实现(曲线边以采样折线近似)。\n *\n * 2026-10-11 双方言通道(方案 docs/plans/2026-10-11-brepkit-svg-view.md,与\n * STEP 引擎中立化同基调:按引擎 id 静态分派通道,无门禁、无 engines 声明、\n * 不因内核缺特性报错):\n * - occt:HLR compound 句柄 → getSubShapes → 3D 曲线采样 → 相机平面投影;\n * - brepkit:内核原生 `projectEdges` 直接返回已投影 2D 折线 JSON\n * `{\"visible\":[[x,y,…],…],\"hidden\":[…]}`(每条折线 = 扁平 x,y 点对数组;\n * y 轴 = x_axis × view,与 occt 输出坐标约定同构),解析后直接序列化。\n */\n\nimport type { Shape } from '../../mesh/types'\nimport { brepOf } from '../../shape'\nimport { getBrepApi } from '../../brep/handle-bridge'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport { getBackends } from '../../runtime-state'\nimport { resolveCamera, type ViewSpec } from './view-camera'\n\n/** 投影相机(与 view-camera 输出同构)。 */\ninterface Camera {\n readonly position: [number, number, number]\n readonly direction: [number, number, number]\n readonly xAxis: [number, number, number]\n readonly yAxis: [number, number, number]\n}\n\n/** projectView 的序列化选项。 */\nexport interface ProjectViewOptions {\n /** viewBox 四周留白(单位 = 投影平面坐标单位;缺省 1)。 */\n margin?: number\n /** 可见/隐藏线 stroke-width(像素;缺省 1)。 */\n strokeWidth?: number\n /** 隐藏线虚线样式(SVG stroke-dasharray;缺省 '4,4')。 */\n dash?: string\n /** 隐藏线透明度(缺省 0.6)。 */\n hiddenOpacity?: number\n /** 输出 SVG 宽度(缺省 = viewBox 宽度)。 */\n width?: number\n /** 输出 SVG 高度(缺省 = viewBox 高度)。 */\n height?: number\n}\n\n/** 单视图投影的结构化结果(projectSheet 复用)。 */\nexport interface ProjectionSvg {\n /** 完整 SVG 字符串。 */\n svg: string\n /** viewBox 属性值('minX minY w h';可见 ∪ 隐藏线并集 + margin)。 */\n viewBox: string\n /** 各 path d 串:可见实线 / 隐藏虚线。 */\n paths: { visible: string[]; hidden: string[] }\n /** 输出宽度/高度。 */\n width: number\n height: number\n}\n\n/** 每条边的 3D 采样点数(直线 2 点;曲线分段近似)。 */\nconst EDGE_SAMPLES = 5\n\ntype Vec3 = readonly [number, number, number]\n\n/** 3D 点 → 相机平面 2D 坐标。\n *\n * GOTCHA: occt-wasm 的 HLR projectEdges 已把边投影到相机平面,输出坐标 =\n * (沿 xAxis 的水平分量, 沿 cross(direction, xAxis) 的垂直分量, 沿 direction\n * 的深度分量≈0)——不是世界坐标。因此 2D 坐标直接取输出的前两分量,不再做\n * dot 二次投影(否则会把垂直信息读丢——垂直在 p.y 而非 p.z)。\n */\nfunction projectTo2D(p: Vec3, _cam: Camera): [number, number] {\n return [p[0], p[1]]\n}\n\n/** 引擎 projectEdges 的返回结构(occt-wasm:6 组 compound 的 arena id)。 */\ninterface ProjectEdgesResult {\n visibleSharp: number\n visibleSmooth: number\n visibleOutline: number\n hiddenSharp: number\n hiddenSmooth: number\n hiddenOutline: number\n}\n\nconst COMPOUND_KEYS = [\n ['visibleSharp', 'visible'],\n ['visibleSmooth', 'visible'],\n ['visibleOutline', 'visible'],\n ['hiddenSharp', 'hidden'],\n ['hiddenSmooth', 'hidden'],\n ['hiddenOutline', 'hidden'],\n] as const\n\n/**\n * HLR 投影 shape → 可见/隐藏 2D 折线(SVG d 串)。\n * 按引擎 id 静态分派方言通道(见文件头 2026-10-11 注):\n * - brepkit → 内核原生折线 JSON 通道;\n * - 其余(含 occt)→ compound 句柄采样通道(现状)。\n * 无引擎门禁:分派只选通道,不因内核缺特性报错。\n */\nfunction projectPolylines(shape: Shape, view: ViewSpec): { visible: string[]; hidden: string[] } {\n const solid = brepOf(shape) as BrepHandle | undefined\n if (solid === undefined) {\n throw new Error(\n '[faijs/view-projection] E_BREP_ONLY_INPUT: operation requires a BREP-backed shape ' +\n '(mesh-only input cannot be projected)',\n )\n }\n const api = getBrepApi()\n const cam = resolveCamera(view) as unknown as Camera\n const engineId = getBackends().config.brepEngineId\n if (engineId === 'brepkit') {\n return projectPolylinesNative(api, solid, cam)\n }\n return projectPolylinesCompound(api, solid, cam)\n}\n\n/** projectEdges 的公共调用参数(两方言同构,签名见 brep/engine/primitives.ts)。 */\nfunction projectEdgesArgs(cam: Camera) {\n return [\n { x: cam.position[0], y: cam.position[1], z: cam.position[2] },\n { x: cam.direction[0], y: cam.direction[1], z: cam.direction[2] },\n { x: cam.xAxis[0], y: cam.xAxis[1], z: cam.xAxis[2] },\n true,\n 0.1,\n ] as const\n}\n\n/**\n * brepkit 原生通道:内核 projectEdges 返回 JSON 字符串\n * `{\"visible\":[[x,y,…],…],\"hidden\":[…]}`(每条折线 = 扁平 x,y 点对数组,已是\n * 相机平面 2D 坐标),解析后直接转 SVG path d 串。内核返回非法 JSON 属实现\n * 缺陷,直接抛错暴露(非\"缺特性\",不受无门禁基调豁免)。\n */\nfunction projectPolylinesNative(\n api: ReturnType<typeof getBrepApi>,\n solid: BrepHandle,\n cam: Camera,\n): { visible: string[]; hidden: string[] } {\n const [origin, direction, xAxis] = projectEdgesArgs(cam)\n const raw = api.projectEdges(solid, origin, direction, xAxis, true, 0.1)\n const parsed = parseNativeProjection(raw)\n return {\n visible: parsed.visible.map(polylineToPath),\n hidden: parsed.hidden.map(polylineToPath),\n }\n}\n\n/** 解析 brepkit projectEdges 的折线 JSON(结构错误一律抛错暴露)。 */\nfunction parseNativeProjection(raw: unknown): { visible: number[][]; hidden: number[][] } {\n if (typeof raw !== 'string') {\n throw new Error(\n `[faijs/view-projection] E_PROJECTION_DIALECT: native projectEdges returned ${typeof raw}, expected JSON string`,\n )\n }\n const obj = JSON.parse(raw) as { visible?: unknown; hidden?: unknown }\n const flat = (v: unknown): number[][] => {\n if (!Array.isArray(v)) throw new Error('[faijs/view-projection] E_PROJECTION_DIALECT: malformed native projection JSON')\n return v.filter((p): p is number[] => Array.isArray(p) && p.length >= 4)\n }\n return { visible: flat(obj.visible), hidden: flat(obj.hidden) }\n}\n\n/** 扁平 x,y 点对数组 → SVG path d 串(M + L 序列)。 */\nfunction polylineToPath(poly: number[]): string {\n let d = `M ${poly[0].toFixed(4)} ${poly[1].toFixed(4)}`\n for (let i = 2; i + 1 < poly.length; i += 2) {\n d += ` L ${poly[i].toFixed(4)} ${poly[i + 1].toFixed(4)}`\n }\n return d\n}\n\n/**\n * occt compound 通道(现状,逐字节不变):HLR 输出 6 组 compound 的 arena id,\n * 逐 compound 取边 → 3D 曲线采样 → 相机平面投影。\n * 全部句柄在本函数内释放(compound + 边;输入 shape 不消费)。\n */\nfunction projectPolylinesCompound(\n api: ReturnType<typeof getBrepApi>,\n solid: BrepHandle,\n cam: Camera,\n): { visible: string[]; hidden: string[] } {\n const [origin, direction, xAxis] = projectEdgesArgs(cam)\n const r = api.projectEdges(solid, origin, direction, xAxis, true, 0.1) as ProjectEdgesResult\n\n const out: { visible: string[]; hidden: string[] } = { visible: [], hidden: [] }\n const toHandle = (id: number): BrepHandle => id as BrepHandle\n try {\n for (const [key, group] of COMPOUND_KEYS) {\n const compoundId = r[key]\n if (typeof compoundId !== 'number' || compoundId === 0) continue\n const edges = api.getSubShapes(toHandle(compoundId), 'edge')\n for (const edge of edges) {\n const d = edgeToPath(api, edge, cam)\n if (d !== null) out[group].push(d)\n }\n // 释放 compound slot(幂等)\n try {\n api.release(toHandle(compoundId))\n } catch {\n // already released\n }\n }\n } finally {\n void 0\n }\n return out\n}\n\n/** 单条边 → SVG path d 串(3D 曲线采样折线投影到相机平面)。 */\nfunction edgeToPath(api: ReturnType<typeof getBrepApi>, edge: BrepHandle, cam: Camera): string | null {\n let cp\n try {\n cp = api.curveParameters(edge)\n } catch {\n return null // 退化边(如孤立顶点线)无曲线参数\n }\n const { first, last } = cp\n const span = last - first\n const pts: [number, number][] = []\n for (let i = 0; i < EDGE_SAMPLES; i += 1) {\n const t = first + (span * i) / (EDGE_SAMPLES - 1)\n const p = api.curvePointAtParam(edge, t)\n pts.push(projectTo2D([p.x, p.y, p.z], cam))\n }\n if (pts.length < 2) return null\n let d = `M ${pts[0][0].toFixed(4)} ${pts[0][1].toFixed(4)}`\n for (let i = 1; i < pts.length; i += 1) {\n d += ` L ${pts[i][0].toFixed(4)} ${pts[i][1].toFixed(4)}`\n }\n return d\n}\n\n/** 解析 'minX minY w h' 为数值数组。 */\nfunction parseViewBox(vb: string): [number, number, number, number] | undefined {\n const parts = vb.trim().split(/\\s+/).map(Number)\n if (parts.length !== 4 || parts.some((n) => !Number.isFinite(n))) return undefined\n return [parts[0], parts[1], parts[2], parts[3]]\n}\n\n/** 折线点集 bbox → viewBox(统一坐标系;margin 再外扩)。 */\nfunction viewBoxOfPaths(paths: string[], margin: number): string {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const d of paths) {\n const nums = d.match(/[-+]?\\d*\\.?\\d+(?:[eE][-+]?\\d+)?/g) ?? []\n for (let i = 0; i + 1 < nums.length; i += 2) {\n const x = Number(nums[i])\n const y = Number(nums[i + 1])\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue\n minX = Math.min(minX, x)\n minY = Math.min(minY, y)\n maxX = Math.max(maxX, x)\n maxY = Math.max(maxY, y)\n }\n }\n if (!Number.isFinite(minX)) return '0 0 0 0' // 空投影(如空 shape)\n return `${minX - margin} ${minY - margin} ${maxX - minX + 2 * margin} ${maxY - minY + 2 * margin}`\n}\n\n/**\n * 单视图投影(结构化结果)。\n *\n * @param shape - 待投影的 faijs Shape(必须带 BREP 槽;mesh-only 输入抛 E_BREP_ONLY_INPUT)。\n * @param view - 视图规格(标准视图 / iso / 轴对平面 / 方向对象)。\n * @param opts - 序列化选项。\n * @returns 结构化投影结果(svg/viewBox/paths/尺寸)。\n */\nexport function projectViewSvg(shape: Shape, view: ViewSpec, opts: ProjectViewOptions = {}): ProjectionSvg {\n const { visible: visiblePaths, hidden: hiddenPaths } = projectPolylines(shape, view)\n const margin = opts.margin ?? 1\n const viewBox = viewBoxOfPaths([...visiblePaths, ...hiddenPaths], margin)\n const parsed = parseViewBox(viewBox) ?? [0, 0, 0, 0]\n const width = opts.width ?? parsed[2]\n const height = opts.height ?? parsed[3]\n const strokeWidth = opts.strokeWidth ?? 1\n const dash = opts.dash ?? '4,4'\n const hiddenOpacity = opts.hiddenOpacity ?? 0.6\n const visibleMarkup = visiblePaths\n .map((d) => `<path d=\"${d}\" fill=\"none\" stroke=\"#000\" stroke-width=\"${strokeWidth}\" />`)\n .join('\\n ')\n const hiddenMarkup = hiddenPaths\n .map(\n (d) =>\n `<path d=\"${d}\" fill=\"none\" stroke=\"#000\" stroke-width=\"${strokeWidth}\" stroke-dasharray=\"${dash}\" opacity=\"${hiddenOpacity}\" />`,\n )\n .join('\\n ')\n const svg = [\n `<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"${viewBox}\" width=\"${width}\" height=\"${height}\" fill=\"none\" stroke=\"black\" stroke-width=\"0.6%\" vector-effect=\"non-scaling-stroke\">`,\n ` <g stroke=\"#000\" fill=\"none\">`,\n ` ${visibleMarkup}${hiddenMarkup === '' ? '' : `\\n ${hiddenMarkup}`}`,\n ` </g>`,\n `</svg>`,\n ].join('\\n')\n return { svg, viewBox, paths: { visible: visiblePaths, hidden: hiddenPaths }, width, height }\n}\n\n/**\n * 单视图投影 → SVG 线稿字符串(纯数据,不消费/修改 shape;规则 1 下裸调用不消费输入)。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name projectView\n * @returns SVG 字符串(<svg viewBox=\"…\"> + 可见实线 <path> + 隐藏虚线 <path>)。裸调用 cad.projectView(part0, 'front') 不消费 part0(规则 1),part 仍留在 canvas。\n * @param shape - 目标几何(必须有 BREP 槽;mesh-only 抛 E_BREP_ONLY_INPUT)。type:Shape required:true\n * @param view - 视图规格(同 viewCamera:标准视图名 / iso / 轴对平面 / 方向对象)。type:string|{dir,xAxis?} required:true\n * @param opts.strokeWidth - 可见线宽(stroke-width)。type:number 默认 1\n * @param opts.dash - 隐藏线虚线样式(stroke-dasharray)。type:string 默认 '4,4'\n * @param opts.hiddenOpacity - 隐藏线透明度。type:number 默认 0.6\n * @param opts.margin - viewBox 外扩边距。type:number 默认 1\n * @param opts.width - 输出宽度(缺省 = viewBox 宽度)。type:number\n * @param opts.height - 输出高度(缺省 = viewBox 高度)。type:number\n * @example\n * const svg = cad.projectView(part0, 'front')\n * const svg = cad.projectView(part0, 'iso', { strokeWidth: 1, dash: '4,4', hiddenOpacity: 0.6 })\n */\nexport function projectView(shape: Shape, view: ViewSpec, opts?: ProjectViewOptions): string {\n return projectViewSvg(shape, view, opts).svg\n}\n"]}
1
+ {"version":3,"file":"view-projection.js","sourceRoot":"","sources":["../../../src/api/view/view-projection.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * view-projection — 单视图投影 → SVG 线稿(faijs 视图投影能力,路径 A)\n *\n * projectView(shape, view, opts?) 返回**纯数据 SVG 字符串**(非 Shape):\n * - 直连 core 引擎的 HLR 投影(`BrepEngineApi.projectEdges`,OCCT\n * HLRBRep 隐线消除):可见 / 隐藏两组边(sharp/smooth/outline compound);\n * - 每组边 → 3D 曲线采样折线(`curveParameters` + `curvePointAtParam`)→\n * 投影到相机平面(正交投影,坐标 = 相对 camera.origin 在 xAxis/yAxis 上的分量);\n * - 序列化为一个完整 SVG:可见轮廓实线 + 隐藏线虚线(stroke-dasharray)。\n *\n * 返回字符串绕开 arg-spec 对 projectEdges/makeProjectedEdges 的 skip 障碍\n * (Edge 句柄数组 + compound 生命周期无法静态收养——本 op 只在内部消费,\n * 产物是 2D 纯文本,无收养问题)。\n *\n * 2026-09-25 core-decouple wrapup(§3.1 A 案):不再依赖 brepjs 的 HLR+2D\n * drawing 链——HLR 由 core 引擎原生提供(occt-wasm projectEdges),2D SVG\n * 序列化为本地实现(曲线边以采样折线近似)。\n *\n * 2026-10-11 双方言通道(方案 docs/plans/2026-10-11-brepkit-svg-view.md,与\n * STEP 引擎中立化同基调:按引擎 id 静态分派通道,无门禁、无 engines 声明、\n * 不因内核缺特性报错):\n * - occt:HLR compound 句柄 → getSubShapes → 3D 曲线采样 → 相机平面投影;\n * - brepkit:内核原生 `projectEdges` 直接返回已投影 2D 折线 JSON\n * `{\"visible\":[[x,y,…],…],\"hidden\":[…]}`(每条折线 = 扁平 x,y 点对数组;\n * y 轴 = x_axis × view,与 occt 输出坐标约定同构),解析后直接序列化。\n */\n\nimport type { Shape } from '../../mesh/types'\nimport { brepOf } from '../../shape'\nimport { getBrepApi } from '../../brep/handle-bridge'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport { getBackends } from '../../runtime-state'\nimport { resolveCamera, type ViewSpec } from './view-camera'\n\n/** 投影相机(与 view-camera 输出同构)。 */\ninterface Camera {\n readonly position: [number, number, number]\n readonly direction: [number, number, number]\n readonly xAxis: [number, number, number]\n readonly yAxis: [number, number, number]\n}\n\n/** projectView 的序列化选项。 */\nexport interface ProjectViewOptions {\n /** viewBox 四周留白(单位 = 投影平面坐标单位;缺省 1)。 */\n margin?: number\n /** 可见/隐藏线 stroke-width(像素;缺省 1)。 */\n strokeWidth?: number\n /** 隐藏线虚线样式(SVG stroke-dasharray;缺省 '4,4')。 */\n dash?: string\n /** 隐藏线透明度(缺省 0.6)。 */\n hiddenOpacity?: number\n /** 输出 SVG 宽度(缺省 = viewBox 宽度)。 */\n width?: number\n /** 输出 SVG 高度(缺省 = viewBox 高度)。 */\n height?: number\n}\n\n/** 单视图投影的结构化结果(projectSheet 复用)。 */\nexport interface ProjectionSvg {\n /** 完整 SVG 字符串。 */\n svg: string\n /** viewBox 属性值('minX minY w h';可见 ∪ 隐藏线并集 + margin)。 */\n viewBox: string\n /** 各 path d 串:可见实线 / 隐藏虚线。 */\n paths: { visible: string[]; hidden: string[] }\n /** 输出宽度/高度。 */\n width: number\n height: number\n}\n\n/**\n * 每条边的 3D 采样点数(occt compound 通道的曲线分段近似;brepkit 原生\n * 通道由内核输出折线,不经本参数)。\n *\n * 2026-10-14 修复:5 点时圆/椭圆轮廓被离散成五边形/八边形级折线——web 端\n * 工程图实测圆柱 iso 轴测图呈多面体感、top 俯视图圆环呈菱形。提高到 48 点\n * 后椭圆视觉光滑。直线边多点采样点仍共线,无视觉差异,故不做边类型分流。\n */\nconst EDGE_SAMPLES = 48\n\ntype Vec3 = readonly [number, number, number]\n\n/** 3D 点 → 相机平面 2D 坐标。\n *\n * GOTCHA: occt-wasm 的 HLR projectEdges 已把边投影到相机平面,输出坐标 =\n * (沿 xAxis 的水平分量, 沿 cross(direction, xAxis) 的垂直分量, 沿 direction\n * 的深度分量≈0)——不是世界坐标。因此 2D 坐标直接取输出的前两分量,不再做\n * dot 二次投影(否则会把垂直信息读丢——垂直在 p.y 而非 p.z)。\n */\nfunction projectTo2D(p: Vec3, _cam: Camera): [number, number] {\n return [p[0], p[1]]\n}\n\n/** 引擎 projectEdges 的返回结构(occt-wasm:6 组 compound 的 arena id)。 */\ninterface ProjectEdgesResult {\n visibleSharp: number\n visibleSmooth: number\n visibleOutline: number\n hiddenSharp: number\n hiddenSmooth: number\n hiddenOutline: number\n}\n\nconst COMPOUND_KEYS = [\n ['visibleSharp', 'visible'],\n ['visibleSmooth', 'visible'],\n ['visibleOutline', 'visible'],\n ['hiddenSharp', 'hidden'],\n ['hiddenSmooth', 'hidden'],\n ['hiddenOutline', 'hidden'],\n] as const\n\n/**\n * HLR 投影 shape → 可见/隐藏 2D 折线(SVG d 串)。\n * 按引擎 id 静态分派方言通道(见文件头 2026-10-11 注):\n * - brepkit → 内核原生折线 JSON 通道;\n * - 其余(含 occt)→ compound 句柄采样通道(现状)。\n * 无引擎门禁:分派只选通道,不因内核缺特性报错。\n */\nfunction projectPolylines(shape: Shape, view: ViewSpec): { visible: string[]; hidden: string[] } {\n const solid = brepOf(shape) as BrepHandle | undefined\n if (solid === undefined) {\n throw new Error(\n '[faijs/view-projection] E_BREP_ONLY_INPUT: operation requires a BREP-backed shape ' +\n '(mesh-only input cannot be projected)',\n )\n }\n const api = getBrepApi()\n const cam = resolveCamera(view) as unknown as Camera\n const engineId = getBackends().config.brepEngineId\n if (engineId === 'brepkit') {\n return projectPolylinesNative(api, solid, cam)\n }\n return projectPolylinesCompound(api, solid, cam)\n}\n\n/** projectEdges 的公共调用参数(两方言同构,签名见 brep/engine/primitives.ts)。 */\nfunction projectEdgesArgs(cam: Camera) {\n return [\n { x: cam.position[0], y: cam.position[1], z: cam.position[2] },\n { x: cam.direction[0], y: cam.direction[1], z: cam.direction[2] },\n { x: cam.xAxis[0], y: cam.xAxis[1], z: cam.xAxis[2] },\n true,\n 0.1,\n ] as const\n}\n\n/**\n * brepkit 原生通道:内核 projectEdges 返回 JSON 字符串\n * `{\"visible\":[[x,y,…],…],\"hidden\":[…]}`(每条折线 = 扁平 x,y 点对数组,已是\n * 相机平面 2D 坐标),解析后直接转 SVG path d 串。内核返回非法 JSON 属实现\n * 缺陷,直接抛错暴露(非\"缺特性\",不受无门禁基调豁免)。\n */\nfunction projectPolylinesNative(\n api: ReturnType<typeof getBrepApi>,\n solid: BrepHandle,\n cam: Camera,\n): { visible: string[]; hidden: string[] } {\n const [origin, direction, xAxis] = projectEdgesArgs(cam)\n const raw = api.projectEdges(solid, origin, direction, xAxis, true, 0.1)\n const parsed = parseNativeProjection(raw)\n return {\n visible: parsed.visible.map(polylineToPath),\n hidden: parsed.hidden.map(polylineToPath),\n }\n}\n\n/** 解析 brepkit projectEdges 的折线 JSON(结构错误一律抛错暴露)。 */\nfunction parseNativeProjection(raw: unknown): { visible: number[][]; hidden: number[][] } {\n if (typeof raw !== 'string') {\n throw new Error(\n `[faijs/view-projection] E_PROJECTION_DIALECT: native projectEdges returned ${typeof raw}, expected JSON string`,\n )\n }\n const obj = JSON.parse(raw) as { visible?: unknown; hidden?: unknown }\n const flat = (v: unknown): number[][] => {\n if (!Array.isArray(v)) throw new Error('[faijs/view-projection] E_PROJECTION_DIALECT: malformed native projection JSON')\n return v.filter((p): p is number[] => Array.isArray(p) && p.length >= 4)\n }\n return { visible: flat(obj.visible), hidden: flat(obj.hidden) }\n}\n\n/** 扁平 x,y 点对数组 → SVG path d 串(M + L 序列)。 */\nfunction polylineToPath(poly: number[]): string {\n let d = `M ${poly[0].toFixed(4)} ${poly[1].toFixed(4)}`\n for (let i = 2; i + 1 < poly.length; i += 2) {\n d += ` L ${poly[i].toFixed(4)} ${poly[i + 1].toFixed(4)}`\n }\n return d\n}\n\n/**\n * occt compound 通道(现状,逐字节不变):HLR 输出 6 组 compound 的 arena id,\n * 逐 compound 取边 → 3D 曲线采样 → 相机平面投影。\n * 全部句柄在本函数内释放(compound + 边;输入 shape 不消费)。\n */\nfunction projectPolylinesCompound(\n api: ReturnType<typeof getBrepApi>,\n solid: BrepHandle,\n cam: Camera,\n): { visible: string[]; hidden: string[] } {\n const [origin, direction, xAxis] = projectEdgesArgs(cam)\n const r = api.projectEdges(solid, origin, direction, xAxis, true, 0.1) as ProjectEdgesResult\n\n const out: { visible: string[]; hidden: string[] } = { visible: [], hidden: [] }\n const toHandle = (id: number): BrepHandle => id as BrepHandle\n try {\n for (const [key, group] of COMPOUND_KEYS) {\n const compoundId = r[key]\n if (typeof compoundId !== 'number' || compoundId === 0) continue\n const edges = api.getSubShapes(toHandle(compoundId), 'edge')\n for (const edge of edges) {\n const d = edgeToPath(api, edge, cam)\n if (d !== null) out[group].push(d)\n }\n // 释放 compound slot(幂等)\n try {\n api.release(toHandle(compoundId))\n } catch {\n // already released\n }\n }\n } finally {\n void 0\n }\n return out\n}\n\n/** 单条边 → SVG path d 串(3D 曲线采样折线投影到相机平面)。 */\nfunction edgeToPath(api: ReturnType<typeof getBrepApi>, edge: BrepHandle, cam: Camera): string | null {\n let cp\n try {\n cp = api.curveParameters(edge)\n } catch {\n return null // 退化边(如孤立顶点线)无曲线参数\n }\n const { first, last } = cp\n const span = last - first\n const pts: [number, number][] = []\n for (let i = 0; i < EDGE_SAMPLES; i += 1) {\n const t = first + (span * i) / (EDGE_SAMPLES - 1)\n const p = api.curvePointAtParam(edge, t)\n pts.push(projectTo2D([p.x, p.y, p.z], cam))\n }\n if (pts.length < 2) return null\n let d = `M ${pts[0][0].toFixed(4)} ${pts[0][1].toFixed(4)}`\n for (let i = 1; i < pts.length; i += 1) {\n d += ` L ${pts[i][0].toFixed(4)} ${pts[i][1].toFixed(4)}`\n }\n return d\n}\n\n/** 解析 'minX minY w h' 为数值数组。 */\nfunction parseViewBox(vb: string): [number, number, number, number] | undefined {\n const parts = vb.trim().split(/\\s+/).map(Number)\n if (parts.length !== 4 || parts.some((n) => !Number.isFinite(n))) return undefined\n return [parts[0], parts[1], parts[2], parts[3]]\n}\n\n/** 折线点集 bbox → viewBox(统一坐标系;margin 再外扩)。 */\nfunction viewBoxOfPaths(paths: string[], margin: number): string {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const d of paths) {\n const nums = d.match(/[-+]?\\d*\\.?\\d+(?:[eE][-+]?\\d+)?/g) ?? []\n for (let i = 0; i + 1 < nums.length; i += 2) {\n const x = Number(nums[i])\n const y = Number(nums[i + 1])\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue\n minX = Math.min(minX, x)\n minY = Math.min(minY, y)\n maxX = Math.max(maxX, x)\n maxY = Math.max(maxY, y)\n }\n }\n if (!Number.isFinite(minX)) return '0 0 0 0' // 空投影(如空 shape)\n return `${minX - margin} ${minY - margin} ${maxX - minX + 2 * margin} ${maxY - minY + 2 * margin}`\n}\n\n/**\n * 单视图投影(结构化结果)。\n *\n * @param shape - 待投影的 faijs Shape(必须带 BREP 槽;mesh-only 输入抛 E_BREP_ONLY_INPUT)。\n * @param view - 视图规格(标准视图 / iso / 轴对平面 / 方向对象)。\n * @param opts - 序列化选项。\n * @returns 结构化投影结果(svg/viewBox/paths/尺寸)。\n */\nexport function projectViewSvg(shape: Shape, view: ViewSpec, opts: ProjectViewOptions = {}): ProjectionSvg {\n const { visible: visiblePaths, hidden: hiddenPaths } = projectPolylines(shape, view)\n const margin = opts.margin ?? 1\n const viewBox = viewBoxOfPaths([...visiblePaths, ...hiddenPaths], margin)\n const parsed = parseViewBox(viewBox) ?? [0, 0, 0, 0]\n const width = opts.width ?? parsed[2]\n const height = opts.height ?? parsed[3]\n const strokeWidth = opts.strokeWidth ?? 1\n const dash = opts.dash ?? '4,4'\n const hiddenOpacity = opts.hiddenOpacity ?? 0.6\n const visibleMarkup = visiblePaths\n .map((d) => `<path d=\"${d}\" fill=\"none\" stroke=\"#000\" stroke-width=\"${strokeWidth}\" />`)\n .join('\\n ')\n const hiddenMarkup = hiddenPaths\n .map(\n (d) =>\n `<path d=\"${d}\" fill=\"none\" stroke=\"#000\" stroke-width=\"${strokeWidth}\" stroke-dasharray=\"${dash}\" opacity=\"${hiddenOpacity}\" />`,\n )\n .join('\\n ')\n const svg = [\n `<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"${viewBox}\" width=\"${width}\" height=\"${height}\" fill=\"none\" stroke=\"black\" stroke-width=\"0.6%\" vector-effect=\"non-scaling-stroke\">`,\n ` <g stroke=\"#000\" fill=\"none\">`,\n ` ${visibleMarkup}${hiddenMarkup === '' ? '' : `\\n ${hiddenMarkup}`}`,\n ` </g>`,\n `</svg>`,\n ].join('\\n')\n return { svg, viewBox, paths: { visible: visiblePaths, hidden: hiddenPaths }, width, height }\n}\n\n/**\n * 单视图投影 → SVG 线稿字符串(纯数据,不消费/修改 shape;规则 1 下裸调用不消费输入)。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name projectView\n * @returns SVG 字符串(<svg viewBox=\"…\"> + 可见实线 <path> + 隐藏虚线 <path>)。裸调用 cad.projectView(part0, 'front') 不消费 part0(规则 1),part 仍留在 canvas。\n * @param shape - 目标几何(必须有 BREP 槽;mesh-only 抛 E_BREP_ONLY_INPUT)。type:Shape required:true\n * @param view - 视图规格(同 viewCamera:标准视图名 / iso / 轴对平面 / 方向对象)。type:string|{dir,xAxis?} required:true\n * @param opts.strokeWidth - 可见线宽(stroke-width)。type:number 默认 1\n * @param opts.dash - 隐藏线虚线样式(stroke-dasharray)。type:string 默认 '4,4'\n * @param opts.hiddenOpacity - 隐藏线透明度。type:number 默认 0.6\n * @param opts.margin - viewBox 外扩边距。type:number 默认 1\n * @param opts.width - 输出宽度(缺省 = viewBox 宽度)。type:number\n * @param opts.height - 输出高度(缺省 = viewBox 高度)。type:number\n * @example\n * const svg = cad.projectView(part0, 'front')\n * const svg = cad.projectView(part0, 'iso', { strokeWidth: 1, dash: '4,4', hiddenOpacity: 0.6 })\n */\nexport function projectView(shape: Shape, view: ViewSpec, opts?: ProjectViewOptions): string {\n return projectViewSvg(shape, view, opts).svg\n}\n"]}
@@ -11,7 +11,7 @@
11
11
  * 生命周期:由 executeScript / executePart 创建,执行结束后释放所有中间句柄。
12
12
  * 终端句柄(如果有)由调用方保留用于导出。
13
13
  */
14
- import { getBrepEngine } from './engine/registry.js';
14
+ import { getActiveBrepEngine } from './engine/registry.js';
15
15
  import { ensureOcctDefaultEngine } from './engine/adapters/occt.js';
16
16
  // ─── CAD 格式静态判定 ───
17
17
  /**
@@ -66,7 +66,7 @@ export function createBrepChainState() {
66
66
  */
67
67
  export async function initBrepChainState() {
68
68
  await ensureOcctDefaultEngine();
69
- const engine = await getBrepEngine();
69
+ const engine = await getActiveBrepEngine();
70
70
  return {
71
71
  solidCache: new Map(),
72
72
  kernel: engine.primitives,
@@ -1 +1 @@
1
- {"version":3,"file":"brep-chain.js","sourceRoot":"","sources":["../../src/brep/brep-chain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAGhE,qBAAqB;AAErB;;;;GAIG;AACH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAA;AAEpD;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CACzB,IAA6B,EAC7B,QAAiB;IAEjB,sCAAsC;IACtC,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAA;IAE3B,kBAAkB;IAClB,MAAM,MAAM,GAAG,IAAI,CAAC,MAA4B,CAAA;IAChD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;IAC9C,CAAC;IAED,sCAAsC;IACtC,MAAM,SAAS,GAAI,IAAI,CAAC,IAA2B,IAAK,IAAI,CAAC,GAA0B,IAAI,EAAE,CAAA;IAC7F,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAA;IAC3D,OAAO,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAC7B,CAAC;AAoDD;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,UAAU,EAAE,IAAI,GAAG,EAAE;QACrB,MAAM,EAAE,IAAI;QACZ,kBAAkB,EAAE,IAAI,GAAG,EAAE;QAC7B,cAAc,EAAE,IAAI,GAAG,EAAE;QACzB,cAAc,EAAE,IAAI,GAAG,EAAE;KAC1B,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,uBAAuB,EAAE,CAAA;IAC/B,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,CAAA;IACpC,OAAO;QACL,UAAU,EAAE,IAAI,GAAG,EAAE;QACrB,MAAM,EAAE,MAAM,CAAC,UAAU;QACzB,kBAAkB,EAAE,IAAI,GAAG,EAAE;QAC7B,cAAc,EAAE,IAAI,GAAG,EAAE;QACzB,cAAc,EAAE,IAAI,GAAG,EAAE;KAC1B,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAqB;IACzD,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,aAAa;QACf,CAAC;IACH,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;IACxB,KAAK,CAAC,cAAc,EAAE,KAAK,EAAE,CAAA;AAC/B,CAAC","sourcesContent":["/**\n * BREP 链状态管理\n *\n * 在语句重放过程中跟踪 OCCT 精确实体句柄。\n * - solidCache: statementId → ShapeHandle(OCCT 实体句柄)\n *\n * BREP 状态是「逐 part」的:一个 part 是否仍为 BREP,\n * 由 solidCache 里是否有它的句柄唯一决定。\n * 不存在全局 brepActive 标志——兄弟 part 互不污染。\n *\n * 生命周期:由 executeScript / executePart 创建,执行结束后释放所有中间句柄。\n * 终端句柄(如果有)由调用方保留用于导出。\n */\n\nimport type { BrepHandle, BrepMeshResult } from './engine/types'\nimport type { BrepEngineApi } from './engine/primitives'\nimport { getBrepEngine } from './engine/registry'\nimport { ensureOcctDefaultEngine } from './engine/adapters/occt'\nimport type { PartName } from '../identity'\n\n// ─── CAD 格式静态判定 ───\n\n/**\n * CAD formats: files in these formats can be imported by the OCCT kernel as\n * exact solids (STEP/STP via importStep, BREP via fromBREP).\n * IGES is intentionally absent — occt-wasm does not link TKDEIGES.\n */\nconst CAD_FORMATS = new Set(['step', 'brep', 'stp'])\n\n/**\n * 静态判定 load 语句的源文件是否为 CAD 格式。\n *\n * 纯函数,按 args.format / 文件路径扩展名判定,\n * 不调用 OCCT、不 try-catch。\n *\n * @param args load 语句的参数表(key/path/url + format)\n * @param isSource buffer 是否为原始字节(可走 BREP 路径的前提)\n * @returns true 表示是 CAD 源(可走 BREP 路径)\n */\nexport function isCadFormat(\n args: Record<string, unknown>,\n isSource: boolean,\n): boolean {\n // 非 source buffer 是转换后的网格数据 → 非 CAD 源\n if (!isSource) return false\n\n // 优先用显式 format 参数\n const format = args.format as string | undefined\n if (format) {\n return CAD_FORMATS.has(format.toLowerCase())\n }\n\n // P4-1:按 path/url 的扩展名判定(fileRef 已移除)\n const pathOrUrl = (args.path as string | undefined) ?? (args.url as string | undefined) ?? ''\n const ext = pathOrUrl.split('.').pop()?.toLowerCase() ?? ''\n return CAD_FORMATS.has(ext)\n}\n\n// ─── BREP 链状态 ───\n\n/**\n * BREP 链状态:在语句重放过程中跟踪 OCCT 实体句柄。\n *\n * BREP 状态是「逐 part」的:\n * - solidCache 中存在该 part 的句柄 → 该 part 仍为 BREP\n * - solidCache 中不存在该 part 的句柄 → 该 part 已降级为 mesh\n *\n * 不再有全局 brepActive / breakReason 字段。\n * 一个 part 失去 BREP 状态,当且仅当:\n * - 它被 knurl/sdf(mesh-only op)产生(不写 solidCache),或\n * - 它的上游输入中至少有一个没有 BREP 实体。\n * 兄弟 part 之间互不污染。\n */\nexport interface BrepChainState {\n /** BREP 实体句柄缓存(PartName → BrepHandle)。存在即该 part 仍为 BREP;缺失即已降级为 mesh。 */\n solidCache: Map<PartName, BrepHandle>\n /** BREP 引擎实例(mesh 模式为 null —— 等价于「无 BREP 能力」)。 */\n kernel: BrepEngineApi | null\n /**\n * P5-2: 面演化映射缓存(statementId → FaceEvolution)。\n *\n * 每个布尔/变换操作执行后,存储面 ordinal 映射(输入 ordinal → 输出 ordinal 列表)。\n * 用于面引用在确定性重放下的稳定性验证和未来的面迁移功能。\n *\n * FaceEvolution = Map<number, number[]>(inOrdinal → outOrdinal[])\n */\n faceEvolutionCache?: Map<PartName, Map<number, number[]>>\n /**\n * 拓扑命名 RoleTable 持久缓存(PartName → RoleTable,§2.3 of\n *\n * 与 faceEvolutionCache 完全同生命周期:runtime 实例级持久、按语句增量同步、\n * dispose 一并 clear。RoleTable 是执行内状态,不序列化、不进 .fai.js、不进\n * ExecutionResult.naming(宿主只拿 §3.7 的纯数据)。hash 是会话内活句柄索引,\n * 跨实例/会话重建时整体重建。\n */\n roleTableCache?: Map<PartName, unknown>\n /**\n * 三角化缓存:PartName → WasmMesh(含 faceGroups)。\n *\n * BREP op 调用 solidToShape 三角化后,把完整 WasmMesh 缓存到此 Map。\n * buildBrepTopology 复用此缓存,避免二次 meshShape 导致拓扑 mesh ≠ 显示 mesh。\n *\n * 规则 1:拓扑数据生成所使用的 mesh,必须是当前用户看到的 mesh。\n * 三角化和拓扑生成都是 faijs 的职责,宿主不参与。\n */\n meshShapeCache?: Map<PartName, BrepMeshResult>\n}\n\n/**\n * Create an empty BREP chain state with no cached solids and no kernel.\n * @returns a new empty BrepChainState.\n */\nexport function createBrepChainState(): BrepChainState {\n return {\n solidCache: new Map(),\n kernel: null,\n faceEvolutionCache: new Map(),\n roleTableCache: new Map(),\n meshShapeCache: new Map(),\n }\n}\n\n/**\n * Initialize the BREP chain state asynchronously: resolve the active BREP\n * engine from the registry and initialize its kernel.\n * OCCT is the built-in default engine: when no engine is registered it is\n * assembled first (ensureOcctDefaultEngine is idempotent).\n * @returns a Promise resolving to an initialized BrepChainState.\n */\nexport async function initBrepChainState(): Promise<BrepChainState> {\n await ensureOcctDefaultEngine()\n const engine = await getBrepEngine()\n return {\n solidCache: new Map(),\n kernel: engine.primitives,\n faceEvolutionCache: new Map(),\n roleTableCache: new Map(),\n meshShapeCache: new Map(),\n }\n}\n\n/**\n * 释放 BREP 链状态中的所有句柄并清空 solidCache。\n *\n * 释放只发生在「重算顶替 / dispose」,不再需要\"保留终端、释放中间\"的选择性语义,\n * 因此 keepIds 参数已删除——调用方想保留任何 solid 时,不应再调用本函数。\n *\n * @param state BREP 链状态\n */\nexport function releaseBrepChainState(state: BrepChainState): void {\n for (const [, handle] of state.solidCache) {\n try {\n state.kernel?.release(handle)\n } catch {\n // 句柄可能已释放,忽略\n }\n }\n state.solidCache.clear()\n state.meshShapeCache?.clear()\n}\n"]}
1
+ {"version":3,"file":"brep-chain.js","sourceRoot":"","sources":["../../src/brep/brep-chain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAGhE,qBAAqB;AAErB;;;;GAIG;AACH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAA;AAEpD;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CACzB,IAA6B,EAC7B,QAAiB;IAEjB,sCAAsC;IACtC,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAA;IAE3B,kBAAkB;IAClB,MAAM,MAAM,GAAG,IAAI,CAAC,MAA4B,CAAA;IAChD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;IAC9C,CAAC;IAED,sCAAsC;IACtC,MAAM,SAAS,GAAI,IAAI,CAAC,IAA2B,IAAK,IAAI,CAAC,GAA0B,IAAI,EAAE,CAAA;IAC7F,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAA;IAC3D,OAAO,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAC7B,CAAC;AAoDD;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,UAAU,EAAE,IAAI,GAAG,EAAE;QACrB,MAAM,EAAE,IAAI;QACZ,kBAAkB,EAAE,IAAI,GAAG,EAAE;QAC7B,cAAc,EAAE,IAAI,GAAG,EAAE;QACzB,cAAc,EAAE,IAAI,GAAG,EAAE;KAC1B,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,uBAAuB,EAAE,CAAA;IAC/B,MAAM,MAAM,GAAG,MAAM,mBAAmB,EAAE,CAAA;IAC1C,OAAO;QACL,UAAU,EAAE,IAAI,GAAG,EAAE;QACrB,MAAM,EAAE,MAAM,CAAC,UAAU;QACzB,kBAAkB,EAAE,IAAI,GAAG,EAAE;QAC7B,cAAc,EAAE,IAAI,GAAG,EAAE;QACzB,cAAc,EAAE,IAAI,GAAG,EAAE;KAC1B,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAqB;IACzD,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,aAAa;QACf,CAAC;IACH,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;IACxB,KAAK,CAAC,cAAc,EAAE,KAAK,EAAE,CAAA;AAC/B,CAAC","sourcesContent":["/**\n * BREP 链状态管理\n *\n * 在语句重放过程中跟踪 OCCT 精确实体句柄。\n * - solidCache: statementId → ShapeHandle(OCCT 实体句柄)\n *\n * BREP 状态是「逐 part」的:一个 part 是否仍为 BREP,\n * 由 solidCache 里是否有它的句柄唯一决定。\n * 不存在全局 brepActive 标志——兄弟 part 互不污染。\n *\n * 生命周期:由 executeScript / executePart 创建,执行结束后释放所有中间句柄。\n * 终端句柄(如果有)由调用方保留用于导出。\n */\n\nimport type { BrepHandle, BrepMeshResult } from './engine/types'\nimport type { BrepEngineApi } from './engine/primitives'\nimport { getActiveBrepEngine } from './engine/registry'\nimport { ensureOcctDefaultEngine } from './engine/adapters/occt'\nimport type { PartName } from '../identity'\n\n// ─── CAD 格式静态判定 ───\n\n/**\n * CAD formats: files in these formats can be imported by the OCCT kernel as\n * exact solids (STEP/STP via importStep, BREP via fromBREP).\n * IGES is intentionally absent — occt-wasm does not link TKDEIGES.\n */\nconst CAD_FORMATS = new Set(['step', 'brep', 'stp'])\n\n/**\n * 静态判定 load 语句的源文件是否为 CAD 格式。\n *\n * 纯函数,按 args.format / 文件路径扩展名判定,\n * 不调用 OCCT、不 try-catch。\n *\n * @param args load 语句的参数表(key/path/url + format)\n * @param isSource buffer 是否为原始字节(可走 BREP 路径的前提)\n * @returns true 表示是 CAD 源(可走 BREP 路径)\n */\nexport function isCadFormat(\n args: Record<string, unknown>,\n isSource: boolean,\n): boolean {\n // 非 source buffer 是转换后的网格数据 → 非 CAD 源\n if (!isSource) return false\n\n // 优先用显式 format 参数\n const format = args.format as string | undefined\n if (format) {\n return CAD_FORMATS.has(format.toLowerCase())\n }\n\n // P4-1:按 path/url 的扩展名判定(fileRef 已移除)\n const pathOrUrl = (args.path as string | undefined) ?? (args.url as string | undefined) ?? ''\n const ext = pathOrUrl.split('.').pop()?.toLowerCase() ?? ''\n return CAD_FORMATS.has(ext)\n}\n\n// ─── BREP 链状态 ───\n\n/**\n * BREP 链状态:在语句重放过程中跟踪 OCCT 实体句柄。\n *\n * BREP 状态是「逐 part」的:\n * - solidCache 中存在该 part 的句柄 → 该 part 仍为 BREP\n * - solidCache 中不存在该 part 的句柄 → 该 part 已降级为 mesh\n *\n * 不再有全局 brepActive / breakReason 字段。\n * 一个 part 失去 BREP 状态,当且仅当:\n * - 它被 knurl/sdf(mesh-only op)产生(不写 solidCache),或\n * - 它的上游输入中至少有一个没有 BREP 实体。\n * 兄弟 part 之间互不污染。\n */\nexport interface BrepChainState {\n /** BREP 实体句柄缓存(PartName → BrepHandle)。存在即该 part 仍为 BREP;缺失即已降级为 mesh。 */\n solidCache: Map<PartName, BrepHandle>\n /** BREP 引擎实例(mesh 模式为 null —— 等价于「无 BREP 能力」)。 */\n kernel: BrepEngineApi | null\n /**\n * P5-2: 面演化映射缓存(statementId → FaceEvolution)。\n *\n * 每个布尔/变换操作执行后,存储面 ordinal 映射(输入 ordinal → 输出 ordinal 列表)。\n * 用于面引用在确定性重放下的稳定性验证和未来的面迁移功能。\n *\n * FaceEvolution = Map<number, number[]>(inOrdinal → outOrdinal[])\n */\n faceEvolutionCache?: Map<PartName, Map<number, number[]>>\n /**\n * 拓扑命名 RoleTable 持久缓存(PartName → RoleTable,§2.3 of\n *\n * 与 faceEvolutionCache 完全同生命周期:runtime 实例级持久、按语句增量同步、\n * dispose 一并 clear。RoleTable 是执行内状态,不序列化、不进 .fai.js、不进\n * ExecutionResult.naming(宿主只拿 §3.7 的纯数据)。hash 是会话内活句柄索引,\n * 跨实例/会话重建时整体重建。\n */\n roleTableCache?: Map<PartName, unknown>\n /**\n * 三角化缓存:PartName → WasmMesh(含 faceGroups)。\n *\n * BREP op 调用 solidToShape 三角化后,把完整 WasmMesh 缓存到此 Map。\n * buildBrepTopology 复用此缓存,避免二次 meshShape 导致拓扑 mesh ≠ 显示 mesh。\n *\n * 规则 1:拓扑数据生成所使用的 mesh,必须是当前用户看到的 mesh。\n * 三角化和拓扑生成都是 faijs 的职责,宿主不参与。\n */\n meshShapeCache?: Map<PartName, BrepMeshResult>\n}\n\n/**\n * Create an empty BREP chain state with no cached solids and no kernel.\n * @returns a new empty BrepChainState.\n */\nexport function createBrepChainState(): BrepChainState {\n return {\n solidCache: new Map(),\n kernel: null,\n faceEvolutionCache: new Map(),\n roleTableCache: new Map(),\n meshShapeCache: new Map(),\n }\n}\n\n/**\n * Initialize the BREP chain state asynchronously: resolve the active BREP\n * engine from the registry and initialize its kernel.\n * OCCT is the built-in default engine: when no engine is registered it is\n * assembled first (ensureOcctDefaultEngine is idempotent).\n * @returns a Promise resolving to an initialized BrepChainState.\n */\nexport async function initBrepChainState(): Promise<BrepChainState> {\n await ensureOcctDefaultEngine()\n const engine = await getActiveBrepEngine()\n return {\n solidCache: new Map(),\n kernel: engine.primitives,\n faceEvolutionCache: new Map(),\n roleTableCache: new Map(),\n meshShapeCache: new Map(),\n }\n}\n\n/**\n * 释放 BREP 链状态中的所有句柄并清空 solidCache。\n *\n * 释放只发生在「重算顶替 / dispose」,不再需要\"保留终端、释放中间\"的选择性语义,\n * 因此 keepIds 参数已删除——调用方想保留任何 solid 时,不应再调用本函数。\n *\n * @param state BREP 链状态\n */\nexport function releaseBrepChainState(state: BrepChainState): void {\n for (const [, handle] of state.solidCache) {\n try {\n state.kernel?.release(handle)\n } catch {\n // 句柄可能已释放,忽略\n }\n }\n state.solidCache.clear()\n state.meshShapeCache?.clear()\n}\n"]}
@@ -396,7 +396,7 @@ export declare function loadBrepAssembly(kernel: BrepEngineApi, buffer: ArrayBuf
396
396
  *
397
397
  * 分派规则(静态,无运行时回退):XCAF(`STEPCAFControl_Reader`)是 occt 内核的
398
398
  * 装配读取器,brepkit 没有;调用方按当前引擎 id 选择本函数还是 XCAF 版本
399
- * (`cad.load` 见 `packages/faijs-extra/src/ops/load.ts`),不靠 try-catch 探测。
399
+ * (`cad.load` 见 `packages/core/src/extra/ops/load.ts`),不靠 try-catch 探测。
400
400
  *
401
401
  * 句柄归属:返回的每个 `part.solid` 即内核枚举出的实体本身(生命周期交给调用方,
402
402
  * `fromBrep` 绑定后归 brepChain)。顶层包装句柄在本函数内释放——但**若顶层句柄
@@ -765,7 +765,7 @@ export async function loadBrepAssembly(kernel, buffer) {
765
765
  *
766
766
  * 分派规则(静态,无运行时回退):XCAF(`STEPCAFControl_Reader`)是 occt 内核的
767
767
  * 装配读取器,brepkit 没有;调用方按当前引擎 id 选择本函数还是 XCAF 版本
768
- * (`cad.load` 见 `packages/faijs-extra/src/ops/load.ts`),不靠 try-catch 探测。
768
+ * (`cad.load` 见 `packages/core/src/extra/ops/load.ts`),不靠 try-catch 探测。
769
769
  *
770
770
  * 句柄归属:返回的每个 `part.solid` 即内核枚举出的实体本身(生命周期交给调用方,
771
771
  * `fromBrep` 绑定后归 brepChain)。顶层包装句柄在本函数内释放——但**若顶层句柄