fluidcad 0.0.29 → 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 (62) hide show
  1. package/lib/dist/common/scene-object.d.ts +1 -0
  2. package/lib/dist/common/scene-object.js +3 -0
  3. package/lib/dist/core/2d/aline.d.ts +12 -12
  4. package/lib/dist/core/2d/aline.js +13 -8
  5. package/lib/dist/core/2d/back.d.ts +12 -0
  6. package/lib/dist/core/2d/back.js +11 -0
  7. package/lib/dist/core/2d/hline.d.ts +19 -12
  8. package/lib/dist/core/2d/hline.js +24 -10
  9. package/lib/dist/core/2d/index.d.ts +1 -0
  10. package/lib/dist/core/2d/index.js +1 -0
  11. package/lib/dist/core/2d/vline.d.ts +19 -12
  12. package/lib/dist/core/2d/vline.js +20 -10
  13. package/lib/dist/core/interfaces.d.ts +54 -0
  14. package/lib/dist/core/mirror.d.ts +7 -7
  15. package/lib/dist/core/rotate.d.ts +5 -5
  16. package/lib/dist/core/translate.d.ts +9 -9
  17. package/lib/dist/features/2d/aline.d.ts +8 -5
  18. package/lib/dist/features/2d/aline.js +70 -18
  19. package/lib/dist/features/2d/back.d.ts +14 -0
  20. package/lib/dist/features/2d/back.js +35 -0
  21. package/lib/dist/features/2d/hline.d.ts +9 -4
  22. package/lib/dist/features/2d/hline.js +65 -14
  23. package/lib/dist/features/2d/sketch.d.ts +1 -0
  24. package/lib/dist/features/2d/sketch.js +15 -0
  25. package/lib/dist/features/2d/vline.d.ts +9 -4
  26. package/lib/dist/features/2d/vline.js +67 -15
  27. package/lib/dist/features/lazy-scene-object.d.ts +1 -0
  28. package/lib/dist/features/lazy-scene-object.js +3 -0
  29. package/lib/dist/features/lazy-vertex.d.ts +1 -0
  30. package/lib/dist/features/lazy-vertex.js +3 -0
  31. package/lib/dist/features/mirror-shape.d.ts +2 -0
  32. package/lib/dist/features/mirror-shape.js +16 -0
  33. package/lib/dist/features/mirror-shape2d.d.ts +2 -0
  34. package/lib/dist/features/mirror-shape2d.js +22 -1
  35. package/lib/dist/features/rotate.d.ts +2 -0
  36. package/lib/dist/features/rotate.js +16 -0
  37. package/lib/dist/features/rotate2d.d.ts +2 -0
  38. package/lib/dist/features/rotate2d.js +16 -0
  39. package/lib/dist/features/translate.d.ts +2 -0
  40. package/lib/dist/features/translate.js +23 -2
  41. package/lib/dist/oc/ray-intersect.d.ts +16 -0
  42. package/lib/dist/oc/ray-intersect.js +91 -0
  43. package/lib/dist/rendering/render.js +4 -1
  44. package/lib/dist/tests/features/2d/back.test.d.ts +1 -0
  45. package/lib/dist/tests/features/2d/back.test.js +60 -0
  46. package/lib/dist/tests/features/2d/constrained.test.js +4 -4
  47. package/lib/dist/tests/features/2d/line.test.js +88 -2
  48. package/lib/dist/tests/features/2d/slot-from-edge.test.js +1 -1
  49. package/lib/dist/tests/features/mirror.test.js +58 -0
  50. package/lib/dist/tests/features/mirror2d.test.js +63 -0
  51. package/lib/dist/tests/features/rotate.test.js +62 -0
  52. package/lib/dist/tests/features/rotate2d.test.js +47 -0
  53. package/lib/dist/tests/features/thin-revolve.test.js +2 -2
  54. package/lib/dist/tests/features/translate.test.js +63 -0
  55. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +1 -1
  57. package/server/dist/index.js +77 -45
  58. package/server/dist/ws-protocol.d.ts +11 -0
  59. package/ui/dist/assets/{index-VY48_dgc.js → index-6Ep4GPxf.js} +92 -55
  60. package/ui/dist/assets/index-DRKfe6N9.css +2 -0
  61. package/ui/dist/index.html +2 -2
  62. package/ui/dist/assets/index-VKkXzLfR.css +0 -2
