fluidcad 0.0.28 → 0.0.30

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 (145) hide show
  1. package/lib/dist/common/profiler.d.ts +12 -0
  2. package/lib/dist/common/profiler.js +35 -0
  3. package/lib/dist/common/scene-object.d.ts +3 -0
  4. package/lib/dist/common/scene-object.js +3 -0
  5. package/lib/dist/common/shape-history-tracker.d.ts +9 -1
  6. package/lib/dist/common/shape-history-tracker.js +37 -23
  7. package/lib/dist/core/2d/aline.d.ts +13 -13
  8. package/lib/dist/core/2d/aline.js +20 -11
  9. package/lib/dist/core/2d/arc.d.ts +6 -6
  10. package/lib/dist/core/2d/arc.js +19 -15
  11. package/lib/dist/core/2d/back.d.ts +12 -0
  12. package/lib/dist/core/2d/back.js +11 -0
  13. package/lib/dist/core/2d/circle.d.ts +2 -2
  14. package/lib/dist/core/2d/circle.js +14 -10
  15. package/lib/dist/core/2d/ellipse.d.ts +35 -0
  16. package/lib/dist/core/2d/ellipse.js +65 -0
  17. package/lib/dist/core/2d/hline.d.ts +20 -13
  18. package/lib/dist/core/2d/hline.js +33 -15
  19. package/lib/dist/core/2d/index.d.ts +2 -0
  20. package/lib/dist/core/2d/index.js +2 -0
  21. package/lib/dist/core/2d/intersect.d.ts +2 -2
  22. package/lib/dist/core/2d/intersect.js +7 -3
  23. package/lib/dist/core/2d/line.d.ts +2 -2
  24. package/lib/dist/core/2d/line.js +14 -10
  25. package/lib/dist/core/2d/offset.d.ts +4 -4
  26. package/lib/dist/core/2d/offset.js +9 -5
  27. package/lib/dist/core/2d/polygon.d.ts +4 -4
  28. package/lib/dist/core/2d/polygon.js +24 -20
  29. package/lib/dist/core/2d/project.d.ts +2 -2
  30. package/lib/dist/core/2d/project.js +7 -3
  31. package/lib/dist/core/2d/rect.d.ts +2 -2
  32. package/lib/dist/core/2d/rect.js +22 -21
  33. package/lib/dist/core/2d/slot.d.ts +6 -6
  34. package/lib/dist/core/2d/slot.js +29 -32
  35. package/lib/dist/core/2d/vline.d.ts +20 -13
  36. package/lib/dist/core/2d/vline.js +29 -15
  37. package/lib/dist/core/interfaces.d.ts +62 -0
  38. package/lib/dist/core/mirror.d.ts +7 -7
  39. package/lib/dist/core/mirror.js +17 -11
  40. package/lib/dist/core/part.d.ts +3 -1
  41. package/lib/dist/core/part.js +1 -1
  42. package/lib/dist/core/rotate.d.ts +5 -5
  43. package/lib/dist/core/rotate.js +4 -1
  44. package/lib/dist/core/sketch.d.ts +3 -1
  45. package/lib/dist/core/sketch.js +1 -1
  46. package/lib/dist/core/translate.d.ts +9 -9
  47. package/lib/dist/features/2d/aline.d.ts +8 -5
  48. package/lib/dist/features/2d/aline.js +70 -18
  49. package/lib/dist/features/2d/back.d.ts +14 -0
  50. package/lib/dist/features/2d/back.js +35 -0
  51. package/lib/dist/features/2d/ellipse.d.ts +23 -0
  52. package/lib/dist/features/2d/ellipse.js +75 -0
  53. package/lib/dist/features/2d/hline.d.ts +9 -4
  54. package/lib/dist/features/2d/hline.js +65 -14
  55. package/lib/dist/features/2d/offset.d.ts +3 -0
  56. package/lib/dist/features/2d/offset.js +27 -3
  57. package/lib/dist/features/2d/sketch.d.ts +1 -0
  58. package/lib/dist/features/2d/sketch.js +15 -0
  59. package/lib/dist/features/2d/vline.d.ts +9 -4
  60. package/lib/dist/features/2d/vline.js +67 -15
  61. package/lib/dist/features/common.js +2 -1
  62. package/lib/dist/features/extrude-base.d.ts +19 -1
  63. package/lib/dist/features/extrude-base.js +75 -12
  64. package/lib/dist/features/extrude-two-distances.js +32 -27
  65. package/lib/dist/features/extrude.d.ts +39 -0
  66. package/lib/dist/features/extrude.js +196 -156
  67. package/lib/dist/features/fuse.js +2 -1
  68. package/lib/dist/features/lazy-scene-object.d.ts +1 -0
  69. package/lib/dist/features/lazy-scene-object.js +3 -0
  70. package/lib/dist/features/lazy-vertex.d.ts +1 -0
  71. package/lib/dist/features/lazy-vertex.js +3 -0
  72. package/lib/dist/features/loft.js +11 -8
  73. package/lib/dist/features/mirror-shape.d.ts +2 -0
  74. package/lib/dist/features/mirror-shape.js +16 -0
  75. package/lib/dist/features/mirror-shape2d.d.ts +2 -0
  76. package/lib/dist/features/mirror-shape2d.js +22 -1
  77. package/lib/dist/features/revolve.d.ts +31 -0
  78. package/lib/dist/features/revolve.js +178 -95
  79. package/lib/dist/features/rotate.d.ts +2 -0
  80. package/lib/dist/features/rotate.js +16 -0
  81. package/lib/dist/features/rotate2d.d.ts +2 -0
  82. package/lib/dist/features/rotate2d.js +16 -0
  83. package/lib/dist/features/select.js +2 -1
  84. package/lib/dist/features/simple-extruder.d.ts +3 -1
  85. package/lib/dist/features/simple-extruder.js +13 -9
  86. package/lib/dist/features/subtract.d.ts +2 -2
  87. package/lib/dist/features/subtract.js +3 -3
  88. package/lib/dist/features/sweep.d.ts +14 -0
  89. package/lib/dist/features/sweep.js +93 -80
  90. package/lib/dist/features/translate.d.ts +2 -0
  91. package/lib/dist/features/translate.js +23 -2
  92. package/lib/dist/filters/edge/edge-filter.d.ts +6 -0
  93. package/lib/dist/filters/edge/edge-filter.js +11 -0
  94. package/lib/dist/filters/face/face-filter.d.ts +6 -0
  95. package/lib/dist/filters/face/face-filter.js +11 -0
  96. package/lib/dist/filters/filter-base.d.ts +7 -1
  97. package/lib/dist/filters/filter-base.js +8 -0
  98. package/lib/dist/filters/filter-builder-base.js +11 -0
  99. package/lib/dist/filters/from-object.d.ts +14 -0
  100. package/lib/dist/filters/from-object.js +40 -0
  101. package/lib/dist/helpers/scene-helpers.d.ts +2 -0
  102. package/lib/dist/helpers/scene-helpers.js +68 -48
  103. package/lib/dist/oc/color-transfer.js +6 -0
  104. package/lib/dist/oc/edge-ops.d.ts +1 -0
  105. package/lib/dist/oc/edge-ops.js +17 -0
  106. package/lib/dist/oc/extrude-ops.d.ts +18 -1
  107. package/lib/dist/oc/extrude-ops.js +34 -1
  108. package/lib/dist/oc/geometry.d.ts +1 -0
  109. package/lib/dist/oc/geometry.js +27 -0
  110. package/lib/dist/oc/mesh.js +11 -9
  111. package/lib/dist/oc/ray-intersect.d.ts +16 -0
  112. package/lib/dist/oc/ray-intersect.js +91 -0
  113. package/lib/dist/oc/thin-face-maker.d.ts +0 -1
  114. package/lib/dist/oc/thin-face-maker.js +2 -20
  115. package/lib/dist/rendering/render.d.ts +2 -1
  116. package/lib/dist/rendering/render.js +72 -33
  117. package/lib/dist/rendering/scene.d.ts +4 -0
  118. package/lib/dist/tests/features/2d/back.test.d.ts +1 -0
  119. package/lib/dist/tests/features/2d/back.test.js +60 -0
  120. package/lib/dist/tests/features/2d/circle.test.js +1 -1
  121. package/lib/dist/tests/features/2d/constrained.test.js +4 -4
  122. package/lib/dist/tests/features/2d/ellipse.test.d.ts +1 -0
  123. package/lib/dist/tests/features/2d/ellipse.test.js +100 -0
  124. package/lib/dist/tests/features/2d/line.test.js +89 -3
  125. package/lib/dist/tests/features/2d/offset.test.js +1 -1
  126. package/lib/dist/tests/features/2d/polygon.test.js +2 -2
  127. package/lib/dist/tests/features/2d/rect.test.js +1 -1
  128. package/lib/dist/tests/features/2d/slot-from-edge.test.js +1 -1
  129. package/lib/dist/tests/features/2d/slot.test.js +1 -1
  130. package/lib/dist/tests/features/mirror.test.js +58 -0
  131. package/lib/dist/tests/features/mirror2d.test.js +63 -0
  132. package/lib/dist/tests/features/rotate.test.js +62 -0
  133. package/lib/dist/tests/features/rotate2d.test.js +47 -0
  134. package/lib/dist/tests/features/thin-revolve.test.js +37 -1
  135. package/lib/dist/tests/features/translate.test.js +63 -0
  136. package/lib/dist/tests/perf/record-fusion-history.bench.test.d.ts +1 -0
  137. package/lib/dist/tests/perf/record-fusion-history.bench.test.js +77 -0
  138. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  139. package/package.json +1 -1
  140. package/server/dist/index.js +77 -45
  141. package/server/dist/ws-protocol.d.ts +11 -0
  142. package/ui/dist/assets/{index-BrW_x4uc.js → index-6Ep4GPxf.js} +131 -77
  143. package/ui/dist/assets/index-DRKfe6N9.css +2 -0
  144. package/ui/dist/index.html +2 -2
  145. package/ui/dist/assets/index-gPoNOiIs.css +0 -2
