fluidcad 0.0.2 → 0.0.4
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 +7 -7
- package/lib/dist/common/shape-factory.d.ts +1 -1
- package/lib/dist/oc/boolean-ops.d.ts +2 -2
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/lib/dist/constraints/constraint.d.ts +0 -11
- package/lib/dist/constraints/constraint.js +0 -51
- package/lib/dist/constraints/outside.d.ts +0 -3
- package/lib/dist/constraints/outside.js +0 -4
- package/lib/dist/core/2d/aslot.d.ts +0 -12
- package/lib/dist/core/2d/aslot.js +0 -40
- package/lib/dist/core/2d/crect.d.ts +0 -12
- package/lib/dist/core/2d/crect.js +0 -74
- package/lib/dist/core/2d/face-maker.d.ts +0 -13
- package/lib/dist/core/2d/face-maker.js +0 -119
- package/lib/dist/core/2d/face-maker2.d.ts +0 -6
- package/lib/dist/core/2d/face-maker2.js +0 -54
- package/lib/dist/core/region.d.ts +0 -13
- package/lib/dist/core/region.js +0 -18
- package/lib/dist/features/2d/amove.d.ts +0 -14
- package/lib/dist/features/2d/amove.js +0 -33
- package/lib/dist/features/2d/constraints/constraint.d.ts +0 -11
- package/lib/dist/features/2d/constraints/constraint.js +0 -49
- package/lib/dist/features/2d/constraints/outside.d.ts +0 -3
- package/lib/dist/features/2d/constraints/outside.js +0 -4
- package/lib/dist/features/2d/tarc-two-circles.d.ts +0 -18
- package/lib/dist/features/2d/tarc-two-circles.js +0 -61
- package/lib/dist/features/2d/tcircle-three-tan.d.ts +0 -13
- package/lib/dist/features/2d/tcircle-three-tan.js +0 -33
- package/lib/dist/features/2d/tcircle-two-tan.d.ts +0 -13
- package/lib/dist/features/2d/tcircle-two-tan.js +0 -33
- package/lib/dist/features/Extrude.d.ts +0 -1
- package/lib/dist/features/Extrude.js +0 -1
- package/lib/dist/features/cut-base.d.ts +0 -49
- package/lib/dist/features/cut-base.js +0 -312
- package/lib/dist/features/cut-symmetric.d.ts +0 -23
- package/lib/dist/features/cut-symmetric.js +0 -119
- package/lib/dist/features/cut-two-distances.d.ts +0 -24
- package/lib/dist/features/cut-two-distances.js +0 -110
- package/lib/dist/features/cut.d.ts +0 -27
- package/lib/dist/features/cut.js +0 -101
- package/lib/dist/features/extrude-symmetric.d.ts +0 -28
- package/lib/dist/features/extrude-symmetric.js +0 -177
- package/lib/dist/features/region2d.d.ts +0 -25
- package/lib/dist/features/region2d.js +0 -185
- package/lib/dist/features/repeat-circular2d.d.ts +0 -17
- package/lib/dist/features/repeat-circular2d.js +0 -90
- package/lib/dist/features/repeat-linear2d.d.ts +0 -17
- package/lib/dist/features/repeat-linear2d.js +0 -114
- package/lib/dist/features/revolve-options.d.ts +0 -6
- package/lib/dist/features/revolve-options.js +0 -1
- package/lib/dist/features/split.d.ts +0 -14
- package/lib/dist/features/split.js +0 -74
- package/lib/dist/features/state-scene-object.d.ts +0 -15
- package/lib/dist/features/state-scene-object.js +0 -44
- package/lib/dist/features/state-select.d.ts +0 -21
- package/lib/dist/features/state-select.js +0 -73
- package/lib/dist/features/translate2d.d.ts +0 -16
- package/lib/dist/features/translate2d.js +0 -61
- package/lib/dist/filters/all-filter.d.ts +0 -8
- package/lib/dist/filters/all-filter.js +0 -12
- package/lib/dist/filters/near-point-filter.d.ts +0 -11
- package/lib/dist/filters/near-point-filter.js +0 -33
- package/lib/dist/helpers/resolve-filters.d.ts +0 -6
- package/lib/dist/helpers/resolve-filters.js +0 -25
- package/lib/dist/math/axis.test.d.ts +0 -1
- package/lib/dist/math/axis.test.js +0 -287
- package/lib/dist/math/coordinate-system.test.d.ts +0 -1
- package/lib/dist/math/coordinate-system.test.js +0 -308
- package/lib/dist/math/matrix4.test.d.ts +0 -1
- package/lib/dist/math/matrix4.test.js +0 -357
- package/lib/dist/math/plane.test.d.ts +0 -1
- package/lib/dist/math/plane.test.js +0 -398
- package/lib/dist/math/point.test.d.ts +0 -1
- package/lib/dist/math/point.test.js +0 -385
- package/lib/dist/math/quaternion.test.d.ts +0 -1
- package/lib/dist/math/quaternion.test.js +0 -278
- package/lib/dist/math/vector3d.test.d.ts +0 -1
- package/lib/dist/math/vector3d.test.js +0 -276
- package/lib/dist/oc/constraint-resolver.d.ts +0 -7
- package/lib/dist/oc/constraint-resolver.js +0 -31
- package/lib/dist/oc/constraints/curve-constraint-solver.d.ts +0 -1
- package/lib/dist/oc/constraints/curve-constraint-solver.js +0 -2
- package/lib/dist/oc/constraints/geometric-constraint-solver.d.ts +0 -1
- package/lib/dist/oc/constraints/geometric-constraint-solver.js +0 -5
- package/lib/dist/oc/face-maker.d.ts +0 -14
- package/lib/dist/oc/face-maker.js +0 -191
- package/lib/dist/oc/measure.d.ts +0 -21
- package/lib/dist/oc/measure.js +0 -256
- package/lib/dist/oc/tangent-circle-solver.d.ts +0 -17
- package/lib/dist/oc/tangent-circle-solver.js +0 -72
- package/lib/dist/oc/tangent-line-solver.d.ts +0 -17
- package/lib/dist/oc/tangent-line-solver.js +0 -83
- package/lib/dist/oc/tangent-solver.d.ts +0 -14
- package/lib/dist/oc/tangent-solver.js +0 -199
- package/lib/dist/rendering/builder-context.d.ts +0 -16
- package/lib/dist/rendering/builder-context.js +0 -63
- package/lib/dist/tests/extrude.test.d.ts +0 -1
- package/lib/dist/tests/extrude.test.js +0 -48
- package/lib/dist/tests/features/copy.test.d.ts +0 -1
- package/lib/dist/tests/features/copy.test.js +0 -158
- package/lib/dist/tests/features/dispose.test.d.ts +0 -1
- package/lib/dist/tests/features/dispose.test.js +0 -189
- package/lib/dist/tests/features/part-pick.test.d.ts +0 -1
- package/lib/dist/tests/features/part-pick.test.js +0 -73
- package/lib/dist/tests/features/part-repeat.test.d.ts +0 -1
- package/lib/dist/tests/features/part-repeat.test.js +0 -109
- package/server/dist/fluidcad-server.d.ts +0 -32
- package/server/dist/fluidcad-server.js +0 -150
- package/server/dist/index.d.ts +0 -1
- package/server/dist/index.js +0 -290
- package/server/dist/routes/actions.d.ts +0 -3
- package/server/dist/routes/actions.js +0 -100
- package/server/dist/routes/export.d.ts +0 -3
- package/server/dist/routes/export.js +0 -55
- package/server/dist/routes/properties.d.ts +0 -3
- package/server/dist/routes/properties.js +0 -46
- package/server/dist/routes/screenshot.d.ts +0 -2
- package/server/dist/routes/screenshot.js +0 -76
- package/server/dist/vite-manager.d.ts +0 -10
- package/server/dist/vite-manager.js +0 -64
- package/server/dist/ws-protocol.d.ts +0 -138
- package/server/dist/ws-protocol.js +0 -4
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { SelectSceneObject } from "../features/select.js";
|
|
2
|
-
export class SceneBuilderContext {
|
|
3
|
-
sceneObjects;
|
|
4
|
-
constructor(sceneObjects) {
|
|
5
|
-
this.sceneObjects = sceneObjects;
|
|
6
|
-
}
|
|
7
|
-
getSceneObjects() {
|
|
8
|
-
return this.sceneObjects;
|
|
9
|
-
}
|
|
10
|
-
getObjectShapesMap(filter) {
|
|
11
|
-
const map = new Map();
|
|
12
|
-
for (const obj of this.sceneObjects) {
|
|
13
|
-
const shapes = obj.getShapes(filter, 'solid');
|
|
14
|
-
if (shapes.length === 0) {
|
|
15
|
-
continue;
|
|
16
|
-
}
|
|
17
|
-
map.set(obj, shapes);
|
|
18
|
-
}
|
|
19
|
-
return map;
|
|
20
|
-
}
|
|
21
|
-
getActiveSceneObjects() {
|
|
22
|
-
return this.sceneObjects.filter(f => f.hasShapes());
|
|
23
|
-
}
|
|
24
|
-
getSceneObjectsFromTo(from, to) {
|
|
25
|
-
const fromIndex = this.sceneObjects.findIndex(f => f === from);
|
|
26
|
-
const toIndex = this.sceneObjects.findIndex(f => f === to);
|
|
27
|
-
return this.sceneObjects.slice(fromIndex, toIndex);
|
|
28
|
-
}
|
|
29
|
-
getLastExtrudable() {
|
|
30
|
-
let count = this.sceneObjects.length;
|
|
31
|
-
while (count--) {
|
|
32
|
-
const object = this.sceneObjects[count];
|
|
33
|
-
if (object.isExtrudable() && !object.parentId) {
|
|
34
|
-
return object;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
getLastSelections() {
|
|
40
|
-
let count = this.sceneObjects.length;
|
|
41
|
-
const selections = [];
|
|
42
|
-
while (count--) {
|
|
43
|
-
const obj = this.sceneObjects[count];
|
|
44
|
-
if (obj instanceof SelectSceneObject) {
|
|
45
|
-
selections.push(obj);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return selections;
|
|
49
|
-
}
|
|
50
|
-
getLastSelection() {
|
|
51
|
-
let count = this.sceneObjects.length;
|
|
52
|
-
while (count--) {
|
|
53
|
-
const obj = this.sceneObjects[count];
|
|
54
|
-
if (obj instanceof SelectSceneObject) {
|
|
55
|
-
return obj;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
addObject(obj) {
|
|
61
|
-
this.sceneObjects.push(obj);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { setupOC, buildScene } from "./setup.js";
|
|
3
|
-
import sketch from "../core/sketch.js";
|
|
4
|
-
import extrude from "../core/extrude.js";
|
|
5
|
-
import { rect } from "../core/2d/index.js";
|
|
6
|
-
import { ShapeProps } from "../oc/props.js";
|
|
7
|
-
describe("extrude", () => {
|
|
8
|
-
setupOC();
|
|
9
|
-
it("extrudes a rectangular sketch into a solid", () => {
|
|
10
|
-
sketch("xy", () => {
|
|
11
|
-
rect(100, 50);
|
|
12
|
-
});
|
|
13
|
-
const e = extrude(30);
|
|
14
|
-
buildScene();
|
|
15
|
-
const shapes = e.getShapes();
|
|
16
|
-
expect(shapes).toHaveLength(1);
|
|
17
|
-
expect(shapes[0].getType()).toBe("solid");
|
|
18
|
-
});
|
|
19
|
-
it("produces correct volume for a box", () => {
|
|
20
|
-
sketch("xy", () => {
|
|
21
|
-
rect(100, 50);
|
|
22
|
-
});
|
|
23
|
-
const e = extrude(30);
|
|
24
|
-
buildScene();
|
|
25
|
-
const shapes = e.getShapes();
|
|
26
|
-
const props = ShapeProps.getProperties(shapes[0].getShape());
|
|
27
|
-
expect(props.volumeMm3).toBeCloseTo(100 * 50 * 30, 0);
|
|
28
|
-
});
|
|
29
|
-
it("produces a solid with 6 faces", () => {
|
|
30
|
-
sketch("xy", () => {
|
|
31
|
-
rect(100, 50);
|
|
32
|
-
});
|
|
33
|
-
const e = extrude(30);
|
|
34
|
-
buildScene();
|
|
35
|
-
const solid = e.getShapes()[0];
|
|
36
|
-
expect(solid.getFaces()).toHaveLength(6);
|
|
37
|
-
});
|
|
38
|
-
it("uses default distance of 25 when no distance given", () => {
|
|
39
|
-
sketch("xy", () => {
|
|
40
|
-
rect(10, 10);
|
|
41
|
-
});
|
|
42
|
-
const e = extrude();
|
|
43
|
-
buildScene();
|
|
44
|
-
const shapes = e.getShapes();
|
|
45
|
-
const props = ShapeProps.getProperties(shapes[0].getShape());
|
|
46
|
-
expect(props.volumeMm3).toBeCloseTo(10 * 10 * 25, 0);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { setupOC, render } from "../setup.js";
|
|
3
|
-
import sketch from "../../core/sketch.js";
|
|
4
|
-
import extrude from "../../core/extrude.js";
|
|
5
|
-
import copy from "../../core/copy.js";
|
|
6
|
-
import { circle, move, rect } from "../../core/2d/index.js";
|
|
7
|
-
import { countShapes } from "../utils.js";
|
|
8
|
-
import { ShapeOps } from "../../oc/shape-ops.js";
|
|
9
|
-
describe("copy", () => {
|
|
10
|
-
setupOC();
|
|
11
|
-
describe("linear copy (3D)", () => {
|
|
12
|
-
it("should create copies along an axis", () => {
|
|
13
|
-
sketch("xy", () => {
|
|
14
|
-
rect(20, 20);
|
|
15
|
-
});
|
|
16
|
-
const e = extrude(10).fuse("none");
|
|
17
|
-
copy("linear", "x", { count: 3, offset: 40 }, e);
|
|
18
|
-
const scene = render();
|
|
19
|
-
// Original + 2 copies = 3 shapes
|
|
20
|
-
expect(countShapes(scene)).toBe(3);
|
|
21
|
-
});
|
|
22
|
-
it("should space copies by the given offset", () => {
|
|
23
|
-
sketch("xy", () => {
|
|
24
|
-
rect(20, 20);
|
|
25
|
-
});
|
|
26
|
-
const e = extrude(10).fuse("none");
|
|
27
|
-
const c = copy("linear", "x", { count: 3, offset: 50 }, e);
|
|
28
|
-
render();
|
|
29
|
-
// 2 copies (index 1 and 2), each offset by 50 along X
|
|
30
|
-
const shapes = c.getShapes();
|
|
31
|
-
expect(shapes).toHaveLength(2);
|
|
32
|
-
const bbox1 = ShapeOps.getBoundingBox(shapes[0]);
|
|
33
|
-
const bbox2 = ShapeOps.getBoundingBox(shapes[1]);
|
|
34
|
-
expect(bbox1.minX).toBeCloseTo(50, 0);
|
|
35
|
-
expect(bbox2.minX).toBeCloseTo(100, 0);
|
|
36
|
-
});
|
|
37
|
-
it("should copy along Y axis", () => {
|
|
38
|
-
sketch("xy", () => {
|
|
39
|
-
rect(20, 20);
|
|
40
|
-
});
|
|
41
|
-
const e = extrude(10).fuse("none");
|
|
42
|
-
const c = copy("linear", "y", { count: 2, offset: 60 }, e);
|
|
43
|
-
render();
|
|
44
|
-
const shapes = c.getShapes();
|
|
45
|
-
expect(shapes).toHaveLength(1);
|
|
46
|
-
const bbox = ShapeOps.getBoundingBox(shapes[0]);
|
|
47
|
-
expect(bbox.minY).toBeCloseTo(60, 0);
|
|
48
|
-
});
|
|
49
|
-
it("should copy along Z axis", () => {
|
|
50
|
-
sketch("xy", () => {
|
|
51
|
-
rect(20, 20);
|
|
52
|
-
});
|
|
53
|
-
const e = extrude(10).fuse("none");
|
|
54
|
-
const c = copy("linear", "z", { count: 2, offset: 30 }, e);
|
|
55
|
-
render();
|
|
56
|
-
const shapes = c.getShapes();
|
|
57
|
-
expect(shapes).toHaveLength(1);
|
|
58
|
-
const bbox = ShapeOps.getBoundingBox(shapes[0]);
|
|
59
|
-
expect(bbox.minZ).toBeCloseTo(30, 0);
|
|
60
|
-
});
|
|
61
|
-
it("should distribute copies by total length", () => {
|
|
62
|
-
sketch("xy", () => {
|
|
63
|
-
rect(20, 20);
|
|
64
|
-
});
|
|
65
|
-
const e = extrude(10).fuse("none");
|
|
66
|
-
// 4 copies over length 120 → offset = 120/4 = 30
|
|
67
|
-
const c = copy("linear", "x", { count: 4, length: 120 }, e);
|
|
68
|
-
render();
|
|
69
|
-
const shapes = c.getShapes();
|
|
70
|
-
expect(shapes).toHaveLength(3);
|
|
71
|
-
const bbox = ShapeOps.getBoundingBox(shapes[0]);
|
|
72
|
-
expect(bbox.minX).toBeCloseTo(30, 0);
|
|
73
|
-
});
|
|
74
|
-
it("should create a 2D grid with multiple axes", () => {
|
|
75
|
-
sketch("xy", () => {
|
|
76
|
-
rect(10, 10);
|
|
77
|
-
});
|
|
78
|
-
const e = extrude(10).fuse("none");
|
|
79
|
-
// 3 along X, 2 along Y → 3×2 = 6 positions, minus original = 5 copies
|
|
80
|
-
copy("linear", ["x", "y"], { count: [3, 2], offset: 30 }, e);
|
|
81
|
-
const scene = render();
|
|
82
|
-
// Original (1) + copies (5) = 6
|
|
83
|
-
expect(countShapes(scene)).toBe(6);
|
|
84
|
-
});
|
|
85
|
-
it("should skip specified positions", () => {
|
|
86
|
-
sketch("xy", () => {
|
|
87
|
-
rect(10, 10);
|
|
88
|
-
});
|
|
89
|
-
const e = extrude(10).fuse("none");
|
|
90
|
-
// 3 copies, skip index 1
|
|
91
|
-
copy("linear", "x", { count: 3, offset: 30, skip: [[1]] }, e);
|
|
92
|
-
const scene = render();
|
|
93
|
-
// Original (1) + 1 copy (skipped index 1, kept index 2) = 2
|
|
94
|
-
expect(countShapes(scene)).toBe(2);
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
describe("circular copy (3D)", () => {
|
|
98
|
-
it("should create copies around an axis", () => {
|
|
99
|
-
sketch("xy", () => {
|
|
100
|
-
move([50, 0]);
|
|
101
|
-
rect(20, 20);
|
|
102
|
-
});
|
|
103
|
-
const e = extrude(10).fuse("none");
|
|
104
|
-
copy("circular", "z", { count: 4, angle: 360 }, e);
|
|
105
|
-
const scene = render();
|
|
106
|
-
// Original + 3 copies = 4 shapes
|
|
107
|
-
expect(countShapes(scene)).toBe(4);
|
|
108
|
-
});
|
|
109
|
-
it("should space copies evenly over the given angle", () => {
|
|
110
|
-
sketch("xy", () => {
|
|
111
|
-
move([50, 0]);
|
|
112
|
-
rect(20, 20);
|
|
113
|
-
});
|
|
114
|
-
const e = extrude(10).fuse("none");
|
|
115
|
-
// 3 copies over 180° → 60° each
|
|
116
|
-
const c = copy("circular", "z", { count: 3, angle: 180 }, e);
|
|
117
|
-
render();
|
|
118
|
-
const shapes = c.getShapes();
|
|
119
|
-
expect(shapes).toHaveLength(2);
|
|
120
|
-
});
|
|
121
|
-
it("should skip specified indices", () => {
|
|
122
|
-
sketch("xy", () => {
|
|
123
|
-
move([50, 0]);
|
|
124
|
-
rect(20, 20);
|
|
125
|
-
});
|
|
126
|
-
const e = extrude(10).fuse("none");
|
|
127
|
-
copy("circular", "z", { count: 4, angle: 360, skip: [1] }, e);
|
|
128
|
-
const scene = render();
|
|
129
|
-
// Original (1) + 2 copies (skipped index 1) = 3
|
|
130
|
-
expect(countShapes(scene)).toBe(3);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
describe("linear copy (2D)", () => {
|
|
134
|
-
it("should create 2D copies inside a sketch", () => {
|
|
135
|
-
sketch("xy", () => {
|
|
136
|
-
const r = rect(20, 20);
|
|
137
|
-
copy("linear", "x", { count: 3, offset: 40 }, r);
|
|
138
|
-
});
|
|
139
|
-
const e = extrude(10);
|
|
140
|
-
render();
|
|
141
|
-
// 3 rects extruded and fused
|
|
142
|
-
const shapes = e.getShapes();
|
|
143
|
-
expect(shapes.length).toBeGreaterThanOrEqual(1);
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
describe("circular copy (2D)", () => {
|
|
147
|
-
it("should create 2D circular copies inside a sketch", () => {
|
|
148
|
-
sketch("xy", () => {
|
|
149
|
-
const c = circle([30, 0], 10);
|
|
150
|
-
copy("circular", [0, 0], { count: 4, angle: 360 }, c);
|
|
151
|
-
});
|
|
152
|
-
const e = extrude(10);
|
|
153
|
-
render();
|
|
154
|
-
const shapes = e.getShapes();
|
|
155
|
-
expect(shapes.length).toBeGreaterThanOrEqual(1);
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { setupOC, render } from "../setup.js";
|
|
3
|
-
import { getCurrentScene, getSceneManager } from "../../scene-manager.js";
|
|
4
|
-
import sketch from "../../core/sketch.js";
|
|
5
|
-
import extrude from "../../core/extrude.js";
|
|
6
|
-
import cylinder from "../../core/cylinder.js";
|
|
7
|
-
import trim from "../../core/trim.js";
|
|
8
|
-
import { circle, rect } from "../../core/2d/index.js";
|
|
9
|
-
import { SceneCompare } from "../../rendering/scene-compare.js";
|
|
10
|
-
import { renderScene } from "../../rendering/render.js";
|
|
11
|
-
import { Sketch } from "../../features/2d/sketch.js";
|
|
12
|
-
describe("dispose", () => {
|
|
13
|
-
setupOC();
|
|
14
|
-
describe("SceneObject.dispose()", () => {
|
|
15
|
-
it("should clear state after dispose", () => {
|
|
16
|
-
sketch("xy", () => {
|
|
17
|
-
rect(100, 50);
|
|
18
|
-
});
|
|
19
|
-
const e = extrude(30);
|
|
20
|
-
render();
|
|
21
|
-
expect(e.getShapes().length).toBeGreaterThan(0);
|
|
22
|
-
e.dispose();
|
|
23
|
-
// State is cleared — getState returns undefined for all keys
|
|
24
|
-
expect(e.getState("addedShapes")).toBeUndefined();
|
|
25
|
-
});
|
|
26
|
-
it("should call Shape.dispose() on addedShapes", () => {
|
|
27
|
-
sketch("xy", () => {
|
|
28
|
-
rect(100, 50);
|
|
29
|
-
});
|
|
30
|
-
const e = extrude(30);
|
|
31
|
-
render();
|
|
32
|
-
const shapes = e.getAddedShapes();
|
|
33
|
-
expect(shapes.length).toBeGreaterThan(0);
|
|
34
|
-
const spies = shapes.map(s => vi.spyOn(s, "dispose"));
|
|
35
|
-
e.dispose();
|
|
36
|
-
for (const spy of spies) {
|
|
37
|
-
expect(spy).toHaveBeenCalled();
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
it("should call Shape.dispose() on face state values", () => {
|
|
41
|
-
sketch("xy", () => {
|
|
42
|
-
rect(100, 50);
|
|
43
|
-
});
|
|
44
|
-
const e = extrude(30);
|
|
45
|
-
render();
|
|
46
|
-
const startFaces = e.getState("start-faces");
|
|
47
|
-
const endFaces = e.getState("end-faces");
|
|
48
|
-
const sideFaces = e.getState("side-faces");
|
|
49
|
-
expect(startFaces.length).toBeGreaterThan(0);
|
|
50
|
-
expect(endFaces.length).toBeGreaterThan(0);
|
|
51
|
-
expect(sideFaces.length).toBeGreaterThan(0);
|
|
52
|
-
const allSpies = [...startFaces, ...endFaces, ...sideFaces].map(s => vi.spyOn(s, "dispose"));
|
|
53
|
-
e.dispose();
|
|
54
|
-
for (const spy of allSpies) {
|
|
55
|
-
expect(spy).toHaveBeenCalled();
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
it("should not dispose shapes in removedShapes", () => {
|
|
59
|
-
sketch("xy", () => {
|
|
60
|
-
circle(50);
|
|
61
|
-
});
|
|
62
|
-
const e1 = extrude(30);
|
|
63
|
-
sketch("xy", () => {
|
|
64
|
-
circle(50);
|
|
65
|
-
});
|
|
66
|
-
const e2 = extrude(30);
|
|
67
|
-
render();
|
|
68
|
-
// e1's shapes were removed (fused into e2)
|
|
69
|
-
const e1Shapes = e1.getAddedShapes();
|
|
70
|
-
const spies = e1Shapes.map(s => vi.spyOn(s, "dispose"));
|
|
71
|
-
// Dispose e2 — it has removedShapes referencing e1's shapes
|
|
72
|
-
e2.dispose();
|
|
73
|
-
// e1's shapes should NOT have been disposed by e2
|
|
74
|
-
for (const spy of spies) {
|
|
75
|
-
expect(spy).not.toHaveBeenCalled();
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
it("should be safe to call dispose twice", () => {
|
|
79
|
-
sketch("xy", () => {
|
|
80
|
-
rect(100, 50);
|
|
81
|
-
});
|
|
82
|
-
const e = extrude(30);
|
|
83
|
-
render();
|
|
84
|
-
e.dispose();
|
|
85
|
-
// Second call should not throw
|
|
86
|
-
expect(() => e.dispose()).not.toThrow();
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
describe("SceneCompare disposes unmatched objects", () => {
|
|
90
|
-
it("should dispose unmatched old scene objects after compare", () => {
|
|
91
|
-
// Build first scene
|
|
92
|
-
sketch("xy", () => {
|
|
93
|
-
rect(100, 50);
|
|
94
|
-
});
|
|
95
|
-
extrude(30);
|
|
96
|
-
const scene1 = render();
|
|
97
|
-
const oldObjects = scene1.getSceneObjects();
|
|
98
|
-
const spies = oldObjects.map(o => vi.spyOn(o, "dispose"));
|
|
99
|
-
// Build second scene with completely different geometry
|
|
100
|
-
getSceneManager().startScene();
|
|
101
|
-
cylinder(50, 100);
|
|
102
|
-
const scene2 = getCurrentScene();
|
|
103
|
-
SceneCompare.compare(scene1, scene2);
|
|
104
|
-
// All old objects are unmatched (cylinder vs sketch+extrude) — all should be disposed
|
|
105
|
-
for (const spy of spies) {
|
|
106
|
-
expect(spy).toHaveBeenCalled();
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
it("should not dispose matched old scene objects", () => {
|
|
110
|
-
// Build first scene
|
|
111
|
-
cylinder(50, 100);
|
|
112
|
-
const scene1 = render();
|
|
113
|
-
const oldObj = scene1.getSceneObjectAt(0);
|
|
114
|
-
const disposeSpy = vi.spyOn(oldObj, "dispose");
|
|
115
|
-
// Build second scene with same structure
|
|
116
|
-
getSceneManager().startScene();
|
|
117
|
-
cylinder(50, 100);
|
|
118
|
-
const scene2 = getCurrentScene();
|
|
119
|
-
SceneCompare.compare(scene1, scene2);
|
|
120
|
-
// Same structure — old object should NOT be disposed (state was transferred)
|
|
121
|
-
expect(disposeSpy).not.toHaveBeenCalled();
|
|
122
|
-
});
|
|
123
|
-
it("should dispose objects after the first mismatch point", () => {
|
|
124
|
-
// Build first scene: cylinder + extrude
|
|
125
|
-
cylinder(50, 100);
|
|
126
|
-
sketch("xy", () => {
|
|
127
|
-
rect(100, 50);
|
|
128
|
-
});
|
|
129
|
-
const e = extrude(30);
|
|
130
|
-
const scene1 = render();
|
|
131
|
-
const cylObj = scene1.getSceneObjectAt(0);
|
|
132
|
-
const cylSpy = vi.spyOn(cylObj, "dispose");
|
|
133
|
-
const eSpy = vi.spyOn(e, "dispose");
|
|
134
|
-
// Build second scene: cylinder + different sketch shape
|
|
135
|
-
getSceneManager().startScene();
|
|
136
|
-
cylinder(50, 100);
|
|
137
|
-
sketch("xy", () => {
|
|
138
|
-
circle(80);
|
|
139
|
-
});
|
|
140
|
-
extrude(30);
|
|
141
|
-
const scene2 = getCurrentScene();
|
|
142
|
-
SceneCompare.compare(scene1, scene2);
|
|
143
|
-
// Cylinder matches — should NOT be disposed
|
|
144
|
-
expect(cylSpy).not.toHaveBeenCalled();
|
|
145
|
-
// Sketch changed (rect -> circle) so from sketch onwards is unmatched
|
|
146
|
-
expect(eSpy).toHaveBeenCalled();
|
|
147
|
-
});
|
|
148
|
-
it("should mark matched objects as cached in new scene", () => {
|
|
149
|
-
cylinder(50, 100);
|
|
150
|
-
const scene1 = render();
|
|
151
|
-
getSceneManager().startScene();
|
|
152
|
-
cylinder(50, 100);
|
|
153
|
-
sketch("xy", () => {
|
|
154
|
-
rect(100, 50);
|
|
155
|
-
});
|
|
156
|
-
extrude(30);
|
|
157
|
-
const scene2 = getCurrentScene();
|
|
158
|
-
SceneCompare.compare(scene1, scene2);
|
|
159
|
-
// Cylinder matched — should be cached
|
|
160
|
-
const newCyl = scene2.getSceneObjectAt(0);
|
|
161
|
-
expect(scene2.isCached(newCyl)).toBe(true);
|
|
162
|
-
// Sketch is new — should not be cached
|
|
163
|
-
const newSketch = scene2.getSceneObjects().find(o => o instanceof Sketch);
|
|
164
|
-
expect(scene2.isCached(newSketch)).toBe(false);
|
|
165
|
-
});
|
|
166
|
-
it("should not delete shapes shared with matched objects (trim2d scenario)", () => {
|
|
167
|
-
// Build first scene: sketch with circle + trim
|
|
168
|
-
sketch("xy", () => {
|
|
169
|
-
circle(100);
|
|
170
|
-
trim();
|
|
171
|
-
});
|
|
172
|
-
const scene1 = render();
|
|
173
|
-
// Build second scene: same sketch, trim with different points
|
|
174
|
-
getSceneManager().startScene();
|
|
175
|
-
sketch("xy", () => {
|
|
176
|
-
circle(100);
|
|
177
|
-
trim([10, 0]);
|
|
178
|
-
});
|
|
179
|
-
const scene2 = getCurrentScene();
|
|
180
|
-
// Compare — circle matches, trim2d does not
|
|
181
|
-
SceneCompare.compare(scene1, scene2);
|
|
182
|
-
// Render should succeed — the matched circle's edge must not be deleted
|
|
183
|
-
expect(() => renderScene(scene2)).not.toThrow();
|
|
184
|
-
// Verify shapes exist on the scene
|
|
185
|
-
const rendered = scene2.getRenderedObjects();
|
|
186
|
-
expect(rendered.length).toBeGreaterThan(0);
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
-
import { setupOC, render } from "../setup.js";
|
|
3
|
-
import { setCurrentFile } from "../../scene-manager.js";
|
|
4
|
-
import sketch from "../../core/sketch.js";
|
|
5
|
-
import extrude from "../../core/extrude.js";
|
|
6
|
-
import { circle, rect } from "../../core/2d/index.js";
|
|
7
|
-
import part from "../../core/part.js";
|
|
8
|
-
import use from "../../core/use.js";
|
|
9
|
-
describe("pick inside part", () => {
|
|
10
|
-
setupOC();
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
setCurrentFile('');
|
|
13
|
-
});
|
|
14
|
-
it("pick outside part should have meta shapes", () => {
|
|
15
|
-
sketch("xy", () => {
|
|
16
|
-
rect(50);
|
|
17
|
-
circle(20);
|
|
18
|
-
});
|
|
19
|
-
extrude().pick();
|
|
20
|
-
const scene = render();
|
|
21
|
-
const rendered = scene.getRenderedObjects();
|
|
22
|
-
const extrudeRender = rendered.find(r => r.type === 'extrude');
|
|
23
|
-
console.log("OUTSIDE PART pick - extrude shapes:", extrudeRender?.sceneShapes.length, "meta:", extrudeRender?.sceneShapes.filter(s => s.isMetaShape).length);
|
|
24
|
-
// Should have meta shapes (pick regions)
|
|
25
|
-
expect(extrudeRender).toBeDefined();
|
|
26
|
-
const metaShapes = extrudeRender.sceneShapes.filter(s => s.isMetaShape);
|
|
27
|
-
expect(metaShapes.length).toBeGreaterThan(0);
|
|
28
|
-
});
|
|
29
|
-
it("pick inside part should have meta shapes", () => {
|
|
30
|
-
const handle = part("test", () => {
|
|
31
|
-
sketch("xy", () => {
|
|
32
|
-
rect(50);
|
|
33
|
-
circle(20);
|
|
34
|
-
});
|
|
35
|
-
extrude().pick();
|
|
36
|
-
});
|
|
37
|
-
use(handle);
|
|
38
|
-
const scene = render();
|
|
39
|
-
const rendered = scene.getRenderedObjects();
|
|
40
|
-
const extrudeRender = rendered.find(r => r.type === 'extrude');
|
|
41
|
-
console.log("INSIDE PART pick - extrude shapes:", extrudeRender?.sceneShapes.length, "meta:", extrudeRender?.sceneShapes.filter(s => s.isMetaShape).length);
|
|
42
|
-
expect(extrudeRender).toBeDefined();
|
|
43
|
-
const metaShapes = extrudeRender.sceneShapes.filter(s => s.isMetaShape);
|
|
44
|
-
expect(metaShapes.length).toBeGreaterThan(0);
|
|
45
|
-
});
|
|
46
|
-
it("pick inside part with second part should have meta shapes", () => {
|
|
47
|
-
const handle1 = part("part1", () => {
|
|
48
|
-
sketch("xy", () => {
|
|
49
|
-
rect(50);
|
|
50
|
-
circle(20);
|
|
51
|
-
});
|
|
52
|
-
extrude().pick();
|
|
53
|
-
});
|
|
54
|
-
const handle2 = part("part2", () => {
|
|
55
|
-
sketch("xy", () => {
|
|
56
|
-
circle(10);
|
|
57
|
-
});
|
|
58
|
-
extrude();
|
|
59
|
-
});
|
|
60
|
-
use(handle1);
|
|
61
|
-
use(handle2);
|
|
62
|
-
const scene = render();
|
|
63
|
-
const rendered = scene.getRenderedObjects();
|
|
64
|
-
const extrudeRenders = rendered.filter(r => r.type === 'extrude');
|
|
65
|
-
console.log("TWO PARTS pick - extrude count:", extrudeRenders.length);
|
|
66
|
-
for (const er of extrudeRenders) {
|
|
67
|
-
console.log(" shapes:", er.sceneShapes.length, "meta:", er.sceneShapes.filter(s => s.isMetaShape).length, "hasError:", er.hasError, er.errorMessage || '');
|
|
68
|
-
}
|
|
69
|
-
// First extrude (pick) should have meta shapes
|
|
70
|
-
const metaShapes = extrudeRenders[0].sceneShapes.filter(s => s.isMetaShape);
|
|
71
|
-
expect(metaShapes.length).toBeGreaterThan(0);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
-
import { setupOC, render } from "../setup.js";
|
|
3
|
-
import { setCurrentFile } from "../../scene-manager.js";
|
|
4
|
-
import sketch from "../../core/sketch.js";
|
|
5
|
-
import extrude from "../../core/extrude.js";
|
|
6
|
-
import cut from "../../core/cut.js";
|
|
7
|
-
import repeat from "../../core/repeat.js";
|
|
8
|
-
import { circle, rect } from "../../core/2d/index.js";
|
|
9
|
-
import part from "../../core/part.js";
|
|
10
|
-
import use from "../../core/use.js";
|
|
11
|
-
import { countShapes } from "../utils.js";
|
|
12
|
-
describe("repeat inside part", () => {
|
|
13
|
-
setupOC();
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
setCurrentFile('');
|
|
16
|
-
});
|
|
17
|
-
it("repeat with explicit objects outside part", () => {
|
|
18
|
-
sketch("xy", () => {
|
|
19
|
-
rect(50);
|
|
20
|
-
});
|
|
21
|
-
const e = extrude();
|
|
22
|
-
sketch(e.endFaces(), () => {
|
|
23
|
-
circle(20);
|
|
24
|
-
});
|
|
25
|
-
const c = cut();
|
|
26
|
-
repeat("linear", "x", { count: 3, offset: 80 }, e, c);
|
|
27
|
-
const scene = render();
|
|
28
|
-
const shapeCount = countShapes(scene);
|
|
29
|
-
console.log("OUTSIDE PART explicit:", shapeCount);
|
|
30
|
-
expect(shapeCount).toBeGreaterThan(0);
|
|
31
|
-
});
|
|
32
|
-
it("repeat with default input outside part", () => {
|
|
33
|
-
sketch("xy", () => {
|
|
34
|
-
rect(50);
|
|
35
|
-
});
|
|
36
|
-
const e = extrude();
|
|
37
|
-
sketch(e.endFaces(), () => {
|
|
38
|
-
circle(20);
|
|
39
|
-
});
|
|
40
|
-
const c = cut();
|
|
41
|
-
repeat("linear", "x", { count: 3, offset: 80 });
|
|
42
|
-
const scene = render();
|
|
43
|
-
const shapeCount = countShapes(scene);
|
|
44
|
-
console.log("OUTSIDE PART default:", shapeCount);
|
|
45
|
-
expect(shapeCount).toBeGreaterThan(0);
|
|
46
|
-
});
|
|
47
|
-
it("repeat with explicit objects inside part", () => {
|
|
48
|
-
const handle = part("test", () => {
|
|
49
|
-
sketch("xy", () => {
|
|
50
|
-
rect(50);
|
|
51
|
-
});
|
|
52
|
-
const e = extrude();
|
|
53
|
-
sketch(e.endFaces(), () => {
|
|
54
|
-
circle(20);
|
|
55
|
-
});
|
|
56
|
-
const c = cut();
|
|
57
|
-
repeat("linear", "x", { count: 3, offset: 80 }, e, c);
|
|
58
|
-
});
|
|
59
|
-
use(handle);
|
|
60
|
-
const scene = render();
|
|
61
|
-
const shapeCount = countShapes(scene);
|
|
62
|
-
console.log("INSIDE PART explicit:", shapeCount);
|
|
63
|
-
expect(shapeCount).toBeGreaterThan(0);
|
|
64
|
-
});
|
|
65
|
-
it("repeat with default input inside part", () => {
|
|
66
|
-
const handle = part("test", () => {
|
|
67
|
-
sketch("xy", () => {
|
|
68
|
-
rect(50);
|
|
69
|
-
});
|
|
70
|
-
const e = extrude();
|
|
71
|
-
sketch(e.endFaces(), () => {
|
|
72
|
-
circle(20);
|
|
73
|
-
});
|
|
74
|
-
const c = cut();
|
|
75
|
-
repeat("linear", "x", { count: 3, offset: 80 });
|
|
76
|
-
});
|
|
77
|
-
use(handle);
|
|
78
|
-
const scene = render();
|
|
79
|
-
const shapeCount = countShapes(scene);
|
|
80
|
-
console.log("INSIDE PART default:", shapeCount);
|
|
81
|
-
expect(shapeCount).toBeGreaterThan(0);
|
|
82
|
-
});
|
|
83
|
-
it("simple repeat with default input inside part", () => {
|
|
84
|
-
const handle = part("test", () => {
|
|
85
|
-
sketch("xy", () => {
|
|
86
|
-
rect(50);
|
|
87
|
-
});
|
|
88
|
-
const e = extrude().fuse("none");
|
|
89
|
-
repeat("linear", "x", { count: 3, offset: 80 });
|
|
90
|
-
});
|
|
91
|
-
use(handle);
|
|
92
|
-
const scene = render();
|
|
93
|
-
const shapeCount = countShapes(scene);
|
|
94
|
-
console.log("INSIDE PART simple default:", shapeCount);
|
|
95
|
-
// Should have 3 shapes (original + 2 clones)
|
|
96
|
-
expect(shapeCount).toBe(3);
|
|
97
|
-
});
|
|
98
|
-
it("simple repeat with default input outside part", () => {
|
|
99
|
-
sketch("xy", () => {
|
|
100
|
-
rect(50);
|
|
101
|
-
});
|
|
102
|
-
const e = extrude().fuse("none");
|
|
103
|
-
repeat("linear", "x", { count: 3, offset: 80 });
|
|
104
|
-
const scene = render();
|
|
105
|
-
const shapeCount = countShapes(scene);
|
|
106
|
-
console.log("OUTSIDE PART simple default:", shapeCount);
|
|
107
|
-
expect(shapeCount).toBe(3);
|
|
108
|
-
});
|
|
109
|
-
});
|