From 82838b8d208611956d9cc273a5c5c5caf3d2ff4e Mon Sep 17 00:00:00 2001 From: Adnane Belmadiaf Date: Sun, 20 Oct 2024 17:23:49 +0200 Subject: [PATCH] feat(vtkGCodeReader): add vtkGCodeReader Fixes #3149 --- .../docs/gallery/GCodeReaderWithIcon.jpg | Bin 0 -> 6219 bytes Documentation/content/examples/index.md | 2 + .../Misc/GCodeReader/example/controller.html | 13 + Sources/IO/Misc/GCodeReader/example/index.js | 114 ++++++++ Sources/IO/Misc/GCodeReader/index.d.ts | 128 +++++++++ Sources/IO/Misc/GCodeReader/index.js | 257 ++++++++++++++++++ Sources/IO/Misc/index.js | 2 + 7 files changed, 516 insertions(+) create mode 100644 Documentation/content/docs/gallery/GCodeReaderWithIcon.jpg create mode 100644 Sources/IO/Misc/GCodeReader/example/controller.html create mode 100644 Sources/IO/Misc/GCodeReader/example/index.js create mode 100644 Sources/IO/Misc/GCodeReader/index.d.ts create mode 100644 Sources/IO/Misc/GCodeReader/index.js diff --git a/Documentation/content/docs/gallery/GCodeReaderWithIcon.jpg b/Documentation/content/docs/gallery/GCodeReaderWithIcon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..70c5b3aa9d0cf96e03f9ee9c8224e1bd7796b137 GIT binary patch literal 6219 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 Yq01Vh?O}zla@4rE|JRWy$@$Q~0LuORCIA2c literal 0 HcmV?d00001 diff --git a/Documentation/content/examples/index.md b/Documentation/content/examples/index.md index 1207c49b9fa..f06c181c010 100644 --- a/Documentation/content/examples/index.md +++ b/Documentation/content/examples/index.md @@ -184,6 +184,7 @@ This will allow you to see the some live code running in your browser. Just pick [![HttpDataSetSeriesReader Example][HttpDataSetSeriesReaderWithIcon]](./HttpDataSetSeriesReader.html "Import a VTK dataset with time support.") [![HttpSceneLoader Example][HttpSceneLoaderWithIcon]](./HttpSceneLoader.html "Import a VTK scene (data + representation)") [![OfflineLocalView Example][OfflineLocalViewWithIcon]](./OfflineLocalView.html "Load a serialized scene (VTKSZ)") +[![G-Code Example][GCodeReaderWithIcon]](./GCodeReader.html "G-Code reader(gcode)") @@ -203,6 +204,7 @@ This will allow you to see the some live code running in your browser. Just pick [HttpDataSetSeriesReaderWithIcon]: ../docs/gallery/HttpDataSetSeriesReaderWithIcon.gif [HttpSceneLoaderWithIcon]: ../docs/gallery/HttpSceneLoaderWithIcon.jpg [OfflineLocalViewWithIcon]: ../docs/gallery/OfflineLocalViewWithIcon.jpg +[GCodeReaderWithIcon]: ../docs/gallery/GCodeReaderWithIcon.jpg # Actors diff --git a/Sources/IO/Misc/GCodeReader/example/controller.html b/Sources/IO/Misc/GCodeReader/example/controller.html new file mode 100644 index 00000000000..42f9ea66af5 --- /dev/null +++ b/Sources/IO/Misc/GCodeReader/example/controller.html @@ -0,0 +1,13 @@ + + + + + + + + +
+

Options

