fluidcad 0.0.32 → 0.0.34

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 (279) hide show
  1. package/README.md +3 -2
  2. package/bin/commands/init.js +55 -0
  3. package/bin/commands/mcp.js +33 -0
  4. package/bin/commands/serve.js +77 -0
  5. package/bin/fluidcad.js +15 -107
  6. package/lib/dist/common/scene-object.d.ts +4 -1
  7. package/lib/dist/common/scene-object.js +9 -2
  8. package/lib/dist/common/solid.d.ts +4 -1
  9. package/lib/dist/common/solid.js +13 -0
  10. package/lib/dist/core/2d/tarc.d.ts +20 -2
  11. package/lib/dist/core/2d/tarc.js +24 -0
  12. package/lib/dist/core/index.d.ts +2 -1
  13. package/lib/dist/core/index.js +1 -0
  14. package/lib/dist/core/interfaces.d.ts +107 -2
  15. package/lib/dist/core/load.d.ts +2 -2
  16. package/lib/dist/core/repeat.js +62 -46
  17. package/lib/dist/core/rib.d.ts +18 -0
  18. package/lib/dist/core/rib.js +37 -0
  19. package/lib/dist/features/2d/arc.d.ts +8 -2
  20. package/lib/dist/features/2d/arc.js +94 -17
  21. package/lib/dist/features/2d/back.js +3 -2
  22. package/lib/dist/features/2d/sketch.d.ts +4 -0
  23. package/lib/dist/features/2d/sketch.js +21 -0
  24. package/lib/dist/features/2d/tarc-constrained.d.ts +2 -0
  25. package/lib/dist/features/2d/tarc-constrained.js +8 -0
  26. package/lib/dist/features/2d/tarc-radius-to-object.d.ts +16 -0
  27. package/lib/dist/features/2d/tarc-radius-to-object.js +58 -0
  28. package/lib/dist/features/2d/tarc-to-object.d.ts +18 -0
  29. package/lib/dist/features/2d/tarc-to-object.js +66 -0
  30. package/lib/dist/features/2d/tarc-to-point-tangent.d.ts +2 -0
  31. package/lib/dist/features/2d/tarc-to-point-tangent.js +3 -0
  32. package/lib/dist/features/2d/tarc-to-point.d.ts +2 -0
  33. package/lib/dist/features/2d/tarc-to-point.js +3 -0
  34. package/lib/dist/features/2d/tarc-with-tangent.d.ts +2 -0
  35. package/lib/dist/features/2d/tarc-with-tangent.js +3 -0
  36. package/lib/dist/features/2d/tarc.d.ts +2 -0
  37. package/lib/dist/features/2d/tarc.js +3 -0
  38. package/lib/dist/features/extrude-base.d.ts +9 -0
  39. package/lib/dist/features/extrude-base.js +22 -0
  40. package/lib/dist/features/extrude-to-face.js +1 -5
  41. package/lib/dist/features/extrude-two-distances.js +1 -2
  42. package/lib/dist/features/extrude.js +1 -2
  43. package/lib/dist/features/load.d.ts +6 -0
  44. package/lib/dist/features/load.js +53 -1
  45. package/lib/dist/features/mirror-feature.d.ts +3 -2
  46. package/lib/dist/features/mirror-feature.js +1 -1
  47. package/lib/dist/features/repeat-circular.d.ts +3 -3
  48. package/lib/dist/features/repeat-circular.js +8 -1
  49. package/lib/dist/features/repeat-linear.d.ts +4 -2
  50. package/lib/dist/features/repeat-linear.js +10 -1
  51. package/lib/dist/features/repeat-matrix.d.ts +3 -1
  52. package/lib/dist/features/repeat-matrix.js +7 -2
  53. package/lib/dist/features/rib.d.ts +31 -0
  54. package/lib/dist/features/rib.js +321 -0
  55. package/lib/dist/features/select.d.ts +1 -0
  56. package/lib/dist/features/select.js +81 -10
  57. package/lib/dist/features/shell.d.ts +4 -1
  58. package/lib/dist/features/shell.js +14 -3
  59. package/lib/dist/filters/edge/belongs-to-face.d.ts +12 -9
  60. package/lib/dist/filters/edge/belongs-to-face.js +64 -15
  61. package/lib/dist/filters/filter-builder-base.d.ts +25 -0
  62. package/lib/dist/filters/filter-builder-base.js +47 -0
  63. package/lib/dist/filters/filter.js +39 -14
  64. package/lib/dist/filters/from-object.d.ts +4 -0
  65. package/lib/dist/filters/from-object.js +10 -0
  66. package/lib/dist/helpers/clone-transform.d.ts +2 -1
  67. package/lib/dist/helpers/scene-helpers.d.ts +1 -1
  68. package/lib/dist/helpers/scene-helpers.js +146 -12
  69. package/lib/dist/index.d.ts +7 -1
  70. package/lib/dist/index.js +3 -3
  71. package/lib/dist/io/file-import.d.ts +5 -1
  72. package/lib/dist/io/file-import.js +29 -18
  73. package/lib/dist/math/lazy-matrix.d.ts +31 -0
  74. package/lib/dist/math/lazy-matrix.js +66 -0
  75. package/lib/dist/oc/color-transfer.d.ts +19 -8
  76. package/lib/dist/oc/color-transfer.js +70 -12
  77. package/lib/dist/oc/constraints/constraint-solver-adaptor.d.ts +5 -0
  78. package/lib/dist/oc/constraints/constraint-solver-adaptor.js +16 -0
  79. package/lib/dist/oc/constraints/constraint-solver.d.ts +4 -0
  80. package/lib/dist/oc/constraints/curve/curve-constraint-solver.d.ts +4 -0
  81. package/lib/dist/oc/constraints/curve/curve-constraint-solver.js +3 -0
  82. package/lib/dist/oc/constraints/geometric/geometric-constraint-solver.d.ts +6 -1
  83. package/lib/dist/oc/constraints/geometric/geometric-constraint-solver.js +4 -0
  84. package/lib/dist/oc/constraints/geometric/tangent-arc-from-point-tangent.d.ts +8 -0
  85. package/lib/dist/oc/constraints/geometric/tangent-arc-from-point-tangent.js +111 -0
  86. package/lib/dist/oc/constraints/geometric/tangent-arc-radius-to-object.d.ts +8 -0
  87. package/lib/dist/oc/constraints/geometric/tangent-arc-radius-to-object.js +161 -0
  88. package/lib/dist/oc/extrude-ops.d.ts +2 -1
  89. package/lib/dist/oc/extrude-ops.js +51 -2
  90. package/lib/dist/oc/mesh.d.ts +9 -4
  91. package/lib/dist/oc/mesh.js +14 -13
  92. package/lib/dist/oc/rib-ops.d.ts +35 -0
  93. package/lib/dist/oc/rib-ops.js +619 -0
  94. package/lib/dist/oc/shell-ops.d.ts +2 -1
  95. package/lib/dist/oc/shell-ops.js +5 -2
  96. package/lib/dist/oc/topology-index.d.ts +6 -0
  97. package/lib/dist/oc/topology-index.js +36 -0
  98. package/lib/dist/rendering/mesh-builder.d.ts +3 -0
  99. package/lib/dist/rendering/mesh-builder.js +8 -4
  100. package/lib/dist/rendering/render-edge.d.ts +2 -1
  101. package/lib/dist/rendering/render-edge.js +2 -2
  102. package/lib/dist/rendering/render-face.d.ts +2 -1
  103. package/lib/dist/rendering/render-face.js +2 -2
  104. package/lib/dist/rendering/render-solid.d.ts +2 -1
  105. package/lib/dist/rendering/render-solid.js +3 -5
  106. package/lib/dist/rendering/render-wire.d.ts +2 -1
  107. package/lib/dist/rendering/render-wire.js +2 -2
  108. package/lib/dist/rendering/render.d.ts +4 -0
  109. package/lib/dist/rendering/render.js +50 -2
  110. package/lib/dist/rendering/scene-compare.js +3 -0
  111. package/lib/dist/rendering/scene.d.ts +1 -0
  112. package/lib/dist/rendering/scene.js +4 -0
  113. package/lib/dist/scene-manager.d.ts +4 -2
  114. package/lib/dist/scene-manager.js +12 -4
  115. package/lib/dist/tests/features/2d/arc.test.js +64 -0
  116. package/lib/dist/tests/features/2d/back.test.js +17 -1
  117. package/lib/dist/tests/features/2d/tarc.test.js +157 -0
  118. package/lib/dist/tests/features/color-lineage.test.js +18 -0
  119. package/lib/dist/tests/features/filter-positional.test.d.ts +1 -0
  120. package/lib/dist/tests/features/filter-positional.test.js +129 -0
  121. package/lib/dist/tests/features/repeat-user-repro.test.d.ts +1 -0
  122. package/lib/dist/tests/features/repeat-user-repro.test.js +60 -0
  123. package/lib/dist/tests/features/rib.test.d.ts +1 -0
  124. package/lib/dist/tests/features/rib.test.js +598 -0
  125. package/lib/dist/tests/features/shell.test.js +36 -0
  126. package/lib/dist/tests/global-setup.js +2 -1
  127. package/lib/dist/tests/helpers/extract-blocks.d.ts +9 -0
  128. package/lib/dist/tests/helpers/extract-blocks.js +56 -0
  129. package/lib/dist/tests/llm-docs-examples.test.d.ts +1 -0
  130. package/lib/dist/tests/llm-docs-examples.test.js +62 -0
  131. package/lib/dist/tests/scene-compare.test.d.ts +1 -0
  132. package/lib/dist/tests/scene-compare.test.js +77 -0
  133. package/lib/dist/tests/setup.js +2 -1
  134. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  135. package/llm-docs/.coverage-allowlist.txt +9 -0
  136. package/llm-docs/api/arc.md +48 -0
  137. package/llm-docs/api/axis.md +42 -0
  138. package/llm-docs/api/bezier.md +42 -0
  139. package/llm-docs/api/booleans.md +44 -0
  140. package/llm-docs/api/chamfer.md +40 -0
  141. package/llm-docs/api/circle.md +36 -0
  142. package/llm-docs/api/color.md +34 -0
  143. package/llm-docs/api/connect.md +41 -0
  144. package/llm-docs/api/constraint-qualifiers.md +48 -0
  145. package/llm-docs/api/copy.md +63 -0
  146. package/llm-docs/api/cursor-lines.md +50 -0
  147. package/llm-docs/api/cursor-move.md +61 -0
  148. package/llm-docs/api/cut.md +55 -0
  149. package/llm-docs/api/draft.md +36 -0
  150. package/llm-docs/api/edge-filter.md +57 -0
  151. package/llm-docs/api/ellipse.md +34 -0
  152. package/llm-docs/api/extrude.md +74 -0
  153. package/llm-docs/api/face-filter.md +61 -0
  154. package/llm-docs/api/fillet.md +51 -0
  155. package/llm-docs/api/index.json +139 -0
  156. package/llm-docs/api/line.md +42 -0
  157. package/llm-docs/api/load.md +37 -0
  158. package/llm-docs/api/local.md +38 -0
  159. package/llm-docs/api/loft.md +37 -0
  160. package/llm-docs/api/mirror.md +44 -0
  161. package/llm-docs/api/offset.md +36 -0
  162. package/llm-docs/api/part.md +40 -0
  163. package/llm-docs/api/plane.md +44 -0
  164. package/llm-docs/api/polygon.md +37 -0
  165. package/llm-docs/api/primitive-solids.md +39 -0
  166. package/llm-docs/api/project-intersect.md +48 -0
  167. package/llm-docs/api/rect.md +48 -0
  168. package/llm-docs/api/remove.md +32 -0
  169. package/llm-docs/api/repeat.md +79 -0
  170. package/llm-docs/api/revolve.md +38 -0
  171. package/llm-docs/api/rib.md +40 -0
  172. package/llm-docs/api/rotate.md +37 -0
  173. package/llm-docs/api/select.md +41 -0
  174. package/llm-docs/api/shell.md +41 -0
  175. package/llm-docs/api/sketch.md +76 -0
  176. package/llm-docs/api/slot.md +36 -0
  177. package/llm-docs/api/split-trim.md +42 -0
  178. package/llm-docs/api/sweep.md +43 -0
  179. package/llm-docs/api/tarc.md +45 -0
  180. package/llm-docs/api/tcircle.md +38 -0
  181. package/llm-docs/api/tline.md +42 -0
  182. package/llm-docs/api/translate.md +40 -0
  183. package/llm-docs/api/types/aline.md +35 -0
  184. package/llm-docs/api/types/arc-angles.md +29 -0
  185. package/llm-docs/api/types/arc-points.md +48 -0
  186. package/llm-docs/api/types/axis-like.md +38 -0
  187. package/llm-docs/api/types/axis.md +21 -0
  188. package/llm-docs/api/types/boolean-operation.md +50 -0
  189. package/llm-docs/api/types/circular-repeat-options.md +31 -0
  190. package/llm-docs/api/types/common.md +32 -0
  191. package/llm-docs/api/types/cut.md +125 -0
  192. package/llm-docs/api/types/draft.md +21 -0
  193. package/llm-docs/api/types/extrudable-geometry.md +23 -0
  194. package/llm-docs/api/types/extrude.md +194 -0
  195. package/llm-docs/api/types/geometry.md +51 -0
  196. package/llm-docs/api/types/hline.md +35 -0
  197. package/llm-docs/api/types/linear-repeat-options.md +31 -0
  198. package/llm-docs/api/types/loft.md +154 -0
  199. package/llm-docs/api/types/mirror.md +35 -0
  200. package/llm-docs/api/types/offset.md +31 -0
  201. package/llm-docs/api/types/plane-like.md +35 -0
  202. package/llm-docs/api/types/plane-transform-options.md +29 -0
  203. package/llm-docs/api/types/plane.md +21 -0
  204. package/llm-docs/api/types/point-like.md +22 -0
  205. package/llm-docs/api/types/point2dlike.md +26 -0
  206. package/llm-docs/api/types/polygon.md +46 -0
  207. package/llm-docs/api/types/rect.md +128 -0
  208. package/llm-docs/api/types/revolve.md +102 -0
  209. package/llm-docs/api/types/rib.md +133 -0
  210. package/llm-docs/api/types/scene-object.md +33 -0
  211. package/llm-docs/api/types/select.md +21 -0
  212. package/llm-docs/api/types/shell.md +54 -0
  213. package/llm-docs/api/types/slot.md +43 -0
  214. package/llm-docs/api/types/sweep.md +189 -0
  215. package/llm-docs/api/types/tangent-arc-two-objects.md +46 -0
  216. package/llm-docs/api/types/transformable.md +93 -0
  217. package/llm-docs/api/types/trim.md +27 -0
  218. package/llm-docs/api/types/two-objects-tangent-line.md +46 -0
  219. package/llm-docs/api/types/vertex.md +17 -0
  220. package/llm-docs/api/types/vline.md +35 -0
  221. package/llm-docs/concepts/coordinate-system.md +45 -0
  222. package/llm-docs/concepts/history-and-rollback.md +40 -0
  223. package/llm-docs/concepts/last-selection.md +49 -0
  224. package/llm-docs/concepts/scene-graph.md +37 -0
  225. package/llm-docs/index.json +1750 -0
  226. package/mcp/dist/client.d.ts +64 -0
  227. package/mcp/dist/client.js +248 -0
  228. package/mcp/dist/discovery.d.ts +11 -0
  229. package/mcp/dist/discovery.js +78 -0
  230. package/mcp/dist/docs-index.d.ts +81 -0
  231. package/mcp/dist/docs-index.js +261 -0
  232. package/mcp/dist/resources.d.ts +4 -0
  233. package/mcp/dist/resources.js +115 -0
  234. package/mcp/dist/server.d.ts +12 -0
  235. package/mcp/dist/server.js +489 -0
  236. package/mcp/dist/tools/coordination.d.ts +9 -0
  237. package/mcp/dist/tools/coordination.js +46 -0
  238. package/mcp/dist/tools/docs.d.ts +66 -0
  239. package/mcp/dist/tools/docs.js +122 -0
  240. package/mcp/dist/tools/engine.d.ts +56 -0
  241. package/mcp/dist/tools/engine.js +145 -0
  242. package/mcp/dist/tools/inspection.d.ts +75 -0
  243. package/mcp/dist/tools/inspection.js +121 -0
  244. package/mcp/dist/tools/screenshot.d.ts +63 -0
  245. package/mcp/dist/tools/screenshot.js +263 -0
  246. package/mcp/dist/tools/source.d.ts +84 -0
  247. package/mcp/dist/tools/source.js +434 -0
  248. package/mcp/dist/tools/workspaces.d.ts +13 -0
  249. package/mcp/dist/tools/workspaces.js +33 -0
  250. package/mcp/dist/types.d.ts +18 -0
  251. package/mcp/dist/types.js +11 -0
  252. package/package.json +19 -5
  253. package/server/dist/code-editor.d.ts +36 -0
  254. package/server/dist/code-editor.js +8 -0
  255. package/server/dist/fluidcad-server.d.ts +50 -0
  256. package/server/dist/fluidcad-server.js +153 -1
  257. package/server/dist/global-registry.d.ts +30 -0
  258. package/server/dist/global-registry.js +126 -0
  259. package/server/dist/index.js +171 -26
  260. package/server/dist/instance-file.d.ts +31 -0
  261. package/server/dist/instance-file.js +73 -0
  262. package/server/dist/lint-fluid-js.d.ts +15 -0
  263. package/server/dist/lint-fluid-js.js +271 -0
  264. package/server/dist/routes/editor.d.ts +24 -0
  265. package/server/dist/routes/editor.js +44 -0
  266. package/server/dist/routes/export.d.ts +1 -1
  267. package/server/dist/routes/export.js +45 -8
  268. package/server/dist/routes/health.d.ts +7 -0
  269. package/server/dist/routes/health.js +14 -0
  270. package/server/dist/routes/lint.d.ts +10 -0
  271. package/server/dist/routes/lint.js +28 -0
  272. package/server/dist/routes/render.d.ts +33 -0
  273. package/server/dist/routes/render.js +34 -0
  274. package/server/dist/routes/scene.d.ts +5 -0
  275. package/server/dist/routes/scene.js +48 -0
  276. package/server/dist/routes/screenshot.js +68 -1
  277. package/server/dist/ws-protocol.d.ts +56 -2
  278. package/ui/dist/assets/{index-DMw0OYCF.js → index-BdqrMDRu.js} +30 -30
  279. package/ui/dist/index.html +1 -1