@@ -9,27 +9,41 @@ import { resolvePlane } from "../../helpers/resolve.js";
9
9
  function build(context) {
10
10
  return function line() {
11
11
  let planeObj = null;
12
- let argCount = arguments.length;
13
- // Detect plane as last argument
14
- if (argCount > 0) {
15
- const lastArg = arguments[argCount - 1];
16
- if (isPlaneLike(lastArg) || (lastArg instanceof SceneObject && !isPoint2DLike(lastArg))) {
17
- planeObj = resolvePlane(lastArg, context);
18
- argCount--;
12
+ let argOffset = 0;
13
+ const inSketch = context.getActiveSketch() !== null;
14
+ if (arguments.length > 0) {
15
+ const firstArg = arguments[0];
16
+ if (isPlaneLike(firstArg)) {
17
+ if (inSketch) {
18
+ throw new Error("vLine(plane, ...) cannot be used inside a sketch. Use vLine(...) instead.");
19
+ }
20
+ planeObj = resolvePlane(firstArg, context);
21
+ argOffset = 1;
19
22
  }
23
+ else if (!inSketch && firstArg instanceof SceneObject && !isPoint2DLike(firstArg)) {
24
+ planeObj = resolvePlane(firstArg, context);
25
+ argOffset = 1;
26
+ }
27
+ }
28
+ if (argOffset === 0 && inSketch && arguments[0] instanceof SceneObject && !isPoint2DLike(arguments[0])) {
29
+ // vLine(target)
30
+ const vline = new VerticalLine(arguments[0], null);
31
+ context.addSceneObject(vline);
32
+ return vline;
20
33
  }
21
- if (typeof arguments[0] !== 'number') {
22
- // vline(start, distance) or vline(start, distance, centered)
34
+ if (argOffset === 0 && typeof arguments[0] !== 'number') {
35
+ // vLine(start, distance) or vLine(start, target)
23
36
  const start = normalizePoint2D(arguments[0]);
24
- const distance = arguments[1];
25
- const centered = argCount >= 3 ? arguments[2] : false;
26
- const vline = new VerticalLine(distance, centered, planeObj);
37
+ const second = arguments[1];
38
+ const distanceOrTarget = second instanceof SceneObject
39
+ ? second
40
+ : second;
41
+ const vline = new VerticalLine(distanceOrTarget, planeObj);
27
42
  context.addSceneObjects([new Move(start), vline]);
28
43
  return vline;
29
44
  }
30
- const distance = arguments[0];
31
- const centered = argCount >= 2 ? arguments[1] : false;
32
- const vline = new VerticalLine(distance, centered, planeObj);
45
+ const distance = arguments[argOffset];
46
+ const vline = new VerticalLine(distance, planeObj);
33
47
  context.addSceneObject(vline);
34
48
  return vline;
35
49
  };
@@ -123,6 +123,14 @@ export interface IGeometry extends ISceneObject {
123
123
  }
124
124
  export interface IExtrudableGeometry extends IGeometry {
125
125
  }
126
+ export interface IOffset extends IExtrudableGeometry {
127
+ /**
128
+ * Closes an open offset by joining it back to the source wire with
129
+ * straight cap edges at each endpoint. Has no effect when the offset
130
+ * is already closed. Cannot be combined with `removeOriginal=true`.
131
+ */
132
+ close(): this;
133
+ }
126
134
  export interface IArcPoints extends IExtrudableGeometry {
127
135
  /**
128
136
  * Sets the bulge radius for point-to-point arcs.
@@ -219,6 +227,33 @@ export interface ISlot extends IExtrudableGeometry {
219
227
  */
220
228
  rotate(angle: number): this;
221
229
  }
230
+ export interface IALine extends IGeometry {
231
+ /**
232
+ * Controls whether the line is centered on the current position.
233
+ * When `true`, the line is offset backward by half its length so that the
234
+ * current position falls at its midpoint.
235
+ * @param value - `true` to center, `false` (default) to start from the current position.
236
+ */
237
+ centered(value?: boolean): this;
238
+ }
239
+ export interface IHLine extends IGeometry {
240
+ /**
241
+ * Controls whether the line is centered on the current position.
242
+ * When `true`, the line is offset backward by half its length so that the
243
+ * current position falls at its midpoint.
244
+ * @param value - `true` to center, `false` (default) to start from the current position.
245
+ */
246
+ centered(value?: boolean): this;
247
+ }
248
+ export interface IVLine extends IGeometry {
249
+ /**
250
+ * Controls whether the line is centered on the current position.
251
+ * When `true`, the line is offset backward by half its length so that the
252
+ * current position falls at its midpoint.
253
+ * @param value - `true` to center, `false` (default) to start from the current position.
254
+ */
255
+ centered(value?: boolean): this;
256
+ }
222
257
  export interface IPolygon extends IExtrudableGeometry {
223
258
  /**
224
259
  * Returns a specific edge of the polygon by index.
@@ -621,6 +656,33 @@ export interface ISweep extends IBooleanOperation {
621
656
  */
622
657
  capEdges(...args: (number | EdgeFilterBuilder)[]): ISceneObject;
623
658
  }
659
+ export interface IMirror extends ISceneObject {
660
+ /**
661
+ * Excludes the given objects from the mirror operation. Useful when
662
+ * mirroring "everything" but a few specific objects should be skipped,
663
+ * or when narrowing an explicit target list.
664
+ * @param objects - The objects to exclude from mirroring.
665
+ */
666
+ exclude(...objects: ISceneObject[]): this;
667
+ }
668
+ export interface ITranslate extends ISceneObject {
669
+ /**
670
+ * Excludes the given objects from the translate operation. Useful when
671
+ * translating "everything" but a few specific objects should be skipped,
672
+ * or when narrowing an explicit target list.
673
+ * @param objects - The objects to exclude from translating.
674
+ */
675
+ exclude(...objects: ISceneObject[]): this;
676
+ }
677
+ export interface IRotate extends ISceneObject {
678
+ /**
679
+ * Excludes the given objects from the rotate operation. Useful when
680
+ * rotating "everything" but a few specific objects should be skipped,
681
+ * or when narrowing an explicit target list.
682
+ * @param objects - The objects to exclude from rotating.
683
+ */
684
+ exclude(...objects: ISceneObject[]): this;
685
+ }
624
686
  export interface IDraft extends ISceneObject {
625
687
  }
626
688
  export interface IShell extends ISceneObject {
@@ -1,40 +1,40 @@
1
1
  import { PlaneLike } from "../math/plane.js";
2
2
  import { AxisLike } from "../math/axis.js";
3
- import { ISceneObject } from "./interfaces.js";
3
+ import { IMirror, ISceneObject } from "./interfaces.js";
4
4
  interface MirrorFunction {
5
5
  /**
6
6
  * [2D] Mirror all sketch geometries across a given line.
7
7
  * @param line The line to mirror across
8
8
  */
9
- (line: ISceneObject): ISceneObject;
9
+ (line: ISceneObject): IMirror;
10
10
  /**
11
11
  * [2D] Mirror all sketch geometries across a given axis.
12
12
  * @param axis The local axis to mirror across
13
13
  */
14
- (axis: AxisLike): ISceneObject;
14
+ (axis: AxisLike): IMirror;
15
15
  /**
16
16
  * [2D] Mirror given sketch geometries across a given line.
17
17
  * @param line The line to mirror across
18
18
  * @param geometries The geometries to mirror
19
19
  */
20
- (line: ISceneObject, ...geometries: ISceneObject[]): ISceneObject;
20
+ (line: ISceneObject, ...geometries: ISceneObject[]): IMirror;
21
21
  /**
22
22
  * [2D] Mirror given sketch geometries across a given axis.
23
23
  * @param axis The local axis to mirror across
24
24
  * @param geometries The geometries to mirror
25
25
  */
26
- (axis: AxisLike, ...geometries: ISceneObject[]): ISceneObject;
26
+ (axis: AxisLike, ...geometries: ISceneObject[]): IMirror;
27
27
  /**
28
28
  * [3D] Mirror all scene shapes across a given plane.
29
29
  * @param plane The plane to mirror across
30
30
  */
31
- (plane: PlaneLike): ISceneObject;
31
+ (plane: PlaneLike): IMirror;
32
32
  /**
33
33
  * [3D] Mirror given shapes across a given plane.
34
34
  * @param plane The plane to mirror across
35
35
  * @param objects The shapes to mirror
36
36
  */
37
- (plane: PlaneLike, ...objects: ISceneObject[]): ISceneObject;
37
+ (plane: PlaneLike, ...objects: ISceneObject[]): IMirror;
38
38
  }
39
39
  declare const _default: MirrorFunction;
40
40
  export default _default;
@@ -5,11 +5,11 @@ import { MirrorShape } from "../features/mirror-shape.js";
5
5
  import { PlaneObjectBase } from "../features/plane-renderable-base.js";
6
6
  import { PlaneObject } from "../features/plane.js";
7
7
  import { isAxisLike, isStandardAxis } from "../math/axis.js";
8
+ import { isPlaneLike } from "../math/plane.js";
8
9
  import { MirrorShape2D } from "../features/mirror-shape2d.js";
9
10
  import { AxisObjectBase } from "../features/axis-renderable-base.js";
10
11
  import { AxisObject } from "../features/axis.js";
11
12
  import { AxisFromEdge } from "../features/axis-from-edge.js";
12
- const axisToPlaneName = { x: "yz", y: "xz", z: "xy" };
13
13
  function resolveAxis(arg, context) {
14
14
  if (arg instanceof AxisObjectBase) {
15
15
  return arg;
@@ -36,6 +36,20 @@ function resolvePlane(arg, context) {
36
36
  function build(context) {
37
37
  return function mirror() {
38
38
  const activeSketch = context.getActiveSketch();
39
+ const firstArg = arguments[0];
40
+ if (activeSketch) {
41
+ const isPlaneArg = firstArg instanceof PlaneObjectBase
42
+ || (!isAxisLike(firstArg) && !(firstArg instanceof SceneObject) && isPlaneLike(firstArg));
43
+ if (isPlaneArg) {
44
+ throw new Error("Cannot specify a plane for mirror inside a sketch. Use mirror(axis) or mirror(line) instead.");
45
+ }
46
+ }
47
+ else if (firstArg instanceof SceneObject && !(firstArg instanceof PlaneObjectBase)) {
48
+ throw new Error("mirror(line) is only valid inside a sketch. For 3D mirroring, specify a plane: mirror(plane).");
49
+ }
50
+ else if (isStandardAxis(firstArg)) {
51
+ throw new Error("Cannot specify an axis for mirror outside a sketch. For 3D mirroring, specify a plane: mirror(plane).");
52
+ }
39
53
  if (arguments.length === 1) {
40
54
  if (activeSketch && (isAxisLike(arguments[0]) || arguments[0] instanceof SceneObject)) {
41
55
  const axis = resolveAxis(arguments[0], context);
@@ -43,11 +57,7 @@ function build(context) {
43
57
  context.addSceneObject(mirror);
44
58
  return mirror;
45
59
  }
46
- let planeArg = arguments[0];
47
- if (isStandardAxis(planeArg)) {
48
- planeArg = axisToPlaneName[planeArg];
49
- }
50
- const planeObj = resolvePlane(planeArg, context);
60
+ const planeObj = resolvePlane(arguments[0], context);
51
61
  const mirror = new MirrorShape(planeObj);
52
62
  context.addSceneObject(mirror);
53
63
  return mirror;
@@ -61,11 +71,7 @@ function build(context) {
61
71
  context.addSceneObject(mirror);
62
72
  return mirror;
63
73
  }
64
- let planeArg = args[0];
65
- if (isStandardAxis(planeArg)) {
66
- planeArg = axisToPlaneName[planeArg];
67
- }
68
- const planeObj = resolvePlane(planeArg, context);
74
+ const planeObj = resolvePlane(args[0], context);
69
75
  const targetObjects = args.slice(1);
70
76
  const mirror = new MirrorShape(planeObj, targetObjects);
71
77
  context.addSceneObject(mirror);
@@ -1,4 +1,6 @@
1
1
  import { ISceneObject } from "./interfaces.js";
2
- type Extend<T> = T extends object ? T : {};
2
+ type Extend<T> = T extends object ? {
3
+ features: T;
4
+ } : {};
3
5
  declare function part<T>(name: string, callback: () => T): ISceneObject & Extend<T>;
4
6
  export default part;
@@ -15,7 +15,7 @@ function part(name, callback) {
15
15
  const extensions = callback();
16
16
  scene.endProgressiveContainer();
17
17
  if (extensions && typeof extensions === 'object') {
18
- Object.assign(partObj, extensions);
18
+ partObj.features = extensions;
19
19
  }
20
20
  return partObj;
21
21
  }
@@ -1,26 +1,26 @@
1
1
  import { AxisLike } from "../math/axis.js";
2
- import { ISceneObject } from "./interfaces.js";
2
+ import { IRotate, ISceneObject } from "./interfaces.js";
3
3
  interface RotateFunction {
4
4
  /**
5
5
  * [2D] Rotates geometry by an angle inside a sketch.
6
6
  * @param angle - The rotation angle in degrees
7
7
  * @param targets - The geometries to rotate (defaults to last object)
8
8
  */
9
- (angle: number, ...targets: ISceneObject[]): ISceneObject;
9
+ (angle: number, ...targets: ISceneObject[]): IRotate;
10
10
  /**
11
11
  * [2D] Rotates geometry by an angle inside a sketch, optionally making a copy.
12
12
  * @param angle - The rotation angle in degrees
13
13
  * @param copy - Whether to copy instead of move
14
14
  * @param targets - The geometries to rotate (defaults to last object)
15
15
  */
16
- (angle: number, copy: boolean, ...targets: ISceneObject[]): ISceneObject;
16
+ (angle: number, copy: boolean, ...targets: ISceneObject[]): IRotate;
17
17
  /**
18
18
  * [3D] Rotates objects around an axis by an angle.
19
19
  * @param axis - The axis to rotate around
20
20
  * @param angle - The rotation angle in degrees
21
21
  * @param targets - The objects to rotate (defaults to last object)
22
22
  */
23
- (axis: AxisLike, angle: number, ...targets: ISceneObject[]): ISceneObject;
23
+ (axis: AxisLike, angle: number, ...targets: ISceneObject[]): IRotate;
24
24
  /**
25
25
  * [3D] Rotates objects around an axis by an angle, optionally making a copy.
26
26
  * @param axis - The axis to rotate around
@@ -28,7 +28,7 @@ interface RotateFunction {
28
28
  * @param copy - Whether to copy instead of move
29
29
  * @param targets - The objects to rotate (defaults to last object)
30
30
  */
31
- (axis: AxisLike, angle: number, copy: boolean, ...targets: ISceneObject[]): ISceneObject;
31
+ (axis: AxisLike, angle: number, copy: boolean, ...targets: ISceneObject[]): IRotate;
32
32
  }
33
33
  declare const _default: RotateFunction;
34
34
  export default _default;
@@ -17,7 +17,10 @@ function build(context) {
17
17
  // Extract copy flag from the end (if boolean)
18
18
  const copy = typeof args[args.length - 1] === 'boolean' ? args.pop() : false;
19
19
  // 2D: rotate(angle, copy?, ...targets)
20
- if (args.length === 1 && activeSketch) {
20
+ if (args.length === 1) {
21
+ if (!activeSketch) {
22
+ throw new Error("rotate(angle) is only valid inside a sketch. For 3D rotation, specify an axis: rotate(axis, angle).");
23
+ }
21
24
  const angle = args[0];
22
25
  const rotate = new Rotate2D(angle, copy, ...targets);
23
26
  context.addSceneObject(rotate);
@@ -1,6 +1,8 @@
1
1
  import { PlaneLike } from "../math/plane.js";
2
2
  import { IPlane, ISceneObject } from "./interfaces.js";
3
- type Extend<T> = T extends object ? T : {};
3
+ type Extend<T> = T extends object ? {
4
+ regions: T;
5
+ } : {};
4
6
  interface SketchFunction {
5
7
  /**
6
8
  * Draws 2D geometry on a standard plane.
@@ -29,7 +29,7 @@ function build(context) {
29
29
  const extensions = sketcher();
30
30
  context.endProgressiveContainer();
31
31
  if (extensions && typeof extensions === 'object') {
32
- Object.assign(sketch, extensions);
32
+ sketch.regions = extensions;
33
33
  }
34
34
  return sketch;
35
35
  };
@@ -1,26 +1,26 @@
1
1
  import { PointLike } from "../math/point.js";
2
- import { ISceneObject } from "./interfaces.js";
2
+ import { ISceneObject, ITranslate } from "./interfaces.js";
3
3
  interface TranslateFunction {
4
4
  /**
5
5
  * Translates objects along the X axis.
6
6
  * @param x - The X distance
7
7
  * @param targets - The objects to translate (defaults to last object)
8
8
  */
9
- (x: number, ...targets: ISceneObject[]): ISceneObject;
9
+ (x: number, ...targets: ISceneObject[]): ITranslate;
10
10
  /**
11
11
  * Translates objects along the X axis, optionally making a copy.
12
12
  * @param x - The X distance
13
13
  * @param copy - Whether to copy instead of move
14
14
  * @param targets - The objects to translate (defaults to last object)
15
15
  */
16
- (x: number, copy: boolean, ...targets: ISceneObject[]): ISceneObject;
16
+ (x: number, copy: boolean, ...targets: ISceneObject[]): ITranslate;
17
17
  /**
18
18
  * Translates objects along the X and Y axes.
19
19
  * @param x - The X distance
20
20
  * @param y - The Y distance
21
21
  * @param targets - The objects to translate (defaults to last object)
22
22
  */
23
- (x: number, y: number, ...targets: ISceneObject[]): ISceneObject;
23
+ (x: number, y: number, ...targets: ISceneObject[]): ITranslate;
24
24
  /**
25
25
  * Translates objects along the X and Y axes, optionally making a copy.
26
26
  * @param x - The X distance
@@ -28,7 +28,7 @@ interface TranslateFunction {
28
28
  * @param copy - Whether to copy instead of move
29
29
  * @param targets - The objects to translate (defaults to last object)
30
30
  */
31
- (x: number, y: number, copy: boolean, ...targets: ISceneObject[]): ISceneObject;
31
+ (x: number, y: number, copy: boolean, ...targets: ISceneObject[]): ITranslate;
32
32
  /**
33
33
  * Translates objects along all three axes.
34
34
  * @param x - The X distance
@@ -36,7 +36,7 @@ interface TranslateFunction {
36
36
  * @param z - The Z distance
37
37
  * @param targets - The objects to translate (defaults to last object)
38
38
  */
39
- (x: number, y: number, z: number, ...targets: ISceneObject[]): ISceneObject;
39
+ (x: number, y: number, z: number, ...targets: ISceneObject[]): ITranslate;
40
40
  /**
41
41
  * Translates objects along all three axes, optionally making a copy.
42
42
  * @param x - The X distance
@@ -45,20 +45,20 @@ interface TranslateFunction {
45
45
  * @param copy - Whether to copy instead of move
46
46
  * @param targets - The objects to translate (defaults to last object)
47
47
  */
48
- (x: number, y: number, z: number, copy: boolean, ...targets: ISceneObject[]): ISceneObject;
48
+ (x: number, y: number, z: number, copy: boolean, ...targets: ISceneObject[]): ITranslate;
49
49
  /**
50
50
  * Translates objects by a point-like offset.
51
51
  * @param distance - The offset as a point
52
52
  * @param targets - The objects to translate (defaults to last object)
53
53
  */
54
- (distance: PointLike, ...targets: ISceneObject[]): ISceneObject;
54
+ (distance: PointLike, ...targets: ISceneObject[]): ITranslate;
55
55
  /**
56
56
  * Translates objects by a point-like offset, optionally making a copy.
57
57
  * @param distance - The offset as a point
58
58
  * @param copy - Whether to copy instead of move
59
59
  * @param targets - The objects to translate (defaults to last object)
60
60
  */
61
- (distance: PointLike, copy: boolean, ...targets: ISceneObject[]): ISceneObject;
61
+ (distance: PointLike, copy: boolean, ...targets: ISceneObject[]): ITranslate;
62
62
  }
63
63
  declare const _default: TranslateFunction;
64
64
  export default _default;
@@ -1,20 +1,23 @@
1
1
  import { SceneObject } from "../../common/scene-object.js";
2
2
  import { PlaneObjectBase } from "../plane-renderable-base.js";
3
3
  import { GeometrySceneObject } from "./geometry.js";
4
- export declare class AngledLine extends GeometrySceneObject {
5
- length: number;
4
+ import { IALine } from "../../core/interfaces.js";
5
+ export declare class AngledLine extends GeometrySceneObject implements IALine {
6
6
  angle: number;
7
- centered: boolean;
7
+ lengthOrTarget: number | SceneObject;
8
8
  private targetPlane;
9
- constructor(length: number, angle: number, centered?: boolean, targetPlane?: PlaneObjectBase);
9
+ private _centered;
10
+ constructor(angle: number, lengthOrTarget: number | SceneObject, targetPlane?: PlaneObjectBase);
11
+ centered(value?: boolean): this;
10
12
  build(): void;
13
+ getDependencies(): SceneObject[];
11
14
  createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
12
15
  compareTo(other: AngledLine): boolean;
13
16
  getType(): string;
14
17
  getUniqueType(): string;
15
18
  serialize(): {
16
- length: number;
17
19
  angle: number;
20
+ length: number;
18
21
  centered: boolean;
19
22
  };
20
23
  }
@@ -1,20 +1,25 @@
1
+ import { SceneObject } from "../../common/scene-object.js";
1
2
  import { Vertex } from "../../common/vertex.js";
2
3
  import { Geometry } from "../../oc/geometry.js";
3
4
  import { rad } from "../../helpers/math-helpers.js";
4
5
  import { Point2D } from "../../math/point.js";
5
6
  import { GeometrySceneObject } from "./geometry.js";
7
+ import { findNearestRayIntersection } from "../../oc/ray-intersect.js";
6
8
  export class AngledLine extends GeometrySceneObject {
7
- length;
8
9
  angle;
9
- centered;
10
+ lengthOrTarget;
10
11
  targetPlane;
11
- constructor(length, angle, centered = false, targetPlane = null) {
12
+ _centered = false;
13
+ constructor(angle, lengthOrTarget, targetPlane = null) {
12
14
  super();
13
- this.length = length;
14
15
  this.angle = angle;
15
- this.centered = centered;
16
+ this.lengthOrTarget = lengthOrTarget;
16
17
  this.targetPlane = targetPlane;
17
18
  }
19
+ centered(value = true) {
20
+ this._centered = value;
21
+ return this;
22
+ }
18
23
  build() {
19
24
  const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
20
25
  let tangent = this.sketch?.getTangentAt(this) || new Point2D(1, 0);
@@ -29,27 +34,63 @@ export class AngledLine extends GeometrySceneObject {
29
34
  const currentPos = this.targetPlane
30
35
  ? plane.worldToLocal(this.targetPlane.getPlaneCenter())
31
36
  : this.getCurrentPosition();
32
- const startPoint = this.centered
33
- ? currentPos.translate(-direction.x * this.length / 2, -direction.y * this.length / 2)
34
- : currentPos;
37
+ let startPoint;
38
+ let endPoint;
39
+ if (typeof this.lengthOrTarget === 'number') {
40
+ const length = this.lengthOrTarget;
41
+ startPoint = this._centered
42
+ ? currentPos.translate(-direction.x * length / 2, -direction.y * length / 2)
43
+ : currentPos;
44
+ endPoint = startPoint.translate(direction.x * length, direction.y * length);
45
+ }
46
+ else {
47
+ if (this._centered) {
48
+ throw new Error('aLine: .centered() cannot be combined with a target geometry');
49
+ }
50
+ startPoint = currentPos;
51
+ endPoint = findNearestRayIntersection(plane, startPoint, direction, this.lengthOrTarget);
52
+ }
35
53
  const start = plane.localToWorld(startPoint);
36
- const worldDir = plane.xDirection.multiply(direction.x).add(plane.yDirection.multiply(direction.y));
37
- const end = start.add(worldDir.multiply(this.length));
38
- const endPoint = plane.worldToLocal(end);
54
+ const end = plane.localToWorld(endPoint);
39
55
  let segment = Geometry.makeSegment(start, end);
40
56
  const edge = Geometry.makeEdge(segment);
41
57
  this.setState('start', Vertex.fromPoint2D(startPoint));
42
58
  this.setState('end', Vertex.fromPoint2D(endPoint));
43
59
  this.addShape(edge);
44
- this.setTangent(direction.normalize());
45
- if (this.sketch)
60
+ // Tangent at end points from start to end (sign-aware when target is behind start)
61
+ const endTangent = endPoint.subtract(startPoint);
62
+ const endLen = Math.hypot(endTangent.x, endTangent.y);
63
+ if (endLen > 1e-12) {
64
+ this.setTangent(new Point2D(endTangent.x / endLen, endTangent.y / endLen));
65
+ }
66
+ else {
67
+ this.setTangent(direction.normalize());
68
+ }
69
+ if (this.sketch) {
46
70
  this.setCurrentPosition(endPoint);
47
- if (this.targetPlane)
71
+ }
72
+ if (this.targetPlane) {
48
73
  this.targetPlane.removeShapes(this);
74
+ }
75
+ }
76
+ getDependencies() {
77
+ const deps = [];
78
+ if (this.targetPlane) {
79
+ deps.push(this.targetPlane);
80
+ }
81
+ if (this.lengthOrTarget instanceof SceneObject) {
82
+ deps.push(this.lengthOrTarget);
83
+ }
84
+ return deps;
49
85
  }
50
86
  createCopy(remap) {
51
87
  const targetPlane = this.targetPlane ? (remap.get(this.targetPlane) || this.targetPlane) : null;
52
- return new AngledLine(this.length, this.angle, this.centered, targetPlane);
88
+ const lengthOrTarget = this.lengthOrTarget instanceof SceneObject
89
+ ? (remap.get(this.lengthOrTarget) || this.lengthOrTarget)
90
+ : this.lengthOrTarget;
91
+ const copy = new AngledLine(this.angle, lengthOrTarget, targetPlane);
92
+ copy.centered(this._centered);
93
+ return copy;
53
94
  }
54
95
  compareTo(other) {
55
96
  if (!(other instanceof AngledLine)) {
@@ -64,7 +105,18 @@ export class AngledLine extends GeometrySceneObject {
64
105
  if (this.targetPlane && other.targetPlane && !this.targetPlane.compareTo(other.targetPlane)) {
65
106
  return false;
66
107
  }
67
- return this.length === other.length && this.angle === other.angle && this.centered === other.centered;
108
+ if (typeof this.lengthOrTarget !== typeof other.lengthOrTarget) {
109
+ return false;
110
+ }
111
+ if (this.lengthOrTarget instanceof SceneObject && other.lengthOrTarget instanceof SceneObject) {
112
+ if (!this.lengthOrTarget.compareTo(other.lengthOrTarget)) {
113
+ return false;
114
+ }
115
+ }
116
+ else if (this.lengthOrTarget !== other.lengthOrTarget) {
117
+ return false;
118
+ }
119
+ return this.angle === other.angle && this._centered === other._centered;
68
120
  }
69
121
  getType() {
70
122
  return 'line';
@@ -74,9 +126,9 @@ export class AngledLine extends GeometrySceneObject {
74
126
  }
75
127
  serialize() {
76
128
  return {
77
- length: this.length,
78
129
  angle: this.angle,
79
- centered: this.centered
130
+ length: typeof this.lengthOrTarget === 'number' ? this.lengthOrTarget : null,
131
+ centered: this._centered
80
132
  };
81
133
  }
82
134
  }
@@ -0,0 +1,14 @@
1
+ import { SceneObject } from "../../common/scene-object.js";
2
+ import { GeometrySceneObject } from "./geometry.js";
3
+ export declare class Back extends GeometrySceneObject {
4
+ count: number;
5
+ constructor(count: number);
6
+ getType(): string;
7
+ build(): void;
8
+ getDependencies(): SceneObject[];
9
+ createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
10
+ compareTo(other: this): boolean;
11
+ serialize(): {
12
+ count: number;
13
+ };
14
+ }
@@ -0,0 +1,35 @@
1
+ import { GeometrySceneObject } from "./geometry.js";
2
+ export class Back extends GeometrySceneObject {
3
+ count;
4
+ constructor(count) {
5
+ super();
6
+ this.count = count;
7
+ }
8
+ getType() {
9
+ return 'back';
10
+ }
11
+ build() {
12
+ const target = this.sketch.getPreviousPosition(this, this.count);
13
+ this.setCurrentPosition(target);
14
+ }
15
+ getDependencies() {
16
+ return [];
17
+ }
18
+ createCopy(remap) {
19
+ return new Back(this.count);
20
+ }
21
+ compareTo(other) {
22
+ if (!(other instanceof Back)) {
23
+ return false;
24
+ }
25
+ if (!super.compareTo(other)) {
26
+ return false;
27
+ }
28
+ return this.count === other.count;
29
+ }
30
+ serialize() {
31
+ return {
32
+ count: this.count
33
+ };
34
+ }
35
+ }
@@ -0,0 +1,23 @@
1
+ import { SceneObject } from "../../common/scene-object.js";
2
+ import { Point2D } from "../../math/point.js";
3
+ import { PlaneObjectBase } from "../plane-renderable-base.js";
4
+ import { ExtrudableGeometryBase } from "./extrudable-base.js";
5
+ export declare class Ellipse extends ExtrudableGeometryBase {
6
+ rx: number;
7
+ ry: number;
8
+ private centerOverride;
9
+ constructor(rx: number, ry: number, targetPlane?: PlaneObjectBase, centerOverride?: Point2D | null);
10
+ getType(): string;
11
+ build(): void;
12
+ getDependencies(): SceneObject[];
13
+ createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
14
+ compareTo(other: this): boolean;
15
+ serialize(): {
16
+ center?: {
17
+ x: number;
18
+ y: number;
19
+ };
20
+ rx: number;
21
+ ry: number;
22
+ };
23
+ }