@kitware/vtk.js 28.3.2 → 28.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/Common/Core/DataArray.js +8 -1
- package/Proxy/Core/View2DProxy.js +2 -1
- package/Proxy/Representations/ResliceRepresentationProxy.d.ts +30 -0
- package/Proxy/Representations/ResliceRepresentationProxy.js +157 -0
- package/Rendering/Core/ImageResliceMapper.d.ts +6 -6
- package/Rendering/OpenGL/ImageMapper.js +11 -2
- package/Rendering/OpenGL/ImageResliceMapper.js +86 -30
- package/Widgets/Widgets3D/ResliceCursorWidget.d.ts +103 -0
- package/index.d.ts +2 -0
- package/package.json +1 -1
package/Common/Core/DataArray.js
CHANGED
|
@@ -264,7 +264,14 @@ function vtkDataArray(publicAPI, model) {
|
|
|
264
264
|
|
|
265
265
|
publicAPI.getRange = function () {
|
|
266
266
|
var componentIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : -1;
|
|
267
|
-
var rangeIdx = componentIndex
|
|
267
|
+
var rangeIdx = componentIndex;
|
|
268
|
+
|
|
269
|
+
if (rangeIdx < 0) {
|
|
270
|
+
// If scalar data, then store in slot 0 (same as componentIndex = 0).
|
|
271
|
+
// If vector data, then store in last slot.
|
|
272
|
+
rangeIdx = model.numberOfComponents === 1 ? 0 : model.numberOfComponents;
|
|
273
|
+
}
|
|
274
|
+
|
|
268
275
|
var range = null;
|
|
269
276
|
|
|
270
277
|
if (!model.ranges) {
|
|
@@ -147,8 +147,9 @@ function vtkView2DProxy(publicAPI, model) {
|
|
|
147
147
|
|
|
148
148
|
if (rep.setSlicingMode) {
|
|
149
149
|
rep.setSlicingMode('XYZ'[model.axis]);
|
|
150
|
-
publicAPI.bindRepresentationToManipulator(rep);
|
|
151
150
|
}
|
|
151
|
+
|
|
152
|
+
publicAPI.bindRepresentationToManipulator(rep);
|
|
152
153
|
};
|
|
153
154
|
|
|
154
155
|
var superRemoveRepresentation = publicAPI.removeRepresentation;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type vtkPolyData from './../../Common/DataModel/PolyData';
|
|
2
|
+
import type vtkPlane from './../../Common/DataModel/Plane';
|
|
3
|
+
import vtkAbstractRepresentationProxy from './../Core/AbstractRepresentationProxy';
|
|
4
|
+
|
|
5
|
+
export interface vtkResliceRepresentationProxy
|
|
6
|
+
extends vtkAbstractRepresentationProxy {
|
|
7
|
+
|
|
8
|
+
// proxy property mappings
|
|
9
|
+
|
|
10
|
+
setVisibility(visible: boolean): boolean;
|
|
11
|
+
getVisibility(): boolean;
|
|
12
|
+
setWindowWidth(width: number): boolean;
|
|
13
|
+
getWindowWidth(): number;
|
|
14
|
+
setWindowLevel(level: number): boolean;
|
|
15
|
+
getWindowLevel(): number;
|
|
16
|
+
setInterpolationType(type: number): boolean;
|
|
17
|
+
getInterpolationType(): number;
|
|
18
|
+
setSlabType(type: number): boolean;
|
|
19
|
+
getSlabtype(): number;
|
|
20
|
+
setSlicePlane(plane: vtkPlane): boolean;
|
|
21
|
+
getSlicePlane(): vtkPlane;
|
|
22
|
+
setSlicePolyData(polydata: vtkPolyData): boolean;
|
|
23
|
+
getSlicePolyData(): vtkPolyData;
|
|
24
|
+
setSlabThickness(thickness: number): boolean;
|
|
25
|
+
getSlabThickness(): number;
|
|
26
|
+
setSlabTrapezoidIntegration(slabTrapezoidIntegration: number): boolean;
|
|
27
|
+
getSlabTrapezoidIntegration(): number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default vtkResliceRepresentationProxy;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import macro from '../../macros.js';
|
|
2
|
+
import vtkImageSlice from '../../Rendering/Core/ImageSlice.js';
|
|
3
|
+
import vtkImageResliceMapper from '../../Rendering/Core/ImageResliceMapper.js';
|
|
4
|
+
import { SlabTypes } from '../../Rendering/Core/ImageResliceMapper/Constants.js';
|
|
5
|
+
import vtkPlane from '../../Common/DataModel/Plane.js';
|
|
6
|
+
import vtkAbstractRepresentationProxy from '../Core/AbstractRepresentationProxy.js';
|
|
7
|
+
|
|
8
|
+
function sum(a, b) {
|
|
9
|
+
return a + b;
|
|
10
|
+
} // ----------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
function mean() {
|
|
14
|
+
for (var _len = arguments.length, array = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
15
|
+
array[_key] = arguments[_key];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return array.reduce(sum, 0) / array.length;
|
|
19
|
+
} // ----------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
function updateDomains(dataset, dataArray, model, updateProp) {
|
|
23
|
+
var dataRange = dataArray.getRange();
|
|
24
|
+
var propToUpdate = {
|
|
25
|
+
windowWidth: {
|
|
26
|
+
domain: {
|
|
27
|
+
min: 0,
|
|
28
|
+
max: dataRange[1] - dataRange[0],
|
|
29
|
+
step: 'any'
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
windowLevel: {
|
|
33
|
+
domain: {
|
|
34
|
+
min: dataRange[0],
|
|
35
|
+
max: dataRange[1],
|
|
36
|
+
step: 'any'
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
updateProp('windowWidth', propToUpdate.windowWidth);
|
|
41
|
+
updateProp('windowLevel', propToUpdate.windowLevel);
|
|
42
|
+
return {
|
|
43
|
+
windowWidth: propToUpdate.windowWidth.domain.max,
|
|
44
|
+
windowLevel: Math.floor(mean(propToUpdate.windowLevel.domain.min, propToUpdate.windowLevel.domain.max))
|
|
45
|
+
};
|
|
46
|
+
} // ----------------------------------------------------------------------------
|
|
47
|
+
// vtkResliceRepresentationProxy methods
|
|
48
|
+
// ----------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
function vtkResliceRepresentationProxy(publicAPI, model) {
|
|
52
|
+
// Set our className
|
|
53
|
+
model.classHierarchy.push('vtkResliceRepresentationProxy');
|
|
54
|
+
model.mapper = vtkImageResliceMapper.newInstance();
|
|
55
|
+
model.actor = vtkImageSlice.newInstance();
|
|
56
|
+
model.property = model.actor.getProperty(); // set slicing plane
|
|
57
|
+
|
|
58
|
+
model.slicePlane = vtkPlane.newInstance();
|
|
59
|
+
model.slicePlane.setNormal(0, 1, 0);
|
|
60
|
+
model.mapper.setSlicePlane(model.slicePlane);
|
|
61
|
+
model.mapper.setSlabType(SlabTypes.MAX); // connect rendering pipeline
|
|
62
|
+
|
|
63
|
+
model.actor.setMapper(model.mapper);
|
|
64
|
+
model.actors.push(model.actor);
|
|
65
|
+
|
|
66
|
+
function setInputData(inputDataset) {
|
|
67
|
+
var state = updateDomains(inputDataset, publicAPI.getDataArray(), model, publicAPI.updateProxyProperty);
|
|
68
|
+
publicAPI.set(state);
|
|
69
|
+
model.slicePlane.setOrigin(inputDataset.getCenter());
|
|
70
|
+
} // Keep things updated
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
model.sourceDependencies.push(model.mapper);
|
|
74
|
+
model.sourceDependencies.push({
|
|
75
|
+
setInputData: setInputData
|
|
76
|
+
}); // API ----------------------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
var parentSetColorBy = publicAPI.setColorBy;
|
|
79
|
+
|
|
80
|
+
publicAPI.setColorBy = function (arrayName, arrayLocation) {
|
|
81
|
+
var componentIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : -1;
|
|
82
|
+
|
|
83
|
+
if (arrayName === null) {
|
|
84
|
+
model.property.setRGBTransferFunction(null);
|
|
85
|
+
model.property.setPiecewiseFunction(null);
|
|
86
|
+
} else {
|
|
87
|
+
parentSetColorBy(arrayName, arrayLocation, componentIndex);
|
|
88
|
+
var lutProxy = publicAPI.getLookupTableProxy(arrayName);
|
|
89
|
+
var pwfProxy = publicAPI.getPiecewiseFunctionProxy(arrayName);
|
|
90
|
+
model.property.setRGBTransferFunction(lutProxy.getLookupTable());
|
|
91
|
+
model.property.setPiecewiseFunction(pwfProxy.getPiecewiseFunction());
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
} // ----------------------------------------------------------------------------
|
|
95
|
+
// Object factory
|
|
96
|
+
// ----------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
var DEFAULT_VALUES = {}; // ----------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
function extend(publicAPI, model) {
|
|
102
|
+
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
103
|
+
Object.assign(model, DEFAULT_VALUES, initialValues); // Object methods
|
|
104
|
+
|
|
105
|
+
vtkAbstractRepresentationProxy.extend(publicAPI, model, initialValues);
|
|
106
|
+
macro.get(publicAPI, model, ['slicePlane']); // Object specific methods
|
|
107
|
+
|
|
108
|
+
vtkResliceRepresentationProxy(publicAPI, model); // Proxyfy
|
|
109
|
+
|
|
110
|
+
macro.proxyPropertyMapping(publicAPI, model, {
|
|
111
|
+
visibility: {
|
|
112
|
+
modelKey: 'actor',
|
|
113
|
+
property: 'visibility'
|
|
114
|
+
},
|
|
115
|
+
windowWidth: {
|
|
116
|
+
modelKey: 'property',
|
|
117
|
+
property: 'colorWindow'
|
|
118
|
+
},
|
|
119
|
+
windowLevel: {
|
|
120
|
+
modelKey: 'property',
|
|
121
|
+
property: 'colorLevel'
|
|
122
|
+
},
|
|
123
|
+
interpolationType: {
|
|
124
|
+
modelKey: 'property',
|
|
125
|
+
property: 'interpolationType'
|
|
126
|
+
},
|
|
127
|
+
slicePlane: {
|
|
128
|
+
modelKey: 'mapper',
|
|
129
|
+
property: 'slicePlane'
|
|
130
|
+
},
|
|
131
|
+
slicePolyData: {
|
|
132
|
+
modelKey: 'mapper',
|
|
133
|
+
property: 'slicePolyData'
|
|
134
|
+
},
|
|
135
|
+
slabType: {
|
|
136
|
+
modelKey: 'mapper',
|
|
137
|
+
property: 'slabType'
|
|
138
|
+
},
|
|
139
|
+
slabThickness: {
|
|
140
|
+
modelKey: 'mapper',
|
|
141
|
+
property: 'slabThickness'
|
|
142
|
+
},
|
|
143
|
+
slabTrapezoidIntegration: {
|
|
144
|
+
modelKey: 'mapper',
|
|
145
|
+
property: 'slabTrapezoidIntegration'
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
} // ----------------------------------------------------------------------------
|
|
149
|
+
|
|
150
|
+
var newInstance = macro.newInstance(extend, 'vtkResliceRepresentationProxy'); // ----------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
var index = {
|
|
153
|
+
newInstance: newInstance,
|
|
154
|
+
extend: extend
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export { index as default, extend, newInstance };
|
|
@@ -78,7 +78,7 @@ export interface vtkImageResliceMapper extends vtkAbstractImageMapper {
|
|
|
78
78
|
*
|
|
79
79
|
* Get the slab composite function.
|
|
80
80
|
*/
|
|
81
|
-
getSlabType():
|
|
81
|
+
getSlabType(): SlabTypes;
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
84
|
*
|
|
@@ -165,9 +165,9 @@ export interface vtkImageResliceMapper extends vtkAbstractImageMapper {
|
|
|
165
165
|
/**
|
|
166
166
|
*
|
|
167
167
|
* Enable slab slicing mode and set the slab thickness in world space (mm).
|
|
168
|
-
* @param {
|
|
168
|
+
* @param {Number} slabThickness The slab thickness in world space (mm). Default: 0.
|
|
169
169
|
*/
|
|
170
|
-
setSlabThickness(slabThickness: number):
|
|
170
|
+
setSlabThickness(slabThickness: number): boolean;
|
|
171
171
|
|
|
172
172
|
/**
|
|
173
173
|
*
|
|
@@ -178,7 +178,7 @@ export interface vtkImageResliceMapper extends vtkAbstractImageMapper {
|
|
|
178
178
|
* @param {Number} slabTrapezoidIntegration Enable/disable trapezoid integration for slab slicing.
|
|
179
179
|
* Default: 0
|
|
180
180
|
*/
|
|
181
|
-
setSlabTrapezoidIntegration(slabTrapezoidIntegration: number):
|
|
181
|
+
setSlabTrapezoidIntegration(slabTrapezoidIntegration: number): boolean;
|
|
182
182
|
|
|
183
183
|
/**
|
|
184
184
|
*
|
|
@@ -201,7 +201,7 @@ export interface vtkImageResliceMapper extends vtkAbstractImageMapper {
|
|
|
201
201
|
* bounds.
|
|
202
202
|
* @param {vtkPlane} slicePlane The implicit plane to slice the volume with. Default: null
|
|
203
203
|
*/
|
|
204
|
-
setSlicePlane(slicePlane: vtkPlane):
|
|
204
|
+
setSlicePlane(slicePlane: vtkPlane): boolean;
|
|
205
205
|
|
|
206
206
|
/**
|
|
207
207
|
*
|
|
@@ -214,7 +214,7 @@ export interface vtkImageResliceMapper extends vtkAbstractImageMapper {
|
|
|
214
214
|
* bounds.
|
|
215
215
|
* @param {vtkPolyData} slicePolyData The polydata to slice the volume with. Default: null
|
|
216
216
|
*/
|
|
217
|
-
setSlicePolyData(slicePolyData: vtkPolyData):
|
|
217
|
+
setSlicePolyData(slicePolyData: vtkPolyData): boolean;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
/**
|
|
@@ -743,7 +743,11 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
743
743
|
for (var j = 0; j < dims[1]; j++) {
|
|
744
744
|
var bsIdx = (sliceOffset + j * dims[0] + k * dims[0] * dims[1]) * numComp;
|
|
745
745
|
id = (k * dims[1] + j) * numComp;
|
|
746
|
-
|
|
746
|
+
var end = bsIdx + numComp;
|
|
747
|
+
|
|
748
|
+
while (bsIdx < end) {
|
|
749
|
+
scalars[id++] = basicScalars[bsIdx++];
|
|
750
|
+
}
|
|
747
751
|
}
|
|
748
752
|
}
|
|
749
753
|
|
|
@@ -770,7 +774,12 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
770
774
|
var _bsIdx = (_i9 + sliceOffset * dims[0] + _k * dims[0] * dims[1]) * numComp;
|
|
771
775
|
|
|
772
776
|
_id = (_k * dims[0] + _i9) * numComp;
|
|
773
|
-
|
|
777
|
+
|
|
778
|
+
var _end = _bsIdx + numComp;
|
|
779
|
+
|
|
780
|
+
while (_bsIdx < _end) {
|
|
781
|
+
scalars[_id++] = basicScalars[_bsIdx++];
|
|
782
|
+
}
|
|
774
783
|
}
|
|
775
784
|
}
|
|
776
785
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
|
|
2
|
+
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
|
|
2
3
|
import { newInstance as newInstance$1, obj, get, vtkErrorMacro as vtkErrorMacro$1 } from '../../macros.js';
|
|
3
|
-
import { mat4, vec3 } from 'gl-matrix';
|
|
4
|
+
import { mat4, mat3, vec3 } from 'gl-matrix';
|
|
4
5
|
import vtkClosedPolyLineToSurfaceFilter from '../../Filters/General/ClosedPolyLineToSurfaceFilter.js';
|
|
5
6
|
import vtkCubeSource from '../../Filters/Sources/CubeSource.js';
|
|
6
7
|
import vtkCutter from '../../Filters/Core/Cutter.js';
|
|
@@ -440,12 +441,9 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
440
441
|
|
|
441
442
|
if (program.isUniformUsed('WCTCMatrix')) {
|
|
442
443
|
var image = model.currentInput;
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
var o = [bounds[0], bounds[2], bounds[4]];
|
|
447
|
-
var q = [0, 0, 0, 1];
|
|
448
|
-
mat4.fromRotationTranslationScale(model.tmpMat4, q, o, sc);
|
|
444
|
+
var dim = image.getDimensions();
|
|
445
|
+
mat4.copy(model.tmpMat4, image.getIndexToWorld());
|
|
446
|
+
mat4.scale(model.tmpMat4, model.tmpMat4, dim);
|
|
449
447
|
mat4.invert(model.tmpMat4, model.tmpMat4);
|
|
450
448
|
|
|
451
449
|
if (inverseShiftScaleMatrix) {
|
|
@@ -455,6 +453,10 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
455
453
|
program.setUniformMatrix('WCTCMatrix', model.tmpMat4);
|
|
456
454
|
}
|
|
457
455
|
|
|
456
|
+
if (program.isUniformUsed('vboScaling')) {
|
|
457
|
+
program.setUniform3fv('vboScaling', cellBO.getCABO().getCoordScale());
|
|
458
|
+
}
|
|
459
|
+
|
|
458
460
|
cellBO.getAttributeUpdateTime().modified();
|
|
459
461
|
} // Depth request
|
|
460
462
|
|
|
@@ -672,7 +674,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
672
674
|
}
|
|
673
675
|
|
|
674
676
|
if (slabThickness > 0.0) {
|
|
675
|
-
tcoordFSDec = tcoordFSDec.concat(['uniform vec3 spacing;', 'uniform float slabThickness;', 'uniform int slabType;', 'uniform int slabTrapezoid;']);
|
|
677
|
+
tcoordFSDec = tcoordFSDec.concat(['uniform vec3 spacing;', 'uniform float slabThickness;', 'uniform int slabType;', 'uniform int slabTrapezoid;', 'uniform vec3 vboScaling;']);
|
|
676
678
|
tcoordFSDec = tcoordFSDec.concat(['vec4 compositeValue(vec4 currVal, vec4 valToComp, int trapezoid)', '{', ' vec4 retVal = vec4(1.0);', ' if (slabType == 0) // min', ' {', ' retVal = min(currVal, valToComp);', ' }', ' else if (slabType == 1) // max', ' {', ' retVal = max(currVal, valToComp);', ' }', ' else if (slabType == 3) // sum', ' {', ' retVal = currVal + (trapezoid > 0 ? 0.5 * valToComp : valToComp); ', ' }', ' else // mean', ' {', ' retVal = currVal + (trapezoid > 0 ? 0.5 * valToComp : valToComp); ', ' }', ' return retVal;', '}']);
|
|
677
679
|
}
|
|
678
680
|
|
|
@@ -680,7 +682,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
680
682
|
var tcoordFSImpl = ['if (any(greaterThan(fragTexCoord, vec3(1.0))) || any(lessThan(fragTexCoord, vec3(0.0))))', '{', ' // set the background color and exit', ' gl_FragData[0] = backgroundColor;', ' return;', '}', 'vec4 tvalue = texture(texture1, fragTexCoord);'];
|
|
681
683
|
|
|
682
684
|
if (slabThickness > 0.0) {
|
|
683
|
-
tcoordFSImpl = tcoordFSImpl.concat(['// Get the first and last samples', 'int numSlices = 1;', '
|
|
685
|
+
tcoordFSImpl = tcoordFSImpl.concat(['// Get the first and last samples', 'int numSlices = 1;', 'float scaling = min(min(spacing.x, spacing.y), spacing.z) * 0.5;', 'vec3 normalxspacing = scaling * normalWCVSOutput;', 'float distTraveled = length(normalxspacing);', 'int trapezoid = 0;', 'while (distTraveled < slabThickness * 0.5)', '{', ' distTraveled += length(normalxspacing);', ' float fnumSlices = float(numSlices);', ' if (distTraveled > slabThickness * 0.5)', ' {', ' // Before stepping outside the slab, sample at the boundaries', ' normalxspacing = normalWCVSOutput * slabThickness * 0.5 / fnumSlices;', ' trapezoid = slabTrapezoid;', ' }', ' vec3 fragTCoordNeg = (WCTCMatrix * vec4(vertexWCVSOutput.xyz - fnumSlices * normalxspacing * vboScaling, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal = texture(texture1, fragTCoordNeg);', ' tvalue = compositeValue(tvalue, newVal, trapezoid);', ' numSlices += 1;', ' }', ' vec3 fragTCoordPos = (WCTCMatrix * vec4(vertexWCVSOutput.xyz + fnumSlices * normalxspacing * vboScaling, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal = texture(texture1, fragTCoordPos);', ' tvalue = compositeValue(tvalue, newVal, trapezoid);', ' numSlices += 1;', ' }', '}', '// Finally, if slab type is *mean*, divide the sum by the numSlices', 'if (slabType == 2)', '{', ' tvalue = tvalue / float(numSlices);', '}']);
|
|
684
686
|
}
|
|
685
687
|
|
|
686
688
|
if (iComps) {
|
|
@@ -787,6 +789,49 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
787
789
|
return [false, 2];
|
|
788
790
|
}
|
|
789
791
|
|
|
792
|
+
function transformPoints(points, transform) {
|
|
793
|
+
var tmp = [0, 0, 0];
|
|
794
|
+
|
|
795
|
+
for (var i = 0; i < points.length; i += 3) {
|
|
796
|
+
var p = points.subarray(i, i + 3);
|
|
797
|
+
|
|
798
|
+
if (transform.length === 9) {
|
|
799
|
+
vec3.transformMat3(tmp, p, transform);
|
|
800
|
+
} else {
|
|
801
|
+
vec3.transformMat4(tmp, p, transform);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
p[0] = tmp[0];
|
|
805
|
+
p[1] = tmp[1];
|
|
806
|
+
p[2] = tmp[2];
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
function imageToCubePolyData(image, outPD) {
|
|
811
|
+
// First create a cube polydata in the index-space of the image.
|
|
812
|
+
var sext = image === null || image === void 0 ? void 0 : image.getSpatialExtent();
|
|
813
|
+
|
|
814
|
+
if (sext) {
|
|
815
|
+
model.cubeSource.setXLength(sext[1] - sext[0]);
|
|
816
|
+
model.cubeSource.setYLength(sext[3] - sext[2]);
|
|
817
|
+
model.cubeSource.setZLength(sext[5] - sext[4]);
|
|
818
|
+
} else {
|
|
819
|
+
model.cubeSource.setXLength(1);
|
|
820
|
+
model.cubeSource.setYLength(1);
|
|
821
|
+
model.cubeSource.setZLength(1);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
model.cubeSource.setCenter(model.cubeSource.getXLength() / 2.0, model.cubeSource.getYLength() / 2.0, model.cubeSource.getZLength() / 2.0);
|
|
825
|
+
model.cubeSource.update();
|
|
826
|
+
var out = model.cubeSource.getOutputData();
|
|
827
|
+
outPD.getPoints().setData(Float32Array.from(out.getPoints().getData()), 3);
|
|
828
|
+
outPD.getPolys().setData(Uint32Array.from(out.getPolys().getData()), 1); // Now, transform the cube polydata points in-place
|
|
829
|
+
// using the image's indexToWorld transformation.
|
|
830
|
+
|
|
831
|
+
var points = outPD.getPoints().getData();
|
|
832
|
+
transformPoints(points, image.getIndexToWorld());
|
|
833
|
+
}
|
|
834
|
+
|
|
790
835
|
publicAPI.updateResliceGeometry = function () {
|
|
791
836
|
var resGeomString = '';
|
|
792
837
|
var image = model.currentInput;
|
|
@@ -805,9 +850,19 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
805
850
|
if (image) {
|
|
806
851
|
resGeomString = resGeomString.concat("Image".concat(image.getMTime()));
|
|
807
852
|
} // Check to see if we can bypass oblique slicing related bounds computation
|
|
853
|
+
// Compute a world-to-image-orientation matrix.
|
|
854
|
+
// Ignore the translation component since we are
|
|
855
|
+
// using it on vectors rather than positions.
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
var w2io = mat3.fromValues(image === null || image === void 0 ? void 0 : image.getDirection());
|
|
859
|
+
mat3.invert(w2io, w2io); // transform the cutting plane normal to image local coords
|
|
808
860
|
|
|
861
|
+
var imageLocalNormal = _toConsumableArray(slicePlane.getNormal());
|
|
809
862
|
|
|
810
|
-
|
|
863
|
+
vec3.transformMat3(imageLocalNormal, imageLocalNormal, w2io);
|
|
864
|
+
|
|
865
|
+
var _isVectorAxisAligned = isVectorAxisAligned(imageLocalNormal);
|
|
811
866
|
|
|
812
867
|
var _isVectorAxisAligned2 = _slicedToArray(_isVectorAxisAligned, 2);
|
|
813
868
|
|
|
@@ -844,26 +899,18 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
844
899
|
model.resliceGeom.getPolys().setData(slicePD.getPolys().getData(), 1);
|
|
845
900
|
model.resliceGeom.getPointData().setNormals(slicePD.getPointData().getNormals());
|
|
846
901
|
} else if (slicePlane) {
|
|
847
|
-
var bounds = image ? imageBounds : [0, 1, 0, 1, 0, 1];
|
|
848
|
-
|
|
849
902
|
if (!orthoSlicing) {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
var cutter = vtkCutter.newInstance();
|
|
856
|
-
cutter.setInputConnection(cube.getOutputPort());
|
|
857
|
-
cutter.setCutFunction(slicePlane);
|
|
858
|
-
var pds = vtkClosedPolyLineToSurfaceFilter.newInstance();
|
|
859
|
-
pds.setInputConnection(cutter.getOutputPort());
|
|
860
|
-
pds.update();
|
|
903
|
+
imageToCubePolyData(image, model.cubePolyData);
|
|
904
|
+
model.cutter.setInputData(model.cubePolyData);
|
|
905
|
+
model.cutter.setCutFunction(slicePlane);
|
|
906
|
+
model.lineToSurfaceFilter.setInputConnection(model.cutter.getOutputPort());
|
|
907
|
+
model.lineToSurfaceFilter.update();
|
|
861
908
|
|
|
862
909
|
if (!model.resliceGeom) {
|
|
863
910
|
model.resliceGeom = vtkPolyData.newInstance();
|
|
864
911
|
}
|
|
865
912
|
|
|
866
|
-
var planePD =
|
|
913
|
+
var planePD = model.lineToSurfaceFilter.getOutputData();
|
|
867
914
|
model.resliceGeom.getPoints().setData(planePD.getPoints().getData(), 3);
|
|
868
915
|
model.resliceGeom.getPolys().setData(planePD.getPolys().getData(), 1);
|
|
869
916
|
model.resliceGeom.getPointData().setNormals(planePD.getPointData().getNormals()); // The above method does not generate point normals
|
|
@@ -887,20 +934,25 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
887
934
|
});
|
|
888
935
|
model.resliceGeom.getPointData().setNormals(normals);
|
|
889
936
|
} else {
|
|
937
|
+
// Since the image-local normal is axis-aligned, we
|
|
938
|
+
// can quickly construct the cutting plane using indexToWorld transforms.
|
|
890
939
|
var ptsArray = new Float32Array(12);
|
|
891
|
-
var
|
|
940
|
+
var indexSpacePlaneOrigin = image.worldToIndex(slicePlane.getOrigin(), [0, 0, 0]);
|
|
892
941
|
var otherAxes = [(orthoAxis + 1) % 3, (orthoAxis + 2) % 3].sort();
|
|
942
|
+
var dim = image.getDimensions();
|
|
943
|
+
var ext = [0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1];
|
|
893
944
|
var ptIdx = 0;
|
|
894
945
|
|
|
895
946
|
for (var _i7 = 0; _i7 < 2; ++_i7) {
|
|
896
947
|
for (var j = 0; j < 2; ++j) {
|
|
897
|
-
ptsArray[ptIdx + orthoAxis] =
|
|
898
|
-
ptsArray[ptIdx + otherAxes[0]] =
|
|
899
|
-
ptsArray[ptIdx + otherAxes[1]] =
|
|
948
|
+
ptsArray[ptIdx + orthoAxis] = indexSpacePlaneOrigin[orthoAxis];
|
|
949
|
+
ptsArray[ptIdx + otherAxes[0]] = ext[2 * otherAxes[0] + j];
|
|
950
|
+
ptsArray[ptIdx + otherAxes[1]] = ext[2 * otherAxes[1] + _i7];
|
|
900
951
|
ptIdx += 3;
|
|
901
952
|
}
|
|
902
953
|
}
|
|
903
954
|
|
|
955
|
+
transformPoints(ptsArray, image.getIndexToWorld());
|
|
904
956
|
var cellArray = new Uint16Array(8);
|
|
905
957
|
cellArray[0] = 3;
|
|
906
958
|
cellArray[1] = 0;
|
|
@@ -992,9 +1044,13 @@ function extend(publicAPI, model) {
|
|
|
992
1044
|
model.colorTexture = vtkOpenGLTexture.newInstance();
|
|
993
1045
|
model.pwfTexture = vtkOpenGLTexture.newInstance();
|
|
994
1046
|
model.VBOBuildTime = {};
|
|
995
|
-
obj(model.VBOBuildTime);
|
|
1047
|
+
obj(model.VBOBuildTime);
|
|
1048
|
+
model.tmpMat4 = mat4.identity(new Float64Array(16)); // Implicit plane to polydata related cache:
|
|
996
1049
|
|
|
997
|
-
model.
|
|
1050
|
+
model.cubeSource = vtkCubeSource.newInstance();
|
|
1051
|
+
model.cubePolyData = vtkPolyData.newInstance();
|
|
1052
|
+
model.cutter = vtkCutter.newInstance();
|
|
1053
|
+
model.lineToSurfaceFilter = vtkClosedPolyLineToSurfaceFilter.newInstance();
|
|
998
1054
|
get(publicAPI, model, ['openGLTexture']); // Object methods
|
|
999
1055
|
|
|
1000
1056
|
vtkOpenGLImageResliceMapper(publicAPI, model);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { mat4 } from 'gl-matrix';
|
|
2
|
+
import vtkAbstractWidgetFactory from './../Core/AbstractWidgetFactory';
|
|
3
|
+
import vtkImageData from './../../Common/DataModel/ImageData';
|
|
4
|
+
import vtkImageReslice from './../../Imaging/Core/ImageReslice';
|
|
5
|
+
import vtkPlaneSource from './../../Filters/Sources/PlaneSource';
|
|
6
|
+
import vtkRenderer from './../../Rendering/Core/Renderer';
|
|
7
|
+
import vtkPlaneManipulator from './../Manipulators/PlaneManipulator';
|
|
8
|
+
import { ViewTypes } from './../Core/WidgetManager/Constants';
|
|
9
|
+
import { Vector2, Vector3 } from './../../types';
|
|
10
|
+
|
|
11
|
+
export interface IDisplayScaleParams {
|
|
12
|
+
dispHeightFactor: number,
|
|
13
|
+
cameraPosition: Vector3,
|
|
14
|
+
cameraDir: Vector3,
|
|
15
|
+
isParallel: false,
|
|
16
|
+
rendererPixelDims: Vector2
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface vtkResliceCursorWidget extends vtkAbstractWidgetFactory {
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {ViewTypes} viewType
|
|
23
|
+
*/
|
|
24
|
+
getRepresentationsForViewType(viewType: ViewTypes): unknown;
|
|
25
|
+
|
|
26
|
+
setImage(image: vtkImageData): void;
|
|
27
|
+
|
|
28
|
+
setCenter(center: Vector3): void;
|
|
29
|
+
|
|
30
|
+
updateCameraPoints(
|
|
31
|
+
renderer: vtkRenderer,
|
|
32
|
+
viewType: ViewTypes,
|
|
33
|
+
resetFocalPoint: boolean,
|
|
34
|
+
keepCenterFocalDistance: boolean,
|
|
35
|
+
computeFocalPointOffset: boolean
|
|
36
|
+
): void;
|
|
37
|
+
|
|
38
|
+
resetCamera(
|
|
39
|
+
renderer: vtkRenderer,
|
|
40
|
+
viewType: ViewTypes,
|
|
41
|
+
resetFocalPoint: boolean,
|
|
42
|
+
keepCenterFocalDistance: boolean
|
|
43
|
+
): void;
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
getPlaneSource(viewType: ViewTypes): vtkPlaneSource;
|
|
47
|
+
|
|
48
|
+
getResliceAxes(viewType: ViewTypes): mat4;
|
|
49
|
+
|
|
50
|
+
updateReslicePlane(imageReslice: vtkImageReslice, viewType: ViewTypes): boolean;
|
|
51
|
+
|
|
52
|
+
getPlaneSourceFromViewType(type: ViewTypes): vtkPlaneSource;
|
|
53
|
+
|
|
54
|
+
getPlaneNormalFromViewType(viewType: ViewTypes): Vector3;
|
|
55
|
+
|
|
56
|
+
getOtherPlaneNormals(viewType: ViewTypes): Array<Vector3>;
|
|
57
|
+
|
|
58
|
+
getResliceMatrix(): mat4;
|
|
59
|
+
|
|
60
|
+
getDisplayScaleParams(): IDisplayScaleParams;
|
|
61
|
+
|
|
62
|
+
setScaleInPixels(scale: boolean): boolean;
|
|
63
|
+
|
|
64
|
+
getScaleInPixels(): boolean;
|
|
65
|
+
|
|
66
|
+
setRotationHandlePosition(position: number): boolean;
|
|
67
|
+
|
|
68
|
+
getRotationHandlePosition(): number;
|
|
69
|
+
|
|
70
|
+
setManipulator(manipulator: vtkPlaneManipulator): boolean;
|
|
71
|
+
|
|
72
|
+
getManipulator(): vtkPlaneManipulator;
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface IResliceCursorWidgetInitialValues {}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Method used to decorate a given object (publicAPI+model) with vtkResliceCursorWidget characteristics.
|
|
80
|
+
*
|
|
81
|
+
* @param publicAPI object on which methods will be bounds (public)
|
|
82
|
+
* @param model object on which data structure will be bounds (protected)
|
|
83
|
+
* @param initialValues (default: {})
|
|
84
|
+
*/
|
|
85
|
+
export function extend(
|
|
86
|
+
publicAPI: object,
|
|
87
|
+
model: object,
|
|
88
|
+
initialValues?: IResliceCursorWidgetInitialValues
|
|
89
|
+
): vtkResliceCursorWidget;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Method used to create a new instance of vtkResliceCursorWidget
|
|
93
|
+
*
|
|
94
|
+
* @param initialValues for pre-setting some of its content
|
|
95
|
+
*/
|
|
96
|
+
export function newInstance(initialValues?: IResliceCursorWidgetInitialValues): vtkResliceCursorWidget;
|
|
97
|
+
|
|
98
|
+
export declare const vtkResliceCursorWidget: {
|
|
99
|
+
newInstance: typeof newInstance;
|
|
100
|
+
extend: typeof extend;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export default vtkResliceCursorWidget;
|
package/index.d.ts
CHANGED
|
@@ -130,6 +130,7 @@
|
|
|
130
130
|
/// <reference path="./Proxy/Core/SourceProxy.d.ts" />
|
|
131
131
|
/// <reference path="./Proxy/Core/View2DProxy.d.ts" />
|
|
132
132
|
/// <reference path="./Proxy/Core/ViewProxy.d.ts" />
|
|
133
|
+
/// <reference path="./Proxy/Representations/ResliceRepresentationProxy.d.ts" />
|
|
133
134
|
/// <reference path="./Proxy/Representations/SliceRepresentationProxy.d.ts" />
|
|
134
135
|
/// <reference path="./Proxy/Representations/VolumeRepresentationProxy.d.ts" />
|
|
135
136
|
/// <reference path="./Rendering/Core/AbstractImageMapper.d.ts" />
|
|
@@ -219,6 +220,7 @@
|
|
|
219
220
|
/// <reference path="./Widgets/Manipulators/TrackballManipulator.d.ts" />
|
|
220
221
|
/// <reference path="./Widgets/Representations/WidgetRepresentation.d.ts" />
|
|
221
222
|
/// <reference path="./Widgets/Widgets3D/InteractiveOrientationWidget.d.ts" />
|
|
223
|
+
/// <reference path="./Widgets/Widgets3D/ResliceCursorWidget.d.ts" />
|
|
222
224
|
/// <reference path="./Widgets/Widgets3D/SphereWidget.d.ts" />
|
|
223
225
|
/// <reference path="./macros.d.ts" />
|
|
224
226
|
/// <reference path="./vtk.d.ts" />
|