@cornerstonejs/core 3.29.1 → 3.29.2
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/dist/esm/RenderingEngine/BaseRenderingEngine.d.ts +53 -0
- package/dist/esm/RenderingEngine/BaseRenderingEngine.js +341 -0
- package/dist/esm/RenderingEngine/BaseVolumeViewport.d.ts +18 -0
- package/dist/esm/RenderingEngine/BaseVolumeViewport.js +77 -0
- package/dist/esm/RenderingEngine/RenderingEngine.d.ts +4 -38
- package/dist/esm/RenderingEngine/RenderingEngine.js +37 -614
- package/dist/esm/RenderingEngine/SequentialRenderingEngine.d.ts +18 -0
- package/dist/esm/RenderingEngine/SequentialRenderingEngine.js +235 -0
- package/dist/esm/RenderingEngine/StackViewport.d.ts +2 -0
- package/dist/esm/RenderingEngine/StackViewport.js +71 -3
- package/dist/esm/RenderingEngine/StandardRenderingEngine.d.ts +23 -0
- package/dist/esm/RenderingEngine/StandardRenderingEngine.js +285 -0
- package/dist/esm/RenderingEngine/helpers/isSequentialRenderingEngine.d.ts +1 -0
- package/dist/esm/RenderingEngine/helpers/isSequentialRenderingEngine.js +6 -0
- package/dist/esm/RenderingEngine/index.d.ts +4 -1
- package/dist/esm/RenderingEngine/index.js +4 -1
- package/dist/esm/enums/RenderingEngineModeEnum.d.ts +5 -0
- package/dist/esm/enums/RenderingEngineModeEnum.js +6 -0
- package/dist/esm/enums/index.d.ts +2 -1
- package/dist/esm/enums/index.js +2 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/init.js +2 -0
- package/dist/esm/types/Cornerstone3DConfig.d.ts +9 -7
- package/dist/esm/types/IRenderingEngine.d.ts +1 -1
- package/dist/esm/types/RenderingEngineMode.d.ts +2 -0
- package/dist/esm/types/RenderingEngineMode.js +0 -0
- package/dist/esm/types/index.d.ts +2 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type IStackViewport from '../types/IStackViewport';
|
|
2
|
+
import type IVolumeViewport from '../types/IVolumeViewport';
|
|
3
|
+
import type * as EventTypes from '../types/EventTypes';
|
|
4
|
+
import type { PublicViewportInput, InternalViewportInput, NormalizedViewportInput, IViewport } from '../types/IViewport';
|
|
5
|
+
export declare const VIEWPORT_MIN_SIZE = 2;
|
|
6
|
+
declare abstract class BaseRenderingEngine {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
hasBeenDestroyed: boolean;
|
|
9
|
+
offscreenMultiRenderWindow: any;
|
|
10
|
+
readonly offScreenCanvasContainer: HTMLDivElement;
|
|
11
|
+
protected _viewports: Map<string, IViewport>;
|
|
12
|
+
protected _needsRender: Set<string>;
|
|
13
|
+
protected _animationFrameSet: boolean;
|
|
14
|
+
protected _animationFrameHandle: number | null;
|
|
15
|
+
protected useCPURendering: boolean;
|
|
16
|
+
constructor(id?: string);
|
|
17
|
+
enableElement(viewportInputEntry: PublicViewportInput): void;
|
|
18
|
+
disableElement(viewportId: string): void;
|
|
19
|
+
setViewports(publicViewportInputEntries: PublicViewportInput[]): void;
|
|
20
|
+
resize(immediate?: boolean, keepCamera?: boolean): void;
|
|
21
|
+
getViewport(viewportId: string): IViewport;
|
|
22
|
+
getViewports(): IViewport[];
|
|
23
|
+
getStackViewport(viewportId: string): IStackViewport;
|
|
24
|
+
getStackViewports(): IStackViewport[];
|
|
25
|
+
getVolumeViewports(): IVolumeViewport[];
|
|
26
|
+
render(): void;
|
|
27
|
+
renderFrameOfReference: (FrameOfReferenceUID: string) => void;
|
|
28
|
+
renderViewports(viewportIds: string[]): void;
|
|
29
|
+
renderViewport(viewportId: string): void;
|
|
30
|
+
destroy(): void;
|
|
31
|
+
fillCanvasWithBackgroundColor(canvas: HTMLCanvasElement, backgroundColor: [number, number, number]): void;
|
|
32
|
+
private _normalizeViewportInputEntry;
|
|
33
|
+
private _normalizeViewportInputEntries;
|
|
34
|
+
private _resizeUsingCustomResizeHandler;
|
|
35
|
+
private _removeViewport;
|
|
36
|
+
private addCustomViewport;
|
|
37
|
+
private setCustomViewports;
|
|
38
|
+
protected _getViewportsAsArray(): IViewport[];
|
|
39
|
+
private _setViewportsToBeRenderedNextFrame;
|
|
40
|
+
private _render;
|
|
41
|
+
private _resetViewport;
|
|
42
|
+
private _clearAnimationFrame;
|
|
43
|
+
private _reset;
|
|
44
|
+
protected _throwIfDestroyed(): void;
|
|
45
|
+
protected abstract _resizeVTKViewports(vtkDrivenViewports: (IStackViewport | IVolumeViewport)[], keepCamera: boolean, immediate: boolean): void;
|
|
46
|
+
protected abstract enableVTKjsDrivenViewport(viewportInputEntry: NormalizedViewportInput): void;
|
|
47
|
+
protected abstract addVtkjsDrivenViewport(viewportInputEntry: InternalViewportInput, offscreenCanvasProperties?: unknown): void;
|
|
48
|
+
protected abstract _renderFlaggedViewports(): void;
|
|
49
|
+
protected abstract setVtkjsDrivenViewports(viewportInputEntries: NormalizedViewportInput[]): void;
|
|
50
|
+
protected abstract renderViewportUsingCustomOrVtkPipeline(viewport: IViewport): EventTypes.ImageRenderedEventDetail;
|
|
51
|
+
protected abstract _renderViewportFromVtkCanvasToOnscreenCanvas(viewport: IViewport, offScreenCanvas: HTMLCanvasElement): EventTypes.ImageRenderedEventDetail;
|
|
52
|
+
}
|
|
53
|
+
export default BaseRenderingEngine;
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import Events from '../enums/Events';
|
|
2
|
+
import renderingEngineCache from './renderingEngineCache';
|
|
3
|
+
import eventTarget from '../eventTarget';
|
|
4
|
+
import uuidv4 from '../utilities/uuidv4';
|
|
5
|
+
import triggerEvent from '../utilities/triggerEvent';
|
|
6
|
+
import { vtkOffscreenMultiRenderWindow } from './vtkClasses';
|
|
7
|
+
import ViewportType from '../enums/ViewportType';
|
|
8
|
+
import BaseVolumeViewport from './BaseVolumeViewport';
|
|
9
|
+
import StackViewport from './StackViewport';
|
|
10
|
+
import viewportTypeUsesCustomRenderingPipeline from './helpers/viewportTypeUsesCustomRenderingPipeline';
|
|
11
|
+
import getOrCreateCanvas from './helpers/getOrCreateCanvas';
|
|
12
|
+
import { getShouldUseCPURendering, isCornerstoneInitialized } from '../init';
|
|
13
|
+
import viewportTypeToViewportClass from './helpers/viewportTypeToViewportClass';
|
|
14
|
+
import { OrientationAxis } from '../enums';
|
|
15
|
+
export const VIEWPORT_MIN_SIZE = 2;
|
|
16
|
+
class BaseRenderingEngine {
|
|
17
|
+
constructor(id) {
|
|
18
|
+
this._needsRender = new Set();
|
|
19
|
+
this._animationFrameSet = false;
|
|
20
|
+
this._animationFrameHandle = null;
|
|
21
|
+
this.renderFrameOfReference = (FrameOfReferenceUID) => {
|
|
22
|
+
const viewports = this._getViewportsAsArray();
|
|
23
|
+
const viewportIdsWithSameFrameOfReferenceUID = viewports.map((vp) => {
|
|
24
|
+
if (vp.getFrameOfReferenceUID() === FrameOfReferenceUID) {
|
|
25
|
+
return vp.id;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
this.renderViewports(viewportIdsWithSameFrameOfReferenceUID);
|
|
29
|
+
};
|
|
30
|
+
this.id = id ? id : uuidv4();
|
|
31
|
+
this.useCPURendering = getShouldUseCPURendering();
|
|
32
|
+
renderingEngineCache.set(this);
|
|
33
|
+
if (!isCornerstoneInitialized()) {
|
|
34
|
+
throw new Error('@cornerstonejs/core is not initialized, run init() first');
|
|
35
|
+
}
|
|
36
|
+
if (!this.useCPURendering) {
|
|
37
|
+
this.offscreenMultiRenderWindow =
|
|
38
|
+
vtkOffscreenMultiRenderWindow.newInstance();
|
|
39
|
+
this.offScreenCanvasContainer = document.createElement('div');
|
|
40
|
+
this.offscreenMultiRenderWindow.setContainer(this.offScreenCanvasContainer);
|
|
41
|
+
}
|
|
42
|
+
this._viewports = new Map();
|
|
43
|
+
this.hasBeenDestroyed = false;
|
|
44
|
+
}
|
|
45
|
+
enableElement(viewportInputEntry) {
|
|
46
|
+
const viewportInput = this._normalizeViewportInputEntry(viewportInputEntry);
|
|
47
|
+
this._throwIfDestroyed();
|
|
48
|
+
const { element, viewportId } = viewportInput;
|
|
49
|
+
if (!element) {
|
|
50
|
+
throw new Error('No element provided');
|
|
51
|
+
}
|
|
52
|
+
const viewport = this.getViewport(viewportId);
|
|
53
|
+
if (viewport) {
|
|
54
|
+
this.disableElement(viewportId);
|
|
55
|
+
}
|
|
56
|
+
const { type } = viewportInput;
|
|
57
|
+
const viewportUsesCustomRenderingPipeline = viewportTypeUsesCustomRenderingPipeline(type);
|
|
58
|
+
if (!this.useCPURendering && !viewportUsesCustomRenderingPipeline) {
|
|
59
|
+
this.enableVTKjsDrivenViewport(viewportInput);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
this.addCustomViewport(viewportInput);
|
|
63
|
+
}
|
|
64
|
+
const canvas = getOrCreateCanvas(element);
|
|
65
|
+
const { background } = viewportInput.defaultOptions;
|
|
66
|
+
this.fillCanvasWithBackgroundColor(canvas, background);
|
|
67
|
+
}
|
|
68
|
+
disableElement(viewportId) {
|
|
69
|
+
this._throwIfDestroyed();
|
|
70
|
+
const viewport = this.getViewport(viewportId);
|
|
71
|
+
if (!viewport) {
|
|
72
|
+
console.warn(`viewport ${viewportId} does not exist`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
this._resetViewport(viewport);
|
|
76
|
+
if (!viewportTypeUsesCustomRenderingPipeline(viewport.type) &&
|
|
77
|
+
!this.useCPURendering) {
|
|
78
|
+
this.offscreenMultiRenderWindow.removeRenderer(viewportId);
|
|
79
|
+
}
|
|
80
|
+
this._removeViewport(viewportId);
|
|
81
|
+
viewport.isDisabled = true;
|
|
82
|
+
this._needsRender.delete(viewportId);
|
|
83
|
+
const viewports = this.getViewports();
|
|
84
|
+
if (!viewports.length) {
|
|
85
|
+
this._clearAnimationFrame();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
setViewports(publicViewportInputEntries) {
|
|
89
|
+
const viewportInputEntries = this._normalizeViewportInputEntries(publicViewportInputEntries);
|
|
90
|
+
this._throwIfDestroyed();
|
|
91
|
+
this._reset();
|
|
92
|
+
const vtkDrivenViewportInputEntries = [];
|
|
93
|
+
const customRenderingViewportInputEntries = [];
|
|
94
|
+
viewportInputEntries.forEach((vpie) => {
|
|
95
|
+
if (!this.useCPURendering &&
|
|
96
|
+
!viewportTypeUsesCustomRenderingPipeline(vpie.type)) {
|
|
97
|
+
vtkDrivenViewportInputEntries.push(vpie);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
customRenderingViewportInputEntries.push(vpie);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
this.setVtkjsDrivenViewports(vtkDrivenViewportInputEntries);
|
|
104
|
+
this.setCustomViewports(customRenderingViewportInputEntries);
|
|
105
|
+
viewportInputEntries.forEach((vp) => {
|
|
106
|
+
const canvas = getOrCreateCanvas(vp.element);
|
|
107
|
+
const { background } = vp.defaultOptions;
|
|
108
|
+
this.fillCanvasWithBackgroundColor(canvas, background);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
resize(immediate = true, keepCamera = true) {
|
|
112
|
+
this._throwIfDestroyed();
|
|
113
|
+
const viewports = this._getViewportsAsArray();
|
|
114
|
+
const vtkDrivenViewports = [];
|
|
115
|
+
const customRenderingViewports = [];
|
|
116
|
+
viewports.forEach((vpie) => {
|
|
117
|
+
if (!viewportTypeUsesCustomRenderingPipeline(vpie.type)) {
|
|
118
|
+
vtkDrivenViewports.push(vpie);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
customRenderingViewports.push(vpie);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
if (vtkDrivenViewports.length) {
|
|
125
|
+
this._resizeVTKViewports(vtkDrivenViewports, keepCamera, immediate);
|
|
126
|
+
}
|
|
127
|
+
if (customRenderingViewports.length) {
|
|
128
|
+
this._resizeUsingCustomResizeHandler(customRenderingViewports, keepCamera, immediate);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
getViewport(viewportId) {
|
|
132
|
+
return this._viewports?.get(viewportId);
|
|
133
|
+
}
|
|
134
|
+
getViewports() {
|
|
135
|
+
this._throwIfDestroyed();
|
|
136
|
+
return this._getViewportsAsArray();
|
|
137
|
+
}
|
|
138
|
+
getStackViewport(viewportId) {
|
|
139
|
+
this._throwIfDestroyed();
|
|
140
|
+
const viewport = this.getViewport(viewportId);
|
|
141
|
+
if (!viewport) {
|
|
142
|
+
throw new Error(`Viewport with Id ${viewportId} does not exist`);
|
|
143
|
+
}
|
|
144
|
+
if (!(viewport instanceof StackViewport)) {
|
|
145
|
+
throw new Error(`Viewport with Id ${viewportId} is not a StackViewport.`);
|
|
146
|
+
}
|
|
147
|
+
return viewport;
|
|
148
|
+
}
|
|
149
|
+
getStackViewports() {
|
|
150
|
+
this._throwIfDestroyed();
|
|
151
|
+
const viewports = this.getViewports();
|
|
152
|
+
return viewports.filter((vp) => vp instanceof StackViewport);
|
|
153
|
+
}
|
|
154
|
+
getVolumeViewports() {
|
|
155
|
+
this._throwIfDestroyed();
|
|
156
|
+
const viewports = this.getViewports();
|
|
157
|
+
const isVolumeViewport = (viewport) => {
|
|
158
|
+
return viewport instanceof BaseVolumeViewport;
|
|
159
|
+
};
|
|
160
|
+
return viewports.filter(isVolumeViewport);
|
|
161
|
+
}
|
|
162
|
+
render() {
|
|
163
|
+
const viewports = this.getViewports();
|
|
164
|
+
const viewportIds = viewports.map((vp) => vp.id);
|
|
165
|
+
this._setViewportsToBeRenderedNextFrame(viewportIds);
|
|
166
|
+
}
|
|
167
|
+
renderViewports(viewportIds) {
|
|
168
|
+
this._setViewportsToBeRenderedNextFrame(viewportIds);
|
|
169
|
+
}
|
|
170
|
+
renderViewport(viewportId) {
|
|
171
|
+
this._setViewportsToBeRenderedNextFrame([viewportId]);
|
|
172
|
+
}
|
|
173
|
+
destroy() {
|
|
174
|
+
if (this.hasBeenDestroyed) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (!this.useCPURendering) {
|
|
178
|
+
const viewports = this._getViewportsAsArray();
|
|
179
|
+
viewports.forEach((vp) => {
|
|
180
|
+
this.offscreenMultiRenderWindow.removeRenderer(vp.id);
|
|
181
|
+
});
|
|
182
|
+
this.offscreenMultiRenderWindow.delete();
|
|
183
|
+
delete this.offscreenMultiRenderWindow;
|
|
184
|
+
}
|
|
185
|
+
this._reset();
|
|
186
|
+
renderingEngineCache.delete(this.id);
|
|
187
|
+
this.hasBeenDestroyed = true;
|
|
188
|
+
}
|
|
189
|
+
fillCanvasWithBackgroundColor(canvas, backgroundColor) {
|
|
190
|
+
const ctx = canvas.getContext('2d');
|
|
191
|
+
let fillStyle;
|
|
192
|
+
if (backgroundColor) {
|
|
193
|
+
const rgb = backgroundColor.map((f) => Math.floor(255 * f));
|
|
194
|
+
fillStyle = `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
fillStyle = 'black';
|
|
198
|
+
}
|
|
199
|
+
ctx.fillStyle = fillStyle;
|
|
200
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
201
|
+
}
|
|
202
|
+
_normalizeViewportInputEntry(viewportInputEntry) {
|
|
203
|
+
const { type, defaultOptions } = viewportInputEntry;
|
|
204
|
+
let options = defaultOptions;
|
|
205
|
+
if (!options || Object.keys(options).length === 0) {
|
|
206
|
+
options = {
|
|
207
|
+
background: [0, 0, 0],
|
|
208
|
+
orientation: null,
|
|
209
|
+
displayArea: null,
|
|
210
|
+
};
|
|
211
|
+
if (type === ViewportType.ORTHOGRAPHIC) {
|
|
212
|
+
options = {
|
|
213
|
+
...options,
|
|
214
|
+
orientation: OrientationAxis.AXIAL,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
...viewportInputEntry,
|
|
220
|
+
defaultOptions: options,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
_normalizeViewportInputEntries(viewportInputEntries) {
|
|
224
|
+
const normalizedViewportInputs = [];
|
|
225
|
+
viewportInputEntries.forEach((viewportInput) => {
|
|
226
|
+
normalizedViewportInputs.push(this._normalizeViewportInputEntry(viewportInput));
|
|
227
|
+
});
|
|
228
|
+
return normalizedViewportInputs;
|
|
229
|
+
}
|
|
230
|
+
_resizeUsingCustomResizeHandler(customRenderingViewports, keepCamera = true, immediate = true) {
|
|
231
|
+
customRenderingViewports.forEach((vp) => {
|
|
232
|
+
if (typeof vp.resize === 'function') {
|
|
233
|
+
vp.resize();
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
customRenderingViewports.forEach((vp) => {
|
|
237
|
+
const prevCamera = vp.getCamera();
|
|
238
|
+
vp.resetCamera();
|
|
239
|
+
if (keepCamera) {
|
|
240
|
+
vp.setCamera(prevCamera);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
if (immediate) {
|
|
244
|
+
this.render();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
_removeViewport(viewportId) {
|
|
248
|
+
const viewport = this.getViewport(viewportId);
|
|
249
|
+
if (!viewport) {
|
|
250
|
+
console.warn(`viewport ${viewportId} does not exist`);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
this._viewports.delete(viewportId);
|
|
254
|
+
}
|
|
255
|
+
addCustomViewport(viewportInputEntry) {
|
|
256
|
+
const { element, viewportId, type, defaultOptions } = viewportInputEntry;
|
|
257
|
+
element.tabIndex = -1;
|
|
258
|
+
const canvas = getOrCreateCanvas(element);
|
|
259
|
+
const { clientWidth, clientHeight } = canvas;
|
|
260
|
+
if (canvas.width !== clientWidth || canvas.height !== clientHeight) {
|
|
261
|
+
canvas.width = clientWidth;
|
|
262
|
+
canvas.height = clientHeight;
|
|
263
|
+
}
|
|
264
|
+
const viewportInput = {
|
|
265
|
+
id: viewportId,
|
|
266
|
+
renderingEngineId: this.id,
|
|
267
|
+
element,
|
|
268
|
+
type,
|
|
269
|
+
canvas,
|
|
270
|
+
sx: 0,
|
|
271
|
+
sy: 0,
|
|
272
|
+
sWidth: clientWidth,
|
|
273
|
+
sHeight: clientHeight,
|
|
274
|
+
defaultOptions: defaultOptions || {},
|
|
275
|
+
};
|
|
276
|
+
const ViewportType = viewportTypeToViewportClass[type];
|
|
277
|
+
const viewport = new ViewportType(viewportInput);
|
|
278
|
+
this._viewports.set(viewportId, viewport);
|
|
279
|
+
const eventDetail = {
|
|
280
|
+
element,
|
|
281
|
+
viewportId,
|
|
282
|
+
renderingEngineId: this.id,
|
|
283
|
+
};
|
|
284
|
+
triggerEvent(eventTarget, Events.ELEMENT_ENABLED, eventDetail);
|
|
285
|
+
}
|
|
286
|
+
setCustomViewports(viewportInputEntries) {
|
|
287
|
+
viewportInputEntries.forEach((vpie) => {
|
|
288
|
+
this.addCustomViewport(vpie);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
_getViewportsAsArray() {
|
|
292
|
+
return Array.from(this._viewports.values());
|
|
293
|
+
}
|
|
294
|
+
_setViewportsToBeRenderedNextFrame(viewportIds) {
|
|
295
|
+
viewportIds.forEach((viewportId) => {
|
|
296
|
+
this._needsRender.add(viewportId);
|
|
297
|
+
});
|
|
298
|
+
this._render();
|
|
299
|
+
}
|
|
300
|
+
_render() {
|
|
301
|
+
if (this._needsRender.size > 0 && !this._animationFrameSet) {
|
|
302
|
+
this._animationFrameHandle = window.requestAnimationFrame(this._renderFlaggedViewports);
|
|
303
|
+
this._animationFrameSet = true;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
_resetViewport(viewport) {
|
|
307
|
+
const renderingEngineId = this.id;
|
|
308
|
+
const { element, canvas, id: viewportId } = viewport;
|
|
309
|
+
const eventDetail = {
|
|
310
|
+
element,
|
|
311
|
+
viewportId,
|
|
312
|
+
renderingEngineId,
|
|
313
|
+
};
|
|
314
|
+
viewport.removeWidgets();
|
|
315
|
+
triggerEvent(eventTarget, Events.ELEMENT_DISABLED, eventDetail);
|
|
316
|
+
element.removeAttribute('data-viewport-uid');
|
|
317
|
+
element.removeAttribute('data-rendering-engine-uid');
|
|
318
|
+
const context = canvas.getContext('2d');
|
|
319
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
320
|
+
}
|
|
321
|
+
_clearAnimationFrame() {
|
|
322
|
+
window.cancelAnimationFrame(this._animationFrameHandle);
|
|
323
|
+
this._needsRender.clear();
|
|
324
|
+
this._animationFrameSet = false;
|
|
325
|
+
this._animationFrameHandle = null;
|
|
326
|
+
}
|
|
327
|
+
_reset() {
|
|
328
|
+
const viewports = this._getViewportsAsArray();
|
|
329
|
+
viewports.forEach((viewport) => {
|
|
330
|
+
this._resetViewport(viewport);
|
|
331
|
+
});
|
|
332
|
+
this._clearAnimationFrame();
|
|
333
|
+
this._viewports = new Map();
|
|
334
|
+
}
|
|
335
|
+
_throwIfDestroyed() {
|
|
336
|
+
if (this.hasBeenDestroyed) {
|
|
337
|
+
throw new Error('this.destroy() has been manually called to free up memory, can not longer use this instance. Instead make a new one.');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
export default BaseRenderingEngine;
|
|
@@ -69,8 +69,11 @@ declare abstract class BaseVolumeViewport extends Viewport {
|
|
|
69
69
|
setCamera(cameraInterface: ICamera, storeAsInitialCamera?: boolean): void;
|
|
70
70
|
private _setVolumeActors;
|
|
71
71
|
canvasToWorld: (canvasPos: Point2) => Point3;
|
|
72
|
+
canvasToWorldSequential: (canvasPos: Point2) => Point3;
|
|
72
73
|
getVtkDisplayCoords: (canvasPos: Point2) => Point3;
|
|
74
|
+
getVtkDisplayCoordsSequential: (canvasPos: Point2) => Point3;
|
|
73
75
|
worldToCanvas: (worldPos: Point3) => Point2;
|
|
76
|
+
worldToCanvasSequential: (worldPos: Point3) => Point2;
|
|
74
77
|
hasImageURI: (imageURI: string) => boolean;
|
|
75
78
|
protected _getOrientationVectors(orientation: OrientationAxis | OrientationVectors): OrientationVectors;
|
|
76
79
|
protected _getAcquisitionPlaneOrientation(): OrientationVectors;
|
|
@@ -86,5 +89,20 @@ declare abstract class BaseVolumeViewport extends Viewport {
|
|
|
86
89
|
abstract resetSlabThickness(): void;
|
|
87
90
|
abstract resetProperties(volumeId?: string): void;
|
|
88
91
|
getAllVolumeIds(): string[];
|
|
92
|
+
private _configureRenderingPipeline;
|
|
93
|
+
protected renderingPipelineFunctions: {
|
|
94
|
+
worldToCanvas: {
|
|
95
|
+
default: (worldPos: Point3) => Point2;
|
|
96
|
+
sequential: (worldPos: Point3) => Point2;
|
|
97
|
+
};
|
|
98
|
+
canvasToWorld: {
|
|
99
|
+
default: (canvasPos: Point2) => Point3;
|
|
100
|
+
sequential: (canvasPos: Point2) => Point3;
|
|
101
|
+
};
|
|
102
|
+
getVtkDisplayCoords: {
|
|
103
|
+
default: (canvasPos: Point2) => Point3;
|
|
104
|
+
sequential: (canvasPos: Point2) => Point3;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
89
107
|
}
|
|
90
108
|
export default BaseVolumeViewport;
|
|
@@ -29,6 +29,7 @@ import imageIdToURI from '../utilities/imageIdToURI';
|
|
|
29
29
|
import uuidv4 from '../utilities/uuidv4';
|
|
30
30
|
import * as metaData from '../metaData';
|
|
31
31
|
import { getCameraVectors } from './helpers/getCameraVectors';
|
|
32
|
+
import { isSequentialRenderingEngine } from './helpers/isSequentialRenderingEngine';
|
|
32
33
|
class BaseVolumeViewport extends Viewport {
|
|
33
34
|
constructor(props) {
|
|
34
35
|
super(props);
|
|
@@ -164,6 +165,28 @@ class BaseVolumeViewport extends Viewport {
|
|
|
164
165
|
vtkCamera.setIsPerformingCoordinateTransformation?.(false);
|
|
165
166
|
return [worldCoord[0], worldCoord[1], worldCoord[2]];
|
|
166
167
|
};
|
|
168
|
+
this.canvasToWorldSequential = (canvasPos) => {
|
|
169
|
+
const vtkCamera = this.getVtkActiveCamera();
|
|
170
|
+
vtkCamera.setIsPerformingCoordinateTransformation?.(true);
|
|
171
|
+
const renderer = this.getRenderer();
|
|
172
|
+
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
173
|
+
const { width, height } = this.canvas;
|
|
174
|
+
const aspectRatio = width / height;
|
|
175
|
+
const canvasPosWithDPR = [
|
|
176
|
+
canvasPos[0] * devicePixelRatio,
|
|
177
|
+
canvasPos[1] * devicePixelRatio,
|
|
178
|
+
];
|
|
179
|
+
const normalizedDisplay = [
|
|
180
|
+
canvasPosWithDPR[0] / width,
|
|
181
|
+
1 - canvasPosWithDPR[1] / height,
|
|
182
|
+
0,
|
|
183
|
+
];
|
|
184
|
+
const projCoords = renderer.normalizedDisplayToProjection(normalizedDisplay[0], normalizedDisplay[1], normalizedDisplay[2]);
|
|
185
|
+
const viewCoords = renderer.projectionToView(projCoords[0], projCoords[1], projCoords[2], aspectRatio);
|
|
186
|
+
const worldCoord = renderer.viewToWorld(viewCoords[0], viewCoords[1], viewCoords[2]);
|
|
187
|
+
vtkCamera.setIsPerformingCoordinateTransformation?.(false);
|
|
188
|
+
return [worldCoord[0], worldCoord[1], worldCoord[2]];
|
|
189
|
+
};
|
|
167
190
|
this.getVtkDisplayCoords = (canvasPos) => {
|
|
168
191
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
169
192
|
const canvasPosWithDPR = [
|
|
@@ -180,6 +203,16 @@ class BaseVolumeViewport extends Viewport {
|
|
|
180
203
|
displayCoord[1] = size[1] - displayCoord[1];
|
|
181
204
|
return [displayCoord[0], displayCoord[1], 0];
|
|
182
205
|
};
|
|
206
|
+
this.getVtkDisplayCoordsSequential = (canvasPos) => {
|
|
207
|
+
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
208
|
+
const canvasPosWithDPR = [
|
|
209
|
+
canvasPos[0] * devicePixelRatio,
|
|
210
|
+
canvasPos[1] * devicePixelRatio,
|
|
211
|
+
];
|
|
212
|
+
const { height } = this.canvas;
|
|
213
|
+
const displayCoord = [canvasPosWithDPR[0], height - canvasPosWithDPR[1]];
|
|
214
|
+
return [displayCoord[0], displayCoord[1], 0];
|
|
215
|
+
};
|
|
183
216
|
this.worldToCanvas = (worldPos) => {
|
|
184
217
|
const vtkCamera = this.getVtkActiveCamera();
|
|
185
218
|
vtkCamera.setIsPerformingCoordinateTransformation?.(true);
|
|
@@ -201,6 +234,25 @@ class BaseVolumeViewport extends Viewport {
|
|
|
201
234
|
vtkCamera.setIsPerformingCoordinateTransformation(false);
|
|
202
235
|
return canvasCoordWithDPR;
|
|
203
236
|
};
|
|
237
|
+
this.worldToCanvasSequential = (worldPos) => {
|
|
238
|
+
const vtkCamera = this.getVtkActiveCamera();
|
|
239
|
+
vtkCamera.setIsPerformingCoordinateTransformation?.(true);
|
|
240
|
+
const renderer = this.getRenderer();
|
|
241
|
+
const { width, height } = this.canvas;
|
|
242
|
+
const aspectRatio = width / height;
|
|
243
|
+
const viewCoords = renderer.worldToView(worldPos[0], worldPos[1], worldPos[2]);
|
|
244
|
+
const projCoords = renderer.viewToProjection(viewCoords[0], viewCoords[1], viewCoords[2], aspectRatio);
|
|
245
|
+
const normalizedDisplay = renderer.projectionToNormalizedDisplay(projCoords[0], projCoords[1], projCoords[2]);
|
|
246
|
+
const canvasX = normalizedDisplay[0] * width;
|
|
247
|
+
const canvasY = (1 - normalizedDisplay[1]) * height;
|
|
248
|
+
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
249
|
+
const canvasCoordWithDPR = [
|
|
250
|
+
canvasX / devicePixelRatio,
|
|
251
|
+
canvasY / devicePixelRatio,
|
|
252
|
+
];
|
|
253
|
+
vtkCamera.setIsPerformingCoordinateTransformation(false);
|
|
254
|
+
return canvasCoordWithDPR;
|
|
255
|
+
};
|
|
204
256
|
this.hasImageURI = (imageURI) => {
|
|
205
257
|
const volumeActors = this.getActors().filter((actorEntry) => actorIsA(actorEntry, 'vtkVolume'));
|
|
206
258
|
return volumeActors.some(({ uid, referencedId }) => {
|
|
@@ -224,10 +276,25 @@ class BaseVolumeViewport extends Viewport {
|
|
|
224
276
|
}
|
|
225
277
|
return imageVolume.imageIds;
|
|
226
278
|
};
|
|
279
|
+
this.renderingPipelineFunctions = {
|
|
280
|
+
worldToCanvas: {
|
|
281
|
+
default: this.worldToCanvas,
|
|
282
|
+
sequential: this.worldToCanvasSequential,
|
|
283
|
+
},
|
|
284
|
+
canvasToWorld: {
|
|
285
|
+
default: this.canvasToWorld,
|
|
286
|
+
sequential: this.canvasToWorldSequential,
|
|
287
|
+
},
|
|
288
|
+
getVtkDisplayCoords: {
|
|
289
|
+
default: this.getVtkDisplayCoords,
|
|
290
|
+
sequential: this.getVtkDisplayCoordsSequential,
|
|
291
|
+
},
|
|
292
|
+
};
|
|
227
293
|
this.useCPURendering = getShouldUseCPURendering();
|
|
228
294
|
if (this.useCPURendering) {
|
|
229
295
|
throw new Error('VolumeViewports cannot be used whilst CPU Fallback Rendering is enabled.');
|
|
230
296
|
}
|
|
297
|
+
this._configureRenderingPipeline();
|
|
231
298
|
const renderer = this.getRenderer();
|
|
232
299
|
const camera = vtkSlabCamera.newInstance();
|
|
233
300
|
renderer.setActiveCamera(camera);
|
|
@@ -986,5 +1053,15 @@ class BaseVolumeViewport extends Viewport {
|
|
|
986
1053
|
getAllVolumeIds() {
|
|
987
1054
|
return Array.from(this.volumeIds);
|
|
988
1055
|
}
|
|
1056
|
+
_configureRenderingPipeline() {
|
|
1057
|
+
const renderingEngine = this.getRenderingEngine();
|
|
1058
|
+
const isSequential = isSequentialRenderingEngine(renderingEngine);
|
|
1059
|
+
for (const key in this.renderingPipelineFunctions) {
|
|
1060
|
+
if (Object.prototype.hasOwnProperty.call(this.renderingPipelineFunctions, key)) {
|
|
1061
|
+
const functions = this.renderingPipelineFunctions[key];
|
|
1062
|
+
this[key] = isSequential ? functions.sequential : functions.default;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
989
1066
|
}
|
|
990
1067
|
export default BaseVolumeViewport;
|
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
import type IStackViewport from '../types
|
|
2
|
-
import type IVolumeViewport from '../types/IVolumeViewport';
|
|
3
|
-
import type { PublicViewportInput, IViewport } from '../types/IViewport';
|
|
1
|
+
import type { IStackViewport, IVolumeViewport, IViewport, PublicViewportInput } from '../types';
|
|
4
2
|
declare class RenderingEngine {
|
|
5
|
-
readonly id: string;
|
|
6
3
|
hasBeenDestroyed: boolean;
|
|
7
4
|
offscreenMultiRenderWindow: any;
|
|
8
|
-
|
|
9
|
-
private _viewports;
|
|
10
|
-
private _needsRender;
|
|
11
|
-
private _animationFrameSet;
|
|
12
|
-
private _animationFrameHandle;
|
|
13
|
-
private useCPURendering;
|
|
5
|
+
private _implementation?;
|
|
14
6
|
constructor(id?: string);
|
|
7
|
+
get id(): string;
|
|
15
8
|
enableElement(viewportInputEntry: PublicViewportInput): void;
|
|
16
9
|
disableElement(viewportId: string): void;
|
|
17
10
|
setViewports(publicViewportInputEntries: PublicViewportInput[]): void;
|
|
@@ -21,37 +14,10 @@ declare class RenderingEngine {
|
|
|
21
14
|
getStackViewport(viewportId: string): IStackViewport;
|
|
22
15
|
getStackViewports(): IStackViewport[];
|
|
23
16
|
getVolumeViewports(): IVolumeViewport[];
|
|
17
|
+
fillCanvasWithBackgroundColor(canvas: HTMLCanvasElement, backgroundColor: [number, number, number]): void;
|
|
24
18
|
render(): void;
|
|
25
|
-
renderFrameOfReference: (FrameOfReferenceUID: string) => void;
|
|
26
19
|
renderViewports(viewportIds: string[]): void;
|
|
27
20
|
renderViewport(viewportId: string): void;
|
|
28
21
|
destroy(): void;
|
|
29
|
-
fillCanvasWithBackgroundColor(canvas: HTMLCanvasElement, backgroundColor: [number, number, number]): void;
|
|
30
|
-
private _normalizeViewportInputEntry;
|
|
31
|
-
private _normalizeViewportInputEntries;
|
|
32
|
-
private _resizeUsingCustomResizeHandler;
|
|
33
|
-
private _resizeVTKViewports;
|
|
34
|
-
private enableVTKjsDrivenViewport;
|
|
35
|
-
private _removeViewport;
|
|
36
|
-
private addVtkjsDrivenViewport;
|
|
37
|
-
private addCustomViewport;
|
|
38
|
-
private setCustomViewports;
|
|
39
|
-
private setVtkjsDrivenViewports;
|
|
40
|
-
private _resizeOffScreenCanvas;
|
|
41
|
-
private _resize;
|
|
42
|
-
private _getViewportCoordsOnOffScreenCanvas;
|
|
43
|
-
private _getViewportsAsArray;
|
|
44
|
-
private _setViewportsToBeRenderedNextFrame;
|
|
45
|
-
private _render;
|
|
46
|
-
private _renderFlaggedViewports;
|
|
47
|
-
private performVtkDrawCall;
|
|
48
|
-
private renderViewportUsingCustomOrVtkPipeline;
|
|
49
|
-
private _renderViewportFromVtkCanvasToOnscreenCanvas;
|
|
50
|
-
private _resetViewport;
|
|
51
|
-
private _clearAnimationFrame;
|
|
52
|
-
private _reset;
|
|
53
|
-
private _throwIfDestroyed;
|
|
54
|
-
_downloadOffScreenCanvas(): void;
|
|
55
|
-
_debugRender(): void;
|
|
56
22
|
}
|
|
57
23
|
export default RenderingEngine;
|