@faicad/faijs 0.33.1 → 0.35.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (392) hide show
  1. package/dist/api/api-namespace.d.ts +14 -14
  2. package/dist/api/api-namespace.d.ts.map +1 -1
  3. package/dist/api/api-namespace.js +40 -14
  4. package/dist/api/api-namespace.js.map +1 -1
  5. package/dist/api/appearance.d.ts +47 -6
  6. package/dist/api/appearance.d.ts.map +1 -1
  7. package/dist/api/appearance.js.map +1 -1
  8. package/dist/api/assembly/solve-tree.d.ts +1 -0
  9. package/dist/api/assembly/solve-tree.d.ts.map +1 -1
  10. package/dist/api/assembly/solve-tree.js +42 -17
  11. package/dist/api/assembly/solve-tree.js.map +1 -1
  12. package/dist/api/assembly/solve.d.ts +1 -0
  13. package/dist/api/assembly/solve.d.ts.map +1 -1
  14. package/dist/api/assembly/solve.js.map +1 -1
  15. package/dist/api/assembly/solvers/global-solver.d.ts.map +1 -1
  16. package/dist/api/assembly/solvers/global-solver.js +130 -23
  17. package/dist/api/assembly/solvers/global-solver.js.map +1 -1
  18. package/dist/api/assembly/solvers/pose-from-delta.d.ts +9 -0
  19. package/dist/api/assembly/solvers/pose-from-delta.d.ts.map +1 -1
  20. package/dist/api/assembly/solvers/pose-from-delta.js +23 -0
  21. package/dist/api/assembly/solvers/pose-from-delta.js.map +1 -1
  22. package/dist/api/assembly/solvers/types.d.ts +20 -2
  23. package/dist/api/assembly/solvers/types.d.ts.map +1 -1
  24. package/dist/api/assembly/solvers/types.js.map +1 -1
  25. package/dist/api/chamfer.d.ts +7 -4
  26. package/dist/api/chamfer.d.ts.map +1 -1
  27. package/dist/api/chamfer.js +57 -13
  28. package/dist/api/chamfer.js.map +1 -1
  29. package/dist/api/draft.d.ts +7 -4
  30. package/dist/api/draft.d.ts.map +1 -1
  31. package/dist/api/draft.js +11 -6
  32. package/dist/api/draft.js.map +1 -1
  33. package/dist/api/edge-ref.d.ts +4 -4
  34. package/dist/api/edge-ref.js +4 -4
  35. package/dist/api/edge-ref.js.map +1 -1
  36. package/dist/api/extrude.d.ts +10 -6
  37. package/dist/api/extrude.d.ts.map +1 -1
  38. package/dist/api/extrude.js +50 -25
  39. package/dist/api/extrude.js.map +1 -1
  40. package/dist/api/face-ref.d.ts +4 -4
  41. package/dist/api/face-ref.js +4 -4
  42. package/dist/api/face-ref.js.map +1 -1
  43. package/dist/api/feature-repair.d.ts +6 -3
  44. package/dist/api/feature-repair.d.ts.map +1 -1
  45. package/dist/api/feature-repair.js +12 -7
  46. package/dist/api/feature-repair.js.map +1 -1
  47. package/dist/api/fillet-variable.d.ts +6 -2
  48. package/dist/api/fillet-variable.d.ts.map +1 -1
  49. package/dist/api/fillet-variable.js +24 -6
  50. package/dist/api/fillet-variable.js.map +1 -1
  51. package/dist/api/fillet.d.ts +7 -4
  52. package/dist/api/fillet.d.ts.map +1 -1
  53. package/dist/api/fillet.js +45 -12
  54. package/dist/api/fillet.js.map +1 -1
  55. package/dist/api/helix.d.ts +13 -13
  56. package/dist/api/helix.d.ts.map +1 -1
  57. package/dist/api/helix.js +19 -24
  58. package/dist/api/helix.js.map +1 -1
  59. package/dist/api/import-brep.d.ts +10 -18
  60. package/dist/api/import-brep.d.ts.map +1 -1
  61. package/dist/api/import-brep.js +17 -25
  62. package/dist/api/import-brep.js.map +1 -1
  63. package/dist/api/import-step.d.ts +10 -15
  64. package/dist/api/import-step.d.ts.map +1 -1
  65. package/dist/api/import-step.js +24 -29
  66. package/dist/api/import-step.js.map +1 -1
  67. package/dist/api/index.js +2 -2
  68. package/dist/api/index.js.map +1 -1
  69. package/dist/api/internal/export-members.js.map +1 -1
  70. package/dist/api/loft-advanced.d.ts +4 -0
  71. package/dist/api/loft-advanced.d.ts.map +1 -1
  72. package/dist/api/loft-advanced.js +4 -0
  73. package/dist/api/loft-advanced.js.map +1 -1
  74. package/dist/api/loft.d.ts +5 -3
  75. package/dist/api/loft.d.ts.map +1 -1
  76. package/dist/api/loft.js +5 -3
  77. package/dist/api/loft.js.map +1 -1
  78. package/dist/api/meta.d.ts +42 -6
  79. package/dist/api/meta.d.ts.map +1 -1
  80. package/dist/api/meta.js.map +1 -1
  81. package/dist/api/punch-hole.d.ts +5 -2
  82. package/dist/api/punch-hole.d.ts.map +1 -1
  83. package/dist/api/punch-hole.js +4 -1
  84. package/dist/api/punch-hole.js.map +1 -1
  85. package/dist/api/replicate.d.ts +4 -5
  86. package/dist/api/replicate.d.ts.map +1 -1
  87. package/dist/api/replicate.js +4 -5
  88. package/dist/api/replicate.js.map +1 -1
  89. package/dist/api/selectors-to-refs.d.ts +83 -0
  90. package/dist/api/selectors-to-refs.d.ts.map +1 -0
  91. package/dist/api/selectors-to-refs.js +211 -0
  92. package/dist/api/selectors-to-refs.js.map +1 -0
  93. package/dist/api/shell.d.ts +17 -8
  94. package/dist/api/shell.d.ts.map +1 -1
  95. package/dist/api/shell.js +45 -15
  96. package/dist/api/shell.js.map +1 -1
  97. package/dist/api/sketch-on-face.d.ts +12 -6
  98. package/dist/api/sketch-on-face.d.ts.map +1 -1
  99. package/dist/api/sketch-on-face.js +31 -4
  100. package/dist/api/sketch-on-face.js.map +1 -1
  101. package/dist/api/sketch-on-plane.d.ts +3 -0
  102. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  103. package/dist/api/sketch-on-plane.js +3 -0
  104. package/dist/api/sketch-on-plane.js.map +1 -1
  105. package/dist/api/sketch-on-surface.d.ts +4 -1
  106. package/dist/api/sketch-on-surface.d.ts.map +1 -1
  107. package/dist/api/sketch-on-surface.js +4 -1
  108. package/dist/api/sketch-on-surface.js.map +1 -1
  109. package/dist/api/view/view-projection.d.ts.map +1 -1
  110. package/dist/api/view/view-projection.js +9 -2
  111. package/dist/api/view/view-projection.js.map +1 -1
  112. package/dist/brep/brep-chain.js +2 -2
  113. package/dist/brep/brep-chain.js.map +1 -1
  114. package/dist/brep/brep-ops.d.ts +1 -1
  115. package/dist/brep/brep-ops.js +1 -1
  116. package/dist/brep/brep-ops.js.map +1 -1
  117. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  118. package/dist/brep/engine/adapters/brep-mock.js +45 -0
  119. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  120. package/dist/brep/engine/primitives.d.ts +87 -3
  121. package/dist/brep/engine/primitives.d.ts.map +1 -1
  122. package/dist/brep/engine/primitives.js +1 -1
  123. package/dist/brep/engine/primitives.js.map +1 -1
  124. package/dist/brep/engine/registry.d.ts +33 -7
  125. package/dist/brep/engine/registry.d.ts.map +1 -1
  126. package/dist/brep/engine/registry.js +47 -16
  127. package/dist/brep/engine/registry.js.map +1 -1
  128. package/dist/brep/handle-bridge.d.ts +14 -15
  129. package/dist/brep/handle-bridge.d.ts.map +1 -1
  130. package/dist/brep/handle-bridge.js +35 -15
  131. package/dist/brep/handle-bridge.js.map +1 -1
  132. package/dist/brep/primitives-brep.js +2 -2
  133. package/dist/brep/primitives-brep.js.map +1 -1
  134. package/dist/brep/text/text-to-solid.d.ts +40 -3
  135. package/dist/brep/text/text-to-solid.d.ts.map +1 -1
  136. package/dist/brep/text/text-to-solid.js +104 -24
  137. package/dist/brep/text/text-to-solid.js.map +1 -1
  138. package/dist/brepkit-kernel/brepkitKernel.d.ts +2 -2
  139. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  140. package/dist/brepkit-kernel/brepkitKernel.js +315 -36
  141. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  142. package/dist/brepkit-kernel/brepkitWasm.js +7 -7
  143. package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
  144. package/dist/brepkit-kernel/multi-version-test.d.ts +2 -2
  145. package/dist/brepkit-kernel/multi-version-test.d.ts.map +1 -1
  146. package/dist/brepkit-kernel/multi-version-test.js +6 -6
  147. package/dist/brepkit-kernel/multi-version-test.js.map +1 -1
  148. package/dist/browser.d.ts +2 -3
  149. package/dist/browser.d.ts.map +1 -1
  150. package/dist/browser.js +1 -2
  151. package/dist/browser.js.map +1 -1
  152. package/dist/cad-runtime/admit-compat-lib.d.ts +9 -1
  153. package/dist/cad-runtime/admit-compat-lib.d.ts.map +1 -1
  154. package/dist/cad-runtime/admit-compat-lib.js +11 -1
  155. package/dist/cad-runtime/admit-compat-lib.js.map +1 -1
  156. package/dist/cad-runtime/browser-lib-loader.d.ts +16 -11
  157. package/dist/cad-runtime/browser-lib-loader.d.ts.map +1 -1
  158. package/dist/cad-runtime/browser-lib-loader.js +16 -8
  159. package/dist/cad-runtime/browser-lib-loader.js.map +1 -1
  160. package/dist/cad-runtime/direct-executor.d.ts +62 -5
  161. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  162. package/dist/cad-runtime/direct-executor.js +617 -42
  163. package/dist/cad-runtime/direct-executor.js.map +1 -1
  164. package/dist/cad-runtime/interp/closure.d.ts +3 -2
  165. package/dist/cad-runtime/interp/closure.d.ts.map +1 -1
  166. package/dist/cad-runtime/interp/closure.js.map +1 -1
  167. package/dist/cad-runtime/interp/env.d.ts +9 -6
  168. package/dist/cad-runtime/interp/env.d.ts.map +1 -1
  169. package/dist/cad-runtime/interp/env.js +4 -2
  170. package/dist/cad-runtime/interp/env.js.map +1 -1
  171. package/dist/cad-runtime/lib-decl.d.ts +121 -0
  172. package/dist/cad-runtime/lib-decl.d.ts.map +1 -0
  173. package/dist/cad-runtime/lib-decl.js +100 -0
  174. package/dist/cad-runtime/lib-decl.js.map +1 -0
  175. package/dist/cad-runtime/ports.d.ts +12 -0
  176. package/dist/cad-runtime/ports.d.ts.map +1 -1
  177. package/dist/cad-runtime/ports.js.map +1 -1
  178. package/dist/cad-runtime/runtime.d.ts +59 -5
  179. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  180. package/dist/cad-runtime/runtime.js +237 -18
  181. package/dist/cad-runtime/runtime.js.map +1 -1
  182. package/dist/extra/browser.d.ts +9 -0
  183. package/dist/extra/browser.d.ts.map +1 -0
  184. package/dist/extra/browser.js +9 -0
  185. package/dist/extra/browser.js.map +1 -0
  186. package/dist/extra/editor-ops.d.ts +22 -0
  187. package/dist/extra/editor-ops.d.ts.map +1 -0
  188. package/dist/extra/editor-ops.js +21 -0
  189. package/dist/extra/editor-ops.js.map +1 -0
  190. package/dist/extra/extras/svg-extrude.d.ts +45 -0
  191. package/dist/extra/extras/svg-extrude.d.ts.map +1 -0
  192. package/dist/extra/extras/svg-extrude.js +110 -0
  193. package/dist/extra/extras/svg-extrude.js.map +1 -0
  194. package/dist/extra/extras/text-cjk.d.ts +36 -0
  195. package/dist/extra/extras/text-cjk.d.ts.map +1 -0
  196. package/dist/extra/extras/text-cjk.js +86 -0
  197. package/dist/extra/extras/text-cjk.js.map +1 -0
  198. package/dist/extra/extras/text-geometry.d.ts +69 -0
  199. package/dist/extra/extras/text-geometry.d.ts.map +1 -0
  200. package/dist/extra/extras/text-geometry.js +188 -0
  201. package/dist/extra/extras/text-geometry.js.map +1 -0
  202. package/dist/extra/index.d.ts +40 -0
  203. package/dist/extra/index.d.ts.map +1 -0
  204. package/dist/extra/index.js +40 -0
  205. package/dist/extra/index.js.map +1 -0
  206. package/dist/extra/mesh/drill-hole/DrillHoleCore.d.ts +94 -0
  207. package/dist/extra/mesh/drill-hole/DrillHoleCore.d.ts.map +1 -0
  208. package/dist/extra/mesh/drill-hole/DrillHoleCore.js +282 -0
  209. package/dist/extra/mesh/drill-hole/DrillHoleCore.js.map +1 -0
  210. package/dist/extra/mesh/drill-hole/drill-types.d.ts +34 -0
  211. package/dist/extra/mesh/drill-hole/drill-types.d.ts.map +1 -0
  212. package/dist/extra/mesh/drill-hole/drill-types.js +7 -0
  213. package/dist/extra/mesh/drill-hole/drill-types.js.map +1 -0
  214. package/dist/extra/mesh/engrave-decoration.d.ts +42 -0
  215. package/dist/extra/mesh/engrave-decoration.d.ts.map +1 -0
  216. package/dist/extra/mesh/engrave-decoration.js +39 -0
  217. package/dist/extra/mesh/engrave-decoration.js.map +1 -0
  218. package/dist/extra/mesh/fai_drill.d.ts +21 -0
  219. package/dist/extra/mesh/fai_drill.d.ts.map +1 -0
  220. package/dist/extra/mesh/fai_drill.js +89 -0
  221. package/dist/extra/mesh/fai_drill.js.map +1 -0
  222. package/dist/extra/mesh/fai_extrude.d.ts +24 -0
  223. package/dist/extra/mesh/fai_extrude.d.ts.map +1 -0
  224. package/dist/extra/mesh/fai_extrude.js +42 -0
  225. package/dist/extra/mesh/fai_extrude.js.map +1 -0
  226. package/dist/extra/mesh/fai_split.d.ts +164 -0
  227. package/dist/extra/mesh/fai_split.d.ts.map +1 -0
  228. package/dist/extra/mesh/fai_split.js +269 -0
  229. package/dist/extra/mesh/fai_split.js.map +1 -0
  230. package/dist/extra/mesh/primitives.d.ts +29 -0
  231. package/dist/extra/mesh/primitives.d.ts.map +1 -0
  232. package/dist/extra/mesh/primitives.js +41 -0
  233. package/dist/extra/mesh/primitives.js.map +1 -0
  234. package/dist/extra/op-names.d.ts +37 -0
  235. package/dist/extra/op-names.d.ts.map +1 -0
  236. package/dist/extra/op-names.js +46 -0
  237. package/dist/extra/op-names.js.map +1 -0
  238. package/dist/extra/ops/compound.d.ts +140 -0
  239. package/dist/extra/ops/compound.d.ts.map +1 -0
  240. package/dist/extra/ops/compound.js +167 -0
  241. package/dist/extra/ops/compound.js.map +1 -0
  242. package/dist/extra/ops/copy.d.ts +40 -0
  243. package/dist/extra/ops/copy.d.ts.map +1 -0
  244. package/dist/extra/ops/copy.js +83 -0
  245. package/dist/extra/ops/copy.js.map +1 -0
  246. package/dist/extra/ops/fai_drill.d.ts +51 -0
  247. package/dist/extra/ops/fai_drill.d.ts.map +1 -0
  248. package/dist/extra/ops/fai_drill.js +233 -0
  249. package/dist/extra/ops/fai_drill.js.map +1 -0
  250. package/dist/extra/ops/fai_extrude.d.ts +36 -0
  251. package/dist/extra/ops/fai_extrude.d.ts.map +1 -0
  252. package/dist/extra/ops/fai_extrude.js +84 -0
  253. package/dist/extra/ops/fai_extrude.js.map +1 -0
  254. package/dist/extra/ops/fai_split.d.ts +46 -0
  255. package/dist/extra/ops/fai_split.d.ts.map +1 -0
  256. package/dist/extra/ops/fai_split.js +235 -0
  257. package/dist/extra/ops/fai_split.js.map +1 -0
  258. package/dist/extra/ops/load.d.ts +49 -0
  259. package/dist/extra/ops/load.d.ts.map +1 -0
  260. package/dist/extra/ops/load.js +385 -0
  261. package/dist/extra/ops/load.js.map +1 -0
  262. package/dist/extra/ops/svg-extrude.d.ts +32 -0
  263. package/dist/extra/ops/svg-extrude.d.ts.map +1 -0
  264. package/dist/extra/ops/svg-extrude.js +74 -0
  265. package/dist/extra/ops/svg-extrude.js.map +1 -0
  266. package/dist/extra/ops/text.d.ts +34 -0
  267. package/dist/extra/ops/text.d.ts.map +1 -0
  268. package/dist/extra/ops/text.js +100 -0
  269. package/dist/extra/ops/text.js.map +1 -0
  270. package/dist/geometry2d/bridge/lift-on-plane.d.ts +8 -5
  271. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -1
  272. package/dist/geometry2d/bridge/lift-on-plane.js +8 -5
  273. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -1
  274. package/dist/index.d.ts +6 -2
  275. package/dist/index.d.ts.map +1 -1
  276. package/dist/index.js +8 -2
  277. package/dist/index.js.map +1 -1
  278. package/dist/lang/symbol-table.d.ts +3 -3
  279. package/dist/lang/symbol-table.generated.d.ts +10 -0
  280. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  281. package/dist/lang/symbol-table.generated.js +10 -0
  282. package/dist/lang/symbol-table.generated.js.map +1 -1
  283. package/dist/lang/symbol-table.js +3 -3
  284. package/dist/lang/symbol-table.js.map +1 -1
  285. package/dist/math3d/index.d.ts +1 -1
  286. package/dist/math3d/index.js +1 -1
  287. package/dist/math3d/index.js.map +1 -1
  288. package/dist/mesh/engrave.d.ts +2 -3
  289. package/dist/mesh/engrave.d.ts.map +1 -1
  290. package/dist/mesh/engrave.js +4 -11
  291. package/dist/mesh/engrave.js.map +1 -1
  292. package/dist/mesh/index.d.ts +0 -2
  293. package/dist/mesh/index.d.ts.map +1 -1
  294. package/dist/mesh/index.js +0 -2
  295. package/dist/mesh/index.js.map +1 -1
  296. package/dist/mesh/primitives.d.ts +1 -1
  297. package/dist/mesh/primitives.js +1 -1
  298. package/dist/mesh/primitives.js.map +1 -1
  299. package/dist/node-host/cli.d.ts +20 -4
  300. package/dist/node-host/cli.d.ts.map +1 -1
  301. package/dist/node-host/cli.js +84 -35
  302. package/dist/node-host/cli.js.map +1 -1
  303. package/dist/node-host/execute-script.d.ts.map +1 -1
  304. package/dist/node-host/execute-script.js +3 -4
  305. package/dist/node-host/execute-script.js.map +1 -1
  306. package/dist/node-host/lib-package-json.d.ts +36 -0
  307. package/dist/node-host/lib-package-json.d.ts.map +1 -0
  308. package/dist/node-host/lib-package-json.js +73 -0
  309. package/dist/node-host/lib-package-json.js.map +1 -0
  310. package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
  311. package/dist/occt-kernel/occt-primitives.js +41 -0
  312. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  313. package/dist/occt-kernel/occtKernel.d.ts +1 -1
  314. package/dist/occt-kernel/occtKernel.js +1 -1
  315. package/dist/occt-kernel/occtKernel.js.map +1 -1
  316. package/dist/runtime-state.d.ts +28 -1
  317. package/dist/runtime-state.d.ts.map +1 -1
  318. package/dist/runtime-state.js +14 -1
  319. package/dist/runtime-state.js.map +1 -1
  320. package/dist/sdk.d.ts +2 -2
  321. package/dist/sdk.d.ts.map +1 -1
  322. package/dist/sdk.js +11 -2
  323. package/dist/sdk.js.map +1 -1
  324. package/dist/sketch/bspline.d.ts +58 -0
  325. package/dist/sketch/bspline.d.ts.map +1 -0
  326. package/dist/sketch/bspline.js +104 -0
  327. package/dist/sketch/bspline.js.map +1 -0
  328. package/dist/sketch/canonical.d.ts +239 -0
  329. package/dist/sketch/canonical.d.ts.map +1 -0
  330. package/dist/sketch/canonical.js +17 -0
  331. package/dist/sketch/canonical.js.map +1 -0
  332. package/dist/sketch/contour.d.ts +43 -0
  333. package/dist/sketch/contour.d.ts.map +1 -0
  334. package/dist/sketch/contour.js +202 -0
  335. package/dist/sketch/contour.js.map +1 -0
  336. package/dist/sketch/dim-spec.d.ts +32 -0
  337. package/dist/sketch/dim-spec.d.ts.map +1 -0
  338. package/dist/sketch/dim-spec.js +112 -0
  339. package/dist/sketch/dim-spec.js.map +1 -0
  340. package/dist/sketch/faces.d.ts +45 -0
  341. package/dist/sketch/faces.d.ts.map +1 -0
  342. package/dist/sketch/faces.js +108 -0
  343. package/dist/sketch/faces.js.map +1 -0
  344. package/dist/sketch/fcstd-types.d.ts +194 -0
  345. package/dist/sketch/fcstd-types.d.ts.map +1 -0
  346. package/dist/sketch/fcstd-types.js +67 -0
  347. package/dist/sketch/fcstd-types.js.map +1 -0
  348. package/dist/sketch/index.d.ts +46 -0
  349. package/dist/sketch/index.d.ts.map +1 -0
  350. package/dist/sketch/index.js +39 -0
  351. package/dist/sketch/index.js.map +1 -0
  352. package/dist/sketch/node.d.ts +14 -0
  353. package/dist/sketch/node.d.ts.map +1 -0
  354. package/dist/sketch/node.js +43 -0
  355. package/dist/sketch/node.js.map +1 -0
  356. package/dist/sketch/op.d.ts +111 -0
  357. package/dist/sketch/op.d.ts.map +1 -0
  358. package/dist/sketch/op.js +185 -0
  359. package/dist/sketch/op.js.map +1 -0
  360. package/dist/sketch/planegcs-backend.d.ts +69 -0
  361. package/dist/sketch/planegcs-backend.d.ts.map +1 -0
  362. package/dist/sketch/planegcs-backend.js +812 -0
  363. package/dist/sketch/planegcs-backend.js.map +1 -0
  364. package/dist/sketch/project.d.ts +176 -0
  365. package/dist/sketch/project.d.ts.map +1 -0
  366. package/dist/sketch/project.js +656 -0
  367. package/dist/sketch/project.js.map +1 -0
  368. package/dist/sketch/shapes.d.ts +370 -0
  369. package/dist/sketch/shapes.d.ts.map +1 -0
  370. package/dist/sketch/shapes.js +959 -0
  371. package/dist/sketch/shapes.js.map +1 -0
  372. package/dist/sketch/solve.d.ts +21 -0
  373. package/dist/sketch/solve.d.ts.map +1 -0
  374. package/dist/sketch/solve.js +144 -0
  375. package/dist/sketch/solve.js.map +1 -0
  376. package/dist/sketch/solver-loader.d.ts +47 -0
  377. package/dist/sketch/solver-loader.d.ts.map +1 -0
  378. package/dist/sketch/solver-loader.js +77 -0
  379. package/dist/sketch/solver-loader.js.map +1 -0
  380. package/dist/sketch/solver.d.ts +63 -0
  381. package/dist/sketch/solver.d.ts.map +1 -0
  382. package/dist/sketch/solver.js +28 -0
  383. package/dist/sketch/solver.js.map +1 -0
  384. package/dist/sketch/verify.d.ts +53 -0
  385. package/dist/sketch/verify.d.ts.map +1 -0
  386. package/dist/sketch/verify.js +71 -0
  387. package/dist/sketch/verify.js.map +1 -0
  388. package/dist/weapp.d.ts +1 -1
  389. package/dist/weapp.d.ts.map +1 -1
  390. package/dist/weapp.js +1 -1
  391. package/dist/weapp.js.map +1 -1
  392. package/package.json +43 -11
