Skip to content

Commit d79c674

Browse files
authored
Merge pull request #92 from sophiedeziel/tube-extrusion
Add a mode to render extrusion as tubes
2 parents 9f8dc58 + c3008e4 commit d79c674

6 files changed

Lines changed: 109 additions & 23 deletions

File tree

demo/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ <h1>GCode Preview</h1>
7272
<label for="extrusion">Extrusion</label
7373
><input type="checkbox" id="extrusion" />
7474
</div>
75+
<div class="controls">
76+
<label for="render-tubes">Render tubes</label
77+
><input type="checkbox" id="render-tubes" />
78+
</div>
7579
<div class="controls">
7680
<label for="extrusion-color">Extrusion color</label>
7781
<input type="color" id="extrusion-color" value="#ff0000" />

demo/js/demo.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const lineWidth = document.getElementById('line-width');
1313
const lineWidthValue = document.getElementById('line-width-value');
1414
const toggleSingleLayerMode = document.getElementById('single-layer-mode');
1515
const toggleExtrusion = document.getElementById('extrusion');
16+
const toggleRenderTubes = document.getElementById('render-tubes');
1617
const extrusionColor = document.getElementById('extrusion-color');
1718
const backgroundColor = document.getElementById('background-color');
1819
const toggleTravel = document.getElementById('travel');
@@ -51,6 +52,7 @@ function initDemo() {
5152
allowDragNDrop: true,
5253
topLayerColor: 'rgb(0, 255, 255)',
5354
lastSegmentColor: '#fff',
55+
renderTubes: false,
5456
extrusionColor: 'hotpink',
5557
backgroundColor: preferDarkMode.matches ? '#111' : '#eee',
5658
travelColor: new THREE.Color('lime')
@@ -111,6 +113,12 @@ function initDemo() {
111113
preview.renderExtrusion = toggleExtrusion.checked;
112114
preview.render();
113115
});
116+
117+
toggleRenderTubes.addEventListener('click', function () {
118+
preview.renderTubes = toggleRenderTubes.checked;
119+
preview.render();
120+
});
121+
114122
extrusionColor.addEventListener('input', () =>
115123
throttle(() => {
116124
preview.extrusionColor = extrusionColor.value;

dist/gcode-preview.d.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,16 @@ declare type RenderLayer = {
6969
travel: number[];
7070
z: number;
7171
};
72-
declare type Vector3 = {
72+
declare type GVector3 = {
7373
x: number;
7474
y: number;
7575
z: number;
7676
r: number;
7777
i: number;
7878
j: number;
7979
};
80-
declare type Point = Vector3;
81-
declare type BuildVolume = Vector3;
80+
declare type Point = GVector3;
81+
declare type BuildVolume = GVector3;
8282
declare type State = {
8383
x: number;
8484
y: number;
@@ -101,6 +101,7 @@ declare type GCodePreviewOptions = {
101101
lineWidth?: number;
102102
nonTravelMoves?: string[];
103103
minLayerThreshold?: number;
104+
renderTubes?: boolean;
104105
startLayer?: number;
105106
targetId?: string;
106107
topLayerColor?: ColorRepresentation;
@@ -118,6 +119,7 @@ declare class WebGLPreview {
118119
canvas: HTMLCanvasElement;
119120
renderExtrusion: boolean;
120121
renderTravel: boolean;
122+
renderTubes: boolean;
121123
lineWidth?: number;
122124
startLayer?: number;
123125
endLayer?: number;
@@ -162,6 +164,7 @@ declare class WebGLPreview {
162164
addLineSegment(layer: RenderLayer, p1: Point, p2: Point, extrude: boolean): void;
163165
addArcSegment(layer: RenderLayer, p1: Point, p2: Point, extrude: boolean, cw: boolean): void;
164166
addLine(vertices: number[], color: number): void;
167+
addTubeLine(vertices: number[], color: number): void;
165168
addThickLine(vertices: number[], color: number): void;
166169
private _enableDropHandler;
167170
_readFromStream(stream: ReadableStream): Promise<void>;

dist/gcode-preview.es.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/gcode-preview.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/webgl-preview.ts

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,33 @@ import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2';
66
import { GridHelper } from './gridHelper';
77
import { LineBox } from './lineBox';
88
import {
9-
Scene,
10-
PerspectiveCamera,
11-
WebGLRenderer,
12-
Group,
13-
Color,
14-
REVISION,
15-
Fog,
9+
AmbientLight,
1610
AxesHelper,
17-
Euler,
1811
BufferGeometry,
12+
CatmullRomCurve3,
13+
Color,
14+
ColorRepresentation,
15+
Euler,
1916
Float32BufferAttribute,
17+
Fog,
18+
Group,
2019
LineBasicMaterial,
2120
LineSegments,
22-
ColorRepresentation
21+
Mesh,
22+
MeshLambertMaterial,
23+
PerspectiveCamera,
24+
PointLight,
25+
REVISION,
26+
Scene,
27+
TubeGeometry,
28+
Vector3,
29+
WebGLRenderer
2330
} from 'three';
2431

2532
type RenderLayer = { extrusion: number[]; travel: number[]; z: number };
26-
type Vector3 = { x: number; y: number; z: number; r: number; i: number; j: number };
27-
type Point = Vector3;
28-
type BuildVolume = Vector3;
33+
type GVector3 = { x: number; y: number; z: number; r: number; i: number; j: number };
34+
type Point = GVector3;
35+
type BuildVolume = GVector3;
2936
export type State = { x: number; y: number; z: number; r: number; e: number; i: number; j: number }; // feedrate?
3037

3138
export type GCodePreviewOptions = {
@@ -41,6 +48,7 @@ export type GCodePreviewOptions = {
4148
lineWidth?: number;
4249
nonTravelMoves?: string[];
4350
minLayerThreshold?: number;
51+
renderTubes?: boolean;
4452
startLayer?: number;
4553
targetId?: string;
4654
topLayerColor?: ColorRepresentation;
@@ -65,6 +73,7 @@ export class WebGLPreview {
6573
canvas: HTMLCanvasElement;
6674
renderExtrusion = true;
6775
renderTravel = false;
76+
renderTubes = false;
6877
lineWidth?: number;
6978
startLayer?: number;
7079
endLayer?: number;
@@ -103,6 +112,7 @@ export class WebGLPreview {
103112
this.debug = opts.debug ?? this.debug;
104113
this.allowDragNDrop = opts.allowDragNDrop ?? this.allowDragNDrop;
105114
this.nonTravelmoves = opts.nonTravelMoves ?? this.nonTravelmoves;
115+
this.renderTubes = opts.renderTubes ?? this.renderTubes;
106116

107117
if (opts.extrusionColor != undefined) {
108118
this.extrusionColor = new Color(opts.extrusionColor);
@@ -238,6 +248,14 @@ export class WebGLPreview {
238248
this.drawBuildVolume();
239249
}
240250

251+
if (this.renderTubes) {
252+
const light = new AmbientLight(0xcccccc, 1);
253+
const dLight = new PointLight(0xffffff, 0.8);
254+
dLight.position.set(0, 500, 500);
255+
this.scene.add(light);
256+
this.scene.add(dLight);
257+
}
258+
241259
this.group = new Group();
242260
this.group.name = 'gcode';
243261
const state: State = { x: 0, y: 0, z: 0, r: 0, e: 0, i: 0, j: 0 };
@@ -311,21 +329,35 @@ export class WebGLPreview {
311329

312330
doRenderExtrusion(layer: RenderLayer, index: number): void {
313331
if (this.renderExtrusion) {
314-
const brightness = 0.1 + (0.7 * index) / this.layers.length;
332+
let extrusionColor;
333+
if (this.singleLayerMode || this.renderTubes) {
334+
extrusionColor = this._extrusionColor;
335+
} else {
336+
const brightness = 0.1 + (0.7 * index) / this.layers.length;
315337

316-
this._extrusionColor.getHSL(target);
317-
const extrusionColor = new Color().setHSL(target.h, target.s, brightness);
338+
this._extrusionColor.getHSL(target);
339+
extrusionColor = new Color().setHSL(target.h, target.s, brightness);
340+
}
318341

319342
if (index == this.layers.length - 1) {
320343
const layerColor = this._topLayerColor ?? extrusionColor;
321344
const lastSegmentColor = this._lastSegmentColor ?? layerColor;
322345

323346
const endPoint = layer.extrusion.splice(-3);
324347
const preendPoint = layer.extrusion.splice(-3);
325-
this.addLine(layer.extrusion, layerColor.getHex());
326-
this.addLine([...preendPoint, ...endPoint], lastSegmentColor.getHex());
348+
if (this.renderTubes) {
349+
this.addTubeLine(layer.extrusion, layerColor.getHex());
350+
this.addTubeLine([...preendPoint, ...endPoint], lastSegmentColor.getHex());
351+
} else {
352+
this.addLine(layer.extrusion, layerColor.getHex());
353+
this.addLine([...preendPoint, ...endPoint], lastSegmentColor.getHex());
354+
}
327355
} else {
328-
this.addLine(layer.extrusion, extrusionColor.getHex());
356+
if (this.renderTubes) {
357+
this.addTubeLine(layer.extrusion, extrusionColor.getHex());
358+
} else {
359+
this.addLine(layer.extrusion, extrusionColor.getHex());
360+
}
329361
}
330362
}
331363

@@ -488,6 +520,45 @@ export class WebGLPreview {
488520
this.group.add(lineSegments);
489521
}
490522

523+
addTubeLine(vertices: number[], color: number): void {
524+
let curvePoints: Vector3[] = [];
525+
const curves: CatmullRomCurve3[] = [];
526+
527+
// Merging into one curve for performance
528+
for (let i = 0; i < vertices.length; i += 6) {
529+
const v = vertices.slice(i, i + 6);
530+
const startPoint = new Vector3(v[0], v[1], v[2]);
531+
const endPoint = new Vector3(v[3], v[4], v[5]);
532+
533+
if (curvePoints.length === 0) {
534+
curvePoints.push(startPoint);
535+
}
536+
537+
if (!curvePoints[curvePoints.length - 1].equals(startPoint)) {
538+
curves.push(new CatmullRomCurve3(curvePoints, false, 'catmullrom', 0));
539+
curvePoints = [];
540+
curvePoints.push(startPoint);
541+
}
542+
543+
curvePoints.push(endPoint);
544+
}
545+
546+
if (curvePoints.length > 2) {
547+
curves.push(new CatmullRomCurve3(curvePoints, false, 'catmullrom', 0));
548+
}
549+
550+
curves.forEach((curve) => {
551+
const material = new MeshLambertMaterial({ color: color });
552+
this.disposables.push(material);
553+
const segments = Math.ceil(curve.getLength() * 2);
554+
const geometry = new TubeGeometry(curve, segments, 0.3, 4, false);
555+
this.disposables.push(geometry);
556+
const lineSegments = new Mesh(geometry, material);
557+
558+
this.group.add(lineSegments);
559+
});
560+
}
561+
491562
addThickLine(vertices: number[], color: number): void {
492563
if (!vertices.length) return;
493564

0 commit comments

Comments
 (0)