fluidcad 0.0.29 → 0.0.31

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 (144) hide show
  1. package/lib/dist/common/build-error.d.ts +13 -0
  2. package/lib/dist/common/build-error.js +18 -0
  3. package/lib/dist/common/describe-error.d.ts +6 -0
  4. package/lib/dist/common/describe-error.js +26 -0
  5. package/lib/dist/common/operand-check.d.ts +19 -0
  6. package/lib/dist/common/operand-check.js +38 -0
  7. package/lib/dist/common/scene-object.d.ts +9 -0
  8. package/lib/dist/common/scene-object.js +13 -0
  9. package/lib/dist/common/shape-factory.d.ts +1 -1
  10. package/lib/dist/core/2d/aline.d.ts +12 -12
  11. package/lib/dist/core/2d/aline.js +13 -8
  12. package/lib/dist/core/2d/arc.d.ts +4 -2
  13. package/lib/dist/core/2d/back.d.ts +12 -0
  14. package/lib/dist/core/2d/back.js +11 -0
  15. package/lib/dist/core/2d/hline.d.ts +19 -12
  16. package/lib/dist/core/2d/hline.js +24 -10
  17. package/lib/dist/core/2d/hmove.d.ts +8 -1
  18. package/lib/dist/core/2d/hmove.js +6 -2
  19. package/lib/dist/core/2d/index.d.ts +1 -0
  20. package/lib/dist/core/2d/index.js +1 -0
  21. package/lib/dist/core/2d/pmove.d.ts +13 -3
  22. package/lib/dist/core/2d/pmove.js +6 -2
  23. package/lib/dist/core/2d/vline.d.ts +19 -12
  24. package/lib/dist/core/2d/vline.js +20 -10
  25. package/lib/dist/core/2d/vmove.d.ts +8 -1
  26. package/lib/dist/core/2d/vmove.js +8 -4
  27. package/lib/dist/core/interfaces.d.ts +54 -0
  28. package/lib/dist/core/mirror.d.ts +7 -7
  29. package/lib/dist/core/rotate.d.ts +5 -5
  30. package/lib/dist/core/translate.d.ts +9 -9
  31. package/lib/dist/features/2d/aline.d.ts +8 -5
  32. package/lib/dist/features/2d/aline.js +75 -19
  33. package/lib/dist/features/2d/arc.d.ts +3 -0
  34. package/lib/dist/features/2d/arc.js +28 -1
  35. package/lib/dist/features/2d/back.d.ts +14 -0
  36. package/lib/dist/features/2d/back.js +35 -0
  37. package/lib/dist/features/2d/hline.d.ts +9 -4
  38. package/lib/dist/features/2d/hline.js +69 -14
  39. package/lib/dist/features/2d/hmove.d.ts +2 -2
  40. package/lib/dist/features/2d/hmove.js +32 -7
  41. package/lib/dist/features/2d/intersect.js +17 -10
  42. package/lib/dist/features/2d/pmove.d.ts +2 -2
  43. package/lib/dist/features/2d/pmove.js +47 -7
  44. package/lib/dist/features/2d/projection.d.ts +1 -1
  45. package/lib/dist/features/2d/projection.js +25 -15
  46. package/lib/dist/features/2d/sketch.d.ts +3 -2
  47. package/lib/dist/features/2d/sketch.js +25 -4
  48. package/lib/dist/features/2d/tarc-to-point.js +0 -3
  49. package/lib/dist/features/2d/tarc.js +0 -3
  50. package/lib/dist/features/2d/tline.js +0 -3
  51. package/lib/dist/features/2d/vline.d.ts +9 -4
  52. package/lib/dist/features/2d/vline.js +71 -15
  53. package/lib/dist/features/2d/vmove.d.ts +2 -2
  54. package/lib/dist/features/2d/vmove.js +32 -7
  55. package/lib/dist/features/axis-from-edge.d.ts +1 -0
  56. package/lib/dist/features/axis-from-edge.js +8 -0
  57. package/lib/dist/features/chamfer.d.ts +1 -0
  58. package/lib/dist/features/chamfer.js +6 -0
  59. package/lib/dist/features/color.d.ts +1 -0
  60. package/lib/dist/features/color.js +6 -0
  61. package/lib/dist/features/common.d.ts +1 -0
  62. package/lib/dist/features/common.js +9 -0
  63. package/lib/dist/features/common2d.d.ts +1 -0
  64. package/lib/dist/features/common2d.js +9 -0
  65. package/lib/dist/features/draft.d.ts +1 -0
  66. package/lib/dist/features/draft.js +6 -0
  67. package/lib/dist/features/fillet.d.ts +1 -0
  68. package/lib/dist/features/fillet.js +6 -0
  69. package/lib/dist/features/fillet2d.d.ts +1 -0
  70. package/lib/dist/features/fillet2d.js +9 -0
  71. package/lib/dist/features/fuse.d.ts +1 -0
  72. package/lib/dist/features/fuse.js +6 -0
  73. package/lib/dist/features/fuse2d.d.ts +1 -0
  74. package/lib/dist/features/fuse2d.js +9 -0
  75. package/lib/dist/features/lazy-scene-object.d.ts +1 -0
  76. package/lib/dist/features/lazy-scene-object.js +3 -0
  77. package/lib/dist/features/lazy-vertex.d.ts +1 -0
  78. package/lib/dist/features/lazy-vertex.js +3 -0
  79. package/lib/dist/features/loft.d.ts +1 -0
  80. package/lib/dist/features/loft.js +6 -0
  81. package/lib/dist/features/mirror-shape.d.ts +3 -0
  82. package/lib/dist/features/mirror-shape.js +44 -8
  83. package/lib/dist/features/mirror-shape2d.d.ts +2 -0
  84. package/lib/dist/features/mirror-shape2d.js +22 -1
  85. package/lib/dist/features/plane-from-object.d.ts +1 -0
  86. package/lib/dist/features/plane-from-object.js +8 -0
  87. package/lib/dist/features/rotate.d.ts +3 -0
  88. package/lib/dist/features/rotate.js +25 -0
  89. package/lib/dist/features/rotate2d.d.ts +2 -0
  90. package/lib/dist/features/rotate2d.js +16 -0
  91. package/lib/dist/features/shell.d.ts +1 -0
  92. package/lib/dist/features/shell.js +6 -0
  93. package/lib/dist/features/subtract.d.ts +1 -0
  94. package/lib/dist/features/subtract.js +5 -0
  95. package/lib/dist/features/subtract2d.d.ts +1 -0
  96. package/lib/dist/features/subtract2d.js +5 -0
  97. package/lib/dist/features/sweep.d.ts +1 -0
  98. package/lib/dist/features/sweep.js +4 -0
  99. package/lib/dist/features/translate.d.ts +3 -0
  100. package/lib/dist/features/translate.js +32 -2
  101. package/lib/dist/oc/boolean-ops.d.ts +2 -2
  102. package/lib/dist/oc/edge-ops.d.ts +17 -0
  103. package/lib/dist/oc/edge-ops.js +60 -0
  104. package/lib/dist/oc/face-query.js +17 -13
  105. package/lib/dist/oc/ray-intersect.d.ts +17 -0
  106. package/lib/dist/oc/ray-intersect.js +89 -0
  107. package/lib/dist/oc/shell-ops.js +15 -2
  108. package/lib/dist/oc/thin-face-maker.d.ts +15 -0
  109. package/lib/dist/oc/thin-face-maker.js +48 -7
  110. package/lib/dist/oc/wire-ops.d.ts +14 -0
  111. package/lib/dist/oc/wire-ops.js +38 -0
  112. package/lib/dist/rendering/render.js +10 -5
  113. package/lib/dist/tests/common/describe-error.test.d.ts +1 -0
  114. package/lib/dist/tests/common/describe-error.test.js +36 -0
  115. package/lib/dist/tests/features/2d/back.test.d.ts +1 -0
  116. package/lib/dist/tests/features/2d/back.test.js +60 -0
  117. package/lib/dist/tests/features/2d/constrained.test.js +4 -4
  118. package/lib/dist/tests/features/2d/intersect.test.js +43 -0
  119. package/lib/dist/tests/features/2d/line.test.js +88 -2
  120. package/lib/dist/tests/features/2d/move.test.js +72 -1
  121. package/lib/dist/tests/features/2d/project-regression.test.js +35 -0
  122. package/lib/dist/tests/features/2d/slot-from-edge.test.js +1 -1
  123. package/lib/dist/tests/features/color-lineage.test.js +24 -0
  124. package/lib/dist/tests/features/cylinder-curve-filter.test.d.ts +1 -0
  125. package/lib/dist/tests/features/cylinder-curve-filter.test.js +99 -0
  126. package/lib/dist/tests/features/mirror.test.js +132 -0
  127. package/lib/dist/tests/features/mirror2d.test.js +63 -0
  128. package/lib/dist/tests/features/rotate.test.js +62 -0
  129. package/lib/dist/tests/features/rotate2d.test.js +47 -0
  130. package/lib/dist/tests/features/subtract-consumed-input.test.d.ts +1 -0
  131. package/lib/dist/tests/features/subtract-consumed-input.test.js +28 -0
  132. package/lib/dist/tests/features/thin-extrude-offset-fix.test.d.ts +1 -0
  133. package/lib/dist/tests/features/thin-extrude-offset-fix.test.js +34 -0
  134. package/lib/dist/tests/features/thin-revolve.test.js +2 -2
  135. package/lib/dist/tests/features/translate.test.js +63 -0
  136. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  137. package/package.json +2 -3
  138. package/server/dist/index.js +77 -45
  139. package/server/dist/ws-protocol.d.ts +11 -0
  140. package/ui/dist/assets/index-B15vMQZ2.js +4946 -0
  141. package/ui/dist/assets/index-DR7c2Qk9.css +2 -0
  142. package/ui/dist/index.html +2 -2
  143. package/ui/dist/assets/index-VKkXzLfR.css +0 -2
  144. package/ui/dist/assets/index-VY48_dgc.js +0 -4909
