@faicad/faijs 0.14.1 → 0.16.0

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 (338) hide show
  1. package/dist/api/api-namespace.d.ts +7 -0
  2. package/dist/api/api-namespace.d.ts.map +1 -1
  3. package/dist/api/api-namespace.js +23 -22
  4. package/dist/api/api-namespace.js.map +1 -1
  5. package/dist/api/boolean.d.ts.map +1 -1
  6. package/dist/api/boolean.js +26 -8
  7. package/dist/api/boolean.js.map +1 -1
  8. package/dist/api/chamfer.d.ts.map +1 -1
  9. package/dist/api/chamfer.js +4 -1
  10. package/dist/api/chamfer.js.map +1 -1
  11. package/dist/api/generated/cad/script-face.d.ts +1 -1
  12. package/dist/api/generated/cad/script-face.d.ts.map +1 -1
  13. package/dist/api/generated/cad/script-face.js +1 -2
  14. package/dist/api/generated/cad/script-face.js.map +1 -1
  15. package/dist/api/generated/operations.js +16 -16
  16. package/dist/api/generated/operations.js.map +1 -1
  17. package/dist/api/generated/script-face-manifest.d.ts.map +1 -1
  18. package/dist/api/generated/script-face-manifest.js +0 -1
  19. package/dist/api/generated/script-face-manifest.js.map +1 -1
  20. package/dist/api/generated/script-face.d.ts +1 -4
  21. package/dist/api/generated/script-face.d.ts.map +1 -1
  22. package/dist/api/generated/script-face.js +2 -3
  23. package/dist/api/generated/script-face.js.map +1 -1
  24. package/dist/api/generated/sketching.js +1 -1
  25. package/dist/api/generated/sketching.js.map +1 -1
  26. package/dist/api/generated/topology.d.ts +0 -8
  27. package/dist/api/generated/topology.d.ts.map +1 -1
  28. package/dist/api/generated/topology.js +19 -26
  29. package/dist/api/generated/topology.js.map +1 -1
  30. package/dist/api/index.d.ts +1 -10
  31. package/dist/api/index.d.ts.map +1 -1
  32. package/dist/api/index.js +10 -18
  33. package/dist/api/index.js.map +1 -1
  34. package/dist/api/internal/compat-projection.d.ts +3 -1
  35. package/dist/api/internal/compat-projection.d.ts.map +1 -1
  36. package/dist/api/internal/compat-projection.js +8 -5
  37. package/dist/api/internal/compat-projection.js.map +1 -1
  38. package/dist/api/internal/replica-role-table.d.ts +36 -0
  39. package/dist/api/internal/replica-role-table.d.ts.map +1 -0
  40. package/dist/api/internal/replica-role-table.js +73 -0
  41. package/dist/api/internal/replica-role-table.js.map +1 -0
  42. package/dist/api/internal/result-unwrap.d.ts +3 -1
  43. package/dist/api/internal/result-unwrap.d.ts.map +1 -1
  44. package/dist/api/internal/result-unwrap.js +2 -2
  45. package/dist/api/internal/result-unwrap.js.map +1 -1
  46. package/dist/api/occt-kernel-bridge.d.ts +105 -27
  47. package/dist/api/occt-kernel-bridge.d.ts.map +1 -1
  48. package/dist/api/occt-kernel-bridge.js +255 -41
  49. package/dist/api/occt-kernel-bridge.js.map +1 -1
  50. package/dist/api/pattern.d.ts.map +1 -1
  51. package/dist/api/pattern.js +25 -61
  52. package/dist/api/pattern.js.map +1 -1
  53. package/dist/api/replicate.d.ts +145 -0
  54. package/dist/api/replicate.d.ts.map +1 -0
  55. package/dist/api/replicate.js +351 -0
  56. package/dist/api/replicate.js.map +1 -0
  57. package/dist/api/revolve.d.ts +36 -0
  58. package/dist/api/revolve.d.ts.map +1 -0
  59. package/dist/api/revolve.js +165 -0
  60. package/dist/api/revolve.js.map +1 -0
  61. package/dist/api/surface/arg-spec.d.ts +8 -0
  62. package/dist/api/surface/arg-spec.d.ts.map +1 -1
  63. package/dist/api/surface/arg-spec.js +37 -36
  64. package/dist/api/surface/arg-spec.js.map +1 -1
  65. package/dist/api/surface/projection-overrides.d.ts.map +1 -1
  66. package/dist/api/surface/projection-overrides.js +6 -0
  67. package/dist/api/surface/projection-overrides.js.map +1 -1
  68. package/dist/boolean/deriveNormals.d.ts +5 -4
  69. package/dist/boolean/deriveNormals.d.ts.map +1 -1
  70. package/dist/boolean/deriveNormals.js +24 -7
  71. package/dist/boolean/deriveNormals.js.map +1 -1
  72. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  73. package/dist/brep/engine/adapters/brep-mock.js +58 -0
  74. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  75. package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
  76. package/dist/brep/engine/adapters/brepkit.js +39 -1
  77. package/dist/brep/engine/adapters/brepkit.js.map +1 -1
  78. package/dist/brep/engine/adapters/occt.d.ts +1 -5
  79. package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
  80. package/dist/brep/engine/adapters/occt.js +232 -18
  81. package/dist/brep/engine/adapters/occt.js.map +1 -1
  82. package/dist/brep/engine/primitives.d.ts +79 -0
  83. package/dist/brep/engine/primitives.d.ts.map +1 -1
  84. package/dist/brep/engine/primitives.js.map +1 -1
  85. package/dist/brep/engine/types.d.ts +18 -1
  86. package/dist/brep/engine/types.d.ts.map +1 -1
  87. package/dist/brep/engine/types.js.map +1 -1
  88. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  89. package/dist/brepkit-kernel/brepkitKernel.js +81 -11
  90. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  91. package/dist/browser.d.ts +6 -28
  92. package/dist/browser.d.ts.map +1 -1
  93. package/dist/browser.js +6 -17
  94. package/dist/browser.js.map +1 -1
  95. package/dist/cad-runtime/admit-compat-lib.d.ts +13 -18
  96. package/dist/cad-runtime/admit-compat-lib.d.ts.map +1 -1
  97. package/dist/cad-runtime/admit-compat-lib.js +25 -18
  98. package/dist/cad-runtime/admit-compat-lib.js.map +1 -1
  99. package/dist/cad-runtime/backend-dispatch.d.ts +4 -2
  100. package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
  101. package/dist/cad-runtime/backend-dispatch.js +2 -0
  102. package/dist/cad-runtime/backend-dispatch.js.map +1 -1
  103. package/dist/cad-runtime/browser-lib-loader.d.ts +4 -6
  104. package/dist/cad-runtime/browser-lib-loader.d.ts.map +1 -1
  105. package/dist/cad-runtime/browser-lib-loader.js +4 -9
  106. package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
  107. package/dist/cad-runtime/ports.d.ts +0 -7
  108. package/dist/cad-runtime/ports.d.ts.map +1 -1
  109. package/dist/cad-runtime/ports.js.map +1 -1
  110. package/dist/cad-runtime/runtime.d.ts +1 -3
  111. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  112. package/dist/cad-runtime/runtime.js +13 -18
  113. package/dist/cad-runtime/runtime.js.map +1 -1
  114. package/dist/env-agnostic.d.ts +38 -0
  115. package/dist/env-agnostic.d.ts.map +1 -0
  116. package/dist/env-agnostic.js +29 -0
  117. package/dist/env-agnostic.js.map +1 -0
  118. package/dist/fcstd/codegen.d.ts.map +1 -1
  119. package/dist/fcstd/codegen.js +8 -1
  120. package/dist/fcstd/codegen.js.map +1 -1
  121. package/dist/fcstd/expressions.d.ts +24 -0
  122. package/dist/fcstd/expressions.d.ts.map +1 -1
  123. package/dist/fcstd/expressions.js +91 -0
  124. package/dist/fcstd/expressions.js.map +1 -1
  125. package/dist/fcstd/feature-translate.d.ts.map +1 -1
  126. package/dist/fcstd/feature-translate.js +16 -2
  127. package/dist/fcstd/feature-translate.js.map +1 -1
  128. package/dist/fcstd/structural-types.d.ts.map +1 -1
  129. package/dist/fcstd/structural-types.js +5 -0
  130. package/dist/fcstd/structural-types.js.map +1 -1
  131. package/dist/index.d.ts +7 -24
  132. package/dist/index.d.ts.map +1 -1
  133. package/dist/index.js +10 -16
  134. package/dist/index.js.map +1 -1
  135. package/dist/lang/determinism-scanner.d.ts +9 -0
  136. package/dist/lang/determinism-scanner.d.ts.map +1 -1
  137. package/dist/lang/determinism-scanner.js +7 -1
  138. package/dist/lang/determinism-scanner.js.map +1 -1
  139. package/dist/lang/symbol-table.d.ts +31 -0
  140. package/dist/lang/symbol-table.d.ts.map +1 -1
  141. package/dist/lang/symbol-table.generated.d.ts +6 -16
  142. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  143. package/dist/lang/symbol-table.generated.js +6 -16
  144. package/dist/lang/symbol-table.generated.js.map +1 -1
  145. package/dist/lang/symbol-table.js +50 -1
  146. package/dist/lang/symbol-table.js.map +1 -1
  147. package/dist/mesh/creased-normals.d.ts +50 -0
  148. package/dist/mesh/creased-normals.d.ts.map +1 -0
  149. package/dist/mesh/creased-normals.js +114 -0
  150. package/dist/mesh/creased-normals.js.map +1 -0
  151. package/dist/mesh/decoration-provider.d.ts +53 -0
  152. package/dist/mesh/decoration-provider.d.ts.map +1 -0
  153. package/dist/mesh/decoration-provider.js +21 -0
  154. package/dist/mesh/decoration-provider.js.map +1 -0
  155. package/dist/mesh/engrave.d.ts +4 -0
  156. package/dist/mesh/engrave.d.ts.map +1 -1
  157. package/dist/mesh/engrave.js +22 -31
  158. package/dist/mesh/engrave.js.map +1 -1
  159. package/dist/mesh/index.d.ts +5 -14
  160. package/dist/mesh/index.d.ts.map +1 -1
  161. package/dist/mesh/index.js +7 -19
  162. package/dist/mesh/index.js.map +1 -1
  163. package/dist/mesh/io.d.ts +2 -1
  164. package/dist/mesh/io.d.ts.map +1 -1
  165. package/dist/mesh/io.js +5 -7
  166. package/dist/mesh/io.js.map +1 -1
  167. package/dist/mesh/primitives.d.ts +5 -18
  168. package/dist/mesh/primitives.d.ts.map +1 -1
  169. package/dist/mesh/primitives.js +4 -48
  170. package/dist/mesh/primitives.js.map +1 -1
  171. package/dist/mesh/stl-loader.d.ts +23 -0
  172. package/dist/mesh/stl-loader.d.ts.map +1 -0
  173. package/dist/mesh/stl-loader.js +139 -0
  174. package/dist/mesh/stl-loader.js.map +1 -0
  175. package/dist/module-resolver/parse-imports.d.ts +37 -0
  176. package/dist/module-resolver/parse-imports.d.ts.map +1 -0
  177. package/dist/module-resolver/parse-imports.js +39 -0
  178. package/dist/module-resolver/parse-imports.js.map +1 -0
  179. package/dist/module-resolver/resolver.d.ts +1 -1
  180. package/dist/module-resolver/resolver.js +2 -2
  181. package/dist/module-resolver/resolver.js.map +1 -1
  182. package/dist/node-host/cli.d.ts.map +1 -1
  183. package/dist/node-host/cli.js +1 -22
  184. package/dist/node-host/cli.js.map +1 -1
  185. package/dist/primitives/text/cjk-font.d.ts +42 -0
  186. package/dist/primitives/text/cjk-font.d.ts.map +1 -0
  187. package/dist/primitives/text/cjk-font.js +86 -0
  188. package/dist/primitives/text/cjk-font.js.map +1 -0
  189. package/dist/sdk.d.ts +2 -2
  190. package/dist/sdk.js +2 -2
  191. package/dist/sdk.js.map +1 -1
  192. package/dist/symbol-table.d.ts +15 -0
  193. package/dist/symbol-table.d.ts.map +1 -0
  194. package/dist/symbol-table.js +14 -0
  195. package/dist/symbol-table.js.map +1 -0
  196. package/dist/topology/naming/lineage-resolve.js +1 -1
  197. package/dist/topology/naming/lineage-resolve.js.map +1 -1
  198. package/dist/vendored/brepjs/kernel/index.d.ts +5 -0
  199. package/dist/vendored/brepjs/kernel/index.d.ts.map +1 -1
  200. package/dist/vendored/brepjs/kernel/index.js +11 -0
  201. package/dist/vendored/brepjs/kernel/index.js.map +1 -1
  202. package/dist/weapp.d.ts +3 -3
  203. package/dist/weapp.d.ts.map +1 -1
  204. package/dist/weapp.js +6 -3
  205. package/dist/weapp.js.map +1 -1
  206. package/package.json +16 -14
  207. package/dist/api/compat/index.d.ts +0 -173
  208. package/dist/api/compat/index.d.ts.map +0 -1
  209. package/dist/api/compat/index.js +0 -222
  210. package/dist/api/compat/index.js.map +0 -1
  211. package/dist/api/compound.d.ts +0 -110
  212. package/dist/api/compound.d.ts.map +0 -1
  213. package/dist/api/compound.js +0 -164
  214. package/dist/api/compound.js.map +0 -1
  215. package/dist/api/copy.d.ts +0 -40
  216. package/dist/api/copy.d.ts.map +0 -1
  217. package/dist/api/copy.js +0 -83
  218. package/dist/api/copy.js.map +0 -1
  219. package/dist/api/fai_drill.d.ts +0 -46
  220. package/dist/api/fai_drill.d.ts.map +0 -1
  221. package/dist/api/fai_drill.js +0 -243
  222. package/dist/api/fai_drill.js.map +0 -1
  223. package/dist/api/fai_extrude.d.ts +0 -36
  224. package/dist/api/fai_extrude.d.ts.map +0 -1
  225. package/dist/api/fai_extrude.js +0 -79
  226. package/dist/api/fai_extrude.js.map +0 -1
  227. package/dist/api/fai_split.d.ts +0 -46
  228. package/dist/api/fai_split.d.ts.map +0 -1
  229. package/dist/api/fai_split.js +0 -254
  230. package/dist/api/fai_split.js.map +0 -1
  231. package/dist/api/load.d.ts +0 -41
  232. package/dist/api/load.d.ts.map +0 -1
  233. package/dist/api/load.js +0 -84
  234. package/dist/api/load.js.map +0 -1
  235. package/dist/api/svgExtrude.d.ts +0 -32
  236. package/dist/api/svgExtrude.d.ts.map +0 -1
  237. package/dist/api/svgExtrude.js +0 -74
  238. package/dist/api/svgExtrude.js.map +0 -1
  239. package/dist/api/text.d.ts +0 -34
  240. package/dist/api/text.d.ts.map +0 -1
  241. package/dist/api/text.js +0 -101
  242. package/dist/api/text.js.map +0 -1
  243. package/dist/brep/text/fontTestHelper.d.ts +0 -30
  244. package/dist/brep/text/fontTestHelper.d.ts.map +0 -1
  245. package/dist/brep/text/fontTestHelper.js +0 -57
  246. package/dist/brep/text/fontTestHelper.js.map +0 -1
  247. package/dist/cad-runtime/module-executor.d.ts +0 -271
  248. package/dist/cad-runtime/module-executor.d.ts.map +0 -1
  249. package/dist/cad-runtime/module-executor.js +0 -630
  250. package/dist/cad-runtime/module-executor.js.map +0 -1
  251. package/dist/cad-runtime/terminal-dag.d.ts +0 -65
  252. package/dist/cad-runtime/terminal-dag.d.ts.map +0 -1
  253. package/dist/cad-runtime/terminal-dag.js +0 -167
  254. package/dist/cad-runtime/terminal-dag.js.map +0 -1
  255. package/dist/faqts/browser.d.ts +0 -16
  256. package/dist/faqts/browser.d.ts.map +0 -1
  257. package/dist/faqts/browser.js +0 -13
  258. package/dist/faqts/browser.js.map +0 -1
  259. package/dist/faqts/exec-blob.d.ts +0 -14
  260. package/dist/faqts/exec-blob.d.ts.map +0 -1
  261. package/dist/faqts/exec-blob.js +0 -22
  262. package/dist/faqts/exec-blob.js.map +0 -1
  263. package/dist/faqts/exec-node.d.ts +0 -15
  264. package/dist/faqts/exec-node.d.ts.map +0 -1
  265. package/dist/faqts/exec-node.js +0 -29
  266. package/dist/faqts/exec-node.js.map +0 -1
  267. package/dist/faqts/imports.d.ts +0 -74
  268. package/dist/faqts/imports.d.ts.map +0 -1
  269. package/dist/faqts/imports.js +0 -95
  270. package/dist/faqts/imports.js.map +0 -1
  271. package/dist/faqts/index.d.ts +0 -22
  272. package/dist/faqts/index.d.ts.map +0 -1
  273. package/dist/faqts/index.js +0 -21
  274. package/dist/faqts/index.js.map +0 -1
  275. package/dist/faqts/node.d.ts +0 -23
  276. package/dist/faqts/node.d.ts.map +0 -1
  277. package/dist/faqts/node.js +0 -23
  278. package/dist/faqts/node.js.map +0 -1
  279. package/dist/faqts/run.d.ts +0 -62
  280. package/dist/faqts/run.d.ts.map +0 -1
  281. package/dist/faqts/run.js +0 -62
  282. package/dist/faqts/run.js.map +0 -1
  283. package/dist/faqts/transform.d.ts +0 -43
  284. package/dist/faqts/transform.d.ts.map +0 -1
  285. package/dist/faqts/transform.js +0 -35
  286. package/dist/faqts/transform.js.map +0 -1
  287. package/dist/lang/compile.d.ts +0 -50
  288. package/dist/lang/compile.d.ts.map +0 -1
  289. package/dist/lang/compile.js +0 -368
  290. package/dist/lang/compile.js.map +0 -1
  291. package/dist/lang/keep.d.ts +0 -109
  292. package/dist/lang/keep.d.ts.map +0 -1
  293. package/dist/lang/keep.js +0 -226
  294. package/dist/lang/keep.js.map +0 -1
  295. package/dist/lang/parser.d.ts +0 -91
  296. package/dist/lang/parser.d.ts.map +0 -1
  297. package/dist/lang/parser.js +0 -1594
  298. package/dist/lang/parser.js.map +0 -1
  299. package/dist/mesh/drill-hole/DrillHoleCore.d.ts +0 -90
  300. package/dist/mesh/drill-hole/DrillHoleCore.d.ts.map +0 -1
  301. package/dist/mesh/drill-hole/DrillHoleCore.js +0 -287
  302. package/dist/mesh/drill-hole/DrillHoleCore.js.map +0 -1
  303. package/dist/mesh/drill-hole/drill-types.d.ts +0 -34
  304. package/dist/mesh/drill-hole/drill-types.d.ts.map +0 -1
  305. package/dist/mesh/drill-hole/drill-types.js +0 -7
  306. package/dist/mesh/drill-hole/drill-types.js.map +0 -1
  307. package/dist/mesh/fai_drill.d.ts +0 -21
  308. package/dist/mesh/fai_drill.d.ts.map +0 -1
  309. package/dist/mesh/fai_drill.js +0 -92
  310. package/dist/mesh/fai_drill.js.map +0 -1
  311. package/dist/mesh/fai_extrude.d.ts +0 -24
  312. package/dist/mesh/fai_extrude.d.ts.map +0 -1
  313. package/dist/mesh/fai_extrude.js +0 -42
  314. package/dist/mesh/fai_extrude.js.map +0 -1
  315. package/dist/mesh/fai_split.d.ts +0 -164
  316. package/dist/mesh/fai_split.d.ts.map +0 -1
  317. package/dist/mesh/fai_split.js +0 -269
  318. package/dist/mesh/fai_split.js.map +0 -1
  319. package/dist/primitives/svg-extrude.d.ts +0 -43
  320. package/dist/primitives/svg-extrude.d.ts.map +0 -1
  321. package/dist/primitives/svg-extrude.js +0 -78
  322. package/dist/primitives/svg-extrude.js.map +0 -1
  323. package/dist/primitives/text/cjk.d.ts +0 -61
  324. package/dist/primitives/text/cjk.d.ts.map +0 -1
  325. package/dist/primitives/text/cjk.js +0 -215
  326. package/dist/primitives/text/cjk.js.map +0 -1
  327. package/dist/primitives/text-geometry.d.ts +0 -47
  328. package/dist/primitives/text-geometry.d.ts.map +0 -1
  329. package/dist/primitives/text-geometry.js +0 -127
  330. package/dist/primitives/text-geometry.js.map +0 -1
  331. package/dist/test-helpers.d.ts +0 -31
  332. package/dist/test-helpers.d.ts.map +0 -1
  333. package/dist/test-helpers.js +0 -55
  334. package/dist/test-helpers.js.map +0 -1
  335. package/dist/vendored/brepjs/core/kernelReentrancy.d.ts +0 -41
  336. package/dist/vendored/brepjs/core/kernelReentrancy.d.ts.map +0 -1
  337. package/dist/vendored/brepjs/core/kernelReentrancy.js +0 -68
  338. package/dist/vendored/brepjs/core/kernelReentrancy.js.map +0 -1
