@faicad/faijs 0.22.2 → 0.29.5

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 (488) hide show
  1. package/LICENSE +202 -28
  2. package/dist/api/api-namespace.d.ts +5 -5
  3. package/dist/api/api-namespace.d.ts.map +1 -1
  4. package/dist/api/api-namespace.js +4 -4
  5. package/dist/api/api-namespace.js.map +1 -1
  6. package/dist/api/appearance.d.ts +138 -0
  7. package/dist/api/appearance.d.ts.map +1 -0
  8. package/dist/api/appearance.js +230 -0
  9. package/dist/api/appearance.js.map +1 -0
  10. package/dist/api/assert.d.ts +2 -2
  11. package/dist/api/assert.js +8 -8
  12. package/dist/api/assert.js.map +1 -1
  13. package/dist/api/asset.d.ts +1 -1
  14. package/dist/api/asset.js +2 -2
  15. package/dist/api/asset.js.map +1 -1
  16. package/dist/api/boolean.d.ts +1 -1
  17. package/dist/api/boolean.d.ts.map +1 -1
  18. package/dist/api/boolean.js +128 -16
  19. package/dist/api/boolean.js.map +1 -1
  20. package/dist/api/cadquery-selectors/borrow-bridge.d.ts +14 -0
  21. package/dist/api/cadquery-selectors/borrow-bridge.d.ts.map +1 -0
  22. package/dist/api/cadquery-selectors/borrow-bridge.js +52 -0
  23. package/dist/api/cadquery-selectors/borrow-bridge.js.map +1 -0
  24. package/dist/api/cadquery-selectors/edge.d.ts +40 -0
  25. package/dist/api/cadquery-selectors/edge.d.ts.map +1 -0
  26. package/dist/api/cadquery-selectors/edge.js +70 -0
  27. package/dist/api/cadquery-selectors/edge.js.map +1 -0
  28. package/dist/api/cadquery-selectors/entity.d.ts +121 -0
  29. package/dist/api/cadquery-selectors/entity.d.ts.map +1 -0
  30. package/dist/api/cadquery-selectors/entity.js +167 -0
  31. package/dist/api/cadquery-selectors/entity.js.map +1 -0
  32. package/dist/api/cadquery-selectors/face.d.ts +33 -0
  33. package/dist/api/cadquery-selectors/face.d.ts.map +1 -0
  34. package/dist/api/cadquery-selectors/face.js +353 -0
  35. package/dist/api/cadquery-selectors/face.js.map +1 -0
  36. package/dist/api/cadquery-selectors/grammar.d.ts +50 -0
  37. package/dist/api/cadquery-selectors/grammar.d.ts.map +1 -0
  38. package/dist/api/cadquery-selectors/grammar.js +345 -0
  39. package/dist/api/cadquery-selectors/grammar.js.map +1 -0
  40. package/dist/api/cadquery-selectors/index.d.ts +18 -0
  41. package/dist/api/cadquery-selectors/index.d.ts.map +1 -0
  42. package/dist/api/cadquery-selectors/index.js +17 -0
  43. package/dist/api/cadquery-selectors/index.js.map +1 -0
  44. package/dist/api/cadquery-selectors/predicates.d.ts +76 -0
  45. package/dist/api/cadquery-selectors/predicates.d.ts.map +1 -0
  46. package/dist/api/cadquery-selectors/predicates.js +85 -0
  47. package/dist/api/cadquery-selectors/predicates.js.map +1 -0
  48. package/dist/api/cadquery-selectors/resolve.d.ts +41 -0
  49. package/dist/api/cadquery-selectors/resolve.d.ts.map +1 -0
  50. package/dist/api/cadquery-selectors/resolve.js +243 -0
  51. package/dist/api/cadquery-selectors/resolve.js.map +1 -0
  52. package/dist/api/cadquery-selectors/types.d.ts +96 -0
  53. package/dist/api/cadquery-selectors/types.d.ts.map +1 -0
  54. package/dist/api/cadquery-selectors/types.js +11 -0
  55. package/dist/api/cadquery-selectors/types.js.map +1 -0
  56. package/dist/api/chamfer.d.ts +13 -5
  57. package/dist/api/chamfer.d.ts.map +1 -1
  58. package/dist/api/chamfer.js +63 -7
  59. package/dist/api/chamfer.js.map +1 -1
  60. package/dist/api/compound-geom.d.ts +1 -1
  61. package/dist/api/compound-geom.js +1 -1
  62. package/dist/api/compound-geom.js.map +1 -1
  63. package/dist/api/draft.d.ts +1 -1
  64. package/dist/api/draft.js +1 -1
  65. package/dist/api/draft.js.map +1 -1
  66. package/dist/api/edge-ref.d.ts +1 -1
  67. package/dist/api/edge-ref.d.ts.map +1 -1
  68. package/dist/api/edge-ref.js +11 -3
  69. package/dist/api/edge-ref.js.map +1 -1
  70. package/dist/api/engrave.d.ts +1 -1
  71. package/dist/api/engrave.js +7 -7
  72. package/dist/api/engrave.js.map +1 -1
  73. package/dist/api/extrude.d.ts +6 -1
  74. package/dist/api/extrude.d.ts.map +1 -1
  75. package/dist/api/extrude.js +59 -5
  76. package/dist/api/extrude.js.map +1 -1
  77. package/dist/api/face-ref.d.ts +1 -1
  78. package/dist/api/face-ref.js +1 -1
  79. package/dist/api/face-ref.js.map +1 -1
  80. package/dist/api/feature-repair.d.ts +1 -1
  81. package/dist/api/feature-repair.js +1 -1
  82. package/dist/api/feature-repair.js.map +1 -1
  83. package/dist/api/fillet-variable.d.ts +1 -1
  84. package/dist/api/fillet-variable.js +1 -1
  85. package/dist/api/fillet-variable.js.map +1 -1
  86. package/dist/api/fillet.d.ts +28 -8
  87. package/dist/api/fillet.d.ts.map +1 -1
  88. package/dist/api/fillet.js +64 -9
  89. package/dist/api/fillet.js.map +1 -1
  90. package/dist/api/geom.d.ts +1 -1
  91. package/dist/api/geom.js +1 -1
  92. package/dist/api/geom.js.map +1 -1
  93. package/dist/api/helix.d.ts +1 -1
  94. package/dist/api/helix.js +1 -1
  95. package/dist/api/helix.js.map +1 -1
  96. package/dist/api/import-brep.d.ts +20 -2
  97. package/dist/api/import-brep.d.ts.map +1 -1
  98. package/dist/api/import-brep.js +28 -3
  99. package/dist/api/import-brep.js.map +1 -1
  100. package/dist/api/import-step.d.ts +17 -2
  101. package/dist/api/import-step.d.ts.map +1 -1
  102. package/dist/api/import-step.js +51 -3
  103. package/dist/api/import-step.js.map +1 -1
  104. package/dist/api/index.d.ts +6 -1
  105. package/dist/api/index.d.ts.map +1 -1
  106. package/dist/api/index.js +7 -2
  107. package/dist/api/index.js.map +1 -1
  108. package/dist/api/internal/compat-op.js +1 -1
  109. package/dist/api/internal/compat-op.js.map +1 -1
  110. package/dist/api/internal/mesh-solid-op.d.ts +236 -0
  111. package/dist/api/internal/mesh-solid-op.d.ts.map +1 -0
  112. package/dist/api/internal/mesh-solid-op.js +352 -0
  113. package/dist/api/internal/mesh-solid-op.js.map +1 -0
  114. package/dist/api/internal/svg-asset-resolver.d.ts +1 -1
  115. package/dist/api/internal/svg-asset-resolver.js +1 -1
  116. package/dist/api/internal/svg-asset-resolver.js.map +1 -1
  117. package/dist/api/knurl.d.ts +1 -1
  118. package/dist/api/knurl.js +2 -2
  119. package/dist/api/knurl.js.map +1 -1
  120. package/dist/api/loft.d.ts +1 -1
  121. package/dist/api/loft.js +1 -1
  122. package/dist/api/loft.js.map +1 -1
  123. package/dist/api/measurement/index.d.ts +9 -5
  124. package/dist/api/measurement/index.d.ts.map +1 -1
  125. package/dist/api/measurement/index.js +47 -20
  126. package/dist/api/measurement/index.js.map +1 -1
  127. package/dist/api/meta.d.ts +93 -0
  128. package/dist/api/meta.d.ts.map +1 -0
  129. package/dist/api/meta.js +99 -0
  130. package/dist/api/meta.js.map +1 -0
  131. package/dist/api/pattern.d.ts +5 -3
  132. package/dist/api/pattern.d.ts.map +1 -1
  133. package/dist/api/pattern.js +32 -4
  134. package/dist/api/pattern.js.map +1 -1
  135. package/dist/api/place.d.ts +1 -1
  136. package/dist/api/place.js +1 -1
  137. package/dist/api/place.js.map +1 -1
  138. package/dist/api/primitives.d.ts +1 -1
  139. package/dist/api/primitives.d.ts.map +1 -1
  140. package/dist/api/primitives.js +119 -4
  141. package/dist/api/primitives.js.map +1 -1
  142. package/dist/api/profile.d.ts +39 -12
  143. package/dist/api/profile.d.ts.map +1 -1
  144. package/dist/api/profile.js +4 -4
  145. package/dist/api/profile.js.map +1 -1
  146. package/dist/api/reconcile.d.ts +1 -1
  147. package/dist/api/reconcile.js +1 -1
  148. package/dist/api/reconcile.js.map +1 -1
  149. package/dist/api/replicate.d.ts.map +1 -1
  150. package/dist/api/replicate.js +122 -1
  151. package/dist/api/replicate.js.map +1 -1
  152. package/dist/api/screw.d.ts +1 -1
  153. package/dist/api/screw.js +3 -3
  154. package/dist/api/screw.js.map +1 -1
  155. package/dist/api/sdf.d.ts +1 -1
  156. package/dist/api/sdf.js +2 -2
  157. package/dist/api/sdf.js.map +1 -1
  158. package/dist/api/section-by-plane.d.ts +1 -1
  159. package/dist/api/section-by-plane.d.ts.map +1 -1
  160. package/dist/api/section-by-plane.js +2 -1
  161. package/dist/api/section-by-plane.js.map +1 -1
  162. package/dist/api/shell.d.ts +11 -4
  163. package/dist/api/shell.d.ts.map +1 -1
  164. package/dist/api/shell.js +53 -7
  165. package/dist/api/shell.js.map +1 -1
  166. package/dist/api/sketch-on-face.d.ts +41 -0
  167. package/dist/api/sketch-on-face.d.ts.map +1 -1
  168. package/dist/api/sketch-on-face.js +100 -1
  169. package/dist/api/sketch-on-face.js.map +1 -1
  170. package/dist/api/sketch-on-plane.d.ts +7 -5
  171. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  172. package/dist/api/sketch-on-plane.js +6 -7
  173. package/dist/api/sketch-on-plane.js.map +1 -1
  174. package/dist/api/split-by-plane.d.ts +1 -1
  175. package/dist/api/split-by-plane.d.ts.map +1 -1
  176. package/dist/api/split-by-plane.js +2 -1
  177. package/dist/api/split-by-plane.js.map +1 -1
  178. package/dist/api/split.d.ts +1 -1
  179. package/dist/api/split.js +2 -2
  180. package/dist/api/split.js.map +1 -1
  181. package/dist/api/sweep.d.ts +1 -1
  182. package/dist/api/sweep.js +1 -1
  183. package/dist/api/sweep.js.map +1 -1
  184. package/dist/api/thicken.d.ts +1 -1
  185. package/dist/api/thicken.js +1 -1
  186. package/dist/api/thicken.js.map +1 -1
  187. package/dist/api/topo-resolve.d.ts +74 -1
  188. package/dist/api/topo-resolve.d.ts.map +1 -1
  189. package/dist/api/topo-resolve.js +180 -2
  190. package/dist/api/topo-resolve.js.map +1 -1
  191. package/dist/api/transform.d.ts +5 -1
  192. package/dist/api/transform.d.ts.map +1 -1
  193. package/dist/api/transform.js +62 -11
  194. package/dist/api/transform.js.map +1 -1
  195. package/dist/api/wire.d.ts +1 -1
  196. package/dist/api/wire.js +1 -1
  197. package/dist/api/wire.js.map +1 -1
  198. package/dist/brep/brep-ops.d.ts +9 -7
  199. package/dist/brep/brep-ops.d.ts.map +1 -1
  200. package/dist/brep/brep-ops.js +50 -26
  201. package/dist/brep/brep-ops.js.map +1 -1
  202. package/dist/brep/brep-topology.d.ts +5 -4
  203. package/dist/brep/brep-topology.d.ts.map +1 -1
  204. package/dist/brep/brep-topology.js +6 -5
  205. package/dist/brep/brep-topology.js.map +1 -1
  206. package/dist/brep/effective-deflection.d.ts +35 -0
  207. package/dist/brep/effective-deflection.d.ts.map +1 -0
  208. package/dist/brep/effective-deflection.js +49 -0
  209. package/dist/brep/effective-deflection.js.map +1 -0
  210. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  211. package/dist/brep/engine/adapters/brep-mock.js +27 -0
  212. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  213. package/dist/brep/engine/adapters/brepkit.d.ts +18 -0
  214. package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
  215. package/dist/brep/engine/adapters/brepkit.js +46 -1
  216. package/dist/brep/engine/adapters/brepkit.js.map +1 -1
  217. package/dist/brep/engine/adapters/occt.d.ts +1 -1
  218. package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
  219. package/dist/brep/engine/adapters/occt.js +4 -2
  220. package/dist/brep/engine/adapters/occt.js.map +1 -1
  221. package/dist/brep/engine/primitives.d.ts +29 -7
  222. package/dist/brep/engine/primitives.d.ts.map +1 -1
  223. package/dist/brep/engine/primitives.js.map +1 -1
  224. package/dist/brep/engine/registry.d.ts +24 -1
  225. package/dist/brep/engine/registry.d.ts.map +1 -1
  226. package/dist/brep/engine/registry.js +24 -0
  227. package/dist/brep/engine/registry.js.map +1 -1
  228. package/dist/brep/engine/types.d.ts +54 -3
  229. package/dist/brep/engine/types.d.ts.map +1 -1
  230. package/dist/brep/engine/types.js +10 -0
  231. package/dist/brep/engine/types.js.map +1 -1
  232. package/dist/brep/export/export-model.d.ts +40 -0
  233. package/dist/brep/export/export-model.d.ts.map +1 -1
  234. package/dist/brep/export/export-model.js +274 -30
  235. package/dist/brep/export/export-model.js.map +1 -1
  236. package/dist/brep/export/step-meta-header.d.ts +102 -0
  237. package/dist/brep/export/step-meta-header.d.ts.map +1 -0
  238. package/dist/brep/export/step-meta-header.js +225 -0
  239. package/dist/brep/export/step-meta-header.js.map +1 -0
  240. package/dist/brep/export/step.d.ts +5 -1
  241. package/dist/brep/export/step.d.ts.map +1 -1
  242. package/dist/brep/export/step.js +11 -2
  243. package/dist/brep/export/step.js.map +1 -1
  244. package/dist/brep/face-evolution.d.ts +1 -1
  245. package/dist/brep/face-evolution.d.ts.map +1 -1
  246. package/dist/brep/face-evolution.js +20 -1
  247. package/dist/brep/face-evolution.js.map +1 -1
  248. package/dist/brep/handle-bridge.d.ts +1 -1
  249. package/dist/brep/handle-bridge.js +1 -1
  250. package/dist/brep/handle-bridge.js.map +1 -1
  251. package/dist/brep/mesh-solid.d.ts +218 -0
  252. package/dist/brep/mesh-solid.d.ts.map +1 -0
  253. package/dist/brep/mesh-solid.js +229 -0
  254. package/dist/brep/mesh-solid.js.map +1 -0
  255. package/dist/brep/text/fontRegistry.d.ts +32 -1
  256. package/dist/brep/text/fontRegistry.d.ts.map +1 -1
  257. package/dist/brep/text/fontRegistry.js +51 -1
  258. package/dist/brep/text/fontRegistry.js.map +1 -1
  259. package/dist/brep/text/text-to-solid.d.ts.map +1 -1
  260. package/dist/brep/text/text-to-solid.js +8 -3
  261. package/dist/brep/text/text-to-solid.js.map +1 -1
  262. package/dist/brepkit-kernel/brepkitKernel.d.ts +18 -2
  263. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  264. package/dist/brepkit-kernel/brepkitKernel.js +449 -123
  265. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  266. package/dist/brepkit-kernel/brepkitWasm.d.ts +8 -0
  267. package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
  268. package/dist/brepkit-kernel/brepkitWasm.js +10 -0
  269. package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
  270. package/dist/browser-host/browser-font-provider.d.ts +12 -0
  271. package/dist/browser-host/browser-font-provider.d.ts.map +1 -1
  272. package/dist/browser-host/browser-font-provider.js +25 -0
  273. package/dist/browser-host/browser-font-provider.js.map +1 -1
  274. package/dist/browser.d.ts +6 -3
  275. package/dist/browser.d.ts.map +1 -1
  276. package/dist/browser.js +10 -3
  277. package/dist/browser.js.map +1 -1
  278. package/dist/cad-runtime/backend-dispatch.d.ts +28 -3
  279. package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
  280. package/dist/cad-runtime/backend-dispatch.js +119 -4
  281. package/dist/cad-runtime/backend-dispatch.js.map +1 -1
  282. package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
  283. package/dist/cad-runtime/direct-executor.d.ts +15 -3
  284. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  285. package/dist/cad-runtime/direct-executor.js +33 -1
  286. package/dist/cad-runtime/direct-executor.js.map +1 -1
  287. package/dist/cad-runtime/ports.d.ts +3 -3
  288. package/dist/cad-runtime/ports.d.ts.map +1 -1
  289. package/dist/cad-runtime/ports.js.map +1 -1
  290. package/dist/cad-runtime/preview-exec.d.ts +4 -4
  291. package/dist/cad-runtime/preview-exec.js +2 -2
  292. package/dist/cad-runtime/preview-exec.js.map +1 -1
  293. package/dist/cad-runtime/runtime.d.ts +42 -7
  294. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  295. package/dist/cad-runtime/runtime.js +68 -5
  296. package/dist/cad-runtime/runtime.js.map +1 -1
  297. package/dist/define-op.d.ts +15 -1
  298. package/dist/define-op.d.ts.map +1 -1
  299. package/dist/define-op.js +73 -2
  300. package/dist/define-op.js.map +1 -1
  301. package/dist/env-agnostic.d.ts +2 -2
  302. package/dist/env-agnostic.d.ts.map +1 -1
  303. package/dist/env-agnostic.js +1 -1
  304. package/dist/env-agnostic.js.map +1 -1
  305. package/dist/geometry2d/adapt.d.ts +39 -4
  306. package/dist/geometry2d/adapt.d.ts.map +1 -1
  307. package/dist/geometry2d/adapt.js +14 -3
  308. package/dist/geometry2d/adapt.js.map +1 -1
  309. package/dist/geometry2d/blueprint.d.ts +2 -2
  310. package/dist/geometry2d/blueprint.js +2 -2
  311. package/dist/geometry2d/blueprint.js.map +1 -1
  312. package/dist/geometry2d/bridge/lift-on-plane.d.ts +18 -8
  313. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
  314. package/dist/geometry2d/bridge/lift-on-plane.js +65 -12
  315. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
  316. package/dist/geometry2d/bridge/plane.d.ts +17 -0
  317. package/dist/geometry2d/bridge/plane.d.ts.map +1 -1
  318. package/dist/geometry2d/bridge/plane.js +22 -0
  319. package/dist/geometry2d/bridge/plane.js.map +1 -1
  320. package/dist/geometry2d/curve2d.d.ts +25 -0
  321. package/dist/geometry2d/curve2d.d.ts.map +1 -1
  322. package/dist/geometry2d/curve2d.js +41 -5
  323. package/dist/geometry2d/curve2d.js.map +1 -1
  324. package/dist/index.d.ts +6 -2
  325. package/dist/index.d.ts.map +1 -1
  326. package/dist/index.js +10 -3
  327. package/dist/index.js.map +1 -1
  328. package/dist/io/bytes-node.d.ts +11 -0
  329. package/dist/io/bytes-node.d.ts.map +1 -0
  330. package/dist/io/bytes-node.js +28 -0
  331. package/dist/io/bytes-node.js.map +1 -0
  332. package/dist/io/bytes.d.ts +33 -0
  333. package/dist/io/bytes.d.ts.map +1 -0
  334. package/dist/io/bytes.js +41 -0
  335. package/dist/io/bytes.js.map +1 -0
  336. package/dist/io/fai-zip/container-read.d.ts +102 -0
  337. package/dist/io/fai-zip/container-read.d.ts.map +1 -0
  338. package/dist/io/fai-zip/container-read.js +305 -0
  339. package/dist/io/fai-zip/container-read.js.map +1 -0
  340. package/dist/io/fai-zip/container-write.d.ts +70 -0
  341. package/dist/io/fai-zip/container-write.d.ts.map +1 -0
  342. package/dist/io/fai-zip/container-write.js +186 -0
  343. package/dist/io/fai-zip/container-write.js.map +1 -0
  344. package/dist/io/fai-zip/container.d.ts +107 -0
  345. package/dist/io/fai-zip/container.d.ts.map +1 -0
  346. package/dist/io/fai-zip/container.js +89 -0
  347. package/dist/io/fai-zip/container.js.map +1 -0
  348. package/dist/io/fai-zip/index.d.ts +18 -0
  349. package/dist/io/fai-zip/index.d.ts.map +1 -0
  350. package/dist/io/fai-zip/index.js +4 -0
  351. package/dist/io/fai-zip/index.js.map +1 -0
  352. package/dist/io/index.d.ts +10 -0
  353. package/dist/io/index.d.ts.map +1 -0
  354. package/dist/io/index.js +13 -0
  355. package/dist/io/index.js.map +1 -0
  356. package/dist/io/zip.d.ts +68 -0
  357. package/dist/io/zip.d.ts.map +1 -0
  358. package/dist/io/zip.js +147 -0
  359. package/dist/io/zip.js.map +1 -0
  360. package/dist/lang/code-to-args.d.ts +1 -1
  361. package/dist/lang/code-to-args.js +1 -1
  362. package/dist/lang/code-to-args.js.map +1 -1
  363. package/dist/lang/metadata-extractor.d.ts.map +1 -1
  364. package/dist/lang/metadata-extractor.js +2 -21
  365. package/dist/lang/metadata-extractor.js.map +1 -1
  366. package/dist/lang/statement-summary.d.ts +1 -1
  367. package/dist/lang/statement-summary.js +1 -1
  368. package/dist/lang/statement-summary.js.map +1 -1
  369. package/dist/lang/types.d.ts +6 -7
  370. package/dist/lang/types.d.ts.map +1 -1
  371. package/dist/lang/types.js +1 -1
  372. package/dist/lang/types.js.map +1 -1
  373. package/dist/mesh/index.d.ts +2 -1
  374. package/dist/mesh/index.d.ts.map +1 -1
  375. package/dist/mesh/index.js +2 -1
  376. package/dist/mesh/index.js.map +1 -1
  377. package/dist/mesh/io.d.ts +13 -0
  378. package/dist/mesh/io.d.ts.map +1 -1
  379. package/dist/mesh/io.js +38 -17
  380. package/dist/mesh/io.js.map +1 -1
  381. package/dist/mesh/primitives.d.ts.map +1 -1
  382. package/dist/mesh/primitives.js +41 -6
  383. package/dist/mesh/primitives.js.map +1 -1
  384. package/dist/mesh/reconcile.d.ts +1 -1
  385. package/dist/mesh/reconcile.js +1 -1
  386. package/dist/mesh/reconcile.js.map +1 -1
  387. package/dist/mesh/rigid-transform.d.ts +3 -3
  388. package/dist/mesh/rigid-transform.js +3 -3
  389. package/dist/mesh/rigid-transform.js.map +1 -1
  390. package/dist/mesh/stl-unit.d.ts +24 -0
  391. package/dist/mesh/stl-unit.d.ts.map +1 -0
  392. package/dist/mesh/stl-unit.js +17 -0
  393. package/dist/mesh/stl-unit.js.map +1 -0
  394. package/dist/mesh/threemf-bambu.d.ts +142 -0
  395. package/dist/mesh/threemf-bambu.d.ts.map +1 -0
  396. package/dist/mesh/threemf-bambu.js +334 -0
  397. package/dist/mesh/threemf-bambu.js.map +1 -0
  398. package/dist/mesh/threemf-loader.d.ts +65 -7
  399. package/dist/mesh/threemf-loader.d.ts.map +1 -1
  400. package/dist/mesh/threemf-loader.js +738 -99
  401. package/dist/mesh/threemf-loader.js.map +1 -1
  402. package/dist/mesh/threemf-view.d.ts +71 -0
  403. package/dist/mesh/threemf-view.d.ts.map +1 -0
  404. package/dist/mesh/threemf-view.js +100 -0
  405. package/dist/mesh/threemf-view.js.map +1 -0
  406. package/dist/mesh/types.d.ts +38 -0
  407. package/dist/mesh/types.d.ts.map +1 -1
  408. package/dist/mesh/types.js.map +1 -1
  409. package/dist/node-host/cli.d.ts +44 -6
  410. package/dist/node-host/cli.d.ts.map +1 -1
  411. package/dist/node-host/cli.js +76 -26
  412. package/dist/node-host/cli.js.map +1 -1
  413. package/dist/node-host/font-family-index.d.ts +93 -0
  414. package/dist/node-host/font-family-index.d.ts.map +1 -0
  415. package/dist/node-host/font-family-index.js +273 -0
  416. package/dist/node-host/font-family-index.js.map +1 -0
  417. package/dist/node-host/fs-asset-resolver.d.ts +8 -3
  418. package/dist/node-host/fs-asset-resolver.d.ts.map +1 -1
  419. package/dist/node-host/fs-asset-resolver.js +13 -5
  420. package/dist/node-host/fs-asset-resolver.js.map +1 -1
  421. package/dist/node-host/index.d.ts +8 -0
  422. package/dist/node-host/index.d.ts.map +1 -1
  423. package/dist/node-host/index.js +1 -0
  424. package/dist/node-host/index.js.map +1 -1
  425. package/dist/node-host/node-font-provider.d.ts +28 -0
  426. package/dist/node-host/node-font-provider.d.ts.map +1 -1
  427. package/dist/node-host/node-font-provider.js +49 -0
  428. package/dist/node-host/node-font-provider.js.map +1 -1
  429. package/dist/node.d.ts +1 -0
  430. package/dist/node.d.ts.map +1 -1
  431. package/dist/node.js +1 -0
  432. package/dist/node.js.map +1 -1
  433. package/dist/occt-kernel/highLevelApi.d.ts +4 -1
  434. package/dist/occt-kernel/highLevelApi.d.ts.map +1 -1
  435. package/dist/occt-kernel/highLevelApi.js +4 -2
  436. package/dist/occt-kernel/highLevelApi.js.map +1 -1
  437. package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
  438. package/dist/occt-kernel/occt-primitives.js +36 -3
  439. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  440. package/dist/occt-kernel/occtKernel.d.ts +19 -14
  441. package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
  442. package/dist/occt-kernel/occtKernel.js +19 -32
  443. package/dist/occt-kernel/occtKernel.js.map +1 -1
  444. package/dist/occt-kernel/stepColorParser.d.ts +18 -0
  445. package/dist/occt-kernel/stepColorParser.d.ts.map +1 -1
  446. package/dist/occt-kernel/stepColorParser.js +38 -0
  447. package/dist/occt-kernel/stepColorParser.js.map +1 -1
  448. package/dist/occt-kernel/stepMetaParser.d.ts +44 -0
  449. package/dist/occt-kernel/stepMetaParser.d.ts.map +1 -0
  450. package/dist/occt-kernel/stepMetaParser.js +166 -0
  451. package/dist/occt-kernel/stepMetaParser.js.map +1 -0
  452. package/dist/occt-kernel/topologyExt.d.ts +1 -1
  453. package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
  454. package/dist/occt-kernel/topologyExt.js +4 -5
  455. package/dist/occt-kernel/topologyExt.js.map +1 -1
  456. package/dist/primitives/text/cjk-font.d.ts +2 -15
  457. package/dist/primitives/text/cjk-font.d.ts.map +1 -1
  458. package/dist/primitives/text/cjk-font.js +13 -1
  459. package/dist/primitives/text/cjk-font.js.map +1 -1
  460. package/dist/runtime-state.d.ts +85 -9
  461. package/dist/runtime-state.d.ts.map +1 -1
  462. package/dist/runtime-state.js +72 -2
  463. package/dist/runtime-state.js.map +1 -1
  464. package/dist/sdk.d.ts +3 -3
  465. package/dist/sdk.d.ts.map +1 -1
  466. package/dist/sdk.js +5 -5
  467. package/dist/sdk.js.map +1 -1
  468. package/dist/shape.d.ts +108 -5
  469. package/dist/shape.d.ts.map +1 -1
  470. package/dist/shape.js +130 -3
  471. package/dist/shape.js.map +1 -1
  472. package/dist/step/stepMetaParser.d.ts +55 -0
  473. package/dist/step/stepMetaParser.d.ts.map +1 -0
  474. package/dist/step/stepMetaParser.js +177 -0
  475. package/dist/step/stepMetaParser.js.map +1 -0
  476. package/dist/topology/naming/lineage.d.ts +6 -0
  477. package/dist/topology/naming/lineage.d.ts.map +1 -1
  478. package/dist/topology/naming/lineage.js +8 -0
  479. package/dist/topology/naming/lineage.js.map +1 -1
  480. package/dist/topology/naming/resolve-edge.d.ts +20 -1
  481. package/dist/topology/naming/resolve-edge.d.ts.map +1 -1
  482. package/dist/topology/naming/resolve-edge.js +54 -20
  483. package/dist/topology/naming/resolve-edge.js.map +1 -1
  484. package/dist/weapp.d.ts +6 -2
  485. package/dist/weapp.d.ts.map +1 -1
  486. package/dist/weapp.js +7 -1
  487. package/dist/weapp.js.map +1 -1
  488. package/package.json +19 -3
