@faicad/faijs 0.29.5 → 0.30.9

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 (582) hide show
  1. package/NOTICE +6 -5
  2. package/dist/api/api-namespace.d.ts +1 -1
  3. package/dist/api/api-namespace.d.ts.map +1 -1
  4. package/dist/api/api-namespace.js +53 -1
  5. package/dist/api/api-namespace.js.map +1 -1
  6. package/dist/api/appearance.d.ts +0 -2
  7. package/dist/api/appearance.d.ts.map +1 -1
  8. package/dist/api/appearance.js +0 -2
  9. package/dist/api/appearance.js.map +1 -1
  10. package/dist/api/assembly/entities.d.ts +1 -1
  11. package/dist/api/assembly/entities.js +1 -1
  12. package/dist/api/assembly/entities.js.map +1 -1
  13. package/dist/api/assembly/index.d.ts +1 -1
  14. package/dist/api/assembly/index.js +1 -1
  15. package/dist/api/assembly/index.js.map +1 -1
  16. package/dist/api/assembly/joints.d.ts +33 -15
  17. package/dist/api/assembly/joints.d.ts.map +1 -1
  18. package/dist/api/assembly/joints.js +31 -13
  19. package/dist/api/assembly/joints.js.map +1 -1
  20. package/dist/api/assembly/preview.d.ts +1 -1
  21. package/dist/api/assembly/preview.js +1 -1
  22. package/dist/api/assembly/preview.js.map +1 -1
  23. package/dist/api/assembly/solve.d.ts +1 -1
  24. package/dist/api/assembly/solve.js +1 -1
  25. package/dist/api/assembly/solve.js.map +1 -1
  26. package/dist/api/assembly/solvers/assembly-tree.d.ts +1 -1
  27. package/dist/api/assembly/solvers/assembly-tree.js +1 -1
  28. package/dist/api/assembly/solvers/assembly-tree.js.map +1 -1
  29. package/dist/api/assembly/solvers/chain-solver.d.ts +2 -2
  30. package/dist/api/assembly/solvers/chain-solver.js.map +1 -1
  31. package/dist/api/assembly/solvers/global-solver.d.ts +1 -2
  32. package/dist/api/assembly/solvers/global-solver.d.ts.map +1 -1
  33. package/dist/api/assembly/solvers/global-solver.js +3 -4
  34. package/dist/api/assembly/solvers/global-solver.js.map +1 -1
  35. package/dist/api/assembly/solvers/joints-kinematics.js +1 -1
  36. package/dist/api/assembly/solvers/joints-kinematics.js.map +1 -1
  37. package/dist/api/assembly/solvers/linalg.d.ts +2 -2
  38. package/dist/api/assembly/solvers/linalg.js +2 -2
  39. package/dist/api/assembly/solvers/linalg.js.map +1 -1
  40. package/dist/api/assembly/solvers/types.d.ts +2 -5
  41. package/dist/api/assembly/solvers/types.d.ts.map +1 -1
  42. package/dist/api/assembly/solvers/types.js +1 -4
  43. package/dist/api/assembly/solvers/types.js.map +1 -1
  44. package/dist/api/boolean.d.ts.map +1 -1
  45. package/dist/api/boolean.js +7 -6
  46. package/dist/api/boolean.js.map +1 -1
  47. package/dist/api/brep-mirror/booleanFns.d.ts +3 -3
  48. package/dist/api/brep-mirror/booleanFns.js +5 -5
  49. package/dist/api/brep-mirror/booleanFns.js.map +1 -1
  50. package/dist/api/brep-mirror/compoundFns.d.ts +1 -1
  51. package/dist/api/brep-mirror/compoundFns.js +4 -4
  52. package/dist/api/brep-mirror/compoundFns.js.map +1 -1
  53. package/dist/api/brep-mirror/healingFns.d.ts +4 -4
  54. package/dist/api/brep-mirror/healingFns.js +4 -4
  55. package/dist/api/brep-mirror/healingFns.js.map +1 -1
  56. package/dist/api/brep-mirror/hullFns.d.ts +2 -2
  57. package/dist/api/brep-mirror/hullFns.js +2 -2
  58. package/dist/api/brep-mirror/hullFns.js.map +1 -1
  59. package/dist/api/brep-mirror/patternFns.d.ts +5 -5
  60. package/dist/api/brep-mirror/patternFns.js +10 -10
  61. package/dist/api/brep-mirror/patternFns.js.map +1 -1
  62. package/dist/api/brep-mirror/primitiveFns.d.ts +4 -4
  63. package/dist/api/brep-mirror/primitiveFns.js +4 -4
  64. package/dist/api/brep-mirror/primitiveFns.js.map +1 -1
  65. package/dist/api/brep-mirror/roofFns.d.ts +3 -3
  66. package/dist/api/brep-mirror/roofFns.js +7 -7
  67. package/dist/api/brep-mirror/roofFns.js.map +1 -1
  68. package/dist/api/brep-mirror/sweepFns.d.ts +7 -7
  69. package/dist/api/brep-mirror/sweepFns.js +14 -14
  70. package/dist/api/brep-mirror/sweepFns.js.map +1 -1
  71. package/dist/api/brep-mirror/threadFns.d.ts +1 -1
  72. package/dist/api/brep-mirror/threadFns.js +1 -1
  73. package/dist/api/brep-mirror/threadFns.js.map +1 -1
  74. package/dist/api/brep-mirror/topologyFns.d.ts +5 -5
  75. package/dist/api/brep-mirror/topologyFns.js +8 -8
  76. package/dist/api/brep-mirror/topologyFns.js.map +1 -1
  77. package/dist/api/brep-operations/booleanFns.d.ts +40 -0
  78. package/dist/api/brep-operations/booleanFns.d.ts.map +1 -0
  79. package/dist/api/brep-operations/booleanFns.js +104 -0
  80. package/dist/api/brep-operations/booleanFns.js.map +1 -0
  81. package/dist/api/brep-operations/brepHelpers.d.ts +55 -0
  82. package/dist/api/brep-operations/brepHelpers.d.ts.map +1 -0
  83. package/dist/api/brep-operations/brepHelpers.js +131 -0
  84. package/dist/api/brep-operations/brepHelpers.js.map +1 -0
  85. package/dist/api/brep-operations/compoundFns.d.ts +46 -0
  86. package/dist/api/brep-operations/compoundFns.d.ts.map +1 -0
  87. package/dist/api/brep-operations/compoundFns.js +299 -0
  88. package/dist/api/brep-operations/compoundFns.js.map +1 -0
  89. package/dist/api/brep-operations/healingFns.d.ts +78 -0
  90. package/dist/api/brep-operations/healingFns.d.ts.map +1 -0
  91. package/dist/api/brep-operations/healingFns.js +294 -0
  92. package/dist/api/brep-operations/healingFns.js.map +1 -0
  93. package/dist/api/brep-operations/hullFns.d.ts +20 -0
  94. package/dist/api/brep-operations/hullFns.d.ts.map +1 -0
  95. package/dist/api/brep-operations/hullFns.js +46 -0
  96. package/dist/api/brep-operations/hullFns.js.map +1 -0
  97. package/dist/api/brep-operations/joinery-brep.d.ts +172 -0
  98. package/dist/api/brep-operations/joinery-brep.d.ts.map +1 -0
  99. package/dist/api/brep-operations/joinery-brep.js +463 -0
  100. package/dist/api/brep-operations/joinery-brep.js.map +1 -0
  101. package/dist/api/brep-operations/patternFns.d.ts +43 -0
  102. package/dist/api/brep-operations/patternFns.d.ts.map +1 -0
  103. package/dist/api/brep-operations/patternFns.js +178 -0
  104. package/dist/api/brep-operations/patternFns.js.map +1 -0
  105. package/dist/api/brep-operations/primitiveFns.d.ts +42 -0
  106. package/dist/api/brep-operations/primitiveFns.d.ts.map +1 -0
  107. package/dist/api/brep-operations/primitiveFns.js +104 -0
  108. package/dist/api/brep-operations/primitiveFns.js.map +1 -0
  109. package/dist/api/brep-operations/roofFns.d.ts +24 -0
  110. package/dist/api/brep-operations/roofFns.d.ts.map +1 -0
  111. package/dist/api/brep-operations/roofFns.js +229 -0
  112. package/dist/api/brep-operations/roofFns.js.map +1 -0
  113. package/dist/api/brep-operations/straightSkeleton.d.ts +36 -0
  114. package/dist/api/brep-operations/straightSkeleton.d.ts.map +1 -0
  115. package/dist/api/brep-operations/straightSkeleton.js +431 -0
  116. package/dist/api/brep-operations/straightSkeleton.js.map +1 -0
  117. package/dist/api/brep-operations/sweepFns.d.ts +60 -0
  118. package/dist/api/brep-operations/sweepFns.d.ts.map +1 -0
  119. package/dist/api/brep-operations/sweepFns.js +323 -0
  120. package/dist/api/brep-operations/sweepFns.js.map +1 -0
  121. package/dist/api/brep-operations/threadFns.d.ts +83 -0
  122. package/dist/api/brep-operations/threadFns.d.ts.map +1 -0
  123. package/dist/api/brep-operations/threadFns.js +138 -0
  124. package/dist/api/brep-operations/threadFns.js.map +1 -0
  125. package/dist/api/brep-operations/topologyFns.d.ts +90 -0
  126. package/dist/api/brep-operations/topologyFns.d.ts.map +1 -0
  127. package/dist/api/brep-operations/topologyFns.js +276 -0
  128. package/dist/api/brep-operations/topologyFns.js.map +1 -0
  129. package/dist/api/brep-topology.d.ts +1 -1
  130. package/dist/api/brep-topology.d.ts.map +1 -1
  131. package/dist/api/brep-topology.js +1 -1
  132. package/dist/api/brep-topology.js.map +1 -1
  133. package/dist/api/brepjs-compat/index.d.ts +1 -1
  134. package/dist/api/brepjs-compat/index.js +3 -3
  135. package/dist/api/brepjs-compat/index.js.map +1 -1
  136. package/dist/api/cadquery-selectors/borrow-bridge.d.ts.map +1 -1
  137. package/dist/api/cadquery-selectors/borrow-bridge.js +3 -4
  138. package/dist/api/cadquery-selectors/borrow-bridge.js.map +1 -1
  139. package/dist/api/curve-sketch/index.d.ts +235 -0
  140. package/dist/api/curve-sketch/index.d.ts.map +1 -0
  141. package/dist/api/curve-sketch/index.js +487 -0
  142. package/dist/api/curve-sketch/index.js.map +1 -0
  143. package/dist/api/engrave.d.ts.map +1 -1
  144. package/dist/api/engrave.js +3 -2
  145. package/dist/api/engrave.js.map +1 -1
  146. package/dist/api/export-brep.d.ts +41 -0
  147. package/dist/api/export-brep.d.ts.map +1 -0
  148. package/dist/api/export-brep.js +58 -0
  149. package/dist/api/export-brep.js.map +1 -0
  150. package/dist/api/export-stl.d.ts +50 -0
  151. package/dist/api/export-stl.d.ts.map +1 -0
  152. package/dist/api/export-stl.js +99 -0
  153. package/dist/api/export-stl.js.map +1 -0
  154. package/dist/api/extrude.d.ts +8 -11
  155. package/dist/api/extrude.d.ts.map +1 -1
  156. package/dist/api/extrude.js +11 -14
  157. package/dist/api/extrude.js.map +1 -1
  158. package/dist/api/fillet-variable.d.ts +2 -2
  159. package/dist/api/fillet-variable.js +2 -2
  160. package/dist/api/fillet-variable.js.map +1 -1
  161. package/dist/api/fillet.d.ts +2 -4
  162. package/dist/api/fillet.d.ts.map +1 -1
  163. package/dist/api/fillet.js +2 -4
  164. package/dist/api/fillet.js.map +1 -1
  165. package/dist/api/generated/2d.d.ts +4 -0
  166. package/dist/api/generated/2d.d.ts.map +1 -1
  167. package/dist/api/generated/2d.js +4 -0
  168. package/dist/api/generated/2d.js.map +1 -1
  169. package/dist/api/generated/core.d.ts +4 -0
  170. package/dist/api/generated/core.d.ts.map +1 -1
  171. package/dist/api/generated/core.js +4 -0
  172. package/dist/api/generated/core.js.map +1 -1
  173. package/dist/api/generated/gear.d.ts +4 -0
  174. package/dist/api/generated/gear.d.ts.map +1 -1
  175. package/dist/api/generated/gear.js +4 -0
  176. package/dist/api/generated/gear.js.map +1 -1
  177. package/dist/api/generated/io.d.ts +4 -0
  178. package/dist/api/generated/io.d.ts.map +1 -1
  179. package/dist/api/generated/io.js +4 -0
  180. package/dist/api/generated/io.js.map +1 -1
  181. package/dist/api/generated/kernel.d.ts +4 -0
  182. package/dist/api/generated/kernel.d.ts.map +1 -1
  183. package/dist/api/generated/kernel.js +4 -0
  184. package/dist/api/generated/kernel.js.map +1 -1
  185. package/dist/api/generated/measurement.d.ts +21 -21
  186. package/dist/api/generated/measurement.d.ts.map +1 -1
  187. package/dist/api/generated/measurement.js +25 -21
  188. package/dist/api/generated/measurement.js.map +1 -1
  189. package/dist/api/generated/ns.d.ts +4 -0
  190. package/dist/api/generated/ns.d.ts.map +1 -1
  191. package/dist/api/generated/ns.js +4 -0
  192. package/dist/api/generated/ns.js.map +1 -1
  193. package/dist/api/generated/operations.d.ts +32 -32
  194. package/dist/api/generated/operations.d.ts.map +1 -1
  195. package/dist/api/generated/operations.js +52 -48
  196. package/dist/api/generated/operations.js.map +1 -1
  197. package/dist/api/generated/projection.d.ts +4 -0
  198. package/dist/api/generated/projection.d.ts.map +1 -1
  199. package/dist/api/generated/projection.js +4 -0
  200. package/dist/api/generated/projection.js.map +1 -1
  201. package/dist/api/generated/query.d.ts +4 -0
  202. package/dist/api/generated/query.d.ts.map +1 -1
  203. package/dist/api/generated/query.js +4 -0
  204. package/dist/api/generated/query.js.map +1 -1
  205. package/dist/api/generated/sketching.d.ts +2 -2
  206. package/dist/api/generated/sketching.d.ts.map +1 -1
  207. package/dist/api/generated/sketching.js +7 -3
  208. package/dist/api/generated/sketching.js.map +1 -1
  209. package/dist/api/generated/text.d.ts +4 -0
  210. package/dist/api/generated/text.d.ts.map +1 -1
  211. package/dist/api/generated/text.js +4 -0
  212. package/dist/api/generated/text.js.map +1 -1
  213. package/dist/api/generated/topology.d.ts +45 -45
  214. package/dist/api/generated/topology.d.ts.map +1 -1
  215. package/dist/api/generated/topology.js +67 -63
  216. package/dist/api/generated/topology.js.map +1 -1
  217. package/dist/api/generated/view.d.ts +4 -0
  218. package/dist/api/generated/view.d.ts.map +1 -1
  219. package/dist/api/generated/view.js +4 -0
  220. package/dist/api/generated/view.js.map +1 -1
  221. package/dist/api/geom-types/constants.d.ts +11 -0
  222. package/dist/api/geom-types/constants.d.ts.map +1 -0
  223. package/dist/api/geom-types/constants.js +11 -0
  224. package/dist/api/geom-types/constants.js.map +1 -0
  225. package/dist/api/geom-types/index.d.ts +21 -0
  226. package/dist/api/geom-types/index.d.ts.map +1 -0
  227. package/dist/api/geom-types/index.js +22 -0
  228. package/dist/api/geom-types/index.js.map +1 -0
  229. package/dist/api/geom-types/planeOps.d.ts +98 -0
  230. package/dist/api/geom-types/planeOps.d.ts.map +1 -0
  231. package/dist/api/geom-types/planeOps.js +170 -0
  232. package/dist/api/geom-types/planeOps.js.map +1 -0
  233. package/dist/api/geom-types/planeTypes.d.ts +24 -0
  234. package/dist/api/geom-types/planeTypes.d.ts.map +1 -0
  235. package/dist/api/geom-types/planeTypes.js +8 -0
  236. package/dist/api/geom-types/planeTypes.js.map +1 -0
  237. package/dist/api/geom-types/types.d.ts +64 -0
  238. package/dist/api/geom-types/types.d.ts.map +1 -0
  239. package/dist/api/geom-types/types.js +48 -0
  240. package/dist/api/geom-types/types.js.map +1 -0
  241. package/dist/api/geom-types/vecOps.d.ts +124 -0
  242. package/dist/api/geom-types/vecOps.d.ts.map +1 -0
  243. package/dist/api/geom-types/vecOps.js +202 -0
  244. package/dist/api/geom-types/vecOps.js.map +1 -0
  245. package/dist/api/geom.d.ts.map +1 -1
  246. package/dist/api/geom.js +6 -5
  247. package/dist/api/geom.js.map +1 -1
  248. package/dist/api/half-space.d.ts +56 -0
  249. package/dist/api/half-space.d.ts.map +1 -0
  250. package/dist/api/half-space.js +82 -0
  251. package/dist/api/half-space.js.map +1 -0
  252. package/dist/api/helix.d.ts +10 -1
  253. package/dist/api/helix.d.ts.map +1 -1
  254. package/dist/api/helix.js +19 -3
  255. package/dist/api/helix.js.map +1 -1
  256. package/dist/api/index.d.ts +15 -6
  257. package/dist/api/index.d.ts.map +1 -1
  258. package/dist/api/index.js +29 -8
  259. package/dist/api/index.js.map +1 -1
  260. package/dist/api/internal/compat-op.d.ts +4 -30
  261. package/dist/api/internal/compat-op.d.ts.map +1 -1
  262. package/dist/api/internal/compat-op.js +10 -42
  263. package/dist/api/internal/compat-op.js.map +1 -1
  264. package/dist/api/internal/compat-projection.d.ts +5 -5
  265. package/dist/api/internal/compat-projection.js +5 -5
  266. package/dist/api/internal/compat-projection.js.map +1 -1
  267. package/dist/api/internal/dual-form-args.d.ts +0 -2
  268. package/dist/api/internal/dual-form-args.d.ts.map +1 -1
  269. package/dist/api/internal/dual-form-args.js +1 -3
  270. package/dist/api/internal/dual-form-args.js.map +1 -1
  271. package/dist/api/internal/l3-bridge.d.ts +5 -37
  272. package/dist/api/internal/l3-bridge.d.ts.map +1 -1
  273. package/dist/api/internal/l3-bridge.js +7 -76
  274. package/dist/api/internal/l3-bridge.js.map +1 -1
  275. package/dist/api/internal/profile-wire.d.ts +1 -1
  276. package/dist/api/internal/profile-wire.js +1 -1
  277. package/dist/api/internal/profile-wire.js.map +1 -1
  278. package/dist/api/internal/result-unwrap.d.ts +4 -6
  279. package/dist/api/internal/result-unwrap.d.ts.map +1 -1
  280. package/dist/api/internal/result-unwrap.js +4 -6
  281. package/dist/api/internal/result-unwrap.js.map +1 -1
  282. package/dist/api/knurl.d.ts.map +1 -1
  283. package/dist/api/knurl.js +5 -3
  284. package/dist/api/knurl.js.map +1 -1
  285. package/dist/api/loft.d.ts +2 -2
  286. package/dist/api/loft.d.ts.map +1 -1
  287. package/dist/api/loft.js +2 -2
  288. package/dist/api/loft.js.map +1 -1
  289. package/dist/api/measurement/index.d.ts +3 -3
  290. package/dist/api/measurement/index.js +3 -3
  291. package/dist/api/measurement/index.js.map +1 -1
  292. package/dist/api/meta.d.ts +0 -2
  293. package/dist/api/meta.d.ts.map +1 -1
  294. package/dist/api/meta.js +0 -2
  295. package/dist/api/meta.js.map +1 -1
  296. package/dist/api/offset2d.d.ts +49 -0
  297. package/dist/api/offset2d.d.ts.map +1 -0
  298. package/dist/api/offset2d.js +86 -0
  299. package/dist/api/offset2d.js.map +1 -0
  300. package/dist/api/pattern.js +3 -3
  301. package/dist/api/pattern.js.map +1 -1
  302. package/dist/api/primitives.d.ts.map +1 -1
  303. package/dist/api/primitives.js +7 -6
  304. package/dist/api/primitives.js.map +1 -1
  305. package/dist/api/replicate.d.ts +2 -2
  306. package/dist/api/replicate.d.ts.map +1 -1
  307. package/dist/api/replicate.js +12 -12
  308. package/dist/api/replicate.js.map +1 -1
  309. package/dist/api/result.d.ts +1 -1
  310. package/dist/api/result.js +1 -1
  311. package/dist/api/result.js.map +1 -1
  312. package/dist/api/revolve.d.ts +2 -2
  313. package/dist/api/revolve.js +3 -3
  314. package/dist/api/revolve.js.map +1 -1
  315. package/dist/api/screw.d.ts +1 -1
  316. package/dist/api/screw.d.ts.map +1 -1
  317. package/dist/api/screw.js +5 -4
  318. package/dist/api/screw.js.map +1 -1
  319. package/dist/api/sdf.d.ts.map +1 -1
  320. package/dist/api/sdf.js +3 -2
  321. package/dist/api/sdf.js.map +1 -1
  322. package/dist/api/shape-type/index.d.ts +141 -0
  323. package/dist/api/shape-type/index.d.ts.map +1 -0
  324. package/dist/api/shape-type/index.js +182 -0
  325. package/dist/api/shape-type/index.js.map +1 -0
  326. package/dist/api/shell.d.ts +2 -2
  327. package/dist/api/shell.js +2 -2
  328. package/dist/api/shell.js.map +1 -1
  329. package/dist/api/solid-from-faces.d.ts +45 -0
  330. package/dist/api/solid-from-faces.d.ts.map +1 -0
  331. package/dist/api/solid-from-faces.js +72 -0
  332. package/dist/api/solid-from-faces.js.map +1 -0
  333. package/dist/api/solid-offset/index.d.ts +67 -0
  334. package/dist/api/solid-offset/index.d.ts.map +1 -0
  335. package/dist/api/solid-offset/index.js +132 -0
  336. package/dist/api/solid-offset/index.js.map +1 -0
  337. package/dist/api/surface/arg-spec.d.ts +35 -33
  338. package/dist/api/surface/arg-spec.d.ts.map +1 -1
  339. package/dist/api/surface/arg-spec.js +222 -224
  340. package/dist/api/surface/arg-spec.js.map +1 -1
  341. package/dist/api/surface-face/index.d.ts +104 -0
  342. package/dist/api/surface-face/index.d.ts.map +1 -0
  343. package/dist/api/surface-face/index.js +217 -0
  344. package/dist/api/surface-face/index.js.map +1 -0
  345. package/dist/api/surface.d.ts +44 -0
  346. package/dist/api/surface.d.ts.map +1 -0
  347. package/dist/api/surface.js +66 -0
  348. package/dist/api/surface.js.map +1 -0
  349. package/dist/api/sweep.d.ts +59 -9
  350. package/dist/api/sweep.d.ts.map +1 -1
  351. package/dist/api/sweep.js +11 -6
  352. package/dist/api/sweep.js.map +1 -1
  353. package/dist/api/thicken.d.ts +1 -1
  354. package/dist/api/thicken.js +1 -1
  355. package/dist/api/thicken.js.map +1 -1
  356. package/dist/api/transform.d.ts +5 -5
  357. package/dist/api/transform.d.ts.map +1 -1
  358. package/dist/api/transform.js +11 -10
  359. package/dist/api/transform.js.map +1 -1
  360. package/dist/api/view/cameraFns.d.ts +1 -1
  361. package/dist/api/view/cameraFns.d.ts.map +1 -1
  362. package/dist/api/view/cameraFns.js +1 -1
  363. package/dist/api/view/cameraFns.js.map +1 -1
  364. package/dist/api/view/index.d.ts +0 -2
  365. package/dist/api/view/index.d.ts.map +1 -1
  366. package/dist/api/view/index.js +0 -2
  367. package/dist/api/view/index.js.map +1 -1
  368. package/dist/api/view/projectionPlanes.d.ts +1 -1
  369. package/dist/api/view/projectionPlanes.d.ts.map +1 -1
  370. package/dist/api/view/projectionPlanes.js.map +1 -1
  371. package/dist/api/view/view-camera.d.ts +7 -9
  372. package/dist/api/view/view-camera.d.ts.map +1 -1
  373. package/dist/api/view/view-camera.js +4 -6
  374. package/dist/api/view/view-camera.js.map +1 -1
  375. package/dist/api/view/view-projection.d.ts +0 -2
  376. package/dist/api/view/view-projection.d.ts.map +1 -1
  377. package/dist/api/view/view-projection.js +0 -2
  378. package/dist/api/view/view-projection.js.map +1 -1
  379. package/dist/api/view/view-sheet.d.ts +0 -2
  380. package/dist/api/view/view-sheet.d.ts.map +1 -1
  381. package/dist/api/view/view-sheet.js +0 -2
  382. package/dist/api/view/view-sheet.js.map +1 -1
  383. package/dist/api/view-export/index.d.ts +97 -0
  384. package/dist/api/view-export/index.d.ts.map +1 -0
  385. package/dist/api/view-export/index.js +118 -0
  386. package/dist/api/view-export/index.js.map +1 -0
  387. package/dist/brep/brep-ops.d.ts +89 -1
  388. package/dist/brep/brep-ops.d.ts.map +1 -1
  389. package/dist/brep/brep-ops.js +176 -10
  390. package/dist/brep/brep-ops.js.map +1 -1
  391. package/dist/brep/brep-topology.d.ts +20 -0
  392. package/dist/brep/brep-topology.d.ts.map +1 -1
  393. package/dist/brep/brep-topology.js +46 -0
  394. package/dist/brep/brep-topology.js.map +1 -1
  395. package/dist/brep/engine/adapters/occt.d.ts +1 -1
  396. package/dist/brep/engine/adapters/occt.js +7 -7
  397. package/dist/brep/engine/adapters/occt.js.map +1 -1
  398. package/dist/brep/engine/primitives.d.ts +2 -3
  399. package/dist/brep/engine/primitives.d.ts.map +1 -1
  400. package/dist/brep/engine/primitives.js +1 -2
  401. package/dist/brep/engine/primitives.js.map +1 -1
  402. package/dist/brep/engine/registry.d.ts +1 -1
  403. package/dist/brep/engine/registry.js +1 -1
  404. package/dist/brep/engine/registry.js.map +1 -1
  405. package/dist/brep/engine/types.d.ts +2 -2
  406. package/dist/brep/engine/types.js.map +1 -1
  407. package/dist/brep/handle-bridge.d.ts +2 -2
  408. package/dist/brep/handle-bridge.js +2 -2
  409. package/dist/brep/handle-bridge.js.map +1 -1
  410. package/dist/brep/index.d.ts +6 -3
  411. package/dist/brep/index.d.ts.map +1 -1
  412. package/dist/brep/index.js +6 -3
  413. package/dist/brep/index.js.map +1 -1
  414. package/dist/brepkit-kernel/brepkitKernel.d.ts +1 -1
  415. package/dist/brepkit-kernel/brepkitKernel.js +2 -2
  416. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  417. package/dist/browser.d.ts +2 -2
  418. package/dist/browser.d.ts.map +1 -1
  419. package/dist/browser.js +5 -4
  420. package/dist/browser.js.map +1 -1
  421. package/dist/cad-runtime/admit-compat-lib.d.ts +3 -10
  422. package/dist/cad-runtime/admit-compat-lib.d.ts.map +1 -1
  423. package/dist/cad-runtime/admit-compat-lib.js +3 -9
  424. package/dist/cad-runtime/admit-compat-lib.js.map +1 -1
  425. package/dist/cad-runtime/backend-dispatch.js +12 -3
  426. package/dist/cad-runtime/backend-dispatch.js.map +1 -1
  427. package/dist/cad-runtime/direct-executor.d.ts +6 -3
  428. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  429. package/dist/cad-runtime/direct-executor.js +31 -9
  430. package/dist/cad-runtime/direct-executor.js.map +1 -1
  431. package/dist/cad-runtime/interp/env.d.ts +1 -1
  432. package/dist/cad-runtime/interp/env.js.map +1 -1
  433. package/dist/cad-runtime/lib-id.d.ts +0 -2
  434. package/dist/cad-runtime/lib-id.d.ts.map +1 -1
  435. package/dist/cad-runtime/lib-id.js +0 -2
  436. package/dist/cad-runtime/lib-id.js.map +1 -1
  437. package/dist/cad-runtime/live-shapes.d.ts +3 -5
  438. package/dist/cad-runtime/live-shapes.d.ts.map +1 -1
  439. package/dist/cad-runtime/live-shapes.js +8 -10
  440. package/dist/cad-runtime/live-shapes.js.map +1 -1
  441. package/dist/cad-runtime/ports.d.ts +3 -3
  442. package/dist/cad-runtime/ports.js.map +1 -1
  443. package/dist/cad-runtime/runtime.d.ts +21 -7
  444. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  445. package/dist/cad-runtime/runtime.js +45 -6
  446. package/dist/cad-runtime/runtime.js.map +1 -1
  447. package/dist/define-op.d.ts +4 -3
  448. package/dist/define-op.d.ts.map +1 -1
  449. package/dist/define-op.js +2 -2
  450. package/dist/define-op.js.map +1 -1
  451. package/dist/geometry2d/bridge/plane.d.ts +1 -1
  452. package/dist/geometry2d/bridge/plane.js +1 -1
  453. package/dist/geometry2d/bridge/plane.js.map +1 -1
  454. package/dist/geometry2d/curve2d.d.ts +1 -1
  455. package/dist/geometry2d/curve2d.js +1 -1
  456. package/dist/geometry2d/curve2d.js.map +1 -1
  457. package/dist/index.d.ts +1 -1
  458. package/dist/index.d.ts.map +1 -1
  459. package/dist/index.js +10 -4
  460. package/dist/index.js.map +1 -1
  461. package/dist/io/fai-zip/container-read.d.ts +16 -0
  462. package/dist/io/fai-zip/container-read.d.ts.map +1 -1
  463. package/dist/io/fai-zip/container-read.js +22 -0
  464. package/dist/io/fai-zip/container-read.js.map +1 -1
  465. package/dist/io/fai-zip/index.d.ts +1 -1
  466. package/dist/io/fai-zip/index.d.ts.map +1 -1
  467. package/dist/io/fai-zip/index.js +1 -1
  468. package/dist/io/fai-zip/index.js.map +1 -1
  469. package/dist/lang/code-to-args.d.ts.map +1 -1
  470. package/dist/lang/code-to-args.js +10 -1
  471. package/dist/lang/code-to-args.js.map +1 -1
  472. package/dist/lang/determinism-scanner.d.ts.map +1 -1
  473. package/dist/lang/determinism-scanner.js +22 -9
  474. package/dist/lang/determinism-scanner.js.map +1 -1
  475. package/dist/lang/metadata-extractor.d.ts +27 -6
  476. package/dist/lang/metadata-extractor.d.ts.map +1 -1
  477. package/dist/lang/metadata-extractor.js +88 -8
  478. package/dist/lang/metadata-extractor.js.map +1 -1
  479. package/dist/lang/parse-error.d.ts +4 -0
  480. package/dist/lang/parse-error.d.ts.map +1 -1
  481. package/dist/lang/parse-error.js.map +1 -1
  482. package/dist/lang/security-scanner.d.ts +27 -2
  483. package/dist/lang/security-scanner.d.ts.map +1 -1
  484. package/dist/lang/security-scanner.js +29 -2
  485. package/dist/lang/security-scanner.js.map +1 -1
  486. package/dist/lang/source-edit.d.ts +2 -2
  487. package/dist/lang/source-edit.js.map +1 -1
  488. package/dist/lang/symbol-table.generated.d.ts +36 -0
  489. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  490. package/dist/lang/symbol-table.generated.js +36 -0
  491. package/dist/lang/symbol-table.generated.js.map +1 -1
  492. package/dist/mesh/import-model.d.ts +94 -0
  493. package/dist/mesh/import-model.d.ts.map +1 -0
  494. package/dist/mesh/import-model.js +15 -0
  495. package/dist/mesh/import-model.js.map +1 -0
  496. package/dist/mesh/index.d.ts +19 -58
  497. package/dist/mesh/index.d.ts.map +1 -1
  498. package/dist/mesh/index.js +19 -70
  499. package/dist/mesh/index.js.map +1 -1
  500. package/dist/mesh/io.d.ts +33 -16
  501. package/dist/mesh/io.d.ts.map +1 -1
  502. package/dist/mesh/io.js +144 -39
  503. package/dist/mesh/io.js.map +1 -1
  504. package/dist/mesh/primitives.js +1 -1
  505. package/dist/mesh/primitives.js.map +1 -1
  506. package/dist/mesh/threemf-bambu.d.ts +12 -1
  507. package/dist/mesh/threemf-bambu.d.ts.map +1 -1
  508. package/dist/mesh/threemf-bambu.js +68 -16
  509. package/dist/mesh/threemf-bambu.js.map +1 -1
  510. package/dist/mesh/threemf-loader.d.ts +14 -1
  511. package/dist/mesh/threemf-loader.d.ts.map +1 -1
  512. package/dist/mesh/threemf-loader.js +24 -7
  513. package/dist/mesh/threemf-loader.js.map +1 -1
  514. package/dist/mesh/transform.d.ts +1 -1
  515. package/dist/mesh/transform.js +1 -1
  516. package/dist/mesh/transform.js.map +1 -1
  517. package/dist/mesh/types.d.ts +5 -5
  518. package/dist/mesh/types.d.ts.map +1 -1
  519. package/dist/mesh/types.js.map +1 -1
  520. package/dist/node-host/cli.d.ts +49 -1
  521. package/dist/node-host/cli.d.ts.map +1 -1
  522. package/dist/node-host/cli.js +125 -19
  523. package/dist/node-host/cli.js.map +1 -1
  524. package/dist/node-host/execute-script.d.ts +55 -0
  525. package/dist/node-host/execute-script.d.ts.map +1 -0
  526. package/dist/node-host/execute-script.js +46 -0
  527. package/dist/node-host/execute-script.js.map +1 -0
  528. package/dist/node.d.ts +2 -0
  529. package/dist/node.d.ts.map +1 -1
  530. package/dist/node.js +3 -0
  531. package/dist/node.js.map +1 -1
  532. package/dist/occt-kernel/generated/occtPlatform.generated.d.ts +260 -0
  533. package/dist/occt-kernel/generated/occtPlatform.generated.d.ts.map +1 -0
  534. package/dist/occt-kernel/generated/occtPlatform.generated.js +875 -0
  535. package/dist/occt-kernel/generated/occtPlatform.generated.js.map +1 -0
  536. package/dist/occt-kernel/hullGeometry.d.ts +2 -2
  537. package/dist/occt-kernel/hullGeometry.js +2 -3
  538. package/dist/occt-kernel/hullGeometry.js.map +1 -1
  539. package/dist/occt-kernel/hullOps.d.ts +3 -3
  540. package/dist/occt-kernel/hullOps.js +4 -4
  541. package/dist/occt-kernel/hullOps.js.map +1 -1
  542. package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
  543. package/dist/occt-kernel/occt-primitives.js +31 -4
  544. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  545. package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
  546. package/dist/occt-kernel/occtKernel.js +18 -0
  547. package/dist/occt-kernel/occtKernel.js.map +1 -1
  548. package/dist/occt-scan/recognize.d.ts +58 -0
  549. package/dist/occt-scan/recognize.d.ts.map +1 -0
  550. package/dist/occt-scan/recognize.js +216 -0
  551. package/dist/occt-scan/recognize.js.map +1 -0
  552. package/dist/primitives/brep-primitives.js +7 -7
  553. package/dist/primitives/brep-primitives.js.map +1 -1
  554. package/dist/result/bug.d.ts +1 -1
  555. package/dist/result/bug.js +1 -1
  556. package/dist/result/bug.js.map +1 -1
  557. package/dist/result/errors.d.ts +2 -2
  558. package/dist/result/errors.d.ts.map +1 -1
  559. package/dist/result/errors.js +1 -1
  560. package/dist/result/errors.js.map +1 -1
  561. package/dist/result/vec3.d.ts +1 -1
  562. package/dist/result/vec3.js +1 -1
  563. package/dist/result/vec3.js.map +1 -1
  564. package/dist/runtime-state.d.ts +16 -0
  565. package/dist/runtime-state.d.ts.map +1 -1
  566. package/dist/runtime-state.js +27 -0
  567. package/dist/runtime-state.js.map +1 -1
  568. package/dist/script-globals.d.ts +24 -0
  569. package/dist/script-globals.d.ts.map +1 -0
  570. package/dist/script-globals.js +24 -0
  571. package/dist/script-globals.js.map +1 -0
  572. package/dist/shape.d.ts +24 -0
  573. package/dist/shape.d.ts.map +1 -1
  574. package/dist/shape.js +40 -0
  575. package/dist/shape.js.map +1 -1
  576. package/dist/topology/naming/lineage.d.ts +3 -2
  577. package/dist/topology/naming/lineage.d.ts.map +1 -1
  578. package/dist/topology/naming/lineage.js.map +1 -1
  579. package/dist/weapp.d.ts +1 -1
  580. package/dist/weapp.js +1 -1
  581. package/dist/weapp.js.map +1 -1
  582. package/package.json +8 -10
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * api/assembly/joints — 运动副声明与运动学解算(P3)
3
3
  *
