@kitware/vtk.js 28.13.1 → 29.0.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/BREAKING_CHANGES.md +7 -0
- package/Proxy/Core/ViewProxy.d.ts +2 -1
- package/Rendering/Core/RenderWindow.d.ts +1 -0
- package/Rendering/Misc/FullScreenRenderWindow.d.ts +4 -1
- package/Rendering/Misc/FullScreenRenderWindow.js +2 -1
- package/Rendering/Misc/GenericRenderWindow.d.ts +3 -2
- package/Rendering/Misc/GenericRenderWindow.js +11 -9
- package/Rendering/OpenGL/RenderWindow.d.ts +0 -34
- package/Rendering/OpenGL/RenderWindow.js +2 -177
- package/Rendering/OpenGL/VolumeMapper.js +4 -4
- package/Rendering/WebGPU/RenderWindow.js +12 -0
- package/Rendering/{OpenGL/RenderWindow → WebXR/RenderWindowHelper}/Constants.d.ts +2 -1
- package/Rendering/WebXR/RenderWindowHelper.d.ts +90 -0
- package/Rendering/WebXR/RenderWindowHelper.js +242 -0
- package/Widgets/Core/WidgetManager.d.ts +0 -24
- package/Widgets/Core/WidgetManager.js +5 -29
- package/Widgets/Widgets3D.js +0 -2
- package/index.d.ts +2 -1
- package/package.json +2 -1
- package/Widgets/Widgets3D/DistanceWidget/behavior.js +0 -133
- package/Widgets/Widgets3D/DistanceWidget/state.js +0 -22
- package/Widgets/Widgets3D/DistanceWidget.js +0 -109
- /package/Rendering/{OpenGL/RenderWindow → WebXR/RenderWindowHelper}/Constants.js +0 -0
package/BREAKING_CHANGES.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## From 28.x to 29
|
|
2
|
+
|
|
3
|
+
- **getOpenGLRenderWindow**: `getOpenGLRenderWindow` has been renamed to `getApiSpecificRenderWindow` in `vtkFullScreenRenderWindow`, `vtkGenericRenderWindow` and `vtkViewProxy` to support WebGL and WebGPU backend. ([#2816](https://github.com/Kitware/vtk-js/pull/2816))
|
|
4
|
+
- **WidgetManager**: Deprecated APIs have been fully removed. ([#2910](https://github.com/Kitware/vtk-js/pull/2910))
|
|
5
|
+
- **OpenGLRenderWindow**: WebXR API has been moved into a WebXR RenderWindowHelper. ([#2924](https://github.com/Kitware/vtk-js/pull/2924))
|
|
6
|
+
- **DistanceWidget**: Removed from vtk.js in favor of vtkLineWidget ([#2945](https://github.com/Kitware/vtk-js/pull/2945))
|
|
7
|
+
|
|
1
8
|
## From 27.x to 28
|
|
2
9
|
|
|
3
10
|
- **vtkManipulator.handleEvent**: Change all `handleEvent` signatures of manipulators. Used to be `handleEvent(callData, glRenderWindow): vec3`, it is now `handleEvent(callData, glRenderWindow): { worldCoords: Nullable<vec3>, worldDirection?: mat3 }`.
|
|
@@ -8,6 +8,7 @@ import { vtkSubscription, vtkObject } from './../../interfaces';
|
|
|
8
8
|
import vtkRenderer from './../../Rendering/Core/Renderer';
|
|
9
9
|
import vtkRenderWindow from './../../Rendering/Core/RenderWindow';
|
|
10
10
|
import vtkOpenGLRenderWindow from './../../Rendering/OpenGL/RenderWindow';
|
|
11
|
+
import vtkWebGPURenderWindow from './../../Rendering/WebGPU/RenderWindow';
|
|
11
12
|
import { VtkProxy } from './../../macros';
|
|
12
13
|
|
|
13
14
|
export interface vtkViewProxy extends VtkProxy {
|
|
@@ -66,7 +67,7 @@ export interface vtkViewProxy extends VtkProxy {
|
|
|
66
67
|
getInteractor(): vtkRenderWindowInteractor;
|
|
67
68
|
getInteractorStyle2D(): vtkInteractorStyle;
|
|
68
69
|
getInteractorStyle3D(): vtkInteractorStyle;
|
|
69
|
-
|
|
70
|
+
getApiSpecificRenderWindow(): vtkOpenGLRenderWindow|vtkWebGPURenderWindow;
|
|
70
71
|
getOrientationAxesType(): string;
|
|
71
72
|
getPresetToOrientationAxes(): any;
|
|
72
73
|
getRenderer(): vtkRenderer;
|
|
@@ -148,6 +148,7 @@ export interface vtkRenderWindow extends vtkObject {
|
|
|
148
148
|
* Switch the rendering backend between WebGL and WebGPU.
|
|
149
149
|
* By default, the WebGL backend is used. To switch, to WebGPU call
|
|
150
150
|
* `renderWindow.setDefaultViewAPI('WebGPU')` before calling `render`.
|
|
151
|
+
* Must be called before `newAPISpecificView()` is called.
|
|
151
152
|
* @param defaultViewAPI (default: 'WebGL')
|
|
152
153
|
*/
|
|
153
154
|
setDefaultViewAPI(defaultViewAPI: DEFAULT_VIEW_API): boolean;
|
|
@@ -17,6 +17,7 @@ export interface IFullScreenRenderWindowInitialValues {
|
|
|
17
17
|
containerStyle?: object;
|
|
18
18
|
controlPanelStyle?: object;
|
|
19
19
|
controllerVisibility?: boolean;
|
|
20
|
+
defaultViewAPI?: boolean;
|
|
20
21
|
listenWindowResize?: boolean;
|
|
21
22
|
resizeCallback?: any;
|
|
22
23
|
}
|
|
@@ -42,7 +43,9 @@ export interface vtkFullScreenRenderWindow extends vtkObject {
|
|
|
42
43
|
delete(): void;
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
|
-
*
|
|
46
|
+
* Returns vtkWebGPURenderWindow if ?viewAPI='WebGPU' is in URL, or if
|
|
47
|
+
* vtkFullScreenRenderWindow has been created with "defaultViewAPI: 'WebGPU",
|
|
48
|
+
* otherwise vtkOpenGLRenderWindow is returned.
|
|
46
49
|
*/
|
|
47
50
|
getApiSpecificRenderWindow(): any; // vtkOpenGLRenderWindow || vtkWebGPURenderWindow
|
|
48
51
|
|
|
@@ -72,7 +72,7 @@ function vtkFullScreenRenderWindow(publicAPI, model) {
|
|
|
72
72
|
model.renderWindow.addRenderer(model.renderer);
|
|
73
73
|
|
|
74
74
|
// apiSpecificRenderWindow
|
|
75
|
-
model.apiSpecificRenderWindow = model.renderWindow.newAPISpecificView(userParams.viewAPI);
|
|
75
|
+
model.apiSpecificRenderWindow = model.renderWindow.newAPISpecificView(userParams.viewAPI ?? model.defaultViewAPI);
|
|
76
76
|
model.apiSpecificRenderWindow.setContainer(model.container);
|
|
77
77
|
model.renderWindow.addView(model.apiSpecificRenderWindow);
|
|
78
78
|
|
|
@@ -161,6 +161,7 @@ const DEFAULT_VALUES = {
|
|
|
161
161
|
background: [0.32, 0.34, 0.43],
|
|
162
162
|
containerStyle: null,
|
|
163
163
|
controlPanelStyle: null,
|
|
164
|
+
// defaultViewAPI: undefined,
|
|
164
165
|
listenWindowResize: true,
|
|
165
166
|
resizeCallback: null,
|
|
166
167
|
controllerVisibility: true
|
|
@@ -4,6 +4,7 @@ import vtkRenderer from './../Core/Renderer';
|
|
|
4
4
|
import vtkRenderWindow from './../Core/RenderWindow';
|
|
5
5
|
import vtkRenderWindowInteractor from './../Core/RenderWindowInteractor';
|
|
6
6
|
import vtkOpenGLRenderWindow from './../OpenGL/RenderWindow';
|
|
7
|
+
import vtkWebGPURenderWindow from './../WebGPU/RenderWindow';
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -33,9 +34,9 @@ export interface vtkGenericRenderWindow extends vtkObject {
|
|
|
33
34
|
getInteractor(): vtkRenderWindowInteractor;
|
|
34
35
|
|
|
35
36
|
/**
|
|
36
|
-
*
|
|
37
|
+
* Get the render back-end specific render window.
|
|
37
38
|
*/
|
|
38
|
-
|
|
39
|
+
getApiSpecificRenderWindow(): vtkOpenGLRenderWindow|vtkWebGPURenderWindow;
|
|
39
40
|
|
|
40
41
|
/**
|
|
41
42
|
*
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { m as macro } from '../../macros2.js';
|
|
2
|
-
import vtkRenderWindow$1 from '../OpenGL/RenderWindow.js';
|
|
3
2
|
import vtkRenderer from '../Core/Renderer.js';
|
|
4
3
|
import vtkRenderWindow from '../Core/RenderWindow.js';
|
|
5
4
|
import vtkRenderWindowInteractor from '../Core/RenderWindowInteractor.js';
|
|
6
5
|
import vtkInteractorStyleTrackballCamera from '../../Interaction/Style/InteractorStyleTrackballCamera.js';
|
|
6
|
+
import vtkURLExtract from '../../Common/Core/URLExtract.js';
|
|
7
7
|
import '../../Common/Core/Points.js';
|
|
8
8
|
import '../../Common/Core/DataArray.js';
|
|
9
9
|
import '../../Common/DataModel/PolyData.js';
|
|
10
10
|
import '../Core/Actor.js';
|
|
11
11
|
import '../Core/Mapper.js';
|
|
12
12
|
|
|
13
|
+
// Process arguments from URL
|
|
14
|
+
const userParams = vtkURLExtract.extractURLParameters();
|
|
13
15
|
function vtkGenericRenderWindow(publicAPI, model) {
|
|
14
16
|
// Capture resize trigger method to remove from publicAPI
|
|
15
17
|
const invokeResize = publicAPI.invokeResize;
|
|
@@ -21,13 +23,13 @@ function vtkGenericRenderWindow(publicAPI, model) {
|
|
|
21
23
|
model.renderWindow.addRenderer(model.renderer);
|
|
22
24
|
|
|
23
25
|
// OpenGLRenderWindow
|
|
24
|
-
model.
|
|
25
|
-
model.renderWindow.addView(model.
|
|
26
|
+
model._apiSpecificRenderWindow = model.renderWindow.newAPISpecificView(userParams.viewAPI ?? model.defaultViewAPI);
|
|
27
|
+
model.renderWindow.addView(model._apiSpecificRenderWindow);
|
|
26
28
|
|
|
27
29
|
// Interactor
|
|
28
30
|
model.interactor = vtkRenderWindowInteractor.newInstance();
|
|
29
31
|
model.interactor.setInteractorStyle(vtkInteractorStyleTrackballCamera.newInstance());
|
|
30
|
-
model.interactor.setView(model.
|
|
32
|
+
model.interactor.setView(model._apiSpecificRenderWindow);
|
|
31
33
|
model.interactor.initialize();
|
|
32
34
|
|
|
33
35
|
// Expose background
|
|
@@ -41,7 +43,7 @@ function vtkGenericRenderWindow(publicAPI, model) {
|
|
|
41
43
|
if (model.container) {
|
|
42
44
|
const dims = model.container.getBoundingClientRect();
|
|
43
45
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
44
|
-
model.
|
|
46
|
+
model._apiSpecificRenderWindow.setSize(Math.floor(dims.width * devicePixelRatio), Math.floor(dims.height * devicePixelRatio));
|
|
45
47
|
invokeResize();
|
|
46
48
|
model.renderWindow.render();
|
|
47
49
|
}
|
|
@@ -55,7 +57,7 @@ function vtkGenericRenderWindow(publicAPI, model) {
|
|
|
55
57
|
|
|
56
58
|
// Switch container
|
|
57
59
|
model.container = el;
|
|
58
|
-
model.
|
|
60
|
+
model._apiSpecificRenderWindow.setContainer(model.container);
|
|
59
61
|
|
|
60
62
|
// Bind to new container
|
|
61
63
|
if (model.container) {
|
|
@@ -64,7 +66,7 @@ function vtkGenericRenderWindow(publicAPI, model) {
|
|
|
64
66
|
};
|
|
65
67
|
|
|
66
68
|
// Properly release GL context
|
|
67
|
-
publicAPI.delete = macro.chain(publicAPI.setContainer, model.
|
|
69
|
+
publicAPI.delete = macro.chain(publicAPI.setContainer, model._apiSpecificRenderWindow.delete, publicAPI.delete);
|
|
68
70
|
|
|
69
71
|
// Handle size
|
|
70
72
|
if (model.listenWindowResize) {
|
|
@@ -91,8 +93,8 @@ function extend(publicAPI, model) {
|
|
|
91
93
|
|
|
92
94
|
// Object methods
|
|
93
95
|
macro.obj(publicAPI, model);
|
|
94
|
-
macro.get(publicAPI, model, ['renderWindow', 'renderer', '
|
|
95
|
-
macro.moveToProtected(publicAPI, model, ['
|
|
96
|
+
macro.get(publicAPI, model, ['renderWindow', 'renderer', '_apiSpecificRenderWindow', 'interactor', 'container']);
|
|
97
|
+
macro.moveToProtected(publicAPI, model, ['_apiSpecificRenderWindow']);
|
|
96
98
|
macro.event(publicAPI, model, 'resize');
|
|
97
99
|
|
|
98
100
|
// Object specific methods
|
|
@@ -29,10 +29,6 @@ export interface IOpenGLRenderWindowInitialValues {
|
|
|
29
29
|
webgl2?: boolean;
|
|
30
30
|
defaultToWebgl2?: boolean;
|
|
31
31
|
activeFramebuffer?: any;
|
|
32
|
-
xrSession?: any;
|
|
33
|
-
xrSessionIsAR?: boolean;
|
|
34
|
-
xrReferenceSpace?: any;
|
|
35
|
-
xrSupported?: boolean;
|
|
36
32
|
imageFormat?: 'image/png';
|
|
37
33
|
useOffScreen?: boolean;
|
|
38
34
|
useBackgroundImage?: boolean;
|
|
@@ -236,36 +232,6 @@ export interface vtkOpenGLRenderWindow extends vtkOpenGLRenderWindowBase {
|
|
|
236
232
|
*/
|
|
237
233
|
get3DContext(options: I3DContextOptions): Nullable<WebGLRenderingContext>;
|
|
238
234
|
|
|
239
|
-
/**
|
|
240
|
-
* Request an XR session on the user device with WebXR,
|
|
241
|
-
* typically in response to a user request such as a button press.
|
|
242
|
-
*/
|
|
243
|
-
startXR(): void;
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* When an XR session is available, set up the XRWebGLLayer
|
|
247
|
-
* and request the first animation frame for the device
|
|
248
|
-
*/
|
|
249
|
-
enterXR(): void,
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Adjust world-to-physical parameters for different viewing modalities
|
|
253
|
-
*
|
|
254
|
-
* @param {Number} inputRescaleFactor
|
|
255
|
-
* @param {Number} inputTranslateZ
|
|
256
|
-
*/
|
|
257
|
-
resetXRScene(inputRescaleFactor: number, inputTranslateZ: number): void,
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Request to stop the current XR session
|
|
261
|
-
*/
|
|
262
|
-
stopXR(): void;
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
*
|
|
266
|
-
*/
|
|
267
|
-
xrRender(): void;
|
|
268
|
-
|
|
269
235
|
/**
|
|
270
236
|
*
|
|
271
237
|
*/
|
|
@@ -8,16 +8,12 @@ import vtkTextureUnitManager from './TextureUnitManager.js';
|
|
|
8
8
|
import vtkViewNodeFactory from './ViewNodeFactory.js';
|
|
9
9
|
import vtkRenderPass from '../SceneGraph/RenderPass.js';
|
|
10
10
|
import vtkRenderWindowViewNode from '../SceneGraph/RenderWindowViewNode.js';
|
|
11
|
-
import
|
|
12
|
-
import { createContextProxyHandler, GET_UNDERLYING_CONTEXT } from './RenderWindow/ContextProxy.js';
|
|
11
|
+
import { createContextProxyHandler } from './RenderWindow/ContextProxy.js';
|
|
13
12
|
|
|
14
13
|
const {
|
|
15
14
|
vtkDebugMacro,
|
|
16
15
|
vtkErrorMacro
|
|
17
16
|
} = macro;
|
|
18
|
-
const {
|
|
19
|
-
XrSessionTypes
|
|
20
|
-
} = Constants;
|
|
21
17
|
const SCREENSHOT_PLACEHOLDER = {
|
|
22
18
|
position: 'absolute',
|
|
23
19
|
top: 0,
|
|
@@ -25,12 +21,6 @@ const SCREENSHOT_PLACEHOLDER = {
|
|
|
25
21
|
width: '100%',
|
|
26
22
|
height: '100%'
|
|
27
23
|
};
|
|
28
|
-
const DEFAULT_RESET_FACTORS = {
|
|
29
|
-
rescaleFactor: 0.25,
|
|
30
|
-
// isotropic scale factor reduces apparent size of objects
|
|
31
|
-
translateZ: -1.5 // default translation initializes object in front of camera
|
|
32
|
-
};
|
|
33
|
-
|
|
34
24
|
function checkRenderTargetSupport(gl, format, type) {
|
|
35
25
|
// create temporary frame buffer and texture
|
|
36
26
|
const framebuffer = gl.createFramebuffer();
|
|
@@ -227,168 +217,6 @@ function vtkOpenGLRenderWindow(publicAPI, model) {
|
|
|
227
217
|
}
|
|
228
218
|
return new Proxy(result, cachingContextHandler);
|
|
229
219
|
};
|
|
230
|
-
|
|
231
|
-
// Request an XR session on the user device with WebXR,
|
|
232
|
-
// typically in response to a user request such as a button press
|
|
233
|
-
publicAPI.startXR = xrSessionType => {
|
|
234
|
-
if (navigator.xr === undefined) {
|
|
235
|
-
throw new Error('WebXR is not available');
|
|
236
|
-
}
|
|
237
|
-
model.xrSessionType = xrSessionType !== undefined ? xrSessionType : XrSessionTypes.HmdVR;
|
|
238
|
-
const isXrSessionAR = [XrSessionTypes.HmdAR, XrSessionTypes.MobileAR].includes(model.xrSessionType);
|
|
239
|
-
const sessionType = isXrSessionAR ? 'immersive-ar' : 'immersive-vr';
|
|
240
|
-
if (!navigator.xr.isSessionSupported(sessionType)) {
|
|
241
|
-
if (isXrSessionAR) {
|
|
242
|
-
throw new Error('Device does not support AR session');
|
|
243
|
-
} else {
|
|
244
|
-
throw new Error('VR display is not available');
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
if (model.xrSession === null) {
|
|
248
|
-
navigator.xr.requestSession(sessionType).then(publicAPI.enterXR, () => {
|
|
249
|
-
throw new Error('Failed to create XR session!');
|
|
250
|
-
});
|
|
251
|
-
} else {
|
|
252
|
-
throw new Error('XR Session already exists!');
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
// When an XR session is available, set up the XRWebGLLayer
|
|
257
|
-
// and request the first animation frame for the device
|
|
258
|
-
publicAPI.enterXR = async xrSession => {
|
|
259
|
-
model.xrSession = xrSession;
|
|
260
|
-
model.oldCanvasSize = model.size.slice();
|
|
261
|
-
if (model.xrSession !== null) {
|
|
262
|
-
const gl = publicAPI.get3DContext();
|
|
263
|
-
await gl.makeXRCompatible();
|
|
264
|
-
const glLayer = new global.XRWebGLLayer(model.xrSession,
|
|
265
|
-
// constructor needs unproxied context
|
|
266
|
-
gl[GET_UNDERLYING_CONTEXT]());
|
|
267
|
-
publicAPI.setSize(glLayer.framebufferWidth, glLayer.framebufferHeight);
|
|
268
|
-
model.xrSession.updateRenderState({
|
|
269
|
-
baseLayer: glLayer
|
|
270
|
-
});
|
|
271
|
-
model.xrSession.requestReferenceSpace('local').then(refSpace => {
|
|
272
|
-
model.xrReferenceSpace = refSpace;
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// Initialize transparent background for augmented reality session
|
|
276
|
-
const isXrSessionAR = [XrSessionTypes.HmdAR, XrSessionTypes.MobileAR].includes(model.xrSessionType);
|
|
277
|
-
if (isXrSessionAR) {
|
|
278
|
-
const ren = model.renderable.getRenderers()[0];
|
|
279
|
-
model.preXrSessionBackground = ren.getBackground();
|
|
280
|
-
ren.setBackground([0, 0, 0, 0]);
|
|
281
|
-
}
|
|
282
|
-
publicAPI.resetXRScene();
|
|
283
|
-
model.renderable.getInteractor().switchToXRAnimation();
|
|
284
|
-
model.xrSceneFrame = model.xrSession.requestAnimationFrame(publicAPI.xrRender);
|
|
285
|
-
} else {
|
|
286
|
-
throw new Error('Failed to enter XR with a null xrSession.');
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
publicAPI.resetXRScene = function () {
|
|
290
|
-
let rescaleFactor = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_RESET_FACTORS.rescaleFactor;
|
|
291
|
-
let translateZ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_RESET_FACTORS.translateZ;
|
|
292
|
-
// Adjust world-to-physical parameters for different modalities
|
|
293
|
-
|
|
294
|
-
const ren = model.renderable.getRenderers()[0];
|
|
295
|
-
ren.resetCamera();
|
|
296
|
-
const camera = ren.getActiveCamera();
|
|
297
|
-
let physicalScale = camera.getPhysicalScale();
|
|
298
|
-
const physicalTranslation = camera.getPhysicalTranslation();
|
|
299
|
-
const rescaledTranslateZ = translateZ * physicalScale;
|
|
300
|
-
physicalScale /= rescaleFactor;
|
|
301
|
-
physicalTranslation[2] += rescaledTranslateZ;
|
|
302
|
-
camera.setPhysicalScale(physicalScale);
|
|
303
|
-
camera.setPhysicalTranslation(physicalTranslation);
|
|
304
|
-
// Clip at 0.1m, 100.0m in physical space by default
|
|
305
|
-
camera.setClippingRange(0.1 * physicalScale, 100.0 * physicalScale);
|
|
306
|
-
};
|
|
307
|
-
publicAPI.stopXR = async () => {
|
|
308
|
-
if (navigator.xr === undefined) {
|
|
309
|
-
// WebXR polyfill not available so nothing to do
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
if (model.xrSession !== null) {
|
|
313
|
-
model.xrSession.cancelAnimationFrame(model.xrSceneFrame);
|
|
314
|
-
model.renderable.getInteractor().returnFromXRAnimation();
|
|
315
|
-
const gl = publicAPI.get3DContext();
|
|
316
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
317
|
-
await model.xrSession.end().catch(error => {
|
|
318
|
-
if (!(error instanceof DOMException)) {
|
|
319
|
-
throw error;
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
model.xrSession = null;
|
|
323
|
-
}
|
|
324
|
-
if (model.oldCanvasSize !== undefined) {
|
|
325
|
-
publicAPI.setSize(...model.oldCanvasSize);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Reset to default canvas
|
|
329
|
-
const ren = model.renderable.getRenderers()[0];
|
|
330
|
-
if (model.preXrSessionBackground != null) {
|
|
331
|
-
ren.setBackground(model.preXrSessionBackground);
|
|
332
|
-
model.preXrSessionBackground = null;
|
|
333
|
-
}
|
|
334
|
-
ren.getActiveCamera().setProjectionMatrix(null);
|
|
335
|
-
ren.resetCamera();
|
|
336
|
-
ren.setViewport(0.0, 0, 1.0, 1.0);
|
|
337
|
-
publicAPI.traverseAllPasses();
|
|
338
|
-
};
|
|
339
|
-
publicAPI.xrRender = async (t, frame) => {
|
|
340
|
-
const xrSession = frame.session;
|
|
341
|
-
const isXrSessionHMD = [XrSessionTypes.HmdVR, XrSessionTypes.HmdAR].includes(model.xrSessionType);
|
|
342
|
-
model.renderable.getInteractor().updateXRGamepads(xrSession, frame, model.xrReferenceSpace);
|
|
343
|
-
model.xrSceneFrame = model.xrSession.requestAnimationFrame(publicAPI.xrRender);
|
|
344
|
-
const xrPose = frame.getViewerPose(model.xrReferenceSpace);
|
|
345
|
-
if (xrPose) {
|
|
346
|
-
const gl = publicAPI.get3DContext();
|
|
347
|
-
if (model.xrSessionType === XrSessionTypes.MobileAR && model.oldCanvasSize !== undefined) {
|
|
348
|
-
gl.canvas.width = model.oldCanvasSize[0];
|
|
349
|
-
gl.canvas.height = model.oldCanvasSize[1];
|
|
350
|
-
}
|
|
351
|
-
const glLayer = xrSession.renderState.baseLayer;
|
|
352
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
|
|
353
|
-
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
354
|
-
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
355
|
-
publicAPI.setSize(glLayer.framebufferWidth, glLayer.framebufferHeight);
|
|
356
|
-
|
|
357
|
-
// get the first renderer
|
|
358
|
-
const ren = model.renderable.getRenderers()[0];
|
|
359
|
-
|
|
360
|
-
// Do a render pass for each eye
|
|
361
|
-
xrPose.views.forEach((view, index) => {
|
|
362
|
-
const viewport = glLayer.getViewport(view);
|
|
363
|
-
if (isXrSessionHMD) {
|
|
364
|
-
if (view.eye === 'left') {
|
|
365
|
-
ren.setViewport(0, 0, 0.5, 1.0);
|
|
366
|
-
} else if (view.eye === 'right') {
|
|
367
|
-
ren.setViewport(0.5, 0, 1.0, 1.0);
|
|
368
|
-
} else {
|
|
369
|
-
// No handling for non-eye viewport
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
} else if (model.xrSessionType === XrSessionTypes.LookingGlassVR) {
|
|
373
|
-
const startX = viewport.x / glLayer.framebufferWidth;
|
|
374
|
-
const startY = viewport.y / glLayer.framebufferHeight;
|
|
375
|
-
const endX = (viewport.x + viewport.width) / glLayer.framebufferWidth;
|
|
376
|
-
const endY = (viewport.y + viewport.height) / glLayer.framebufferHeight;
|
|
377
|
-
ren.setViewport(startX, startY, endX, endY);
|
|
378
|
-
} else {
|
|
379
|
-
ren.setViewport(0, 0, 1, 1);
|
|
380
|
-
}
|
|
381
|
-
ren.getActiveCamera().computeViewParametersFromPhysicalMatrix(view.transform.inverse.matrix);
|
|
382
|
-
ren.getActiveCamera().setProjectionMatrix(view.projectionMatrix);
|
|
383
|
-
publicAPI.traverseAllPasses();
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// Reset scissorbox before any subsequent rendering to external displays
|
|
387
|
-
// on frame end, such as rendering to a Looking Glass display.
|
|
388
|
-
gl.scissor(0, 0, glLayer.framebufferWidth, glLayer.framebufferHeight);
|
|
389
|
-
gl.disable(gl.SCISSOR_TEST);
|
|
390
|
-
}
|
|
391
|
-
};
|
|
392
220
|
publicAPI.restoreContext = () => {
|
|
393
221
|
const rp = vtkRenderPass.newInstance();
|
|
394
222
|
rp.setCurrentOperation('Release');
|
|
@@ -855,9 +683,6 @@ const DEFAULT_VALUES = {
|
|
|
855
683
|
defaultToWebgl2: true,
|
|
856
684
|
// attempt webgl2 on by default
|
|
857
685
|
activeFramebuffer: null,
|
|
858
|
-
xrSession: null,
|
|
859
|
-
xrReferenceSpace: null,
|
|
860
|
-
xrSupported: true,
|
|
861
686
|
imageFormat: 'image/png',
|
|
862
687
|
useOffScreen: false,
|
|
863
688
|
useBackgroundImage: false
|
|
@@ -906,7 +731,7 @@ function extend(publicAPI, model) {
|
|
|
906
731
|
macro.event(publicAPI, model, 'imageReady');
|
|
907
732
|
|
|
908
733
|
// Build VTK API
|
|
909
|
-
macro.get(publicAPI, model, ['shaderCache', 'textureUnitManager', 'webgl2', '
|
|
734
|
+
macro.get(publicAPI, model, ['shaderCache', 'textureUnitManager', 'webgl2', 'useBackgroundImage', 'activeFramebuffer']);
|
|
910
735
|
macro.setGet(publicAPI, model, ['initialized', 'context', 'canvas', 'renderPasses', 'notifyStartCaptureImage', 'defaultToWebgl2', 'cursor', 'useOffScreen']);
|
|
911
736
|
macro.setGetArray(publicAPI, model, ['size'], 2);
|
|
912
737
|
macro.event(publicAPI, model, 'windowResizeEvent');
|
|
@@ -175,8 +175,8 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
|
|
|
175
175
|
|
|
176
176
|
// if we have a ztexture then declare it and use it
|
|
177
177
|
if (model.zBufferTexture !== null) {
|
|
178
|
-
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Dec', ['uniform sampler2D zBufferTexture;', 'uniform float
|
|
179
|
-
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Impl', ['vec4 depthVec = texture2D(zBufferTexture, vec2(gl_FragCoord.x /
|
|
178
|
+
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Dec', ['uniform sampler2D zBufferTexture;', 'uniform float vpZWidth;', 'uniform float vpZHeight;']).result;
|
|
179
|
+
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Impl', ['vec4 depthVec = texture2D(zBufferTexture, vec2(gl_FragCoord.x / vpZWidth, gl_FragCoord.y/vpZHeight));', 'float zdepth = (depthVec.r*256.0 + depthVec.g)/257.0;', 'zdepth = zdepth * 2.0 - 1.0;', 'if (cameraParallel == 0) {', 'zdepth = -2.0 * camFar * camNear / (zdepth*(camFar-camNear)-(camFar+camNear)) - camNear;}', 'else {', 'zdepth = (zdepth + 1.0) * 0.5 * (camFar - camNear);}\n', 'zdepth = -zdepth/rayDir.z;', 'dists.y = min(zdepth,dists.y);']).result;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
// Set the BlendMode approach
|
|
@@ -362,8 +362,8 @@ function vtkOpenGLVolumeMapper(publicAPI, model) {
|
|
|
362
362
|
if (model.zBufferTexture !== null) {
|
|
363
363
|
program.setUniformi('zBufferTexture', model.zBufferTexture.getTextureUnit());
|
|
364
364
|
const size = model._useSmallViewport ? [model._smallViewportWidth, model._smallViewportHeight] : model._openGLRenderWindow.getFramebufferSize();
|
|
365
|
-
program.setUniformf('
|
|
366
|
-
program.setUniformf('
|
|
365
|
+
program.setUniformf('vpZWidth', size[0]);
|
|
366
|
+
program.setUniformf('vpZHeight', size[1]);
|
|
367
367
|
}
|
|
368
368
|
};
|
|
369
369
|
publicAPI.setCameraShaderParameters = (cellBO, ren, actor) => {
|
|
@@ -490,6 +490,17 @@ function vtkWebGPURenderWindow(publicAPI, model) {
|
|
|
490
490
|
ret.setWebGPURenderWindow(publicAPI);
|
|
491
491
|
return ret;
|
|
492
492
|
};
|
|
493
|
+
const superSetSize = publicAPI.setSize;
|
|
494
|
+
publicAPI.setSize = (width, height) => {
|
|
495
|
+
const modified = superSetSize(width, height);
|
|
496
|
+
if (modified) {
|
|
497
|
+
publicAPI.invokeWindowResizeEvent({
|
|
498
|
+
width,
|
|
499
|
+
height
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
return modified;
|
|
503
|
+
};
|
|
493
504
|
publicAPI.delete = macro.chain(publicAPI.delete, publicAPI.setViewStream);
|
|
494
505
|
}
|
|
495
506
|
|
|
@@ -555,6 +566,7 @@ function extend(publicAPI, model) {
|
|
|
555
566
|
macro.get(publicAPI, model, ['commandEncoder', 'device', 'presentationFormat', 'useBackgroundImage', 'xrSupported']);
|
|
556
567
|
macro.setGet(publicAPI, model, ['initialized', 'context', 'canvas', 'device', 'renderPasses', 'notifyStartCaptureImage', 'cursor', 'useOffScreen']);
|
|
557
568
|
macro.setGetArray(publicAPI, model, ['size'], 2);
|
|
569
|
+
macro.event(publicAPI, model, 'windowResizeEvent');
|
|
558
570
|
|
|
559
571
|
// Object methods
|
|
560
572
|
vtkWebGPURenderWindow(publicAPI, model);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { vtkObject } from './../../interfaces';
|
|
2
|
+
import { Nullable } from './../../types';
|
|
3
|
+
import vtkOpenGLRenderWindow from './../OpenGL/RenderWindow';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
export interface IWebXRRenderWindowHelperInitialValues {
|
|
9
|
+
initialized: boolean,
|
|
10
|
+
initCanvasSize?: [number, number],
|
|
11
|
+
initBackground?: [number, number, number, number],
|
|
12
|
+
renderWindow?: Nullable<vtkOpenGLRenderWindow>,
|
|
13
|
+
xrSession?: Nullable<XRSession>,
|
|
14
|
+
xrSessionType: number,
|
|
15
|
+
xrReferenceSpace?: any,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface vtkWebXRRenderWindowHelper extends vtkObject {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Initialize the instance.
|
|
22
|
+
*/
|
|
23
|
+
initialize(): void;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Request an XR session on the user device with WebXR,
|
|
27
|
+
* typically in response to a user request such as a button press.
|
|
28
|
+
*/
|
|
29
|
+
startXR(xrSessionType: Number): void;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* When an XR session is available, set up the XRWebGLLayer
|
|
33
|
+
* and request the first animation frame for the device
|
|
34
|
+
*/
|
|
35
|
+
enterXR(): void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Adjust world-to-physical parameters for different viewing modalities
|
|
39
|
+
*
|
|
40
|
+
* @param {Number} inputRescaleFactor
|
|
41
|
+
* @param {Number} inputTranslateZ
|
|
42
|
+
*/
|
|
43
|
+
resetXRScene(inputRescaleFactor: number, inputTranslateZ: number): void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Request to stop the current XR session
|
|
47
|
+
*/
|
|
48
|
+
stopXR(): void;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get the underlying render window to drive XR rendering.
|
|
52
|
+
*/
|
|
53
|
+
getRenderWindow(): Nullable<vtkOpenGLRenderWindow>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Set the underlying render window to drive XR rendering.
|
|
57
|
+
*/
|
|
58
|
+
setRenderWindow(renderWindow:Nullable<vtkOpenGLRenderWindow>);
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get the active WebXR session.
|
|
62
|
+
*/
|
|
63
|
+
getXrSession(): Nullable<XRSession>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Method used to decorate a given object (publicAPI+model) with vtkWebXRRenderWindowHelper characteristics.
|
|
68
|
+
*
|
|
69
|
+
* @param publicAPI object on which methods will be bounds (public)
|
|
70
|
+
* @param model object on which data structure will be bounds (protected)
|
|
71
|
+
* @param {IWebXRRenderWindowHelperInitialValues} [initialValues] (default: {})
|
|
72
|
+
*/
|
|
73
|
+
export function extend(publicAPI: object, model: object, initialValues?: IWebXRRenderWindowHelperInitialValues): void;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Method used to create a new instance of vtkWebXRRenderWindowHelper.
|
|
77
|
+
* @param {IWebXRRenderWindowHelperInitialValues} [initialValues] for pre-setting some of its content
|
|
78
|
+
*/
|
|
79
|
+
export function newInstance(initialValues?: IWebXRRenderWindowHelperInitialValues): vtkWebXRRenderWindowHelper;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* WebXR rendering helper
|
|
83
|
+
*
|
|
84
|
+
* vtkWebXRRenderWindowHelper is designed to wrap a vtkRenderWindow for XR rendering.
|
|
85
|
+
*/
|
|
86
|
+
export declare const vtkWebXRRenderWindowHelper: {
|
|
87
|
+
newInstance: typeof newInstance,
|
|
88
|
+
extend: typeof extend,
|
|
89
|
+
};
|
|
90
|
+
export default vtkWebXRRenderWindowHelper;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { m as macro } from '../../macros2.js';
|
|
2
|
+
import Constants from './RenderWindowHelper/Constants.js';
|
|
3
|
+
import { GET_UNDERLYING_CONTEXT } from '../OpenGL/RenderWindow/ContextProxy.js';
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
XrSessionTypes
|
|
7
|
+
} = Constants;
|
|
8
|
+
const DEFAULT_RESET_FACTORS = {
|
|
9
|
+
rescaleFactor: 0.25,
|
|
10
|
+
// isotropic scale factor reduces apparent size of objects
|
|
11
|
+
translateZ: -1.5 // default translation initializes object in front of camera
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// ----------------------------------------------------------------------------
|
|
15
|
+
// vtkWebXRRenderWindowHelper methods
|
|
16
|
+
// ----------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
function vtkWebXRRenderWindowHelper(publicAPI, model) {
|
|
19
|
+
// Set our className
|
|
20
|
+
model.classHierarchy.push('vtkWebXRRenderWindowHelper');
|
|
21
|
+
publicAPI.initialize = renderWindow => {
|
|
22
|
+
if (!model.initialized) {
|
|
23
|
+
model.renderWindow = renderWindow;
|
|
24
|
+
model.initialized = true;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
publicAPI.getXrSupported = () => navigator.xr !== undefined;
|
|
28
|
+
|
|
29
|
+
// Request an XR session on the user device with WebXR,
|
|
30
|
+
// typically in response to a user request such as a button press
|
|
31
|
+
publicAPI.startXR = xrSessionType => {
|
|
32
|
+
if (navigator.xr === undefined) {
|
|
33
|
+
throw new Error('WebXR is not available');
|
|
34
|
+
}
|
|
35
|
+
model.xrSessionType = xrSessionType !== undefined ? xrSessionType : XrSessionTypes.HmdVR;
|
|
36
|
+
const isXrSessionAR = [XrSessionTypes.HmdAR, XrSessionTypes.MobileAR].includes(model.xrSessionType);
|
|
37
|
+
const sessionType = isXrSessionAR ? 'immersive-ar' : 'immersive-vr';
|
|
38
|
+
if (!navigator.xr.isSessionSupported(sessionType)) {
|
|
39
|
+
if (isXrSessionAR) {
|
|
40
|
+
throw new Error('Device does not support AR session');
|
|
41
|
+
} else {
|
|
42
|
+
throw new Error('VR display is not available');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (model.xrSession === null) {
|
|
46
|
+
navigator.xr.requestSession(sessionType).then(publicAPI.enterXR, () => {
|
|
47
|
+
throw new Error('Failed to create XR session!');
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
throw new Error('XR Session already exists!');
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// When an XR session is available, set up the XRWebGLLayer
|
|
55
|
+
// and request the first animation frame for the device
|
|
56
|
+
publicAPI.enterXR = async xrSession => {
|
|
57
|
+
model.xrSession = xrSession;
|
|
58
|
+
model.initCanvasSize = model.renderWindow.getSize();
|
|
59
|
+
if (model.xrSession !== null) {
|
|
60
|
+
const gl = model.renderWindow.get3DContext();
|
|
61
|
+
await gl.makeXRCompatible();
|
|
62
|
+
|
|
63
|
+
// XRWebGLLayer definition is deferred to here to give any WebXR polyfill
|
|
64
|
+
// an opportunity to override this definition.
|
|
65
|
+
const {
|
|
66
|
+
XRWebGLLayer
|
|
67
|
+
} = window;
|
|
68
|
+
const glLayer = new XRWebGLLayer(model.xrSession,
|
|
69
|
+
// constructor needs unproxied context
|
|
70
|
+
gl[GET_UNDERLYING_CONTEXT]());
|
|
71
|
+
model.renderWindow.setSize(glLayer.framebufferWidth, glLayer.framebufferHeight);
|
|
72
|
+
model.xrSession.updateRenderState({
|
|
73
|
+
baseLayer: glLayer
|
|
74
|
+
});
|
|
75
|
+
model.xrSession.requestReferenceSpace('local').then(refSpace => {
|
|
76
|
+
model.xrReferenceSpace = refSpace;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Initialize transparent background for augmented reality session
|
|
80
|
+
const isXrSessionAR = [XrSessionTypes.HmdAR, XrSessionTypes.MobileAR].includes(model.xrSessionType);
|
|
81
|
+
if (isXrSessionAR) {
|
|
82
|
+
const ren = model.renderWindow.getRenderable().getRenderers()[0];
|
|
83
|
+
model.initBackground = ren.getBackground();
|
|
84
|
+
ren.setBackground([0, 0, 0, 0]);
|
|
85
|
+
}
|
|
86
|
+
publicAPI.resetXRScene();
|
|
87
|
+
model.renderWindow.getRenderable().getInteractor().switchToXRAnimation();
|
|
88
|
+
model.xrSceneFrame = model.xrSession.requestAnimationFrame(model.xrRender);
|
|
89
|
+
publicAPI.modified();
|
|
90
|
+
} else {
|
|
91
|
+
throw new Error('Failed to enter XR with a null xrSession.');
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
publicAPI.resetXRScene = function () {
|
|
95
|
+
let rescaleFactor = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_RESET_FACTORS.rescaleFactor;
|
|
96
|
+
let translateZ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_RESET_FACTORS.translateZ;
|
|
97
|
+
// Adjust world-to-physical parameters for different modalities
|
|
98
|
+
|
|
99
|
+
const ren = model.renderWindow.getRenderable().getRenderers()[0];
|
|
100
|
+
ren.resetCamera();
|
|
101
|
+
const camera = ren.getActiveCamera();
|
|
102
|
+
let physicalScale = camera.getPhysicalScale();
|
|
103
|
+
const physicalTranslation = camera.getPhysicalTranslation();
|
|
104
|
+
const rescaledTranslateZ = translateZ * physicalScale;
|
|
105
|
+
physicalScale /= rescaleFactor;
|
|
106
|
+
physicalTranslation[2] += rescaledTranslateZ;
|
|
107
|
+
camera.setPhysicalScale(physicalScale);
|
|
108
|
+
camera.setPhysicalTranslation(physicalTranslation);
|
|
109
|
+
// Clip at 0.1m, 100.0m in physical space by default
|
|
110
|
+
camera.setClippingRange(0.1 * physicalScale, 100.0 * physicalScale);
|
|
111
|
+
};
|
|
112
|
+
publicAPI.stopXR = async () => {
|
|
113
|
+
if (navigator.xr === undefined) {
|
|
114
|
+
// WebXR polyfill not available so nothing to do
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (model.xrSession !== null) {
|
|
118
|
+
model.xrSession.cancelAnimationFrame(model.xrSceneFrame);
|
|
119
|
+
model.renderWindow.getRenderable().getInteractor().returnFromXRAnimation();
|
|
120
|
+
const gl = model.renderWindow.get3DContext();
|
|
121
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
122
|
+
await model.xrSession.end().catch(error => {
|
|
123
|
+
if (!(error instanceof DOMException)) {
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
model.xrSession = null;
|
|
128
|
+
}
|
|
129
|
+
if (model.initCanvasSize !== null) {
|
|
130
|
+
model.renderWindow.setSize(...model.initCanvasSize);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Reset to default canvas
|
|
134
|
+
const ren = model.renderWindow.getRenderable().getRenderers()[0];
|
|
135
|
+
if (model.initBackground != null) {
|
|
136
|
+
ren.setBackground(model.initBackground);
|
|
137
|
+
model.initBackground = null;
|
|
138
|
+
}
|
|
139
|
+
ren.getActiveCamera().setProjectionMatrix(null);
|
|
140
|
+
ren.resetCamera();
|
|
141
|
+
ren.setViewport(0.0, 0, 1.0, 1.0);
|
|
142
|
+
model.renderWindow.traverseAllPasses();
|
|
143
|
+
publicAPI.modified();
|
|
144
|
+
};
|
|
145
|
+
model.xrRender = async (t, frame) => {
|
|
146
|
+
const xrSession = frame.session;
|
|
147
|
+
const isXrSessionHMD = [XrSessionTypes.HmdVR, XrSessionTypes.HmdAR].includes(model.xrSessionType);
|
|
148
|
+
model.renderWindow.getRenderable().getInteractor().updateXRGamepads(xrSession, frame, model.xrReferenceSpace);
|
|
149
|
+
model.xrSceneFrame = model.xrSession.requestAnimationFrame(model.xrRender);
|
|
150
|
+
const xrPose = frame.getViewerPose(model.xrReferenceSpace);
|
|
151
|
+
if (xrPose) {
|
|
152
|
+
const gl = model.renderWindow.get3DContext();
|
|
153
|
+
if (model.xrSessionType === XrSessionTypes.MobileAR && model.initCanvasSize !== null) {
|
|
154
|
+
gl.canvas.width = model.initCanvasSize[0];
|
|
155
|
+
gl.canvas.height = model.initCanvasSize[1];
|
|
156
|
+
}
|
|
157
|
+
const glLayer = xrSession.renderState.baseLayer;
|
|
158
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
|
|
159
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
160
|
+
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
161
|
+
model.renderWindow.setSize(glLayer.framebufferWidth, glLayer.framebufferHeight);
|
|
162
|
+
|
|
163
|
+
// get the first renderer
|
|
164
|
+
const ren = model.renderWindow.getRenderable().getRenderers()[0];
|
|
165
|
+
|
|
166
|
+
// Do a render pass for each eye
|
|
167
|
+
xrPose.views.forEach((view, index) => {
|
|
168
|
+
const viewport = glLayer.getViewport(view);
|
|
169
|
+
if (isXrSessionHMD) {
|
|
170
|
+
if (view.eye === 'left') {
|
|
171
|
+
ren.setViewport(0, 0, 0.5, 1.0);
|
|
172
|
+
} else if (view.eye === 'right') {
|
|
173
|
+
ren.setViewport(0.5, 0, 1.0, 1.0);
|
|
174
|
+
} else {
|
|
175
|
+
// No handling for non-eye viewport
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
} else if (model.xrSessionType === XrSessionTypes.LookingGlassVR) {
|
|
179
|
+
const startX = viewport.x / glLayer.framebufferWidth;
|
|
180
|
+
const startY = viewport.y / glLayer.framebufferHeight;
|
|
181
|
+
const endX = (viewport.x + viewport.width) / glLayer.framebufferWidth;
|
|
182
|
+
const endY = (viewport.y + viewport.height) / glLayer.framebufferHeight;
|
|
183
|
+
ren.setViewport(startX, startY, endX, endY);
|
|
184
|
+
} else {
|
|
185
|
+
ren.setViewport(0, 0, 1, 1);
|
|
186
|
+
}
|
|
187
|
+
ren.getActiveCamera().computeViewParametersFromPhysicalMatrix(view.transform.inverse.matrix);
|
|
188
|
+
ren.getActiveCamera().setProjectionMatrix(view.projectionMatrix);
|
|
189
|
+
model.renderWindow.traverseAllPasses();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Reset scissorbox before any subsequent rendering to external displays
|
|
193
|
+
// on frame end, such as rendering to a Looking Glass display.
|
|
194
|
+
gl.scissor(0, 0, glLayer.framebufferWidth, glLayer.framebufferHeight);
|
|
195
|
+
gl.disable(gl.SCISSOR_TEST);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
publicAPI.delete = macro.chain(publicAPI.delete);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ----------------------------------------------------------------------------
|
|
202
|
+
// Object factory
|
|
203
|
+
// ----------------------------------------------------------------------------
|
|
204
|
+
|
|
205
|
+
const DEFAULT_VALUES = {
|
|
206
|
+
initialized: false,
|
|
207
|
+
initCanvasSize: null,
|
|
208
|
+
initBackground: null,
|
|
209
|
+
renderWindow: null,
|
|
210
|
+
xrSession: null,
|
|
211
|
+
xrSessionType: 0,
|
|
212
|
+
xrReferenceSpace: null
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// ----------------------------------------------------------------------------
|
|
216
|
+
|
|
217
|
+
function extend(publicAPI, model) {
|
|
218
|
+
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
219
|
+
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
220
|
+
|
|
221
|
+
// Build VTK API
|
|
222
|
+
macro.obj(publicAPI, model);
|
|
223
|
+
macro.event(publicAPI, model, 'event');
|
|
224
|
+
macro.get(publicAPI, model, ['xrSession']);
|
|
225
|
+
macro.setGet(publicAPI, model, ['renderWindow']);
|
|
226
|
+
|
|
227
|
+
// Object methods
|
|
228
|
+
vtkWebXRRenderWindowHelper(publicAPI, model);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ----------------------------------------------------------------------------
|
|
232
|
+
|
|
233
|
+
const newInstance = macro.newInstance(extend, 'vtkWebXRRenderWindowHelper');
|
|
234
|
+
|
|
235
|
+
// ----------------------------------------------------------------------------
|
|
236
|
+
|
|
237
|
+
var index = {
|
|
238
|
+
newInstance,
|
|
239
|
+
extend
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
export { index as default, extend, newInstance };
|
|
@@ -99,16 +99,6 @@ export interface vtkWidgetManager extends vtkObject {
|
|
|
99
99
|
*/
|
|
100
100
|
getPickingEnabled(): boolean;
|
|
101
101
|
|
|
102
|
-
/**
|
|
103
|
-
* @deprecated
|
|
104
|
-
*/
|
|
105
|
-
getUseSvgLayer(): boolean;
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* @deprecated
|
|
109
|
-
*/
|
|
110
|
-
setUseSvgLayer(use: boolean): boolean;
|
|
111
|
-
|
|
112
102
|
/**
|
|
113
103
|
* Enable the picking.
|
|
114
104
|
*/
|
|
@@ -165,16 +155,6 @@ export interface vtkWidgetManager extends vtkObject {
|
|
|
165
155
|
*/
|
|
166
156
|
getSelectedDataForXY(x: number, y: number): Promise<ISelectedData>;
|
|
167
157
|
|
|
168
|
-
/**
|
|
169
|
-
* @deprecated
|
|
170
|
-
*/
|
|
171
|
-
updateSelectionFromXY(x: number, y: number): void;
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* @deprecated
|
|
175
|
-
*/
|
|
176
|
-
updateSelectionFromMouseEvent(event: MouseEvent): void;
|
|
177
|
-
|
|
178
158
|
/**
|
|
179
159
|
* The all currently selected data.
|
|
180
160
|
*/
|
|
@@ -197,10 +177,6 @@ export interface IWidgetManagerInitialValues {
|
|
|
197
177
|
captureOn?: CaptureOn;
|
|
198
178
|
viewType?: ViewTypes;
|
|
199
179
|
pickingEnabled?: boolean;
|
|
200
|
-
/**
|
|
201
|
-
* @deprecated
|
|
202
|
-
*/
|
|
203
|
-
useSvgLayer?: boolean;
|
|
204
180
|
}
|
|
205
181
|
|
|
206
182
|
/**
|
|
@@ -10,8 +10,7 @@ const {
|
|
|
10
10
|
CaptureOn
|
|
11
11
|
} = WidgetManagerConst;
|
|
12
12
|
const {
|
|
13
|
-
vtkErrorMacro
|
|
14
|
-
vtkWarningMacro
|
|
13
|
+
vtkErrorMacro
|
|
15
14
|
} = macro;
|
|
16
15
|
let viewIdCount = 1;
|
|
17
16
|
|
|
@@ -203,15 +202,16 @@ function vtkWidgetManager(publicAPI, model) {
|
|
|
203
202
|
}
|
|
204
203
|
async function captureBuffers(x1, y1, x2, y2) {
|
|
205
204
|
if (model._captureInProgress) {
|
|
205
|
+
await model._captureInProgress;
|
|
206
206
|
return;
|
|
207
207
|
}
|
|
208
|
-
model._captureInProgress = true;
|
|
209
208
|
renderPickingBuffer();
|
|
210
209
|
model._capturedBuffers = null;
|
|
211
|
-
model.
|
|
210
|
+
model._captureInProgress = model._selector.getSourceDataAsync(model._renderer, x1, y1, x2, y2);
|
|
211
|
+
model._capturedBuffers = await model._captureInProgress;
|
|
212
|
+
model._captureInProgress = null;
|
|
212
213
|
model.previousSelectedData = null;
|
|
213
214
|
renderFrontBuffer();
|
|
214
|
-
model._captureInProgress = false;
|
|
215
215
|
}
|
|
216
216
|
publicAPI.enablePicking = () => {
|
|
217
217
|
model.pickingEnabled = true;
|
|
@@ -343,30 +343,6 @@ function vtkWidgetManager(publicAPI, model) {
|
|
|
343
343
|
}
|
|
344
344
|
return publicAPI.getSelectedData();
|
|
345
345
|
};
|
|
346
|
-
publicAPI.updateSelectionFromXY = (x, y) => {
|
|
347
|
-
vtkWarningMacro('updateSelectionFromXY is deprecated, please use getSelectedDataForXY');
|
|
348
|
-
if (model.pickingEnabled) {
|
|
349
|
-
// Then pick regular representations.
|
|
350
|
-
if (model.captureOn === CaptureOn.MOUSE_MOVE) {
|
|
351
|
-
captureBuffers(x, y, x, y);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
publicAPI.updateSelectionFromMouseEvent = event => {
|
|
356
|
-
vtkWarningMacro('updateSelectionFromMouseEvent is deprecated, please use getSelectedDataForXY');
|
|
357
|
-
const {
|
|
358
|
-
pageX,
|
|
359
|
-
pageY
|
|
360
|
-
} = event;
|
|
361
|
-
const {
|
|
362
|
-
top,
|
|
363
|
-
left,
|
|
364
|
-
height
|
|
365
|
-
} = model._apiSpecificRenderWindow.getCanvas().getBoundingClientRect();
|
|
366
|
-
const x = pageX - left;
|
|
367
|
-
const y = height - (pageY - top);
|
|
368
|
-
publicAPI.updateSelectionFromXY(x, y);
|
|
369
|
-
};
|
|
370
346
|
publicAPI.getSelectedData = () => {
|
|
371
347
|
if (!model.selections || !model.selections.length) {
|
|
372
348
|
model.previousSelectedData = null;
|
package/Widgets/Widgets3D.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import vtkAngleWidget from './Widgets3D/AngleWidget.js';
|
|
2
|
-
import vtkDistanceWidget from './Widgets3D/DistanceWidget.js';
|
|
3
2
|
import vtkEllipseWidget from './Widgets3D/EllipseWidget.js';
|
|
4
3
|
import vtkImageCroppingWidget from './Widgets3D/ImageCroppingWidget.js';
|
|
5
4
|
import vtkImplicitPlaneWidget from './Widgets3D/ImplicitPlaneWidget.js';
|
|
@@ -16,7 +15,6 @@ import vtkSplineWidget from './Widgets3D/SplineWidget.js';
|
|
|
16
15
|
|
|
17
16
|
var Widgets3D = {
|
|
18
17
|
vtkAngleWidget,
|
|
19
|
-
vtkDistanceWidget,
|
|
20
18
|
vtkEllipseWidget,
|
|
21
19
|
vtkImageCroppingWidget,
|
|
22
20
|
vtkImplicitPlaneWidget,
|
package/index.d.ts
CHANGED
|
@@ -205,11 +205,12 @@
|
|
|
205
205
|
/// <reference path="./Rendering/Misc/TextureLODsDownloader.d.ts" />
|
|
206
206
|
/// <reference path="./Rendering/OpenGL/HardwareSelector/Constants.d.ts" />
|
|
207
207
|
/// <reference path="./Rendering/OpenGL/HardwareSelector.d.ts" />
|
|
208
|
-
/// <reference path="./Rendering/OpenGL/RenderWindow/Constants.d.ts" />
|
|
209
208
|
/// <reference path="./Rendering/OpenGL/RenderWindow.d.ts" />
|
|
210
209
|
/// <reference path="./Rendering/SceneGraph/RenderPass.d.ts" />
|
|
211
210
|
/// <reference path="./Rendering/SceneGraph/ViewNode.d.ts" />
|
|
212
211
|
/// <reference path="./Rendering/SceneGraph/ViewNodeFactory.d.ts" />
|
|
212
|
+
/// <reference path="./Rendering/WebXR/RenderWindowHelper/Constants.d.ts" />
|
|
213
|
+
/// <reference path="./Rendering/WebXR/RenderWindowHelper.d.ts" />
|
|
213
214
|
/// <reference path="./Widgets/Core/AbstractWidget.d.ts" />
|
|
214
215
|
/// <reference path="./Widgets/Core/AbstractWidgetFactory.d.ts" />
|
|
215
216
|
/// <reference path="./Widgets/Core/StateBuilder.d.ts" />
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kitware/vtk.js",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "29.0.0",
|
|
4
4
|
"description": "Visualization Toolkit for the Web",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"3d",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"module": "./index.js",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@babel/runtime": "7.22.11",
|
|
34
|
+
"@types/webxr": "^0.5.5",
|
|
34
35
|
"commander": "9.2.0",
|
|
35
36
|
"d3-scale": "4.0.2",
|
|
36
37
|
"fast-deep-equal": "^3.1.3",
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { m as macro } from '../../../macros2.js';
|
|
2
|
-
|
|
3
|
-
const MAX_POINTS = 2;
|
|
4
|
-
function widgetBehavior(publicAPI, model) {
|
|
5
|
-
model.classHierarchy.push('vtkDistanceWidgetProp');
|
|
6
|
-
model._isDragging = false;
|
|
7
|
-
|
|
8
|
-
// --------------------------------------------------------------------------
|
|
9
|
-
// Display 2D
|
|
10
|
-
// --------------------------------------------------------------------------
|
|
11
|
-
|
|
12
|
-
publicAPI.setDisplayCallback = callback => model.representations[0].setDisplayCallback(callback);
|
|
13
|
-
|
|
14
|
-
// --------------------------------------------------------------------------
|
|
15
|
-
// Interactor events
|
|
16
|
-
// --------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
function ignoreKey(e) {
|
|
19
|
-
return e.altKey || e.controlKey || e.shiftKey;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// --------------------------------------------------------------------------
|
|
23
|
-
// Left press: Select handle to drag
|
|
24
|
-
// --------------------------------------------------------------------------
|
|
25
|
-
|
|
26
|
-
publicAPI.handleLeftButtonPress = e => {
|
|
27
|
-
if (!model.activeState || !model.activeState.getActive() || !model.pickable || ignoreKey(e)) {
|
|
28
|
-
return macro.VOID;
|
|
29
|
-
}
|
|
30
|
-
const manipulator = model.activeState?.getManipulator?.() ?? model.manipulator;
|
|
31
|
-
if (model.activeState === model.widgetState.getMoveHandle() && model.widgetState.getHandleList().length < MAX_POINTS && manipulator) {
|
|
32
|
-
const {
|
|
33
|
-
worldCoords
|
|
34
|
-
} = manipulator.handleEvent(e, model._apiSpecificRenderWindow);
|
|
35
|
-
// Commit handle to location
|
|
36
|
-
const moveHandle = model.widgetState.getMoveHandle();
|
|
37
|
-
moveHandle.setOrigin(...worldCoords);
|
|
38
|
-
const newHandle = model.widgetState.addHandle();
|
|
39
|
-
newHandle.setOrigin(...moveHandle.getOrigin());
|
|
40
|
-
newHandle.setColor(moveHandle.getColor());
|
|
41
|
-
newHandle.setScale1(moveHandle.getScale1());
|
|
42
|
-
newHandle.setManipulator(manipulator);
|
|
43
|
-
} else if (model.dragable) {
|
|
44
|
-
model._isDragging = true;
|
|
45
|
-
model._apiSpecificRenderWindow.setCursor('grabbing');
|
|
46
|
-
model._interactor.requestAnimation(publicAPI);
|
|
47
|
-
}
|
|
48
|
-
publicAPI.invokeStartInteractionEvent();
|
|
49
|
-
return macro.EVENT_ABORT;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// --------------------------------------------------------------------------
|
|
53
|
-
// Mouse move: Drag selected handle / Handle follow the mouse
|
|
54
|
-
// --------------------------------------------------------------------------
|
|
55
|
-
|
|
56
|
-
publicAPI.handleMouseMove = callData => {
|
|
57
|
-
const manipulator = model.activeState?.getManipulator?.() ?? model.manipulator;
|
|
58
|
-
if (manipulator && model.pickable && model.dragable && model.activeState && model.activeState.getActive() && !ignoreKey(callData)) {
|
|
59
|
-
const {
|
|
60
|
-
worldCoords
|
|
61
|
-
} = manipulator.handleEvent(callData, model._apiSpecificRenderWindow);
|
|
62
|
-
if (worldCoords.length && (model.activeState === model.widgetState.getMoveHandle() || model._isDragging) && model.activeState.setOrigin // e.g. the line is pickable but not draggable
|
|
63
|
-
) {
|
|
64
|
-
model.activeState.setOrigin(worldCoords);
|
|
65
|
-
publicAPI.invokeInteractionEvent();
|
|
66
|
-
return macro.EVENT_ABORT;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return macro.VOID;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// --------------------------------------------------------------------------
|
|
73
|
-
// Left release: Finish drag / Create new handle
|
|
74
|
-
// --------------------------------------------------------------------------
|
|
75
|
-
|
|
76
|
-
publicAPI.handleLeftButtonRelease = () => {
|
|
77
|
-
if (!model.activeState || !model.activeState.getActive() || !model.pickable) {
|
|
78
|
-
return macro.VOID;
|
|
79
|
-
}
|
|
80
|
-
if (model.hasFocus && model.widgetState.getHandleList().length === MAX_POINTS) {
|
|
81
|
-
publicAPI.loseFocus();
|
|
82
|
-
return macro.VOID;
|
|
83
|
-
}
|
|
84
|
-
if (model._isDragging) {
|
|
85
|
-
model._apiSpecificRenderWindow.setCursor('pointer');
|
|
86
|
-
model.widgetState.deactivate();
|
|
87
|
-
model._interactor.cancelAnimation(publicAPI);
|
|
88
|
-
model._isDragging = false;
|
|
89
|
-
} else if (model.activeState !== model.widgetState.getMoveHandle()) {
|
|
90
|
-
model.widgetState.deactivate();
|
|
91
|
-
}
|
|
92
|
-
if (model.hasFocus && !model.activeState || model.activeState && !model.activeState.getActive()) {
|
|
93
|
-
model._widgetManager.enablePicking();
|
|
94
|
-
model._interactor.render();
|
|
95
|
-
}
|
|
96
|
-
publicAPI.invokeEndInteractionEvent();
|
|
97
|
-
return macro.EVENT_ABORT;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// --------------------------------------------------------------------------
|
|
101
|
-
// Focus API - modeHandle follow mouse when widget has focus
|
|
102
|
-
// --------------------------------------------------------------------------
|
|
103
|
-
|
|
104
|
-
publicAPI.grabFocus = () => {
|
|
105
|
-
if (!model.hasFocus && model.widgetState.getHandleList().length < MAX_POINTS) {
|
|
106
|
-
model.activeState = model.widgetState.getMoveHandle();
|
|
107
|
-
model.activeState.activate();
|
|
108
|
-
model.activeState.setVisible(true);
|
|
109
|
-
model._interactor.requestAnimation(publicAPI);
|
|
110
|
-
publicAPI.invokeStartInteractionEvent();
|
|
111
|
-
}
|
|
112
|
-
model.hasFocus = true;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
// --------------------------------------------------------------------------
|
|
116
|
-
|
|
117
|
-
publicAPI.loseFocus = () => {
|
|
118
|
-
if (model.hasFocus) {
|
|
119
|
-
model._interactor.cancelAnimation(publicAPI);
|
|
120
|
-
publicAPI.invokeEndInteractionEvent();
|
|
121
|
-
}
|
|
122
|
-
model.widgetState.deactivate();
|
|
123
|
-
model.widgetState.getMoveHandle().deactivate();
|
|
124
|
-
model.widgetState.getMoveHandle().setVisible(false);
|
|
125
|
-
model.widgetState.getMoveHandle().setOrigin(null);
|
|
126
|
-
model.activeState = null;
|
|
127
|
-
model.hasFocus = false;
|
|
128
|
-
model._widgetManager.enablePicking();
|
|
129
|
-
model._interactor.render();
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export { widgetBehavior as default };
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import vtkStateBuilder from '../../Core/StateBuilder.js';
|
|
2
|
-
|
|
3
|
-
function generateState() {
|
|
4
|
-
return vtkStateBuilder.createBuilder().addStateFromMixin({
|
|
5
|
-
labels: ['moveHandle'],
|
|
6
|
-
mixins: ['origin', 'color', 'scale1', 'visible', 'manipulator'],
|
|
7
|
-
name: 'moveHandle',
|
|
8
|
-
initialValues: {
|
|
9
|
-
scale1: 30,
|
|
10
|
-
visible: false
|
|
11
|
-
}
|
|
12
|
-
}).addDynamicMixinState({
|
|
13
|
-
labels: ['handles'],
|
|
14
|
-
mixins: ['origin', 'color', 'scale1', 'visible', 'manipulator'],
|
|
15
|
-
name: 'handle',
|
|
16
|
-
initialValues: {
|
|
17
|
-
scale1: 30
|
|
18
|
-
}
|
|
19
|
-
}).build();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export { generateState as default };
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { m as macro } from '../../macros2.js';
|
|
2
|
-
import vtkAbstractWidgetFactory from '../Core/AbstractWidgetFactory.js';
|
|
3
|
-
import vtkPlanePointManipulator from '../Manipulators/PlaneManipulator.js';
|
|
4
|
-
import vtkPolyLineRepresentation from '../Representations/PolyLineRepresentation.js';
|
|
5
|
-
import vtkSphereHandleRepresentation from '../Representations/SphereHandleRepresentation.js';
|
|
6
|
-
import { e as distance2BetweenPoints } from '../../Common/Core/Math/index.js';
|
|
7
|
-
import widgetBehavior from './DistanceWidget/behavior.js';
|
|
8
|
-
import generateState from './DistanceWidget/state.js';
|
|
9
|
-
import { ViewTypes } from '../Core/WidgetManager/Constants.js';
|
|
10
|
-
|
|
11
|
-
// ----------------------------------------------------------------------------
|
|
12
|
-
// Factory
|
|
13
|
-
// ----------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
function vtkDistanceWidget(publicAPI, model) {
|
|
16
|
-
model.classHierarchy.push('vtkDistanceWidget');
|
|
17
|
-
const superClass = {
|
|
18
|
-
...publicAPI
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
// --- Widget Requirement ---------------------------------------------------
|
|
22
|
-
|
|
23
|
-
model.methodsToLink = ['activeScaleFactor', 'activeColor', 'useActiveColor', 'glyphResolution', 'defaultScale', 'scaleInPixels'];
|
|
24
|
-
publicAPI.getRepresentationsForViewType = viewType => {
|
|
25
|
-
switch (viewType) {
|
|
26
|
-
case ViewTypes.DEFAULT:
|
|
27
|
-
case ViewTypes.GEOMETRY:
|
|
28
|
-
case ViewTypes.SLICE:
|
|
29
|
-
case ViewTypes.VOLUME:
|
|
30
|
-
default:
|
|
31
|
-
return [{
|
|
32
|
-
builder: vtkSphereHandleRepresentation,
|
|
33
|
-
labels: ['handles']
|
|
34
|
-
}, {
|
|
35
|
-
builder: vtkSphereHandleRepresentation,
|
|
36
|
-
labels: ['moveHandle']
|
|
37
|
-
}, {
|
|
38
|
-
builder: vtkPolyLineRepresentation,
|
|
39
|
-
labels: ['handles', 'moveHandle']
|
|
40
|
-
}];
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// --- Public methods -------------------------------------------------------
|
|
45
|
-
|
|
46
|
-
publicAPI.getDistance = () => {
|
|
47
|
-
const handles = model.widgetState.getHandleList();
|
|
48
|
-
if (handles.length !== 2) {
|
|
49
|
-
return 0;
|
|
50
|
-
}
|
|
51
|
-
if (!handles[0].getOrigin() || !handles[1].getOrigin()) {
|
|
52
|
-
return 0;
|
|
53
|
-
}
|
|
54
|
-
return Math.sqrt(distance2BetweenPoints(handles[0].getOrigin(), handles[1].getOrigin()));
|
|
55
|
-
};
|
|
56
|
-
publicAPI.setManipulator = manipulator => {
|
|
57
|
-
superClass.setManipulator(manipulator);
|
|
58
|
-
model.widgetState.getMoveHandle().setManipulator(manipulator);
|
|
59
|
-
model.widgetState.getHandleList().forEach(handle => {
|
|
60
|
-
handle.setManipulator(manipulator);
|
|
61
|
-
});
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
// --------------------------------------------------------------------------
|
|
65
|
-
// initialization
|
|
66
|
-
// --------------------------------------------------------------------------
|
|
67
|
-
|
|
68
|
-
model.widgetState.onBoundsChange(bounds => {
|
|
69
|
-
const center = [(bounds[0] + bounds[1]) * 0.5, (bounds[2] + bounds[3]) * 0.5, (bounds[4] + bounds[5]) * 0.5];
|
|
70
|
-
model.widgetState.getMoveHandle().setOrigin(center);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Default manipulator
|
|
74
|
-
publicAPI.setManipulator(model.manipulator || vtkPlanePointManipulator.newInstance({
|
|
75
|
-
useCameraNormal: true
|
|
76
|
-
}));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// ----------------------------------------------------------------------------
|
|
80
|
-
|
|
81
|
-
const defaultValues = initialValues => ({
|
|
82
|
-
// manipulator: null,
|
|
83
|
-
behavior: widgetBehavior,
|
|
84
|
-
widgetState: generateState(),
|
|
85
|
-
...initialValues
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// ----------------------------------------------------------------------------
|
|
89
|
-
|
|
90
|
-
function extend(publicAPI, model) {
|
|
91
|
-
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
92
|
-
Object.assign(model, defaultValues(initialValues));
|
|
93
|
-
vtkAbstractWidgetFactory.extend(publicAPI, model, initialValues);
|
|
94
|
-
macro.setGet(publicAPI, model, ['manipulator']);
|
|
95
|
-
vtkDistanceWidget(publicAPI, model);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ----------------------------------------------------------------------------
|
|
99
|
-
|
|
100
|
-
const newInstance = macro.newInstance(extend, 'vtkDistanceWidget');
|
|
101
|
-
|
|
102
|
-
// ----------------------------------------------------------------------------
|
|
103
|
-
|
|
104
|
-
var vtkDistanceWidget$1 = {
|
|
105
|
-
newInstance,
|
|
106
|
-
extend
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
export { vtkDistanceWidget$1 as default, extend, newInstance };
|
|
File without changes
|