chore(prettier): full repo linting and code reformatting once and for all (#3627)

This commit is contained in:
Alireza authored and GitHub committed 2023-09-01 16:19:39 -04:00
1 parent 01500a2d4c
commit 9045ddaedc
656 files changed
+21737 -20628

No files matched your search

@@ -40,13 +40,7 @@ module.exports = (env, argv) => {
libraryTarget: 'umd',
filename: pkg.main,
},
externals: [
/\b(vtk.js)/,
/\b(dcmjs)/,
/\b(gl-matrix)/,
/^@ohif/,
/^@cornerstonejs/,
],
externals: [/\b(vtk.js)/, /\b(dcmjs)/, /\b(gl-matrix)/, /^@ohif/, /^@cornerstonejs/],
plugins: [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
@@ -11,10 +11,7 @@ import {
} from '@cornerstonejs/core';
import { MeasurementService } from '@ohif/core';
import { Notification, useViewportDialog } from '@ohif/ui';
import {
IStackViewport,
IVolumeViewport,
} from '@cornerstonejs/core/dist/esm/types';
import { IStackViewport, IVolumeViewport } from '@cornerstonejs/core/dist/esm/types';
import { setEnabledElement } from '../state';
@@ -42,24 +39,15 @@ function areEqual(prevProps, nextProps) {
return false;
}
if (
prevProps.viewportOptions.orientation !==
nextProps.viewportOptions.orientation
) {
if (prevProps.viewportOptions.orientation !== nextProps.viewportOptions.orientation) {
return false;
}
if (
prevProps.viewportOptions.toolGroupId !==
nextProps.viewportOptions.toolGroupId
) {
if (prevProps.viewportOptions.toolGroupId !== nextProps.viewportOptions.toolGroupId) {
return false;
}
if (
prevProps.viewportOptions.viewportType !==
nextProps.viewportOptions.viewportType
) {
if (prevProps.viewportOptions.viewportType !== nextProps.viewportOptions.viewportType) {
return false;
}
@@ -79,8 +67,7 @@ function areEqual(prevProps, nextProps) {
const foundDisplaySet = nextDisplaySets.find(
nextDisplaySet =>
nextDisplaySet.displaySetInstanceUID ===
prevDisplaySet.displaySetInstanceUID
nextDisplaySet.displaySetInstanceUID === prevDisplaySet.displaySetInstanceUID
);
if (!foundDisplaySet) {
@@ -95,9 +82,7 @@ function areEqual(prevProps, nextProps) {
// check if their imageIds are the same
if (foundDisplaySet.images?.length) {
for (let j = 0; j < foundDisplaySet.images.length; j++) {
if (
foundDisplaySet.images[j].imageId !== prevDisplaySet.images[j].imageId
) {
if (foundDisplaySet.images[j].imageId !== prevDisplaySet.images[j].imageId) {
return false;
}
}
@@ -163,16 +148,9 @@ const OHIFCornerstoneViewport = React.memo(props => {
const renderingEngineId = viewportInfo.getRenderingEngineId();
const syncGroups = viewportInfo.getSyncGroups();
toolGroupService.removeViewportFromToolGroup(
viewportId,
renderingEngineId
);
toolGroupService.removeViewportFromToolGroup(viewportId, renderingEngineId);
syncGroupService.removeViewportFromSyncGroup(
viewportId,
renderingEngineId,
syncGroups
);
syncGroupService.removeViewportFromSyncGroup(viewportId, renderingEngineId, syncGroups);
},
[viewportId]
);
@@ -185,9 +163,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
}
const { viewportId, element } = evt.detail;
const viewportInfo = cornerstoneViewportService.getViewportInfo(
viewportId
);
const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
setEnabledElement(viewportId, element);
setEnabledVPElement(element);
@@ -195,17 +171,9 @@ const OHIFCornerstoneViewport = React.memo(props => {
const toolGroupId = viewportInfo.getToolGroupId();
const syncGroups = viewportInfo.getSyncGroups();
toolGroupService.addViewportToToolGroup(
viewportId,
renderingEngineId,
toolGroupId
);
toolGroupService.addViewportToToolGroup(viewportId, renderingEngineId, toolGroupId);
syncGroupService.addViewportToSyncGroup(
viewportId,
renderingEngineId,
syncGroups
);
syncGroupService.addViewportToSyncGroup(viewportId, renderingEngineId, syncGroups);
if (onElementEnabled) {
onElementEnabled(evt);
@@ -218,17 +186,12 @@ const OHIFCornerstoneViewport = React.memo(props => {
useEffect(() => {
cornerstoneViewportService.enableViewport(viewportId, elementRef.current);
eventTarget.addEventListener(
Enums.Events.ELEMENT_ENABLED,
elementEnabledHandler
);
eventTarget.addEventListener(Enums.Events.ELEMENT_ENABLED, elementEnabledHandler);
setImageScrollBarHeight();
return () => {
const viewportInfo = cornerstoneViewportService.getViewportInfo(
viewportId
);
const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
if (!viewportInfo) {
return;
@@ -241,10 +204,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
onElementDisabled(viewportInfo);
}
eventTarget.removeEventListener(
Enums.Events.ELEMENT_ENABLED,
elementEnabledHandler
);
eventTarget.removeEventListener(Enums.Events.ELEMENT_ENABLED, elementEnabledHandler);
};
}, []);
@@ -267,9 +227,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
return;
}
const viewportInfo = cornerstoneViewportService.getViewportInfo(
viewportId
);
const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
if (viewportInfo.hasDisplaySet(invalidatedDisplaySetInstanceUID)) {
const viewportData = viewportInfo.getViewportData();
@@ -281,11 +239,7 @@ const OHIFCornerstoneViewport = React.memo(props => {
);
const keepCamera = true;
cornerstoneViewportService.updateViewport(
viewportId,
newViewportData,
keepCamera
);
cornerstoneViewportService.updateViewport(viewportId, newViewportData, keepCamera);
}
}
);
@@ -311,16 +265,11 @@ const OHIFCornerstoneViewport = React.memo(props => {
// The presentation state will have been stored previously by closing
// a viewport. Otherwise, this viewport will be unchanged and the
// presentation information will be directly carried over.
const {
lutPresentationStore,
positionPresentationStore,
} = stateSyncService.getState();
const { lutPresentationStore, positionPresentationStore } = stateSyncService.getState();
const { presentationIds } = viewportOptions;
const presentations = {
positionPresentation:
positionPresentationStore[presentationIds?.positionPresentationId],
lutPresentation:
lutPresentationStore[presentationIds?.lutPresentationId],
positionPresentation: positionPresentationStore[presentationIds?.positionPresentationId],
lutPresentation: lutPresentationStore[presentationIds?.lutPresentationId],
};
let measurement;
if (cacheJumpToMeasurementEvent?.viewportId === viewportId) {
@@ -459,11 +408,12 @@ function _subscribeToJumpToMeasurementEvents(
}
if (cacheJumpToMeasurementEvent.cornerstoneViewport === undefined) {
// Decide on which viewport should handle this
cacheJumpToMeasurementEvent.cornerstoneViewport = cornerstoneViewportService.getViewportIdToJump(
jumpId,
measurement.displaySetInstanceUID,
{ referencedImageId: measurement.referencedImageId }
);
cacheJumpToMeasurementEvent.cornerstoneViewport =
cornerstoneViewportService.getViewportIdToJump(
jumpId,
measurement.displaySetInstanceUID,
{ referencedImageId: measurement.referencedImageId }
);
}
if (cacheJumpToMeasurementEvent.cornerstoneViewport !== viewportId) {
return;
@@ -500,9 +450,7 @@ function _checkForCachedJumpToMeasurementEvents(
cacheJumpToMeasurementEvent = null;
return;
}
const displaysUIDs = displaySets.map(
displaySet => displaySet.displaySetInstanceUID
);
const displaysUIDs = displaySets.map(displaySet => displaySet.displaySetInstanceUID);
if (!displaysUIDs?.length) {
return;
}
@@ -541,9 +489,7 @@ function _jumpToMeasurement(
return;
}
const referencedDisplaySet = displaySetService.getDisplaySetByUID(
displaySetInstanceUID
);
const referencedDisplaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
// Todo: setCornerstoneMeasurementActive should be handled by the toolGroupManager
// to set it properly
@@ -555,9 +501,7 @@ function _jumpToMeasurement(
if (enabledElement) {
// See how the jumpToSlice() of Cornerstone3D deals with imageIdx param.
const viewport = enabledElement.viewport as
| IStackViewport
| IVolumeViewport;
const viewport = enabledElement.viewport as IStackViewport | IVolumeViewport;
let imageIdIndex = 0;
let viewportCameraDirectionMatch = true;
@@ -565,14 +509,9 @@ function _jumpToMeasurement(
if (viewport instanceof StackViewport) {
const imageIds = viewport.getImageIds();
imageIdIndex = imageIds.findIndex(imageId => {
const {
SOPInstanceUID: aSOPInstanceUID,
frameNumber: aFrameNumber,
} = getSOPInstanceAttributes(imageId);
return (
aSOPInstanceUID === SOPInstanceUID &&
(!frameNumber || frameNumber === aFrameNumber)
);
const { SOPInstanceUID: aSOPInstanceUID, frameNumber: aFrameNumber } =
getSOPInstanceAttributes(imageId);
return aSOPInstanceUID === SOPInstanceUID && (!frameNumber || frameNumber === aFrameNumber);
});
} else {
// for volume viewport we can't rely on the imageIdIndex since it can be
@@ -587,10 +526,7 @@ function _jumpToMeasurement(
// should compare abs for both planes since the direction can be flipped
if (
measurementViewPlane &&
!csUtils.isEqual(
measurementViewPlane.map(Math.abs),
viewportViewPlane.map(Math.abs)
)
!csUtils.isEqual(measurementViewPlane.map(Math.abs), viewportViewPlane.map(Math.abs))
) {
viewportCameraDirectionMatch = false;
}
@@ -629,10 +565,7 @@ OHIFCornerstoneViewport.propTypes = {
// Note: you SHOULD NOT use the initialImageIdOrIndex for manipulation
// of the imageData in the OHIFCornerstoneViewport. This prop is used
// to set the initial state of the viewport's first image to render
initialImageIdOrIndex: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
initialImageIdOrIndex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
export default OHIFCornerstoneViewport;
@@ -3,12 +3,7 @@ import { vec3 } from 'gl-matrix';
import PropTypes from 'prop-types';
import { metaData, Enums, utilities } from '@cornerstonejs/core';
import { ViewportOverlay } from '@ohif/ui';
import {
formatPN,
formatDICOMDate,
formatDICOMTime,
formatNumberPrecision,
} from './utils';
import { formatPN, formatDICOMDate, formatDICOMTime, formatNumberPrecision } from './utils';
import { InstanceMetadata } from 'platform/core/src/types';
import { ServicesManager } from '@ohif/core';
import { ImageSliceData } from '@cornerstonejs/core/dist/esm/types';
@@ -55,13 +50,9 @@ function VOIOverlayItem({ voi, customization }: OverlayItemProps) {
style={{ color: (customization && customization.color) || undefined }}
>
<span className="mr-1 shrink-0">W:</span>
<span className="ml-1 mr-2 font-light shrink-0">
{windowWidth.toFixed(0)}
</span>
<span className="ml-1 mr-2 shrink-0 font-light">{windowWidth.toFixed(0)}</span>
<span className="mr-1 shrink-0">L:</span>
<span className="ml-1 font-light shrink-0">
{windowCenter.toFixed(0)}
</span>
<span className="ml-1 shrink-0 font-light">{windowCenter.toFixed(0)}</span>
</div>
);
}
@@ -116,11 +107,8 @@ function CustomizableViewportOverlay({
viewportId,
servicesManager,
}) {
const {
toolbarService,
cornerstoneViewportService,
customizationService,
} = servicesManager.services;
const { toolbarService, cornerstoneViewportService, customizationService } =
servicesManager.services;
const [voi, setVOI] = useState({ windowCenter: null, windowWidth: null });
const [scale, setScale] = useState(1);
const [activeTools, setActiveTools] = useState([]);
@@ -149,12 +137,7 @@ function CustomizableViewportOverlay({
const instanceNumber = useMemo(() => {
if (viewportData != null) {
return _getInstanceNumber(
viewportData,
viewportId,
imageIndex,
cornerstoneViewportService
);
return _getInstanceNumber(viewportData, viewportId, imageIndex, cornerstoneViewportService);
}
return null;
}, [viewportData, viewportId, imageIndex, cornerstoneViewportService]);
@@ -178,10 +161,7 @@ function CustomizableViewportOverlay({
}
const { lower, upper } = range;
const { windowWidth, windowCenter } = utilities.windowLevel.toWindowLevel(
lower,
upper
);
const { windowWidth, windowCenter } = utilities.windowLevel.toWindowLevel(lower, upper);
setVOI({ windowCenter, windowWidth });
};
@@ -204,9 +184,7 @@ function CustomizableViewportOverlay({
previousCamera.parallelScale !== camera.parallelScale ||
previousCamera.scale !== camera.scale
) {
const viewport = cornerstoneViewportService.getCornerstoneViewport(
viewportId
);
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
if (!viewport) {
return;
@@ -225,8 +203,7 @@ function CustomizableViewportOverlay({
const { spacing } = imageData;
// convert parallel scale to scale
const scale =
(element.clientHeight * spacing[0] * 0.5) / camera.parallelScale;
const scale = (element.clientHeight * spacing[0] * 0.5) / camera.parallelScale;
setScale(scale);
}
};
@@ -342,9 +319,7 @@ function CustomizableViewportOverlay({
return (
<>
{items.map((item, i) => (
<div key={`bottomLeftOverlayItem_${i}`}>
{_renderOverlayItem(item)}
</div>
<div key={`bottomLeftOverlayItem_${i}`}>{_renderOverlayItem(item)}</div>
))}
</>
);
@@ -355,9 +330,7 @@ function CustomizableViewportOverlay({
return (
<>
{items.map((item, i) => (
<div key={`bottomRightOverlayItem_${i}`}>
{_renderOverlayItem(item)}
</div>
<div key={`bottomRightOverlayItem_${i}`}>{_renderOverlayItem(item)}</div>
))}
</>
);
@@ -387,12 +360,7 @@ function _getViewportInstance(viewportData, imageIndex) {
return imageId ? metaData.get('instance', imageId) || {} : {};
}
function _getInstanceNumber(
viewportData,
viewportId,
imageIndex,
cornerstoneViewportService
) {
function _getInstanceNumber(viewportData, viewportId, imageIndex, cornerstoneViewportService) {
let instanceNumber;
if (viewportData.viewportType === Enums.ViewportType.STACK) {
@@ -435,11 +403,7 @@ function _getInstanceNumberFromStack(viewportData, imageIndex) {
// Since volume viewports can be in any view direction, they can render
// a reconstructed image which don't have imageIds; therefore, no instance and instanceNumber
// Here we check if viewport is in the acquisition direction and if so, we get the instanceNumber
function _getInstanceNumberFromVolume(
viewportData,
viewportId,
cornerstoneViewportService
) {
function _getInstanceNumberFromVolume(viewportData, viewportId, cornerstoneViewportService) {
const volumes = viewportData.volumes;
// Todo: support fusion of acquisition plane which has instanceNumber
@@ -450,9 +414,7 @@ function _getInstanceNumberFromVolume(
const volume = volumes[0];
const { direction, imageIds } = volume;
const cornerstoneViewport = cornerstoneViewportService.getCornerstoneViewport(
viewportId
);
const cornerstoneViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
if (!cornerstoneViewport) {
return;
@@ -475,8 +437,7 @@ function _getInstanceNumberFromVolume(
return {};
}
const { instanceNumber } =
metaData.get('generalImageModule', imageId) || {};
const { instanceNumber } = metaData.get('generalImageModule', imageId) || {};
return parseInt(instanceNumber);
}
}
@@ -14,15 +14,10 @@ function CornerstoneImageScrollbar({
scrollbarHeight,
servicesManager,
}) {
const {
cineService,
cornerstoneViewportService,
} = (servicesManager as ServicesManger).services;
const { cineService, cornerstoneViewportService } = (servicesManager as ServicesManger).services;
const onImageScrollbarChange = (imageIndex, viewportId) => {
const viewport = cornerstoneViewportService.getCornerstoneViewport(
viewportId
);
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
const { isCineEnabled } = cineService.getState();
@@ -43,9 +38,7 @@ function CornerstoneImageScrollbar({
return;
}
const viewport = cornerstoneViewportService.getCornerstoneViewport(
viewportId
);
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
if (!viewport) {
return;
@@ -90,16 +83,10 @@ function CornerstoneImageScrollbar({
});
};
element.addEventListener(
Enums.Events.STACK_VIEWPORT_SCROLL,
updateStackIndex
);
element.addEventListener(Enums.Events.STACK_VIEWPORT_SCROLL, updateStackIndex);
return () => {
element.removeEventListener(
Enums.Events.STACK_VIEWPORT_SCROLL,
updateStackIndex
);
element.removeEventListener(Enums.Events.STACK_VIEWPORT_SCROLL, updateStackIndex);
};
}, [viewportData, element]);
@@ -117,19 +104,14 @@ function CornerstoneImageScrollbar({
element.addEventListener(Enums.Events.VOLUME_NEW_IMAGE, updateVolumeIndex);
return () => {
element.removeEventListener(
Enums.Events.VOLUME_NEW_IMAGE,
updateVolumeIndex
);
element.removeEventListener(Enums.Events.VOLUME_NEW_IMAGE, updateVolumeIndex);
};
}, [viewportData, element]);
return (
<ImageScrollbar
onChange={evt => onImageScrollbarChange(evt, viewportId)}
max={
imageSliceData.numberOfSlices ? imageSliceData.numberOfSlices - 1 : 0
}
max={imageSliceData.numberOfSlices ? imageSliceData.numberOfSlices - 1 : 0}
height={scrollbarHeight}
value={imageSliceData.imageIndex}
/>
@@ -33,26 +33,14 @@ function ViewportImageSliceLoadingIndicator({ viewportData, element }) {
};
useEffect(() => {
element.addEventListener(
Enums.Events.STACK_VIEWPORT_SCROLL,
setLoadingState
);
element.addEventListener(Enums.Events.STACK_VIEWPORT_SCROLL, setLoadingState);
element.addEventListener(Enums.Events.IMAGE_LOAD_ERROR, setErrorState);
element.addEventListener(
Enums.Events.STACK_NEW_IMAGE,
setFinishLoadingState
);
element.addEventListener(Enums.Events.STACK_NEW_IMAGE, setFinishLoadingState);
return () => {
element.removeEventListener(
Enums.Events.STACK_VIEWPORT_SCROLL,
setLoadingState
);
element.removeEventListener(Enums.Events.STACK_VIEWPORT_SCROLL, setLoadingState);
element.removeEventListener(
Enums.Events.STACK_NEW_IMAGE,
setFinishLoadingState
);
element.removeEventListener(Enums.Events.STACK_NEW_IMAGE, setFinishLoadingState);
element.removeEventListener(Enums.Events.IMAGE_LOAD_ERROR, setErrorState);
};
@@ -61,8 +49,8 @@ function ViewportImageSliceLoadingIndicator({ viewportData, element }) {
if (error) {
return (
<>
<div className="bg-black opacity-50 absolute h-full w-full top-0 left-0">
<div className="flex transparent items-center justify-center w-full h-full">
<div className="absolute top-0 left-0 h-full w-full bg-black opacity-50">
<div className="transparent flex h-full w-full items-center justify-center">
<p className="text-primary-light text-xl font-light">
<h4>Error Loading Image</h4>
<p>An error has occurred.</p>
@@ -78,8 +66,8 @@ function ViewportImageSliceLoadingIndicator({ viewportData, element }) {
return (
// IMPORTANT: we need to use the pointer-events-none class to prevent the loading indicator from
// interacting with the mouse, since scrolling should propagate to the viewport underneath
<div className="pointer-events-none bg-black opacity-50 absolute h-full w-full top-0 left-0">
<div className="flex transparent items-center justify-center w-full h-full">
<div className="pointer-events-none absolute top-0 left-0 h-full w-full bg-black opacity-50">
<div className="transparent flex h-full w-full items-center justify-center">
<p className="text-primary-light text-xl font-light">Loading...</p>
</div>
</div>
@@ -13,10 +13,7 @@ import { vec3 } from 'gl-matrix';
import './ViewportOrientationMarkers.css';
const {
getOrientationStringLPS,
invertOrientationStringLPS,
} = utilities.orientation;
const { getOrientationStringLPS, invertOrientationStringLPS } = utilities.orientation;
function ViewportOrientationMarkers({
element,
@@ -33,9 +30,7 @@ function ViewportOrientationMarkers({
const { cornerstoneViewportService } = servicesManager.services;
useEffect(() => {
const cameraModifiedListener = (
evt: Types.EventTypes.CameraModifiedEvent
) => {
const cameraModifiedListener = (evt: Types.EventTypes.CameraModifiedEvent) => {
const { rotation, previousCamera, camera } = evt.detail;
if (rotation !== undefined) {
@@ -57,16 +52,10 @@ function ViewportOrientationMarkers({
}
};
element.addEventListener(
Enums.Events.CAMERA_MODIFIED,
cameraModifiedListener
);
element.addEventListener(Enums.Events.CAMERA_MODIFIED, cameraModifiedListener);
return () => {
element.removeEventListener(
Enums.Events.CAMERA_MODIFIED,
cameraModifiedListener
);
element.removeEventListener(Enums.Events.CAMERA_MODIFIED, cameraModifiedListener);
};
}, []);
@@ -85,8 +74,7 @@ function ViewportOrientationMarkers({
return false;
}
({ rowCosines, columnCosines } =
metaData.get('imagePlaneModule', imageId) || {});
({ rowCosines, columnCosines } = metaData.get('imagePlaneModule', imageId) || {});
} else {
if (!element || !getEnabledElement(element)) {
return '';
@@ -124,9 +112,7 @@ function ViewportOrientationMarkers({
// Todo: probably this can be done in a better way in which we identify bright
// background
const isLight = backgroundColor
? csUtils.isEqual(backgroundColor, [1, 1, 1])
: false;
const isLight = backgroundColor ? csUtils.isEqual(backgroundColor, [1, 1, 1]) : false;
return orientationMarkers.map((m, index) => (
<div
@@ -172,13 +158,7 @@ ViewportOrientationMarkers.defaultProps = {
* @param {*} rotation in degrees
* @returns
*/
function _getOrientationMarkers(
rowCosines,
columnCosines,
rotation,
flipVertical,
flipHorizontal
) {
function _getOrientationMarkers(rowCosines, columnCosines, rotation, flipVertical, flipHorizontal) {
const rowString = getOrientationStringLPS(rowCosines);
const columnString = getOrientationStringLPS(columnCosines);
const oppositeRowString = invertOrientationStringLPS(rowString);
@@ -14,10 +14,7 @@ function CornerstoneViewportOverlay({
viewportId,
servicesManager,
}) {
const {
cornerstoneViewportService,
toolbarService,
} = servicesManager.services;
const { cornerstoneViewportService, toolbarService } = servicesManager.services;
const [voi, setVOI] = useState({ windowCenter: null, windowWidth: null });
const [scale, setScale] = useState(1);
const [activeTools, setActiveTools] = useState([]);
@@ -60,10 +57,7 @@ function CornerstoneViewportOverlay({
}
const { lower, upper } = range;
const { windowWidth, windowCenter } = utilities.windowLevel.toWindowLevel(
lower,
upper
);
const { windowWidth, windowCenter } = utilities.windowLevel.toWindowLevel(lower, upper);
setVOI({ windowCenter, windowWidth });
};
@@ -86,9 +80,7 @@ function CornerstoneViewportOverlay({
previousCamera.parallelScale !== camera.parallelScale ||
previousCamera.scale !== camera.scale
) {
const viewport = cornerstoneViewportService.getCornerstoneViewport(
viewportId
);
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
if (!viewport) {
return;
@@ -107,8 +99,7 @@ function CornerstoneViewportOverlay({
const { spacing } = imageData;
// convert parallel scale to scale
const scale =
(element.clientHeight * spacing[0] * 0.5) / camera.parallelScale;
const scale = (element.clientHeight * spacing[0] * 0.5) / camera.parallelScale;
setScale(scale);
}
};
@@ -199,9 +190,7 @@ function CornerstoneViewportOverlay({
// Todo: probably this can be done in a better way in which we identify bright
// background
const isLight = backgroundColor
? utilities.isEqual(backgroundColor, [1, 1, 1])
: false;
const isLight = backgroundColor ? utilities.isEqual(backgroundColor, [1, 1, 1]) : false;
return (
<ViewportOverlay
@@ -251,9 +240,7 @@ function _getInstanceNumberFromVolume(
const volume = volumes[0];
const { direction, imageIds } = volume;
const cornerstoneViewport = cornerstoneViewportService.getCornerstoneViewport(
viewportId
);
const cornerstoneViewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
if (!cornerstoneViewport) {
return;
@@ -276,8 +263,7 @@ function _getInstanceNumberFromVolume(
return {};
}
const { instanceNumber } =
metaData.get('generalImageModule', imageId) || {};
const { instanceNumber } = metaData.get('generalImageModule', imageId) || {};
return parseInt(instanceNumber);
}
}
@@ -79,18 +79,12 @@ export function formatPN(name) {
*/
export function getCompression(imageId) {
const generalImageModule = metaData.get('generalImageModule', imageId) || {};
const {
lossyImageCompression,
lossyImageCompressionRatio,
lossyImageCompressionMethod,
} = generalImageModule;
const { lossyImageCompression, lossyImageCompressionRatio, lossyImageCompressionMethod } =
generalImageModule;
if (lossyImageCompression === '01' && lossyImageCompressionRatio !== '') {
const compressionMethod = lossyImageCompressionMethod || 'Lossy: ';
const compressionRatio = formatNumberPrecision(
lossyImageCompressionRatio,
2
);
const compressionRatio = formatNumberPrecision(lossyImageCompressionRatio, 2);
return compressionMethod + compressionRatio + ' : 1';
}
+21 -66
View File
@@ -57,9 +57,7 @@ function commandsModule({
// filter by allowed selected tools from config property (if there is any)
const isToolAllowed =
!optionsToUse.allowedSelectedTools ||
optionsToUse.allowedSelectedTools.includes(
firstAnnotationSelected?.metadata?.toolName
);
optionsToUse.allowedSelectedTools.includes(firstAnnotationSelected?.metadata?.toolName);
if (isToolAllowed) {
optionsToUse.nearbyToolData = firstAnnotationSelected;
} else {
@@ -89,10 +87,7 @@ function commandsModule({
},
getNearbyToolData({ nearbyToolData, element, canvasCoordinates }) {
return (
nearbyToolData ??
cstUtils.getAnnotationNearPoint(element, canvasCoordinates)
);
return nearbyToolData ?? cstUtils.getAnnotationNearPoint(element, canvasCoordinates);
},
getNearbyAnnotation({ element, canvasCoordinates }) {
const nearbyToolData = actions.getNearbyToolData({
@@ -109,18 +104,14 @@ function commandsModule({
}
const { renderingEngineId, viewportId } = enabledElement;
const toolGroup = ToolGroupManager.getToolGroupForViewport(
viewportId,
renderingEngineId
);
const toolGroup = ToolGroupManager.getToolGroupForViewport(viewportId, renderingEngineId);
const toolInstance = toolGroup.getToolInstance(toolName);
return toolInstance?.constructor?.isAnnotation ?? true;
};
return nearbyToolData?.metadata?.toolName &&
isAnnotation(nearbyToolData.metadata.toolName)
return nearbyToolData?.metadata?.toolName && isAnnotation(nearbyToolData.metadata.toolName)
? nearbyToolData
: null;
},
@@ -153,11 +144,7 @@ function commandsModule({
label,
});
measurementService.update(
updatedMeasurement.uid,
updatedMeasurement,
true
);
measurementService.update(updatedMeasurement.uid, updatedMeasurement, true);
},
false
);
@@ -220,20 +207,14 @@ function commandsModule({
}
}
}
measurementService.update(
updatedMeasurement.uid,
updatedMeasurement,
true
);
measurementService.update(updatedMeasurement.uid, updatedMeasurement, true);
},
// Retrieve value commands
getActiveViewportEnabledElement: _getActiveViewportEnabledElement,
setViewportActive: ({ viewportId }) => {
const viewportInfo = cornerstoneViewportService.getViewportInfo(
viewportId
);
const viewportInfo = cornerstoneViewportService.getViewportInfo(viewportId);
if (!viewportInfo) {
console.warn('No viewport found for viewportId:', viewportId);
return;
@@ -249,9 +230,7 @@ function commandsModule({
const { isCineEnabled } = cineService.getState();
cineService.setIsCineEnabled(!isCineEnabled);
toolbarService.setButton('Cine', { props: { isActive: !isCineEnabled } });
viewports.forEach((_, index) =>
cineService.setCine({ id: index, isPlaying: false })
);
viewports.forEach((_, index) => cineService.setCine({ id: index, isPlaying: false }));
},
setWindowLevel({ window, level, toolGroupId }) {
// convert to numbers
@@ -259,9 +238,7 @@ function commandsModule({
const windowCenterNum = Number(level);
const { viewportId } = _getActiveViewportEnabledElement();
const viewportToolGroupId = toolGroupService.getToolGroupForViewport(
viewportId
);
const viewportToolGroupId = toolGroupService.getToolGroupForViewport(viewportId);
if (toolGroupId && toolGroupId !== viewportToolGroupId) {
return;
@@ -271,10 +248,7 @@ function commandsModule({
const renderingEngine = cornerstoneViewportService.getRenderingEngine();
const viewport = renderingEngine.getViewport(viewportId);
const { lower, upper } = csUtils.windowLevel.toLowHighRange(
windowWidthNum,
windowCenterNum
);
const { lower, upper } = csUtils.windowLevel.toLowHighRange(windowWidthNum, windowCenterNum);
viewport.setProperties({
voiRange: {
@@ -323,11 +297,9 @@ function commandsModule({
return;
}
const filteredViewports = Array.from(viewports.values()).filter(
viewport => {
return toolGroupViewportIds.includes(viewport.viewportId);
}
);
const filteredViewports = Array.from(viewports.values()).filter(viewport => {
return toolGroupViewportIds.includes(viewport.viewportId);
});
if (!filteredViewports.length) {
return;
@@ -367,9 +339,7 @@ function commandsModule({
showDownloadViewportModal: () => {
const { activeViewportId } = viewportGridService.getState();
if (
!cornerstoneViewportService.getCornerstoneViewport(activeViewportId)
) {
if (!cornerstoneViewportService.getCornerstoneViewport(activeViewportId)) {
// Cannot download a non-cornerstone viewport (image).
uiNotificationService.show({
title: 'Download Image',
@@ -508,9 +478,7 @@ function commandsModule({
}
viewport = enabledElement.viewport;
} else {
viewport = cornerstoneViewportService.getCornerstoneViewport(
gridViewport.id
);
viewport = cornerstoneViewportService.getCornerstoneViewport(gridViewport.id);
}
// Get number of slices
@@ -520,14 +488,12 @@ function commandsModule({
if (viewport instanceof StackViewport) {
numberOfSlices = viewport.getImageIds().length;
} else if (viewport instanceof VolumeViewport) {
numberOfSlices = csUtils.getImageSliceDataForVolumeViewport(viewport)
.numberOfSlices;
numberOfSlices = csUtils.getImageSliceDataForVolumeViewport(viewport).numberOfSlices;
} else {
throw new Error('Unsupported viewport type');
}
const jumpIndex =
imageIndex < 0 ? numberOfSlices + imageIndex : imageIndex;
const jumpIndex = imageIndex < 0 ? numberOfSlices + imageIndex : imageIndex;
if (jumpIndex >= numberOfSlices || jumpIndex < 0) {
throw new Error(`Can't jump to ${imageIndex}`);
}
@@ -548,15 +514,8 @@ function commandsModule({
cstUtils.scroll(viewport, options);
},
setViewportColormap: ({
viewportId,
displaySetInstanceUID,
colormap,
immediate = false,
}) => {
const viewport = cornerstoneViewportService.getCornerstoneViewport(
viewportId
);
setViewportColormap: ({ viewportId, displaySetInstanceUID, colormap, immediate = false }) => {
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
const actorEntries = viewport.getActors();
@@ -578,9 +537,7 @@ function commandsModule({
const currentIndex = viewportIds.indexOf(activeViewportId);
const nextViewportIndex =
(currentIndex + direction + viewportIds.length) % viewportIds.length;
viewportGridService.setActiveViewportId(
viewportIds[nextViewportIndex] as string
);
viewportGridService.setActiveViewportId(viewportIds[nextViewportIndex] as string);
},
toggleStackImageSync: ({ toggledState }) => {
@@ -592,9 +549,7 @@ function commandsModule({
},
toggleReferenceLines: ({ toggledState }) => {
const { activeViewportId } = viewportGridService.getState();
const viewportInfo = cornerstoneViewportService.getViewportInfo(
activeViewportId
);
const viewportInfo = cornerstoneViewportService.getViewportInfo(activeViewportId);
const viewportId = viewportInfo.getViewportId();
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);
@@ -46,17 +46,11 @@ function WrappedCinePlayer({ enabledVPElement, viewportId, servicesManager }) {
};
useEffect(() => {
eventTarget.addEventListener(
Enums.Events.STACK_VIEWPORT_NEW_STACK,
cineHandler
);
eventTarget.addEventListener(Enums.Events.STACK_VIEWPORT_NEW_STACK, cineHandler);
return () => {
cineService.setCine({ id: viewportId, isPlaying: false });
eventTarget.removeEventListener(
Enums.Events.STACK_VIEWPORT_NEW_STACK,
cineHandler
);
eventTarget.removeEventListener(Enums.Events.STACK_VIEWPORT_NEW_STACK, cineHandler);
};
}, [enabledVPElement]);
@@ -80,7 +74,7 @@ function WrappedCinePlayer({ enabledVPElement, viewportId, servicesManager }) {
return (
isCineEnabled && (
<CinePlayerComponent
className="absolute left-1/2 -translate-x-1/2 bottom-3"
className="absolute left-1/2 bottom-3 -translate-x-1/2"
isPlaying={isPlaying}
onClose={handleCineClose}
onPlayPauseChange={isPlaying =>
@@ -1,6 +1,23 @@
.dicom-upload-drop-area-border-dash {
background-image: repeating-linear-gradient(to right, #7BB2CE 0%, #7BB2CE 50%, transparent 50%, transparent 100%), repeating-linear-gradient(to right, #7BB2CE 0%, #7BB2CE 50%, transparent 50%, transparent 100%), repeating-linear-gradient(to bottom, #7BB2CE 0%, #7BB2CE 50%, transparent 50%, transparent 100%), repeating-linear-gradient(to bottom, #7BB2CE 0%, #7BB2CE 50%, transparent 50%, transparent 100%);
background-position: left top, left bottom, left top, right top;
background-image: repeating-linear-gradient(
to right,
#7bb2ce 0%,
#7bb2ce 50%,
transparent 50%,
transparent 100%
),
repeating-linear-gradient(to right, #7bb2ce 0%, #7bb2ce 50%, transparent 50%, transparent 100%),
repeating-linear-gradient(to bottom, #7bb2ce 0%, #7bb2ce 50%, transparent 50%, transparent 100%),
repeating-linear-gradient(to bottom, #7bb2ce 0%, #7bb2ce 50%, transparent 50%, transparent 100%);
background-position:
left top,
left bottom,
left top,
right top;
background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
background-size: 20px 3px, 20px 3px, 3px 20px, 3px 20px;
background-size:
20px 3px,
20px 3px,
3px 20px,
3px 20px;
}
@@ -14,19 +14,13 @@ type DicomUploadProps = {
onStarted: () => void;
};
function DicomUpload({
dataSource,
onComplete,
onStarted,
}: DicomUploadProps): ReactElement {
function DicomUpload({ dataSource, onComplete, onStarted }: DicomUploadProps): ReactElement {
const baseClassNames = 'min-h-[480px] flex flex-col bg-black select-none';
const [dicomFileUploaderArr, setDicomFileUploaderArr] = useState([]);
const onDrop = useCallback(async acceptedFiles => {
onStarted();
setDicomFileUploaderArr(
acceptedFiles.map(file => new DicomFileUploader(file, dataSource))
);
setDicomFileUploaderArr(acceptedFiles.map(file => new DicomFileUploader(file, dataSource)));
}, []);
const getDropZoneComponent = (): ReactElement => {
@@ -40,20 +34,29 @@ function DicomUpload({
{({ getRootProps }) => (
<div
{...getRootProps()}
className="m-5 dicom-upload-drop-area-border-dash flex flex-col items-center justify-center h-full"
className="dicom-upload-drop-area-border-dash m-5 flex h-full flex-col items-center justify-center"
>
<div className="flex gap-3">
<Dropzone onDrop={onDrop} noDrag>
<Dropzone
onDrop={onDrop}
noDrag
>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()}>
<Button disabled={false} onClick={() => {}}>
<Button
disabled={false}
onClick={() => {}}
>
{'Add files'}
<input {...getInputProps()} />
</Button>
</div>
)}
</Dropzone>
<Dropzone onDrop={onDrop} noDrag>
<Dropzone
onDrop={onDrop}
noDrag
>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()}>
<Button
@@ -73,9 +76,7 @@ function DicomUpload({
</Dropzone>
</div>
<div className="pt-5">or drag images or folders here</div>
<div className="pt-3 text-aqua-pale text-lg">
(DICOM files supported)
</div>
<div className="text-aqua-pale pt-3 text-lg">(DICOM files supported)</div>
</div>
)}
</Dropzone>
@@ -92,9 +93,7 @@ function DicomUpload({
/>
</div>
) : (
<div className={classNames('h-[480px]', baseClassNames)}>
{getDropZoneComponent()}
</div>
<div className={classNames('h-[480px]', baseClassNames)}>{getDropZoneComponent()}</div>
)}
</>
);
@@ -1,10 +1,4 @@
import React, {
useCallback,
useEffect,
useRef,
useState,
ReactElement,
} from 'react';
import React, { useCallback, useEffect, useRef, useState, ReactElement } from 'react';
import PropTypes from 'prop-types';
import { Button, Icon, ProgressLoadingBar } from '@ohif/ui';
import DicomFileUploader, {
@@ -39,18 +33,14 @@ const BASE_INTERVAL_TIME = 15000;
// calculate the upload rate.
const UPLOAD_RATE_THRESHOLD = 75;
const NO_WRAP_ELLIPSIS_CLASS_NAMES =
'text-ellipsis whitespace-nowrap overflow-hidden';
const NO_WRAP_ELLIPSIS_CLASS_NAMES = 'text-ellipsis whitespace-nowrap overflow-hidden';
function DicomUploadProgress({
dicomFileUploaderArr,
onComplete,
}: DicomUploadProgressProps): ReactElement {
const [totalUploadSize] = useState(
dicomFileUploaderArr.reduce(
(acc, fileUploader) => acc + fileUploader.getFileSize(),
0
)
dicomFileUploaderArr.reduce((acc, fileUploader) => acc + fileUploader.getFileSize(), 0)
);
const currentUploadSizeRef = useRef<number>(0);
@@ -83,15 +73,13 @@ function DicomUploadProgress({
let intervalStartTime = Date.now();
const setUploadRateRef = () => {
const uploadSizeFromStartOfInterval =
currentUploadSizeRef.current - intervalStartUploadSize;
const uploadSizeFromStartOfInterval = currentUploadSizeRef.current - intervalStartUploadSize;
const now = Date.now();
const timeSinceStartOfInterval = now - intervalStartTime;
// Calculate and set the upload rate (ref)
uploadRateRef.current =
uploadSizeFromStartOfInterval / timeSinceStartOfInterval;
uploadRateRef.current = uploadSizeFromStartOfInterval / timeSinceStartOfInterval;
// Reset the interval starting values.
intervalStartUploadSize = currentUploadSizeRef.current;
@@ -134,28 +122,19 @@ function DicomUploadProgress({
const updateProgress = (percentComplete: number) => {
const previousFileUploadSize = currentFileUploadSize;
currentFileUploadSize = Math.round(
(percentComplete / 100) * fileUploader.getFileSize()
);
currentFileUploadSize = Math.round((percentComplete / 100) * fileUploader.getFileSize());
currentUploadSizeRef.current = Math.min(
totalUploadSize,
currentUploadSizeRef.current -
previousFileUploadSize +
currentFileUploadSize
currentUploadSizeRef.current - previousFileUploadSize + currentFileUploadSize
);
setPercentComplete(
(currentUploadSizeRef.current / totalUploadSize) * 100
);
setPercentComplete((currentUploadSizeRef.current / totalUploadSize) * 100);
if (uploadRateRef.current !== 0) {
const uploadSizeRemaining =
totalUploadSize - currentUploadSizeRef.current;
const uploadSizeRemaining = totalUploadSize - currentUploadSizeRef.current;
const timeRemaining = Math.round(
uploadSizeRemaining / uploadRateRef.current
);
const timeRemaining = Math.round(uploadSizeRemaining / uploadRateRef.current);
if (currentTimeRemaining === null) {
currentTimeRemaining = timeRemaining;
@@ -168,9 +147,7 @@ function DicomUploadProgress({
// due to rounding, inaccuracies in the estimate and slight variations
// in upload rates over time.
if (timeRemaining < ONE_MINUTE) {
const currentSecondsRemaining = Math.ceil(
currentTimeRemaining / ONE_SECOND
);
const currentSecondsRemaining = Math.ceil(currentTimeRemaining / ONE_SECOND);
const secondsRemaining = Math.ceil(timeRemaining / ONE_SECOND);
const delta = secondsRemaining - currentSecondsRemaining;
if (delta < 0 || delta > 2) {
@@ -181,9 +158,7 @@ function DicomUploadProgress({
}
if (timeRemaining < ONE_HOUR) {
const currentMinutesRemaining = Math.ceil(
currentTimeRemaining / ONE_MINUTE
);
const currentMinutesRemaining = Math.ceil(currentTimeRemaining / ONE_MINUTE);
const minutesRemaining = Math.ceil(timeRemaining / ONE_MINUTE);
const delta = minutesRemaining - currentMinutesRemaining;
if (delta < 0 || delta > 2) {
@@ -199,9 +174,7 @@ function DicomUploadProgress({
}
};
const progressCallback = (
progressEvent: DicomFileUploaderProgressEvent
) => {
const progressCallback = (progressEvent: DicomFileUploaderProgressEvent) => {
updateProgress(progressEvent.percentComplete);
};
@@ -249,16 +222,12 @@ function DicomUploadProgress({
if (timeRemaining < ONE_MINUTE) {
const secondsRemaining = Math.ceil(timeRemaining / ONE_SECOND);
return `${secondsRemaining} ${
secondsRemaining === 1 ? 'second' : 'seconds'
}`;
return `${secondsRemaining} ${secondsRemaining === 1 ? 'second' : 'seconds'}`;
}
if (timeRemaining < ONE_HOUR) {
const minutesRemaining = Math.ceil(timeRemaining / ONE_MINUTE);
return `${minutesRemaining} ${
minutesRemaining === 1 ? 'minute' : 'minutes'
}`;
return `${minutesRemaining} ${minutesRemaining === 1 ? 'minute' : 'minutes'}`;
}
const hoursRemaining = Math.ceil(timeRemaining / ONE_HOUR);
@@ -278,9 +247,7 @@ function DicomUploadProgress({
const showInfiniteProgressBar = useCallback((): boolean => {
return (
getPercentCompleteRounded() < 1 &&
(progressBarContainerRef?.current?.offsetWidth ?? 0) *
(percentComplete / 100) <
1
(progressBarContainerRef?.current?.offsetWidth ?? 0) * (percentComplete / 100) < 1
);
}, [getPercentCompleteRounded, percentComplete]);
@@ -300,15 +267,17 @@ function DicomUploadProgress({
const getNumCompletedAndTimeRemainingComponent = (): ReactElement => {
return (
<div className="text-lg px-1 pb-4 h-14 flex bg-primary-dark items-center">
<div className="bg-primary-dark flex h-14 items-center px-1 pb-4 text-lg">
{numFilesCompleted === dicomFileUploaderArr.length ? (
<>
<span className={NO_WRAP_ELLIPSIS_CLASS_NAMES}>{`${
dicomFileUploaderArr.length
} ${
<span className={NO_WRAP_ELLIPSIS_CLASS_NAMES}>{`${dicomFileUploaderArr.length} ${
dicomFileUploaderArr.length > 1 ? 'files' : 'file'
} completed.`}</span>
<Button disabled={false} className="ml-auto" onClick={onComplete}>
<Button
disabled={false}
className="ml-auto"
onClick={onComplete}
>
{'Close'}
</Button>
</>
@@ -320,18 +289,14 @@ function DicomUploadProgress({
>
{`${numFilesCompleted} of ${dicomFileUploaderArr.length}`}&nbsp;
</span>
<span className={NO_WRAP_ELLIPSIS_CLASS_NAMES}>{' files completed.'}&nbsp;</span>
<span className={NO_WRAP_ELLIPSIS_CLASS_NAMES}>
{' files completed.'}&nbsp;
</span>
<span className={NO_WRAP_ELLIPSIS_CLASS_NAMES}>
{timeRemaining
? `Less than ${getFormattedTimeRemaining()} remaining. `
: ''}
{timeRemaining ? `Less than ${getFormattedTimeRemaining()} remaining. ` : ''}
</span>
<span
className={classNames(
NO_WRAP_ELLIPSIS_CLASS_NAMES,
'cursor-pointer text-primary-active hover:text-primary-light active:text-aqua-pale ml-auto'
'text-primary-active hover:text-primary-light active:text-aqua-pale ml-auto cursor-pointer'
)}
onClick={cancelAllUploads}
>
@@ -345,14 +310,13 @@ function DicomUploadProgress({
const getShowFailedOnlyIconComponent = (): ReactElement => {
return (
<div className="ml-auto flex justify-center w-6">
<div className="ml-auto flex w-6 justify-center">
{numFails > 0 && (
<div
onClick={() =>
setShowFailedOnly(currentShowFailedOnly => !currentShowFailedOnly)
}
>
<Icon className="cursor-pointer" name="icon-status-alert"></Icon>
<div onClick={() => setShowFailedOnly(currentShowFailedOnly => !currentShowFailedOnly)}>
<Icon
className="cursor-pointer"
name="icon-status-alert"
></Icon>
</div>
)}
</div>
@@ -361,31 +325,28 @@ function DicomUploadProgress({
const getPercentCompleteComponent = (): ReactElement => {
return (
<div className="overflow-y-scroll ohif-scrollbar px-2 border-b border-secondary-light">
<div className="flex w-full p-2.5 items-center min-h-14">
<div className="ohif-scrollbar border-secondary-light overflow-y-scroll border-b px-2">
<div className="min-h-14 flex w-full items-center p-2.5">
{numFilesCompleted === dicomFileUploaderArr.length ? (
<>
<div className="text-xl text-primary-light">
<div className="text-primary-light text-xl">
{numFails > 0
? `Completed with ${numFails} ${
numFails > 1 ? 'errors' : 'error'
}!`
? `Completed with ${numFails} ${numFails > 1 ? 'errors' : 'error'}!`
: 'Completed!'}
</div>
{getShowFailedOnlyIconComponent()}
</>
) : (
<>
<div ref={progressBarContainerRef} className="flex-grow">
<div
ref={progressBarContainerRef}
className="flex-grow"
>
<ProgressLoadingBar
progress={
showInfiniteProgressBar()
? undefined
: Math.min(100, percentComplete)
}
progress={showInfiniteProgressBar() ? undefined : Math.min(100, percentComplete)}
></ProgressLoadingBar>
</div>
<div className="w-24 ml-1 flex items-center">
<div className="ml-1 flex w-24 items-center">
<div className="w-10 text-right">{`${getPercentCompleteRounded()}%`}</div>
{getShowFailedOnlyIconComponent()}
</div>
@@ -397,16 +358,15 @@ function DicomUploadProgress({
};
return (
<div className="flex flex-col grow">
<div className="flex grow flex-col">
{getNumCompletedAndTimeRemainingComponent()}
<div className="flex flex-col bg-black text-lg overflow-hidden grow">
<div className="flex grow flex-col overflow-hidden bg-black text-lg">
{getPercentCompleteComponent()}
<div className="overflow-y-scroll ohif-scrollbar px-2 grow h-1">
<div className="ohif-scrollbar h-1 grow overflow-y-scroll px-2">
{dicomFileUploaderArr
.filter(
dicomFileUploader =>
!showFailedOnly ||
dicomFileUploader.getStatus() === UploadStatus.Failed
!showFailedOnly || dicomFileUploader.getStatus() === UploadStatus.Failed
)
.map(dicomFileUploader => (
<DicomUploadProgressItem
@@ -421,9 +381,7 @@ function DicomUploadProgress({
}
DicomUploadProgress.propTypes = {
dicomFileUploaderArr: PropTypes.arrayOf(
PropTypes.instanceOf(DicomFileUploader)
).isRequired,
dicomFileUploaderArr: PropTypes.arrayOf(PropTypes.instanceOf(DicomFileUploader)).isRequired,
onComplete: PropTypes.func.isRequired,
};
@@ -1,10 +1,4 @@
import React, {
ReactElement,
memo,
useCallback,
useEffect,
useState,
} from 'react';
import React, { ReactElement, memo, useCallback, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import DicomFileUploader, {
DicomFileUploaderProgressEvent,
@@ -21,9 +15,7 @@ type DicomUploadProgressItemProps = {
// eslint-disable-next-line react/display-name
const DicomUploadProgressItem = memo(
({ dicomFileUploader }: DicomUploadProgressItemProps): ReactElement => {
const [percentComplete, setPercentComplete] = useState(
dicomFileUploader.getPercentComplete()
);
const [percentComplete, setPercentComplete] = useState(dicomFileUploader.getPercentComplete());
const [failedReason, setFailedReason] = useState('');
const [status, setStatus] = useState(dicomFileUploader.getStatus());
@@ -62,7 +54,10 @@ const DicomUploadProgressItem = memo(
switch (dicomFileUploader.getStatus()) {
case UploadStatus.Success:
return (
<Icon name="status-tracked" className="text-primary-light"></Icon>
<Icon
name="status-tracked"
className="text-primary-light"
></Icon>
);
case UploadStatus.InProgress:
return <Icon name="icon-transferring"></Icon>;
@@ -76,27 +71,25 @@ const DicomUploadProgressItem = memo(
};
return (
<div className="flex w-full p-2.5 text-lg min-h-14 items-center border-b border-secondary-light overflow-hidden">
<div className="flex flex-col gap-1 self-top w-0 grow shrink">
<div className="min-h-14 border-secondary-light flex w-full items-center overflow-hidden border-b p-2.5 text-lg">
<div className="self-top flex w-0 shrink grow flex-col gap-1">
<div className="flex gap-4">
<div className="flex w-6 justify-center items-center shrink-0">
{getStatusIcon()}
</div>
<div className="text-ellipsis whitespace-nowrap overflow-hidden">
<div className="flex w-6 shrink-0 items-center justify-center">{getStatusIcon()}</div>
<div className="overflow-hidden text-ellipsis whitespace-nowrap">
{dicomFileUploader.getFileName()}
</div>
</div>
{failedReason && <div className="pl-10">{failedReason}</div>}
</div>
<div className="w-24 flex items-center">
<div className="flex w-24 items-center">
{!isComplete() && (
<>
{dicomFileUploader.getStatus() === UploadStatus.InProgress && (
<div className="w-10 text-right">{percentComplete}%</div>
)}
<div className="flex cursor-pointer ml-auto">
<div className="ml-auto flex cursor-pointer">
<Icon
className="self-center text-primary-active"
className="text-primary-active self-center"
name="close"
onClick={cancelUpload}
/>
+8 -7
View File
@@ -31,9 +31,7 @@ import { measurementMappingUtils } from './utils/measurementServiceMappings';
import type { PublicViewportOptions } from './services/ViewportService/Viewport';
const Component = React.lazy(() => {
return import(
/* webpackPrefetch: true */ './Viewport/OHIFCornerstoneViewport'
);
return import(/* webpackPrefetch: true */ './Viewport/OHIFCornerstoneViewport');
});
const OHIFCornerstoneViewport = props => {
@@ -69,9 +67,7 @@ const cornerstoneExtension: Types.Extensions.Extension = {
*
* @param configuration.csToolsConfig - Passed directly to `initCornerstoneTools`
*/
preRegistration: function (
props: Types.Extensions.ExtensionParams
): Promise<void> {
preRegistration: function (props: Types.Extensions.ExtensionParams): Promise<void> {
const { servicesManager } = props;
servicesManager.registerService(CornerstoneViewportService.REGISTRATION);
servicesManager.registerService(ToolGroupService.REGISTRATION);
@@ -139,5 +135,10 @@ const cornerstoneExtension: Types.Extensions.Extension = {
};
export type { PublicViewportOptions };
export { measurementMappingUtils, CornerstoneExtensionTypes, toolNames , getActiveViewportEnabledElement};
export {
measurementMappingUtils,
CornerstoneExtensionTypes,
toolNames,
getActiveViewportEnabledElement,
};
export default cornerstoneExtension;
+29 -78
View File
@@ -49,8 +49,7 @@ export default async function init({
...cornerstone.getConfiguration(),
rendering: {
...cornerstone.getConfiguration().rendering,
strictZSpacingForVolumeViewport:
appConfig.strictZSpacingForVolumeViewport,
strictZSpacingForVolumeViewport: appConfig.strictZSpacingForVolumeViewport,
},
});
@@ -62,10 +61,7 @@ export default async function init({
initCornerstoneTools();
Settings.getRuntimeSettings().set(
'useCursors',
Boolean(appConfig.useCursors)
);
Settings.getRuntimeSettings().set('useCursors', Boolean(appConfig.useCursors));
const {
userAuthenticationService,
@@ -84,22 +80,15 @@ export default async function init({
window.extensionManager = extensionManager;
window.commandsManager = commandsManager;
if (
appConfig.showWarningMessageForCrossOrigin &&
!window.crossOriginIsolated
) {
if (appConfig.showWarningMessageForCrossOrigin && !window.crossOriginIsolated) {
uiNotificationService.show({
title: 'Cross Origin Isolation',
message:
'Cross Origin Isolation is not enabled, volume rendering will not work (e.g., MPR)',
message: 'Cross Origin Isolation is not enabled, volume rendering will not work (e.g., MPR)',
type: 'warning',
});
}
if (
appConfig.showCPUFallbackMessage &&
cornerstone.getShouldUseCPURendering()
) {
if (appConfig.showCPUFallbackMessage && cornerstone.getShouldUseCPURendering()) {
_showCPURenderingModal(uiModalService, hangingProtocolService);
}
@@ -119,18 +108,14 @@ export default async function init({
clearOnModeExit: true,
});
const labelmapRepresentation =
cornerstoneTools.Enums.SegmentationRepresentations.Labelmap;
const labelmapRepresentation = cornerstoneTools.Enums.SegmentationRepresentations.Labelmap;
cornerstoneTools.segmentation.config.setGlobalRepresentationConfig(
labelmapRepresentation,
{
fillAlpha: 0.3,
fillAlphaInactive: 0.2,
outlineOpacity: 1,
outlineOpacityInactive: 0.65,
}
);
cornerstoneTools.segmentation.config.setGlobalRepresentationConfig(labelmapRepresentation, {
fillAlpha: 0.3,
fillAlphaInactive: 0.2,
outlineOpacity: 1,
outlineOpacityInactive: 0.65,
});
const metadataProvider = OHIF.classes.MetadataProvider;
@@ -139,14 +124,8 @@ export default async function init({
cornerstoneStreamingImageVolumeLoader
);
hangingProtocolService.registerImageLoadStrategy(
'interleaveCenter',
interleaveCenterLoader
);
hangingProtocolService.registerImageLoadStrategy(
'interleaveTopToBottom',
interleaveTopToBottom
);
hangingProtocolService.registerImageLoadStrategy('interleaveCenter', interleaveCenterLoader);
hangingProtocolService.registerImageLoadStrategy('interleaveTopToBottom', interleaveTopToBottom);
hangingProtocolService.registerImageLoadStrategy('nth', nthLoader);
// add metadata providers
@@ -166,9 +145,7 @@ export default async function init({
initWADOImageLoader(userAuthenticationService, appConfig, extensionManager);
/* Measurement Service */
this.measurementServiceSource = connectToolsToMeasurementService(
servicesManager
);
this.measurementServiceSource = connectToolsToMeasurementService(servicesManager);
initCineService(cineService);
@@ -178,31 +155,18 @@ export default async function init({
volumeInputArrayMap => {
for (const entry of volumeInputArrayMap.entries()) {
const [viewportId, volumeInputArray] = entry;
const viewport = cornerstoneViewportService.getCornerstoneViewport(
viewportId
);
const viewport = cornerstoneViewportService.getCornerstoneViewport(viewportId);
const ohifViewport = cornerstoneViewportService.getViewportInfo(
viewportId
);
const ohifViewport = cornerstoneViewportService.getViewportInfo(viewportId);
const {
lutPresentationStore,
positionPresentationStore,
} = stateSyncService.getState();
const { lutPresentationStore, positionPresentationStore } = stateSyncService.getState();
const { presentationIds } = ohifViewport.getViewportOptions();
const presentations = {
positionPresentation:
positionPresentationStore[presentationIds?.positionPresentationId],
lutPresentation:
lutPresentationStore[presentationIds?.lutPresentationId],
positionPresentation: positionPresentationStore[presentationIds?.positionPresentationId],
lutPresentation: lutPresentationStore[presentationIds?.lutPresentationId],
};
cornerstoneViewportService.setVolumesForViewport(
viewport,
volumeInputArray,
presentations
);
cornerstoneViewportService.setVolumesForViewport(viewport, volumeInputArray, presentations);
}
}
);
@@ -225,9 +189,7 @@ export default async function init({
const resetCrosshairs = evt => {
const { element } = evt.detail;
const { viewportId, renderingEngineId } = cornerstone.getEnabledElement(
element
);
const { viewportId, renderingEngineId } = cornerstone.getEnabledElement(element);
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroupForViewport(
viewportId,
@@ -253,10 +215,7 @@ export default async function init({
const { element } = evt.detail;
element.addEventListener(EVENTS.CAMERA_RESET, resetCrosshairs);
eventTarget.addEventListener(
EVENTS.STACK_VIEWPORT_NEW_STACK,
newStackCallback
);
eventTarget.addEventListener(EVENTS.STACK_VIEWPORT_NEW_STACK, newStackCallback);
}
function elementDisabledHandler(evt) {
@@ -271,15 +230,9 @@ export default async function init({
// );
}
eventTarget.addEventListener(
EVENTS.ELEMENT_ENABLED,
elementEnabledHandler.bind(null)
);
eventTarget.addEventListener(EVENTS.ELEMENT_ENABLED, elementEnabledHandler.bind(null));
eventTarget.addEventListener(
EVENTS.ELEMENT_DISABLED,
elementDisabledHandler.bind(null)
);
eventTarget.addEventListener(EVENTS.ELEMENT_DISABLED, elementDisabledHandler.bind(null));
viewportGridService.subscribe(
viewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED,
@@ -292,8 +245,7 @@ export default async function init({
// check if reference lines are active
const referenceLinesEnabled =
toolGroup._toolInstances['ReferenceLines'].mode ===
Enums.ToolModes.Enabled;
toolGroup._toolInstances['ReferenceLines'].mode === Enums.ToolModes.Enabled;
if (!referenceLinesEnabled) {
return;
@@ -318,10 +270,9 @@ function CPUModal() {
return (
<div>
<p>
Your computer does not have enough GPU power to support the default GPU
rendering mode. OHIF has switched to CPU rendering mode. Please note
that CPU rendering does not support all features such as Volume
Rendering, Multiplanar Reconstruction, and Segmentation Overlays.
Your computer does not have enough GPU power to support the default GPU rendering mode. OHIF
has switched to CPU rendering mode. Please note that CPU rendering does not support all
features such as Volume Rendering, Multiplanar Reconstruction, and Segmentation Overlays.
</p>
</div>
);
+5 -18
View File
@@ -60,8 +60,7 @@ function initContextMenu({
*/
const cornerstoneViewportHandleEvent = (name, evt) => {
const customizations =
customizationService.get('cornerstoneViewportClickCommands') ||
DEFAULT_CONTEXT_MENU_CLICKS;
customizationService.get('cornerstoneViewportClickCommands') || DEFAULT_CONTEXT_MENU_CLICKS;
const toRun = customizations[name];
const options = {
nearbyToolData: findNearbyToolData(commandsManager, evt),
@@ -84,30 +83,18 @@ function initContextMenu({
// TODO check update upstream
setEnabledElement(viewportId, element);
element.addEventListener(
cs3DToolsEvents.MOUSE_CLICK,
cornerstoneViewportHandleClick
);
element.addEventListener(cs3DToolsEvents.MOUSE_CLICK, cornerstoneViewportHandleClick);
}
function elementDisabledHandler(evt) {
const { element } = evt.detail;
element.removeEventListener(
cs3DToolsEvents.MOUSE_CLICK,
cornerstoneViewportHandleClick
);
element.removeEventListener(cs3DToolsEvents.MOUSE_CLICK, cornerstoneViewportHandleClick);
}
eventTarget.addEventListener(
EVENTS.ELEMENT_ENABLED,
elementEnabledHandler.bind(null)
);
eventTarget.addEventListener(EVENTS.ELEMENT_ENABLED, elementEnabledHandler.bind(null));
eventTarget.addEventListener(
EVENTS.ELEMENT_DISABLED,
elementDisabledHandler.bind(null)
);
eventTarget.addEventListener(EVENTS.ELEMENT_DISABLED, elementDisabledHandler.bind(null));
}
export default initContextMenu;
+4 -14
View File
@@ -39,10 +39,7 @@ export type initDoubleClickArgs = {
commandsManager: CommandsManager;
};
function initDoubleClick({
customizationService,
commandsManager,
}: initDoubleClickArgs): void {
function initDoubleClick({ customizationService, commandsManager }: initDoubleClickArgs): void {
const cornerstoneViewportHandleDoubleClick = (evt: CustomEvent) => {
// Do not allow double click on a tool.
const nearbyToolData = findNearbyToolData(commandsManager, evt);
@@ -54,8 +51,7 @@ function initDoubleClick({
// Allows for the customization of the double click on a viewport.
const customizations =
customizationService.get('cornerstoneViewportClickCommands') ||
DEFAULT_DOUBLE_CLICK;
customizationService.get('cornerstoneViewportClickCommands') || DEFAULT_DOUBLE_CLICK;
const toRun = customizations[eventName];
@@ -84,15 +80,9 @@ function initDoubleClick({
);
}
eventTarget.addEventListener(
EVENTS.ELEMENT_ENABLED,
elementEnabledHandler.bind(null)
);
eventTarget.addEventListener(EVENTS.ELEMENT_ENABLED, elementEnabledHandler.bind(null));
eventTarget.addEventListener(
EVENTS.ELEMENT_DISABLED,
elementDisabledHandler.bind(null)
);
eventTarget.addEventListener(EVENTS.ELEMENT_DISABLED, elementDisabledHandler.bind(null));
}
export default initDoubleClick;
@@ -127,11 +127,8 @@ const initMeasurementService = (
};
const connectToolsToMeasurementService = servicesManager => {
const {
measurementService,
displaySetService,
cornerstoneViewportService,
} = servicesManager.services;
const { measurementService, displaySetService, cornerstoneViewportService } =
servicesManager.services;
const csTools3DVer1MeasurementSource = initMeasurementService(
measurementService,
displaySetService,
@@ -153,10 +150,7 @@ const connectToolsToMeasurementService = servicesManager => {
} = annotationAddedEventDetail;
const { toolName } = metadata;
if (
csToolsEvent.type === completedEvt &&
toolName === toolNames.CalibrationLine
) {
if (csToolsEvent.type === completedEvt && toolName === toolNames.CalibrationLine) {
// show modal to input the measurement (mm)
onCompletedCalibrationLine(servicesManager, csToolsEvent)
.then(
@@ -212,10 +206,8 @@ const connectToolsToMeasurementService = servicesManager => {
try {
const annotationSelectionEventDetail = csToolsEvent.detail;
const {
added: addedSelectedAnnotationUIDs,
removed: removedSelectedAnnotationUIDs,
} = annotationSelectionEventDetail;
const { added: addedSelectedAnnotationUIDs, removed: removedSelectedAnnotationUIDs } =
annotationSelectionEventDetail;
if (removedSelectedAnnotationUIDs) {
removedSelectedAnnotationUIDs.forEach(annotationUID =>
@@ -283,12 +275,8 @@ const connectMeasurementServiceToTools = (
cornerstoneViewportService,
measurementSource
) => {
const {
MEASUREMENT_REMOVED,
MEASUREMENTS_CLEARED,
MEASUREMENT_UPDATED,
RAW_MEASUREMENT_ADDED,
} = measurementService.EVENTS;
const { MEASUREMENT_REMOVED, MEASUREMENTS_CLEARED, MEASUREMENT_UPDATED, RAW_MEASUREMENT_ADDED } =
measurementService.EVENTS;
const csTools3DVer1MeasurementSource = measurementService.getSource(
CORNERSTONE_3D_TOOLS_SOURCE_NAME,
@@ -351,11 +339,7 @@ const connectMeasurementServiceToTools = (
return;
}
const {
referenceSeriesUID,
referenceStudyUID,
SOPInstanceUID,
} = measurement;
const { referenceSeriesUID, referenceStudyUID, SOPInstanceUID } = measurement;
const instance = DicomMetadataStore.getInstance(
referenceStudyUID,
@@ -368,9 +352,7 @@ const connectMeasurementServiceToTools = (
if (measurement?.metadata?.referencedImageId) {
imageId = measurement.metadata.referencedImageId;
frameNumber = getSOPInstanceAttributes(
measurement.metadata.referencedImageId
).frameNumber;
frameNumber = getSOPInstanceAttributes(measurement.metadata.referencedImageId).frameNumber;
} else {
imageId = dataSource.getImageIdsForInstance({ instance });
}
@@ -1,9 +1,7 @@
import * as cornerstone from '@cornerstonejs/core';
import { volumeLoader } from '@cornerstonejs/core';
import { cornerstoneStreamingImageVolumeLoader } from '@cornerstonejs/streaming-image-volume-loader';
import dicomImageLoader, {
webWorkerManager,
} from '@cornerstonejs/dicom-image-loader';
import dicomImageLoader, { webWorkerManager } from '@cornerstonejs/dicom-image-loader';
import dicomParser from 'dicom-parser';
import { errorHandler, utils } from '@ohif/core';
@@ -41,10 +39,7 @@ export default function initWADOImageLoader(
dicomImageLoader.external.cornerstone = cornerstone;
dicomImageLoader.external.dicomParser = dicomParser;
registerVolumeLoader(
'cornerstoneStreamingImageVolume',
cornerstoneStreamingImageVolumeLoader
);
registerVolumeLoader('cornerstoneStreamingImageVolume', cornerstoneStreamingImageVolumeLoader);
dicomImageLoader.configure({
decodeConfig: {
@@ -55,10 +50,9 @@ export default function initWADOImageLoader(
// we should set this flag to false.
convertFloatPixelDataToInt: false,
},
beforeSend: function(xhr) {
beforeSend: function (xhr) {
//TODO should be removed in the future and request emitted by DicomWebDataSource
const sourceConfig =
extensionManager.getActiveDataSource()?.[0].getConfig() ?? {};
const sourceConfig = extensionManager.getActiveDataSource()?.[0].getConfig() ?? {};
const headers = userAuthenticationService.getAuthorizationHeader();
const acceptHeader = utils.generateAcceptHeader(
sourceConfig.acceptHeader,
@@ -1,16 +1,8 @@
import { ServicesManager, Types } from '@ohif/core';
import {
cache as cs3DCache,
Enums,
volumeLoader,
utilities as utils,
} from '@cornerstonejs/core';
import { cache as cs3DCache, Enums, volumeLoader, utilities as utils } from '@cornerstonejs/core';
import getCornerstoneViewportType from '../../utils/getCornerstoneViewportType';
import {
StackViewportData,
VolumeViewportData,
} from '../../types/CornerstoneCacheService';
import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService';
const VOLUME_LOADER_SCHEME = 'cornerstoneStreamingImageVolume';
@@ -18,9 +10,7 @@ class CornerstoneCacheService {
static REGISTRATION = {
name: 'cornerstoneCacheService',
altName: 'CornerstoneCacheService',
create: ({
servicesManager,
}: Types.Extensions.ExtensionParams): CornerstoneCacheService => {
create: ({ servicesManager }: Types.Extensions.ExtensionParams): CornerstoneCacheService => {
return new CornerstoneCacheService(servicesManager);
},
};
@@ -77,11 +67,7 @@ class CornerstoneCacheService {
cs3DViewportType === Enums.ViewportType.ORTHOGRAPHIC ||
cs3DViewportType === Enums.ViewportType.VOLUME_3D
) {
viewportData = await this._getVolumeViewportData(
dataSource,
displaySets,
cs3DViewportType
);
viewportData = await this._getVolumeViewportData(dataSource, displaySets, cs3DViewportType);
}
viewportData.viewportType = cs3DViewportType;
@@ -134,20 +120,14 @@ class CornerstoneCacheService {
// For Stack Viewport we don't have fusion currently
const displaySet = displaySets[0];
let stackImageIds = this.stackImageIds.get(
displaySet.displaySetInstanceUID
);
let stackImageIds = this.stackImageIds.get(displaySet.displaySetInstanceUID);
if (!stackImageIds) {
stackImageIds = this._getCornerstoneStackImageIds(displaySet, dataSource);
this.stackImageIds.set(displaySet.displaySetInstanceUID, stackImageIds);
}
const {
displaySetInstanceUID,
StudyInstanceUID,
isCompositeStack,
} = displaySet;
const { displaySetInstanceUID, StudyInstanceUID, isCompositeStack } = displaySet;
const StackViewportData: StackViewportData = {
viewportType,
@@ -196,31 +176,22 @@ class CornerstoneCacheService {
continue;
}
const volumeLoaderSchema =
displaySet.volumeLoaderSchema ?? VOLUME_LOADER_SCHEME;
const volumeLoaderSchema = displaySet.volumeLoaderSchema ?? VOLUME_LOADER_SCHEME;
const volumeId = `${volumeLoaderSchema}:${displaySet.displaySetInstanceUID}`;
let volumeImageIds = this.volumeImageIds.get(
displaySet.displaySetInstanceUID
);
let volumeImageIds = this.volumeImageIds.get(displaySet.displaySetInstanceUID);
let volume = cs3DCache.getVolume(volumeId);
if (!volumeImageIds || !volume) {
volumeImageIds = this._getCornerstoneVolumeImageIds(
displaySet,
dataSource
);
volumeImageIds = this._getCornerstoneVolumeImageIds(displaySet, dataSource);
volume = await volumeLoader.createAndCacheVolume(volumeId, {
imageIds: volumeImageIds,
});
this.volumeImageIds.set(
displaySet.displaySetInstanceUID,
volumeImageIds
);
this.volumeImageIds.set(displaySet.displaySetInstanceUID, volumeImageIds);
}
volumeData.push({
@@ -268,10 +239,7 @@ class CornerstoneCacheService {
}
private _getCornerstoneVolumeImageIds(displaySet, dataSource): string[] {
const stackImageIds = this._getCornerstoneStackImageIds(
displaySet,
dataSource
);
const stackImageIds = this._getCornerstoneStackImageIds(displaySet, dataSource);
return stackImageIds;
}
@@ -7,32 +7,27 @@
* @returns An array of object that includes data, id, segmentIndex, color
* and geometry Id
*/
export function mapROIContoursToRTStructData(
structureSet: unknown,
rtDisplaySetUID: unknown
) {
return structureSet.ROIContours.map(
({ contourPoints, ROINumber, ROIName, colorArray }) => {
const data = contourPoints.map(({ points, ...rest }) => {
const newPoints = points.map(({ x, y, z }) => {
return [x, y, z];
});
return {
...rest,
points: newPoints,
};
export function mapROIContoursToRTStructData(structureSet: unknown, rtDisplaySetUID: unknown) {
return structureSet.ROIContours.map(({ contourPoints, ROINumber, ROIName, colorArray }) => {
const data = contourPoints.map(({ points, ...rest }) => {
const newPoints = points.map(({ x, y, z }) => {
return [x, y, z];
});
const id = ROIName || ROINumber;
return {
data,
id,
segmentIndex: ROINumber,
color: colorArray,
geometryId: `${rtDisplaySetUID}:${id}:segmentIndex-${ROINumber}`,
...rest,
points: newPoints,
};
}
);
});
const id = ROIName || ROINumber;
return {
data,
id,
segmentIndex: ROINumber,
color: colorArray,
geometryId: `${rtDisplaySetUID}:${id}:segmentIndex-${ROINumber}`,
};
});
}
@@ -21,11 +21,7 @@ import {
import isEqual from 'lodash.isequal';
import { Types as ohifTypes } from '@ohif/core';
import { easeInOutBell, reverseEaseInOutBell } from '../../utils/transitions';
import {
Segment,
Segmentation,
SegmentationConfig,
} from './SegmentationServiceTypes';
import { Segment, Segmentation, SegmentationConfig } from './SegmentationServiceTypes';
import { mapROIContoursToRTStructData } from './RTSTRUCT/mapROIContoursToRTStructData';
const { COLOR_LUT } = cstConstants;
@@ -42,8 +38,7 @@ const EVENTS = {
// fired when the segmentation is removed
SEGMENTATION_REMOVED: 'event::segmentation_removed',
// fired when the configuration for the segmentation is changed (e.g., brush size, render fill, outline thickness, etc.)
SEGMENTATION_CONFIGURATION_CHANGED:
'event::segmentation_configuration_changed',
SEGMENTATION_CONFIGURATION_CHANGED: 'event::segmentation_configuration_changed',
// fired when the active segment is loaded in SEG or RTSTRUCT
SEGMENT_LOADING_COMPLETE: 'event::segment_loading_complete',
// for all segments
@@ -64,9 +59,7 @@ class SegmentationService extends PubSubService {
static REGISTRATION = {
name: 'segmentationService',
altName: 'SegmentationService',
create: ({
servicesManager,
}: OhifTypes.Extensions.ExtensionParams): SegmentationService => {
create: ({ servicesManager }: OhifTypes.Extensions.ExtensionParams): SegmentationService => {
return new SegmentationService({ servicesManager });
},
};
@@ -138,10 +131,10 @@ class SegmentationService extends PubSubService {
toolGroupId = toolGroupId ?? this._getFirstToolGroupId();
const {
segmentationRepresentationUID,
segmentation,
} = this._getSegmentationInfo(segmentationId, toolGroupId);
const { segmentationRepresentationUID, segmentation } = this._getSegmentationInfo(
segmentationId,
toolGroupId
);
if (this._getSegmentInfo(segmentation, segmentIndex)) {
throw new Error(`Segment ${segmentIndex} already exists`);
@@ -166,32 +159,14 @@ class SegmentationService extends PubSubService {
const suppressEvents = true;
if (properties !== undefined) {
const {
color: newColor,
opacity,
isLocked,
visibility,
active,
} = properties;
const { color: newColor, opacity, isLocked, visibility, active } = properties;
if (newColor !== undefined) {
this._setSegmentColor(
segmentationId,
segmentIndex,
newColor,
toolGroupId,
suppressEvents
);
this._setSegmentColor(segmentationId, segmentIndex, newColor, toolGroupId, suppressEvents);
}
if (opacity !== undefined) {
this._setSegmentOpacity(
segmentationId,
segmentIndex,
opacity,
toolGroupId,
suppressEvents
);
this._setSegmentOpacity(segmentationId, segmentIndex, opacity, toolGroupId, suppressEvents);
}
if (visibility !== undefined) {
@@ -209,12 +184,7 @@ class SegmentationService extends PubSubService {
}
if (isLocked !== undefined) {
this._setSegmentLocked(
segmentationId,
segmentIndex,
isLocked,
suppressEvents
);
this._setSegmentLocked(segmentationId, segmentIndex, isLocked, suppressEvents);
}
}
@@ -285,9 +255,7 @@ class SegmentationService extends PubSubService {
if (segmentation.activeSegmentIndex === segmentIndex) {
const segmentIndices = Object.keys(segmentation.segments);
const newActiveSegmentIndex = segmentIndices.length
? Number(segmentIndices[0])
: 1;
const newActiveSegmentIndex = segmentIndices.length ? Number(segmentIndices[0]) : 1;
this._setActiveSegment(segmentationId, newActiveSegmentIndex, true);
}
@@ -319,19 +287,10 @@ class SegmentationService extends PubSubService {
isLocked: boolean
): void {
const suppressEvents = false;
this._setSegmentLocked(
segmentationId,
segmentIndex,
isLocked,
suppressEvents
);
this._setSegmentLocked(segmentationId, segmentIndex, isLocked, suppressEvents);
}
public setSegmentLabel(
segmentationId: string,
segmentIndex: number,
segmentLabel: string
): void {
public setSegmentLabel(segmentationId: string, segmentIndex: number, segmentLabel: string): void {
this._setSegmentLabel(segmentationId, segmentIndex, segmentLabel);
}
@@ -387,24 +346,14 @@ class SegmentationService extends PubSubService {
this._setSegmentOpacity(segmentationId, segmentIndex, opacity, toolGroupId);
}
public setActiveSegmentationForToolGroup(
segmentationId: string,
toolGroupId?: string
): void {
public setActiveSegmentationForToolGroup(segmentationId: string, toolGroupId?: string): void {
toolGroupId = toolGroupId ?? this._getFirstToolGroupId();
const suppressEvents = false;
this._setActiveSegmentationForToolGroup(
segmentationId,
toolGroupId,
suppressEvents
);
this._setActiveSegmentationForToolGroup(segmentationId, toolGroupId, suppressEvents);
}
public setActiveSegmentForSegmentation(
segmentationId: string,
segmentIndex: number
): void {
public setActiveSegmentForSegmentation(segmentationId: string, segmentIndex: number): void {
this._setActiveSegment(segmentationId, segmentIndex, false);
}
@@ -420,9 +369,7 @@ class SegmentationService extends PubSubService {
* @return Array of segmentations
*/
public getSegmentations(
filterNonHydratedSegmentations = true
): Segmentation[] {
public getSegmentations(filterNonHydratedSegmentations = true): Segmentation[] {
const segmentations = this._getSegmentations();
return (
@@ -435,10 +382,7 @@ class SegmentationService extends PubSubService {
private _getSegmentations(): Segmentation[] {
const segmentations = this.arrayOfObjects(this.segmentations);
return (
segmentations &&
segmentations.map(m => this.segmentations[Object.keys(m)[0]])
);
return segmentations && segmentations.map(m => this.segmentations[Object.keys(m)[0]]);
}
/**
@@ -477,8 +421,7 @@ class SegmentationService extends PubSubService {
}
const representationType = segmentation.type;
const representationData =
segmentation.representationData[representationType];
const representationData = segmentation.representationData[representationType];
cstSegmentation.addSegmentations([
{
segmentationId,
@@ -566,9 +509,7 @@ class SegmentationService extends PubSubService {
const { labelmapBufferArray, referencedVolumeId } = segDisplaySet;
if (!labelmapBufferArray || !referencedVolumeId) {
throw new Error(
'No labelmapBufferArray or referencedVolumeId found for the SEG displaySet'
);
throw new Error('No labelmapBufferArray or referencedVolumeId found for the SEG displaySet');
}
// if the labelmap doesn't exist, we need to create it first from the
@@ -576,23 +517,18 @@ class SegmentationService extends PubSubService {
const referencedVolume = cache.getVolume(referencedVolumeId);
if (!referencedVolume) {
throw new Error(
`No volume found for referencedVolumeId: ${referencedVolumeId}`
);
throw new Error(`No volume found for referencedVolumeId: ${referencedVolumeId}`);
}
// Force use of a Uint8Array SharedArrayBuffer for the segmentation to save space and so
// it is easily compressible in worker thread.
const derivedVolume = await volumeLoader.createAndCacheDerivedVolume(
referencedVolumeId,
{
volumeId: segmentationId,
targetBuffer: {
type: 'Uint8Array',
sharedArrayBuffer: true,
},
}
);
const derivedVolume = await volumeLoader.createAndCacheDerivedVolume(referencedVolumeId, {
volumeId: segmentationId,
targetBuffer: {
type: 'Uint8Array',
sharedArrayBuffer: true,
},
});
const derivedVolumeScalarData = derivedVolume.getScalarData();
const segmentsInfo = segDisplaySet.segMetadata.data;
@@ -680,10 +616,7 @@ class SegmentationService extends PubSubService {
const defaultScheme = this._getDefaultSegmentationScheme();
const rtDisplaySetUID = rtDisplaySet.displaySetInstanceUID;
const allRTStructData = mapROIContoursToRTStructData(
structureSet,
rtDisplaySetUID
);
const allRTStructData = mapROIContoursToRTStructData(structureSet, rtDisplaySetUID);
// sort by segmentIndex
allRTStructData.sort((a, b) => a.segmentIndex - b.segmentIndex);
@@ -726,19 +659,16 @@ class SegmentationService extends PubSubService {
// catch error instead of failing to allow loading to continue
try {
const geometry = await geometryLoader.createAndCacheGeometry(
geometryId,
{
geometryData: {
data,
id,
color,
frameOfReferenceUID: structureSet.frameOfReferenceUID,
segmentIndex,
},
type: csEnums.GeometryType.CONTOUR,
}
);
const geometry = await geometryLoader.createAndCacheGeometry(geometryId, {
geometryData: {
data,
id,
color,
frameOfReferenceUID: structureSet.frameOfReferenceUID,
segmentIndex,
},
type: csEnums.GeometryType.CONTOUR,
});
const contourSet = geometry.data;
const centroid = contourSet.getCentroid();
@@ -758,9 +688,7 @@ class SegmentationService extends PubSubService {
const numInitialized = Object.keys(segmentsCachedStats).length;
// Calculate percentage completed
const percentComplete = Math.round(
(numInitialized / allRTStructData.length) * 100
);
const percentComplete = Math.round((numInitialized / allRTStructData.length) * 100);
this._broadcastEvent(EVENTS.SEGMENT_LOADING_COMPLETE, {
percentComplete,
@@ -824,8 +752,7 @@ class SegmentationService extends PubSubService {
const { world } = center;
// todo: generalize
toolGroupId =
toolGroupId || this._getToolGroupIdsWithSegmentation(segmentationId);
toolGroupId = toolGroupId || this._getToolGroupIdsWithSegmentation(segmentationId);
const toolGroups = [];
@@ -842,10 +769,7 @@ class SegmentationService extends PubSubService {
// @ts-ignore
for (const { viewportId, renderingEngineId } of viewportsInfo) {
const { viewport } = getEnabledElementByIds(
viewportId,
renderingEngineId
);
const { viewport } = getEnabledElementByIds(viewportId, renderingEngineId);
cstUtils.viewport.jumpToWorld(viewport, world);
}
@@ -888,9 +812,7 @@ class SegmentationService extends PubSubService {
const { segments } = segmentation;
const highlightFn =
type === LABELMAP
? this._highlightLabelmap.bind(this)
: this._highlightContour.bind(this);
type === LABELMAP ? this._highlightLabelmap.bind(this) : this._highlightContour.bind(this);
const adjustedAlpha = type === LABELMAP ? alpha : 1 - alpha;
@@ -914,9 +836,7 @@ class SegmentationService extends PubSubService {
): Promise<string> => {
const { displaySetService } = this.servicesManager.services;
const displaySet = displaySetService.getDisplaySetByUID(
displaySetInstanceUID
);
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
// Todo: we currently only support labelmap for segmentation for a displaySet
const representationType = LABELMAP;
@@ -977,9 +897,7 @@ class SegmentationService extends PubSubService {
const segmentation = this.getSegmentation(segmentationId);
if (!segmentation) {
throw new Error(
`Segmentation with segmentationId ${segmentationId} not found.`
);
throw new Error(`Segmentation with segmentationId ${segmentationId} not found.`);
}
if (hydrateSegmentation) {
@@ -1019,34 +937,16 @@ class SegmentationService extends PubSubService {
continue;
}
const {
segmentIndex,
color,
isLocked,
isVisible: visibility,
opacity,
} = segment;
const { segmentIndex, color, isLocked, isVisible: visibility, opacity } = segment;
const suppressEvents = true;
if (color !== undefined) {
this._setSegmentColor(
segmentationId,
segmentIndex,
color,
toolGroupId,
suppressEvents
);
this._setSegmentColor(segmentationId, segmentIndex, color, toolGroupId, suppressEvents);
}
if (opacity !== undefined) {
this._setSegmentOpacity(
segmentationId,
segmentIndex,
opacity,
toolGroupId,
suppressEvents
);
this._setSegmentOpacity(segmentationId, segmentIndex, opacity, toolGroupId, suppressEvents);
}
if (visibility !== undefined) {
@@ -1060,12 +960,7 @@ class SegmentationService extends PubSubService {
}
if (isLocked !== undefined) {
this._setSegmentLocked(
segmentationId,
segmentIndex,
isLocked,
suppressEvents
);
this._setSegmentLocked(segmentationId, segmentIndex, isLocked, suppressEvents);
}
}
};
@@ -1102,25 +997,16 @@ class SegmentationService extends PubSubService {
});
};
public getToolGroupIdsWithSegmentation = (
segmentationId: string
): string[] => {
const toolGroupIds = cstSegmentation.state.getToolGroupIdsWithSegmentation(
segmentationId
);
public getToolGroupIdsWithSegmentation = (segmentationId: string): string[] => {
const toolGroupIds = cstSegmentation.state.getToolGroupIdsWithSegmentation(segmentationId);
return toolGroupIds;
};
public hydrateSegmentation = (
segmentationId: string,
suppressEvents = false
): void => {
public hydrateSegmentation = (segmentationId: string, suppressEvents = false): void => {
const segmentation = this.getSegmentation(segmentationId);
if (!segmentation) {
throw new Error(
`Segmentation with segmentationId ${segmentationId} not found.`
);
throw new Error(`Segmentation with segmentationId ${segmentationId} not found.`);
}
this._setDisplaySetIsHydrated(segmentationId, true);
@@ -1134,13 +1020,8 @@ class SegmentationService extends PubSubService {
}
};
private _setDisplaySetIsHydrated(
displaySetUID: string,
isHydrated: boolean
): void {
const {
DisplaySetService: displaySetService,
} = this.servicesManager.services;
private _setDisplaySetIsHydrated(displaySetUID: string, isHydrated: boolean): void {
const { DisplaySetService: displaySetService } = this.servicesManager.services;
const displaySet = displaySetService.getDisplaySetByUID(displaySetUID);
displaySet.isHydrated = isHydrated;
displaySetService.setDisplaySetMetadataInvalidated(displaySetUID, false);
@@ -1259,17 +1140,13 @@ class SegmentationService extends PubSubService {
): void {
const uids = segmentationRepresentationUIDsIds || [];
if (!uids.length) {
const representations = cstSegmentation.state.getSegmentationRepresentations(
toolGroupId
);
const representations = cstSegmentation.state.getSegmentationRepresentations(toolGroupId);
if (!representations || !representations.length) {
return;
}
uids.push(
...representations.map(rep => rep.segmentationRepresentationUID)
);
uids.push(...representations.map(rep => rep.segmentationRepresentationUID));
}
cstSegmentation.removeSegmentationsFromToolGroup(toolGroupId, uids);
@@ -1285,9 +1162,7 @@ class SegmentationService extends PubSubService {
const wasActive = segmentation.isActive;
if (!segmentationId || !segmentation) {
console.warn(
`No segmentationId provided, or unable to find segmentation by id.`
);
console.warn(`No segmentationId provided, or unable to find segmentation by id.`);
return;
}
@@ -1309,11 +1184,7 @@ class SegmentationService extends PubSubService {
if (remainingSegmentations.length) {
const { id } = remainingSegmentations[0];
this._setActiveSegmentationForToolGroup(
id,
this._getFirstToolGroupId(),
false
);
this._setActiveSegmentationForToolGroup(id, this._getFirstToolGroupId(), false);
}
}
@@ -1337,9 +1208,8 @@ class SegmentationService extends PubSubService {
// toolGroupId
// );
const segmentationRepresentations = this.getSegmentationRepresentationsForToolGroup(
toolGroupId
);
const segmentationRepresentations =
this.getSegmentationRepresentationsForToolGroup(toolGroupId);
const typeToUse = segmentationRepresentations?.[0]?.type || LABELMAP;
@@ -1397,11 +1267,7 @@ class SegmentationService extends PubSubService {
setConfigValueIfDefined('outlineOpacity', outlineOpacity, v => v / 100);
setConfigValueIfDefined('fillAlpha', fillAlpha, v => v / 100);
setConfigValueIfDefined('renderFill', renderFill);
setConfigValueIfDefined(
'fillAlphaInactive',
fillAlphaInactive,
v => v / 100
);
setConfigValueIfDefined('fillAlphaInactive', fillAlphaInactive, v => v / 100);
setConfigValueIfDefined('outlineOpacityInactive', fillAlphaInactive, v =>
Math.max(0.75, v / 100)
);
@@ -1435,10 +1301,7 @@ class SegmentationService extends PubSubService {
// });
// }
this._broadcastEvent(
this.EVENTS.SEGMENTATION_CONFIGURATION_CHANGED,
this.getConfiguration()
);
this._broadcastEvent(this.EVENTS.SEGMENTATION_CONFIGURATION_CHANGED, this.getConfiguration());
};
public getLabelmapVolume = (segmentationId: string) => {
@@ -1472,9 +1335,7 @@ class SegmentationService extends PubSubService {
const segmentInfo = segmentation.segments[segmentIndex];
if (segmentInfo === undefined) {
throw new Error(
`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`
);
throw new Error(`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`);
}
segmentInfo.label = label;
@@ -1487,14 +1348,8 @@ class SegmentationService extends PubSubService {
}
}
public shouldRenderSegmentation(
viewportDisplaySetInstanceUIDs,
segDisplaySetInstanceUID
) {
if (
!viewportDisplaySetInstanceUIDs ||
!viewportDisplaySetInstanceUIDs.length
) {
public shouldRenderSegmentation(viewportDisplaySetInstanceUIDs, segDisplaySetInstanceUID) {
if (!viewportDisplaySetInstanceUIDs || !viewportDisplaySetInstanceUIDs.length) {
return false;
}
@@ -1502,20 +1357,14 @@ class SegmentationService extends PubSubService {
let shouldDisplaySeg = false;
const segDisplaySet = displaySetService.getDisplaySetByUID(
segDisplaySetInstanceUID
);
const segDisplaySet = displaySetService.getDisplaySetByUID(segDisplaySetInstanceUID);
const segFrameOfReferenceUID = this._getFrameOfReferenceUIDForSeg(
segDisplaySet
);
const segFrameOfReferenceUID = this._getFrameOfReferenceUIDForSeg(segDisplaySet);
// check if the displaySet is sharing the same frameOfReferenceUID
// with the new segmentation
for (const displaySetInstanceUID of viewportDisplaySetInstanceUIDs) {
const displaySet = displaySetService.getDisplaySetByUID(
displaySetInstanceUID
);
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
// Todo: this might not be ideal for use cases such as 4D, since we
// don't want to show the segmentation for all the frames
@@ -1563,10 +1412,7 @@ class SegmentationService extends PubSubService {
segmentation.isActive = segmentation.id === segmentationId;
});
const representation = this._getSegmentationRepresentation(
segmentationId,
toolGroupId
);
const representation = this._getSegmentationRepresentation(segmentationId, toolGroupId);
cstSegmentation.activeSegmentation.setActiveSegmentationRepresentation(
toolGroupId,
@@ -1580,16 +1426,11 @@ class SegmentationService extends PubSubService {
}
}
private _toggleSegmentationVisibility = (
segmentationId: string,
suppressEvents = false
) => {
private _toggleSegmentationVisibility = (segmentationId: string, suppressEvents = false) => {
const segmentation = this.segmentations[segmentationId];
if (!segmentation) {
throw new Error(
`Segmentation with segmentationId ${segmentationId} not found.`
);
throw new Error(`Segmentation with segmentationId ${segmentationId} not found.`);
}
segmentation.isVisible = !segmentation.isVisible;
@@ -1603,21 +1444,14 @@ class SegmentationService extends PubSubService {
}
};
private _setActiveSegment(
segmentationId: string,
segmentIndex: number,
suppressEvents = false
) {
private _setActiveSegment(segmentationId: string, segmentIndex: number, suppressEvents = false) {
const segmentation = this.getSegmentation(segmentationId);
if (segmentation === undefined) {
throw new Error(`no segmentation for segmentationId: ${segmentationId}`);
}
cstSegmentation.segmentIndex.setActiveSegmentIndex(
segmentationId,
segmentIndex
);
cstSegmentation.segmentIndex.setActiveSegmentIndex(segmentationId, segmentIndex);
segmentation.activeSegmentIndex = segmentIndex;
@@ -1641,8 +1475,7 @@ class SegmentationService extends PubSubService {
}
private _getVolumeIdForDisplaySet(displaySet) {
const volumeLoaderSchema =
displaySet.volumeLoaderSchema ?? VOLUME_LOADER_SCHEME;
const volumeLoaderSchema = displaySet.volumeLoaderSchema ?? VOLUME_LOADER_SCHEME;
return `${volumeLoaderSchema}:${displaySet.displaySetInstanceUID}`;
}
@@ -1663,9 +1496,7 @@ class SegmentationService extends PubSubService {
const segmentInfo = this._getSegmentInfo(segmentation, segmentIndex);
if (segmentInfo === undefined) {
throw new Error(
`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`
);
throw new Error(`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`);
}
toolGroupId = toolGroupId ?? this._getFirstToolGroupId();
@@ -1676,9 +1507,7 @@ class SegmentationService extends PubSubService {
);
if (!segmentationRepresentation) {
throw new Error(
'Must add representation to toolgroup before setting segments'
);
throw new Error('Must add representation to toolgroup before setting segments');
}
const { segmentationRepresentationUID } = segmentationRepresentation;
@@ -1743,18 +1572,12 @@ class SegmentationService extends PubSubService {
const segmentInfo = this._getSegmentInfo(segmentation, segmentIndex);
if (segmentInfo === undefined) {
throw new Error(
`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`
);
throw new Error(`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`);
}
segmentInfo.isLocked = isLocked;
cstSegmentation.segmentLocking.setSegmentIndexLocked(
segmentationId,
segmentIndex,
isLocked
);
cstSegmentation.segmentLocking.setSegmentIndexLocked(segmentationId, segmentIndex, isLocked);
if (suppressEvents === false) {
this._broadcastEvent(this.EVENTS.SEGMENTATION_UPDATED, {
@@ -1772,10 +1595,10 @@ class SegmentationService extends PubSubService {
) {
toolGroupId = toolGroupId ?? this._getFirstToolGroupId();
const {
segmentationRepresentationUID,
segmentation,
} = this._getSegmentationInfo(segmentationId, toolGroupId);
const { segmentationRepresentationUID, segmentation } = this._getSegmentationInfo(
segmentationId,
toolGroupId
);
if (segmentation === undefined) {
throw new Error(`no segmentation for segmentationId: ${segmentationId}`);
@@ -1784,9 +1607,7 @@ class SegmentationService extends PubSubService {
const segmentInfo = this._getSegmentInfo(segmentation, segmentIndex);
if (segmentInfo === undefined) {
throw new Error(
`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`
);
throw new Error(`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`);
}
segmentInfo.isVisible = isVisible;
@@ -1828,9 +1649,7 @@ class SegmentationService extends PubSubService {
const segmentInfo = this._getSegmentInfo(segmentation, segmentIndex);
if (segmentInfo === undefined) {
throw new Error(
`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`
);
throw new Error(`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`);
}
toolGroupId = toolGroupId ?? this._getFirstToolGroupId();
@@ -1841,9 +1660,7 @@ class SegmentationService extends PubSubService {
);
if (!segmentationRepresentation) {
throw new Error(
'Must add representation to toolgroup before setting segments'
);
throw new Error('Must add representation to toolgroup before setting segments');
}
const { segmentationRepresentationUID } = segmentationRepresentation;
@@ -1884,9 +1701,7 @@ class SegmentationService extends PubSubService {
const segmentInfo = this._getSegmentInfo(segmentation, segmentIndex);
if (segmentInfo === undefined) {
throw new Error(
`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`
);
throw new Error(`Segment ${segmentIndex} not yet added to segmentation: ${segmentationId}`);
}
segmentInfo.label = segmentLabel;
@@ -1899,9 +1714,8 @@ class SegmentationService extends PubSubService {
}
private _getSegmentationRepresentation(segmentationId, toolGroupId) {
const segmentationRepresentations = this.getSegmentationRepresentationsForToolGroup(
toolGroupId
);
const segmentationRepresentations =
this.getSegmentationRepresentationsForToolGroup(toolGroupId);
if (segmentationRepresentations.length === 0) {
return;
@@ -1974,21 +1788,13 @@ class SegmentationService extends PubSubService {
return;
}
const segmentationState = cstSegmentation.state.getSegmentation(
segmentationId
);
const segmentationState = cstSegmentation.state.getSegmentation(segmentationId);
if (!segmentationState) {
return;
}
const {
activeSegmentIndex,
cachedStats,
segmentsLocked,
label,
type,
} = segmentationState;
const { activeSegmentIndex, cachedStats, segmentsLocked, label, type } = segmentationState;
if (![LABELMAP, CONTOUR].includes(type)) {
throw new Error(
@@ -2018,10 +1824,7 @@ class SegmentationService extends PubSubService {
try {
this.addOrUpdateSegmentation(segmentationSchema);
} catch (error) {
console.warn(
`Failed to add/update segmentation ${segmentationId}`,
error
);
console.warn(`Failed to add/update segmentation ${segmentationId}`, error);
}
};
@@ -2037,9 +1840,7 @@ class SegmentationService extends PubSubService {
);
if (!segmentationRepresentation) {
throw new Error(
'Must add representation to toolgroup before setting segments'
);
throw new Error('Must add representation to toolgroup before setting segments');
}
const { segmentationRepresentationUID } = segmentationRepresentation;
@@ -2057,14 +1858,11 @@ class SegmentationService extends PubSubService {
return;
}
const toolGroupIds = segmentationState.getToolGroupIdsWithSegmentation(
segmentationId
);
const toolGroupIds = segmentationState.getToolGroupIdsWithSegmentation(segmentationId);
toolGroupIds.forEach(toolGroupId => {
const segmentationRepresentations = segmentationState.getSegmentationRepresentations(
toolGroupId
);
const segmentationRepresentations =
segmentationState.getSegmentationRepresentations(toolGroupId);
const UIDsToRemove = [];
segmentationRepresentations.forEach(representation => {
@@ -2089,17 +1887,12 @@ class SegmentationService extends PubSubService {
}
}
private _updateCornerstoneSegmentations({
segmentationId,
notYetUpdatedAtSource,
}) {
private _updateCornerstoneSegmentations({ segmentationId, notYetUpdatedAtSource }) {
if (notYetUpdatedAtSource === false) {
return;
}
const segmentationState = cstSegmentation.state;
const sourceSegmentation = segmentationState.getSegmentation(
segmentationId
);
const sourceSegmentation = segmentationState.getSegmentation(segmentationId);
const segmentation = this.segmentations[segmentationId];
const { label, cachedStats } = segmentation;
@@ -2115,14 +1908,11 @@ class SegmentationService extends PubSubService {
private _updateCornerstoneSegmentationVisibility = segmentationId => {
const segmentationState = cstSegmentation.state;
const toolGroupIds = segmentationState.getToolGroupIdsWithSegmentation(
segmentationId
);
const toolGroupIds = segmentationState.getToolGroupIdsWithSegmentation(segmentationId);
toolGroupIds.forEach(toolGroupId => {
const segmentationRepresentations = cstSegmentation.state.getSegmentationRepresentations(
toolGroupId
);
const segmentationRepresentations =
cstSegmentation.state.getSegmentationRepresentations(toolGroupId);
if (segmentationRepresentations.length === 0) {
return;
@@ -2146,10 +1936,7 @@ class SegmentationService extends PubSubService {
);
// update segments visibility
const { segmentation } = this._getSegmentationInfo(
segmentationId,
toolGroupId
);
const { segmentation } = this._getSegmentationInfo(segmentationId, toolGroupId);
const segments = segmentation.segments.filter(Boolean);
@@ -2161,9 +1948,7 @@ class SegmentationService extends PubSubService {
private _getToolGroupIdsWithSegmentation(segmentationId: string) {
const segmentationState = cstSegmentation.state;
const toolGroupIds = segmentationState.getToolGroupIdsWithSegmentation(
segmentationId
);
const toolGroupIds = segmentationState.getToolGroupIdsWithSegmentation(segmentationId);
return toolGroupIds;
}
@@ -1,8 +1,4 @@
import {
synchronizers,
SynchronizerManager,
Synchronizer,
} from '@cornerstonejs/tools';
import { synchronizers, SynchronizerManager, Synchronizer } from '@cornerstonejs/tools';
import { pubSubServiceInterface, Types, ServicesManager } from '@ohif/core';
@@ -14,10 +10,7 @@ const EVENTS = {
* @params options - are an optional set of options associated with the first
* sync group declared.
*/
export type SyncCreator = (
id: string,
options?: Record<string, unknown>
) => Synchronizer;
export type SyncCreator = (id: string, options?: Record<string, unknown>) => Synchronizer;
export type SyncGroup = {
type: string;
@@ -40,9 +33,7 @@ export default class SyncGroupService {
static REGISTRATION = {
name: 'syncGroupService',
altName: 'SyncGroupService',
create: ({
servicesManager,
}: Types.Extensions.ExtensionParams): SyncGroupService => {
create: ({ servicesManager }: Types.Extensions.ExtensionParams): SyncGroupService => {
return new SyncGroupService(servicesManager);
},
};
@@ -65,11 +56,7 @@ export default class SyncGroupService {
Object.assign(this, pubSubServiceInterface);
}
private _createSynchronizer(
type: string,
id: string,
options
): Synchronizer | undefined {
private _createSynchronizer(type: string, id: string, options): Synchronizer | undefined {
const syncCreator = this.synchronizerCreators[type.toLowerCase()];
if (syncCreator) {
return syncCreator(id, options);
@@ -109,19 +96,11 @@ export default class SyncGroupService {
return;
}
const syncGroupsArray = Array.isArray(syncGroups)
? syncGroups
: [syncGroups];
const syncGroupsArray = Array.isArray(syncGroups) ? syncGroups : [syncGroups];
syncGroupsArray.forEach(syncGroup => {
const syncGroupObj = asSyncGroup(syncGroup);
const {
type,
target = true,
source = true,
options = {},
id = type,
} = syncGroupObj;
const { type, target = true, source = true, options = {}, id = type } = syncGroupObj;
const synchronizer = this._getOrCreateSynchronizer(type, id, options);
synchronizer.setOptions(viewportId, options);
@@ -24,9 +24,7 @@ export default class ToolGroupService {
public static REGISTRATION = {
name: 'toolGroupService',
altName: 'ToolGroupService',
create: ({
servicesManager,
}: OhifTypes.Extensions.ExtensionParams): ToolGroupService => {
create: ({ servicesManager }: OhifTypes.Extensions.ExtensionParams): ToolGroupService => {
return new ToolGroupService(servicesManager);
},
};
@@ -40,10 +38,7 @@ export default class ToolGroupService {
EVENTS: { [key: string]: string };
constructor(serviceManager) {
const {
cornerstoneViewportService,
viewportGridService,
} = serviceManager.services;
const { cornerstoneViewportService, viewportGridService } = serviceManager.services;
this.cornerstoneViewportService = cornerstoneViewportService;
this.viewportGridService = viewportGridService;
this.listeners = {};
@@ -66,19 +61,14 @@ export default class ToolGroupService {
if (!toolGroupIdToUse) {
// Use the active viewport's tool group if no tool group id is provided
const enabledElement = getActiveViewportEnabledElement(
this.viewportGridService
);
const enabledElement = getActiveViewportEnabledElement(this.viewportGridService);
if (!enabledElement) {
return;
}
const { renderingEngineId, viewportId } = enabledElement;
const toolGroup = ToolGroupManager.getToolGroupForViewport(
viewportId,
renderingEngineId
);
const toolGroup = ToolGroupManager.getToolGroupForViewport(viewportId, renderingEngineId);
if (!toolGroup) {
console.warn(
@@ -103,10 +93,7 @@ export default class ToolGroupService {
public getToolGroupForViewport(viewportId: string): Types.IToolGroup | void {
const renderingEngine = this.cornerstoneViewportService.getRenderingEngine();
return ToolGroupManager.getToolGroupForViewport(
viewportId,
renderingEngine.id
);
return ToolGroupManager.getToolGroupForViewport(viewportId, renderingEngine.id);
}
public getActiveToolForViewport(viewportId: string): string {
@@ -133,10 +120,7 @@ export default class ToolGroupService {
renderingEngineId: string,
deleteToolGroupIfEmpty?: boolean
): void {
const toolGroup = ToolGroupManager.getToolGroupForViewport(
viewportId,
renderingEngineId
);
const toolGroup = ToolGroupManager.getToolGroupForViewport(viewportId, renderingEngineId);
if (!toolGroup) {
return;
@@ -193,11 +177,7 @@ export default class ToolGroupService {
return toolGroup;
}
public addToolsToToolGroup(
toolGroupId: string,
tools: Array<Tool>,
configs: any = {}
): void {
public addToolsToToolGroup(toolGroupId: string, tools: Array<Tool>, configs: any = {}): void {
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId);
// this.changeConfigurationIfNecessary(toolGroup, volumeId);
this._addTools(toolGroup, tools, configs);
@@ -12,10 +12,7 @@ import {
Enums as csEnums,
} from '@cornerstonejs/core';
import {
utilities as csToolsUtils,
Enums as csToolsEnums,
} from '@cornerstonejs/tools';
import { utilities as csToolsUtils, Enums as csToolsEnums } from '@cornerstonejs/tools';
import { IViewportService } from './IViewportService';
import { RENDERING_ENGINE_ID } from './constants';
import ViewportInfo, {
@@ -23,25 +20,20 @@ import ViewportInfo, {
DisplaySetOptions,
PublicViewportOptions,
} from './Viewport';
import {
StackViewportData,
VolumeViewportData,
} from '../../types/CornerstoneCacheService';
import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService';
import { Presentation, Presentations } from '../../types/Presentation';
import JumpPresets from '../../utils/JumpPresets';
const EVENTS = {
VIEWPORT_DATA_CHANGED:
'event::cornerstoneViewportService:viewportDataChanged',
VIEWPORT_DATA_CHANGED: 'event::cornerstoneViewportService:viewportDataChanged',
};
/**
* Handles cornerstone viewport logic including enabling, disabling, and
* updating the viewport.
*/
class CornerstoneViewportService extends PubSubService
implements IViewportService {
class CornerstoneViewportService extends PubSubService implements IViewportService {
static REGISTRATION = {
name: 'cornerstoneViewportService',
altName: 'CornerstoneViewportService',
@@ -182,8 +174,7 @@ class CornerstoneViewportService extends PubSubService
const camera = csViewport.getCamera();
return {
presentationIds,
viewportType:
!viewportType || viewportType === 'stack' ? 'stack' : 'volume',
viewportType: !viewportType || viewportType === 'stack' ? 'stack' : 'volume',
properties,
initialImageIndex,
camera,
@@ -202,10 +193,7 @@ class CornerstoneViewportService extends PubSubService
if (!presentation || !presentation.presentationIds) {
return;
}
const {
lutPresentationStore,
positionPresentationStore,
} = stateSyncService.getState();
const { lutPresentationStore, positionPresentationStore } = stateSyncService.getState();
const { presentationIds } = presentation;
const { lutPresentationId, positionPresentationId } = presentationIds || {};
const storeState = {};
@@ -258,12 +246,8 @@ class CornerstoneViewportService extends PubSubService
// override the viewportOptions and displaySetOptions with the public ones
// since those are the newly set ones, we set them here so that it handles defaults
const displaySetOptions = viewportInfo.setPublicDisplaySetOptions(
publicDisplaySetOptions
);
const viewportOptions = viewportInfo.setPublicViewportOptions(
publicViewportOptions
);
const displaySetOptions = viewportInfo.setPublicDisplaySetOptions(publicDisplaySetOptions);
const viewportOptions = viewportInfo.setPublicViewportOptions(publicViewportOptions);
const element = viewportInfo.getElement();
const type = viewportInfo.getViewportType();
@@ -317,11 +301,7 @@ class CornerstoneViewportService extends PubSubService
): Types.IStackViewport | Types.IVolumeViewport | null {
const viewportInfo = this.getViewportInfo(viewportId);
if (
!viewportInfo ||
!this.renderingEngine ||
this.renderingEngine.hasBeenDestroyed
) {
if (!viewportInfo || !this.renderingEngine || this.renderingEngine.hasBeenDestroyed) {
return null;
}
@@ -342,24 +322,15 @@ class CornerstoneViewportService extends PubSubService
): void {
const displaySetOptions = viewportInfo.getDisplaySetOptions();
const {
imageIds,
initialImageIndex,
displaySetInstanceUID,
} = viewportData.data;
const { imageIds, initialImageIndex, displaySetInstanceUID } = viewportData.data;
this.viewportsDisplaySets.set(viewport.id, [displaySetInstanceUID]);
let initialImageIndexToUse =
presentations?.positionPresentation?.initialImageIndex ??
initialImageIndex;
presentations?.positionPresentation?.initialImageIndex ?? initialImageIndex;
if (
initialImageIndexToUse === undefined ||
initialImageIndexToUse === null
) {
initialImageIndexToUse =
this._getInitialImageIndexForViewport(viewportInfo, imageIds) || 0;
if (initialImageIndexToUse === undefined || initialImageIndexToUse === null) {
initialImageIndexToUse = this._getInitialImageIndexForViewport(viewportInfo, imageIds) || 0;
}
const properties = { ...presentations.lutPresentation?.properties };
@@ -404,12 +375,8 @@ class CornerstoneViewportService extends PubSubService
if (viewportType === csEnums.ViewportType.STACK) {
numberOfSlices = imageIds.length;
} else if (viewportType === csEnums.ViewportType.ORTHOGRAPHIC) {
const viewport = this.getCornerstoneViewport(
viewportInfo.getViewportId()
);
const imageSliceData = csUtils.getImageSliceDataForVolumeViewport(
viewport
);
const viewport = this.getCornerstoneViewport(viewportInfo.getViewportId());
const imageSliceData = csUtils.getImageSliceDataForVolumeViewport(viewport);
if (!imageSliceData) {
return;
@@ -423,11 +390,7 @@ class CornerstoneViewportService extends PubSubService
return this._getInitialImageIndex(numberOfSlices, index, preset);
}
_getInitialImageIndex(
numberOfSlices: number,
imageIndex?: number,
preset?: JumpPresets
): number {
_getInitialImageIndex(numberOfSlices: number, imageIndex?: number, preset?: JumpPresets): number {
const lastSliceIndex = numberOfSlices - 1;
if (imageIndex !== undefined) {
@@ -449,9 +412,7 @@ class CornerstoneViewportService extends PubSubService
// it will jump to a different slice than the middle one which
// was the initial slice, and we have some tools such as Crosshairs
// which rely on a relative camera modifications and those will break.
return lastSliceIndex % 2 === 0
? lastSliceIndex / 2
: (lastSliceIndex + 1) / 2;
return lastSliceIndex % 2 === 0 ? lastSliceIndex / 2 : (lastSliceIndex + 1) / 2;
}
return 0;
@@ -521,22 +482,11 @@ class CornerstoneViewportService extends PubSubService
});
// This returns the async continuation only
return this.setVolumesForViewport(
viewport,
volumeInputArray,
presentations
);
return this.setVolumesForViewport(viewport, volumeInputArray, presentations);
}
public async setVolumesForViewport(
viewport,
volumeInputArray,
presentations
) {
const {
displaySetService,
toolGroupService,
} = this.servicesManager.services;
public async setVolumesForViewport(viewport, volumeInputArray, presentations) {
const { displaySetService, toolGroupService } = this.servicesManager.services;
const viewportInfo = this.getViewportInfo(viewport.id);
const displaySetOptions = viewportInfo.getDisplaySetOptions();
@@ -594,10 +544,7 @@ class CornerstoneViewportService extends PubSubService
// associated with the primary displaySet
// get segmentations only returns the hydrated segmentations
this._addSegmentationRepresentationToToolGroupIfNecessary(
displaySetInstanceUIDs,
viewport
);
this._addSegmentationRepresentationToToolGroupIfNecessary(displaySetInstanceUIDs, viewport);
}
const toolGroup = toolGroupService.getToolGroupForViewport(viewport.id);
@@ -618,10 +565,7 @@ class CornerstoneViewportService extends PubSubService
displaySetInstanceUIDs: string[],
viewport: any
) {
const {
segmentationService,
toolGroupService,
} = this.servicesManager.services;
const { segmentationService, toolGroupService } = this.servicesManager.services;
const toolGroup = toolGroupService.getToolGroupForViewport(viewport.id);
@@ -630,9 +574,7 @@ class CornerstoneViewportService extends PubSubService
for (const segmentation of segmentations) {
const toolGroupSegmentationRepresentations =
segmentationService.getSegmentationRepresentationsForToolGroup(
toolGroup.id
) || [];
segmentationService.getSegmentationRepresentationsForToolGroup(toolGroup.id) || [];
// if there is already a segmentation representation for this segmentation
// for this toolGroup, don't bother at all
@@ -647,16 +589,12 @@ class CornerstoneViewportService extends PubSubService
// otherwise, check if the hydrated segmentations are in the same FOR
// as the primary displaySet, if so add the representation (since it was not there)
const { id: segDisplaySetInstanceUID, type } = segmentation;
const segFrameOfReferenceUID = this._getFrameOfReferenceUID(
segDisplaySetInstanceUID
);
const segFrameOfReferenceUID = this._getFrameOfReferenceUID(segDisplaySetInstanceUID);
let shouldDisplaySeg = false;
for (const displaySetInstanceUID of displaySetInstanceUIDs) {
const primaryFrameOfReferenceUID = this._getFrameOfReferenceUID(
displaySetInstanceUID
);
const primaryFrameOfReferenceUID = this._getFrameOfReferenceUID(displaySetInstanceUID);
if (segFrameOfReferenceUID === primaryFrameOfReferenceUID) {
shouldDisplaySeg = true;
@@ -677,14 +615,8 @@ class CornerstoneViewportService extends PubSubService
}
}
private addOverlayRepresentationForDisplaySet(
displaySet: any,
viewport: any
) {
const {
segmentationService,
toolGroupService,
} = this.servicesManager.services;
private addOverlayRepresentationForDisplaySet(displaySet: any, viewport: any) {
const { segmentationService, toolGroupService } = this.servicesManager.services;
const { referencedVolumeId } = displaySet;
const segmentationId = displaySet.displaySetInstanceUID;
@@ -711,10 +643,7 @@ class CornerstoneViewportService extends PubSubService
const viewport = this.getCornerstoneViewport(viewportId);
const viewportCamera = viewport.getCamera();
if (
viewport instanceof VolumeViewport ||
viewport instanceof VolumeViewport3D
) {
if (viewport instanceof VolumeViewport || viewport instanceof VolumeViewport3D) {
this._setVolumeViewport(viewport, viewportData, viewportInfo).then(() => {
if (keepCamera) {
viewport.setCamera(viewportCamera);
@@ -744,10 +673,7 @@ class CornerstoneViewportService extends PubSubService
viewportInfo,
presentations
);
} else if (
viewport instanceof VolumeViewport ||
viewport instanceof VolumeViewport3D
) {
} else if (viewport instanceof VolumeViewport || viewport instanceof VolumeViewport3D) {
this._setVolumeViewport(
viewport,
viewportData as VolumeViewportData,
@@ -770,10 +696,7 @@ class CornerstoneViewportService extends PubSubService
_getSlabThickness(displaySetOptions, volumeId) {
const { blendMode } = displaySetOptions;
if (
blendMode === undefined ||
displaySetOptions.slabThickness === undefined
) {
if (blendMode === undefined || displaySetOptions.slabThickness === undefined) {
return;
}
@@ -799,9 +722,7 @@ class CornerstoneViewportService extends PubSubService
_getFrameOfReferenceUID(displaySetInstanceUID) {
const { displaySetService } = this.servicesManager.services;
const displaySet = displaySetService.getDisplaySetByUID(
displaySetInstanceUID
);
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
if (!displaySet) {
return;
@@ -1,10 +1,6 @@
import { Types } from '@cornerstonejs/core';
import { StackData, VolumeData } from '../../types/CornerstoneCacheService';
import {
DisplaySetOptions,
PublicViewportOptions,
ViewportOptions,
} from './Viewport';
import { DisplaySetOptions, PublicViewportOptions, ViewportOptions } from './Viewport';
/**
* Handles cornerstone viewport logic including enabling, disabling, and
@@ -1,9 +1,6 @@
import { Types, Enums } from '@cornerstonejs/core';
import { Types as UITypes } from '@ohif/ui';
import {
StackViewportData,
VolumeViewportData,
} from '../../types/CornerstoneCacheService';
import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService';
import getCornerstoneBlendMode from '../../utils/getCornerstoneBlendMode';
import getCornerstoneOrientation from '../../utils/getCornerstoneOrientation';
import getCornerstoneViewportType from '../../utils/getCornerstoneViewportType';
@@ -90,11 +87,7 @@ const DEFAULT_TOOLGROUP_ID = 'default';
// Return true if the data contains the given display set UID OR the imageId
// if it is a composite object.
const dataContains = (
data,
displaySetUID: string,
imageId?: string
): boolean => {
const dataContains = (data, displaySetUID: string, imageId?: string): boolean => {
if (data.displaySetInstanceUID === displaySetUID) {
return true;
}
@@ -128,9 +121,7 @@ class ViewportInfo {
}
if (this.viewportData.data.length) {
return !!this.viewportData.data.find(data =>
dataContains(data, displaySetUID, imageId)
);
return !!this.viewportData.data.find(data => dataContains(data, displaySetUID, imageId));
}
return dataContains(this.viewportData.data, displaySetUID, imageId);
}
@@ -158,9 +149,7 @@ class ViewportInfo {
this.element = element;
}
public setViewportData(
viewportData: StackViewportData | VolumeViewportData
): void {
public setViewportData(viewportData: StackViewportData | VolumeViewportData): void {
this.viewportData = viewportData;
}
@@ -168,7 +157,6 @@ class ViewportInfo {
return this.viewportData;
}
public getElement(): HTMLDivElement {
return this.element;
}
@@ -181,13 +169,11 @@ class ViewportInfo {
publicDisplaySetOptions: PublicDisplaySetOptions[] | DisplaySetSelector[]
): Array<DisplaySetOptions> {
// map the displaySetOptions and check if they are undefined then set them to default values
const displaySetOptions = this.mapDisplaySetOptions(
publicDisplaySetOptions
);
const displaySetOptions = this.mapDisplaySetOptions(publicDisplaySetOptions);
this.setDisplaySetOptions(displaySetOptions);
return this.displaySetOptions
return this.displaySetOptions;
}
public hasDisplaySet(displaySetInstanceUID: string): boolean {
@@ -196,8 +182,9 @@ class ViewportInfo {
// via cornerstoneViewportService
let viewportData = this.getViewportData();
if (viewportData.viewportType === Enums.ViewportType.ORTHOGRAPHIC ||
viewportData.viewportType === Enums.ViewportType.VOLUME_3D
if (
viewportData.viewportType === Enums.ViewportType.ORTHOGRAPHIC ||
viewportData.viewportType === Enums.ViewportType.VOLUME_3D
) {
viewportData = viewportData as VolumeViewportData;
return viewportData.data.some(
@@ -209,22 +196,15 @@ class ViewportInfo {
return viewportData.data.displaySetInstanceUID === displaySetInstanceUID;
}
public setPublicViewportOptions(
viewportOptionsEntry: PublicViewportOptions
): ViewportOptions {
public setPublicViewportOptions(viewportOptionsEntry: PublicViewportOptions): ViewportOptions {
let viewportType = viewportOptionsEntry.viewportType;
const {
toolGroupId = DEFAULT_TOOLGROUP_ID,
presentationIds,
} = viewportOptionsEntry;
const { toolGroupId = DEFAULT_TOOLGROUP_ID, presentationIds } = viewportOptionsEntry;
let orientation;
if (!viewportType) {
viewportType = getCornerstoneViewportType(STACK);
} else {
viewportType = getCornerstoneViewportType(
viewportOptionsEntry.viewportType
);
viewportType = getCornerstoneViewportType(viewportOptionsEntry.viewportType);
}
// map SAGITTAL, AXIAL, CORONAL orientation to be used by cornerstone
@@ -256,9 +236,7 @@ class ViewportInfo {
return this.viewportOptions;
}
public setDisplaySetOptions(
displaySetOptions: Array<DisplaySetOptions>
): void {
public setDisplaySetOptions(displaySetOptions: Array<DisplaySetOptions>): void {
this.displaySetOptions = displaySetOptions;
}
+1 -5
View File
@@ -9,11 +9,7 @@ const state = {
* @param {HTMLElement} dom Active viewport element.
* @return void
*/
const setEnabledElement = (
viewportId: string,
element: HTMLElement,
context?: string
): void => {
const setEnabledElement = (viewportId: string, element: HTMLElement, context?: string): void => {
const targetContext = context || state.DEFAULT_CONTEXT;
state.enabledElements[viewportId] = {
@@ -25,8 +25,7 @@ class CalibrationLineTool extends LengthTool {
this._renderingViewport.worldToCanvas(p)
);
// for display, round to 2 decimal points
const lengthPx =
Math.round(calculateLength2(canvasPoint1, canvasPoint2) * 100) / 100;
const lengthPx = Math.round(calculateLength2(canvasPoint1, canvasPoint2) * 100) / 100;
const textLines = [`${lengthPx}px`];
@@ -64,17 +63,11 @@ export function onCompletedCalibrationLine(servicesManager, csToolsEvent) {
const length =
Math.round(
calculateLength3(
annotationData.handles.points[0],
annotationData.handles.points[1]
) * 100
calculateLength3(annotationData.handles.points[0], annotationData.handles.points[1]) * 100
) / 100;
// calculate the currently applied pixel spacing on the viewport
const calibratedPixelSpacing = metaData.get(
'calibratedPixelSpacing',
imageId
);
const calibratedPixelSpacing = metaData.get('calibratedPixelSpacing', imageId);
const imagePlaneModule = metaData.get('imagePlaneModule', imageId);
const currentRowPixelSpacing =
calibratedPixelSpacing?.[0] || imagePlaneModule?.rowPixelSpacing || 1;
@@ -87,12 +80,7 @@ export function onCompletedCalibrationLine(servicesManager, csToolsEvent) {
const colSpacing = spacingScale * currentColumnPixelSpacing;
// trigger resize of the viewport to adjust the world/pixel mapping
calibrateImageSpacing(
imageId,
viewport.getRenderingEngine(),
rowSpacing,
colSpacing
);
calibrateImageSpacing(imageId, viewport.getRenderingEngine(), rowSpacing, colSpacing);
};
return new Promise((resolve, reject) => {
+2 -5
View File
@@ -1,7 +1,4 @@
import * as CornerstoneCacheService from './CornerstoneCacheService'
import * as CornerstoneCacheService from './CornerstoneCacheService';
import CornerstoneServices from './CornerstoneServices';
export type {
CornerstoneCacheService,
CornerstoneServices,
}
export type { CornerstoneCacheService, CornerstoneServices };
@@ -27,31 +27,22 @@ const CornerstoneViewportDownloadForm = ({
const activeViewportElement = enabledElement?.element;
const activeViewportEnabledElement = getEnabledElement(activeViewportElement);
const {
viewportId: activeViewportId,
renderingEngineId,
} = activeViewportEnabledElement;
const { viewportId: activeViewportId, renderingEngineId } = activeViewportEnabledElement;
const toolGroup = ToolGroupManager.getToolGroupForViewport(
activeViewportId,
renderingEngineId
);
const toolGroup = ToolGroupManager.getToolGroupForViewport(activeViewportId, renderingEngineId);
const toolModeAndBindings = Object.keys(toolGroup.toolOptions).reduce(
(acc, toolName) => {
const tool = toolGroup.toolOptions[toolName];
const { mode, bindings } = tool;
const toolModeAndBindings = Object.keys(toolGroup.toolOptions).reduce((acc, toolName) => {
const tool = toolGroup.toolOptions[toolName];
const { mode, bindings } = tool;
return {
...acc,
[toolName]: {
mode,
bindings,
},
};
},
{}
);
return {
...acc,
[toolName]: {
mode,
bindings,
},
};
}, {});
useEffect(() => {
return () => {
@@ -64,9 +55,7 @@ const CornerstoneViewportDownloadForm = ({
const enableViewport = viewportElement => {
if (viewportElement) {
const { renderingEngine, viewport } = getEnabledElement(
activeViewportElement
);
const { renderingEngine, viewport } = getEnabledElement(activeViewportElement);
const viewportInput = {
viewportId: VIEWPORT_ID,
@@ -91,11 +80,7 @@ const CornerstoneViewportDownloadForm = ({
}
};
const updateViewportPreview = (
downloadViewportElement,
internalCanvas,
fileType
) =>
const updateViewportPreview = (downloadViewportElement, internalCanvas, fileType) =>
new Promise(resolve => {
const enabledElement = getEnabledElement(downloadViewportElement);
@@ -133,10 +118,7 @@ const CornerstoneViewportDownloadForm = ({
resolve({ dataUrl, width: newWidth, height: newHeight });
downloadViewportElement.removeEventListener(
Enums.Events.IMAGE_RENDERED,
updateViewport
);
downloadViewportElement.removeEventListener(Enums.Events.IMAGE_RENDERED, updateViewport);
}
);
});
@@ -144,9 +126,7 @@ const CornerstoneViewportDownloadForm = ({
const loadImage = (activeViewportElement, viewportElement, width, height) =>
new Promise(resolve => {
if (activeViewportElement && viewportElement) {
const activeViewportEnabledElement = getEnabledElement(
activeViewportElement
);
const activeViewportEnabledElement = getEnabledElement(activeViewportElement);
if (!activeViewportEnabledElement) {
return;
@@ -165,10 +145,7 @@ const CornerstoneViewportDownloadForm = ({
downloadViewport.setProperties(properties);
const newWidth = Math.min(width || image.width, MAX_TEXTURE_SIZE);
const newHeight = Math.min(
height || image.height,
MAX_TEXTURE_SIZE
);
const newHeight = Math.min(height || image.height, MAX_TEXTURE_SIZE);
resolve({ width: newWidth, height: newHeight });
});
@@ -190,31 +167,19 @@ const CornerstoneViewportDownloadForm = ({
}
});
const toggleAnnotations = (
toggle,
viewportElement,
activeViewportElement
) => {
const activeViewportEnabledElement = getEnabledElement(
activeViewportElement
);
const toggleAnnotations = (toggle, viewportElement, activeViewportElement) => {
const activeViewportEnabledElement = getEnabledElement(activeViewportElement);
const downloadViewportElement = getEnabledElement(viewportElement);
const {
viewportId: activeViewportId,
renderingEngineId,
} = activeViewportEnabledElement;
const { viewportId: activeViewportId, renderingEngineId } = activeViewportEnabledElement;
const { viewportId: downloadViewportId } = downloadViewportElement;
if (!activeViewportEnabledElement || !downloadViewportElement) {
return;
}
const toolGroup = ToolGroupManager.getToolGroupForViewport(
activeViewportId,
renderingEngineId
);
const toolGroup = ToolGroupManager.getToolGroupForViewport(activeViewportId, renderingEngineId);
// add the viewport to the toolGroup
toolGroup.addViewport(downloadViewportId, renderingEngineId);
@@ -98,22 +98,13 @@ export default class DicomFileUploader extends PubSubService {
});
},
timeout: () => {
this._reject(
reject,
new UploadRejection(UploadStatus.Failed, 'The request timed out.')
);
this._reject(reject, new UploadRejection(UploadStatus.Failed, 'The request timed out.'));
},
abort: () => {
this._reject(
reject,
new UploadRejection(UploadStatus.Cancelled, 'Cancelled')
);
this._reject(reject, new UploadRejection(UploadStatus.Cancelled, 'Cancelled'));
},
error: () => {
this._reject(
reject,
new UploadRejection(UploadStatus.Failed, 'The request failed.')
);
this._reject(reject, new UploadRejection(UploadStatus.Failed, 'The request failed.'));
},
};
@@ -122,10 +113,7 @@ export default class DicomFileUploader extends PubSubService {
.loadFileRequest(this._fileId)
.then(dicomFile => {
if (this._abortController.signal.aborted) {
this._reject(
reject,
new UploadRejection(UploadStatus.Cancelled, 'Cancelled')
);
this._reject(reject, new UploadRejection(UploadStatus.Cancelled, 'Cancelled'));
return;
}
@@ -133,10 +121,7 @@ export default class DicomFileUploader extends PubSubService {
// The file is not DICOM
this._reject(
reject,
new UploadRejection(
UploadStatus.Failed,
'Not a valid DICOM file.'
)
new UploadRejection(UploadStatus.Failed, 'Not a valid DICOM file.')
);
return;
}
@@ -164,10 +149,7 @@ export default class DicomFileUploader extends PubSubService {
}
private _isRejected(): boolean {
return (
this._status === UploadStatus.Failed ||
this._status === UploadStatus.Cancelled
);
return this._status === UploadStatus.Failed || this._status === UploadStatus.Cancelled;
}
private _reject(reject: (reason?: any) => void, reason: any) {
@@ -21,11 +21,7 @@ function callInputDialog(
dialogConfig: any = {}
) {
const dialogId = 'dialog-enter-annotation';
const label = data
? isArrowAnnotateInputDialog
? data.text
: data.label
: '';
const label = data ? (isArrowAnnotateInputDialog ? data.text : data.label) : '';
const {
dialogTitle = 'Annotation',
inputLabel = 'Enter your annotation',
@@ -69,7 +65,7 @@ function callInputDialog(
return (
<Input
autoFocus
className="bg-black border-primary-main"
className="border-primary-main bg-black"
type="text"
id="annotation"
label={inputLabel}
@@ -8,9 +8,7 @@ const getImageId = imageObj => {
return;
}
return typeof imageObj.getImageId === 'function'
? imageObj.getImageId()
: imageObj.url;
return typeof imageObj.getImageId === 'function' ? imageObj.getImageId() : imageObj.url;
};
const findImageIdOnStudies = (studies, displaySetInstanceUID) => {
@@ -163,9 +161,7 @@ class DicomLoaderService {
getDicomDataMethod = fetchIt.bind(this, imageId);
break;
default:
throw new Error(
`Unsupported image type: ${loaderType} for imageId: ${imageId}`
);
throw new Error(`Unsupported image type: ${loaderType} for imageId: ${imageId}`);
}
return getDicomDataMethod();
@@ -3,9 +3,7 @@ import { IEnabledElement } from '@cornerstonejs/core/dist/esm/types';
import { getEnabledElement as OHIFgetEnabledElement } from '../state';
export default function getActiveViewportEnabledElement(
viewportGridService
): IEnabledElement {
export default function getActiveViewportEnabledElement(viewportGridService): IEnabledElement {
const { activeViewportId } = viewportGridService.getState();
const { element } = OHIFgetEnabledElement(activeViewportId) || {};
const enabledElement = getEnabledElement(element);
@@ -2,9 +2,7 @@ import { Enums } from '@cornerstonejs/core';
const MIP = 'mip';
export default function getCornerstoneBlendMode(
blendMode: string
): Enums.BlendModes {
export default function getCornerstoneBlendMode(blendMode: string): Enums.BlendModes {
if (!blendMode) {
return Enums.BlendModes.COMPOSITE;
}
@@ -4,9 +4,7 @@ const AXIAL = 'axial';
const SAGITTAL = 'sagittal';
const CORONAL = 'coronal';
export default function getCornerstoneOrientation(
orientation: string
): Enums.OrientationAxis {
export default function getCornerstoneOrientation(orientation: string): Enums.OrientationAxis {
if (orientation) {
switch (orientation.toLowerCase()) {
case AXIAL:
@@ -5,9 +5,7 @@ const VOLUME = 'volume';
const ORTHOGRAPHIC = 'orthographic';
const VOLUME_3D = 'volume3d';
export default function getCornerstoneViewportType(
viewportType: string
): Enums.ViewportType {
export default function getCornerstoneViewportType(viewportType: string): Enums.ViewportType {
const lowerViewportType = viewportType.toLowerCase();
if (lowerViewportType === STACK) {
return Enums.ViewportType.STACK;
@@ -21,7 +19,5 @@ export default function getCornerstoneViewportType(
return Enums.ViewportType.VOLUME_3D;
}
throw new Error(
`Invalid viewport type: ${viewportType}. Valid types are: stack, volume`
);
throw new Error(`Invalid viewport type: ${viewportType}. Valid types are: stack, volume`);
}
@@ -19,11 +19,7 @@ export default function getNthFrames(imageIds) {
const centerEnd = centerStart + 6;
for (let i = 0; i < imageIds.length; i++) {
if (
i < 2 ||
i > imageIds.length - 4 ||
(i > centerStart && i < centerEnd)
) {
if (i < 2 || i > imageIds.length - 4 || (i > centerStart && i < centerEnd)) {
frames[0].push(imageIds[i]);
} else if (i % 7 === 2) {
frames[1].push(imageIds[i]);
@@ -33,12 +29,6 @@ export default function getNthFrames(imageIds) {
frames[(i % 2) + 3].push(imageIds[i]);
}
}
const ret = [
...frames[0],
...frames[1],
...frames[2],
...frames[3],
...frames[4],
];
const ret = [...frames[0], ...frames[1], ...frames[2], ...frames[3], ...frames[4]];
return ret;
}
@@ -105,9 +105,7 @@ export default function interleaveCenterLoader({
const { imageId } = request;
AllRequests.forEach(volumeRequests => {
const volumeImageIdRequest = volumeRequests.find(
req => req.imageId === imageId
);
const volumeImageIdRequest = volumeRequests.find(req => req.imageId === imageId);
if (volumeImageIdRequest) {
finalRequests.push(volumeImageIdRequest);
}
@@ -117,31 +115,17 @@ export default function interleaveCenterLoader({
const requestType = Enums.RequestType.Prefetch;
const priority = 0;
finalRequests.forEach(
({ callLoadImage, additionalDetails, imageId, imageIdIndex, options }) => {
const callLoadImageBound = callLoadImage.bind(
null,
imageId,
imageIdIndex,
options
);
finalRequests.forEach(({ callLoadImage, additionalDetails, imageId, imageIdIndex, options }) => {
const callLoadImageBound = callLoadImage.bind(null, imageId, imageIdIndex, options);
imageLoadPoolManager.addRequest(
callLoadImageBound,
requestType,
additionalDetails,
priority
);
}
);
imageLoadPoolManager.addRequest(callLoadImageBound, requestType, additionalDetails, priority);
});
// clear the volumeIdMapsToLoad
volumeIdMapsToLoad.clear();
// copy the viewportIdVolumeInputArrayMap
const viewportIdVolumeInputArrayMapCopy = new Map(
viewportIdVolumeInputArrayMap
);
const viewportIdVolumeInputArrayMapCopy = new Map(viewportIdVolumeInputArrayMap);
// reset the viewportIdVolumeInputArrayMap
viewportIdVolumeInputArrayMap.clear();
@@ -94,9 +94,7 @@ export default function interleaveTopToBottom({
const { imageId } = request;
AllRequests.forEach(volumeRequests => {
const volumeImageIdRequest = volumeRequests.find(
req => req.imageId === imageId
);
const volumeImageIdRequest = volumeRequests.find(req => req.imageId === imageId);
if (volumeImageIdRequest) {
finalRequests.push(volumeImageIdRequest);
}
@@ -106,31 +104,17 @@ export default function interleaveTopToBottom({
const requestType = Enums.RequestType.Prefetch;
const priority = 0;
finalRequests.forEach(
({ callLoadImage, additionalDetails, imageId, imageIdIndex, options }) => {
const callLoadImageBound = callLoadImage.bind(
null,
imageId,
imageIdIndex,
options
);
finalRequests.forEach(({ callLoadImage, additionalDetails, imageId, imageIdIndex, options }) => {
const callLoadImageBound = callLoadImage.bind(null, imageId, imageIdIndex, options);
imageLoadPoolManager.addRequest(
callLoadImageBound,
requestType,
additionalDetails,
priority
);
}
);
imageLoadPoolManager.addRequest(callLoadImageBound, requestType, additionalDetails, priority);
});
// clear the volumeIdMapsToLoad
volumeIdMapsToLoad.clear();
// copy the viewportIdVolumeInputArrayMap
const viewportIdVolumeInputArrayMapCopy = new Map(
viewportIdVolumeInputArrayMap
);
const viewportIdVolumeInputArrayMapCopy = new Map(viewportIdVolumeInputArrayMap);
// reset the viewportIdVolumeInputArrayMap
viewportIdVolumeInputArrayMap.clear();
@@ -32,11 +32,7 @@ const Angle = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = getSOPInstanceAttributes(
referencedImageId,
CornerstoneViewportService,
viewportId
@@ -55,14 +51,10 @@ const Angle = {
const { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
displaySetService
);
const mappedAnnotations = getMappedAnnotations(annotation, displaySetService);
const displayText = getDisplayText(mappedAnnotations, displaySet);
const getReport = () =>
_getReport(mappedAnnotations, points, FrameOfReferenceUID);
const getReport = () => _getReport(mappedAnnotations, points, FrameOfReferenceUID);
return {
uid: annotationUID,
@@ -99,16 +91,11 @@ function getMappedAnnotations(annotation, DisplaySetService) {
const targetStats = cachedStats[targetId];
if (!referencedImageId) {
throw new Error(
'Non-acquisition plane measurement mapping not supported'
);
throw new Error('Non-acquisition plane measurement mapping not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
getSOPInstanceAttributes(referencedImageId);
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@@ -179,17 +166,9 @@ function getDisplayText(mappedAnnotations, displaySet) {
const displayText = [];
// Area is the same for all series
const {
angle,
unit,
SeriesNumber,
SOPInstanceUID,
frameNumber,
} = mappedAnnotations[0];
const { angle, unit, SeriesNumber, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
);
const instance = displaySet.images.find(image => image.SOPInstanceUID === SOPInstanceUID);
let InstanceNumber;
if (instance) {
@@ -202,9 +181,7 @@ function getDisplayText(mappedAnnotations, displaySet) {
return displayText;
}
const roundedAngle = utils.roundNumber(angle, 2);
displayText.push(
`${roundedAngle} ${unit} (S: ${SeriesNumber}${instanceText}${frameText})`
);
displayText.push(`${roundedAngle} ${unit} (S: ${SeriesNumber}${instanceText}${frameText})`);
return displayText;
}
@@ -31,11 +31,7 @@ const Length = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = getSOPInstanceAttributes(
referencedImageId,
cornerstoneViewportService,
viewportId
@@ -54,10 +50,7 @@ const Length = {
const { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
displaySetService
);
const mappedAnnotations = getMappedAnnotations(annotation, displaySetService);
const displayText = getDisplayText(mappedAnnotations, displaySet);
@@ -91,11 +84,8 @@ function getMappedAnnotations(annotation, displaySetService) {
const annotations = [];
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
getSOPInstanceAttributes(referencedImageId);
const displaySet = displaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@@ -126,9 +116,7 @@ function getDisplayText(mappedAnnotations, displaySet) {
// Area is the same for all series
const { SeriesNumber, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
);
const instance = displaySet.images.find(image => image.SOPInstanceUID === SOPInstanceUID);
let InstanceNumber;
if (instance) {
@@ -27,11 +27,7 @@ const Bidirectional = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = getSOPInstanceAttributes(
referencedImageId,
cornerstoneViewportService,
viewportId
@@ -50,14 +46,10 @@ const Bidirectional = {
const { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
displaySetService
);
const mappedAnnotations = getMappedAnnotations(annotation, displaySetService);
const displayText = getDisplayText(mappedAnnotations, displaySet);
const getReport = () =>
_getReport(mappedAnnotations, points, FrameOfReferenceUID);
const getReport = () => _getReport(mappedAnnotations, points, FrameOfReferenceUID);
return {
uid: annotationUID,
@@ -94,16 +86,11 @@ function getMappedAnnotations(annotation, displaySetService) {
const targetStats = cachedStats[targetId];
if (!referencedImageId) {
throw new Error(
'Non-acquisition plane measurement mapping not supported'
);
throw new Error('Non-acquisition plane measurement mapping not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
getSOPInstanceAttributes(referencedImageId);
const displaySet = displaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@@ -175,19 +162,11 @@ function getDisplayText(mappedAnnotations, displaySet) {
const displayText = [];
// Area is the same for all series
const {
length,
width,
SeriesNumber,
SOPInstanceUID,
frameNumber,
} = mappedAnnotations[0];
const { length, width, SeriesNumber, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
const roundedLength = utils.roundNumber(length, 2);
const roundedWidth = utils.roundNumber(width, 2);
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
);
const instance = displaySet.images.find(image => image.SOPInstanceUID === SOPInstanceUID);
let InstanceNumber;
if (instance) {
@@ -197,9 +176,7 @@ function getDisplayText(mappedAnnotations, displaySet) {
const instanceText = InstanceNumber ? ` I: ${InstanceNumber}` : '';
const frameText = displaySet.isMultiFrame ? ` F: ${frameNumber}` : '';
displayText.push(
`L: ${roundedLength} mm (S: ${SeriesNumber}${instanceText}${frameText})`
);
displayText.push(`L: ${roundedLength} mm (S: ${SeriesNumber}${instanceText}${frameText})`);
displayText.push(`W: ${roundedWidth} mm`);
return displayText;
@@ -25,11 +25,7 @@ const CircleROI = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = getSOPInstanceAttributes(
referencedImageId,
CornerstoneViewportService,
viewportId
@@ -48,14 +44,10 @@ const CircleROI = {
const { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
DisplaySetService
);
const mappedAnnotations = getMappedAnnotations(annotation, DisplaySetService);
const displayText = getDisplayText(mappedAnnotations, displaySet);
const getReport = () =>
_getReport(mappedAnnotations, points, FrameOfReferenceUID);
const getReport = () => _getReport(mappedAnnotations, points, FrameOfReferenceUID);
return {
uid: annotationUID,
@@ -93,16 +85,11 @@ function getMappedAnnotations(annotation, DisplaySetService) {
if (!referencedImageId) {
// Todo: Non-acquisition plane measurement mapping not supported yet
throw new Error(
'Non-acquisition plane measurement mapping not supported'
);
throw new Error('Non-acquisition plane measurement mapping not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
getSOPInstanceAttributes(referencedImageId);
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@@ -150,12 +137,7 @@ function _getReport(mappedAnnotations, points, FrameOfReferenceUID) {
return;
}
columns.push(
`max (${unit})`,
`mean (${unit})`,
`std (${unit})`,
`area (mm2)`
);
columns.push(`max (${unit})`, `mean (${unit})`, `std (${unit})`, `area (mm2)`);
values.push(max, mean, stdDev, area);
});
@@ -188,9 +170,7 @@ function getDisplayText(mappedAnnotations, displaySet) {
// Area is the same for all series
const { area, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
);
const instance = displaySet.images.find(image => image.SOPInstanceUID === SOPInstanceUID);
let InstanceNumber;
if (instance) {
@@ -32,11 +32,7 @@ const CobbAngle = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = getSOPInstanceAttributes(
referencedImageId,
CornerstoneViewportService,
viewportId
@@ -55,14 +51,10 @@ const CobbAngle = {
const { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
displaySetService
);
const mappedAnnotations = getMappedAnnotations(annotation, displaySetService);
const displayText = getDisplayText(mappedAnnotations, displaySet);
const getReport = () =>
_getReport(mappedAnnotations, points, FrameOfReferenceUID);
const getReport = () => _getReport(mappedAnnotations, points, FrameOfReferenceUID);
return {
uid: annotationUID,
@@ -99,16 +91,11 @@ function getMappedAnnotations(annotation, DisplaySetService) {
const targetStats = cachedStats[targetId];
if (!referencedImageId) {
throw new Error(
'Non-acquisition plane measurement mapping not supported'
);
throw new Error('Non-acquisition plane measurement mapping not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
getSOPInstanceAttributes(referencedImageId);
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@@ -179,17 +166,9 @@ function getDisplayText(mappedAnnotations, displaySet) {
const displayText = [];
// Area is the same for all series
const {
angle,
unit,
SeriesNumber,
SOPInstanceUID,
frameNumber,
} = mappedAnnotations[0];
const { angle, unit, SeriesNumber, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
);
const instance = displaySet.images.find(image => image.SOPInstanceUID === SOPInstanceUID);
let InstanceNumber;
if (instance) {
@@ -202,9 +181,7 @@ function getDisplayText(mappedAnnotations, displaySet) {
return displayText;
}
const roundedAngle = utils.roundNumber(angle, 2);
displayText.push(
`${roundedAngle} ${unit} (S: ${SeriesNumber}${instanceText}${frameText})`
);
displayText.push(`${roundedAngle} ${unit} (S: ${SeriesNumber}${instanceText}${frameText})`);
return displayText;
}
@@ -25,11 +25,7 @@ const EllipticalROI = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = getSOPInstanceAttributes(
referencedImageId,
cornerstoneViewportService,
viewportId
@@ -48,14 +44,10 @@ const EllipticalROI = {
const { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
displaySetService
);
const mappedAnnotations = getMappedAnnotations(annotation, displaySetService);
const displayText = getDisplayText(mappedAnnotations, displaySet);
const getReport = () =>
_getReport(mappedAnnotations, points, FrameOfReferenceUID);
const getReport = () => _getReport(mappedAnnotations, points, FrameOfReferenceUID);
return {
uid: annotationUID,
@@ -93,16 +85,11 @@ function getMappedAnnotations(annotation, displaySetService) {
if (!referencedImageId) {
// Todo: Non-acquisition plane measurement mapping not supported yet
throw new Error(
'Non-acquisition plane measurement mapping not supported'
);
throw new Error('Non-acquisition plane measurement mapping not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
getSOPInstanceAttributes(referencedImageId);
const displaySet = displaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@@ -150,12 +137,7 @@ function _getReport(mappedAnnotations, points, FrameOfReferenceUID) {
return;
}
columns.push(
`max (${unit})`,
`mean (${unit})`,
`std (${unit})`,
`area (mm2)`
);
columns.push(`max (${unit})`, `mean (${unit})`, `std (${unit})`, `area (mm2)`);
values.push(max, mean, stdDev, area);
});
@@ -188,9 +170,7 @@ function getDisplayText(mappedAnnotations, displaySet) {
// Area is the same for all series
const { area, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
);
const instance = displaySet.images.find(image => image.SOPInstanceUID === SOPInstanceUID);
let InstanceNumber;
if (instance) {
@@ -32,11 +32,7 @@ const Length = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = getSOPInstanceAttributes(
referencedImageId,
cornerstoneViewportService,
viewportId
@@ -55,14 +51,10 @@ const Length = {
const { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
displaySetService
);
const mappedAnnotations = getMappedAnnotations(annotation, displaySetService);
const displayText = getDisplayText(mappedAnnotations, displaySet);
const getReport = () =>
_getReport(mappedAnnotations, points, FrameOfReferenceUID);
const getReport = () => _getReport(mappedAnnotations, points, FrameOfReferenceUID);
return {
uid: annotationUID,
@@ -99,16 +91,11 @@ function getMappedAnnotations(annotation, displaySetService) {
const targetStats = cachedStats[targetId];
if (!referencedImageId) {
throw new Error(
'Non-acquisition plane measurement mapping not supported'
);
throw new Error('Non-acquisition plane measurement mapping not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
getSOPInstanceAttributes(referencedImageId);
const displaySet = displaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@@ -179,16 +166,9 @@ function getDisplayText(mappedAnnotations, displaySet) {
const displayText = [];
// Area is the same for all series
const {
length,
SeriesNumber,
SOPInstanceUID,
frameNumber,
} = mappedAnnotations[0];
const { length, SeriesNumber, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
);
const instance = displaySet.images.find(image => image.SOPInstanceUID === SOPInstanceUID);
let InstanceNumber;
if (instance) {
@@ -202,9 +182,7 @@ function getDisplayText(mappedAnnotations, displaySet) {
return displayText;
}
const roundedLength = utils.roundNumber(length, 2);
displayText.push(
`${roundedLength} mm (S: ${SeriesNumber}${instanceText}${frameText})`
);
displayText.push(`${roundedLength} mm (S: ${SeriesNumber}${instanceText}${frameText})`);
return displayText;
}
@@ -31,11 +31,7 @@ const PlanarFreehandROI = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = getSOPInstanceAttributes(
referencedImageId,
CornerstoneViewportService,
viewportId
@@ -54,14 +50,10 @@ const PlanarFreehandROI = {
const { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
DisplaySetService
);
const mappedAnnotations = getMappedAnnotations(annotation, DisplaySetService);
const displayText = getDisplayText(mappedAnnotations);
const getReport = () =>
_getReport(mappedAnnotations, points, FrameOfReferenceUID);
const getReport = () => _getReport(mappedAnnotations, points, FrameOfReferenceUID);
return {
uid: annotationUID,
@@ -96,10 +88,8 @@ function getMappedAnnotations(annotationData, DisplaySetService) {
const annotations = [];
const {
SOPInstanceUID: _SOPInstanceUID,
SeriesInstanceUID: _SeriesInstanceUID,
} = getSOPInstanceAttributes(referencedImageId) || {};
const { SOPInstanceUID: _SOPInstanceUID, SeriesInstanceUID: _SeriesInstanceUID } =
getSOPInstanceAttributes(referencedImageId) || {};
if (!_SOPInstanceUID || !_SeriesInstanceUID) {
return annotations;
@@ -25,11 +25,7 @@ const RectangleROI = {
throw new Error('Tool not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
StudyInstanceUID,
} = getSOPInstanceAttributes(
const { SOPInstanceUID, SeriesInstanceUID, StudyInstanceUID } = getSOPInstanceAttributes(
referencedImageId,
CornerstoneViewportService,
viewportId
@@ -48,14 +44,10 @@ const RectangleROI = {
const { points } = data.handles;
const mappedAnnotations = getMappedAnnotations(
annotation,
DisplaySetService
);
const mappedAnnotations = getMappedAnnotations(annotation, DisplaySetService);
const displayText = getDisplayText(mappedAnnotations, displaySet);
const getReport = () =>
_getReport(mappedAnnotations, points, FrameOfReferenceUID);
const getReport = () => _getReport(mappedAnnotations, points, FrameOfReferenceUID);
return {
uid: annotationUID,
@@ -93,16 +85,11 @@ function getMappedAnnotations(annotation, DisplaySetService) {
if (!referencedImageId) {
// Todo: Non-acquisition plane measurement mapping not supported yet
throw new Error(
'Non-acquisition plane measurement mapping not supported'
);
throw new Error('Non-acquisition plane measurement mapping not supported');
}
const {
SOPInstanceUID,
SeriesInstanceUID,
frameNumber,
} = getSOPInstanceAttributes(referencedImageId);
const { SOPInstanceUID, SeriesInstanceUID, frameNumber } =
getSOPInstanceAttributes(referencedImageId);
const displaySet = DisplaySetService.getDisplaySetForSOPInstanceUID(
SOPInstanceUID,
@@ -150,12 +137,7 @@ function _getReport(mappedAnnotations, points, FrameOfReferenceUID) {
return;
}
columns.push(
`max (${unit})`,
`mean (${unit})`,
`std (${unit})`,
`area (mm2)`
);
columns.push(`max (${unit})`, `mean (${unit})`, `std (${unit})`, `area (mm2)`);
values.push(max, mean, stdDev, area);
});
@@ -188,9 +170,7 @@ function getDisplayText(mappedAnnotations, displaySet) {
// Area is the same for all series
const { area, SOPInstanceUID, frameNumber } = mappedAnnotations[0];
const instance = displaySet.images.find(
image => image.SOPInstanceUID === SOPInstanceUID
);
const instance = displaySet.images.find(image => image.SOPInstanceUID === SOPInstanceUID);
let InstanceNumber;
if (instance) {
@@ -23,15 +23,8 @@ const measurementServiceMappingsFactory = (
*/
const _getValueTypeFromToolType = toolType => {
const {
POLYLINE,
ELLIPSE,
CIRCLE,
RECTANGLE,
BIDIRECTIONAL,
POINT,
ANGLE,
} = MeasurementService.VALUE_TYPES;
const { POLYLINE, ELLIPSE, CIRCLE, RECTANGLE, BIDIRECTIONAL, POINT, ANGLE } =
MeasurementService.VALUE_TYPES;
// TODO -> I get why this was attempted, but its not nearly flexible enough.
// A single measurement may have an ellipse + a bidirectional measurement, for instances.
@@ -18,24 +18,16 @@ function setAnnotationSelected(annotationUID: string, selected: boolean): void {
const isCurrentSelected = isAnnotationSelected(annotationUID);
// branch cut, avoid invoking imaging library unnecessarily.
if (isCurrentSelected !== selected) {
cs3dToolAnnotationUtils.selection.setAnnotationSelected(
annotationUID,
selected
);
cs3dToolAnnotationUtils.selection.setAnnotationSelected(annotationUID, selected);
}
}
function getFirstAnnotationSelected(element) {
const [selectedAnnotationUID] =
cs3dToolAnnotationUtils.selection.getAnnotationsSelected() || [];
const [selectedAnnotationUID] = cs3dToolAnnotationUtils.selection.getAnnotationsSelected() || [];
if (selectedAnnotationUID) {
return cs3dToolAnnotationUtils.state.getAnnotation(selectedAnnotationUID);
}
}
export {
isAnnotationSelected,
setAnnotationSelected,
getFirstAnnotationSelected,
};
export { isAnnotationSelected, setAnnotationSelected, getFirstAnnotationSelected };
+6 -22
View File
@@ -51,9 +51,7 @@ export default function interleaveNthLoader({
.map(volume => volume.getImageLoadRequests())
.filter(requests => requests?.[0]?.imageId);
const orderedRequests = originalRequests.map(request =>
getNthFrames(request)
);
const orderedRequests = originalRequests.map(request => getNthFrames(request));
// set the finalRequests to the imageLoadPoolManager
const finalRequests = interleave(orderedRequests);
@@ -61,31 +59,17 @@ export default function interleaveNthLoader({
const requestType = Enums.RequestType.Prefetch;
const priority = 0;
finalRequests.forEach(
({ callLoadImage, additionalDetails, imageId, imageIdIndex, options }) => {
const callLoadImageBound = callLoadImage.bind(
null,
imageId,
imageIdIndex,
options
);
finalRequests.forEach(({ callLoadImage, additionalDetails, imageId, imageIdIndex, options }) => {
const callLoadImageBound = callLoadImage.bind(null, imageId, imageIdIndex, options);
imageLoadPoolManager.addRequest(
callLoadImageBound,
requestType,
additionalDetails,
priority
);
}
);
imageLoadPoolManager.addRequest(callLoadImageBound, requestType, additionalDetails, priority);
});
// clear the volumeIdMapsToLoad
volumeIdMapsToLoad.clear();
// copy the viewportIdVolumeInputArrayMap
const viewportIdVolumeInputArrayMapCopy = new Map(
viewportIdVolumeInputArrayMap
);
const viewportIdVolumeInputArrayMapCopy = new Map(viewportIdVolumeInputArrayMap);
// reset the viewportIdVolumeInputArrayMap
viewportIdVolumeInputArrayMap.clear();
@@ -1,9 +1,7 @@
import { segmentation } from '@cornerstonejs/tools';
function removeToolGroupSegmentationRepresentations(toolGroupId) {
const representations = segmentation.state.getSegmentationRepresentations(
toolGroupId
);
const representations = segmentation.state.getSegmentationRepresentations(toolGroupId);
if (!representations || !representations.length) {
return;
@@ -1,8 +1,6 @@
import { Types, getRenderingEngine, utilities } from '@cornerstonejs/core';
export default function calculateViewportRegistrations(
viewports: Types.IViewportId[]
) {
export default function calculateViewportRegistrations(viewports: Types.IViewportId[]) {
const viewportPairs = _getViewportPairs(viewports);
for (const [viewport, nextViewport] of viewportPairs) {
@@ -6,28 +6,16 @@ import calculateViewportRegistrations from './calculateViewportRegistrations';
// ]}
let STACK_IMAGE_SYNC_GROUPS_INFO = [];
export default function toggleStackImageSync({
toggledState,
servicesManager,
getEnabledElement,
}) {
const {
syncGroupService,
viewportGridService,
displaySetService,
cornerstoneViewportService,
} = servicesManager.services;
export default function toggleStackImageSync({ toggledState, servicesManager, getEnabledElement }) {
const { syncGroupService, viewportGridService, displaySetService, cornerstoneViewportService } =
servicesManager.services;
if (!toggledState) {
STACK_IMAGE_SYNC_GROUPS_INFO.forEach(syncGroupInfo => {
const { viewports, synchronizerId } = syncGroupInfo;
viewports.forEach(({ viewportId, renderingEngineId }) => {
syncGroupService.removeViewportFromSyncGroup(
viewportId,
renderingEngineId,
synchronizerId
);
syncGroupService.removeViewportFromSyncGroup(viewportId, renderingEngineId, synchronizerId);
});
});
@@ -47,9 +35,7 @@ export default function toggleStackImageSync({
const { displaySetInstanceUIDs } = viewport;
for (const displaySetInstanceUID of displaySetInstanceUIDs) {
const displaySet = displaySetService.getDisplaySetByUID(
displaySetInstanceUID
);
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
return !!displaySet?.isReconstructable;
}
@@ -64,8 +50,7 @@ export default function toggleStackImageSync({
}
const { element } = cornerstoneViewportService.getViewportInfo(viewportId);
const { viewport: csViewport, renderingEngineId } =
getEnabledElement(element);
const { viewport: csViewport, renderingEngineId } = getEnabledElement(element);
const { viewPlaneNormal } = csViewport.getCamera();
// Should we round here? I guess so, but not sure how much precision we need
@@ -82,9 +67,7 @@ export default function toggleStackImageSync({
// create synchronizer for each group
Object.values(viewportsByOrientation).map(viewports => {
let synchronizerId = viewports
.map(({ viewportId }) => viewportId)
.join(',');
let synchronizerId = viewports.map(({ viewportId }) => viewportId).join(',');
synchronizerId = `imageSync_${synchronizerId}`;