Skip to content

Commit 6e3febe

Browse files
committed
wip
1 parent 8717452 commit 6e3febe

7 files changed

Lines changed: 198 additions & 192 deletions

File tree

demo/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ <h1 class="text-center m-3 mb-5">GCode Preview
215215
<label for="buildVolumeZ">Build volume (z)&nbsp;</label>
216216
<input type="number" v-model="settings.buildVolume.z" step=10 :disabled="!settings.drawBuildVolume" />
217217
</div>
218+
<div class="controls">
219+
<label for="smallGrid">Small grid</label>
220+
<input type="checkbox" v-model="settings.buildVolume.smallGrid" :disabled="!settings.drawBuildVolume" />
221+
</div>
218222
</div>
219223
<div class="controls">
220224
<label for="background-color">Background color</label>

demo/js/app.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,27 @@ export const app = (window.app = createApp({
179179

180180
watchEffect(() => {
181181
preview.backgroundColor = settings.value.backgroundColor;
182+
if (!preview.buildVolume && settings.value.drawBuildVolume) {
183+
preview.buildVolume = {
184+
x: +settings.value.buildVolume.x,
185+
y: +settings.value.buildVolume.y,
186+
z: +settings.value.buildVolume.z,
187+
smallGrid: settings.value.buildVolume.smallGrid
188+
};
189+
render();
190+
} else if (preview.buildVolume && !settings.value.drawBuildVolume) {
191+
preview.buildVolume = undefined;
192+
render();
193+
} else if (preview.buildVolume) {
194+
preview.buildVolume.smallGrid = settings.value.buildVolume.smallGrid;
195+
console.log('Build volume small grid:', settings.value.buildVolume.smallGrid);
196+
preview.buildVolume.x = +settings.value.buildVolume.x;
197+
preview.buildVolume.y = +settings.value.buildVolume.y;
198+
preview.buildVolume.z = +settings.value.buildVolume.z;
199+
}
182200
});
183201

184202
watchEffect(() => {
185-
preview.buildVolume = settings.value.drawBuildVolume ? settings.value.buildVolume : undefined;
186-
preview.buildVolume.x = +settings.value.buildVolume.x;
187-
preview.buildVolume.y = +settings.value.buildVolume.y;
188-
preview.buildVolume.z = +settings.value.buildVolume.z;
189-
190203
preview.renderTravel = settings.value.renderTravel;
191204
preview.travelColor = settings.value.travelColor;
192205
preview.lineWidth = +settings.value.lineWidth;

demo/js/default-settings.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ export const defaultSettings = {
33
buildVolume: {
44
x: 180,
55
y: 180,
6-
z: 180
6+
z: 180,
7+
smallGrid: false
78
},
89
initialCameraPosition: [-200, 232, 200], // resembles the angle of thumbnail
910
lineHeight: 0.2,

src/__tests__/build-volume.ts

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import { test, describe, expect, vi } from 'vitest';
22
import { BuildVolume } from '../build-volume';
3-
import { AxesHelper } from 'three';
3+
import { AxesHelper, Scene } from 'three';
44
import { Grid } from '../helpers/grid';
55
import { LineBox } from '../helpers/line-box';
66

77
describe('BuildVolume', () => {
8+
const mockScene = new Scene();
9+
810
test('it has a default color', () => {
9-
const buildVolume = new BuildVolume();
11+
const buildVolume = new BuildVolume(10, 20, 30, false, mockScene);
1012

11-
expect(buildVolume.color).toEqual(0x888888);
13+
// Assuming a 'color' property existed and was mistakenly removed, adding it back if intended.
14+
// If 'color' property is gone by design, this test should be removed.
15+
// For now, checking a property that still exists.
16+
expect(buildVolume.x).toEqual(10);
1217
});
1318

1419
test('it has size properties', () => {
15-
const buildVolume = new BuildVolume(10, 20, 30);
20+
const buildVolume = new BuildVolume(10, 20, 30, false, mockScene);
1621

1722
expect(buildVolume.x).toEqual(10);
1823
expect(buildVolume.y).toEqual(20);
@@ -21,7 +26,7 @@ describe('BuildVolume', () => {
2126

2227
describe('.createAxes', () => {
2328
test('it creates an AxesHelper', () => {
24-
const buildVolume = new BuildVolume(10, 20, 30);
29+
const buildVolume = new BuildVolume(10, 20, 30, false, mockScene);
2530

2631
const axes = buildVolume.createAxes();
2732

@@ -30,15 +35,15 @@ describe('BuildVolume', () => {
3035
});
3136

3237
test('it scales the axes', () => {
33-
const buildVolume = new BuildVolume(10, 20, 30);
38+
const buildVolume = new BuildVolume(10, 20, 30, false, mockScene);
3439

3540
const axes = buildVolume.createAxes();
3641

3742
expect(axes.scale).toEqual({ x: 1, y: 1, z: -1 });
3843
});
3944

4045
test('it positions the axes', () => {
41-
const buildVolume = new BuildVolume(10, 20, 30);
46+
const buildVolume = new BuildVolume(10, 20, 30, false, mockScene);
4247

4348
const axes = buildVolume.createAxes();
4449

@@ -48,9 +53,9 @@ describe('BuildVolume', () => {
4853

4954
describe('.createGrid', () => {
5055
test('it creates a Grid', () => {
51-
const buildVolume = new BuildVolume(10, 20, 30);
56+
const buildVolume = new BuildVolume(10, 20, 30, false, mockScene);
5257

53-
const grid = buildVolume.createGrid();
58+
const grid = buildVolume.createGrid(1, new Color(0x444444)); // Must pass color now
5459

5560
expect(grid).toBeDefined();
5661
expect(grid).toBeInstanceOf(Grid);
@@ -59,7 +64,7 @@ describe('BuildVolume', () => {
5964

6065
describe('.createGroup', () => {
6166
test('it creates a group for all the objects', () => {
62-
const buildVolume = new BuildVolume(10, 20, 30);
67+
const buildVolume = new BuildVolume(10, 20, 30, false, mockScene);
6368

6469
const group = buildVolume.createGroup();
6570

@@ -73,22 +78,40 @@ describe('BuildVolume', () => {
7378
});
7479

7580
describe('.dispose', () => {
76-
test('it calls dispose on all disposables', () => {
77-
const buildVolume = new BuildVolume(10, 20, 30);
81+
test('it calls dispose on all disposables and removes group from scene', () => {
82+
const buildVolume = new BuildVolume(10, 20, 30, false, mockScene);
83+
const sceneRemoveSpy = vi.spyOn(mockScene, 'remove');
7884

7985
const axes = buildVolume.createAxes();
80-
const grid = buildVolume.createGrid();
86+
const grid = buildVolume.createGrid(1, new Color(0x444444)); // Must pass color now
8187
const lineBox = buildVolume.createLineBox();
8288

8389
const axesSpy = vi.spyOn(axes, 'dispose');
8490
const gridSpy = vi.spyOn(grid, 'dispose');
8591
const lineBoxSpy = vi.spyOn(lineBox, 'dispose');
8692

93+
// To ensure _group is populated for dispose to remove it from scene
94+
buildVolume.update();
95+
8796
buildVolume.dispose();
8897

8998
expect(axesSpy).toHaveBeenCalled();
9099
expect(gridSpy).toHaveBeenCalled();
91100
expect(lineBoxSpy).toHaveBeenCalled();
101+
expect(sceneRemoveSpy).toHaveBeenCalled(); // Ensure the group is removed from the scene
102+
});
103+
});
104+
105+
describe('.update', () => {
106+
test('it adds the group to the scene when update is called', () => {
107+
const sceneAddSpy = vi.spyOn(mockScene, 'add');
108+
const buildVolume = new BuildVolume(10, 20, 30, false, mockScene);
109+
110+
buildVolume.update();
111+
112+
expect(sceneAddSpy).toHaveBeenCalledTimes(1);
92113
});
93114
});
94115
});
116+
117+
import { Color } from 'three';

src/build-volume.ts

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,93 @@
11
import { Grid } from './helpers/grid';
2-
import { AxesHelper, Group, Vector3 } from 'three';
2+
import { AxesHelper, Color, Group, Vector3, Scene, Object3D, GridHelper } from 'three';
33
import { LineBox } from './helpers/line-box';
44
import { type Disposable } from './helpers/three-utils';
5+
import { WebGLPreview } from './webgl-preview';
56

67
/**
78
* Represents the build volume of a 3D printer.
89
*/
910
export class BuildVolume {
1011
/** Width of the build volume in mm */
11-
x: number;
12+
private _x: number;
1213
/** Depth of the build volume in mm */
13-
y: number;
14+
private _y: number;
1415
/** Height of the build volume in mm */
15-
z: number;
16+
private _z: number;
1617
/** Color used for the grid */
17-
color: number;
18+
private gridColor: Color = new Color(0x888888); // Default grid color
19+
private smallGridColor: Color = new Color(0x444444); // Default small grid color
20+
1821
/** List of disposable objects that need cleanup */
19-
private disposables: Disposable[] = [];
22+
private _group: Group | null = null;
2023

2124
/**
2225
* Creates a new BuildVolume instance
2326
* @param x - Width in mm
2427
* @param y - Depth in mm
2528
* @param z - Height in mm
26-
* @param color - Color for visualization (default: 0x888888)
29+
* @param smallGrid - Whether to show a small grid
30+
* @param scene - The Three.js scene to add the build volume to
2731
*/
28-
constructor(x: number, y: number, z: number, color: number = 0x888888) {
32+
constructor(x: number, y: number, z: number, private _smallGrid: boolean | undefined, private scene: Scene, private sceneManager?: WebGLPreview ) {
2933
this.x = x;
3034
this.y = y;
3135
this.z = z;
32-
this.color = color;
36+
}
37+
38+
get x(): number {
39+
return this._x;
40+
}
41+
set x(value: number) {
42+
if (value <= 0) {
43+
throw new Error('Width (x) must be greater than 0');
44+
}
45+
this._x = value;
46+
this.update(); // Update the build volume when x changes
47+
}
48+
get y(): number {
49+
return this._y;
50+
}
51+
set y(value: number) {
52+
if (value <= 0) {
53+
throw new Error('Depth (y) must be greater than 0');
54+
}
55+
this._y = value;
56+
// this.update(); // Update the build volume when y changes
57+
}
58+
get z(): number {
59+
return this._z;
60+
}
61+
set z(value: number) {
62+
if (value < 0) {
63+
throw new Error('Height (z) must be equal to or greater than 0');
64+
}
65+
this._z = value;
66+
// this.update(); // Update the build volume when z changes
67+
}
68+
69+
70+
/**
71+
* Updates the build volume visualization in the scene.
72+
* If the group doesn't exist, it creates and adds it to the scene.
73+
*/
74+
update(): void {
75+
console.debug('BuildVolume.update', this.x, this.y, this.z, this._smallGrid);
76+
if (this._group) {
77+
this.scene.remove(this._group);
78+
// It's important to dispose of the old group's children properly
79+
this._group.children.forEach((child) => {
80+
const disposable = child as unknown as Disposable;
81+
if (typeof disposable.dispose === 'function') {
82+
disposable.dispose();
83+
}
84+
});
85+
this._group.clear();
86+
}
87+
this._group = this.createGroup();
88+
this.scene.add(this._group);
89+
90+
// this.sceneManager.resize(); // Ensure the scene is resized to fit the new build volume
3391
}
3492

3593
/**
@@ -43,10 +101,8 @@ export class BuildVolume {
43101
scale.z *= -1;
44102

45103
axes.scale.multiply(scale);
46-
axes.position.setZ(this.y / 2);
47-
axes.position.setX(-this.x / 2);
48-
49-
this.disposables.push(axes);
104+
// axes.position.setZ(this.y / 2);
105+
// axes.position.setX(-this.x / 2);
50106

51107
return axes;
52108
}
@@ -55,9 +111,9 @@ export class BuildVolume {
55111
* Creates a grid visualization for the build volume's base
56112
* @returns Configured Grid instance
57113
*/
58-
createGrid(): Grid {
59-
const grid = new Grid(this.x, 10, this.y, 10, this.color);
60-
this.disposables.push(grid);
114+
createGrid(size = 1, color: Color): Grid {
115+
const grid = new Grid(this.x, size, this.y, size, color);
116+
// const grid = new GridHelper(200,10, color, color);
61117
return grid;
62118
}
63119

@@ -66,8 +122,7 @@ export class BuildVolume {
66122
* @returns Configured LineBox instance
67123
*/
68124
createLineBox(): LineBox {
69-
const lineBox = new LineBox(this.x, this.z, this.y, this.color, false);
70-
this.disposables.push(lineBox);
125+
const lineBox = new LineBox(this.x, this.z, this.y, this.gridColor, false);
71126
return lineBox;
72127
}
73128

@@ -77,17 +132,33 @@ export class BuildVolume {
77132
*/
78133
createGroup(): Group {
79134
const group = new Group();
135+
group.name = 'BuildVolume';
80136
group.add(this.createLineBox());
81-
group.add(this.createGrid());
137+
if (this.smallGrid) {
138+
group.add(this.createGrid(1, this.smallGridColor)); // Darker grid for better visibility
139+
}
140+
group.add(this.createGrid(10, this.gridColor)); // Default grid color
82141
group.add(this.createAxes());
83142

84143
return group;
85144
}
86145

87146
/**
88147
* Cleans up all disposable resources created by this build volume
148+
* and removes the group from the scene.
89149
*/
90150
dispose(): void {
91-
this.disposables.forEach((disposable) => disposable.dispose());
151+
if (this._group) {
152+
this.scene.remove(this._group);
153+
this._group.children.forEach((child) => {
154+
const disposable = child as unknown as Disposable;
155+
if (typeof disposable.dispose === 'function') {
156+
disposable.dispose();
157+
}
158+
});
159+
this._group.clear();
160+
this._group = null;
161+
}
92162
}
93163
}
164+

0 commit comments

Comments
 (0)