@@ -1,11 +1,15 @@
1
1
  import { VMove } from "../../features/2d/vmove.js";
2
+ import { SceneObject } from "../../common/scene-object.js";
2
3
  import { registerBuilder } from "../../index.js";
3
4
  function build(context) {
4
5
  return function move() {
5
- const distance = arguments[0];
6
- const move = new VMove(distance);
7
- context.addSceneObject(move);
8
- return move;
6
+ const arg = arguments[0];
7
+ const distanceOrTarget = arg instanceof SceneObject
8
+ ? arg
9
+ : arg;
10
+ const vmove = new VMove(distanceOrTarget);
11
+ context.addSceneObject(vmove);
12
+ return vmove;
9
13
  };
10
14
  }
11
15
  export default registerBuilder(build);
@@ -227,6 +227,33 @@ export interface ISlot extends IExtrudableGeometry {
227
227
  */
228
228
  rotate(angle: number): this;
229
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
+ }
230
257
  export interface IPolygon extends IExtrudableGeometry {
231
258
  /**
232
259
  * Returns a specific edge of the polygon by index.
@@ -629,6 +656,33 @@ export interface ISweep extends IBooleanOperation {
629
656
  */
630
657
  capEdges(...args: (number | EdgeFilterBuilder)[]): ISceneObject;
631
658
  }