+
Layers: + +
diff --git a/Sources/IO/Misc/GCodeReader/example/index.js b/Sources/IO/Misc/GCodeReader/example/index.js new file mode 100644 index 00000000000..86fc4674205 --- /dev/null +++ b/Sources/IO/Misc/GCodeReader/example/index.js @@ -0,0 +1,114 @@ +import '@kitware/vtk.js/favicon'; + +// Load the rendering pieces we want to use (for both WebGL and WebGPU) +import '@kitware/vtk.js/Rendering/Profiles/Geometry'; + +import vtkMath from '@kitware/vtk.js/Common/Core/Math'; + +import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow'; +import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor'; +import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper'; +import vtkGCodeReader from '@kitware/vtk.js/IO/Misc/GCodeReader'; + +import controlPanel from './controller.html'; + +// ---------------------------------------------------------------------------- +// Example code +// ---------------------------------------------------------------------------- + +let renderer = null; +let renderWindow = null; +let layersSelector = null; +let layersLabel = null; + +const reader = vtkGCodeReader.newInstance(); + +// ---------------------------------------------------------------------------- + +function refresh() { + if (renderer && renderWindow) { + renderer.resetCamera(); + renderWindow.render(); + } +} + +function update() { + const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance(); + fullScreenRenderer.addController(controlPanel); + layersSelector = document.querySelector('.layers'); + layersLabel = document.querySelector('.label'); + renderer = fullScreenRenderer.getRenderer(); + renderWindow = fullScreenRenderer.getRenderWindow(); + const numLayers = reader.getNumberOfOutputPorts(); + + layersLabel.innerHTML = `Layers(${numLayers}):`; + layersSelector.max = numLayers.toString(); + layersSelector.value = numLayers.toString(); + + const actors = []; + + for (let idx = 1; idx < numLayers; idx++) { + const polyData = reader.getOutputData(idx); + if (polyData) { + const mapper = vtkMapper.newInstance(); + mapper.setInputData(polyData); + + const actor = vtkActor.newInstance(); + actor.setMapper(mapper); + + const hue = idx / numLayers; + const saturation = 0.8; + const value = 1; + const hsv = [hue, saturation, value]; + const rgb = []; + vtkMath.hsv2rgb(hsv, rgb); + actor.getProperty().setColor(rgb); + actor.rotateX(-90); + + actors.push(actor); + } + } + + layersSelector.addEventListener('input', (event) => { + const visibleLayers = parseInt(event.target.value, 10); + actors.forEach((actor, index) => { + actor.setVisibility(index < visibleLayers); + }); + renderWindow.render(); + }); + + actors.forEach((actor) => renderer.addActor(actor)); + refresh(); +} + +// ---------------------------------------------------------------------------- +// Use a file reader to load a local file +// ---------------------------------------------------------------------------- + +const myContainer = document.querySelector('body'); +const fileContainer = document.createElement('div'); +fileContainer.innerHTML = + '
Select a gcode file.
'; +myContainer.appendChild(fileContainer); + +const fileInput = fileContainer.querySelector('input'); + +function handleFile(event) { + event.preventDefault(); + const dataTransfer = event.dataTransfer; + const files = event.target.files || dataTransfer.files; + myContainer.removeChild(fileContainer); + const fileReader = new FileReader(); + fileReader.onload = function onLoad(e) { + reader.parse(fileReader.result); + update(); + }; + fileReader.readAsArrayBuffer(files[0]); +} + +fileInput.addEventListener('change', handleFile); + +// ---------------------------------------------------------------------------- +// Use the reader to download a file +// ---------------------------------------------------------------------------- +// reader.setUrl(`${__BASE_PATH__}/data/gcode/cube.gcode`, { binary: true }).then(update); diff --git a/Sources/IO/Misc/GCodeReader/index.d.ts b/Sources/IO/Misc/GCodeReader/index.d.ts new file mode 100644 index 00000000000..3008ae4702f --- /dev/null +++ b/Sources/IO/Misc/GCodeReader/index.d.ts @@ -0,0 +1,128 @@ +import { vtkAlgorithm, vtkObject } from '../../../interfaces'; +import HtmlDataAccessHelper from '../../Core/DataAccessHelper/HtmlDataAccessHelper'; +import HttpDataAccessHelper from '../../Core/DataAccessHelper/HttpDataAccessHelper'; +import JSZipDataAccessHelper from '../../Core/DataAccessHelper/JSZipDataAccessHelper'; +import LiteHttpDataAccessHelper from '../../Core/DataAccessHelper/LiteHttpDataAccessHelper'; + +interface IGCodeReaderOptions { + binary?: boolean; + compression?: string; + progressCallback?: any; +} + +/** + * + */ +export interface IGCodeReaderInitialValues {} + +type vtkGCodeReaderBase = vtkObject & + Omit< + vtkAlgorithm, + | 'getInputData' + | 'setInputData' + | 'setInputConnection' + | 'getInputConnection' + | 'addInputConnection' + | 'addInputData' + >; + +export interface vtkGCodeReader extends vtkGCodeReaderBase { + /** + * + */ + getBaseURL(): string; + + /** + * + */ + getDataAccessHelper(): + | HtmlDataAccessHelper + | HttpDataAccessHelper + | JSZipDataAccessHelper + | LiteHttpDataAccessHelper; + + /** + * Get the url of the object to load. + */ + getUrl(): string; + + /** + * Load the object data. + * @param {IGCodeReaderOptions} [options] + */ + loadData(options?: IGCodeReaderOptions): Promise; + + /** + * Parse data. + * @param {String | ArrayBuffer} content The content to parse. + */ + parse(content: string | ArrayBuffer): void; + + /** + * Parse data as ArrayBuffer. + * @param {ArrayBuffer} content The content to parse. + */ + parseAsArrayBuffer(content: ArrayBuffer): void; + + /** + * Parse data as text. + * @param {String} content The content to parse. + */ + parseAsText(content: string): void; + + /** + * + * @param inData + * @param outData + */ + requestData(inData: any, outData: any): void; + + /** + * + * @param dataAccessHelper + */ + setDataAccessHelper( + dataAccessHelper: + | HtmlDataAccessHelper + | HttpDataAccessHelper + | JSZipDataAccessHelper + | LiteHttpDataAccessHelper + ): boolean; + + /** + * Set the url of the object to load. + * @param {String} url the url of the object to load. + * @param {IGCodeReaderOptions} [option] The PLY reader options. + */ + setUrl(url: string, option?: IGCodeReaderOptions): Promise; +} + +/** + * Method used to decorate a given object (publicAPI+model) with vtkGCodeReader characteristics. + * + * @param publicAPI object on which methods will be bounds (public) + * @param model object on which data structure will be bounds (protected) + * @param {IGCodeReaderInitialValues} [initialValues] (default: {}) + */ +export function extend( + publicAPI: object, + model: object, + initialValues?: IGCodeReaderInitialValues +): void; + +/** + * Method used to create a new instance of vtkGCodeReader + * @param {IGCodeReaderInitialValues} [initialValues] for pre-setting some of its content + */ +export function newInstance( + initialValues?: IGCodeReaderInitialValues +): vtkGCodeReader; + +/** + * vtkGCodeReader is a source object that reads a GCODE file. + */ +export declare const vtkGCodeReader: { + newInstance: typeof newInstance; + extend: typeof extend; +}; +export default vtkGCodeReader; diff --git a/Sources/IO/Misc/GCodeReader/index.js b/Sources/IO/Misc/GCodeReader/index.js new file mode 100644 index 00000000000..4993a33b85f --- /dev/null +++ b/Sources/IO/Misc/GCodeReader/index.js @@ -0,0 +1,257 @@ +import macro from 'vtk.js/Sources/macros'; +import BinaryHelper from 'vtk.js/Sources/IO/Core/BinaryHelper'; +import DataAccessHelper from 'vtk.js/Sources/IO/Core/DataAccessHelper'; +import vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData'; +import vtkPoints from 'vtk.js/Sources/Common/Core/Points'; +import vtkCellArray from 'vtk.js/Sources/Common/Core/CellArray'; + +// Enable several sources for DataAccessHelper +import 'vtk.js/Sources/IO/Core/DataAccessHelper/LiteHttpDataAccessHelper'; // Just need HTTP +// import 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper'; // HTTP + gz +// import 'vtk.js/Sources/IO/Core/DataAccessHelper/HtmlDataAccessHelper'; // html + base64 + zip +// import 'vtk.js/Sources/IO/Core/DataAccessHelper/JSZipDataAccessHelper'; // zip + +const state = {}; + +// ---------------------------------------------------------------------------- +// vtkGCodeReader methods +// ---------------------------------------------------------------------------- +function vtkGCodeReader(publicAPI, model) { + state.currentPosition = { x: 0, y: 0, z: 0 }; + state.offset = { x: 0, y: 0, z: 0 }; + state.currentLayer = 0; + state.layers = new Map(); // Map to store layer data + state.isAbsolute = true; // G90 is default + state.isMetric = true; // G21 is default + state.lastZ = 0; // Track Z changes for layer detection + + model.classHierarchy.push('vtkGCodeReader'); + + if (!model.dataAccessHelper) { + model.dataAccessHelper = DataAccessHelper.get('http'); + } + + function fetchData(url, option = {}) { + const { compression, progressCallback } = model; + if (option.binary) { + return model.dataAccessHelper.fetchBinary(url, { + compression, + progressCallback, + }); + } + return model.dataAccessHelper.fetchText(publicAPI, url, { + compression, + progressCallback, + }); + } + + function detectLayerChange(newZ) { + if (Math.abs(newZ - state.lastZ) > 0.001) { + state.currentLayer++; + state.lastZ = newZ; + return true; + } + return false; + } + + function initializeLayer() { + if (!state.layers.has(state.currentLayer)) { + const points = vtkPoints.newInstance(); + const lines = vtkCellArray.newInstance(); + const polyData = vtkPolyData.newInstance(); + + polyData.setPoints(points); + polyData.setLines(lines); + + state.layers.set(state.currentLayer, { + polyData, + points, + lines, + zHeight: state.lastZ, + }); + } + } + + function addLineToLayer(startPoint, endPoint) { + initializeLayer(); + const layer = state.layers.get(state.currentLayer); + + // Add points and get their indices + const startIndex = layer.points.insertNextPoint( + startPoint[0], + startPoint[1], + startPoint[2] + ); + const endIndex = layer.points.insertNextPoint( + endPoint[0], + endPoint[1], + endPoint[2] + ); + + // Add line cell + layer.lines.insertNextCell([startIndex, endIndex]); + } + + function processMove(params) { + const newPosition = { ...state.currentPosition }; + let positionChanged = false; + + ['X', 'Y', 'Z'].forEach((axis) => { + if (axis in params) { + const value = state.isMetric ? params[axis] : params[axis] * 25.4; + newPosition[axis.toLowerCase()] = state.isAbsolute + ? value + state.offset[axis.toLowerCase()] + : state.currentPosition[axis.toLowerCase()] + value; + positionChanged = true; + } + }); + + if (positionChanged) { + if ('Z' in params) { + detectLayerChange(newPosition.z); + } + + const startPoint = [ + state.currentPosition.x, + state.currentPosition.y, + state.currentPosition.z, + ]; + const endPoint = [newPosition.x, newPosition.y, newPosition.z]; + + addLineToLayer(startPoint, endPoint); + state.currentPosition = newPosition; + } + } + + function processG92(params) { + ['X', 'Y', 'Z'].forEach((axis) => { + if (axis in params) { + state.offset[axis.toLowerCase()] = + state.currentPosition[axis.toLowerCase()] - + (state.isMetric ? params[axis] : params[axis] * 25.4); + } + }); + } + + function processCommand(command, params) { + switch (command) { + case 'G0': // Rapid move + case 'G1': // Linear move + processMove(params); + break; + case 'G20': // Imperial + state.isMetric = false; + break; + case 'G21': // Metric + state.isMetric = true; + break; + case 'G90': // Absolute positioning + state.isAbsolute = true; + break; + case 'G91': // Relative positioning + state.isAbsolute = false; + break; + case 'G92': // Set position + processG92(params); + break; + default: + break; + } + } + + function parseGCode(gcodeText) { + const lines = gcodeText.split('\n'); + + lines.forEach((line) => { + const sline = line.split(';')[0].trim(); + if (!sline) return; + + const tokens = sline.split(' '); + const command = tokens[0]; + + const params = {}; + tokens.slice(1).forEach((token) => { + const param = token[0]; + const value = parseFloat(token.slice(1)); + if (!Number.isNaN(value)) { + params[param] = value; + } + }); + + processCommand(command, params); + }); + } + + // Public methods + publicAPI.setUrl = (url, option = { binary: true }) => { + model.url = url; + const path = url.split('/'); + path.pop(); + model.baseURL = path.join('/'); + model.compression = option.compression; + + return publicAPI.loadData({ + progressCallback: option.progressCallback, + binary: !!option.binary, + }); + }; + + publicAPI.loadData = (option = {}) => { + const promise = fetchData(model.url, option); + promise.then(publicAPI.parse); + return promise; + }; + + publicAPI.parseAsText = (content) => { + parseGCode(content); + }; + + publicAPI.parseAsArrayBuffer = (content) => { + const data = BinaryHelper.arrayBufferToString(content); + parseGCode(data); + }; + + publicAPI.parse = (content) => { + if (typeof content === 'string') { + publicAPI.parseAsText(content); + } else { + publicAPI.parseAsArrayBuffer(content); + } + + state.layers.forEach((layer, i) => { + model.output[i] = layer.polyData; + }); + }; + + publicAPI.requestData = (inData, outData) => { + publicAPI.parse(model.parseData); + }; + + publicAPI.getNumberOfOutputPorts = () => state.layers.size; +} + +const DEFAULT_VALUES = { + // baseURL: null, + // dataAccessHelper: null, + // url: null, +}; + +export function extend(publicAPI, model, initialValues = {}) { + Object.assign(model, DEFAULT_VALUES, initialValues); + + // Build VTK API + macro.obj(publicAPI, model); + macro.get(publicAPI, model, ['url', 'baseURL']); + macro.setGet(publicAPI, model, ['dataAccessHelper']); + macro.algo(publicAPI, model, 0, 1); + macro.event(publicAPI, model, 'ready'); + + vtkGCodeReader(publicAPI, model); +} + +export const newInstance = macro.newInstance(extend, 'vtkGCodeReader'); + +export default { + extend, + newInstance, +}; diff --git a/Sources/IO/Misc/index.js b/Sources/IO/Misc/index.js index 3563a47257c..57704ad77c3 100644 --- a/Sources/IO/Misc/index.js +++ b/Sources/IO/Misc/index.js @@ -7,6 +7,7 @@ import vtkMTLReader from './MTLReader'; import vtkOBJReader from './OBJReader'; import vtkPDBReader from './PDBReader'; import vtkSkyboxReader from './SkyboxReader'; +import vtkGCodeReader from './GCodeReader'; export default { vtkElevationReader, @@ -18,4 +19,5 @@ export default { vtkOBJReader, vtkPDBReader, vtkSkyboxReader, + vtkGCodeReader, };