fluidcad 0.0.14 → 0.0.16

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 (88) hide show
  1. package/bin/fluidcad.js +2 -2
  2. package/lib/dist/common/scene-object.d.ts +7 -1
  3. package/lib/dist/common/scene-object.js +21 -3
  4. package/lib/dist/core/2d/arc.d.ts +14 -56
  5. package/lib/dist/core/2d/arc.js +8 -23
  6. package/lib/dist/core/2d/center.d.ts +9 -0
  7. package/lib/dist/core/2d/center.js +10 -0
  8. package/lib/dist/core/2d/index.d.ts +2 -0
  9. package/lib/dist/core/2d/index.js +2 -0
  10. package/lib/dist/core/2d/intersect.d.ts +17 -0
  11. package/lib/dist/core/2d/intersect.js +20 -0
  12. package/lib/dist/core/interfaces.d.ts +68 -2
  13. package/lib/dist/core/part.js +1 -1
  14. package/lib/dist/core/repeat.js +12 -4
  15. package/lib/dist/features/2d/aline.d.ts +2 -0
  16. package/lib/dist/features/2d/aline.js +4 -0
  17. package/lib/dist/features/2d/arc.d.ts +27 -14
  18. package/lib/dist/features/2d/arc.js +269 -38
  19. package/lib/dist/features/2d/intersect.d.ts +15 -0
  20. package/lib/dist/features/2d/intersect.js +83 -0
  21. package/lib/dist/features/2d/plane-center.d.ts +13 -0
  22. package/lib/dist/features/2d/plane-center.js +40 -0
  23. package/lib/dist/features/2d/projection.js +3 -4
  24. package/lib/dist/features/2d/rect.d.ts +2 -2
  25. package/lib/dist/features/2d/rect.js +3 -3
  26. package/lib/dist/features/2d/sketch.d.ts +2 -2
  27. package/lib/dist/features/2d/sketch.js +13 -1
  28. package/lib/dist/features/2d/slot.d.ts +2 -2
  29. package/lib/dist/features/2d/slot.js +3 -3
  30. package/lib/dist/features/axis.d.ts +2 -0
  31. package/lib/dist/features/axis.js +3 -0
  32. package/lib/dist/features/color.d.ts +1 -0
  33. package/lib/dist/features/color.js +4 -0
  34. package/lib/dist/features/extrude-base.d.ts +17 -0
  35. package/lib/dist/features/extrude-base.js +91 -0
  36. package/lib/dist/features/extrude-to-face.d.ts +1 -0
  37. package/lib/dist/features/extrude-to-face.js +30 -5
  38. package/lib/dist/features/extrude-two-distances.d.ts +1 -0
  39. package/lib/dist/features/extrude-two-distances.js +74 -16
  40. package/lib/dist/features/extrude.d.ts +1 -0
  41. package/lib/dist/features/extrude.js +92 -19
  42. package/lib/dist/features/mirror-shape2d.d.ts +1 -0
  43. package/lib/dist/features/mirror-shape2d.js +7 -0
  44. package/lib/dist/features/plane-renderable-base.d.ts +2 -1
  45. package/lib/dist/features/plane-renderable-base.js +1 -1
  46. package/lib/dist/features/plane.d.ts +1 -1
  47. package/lib/dist/features/remove.js +1 -1
  48. package/lib/dist/filters/face/face-filter.d.ts +10 -0
  49. package/lib/dist/filters/face/face-filter.js +39 -0
  50. package/lib/dist/filters/face/intersects-with.d.ts +18 -0
  51. package/lib/dist/filters/face/intersects-with.js +41 -0
  52. package/lib/dist/filters/filter-builder-base.d.ts +7 -0
  53. package/lib/dist/filters/filter-builder-base.js +16 -0
  54. package/lib/dist/filters/filter.js +6 -0
  55. package/lib/dist/filters/tangent-expander.d.ts +47 -0
  56. package/lib/dist/filters/tangent-expander.js +223 -0
  57. package/lib/dist/helpers/clone-transform.js +1 -0
  58. package/lib/dist/index.js +6 -1
  59. package/lib/dist/oc/boolean-ops.js +0 -2
  60. package/lib/dist/oc/face-query.d.ts +1 -0
  61. package/lib/dist/oc/face-query.js +15 -0
  62. package/lib/dist/oc/index.d.ts +1 -0
  63. package/lib/dist/oc/index.js +1 -0
  64. package/lib/dist/oc/section-ops.d.ts +6 -0
  65. package/lib/dist/oc/section-ops.js +26 -0
  66. package/lib/dist/oc/thin-face-maker.d.ts +40 -0
  67. package/lib/dist/oc/thin-face-maker.js +204 -0
  68. package/lib/dist/rendering/render.js +16 -0
  69. package/lib/dist/rendering/scene.js +5 -4
  70. package/lib/dist/tests/features/2d/arc.test.js +2 -2
  71. package/lib/dist/tests/features/2d/intersect.test.d.ts +1 -0
  72. package/lib/dist/tests/features/2d/intersect.test.js +22 -0
  73. package/lib/dist/tests/features/2d/rect.test.js +1 -1
  74. package/lib/dist/tests/features/extrude-two-distances.test.js +16 -0
  75. package/lib/dist/tests/features/loft.test.js +1 -1
  76. package/lib/dist/tests/features/repeat-circular.test.js +12 -0
  77. package/lib/dist/tests/features/repeat-linear.test.js +22 -0
  78. package/lib/dist/tests/features/select.test.js +104 -1
  79. package/lib/dist/tests/features/thin-extrude.test.d.ts +1 -0
  80. package/lib/dist/tests/features/thin-extrude.test.js +198 -0
  81. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  82. package/package.json +3 -3
  83. package/ui/dist/assets/{index-mLcpjEcV.js → index-CLQhpG6A.js} +3 -3
  84. package/ui/dist/index.html +1 -1
  85. package/lib/dist/features/2d/arc-three-points.d.ts +0 -19
  86. package/lib/dist/features/2d/arc-three-points.js +0 -75
  87. package/lib/dist/features/2d/arc-to-point.d.ts +0 -17
  88. package/lib/dist/features/2d/arc-to-point.js +0 -95