@@ -0,0 +1,229 @@
1
+ /**
2
+ * mesh-solid — 网格实体(mesh solid)与其网格后端端口
3
+ *
4
+ *
5
+ * 名词边界(方案 §3.1):
6
+ * - **网格实体** = 由网格文件导入、经「规范化」得到的引擎实体。它是**近似拓扑**
7
+ * 的载体,不是精度链的一环;永不进 `brepChain.solidCache`。
8
+ * - **规范化** = `importIndexedMesh` → `weldShellsAndFaces(tol)` → `unifyFaces()`。
9
+ * **顺序不可交换**:先 `unifyFaces` 会把实体做坏(体积归零),防回归用例见
10
+ * `brepkit-kernel/mesh-solid-topology.test.ts`。
11
+ * - **网格后端** = 提供网格实体能力的引擎侧组件(本期即 brepkit 的网格用法)。
12
+ * 与 BREP 引擎**同名不同用**:可能同一个 wasm 实例,但走 mesh 语义路径。
13
+ *
14
+ * 本模块只依赖 L1(`engine/types`、`engine/primitives`)与拓扑构建器;后端实现
15
+ * 放在适配器侧(`brep/engine/adapters/brepkit`),因此本模块自身不含任何内核私有
16
+ * 调用——`MeshSolidKernelOps` 是内核私有原语的端口(L1 契约不含 weld/unify)。
17
+ */
18
+ import { buildTopologyFromMesh } from './brep-topology.js';
19
+ // ── 规范化驱动(引擎中立,供适配器的 MeshSolidBackend 实现复用) ──
20
+ /** 与显示 mesh 一致的默认三角化参数(`buildSolidTopologyRuntime` 同源)。 */
21
+ const DISPLAY_LINEAR_DEFLECTION = 0.1;
22
+ const DISPLAY_ANGULAR_DEFLECTION = (2 * Math.PI) / 32;
23
+ /**
24
+ * 由包围盒对角线导出焊接容差(方案 §3.3)。
25
+ *
26
+ * 下限 1e-6 兜住退化 bbox(单点/零厚网格);上不封顶——超大模型需要更粗的
27
+ * 缝合半径才缝得上(float32 坐标的相对误差随尺度线性增长)。
28
+ *
29
+ * @param kernel - the L1 kernel API (bbox query only).
30
+ * @param shape - the raw imported shape.
31
+ * @returns the weld tolerance derived from the bounding-box diagonal.
32
+ */
33
+ export function weldToleranceFor(kernel, shape) {
34
+ const bb = kernel.getBoundingBox(shape, false);
35
+ const dx = bb.xmax - bb.xmin;
36
+ const dy = bb.ymax - bb.ymin;
37
+ const dz = bb.zmax - bb.zmin;
38
+ const diag = Math.sqrt(dx * dx + dy * dy + dz * dz);
39
+ return Math.max(1e-6, diag * 1e-6);
40
+ }
41
+ /**
42
+ * 规范化:`importMesh` → `weld` → `unify`,再校验并三角化。
43
+ *
44
+ * 三条硬约束,都是 Phase 0 实测结论:
45
+ * 1. **顺序不可交换**——先 unify 再 weld 会得到体积归零的坏实体;
46
+ * 2. `unify` **原地修改**,返回值是合并面数,不是句柄;
47
+ * 3. 校验用 `isValid`(weld 后必须合法),不合法即抛错——开放/非流形网格必须
48
+ * 在导入处失败,不能静默退化成"无拓扑的裸网格"(那会让所有下游 mesh op
49
+ * 失去选择能力)。
50
+ *
51
+ * @param backend - the mesh backend providing ops + kernel.
52
+ * @param mesh - the source triangle mesh.
53
+ * @param opts - optional weld tolerance / tessellation overrides.
54
+ * @returns the normalized mesh solid, its tessellation, and element counts.
55
+ * @throws {Error} `E_MESH_SOLID_UNWELDABLE` when welding leaves an invalid solid.
56
+ */
57
+ export function normalizeMeshSolid(backend, mesh, opts) {
58
+ const { kernel, ops } = backend;
59
+ const raw = ops.importMesh(mesh.positions, mesh.indices);
60
+ const tolerance = opts?.weldTolerance ?? weldToleranceFor(kernel, raw);
61
+ const faces = kernel.getSubShapes(raw, 'face');
62
+ const welded = ops.weld(faces, tolerance);
63
+ // 原地修改:返回值是合并掉的面数。绝不能把它当句柄。
64
+ const mergedFaceCount = ops.unify(welded);
65
+ if (!kernel.isValid(welded)) {
66
+ // 原始实体(逐三角形、边不共享)在 weld 前就不合法是正常的;weld 后仍不合法
67
+ // 说明网格本身开放/非流形/自交——这是**必须暴露的导入失败**,不是可降级状态。
68
+ try {
69
+ backend.release(raw);
70
+ }
71
+ catch { /* already released */ }
72
+ throw new Error(`E_MESH_SOLID_UNWELDABLE: welded mesh is still an invalid solid (tolerance=${tolerance}) — ` +
73
+ 'the source mesh is open, non-manifold or self-intersecting');
74
+ }
75
+ // 焊接后原始逐三角形实体已无用;及时释放,避免句柄堆积(新路径不得添泄漏)。
76
+ try {
77
+ backend.release(raw);
78
+ }
79
+ catch { /* already released */ }
80
+ const tess = kernel.meshShape(welded, {
81
+ linearDeflection: opts?.linearDeflection ?? DISPLAY_LINEAR_DEFLECTION,
82
+ angularDeflection: opts?.angularDeflection ?? DISPLAY_ANGULAR_DEFLECTION,
83
+ });
84
+ return {
85
+ solid: welded,
86
+ mesh: tess,
87
+ faceCount: kernel.getSubShapes(welded, 'face').length,
88
+ edgeCount: kernel.getSubShapes(welded, 'edge').length,
89
+ vertexCount: kernel.getSubShapes(welded, 'vertex').length,
90
+ weldTolerance: tolerance,
91
+ mergedFaceCount,
92
+ };
93
+ }
94
+ /**
95
+ * 已存在的网格实体 → 结果描述(三角化 + 计数)。
96
+ *
97
+ * Phase 2 的 mesh op 产出的新实体走这里:**一次**三角化同时喂显示与拓扑,
98
+ * 保证 `faceRuns` 与所见三角形一一对应(规则 1)。重复调 `describe` 会得到
99
+ * 另一份三角化结果——同一实体在同一参数下确定性一致,但仍应复用同一份结果。
100
+ *
101
+ * @param backend - the mesh backend.
102
+ * @param solid - an existing mesh solid handle.
103
+ * @param opts - optional tessellation overrides.
104
+ * @returns the mesh solid result carrying the shared tessellation.
105
+ */
106
+ export function describeMeshSolid(backend, solid, opts) {
107
+ const { kernel } = backend;
108
+ const tess = kernel.meshShape(solid, {
109
+ linearDeflection: opts?.linearDeflection ?? DISPLAY_LINEAR_DEFLECTION,
110
+ angularDeflection: opts?.angularDeflection ?? DISPLAY_ANGULAR_DEFLECTION,
111
+ });
112
+ return {
113
+ solid,
114
+ mesh: tess,
115
+ faceCount: kernel.getSubShapes(solid, 'face').length,
116
+ edgeCount: kernel.getSubShapes(solid, 'edge').length,
117
+ vertexCount: kernel.getSubShapes(solid, 'vertex').length,
118
+ weldTolerance: 0,
119
+ mergedFaceCount: 0,
120
+ };
121
+ }
122
+ /**
123
+ * 网格实体 → 近似拓扑数据(`SelectorRuntimeData`)。
124
+ *
125
+ * 复用 BREP 路径同源的 `buildTopologyFromMesh`(方案 §1.3 实测:产物与 BREP
126
+ * 路径同构——同样的 FaceRow/EdgeRow 字段、同样的 `faceStart/faceCount` 邻接)。
127
+ * **不引入第二套拓扑表示。**
128
+ *
129
+ * @param backend - the mesh backend (kernel + release).
130
+ * @param result - the normalized mesh solid result (carries the shared tessellation).
131
+ * @returns the serializable selector runtime data.
132
+ */
133
+ export function buildMeshSolidTopology(backend, result) {
134
+ return buildTopologyFromMesh(backend.kernel, result.solid, result.mesh);
135
+ }
136
+ // ── 注册表(生命周期,与 brepChain.solidCache 并列且互不干扰) ──
137
+ /**
138
+ * 网格实体句柄注册表(`PartName → BrepHandle`)。
139
+ *
140
+ * 与 `brepChain.solidCache` 的差别:本表**永不**参与 BREP 精度链判定——
141
+ * 它存在只表示"该 part 是网格零件,携带近似拓扑"。释放语义与 solidCache 对齐:
142
+ * `set` 覆盖不释放(旧句柄可能仍被旧输出 Shape 引用),`delete`/`clear` 释放。
143
+ */
144
+ export class MeshSolidRegistry {
145
+ handles = new Map();
146
+ backendRef = null;
147
+ /**
148
+ * 装配/换装网格后端(宿主装配期;运行期只读语义)。
149
+ * @param backend - the mesh backend, or null to detach.
150
+ */
151
+ setBackend(backend) {
152
+ this.backendRef = backend;
153
+ }
154
+ /**
155
+ * 当前网格后端(未装配则 null)。
156
+ * @returns the assembled mesh backend, or null.
157
+ */
158
+ get backend() {
159
+ return this.backendRef;
160
+ }
161
+ /**
162
+ * 登记某 part 的网格实体句柄(覆盖旧值,**不释放**旧句柄——与 solidCache 同语义)。
163
+ * @param part - the part name.
164
+ * @param solid - the mesh solid handle.
165
+ */
166
+ set(part, solid) {
167
+ this.handles.set(part, solid);
168
+ }
169
+ /**
170
+ * 读取某 part 的网格实体句柄。
171
+ * @param part - the part name.
172
+ * @returns the handle, or undefined.
173
+ */
174
+ get(part) {
175
+ return this.handles.get(part);
176
+ }
177
+ /**
178
+ * 该 part 是否携带网格实体。
179
+ * @param part - the part name.
180
+ * @returns true when a handle is registered.
181
+ */
182
+ has(part) {
183
+ return this.handles.has(part);
184
+ }
185
+ /**
186
+ * 删除某 part 并释放其句柄(重放/失效路径)。
187
+ * @param part - the part name.
188
+ */
189
+ delete(part) {
190
+ const h = this.handles.get(part);
191
+ if (h === undefined)
192
+ return;
193
+ this.handles.delete(part);
194
+ try {
195
+ this.backendRef?.release(h);
196
+ }
197
+ catch { /* already released */ }
198
+ }
199
+ /**
200
+ * 按 part 名列表批量删除(重放失效用)。
201
+ * @param parts - the part names to delete; unknown names are ignored.
202
+ */
203
+ deleteMany(parts) {
204
+ for (const p of parts)
205
+ this.delete(p);
206
+ }
207
+ /** 释放全部句柄并清空(dispose)。 */
208
+ clear() {
209
+ for (const h of this.handles.values()) {
210
+ try {
211
+ this.backendRef?.release(h);
212
+ }
213
+ catch { /* already released */ }
214
+ }
215
+ this.handles.clear();
216
+ }
217
+ /**
218
+ * 当前登记的全部 part 名(诊断/测试)。
219
+ * @returns the registered part names.
220
+ */
221
+ keys() {
222
+ return [...this.handles.keys()];
223
+ }
224
+ /** 登记数量(诊断/测试)。 */
225
+ get size() {
226
+ return this.handles.size;
227
+ }
228
+ }
229
+ //# sourceMappingURL=mesh-solid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh-solid.js","sourceRoot":"","sources":["../../src/brep/mesh-solid.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * mesh-solid — 网格实体(mesh solid)与其网格后端端口\n *\n *\n * 名词边界(方案 §3.1):\n * - **网格实体** = 由网格文件导入、经「规范化」得到的引擎实体。它是**近似拓扑**\n * 的载体,不是精度链的一环;永不进 `brepChain.solidCache`。\n * - **规范化** = `importIndexedMesh` → `weldShellsAndFaces(tol)` → `unifyFaces()`。\n * **顺序不可交换**:先 `unifyFaces` 会把实体做坏(体积归零),防回归用例见\n * `brepkit-kernel/mesh-solid-topology.test.ts`。\n * - **网格后端** = 提供网格实体能力的引擎侧组件(本期即 brepkit 的网格用法)。\n * 与 BREP 引擎**同名不同用**:可能同一个 wasm 实例,但走 mesh 语义路径。\n *\n * 本模块只依赖 L1(`engine/types`、`engine/primitives`)与拓扑构建器;后端实现\n * 放在适配器侧(`brep/engine/adapters/brepkit`),因此本模块自身不含任何内核私有\n * 调用——`MeshSolidKernelOps` 是内核私有原语的端口(L1 契约不含 weld/unify)。\n */\n\nimport type { BrepHandle, BrepMeshResult } from './engine/types'\nimport type { BrepEngineApi } from './engine/primitives'\nimport type { PartName } from '../identity'\nimport type { SelectorRuntimeData } from '../topology/build-selector-runtime'\nimport { buildTopologyFromMesh } from './brep-topology'\n\n/** 网格实体构建的输入网格(已按基准单位折算的坐标,与 `Shape` 同构)。 */\nexport interface MeshSolidInput {\n positions: Float32Array\n indices: Uint32Array\n}\n\n/** 规范化选项。 */\nexport interface MeshSolidNormalizeOptions {\n /**\n * 焊接容差(顶点/重复边缝合半径)。缺省由包围盒对角线定标\n * (`max(1e-6, 对角线 × 1e-6)`)——**不得写死绝对值**:STL 无单位元数据,\n * 同一文件既可能是 mm 也可能是 inch,绝对容差在两种尺度下必有一边失准。\n */\n weldTolerance?: number\n /** 三角化参数(缺省与显示 mesh 一致:0.1 / 2π/32)。 */\n linearDeflection?: number\n angularDeflection?: number\n}\n\n/** 规范化结果:实体句柄 + 其三角化(显示 mesh 与拓扑 mesh 的唯一真源)。 */\nexport interface MeshSolidResult {\n /** 规范化后的网格实体句柄。 */\n readonly solid: BrepHandle\n /**\n * 同一实体的三角化(含 faceGroups)。**显示 mesh 必须用这一份**——规则 1:\n * 拓扑 faceRuns 所索引的三角形,必须就是用户看到的三角形。若显示仍用原始\n * STL 顶点数组、拓扑用实体的重新三角化,两者三角形数/序不一致 → faceRuns 错位。\n */\n readonly mesh: BrepMeshResult\n readonly faceCount: number\n readonly edgeCount: number\n readonly vertexCount: number\n /** 实际使用的焊接容差(诊断/复现用)。 */\n readonly weldTolerance: number\n /** `unifyFaces` 合并掉的重复面数(0 = 共面面片未被合并,顶点未焊上)。 */\n readonly mergedFaceCount: number\n}\n\n/**\n * 网格后端的**内核私有原语**(L1 `BrepEngineApi` 不含 weld/unify)。\n *\n * 由适配器(拥用内核闭包的一侧)实现;句柄一律是 faijs `BrepHandle`\n * (适配器内部负责 `asNum()` 剥离标签),本模块不感知内核方言。\n */\nexport interface MeshSolidKernelOps {\n /** 原始三角网格 → 逐三角形面的实体(内核自带顶点焊接)。 */\n importMesh(positions: Float32Array, indices: Uint32Array): BrepHandle\n /** 面列表 → 缝合后的实体(重复边缝成共享边 → 真流形)。 */\n weld(faces: BrepHandle[], tolerance: number): BrepHandle\n /** 共面区域合并(**原地修改**,返回合并掉的面数)。 */\n unify(solid: BrepHandle): number\n}\n\n/**\n * 网格后端端口:`load` 的 mesh 路径经它产出网格实体与近似拓扑。\n *\n * 生命周期:由宿主装配期注册进 mesh 引擎槽(`registerMeshEngine`),运行期只读。\n */\nexport interface MeshSolidBackend {\n /** 后端 id(与 `defineOp.meshEngines` 的门禁名同源,如 `'brepkit'`)。 */\n readonly id: string\n /** L1 契约面(拓扑查询 + 几何操作;brepkit 适配器已全实现)。 */\n readonly kernel: BrepEngineApi\n /** 内核私有原语(weld/unify)。 */\n readonly ops: MeshSolidKernelOps\n /**\n * 规范化 + 三角化。**失败必须抛错**(带 part 名由调用方补),不静默降级。\n * @param mesh - the source triangle mesh (base-unit coordinates).\n * @param opts - optional weld tolerance / tessellation overrides.\n * @returns the mesh solid with its tessellation.\n */\n normalize(mesh: MeshSolidInput, opts?: MeshSolidNormalizeOptions): MeshSolidResult\n /**\n * 已存在的网格实体 → 结果描述(三角化 + 计数)。Phase 2 的 mesh op 用它把\n * 「内核操作产出的新实体」包成下一份网格零件(显示 mesh 与拓扑 mesh 同源)。\n * @param solid - an existing mesh solid handle.\n * @param opts - optional tessellation overrides.\n * @returns the mesh solid result carrying the shared tessellation.\n */\n describe(solid: BrepHandle, opts?: MeshSolidNormalizeOptions): MeshSolidResult\n /**\n * 从网格实体结果构建近似拓扑数据(`SelectorRuntimeData`,可直接交 `setTopology`)。\n * @param result - the mesh solid result (its tessellation indexes the topology).\n * @returns the serializable selector runtime data.\n */\n buildTopologyData(result: MeshSolidResult): SelectorRuntimeData\n /** 释放网格实体句柄。 */\n release(solid: BrepHandle): void\n}\n\n// ── 规范化驱动(引擎中立,供适配器的 MeshSolidBackend 实现复用) ──\n\n/** 与显示 mesh 一致的默认三角化参数(`buildSolidTopologyRuntime` 同源)。 */\nconst DISPLAY_LINEAR_DEFLECTION = 0.1\nconst DISPLAY_ANGULAR_DEFLECTION = (2 * Math.PI) / 32\n\n/**\n * 由包围盒对角线导出焊接容差(方案 §3.3)。\n *\n * 下限 1e-6 兜住退化 bbox(单点/零厚网格);上不封顶——超大模型需要更粗的\n * 缝合半径才缝得上(float32 坐标的相对误差随尺度线性增长)。\n *\n * @param kernel - the L1 kernel API (bbox query only).\n * @param shape - the raw imported shape.\n * @returns the weld tolerance derived from the bounding-box diagonal.\n */\nexport function weldToleranceFor(kernel: BrepEngineApi, shape: BrepHandle): number {\n const bb = kernel.getBoundingBox(shape, false)\n const dx = bb.xmax - bb.xmin\n const dy = bb.ymax - bb.ymin\n const dz = bb.zmax - bb.zmin\n const diag = Math.sqrt(dx * dx + dy * dy + dz * dz)\n return Math.max(1e-6, diag * 1e-6)\n}\n\n/**\n * 规范化:`importMesh` → `weld` → `unify`,再校验并三角化。\n *\n * 三条硬约束,都是 Phase 0 实测结论:\n * 1. **顺序不可交换**——先 unify 再 weld 会得到体积归零的坏实体;\n * 2. `unify` **原地修改**,返回值是合并面数,不是句柄;\n * 3. 校验用 `isValid`(weld 后必须合法),不合法即抛错——开放/非流形网格必须\n * 在导入处失败,不能静默退化成\"无拓扑的裸网格\"(那会让所有下游 mesh op\n * 失去选择能力)。\n *\n * @param backend - the mesh backend providing ops + kernel.\n * @param mesh - the source triangle mesh.\n * @param opts - optional weld tolerance / tessellation overrides.\n * @returns the normalized mesh solid, its tessellation, and element counts.\n * @throws {Error} `E_MESH_SOLID_UNWELDABLE` when welding leaves an invalid solid.\n */\nexport function normalizeMeshSolid(\n backend: MeshSolidBackend,\n mesh: MeshSolidInput,\n opts?: MeshSolidNormalizeOptions,\n): MeshSolidResult {\n const { kernel, ops } = backend\n const raw = ops.importMesh(mesh.positions, mesh.indices)\n const tolerance = opts?.weldTolerance ?? weldToleranceFor(kernel, raw)\n\n const faces = kernel.getSubShapes(raw, 'face')\n const welded = ops.weld(faces, tolerance)\n // 原地修改:返回值是合并掉的面数。绝不能把它当句柄。\n const mergedFaceCount = ops.unify(welded)\n\n if (!kernel.isValid(welded)) {\n // 原始实体(逐三角形、边不共享)在 weld 前就不合法是正常的;weld 后仍不合法\n // 说明网格本身开放/非流形/自交——这是**必须暴露的导入失败**,不是可降级状态。\n try { backend.release(raw) } catch { /* already released */ }\n throw new Error(\n `E_MESH_SOLID_UNWELDABLE: welded mesh is still an invalid solid (tolerance=${tolerance}) — ` +\n 'the source mesh is open, non-manifold or self-intersecting',\n )\n }\n // 焊接后原始逐三角形实体已无用;及时释放,避免句柄堆积(新路径不得添泄漏)。\n try { backend.release(raw) } catch { /* already released */ }\n\n const tess = kernel.meshShape(welded, {\n linearDeflection: opts?.linearDeflection ?? DISPLAY_LINEAR_DEFLECTION,\n angularDeflection: opts?.angularDeflection ?? DISPLAY_ANGULAR_DEFLECTION,\n })\n\n return {\n solid: welded,\n mesh: tess,\n faceCount: kernel.getSubShapes(welded, 'face').length,\n edgeCount: kernel.getSubShapes(welded, 'edge').length,\n vertexCount: kernel.getSubShapes(welded, 'vertex').length,\n weldTolerance: tolerance,\n mergedFaceCount,\n }\n}\n\n/**\n * 已存在的网格实体 → 结果描述(三角化 + 计数)。\n *\n * Phase 2 的 mesh op 产出的新实体走这里:**一次**三角化同时喂显示与拓扑,\n * 保证 `faceRuns` 与所见三角形一一对应(规则 1)。重复调 `describe` 会得到\n * 另一份三角化结果——同一实体在同一参数下确定性一致,但仍应复用同一份结果。\n *\n * @param backend - the mesh backend.\n * @param solid - an existing mesh solid handle.\n * @param opts - optional tessellation overrides.\n * @returns the mesh solid result carrying the shared tessellation.\n */\nexport function describeMeshSolid(\n backend: MeshSolidBackend,\n solid: BrepHandle,\n opts?: MeshSolidNormalizeOptions,\n): MeshSolidResult {\n const { kernel } = backend\n const tess = kernel.meshShape(solid, {\n linearDeflection: opts?.linearDeflection ?? DISPLAY_LINEAR_DEFLECTION,\n angularDeflection: opts?.angularDeflection ?? DISPLAY_ANGULAR_DEFLECTION,\n })\n return {\n solid,\n mesh: tess,\n faceCount: kernel.getSubShapes(solid, 'face').length,\n edgeCount: kernel.getSubShapes(solid, 'edge').length,\n vertexCount: kernel.getSubShapes(solid, 'vertex').length,\n weldTolerance: 0,\n mergedFaceCount: 0,\n }\n}\n\n/**\n * 网格实体 → 近似拓扑数据(`SelectorRuntimeData`)。\n *\n * 复用 BREP 路径同源的 `buildTopologyFromMesh`(方案 §1.3 实测:产物与 BREP\n * 路径同构——同样的 FaceRow/EdgeRow 字段、同样的 `faceStart/faceCount` 邻接)。\n * **不引入第二套拓扑表示。**\n *\n * @param backend - the mesh backend (kernel + release).\n * @param result - the normalized mesh solid result (carries the shared tessellation).\n * @returns the serializable selector runtime data.\n */\nexport function buildMeshSolidTopology(\n backend: MeshSolidBackend,\n result: MeshSolidResult,\n): SelectorRuntimeData {\n return buildTopologyFromMesh(backend.kernel, result.solid, result.mesh)\n}\n\n// ── 注册表(生命周期,与 brepChain.solidCache 并列且互不干扰) ──\n\n/**\n * 网格实体句柄注册表(`PartName → BrepHandle`)。\n *\n * 与 `brepChain.solidCache` 的差别:本表**永不**参与 BREP 精度链判定——\n * 它存在只表示\"该 part 是网格零件,携带近似拓扑\"。释放语义与 solidCache 对齐:\n * `set` 覆盖不释放(旧句柄可能仍被旧输出 Shape 引用),`delete`/`clear` 释放。\n */\nexport class MeshSolidRegistry {\n private readonly handles = new Map<PartName, BrepHandle>()\n private backendRef: MeshSolidBackend | null = null\n\n /**\n * 装配/换装网格后端(宿主装配期;运行期只读语义)。\n * @param backend - the mesh backend, or null to detach.\n */\n setBackend(backend: MeshSolidBackend | null): void {\n this.backendRef = backend\n }\n\n /**\n * 当前网格后端(未装配则 null)。\n * @returns the assembled mesh backend, or null.\n */\n get backend(): MeshSolidBackend | null {\n return this.backendRef\n }\n\n /**\n * 登记某 part 的网格实体句柄(覆盖旧值,**不释放**旧句柄——与 solidCache 同语义)。\n * @param part - the part name.\n * @param solid - the mesh solid handle.\n */\n set(part: PartName, solid: BrepHandle): void {\n this.handles.set(part, solid)\n }\n\n /**\n * 读取某 part 的网格实体句柄。\n * @param part - the part name.\n * @returns the handle, or undefined.\n */\n get(part: PartName): BrepHandle | undefined {\n return this.handles.get(part)\n }\n\n /**\n * 该 part 是否携带网格实体。\n * @param part - the part name.\n * @returns true when a handle is registered.\n */\n has(part: PartName): boolean {\n return this.handles.has(part)\n }\n\n /**\n * 删除某 part 并释放其句柄(重放/失效路径)。\n * @param part - the part name.\n */\n delete(part: PartName): void {\n const h = this.handles.get(part)\n if (h === undefined) return\n this.handles.delete(part)\n try { this.backendRef?.release(h) } catch { /* already released */ }\n }\n\n /**\n * 按 part 名列表批量删除(重放失效用)。\n * @param parts - the part names to delete; unknown names are ignored.\n */\n deleteMany(parts: Iterable<PartName>): void {\n for (const p of parts) this.delete(p)\n }\n\n /** 释放全部句柄并清空(dispose)。 */\n clear(): void {\n for (const h of this.handles.values()) {\n try { this.backendRef?.release(h) } catch { /* already released */ }\n }\n this.handles.clear()\n }\n\n /**\n * 当前登记的全部 part 名(诊断/测试)。\n * @returns the registered part names.\n */\n keys(): PartName[] {\n return [...this.handles.keys()]\n }\n\n /** 登记数量(诊断/测试)。 */\n get size(): number {\n return this.handles.size\n }\n}\n"]}
@@ -13,11 +13,24 @@ import type { Font } from 'opentype.js';
13
13
  * 字体二进制加载器接口。
