@kitware/vtk.js 32.3.1 → 32.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/IO/Misc/GCodeReader.d.ts +128 -0
- package/IO/Misc/GCodeReader.js +236 -0
- package/IO/Misc.js +3 -1
- package/Rendering/Core/Mapper/CoincidentTopologyHelper.js +6 -2
- package/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { vtkAlgorithm, vtkObject } from './../../interfaces';
|
|
2
|
+
import HtmlDataAccessHelper from './../Core/DataAccessHelper/HtmlDataAccessHelper';
|
|
3
|
+
import HttpDataAccessHelper from './../Core/DataAccessHelper/HttpDataAccessHelper';
|
|
4
|
+
import JSZipDataAccessHelper from './../Core/DataAccessHelper/JSZipDataAccessHelper';
|
|
5
|
+
import LiteHttpDataAccessHelper from './../Core/DataAccessHelper/LiteHttpDataAccessHelper';
|
|
6
|
+
|
|
7
|
+
interface IGCodeReaderOptions {
|
|
8
|
+
binary?: boolean;
|
|
9
|
+
compression?: string;
|
|
10
|
+
progressCallback?: any;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export interface IGCodeReaderInitialValues {}
|
|
17
|
+
|
|
18
|
+
type vtkGCodeReaderBase = vtkObject &
|
|
19
|
+
Omit<
|
|
20
|
+
vtkAlgorithm,
|
|
21
|
+
| 'getInputData'
|
|
22
|
+
| 'setInputData'
|
|
23
|
+
| 'setInputConnection'
|
|
24
|
+
| 'getInputConnection'
|
|
25
|
+
| 'addInputConnection'
|
|
26
|
+
| 'addInputData'
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
export interface vtkGCodeReader extends vtkGCodeReaderBase {
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
getBaseURL(): string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
*/
|
|
38
|
+
getDataAccessHelper():
|
|
39
|
+
| HtmlDataAccessHelper
|
|
40
|
+
| HttpDataAccessHelper
|
|
41
|
+
| JSZipDataAccessHelper
|
|
42
|
+
| LiteHttpDataAccessHelper;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get the url of the object to load.
|
|
46
|
+
*/
|
|
47
|
+
getUrl(): string;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Load the object data.
|
|
51
|
+
* @param {IGCodeReaderOptions} [options]
|
|
52
|
+
*/
|
|
53
|
+
loadData(options?: IGCodeReaderOptions): Promise<any>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Parse data.
|
|
57
|
+
* @param {String | ArrayBuffer} content The content to parse.
|
|
58
|
+
*/
|
|
59
|
+
parse(content: string | ArrayBuffer): void;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Parse data as ArrayBuffer.
|
|
63
|
+
* @param {ArrayBuffer} content The content to parse.
|
|
64
|
+
*/
|
|
65
|
+
parseAsArrayBuffer(content: ArrayBuffer): void;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Parse data as text.
|
|
69
|
+
* @param {String} content The content to parse.
|
|
70
|
+
*/
|
|
71
|
+
parseAsText(content: string): void;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
*
|
|
75
|
+
* @param inData
|
|
76
|
+
* @param outData
|
|
77
|
+
*/
|
|
78
|
+
requestData(inData: any, outData: any): void;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
*
|
|
82
|
+
* @param dataAccessHelper
|
|
83
|
+
*/
|
|
84
|
+
setDataAccessHelper(
|
|
85
|
+
dataAccessHelper:
|
|
86
|
+
| HtmlDataAccessHelper
|
|
87
|
+
| HttpDataAccessHelper
|
|
88
|
+
| JSZipDataAccessHelper
|
|
89
|
+
| LiteHttpDataAccessHelper
|
|
90
|
+
): boolean;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Set the url of the object to load.
|
|
94
|
+
* @param {String} url the url of the object to load.
|
|
95
|
+
* @param {IGCodeReaderOptions} [option] The PLY reader options.
|
|
96
|
+
*/
|
|
97
|
+
setUrl(url: string, option?: IGCodeReaderOptions): Promise<string | any>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Method used to decorate a given object (publicAPI+model) with vtkGCodeReader characteristics.
|
|
102
|
+
*
|
|
103
|
+
* @param publicAPI object on which methods will be bounds (public)
|
|
104
|
+
* @param model object on which data structure will be bounds (protected)
|
|
105
|
+
* @param {IGCodeReaderInitialValues} [initialValues] (default: {})
|
|
106
|
+
*/
|
|
107
|
+
export function extend(
|
|
108
|
+
publicAPI: object,
|
|
109
|
+
model: object,
|
|
110
|
+
initialValues?: IGCodeReaderInitialValues
|
|
111
|
+
): void;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Method used to create a new instance of vtkGCodeReader
|
|
115
|
+
* @param {IGCodeReaderInitialValues} [initialValues] for pre-setting some of its content
|
|
116
|
+
*/
|
|
117
|
+
export function newInstance(
|
|
118
|
+
initialValues?: IGCodeReaderInitialValues
|
|
119
|
+
): vtkGCodeReader;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* vtkGCodeReader is a source object that reads a GCODE file.
|
|
123
|
+
*/
|
|
124
|
+
export declare const vtkGCodeReader: {
|
|
125
|
+
newInstance: typeof newInstance;
|
|
126
|
+
extend: typeof extend;
|
|
127
|
+
};
|
|
128
|
+
export default vtkGCodeReader;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { m as macro } from '../../macros2.js';
|
|
2
|
+
import BinaryHelper from '../Core/BinaryHelper.js';
|
|
3
|
+
import DataAccessHelper from '../Core/DataAccessHelper.js';
|
|
4
|
+
import vtkPolyData from '../../Common/DataModel/PolyData.js';
|
|
5
|
+
import vtkPoints from '../../Common/Core/Points.js';
|
|
6
|
+
import vtkCellArray from '../../Common/Core/CellArray.js';
|
|
7
|
+
import '../Core/DataAccessHelper/LiteHttpDataAccessHelper.js';
|
|
8
|
+
|
|
9
|
+
// import 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper'; // HTTP + gz
|
|
10
|
+
// import 'vtk.js/Sources/IO/Core/DataAccessHelper/HtmlDataAccessHelper'; // html + base64 + zip
|
|
11
|
+
// import 'vtk.js/Sources/IO/Core/DataAccessHelper/JSZipDataAccessHelper'; // zip
|
|
12
|
+
|
|
13
|
+
// ----------------------------------------------------------------------------
|
|
14
|
+
// vtkGCodeReader methods
|
|
15
|
+
// ----------------------------------------------------------------------------
|
|
16
|
+
function vtkGCodeReader(publicAPI, model) {
|
|
17
|
+
const state = {
|
|
18
|
+
currentPosition: {
|
|
19
|
+
x: 0,
|
|
20
|
+
y: 0,
|
|
21
|
+
z: 0
|
|
22
|
+
},
|
|
23
|
+
offset: {
|
|
24
|
+
x: 0,
|
|
25
|
+
y: 0,
|
|
26
|
+
z: 0
|
|
27
|
+
},
|
|
28
|
+
currentLayer: 0,
|
|
29
|
+
layers: new Map(),
|
|
30
|
+
// Map to store layer data
|
|
31
|
+
isAbsolute: true,
|
|
32
|
+
// G90 is default
|
|
33
|
+
isMetric: true,
|
|
34
|
+
// G21 is default
|
|
35
|
+
lastZ: 0 // Track Z changes for layer detection
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
model.classHierarchy.push('vtkGCodeReader');
|
|
39
|
+
if (!model.dataAccessHelper) {
|
|
40
|
+
model.dataAccessHelper = DataAccessHelper.get('http');
|
|
41
|
+
}
|
|
42
|
+
function fetchData(url) {
|
|
43
|
+
let option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
44
|
+
const {
|
|
45
|
+
compression,
|
|
46
|
+
progressCallback
|
|
47
|
+
} = model;
|
|
48
|
+
if (option.binary) {
|
|
49
|
+
return model.dataAccessHelper.fetchBinary(url, {
|
|
50
|
+
compression,
|
|
51
|
+
progressCallback
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return model.dataAccessHelper.fetchText(publicAPI, url, {
|
|
55
|
+
compression,
|
|
56
|
+
progressCallback
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function detectLayerChange(newZ) {
|
|
60
|
+
if (Math.abs(newZ - state.lastZ) > 0.001) {
|
|
61
|
+
state.currentLayer++;
|
|
62
|
+
state.lastZ = newZ;
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
function initializeLayer() {
|
|
68
|
+
if (!state.layers.has(state.currentLayer)) {
|
|
69
|
+
const points = vtkPoints.newInstance();
|
|
70
|
+
const lines = vtkCellArray.newInstance();
|
|
71
|
+
const polyData = vtkPolyData.newInstance();
|
|
72
|
+
polyData.setPoints(points);
|
|
73
|
+
polyData.setLines(lines);
|
|
74
|
+
state.layers.set(state.currentLayer, {
|
|
75
|
+
polyData,
|
|
76
|
+
points,
|
|
77
|
+
lines,
|
|
78
|
+
zHeight: state.lastZ
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function addLineToLayer(startPoint, endPoint) {
|
|
83
|
+
initializeLayer();
|
|
84
|
+
const layer = state.layers.get(state.currentLayer);
|
|
85
|
+
|
|
86
|
+
// Add points and get their indices
|
|
87
|
+
const startIndex = layer.points.insertNextPoint(startPoint[0], startPoint[1], startPoint[2]);
|
|
88
|
+
const endIndex = layer.points.insertNextPoint(endPoint[0], endPoint[1], endPoint[2]);
|
|
89
|
+
|
|
90
|
+
// Add line cell
|
|
91
|
+
layer.lines.insertNextCell([startIndex, endIndex]);
|
|
92
|
+
}
|
|
93
|
+
function processMove(params) {
|
|
94
|
+
const newPosition = {
|
|
95
|
+
...state.currentPosition
|
|
96
|
+
};
|
|
97
|
+
let positionChanged = false;
|
|
98
|
+
['X', 'Y', 'Z'].forEach(axis => {
|
|
99
|
+
if (axis in params) {
|
|
100
|
+
const value = state.isMetric ? params[axis] : params[axis] * 25.4;
|
|
101
|
+
newPosition[axis.toLowerCase()] = state.isAbsolute ? value + state.offset[axis.toLowerCase()] : state.currentPosition[axis.toLowerCase()] + value;
|
|
102
|
+
positionChanged = true;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
if (positionChanged) {
|
|
106
|
+
if ('Z' in params) {
|
|
107
|
+
detectLayerChange(newPosition.z);
|
|
108
|
+
}
|
|
109
|
+
const startPoint = [state.currentPosition.x, state.currentPosition.y, state.currentPosition.z];
|
|
110
|
+
const endPoint = [newPosition.x, newPosition.y, newPosition.z];
|
|
111
|
+
addLineToLayer(startPoint, endPoint);
|
|
112
|
+
state.currentPosition = newPosition;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function processG92(params) {
|
|
116
|
+
['X', 'Y', 'Z'].forEach(axis => {
|
|
117
|
+
if (axis in params) {
|
|
118
|
+
state.offset[axis.toLowerCase()] = state.currentPosition[axis.toLowerCase()] - (state.isMetric ? params[axis] : params[axis] * 25.4);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function processCommand(command, params) {
|
|
123
|
+
switch (command) {
|
|
124
|
+
case 'G0': // Rapid move
|
|
125
|
+
case 'G1':
|
|
126
|
+
// Linear move
|
|
127
|
+
processMove(params);
|
|
128
|
+
break;
|
|
129
|
+
case 'G20':
|
|
130
|
+
// Imperial
|
|
131
|
+
state.isMetric = false;
|
|
132
|
+
break;
|
|
133
|
+
case 'G21':
|
|
134
|
+
// Metric
|
|
135
|
+
state.isMetric = true;
|
|
136
|
+
break;
|
|
137
|
+
case 'G90':
|
|
138
|
+
// Absolute positioning
|
|
139
|
+
state.isAbsolute = true;
|
|
140
|
+
break;
|
|
141
|
+
case 'G91':
|
|
142
|
+
// Relative positioning
|
|
143
|
+
state.isAbsolute = false;
|
|
144
|
+
break;
|
|
145
|
+
case 'G92':
|
|
146
|
+
// Set position
|
|
147
|
+
processG92(params);
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function parseGCode(gcodeText) {
|
|
152
|
+
const lines = gcodeText.split('\n');
|
|
153
|
+
lines.forEach(line => {
|
|
154
|
+
const sline = line.split(';')[0].trim();
|
|
155
|
+
if (!sline) return;
|
|
156
|
+
const tokens = sline.split(' ');
|
|
157
|
+
const command = tokens[0];
|
|
158
|
+
const params = {};
|
|
159
|
+
tokens.slice(1).forEach(token => {
|
|
160
|
+
const param = token[0];
|
|
161
|
+
const value = parseFloat(token.slice(1));
|
|
162
|
+
if (!Number.isNaN(value)) {
|
|
163
|
+
params[param] = value;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
processCommand(command, params);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Public methods
|
|
171
|
+
publicAPI.setUrl = function (url) {
|
|
172
|
+
let option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
|
|
173
|
+
binary: true
|
|
174
|
+
};
|
|
175
|
+
model.url = url;
|
|
176
|
+
const path = url.split('/');
|
|
177
|
+
path.pop();
|
|
178
|
+
model.baseURL = path.join('/');
|
|
179
|
+
model.compression = option.compression;
|
|
180
|
+
return publicAPI.loadData({
|
|
181
|
+
progressCallback: option.progressCallback,
|
|
182
|
+
binary: !!option.binary
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
publicAPI.loadData = function () {
|
|
186
|
+
let option = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
187
|
+
const promise = fetchData(model.url, option);
|
|
188
|
+
promise.then(publicAPI.parse);
|
|
189
|
+
return promise;
|
|
190
|
+
};
|
|
191
|
+
publicAPI.parseAsText = content => {
|
|
192
|
+
parseGCode(content);
|
|
193
|
+
};
|
|
194
|
+
publicAPI.parseAsArrayBuffer = content => {
|
|
195
|
+
const data = BinaryHelper.arrayBufferToString(content);
|
|
196
|
+
parseGCode(data);
|
|
197
|
+
};
|
|
198
|
+
publicAPI.parse = content => {
|
|
199
|
+
if (typeof content === 'string') {
|
|
200
|
+
publicAPI.parseAsText(content);
|
|
201
|
+
} else {
|
|
202
|
+
publicAPI.parseAsArrayBuffer(content);
|
|
203
|
+
}
|
|
204
|
+
state.layers.forEach((layer, i) => {
|
|
205
|
+
model.output[i] = layer.polyData;
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
publicAPI.requestData = (inData, outData) => {
|
|
209
|
+
publicAPI.parse(model.parseData);
|
|
210
|
+
};
|
|
211
|
+
publicAPI.getNumberOfOutputPorts = () => state.layers.size;
|
|
212
|
+
}
|
|
213
|
+
const DEFAULT_VALUES = {
|
|
214
|
+
// baseURL: null,
|
|
215
|
+
// dataAccessHelper: null,
|
|
216
|
+
// url: null,
|
|
217
|
+
};
|
|
218
|
+
function extend(publicAPI, model) {
|
|
219
|
+
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
220
|
+
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
221
|
+
|
|
222
|
+
// Build VTK API
|
|
223
|
+
macro.obj(publicAPI, model);
|
|
224
|
+
macro.get(publicAPI, model, ['url', 'baseURL']);
|
|
225
|
+
macro.setGet(publicAPI, model, ['dataAccessHelper']);
|
|
226
|
+
macro.algo(publicAPI, model, 0, 1);
|
|
227
|
+
macro.event(publicAPI, model, 'ready');
|
|
228
|
+
vtkGCodeReader(publicAPI, model);
|
|
229
|
+
}
|
|
230
|
+
const newInstance = macro.newInstance(extend, 'vtkGCodeReader');
|
|
231
|
+
var vtkGCodeReader$1 = {
|
|
232
|
+
extend,
|
|
233
|
+
newInstance
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export { vtkGCodeReader$1 as default, extend, newInstance };
|
package/IO/Misc.js
CHANGED
|
@@ -7,6 +7,7 @@ import vtkMTLReader from './Misc/MTLReader.js';
|
|
|
7
7
|
import vtkOBJReader from './Misc/OBJReader.js';
|
|
8
8
|
import vtkPDBReader from './Misc/PDBReader.js';
|
|
9
9
|
import vtkSkyboxReader from './Misc/SkyboxReader.js';
|
|
10
|
+
import vtkGCodeReader from './Misc/GCodeReader.js';
|
|
10
11
|
|
|
11
12
|
var Misc = {
|
|
12
13
|
vtkElevationReader,
|
|
@@ -17,7 +18,8 @@ var Misc = {
|
|
|
17
18
|
vtkMTLReader,
|
|
18
19
|
vtkOBJReader,
|
|
19
20
|
vtkPDBReader,
|
|
20
|
-
vtkSkyboxReader
|
|
21
|
+
vtkSkyboxReader,
|
|
22
|
+
vtkGCodeReader
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
export { Misc as default };
|
|
@@ -30,7 +30,10 @@ const staticOffsetModel = {
|
|
|
30
30
|
offset: -2
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
|
-
const
|
|
33
|
+
const noOp = () => undefined;
|
|
34
|
+
const staticOffsetAPI = {
|
|
35
|
+
modified: noOp
|
|
36
|
+
};
|
|
34
37
|
addCoincidentTopologyMethods(staticOffsetAPI, staticOffsetModel, CATEGORIES.map(key => ({
|
|
35
38
|
key,
|
|
36
39
|
method: `ResolveCoincidentTopology${key}OffsetParameters`
|
|
@@ -61,7 +64,8 @@ function implementCoincidentTopologyMethods(publicAPI, model) {
|
|
|
61
64
|
Object.keys(otherStaticMethods).forEach(methodName => {
|
|
62
65
|
publicAPI[methodName] = otherStaticMethods[methodName];
|
|
63
66
|
});
|
|
64
|
-
Object.keys(staticOffsetAPI).
|
|
67
|
+
Object.keys(staticOffsetAPI).filter(methodName => methodName !== 'modified') // don't override instance's modified
|
|
68
|
+
.forEach(methodName => {
|
|
65
69
|
publicAPI[methodName] = staticOffsetAPI[methodName];
|
|
66
70
|
});
|
|
67
71
|
addCoincidentTopologyMethods(publicAPI, model.topologyOffset, CATEGORIES.map(key => ({
|
package/index.d.ts
CHANGED
|
@@ -97,6 +97,7 @@
|
|
|
97
97
|
/// <reference path="./IO/Geometry/STLReader.d.ts" />
|
|
98
98
|
/// <reference path="./IO/Geometry/STLWriter.d.ts" />
|
|
99
99
|
/// <reference path="./IO/Misc/ElevationReader.d.ts" />
|
|
100
|
+
/// <reference path="./IO/Misc/GCodeReader.d.ts" />
|
|
100
101
|
/// <reference path="./IO/Misc/ITKImageReader.d.ts" />
|
|
101
102
|
/// <reference path="./IO/Misc/ITKPolyDataReader.d.ts" />
|
|
102
103
|
/// <reference path="./IO/Misc/JSONNucleoReader.d.ts" />
|