package/bin/fluidcad.js CHANGED
@@ -26,14 +26,14 @@ if (positionals[0] === 'init') {
26
26
  process.exit(1);
27
27
  }
28
28
 
29
- writeFileSync(initPath, `import { init } from 'fluidcad'\n\nexport default init()\n`);
29
+ writeFileSync(initPath, `import { init } from 'fluidcad'\n\nexport default await init()\n`);
30
30
 
31
31
  const testPath = resolve(cwd, 'test.fluid.js');
32
32
  if (!existsSync(testPath)) {
33
33
  writeFileSync(testPath, `import { extrude, fillet, rect, shell, sketch } from "fluidcad/core";
34
34
 
35
35
  sketch("xy", () => {
36
- rect(100, 50).radius(10).center();
36
+ rect(100, 50).radius(10).centered();
37
37
  });
38
38
 
39
39
  const e = extrude(30);
@@ -27,10 +27,12 @@ export declare abstract class SceneObject implements Comparable<SceneObject>, Se
27
27
  private _id;
28
28
  private _order;
29
29
  private _transform;
30
+ private _cloneSource;
30
31
  private _parent;
31
32
  private _alwaysVisible;
32
33
  private _name;
33
34
  private _guide;
35
+ private _reusable;
34
36
  private _sourceLocation;
35
37
  private _error;
36
38
  protected _fusionScope?: FusionScope;
@@ -60,6 +62,8 @@ export declare abstract class SceneObject implements Comparable<SceneObject>, Se
60
62
  clone(): SceneObject[];
61
63
  setTransform(matrix: Matrix4): void;
62
64
  getTransform(): Matrix4 | null;
65
+ setCloneSource(source: SceneObject): void;
66
+ getCloneSource(): SceneObject | null;
63
67
  getTransformMatrix(): Matrix4 | null;
64
68
  isExtrudable(): boolean;
65
69
  init(): void;
@@ -71,7 +75,7 @@ export declare abstract class SceneObject implements Comparable<SceneObject>, Se
71
75
  addShape(shape: Shape): void;
72
76
  addShapes(shapes: Shape[]): void;
73
77
  removeShape(shape: Shape, removedBy: SceneObject): void;
74
- removeShapes(removedBy: SceneObject): void;
78
+ removeShapes(removedBy: SceneObject, force?: boolean): void;
75
79
  getOwnShapes(filter?: ShapeFilter, scope?: Set<SceneObject>): Shape[];
76
80
  getChildShapes(filter?: ShapeFilter, type?: ShapeType): Shape[];
77
81
  getShapes(filter?: ShapeFilter, type?: ShapeType): Shape[];
@@ -89,6 +93,8 @@ export declare abstract class SceneObject implements Comparable<SceneObject>, Se
89
93
  getName(): string;
90
94
  name(value: string): this;
91
95
  guide(): this;
96
+ reusable(): this;
97
+ isReusable(): boolean;
92
98
  setSourceLocation(loc: SourceLocation): void;
93
99
  getSourceLocation(): SourceLocation | null;
94
100
  setError(message: string): void;
@@ -5,10 +5,12 @@ export class SceneObject {
5
5
  _id;
6
6
  _order = 0;
7
7
  _transform = null;
8
+ _cloneSource = null;
8
9
  _parent = null;
9
10
  _alwaysVisible = false;
10
11
  _name = null;
11
12
  _guide = false;
13
+ _reusable = false;
12
14
  _sourceLocation = null;
13
15
  _error = null;
14
16
  _fusionScope = 'all';
@@ -88,7 +90,7 @@ export class SceneObject {
88
90
  return this.getState('snapshot') || [];
89
91
  }
90
92
  compareTo(other) {
91
- const match = this._guide === other._guide;
93
+ const match = this._guide === other._guide && this._reusable === other._reusable;
92
94
  if (!match) {
93
95
  return false;
94
96
  }
@@ -161,6 +163,12 @@ export class SceneObject {
161
163
  getTransform() {
162
164
  return this._transform;
163
165
  }
166
+ setCloneSource(source) {
167
+ this._cloneSource = source;
168
+ }
169
+ getCloneSource() {
170
+ return this._cloneSource;
171
+ }
164
172
  getTransformMatrix() {
165
173
  return null;
166
174
  }
@@ -210,10 +218,13 @@ export class SceneObject {
210
218
  removedBy
211
219
  });
212
220
  }
213
- removeShapes(removedBy) {
221
+ removeShapes(removedBy, force) {
222
+ if (this._reusable && !force) {
223
+ return;
224
+ }
214
225
  if (this.isContainer()) {
215
226
  for (const child of this.children) {
216
- child.removeShapes(removedBy);
227
+ child.removeShapes(removedBy, force);
217
228
  }
218
229
  return;
219
230
  }
@@ -296,6 +307,13 @@ export class SceneObject {
296
307
  this._guide = true;
297
308
  return this;
298
309
  }
310
+ reusable() {
311
+ this._reusable = true;
312
+ return this;
313
+ }
314
+ isReusable() {
315
+ return this._reusable;
316
+ }
299
317
  setSourceLocation(loc) {
300
318
  this._sourceLocation = loc;
301
319
  }
@@ -1,84 +1,42 @@
1
1
  import { Point2DLike } from "../../math/point.js";
2
2
  import { PlaneLike } from "../../math/plane.js";
3
- import { IGeometry, ISceneObject } from "../interfaces.js";
3
+ import { IArcPoints, IArcAngles, ISceneObject } from "../interfaces.js";
4
4
  interface ArcFunction {
5
5
  /**
6
- * Draws an arc to an end point with an optional bulge radius.
6
+ * Draws an arc to an end point from the current position.
7
+ * Chain `.radius(r)` to set bulge radius, or `.center(point)` to specify the circle center.
7
8
  * @param endPoint - The end point of the arc
8
- * @param radius - The bulge radius (0 = auto)
9
9
  */
10
- (endPoint: Point2DLike, radius?: number): IGeometry;
10
+ (endPoint: Point2DLike): IArcPoints;
11
11
  /**
12
- * Draws an arc from a start point to an end point with an optional bulge radius.
12
+ * Draws an arc from a start point to an end point.
13
+ * By default, uses the current position as the arc center.
14
+ * Chain `.radius(r)` to use bulge radius instead, or `.center(point)` to specify an explicit center.
13
15
  * @param startPoint - The start point of the arc
14
16
  * @param endPoint - The end point of the arc
15
- * @param radius - The bulge radius (0 = auto)
16
17
  */
17
- (startPoint: Point2DLike, endPoint: Point2DLike, radius?: number): IGeometry;
18
+ (startPoint: Point2DLike, endPoint: Point2DLike): IArcPoints;
18
19
  /**
19
- * Draws an arc by radius and angle range.
20
+ * Draws an arc by radius and angle range at the current position.
21
+ * Chain `.centered()` to center the arc symmetrically around the start angle.
20
22
  * @param radius - The arc radius
21
23
  * @param startAngle - The start angle in degrees (defaults to 0)
22
24
  * @param endAngle - The end angle in degrees (defaults to 180)
23
- * @param centered - Whether to center the arc on the current position
24
25
  */
25
- (radius: number, startAngle?: number, endAngle?: number, centered?: boolean): IGeometry;
26
- /**
27
- * Draws an arc from a start point to an end point around a center point.
28
- * @param startPoint - The start point of the arc
29
- * @param endPoint - The end point of the arc
30
- * @param center - The center point of the arc
31
- */
32
- (startPoint: Point2DLike, endPoint: Point2DLike, center: Point2DLike): IGeometry;
26
+ (radius: number, startAngle?: number, endAngle?: number): IArcAngles;
33
27
  /**
34
28
  * Draws an arc to an end point on a specific plane.
35
29
  * @param endPoint - The end point of the arc
36
30
  * @param targetPlane - The plane to draw on
37
31
  */
38
- (endPoint: Point2DLike, targetPlane: PlaneLike | ISceneObject): IGeometry;
39
- /**
40
- * Draws an arc to an end point with a bulge radius on a specific plane.
41
- * @param endPoint - The end point of the arc
42
- * @param radius - The bulge radius
43
- * @param targetPlane - The plane to draw on
44
- */
45
- (endPoint: Point2DLike, radius: number, targetPlane: PlaneLike | ISceneObject): IGeometry;
32
+ (endPoint: Point2DLike, targetPlane: PlaneLike | ISceneObject): IArcPoints;
46
33
  /**
47
34
  * Draws an arc between two points on a specific plane.
48
35
  * @param startPoint - The start point of the arc
49
36
  * @param endPoint - The end point of the arc
50
37
  * @param targetPlane - The plane to draw on
51
38
  */
52
- (startPoint: Point2DLike, endPoint: Point2DLike, targetPlane: PlaneLike | ISceneObject): IGeometry;
53
- /**
54
- * Draws an arc between two points with a bulge radius on a specific plane.
55
- * @param startPoint - The start point of the arc
56
- * @param endPoint - The end point of the arc
57
- * @param radius - The bulge radius
58
- * @param targetPlane - The plane to draw on
59
- */
60
- (startPoint: Point2DLike, endPoint: Point2DLike, radius: number, targetPlane: PlaneLike | ISceneObject): IGeometry;
61
- /**
62
- * Draws an arc from a start point to an end point around a center point on a specific plane.
63
- * @param startPoint - The start point of the arc
64
- * @param endPoint - The end point of the arc
65
- * @param center - The center point of the arc
66
- * @param targetPlane - The plane to draw on
67
- */
68
- (startPoint: Point2DLike, endPoint: Point2DLike, center: Point2DLike, targetPlane: PlaneLike | ISceneObject): IGeometry;
69
- /**
70
- * Draws an arc by radius on a specific plane.
71
- * @param radius - The arc radius
72
- * @param targetPlane - The plane to draw on
73
- */
74
- (radius: number, targetPlane: PlaneLike | ISceneObject): IGeometry;
75
- /**
76
- * Draws an arc by radius and start angle on a specific plane.
77
- * @param radius - The arc radius
78
- * @param startAngle - The start angle in degrees
79
- * @param targetPlane - The plane to draw on
80
- */
81
- (radius: number, startAngle: number, targetPlane: PlaneLike | ISceneObject): IGeometry;
39
+ (startPoint: Point2DLike, endPoint: Point2DLike, targetPlane: PlaneLike | ISceneObject): IArcPoints;
82
40
  /**
83
41
  * Draws an arc by radius and angle range on a specific plane.
84
42
  * @param radius - The arc radius
@@ -86,7 +44,7 @@ interface ArcFunction {
86
44
  * @param endAngle - The end angle in degrees
87
45
  * @param targetPlane - The plane to draw on
88
46
  */
89
- (radius: number, startAngle: number, endAngle: number, targetPlane: PlaneLike | ISceneObject): IGeometry;
47
+ (radius: number, startAngle: number, endAngle: number, targetPlane: PlaneLike | ISceneObject): IArcAngles;
90
48
  }
91
49
  declare const _default: ArcFunction;
92
50
  export default _default;
@@ -1,8 +1,5 @@
1
1
  import { isPoint2DLike } from "../../math/point.js";
2
- import { ArcFromTwoAngles } from "../../features/2d/arc.js";
3
- import { ArcToPoint } from "../../features/2d/arc-to-point.js";
4
- import { ArcThreePoints } from "../../features/2d/arc-three-points.js";
5
- import { Move } from "../../features/2d/move.js";
2
+ import { Arc } from "../../features/2d/arc.js";
6
3
  import { normalizePoint2D } from "../../helpers/normalize.js";
7
4
  import { registerBuilder } from "../../index.js";
8
5
  import { isPlaneLike } from "../../math/plane.js";
@@ -20,38 +17,26 @@ function build(context) {
20
17
  argCount--;
21
18
  }
22
19
  }
23
- // (startPoint, endPoint, center) — three Point2DLike args
24
- if (argCount >= 3 && isPoint2DLike(arguments[0]) && isPoint2DLike(arguments[1]) && isPoint2DLike(arguments[2])) {
25
- const start = normalizePoint2D(arguments[0]);
26
- const end = normalizePoint2D(arguments[1]);
27
- const center = normalizePoint2D(arguments[2]);
28
- const arcObj = new ArcThreePoints(start, end, center, planeObj);
29
- context.addSceneObjects([new Move(start), arcObj]);
30
- return arcObj;
31
- }
32
- // (startPoint, endPoint, radius?) — two Point2DLike args
20
+ // (startPoint, endPoint) — two Point2DLike args, default center = current position
33
21
  if (argCount >= 2 && isPoint2DLike(arguments[0]) && isPoint2DLike(arguments[1])) {
34
22
  const start = normalizePoint2D(arguments[0]);
35
23
  const end = normalizePoint2D(arguments[1]);
36
- const radius = argCount >= 3 ? arguments[2] : 0;
37
- const arcObj = new ArcToPoint(end, radius, planeObj);
38
- context.addSceneObjects([new Move(start), arcObj]);
24
+ const arcObj = Arc.twoPoints(start, end, planeObj);
25
+ context.addSceneObject(arcObj);
39
26
  return arcObj;
40
27
  }
41
- // (endPoint, radius?) — single Point2DLike arg
28
+ // (endPoint) — single Point2DLike arg
42
29
  if (isPoint2DLike(arguments[0])) {
43
30
  const end = normalizePoint2D(arguments[0]);
44
- const radius = argCount >= 2 ? arguments[1] : 0;
45
- const arcObj = new ArcToPoint(end, radius, planeObj);
31
+ const arcObj = Arc.toPoint(end, planeObj);
46
32
  context.addSceneObject(arcObj);
47
33
  return arcObj;
48
34
  }
49
- // (radius, startAngle, endAngle?, centered?) — all numeric args
35
+ // (radius, startAngle?, endAngle?) — all numeric args
50
36
  const radius = arguments[0] || 100;
51
37
  const startAngle = arguments[1] || 0;
52
38
  const endAngle = argCount >= 3 ? arguments[2] : 180;
53
- const centered = argCount >= 4 ? arguments[3] : false;
54
- const arcObj = new ArcFromTwoAngles(radius, startAngle, endAngle, centered, planeObj);
39
+ const arcObj = Arc.fromAngles(radius, startAngle, endAngle, planeObj);
55
40
  context.addSceneObject(arcObj);
56
41
  return arcObj;
57
42
  };
@@ -0,0 +1,9 @@
1
+ import { IGeometry } from "../interfaces.js";
2
+ interface CenterFunction {
3
+ /**
4
+ * Move the current position to the center of the sketch plane.
5
+ */
6
+ (): IGeometry;
7
+ }
8
+ declare const _default: CenterFunction;
9
+ export default _default;
@@ -0,0 +1,10 @@
1
+ import { PlaneCenter } from "../../features/2d/plane-center.js";
2
+ import { registerBuilder } from "../../index.js";
3
+ function build(context) {
4
+ return function center() {
5
+ const planeCenter = new PlaneCenter();
6
+ context.addSceneObject(planeCenter);
7
+ return planeCenter;
8
+ };
9
+ }
10
+ export default registerBuilder(build);
@@ -18,4 +18,6 @@ export { default as connect } from './connect.js';
18
18
  export { default as polygon } from './polygon.js';
19
19
  export { default as offset } from './offset.js';
20
20
  export { default as project } from './project.js';
21
+ export { default as intersect } from './intersect.js';
21
22
  export { default as bezier } from './bezier.js';
23
+ export { default as center } from './center.js';
@@ -18,4 +18,6 @@ export { default as connect } from './connect.js';
18
18
  export { default as polygon } from './polygon.js';
19
19
  export { default as offset } from './offset.js';
20
20
  export { default as project } from './project.js';
21
+ export { default as intersect } from './intersect.js';
21
22
  export { default as bezier } from './bezier.js';
23
+ export { default as center } from './center.js';
@@ -0,0 +1,17 @@
1
+ import { PlaneLike } from "../../math/plane.js";
2
+ import { IExtrudableGeometry, ISceneObject } from "../interfaces.js";
3
+ interface IntersectFunction {
4
+ /**
5
+ * Intersects 3D objects with the current sketch plane, producing cross-section edges.
6
+ * @param sourceObjects - The 3D objects to intersect
7
+ */
8
+ (...sourceObjects: ISceneObject[]): IExtrudableGeometry;
9
+ /**
10
+ * Intersects 3D objects with a target plane, producing cross-section edges.
11
+ * @param sourceObjects - The 3D objects to intersect
12
+ * @param targetPlane - The plane to intersect with
13
+ */
14
+ (sourceObjects: ISceneObject[], targetPlane: PlaneLike | ISceneObject): IExtrudableGeometry;
15
+ }
16
+ declare const _default: IntersectFunction;
17
+ export default _default;
@@ -0,0 +1,20 @@
1
+ import { Intersect } from "../../features/2d/intersect.js";
2
+ import { resolvePlane } from "../../helpers/resolve.js";
3
+ import { registerBuilder } from "../../index.js";
4
+ function build(context) {
5
+ return function intersect(...args) {
6
+ if (Array.isArray(args[0])) {
7
+ const sourceObjects = args[0];
8
+ context.addSceneObjects(sourceObjects);
9
+ const planeObj = resolvePlane(args[1], context);
10
+ const result = new Intersect(sourceObjects, planeObj);
11
+ context.addSceneObject(result);
12
+ return result;
13
+ }
14
+ const result = new Intersect(args);
15
+ context.addSceneObjects(args);
16
+ context.addSceneObject(result);
17
+ return result;
18
+ };
19
+ }
20
+ export default registerBuilder(build);
@@ -13,6 +13,13 @@ export interface ISceneObject {
13
13
  * final geometry output unless explicitly included.
14
14
  */
15
15
  guide(): this;
16
+ /**
17
+ * Marks this object as reusable. Reusable objects retain their shapes when
18
+ * consumed by features (e.g., extrude, revolve), allowing multiple features
19
+ * to reference the same source geometry. Use `remove(obj)` to force-remove
20
+ * shapes from a reusable object.
21
+ */
22
+ reusable(): this;
16
23
  }
17
24
  export interface IFuseable extends ISceneObject {
18
25
  /**
@@ -58,6 +65,26 @@ export interface IGeometry extends ISceneObject {
58
65
  }
59
66
  export interface IExtrudableGeometry extends IGeometry {
60
67
  }
68
+ export interface IArcPoints extends IExtrudableGeometry {
69
+ /**
70
+ * Sets the bulge radius for point-to-point arcs.
71
+ * Positive = CCW, negative = CW.
72
+ * @param value - The bulge radius.
73
+ */
74
+ radius(value: number): this;
75
+ /**
76
+ * Specifies the circle center point for the arc.
77
+ * Mutually exclusive with `.radius()`.
78
+ * @param value - The center point of the arc's circle.
79
+ */
80
+ center(value: Point2DLike): this;
81
+ }
82
+ export interface IArcAngles extends IExtrudableGeometry {
83
+ /**
84
+ * Centers the arc symmetrically around the start angle.
85
+ */
86
+ centered(): this;
87
+ }
61
88
  export interface IRect extends IExtrudableGeometry {
62
89
  /**
63
90
  * Sets corner radii for a rounded rectangle. Accepts 1–4 values
@@ -71,7 +98,7 @@ export interface IRect extends IExtrudableGeometry {
71
98
  * @param value - `true` centers on both axes, `'horizontal'` or `'vertical'` centers
72
99
  * on one axis, `false` (default) keeps the current point as the origin corner.
73
100
  */
74
- center(value?: boolean | 'horizontal' | 'vertical'): this;
101
+ centered(value?: boolean | 'horizontal' | 'vertical'): this;
75
102
  /**
76
103
  * Returns the top straight edge of the rectangle.
77
104
  */
@@ -127,7 +154,7 @@ export interface ISlot extends IExtrudableGeometry {
127
154
  * When `true`, the slot is offset backward by half its length.
128
155
  * @param value - `true` to center, `false` (default) to start from the current position.
129
156
  */
130
- center(value?: boolean): this;
157
+ centered(value?: boolean): this;
131
158
  /**
132
159
  * Sets the rotation angle of the slot's primary axis.
133
160
  * @param angle - Rotation in degrees.
@@ -223,6 +250,17 @@ export interface IExtrude extends IFuseable {
223
250
  * @param args - Numeric indices or {@link EdgeFilterBuilder} instances to filter the selection.
224
251
  */
225
252
  internalEdges(...args: (number | EdgeFilterBuilder)[]): ISceneObject;
253
+ /**
254
+ * Selects the cap faces at the open ends of a thin-walled extrusion from an open profile.
255
+ * These are the small faces connecting the inner and outer walls at the profile endpoints.
256
+ * @param args - Numeric indices or {@link FaceFilterBuilder} instances to filter the selection.
257
+ */
258
+ capFaces(...args: (number | FaceFilterBuilder)[]): ISceneObject;
259
+ /**
260
+ * Selects edges on the cap faces of a thin-walled extrusion from an open profile.
261
+ * @param args - Numeric indices or {@link EdgeFilterBuilder} instances to filter the selection.
262
+ */
263
+ capEdges(...args: (number | EdgeFilterBuilder)[]): ISceneObject;
226
264
  /**
227
265
  * Applies a draft (taper) angle to the extrusion walls.
228
266
  * @param value - A single angle for uniform draft, or a `[start, end]` tuple for asymmetric draft.
@@ -244,6 +282,20 @@ export interface IExtrude extends IFuseable {
244
282
  * @param points - 2D points in the sketch plane identifying regions to extrude.
245
283
  */
246
284
  pick(...points: Point2DLike[]): this;
285
+ /**
286
+ * Enables thin extrude mode — offsets the profile edges to create a thin-walled solid
287
+ * instead of extruding filled faces. Positive values offset outward, negative values offset inward.
288
+ * @param offset - The wall offset distance. Positive = outward, negative = inward.
289
+ */
290
+ thin(offset: number): this;
291
+ /**
292
+ * Enables thin extrude mode with two offset directions.
293
+ * The two offsets must go in opposite directions. If both have the same sign,
294
+ * the second offset is automatically flipped.
295
+ * @param offset1 - The first wall offset distance. Positive = outward, negative = inward.
296
+ * @param offset2 - The second wall offset distance, in the opposite direction of offset1.
297
+ */
298
+ thin(offset1: number, offset2: number): this;
247
299
  }
248
300
  export interface ICut extends ISceneObject {
249
301
  /**
@@ -290,6 +342,20 @@ export interface ICut extends ISceneObject {
290
342
  * @param points - 2D points in the sketch plane identifying regions to cut.
291
343
  */
292
344
  pick(...points: Point2DLike[]): this;
345
+ /**
346
+ * Enables thin cut mode — offsets the profile edges to cut a thin-walled shape
347
+ * instead of cutting filled faces. Positive values offset outward, negative values offset inward.
348
+ * @param offset - The wall offset distance. Positive = outward, negative = inward.
349
+ */
350
+ thin(offset: number): this;
351
+ /**
352
+ * Enables thin cut mode with two offset directions.
353
+ * The two offsets must go in opposite directions. If both have the same sign,
354
+ * the second offset is automatically flipped.
355
+ * @param offset1 - The first wall offset distance. Positive = outward, negative = inward.
356
+ * @param offset2 - The second wall offset distance, in the opposite direction of offset1.
357
+ */
358
+ thin(offset1: number, offset2: number): this;
293
359
  }
294
360
  export interface IRevolve extends IFuseable {
295
361
  /**
@@ -11,7 +11,7 @@ function part(name, callback) {
11
11
  const currentFile = getCurrentFile();
12
12
  const isDirectEdit = sourceLocation
13
13
  && currentFile
14
- && sourceLocation.filePath.replace('virtual:live-render:', '') === currentFile;
14
+ && sourceLocation.filePath === currentFile;
15
15
  if (isDirectEdit) {
16
16
  const scene = getCurrentScene();
17
17
  if (scene) {
@@ -73,9 +73,16 @@ function build(context) {
73
73
  indexCombinations.push(...newCombinations);
74
74
  }
75
75
  for (const indices of indexCombinations) {
76
- // Skip the origin instance (all zeros)
77
- if (indices.every(i => i === 0)) {
78
- continue;
76
+ // Skip the origin instance
77
+ if (options.centered) {
78
+ if (indices.every((idx, a) => idx === Math.floor(axisOffsets[a].count / 2))) {
79
+ continue;
80
+ }
81
+ }
82
+ else {
83
+ if (indices.every(i => i === 0)) {
84
+ continue;
85
+ }
79
86
  }
80
87
  // Skip if in the skip list
81
88
  if (options.skip?.some(s => s.length === indices.length && s.every((v, i) => v === indices[i]))) {
@@ -110,7 +117,8 @@ function build(context) {
110
117
  offset = circularOptions.offset;
111
118
  }
112
119
  else {
113
- offset = circularOptions.angle / (count - 1);
120
+ const angle = circularOptions.angle;
121
+ offset = angle % 360 === 0 ? angle / count : angle / (count - 1);
114
122
  }
115
123
  const startOffset = centered ? -(count * offset) / 2 : 0;
116
124
  const transformedObjects = [];
@@ -1,3 +1,4 @@
1
+ import { SceneObject } from "../../common/scene-object.js";
1
2
  import { PlaneObjectBase } from "../plane-renderable-base.js";
2
3
  import { GeometrySceneObject } from "./geometry.js";
3
4
  export declare class AngledLine extends GeometrySceneObject {
@@ -7,6 +8,7 @@ export declare class AngledLine extends GeometrySceneObject {
7
8
  private targetPlane;
8
9
  constructor(length: number, angle: number, centered?: boolean, targetPlane?: PlaneObjectBase);
9
10
  build(): void;
11
+ createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
10
12
  compareTo(other: AngledLine): boolean;
11
13
  getType(): string;
12
14
  getUniqueType(): string;
@@ -47,6 +47,10 @@ export class AngledLine extends GeometrySceneObject {
47
47
  if (this.targetPlane)
48
48
  this.targetPlane.removeShapes(this);
49
49
  }
50
+ createCopy(remap) {
51
+ const targetPlane = this.targetPlane ? (remap.get(this.targetPlane) || this.targetPlane) : null;
52
+ return new AngledLine(this.length, this.angle, this.centered, targetPlane);
53
+ }
50
54
  compareTo(other) {
51
55
  if (!(other instanceof AngledLine)) {
52
56
  return false;
@@ -1,19 +1,32 @@
1
+ import { Point2DLike } from "../../math/point.js";
1
2
  import { PlaneObjectBase } from "../plane-renderable-base.js";
2
3
  import { GeometrySceneObject } from "./geometry.js";
3
- export declare class ArcFromTwoAngles extends GeometrySceneObject {
4
- radius: number;
5
- startAngle: number;
6
- endAngle: number;
7
- centered: boolean;
8
- private targetPlane;
9
- constructor(radius: number, startAngle: number, endAngle: number, centered?: boolean, targetPlane?: PlaneObjectBase);
4
+ import { LazyVertex } from "../lazy-vertex.js";
5
+ import { IArcPoints, IArcAngles } from "../../core/interfaces.js";
6
+ export declare class Arc extends GeometrySceneObject implements IArcPoints, IArcAngles {
7
+ private _startPoint;
8
+ private _endPoint;
9
+ private _arcRadius;
10
+ private _startAngle;
11
+ private _endAngle;
12
+ private _bulgeRadius;
13
+ private _centerPoint;
14
+ private _centered;
15
+ private _targetPlane;
16
+ constructor(targetPlane?: PlaneObjectBase | null);
17
+ static toPoint(endPoint: LazyVertex, targetPlane?: PlaneObjectBase | null): Arc;
18
+ static twoPoints(startPoint: LazyVertex, endPoint: LazyVertex, targetPlane?: PlaneObjectBase | null): Arc;
19
+ static fromAngles(arcRadius: number, startAngle: number, endAngle: number, targetPlane?: PlaneObjectBase | null): Arc;
20
+ radius(value: number): this;
21
+ center(value: Point2DLike): this;
22
+ centered(): this;
10
23
  build(): void;
24
+ private buildTwoPointsCenter;
25
+ private buildTwoPointsBulge;
26
+ private buildToPoint;
27
+ private buildWithCenter;
28
+ private buildFromAngles;
11
29
  getType(): string;
12
- compareTo(other: ArcFromTwoAngles): boolean;
13
- serialize(): {
14
- radius: number;
15
- startAngle: number;
16
- endAngle: number;
17
- centered: boolean;
18
- };
30
+ compareTo(other: Arc): boolean;
31
+ serialize(): Record<string, unknown>;
19
32
  }