@@ -1 +1 @@
1
- {"version":3,"file":"solve-tree.js","sourceRoot":"","sources":["../../../src/api/assembly/solve-tree.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api/assembly/solve-tree — 嵌套子装配求解(P4,方案 §4.2)\n *\n * flatten → solveGlobal → recompose:\n * 1. flatten:walkAssembly 收集叶 shape + qualified member name(如 `subassy.part`),\n * 构建扁平 members/memberNames;约束从各层收集(part 名用 qualified name,可跨层引用)。\n * 2. solve:调 solveGlobal 求解扁平问题。\n * 3. recompose:自顶向下将父变换(AssemblyNode.translate/rotate)与 solver 变换复合\n * (parentTransform ∘ childLocalTransform),得到每个叶节点的世界变换。\n *\n * 语义对齐 CQ `Assembly.solve()`:每个对象的 `loc` 累积合成世界变换。\n * faijs Shape 不携带 placement → 求解器从 identity 初值求解;父变换在 recompose 阶段复合。\n */\n\nimport type { Shape } from '../../mesh/types'\nimport type { AssemblyTransform } from '../../runtime-state'\nimport type { AssemblyConstraint } from './types'\nimport type { SolveOptions } from './solvers/types'\nimport type { AssemblyNode } from './solvers/assembly-tree'\nimport { solveGlobal } from './solvers/global-solver'\nimport { poseToAssemblyTransform, toBrepjsQuat, isIdentityPose, type SolverPose } from './pose'\nimport { quatFromAxisAngle, quatRotate, quatMultiply } from './solvers/quat'\n\nconst DEG2RAD = Math.PI / 180\n\n/** 嵌套子装配求解结果:per-leaf 世界变换 + 诊断量。 */\nexport interface AssemblyTreeSolveResult {\n /** 每个叶节点的世界变换(键 = qualified name)。 */\n transforms: Record<string, AssemblyTransform>\n /** 是否全部约束可解。 */\n converged: boolean\n /** 无法求解的约束明细。 */\n unsupported: string[]\n /** 逐约束最终残差。 */\n residuals: number[]\n /** 残差超阈值的约束逐条写入。 */\n warnings?: string[]\n /**\n * P7/D1-3:欠定自由度诊断(透传自 solveGlobal)。dof > 0 = 约束集欠定,\n * 终态位姿依赖优化器轨迹、无唯一「正确解」——判等方应走规范判等通道而非逐位比对。\n */\n underdetermined?: { dof: number }\n}\n\n\n/** 把 AssemblyNode 的 translate/rotate 转为 SolverPose(brepjs [w,x,y,z] 旋转)。 */\nfunction nodeToPose(node: AssemblyNode): SolverPose {\n const position: [number, number, number] = node.translate\n ? [node.translate[0], node.translate[1], node.translate[2]]\n : [0, 0, 0]\n let rotation: [number, number, number, number] = [1, 0, 0, 0]\n if (node.rotate) {\n const axis: readonly [number, number, number] = node.rotate.axis\n ? [node.rotate.axis[0], node.rotate.axis[1], node.rotate.axis[2]]\n : [0, 0, 1]\n rotation = quatFromAxisAngle(axis, node.rotate.angle * DEG2RAD)\n }\n return { position, rotation }\n}\n\n/** 复合两个 pose:先应用 child,再应用 parent(p' = R_p·(R_c·p + T_c) + T_p)。 */\nfunction composePose(parent: SolverPose, child: SolverPose): SolverPose {\n const rotatedT = quatRotate(parent.rotation, child.position)\n return {\n position: [\n parent.position[0] + rotatedT[0],\n parent.position[1] + rotatedT[1],\n parent.position[2] + rotatedT[2],\n ],\n rotation: quatMultiply(parent.rotation, child.rotation),\n }\n}\n\ninterface FlatAssembly {\n members: Shape[]\n memberNames: string[]\n constraints: AssemblyConstraint[]\n /** 每个叶节点的累积父 pose(从 root 到该叶,含该叶自身 translate/rotate)。 */\n parentPoses: Map<string, SolverPose>\n}\n\n/**\n * flatten:递归遍历装配树,收集叶 shape + qualified name + 约束 + 累积父 pose。\n *\n * qualified name = 从 root 的子节点到叶的 dot-separated 路径(如 `subassy.partB`)。\n * 约束从各层收集 as-is——约束中的 part 名应为 qualified name(可跨层引用)。\n */\nfunction flattenTree(root: AssemblyNode): FlatAssembly {\n const members: Shape[] = []\n const memberNames: string[] = []\n const constraints: AssemblyConstraint[] = []\n const parentPoses = new Map<string, SolverPose>()\n\n if (root.constraints) {\n for (const c of root.constraints) constraints.push(c)\n }\n\n function walk(node: AssemblyNode, prefix: string, accumulated: SolverPose): void {\n for (const child of node.children) {\n const qName = prefix ? `${prefix}.${child.name}` : child.name\n const childPose = nodeToPose(child)\n const childAccumulated = composePose(accumulated, childPose)\n\n if (child.shape) {\n members.push(child.shape)\n memberNames.push(qName)\n parentPoses.set(qName, childAccumulated)\n }\n\n if (child.constraints) {\n for (const c of child.constraints) constraints.push(c)\n }\n\n if (child.children.length > 0) {\n walk(child, qName, childAccumulated)\n }\n }\n }\n\n const rootPose = nodeToPose(root)\n walk(root, '', rootPose)\n return { members, memberNames, constraints, parentPoses }\n}\n\n/**\n * 求解嵌套子装配树:flatten → solveGlobal → recompose。\n *\n * @param root - 装配树根节点(root 的 shape 被忽略,仅作容器)。\n * @param opts - 求解选项(透传给 solveGlobal;默认 solver:'global')。\n * @returns 每个叶节点的世界变换 + 诊断量。\n * @throws Error on empty members, unknown constraint parts, or non-convergence.\n */\nexport function solveAssemblyTree(\n root: AssemblyNode,\n opts?: SolveOptions,\n): AssemblyTreeSolveResult {\n const flat = flattenTree(root)\n if (flat.members.length === 0) {\n return { transforms: {}, converged: true, unsupported: [], residuals: [] }\n }\n\n const solveOpts: SolveOptions = { solver: 'global', ...opts }\n const result = solveGlobal(flat.members, flat.memberNames, flat.constraints, solveOpts)\n if (!result.converged) {\n throw new Error(\n '[assembly:tree] constraint solve did not converge; unsupported: ' +\n (result.unsupported.length > 0 ? result.unsupported.join(', ') : '(no detail)'),\n )\n }\n\n const transforms: Record<string, AssemblyTransform> = {}\n\n for (let i = 0; i < flat.memberNames.length; i++) {\n const name = flat.memberNames[i]\n const parentPose = flat.parentPoses.get(name)\n if (parentPose && !isIdentityPose(parentPose)) {\n transforms[name] = poseToAssemblyTransform(parentPose, [0, 0, 0], i)\n }\n }\n\n for (const t of result.transforms) {\n const name = flat.memberNames[t.index]\n if (!name) continue\n const parentPose = flat.parentPoses.get(name)\n if (!parentPose || isIdentityPose(parentPose)) {\n transforms[name] = t\n continue\n }\n const solverPose: SolverPose = {\n position: [t.translation[0], t.translation[1], t.translation[2]],\n rotation: toBrepjsQuat(t.quaternion as [number, number, number, number]),\n }\n const composed = composePose(parentPose, solverPose)\n transforms[name] = poseToAssemblyTransform(composed, [0, 0, 0], t.index)\n }\n\n return {\n transforms,\n converged: result.converged,\n unsupported: result.unsupported,\n residuals: result.residuals,\n warnings: result.warnings,\n // P7/D1-3:显式透传(此处是重建对象,spread 不会带上)。\n underdetermined: result.underdetermined,\n }\n}"]}
1
+ {"version":3,"file":"solve-tree.js","sourceRoot":"","sources":["../../../src/api/assembly/solve-tree.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api/assembly/solve-tree — 嵌套子装配求解(P4,方案 §4.2)\n *\n * flatten → solveGlobal → recompose:\n * 1. flatten:walkAssembly 收集叶 shape + qualified member name(如 `subassy.part`),\n * 构建扁平 members/memberNames;约束从各层收集(part 名用 qualified name,可跨层引用)。\n * 2. solve:调 solveGlobal 求解扁平问题。\n * 3. recompose:自顶向下将父变换(AssemblyNode.translate/rotate)与 solver 变换复合\n * (parentTransform ∘ childLocalTransform),得到每个叶节点的世界变换。\n *\n * 语义对齐 CQ `Assembly.solve()`:每个对象的 `loc` 累积合成世界变换。\n * faijs Shape 不携带 placement → 求解器从 identity 初值求解;父变换在 recompose 阶段复合。\n */\n\nimport type { Shape } from '../../mesh/types'\nimport type { AssemblyTransform } from '../../runtime-state'\nimport type { AssemblyConstraint } from './types'\nimport type { SolveOptions } from './solvers/types'\nimport type { AssemblyNode } from './solvers/assembly-tree'\nimport { solveGlobal } from './solvers/global-solver'\nimport { poseToAssemblyTransform, isIdentityPose, type SolverPose } from './pose'\nimport { quatFromAxisAngle, quatRotate, quatMultiply } from './solvers/quat'\n\nconst DEG2RAD = Math.PI / 180\n\n/** 嵌套子装配求解结果:per-leaf 世界变换 + 诊断量。 */\nexport interface AssemblyTreeSolveResult {\n /** 每个叶节点的世界变换(键 = qualified name)。 */\n transforms: Record<string, AssemblyTransform>\n /** 是否全部约束可解。 */\n converged: boolean\n /** 无法求解的约束明细。 */\n unsupported: string[]\n /** 逐约束最终残差。 */\n residuals: number[]\n /** 残差超阈值的约束逐条写入。 */\n warnings?: string[]\n /**\n * P7/D1-3:欠定自由度诊断(透传自 solveGlobal)。dof > 0 = 约束集欠定,\n * 终态位姿依赖优化器轨迹、无唯一「正确解」——判等方应走规范判等通道而非逐位比对。\n */\n underdetermined?: { dof: number; freeDirs?: number[][] }\n}\n\n\n/** 把 AssemblyNode 的 translate/rotate 转为 SolverPose(brepjs [w,x,y,z] 旋转)。 */\nfunction nodeToPose(node: AssemblyNode): SolverPose {\n const position: [number, number, number] = node.translate\n ? [node.translate[0], node.translate[1], node.translate[2]]\n : [0, 0, 0]\n let rotation: [number, number, number, number] = [1, 0, 0, 0]\n if (node.rotate) {\n const axis: readonly [number, number, number] = node.rotate.axis\n ? [node.rotate.axis[0], node.rotate.axis[1], node.rotate.axis[2]]\n : [0, 0, 1]\n rotation = quatFromAxisAngle(axis, node.rotate.angle * DEG2RAD)\n }\n return { position, rotation }\n}\n\n/** 复合两个 pose:先应用 child,再应用 parent(p' = R_p·(R_c·p + T_c) + T_p)。 */\nfunction composePose(parent: SolverPose, child: SolverPose): SolverPose {\n const rotatedT = quatRotate(parent.rotation, child.position)\n return {\n position: [\n parent.position[0] + rotatedT[0],\n parent.position[1] + rotatedT[1],\n parent.position[2] + rotatedT[2],\n ],\n rotation: quatMultiply(parent.rotation, child.rotation),\n }\n}\n\ninterface FlatAssembly {\n members: Shape[]\n memberNames: string[]\n constraints: AssemblyConstraint[]\n /** 每个叶节点的累积父 pose(从 root 到该叶,含该叶自身 translate/rotate)。 */\n parentPoses: Map<string, SolverPose>\n /** P8:刚体分组(成员下标)——同一子装配的叶共享一个刚体块。 */\n rigidGroups: number[][]\n}\n\n/**\n * flatten:递归遍历装配树,收集叶 shape + qualified name + 约束 + 累积父 pose。\n *\n * qualified name = 从 root 的子节点到叶的 dot-separated 路径(如 `subassy.partB`)。\n * 约束从各层收集 as-is——约束中的 part 名应为 qualified name(可跨层引用)。\n */\nfunction flattenTree(root: AssemblyNode): FlatAssembly {\n const members: Shape[] = []\n const memberNames: string[] = []\n const constraints: AssemblyConstraint[] = []\n const parentPoses = new Map<string, SolverPose>()\n // P8:子装配 → 叶下标分组(叶序号在收集时递增,组按收集序记录)。\n const rigidGroups: number[][] = []\n\n if (root.constraints) {\n for (const c of root.constraints) constraints.push(c)\n }\n\n function walk(node: AssemblyNode, prefix: string, accumulated: SolverPose, groupId: number | null): void {\n for (const child of node.children) {\n const qName = prefix ? `${prefix}.${child.name}` : child.name\n const childPose = nodeToPose(child)\n const childAccumulated = composePose(accumulated, childPose)\n\n // P8:子装配节点(有 children)开一个新刚体组——其自身 shape 叶(root 件)\n // 与全部成员叶同组。必须在建组后再 push 自身叶,否则 root 件落在外层\n // groupId(null)下、组内只剩成员叶,length>1 过滤会把整组丢掉\n // (nested_assy 实测:组 [b3] 被滤掉,b2 仍自由漂移)。\n const isSub = child.children.length > 0\n const myGroup = isSub ? rigidGroups.length : groupId\n if (isSub) rigidGroups.push([])\n\n if (child.shape) {\n members.push(child.shape)\n memberNames.push(qName)\n parentPoses.set(qName, childAccumulated)\n if (myGroup !== null) rigidGroups[myGroup].push(members.length - 1)\n }\n\n if (child.constraints) {\n for (const c of child.constraints) constraints.push(c)\n }\n\n if (isSub) {\n walk(child, qName, childAccumulated, myGroup)\n }\n }\n }\n\n const rootPose = nodeToPose(root)\n walk(root, '', rootPose, null)\n return { members, memberNames, constraints, parentPoses, rigidGroups }\n}\n\n/**\n * 求解嵌套子装配树:flatten → solveGlobal → recompose。\n *\n * @param root - 装配树根节点(root 的 shape 被忽略,仅作容器)。\n * @param opts - 求解选项(透传给 solveGlobal;默认 solver:'global')。\n * @returns 每个叶节点的世界变换 + 诊断量。\n * @throws Error on empty members, unknown constraint parts, or non-convergence.\n */\nexport function solveAssemblyTree(\n root: AssemblyNode,\n opts?: SolveOptions,\n): AssemblyTreeSolveResult {\n const flat = flattenTree(root)\n if (flat.members.length === 0) {\n return { transforms: {}, converged: true, unsupported: [], residuals: [] }\n }\n\n const solveOpts: SolveOptions = { solver: 'global', ...opts }\n // P8:子装配刚体分组传入求解器(同组叶共享一个 6 维状态块)。\n const groups = flat.rigidGroups.filter((g) => g.length > 1)\n if (groups.length > 0) solveOpts.rigidGroups = groups\n // P8 方案 A(CQ sublocs):叶的累积 loc(含自身 translate/rotate)作为求解\n // 初位姿传入——约束 marker 取自成员本地系,绝对位姿 = initial ∘ delta 在\n // 求解器内部合成。无累积位姿(恒等)的叶不注入,保持旧语义。\n const initPoses: SolveOptions['initialPoses'] = []\n let hasInit = false\n for (let i = 0; i < flat.memberNames.length; i++) {\n const pp = flat.parentPoses.get(flat.memberNames[i]!)\n if (pp && !isIdentityPose(pp)) {\n initPoses[i] = {\n translation: [pp.position[0], pp.position[1], pp.position[2]],\n rotation: [pp.rotation[0], pp.rotation[1], pp.rotation[2], pp.rotation[3]],\n }\n hasInit = true\n }\n }\n if (hasInit) solveOpts.initialPoses = initPoses\n const result = solveGlobal(flat.members, flat.memberNames, flat.constraints, solveOpts)\n if (!result.converged) {\n throw new Error(\n '[assembly:tree] constraint solve did not converge; unsupported: ' +\n (result.unsupported.length > 0 ? result.unsupported.join(', ') : '(no detail)'),\n )\n }\n\n const transforms: Record<string, AssemblyTransform> = {}\n\n for (let i = 0; i < flat.memberNames.length; i++) {\n const name = flat.memberNames[i]\n const parentPose = flat.parentPoses.get(name)\n if (parentPose && !isIdentityPose(parentPose)) {\n transforms[name] = poseToAssemblyTransform(parentPose, [0, 0, 0], i)\n }\n }\n\n for (const t of result.transforms) {\n const name = flat.memberNames[t.index]\n if (!name) continue\n // P8 方案 A:solver 发射的已是绝对位姿(initial ∘ delta 在求解器内合成),\n // 直接采用——若再 compose parentPose 会把初 loc 算两遍。\n transforms[name] = t\n }\n\n return {\n transforms,\n converged: result.converged,\n unsupported: result.unsupported,\n residuals: result.residuals,\n warnings: result.warnings,\n // P7/D1-3:显式透传(此处是重建对象,spread 不会带上)。\n underdetermined: result.underdetermined,\n }\n}"]}
@@ -42,6 +42,7 @@ export interface AssemblySolveResult {
42
42
  */
43
43
  underdetermined?: {
44
44
  dof: number;
45
+ freeDirs?: number[][];
45
46
  };
46
47
  }
