@cornerstonejs/core 2.0.0-beta.26 → 2.0.0-beta.28
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/BaseVolumeViewport.d.ts +5 -1
- package/dist/esm/RenderingEngine/BaseVolumeViewport.js +56 -32
- package/dist/esm/RenderingEngine/RenderingEngine.js +7 -3
- package/dist/esm/RenderingEngine/StackViewport.d.ts +1 -2
- package/dist/esm/RenderingEngine/StackViewport.js +70 -85
- package/dist/esm/RenderingEngine/VideoViewport.js +50 -25
- package/dist/esm/RenderingEngine/Viewport.d.ts +3 -1
- package/dist/esm/RenderingEngine/Viewport.js +14 -8
- package/dist/esm/RenderingEngine/VolumeViewport.d.ts +1 -1
- package/dist/esm/RenderingEngine/VolumeViewport.js +15 -17
- package/dist/esm/RenderingEngine/VolumeViewport3D.d.ts +4 -1
- package/dist/esm/RenderingEngine/VolumeViewport3D.js +23 -3
- package/dist/esm/RenderingEngine/WSIViewport.d.ts +1 -1
- package/dist/esm/RenderingEngine/WSIViewport.js +31 -18
- package/dist/esm/RenderingEngine/helpers/createVolumeActor.js +2 -0
- package/dist/esm/RenderingEngine/helpers/setDefaultVolumeVOI.js +10 -11
- package/dist/esm/cache/cache.d.ts +1 -1
- package/dist/esm/cache/cache.js +8 -2
- package/dist/esm/cache/classes/StreamingDynamicImageVolume.js +2 -0
- package/dist/esm/enums/Events.d.ts +1 -1
- package/dist/esm/enums/Events.js +1 -1
- package/dist/esm/loaders/configuration/interleavedRetrieve.js +0 -3
- package/dist/esm/loaders/configuration/singleRetrieve.js +0 -3
- package/dist/esm/loaders/imageLoader.d.ts +9 -4
- package/dist/esm/loaders/imageLoader.js +55 -42
- package/dist/esm/loaders/index.d.ts +6 -0
- package/dist/esm/loaders/index.js +7 -0
- package/dist/esm/loaders/volumeLoader.d.ts +8 -4
- package/dist/esm/loaders/volumeLoader.js +26 -7
- package/dist/esm/types/AABB2.js +0 -1
- package/dist/esm/types/AABB3.js +0 -1
- package/dist/esm/types/ActorSliceRange.js +0 -1
- package/dist/esm/types/AffineMatrix.js +0 -1
- package/dist/esm/types/BoundsIJK.js +0 -1
- package/dist/esm/types/BoundsLPS.js +0 -1
- package/dist/esm/types/CPUFallbackColormap.js +0 -1
- package/dist/esm/types/CPUFallbackColormapData.js +0 -1
- package/dist/esm/types/CPUFallbackColormapsData.js +0 -1
- package/dist/esm/types/CPUFallbackEnabledElement.js +0 -1
- package/dist/esm/types/CPUFallbackLUT.js +0 -1
- package/dist/esm/types/CPUFallbackLookupTable.js +0 -1
- package/dist/esm/types/CPUFallbackRenderingTools.js +0 -1
- package/dist/esm/types/CPUFallbackTransform.js +0 -1
- package/dist/esm/types/CPUFallbackViewport.js +0 -1
- package/dist/esm/types/CPUFallbackViewportDisplayedArea.js +0 -1
- package/dist/esm/types/CPUIImageData.js +0 -1
- package/dist/esm/types/Color.js +0 -1
- package/dist/esm/types/Colormap.js +0 -1
- package/dist/esm/types/ContourData.js +0 -1
- package/dist/esm/types/Cornerstone3DConfig.js +0 -1
- package/dist/esm/types/CustomEventType.js +0 -1
- package/dist/esm/types/EventTypes.js +0 -1
- package/dist/esm/types/FlipDirection.js +0 -1
- package/dist/esm/types/IActor.js +0 -1
- package/dist/esm/types/IBaseVolumeViewport.js +0 -1
- package/dist/esm/types/ICache.js +0 -1
- package/dist/esm/types/ICachedGeometry.js +0 -1
- package/dist/esm/types/ICachedImage.js +0 -1
- package/dist/esm/types/ICachedVolume.js +0 -1
- package/dist/esm/types/ICamera.js +0 -1
- package/dist/esm/types/IContour.js +0 -1
- package/dist/esm/types/IContourSet.js +0 -1
- package/dist/esm/types/IDynamicImageVolume.js +0 -1
- package/dist/esm/types/IEnabledElement.js +0 -1
- package/dist/esm/types/IGeometry.js +0 -1
- package/dist/esm/types/IImage.js +0 -1
- package/dist/esm/types/IImageCalibration.js +0 -1
- package/dist/esm/types/IImageData.js +0 -1
- package/dist/esm/types/IImageFrame.js +0 -1
- package/dist/esm/types/IImageVolume.js +0 -1
- package/dist/esm/types/ILoadObject.js +0 -1
- package/dist/esm/types/IPointsManager.js +0 -1
- package/dist/esm/types/IRLEVoxelMap.js +0 -1
- package/dist/esm/types/IRegisterImageLoader.js +0 -1
- package/dist/esm/types/IRenderingEngine.js +0 -1
- package/dist/esm/types/IRetrieveConfiguration.js +0 -1
- package/dist/esm/types/IStackInput.js +0 -1
- package/dist/esm/types/IStackViewport.js +0 -1
- package/dist/esm/types/IStreamingImageVolume.js +0 -1
- package/dist/esm/types/IStreamingVolumeProperties.js +0 -1
- package/dist/esm/types/ISurface.js +0 -1
- package/dist/esm/types/ITransferFunctionNode.js +0 -1
- package/dist/esm/types/IVideoViewport.js +0 -1
- package/dist/esm/types/IViewport.js +0 -1
- package/dist/esm/types/IViewportId.js +0 -1
- package/dist/esm/types/IVolume.js +0 -1
- package/dist/esm/types/IVolumeInput.js +0 -1
- package/dist/esm/types/IVolumeViewport.js +0 -1
- package/dist/esm/types/IVoxelManager.js +0 -1
- package/dist/esm/types/IWSIViewport.js +0 -1
- package/dist/esm/types/ImageLoadListener.js +0 -1
- package/dist/esm/types/ImageLoadRequests.js +0 -1
- package/dist/esm/types/ImageLoaderFn.js +0 -1
- package/dist/esm/types/ImagePixelModule.js +0 -1
- package/dist/esm/types/ImagePlaneModule.js +0 -1
- package/dist/esm/types/ImageSliceData.js +0 -1
- package/dist/esm/types/ImageVolumeProps.js +0 -1
- package/dist/esm/types/Mat3.js +0 -1
- package/dist/esm/types/Metadata.js +0 -1
- package/dist/esm/types/MetadataModuleTypes.d.ts +4 -4
- package/dist/esm/types/MetadataModuleTypes.js +0 -1
- package/dist/esm/types/OrientationVectors.js +0 -1
- package/dist/esm/types/PixelDataTypedArray.js +0 -1
- package/dist/esm/types/Plane.js +0 -1
- package/dist/esm/types/Point2.js +0 -1
- package/dist/esm/types/Point3.js +0 -1
- package/dist/esm/types/Point4.js +0 -1
- package/dist/esm/types/RGB.js +0 -1
- package/dist/esm/types/ScalingParameters.js +0 -1
- package/dist/esm/types/StackViewportProperties.js +0 -1
- package/dist/esm/types/SurfaceData.js +0 -1
- package/dist/esm/types/TransformMatrix2D.js +0 -1
- package/dist/esm/types/VideoViewportProperties.js +0 -1
- package/dist/esm/types/VideoViewportTypes.js +0 -1
- package/dist/esm/types/ViewportInputOptions.js +0 -1
- package/dist/esm/types/ViewportPreset.js +0 -1
- package/dist/esm/types/ViewportProperties.d.ts +1 -0
- package/dist/esm/types/ViewportProperties.js +0 -1
- package/dist/esm/types/VolumeLoaderFn.js +0 -1
- package/dist/esm/types/VolumeProps.js +0 -1
- package/dist/esm/types/VolumeViewportProperties.js +0 -1
- package/dist/esm/types/WSIViewportProperties.js +0 -1
- package/dist/esm/types/displayArea.js +0 -1
- package/dist/esm/types/index.js +0 -1
- package/dist/esm/types/voi.js +0 -1
- package/dist/esm/utilities/VoxelManager.d.ts +3 -1
- package/dist/esm/utilities/VoxelManager.js +15 -9
- package/dist/esm/utilities/autoLoad.js +1 -1
- package/dist/esm/utilities/convertVolumeToStackViewport.js +1 -3
- package/dist/esm/utilities/createSigmoidRGBTransferFunction.d.ts +2 -1
- package/dist/esm/utilities/deepClone.d.ts +1 -0
- package/dist/esm/utilities/deepClone.js +28 -0
- package/dist/esm/utilities/eventListener/TargetEventListeners.js +1 -1
- package/dist/esm/utilities/getViewportImageIds.js +1 -3
- package/dist/esm/utilities/getViewportModality.js +1 -1
- package/dist/esm/utilities/getViewportsWithImageURI.d.ts +3 -3
- package/dist/esm/utilities/getViewportsWithImageURI.js +2 -9
- package/dist/esm/utilities/getViewportsWithVolumeId.d.ts +1 -1
- package/dist/esm/utilities/getViewportsWithVolumeId.js +3 -5
- package/dist/esm/utilities/getViewportsWithVolumeURI.d.ts +3 -0
- package/dist/esm/utilities/getViewportsWithVolumeURI.js +14 -0
- package/dist/esm/utilities/index.d.ts +3 -1
- package/dist/esm/utilities/index.js +3 -1
- package/dist/esm/utilities/loadImageToCanvas.js +0 -4
- package/dist/esm/utilities/pointInShapeCallback.d.ts +24 -0
- package/dist/esm/utilities/pointInShapeCallback.js +92 -0
- package/dist/esm/webWorkerManager/webWorkerManager.d.ts +11 -4
- package/package.json +56 -29
- package/dist/umd/index.js +0 -2
- package/dist/umd/index.js.map +0 -1
|
@@ -7,6 +7,8 @@ import Viewport from './Viewport';
|
|
|
7
7
|
import { getOrCreateCanvas } from './helpers';
|
|
8
8
|
import CanvasActor from './CanvasActor';
|
|
9
9
|
import cache from '../cache/cache';
|
|
10
|
+
import uuidv4 from '../utilities/uuidv4';
|
|
11
|
+
import { pointInShapeCallback } from '../utilities/pointInShapeCallback';
|
|
10
12
|
class VideoViewport extends Viewport {
|
|
11
13
|
static { this.frameRangeExtractor = /(\/frames\/|[&?]frameNumber=)([^/&?]*)/i; }
|
|
12
14
|
constructor(props) {
|
|
@@ -110,12 +112,14 @@ class VideoViewport extends Viewport {
|
|
|
110
112
|
this.renderFrame();
|
|
111
113
|
};
|
|
112
114
|
this.renderFrame = () => {
|
|
115
|
+
const dpr = window.devicePixelRatio || 1;
|
|
113
116
|
const transform = this.getTransform();
|
|
114
117
|
const transformationMatrix = transform.getMatrix();
|
|
115
118
|
const ctx = this.canvasContext;
|
|
116
119
|
ctx.resetTransform();
|
|
117
|
-
ctx.
|
|
118
|
-
ctx.
|
|
120
|
+
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
121
|
+
ctx.transform(transformationMatrix[0] / dpr, transformationMatrix[1] / dpr, transformationMatrix[2] / dpr, transformationMatrix[3] / dpr, transformationMatrix[4] / dpr, transformationMatrix[5] / dpr);
|
|
122
|
+
ctx.drawImage(this.videoElement, 0, 0, this.videoWidth, this.videoHeight);
|
|
119
123
|
for (const actor of this.getActors()) {
|
|
120
124
|
actor.actor.render(this, this.canvasContext);
|
|
121
125
|
}
|
|
@@ -138,7 +142,7 @@ class VideoViewport extends Viewport {
|
|
|
138
142
|
time: this.videoElement.currentTime,
|
|
139
143
|
duration: this.videoElement.duration,
|
|
140
144
|
});
|
|
141
|
-
this.initialRender();
|
|
145
|
+
this.initialRender?.();
|
|
142
146
|
const frame = this.getFrameNumber();
|
|
143
147
|
if (this.isPlaying) {
|
|
144
148
|
if (frame < this.frameRange[0]) {
|
|
@@ -225,7 +229,7 @@ class VideoViewport extends Viewport {
|
|
|
225
229
|
};
|
|
226
230
|
}
|
|
227
231
|
setDataIds(imageIds, options) {
|
|
228
|
-
this.setVideo(imageIds[0], (options.viewReference
|
|
232
|
+
this.setVideo(imageIds[0], (options.viewReference?.sliceIndex || 0) + 1);
|
|
229
233
|
}
|
|
230
234
|
setVideo(imageId, frameNumber) {
|
|
231
235
|
this.imageId = Array.isArray(imageId) ? imageId[0] : imageId;
|
|
@@ -423,15 +427,24 @@ class VideoViewport extends Viewport {
|
|
|
423
427
|
});
|
|
424
428
|
}
|
|
425
429
|
getScalarData() {
|
|
426
|
-
if (this.scalarData
|
|
430
|
+
if (this.scalarData?.frameNumber === this.getFrameNumber()) {
|
|
427
431
|
return this.scalarData;
|
|
428
432
|
}
|
|
433
|
+
if (!this.videoElement ||
|
|
434
|
+
!this.videoElement.videoWidth ||
|
|
435
|
+
!this.videoElement.videoHeight) {
|
|
436
|
+
console.debug('Video not ready yet, returning empty scalar data');
|
|
437
|
+
const emptyData = new Uint8ClampedArray();
|
|
438
|
+
emptyData.getRange = () => [0, 255];
|
|
439
|
+
emptyData.frameNumber = -1;
|
|
440
|
+
return emptyData;
|
|
441
|
+
}
|
|
429
442
|
const canvas = document.createElement('canvas');
|
|
430
|
-
canvas.width = this.videoWidth;
|
|
431
|
-
canvas.height = this.videoHeight;
|
|
443
|
+
canvas.width = this.videoElement.videoWidth;
|
|
444
|
+
canvas.height = this.videoElement.videoHeight;
|
|
432
445
|
const context = canvas.getContext('2d');
|
|
433
446
|
context.drawImage(this.videoElement, 0, 0);
|
|
434
|
-
const canvasData = context.getImageData(0, 0,
|
|
447
|
+
const canvasData = context.getImageData(0, 0, canvas.width, canvas.height);
|
|
435
448
|
const scalarData = canvasData.data;
|
|
436
449
|
scalarData.getRange = () => [0, 255];
|
|
437
450
|
scalarData.frameNumber = this.getFrameNumber();
|
|
@@ -442,6 +455,22 @@ class VideoViewport extends Viewport {
|
|
|
442
455
|
const { metadata } = this;
|
|
443
456
|
const spacing = metadata.spacing;
|
|
444
457
|
const imageData = {
|
|
458
|
+
getDirection: () => metadata.direction,
|
|
459
|
+
getDimensions: () => metadata.dimensions,
|
|
460
|
+
getRange: () => [0, 255],
|
|
461
|
+
getScalarData: () => this.getScalarData(),
|
|
462
|
+
getSpacing: () => metadata.spacing,
|
|
463
|
+
worldToIndex: (point) => {
|
|
464
|
+
const canvasPoint = this.worldToCanvas(point);
|
|
465
|
+
const pixelCoord = this.canvasToIndex(canvasPoint);
|
|
466
|
+
return [pixelCoord[0], pixelCoord[1], 0];
|
|
467
|
+
},
|
|
468
|
+
indexToWorld: (point, destPoint) => {
|
|
469
|
+
const canvasPoint = this.indexToCanvas([point[0], point[1]]);
|
|
470
|
+
return this.canvasToWorld(canvasPoint, destPoint);
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
const imageDataForReturn = {
|
|
445
474
|
dimensions: metadata.dimensions,
|
|
446
475
|
spacing,
|
|
447
476
|
origin: metadata.origin,
|
|
@@ -452,20 +481,15 @@ class VideoViewport extends Viewport {
|
|
|
452
481
|
},
|
|
453
482
|
getScalarData: () => this.getScalarData(),
|
|
454
483
|
scalarData: this.getScalarData(),
|
|
455
|
-
imageData
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
return [pixelCoord[0], pixelCoord[1], 0];
|
|
465
|
-
},
|
|
466
|
-
indexToWorld: (point, destPoint) => {
|
|
467
|
-
const canvasPoint = this.indexToCanvas([point[0], point[1]]);
|
|
468
|
-
return this.canvasToWorld(canvasPoint, destPoint);
|
|
484
|
+
imageData,
|
|
485
|
+
voxelManager: {
|
|
486
|
+
forEach: (callback, options) => {
|
|
487
|
+
return pointInShapeCallback(options.imageData, {
|
|
488
|
+
pointInShapeFn: options.isInObject ?? (() => true),
|
|
489
|
+
callback: callback,
|
|
490
|
+
boundsIJK: options.boundsIJK,
|
|
491
|
+
returnPoints: options.returnPoints ?? false,
|
|
492
|
+
});
|
|
469
493
|
},
|
|
470
494
|
},
|
|
471
495
|
hasPixelSpacing: this.hasPixelSpacing,
|
|
@@ -478,7 +502,7 @@ class VideoViewport extends Viewport {
|
|
|
478
502
|
get: () => this.getScalarData(),
|
|
479
503
|
enumerable: true,
|
|
480
504
|
});
|
|
481
|
-
return
|
|
505
|
+
return imageDataForReturn;
|
|
482
506
|
}
|
|
483
507
|
hasImageURI(imageURI) {
|
|
484
508
|
const framesMatch = imageURI.match(VideoViewport.frameRangeExtractor);
|
|
@@ -612,7 +636,7 @@ class VideoViewport extends Viewport {
|
|
|
612
636
|
}
|
|
613
637
|
}
|
|
614
638
|
getViewReference(viewRefSpecifier) {
|
|
615
|
-
let sliceIndex = viewRefSpecifier.
|
|
639
|
+
let sliceIndex = viewRefSpecifier?.sliceIndex ?? this.getSliceIndex();
|
|
616
640
|
if (!sliceIndex) {
|
|
617
641
|
sliceIndex = this.isPlaying
|
|
618
642
|
? [this.frameRange[0] - 1, this.frameRange[1] - 1]
|
|
@@ -704,8 +728,9 @@ class VideoViewport extends Viewport {
|
|
|
704
728
|
stackInputs.forEach((stackInput) => {
|
|
705
729
|
const image = cache.getImage(stackInput.imageId);
|
|
706
730
|
const imageActor = this.createActorMapper(image);
|
|
731
|
+
const uid = stackInput.actorUID ?? uuidv4();
|
|
707
732
|
if (imageActor) {
|
|
708
|
-
actors.push({ uid
|
|
733
|
+
actors.push({ uid, actor: imageActor });
|
|
709
734
|
if (stackInput.callback) {
|
|
710
735
|
stackInput.callback({
|
|
711
736
|
imageActor: imageActor,
|
|
@@ -77,7 +77,9 @@ declare class Viewport {
|
|
|
77
77
|
setActors(actors: ActorEntry[]): void;
|
|
78
78
|
_removeActor(actorUID: string): void;
|
|
79
79
|
removeActors(actorUIDs: string[]): void;
|
|
80
|
-
addActors(actors: ActorEntry[],
|
|
80
|
+
addActors(actors: ActorEntry[], options?: {
|
|
81
|
+
resetCamera?: boolean;
|
|
82
|
+
}): void;
|
|
81
83
|
addActor(actorEntry: ActorEntry): void;
|
|
82
84
|
removeAllActors(): void;
|
|
83
85
|
protected resetCameraNoEvent(): void;
|
|
@@ -199,8 +199,7 @@ class Viewport {
|
|
|
199
199
|
}
|
|
200
200
|
setActors(actors) {
|
|
201
201
|
this.removeAllActors();
|
|
202
|
-
|
|
203
|
-
this.addActors(actors, resetCameraPanAndZoom);
|
|
202
|
+
this.addActors(actors, { resetCamera: true });
|
|
204
203
|
}
|
|
205
204
|
_removeActor(actorUID) {
|
|
206
205
|
const actorEntry = this.getActor(actorUID);
|
|
@@ -217,7 +216,8 @@ class Viewport {
|
|
|
217
216
|
this._removeActor(actorUID);
|
|
218
217
|
});
|
|
219
218
|
}
|
|
220
|
-
addActors(actors,
|
|
219
|
+
addActors(actors, options = {}) {
|
|
220
|
+
const { resetCamera = false } = options;
|
|
221
221
|
const renderingEngine = this.getRenderingEngine();
|
|
222
222
|
if (!renderingEngine || renderingEngine.hasBeenDestroyed) {
|
|
223
223
|
console.warn('Viewport::addActors::Rendering engine has not been initialized or has been destroyed');
|
|
@@ -226,10 +226,13 @@ class Viewport {
|
|
|
226
226
|
actors.forEach((actor) => {
|
|
227
227
|
this.addActor(actor);
|
|
228
228
|
});
|
|
229
|
-
this.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
const prevViewPresentation = this.getViewPresentation();
|
|
230
|
+
const prevViewRef = this.getViewReference();
|
|
231
|
+
this.resetCamera();
|
|
232
|
+
if (!resetCamera) {
|
|
233
|
+
this.setViewReference(prevViewRef);
|
|
234
|
+
this.setViewPresentation(prevViewPresentation);
|
|
235
|
+
}
|
|
233
236
|
}
|
|
234
237
|
addActor(actorEntry) {
|
|
235
238
|
const { uid: actorUID, actor } = actorEntry;
|
|
@@ -498,6 +501,9 @@ class Viewport {
|
|
|
498
501
|
this.fitToCanvasCamera = camera;
|
|
499
502
|
}
|
|
500
503
|
getPan(initialCamera = this.initialCamera) {
|
|
504
|
+
if (!initialCamera) {
|
|
505
|
+
return [0, 0];
|
|
506
|
+
}
|
|
501
507
|
const activeCamera = this.getVtkActiveCamera();
|
|
502
508
|
const focalPoint = activeCamera.getFocalPoint();
|
|
503
509
|
const zero3 = this.canvasToWorld([0, 0]);
|
|
@@ -664,7 +670,7 @@ class Viewport {
|
|
|
664
670
|
}
|
|
665
671
|
if (cameraModifiedOutOfPlane || viewUpHasChanged) {
|
|
666
672
|
const actorEntry = this.getDefaultActor();
|
|
667
|
-
if (!actorEntry
|
|
673
|
+
if (!actorEntry?.actor) {
|
|
668
674
|
return;
|
|
669
675
|
}
|
|
670
676
|
if (!actorIsA(actorEntry, 'vtkActor')) {
|
|
@@ -11,6 +11,7 @@ declare class VolumeViewport extends BaseVolumeViewport {
|
|
|
11
11
|
getNumberOfSlices: () => number;
|
|
12
12
|
addVolumes(volumeInputArray: IVolumeInput[], immediate?: boolean, suppressEvents?: boolean): Promise<void>;
|
|
13
13
|
setOrientation(orientation: OrientationAxis | OrientationVectors, immediate?: boolean): void;
|
|
14
|
+
protected setCameraClippingRange(): void;
|
|
14
15
|
private _getAcquisitionPlaneOrientation;
|
|
15
16
|
private _setViewPlaneToAcquisitionPlane;
|
|
16
17
|
setBlendMode(blendMode: BlendModes, filterActorUIDs?: any[], immediate?: boolean): void;
|
|
@@ -33,7 +34,6 @@ declare class VolumeViewport extends BaseVolumeViewport {
|
|
|
33
34
|
getViewReference(viewRefSpecifier?: ViewReferenceSpecifier): ViewReference;
|
|
34
35
|
resetProperties(volumeId?: string): void;
|
|
35
36
|
private _resetProperties;
|
|
36
|
-
private setCameraClippingRange;
|
|
37
37
|
getSlicesClippingPlanes(): {
|
|
38
38
|
sliceIndex: number;
|
|
39
39
|
planes: {
|
|
@@ -54,8 +54,7 @@ class VolumeViewport extends BaseVolumeViewport {
|
|
|
54
54
|
if (!actorEntry || !actorIsA(actorEntry, 'vtkVolume')) {
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
|
-
const
|
|
58
|
-
const volume = cache.getVolume(uid);
|
|
57
|
+
const volume = cache.getVolume(this.getVolumeId());
|
|
59
58
|
if (!volume) {
|
|
60
59
|
return;
|
|
61
60
|
}
|
|
@@ -68,7 +67,7 @@ class VolumeViewport extends BaseVolumeViewport {
|
|
|
68
67
|
console.warn('No image data found for calculating vtkPlanes.');
|
|
69
68
|
return [];
|
|
70
69
|
}
|
|
71
|
-
const volumeId =
|
|
70
|
+
const volumeId = this.getVolumeId();
|
|
72
71
|
const imageVolume = cache.getVolume(volumeId);
|
|
73
72
|
const camera = this.getCamera();
|
|
74
73
|
const { focalPoint, position, viewPlaneNormal } = camera;
|
|
@@ -140,12 +139,21 @@ class VolumeViewport extends BaseVolumeViewport {
|
|
|
140
139
|
this.render();
|
|
141
140
|
}
|
|
142
141
|
}
|
|
142
|
+
setCameraClippingRange() {
|
|
143
|
+
const activeCamera = this.getVtkActiveCamera();
|
|
144
|
+
if (activeCamera.getParallelProjection()) {
|
|
145
|
+
activeCamera.setClippingRange(activeCamera.getDistance(), activeCamera.getDistance() + this.getSlabThickness());
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
activeCamera.setClippingRange(RENDERING_DEFAULTS.MINIMUM_SLAB_THICKNESS, RENDERING_DEFAULTS.MAXIMUM_RAY_DISTANCE);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
143
151
|
_getAcquisitionPlaneOrientation() {
|
|
144
152
|
const actorEntry = this.getDefaultActor();
|
|
145
153
|
if (!actorEntry) {
|
|
146
154
|
return;
|
|
147
155
|
}
|
|
148
|
-
const volumeId =
|
|
156
|
+
const volumeId = this.getVolumeId();
|
|
149
157
|
const imageVolume = cache.getVolume(volumeId);
|
|
150
158
|
if (!imageVolume) {
|
|
151
159
|
throw new Error(`imageVolume with id: ${volumeId} does not exist in cache`);
|
|
@@ -199,7 +207,6 @@ class VolumeViewport extends BaseVolumeViewport {
|
|
|
199
207
|
}
|
|
200
208
|
super.resetCamera({ resetPan, resetZoom, resetToCenter });
|
|
201
209
|
const activeCamera = this.getVtkActiveCamera();
|
|
202
|
-
this.setCameraClippingRange();
|
|
203
210
|
const viewPlaneNormal = activeCamera.getViewPlaneNormal();
|
|
204
211
|
const focalPoint = activeCamera.getFocalPoint();
|
|
205
212
|
const actorEntries = this.getActors();
|
|
@@ -258,7 +265,6 @@ class VolumeViewport extends BaseVolumeViewport {
|
|
|
258
265
|
});
|
|
259
266
|
const currentCamera = this.getCamera();
|
|
260
267
|
this.updateClippingPlanesForActors(currentCamera);
|
|
261
|
-
this.setCameraClippingRange();
|
|
262
268
|
this.triggerCameraModifiedEventIfNecessary(currentCamera, currentCamera);
|
|
263
269
|
this.viewportProperties.slabThickness = slabThickness;
|
|
264
270
|
}
|
|
@@ -366,9 +372,10 @@ class VolumeViewport extends BaseVolumeViewport {
|
|
|
366
372
|
this.viewportProperties.slabThickness = undefined;
|
|
367
373
|
this.updateClippingPlanesForActors(this.getCamera());
|
|
368
374
|
}
|
|
369
|
-
|
|
375
|
+
volumeId ||= this.getVolumeId();
|
|
376
|
+
const imageVolume = cache.getVolume(volumeId);
|
|
370
377
|
if (!imageVolume) {
|
|
371
|
-
throw new Error(`imageVolume with id: ${
|
|
378
|
+
throw new Error(`imageVolume with id: ${volumeId} does not exist in cache`);
|
|
372
379
|
}
|
|
373
380
|
setDefaultVolumeVOI(volumeActor.actor, imageVolume);
|
|
374
381
|
if (isImageActor(volumeActor)) {
|
|
@@ -392,15 +399,6 @@ class VolumeViewport extends BaseVolumeViewport {
|
|
|
392
399
|
});
|
|
393
400
|
triggerEvent(this.element, Events.VOI_MODIFIED, eventDetails);
|
|
394
401
|
}
|
|
395
|
-
setCameraClippingRange() {
|
|
396
|
-
const activeCamera = this.getVtkActiveCamera();
|
|
397
|
-
if (activeCamera.getParallelProjection()) {
|
|
398
|
-
activeCamera.setClippingRange(activeCamera.getDistance(), activeCamera.getDistance() + this.getSlabThickness());
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
activeCamera.setClippingRange(RENDERING_DEFAULTS.MINIMUM_SLAB_THICKNESS, RENDERING_DEFAULTS.MAXIMUM_RAY_DISTANCE);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
402
|
getSlicesClippingPlanes() {
|
|
405
403
|
const focalPoints = this.getSlicePlaneCoordinates();
|
|
406
404
|
const { viewPlaneNormal } = this.getCamera();
|
|
@@ -3,7 +3,7 @@ import type { ViewportInput } from '../types/IViewport';
|
|
|
3
3
|
import BaseVolumeViewport from './BaseVolumeViewport';
|
|
4
4
|
declare class VolumeViewport3D extends BaseVolumeViewport {
|
|
5
5
|
constructor(props: ViewportInput);
|
|
6
|
-
resetCamera({ resetPan, resetZoom, resetToCenter, }
|
|
6
|
+
resetCamera({ resetPan, resetZoom, resetToCenter, }?: {
|
|
7
7
|
resetPan?: boolean;
|
|
8
8
|
resetZoom?: boolean;
|
|
9
9
|
resetToCenter?: boolean;
|
|
@@ -14,6 +14,9 @@ declare class VolumeViewport3D extends BaseVolumeViewport {
|
|
|
14
14
|
setSlabThickness(slabThickness: number, filterActorUIDs?: string[]): void;
|
|
15
15
|
setBlendMode(blendMode: BlendModes, filterActorUIDs?: string[], immediate?: boolean): void;
|
|
16
16
|
resetProperties(volumeId?: string): void;
|
|
17
|
+
resetCameraForResize: () => boolean;
|
|
18
|
+
getSliceIndex(): number;
|
|
19
|
+
protected setCameraClippingRange(): void;
|
|
17
20
|
resetSlabThickness(): void;
|
|
18
21
|
}
|
|
19
22
|
export default VolumeViewport3D;
|
|
@@ -16,6 +16,13 @@ class VolumeViewport3D extends BaseVolumeViewport {
|
|
|
16
16
|
this.getCurrentImageId = () => {
|
|
17
17
|
return null;
|
|
18
18
|
};
|
|
19
|
+
this.resetCameraForResize = () => {
|
|
20
|
+
return this.resetCamera({
|
|
21
|
+
resetPan: true,
|
|
22
|
+
resetZoom: true,
|
|
23
|
+
resetToCenter: true,
|
|
24
|
+
});
|
|
25
|
+
};
|
|
19
26
|
const { parallelProjection, orientation } = this.options;
|
|
20
27
|
const activeCamera = this.getVtkActiveCamera();
|
|
21
28
|
if (parallelProjection != null) {
|
|
@@ -25,7 +32,7 @@ class VolumeViewport3D extends BaseVolumeViewport {
|
|
|
25
32
|
this.applyViewOrientation(orientation);
|
|
26
33
|
}
|
|
27
34
|
}
|
|
28
|
-
resetCamera({ resetPan = true, resetZoom = true, resetToCenter = true, }) {
|
|
35
|
+
resetCamera({ resetPan = true, resetZoom = true, resetToCenter = true, } = {}) {
|
|
29
36
|
super.resetCamera({ resetPan, resetZoom, resetToCenter });
|
|
30
37
|
const activeCamera = this.getVtkActiveCamera();
|
|
31
38
|
if (activeCamera.getParallelProjection()) {
|
|
@@ -54,9 +61,10 @@ class VolumeViewport3D extends BaseVolumeViewport {
|
|
|
54
61
|
this.viewportProperties.slabThickness = undefined;
|
|
55
62
|
this.updateClippingPlanesForActors(this.getCamera());
|
|
56
63
|
}
|
|
57
|
-
|
|
64
|
+
volumeId ||= this.getVolumeId();
|
|
65
|
+
const imageVolume = cache.getVolume(volumeId);
|
|
58
66
|
if (!imageVolume) {
|
|
59
|
-
throw new Error(`imageVolume with id: ${
|
|
67
|
+
throw new Error(`imageVolume with id: ${volumeId} does not exist in cache`);
|
|
60
68
|
}
|
|
61
69
|
setDefaultVolumeVOI(volumeActor.actor, imageVolume);
|
|
62
70
|
if (isImageActor(volumeActor)) {
|
|
@@ -68,6 +76,18 @@ class VolumeViewport3D extends BaseVolumeViewport {
|
|
|
68
76
|
this.setCamera(this.initialCamera);
|
|
69
77
|
triggerEvent(this.element, Events.VOI_MODIFIED, super.getVOIModifiedEventDetail(volumeId));
|
|
70
78
|
}
|
|
79
|
+
getSliceIndex() {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
setCameraClippingRange() {
|
|
83
|
+
const activeCamera = this.getVtkActiveCamera();
|
|
84
|
+
if (activeCamera.getParallelProjection()) {
|
|
85
|
+
activeCamera.setClippingRange(-RENDERING_DEFAULTS.MAXIMUM_RAY_DISTANCE, RENDERING_DEFAULTS.MAXIMUM_RAY_DISTANCE);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
activeCamera.setClippingRange(RENDERING_DEFAULTS.MINIMUM_SLAB_THICKNESS, RENDERING_DEFAULTS.MAXIMUM_RAY_DISTANCE);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
71
91
|
resetSlabThickness() {
|
|
72
92
|
return null;
|
|
73
93
|
}
|
|
@@ -52,7 +52,7 @@ declare class WSIViewport extends Viewport {
|
|
|
52
52
|
getZoom(): any;
|
|
53
53
|
setZoom(zoom: number): void;
|
|
54
54
|
protected getTransform(): Transform;
|
|
55
|
-
|
|
55
|
+
getViewReferenceId(): string;
|
|
56
56
|
getCurrentImageIdIndex(): number;
|
|
57
57
|
}
|
|
58
58
|
export default WSIViewport;
|
|
@@ -8,6 +8,7 @@ import { getOrCreateCanvas } from './helpers';
|
|
|
8
8
|
import { EPSILON } from '../constants';
|
|
9
9
|
import triggerEvent from '../utilities/triggerEvent';
|
|
10
10
|
import { peerImport } from '../init';
|
|
11
|
+
import { pointInShapeCallback } from '../utilities/pointInShapeCallback';
|
|
11
12
|
const _map = Symbol.for('map');
|
|
12
13
|
const EVENT_POSTRENDER = 'postrender';
|
|
13
14
|
class WSIViewport extends Viewport {
|
|
@@ -186,7 +187,23 @@ class WSIViewport extends Viewport {
|
|
|
186
187
|
return null;
|
|
187
188
|
}
|
|
188
189
|
const { spacing } = metadata;
|
|
189
|
-
|
|
190
|
+
const imageData = {
|
|
191
|
+
getDirection: () => metadata.direction,
|
|
192
|
+
getDimensions: () => metadata.dimensions,
|
|
193
|
+
getRange: () => [0, 255],
|
|
194
|
+
getScalarData: () => this.getScalarData(),
|
|
195
|
+
getSpacing: () => metadata.spacing,
|
|
196
|
+
worldToIndex: (point) => {
|
|
197
|
+
const canvasPoint = this.worldToCanvas(point);
|
|
198
|
+
const pixelCoord = this.canvasToIndex(canvasPoint);
|
|
199
|
+
return [pixelCoord[0], pixelCoord[1], 0];
|
|
200
|
+
},
|
|
201
|
+
indexToWorld: (point) => {
|
|
202
|
+
const canvasPoint = this.indexToCanvas([point[0], point[1]]);
|
|
203
|
+
return this.canvasToWorld(canvasPoint);
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
const imageDataReturn = {
|
|
190
207
|
dimensions: metadata.dimensions,
|
|
191
208
|
spacing,
|
|
192
209
|
numberOfComponents: 3,
|
|
@@ -196,29 +213,25 @@ class WSIViewport extends Viewport {
|
|
|
196
213
|
Modality: this.modality,
|
|
197
214
|
FrameOfReferenceUID: this.frameOfReferenceUID,
|
|
198
215
|
},
|
|
199
|
-
imageData: {
|
|
200
|
-
getDirection: () => metadata.direction,
|
|
201
|
-
getDimensions: () => metadata.dimensions,
|
|
202
|
-
getRange: () => [0, 255],
|
|
203
|
-
getScalarData: () => this.getScalarData(),
|
|
204
|
-
getSpacing: () => metadata.spacing,
|
|
205
|
-
worldToIndex: (point) => {
|
|
206
|
-
const canvasPoint = this.worldToCanvas(point);
|
|
207
|
-
const pixelCoord = this.canvasToIndex(canvasPoint);
|
|
208
|
-
return [pixelCoord[0], pixelCoord[1], 0];
|
|
209
|
-
},
|
|
210
|
-
indexToWorld: (point) => {
|
|
211
|
-
const canvasPoint = this.indexToCanvas([point[0], point[1]]);
|
|
212
|
-
return this.canvasToWorld(canvasPoint);
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
216
|
hasPixelSpacing: this.hasPixelSpacing,
|
|
216
217
|
calibration: this.calibration,
|
|
217
218
|
preScale: {
|
|
218
219
|
scaled: false,
|
|
219
220
|
},
|
|
220
221
|
scalarData: this.getScalarData(),
|
|
222
|
+
imageData,
|
|
223
|
+
voxelManager: {
|
|
224
|
+
forEach: (callback, options) => {
|
|
225
|
+
return pointInShapeCallback(options.imageData, {
|
|
226
|
+
pointInShapeFn: options.isInObject ?? (() => true),
|
|
227
|
+
callback: callback,
|
|
228
|
+
boundsIJK: options.boundsIJK,
|
|
229
|
+
returnPoints: options.returnPoints ?? false,
|
|
230
|
+
});
|
|
231
|
+
},
|
|
232
|
+
},
|
|
221
233
|
};
|
|
234
|
+
return imageDataReturn;
|
|
222
235
|
}
|
|
223
236
|
hasImageURI(imageURI) {
|
|
224
237
|
return true;
|
|
@@ -404,7 +417,7 @@ class WSIViewport extends Viewport {
|
|
|
404
417
|
transform.translate(-center[0], -center[1]);
|
|
405
418
|
return transform;
|
|
406
419
|
}
|
|
407
|
-
|
|
420
|
+
getViewReferenceId() {
|
|
408
421
|
return `imageId:${this.getCurrentImageId()}`;
|
|
409
422
|
}
|
|
410
423
|
getCurrentImageIdIndex() {
|
|
@@ -18,6 +18,8 @@ async function createVolumeActor(props, element, viewportId, suppressEvents = fa
|
|
|
18
18
|
const volumeActor = vtkVolume.newInstance();
|
|
19
19
|
volumeActor.setMapper(volumeMapper);
|
|
20
20
|
const { numberOfComponents } = imageData.get('numberOfComponents');
|
|
21
|
+
const volumeProperty = volumeActor.getProperty();
|
|
22
|
+
volumeProperty.set({ viewportId: viewportId });
|
|
21
23
|
if (numberOfComponents === 3) {
|
|
22
24
|
volumeActor.getProperty().setIndependentComponents(false);
|
|
23
25
|
}
|
|
@@ -44,24 +44,23 @@ function getVOIFromMetadata(imageVolume) {
|
|
|
44
44
|
const voiLutModule = metaData.get('voiLutModule', imageId);
|
|
45
45
|
if (voiLutModule?.windowWidth && voiLutModule.windowCenter) {
|
|
46
46
|
const { windowWidth, windowCenter } = voiLutModule;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
const width = Array.isArray(windowWidth) ? windowWidth[0] : windowWidth;
|
|
48
|
+
const center = Array.isArray(windowCenter)
|
|
49
|
+
? windowCenter[0]
|
|
50
|
+
: windowCenter;
|
|
51
|
+
if (width !== 0) {
|
|
52
|
+
voi = { windowWidth: width, windowCenter: center };
|
|
53
|
+
}
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
else {
|
|
56
57
|
voi = metadata.voiLut[0];
|
|
57
58
|
}
|
|
58
|
-
if (voi) {
|
|
59
|
+
if (voi && (voi.windowWidth !== 0 || voi.windowCenter !== 0)) {
|
|
59
60
|
const { lower, upper } = windowLevel.toLowHighRange(Number(voi.windowWidth), Number(voi.windowCenter));
|
|
60
|
-
return {
|
|
61
|
-
lower,
|
|
62
|
-
upper,
|
|
63
|
-
};
|
|
61
|
+
return { lower, upper };
|
|
64
62
|
}
|
|
63
|
+
return undefined;
|
|
65
64
|
}
|
|
66
65
|
async function getVOIFromMiddleSliceMinMax(imageVolume) {
|
|
67
66
|
const { imageIds } = imageVolume;
|
|
@@ -31,7 +31,7 @@ declare class Cache {
|
|
|
31
31
|
getVolumeLoadObject: (volumeId: string) => IVolumeLoadObject | undefined;
|
|
32
32
|
getGeometry: (geometryId: string) => IGeometry | undefined;
|
|
33
33
|
getImage: (imageId: string) => IImage | undefined;
|
|
34
|
-
getVolume: (volumeId: string) => IImageVolume | undefined;
|
|
34
|
+
getVolume: (volumeId: string, allowPartialMatch?: boolean) => IImageVolume | undefined;
|
|
35
35
|
getVolumes: () => IImageVolume[];
|
|
36
36
|
filterVolumesByReferenceId: (volumeId: string) => IImageVolume[];
|
|
37
37
|
removeImageLoadObject: (imageId: string) => void;
|
package/dist/esm/cache/cache.js
CHANGED
|
@@ -133,13 +133,15 @@ class Cache {
|
|
|
133
133
|
cachedImage.timeStamp = Date.now();
|
|
134
134
|
return cachedImage.image;
|
|
135
135
|
};
|
|
136
|
-
this.getVolume = (volumeId) => {
|
|
136
|
+
this.getVolume = (volumeId, allowPartialMatch = false) => {
|
|
137
137
|
if (volumeId === undefined) {
|
|
138
138
|
throw new Error('getVolume: volumeId must not be undefined');
|
|
139
139
|
}
|
|
140
140
|
const cachedVolume = this._volumeCache.get(volumeId);
|
|
141
141
|
if (!cachedVolume) {
|
|
142
|
-
return
|
|
142
|
+
return allowPartialMatch
|
|
143
|
+
? [...this._volumeCache.values()].find((cv) => cv.volumeId.includes(volumeId))?.volume
|
|
144
|
+
: undefined;
|
|
143
145
|
}
|
|
144
146
|
cachedVolume.timeStamp = Date.now();
|
|
145
147
|
return cachedVolume.volume;
|
|
@@ -277,6 +279,10 @@ class Cache {
|
|
|
277
279
|
console.warn('The image was purged from the cache before it completed loading.');
|
|
278
280
|
return;
|
|
279
281
|
}
|
|
282
|
+
if (!image) {
|
|
283
|
+
console.warn('Image is undefined');
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
280
286
|
if (image.sizeInBytes === undefined || Number.isNaN(image.sizeInBytes)) {
|
|
281
287
|
throw new Error('_putImageCommon: image.sizeInBytes must not be undefined');
|
|
282
288
|
}
|
|
@@ -49,6 +49,8 @@ export default class StreamingDynamicImageVolume extends BaseStreamingImageVolum
|
|
|
49
49
|
this.invalidateVolume(true);
|
|
50
50
|
triggerEvent(eventTarget, Events.DYNAMIC_VOLUME_TIME_POINT_INDEX_CHANGED, {
|
|
51
51
|
volumeId: this.volumeId,
|
|
52
|
+
timePointIndex: index,
|
|
53
|
+
numTimePoints: this.numTimePoints,
|
|
52
54
|
imageIdGroupIndex: index,
|
|
53
55
|
numImageIdGroups: this.numTimePoints,
|
|
54
56
|
splittingTag: this.splittingTag,
|
|
@@ -26,7 +26,7 @@ declare enum Events {
|
|
|
26
26
|
VOLUME_NEW_IMAGE = "CORNERSTONE_VOLUME_NEW_IMAGE",
|
|
27
27
|
PRE_STACK_NEW_IMAGE = "CORNERSTONE_PRE_STACK_NEW_IMAGE",
|
|
28
28
|
IMAGE_SPACING_CALIBRATED = "CORNERSTONE_IMAGE_SPACING_CALIBRATED",
|
|
29
|
-
VIEWPORT_NEW_IMAGE_SET = "
|
|
29
|
+
VIEWPORT_NEW_IMAGE_SET = "CORNERSTONE_VIEWPORT_NEW_IMAGE_SET",
|
|
30
30
|
STACK_VIEWPORT_SCROLL = "CORNERSTONE_STACK_VIEWPORT_SCROLL",
|
|
31
31
|
GEOMETRY_CACHE_GEOMETRY_ADDED = "CORNERSTONE_GEOMETRY_CACHE_GEOMETRY_ADDED",
|
|
32
32
|
VOLUME_VIEWPORT_SCROLL_OUT_OF_BOUNDS = "VOLUME_VIEWPORT_SCROLL_OUT_OF_BOUNDS",
|
package/dist/esm/enums/Events.js
CHANGED
|
@@ -27,7 +27,7 @@ var Events;
|
|
|
27
27
|
Events["VOLUME_NEW_IMAGE"] = "CORNERSTONE_VOLUME_NEW_IMAGE";
|
|
28
28
|
Events["PRE_STACK_NEW_IMAGE"] = "CORNERSTONE_PRE_STACK_NEW_IMAGE";
|
|
29
29
|
Events["IMAGE_SPACING_CALIBRATED"] = "CORNERSTONE_IMAGE_SPACING_CALIBRATED";
|
|
30
|
-
Events["VIEWPORT_NEW_IMAGE_SET"] = "
|
|
30
|
+
Events["VIEWPORT_NEW_IMAGE_SET"] = "CORNERSTONE_VIEWPORT_NEW_IMAGE_SET";
|
|
31
31
|
Events["STACK_VIEWPORT_SCROLL"] = "CORNERSTONE_STACK_VIEWPORT_SCROLL";
|
|
32
32
|
Events["GEOMETRY_CACHE_GEOMETRY_ADDED"] = "CORNERSTONE_GEOMETRY_CACHE_GEOMETRY_ADDED";
|
|
33
33
|
Events["VOLUME_VIEWPORT_SCROLL_OUT_OF_BOUNDS"] = "VOLUME_VIEWPORT_SCROLL_OUT_OF_BOUNDS";
|