fluidcad 0.0.34 → 0.0.35
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 +120 -0
- package/bin/commands/pack.js +49 -0
- package/bin/commands/publish.js +136 -0
- package/bin/fluidcad.js +6 -0
- package/bin/lib/api-client.js +40 -0
- package/bin/lib/browser.js +16 -0
- package/bin/lib/config.js +39 -0
- package/bin/lib/model-config.js +38 -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 +68 -1
- package/server/dist/fluidcad-server.js +224 -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 +229 -0
- package/server/dist/model-package/types.d.ts +78 -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
|
@@ -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 || [];
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { BuildSceneObjectContext, SceneObject } from "../common/scene-object.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { RepeatBase, RepeatAxisSource } from "./repeat-base.js";
|
|
3
|
+
export { RepeatAxisSource } from "./repeat-base.js";
|
|
4
|
+
import { type NumberParam } from "../core/param.js";
|
|
5
5
|
export type LinearRepeatOptions = {
|
|
6
|
-
count:
|
|
6
|
+
count: NumberParam | number[];
|
|
7
7
|
centered?: boolean;
|
|
8
8
|
skip?: number[][];
|
|
9
9
|
} & ({
|
|
10
|
-
offset:
|
|
10
|
+
offset: NumberParam | number[];
|
|
11
11
|
length?: never;
|
|
12
12
|
} | {
|
|
13
|
-
length:
|
|
13
|
+
length: NumberParam | number[];
|
|
14
14
|
offset?: never;
|
|
15
15
|
});
|
|
16
|
-
export declare class RepeatLinear extends
|
|
16
|
+
export declare class RepeatLinear extends RepeatBase {
|
|
17
17
|
axes: RepeatAxisSource[];
|
|
18
18
|
options: LinearRepeatOptions;
|
|
19
19
|
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 RepeatLinear extends SceneObject {
|
|
2
|
+
import { RepeatBase } from "./repeat-base.js";
|
|
3
|
+
export class RepeatLinear extends RepeatBase {
|
|
7
4
|
axes;
|
|
8
5
|
options;
|
|
9
6
|
targetObjects;
|
|
@@ -36,7 +33,7 @@ export class RepeatLinear extends SceneObject {
|
|
|
36
33
|
return false;
|
|
37
34
|
}
|
|
38
35
|
for (let i = 0; i < this.axes.length; i++) {
|
|
39
|
-
if (!
|
|
36
|
+
if (!RepeatLinear.axisSourceEquals(this.axes[i], other.axes[i])) {
|
|
40
37
|
return false;
|
|
41
38
|
}
|
|
42
39
|
}
|
package/lib/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,11 @@ export type SceneParserContext = {
|
|
|
17
17
|
getActiveSketch(): Sketch | null;
|
|
18
18
|
};
|
|
19
19
|
export declare function registerBuilder<T extends Function>(builder: (context: SceneParserContext) => T): T;
|
|
20
|
+
export { createParamRegistry, getParamRegistry } from './param-registry.js';
|
|
21
|
+
export type { ParamDefinition, MultiControlType, SelectOption, ParamVal, ParamScalar } from './param-registry.js';
|
|
22
|
+
export { setAssetProvider } from './io/file-import.js';
|
|
23
|
+
export type { AssetProvider } from './io/file-import.js';
|
|
24
|
+
export { getSceneManager } from './scene-manager.js';
|
|
20
25
|
export interface FluidCADOptions {
|
|
21
26
|
mesh?: {
|
|
22
27
|
lineDeflection?: number;
|
package/lib/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { loadOC } from "./load.js";
|
|
2
|
-
import { createManager, getCurrentScene } from "./scene-manager.js";
|
|
2
|
+
import { createManager, getCurrentScene, getSceneManager } from "./scene-manager.js";
|
|
3
3
|
import { parse as parseStackTrace } from "stacktrace-parser";
|
|
4
4
|
export function captureSourceLocation() {
|
|
5
5
|
const stack = new Error().stack;
|
|
@@ -88,8 +88,15 @@ export function registerBuilder(builder) {
|
|
|
88
88
|
return fn;
|
|
89
89
|
;
|
|
90
90
|
}
|
|
91
|
+
export { createParamRegistry, getParamRegistry } from './param-registry.js';
|
|
92
|
+
export { setAssetProvider } from './io/file-import.js';
|
|
93
|
+
export { getSceneManager } from './scene-manager.js';
|
|
91
94
|
export async function init(options) {
|
|
92
95
|
await loadOC();
|
|
96
|
+
const existing = getSceneManager();
|
|
97
|
+
if (existing) {
|
|
98
|
+
return existing;
|
|
99
|
+
}
|
|
93
100
|
const resolvedPath = process.env.FLUIDCAD_WORKSPACE_PATH || '';
|
|
94
101
|
return createManager(resolvedPath, options);
|
|
95
102
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Shape } from "../common/shape.js";
|
|
2
2
|
import { Solid } from "../common/solid.js";
|
|
3
|
+
/**
|
|
4
|
+
* Override hook for hub mode (and tests). When set, asset reads consult
|
|
5
|
+
* the provider instead of the filesystem — paths are workspace-relative
|
|
6
|
+
* (e.g. `imports/foo.brep`). Returning null falls back to disk.
|
|
7
|
+
*/
|
|
8
|
+
export type AssetProvider = (workspaceRelPath: string) => Uint8Array | null;
|
|
9
|
+
export declare function setAssetProvider(provider: AssetProvider | null): void;
|
|
3
10
|
export declare class FileImport {
|
|
4
11
|
static deserializeShapes(fileName: string): Solid[];
|
|
5
12
|
static serializeShape(shape: Shape, workspacePath: string, fileName: string): void;
|
|
@@ -2,17 +2,37 @@ import * as fs from "fs";
|
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { OcIO } from "../oc/io.js";
|
|
4
4
|
import { getSceneManager } from "../scene-manager.js";
|
|
5
|
+
let assetProvider = null;
|
|
6
|
+
export function setAssetProvider(provider) {
|
|
7
|
+
assetProvider = provider;
|
|
8
|
+
}
|
|
9
|
+
function readWorkspaceAsset(relPath) {
|
|
10
|
+
if (assetProvider) {
|
|
11
|
+
const bytes = assetProvider(relPath);
|
|
12
|
+
if (bytes) {
|
|
13
|
+
return { text: Buffer.from(bytes).toString('utf8'), exists: true };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const sceneManager = getSceneManager();
|
|
17
|
+
const filePath = join(sceneManager.rootPath, relPath);
|
|
18
|
+
if (!fs.existsSync(filePath)) {
|
|
19
|
+
return { exists: false };
|
|
20
|
+
}
|
|
21
|
+
return { text: fs.readFileSync(filePath, 'utf8'), exists: true };
|
|
22
|
+
}
|
|
5
23
|
export class FileImport {
|
|
6
24
|
static deserializeShapes(fileName) {
|
|
7
25
|
if (!fileName.endsWith(('.brep'))) {
|
|
8
26
|
fileName += '.brep';
|
|
9
27
|
}
|
|
10
|
-
const
|
|
11
|
-
const filePath = join(sceneManager.rootPath, 'imports', fileName);
|
|
28
|
+
const relPath = join('imports', fileName);
|
|
12
29
|
console.log(`Reading file ${fileName}`);
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
30
|
+
const result = readWorkspaceAsset(relPath);
|
|
31
|
+
if (!result.exists) {
|
|
32
|
+
throw new Error(`Imported asset not found: ${relPath}`);
|
|
33
|
+
}
|
|
34
|
+
console.log(`File ${relPath} read successfully, size: ${result.text.length} bytes`);
|
|
35
|
+
return OcIO.readBRepSolids(fileName, result.text);
|
|
16
36
|
}
|
|
17
37
|
static serializeShape(shape, workspacePath, fileName) {
|
|
18
38
|
const file = OcIO.writeBRep(shape, fileName);
|
|
@@ -56,11 +76,11 @@ export class FileImport {
|
|
|
56
76
|
// Read color metadata from JSON sidecar (skipped when noColors is set)
|
|
57
77
|
let colorData = [];
|
|
58
78
|
if (!options?.noColors) {
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
if (
|
|
62
|
-
colorData = JSON.parse(
|
|
63
|
-
console.log(`Loaded color metadata from ${
|
|
79
|
+
const relPath = join('imports', brepFileName + '.colors.json');
|
|
80
|
+
const result = readWorkspaceAsset(relPath);
|
|
81
|
+
if (result.exists) {
|
|
82
|
+
colorData = JSON.parse(result.text);
|
|
83
|
+
console.log(`Loaded color metadata from ${relPath}`);
|
|
64
84
|
}
|
|
65
85
|
}
|
|
66
86
|
const include = options?.include;
|
|
@@ -4,10 +4,12 @@ import { Plane } from "./plane.js";
|
|
|
4
4
|
/** Anything that can be resolved to an `Axis` once built — e.g. `AxisObjectBase`. */
|
|
5
5
|
export interface AxisLazySource {
|
|
6
6
|
getAxis(): Axis;
|
|
7
|
+
compareTo?(other: unknown): boolean;
|
|
7
8
|
}
|
|
8
9
|
/** Anything that can be resolved to a `Plane` once built — e.g. `PlaneObjectBase`. */
|
|
9
10
|
export interface PlaneLazySource {
|
|
10
11
|
getPlane(): Plane;
|
|
12
|
+
compareTo?(other: unknown): boolean;
|
|
11
13
|
}
|
|
12
14
|
/**
|
|
13
15
|
* Memoized thunk over a Matrix4. Lets parse-time code thread a transform
|
|
@@ -20,9 +22,12 @@ export interface PlaneLazySource {
|
|
|
20
22
|
export declare class LazyMatrix {
|
|
21
23
|
private _resolver;
|
|
22
24
|
private _cached;
|
|
25
|
+
private _identity;
|
|
23
26
|
private constructor();
|
|
24
27
|
resolve(): Matrix4;
|
|
25
28
|
equals(other: LazyMatrix, tolerance?: number): boolean;
|
|
29
|
+
private static axisSourceEquals;
|
|
30
|
+
private static planeSourceEquals;
|
|
26
31
|
static of(matrix: Matrix4): LazyMatrix;
|
|
27
32
|
static from(resolver: () => Matrix4): LazyMatrix;
|
|
28
33
|
static mirror(plane: Plane | PlaneLazySource): LazyMatrix;
|