@cornerstonejs/core 3.29.0 → 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.
Files changed (31) hide show
  1. package/dist/esm/RenderingEngine/BaseRenderingEngine.d.ts +53 -0
  2. package/dist/esm/RenderingEngine/BaseRenderingEngine.js +341 -0
  3. package/dist/esm/RenderingEngine/BaseVolumeViewport.d.ts +18 -0
  4. package/dist/esm/RenderingEngine/BaseVolumeViewport.js +77 -0
  5. package/dist/esm/RenderingEngine/RenderingEngine.d.ts +4 -38
  6. package/dist/esm/RenderingEngine/RenderingEngine.js +37 -614
  7. package/dist/esm/RenderingEngine/SequentialRenderingEngine.d.ts +18 -0
  8. package/dist/esm/RenderingEngine/SequentialRenderingEngine.js +235 -0
  9. package/dist/esm/RenderingEngine/StackViewport.d.ts +2 -0
  10. package/dist/esm/RenderingEngine/StackViewport.js +71 -3
  11. package/dist/esm/RenderingEngine/StandardRenderingEngine.d.ts +23 -0
  12. package/dist/esm/RenderingEngine/StandardRenderingEngine.js +285 -0
  13. package/dist/esm/RenderingEngine/helpers/isSequentialRenderingEngine.d.ts +1 -0
  14. package/dist/esm/RenderingEngine/helpers/isSequentialRenderingEngine.js +6 -0
  15. package/dist/esm/RenderingEngine/index.d.ts +4 -1
  16. package/dist/esm/RenderingEngine/index.js +4 -1
  17. package/dist/esm/enums/RenderingEngineModeEnum.d.ts +5 -0
  18. package/dist/esm/enums/RenderingEngineModeEnum.js +6 -0
  19. package/dist/esm/enums/index.d.ts +2 -1
  20. package/dist/esm/enums/index.js +2 -1
  21. package/dist/esm/index.d.ts +2 -2
  22. package/dist/esm/index.js +2 -2
  23. package/dist/esm/init.js +2 -0
  24. package/dist/esm/types/Cornerstone3DConfig.d.ts +9 -7
  25. package/dist/esm/types/IRenderingEngine.d.ts +1 -1
  26. package/dist/esm/types/RenderingEngineMode.d.ts +2 -0
  27. package/dist/esm/types/RenderingEngineMode.js +0 -0
  28. package/dist/esm/types/index.d.ts +2 -1
  29. package/dist/esm/version.d.ts +1 -1
  30. package/dist/esm/version.js +1 -1
  31. 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/IStackViewport';
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
- readonly offScreenCanvasContainer: HTMLDivElement;
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;