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.
Files changed (123) hide show
  1. package/README.md +7 -7
  2. package/lib/dist/common/shape-factory.d.ts +1 -1
  3. package/lib/dist/oc/boolean-ops.d.ts +2 -2
  4. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  5. package/package.json +3 -2
  6. package/lib/dist/constraints/constraint.d.ts +0 -11
  7. package/lib/dist/constraints/constraint.js +0 -51
  8. package/lib/dist/constraints/outside.d.ts +0 -3
  9. package/lib/dist/constraints/outside.js +0 -4
  10. package/lib/dist/core/2d/aslot.d.ts +0 -12
  11. package/lib/dist/core/2d/aslot.js +0 -40
  12. package/lib/dist/core/2d/crect.d.ts +0 -12
  13. package/lib/dist/core/2d/crect.js +0 -74
  14. package/lib/dist/core/2d/face-maker.d.ts +0 -13
  15. package/lib/dist/core/2d/face-maker.js +0 -119
  16. package/lib/dist/core/2d/face-maker2.d.ts +0 -6
  17. package/lib/dist/core/2d/face-maker2.js +0 -54
  18. package/lib/dist/core/region.d.ts +0 -13
  19. package/lib/dist/core/region.js +0 -18
  20. package/lib/dist/features/2d/amove.d.ts +0 -14
  21. package/lib/dist/features/2d/amove.js +0 -33
  22. package/lib/dist/features/2d/constraints/constraint.d.ts +0 -11
  23. package/lib/dist/features/2d/constraints/constraint.js +0 -49
  24. package/lib/dist/features/2d/constraints/outside.d.ts +0 -3
  25. package/lib/dist/features/2d/constraints/outside.js +0 -4
  26. package/lib/dist/features/2d/tarc-two-circles.d.ts +0 -18
  27. package/lib/dist/features/2d/tarc-two-circles.js +0 -61
  28. package/lib/dist/features/2d/tcircle-three-tan.d.ts +0 -13
  29. package/lib/dist/features/2d/tcircle-three-tan.js +0 -33
  30. package/lib/dist/features/2d/tcircle-two-tan.d.ts +0 -13
  31. package/lib/dist/features/2d/tcircle-two-tan.js +0 -33
  32. package/lib/dist/features/Extrude.d.ts +0 -1
  33. package/lib/dist/features/Extrude.js +0 -1
  34. package/lib/dist/features/cut-base.d.ts +0 -49
  35. package/lib/dist/features/cut-base.js +0 -312
  36. package/lib/dist/features/cut-symmetric.d.ts +0 -23
  37. package/lib/dist/features/cut-symmetric.js +0 -119
  38. package/lib/dist/features/cut-two-distances.d.ts +0 -24
  39. package/lib/dist/features/cut-two-distances.js +0 -110
  40. package/lib/dist/features/cut.d.ts +0 -27
  41. package/lib/dist/features/cut.js +0 -101
  42. package/lib/dist/features/extrude-symmetric.d.ts +0 -28
  43. package/lib/dist/features/extrude-symmetric.js +0 -177
  44. package/lib/dist/features/region2d.d.ts +0 -25
  45. package/lib/dist/features/region2d.js +0 -185
  46. package/lib/dist/features/repeat-circular2d.d.ts +0 -17
  47. package/lib/dist/features/repeat-circular2d.js +0 -90
  48. package/lib/dist/features/repeat-linear2d.d.ts +0 -17
  49. package/lib/dist/features/repeat-linear2d.js +0 -114
  50. package/lib/dist/features/revolve-options.d.ts +0 -6
  51. package/lib/dist/features/revolve-options.js +0 -1
  52. package/lib/dist/features/split.d.ts +0 -14
  53. package/lib/dist/features/split.js +0 -74
  54. package/lib/dist/features/state-scene-object.d.ts +0 -15
  55. package/lib/dist/features/state-scene-object.js +0 -44
  56. package/lib/dist/features/state-select.d.ts +0 -21
  57. package/lib/dist/features/state-select.js +0 -73
  58. package/lib/dist/features/translate2d.d.ts +0 -16
  59. package/lib/dist/features/translate2d.js +0 -61
  60. package/lib/dist/filters/all-filter.d.ts +0 -8
  61. package/lib/dist/filters/all-filter.js +0 -12
  62. package/lib/dist/filters/near-point-filter.d.ts +0 -11
  63. package/lib/dist/filters/near-point-filter.js +0 -33
  64. package/lib/dist/helpers/resolve-filters.d.ts +0 -6
  65. package/lib/dist/helpers/resolve-filters.js +0 -25
  66. package/lib/dist/math/axis.test.d.ts +0 -1
  67. package/lib/dist/math/axis.test.js +0 -287
  68. package/lib/dist/math/coordinate-system.test.d.ts +0 -1
  69. package/lib/dist/math/coordinate-system.test.js +0 -308
  70. package/lib/dist/math/matrix4.test.d.ts +0 -1
  71. package/lib/dist/math/matrix4.test.js +0 -357
  72. package/lib/dist/math/plane.test.d.ts +0 -1
  73. package/lib/dist/math/plane.test.js +0 -398
  74. package/lib/dist/math/point.test.d.ts +0 -1
  75. package/lib/dist/math/point.test.js +0 -385
  76. package/lib/dist/math/quaternion.test.d.ts +0 -1
  77. package/lib/dist/math/quaternion.test.js +0 -278
  78. package/lib/dist/math/vector3d.test.d.ts +0 -1
  79. package/lib/dist/math/vector3d.test.js +0 -276
  80. package/lib/dist/oc/constraint-resolver.d.ts +0 -7
  81. package/lib/dist/oc/constraint-resolver.js +0 -31
  82. package/lib/dist/oc/constraints/curve-constraint-solver.d.ts +0 -1
  83. package/lib/dist/oc/constraints/curve-constraint-solver.js +0 -2
  84. package/lib/dist/oc/constraints/geometric-constraint-solver.d.ts +0 -1
  85. package/lib/dist/oc/constraints/geometric-constraint-solver.js +0 -5
  86. package/lib/dist/oc/face-maker.d.ts +0 -14
  87. package/lib/dist/oc/face-maker.js +0 -191
  88. package/lib/dist/oc/measure.d.ts +0 -21
  89. package/lib/dist/oc/measure.js +0 -256
  90. package/lib/dist/oc/tangent-circle-solver.d.ts +0 -17
  91. package/lib/dist/oc/tangent-circle-solver.js +0 -72
  92. package/lib/dist/oc/tangent-line-solver.d.ts +0 -17
  93. package/lib/dist/oc/tangent-line-solver.js +0 -83
  94. package/lib/dist/oc/tangent-solver.d.ts +0 -14
  95. package/lib/dist/oc/tangent-solver.js +0 -199
  96. package/lib/dist/rendering/builder-context.d.ts +0 -16
  97. package/lib/dist/rendering/builder-context.js +0 -63
  98. package/lib/dist/tests/extrude.test.d.ts +0 -1
  99. package/lib/dist/tests/extrude.test.js +0 -48
  100. package/lib/dist/tests/features/copy.test.d.ts +0 -1
  101. package/lib/dist/tests/features/copy.test.js +0 -158
  102. package/lib/dist/tests/features/dispose.test.d.ts +0 -1
  103. package/lib/dist/tests/features/dispose.test.js +0 -189
  104. package/lib/dist/tests/features/part-pick.test.d.ts +0 -1
  105. package/lib/dist/tests/features/part-pick.test.js +0 -73
  106. package/lib/dist/tests/features/part-repeat.test.d.ts +0 -1
  107. package/lib/dist/tests/features/part-repeat.test.js +0 -109
  108. package/server/dist/fluidcad-server.d.ts +0 -32
  109. package/server/dist/fluidcad-server.js +0 -150
  110. package/server/dist/index.d.ts +0 -1
  111. package/server/dist/index.js +0 -290
  112. package/server/dist/routes/actions.d.ts +0 -3
  113. package/server/dist/routes/actions.js +0 -100
  114. package/server/dist/routes/export.d.ts +0 -3
  115. package/server/dist/routes/export.js +0 -55
  116. package/server/dist/routes/properties.d.ts +0 -3
  117. package/server/dist/routes/properties.js +0 -46
  118. package/server/dist/routes/screenshot.d.ts +0 -2
  119. package/server/dist/routes/screenshot.js +0 -76
  120. package/server/dist/vite-manager.d.ts +0 -10
  121. package/server/dist/vite-manager.js +0 -64
  122. package/server/dist/ws-protocol.d.ts +0 -138
  123. 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
- });