14
14
  *
15
15
  * 生产代码(text.ts / engrave.ts)不自己决定字体来源,
16
- * 而是通过 ensureDefaultFont() 使用注入的 FontLoader。
16
+ * 而是通过 ensureDefaultFont() / ensureFont() 使用注入的 FontLoader。
17
17
  */
18
18
  export interface FontLoader {
19
19
  /** 返回默认字体的二进制数据 */
20
20
  loadDefaultFont(): Promise<ArrayBuffer>;
21
+ /**
22
+ * 可选:按**字体族名**或**文件路径**取字体二进制。
23
+ *
24
+ * 宿主实现(Node 读磁盘/系统字体目录、浏览器按 URL 映射)决定来源;引擎核心
25
+ * 不碰 fs/fetch。返回 `null` 表示宿主无法解析该名字——调用方回退到默认字体
26
+ * (与 CadQuery/OCC `Font_FontMgr::FindFont` 找不到名字时回退默认字体的语义一致)。
27
+ *
28
+ * 未实现该方法的宿主(如浏览器)会让 `ensureFont(name)` 直接回退默认字体。
29
+ *
30
+ * @param nameOrPath - 字体族名(如 `"Arial"`)或字体文件路径
31
+ * @returns 字体字节,或 null(无法解析)
32
+ */
33
+ resolveFont?(nameOrPath: string): Promise<ArrayBuffer | null>;
21
34
  }