47
48
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"solve.d.ts","sourceRoot":"","sources":["../../../src/api/assembly/solve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAO5D,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAA;AAC/E,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,SAAS,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAGnD,oCAAoC;AACpC,MAAM,WAAW,mBAAmB;IAClC,2CAA2C;IAC3C,UAAU,EAAE,iBAAiB,EAAE,CAAA;IAC/B,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAA;IACX,kDAAkD;IAClD,SAAS,EAAE,OAAO,CAAA;IAClB,uCAAuC;IACvC,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IAC3C;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB;;;OAGG;IACH,eAAe,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAClC;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,KAAK,EAAE,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,kBAAkB,EAAE,EACjC,IAAI,CAAC,EAAE,YAAY,GAClB,mBAAmB,CA0DrB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,KAAK,EAAE,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,kBAAkB,EAAE,EACjC,MAAM,GAAE,SAAS,EAAO,EACxB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EACzC,IAAI,CAAC,EAAE,YAAY,GAClB,mBAAmB,CAkCrB"}
1
+ {"version":3,"file":"solve.d.ts","sourceRoot":"","sources":["../../../src/api/assembly/solve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAO5D,OAAO,EAAmB,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAA;AAC/E,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,SAAS,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAGnD,oCAAoC;AACpC,MAAM,WAAW,mBAAmB;IAClC,2CAA2C;IAC3C,UAAU,EAAE,iBAAiB,EAAE,CAAA;IAC/B,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAA;IACX,kDAAkD;IAClD,SAAS,EAAE,OAAO,CAAA;IAClB,uCAAuC;IACvC,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IAC3C;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB;;;OAGG;IACH,eAAe,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,CAAA;KAAE,CAAA;CACzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,KAAK,EAAE,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,kBAAkB,EAAE,EACjC,IAAI,CAAC,EAAE,YAAY,GAClB,mBAAmB,CA0DrB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,KAAK,EAAE,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,kBAAkB,EAAE,EACjC,MAAM,GAAE,SAAS,EAAO,EACxB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EACzC,IAAI,CAAC,EAAE,YAAY,GAClB,mBAAmB,CAkCrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"solve.js","sourceRoot":"","sources":["../../../src/api/assembly/solve.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api/assembly/solve — 装配求解入口(P1,方案 §4.2)\n *\n * 流程:规范化(normalize)→ 降级(lower)→ brepjs solveConstraints\n *(拓扑轮次调度 / DOF / converged 全部由 brepjs 提供,零 brepjs 修改)→\n * per-member 终态 AssemblyTransform(修 L6:不再 per-constraint 增量叠加)。\n *\n * 不收敛 → 抛错(D3,错误信息带 unsupported 明细;对齐「绝不静默」约定)。\n * 恒等位姿的成员(锚定/链根)不输出变换——引擎不做无谓的几何重算。\n */\n\nimport type { Shape } from '../../mesh/types'\nimport type { BrepEngineApi } from '../../brep/engine/primitives'\nimport type { AssemblyTransform } from '../../runtime-state'\nimport { getBrepApi } from '../../brep/handle-bridge'\nimport { solveConstraints } from './solvers/chain-solver'\nimport { normalizeConstraint } from './normalize'\nimport { lowerStructuralConstraint } from './lower'\nimport { type EntityResolutionEnv } from './entities'\nimport { poseToAssemblyTransform, isIdentityPose, type SolverPose } from './pose'\nimport { solveKinematics, type JointSpec, type KinematicsPose } from './joints'\nimport type { AssemblyConstraint, AssemblyVec3 } from './types'\nimport type { SolveOptions } from './solvers/types'\nimport { solveGlobal } from './solvers/global-solver'\n\n/** 求解完整结果:per-member 终态变换 + 诊断量。 */\nexport interface AssemblySolveResult {\n /** 每个被定位成员一条终态变换(index = 成员下标;恒等位姿不输出)。 */\n transforms: AssemblyTransform[]\n /** unsupported 约束的自由度合计(诊断量;收敛时为 0)。 */\n dof: number\n /** 是否全部约束可解(不收敛时 solveAssembly 已抛错,此字段恒 true)。 */\n converged: boolean\n /** 无法求解的约束明细(entity 类型不匹配 / 参考不可达)。 */\n unsupported: string[]\n /**\n * P3:运动副解算的全成员位姿表(键 = 成员名;含恒等链根),\n * 只有该装配声明了 joints 时才存在——宿主从 ExecutionResult.kinematics 消费。\n */\n kinematics?: Record<string, KinematicsPose>\n /**\n * P3:合并诊断(joints 覆盖约束解时各记一条;D-P3-1,不参与 converged 统计)。\n */\n warnings?: string[]\n /**\n * P1(global 求解器):逐约束最终残差(CQ 代价的逐约束平方和)。chain 路径不填。\n */\n residuals?: number[]\n /**\n * P7/D1-3:欠定自由度诊断(仅 global 路径透传)。dof > 0 = 约束集欠定,\n * 终态位姿依赖优化器轨迹、无唯一「正确解」——判等方应走规范判等通道而非逐位比对。\n */\n underdetermined?: { dof: number }\n}\n\n/**\n * 求解装配:members + memberNames + constraints → per-member 终态。\n *\n * @param members - member shapes (compound children, aligned with memberNames).\n * @param memberNames - member variable names (R7: empty names throw before solving).\n * @param constraints - raw constraints from `cad.assembly({ constraints })`.\n * @param opts - optional solver options (e.g. `solver: 'global'` selects the global least-squares path).\n * @returns the solve result (transforms + diagnostics).\n * @throws Error on empty member names, unknown constraint parts, or non-convergence.\n */\nexport function solveAssembly(\n members: Shape[],\n memberNames: string[],\n constraints: AssemblyConstraint[],\n opts?: SolveOptions,\n): AssemblySolveResult {\n // P1:global 求解器分派(CadQuery 兼容全局最小二乘;零额外依赖)\n if (opts?.solver === 'global') {\n return solveGlobal(members, memberNames, constraints, opts)\n }\n\n // R7:成员名是 solver 的节点键,空串会让多成员互相覆盖——求解前断言\n memberNames.forEach((name, i) => {\n if (!name) {\n throw new Error(\n `[assembly] member at index ${i} has an empty name — members are referenced by variable name in constraints`,\n )\n }\n })\n\n const memberMap = new Map<string, Shape>()\n members.forEach((m, i) => {\n const name = memberNames[i]\n if (name && !memberMap.has(name)) memberMap.set(name, m)\n })\n // kernel 仅 TopoRef/边引用解析需要;backends 未配置(纯位姿场景/单测)→ null,\n // 此时快照引用仍可解,TopoRef 引用按 E_TOPO_NOT_FOUND 显式报错\n let kernel: BrepEngineApi | null = null\n try {\n kernel = getBrepApi()\n } catch {\n // backends not configured — snapshot-form constraints still solvable\n }\n const env: EntityResolutionEnv = { kernel, memberOf: (p: string) => memberMap.get(p) }\n\n const lowered: ReturnType<typeof lowerStructuralConstraint>['constraint'][] = []\n const depOrigins = new Map<string, AssemblyVec3>()\n for (const raw of constraints) {\n const c = normalizeConstraint(raw)\n const { constraint, depOrigin } = lowerStructuralConstraint(c, env)\n lowered.push(constraint)\n if (depOrigin && constraint.entityB) depOrigins.set(constraint.entityB.node, depOrigin)\n }\n\n const result = solveConstraints([...memberNames], lowered)\n if (!result.converged) {\n throw new Error(\n `[assembly] constraint solve did not converge (dof=${result.dof}); unsupported: ` +\n (result.unsupported.length > 0 ? result.unsupported.join(', ') : '(no detail)'),\n )\n }\n\n // per-member 终态(L6 修复):恒等位姿(锚定/链根)不输出,引擎不重算\n const transforms: AssemblyTransform[] = []\n for (const [node, rawPose] of result.transforms) {\n const pose: SolverPose = rawPose\n if (isIdentityPose(pose)) continue\n const index = memberNames.indexOf(node)\n if (index < 0) continue\n const pivot = depOrigins.get(node) ?? ([0, 0, 0] as AssemblyVec3)\n transforms.push(poseToAssemblyTransform(pose, pivot, index))\n }\n return { transforms, dof: result.dof, converged: result.converged, unsupported: result.unsupported }\n}\n\n/**\n * 求解装配(约束 + 运动副,P3):先跑约束求解得到 per-member 终态,再跑\n * solveKinematics 得到 joints 的 per-member 位姿,以**成员名**为键用 joints 结果\n * 覆盖同名成员的约束解,得到唯一一张表——**在库侧一次合并**,调用方一次性\n * setPendingAssemblyTransforms(禁止引擎侧两次登记)。\n *\n * 诊断不混用:joints 不参与 solveConstraints 的 converged/dof/unsupported 统计;\n * 覆盖发生时在 warnings 里各记一条(D-P3-1)。kinematics 为全成员位姿表(含\n * 恒等链根),供宿主从 ExecutionResult.kinematics 消费。\n *\n * joints 为空 → 退化为基础 solveAssembly 行为(无 kinematics/warnings 字段)。\n *\n * @param members - member shapes (aligned with memberNames).\n * @param memberNames - member variable names (R7: empty names throw).\n * @param constraints - raw constraints (may be empty).\n * @param joints - raw joint declarations (may be empty).\n * @param drive - per-child DOF value overrides (may be undefined).\n * @param opts - optional solver options (forwarded to the base constraint solve).\n * @returns the merged solve result (transforms + diagnostics + kinematics/warnings).\n */\nexport function solveAssemblyAndKinematics(\n members: Shape[],\n memberNames: string[],\n constraints: AssemblyConstraint[],\n joints: JointSpec[] = [],\n drive?: Record<string, number | number[]>,\n opts?: SolveOptions,\n): AssemblySolveResult {\n const base = solveAssembly(members, memberNames, constraints, opts)\n if (joints.length === 0) return base\n\n const kin = solveKinematics(memberNames, joints, drive)\n // 合并:以成员名为键,joints 结果覆盖同名成员的约束解(唯一一张表)\n const merged = new Map<string, AssemblyTransform>()\n for (const t of base.transforms) {\n const name = memberNames[t.index]\n if (name) merged.set(name, t)\n }\n const warnings: string[] = []\n for (const t of kin.transforms) {\n const name = memberNames[t.index]\n if (!name) continue\n if (merged.has(name)) {\n warnings.push(`[assembly] joint '${name}' overrides the constraint solution for member '${name}'`)\n }\n merged.set(name, t)\n }\n // 按成员下标升序输出(与约束解的 Map 遍历序解耦,输出顺序确定)\n const transforms = [...merged.entries()]\n .map(([name, t]) => ({ name, t }))\n .sort((a, b) => memberNames.indexOf(a.name) - memberNames.indexOf(b.name))\n .map(({ t }) => t)\n\n return {\n transforms,\n dof: base.dof,\n converged: base.converged,\n unsupported: base.unsupported,\n kinematics: kin.kinematics,\n warnings: warnings.length > 0 ? warnings : undefined,\n }\n}\n"]}
1
+ {"version":3,"file":"solve.js","sourceRoot":"","sources":["../../../src/api/assembly/solve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AAEnD,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAmB,MAAM,QAAQ,CAAA;AACjF,OAAO,EAAE,eAAe,EAAuC,MAAM,UAAU,CAAA;AAG/E,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAgCrD;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAgB,EAChB,WAAqB,EACrB,WAAiC,EACjC,IAAmB;IAEnB,2CAA2C;IAC3C,IAAI,IAAI,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,CAAC,CAAA;IAC7D,CAAC;IAED,yCAAyC;IACzC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CACb,8BAA8B,CAAC,6EAA6E,CAC7G,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,MAAM,SAAS,GAAG,IAAI,GAAG,EAAiB,CAAA;IAC1C,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACvB,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;QAC3B,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAA;IACF,yDAAyD;IACzD,8CAA8C;IAC9C,IAAI,MAAM,GAAyB,IAAI,CAAA;IACvC,IAAI,CAAC;QACH,MAAM,GAAG,UAAU,EAAE,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;IACvE,CAAC;IACD,MAAM,GAAG,GAAwB,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IAEtF,MAAM,OAAO,GAAiE,EAAE,CAAA;IAChF,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwB,CAAA;IAClD,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAA;QAClC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,yBAAyB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;QACnE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACxB,IAAI,SAAS,IAAI,UAAU,CAAC,OAAO;YAAE,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;IACzF,CAAC;IAED,MAAM,MAAM,GAAG,gBAAgB,CAAC,CAAC,GAAG,WAAW,CAAC,EAAE,OAAO,CAAC,CAAA;IAC1D,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,qDAAqD,MAAM,CAAC,GAAG,kBAAkB;YAC/E,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAClF,CAAA;IACH,CAAC;IAED,4CAA4C;IAC5C,MAAM,UAAU,GAAwB,EAAE,CAAA;IAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QAChD,MAAM,IAAI,GAAe,OAAO,CAAA;QAChC,IAAI,cAAc,CAAC,IAAI,CAAC;YAAE,SAAQ;QAClC,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,KAAK,GAAG,CAAC;YAAE,SAAQ;QACvB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAkB,CAAA;QACjE,UAAU,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;IAC9D,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAA;AACtG,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAgB,EAChB,WAAqB,EACrB,WAAiC,EACjC,SAAsB,EAAE,EACxB,KAAyC,EACzC,IAAmB;IAEnB,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,CAAC,CAAA;IACnE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAEpC,MAAM,GAAG,GAAG,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;IACvD,uCAAuC;IACvC,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6B,CAAA;IACnD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;QACjC,IAAI,IAAI;YAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IAC/B,CAAC;IACD,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;QACjC,IAAI,CAAC,IAAI;YAAE,SAAQ;QACnB,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,QAAQ,CAAC,IAAI,CAAC,qBAAqB,IAAI,mDAAmD,IAAI,GAAG,CAAC,CAAA;QACpG,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IACrB,CAAC;IACD,oCAAoC;IACpC,MAAM,UAAU,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;SACrC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;SACjC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SACzE,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;IAEpB,OAAO;QACL,UAAU;QACV,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;KACrD,CAAA;AACH,CAAC","sourcesContent":["/**\n * api/assembly/solve — 装配求解入口(P1,方案 §4.2)\n *\n * 流程:规范化(normalize)→ 降级(lower)→ brepjs solveConstraints\n *(拓扑轮次调度 / DOF / converged 全部由 brepjs 提供,零 brepjs 修改)→\n * per-member 终态 AssemblyTransform(修 L6:不再 per-constraint 增量叠加)。\n *\n * 不收敛 → 抛错(D3,错误信息带 unsupported 明细;对齐「绝不静默」约定)。\n * 恒等位姿的成员(锚定/链根)不输出变换——引擎不做无谓的几何重算。\n */\n\nimport type { Shape } from '../../mesh/types'\nimport type { BrepEngineApi } from '../../brep/engine/primitives'\nimport type { AssemblyTransform } from '../../runtime-state'\nimport { getBrepApi } from '../../brep/handle-bridge'\nimport { solveConstraints } from './solvers/chain-solver'\nimport { normalizeConstraint } from './normalize'\nimport { lowerStructuralConstraint } from './lower'\nimport { type EntityResolutionEnv } from './entities'\nimport { poseToAssemblyTransform, isIdentityPose, type SolverPose } from './pose'\nimport { solveKinematics, type JointSpec, type KinematicsPose } from './joints'\nimport type { AssemblyConstraint, AssemblyVec3 } from './types'\nimport type { SolveOptions } from './solvers/types'\nimport { solveGlobal } from './solvers/global-solver'\n\n/** 求解完整结果:per-member 终态变换 + 诊断量。 */\nexport interface AssemblySolveResult {\n /** 每个被定位成员一条终态变换(index = 成员下标;恒等位姿不输出)。 */\n transforms: AssemblyTransform[]\n /** unsupported 约束的自由度合计(诊断量;收敛时为 0)。 */\n dof: number\n /** 是否全部约束可解(不收敛时 solveAssembly 已抛错,此字段恒 true)。 */\n converged: boolean\n /** 无法求解的约束明细(entity 类型不匹配 / 参考不可达)。 */\n unsupported: string[]\n /**\n * P3:运动副解算的全成员位姿表(键 = 成员名;含恒等链根),\n * 只有该装配声明了 joints 时才存在——宿主从 ExecutionResult.kinematics 消费。\n */\n kinematics?: Record<string, KinematicsPose>\n /**\n * P3:合并诊断(joints 覆盖约束解时各记一条;D-P3-1,不参与 converged 统计)。\n */\n warnings?: string[]\n /**\n * P1(global 求解器):逐约束最终残差(CQ 代价的逐约束平方和)。chain 路径不填。\n */\n residuals?: number[]\n /**\n * P7/D1-3:欠定自由度诊断(仅 global 路径透传)。dof > 0 = 约束集欠定,\n * 终态位姿依赖优化器轨迹、无唯一「正确解」——判等方应走规范判等通道而非逐位比对。\n */\n underdetermined?: { dof: number; freeDirs?: number[][] }\n}\n\n/**\n * 求解装配:members + memberNames + constraints → per-member 终态。\n *\n * @param members - member shapes (compound children, aligned with memberNames).\n * @param memberNames - member variable names (R7: empty names throw before solving).\n * @param constraints - raw constraints from `cad.assembly({ constraints })`.\n * @param opts - optional solver options (e.g. `solver: 'global'` selects the global least-squares path).\n * @returns the solve result (transforms + diagnostics).\n * @throws Error on empty member names, unknown constraint parts, or non-convergence.\n */\nexport function solveAssembly(\n members: Shape[],\n memberNames: string[],\n constraints: AssemblyConstraint[],\n opts?: SolveOptions,\n): AssemblySolveResult {\n // P1:global 求解器分派(CadQuery 兼容全局最小二乘;零额外依赖)\n if (opts?.solver === 'global') {\n return solveGlobal(members, memberNames, constraints, opts)\n }\n\n // R7:成员名是 solver 的节点键,空串会让多成员互相覆盖——求解前断言\n memberNames.forEach((name, i) => {\n if (!name) {\n throw new Error(\n `[assembly] member at index ${i} has an empty name — members are referenced by variable name in constraints`,\n )\n }\n })\n\n const memberMap = new Map<string, Shape>()\n members.forEach((m, i) => {\n const name = memberNames[i]\n if (name && !memberMap.has(name)) memberMap.set(name, m)\n })\n // kernel 仅 TopoRef/边引用解析需要;backends 未配置(纯位姿场景/单测)→ null,\n // 此时快照引用仍可解,TopoRef 引用按 E_TOPO_NOT_FOUND 显式报错\n let kernel: BrepEngineApi | null = null\n try {\n kernel = getBrepApi()\n } catch {\n // backends not configured — snapshot-form constraints still solvable\n }\n const env: EntityResolutionEnv = { kernel, memberOf: (p: string) => memberMap.get(p) }\n\n const lowered: ReturnType<typeof lowerStructuralConstraint>['constraint'][] = []\n const depOrigins = new Map<string, AssemblyVec3>()\n for (const raw of constraints) {\n const c = normalizeConstraint(raw)\n const { constraint, depOrigin } = lowerStructuralConstraint(c, env)\n lowered.push(constraint)\n if (depOrigin && constraint.entityB) depOrigins.set(constraint.entityB.node, depOrigin)\n }\n\n const result = solveConstraints([...memberNames], lowered)\n if (!result.converged) {\n throw new Error(\n `[assembly] constraint solve did not converge (dof=${result.dof}); unsupported: ` +\n (result.unsupported.length > 0 ? result.unsupported.join(', ') : '(no detail)'),\n )\n }\n\n // per-member 终态(L6 修复):恒等位姿(锚定/链根)不输出,引擎不重算\n const transforms: AssemblyTransform[] = []\n for (const [node, rawPose] of result.transforms) {\n const pose: SolverPose = rawPose\n if (isIdentityPose(pose)) continue\n const index = memberNames.indexOf(node)\n if (index < 0) continue\n const pivot = depOrigins.get(node) ?? ([0, 0, 0] as AssemblyVec3)\n transforms.push(poseToAssemblyTransform(pose, pivot, index))\n }\n return { transforms, dof: result.dof, converged: result.converged, unsupported: result.unsupported }\n}\n\n/**\n * 求解装配(约束 + 运动副,P3):先跑约束求解得到 per-member 终态,再跑\n * solveKinematics 得到 joints 的 per-member 位姿,以**成员名**为键用 joints 结果\n * 覆盖同名成员的约束解,得到唯一一张表——**在库侧一次合并**,调用方一次性\n * setPendingAssemblyTransforms(禁止引擎侧两次登记)。\n *\n * 诊断不混用:joints 不参与 solveConstraints 的 converged/dof/unsupported 统计;\n * 覆盖发生时在 warnings 里各记一条(D-P3-1)。kinematics 为全成员位姿表(含\n * 恒等链根),供宿主从 ExecutionResult.kinematics 消费。\n *\n * joints 为空 → 退化为基础 solveAssembly 行为(无 kinematics/warnings 字段)。\n *\n * @param members - member shapes (aligned with memberNames).\n * @param memberNames - member variable names (R7: empty names throw).\n * @param constraints - raw constraints (may be empty).\n * @param joints - raw joint declarations (may be empty).\n * @param drive - per-child DOF value overrides (may be undefined).\n * @param opts - optional solver options (forwarded to the base constraint solve).\n * @returns the merged solve result (transforms + diagnostics + kinematics/warnings).\n */\nexport function solveAssemblyAndKinematics(\n members: Shape[],\n memberNames: string[],\n constraints: AssemblyConstraint[],\n joints: JointSpec[] = [],\n drive?: Record<string, number | number[]>,\n opts?: SolveOptions,\n): AssemblySolveResult {\n const base = solveAssembly(members, memberNames, constraints, opts)\n if (joints.length === 0) return base\n\n const kin = solveKinematics(memberNames, joints, drive)\n // 合并:以成员名为键,joints 结果覆盖同名成员的约束解(唯一一张表)\n const merged = new Map<string, AssemblyTransform>()\n for (const t of base.transforms) {\n const name = memberNames[t.index]\n if (name) merged.set(name, t)\n }\n const warnings: string[] = []\n for (const t of kin.transforms) {\n const name = memberNames[t.index]\n if (!name) continue\n if (merged.has(name)) {\n warnings.push(`[assembly] joint '${name}' overrides the constraint solution for member '${name}'`)\n }\n merged.set(name, t)\n }\n // 按成员下标升序输出(与约束解的 Map 遍历序解耦,输出顺序确定)\n const transforms = [...merged.entries()]\n .map(([name, t]) => ({ name, t }))\n .sort((a, b) => memberNames.indexOf(a.name) - memberNames.indexOf(b.name))\n .map(({ t }) => t)\n\n return {\n transforms,\n dof: base.dof,\n converged: base.converged,\n unsupported: base.unsupported,\n kinematics: kin.kinematics,\n warnings: warnings.length > 0 ? warnings : undefined,\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"global-solver.d.ts","sourceRoot":"","sources":["../../../../src/api/assembly/solvers/global-solver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAIhD,OAAO,KAAK,EAAE,kBAAkB,EAAa,MAAM,UAAU,CAAA;AAQ7D,OAAO,EAAE,KAAK,YAAY,EAAqB,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAA;AA8PtF;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,KAAK,EAAE,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,kBAAkB,EAAE,EACjC,IAAI,CAAC,EAAE,YAAY,GAClB,iBAAiB,CA6UnB"}
1
+ {"version":3,"file":"global-solver.d.ts","sourceRoot":"","sources":["../../../../src/api/assembly/solvers/global-solver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAIhD,OAAO,KAAK,EAAE,kBAAkB,EAAa,MAAM,UAAU,CAAA;AAQ7D,OAAO,EAAE,KAAK,YAAY,EAAqB,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAsStF;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,KAAK,EAAE,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,kBAAkB,EAAE,EACjC,IAAI,CAAC,EAAE,YAAY,GAClB,iBAAiB,CAoYnB"}
@@ -22,7 +22,8 @@ import { normalizeConstraint } from '../normalize.js';
22
22
  import { poseToAssemblyTransform } from '../pose.js';
23
23
  import { resolveFaceGeometryOfRef, resolveSolverEntity, } from '../entities.js';
24
24
  import { vadd, vsub, vdot, vscale, vnormalize, vsumsqr, ata, atb, solveDampedNormal, } from './linalg.js';
25
- import { rotateByR, quatFromR } from './pose-from-delta.js';
25
+ import { rotateByR, quatFromR, quatToRvec } from './pose-from-delta.js';
26
+ import { quatMultiply, quatRotate } from './quat.js';
26
27
  const DEG2RAD = Math.PI / 180;
27
28
  const R_INIT = 1e-2; // B3
28
29
  const LM_LAMBDA0 = 1e-3;
@@ -86,7 +87,7 @@ function termResidual(t, sa, sb, scale) {
86
87
  const d = vscale(vsub(pa, pb), inv);
87
88
  if (Math.abs(t.val) < 1e-12)
88
89
  return d; // 3-vec,val=0
89
- return [vsumsqr(d) - (t.val / scale) ** 2]; // 1-vec,val≠0
90
+ return [vsumsqr(d) - (t.val * inv) ** 2]; // 1-vec,val≠0(目标值与残差同除 scale)
90
91
  }
91
92
  case 'axis': {
92
93
  const d1 = markerDir(t.ma, sa.R);
@@ -114,7 +115,11 @@ function termResidual(t, sa, sb, scale) {
114
115
  const perp = vscale(vsub(delta, vscale(dln, vdot(delta, dln))), inv);
115
116
  if (Math.abs(t.val) < 1e-12)
116
117
  return perp; // 3-vec,val=0
117
- return [vsumsqr(perp) - t.val]; // 1-vec,val≠0(注意 val 不缩放)
118
+ // 1-vec,val≠0:perp 已除 scale → vsumsqr(perp) = (dist/scale)²;
119
+ // 目标值必须同尺度(t.val·inv)²,否则实际满足 dist = scale·√val。
120
+ // (历史缺陷:此处曾写 `vsumsqr(perp) - t.val`,val 不缩放——金丝雀见
121
+ // planetary-static.test.ts distance 用例,修复后该断言已翻转为 ORBIT_R。)
122
+ return [vsumsqr(perp) - (t.val * inv) ** 2];
118
123
  }
119
124
  }
120
125
  }
@@ -133,12 +138,22 @@ function residualDim(t) {
133
138
  }
134
139
  void residualDim; // P7/D1-1:诊断参考表(秩判定走列归一特征值,见下)
135
140
  /**
136
- * 对称 n×n 矩阵的特征值(循环 Jacobi 旋转)。
141
+ * 对称 n×n 矩阵的特征分解(循环 Jacobi 旋转)。
137
142
  *
143
+ * @param A 行主 n×n 对称矩阵(会被复制,不修改原矩阵)。
144
+ * @param n 阶数。
145
+ * @param outVec 可选输出:n×n 行主特征向量矩阵 V(列 v[:,i] 是 outVec[i] 对应的
146
+ * 特征向量)。传 `V`(单位矩阵)时原地累积旋转。
138
147
  * @returns 特征值数组(无序);扫掠不收敛返回 null(调用方走保守 fallback)。
139
148
  */
140
- function symEigenvalues(A, n) {
149
+ function symEigenvalues(A, n, outVec) {
141
150
  const a = A.slice();
151
+ if (outVec)
152
+ for (let i = 0; i < n * n; i++)
153
+ outVec[i] = 0;
154
+ if (outVec)
155
+ for (let i = 0; i < n; i++)
156
+ outVec[i * n + i] = 1;
142
157
  for (let sweep = 0; sweep < 60; sweep++) {
143
158
  let off = 0;
144
159
  for (let p = 0; p < n; p++) {
@@ -169,6 +184,14 @@ function symEigenvalues(A, n) {
169
184
  a[p * n + k] = c * apk - s * aqk;
170
185
  a[q * n + k] = s * apk + c * aqk;
171
186
  }
187
+ if (outVec) {
188
+ for (let k = 0; k < n; k++) {
189
+ const vkp = outVec[k * n + p];
190
+ const vkq = outVec[k * n + q];
191
+ outVec[k * n + p] = c * vkp - s * vkq;
192
+ outVec[k * n + q] = s * vkp + c * vkq;
193
+ }
194
+ }
172
195
  }
173
196
  }
174
197
  if (sweep === 59)
@@ -195,7 +218,7 @@ function symEigenvalues(A, n) {
195
218
  *
196
219
  * @returns 剩余自由度(0 = 适定);特征分解不收敛时保守报 0(不阻塞消费方)。
197
220
  */
198
- function computeUnderdeterminedDof(terms, scale, n, x, stateOf) {
221
+ function computeUnderdeterminedDof(terms, scale, n, x, stateOf, outFreeDirs) {
199
222
  if (n === 0)
200
223
  return 0;
201
224
  // 仅约束残差(剔除 penalty 正则行)
@@ -243,14 +266,37 @@ function computeUnderdeterminedDof(terms, scale, n, x, stateOf) {
243
266
  Jn[row * n + col] /= d;
244
267
  }
245
268
  const JtJ = ata(Jn, m, n);
246
- const eig = symEigenvalues(JtJ, n);
269
+ const V = new Array(n * n).fill(0);
270
+ const eig = symEigenvalues(JtJ, n, V);
247
271
  if (!eig)
248
272
  return 0; // 保守 fallback(适定假设,不阻塞)
249
273
  const lambdaMax = Math.max(...eig.map(Math.abs));
250
274
  if (!(lambdaMax > 1e-300))
251
275
  return freeCols + n; // 理论不可达;防御
252
276
  const rank = eig.filter((v) => Math.abs(v) > lambdaMax * 1e-8).length;
253
- return Math.max(0, n - rank);
277
+ const dof = Math.max(0, n - rank);
278
+ // P7/D1-4:零空间特征向量(λ < λmax·1e-8 的列)= 欠定自由方向(变量系:
279
+ // 每成员 6 维 [tx,ty,tz,rx,ry,rz],列范数已归一)。旋转分量为主的方向对
280
+ // 位姿判等有意义;调用方按需解释。
281
+ if (outFreeDirs && dof > 0) {
282
+ for (let i = 0; i < n; i++) {
283
+ if (Math.abs(eig[i]) > lambdaMax * 1e-8)
284
+ continue;
285
+ const v = new Array(n);
286
+ for (let r = 0; r < n; r++)
287
+ v[r] = V[r * n + i];
288
+ outFreeDirs.push(v);
289
+ }
290
+ // 零范数列(约束摸不到的坐标轴方向)也是自由方向,补在后面
291
+ for (let col = 0; col < n; col++) {
292
+ if (norms[col] > 1e-12)
293
+ continue;
294
+ const v = new Array(n).fill(0);
295
+ v[col] = 1;
296
+ outFreeDirs.push(v);
297
+ }
298
+ }
299
+ return dof;
254
300
  }
255
301
  /**
256
302
  * 纯 TS global 求解器入口。
@@ -451,13 +497,31 @@ export function solveGlobal(members, memberNames, constraints, opts) {
451
497
  // ── scale = 所有 marker 点的包围盒对角长(CQ B5;marker 近似几何 bbox) ──
452
498
  const scale = computeScale(scalePts);
453
499
  // ── 自由成员与变量 ──
500
+ // P8 刚体分组:同组成员共享一个 6 维状态块(子装配在 CQ 语义里是刚体)。
501
+ // freeIdx 每项是一个块的"代表成员"下标;blockOf 把每个自由成员映射到其块位置 k
502
+ // (代表自身与跟随者都映射到同一 k——stateOf 按成员直接查块,无需二次 rep 解析)。
454
503
  const freeIdx = [];
455
- const blockMap = new Map();
504
+ const blockOf = new Map();
505
+ const groupOf = new Map(); // member idx -> 代表成员 idx
506
+ if (opts?.rigidGroups) {
507
+ for (const g of opts.rigidGroups) {
508
+ for (const m of g)
509
+ groupOf.set(m, g[0]);
510
+ }
511
+ }
456
512
  memberNames.forEach((_, i) => {
457
- if (!lockedSet.has(i)) {
458
- blockMap.set(i, freeIdx.length);
459
- freeIdx.push(i);
513
+ if (lockedSet.has(i))
514
+ return;
515
+ const rep = groupOf.get(i) ?? i;
516
+ // 组代表被锁:整组随锁(跟随者也不进自由集)。
517
+ if (lockedSet.has(rep))
518
+ return;
519
+ let k = freeIdx.indexOf(rep);
520
+ if (k < 0) {
521
+ k = freeIdx.length;
522
+ freeIdx.push(rep);
460
523
  }
524
+ blockOf.set(i, k);
461
525
  });
462
526
  const n = freeIdx.length * 6;
463
527
  const x = new Array(n).fill(0);
@@ -466,17 +530,45 @@ export function solveGlobal(members, memberNames, constraints, opts) {
466
530
  x[6 * k + 4] = R_INIT;
467
531
  x[6 * k + 5] = R_INIT;
468
532
  }
533
+ // P8 方案 A(CQ sublocs 语义):成员建模坐标是装配前本地系,约束 marker 取自
534
+ // 该本地系;求解器状态是 delta,绝对位姿 = initialPose ∘ delta(penalty 拉
535
+ // delta→0 = 倾向保持初 loc)。未传 initialPoses 时初位姿为恒等——与旧 delta
536
+ // 语义完全一致(回归零影响)。
537
+ // 关键:init 按【成员下标】存,delta 按块共享——刚体组成员初位各不同
538
+ // (nested_assy:b2 初 (0,4,0)、b3 初 (0,8,0)),同一 delta 下绝对位姿各异;
539
+ // 若 init 按块存,跟随者会错拿代表的初位(实测 b2 错落 (2,0,0.75),ref (2,−4,0.75))。
540
+ const initT = new Map();
541
+ const initQ = new Map();
542
+ if (opts?.initialPoses) {
543
+ opts.initialPoses.forEach((ip, i) => {
544
+ if (!ip)
545
+ return;
546
+ initT.set(i, [ip.translation[0], ip.translation[1], ip.translation[2]]);
547
+ initQ.set(i, [ip.rotation[0], ip.rotation[1], ip.rotation[2], ip.rotation[3]]);
548
+ });
549
+ }
469
550
  const stateOf = (xx, i) => {
470
551
  // 世界哨兵 i = -1:identity(世界系 marker 已存字面坐标,不再施加成员变换)
471
552
  if (i < 0)
472
553
  return { T: [0, 0, 0], R: [0, 0, 0] };
473
554
  if (lockedSet.has(i))
474
555
  return { T: [0, 0, 0], R: [0, 0, 0] };
475
- const k = blockMap.get(i);
476
- return {
477
- T: [xx[6 * k], xx[6 * k + 1], xx[6 * k + 2]],
478
- R: [xx[6 * k + 3], xx[6 * k + 4], xx[6 * k + 5]],
479
- };
556
+ const k = blockOf.get(i);
557
+ if (k === undefined)
558
+ return { T: [0, 0, 0], R: [0, 0, 0] };
559
+ const dT = [xx[6 * k], xx[6 * k + 1], xx[6 * k + 2]];
560
+ const dR = [xx[6 * k + 3], xx[6 * k + 4], xx[6 * k + 5]];
561
+ const it = initT.get(i);
562
+ const iq = initQ.get(i);
563
+ if (!it || !iq)
564
+ return { T: dT, R: dR };
565
+ // absolute = initial ∘ delta:先转 delta 再平移初 loc。
566
+ const qd = quatFromR(dR[0], dR[1], dR[2]);
567
+ const at = vadd(it, quatRotate(iq, dT));
568
+ const aq = quatMultiply(iq, qd);
569
+ // 绝对四元数 → 旋转向量(pose-from-delta 的 R 约定),供 markerPoint 复用。
570
+ const Rm = quatToRvec(aq);
571
+ return { T: at, R: Rm };
480
572
  };
481
573
  const residual = (xx) => {
482
574
  const r = [];
@@ -558,13 +650,25 @@ export function solveGlobal(members, memberNames, constraints, opts) {
558
650
  }
559
651
  // ── 组装结果 ──
560
652
  const transforms = [];
653
+ // P8 方案 A:发射绝对位姿 = initial ∘ delta(stateOf 终态),不再裸发 delta。
561
654
  for (let k = 0; k < freeIdx.length; k++) {
562
655
  const i = freeIdx[k];
563
- const T = [x[6 * k], x[6 * k + 1], x[6 * k + 2]];
564
- const R = [x[6 * k + 3], x[6 * k + 4], x[6 * k + 5]];
565
- const pose = { position: T, rotation: quatFromR(R[0], R[1], R[2]) };
656
+ const st = stateOf(x, i);
657
+ const pose = { position: st.T, rotation: quatFromR(st.R[0], st.R[1], st.R[2]) };
566
658
  transforms.push(poseToAssemblyTransform(pose, [0, 0, 0], i));
567
659
  }
660
+ // P8 刚体分组:跟随成员与组代表共享同一刚体位姿——为每个跟随者补一条
661
+ // 同 pose 的 transform(index=跟随者),否则 solve-tree 的 recompose 拿不到
662
+ // 组员的变换(nested_assy 的 b3 叶会缺条目)。
663
+ for (const [member, rep] of groupOf) {
664
+ if (member === rep)
665
+ continue;
666
+ if (lockedSet.has(member))
667
+ continue;
668
+ const st = stateOf(x, rep);
669
+ const pose = { position: st.T, rotation: quatFromR(st.R[0], st.R[1], st.R[2]) };
670
+ transforms.push(poseToAssemblyTransform(pose, [0, 0, 0], member));
671
+ }
568
672
  // 逐约束残差(诊断)
569
673
  const residuals = [];
570
674
  const warnings = [];
@@ -580,13 +684,16 @@ export function solveGlobal(members, memberNames, constraints, opts) {
580
684
  if (r > RESIDUAL_WARN * scale)
581
685
  warnings.push(`constraint #${cid} residual=${r.toExponential(3)} (> ${RESIDUAL_WARN * scale})`);
582
686
  });
583
- // P7/D1-2:欠定自由度诊断(剔除 penalty 正则行后按 JᵀJc 特征值秩判定)
584
- const underdeterminedDof = computeUnderdeterminedDof(terms, scale, n, x, stateOf);
687
+ // P7/D1-2/D1-4:欠定自由度诊断 + 零空间自由方向(变量系 6 维块 [tx,ty,tz,rx,ry,rz])
688
+ const freeDirs = [];
689
+ const underdeterminedDof = computeUnderdeterminedDof(terms, scale, n, x, stateOf, freeDirs);
585
690
  return {
586
691
  transforms,
587
692
  dof: 0,
588
693
  // P7/D1-3:旧 `dof` 字段语义不变(unsupported 合计的占位),欠定信息走新字段。
589
- underdetermined: underdeterminedDof > 0 ? { dof: underdeterminedDof } : undefined,
694
+ underdetermined: underdeterminedDof > 0
695
+ ? { dof: underdeterminedDof, freeDirs: freeDirs.map((v) => v.map((c) => Math.abs(c) < 1e-12 ? 0 : +c.toFixed(12))) }
696
+ : undefined,
590
697
  converged: true,
591
698
  unsupported,
592
699
  residuals,