@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.
@@ -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 < 0 ? model.numberOfComponents : 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(): boolean;
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 {Boolean} slabThickness The slab thickness in world space (mm). Default: 0.
168
+ * @param {Number} slabThickness The slab thickness in world space (mm). Default: 0.
169
169
  */
170
- setSlabThickness(slabThickness: number): 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): 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): 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): 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
- scalars.set(basicScalars.subarray(bsIdx, bsIdx + numComp), id);
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
- scalars.set(basicScalars.subarray(_bsIdx, _bsIdx + numComp), _id);
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
- mat4.identity(model.tmpMat4);
444
- var bounds = image.getBounds();
445
- var sc = [bounds[1] - bounds[0], bounds[3] - bounds[2], bounds[5] - bounds[4]];
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;', 'vec3 normalxspacing = normalWCVSOutput * spacing * 0.5;', '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, 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, 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);', '}']);
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
- var _isVectorAxisAligned = isVectorAxisAligned(slicePlane.getNormal());
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
- var cube = vtkCubeSource.newInstance();
851
- cube.setCenter(0.5 * (bounds[0] + bounds[1]), 0.5 * (bounds[2] + bounds[3]), 0.5 * (bounds[4] + bounds[5]));
852
- cube.setXLength(bounds[1] - bounds[0]);
853
- cube.setYLength(bounds[3] - bounds[2]);
854
- cube.setZLength(bounds[5] - bounds[4]);
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 = pds.getOutputData();
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 o = slicePlane.getOrigin();
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] = o[orthoAxis];
898
- ptsArray[ptIdx + otherAxes[0]] = bounds[2 * otherAxes[0] + j];
899
- ptsArray[ptIdx + otherAxes[1]] = bounds[2 * otherAxes[1] + _i7];
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); // model.modelToView = mat4.identity(new Float64Array(16));
1047
+ obj(model.VBOBuildTime);
1048
+ model.tmpMat4 = mat4.identity(new Float64Array(16)); // Implicit plane to polydata related cache:
996
1049
 
997
- model.tmpMat4 = mat4.identity(new Float64Array(16));
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" />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitware/vtk.js",
3
- "version": "28.3.2",
3
+ "version": "28.4.0",
4
4
  "description": "Visualization Toolkit for the Web",
5
5
  "keywords": [
6
6
  "3d",