@@ -10,18 +10,13 @@ export default {
10
10
  "cylinder": {},
11
11
  "cone": {},
12
12
  "wedge": {},
13
- "text": {},
14
13
  "screw": {},
15
- "svgExtrude": {},
16
14
  "sketch": {},
17
15
  "sdf": {},
18
- "load": {},
19
16
  "translate": {},
20
17
  "rotate_euler": {},
21
18
  "scale": {},
22
19
  "scale3d": {},
23
- "fai_drill": {},
24
- "fai_extrude": {},
25
20
  "engrave": {},
26
21
  "chamfer": {},
27
22
  "fillet": {},
@@ -31,10 +26,6 @@ export default {
31
26
  "intersect": {},
32
27
  "extrude": {},
33
28
  "revolve": {},
34
- "fai_split": {},
35
- "group": {},
36
- "assembly": {},
37
- "copy": {},
38
29
  "faceNormal": {},
39
30
  "bboxCenter": {},
40
31
  "bboxMin": {},
@@ -52,26 +43,25 @@ export default {
52
43
  "cut": {},
53
44
  "split": {},
54
45
  "linearPattern": {},
46
+ "circularPattern": {},
47
+ "gridPattern": {},
48
+ "rectangularPattern": {},
49
+ "mirrorJoin": {},
50
+ "mirror": {},
51
+ "clone": {},
55
52
  "torus": {},
56
53
  "fuse": {},
57
54
  "viewCamera": {},
58
55
  "projectView": {},
59
56
  "projectSheet": {},
60
- "circularPattern": {},
61
- "gridPattern": {},
62
57
  "drill": {},
63
58
  "pocket": {},
64
59
  "boss": {},
65
- "mirrorJoin": {},
66
- "rectangularPattern": {},
67
60
  "convexHull": {},
68
61
  "makeBaseBox": {},
69
62
  "ellipsoid": {},
70
63
  "rotate": {},
71
- "mirror": {},
72
- "clone": {},
73
64
  "applyMatrix": {},
74
- "transformCopy": {},
75
65
  "locate": {},
76
66
  "offset": {},
77
67
  "heal": {},
@@ -1 +1 @@
1
- {"version":3,"file":"symbol-table.generated.js","sourceRoot":"","sources":["../../src/lang/symbol-table.generated.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAe;IACb,KAAK,EAAE,EAAE;IACT,QAAQ,EAAE,EAAE;IACZ,UAAU,EAAE,EAAE;IACd,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,EAAE;IACX,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,EAAE;IACX,YAAY,EAAE,EAAE;IAChB,QAAQ,EAAE,EAAE;IACZ,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,EAAE;IACV,WAAW,EAAE,EAAE;IACf,cAAc,EAAE,EAAE;IAClB,OAAO,EAAE,EAAE;IACX,SAAS,EAAE,EAAE;IACb,WAAW,EAAE,EAAE;IACf,aAAa,EAAE,EAAE;IACjB,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,EAAE;IACf,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,WAAW,EAAE,EAAE;IACf,OAAO,EAAE,EAAE;IACX,UAAU,EAAE,EAAE;IACd,MAAM,EAAE,EAAE;IACV,YAAY,EAAE,EAAE;IAChB,YAAY,EAAE,EAAE;IAChB,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,iBAAiB,EAAE,EAAE;IACrB,mBAAmB,EAAE,EAAE;IACvB,cAAc,EAAE,EAAE;IAClB,OAAO,EAAE,EAAE;IACX,aAAa,EAAE,EAAE;IACjB,aAAa,EAAE,EAAE;IACjB,UAAU,EAAE,EAAE;IACd,OAAO,EAAE,EAAE;IACX,KAAK,EAAE,EAAE;IACT,OAAO,EAAE,EAAE;IACX,eAAe,EAAE,EAAE;IACnB,OAAO,EAAE,EAAE;IACX,MAAM,EAAE,EAAE;IACV,YAAY,EAAE,EAAE;IAChB,aAAa,EAAE,EAAE;IACjB,cAAc,EAAE,EAAE;IAClB,iBAAiB,EAAE,EAAE;IACrB,aAAa,EAAE,EAAE;IACjB,OAAO,EAAE,EAAE;IACX,QAAQ,EAAE,EAAE;IACZ,MAAM,EAAE,EAAE;IACV,YAAY,EAAE,EAAE;IAChB,oBAAoB,EAAE,EAAE;IACxB,YAAY,EAAE,EAAE;IAChB,aAAa,EAAE,EAAE;IACjB,WAAW,EAAE,EAAE;IACf,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE,EAAE;IACX,aAAa,EAAE,EAAE;IACjB,eAAe,EAAE,EAAE;IACnB,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;IACZ,MAAM,EAAE,EAAE;IACV,UAAU,EAAE,EAAE;IACd,UAAU,EAAE,EAAE;IACd,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,EAAE;CAChB,CAAA","sourcesContent":["/**\n * symbol-table 生成文件 — 禁手改。\n * 由 scripts/gen-symbol-table.ts 从 api-namespace 的 cad 命名空间生成(键存在性)。\n * keep-syntax P1 后符号表只承载 check() 符号检查(\"函数不存在\"判定);\n * 保留语义由 keep 声明表达,不再有 readonly 标注。\n */\nexport default {\n \"box\": {},\n \"sphere\": {},\n \"cylinder\": {},\n \"cone\": {},\n \"wedge\": {},\n \"text\": {},\n \"screw\": {},\n \"svgExtrude\": {},\n \"sketch\": {},\n \"sdf\": {},\n \"load\": {},\n \"translate\": {},\n \"rotate_euler\": {},\n \"scale\": {},\n \"scale3d\": {},\n \"fai_drill\": {},\n \"fai_extrude\": {},\n \"engrave\": {},\n \"chamfer\": {},\n \"fillet\": {},\n \"knurl\": {},\n \"union\": {},\n \"subtract\": {},\n \"intersect\": {},\n \"extrude\": {},\n \"revolve\": {},\n \"fai_split\": {},\n \"group\": {},\n \"assembly\": {},\n \"copy\": {},\n \"faceNormal\": {},\n \"bboxCenter\": {},\n \"bboxMin\": {},\n \"bboxMax\": {},\n \"edgeRef\": {},\n \"faceRef\": {},\n \"jointTrajectory\": {},\n \"inverseKinematics\": {},\n \"mechanismDOF\": {},\n \"asset\": {},\n \"import_brep\": {},\n \"import_step\": {},\n \"compound\": {},\n \"place\": {},\n \"cut\": {},\n \"split\": {},\n \"linearPattern\": {},\n \"torus\": {},\n \"fuse\": {},\n \"viewCamera\": {},\n \"projectView\": {},\n \"projectSheet\": {},\n \"circularPattern\": {},\n \"gridPattern\": {},\n \"drill\": {},\n \"pocket\": {},\n \"boss\": {},\n \"mirrorJoin\": {},\n \"rectangularPattern\": {},\n \"convexHull\": {},\n \"makeBaseBox\": {},\n \"ellipsoid\": {},\n \"rotate\": {},\n \"mirror\": {},\n \"clone\": {},\n \"applyMatrix\": {},\n \"transformCopy\": {},\n \"locate\": {},\n \"offset\": {},\n \"heal\": {},\n \"simplify\": {},\n \"autoHeal\": {},\n \"fixShape\": {},\n \"healSolid\": {}\n}\n"]}
1
+ {"version":3,"file":"symbol-table.generated.js","sourceRoot":"","sources":["../../src/lang/symbol-table.generated.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAe;IACb,KAAK,EAAE,EAAE;IACT,QAAQ,EAAE,EAAE;IACZ,UAAU,EAAE,EAAE;IACd,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,QAAQ,EAAE,EAAE;IACZ,KAAK,EAAE,EAAE;IACT,WAAW,EAAE,EAAE;IACf,cAAc,EAAE,EAAE;IAClB,OAAO,EAAE,EAAE;IACX,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,EAAE;IACf,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,YAAY,EAAE,EAAE;IAChB,YAAY,EAAE,EAAE;IAChB,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,iBAAiB,EAAE,EAAE;IACrB,mBAAmB,EAAE,EAAE;IACvB,cAAc,EAAE,EAAE;IAClB,OAAO,EAAE,EAAE;IACX,aAAa,EAAE,EAAE;IACjB,aAAa,EAAE,EAAE;IACjB,UAAU,EAAE,EAAE;IACd,OAAO,EAAE,EAAE;IACX,KAAK,EAAE,EAAE;IACT,OAAO,EAAE,EAAE;IACX,eAAe,EAAE,EAAE;IACnB,iBAAiB,EAAE,EAAE;IACrB,aAAa,EAAE,EAAE;IACjB,oBAAoB,EAAE,EAAE;IACxB,YAAY,EAAE,EAAE;IAChB,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,MAAM,EAAE,EAAE;IACV,YAAY,EAAE,EAAE;IAChB,aAAa,EAAE,EAAE;IACjB,cAAc,EAAE,EAAE;IAClB,OAAO,EAAE,EAAE;IACX,QAAQ,EAAE,EAAE;IACZ,MAAM,EAAE,EAAE;IACV,YAAY,EAAE,EAAE;IAChB,aAAa,EAAE,EAAE;IACjB,WAAW,EAAE,EAAE;IACf,QAAQ,EAAE,EAAE;IACZ,aAAa,EAAE,EAAE;IACjB,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE;IACZ,MAAM,EAAE,EAAE;IACV,UAAU,EAAE,EAAE;IACd,UAAU,EAAE,EAAE;IACd,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,EAAE;CAChB,CAAA","sourcesContent":["/**\n * symbol-table 生成文件 — 禁手改。\n * 由 scripts/gen-symbol-table.ts 从 api-namespace 的 cad 命名空间生成(键存在性)。\n * keep-syntax P1 后符号表只承载 check() 符号检查(\"函数不存在\"判定);\n * 保留语义由 keep 声明表达,不再有 readonly 标注。\n */\nexport default {\n \"box\": {},\n \"sphere\": {},\n \"cylinder\": {},\n \"cone\": {},\n \"wedge\": {},\n \"screw\": {},\n \"sketch\": {},\n \"sdf\": {},\n \"translate\": {},\n \"rotate_euler\": {},\n \"scale\": {},\n \"scale3d\": {},\n \"engrave\": {},\n \"chamfer\": {},\n \"fillet\": {},\n \"knurl\": {},\n \"union\": {},\n \"subtract\": {},\n \"intersect\": {},\n \"extrude\": {},\n \"revolve\": {},\n \"faceNormal\": {},\n \"bboxCenter\": {},\n \"bboxMin\": {},\n \"bboxMax\": {},\n \"edgeRef\": {},\n \"faceRef\": {},\n \"jointTrajectory\": {},\n \"inverseKinematics\": {},\n \"mechanismDOF\": {},\n \"asset\": {},\n \"import_brep\": {},\n \"import_step\": {},\n \"compound\": {},\n \"place\": {},\n \"cut\": {},\n \"split\": {},\n \"linearPattern\": {},\n \"circularPattern\": {},\n \"gridPattern\": {},\n \"rectangularPattern\": {},\n \"mirrorJoin\": {},\n \"mirror\": {},\n \"clone\": {},\n \"torus\": {},\n \"fuse\": {},\n \"viewCamera\": {},\n \"projectView\": {},\n \"projectSheet\": {},\n \"drill\": {},\n \"pocket\": {},\n \"boss\": {},\n \"convexHull\": {},\n \"makeBaseBox\": {},\n \"ellipsoid\": {},\n \"rotate\": {},\n \"applyMatrix\": {},\n \"locate\": {},\n \"offset\": {},\n \"heal\": {},\n \"simplify\": {},\n \"autoHeal\": {},\n \"fixShape\": {},\n \"healSolid\": {}\n}\n"]}
@@ -10,10 +10,59 @@
10
10
  * 未知第三方函数不在表中时,check() 报"函数不存在",其它机制不受影响。
11
11
  *
12
12
  * 生成文件:src/lang/symbol-table.generated.ts(由 scripts/gen-symbol-table.ts 生成,禁手改)。
13
+ *
14
+ * P5(2026-09-23 扩展库拆分):符号表额外接受**宿主注册的扩展条目**
15
+ * (`registerSymbolTableEntries`)。扩展库(如 `@faicad/faijs-extra`)的 op 不在
16
+ * 生成表里——生成表的唯一来源是 core 的 `createApiNamespace()` 平台面;扩展库由
17
+ * 宿主在装配时注入名字清单,使静态分析同样能查到 `cad.fai_drill`。
18
+ * 扩展条目**不得**覆盖平台函数(真重名即抛错,不静默覆盖)。
13
19
  */
14
20
  import symbolTable from './symbol-table.generated.js';
15
21
  /** 生成的符号表(禁手改,由 scripts/gen-symbol-table.ts 生成) */
16
22
  export const SYMBOL_TABLE = symbolTable;
23
+ /**
24
+ * Host-registered extension entries (library namespaces outside core's platform
25
+ * surface). Kept apart from `SYMBOL_TABLE` so "platform surface" stays
26
+ * machine-derivable from the generated table alone.
27
+ */
28
+ const extensionEntries = new Map();
29
+ /**
30
+ * Register library function names in the symbol table (P5).
31
+ *
32
+ * Idempotent for names already registered as extensions; throws when a name
33
+ * collides with a platform function, because a silent override would let a
34
+ * library shadow the platform surface in static analysis.
35
+ *
36
+ * @param names - the library's function names (`cad.<name>`).
37
+ * @throws when a name is already a platform function of the generated table.
38
+ */
39
+ export function registerSymbolTableEntries(names) {
40
+ for (const name of names) {
41
+ if (Object.prototype.hasOwnProperty.call(SYMBOL_TABLE, name)) {
42
+ throw new Error(`[faijs] symbol-table extension redefines platform function "${name}"`);
43
+ }
44
+ extensionEntries.set(name, {});
45
+ }
46
+ }
47
+ /**
48
+ * Remove previously registered extension entries (host unloads a library).
49
+ * Unknown names are ignored.
50
+ *
51
+ * @param names - the function names to unregister.
52
+ */
53
+ export function unregisterSymbolTableEntries(names) {
54
+ for (const name of names)
55
+ extensionEntries.delete(name);
56
+ }
57
+ /**
58
+ * All callee names known to the symbol table: the generated platform table plus
59
+ * the registered extension entries.
60
+ *
61
+ * @returns the union of platform and extension names, platform first.
62
+ */
63
+ export function symbolTableNames() {
64
+ return [...new Set([...Object.keys(SYMBOL_TABLE), ...extensionEntries.keys()])];
65
+ }
17
66
  /**
18
67
  * Look up a callee in the standard-library symbol table. Unknown functions
19
68
  * (absent from the table) return undefined, which check() reports as
@@ -22,6 +71,6 @@ export const SYMBOL_TABLE = symbolTable;
22
71
  * @returns the matching symbol-table entry, or undefined when unknown.
23
72
  */
24
73
  export function getFunctionSymbol(callee) {
25
- return SYMBOL_TABLE[callee];
74
+ return SYMBOL_TABLE[callee] ?? extensionEntries.get(callee);
26
75
  }
27
76
  //# sourceMappingURL=symbol-table.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"symbol-table.js","sourceRoot":"","sources":["../../src/lang/symbol-table.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,WAAW,MAAM,0BAA0B,CAAA;AAQlD,mDAAmD;AACnD,MAAM,CAAC,MAAM,YAAY,GAAgB,WAA0B,CAAA;AAEnE;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,OAAO,YAAY,CAAC,MAAM,CAAC,CAAA;AAC7B,CAAC","sourcesContent":["/**\n * symbol-table — 标准库符号表类型与消费入口(L0 零依赖)\n *\n *\n * 符号表是\"标准库符号表\"(正常语言编译器认识 prelude 的同款机制),\n * 机器生成、均匀查询。keep-syntax P1 之后它只承载一个职责:\n * check() 符号检查判定 callee 是否存在(\"函数不存在\"诊断)。\n * 保留语义(readonlyPositions/readonlyPaths)已删除——保留由 keep 声明\n * (调用点 keep / 函数体 exec.keep)显式表达,不再靠类型标注提取(R7)。\n * 未知第三方函数不在表中时,check() 报\"函数不存在\",其它机制不受影响。\n *\n * 生成文件:src/lang/symbol-table.generated.ts(由 scripts/gen-symbol-table.ts 生成,禁手改)。\n */\n\nimport symbolTable from './symbol-table.generated'\n\n/** 符号表条目(keep-syntax P1 后为空对象占位,仅承载键存在性)。 */\nexport type FunctionSymbol = Record<string, never>\n\n/** 标准库符号表:callee → 条目。均匀数据,无 per-函数代码。 */\nexport type SymbolTable = Record<string, FunctionSymbol>\n\n/** 生成的符号表(禁手改,由 scripts/gen-symbol-table.ts 生成) */\nexport const SYMBOL_TABLE: SymbolTable = symbolTable as SymbolTable\n\n/**\n * Look up a callee in the standard-library symbol table. Unknown functions\n * (absent from the table) return undefined, which check() reports as\n * \"function does not exist\".\n * @param callee - the callee name to look up.\n * @returns the matching symbol-table entry, or undefined when unknown.\n */\nexport function getFunctionSymbol(callee: string): FunctionSymbol | undefined {\n return SYMBOL_TABLE[callee]\n}\n"]}
1
+ {"version":3,"file":"symbol-table.js","sourceRoot":"","sources":["../../src/lang/symbol-table.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,WAAW,MAAM,0BAA0B,CAAA;AAQlD,mDAAmD;AACnD,MAAM,CAAC,MAAM,YAAY,GAAgB,WAA0B,CAAA;AAEnE;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAA0B,CAAA;AAE1D;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CAAC,KAAwB;IACjE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,+DAA+D,IAAI,GAAG,CAAC,CAAA;QACzF,CAAC;QACD,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAChC,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,KAAwB;IACnE,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;AACjF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,OAAO,YAAY,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;AAC7D,CAAC","sourcesContent":["/**\n * symbol-table — 标准库符号表类型与消费入口(L0 零依赖)\n *\n *\n * 符号表是\"标准库符号表\"(正常语言编译器认识 prelude 的同款机制),\n * 机器生成、均匀查询。keep-syntax P1 之后它只承载一个职责:\n * check() 符号检查判定 callee 是否存在(\"函数不存在\"诊断)。\n * 保留语义(readonlyPositions/readonlyPaths)已删除——保留由 keep 声明\n * (调用点 keep / 函数体 exec.keep)显式表达,不再靠类型标注提取(R7)。\n * 未知第三方函数不在表中时,check() 报\"函数不存在\",其它机制不受影响。\n *\n * 生成文件:src/lang/symbol-table.generated.ts(由 scripts/gen-symbol-table.ts 生成,禁手改)。\n *\n * P5(2026-09-23 扩展库拆分):符号表额外接受**宿主注册的扩展条目**\n * (`registerSymbolTableEntries`)。扩展库(如 `@faicad/faijs-extra`)的 op 不在\n * 生成表里——生成表的唯一来源是 core 的 `createApiNamespace()` 平台面;扩展库由\n * 宿主在装配时注入名字清单,使静态分析同样能查到 `cad.fai_drill`。\n * 扩展条目**不得**覆盖平台函数(真重名即抛错,不静默覆盖)。\n */\n\nimport symbolTable from './symbol-table.generated'\n\n/** 符号表条目(keep-syntax P1 后为空对象占位,仅承载键存在性)。 */\nexport type FunctionSymbol = Record<string, never>\n\n/** 标准库符号表:callee → 条目。均匀数据,无 per-函数代码。 */\nexport type SymbolTable = Record<string, FunctionSymbol>\n\n/** 生成的符号表(禁手改,由 scripts/gen-symbol-table.ts 生成) */\nexport const SYMBOL_TABLE: SymbolTable = symbolTable as SymbolTable\n\n/**\n * Host-registered extension entries (library namespaces outside core's platform\n * surface). Kept apart from `SYMBOL_TABLE` so \"platform surface\" stays\n * machine-derivable from the generated table alone.\n */\nconst extensionEntries = new Map<string, FunctionSymbol>()\n\n/**\n * Register library function names in the symbol table (P5).\n *\n * Idempotent for names already registered as extensions; throws when a name\n * collides with a platform function, because a silent override would let a\n * library shadow the platform surface in static analysis.\n *\n * @param names - the library's function names (`cad.<name>`).\n * @throws when a name is already a platform function of the generated table.\n */\nexport function registerSymbolTableEntries(names: readonly string[]): void {\n for (const name of names) {\n if (Object.prototype.hasOwnProperty.call(SYMBOL_TABLE, name)) {\n throw new Error(`[faijs] symbol-table extension redefines platform function \"${name}\"`)\n }\n extensionEntries.set(name, {})\n }\n}\n\n/**\n * Remove previously registered extension entries (host unloads a library).\n * Unknown names are ignored.\n *\n * @param names - the function names to unregister.\n */\nexport function unregisterSymbolTableEntries(names: readonly string[]): void {\n for (const name of names) extensionEntries.delete(name)\n}\n\n/**\n * All callee names known to the symbol table: the generated platform table plus\n * the registered extension entries.\n *\n * @returns the union of platform and extension names, platform first.\n */\nexport function symbolTableNames(): string[] {\n return [...new Set([...Object.keys(SYMBOL_TABLE), ...extensionEntries.keys()])]\n}\n\n/**\n * Look up a callee in the standard-library symbol table. Unknown functions\n * (absent from the table) return undefined, which check() reports as\n * \"function does not exist\".\n * @param callee - the callee name to look up.\n * @returns the matching symbol-table entry, or undefined when unknown.\n */\nexport function getFunctionSymbol(callee: string): FunctionSymbol | undefined {\n return SYMBOL_TABLE[callee] ?? extensionEntries.get(callee)\n}\n"]}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * creased-normals.ts — dependency-free creased (folded) normal computation.
3
+ *
4
+ * The engine's own port of three's `toCreasedNormals`
5
+ * (three/examples/jsm/utils/BufferGeometryUtils.js). Why a port instead of an
6
+ * import: the three helper drags the whole `three` package into any consumer
7
+ * (weapp main thread cannot hold two three copies — see 3d_editor weapp plan
8
+ * §1.1.1 "no three via dependency packages"), while the algorithm itself is
9
+ * pure array math.
10
+ *
11
+ * Semantics are aligned with three r162..r184 `toCreasedNormals` line by line:
12
+ * - input is expanded to non-indexed triangles (indexed geometry is unwound);
13
+ * output is always non-indexed (positions count = triangleCount * 3, indices = null);
14
+ * - a face normal is computed per triangle and pushed onto hash buckets of its
15
+ * 3 vertices (hash = trunc(x * 100 * (1 + 1e-10)) per component, same
16
+ * quantization as three's `hashVertex`);
17
+ * - each vertex normal = normalize(sum of bucket normals whose dot with the
18
+ * face normal exceeds cos(creaseAngleDeg)) — sharp edges split, smooth
19
+ * surfaces (drill walls) stay averaged;
20
+ * - degenerate (zero-area) faces yield NaN normals exactly like three's
21
+ * divide-by-zero; callers treat that as invalid geometry upstream.
22
+ */
23
+ export interface CreasedNormalsInput {
24
+ /** Triangle positions, xyz interleaved, length = n * 3. */
25
+ positions: Float32Array;
26
+ /** Triangle vertex indices, length = n * 3 (n = triangle count). `null` = sequential. */
27
+ indices: Uint32Array | null;
28
+ /** Dihedral-angle threshold in degrees above which normals split (default 60). */
29
+ creaseAngleDeg?: number;
30
+ }
31
+ /**
32
+ * Creased-normals computation input/output (dependency-free surface).
33
+ */
34
+ export interface CreasedNormalsResult {
35
+ /** Non-indexed positions (indexed input is expanded). */
36
+ positions: Float32Array;
37
+ /** Per-vertex creased normals, xyz interleaved. */
38
+ normals: Float32Array;
39
+ /** Always null — creased normals cannot be expressed on shared vertices. */
40
+ indices: null;
41
+ }
42
+ /**
43
+ * Derive creased (folded) normals from raw triangle data — the dependency-free
44
+ * equivalent of three's `toCreasedNormals`. See the module header for the
45
+ * aligned semantics.
46
+ * @param input - positions (+ optional indices) and the crease angle threshold.
47
+ * @returns non-indexed positions plus per-vertex creased normals.
48
+ */
49
+ export declare function deriveCreasedNormalsData(input: CreasedNormalsInput): CreasedNormalsResult;
50
+ //# sourceMappingURL=creased-normals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"creased-normals.d.ts","sourceRoot":"","sources":["../../src/mesh/creased-normals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,mBAAmB;IAClC,2DAA2D;IAC3D,SAAS,EAAE,YAAY,CAAA;IACvB,yFAAyF;IACzF,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;IAC3B,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,SAAS,EAAE,YAAY,CAAA;IACvB,mDAAmD;IACnD,OAAO,EAAE,YAAY,CAAA;IACrB,4EAA4E;IAC5E,OAAO,EAAE,IAAI,CAAA;CACd;AAYD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,mBAAmB,GAAG,oBAAoB,CA8EzF"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * creased-normals.ts — dependency-free creased (folded) normal computation.
3
+ *
4
+ * The engine's own port of three's `toCreasedNormals`
5
+ * (three/examples/jsm/utils/BufferGeometryUtils.js). Why a port instead of an
6
+ * import: the three helper drags the whole `three` package into any consumer
7
+ * (weapp main thread cannot hold two three copies — see 3d_editor weapp plan
8
+ * §1.1.1 "no three via dependency packages"), while the algorithm itself is
9
+ * pure array math.
10
+ *
11
+ * Semantics are aligned with three r162..r184 `toCreasedNormals` line by line:
12
+ * - input is expanded to non-indexed triangles (indexed geometry is unwound);
13
+ * output is always non-indexed (positions count = triangleCount * 3, indices = null);
14
+ * - a face normal is computed per triangle and pushed onto hash buckets of its
15
+ * 3 vertices (hash = trunc(x * 100 * (1 + 1e-10)) per component, same
16
+ * quantization as three's `hashVertex`);
17
+ * - each vertex normal = normalize(sum of bucket normals whose dot with the
18
+ * face normal exceeds cos(creaseAngleDeg)) — sharp edges split, smooth
19
+ * surfaces (drill walls) stay averaged;
20
+ * - degenerate (zero-area) faces yield NaN normals exactly like three's
21
+ * divide-by-zero; callers treat that as invalid geometry upstream.
22
+ */
23
+ const HASH_MULTIPLIER = (1 + 1e-10) * 1e2;
24
+ function hashVertex(x, y, z) {
25
+ // Same truncation semantics as three: `~~` (32-bit trunc) on scaled coords.
26
+ const hx = ~~(x * HASH_MULTIPLIER);
27
+ const hy = ~~(y * HASH_MULTIPLIER);
28
+ const hz = ~~(z * HASH_MULTIPLIER);
29
+ return `${hx},${hy},${hz}`;
30
+ }
31
+ /**
32
+ * Derive creased (folded) normals from raw triangle data — the dependency-free
33
+ * equivalent of three's `toCreasedNormals`. See the module header for the
34
+ * aligned semantics.
35
+ * @param input - positions (+ optional indices) and the crease angle threshold.
36
+ * @returns non-indexed positions plus per-vertex creased normals.
37
+ */
38
+ export function deriveCreasedNormalsData(input) {
39
+ const { indices, creaseAngleDeg = 60 } = input;
40
+ const srcPos = input.positions;
41
+ const triCount = indices ? indices.length / 3 : srcPos.length / 9;
42
+ // Expand to non-indexed triangles (three: geometry.toNonIndexed()).
43
+ const pos = new Float32Array(triCount * 9);
44
+ for (let t = 0; t < triCount; t++) {
45
+ for (let v = 0; v < 3; v++) {
46
+ const srcIdx = indices ? indices[t * 3 + v] : t * 3 + v;
47
+ pos[t * 9 + v * 3 + 0] = srcPos[srcIdx * 3 + 0];
48
+ pos[t * 9 + v * 3 + 1] = srcPos[srcIdx * 3 + 1];
49
+ pos[t * 9 + v * 3 + 2] = srcPos[srcIdx * 3 + 2];
50
+ }
51
+ }
52
+ const creaseDot = Math.cos((creaseAngleDeg * Math.PI) / 180);
53
+ // Pass 1: face normals into per-vertex hash buckets.
54
+ const vertexMap = new Map();
55
+ const fnx = new Float32Array(triCount);
56
+ const fny = new Float32Array(triCount);
57
+ const fnz = new Float32Array(triCount);
58
+ for (let t = 0; t < triCount; t++) {
59
+ const ax = pos[t * 9 + 0], ay = pos[t * 9 + 1], az = pos[t * 9 + 2];
60
+ const bx = pos[t * 9 + 3], by = pos[t * 9 + 4], bz = pos[t * 9 + 5];
61
+ const cx = pos[t * 9 + 6], cy = pos[t * 9 + 7], cz = pos[t * 9 + 8];
62
+ // cb = c - b, ab = a - b; normal = cb × ab (same edge order as three).
63
+ const e1x = cx - bx, e1y = cy - by, e1z = cz - bz;
64
+ const e2x = ax - bx, e2y = ay - by, e2z = az - bz;
65
+ let nx = e1y * e2z - e1z * e2y;
66
+ let ny = e1z * e2x - e1x * e2z;
67
+ let nz = e1x * e2y - e1y * e2x;
68
+ const len = Math.sqrt(nx * nx + ny * ny + nz * nz);
69
+ if (len > 0) {
70
+ nx /= len;
71
+ ny /= len;
72
+ nz /= len;
73
+ }
74
+ fnx[t] = nx;
75
+ fny[t] = ny;
76
+ fnz[t] = nz;
77
+ for (let v = 0; v < 3; v++) {
78
+ const h = hashVertex(pos[t * 9 + v * 3], pos[t * 9 + v * 3 + 1], pos[t * 9 + v * 3 + 2]);
79
+ let bucket = vertexMap.get(h);
80
+ if (!bucket) {
81
+ bucket = [];
82
+ vertexMap.set(h, bucket);
83
+ }
84
+ bucket.push([nx, ny, nz]);
85
+ }
86
+ }
87
+ // Pass 2: average bucket normals within the crease threshold.
88
+ const normals = new Float32Array(triCount * 9);
89
+ for (let t = 0; t < triCount; t++) {
90
+ for (let v = 0; v < 3; v++) {
91
+ const h = hashVertex(pos[t * 9 + v * 3], pos[t * 9 + v * 3 + 1], pos[t * 9 + v * 3 + 2]);
92
+ const bucket = vertexMap.get(h);
93
+ let sx = 0, sy = 0, sz = 0;
94
+ for (let k = 0; k < bucket.length; k++) {
95
+ const on = bucket[k];
96
+ // Three uses `>` (strictly greater) — coplanar neighbours merge,
97
+ // faces at exactly the crease angle do not.
98
+ if (fnx[t] * on[0] + fny[t] * on[1] + fnz[t] * on[2] > creaseDot) {
99
+ sx += on[0];
100
+ sy += on[1];
101
+ sz += on[2];
102
+ }
103
+ }
104
+ const sl = Math.sqrt(sx * sx + sy * sy + sz * sz);
105
+ // Divide unconditionally: a zero-length sum yields NaN, matching three's
106
+ // divide-by-zero behavior on degenerate geometry.
107
+ normals[t * 9 + v * 3 + 0] = sx / sl;
108
+ normals[t * 9 + v * 3 + 1] = sy / sl;
109
+ normals[t * 9 + v * 3 + 2] = sz / sl;
110
+ }
111
+ }
112
+ return { positions: pos, normals, indices: null };
113
+ }
114
+ //# sourceMappingURL=creased-normals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"creased-normals.js","sourceRoot":"","sources":["../../src/mesh/creased-normals.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * creased-normals.ts — dependency-free creased (folded) normal computation.\n *\n * The engine's own port of three's `toCreasedNormals`\n * (three/examples/jsm/utils/BufferGeometryUtils.js). Why a port instead of an\n * import: the three helper drags the whole `three` package into any consumer\n * (weapp main thread cannot hold two three copies — see 3d_editor weapp plan\n * §1.1.1 \"no three via dependency packages\"), while the algorithm itself is\n * pure array math.\n *\n * Semantics are aligned with three r162..r184 `toCreasedNormals` line by line:\n * - input is expanded to non-indexed triangles (indexed geometry is unwound);\n * output is always non-indexed (positions count = triangleCount * 3, indices = null);\n * - a face normal is computed per triangle and pushed onto hash buckets of its\n * 3 vertices (hash = trunc(x * 100 * (1 + 1e-10)) per component, same\n * quantization as three's `hashVertex`);\n * - each vertex normal = normalize(sum of bucket normals whose dot with the\n * face normal exceeds cos(creaseAngleDeg)) — sharp edges split, smooth\n * surfaces (drill walls) stay averaged;\n * - degenerate (zero-area) faces yield NaN normals exactly like three's\n * divide-by-zero; callers treat that as invalid geometry upstream.\n */\n\nexport interface CreasedNormalsInput {\n /** Triangle positions, xyz interleaved, length = n * 3. */\n positions: Float32Array\n /** Triangle vertex indices, length = n * 3 (n = triangle count). `null` = sequential. */\n indices: Uint32Array | null\n /** Dihedral-angle threshold in degrees above which normals split (default 60). */\n creaseAngleDeg?: number\n}\n\n/**\n * Creased-normals computation input/output (dependency-free surface).\n */\nexport interface CreasedNormalsResult {\n /** Non-indexed positions (indexed input is expanded). */\n positions: Float32Array\n /** Per-vertex creased normals, xyz interleaved. */\n normals: Float32Array\n /** Always null — creased normals cannot be expressed on shared vertices. */\n indices: null\n}\n\nconst HASH_MULTIPLIER = (1 + 1e-10) * 1e2\n\nfunction hashVertex(x: number, y: number, z: number): string {\n // Same truncation semantics as three: `~~` (32-bit trunc) on scaled coords.\n const hx = ~~(x * HASH_MULTIPLIER)\n const hy = ~~(y * HASH_MULTIPLIER)\n const hz = ~~(z * HASH_MULTIPLIER)\n return `${hx},${hy},${hz}`\n}\n\n/**\n * Derive creased (folded) normals from raw triangle data — the dependency-free\n * equivalent of three's `toCreasedNormals`. See the module header for the\n * aligned semantics.\n * @param input - positions (+ optional indices) and the crease angle threshold.\n * @returns non-indexed positions plus per-vertex creased normals.\n */\nexport function deriveCreasedNormalsData(input: CreasedNormalsInput): CreasedNormalsResult {\n const { indices, creaseAngleDeg = 60 } = input\n const srcPos = input.positions\n\n const triCount = indices ? indices.length / 3 : srcPos.length / 9\n\n // Expand to non-indexed triangles (three: geometry.toNonIndexed()).\n const pos = new Float32Array(triCount * 9)\n for (let t = 0; t < triCount; t++) {\n for (let v = 0; v < 3; v++) {\n const srcIdx = indices ? indices[t * 3 + v] : t * 3 + v\n pos[t * 9 + v * 3 + 0] = srcPos[srcIdx * 3 + 0]\n pos[t * 9 + v * 3 + 1] = srcPos[srcIdx * 3 + 1]\n pos[t * 9 + v * 3 + 2] = srcPos[srcIdx * 3 + 2]\n }\n }\n\n const creaseDot = Math.cos((creaseAngleDeg * Math.PI) / 180)\n\n // Pass 1: face normals into per-vertex hash buckets.\n const vertexMap = new Map<string, number[][]>()\n const fnx = new Float32Array(triCount)\n const fny = new Float32Array(triCount)\n const fnz = new Float32Array(triCount)\n\n for (let t = 0; t < triCount; t++) {\n const ax = pos[t * 9 + 0], ay = pos[t * 9 + 1], az = pos[t * 9 + 2]\n const bx = pos[t * 9 + 3], by = pos[t * 9 + 4], bz = pos[t * 9 + 5]\n const cx = pos[t * 9 + 6], cy = pos[t * 9 + 7], cz = pos[t * 9 + 8]\n\n // cb = c - b, ab = a - b; normal = cb × ab (same edge order as three).\n const e1x = cx - bx, e1y = cy - by, e1z = cz - bz\n const e2x = ax - bx, e2y = ay - by, e2z = az - bz\n let nx = e1y * e2z - e1z * e2y\n let ny = e1z * e2x - e1x * e2z\n let nz = e1x * e2y - e1y * e2x\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz)\n if (len > 0) {\n nx /= len; ny /= len; nz /= len\n }\n fnx[t] = nx; fny[t] = ny; fnz[t] = nz\n\n for (let v = 0; v < 3; v++) {\n const h = hashVertex(pos[t * 9 + v * 3], pos[t * 9 + v * 3 + 1], pos[t * 9 + v * 3 + 2])\n let bucket = vertexMap.get(h)\n if (!bucket) {\n bucket = []\n vertexMap.set(h, bucket)\n }\n bucket.push([nx, ny, nz])\n }\n }\n\n // Pass 2: average bucket normals within the crease threshold.\n const normals = new Float32Array(triCount * 9)\n for (let t = 0; t < triCount; t++) {\n for (let v = 0; v < 3; v++) {\n const h = hashVertex(pos[t * 9 + v * 3], pos[t * 9 + v * 3 + 1], pos[t * 9 + v * 3 + 2])\n const bucket = vertexMap.get(h)!\n let sx = 0, sy = 0, sz = 0\n for (let k = 0; k < bucket.length; k++) {\n const on = bucket[k]\n // Three uses `>` (strictly greater) — coplanar neighbours merge,\n // faces at exactly the crease angle do not.\n if (fnx[t] * on[0] + fny[t] * on[1] + fnz[t] * on[2] > creaseDot) {\n sx += on[0]; sy += on[1]; sz += on[2]\n }\n }\n const sl = Math.sqrt(sx * sx + sy * sy + sz * sz)\n // Divide unconditionally: a zero-length sum yields NaN, matching three's\n // divide-by-zero behavior on degenerate geometry.\n normals[t * 9 + v * 3 + 0] = sx / sl\n normals[t * 9 + v * 3 + 1] = sy / sl\n normals[t * 9 + v * 3 + 2] = sz / sl\n }\n }\n\n return { positions: pos, normals, indices: null }\n}\n"]}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * decoration-provider — host-injectable text/SVG decoration geometry.
3
+ *
4
+ * The `cad.engrave` op is a platform op (plan §4.2 C) but its decoration input
5
+ * is text or SVG, whose mesh geometry is produced by three's non-basic chain
6
+ * (`Shape` / `ExtrudeGeometry` / `SVGLoader`). That chain now lives in
7
+ * `@faicad/faijs-extra`, so core asks the host for the decoration geometry
8
+ * instead of importing it — the same capability-injection shape as
9
+ * `setFontLoader` / `setKnurlTextureLoader`.
10
+ *
11
+ * With no provider installed, `cad.engrave` still works on its BREP path
12
+ * (OCCT `textToSolid` / `svgToSolid`, zero three); only the **mesh** path needs
13
+ * a provider, and it reports a precise error instead of failing obscurely.
14
+ */
15
+ import type * as THREE from 'three';
16
+ /** Decoration inputs `cad.engrave` passes to the provider. */
17
+ export interface EngraveDecorationParams {
18
+ /** Text to engrave (mutually exclusive with `svg`). */
19
+ text?: string;
20
+ /** Text size in mm. */
21
+ textSize?: number;
22
+ /** SVG source text (mutually exclusive with `text`). */
23
+ svg?: string;
24
+ /** SVG long-side target size in mm. */
25
+ svgSize?: number;
26
+ /** SVG logical width, used for the scale factor. */
27
+ svgNaturalWidth?: number;
28
+ /** SVG logical height, used for the scale factor. */
29
+ svgNaturalHeight?: number;
30
+ /** Extrusion depth in mm. */
31
+ depth: number;
32
+ }
33
+ /**
34
+ * Produces the decoration geometry (local space, `+Z` = extrusion direction) for
35
+ * `cad.engrave`'s mesh path.
36
+ */
37
+ export type EngraveDecorationProvider = (params: EngraveDecorationParams) => Promise<THREE.BufferGeometry>;
38
+ /**
39
+ * Install (or clear, with `null`) the mesh-decoration provider.
40
+ * @param next - the provider, or null to uninstall.
41
+ */
42
+ export declare function setEngraveDecorationProvider(next: EngraveDecorationProvider | null): void;
43
+ /**
44
+ * Read the installed mesh-decoration provider.
45
+ *
46
+ * `cad.engrave`'s mesh path calls this; a null result means the host installed
47
+ * no provider and the op reports the precise "install a provider" error rather
48
+ * than failing obscurely.
49
+ *
50
+ * @returns the installed mesh-decoration provider, or null when none is set.
51
+ */
52
+ export declare function getEngraveDecorationProvider(): EngraveDecorationProvider | null;
53
+ //# sourceMappingURL=decoration-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decoration-provider.d.ts","sourceRoot":"","sources":["../../src/mesh/decoration-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAEnC,8DAA8D;AAC9D,MAAM,WAAW,uBAAuB;IACtC,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uBAAuB;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oDAAoD;IACpD,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,qDAAqD;IACrD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;GAGG;AACH,MAAM,MAAM,yBAAyB,GAAG,CACtC,MAAM,EAAE,uBAAuB,KAC5B,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;AAIlC;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,yBAAyB,GAAG,IAAI,GAAG,IAAI,CAEzF;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,IAAI,yBAAyB,GAAG,IAAI,CAE/E"}
@@ -0,0 +1,21 @@
1
+ let provider = null;
2
+ /**
3
+ * Install (or clear, with `null`) the mesh-decoration provider.
4
+ * @param next - the provider, or null to uninstall.
5
+ */
6
+ export function setEngraveDecorationProvider(next) {
7
+ provider = next;
8
+ }
9
+ /**
10
+ * Read the installed mesh-decoration provider.
11
+ *
12
+ * `cad.engrave`'s mesh path calls this; a null result means the host installed
13
+ * no provider and the op reports the precise "install a provider" error rather
14
+ * than failing obscurely.
15
+ *
16
+ * @returns the installed mesh-decoration provider, or null when none is set.
17
+ */
18
+ export function getEngraveDecorationProvider() {
19
+ return provider;
20
+ }
21
+ //# sourceMappingURL=decoration-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decoration-provider.js","sourceRoot":"","sources":["../../src/mesh/decoration-provider.ts"],"names":[],"mappings":"AA0CA,IAAI,QAAQ,GAAqC,IAAI,CAAA;AAErD;;;GAGG;AACH,MAAM,UAAU,4BAA4B,CAAC,IAAsC;IACjF,QAAQ,GAAG,IAAI,CAAA;AACjB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,4BAA4B;IAC1C,OAAO,QAAQ,CAAA;AACjB,CAAC","sourcesContent":["/**\n * decoration-provider — host-injectable text/SVG decoration geometry.\n *\n * The `cad.engrave` op is a platform op (plan §4.2 C) but its decoration input\n * is text or SVG, whose mesh geometry is produced by three's non-basic chain\n * (`Shape` / `ExtrudeGeometry` / `SVGLoader`). That chain now lives in\n * `@faicad/faijs-extra`, so core asks the host for the decoration geometry\n * instead of importing it — the same capability-injection shape as\n * `setFontLoader` / `setKnurlTextureLoader`.\n *\n * With no provider installed, `cad.engrave` still works on its BREP path\n * (OCCT `textToSolid` / `svgToSolid`, zero three); only the **mesh** path needs\n * a provider, and it reports a precise error instead of failing obscurely.\n */\nimport type * as THREE from 'three'\n\n/** Decoration inputs `cad.engrave` passes to the provider. */\nexport interface EngraveDecorationParams {\n /** Text to engrave (mutually exclusive with `svg`). */\n text?: string\n /** Text size in mm. */\n textSize?: number\n /** SVG source text (mutually exclusive with `text`). */\n svg?: string\n /** SVG long-side target size in mm. */\n svgSize?: number\n /** SVG logical width, used for the scale factor. */\n svgNaturalWidth?: number\n /** SVG logical height, used for the scale factor. */\n svgNaturalHeight?: number\n /** Extrusion depth in mm. */\n depth: number\n}\n\n/**\n * Produces the decoration geometry (local space, `+Z` = extrusion direction) for\n * `cad.engrave`'s mesh path.\n */\nexport type EngraveDecorationProvider = (\n params: EngraveDecorationParams,\n) => Promise<THREE.BufferGeometry>\n\nlet provider: EngraveDecorationProvider | null = null\n\n/**\n * Install (or clear, with `null`) the mesh-decoration provider.\n * @param next - the provider, or null to uninstall.\n */\nexport function setEngraveDecorationProvider(next: EngraveDecorationProvider | null): void {\n provider = next\n}\n\n/**\n * Read the installed mesh-decoration provider.\n *\n * `cad.engrave`'s mesh path calls this; a null result means the host installed\n * no provider and the op reports the precise \"install a provider\" error rather\n * than failing obscurely.\n *\n * @returns the installed mesh-decoration provider, or null when none is set.\n */\nexport function getEngraveDecorationProvider(): EngraveDecorationProvider | null {\n return provider\n}\n"]}
@@ -17,6 +17,10 @@ import type { Shape, EngraveParams, KnurlParams } from './types.js';
17
17
  * position it onto a face, then run a boolean union (convex) or subtract
18
18
  * (concave).
19
19
  *
20
+ * The decoration geometry itself comes from the host-installed provider
21
+ * (`setEngraveDecorationProvider`) — three's `Shape`/`ExtrudeGeometry`/`SVGLoader`
22
+ * chain belongs to `@faicad/faijs-extra`, not to the platform surface.
23
+ *
20
24
  * @param shape - the world-space target shape.
21
25
  * @param params - engrave parameters (text/svg, depth, face, mode).
22
26
  * @returns the engraved shape in world space.
@@ -1 +1 @@
1
- {"version":3,"file":"engrave.d.ts","sourceRoot":"","sources":["../../src/mesh/engrave.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAEhE;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,CA0EjF;AAED;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CA8E7E"}
1
+ {"version":3,"file":"engrave.d.ts","sourceRoot":"","sources":["../../src/mesh/engrave.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAEhE;;;;;;;;;;;;GAYG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,CAyDjF;AAED;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,CA8E7E"}
@@ -13,50 +13,41 @@
13
13
  */
14
14
  import * as THREE from 'three';
15
15
  import { computeBoolean, geoToManifoldMesh, manifoldMeshToGeo } from '../boolean/csg-backend.js';
16
- import { svgToExtrudedGeometry } from '../primitives/svg-extrude.js';
16
+ import { getEngraveDecorationProvider } from './decoration-provider.js';
17
17
  /**
18
18
  * Execute an engraving: generate the decoration geometry (text or SVG),
19
19
  * position it onto a face, then run a boolean union (convex) or subtract
20
20
  * (concave).
21
21
  *
22
+ * The decoration geometry itself comes from the host-installed provider
23
+ * (`setEngraveDecorationProvider`) — three's `Shape`/`ExtrudeGeometry`/`SVGLoader`
24
+ * chain belongs to `@faicad/faijs-extra`, not to the platform surface.
25
+ *
22
26
  * @param shape - the world-space target shape.
23
27
  * @param params - engrave parameters (text/svg, depth, face, mode).
24
28
  * @returns the engraved shape in world space.
25
29
  */
26
30
  export async function engrave(shape, params) {
27
31
  // 1. 生成装饰几何(局部空间,+Z = 挤出方向)
28
- let decorationGeo;
29
- if (params.text) {
30
- if (!params.text)
31
- throw new Error('Text is empty');
32
- const { getOpentypeFont, createTextGeometry } = await import('../primitives/text-geometry.js');
33
- const { containsCjk, loadSystemCjkFont, createMixedTextGeometry } = await import('../primitives/text/cjk.js');
34
- const font = await getOpentypeFont();
35
- if (containsCjk(params.text)) {
36
- const cjkFont = await loadSystemCjkFont();
37
- if (cjkFont) {
38
- decorationGeo = await createMixedTextGeometry(params.text, params.textSize ?? 10, params.depth, cjkFont.font, font);
39
- }
40
- else {
41
- decorationGeo = await createTextGeometry(params.text, params.textSize ?? 10, params.depth, font);
42
- }
43
- }
44
- else {
45
- decorationGeo = await createTextGeometry(params.text, params.textSize ?? 10, params.depth, font);
46
- }
47
- }
48
- else if (params.svg) {
49
- // logo / SVG
50
- decorationGeo = svgToExtrudedGeometry(params.svg, {
51
- depth: params.depth,
52
- targetLongSide: params.svgSize,
53
- naturalWidth: params.svgNaturalWidth ?? 0,
54
- naturalHeight: params.svgNaturalHeight ?? 0,
55
- });
56
- }
57
- else {
32
+ if (!params.text && !params.svg) {
58
33
  throw new Error('engrave requires either text or svg');
59
34
  }
35
+ const provider = getEngraveDecorationProvider();
36
+ if (!provider) {
37
+ throw new Error('engrave: no mesh decoration provider installed — the text/SVG geometry chain ' +
38
+ 'lives in @faicad/faijs-extra; call setEngraveDecorationProvider() (or ' +
39
+ 'installEditorMeshProviders() from @faicad/faijs-extra) before engraving in mesh mode, ' +
40
+ 'or run the op on the BREP path');
41
+ }
42
+ const decorationGeo = await provider({
43
+ text: params.text,
44
+ textSize: params.textSize,
45
+ svg: params.svg,
46
+ svgSize: params.svgSize,
47
+ svgNaturalWidth: params.svgNaturalWidth,
48
+ svgNaturalHeight: params.svgNaturalHeight,
49
+ depth: params.depth,
50
+ });
60
51
  // 2. 定位装饰几何到面
61
52
  const faceCenter = new THREE.Vector3(...params.face.center);
62
53
  const faceNormal = new THREE.Vector3(...params.face.normal);
@@ -1 +1 @@
1
- {"version":3,"file":"engrave.js","sourceRoot":"","sources":["../../src/mesh/engrave.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * mesh 雕刻 API\n *\n * 提取来源:engine/components/engraving/EngravingCore.ts\n *\n * 从 executeEngraving 中提取纯几何计算部分:\n * 1. 生成装饰几何(文字或 SVG)\n * 2. 定位到面\n * 3. 布尔运算(凸=union,凹=subtract)\n *\n * 不包含:store 读写、commitGeometry、undo snapshot、toast。\n * 这些由执行器负责(P1 不改变现有执行器行为)。\n */\n\nimport * as THREE from 'three'\nimport { computeBoolean, geoToManifoldMesh, manifoldMeshToGeo } from '../boolean/csg-backend'\nimport { svgToExtrudedGeometry } from '../primitives/svg-extrude'\nimport type { Shape, EngraveParams, KnurlParams } from './types'\n\n/**\n * Execute an engraving: generate the decoration geometry (text or SVG),\n * position it onto a face, then run a boolean union (convex) or subtract\n * (concave).\n *\n * @param shape - the world-space target shape.\n * @param params - engrave parameters (text/svg, depth, face, mode).\n * @returns the engraved shape in world space.\n */\nexport async function engrave(shape: Shape, params: EngraveParams): Promise<Shape> {\n // 1. 生成装饰几何(局部空间,+Z = 挤出方向)\n let decorationGeo: THREE.BufferGeometry\n\n if (params.text) {\n if (!params.text) throw new Error('Text is empty')\n const { getOpentypeFont, createTextGeometry } = await import(\n '../primitives/text-geometry'\n )\n const { containsCjk, loadSystemCjkFont, createMixedTextGeometry } = await import(\n '../primitives/text/cjk'\n )\n const font = await getOpentypeFont()\n if (containsCjk(params.text)) {\n const cjkFont = await loadSystemCjkFont()\n if (cjkFont) {\n decorationGeo = await createMixedTextGeometry(\n params.text, params.textSize ?? 10, params.depth, cjkFont.font, font,\n )\n } else {\n decorationGeo = await createTextGeometry(\n params.text, params.textSize ?? 10, params.depth, font,\n )\n }\n } else {\n decorationGeo = await createTextGeometry(\n params.text, params.textSize ?? 10, params.depth, font,\n )\n }\n } else if (params.svg) {\n // logo / SVG\n decorationGeo = svgToExtrudedGeometry(params.svg, {\n depth: params.depth,\n targetLongSide: params.svgSize,\n naturalWidth: params.svgNaturalWidth ?? 0,\n naturalHeight: params.svgNaturalHeight ?? 0,\n })\n } else {\n throw new Error('engrave requires either text or svg')\n }\n\n // 2. 定位装饰几何到面\n const faceCenter = new THREE.Vector3(...params.face.center)\n const faceNormal = new THREE.Vector3(...params.face.normal)\n\n // Center geometry at origin\n decorationGeo.computeBoundingBox()\n const center = new THREE.Vector3()\n decorationGeo.boundingBox!.getCenter(center)\n decorationGeo.translate(-center.x, -center.y, -center.z)\n\n // Rotate +Z to align with face normal\n const quat = new THREE.Quaternion().setFromUnitVectors(\n new THREE.Vector3(0, 0, 1),\n faceNormal,\n )\n decorationGeo.applyQuaternion(quat)\n\n // Offset along normal (convex = outward, concave = inward)\n const offset = params.mode === 'convex' ? params.depth / 2 : -params.depth / 2\n const pos = faceCenter.clone().add(faceNormal.clone().multiplyScalar(offset))\n decorationGeo.translate(pos.x, pos.y, pos.z)\n\n // 3. 转换为 ManifoldMeshData\n const decorationData = geoToManifoldMesh(decorationGeo)\n\n // 4. 布尔运算\n const op = params.mode === 'convex' ? 'union' : 'subtract'\n const result = await computeBoolean([shape, decorationData], op)\n\n // 5. 清理\n decorationGeo.dispose()\n\n return result\n}\n\n/**\n * Apply a knurling texture displacement to a shape (vertex displacement, not a\n * boolean op). The replay path approximates UI face selection by excluding\n * faces whose normal deviates from the given face normal; the angle limits act\n * as an angular mask.\n *\n * @param shape - the world-space shape to knurl.\n * @param params - knurl parameters (texture height, refine length, UV scale, mapping mode).\n * @returns the displaced shape in world space.\n */\nexport async function knurl(shape: Shape, params: KnurlParams): Promise<Shape> {\n const { applyKnurlDisplacement, KNURL_DEFAULTS } = await import(\n './knurl/KnurlGenerator'\n )\n\n // 1. Shape → THREE.BufferGeometry\n const geo = manifoldMeshToGeo(shape, { computeNormals: true })\n\n // 2. 计算面排除权重:法向与 face.normal 不接近的面标记为排除\n const posAttr = geo.getAttribute('position')\n const triCount = posAttr.count / 3\n const faceNormal = new THREE.Vector3(...params.face.normal).normalize()\n\n // 计算每个三角形的法向\n const positions = posAttr.array as Float32Array\n const indices = geo.index ? (geo.index.array as Uint32Array) : null\n const faceWeights = new Float32Array(posAttr.count)\n\n const v0 = new THREE.Vector3()\n const v1 = new THREE.Vector3()\n const v2 = new THREE.Vector3()\n const edge1 = new THREE.Vector3()\n const edge2 = new THREE.Vector3()\n const triNormal = new THREE.Vector3()\n\n for (let t = 0; t < triCount; t++) {\n const i0 = indices ? indices[t * 3] : t * 3\n const i1 = indices ? indices[t * 3 + 1] : t * 3 + 1\n const i2 = indices ? indices[t * 3 + 2] : t * 3 + 2\n\n v0.set(positions[i0 * 3], positions[i0 * 3 + 1], positions[i0 * 3 + 2])\n v1.set(positions[i1 * 3], positions[i1 * 3 + 1], positions[i1 * 3 + 2])\n v2.set(positions[i2 * 3], positions[i2 * 3 + 1], positions[i2 * 3 + 2])\n\n edge1.subVectors(v1, v0)\n edge2.subVectors(v2, v0)\n triNormal.crossVectors(edge1, edge2).normalize()\n\n // 法向相似度:dot > 0.5 (~60° within) → 不排除\n const dot = triNormal.dot(faceNormal)\n if (dot < 0.5) {\n faceWeights[t * 3] = 1.0\n faceWeights[t * 3 + 1] = 1.0\n faceWeights[t * 3 + 2] = 1.0\n }\n }\n\n // 3. 计算包围盒\n geo.computeBoundingBox()\n const bb = geo.boundingBox!\n const partBounds = {\n min: bb.min.clone(),\n max: bb.max.clone(),\n size: new THREE.Vector3().subVectors(bb.max, bb.min),\n center: new THREE.Vector3().addVectors(bb.min, bb.max).multiplyScalar(0.5),\n }\n\n // 4. 调用 applyKnurlDisplacement\n const resultGeo = await applyKnurlDisplacement(\n geo,\n {\n ...KNURL_DEFAULTS,\n textureHeight: params.knurlTextureHeight,\n invertDisplacement: params.knurlInvertDisplacement,\n refineLength: params.knurlRefineLength,\n scaleU: params.knurlScaleU,\n scaleV: params.knurlScaleV,\n mappingMode: params.knurlMappingMode,\n faceWeights,\n },\n undefined,\n partBounds,\n )\n\n geo.dispose()\n\n // 5. THREE.BufferGeometry → Shape\n return geoToManifoldMesh(resultGeo)\n}\n"]}
1
+ {"version":3,"file":"engrave.js","sourceRoot":"","sources":["../../src/mesh/engrave.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * mesh 雕刻 API\n *\n * 提取来源:engine/components/engraving/EngravingCore.ts\n *\n * 从 executeEngraving 中提取纯几何计算部分:\n * 1. 生成装饰几何(文字或 SVG)\n * 2. 定位到面\n * 3. 布尔运算(凸=union,凹=subtract)\n *\n * 不包含:store 读写、commitGeometry、undo snapshot、toast。\n * 这些由执行器负责(P1 不改变现有执行器行为)。\n */\n\nimport * as THREE from 'three'\nimport { computeBoolean, geoToManifoldMesh, manifoldMeshToGeo } from '../boolean/csg-backend'\nimport { getEngraveDecorationProvider } from './decoration-provider'\nimport type { Shape, EngraveParams, KnurlParams } from './types'\n\n/**\n * Execute an engraving: generate the decoration geometry (text or SVG),\n * position it onto a face, then run a boolean union (convex) or subtract\n * (concave).\n *\n * The decoration geometry itself comes from the host-installed provider\n * (`setEngraveDecorationProvider`) — three's `Shape`/`ExtrudeGeometry`/`SVGLoader`\n * chain belongs to `@faicad/faijs-extra`, not to the platform surface.\n *\n * @param shape - the world-space target shape.\n * @param params - engrave parameters (text/svg, depth, face, mode).\n * @returns the engraved shape in world space.\n */\nexport async function engrave(shape: Shape, params: EngraveParams): Promise<Shape> {\n // 1. 生成装饰几何(局部空间,+Z = 挤出方向)\n if (!params.text && !params.svg) {\n throw new Error('engrave requires either text or svg')\n }\n const provider = getEngraveDecorationProvider()\n if (!provider) {\n throw new Error(\n 'engrave: no mesh decoration provider installed — the text/SVG geometry chain ' +\n 'lives in @faicad/faijs-extra; call setEngraveDecorationProvider() (or ' +\n 'installEditorMeshProviders() from @faicad/faijs-extra) before engraving in mesh mode, ' +\n 'or run the op on the BREP path',\n )\n }\n const decorationGeo: THREE.BufferGeometry = await provider({\n text: params.text,\n textSize: params.textSize,\n svg: params.svg,\n svgSize: params.svgSize,\n svgNaturalWidth: params.svgNaturalWidth,\n svgNaturalHeight: params.svgNaturalHeight,\n depth: params.depth,\n })\n\n // 2. 定位装饰几何到面\n const faceCenter = new THREE.Vector3(...params.face.center)\n const faceNormal = new THREE.Vector3(...params.face.normal)\n\n // Center geometry at origin\n decorationGeo.computeBoundingBox()\n const center = new THREE.Vector3()\n decorationGeo.boundingBox!.getCenter(center)\n decorationGeo.translate(-center.x, -center.y, -center.z)\n\n // Rotate +Z to align with face normal\n const quat = new THREE.Quaternion().setFromUnitVectors(\n new THREE.Vector3(0, 0, 1),\n faceNormal,\n )\n decorationGeo.applyQuaternion(quat)\n\n // Offset along normal (convex = outward, concave = inward)\n const offset = params.mode === 'convex' ? params.depth / 2 : -params.depth / 2\n const pos = faceCenter.clone().add(faceNormal.clone().multiplyScalar(offset))\n decorationGeo.translate(pos.x, pos.y, pos.z)\n\n // 3. 转换为 ManifoldMeshData\n const decorationData = geoToManifoldMesh(decorationGeo)\n\n // 4. 布尔运算\n const op = params.mode === 'convex' ? 'union' : 'subtract'\n const result = await computeBoolean([shape, decorationData], op)\n\n // 5. 清理\n decorationGeo.dispose()\n\n return result\n}\n\n/**\n * Apply a knurling texture displacement to a shape (vertex displacement, not a\n * boolean op). The replay path approximates UI face selection by excluding\n * faces whose normal deviates from the given face normal; the angle limits act\n * as an angular mask.\n *\n * @param shape - the world-space shape to knurl.\n * @param params - knurl parameters (texture height, refine length, UV scale, mapping mode).\n * @returns the displaced shape in world space.\n */\nexport async function knurl(shape: Shape, params: KnurlParams): Promise<Shape> {\n const { applyKnurlDisplacement, KNURL_DEFAULTS } = await import(\n './knurl/KnurlGenerator'\n )\n\n // 1. Shape → THREE.BufferGeometry\n const geo = manifoldMeshToGeo(shape, { computeNormals: true })\n\n // 2. 计算面排除权重:法向与 face.normal 不接近的面标记为排除\n const posAttr = geo.getAttribute('position')\n const triCount = posAttr.count / 3\n const faceNormal = new THREE.Vector3(...params.face.normal).normalize()\n\n // 计算每个三角形的法向\n const positions = posAttr.array as Float32Array\n const indices = geo.index ? (geo.index.array as Uint32Array) : null\n const faceWeights = new Float32Array(posAttr.count)\n\n const v0 = new THREE.Vector3()\n const v1 = new THREE.Vector3()\n const v2 = new THREE.Vector3()\n const edge1 = new THREE.Vector3()\n const edge2 = new THREE.Vector3()\n const triNormal = new THREE.Vector3()\n\n for (let t = 0; t < triCount; t++) {\n const i0 = indices ? indices[t * 3] : t * 3\n const i1 = indices ? indices[t * 3 + 1] : t * 3 + 1\n const i2 = indices ? indices[t * 3 + 2] : t * 3 + 2\n\n v0.set(positions[i0 * 3], positions[i0 * 3 + 1], positions[i0 * 3 + 2])\n v1.set(positions[i1 * 3], positions[i1 * 3 + 1], positions[i1 * 3 + 2])\n v2.set(positions[i2 * 3], positions[i2 * 3 + 1], positions[i2 * 3 + 2])\n\n edge1.subVectors(v1, v0)\n edge2.subVectors(v2, v0)\n triNormal.crossVectors(edge1, edge2).normalize()\n\n // 法向相似度:dot > 0.5 (~60° within) → 不排除\n const dot = triNormal.dot(faceNormal)\n if (dot < 0.5) {\n faceWeights[t * 3] = 1.0\n faceWeights[t * 3 + 1] = 1.0\n faceWeights[t * 3 + 2] = 1.0\n }\n }\n\n // 3. 计算包围盒\n geo.computeBoundingBox()\n const bb = geo.boundingBox!\n const partBounds = {\n min: bb.min.clone(),\n max: bb.max.clone(),\n size: new THREE.Vector3().subVectors(bb.max, bb.min),\n center: new THREE.Vector3().addVectors(bb.min, bb.max).multiplyScalar(0.5),\n }\n\n // 4. 调用 applyKnurlDisplacement\n const resultGeo = await applyKnurlDisplacement(\n geo,\n {\n ...KNURL_DEFAULTS,\n textureHeight: params.knurlTextureHeight,\n invertDisplacement: params.knurlInvertDisplacement,\n refineLength: params.knurlRefineLength,\n scaleU: params.knurlScaleU,\n scaleV: params.knurlScaleV,\n mappingMode: params.knurlMappingMode,\n faceWeights,\n },\n undefined,\n partBounds,\n )\n\n geo.dispose()\n\n // 5. THREE.BufferGeometry → Shape\n return geoToManifoldMesh(resultGeo)\n}\n"]}