659
+ export interface IMirror extends IBooleanOperation {
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
+ }
632
686
  export interface IDraft extends ISceneObject {
633
687
  }
634
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;
@@ -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;
@@ -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,23 +1,28 @@
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
- let tangent = this.sketch?.getTangentAt(this) || new Point2D(1, 0);
25
+ let tangent = this.sketch?.getTangentAt(this) ?? new Point2D(1, 0);
21
26
  tangent = tangent.normalize();
22
27
  const angleRad = rad(this.angle);
23
28
  // 2D rotation of tangent by angle
@@ -29,27 +34,67 @@ 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
+ const hit = findNearestRayIntersection(plane, startPoint, direction, this.lengthOrTarget);
52
+ if (!hit) {
53
+ throw new Error("Line does not intersect target geometry");
54
+ }
55
+ endPoint = hit;
56
+ }
35
57
  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);
58
+ const end = plane.localToWorld(endPoint);
39
59
  let segment = Geometry.makeSegment(start, end);
40
60
  const edge = Geometry.makeEdge(segment);
41
61
  this.setState('start', Vertex.fromPoint2D(startPoint));
42
62
  this.setState('end', Vertex.fromPoint2D(endPoint));
43
63
  this.addShape(edge);
44
- this.setTangent(direction.normalize());
45
- if (this.sketch)
64
+ // Tangent at end points from start to end (sign-aware when target is behind start)
65
+ const endTangent = endPoint.subtract(startPoint);
66
+ const endLen = Math.hypot(endTangent.x, endTangent.y);
67
+ if (endLen > 1e-12) {
68
+ this.setTangent(new Point2D(endTangent.x / endLen, endTangent.y / endLen));
69
+ }
70
+ else {
71
+ this.setTangent(direction.normalize());
72
+ }
73
+ if (this.sketch) {
46
74
  this.setCurrentPosition(endPoint);
47
- if (this.targetPlane)
75
+ }
76
+ if (this.targetPlane) {
48
77
  this.targetPlane.removeShapes(this);
78
+ }
79
+ }
80
+ getDependencies() {
81
+ const deps = [];
82
+ if (this.targetPlane) {
83
+ deps.push(this.targetPlane);
84
+ }
85
+ if (this.lengthOrTarget instanceof SceneObject) {
86
+ deps.push(this.lengthOrTarget);
87
+ }
88
+ return deps;
49
89
  }