@@ -19,6 +19,25 @@ export interface ISceneObject {
19
19
  */
20
20
  reusable(): this;
21
21
  }
22
+ export interface ILoadFile extends ISceneObject {
23
+ /**
24
+ * Skip applying colors from the imported file's color metadata sidecar.
25
+ */
26
+ noColors(): this;
27
+ /**
28
+ * Keep only the solids at the given 0-based indices (in load order).
29
+ * Combined with {@link exclude} by applying include first, then exclude.
30
+ * Repeated calls accumulate.
31
+ * @param indices - The 0-based solid indices to keep.
32
+ */
33
+ include(...indices: number[]): this;
34
+ /**
35
+ * Drop the solids at the given 0-based indices. Applied after {@link include}.
36
+ * Repeated calls accumulate.
37
+ * @param indices - The 0-based solid indices to drop.
38
+ */
39
+ exclude(...indices: number[]): this;
40
+ }
22
41
  export interface IBooleanOperation extends ISceneObject {
23
42
  /**
24
43
  * Additive boolean operation — fuses the result with all intersecting scene objects.
@@ -138,13 +157,27 @@ export interface IArcPoints extends IExtrudableGeometry {
138
157
  * Positive = CCW, negative = CW.
139
158
  * @param value - The bulge radius.
140
159
  */
141
- radius(value: number): this;
160
+ radius(value: number): IArcRadius;
142
161
  /**
143
162
  * Specifies the circle center point for the arc.
144
163
  * Mutually exclusive with `.radius()`.
145
164
  * @param value - The center point of the arc's circle.
146
165
  */
147
- center(value: Point2DLike): this;
166
+ center(value: Point2DLike): IArcCenter;
167
+ }
168
+ export interface IArcRadius extends IExtrudableGeometry {
169
+ /**
170
+ * Switches to the major arc (> 180°).
171
+ * By default, `.radius()` produces the minor arc (< 180°);
172
+ * `.major()` switches to the complementary major arc on the same circle.
173
+ */
174
+ major(): this;
175
+ }
176
+ export interface IArcCenter extends IExtrudableGeometry {
177
+ /**
178
+ * Sweeps the arc clockwise from start to end instead of the default counter-clockwise.
179
+ */
180
+ cw(): this;
148
181
  }