22
35
  /**
23
36
  * 设置当前环境的字体加载器。
@@ -61,6 +74,24 @@ export declare function ensureDefaultFont(): Promise<void>;
61
74
  * @returns opentype.js Font 对象,如果未加载则返回 undefined
62
75
  */
63
76
  export declare function getFont(fontFamily?: string): Font | undefined;
77
+ /**
78
+ * 确保某个**具名字体**可用,并返回它。
79
+ *
80
+ * 语义对齐 CadQuery 的 `font=`/`fontPath=`:
81
+ *
82
+ * - 名字已注册过(含 `loadFont(data, name)` 直接注册)⇒ 直接返回;
83
+ * - `fontPath`(已存在的文件路径)或字体族名 ⇒ 交给 `FontLoader.resolveFont` 解析,
84
+ * 解析成功后**以该名字注册**,后续同名调用命中缓存;
85
+ * - 宿主没有 `resolveFont`、或解析失败(名字不是本机已安装字体)⇒ **回退到默认字体**
86
+ * (OCC `Font_FontMgr::FindFont` 找不到字体时同样回退默认字体,不会抛错)。
87
+ *
88
+ * `null`/`undefined`/空串等价于「不指定」⇒ 默认字体。
89
+ *
90
+ * @param nameOrPath - 字体族名、字体文件路径,或 null/undefined 表示默认字体
91
+ * @returns 解析到的字体(解析不到时是默认字体)
92
+ * @throws 没有安装 FontLoader 且默认字体也未加载时
93
+ */
94
+ export declare function ensureFont(nameOrPath?: string | null): Promise<Font>;
64
95
  /**
65
96
  * 清除所有已注册的字体。
66
97
  *
@@ -1 +1 @@
1
- {"version":3,"file":"fontRegistry.d.ts","sourceRoot":"","sources":["../../../src/brep/text/fontRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAMvC;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,mBAAmB;IACnB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,CAAA;CACxC;AAID;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAE7D;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,WAAW,EACrB,UAAU,SAAY,EACtB,KAAK,UAAQ,GACZ,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAavD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,UAAU,SAAY,GAAG,IAAI,GAAG,SAAS,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAIjC"}
1
+ {"version":3,"file":"fontRegistry.d.ts","sourceRoot":"","sources":["../../../src/brep/text/fontRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAoBvC;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,mBAAmB;IACnB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,CAAA;IACvC;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;CAC9D;AAID;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAE7D;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,WAAW,EACrB,UAAU,SAAY,EACtB,KAAK,UAAQ,GACZ,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAavD;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,UAAU,SAAY,GAAG,IAAI,GAAG,SAAS,CAEhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB1E;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAIjC"}
@@ -8,7 +8,19 @@
8
8
  * - Node 测试:fontTestHelper.ts 通过 fs.readFileSync 加载
9
9
  * - 字体文件唯一真源:src/assets/fonts/OpenSans-Regular.ttf
10
10
  */
