Skip to content

Commit c6e0942

Browse files
committed
Make layers 100% progressive rendering ready
1 parent 0276f7a commit c6e0942

4 files changed

Lines changed: 318 additions & 192 deletions

File tree

src/__tests__/interpreter.ts

Lines changed: 190 additions & 188 deletions
Original file line numberDiff line numberDiff line change
@@ -1,200 +1,202 @@
1-
import { test, expect } from 'vitest';
1+
import { test, expect, describe } from 'vitest';
22
import { GCodeCommand } from '../gcode-parser';
33
import { Interpreter } from '../interpreter';
44
import { Job } from '../job';
55
import { PathType } from '../path';
66

7-
test('.execute returns a stateful job', () => {
8-
const command = new GCodeCommand('G0 X1 Y2 Z3', 'g0', { x: 1, y: 2, z: 3 });
9-
const interpreter = new Interpreter();
10-
11-
const result = interpreter.execute([command]);
12-
13-
expect(result).not.toBeNull();
14-
expect(result).toBeInstanceOf(Job);
15-
expect(result.state.x).toEqual(1);
16-
expect(result.state.y).toEqual(2);
17-
expect(result.state.z).toEqual(3);
18-
});
19-
20-
test('.execute ignores unknown commands', () => {
21-
const command = new GCodeCommand('G42', 'g42', {});
22-
const interpreter = new Interpreter();
23-
24-
const result = interpreter.execute([command]);
25-
26-
expect(result).not.toBeNull();
27-
expect(result).toBeInstanceOf(Job);
28-
expect(result.state.x).toEqual(0);
29-
expect(result.state.y).toEqual(0);
30-
expect(result.state.z).toEqual(0);
31-
});
32-
33-
test('.execute runs multiple commands', () => {
34-
const command1 = new GCodeCommand('G0 X1 Y2 Z3', 'g0', { x: 1, y: 2, z: 3 });
35-
const command2 = new GCodeCommand('G0 X4 Y5 Z6', 'g0', { x: 4, y: 5, z: 6 });
36-
const interpreter = new Interpreter();
37-
38-
const result = interpreter.execute([command1, command2, command1, command2]);
39-
40-
expect(result).not.toBeNull();
41-
expect(result).toBeInstanceOf(Job);
42-
expect(result.state.x).toEqual(4);
43-
expect(result.state.y).toEqual(5);
44-
expect(result.state.z).toEqual(6);
45-
});
46-
47-
test('.execute runs on an existing job', () => {
48-
const job = new Job();
49-
const command = new GCodeCommand('G0 X1 Y2 Z3', 'g0', { x: 1, y: 2, z: 3 });
50-
const interpreter = new Interpreter();
51-
52-
const result = interpreter.execute([command], job);
53-
54-
expect(result).toEqual(job);
55-
expect(result.state.x).toEqual(1);
56-
expect(result.state.y).toEqual(2);
57-
expect(result.state.z).toEqual(3);
58-
});
59-
60-
test('.G0 moves the state to the new position', () => {
61-
const command = new GCodeCommand('G0 X1 Y2 Z3', 'g0', { x: 1, y: 2, z: 3 });
62-
const interpreter = new Interpreter();
63-
64-
const job = interpreter.execute([command]);
65-
66-
expect(job.state.x).toEqual(1);
67-
expect(job.state.y).toEqual(2);
68-
expect(job.state.z).toEqual(3);
69-
});
70-
71-
test('.G0 starts a path if the job has none', () => {
72-
const command = new GCodeCommand('G0 X1 Y2', 'g0', { x: 1, y: 2 });
73-
const interpreter = new Interpreter();
74-
75-
const job = interpreter.execute([command]);
76-
77-
expect(job.paths.length).toEqual(0);
78-
expect(job.inprogressPath).not.toBeNull();
79-
expect(job.inprogressPath?.vertices.length).toEqual(6);
80-
expect(job.inprogressPath?.vertices[0]).toEqual(0);
81-
expect(job.inprogressPath?.vertices[1]).toEqual(0);
82-
expect(job.inprogressPath?.vertices[2]).toEqual(0);
83-
expect(job.inprogressPath?.vertices[3]).toEqual(1);
84-
expect(job.inprogressPath?.vertices[4]).toEqual(2);
85-
expect(job.inprogressPath?.vertices[5]).toEqual(0);
86-
});
87-
88-
test('.G0 starts a path if the job has none, starting at the job current state', () => {
89-
const command = new GCodeCommand('G0 X1 Y2', 'g0', { x: 1, y: 2 });
90-
const interpreter = new Interpreter();
91-
const job = new Job();
92-
job.state.x = 3;
93-
job.state.y = 4;
94-
job.state.tool = 5;
95-
96-
interpreter.execute([command], job);
97-
98-
expect(job.paths.length).toEqual(0);
99-
expect(job.inprogressPath?.vertices.length).toEqual(6);
100-
expect(job.inprogressPath?.vertices[0]).toEqual(3);
101-
expect(job.inprogressPath?.vertices[1]).toEqual(4);
102-
expect(job.inprogressPath?.vertices[2]).toEqual(0);
103-
expect(job.inprogressPath?.tool).toEqual(5);
7+
describe('.execute', () => {
8+
test('returns a stateful job', () => {
9+
const command = new GCodeCommand('G0 X1 Y2 Z3', 'g0', { x: 1, y: 2, z: 3 });
10+
const interpreter = new Interpreter();
11+
12+
const result = interpreter.execute([command]);
13+
14+
expect(result).not.toBeNull();
15+
expect(result).toBeInstanceOf(Job);
16+
expect(result.state.x).toEqual(1);
17+
expect(result.state.y).toEqual(2);
18+
expect(result.state.z).toEqual(3);
19+
});
20+
21+
test('ignores unknown commands', () => {
22+
const command = new GCodeCommand('G42', 'g42', {});
23+
const interpreter = new Interpreter();
24+
25+
const result = interpreter.execute([command]);
26+
27+
expect(result).not.toBeNull();
28+
expect(result).toBeInstanceOf(Job);
29+
expect(result.state.x).toEqual(0);
30+
expect(result.state.y).toEqual(0);
31+
expect(result.state.z).toEqual(0);
32+
});
33+
34+
test('runs multiple commands', () => {
35+
const command1 = new GCodeCommand('G0 X1 Y2 Z3', 'g0', { x: 1, y: 2, z: 3 });
36+
const command2 = new GCodeCommand('G0 X4 Y5 Z6', 'g0', { x: 4, y: 5, z: 6 });
37+
const interpreter = new Interpreter();
38+
39+
const result = interpreter.execute([command1, command2, command1, command2]);
40+
41+
expect(result).not.toBeNull();
42+
expect(result).toBeInstanceOf(Job);
43+
expect(result.state.x).toEqual(4);
44+
expect(result.state.y).toEqual(5);
45+
expect(result.state.z).toEqual(6);
46+
});
47+
48+
test('runs on an existing job', () => {
49+
const job = new Job();
50+
const command = new GCodeCommand('G0 X1 Y2 Z3', 'g0', { x: 1, y: 2, z: 3 });
51+
const interpreter = new Interpreter();
52+
53+
const result = interpreter.execute([command], job);
54+
55+
expect(result).toEqual(job);
56+
expect(result.state.x).toEqual(1);
57+
expect(result.state.y).toEqual(2);
58+
expect(result.state.z).toEqual(3);
59+
});
60+
61+
test('finishes the current path at the end of the job', () => {
62+
const job = new Job();
63+
const command = new GCodeCommand('G0 X1 Y2 Z3', 'g0', { x: 1, y: 2, z: 3 });
64+
const interpreter = new Interpreter();
65+
interpreter.execute([command], job);
66+
67+
expect(job.paths.length).toEqual(1);
68+
expect(job.inprogressPath).toBeUndefined();
69+
});
70+
71+
test('resumes the current path when doing incremental execution', () => {
72+
const job = new Job();
73+
const command1 = new GCodeCommand('G0 X1 Y2 Z3', 'g0', { x: 1, y: 2, z: 3 });
74+
const command2 = new GCodeCommand('G0 X4 Y5 Z6', 'g0', { x: 4, y: 5, z: 6 });
75+
const interpreter = new Interpreter();
76+
77+
interpreter.execute([command1], job);
78+
interpreter.execute([command2], job);
79+
80+
expect(job.paths.length).toEqual(1);
81+
expect(job.paths[0].vertices.length).toEqual(9);
82+
expect(job.paths[0].vertices[6]).toEqual(command2.params.x);
83+
expect(job.paths[0].vertices[7]).toEqual(command2.params.y);
84+
expect(job.paths[0].vertices[8]).toEqual(command2.params.z);
85+
});
10486
});
10587

106-
test('.G0 continues the path if the job has one', () => {
107-
const command1 = new GCodeCommand('G0 X1 Y2', 'g0', { x: 1, y: 2 });
108-
const command2 = new GCodeCommand('G0 X3 Y4', 'g0', { x: 3, y: 4 });
109-
const interpreter = new Interpreter();
110-
const job = new Job();
111-
112-
job.state.z = 5;
113-
interpreter.execute([command1], job);
114-
115-
interpreter.g0(command2, job);
88+
describe('.g0', () => {
89+
test('starts a path if the job has none, starting at the job current state', () => {
90+
const command = new GCodeCommand('G0 X1 Y2', 'g0', { x: 1, y: 2 });
91+
const interpreter = new Interpreter();
92+
const job = new Job();
93+
job.state.x = 3;
94+
job.state.y = 4;
95+
job.state.tool = 5;
96+
97+
interpreter.g0(command, job);
98+
99+
expect(job.paths.length).toEqual(0);
100+
expect(job.inprogressPath?.vertices.length).toEqual(6);
101+
expect(job.inprogressPath?.vertices[0]).toEqual(3);
102+
expect(job.inprogressPath?.vertices[1]).toEqual(4);
103+
expect(job.inprogressPath?.vertices[2]).toEqual(0);
104+
expect(job.inprogressPath?.tool).toEqual(5);
105+
});
106+
107+
test('continues the path if the job has one', () => {
108+
const command1 = new GCodeCommand('G0 X1 Y2', 'g0', { x: 1, y: 2 });
109+
const command2 = new GCodeCommand('G0 X3 Y4', 'g0', { x: 3, y: 4 });
110+
const interpreter = new Interpreter();
111+
const job = new Job();
112+
113+
job.state.z = 5;
114+
interpreter.g0(command1, job);
115+
116+
interpreter.g0(command2, job);
117+
118+
expect(job.paths.length).toEqual(0);
119+
expect(job.inprogressPath?.vertices.length).toEqual(9);
120+
expect(job.inprogressPath?.vertices[6]).toEqual(command2.params.x);
121+
expect(job.inprogressPath?.vertices[7]).toEqual(command2.params.y);
122+
expect(job.inprogressPath?.vertices[8]).toEqual(job.state.z);
123+
});
124+
125+
test("assigns the travel type if there's no extrusion", () => {
126+
const command = new GCodeCommand('G0 X1 Y2', 'g0', { x: 1, y: 2 });
127+
const interpreter = new Interpreter();
128+
const job = new Job();
129+
130+
interpreter.g0(command, job);
131+
132+
expect(job.paths.length).toEqual(0);
133+
expect(job.inprogressPath?.travelType).toEqual(PathType.Travel);
134+
});
135+
136+
test("assigns the extrusion type if there's extrusion", () => {
137+
const command = new GCodeCommand('G1 X1 Y2 E3', 'g1', { x: 1, y: 2, e: 3 });
138+
const interpreter = new Interpreter();
139+
const job = new Job();
140+
141+
interpreter.g0(command, job);
142+
143+
expect(job.paths.length).toEqual(0);
144+
expect(job.inprogressPath?.travelType).toEqual('Extrusion');
145+
});
146+
147+
test('assigns the travel type if the extrusion is a retraction', () => {
148+
const command = new GCodeCommand('G0 E-2', 'g0', { e: -2 });
149+
const interpreter = new Interpreter();
150+
const job = new Job();
151+
152+
interpreter.g0(command, job);
153+
154+
expect(job.paths.length).toEqual(0);
155+
expect(job.inprogressPath?.travelType).toEqual('Travel');
156+
});
157+
158+
test('assigns the travel type if the extrusion is a retraction', () => {
159+
const command = new GCodeCommand('G0 E-2', 'g0', { e: -2 });
160+
const interpreter = new Interpreter();
161+
const job = new Job();
162+
163+
interpreter.g0(command, job);
164+
165+
expect(job.paths.length).toEqual(0);
166+
expect(job.inprogressPath?.travelType).toEqual('Travel');
167+
});
168+
169+
test('starts a new path if the travel type changes from Travel to Extrusion', () => {
170+
const command1 = new GCodeCommand('G0 X1 Y2', 'g0', { x: 1, y: 2 });
171+
const command2 = new GCodeCommand('G1 X3 Y4 E5', 'g1', { x: 3, y: 4, e: 5 });
172+
const interpreter = new Interpreter();
173+
const job = new Job();
174+
interpreter.execute([command1], job);
175+
176+
interpreter.g0(command2, job);
177+
178+
expect(job.paths.length).toEqual(1);
179+
expect(job.inprogressPath?.travelType).toEqual('Extrusion');
180+
});
181+
182+
test('starts a new path if the travel type changes from Extrusion to Travel', () => {
183+
const command1 = new GCodeCommand('G1 X1 Y2 E3', 'g1', { x: 1, y: 2, e: 3 });
184+
const command2 = new GCodeCommand('G0 X3 Y4', 'g0', { x: 3, y: 4 });
185+
const interpreter = new Interpreter();
186+
const job = new Job();
187+
interpreter.execute([command1], job);
188+
189+
interpreter.g0(command2, job);
190+
191+
expect(job.paths.length).toEqual(1);
192+
expect(job.inprogressPath?.travelType).toEqual('Travel');
193+
});
116194

117-
expect(job.paths.length).toEqual(0);
118-
expect(job.inprogressPath?.vertices.length).toEqual(9);
119-
expect(job.inprogressPath?.vertices[6]).toEqual(3);
120-
expect(job.inprogressPath?.vertices[7]).toEqual(4);
121-
expect(job.inprogressPath?.vertices[8]).toEqual(5);
122-
});
123-
124-
test(".G0 assigns the travel type if there's no extrusion", () => {
125-
const command = new GCodeCommand('G0 X1 Y2', 'g0', { x: 1, y: 2 });
126-
const interpreter = new Interpreter();
127-
const job = new Job();
128-
129-
interpreter.g0(command, job);
130-
131-
expect(job.paths.length).toEqual(0);
132-
expect(job.inprogressPath?.travelType).toEqual(PathType.Travel);
133-
});
134-
135-
test(".G0 assigns the extrusion type if there's extrusion", () => {
136-
const command = new GCodeCommand('G1 X1 Y2 E3', 'g1', { x: 1, y: 2, e: 3 });
137-
const interpreter = new Interpreter();
138-
const job = new Job();
139-
140-
interpreter.g0(command, job);
141-
142-
expect(job.paths.length).toEqual(0);
143-
expect(job.inprogressPath?.travelType).toEqual('Extrusion');
144-
});
145-
146-
test('.G0 assigns the travel type if the extrusion is a retraction', () => {
147-
const command = new GCodeCommand('G0 E-2', 'g0', { e: -2 });
148-
const interpreter = new Interpreter();
149-
const job = new Job();
150-
151-
interpreter.g0(command, job);
152-
153-
expect(job.paths.length).toEqual(0);
154-
expect(job.inprogressPath?.travelType).toEqual('Travel');
155-
});
156-
157-
test('.G0 assigns the travel type if the extrusion is a retraction', () => {
158-
const command = new GCodeCommand('G0 E-2', 'g0', { e: -2 });
159-
const interpreter = new Interpreter();
160-
const job = new Job();
161-
162-
interpreter.g0(command, job);
163-
164-
expect(job.paths.length).toEqual(0);
165-
expect(job.inprogressPath?.travelType).toEqual('Travel');
166-
});
167-
168-
test('.G0 starts a new path if the travel type changes from Travel to Extrusion', () => {
169-
const command1 = new GCodeCommand('G0 X1 Y2', 'g0', { x: 1, y: 2 });
170-
const command2 = new GCodeCommand('G1 X3 Y4 E5', 'g1', { x: 3, y: 4, e: 5 });
171-
const interpreter = new Interpreter();
172-
const job = new Job();
173-
interpreter.execute([command1], job);
174-
175-
interpreter.g0(command2, job);
176-
177-
expect(job.paths.length).toEqual(1);
178-
expect(job.inprogressPath?.travelType).toEqual('Extrusion');
179-
});
180-
181-
test('.G0 starts a new path if the travel type changes from Extrusion to Travel', () => {
182-
const command1 = new GCodeCommand('G1 X1 Y2 E3', 'g1', { x: 1, y: 2, e: 3 });
183-
const command2 = new GCodeCommand('G0 X3 Y4', 'g0', { x: 3, y: 4 });
184-
const interpreter = new Interpreter();
185-
const job = new Job();
186-
interpreter.execute([command1], job);
187-
188-
interpreter.g0(command2, job);
189-
190-
expect(job.paths.length).toEqual(1);
191-
expect(job.inprogressPath?.travelType).toEqual('Travel');
192-
});
193-
194-
test('.G1 is an alias to .G0', () => {
195-
const interpreter = new Interpreter();
195+
test('.G1 is an alias to .G0', () => {
196+
const interpreter = new Interpreter();
196197

197-
expect(interpreter.g1).toEqual(interpreter.g0);
198+
expect(interpreter.g1).toEqual(interpreter.g0);
199+
});
198200
});
199201

200202
test('.G20 sets the units to inches', () => {

0 commit comments

Comments
 (0)