4
- * JointSpec 是 .fai.js 可序列化子集(派生字段 dofs 由 vendored 工厂构造,
4
+ * JointSpec 是 .fai.js 可序列化子集(派生字段 dofs 由 brepjs 工厂构造,
5
5
  * 与 brepjs Joint.dofs 的组合顺序对齐:cylindrical → [rotation, translation]、
6
6
  * planar → [u, v, rotation]、spherical → [x, y, z])。
7
7
  *
@@ -9,8 +9,8 @@
9
9
  * spherical 在 buildJoint 里显式抛错(绝不静默降级成单 DOF),待 per-DOF ranges
10
10
  * 启用(JointSpec.dofs 已按此预留)。
11
11
  *
12
- * 链路:JointSpec[] → buildJoint(vendored 工厂)→ buildKinematicTree(建树三步
13
- * + 校验)→ solveKinematics(vendored forwardKinematics)→ per-member 位姿。
12
+ * 链路:JointSpec[] → buildJoint(brepjs 工厂)→ buildKinematicTree(建树三步
13
+ * + 校验)→ solveKinematics(brepjs forwardKinematics)→ per-member 位姿。
14
14
  *
15
15
  * cad.* 查询函数(jointTrajectory / inverseKinematics / mechanismDOF)是无副作用
16
16
  * 纯函数:输入纯数据、输出纯数据,不挂在 assembly receiver 上。
@@ -25,13 +25,13 @@ import { fromBrepjsQuat, toBrepjsQuat, jointPoseToAssemblyTransform, isIdentityP
25
25
  /**
26
26
  * 由 JointSpec 构造 brepjs Joint。
27
27
  *
28
- * revolute/prismatic 走 vendored 工厂(主 DOF 的 value 在工厂内 clamp 到
28
+ * revolute/prismatic 走 brepjs 工厂(主 DOF 的 value 在工厂内 clamp 到
29
29
  * [min,max]);cylindrical/planar/spherical 显式抛错(多 DOF 未启用,绝不
30
30
  * 静默降级)。offset 的四元数经 toBrepjsQuat 换序(faijs [x,y,z,w] → brepjs
31
31
  * [w,x,y,z])。
32
32
  *
33
33
  * @param spec - the serializable joint declaration.
34
- * @returns the vendored brepjs Joint (with offset attached when declared).
34
+ * @returns the Joint (with offset attached when declared).
35
35
  * @throws Error on multi-DOF joint types and unknown joint types.
36
36
  */
37
37
  export function buildJoint(spec) {
@@ -70,7 +70,7 @@ export function buildJoint(spec) {
70
70
  }
71
71
  // ── buildKinematicTree:建树三步 + 校验 ──
72
72
  /**
73
- * 由成员名 + JointSpec[] 构建 kinematic AssemblyNode 树(vendored
73
+ * 由成员名 + JointSpec[] 构建 kinematic AssemblyNode 树(brepjs
74
74
  * forwardKinematics 只接受单个根;多成员必须有唯一合成根)。
75
75
  *
76
76
  * 校验(求解前,绝不静默):
@@ -133,7 +133,7 @@ function specMemberNames(joints) {
133
133
  return names;
134
134
  }
135
135
  /**
136
- * 运动学正解:buildKinematicTree → vendored forwardKinematics → per-member 位姿。
136
+ * 运动学正解:buildKinematicTree → brepjs forwardKinematics → per-member 位姿。
137
137
  *
138
138
  * 校验(求解前):成员名空串 / parent-child ∈ members / child 唯一驱动(都收在
139
139
  * buildKinematicTree 内);drive 键必须 ∈ joints 的 child 集(多余键是笔误,
@@ -184,8 +184,14 @@ export function solveKinematics(memberNames, joints, drive) {
184
184
  * 产出 steps+1 个采样(含两端点);joints 缺省值在两端取存储值。
185
185
  * 无 endEffector 参数(关节空间插值,不追踪端点)。
186
186
  *
187
- * @param p - trajectory query parameters.
188
- * @returns the sampled trajectory (poses with faijs-order quaternions).
187
+ * @group 查询
188
+ * @inputs 0
189
+ * @async false
190
+ * @qual ok
191
+ * @name jointTrajectory
192
+ * @note 纯函数:输入输出都是纯数据,不产 Shape、不依赖引擎;装配面契约见 `docs/api-contract.md` §12。
193
+ * @returns FaijsTrajectorySample[] 采样序列(steps+1 个,含两端点)。
194
+ * @param p - 轨迹查询参数。type:JointTrajectoryParams required:true
189
195
  */
190
196
  export function jointTrajectory(p) {
191
197
  const memberNames = specMemberNames(p.joints);
@@ -207,8 +213,14 @@ export function jointTrajectory(p) {
207
213
  * damped-least-squares IK:求使末端到达 target 的关节值。关节范围在每个迭代
208
214
  * clamp;不可达目标返回 converged:false 与最优配置。纯函数,无副作用。
209
215
  *
210
- * @param p - IK query parameters.
211
- * @returns the solved joint values plus convergence diagnostics.
216
+ * @group 查询
217
+ * @inputs 0
218
+ * @async false
219
+ * @qual ok
220
+ * @name inverseKinematics
221
+ * @note 纯函数:输入输出都是纯数据,不产 Shape、不依赖引擎;装配面契约见 `docs/api-contract.md` §12。
222
+ * @returns IKResult 关节值 + 收敛诊断(converged / iterations / error)。
223
+ * @param p - IK 查询参数。type:InverseKinematicsParams required:true
212
224
  */
213
225
  export function inverseKinematics(p) {
214
226
  const memberNames = specMemberNames(p.joints);
@@ -229,8 +241,14 @@ export function inverseKinematics(p) {
229
241
  * `cad.mechanismDOF({ joints })` — 开链机构自由度 = 各 joint DOF 数之和
230
242
  * (revolute/prismatic 各 1;串联两 revolute = 2)。纯函数,无副作用。
231
243
  *
232
- * @param p - DOF query parameters.
233
- * @returns the mechanism's total degree of freedom.
244
+ * @group 查询
245
+ * @inputs 0
246
+ * @async false
247
+ * @qual ok
248
+ * @name mechanismDOF
249
+ * @note 纯函数:输入输出都是纯数据,不产 Shape、不依赖引擎;装配面契约见 `docs/api-contract.md` §12。
250
+ * @returns number 机构总自由度。
251
+ * @param p - 自由度查询参数。type:MechanismDOFParams required:true
234
252
  */
235
253
  export function mechanismDOF(p) {
236
254
  const memberNames = specMemberNames(p.joints);
@@ -1 +1 @@
1
- {"version":3,"file":"joints.js","sourceRoot":"","sources":["../../../src/api/assembly/joints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,aAAa,EACb,cAAc,EACd,iBAAiB,IAAI,uBAAuB,EAC5C,YAAY,IAAI,kBAAkB,EAClC,eAAe,IAAI,qBAAqB,EACxC,iBAAiB,IAAI,uBAAuB,EAC5C,QAAQ,GAMT,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAqB,MAAM,yBAAyB,CAAA;AACzF,OAAO,EACL,cAAc,EACd,YAAY,EACZ,4BAA4B,EAC5B,cAAc,GAEf,MAAM,QAAQ,CAAA;AAmDf,4CAA4C;AAE5C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,IAAe;IACxC,MAAM,IAAI,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAA;IACzE,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAA;IACnE,IAAI,KAAY,CAAA;IAChB,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,UAAU;YACb,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;YAC7E,MAAK;QACP,KAAK,WAAW;YACd,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;YAC9E,MAAK;QACP,KAAK,aAAa,CAAC;QACnB,KAAK,QAAQ,CAAC;QACd,KAAK,WAAW;YACd,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,IAAI,gDAAgD,CAAC,CAAA;QACtG,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,UAAU,GAAU,IAAI,CAAC,IAAI,CAAA;YACnC,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QAC1E,CAAC;IACH,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ;YACnC,CAAC,CAAE,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAsC;YAC/E,CAAC,CAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAsC,CAAA;QACtD,KAAK,GAAG;YACN,GAAG,KAAK;YACR,MAAM,EAAE;gBACN,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAA8B;gBACzE,QAAQ;aACT;SACF,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,qCAAqC;AAErC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAqB,EAAE,MAAmB;IAC3E,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CACb,8BAA8B,CAAC,+DAA+D,CAC/F,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IACF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAA;IACtC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAA;IAChC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CACb,4BAA4B,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,gCAAgC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACrG,CAAA;QACH,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CACb,2BAA2B,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,gCAAgC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACnG,CAAA;QACH,CAAC;QACD,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,2BAA2B,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,qFAAqF,CAChI,CAAA;QACH,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;IAC7B,CAAC;IACD,eAAe;IACf,IAAI,IAAI,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAA;IAC3C,KAAK,MAAM,CAAC,IAAI,WAAW;QAAE,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAA;IACzE,KAAK,MAAM,CAAC,IAAI,MAAM;QAAE,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;IAC5D,OAAO,IAAI,CAAA;AACb,CAAC;AAkBD,kDAAkD;AAClD,SAAS,eAAe,CAAC,MAAmB;IAC1C,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;gBACX,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACf,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,eAAe,CAC7B,WAAqB,EACrB,MAAmB,EACnB,KAAyC;IAEzC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACjE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5B,MAAM,IAAI,KAAK,CACb,yBAAyB,GAAG,mDAAmD,CAAC,GAAG,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/G,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAG,kBAAkB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;IACpD,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAClD,MAAM,UAAU,GAAwB,EAAE,CAAA;IAC1C,MAAM,UAAU,GAAmC,EAAE,CAAA;IACrD,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC5B,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC9C,UAAU,CAAC,IAAI,CAAC,GAAG;YACjB,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAChE,QAAQ;SACT,CAAA;QACD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;YAAE,UAAU,CAAC,IAAI,CAAC,4BAA4B,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;IACvF,CAAC,CAAC,CAAA;IACF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAA;AACnC,CAAC;AAsBD;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,CAAwB;IACtD,MAAM,WAAW,GAAG,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,kBAAkB,CAAC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;IACtD,OAAO,qBAAqB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACpE,CAAC,EAAE,CAAC,CAAC,CAAC;QACN,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,KAAK,EAAE,IAAI,GAAG,CACZ,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI;YACJ;gBACE,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAChE,QAAQ,EAAE,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;aACxC;SACF,CAAC,CACH;KACF,CAAC,CAAC,CAAA;AACL,CAAC;AAoBD;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAA0B;IAC1D,MAAM,WAAW,GAAG,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,kBAAkB,CAAC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;IACtD,MAAM,MAAM,GAAmB;QAC7B,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ;QAC3B,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAA;IACD,MAAM,MAAM,GAAmB,uBAAuB,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAA;IAC9F,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAA;AACH,CAAC;AAOD;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,CAAqB;IAChD,MAAM,WAAW,GAAG,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,kBAAkB,CAAC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;IACtD,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAA;AACjC,CAAC","sourcesContent":["/**\n * api/assembly/joints — 运动副声明与运动学解算(P3)\n *\n * JointSpec 是 .fai.js 可序列化子集(派生字段 dofs 由 vendored 工厂构造,\n * 与 brepjs Joint.dofs 的组合顺序对齐:cylindrical → [rotation, translation]、\n * planar → [u, v, rotation]、spherical → [x, y, z])。\n *\n * P3 首期只实现 revolute / prismatic 两种单 DOF 运动副;cylindrical / planar /\n * spherical 在 buildJoint 里显式抛错(绝不静默降级成单 DOF),待 per-DOF ranges\n * 启用(JointSpec.dofs 已按此预留)。\n *\n * 链路:JointSpec[] → buildJoint(vendored 工厂)→ buildKinematicTree(建树三步\n * + 校验)→ solveKinematics(vendored forwardKinematics)→ per-member 位姿。\n *\n * cad.* 查询函数(jointTrajectory / inverseKinematics / mechanismDOF)是无副作用\n * 纯函数:输入纯数据、输出纯数据,不挂在 assembly receiver 上。\n *\n * 四元数顺序:faijs 对外 [x,y,z,w],brepjs [w,x,y,z]——只经 ./pose 的转换函数\n * 换序,禁止在本模块手写分量重排。\n */\n\nimport {\n revoluteJoint,\n prismaticJoint,\n forwardKinematics as brepjsForwardKinematics,\n mechanismDOF as brepjsMechanismDOF,\n jointTrajectory as brepjsJointTrajectory,\n inverseKinematics as brepjsInverseKinematics,\n addJoint,\n type Joint,\n type JointPose,\n type IKResult as BrepjsIKResult,\n type IKOptions as BrepjsIKOptions,\n type IKTarget as BrepjsIKTarget,\n} from './solvers/joints-kinematics'\nimport { createAssemblyNode, addChild, type AssemblyNode } from './solvers/assembly-tree'\nimport {\n fromBrepjsQuat,\n toBrepjsQuat,\n jointPoseToAssemblyTransform,\n isIdentityPose,\n type FaijsQuat,\n} from './pose'\nimport type { AssemblyTransform } from '../../runtime-state'\nimport type { AssemblyVec3 } from './types'\n\n// ── JointSpec(.fai.js 可序列化子集)──\n\n/** 运动副类型:P3 首期只实现 revolute / prismatic。 */\nexport type JointType = 'revolute' | 'prismatic' | 'cylindrical' | 'planar' | 'spherical'\n\n/** 单 DOF 范围(主 DOF 镜像字段 min/max/value)。 */\nexport interface JointDofSpec {\n min: number\n max: number\n value: number\n}\n\n/**\n * 可序列化运动副声明(.fai.js 对象字面量)。派生字段(dofs)由 buildJoint 内\n * vendored 工厂构造——脚本里只写纯数据。\n */\nexport interface JointSpec {\n type: JointType\n /**\n * 参考体(不动);child 相对它运动。必须是 members 里的**变量名**(字符串——\n * `.fai.js` 可序列化子集;members 也是字符串名数组)。buildKinematicTree\n * 校验二者 ∈ members。\n */\n parent: string\n /** 从动体(同样是 members 里的变量名)。 */\n child: string\n /** 主轴:origin 是所有旋转 DOF 的枢轴锚点。 */\n axis: { origin: AssemblyVec3; direction: AssemblyVec3 }\n /** 主 DOF 范围与当前值(revolute 单位 deg / prismatic 单位 mm;由 type 决定)。 */\n min: number\n max: number\n value: number\n /**\n * 多 DOF 运动副(cylindrical 2 / planar 3 / spherical 3)的逐 DOF 范围,\n * **长度必须与 type 的 DOF 数一致,顺序 = brepjs `Joint.dofs` 的组合顺序**:\n * cylindrical → [rotation, translation]\n * planar → [u, v, rotation]\n * spherical → [x, y, z]\n * P3 首期只实现 revolute/prismatic,此字段随多 DOF 类型一起启用。\n */\n dofs?: JointDofSpec[]\n /** planar 专用:面内 u 参考方向(brepjs 会投影到平面并归一化)。 */\n uDirection?: AssemblyVec3\n /** 静态连杆偏置(childWorld = parentWorld ∘ jointTransform ∘ offset),可选。 */\n offset?: { position?: AssemblyVec3; rotation?: FaijsQuat }\n}\n\n// ── buildJoint:JointSpec → brepjs Joint ──\n\n/**\n * 由 JointSpec 构造 brepjs Joint。\n *\n * revolute/prismatic 走 vendored 工厂(主 DOF 的 value 在工厂内 clamp 到\n * [min,max]);cylindrical/planar/spherical 显式抛错(多 DOF 未启用,绝不\n * 静默降级)。offset 的四元数经 toBrepjsQuat 换序(faijs [x,y,z,w] → brepjs\n * [w,x,y,z])。\n *\n * @param spec - the serializable joint declaration.\n * @returns the vendored brepjs Joint (with offset attached when declared).\n * @throws Error on multi-DOF joint types and unknown joint types.\n */\nexport function buildJoint(spec: JointSpec): Joint {\n const axis = { origin: spec.axis.origin, direction: spec.axis.direction }\n const options = { min: spec.min, max: spec.max, value: spec.value }\n let joint: Joint\n switch (spec.type) {\n case 'revolute':\n joint = revoluteJoint(String(spec.parent), String(spec.child), axis, options)\n break\n case 'prismatic':\n joint = prismaticJoint(String(spec.parent), String(spec.child), axis, options)\n break\n case 'cylindrical':\n case 'planar':\n case 'spherical':\n throw new Error(`[assembly] joint type '${spec.type}' is not supported yet; per-DOF ranges pending`)\n default: {\n const exhaustive: never = spec.type\n throw new Error(`[assembly] unknown joint type '${String(exhaustive)}'`)\n }\n }\n if (spec.offset) {\n const rotation = spec.offset.rotation\n ? ([...toBrepjsQuat(spec.offset.rotation)] as [number, number, number, number])\n : ([1, 0, 0, 0] as [number, number, number, number])\n joint = {\n ...joint,\n offset: {\n position: spec.offset.position ?? ([0, 0, 0] as [number, number, number]),\n rotation,\n },\n }\n }\n return joint\n}\n\n// ── buildKinematicTree:建树三步 + 校验 ──\n\n/**\n * 由成员名 + JointSpec[] 构建 kinematic AssemblyNode 树(vendored\n * forwardKinematics 只接受单个根;多成员必须有唯一合成根)。\n *\n * 校验(求解前,绝不静默):\n * - 成员名空串 → 抛错(与约束求解 R7 同源);\n * - parent/child 必须在 members 里 → 抛错并附成员名全集;\n * - 同一 child 不得被两个 joint 驱动(brepjs forwardKinematics 对重复 child\n * 静默跳过——faijs 侧必须在求解前显式失败)。\n *\n * 建树三步:\n * ① 合成根 '__asm_root'(不带 shape);② 全部成员挂成子节点(未被 joint 驱动\n * 的成员靠这一步拿到 identity 位姿;addChild 返回新节点必须重新赋值);③ 每个\n * joint 经 addJoint 挂到树上(FK 用 walkAssembly 收集 node.joints,位姿按\n * joint.parent/child 的名字图传播,与树边无关)。\n *\n * @param memberNames - member variable names (the tree covers every member).\n * @param joints - raw joint declarations.\n * @returns the assembled kinematic tree root.\n * @throws Error on empty member names, unknown joint parts, or duplicate child drive.\n */\nexport function buildKinematicTree(memberNames: string[], joints: JointSpec[]): AssemblyNode {\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 name in joints`,\n )\n }\n })\n const memberSet = new Set(memberNames)\n const driven = new Set<string>()\n for (const j of joints) {\n if (!memberSet.has(String(j.parent))) {\n throw new Error(\n `[assembly] joint parent '${String(j.parent)}' is not a member — members: ${memberNames.join(', ')}`,\n )\n }\n if (!memberSet.has(String(j.child))) {\n throw new Error(\n `[assembly] joint child '${String(j.child)}' is not a member — members: ${memberNames.join(', ')}`,\n )\n }\n if (driven.has(String(j.child))) {\n throw new Error(\n `[assembly] joint child '${String(j.child)}' is driven by more than one joint — each child must be driven by exactly one joint`,\n )\n }\n driven.add(String(j.child))\n }\n // 建树三步(见函数头注释)\n let root = createAssemblyNode('__asm_root')\n for (const m of memberNames) root = addChild(root, createAssemblyNode(m))\n for (const j of joints) root = addJoint(root, buildJoint(j))\n return root\n}\n\n// ── solveKinematics:正解 ──\n\n/** per-member 运动学位姿(rotation 为 faijs [x,y,z,w])。 */\nexport interface KinematicsPose {\n position: AssemblyVec3\n rotation: FaijsQuat\n}\n\n/** 运动学解算结果:装配变换(被驱动成员)+ 全成员位姿表。 */\nexport interface KinematicsSolveResult {\n /** 被 joints 定位(非恒等)的成员装配变换;index = 成员下标。 */\n transforms: AssemblyTransform[]\n /** 全部成员的终态位姿(含恒等,链根也在此);键 = 成员名。 */\n kinematics: Record<string, KinematicsPose>\n}\n\n/** 从 joints 推导查询场景的成员名全集(parent ∪ child,保序去重)。 */\nfunction specMemberNames(joints: JointSpec[]): string[] {\n const names: string[] = []\n const seen = new Set<string>()\n for (const j of joints) {\n for (const n of [String(j.parent), String(j.child)]) {\n if (!seen.has(n)) {\n seen.add(n)\n names.push(n)\n }\n }\n }\n return names\n}\n\n/**\n * 运动学正解:buildKinematicTree → vendored forwardKinematics → per-member 位姿。\n *\n * 校验(求解前):成员名空串 / parent-child ∈ members / child 唯一驱动(都收在\n * buildKinematicTree 内);drive 键必须 ∈ joints 的 child 集(多余键是笔误,\n * 显式失败而非静默忽略)。\n *\n * forwards 返回的 Map 含合成根 '__asm_root'——本函数按 memberNames 过滤掉,\n * 只输出成员位姿。transforms 只含非恒等(被驱动)成员,恒等成员不输出(引擎\n * 不做无谓重算,与约束求解语义一致);kinematics 则覆盖全部成员(含恒等),\n * 供宿主动画/导出读取完整骨架。\n *\n * @param memberNames - member variable names.\n * @param joints - raw joint declarations.\n * @param drive - per-child DOF value overrides (number for the primary DOF, or\n * a per-DOF array); keyed by child member name.\n * @returns the per-member kinematics result.\n * @throws Error on empty member names, unknown joint parts, duplicate child drive,\n * or a drive key that is not a joint child.\n */\nexport function solveKinematics(\n memberNames: string[],\n joints: JointSpec[],\n drive?: Record<string, number | number[]>,\n): KinematicsSolveResult {\n if (drive) {\n const jointChildren = new Set(joints.map((j) => String(j.child)))\n for (const key of Object.keys(drive)) {\n if (!jointChildren.has(key)) {\n throw new Error(\n `[assembly] drive key '${key}' does not name a joint child — joint children: ${[...jointChildren].join(', ')}`,\n )\n }\n }\n }\n const tree = buildKinematicTree(memberNames, joints)\n const poses = brepjsForwardKinematics(tree, drive)\n const transforms: AssemblyTransform[] = []\n const kinematics: Record<string, KinematicsPose> = {}\n memberNames.forEach((name, index) => {\n const pose = poses.get(name)\n if (!pose) return\n const rotation = fromBrepjsQuat(pose.rotation)\n kinematics[name] = {\n position: [pose.position[0], pose.position[1], pose.position[2]],\n rotation,\n }\n if (!isIdentityPose(pose)) transforms.push(jointPoseToAssemblyTransform(pose, index))\n })\n return { transforms, kinematics }\n}\n\n// ── cad.* 查询函数(纯函数,无副作用;输入输出都是纯数据)──\n\n/** `cad.jointTrajectory({ joints, from, to, steps })` 参数。 */\nexport interface JointTrajectoryParams {\n joints: JointSpec[]\n from: Record<string, number | number[]>\n to: Record<string, number | number[]>\n steps: number\n}\n\n/** 轨迹采样(poses 的 rotation 已换序为 faijs [x,y,z,w])。 */\nexport interface FaijsTrajectorySample {\n /** 归一化路径参数 ∈ [0,1]。 */\n t: number\n /** 该步的逐 DOF 值(键 = child 成员名)。 */\n values: Record<string, number[]>\n /** 该步全成员世界位姿。 */\n poses: Map<string, KinematicsPose>\n}\n\n/**\n * `cad.jointTrajectory({ joints, from, to, steps })` — 关节空间直线路径采样。\n * 产出 steps+1 个采样(含两端点);joints 缺省值在两端取存储值。\n * 无 endEffector 参数(关节空间插值,不追踪端点)。\n *\n * @param p - trajectory query parameters.\n * @returns the sampled trajectory (poses with faijs-order quaternions).\n */\nexport function jointTrajectory(p: JointTrajectoryParams): FaijsTrajectorySample[] {\n const memberNames = specMemberNames(p.joints)\n const tree = buildKinematicTree(memberNames, p.joints)\n return brepjsJointTrajectory(tree, p.from, p.to, p.steps).map((s) => ({\n t: s.t,\n values: s.values,\n poses: new Map(\n [...s.poses.entries()].map(([name, pose]) => [\n name,\n {\n position: [pose.position[0], pose.position[1], pose.position[2]],\n rotation: fromBrepjsQuat(pose.rotation),\n },\n ]),\n ),\n }))\n}\n\n/** `cad.inverseKinematics({ joints, endEffector, target, options? })` 参数。 */\nexport interface InverseKinematicsParams {\n joints: JointSpec[]\n /** 末端执行器 = child 成员名。 */\n endEffector: string\n /** 目标位姿(rotation 对外 faijs [x,y,z,w],内部 toBrepjsQuat 换序)。 */\n target: { position: AssemblyVec3; rotation?: FaijsQuat }\n options?: BrepjsIKOptions\n}\n\n/** IK 结果(与 vendored IKResult 同构;values 键 = child 成员名)。 */\nexport interface IKResult {\n values: Record<string, number[]>\n converged: boolean\n iterations: number\n error: number\n}\n\n/**\n * `cad.inverseKinematics({ joints, endEffector, target, options? })` —\n * damped-least-squares IK:求使末端到达 target 的关节值。关节范围在每个迭代\n * clamp;不可达目标返回 converged:false 与最优配置。纯函数,无副作用。\n *\n * @param p - IK query parameters.\n * @returns the solved joint values plus convergence diagnostics.\n */\nexport function inverseKinematics(p: InverseKinematicsParams): IKResult {\n const memberNames = specMemberNames(p.joints)\n const tree = buildKinematicTree(memberNames, p.joints)\n const target: BrepjsIKTarget = {\n position: p.target.position,\n ...(p.target.rotation ? { rotation: toBrepjsQuat(p.target.rotation) } : {}),\n }\n const result: BrepjsIKResult = brepjsInverseKinematics(tree, p.endEffector, target, p.options)\n return {\n values: result.values,\n converged: result.converged,\n iterations: result.iterations,\n error: result.error,\n }\n}\n\n/** `cad.mechanismDOF({ joints })` 参数。 */\nexport interface MechanismDOFParams {\n joints: JointSpec[]\n}\n\n/**\n * `cad.mechanismDOF({ joints })` — 开链机构自由度 = 各 joint DOF 数之和\n * (revolute/prismatic 各 1;串联两 revolute = 2)。纯函数,无副作用。\n *\n * @param p - DOF query parameters.\n * @returns the mechanism's total degree of freedom.\n */\nexport function mechanismDOF(p: MechanismDOFParams): number {\n const memberNames = specMemberNames(p.joints)\n const tree = buildKinematicTree(memberNames, p.joints)\n return brepjsMechanismDOF(tree)\n}\n\n// re-export:查询函数对外的类型面(IKOptions 透传给宿主)。\nexport type { JointPose, BrepjsIKOptions as IKOptions }"]}
1
+ {"version":3,"file":"joints.js","sourceRoot":"","sources":["../../../src/api/assembly/joints.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api/assembly/joints — 运动副声明与运动学解算(P3)\n *\n * JointSpec 是 .fai.js 可序列化子集(派生字段 dofs 由 brepjs 工厂构造,\n * 与 brepjs Joint.dofs 的组合顺序对齐:cylindrical → [rotation, translation]、\n * planar → [u, v, rotation]、spherical → [x, y, z])。\n *\n * P3 首期只实现 revolute / prismatic 两种单 DOF 运动副;cylindrical / planar /\n * spherical 在 buildJoint 里显式抛错(绝不静默降级成单 DOF),待 per-DOF ranges\n * 启用(JointSpec.dofs 已按此预留)。\n *\n * 链路:JointSpec[] → buildJoint(brepjs 工厂)→ buildKinematicTree(建树三步\n * + 校验)→ solveKinematics(brepjs forwardKinematics)→ per-member 位姿。\n *\n * cad.* 查询函数(jointTrajectory / inverseKinematics / mechanismDOF)是无副作用\n * 纯函数:输入纯数据、输出纯数据,不挂在 assembly receiver 上。\n *\n * 四元数顺序:faijs 对外 [x,y,z,w],brepjs [w,x,y,z]——只经 ./pose 的转换函数\n * 换序,禁止在本模块手写分量重排。\n */\n\nimport {\n revoluteJoint,\n prismaticJoint,\n forwardKinematics as brepjsForwardKinematics,\n mechanismDOF as brepjsMechanismDOF,\n jointTrajectory as brepjsJointTrajectory,\n inverseKinematics as brepjsInverseKinematics,\n addJoint,\n type Joint,\n type JointPose,\n type IKResult as BrepjsIKResult,\n type IKOptions as BrepjsIKOptions,\n type IKTarget as BrepjsIKTarget,\n} from './solvers/joints-kinematics'\nimport { createAssemblyNode, addChild, type AssemblyNode } from './solvers/assembly-tree'\nimport {\n fromBrepjsQuat,\n toBrepjsQuat,\n jointPoseToAssemblyTransform,\n isIdentityPose,\n type FaijsQuat,\n} from './pose'\nimport type { AssemblyTransform } from '../../runtime-state'\nimport type { AssemblyVec3 } from './types'\n\n// ── JointSpec(.fai.js 可序列化子集)──\n\n/** 运动副类型:P3 首期只实现 revolute / prismatic。 */\nexport type JointType = 'revolute' | 'prismatic' | 'cylindrical' | 'planar' | 'spherical'\n\n/** 单 DOF 范围(主 DOF 镜像字段 min/max/value)。 */\nexport interface JointDofSpec {\n min: number\n max: number\n value: number\n}\n\n/**\n * 可序列化运动副声明(.fai.js 对象字面量)。派生字段(dofs)由 buildJoint 内\n * brepjs 工厂构造——脚本里只写纯数据。\n */\nexport interface JointSpec {\n type: JointType\n /**\n * 参考体(不动);child 相对它运动。必须是 members 里的**变量名**(字符串——\n * `.fai.js` 可序列化子集;members 也是字符串名数组)。buildKinematicTree\n * 校验二者 ∈ members。\n */\n parent: string\n /** 从动体(同样是 members 里的变量名)。 */\n child: string\n /** 主轴:origin 是所有旋转 DOF 的枢轴锚点。 */\n axis: { origin: AssemblyVec3; direction: AssemblyVec3 }\n /** 主 DOF 范围与当前值(revolute 单位 deg / prismatic 单位 mm;由 type 决定)。 */\n min: number\n max: number\n value: number\n /**\n * 多 DOF 运动副(cylindrical 2 / planar 3 / spherical 3)的逐 DOF 范围,\n * **长度必须与 type 的 DOF 数一致,顺序 = brepjs `Joint.dofs` 的组合顺序**:\n * cylindrical → [rotation, translation]\n * planar → [u, v, rotation]\n * spherical → [x, y, z]\n * P3 首期只实现 revolute/prismatic,此字段随多 DOF 类型一起启用。\n */\n dofs?: JointDofSpec[]\n /** planar 专用:面内 u 参考方向(brepjs 会投影到平面并归一化)。 */\n uDirection?: AssemblyVec3\n /** 静态连杆偏置(childWorld = parentWorld ∘ jointTransform ∘ offset),可选。 */\n offset?: { position?: AssemblyVec3; rotation?: FaijsQuat }\n}\n\n// ── buildJoint:JointSpec → brepjs Joint ──\n\n/**\n * 由 JointSpec 构造 brepjs Joint。\n *\n * revolute/prismatic 走 brepjs 工厂(主 DOF 的 value 在工厂内 clamp 到\n * [min,max]);cylindrical/planar/spherical 显式抛错(多 DOF 未启用,绝不\n * 静默降级)。offset 的四元数经 toBrepjsQuat 换序(faijs [x,y,z,w] → brepjs\n * [w,x,y,z])。\n *\n * @param spec - the serializable joint declaration.\n * @returns the Joint (with offset attached when declared).\n * @throws Error on multi-DOF joint types and unknown joint types.\n */\nexport function buildJoint(spec: JointSpec): Joint {\n const axis = { origin: spec.axis.origin, direction: spec.axis.direction }\n const options = { min: spec.min, max: spec.max, value: spec.value }\n let joint: Joint\n switch (spec.type) {\n case 'revolute':\n joint = revoluteJoint(String(spec.parent), String(spec.child), axis, options)\n break\n case 'prismatic':\n joint = prismaticJoint(String(spec.parent), String(spec.child), axis, options)\n break\n case 'cylindrical':\n case 'planar':\n case 'spherical':\n throw new Error(`[assembly] joint type '${spec.type}' is not supported yet; per-DOF ranges pending`)\n default: {\n const exhaustive: never = spec.type\n throw new Error(`[assembly] unknown joint type '${String(exhaustive)}'`)\n }\n }\n if (spec.offset) {\n const rotation = spec.offset.rotation\n ? ([...toBrepjsQuat(spec.offset.rotation)] as [number, number, number, number])\n : ([1, 0, 0, 0] as [number, number, number, number])\n joint = {\n ...joint,\n offset: {\n position: spec.offset.position ?? ([0, 0, 0] as [number, number, number]),\n rotation,\n },\n }\n }\n return joint\n}\n\n// ── buildKinematicTree:建树三步 + 校验 ──\n\n/**\n * 由成员名 + JointSpec[] 构建 kinematic AssemblyNode 树(brepjs\n * forwardKinematics 只接受单个根;多成员必须有唯一合成根)。\n *\n * 校验(求解前,绝不静默):\n * - 成员名空串 → 抛错(与约束求解 R7 同源);\n * - parent/child 必须在 members 里 → 抛错并附成员名全集;\n * - 同一 child 不得被两个 joint 驱动(brepjs forwardKinematics 对重复 child\n * 静默跳过——faijs 侧必须在求解前显式失败)。\n *\n * 建树三步:\n * ① 合成根 '__asm_root'(不带 shape);② 全部成员挂成子节点(未被 joint 驱动\n * 的成员靠这一步拿到 identity 位姿;addChild 返回新节点必须重新赋值);③ 每个\n * joint 经 addJoint 挂到树上(FK 用 walkAssembly 收集 node.joints,位姿按\n * joint.parent/child 的名字图传播,与树边无关)。\n *\n * @param memberNames - member variable names (the tree covers every member).\n * @param joints - raw joint declarations.\n * @returns the assembled kinematic tree root.\n * @throws Error on empty member names, unknown joint parts, or duplicate child drive.\n */\nexport function buildKinematicTree(memberNames: string[], joints: JointSpec[]): AssemblyNode {\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 name in joints`,\n )\n }\n })\n const memberSet = new Set(memberNames)\n const driven = new Set<string>()\n for (const j of joints) {\n if (!memberSet.has(String(j.parent))) {\n throw new Error(\n `[assembly] joint parent '${String(j.parent)}' is not a member — members: ${memberNames.join(', ')}`,\n )\n }\n if (!memberSet.has(String(j.child))) {\n throw new Error(\n `[assembly] joint child '${String(j.child)}' is not a member — members: ${memberNames.join(', ')}`,\n )\n }\n if (driven.has(String(j.child))) {\n throw new Error(\n `[assembly] joint child '${String(j.child)}' is driven by more than one joint — each child must be driven by exactly one joint`,\n )\n }\n driven.add(String(j.child))\n }\n // 建树三步(见函数头注释)\n let root = createAssemblyNode('__asm_root')\n for (const m of memberNames) root = addChild(root, createAssemblyNode(m))\n for (const j of joints) root = addJoint(root, buildJoint(j))\n return root\n}\n\n// ── solveKinematics:正解 ──\n\n/** per-member 运动学位姿(rotation 为 faijs [x,y,z,w])。 */\nexport interface KinematicsPose {\n position: AssemblyVec3\n rotation: FaijsQuat\n}\n\n/** 运动学解算结果:装配变换(被驱动成员)+ 全成员位姿表。 */\nexport interface KinematicsSolveResult {\n /** 被 joints 定位(非恒等)的成员装配变换;index = 成员下标。 */\n transforms: AssemblyTransform[]\n /** 全部成员的终态位姿(含恒等,链根也在此);键 = 成员名。 */\n kinematics: Record<string, KinematicsPose>\n}\n\n/** 从 joints 推导查询场景的成员名全集(parent ∪ child,保序去重)。 */\nfunction specMemberNames(joints: JointSpec[]): string[] {\n const names: string[] = []\n const seen = new Set<string>()\n for (const j of joints) {\n for (const n of [String(j.parent), String(j.child)]) {\n if (!seen.has(n)) {\n seen.add(n)\n names.push(n)\n }\n }\n }\n return names\n}\n\n/**\n * 运动学正解:buildKinematicTree → brepjs forwardKinematics → per-member 位姿。\n *\n * 校验(求解前):成员名空串 / parent-child ∈ members / child 唯一驱动(都收在\n * buildKinematicTree 内);drive 键必须 ∈ joints 的 child 集(多余键是笔误,\n * 显式失败而非静默忽略)。\n *\n * forwards 返回的 Map 含合成根 '__asm_root'——本函数按 memberNames 过滤掉,\n * 只输出成员位姿。transforms 只含非恒等(被驱动)成员,恒等成员不输出(引擎\n * 不做无谓重算,与约束求解语义一致);kinematics 则覆盖全部成员(含恒等),\n * 供宿主动画/导出读取完整骨架。\n *\n * @param memberNames - member variable names.\n * @param joints - raw joint declarations.\n * @param drive - per-child DOF value overrides (number for the primary DOF, or\n * a per-DOF array); keyed by child member name.\n * @returns the per-member kinematics result.\n * @throws Error on empty member names, unknown joint parts, duplicate child drive,\n * or a drive key that is not a joint child.\n */\nexport function solveKinematics(\n memberNames: string[],\n joints: JointSpec[],\n drive?: Record<string, number | number[]>,\n): KinematicsSolveResult {\n if (drive) {\n const jointChildren = new Set(joints.map((j) => String(j.child)))\n for (const key of Object.keys(drive)) {\n if (!jointChildren.has(key)) {\n throw new Error(\n `[assembly] drive key '${key}' does not name a joint child — joint children: ${[...jointChildren].join(', ')}`,\n )\n }\n }\n }\n const tree = buildKinematicTree(memberNames, joints)\n const poses = brepjsForwardKinematics(tree, drive)\n const transforms: AssemblyTransform[] = []\n const kinematics: Record<string, KinematicsPose> = {}\n memberNames.forEach((name, index) => {\n const pose = poses.get(name)\n if (!pose) return\n const rotation = fromBrepjsQuat(pose.rotation)\n kinematics[name] = {\n position: [pose.position[0], pose.position[1], pose.position[2]],\n rotation,\n }\n if (!isIdentityPose(pose)) transforms.push(jointPoseToAssemblyTransform(pose, index))\n })\n return { transforms, kinematics }\n}\n\n// ── cad.* 查询函数(纯函数,无副作用;输入输出都是纯数据)──\n\n/** `cad.jointTrajectory({ joints, from, to, steps })` 参数。 */\nexport interface JointTrajectoryParams {\n joints: JointSpec[]\n from: Record<string, number | number[]>\n to: Record<string, number | number[]>\n steps: number\n}\n\n/** 轨迹采样(poses 的 rotation 已换序为 faijs [x,y,z,w])。 */\nexport interface FaijsTrajectorySample {\n /** 归一化路径参数 ∈ [0,1]。 */\n t: number\n /** 该步的逐 DOF 值(键 = child 成员名)。 */\n values: Record<string, number[]>\n /** 该步全成员世界位姿。 */\n poses: Map<string, KinematicsPose>\n}\n\n/**\n * `cad.jointTrajectory({ joints, from, to, steps })` — 关节空间直线路径采样。\n * 产出 steps+1 个采样(含两端点);joints 缺省值在两端取存储值。\n * 无 endEffector 参数(关节空间插值,不追踪端点)。\n *\n * @group 查询\n * @inputs 0\n * @async false\n * @qual ok\n * @name jointTrajectory\n * @note 纯函数:输入输出都是纯数据,不产 Shape、不依赖引擎;装配面契约见 `docs/api-contract.md` §12。\n * @returns FaijsTrajectorySample[] 采样序列(steps+1 个,含两端点)。\n * @param p - 轨迹查询参数。type:JointTrajectoryParams required:true\n */\nexport function jointTrajectory(p: JointTrajectoryParams): FaijsTrajectorySample[] {\n const memberNames = specMemberNames(p.joints)\n const tree = buildKinematicTree(memberNames, p.joints)\n return brepjsJointTrajectory(tree, p.from, p.to, p.steps).map((s) => ({\n t: s.t,\n values: s.values,\n poses: new Map(\n [...s.poses.entries()].map(([name, pose]) => [\n name,\n {\n position: [pose.position[0], pose.position[1], pose.position[2]],\n rotation: fromBrepjsQuat(pose.rotation),\n },\n ]),\n ),\n }))\n}\n\n/** `cad.inverseKinematics({ joints, endEffector, target, options? })` 参数。 */\nexport interface InverseKinematicsParams {\n joints: JointSpec[]\n /** 末端执行器 = child 成员名。 */\n endEffector: string\n /** 目标位姿(rotation 对外 faijs [x,y,z,w],内部 toBrepjsQuat 换序)。 */\n target: { position: AssemblyVec3; rotation?: FaijsQuat }\n options?: BrepjsIKOptions\n}\n\n/** IK 结果(与 brepjs IKResult 同构;values 键 = child 成员名)。 */\nexport interface IKResult {\n values: Record<string, number[]>\n converged: boolean\n iterations: number\n error: number\n}\n\n/**\n * `cad.inverseKinematics({ joints, endEffector, target, options? })` —\n * damped-least-squares IK:求使末端到达 target 的关节值。关节范围在每个迭代\n * clamp;不可达目标返回 converged:false 与最优配置。纯函数,无副作用。\n *\n * @group 查询\n * @inputs 0\n * @async false\n * @qual ok\n * @name inverseKinematics\n * @note 纯函数:输入输出都是纯数据,不产 Shape、不依赖引擎;装配面契约见 `docs/api-contract.md` §12。\n * @returns IKResult 关节值 + 收敛诊断(converged / iterations / error)。\n * @param p - IK 查询参数。type:InverseKinematicsParams required:true\n */\nexport function inverseKinematics(p: InverseKinematicsParams): IKResult {\n const memberNames = specMemberNames(p.joints)\n const tree = buildKinematicTree(memberNames, p.joints)\n const target: BrepjsIKTarget = {\n position: p.target.position,\n ...(p.target.rotation ? { rotation: toBrepjsQuat(p.target.rotation) } : {}),\n }\n const result: BrepjsIKResult = brepjsInverseKinematics(tree, p.endEffector, target, p.options)\n return {\n values: result.values,\n converged: result.converged,\n iterations: result.iterations,\n error: result.error,\n }\n}\n\n/** `cad.mechanismDOF({ joints })` 参数。 */\nexport interface MechanismDOFParams {\n joints: JointSpec[]\n}\n\n/**\n * `cad.mechanismDOF({ joints })` — 开链机构自由度 = 各 joint DOF 数之和\n * (revolute/prismatic 各 1;串联两 revolute = 2)。纯函数,无副作用。\n *\n * @group 查询\n * @inputs 0\n * @async false\n * @qual ok\n * @name mechanismDOF\n * @note 纯函数:输入输出都是纯数据,不产 Shape、不依赖引擎;装配面契约见 `docs/api-contract.md` §12。\n * @returns number 机构总自由度。\n * @param p - 自由度查询参数。type:MechanismDOFParams required:true\n */\nexport function mechanismDOF(p: MechanismDOFParams): number {\n const memberNames = specMemberNames(p.joints)\n const tree = buildKinematicTree(memberNames, p.joints)\n return brepjsMechanismDOF(tree)\n}\n\n// re-export:查询函数对外的类型面(IKOptions 透传给宿主)。\nexport type { JointPose, BrepjsIKOptions as IKOptions }"]}
@@ -4,7 +4,7 @@
4
4
  * 动机:3d_editor 预览需要**与执行同源**的轻量入口(P2-f5 已删除旧预览专用数学);
5
5
  *
6
6
  * 同源性保证:内部复用 lowerEntities(与 lowerStructuralConstraint 同编码规则)
7
- * 与 vendored brepjs solveConstraints——不另写数学。
7
+ * 与 chain-solver solveConstraints——不另写数学。
8
8
  *
9
9
  * **输入约定**:一律是"未编码"的实体(SolverEntity,纯数据)——
10
10
  * 面 → {type:'plane', origin:center, normal},圆柱/圆锥面与边 →
@@ -4,7 +4,7 @@
4
4
  * 动机:3d_editor 预览需要**与执行同源**的轻量入口(P2-f5 已删除旧预览专用数学);
5
5
  *
6
6
  * 同源性保证:内部复用 lowerEntities(与 lowerStructuralConstraint 同编码规则)
7
- * 与 vendored brepjs solveConstraints——不另写数学。
7
+ * 与 chain-solver solveConstraints——不另写数学。
8
8
  *
9
9
  * **输入约定**:一律是"未编码"的实体(SolverEntity,纯数据)——
10
10
  * 面 → {type:'plane', origin:center, normal},圆柱/圆锥面与边 →
@@ -1 +1 @@
1
- {"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/api/assembly/preview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAA;AAOhD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAC1B,IAA2B,EAC3B,SAAuB,EACvB,SAAuB,EACvB,KAAc;IAEd,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,aAAa,CAC7C,IAAI,EACJ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,EACpC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,EACpC,KAAK,CACN,CAAA;IACD,MAAM,CAAC,GAAG,gBAAgB,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,UAA8B,CAAC,CAAC,CAAA;IAChF,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,gEAAgE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,aAAa,EAAE,CAC5G,CAAA;IACH,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;IAC7E,OAAO,uBAAuB,CAAC,IAAI,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AAClE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,CAG2C;IAE3C,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,OAAO;YACV,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;QAC9D,KAAK,MAAM;YACT,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAA;QACnE,KAAK,OAAO;YACV,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;IAC9C,CAAC;AACH,CAAC","sourcesContent":["/**\n * api/assembly/preview — 装配约束预览纯函数入口(P2-f3,方案 §2.3)\n *\n * 动机:3d_editor 预览需要**与执行同源**的轻量入口(P2-f5 已删除旧预览专用数学);\n *\n * 同源性保证:内部复用 lowerEntities(与 lowerStructuralConstraint 同编码规则)\n * 与 vendored brepjs solveConstraints——不另写数学。\n *\n * **输入约定**:一律是\"未编码\"的实体(SolverEntity,纯数据)——\n * 面 → {type:'plane', origin:center, normal},圆柱/圆锥面与边 →\n * {type:'axis', origin, direction},点 → {type:'point', origin};\n * `mate`/`align` 的 flip 由 solvePreview 内部负责(mate:dep 侧法向取反;\n * align:不取反),宿主不需要知道自己该不该 flip。\n *\n * 仅支持\"恰好定位一个 dependent\"的单条约束;`fixed`(无位移语义)与\n * `parallel`/`perpendicular`(请用 `angle` 0/90 显式表达)不支持,报错。\n */\n\nimport type { SolverConstraint, SolverEntity } from './solvers/types'\nimport type { AssemblyTransform } from '../../runtime-state'\nimport { solveConstraints } from './solvers/chain-solver'\nimport { lowerEntities } from './lower'\nimport { poseToAssemblyTransform } from './pose'\nimport type { AssemblyVec3 } from './types'\n\n/** 预览支持的约束类型(fixed 无位移语义 → 抛错;parallel/perpendicular → angle 糖)。 */\nexport type PreviewConstraintType =\n | 'mate' | 'align' | 'coincident' | 'concentric' | 'distance' | 'angle'\n\n/**\n * 单约束预览:给定两条实体的几何(SolverEntity,纯数据),\n * 走与 solveAssembly 完全相同的 lower → solveConstraints 链路,\n * 返回 dependent 侧成员的位姿(AssemblyTransform,index 固定 -1,\n * pivot = dep 实体 origin)。\n *\n * @param type - the constraint type.\n * @param refEntity - the reference-side solver entity.\n * @param depEntity - the dependent-side solver entity.\n * @param value - distance/angle 用(定距 mm / 夹角 deg)。\n * @returns the dependent-side AssemblyTransform (index = -1).\n * @throws Error on entity type mismatch / non-convergence / dep not positioned.\n */\nexport function solvePreview(\n type: PreviewConstraintType,\n refEntity: SolverEntity,\n depEntity: SolverEntity,\n value?: number,\n): AssemblyTransform {\n const { constraint, depOrigin } = lowerEntities(\n type,\n { node: '__ref', entity: refEntity },\n { node: '__dep', entity: depEntity },\n value,\n )\n const r = solveConstraints(['__ref', '__dep'], [constraint as SolverConstraint])\n if (!r.converged) {\n throw new Error(\n `[assembly:preview] constraint did not converge; unsupported: ${r.unsupported.join(', ') || '(no detail)'}`,\n )\n }\n const pose = r.transforms.get('__dep')\n if (!pose) throw new Error('[assembly:preview] dependent was not positioned')\n return poseToAssemblyTransform(pose, depOrigin ?? [0, 0, 0], -1)\n}\n\n/**\n * 宿主拾取数据 → SolverEntity(预览时几何就在手上,不经过 TopoRef 解析)。\n *\n * @param g - 宿主拾取的几何数据(plane/axis/point,带 kind 判别)。\n * @returns 可供求解器消解的 SolverEntity(plane/axis/point)。\n */\nexport function entityFromGeometry(\n g:\n | { kind: 'plane'; center: AssemblyVec3; normal: AssemblyVec3 }\n | { kind: 'axis'; origin: AssemblyVec3; direction: AssemblyVec3 }\n | { kind: 'point'; origin: AssemblyVec3 },\n): SolverEntity {\n switch (g.kind) {\n case 'plane':\n return { type: 'plane', origin: g.center, normal: g.normal }\n case 'axis':\n return { type: 'axis', origin: g.origin, direction: g.direction }\n case 'point':\n return { type: 'point', origin: g.origin }\n }\n}"]}
1
+ {"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/api/assembly/preview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAA;AAOhD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAC1B,IAA2B,EAC3B,SAAuB,EACvB,SAAuB,EACvB,KAAc;IAEd,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,aAAa,CAC7C,IAAI,EACJ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,EACpC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,EACpC,KAAK,CACN,CAAA;IACD,MAAM,CAAC,GAAG,gBAAgB,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,UAA8B,CAAC,CAAC,CAAA;IAChF,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,gEAAgE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,aAAa,EAAE,CAC5G,CAAA;IACH,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACtC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;IAC7E,OAAO,uBAAuB,CAAC,IAAI,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AAClE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,CAG2C;IAE3C,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,OAAO;YACV,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;QAC9D,KAAK,MAAM;YACT,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAA;QACnE,KAAK,OAAO;YACV,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;IAC9C,CAAC;AACH,CAAC","sourcesContent":["/**\n * api/assembly/preview — 装配约束预览纯函数入口(P2-f3,方案 §2.3)\n *\n * 动机:3d_editor 预览需要**与执行同源**的轻量入口(P2-f5 已删除旧预览专用数学);\n *\n * 同源性保证:内部复用 lowerEntities(与 lowerStructuralConstraint 同编码规则)\n * 与 chain-solver solveConstraints——不另写数学。\n *\n * **输入约定**:一律是\"未编码\"的实体(SolverEntity,纯数据)——\n * 面 → {type:'plane', origin:center, normal},圆柱/圆锥面与边 →\n * {type:'axis', origin, direction},点 → {type:'point', origin};\n * `mate`/`align` 的 flip 由 solvePreview 内部负责(mate:dep 侧法向取反;\n * align:不取反),宿主不需要知道自己该不该 flip。\n *\n * 仅支持\"恰好定位一个 dependent\"的单条约束;`fixed`(无位移语义)与\n * `parallel`/`perpendicular`(请用 `angle` 0/90 显式表达)不支持,报错。\n */\n\nimport type { SolverConstraint, SolverEntity } from './solvers/types'\nimport type { AssemblyTransform } from '../../runtime-state'\nimport { solveConstraints } from './solvers/chain-solver'\nimport { lowerEntities } from './lower'\nimport { poseToAssemblyTransform } from './pose'\nimport type { AssemblyVec3 } from './types'\n\n/** 预览支持的约束类型(fixed 无位移语义 → 抛错;parallel/perpendicular → angle 糖)。 */\nexport type PreviewConstraintType =\n | 'mate' | 'align' | 'coincident' | 'concentric' | 'distance' | 'angle'\n\n/**\n * 单约束预览:给定两条实体的几何(SolverEntity,纯数据),\n * 走与 solveAssembly 完全相同的 lower → solveConstraints 链路,\n * 返回 dependent 侧成员的位姿(AssemblyTransform,index 固定 -1,\n * pivot = dep 实体 origin)。\n *\n * @param type - the constraint type.\n * @param refEntity - the reference-side solver entity.\n * @param depEntity - the dependent-side solver entity.\n * @param value - distance/angle 用(定距 mm / 夹角 deg)。\n * @returns the dependent-side AssemblyTransform (index = -1).\n * @throws Error on entity type mismatch / non-convergence / dep not positioned.\n */\nexport function solvePreview(\n type: PreviewConstraintType,\n refEntity: SolverEntity,\n depEntity: SolverEntity,\n value?: number,\n): AssemblyTransform {\n const { constraint, depOrigin } = lowerEntities(\n type,\n { node: '__ref', entity: refEntity },\n { node: '__dep', entity: depEntity },\n value,\n )\n const r = solveConstraints(['__ref', '__dep'], [constraint as SolverConstraint])\n if (!r.converged) {\n throw new Error(\n `[assembly:preview] constraint did not converge; unsupported: ${r.unsupported.join(', ') || '(no detail)'}`,\n )\n }\n const pose = r.transforms.get('__dep')\n if (!pose) throw new Error('[assembly:preview] dependent was not positioned')\n return poseToAssemblyTransform(pose, depOrigin ?? [0, 0, 0], -1)\n}\n\n/**\n * 宿主拾取数据 → SolverEntity(预览时几何就在手上,不经过 TopoRef 解析)。\n *\n * @param g - 宿主拾取的几何数据(plane/axis/point,带 kind 判别)。\n * @returns 可供求解器消解的 SolverEntity(plane/axis/point)。\n */\nexport function entityFromGeometry(\n g:\n | { kind: 'plane'; center: AssemblyVec3; normal: AssemblyVec3 }\n | { kind: 'axis'; origin: AssemblyVec3; direction: AssemblyVec3 }\n | { kind: 'point'; origin: AssemblyVec3 },\n): SolverEntity {\n switch (g.kind) {\n case 'plane':\n return { type: 'plane', origin: g.center, normal: g.normal }\n case 'axis':\n return { type: 'axis', origin: g.origin, direction: g.direction }\n case 'point':\n return { type: 'point', origin: g.origin }\n }\n}"]}
@@ -2,7 +2,7 @@
2
2
  * api/assembly/solve — 装配求解入口(P1,方案 §4.2)
3
3
  *
4
4
  * 流程:规范化(normalize)→ 降级(lower)→ brepjs solveConstraints
5
- *(拓扑轮次调度 / DOF / converged 全部由 brepjs 提供,零 vendored 修改)→
5
+ *(拓扑轮次调度 / DOF / converged 全部由 brepjs 提供,零 brepjs 修改)→
6
6
  * per-member 终态 AssemblyTransform(修 L6:不再 per-constraint 增量叠加)。
7
7
  *
8
8
  * 不收敛 → 抛错(D3,错误信息带 unsupported 明细;对齐「绝不静默」约定)。
@@ -2,7 +2,7 @@
2
2
  * api/assembly/solve — 装配求解入口(P1,方案 §4.2)
3
3
  *
4
4
  * 流程:规范化(normalize)→ 降级(lower)→ brepjs solveConstraints
5
- *(拓扑轮次调度 / DOF / converged 全部由 brepjs 提供,零 vendored 修改)→
5
+ *(拓扑轮次调度 / DOF / converged 全部由 brepjs 提供,零 brepjs 修改)→
6
6
  * per-member 终态 AssemblyTransform(修 L6:不再 per-constraint 增量叠加)。
7
7
  *
8
8
  * 不收敛 → 抛错(D3,错误信息带 unsupported 明细;对齐「绝不静默」约定)。
@@ -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 提供,零 vendored 修改)→\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\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":"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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\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,5 +1,5 @@
1
1
  /**
2
- * Assembly tree — core 自有实现(§5.6 移植:vendored assemblyFns 逐字对齐,纯数据结构)。
2
+ * Assembly tree — core 自有实现(§5.6 移植:brepjs assemblyFns 逐字对齐,纯数据结构)。
3
3
  *
4
4
  * An assembly is a tree of nodes. Each node has an optional shape,
5
5
  * a local transform (translation + rotation), optional metadata,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Assembly tree — core 自有实现(§5.6 移植:vendored assemblyFns 逐字对齐,纯数据结构)。
2
+ * Assembly tree — core 自有实现(§5.6 移植:brepjs assemblyFns 逐字对齐,纯数据结构)。
3
3
  *
4
4
  * An assembly is a tree of nodes. Each node has an optional shape,
5
5
  * a local transform (translation + rotation), optional metadata,
@@ -1 +1 @@
1
- {"version":3,"file":"assembly-tree.js","sourceRoot":"","sources":["../../../../src/api/assembly/solvers/assembly-tree.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Assembly tree — core 自有实现(§5.6 移植:vendored assemblyFns 逐字对齐,纯数据结构)。\n *\n * An assembly is a tree of nodes. Each node has an optional shape,\n * a local transform (translation + rotation), optional metadata,\n * and child nodes. This is a pure data structure with no kernel calls.\n *\n * Usage:\n * const asm = createAssemblyNode('root')\n * |> addChild(_, createAssemblyNode('part-a', { shape: boxShape, translate: [10, 0, 0] }))\n * |> addChild(_, createAssemblyNode('part-b', { shape: cylShape }));\n */\n\nimport type { Shape } from '../../../mesh/types'\n\n/** 3D vector(core 本地别名,§5.6 移植)。 */\nexport type Vec3 = readonly [number, number, number];\n\n// ---------------------------------------------------------------------------\n// Assembly types\n// ---------------------------------------------------------------------------\n\n/**\n * A node in an assembly tree: optional shape, local transform, metadata, and children.\n */\nexport interface AssemblyNode {\n readonly name: string;\n readonly shape?: Shape;\n readonly translate?: Vec3;\n readonly rotate?: { angle: number; axis?: Vec3 };\n readonly metadata?: Readonly<Record<string, unknown>>;\n readonly children: ReadonlyArray<AssemblyNode>;\n readonly mates?: readonly unknown[];\n /** Drivable kinematic joints (see jointFns). Typed loosely to avoid a cycle. */\n readonly joints?: readonly unknown[];\n}\n\n/** Optional properties for creating or updating an assembly node. */\nexport interface AssemblyNodeOptions {\n shape?: Shape;\n translate?: Vec3;\n rotate?: { angle: number; axis?: Vec3 };\n metadata?: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\n/**\n * Create a new assembly node.\n * @param name - Name of the node.\n * @param options - Optional shape, transform, and metadata.\n * @returns The newly created assembly node.\n */\nexport function createAssemblyNode(name: string, options: AssemblyNodeOptions = {}): AssemblyNode {\n return {\n name,\n children: [],\n ...(options.shape !== undefined ? { shape: options.shape } : {}),\n ...(options.translate !== undefined ? { translate: options.translate } : {}),\n ...(options.rotate !== undefined ? { rotate: options.rotate } : {}),\n ...(options.metadata !== undefined ? { metadata: options.metadata } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Immutable tree operations\n// ---------------------------------------------------------------------------\n\n/**\n * Add a child node. Returns a new parent node.\n * @param parent - The parent node to extend.\n * @param child - The child node to append.\n * @returns A new parent node with the child added.\n */\nexport function addChild(parent: AssemblyNode, child: AssemblyNode): AssemblyNode {\n return { ...parent, children: [...parent.children, child] };\n}\n\n/**\n * Remove a child by name (first match). Returns a new parent node.\n * @param parent - The parent node to modify.\n * @param childName - Name of the child to remove.\n * @returns A new parent node with the child removed.\n */\nexport function removeChild(parent: AssemblyNode, childName: string): AssemblyNode {\n const idx = parent.children.findIndex((c) => c.name === childName);\n if (idx === -1) return parent;\n const children = [...parent.children];\n children.splice(idx, 1);\n return { ...parent, children };\n}\n\n/**\n * Update a node's properties. Returns a new node.\n * @param node - The node to update.\n * @param updates - Partial options to apply.\n * @returns A new node with the updates applied.\n */\nexport function updateNode(\n node: AssemblyNode,\n updates: Partial<AssemblyNodeOptions>\n): AssemblyNode {\n return {\n ...node,\n ...(updates.shape !== undefined ? { shape: updates.shape } : {}),\n ...(updates.translate !== undefined ? { translate: updates.translate } : {}),\n ...(updates.rotate !== undefined ? { rotate: updates.rotate } : {}),\n ...(updates.metadata !== undefined ? { metadata: updates.metadata } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Traversal\n// ---------------------------------------------------------------------------\n\n/**\n * Find a node by name (depth-first). Returns undefined if not found.\n * @param root - Root of the subtree to search.\n * @param name - Name of the node to find.\n * @returns The first matching node, or undefined.\n */\nexport function findNode(root: AssemblyNode, name: string): AssemblyNode | undefined {\n if (root.name === name) return root;\n for (const child of root.children) {\n const found = findNode(child, name);\n if (found) return found;\n }\n return undefined;\n}\n\n/**\n * Walk the tree depth-first, calling visitor for each node.\n * @param root - Root node to walk from.\n * @param visitor - Callback invoked with each node and its depth.\n * @param depth - Starting depth (used internally for recursion).\n * @returns Nothing.\n */\nexport function walkAssembly(\n root: AssemblyNode,\n visitor: (node: AssemblyNode, depth: number) => void,\n depth = 0\n): void {\n visitor(root, depth);\n for (const child of root.children) {\n walkAssembly(child, visitor, depth + 1);\n }\n}\n\n/**\n * Count all nodes in the tree.\n * @param root - Root node to count from.\n * @returns Total number of nodes including the root.\n */\nexport function countNodes(root: AssemblyNode): number {\n let count = 1;\n for (const child of root.children) {\n count += countNodes(child);\n }\n return count;\n}\n\n/**\n * Collect all shapes in the tree (depth-first).\n * @param root - Root node to collect from.\n * @returns All shapes found on nodes in the tree.\n */\nexport function collectShapes(root: AssemblyNode): Shape[] {\n const shapes: Shape[] = [];\n walkAssembly(root, (node) => {\n if (node.shape) shapes.push(node.shape);\n });\n return shapes;\n}\n"]}
1
+ {"version":3,"file":"assembly-tree.js","sourceRoot":"","sources":["../../../../src/api/assembly/solvers/assembly-tree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAkCH,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,UAA+B,EAAE;IAChF,OAAO;QACL,IAAI;QACJ,QAAQ,EAAE,EAAE;QACZ,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,4BAA4B;AAC5B,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAoB,EAAE,KAAmB;IAChE,OAAO,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAoB,EAAE,SAAiB;IACjE,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IACnE,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IAC9B,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACxB,OAAO,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CACxB,IAAkB,EAClB,OAAqC;IAErC,OAAO;QACL,GAAG,IAAI;QACP,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAkB,EAAE,IAAY;IACvD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACpC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAkB,EAClB,OAAoD,EACpD,KAAK,GAAG,CAAC;IAET,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClC,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAkB;IAC3C,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAkB;IAC9C,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;QAC1B,IAAI,IAAI,CAAC,KAAK;YAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["/**\n * Assembly tree — core 自有实现(§5.6 移植:brepjs assemblyFns 逐字对齐,纯数据结构)。\n *\n * An assembly is a tree of nodes. Each node has an optional shape,\n * a local transform (translation + rotation), optional metadata,\n * and child nodes. This is a pure data structure with no kernel calls.\n *\n * Usage:\n * const asm = createAssemblyNode('root')\n * |> addChild(_, createAssemblyNode('part-a', { shape: boxShape, translate: [10, 0, 0] }))\n * |> addChild(_, createAssemblyNode('part-b', { shape: cylShape }));\n */\n\nimport type { Shape } from '../../../mesh/types'\n\n/** 3D vector(core 本地别名,§5.6 移植)。 */\nexport type Vec3 = readonly [number, number, number];\n\n// ---------------------------------------------------------------------------\n// Assembly types\n// ---------------------------------------------------------------------------\n\n/**\n * A node in an assembly tree: optional shape, local transform, metadata, and children.\n */\nexport interface AssemblyNode {\n readonly name: string;\n readonly shape?: Shape;\n readonly translate?: Vec3;\n readonly rotate?: { angle: number; axis?: Vec3 };\n readonly metadata?: Readonly<Record<string, unknown>>;\n readonly children: ReadonlyArray<AssemblyNode>;\n readonly mates?: readonly unknown[];\n /** Drivable kinematic joints (see jointFns). Typed loosely to avoid a cycle. */\n readonly joints?: readonly unknown[];\n}\n\n/** Optional properties for creating or updating an assembly node. */\nexport interface AssemblyNodeOptions {\n shape?: Shape;\n translate?: Vec3;\n rotate?: { angle: number; axis?: Vec3 };\n metadata?: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\n/**\n * Create a new assembly node.\n * @param name - Name of the node.\n * @param options - Optional shape, transform, and metadata.\n * @returns The newly created assembly node.\n */\nexport function createAssemblyNode(name: string, options: AssemblyNodeOptions = {}): AssemblyNode {\n return {\n name,\n children: [],\n ...(options.shape !== undefined ? { shape: options.shape } : {}),\n ...(options.translate !== undefined ? { translate: options.translate } : {}),\n ...(options.rotate !== undefined ? { rotate: options.rotate } : {}),\n ...(options.metadata !== undefined ? { metadata: options.metadata } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Immutable tree operations\n// ---------------------------------------------------------------------------\n\n/**\n * Add a child node. Returns a new parent node.\n * @param parent - The parent node to extend.\n * @param child - The child node to append.\n * @returns A new parent node with the child added.\n */\nexport function addChild(parent: AssemblyNode, child: AssemblyNode): AssemblyNode {\n return { ...parent, children: [...parent.children, child] };\n}\n\n/**\n * Remove a child by name (first match). Returns a new parent node.\n * @param parent - The parent node to modify.\n * @param childName - Name of the child to remove.\n * @returns A new parent node with the child removed.\n */\nexport function removeChild(parent: AssemblyNode, childName: string): AssemblyNode {\n const idx = parent.children.findIndex((c) => c.name === childName);\n if (idx === -1) return parent;\n const children = [...parent.children];\n children.splice(idx, 1);\n return { ...parent, children };\n}\n\n/**\n * Update a node's properties. Returns a new node.\n * @param node - The node to update.\n * @param updates - Partial options to apply.\n * @returns A new node with the updates applied.\n */\nexport function updateNode(\n node: AssemblyNode,\n updates: Partial<AssemblyNodeOptions>\n): AssemblyNode {\n return {\n ...node,\n ...(updates.shape !== undefined ? { shape: updates.shape } : {}),\n ...(updates.translate !== undefined ? { translate: updates.translate } : {}),\n ...(updates.rotate !== undefined ? { rotate: updates.rotate } : {}),\n ...(updates.metadata !== undefined ? { metadata: updates.metadata } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Traversal\n// ---------------------------------------------------------------------------\n\n/**\n * Find a node by name (depth-first). Returns undefined if not found.\n * @param root - Root of the subtree to search.\n * @param name - Name of the node to find.\n * @returns The first matching node, or undefined.\n */\nexport function findNode(root: AssemblyNode, name: string): AssemblyNode | undefined {\n if (root.name === name) return root;\n for (const child of root.children) {\n const found = findNode(child, name);\n if (found) return found;\n }\n return undefined;\n}\n\n/**\n * Walk the tree depth-first, calling visitor for each node.\n * @param root - Root node to walk from.\n * @param visitor - Callback invoked with each node and its depth.\n * @param depth - Starting depth (used internally for recursion).\n * @returns Nothing.\n */\nexport function walkAssembly(\n root: AssemblyNode,\n visitor: (node: AssemblyNode, depth: number) => void,\n depth = 0\n): void {\n visitor(root, depth);\n for (const child of root.children) {\n walkAssembly(child, visitor, depth + 1);\n }\n}\n\n/**\n * Count all nodes in the tree.\n * @param root - Root node to count from.\n * @returns Total number of nodes including the root.\n */\nexport function countNodes(root: AssemblyNode): number {\n let count = 1;\n for (const child of root.children) {\n count += countNodes(child);\n }\n return count;\n}\n\n/**\n * Collect all shapes in the tree (depth-first).\n * @param root - Root node to collect from.\n * @returns All shapes found on nodes in the tree.\n */\nexport function collectShapes(root: AssemblyNode): Shape[] {\n const shapes: Shape[] = [];\n walkAssembly(root, (node) => {\n if (node.shape) shapes.push(node.shape);\n });\n return shapes;\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Constraint solver (chain) — core 自有实现(§5.6 移植:vendored solverAdapter 逐字对齐)。
2
+ * Constraint solver (chain) — core 自有实现(§5.6 移植:brepjs solverAdapter 逐字对齐)。
3
3
  *
4
4
  * 移植来源:packages/brepjs/src/kernel/solverAdapter.ts(Phase 5 随 brepjs 包删除前
5
- * 已做 parity 对拍——本文件与 vendored 行为逐项一致,无重新设计)。
5
+ * 已做 parity 对拍——本文件与 brepjs 行为逐项一致,无重新设计)。
6
6
  * 类型 SolverEntity/SolverConstraint/SolverResult 迁入 ./types(§5.6.1,消费方共用)。
7
7
  */
8
8
  import type { SolverConstraint, SolverResult } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"chain-solver.js","sourceRoot":"","sources":["../../../../src/api/assembly/solvers/chain-solver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Constraint solver (chain) — core 自有实现(§5.6 移植:vendored solverAdapter 逐字对齐)。\n *\n * 移植来源:packages/brepjs/src/kernel/solverAdapter.ts(Phase 5 随 brepjs 包删除前\n * 已做 parity 对拍——本文件与 vendored 行为逐项一致,无重新设计)。\n * 类型 SolverEntity/SolverConstraint/SolverResult 迁入 ./types(§5.6.1,消费方共用)。\n */\nimport type { SolverEntity, SolverConstraint, SolverResult } from './types'\n\nimport { quatRotate, quatFromAxisAngle, quatFromTo } from './quat'\n\n/** 3D vector (local alias to avoid cross-layer import). */\ntype Vec3 = readonly [number, number, number];\n\n/**\n * Degrees of freedom each constraint leaves unresolved when it can't be applied\n * (entity-type mismatch or an unreachable reference). All four types now solve\n * for well-typed inputs; these counts only feed the diagnostic `dof` for the\n * unsupported cases.\n * coincident: 3 translational · concentric: 2 rotational + 2 translational = 4\n * distance: 1 translational · angle: 1 rotational\n */\nconst UNSUPPORTED_DOF: Readonly<Record<string, number>> = {\n coincident: 3,\n concentric: 4,\n distance: 1,\n angle: 1,\n};\n\ntype Quat = [number, number, number, number];\ntype Pose = { position: Vec3; rotation: Quat };\n\nconst IDENTITY_ROTATION: Quat = [1, 0, 0, 0];\n\nfunction add(a: Vec3, b: Vec3): Vec3 {\n return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];\n}\n\nfunction sub(a: Vec3, b: Vec3): Vec3 {\n return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];\n}\n\nfunction dot(a: Vec3, b: Vec3): number {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n}\n\nfunction cross(a: Vec3, b: Vec3): Vec3 {\n return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];\n}\n\nfunction scale(a: Vec3, s: number): Vec3 {\n return [a[0] * s, a[1] * s, a[2] * s];\n}\n\nfunction normalize(a: Vec3): Vec3 {\n const l = Math.hypot(a[0], a[1], a[2]) || 1;\n return [a[0] / l, a[1] / l, a[2] / l];\n}\n\n/** A unit vector perpendicular to `v` (for the parallel-normals degenerate case). */\nfunction anyPerpendicular(v: Vec3): Vec3 {\n const ref: Vec3 = Math.abs(v[0]) < 0.9 ? [1, 0, 0] : [0, 1, 0];\n return normalize(cross(v, ref));\n}\n\n/** Apply a pose (rotate then translate) to an entity's origin and any directions. */\nfunction transformEntity(e: SolverEntity, pose: Pose): SolverEntity {\n const origin = add(quatRotate(pose.rotation, e.origin), pose.position);\n return {\n type: e.type,\n origin,\n ...(e.normal ? { normal: quatRotate(pose.rotation, e.normal) } : {}),\n ...(e.direction ? { direction: quatRotate(pose.rotation, e.direction) } : {}),\n };\n}\n\n/**\n * Position a dependent plane against an already-placed reference plane.\n *\n * `ref` is the reference entity already in world space. The dependent is at the\n * origin (a node is only solved once, while unplaced), so the returned position\n * is its absolute translation along the reference normal. `extra` is the gap for\n * a distance mate (0 for coincident). Plane mates don't reorient the dependent.\n */\nfunction solvePlanePair(ref: SolverEntity, dep: SolverEntity, extra: number): Pose {\n const n = ref.normal ?? [0, 0, 1];\n const offset = dot(n, sub(ref.origin, dep.origin)) + extra;\n return { position: scale(n, offset), rotation: IDENTITY_ROTATION };\n}\n\n/**\n * Concentric (axis-axis) mate: rotate the dependent so its axis is parallel to\n * the reference axis, then translate so the two axes are collinear (the\n * dependent's axis point is placed on the reference axis). `ref` is in world\n * space; the dependent is at the origin.\n */\nfunction solveConcentric(ref: SolverEntity, dep: SolverEntity): Pose {\n const dRef = ref.direction ?? [0, 0, 1];\n const dDep = dep.direction ?? [0, 0, 1];\n const rotation = quatFromTo(dDep, dRef);\n const rotatedOrigin = quatRotate(rotation, dep.origin);\n return { position: sub(ref.origin, rotatedOrigin), rotation };\n}\n\n/**\n * Angle mate: rotate the dependent so the angle between its (plane) normal and\n * the reference normal equals `angleRad`. Orientation-only — position is left at\n * the origin. `ref` is in world space; the dependent is at the origin.\n */\nfunction solveAngle(ref: SolverEntity, dep: SolverEntity, angleRad: number): Pose {\n const nRef = normalize(ref.normal ?? [0, 0, 1]);\n const nDep = normalize(dep.normal ?? [0, 0, 1]);\n const phi = Math.acos(Math.max(-1, Math.min(1, dot(nDep, nRef))));\n const c = cross(nDep, nRef);\n const axis = Math.hypot(c[0], c[1], c[2]) < 1e-9 ? anyPerpendicular(nDep) : c;\n // Rotating nDep about (nDep×nRef) by +phi aligns it with nRef; rotate by\n // (phi − angle) to leave exactly `angleRad` between them.\n return { position: [0, 0, 0], rotation: quatFromAxisAngle(axis, phi - angleRad) };\n}\n\n/**\n * Point-point coincident/distance: place the dependent point on the reference\n * point (`extra` = 0) or at `extra` along the original separation direction.\n * If the points already coincide the direction is arbitrary (+X).\n */\nfunction solvePointPair(refOrigin: Vec3, depOrigin: Vec3, extra: number): Pose {\n const sep = sub(depOrigin, refOrigin);\n const len = Math.hypot(sep[0], sep[1], sep[2]);\n const dir: Vec3 = len < 1e-9 ? [1, 0, 0] : scale(sep, 1 / len);\n const target = add(refOrigin, scale(dir, extra));\n return { position: sub(target, depOrigin), rotation: IDENTITY_ROTATION };\n}\n\n/**\n * Move the dependent plane (normal `depNormal`, at the origin) so its signed\n * distance from the reference point equals `extra` (the mirror of `solvePlanePair`\n * for a point reference and a plane dependent).\n */\nfunction solvePlaneToPoint(depNormal: Vec3, refOrigin: Vec3, depOrigin: Vec3, extra: number): Pose {\n const n = normalize(depNormal);\n const t = dot(n, sub(refOrigin, depOrigin)) - extra;\n return { position: scale(n, t), rotation: IDENTITY_ROTATION };\n}\n\n/**\n * Reference axis, dependent point: drop the point onto the axis line\n * (`extra` = 0) or place it at radial distance `extra` from the line, keeping\n * its along-axis position. A point already on the axis gets an arbitrary radial.\n */\nfunction solveAxisToPoint(ref: SolverEntity, depOrigin: Vec3, extra: number): Pose {\n const d = normalize(ref.direction ?? [0, 0, 1]);\n const foot = add(ref.origin, scale(d, dot(d, sub(depOrigin, ref.origin))));\n if (extra === 0) return { position: sub(foot, depOrigin), rotation: IDENTITY_ROTATION };\n const radial = sub(depOrigin, foot);\n const rlen = Math.hypot(radial[0], radial[1], radial[2]);\n const rdir = rlen < 1e-9 ? anyPerpendicular(d) : scale(radial, 1 / rlen);\n return { position: sub(add(foot, scale(rdir, extra)), depOrigin), rotation: IDENTITY_ROTATION };\n}\n\n/**\n * Reference point, dependent axis: translate the axis line so it passes through\n * the point (`extra` = 0) or lies at perpendicular distance `extra` from it.\n * Translation is purely perpendicular to the axis, so the line's direction and\n * along-axis parameterization are preserved.\n */\nfunction solvePointToAxis(refOrigin: Vec3, dep: SolverEntity, extra: number): Pose {\n const d = normalize(dep.direction ?? [0, 0, 1]);\n const w = sub(dep.origin, refOrigin);\n const perp = sub(w, scale(d, dot(d, w)));\n const plen = Math.hypot(perp[0], perp[1], perp[2]);\n if (extra === 0) return { position: scale(perp, -1), rotation: IDENTITY_ROTATION };\n const pdir = plen < 1e-9 ? anyPerpendicular(d) : scale(perp, 1 / plen);\n return { position: sub(scale(pdir, extra), perp), rotation: IDENTITY_ROTATION };\n}\n\n/**\n * Axis-axis distance: align the dependent axis parallel to the reference, then\n * offset it to perpendicular distance `extra` (parallel pin-and-spacer). With\n * `extra` = 0 the axes become collinear, matching `concentric`.\n */\nfunction solveAxisAxisDistance(ref: SolverEntity, dep: SolverEntity, extra: number): Pose {\n const dRef = normalize(ref.direction ?? [0, 0, 1]);\n const dDep = normalize(dep.direction ?? [0, 0, 1]);\n const rotation = quatFromTo(dDep, dRef);\n const depO = quatRotate(rotation, dep.origin);\n const w = sub(depO, ref.origin);\n const perp = sub(w, scale(dRef, dot(dRef, w)));\n const plen = Math.hypot(perp[0], perp[1], perp[2]);\n const pdir = plen < 1e-9 ? anyPerpendicular(dRef) : scale(perp, 1 / plen);\n return { position: sub(scale(pdir, extra), perp), rotation };\n}\n\n/**\n * Supported entity-type pairs for the translational mates (`coincident` /\n * `distance`), keyed `${entityA}-${entityB}`. Both orders are listed where the\n * solver handles them, so a user need not pre-order the entities.\n */\nconst TRANSLATIONAL_PAIRS = new Set([\n 'plane-plane',\n 'plane-point',\n 'point-plane',\n 'point-point',\n 'axis-axis',\n 'axis-point',\n 'point-axis',\n]);\n\n/** Entity types the orientation/axis mates require of (entityA, entityB). */\nconst REQUIRED_ENTITIES: Readonly<Record<string, SolverEntity['type']>> = {\n angle: 'plane',\n concentric: 'axis',\n};\n\nconst POSITIONING_TYPES = new Set(['coincident', 'distance', 'angle', 'concentric']);\n\n/** Whether a positioning mate's entity pair is solvable. */\nfunction isSupportedPair(type: string, a: SolverEntity['type'], b: SolverEntity['type']): boolean {\n const required = REQUIRED_ENTITIES[type];\n if (required) return a === required && b === required;\n // coincident / distance: dispatch by entity-type pair.\n return TRANSLATIONAL_PAIRS.has(`${a}-${b}`);\n}\n\n/**\n * Solve a `coincident` (extra = 0) or `distance` (extra = value) mate for any\n * supported entity-type pair. `ref` is already in world space; the dependent is\n * at the origin. Returns null only for an unsupported pair (filtered out\n * upstream by `isSupportedPair`).\n */\nfunction solveTranslational(ref: SolverEntity, dep: SolverEntity, extra: number): Pose | null {\n const key = `${ref.type}-${dep.type}`;\n switch (key) {\n case 'plane-plane':\n case 'plane-point':\n // Both use the reference plane normal; a point dependent has no normal.\n return solvePlanePair(ref, dep, extra);\n case 'point-plane':\n return solvePlaneToPoint(dep.normal ?? [0, 0, 1], ref.origin, dep.origin, extra);\n case 'point-point':\n return solvePointPair(ref.origin, dep.origin, extra);\n case 'axis-axis':\n return extra === 0 ? solveConcentric(ref, dep) : solveAxisAxisDistance(ref, dep, extra);\n case 'axis-point':\n return solveAxisToPoint(ref, dep.origin, extra);\n case 'point-axis':\n return solvePointToAxis(ref.origin, dep, extra);\n default:\n return null;\n }\n}\n\n/** Dispatch a positioning mate to its solver. `ref` is already in world space. */\nfunction solveMate(c: SolverConstraint, ref: SolverEntity, dep: SolverEntity): Pose {\n switch (c.type) {\n case 'concentric':\n return solveConcentric(ref, dep);\n case 'angle':\n return solveAngle(ref, dep, ((c.value ?? 0) * Math.PI) / 180);\n default: {\n // coincident (extra = 0) / distance (extra = value). isSupportedPair has\n // already filtered out unsupported pairs upstream, so a null here means\n // TRANSLATIONAL_PAIRS and solveTranslational drifted out of sync — surface\n // that invariant violation loudly rather than guessing with plane logic.\n const extra = c.type === 'distance' ? (c.value ?? 0) : 0;\n const pose = solveTranslational(ref, dep, extra);\n if (!pose) {\n throw new Error(\n `solveMate: unsupported entity pair escaped filter: ${ref.type}-${dep.type}`\n );\n }\n return pose;\n }\n }\n}\n\n/**\n * Solve assembly constraints analytically.\n *\n * Handles: fixed, concentric (axis-axis), angle (plane-plane orientation), and\n * coincident/distance for any supported entity-type pair (plane-plane,\n * plane-point, point-point, axis-axis, axis-point, and both point orders — see\n * `TRANSLATIONAL_PAIRS`). For a positioning mate, entityA is the reference and\n * entityB the dependent. Chain roots (nodes never positioned by a\n * mate) and explicit `fixed` nodes anchor at the origin; constraints then resolve\n * in topological order — each places its dependent against the reference's solved\n * pose (rotation included), so multi-body chains compose. Returns\n * `converged: false` with details for entity-type mismatches and any constraint\n * whose reference never resolves.\n * @param nodes - Names of the nodes participating in the assembly.\n * @param constraints - Constraints to solve.\n * @returns The solver result with per-node transforms, DOF count, and convergence info.\n */\nexport function solveConstraints(nodes: string[], constraints: SolverConstraint[]): SolverResult {\n const transforms = new Map<string, Pose>();\n\n // Initialize all nodes at origin\n for (const node of nodes) {\n transforms.set(node, { position: [0, 0, 0], rotation: IDENTITY_ROTATION });\n }\n\n const unsupported: string[] = [];\n\n // For positioning mates, entityA is the reference and entityB the dependent.\n const positioning = constraints.filter(\n (c) => POSITIONING_TYPES.has(c.type) && c.entityA && c.entityB\n );\n const dependents = new Set<string>();\n for (const c of positioning) if (c.entityB) dependents.add(c.entityB.node);\n\n // Anchors are placed at the origin: any node never positioned by a mate (a\n // chain root), plus any explicit `fixed` node.\n const placed = new Set<string>();\n for (const node of nodes) if (!dependents.has(node)) placed.add(node);\n for (const c of constraints) if (c.type === 'fixed' && c.entityA) placed.add(c.entityA.node);\n\n // Entity-type mismatches are unsupported regardless of order; report them\n // eagerly and keep only well-typed mates for topological resolution. A node\n // left unplaced by such a mate (it's a dependent, so not a root) will cause\n // any downstream mate that references it to end up `(unanchored)` — intended:\n // an unsolved reference can't compose, so the chain doesn't converge.\n const pending: SolverConstraint[] = [];\n for (const c of positioning) {\n if (!c.entityA || !c.entityB) continue;\n const a = c.entityA.entity.type;\n const b = c.entityB.entity.type;\n if (!isSupportedPair(c.type, a, b)) {\n unsupported.push(`${c.type}(${a}-${b})`);\n continue;\n }\n pending.push(c);\n }\n\n // Resolve in topological rounds: a mate solves once its reference (entityA) is\n // placed, positioning the dependent (entityB) against the reference's solved\n // world-space pose so multi-body chains compose.\n let progress = true;\n while (progress && pending.length > 0) {\n progress = false;\n for (let i = pending.length - 1; i >= 0; i--) {\n const c = pending[i];\n if (!c?.entityA || !c.entityB) continue;\n const ref = c.entityA;\n const dep = c.entityB;\n if (!placed.has(ref.node)) continue; // reference not solved yet — defer\n\n pending.splice(i, 1);\n progress = true;\n if (placed.has(dep.node)) continue; // dependent already anchored (fixed) — redundant\n\n const refPose = transforms.get(ref.node) ?? {\n position: [0, 0, 0],\n rotation: IDENTITY_ROTATION,\n };\n const refWorld = transformEntity(ref.entity, refPose);\n transforms.set(dep.node, solveMate(c, refWorld, dep.entity));\n placed.add(dep.node);\n }\n }\n\n // Anything still pending has a reference that never resolved (e.g. a cycle).\n for (const c of pending) unsupported.push(`${c.type}(unanchored)`);\n\n const dof = unsupported.reduce((sum, type) => {\n // Look up by exact key first, then by base type (before parenthesis)\n const baseDof = UNSUPPORTED_DOF[type] ?? UNSUPPORTED_DOF[type.split('(')[0] ?? ''] ?? 0;\n return sum + baseDof;\n }, 0);\n\n return { transforms, dof, converged: unsupported.length === 0, unsupported };\n}\n"]}
1
+ {"version":3,"file":"chain-solver.js","sourceRoot":"","sources":["../../../../src/api/assembly/solvers/chain-solver.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAKlE;;;;;;;GAOG;AACH,MAAM,eAAe,GAAqC;IACxD,UAAU,EAAE,CAAC;IACb,UAAU,EAAE,CAAC;IACb,QAAQ,EAAE,CAAC;IACX,KAAK,EAAE,CAAC;CACT,CAAC;AAKF,MAAM,iBAAiB,GAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAE7C,SAAS,GAAG,CAAC,CAAO,EAAE,CAAO;IAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,GAAG,CAAC,CAAO,EAAE,CAAO;IAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,GAAG,CAAC,CAAO,EAAE,CAAO;IAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,KAAK,CAAC,CAAO,EAAE,CAAO;IAC7B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3F,CAAC;AAED,SAAS,KAAK,CAAC,CAAO,EAAE,CAAS;IAC/B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,SAAS,CAAC,CAAO;IACxB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5C,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,qFAAqF;AACrF,SAAS,gBAAgB,CAAC,CAAO;IAC/B,MAAM,GAAG,GAAS,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/D,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,qFAAqF;AACrF,SAAS,eAAe,CAAC,CAAe,EAAE,IAAU;IAClD,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvE,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM;QACN,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9E,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,GAAiB,EAAE,GAAiB,EAAE,KAAa;IACzE,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC;IAC3D,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;AACrE,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,GAAiB,EAAE,GAAiB;IAC3D,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,aAAa,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvD,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC;AAChE,CAAC;AAED;;;;GAIG;AACH,SAAS,UAAU,CAAC,GAAiB,EAAE,GAAiB,EAAE,QAAgB;IACxE,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,yEAAyE;IACzE,0DAA0D;IAC1D,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,iBAAiB,CAAC,IAAI,EAAE,GAAG,GAAG,QAAQ,CAAC,EAAE,CAAC;AACpF,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,SAAe,EAAE,SAAe,EAAE,KAAa;IACrE,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAS,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IACjD,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,SAAe,EAAE,SAAe,EAAE,SAAe,EAAE,KAAa;IACzF,MAAM,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IAC/B,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,GAAG,KAAK,CAAC;IACpD,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;AAChE,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,GAAiB,EAAE,SAAe,EAAE,KAAa;IACzE,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IACxF,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IACzE,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;AAClG,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,SAAe,EAAE,GAAiB,EAAE,KAAa;IACzE,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IACnF,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IACvE,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;AAClF,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,GAAiB,EAAE,GAAiB,EAAE,KAAa;IAChF,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1E,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,aAAa;IACb,aAAa;IACb,aAAa;IACb,aAAa;IACb,WAAW;IACX,YAAY;IACZ,YAAY;CACb,CAAC,CAAC;AAEH,6EAA6E;AAC7E,MAAM,iBAAiB,GAAmD;IACxE,KAAK,EAAE,OAAO;IACd,UAAU,EAAE,MAAM;CACnB,CAAC;AAEF,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;AAErF,4DAA4D;AAC5D,SAAS,eAAe,CAAC,IAAY,EAAE,CAAuB,EAAE,CAAuB;IACrF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,QAAQ;QAAE,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,QAAQ,CAAC;IACtD,uDAAuD;IACvD,OAAO,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,SAAS,kBAAkB,CAAC,GAAiB,EAAE,GAAiB,EAAE,KAAa;IAC7E,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;IACtC,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,aAAa,CAAC;QACnB,KAAK,aAAa;YAChB,wEAAwE;YACxE,OAAO,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QACzC,KAAK,aAAa;YAChB,OAAO,iBAAiB,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACnF,KAAK,aAAa;YAChB,OAAO,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACvD,KAAK,WAAW;YACd,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAC1F,KAAK,YAAY;YACf,OAAO,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAClD,KAAK,YAAY;YACf,OAAO,gBAAgB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QAClD;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,kFAAkF;AAClF,SAAS,SAAS,CAAC,CAAmB,EAAE,GAAiB,EAAE,GAAiB;IAC1E,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,YAAY;YACf,OAAO,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACnC,KAAK,OAAO;YACV,OAAO,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC;QAChE,OAAO,CAAC,CAAC,CAAC;YACR,yEAAyE;YACzE,wEAAwE;YACxE,2EAA2E;YAC3E,yEAAyE;YACzE,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzD,MAAM,IAAI,GAAG,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YACjD,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CACb,sDAAsD,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAC7E,CAAC;YACJ,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAe,EAAE,WAA+B;IAC/E,MAAM,UAAU,GAAG,IAAI,GAAG,EAAgB,CAAC;IAE3C,iCAAiC;IACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,6EAA6E;IAC7E,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAC/D,CAAC;IACF,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,WAAW;QAAE,IAAI,CAAC,CAAC,OAAO;YAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3E,2EAA2E;IAC3E,+CAA+C;IAC/C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtE,KAAK,MAAM,CAAC,IAAI,WAAW;QAAE,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO;YAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7F,0EAA0E;IAC1E,4EAA4E;IAC5E,4EAA4E;IAC5E,8EAA8E;IAC9E,sEAAsE;IACtE,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO;YAAE,SAAS;QACvC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;QAChC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACnC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzC,SAAS;QACX,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,+EAA+E;IAC/E,6EAA6E;IAC7E,iDAAiD;IACjD,IAAI,QAAQ,GAAG,IAAI,CAAC;IACpB,OAAO,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,QAAQ,GAAG,KAAK,CAAC;QACjB,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACrB,IAAI,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,SAAS;YACxC,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC;YACtB,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC;YACtB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS,CAAC,mCAAmC;YAExE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS,CAAC,iDAAiD;YAErF,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;gBAC1C,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBACnB,QAAQ,EAAE,iBAAiB;aAC5B,CAAC;YACF,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACtD,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7D,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC;IAEnE,MAAM,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QAC3C,qEAAqE;QACrE,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;QACxF,OAAO,GAAG,GAAG,OAAO,CAAC;IACvB,CAAC,EAAE,CAAC,CAAC,CAAC;IAEN,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;AAC/E,CAAC","sourcesContent":["/**\n * Constraint solver (chain) — core 自有实现(§5.6 移植:brepjs solverAdapter 逐字对齐)。\n *\n * 移植来源:packages/brepjs/src/kernel/solverAdapter.ts(Phase 5 随 brepjs 包删除前\n * 已做 parity 对拍——本文件与 brepjs 行为逐项一致,无重新设计)。\n * 类型 SolverEntity/SolverConstraint/SolverResult 迁入 ./types(§5.6.1,消费方共用)。\n */\nimport type { SolverEntity, SolverConstraint, SolverResult } from './types'\n\nimport { quatRotate, quatFromAxisAngle, quatFromTo } from './quat'\n\n/** 3D vector (local alias to avoid cross-layer import). */\ntype Vec3 = readonly [number, number, number];\n\n/**\n * Degrees of freedom each constraint leaves unresolved when it can't be applied\n * (entity-type mismatch or an unreachable reference). All four types now solve\n * for well-typed inputs; these counts only feed the diagnostic `dof` for the\n * unsupported cases.\n * coincident: 3 translational · concentric: 2 rotational + 2 translational = 4\n * distance: 1 translational · angle: 1 rotational\n */\nconst UNSUPPORTED_DOF: Readonly<Record<string, number>> = {\n coincident: 3,\n concentric: 4,\n distance: 1,\n angle: 1,\n};\n\ntype Quat = [number, number, number, number];\ntype Pose = { position: Vec3; rotation: Quat };\n\nconst IDENTITY_ROTATION: Quat = [1, 0, 0, 0];\n\nfunction add(a: Vec3, b: Vec3): Vec3 {\n return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];\n}\n\nfunction sub(a: Vec3, b: Vec3): Vec3 {\n return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];\n}\n\nfunction dot(a: Vec3, b: Vec3): number {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n}\n\nfunction cross(a: Vec3, b: Vec3): Vec3 {\n return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];\n}\n\nfunction scale(a: Vec3, s: number): Vec3 {\n return [a[0] * s, a[1] * s, a[2] * s];\n}\n\nfunction normalize(a: Vec3): Vec3 {\n const l = Math.hypot(a[0], a[1], a[2]) || 1;\n return [a[0] / l, a[1] / l, a[2] / l];\n}\n\n/** A unit vector perpendicular to `v` (for the parallel-normals degenerate case). */\nfunction anyPerpendicular(v: Vec3): Vec3 {\n const ref: Vec3 = Math.abs(v[0]) < 0.9 ? [1, 0, 0] : [0, 1, 0];\n return normalize(cross(v, ref));\n}\n\n/** Apply a pose (rotate then translate) to an entity's origin and any directions. */\nfunction transformEntity(e: SolverEntity, pose: Pose): SolverEntity {\n const origin = add(quatRotate(pose.rotation, e.origin), pose.position);\n return {\n type: e.type,\n origin,\n ...(e.normal ? { normal: quatRotate(pose.rotation, e.normal) } : {}),\n ...(e.direction ? { direction: quatRotate(pose.rotation, e.direction) } : {}),\n };\n}\n\n/**\n * Position a dependent plane against an already-placed reference plane.\n *\n * `ref` is the reference entity already in world space. The dependent is at the\n * origin (a node is only solved once, while unplaced), so the returned position\n * is its absolute translation along the reference normal. `extra` is the gap for\n * a distance mate (0 for coincident). Plane mates don't reorient the dependent.\n */\nfunction solvePlanePair(ref: SolverEntity, dep: SolverEntity, extra: number): Pose {\n const n = ref.normal ?? [0, 0, 1];\n const offset = dot(n, sub(ref.origin, dep.origin)) + extra;\n return { position: scale(n, offset), rotation: IDENTITY_ROTATION };\n}\n\n/**\n * Concentric (axis-axis) mate: rotate the dependent so its axis is parallel to\n * the reference axis, then translate so the two axes are collinear (the\n * dependent's axis point is placed on the reference axis). `ref` is in world\n * space; the dependent is at the origin.\n */\nfunction solveConcentric(ref: SolverEntity, dep: SolverEntity): Pose {\n const dRef = ref.direction ?? [0, 0, 1];\n const dDep = dep.direction ?? [0, 0, 1];\n const rotation = quatFromTo(dDep, dRef);\n const rotatedOrigin = quatRotate(rotation, dep.origin);\n return { position: sub(ref.origin, rotatedOrigin), rotation };\n}\n\n/**\n * Angle mate: rotate the dependent so the angle between its (plane) normal and\n * the reference normal equals `angleRad`. Orientation-only — position is left at\n * the origin. `ref` is in world space; the dependent is at the origin.\n */\nfunction solveAngle(ref: SolverEntity, dep: SolverEntity, angleRad: number): Pose {\n const nRef = normalize(ref.normal ?? [0, 0, 1]);\n const nDep = normalize(dep.normal ?? [0, 0, 1]);\n const phi = Math.acos(Math.max(-1, Math.min(1, dot(nDep, nRef))));\n const c = cross(nDep, nRef);\n const axis = Math.hypot(c[0], c[1], c[2]) < 1e-9 ? anyPerpendicular(nDep) : c;\n // Rotating nDep about (nDep×nRef) by +phi aligns it with nRef; rotate by\n // (phi − angle) to leave exactly `angleRad` between them.\n return { position: [0, 0, 0], rotation: quatFromAxisAngle(axis, phi - angleRad) };\n}\n\n/**\n * Point-point coincident/distance: place the dependent point on the reference\n * point (`extra` = 0) or at `extra` along the original separation direction.\n * If the points already coincide the direction is arbitrary (+X).\n */\nfunction solvePointPair(refOrigin: Vec3, depOrigin: Vec3, extra: number): Pose {\n const sep = sub(depOrigin, refOrigin);\n const len = Math.hypot(sep[0], sep[1], sep[2]);\n const dir: Vec3 = len < 1e-9 ? [1, 0, 0] : scale(sep, 1 / len);\n const target = add(refOrigin, scale(dir, extra));\n return { position: sub(target, depOrigin), rotation: IDENTITY_ROTATION };\n}\n\n/**\n * Move the dependent plane (normal `depNormal`, at the origin) so its signed\n * distance from the reference point equals `extra` (the mirror of `solvePlanePair`\n * for a point reference and a plane dependent).\n */\nfunction solvePlaneToPoint(depNormal: Vec3, refOrigin: Vec3, depOrigin: Vec3, extra: number): Pose {\n const n = normalize(depNormal);\n const t = dot(n, sub(refOrigin, depOrigin)) - extra;\n return { position: scale(n, t), rotation: IDENTITY_ROTATION };\n}\n\n/**\n * Reference axis, dependent point: drop the point onto the axis line\n * (`extra` = 0) or place it at radial distance `extra` from the line, keeping\n * its along-axis position. A point already on the axis gets an arbitrary radial.\n */\nfunction solveAxisToPoint(ref: SolverEntity, depOrigin: Vec3, extra: number): Pose {\n const d = normalize(ref.direction ?? [0, 0, 1]);\n const foot = add(ref.origin, scale(d, dot(d, sub(depOrigin, ref.origin))));\n if (extra === 0) return { position: sub(foot, depOrigin), rotation: IDENTITY_ROTATION };\n const radial = sub(depOrigin, foot);\n const rlen = Math.hypot(radial[0], radial[1], radial[2]);\n const rdir = rlen < 1e-9 ? anyPerpendicular(d) : scale(radial, 1 / rlen);\n return { position: sub(add(foot, scale(rdir, extra)), depOrigin), rotation: IDENTITY_ROTATION };\n}\n\n/**\n * Reference point, dependent axis: translate the axis line so it passes through\n * the point (`extra` = 0) or lies at perpendicular distance `extra` from it.\n * Translation is purely perpendicular to the axis, so the line's direction and\n * along-axis parameterization are preserved.\n */\nfunction solvePointToAxis(refOrigin: Vec3, dep: SolverEntity, extra: number): Pose {\n const d = normalize(dep.direction ?? [0, 0, 1]);\n const w = sub(dep.origin, refOrigin);\n const perp = sub(w, scale(d, dot(d, w)));\n const plen = Math.hypot(perp[0], perp[1], perp[2]);\n if (extra === 0) return { position: scale(perp, -1), rotation: IDENTITY_ROTATION };\n const pdir = plen < 1e-9 ? anyPerpendicular(d) : scale(perp, 1 / plen);\n return { position: sub(scale(pdir, extra), perp), rotation: IDENTITY_ROTATION };\n}\n\n/**\n * Axis-axis distance: align the dependent axis parallel to the reference, then\n * offset it to perpendicular distance `extra` (parallel pin-and-spacer). With\n * `extra` = 0 the axes become collinear, matching `concentric`.\n */\nfunction solveAxisAxisDistance(ref: SolverEntity, dep: SolverEntity, extra: number): Pose {\n const dRef = normalize(ref.direction ?? [0, 0, 1]);\n const dDep = normalize(dep.direction ?? [0, 0, 1]);\n const rotation = quatFromTo(dDep, dRef);\n const depO = quatRotate(rotation, dep.origin);\n const w = sub(depO, ref.origin);\n const perp = sub(w, scale(dRef, dot(dRef, w)));\n const plen = Math.hypot(perp[0], perp[1], perp[2]);\n const pdir = plen < 1e-9 ? anyPerpendicular(dRef) : scale(perp, 1 / plen);\n return { position: sub(scale(pdir, extra), perp), rotation };\n}\n\n/**\n * Supported entity-type pairs for the translational mates (`coincident` /\n * `distance`), keyed `${entityA}-${entityB}`. Both orders are listed where the\n * solver handles them, so a user need not pre-order the entities.\n */\nconst TRANSLATIONAL_PAIRS = new Set([\n 'plane-plane',\n 'plane-point',\n 'point-plane',\n 'point-point',\n 'axis-axis',\n 'axis-point',\n 'point-axis',\n]);\n\n/** Entity types the orientation/axis mates require of (entityA, entityB). */\nconst REQUIRED_ENTITIES: Readonly<Record<string, SolverEntity['type']>> = {\n angle: 'plane',\n concentric: 'axis',\n};\n\nconst POSITIONING_TYPES = new Set(['coincident', 'distance', 'angle', 'concentric']);\n\n/** Whether a positioning mate's entity pair is solvable. */\nfunction isSupportedPair(type: string, a: SolverEntity['type'], b: SolverEntity['type']): boolean {\n const required = REQUIRED_ENTITIES[type];\n if (required) return a === required && b === required;\n // coincident / distance: dispatch by entity-type pair.\n return TRANSLATIONAL_PAIRS.has(`${a}-${b}`);\n}\n\n/**\n * Solve a `coincident` (extra = 0) or `distance` (extra = value) mate for any\n * supported entity-type pair. `ref` is already in world space; the dependent is\n * at the origin. Returns null only for an unsupported pair (filtered out\n * upstream by `isSupportedPair`).\n */\nfunction solveTranslational(ref: SolverEntity, dep: SolverEntity, extra: number): Pose | null {\n const key = `${ref.type}-${dep.type}`;\n switch (key) {\n case 'plane-plane':\n case 'plane-point':\n // Both use the reference plane normal; a point dependent has no normal.\n return solvePlanePair(ref, dep, extra);\n case 'point-plane':\n return solvePlaneToPoint(dep.normal ?? [0, 0, 1], ref.origin, dep.origin, extra);\n case 'point-point':\n return solvePointPair(ref.origin, dep.origin, extra);\n case 'axis-axis':\n return extra === 0 ? solveConcentric(ref, dep) : solveAxisAxisDistance(ref, dep, extra);\n case 'axis-point':\n return solveAxisToPoint(ref, dep.origin, extra);\n case 'point-axis':\n return solvePointToAxis(ref.origin, dep, extra);\n default:\n return null;\n }\n}\n\n/** Dispatch a positioning mate to its solver. `ref` is already in world space. */\nfunction solveMate(c: SolverConstraint, ref: SolverEntity, dep: SolverEntity): Pose {\n switch (c.type) {\n case 'concentric':\n return solveConcentric(ref, dep);\n case 'angle':\n return solveAngle(ref, dep, ((c.value ?? 0) * Math.PI) / 180);\n default: {\n // coincident (extra = 0) / distance (extra = value). isSupportedPair has\n // already filtered out unsupported pairs upstream, so a null here means\n // TRANSLATIONAL_PAIRS and solveTranslational drifted out of sync — surface\n // that invariant violation loudly rather than guessing with plane logic.\n const extra = c.type === 'distance' ? (c.value ?? 0) : 0;\n const pose = solveTranslational(ref, dep, extra);\n if (!pose) {\n throw new Error(\n `solveMate: unsupported entity pair escaped filter: ${ref.type}-${dep.type}`\n );\n }\n return pose;\n }\n }\n}\n\n/**\n * Solve assembly constraints analytically.\n *\n * Handles: fixed, concentric (axis-axis), angle (plane-plane orientation), and\n * coincident/distance for any supported entity-type pair (plane-plane,\n * plane-point, point-point, axis-axis, axis-point, and both point orders — see\n * `TRANSLATIONAL_PAIRS`). For a positioning mate, entityA is the reference and\n * entityB the dependent. Chain roots (nodes never positioned by a\n * mate) and explicit `fixed` nodes anchor at the origin; constraints then resolve\n * in topological order — each places its dependent against the reference's solved\n * pose (rotation included), so multi-body chains compose. Returns\n * `converged: false` with details for entity-type mismatches and any constraint\n * whose reference never resolves.\n * @param nodes - Names of the nodes participating in the assembly.\n * @param constraints - Constraints to solve.\n * @returns The solver result with per-node transforms, DOF count, and convergence info.\n */\nexport function solveConstraints(nodes: string[], constraints: SolverConstraint[]): SolverResult {\n const transforms = new Map<string, Pose>();\n\n // Initialize all nodes at origin\n for (const node of nodes) {\n transforms.set(node, { position: [0, 0, 0], rotation: IDENTITY_ROTATION });\n }\n\n const unsupported: string[] = [];\n\n // For positioning mates, entityA is the reference and entityB the dependent.\n const positioning = constraints.filter(\n (c) => POSITIONING_TYPES.has(c.type) && c.entityA && c.entityB\n );\n const dependents = new Set<string>();\n for (const c of positioning) if (c.entityB) dependents.add(c.entityB.node);\n\n // Anchors are placed at the origin: any node never positioned by a mate (a\n // chain root), plus any explicit `fixed` node.\n const placed = new Set<string>();\n for (const node of nodes) if (!dependents.has(node)) placed.add(node);\n for (const c of constraints) if (c.type === 'fixed' && c.entityA) placed.add(c.entityA.node);\n\n // Entity-type mismatches are unsupported regardless of order; report them\n // eagerly and keep only well-typed mates for topological resolution. A node\n // left unplaced by such a mate (it's a dependent, so not a root) will cause\n // any downstream mate that references it to end up `(unanchored)` — intended:\n // an unsolved reference can't compose, so the chain doesn't converge.\n const pending: SolverConstraint[] = [];\n for (const c of positioning) {\n if (!c.entityA || !c.entityB) continue;\n const a = c.entityA.entity.type;\n const b = c.entityB.entity.type;\n if (!isSupportedPair(c.type, a, b)) {\n unsupported.push(`${c.type}(${a}-${b})`);\n continue;\n }\n pending.push(c);\n }\n\n // Resolve in topological rounds: a mate solves once its reference (entityA) is\n // placed, positioning the dependent (entityB) against the reference's solved\n // world-space pose so multi-body chains compose.\n let progress = true;\n while (progress && pending.length > 0) {\n progress = false;\n for (let i = pending.length - 1; i >= 0; i--) {\n const c = pending[i];\n if (!c?.entityA || !c.entityB) continue;\n const ref = c.entityA;\n const dep = c.entityB;\n if (!placed.has(ref.node)) continue; // reference not solved yet — defer\n\n pending.splice(i, 1);\n progress = true;\n if (placed.has(dep.node)) continue; // dependent already anchored (fixed) — redundant\n\n const refPose = transforms.get(ref.node) ?? {\n position: [0, 0, 0],\n rotation: IDENTITY_ROTATION,\n };\n const refWorld = transformEntity(ref.entity, refPose);\n transforms.set(dep.node, solveMate(c, refWorld, dep.entity));\n placed.add(dep.node);\n }\n }\n\n // Anything still pending has a reference that never resolved (e.g. a cycle).\n for (const c of pending) unsupported.push(`${c.type}(unanchored)`);\n\n const dof = unsupported.reduce((sum, type) => {\n // Look up by exact key first, then by base type (before parenthesis)\n const baseDof = UNSUPPORTED_DOF[type] ?? UNSUPPORTED_DOF[type.split('(')[0] ?? ''] ?? 0;\n return sum + baseDof;\n }, 0);\n\n return { transforms, dof, converged: unsupported.length === 0, unsupported };\n}\n"]}
@@ -3,8 +3,7 @@
3
3
  *
4
4
  * 复刻 CadQuery `cadquery/occ_impl/solver.py` 的**语义**(全局 NLP、模长参数化旋转、
5
5
  * 9 类代价、Axis 缺省反平行、Plane=Axis(π)+Point(0)、包围盒对角长缩放),
6
- * 以 Levenberg-Marquardt 替代 IPOPT,**零原生/WASM 依赖**(裁定 1–6,详见
7
- * `docs/plans/2026-09-08-assembly-dual-solver.md`)。
6
+ * 以 Levenberg-Marquardt 替代 IPOPT,**零原生/WASM 依赖**(裁定 1–6)。
8
7
  *
9
8
  * 关键裁定(写进代码,不在别处手算):
10
9
  * - 裁定 1/2:faijs Shape 不携带 placement → 初值 T0=R0=0,world 系==本地系;
@@ -1 +1 @@
1
- {"version":3,"file":"global-solver.d.ts","sourceRoot":"","sources":["../../../../src/api/assembly/solvers/global-solver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;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;AA8HtF;;;;;;;;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,CAoQnB"}
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;AA8HtF;;;;;;;;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,CAoQnB"}