fluidcad 0.0.34 → 0.0.36
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.
- package/README.md +69 -0
- package/bin/commands/login.js +148 -0
- package/bin/commands/mcp.js +3 -2
- package/bin/commands/pack.js +49 -0
- package/bin/commands/publish.js +231 -0
- package/bin/fluidcad.js +6 -0
- package/bin/lib/api-client.js +48 -0
- package/bin/lib/browser.js +16 -0
- package/bin/lib/config.js +39 -0
- package/bin/lib/model-config.js +61 -0
- package/bin/lib/prompt.js +97 -0
- package/bin/lib/workspace.js +57 -0
- package/lib/dist/common/shape-factory.d.ts +2 -1
- package/lib/dist/common/shape-factory.js +4 -0
- package/lib/dist/common/transformable-primitive.d.ts +6 -5
- package/lib/dist/common/transformable-primitive.js +8 -7
- package/lib/dist/common/vertex.js +0 -1
- package/lib/dist/core/2d/aline.d.ts +4 -3
- package/lib/dist/core/2d/aline.js +3 -2
- package/lib/dist/core/2d/arc.d.ts +3 -2
- package/lib/dist/core/2d/arc.js +4 -3
- package/lib/dist/core/2d/bezier.d.ts +8 -6
- package/lib/dist/core/2d/circle.d.ts +4 -3
- package/lib/dist/core/2d/circle.js +3 -2
- package/lib/dist/core/2d/ellipse.d.ts +5 -4
- package/lib/dist/core/2d/ellipse.js +5 -4
- package/lib/dist/core/2d/hline.d.ts +4 -3
- package/lib/dist/core/2d/hline.js +5 -3
- package/lib/dist/core/2d/line.js +1 -0
- package/lib/dist/core/2d/offset.d.ts +3 -2
- package/lib/dist/core/2d/offset.js +6 -5
- package/lib/dist/core/2d/polygon.d.ts +5 -4
- package/lib/dist/core/2d/polygon.js +10 -9
- package/lib/dist/core/2d/rect.d.ts +4 -3
- package/lib/dist/core/2d/rect.js +10 -9
- package/lib/dist/core/2d/slot.d.ts +14 -6
- package/lib/dist/core/2d/slot.js +19 -8
- package/lib/dist/core/2d/vline.d.ts +4 -3
- package/lib/dist/core/2d/vline.js +5 -3
- package/lib/dist/core/chamfer.d.ts +5 -4
- package/lib/dist/core/chamfer.js +7 -6
- package/lib/dist/core/color.d.ts +3 -2
- package/lib/dist/core/color.js +2 -1
- package/lib/dist/core/cut.d.ts +4 -3
- package/lib/dist/core/cut.js +5 -4
- package/lib/dist/core/cylinder.d.ts +2 -1
- package/lib/dist/core/cylinder.js +2 -1
- package/lib/dist/core/draft.d.ts +3 -2
- package/lib/dist/core/draft.js +3 -2
- package/lib/dist/core/extrude.d.ts +4 -3
- package/lib/dist/core/extrude.js +5 -4
- package/lib/dist/core/fillet.d.ts +5 -4
- package/lib/dist/core/fillet.js +6 -5
- package/lib/dist/core/index.d.ts +1 -0
- package/lib/dist/core/index.js +1 -0
- package/lib/dist/core/interfaces.d.ts +25 -24
- package/lib/dist/core/param.d.ts +74 -0
- package/lib/dist/core/param.js +147 -0
- package/lib/dist/core/repeat.d.ts +2 -1
- package/lib/dist/core/repeat.js +10 -8
- package/lib/dist/core/revolve.d.ts +2 -1
- package/lib/dist/core/revolve.js +3 -2
- package/lib/dist/core/rib.d.ts +3 -2
- package/lib/dist/core/rib.js +6 -2
- package/lib/dist/core/rotate.d.ts +5 -4
- package/lib/dist/core/rotate.js +4 -3
- package/lib/dist/core/shell.d.ts +3 -2
- package/lib/dist/core/shell.js +3 -2
- package/lib/dist/core/sphere.d.ts +3 -2
- package/lib/dist/core/sphere.js +2 -1
- package/lib/dist/core/translate.d.ts +7 -6
- package/lib/dist/core/translate.js +6 -5
- package/lib/dist/features/2d/arc.js +5 -5
- package/lib/dist/features/2d/bezier.js +16 -16
- package/lib/dist/features/2d/circle.js +4 -0
- package/lib/dist/features/2d/ellipse.js +4 -0
- package/lib/dist/features/2d/hline.d.ts +3 -0
- package/lib/dist/features/2d/hline.js +9 -2
- package/lib/dist/features/2d/line.d.ts +3 -0
- package/lib/dist/features/2d/line.js +11 -3
- package/lib/dist/features/2d/sketch.js +5 -1
- package/lib/dist/features/2d/slot.d.ts +5 -0
- package/lib/dist/features/2d/slot.js +52 -7
- package/lib/dist/features/2d/tarc-to-point-tangent.js +3 -0
- package/lib/dist/features/2d/tarc-to-point.js +3 -0
- package/lib/dist/features/2d/tarc-with-tangent.js +3 -0
- package/lib/dist/features/2d/tarc.js +3 -0
- package/lib/dist/features/2d/vline.d.ts +3 -0
- package/lib/dist/features/2d/vline.js +9 -2
- package/lib/dist/features/copy-circular.d.ts +4 -3
- package/lib/dist/features/copy-circular.js +16 -9
- package/lib/dist/features/copy-circular2d.js +16 -9
- package/lib/dist/features/copy-linear.d.ts +4 -3
- package/lib/dist/features/copy-linear.js +18 -12
- package/lib/dist/features/copy-linear2d.js +18 -12
- package/lib/dist/features/extrude-base.d.ts +4 -3
- package/lib/dist/features/extrude-base.js +10 -3
- package/lib/dist/features/mirror-shape2d.js +2 -2
- package/lib/dist/features/repeat-base.d.ts +13 -0
- package/lib/dist/features/repeat-base.js +21 -0
- package/lib/dist/features/repeat-circular.d.ts +6 -5
- package/lib/dist/features/repeat-circular.js +3 -6
- package/lib/dist/features/repeat-linear.d.ts +7 -7
- package/lib/dist/features/repeat-linear.js +3 -6
- package/lib/dist/index.d.ts +5 -0
- package/lib/dist/index.js +8 -1
- package/lib/dist/io/file-import.d.ts +7 -0
- package/lib/dist/io/file-import.js +30 -10
- package/lib/dist/math/lazy-matrix.d.ts +5 -0
- package/lib/dist/math/lazy-matrix.js +78 -10
- package/lib/dist/oc/boolean-ops.d.ts +2 -2
- package/lib/dist/param-registry.d.ts +34 -0
- package/lib/dist/param-registry.js +60 -0
- package/lib/dist/rendering/mesh-builder.js +2 -1
- package/lib/dist/tests/features/copy-circular.test.js +1 -1
- package/lib/dist/tests/features/copy-linear.test.js +10 -10
- package/lib/dist/tests/features/repeat-user-repro-cache.test.d.ts +1 -0
- package/lib/dist/tests/features/repeat-user-repro-cache.test.js +97 -0
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/llm-docs/api/bezier.md +10 -11
- package/llm-docs/api/index.json +1 -1
- package/llm-docs/api/types/arc-points.md +2 -2
- package/llm-docs/api/types/cut.md +10 -10
- package/llm-docs/api/types/extrude.md +10 -10
- package/llm-docs/api/types/loft.md +6 -6
- package/llm-docs/api/types/revolve.md +6 -6
- package/llm-docs/api/types/rib.md +2 -2
- package/llm-docs/api/types/slot.md +2 -2
- package/llm-docs/api/types/sweep.md +10 -10
- package/llm-docs/api/types/transformable.md +14 -14
- package/llm-docs/index.json +12 -12
- package/mcp/dist/client.d.ts +1 -0
- package/mcp/dist/client.js +8 -1
- package/mcp/dist/server.js +14 -1
- package/mcp/dist/tools/engine.d.ts +16 -0
- package/mcp/dist/tools/engine.js +45 -0
- package/package.json +9 -3
- package/server/dist/api.d.ts +37 -0
- package/server/dist/api.js +44 -0
- package/server/dist/code-editor.d.ts +64 -0
- package/server/dist/code-editor.js +520 -2
- package/server/dist/fluidcad-server.d.ts +87 -1
- package/server/dist/fluidcad-server.js +254 -88
- package/server/dist/host/blocked-imports.d.ts +8 -0
- package/server/dist/host/blocked-imports.js +30 -0
- package/server/dist/{vite-manager.d.ts → host/local-scene-host.d.ts} +3 -1
- package/server/dist/{vite-manager.js → host/local-scene-host.js} +6 -26
- package/server/dist/host/scene-host.d.ts +19 -0
- package/server/dist/host/scene-host.js +1 -0
- package/server/dist/index.js +24 -117
- package/server/dist/model-package/capture-params.d.ts +19 -0
- package/server/dist/model-package/capture-params.js +42 -0
- package/server/dist/model-package/pack.d.ts +23 -0
- package/server/dist/model-package/pack.js +230 -0
- package/server/dist/model-package/types.d.ts +79 -0
- package/server/dist/model-package/types.js +17 -0
- package/server/dist/routes/hit-test.d.ts +3 -0
- package/server/dist/routes/hit-test.js +17 -0
- package/server/dist/routes/pack.d.ts +10 -0
- package/server/dist/routes/pack.js +47 -0
- package/server/dist/routes/params.d.ts +3 -0
- package/server/dist/routes/params.js +75 -0
- package/server/dist/routes/sketch-edits.d.ts +3 -0
- package/server/dist/routes/sketch-edits.js +542 -0
- package/server/dist/routes/timeline.d.ts +3 -0
- package/server/dist/routes/timeline.js +49 -0
- package/server/dist/server-core.d.ts +53 -0
- package/server/dist/server-core.js +147 -0
- package/server/dist/ws-protocol.d.ts +101 -2
- package/ui/dist/assets/index-CDJmUpFI.css +2 -0
- package/ui/dist/assets/index-MRqwG9Vh.js +5417 -0
- package/ui/dist/index.html +2 -2
- package/server/dist/routes/actions.d.ts +0 -3
- package/server/dist/routes/actions.js +0 -309
- package/ui/dist/assets/index-BdqrMDRu.js +0 -4946
- package/ui/dist/assets/index-DR7c2Qk9.css +0 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Point2D } from "../../math/point.js";
|
|
2
2
|
import { Geometry } from "../../oc/geometry.js";
|
|
3
|
+
import { Vertex } from "../../common/vertex.js";
|
|
3
4
|
import { rad } from "../../helpers/math-helpers.js";
|
|
4
5
|
import { ExtrudableGeometryBase } from "./extrudable-base.js";
|
|
5
6
|
export class Slot extends ExtrudableGeometryBase {
|
|
@@ -7,11 +8,19 @@ export class Slot extends ExtrudableGeometryBase {
|
|
|
7
8
|
radius;
|
|
8
9
|
_center = false;
|
|
9
10
|
_angle = 0;
|
|
11
|
+
_startPoint = null;
|
|
12
|
+
_endPoint = null;
|
|
10
13
|
constructor(distance, radius, targetPlane = null) {
|
|
11
14
|
super(targetPlane);
|
|
12
15
|
this.distance = distance;
|
|
13
16
|
this.radius = radius;
|
|
14
17
|
}
|
|
18
|
+
static fromTwoPoints(start, end, radius, targetPlane = null) {
|
|
19
|
+
const slot = new Slot(0, radius, targetPlane);
|
|
20
|
+
slot._startPoint = start;
|
|
21
|
+
slot._endPoint = end;
|
|
22
|
+
return slot;
|
|
23
|
+
}
|
|
15
24
|
centered(value = true) {
|
|
16
25
|
this._center = value;
|
|
17
26
|
return this;
|
|
@@ -21,21 +30,28 @@ export class Slot extends ExtrudableGeometryBase {
|
|
|
21
30
|
return this;
|
|
22
31
|
}
|
|
23
32
|
build() {
|
|
24
|
-
if (this.
|
|
25
|
-
|
|
33
|
+
if (this._startPoint && this._endPoint) {
|
|
34
|
+
const s = this._startPoint.asPoint2D();
|
|
35
|
+
const e = this._endPoint.asPoint2D();
|
|
36
|
+
const dx = e.x - s.x;
|
|
37
|
+
const dy = e.y - s.y;
|
|
38
|
+
this.distance = Math.sqrt(dx * dx + dy * dy);
|
|
39
|
+
this._angle = Math.atan2(dy, dx) * 180 / Math.PI;
|
|
26
40
|
}
|
|
41
|
+
const absDistance = Math.abs(this.distance);
|
|
42
|
+
const flipAngle = this.distance < 0 ? 180 : 0;
|
|
27
43
|
const plane = this.targetPlane?.getPlane() || this.getParent().getPlane();
|
|
28
44
|
const localToWorld = plane.localToWorld.bind(plane);
|
|
29
45
|
let leftCenter = this.targetPlane
|
|
30
46
|
? plane.worldToLocal(this.targetPlane.getPlaneCenter())
|
|
31
47
|
: this.getCurrentPosition();
|
|
32
48
|
if (this._center) {
|
|
33
|
-
const angleRad = rad(this._angle);
|
|
49
|
+
const angleRad = rad(this._angle + flipAngle);
|
|
34
50
|
const cos = Math.cos(angleRad);
|
|
35
51
|
const sin = Math.sin(angleRad);
|
|
36
|
-
leftCenter = leftCenter.translate(-
|
|
52
|
+
leftCenter = leftCenter.translate(-absDistance / 2 * cos, -absDistance / 2 * sin);
|
|
37
53
|
}
|
|
38
|
-
const angleRad = rad(this._angle);
|
|
54
|
+
const angleRad = rad(this._angle + flipAngle);
|
|
39
55
|
const cos = Math.cos(angleRad);
|
|
40
56
|
const sin = Math.sin(angleRad);
|
|
41
57
|
// Direction along the slot axis
|
|
@@ -44,7 +60,7 @@ export class Slot extends ExtrudableGeometryBase {
|
|
|
44
60
|
// Perpendicular direction (90 degrees CCW)
|
|
45
61
|
const perpX = -sin;
|
|
46
62
|
const perpY = cos;
|
|
47
|
-
const rightCenter = new Point2D(leftCenter.x +
|
|
63
|
+
const rightCenter = new Point2D(leftCenter.x + absDistance * dirX, leftCenter.y + absDistance * dirY);
|
|
48
64
|
// Four key points where lines meet arcs
|
|
49
65
|
const topLeft = new Point2D(leftCenter.x + this.radius * perpX, leftCenter.y + this.radius * perpY);
|
|
50
66
|
const topRight = new Point2D(rightCenter.x + this.radius * perpX, rightCenter.y + this.radius * perpY);
|
|
@@ -65,6 +81,12 @@ export class Slot extends ExtrudableGeometryBase {
|
|
|
65
81
|
Geometry.makeEdgeFromCurve(leftArc),
|
|
66
82
|
];
|
|
67
83
|
this.addShapes(edges);
|
|
84
|
+
const leftCenterVertex = Vertex.fromPoint2D(leftCenter);
|
|
85
|
+
leftCenterVertex.markAsMetaShape();
|
|
86
|
+
this.addShape(leftCenterVertex);
|
|
87
|
+
const rightCenterVertex = Vertex.fromPoint2D(rightCenter);
|
|
88
|
+
rightCenterVertex.markAsMetaShape();
|
|
89
|
+
this.addShape(rightCenterVertex);
|
|
68
90
|
if (this.sketch) {
|
|
69
91
|
if (this._center) {
|
|
70
92
|
this.setCurrentPosition(this.getCurrentPosition());
|
|
@@ -85,7 +107,13 @@ export class Slot extends ExtrudableGeometryBase {
|
|
|
85
107
|
}
|
|
86
108
|
createCopy(remap) {
|
|
87
109
|
const targetPlane = this.targetPlane ? (remap.get(this.targetPlane) || this.targetPlane) : null;
|
|
88
|
-
|
|
110
|
+
let s;
|
|
111
|
+
if (this._startPoint && this._endPoint) {
|
|
112
|
+
s = Slot.fromTwoPoints(this._startPoint, this._endPoint, this.radius, targetPlane);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
s = new Slot(this.distance, this.radius, targetPlane);
|
|
116
|
+
}
|
|
89
117
|
s.centered(this._center);
|
|
90
118
|
s.rotate(this._angle);
|
|
91
119
|
return s;
|
|
@@ -103,6 +131,22 @@ export class Slot extends ExtrudableGeometryBase {
|
|
|
103
131
|
if (this.targetPlane && other.targetPlane && !this.targetPlane.compareTo(other.targetPlane)) {
|
|
104
132
|
return false;
|
|
105
133
|
}
|
|
134
|
+
if ((this._startPoint === null) !== (other._startPoint === null)) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
if ((this._endPoint === null) !== (other._endPoint === null)) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
if (this._startPoint && other._startPoint && !this._startPoint.compareTo(other._startPoint)) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
if (this._endPoint && other._endPoint && !this._endPoint.compareTo(other._endPoint)) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if (this._startPoint && this._endPoint) {
|
|
147
|
+
return this.radius === other.radius &&
|
|
148
|
+
this._center === other._center;
|
|
149
|
+
}
|
|
106
150
|
return this.distance === other.distance &&
|
|
107
151
|
this.radius === other.radius &&
|
|
108
152
|
this._center === other._center &&
|
|
@@ -114,6 +158,7 @@ export class Slot extends ExtrudableGeometryBase {
|
|
|
114
158
|
radius: this.radius,
|
|
115
159
|
centered: this._center,
|
|
116
160
|
angle: this._angle,
|
|
161
|
+
hasTwoPoints: this._startPoint !== null && this._endPoint !== null,
|
|
117
162
|
};
|
|
118
163
|
}
|
|
119
164
|
}
|
|
@@ -60,6 +60,9 @@ export class TangentArcToPointTangent extends GeometrySceneObject {
|
|
|
60
60
|
this.setState('start', Vertex.fromPoint2D(startPoint));
|
|
61
61
|
this.setState('end', Vertex.fromPoint2D(targetPoint));
|
|
62
62
|
this.addShape(edge);
|
|
63
|
+
const centerVertex = Vertex.fromPoint2D(centerPoint);
|
|
64
|
+
centerVertex.markAsMetaShape();
|
|
65
|
+
this.addShape(centerVertex);
|
|
63
66
|
this.setCurrentPosition(targetPoint);
|
|
64
67
|
}
|
|
65
68
|
createCopy(remap) {
|
|
@@ -58,6 +58,9 @@ export class TangentArcToPoint extends GeometrySceneObject {
|
|
|
58
58
|
this.setState('start', Vertex.fromPoint2D(startPoint));
|
|
59
59
|
this.setState('end', Vertex.fromPoint2D(targetPoint));
|
|
60
60
|
this.addShape(edge);
|
|
61
|
+
const centerVertex = Vertex.fromPoint2D(centerPoint);
|
|
62
|
+
centerVertex.markAsMetaShape();
|
|
63
|
+
this.addShape(centerVertex);
|
|
61
64
|
this.setCurrentPosition(targetPoint);
|
|
62
65
|
}
|
|
63
66
|
createCopy(remap) {
|
|
@@ -44,6 +44,9 @@ export class TangentArcWithTangent extends GeometrySceneObject {
|
|
|
44
44
|
const ty = sign * Math.cos(endAngleRad);
|
|
45
45
|
this.setTangent(new Point2D(tx, ty));
|
|
46
46
|
this.addShape(edge);
|
|
47
|
+
const centerVertex = Vertex.fromPoint2D(centerPoint);
|
|
48
|
+
centerVertex.markAsMetaShape();
|
|
49
|
+
this.addShape(centerVertex);
|
|
47
50
|
this.setCurrentPosition(endPoint);
|
|
48
51
|
}
|
|
49
52
|
createCopy(remap) {
|
|
@@ -46,6 +46,9 @@ export class TangentArc extends GeometrySceneObject {
|
|
|
46
46
|
const ty = sign * Math.cos(endAngleRad);
|
|
47
47
|
this.setTangent(new Point2D(tx, ty));
|
|
48
48
|
this.addShape(edge);
|
|
49
|
+
const centerVertex = Vertex.fromPoint2D(centerPoint);
|
|
50
|
+
centerVertex.markAsMetaShape();
|
|
51
|
+
this.addShape(centerVertex);
|
|
49
52
|
this.setCurrentPosition(endPoint);
|
|
50
53
|
}
|
|
51
54
|
createCopy(remap) {
|
|
@@ -6,8 +6,10 @@ export declare class VerticalLine extends GeometrySceneObject implements IVLine
|
|
|
6
6
|
distanceOrTarget: number | SceneObject;
|
|
7
7
|
private targetPlane;
|
|
8
8
|
private _centered;
|
|
9
|
+
private _hasExplicitStart;
|
|
9
10
|
constructor(distanceOrTarget: number | SceneObject, targetPlane?: PlaneObjectBase);
|
|
10
11
|
centered(value?: boolean): this;
|
|
12
|
+
setHasExplicitStart(value?: boolean): this;
|
|
11
13
|
build(): void;
|
|
12
14
|
getDependencies(): SceneObject[];
|
|
13
15
|
createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
|
|
@@ -17,5 +19,6 @@ export declare class VerticalLine extends GeometrySceneObject implements IVLine
|
|
|
17
19
|
serialize(): {
|
|
18
20
|
distance: number;
|
|
19
21
|
centered: boolean;
|
|
22
|
+
hasExplicitStart: boolean;
|
|
20
23
|
};
|
|
21
24
|
}
|
|
@@ -8,6 +8,7 @@ export class VerticalLine extends GeometrySceneObject {
|
|
|
8
8
|
distanceOrTarget;
|
|
9
9
|
targetPlane;
|
|
10
10
|
_centered = false;
|
|
11
|
+
_hasExplicitStart = false;
|
|
11
12
|
constructor(distanceOrTarget, targetPlane = null) {
|
|
12
13
|
super();
|
|
13
14
|
this.distanceOrTarget = distanceOrTarget;
|
|
@@ -17,6 +18,10 @@ export class VerticalLine extends GeometrySceneObject {
|
|
|
17
18
|
this._centered = value;
|
|
18
19
|
return this;
|
|
19
20
|
}
|
|
21
|
+
setHasExplicitStart(value = true) {
|
|
22
|
+
this._hasExplicitStart = value;
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
20
25
|
build() {
|
|
21
26
|
const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
|
|
22
27
|
const currentPos = this.targetPlane
|
|
@@ -78,6 +83,7 @@ export class VerticalLine extends GeometrySceneObject {
|
|
|
78
83
|
: this.distanceOrTarget;
|
|
79
84
|
const copy = new VerticalLine(distanceOrTarget, targetPlane);
|
|
80
85
|
copy.centered(this._centered);
|
|
86
|
+
copy._hasExplicitStart = this._hasExplicitStart;
|
|
81
87
|
return copy;
|
|
82
88
|
}
|
|
83
89
|
compareTo(other) {
|
|
@@ -104,7 +110,7 @@ export class VerticalLine extends GeometrySceneObject {
|
|
|
104
110
|
else if (this.distanceOrTarget !== other.distanceOrTarget) {
|
|
105
111
|
return false;
|
|
106
112
|
}
|
|
107
|
-
return this._centered === other._centered;
|
|
113
|
+
return this._centered === other._centered && this._hasExplicitStart === other._hasExplicitStart;
|
|
108
114
|
}
|
|
109
115
|
getType() {
|
|
110
116
|
return 'line';
|
|
@@ -115,7 +121,8 @@ export class VerticalLine extends GeometrySceneObject {
|
|
|
115
121
|
serialize() {
|
|
116
122
|
return {
|
|
117
123
|
distance: typeof this.distanceOrTarget === 'number' ? this.distanceOrTarget : null,
|
|
118
|
-
centered: this._centered
|
|
124
|
+
centered: this._centered,
|
|
125
|
+
hasExplicitStart: this._hasExplicitStart,
|
|
119
126
|
};
|
|
120
127
|
}
|
|
121
128
|
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { BuildSceneObjectContext, SceneObject } from "../common/scene-object.js";
|
|
2
2
|
import { Axis } from "../math/axis.js";
|
|
3
|
+
import { type NumberParam } from "../core/param.js";
|
|
3
4
|
export type CircularCopyOptions = {
|
|
4
|
-
count:
|
|
5
|
+
count: NumberParam;
|
|
5
6
|
centered?: boolean;
|
|
6
7
|
skip?: number[];
|
|
7
8
|
} & ({
|
|
8
|
-
offset:
|
|
9
|
+
offset: NumberParam;
|
|
9
10
|
angle?: never;
|
|
10
11
|
} | {
|
|
11
|
-
angle:
|
|
12
|
+
angle: NumberParam;
|
|
12
13
|
offset?: never;
|
|
13
14
|
});
|
|
14
15
|
export declare class CopyCircular extends SceneObject {
|
|
@@ -2,6 +2,7 @@ import { SceneObject } from "../common/scene-object.js";
|
|
|
2
2
|
import { Matrix4 } from "../math/matrix4.js";
|
|
3
3
|
import { rad } from "../helpers/math-helpers.js";
|
|
4
4
|
import { ShapeOps } from "../oc/shape-ops.js";
|
|
5
|
+
import { resolveParam } from "../core/param.js";
|
|
5
6
|
export class CopyCircular extends SceneObject {
|
|
6
7
|
axis;
|
|
7
8
|
options;
|
|
@@ -17,13 +18,21 @@ export class CopyCircular extends SceneObject {
|
|
|
17
18
|
if (!this.targetObjects) {
|
|
18
19
|
objects = context.getActiveSceneObjects();
|
|
19
20
|
}
|
|
20
|
-
const
|
|
21
|
+
const originalShapes = objects.flatMap(obj => obj.getShapes());
|
|
22
|
+
for (const obj of objects) {
|
|
23
|
+
obj.removeShapes(this);
|
|
24
|
+
}
|
|
25
|
+
for (const shape of originalShapes) {
|
|
26
|
+
this.addShape(shape);
|
|
27
|
+
}
|
|
28
|
+
const count = resolveParam(this.options.count);
|
|
29
|
+
const { centered, skip } = this.options;
|
|
21
30
|
let offset;
|
|
22
31
|
if ('offset' in this.options && this.options.offset !== undefined) {
|
|
23
|
-
offset = this.options.offset;
|
|
32
|
+
offset = resolveParam(this.options.offset);
|
|
24
33
|
}
|
|
25
34
|
else {
|
|
26
|
-
offset = this.options.angle / count;
|
|
35
|
+
offset = resolveParam(this.options.angle) / count;
|
|
27
36
|
}
|
|
28
37
|
const startOffset = centered ? -(count * offset) / 2 : 0;
|
|
29
38
|
for (let i = 1; i < count; i++) {
|
|
@@ -31,12 +40,10 @@ export class CopyCircular extends SceneObject {
|
|
|
31
40
|
continue;
|
|
32
41
|
const angle = startOffset + offset * i;
|
|
33
42
|
const matrix = Matrix4.fromRotationAroundAxis(this.axis.origin, this.axis.direction, rad(angle));
|
|
34
|
-
for (const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
this.addShape(transformed);
|
|
39
|
-
}
|
|
43
|
+
for (const shape of originalShapes) {
|
|
44
|
+
const transformed = ShapeOps.transform(shape, matrix);
|
|
45
|
+
transformed.setMeshSource(shape, matrix);
|
|
46
|
+
this.addShape(transformed);
|
|
40
47
|
}
|
|
41
48
|
}
|
|
42
49
|
}
|
|
@@ -2,6 +2,7 @@ import { Matrix4 } from "../math/matrix4.js";
|
|
|
2
2
|
import { rad } from "../helpers/math-helpers.js";
|
|
3
3
|
import { ShapeOps } from "../oc/shape-ops.js";
|
|
4
4
|
import { GeometrySceneObject } from "./2d/geometry.js";
|
|
5
|
+
import { resolveParam } from "../core/param.js";
|
|
5
6
|
export class CopyCircular2D extends GeometrySceneObject {
|
|
6
7
|
center;
|
|
7
8
|
options;
|
|
@@ -21,16 +22,24 @@ export class CopyCircular2D extends GeometrySceneObject {
|
|
|
21
22
|
else {
|
|
22
23
|
objects = allSiblings;
|
|
23
24
|
}
|
|
25
|
+
const originalShapes = objects.flatMap(obj => obj.getShapes());
|
|
26
|
+
for (const obj of objects) {
|
|
27
|
+
obj.removeShapes(this);
|
|
28
|
+
}
|
|
29
|
+
for (const shape of originalShapes) {
|
|
30
|
+
this.addShape(shape);
|
|
31
|
+
}
|
|
24
32
|
const plane = this.sketch.getPlane();
|
|
25
33
|
const origin = plane.localToWorld(this.center.asPoint2D());
|
|
26
34
|
const direction = plane.normal;
|
|
27
|
-
const
|
|
35
|
+
const count = resolveParam(this.options.count);
|
|
36
|
+
const { centered, skip } = this.options;
|
|
28
37
|
let offset;
|
|
29
38
|
if ('offset' in this.options && this.options.offset !== undefined) {
|
|
30
|
-
offset = this.options.offset;
|
|
39
|
+
offset = resolveParam(this.options.offset);
|
|
31
40
|
}
|
|
32
41
|
else {
|
|
33
|
-
offset = this.options.angle / count;
|
|
42
|
+
offset = resolveParam(this.options.angle) / count;
|
|
34
43
|
}
|
|
35
44
|
const startOffset = centered ? -(count * offset) / 2 : 0;
|
|
36
45
|
for (let i = 1; i < count; i++) {
|
|
@@ -38,12 +47,10 @@ export class CopyCircular2D extends GeometrySceneObject {
|
|
|
38
47
|
continue;
|
|
39
48
|
const angle = startOffset + offset * i;
|
|
40
49
|
const matrix = Matrix4.fromRotationAroundAxis(origin, direction, rad(angle));
|
|
41
|
-
for (const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.addShape(transformed);
|
|
46
|
-
}
|
|
50
|
+
for (const shape of originalShapes) {
|
|
51
|
+
const transformed = ShapeOps.transform(shape, matrix);
|
|
52
|
+
transformed.setMeshSource(shape, matrix);
|
|
53
|
+
this.addShape(transformed);
|
|
47
54
|
}
|
|
48
55
|
}
|
|
49
56
|
this.setCurrentPosition(this.center.asPoint2D());
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { BuildSceneObjectContext, SceneObject } from "../common/scene-object.js";
|
|
2
2
|
import { Axis } from "../math/axis.js";
|
|
3
|
+
import { type NumberParam } from "../core/param.js";
|
|
3
4
|
export type LinearCopyOptions = {
|
|
4
|
-
count:
|
|
5
|
+
count: NumberParam | number[];
|
|
5
6
|
centered?: boolean;
|
|
6
7
|
skip?: number[][];
|
|
7
8
|
} & ({
|
|
8
|
-
offset:
|
|
9
|
+
offset: NumberParam | number[];
|
|
9
10
|
length?: never;
|
|
10
11
|
} | {
|
|
11
|
-
length:
|
|
12
|
+
length: NumberParam | number[];
|
|
12
13
|
offset?: never;
|
|
13
14
|
});
|
|
14
15
|
export declare class CopyLinear extends SceneObject {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SceneObject } from "../common/scene-object.js";
|
|
2
2
|
import { Matrix4 } from "../math/matrix4.js";
|
|
3
3
|
import { ShapeOps } from "../oc/shape-ops.js";
|
|
4
|
+
import { resolveParam } from "../core/param.js";
|
|
4
5
|
export class CopyLinear extends SceneObject {
|
|
5
6
|
axes;
|
|
6
7
|
options;
|
|
@@ -16,15 +17,22 @@ export class CopyLinear extends SceneObject {
|
|
|
16
17
|
if (!this.targetObjects) {
|
|
17
18
|
objects = context.getActiveSceneObjects();
|
|
18
19
|
}
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
const originalShapes = objects.flatMap(obj => obj.getShapes());
|
|
21
|
+
for (const obj of objects) {
|
|
22
|
+
obj.removeShapes(this);
|
|
23
|
+
}
|
|
24
|
+
for (const shape of originalShapes) {
|
|
25
|
+
this.addShape(shape);
|
|
26
|
+
}
|
|
27
|
+
const { centered, skip } = this.options;
|
|
28
|
+
const counts = Array.isArray(this.options.count)
|
|
29
|
+
? this.options.count
|
|
30
|
+
: this.axes.map(() => resolveParam(this.options.count));
|
|
23
31
|
const offsets = 'offset' in this.options && this.options.offset !== undefined
|
|
24
|
-
? (Array.isArray(this.options.offset) ? this.options.offset : this.axes.map(() => this.options.offset))
|
|
32
|
+
? (Array.isArray(this.options.offset) ? this.options.offset : this.axes.map(() => resolveParam(this.options.offset)))
|
|
25
33
|
: null;
|
|
26
34
|
const lengths = 'length' in this.options && this.options.length !== undefined
|
|
27
|
-
? (Array.isArray(this.options.length) ? this.options.length : this.axes.map(() => this.options.length))
|
|
35
|
+
? (Array.isArray(this.options.length) ? this.options.length : this.axes.map(() => resolveParam(this.options.length)))
|
|
28
36
|
: null;
|
|
29
37
|
const axisOffsets = this.axes.map((_, a) => {
|
|
30
38
|
if (offsets) {
|
|
@@ -58,12 +66,10 @@ export class CopyLinear extends SceneObject {
|
|
|
58
66
|
const translation = this.axes[a].direction.multiply(distance);
|
|
59
67
|
matrix = matrix.multiply(Matrix4.fromTranslationVector(translation));
|
|
60
68
|
}
|
|
61
|
-
for (const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
this.addShape(transformed);
|
|
66
|
-
}
|
|
69
|
+
for (const shape of originalShapes) {
|
|
70
|
+
const transformed = ShapeOps.transform(shape, matrix);
|
|
71
|
+
transformed.setMeshSource(shape, matrix);
|
|
72
|
+
this.addShape(transformed);
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
}
|
|
@@ -2,6 +2,7 @@ import { Matrix4 } from "../math/matrix4.js";
|
|
|
2
2
|
import { ShapeOps } from "../oc/shape-ops.js";
|
|
3
3
|
import { GeometrySceneObject } from "./2d/geometry.js";
|
|
4
4
|
import { AxisObjectBase } from "./axis-renderable-base.js";
|
|
5
|
+
import { resolveParam } from "../core/param.js";
|
|
5
6
|
export class CopyLinear2D extends GeometrySceneObject {
|
|
6
7
|
axes;
|
|
7
8
|
options;
|
|
@@ -21,16 +22,23 @@ export class CopyLinear2D extends GeometrySceneObject {
|
|
|
21
22
|
else {
|
|
22
23
|
objects = allSiblings;
|
|
23
24
|
}
|
|
25
|
+
const originalShapes = objects.flatMap(obj => obj.getShapes());
|
|
26
|
+
for (const obj of objects) {
|
|
27
|
+
obj.removeShapes(this);
|
|
28
|
+
}
|
|
29
|
+
for (const shape of originalShapes) {
|
|
30
|
+
this.addShape(shape);
|
|
31
|
+
}
|
|
24
32
|
const resolvedAxes = this.axes.map(a => a instanceof AxisObjectBase ? a.getAxis() : a);
|
|
25
|
-
const {
|
|
26
|
-
const counts = Array.isArray(count)
|
|
27
|
-
? count
|
|
28
|
-
: resolvedAxes.map(() => count);
|
|
33
|
+
const { centered, skip } = this.options;
|
|
34
|
+
const counts = Array.isArray(this.options.count)
|
|
35
|
+
? this.options.count
|
|
36
|
+
: resolvedAxes.map(() => resolveParam(this.options.count));
|
|
29
37
|
const offsets = 'offset' in this.options && this.options.offset !== undefined
|
|
30
|
-
? (Array.isArray(this.options.offset) ? this.options.offset : resolvedAxes.map(() => this.options.offset))
|
|
38
|
+
? (Array.isArray(this.options.offset) ? this.options.offset : resolvedAxes.map(() => resolveParam(this.options.offset)))
|
|
31
39
|
: null;
|
|
32
40
|
const lengths = 'length' in this.options && this.options.length !== undefined
|
|
33
|
-
? (Array.isArray(this.options.length) ? this.options.length : resolvedAxes.map(() => this.options.length))
|
|
41
|
+
? (Array.isArray(this.options.length) ? this.options.length : resolvedAxes.map(() => resolveParam(this.options.length)))
|
|
34
42
|
: null;
|
|
35
43
|
const axisOffsets = resolvedAxes.map((_, a) => {
|
|
36
44
|
if (offsets) {
|
|
@@ -64,12 +72,10 @@ export class CopyLinear2D extends GeometrySceneObject {
|
|
|
64
72
|
const translation = resolvedAxes[a].direction.multiply(distance);
|
|
65
73
|
matrix = matrix.multiply(Matrix4.fromTranslationVector(translation));
|
|
66
74
|
}
|
|
67
|
-
for (const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
this.addShape(transformed);
|
|
72
|
-
}
|
|
75
|
+
for (const shape of originalShapes) {
|
|
76
|
+
const transformed = ShapeOps.transform(shape, matrix);
|
|
77
|
+
transformed.setMeshSource(shape, matrix);
|
|
78
|
+
this.addShape(transformed);
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
81
|
}
|
|
@@ -9,6 +9,7 @@ import { Point2DLike } from "../math/point.js";
|
|
|
9
9
|
import { Plane } from "../math/plane.js";
|
|
10
10
|
import { FaceFilterBuilder } from "../filters/face/face-filter.js";
|
|
11
11
|
import { EdgeFilterBuilder } from "../filters/edge/edge-filter.js";
|
|
12
|
+
import { type NumberParam } from "../core/param.js";
|
|
12
13
|
import { ShapeHistory } from "../common/shape-history-tracker.js";
|
|
13
14
|
/** A 3D op's classified face buckets. Each is empty if the op doesn't produce that category. */
|
|
14
15
|
export type ClassifiedFaces = {
|
|
@@ -105,10 +106,10 @@ export declare abstract class ExtrudeBase extends SceneObject implements IExtrud
|
|
|
105
106
|
private buildSuffix;
|
|
106
107
|
private resolveFaces;
|
|
107
108
|
private resolveEdges;
|
|
108
|
-
draft(value:
|
|
109
|
-
endOffset(value:
|
|
109
|
+
draft(value: NumberParam | [NumberParam, NumberParam]): this;
|
|
110
|
+
endOffset(value: NumberParam): this;
|
|
110
111
|
drill(value?: boolean): this;
|
|
111
|
-
thin(offset1:
|
|
112
|
+
thin(offset1: NumberParam, offset2?: NumberParam): this;
|
|
112
113
|
isThin(): boolean;
|
|
113
114
|
getThinOffsets(): [number] | [number, number] | undefined;
|
|
114
115
|
protected serializePickFields(): {
|
|
@@ -11,6 +11,7 @@ import { EdgeFilterBuilder } from "../filters/edge/edge-filter.js";
|
|
|
11
11
|
import { ShapeFilter } from "../filters/filter.js";
|
|
12
12
|
import { EdgeOps } from "../oc/edge-ops.js";
|
|
13
13
|
import { Explorer } from "../oc/explorer.js";
|
|
14
|
+
import { resolveParam } from "../core/param.js";
|
|
14
15
|
import { getOC } from "../oc/init.js";
|
|
15
16
|
import { ShapeHistoryTracker } from "../common/shape-history-tracker.js";
|
|
16
17
|
import { fuseWithSceneObjects } from "../helpers/scene-helpers.js";
|
|
@@ -398,11 +399,16 @@ export class ExtrudeBase extends SceneObject {
|
|
|
398
399
|
return new ShapeFilter(shapes, ...filters).apply();
|
|
399
400
|
}
|
|
400
401
|
draft(value) {
|
|
401
|
-
|
|
402
|
+
if (Array.isArray(value)) {
|
|
403
|
+
this._draft = [resolveParam(value[0]), resolveParam(value[1])];
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
this._draft = resolveParam(value);
|
|
407
|
+
}
|
|
402
408
|
return this;
|
|
403
409
|
}
|
|
404
410
|
endOffset(value) {
|
|
405
|
-
this._endOffset = value;
|
|
411
|
+
this._endOffset = resolveParam(value);
|
|
406
412
|
return this;
|
|
407
413
|
}
|
|
408
414
|
drill(value = true) {
|
|
@@ -410,7 +416,8 @@ export class ExtrudeBase extends SceneObject {
|
|
|
410
416
|
return this;
|
|
411
417
|
}
|
|
412
418
|
thin(offset1, offset2) {
|
|
413
|
-
|
|
419
|
+
const o1 = resolveParam(offset1);
|
|
420
|
+
this._thin = offset2 !== undefined ? [o1, resolveParam(offset2)] : [o1];
|
|
414
421
|
return this;
|
|
415
422
|
}
|
|
416
423
|
isThin() {
|
|
@@ -44,8 +44,8 @@ export class MirrorShape2D extends GeometrySceneObject {
|
|
|
44
44
|
transformedShapes.push(transformed);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
const firstShape = transformedShapes
|
|
48
|
-
const lastShape = transformedShapes
|
|
47
|
+
const firstShape = transformedShapes.find(shape => !shape.isMetaShape() && !shape.isGuideShape());
|
|
48
|
+
const lastShape = transformedShapes.toReversed().find(shape => !shape.isMetaShape() && !shape.isGuideShape());
|
|
49
49
|
if (firstShape) {
|
|
50
50
|
const start = firstShape.getFirstVertex();
|
|
51
51
|
if (start) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SceneObject } from "../common/scene-object.js";
|
|
2
|
+
import { Axis } from "../math/axis.js";
|
|
3
|
+
import { AxisObjectBase } from "./axis-renderable-base.js";
|
|
4
|
+
export type RepeatAxisSource = Axis | AxisObjectBase;
|
|
5
|
+
/**
|
|
6
|
+
* Shared base for repeat features. Holds structural equality helpers used
|
|
7
|
+
* by `compareTo`, which runs during cache-compare — before any render —
|
|
8
|
+
* when an `AxisObjectBase` source may not yet have its resolved `Axis`
|
|
9
|
+
* state. Comparing via `getAxis()` at that point would NPE.
|
|
10
|
+
*/
|
|
11
|
+
export declare abstract class RepeatBase extends SceneObject {
|
|
12
|
+
protected static axisSourceEquals(a: RepeatAxisSource, b: RepeatAxisSource): boolean;
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SceneObject } from "../common/scene-object.js";
|
|
2
|
+
import { AxisObjectBase } from "./axis-renderable-base.js";
|
|
3
|
+
/**
|
|
4
|
+
* Shared base for repeat features. Holds structural equality helpers used
|
|
5
|
+
* by `compareTo`, which runs during cache-compare — before any render —
|
|
6
|
+
* when an `AxisObjectBase` source may not yet have its resolved `Axis`
|
|
7
|
+
* state. Comparing via `getAxis()` at that point would NPE.
|
|
8
|
+
*/
|
|
9
|
+
export class RepeatBase extends SceneObject {
|
|
10
|
+
static axisSourceEquals(a, b) {
|
|
11
|
+
const aObj = a instanceof AxisObjectBase;
|
|
12
|
+
const bObj = b instanceof AxisObjectBase;
|
|
13
|
+
if (aObj !== bObj) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
if (aObj) {
|
|
17
|
+
return a.compareTo(b);
|
|
18
|
+
}
|
|
19
|
+
return a.equals(b);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { BuildSceneObjectContext, SceneObject } from "../common/scene-object.js";
|
|
2
|
-
import { RepeatAxisSource } from "./repeat-
|
|
2
|
+
import { RepeatBase, RepeatAxisSource } from "./repeat-base.js";
|
|
3
|
+
import { type NumberParam } from "../core/param.js";
|
|
3
4
|
export type CircularRepeatOptions = {
|
|
4
|
-
count:
|
|
5
|
+
count: NumberParam;
|
|
5
6
|
centered?: boolean;
|
|
6
7
|
skip?: number[];
|
|
7
8
|
} & ({
|
|
8
|
-
offset:
|
|
9
|
+
offset: NumberParam;
|
|
9
10
|
angle?: never;
|
|
10
11
|
} | {
|
|
11
|
-
angle:
|
|
12
|
+
angle: NumberParam;
|
|
12
13
|
offset?: never;
|
|
13
14
|
});
|
|
14
|
-
export declare class RepeatCircular extends
|
|
15
|
+
export declare class RepeatCircular extends RepeatBase {
|
|
15
16
|
axis: RepeatAxisSource;
|
|
16
17
|
options: CircularRepeatOptions;
|
|
17
18
|
targetObjects: SceneObject[] | null;
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { SceneObject } from "../common/scene-object.js";
|
|
2
1
|
import { AxisObjectBase } from "./axis-renderable-base.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
export class RepeatCircular extends SceneObject {
|
|
2
|
+
import { RepeatBase } from "./repeat-base.js";
|
|
3
|
+
export class RepeatCircular extends RepeatBase {
|
|
7
4
|
axis;
|
|
8
5
|
options;
|
|
9
6
|
targetObjects;
|
|
@@ -30,7 +27,7 @@ export class RepeatCircular extends SceneObject {
|
|
|
30
27
|
if (!super.compareTo(other)) {
|
|
31
28
|
return false;
|
|
32
29
|
}
|
|
33
|
-
if (!
|
|
30
|
+
if (!RepeatCircular.axisSourceEquals(this.axis, other.axis)) {
|
|
34
31
|
return false;
|
|
35
32
|
}
|
|
36
33
|
const thisTargetObjects = this.targetObjects || [];
|