@kitware/vtk.js 32.7.1 → 32.8.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/Common/Core/DataArray.d.ts +4 -0
- package/Common/Core/DataArray.js +3 -0
- package/IO/Geometry/GLTFImporter/Animations.js +1 -1
- package/IO/Geometry/GLTFImporter/Parser.js +1 -1
- package/IO/Geometry/GLTFImporter/Reader.js +55 -44
- package/IO/Geometry/GLTFImporter/Utils.js +1 -1
- package/IO/Geometry/IFCImporter.d.ts +163 -0
- package/IO/Geometry/IFCImporter.js +267 -0
- package/IO/Geometry.js +3 -1
- package/IO/Image/TIFFReader.d.ts +133 -0
- package/IO/Image/TIFFReader.js +144 -0
- package/IO/Image.js +3 -1
- package/Widgets/Widgets3D/AngleWidget/behavior.js +2 -0
- package/Widgets/Widgets3D/ResliceCursorWidget/behavior.js +17 -0
- package/Widgets/Widgets3D/ResliceCursorWidget/helpers.js +1 -0
- package/Widgets/Widgets3D/ShapeWidget/behavior.js +3 -0
- package/index.d.ts +2 -0
- package/package.json +2 -1
|
@@ -408,6 +408,10 @@ export function extend(
|
|
|
408
408
|
|
|
409
409
|
/**
|
|
410
410
|
* Method use to create a new instance of vtkDataArray
|
|
411
|
+
*
|
|
412
|
+
* If the provided `values` is a plain Array and `dataType` is not explicitly provided,
|
|
413
|
+
* then the vtkDataArray data type will be a Float32Array.
|
|
414
|
+
*
|
|
411
415
|
* @param {object} [initialValues] for pre-setting some of its content
|
|
412
416
|
*/
|
|
413
417
|
export function newInstance(initialValues?: object): vtkDataArray;
|
package/Common/Core/DataArray.js
CHANGED
|
@@ -497,6 +497,9 @@ const DEFAULT_VALUES = {
|
|
|
497
497
|
function extend(publicAPI, model) {
|
|
498
498
|
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
499
499
|
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
500
|
+
if (Array.isArray(initialValues.values) && initialValues.dataType === undefined) {
|
|
501
|
+
console.warn('vtkDataArray.newInstance: no dataType provided, converting to Float32Array');
|
|
502
|
+
}
|
|
500
503
|
if (!model.empty && !model.values && !model.size) {
|
|
501
504
|
throw new TypeError('Cannot create vtkDataArray object without: size > 0, values');
|
|
502
505
|
}
|
|
@@ -133,7 +133,7 @@ function createAnimationSampler(glTFSampler) {
|
|
|
133
133
|
result = cubicSplineInterpolate(path, t0, t1, i0, i1, time);
|
|
134
134
|
break;
|
|
135
135
|
default:
|
|
136
|
-
|
|
136
|
+
vtkWarningMacro(`Unknown interpolation method: ${glTFSampler.interpolation}`);
|
|
137
137
|
}
|
|
138
138
|
return result;
|
|
139
139
|
}
|
|
@@ -101,7 +101,7 @@ class GLTFParser {
|
|
|
101
101
|
if (mesh.primitives) {
|
|
102
102
|
mesh.primitives = mesh.primitives.map((primitive, idx) => {
|
|
103
103
|
const attributes = primitive.attributes;
|
|
104
|
-
primitive.name = `
|
|
104
|
+
primitive.name = `primitive-${idx}`;
|
|
105
105
|
primitive.attributes = {};
|
|
106
106
|
for (const attribute in attributes) {
|
|
107
107
|
const attr = SEMANTIC_ATTRIBUTE_MAP[attribute];
|
|
@@ -30,18 +30,15 @@ async function parseGLTF(gltf, options) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* Creates VTK polydata from a GLTF mesh
|
|
34
|
-
* @param {
|
|
33
|
+
* Creates VTK polydata from a GLTF mesh primitive
|
|
34
|
+
* @param {GLTFPrimitive} primitive - The GLTF mesh primitive
|
|
35
35
|
* @returns {vtkPolyData} The created VTK polydata
|
|
36
36
|
*/
|
|
37
|
-
async function createPolyDataFromGLTFMesh(
|
|
38
|
-
const primitive = mesh.primitives[0]; // For simplicity, we'll just use the first primitive
|
|
39
|
-
|
|
37
|
+
async function createPolyDataFromGLTFMesh(primitive) {
|
|
40
38
|
if (!primitive || !primitive.attributes) {
|
|
41
|
-
vtkWarningMacro('
|
|
39
|
+
vtkWarningMacro('Primitive has no position data, skipping');
|
|
42
40
|
return null;
|
|
43
41
|
}
|
|
44
|
-
const mode = primitive.mode;
|
|
45
42
|
if (primitive.extensions?.KHR_draco_mesh_compression) {
|
|
46
43
|
return handleKHRDracoMeshCompression(primitive.extensions.KHR_draco_mesh_compression);
|
|
47
44
|
}
|
|
@@ -118,10 +115,10 @@ async function createPolyDataFromGLTFMesh(mesh) {
|
|
|
118
115
|
});
|
|
119
116
|
|
|
120
117
|
// Handle indices if available
|
|
121
|
-
if (primitive.indices
|
|
118
|
+
if (primitive.indices != null) {
|
|
122
119
|
const indices = primitive.indices.value;
|
|
123
120
|
const nCells = indices.length - 2;
|
|
124
|
-
switch (mode) {
|
|
121
|
+
switch (primitive.mode) {
|
|
125
122
|
case MODES.GL_LINE_STRIP:
|
|
126
123
|
case MODES.GL_TRIANGLE_STRIP:
|
|
127
124
|
case MODES.GL_LINE_LOOP:
|
|
@@ -135,7 +132,7 @@ async function createPolyDataFromGLTFMesh(mesh) {
|
|
|
135
132
|
}
|
|
136
133
|
}
|
|
137
134
|
}
|
|
138
|
-
switch (mode) {
|
|
135
|
+
switch (primitive.mode) {
|
|
139
136
|
case MODES.GL_TRIANGLES:
|
|
140
137
|
case MODES.GL_TRIANGLE_FAN:
|
|
141
138
|
polyData.setPolys(cells);
|
|
@@ -159,7 +156,7 @@ async function createPolyDataFromGLTFMesh(mesh) {
|
|
|
159
156
|
|
|
160
157
|
/**
|
|
161
158
|
* Creates a VTK property from a GLTF material
|
|
162
|
-
* @param {
|
|
159
|
+
* @param {object} model - The vtk model object
|
|
163
160
|
* @param {GLTFMaterial} material - The GLTF material
|
|
164
161
|
* @param {vtkActor} actor - The VTK actor
|
|
165
162
|
*/
|
|
@@ -169,15 +166,15 @@ async function createPropertyFromGLTFMaterial(model, material, actor) {
|
|
|
169
166
|
const emissiveFactor = material.emissiveFactor;
|
|
170
167
|
const property = actor.getProperty();
|
|
171
168
|
const pbr = material.pbrMetallicRoughness;
|
|
172
|
-
if (pbr
|
|
169
|
+
if (pbr != null) {
|
|
173
170
|
if (!pbr?.metallicFactor || pbr?.metallicFactor <= 0 || pbr?.metallicFactor >= 1) {
|
|
174
|
-
|
|
171
|
+
vtkDebugMacro('Invalid material.pbrMetallicRoughness.metallicFactor value. Using default value instead.');
|
|
175
172
|
} else metallicFactor = pbr.metallicFactor;
|
|
176
173
|
if (!pbr?.roughnessFactor || pbr?.roughnessFactor <= 0 || pbr?.roughnessFactor >= 1) {
|
|
177
|
-
|
|
174
|
+
vtkDebugMacro('Invalid material.pbrMetallicRoughness.roughnessFactor value. Using default value instead.');
|
|
178
175
|
} else roughnessFactor = pbr.roughnessFactor;
|
|
179
176
|
const color = pbr.baseColorFactor;
|
|
180
|
-
if (color
|
|
177
|
+
if (color != null) {
|
|
181
178
|
property.setDiffuseColor(color[0], color[1], color[2]);
|
|
182
179
|
property.setOpacity(color[3]);
|
|
183
180
|
}
|
|
@@ -187,7 +184,7 @@ async function createPropertyFromGLTFMaterial(model, material, actor) {
|
|
|
187
184
|
if (pbr.baseColorTexture) {
|
|
188
185
|
pbr.baseColorTexture.extensions;
|
|
189
186
|
const tex = pbr.baseColorTexture.texture;
|
|
190
|
-
if (tex.extensions
|
|
187
|
+
if (tex.extensions != null) {
|
|
191
188
|
const extensionsNames = Object.keys(tex.extensions);
|
|
192
189
|
extensionsNames.forEach(extensionName => {
|
|
193
190
|
// TODO: Handle KHR_texture_basisu extension
|
|
@@ -243,7 +240,7 @@ async function createPropertyFromGLTFMaterial(model, material, actor) {
|
|
|
243
240
|
property.setEmissionTexture(emissiveTex);
|
|
244
241
|
|
|
245
242
|
// Handle mutiple Uvs
|
|
246
|
-
if (material.emissiveTexture.texCoord
|
|
243
|
+
if (material.emissiveTexture.texCoord != null) {
|
|
247
244
|
const pd = actor.getMapper().getInputData().getPointData();
|
|
248
245
|
pd.setActiveTCoords(`TEXCOORD_${material.emissiveTexture.texCoord}`);
|
|
249
246
|
}
|
|
@@ -257,14 +254,14 @@ async function createPropertyFromGLTFMaterial(model, material, actor) {
|
|
|
257
254
|
const normalImage = await loadImage(tex.source);
|
|
258
255
|
const normalTex = createVTKTextureFromGLTFTexture(normalImage, sampler);
|
|
259
256
|
property.setNormalTexture(normalTex);
|
|
260
|
-
if (material.normalTexture.scale
|
|
257
|
+
if (material.normalTexture.scale != null) {
|
|
261
258
|
property.setNormalStrength(material.normalTexture.scale);
|
|
262
259
|
}
|
|
263
260
|
}
|
|
264
261
|
}
|
|
265
262
|
|
|
266
263
|
// Material extensions
|
|
267
|
-
if (material.extensions
|
|
264
|
+
if (material.extensions != null) {
|
|
268
265
|
const extensionsNames = Object.keys(material.extensions);
|
|
269
266
|
extensionsNames.forEach(extensionName => {
|
|
270
267
|
const extension = material.extensions[extensionName];
|
|
@@ -291,17 +288,17 @@ async function createPropertyFromGLTFMaterial(model, material, actor) {
|
|
|
291
288
|
|
|
292
289
|
/**
|
|
293
290
|
* Handles primitive extensions
|
|
291
|
+
* @param {string} nodeId The GLTF node id
|
|
294
292
|
* @param {*} extensions The extensions object
|
|
295
293
|
* @param {*} model The vtk model object
|
|
296
|
-
* @param {GLTFNode} node The GLTF node
|
|
297
294
|
*/
|
|
298
|
-
function handlePrimitiveExtensions(extensions, model
|
|
295
|
+
function handlePrimitiveExtensions(nodeId, extensions, model) {
|
|
299
296
|
const extensionsNames = Object.keys(extensions);
|
|
300
297
|
extensionsNames.forEach(extensionName => {
|
|
301
298
|
const extension = extensions[extensionName];
|
|
302
299
|
switch (extensionName) {
|
|
303
300
|
case 'KHR_materials_variants':
|
|
304
|
-
model.variantMappings.set(
|
|
301
|
+
model.variantMappings.set(nodeId, extension.mappings);
|
|
305
302
|
break;
|
|
306
303
|
default:
|
|
307
304
|
vtkWarningMacro(`Unhandled extension: ${extensionName}`);
|
|
@@ -314,33 +311,43 @@ function handlePrimitiveExtensions(extensions, model, node) {
|
|
|
314
311
|
* @param {GLTFMesh} mesh - The GLTF mesh
|
|
315
312
|
* @returns {vtkActor} The created VTK actor
|
|
316
313
|
*/
|
|
317
|
-
async function createActorFromGTLFNode(
|
|
314
|
+
async function createActorFromGTLFNode(worldMatrix) {
|
|
318
315
|
const actor = vtkActor.newInstance();
|
|
319
316
|
const mapper = vtkMapper.newInstance();
|
|
320
317
|
mapper.setColorModeToDirectScalars();
|
|
321
318
|
actor.setMapper(mapper);
|
|
322
319
|
actor.setUserMatrix(worldMatrix);
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
320
|
+
const polydata = vtkPolyData.newInstance();
|
|
321
|
+
mapper.setInputData(polydata);
|
|
322
|
+
return actor;
|
|
323
|
+
}
|
|
327
324
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
325
|
+
/**
|
|
326
|
+
* Creates a VTK actor from a GLTF mesh
|
|
327
|
+
* @param {GLTFMesh} mesh - The GLTF mesh
|
|
328
|
+
* @returns {vtkActor} The created VTK actor
|
|
329
|
+
*/
|
|
330
|
+
async function createActorFromGTLFPrimitive(model, primitive, worldMatrix) {
|
|
331
|
+
const actor = vtkActor.newInstance();
|
|
332
|
+
const mapper = vtkMapper.newInstance();
|
|
333
|
+
mapper.setColorModeToDirectScalars();
|
|
334
|
+
actor.setMapper(mapper);
|
|
335
|
+
actor.setUserMatrix(worldMatrix);
|
|
336
|
+
const polydata = await createPolyDataFromGLTFMesh(primitive);
|
|
337
|
+
mapper.setInputData(polydata);
|
|
338
|
+
|
|
339
|
+
// Support for materials
|
|
340
|
+
if (primitive.material != null) {
|
|
341
|
+
await createPropertyFromGLTFMaterial(model, primitive.material, actor);
|
|
342
|
+
}
|
|
343
|
+
if (primitive.extensions != null) {
|
|
344
|
+
handlePrimitiveExtensions(`${primitive.name}`, primitive.extensions, model);
|
|
338
345
|
}
|
|
339
346
|
return actor;
|
|
340
347
|
}
|
|
341
348
|
|
|
342
349
|
/**
|
|
343
|
-
*
|
|
350
|
+
* Creates a GLTF animation object
|
|
344
351
|
* @param {GLTFAnimation} animation
|
|
345
352
|
* @returns
|
|
346
353
|
*/
|
|
@@ -366,7 +373,7 @@ function getTransformationMatrix(node) {
|
|
|
366
373
|
const translation = node.translation ?? vec3.create();
|
|
367
374
|
const rotation = node.rotation ?? quat.create();
|
|
368
375
|
const scale = node.scale ?? vec3.fromValues(1.0, 1.0, 1.0);
|
|
369
|
-
const matrix = node.matrix
|
|
376
|
+
const matrix = node.matrix != null ? mat4.clone(node.matrix) : mat4.fromRotationTranslationScale(mat4.create(), rotation, translation, scale);
|
|
370
377
|
return matrix;
|
|
371
378
|
}
|
|
372
379
|
|
|
@@ -384,13 +391,17 @@ async function processNode(node, model) {
|
|
|
384
391
|
const worldMatrix = mat4.multiply(mat4.create(), parentMatrix, node.transform);
|
|
385
392
|
|
|
386
393
|
// Create actor for the current node
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
actor.setUserMatrix(worldMatrix);
|
|
394
|
+
if (node.mesh != null) {
|
|
395
|
+
const nodeActor = await createActorFromGTLFNode(worldMatrix);
|
|
390
396
|
if (parentActor) {
|
|
391
|
-
|
|
397
|
+
nodeActor.setParentProp(parentActor);
|
|
392
398
|
}
|
|
393
|
-
model.actors.set(node.id
|
|
399
|
+
model.actors.set(`${node.id}`, nodeActor);
|
|
400
|
+
await Promise.all(node.mesh.primitives.map(async (primitive, i) => {
|
|
401
|
+
const actor = await createActorFromGTLFPrimitive(model, primitive, worldMatrix);
|
|
402
|
+
actor.setParentProp(nodeActor);
|
|
403
|
+
model.actors.set(`${node.id}_${primitive.name}`, actor);
|
|
404
|
+
}));
|
|
394
405
|
}
|
|
395
406
|
|
|
396
407
|
// Handle KHRLightsPunctual extension
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { vtkAlgorithm, vtkObject } from './../../interfaces';
|
|
2
|
+
import vtkRenderer from './../../Rendering/Core/Renderer';
|
|
3
|
+
import HtmlDataAccessHelper from './../Core/DataAccessHelper/HtmlDataAccessHelper';
|
|
4
|
+
import HttpDataAccessHelper from './../Core/DataAccessHelper/HttpDataAccessHelper';
|
|
5
|
+
import JSZipDataAccessHelper from './../Core/DataAccessHelper/JSZipDataAccessHelper';
|
|
6
|
+
import LiteHttpDataAccessHelper from './../Core/DataAccessHelper/LiteHttpDataAccessHelper';
|
|
7
|
+
|
|
8
|
+
interface IIFCImporterOptions {
|
|
9
|
+
compression?: string;
|
|
10
|
+
progressCallback?: any;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export interface IIFCImporterInitialValues {
|
|
17
|
+
mergeGeometries?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type vtkIFCImporterBase = vtkObject &
|
|
21
|
+
Omit<
|
|
22
|
+
vtkAlgorithm,
|
|
23
|
+
| 'getInputData'
|
|
24
|
+
| 'setInputData'
|
|
25
|
+
| 'setInputConnection'
|
|
26
|
+
| 'getInputConnection'
|
|
27
|
+
| 'addInputConnection'
|
|
28
|
+
| 'addInputData'
|
|
29
|
+
>;
|
|
30
|
+
|
|
31
|
+
export interface vtkIFCImporter extends vtkIFCImporterBase {
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
*/
|
|
35
|
+
getBaseURL(): string;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
*/
|
|
40
|
+
getDataAccessHelper():
|
|
41
|
+
| HtmlDataAccessHelper
|
|
42
|
+
| HttpDataAccessHelper
|
|
43
|
+
| JSZipDataAccessHelper
|
|
44
|
+
| LiteHttpDataAccessHelper;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get the url of the object to load.
|
|
48
|
+
*/
|
|
49
|
+
getUrl(): string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Import actors into the renderer.
|
|
53
|
+
* @param {vtkRenderer} renderer The vtkRenderer to import the actors into.
|
|
54
|
+
*/
|
|
55
|
+
importActors(renderer: vtkRenderer): void;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Load the object data.
|
|
59
|
+
* @param {IIFCImporterOptions} [options]
|
|
60
|
+
*/
|
|
61
|
+
loadData(options?: IIFCImporterOptions): Promise<any>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Parse data.
|
|
65
|
+
* @param {String | ArrayBuffer} content The content to parse.
|
|
66
|
+
*/
|
|
67
|
+
parse(content: string | ArrayBuffer): void;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Parse data as ArrayBuffer.
|
|
71
|
+
* @param {ArrayBuffer} content The content to parse.
|
|
72
|
+
*/
|
|
73
|
+
parseAsArrayBuffer(content: ArrayBuffer): void;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
*
|
|
77
|
+
* @param inData
|
|
78
|
+
* @param outData
|
|
79
|
+
*/
|
|
80
|
+
requestData(inData: any, outData: any): void;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
* @param dataAccessHelper
|
|
85
|
+
*/
|
|
86
|
+
setDataAccessHelper(
|
|
87
|
+
dataAccessHelper:
|
|
88
|
+
| HtmlDataAccessHelper
|
|
89
|
+
| HttpDataAccessHelper
|
|
90
|
+
| JSZipDataAccessHelper
|
|
91
|
+
| LiteHttpDataAccessHelper
|
|
92
|
+
): boolean;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Set the url of the object to load.
|
|
96
|
+
* @param {String} url the url of the object to load.
|
|
97
|
+
* @param {IIFCImporterOptions} [option] The PLY reader options.
|
|
98
|
+
*/
|
|
99
|
+
setUrl(url: string, option?: IIFCImporterOptions): Promise<string | any>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Set WebIFC api to be used by vtkIFCImporter
|
|
104
|
+
* @param {object} ifcApi
|
|
105
|
+
*/
|
|
106
|
+
export function setIFCAPI(ifcApi: any): void;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Method used to decorate a given object (publicAPI+model) with vtkIFCImporter characteristics.
|
|
110
|
+
*
|
|
111
|
+
* @param publicAPI object on which methods will be bounds (public)
|
|
112
|
+
* @param model object on which data structure will be bounds (protected)
|
|
113
|
+
* @param {IIFCImporterInitialValues} [initialValues] (default: {})
|
|
114
|
+
*/
|
|
115
|
+
export function extend(
|
|
116
|
+
publicAPI: object,
|
|
117
|
+
model: object,
|
|
118
|
+
initialValues?: IIFCImporterInitialValues
|
|
119
|
+
): void;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Method used to create a new instance of vtkIFCImporter
|
|
123
|
+
* @param {IIFCImporterInitialValues} [initialValues] for pre-setting some of its content
|
|
124
|
+
*/
|
|
125
|
+
export function newInstance(
|
|
126
|
+
initialValues?: IIFCImporterInitialValues
|
|
127
|
+
): vtkIFCImporter;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* vtkIFCImporter is a source object that reads Industry Foundation Class(IFC) files.
|
|
131
|
+
*
|
|
132
|
+
* The vtkIFCImporter is using web-ifc library to parse the IFC file.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```js
|
|
136
|
+
* import vtkResourceLoader from '@kitware/vtk.js/IO/Core/ResourceLoader';
|
|
137
|
+
* import vtkIFCImporter from '@kitware/vtk.js/IO/Geometry/IFCImporter';
|
|
138
|
+
*
|
|
139
|
+
* function update() {
|
|
140
|
+
* importer.onReady(() => {
|
|
141
|
+
* importer.importActors(renderer);
|
|
142
|
+
* renderer.resetCamera();
|
|
143
|
+
* renderWindow.render();
|
|
144
|
+
* });
|
|
145
|
+
* }
|
|
146
|
+
*
|
|
147
|
+
* vtkResourceLoader
|
|
148
|
+
* .loadScript('https://cdn.jsdelivr.net/npm/web-ifc@0.0.55/web-ifc-api-iife.js')
|
|
149
|
+
* .then(() => {
|
|
150
|
+
* // Pass WebIFC api to vtkIFCImporter
|
|
151
|
+
* vtkIFCImporter.setIFCAPI(window.WebIFC);
|
|
152
|
+
*
|
|
153
|
+
* // Trigger data download
|
|
154
|
+
* importer.setUrl(`${__BASE_PATH__}/data/ifc/house.ifc`).then(update);
|
|
155
|
+
* });
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export declare const vtkIFCImporter: {
|
|
159
|
+
newInstance: typeof newInstance;
|
|
160
|
+
extend: typeof extend;
|
|
161
|
+
setIFCAPI: typeof setIFCAPI;
|
|
162
|
+
};
|
|
163
|
+
export default vtkIFCImporter;
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { m as macro } from '../../macros2.js';
|
|
2
|
+
import '../Core/DataAccessHelper/LiteHttpDataAccessHelper.js';
|
|
3
|
+
import DataAccessHelper from '../Core/DataAccessHelper.js';
|
|
4
|
+
import vtkActor from '../../Rendering/Core/Actor.js';
|
|
5
|
+
import vtkMapper from '../../Rendering/Core/Mapper.js';
|
|
6
|
+
import vtkDataArray from '../../Common/Core/DataArray.js';
|
|
7
|
+
import vtkPolyData from '../../Common/DataModel/PolyData.js';
|
|
8
|
+
import vtkCellArray from '../../Common/Core/CellArray.js';
|
|
9
|
+
import vtkAppendPolyData from '../../Filters/General/AppendPolyData.js';
|
|
10
|
+
import vtkMatrixBuilder from '../../Common/Core/MatrixBuilder.js';
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
vtkErrorMacro
|
|
14
|
+
} = macro;
|
|
15
|
+
let WebIFC;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Set WebIFC api to be used by vtkIFCImporter
|
|
19
|
+
* @param {object} ifcApi
|
|
20
|
+
*/
|
|
21
|
+
function setIFCAPI(ifcApi) {
|
|
22
|
+
WebIFC = ifcApi;
|
|
23
|
+
}
|
|
24
|
+
function vtkIFCImporter(publicAPI, model) {
|
|
25
|
+
model.classHierarchy.push('vtkIFCImporter');
|
|
26
|
+
const meshes = [];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a vtkPolyData from an IFC mesh object
|
|
30
|
+
* @param {object} mesh the IFC web mesh object
|
|
31
|
+
* @returns vtkPolyData
|
|
32
|
+
*/
|
|
33
|
+
function createPolyDataFromIFCMesh(mesh) {
|
|
34
|
+
const {
|
|
35
|
+
vertices,
|
|
36
|
+
indices
|
|
37
|
+
} = mesh;
|
|
38
|
+
const pd = vtkPolyData.newInstance();
|
|
39
|
+
const cells = vtkCellArray.newInstance();
|
|
40
|
+
const pointValues = new Float32Array(vertices.length / 2);
|
|
41
|
+
const normalsArray = new Float32Array(vertices.length / 2);
|
|
42
|
+
for (let i = 0; i < vertices.length; i += 6) {
|
|
43
|
+
pointValues[i / 2] = vertices[i];
|
|
44
|
+
pointValues[i / 2 + 1] = vertices[i + 1];
|
|
45
|
+
pointValues[i / 2 + 2] = vertices[i + 2];
|
|
46
|
+
normalsArray[i / 2] = vertices[i + 3];
|
|
47
|
+
normalsArray[i / 2 + 1] = vertices[i + 4];
|
|
48
|
+
normalsArray[i / 2 + 2] = vertices[i + 5];
|
|
49
|
+
}
|
|
50
|
+
const nCells = indices.length;
|
|
51
|
+
cells.resize(3 * nCells / 3);
|
|
52
|
+
for (let cellId = 0; cellId < nCells; cellId += 3) {
|
|
53
|
+
const cell = indices.slice(cellId, cellId + 3);
|
|
54
|
+
cells.insertNextCell(cell);
|
|
55
|
+
}
|
|
56
|
+
pd.getPoints().setData(pointValues, 3);
|
|
57
|
+
pd.setStrips(cells);
|
|
58
|
+
pd.getPointData().setNormals(vtkDataArray.newInstance({
|
|
59
|
+
name: 'Normals',
|
|
60
|
+
values: normalsArray,
|
|
61
|
+
numberOfComponents: 3
|
|
62
|
+
}));
|
|
63
|
+
return pd;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Create a colored vtkPolyData from an IFC mesh object
|
|
68
|
+
* @param {object} mesh the IFC mesh object
|
|
69
|
+
* @returns vtkPolyData
|
|
70
|
+
*/
|
|
71
|
+
function createColoredPolyDataFromIFCMesh(mesh) {
|
|
72
|
+
const {
|
|
73
|
+
vertices,
|
|
74
|
+
indices,
|
|
75
|
+
color,
|
|
76
|
+
userMatrix
|
|
77
|
+
} = mesh;
|
|
78
|
+
const pd = vtkPolyData.newInstance();
|
|
79
|
+
const cells = vtkCellArray.newInstance();
|
|
80
|
+
const pointValues = new Float32Array(vertices.length / 2);
|
|
81
|
+
const normalsArray = new Float32Array(vertices.length / 2);
|
|
82
|
+
const colorArray = new Float32Array(vertices.length / 2);
|
|
83
|
+
if (userMatrix) {
|
|
84
|
+
const transformMatrix = vtkMatrixBuilder.buildFromRadian().setMatrix(userMatrix);
|
|
85
|
+
for (let i = 0; i < vertices.length; i += 6) {
|
|
86
|
+
const point = [vertices[i], vertices[i + 1], vertices[i + 2]];
|
|
87
|
+
const normal = [vertices[i + 3], vertices[i + 4], vertices[i + 5]];
|
|
88
|
+
transformMatrix.apply(point).apply(normal);
|
|
89
|
+
pointValues[i / 2] = point[0];
|
|
90
|
+
pointValues[i / 2 + 1] = point[1];
|
|
91
|
+
pointValues[i / 2 + 2] = point[2];
|
|
92
|
+
normalsArray[i / 2] = normal[0];
|
|
93
|
+
normalsArray[i / 2 + 1] = normal[1];
|
|
94
|
+
normalsArray[i / 2 + 2] = normal[2];
|
|
95
|
+
const colorIndex = i / 2;
|
|
96
|
+
colorArray[colorIndex] = color.x;
|
|
97
|
+
colorArray[colorIndex + 1] = color.y;
|
|
98
|
+
colorArray[colorIndex + 2] = color.z;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
for (let i = 0; i < vertices.length; i += 6) {
|
|
102
|
+
pointValues[i / 2] = vertices[i];
|
|
103
|
+
pointValues[i / 2 + 1] = vertices[i + 1];
|
|
104
|
+
pointValues[i / 2 + 2] = vertices[i + 2];
|
|
105
|
+
normalsArray[i / 2] = vertices[i + 3];
|
|
106
|
+
normalsArray[i / 2 + 1] = vertices[i + 4];
|
|
107
|
+
normalsArray[i / 2 + 2] = vertices[i + 5];
|
|
108
|
+
const colorIndex = i / 2;
|
|
109
|
+
colorArray[colorIndex] = color.x;
|
|
110
|
+
colorArray[colorIndex + 1] = color.y;
|
|
111
|
+
colorArray[colorIndex + 2] = color.z;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const nCells = indices.length;
|
|
115
|
+
cells.resize(3 * nCells / 3);
|
|
116
|
+
for (let cellId = 0; cellId < nCells; cellId += 3) {
|
|
117
|
+
const cell = indices.slice(cellId, cellId + 3);
|
|
118
|
+
cells.insertNextCell(cell);
|
|
119
|
+
}
|
|
120
|
+
pd.getPoints().setData(pointValues, 3);
|
|
121
|
+
pd.setPolys(cells);
|
|
122
|
+
pd.getPointData().setNormals(vtkDataArray.newInstance({
|
|
123
|
+
name: 'Normals',
|
|
124
|
+
values: normalsArray,
|
|
125
|
+
numberOfComponents: 3
|
|
126
|
+
}));
|
|
127
|
+
pd.getPointData().setScalars(vtkDataArray.newInstance({
|
|
128
|
+
name: 'Colors',
|
|
129
|
+
values: colorArray,
|
|
130
|
+
numberOfComponents: 3
|
|
131
|
+
}));
|
|
132
|
+
return pd;
|
|
133
|
+
}
|
|
134
|
+
function parseIfc(content) {
|
|
135
|
+
const modelID = model._ifcApi.OpenModel(new Uint8Array(content), {
|
|
136
|
+
COORDINATE_TO_ORIGIN: true,
|
|
137
|
+
USE_FAST_BOOLS: true
|
|
138
|
+
});
|
|
139
|
+
model._ifcApi.StreamAllMeshes(modelID, mesh => {
|
|
140
|
+
const placedGeometries = mesh.geometries;
|
|
141
|
+
for (let i = 0; i < placedGeometries.size(); i++) {
|
|
142
|
+
const placedGeometry = placedGeometries.get(i);
|
|
143
|
+
const ifcGeometryData = model._ifcApi.GetGeometry(modelID, placedGeometry.geometryExpressID);
|
|
144
|
+
const ifcVertices = model._ifcApi.GetVertexArray(ifcGeometryData.GetVertexData(), ifcGeometryData.GetVertexDataSize());
|
|
145
|
+
const ifcIndices = model._ifcApi.GetIndexArray(ifcGeometryData.GetIndexData(), ifcGeometryData.GetIndexDataSize());
|
|
146
|
+
meshes.push({
|
|
147
|
+
vertices: ifcVertices,
|
|
148
|
+
indices: ifcIndices,
|
|
149
|
+
color: placedGeometry.color,
|
|
150
|
+
userMatrix: placedGeometry.flatTransformation
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
model._ifcApi.CloseModel(modelID);
|
|
155
|
+
}
|
|
156
|
+
if (!model.dataAccessHelper) {
|
|
157
|
+
model.dataAccessHelper = DataAccessHelper.get('http');
|
|
158
|
+
}
|
|
159
|
+
function fetchData(url) {
|
|
160
|
+
const {
|
|
161
|
+
compression,
|
|
162
|
+
progressCallback
|
|
163
|
+
} = model;
|
|
164
|
+
return model.dataAccessHelper.fetchBinary(url, {
|
|
165
|
+
compression,
|
|
166
|
+
progressCallback
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
publicAPI.setUrl = function (url) {
|
|
170
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
|
|
171
|
+
binary: true
|
|
172
|
+
};
|
|
173
|
+
model.url = url;
|
|
174
|
+
model.baseURL = url.split('/').slice(0, -1).join('/');
|
|
175
|
+
model.compression = options.compression;
|
|
176
|
+
return publicAPI.loadData(options);
|
|
177
|
+
};
|
|
178
|
+
publicAPI.loadData = function () {
|
|
179
|
+
return fetchData(model.url).then(publicAPI.parse);
|
|
180
|
+
};
|
|
181
|
+
publicAPI.parse = content => {
|
|
182
|
+
publicAPI.parseAsArrayBuffer(content);
|
|
183
|
+
};
|
|
184
|
+
publicAPI.parseAsArrayBuffer = content => {
|
|
185
|
+
if (!content) {
|
|
186
|
+
vtkErrorMacro('No content to parse.');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (!WebIFC) {
|
|
190
|
+
vtkErrorMacro('vtkIFCImporter requires WebIFC API to be set.');
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
model._ifcApi = new WebIFC.IfcAPI();
|
|
194
|
+
model._ifcApi.Init().then(() => {
|
|
195
|
+
parseIfc(content);
|
|
196
|
+
publicAPI.invokeReady();
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
publicAPI.importActors = renderer => {
|
|
200
|
+
if (model.mergeGeometries) {
|
|
201
|
+
const opaqueMeshes = meshes.filter(mesh => mesh.color.w === 1);
|
|
202
|
+
let apd = vtkAppendPolyData.newInstance();
|
|
203
|
+
opaqueMeshes.forEach(mesh => {
|
|
204
|
+
const pd = createColoredPolyDataFromIFCMesh(mesh);
|
|
205
|
+
apd.addInputData(pd);
|
|
206
|
+
});
|
|
207
|
+
let mapper = vtkMapper.newInstance();
|
|
208
|
+
mapper.setColorModeToDirectScalars();
|
|
209
|
+
mapper.setInputConnection(apd.getOutputPort());
|
|
210
|
+
let actor = vtkActor.newInstance();
|
|
211
|
+
actor.setMapper(mapper);
|
|
212
|
+
renderer.addActor(actor);
|
|
213
|
+
const transparentMeshes = meshes.filter(mesh => mesh.color.w < 1);
|
|
214
|
+
apd = vtkAppendPolyData.newInstance();
|
|
215
|
+
transparentMeshes.forEach(mesh => {
|
|
216
|
+
const pd = createColoredPolyDataFromIFCMesh(mesh);
|
|
217
|
+
apd.addInputData(pd);
|
|
218
|
+
});
|
|
219
|
+
mapper = vtkMapper.newInstance();
|
|
220
|
+
mapper.setColorModeToDirectScalars();
|
|
221
|
+
mapper.setInputConnection(apd.getOutputPort());
|
|
222
|
+
actor = vtkActor.newInstance();
|
|
223
|
+
actor.setMapper(mapper);
|
|
224
|
+
actor.getProperty().setOpacity(0.5);
|
|
225
|
+
renderer.addActor(actor);
|
|
226
|
+
} else {
|
|
227
|
+
meshes.forEach(mesh => {
|
|
228
|
+
const pd = createPolyDataFromIFCMesh(mesh);
|
|
229
|
+
const mapper = vtkMapper.newInstance();
|
|
230
|
+
mapper.setInputData(pd);
|
|
231
|
+
const actor = vtkActor.newInstance();
|
|
232
|
+
actor.setMapper(mapper);
|
|
233
|
+
const {
|
|
234
|
+
x,
|
|
235
|
+
y,
|
|
236
|
+
z,
|
|
237
|
+
w
|
|
238
|
+
} = mesh.color;
|
|
239
|
+
actor.getProperty().setColor(x, y, z);
|
|
240
|
+
actor.getProperty().setOpacity(w);
|
|
241
|
+
actor.setUserMatrix(mesh.userMatrix);
|
|
242
|
+
renderer.addActor(actor);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
const DEFAULT_VALUES = {
|
|
248
|
+
mergeGeometries: false
|
|
249
|
+
};
|
|
250
|
+
function extend(publicAPI, model) {
|
|
251
|
+
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
252
|
+
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
253
|
+
macro.obj(publicAPI, model);
|
|
254
|
+
macro.get(publicAPI, model, ['url', 'baseURL']);
|
|
255
|
+
macro.setGet(publicAPI, model, ['dataAccessHelper', 'mergeGeometries']);
|
|
256
|
+
macro.event(publicAPI, model, 'ready');
|
|
257
|
+
macro.algo(publicAPI, model, 0, 1);
|
|
258
|
+
vtkIFCImporter(publicAPI, model);
|
|
259
|
+
}
|
|
260
|
+
const newInstance = macro.newInstance(extend, 'vtkIFCImporter');
|
|
261
|
+
var vtkIFCImporter$1 = {
|
|
262
|
+
newInstance,
|
|
263
|
+
extend,
|
|
264
|
+
setIFCAPI
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
export { vtkIFCImporter$1 as default, extend, newInstance };
|
package/IO/Geometry.js
CHANGED
|
@@ -4,6 +4,7 @@ import vtkDracoReader from './Geometry/DracoReader.js';
|
|
|
4
4
|
import vtkSTLWriter from './Geometry/STLWriter.js';
|
|
5
5
|
import vtkPLYWriter from './Geometry/PLYWriter.js';
|
|
6
6
|
import vtkGLTFImporter from './Geometry/GLTFImporter.js';
|
|
7
|
+
import vtkIFCImporter from './Geometry/IFCImporter.js';
|
|
7
8
|
|
|
8
9
|
var Geometry = {
|
|
9
10
|
vtkSTLReader,
|
|
@@ -11,7 +12,8 @@ var Geometry = {
|
|
|
11
12
|
vtkDracoReader,
|
|
12
13
|
vtkSTLWriter,
|
|
13
14
|
vtkPLYWriter,
|
|
14
|
-
vtkGLTFImporter
|
|
15
|
+
vtkGLTFImporter,
|
|
16
|
+
vtkIFCImporter
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
export { Geometry as default };
|
|
@@ -0,0 +1,133 @@
|
|
|
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 ITIFFReaderOptions {
|
|
8
|
+
compression?: string;
|
|
9
|
+
progressCallback?: any;
|
|
10
|
+
flipY?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
*/
|
|
16
|
+
export interface ITIFFReaderInitialValues {}
|
|
17
|
+
|
|
18
|
+
type vtkTIFFReaderBase = vtkObject &
|
|
19
|
+
Omit<
|
|
20
|
+
vtkAlgorithm,
|
|
21
|
+
| 'getInputData'
|
|
22
|
+
| 'setInputData'
|
|
23
|
+
| 'setInputConnection'
|
|
24
|
+
| 'getInputConnection'
|
|
25
|
+
| 'addInputConnection'
|
|
26
|
+
| 'addInputData'
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
export interface vtkTIFFReader extends vtkTIFFReaderBase {
|
|
30
|
+
/**
|
|
31
|
+
* Get the base url.
|
|
32
|
+
*/
|
|
33
|
+
getBaseURL(): string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get if the image is flipped vertically.
|
|
37
|
+
*/
|
|
38
|
+
getFlipY(): boolean;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the dataAccess helper.
|
|
42
|
+
*/
|
|
43
|
+
getDataAccessHelper():
|
|
44
|
+
| HtmlDataAccessHelper
|
|
45
|
+
| HttpDataAccessHelper
|
|
46
|
+
| JSZipDataAccessHelper
|
|
47
|
+
| LiteHttpDataAccessHelper;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get the url of the object to load.
|
|
51
|
+
*/
|
|
52
|
+
getUrl(): string;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load the object data.
|
|
56
|
+
* @param {ITIFFReaderOptions} [options]
|
|
57
|
+
*/
|
|
58
|
+
loadData(options?: ITIFFReaderOptions): Promise<any>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Parse data.
|
|
62
|
+
* @param {ArrayBuffer} content The content to parse.
|
|
63
|
+
*/
|
|
64
|
+
parse(content: ArrayBuffer): void;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parse data as ArrayBuffer.
|
|
68
|
+
* @param {ArrayBuffer} content The content to parse.
|
|
69
|
+
*/
|
|
70
|
+
parseAsArrayBuffer(content: ArrayBuffer): void;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
*
|
|
74
|
+
* @param inData
|
|
75
|
+
* @param outData
|
|
76
|
+
*/
|
|
77
|
+
requestData(inData: any, outData: any): void;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Flip the image vertically.
|
|
81
|
+
* @param {String} flipY If true, flip the image vertically.
|
|
82
|
+
*/
|
|
83
|
+
setFlipY(flipY: boolean): boolean;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
*
|
|
87
|
+
* @param dataAccessHelper
|
|
88
|
+
*/
|
|
89
|
+
setDataAccessHelper(
|
|
90
|
+
dataAccessHelper:
|
|
91
|
+
| HtmlDataAccessHelper
|
|
92
|
+
| HttpDataAccessHelper
|
|
93
|
+
| JSZipDataAccessHelper
|
|
94
|
+
| LiteHttpDataAccessHelper
|
|
95
|
+
): boolean;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Set the url of the object to load.
|
|
99
|
+
* @param {String} url the url of the object to load.
|
|
100
|
+
* @param {ITIFFReaderOptions} [option] The PLY reader options.
|
|
101
|
+
*/
|
|
102
|
+
setUrl(url: string, option?: ITIFFReaderOptions): Promise<string | any>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Method used to decorate a given object (publicAPI+model) with vtkTIFFReader characteristics.
|
|
107
|
+
*
|
|
108
|
+
* @param publicAPI object on which methods will be bounds (public)
|
|
109
|
+
* @param model object on which data structure will be bounds (protected)
|
|
110
|
+
* @param {ITIFFReaderInitialValues} [initialValues] (default: {})
|
|
111
|
+
*/
|
|
112
|
+
export function extend(
|
|
113
|
+
publicAPI: object,
|
|
114
|
+
model: object,
|
|
115
|
+
initialValues?: ITIFFReaderInitialValues
|
|
116
|
+
): void;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Method used to create a new instance of vtkTIFFReader
|
|
120
|
+
* @param {ITIFFReaderInitialValues} [initialValues] for pre-setting some of its content
|
|
121
|
+
*/
|
|
122
|
+
export function newInstance(
|
|
123
|
+
initialValues?: ITIFFReaderInitialValues
|
|
124
|
+
): vtkTIFFReader;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* vtkTIFFReader is a source object that reads TIFF files.
|
|
128
|
+
*/
|
|
129
|
+
export declare const vtkTIFFReader: {
|
|
130
|
+
newInstance: typeof newInstance;
|
|
131
|
+
extend: typeof extend;
|
|
132
|
+
};
|
|
133
|
+
export default vtkTIFFReader;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { m as macro } from '../../macros2.js';
|
|
2
|
+
import '../Core/DataAccessHelper/LiteHttpDataAccessHelper.js';
|
|
3
|
+
import DataAccessHelper from '../Core/DataAccessHelper.js';
|
|
4
|
+
import vtkImageData from '../../Common/DataModel/ImageData.js';
|
|
5
|
+
import vtkDataArray from '../../Common/Core/DataArray.js';
|
|
6
|
+
import UTIF from 'utif';
|
|
7
|
+
|
|
8
|
+
// ----------------------------------------------------------------------------
|
|
9
|
+
// vtkTIFFReader methods
|
|
10
|
+
// ----------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
function vtkTIFFReader(publicAPI, model) {
|
|
13
|
+
// Set our className
|
|
14
|
+
model.classHierarchy.push('vtkTIFFReader');
|
|
15
|
+
|
|
16
|
+
// Create default dataAccessHelper if not available
|
|
17
|
+
if (!model.dataAccessHelper) {
|
|
18
|
+
model.dataAccessHelper = DataAccessHelper.get('http');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Internal method to fetch Array
|
|
22
|
+
function fetchData(url) {
|
|
23
|
+
const {
|
|
24
|
+
compression,
|
|
25
|
+
progressCallback
|
|
26
|
+
} = model;
|
|
27
|
+
return model.dataAccessHelper.fetchBinary(url, {
|
|
28
|
+
compression,
|
|
29
|
+
progressCallback
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Set DataSet url
|
|
34
|
+
publicAPI.setUrl = function (url) {
|
|
35
|
+
let option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
|
|
36
|
+
binary: true
|
|
37
|
+
};
|
|
38
|
+
model.url = url;
|
|
39
|
+
|
|
40
|
+
// Remove the file in the URL
|
|
41
|
+
const path = url.split('/');
|
|
42
|
+
path.pop();
|
|
43
|
+
model.baseURL = path.join('/');
|
|
44
|
+
model.compression = option.compression;
|
|
45
|
+
|
|
46
|
+
// Fetch metadata
|
|
47
|
+
return publicAPI.loadData({
|
|
48
|
+
progressCallback: option.progressCallback
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Fetch the actual data arrays
|
|
53
|
+
publicAPI.loadData = function () {
|
|
54
|
+
const promise = fetchData(model.url);
|
|
55
|
+
promise.then(publicAPI.parse);
|
|
56
|
+
return promise;
|
|
57
|
+
};
|
|
58
|
+
publicAPI.parse = content => {
|
|
59
|
+
publicAPI.parseAsArrayBuffer(content);
|
|
60
|
+
};
|
|
61
|
+
publicAPI.parseAsArrayBuffer = content => {
|
|
62
|
+
if (!content) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Read Header
|
|
67
|
+
const ifds = UTIF.decode(content);
|
|
68
|
+
UTIF.decodeImage(content, ifds[0]);
|
|
69
|
+
const data = UTIF.toRGBA8(ifds[0]);
|
|
70
|
+
const width = ifds[0].width;
|
|
71
|
+
const height = ifds[0].height;
|
|
72
|
+
const output = new Uint8Array(data.length);
|
|
73
|
+
if (model.flipY) {
|
|
74
|
+
for (let y = 0; y < height; y++) {
|
|
75
|
+
for (let x = 0; x < width; x++) {
|
|
76
|
+
const srcIndex = (y * width + x) * 4;
|
|
77
|
+
const destIndex = ((height - y - 1) * width + x) * 4;
|
|
78
|
+
output[destIndex] = data[srcIndex]; // R
|
|
79
|
+
output[destIndex + 1] = data[srcIndex + 1]; // G
|
|
80
|
+
output[destIndex + 2] = data[srcIndex + 2]; // B
|
|
81
|
+
output[destIndex + 3] = data[srcIndex + 3]; // A
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const dataExtent = [0, width - 1, 0, height - 1];
|
|
87
|
+
const dataSpacing = [1, 1, 1];
|
|
88
|
+
const imageData = vtkImageData.newInstance();
|
|
89
|
+
imageData.setDimensions(width, height, 1);
|
|
90
|
+
imageData.setExtent(dataExtent);
|
|
91
|
+
imageData.setSpacing(dataSpacing);
|
|
92
|
+
const dataArray = vtkDataArray.newInstance({
|
|
93
|
+
name: 'TIFFImage',
|
|
94
|
+
numberOfComponents: 4,
|
|
95
|
+
values: output
|
|
96
|
+
});
|
|
97
|
+
imageData.getPointData().setScalars(dataArray);
|
|
98
|
+
model.output[0] = imageData;
|
|
99
|
+
};
|
|
100
|
+
publicAPI.requestData = (inData, outData) => {
|
|
101
|
+
publicAPI.parse(model.parseData);
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ----------------------------------------------------------------------------
|
|
106
|
+
// Object factory
|
|
107
|
+
// ----------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
const DEFAULT_VALUES = {
|
|
110
|
+
flipY: true,
|
|
111
|
+
compression: null,
|
|
112
|
+
progressCallback: null
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// ----------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
function extend(publicAPI, model) {
|
|
118
|
+
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
119
|
+
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
120
|
+
|
|
121
|
+
// Make this a VTK object
|
|
122
|
+
macro.obj(publicAPI, model);
|
|
123
|
+
|
|
124
|
+
// Also make it an algorithm with one input and one output
|
|
125
|
+
macro.algo(publicAPI, model, 0, 1);
|
|
126
|
+
macro.get(publicAPI, model, ['url', 'baseURL']);
|
|
127
|
+
macro.setGet(publicAPI, model, ['dataAccessHelper', 'flipY']);
|
|
128
|
+
|
|
129
|
+
// Object specific methods
|
|
130
|
+
vtkTIFFReader(publicAPI, model);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ----------------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
const newInstance = macro.newInstance(extend, 'vtkTIFFReader');
|
|
136
|
+
|
|
137
|
+
// ----------------------------------------------------------------------------
|
|
138
|
+
|
|
139
|
+
var vtkTIFFReader$1 = {
|
|
140
|
+
newInstance,
|
|
141
|
+
extend
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export { vtkTIFFReader$1 as default, extend, newInstance };
|
package/IO/Image.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import vtkHDRReader from './Image/HDRReader.js';
|
|
2
2
|
import vtkTGAReader from './Image/TGAReader.js';
|
|
3
|
+
import vtkTIFFReader from './Image/TIFFReader.js';
|
|
3
4
|
|
|
4
5
|
var index = {
|
|
5
6
|
vtkHDRReader,
|
|
6
|
-
vtkTGAReader
|
|
7
|
+
vtkTGAReader,
|
|
8
|
+
vtkTIFFReader
|
|
7
9
|
};
|
|
8
10
|
|
|
9
11
|
export { index as default };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { m as macro } from '../../../macros2.js';
|
|
2
2
|
import { k as add } from '../../../Common/Core/Math/index.js';
|
|
3
|
+
import vtkBoundingBox from '../../../Common/DataModel/BoundingBox.js';
|
|
3
4
|
import vtkPointPicker from '../../../Rendering/Core/PointPicker.js';
|
|
4
5
|
|
|
5
6
|
const MAX_POINTS = 3;
|
|
@@ -8,6 +9,7 @@ function widgetBehavior(publicAPI, model) {
|
|
|
8
9
|
model._isDragging = false;
|
|
9
10
|
const picker = vtkPointPicker.newInstance();
|
|
10
11
|
picker.setPickFromList(1);
|
|
12
|
+
publicAPI.getBounds = () => model.widgetState.getHandleList().reduce((bounds, handle) => vtkBoundingBox.inflate(vtkBoundingBox.addPoint(bounds, ...handle.getOrigin()), publicAPI.getScaleInPixels() ? 0 : handle.getScale1() / 2), [...vtkBoundingBox.INIT_BOUNDS]);
|
|
11
13
|
|
|
12
14
|
// --------------------------------------------------------------------------
|
|
13
15
|
// Display 2D
|
|
@@ -342,6 +342,23 @@ function widgetBehavior(publicAPI, model) {
|
|
|
342
342
|
};
|
|
343
343
|
};
|
|
344
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Rotate a line by a specified angle
|
|
347
|
+
* @param {string} lineName The line name to rotate (e.g. YinX, ZinX, XinY, ZinY, XinZ, YinZ)
|
|
348
|
+
* @param {Number} radianAngle Applied angle in radian
|
|
349
|
+
*/
|
|
350
|
+
publicAPI.setViewPlane = (viewType, normal, viewUp) => {
|
|
351
|
+
let newViewUp = viewUp;
|
|
352
|
+
if (newViewUp == null) {
|
|
353
|
+
newViewUp = model.widgetState.getPlanes()[viewType].viewUp;
|
|
354
|
+
}
|
|
355
|
+
model.widgetState.getPlanes()[viewType] = {
|
|
356
|
+
normal,
|
|
357
|
+
viewUp: newViewUp
|
|
358
|
+
};
|
|
359
|
+
updateState(model.widgetState, model._factory.getScaleInPixels(), model._factory.getRotationHandlePosition());
|
|
360
|
+
};
|
|
361
|
+
|
|
345
362
|
// --------------------------------------------------------------------------
|
|
346
363
|
// initialization
|
|
347
364
|
// --------------------------------------------------------------------------
|
|
@@ -113,6 +113,7 @@ function rotateVector(vectorToBeRotated, axis, angle) {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/**
|
|
116
|
+
* Return ['X'] if there are only 1 plane defined in the widget state.
|
|
116
117
|
* Return ['X', 'Y'] if there are only 2 planes defined in the widget state.
|
|
117
118
|
* Return ['X', 'Y', 'Z'] if there are 3 planes defined in the widget state.
|
|
118
119
|
* @param {object} widgetState the state of the widget
|
|
@@ -290,6 +290,9 @@ function widgetBehavior(publicAPI, model) {
|
|
|
290
290
|
const up = model._camera.getViewUp();
|
|
291
291
|
const right = [];
|
|
292
292
|
vec3.cross(right, up, normal);
|
|
293
|
+
vtkMath.normalize(right);
|
|
294
|
+
vec3.cross(up, normal, right);
|
|
295
|
+
vtkMath.normalize(up);
|
|
293
296
|
model.shapeHandle.setUp(up);
|
|
294
297
|
model.shapeHandle.setRight(right);
|
|
295
298
|
model.shapeHandle.setDirection(normal);
|
package/index.d.ts
CHANGED
|
@@ -93,12 +93,14 @@
|
|
|
93
93
|
/// <reference path="./IO/Core/WSLinkClient.d.ts" />
|
|
94
94
|
/// <reference path="./IO/Geometry/DracoReader.d.ts" />
|
|
95
95
|
/// <reference path="./IO/Geometry/GLTFImporter.d.ts" />
|
|
96
|
+
/// <reference path="./IO/Geometry/IFCImporter.d.ts" />
|
|
96
97
|
/// <reference path="./IO/Geometry/PLYReader.d.ts" />
|
|
97
98
|
/// <reference path="./IO/Geometry/PLYWriter.d.ts" />
|
|
98
99
|
/// <reference path="./IO/Geometry/STLReader.d.ts" />
|
|
99
100
|
/// <reference path="./IO/Geometry/STLWriter.d.ts" />
|
|
100
101
|
/// <reference path="./IO/Image/HDRReader.d.ts" />
|
|
101
102
|
/// <reference path="./IO/Image/TGAReader.d.ts" />
|
|
103
|
+
/// <reference path="./IO/Image/TIFFReader.d.ts" />
|
|
102
104
|
/// <reference path="./IO/Misc/ElevationReader.d.ts" />
|
|
103
105
|
/// <reference path="./IO/Misc/GCodeReader.d.ts" />
|
|
104
106
|
/// <reference path="./IO/Misc/ITKImageReader.d.ts" />
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kitware/vtk.js",
|
|
3
|
-
"version": "32.
|
|
3
|
+
"version": "32.8.0",
|
|
4
4
|
"description": "Visualization Toolkit for the Web",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"3d",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"shelljs": "0.8.5",
|
|
44
44
|
"spark-md5": "3.0.2",
|
|
45
45
|
"stream-browserify": "3.0.0",
|
|
46
|
+
"utif": "3.1.0",
|
|
46
47
|
"webworker-promise": "0.5.0",
|
|
47
48
|
"worker-loader": "3.0.8",
|
|
48
49
|
"xmlbuilder2": "3.0.2"
|