149
182
  export interface IArcAngles extends IExtrudableGeometry {
150
183
  /**
@@ -279,6 +312,14 @@ export interface ITwoObjectsTangentLine extends IGeometry {
279
312
  */
280
313
  end(index?: number): LazyVertex;
281
314
  }
315
+ export interface ITangentArcToObject extends IGeometry {
316
+ /**
317
+ * Flips the arc to the opposite side of the start tangent. By default,
318
+ * the arc curves to the left of the current tangent direction;
319
+ * `.flip()` switches it to the right.
320
+ */
321
+ flip(): this;
322
+ }
282
323
  export interface ITangentArcTwoObjects extends IGeometry {
283
324
  /**
284
325
  * Returns the start vertex of the tangent arc.
@@ -695,6 +736,64 @@ export interface IRotate extends ISceneObject {
695
736
  }
696
737
  export interface IDraft extends ISceneObject {
697
738
  }
739
+ export interface IRib extends IBooleanOperation {
740
+ /**
741
+ * Selects faces at the start (base) of the rib — the profile face at the sketch plane.
742
+ * @param args - Numeric indices or {@link FaceFilterBuilder} instances to filter the selection.
743
+ */
744
+ startFaces(...args: (number | FaceFilterBuilder)[]): ISceneObject;
745
+ /**
746
+ * Selects faces at the end (top) of the rib — where the rib meets the boundary.
747
+ * @param args - Numeric indices or {@link FaceFilterBuilder} instances to filter the selection.
748
+ */
749
+ endFaces(...args: (number | FaceFilterBuilder)[]): ISceneObject;
750
+ /**
751
+ * Selects the lateral wall faces of the rib.
752
+ * @param args - Numeric indices or {@link FaceFilterBuilder} instances to filter the selection.
753
+ */
754
+ sideFaces(...args: (number | FaceFilterBuilder)[]): ISceneObject;
755
+ /**
756
+ * Selects the small cap faces at the spine endpoints.
757
+ * @param args - Numeric indices or {@link FaceFilterBuilder} instances to filter the selection.
758
+ */
759
+ capFaces(...args: (number | FaceFilterBuilder)[]): ISceneObject;
760
+ /**
761
+ * Selects edges on the start faces.
762
+ * @param args - Numeric indices or {@link EdgeFilterBuilder} instances to filter the selection.
763
+ */
764
+ startEdges(...args: (number | EdgeFilterBuilder)[]): ISceneObject;
765
+ /**
766
+ * Selects edges on the end faces.
767
+ * @param args - Numeric indices or {@link EdgeFilterBuilder} instances to filter the selection.
768
+ */
769
+ endEdges(...args: (number | EdgeFilterBuilder)[]): ISceneObject;
770
+ /**
771
+ * Selects edges on the side faces, excluding edges shared with start/end faces.
772
+ * @param args - Numeric indices or {@link EdgeFilterBuilder} instances to filter the selection.
773
+ */
774
+ sideEdges(...args: (number | EdgeFilterBuilder)[]): ISceneObject;
775
+ /**
776
+ * Selects edges on the cap faces.
777
+ * @param args - Numeric indices or {@link EdgeFilterBuilder} instances to filter the selection.
778
+ */
779
+ capEdges(...args: (number | EdgeFilterBuilder)[]): ISceneObject;
780
+ /**
781
+ * Applies a draft (taper) angle to the rib walls.
782
+ * @param value - A single angle for uniform draft, or a `[start, end]` tuple for asymmetric draft.
783
+ */
784
+ draft(value: number | [number, number]): this;
785
+ /**
786
+ * Switches the extrusion direction to parallel to the sketch plane
787
+ * (perpendicular to the spine within the plane) instead of normal to it.
788
+ */
789
+ parallel(): this;
790
+ /**
791
+ * Extends the rib's side faces at the spine endpoints outward to blend
792
+ * with the target solids' walls.
793
+ */
794
+ extend(): this;
795
+ }
796
+ export type ShellJoinType = 'arc' | 'intersection' | 'tangent';
698
797
  export interface IShell extends ISceneObject {
699
798
  /**
700
799
  * Selects the inner wall faces created by the shell operation (from thickness removal).
@@ -707,4 +806,10 @@ export interface IShell extends ISceneObject {
707
806
  * @param args - Numeric indices or {@link EdgeFilterBuilder} instances to filter the selection.
708
807
  */
709
808
  internalEdges(...args: (number | EdgeFilterBuilder)[]): ISceneObject;
809
+ /**
810
+ * Sets the join type used at inner-wall corners.
811
+ * @param type - `'arc'` (default) for rounded blends, `'intersection'` for sharp corners,
812
+ * or `'tangent'` for tangent-continuous blends.
813
+ */
814
+ join(type: ShellJoinType): this;
710
815
  }