11
- import * as opentype from 'opentype.js';
11
+ import * as opentypeModule from 'opentype.js';
12
+ /**
13
+ * `opentype.js` publishes no `exports` map: it ships a UMD bundle (`main`) plus
14
+ * an ESM build (`module`). Node ESM resolves the UMD `main`, whose CommonJS
15
+ * interop exposes a namespace import as `{ default }` only — so
16
+ * `opentypeModule.parse` is undefined there — whereas bundlers (vite/vitest)
17
+ * resolve the ESM build and expose the named exports directly. Resolve once,
18
+ * here, so glyph parsing works in every host (CLI/tsx = Node ESM,
19
+ * vitest/browser = bundler).
20
+ */
21
+ const opentype = typeof opentypeModule.parse === 'function'
22
+ ? opentypeModule
23
+ : opentypeModule.default;
12
24
  const FONT_REGISTER = {};
13
25
  let activeFontLoader = null;
14
26
  /**
@@ -86,6 +98,44 @@ export async function ensureDefaultFont() {
86
98
  export function getFont(fontFamily = 'default') {
87
99
  return FONT_REGISTER[fontFamily];
88
100
  }
101
+ /**
102
+ * 确保某个**具名字体**可用,并返回它。
103
+ *
104
+ * 语义对齐 CadQuery 的 `font=`/`fontPath=`:
105
+ *
106
+ * - 名字已注册过(含 `loadFont(data, name)` 直接注册)⇒ 直接返回;
107
+ * - `fontPath`(已存在的文件路径)或字体族名 ⇒ 交给 `FontLoader.resolveFont` 解析,
108
+ * 解析成功后**以该名字注册**,后续同名调用命中缓存;
109
+ * - 宿主没有 `resolveFont`、或解析失败(名字不是本机已安装字体)⇒ **回退到默认字体**
110
+ * (OCC `Font_FontMgr::FindFont` 找不到字体时同样回退默认字体,不会抛错)。
111
+ *
112
+ * `null`/`undefined`/空串等价于「不指定」⇒ 默认字体。
113
+ *
114
+ * @param nameOrPath - 字体族名、字体文件路径,或 null/undefined 表示默认字体
115
+ * @returns 解析到的字体(解析不到时是默认字体)
116
+ * @throws 没有安装 FontLoader 且默认字体也未加载时
117
+ */
118
+ export async function ensureFont(nameOrPath) {
119
+ if (!nameOrPath) {
120
+ await ensureDefaultFont();
121
+ return getFont();
122
+ }
123
+ const already = getFont(nameOrPath);
124
+ if (already)
125
+ return already;
126
+ if (nameOrPath === 'default') {
127
+ await ensureDefaultFont();
128
+ return getFont();
129
+ }
130
+ const resolver = activeFontLoader?.resolveFont;
131
+ if (resolver) {
132
+ const data = await activeFontLoader.resolveFont(nameOrPath);
133
+ if (data)
134
+ return loadFont(data, nameOrPath, true);
135
+ }
136
+ await ensureDefaultFont();
137
+ return getFont();
138
+ }
89
139
  /**
90
140
  * 清除所有已注册的字体。
91
141
  *
@@ -1 +1 @@
1
- {"version":3,"file":"fontRegistry.js","sourceRoot":"","sources":["../../../src/brep/text/fontRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,QAAQ,MAAM,aAAa,CAAA;AAGvC,MAAM,aAAa,GAAyB,EAAE,CAAA;AAe9C,IAAI,gBAAgB,GAAsB,IAAI,CAAA;AAE9C;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,MAAyB;IACrD,gBAAgB,GAAG,MAAM,CAAA;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,gBAAgB,CAAA;AACzB,CAAC;AAED,iBAAiB;AAEjB;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,QAAqB,EACrB,UAAU,GAAG,SAAS,EACtB,KAAK,GAAG,KAAK;IAEb,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;QACxC,OAAO,aAAa,CAAC,UAAU,CAAC,CAAA;IAClC,CAAC;IAED,IAAI,IAAU,CAAA;IACd,IAAI,CAAC;QACH,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;IAC3G,CAAC;IAED,aAAa,CAAC,UAAU,CAAC,GAAG,IAAI,CAAA;IAChC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,aAAa,CAAC,SAAS,CAAC,GAAG,IAAI,CAAA;IACjC,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,OAAO,CAAC,SAAS,CAAC;QAAE,OAAM;IAE9B,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,qCAAqC;YACrC,oDAAoD;YACpD,0EAA0E,CAC3E,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,eAAe,EAAE,CAAA;IACrD,MAAM,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,UAAU,GAAG,SAAS;IAC5C,OAAO,aAAa,CAAC,UAAU,CAAC,CAAA;AAClC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU;IACxB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QAC7C,OAAO,aAAa,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC;AACH,CAAC","sourcesContent":["/**\n * 字体加载与注册 — 单一真源\n *\n * 设计原则:\n * - loadFont 只接受 ArrayBuffer(纯函数,无 fs/fetch 环境依赖)\n * - 字体二进制的获取方式由 FontLoader 接口注入(依赖反转)\n * - 浏览器:browserFontLoader.ts 通过 vite ?url + fetch 加载\n * - Node 测试:fontTestHelper.ts 通过 fs.readFileSync 加载\n * - 字体文件唯一真源:src/assets/fonts/OpenSans-Regular.ttf\n */\n\nimport * as opentype from 'opentype.js'\nimport type { Font } from 'opentype.js'\n\nconst FONT_REGISTER: Record<string, Font> = {}\n\n// ─── FontLoader 依赖注入 ───\n\n/**\n * 字体二进制加载器接口。\n *\n * 生产代码(text.ts / engrave.ts)不自己决定字体来源,\n * 而是通过 ensureDefaultFont() 使用注入的 FontLoader。\n */\nexport interface FontLoader {\n /** 返回默认字体的二进制数据 */\n loadDefaultFont(): Promise<ArrayBuffer>\n}\n\nlet activeFontLoader: FontLoader | null = null\n\n/**\n * 设置当前环境的字体加载器。\n *\n * 浏览器:由 browserFontLoader.ts 在应用启动时自动调用。\n * 测试:由 fontTestHelper.ts 在 beforeAll 中调用。\n *\n * @param loader - the font loader to install, or null to clear the active one.\n */\nexport function setFontLoader(loader: FontLoader | null): void {\n activeFontLoader = loader\n}\n\n/**\n * Get the currently-installed font loader (may be null).\n * @returns the active font loader, or null when none is set.\n */\nexport function getFontLoader(): FontLoader | null {\n return activeFontLoader\n}\n\n// ─── 核心 API ───\n\n/**\n * 加载并注册一个 OpenType/TrueType 字体。\n *\n * 纯函数:只接受 ArrayBuffer,不处理 fs/fetch。\n * 环境差异由 FontLoader 接口在外部处理。\n *\n * @param fontData 字体文件二进制数据\n * @param fontFamily 注册名(默认 'default')\n * @param force 是否覆盖已注册的同名字体\n * @returns 解析后的 opentype.js Font 对象\n */\nexport async function loadFont(\n fontData: ArrayBuffer,\n fontFamily = 'default',\n force = false,\n): Promise<Font> {\n if (!force && FONT_REGISTER[fontFamily]) {\n return FONT_REGISTER[fontFamily]\n }\n\n let font: Font\n try {\n font = opentype.parse(fontData)\n } catch (e) {\n throw new Error(`Failed to parse font data: ${e instanceof Error ? e.message : String(e)}`, { cause: e })\n }\n\n FONT_REGISTER[fontFamily] = font\n if (!FONT_REGISTER['default']) {\n FONT_REGISTER['default'] = font\n }\n\n return font\n}\n\n/**\n * 确保默认字体已加载(惰性加载)。\n *\n * 使用注入的 FontLoader 获取字体二进制,然后调用 loadFont 解析注册。\n * 如果字体已加载(getFont('default') 返回非 undefined),直接返回。\n *\n * @throws 如果没有设置 FontLoader 且字体尚未加载\n */\nexport async function ensureDefaultFont(): Promise<void> {\n if (getFont('default')) return\n\n if (!activeFontLoader) {\n throw new Error(\n '[fontRegistry] No font loader set. ' +\n 'Call setFontLoader() before using text functions. ' +\n 'Browser: import browserFontLoader.ts; Node tests: use fontTestHelper.ts.',\n )\n }\n\n const data = await activeFontLoader.loadDefaultFont()\n await loadFont(data, 'default', true)\n}\n\n/**\n * 获取已注册的字体。\n *\n * @param fontFamily 注册名(默认 'default')\n * @returns opentype.js Font 对象,如果未加载则返回 undefined\n */\nexport function getFont(fontFamily = 'default'): Font | undefined {\n return FONT_REGISTER[fontFamily]\n}\n\n/**\n * 清除所有已注册的字体。\n *\n * 主要用于测试:在注入失败 loader 前,先清除已加载的字体,\n * 确保 ensureDefaultFont() 会重新调用 loader。\n */\nexport function clearFonts(): void {\n for (const key of Object.keys(FONT_REGISTER)) {\n delete FONT_REGISTER[key]\n }\n}\n"]}
1
+ {"version":3,"file":"fontRegistry.js","sourceRoot":"","sources":["../../../src/brep/text/fontRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 字体加载与注册 — 单一真源\n *\n * 设计原则:\n * - loadFont 只接受 ArrayBuffer(纯函数,无 fs/fetch 环境依赖)\n * - 字体二进制的获取方式由 FontLoader 接口注入(依赖反转)\n * - 浏览器:browserFontLoader.ts 通过 vite ?url + fetch 加载\n * - Node 测试:fontTestHelper.ts 通过 fs.readFileSync 加载\n * - 字体文件唯一真源:src/assets/fonts/OpenSans-Regular.ttf\n */\n\nimport * as opentypeModule from 'opentype.js'\nimport type { Font } from 'opentype.js'\n\n/**\n * `opentype.js` publishes no `exports` map: it ships a UMD bundle (`main`) plus\n * an ESM build (`module`). Node ESM resolves the UMD `main`, whose CommonJS\n * interop exposes a namespace import as `{ default }` only — so\n * `opentypeModule.parse` is undefined there — whereas bundlers (vite/vitest)\n * resolve the ESM build and expose the named exports directly. Resolve once,\n * here, so glyph parsing works in every host (CLI/tsx = Node ESM,\n * vitest/browser = bundler).\n */\nconst opentype: typeof opentypeModule =\n typeof (opentypeModule as { parse?: unknown }).parse === 'function'\n ? opentypeModule\n : (opentypeModule as unknown as { default: typeof opentypeModule }).default\n\nconst FONT_REGISTER: Record<string, Font> = {}\n\n// ─── FontLoader 依赖注入 ───\n\n/**\n * 字体二进制加载器接口。\n *\n * 生产代码(text.ts / engrave.ts)不自己决定字体来源,\n * 而是通过 ensureDefaultFont() / ensureFont() 使用注入的 FontLoader。\n */\nexport interface FontLoader {\n /** 返回默认字体的二进制数据 */\n loadDefaultFont(): Promise<ArrayBuffer>\n /**\n * 可选:按**字体族名**或**文件路径**取字体二进制。\n *\n * 宿主实现(Node 读磁盘/系统字体目录、浏览器按 URL 映射)决定来源;引擎核心\n * 不碰 fs/fetch。返回 `null` 表示宿主无法解析该名字——调用方回退到默认字体\n * (与 CadQuery/OCC `Font_FontMgr::FindFont` 找不到名字时回退默认字体的语义一致)。\n *\n * 未实现该方法的宿主(如浏览器)会让 `ensureFont(name)` 直接回退默认字体。\n *\n * @param nameOrPath - 字体族名(如 `\"Arial\"`)或字体文件路径\n * @returns 字体字节,或 null(无法解析)\n */\n resolveFont?(nameOrPath: string): Promise<ArrayBuffer | null>\n}\n\nlet activeFontLoader: FontLoader | null = null\n\n/**\n * 设置当前环境的字体加载器。\n *\n * 浏览器:由 browserFontLoader.ts 在应用启动时自动调用。\n * 测试:由 fontTestHelper.ts 在 beforeAll 中调用。\n *\n * @param loader - the font loader to install, or null to clear the active one.\n */\nexport function setFontLoader(loader: FontLoader | null): void {\n activeFontLoader = loader\n}\n\n/**\n * Get the currently-installed font loader (may be null).\n * @returns the active font loader, or null when none is set.\n */\nexport function getFontLoader(): FontLoader | null {\n return activeFontLoader\n}\n\n// ─── 核心 API ───\n\n/**\n * 加载并注册一个 OpenType/TrueType 字体。\n *\n * 纯函数:只接受 ArrayBuffer,不处理 fs/fetch。\n * 环境差异由 FontLoader 接口在外部处理。\n *\n * @param fontData 字体文件二进制数据\n * @param fontFamily 注册名(默认 'default')\n * @param force 是否覆盖已注册的同名字体\n * @returns 解析后的 opentype.js Font 对象\n */\nexport async function loadFont(\n fontData: ArrayBuffer,\n fontFamily = 'default',\n force = false,\n): Promise<Font> {\n if (!force && FONT_REGISTER[fontFamily]) {\n return FONT_REGISTER[fontFamily]\n }\n\n let font: Font\n try {\n font = opentype.parse(fontData)\n } catch (e) {\n throw new Error(`Failed to parse font data: ${e instanceof Error ? e.message : String(e)}`, { cause: e })\n }\n\n FONT_REGISTER[fontFamily] = font\n if (!FONT_REGISTER['default']) {\n FONT_REGISTER['default'] = font\n }\n\n return font\n}\n\n/**\n * 确保默认字体已加载(惰性加载)。\n *\n * 使用注入的 FontLoader 获取字体二进制,然后调用 loadFont 解析注册。\n * 如果字体已加载(getFont('default') 返回非 undefined),直接返回。\n *\n * @throws 如果没有设置 FontLoader 且字体尚未加载\n */\nexport async function ensureDefaultFont(): Promise<void> {\n if (getFont('default')) return\n\n if (!activeFontLoader) {\n throw new Error(\n '[fontRegistry] No font loader set. ' +\n 'Call setFontLoader() before using text functions. ' +\n 'Browser: import browserFontLoader.ts; Node tests: use fontTestHelper.ts.',\n )\n }\n\n const data = await activeFontLoader.loadDefaultFont()\n await loadFont(data, 'default', true)\n}\n\n/**\n * 获取已注册的字体。\n *\n * @param fontFamily 注册名(默认 'default')\n * @returns opentype.js Font 对象,如果未加载则返回 undefined\n */\nexport function getFont(fontFamily = 'default'): Font | undefined {\n return FONT_REGISTER[fontFamily]\n}\n\n/**\n * 确保某个**具名字体**可用,并返回它。\n *\n * 语义对齐 CadQuery 的 `font=`/`fontPath=`:\n *\n * - 名字已注册过(含 `loadFont(data, name)` 直接注册)⇒ 直接返回;\n * - `fontPath`(已存在的文件路径)或字体族名 ⇒ 交给 `FontLoader.resolveFont` 解析,\n * 解析成功后**以该名字注册**,后续同名调用命中缓存;\n * - 宿主没有 `resolveFont`、或解析失败(名字不是本机已安装字体)⇒ **回退到默认字体**\n * (OCC `Font_FontMgr::FindFont` 找不到字体时同样回退默认字体,不会抛错)。\n *\n * `null`/`undefined`/空串等价于「不指定」⇒ 默认字体。\n *\n * @param nameOrPath - 字体族名、字体文件路径,或 null/undefined 表示默认字体\n * @returns 解析到的字体(解析不到时是默认字体)\n * @throws 没有安装 FontLoader 且默认字体也未加载时\n */\nexport async function ensureFont(nameOrPath?: string | null): Promise<Font> {\n if (!nameOrPath) {\n await ensureDefaultFont()\n return getFont()!\n }\n\n const already = getFont(nameOrPath)\n if (already) return already\n\n if (nameOrPath === 'default') {\n await ensureDefaultFont()\n return getFont()!\n }\n\n const resolver = activeFontLoader?.resolveFont\n if (resolver) {\n const data = await activeFontLoader!.resolveFont!(nameOrPath)\n if (data) return loadFont(data, nameOrPath, true)\n }\n\n await ensureDefaultFont()\n return getFont()!\n}\n\n/**\n * 清除所有已注册的字体。\n *\n * 主要用于测试:在注入失败 loader 前,先清除已加载的字体,\n * 确保 ensureDefaultFont() 会重新调用 loader。\n */\nexport function clearFonts(): void {\n for (const key of Object.keys(FONT_REGISTER)) {\n delete FONT_REGISTER[key]\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"text-to-solid.d.ts","sourceRoot":"","sources":["../../../src/brep/text/text-to-solid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAmDzD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACf,GACL,UAAU,EAAE,CAwHd;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IACP,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;CACd,GACA,UAAU,CAqCZ"}
1
+ {"version":3,"file":"text-to-solid.d.ts","sourceRoot":"","sources":["../../../src/brep/text/text-to-solid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAwDzD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACf,GACL,UAAU,EAAE,CAwHd;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IACP,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;CACd,GACA,UAAU,CAqCZ"}
@@ -17,10 +17,15 @@
17
17
  * - Z (closePath) → 闭合 wire
18
18
  */
19
19
  import { getFont } from './fontRegistry.js';
20
- /** 将 opentype.js 坐标转为 OCCT 点(XY 平面,Z=0) */
20
+ /**
21
+ * 将 opentype.js 坐标转为 OCCT 点(XY 平面,Z=0)。
22
+ *
23
+ * opentype.js 的 path 是 **y 向下**(canvas 约定:字形主体在负 y),OCCT 是
24
+ * **y 向上**,故这里翻转 y —— 与 `../svg/svg-to-solid.ts` 的 `flipY`
25
+ * (SVG Y-down → OCCT Y-up)同一约定。X 不翻转,文字从左到右。
26
+ */
21
27
  function toPt(x, y) {
22
- // 与 mesh 路径一致:不翻转 X 轴,文字从左到右
23
- return { x, y, z: 0 };
28
+ return { x, y: -y, z: 0 };
24
29
  }
25
30
  /**
26
31
  * 将 opentype.js 二次贝塞尔转换为三次贝塞尔的控制点。
@@ -1 +1 @@
1
- {"version":3,"file":"text-to-solid.js","sourceRoot":"","sources":["../../../src/brep/text/text-to-solid.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 文字 → OCCT wire/face 转换\n *\n * 适配自 brepjs `src/text/text-to-solid.ts`。\n * 保留文件名和核心算法,适配本项目的 occt-wasm API。\n *\n * 与 brepjs 的差异:\n * - brepjs 用 BlueprintSketcher 构造 wire → 本项目直接用 kernel.makeLineEdge / makeBezierEdge\n * - brepjs 用 organiseBlueprints 处理孔洞 → 本项目用 makeFace 直接构建(OCCT 自动处理内孔)\n * - brepjs 用 sketchOnPlane → 本项目直接在 XY 平面构造然后按需变换\n *\n * opentype.js 路径命令 → OCCT edge 映射:\n * - M (moveTo) → 开始新子路径\n * - L (lineTo) → kernel.makeLineEdge(prev, curr)\n * - C (cubicBezier) → kernel.makeBezierEdge([p0, cp1, cp2, p1])\n * - Q (quadraticBezier) → 转换为三次贝塞尔后用 makeBezierEdge\n * - Z (closePath) → 闭合 wire\n */\n\nimport type { BrepHandle } from '../engine/types'\nimport type { BrepEngineApi } from '../engine/primitives'\nimport type { Font } from 'opentype.js'\nimport type { PathCommand } from 'opentype.js'\nimport { getFont } from './fontRegistry'\n\n/** 点坐标(OCCT 格式) */\ninterface Pt { x: number; y: number; z: number }\n\n/** 将 opentype.js 坐标转为 OCCT 点(XY 平面,Z=0) */\nfunction toPt(x: number, y: number): Pt {\n // 与 mesh 路径一致:不翻转 X 轴,文字从左到右\n return { x, y, z: 0 }\n}\n\n/**\n * 将 opentype.js 二次贝塞尔转换为三次贝塞尔的控制点。\n *\n * Q: P0 → P1 (cp) → P2\n * C: P0 → C1 → C2 → P2\n * C1 = P0 + 2/3 * (P1 - P0) = (2*P1 + P0) / 3\n * C2 = P2 + 2/3 * (P1 - P2) = (2*P1 + P2) / 3\n */\nfunction quadToCubic(\n p0: Pt, cp: Pt, p2: Pt,\n): [Pt, Pt] {\n const c1 = {\n x: (2 * cp.x + p0.x) / 3,\n y: (2 * cp.y + p0.y) / 3,\n z: 0,\n }\n const c2 = {\n x: (2 * cp.x + p2.x) / 3,\n y: (2 * cp.y + p2.y) / 3,\n z: 0,\n }\n return [c1, c2]\n}\n\n/**\n * 用 OCCT 贝塞尔边构造一段三次贝塞尔曲线。\n *\n * 三次贝塞尔曲线有 4 个控制点:P0, C1, C2, P1。\n * occt-wasm 的 makeBezierEdge 接受 Vec3[] 控制点数组。\n */\nfunction makeBezierFromPoints(\n kernel: BrepEngineApi,\n p0: Pt, c1: Pt, c2: Pt, p1: Pt,\n): BrepHandle {\n return kernel.makeBezierEdge([p0, c1, c2, p1])\n}\n\n/**\n * 将文字转换为 OCCT wire 数组(每个闭合轮廓一个 wire)。\n *\n * @param kernel OCCT 内核\n * @param text 文字字符串\n * @param options 配置选项\n * @returns BrepHandle 数组(每个是一个闭合 wire)\n */\nexport function textBlueprints(\n kernel: BrepEngineApi,\n text: string,\n options: {\n startX?: number\n startY?: number\n fontSize?: number\n fontFamily?: string\n } = {},\n): BrepHandle[] {\n const { startX = 0, startY = 0, fontSize = 16, fontFamily = 'default' } = options\n\n let font: Font | undefined = getFont(fontFamily)\n if (!font) font = getFont()\n if (!font) {\n throw new Error('[textBlueprints] No fonts loaded. Call loadFont() before using text functions.')\n }\n\n // 检查缺字形(CJK 字符在 OpenSans Regular 中没有对应字形)\n for (const ch of text) {\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') continue\n const glyph = font.charToGlyph(ch)\n if (glyph.index === 0) {\n throw new Error(\n `[textBlueprints] Character \"${ch}\" (U+${ch.codePointAt(0)!.toString(16).toUpperCase()}) ` +\n `not found in font. If it is a CJK character, a CJK font must be loaded.`,\n )\n }\n }\n\n // 获取文字路径\n const path = font.getPath(text, startX, startY, fontSize)\n const commands = path.commands as PathCommand[]\n\n const wires: BrepHandle[] = []\n const allEdges: BrepHandle[] = []\n\n let currentEdges: BrepHandle[] = []\n let lastPt: Pt | null = null\n let subpathStart: Pt | null = null\n\n for (const cmd of commands) {\n switch (cmd.type) {\n case 'M': {\n // 开始新子路径 — 如果当前有 edges,先构建 wire\n if (currentEdges.length > 0) {\n const wire = kernel.makeWire(currentEdges)\n wires.push(wire)\n allEdges.push(...currentEdges)\n currentEdges = []\n }\n lastPt = toPt(cmd.x!, cmd.y!)\n subpathStart = lastPt\n break\n }\n case 'L': {\n if (!lastPt) {\n lastPt = toPt(cmd.x!, cmd.y!)\n subpathStart = lastPt\n break\n }\n const curr = toPt(cmd.x!, cmd.y!)\n // 跳过零长度边\n if (Math.abs(curr.x - lastPt.x) > 1e-9 || Math.abs(curr.y - lastPt.y) > 1e-9) {\n const edge = kernel.makeLineEdge(lastPt, curr)\n currentEdges.push(edge)\n allEdges.push(edge)\n }\n lastPt = curr\n break\n }\n case 'Q': {\n if (!lastPt) break\n const cp = toPt(cmd.x1!, cmd.y1!)\n const endPt = toPt(cmd.x!, cmd.y!)\n // 转换为三次贝塞尔\n const [c1, c2] = quadToCubic(lastPt, cp, endPt)\n const edge = makeBezierFromPoints(kernel, lastPt, c1, c2, endPt)\n currentEdges.push(edge)\n allEdges.push(edge)\n lastPt = endPt\n break\n }\n case 'C': {\n if (!lastPt) break\n const c1 = toPt(cmd.x1!, cmd.y1!)\n const c2 = toPt(cmd.x2!, cmd.y2!)\n const endPt = toPt(cmd.x!, cmd.y!)\n const edge = makeBezierFromPoints(kernel, lastPt, c1, c2, endPt)\n currentEdges.push(edge)\n allEdges.push(edge)\n lastPt = endPt\n break\n }\n case 'Z': {\n // 闭合 — 如果有起点,添加闭合边\n if (subpathStart && lastPt &&\n (Math.abs(subpathStart.x - lastPt.x) > 1e-9 || Math.abs(subpathStart.y - lastPt.y) > 1e-9)) {\n const edge = kernel.makeLineEdge(lastPt, subpathStart)\n currentEdges.push(edge)\n allEdges.push(edge)\n }\n // 构建 wire\n if (currentEdges.length > 0) {\n const wire = kernel.makeWire(currentEdges)\n wires.push(wire)\n allEdges.push(...currentEdges)\n currentEdges = []\n }\n lastPt = null\n subpathStart = null\n break\n }\n }\n }\n\n // 处理最后一个未闭合的子路径\n if (currentEdges.length > 0) {\n const wire = kernel.makeWire(currentEdges)\n wires.push(wire)\n allEdges.push(...currentEdges)\n }\n\n // 释放所有边(wire 已共享 TShape)\n for (const e of allEdges) {\n kernel.release(e)\n }\n\n return wires\n}\n\n/**\n * 将文字转换为 OCCT 3D solid(face → extrude → fuse)。\n *\n * @param kernel OCCT 内核\n * @param text 文字字符串\n * @param options 配置选项\n * @returns BrepHandle(合并后的 solid)\n */\nexport function textToSolid(\n kernel: BrepEngineApi,\n text: string,\n options: {\n fontSize?: number\n fontFamily?: string\n depth: number\n },\n): BrepHandle {\n const { fontSize = 16, fontFamily = 'default', depth } = options\n\n const wires = textBlueprints(kernel, text, { fontSize, fontFamily })\n\n if (wires.length === 0) {\n throw new Error('[textToSolid] no wires generated from text')\n }\n\n // 为每个 wire 创建 face → extrude\n const solids: BrepHandle[] = []\n for (const wire of wires) {\n try {\n const face = kernel.makeFace(wire)\n const solid = kernel.extrude(face, 0, 0, depth)\n kernel.release(face)\n solids.push(solid)\n } catch {\n // 某些 wire 可能无法构建 face(如开放线框)— 跳过\n }\n kernel.release(wire)\n }\n\n if (solids.length === 0) {\n throw new Error('[textToSolid] no solids generated from wires')\n }\n\n // Fuse 所有 solid\n let result = solids[0]\n for (let i = 1; i < solids.length; i++) {\n const prev = result\n result = kernel.fuse(prev, solids[i])\n kernel.release(prev)\n kernel.release(solids[i])\n }\n\n return result\n}\n"]}
1
+ {"version":3,"file":"text-to-solid.js","sourceRoot":"","sources":["../../../src/brep/text/text-to-solid.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 文字 → OCCT wire/face 转换\n *\n * 适配自 brepjs `src/text/text-to-solid.ts`。\n * 保留文件名和核心算法,适配本项目的 occt-wasm API。\n *\n * 与 brepjs 的差异:\n * - brepjs 用 BlueprintSketcher 构造 wire → 本项目直接用 kernel.makeLineEdge / makeBezierEdge\n * - brepjs 用 organiseBlueprints 处理孔洞 → 本项目用 makeFace 直接构建(OCCT 自动处理内孔)\n * - brepjs 用 sketchOnPlane → 本项目直接在 XY 平面构造然后按需变换\n *\n * opentype.js 路径命令 → OCCT edge 映射:\n * - M (moveTo) → 开始新子路径\n * - L (lineTo) → kernel.makeLineEdge(prev, curr)\n * - C (cubicBezier) → kernel.makeBezierEdge([p0, cp1, cp2, p1])\n * - Q (quadraticBezier) → 转换为三次贝塞尔后用 makeBezierEdge\n * - Z (closePath) → 闭合 wire\n */\n\nimport type { BrepHandle } from '../engine/types'\nimport type { BrepEngineApi } from '../engine/primitives'\nimport type { Font } from 'opentype.js'\nimport type { PathCommand } from 'opentype.js'\nimport { getFont } from './fontRegistry'\n\n/** 点坐标(OCCT 格式) */\ninterface Pt { x: number; y: number; z: number }\n\n/**\n * 将 opentype.js 坐标转为 OCCT 点(XY 平面,Z=0)。\n *\n * opentype.js 的 path 是 **y 向下**(canvas 约定:字形主体在负 y),OCCT 是\n * **y 向上**,故这里翻转 y —— 与 `../svg/svg-to-solid.ts` 的 `flipY`\n * (SVG Y-down → OCCT Y-up)同一约定。X 不翻转,文字从左到右。\n */\nfunction toPt(x: number, y: number): Pt {\n return { x, y: -y, z: 0 }\n}\n\n/**\n * 将 opentype.js 二次贝塞尔转换为三次贝塞尔的控制点。\n *\n * Q: P0 → P1 (cp) → P2\n * C: P0 → C1 → C2 → P2\n * C1 = P0 + 2/3 * (P1 - P0) = (2*P1 + P0) / 3\n * C2 = P2 + 2/3 * (P1 - P2) = (2*P1 + P2) / 3\n */\nfunction quadToCubic(\n p0: Pt, cp: Pt, p2: Pt,\n): [Pt, Pt] {\n const c1 = {\n x: (2 * cp.x + p0.x) / 3,\n y: (2 * cp.y + p0.y) / 3,\n z: 0,\n }\n const c2 = {\n x: (2 * cp.x + p2.x) / 3,\n y: (2 * cp.y + p2.y) / 3,\n z: 0,\n }\n return [c1, c2]\n}\n\n/**\n * 用 OCCT 贝塞尔边构造一段三次贝塞尔曲线。\n *\n * 三次贝塞尔曲线有 4 个控制点:P0, C1, C2, P1。\n * occt-wasm 的 makeBezierEdge 接受 Vec3[] 控制点数组。\n */\nfunction makeBezierFromPoints(\n kernel: BrepEngineApi,\n p0: Pt, c1: Pt, c2: Pt, p1: Pt,\n): BrepHandle {\n return kernel.makeBezierEdge([p0, c1, c2, p1])\n}\n\n/**\n * 将文字转换为 OCCT wire 数组(每个闭合轮廓一个 wire)。\n *\n * @param kernel OCCT 内核\n * @param text 文字字符串\n * @param options 配置选项\n * @returns BrepHandle 数组(每个是一个闭合 wire)\n */\nexport function textBlueprints(\n kernel: BrepEngineApi,\n text: string,\n options: {\n startX?: number\n startY?: number\n fontSize?: number\n fontFamily?: string\n } = {},\n): BrepHandle[] {\n const { startX = 0, startY = 0, fontSize = 16, fontFamily = 'default' } = options\n\n let font: Font | undefined = getFont(fontFamily)\n if (!font) font = getFont()\n if (!font) {\n throw new Error('[textBlueprints] No fonts loaded. Call loadFont() before using text functions.')\n }\n\n // 检查缺字形(CJK 字符在 OpenSans Regular 中没有对应字形)\n for (const ch of text) {\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') continue\n const glyph = font.charToGlyph(ch)\n if (glyph.index === 0) {\n throw new Error(\n `[textBlueprints] Character \"${ch}\" (U+${ch.codePointAt(0)!.toString(16).toUpperCase()}) ` +\n `not found in font. If it is a CJK character, a CJK font must be loaded.`,\n )\n }\n }\n\n // 获取文字路径\n const path = font.getPath(text, startX, startY, fontSize)\n const commands = path.commands as PathCommand[]\n\n const wires: BrepHandle[] = []\n const allEdges: BrepHandle[] = []\n\n let currentEdges: BrepHandle[] = []\n let lastPt: Pt | null = null\n let subpathStart: Pt | null = null\n\n for (const cmd of commands) {\n switch (cmd.type) {\n case 'M': {\n // 开始新子路径 — 如果当前有 edges,先构建 wire\n if (currentEdges.length > 0) {\n const wire = kernel.makeWire(currentEdges)\n wires.push(wire)\n allEdges.push(...currentEdges)\n currentEdges = []\n }\n lastPt = toPt(cmd.x!, cmd.y!)\n subpathStart = lastPt\n break\n }\n case 'L': {\n if (!lastPt) {\n lastPt = toPt(cmd.x!, cmd.y!)\n subpathStart = lastPt\n break\n }\n const curr = toPt(cmd.x!, cmd.y!)\n // 跳过零长度边\n if (Math.abs(curr.x - lastPt.x) > 1e-9 || Math.abs(curr.y - lastPt.y) > 1e-9) {\n const edge = kernel.makeLineEdge(lastPt, curr)\n currentEdges.push(edge)\n allEdges.push(edge)\n }\n lastPt = curr\n break\n }\n case 'Q': {\n if (!lastPt) break\n const cp = toPt(cmd.x1!, cmd.y1!)\n const endPt = toPt(cmd.x!, cmd.y!)\n // 转换为三次贝塞尔\n const [c1, c2] = quadToCubic(lastPt, cp, endPt)\n const edge = makeBezierFromPoints(kernel, lastPt, c1, c2, endPt)\n currentEdges.push(edge)\n allEdges.push(edge)\n lastPt = endPt\n break\n }\n case 'C': {\n if (!lastPt) break\n const c1 = toPt(cmd.x1!, cmd.y1!)\n const c2 = toPt(cmd.x2!, cmd.y2!)\n const endPt = toPt(cmd.x!, cmd.y!)\n const edge = makeBezierFromPoints(kernel, lastPt, c1, c2, endPt)\n currentEdges.push(edge)\n allEdges.push(edge)\n lastPt = endPt\n break\n }\n case 'Z': {\n // 闭合 — 如果有起点,添加闭合边\n if (subpathStart && lastPt &&\n (Math.abs(subpathStart.x - lastPt.x) > 1e-9 || Math.abs(subpathStart.y - lastPt.y) > 1e-9)) {\n const edge = kernel.makeLineEdge(lastPt, subpathStart)\n currentEdges.push(edge)\n allEdges.push(edge)\n }\n // 构建 wire\n if (currentEdges.length > 0) {\n const wire = kernel.makeWire(currentEdges)\n wires.push(wire)\n allEdges.push(...currentEdges)\n currentEdges = []\n }\n lastPt = null\n subpathStart = null\n break\n }\n }\n }\n\n // 处理最后一个未闭合的子路径\n if (currentEdges.length > 0) {\n const wire = kernel.makeWire(currentEdges)\n wires.push(wire)\n allEdges.push(...currentEdges)\n }\n\n // 释放所有边(wire 已共享 TShape)\n for (const e of allEdges) {\n kernel.release(e)\n }\n\n return wires\n}\n\n/**\n * 将文字转换为 OCCT 3D solid(face → extrude → fuse)。\n *\n * @param kernel OCCT 内核\n * @param text 文字字符串\n * @param options 配置选项\n * @returns BrepHandle(合并后的 solid)\n */\nexport function textToSolid(\n kernel: BrepEngineApi,\n text: string,\n options: {\n fontSize?: number\n fontFamily?: string\n depth: number\n },\n): BrepHandle {\n const { fontSize = 16, fontFamily = 'default', depth } = options\n\n const wires = textBlueprints(kernel, text, { fontSize, fontFamily })\n\n if (wires.length === 0) {\n throw new Error('[textToSolid] no wires generated from text')\n }\n\n // 为每个 wire 创建 face → extrude\n const solids: BrepHandle[] = []\n for (const wire of wires) {\n try {\n const face = kernel.makeFace(wire)\n const solid = kernel.extrude(face, 0, 0, depth)\n kernel.release(face)\n solids.push(solid)\n } catch {\n // 某些 wire 可能无法构建 face(如开放线框)— 跳过\n }\n kernel.release(wire)\n }\n\n if (solids.length === 0) {\n throw new Error('[textToSolid] no solids generated from wires')\n }\n\n // Fuse 所有 solid\n let result = solids[0]\n for (let i = 1; i < solids.length; i++) {\n const prev = result\n result = kernel.fuse(prev, solids[i])\n kernel.release(prev)\n kernel.release(solids[i])\n }\n\n return result\n}\n"]}
@@ -20,9 +20,18 @@
20
20
  */
21
21
  import { type BrepKitKernel } from './brepkitWasm.js';
22
22
  import type { BrepEngineApi } from '../brep/engine/primitives.js';
23
- /** brepkit 适配器返回类型:BrepEngineApi + brepkit 专属诊断。 */
23
+ /** brepkit 适配器返回类型:BrepEngineApi + brepkit 专属诊断 + 网格实体原语。 */
24
24
  type BrepkitEngineExtras = BrepEngineApi & {
25
25
  getMeshFallbackCount(): number;
26
+ /**
27
+ * 网格实体原语(`brep/mesh-solid.ts` 的 `MeshSolidKernelOps`)。
28
+ *
29
+ * 为什么放在适配器而不是 L1 契约面:`weldShellsAndFaces` / `unifyFaces` 是
30
+ * brepkit **内核私有**的缝合/合并原语(L1 `BrepEngineApi` 没有对应概念——
31
+ * OCCT 侧用 `sew`+`unifySameDomain` 才有等价语义,形态不同)。挂在适配器
32
+ * 返回对象上,网格后端(`MeshSolidBackend`)经端口取用,契约面保持干净。
33
+ */
34
+ meshSolid: import('../brep/mesh-solid.js').MeshSolidKernelOps;
26
35
  };
27
36
  /**
28
37
  * 创建 brepkit BrepEngineApi 实现(L1 契约显式对象字面量)。
@@ -41,7 +50,14 @@ export declare function createBrepkitPrimitives(): Promise<BrepkitEngineExtras>;
41
50
  * @returns the live brepkit wasm kernel singleton.
42
51
  */
43
52
  export declare function getBrepkitKernel(): BrepKitKernel;
44
- /** 释放内核单例(测试收尾用;宿主常驻不需调用)。 */
53
+ /**
54
+ * 释放内核单例(测试收尾用;宿主常驻不需调用)。
55
+ *
56
+ * GOTCHA(2026-10-01 修复):旧实现只 `free()` 内核、**不重置** brepkitWasm.ts 里
57
+ * 缓存的 `initPromise`,也不丢 memo 化的原语对象 → 第二次 `createBrepkitPrimitives()`
58
+ * 拿到**已释放**的内核,随后一切内核调用报 `null pointer passed to rust`
59
+ * (实测:`BrepKernel.makeBox`)。现在三样一起清:内核、initPromise、memo 原语。
60
+ */
45
61
  export declare function disposeBrepkit(): void;
46
62
  /** brepkit 适配器原语集类型(BrepEngineApi + brepkit 专属诊断 getMeshFallbackCount)。 */
47
63
  export type BrepkitPrimitives = Awaited<ReturnType<typeof createBrepkitPrimitives>>;
@@ -1 +1 @@
1
- {"version":3,"file":"brepkitKernel.d.ts","sourceRoot":"","sources":["../../src/brepkit-kernel/brepkitKernel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAGnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAwI9D,oDAAoD;AACpD,KAAK,mBAAmB,GAAG,aAAa,GAAG;IAAE,oBAAoB,IAAI,MAAM,CAAA;CAAE,CAAA;AAuC7E;;;;;GAKG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,mBAAmB,CAAC,CA65B5E;AAoDD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAKhD;AAED,8BAA8B;AAC9B,wBAAgB,cAAc,IAAI,IAAI,CAKrC;AAED,2EAA2E;AAC3E,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"brepkitKernel.d.ts","sourceRoot":"","sources":["../../src/brepkit-kernel/brepkitKernel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAqC,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAGrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAoO9D,6DAA6D;AAC7D,KAAK,mBAAmB,GAAG,aAAa,GAAG;IACzC,oBAAoB,IAAI,MAAM,CAAA;IAC9B;;;;;;;OAOG;IACH,SAAS,EAAE,OAAO,oBAAoB,EAAE,kBAAkB,CAAA;CAC3D,CAAA;AAkDD;;;;;GAKG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,mBAAmB,CAAC,CA6mC5E;AAwDD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAKhD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAQrC;AAED,2EAA2E;AAC3E,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC,CAAA"}