From 3be779d00abc34d40bfdb0438f8308c31785f566 Mon Sep 17 00:00:00 2001 From: Remco Veldkamp Date: Fri, 12 Sep 2025 18:05:30 +0200 Subject: [PATCH 1/6] Update travel line color instantly --- src/scene-manager.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/scene-manager.ts b/src/scene-manager.ts index dcdef194..a18ddd48 100644 --- a/src/scene-manager.ts +++ b/src/scene-manager.ts @@ -364,6 +364,10 @@ export class SceneManager { */ set travelColor(value: number | string | Color) { this._travelColor = new Color(value); + + if (this.travelLineMaterial) { + this.travelLineMaterial.color.set(this._travelColor); + } } /** @@ -843,6 +847,7 @@ export class SceneManager { } } + private travelLineMaterial: LineMaterial; /** * Renders paths as 2D lines * @param paths - Array of paths to render @@ -855,7 +860,7 @@ export class SceneManager { let clippingPlanes: Plane[] = []; clippingPlanes = this.createClippingPlanes(minZ, maxZ); - const material = new LineMaterial({ + this.travelLineMaterial = new LineMaterial({ color: Number(color.getHex()), linewidth: this.lineWidth, clippingPlanes @@ -877,9 +882,9 @@ export class SceneManager { }); const geometry = new LineSegmentsGeometry().setPositions(lineVertices); - const line = new LineSegments2(geometry, material); + const line = new LineSegments2(geometry, this.travelLineMaterial); - this.disposables.push(material); + this.disposables.push(this.travelLineMaterial); this.disposables.push(geometry); this.currentChunk?.add(line); } From 4bd13d41dcb6234deb4d5efb009591cf68169d60 Mon Sep 17 00:00:00 2001 From: Remco Veldkamp Date: Fri, 12 Sep 2025 18:54:25 +0200 Subject: [PATCH 2/6] Make it work in progressive / chunked mode --- src/scene-manager.ts | 66 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/src/scene-manager.ts b/src/scene-manager.ts index a18ddd48..29be1016 100644 --- a/src/scene-manager.ts +++ b/src/scene-manager.ts @@ -27,7 +27,8 @@ import { Vector3, WebGLRenderer, MathUtils, - LineBasicMaterial + LineBasicMaterial, + Object3D } from 'three'; export type BuildVolumeDef = Pick; @@ -331,6 +332,12 @@ export class SceneManager { } this.materials[0].uniforms.uColor.value = this._extrusionColor; + + if (!this.renderTubes) { + for (const line of this._extrusionLines) { + line.material.color.set(this._extrusionColor); + } + } } /** @@ -365,8 +372,8 @@ export class SceneManager { set travelColor(value: number | string | Color) { this._travelColor = new Color(value); - if (this.travelLineMaterial) { - this.travelLineMaterial.color.set(this._travelColor); + for (const line of this._travelLines) { + line.material.color.set(this._travelColor); } } @@ -832,7 +839,10 @@ export class SceneManager { */ private renderPaths(endPathNumber: number = Infinity): void { if (this.renderTravel) { - this.renderPathsAsLines(this.job.travels.slice(this.renderPathIndex, endPathNumber), this._travelColor); + const travelLine = this.renderPathsAsLines(this.job.travels.slice(this.renderPathIndex, endPathNumber), this._travelColor); + travelLine.userData = { + lineType: 'travel' + } } if (this.renderExtrusion) { @@ -841,26 +851,28 @@ export class SceneManager { if (this.renderTubes) { this.renderPathsAsTubes(toolPaths.slice(this.renderPathIndex, endPathNumber), color); } else { - this.renderPathsAsLines(toolPaths.slice(this.renderPathIndex, endPathNumber), color); + const extrusionLine = this.renderPathsAsLines(toolPaths.slice(this.renderPathIndex, endPathNumber), color); + extrusionLine.userData = { + lineType: 'extrusion' + } } }); } } - private travelLineMaterial: LineMaterial; /** * Renders paths as 2D lines * @param paths - Array of paths to render * @param color - Color to use for the lines */ - private renderPathsAsLines(paths: Path[], color: Color): void { + private renderPathsAsLines(paths: Path[], color: Color): Object3D { const minZ = this.job.layers[this._startLayer - 1]?.z; const maxZ = this.job.layers[this._endLayer - 1]?.z; let clippingPlanes: Plane[] = []; clippingPlanes = this.createClippingPlanes(minZ, maxZ); - this.travelLineMaterial = new LineMaterial({ + const material = new LineMaterial({ color: Number(color.getHex()), linewidth: this.lineWidth, clippingPlanes @@ -882,11 +894,12 @@ export class SceneManager { }); const geometry = new LineSegmentsGeometry().setPositions(lineVertices); - const line = new LineSegments2(geometry, this.travelLineMaterial); + const line = new LineSegments2(geometry, material); - this.disposables.push(this.travelLineMaterial); + this.disposables.push(material); this.disposables.push(geometry); this.currentChunk?.add(line); + return line; } /** @@ -975,4 +988,37 @@ export class SceneManager { localStorage.removeItem('cameraZoom'); localStorage.removeItem('cameraTarget'); } + + get _travelLines() { + const lines = this.scene.getObjectByUserDataProperty('lineType', 'travel'); + return lines as unknown as [LineSegments2]; + } + + get _extrusionLines() { + const lines = this.scene.getObjectByUserDataProperty('lineType', 'extrusion'); + return lines as unknown as [LineSegments2]; + } +} + +import * as THREE from "three"; + +declare module 'three' { + interface Object3D { + // eslint-disable-next-line no-unused-vars + getObjectByUserDataProperty(name: string, value: unknown): Array; + } +} + +THREE.Object3D.prototype.getObjectByUserDataProperty = function (this: Object3D, name: string, value: unknown) { + const result: Array = []; + + if (this.userData[name] === value) + result.push(this); + + for (const child of this.children) { + const objects = child.getObjectByUserDataProperty(name, value); + result.push(...objects); + } + + return result; } From fe4011ca930bf7fed56311e9621205d1c49f3d6a Mon Sep 17 00:00:00 2001 From: Remco Veldkamp Date: Fri, 12 Sep 2025 21:24:28 +0200 Subject: [PATCH 3/6] Move extension method --- src/extensions/object3d.ts | 22 ++++++++++++++++++++++ src/gcode-preview.ts | 1 + src/scene-manager.ts | 22 ---------------------- 3 files changed, 23 insertions(+), 22 deletions(-) create mode 100644 src/extensions/object3d.ts diff --git a/src/extensions/object3d.ts b/src/extensions/object3d.ts new file mode 100644 index 00000000..6ea60951 --- /dev/null +++ b/src/extensions/object3d.ts @@ -0,0 +1,22 @@ +import { Object3D } from "three"; + +declare module 'three' { + interface Object3D { + // eslint-disable-next-line no-unused-vars + getObjectByUserDataProperty(name: string, value: unknown): Array; + } +} + +Object3D.prototype.getObjectByUserDataProperty = function (this: Object3D, name: string, value: unknown) { + const result: Array = []; + + if (this.userData[name] === value) + result.push(this); + + for (const child of this.children) { + const objects = child.getObjectByUserDataProperty(name, value); + result.push(...objects); + } + + return result; +} diff --git a/src/gcode-preview.ts b/src/gcode-preview.ts index 0a410539..758660dd 100644 --- a/src/gcode-preview.ts +++ b/src/gcode-preview.ts @@ -5,6 +5,7 @@ import { Job } from './job'; import { DevGUI, type DevModeOptions } from './dev-gui'; import Stats from 'three/examples/jsm/libs/stats.module.js'; import { makeDroppable } from './extra/dom-utils'; +import "./extensions/object3d"; // import extensions /** * Options for configuring the G-code preview diff --git a/src/scene-manager.ts b/src/scene-manager.ts index 29be1016..db1064fd 100644 --- a/src/scene-manager.ts +++ b/src/scene-manager.ts @@ -1000,25 +1000,3 @@ export class SceneManager { } } -import * as THREE from "three"; - -declare module 'three' { - interface Object3D { - // eslint-disable-next-line no-unused-vars - getObjectByUserDataProperty(name: string, value: unknown): Array; - } -} - -THREE.Object3D.prototype.getObjectByUserDataProperty = function (this: Object3D, name: string, value: unknown) { - const result: Array = []; - - if (this.userData[name] === value) - result.push(this); - - for (const child of this.children) { - const objects = child.getObjectByUserDataProperty(name, value); - result.push(...objects); - } - - return result; -} From 44035faacb474f86c7c4b4e01c8d1704c505c197 Mon Sep 17 00:00:00 2001 From: Remco Veldkamp Date: Fri, 12 Sep 2025 21:31:42 +0200 Subject: [PATCH 4/6] code cleanup --- src/extensions/object3d.ts | 21 ++++++++++----------- src/scene-manager.ts | 13 ++++++------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/extensions/object3d.ts b/src/extensions/object3d.ts index 6ea60951..2f49814b 100644 --- a/src/extensions/object3d.ts +++ b/src/extensions/object3d.ts @@ -3,20 +3,19 @@ import { Object3D } from "three"; declare module 'three' { interface Object3D { // eslint-disable-next-line no-unused-vars - getObjectByUserDataProperty(name: string, value: unknown): Array; + getByUserData(name: string, value: unknown): Array; } } -Object3D.prototype.getObjectByUserDataProperty = function (this: Object3D, name: string, value: unknown) { - const result: Array = []; +// from https://discourse.threejs.org/t/getobject-by-any-custom-property-present-in-userdata-of-object/3378/3 +Object3D.prototype.getByUserData = function (this: Object3D, name: string, value: unknown) { + const meshes: Array = []; - if (this.userData[name] === value) - result.push(this); + this.traverse((node) => { + if (node.userData[name] === value) { + meshes.push(node); + } + }); - for (const child of this.children) { - const objects = child.getObjectByUserDataProperty(name, value); - result.push(...objects); - } - - return result; + return meshes; } diff --git a/src/scene-manager.ts b/src/scene-manager.ts index db1064fd..5d681746 100644 --- a/src/scene-manager.ts +++ b/src/scene-manager.ts @@ -334,7 +334,7 @@ export class SceneManager { this.materials[0].uniforms.uColor.value = this._extrusionColor; if (!this.renderTubes) { - for (const line of this._extrusionLines) { + for (const line of this.extrusionLines) { line.material.color.set(this._extrusionColor); } } @@ -372,7 +372,7 @@ export class SceneManager { set travelColor(value: number | string | Color) { this._travelColor = new Color(value); - for (const line of this._travelLines) { + for (const line of this.travelLines) { line.material.color.set(this._travelColor); } } @@ -989,14 +989,13 @@ export class SceneManager { localStorage.removeItem('cameraTarget'); } - get _travelLines() { - const lines = this.scene.getObjectByUserDataProperty('lineType', 'travel'); + private get travelLines() { + const lines = this.scene.getByUserData('lineType', 'travel'); return lines as unknown as [LineSegments2]; } - get _extrusionLines() { - const lines = this.scene.getObjectByUserDataProperty('lineType', 'extrusion'); + private get extrusionLines() { + const lines = this.scene.getByUserData('lineType', 'extrusion'); return lines as unknown as [LineSegments2]; } } - From f4a00c9c924cb26bf5a950ca7f94365bd74e9904 Mon Sep 17 00:00:00 2001 From: Remco Veldkamp Date: Fri, 12 Sep 2025 21:32:48 +0200 Subject: [PATCH 5/6] Dont build mesh on color change --- demo/js/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/js/app.js b/demo/js/app.js index 85cde8aa..18fbcabe 100644 --- a/demo/js/app.js +++ b/demo/js/app.js @@ -200,12 +200,12 @@ export const app = (window.app = createApp({ preview.sceneManager.boundingBoxColor = drawBoundingBox.value ? (settings.value.boundingBoxColor ?? 'magenta') : undefined; + preview.sceneManager.travelColor = settings.value.travelColor; }); watchEffect(() => { if (!preview) return; preview.sceneManager.renderTravel = settings.value.renderTravel; - preview.sceneManager.travelColor = settings.value.travelColor; preview.sceneManager.lineWidth = +settings.value.lineWidth; preview.sceneManager.renderExtrusion = settings.value.renderExtrusion; From 835a3f573df16440ffe460877da5b5a5aaf06eb9 Mon Sep 17 00:00:00 2001 From: Remco Veldkamp Date: Fri, 12 Sep 2025 21:35:22 +0200 Subject: [PATCH 6/6] linting --- src/extensions/object3d.ts | 4 ++-- src/gcode-preview.ts | 2 +- src/scene-manager.ts | 29 ++++++++++++++++------------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/extensions/object3d.ts b/src/extensions/object3d.ts index 2f49814b..bd2293e9 100644 --- a/src/extensions/object3d.ts +++ b/src/extensions/object3d.ts @@ -1,4 +1,4 @@ -import { Object3D } from "three"; +import { Object3D } from 'three'; declare module 'three' { interface Object3D { @@ -18,4 +18,4 @@ Object3D.prototype.getByUserData = function (this: Object3D, name: string, value }); return meshes; -} +}; diff --git a/src/gcode-preview.ts b/src/gcode-preview.ts index 758660dd..c07e9018 100644 --- a/src/gcode-preview.ts +++ b/src/gcode-preview.ts @@ -5,7 +5,7 @@ import { Job } from './job'; import { DevGUI, type DevModeOptions } from './dev-gui'; import Stats from 'three/examples/jsm/libs/stats.module.js'; import { makeDroppable } from './extra/dom-utils'; -import "./extensions/object3d"; // import extensions +import './extensions/object3d'; // import extensions /** * Options for configuring the G-code preview diff --git a/src/scene-manager.ts b/src/scene-manager.ts index 5d681746..34a7468f 100644 --- a/src/scene-manager.ts +++ b/src/scene-manager.ts @@ -615,6 +615,16 @@ export class SceneManager { }); } + private get travelLines() { + const lines = this.scene.getByUserData('lineType', 'travel'); + return lines as unknown as [LineSegments2]; + } + + private get extrusionLines() { + const lines = this.scene.getByUserData('lineType', 'extrusion'); + return lines as unknown as [LineSegments2]; + } + /** @internal */ /** * Animation loop that continuously renders the scene @@ -839,10 +849,13 @@ export class SceneManager { */ private renderPaths(endPathNumber: number = Infinity): void { if (this.renderTravel) { - const travelLine = this.renderPathsAsLines(this.job.travels.slice(this.renderPathIndex, endPathNumber), this._travelColor); + const travelLine = this.renderPathsAsLines( + this.job.travels.slice(this.renderPathIndex, endPathNumber), + this._travelColor + ); travelLine.userData = { lineType: 'travel' - } + }; } if (this.renderExtrusion) { @@ -854,7 +867,7 @@ export class SceneManager { const extrusionLine = this.renderPathsAsLines(toolPaths.slice(this.renderPathIndex, endPathNumber), color); extrusionLine.userData = { lineType: 'extrusion' - } + }; } }); } @@ -988,14 +1001,4 @@ export class SceneManager { localStorage.removeItem('cameraZoom'); localStorage.removeItem('cameraTarget'); } - - private get travelLines() { - const lines = this.scene.getByUserData('lineType', 'travel'); - return lines as unknown as [LineSegments2]; - } - - private get extrusionLines() { - const lines = this.scene.getByUserData('lineType', 'extrusion'); - return lines as unknown as [LineSegments2]; - } }