@@ -1,10 +1,10 @@
1
- import { ISceneObject } from "./interfaces.js";
1
+ import { ILoadFile } from "./interfaces.js";
2
2
  interface LoadFunction {
3
3
  /**
4
4
  * Loads a 3D model file (STEP, STL, etc.) by filename.
5
5
  * @param fileName - The path to the model file
6
6
  */
7
- (fileName: string): ISceneObject;
7
+ (fileName: string): ILoadFile;
8
8
  }
9
9
  declare const _default: LoadFunction;
10
10
  export default _default;
@@ -1,15 +1,36 @@
1
1
  import { registerBuilder } from "../index.js";
2
- import { normalizeAxis, normalizePlane } from "../helpers/normalize.js";
2
+ import { Axis } from "../math/axis.js";
3
+ import { SceneObject } from "../common/scene-object.js";
3
4
  import { Matrix4 } from "../math/matrix4.js";
5
+ import { LazyMatrix } from "../math/lazy-matrix.js";
4
6
  import { rad } from "../helpers/math-helpers.js";
5
7
  import { RepeatLinear } from "../features/repeat-linear.js";
6
8
  import { RepeatCircular } from "../features/repeat-circular.js";
7
9
  import { cloneWithTransform } from "../helpers/clone-transform.js";
8
- import { PlaneObjectBase } from "../features/plane-renderable-base.js";
9
- import { PlaneObject } from "../features/plane.js";
10
10
  import { MirrorFeature } from "../features/mirror-feature.js";
