fluidcad 0.0.26 → 0.0.28
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/lib/dist/common/scene-object.d.ts +45 -0
- package/lib/dist/common/scene-object.js +121 -0
- package/lib/dist/common/shape-factory.d.ts +1 -1
- package/lib/dist/common/shape-history-tracker.d.ts +35 -0
- package/lib/dist/common/shape-history-tracker.js +114 -0
- package/lib/dist/common/shape.js +7 -1
- package/lib/dist/common/shapes.d.ts +0 -1
- package/lib/dist/common/shapes.js +0 -1
- package/lib/dist/common/solid.js +5 -1
- package/lib/dist/core/extrude.d.ts +12 -13
- package/lib/dist/core/extrude.js +19 -1
- package/lib/dist/core/part.d.ts +2 -1
- package/lib/dist/core/part.js +4 -1
- package/lib/dist/core/sketch.d.ts +4 -3
- package/lib/dist/core/sketch.js +4 -1
- package/lib/dist/features/chamfer.js +12 -6
- package/lib/dist/features/extrude-base.d.ts +43 -1
- package/lib/dist/features/extrude-base.js +141 -36
- package/lib/dist/features/extrude-to-face.d.ts +1 -1
- package/lib/dist/features/extrude-to-face.js +42 -19
- package/lib/dist/features/extrude-two-distances.d.ts +1 -1
- package/lib/dist/features/extrude-two-distances.js +41 -15
- package/lib/dist/features/extrude.d.ts +1 -1
- package/lib/dist/features/extrude.js +75 -20
- package/lib/dist/features/fillet.js +3 -4
- package/lib/dist/features/fuse.js +14 -0
- package/lib/dist/features/infinite-extrude.d.ts +1 -0
- package/lib/dist/features/infinite-extrude.js +33 -4
- package/lib/dist/features/loft.js +18 -5
- package/lib/dist/features/mirror-shape.d.ts +1 -3
- package/lib/dist/features/mirror-shape.js +2 -1
- package/lib/dist/features/revolve.js +17 -4
- package/lib/dist/features/rotate.js +1 -0
- package/lib/dist/features/simple-extruder.js +5 -0
- package/lib/dist/features/sweep.js +13 -2
- package/lib/dist/features/translate.js +3 -1
- package/lib/dist/filters/face/face-filter.d.ts +12 -0
- package/lib/dist/filters/face/face-filter.js +21 -0
- package/lib/dist/filters/face/torus-filter.d.ts +19 -0
- package/lib/dist/filters/face/torus-filter.js +38 -0
- package/lib/dist/helpers/scene-helpers.d.ts +10 -2
- package/lib/dist/helpers/scene-helpers.js +278 -10
- package/lib/dist/index.d.ts +1 -0
- package/lib/dist/oc/boolean-ops.d.ts +32 -4
- package/lib/dist/oc/boolean-ops.js +122 -11
- package/lib/dist/oc/color-transfer.d.ts +37 -0
- package/lib/dist/oc/color-transfer.js +135 -0
- package/lib/dist/oc/extrude-ops.js +25 -3
- package/lib/dist/oc/face-ops.d.ts +0 -1
- package/lib/dist/oc/face-ops.js +0 -13
- package/lib/dist/oc/face-query.d.ts +2 -0
- package/lib/dist/oc/face-query.js +30 -0
- package/lib/dist/oc/fillet-ops.d.ts +5 -3
- package/lib/dist/oc/fillet-ops.js +107 -70
- package/lib/dist/oc/intersection.js +6 -3
- package/lib/dist/oc/mesh.d.ts +25 -2
- package/lib/dist/oc/mesh.js +112 -35
- package/lib/dist/oc/shape-ops.d.ts +25 -20
- package/lib/dist/oc/shape-ops.js +129 -113
- package/lib/dist/rendering/mesh-transform.js +17 -1
- package/lib/dist/rendering/render-solid.js +19 -6
- package/lib/dist/rendering/render-wire.js +2 -0
- package/lib/dist/rendering/render.d.ts +12 -2
- package/lib/dist/rendering/render.js +195 -220
- package/lib/dist/scene-manager.d.ts +2 -0
- package/lib/dist/scene-manager.js +4 -3
- package/lib/dist/tests/common/scene-object-history.test.d.ts +1 -0
- package/lib/dist/tests/common/scene-object-history.test.js +274 -0
- package/lib/dist/tests/common/shape-history-tracker.test.d.ts +1 -0
- package/lib/dist/tests/common/shape-history-tracker.test.js +110 -0
- package/lib/dist/tests/features/2d/project-regression.test.d.ts +1 -0
- package/lib/dist/tests/features/2d/project-regression.test.js +69 -0
- package/lib/dist/tests/features/2d/project-user-regression.test.d.ts +1 -0
- package/lib/dist/tests/features/2d/project-user-regression.test.js +37 -0
- package/lib/dist/tests/features/color-lineage.test.d.ts +1 -0
- package/lib/dist/tests/features/color-lineage.test.js +213 -0
- package/lib/dist/tests/features/cut-symmetric-through-all.test.d.ts +1 -0
- package/lib/dist/tests/features/cut-symmetric-through-all.test.js +32 -0
- package/lib/dist/tests/features/extrude-history.test.d.ts +1 -0
- package/lib/dist/tests/features/extrude-history.test.js +248 -0
- package/lib/dist/tests/features/extrude.test.js +71 -0
- package/lib/dist/tests/features/fillet2d.test.js +16 -1
- package/lib/dist/tests/features/peer-ops-history.test.d.ts +1 -0
- package/lib/dist/tests/features/peer-ops-history.test.js +119 -0
- package/lib/dist/tests/features/select.test.js +50 -0
- package/lib/dist/tests/features/subtract.test.js +21 -1
- package/lib/dist/tests/setup.js +3 -2
- package/lib/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/ui/dist/assets/{index-BeLxRMCv.js → index-BrW_x4uc.js} +37 -37
- package/ui/dist/index.html +1 -1
- package/lib/dist/common/solid-face.d.ts +0 -9
- package/lib/dist/common/solid-face.js +0 -22
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { setupOC, render } from "../setup.js";
|
|
3
|
+
import sketch from "../../core/sketch.js";
|
|
4
|
+
import revolve from "../../core/revolve.js";
|
|
5
|
+
import sweep from "../../core/sweep.js";
|
|
6
|
+
import loft from "../../core/loft.js";
|
|
7
|
+
import extrude from "../../core/extrude.js";
|
|
8
|
+
import cylinder from "../../core/cylinder.js";
|
|
9
|
+
import plane from "../../core/plane.js";
|
|
10
|
+
import { move, rect, circle, vLine } from "../../core/2d/index.js";
|
|
11
|
+
describe("Revolve — history tracking", () => {
|
|
12
|
+
setupOC();
|
|
13
|
+
it("records added faces/edges and finalShapes on a plain revolve into empty scene", () => {
|
|
14
|
+
sketch("xz", () => {
|
|
15
|
+
move([20, 0]);
|
|
16
|
+
rect(10, 30);
|
|
17
|
+
});
|
|
18
|
+
const r = revolve("z");
|
|
19
|
+
render();
|
|
20
|
+
expect(r.getAddedFaces().length).toBeGreaterThan(0);
|
|
21
|
+
expect(r.getAddedEdges().length).toBeGreaterThan(0);
|
|
22
|
+
expect(r.getModifiedFaces()).toEqual([]);
|
|
23
|
+
expect(r.getRemovedFaces()).toEqual([]);
|
|
24
|
+
expect(r.getFinalShapes().length).toBeGreaterThan(0);
|
|
25
|
+
});
|
|
26
|
+
it("pre-computes edge categories in state after revolve build", () => {
|
|
27
|
+
sketch("xz", () => {
|
|
28
|
+
move([20, 0]);
|
|
29
|
+
rect(10, 30);
|
|
30
|
+
});
|
|
31
|
+
const r = revolve("z", 90);
|
|
32
|
+
render();
|
|
33
|
+
expect(r.getState('start-edges')).toBeDefined();
|
|
34
|
+
expect(r.getState('end-edges')).toBeDefined();
|
|
35
|
+
expect(r.getState('side-edges')).toBeDefined();
|
|
36
|
+
});
|
|
37
|
+
it("attributes modifications to the scene object when revolve fuses with it", () => {
|
|
38
|
+
const c = cylinder(30, 40);
|
|
39
|
+
sketch("xz", () => {
|
|
40
|
+
move([20, 0]);
|
|
41
|
+
rect(8, 20);
|
|
42
|
+
});
|
|
43
|
+
const r = revolve("z");
|
|
44
|
+
render();
|
|
45
|
+
const modified = c.getModifiedFaces();
|
|
46
|
+
expect(modified.length).toBeGreaterThan(0);
|
|
47
|
+
for (const record of modified) {
|
|
48
|
+
expect(record.modifiedBy).toBe(r);
|
|
49
|
+
}
|
|
50
|
+
expect(r.getAddedFaces().length).toBeGreaterThan(0);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe("Sweep — history tracking", () => {
|
|
54
|
+
setupOC();
|
|
55
|
+
it("records added faces/edges and finalShapes on a plain sweep into empty scene", () => {
|
|
56
|
+
const profile = sketch("xy", () => {
|
|
57
|
+
circle(10);
|
|
58
|
+
});
|
|
59
|
+
const path = sketch("xz", () => {
|
|
60
|
+
vLine(50);
|
|
61
|
+
});
|
|
62
|
+
const s = sweep(path, profile);
|
|
63
|
+
render();
|
|
64
|
+
expect(s.getAddedFaces().length).toBeGreaterThan(0);
|
|
65
|
+
expect(s.getAddedEdges().length).toBeGreaterThan(0);
|
|
66
|
+
expect(s.getFinalShapes().length).toBeGreaterThan(0);
|
|
67
|
+
expect(s.getState('side-edges')).toBeDefined();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe("Loft — history tracking", () => {
|
|
71
|
+
setupOC();
|
|
72
|
+
it("records added faces/edges and finalShapes on a plain loft into empty scene", () => {
|
|
73
|
+
const s1 = sketch("xy", () => {
|
|
74
|
+
rect(20, 20);
|
|
75
|
+
});
|
|
76
|
+
const p = plane("xy", { offset: 50 });
|
|
77
|
+
const s2 = sketch(p, () => {
|
|
78
|
+
circle(10);
|
|
79
|
+
});
|
|
80
|
+
const l = loft(s1, s2);
|
|
81
|
+
render();
|
|
82
|
+
expect(l.getAddedFaces().length).toBeGreaterThan(0);
|
|
83
|
+
expect(l.getAddedEdges().length).toBeGreaterThan(0);
|
|
84
|
+
expect(l.getFinalShapes().length).toBeGreaterThan(0);
|
|
85
|
+
expect(l.getState('side-edges')).toBeDefined();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe("ExtrudeToFace — history tracking", () => {
|
|
89
|
+
setupOC();
|
|
90
|
+
it("records added faces/edges and finalShapes into empty scene via 'last-face'", () => {
|
|
91
|
+
sketch("xy", () => {
|
|
92
|
+
rect(100, 50);
|
|
93
|
+
});
|
|
94
|
+
extrude(30);
|
|
95
|
+
sketch("xy", () => {
|
|
96
|
+
rect(20, 20);
|
|
97
|
+
});
|
|
98
|
+
const e = extrude("last-face");
|
|
99
|
+
render();
|
|
100
|
+
expect(e.getAddedFaces().length).toBeGreaterThan(0);
|
|
101
|
+
expect(e.getAddedEdges().length).toBeGreaterThan(0);
|
|
102
|
+
expect(e.getFinalShapes().length).toBeGreaterThan(0);
|
|
103
|
+
expect(e.getState('side-edges')).toBeDefined();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe("ExtrudeTwoDistances — history tracking", () => {
|
|
107
|
+
setupOC();
|
|
108
|
+
it("records added faces/edges and finalShapes into empty scene", () => {
|
|
109
|
+
sketch("xy", () => {
|
|
110
|
+
rect(40, 30);
|
|
111
|
+
});
|
|
112
|
+
const e2 = extrude(20, 10);
|
|
113
|
+
render();
|
|
114
|
+
expect(e2.getAddedFaces().length).toBeGreaterThan(0);
|
|
115
|
+
expect(e2.getAddedEdges().length).toBeGreaterThan(0);
|
|
116
|
+
expect(e2.getFinalShapes().length).toBeGreaterThan(0);
|
|
117
|
+
expect(e2.getState('side-edges')).toBeDefined();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -4,6 +4,7 @@ import sketch from "../../core/sketch.js";
|
|
|
4
4
|
import extrude from "../../core/extrude.js";
|
|
5
5
|
import select from "../../core/select.js";
|
|
6
6
|
import cylinder from "../../core/cylinder.js";
|
|
7
|
+
import fillet from "../../core/fillet.js";
|
|
7
8
|
import { circle, move, rect } from "../../core/2d/index.js";
|
|
8
9
|
import { face, edge } from "../../filters/index.js";
|
|
9
10
|
describe("select", () => {
|
|
@@ -177,6 +178,55 @@ describe("select", () => {
|
|
|
177
178
|
expect(shapes).toHaveLength(2);
|
|
178
179
|
});
|
|
179
180
|
});
|
|
181
|
+
describe("torus / notTorus", () => {
|
|
182
|
+
// Filleting the top edge of a cylinder produces a canonical GeomAbs_Torus face.
|
|
183
|
+
// For cylinder(radius=30, height=50) with fillet(5): major=25, minor=5.
|
|
184
|
+
const makeFilletedCylinder = () => {
|
|
185
|
+
cylinder(30, 50);
|
|
186
|
+
select(edge().onPlane("xy", 50));
|
|
187
|
+
fillet(5);
|
|
188
|
+
};
|
|
189
|
+
it("should select the toroidal face from a filleted cylinder edge", () => {
|
|
190
|
+
makeFilletedCylinder();
|
|
191
|
+
const sel = select(face().torus());
|
|
192
|
+
render();
|
|
193
|
+
const shapes = sel.getShapes();
|
|
194
|
+
expect(shapes).toHaveLength(1);
|
|
195
|
+
expect(shapes[0].getType()).toBe("face");
|
|
196
|
+
});
|
|
197
|
+
it("should match a torus by both major and minor radius", () => {
|
|
198
|
+
makeFilletedCylinder();
|
|
199
|
+
const sel = select(face().torus(25, 5));
|
|
200
|
+
render();
|
|
201
|
+
expect(sel.getShapes()).toHaveLength(1);
|
|
202
|
+
});
|
|
203
|
+
it("should match a torus by major radius only", () => {
|
|
204
|
+
makeFilletedCylinder();
|
|
205
|
+
const sel = select(face().torus(25));
|
|
206
|
+
render();
|
|
207
|
+
expect(sel.getShapes()).toHaveLength(1);
|
|
208
|
+
});
|
|
209
|
+
it("should match a torus by minor radius only", () => {
|
|
210
|
+
makeFilletedCylinder();
|
|
211
|
+
const sel = select(face().torus(undefined, 5));
|
|
212
|
+
render();
|
|
213
|
+
expect(sel.getShapes()).toHaveLength(1);
|
|
214
|
+
});
|
|
215
|
+
it("should not match a torus with the wrong major radius", () => {
|
|
216
|
+
makeFilletedCylinder();
|
|
217
|
+
const sel = select(face().torus(999));
|
|
218
|
+
render();
|
|
219
|
+
expect(sel.getShapes()).toHaveLength(0);
|
|
220
|
+
});
|
|
221
|
+
it("should exclude toroidal faces via notTorus", () => {
|
|
222
|
+
makeFilletedCylinder();
|
|
223
|
+
const sel = select(face().notTorus());
|
|
224
|
+
render();
|
|
225
|
+
// Filleted cylinder has 4 faces (side cylinder, top/bottom circles, torus fillet).
|
|
226
|
+
// Excluding the torus leaves 3.
|
|
227
|
+
expect(sel.getShapes()).toHaveLength(3);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
180
230
|
describe("cone / notCone", () => {
|
|
181
231
|
it("should select conical faces from a drafted extrusion", () => {
|
|
182
232
|
sketch("xy", () => {
|
|
@@ -4,7 +4,10 @@ import sketch from "../../core/sketch.js";
|
|
|
4
4
|
import extrude from "../../core/extrude.js";
|
|
5
5
|
import subtract from "../../core/subtract.js";
|
|
6
6
|
import cylinder from "../../core/cylinder.js";
|
|
7
|
-
import
|
|
7
|
+
import sphere from "../../core/sphere.js";
|
|
8
|
+
import axis from "../../core/axis.js";
|
|
9
|
+
import revolve from "../../core/revolve.js";
|
|
10
|
+
import { circle, move, rect } from "../../core/2d/index.js";
|
|
8
11
|
import { countShapes } from "../utils.js";
|
|
9
12
|
import { ShapeOps } from "../../oc/shape-ops.js";
|
|
10
13
|
describe("subtract", () => {
|
|
@@ -99,5 +102,22 @@ describe("subtract", () => {
|
|
|
99
102
|
const solid = shapes[0];
|
|
100
103
|
expect(solid.getFaces()).toHaveLength(6);
|
|
101
104
|
});
|
|
105
|
+
// Repro for issue #46: a torus revolved on the -yz plane produced an
|
|
106
|
+
// inside-out solid that caused subtract() to silently fail.
|
|
107
|
+
it("should subtract a revolved torus built on the -yz plane", () => {
|
|
108
|
+
const s = sphere(10);
|
|
109
|
+
const a = axis("y", { offsetZ: 20 });
|
|
110
|
+
sketch("-yz", () => {
|
|
111
|
+
circle([0, 1], 5);
|
|
112
|
+
});
|
|
113
|
+
const ringHole = revolve(a).new();
|
|
114
|
+
const result = subtract(s, ringHole);
|
|
115
|
+
render();
|
|
116
|
+
// Sphere (r=10) and torus (centered at z=20, tube r=5) don't intersect,
|
|
117
|
+
// so the subtract should leave the sphere intact.
|
|
118
|
+
const shapes = result.getShapes();
|
|
119
|
+
expect(shapes).toHaveLength(1);
|
|
120
|
+
expect(shapes[0].getType()).toBe("solid");
|
|
121
|
+
});
|
|
102
122
|
});
|
|
103
123
|
});
|
package/lib/dist/tests/setup.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { beforeEach } from "vitest";
|
|
2
2
|
import { getSceneManager, getCurrentScene } from "../scene-manager.js";
|
|
3
|
-
import {
|
|
3
|
+
import { SceneRenderer } from "../rendering/render.js";
|
|
4
|
+
const renderer = new SceneRenderer();
|
|
4
5
|
export function setupOC() {
|
|
5
6
|
beforeEach(() => {
|
|
6
7
|
getSceneManager().startScene();
|
|
7
8
|
});
|
|
8
9
|
}
|
|
9
10
|
export function render() {
|
|
10
|
-
return
|
|
11
|
+
return renderer.render(getCurrentScene());
|
|
11
12
|
}
|
|
12
13
|
export function addToScene(obj) {
|
|
13
14
|
getCurrentScene().addSceneObject(obj);
|