@faicad/faijs 0.30.9 → 0.31.1

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 (284) hide show
  1. package/dist/api/align/index.d.ts +64 -0
  2. package/dist/api/align/index.d.ts.map +1 -0
  3. package/dist/api/align/index.js +101 -0
  4. package/dist/api/align/index.js.map +1 -0
  5. package/dist/api/api-namespace.d.ts +5 -4
  6. package/dist/api/api-namespace.d.ts.map +1 -1
  7. package/dist/api/api-namespace.js +36 -4
  8. package/dist/api/api-namespace.js.map +1 -1
  9. package/dist/api/boolean-op/index.d.ts +65 -0
  10. package/dist/api/boolean-op/index.d.ts.map +1 -0
  11. package/dist/api/boolean-op/index.js +113 -0
  12. package/dist/api/boolean-op/index.js.map +1 -0
  13. package/dist/api/boolean.d.ts.map +1 -1
  14. package/dist/api/boolean.js +15 -27
  15. package/dist/api/boolean.js.map +1 -1
  16. package/dist/api/brep-operations/healingFns.d.ts +13 -0
  17. package/dist/api/brep-operations/healingFns.d.ts.map +1 -1
  18. package/dist/api/brep-operations/healingFns.js +28 -1
  19. package/dist/api/brep-operations/healingFns.js.map +1 -1
  20. package/dist/api/brep-operations/topologyFns.d.ts +27 -6
  21. package/dist/api/brep-operations/topologyFns.d.ts.map +1 -1
  22. package/dist/api/brep-operations/topologyFns.js +46 -22
  23. package/dist/api/brep-operations/topologyFns.js.map +1 -1
  24. package/dist/api/chamfer.d.ts +5 -4
  25. package/dist/api/chamfer.d.ts.map +1 -1
  26. package/dist/api/chamfer.js +12 -11
  27. package/dist/api/chamfer.js.map +1 -1
  28. package/dist/api/curve-sketch/index.d.ts.map +1 -1
  29. package/dist/api/curve-sketch/index.js +9 -3
  30. package/dist/api/curve-sketch/index.js.map +1 -1
  31. package/dist/api/draft.d.ts.map +1 -1
  32. package/dist/api/draft.js +1 -3
  33. package/dist/api/draft.js.map +1 -1
  34. package/dist/api/engrave.d.ts.map +1 -1
  35. package/dist/api/engrave.js +3 -13
  36. package/dist/api/engrave.js.map +1 -1
  37. package/dist/api/export-3mf.d.ts +73 -0
  38. package/dist/api/export-3mf.d.ts.map +1 -0
  39. package/dist/api/export-3mf.js +121 -0
  40. package/dist/api/export-3mf.js.map +1 -0
  41. package/dist/api/export-brep.d.ts +6 -0
  42. package/dist/api/export-brep.d.ts.map +1 -1
  43. package/dist/api/export-brep.js +11 -2
  44. package/dist/api/export-brep.js.map +1 -1
  45. package/dist/api/export-step.d.ts +67 -0
  46. package/dist/api/export-step.d.ts.map +1 -0
  47. package/dist/api/export-step.js +98 -0
  48. package/dist/api/export-step.js.map +1 -0
  49. package/dist/api/export-stl.d.ts +8 -0
  50. package/dist/api/export-stl.d.ts.map +1 -1
  51. package/dist/api/export-stl.js +23 -8
  52. package/dist/api/export-stl.js.map +1 -1
  53. package/dist/api/feature-repair.d.ts +1 -1
  54. package/dist/api/feature-repair.d.ts.map +1 -1
  55. package/dist/api/feature-repair.js +1 -7
  56. package/dist/api/feature-repair.js.map +1 -1
  57. package/dist/api/fillet-variable.d.ts.map +1 -1
  58. package/dist/api/fillet-variable.js +0 -1
  59. package/dist/api/fillet-variable.js.map +1 -1
  60. package/dist/api/fillet.d.ts +3 -3
  61. package/dist/api/fillet.d.ts.map +1 -1
  62. package/dist/api/fillet.js +3 -4
  63. package/dist/api/fillet.js.map +1 -1
  64. package/dist/api/generated/operations.js +6 -6
  65. package/dist/api/generated/operations.js.map +1 -1
  66. package/dist/api/generated/script-face-manifest.d.ts +1 -1
  67. package/dist/api/generated/script-face-manifest.js +3 -3
  68. package/dist/api/generated/script-face-manifest.js.map +1 -1
  69. package/dist/api/generated/script-face.d.ts +1 -1
  70. package/dist/api/generated/script-face.js +1 -1
  71. package/dist/api/generated/script-face.js.map +1 -1
  72. package/dist/api/generated/sketching.js +1 -1
  73. package/dist/api/generated/sketching.js.map +1 -1
  74. package/dist/api/generated/topology.js +10 -10
  75. package/dist/api/generated/topology.js.map +1 -1
  76. package/dist/api/helix.d.ts +1 -1
  77. package/dist/api/helix.js +1 -1
  78. package/dist/api/helix.js.map +1 -1
  79. package/dist/api/index.d.ts +4 -1
  80. package/dist/api/index.d.ts.map +1 -1
  81. package/dist/api/index.js +16 -4
  82. package/dist/api/index.js.map +1 -1
  83. package/dist/api/internal/compat-op.d.ts +6 -6
  84. package/dist/api/internal/compat-op.d.ts.map +1 -1
  85. package/dist/api/internal/compat-op.js +7 -9
  86. package/dist/api/internal/compat-op.js.map +1 -1
  87. package/dist/api/internal/export-members.d.ts +80 -0
  88. package/dist/api/internal/export-members.d.ts.map +1 -0
  89. package/dist/api/internal/export-members.js +104 -0
  90. package/dist/api/internal/export-members.js.map +1 -0
  91. package/dist/api/internal/l3-bridge.d.ts +17 -0
  92. package/dist/api/internal/l3-bridge.d.ts.map +1 -1
  93. package/dist/api/internal/l3-bridge.js +23 -1
  94. package/dist/api/internal/l3-bridge.js.map +1 -1
  95. package/dist/api/measure-query/index.d.ts +262 -0
  96. package/dist/api/measure-query/index.d.ts.map +1 -0
  97. package/dist/api/measure-query/index.js +390 -0
  98. package/dist/api/measure-query/index.js.map +1 -0
  99. package/dist/api/pattern.d.ts.map +1 -1
  100. package/dist/api/pattern.js +0 -3
  101. package/dist/api/pattern.js.map +1 -1
  102. package/dist/api/primitives.d.ts +6 -6
  103. package/dist/api/primitives.d.ts.map +1 -1
  104. package/dist/api/primitives.js +12 -11
  105. package/dist/api/primitives.js.map +1 -1
  106. package/dist/api/profile.d.ts.map +1 -1
  107. package/dist/api/profile.js +0 -1
  108. package/dist/api/profile.js.map +1 -1
  109. package/dist/api/punch-hole.d.ts.map +1 -1
  110. package/dist/api/punch-hole.js +0 -1
  111. package/dist/api/punch-hole.js.map +1 -1
  112. package/dist/api/replicate.d.ts +5 -7
  113. package/dist/api/replicate.d.ts.map +1 -1
  114. package/dist/api/replicate.js +18 -56
  115. package/dist/api/replicate.js.map +1 -1
  116. package/dist/api/section-by-plane.d.ts.map +1 -1
  117. package/dist/api/section-by-plane.js +0 -1
  118. package/dist/api/section-by-plane.js.map +1 -1
  119. package/dist/api/shell.d.ts +1 -1
  120. package/dist/api/shell.d.ts.map +1 -1
  121. package/dist/api/shell.js +11 -2
  122. package/dist/api/shell.js.map +1 -1
  123. package/dist/api/sketch-on-face.d.ts +3 -3
  124. package/dist/api/sketch-on-face.d.ts.map +1 -1
  125. package/dist/api/sketch-on-face.js +6 -4
  126. package/dist/api/sketch-on-face.js.map +1 -1
  127. package/dist/api/sketch-on-plane.d.ts.map +1 -1
  128. package/dist/api/sketch-on-plane.js +0 -1
  129. package/dist/api/sketch-on-plane.js.map +1 -1
  130. package/dist/api/split-by-plane.d.ts.map +1 -1
  131. package/dist/api/split-by-plane.js +0 -1
  132. package/dist/api/split-by-plane.js.map +1 -1
  133. package/dist/api/split.d.ts +1 -1
  134. package/dist/api/split.js +1 -1
  135. package/dist/api/split.js.map +1 -1
  136. package/dist/api/surface/arg-spec.d.ts +3 -12
  137. package/dist/api/surface/arg-spec.d.ts.map +1 -1
  138. package/dist/api/surface/arg-spec.js +19 -26
  139. package/dist/api/surface/arg-spec.js.map +1 -1
  140. package/dist/api/sweep.d.ts +15 -3
  141. package/dist/api/sweep.d.ts.map +1 -1
  142. package/dist/api/sweep.js +5 -3
  143. package/dist/api/sweep.js.map +1 -1
  144. package/dist/api/thicken.d.ts.map +1 -1
  145. package/dist/api/thicken.js +11 -2
  146. package/dist/api/thicken.js.map +1 -1
  147. package/dist/api/transform.d.ts +3 -3
  148. package/dist/api/transform.d.ts.map +1 -1
  149. package/dist/api/transform.js +47 -17
  150. package/dist/api/transform.js.map +1 -1
  151. package/dist/boolean/index.d.ts +23 -0
  152. package/dist/boolean/index.d.ts.map +1 -0
  153. package/dist/boolean/index.js +27 -0
  154. package/dist/boolean/index.js.map +1 -0
  155. package/dist/brep/brep-chain.d.ts +1 -19
  156. package/dist/brep/brep-chain.d.ts.map +1 -1
  157. package/dist/brep/brep-chain.js +0 -1
  158. package/dist/brep/brep-chain.js.map +1 -1
  159. package/dist/brep/brep-ops.d.ts +4 -1
  160. package/dist/brep/brep-ops.d.ts.map +1 -1
  161. package/dist/brep/brep-ops.js +9 -5
  162. package/dist/brep/brep-ops.js.map +1 -1
  163. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  164. package/dist/brep/engine/adapters/brep-mock.js +0 -3
  165. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  166. package/dist/brep/engine/adapters/brepkit.d.ts +4 -3
  167. package/dist/brep/engine/adapters/brepkit.d.ts.map +1 -1
  168. package/dist/brep/engine/adapters/brepkit.js +4 -98
  169. package/dist/brep/engine/adapters/brepkit.js.map +1 -1
  170. package/dist/brep/engine/adapters/occt.d.ts.map +1 -1
  171. package/dist/brep/engine/adapters/occt.js +0 -144
  172. package/dist/brep/engine/adapters/occt.js.map +1 -1
  173. package/dist/brep/engine/native-history.d.ts +27 -0
  174. package/dist/brep/engine/native-history.d.ts.map +1 -0
  175. package/dist/brep/engine/native-history.js +54 -0
  176. package/dist/brep/engine/native-history.js.map +1 -0
  177. package/dist/brep/engine/registry.d.ts +2 -4
  178. package/dist/brep/engine/registry.d.ts.map +1 -1
  179. package/dist/brep/engine/registry.js +1 -1
  180. package/dist/brep/engine/registry.js.map +1 -1
  181. package/dist/brep/engine/types.d.ts +35 -77
  182. package/dist/brep/engine/types.d.ts.map +1 -1
  183. package/dist/brep/engine/types.js.map +1 -1
  184. package/dist/brep/export/export-model.d.ts +21 -0
  185. package/dist/brep/export/export-model.d.ts.map +1 -1
  186. package/dist/brep/export/export-model.js +171 -73
  187. package/dist/brep/export/export-model.js.map +1 -1
  188. package/dist/brep/export/step.d.ts +17 -1
  189. package/dist/brep/export/step.d.ts.map +1 -1
  190. package/dist/brep/export/step.js +133 -0
  191. package/dist/brep/export/step.js.map +1 -1
  192. package/dist/brep/export/stl.d.ts +22 -1
  193. package/dist/brep/export/stl.d.ts.map +1 -1
  194. package/dist/brep/export/stl.js +58 -10
  195. package/dist/brep/export/stl.js.map +1 -1
  196. package/dist/brep/export/transform12.d.ts +47 -0
  197. package/dist/brep/export/transform12.d.ts.map +1 -0
  198. package/dist/brep/export/transform12.js +87 -0
  199. package/dist/brep/export/transform12.js.map +1 -0
  200. package/dist/brep/face-evolution.d.ts +53 -0
  201. package/dist/brep/face-evolution.d.ts.map +1 -1
  202. package/dist/brep/face-evolution.js +65 -0
  203. package/dist/brep/face-evolution.js.map +1 -1
  204. package/dist/browser-host/index.d.ts +4 -1
  205. package/dist/browser-host/index.d.ts.map +1 -1
  206. package/dist/browser-host/index.js +7 -1
  207. package/dist/browser-host/index.js.map +1 -1
  208. package/dist/browser.d.ts +4 -8
  209. package/dist/browser.d.ts.map +1 -1
  210. package/dist/browser.js +4 -26
  211. package/dist/browser.js.map +1 -1
  212. package/dist/cad-runtime/backend-dispatch.d.ts +13 -58
  213. package/dist/cad-runtime/backend-dispatch.d.ts.map +1 -1
  214. package/dist/cad-runtime/backend-dispatch.js +22 -80
  215. package/dist/cad-runtime/backend-dispatch.js.map +1 -1
  216. package/dist/cad-runtime/content-key.d.ts +3 -3
  217. package/dist/cad-runtime/content-key.js +3 -3
  218. package/dist/cad-runtime/content-key.js.map +1 -1
  219. package/dist/cad-runtime/ports.d.ts +28 -0
  220. package/dist/cad-runtime/ports.d.ts.map +1 -1
  221. package/dist/cad-runtime/ports.js.map +1 -1
  222. package/dist/cad-runtime/runtime.d.ts +33 -12
  223. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  224. package/dist/cad-runtime/runtime.js +44 -48
  225. package/dist/cad-runtime/runtime.js.map +1 -1
  226. package/dist/define-op.d.ts +6 -11
  227. package/dist/define-op.d.ts.map +1 -1
  228. package/dist/define-op.js +3 -20
  229. package/dist/define-op.js.map +1 -1
  230. package/dist/env-agnostic.d.ts +2 -2
  231. package/dist/env-agnostic.d.ts.map +1 -1
  232. package/dist/env-agnostic.js +1 -1
  233. package/dist/env-agnostic.js.map +1 -1
  234. package/dist/index.d.ts +13 -64
  235. package/dist/index.d.ts.map +1 -1
  236. package/dist/index.js +17 -75
  237. package/dist/index.js.map +1 -1
  238. package/dist/lang/symbol-table.generated.d.ts +17 -0
  239. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  240. package/dist/lang/symbol-table.generated.js +17 -0
  241. package/dist/lang/symbol-table.generated.js.map +1 -1
  242. package/dist/mesh/index.d.ts +18 -23
  243. package/dist/mesh/index.d.ts.map +1 -1
  244. package/dist/mesh/index.js +18 -20
  245. package/dist/mesh/index.js.map +1 -1
  246. package/dist/mesh/io.d.ts +42 -14
  247. package/dist/mesh/io.d.ts.map +1 -1
  248. package/dist/mesh/io.js +77 -13
  249. package/dist/mesh/io.js.map +1 -1
  250. package/dist/mesh/threemf-loader.d.ts +38 -4
  251. package/dist/mesh/threemf-loader.d.ts.map +1 -1
  252. package/dist/mesh/threemf-loader.js +115 -34
  253. package/dist/mesh/threemf-loader.js.map +1 -1
  254. package/dist/mesh/types.d.ts +30 -0
  255. package/dist/mesh/types.d.ts.map +1 -1
  256. package/dist/mesh/types.js.map +1 -1
  257. package/dist/node-host/execute-script.d.ts +2 -1
  258. package/dist/node-host/execute-script.d.ts.map +1 -1
  259. package/dist/node-host/execute-script.js +5 -4
  260. package/dist/node-host/execute-script.js.map +1 -1
  261. package/dist/node-host/index.d.ts +1 -0
  262. package/dist/node-host/index.d.ts.map +1 -1
  263. package/dist/node-host/index.js +4 -0
  264. package/dist/node-host/index.js.map +1 -1
  265. package/dist/primitives/index.d.ts +19 -0
  266. package/dist/primitives/index.d.ts.map +1 -0
  267. package/dist/primitives/index.js +21 -0
  268. package/dist/primitives/index.js.map +1 -0
  269. package/dist/runtime-state.d.ts +63 -29
  270. package/dist/runtime-state.d.ts.map +1 -1
  271. package/dist/runtime-state.js +57 -0
  272. package/dist/runtime-state.js.map +1 -1
  273. package/dist/sdf/index.d.ts +12 -0
  274. package/dist/sdf/index.d.ts.map +1 -0
  275. package/dist/sdf/index.js +13 -0
  276. package/dist/sdf/index.js.map +1 -0
  277. package/dist/sdk.d.ts +0 -1
  278. package/dist/sdk.d.ts.map +1 -1
  279. package/dist/sdk.js.map +1 -1
  280. package/dist/weapp.d.ts +2 -2
  281. package/dist/weapp.d.ts.map +1 -1
  282. package/dist/weapp.js +1 -1
  283. package/dist/weapp.js.map +1 -1
  284. package/package.json +276 -35
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/api/curve-sketch/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api curve-sketch — 曲线与草图构造族(S4,平台 op engines:['occt'])\n *\n * @platform occt — 本目录 import occt-kernel:各 op 直调 occt 原生曲线构造/精修方法\n * (`makeEdge` / `makeCircleArc` / `makeEllipseEdge` / `makeEllipseArc` /\n * `makeTangentArc` / `approximatePoints` / `interpolatePointsWithTangents` /\n * `curveDegreeElevate` / `curveKnotInsert` / `curveKnotRemove` / `curveIsPeriodic`,\n * occt-wasm 原生有)。这些原生方法**不在** L1 契约 `BrepEngineApi` 里(L1 只有\n * `makeLineEdge` / `makeArcEdge` / `interpolatePoints` 等按几何构造的子集,见\n * brep/engine/primitives.ts)⇒ 全族平台 op:defineOp 声明 `engines: ['occt']`(D11)。\n *\n * 方案落点:docs/plans/2026-10-07-occt-wasm-op-enablement-plan.md §3.4.1。\n * 与既有 op 的边界(§4.5 去重表):`edge`(顶点对构造)≠ `makeLineEdge`(L1 点对构造,\n * 无脚本符号)≠ `wire`(多边组装);`approximatePoints`(逼近)与 L1 `interpolatePoints`\n * (插值)是数学对偶的两条路径;`interpolateWithTangents` 是带端点切向的插值。\n *\n * 角度约定(实测钉住,见 test/api/occt-s4-curve-sketch.test.ts):occt 原生\n * `makeCircleArc` / `makeEllipseArc` 的起止角走 `Geom_TrimmedCurve`(**弧度**,\n * 见 occt-wasm facade `Geom_TrimmedCurve(new Geom_Circle(circle), startAngle, endAngle)`);\n * 本仓契约「角度用度」(docs/api-contract.md)⇒ 脚本面收**度**、内部换算弧度。\n *\n * 产物形态(同 offset2d / helix):1D 曲线经 `fromBrepCurve` 登记为 `kind:'curve'`\n * (wire/edge 三角载荷为空,显示走 L1 `wireframe`)。\n *\n * `curveIsPeriodic` 返回布尔(非 Shape)⇒ 与 shape-type 族同口径:普通函数 +\n * `assertEngineFor('curveIsPeriodic', ['occt'])`(见 api/shape-type/index.ts 头注),\n * 覆盖率扫描器经 PLAN_C2_EXTRA 计入。\n */\n\nimport type { Shape } from '../../mesh/types'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport { solidToShape } from '../../brep/brep-ops'\nimport { getBrepApi } from '../../brep/handle-bridge'\nimport { brepOf, fromBrepCurve } from '../../shape'\nimport { defineOp } from '../../sdk'\nimport type { Provenance } from '../../topology/naming/lineage'\nimport { getOcctKernel } from '../../occt-kernel/occtKernel'\nimport { assertEngineFor } from '../internal/l3-bridge'\n\ntype Vec3 = [number, number, number]\n\n/** 度 → 弧度(脚本面按契约收度;occt Geom_TrimmedCurve 吃弧度)。 */\nconst DEG2RAD = Math.PI / 180\n\n/** 1D 曲线产物登记:内核句柄 → kind:'curve' 的 faijs Shape。 */\nfunction adoptCurve(handle: BrepHandle): Shape {\n return fromBrepCurve(solidToShape(getBrepApi(), handle), { solid: handle })\n}\n\n/** 元组 → {x,y,z}(同 halfSpace:occt 原生向量形参是 {x,y,z} 对象)。 */\nfunction toVec3(v: Vec3, op: string, which: string): { x: number; y: number; z: number } {\n if (\n !Array.isArray(v) ||\n v.length !== 3 ||\n v.some((n) => typeof n !== 'number' || !Number.isFinite(n))\n ) {\n throw new Error(`E_${op.toUpperCase()}_BAD_${which.toUpperCase()}: ${which} must be [x,y,z] finite numbers`)\n }\n return { x: v[0], y: v[1], z: v[2] }\n}\n\n/** 非零向量校验(方向/切向量)。 */\nfunction toNonZeroVec3(v: Vec3, op: string, which: string): { x: number; y: number; z: number } {\n const out = toVec3(v, op, which)\n if (out.x === 0 && out.y === 0 && out.z === 0) {\n throw new Error(`E_${op.toUpperCase()}_BAD_${which.toUpperCase()}: ${which} must be a non-zero vector`)\n }\n return out\n}\n\n/** 曲线输入 Shape → 内核句柄(无 BREP 槽报错)。 */\nfunction curveHandleOf(shape: Shape, op: string): BrepHandle {\n const h = brepOf(shape) as BrepHandle | undefined\n if (!h) {\n throw new Error(`E_${op.toUpperCase()}_NO_BREP: ${op} requires a BREP handle (mesh-only shape has none)`)\n }\n return h\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// edge — 顶点对构造边(occt 原生 makeEdge;顶点可来自 vertex Shape 或 [x,y,z])\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** 顶点入参:vertex Shape 或 [x,y,z] 点(内部经契约 makeVertex 物化)。 */\nfunction vertexHandleOf(v: Shape | Vec3, op: string): BrepHandle {\n if (Array.isArray(v)) {\n const p = toVec3(v, op, 'vertex')\n return getBrepApi().makeVertex(p.x, p.y, p.z) as unknown as BrepHandle\n }\n return curveHandleOf(v, op)\n}\n\n/** BREP 路径:顶点对 → occt 原生 makeEdge。 */\nfunction edgeBrep(v1: Shape | Vec3, v2: Shape | Vec3): Shape {\n if (v1 === undefined || v2 === undefined) {\n throw new Error('E_EDGE_MISSING_VERTEX: edge requires two vertices (vertex Shape or [x,y,z])')\n }\n const h1 = vertexHandleOf(v1, 'edge')\n const h2 = vertexHandleOf(v2, 'edge')\n const handle = getOcctKernel().makeEdge(h1 as never, h2 as never) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 两顶点构造边。顶点入参可以是 vertex Shape,也可以是 `[x,y,z]` 点\n * (点经 L1 契约 `makeVertex` 物化成顶点再配边)。\n * @group 创建\n * @inputs 2\n * @async false\n * @qual ok\n * @name edge\n * @note 平台 op:仅 occt 引擎(原生 makeEdge,L1 契约只有 makeLineEdge 等按几何构造)。\n * 非 occt 引擎执行前报错;brep_mock 不拦截。\n * @returns Shape 1D 直线边(kind:'curve')。\n * @param v1 - 第一个顶点(vertex Shape 或 [x,y,z])。type:Shape|Vec3 required:true\n * @param v2 - 第二个顶点(vertex Shape 或 [x,y,z])。type:Shape|Vec3 required:true\n * @example\n * const e = cad.edge([0,0,0], [10,0,0])\n */\nexport const edge = defineOp({\n name: 'edge',\n brep(v1: Shape | Vec3, v2: Shape | Vec3) {\n return edgeBrep(v1, v2)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D edge has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// circleArc — 圆心+法向+半径+起止角(度)构造圆弧\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** BREP 路径:occt 原生 makeCircleArc(角度内部换算弧度)。 */\nfunction circleArcBrep(\n center: Vec3,\n normal: Vec3,\n radius: number,\n startAngleDeg: number,\n endAngleDeg: number,\n): Shape {\n if (typeof radius !== 'number' || !(radius > 0)) {\n throw new Error('E_CIRCLEARC_BAD_RADIUS: radius must be a positive number')\n }\n if (\n typeof startAngleDeg !== 'number' || !Number.isFinite(startAngleDeg) ||\n typeof endAngleDeg !== 'number' || !Number.isFinite(endAngleDeg)\n ) {\n throw new Error('E_CIRCLEARC_BAD_ANGLE: startAngle/endAngle must be finite numbers (degrees)')\n }\n const c = toVec3(center, 'circleArc', 'center')\n const n = toNonZeroVec3(normal, 'circleArc', 'normal')\n const handle = getOcctKernel().makeCircleArc(\n c as never, n as never, radius, startAngleDeg * DEG2RAD, endAngleDeg * DEG2RAD,\n ) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 构造圆弧:圆心 + 法向 + 半径 + 起止角(度,绕法向右手逆时针)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name circleArc\n * @note 平台 op:仅 occt 引擎(原生 makeCircleArc)。角度单位是**度**(内部换算弧度\n * 传给 occt 的 Geom_TrimmedCurve)。\n * @returns Shape 1D 圆弧(kind:'curve')。\n * @param center - 圆心 [x,y,z]。type:Vec3 required:true\n * @param normal - 圆面法向 [x,y,z](非零)。type:Vec3 required:true\n * @param radius - 半径(mm,>0)。type:number required:true\n * @param startAngle - 起始角(度,自法向基准 X 方向起量)。type:number required:true\n * @param endAngle - 终止角(度)。type:number required:true\n * @example\n * const a = cad.circleArc([0,0,0], [0,0,1], 5, 0, 90)\n */\nexport const circleArc = defineOp({\n name: 'circleArc',\n paramDims: { center: 'length', normal: 'length', radius: 'length', startAngle: 'angle', endAngle: 'angle' },\n brep(center: Vec3, normal: Vec3, radius: number, startAngleDeg: number, endAngleDeg: number) {\n return circleArcBrep(center, normal, radius, startAngleDeg, endAngleDeg)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D arc has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ellipseEdge / ellipseArc — 椭圆整边 / 椭圆弧\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** 椭圆公共参数校验:两半径均正,且 major > minor(gp_Elips 约束)。 */\nfunction checkEllipseRadii(op: string, majorRadius: number, minorRadius: number): void {\n if (typeof majorRadius !== 'number' || !(majorRadius > 0)) {\n throw new Error(`E_${op.toUpperCase()}_BAD_MAJOR: majorRadius must be a positive number`)\n }\n if (typeof minorRadius !== 'number' || !(minorRadius > 0)) {\n throw new Error(`E_${op.toUpperCase()}_BAD_MINOR: minorRadius must be a positive number`)\n }\n if (minorRadius > majorRadius) {\n throw new Error(`E_${op.toUpperCase()}_BAD_RADII: minorRadius must be <= majorRadius (gp_Elips constraint)`)\n }\n}\n\n/** BREP 路径:occt 原生 makeEllipseEdge。 */\nfunction ellipseEdgeBrep(center: Vec3, normal: Vec3, majorRadius: number, minorRadius: number): Shape {\n checkEllipseRadii('ELLIPSEEDGE', majorRadius, minorRadius)\n const c = toVec3(center, 'ellipseEdge', 'center')\n const n = toNonZeroVec3(normal, 'ellipseEdge', 'normal')\n const handle = getOcctKernel().makeEllipseEdge(c as never, n as never, majorRadius, minorRadius) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 构造整椭圆边:中心 + 法向 + 长半轴 + 短半轴。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name ellipseEdge\n * @note 平台 op:仅 occt 引擎(原生 makeEllipseEdge)。要求 majorRadius >= minorRadius。\n * @returns Shape 1D 椭圆边(kind:'curve')。\n * @param center - 椭圆中心 [x,y,z]。type:Vec3 required:true\n * @param normal - 椭圆面法向 [x,y,z](非零)。type:Vec3 required:true\n * @param majorRadius - 长半轴(mm,>0)。type:number required:true\n * @param minorRadius - 短半轴(mm,>0 且 <= 长半轴)。type:number required:true\n * @example\n * const e = cad.ellipseEdge([0,0,0], [0,0,1], 10, 5)\n */\nexport const ellipseEdge = defineOp({\n name: 'ellipseEdge',\n paramDims: { center: 'length', normal: 'length', majorRadius: 'length', minorRadius: 'length' },\n brep(center: Vec3, normal: Vec3, majorRadius: number, minorRadius: number) {\n return ellipseEdgeBrep(center, normal, majorRadius, minorRadius)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D ellipse has no face role vocabulary' } as Provenance,\n})\n\n/** BREP 路径:occt 原生 makeEllipseArc(角度内部换算弧度)。 */\nfunction ellipseArcBrep(\n center: Vec3,\n normal: Vec3,\n majorRadius: number,\n minorRadius: number,\n startAngleDeg: number,\n endAngleDeg: number,\n): Shape {\n checkEllipseRadii('ELLIPSEARC', majorRadius, minorRadius)\n if (\n typeof startAngleDeg !== 'number' || !Number.isFinite(startAngleDeg) ||\n typeof endAngleDeg !== 'number' || !Number.isFinite(endAngleDeg)\n ) {\n throw new Error('E_ELLIPSEARC_BAD_ANGLE: startAngle/endAngle must be finite numbers (degrees)')\n }\n const c = toVec3(center, 'ellipseArc', 'center')\n const n = toNonZeroVec3(normal, 'ellipseArc', 'normal')\n const handle = getOcctKernel().makeEllipseArc(\n c as never, n as never, majorRadius, minorRadius, startAngleDeg * DEG2RAD, endAngleDeg * DEG2RAD,\n ) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 构造椭圆弧:中心 + 法向 + 长短半轴 + 起止角(度)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name ellipseArc\n * @note 平台 op:仅 occt 引擎(原生 makeEllipseArc)。角度单位是**度**(内部换算弧度)。\n * @returns Shape 1D 椭圆弧(kind:'curve')。\n * @param center - 椭圆中心 [x,y,z]。type:Vec3 required:true\n * @param normal - 椭圆面法向 [x,y,z](非零)。type:Vec3 required:true\n * @param majorRadius - 长半轴(mm,>0)。type:number required:true\n * @param minorRadius - 短半轴(mm,>0 且 <= 长半轴)。type:number required:true\n * @param startAngle - 起始角(度)。type:number required:true\n * @param endAngle - 终止角(度)。type:number required:true\n * @example\n * const a = cad.ellipseArc([0,0,0], [0,0,1], 10, 5, 0, 90)\n */\nexport const ellipseArc = defineOp({\n name: 'ellipseArc',\n paramDims: { center: 'length', normal: 'length', majorRadius: 'length', minorRadius: 'length', startAngle: 'angle', endAngle: 'angle' },\n brep(center: Vec3, normal: Vec3, majorRadius: number, minorRadius: number, startAngleDeg: number, endAngleDeg: number) {\n return ellipseArcBrep(center, normal, majorRadius, minorRadius, startAngleDeg, endAngleDeg)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D ellipse arc has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// tangentArc — 起点+切向+终点构造圆弧\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** BREP 路径:occt 原生 makeTangentArc(GC_MakeArcOfCircle(start, tangent, end))。 */\nfunction tangentArcBrep(start: Vec3, tangent: Vec3, end: Vec3): Shape {\n const s = toVec3(start, 'tangentArc', 'start')\n const t = toNonZeroVec3(tangent, 'tangentArc', 'tangent')\n const e = toVec3(end, 'tangentArc', 'end')\n const handle = getOcctKernel().makeTangentArc(s as never, t as never, e as never) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 构造圆弧:过起点、以给定切向出发、终于终点(GC_MakeArcOfCircle 语义)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name tangentArc\n * @note 平台 op:仅 occt 引擎(原生 makeTangentArc)。切向为零向量非法。\n * @returns Shape 1D 圆弧(kind:'curve')。\n * @param start - 起点 [x,y,z]。type:Vec3 required:true\n * @param tangent - 起点切向 [x,y,z](非零,不必单位化)。type:Vec3 required:true\n * @param end - 终点 [x,y,z]。type:Vec3 required:true\n * @example\n * const a = cad.tangentArc([0,0,0], [1,0,0], [5,5,0])\n */\nexport const tangentArc = defineOp({\n name: 'tangentArc',\n paramDims: { start: 'length', tangent: 'length', end: 'length' },\n brep(start: Vec3, tangent: Vec3, end: Vec3) {\n return tangentArcBrep(start, tangent, end)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D arc has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// approximatePoints — 点集逼近(与 L1 interpolatePoints 的插值成对)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** 点集校验(≥2 点)。 */\nfunction checkPoints(op: string, points: Vec3[]): void {\n if (!Array.isArray(points) || points.length < 2) {\n throw new Error(`E_${op.toUpperCase()}_BAD_POINTS: ${op} requires at least 2 points`)\n }\n for (const p of points) toVec3(p, op, 'point')\n}\n\n/** BREP 路径:occt 原生 approximatePoints(逼近曲线;tolerance 缺省 = 原生 1e-3)。 */\nfunction approximatePointsBrep(points: Vec3[], tolerance?: number): Shape {\n checkPoints('APPROXIMATEPOINTS', points)\n if (tolerance !== undefined && (typeof tolerance !== 'number' || !(tolerance > 0))) {\n throw new Error('E_APPROXIMATEPOINTS_BAD_TOLERANCE: tolerance must be a positive number')\n }\n const handle = (\n tolerance === undefined\n ? getOcctKernel().approximatePoints(points as never)\n : getOcctKernel().approximatePoints(points as never, tolerance)\n ) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 点集**逼近**曲线:过点但不严格插值(逼近容差内贴合,产平滑 B 样条)。\n * 与 L1 `interpolatePoints`(严格插值)成对的数学对偶路径。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name approximatePoints\n * @note 平台 op:仅 occt 引擎(原生 approximatePoints,tolerance 缺省 1e-3)。\n * @returns Shape 1D 逼近曲线(kind:'curve')。\n * @param points - 点集 [x,y,z][](≥2 点)。type:Vec3[] required:true\n * @param tolerance - 逼近容差(mm,默认 1e-3)。type:number required:false\n * @example\n * const c = cad.approximatePoints([[0,0,0],[5,3,0],[10,0,0]])\n */\nexport const approximatePoints = defineOp({\n name: 'approximatePoints',\n paramDims: { points: 'length', tolerance: 'length' },\n brep(points: Vec3[], tolerance?: number) {\n return approximatePointsBrep(points, tolerance)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D approximated curve has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// interpolateWithTangents — 带端点切向的插值\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** BREP 路径:occt 原生 interpolatePointsWithTangents。 */\nfunction interpolateWithTangentsBrep(points: Vec3[], startTangent: Vec3, endTangent: Vec3): Shape {\n checkPoints('INTERPOLATEWITHTANGENTS', points)\n const st = toNonZeroVec3(startTangent, 'interpolateWithTangents', 'startTangent')\n const et = toNonZeroVec3(endTangent, 'interpolateWithTangents', 'endTangent')\n const handle = getOcctKernel().interpolatePointsWithTangents(\n points as never, st as never, et as never,\n ) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 点集**插值**曲线,带端点切向约束(三次 B 样条,过全部点且端点切向指定)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name interpolateWithTangents\n * @note 平台 op:仅 occt 引擎(原生 interpolatePointsWithTangents)。两端切向非零。\n * @returns Shape 1D 插值曲线(kind:'curve')。\n * @param points - 点集 [x,y,z][](≥2 点)。type:Vec3[] required:true\n * @param startTangent - 起点切向 [x,y,z](非零)。type:Vec3 required:true\n * @param endTangent - 终点切向 [x,y,z](非零)。type:Vec3 required:true\n * @example\n * const c = cad.interpolateWithTangents([[0,0,0],[5,3,0],[10,0,0]], [1,0,0], [1,0,0])\n */\nexport const interpolateWithTangents = defineOp({\n name: 'interpolateWithTangents',\n paramDims: { points: 'length', startTangent: 'length', endTangent: 'length' },\n brep(points: Vec3[], startTangent: Vec3, endTangent: Vec3) {\n return interpolateWithTangentsBrep(points, startTangent, endTangent)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D interpolated curve has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// NURBS 精修族 — curveDegreeElevate / curveKnotInsert / curveKnotRemove\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** BREP 路径:occt 原生 curveDegreeElevate(NURBS 升阶)。 */\nfunction curveDegreeElevateBrep(curve: Shape, elevateBy: number): Shape {\n if (!Number.isInteger(elevateBy) || elevateBy <= 0) {\n throw new Error('E_CURVEDEGREEELEVATE_BAD_STEP: elevateBy must be a positive integer')\n }\n const h = curveHandleOf(curve, 'curveDegreeElevate')\n const handle = getOcctKernel().curveDegreeElevate(h as never, elevateBy) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * NURBS 曲线升阶:把边/曲线的阶数提升 `elevateBy`(几何不变,表示空间变大)。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name curveDegreeElevate\n * @note 平台 op:仅 occt 引擎(原生 curveDegreeElevate)。输入边/曲线。\n * @returns Shape 升阶后的 1D 曲线(kind:'curve')。\n * @param curve - 输入边/曲线。type:Shape required:true\n * @param elevateBy - 升阶量(正整数)。type:number required:true\n * @example\n * const up = cad.curveDegreeElevate(e, 2)\n */\nexport const curveDegreeElevate = defineOp({\n name: 'curveDegreeElevate',\n brep(curve: Shape, elevateBy: number) {\n return curveDegreeElevateBrep(curve, elevateBy)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D refined curve has no face role vocabulary' } as Provenance,\n})\n\n/** BREP 路径:occt 原生 curveKnotInsert(插节点 times 次)。 */\nfunction curveKnotInsertBrep(curve: Shape, knot: number, times: number): Shape {\n if (typeof knot !== 'number' || !Number.isFinite(knot)) {\n throw new Error('E_CURVEKNOTINSERT_BAD_KNOT: knot must be a finite number (curve parameter)')\n }\n if (!Number.isInteger(times) || times <= 0) {\n throw new Error('E_CURVEKNOTINSERT_BAD_TIMES: times must be a positive integer')\n }\n const h = curveHandleOf(curve, 'curveKnotInsert')\n const handle = getOcctKernel().curveKnotInsert(h as never, knot, times) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * NURBS 曲线插节点:在曲线参数 `knot` 处插入节点 `times` 次(几何不变)。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name curveKnotInsert\n * @note 平台 op:仅 occt 引擎(原生 curveKnotInsert)。knot 是曲线参数(不是长度)。\n * @returns Shape 插节点后的 1D 曲线(kind:'curve')。\n * @param curve - 输入边/曲线。type:Shape required:true\n * @param knot - 目标节点参数。type:number required:true\n * @param times - 重复次数(正整数)。type:number required:true\n * @example\n * const refined = cad.curveKnotInsert(e, 0.5, 1)\n */\nexport const curveKnotInsert = defineOp({\n name: 'curveKnotInsert',\n brep(curve: Shape, knot: number, times: number) {\n return curveKnotInsertBrep(curve, knot, times)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D refined curve has no face role vocabulary' } as Provenance,\n})\n\n/** BREP 路径:occt 原生 curveKnotRemove(容差内去节点)。 */\nfunction curveKnotRemoveBrep(curve: Shape, knot: number, tolerance: number): Shape {\n if (typeof knot !== 'number' || !Number.isFinite(knot)) {\n throw new Error('E_CURVEKNOTREMOVE_BAD_KNOT: knot must be a finite number (curve parameter)')\n }\n if (typeof tolerance !== 'number' || !(tolerance > 0)) {\n throw new Error('E_CURVEKNOTREMOVE_BAD_TOLERANCE: tolerance must be a positive number')\n }\n const h = curveHandleOf(curve, 'curveKnotRemove')\n const handle = getOcctKernel().curveKnotRemove(h as never, knot, tolerance) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * NURBS 曲线去节点:在容差内移除参数 `knot` 处的节点(几何漂移不超过 tolerance)。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name curveKnotRemove\n * @note 平台 op:仅 occt 引擎(原生 curveKnotRemove)。knot 是曲线参数(不是长度)。\n * @returns Shape 去节点后的 1D 曲线(kind:'curve')。\n * @param curve - 输入边/曲线。type:Shape required:true\n * @param knot - 目标节点参数。type:number required:true\n * @param tolerance - 允许的几何漂移(mm,>0)。type:number required:true\n * @example\n * const lean = cad.curveKnotRemove(e, 0.5, 1e-4)\n */\nexport const curveKnotRemove = defineOp({\n name: 'curveKnotRemove',\n paramDims: { tolerance: 'length' },\n brep(curve: Shape, knot: number, tolerance: number) {\n return curveKnotRemoveBrep(curve, knot, tolerance)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D refined curve has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// curveIsPeriodic — 周期性查询(返回布尔 ⇒ 普通函数形态,同 shape-type 族口径)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * 曲线是否周期(L1 契约只有 `curveIsClosed`,周期性是 occt 原生独有查询)。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name curveIsPeriodic\n * @note 平台 op:仅 occt 引擎(原生 curveIsPeriodic,L1 无对应成员)。非 occt 引擎\n * 执行前报 E_BREP_UNSUPPORTED。\n * @returns boolean 是否为周期曲线。\n * @param curve - 被查询的边/曲线。type:Shape required:true\n * @example\n * const c = cad.circleArc([0,0,0], [0,0,1], 5, 0, 360)\n * const periodic = cad.curveIsPeriodic(c)\n */\nexport function curveIsPeriodic(curve: Shape): boolean {\n assertEngineFor('curveIsPeriodic', ['occt'])\n const h = curveHandleOf(curve, 'curveIsPeriodic')\n const kernel = getOcctKernel() as unknown as { curveIsPeriodic(h: unknown): boolean }\n return kernel.curveIsPeriodic(h)\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/api/curve-sketch/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAIvD,mDAAmD;AACnD,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,GAAG,GAAG,CAAA;AAE7B,mDAAmD;AACnD,SAAS,UAAU,CAAC,MAAkB;IACpC,OAAO,aAAa,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;AAC7E,CAAC;AAED,yDAAyD;AACzD,SAAS,MAAM,CAAC,CAAO,EAAE,EAAU,EAAE,KAAa;IAChD,IACE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACjB,CAAC,CAAC,MAAM,KAAK,CAAC;QACd,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAC3D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,QAAQ,KAAK,CAAC,WAAW,EAAE,KAAK,KAAK,iCAAiC,CAAC,CAAA;IAC9G,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AACtC,CAAC;AAED,sBAAsB;AACtB,SAAS,aAAa,CAAC,CAAO,EAAE,EAAU,EAAE,KAAa;IACvD,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,CAAA;IAChC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,QAAQ,KAAK,CAAC,WAAW,EAAE,KAAK,KAAK,4BAA4B,CAAC,CAAA;IACzG,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,qCAAqC;AACrC,SAAS,aAAa,CAAC,KAAY,EAAE,EAAU;IAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAA2B,CAAA;IACjD,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,oDAAoD,CAAC,CAAA;IAC3G,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC;AAED,gFAAgF;AAChF,+DAA+D;AAC/D,gFAAgF;AAEhF,0DAA0D;AAC1D,SAAS,cAAc,CAAC,CAAe,EAAE,EAAU;IACjD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAA;QACjC,OAAO,UAAU,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAA0B,CAAA;IACxE,CAAC;IACD,OAAO,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAC7B,CAAC;AAED,sCAAsC;AACtC,SAAS,QAAQ,CAAC,EAAgB,EAAE,EAAgB;IAClD,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAA;IAChG,CAAC;IACD,MAAM,EAAE,GAAG,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IACrC,MAAM,EAAE,GAAG,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IACrC,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC,QAAQ,CAAC,EAAW,EAAE,EAAW,CAA0B,CAAA;IAC1F,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,QAAQ,CAAC;IAC3B,IAAI,EAAE,MAAM;IACZ,IAAI,CAAC,EAAgB,EAAE,EAAgB;QACrC,OAAO,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;IACzB,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,qCAAqC,EAAgB;CAC3F,CAAC,CAAA;AAEF,gFAAgF;AAChF,kCAAkC;AAClC,gFAAgF;AAEhF,+CAA+C;AAC/C,SAAS,aAAa,CACpB,MAAY,EACZ,MAAY,EACZ,MAAc,EACd,aAAqB,EACrB,WAAmB;IAEnB,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAA;IAC7E,CAAC;IACD,IACE,OAAO,aAAa,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC;QACpE,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAChE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAA;IAChG,CAAC;IACD,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAA;IAC/C,MAAM,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAA;IACtD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC,aAAa,CAC1C,CAAU,EAAE,CAAU,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,EAAE,WAAW,GAAG,OAAO,CACtD,CAAA;IAC1B,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,QAAQ,CAAC;IAChC,IAAI,EAAE,WAAW;IACjB,SAAS,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE;IAC3G,IAAI,CAAC,MAAY,EAAE,MAAY,EAAE,MAAc,EAAE,aAAqB,EAAE,WAAmB;QACzF,OAAO,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,CAAC,CAAA;IAC1E,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,oCAAoC,EAAgB;CAC1F,CAAC,CAAA;AAEF,gFAAgF;AAChF,wCAAwC;AACxC,gFAAgF;AAEhF,mDAAmD;AACnD,SAAS,iBAAiB,CAAC,EAAU,EAAE,WAAmB,EAAE,WAAmB;IAC7E,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,mDAAmD,CAAC,CAAA;IAC3F,CAAC;IACD,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,mDAAmD,CAAC,CAAA;IAC3F,CAAC;IACD,IAAI,WAAW,GAAG,WAAW,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,sEAAsE,CAAC,CAAA;IAC9G,CAAC;AACH,CAAC;AAED,uCAAuC;AACvC,SAAS,eAAe,CAAC,MAAY,EAAE,MAAY,EAAE,WAAmB,EAAE,WAAmB;IAC3F,iBAAiB,CAAC,aAAa,EAAE,WAAW,EAAE,WAAW,CAAC,CAAA;IAC1D,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAA;IACjD,MAAM,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAA;IACxD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC,eAAe,CAAC,CAAU,EAAE,CAAU,EAAE,WAAW,EAAE,WAAW,CAA0B,CAAA;IACzH,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC;IAClC,IAAI,EAAE,aAAa;IACnB,SAAS,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE;IAC/F,IAAI,CAAC,MAAY,EAAE,MAAY,EAAE,WAAmB,EAAE,WAAmB;QACvE,OAAO,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,CAAA;IAClE,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,wCAAwC,EAAgB;CAC9F,CAAC,CAAA;AAEF,gDAAgD;AAChD,SAAS,cAAc,CACrB,MAAY,EACZ,MAAY,EACZ,WAAmB,EACnB,WAAmB,EACnB,aAAqB,EACrB,WAAmB;IAEnB,iBAAiB,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,CAAC,CAAA;IACzD,IACE,OAAO,aAAa,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC;QACpE,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAChE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAA;IACjG,CAAC;IACD,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAA;IAChD,MAAM,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAA;IACvD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC,cAAc,CAC3C,CAAU,EAAE,CAAU,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,GAAG,OAAO,EAAE,WAAW,GAAG,OAAO,CACxE,CAAA;IAC1B,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC;IACjC,IAAI,EAAE,YAAY;IAClB,SAAS,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE;IACvI,IAAI,CAAC,MAAY,EAAE,MAAY,EAAE,WAAmB,EAAE,WAAmB,EAAE,aAAqB,EAAE,WAAmB;QACnH,OAAO,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,CAAC,CAAA;IAC7F,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,4CAA4C,EAAgB;CAClG,CAAC,CAAA;AAEF,gFAAgF;AAChF,4BAA4B;AAC5B,gFAAgF;AAEhF,+EAA+E;AAC/E,SAAS,cAAc,CAAC,KAAW,EAAE,OAAa,EAAE,GAAS;IAC3D,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,CAAA;IAC9C,MAAM,CAAC,GAAG,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,CAAC,CAAA;IACzD,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC,cAAc,CAAC,CAAU,EAAE,CAAU,EAAE,CAAU,CAA0B,CAAA;IAC1G,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC;IACjC,IAAI,EAAE,YAAY;IAClB,SAAS,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE;IAChE,IAAI,CAAC,KAAW,EAAE,OAAa,EAAE,GAAS;QACxC,OAAO,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IAC5C,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,oCAAoC,EAAgB;CAC1F,CAAC,CAAA;AAEF,gFAAgF;AAChF,yDAAyD;AACzD,gFAAgF;AAEhF,kBAAkB;AAClB,SAAS,WAAW,CAAC,EAAU,EAAE,MAAc;IAC7C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,6BAA6B,CAAC,CAAA;IACvF,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,MAAM;QAAE,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AAChD,CAAC;AAED,+DAA+D;AAC/D,SAAS,WAAW,CAAC,EAAU,EAAE,MAAc;IAC7C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,sEAAsE;AACtE,SAAS,qBAAqB,CAAC,MAAc,EAAE,SAAkB;IAC/D,WAAW,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAA;IACxC,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACnF,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAA;IAC3F,CAAC;IACD,MAAM,GAAG,GAAG,WAAW,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAA;IACpD,MAAM,MAAM,GAAG,CACb,SAAS,KAAK,SAAS;QACrB,CAAC,CAAC,aAAa,EAAE,CAAC,iBAAiB,CAAC,GAAY,CAAC;QACjD,CAAC,CAAC,aAAa,EAAE,CAAC,iBAAiB,CAAC,GAAY,EAAE,SAAS,CAAC,CACtC,CAAA;IAC1B,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACxC,IAAI,EAAE,mBAAmB;IACzB,SAAS,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE;IACpD,IAAI,CAAC,MAAc,EAAE,SAAkB;QACrC,OAAO,qBAAqB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IACjD,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,mDAAmD,EAAgB;CACzG,CAAC,CAAA;AAEF,gFAAgF;AAChF,qCAAqC;AACrC,gFAAgF;AAEhF,qDAAqD;AACrD,SAAS,2BAA2B,CAAC,MAAc,EAAE,YAAkB,EAAE,UAAgB;IACvF,WAAW,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAA;IAC9C,MAAM,EAAE,GAAG,aAAa,CAAC,YAAY,EAAE,yBAAyB,EAAE,cAAc,CAAC,CAAA;IACjF,MAAM,EAAE,GAAG,aAAa,CAAC,UAAU,EAAE,yBAAyB,EAAE,YAAY,CAAC,CAAA;IAC7E,MAAM,GAAG,GAAG,WAAW,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAA;IAC1D,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC,6BAA6B,CAC1D,GAAY,EAAE,EAAW,EAAE,EAAW,CACd,CAAA;IAC1B,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC9C,IAAI,EAAE,yBAAyB;IAC/B,SAAS,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE;IAC7E,IAAI,CAAC,MAAc,EAAE,YAAkB,EAAE,UAAgB;QACvD,OAAO,2BAA2B,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,CAAC,CAAA;IACtE,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,mDAAmD,EAAgB;CACzG,CAAC,CAAA;AAEF,gFAAgF;AAChF,qEAAqE;AACrE,gFAAgF;AAEhF,oDAAoD;AACpD,SAAS,sBAAsB,CAAC,KAAY,EAAE,SAAiB;IAC7D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAA;IACxF,CAAC;IACD,MAAM,CAAC,GAAG,aAAa,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAA;IACpD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC,kBAAkB,CAAC,CAAU,EAAE,SAAS,CAA0B,CAAA;IACjG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACzC,IAAI,EAAE,oBAAoB;IAC1B,IAAI,CAAC,KAAY,EAAE,SAAiB;QAClC,OAAO,sBAAsB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IACjD,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,8CAA8C,EAAgB;CACpG,CAAC,CAAA;AAEF,oDAAoD;AACpD,SAAS,mBAAmB,CAAC,KAAY,EAAE,IAAY,EAAE,KAAa;IACpE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAA;IAC/F,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAA;IAClF,CAAC;IACD,MAAM,CAAC,GAAG,aAAa,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAA;IACjD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC,eAAe,CAAC,CAAU,EAAE,IAAI,EAAE,KAAK,CAA0B,CAAA;IAChG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;IACtC,IAAI,EAAE,iBAAiB;IACvB,IAAI,CAAC,KAAY,EAAE,IAAY,EAAE,KAAa;QAC5C,OAAO,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;IAChD,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,8CAA8C,EAAgB;CACpG,CAAC,CAAA;AAEF,+CAA+C;AAC/C,SAAS,mBAAmB,CAAC,KAAY,EAAE,IAAY,EAAE,SAAiB;IACxE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAA;IAC/F,CAAC;IACD,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAA;IACzF,CAAC;IACD,MAAM,CAAC,GAAG,aAAa,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAA;IACjD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC,eAAe,CAAC,CAAU,EAAE,IAAI,EAAE,SAAS,CAA0B,CAAA;IACpG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;IACtC,IAAI,EAAE,iBAAiB;IACvB,SAAS,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;IAClC,IAAI,CAAC,KAAY,EAAE,IAAY,EAAE,SAAiB;QAChD,OAAO,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;IACpD,CAAC;IACD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,8CAA8C,EAAgB;CACpG,CAAC,CAAA;AAEF,gFAAgF;AAChF,0DAA0D;AAC1D,gFAAgF;AAEhF;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAAC,KAAY;IAC1C,eAAe,CAAC,iBAAiB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAC5C,MAAM,CAAC,GAAG,aAAa,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAA;IACjD,MAAM,MAAM,GAAG,aAAa,EAAyD,CAAA;IACrF,OAAO,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;AAClC,CAAC","sourcesContent":["/**\n * api curve-sketch — 曲线与草图构造族(S4,平台 op engines:['occt'])\n *\n * @platform occt — 本目录 import occt-kernel:各 op 直调 occt 原生曲线构造/精修方法\n * (`makeEdge` / `makeCircleArc` / `makeEllipseEdge` / `makeEllipseArc` /\n * `makeTangentArc` / `approximatePoints` / `interpolatePointsWithTangents` /\n * `curveDegreeElevate` / `curveKnotInsert` / `curveKnotRemove` / `curveIsPeriodic`,\n * occt-wasm 原生有)。这些原生方法**不在** L1 契约 `BrepEngineApi` 里(L1 只有\n * `makeLineEdge` / `makeArcEdge` / `interpolatePoints` 等按几何构造的子集,见\n * brep/engine/primitives.ts)⇒ 全族平台 op:defineOp 声明 `engines: ['occt']`(D11)。\n *\n * 方案落点:docs/plans/2026-10-07-occt-wasm-op-enablement-plan.md §3.4.1。\n * 与既有 op 的边界(§4.5 去重表):`edge`(顶点对构造)≠ `makeLineEdge`(L1 点对构造,\n * 无脚本符号)≠ `wire`(多边组装);`approximatePoints`(逼近)与 L1 `interpolatePoints`\n * (插值)是数学对偶的两条路径;`interpolateWithTangents` 是带端点切向的插值。\n *\n * 角度约定(实测钉住,见 test/api/occt-s4-curve-sketch.test.ts):occt 原生\n * `makeCircleArc` / `makeEllipseArc` 的起止角走 `Geom_TrimmedCurve`(**弧度**,\n * 见 occt-wasm facade `Geom_TrimmedCurve(new Geom_Circle(circle), startAngle, endAngle)`);\n * 本仓契约「角度用度」(docs/api-contract.md)⇒ 脚本面收**度**、内部换算弧度。\n *\n * 产物形态(同 offset2d / helix):1D 曲线经 `fromBrepCurve` 登记为 `kind:'curve'`\n * (wire/edge 三角载荷为空,显示走 L1 `wireframe`)。\n *\n * `curveIsPeriodic` 返回布尔(非 Shape)⇒ 与 shape-type 族同口径:普通函数 +\n * `assertEngineFor('curveIsPeriodic', ['occt'])`(见 api/shape-type/index.ts 头注),\n * 覆盖率扫描器经 PLAN_C2_EXTRA 计入。\n */\n\nimport type { Shape } from '../../mesh/types'\nimport type { BrepHandle } from '../../brep/engine/types'\nimport { solidToShape } from '../../brep/brep-ops'\nimport { getBrepApi } from '../../brep/handle-bridge'\nimport { brepOf, fromBrepCurve } from '../../shape'\nimport { defineOp } from '../../sdk'\nimport type { Provenance } from '../../topology/naming/lineage'\nimport { getOcctKernel } from '../../occt-kernel/occtKernel'\nimport { assertEngineFor } from '../internal/l3-bridge'\n\ntype Vec3 = [number, number, number]\n\n/** 度 → 弧度(脚本面按契约收度;occt Geom_TrimmedCurve 吃弧度)。 */\nconst DEG2RAD = Math.PI / 180\n\n/** 1D 曲线产物登记:内核句柄 → kind:'curve' 的 faijs Shape。 */\nfunction adoptCurve(handle: BrepHandle): Shape {\n return fromBrepCurve(solidToShape(getBrepApi(), handle), { solid: handle })\n}\n\n/** 元组 → {x,y,z}(同 halfSpace:occt 原生向量形参是 {x,y,z} 对象)。 */\nfunction toVec3(v: Vec3, op: string, which: string): { x: number; y: number; z: number } {\n if (\n !Array.isArray(v) ||\n v.length !== 3 ||\n v.some((n) => typeof n !== 'number' || !Number.isFinite(n))\n ) {\n throw new Error(`E_${op.toUpperCase()}_BAD_${which.toUpperCase()}: ${which} must be [x,y,z] finite numbers`)\n }\n return { x: v[0], y: v[1], z: v[2] }\n}\n\n/** 非零向量校验(方向/切向量)。 */\nfunction toNonZeroVec3(v: Vec3, op: string, which: string): { x: number; y: number; z: number } {\n const out = toVec3(v, op, which)\n if (out.x === 0 && out.y === 0 && out.z === 0) {\n throw new Error(`E_${op.toUpperCase()}_BAD_${which.toUpperCase()}: ${which} must be a non-zero vector`)\n }\n return out\n}\n\n/** 曲线输入 Shape → 内核句柄(无 BREP 槽报错)。 */\nfunction curveHandleOf(shape: Shape, op: string): BrepHandle {\n const h = brepOf(shape) as BrepHandle | undefined\n if (!h) {\n throw new Error(`E_${op.toUpperCase()}_NO_BREP: ${op} requires a BREP handle (mesh-only shape has none)`)\n }\n return h\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// edge — 顶点对构造边(occt 原生 makeEdge;顶点可来自 vertex Shape 或 [x,y,z])\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** 顶点入参:vertex Shape 或 [x,y,z] 点(内部经契约 makeVertex 物化)。 */\nfunction vertexHandleOf(v: Shape | Vec3, op: string): BrepHandle {\n if (Array.isArray(v)) {\n const p = toVec3(v, op, 'vertex')\n return getBrepApi().makeVertex(p.x, p.y, p.z) as unknown as BrepHandle\n }\n return curveHandleOf(v, op)\n}\n\n/** BREP 路径:顶点对 → occt 原生 makeEdge。 */\nfunction edgeBrep(v1: Shape | Vec3, v2: Shape | Vec3): Shape {\n if (v1 === undefined || v2 === undefined) {\n throw new Error('E_EDGE_MISSING_VERTEX: edge requires two vertices (vertex Shape or [x,y,z])')\n }\n const h1 = vertexHandleOf(v1, 'edge')\n const h2 = vertexHandleOf(v2, 'edge')\n const handle = getOcctKernel().makeEdge(h1 as never, h2 as never) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 两顶点构造边。顶点入参可以是 vertex Shape,也可以是 `[x,y,z]` 点\n * (点经 L1 契约 `makeVertex` 物化成顶点再配边)。\n * @group 创建\n * @inputs 2\n * @async false\n * @qual ok\n * @name edge\n * @note 平台 op:仅 occt 引擎(原生 makeEdge,L1 契约只有 makeLineEdge 等按几何构造)。\n * 非 occt 引擎执行前报错;brep_mock 不拦截。\n * @returns Shape 1D 直线边(kind:'curve')。\n * @param v1 - 第一个顶点(vertex Shape 或 [x,y,z])。type:Shape|Vec3 required:true\n * @param v2 - 第二个顶点(vertex Shape 或 [x,y,z])。type:Shape|Vec3 required:true\n * @example\n * const e = cad.edge([0,0,0], [10,0,0])\n */\nexport const edge = defineOp({\n name: 'edge',\n brep(v1: Shape | Vec3, v2: Shape | Vec3) {\n return edgeBrep(v1, v2)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D edge has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// circleArc — 圆心+法向+半径+起止角(度)构造圆弧\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** BREP 路径:occt 原生 makeCircleArc(角度内部换算弧度)。 */\nfunction circleArcBrep(\n center: Vec3,\n normal: Vec3,\n radius: number,\n startAngleDeg: number,\n endAngleDeg: number,\n): Shape {\n if (typeof radius !== 'number' || !(radius > 0)) {\n throw new Error('E_CIRCLEARC_BAD_RADIUS: radius must be a positive number')\n }\n if (\n typeof startAngleDeg !== 'number' || !Number.isFinite(startAngleDeg) ||\n typeof endAngleDeg !== 'number' || !Number.isFinite(endAngleDeg)\n ) {\n throw new Error('E_CIRCLEARC_BAD_ANGLE: startAngle/endAngle must be finite numbers (degrees)')\n }\n const c = toVec3(center, 'circleArc', 'center')\n const n = toNonZeroVec3(normal, 'circleArc', 'normal')\n const handle = getOcctKernel().makeCircleArc(\n c as never, n as never, radius, startAngleDeg * DEG2RAD, endAngleDeg * DEG2RAD,\n ) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 构造圆弧:圆心 + 法向 + 半径 + 起止角(度,绕法向右手逆时针)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name circleArc\n * @note 平台 op:仅 occt 引擎(原生 makeCircleArc)。角度单位是**度**(内部换算弧度\n * 传给 occt 的 Geom_TrimmedCurve)。\n * @returns Shape 1D 圆弧(kind:'curve')。\n * @param center - 圆心 [x,y,z]。type:Vec3 required:true\n * @param normal - 圆面法向 [x,y,z](非零)。type:Vec3 required:true\n * @param radius - 半径(mm,>0)。type:number required:true\n * @param startAngle - 起始角(度,自法向基准 X 方向起量)。type:number required:true\n * @param endAngle - 终止角(度)。type:number required:true\n * @example\n * const a = cad.circleArc([0,0,0], [0,0,1], 5, 0, 90)\n */\nexport const circleArc = defineOp({\n name: 'circleArc',\n paramDims: { center: 'length', normal: 'length', radius: 'length', startAngle: 'angle', endAngle: 'angle' },\n brep(center: Vec3, normal: Vec3, radius: number, startAngleDeg: number, endAngleDeg: number) {\n return circleArcBrep(center, normal, radius, startAngleDeg, endAngleDeg)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D arc has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ellipseEdge / ellipseArc — 椭圆整边 / 椭圆弧\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** 椭圆公共参数校验:两半径均正,且 major > minor(gp_Elips 约束)。 */\nfunction checkEllipseRadii(op: string, majorRadius: number, minorRadius: number): void {\n if (typeof majorRadius !== 'number' || !(majorRadius > 0)) {\n throw new Error(`E_${op.toUpperCase()}_BAD_MAJOR: majorRadius must be a positive number`)\n }\n if (typeof minorRadius !== 'number' || !(minorRadius > 0)) {\n throw new Error(`E_${op.toUpperCase()}_BAD_MINOR: minorRadius must be a positive number`)\n }\n if (minorRadius > majorRadius) {\n throw new Error(`E_${op.toUpperCase()}_BAD_RADII: minorRadius must be <= majorRadius (gp_Elips constraint)`)\n }\n}\n\n/** BREP 路径:occt 原生 makeEllipseEdge。 */\nfunction ellipseEdgeBrep(center: Vec3, normal: Vec3, majorRadius: number, minorRadius: number): Shape {\n checkEllipseRadii('ELLIPSEEDGE', majorRadius, minorRadius)\n const c = toVec3(center, 'ellipseEdge', 'center')\n const n = toNonZeroVec3(normal, 'ellipseEdge', 'normal')\n const handle = getOcctKernel().makeEllipseEdge(c as never, n as never, majorRadius, minorRadius) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 构造整椭圆边:中心 + 法向 + 长半轴 + 短半轴。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name ellipseEdge\n * @note 平台 op:仅 occt 引擎(原生 makeEllipseEdge)。要求 majorRadius >= minorRadius。\n * @returns Shape 1D 椭圆边(kind:'curve')。\n * @param center - 椭圆中心 [x,y,z]。type:Vec3 required:true\n * @param normal - 椭圆面法向 [x,y,z](非零)。type:Vec3 required:true\n * @param majorRadius - 长半轴(mm,>0)。type:number required:true\n * @param minorRadius - 短半轴(mm,>0 且 <= 长半轴)。type:number required:true\n * @example\n * const e = cad.ellipseEdge([0,0,0], [0,0,1], 10, 5)\n */\nexport const ellipseEdge = defineOp({\n name: 'ellipseEdge',\n paramDims: { center: 'length', normal: 'length', majorRadius: 'length', minorRadius: 'length' },\n brep(center: Vec3, normal: Vec3, majorRadius: number, minorRadius: number) {\n return ellipseEdgeBrep(center, normal, majorRadius, minorRadius)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D ellipse has no face role vocabulary' } as Provenance,\n})\n\n/** BREP 路径:occt 原生 makeEllipseArc(角度内部换算弧度)。 */\nfunction ellipseArcBrep(\n center: Vec3,\n normal: Vec3,\n majorRadius: number,\n minorRadius: number,\n startAngleDeg: number,\n endAngleDeg: number,\n): Shape {\n checkEllipseRadii('ELLIPSEARC', majorRadius, minorRadius)\n if (\n typeof startAngleDeg !== 'number' || !Number.isFinite(startAngleDeg) ||\n typeof endAngleDeg !== 'number' || !Number.isFinite(endAngleDeg)\n ) {\n throw new Error('E_ELLIPSEARC_BAD_ANGLE: startAngle/endAngle must be finite numbers (degrees)')\n }\n const c = toVec3(center, 'ellipseArc', 'center')\n const n = toNonZeroVec3(normal, 'ellipseArc', 'normal')\n const handle = getOcctKernel().makeEllipseArc(\n c as never, n as never, majorRadius, minorRadius, startAngleDeg * DEG2RAD, endAngleDeg * DEG2RAD,\n ) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 构造椭圆弧:中心 + 法向 + 长短半轴 + 起止角(度)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name ellipseArc\n * @note 平台 op:仅 occt 引擎(原生 makeEllipseArc)。角度单位是**度**(内部换算弧度)。\n * @returns Shape 1D 椭圆弧(kind:'curve')。\n * @param center - 椭圆中心 [x,y,z]。type:Vec3 required:true\n * @param normal - 椭圆面法向 [x,y,z](非零)。type:Vec3 required:true\n * @param majorRadius - 长半轴(mm,>0)。type:number required:true\n * @param minorRadius - 短半轴(mm,>0 且 <= 长半轴)。type:number required:true\n * @param startAngle - 起始角(度)。type:number required:true\n * @param endAngle - 终止角(度)。type:number required:true\n * @example\n * const a = cad.ellipseArc([0,0,0], [0,0,1], 10, 5, 0, 90)\n */\nexport const ellipseArc = defineOp({\n name: 'ellipseArc',\n paramDims: { center: 'length', normal: 'length', majorRadius: 'length', minorRadius: 'length', startAngle: 'angle', endAngle: 'angle' },\n brep(center: Vec3, normal: Vec3, majorRadius: number, minorRadius: number, startAngleDeg: number, endAngleDeg: number) {\n return ellipseArcBrep(center, normal, majorRadius, minorRadius, startAngleDeg, endAngleDeg)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D ellipse arc has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// tangentArc — 起点+切向+终点构造圆弧\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** BREP 路径:occt 原生 makeTangentArc(GC_MakeArcOfCircle(start, tangent, end))。 */\nfunction tangentArcBrep(start: Vec3, tangent: Vec3, end: Vec3): Shape {\n const s = toVec3(start, 'tangentArc', 'start')\n const t = toNonZeroVec3(tangent, 'tangentArc', 'tangent')\n const e = toVec3(end, 'tangentArc', 'end')\n const handle = getOcctKernel().makeTangentArc(s as never, t as never, e as never) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 构造圆弧:过起点、以给定切向出发、终于终点(GC_MakeArcOfCircle 语义)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name tangentArc\n * @note 平台 op:仅 occt 引擎(原生 makeTangentArc)。切向为零向量非法。\n * @returns Shape 1D 圆弧(kind:'curve')。\n * @param start - 起点 [x,y,z]。type:Vec3 required:true\n * @param tangent - 起点切向 [x,y,z](非零,不必单位化)。type:Vec3 required:true\n * @param end - 终点 [x,y,z]。type:Vec3 required:true\n * @example\n * const a = cad.tangentArc([0,0,0], [1,0,0], [5,5,0])\n */\nexport const tangentArc = defineOp({\n name: 'tangentArc',\n paramDims: { start: 'length', tangent: 'length', end: 'length' },\n brep(start: Vec3, tangent: Vec3, end: Vec3) {\n return tangentArcBrep(start, tangent, end)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D arc has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// approximatePoints — 点集逼近(与 L1 interpolatePoints 的插值成对)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** 点集校验(≥2 点)。 */\nfunction checkPoints(op: string, points: Vec3[]): void {\n if (!Array.isArray(points) || points.length < 2) {\n throw new Error(`E_${op.toUpperCase()}_BAD_POINTS: ${op} requires at least 2 points`)\n }\n for (const p of points) toVec3(p, op, 'point')\n}\n\n/** 点集 [x,y,z][] → occt {x,y,z}[](occt-wasm Vec3 是对象接口,非数组)。 */\nfunction toVec3Array(op: string, points: Vec3[]): { x: number; y: number; z: number }[] {\n return points.map((p) => toVec3(p, op, 'point'))\n}\n\n/** BREP 路径:occt 原生 approximatePoints(逼近曲线;tolerance 缺省 = 原生 1e-3)。 */\nfunction approximatePointsBrep(points: Vec3[], tolerance?: number): Shape {\n checkPoints('APPROXIMATEPOINTS', points)\n if (tolerance !== undefined && (typeof tolerance !== 'number' || !(tolerance > 0))) {\n throw new Error('E_APPROXIMATEPOINTS_BAD_TOLERANCE: tolerance must be a positive number')\n }\n const pts = toVec3Array('approximatePoints', points)\n const handle = (\n tolerance === undefined\n ? getOcctKernel().approximatePoints(pts as never)\n : getOcctKernel().approximatePoints(pts as never, tolerance)\n ) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 点集**逼近**曲线:过点但不严格插值(逼近容差内贴合,产平滑 B 样条)。\n * 与 L1 `interpolatePoints`(严格插值)成对的数学对偶路径。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name approximatePoints\n * @note 平台 op:仅 occt 引擎(原生 approximatePoints,tolerance 缺省 1e-3)。\n * @returns Shape 1D 逼近曲线(kind:'curve')。\n * @param points - 点集 [x,y,z][](≥2 点)。type:Vec3[] required:true\n * @param tolerance - 逼近容差(mm,默认 1e-3)。type:number required:false\n * @example\n * const c = cad.approximatePoints([[0,0,0],[5,3,0],[10,0,0]])\n */\nexport const approximatePoints = defineOp({\n name: 'approximatePoints',\n paramDims: { points: 'length', tolerance: 'length' },\n brep(points: Vec3[], tolerance?: number) {\n return approximatePointsBrep(points, tolerance)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D approximated curve has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// interpolateWithTangents — 带端点切向的插值\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** BREP 路径:occt 原生 interpolatePointsWithTangents。 */\nfunction interpolateWithTangentsBrep(points: Vec3[], startTangent: Vec3, endTangent: Vec3): Shape {\n checkPoints('INTERPOLATEWITHTANGENTS', points)\n const st = toNonZeroVec3(startTangent, 'interpolateWithTangents', 'startTangent')\n const et = toNonZeroVec3(endTangent, 'interpolateWithTangents', 'endTangent')\n const pts = toVec3Array('interpolateWithTangents', points)\n const handle = getOcctKernel().interpolatePointsWithTangents(\n pts as never, st as never, et as never,\n ) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * 点集**插值**曲线,带端点切向约束(三次 B 样条,过全部点且端点切向指定)。\n * @group 创建\n * @inputs 0\n * @async false\n * @qual ok\n * @name interpolateWithTangents\n * @note 平台 op:仅 occt 引擎(原生 interpolatePointsWithTangents)。两端切向非零。\n * @returns Shape 1D 插值曲线(kind:'curve')。\n * @param points - 点集 [x,y,z][](≥2 点)。type:Vec3[] required:true\n * @param startTangent - 起点切向 [x,y,z](非零)。type:Vec3 required:true\n * @param endTangent - 终点切向 [x,y,z](非零)。type:Vec3 required:true\n * @example\n * const c = cad.interpolateWithTangents([[0,0,0],[5,3,0],[10,0,0]], [1,0,0], [1,0,0])\n */\nexport const interpolateWithTangents = defineOp({\n name: 'interpolateWithTangents',\n paramDims: { points: 'length', startTangent: 'length', endTangent: 'length' },\n brep(points: Vec3[], startTangent: Vec3, endTangent: Vec3) {\n return interpolateWithTangentsBrep(points, startTangent, endTangent)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D interpolated curve has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// NURBS 精修族 — curveDegreeElevate / curveKnotInsert / curveKnotRemove\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** BREP 路径:occt 原生 curveDegreeElevate(NURBS 升阶)。 */\nfunction curveDegreeElevateBrep(curve: Shape, elevateBy: number): Shape {\n if (!Number.isInteger(elevateBy) || elevateBy <= 0) {\n throw new Error('E_CURVEDEGREEELEVATE_BAD_STEP: elevateBy must be a positive integer')\n }\n const h = curveHandleOf(curve, 'curveDegreeElevate')\n const handle = getOcctKernel().curveDegreeElevate(h as never, elevateBy) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * NURBS 曲线升阶:把边/曲线的阶数提升 `elevateBy`(几何不变,表示空间变大)。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name curveDegreeElevate\n * @note 平台 op:仅 occt 引擎(原生 curveDegreeElevate)。输入边/曲线。\n * @returns Shape 升阶后的 1D 曲线(kind:'curve')。\n * @param curve - 输入边/曲线。type:Shape required:true\n * @param elevateBy - 升阶量(正整数)。type:number required:true\n * @example\n * const up = cad.curveDegreeElevate(e, 2)\n */\nexport const curveDegreeElevate = defineOp({\n name: 'curveDegreeElevate',\n brep(curve: Shape, elevateBy: number) {\n return curveDegreeElevateBrep(curve, elevateBy)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D refined curve has no face role vocabulary' } as Provenance,\n})\n\n/** BREP 路径:occt 原生 curveKnotInsert(插节点 times 次)。 */\nfunction curveKnotInsertBrep(curve: Shape, knot: number, times: number): Shape {\n if (typeof knot !== 'number' || !Number.isFinite(knot)) {\n throw new Error('E_CURVEKNOTINSERT_BAD_KNOT: knot must be a finite number (curve parameter)')\n }\n if (!Number.isInteger(times) || times <= 0) {\n throw new Error('E_CURVEKNOTINSERT_BAD_TIMES: times must be a positive integer')\n }\n const h = curveHandleOf(curve, 'curveKnotInsert')\n const handle = getOcctKernel().curveKnotInsert(h as never, knot, times) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * NURBS 曲线插节点:在曲线参数 `knot` 处插入节点 `times` 次(几何不变)。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name curveKnotInsert\n * @note 平台 op:仅 occt 引擎(原生 curveKnotInsert)。knot 是曲线参数(不是长度)。\n * @returns Shape 插节点后的 1D 曲线(kind:'curve')。\n * @param curve - 输入边/曲线。type:Shape required:true\n * @param knot - 目标节点参数。type:number required:true\n * @param times - 重复次数(正整数)。type:number required:true\n * @example\n * const refined = cad.curveKnotInsert(e, 0.5, 1)\n */\nexport const curveKnotInsert = defineOp({\n name: 'curveKnotInsert',\n brep(curve: Shape, knot: number, times: number) {\n return curveKnotInsertBrep(curve, knot, times)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D refined curve has no face role vocabulary' } as Provenance,\n})\n\n/** BREP 路径:occt 原生 curveKnotRemove(容差内去节点)。 */\nfunction curveKnotRemoveBrep(curve: Shape, knot: number, tolerance: number): Shape {\n if (typeof knot !== 'number' || !Number.isFinite(knot)) {\n throw new Error('E_CURVEKNOTREMOVE_BAD_KNOT: knot must be a finite number (curve parameter)')\n }\n if (typeof tolerance !== 'number' || !(tolerance > 0)) {\n throw new Error('E_CURVEKNOTREMOVE_BAD_TOLERANCE: tolerance must be a positive number')\n }\n const h = curveHandleOf(curve, 'curveKnotRemove')\n const handle = getOcctKernel().curveKnotRemove(h as never, knot, tolerance) as unknown as BrepHandle\n return adoptCurve(handle)\n}\n\n/**\n * NURBS 曲线去节点:在容差内移除参数 `knot` 处的节点(几何漂移不超过 tolerance)。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name curveKnotRemove\n * @note 平台 op:仅 occt 引擎(原生 curveKnotRemove)。knot 是曲线参数(不是长度)。\n * @returns Shape 去节点后的 1D 曲线(kind:'curve')。\n * @param curve - 输入边/曲线。type:Shape required:true\n * @param knot - 目标节点参数。type:number required:true\n * @param tolerance - 允许的几何漂移(mm,>0)。type:number required:true\n * @example\n * const lean = cad.curveKnotRemove(e, 0.5, 1e-4)\n */\nexport const curveKnotRemove = defineOp({\n name: 'curveKnotRemove',\n paramDims: { tolerance: 'length' },\n brep(curve: Shape, knot: number, tolerance: number) {\n return curveKnotRemoveBrep(curve, knot, tolerance)\n },\n engines: ['occt'],\n naming: { kind: 'unmodeled', reason: '1D refined curve has no face role vocabulary' } as Provenance,\n})\n\n// ─────────────────────────────────────────────────────────────────────────────\n// curveIsPeriodic — 周期性查询(返回布尔 ⇒ 普通函数形态,同 shape-type 族口径)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * 曲线是否周期(L1 契约只有 `curveIsClosed`,周期性是 occt 原生独有查询)。\n * @group 查询\n * @inputs 1\n * @async false\n * @qual ok\n * @name curveIsPeriodic\n * @note 平台 op:仅 occt 引擎(原生 curveIsPeriodic,L1 无对应成员)。非 occt 引擎\n * 执行前报 E_BREP_UNSUPPORTED。\n * @returns boolean 是否为周期曲线。\n * @param curve - 被查询的边/曲线。type:Shape required:true\n * @example\n * const c = cad.circleArc([0,0,0], [0,0,1], 5, 0, 360)\n * const periodic = cad.curveIsPeriodic(c)\n */\nexport function curveIsPeriodic(curve: Shape): boolean {\n assertEngineFor('curveIsPeriodic', ['occt'])\n const h = curveHandleOf(curve, 'curveIsPeriodic')\n const kernel = getOcctKernel() as unknown as { curveIsPeriodic(h: unknown): boolean }\n return kernel.curveIsPeriodic(h)\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/api/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAM1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAKrD,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAEpC,sBAAsB;AACtB,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,cAAc;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,mBAAmB;IACnB,IAAI,CAAC,EAAE,IAAI,CAAA;IACX;;;;OAIG;IACH,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,IAAI,CAAA;KAAE,CAAA;CACzC;AAwDD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,KAAK;;CAUhB,CAAA"}
1
+ {"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/api/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAM1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAKrD,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAEpC,sBAAsB;AACtB,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB,cAAc;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,mBAAmB;IACnB,IAAI,CAAC,EAAE,IAAI,CAAA;IACX;;;;OAIG;IACH,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,IAAI,CAAA;KAAE,CAAA;CACzC;AAwDD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,KAAK;;CAQhB,CAAA"}
package/dist/api/draft.js CHANGED
@@ -96,10 +96,8 @@ function draftBrep(input, params) {
96
96
  * const d = await cad.draft(part0, { faces: [cad.faceRef(part0, 3)], angleDeg: 3 })
97
97
  */
98
98
  export const draft = defineOp({
99
- capabilities: ['directEdit'],
100
99
  // 实证收窄(2026-09-24):brepkit 的 L1 draft 产出错误几何(破坏对称性 / 静默无操作),
101
- // 声明 occt 白名单让静态门在执行前拒绝 —— 与 capabilities 并存合法(两条正交轴,
102
- // engines 先判、能力门在引擎匹配后再求交)。
100
+ // 声明 occt 白名单让静态门在执行前拒绝(引擎身份是 op 侧唯一的收窄轴)。
103
101
  engines: ['occt'],
104
102
  brep(input, params) {
105
103
  return draftBrep(input, params);
@@ -1 +1 @@
1
- {"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/api/draft.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api draft — 拔模:对选定面施加拔模斜度(手写**平台** op,Phase 5)\n *\n * `engines: ['occt']` —— 但**不是平台依赖**(实现只经 L1 契约面 `getBrepApi()`,\n * 见下选面口径),而是**实证收窄**:brepkit 的 L1 `draft` 实测产出错误几何,\n * 必须让静态门在执行前拒绝(红线:BREP 链可用性执行前静态判定,不允许\n * 「门说能、内核说不能」;也不允许静默产出错几何)。\n *\n * 实证(同脚本、box(20,20,10)、angleDeg=3,两引擎同一次运行):\n * - occt:4 个侧面(faceRef ordinal 1–4)**都给一致 delta = −52.4078**\n * —— 对称输入 ⇒ 对称输出,几何自洽;⊥ pull 的端面由内核报 KERNEL_ERROR。\n * - brepkit:ordinal 1–5 给 +60.29 / 0 / 0 / +17.47 / 0 —— **对称性被破坏**\n * (对称 box 上对单个侧面拔模,四个侧面不可能给出不同结果),其中三个是\n * **静默无操作**(体积与 bbox 均不变),而 ⊥ pull 的端面反而把 x/y 凸包各撑大\n * 0.524(= 10·tan 3°)。序号错配不能解释:破坏对称性与序号无关。\n *\n * 选面口径(设计原则 4):`faces: FaceTopoRef[]`(`cad.faceRef` 产物)。\n * `neutral` 用 `{point, normal}` 平面参数——不给 face 引用(方案 §7 建议 2)。\n *\n * 回归守卫:`api/feature-family.test.ts` 的「brepkit 下 draft 静态拒绝」用例。\n */\n\nimport type { Shape } from '../mesh/types'\nimport type { BrepHandle, BrepVec3 } from '../brep/engine/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { brepOf, fromBrep } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { FaceTopoRef } from '../topology/naming'\nimport { resolveTopoRef, TopoRefError } from '../topology/naming'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { buildEdgeResolutionContext } from './topo-resolve'\n\ntype Vec3 = [number, number, number]\n\n/** `cad.draft` 参数。 */\nexport interface DraftParams {\n /** 拔模面(FaceTopoRef[],`cad.faceRef` 产物)。 */\n faces: FaceTopoRef[]\n /** 拔模角(度)。 */\n angleDeg: number\n /** 拔模方向(默认 +Z)。 */\n pull?: Vec3\n /**\n * 中性平面:**只有点的语义**(内核把该点所在高度视为 0° 基准;省略取原点)。\n * `normal` 无任何内核消费者(occt-wasm 原生 `draft` 无 neutral 形参,brepkit\n * 只收点),传了会显式报 `E_DRAFT_NEUTRAL_NORMAL_UNUSED`。\n */\n neutral?: { point: Vec3; normal?: Vec3 }\n}\n\n/** BREP 路径:解析面引用 → L1 draft → 收养。 */\nfunction draftBrep(input: Shape, params: DraftParams): Shape {\n const { faces, angleDeg } = params ?? ({} as DraftParams)\n if (!Array.isArray(faces) || faces.length === 0) {\n throw new Error('E_DRAFT_NO_FACES: draft requires at least one FaceTopoRef in faces')\n }\n if (typeof angleDeg !== 'number' || !Number.isFinite(angleDeg) || angleDeg === 0) {\n throw new Error('E_DRAFT_BAD_ANGLE: draft.angleDeg must be a non-zero number (degrees)')\n }\n const kernel = getBrepApi()\n const solid = brepOf(input) as BrepHandle | undefined\n if (!solid) throw new Error('E_DRAFT_NO_BREP: draft input is not BREP')\n\n const ctx = buildEdgeResolutionContext(kernel, input as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'draft: input has no BREP naming context')\n const faceHandles = faces.map((ref) => {\n if (!ref || (ref as { kind?: unknown }).kind !== 'face') {\n throw new Error('E_DRAFT_BAD_FACE_REF: every faces entry must be a FaceTopoRef (cad.faceRef)')\n }\n const r = resolveTopoRef(ref, ctx)\n if (r.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', `draft: face resolved without handle (${ref.origin}/${ref.role})`)\n }\n return r.handle as BrepHandle\n })\n\n // GOTCHA-1(Phase 5 实测):L1 的向量形参是 `BrepVec3 = {x,y,z}` **对象**,不是元组。\n // 传 `[0,0,1]` 会被内核读成零向量 ⇒ occt 抛空文案 KERNEL_ERROR、brepkit 抛\n // \"cannot normalize zero vector\",两边都不可用。必须显式转对象(同 pattern.ts:41)。\n const [px, py, pz] = params.pull ?? [0, 0, 1]\n const pullVec: BrepVec3 = { x: px, y: py, z: pz }\n\n // 中性面缺省:中性点取原点(内核语义为「该点处角度为 0」)。\n const nPoint = params.neutral?.point\n const neutralVec: BrepVec3 = nPoint\n ? { x: nPoint[0], y: nPoint[1], z: nPoint[2] }\n : { x: 0, y: 0, z: 0 }\n\n // GOTCHA-2(Phase 5 实测):L1 draft 的 neutral 只有**点**语义(occt-wasm 原生\n // `draft(shape, face, angleRad, direction)` 根本没有 neutral 形参,brepkit 也只收\n // 点:brepkitKernel.ts:669-676)。故 `neutral.normal` 无任何消费者——按项目约定\n // (occt-primitives.ts interpolatePoints「拒绝而非静默产出错几何」)显式报错,\n // 不静默丢弃。\n if (params.neutral?.normal) {\n throw new Error(\n 'E_DRAFT_NEUTRAL_NORMAL_UNUSED: L1 draft takes a neutral POINT only (no plane normal) — ' +\n 'drop neutral.normal, or model the plane via pull + a point on it',\n )\n }\n\n const result = kernel.draft(solid, faceHandles, pullVec, neutralVec, angleDeg)\n return fromBrep(solidToShape(kernel, result), { solid: result })\n}\n\n/**\n * 拔模:对选定面施加拔模斜度(铸造/注塑出模角)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name draft\n * @note **occt-only**(`engines: ['occt']`;实证收窄,非平台依赖——见文件头实证:\n * brepkit 破坏对称性且部分 ordinal 静默无操作)。`neutral`(中性点)**只支持\n * 原点**:occt-wasm 原生 `draft(shape, face, angleRad, direction)` 没有 neutral\n * 形参,传非原点中性点会显式报错(不静默产出错几何);brepkit 已被静态拒绝,\n * 故非原点 `neutral` 当前**没有任何可用引擎**——需要该语义时请改用\n * `pull` + 面上一点建模。仅 BREP 可用(mesh 输入执行前报错)。\n * @returns Shape 拔模后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.faces - 拔模面(FaceTopoRef[],cad.faceRef 产物)。type:FaceTopoRef[] required:true\n * @param params.angleDeg - 拔模角(度,≠0)。type:number required:true\n * @param params.pull - 拔模方向(默认 +Z)。type:Vec3 required:false\n * @param params.neutral - 中性面**点**({point};normal 无消费者)。type:{point:Vec3,normal?:Vec3} required:false\n * @example\n * const d = await cad.draft(part0, { faces: [cad.faceRef(part0, 3)], angleDeg: 3 })\n */\nexport const draft = defineOp({\n capabilities: ['directEdit'],\n // 实证收窄(2026-09-24):brepkit 的 L1 draft 产出错误几何(破坏对称性 / 静默无操作),\n // 声明 occt 白名单让静态门在执行前拒绝 —— 与 capabilities 并存合法(两条正交轴,\n // engines 先判、能力门在引擎匹配后再求交)。\n engines: ['occt'],\n brep(input: Shape, params: DraftParams) {\n return draftBrep(input, params)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n})\n"]}
1
+ {"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/api/draft.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api draft — 拔模:对选定面施加拔模斜度(手写**平台** op,Phase 5)\n *\n * `engines: ['occt']` —— 但**不是平台依赖**(实现只经 L1 契约面 `getBrepApi()`,\n * 见下选面口径),而是**实证收窄**:brepkit 的 L1 `draft` 实测产出错误几何,\n * 必须让静态门在执行前拒绝(红线:BREP 链可用性执行前静态判定,不允许\n * 「门说能、内核说不能」;也不允许静默产出错几何)。\n *\n * 实证(同脚本、box(20,20,10)、angleDeg=3,两引擎同一次运行):\n * - occt:4 个侧面(faceRef ordinal 1–4)**都给一致 delta = −52.4078**\n * —— 对称输入 ⇒ 对称输出,几何自洽;⊥ pull 的端面由内核报 KERNEL_ERROR。\n * - brepkit:ordinal 1–5 给 +60.29 / 0 / 0 / +17.47 / 0 —— **对称性被破坏**\n * (对称 box 上对单个侧面拔模,四个侧面不可能给出不同结果),其中三个是\n * **静默无操作**(体积与 bbox 均不变),而 ⊥ pull 的端面反而把 x/y 凸包各撑大\n * 0.524(= 10·tan 3°)。序号错配不能解释:破坏对称性与序号无关。\n *\n * 选面口径(设计原则 4):`faces: FaceTopoRef[]`(`cad.faceRef` 产物)。\n * `neutral` 用 `{point, normal}` 平面参数——不给 face 引用(方案 §7 建议 2)。\n *\n * 回归守卫:`api/feature-family.test.ts` 的「brepkit 下 draft 静态拒绝」用例。\n */\n\nimport type { Shape } from '../mesh/types'\nimport type { BrepHandle, BrepVec3 } from '../brep/engine/types'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { brepOf, fromBrep } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { FaceTopoRef } from '../topology/naming'\nimport { resolveTopoRef, TopoRefError } from '../topology/naming'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { buildEdgeResolutionContext } from './topo-resolve'\n\ntype Vec3 = [number, number, number]\n\n/** `cad.draft` 参数。 */\nexport interface DraftParams {\n /** 拔模面(FaceTopoRef[],`cad.faceRef` 产物)。 */\n faces: FaceTopoRef[]\n /** 拔模角(度)。 */\n angleDeg: number\n /** 拔模方向(默认 +Z)。 */\n pull?: Vec3\n /**\n * 中性平面:**只有点的语义**(内核把该点所在高度视为 0° 基准;省略取原点)。\n * `normal` 无任何内核消费者(occt-wasm 原生 `draft` 无 neutral 形参,brepkit\n * 只收点),传了会显式报 `E_DRAFT_NEUTRAL_NORMAL_UNUSED`。\n */\n neutral?: { point: Vec3; normal?: Vec3 }\n}\n\n/** BREP 路径:解析面引用 → L1 draft → 收养。 */\nfunction draftBrep(input: Shape, params: DraftParams): Shape {\n const { faces, angleDeg } = params ?? ({} as DraftParams)\n if (!Array.isArray(faces) || faces.length === 0) {\n throw new Error('E_DRAFT_NO_FACES: draft requires at least one FaceTopoRef in faces')\n }\n if (typeof angleDeg !== 'number' || !Number.isFinite(angleDeg) || angleDeg === 0) {\n throw new Error('E_DRAFT_BAD_ANGLE: draft.angleDeg must be a non-zero number (degrees)')\n }\n const kernel = getBrepApi()\n const solid = brepOf(input) as BrepHandle | undefined\n if (!solid) throw new Error('E_DRAFT_NO_BREP: draft input is not BREP')\n\n const ctx = buildEdgeResolutionContext(kernel, input as object)\n if (!ctx) throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', 'draft: input has no BREP naming context')\n const faceHandles = faces.map((ref) => {\n if (!ref || (ref as { kind?: unknown }).kind !== 'face') {\n throw new Error('E_DRAFT_BAD_FACE_REF: every faces entry must be a FaceTopoRef (cad.faceRef)')\n }\n const r = resolveTopoRef(ref, ctx)\n if (r.handle === undefined) {\n throw new TopoRefError('E_TOPO_NOT_FOUND', 'face', `draft: face resolved without handle (${ref.origin}/${ref.role})`)\n }\n return r.handle as BrepHandle\n })\n\n // GOTCHA-1(Phase 5 实测):L1 的向量形参是 `BrepVec3 = {x,y,z}` **对象**,不是元组。\n // 传 `[0,0,1]` 会被内核读成零向量 ⇒ occt 抛空文案 KERNEL_ERROR、brepkit 抛\n // \"cannot normalize zero vector\",两边都不可用。必须显式转对象(同 pattern.ts:41)。\n const [px, py, pz] = params.pull ?? [0, 0, 1]\n const pullVec: BrepVec3 = { x: px, y: py, z: pz }\n\n // 中性面缺省:中性点取原点(内核语义为「该点处角度为 0」)。\n const nPoint = params.neutral?.point\n const neutralVec: BrepVec3 = nPoint\n ? { x: nPoint[0], y: nPoint[1], z: nPoint[2] }\n : { x: 0, y: 0, z: 0 }\n\n // GOTCHA-2(Phase 5 实测):L1 draft 的 neutral 只有**点**语义(occt-wasm 原生\n // `draft(shape, face, angleRad, direction)` 根本没有 neutral 形参,brepkit 也只收\n // 点:brepkitKernel.ts:669-676)。故 `neutral.normal` 无任何消费者——按项目约定\n // (occt-primitives.ts interpolatePoints「拒绝而非静默产出错几何」)显式报错,\n // 不静默丢弃。\n if (params.neutral?.normal) {\n throw new Error(\n 'E_DRAFT_NEUTRAL_NORMAL_UNUSED: L1 draft takes a neutral POINT only (no plane normal) — ' +\n 'drop neutral.normal, or model the plane via pull + a point on it',\n )\n }\n\n const result = kernel.draft(solid, faceHandles, pullVec, neutralVec, angleDeg)\n return fromBrep(solidToShape(kernel, result), { solid: result })\n}\n\n/**\n * 拔模:对选定面施加拔模斜度(铸造/注塑出模角)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name draft\n * @note **occt-only**(`engines: ['occt']`;实证收窄,非平台依赖——见文件头实证:\n * brepkit 破坏对称性且部分 ordinal 静默无操作)。`neutral`(中性点)**只支持\n * 原点**:occt-wasm 原生 `draft(shape, face, angleRad, direction)` 没有 neutral\n * 形参,传非原点中性点会显式报错(不静默产出错几何);brepkit 已被静态拒绝,\n * 故非原点 `neutral` 当前**没有任何可用引擎**——需要该语义时请改用\n * `pull` + 面上一点建模。仅 BREP 可用(mesh 输入执行前报错)。\n * @returns Shape 拔模后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.faces - 拔模面(FaceTopoRef[],cad.faceRef 产物)。type:FaceTopoRef[] required:true\n * @param params.angleDeg - 拔模角(度,≠0)。type:number required:true\n * @param params.pull - 拔模方向(默认 +Z)。type:Vec3 required:false\n * @param params.neutral - 中性面**点**({point};normal 无消费者)。type:{point:Vec3,normal?:Vec3} required:false\n * @example\n * const d = await cad.draft(part0, { faces: [cad.faceRef(part0, 3)], angleDeg: 3 })\n */\nexport const draft = defineOp({\n // 实证收窄(2026-09-24):brepkit 的 L1 draft 产出错误几何(破坏对称性 / 静默无操作),\n // 声明 occt 白名单让静态门在执行前拒绝(引擎身份是 op 侧唯一的收窄轴)。\n engines: ['occt'],\n brep(input: Shape, params: DraftParams) {\n return draftBrep(input, params)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n})\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"engrave.d.ts","sourceRoot":"","sources":["../../src/api/engrave.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAQ,MAAM,eAAe,CAAA;AAsBhD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CASzE;AAqID;;;;;;;;;;;;;;;;;;;;IAoBI;AACJ,eAAO,MAAM,OAAO;;CA8BlB,CAAA"}
1
+ {"version":3,"file":"engrave.d.ts","sourceRoot":"","sources":["../../src/api/engrave.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAQ,MAAM,eAAe,CAAA;AAsBhD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CASzE;AAwHD;;;;;;;;;;;;;;;;;;;;IAoBI;AACJ,eAAO,MAAM,OAAO;;CA8BlB,CAAA"}
@@ -35,17 +35,6 @@ export function assertEngraveParams(params) {
35
35
  assertPositiveNumber(params.depth, 'engrave.depth');
36
36
  }
37
37
  }
38
- /** 世界坐标 → BREP solid 局部坐标。 */
39
- function worldToLocalPosition(worldPos, partTransform) {
40
- const offset = partTransform?.position;
41
- if (!offset)
42
- return worldPos;
43
- return [
44
- worldPos[0] - offset[0],
45
- worldPos[1] - offset[1],
46
- worldPos[2] - offset[2],
47
- ];
48
- }
49
38
  /** 计算将 +Z 轴对齐到目标法向量的 3x4 仿射变换矩阵(仅旋转,无平移,Rodrigues 公式)。 */
50
39
  function alignZToNormal(normal) {
51
40
  const [nx, ny, nz] = normal;
@@ -112,8 +101,9 @@ async function engraveBrepPath(input, params, svgText) {
112
101
  const rotated = kernel.transform(decorationSolid, rotMatrix);
113
102
  kernel.release(decorationSolid);
114
103
  // 4. 沿法向偏移 + 平移到面中心(凸 offset=+depth/2,凹 offset=-depth/2;加 0.01 避免共面)
115
- const worldFaceCenter = params.faceCenter ?? [0, 0, 0];
116
- const localFaceCenter = worldToLocalPosition(worldFaceCenter, getBackends().config.partTransform);
104
+ // faceCenter/faceNormal 契约(方向 A):模型局部空间值(宿主生成脚本时已把交互
105
+ // 世界坐标转换好),本 op 不做 world→local(无 partTransform 依赖)。
106
+ const localFaceCenter = params.faceCenter ?? [0, 0, 0];
117
107
  const offset = mode === 'convex' ? depth / 2 : -depth / 2;
118
108
  const epsilon = 0.01;
119
109
  const tx = localFaceCenter[0] + worldFaceNormal[0] * (offset + epsilon);
@@ -1 +1 @@
1
- {"version":3,"file":"engrave.js","sourceRoot":"","sources":["../../src/api/engrave.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api engrave — 雕刻库函数\n *\n *\n * dispatchPath 静态判定 brep/mesh。\n * BREP 路径:textToSolid/svgToSolid + boolean(cut/fuse)。\n */\n\nimport type { Shape, Vec3 } from '../mesh/types'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { AssetResolver } from '../cad-runtime/ports'\n// B3 correction (2026-10-06): no library-face cad aggregate — import the impl from its own module.\nimport * as meshEngrave from '../mesh/engrave'\nimport { parseSvgNaturalSize } from '../primitives/parse-svg-size'\nimport { textToSolid } from '../brep/text/text-to-solid'\nimport { svgToSolid } from '../brep/svg/svg-to-solid'\nimport { ensureDefaultFont } from '../brep/text/fontRegistry'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getSolidBoundingBox } from '../brep/brep-utils'\nimport { resolveSvgArg } from './internal/svg-asset-resolver'\nimport { getBackends } from '../runtime-state'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { fromBrep, brepOf } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { assertPositiveNumber } from './assert'\n\n// ── per-op 参数自校验(Phase 2.2;api 层被直接 import 时的防御层) ──\n\n/**\n * Validate engrave parameters: at least one of `text` or `svg` must be\n * provided, and `depth` (if provided) must be a positive number.\n * @param params - the raw engrave operation parameters.\n */\nexport function assertEngraveParams(params: Record<string, unknown>): void {\n const hasText = params.text !== undefined && params.text !== null && params.text !== ''\n const hasSvg = params.svg !== undefined && params.svg !== null\n if (!hasText && !hasSvg) {\n throw new Error('[api/engrave] requires either \"text\" or \"svg\"')\n }\n if (params.depth !== undefined && params.depth !== null) {\n assertPositiveNumber(params.depth, 'engrave.depth')\n }\n}\n\n/** 世界坐标 → BREP solid 局部坐标。 */\nfunction worldToLocalPosition(\n worldPos: Vec3,\n partTransform: { position?: [number, number, number] } | undefined,\n): Vec3 {\n const offset = partTransform?.position\n if (!offset) return worldPos\n return [\n worldPos[0] - offset[0],\n worldPos[1] - offset[1],\n worldPos[2] - offset[2],\n ]\n}\n\n/** 计算将 +Z 轴对齐到目标法向量的 3x4 仿射变换矩阵(仅旋转,无平移,Rodrigues 公式)。 */\nfunction alignZToNormal(normal: Vec3): number[] {\n const [nx, ny, nz] = normal\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz)\n if (len < 1e-10) {\n return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]\n }\n const ux = nx / len, uy = ny / len, uz = nz / len\n\n if (Math.abs(ux) < 1e-10 && Math.abs(uy) < 1e-10) {\n if (uz > 0) return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]\n return [1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0]\n }\n\n const s = Math.sqrt(ux * ux + uy * uy)\n const c = uz\n const t = 1 - c\n const ax = -uy / s, ay = ux / s\n\n return [\n c + ax * ax * t, ax * ay * t, ay * s, 0,\n ax * ay * t, c + ay * ay * t, -ax * s, 0,\n -ay * s, ax * s, c, 0,\n ]\n}\n\n/** 将 solid 居中到原点(基于包围盒中心,与 mesh 路径语义一致)。 */\nfunction centerSolidAtOrigin(kernel: BrepEngineApi, solid: BrepHandle): BrepHandle {\n const bb = getSolidBoundingBox(kernel, solid)\n const cx = (bb.min[0] + bb.max[0]) / 2\n const cy = (bb.min[1] + bb.max[1]) / 2\n const cz = (bb.min[2] + bb.max[2]) / 2\n const centered = kernel.translate(solid, -cx, -cy, -cz)\n kernel.release(solid)\n return centered\n}\n\n/** BREP 路径:textToSolid/svgToSolid + boolean(cut/fuse)。 */\nasync function engraveBrepPath(input: Shape, params: Record<string, unknown>, svgText?: string): Promise<Shape> {\n const kernel = getBrepApi()\n const inputSolid = brepOf(input) as BrepHandle | undefined\n if (!inputSolid) throw new Error('[api/engrave] input is not BREP')\n\n const depth = params.depth as number\n const mode = (params.mode as 'convex' | 'concave' | undefined) ?? 'concave'\n const text = params.text as string | undefined\n\n // 1. 创建装饰 solid(文字或 SVG),depth 与 mesh 路径一致\n let decorationSolid: BrepHandle\n if (text) {\n await ensureDefaultFont()\n const textSize = (params.textSize as number) ?? 10\n decorationSolid = textToSolid(kernel, text, { fontSize: textSize, depth })\n } else if (svgText) {\n decorationSolid = svgToSolid(kernel, svgText, {\n depth,\n targetLongSide: (params.svgSize as number) ?? 20,\n })\n } else {\n throw new Error('[api/engrave] neither text nor svg provided')\n }\n\n // 2. 居中到原点\n decorationSolid = centerSolidAtOrigin(kernel, decorationSolid)\n\n // 3. 旋转 +Z 对齐面法向\n const worldFaceNormal: Vec3 = (params.faceNormal as Vec3) ?? [0, 0, 1]\n const rotMatrix = alignZToNormal(worldFaceNormal)\n const rotated = kernel.transform(decorationSolid, rotMatrix)\n kernel.release(decorationSolid)\n\n // 4. 沿法向偏移 + 平移到面中心(凸 offset=+depth/2,凹 offset=-depth/2;加 0.01 避免共面)\n const worldFaceCenter: Vec3 = (params.faceCenter as Vec3) ?? [0, 0, 0]\n const localFaceCenter = worldToLocalPosition(worldFaceCenter, getBackends().config.partTransform)\n const offset = mode === 'convex' ? depth / 2 : -depth / 2\n const epsilon = 0.01\n const tx = localFaceCenter[0] + worldFaceNormal[0] * (offset + epsilon)\n const ty = localFaceCenter[1] + worldFaceNormal[1] * (offset + epsilon)\n const tz = localFaceCenter[2] + worldFaceNormal[2] * (offset + epsilon)\n const positioned = kernel.translate(rotated, tx, ty, tz)\n kernel.release(rotated)\n\n // 5. 布尔运算(凸=fuse,凹=cut)\n const isRaised = mode === 'convex'\n let result: BrepHandle\n if (isRaised) {\n result = kernel.fuse(inputSolid, positioned)\n } else {\n result = kernel.cut(inputSolid, positioned)\n }\n kernel.release(positioned)\n\n // 5b. cut 可能分裂成多个 solid(compound),用 fuseAll 合并回单一 solid\n try {\n const subSolids = kernel.getSubShapes(result, 'solid')\n if (subSolids.length > 1) {\n const fused = kernel.fuseAll(subSolids)\n for (const s of subSolids) {\n try { kernel.release(s) } catch { /* 已释放 */ }\n }\n try { kernel.release(result) } catch { /* 已释放 */ }\n result = fused\n }\n } catch {\n // getSubShapes 失败说明结果不是 compound,无需处理\n }\n\n return fromBrep(solidToShape(kernel, result), { solid: result })\n}\n\n/** 解析 SVG 资产引用(AssetRef → SVG 文本),两条路径共享;无 svg 返回 undefined。 */\nasync function resolveEngraveSvg(params: Record<string, unknown>): Promise<string | undefined> {\n return params.svg !== undefined && params.svg !== null\n ? await resolveSvgArg(params.svg, { assets: getBackends().assets as AssetResolver | undefined })\n : undefined\n}\n\n/**\n * 在几何表面雕刻文字或 SVG(文字分支与 logo 分支都可用)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name engrave\n * @returns Shape 雕刻后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.mode - 雕刻方式:concave 凹陷(减法)/ convex 凸出(加法)。type:'concave' | 'convex' 默认 'concave'\n * @param params.depth - 深度 / 凸出高度(mm)。type:number 默认 0\n * @param params.text - 文字内容(与 svg 二选一)。type:string\n * @param params.textSize - 字号(mm)。type:number 默认 10\n * @param params.svg - SVG 资产引用(与 text 二选一;经 cad.asset 解析)。type:string\n * @param params.svgSize - SVG 长边目标尺寸。type:number\n * @param params.faceCenter - 面位置(绝对坐标)。type:[x,y,z] 默认 [0,0,0]\n * @param params.faceNormal - 面法向。type:[x,y,z] 默认 [0,0,1]\n * @note 早期 logo 分支用 `svgText`(整份 XML 拷贝 + `svgSize` 文本导出丢失,往返失真);现已改为 `svg` 资产引用,`engravingType` 冗余键已移除。faceCenter/faceNormal 目前是绝对坐标快照。\n * @example\n * const p = await cad.engrave(part0, { mode: 'concave', depth: 2, text: 'Hello', textSize: 10, faceCenter: [0, 0, 0], faceNormal: [0, 0, -1] })\n */\nexport const engrave = defineOp({\n mesh: async (input: Shape, params: Record<string, unknown>) => {\n if (!input) throw new Error('[api/engrave] no input geometry')\n assertEngraveParams(params)\n const svgText = await resolveEngraveSvg(params)\n // mesh 路径\n const faceCenter: Vec3 = (params.faceCenter as Vec3) ?? [0, 0, 0]\n const faceNormal: Vec3 = (params.faceNormal as Vec3) ?? [0, 0, 1]\n const { naturalWidth, naturalHeight } = svgText ? parseSvgNaturalSize(svgText) : { naturalWidth: 0, naturalHeight: 0 }\n const hasText = !!(params.text as string | undefined)\n\n return meshEngrave.engrave(input, {\n mode: (params.mode as 'convex' | 'concave' | undefined) ?? 'concave',\n depth: params.depth as number,\n face: { center: faceCenter, normal: faceNormal },\n text: hasText ? (params.text as string) : undefined,\n textSize: params.textSize as number | undefined,\n svg: svgText,\n svgNaturalWidth: naturalWidth,\n svgNaturalHeight: naturalHeight,\n svgSize: params.svgSize as number | undefined,\n })\n },\n brep: async (input: Shape, params: Record<string, unknown>) => {\n if (!input) throw new Error('[api/engrave] no input geometry')\n assertEngraveParams(params)\n const svgText = await resolveEngraveSvg(params)\n return engraveBrepPath(input, params, svgText)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n})\n"]}
1
+ {"version":3,"file":"engrave.js","sourceRoot":"","sources":["../../src/api/engrave.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * api engrave — 雕刻库函数\n *\n *\n * dispatchPath 静态判定 brep/mesh。\n * BREP 路径:textToSolid/svgToSolid + boolean(cut/fuse)。\n */\n\nimport type { Shape, Vec3 } from '../mesh/types'\nimport type { BrepHandle } from '../brep/engine/types'\nimport type { BrepEngineApi } from '../brep/engine/primitives'\nimport type { AssetResolver } from '../cad-runtime/ports'\n// B3 correction (2026-10-06): no library-face cad aggregate — import the impl from its own module.\nimport * as meshEngrave from '../mesh/engrave'\nimport { parseSvgNaturalSize } from '../primitives/parse-svg-size'\nimport { textToSolid } from '../brep/text/text-to-solid'\nimport { svgToSolid } from '../brep/svg/svg-to-solid'\nimport { ensureDefaultFont } from '../brep/text/fontRegistry'\nimport { solidToShape } from '../brep/brep-ops'\nimport { getSolidBoundingBox } from '../brep/brep-utils'\nimport { resolveSvgArg } from './internal/svg-asset-resolver'\nimport { getBackends } from '../runtime-state'\nimport { getBrepApi } from '../brep/handle-bridge'\nimport { fromBrep, brepOf } from '../shape'\nimport { defineOp } from '../sdk'\nimport type { Provenance } from '../topology/naming/lineage'\nimport { assertPositiveNumber } from './assert'\n\n// ── per-op 参数自校验(Phase 2.2;api 层被直接 import 时的防御层) ──\n\n/**\n * Validate engrave parameters: at least one of `text` or `svg` must be\n * provided, and `depth` (if provided) must be a positive number.\n * @param params - the raw engrave operation parameters.\n */\nexport function assertEngraveParams(params: Record<string, unknown>): void {\n const hasText = params.text !== undefined && params.text !== null && params.text !== ''\n const hasSvg = params.svg !== undefined && params.svg !== null\n if (!hasText && !hasSvg) {\n throw new Error('[api/engrave] requires either \"text\" or \"svg\"')\n }\n if (params.depth !== undefined && params.depth !== null) {\n assertPositiveNumber(params.depth, 'engrave.depth')\n }\n}\n\n/** 计算将 +Z 轴对齐到目标法向量的 3x4 仿射变换矩阵(仅旋转,无平移,Rodrigues 公式)。 */\nfunction alignZToNormal(normal: Vec3): number[] {\n const [nx, ny, nz] = normal\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz)\n if (len < 1e-10) {\n return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]\n }\n const ux = nx / len, uy = ny / len, uz = nz / len\n\n if (Math.abs(ux) < 1e-10 && Math.abs(uy) < 1e-10) {\n if (uz > 0) return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]\n return [1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0]\n }\n\n const s = Math.sqrt(ux * ux + uy * uy)\n const c = uz\n const t = 1 - c\n const ax = -uy / s, ay = ux / s\n\n return [\n c + ax * ax * t, ax * ay * t, ay * s, 0,\n ax * ay * t, c + ay * ay * t, -ax * s, 0,\n -ay * s, ax * s, c, 0,\n ]\n}\n\n/** 将 solid 居中到原点(基于包围盒中心,与 mesh 路径语义一致)。 */\nfunction centerSolidAtOrigin(kernel: BrepEngineApi, solid: BrepHandle): BrepHandle {\n const bb = getSolidBoundingBox(kernel, solid)\n const cx = (bb.min[0] + bb.max[0]) / 2\n const cy = (bb.min[1] + bb.max[1]) / 2\n const cz = (bb.min[2] + bb.max[2]) / 2\n const centered = kernel.translate(solid, -cx, -cy, -cz)\n kernel.release(solid)\n return centered\n}\n\n/** BREP 路径:textToSolid/svgToSolid + boolean(cut/fuse)。 */\nasync function engraveBrepPath(input: Shape, params: Record<string, unknown>, svgText?: string): Promise<Shape> {\n const kernel = getBrepApi()\n const inputSolid = brepOf(input) as BrepHandle | undefined\n if (!inputSolid) throw new Error('[api/engrave] input is not BREP')\n\n const depth = params.depth as number\n const mode = (params.mode as 'convex' | 'concave' | undefined) ?? 'concave'\n const text = params.text as string | undefined\n\n // 1. 创建装饰 solid(文字或 SVG),depth 与 mesh 路径一致\n let decorationSolid: BrepHandle\n if (text) {\n await ensureDefaultFont()\n const textSize = (params.textSize as number) ?? 10\n decorationSolid = textToSolid(kernel, text, { fontSize: textSize, depth })\n } else if (svgText) {\n decorationSolid = svgToSolid(kernel, svgText, {\n depth,\n targetLongSide: (params.svgSize as number) ?? 20,\n })\n } else {\n throw new Error('[api/engrave] neither text nor svg provided')\n }\n\n // 2. 居中到原点\n decorationSolid = centerSolidAtOrigin(kernel, decorationSolid)\n\n // 3. 旋转 +Z 对齐面法向\n const worldFaceNormal: Vec3 = (params.faceNormal as Vec3) ?? [0, 0, 1]\n const rotMatrix = alignZToNormal(worldFaceNormal)\n const rotated = kernel.transform(decorationSolid, rotMatrix)\n kernel.release(decorationSolid)\n\n // 4. 沿法向偏移 + 平移到面中心(凸 offset=+depth/2,凹 offset=-depth/2;加 0.01 避免共面)\n // faceCenter/faceNormal 契约(方向 A):模型局部空间值(宿主生成脚本时已把交互\n // 世界坐标转换好),本 op 不做 world→local(无 partTransform 依赖)。\n const localFaceCenter: Vec3 = (params.faceCenter as Vec3) ?? [0, 0, 0]\n const offset = mode === 'convex' ? depth / 2 : -depth / 2\n const epsilon = 0.01\n const tx = localFaceCenter[0] + worldFaceNormal[0] * (offset + epsilon)\n const ty = localFaceCenter[1] + worldFaceNormal[1] * (offset + epsilon)\n const tz = localFaceCenter[2] + worldFaceNormal[2] * (offset + epsilon)\n const positioned = kernel.translate(rotated, tx, ty, tz)\n kernel.release(rotated)\n\n // 5. 布尔运算(凸=fuse,凹=cut)\n const isRaised = mode === 'convex'\n let result: BrepHandle\n if (isRaised) {\n result = kernel.fuse(inputSolid, positioned)\n } else {\n result = kernel.cut(inputSolid, positioned)\n }\n kernel.release(positioned)\n\n // 5b. cut 可能分裂成多个 solid(compound),用 fuseAll 合并回单一 solid\n try {\n const subSolids = kernel.getSubShapes(result, 'solid')\n if (subSolids.length > 1) {\n const fused = kernel.fuseAll(subSolids)\n for (const s of subSolids) {\n try { kernel.release(s) } catch { /* 已释放 */ }\n }\n try { kernel.release(result) } catch { /* 已释放 */ }\n result = fused\n }\n } catch {\n // getSubShapes 失败说明结果不是 compound,无需处理\n }\n\n return fromBrep(solidToShape(kernel, result), { solid: result })\n}\n\n/** 解析 SVG 资产引用(AssetRef → SVG 文本),两条路径共享;无 svg 返回 undefined。 */\nasync function resolveEngraveSvg(params: Record<string, unknown>): Promise<string | undefined> {\n return params.svg !== undefined && params.svg !== null\n ? await resolveSvgArg(params.svg, { assets: getBackends().assets as AssetResolver | undefined })\n : undefined\n}\n\n/**\n * 在几何表面雕刻文字或 SVG(文字分支与 logo 分支都可用)。\n * @group 特征\n * @inputs 1\n * @async true\n * @qual ok\n * @name engrave\n * @returns Shape 雕刻后的几何。\n * @param input - 目标几何。type:Shape required:true\n * @param params.mode - 雕刻方式:concave 凹陷(减法)/ convex 凸出(加法)。type:'concave' | 'convex' 默认 'concave'\n * @param params.depth - 深度 / 凸出高度(mm)。type:number 默认 0\n * @param params.text - 文字内容(与 svg 二选一)。type:string\n * @param params.textSize - 字号(mm)。type:number 默认 10\n * @param params.svg - SVG 资产引用(与 text 二选一;经 cad.asset 解析)。type:string\n * @param params.svgSize - SVG 长边目标尺寸。type:number\n * @param params.faceCenter - 面位置(绝对坐标)。type:[x,y,z] 默认 [0,0,0]\n * @param params.faceNormal - 面法向。type:[x,y,z] 默认 [0,0,1]\n * @note 早期 logo 分支用 `svgText`(整份 XML 拷贝 + `svgSize` 文本导出丢失,往返失真);现已改为 `svg` 资产引用,`engravingType` 冗余键已移除。faceCenter/faceNormal 目前是绝对坐标快照。\n * @example\n * const p = await cad.engrave(part0, { mode: 'concave', depth: 2, text: 'Hello', textSize: 10, faceCenter: [0, 0, 0], faceNormal: [0, 0, -1] })\n */\nexport const engrave = defineOp({\n mesh: async (input: Shape, params: Record<string, unknown>) => {\n if (!input) throw new Error('[api/engrave] no input geometry')\n assertEngraveParams(params)\n const svgText = await resolveEngraveSvg(params)\n // mesh 路径\n const faceCenter: Vec3 = (params.faceCenter as Vec3) ?? [0, 0, 0]\n const faceNormal: Vec3 = (params.faceNormal as Vec3) ?? [0, 0, 1]\n const { naturalWidth, naturalHeight } = svgText ? parseSvgNaturalSize(svgText) : { naturalWidth: 0, naturalHeight: 0 }\n const hasText = !!(params.text as string | undefined)\n\n return meshEngrave.engrave(input, {\n mode: (params.mode as 'convex' | 'concave' | undefined) ?? 'concave',\n depth: params.depth as number,\n face: { center: faceCenter, normal: faceNormal },\n text: hasText ? (params.text as string) : undefined,\n textSize: params.textSize as number | undefined,\n svg: svgText,\n svgNaturalWidth: naturalWidth,\n svgNaturalHeight: naturalHeight,\n svgSize: params.svgSize as number | undefined,\n })\n },\n brep: async (input: Shape, params: Record<string, unknown>) => {\n if (!input) throw new Error('[api/engrave] no input geometry')\n assertEngraveParams(params)\n const svgText = await resolveEngraveSvg(params)\n return engraveBrepPath(input, params, svgText)\n },\n naming: { kind: 'kernel', newFaces: { via: 'byAdjacency' } } as Provenance,\n})\n"]}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * api export3mf — 3MF 导出(脚本面薄壳:宿主门 + 库面序列化器)
3
+ *
4
+ * §2.6 定式 1「薄壳 + 门禁,不重写格式逻辑」:本体只做三件事——宿主门
5
+ * (`assertHostFor`)→ 把入参转成 `ExportEntry[]` → 调库面序列化器
6
+ * `exportModelSync(entries, '3mf', { unit })`。因此脚本面与库面**天然逐字节同源**
7
+ * (矩阵 B14)。
8
+ *
9
+ * **无引擎门**(与 `exportStep` 的差别):faijs 的 3MF 写出器是纯 XML + ZIP
10
+ * (`build3mfModelXml` + `writeZipEntries`),与引擎身份无关;只有「活句柄 → 三角
11
+ * 载荷」这一条兜底路径需要内核,且它对 occt / brepkit 一视同仁(走 `getBrepApi()`
12
+ * 的当前引擎,不做身份断言)。
13
+ *
14
+ * **宿主门**:与其余导出命令同轴(§2.5),仅 `'node'` 宿主开放。理由:`.fai.js` 可
15
+ * 由 AI 生成任意代码、属不受信输入,导出把「往哪写、写几份、写什么」的决定权交给
16
+ * 脚本文本;浏览器 / 小程序里要导出模型必须由宿主入口发起。断言写在函数体第一行,
17
+ * 所以脚本面 `cad.*` 与 TS 直连同一函数都被同一门禁覆盖。
18
+ *
19
+ * **条目必须是 `mesh`,且不得是空 mesh**(定式 4 / P8):`build3mfModelXml` 对无
20
+ * `mesh` 的条目**静默跳过**(`export-model.ts:330` 的 `if (!e.mesh) return`),只给
21
+ * `solid` 会产出「ZIP 合法但对象为空」的假成功。故本 op 只交 `mesh` 条目,且三角数
22
+ * 为 0 的成员视为不可导出;全体不可导出时**显式报错**,不落空文件。
23
+ *
24
+ * **三角载荷取自 Shape 自身,而非二次三角化**(对 §2.6 定式 4 措辞的按证据修正):
25
+ * 定式 4 原话是「3mf 先 `solidToShape` 三角化再给 `mesh`」,但其依据是
26
+ * `cli.ts#writeOutput` 的 `brepSolid` 分支——那里 solid 来自独立快照表、`shape` 可能
27
+ * 只有 mesh,故必须先三角化。本 op 的入参 Shape 由执行链产出时**已带当前显示 mesh**
28
+ * (mesh 链由构造器填、brep 链由 `fromHandle` → `meshHandle` 填)。再走一遍
29
+ * `solidToShape` 会**二次三角化**并换掉默认精度:`meshHandle` 缺省 segments=32
30
+ * (`brep/handle-bridge.ts:125`),`solidToShape` 缺省 2π/64(`brep/brep-ops.ts:68`),
31
+ * 两者产出的是**两份不同的 mesh**——违反「导出所用 mesh 必须是用户看到的 mesh」
32
+ * (规则 1),与 `api/export-stl.ts` 拒绝走原生二次三角化是同一取舍。故只在 Shape
33
+ * 自带的三角载荷缺席 / 为空时(例如只有 BREP 槽的跨库产物)才用 `solidToShape` 兜底。
34
+ */
35
+ import type { Shape } from '../mesh/types.js';
36
+ import type { CompoundShape } from '../shape.js';
37
+ import type { UnitName } from '../units.js';
38
+ /** `cad.export3mf` 选项。 */
39
+ export interface Export3mfOptions {
40
+ /**
41
+ * 文件里声明的长度单位(缺省 `'mm'`)。语义与库面 `ExportOptions.unit` 一致:
42
+ * 实现负责把坐标换算到该刻度,并与 `<model unit>` 成对写出(§10.3 规则 3);
43
+ * `yard` 无 3MF 枚举值,库面成对回落到 mm(§10.3 规则 2)。
44
+ */
45
+ unit?: UnitName;
46
+ }
47
+ /**
48
+ * 导出 3MF(ZIP 容器字节)。
49
+ * @group 导出
50
+ * @inputs 1
51
+ * @async false
52
+ * @qual ok
53
+ * @name export3mf
54
+ * @note 薄壳 op:条目构造后一律交库面 `exportModelSync(entries,'3mf',{unit})` 序列化,
55
+ * 故同一入参下脚本面字节与库面**逐字节一致**(同一真源)。返回 **ZIP 字节**
56
+ * (`Uint8Array`),由宿主写入 `.3mf` 文件——内核不 import fs。`unit` 只声明单位
57
+ * (写 `<model unit>`),坐标随之换算,两者同源(缺省 mm)。
58
+ * 入参可为单件 Shape 或装配 compound;compound 逐成员导出并带上成员名与
59
+ * `memberColors`(basematerials)。条目**只交 mesh**:无 mesh 的条目会被写出器
60
+ * 静默跳过、产出「ZIP 合法但对象为空」的假成功,故三角数为 0 的成员视为不可导出,
61
+ * 全体不可导出时显式报 E_EXPORT_3MF_EMPTY。
62
+ * **宿主门**:仅 `'node'` 宿主可执行;browser / weapp / 未声明宿主报
63
+ * E_HOST_UNSUPPORTED(门在读取载荷之前)。无引擎门——写出器是纯 XML + ZIP,
64
+ * 与引擎身份无关。
65
+ * @returns Uint8Array 3MF(ZIP)字节。
66
+ * @param shape - 目标几何(单件 Shape 或装配 compound)。type:Shape|CompoundShape required:true
67
+ * @param options.unit - 文件里声明的长度单位,缺省 mm(坐标随之换算)。type:UnitName
68
+ * @example
69
+ * const bytes = cad.export3mf(part0)
70
+ * const asmBytes = cad.export3mf(asm1)
71
+ */
72
+ export declare function export3mf(shape: Shape | CompoundShape, options?: Export3mfOptions): Uint8Array;
73
+ //# sourceMappingURL=export-3mf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-3mf.d.ts","sourceRoot":"","sources":["../../src/api/export-3mf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAQxC,0BAA0B;AAC1B,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAA;CAChB;AAmCD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,aAAa,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,UAAU,CAe9F"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * api export3mf — 3MF 导出(脚本面薄壳:宿主门 + 库面序列化器)
3
+ *
4
+ * §2.6 定式 1「薄壳 + 门禁,不重写格式逻辑」:本体只做三件事——宿主门
5
+ * (`assertHostFor`)→ 把入参转成 `ExportEntry[]` → 调库面序列化器
6
+ * `exportModelSync(entries, '3mf', { unit })`。因此脚本面与库面**天然逐字节同源**
7
+ * (矩阵 B14)。
8
+ *
9
+ * **无引擎门**(与 `exportStep` 的差别):faijs 的 3MF 写出器是纯 XML + ZIP
10
+ * (`build3mfModelXml` + `writeZipEntries`),与引擎身份无关;只有「活句柄 → 三角
11
+ * 载荷」这一条兜底路径需要内核,且它对 occt / brepkit 一视同仁(走 `getBrepApi()`
12
+ * 的当前引擎,不做身份断言)。
13
+ *
14
+ * **宿主门**:与其余导出命令同轴(§2.5),仅 `'node'` 宿主开放。理由:`.fai.js` 可
15
+ * 由 AI 生成任意代码、属不受信输入,导出把「往哪写、写几份、写什么」的决定权交给
16
+ * 脚本文本;浏览器 / 小程序里要导出模型必须由宿主入口发起。断言写在函数体第一行,
17
+ * 所以脚本面 `cad.*` 与 TS 直连同一函数都被同一门禁覆盖。
18
+ *
19
+ * **条目必须是 `mesh`,且不得是空 mesh**(定式 4 / P8):`build3mfModelXml` 对无
20
+ * `mesh` 的条目**静默跳过**(`export-model.ts:330` 的 `if (!e.mesh) return`),只给
21
+ * `solid` 会产出「ZIP 合法但对象为空」的假成功。故本 op 只交 `mesh` 条目,且三角数
22
+ * 为 0 的成员视为不可导出;全体不可导出时**显式报错**,不落空文件。
23
+ *
24
+ * **三角载荷取自 Shape 自身,而非二次三角化**(对 §2.6 定式 4 措辞的按证据修正):
25
+ * 定式 4 原话是「3mf 先 `solidToShape` 三角化再给 `mesh`」,但其依据是
26
+ * `cli.ts#writeOutput` 的 `brepSolid` 分支——那里 solid 来自独立快照表、`shape` 可能
27
+ * 只有 mesh,故必须先三角化。本 op 的入参 Shape 由执行链产出时**已带当前显示 mesh**
28
+ * (mesh 链由构造器填、brep 链由 `fromHandle` → `meshHandle` 填)。再走一遍
29
+ * `solidToShape` 会**二次三角化**并换掉默认精度:`meshHandle` 缺省 segments=32
30
+ * (`brep/handle-bridge.ts:125`),`solidToShape` 缺省 2π/64(`brep/brep-ops.ts:68`),
31
+ * 两者产出的是**两份不同的 mesh**——违反「导出所用 mesh 必须是用户看到的 mesh」
32
+ * (规则 1),与 `api/export-stl.ts` 拒绝走原生二次三角化是同一取舍。故只在 Shape
33
+ * 自带的三角载荷缺席 / 为空时(例如只有 BREP 槽的跨库产物)才用 `solidToShape` 兜底。
34
+ */
35
+ import { brepOf } from '../shape.js';
36
+ import { getBrepApi } from '../brep/handle-bridge.js';
37
+ import { solidToShape } from '../brep/brep-ops.js';
38
+ import { exportModelSync } from '../brep/export/export-model.js';
39
+ import { exportTreeOf } from './internal/export-members.js';
40
+ import { assertHostFor } from './internal/l3-bridge.js';
41
+ /** 节点自带的三角载荷(非空才算数)。 */
42
+ function ownMeshOf(node) {
43
+ const positions = node.shape?.positions;
44
+ const indices = node.shape?.indices;
45
+ if (!positions || !indices)
46
+ return undefined;
47
+ if (positions.length === 0 || indices.length === 0)
48
+ return undefined;
49
+ return { positions, indices };
50
+ }
51
+ /**
52
+ * 一个成员树节点 → 3mf 条目:递归携带 children(装配层级 → `<components>`)。
53
+ * 只产出带非空 `mesh` 的节点,或带 children 的容器(无 mesh 的节点会被写出器静默
54
+ * 跳过,故容器节点若无 mesh 仅以 `<components>` 表达层级,符合 3MF Core 规范)。
55
+ */
56
+ function entryOfNode(node) {
57
+ let mesh = ownMeshOf(node);
58
+ if (!mesh) {
59
+ // 兜底:Shape 只有 BREP 槽(跨库产物)时现场三角化一次;引擎身份中立。
60
+ const handle = brepOf(node.shape);
61
+ if (handle) {
62
+ const tri = solidToShape(getBrepApi(), handle);
63
+ if (tri.indices.length > 0)
64
+ mesh = { positions: tri.positions, indices: tri.indices };
65
+ }
66
+ }
67
+ const entry = {};
68
+ if (node.name !== undefined)
69
+ entry.name = node.name;
70
+ if (node.color !== undefined)
71
+ entry.color = node.color;
72
+ if (node.transform)
73
+ entry.transform = node.transform;
74
+ if (mesh)
75
+ entry.mesh = mesh;
76
+ if (node.children?.length)
77
+ entry.children = node.children.map(entryOfNode);
78
+ return entry;
79
+ }
80
+ /**
81
+ * 导出 3MF(ZIP 容器字节)。
82
+ * @group 导出
83
+ * @inputs 1
84
+ * @async false
85
+ * @qual ok
86
+ * @name export3mf
87
+ * @note 薄壳 op:条目构造后一律交库面 `exportModelSync(entries,'3mf',{unit})` 序列化,
88
+ * 故同一入参下脚本面字节与库面**逐字节一致**(同一真源)。返回 **ZIP 字节**
89
+ * (`Uint8Array`),由宿主写入 `.3mf` 文件——内核不 import fs。`unit` 只声明单位
90
+ * (写 `<model unit>`),坐标随之换算,两者同源(缺省 mm)。
91
+ * 入参可为单件 Shape 或装配 compound;compound 逐成员导出并带上成员名与
92
+ * `memberColors`(basematerials)。条目**只交 mesh**:无 mesh 的条目会被写出器
93
+ * 静默跳过、产出「ZIP 合法但对象为空」的假成功,故三角数为 0 的成员视为不可导出,
94
+ * 全体不可导出时显式报 E_EXPORT_3MF_EMPTY。
95
+ * **宿主门**:仅 `'node'` 宿主可执行;browser / weapp / 未声明宿主报
96
+ * E_HOST_UNSUPPORTED(门在读取载荷之前)。无引擎门——写出器是纯 XML + ZIP,
97
+ * 与引擎身份无关。
98
+ * @returns Uint8Array 3MF(ZIP)字节。
99
+ * @param shape - 目标几何(单件 Shape 或装配 compound)。type:Shape|CompoundShape required:true
100
+ * @param options.unit - 文件里声明的长度单位,缺省 mm(坐标随之换算)。type:UnitName
101
+ * @example
102
+ * const bytes = cad.export3mf(part0)
103
+ * const asmBytes = cad.export3mf(asm1)
104
+ */
105
+ export function export3mf(shape, options) {
106
+ // 宿主门在实现体最前:非 node 宿主先报 E_HOST_UNSUPPORTED,不读取载荷、不产字节。
107
+ assertHostFor('export3mf', ['node']);
108
+ const entries = exportTreeOf(shape)
109
+ .map(entryOfNode)
110
+ .filter((e) => e.mesh !== undefined || (e.children?.length ?? 0) > 0);
111
+ if (entries.length === 0) {
112
+ throw new Error('E_EXPORT_3MF_EMPTY: export3mf input has no exportable member (empty assembly or members without triangles)');
113
+ }
114
+ const buffer = exportModelSync(entries, '3mf', options?.unit === undefined ? undefined : { unit: options.unit });
115
+ const bytes = new Uint8Array(buffer);
116
+ if (bytes.length === 0) {
117
+ throw new Error('E_EXPORT_3MF_EMPTY: 3MF writer produced no bytes');
118
+ }
119
+ return bytes;
120
+ }
121
+ //# sourceMappingURL=export-3mf.js.map