50
90
  createCopy(remap) {
51
91
  const targetPlane = this.targetPlane ? (remap.get(this.targetPlane) || this.targetPlane) : null;
52
- return new AngledLine(this.length, this.angle, this.centered, targetPlane);
92
+ const lengthOrTarget = this.lengthOrTarget instanceof SceneObject
93
+ ? (remap.get(this.lengthOrTarget) || this.lengthOrTarget)
94
+ : this.lengthOrTarget;
95
+ const copy = new AngledLine(this.angle, lengthOrTarget, targetPlane);
96
+ copy.centered(this._centered);
97
+ return copy;
53
98
  }
54
99
  compareTo(other) {
55
100
  if (!(other instanceof AngledLine)) {
@@ -64,7 +109,18 @@ export class AngledLine extends GeometrySceneObject {
64
109
  if (this.targetPlane && other.targetPlane && !this.targetPlane.compareTo(other.targetPlane)) {
65
110
  return false;
66
111
  }
67
- return this.length === other.length && this.angle === other.angle && this.centered === other.centered;
112
+ if (typeof this.lengthOrTarget !== typeof other.lengthOrTarget) {
113
+ return false;
114
+ }
115
+ if (this.lengthOrTarget instanceof SceneObject && other.lengthOrTarget instanceof SceneObject) {
116
+ if (!this.lengthOrTarget.compareTo(other.lengthOrTarget)) {
117
+ return false;
118
+ }
119
+ }
120
+ else if (this.lengthOrTarget !== other.lengthOrTarget) {
121
+ return false;
122
+ }
123
+ return this.angle === other.angle && this._centered === other._centered;
68
124
  }
69
125
  getType() {
70
126
  return 'line';
@@ -74,9 +130,9 @@ export class AngledLine extends GeometrySceneObject {
74
130
  }
75
131
  serialize() {
76
132
  return {
77
- length: this.length,
78
133
  angle: this.angle,
79
- centered: this.centered
134
+ length: typeof this.lengthOrTarget === 'number' ? this.lengthOrTarget : null,
135
+ centered: this._centered
80
136
  };
81
137
  }
82
138
  }
@@ -3,6 +3,7 @@ import { PlaneObjectBase } from "../plane-renderable-base.js";
3
3
  import { GeometrySceneObject } from "./geometry.js";
4
4
  import { LazyVertex } from "../lazy-vertex.js";
5
5
  import { IArcPoints, IArcAngles } from "../../core/interfaces.js";
6
+ import { SceneObject } from "../../common/scene-object.js";
6
7
  export declare class Arc extends GeometrySceneObject implements IArcPoints, IArcAngles {
7
8
  private _startPoint;
8
9
  private _endPoint;
@@ -27,6 +28,8 @@ export declare class Arc extends GeometrySceneObject implements IArcPoints, IArc
27
28
  private buildWithCenter;
28
29
  private buildFromAngles;
29
30
  getType(): string;
31
+ getDependencies(): SceneObject[];
32
+ createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
30
33
  compareTo(other: Arc): boolean;
31
34
  serialize(): Record<string, unknown>;
32
35
  }
@@ -167,7 +167,6 @@ export class Arc extends GeometrySceneObject {
167
167
  const d = Math.sqrt(r * r - (chordLen / 2) * (chordLen / 2));
168
168
  const sign = cw ? -1 : 1;
169
169
  const centerPoint = new Point2D(mx + sign * d * px, my + sign * d * py);
170
- const startAngle = Math.atan2(startPoint.y - centerPoint.y, startPoint.x - centerPoint.x);
171
170
  const endAngle = Math.atan2(targetPoint.y - centerPoint.y, targetPoint.x - centerPoint.x);
172
171
  const normal = cw ? plane.normal.negate() : plane.normal;
173
172
  const center = plane.localToWorld(centerPoint);
@@ -224,6 +223,10 @@ export class Arc extends GeometrySceneObject {
224
223
  const centerPoint = this._targetPlane
225
224
  ? plane.worldToLocal(this._targetPlane.getPlaneCenter())
226
225
  : this.getCurrentPosition();
226
+ // Angles are measured relative to the current tangent (defaults to +X).
227
+ const tangent = (this._targetPlane ? null : this.sketch?.getTangentAt(this))
228
+ ?? new Point2D(1, 0);
229
+ const tangentAngle = Math.atan2(tangent.y, tangent.x);
227
230
  const cw = this._endAngle < 0;
228
231
  const absStartAngle = Math.abs(this._startAngle);
229
232
  const absEndAngle = Math.abs(this._endAngle);
@@ -239,6 +242,8 @@ export class Arc extends GeometrySceneObject {
239
242
  startAngleRad = rad(absStartAngle);
240
243
  endAngleRad = rad(absEndAngle);
241
244
  }
245
+ startAngleRad += tangentAngle;
246
+ endAngleRad += tangentAngle;
242
247
  const normal = cw ? plane.normal.negate() : plane.normal;
243
248
  const startPoint = Geometry.getPointOnCircle(centerPoint, radius, startAngleRad);
244
249
  const endPoint = Geometry.getPointOnCircle(centerPoint, radius, endAngleRad);
@@ -261,6 +266,28 @@ export class Arc extends GeometrySceneObject {
261
266
  getType() {
262
267
  return 'arc';
263
268
  }
269
+ getDependencies() {
270
+ return this._targetPlane ? [this._targetPlane] : [];
271
+ }
272
+ createCopy(remap) {
273
+ const targetPlane = this._targetPlane
274
+ ? (remap.get(this._targetPlane) || this._targetPlane)
275
+ : null;
276
+ let copy;
277
+ if (this._startPoint && this._endPoint) {
278
+ copy = Arc.twoPoints(this._startPoint, this._endPoint, targetPlane);
279
+ }
280
+ else if (this._endPoint) {
281
+ copy = Arc.toPoint(this._endPoint, targetPlane);
282
+ }
283
+ else {
284
+ copy = Arc.fromAngles(this._arcRadius, this._startAngle, this._endAngle, targetPlane);
285
+ }
286
+ copy._bulgeRadius = this._bulgeRadius;
287
+ copy._centerPoint = this._centerPoint;
288
+ copy._centered = this._centered;
289
+ return copy;
290
+ }
264
291
  compareTo(other) {
265
292
  if (!(other instanceof Arc)) {
266
293
  return false;
@@ -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;