@kitware/vtk.js 30.7.1 → 30.9.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/Interaction/Style/InteractorStyleImage.js +3 -3
- package/Interaction/Style/InteractorStyleManipulator.js +12 -12
- package/Interaction/Style/InteractorStyleTrackballCamera.js +10 -10
- package/Interaction/Widgets/OrientationMarkerWidget.d.ts +7 -0
- package/Interaction/Widgets/OrientationMarkerWidget.js +4 -3
- package/Rendering/Core/InteractorStyle.d.ts +15 -0
- package/Rendering/Core/InteractorStyle.js +6 -4
- package/Rendering/Core/Mapper.d.ts +21 -12
- package/Rendering/Core/Mapper.js +62 -67
- package/Rendering/OpenGL/CellArrayBufferObject.js +37 -32
- package/Rendering/OpenGL/PolyDataMapper.js +6 -2
- package/Widgets/Widgets3D/InteractiveOrientationWidget/helpers.d.ts +73 -0
- package/Widgets/Widgets3D/InteractiveOrientationWidget/helpers.js +71 -0
- package/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ function vtkInteractorStyleImage(publicAPI, model) {
|
|
|
15
15
|
publicAPI.superHandleMouseMove = publicAPI.handleMouseMove;
|
|
16
16
|
publicAPI.handleMouseMove = callData => {
|
|
17
17
|
const pos = callData.position;
|
|
18
|
-
const renderer = callData
|
|
18
|
+
const renderer = model.getRenderer(callData);
|
|
19
19
|
switch (model.state) {
|
|
20
20
|
case States.IS_WINDOW_LEVEL:
|
|
21
21
|
publicAPI.windowLevel(renderer, pos);
|
|
@@ -94,7 +94,7 @@ function vtkInteractorStyleImage(publicAPI, model) {
|
|
|
94
94
|
|
|
95
95
|
//--------------------------------------------------------------------------
|
|
96
96
|
publicAPI.handleMouseWheel = callData => {
|
|
97
|
-
const camera = callData.
|
|
97
|
+
const camera = model.getRenderer(callData).getActiveCamera();
|
|
98
98
|
let distance = camera.getDistance();
|
|
99
99
|
distance += callData.spinY;
|
|
100
100
|
|
|
@@ -107,7 +107,7 @@ function vtkInteractorStyleImage(publicAPI, model) {
|
|
|
107
107
|
distance = range[1];
|
|
108
108
|
}
|
|
109
109
|
camera.setDistance(distance);
|
|
110
|
-
const props = callData.
|
|
110
|
+
const props = model.getRenderer(callData).getViewProps().filter(prop => prop.isA('vtkImageSlice'));
|
|
111
111
|
props.forEach(prop => {
|
|
112
112
|
if (prop.getMapper().isA('vtkImageResliceMapper')) {
|
|
113
113
|
const p = prop.getMapper().getSlicePlane();
|
|
@@ -251,7 +251,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
251
251
|
if (manipulator) {
|
|
252
252
|
// register the manipulator for this device
|
|
253
253
|
model.currentVRManipulators.set(ed.device, manipulator);
|
|
254
|
-
manipulator.onButton3D(publicAPI, ed
|
|
254
|
+
manipulator.onButton3D(publicAPI, model.getRenderer(ed), model.state, ed);
|
|
255
255
|
if (ed.pressed) {
|
|
256
256
|
publicAPI.startCameraPose();
|
|
257
257
|
} else {
|
|
@@ -271,7 +271,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
271
271
|
publicAPI.handleMove3D = ed => {
|
|
272
272
|
const manipulator = model.currentVRManipulators.get(ed.device);
|
|
273
273
|
if (manipulator && model.state === States.IS_CAMERA_POSE) {
|
|
274
|
-
manipulator.onMove3D(publicAPI, ed
|
|
274
|
+
manipulator.onMove3D(publicAPI, model.getRenderer(ed), model.state, ed);
|
|
275
275
|
}
|
|
276
276
|
};
|
|
277
277
|
|
|
@@ -292,7 +292,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
292
292
|
model.currentManipulator.setRotationFactor(model.rotationFactor);
|
|
293
293
|
}
|
|
294
294
|
model.currentManipulator.startInteraction();
|
|
295
|
-
model.currentManipulator.onButtonDown(model._interactor, callData
|
|
295
|
+
model.currentManipulator.onButtonDown(model._interactor, model.getRenderer(callData), callData.position);
|
|
296
296
|
model._interactor.requestAnimation(publicAPI.onButtonDown);
|
|
297
297
|
publicAPI.invokeStartInteractionEvent(START_INTERACTION_EVENT);
|
|
298
298
|
} else {
|
|
@@ -373,7 +373,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
373
373
|
}
|
|
374
374
|
if (manipulator) {
|
|
375
375
|
model.currentWheelManipulator = manipulator;
|
|
376
|
-
model.currentWheelManipulator.onStartScroll(model._interactor, callData
|
|
376
|
+
model.currentWheelManipulator.onStartScroll(model._interactor, model.getRenderer(callData), callData.spinY);
|
|
377
377
|
model.currentWheelManipulator.startInteraction();
|
|
378
378
|
model._interactor.requestAnimation(publicAPI.handleStartMouseWheel);
|
|
379
379
|
publicAPI.invokeStartInteractionEvent(START_INTERACTION_EVENT);
|
|
@@ -399,7 +399,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
399
399
|
//-------------------------------------------------------------------------
|
|
400
400
|
publicAPI.handleMouseWheel = callData => {
|
|
401
401
|
if (model.currentWheelManipulator && model.currentWheelManipulator.onScroll) {
|
|
402
|
-
model.currentWheelManipulator.onScroll(model._interactor, callData
|
|
402
|
+
model.currentWheelManipulator.onScroll(model._interactor, model.getRenderer(callData), callData.spinY, model.cachedMousePosition);
|
|
403
403
|
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
|
|
404
404
|
}
|
|
405
405
|
};
|
|
@@ -408,7 +408,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
408
408
|
publicAPI.handleMouseMove = callData => {
|
|
409
409
|
model.cachedMousePosition = callData.position;
|
|
410
410
|
if (model.currentManipulator && model.currentManipulator.onMouseMove) {
|
|
411
|
-
model.currentManipulator.onMouseMove(model._interactor, callData
|
|
411
|
+
model.currentManipulator.onMouseMove(model._interactor, model.getRenderer(callData), callData.position);
|
|
412
412
|
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
|
|
413
413
|
}
|
|
414
414
|
};
|
|
@@ -418,7 +418,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
418
418
|
//-------------------------------------------------------------------------
|
|
419
419
|
publicAPI.handleKeyPress = callData => {
|
|
420
420
|
model.keyboardManipulators.filter(m => m.onKeyPress).forEach(manipulator => {
|
|
421
|
-
manipulator.onKeyPress(model._interactor, callData
|
|
421
|
+
manipulator.onKeyPress(model._interactor, model.getRenderer(callData), callData.key);
|
|
422
422
|
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
|
|
423
423
|
});
|
|
424
424
|
};
|
|
@@ -426,7 +426,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
426
426
|
//-------------------------------------------------------------------------
|
|
427
427
|
publicAPI.handleKeyDown = callData => {
|
|
428
428
|
model.keyboardManipulators.filter(m => m.onKeyDown).forEach(manipulator => {
|
|
429
|
-
manipulator.onKeyDown(model._interactor, callData
|
|
429
|
+
manipulator.onKeyDown(model._interactor, model.getRenderer(callData), callData.key);
|
|
430
430
|
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
|
|
431
431
|
});
|
|
432
432
|
};
|
|
@@ -434,7 +434,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
434
434
|
//-------------------------------------------------------------------------
|
|
435
435
|
publicAPI.handleKeyUp = callData => {
|
|
436
436
|
model.keyboardManipulators.filter(m => m.onKeyUp).forEach(manipulator => {
|
|
437
|
-
manipulator.onKeyUp(model._interactor, callData
|
|
437
|
+
manipulator.onKeyUp(model._interactor, model.getRenderer(callData), callData.key);
|
|
438
438
|
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
|
|
439
439
|
});
|
|
440
440
|
};
|
|
@@ -539,7 +539,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
539
539
|
while (count--) {
|
|
540
540
|
const manipulator = model.gestureManipulators[count];
|
|
541
541
|
if (manipulator && manipulator.isPinchEnabled()) {
|
|
542
|
-
manipulator.onPinch(model._interactor, callData
|
|
542
|
+
manipulator.onPinch(model._interactor, model.getRenderer(callData), callData.scale);
|
|
543
543
|
actionCount++;
|
|
544
544
|
}
|
|
545
545
|
}
|
|
@@ -555,7 +555,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
555
555
|
while (count--) {
|
|
556
556
|
const manipulator = model.gestureManipulators[count];
|
|
557
557
|
if (manipulator && manipulator.isPanEnabled()) {
|
|
558
|
-
manipulator.onPan(model._interactor, callData
|
|
558
|
+
manipulator.onPan(model._interactor, model.getRenderer(callData), callData.translation);
|
|
559
559
|
actionCount++;
|
|
560
560
|
}
|
|
561
561
|
}
|
|
@@ -571,7 +571,7 @@ function vtkInteractorStyleManipulator(publicAPI, model) {
|
|
|
571
571
|
while (count--) {
|
|
572
572
|
const manipulator = model.gestureManipulators[count];
|
|
573
573
|
if (manipulator && manipulator.isRotateEnabled()) {
|
|
574
|
-
manipulator.onRotate(model._interactor, callData
|
|
574
|
+
manipulator.onRotate(model._interactor, model.getRenderer(callData), callData.rotation);
|
|
575
575
|
actionCount++;
|
|
576
576
|
}
|
|
577
577
|
}
|
|
@@ -21,7 +21,7 @@ function vtkInteractorStyleTrackballCamera(publicAPI, model) {
|
|
|
21
21
|
// Public API methods
|
|
22
22
|
publicAPI.handleMouseMove = callData => {
|
|
23
23
|
const pos = callData.position;
|
|
24
|
-
const renderer = callData
|
|
24
|
+
const renderer = model.getRenderer(callData);
|
|
25
25
|
switch (model.state) {
|
|
26
26
|
case States.IS_ROTATE:
|
|
27
27
|
publicAPI.handleMouseRotate(renderer, pos);
|
|
@@ -73,7 +73,7 @@ function vtkInteractorStyleTrackballCamera(publicAPI, model) {
|
|
|
73
73
|
publicAPI.updateCameraPose = ed => {
|
|
74
74
|
// move the world in the direction of the
|
|
75
75
|
// controller
|
|
76
|
-
const camera = ed.
|
|
76
|
+
const camera = model.getRenderer(ed).getActiveCamera();
|
|
77
77
|
const oldTrans = camera.getPhysicalTranslation();
|
|
78
78
|
|
|
79
79
|
// look at the y axis to determine how fast / what direction to move
|
|
@@ -169,25 +169,25 @@ function vtkInteractorStyleTrackballCamera(publicAPI, model) {
|
|
|
169
169
|
|
|
170
170
|
//----------------------------------------------------------------------------
|
|
171
171
|
publicAPI.handlePinch = callData => {
|
|
172
|
-
publicAPI.dollyByFactor(callData
|
|
172
|
+
publicAPI.dollyByFactor(model.getRenderer(callData), callData.scale / model.previousScale);
|
|
173
173
|
model.previousScale = callData.scale;
|
|
174
174
|
};
|
|
175
175
|
|
|
176
176
|
//----------------------------------------------------------------------------
|
|
177
177
|
publicAPI.handlePan = callData => {
|
|
178
|
-
const camera = callData.
|
|
178
|
+
const camera = model.getRenderer(callData).getActiveCamera();
|
|
179
179
|
|
|
180
180
|
// Calculate the focal depth since we'll be using it a lot
|
|
181
181
|
let viewFocus = camera.getFocalPoint();
|
|
182
|
-
viewFocus = publicAPI.computeWorldToDisplay(callData
|
|
182
|
+
viewFocus = publicAPI.computeWorldToDisplay(model.getRenderer(callData), viewFocus[0], viewFocus[1], viewFocus[2]);
|
|
183
183
|
const focalDepth = viewFocus[2];
|
|
184
184
|
const trans = callData.translation;
|
|
185
185
|
const lastTrans = model.previousTranslation;
|
|
186
|
-
const newPickPoint = publicAPI.computeDisplayToWorld(callData
|
|
186
|
+
const newPickPoint = publicAPI.computeDisplayToWorld(model.getRenderer(callData), viewFocus[0] + trans[0] - lastTrans[0], viewFocus[1] + trans[1] - lastTrans[1], focalDepth);
|
|
187
187
|
|
|
188
188
|
// Has to recalc old mouse point since the viewport has moved,
|
|
189
189
|
// so can't move it outside the loop
|
|
190
|
-
const oldPickPoint = publicAPI.computeDisplayToWorld(callData
|
|
190
|
+
const oldPickPoint = publicAPI.computeDisplayToWorld(model.getRenderer(callData), viewFocus[0], viewFocus[1], focalDepth);
|
|
191
191
|
|
|
192
192
|
// Camera motion is reversed
|
|
193
193
|
const motionVector = [];
|
|
@@ -199,7 +199,7 @@ function vtkInteractorStyleTrackballCamera(publicAPI, model) {
|
|
|
199
199
|
camera.setFocalPoint(motionVector[0] + viewFocus[0], motionVector[1] + viewFocus[1], motionVector[2] + viewFocus[2]);
|
|
200
200
|
camera.setPosition(motionVector[0] + viewPoint[0], motionVector[1] + viewPoint[1], motionVector[2] + viewPoint[2]);
|
|
201
201
|
if (model._interactor.getLightFollowCamera()) {
|
|
202
|
-
callData.
|
|
202
|
+
model.getRenderer(callData).updateLightsGeometryToFollowCamera();
|
|
203
203
|
}
|
|
204
204
|
camera.orthogonalizeViewUp();
|
|
205
205
|
model.previousTranslation = callData.translation;
|
|
@@ -207,7 +207,7 @@ function vtkInteractorStyleTrackballCamera(publicAPI, model) {
|
|
|
207
207
|
|
|
208
208
|
//----------------------------------------------------------------------------
|
|
209
209
|
publicAPI.handleRotate = callData => {
|
|
210
|
-
const camera = callData.
|
|
210
|
+
const camera = model.getRenderer(callData).getActiveCamera();
|
|
211
211
|
camera.roll(callData.rotation - model.previousRotation);
|
|
212
212
|
camera.orthogonalizeViewUp();
|
|
213
213
|
model.previousRotation = callData.rotation;
|
|
@@ -306,7 +306,7 @@ function vtkInteractorStyleTrackballCamera(publicAPI, model) {
|
|
|
306
306
|
//----------------------------------------------------------------------------
|
|
307
307
|
publicAPI.handleMouseWheel = callData => {
|
|
308
308
|
const dyf = 1 - callData.spinY / model.zoomFactor;
|
|
309
|
-
publicAPI.dollyByFactor(callData
|
|
309
|
+
publicAPI.dollyByFactor(model.getRenderer(callData), dyf);
|
|
310
310
|
};
|
|
311
311
|
|
|
312
312
|
//----------------------------------------------------------------------------
|
|
@@ -145,6 +145,13 @@ export interface vtkOrientationMarkerWidget extends vtkObject {
|
|
|
145
145
|
* Updates the orientation widget viewport size.
|
|
146
146
|
*/
|
|
147
147
|
updateViewport(): void;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* An instance of this class will spawn its own renderer, by default non interactive.
|
|
151
|
+
* This behavior is configurable through the interactiveRenderer property when initializing the instance.
|
|
152
|
+
* @returns true if the renderer was created as interactive, false otherwise.
|
|
153
|
+
*/
|
|
154
|
+
getInteractiveRenderer(): boolean;
|
|
148
155
|
}
|
|
149
156
|
|
|
150
157
|
/**
|
|
@@ -123,7 +123,7 @@ function vtkOrientationMarkerWidget(publicAPI, model) {
|
|
|
123
123
|
}
|
|
124
124
|
// Highest number is foreground
|
|
125
125
|
selfRenderer.setLayer(renderWindow.getNumberOfLayers() - 1);
|
|
126
|
-
selfRenderer.setInteractive(
|
|
126
|
+
selfRenderer.setInteractive(model.interactiveRenderer);
|
|
127
127
|
selfRenderer.addViewProp(model.actor);
|
|
128
128
|
model.actor.setVisibility(true);
|
|
129
129
|
onCameraChangedSub = ren.onEvent(event => {
|
|
@@ -236,7 +236,8 @@ const DEFAULT_VALUES = {
|
|
|
236
236
|
viewportSize: 0.2,
|
|
237
237
|
minPixelSize: 50,
|
|
238
238
|
maxPixelSize: 200,
|
|
239
|
-
parentRenderer: null
|
|
239
|
+
parentRenderer: null,
|
|
240
|
+
interactiveRenderer: false
|
|
240
241
|
};
|
|
241
242
|
|
|
242
243
|
// ----------------------------------------------------------------------------
|
|
@@ -247,7 +248,7 @@ function extend(publicAPI, model) {
|
|
|
247
248
|
|
|
248
249
|
// Build VTK API
|
|
249
250
|
macro.obj(publicAPI, model);
|
|
250
|
-
macro.get(publicAPI, model, ['enabled', 'viewportCorner', 'viewportSize']);
|
|
251
|
+
macro.get(publicAPI, model, ['enabled', 'viewportCorner', 'viewportSize', 'interactiveRenderer']);
|
|
251
252
|
|
|
252
253
|
// NOTE: setting these while the widget is enabled will
|
|
253
254
|
// not update the widget.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { EventHandler, vtkSubscription } from './../../interfaces';
|
|
2
|
+
import { Nullable } from './../../types';
|
|
2
3
|
import vtkInteractorObserver from './InteractorObserver';
|
|
4
|
+
import vtkRenderer from './Renderer';
|
|
3
5
|
|
|
4
6
|
export interface vtkInteractorStyle extends vtkInteractorObserver {
|
|
5
7
|
/**
|
|
@@ -210,6 +212,19 @@ export interface vtkInteractorStyle extends vtkInteractorObserver {
|
|
|
210
212
|
* Handles a keypress.
|
|
211
213
|
*/
|
|
212
214
|
handleKeyPress(callData: unknown): void;
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Explicitly defines a renderer to be used for event handling.
|
|
218
|
+
* If never called or called with null, the pokedRenderer of the event will be used.
|
|
219
|
+
*
|
|
220
|
+
* @param {Nullable<vtkRenderer>} renderer
|
|
221
|
+
*/
|
|
222
|
+
setFocusedRenderer(renderer: Nullable<vtkRenderer>): boolean;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get the renderer used for event handling, returns null if not set.
|
|
226
|
+
*/
|
|
227
|
+
getFocusedRenderer(): Nullable<vtkRenderer>;
|
|
213
228
|
}
|
|
214
229
|
|
|
215
230
|
export interface IInteractorStyleInitialValues {
|
|
@@ -64,6 +64,7 @@ function vtkInteractorStyle(publicAPI, model) {
|
|
|
64
64
|
model._interactor.render();
|
|
65
65
|
};
|
|
66
66
|
});
|
|
67
|
+
model.getRenderer = callData => model.focusedRenderer || callData.pokedRenderer;
|
|
67
68
|
|
|
68
69
|
//----------------------------------------------------------------------------
|
|
69
70
|
publicAPI.handleKeyPress = callData => {
|
|
@@ -72,12 +73,12 @@ function vtkInteractorStyle(publicAPI, model) {
|
|
|
72
73
|
switch (callData.key) {
|
|
73
74
|
case 'r':
|
|
74
75
|
case 'R':
|
|
75
|
-
callData.
|
|
76
|
+
model.getRenderer(callData).resetCamera();
|
|
76
77
|
rwi.render();
|
|
77
78
|
break;
|
|
78
79
|
case 'w':
|
|
79
80
|
case 'W':
|
|
80
|
-
ac = callData.
|
|
81
|
+
ac = model.getRenderer(callData).getActors();
|
|
81
82
|
ac.forEach(anActor => {
|
|
82
83
|
const prop = anActor.getProperty();
|
|
83
84
|
if (prop.setRepresentationToWireframe) {
|
|
@@ -88,7 +89,7 @@ function vtkInteractorStyle(publicAPI, model) {
|
|
|
88
89
|
break;
|
|
89
90
|
case 's':
|
|
90
91
|
case 'S':
|
|
91
|
-
ac = callData.
|
|
92
|
+
ac = model.getRenderer(callData).getActors();
|
|
92
93
|
ac.forEach(anActor => {
|
|
93
94
|
const prop = anActor.getProperty();
|
|
94
95
|
if (prop.setRepresentationToSurface) {
|
|
@@ -99,7 +100,7 @@ function vtkInteractorStyle(publicAPI, model) {
|
|
|
99
100
|
break;
|
|
100
101
|
case 'v':
|
|
101
102
|
case 'V':
|
|
102
|
-
ac = callData.
|
|
103
|
+
ac = model.getRenderer(callData).getActors();
|
|
103
104
|
ac.forEach(anActor => {
|
|
104
105
|
const prop = anActor.getProperty();
|
|
105
106
|
if (prop.setRepresentationToPoints) {
|
|
@@ -130,6 +131,7 @@ function extend(publicAPI, model) {
|
|
|
130
131
|
|
|
131
132
|
// Inheritance
|
|
132
133
|
vtkInteractorObserver.extend(publicAPI, model, initialValues);
|
|
134
|
+
macro.setGet(publicAPI, model, ['focusedRenderer']);
|
|
133
135
|
|
|
134
136
|
// Object specific methods
|
|
135
137
|
vtkInteractorStyle(publicAPI, model);
|
|
@@ -3,6 +3,7 @@ import vtkAbstractMapper3D, {
|
|
|
3
3
|
IAbstractMapper3DInitialValues,
|
|
4
4
|
} from './AbstractMapper3D';
|
|
5
5
|
import { ColorMode, GetArray, ScalarMode } from './Mapper/Constants';
|
|
6
|
+
import vtkDataArray from './../../Common/Core/DataArray';
|
|
6
7
|
|
|
7
8
|
interface IPrimitiveCount {
|
|
8
9
|
points: number;
|
|
@@ -13,6 +14,7 @@ interface IPrimitiveCount {
|
|
|
13
14
|
|
|
14
15
|
interface IAbstractScalars {
|
|
15
16
|
cellFlag: boolean;
|
|
17
|
+
scalars: Nullable<vtkDataArray>;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
interface ICoincidentTopology {
|
|
@@ -54,9 +56,13 @@ export interface vtkMapper extends vtkAbstractMapper3D {
|
|
|
54
56
|
* When rendering multiblock datasets, if any 2 blocks provide different
|
|
55
57
|
* lookup tables for the scalars, then also we cannot use textures. This case
|
|
56
58
|
* can be handled if required.
|
|
57
|
-
* @param
|
|
59
|
+
* @param scalars
|
|
60
|
+
* @param cellFlag True when the scalars are per cell instead of per point
|
|
58
61
|
*/
|
|
59
|
-
canUseTextureMapForColoring(
|
|
62
|
+
canUseTextureMapForColoring(
|
|
63
|
+
scalars: vtkDataArray,
|
|
64
|
+
cellFlag: boolean
|
|
65
|
+
): boolean;
|
|
60
66
|
|
|
61
67
|
/**
|
|
62
68
|
* Call to force a rebuild of color result arrays on next MapScalars.
|
|
@@ -77,26 +83,18 @@ export interface vtkMapper extends vtkAbstractMapper3D {
|
|
|
77
83
|
/**
|
|
78
84
|
*
|
|
79
85
|
* @param input
|
|
80
|
-
* @param output
|
|
81
|
-
* @param numScalars
|
|
82
|
-
* @param numComps
|
|
83
86
|
* @param component
|
|
84
87
|
* @param range
|
|
85
|
-
* @param tableRange
|
|
86
88
|
* @param tableNumberOfColors
|
|
87
89
|
* @param useLogScale
|
|
88
90
|
*/
|
|
89
91
|
createColorTextureCoordinates(
|
|
90
|
-
input:
|
|
91
|
-
output: any,
|
|
92
|
-
numScalars: number,
|
|
93
|
-
numComps: number,
|
|
92
|
+
input: vtkDataArray,
|
|
94
93
|
component: number,
|
|
95
94
|
range: any,
|
|
96
|
-
tableRange: any,
|
|
97
95
|
tableNumberOfColors: number,
|
|
98
96
|
useLogScale: boolean
|
|
99
|
-
):
|
|
97
|
+
): vtkDataArray;
|
|
100
98
|
|
|
101
99
|
/**
|
|
102
100
|
* Create default lookup table. Generally used to create one when
|
|
@@ -120,6 +118,17 @@ export interface vtkMapper extends vtkAbstractMapper3D {
|
|
|
120
118
|
arrayName: any
|
|
121
119
|
): IAbstractScalars;
|
|
122
120
|
|
|
121
|
+
/**
|
|
122
|
+
* When scalars are mapped from cells,
|
|
123
|
+
* there is one color coordinate per cell instead of one per point
|
|
124
|
+
* in the vtkDataArray getColorCoordinates().
|
|
125
|
+
* It means that when getAreScalarsMappedFromCells() is true,
|
|
126
|
+
* the number of tuples in getColorCoordinates() is the number of points,
|
|
127
|
+
* and when getAreScalarsMappedFromCells() is false,
|
|
128
|
+
* the number of tuples in getColorCoordinates() is the number of cells.
|
|
129
|
+
*/
|
|
130
|
+
getAreScalarsMappedFromCells(): boolean;
|
|
131
|
+
|
|
123
132
|
/**
|
|
124
133
|
*
|
|
125
134
|
*/
|
package/Rendering/Core/Mapper.js
CHANGED
|
@@ -132,7 +132,11 @@ function vtkMapper(publicAPI, model) {
|
|
|
132
132
|
};
|
|
133
133
|
};
|
|
134
134
|
publicAPI.mapScalars = (input, alpha) => {
|
|
135
|
-
const
|
|
135
|
+
const {
|
|
136
|
+
scalars,
|
|
137
|
+
cellFlag
|
|
138
|
+
} = publicAPI.getAbstractScalars(input, model.scalarMode, model.arrayAccessMode, model.arrayId, model.colorByArrayName);
|
|
139
|
+
model.areScalarsMappedFromCells = cellFlag;
|
|
136
140
|
if (!scalars) {
|
|
137
141
|
model.colorCoordinates = null;
|
|
138
142
|
model.colorTextureMap = null;
|
|
@@ -150,7 +154,7 @@ function vtkMapper(publicAPI, model) {
|
|
|
150
154
|
// Decide between texture color or vertex color.
|
|
151
155
|
// Cell data always uses vertex color.
|
|
152
156
|
// Only point data can use both texture and vertex coloring.
|
|
153
|
-
if (publicAPI.canUseTextureMapForColoring(
|
|
157
|
+
if (publicAPI.canUseTextureMapForColoring(scalars, cellFlag)) {
|
|
154
158
|
publicAPI.mapScalarsToTexture(scalars, alpha);
|
|
155
159
|
} else {
|
|
156
160
|
model.colorCoordinates = null;
|
|
@@ -205,50 +209,56 @@ function vtkMapper(publicAPI, model) {
|
|
|
205
209
|
};
|
|
206
210
|
|
|
207
211
|
//-----------------------------------------------------------------------------
|
|
208
|
-
publicAPI.createColorTextureCoordinates = (input,
|
|
212
|
+
publicAPI.createColorTextureCoordinates = (input, component, range, tableNumberOfColors, useLogScale) => {
|
|
209
213
|
// We have to change the range used for computing texture
|
|
210
214
|
// coordinates slightly to accommodate the special above- and
|
|
211
215
|
// below-range colors that are the first and last texels,
|
|
212
216
|
// respectively.
|
|
213
217
|
const scalarTexelWidth = (range[1] - range[0]) / tableNumberOfColors;
|
|
214
|
-
const paddedRange = [];
|
|
215
|
-
paddedRange[0] = range[0] - scalarTexelWidth;
|
|
216
|
-
paddedRange[1] = range[1] + scalarTexelWidth;
|
|
218
|
+
const paddedRange = [range[0] - scalarTexelWidth, range[1] + scalarTexelWidth];
|
|
217
219
|
const invRangeWidth = 1.0 / (paddedRange[1] - paddedRange[0]);
|
|
218
|
-
const outputV = output.getData();
|
|
219
220
|
const inputV = input.getData();
|
|
220
|
-
|
|
221
|
-
|
|
221
|
+
const numScalars = input.getNumberOfTuples();
|
|
222
|
+
const numComps = input.getNumberOfComponents();
|
|
223
|
+
const output = vtkDataArray.newInstance({
|
|
224
|
+
numberOfComponents: 2,
|
|
225
|
+
values: new Float32Array(numScalars * 2)
|
|
226
|
+
});
|
|
227
|
+
const outputV = output.getData();
|
|
222
228
|
if (component < 0 || component >= numComps) {
|
|
229
|
+
// Convert the magnitude of all components to texture coordinates
|
|
230
|
+
let inputIdx = 0;
|
|
231
|
+
let outputIdx = 0;
|
|
223
232
|
for (let scalarIdx = 0; scalarIdx < numScalars; ++scalarIdx) {
|
|
224
233
|
let sum = 0;
|
|
225
234
|
for (let compIdx = 0; compIdx < numComps; ++compIdx) {
|
|
226
|
-
sum += inputV[
|
|
227
|
-
|
|
235
|
+
sum += inputV[inputIdx] * inputV[inputIdx];
|
|
236
|
+
inputIdx++;
|
|
228
237
|
}
|
|
229
238
|
let magnitude = Math.sqrt(sum);
|
|
230
239
|
if (useLogScale) {
|
|
231
|
-
magnitude = vtkLookupTable.applyLogScale(magnitude,
|
|
240
|
+
magnitude = vtkLookupTable.applyLogScale(magnitude, range, range);
|
|
232
241
|
}
|
|
233
242
|
const outputs = publicAPI.scalarToTextureCoordinate(magnitude, paddedRange[0], invRangeWidth);
|
|
234
|
-
outputV[
|
|
235
|
-
outputV[
|
|
236
|
-
outputCount += 2;
|
|
243
|
+
outputV[outputIdx++] = outputs.texCoordS;
|
|
244
|
+
outputV[outputIdx++] = outputs.texCoordT;
|
|
237
245
|
}
|
|
238
246
|
} else {
|
|
239
|
-
|
|
247
|
+
// Convert one of the components to texture coordinates
|
|
248
|
+
let inputIdx = component;
|
|
249
|
+
let outputIdx = 0;
|
|
240
250
|
for (let scalarIdx = 0; scalarIdx < numScalars; ++scalarIdx) {
|
|
241
|
-
let inputValue = inputV[
|
|
251
|
+
let inputValue = inputV[inputIdx];
|
|
242
252
|
if (useLogScale) {
|
|
243
|
-
inputValue = vtkLookupTable.applyLogScale(inputValue,
|
|
253
|
+
inputValue = vtkLookupTable.applyLogScale(inputValue, range, range);
|
|
244
254
|
}
|
|
245
255
|
const outputs = publicAPI.scalarToTextureCoordinate(inputValue, paddedRange[0], invRangeWidth);
|
|
246
|
-
outputV[
|
|
247
|
-
outputV[
|
|
248
|
-
|
|
249
|
-
count += numComps;
|
|
256
|
+
outputV[outputIdx++] = outputs.texCoordS;
|
|
257
|
+
outputV[outputIdx++] = outputs.texCoordT;
|
|
258
|
+
inputIdx += numComps;
|
|
250
259
|
}
|
|
251
260
|
}
|
|
261
|
+
return output;
|
|
252
262
|
};
|
|
253
263
|
publicAPI.mapScalarsToTexture = (scalars, alpha) => {
|
|
254
264
|
const range = model.lookupTable.getRange();
|
|
@@ -274,28 +284,23 @@ function vtkMapper(publicAPI, model) {
|
|
|
274
284
|
// Create a dummy ramp of scalars.
|
|
275
285
|
// In the future, we could extend vtkScalarsToColors.
|
|
276
286
|
model.lookupTable.build();
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const newArray = new Float64Array(numberOfColors * 2);
|
|
287
|
-
for (let i = 0; i < numberOfColors; ++i) {
|
|
288
|
-
newArray[i] = range[0] + i * k - k / 2.0; // minus k / 2 to start at below range color
|
|
287
|
+
const numberOfColorsInRange = Math.min(Math.max(model.lookupTable.getNumberOfAvailableColors(), 64), 4094);
|
|
288
|
+
// Texel width is computed before min and max colors that are out of range
|
|
289
|
+
const scalarTexelWidth = (range[1] - range[0]) / numberOfColorsInRange;
|
|
290
|
+
// Add two colors for special min and max colors
|
|
291
|
+
const totalNumberOfColors = numberOfColorsInRange + 2;
|
|
292
|
+
const newArray = new Float64Array(totalNumberOfColors * 2);
|
|
293
|
+
for (let i = 0; i < totalNumberOfColors; ++i) {
|
|
294
|
+
// minus 0.5 to start at below range color
|
|
295
|
+
newArray[i] = range[0] + (i - 0.5) * scalarTexelWidth;
|
|
289
296
|
if (useLogScale) {
|
|
290
297
|
newArray[i] = 10.0 ** newArray[i];
|
|
291
298
|
}
|
|
292
299
|
}
|
|
293
300
|
// Dimension on NaN.
|
|
294
|
-
|
|
295
|
-
newArray[i + numberOfColors] = NaN;
|
|
296
|
-
}
|
|
301
|
+
newArray.fill(NaN, totalNumberOfColors);
|
|
297
302
|
model.colorTextureMap = vtkImageData.newInstance();
|
|
298
|
-
model.colorTextureMap.setExtent(0,
|
|
303
|
+
model.colorTextureMap.setExtent(0, totalNumberOfColors - 1, 0, 1, 0, 0);
|
|
299
304
|
const tmp = vtkDataArray.newInstance({
|
|
300
305
|
numberOfComponents: 1,
|
|
301
306
|
values: newArray
|
|
@@ -304,28 +309,20 @@ function vtkMapper(publicAPI, model) {
|
|
|
304
309
|
model.lookupTable.setAlpha(origAlpha);
|
|
305
310
|
}
|
|
306
311
|
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
// Get rid of old colors
|
|
311
|
-
model.colorCoordinates = null;
|
|
312
|
+
// Although I like the feature of applying magnitude to single component
|
|
313
|
+
// scalars, it is not how the old MapScalars for vertex coloring works.
|
|
314
|
+
const scalarComponent = model.lookupTable.getVectorMode() === VectorMode.MAGNITUDE && scalars.getNumberOfComponents() > 1 ? -1 : model.lookupTable.getVectorComponent();
|
|
312
315
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
+
// Reverse the computation of numberOfColorsInRange that is used to compute model.colorTextureMap
|
|
317
|
+
const textureMapTuples = model.colorTextureMap.getPointData().getScalars().getNumberOfTuples();
|
|
318
|
+
const totalNumberOfColors = textureMapTuples / 2;
|
|
319
|
+
const numberOfColorsInRange = totalNumberOfColors - 2;
|
|
316
320
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
let scalarComponent = model.lookupTable.getVectorComponent();
|
|
323
|
-
// Although I like the feature of applying magnitude to single component
|
|
324
|
-
// scalars, it is not how the old MapScalars for vertex coloring works.
|
|
325
|
-
if (model.lookupTable.getVectorMode() === VectorMode.MAGNITUDE && scalars.getNumberOfComponents() > 1) {
|
|
326
|
-
scalarComponent = -1;
|
|
327
|
-
}
|
|
328
|
-
publicAPI.createColorTextureCoordinates(scalars, model.colorCoordinates, num, numComps, scalarComponent, range, model.lookupTable.getRange(), model.colorTextureMap.getPointData().getScalars().getNumberOfTuples() / 2 - 2, useLogScale);
|
|
321
|
+
// Create new coordinates if necessary.
|
|
322
|
+
const colorCoordinatesString = `${scalars.getMTime()}/${scalarComponent}/${range}/${numberOfColorsInRange}/${useLogScale}`;
|
|
323
|
+
if (colorCoordinatesString !== model.colorCoordinatesString) {
|
|
324
|
+
model.colorCoordinates = publicAPI.createColorTextureCoordinates(scalars, scalarComponent, range, numberOfColorsInRange, useLogScale);
|
|
325
|
+
model.colorCoordinatesString = colorCoordinatesString;
|
|
329
326
|
}
|
|
330
327
|
};
|
|
331
328
|
publicAPI.getIsOpaque = () => {
|
|
@@ -344,7 +341,11 @@ function vtkMapper(publicAPI, model) {
|
|
|
344
341
|
}
|
|
345
342
|
return true;
|
|
346
343
|
};
|
|
347
|
-
publicAPI.canUseTextureMapForColoring =
|
|
344
|
+
publicAPI.canUseTextureMapForColoring = (scalars, cellFlag) => {
|
|
345
|
+
if (cellFlag) {
|
|
346
|
+
return true; // cell data always use textures.
|
|
347
|
+
}
|
|
348
|
+
|
|
348
349
|
if (!model.interpolateScalarsBeforeMapping) {
|
|
349
350
|
return false; // user doesn't want us to use texture maps at all.
|
|
350
351
|
}
|
|
@@ -353,16 +354,10 @@ function vtkMapper(publicAPI, model) {
|
|
|
353
354
|
if (model.lookupTable && model.lookupTable.getIndexedLookup()) {
|
|
354
355
|
return false;
|
|
355
356
|
}
|
|
356
|
-
const gasResult = publicAPI.getAbstractScalars(input, model.scalarMode, model.arrayAccessMode, model.arrayId, model.colorByArrayName);
|
|
357
|
-
const scalars = gasResult.scalars;
|
|
358
357
|
if (!scalars) {
|
|
359
358
|
// no scalars on this dataset, we don't care if texture is used at all.
|
|
360
359
|
return false;
|
|
361
360
|
}
|
|
362
|
-
if (gasResult.cellFlag) {
|
|
363
|
-
return false; // cell data colors, don't use textures.
|
|
364
|
-
}
|
|
365
|
-
|
|
366
361
|
if (model.colorMode === ColorMode.DEFAULT && scalars.getDataType() === VtkDataTypes.UNSIGNED_CHAR || model.colorMode === ColorMode.DIRECT_SCALARS) {
|
|
367
362
|
// Don't use texture is direct coloring using RGB unsigned chars is
|
|
368
363
|
// requested.
|
|
@@ -464,7 +459,7 @@ function vtkMapper(publicAPI, model) {
|
|
|
464
459
|
const DEFAULT_VALUES = {
|
|
465
460
|
colorMapColors: null,
|
|
466
461
|
// Same as this->Colors
|
|
467
|
-
|
|
462
|
+
areScalarsMappedFromCells: false,
|
|
468
463
|
static: false,
|
|
469
464
|
lookupTable: null,
|
|
470
465
|
scalarVisibility: true,
|
|
@@ -497,7 +492,7 @@ function extend(publicAPI, model) {
|
|
|
497
492
|
|
|
498
493
|
// Inheritance
|
|
499
494
|
vtkAbstractMapper3D.extend(publicAPI, model, initialValues);
|
|
500
|
-
macro.get(publicAPI, model, ['colorCoordinates', 'colorMapColors', 'colorTextureMap', 'selectionWebGLIdsToVTKIds']);
|
|
495
|
+
macro.get(publicAPI, model, ['areScalarsMappedFromCells', 'colorCoordinates', 'colorMapColors', 'colorTextureMap', 'selectionWebGLIdsToVTKIds']);
|
|
501
496
|
macro.setGet(publicAPI, model, ['colorByArrayName', 'arrayAccessMode', 'colorMode', 'fieldDataTupleId', 'interpolateScalarsBeforeMapping', 'lookupTable', 'populateSelectionSettings', 'renderTime', 'scalarMode', 'scalarVisibility', 'static', 'useLookupTableScalarRange', 'customShaderAttributes' // point data array names that will be transferred to the VBO
|
|
502
497
|
]);
|
|
503
498
|
|
|
@@ -104,52 +104,52 @@ function vtkOpenGLCellArrayBufferObject(publicAPI, model) {
|
|
|
104
104
|
let addAPoint;
|
|
105
105
|
const cellBuilders = {
|
|
106
106
|
// easy, every input point becomes an output point
|
|
107
|
-
anythingToPoints(numPoints, cellPts, offset) {
|
|
107
|
+
anythingToPoints(numPoints, cellPts, offset, cellId) {
|
|
108
108
|
for (let i = 0; i < numPoints; ++i) {
|
|
109
|
-
addAPoint(cellPts[offset + i]);
|
|
109
|
+
addAPoint(cellPts[offset + i], cellId);
|
|
110
110
|
}
|
|
111
111
|
},
|
|
112
|
-
linesToWireframe(numPoints, cellPts, offset) {
|
|
112
|
+
linesToWireframe(numPoints, cellPts, offset, cellIdx) {
|
|
113
113
|
// for lines we add a bunch of segments
|
|
114
114
|
for (let i = 0; i < numPoints - 1; ++i) {
|
|
115
|
-
addAPoint(cellPts[offset + i]);
|
|
116
|
-
addAPoint(cellPts[offset + i + 1]);
|
|
115
|
+
addAPoint(cellPts[offset + i], cellIdx);
|
|
116
|
+
addAPoint(cellPts[offset + i + 1], cellIdx);
|
|
117
117
|
}
|
|
118
118
|
},
|
|
119
|
-
polysToWireframe(numPoints, cellPts, offset) {
|
|
119
|
+
polysToWireframe(numPoints, cellPts, offset, cellIdx) {
|
|
120
120
|
// for polys we add a bunch of segments and close it
|
|
121
121
|
if (numPoints > 2) {
|
|
122
122
|
for (let i = 0; i < numPoints; ++i) {
|
|
123
|
-
addAPoint(cellPts[offset + i]);
|
|
124
|
-
addAPoint(cellPts[offset + (i + 1) % numPoints]);
|
|
123
|
+
addAPoint(cellPts[offset + i], cellIdx);
|
|
124
|
+
addAPoint(cellPts[offset + (i + 1) % numPoints], cellIdx);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
},
|
|
128
|
-
stripsToWireframe(numPoints, cellPts, offset) {
|
|
128
|
+
stripsToWireframe(numPoints, cellPts, offset, cellIdx) {
|
|
129
129
|
if (numPoints > 2) {
|
|
130
130
|
// for strips we add a bunch of segments and close it
|
|
131
131
|
for (let i = 0; i < numPoints - 1; ++i) {
|
|
132
|
-
addAPoint(cellPts[offset + i]);
|
|
133
|
-
addAPoint(cellPts[offset + i + 1]);
|
|
132
|
+
addAPoint(cellPts[offset + i], cellIdx);
|
|
133
|
+
addAPoint(cellPts[offset + i + 1], cellIdx);
|
|
134
134
|
}
|
|
135
135
|
for (let i = 0; i < numPoints - 2; i++) {
|
|
136
|
-
addAPoint(cellPts[offset + i]);
|
|
137
|
-
addAPoint(cellPts[offset + i + 2]);
|
|
136
|
+
addAPoint(cellPts[offset + i], cellIdx);
|
|
137
|
+
addAPoint(cellPts[offset + i + 2], cellIdx);
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
},
|
|
141
|
-
polysToSurface(npts, cellPts, offset) {
|
|
141
|
+
polysToSurface(npts, cellPts, offset, cellIdx) {
|
|
142
142
|
for (let i = 0; i < npts - 2; i++) {
|
|
143
|
-
addAPoint(cellPts[offset + 0]);
|
|
144
|
-
addAPoint(cellPts[offset + i + 1]);
|
|
145
|
-
addAPoint(cellPts[offset + i + 2]);
|
|
143
|
+
addAPoint(cellPts[offset + 0], cellIdx);
|
|
144
|
+
addAPoint(cellPts[offset + i + 1], cellIdx);
|
|
145
|
+
addAPoint(cellPts[offset + i + 2], cellIdx);
|
|
146
146
|
}
|
|
147
147
|
},
|
|
148
|
-
stripsToSurface(npts, cellPts, offset) {
|
|
148
|
+
stripsToSurface(npts, cellPts, offset, cellIdx) {
|
|
149
149
|
for (let i = 0; i < npts - 2; i++) {
|
|
150
|
-
addAPoint(cellPts[offset + i]);
|
|
151
|
-
addAPoint(cellPts[offset + i + 1 + i % 2]);
|
|
152
|
-
addAPoint(cellPts[offset + i + 1 + (i + 1) % 2]);
|
|
150
|
+
addAPoint(cellPts[offset + i], cellIdx);
|
|
151
|
+
addAPoint(cellPts[offset + i + 1 + i % 2], cellIdx);
|
|
152
|
+
addAPoint(cellPts[offset + i + 1 + (i + 1) % 2], cellIdx);
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
};
|
|
@@ -264,16 +264,16 @@ function vtkOpenGLCellArrayBufferObject(publicAPI, model) {
|
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
let pointCount = options.vertexOffset;
|
|
267
|
-
addAPoint = function addAPointFunc(
|
|
267
|
+
addAPoint = function addAPointFunc(pointId, cellId) {
|
|
268
268
|
// Keep track of original point and cell ids, for selection
|
|
269
269
|
if (selectionMaps) {
|
|
270
|
-
selectionMaps.points[pointCount] =
|
|
270
|
+
selectionMaps.points[pointCount] = pointId;
|
|
271
271
|
selectionMaps.cells[pointCount] = cellCount + options.cellOffset;
|
|
272
272
|
}
|
|
273
273
|
++pointCount;
|
|
274
274
|
|
|
275
275
|
// Vertices
|
|
276
|
-
pointIdx =
|
|
276
|
+
pointIdx = pointId * 3;
|
|
277
277
|
if (!model.coordShiftAndScaleEnabled) {
|
|
278
278
|
packedVBO[vboidx++] = pointData[pointIdx++];
|
|
279
279
|
packedVBO[vboidx++] = pointData[pointIdx++];
|
|
@@ -288,20 +288,24 @@ function vtkOpenGLCellArrayBufferObject(publicAPI, model) {
|
|
|
288
288
|
if (options.haveCellNormals) {
|
|
289
289
|
normalIdx = (cellCount + options.cellOffset) * 3;
|
|
290
290
|
} else {
|
|
291
|
-
normalIdx =
|
|
291
|
+
normalIdx = pointId * 3;
|
|
292
292
|
}
|
|
293
293
|
packedVBO[vboidx++] = normalData[normalIdx++];
|
|
294
294
|
packedVBO[vboidx++] = normalData[normalIdx++];
|
|
295
295
|
packedVBO[vboidx++] = normalData[normalIdx++];
|
|
296
296
|
}
|
|
297
297
|
model.customData.forEach(attr => {
|
|
298
|
-
custIdx =
|
|
298
|
+
custIdx = pointId * attr.components;
|
|
299
299
|
for (let j = 0; j < attr.components; ++j) {
|
|
300
300
|
packedVBO[vboidx++] = attr.data[custIdx++];
|
|
301
301
|
}
|
|
302
302
|
});
|
|
303
303
|
if (tcoordData !== null) {
|
|
304
|
-
|
|
304
|
+
if (options.useTCoordsPerCell) {
|
|
305
|
+
tcoordIdx = cellId * textureComponents;
|
|
306
|
+
} else {
|
|
307
|
+
tcoordIdx = pointId * textureComponents;
|
|
308
|
+
}
|
|
305
309
|
for (let j = 0; j < textureComponents; ++j) {
|
|
306
310
|
packedVBO[vboidx++] = tcoordData[tcoordIdx++];
|
|
307
311
|
}
|
|
@@ -310,7 +314,7 @@ function vtkOpenGLCellArrayBufferObject(publicAPI, model) {
|
|
|
310
314
|
if (options.haveCellScalars) {
|
|
311
315
|
colorIdx = (cellCount + options.cellOffset) * colorComponents;
|
|
312
316
|
} else {
|
|
313
|
-
colorIdx =
|
|
317
|
+
colorIdx = pointId * colorComponents;
|
|
314
318
|
}
|
|
315
319
|
packedUCVBO[ucidx++] = colorData[colorIdx++];
|
|
316
320
|
packedUCVBO[ucidx++] = colorData[colorIdx++];
|
|
@@ -318,10 +322,11 @@ function vtkOpenGLCellArrayBufferObject(publicAPI, model) {
|
|
|
318
322
|
packedUCVBO[ucidx++] = colorComponents === 4 ? colorData[colorIdx++] : 255;
|
|
319
323
|
}
|
|
320
324
|
};
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
+
|
|
326
|
+
// Browse the cell array: the index is at the beginning of a cell
|
|
327
|
+
// The value of 'array' at the position 'index' is the number of points in the cell
|
|
328
|
+
for (let index = 0; index < size; index += array[index] + 1, cellCount++) {
|
|
329
|
+
func(array[index], array, index + 1, cellCount);
|
|
325
330
|
}
|
|
326
331
|
model.elementCount = caboCount;
|
|
327
332
|
publicAPI.upload(packedVBO, ObjectType.ARRAY_BUFFER);
|
|
@@ -147,7 +147,7 @@ function vtkOpenGLPolyDataMapper(publicAPI, model) {
|
|
|
147
147
|
if (model.lastBoundBO.getCABO().getColorComponents() !== 0 && !model.drawingEdges) {
|
|
148
148
|
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Color::Impl', colorImpl.concat([' diffuseColor = vertexColorVSOutput.rgb;', ' ambientColor = vertexColorVSOutput.rgb;', ' opacity = opacity*vertexColorVSOutput.a;'])).result;
|
|
149
149
|
} else {
|
|
150
|
-
if (model.renderable.getInterpolateScalarsBeforeMapping() && model.renderable.getColorCoordinates() && !model.drawingEdges) {
|
|
150
|
+
if ((model.renderable.getAreScalarsMappedFromCells() || model.renderable.getInterpolateScalarsBeforeMapping()) && model.renderable.getColorCoordinates() && !model.drawingEdges) {
|
|
151
151
|
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::Color::Impl', colorImpl.concat([' vec4 texColor = texture2D(texture1, tcoordVCVSOutput.st);', ' diffuseColor = texColor.rgb;', ' ambientColor = texColor.rgb;', ' opacity = opacity*texColor.a;'])).result;
|
|
152
152
|
} else {
|
|
153
153
|
if (actor.getBackfaceProperty() && !model.drawingEdges) {
|
|
@@ -993,9 +993,12 @@ function vtkOpenGLPolyDataMapper(publicAPI, model) {
|
|
|
993
993
|
tcoords = null;
|
|
994
994
|
}
|
|
995
995
|
|
|
996
|
+
// Flag to check if tcoords are per cell instead of per point
|
|
997
|
+
let useTCoordsPerCell = false;
|
|
996
998
|
// handle color mapping via texture
|
|
997
999
|
if (model.renderable.getColorCoordinates()) {
|
|
998
1000
|
tcoords = model.renderable.getColorCoordinates();
|
|
1001
|
+
useTCoordsPerCell = model.renderable.getAreScalarsMappedFromCells();
|
|
999
1002
|
if (!model.internalColorTexture) {
|
|
1000
1003
|
model.internalColorTexture = vtkOpenGLTexture.newInstance({
|
|
1001
1004
|
resizable: true
|
|
@@ -1028,6 +1031,7 @@ function vtkOpenGLPolyDataMapper(publicAPI, model) {
|
|
|
1028
1031
|
cellOffset: 0,
|
|
1029
1032
|
vertexOffset: 0,
|
|
1030
1033
|
// Used to keep track of vertex ids across primitives for selection
|
|
1034
|
+
useTCoordsPerCell,
|
|
1031
1035
|
haveCellScalars: model.haveCellScalars,
|
|
1032
1036
|
haveCellNormals: model.haveCellNormals,
|
|
1033
1037
|
customAttributes: model.renderable.getCustomShaderAttributes().map(arrayName => poly.getPointData().getArrayByName(arrayName))
|
|
@@ -1085,9 +1089,9 @@ function vtkOpenGLPolyDataMapper(publicAPI, model) {
|
|
|
1085
1089
|
model.renderable.setSelectionWebGLIdsToVTKIds(model.selectionWebGLIdsToVTKIds);
|
|
1086
1090
|
publicAPI.updateMaximumPointCellIds();
|
|
1087
1091
|
}
|
|
1088
|
-
model.VBOBuildTime.modified();
|
|
1089
1092
|
model.VBOBuildString = toString;
|
|
1090
1093
|
}
|
|
1094
|
+
model.VBOBuildTime.modified();
|
|
1091
1095
|
};
|
|
1092
1096
|
publicAPI.getAllocatedGPUMemoryInBytes = () => {
|
|
1093
1097
|
let memUsed = 0;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import vtkAbstractWidget from '../../../Widgets/Core/AbstractWidget';
|
|
2
|
+
import vtkCamera from '../../../Rendering/Core/Camera';
|
|
3
|
+
import vtkInteractiveOrientationWidget from '../InteractiveOrientationWidget';
|
|
4
|
+
import vtkOrientationMarkerWidget from '../../../Interaction/Widgets/OrientationMarkerWidget';
|
|
5
|
+
import vtkRenderer from '../../../Rendering/Core/Renderer';
|
|
6
|
+
import vtkRenderWindowInteractor from '../../../Rendering/Core/RenderWindowInteractor';
|
|
7
|
+
import vtkWidgetManager from '../../../Widgets/Core/WidgetManager';
|
|
8
|
+
import { vtkSubscription } from '../../../interfaces';
|
|
9
|
+
import { Bounds, Vector3 } from '../../../types';
|
|
10
|
+
|
|
11
|
+
export function majorAxis(
|
|
12
|
+
vec3: Vector3,
|
|
13
|
+
idxA: number,
|
|
14
|
+
idxB: number
|
|
15
|
+
): [number, number, number];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create a new vtkOrientationMarkerWidget instance from the provided interactor and parentRenderer and sensible defaults.
|
|
19
|
+
*
|
|
20
|
+
* @param {vtkRenderWindowInteractor} interactor
|
|
21
|
+
* @param {vtkRenderer} parentRenderer
|
|
22
|
+
* @returns {vtkOrientationMarkerWidget}
|
|
23
|
+
*/
|
|
24
|
+
export function createOrientationMarkerWidget(
|
|
25
|
+
interactor: vtkRenderWindowInteractor,
|
|
26
|
+
parentRenderer: vtkRenderer
|
|
27
|
+
): vtkOrientationMarkerWidget;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create a new vtkInteractiveOrientationWidget instance and place it at the given bounds.
|
|
31
|
+
*
|
|
32
|
+
* @param {Bounds} bounds
|
|
33
|
+
* @returns {vtkInteractiveOrientationWidget}
|
|
34
|
+
*/
|
|
35
|
+
export function createInteractiveOrientationWidget(
|
|
36
|
+
bounds: Bounds
|
|
37
|
+
): vtkInteractiveOrientationWidget;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Create a new vtkOrientationMarkerWidget alongside with a new vtkInteractiveOrientationWidget with sensible defaults.
|
|
41
|
+
*
|
|
42
|
+
* @param {vtkWidgetManager} widgetManager
|
|
43
|
+
* @param {vtkRenderWindowInteractor} interactor
|
|
44
|
+
* @param {vtkRenderer} mainRenderer
|
|
45
|
+
* @returns {Object} the constructed widget instances
|
|
46
|
+
*/
|
|
47
|
+
export function createInteractiveOrientationMarkerWidget(
|
|
48
|
+
widgetManager: vtkWidgetManager,
|
|
49
|
+
interactor: vtkRenderWindowInteractor,
|
|
50
|
+
mainRenderer: vtkRenderer
|
|
51
|
+
): {
|
|
52
|
+
interactiveOrientationWidget: vtkInteractiveOrientationWidget;
|
|
53
|
+
orientationMarkerWidget: vtkOrientationMarkerWidget;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Listen to OrientationChange events on the given view widget.
|
|
58
|
+
* The event handler will align the provided camera and update the provided vtkOrientationMarkerWidget instance.
|
|
59
|
+
*
|
|
60
|
+
* @param {vtkAbstractWidget} viewWidget Must be a vtkInteractiveOrientationWidget view widget
|
|
61
|
+
* @param {vtkCamera} camera The camera instance to upate when orientation changes
|
|
62
|
+
* @param {vtkOrientationMarkerWidget} orientationMarkerWidget The instance to update when orientation changes
|
|
63
|
+
* @param {vtkWidgetManager} widgetManager
|
|
64
|
+
* @param {Function} render A callback that should render the view
|
|
65
|
+
* @returns {vtkSubscription} the corresponding event subscription, can be used to unsubscribe from the event
|
|
66
|
+
*/
|
|
67
|
+
export function alignCameraOnViewWidgetOrientationChange(
|
|
68
|
+
viewWidget: vtkAbstractWidget,
|
|
69
|
+
camera: vtkCamera,
|
|
70
|
+
orientationMarkerWidget: vtkOrientationMarkerWidget,
|
|
71
|
+
widgetManager: vtkWidgetManager,
|
|
72
|
+
render: () => void
|
|
73
|
+
): vtkSubscription;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as vtkMath from '@kitware/vtk.js/Common/Core/Math';
|
|
2
|
+
import vtkOrientationMarkerWidget from '@kitware/vtk.js/Interaction/Widgets/OrientationMarkerWidget';
|
|
3
|
+
import vtkAxesActor from '@kitware/vtk.js/Rendering/Core/AxesActor';
|
|
4
|
+
import vtkInteractiveOrientationWidget from '@kitware/vtk.js/Widgets/Widgets3D/InteractiveOrientationWidget';
|
|
5
|
+
|
|
6
|
+
function majorAxis(vec3, idxA, idxB) {
|
|
7
|
+
const axis = [0, 0, 0];
|
|
8
|
+
const idx = Math.abs(vec3[idxA]) > Math.abs(vec3[idxB]) ? idxA : idxB;
|
|
9
|
+
const value = vec3[idx] > 0 ? 1 : -1;
|
|
10
|
+
axis[idx] = value;
|
|
11
|
+
return axis;
|
|
12
|
+
}
|
|
13
|
+
function createOrientationMarkerWidget(interactor, parentRenderer) {
|
|
14
|
+
const axes = vtkAxesActor.newInstance();
|
|
15
|
+
const orientationWidget = vtkOrientationMarkerWidget.newInstance({
|
|
16
|
+
actor: axes,
|
|
17
|
+
interactor,
|
|
18
|
+
interactiveRenderer: true,
|
|
19
|
+
viewportSize: 0.1,
|
|
20
|
+
minPixelSize: 100,
|
|
21
|
+
maxPixelSize: 300,
|
|
22
|
+
parentRenderer
|
|
23
|
+
});
|
|
24
|
+
orientationWidget.setEnabled(true);
|
|
25
|
+
orientationWidget.setViewportCorner(vtkOrientationMarkerWidget.Corners.BOTTOM_LEFT);
|
|
26
|
+
return orientationWidget;
|
|
27
|
+
}
|
|
28
|
+
function createInteractiveOrientationWidget(bounds) {
|
|
29
|
+
const widget = vtkInteractiveOrientationWidget.newInstance();
|
|
30
|
+
widget.placeWidget(bounds);
|
|
31
|
+
widget.setBounds(bounds.map(v => v * 0.45));
|
|
32
|
+
return widget;
|
|
33
|
+
}
|
|
34
|
+
function createInteractiveOrientationMarkerWidget(widgetManager, interactor, mainRenderer) {
|
|
35
|
+
const orientationMarkerWidget = createOrientationMarkerWidget(interactor, mainRenderer);
|
|
36
|
+
interactor.getInteractorStyle().setFocusedRenderer(mainRenderer);
|
|
37
|
+
widgetManager.setRenderer(orientationMarkerWidget.getRenderer());
|
|
38
|
+
const widget = createInteractiveOrientationWidget(orientationMarkerWidget.getActor().getBounds());
|
|
39
|
+
return {
|
|
40
|
+
interactiveOrientationWidget: widget,
|
|
41
|
+
orientationMarkerWidget
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function alignCameraOnViewWidgetOrientationChange(viewWidget, camera, orientationMarkerWidget, widgetManager, render) {
|
|
45
|
+
return viewWidget.onOrientationChange(_ref => {
|
|
46
|
+
let {
|
|
47
|
+
up,
|
|
48
|
+
direction,
|
|
49
|
+
action,
|
|
50
|
+
event
|
|
51
|
+
} = _ref;
|
|
52
|
+
const focalPoint = camera.getFocalPoint();
|
|
53
|
+
const position = camera.getPosition();
|
|
54
|
+
const viewUp = camera.getViewUp();
|
|
55
|
+
const distance = Math.sqrt(vtkMath.distance2BetweenPoints(position, focalPoint));
|
|
56
|
+
camera.setPosition(focalPoint[0] + direction[0] * distance, focalPoint[1] + direction[1] * distance, focalPoint[2] + direction[2] * distance);
|
|
57
|
+
if (direction[0]) {
|
|
58
|
+
camera.setViewUp(majorAxis(viewUp, 1, 2));
|
|
59
|
+
}
|
|
60
|
+
if (direction[1]) {
|
|
61
|
+
camera.setViewUp(majorAxis(viewUp, 0, 2));
|
|
62
|
+
}
|
|
63
|
+
if (direction[2]) {
|
|
64
|
+
camera.setViewUp(majorAxis(viewUp, 0, 1));
|
|
65
|
+
}
|
|
66
|
+
orientationMarkerWidget.updateMarkerOrientation();
|
|
67
|
+
render();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { alignCameraOnViewWidgetOrientationChange, createInteractiveOrientationMarkerWidget, createInteractiveOrientationWidget, createOrientationMarkerWidget, majorAxis };
|
package/index.d.ts
CHANGED
|
@@ -234,6 +234,7 @@
|
|
|
234
234
|
/// <reference path="./Widgets/Manipulators/PlaneManipulator.d.ts" />
|
|
235
235
|
/// <reference path="./Widgets/Manipulators/TrackballManipulator.d.ts" />
|
|
236
236
|
/// <reference path="./Widgets/Representations/WidgetRepresentation.d.ts" />
|
|
237
|
+
/// <reference path="./Widgets/Widgets3D/InteractiveOrientationWidget/helpers.d.ts" />
|
|
237
238
|
/// <reference path="./Widgets/Widgets3D/InteractiveOrientationWidget.d.ts" />
|
|
238
239
|
/// <reference path="./Widgets/Widgets3D/ResliceCursorWidget/Constants.d.ts" />
|
|
239
240
|
/// <reference path="./Widgets/Widgets3D/ResliceCursorWidget/behavior.d.ts" />
|