@@ -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
+ }
@@ -1,11 +1,16 @@
1
1
  import { PlaneObjectBase } from "../plane-renderable-base.js";
2
2
  import { GeometrySceneObject } from "./geometry.js";
3
- export declare class HorizontalLine extends GeometrySceneObject {
4
- distance: number;
5
- centered: boolean;
3
+ import { IHLine } from "../../core/interfaces.js";
4
+ import { SceneObject } from "../../common/scene-object.js";
5
+ export declare class HorizontalLine extends GeometrySceneObject implements IHLine {
6
+ distanceOrTarget: number | SceneObject;
6
7
  private targetPlane;
7
- constructor(distance: number, centered?: boolean, targetPlane?: PlaneObjectBase);
8
+ private _centered;
9
+ constructor(distanceOrTarget: number | SceneObject, targetPlane?: PlaneObjectBase);
10
+ centered(value?: boolean): this;
8
11
  build(): void;
12
+ getDependencies(): SceneObject[];
13
+ createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
9
14
  compareTo(other: HorizontalLine): boolean;
10
15
  getType(): string;
11
16
  getUniqueType(): string;
@@ -2,25 +2,45 @@ import { Vertex } from "../../common/vertex.js";
2
2
  import { Geometry } from "../../oc/geometry.js";
3
3
  import { Point2D } from "../../math/point.js";
4
4
  import { GeometrySceneObject } from "./geometry.js";
5
+ import { SceneObject } from "../../common/scene-object.js";
6
+ import { findNearestRayIntersection } from "../../oc/ray-intersect.js";
5
7
  export class HorizontalLine extends GeometrySceneObject {
6
- distance;
7
- centered;
8
+ distanceOrTarget;
8
9
  targetPlane;
9
- constructor(distance, centered = false, targetPlane = null) {
10
+ _centered = false;
11
+ constructor(distanceOrTarget, targetPlane = null) {
10
12
  super();
11
- this.distance = distance;
12
- this.centered = centered;
13
+ this.distanceOrTarget = distanceOrTarget;
13
14
  this.targetPlane = targetPlane;
14
15
  }
16
+ centered(value = true) {
17
+ this._centered = value;
18
+ return this;
19
+ }
15
20
  build() {
16
21
  const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
17
22
  const currentPos = this.targetPlane
18
23
  ? plane.worldToLocal(this.targetPlane.getPlaneCenter())
19
24
  : this.getCurrentPosition();
20
- const startPoint = this.centered
21
- ? currentPos.translate(-this.distance / 2, 0)
22
- : currentPos;
23
- const endPoint = startPoint.translate(this.distance, 0);
25
+ let startPoint;
26
+ let endPoint;
27
+ let signedLength;
28
+ if (typeof this.distanceOrTarget === 'number') {
29
+ const distance = this.distanceOrTarget;
30
+ startPoint = this._centered
31
+ ? currentPos.translate(-distance / 2, 0)
32
+ : currentPos;
33
+ endPoint = startPoint.translate(distance, 0);
34
+ signedLength = distance;
35
+ }
36
+ else {
37
+ if (this._centered) {
38
+ throw new Error('hLine: .centered() cannot be combined with a target geometry');
39
+ }
40
+ startPoint = currentPos;
41
+ endPoint = findNearestRayIntersection(plane, startPoint, new Point2D(1, 0), this.distanceOrTarget);
42
+ signedLength = endPoint.x - startPoint.x;
43
+ }
24
44
  const start = plane.localToWorld(startPoint);
25
45
  const end = plane.localToWorld(endPoint);
26
46
  let segment = Geometry.makeSegment(start, end);
@@ -28,13 +48,33 @@ export class HorizontalLine extends GeometrySceneObject {
28
48
  this.setState('start', Vertex.fromPoint2D(startPoint));
29
49
  this.setState('end', Vertex.fromPoint2D(endPoint));
30
50
  this.addShape(edge);
31
- const sign = Math.sign(this.distance) || 1;
51
+ const sign = Math.sign(signedLength) || 1;
32
52
  this.setTangent(new Point2D(sign, 0));
33
53
  if (this.sketch) {
34
54
  this.setCurrentPosition(endPoint);
35
55
  }
36
- if (this.targetPlane)
56
+ if (this.targetPlane) {
37
57
  this.targetPlane.removeShapes(this);
58
+ }
59
+ }
60
+ getDependencies() {
61
+ const deps = [];
62
+ if (this.targetPlane) {
63
+ deps.push(this.targetPlane);
64
+ }
65
+ if (this.distanceOrTarget instanceof SceneObject) {
66
+ deps.push(this.distanceOrTarget);
67
+ }
68
+ return deps;
69
+ }
70
+ createCopy(remap) {
71
+ const targetPlane = this.targetPlane ? (remap.get(this.targetPlane) || this.targetPlane) : null;
72
+ const distanceOrTarget = this.distanceOrTarget instanceof SceneObject
73
+ ? (remap.get(this.distanceOrTarget) || this.distanceOrTarget)
74
+ : this.distanceOrTarget;
75
+ const copy = new HorizontalLine(distanceOrTarget, targetPlane);
76
+ copy.centered(this._centered);
77
+ return copy;
38
78
  }
39
79
  compareTo(other) {
40
80
  if (!(other instanceof HorizontalLine)) {
@@ -49,7 +89,18 @@ export class HorizontalLine extends GeometrySceneObject {
49
89
  if (this.targetPlane && other.targetPlane && !this.targetPlane.compareTo(other.targetPlane)) {
50
90
  return false;
51
91
  }
52
- return this.distance === other.distance && this.centered === other.centered;
92
+ if (typeof this.distanceOrTarget !== typeof other.distanceOrTarget) {
93
+ return false;
94
+ }
95
+ if (this.distanceOrTarget instanceof SceneObject && other.distanceOrTarget instanceof SceneObject) {
96
+ if (!this.distanceOrTarget.compareTo(other.distanceOrTarget)) {
97
+ return false;
98
+ }
99
+ }
100
+ else if (this.distanceOrTarget !== other.distanceOrTarget) {
101
+ return false;
102
+ }
103
+ return this._centered === other._centered;
53
104
  }
54
105
  getType() {
55
106
  return 'line';
@@ -59,8 +110,8 @@ export class HorizontalLine extends GeometrySceneObject {
59
110
  }
60
111
  serialize() {
61
112
  return {
62
- distance: this.distance,
63
- centered: this.centered
113
+ distance: typeof this.distanceOrTarget === 'number' ? this.distanceOrTarget : null,
114
+ centered: this._centered
64
115
  };
65
116
  }
66
117
  }
@@ -14,6 +14,7 @@ export declare class Sketch extends SceneObject implements Extrudable {
14
14
  getStartPoint(): Point2D;
15
15
  getTangentAt(currentObj: GeometrySceneObject): Point2D | null;
16
16
  getPositionAt(currentObj: GeometrySceneObject): Point2D;
17
+ getPreviousPosition(currentObj: GeometrySceneObject, count?: number): Point2D;
17
18
  getLastPosition(scope?: Set<SceneObject>): Point2D;
18
19
  build(context?: BuildSceneObjectContext): void;
19
20
  getEdges(): Edge[];
@@ -58,6 +58,21 @@ export class Sketch extends SceneObject {
58
58
  }
59
59
  return this.getStartPoint();
60
60
  }
61
+ getPreviousPosition(currentObj, count = 1) {
62
+ const children = this.getChildren();
63
+ const previous = children.slice(0, children.indexOf(currentObj));
64
+ let remaining = count;
65
+ for (let i = previous.length - 1; i >= 0; i--) {
66
+ const pos = previous[i].getState('current-position');
67
+ if (pos) {
68
+ if (remaining === 0) {
69
+ return pos;
70
+ }
71
+ remaining--;
72
+ }
73
+ }
74
+ return this.getStartPoint();
75
+ }
61
76
  getLastPosition(scope) {
62
77
  let children = this.getChildren().slice();
63
78
  if (scope) {
@@ -1,11 +1,16 @@
1
1
  import { PlaneObjectBase } from "../plane-renderable-base.js";
2
2
  import { GeometrySceneObject } from "./geometry.js";
3
- export declare class VerticalLine extends GeometrySceneObject {
4
- distance: number;
5
- centered: boolean;
3
+ import { IVLine } from "../../core/interfaces.js";
4
+ import { SceneObject } from "../../common/scene-object.js";
5
+ export declare class VerticalLine extends GeometrySceneObject implements IVLine {
6
+ distanceOrTarget: number | SceneObject;
6
7
  private targetPlane;
7
- constructor(distance: number, centered?: boolean, targetPlane?: PlaneObjectBase);
8
+ private _centered;
9
+ constructor(distanceOrTarget: number | SceneObject, targetPlane?: PlaneObjectBase);
10
+ centered(value?: boolean): this;
8
11
  build(): void;
12
+ getDependencies(): SceneObject[];
13
+ createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
9
14
  compareTo(other: VerticalLine): boolean;
10
15
  getType(): string;
11
16
  getUniqueType(): string;
@@ -2,25 +2,45 @@ import { Vertex } from "../../common/vertex.js";
2
2
  import { Geometry } from "../../oc/geometry.js";
3
3
  import { Point2D } from "../../math/point.js";
4
4
  import { GeometrySceneObject } from "./geometry.js";
5
+ import { SceneObject } from "../../common/scene-object.js";
6
+ import { findNearestRayIntersection } from "../../oc/ray-intersect.js";
5
7
  export class VerticalLine extends GeometrySceneObject {
6
- distance;
7
- centered;
8
+ distanceOrTarget;
8
9
  targetPlane;
9
- constructor(distance, centered = false, targetPlane = null) {
10
+ _centered = false;
11
+ constructor(distanceOrTarget, targetPlane = null) {
10
12
  super();
11
- this.distance = distance;
12
- this.centered = centered;
13
+ this.distanceOrTarget = distanceOrTarget;
13
14
  this.targetPlane = targetPlane;
14
15
  }
16
+ centered(value = true) {
17
+ this._centered = value;
18
+ return this;
19
+ }
15
20
  build() {
16
21
  const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
17
22
  const currentPos = this.targetPlane
18
23
  ? plane.worldToLocal(this.targetPlane.getPlaneCenter())
19
24
  : this.getCurrentPosition();
20
- const startPoint = this.centered
21
- ? currentPos.translate(0, -this.distance / 2)
22
- : currentPos;
23
- const endPoint = startPoint.translate(0, this.distance);
25
+ let startPoint;
26
+ let endPoint;
27
+ let signedLength;
28
+ if (typeof this.distanceOrTarget === 'number') {
29
+ const distance = this.distanceOrTarget;
30
+ startPoint = this._centered
31
+ ? currentPos.translate(0, -distance / 2)
32
+ : currentPos;
33
+ endPoint = startPoint.translate(0, distance);
34
+ signedLength = distance;
35
+ }
36
+ else {
37
+ if (this._centered) {
38
+ throw new Error('vLine: .centered() cannot be combined with a target geometry');
39
+ }
40
+ startPoint = currentPos;
41
+ endPoint = findNearestRayIntersection(plane, startPoint, new Point2D(0, 1), this.distanceOrTarget);
42
+ signedLength = endPoint.y - startPoint.y;
43
+ }
24
44
  const start = plane.localToWorld(startPoint);
25
45
  const end = plane.localToWorld(endPoint);
26
46
  let segment = Geometry.makeSegment(start, end);
@@ -28,12 +48,33 @@ export class VerticalLine extends GeometrySceneObject {
28
48
  this.setState('start', Vertex.fromPoint2D(startPoint));
29
49
  this.setState('end', Vertex.fromPoint2D(endPoint));
30
50
  this.addShape(edge);
31
- const sign = Math.sign(this.distance) || 1;
51
+ const sign = Math.sign(signedLength) || 1;
32
52
  this.setTangent(new Point2D(0, sign));
33
- if (this.sketch)
53
+ if (this.sketch) {
34
54
  this.setCurrentPosition(endPoint);
35
- if (this.targetPlane)
55
+ }
56
+ if (this.targetPlane) {
36
57
  this.targetPlane.removeShapes(this);
58
+ }
59
+ }
60
+ getDependencies() {
61
+ const deps = [];
62
+ if (this.targetPlane) {
63
+ deps.push(this.targetPlane);
64
+ }
65
+ if (this.distanceOrTarget instanceof SceneObject) {
66
+ deps.push(this.distanceOrTarget);
67
+ }
68
+ return deps;
69
+ }
70
+ createCopy(remap) {
71
+ const targetPlane = this.targetPlane ? (remap.get(this.targetPlane) || this.targetPlane) : null;
72
+ const distanceOrTarget = this.distanceOrTarget instanceof SceneObject
73
+ ? (remap.get(this.distanceOrTarget) || this.distanceOrTarget)
74
+ : this.distanceOrTarget;
75
+ const copy = new VerticalLine(distanceOrTarget, targetPlane);
76
+ copy.centered(this._centered);
77
+ return copy;
37
78
  }
38
79
  compareTo(other) {
39
80
  if (!(other instanceof VerticalLine)) {
@@ -48,7 +89,18 @@ export class VerticalLine extends GeometrySceneObject {
48
89
  if (this.targetPlane && other.targetPlane && !this.targetPlane.compareTo(other.targetPlane)) {
49
90
  return false;
50
91
  }
51
- return this.distance === other.distance && this.centered === other.centered;
92
+ if (typeof this.distanceOrTarget !== typeof other.distanceOrTarget) {
93
+ return false;
94
+ }
95
+ if (this.distanceOrTarget instanceof SceneObject && other.distanceOrTarget instanceof SceneObject) {
96
+ if (!this.distanceOrTarget.compareTo(other.distanceOrTarget)) {
97
+ return false;
98
+ }
99
+ }
100
+ else if (this.distanceOrTarget !== other.distanceOrTarget) {
101
+ return false;
102
+ }
103
+ return this._centered === other._centered;
52
104
  }
53
105
  getType() {
54
106
  return 'line';
@@ -58,8 +110,8 @@ export class VerticalLine extends GeometrySceneObject {
58
110
  }
59
111
  serialize() {
60
112
  return {
61
- distance: this.distance,
62
- centered: this.centered
113
+ distance: typeof this.distanceOrTarget === 'number' ? this.distanceOrTarget : null,
114
+ centered: this._centered
63
115
  };
64
116
  }
65
117
  }
@@ -7,6 +7,7 @@ export declare class LazySelectionSceneObject extends SceneObject {
7
7
  private _originalParent;
8
8
  constructor(uniqueName: string, getShapesFn: (parent: SceneObject) => Shape[], sourceParent: SceneObject);
9
9
  build(): void;
10
+ isLazy(): boolean;
10
11
  getDependencies(): SceneObject[];
11
12
  createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
12
13
  compareTo(other: LazySelectionSceneObject): boolean;
@@ -14,6 +14,9 @@ export class LazySelectionSceneObject extends SceneObject {
14
14
  const shapes = this.getShapesFn(this.sourceParent);
15
15
  this.addShapes(shapes);
16
16
  }
17
+ isLazy() {
18
+ return true;
19
+ }
17
20
  getDependencies() {
18
21
  return [this.sourceParent];
19
22
  }
@@ -8,6 +8,7 @@ export declare class LazyVertex extends SceneObject {
8
8
  private _isBuilt;
9
9
  constructor(uniqueName: string, getShapesFn: () => Shape[]);
10
10
  build(): void;
11
+ isLazy(): boolean;
11
12
  getShapes(filter?: ShapeFilter, type?: ShapeType): Shape[];
12
13
  asPoint(): import("../math/point.js").Point;
13
14
  asPoint2D(): import("../math/point.js").Point2D;
@@ -19,6 +19,9 @@ export class LazyVertex extends SceneObject {
19
19
  }
20
20
  this.addShapes(shapes);
21
21
  }
22
+ isLazy() {
23
+ return true;
24
+ }
22
25
  getShapes(filter, type) {
23
26
  if (this._isBuilt) {
24
27
  return super.getShapes(filter, type);
@@ -3,7 +3,9 @@ import { PlaneObjectBase } from "./plane-renderable-base.js";
3
3
  export declare class MirrorShape extends SceneObject {
4
4
  private plane;
5
5
  targetObjects: SceneObject[] | null;
6
+ private _excludedObjects;
6
7
  constructor(plane: PlaneObjectBase, targetObjects?: SceneObject[] | null);
8
+ exclude(...objects: SceneObject[]): this;
7
9
  build(context: BuildSceneObjectContext): void;
8
10
  compareTo(other: MirrorShape): boolean;
9
11
  getType(): string;
@@ -5,11 +5,16 @@ import { fuseWithSceneObjects } from "../helpers/scene-helpers.js";
5
5
  export class MirrorShape extends SceneObject {
6
6
  plane;
7
7
  targetObjects;
8
+ _excludedObjects = [];
8
9
  constructor(plane, targetObjects = null) {
9
10
  super();
10
11
  this.plane = plane;
11
12
  this.targetObjects = targetObjects;
12
13
  }
14
+ exclude(...objects) {
15
+ this._excludedObjects.push(...objects);
16
+ return this;
17
+ }
13
18
  build(context) {
14
19
  let objects;
15
20
  let targetObjects = this.targetObjects;
@@ -30,6 +35,9 @@ export class MirrorShape extends SceneObject {
30
35
  else {
31
36
  targetObjects = lastObj ? [lastObj] : objects;
32
37
  }
38
+ if (this._excludedObjects.length > 0) {
39
+ targetObjects = targetObjects.filter(obj => !this._excludedObjects.includes(obj));
40
+ }
33
41
  if (this.plane) {
34
42
  this.plane.removeShapes(this);
35
43
  }
@@ -81,6 +89,14 @@ export class MirrorShape extends SceneObject {
81
89
  return false;
82
90
  }
83
91
  }
92
+ if (this._excludedObjects.length !== other._excludedObjects.length) {
93
+ return false;
94
+ }
95
+ for (let i = 0; i < this._excludedObjects.length; i++) {
96
+ if (!this._excludedObjects[i].compareTo(other._excludedObjects[i])) {
97
+ return false;
98
+ }
99
+ }
84
100
  return true;
85
101
  }
86
102
  getType() {
@@ -5,7 +5,9 @@ import { LazyVertex } from "./lazy-vertex.js";
5
5
  export declare class MirrorShape2D extends GeometrySceneObject {
6
6
  private axis;
7
7
  private targetObjects;
8
+ private _excludedObjects;
8
9
  constructor(axis: AxisObjectBase, targetObjects?: SceneObject[]);
10
+ exclude(...objects: SceneObject[]): this;
9
11
  build(context: BuildSceneObjectContext): void;
10
12
  start(): LazyVertex;
11
13
  end(): LazyVertex;
@@ -6,11 +6,16 @@ import { Vertex } from "../common/vertex.js";
6
6
  export class MirrorShape2D extends GeometrySceneObject {
7
7
  axis;
8
8
  targetObjects;
9
+ _excludedObjects = [];
9
10
  constructor(axis, targetObjects = null) {
10
11
  super();
11
12
  this.axis = axis;
12
13
  this.targetObjects = targetObjects;
13
14
  }
15
+ exclude(...objects) {
16
+ this._excludedObjects.push(...objects);
17
+ return this;
18
+ }
14
19
  build(context) {
15
20
  let targetObjects = this.targetObjects;
16
21
  let sketch = this.sketch;
@@ -23,6 +28,9 @@ export class MirrorShape2D extends GeometrySceneObject {
23
28
  else {
24
29
  targetObjects = objects;
25
30
  }
31
+ if (this._excludedObjects.length > 0) {
32
+ targetObjects = targetObjects.filter(obj => !this._excludedObjects.includes(obj));
33
+ }
26
34
  this.axis.removeShapes(this);
27
35
  axis = this.axis.getAxis();
28
36
  const transformedShapes = [];
@@ -79,7 +87,12 @@ export class MirrorShape2D extends GeometrySceneObject {
79
87
  const targetObjects = this.targetObjects
80
88
  ? this.targetObjects.map(obj => remap.get(obj) || obj)
81
89
  : null;
82
- return new MirrorShape2D(axis, targetObjects);
90
+ const copy = new MirrorShape2D(axis, targetObjects);
91
+ if (this._excludedObjects.length > 0) {
92
+ const remappedExcluded = this._excludedObjects.map(obj => remap.get(obj) || obj);
93
+ copy.exclude(...remappedExcluded);
94
+ }
95
+ return copy;
83
96
  }
84
97
  compareTo(other) {
85
98
  if (!(other instanceof MirrorShape2D)) {
@@ -101,6 +114,14 @@ export class MirrorShape2D extends GeometrySceneObject {
101
114
  return false;
102
115
  }
103
116
  }
117
+ if (this._excludedObjects.length !== other._excludedObjects.length) {
118
+ return false;
119
+ }
120
+ for (let i = 0; i < this._excludedObjects.length; i++) {
121
+ if (!this._excludedObjects[i].compareTo(other._excludedObjects[i])) {
122
+ return false;
123
+ }
124
+ }
104
125
  return true;
105
126
  }
106
127
  getType() {