11
11
  import { RepeatMatrix } from "../features/repeat-matrix.js";
12
+ import { resolveAxis, resolvePlane } from "../helpers/resolve.js";
13
+ import { normalizeAxis } from "../helpers/normalize.js";
12
14
  import { AxisObjectBase } from "../features/axis-renderable-base.js";
15
+ /**
16
+ * Resolve a repeat axis argument to a value usable by LazyMatrix. Scene-
17
+ * resident sources (AxisObjectBase or an edge SceneObject) go through
18
+ * resolveAxis so they end up in the scene and get built before consumers.
19
+ * Primitive inputs (world-axis string, raw Axis) stay as concrete Axis
20
+ * values — no extra scene object, no rendered world-axis line.
21
+ */
22
+ function resolveRepeatAxis(arg, context) {
23
+ if (arg instanceof AxisObjectBase) {
24
+ return arg;
25
+ }
26
+ if (arg instanceof SceneObject) {
27
+ return resolveAxis(arg, context);
28
+ }
29
+ if (arg instanceof Axis) {
30
+ return arg;
31
+ }
32
+ return normalizeAxis(arg);
33
+ }
13
34
  function build(context) {
14
35
  return (function repeat() {
15
36
  const args = Array.from(arguments);
@@ -23,8 +44,9 @@ function build(context) {
23
44
  const objects = restObjects.length > 0
24
45
  ? restObjects
25
46
  : [context.getSceneObjects().at(-1)];
26
- const feature = new RepeatMatrix(matrix, objects);
27
- const cloned = cloneWithTransform(objects, matrix, feature);
47
+ const lazy = LazyMatrix.of(matrix);
48
+ const feature = new RepeatMatrix(lazy, objects);
49
+ const cloned = cloneWithTransform(objects, lazy, feature);
28
50
  context.addSceneObject(feature);
29
51
  context.addSceneObjects(cloned);
30
52
  return feature;
@@ -35,9 +57,9 @@ function build(context) {
35
57
  const type = args[0];
36
58
  if (type === 'linear' || type === 'circular') {
37
59
  const axisArg = args[1];
38
- const axes = Array.isArray(axisArg)
39
- ? axisArg.map(a => normalizeAxis(a))
40
- : [normalizeAxis(axisArg)];
60
+ const axisSources = Array.isArray(axisArg)
61
+ ? axisArg.map(a => resolveRepeatAxis(a, context))
62
+ : [resolveRepeatAxis(axisArg, context)];
41
63
  const options = args[2];
42
64
  const restObjects = args.slice(3);
43
65
  const objects = restObjects.length > 0
@@ -51,9 +73,9 @@ function build(context) {
51
73
  const lengths = 'length' in options && options.length != null
52
74
  ? (Array.isArray(options.length) ? options.length : [options.length])
53
75
  : null;
54
- const repeat = new RepeatLinear(axes, options, objects);
76
+ const repeat = new RepeatLinear(axisSources, options, objects);
55
77
  const transformedObjects = [];
56
- const axisOffsets = axes.map((axis, i) => {
78
+ const axisOffsets = axisSources.map((axis, i) => {
57
79
  const count = counts[i] ?? counts[0];
58
80
  const offset = offsets != null
59
81
  ? (offsets[i] ?? offsets[0])
@@ -88,19 +110,26 @@ function build(context) {
88
110
  if (options.skip?.some(s => s.length === indices.length && s.every((v, i) => v === indices[i]))) {
89
111
  continue;
90
112
  }
91
- // Compose translation from all axes
92
- let dx = 0, dy = 0, dz = 0;
93
- for (let a = 0; a < axisOffsets.length; a++) {
94
- const { axis, offset } = axisOffsets[a];
113
+ // Capture per-axis offset + signed index for this instance; the
114
+ // axis direction is read lazily at build time so an AxisObjectBase
115
+ // can still be unbuilt at parse time.
116
+ const perAxis = axisOffsets.map((entry, a) => {
95
117
  const idx = options.centered
96
- ? indices[a] - Math.floor(axisOffsets[a].count / 2)
118
+ ? indices[a] - Math.floor(entry.count / 2)
97
119
  : indices[a];
98
- dx += axis.direction.x * offset * idx;
99
- dy += axis.direction.y * offset * idx;
100
- dz += axis.direction.z * offset * idx;
101
- }
102
- const transform = Matrix4.fromTranslation(dx, dy, dz);
103
- const cloned = cloneWithTransform(objects, transform, repeat);
120
+ return { axis: entry.axis, offset: entry.offset, idx };
121
+ });
122
+ const lazy = LazyMatrix.from(() => {
123
+ let dx = 0, dy = 0, dz = 0;
124
+ for (const { axis, offset, idx } of perAxis) {
125
+ const dir = (axis instanceof AxisObjectBase ? axis.getAxis() : axis).direction;
126
+ dx += dir.x * offset * idx;
127
+ dy += dir.y * offset * idx;
128
+ dz += dir.z * offset * idx;
129
+ }
130
+ return Matrix4.fromTranslation(dx, dy, dz);
131
+ });
132
+ const cloned = cloneWithTransform(objects, lazy, repeat);
104
133
  transformedObjects.push(...cloned);
105
134
  }
106
135
  context.addSceneObject(repeat);
@@ -108,7 +137,7 @@ function build(context) {
108
137
  return repeat;
109
138
  }
110
139
  if (type === 'circular') {
111
- const axis = axes[0];
140
+ const axis = axisSources[0];
112
141
  const circularOptions = options;
113
142
  const { count, centered, skip } = circularOptions;
114
143
  const repeat = new RepeatCircular(axis, circularOptions, objects);
@@ -127,8 +156,8 @@ function build(context) {
127
156
  continue;
128
157
  }
129
158
  const angle = startOffset + offset * i;
130
- const matrix = Matrix4.fromRotationAroundAxis(axis.origin, axis.direction, rad(angle));
131
- const cloned = cloneWithTransform(objects, matrix, repeat);
159
+ const lazy = LazyMatrix.rotation(axis, rad(angle));
160
+ const cloned = cloneWithTransform(objects, lazy, repeat);
132
161
  transformedObjects.push(...cloned);
133
162
  }
134
163
  context.addSceneObject(repeat);
@@ -142,31 +171,16 @@ function build(context) {
142
171
  const targetObjects = restObjects.length > 0
143
172
  ? restObjects
144
173
  : [context.getSceneObjects().at(-1)];
145
- let planeObj;
146
- let normalizedPlane;
147
- if (planeArg instanceof PlaneObjectBase) {
148
- planeObj = planeArg;
149
- planeObj.build();
150
- normalizedPlane = planeObj.getPlane();
151
- }
152
- else {
153
- normalizedPlane = normalizePlane(planeArg);
154
- planeObj = new PlaneObject(normalizedPlane);
155
- planeObj.build();
156
- context.addSceneObject(planeObj);
157
- }
158
- const matrix = Matrix4.mirrorPlane(normalizedPlane.normal, normalizedPlane.origin);
159
- const mirrorFeature = new MirrorFeature(planeObj, matrix);
160
- const mirrorTree = cloneWithTransform(targetObjects, matrix, mirrorFeature);
174
+ const planeObj = resolvePlane(planeArg, context);
175
+ const lazy = LazyMatrix.mirror(planeObj);
176
+ const mirrorFeature = new MirrorFeature(planeObj, lazy);
177
+ const mirrorTree = cloneWithTransform(targetObjects, lazy, mirrorFeature);
161
178
  context.addSceneObject(mirrorFeature);
162
179
  context.addSceneObjects(mirrorTree);
163
180
  return mirrorFeature;
164
181
  }
165
182
  if (type === 'rotate') {
166
183
  const axisArg = args[1];
167
- const axis = axisArg instanceof AxisObjectBase
168
- ? axisArg.getAxis()
169
- : normalizeAxis(axisArg);
170
184
  let angle = 90;
171
185
  let restStart = 2;
172
186
  if (typeof args[2] === 'number') {
@@ -177,9 +191,11 @@ function build(context) {
177
191
  const objects = restObjects.length > 0
178
192
  ? restObjects
179
193
  : [context.getSceneObjects().at(-1)];
180
- const matrix = Matrix4.fromRotationAroundAxis(axis.origin, axis.direction, rad(angle));
181
- const feature = new RepeatMatrix(matrix, objects);
182
- const cloned = cloneWithTransform(objects, matrix, feature);
194
+ const axis = resolveRepeatAxis(axisArg, context);
195
+ const lazy = LazyMatrix.rotation(axis, rad(angle));
196
+ const sources = axis instanceof AxisObjectBase ? [axis] : [];
197
+ const feature = new RepeatMatrix(lazy, objects, sources);
198
+ const cloned = cloneWithTransform(objects, lazy, feature);
183
199
  context.addSceneObject(feature);
184
200
  context.addSceneObjects(cloned);
185
201
  return feature;
@@ -0,0 +1,18 @@
1
+ import { IRib, ISceneObject } from "./interfaces.js";
2
+ interface RibFunction {
3
+ /**
4
+ * Creates a rib from the last sketch with the given thickness.
5
+ * The rib extends in the sketch normal direction until it reaches
6
+ * surrounding solids. Positive thickness = forward, negative = reverse.
7
+ * @param thickness - Wall thickness (sign controls direction)
8
+ */
9
+ (thickness: number): IRib;
10
+ /**
11
+ * Creates a rib from an explicit sketch spine with the given thickness.
12
+ * @param thickness - Wall thickness (sign controls direction)
13
+ * @param spine - The sketch providing the rib spine wire and plane
14
+ */
15
+ (thickness: number, spine: ISceneObject): IRib;
16
+ }
17
+ declare const _default: RibFunction;
18
+ export default _default;
@@ -0,0 +1,37 @@
1
+ import { SceneObject } from "../common/scene-object.js";
2
+ import { registerBuilder } from "../index.js";
3
+ import { Rib } from "../features/rib.js";
4
+ function isExtrudable(obj) {
5
+ return obj instanceof SceneObject && obj.isExtrudable();
6
+ }
7
+ function build(context) {
8
+ //@ts-ignore
9
+ return function rib() {
10
+ const args = [...arguments];
11
+ if (args.length === 0) {
12
+ throw new Error("rib() requires at least a thickness argument.");
13
+ }
14
+ const thickness = args[0];
15
+ if (typeof thickness !== 'number' || thickness === 0) {
16
+ throw new Error("rib() thickness must be a non-zero number.");
17
+ }
18
+ let spine;
19
+ let extrudable;
20
+ if (args.length > 1 && isExtrudable(args[1])) {
21
+ spine = args[1];
22
+ extrudable = args[1];
23
+ }
24
+ else {
25
+ const lastExtrudable = context.getLastExtrudable();
26
+ if (!lastExtrudable) {
27
+ throw new Error("rib() requires a sketch. No sketch found in the scene.");
28
+ }
29
+ spine = lastExtrudable;
30
+ extrudable = lastExtrudable;
31
+ }
32
+ const result = new Rib(thickness, spine, extrudable);
33
+ context.addSceneObject(result);
34
+ return result;
35
+ };
36
+ }
37
+ export default registerBuilder(build);
@@ -2,9 +2,9 @@ import { Point2DLike } from "../../math/point.js";
2
2
  import { PlaneObjectBase } from "../plane-renderable-base.js";
3
3
  import { GeometrySceneObject } from "./geometry.js";
4
4
  import { LazyVertex } from "../lazy-vertex.js";
5
- import { IArcPoints, IArcAngles } from "../../core/interfaces.js";
5
+ import { IArcPoints, IArcRadius, IArcCenter, IArcAngles } from "../../core/interfaces.js";
6
6
  import { SceneObject } from "../../common/scene-object.js";
7
- export declare class Arc extends GeometrySceneObject implements IArcPoints, IArcAngles {
7
+ export declare class Arc extends GeometrySceneObject implements IArcPoints, IArcRadius, IArcCenter, IArcAngles {
8
8
  private _startPoint;
9
9
  private _endPoint;
10
10
  private _arcRadius;
@@ -13,18 +13,24 @@ export declare class Arc extends GeometrySceneObject implements IArcPoints, IArc
13
13
  private _bulgeRadius;
14
14
  private _centerPoint;
15
15
  private _centered;
16
+ private _clockwise;
17
+ private _major;
16
18
  private _targetPlane;
17
19
  constructor(targetPlane?: PlaneObjectBase | null);
18
20
  static toPoint(endPoint: LazyVertex, targetPlane?: PlaneObjectBase | null): Arc;
19
21
  static twoPoints(startPoint: LazyVertex, endPoint: LazyVertex, targetPlane?: PlaneObjectBase | null): Arc;
20
22
  static fromAngles(arcRadius: number, startAngle: number, endAngle: number, targetPlane?: PlaneObjectBase | null): Arc;
23
+ private static circumcenter;
21
24
  radius(value: number): this;
22
25
  center(value: Point2DLike): this;
23
26
  centered(): this;
27
+ cw(): this;
28
+ major(): this;
24
29
  build(): void;
25
30
  private buildTwoPointsCenter;
26
31
  private buildTwoPointsBulge;
27
32
  private buildToPoint;
33
+ private makeMajorArc;
28
34
  private buildWithCenter;
29
35
  private buildFromAngles;
30
36
  getType(): string;
@@ -16,6 +16,8 @@ export class Arc extends GeometrySceneObject {
16
16
  _bulgeRadius = 0;
17
17
  _centerPoint = null;
18
18
  _centered = false;
19
+ _clockwise = false;
20
+ _major = false;
19
21
  _targetPlane;
20
22
  constructor(targetPlane = null) {
21
23
  super();
@@ -39,6 +41,13 @@ export class Arc extends GeometrySceneObject {
39
41
  arc._endAngle = endAngle;
40
42
  return arc;
41
43
  }
44
+ static circumcenter(a, b, c) {
45
+ const D = 2 * (a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y));
46
+ const aa = a.x * a.x + a.y * a.y;
47
+ const bb = b.x * b.x + b.y * b.y;
48
+ const cc = c.x * c.x + c.y * c.y;
49
+ return new Point2D((aa * (b.y - c.y) + bb * (c.y - a.y) + cc * (a.y - b.y)) / D, (aa * (c.x - b.x) + bb * (a.x - c.x) + cc * (b.x - a.x)) / D);
50
+ }
42
51
  // Chainable methods (IArc)
43
52
  radius(value) {
44
53
  this._bulgeRadius = value;
@@ -52,6 +61,14 @@ export class Arc extends GeometrySceneObject {
52
61
  this._centered = true;
53
62
  return this;
54
63
  }
64
+ cw() {
65
+ this._clockwise = true;
66
+ return this;
67
+ }
68
+ major() {
69
+ this._major = true;
70
+ return this;
71
+ }
55
72
  build() {
56
73
  if (this._startPoint && this._endPoint) {
57
74
  // Two explicit points: default center = current position
@@ -81,21 +98,26 @@ export class Arc extends GeometrySceneObject {
81
98
  const endPt = this._endPoint.asPoint2D();
82
99
  const centerPt = this._centerPoint
83
100
  ? this._centerPoint.asPoint2D()
84
- : this.getCurrentPosition();
101
+ : new Point2D((startPt.x + endPt.x) / 2, (startPt.y + endPt.y) / 2);
85
102
  const dx = startPt.x - centerPt.x;
86
103
  const dy = startPt.y - centerPt.y;
87
104
  const radius = Math.sqrt(dx * dx + dy * dy);
88
105
  const endAngle = Math.atan2(endPt.y - centerPt.y, endPt.x - centerPt.x);
106
+ const normal = this._clockwise ? plane.normal.negate() : plane.normal;
89
107
  const center = plane.localToWorld(centerPt);
90
108
  const start = plane.localToWorld(startPt);
91
109
  const end = plane.localToWorld(endPt);
92
- const arc = Geometry.makeArc(center, radius, plane.normal, start, end);
110
+ const arc = Geometry.makeArc(center, radius, normal, start, end);
93
111
  const edge = Geometry.makeEdgeFromCurve(arc);
94
- const tx = -Math.sin(endAngle);
95
- const ty = Math.cos(endAngle);
112
+ const sign = this._clockwise ? -1 : 1;
113
+ const tx = sign * (-Math.sin(endAngle));
114
+ const ty = sign * Math.cos(endAngle);
96
115
  this.setTangent(new Point2D(tx, ty));
97
116
  this.setState('start', Vertex.fromPoint2D(startPt));
98
117
  this.setState('end', Vertex.fromPoint2D(endPt));
118
+ const centerVertex = Vertex.fromPoint2D(centerPt);
119
+ centerVertex.markAsMetaShape();
120
+ this.addShape(centerVertex);
99
121
  this.addShape(edge);
100
122
  if (this.sketch) {
101
123
  this.setCurrentPosition(endPt);
@@ -129,14 +151,19 @@ export class Arc extends GeometrySceneObject {
129
151
  const center = plane.localToWorld(centerPoint);
130
152
  const start = plane.localToWorld(startPoint);
131
153
  const end = plane.localToWorld(targetPoint);
132
- const arc = Geometry.makeArc(center, r, normal, start, end);
154
+ const arc = this._major
155
+ ? this.makeMajorArc(startPoint, targetPoint, centerPoint, cw, plane)
156
+ : Geometry.makeArc(center, r, normal, start, end);
133
157
  const edge = Geometry.makeEdgeFromCurve(arc);
134
- const signT = cw ? -1 : 1;
158
+ const signT = (cw ? -1 : 1) * (this._major ? -1 : 1);
135
159
  const endTx = signT * (-Math.sin(endAngle));
136
160
  const endTy = signT * Math.cos(endAngle);
137
161
  this.setTangent(new Point2D(endTx, endTy));
138
162
  this.setState('start', Vertex.fromPoint2D(startPoint));
139
163
  this.setState('end', Vertex.fromPoint2D(targetPoint));
164
+ const centerVertex = Vertex.fromPoint2D(centerPoint);
165
+ centerVertex.markAsMetaShape();
166
+ this.addShape(centerVertex);
140
167
  this.addShape(edge);
141
168
  if (this.sketch) {
142
169
  this.setCurrentPosition(targetPoint);
@@ -172,14 +199,19 @@ export class Arc extends GeometrySceneObject {
172
199
  const center = plane.localToWorld(centerPoint);
173
200
  const start = plane.localToWorld(startPoint);
174
201
  const end = plane.localToWorld(targetPoint);
175
- const arc = Geometry.makeArc(center, r, normal, start, end);
202
+ const arc = this._major
203
+ ? this.makeMajorArc(startPoint, targetPoint, centerPoint, cw, plane)
204
+ : Geometry.makeArc(center, r, normal, start, end);
176
205
  const edge = Geometry.makeEdgeFromCurve(arc);
177
- const signT = cw ? -1 : 1;
206
+ const signT = (cw ? -1 : 1) * (this._major ? -1 : 1);
178
207
  const endTx = signT * (-Math.sin(endAngle));
179
208
  const endTy = signT * Math.cos(endAngle);
180
209
  this.setTangent(new Point2D(endTx, endTy));
181
210
  this.setState('start', Vertex.fromPoint2D(startPoint));
182
211
  this.setState('end', Vertex.fromPoint2D(targetPoint));
212
+ const centerVertex = Vertex.fromPoint2D(centerPoint);
213
+ centerVertex.markAsMetaShape();
214
+ this.addShape(centerVertex);
183
215
  this.addShape(edge);
184
216
  if (this.sketch) {
185
217
  this.setCurrentPosition(targetPoint);
@@ -188,6 +220,24 @@ export class Arc extends GeometrySceneObject {
188
220
  this._targetPlane.removeShapes(this);
189
221
  }
190
222
  }
223
+ makeMajorArc(startPoint2D, endPoint2D, centerPoint2D, cw, plane) {
224
+ const startAngleRad = Math.atan2(startPoint2D.y - centerPoint2D.y, startPoint2D.x - centerPoint2D.x);
225
+ const endAngleRad = Math.atan2(endPoint2D.y - centerPoint2D.y, endPoint2D.x - centerPoint2D.x);
226
+ let minorSweep = cw ? startAngleRad - endAngleRad : endAngleRad - startAngleRad;
227
+ if (minorSweep <= 0) {
228
+ minorSweep += 2 * Math.PI;
229
+ }
230
+ const midAngle = cw
231
+ ? startAngleRad + (2 * Math.PI - minorSweep) / 2
232
+ : startAngleRad - (2 * Math.PI - minorSweep) / 2;
233
+ const r = Math.sqrt((startPoint2D.x - centerPoint2D.x) ** 2 +
234
+ (startPoint2D.y - centerPoint2D.y) ** 2);
235
+ const midPoint2D = new Point2D(centerPoint2D.x + r * Math.cos(midAngle), centerPoint2D.y + r * Math.sin(midAngle));
236
+ const start = plane.localToWorld(startPoint2D);
237
+ const mid = plane.localToWorld(midPoint2D);
238
+ const end = plane.localToWorld(endPoint2D);
239
+ return Geometry.makeArcThreePoints(start, mid, end);
240
+ }
191
241
  buildWithCenter() {
192
242
  const plane = this._targetPlane?.getPlane() || this.sketch.getPlane();
193
243
  const startPt = this._targetPlane
@@ -195,20 +245,33 @@ export class Arc extends GeometrySceneObject {
195
245
  : this.getCurrentPosition();
196
246
  const endPt = this._endPoint.asPoint2D();
197
247
  const centerPt = this._centerPoint.asPoint2D();
198
- const dx = startPt.x - centerPt.x;
199
- const dy = startPt.y - centerPt.y;
200
- const radius = Math.sqrt(dx * dx + dy * dy);
201
- const endAngle = Math.atan2(endPt.y - centerPt.y, endPt.x - centerPt.x);
202
- const center = plane.localToWorld(centerPt);
248
+ const aStart = Math.atan2(startPt.y - centerPt.y, startPt.x - centerPt.x);
249
+ const aEnd = Math.atan2(endPt.y - centerPt.y, endPt.x - centerPt.x);
250
+ let sweep = this._clockwise ? aStart - aEnd : aEnd - aStart;
251
+ if (sweep <= 0) {
252
+ sweep += 2 * Math.PI;
253
+ }
254
+ const midAngle = this._clockwise ? aStart - sweep / 2 : aStart + sweep / 2;
255
+ const rStart = Math.sqrt((startPt.x - centerPt.x) ** 2 + (startPt.y - centerPt.y) ** 2);
256
+ const rEnd = Math.sqrt((endPt.x - centerPt.x) ** 2 + (endPt.y - centerPt.y) ** 2);
257
+ const rMid = (rStart + rEnd) / 2;
258
+ const midPt = new Point2D(centerPt.x + rMid * Math.cos(midAngle), centerPt.y + rMid * Math.sin(midAngle));
259
+ const actualCenter = Arc.circumcenter(startPt, midPt, endPt);
260
+ const endAngle = Math.atan2(endPt.y - actualCenter.y, endPt.x - actualCenter.x);
203
261
  const start = plane.localToWorld(startPt);
204
262
  const end = plane.localToWorld(endPt);
205
- const arc = Geometry.makeArc(center, radius, plane.normal, start, end);
263
+ const mid = plane.localToWorld(midPt);
264
+ const arc = Geometry.makeArcThreePoints(start, mid, end);
206
265
  const edge = Geometry.makeEdgeFromCurve(arc);
207
- const tx = -Math.sin(endAngle);
208
- const ty = Math.cos(endAngle);
266
+ const sign = this._clockwise ? -1 : 1;
267
+ const tx = sign * (-Math.sin(endAngle));
268
+ const ty = sign * Math.cos(endAngle);
209
269
  this.setTangent(new Point2D(tx, ty));
210
270
  this.setState('start', Vertex.fromPoint2D(startPt));
211
271
  this.setState('end', Vertex.fromPoint2D(endPt));
272
+ const centerVertex = Vertex.fromPoint2D(actualCenter);
273
+ centerVertex.markAsMetaShape();
274
+ this.addShape(centerVertex);
212
275
  this.addShape(edge);
213
276
  if (this.sketch) {
214
277
  this.setCurrentPosition(endPt);
@@ -254,6 +317,9 @@ export class Arc extends GeometrySceneObject {
254
317
  const edge = Geometry.makeEdgeFromCurve(arc);
255
318
  this.setState('start', Vertex.fromPoint2D(startPoint));
256
319
  this.setState('end', Vertex.fromPoint2D(endPoint));
320
+ const centerVertex = Vertex.fromPoint2D(centerPoint);
321
+ centerVertex.markAsMetaShape();
322
+ this.addShape(centerVertex);
257
323
  const sign = cw ? -1 : 1;
258
324
  const tx = sign * (-Math.sin(endAngleRad));
259
325
  const ty = sign * Math.cos(endAngleRad);
@@ -286,6 +352,8 @@ export class Arc extends GeometrySceneObject {
286
352
  copy._bulgeRadius = this._bulgeRadius;
287
353
  copy._centerPoint = this._centerPoint;
288
354
  copy._centered = this._centered;
355
+ copy._clockwise = this._clockwise;
356
+ copy._major = this._major;
289
357
  return copy;
290
358
  }
291
359
  compareTo(other) {
@@ -301,6 +369,9 @@ export class Arc extends GeometrySceneObject {
301
369
  if (this._targetPlane && other._targetPlane && !this._targetPlane.compareTo(other._targetPlane)) {
302
370
  return false;
303
371
  }
372
+ if (this._clockwise !== other._clockwise) {
373
+ return false;
374
+ }
304
375
  if (this._endPoint && other._endPoint) {
305
376
  if (!this._endPoint.compareTo(other._endPoint)) {
306
377
  return false;
@@ -316,7 +387,7 @@ export class Arc extends GeometrySceneObject {
316
387
  if (this._centerPoint && other._centerPoint) {
317
388
  return this._centerPoint.compareTo(other._centerPoint);
318
389
  }
319
- return this._bulgeRadius === other._bulgeRadius;
390
+ return this._bulgeRadius === other._bulgeRadius && this._major === other._major;
320
391
  }
321
392
  if (!this._endPoint && !other._endPoint) {
322
393
  return this._arcRadius === other._arcRadius &&
@@ -340,6 +411,12 @@ export class Arc extends GeometrySceneObject {
340
411
  if (this._bulgeRadius !== 0) {
341
412
  base.radius = this._bulgeRadius;
342
413
  }
414
+ if (this._clockwise) {
415
+ base.clockwise = true;
416
+ }
417
+ if (this._major) {
418
+ base.major = true;
419
+ }
343
420
  return base;
344
421
  }
345
422
  return {