@faicad/faijs 0.32.2 → 0.33.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 (195) hide show
  1. package/dist/api/api-namespace.js +3 -3
  2. package/dist/api/api-namespace.js.map +1 -1
  3. package/dist/api/assembly/index.d.ts +1 -0
  4. package/dist/api/assembly/index.d.ts.map +1 -1
  5. package/dist/api/assembly/index.js +1 -0
  6. package/dist/api/assembly/index.js.map +1 -1
  7. package/dist/api/assembly/lower.d.ts.map +1 -1
  8. package/dist/api/assembly/lower.js +7 -0
  9. package/dist/api/assembly/lower.js.map +1 -1
  10. package/dist/api/assembly/normalize.d.ts.map +1 -1
  11. package/dist/api/assembly/normalize.js +2 -1
  12. package/dist/api/assembly/normalize.js.map +1 -1
  13. package/dist/api/assembly/solve-tree.d.ts +46 -0
  14. package/dist/api/assembly/solve-tree.d.ts.map +1 -0
  15. package/dist/api/assembly/solve-tree.js +135 -0
  16. package/dist/api/assembly/solve-tree.js.map +1 -0
  17. package/dist/api/assembly/solve.d.ts +7 -0
  18. package/dist/api/assembly/solve.d.ts.map +1 -1
  19. package/dist/api/assembly/solve.js.map +1 -1
  20. package/dist/api/assembly/solvers/assembly-tree.d.ts +4 -0
  21. package/dist/api/assembly/solvers/assembly-tree.d.ts.map +1 -1
  22. package/dist/api/assembly/solvers/assembly-tree.js +1 -0
  23. package/dist/api/assembly/solvers/assembly-tree.js.map +1 -1
  24. package/dist/api/assembly/solvers/global-solver.d.ts.map +1 -1
  25. package/dist/api/assembly/solvers/global-solver.js +210 -3
  26. package/dist/api/assembly/solvers/global-solver.js.map +1 -1
  27. package/dist/api/assembly/solvers/types.d.ts +8 -0
  28. package/dist/api/assembly/solvers/types.d.ts.map +1 -1
  29. package/dist/api/assembly/solvers/types.js.map +1 -1
  30. package/dist/api/assembly/types.d.ts +32 -1
  31. package/dist/api/assembly/types.d.ts.map +1 -1
  32. package/dist/api/assembly/types.js.map +1 -1
  33. package/dist/api/assembly/validate.d.ts +2 -2
  34. package/dist/api/assembly/validate.d.ts.map +1 -1
  35. package/dist/api/assembly/validate.js +24 -2
  36. package/dist/api/assembly/validate.js.map +1 -1
  37. package/dist/api/cadquery-selectors/edge.js +1 -1
  38. package/dist/api/cadquery-selectors/edge.js.map +1 -1
  39. package/dist/api/cadquery-selectors/entity.d.ts +29 -20
  40. package/dist/api/cadquery-selectors/entity.d.ts.map +1 -1
  41. package/dist/api/cadquery-selectors/entity.js +26 -20
  42. package/dist/api/cadquery-selectors/entity.js.map +1 -1
  43. package/dist/api/cadquery-selectors/face.d.ts +4 -2
  44. package/dist/api/cadquery-selectors/face.d.ts.map +1 -1
  45. package/dist/api/cadquery-selectors/face.js +8 -7
  46. package/dist/api/cadquery-selectors/face.js.map +1 -1
  47. package/dist/api/cadquery-selectors/resolve.d.ts +7 -6
  48. package/dist/api/cadquery-selectors/resolve.d.ts.map +1 -1
  49. package/dist/api/cadquery-selectors/resolve.js +13 -11
  50. package/dist/api/cadquery-selectors/resolve.js.map +1 -1
  51. package/dist/api/chamfer.js +1 -1
  52. package/dist/api/chamfer.js.map +1 -1
  53. package/dist/api/draft.js +1 -1
  54. package/dist/api/draft.js.map +1 -1
  55. package/dist/api/edge-ref.js +2 -2
  56. package/dist/api/edge-ref.js.map +1 -1
  57. package/dist/api/engrave.js +1 -1
  58. package/dist/api/engrave.js.map +1 -1
  59. package/dist/api/export-3mf.js +1 -1
  60. package/dist/api/export-3mf.js.map +1 -1
  61. package/dist/api/export-brep.js +1 -1
  62. package/dist/api/export-brep.js.map +1 -1
  63. package/dist/api/export-step.d.ts +12 -13
  64. package/dist/api/export-step.d.ts.map +1 -1
  65. package/dist/api/export-step.js +19 -17
  66. package/dist/api/export-step.js.map +1 -1
  67. package/dist/api/extrude.js +3 -3
  68. package/dist/api/extrude.js.map +1 -1
  69. package/dist/api/face-ref.js +2 -2
  70. package/dist/api/face-ref.js.map +1 -1
  71. package/dist/api/feature-repair.js +2 -2
  72. package/dist/api/feature-repair.js.map +1 -1
  73. package/dist/api/fillet-variable.js +1 -1
  74. package/dist/api/fillet-variable.js.map +1 -1
  75. package/dist/api/fillet.js +1 -1
  76. package/dist/api/fillet.js.map +1 -1
  77. package/dist/api/geom.js +1 -1
  78. package/dist/api/geom.js.map +1 -1
  79. package/dist/api/import-step.d.ts.map +1 -1
  80. package/dist/api/import-step.js +4 -2
  81. package/dist/api/import-step.js.map +1 -1
  82. package/dist/api/pattern.js +1 -1
  83. package/dist/api/pattern.js.map +1 -1
  84. package/dist/api/place.js +1 -1
  85. package/dist/api/place.js.map +1 -1
  86. package/dist/api/punch-hole.js +1 -1
  87. package/dist/api/punch-hole.js.map +1 -1
  88. package/dist/api/replicate.js +1 -1
  89. package/dist/api/replicate.js.map +1 -1
  90. package/dist/api/revolve.js +1 -1
  91. package/dist/api/revolve.js.map +1 -1
  92. package/dist/api/section-by-plane.js +1 -1
  93. package/dist/api/section-by-plane.js.map +1 -1
  94. package/dist/api/shell.js +1 -1
  95. package/dist/api/shell.js.map +1 -1
  96. package/dist/api/sketch-on-face.js +1 -1
  97. package/dist/api/sketch-on-face.js.map +1 -1
  98. package/dist/api/split-by-plane.js +1 -1
  99. package/dist/api/split-by-plane.js.map +1 -1
  100. package/dist/api/split.js +1 -1
  101. package/dist/api/split.js.map +1 -1
  102. package/dist/api/thicken.js +1 -1
  103. package/dist/api/thicken.js.map +1 -1
  104. package/dist/api/topo-resolve.js +4 -4
  105. package/dist/api/topo-resolve.js.map +1 -1
  106. package/dist/api/transform.js +1 -1
  107. package/dist/api/transform.js.map +1 -1
  108. package/dist/api/view/view-projection.d.ts +8 -0
  109. package/dist/api/view/view-projection.d.ts.map +1 -1
  110. package/dist/api/view/view-projection.js +73 -2
  111. package/dist/api/view/view-projection.js.map +1 -1
  112. package/dist/boolean/cross-section.d.ts.map +1 -1
  113. package/dist/boolean/cross-section.js +3 -1
  114. package/dist/boolean/cross-section.js.map +1 -1
  115. package/dist/brep/brep-ops.d.ts +26 -0
  116. package/dist/brep/brep-ops.d.ts.map +1 -1
  117. package/dist/brep/brep-ops.js +45 -0
  118. package/dist/brep/brep-ops.js.map +1 -1
  119. package/dist/brep/brep-topology.js +1 -1
  120. package/dist/brep/brep-topology.js.map +1 -1
  121. package/dist/brep/engine/adapters/brep-mock.d.ts.map +1 -1
  122. package/dist/brep/engine/adapters/brep-mock.js +2 -0
  123. package/dist/brep/engine/adapters/brep-mock.js.map +1 -1
  124. package/dist/brep/engine/primitives.d.ts +17 -0
  125. package/dist/brep/engine/primitives.d.ts.map +1 -1
  126. package/dist/brep/engine/primitives.js.map +1 -1
  127. package/dist/brep/export/export-model.d.ts.map +1 -1
  128. package/dist/brep/export/export-model.js +36 -11
  129. package/dist/brep/export/export-model.js.map +1 -1
  130. package/dist/brep/export/step-flat.d.ts +35 -0
  131. package/dist/brep/export/step-flat.d.ts.map +1 -0
  132. package/dist/brep/export/step-flat.js +94 -0
  133. package/dist/brep/export/step-flat.js.map +1 -0
  134. package/dist/brep/export/step.d.ts.map +1 -1
  135. package/dist/brep/export/step.js +42 -21
  136. package/dist/brep/export/step.js.map +1 -1
  137. package/dist/brep/handle-bridge.d.ts +4 -4
  138. package/dist/brep/handle-bridge.js +4 -4
  139. package/dist/brep/handle-bridge.js.map +1 -1
  140. package/dist/brep/svg/svg-to-solid.d.ts +3 -17
  141. package/dist/brep/svg/svg-to-solid.d.ts.map +1 -1
  142. package/dist/brep/svg/svg-to-solid.js +16 -317
  143. package/dist/brep/svg/svg-to-solid.js.map +1 -1
  144. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  145. package/dist/brepkit-kernel/brepkitKernel.js +10 -0
  146. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  147. package/dist/brepkit-kernel/brepkitWasm.d.ts +1 -1
  148. package/dist/brepkit-kernel/brepkitWasm.d.ts.map +1 -1
  149. package/dist/brepkit-kernel/brepkitWasm.js +7 -6
  150. package/dist/brepkit-kernel/brepkitWasm.js.map +1 -1
  151. package/dist/brepkit-kernel/multi-version-test.d.ts +7 -7
  152. package/dist/brepkit-kernel/multi-version-test.d.ts.map +1 -1
  153. package/dist/brepkit-kernel/multi-version-test.js +10 -10
  154. package/dist/brepkit-kernel/multi-version-test.js.map +1 -1
  155. package/dist/cad-runtime/direct-executor.js +2 -2
  156. package/dist/cad-runtime/direct-executor.js.map +1 -1
  157. package/dist/cad-runtime/runtime.js +5 -5
  158. package/dist/cad-runtime/runtime.js.map +1 -1
  159. package/dist/geometry2d/curve2d.js +42 -1
  160. package/dist/geometry2d/curve2d.js.map +1 -1
  161. package/dist/math3d/Box3.js.map +1 -1
  162. package/dist/math3d/Euler.js.map +1 -1
  163. package/dist/math3d/Mat4.js.map +1 -1
  164. package/dist/math3d/Plane.js.map +1 -1
  165. package/dist/math3d/Quat.js.map +1 -1
  166. package/dist/math3d/Vec2.js.map +1 -1
  167. package/dist/math3d/Vec3.js.map +1 -1
  168. package/dist/math3d/index.js.map +1 -1
  169. package/dist/mesh/meshdata/contour.d.ts +34 -0
  170. package/dist/mesh/meshdata/contour.d.ts.map +1 -0
  171. package/dist/mesh/meshdata/contour.js +39 -0
  172. package/dist/mesh/meshdata/contour.js.map +1 -0
  173. package/dist/mesh/meshdata/extrude.d.ts +25 -0
  174. package/dist/mesh/meshdata/extrude.d.ts.map +1 -0
  175. package/dist/mesh/meshdata/extrude.js +198 -0
  176. package/dist/mesh/meshdata/extrude.js.map +1 -0
  177. package/dist/mesh/meshdata/index.js.map +1 -1
  178. package/dist/mesh/meshdata/ops.js.map +1 -1
  179. package/dist/mesh/meshdata/parametric.js.map +1 -1
  180. package/dist/mesh/meshdata/weld.js.map +1 -1
  181. package/dist/node-host/cli.d.ts.map +1 -1
  182. package/dist/node-host/cli.js +3 -2
  183. package/dist/node-host/cli.js.map +1 -1
  184. package/dist/occt-kernel/occt-primitives.d.ts.map +1 -1
  185. package/dist/occt-kernel/occt-primitives.js +2 -0
  186. package/dist/occt-kernel/occt-primitives.js.map +1 -1
  187. package/dist/primitives/svg/svg-path.d.ts +192 -0
  188. package/dist/primitives/svg/svg-path.d.ts.map +1 -0
  189. package/dist/primitives/svg/svg-path.js +776 -0
  190. package/dist/primitives/svg/svg-path.js.map +1 -0
  191. package/dist/third-party/earcut.d.ts +19 -0
  192. package/dist/third-party/earcut.d.ts.map +1 -0
  193. package/dist/third-party/earcut.js +575 -0
  194. package/dist/third-party/earcut.js.map +1 -0
  195. package/package.json +22 -3
