@cornerstonejs/core 2.0.0-beta.1 → 2.0.0-beta.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/cjs/RenderingEngine/BaseVolumeViewport.d.ts +4 -1
- package/dist/cjs/RenderingEngine/BaseVolumeViewport.js +28 -2
- package/dist/cjs/RenderingEngine/BaseVolumeViewport.js.map +1 -1
- package/dist/cjs/RenderingEngine/RenderingEngine.js.map +1 -1
- package/dist/cjs/RenderingEngine/StackViewport.d.ts +1 -0
- package/dist/cjs/RenderingEngine/StackViewport.js +15 -6
- package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
- package/dist/cjs/RenderingEngine/VolumeViewport.d.ts +2 -0
- package/dist/cjs/RenderingEngine/VolumeViewport.js +17 -0
- package/dist/cjs/RenderingEngine/VolumeViewport.js.map +1 -1
- package/dist/cjs/RenderingEngine/VolumeViewport3D.d.ts +1 -0
- package/dist/cjs/RenderingEngine/VolumeViewport3D.js +3 -0
- package/dist/cjs/RenderingEngine/VolumeViewport3D.js.map +1 -1
- package/dist/cjs/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.js +3 -1
- package/dist/cjs/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.js.map +1 -1
- package/dist/cjs/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.js +3 -2
- package/dist/cjs/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.js.map +1 -1
- package/dist/cjs/RenderingEngine/helpers/setVolumesForViewports.js.map +1 -1
- package/dist/cjs/Settings.js +4 -2
- package/dist/cjs/Settings.js.map +1 -1
- package/dist/cjs/cache/classes/ImageVolume.js +2 -3
- package/dist/cjs/cache/classes/ImageVolume.js.map +1 -1
- package/dist/cjs/init.d.ts +1 -1
- package/dist/cjs/init.js +1 -1
- package/dist/cjs/init.js.map +1 -1
- package/dist/cjs/loaders/volumeLoader.d.ts +1 -1
- package/dist/cjs/loaders/volumeLoader.js.map +1 -1
- package/dist/cjs/requestPool/requestPoolManager.js +1 -1
- package/dist/cjs/requestPool/requestPoolManager.js.map +1 -1
- package/dist/cjs/types/AffineMatrix.d.ts +27 -0
- package/dist/cjs/types/AffineMatrix.js +3 -0
- package/dist/cjs/types/AffineMatrix.js.map +1 -0
- package/dist/cjs/types/IImage.d.ts +1 -0
- package/dist/cjs/types/IVolumeViewport.d.ts +2 -0
- package/dist/cjs/types/Mat3.d.ts +1 -11
- package/dist/cjs/types/ViewportProperties.d.ts +2 -1
- package/dist/cjs/types/index.d.ts +2 -1
- package/dist/cjs/utilities/calculateViewportsSpatialRegistration.js +9 -14
- package/dist/cjs/utilities/calculateViewportsSpatialRegistration.js.map +1 -1
- package/dist/cjs/utilities/getClosestStackImageIndexForPoint.js +12 -6
- package/dist/cjs/utilities/getClosestStackImageIndexForPoint.js.map +1 -1
- package/dist/cjs/utilities/getRuntimeId.js +2 -1
- package/dist/cjs/utilities/getRuntimeId.js.map +1 -1
- package/dist/cjs/utilities/windowLevel.js +4 -4
- package/dist/cjs/utilities/windowLevel.js.map +1 -1
- package/dist/esm/RenderingEngine/BaseVolumeViewport.d.ts +4 -1
- package/dist/esm/RenderingEngine/BaseVolumeViewport.js +28 -2
- package/dist/esm/RenderingEngine/BaseVolumeViewport.js.map +1 -1
- package/dist/esm/RenderingEngine/RenderingEngine.js.map +1 -1
- package/dist/esm/RenderingEngine/StackViewport.d.ts +1 -0
- package/dist/esm/RenderingEngine/StackViewport.js +15 -6
- package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
- package/dist/esm/RenderingEngine/VolumeViewport.d.ts +2 -0
- package/dist/esm/RenderingEngine/VolumeViewport.js +17 -0
- package/dist/esm/RenderingEngine/VolumeViewport.js.map +1 -1
- package/dist/esm/RenderingEngine/VolumeViewport3D.d.ts +1 -0
- package/dist/esm/RenderingEngine/VolumeViewport3D.js +3 -0
- package/dist/esm/RenderingEngine/VolumeViewport3D.js.map +1 -1
- package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.js +3 -1
- package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.js.map +1 -1
- package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.js +3 -2
- package/dist/esm/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.js.map +1 -1
- package/dist/esm/RenderingEngine/helpers/setVolumesForViewports.js.map +1 -1
- package/dist/esm/Settings.js +4 -2
- package/dist/esm/Settings.js.map +1 -1
- package/dist/esm/cache/classes/ImageVolume.js +2 -3
- package/dist/esm/cache/classes/ImageVolume.js.map +1 -1
- package/dist/esm/init.d.ts +1 -1
- package/dist/esm/init.js +1 -1
- package/dist/esm/init.js.map +1 -1
- package/dist/esm/loaders/volumeLoader.d.ts +1 -1
- package/dist/esm/loaders/volumeLoader.js.map +1 -1
- package/dist/esm/requestPool/requestPoolManager.js +1 -1
- package/dist/esm/requestPool/requestPoolManager.js.map +1 -1
- package/dist/esm/types/AffineMatrix.d.ts +27 -0
- package/dist/esm/types/AffineMatrix.js +2 -0
- package/dist/esm/types/AffineMatrix.js.map +1 -0
- package/dist/esm/types/IImage.d.ts +1 -0
- package/dist/esm/types/IVolumeViewport.d.ts +2 -0
- package/dist/esm/types/Mat3.d.ts +1 -11
- package/dist/esm/types/ViewportProperties.d.ts +2 -1
- package/dist/esm/types/index.d.ts +2 -1
- package/dist/esm/utilities/calculateViewportsSpatialRegistration.js +9 -14
- package/dist/esm/utilities/calculateViewportsSpatialRegistration.js.map +1 -1
- package/dist/esm/utilities/getClosestStackImageIndexForPoint.js +12 -6
- package/dist/esm/utilities/getClosestStackImageIndexForPoint.js.map +1 -1
- package/dist/esm/utilities/getRuntimeId.js +2 -1
- package/dist/esm/utilities/getRuntimeId.js.map +1 -1
- package/dist/esm/utilities/windowLevel.js +4 -4
- package/dist/esm/utilities/windowLevel.js.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +2 -2
- package/src/RenderingEngine/BaseVolumeViewport.ts +55 -1
- package/src/RenderingEngine/RenderingEngine.ts +1 -0
- package/src/RenderingEngine/StackViewport.ts +23 -7
- package/src/RenderingEngine/VolumeViewport.ts +34 -0
- package/src/RenderingEngine/VolumeViewport3D.ts +4 -0
- package/src/RenderingEngine/helpers/cpuFallback/rendering/getVOILut.ts +9 -1
- package/src/RenderingEngine/helpers/cpuFallback/rendering/renderColorImage.ts +5 -3
- package/src/RenderingEngine/helpers/setVolumesForViewports.ts +3 -1
- package/src/Settings.ts +6 -2
- package/src/cache/classes/ImageVolume.ts +3 -3
- package/src/init.ts +1 -1
- package/src/loaders/volumeLoader.ts +2 -2
- package/src/requestPool/requestPoolManager.ts +1 -1
- package/src/types/AffineMatrix.ts +8 -0
- package/src/types/IImage.ts +2 -0
- package/src/types/IVolumeViewport.ts +8 -0
- package/src/types/Mat3.ts +3 -11
- package/src/types/ViewportProperties.ts +3 -1
- package/src/types/index.ts +2 -0
- package/src/utilities/calculateViewportsSpatialRegistration.ts +21 -28
- package/src/utilities/getClosestStackImageIndexForPoint.ts +18 -6
- package/src/utilities/getRuntimeId.ts +3 -1
- package/src/utilities/windowLevel.ts +13 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/core",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/umd/index.js",
|
|
6
6
|
"types": "dist/esm/index.d.ts",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"type": "individual",
|
|
47
47
|
"url": "https://ohif.org/donate"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "c154f7531c166db29a54fe41c76a22ecc7ac47c8"
|
|
50
50
|
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
BlendModes,
|
|
14
14
|
Events,
|
|
15
|
+
InterpolationType,
|
|
15
16
|
OrientationAxis,
|
|
16
17
|
ViewportStatus,
|
|
17
18
|
VOILUTFunctionType,
|
|
@@ -367,6 +368,23 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
|
|
|
367
368
|
return newRGBTransferFunction;
|
|
368
369
|
}
|
|
369
370
|
|
|
371
|
+
private setInterpolationType(
|
|
372
|
+
interpolationType: InterpolationType,
|
|
373
|
+
volumeId?: string
|
|
374
|
+
) {
|
|
375
|
+
const applicableVolumeActorInfo = this._getApplicableVolumeActor(volumeId);
|
|
376
|
+
|
|
377
|
+
if (!applicableVolumeActorInfo) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const { volumeActor } = applicableVolumeActorInfo;
|
|
382
|
+
const volumeProperty = volumeActor.getProperty();
|
|
383
|
+
|
|
384
|
+
// @ts-ignore
|
|
385
|
+
volumeProperty.setInterpolationType(interpolationType);
|
|
386
|
+
}
|
|
387
|
+
|
|
370
388
|
/**
|
|
371
389
|
* Sets the properties for the volume viewport on the volume
|
|
372
390
|
* (if fusion, it sets it for the first volume in the fusion)
|
|
@@ -449,6 +467,7 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
|
|
|
449
467
|
invert,
|
|
450
468
|
colormap,
|
|
451
469
|
preset,
|
|
470
|
+
interpolationType,
|
|
452
471
|
}: VolumeViewportProperties = {},
|
|
453
472
|
volumeId?: string,
|
|
454
473
|
suppressEvents = false
|
|
@@ -467,6 +486,10 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
|
|
|
467
486
|
this.setVOI(voiRange, volumeId, suppressEvents);
|
|
468
487
|
}
|
|
469
488
|
|
|
489
|
+
if (typeof interpolationType !== 'undefined') {
|
|
490
|
+
this.setInterpolationType(interpolationType);
|
|
491
|
+
}
|
|
492
|
+
|
|
470
493
|
if (VOILUTFunction !== undefined) {
|
|
471
494
|
this.setVOILUTFunction(VOILUTFunction, volumeId, suppressEvents);
|
|
472
495
|
}
|
|
@@ -519,7 +542,9 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
|
|
|
519
542
|
const volumeActor = actorEntry.actor as vtkVolume;
|
|
520
543
|
const volumeId = actorEntry.uid;
|
|
521
544
|
const volume = cache.getVolume(volumeId);
|
|
522
|
-
if (!volume)
|
|
545
|
+
if (!volume) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
523
548
|
const cfun = volumeActor.getProperty().getRGBTransferFunction(0);
|
|
524
549
|
const [lower, upper] =
|
|
525
550
|
this.VOILUTFunction === 'SIGMOID'
|
|
@@ -847,6 +872,8 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
|
|
|
847
872
|
*
|
|
848
873
|
*/
|
|
849
874
|
private _setVolumeActors(volumeActorEntries: Array<ActorEntry>): void {
|
|
875
|
+
// New volume actors implies resetting the inverted flag (i.e. like starting from scratch).
|
|
876
|
+
this.inverted = false;
|
|
850
877
|
this.setActors(volumeActorEntries);
|
|
851
878
|
}
|
|
852
879
|
|
|
@@ -1078,6 +1105,31 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
|
|
|
1078
1105
|
return volume.getScalarData()[voxelIndex];
|
|
1079
1106
|
}
|
|
1080
1107
|
|
|
1108
|
+
/**
|
|
1109
|
+
* Returns the list of image Ids for the current viewport
|
|
1110
|
+
*
|
|
1111
|
+
* @param volumeId - volumeId
|
|
1112
|
+
* @returns list of strings for image Ids
|
|
1113
|
+
*/
|
|
1114
|
+
public getImageIds = (volumeId?: string): Array<string> => {
|
|
1115
|
+
const applicableVolumeActorInfo = this._getApplicableVolumeActor(volumeId);
|
|
1116
|
+
|
|
1117
|
+
if (!applicableVolumeActorInfo) {
|
|
1118
|
+
throw new Error(`No actor found for the given volumeId: ${volumeId}`);
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
const volumeIdToUse = applicableVolumeActorInfo.volumeId;
|
|
1122
|
+
|
|
1123
|
+
const imageVolume = cache.getVolume(volumeIdToUse);
|
|
1124
|
+
if (!imageVolume) {
|
|
1125
|
+
throw new Error(
|
|
1126
|
+
`imageVolume with id: ${volumeIdToUse} does not exist in cache`
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
return imageVolume.imageIds;
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1081
1133
|
abstract getCurrentImageIdIndex(): number;
|
|
1082
1134
|
|
|
1083
1135
|
abstract getCurrentImageId(): string;
|
|
@@ -1092,6 +1144,8 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
|
|
|
1092
1144
|
slabThickness: number,
|
|
1093
1145
|
filterActorUIDs?: Array<string>
|
|
1094
1146
|
): void;
|
|
1147
|
+
|
|
1148
|
+
abstract resetProperties(volumeId?: string): void;
|
|
1095
1149
|
}
|
|
1096
1150
|
|
|
1097
1151
|
export default BaseVolumeViewport;
|
|
@@ -54,6 +54,7 @@ const VIEWPORT_MIN_SIZE = 2;
|
|
|
54
54
|
* trigger a render on a specific viewport(s). Each viewport also has a `.render` method which can be used to trigger a render on that
|
|
55
55
|
* viewport.
|
|
56
56
|
*
|
|
57
|
+
*
|
|
57
58
|
* Rendering engine uses `detect-gpu` external library to detect if GPU is available and
|
|
58
59
|
* it has minimum requirement to be able to render a volume with vtk.js. If GPU is not available
|
|
59
60
|
* RenderingEngine will throw an error if you try to render a volume; however, for StackViewports
|
|
@@ -130,6 +130,8 @@ class StackViewport extends Viewport implements IStackViewport {
|
|
|
130
130
|
private VOILUTFunction: VOILUTFunctionType;
|
|
131
131
|
//
|
|
132
132
|
private invert = false;
|
|
133
|
+
// The initial invert of the image loaded as opposed to the invert status of the viewport itself (see above).
|
|
134
|
+
private initialInvert = false;
|
|
133
135
|
private interpolationType: InterpolationType;
|
|
134
136
|
|
|
135
137
|
// Helpers
|
|
@@ -606,7 +608,9 @@ class StackViewport extends Viewport implements IStackViewport {
|
|
|
606
608
|
this.hasPixelSpacing = scale > 0 || imagePlaneModule.rowPixelSpacing > 0;
|
|
607
609
|
imagePlaneModule.calibration = calibration;
|
|
608
610
|
|
|
609
|
-
if (!isUpdated)
|
|
611
|
+
if (!isUpdated) {
|
|
612
|
+
return imagePlaneModule;
|
|
613
|
+
}
|
|
610
614
|
|
|
611
615
|
this.calibration = calibration;
|
|
612
616
|
this._publishCalibratedEvent = true;
|
|
@@ -728,7 +732,7 @@ class StackViewport extends Viewport implements IStackViewport {
|
|
|
728
732
|
this.setRotation(0);
|
|
729
733
|
}
|
|
730
734
|
this.setInterpolationType(InterpolationType.LINEAR);
|
|
731
|
-
this.setInvertColor(
|
|
735
|
+
this.setInvertColor(this.initialInvert);
|
|
732
736
|
}
|
|
733
737
|
|
|
734
738
|
private _setPropertiesFromCache(): void {
|
|
@@ -1755,10 +1759,17 @@ class StackViewport extends Viewport implements IStackViewport {
|
|
|
1755
1759
|
return;
|
|
1756
1760
|
}
|
|
1757
1761
|
|
|
1758
|
-
//If Photometric Interpretation is not the same for the next image we are trying to load
|
|
1762
|
+
// If Photometric Interpretation is not the same for the next image we are trying to load
|
|
1763
|
+
// invalidate the stack to recreate the VTK imageData
|
|
1764
|
+
const csImgFrame = this.csImage?.imageFrame;
|
|
1765
|
+
const imgFrame = image?.imageFrame;
|
|
1766
|
+
|
|
1767
|
+
// if a volume is decached into images then the imageFrame will be undefined
|
|
1759
1768
|
if (
|
|
1760
|
-
|
|
1761
|
-
|
|
1769
|
+
csImgFrame?.photometricInterpretation !==
|
|
1770
|
+
imgFrame?.photometricInterpretation ||
|
|
1771
|
+
this.csImage?.photometricInterpretation !==
|
|
1772
|
+
image?.photometricInterpretation
|
|
1762
1773
|
) {
|
|
1763
1774
|
this.stackInvalidated = true;
|
|
1764
1775
|
}
|
|
@@ -2057,8 +2068,10 @@ class StackViewport extends Viewport implements IStackViewport {
|
|
|
2057
2068
|
forceRecreateLUTFunction: !!monochrome1,
|
|
2058
2069
|
});
|
|
2059
2070
|
|
|
2071
|
+
this.initialInvert = !!monochrome1;
|
|
2072
|
+
|
|
2060
2073
|
// should carry over the invert color from the previous image if has been applied
|
|
2061
|
-
this.setInvertColor(this.invert ||
|
|
2074
|
+
this.setInvertColor(this.invert || this.initialInvert);
|
|
2062
2075
|
|
|
2063
2076
|
// Saving position of camera on render, to cache the panning
|
|
2064
2077
|
this.cameraFocalPointOnRender = this.getCamera().focalPoint;
|
|
@@ -2142,6 +2155,7 @@ class StackViewport extends Viewport implements IStackViewport {
|
|
|
2142
2155
|
// Update the state of the viewport to the new imageIdIndex;
|
|
2143
2156
|
this.currentImageIdIndex = imageIdIndex;
|
|
2144
2157
|
this.hasPixelSpacing = true;
|
|
2158
|
+
this.viewportStatus = ViewportStatus.PRE_RENDER;
|
|
2145
2159
|
|
|
2146
2160
|
// Todo: trigger an event to allow applications to hook into START of loading state
|
|
2147
2161
|
// Currently we use loadHandlerManagers for this
|
|
@@ -2564,7 +2578,9 @@ class StackViewport extends Viewport implements IStackViewport {
|
|
|
2564
2578
|
public hasImageURI = (imageURI: string): boolean => {
|
|
2565
2579
|
const imageIds = this.imageIds;
|
|
2566
2580
|
for (let i = 0; i < imageIds.length; i++) {
|
|
2567
|
-
if (imageIdToURI(imageIds[i]) === imageURI)
|
|
2581
|
+
if (imageIdToURI(imageIds[i]) === imageURI) {
|
|
2582
|
+
return true;
|
|
2583
|
+
}
|
|
2568
2584
|
}
|
|
2569
2585
|
|
|
2570
2586
|
return false;
|
|
@@ -14,6 +14,8 @@ import type {
|
|
|
14
14
|
import type { ViewportInput } from '../types/IViewport';
|
|
15
15
|
import { actorIsA, getClosestImageId } from '../utilities';
|
|
16
16
|
import BaseVolumeViewport from './BaseVolumeViewport';
|
|
17
|
+
import setDefaultVolumeVOI from './helpers/setDefaultVolumeVOI';
|
|
18
|
+
import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume';
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* An object representing a VolumeViewport. VolumeViewports are used to render
|
|
@@ -350,6 +352,38 @@ class VolumeViewport extends BaseVolumeViewport {
|
|
|
350
352
|
};
|
|
351
353
|
|
|
352
354
|
getRotation = (): number => 0;
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Reset the viewport properties to the default values
|
|
358
|
+
*
|
|
359
|
+
|
|
360
|
+
* @param volumeId - Optional volume ID to specify which volume properties to reset.
|
|
361
|
+
* If not provided, it will reset the properties of the default actor.
|
|
362
|
+
*
|
|
363
|
+
* @returns void
|
|
364
|
+
*/
|
|
365
|
+
public resetProperties(volumeId?: string): void {
|
|
366
|
+
this._resetProperties(volumeId);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private _resetProperties(volumeId?: string) {
|
|
370
|
+
// Get the actor based on the volumeId if provided, otherwise use the default actor.
|
|
371
|
+
const volumeActor = volumeId
|
|
372
|
+
? this.getActor(volumeId)
|
|
373
|
+
: this.getDefaultActor();
|
|
374
|
+
|
|
375
|
+
if (!volumeActor) {
|
|
376
|
+
throw new Error(`No actor found for the given volumeId: ${volumeId}`);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const imageVolume = cache.getVolume(volumeActor.uid);
|
|
380
|
+
if (!imageVolume) {
|
|
381
|
+
throw new Error(
|
|
382
|
+
`imageVolume with id: ${volumeActor.uid} does not exist in cache`
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
setDefaultVolumeVOI(volumeActor.actor as vtkVolume, imageVolume, false);
|
|
386
|
+
}
|
|
353
387
|
}
|
|
354
388
|
|
|
355
389
|
export default VolumeViewport;
|
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
+
* Generates the linear VOI LUT function.
|
|
19
|
+
* From the DICOM standard:
|
|
20
|
+
* https://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.11.2.1.2.1
|
|
21
|
+
* ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax- ymin) + ymin
|
|
22
|
+
* clipped to the ymin...ymax range
|
|
18
23
|
*
|
|
19
24
|
* @param {Number} windowWidth Window Width
|
|
20
25
|
* @param {Number} windowCenter Window Center
|
|
@@ -23,7 +28,10 @@
|
|
|
23
28
|
*/
|
|
24
29
|
function generateLinearVOILUT(windowWidth: number, windowCenter: number) {
|
|
25
30
|
return function (modalityLutValue) {
|
|
26
|
-
|
|
31
|
+
const value =
|
|
32
|
+
((modalityLutValue - (windowCenter - 0.5)) / (windowWidth - 1) + 0.5) *
|
|
33
|
+
255.0;
|
|
34
|
+
return Math.min(Math.max(value, 0), 255);
|
|
27
35
|
};
|
|
28
36
|
}
|
|
29
37
|
|
|
@@ -72,10 +72,12 @@ function getRenderCanvas(
|
|
|
72
72
|
const renderCanvas = enabledElement.renderingTools.renderCanvas;
|
|
73
73
|
|
|
74
74
|
// The ww/wc is identity and not inverted - get a canvas with the image rendered into it for
|
|
75
|
-
// Fast drawing
|
|
75
|
+
// Fast drawing. Note that this is 256/128, and NOT 255/127, per the DICOM
|
|
76
|
+
// standard, but allow either.
|
|
77
|
+
const { windowWidth, windowCenter } = enabledElement.viewport.voi;
|
|
76
78
|
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
(windowWidth === 256 || windowWidth === 255) &&
|
|
80
|
+
(windowCenter === 128 || windowCenter === 127) &&
|
|
79
81
|
enabledElement.viewport.invert === false &&
|
|
80
82
|
image.getCanvas &&
|
|
81
83
|
image.getCanvas()
|
|
@@ -34,7 +34,9 @@ async function setVolumesForViewports(
|
|
|
34
34
|
|
|
35
35
|
// if not instance of BaseVolumeViewport, throw
|
|
36
36
|
if (!(viewport instanceof BaseVolumeViewport)) {
|
|
37
|
-
throw new Error(
|
|
37
|
+
throw new Error(
|
|
38
|
+
'setVolumesForViewports only supports VolumeViewport and VolumeViewport3D'
|
|
39
|
+
);
|
|
38
40
|
}
|
|
39
41
|
});
|
|
40
42
|
|
package/src/Settings.ts
CHANGED
|
@@ -250,10 +250,14 @@ function get(dictionary: Record<string, unknown>, key: string): unknown {
|
|
|
250
250
|
*/
|
|
251
251
|
function isValidKey(key: string): boolean {
|
|
252
252
|
let last: number, current: number, previous: number;
|
|
253
|
-
if (typeof key !== 'string' || (last = key.length - 1) < 0)
|
|
253
|
+
if (typeof key !== 'string' || (last = key.length - 1) < 0) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
254
256
|
previous = -1;
|
|
255
257
|
while ((current = key.indexOf('.', previous + 1)) >= 0) {
|
|
256
|
-
if (current - previous < 2 || current === last)
|
|
258
|
+
if (current - previous < 2 || current === last) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
257
261
|
previous = current;
|
|
258
262
|
}
|
|
259
263
|
return true;
|
|
@@ -151,12 +151,12 @@ export class ImageVolume implements IImageVolume {
|
|
|
151
151
|
*/
|
|
152
152
|
destroy(): void {
|
|
153
153
|
// TODO: GPU memory associated with volume is not cleared.
|
|
154
|
-
this.vtkOpenGLTexture.releaseGraphicsResources();
|
|
155
|
-
this.vtkOpenGLTexture.destroyTexture();
|
|
156
|
-
this.vtkOpenGLTexture.delete();
|
|
157
154
|
this.imageData.delete();
|
|
158
155
|
this.imageData = null;
|
|
159
156
|
this.scalarData = null;
|
|
157
|
+
|
|
158
|
+
this.vtkOpenGLTexture.releaseGraphicsResources();
|
|
159
|
+
this.vtkOpenGLTexture.delete();
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
package/src/init.ts
CHANGED
|
@@ -100,7 +100,7 @@ function hasSharedArrayBuffer() {
|
|
|
100
100
|
* @returns A promise that resolves to true cornerstone has been initialized successfully.
|
|
101
101
|
* @category Initialization
|
|
102
102
|
*/
|
|
103
|
-
async function init(configuration =
|
|
103
|
+
async function init(configuration = config): Promise<boolean> {
|
|
104
104
|
if (csRenderInitialized) {
|
|
105
105
|
return csRenderInitialized;
|
|
106
106
|
}
|
|
@@ -132,7 +132,7 @@ let unknownVolumeLoader;
|
|
|
132
132
|
*/
|
|
133
133
|
function loadVolumeFromVolumeLoader(
|
|
134
134
|
volumeId: string,
|
|
135
|
-
options
|
|
135
|
+
options?: VolumeLoaderOptions
|
|
136
136
|
): Types.IVolumeLoadObject {
|
|
137
137
|
const colonIndex = volumeId.indexOf(':');
|
|
138
138
|
const scheme = volumeId.substring(0, colonIndex);
|
|
@@ -210,7 +210,7 @@ export function loadVolume(
|
|
|
210
210
|
*/
|
|
211
211
|
export async function createAndCacheVolume(
|
|
212
212
|
volumeId: string,
|
|
213
|
-
options
|
|
213
|
+
options?: VolumeLoaderOptions
|
|
214
214
|
): Promise<Record<string, any>> {
|
|
215
215
|
if (volumeId === undefined) {
|
|
216
216
|
throw new Error(
|
package/src/types/IImage.ts
CHANGED
|
@@ -72,6 +72,8 @@ interface IImage {
|
|
|
72
72
|
sliceThickness?: number;
|
|
73
73
|
/** whether image pixels are inverted in color */
|
|
74
74
|
invert: boolean;
|
|
75
|
+
/** image photometric interpretation */
|
|
76
|
+
photometricInterpretation?: string;
|
|
75
77
|
/** image size in number of bytes */
|
|
76
78
|
sizeInBytes: number;
|
|
77
79
|
/** CPU: custom modality LUT for image */
|
|
@@ -28,6 +28,10 @@ export default interface IVolumeViewport extends IViewport {
|
|
|
28
28
|
* projected onto the `Viewport`'s `canvas`.
|
|
29
29
|
*/
|
|
30
30
|
worldToCanvas: (worldPos: Point3) => Point2;
|
|
31
|
+
/**
|
|
32
|
+
* Returns the list of image Ids for the current viewport
|
|
33
|
+
*/
|
|
34
|
+
getImageIds: (volumeId?: string) => string[];
|
|
31
35
|
/**
|
|
32
36
|
* Uses viewport camera and volume actor to decide if the viewport
|
|
33
37
|
* is looking at the volume in the direction of acquisition (imageIds).
|
|
@@ -138,4 +142,8 @@ export default interface IVolumeViewport extends IViewport {
|
|
|
138
142
|
getImageData(volumeId?: string): IImageData | undefined;
|
|
139
143
|
|
|
140
144
|
setOrientation(orientation: OrientationAxis): void;
|
|
145
|
+
/**
|
|
146
|
+
* Reset the viewport properties to the default values
|
|
147
|
+
*/
|
|
148
|
+
resetProperties(volumeId?: string): void;
|
|
141
149
|
}
|
package/src/types/Mat3.ts
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This represents a 3x3 matrix of numbers
|
|
3
3
|
*/
|
|
4
|
-
type Mat3 =
|
|
5
|
-
number,
|
|
6
|
-
|
|
7
|
-
number,
|
|
8
|
-
number,
|
|
9
|
-
number,
|
|
10
|
-
number,
|
|
11
|
-
number,
|
|
12
|
-
number,
|
|
13
|
-
number
|
|
14
|
-
];
|
|
4
|
+
type Mat3 =
|
|
5
|
+
| [number, number, number, number, number, number, number, number, number]
|
|
6
|
+
| Float32Array;
|
|
15
7
|
|
|
16
8
|
export default Mat3;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VOILUTFunctionType } from '../enums';
|
|
1
|
+
import { InterpolationType, VOILUTFunctionType } from '../enums';
|
|
2
2
|
import { VOIRange } from './voi';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -11,6 +11,8 @@ type ViewportProperties = {
|
|
|
11
11
|
VOILUTFunction?: VOILUTFunctionType;
|
|
12
12
|
/** invert flag - whether the image is inverted */
|
|
13
13
|
invert?: boolean;
|
|
14
|
+
/** interpolation type */
|
|
15
|
+
interpolationType?: InterpolationType;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
export type { ViewportProperties };
|
package/src/types/index.ts
CHANGED
|
@@ -81,6 +81,7 @@ import type { ViewportProperties } from './ViewportProperties';
|
|
|
81
81
|
import type { PixelDataTypedArray } from './PixelDataTypedArray';
|
|
82
82
|
import type { ImagePixelModule } from './ImagePixelModule';
|
|
83
83
|
import type { ImagePlaneModule } from './ImagePlaneModule';
|
|
84
|
+
import type { AffineMatrix } from './AffineMatrix';
|
|
84
85
|
|
|
85
86
|
export type {
|
|
86
87
|
// config
|
|
@@ -173,4 +174,5 @@ export type {
|
|
|
173
174
|
PixelDataTypedArray,
|
|
174
175
|
ImagePixelModule,
|
|
175
176
|
ImagePlaneModule,
|
|
177
|
+
AffineMatrix,
|
|
176
178
|
};
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { vec3, mat4 } from 'gl-matrix';
|
|
2
2
|
import { IStackViewport } from '../types';
|
|
3
|
-
import { StackViewport } from '../RenderingEngine';
|
|
4
3
|
import spatialRegistrationMetadataProvider from './spatialRegistrationMetadataProvider';
|
|
5
4
|
import { metaData } from '..';
|
|
6
|
-
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Defines the allowed difference as a percent between the unit normals before
|
|
8
|
+
* two planes are considered not coplanar. Since this value is small compared
|
|
9
|
+
* to the unit lenght, this value is approximately the angular difference, measured
|
|
10
|
+
* in radians. That is, allow about a 3 degrees variation.
|
|
11
|
+
*/
|
|
12
|
+
const ALLOWED_DELTA = 0.05;
|
|
7
13
|
|
|
8
14
|
/**
|
|
9
15
|
* It calculates the registration matrix between two viewports (currently only
|
|
@@ -21,40 +27,28 @@ function calculateViewportsSpatialRegistration(
|
|
|
21
27
|
viewport1: IStackViewport,
|
|
22
28
|
viewport2: IStackViewport
|
|
23
29
|
): void {
|
|
24
|
-
if (
|
|
25
|
-
!(viewport1 instanceof StackViewport) ||
|
|
26
|
-
!(viewport2 instanceof StackViewport)
|
|
27
|
-
) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
'calculateViewportsSpatialRegistration: Both viewports must be StackViewports, volume viewports are not supported yet'
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const isSameFrameOfReference =
|
|
34
|
-
viewport1.getFrameOfReferenceUID() === viewport2.getFrameOfReferenceUID();
|
|
35
|
-
|
|
36
|
-
if (isSameFrameOfReference) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
30
|
const imageId1 = viewport1.getCurrentImageId();
|
|
41
31
|
const imageId2 = viewport2.getCurrentImageId();
|
|
42
32
|
|
|
43
33
|
const imagePlaneModule1 = metaData.get('imagePlaneModule', imageId1);
|
|
44
34
|
const imagePlaneModule2 = metaData.get('imagePlaneModule', imageId2);
|
|
45
35
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
36
|
+
if (!imagePlaneModule1 || !imagePlaneModule2) {
|
|
37
|
+
console.log('Viewport spatial registration requires image plane module');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const { imageOrientationPatient: iop2 } = imagePlaneModule2;
|
|
41
|
+
const isSameImagePlane = imagePlaneModule1.imageOrientationPatient.every(
|
|
42
|
+
(v, i) => Math.abs(v - iop2[i]) < ALLOWED_DELTA
|
|
43
|
+
);
|
|
53
44
|
|
|
54
45
|
if (!isSameImagePlane) {
|
|
55
|
-
|
|
56
|
-
'Viewport spatial registration only supported for same orientation (hence translation only) for now'
|
|
46
|
+
console.log(
|
|
47
|
+
'Viewport spatial registration only supported for same orientation (hence translation only) for now',
|
|
48
|
+
imagePlaneModule1?.imageOrientationPatient,
|
|
49
|
+
imagePlaneModule2?.imageOrientationPatient
|
|
57
50
|
);
|
|
51
|
+
return;
|
|
58
52
|
}
|
|
59
53
|
|
|
60
54
|
const imagePositionPatient1 = imagePlaneModule1.imagePositionPatient;
|
|
@@ -67,7 +61,6 @@ function calculateViewportsSpatialRegistration(
|
|
|
67
61
|
);
|
|
68
62
|
|
|
69
63
|
const mat = mat4.fromTranslation(mat4.create(), translation);
|
|
70
|
-
|
|
71
64
|
spatialRegistrationMetadataProvider.add([viewport1.id, viewport2.id], mat);
|
|
72
65
|
}
|
|
73
66
|
|
|
@@ -29,11 +29,15 @@ export function calculateMinimalDistanceForStackViewport(
|
|
|
29
29
|
const imageIds = viewport.getImageIds();
|
|
30
30
|
const currentImageIdIndex = viewport.getCurrentImageIdIndex();
|
|
31
31
|
|
|
32
|
-
if (imageIds.length === 0)
|
|
32
|
+
if (imageIds.length === 0) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
33
35
|
|
|
34
36
|
const getDistance = (imageId: string): null | number => {
|
|
35
37
|
const planeMetadata = getPlaneMetadata(imageId);
|
|
36
|
-
if (!planeMetadata)
|
|
38
|
+
if (!planeMetadata) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
37
41
|
const plane = planar.planeEquation(
|
|
38
42
|
planeMetadata.planeNormal,
|
|
39
43
|
planeMetadata.imagePositionPatient
|
|
@@ -53,22 +57,30 @@ export function calculateMinimalDistanceForStackViewport(
|
|
|
53
57
|
for (let i = 0; i < higherImageIds.length; i++) {
|
|
54
58
|
const id = higherImageIds[i];
|
|
55
59
|
const distance = getDistance(id);
|
|
56
|
-
if (distance === null)
|
|
60
|
+
if (distance === null) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
57
63
|
if (distance <= closestStack.distance) {
|
|
58
64
|
closestStack.distance = distance;
|
|
59
65
|
closestStack.index = i + currentImageIdIndex + 1;
|
|
60
|
-
} else
|
|
66
|
+
} else {
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
61
69
|
}
|
|
62
70
|
//check lower indices
|
|
63
71
|
const lowerImageIds = imageIds.slice(0, currentImageIdIndex);
|
|
64
72
|
for (let i = lowerImageIds.length - 1; i >= 0; i--) {
|
|
65
73
|
const id = lowerImageIds[i];
|
|
66
74
|
const distance = getDistance(id);
|
|
67
|
-
if (distance === null || distance === closestStack.distance)
|
|
75
|
+
if (distance === null || distance === closestStack.distance) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
68
78
|
if (distance < closestStack.distance) {
|
|
69
79
|
closestStack.distance = distance;
|
|
70
80
|
closestStack.index = i;
|
|
71
|
-
} else
|
|
81
|
+
} else {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
72
84
|
}
|
|
73
85
|
return closestStack.distance === Infinity ? null : closestStack;
|
|
74
86
|
}
|