@@ -0,0 +1,39 @@
1
+ /**
2
+ * meshdata/contour — 2D 轮廓类型(three `THREE.Shape` 的自有替代)。
3
+ *
4
+ * 语义对应:
5
+ * - `outer` ↔ three `Shape` 的外轮廓点集(points)
6
+ * - `holes` ↔ three `Shape.holes`(孔洞子路径)
7
+ * - 多条互不相交轮廓(`SVGLoader.createShapes` 返回 `Shape[]` 的情形)用 `Contour[]` 表达
8
+ *
9
+ * 坐标约定:**Y-up 平面坐标**(与 core 世界坐标系一致,+Z 向上、轮廓位于 XY 平面)。
10
+ * 从 SVG(Y-down)/ opentype(Y-down)来的数据由调用方负责翻转后再交给本模块。
11
+ */
12
+ /**
13
+ * Shoelace 有符号面积。Y-up 坐标系下 >0 为逆时针(CCW)。
14
+ * @param pts - 轮廓顶点(含首尾闭环约定则自动忽略重复尾点的影响)。
15
+ * @returns the signed area; 0 when fewer than 3 points.
16
+ */
17
+ export function signedArea2(pts) {
18
+ const n = pts.length;
19
+ if (n < 3)
20
+ return 0;
21
+ let area = 0;
22
+ for (let i = 0; i < n; i++) {
23
+ const j = (i + 1) % n;
24
+ area += pts[i].x * pts[j].y - pts[j].x * pts[i].y;
25
+ }
26
+ return area / 2;
27
+ }
28
+ /**
29
+ * 反转轮廓顶点顺序(用于 winding 归一:外环转 CCW、孔环转 CW)。
30
+ * @param pts - source points.
31
+ * @returns a new array with reversed order.
32
+ */
33
+ export function reverse2(pts) {
34
+ const out = new Array(pts.length);
35
+ for (let i = 0; i < pts.length; i++)
36
+ out[i] = pts[pts.length - 1 - i];
37
+ return out;
38
+ }
39
+ //# sourceMappingURL=contour.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contour.js","sourceRoot":"","sources":["../../../src/mesh/meshdata/contour.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAcH;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,GAAS;IACnC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAA;IACpB,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,CAAA;IACnB,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;QACrB,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACnD,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,CAAA;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAS;IAChC,MAAM,GAAG,GAAS,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;IACrE,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["/**\n * meshdata/contour — 2D 轮廓类型(three `THREE.Shape` 的自有替代)。\n *\n * 语义对应:\n * - `outer` ↔ three `Shape` 的外轮廓点集(points)\n * - `holes` ↔ three `Shape.holes`(孔洞子路径)\n * - 多条互不相交轮廓(`SVGLoader.createShapes` 返回 `Shape[]` 的情形)用 `Contour[]` 表达\n *\n * 坐标约定:**Y-up 平面坐标**(与 core 世界坐标系一致,+Z 向上、轮廓位于 XY 平面)。\n * 从 SVG(Y-down)/ opentype(Y-down)来的数据由调用方负责翻转后再交给本模块。\n */\n\n/** 2D 平面点(轮廓顶点)。 */\nexport interface P2 {\n x: number\n y: number\n}\n\n/** 一条 2D 轮廓:外环 + 孔环。 */\nexport interface Contour {\n outer: P2[]\n holes: P2[][]\n}\n\n/**\n * Shoelace 有符号面积。Y-up 坐标系下 >0 为逆时针(CCW)。\n * @param pts - 轮廓顶点(含首尾闭环约定则自动忽略重复尾点的影响)。\n * @returns the signed area; 0 when fewer than 3 points.\n */\nexport function signedArea2(pts: P2[]): number {\n const n = pts.length\n if (n < 3) return 0\n let area = 0\n for (let i = 0; i < n; i++) {\n const j = (i + 1) % n\n area += pts[i].x * pts[j].y - pts[j].x * pts[i].y\n }\n return area / 2\n}\n\n/**\n * 反转轮廓顶点顺序(用于 winding 归一:外环转 CCW、孔环转 CW)。\n * @param pts - source points.\n * @returns a new array with reversed order.\n */\nexport function reverse2(pts: P2[]): P2[] {\n const out: P2[] = new Array(pts.length)\n for (let i = 0; i < pts.length; i++) out[i] = pts[pts.length - 1 - i]\n return out\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import type { Shape } from '../types.js';
2
+ import type { Contour } from './contour.js';
3
+ export type { Contour, P2 } from './contour.js';
4
+ /** 拉伸配置。 */
5
+ export interface ExtrudeShapeOptions {
6
+ /** 曲线采样段数(曲线已在输入轮廓中折线化,本参数仅保留语义占位)。 */
7
+ curveSegments?: number;
8
+ /** 是否支持 bevel(本项目不支持,传 true 抛错)。 */
9
+ bevelEnabled?: boolean;
10
+ }
11
+ /**
12
+ * 将一组 2D 轮廓直线拉伸为 3D 网格(bevel off)。
13
+ *
14
+ * 输出为 three r162 `ExtrudeGeometry`(bevelEnabled:false)的同构三角流:
15
+ * `positions` = 每三角形 3 顶点副本(底→顶→侧壁),`indices` = 顺序 0..n-1,
16
+ * `normals` = 硬边法线(computeVertexNormals 于该非索引布局上)。
17
+ *
18
+ * @param contours - the closed 2D contours (Y-up) to extrude.
19
+ * @param depth - the extrusion depth along +Z.
20
+ * @param opts - optional settings.
21
+ * @returns the extruded indexed Shape (with per-vertex normals).
22
+ * @throws when bevel is requested (unsupported) or depth is non-positive.
23
+ */
24
+ export declare function extrudeShape(contours: Contour[], depth: number, opts?: ExtrudeShapeOptions): Shape;
25
+ //# sourceMappingURL=extrude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extrude.d.ts","sourceRoot":"","sources":["../../../src/mesh/meshdata/extrude.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AAErC,OAAO,KAAK,EAAE,OAAO,EAAM,MAAM,WAAW,CAAA;AAG5C,YAAY,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AAE5C,YAAY;AACZ,MAAM,WAAW,mBAAmB;IAClC,uCAAuC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,oCAAoC;IACpC,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAuBlG"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * meshdata/extrude — 2D 轮廓直线拉伸(three r162 `ExtrudeGeometry` 的自有替代)。
3
+ *
4
+ * 语义对齐 three r162 `ExtrudeGeometry`(bevelEnabled=false、steps=1、直线挤压):
5
+ * - **winding 归一**:外环强制顺时针(CW,Y-up 下 shoelace<0),孔环仅在外环被反转时
6
+ * 把 CW 孔反转(与 three `ExtrudeGeometry.js` L131–L151 行为逐行一致);
7
+ * - **顶点布局**:与 three 一致输出**非索引三角流**(每三角形 3 个独立顶点副本,
8
+ * 顺序 = 底面 faces → 顶面 faces → 侧壁 quad 拆 (a,b,d)+(b,c,d)),
9
+ * `indices` 为平凡顺序 0..n-1。因此 positions/normals 与 three r162 逐位一致,
10
+ * 且底/侧/顶棱边保留**硬边法线**(与 three computeVertexNormals 行为相同);
11
+ * - **三角化**:vendored earcut **2.2.4** ESM(`../third-party/earcut`,算法与 npm
12
+ * earcut@2.2.4 逐字节一致;注:three r162 内置 Earcut 与该 npm 版对凹多边形的
13
+ * 划分可能不同,golden 对照按**几何等价**断言、绝不搬 three 内部 Earcut)。
14
+ *
15
+ * 与 three 的差异(登记为设计决策):
16
+ * - three `Shape.extractPoints(curveSegments)` 会把每段(含直线)细分为
17
+ * curveSegments+1 个冗余点(LineCurve 插值点);本实现**不细分直线**(曲线已在
18
+ * `primitives/svg/svg-path.ts` / 文本链采样成折线)。直线的细分点与端点共线,
19
+ * 在几何(去重后)层面完全等价;golden 对照按三角形流逐位断言(见
20
+ * test/mesh/meshdata-extrude.test.ts),用例输入不含曲线段。
21
+ * - 不支持 bevel / extrudePath:传入即抛错(报错好于掩盖,全仓未使用)。
22
+ *
23
+ * 坐标约定:输入轮廓为 **Y-up 平面坐标**(+Z 向上),拉伸沿 +Z,
24
+ * 底面 z=0、顶面 z=depth。
25
+ */
26
+ // earcut 上游仅提供 CJS,浏览器/Vite 直接 serve 无法 default import;vendored
27
+ // ESM(`../third-party/earcut`,算法与 npm earcut@2.2.4 逐字节一致,ISC)。
28
+ import earcut from '../../third-party/earcut.js';
29
+ import { computeVertexNormals } from './ops.js';
30
+ import { signedArea2 } from './contour.js';
31
+ /**
32
+ * 将一组 2D 轮廓直线拉伸为 3D 网格(bevel off)。
33
+ *
34
+ * 输出为 three r162 `ExtrudeGeometry`(bevelEnabled:false)的同构三角流:
35
+ * `positions` = 每三角形 3 顶点副本(底→顶→侧壁),`indices` = 顺序 0..n-1,
36
+ * `normals` = 硬边法线(computeVertexNormals 于该非索引布局上)。
37
+ *
38
+ * @param contours - the closed 2D contours (Y-up) to extrude.
39
+ * @param depth - the extrusion depth along +Z.
40
+ * @param opts - optional settings.
41
+ * @returns the extruded indexed Shape (with per-vertex normals).
42
+ * @throws when bevel is requested (unsupported) or depth is non-positive.
43
+ */
44
+ export function extrudeShape(contours, depth, opts) {
45
+ if (opts?.bevelEnabled) {
46
+ throw new Error('[extrudeShape] bevel is not supported; use plain straight extrusion');
47
+ }
48
+ if (!(depth > 0)) {
49
+ throw new Error(`[extrudeShape] depth must be positive, got ${depth}`);
50
+ }
51
+ const positions = [];
52
+ for (const contour of contours) {
53
+ addContourShape(contour, depth, positions);
54
+ }
55
+ const indices = new Uint32Array(positions.length / 3);
56
+ for (let i = 0; i < indices.length; i++)
57
+ indices[i] = i;
58
+ const shape = {
59
+ positions: Float32Array.from(positions),
60
+ indices,
61
+ };
62
+ shape.normals = computeVertexNormals(shape);
63
+ return shape;
64
+ }
65
+ function addContourShape(contour, depth, positions) {
66
+ // 1. winding 归一(复刻 three L131–L151)
67
+ let outer = contour.outer.slice();
68
+ removeDupEndPts(outer);
69
+ if (outer.length < 3)
70
+ return;
71
+ const holes = contour.holes.map((h) => h.slice()).filter((h) => h.length >= 3);
72
+ for (const h of holes)
73
+ removeDupEndPts(h);
74
+ // 1b. 净化相邻重复点(零长度段)。opentype 字形路径常含连续命令终点相同的
75
+ // 退化段(如 `L 3.12,-0.098 L 3.12,-0.098`);earcut 2.2.4 对这类输入会输出
76
+ // 重叠/退化三角(same edge 出现 4 次 → 非流形)。主动删除相邻同坐标点,
77
+ // 使 earcut 输入与侧壁环一致(earcut 内部 filterPoints 仅删共线,不保证
78
+ // 对零长度段输出干净三角化)。
79
+ removeAdjacentDup(outer);
80
+ for (const h of holes)
81
+ removeAdjacentDup(h);
82
+ if (outer.length < 3)
83
+ return;
84
+ const reverse = !isClockWise(outer);
85
+ if (reverse) {
86
+ outer = outer.reverse();
87
+ for (const h of holes) {
88
+ if (isClockWise(h))
89
+ h.reverse();
90
+ }
91
+ }
92
+ // 2. earcut 三角化(外环 + 孔,earcut 2.2.x 与 three r162 内置输出一致)
93
+ const data = [];
94
+ const holeIndices = [];
95
+ for (const p of outer)
96
+ data.push(p.x, p.y);
97
+ for (const h of holes) {
98
+ holeIndices.push(data.length / 2);
99
+ for (const p of h)
100
+ data.push(p.x, p.y);
101
+ }
102
+ const faces = earcut(data, holeIndices.length > 0 ? holeIndices : undefined, 2);
103
+ // 顶点索引(earcut 输出)→ 坐标
104
+ const verts = [...outer];
105
+ for (const h of holes)
106
+ verts.push(...h);
107
+ const at = (i) => verts[i];
108
+ // 3a. 底面(法线朝 -Z):f3(c, b, a)
109
+ for (let i = 0; i < faces.length; i += 3) {
110
+ const p = at(faces[i + 2]);
111
+ positions.push(p.x, p.y, 0);
112
+ const q = at(faces[i + 1]);
113
+ positions.push(q.x, q.y, 0);
114
+ const r = at(faces[i]);
115
+ positions.push(r.x, r.y, 0);
116
+ }
117
+ // 3b. 顶面(法线朝 +Z):f3(a, b, c)
118
+ for (let i = 0; i < faces.length; i += 3) {
119
+ const p = at(faces[i]);
120
+ positions.push(p.x, p.y, depth);
121
+ const q = at(faces[i + 1]);
122
+ positions.push(q.x, q.y, depth);
123
+ const r = at(faces[i + 2]);
124
+ positions.push(r.x, r.y, depth);
125
+ }
126
+ // 3c. 侧壁:基于 earcut 输出三角的**边界边**(无向出现 1 次的边)生成 quad。
127
+ // - 内部共享边在相邻三角中方向相反(各出现 1 次有向)→ 必须按**无向** key 计数
128
+ // 才不会被误判为边界;
129
+ // - 这样底面/顶面的边界与侧壁严格共享同一组边 → 网格必然水密;
130
+ // earcut 内部会过滤共线点(filterPoints),若侧壁改用未过滤的输入环,
131
+ // 被滤点在侧壁有边、在顶底没有 → 出现开放边。本实现从几何上消除该不一致。
132
+ // - earcut 输出三角方向统一为外环方向(CW),边界边首次出现的有向方向
133
+ // (a→b) 即环方向 → quad 法线朝外。
134
+ const edgeCount = new Map();
135
+ for (let i = 0; i < faces.length; i += 3) {
136
+ const a = faces[i], b = faces[i + 1], c = faces[i + 2];
137
+ for (const [u, v] of [[a, b], [b, c], [c, a]]) {
138
+ const key = u < v ? `${u},${v}` : `${v},${u}`;
139
+ const entry = edgeCount.get(key);
140
+ if (entry) {
141
+ entry.n++;
142
+ }
143
+ else {
144
+ edgeCount.set(key, { a: u, b: v, n: 1 });
145
+ }
146
+ }
147
+ }
148
+ for (const { a, b, n } of edgeCount.values()) {
149
+ if (n !== 1)
150
+ continue;
151
+ const pa = at(a);
152
+ const pb = at(b);
153
+ // 与 three `sidewalls` 相同的 quad 拆分,但取**反向边 (b→a)**:
154
+ // three 的 sidewalls 从 contour 尾部向前遍历(等价于取环反向),本实现
155
+ // 直接以反向边构造 quad —— tri (a底, b底, a顶) + tri (b底, b顶, a顶),
156
+ // 法线朝外(earcut 外环为数学 CW,正向 (a→b) 沿 CW 行进右转朝内)。
157
+ positions.push(pa.x, pa.y, 0);
158
+ positions.push(pb.x, pb.y, 0);
159
+ positions.push(pa.x, pa.y, depth);
160
+ positions.push(pb.x, pb.y, 0);
161
+ positions.push(pb.x, pb.y, depth);
162
+ positions.push(pa.x, pa.y, depth);
163
+ }
164
+ }
165
+ /**
166
+ * three `ShapeUtils.isClockWise`:shoelace 面积 < 0 即顺时针(Y-up,与
167
+ * three `ShapeUtils.area(pts) < 0` 逐字一致)。注意数学约定里逆时针为正,
168
+ * three 命名 "isClockWise" 判的是面积为负(数学 CW);本实现与 three 对齐。
169
+ */
170
+ function isClockWise(pts) {
171
+ return signedArea2(pts) < 0;
172
+ }
173
+ /** three `removeDupEndPts`:删除与首点重复的尾点。 */
174
+ function removeDupEndPts(pts) {
175
+ const l = pts.length;
176
+ if (l > 2 && Math.abs(pts[l - 1].x - pts[0].x) < 1e-12 && Math.abs(pts[l - 1].y - pts[0].y) < 1e-12) {
177
+ pts.pop();
178
+ }
179
+ }
180
+ /**
181
+ * 删除环上相邻的重复坐标点(零长度段),循环至稳定。
182
+ * 判定容差 1e-9(比 earcut filterPoints 的严格 ===0 更宽,保证净化后的环
183
+ * 不再含任何可判定的零长度段;共线非重复点仍留给 earcut 处理)。
184
+ */
185
+ function removeAdjacentDup(pts) {
186
+ let changed = true;
187
+ while (changed && pts.length >= 3) {
188
+ changed = false;
189
+ for (let i = pts.length - 1; i >= 0; i--) {
190
+ const j = i + 1 >= pts.length ? 0 : i + 1;
191
+ if (Math.abs(pts[i].x - pts[j].x) < 1e-9 && Math.abs(pts[i].y - pts[j].y) < 1e-9) {
192
+ pts.splice(i, 1);
193
+ changed = true;
194
+ }
195
+ }
196
+ }
197
+ }
198
+ //# sourceMappingURL=extrude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extrude.js","sourceRoot":"","sources":["../../../src/mesh/meshdata/extrude.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * meshdata/extrude — 2D 轮廓直线拉伸(three r162 `ExtrudeGeometry` 的自有替代)。\n *\n * 语义对齐 three r162 `ExtrudeGeometry`(bevelEnabled=false、steps=1、直线挤压):\n * - **winding 归一**:外环强制顺时针(CW,Y-up 下 shoelace<0),孔环仅在外环被反转时\n * 把 CW 孔反转(与 three `ExtrudeGeometry.js` L131–L151 行为逐行一致);\n * - **顶点布局**:与 three 一致输出**非索引三角流**(每三角形 3 个独立顶点副本,\n * 顺序 = 底面 faces → 顶面 faces → 侧壁 quad 拆 (a,b,d)+(b,c,d)),\n * `indices` 为平凡顺序 0..n-1。因此 positions/normals 与 three r162 逐位一致,\n * 且底/侧/顶棱边保留**硬边法线**(与 three computeVertexNormals 行为相同);\n * - **三角化**:vendored earcut **2.2.4** ESM(`../third-party/earcut`,算法与 npm\n * earcut@2.2.4 逐字节一致;注:three r162 内置 Earcut 与该 npm 版对凹多边形的\n * 划分可能不同,golden 对照按**几何等价**断言、绝不搬 three 内部 Earcut)。\n *\n * 与 three 的差异(登记为设计决策):\n * - three `Shape.extractPoints(curveSegments)` 会把每段(含直线)细分为\n * curveSegments+1 个冗余点(LineCurve 插值点);本实现**不细分直线**(曲线已在\n * `primitives/svg/svg-path.ts` / 文本链采样成折线)。直线的细分点与端点共线,\n * 在几何(去重后)层面完全等价;golden 对照按三角形流逐位断言(见\n * test/mesh/meshdata-extrude.test.ts),用例输入不含曲线段。\n * - 不支持 bevel / extrudePath:传入即抛错(报错好于掩盖,全仓未使用)。\n *\n * 坐标约定:输入轮廓为 **Y-up 平面坐标**(+Z 向上),拉伸沿 +Z,\n * 底面 z=0、顶面 z=depth。\n */\n// earcut 上游仅提供 CJS,浏览器/Vite 直接 serve 无法 default import;vendored\n// ESM(`../third-party/earcut`,算法与 npm earcut@2.2.4 逐字节一致,ISC)。\nimport earcut from '../../third-party/earcut'\nimport type { Shape } from '../types'\nimport { computeVertexNormals } from './ops'\nimport type { Contour, P2 } from './contour'\nimport { signedArea2 } from './contour'\n\nexport type { Contour, P2 } from './contour'\n\n/** 拉伸配置。 */\nexport interface ExtrudeShapeOptions {\n /** 曲线采样段数(曲线已在输入轮廓中折线化,本参数仅保留语义占位)。 */\n curveSegments?: number\n /** 是否支持 bevel(本项目不支持,传 true 抛错)。 */\n bevelEnabled?: boolean\n}\n\n/**\n * 将一组 2D 轮廓直线拉伸为 3D 网格(bevel off)。\n *\n * 输出为 three r162 `ExtrudeGeometry`(bevelEnabled:false)的同构三角流:\n * `positions` = 每三角形 3 顶点副本(底→顶→侧壁),`indices` = 顺序 0..n-1,\n * `normals` = 硬边法线(computeVertexNormals 于该非索引布局上)。\n *\n * @param contours - the closed 2D contours (Y-up) to extrude.\n * @param depth - the extrusion depth along +Z.\n * @param opts - optional settings.\n * @returns the extruded indexed Shape (with per-vertex normals).\n * @throws when bevel is requested (unsupported) or depth is non-positive.\n */\nexport function extrudeShape(contours: Contour[], depth: number, opts?: ExtrudeShapeOptions): Shape {\n if (opts?.bevelEnabled) {\n throw new Error('[extrudeShape] bevel is not supported; use plain straight extrusion')\n }\n if (!(depth > 0)) {\n throw new Error(`[extrudeShape] depth must be positive, got ${depth}`)\n }\n\n const positions: number[] = []\n\n for (const contour of contours) {\n addContourShape(contour, depth, positions)\n }\n\n const indices = new Uint32Array(positions.length / 3)\n for (let i = 0; i < indices.length; i++) indices[i] = i\n\n const shape: Shape = {\n positions: Float32Array.from(positions),\n indices,\n }\n shape.normals = computeVertexNormals(shape)\n return shape\n}\n\nfunction addContourShape(contour: Contour, depth: number, positions: number[]): void {\n // 1. winding 归一(复刻 three L131–L151)\n let outer = contour.outer.slice()\n removeDupEndPts(outer)\n if (outer.length < 3) return\n const holes = contour.holes.map((h) => h.slice()).filter((h) => h.length >= 3)\n for (const h of holes) removeDupEndPts(h)\n\n // 1b. 净化相邻重复点(零长度段)。opentype 字形路径常含连续命令终点相同的\n // 退化段(如 `L 3.12,-0.098 L 3.12,-0.098`);earcut 2.2.4 对这类输入会输出\n // 重叠/退化三角(same edge 出现 4 次 → 非流形)。主动删除相邻同坐标点,\n // 使 earcut 输入与侧壁环一致(earcut 内部 filterPoints 仅删共线,不保证\n // 对零长度段输出干净三角化)。\n removeAdjacentDup(outer)\n for (const h of holes) removeAdjacentDup(h)\n if (outer.length < 3) return\n\n const reverse = !isClockWise(outer)\n if (reverse) {\n outer = outer.reverse()\n for (const h of holes) {\n if (isClockWise(h)) h.reverse()\n }\n }\n\n // 2. earcut 三角化(外环 + 孔,earcut 2.2.x 与 three r162 内置输出一致)\n const data: number[] = []\n const holeIndices: number[] = []\n for (const p of outer) data.push(p.x, p.y)\n for (const h of holes) {\n holeIndices.push(data.length / 2)\n for (const p of h) data.push(p.x, p.y)\n }\n const faces = earcut(data, holeIndices.length > 0 ? holeIndices : undefined, 2)\n\n // 顶点索引(earcut 输出)→ 坐标\n const verts: P2[] = [...outer]\n for (const h of holes) verts.push(...h)\n const at = (i: number): P2 => verts[i]\n\n // 3a. 底面(法线朝 -Z):f3(c, b, a)\n for (let i = 0; i < faces.length; i += 3) {\n const p = at(faces[i + 2])\n positions.push(p.x, p.y, 0)\n const q = at(faces[i + 1])\n positions.push(q.x, q.y, 0)\n const r = at(faces[i])\n positions.push(r.x, r.y, 0)\n }\n\n // 3b. 顶面(法线朝 +Z):f3(a, b, c)\n for (let i = 0; i < faces.length; i += 3) {\n const p = at(faces[i])\n positions.push(p.x, p.y, depth)\n const q = at(faces[i + 1])\n positions.push(q.x, q.y, depth)\n const r = at(faces[i + 2])\n positions.push(r.x, r.y, depth)\n }\n\n // 3c. 侧壁:基于 earcut 输出三角的**边界边**(无向出现 1 次的边)生成 quad。\n // - 内部共享边在相邻三角中方向相反(各出现 1 次有向)→ 必须按**无向** key 计数\n // 才不会被误判为边界;\n // - 这样底面/顶面的边界与侧壁严格共享同一组边 → 网格必然水密;\n // earcut 内部会过滤共线点(filterPoints),若侧壁改用未过滤的输入环,\n // 被滤点在侧壁有边、在顶底没有 → 出现开放边。本实现从几何上消除该不一致。\n // - earcut 输出三角方向统一为外环方向(CW),边界边首次出现的有向方向\n // (a→b) 即环方向 → quad 法线朝外。\n const edgeCount = new Map<string, { a: number; b: number; n: number }>()\n for (let i = 0; i < faces.length; i += 3) {\n const a = faces[i], b = faces[i + 1], c = faces[i + 2]\n for (const [u, v] of [[a, b], [b, c], [c, a]] as const) {\n const key = u < v ? `${u},${v}` : `${v},${u}`\n const entry = edgeCount.get(key)\n if (entry) {\n entry.n++\n } else {\n edgeCount.set(key, { a: u, b: v, n: 1 })\n }\n }\n }\n for (const { a, b, n } of edgeCount.values()) {\n if (n !== 1) continue\n const pa = at(a)\n const pb = at(b)\n // 与 three `sidewalls` 相同的 quad 拆分,但取**反向边 (b→a)**:\n // three 的 sidewalls 从 contour 尾部向前遍历(等价于取环反向),本实现\n // 直接以反向边构造 quad —— tri (a底, b底, a顶) + tri (b底, b顶, a顶),\n // 法线朝外(earcut 外环为数学 CW,正向 (a→b) 沿 CW 行进右转朝内)。\n positions.push(pa.x, pa.y, 0)\n positions.push(pb.x, pb.y, 0)\n positions.push(pa.x, pa.y, depth)\n positions.push(pb.x, pb.y, 0)\n positions.push(pb.x, pb.y, depth)\n positions.push(pa.x, pa.y, depth)\n }\n}\n\n/**\n * three `ShapeUtils.isClockWise`:shoelace 面积 < 0 即顺时针(Y-up,与\n * three `ShapeUtils.area(pts) < 0` 逐字一致)。注意数学约定里逆时针为正,\n * three 命名 \"isClockWise\" 判的是面积为负(数学 CW);本实现与 three 对齐。\n */\nfunction isClockWise(pts: P2[]): boolean {\n return signedArea2(pts) < 0\n}\n\n/** three `removeDupEndPts`:删除与首点重复的尾点。 */\nfunction removeDupEndPts(pts: P2[]): void {\n const l = pts.length\n if (l > 2 && Math.abs(pts[l - 1].x - pts[0].x) < 1e-12 && Math.abs(pts[l - 1].y - pts[0].y) < 1e-12) {\n pts.pop()\n }\n}\n\n/**\n * 删除环上相邻的重复坐标点(零长度段),循环至稳定。\n * 判定容差 1e-9(比 earcut filterPoints 的严格 ===0 更宽,保证净化后的环\n * 不再含任何可判定的零长度段;共线非重复点仍留给 earcut 处理)。\n */\nfunction removeAdjacentDup(pts: P2[]): void {\n let changed = true\n while (changed && pts.length >= 3) {\n changed = false\n for (let i = pts.length - 1; i >= 0; i--) {\n const j = i + 1 >= pts.length ? 0 : i + 1\n if (Math.abs(pts[i].x - pts[j].x) < 1e-9 && Math.abs(pts[i].y - pts[j].y) < 1e-9) {\n pts.splice(i, 1)\n changed = true\n }\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mesh/meshdata/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAiB,MAAM,QAAQ,CAAA;AAChD,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,cAAc,GAEf,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,WAAW,GAEZ,MAAM,OAAO,CAAA","sourcesContent":["/**\r\n * meshdata — core 自有的 mesh 容器与参数化几何(three `BufferGeometry` 与\r\n * `Box/Cylinder/Cone/SphereGeometry` 的替代)。\r\n *\r\n * 纯函数集作用于对外类型 `Shape`(不挂方法);参数化几何逐位复刻 three r162\r\n * 的顶点/索引顺序以保 `faceRanges` 面序契约(MIT License, © 2010-2024 three.js\r\n * authors)。与既有 `mesh/query.ts`(boundingBox/volume 等查询)职责不重叠。\r\n */\r\n\r\nexport { weldMesh, type MeshData } from './weld'\r\nexport {\r\n boxGeometry,\r\n cylinderGeometry,\r\n coneGeometry,\r\n sphereGeometry,\r\n type GeoData,\r\n} from './parametric'\r\nexport {\r\n shapeFromMesh,\r\n toNonIndexed,\r\n transformShape,\r\n translateShape,\r\n computeVertexNormals,\r\n mergeShapes,\r\n type MatrixLike,\r\n} from './ops'"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mesh/meshdata/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAiB,MAAM,QAAQ,CAAA;AAChD,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,cAAc,GAEf,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,WAAW,GAEZ,MAAM,OAAO,CAAA","sourcesContent":["/**\n * meshdata — core 自有的 mesh 容器与参数化几何(three `BufferGeometry` 与\n * `Box/Cylinder/Cone/SphereGeometry` 的替代)。\n *\n * 纯函数集作用于对外类型 `Shape`(不挂方法);参数化几何逐位复刻 three r162\n * 的顶点/索引顺序以保 `faceRanges` 面序契约(MIT License, © 2010-2024 three.js\n * authors)。与既有 `mesh/query.ts`(boundingBox/volume 等查询)职责不重叠。\n */\n\nexport { weldMesh, type MeshData } from './weld'\nexport {\n boxGeometry,\n cylinderGeometry,\n coneGeometry,\n sphereGeometry,\n type GeoData,\n} from './parametric'\nexport {\n shapeFromMesh,\n toNonIndexed,\n transformShape,\n translateShape,\n computeVertexNormals,\n mergeShapes,\n type MatrixLike,\n} from './ops'"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ops.js","sourceRoot":"","sources":["../../../src/mesh/meshdata/ops.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * meshdata/ops — 作用在 Shape / 原始数组上的纯函数几何操作(L1 容器操作)。\r\n *\r\n * 替代 three `BufferGeometry` 的少量方法面(`toNonIndexed`、`computeVertexNormals`、\r\n * `applyMatrix4`/`translate`、`clone`、merge)——**纯函数集,不给对外 `Shape` 挂方法**\r\n * (与设计 §3.3 一致)。不重复 `mesh/query.ts` 已有的 `boundingBox`/`volume` 等查询。\r\n */\r\n\r\nimport { Vec3, type MatrixLike } from '../../math3d'\r\nimport type { Shape } from '../types'\r\nimport { weldMesh, type MeshData } from './weld'\r\n\r\nexport type { MatrixLike }\r\n\r\n/**\r\n * Weld raw positions+indices into a mesh Shape (same behaviour as the old\r\n * `geoToManifoldMesh` on a position-only geometry).\r\n * @param positions - flat position array (x, y, z, ...).\r\n * @param indices - triangle index array into `positions`.\r\n * @param extra - optional extra Shape fields to attach (e.g. `faceRanges`).\r\n * @returns the welded Shape.\r\n */\r\nexport function shapeFromMesh(\r\n positions: ArrayLike<number>,\r\n indices: ArrayLike<number>,\r\n extra?: Partial<Shape>,\r\n): Shape {\r\n const mesh = weldMesh(positions, indices)\r\n return { positions: mesh.positions, indices: mesh.indices, ...extra }\r\n}\r\n\r\n/**\r\n * Expand an indexed Shape to non-indexed (each triangle gets its own vertices),\r\n * mirroring three `BufferGeometry.toNonIndexed`.\r\n * @param shape - the indexed shape.\r\n * @returns a non-indexed copy of the shape.\r\n */\r\nexport function toNonIndexed(shape: Shape): MeshData {\r\n const positions = shape.positions\r\n const indices = shape.indices\r\n const out = new Float32Array(indices.length * 3)\r\n for (let i = 0; i < indices.length; i++) {\r\n const v = indices[i] * 3\r\n out[i * 3] = positions[v]\r\n out[i * 3 + 1] = positions[v + 1]\r\n out[i * 3 + 2] = positions[v + 2]\r\n }\r\n const seq = new Uint32Array(indices.length)\r\n for (let i = 0; i < indices.length; i++) seq[i] = i\r\n return { positions: out, indices: seq }\r\n}\r\n\r\n/**\r\n * Apply a 4x4 matrix to a Shape's vertices (bakes the transform).\r\n * @param shape - the source shape.\r\n * @param m - column-major 4x4 matrix.\r\n * @returns a new shape with transformed vertices (indices/other fields preserved).\r\n */\r\nexport function transformShape(shape: Shape, m: MatrixLike): Shape {\r\n const out = new Float32Array(shape.positions.length)\r\n const v = new Vec3()\r\n for (let i = 0; i < shape.positions.length; i += 3) {\r\n v.set(shape.positions[i], shape.positions[i + 1], shape.positions[i + 2])\r\n v.applyMatrix4(m)\r\n out[i] = v.x\r\n out[i + 1] = v.y\r\n out[i + 2] = v.z\r\n }\r\n return { ...shape, positions: out }\r\n}\r\n\r\n/**\r\n * Translate a Shape's vertices by (x, y, z).\r\n * @param shape - the source shape.\r\n * @param x - X offset.\r\n * @param y - Y offset.\r\n * @param z - Z offset.\r\n * @returns a new shape with translated vertices.\r\n */\r\nexport function translateShape(shape: Shape, x: number, y: number, z = 0): Shape {\r\n if (x === 0 && y === 0 && z === 0) return { ...shape }\r\n const out = new Float32Array(shape.positions)\r\n for (let i = 0; i < out.length; i += 3) {\r\n out[i] += x\r\n out[i + 1] += y\r\n out[i + 2] += z\r\n }\r\n return { ...shape, positions: out }\r\n}\r\n\r\n/**\r\n * Compute per-vertex normals with three `BufferGeometry.computeVertexNormals`\r\n * semantics (face normals averaged across shared vertices).\r\n *\r\n * **折边红线提醒**:在索引(共享顶点)几何上这会把棱边\"磨圆\"——core 的派生法线\r\n * 一律走 `boolean/creased-normals.ts`(`deriveNormals`)。本函数只为替换 three 的\r\n * **罕见**直调用点而保留,返回纯数据,不改变 Shape。\r\n * @param shape - the source shape.\r\n * @returns a Float32Array of per-vertex normals.\r\n */\r\nexport function computeVertexNormals(shape: Shape): Float32Array {\r\n const positions = shape.positions\r\n const indices = shape.indices\r\n const normals = new Float32Array(positions.length)\r\n const pA = new Vec3()\r\n const pB = new Vec3()\r\n const pC = new Vec3()\r\n const cb = new Vec3()\r\n const ab = new Vec3()\r\n\r\n for (let i = 0; i < indices.length; i += 3) {\r\n const a = indices[i] * 3\r\n const b = indices[i + 1] * 3\r\n const c = indices[i + 2] * 3\r\n pA.set(positions[a], positions[a + 1], positions[a + 2])\r\n pB.set(positions[b], positions[b + 1], positions[b + 2])\r\n pC.set(positions[c], positions[c + 1], positions[c + 2])\r\n cb.subVectors(pC, pB)\r\n ab.subVectors(pA, pB)\r\n cb.cross(ab)\r\n normals[a] += cb.x\r\n normals[a + 1] += cb.y\r\n normals[a + 2] += cb.z\r\n normals[b] += cb.x\r\n normals[b + 1] += cb.y\r\n normals[b + 2] += cb.z\r\n normals[c] += cb.x\r\n normals[c + 1] += cb.y\r\n normals[c + 2] += cb.z\r\n }\r\n\r\n const v = new Vec3()\r\n for (let i = 0; i < normals.length; i += 3) {\r\n v.set(normals[i], normals[i + 1], normals[i + 2]).normalize()\r\n normals[i] = v.x\r\n normals[i + 1] = v.y\r\n normals[i + 2] = v.z\r\n }\r\n return normals\r\n}\r\n\r\n/**\r\n * Merge several Shapes into one indexed Shape (position + index concatenation,\r\n * mirroring the old `mergeBufferGeometries`).\r\n * @param shapes - the shapes to merge.\r\n * @returns the merged Shape.\r\n */\r\nexport function mergeShapes(shapes: Shape[]): Shape {\r\n if (shapes.length === 1) {\r\n const s = shapes[0]\r\n return { positions: new Float32Array(s.positions), indices: new Uint32Array(s.indices) }\r\n }\r\n let posLen = 0\r\n let idxLen = 0\r\n for (const s of shapes) {\r\n posLen += s.positions.length\r\n idxLen += s.indices.length\r\n }\r\n const positions = new Float32Array(posLen)\r\n const indices = new Uint32Array(idxLen)\r\n let po = 0\r\n let io = 0\r\n let vertexOffset = 0\r\n for (const s of shapes) {\r\n positions.set(s.positions, po)\r\n po += s.positions.length\r\n for (let i = 0; i < s.indices.length; i++) indices[io + i] = s.indices[i] + vertexOffset\r\n io += s.indices.length\r\n vertexOffset += s.positions.length / 3\r\n }\r\n return { positions, indices }\r\n}"]}
1
+ {"version":3,"file":"ops.js","sourceRoot":"","sources":["../../../src/mesh/meshdata/ops.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * meshdata/ops — 作用在 Shape / 原始数组上的纯函数几何操作(L1 容器操作)。\n *\n * 替代 three `BufferGeometry` 的少量方法面(`toNonIndexed`、`computeVertexNormals`、\n * `applyMatrix4`/`translate`、`clone`、merge)——**纯函数集,不给对外 `Shape` 挂方法**\n * (与设计 §3.3 一致)。不重复 `mesh/query.ts` 已有的 `boundingBox`/`volume` 等查询。\n */\n\nimport { Vec3, type MatrixLike } from '../../math3d'\nimport type { Shape } from '../types'\nimport { weldMesh, type MeshData } from './weld'\n\nexport type { MatrixLike }\n\n/**\n * Weld raw positions+indices into a mesh Shape (same behaviour as the old\n * `geoToManifoldMesh` on a position-only geometry).\n * @param positions - flat position array (x, y, z, ...).\n * @param indices - triangle index array into `positions`.\n * @param extra - optional extra Shape fields to attach (e.g. `faceRanges`).\n * @returns the welded Shape.\n */\nexport function shapeFromMesh(\n positions: ArrayLike<number>,\n indices: ArrayLike<number>,\n extra?: Partial<Shape>,\n): Shape {\n const mesh = weldMesh(positions, indices)\n return { positions: mesh.positions, indices: mesh.indices, ...extra }\n}\n\n/**\n * Expand an indexed Shape to non-indexed (each triangle gets its own vertices),\n * mirroring three `BufferGeometry.toNonIndexed`.\n * @param shape - the indexed shape.\n * @returns a non-indexed copy of the shape.\n */\nexport function toNonIndexed(shape: Shape): MeshData {\n const positions = shape.positions\n const indices = shape.indices\n const out = new Float32Array(indices.length * 3)\n for (let i = 0; i < indices.length; i++) {\n const v = indices[i] * 3\n out[i * 3] = positions[v]\n out[i * 3 + 1] = positions[v + 1]\n out[i * 3 + 2] = positions[v + 2]\n }\n const seq = new Uint32Array(indices.length)\n for (let i = 0; i < indices.length; i++) seq[i] = i\n return { positions: out, indices: seq }\n}\n\n/**\n * Apply a 4x4 matrix to a Shape's vertices (bakes the transform).\n * @param shape - the source shape.\n * @param m - column-major 4x4 matrix.\n * @returns a new shape with transformed vertices (indices/other fields preserved).\n */\nexport function transformShape(shape: Shape, m: MatrixLike): Shape {\n const out = new Float32Array(shape.positions.length)\n const v = new Vec3()\n for (let i = 0; i < shape.positions.length; i += 3) {\n v.set(shape.positions[i], shape.positions[i + 1], shape.positions[i + 2])\n v.applyMatrix4(m)\n out[i] = v.x\n out[i + 1] = v.y\n out[i + 2] = v.z\n }\n return { ...shape, positions: out }\n}\n\n/**\n * Translate a Shape's vertices by (x, y, z).\n * @param shape - the source shape.\n * @param x - X offset.\n * @param y - Y offset.\n * @param z - Z offset.\n * @returns a new shape with translated vertices.\n */\nexport function translateShape(shape: Shape, x: number, y: number, z = 0): Shape {\n if (x === 0 && y === 0 && z === 0) return { ...shape }\n const out = new Float32Array(shape.positions)\n for (let i = 0; i < out.length; i += 3) {\n out[i] += x\n out[i + 1] += y\n out[i + 2] += z\n }\n return { ...shape, positions: out }\n}\n\n/**\n * Compute per-vertex normals with three `BufferGeometry.computeVertexNormals`\n * semantics (face normals averaged across shared vertices).\n *\n * **折边红线提醒**:在索引(共享顶点)几何上这会把棱边\"磨圆\"——core 的派生法线\n * 一律走 `boolean/creased-normals.ts`(`deriveNormals`)。本函数只为替换 three 的\n * **罕见**直调用点而保留,返回纯数据,不改变 Shape。\n * @param shape - the source shape.\n * @returns a Float32Array of per-vertex normals.\n */\nexport function computeVertexNormals(shape: Shape): Float32Array {\n const positions = shape.positions\n const indices = shape.indices\n const normals = new Float32Array(positions.length)\n const pA = new Vec3()\n const pB = new Vec3()\n const pC = new Vec3()\n const cb = new Vec3()\n const ab = new Vec3()\n\n for (let i = 0; i < indices.length; i += 3) {\n const a = indices[i] * 3\n const b = indices[i + 1] * 3\n const c = indices[i + 2] * 3\n pA.set(positions[a], positions[a + 1], positions[a + 2])\n pB.set(positions[b], positions[b + 1], positions[b + 2])\n pC.set(positions[c], positions[c + 1], positions[c + 2])\n cb.subVectors(pC, pB)\n ab.subVectors(pA, pB)\n cb.cross(ab)\n normals[a] += cb.x\n normals[a + 1] += cb.y\n normals[a + 2] += cb.z\n normals[b] += cb.x\n normals[b + 1] += cb.y\n normals[b + 2] += cb.z\n normals[c] += cb.x\n normals[c + 1] += cb.y\n normals[c + 2] += cb.z\n }\n\n const v = new Vec3()\n for (let i = 0; i < normals.length; i += 3) {\n v.set(normals[i], normals[i + 1], normals[i + 2]).normalize()\n normals[i] = v.x\n normals[i + 1] = v.y\n normals[i + 2] = v.z\n }\n return normals\n}\n\n/**\n * Merge several Shapes into one indexed Shape (position + index concatenation,\n * mirroring the old `mergeBufferGeometries`).\n * @param shapes - the shapes to merge.\n * @returns the merged Shape.\n */\nexport function mergeShapes(shapes: Shape[]): Shape {\n if (shapes.length === 1) {\n const s = shapes[0]\n return { positions: new Float32Array(s.positions), indices: new Uint32Array(s.indices) }\n }\n let posLen = 0\n let idxLen = 0\n for (const s of shapes) {\n posLen += s.positions.length\n idxLen += s.indices.length\n }\n const positions = new Float32Array(posLen)\n const indices = new Uint32Array(idxLen)\n let po = 0\n let io = 0\n let vertexOffset = 0\n for (const s of shapes) {\n positions.set(s.positions, po)\n po += s.positions.length\n for (let i = 0; i < s.indices.length; i++) indices[io + i] = s.indices[i] + vertexOffset\n io += s.indices.length\n vertexOffset += s.positions.length / 3\n }\n return { positions, indices }\n}"]}
@@ -1 +1 @@
1
- {"version":3,"file":"parametric.js","sourceRoot":"","sources":["../../../src/mesh/meshdata/parametric.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * meshdata/parametric — three.js r162 参数化几何的最小复刻(box / cylinder /\r\n * cone / sphere),去掉 normal / uv,只产出 position + index。\r\n *\r\n * Ported from three.js r162 `src/geometries/{Box,Cylinder,Cone,Sphere}Geometry.js`\r\n * (MIT License, © 2010-2024 three.js authors). **顶点与索引的生成顺序逐行照抄**\r\n * ——`mesh/primitives.ts` 的 `faceRanges` 面序契约正建立在该顺序之上(例如 Box\r\n * 12 三角形 = 6 面 × 2,顺序固定 +X/−X/+Y/−Y/+Z/−Z;Cylinder 侧面→顶盖→底盖)。\r\n * 改动这里的循环顺序 = 改变面序契约,属破坏性改动。\r\n *\r\n * 本模块零依赖(除 `MeshData` 类型),是「去 three」后 core 自有的参数化几何来源。\r\n */\r\n\r\nimport type { MeshData } from './weld'\r\n\r\n/** Raw geometry output: interleaved positions + triangle indices. */\r\nexport interface GeoData {\r\n positions: Float32Array\r\n indices: Uint32Array\r\n}\r\n\r\ntype Axis = 'x' | 'y' | 'z'\r\n\r\n/**\r\n * Box geometry (three `BoxGeometry`, default 1 segment per side).\r\n * @param width - size along X.\r\n * @param height - size along Y.\r\n * @param depth - size along Z.\r\n * @param widthSegments - segments along X.\r\n * @param heightSegments - segments along Y.\r\n * @param depthSegments - segments along Z.\r\n * @returns positions + indices in three's vertex/index order.\r\n */\r\nexport function boxGeometry(\r\n width = 1,\r\n height = 1,\r\n depth = 1,\r\n widthSegments = 1,\r\n heightSegments = 1,\r\n depthSegments = 1,\r\n): GeoData {\r\n const indices: number[] = []\r\n const vertices: number[] = []\r\n let numberOfVertices = 0\r\n\r\n const gx = Math.floor(widthSegments)\r\n const gy = Math.floor(heightSegments)\r\n const gz = Math.floor(depthSegments)\r\n const vector: Record<Axis, number> = { x: 0, y: 0, z: 0 }\r\n\r\n function buildPlane(\r\n u: Axis, v: Axis, w: Axis,\r\n udir: number, vdir: number,\r\n planeWidth: number, planeHeight: number, planeDepth: number,\r\n gridX: number, gridY: number,\r\n ): void {\r\n const segmentWidth = planeWidth / gridX\r\n const segmentHeight = planeHeight / gridY\r\n const widthHalf = planeWidth / 2\r\n const heightHalf = planeHeight / 2\r\n const depthHalf = planeDepth / 2\r\n const gridX1 = gridX + 1\r\n const gridY1 = gridY + 1\r\n let vertexCounter = 0\r\n\r\n for (let iy = 0; iy < gridY1; iy++) {\r\n const y = iy * segmentHeight - heightHalf\r\n for (let ix = 0; ix < gridX1; ix++) {\r\n const x = ix * segmentWidth - widthHalf\r\n vector[u] = x * udir\r\n vector[v] = y * vdir\r\n vector[w] = depthHalf\r\n vertices.push(vector.x, vector.y, vector.z)\r\n vertexCounter += 1\r\n }\r\n }\r\n\r\n for (let iy = 0; iy < gridY; iy++) {\r\n for (let ix = 0; ix < gridX; ix++) {\r\n const a = numberOfVertices + ix + gridX1 * iy\r\n const b = numberOfVertices + ix + gridX1 * (iy + 1)\r\n const c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1)\r\n const d = numberOfVertices + (ix + 1) + gridX1 * iy\r\n indices.push(a, b, d)\r\n indices.push(b, c, d)\r\n }\r\n }\r\n\r\n numberOfVertices += vertexCounter\r\n }\r\n\r\n buildPlane('z', 'y', 'x', -1, -1, depth, height, width, gz, gy) // px\r\n buildPlane('z', 'y', 'x', 1, -1, depth, height, -width, gz, gy) // nx\r\n buildPlane('x', 'z', 'y', 1, 1, width, depth, height, gx, gz) // py\r\n buildPlane('x', 'z', 'y', 1, -1, width, depth, -height, gx, gz) // ny\r\n buildPlane('x', 'y', 'z', 1, -1, width, height, depth, gx, gy) // pz\r\n buildPlane('x', 'y', 'z', -1, -1, width, height, -depth, gx, gy) // nz\r\n\r\n return { positions: new Float32Array(vertices), indices: new Uint32Array(indices) }\r\n}\r\n\r\n/**\r\n * Cylinder / frustum geometry (three `CylinderGeometry`: torso then top cap then\r\n * bottom cap).\r\n * @param radiusTop - top radius.\r\n * @param radiusBottom - bottom radius.\r\n * @param height - height along Y (three is Y-up; callers rotate to Z-up).\r\n * @param radialSegments - radial segment count.\r\n * @param heightSegments - axial segment count.\r\n * @param openEnded - skip caps when true.\r\n * @param thetaStart - start angle.\r\n * @param thetaLength - swept angle.\r\n * @returns positions + indices in three's vertex/index order.\r\n */\r\nexport function cylinderGeometry(\r\n radiusTop = 1,\r\n radiusBottom = 1,\r\n height = 1,\r\n radialSegments = 32,\r\n heightSegments = 1,\r\n openEnded = false,\r\n thetaStart = 0,\r\n thetaLength = Math.PI * 2,\r\n): GeoData {\r\n const indices: number[] = []\r\n const vertices: number[] = []\r\n let index = 0\r\n const halfHeight = height / 2\r\n\r\n const rSeg = Math.floor(radialSegments)\r\n const hSeg = Math.floor(heightSegments)\r\n\r\n const indexArray: number[][] = []\r\n\r\n // torso\r\n {\r\n\r\n for (let y = 0; y <= hSeg; y++) {\r\n const indexRow: number[] = []\r\n const v = y / hSeg\r\n const radius = v * (radiusBottom - radiusTop) + radiusTop\r\n for (let x = 0; x <= rSeg; x++) {\r\n const u = x / rSeg\r\n const theta = u * thetaLength + thetaStart\r\n const sinTheta = Math.sin(theta)\r\n const cosTheta = Math.cos(theta)\r\n vertices.push(radius * sinTheta, -v * height + halfHeight, radius * cosTheta)\r\n indexRow.push(index++)\r\n }\r\n indexArray.push(indexRow)\r\n }\r\n for (let x = 0; x < rSeg; x++) {\r\n for (let y = 0; y < hSeg; y++) {\r\n const a = indexArray[y][x]\r\n const b = indexArray[y + 1][x]\r\n const c = indexArray[y + 1][x + 1]\r\n const d = indexArray[y][x + 1]\r\n indices.push(a, b, d)\r\n indices.push(b, c, d)\r\n }\r\n }\r\n\r\n }\r\n\r\n const generateCap = (top: boolean): void => {\r\n const centerIndexStart = index\r\n const radius = top ? radiusTop : radiusBottom\r\n const sign = top ? 1 : -1\r\n for (let x = 1; x <= rSeg; x++) {\r\n vertices.push(0, halfHeight * sign, 0)\r\n index++\r\n }\r\n const centerIndexEnd = index\r\n for (let x = 0; x <= rSeg; x++) {\r\n const u = x / rSeg\r\n const theta = u * thetaLength + thetaStart\r\n const cosTheta = Math.cos(theta)\r\n const sinTheta = Math.sin(theta)\r\n vertices.push(radius * sinTheta, halfHeight * sign, radius * cosTheta)\r\n index++\r\n }\r\n for (let x = 0; x < rSeg; x++) {\r\n const c = centerIndexStart + x\r\n const i = centerIndexEnd + x\r\n if (top) indices.push(i, i + 1, c)\r\n else indices.push(i + 1, i, c)\r\n }\r\n }\r\n\r\n if (!openEnded) {\r\n if (radiusTop > 0) generateCap(true)\r\n if (radiusBottom > 0) generateCap(false)\r\n }\r\n\r\n return { positions: new Float32Array(vertices), indices: new Uint32Array(indices) }\r\n}\r\n\r\n/**\r\n * Cone geometry (three `ConeGeometry` = `CylinderGeometry(0, radius, ...)`).\r\n * @param radius - base radius.\r\n * @param height - height along Y.\r\n * @param radialSegments - radial segment count.\r\n * @param heightSegments - axial segment count.\r\n * @param openEnded - skip the base cap when true.\r\n * @param thetaStart - start angle.\r\n * @param thetaLength - swept angle.\r\n * @returns positions + indices in three's vertex/index order.\r\n */\r\nexport function coneGeometry(\r\n radius = 1,\r\n height = 1,\r\n radialSegments = 32,\r\n heightSegments = 1,\r\n openEnded = false,\r\n thetaStart = 0,\r\n thetaLength = Math.PI * 2,\r\n): GeoData {\r\n return cylinderGeometry(0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength)\r\n}\r\n\r\n/**\r\n * Sphere geometry (three `SphereGeometry`).\r\n * @param radius - sphere radius.\r\n * @param widthSegments - longitude segment count.\r\n * @param heightSegments - latitude segment count.\r\n * @param phiStart - start longitude.\r\n * @param phiLength - swept longitude.\r\n * @param thetaStart - start latitude.\r\n * @param thetaLength - swept latitude.\r\n * @returns positions + indices in three's vertex/index order.\r\n */\r\nexport function sphereGeometry(\r\n radius = 1,\r\n widthSegments = 32,\r\n heightSegments = 16,\r\n phiStart = 0,\r\n phiLength = Math.PI * 2,\r\n thetaStart = 0,\r\n thetaLength = Math.PI,\r\n): GeoData {\r\n const wSeg = Math.max(3, Math.floor(widthSegments))\r\n const hSeg = Math.max(2, Math.floor(heightSegments))\r\n const thetaEnd = Math.min(thetaStart + thetaLength, Math.PI)\r\n\r\n let index = 0\r\n const grid: number[][] = []\r\n const indices: number[] = []\r\n const vertices: number[] = []\r\n\r\n for (let iy = 0; iy <= hSeg; iy++) {\r\n const verticesRow: number[] = []\r\n const v = iy / hSeg\r\n for (let ix = 0; ix <= wSeg; ix++) {\r\n const u = ix / wSeg\r\n const x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength)\r\n const y = radius * Math.cos(thetaStart + v * thetaLength)\r\n const z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength)\r\n vertices.push(x, y, z)\r\n verticesRow.push(index++)\r\n }\r\n grid.push(verticesRow)\r\n }\r\n\r\n for (let iy = 0; iy < hSeg; iy++) {\r\n for (let ix = 0; ix < wSeg; ix++) {\r\n const a = grid[iy][ix + 1]\r\n const b = grid[iy][ix]\r\n const c = grid[iy + 1][ix]\r\n const d = grid[iy + 1][ix + 1]\r\n if (iy !== 0 || thetaStart > 0) indices.push(a, b, d)\r\n if (iy !== hSeg - 1 || thetaEnd < Math.PI) indices.push(b, c, d)\r\n }\r\n }\r\n\r\n return { positions: new Float32Array(vertices), indices: new Uint32Array(indices) }\r\n}\r\n\r\n/** Re-export the raw mesh container type for callers. */\r\nexport type { MeshData }"]}
1
+ {"version":3,"file":"parametric.js","sourceRoot":"","sources":["../../../src/mesh/meshdata/parametric.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * meshdata/parametric — three.js r162 参数化几何的最小复刻(box / cylinder /\n * cone / sphere),去掉 normal / uv,只产出 position + index。\n *\n * Ported from three.js r162 `src/geometries/{Box,Cylinder,Cone,Sphere}Geometry.js`\n * (MIT License, © 2010-2024 three.js authors). **顶点与索引的生成顺序逐行照抄**\n * ——`mesh/primitives.ts` 的 `faceRanges` 面序契约正建立在该顺序之上(例如 Box\n * 12 三角形 = 6 面 × 2,顺序固定 +X/−X/+Y/−Y/+Z/−Z;Cylinder 侧面→顶盖→底盖)。\n * 改动这里的循环顺序 = 改变面序契约,属破坏性改动。\n *\n * 本模块零依赖(除 `MeshData` 类型),是「去 three」后 core 自有的参数化几何来源。\n */\n\nimport type { MeshData } from './weld'\n\n/** Raw geometry output: interleaved positions + triangle indices. */\nexport interface GeoData {\n positions: Float32Array\n indices: Uint32Array\n}\n\ntype Axis = 'x' | 'y' | 'z'\n\n/**\n * Box geometry (three `BoxGeometry`, default 1 segment per side).\n * @param width - size along X.\n * @param height - size along Y.\n * @param depth - size along Z.\n * @param widthSegments - segments along X.\n * @param heightSegments - segments along Y.\n * @param depthSegments - segments along Z.\n * @returns positions + indices in three's vertex/index order.\n */\nexport function boxGeometry(\n width = 1,\n height = 1,\n depth = 1,\n widthSegments = 1,\n heightSegments = 1,\n depthSegments = 1,\n): GeoData {\n const indices: number[] = []\n const vertices: number[] = []\n let numberOfVertices = 0\n\n const gx = Math.floor(widthSegments)\n const gy = Math.floor(heightSegments)\n const gz = Math.floor(depthSegments)\n const vector: Record<Axis, number> = { x: 0, y: 0, z: 0 }\n\n function buildPlane(\n u: Axis, v: Axis, w: Axis,\n udir: number, vdir: number,\n planeWidth: number, planeHeight: number, planeDepth: number,\n gridX: number, gridY: number,\n ): void {\n const segmentWidth = planeWidth / gridX\n const segmentHeight = planeHeight / gridY\n const widthHalf = planeWidth / 2\n const heightHalf = planeHeight / 2\n const depthHalf = planeDepth / 2\n const gridX1 = gridX + 1\n const gridY1 = gridY + 1\n let vertexCounter = 0\n\n for (let iy = 0; iy < gridY1; iy++) {\n const y = iy * segmentHeight - heightHalf\n for (let ix = 0; ix < gridX1; ix++) {\n const x = ix * segmentWidth - widthHalf\n vector[u] = x * udir\n vector[v] = y * vdir\n vector[w] = depthHalf\n vertices.push(vector.x, vector.y, vector.z)\n vertexCounter += 1\n }\n }\n\n for (let iy = 0; iy < gridY; iy++) {\n for (let ix = 0; ix < gridX; ix++) {\n const a = numberOfVertices + ix + gridX1 * iy\n const b = numberOfVertices + ix + gridX1 * (iy + 1)\n const c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1)\n const d = numberOfVertices + (ix + 1) + gridX1 * iy\n indices.push(a, b, d)\n indices.push(b, c, d)\n }\n }\n\n numberOfVertices += vertexCounter\n }\n\n buildPlane('z', 'y', 'x', -1, -1, depth, height, width, gz, gy) // px\n buildPlane('z', 'y', 'x', 1, -1, depth, height, -width, gz, gy) // nx\n buildPlane('x', 'z', 'y', 1, 1, width, depth, height, gx, gz) // py\n buildPlane('x', 'z', 'y', 1, -1, width, depth, -height, gx, gz) // ny\n buildPlane('x', 'y', 'z', 1, -1, width, height, depth, gx, gy) // pz\n buildPlane('x', 'y', 'z', -1, -1, width, height, -depth, gx, gy) // nz\n\n return { positions: new Float32Array(vertices), indices: new Uint32Array(indices) }\n}\n\n/**\n * Cylinder / frustum geometry (three `CylinderGeometry`: torso then top cap then\n * bottom cap).\n * @param radiusTop - top radius.\n * @param radiusBottom - bottom radius.\n * @param height - height along Y (three is Y-up; callers rotate to Z-up).\n * @param radialSegments - radial segment count.\n * @param heightSegments - axial segment count.\n * @param openEnded - skip caps when true.\n * @param thetaStart - start angle.\n * @param thetaLength - swept angle.\n * @returns positions + indices in three's vertex/index order.\n */\nexport function cylinderGeometry(\n radiusTop = 1,\n radiusBottom = 1,\n height = 1,\n radialSegments = 32,\n heightSegments = 1,\n openEnded = false,\n thetaStart = 0,\n thetaLength = Math.PI * 2,\n): GeoData {\n const indices: number[] = []\n const vertices: number[] = []\n let index = 0\n const halfHeight = height / 2\n\n const rSeg = Math.floor(radialSegments)\n const hSeg = Math.floor(heightSegments)\n\n const indexArray: number[][] = []\n\n // torso\n {\n\n for (let y = 0; y <= hSeg; y++) {\n const indexRow: number[] = []\n const v = y / hSeg\n const radius = v * (radiusBottom - radiusTop) + radiusTop\n for (let x = 0; x <= rSeg; x++) {\n const u = x / rSeg\n const theta = u * thetaLength + thetaStart\n const sinTheta = Math.sin(theta)\n const cosTheta = Math.cos(theta)\n vertices.push(radius * sinTheta, -v * height + halfHeight, radius * cosTheta)\n indexRow.push(index++)\n }\n indexArray.push(indexRow)\n }\n for (let x = 0; x < rSeg; x++) {\n for (let y = 0; y < hSeg; y++) {\n const a = indexArray[y][x]\n const b = indexArray[y + 1][x]\n const c = indexArray[y + 1][x + 1]\n const d = indexArray[y][x + 1]\n indices.push(a, b, d)\n indices.push(b, c, d)\n }\n }\n\n }\n\n const generateCap = (top: boolean): void => {\n const centerIndexStart = index\n const radius = top ? radiusTop : radiusBottom\n const sign = top ? 1 : -1\n for (let x = 1; x <= rSeg; x++) {\n vertices.push(0, halfHeight * sign, 0)\n index++\n }\n const centerIndexEnd = index\n for (let x = 0; x <= rSeg; x++) {\n const u = x / rSeg\n const theta = u * thetaLength + thetaStart\n const cosTheta = Math.cos(theta)\n const sinTheta = Math.sin(theta)\n vertices.push(radius * sinTheta, halfHeight * sign, radius * cosTheta)\n index++\n }\n for (let x = 0; x < rSeg; x++) {\n const c = centerIndexStart + x\n const i = centerIndexEnd + x\n if (top) indices.push(i, i + 1, c)\n else indices.push(i + 1, i, c)\n }\n }\n\n if (!openEnded) {\n if (radiusTop > 0) generateCap(true)\n if (radiusBottom > 0) generateCap(false)\n }\n\n return { positions: new Float32Array(vertices), indices: new Uint32Array(indices) }\n}\n\n/**\n * Cone geometry (three `ConeGeometry` = `CylinderGeometry(0, radius, ...)`).\n * @param radius - base radius.\n * @param height - height along Y.\n * @param radialSegments - radial segment count.\n * @param heightSegments - axial segment count.\n * @param openEnded - skip the base cap when true.\n * @param thetaStart - start angle.\n * @param thetaLength - swept angle.\n * @returns positions + indices in three's vertex/index order.\n */\nexport function coneGeometry(\n radius = 1,\n height = 1,\n radialSegments = 32,\n heightSegments = 1,\n openEnded = false,\n thetaStart = 0,\n thetaLength = Math.PI * 2,\n): GeoData {\n return cylinderGeometry(0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength)\n}\n\n/**\n * Sphere geometry (three `SphereGeometry`).\n * @param radius - sphere radius.\n * @param widthSegments - longitude segment count.\n * @param heightSegments - latitude segment count.\n * @param phiStart - start longitude.\n * @param phiLength - swept longitude.\n * @param thetaStart - start latitude.\n * @param thetaLength - swept latitude.\n * @returns positions + indices in three's vertex/index order.\n */\nexport function sphereGeometry(\n radius = 1,\n widthSegments = 32,\n heightSegments = 16,\n phiStart = 0,\n phiLength = Math.PI * 2,\n thetaStart = 0,\n thetaLength = Math.PI,\n): GeoData {\n const wSeg = Math.max(3, Math.floor(widthSegments))\n const hSeg = Math.max(2, Math.floor(heightSegments))\n const thetaEnd = Math.min(thetaStart + thetaLength, Math.PI)\n\n let index = 0\n const grid: number[][] = []\n const indices: number[] = []\n const vertices: number[] = []\n\n for (let iy = 0; iy <= hSeg; iy++) {\n const verticesRow: number[] = []\n const v = iy / hSeg\n for (let ix = 0; ix <= wSeg; ix++) {\n const u = ix / wSeg\n const x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength)\n const y = radius * Math.cos(thetaStart + v * thetaLength)\n const z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength)\n vertices.push(x, y, z)\n verticesRow.push(index++)\n }\n grid.push(verticesRow)\n }\n\n for (let iy = 0; iy < hSeg; iy++) {\n for (let ix = 0; ix < wSeg; ix++) {\n const a = grid[iy][ix + 1]\n const b = grid[iy][ix]\n const c = grid[iy + 1][ix]\n const d = grid[iy + 1][ix + 1]\n if (iy !== 0 || thetaStart > 0) indices.push(a, b, d)\n if (iy !== hSeg - 1 || thetaEnd < Math.PI) indices.push(b, c, d)\n }\n }\n\n return { positions: new Float32Array(vertices), indices: new Uint32Array(indices) }\n}\n\n/** Re-export the raw mesh container type for callers. */\nexport type { MeshData }"]}
@@ -1 +1 @@
1
- {"version":3,"file":"weld.js","sourceRoot":"","sources":["../../../src/mesh/meshdata/weld.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CACtB,SAA4B,EAC5B,OAA0B,EAC1B,QAAgB,OAAO,CAAC,MAAM;IAE9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAA4C,CAAA;IAChE,MAAM,YAAY,GAAa,EAAE,CAAA;IACjC,MAAM,YAAY,GAAa,EAAE,CAAA;IAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;QACrB,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;QAC3B,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QAC/B,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;QAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;QAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;QAE9B,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACvB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,GAAG,IAAI,GAAG,EAA+B,CAAA;YAC7C,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;QACpB,CAAC;QACD,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACvB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAA;YAChC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;QACpB,CAAC;QACD,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACrB,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,EAAE,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAA;YAC5B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;YAChB,YAAY,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QAC5B,CAAC;QACD,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACvB,CAAC;IAED,OAAO;QACL,SAAS,EAAE,IAAI,YAAY,CAAC,YAAY,CAAC;QACzC,OAAO,EAAE,IAAI,WAAW,CAAC,YAAY,CAAC;KACvC,CAAA;AACH,CAAC","sourcesContent":["/**\r\n * meshdata/weld — 顶点焊接(从 `boolean/geo-convert.ts` 迁出的共享实现)。\r\n *\r\n * 按 1e-6 量化位置把重复顶点焊成唯一顶点,并把索引用焊接后的编号重写。\r\n * 这是 mesh 面从「未焊接的生成几何」到「Shape」的统一收口,`geo-convert` 与\r\n * `meshdata` 共用同一实现(一个事实一个家,避免两份焊接逻辑漂移)。\r\n */\r\n\r\n/** Interleaved positions + triangle indices (the raw mesh container). */\r\nexport interface MeshData {\r\n positions: Float32Array\r\n indices: Uint32Array\r\n}\r\n\r\n/**\r\n * Weld duplicate vertices by 1e-6-quantised position.\r\n * @param positions - flat position array (x, y, z, ...).\r\n * @param indices - triangle index array into `positions`.\r\n * @param count - number of indices to consume (defaults to the whole array).\r\n * @returns welded positions and rewritten indices.\r\n */\r\nexport function weldMesh(\r\n positions: ArrayLike<number>,\r\n indices: ArrayLike<number>,\r\n count: number = indices.length,\r\n): MeshData {\r\n const mapX = new Map<number, Map<number, Map<number, number>>>()\r\n const weldedPosArr: number[] = []\r\n const weldedIdxArr: number[] = []\r\n\r\n for (let i = 0; i < count; i++) {\r\n const vi = indices[i]\r\n const x = positions[vi * 3]\r\n const y = positions[vi * 3 + 1]\r\n const z = positions[vi * 3 + 2]\r\n const qx = Math.round(x * 1e6)\r\n const qy = Math.round(y * 1e6)\r\n const qz = Math.round(z * 1e6)\r\n\r\n let mapY = mapX.get(qx)\r\n if (mapY === undefined) {\r\n mapY = new Map<number, Map<number, number>>()\r\n mapX.set(qx, mapY)\r\n }\r\n let mapZ = mapY.get(qy)\r\n if (mapZ === undefined) {\r\n mapZ = new Map<number, number>()\r\n mapY.set(qy, mapZ)\r\n }\r\n let ni = mapZ.get(qz)\r\n if (ni === undefined) {\r\n ni = weldedPosArr.length / 3\r\n mapZ.set(qz, ni)\r\n weldedPosArr.push(x, y, z)\r\n }\r\n weldedIdxArr.push(ni)\r\n }\r\n\r\n return {\r\n positions: new Float32Array(weldedPosArr),\r\n indices: new Uint32Array(weldedIdxArr),\r\n }\r\n}"]}
1
+ {"version":3,"file":"weld.js","sourceRoot":"","sources":["../../../src/mesh/meshdata/weld.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CACtB,SAA4B,EAC5B,OAA0B,EAC1B,QAAgB,OAAO,CAAC,MAAM;IAE9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAA4C,CAAA;IAChE,MAAM,YAAY,GAAa,EAAE,CAAA;IACjC,MAAM,YAAY,GAAa,EAAE,CAAA;IAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;QACrB,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;QAC3B,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QAC/B,MAAM,CAAC,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;QAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;QAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;QAE9B,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACvB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,GAAG,IAAI,GAAG,EAA+B,CAAA;YAC7C,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;QACpB,CAAC;QACD,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACvB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAA;YAChC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;QACpB,CAAC;QACD,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACrB,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,EAAE,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAA;YAC5B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;YAChB,YAAY,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QAC5B,CAAC;QACD,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACvB,CAAC;IAED,OAAO;QACL,SAAS,EAAE,IAAI,YAAY,CAAC,YAAY,CAAC;QACzC,OAAO,EAAE,IAAI,WAAW,CAAC,YAAY,CAAC;KACvC,CAAA;AACH,CAAC","sourcesContent":["/**\n * meshdata/weld — 顶点焊接(从 `boolean/geo-convert.ts` 迁出的共享实现)。\n *\n * 按 1e-6 量化位置把重复顶点焊成唯一顶点,并把索引用焊接后的编号重写。\n * 这是 mesh 面从「未焊接的生成几何」到「Shape」的统一收口,`geo-convert` 与\n * `meshdata` 共用同一实现(一个事实一个家,避免两份焊接逻辑漂移)。\n */\n\n/** Interleaved positions + triangle indices (the raw mesh container). */\nexport interface MeshData {\n positions: Float32Array\n indices: Uint32Array\n}\n\n/**\n * Weld duplicate vertices by 1e-6-quantised position.\n * @param positions - flat position array (x, y, z, ...).\n * @param indices - triangle index array into `positions`.\n * @param count - number of indices to consume (defaults to the whole array).\n * @returns welded positions and rewritten indices.\n */\nexport function weldMesh(\n positions: ArrayLike<number>,\n indices: ArrayLike<number>,\n count: number = indices.length,\n): MeshData {\n const mapX = new Map<number, Map<number, Map<number, number>>>()\n const weldedPosArr: number[] = []\n const weldedIdxArr: number[] = []\n\n for (let i = 0; i < count; i++) {\n const vi = indices[i]\n const x = positions[vi * 3]\n const y = positions[vi * 3 + 1]\n const z = positions[vi * 3 + 2]\n const qx = Math.round(x * 1e6)\n const qy = Math.round(y * 1e6)\n const qz = Math.round(z * 1e6)\n\n let mapY = mapX.get(qx)\n if (mapY === undefined) {\n mapY = new Map<number, Map<number, number>>()\n mapX.set(qx, mapY)\n }\n let mapZ = mapY.get(qy)\n if (mapZ === undefined) {\n mapZ = new Map<number, number>()\n mapY.set(qy, mapZ)\n }\n let ni = mapZ.get(qz)\n if (ni === undefined) {\n ni = weldedPosArr.length / 3\n mapZ.set(qz, ni)\n weldedPosArr.push(x, y, z)\n }\n weldedIdxArr.push(ni)\n }\n\n return {\n positions: new Float32Array(weldedPosArr),\n indices: new Uint32Array(weldedIdxArr),\n }\n}"]}
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/node-host/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/node-host/cli.ts"],"names":[],"mappings":"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"}
@@ -291,7 +291,7 @@ export function selectExportableTerminals(terminals, includeHidden = false) {
291
291
  */
292
292
  export function isExportableSolid(shape, probe) {
293
293
  // 无 BREP 句柄(纯 mesh 终端)→ 导出(既有能力,零回归)。
294
- if (!shape || !probe)
294
+ if (shape === undefined || !probe)
295
295
  return true;
296
296
  let type;
297
297
  try {
@@ -626,7 +626,8 @@ function writeAssemblyStep(outPath, ext, compound, execResult, hiddenTerminals)
626
626
  // transformed members.
627
627
  const child = children[i];
628
628
  const liveSolid = child ? brepOf(child) : undefined;
629
- if (liveSolid) {
629
+ // 句柄 0 也是合法句柄(brepkit 0 基)——存在性判断必须写 `!== undefined`。
630
+ if (liveSolid !== undefined) {
630
631
  if (!kernel)
631
632
  kernel = execResult.brepSolids?.values().next().value?.kernel ?? null;
632
633
  if (kernel) {