feat(4D): Add 4D dynamic volume rendering and new pre-clinical 4d pt/ct mode (#3664)
Co-authored-by: Alireza <ar.sedghi@gmail.com> Co-authored-by: Neil <neil.a.macphee@gmail.com>
This commit is contained in:
200 files changed
+9589
-2178
No files matched your search
@@ -32,8 +32,8 @@
|
||||
"start": "yarn run dev"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cornerstonejs/core": "^1.68.1",
|
||||
"@cornerstonejs/tools": "^1.68.1",
|
||||
"@cornerstonejs/core": "^1.70.0",
|
||||
"@cornerstonejs/tools": "^1.70.0",
|
||||
"@ohif/core": "3.8.0-beta.73",
|
||||
"@ohif/extension-cornerstone-dicom-sr": "3.8.0-beta.73",
|
||||
"@ohif/ui": "3.8.0-beta.73",
|
||||
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Button, ButtonEnums } from '@ohif/ui';
|
||||
|
||||
function ActionButtons({ onExportClick, onCreateReportClick, disabled }) {
|
||||
const { t } = useTranslation('MeasurementTable');
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Button
|
||||
onClick={onExportClick}
|
||||
disabled={disabled}
|
||||
type={ButtonEnums.type.secondary}
|
||||
size={ButtonEnums.size.small}
|
||||
>
|
||||
{t('Export')}
|
||||
</Button>
|
||||
<Button
|
||||
className="ml-2"
|
||||
onClick={onCreateReportClick}
|
||||
type={ButtonEnums.type.secondary}
|
||||
size={ButtonEnums.size.small}
|
||||
disabled={disabled}
|
||||
>
|
||||
{t('Create Report')}
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
ActionButtons.propTypes = {
|
||||
onExportClick: PropTypes.func,
|
||||
onCreateReportClick: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
ActionButtons.defaultProps = {
|
||||
onExportClick: () => alert('Export'),
|
||||
onCreateReportClick: () => alert('Create Report'),
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
export default ActionButtons;
|
||||
+25
-20
@@ -1,19 +1,12 @@
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
StudySummary,
|
||||
MeasurementTable,
|
||||
Dialog,
|
||||
Input,
|
||||
useViewportGrid,
|
||||
ButtonEnums,
|
||||
} from '@ohif/ui';
|
||||
import { StudySummary, MeasurementTable, useViewportGrid, ActionButtons } from '@ohif/ui';
|
||||
import { DicomMetadataStore, utils } from '@ohif/core';
|
||||
import { useDebounce } from '@hooks';
|
||||
import { useAppConfig } from '@state';
|
||||
import ActionButtons from './ActionButtons';
|
||||
import { useTrackedMeasurements } from '../../getContextModule';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const { downloadCSVReport } = utils;
|
||||
const { formatDate } = utils;
|
||||
@@ -27,9 +20,11 @@ const DISPLAY_STUDY_SUMMARY_INITIAL_VALUE = {
|
||||
|
||||
function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
const [viewportGrid] = useViewportGrid();
|
||||
const { t } = useTranslation('MeasurementTable');
|
||||
const [measurementChangeTimestamp, setMeasurementsUpdated] = useState(Date.now().toString());
|
||||
const debouncedMeasurementChangeTimestamp = useDebounce(measurementChangeTimestamp, 200);
|
||||
const { measurementService, uiDialogService, displaySetService, customizationService } = servicesManager.services;
|
||||
const { measurementService, uiDialogService, displaySetService, customizationService } =
|
||||
servicesManager.services;
|
||||
const [trackedMeasurements, sendTrackedMeasurementsEvent] = useTrackedMeasurements();
|
||||
const { trackedStudy, trackedSeries } = trackedMeasurements.context;
|
||||
const [displayStudySummary, setDisplayStudySummary] = useState(
|
||||
@@ -172,6 +167,9 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
dm => dm.measurementType === measurementService.VALUE_TYPES.POINT
|
||||
);
|
||||
|
||||
const disabled =
|
||||
additionalFindings.length === 0 && displayMeasurementsWithoutFindings.length === 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -206,16 +204,23 @@ function PanelMeasurementTableTracking({ servicesManager, extensionManager }) {
|
||||
{!appConfig?.disableEditing && (
|
||||
<div className="flex justify-center p-4">
|
||||
<ActionButtons
|
||||
onExportClick={exportReport}
|
||||
onCreateReportClick={() => {
|
||||
sendTrackedMeasurementsEvent('SAVE_REPORT', {
|
||||
viewportId: viewportGrid.activeViewportId,
|
||||
isBackupSave: true,
|
||||
});
|
||||
}}
|
||||
disabled={
|
||||
additionalFindings.length === 0 && displayMeasurementsWithoutFindings.length === 0
|
||||
}
|
||||
t={t}
|
||||
actions={[
|
||||
{
|
||||
label: 'Export',
|
||||
onClick: exportReport,
|
||||
},
|
||||
{
|
||||
label: 'Create Report',
|
||||
onClick: () => {
|
||||
sendTrackedMeasurementsEvent('SAVE_REPORT', {
|
||||
viewportId: viewportGrid.activeViewportId,
|
||||
isBackupSave: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
]}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
+24
-5
@@ -19,8 +19,13 @@ function PanelStudyBrowserTracking({
|
||||
requestDisplaySetCreationForStudy,
|
||||
dataSource,
|
||||
}) {
|
||||
const { displaySetService, uiDialogService, hangingProtocolService, uiNotificationService, measurementService } =
|
||||
servicesManager.services;
|
||||
const {
|
||||
displaySetService,
|
||||
uiDialogService,
|
||||
hangingProtocolService,
|
||||
uiNotificationService,
|
||||
measurementService,
|
||||
} = servicesManager.services;
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { t } = useTranslation('Common');
|
||||
@@ -129,7 +134,8 @@ function PanelStudyBrowserTracking({
|
||||
const newImageSrcEntry = {};
|
||||
const displaySet = displaySetService.getDisplaySetByUID(dSet.displaySetInstanceUID);
|
||||
const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
|
||||
const imageId = imageIds[Math.floor(imageIds.length / 2)];
|
||||
|
||||
const imageId = getImageIdForThumbnail(displaySet, imageIds);
|
||||
|
||||
// TODO: Is it okay that imageIds are not returned here for SR displaySets?
|
||||
if (!imageId || displaySet?.unsupported) {
|
||||
@@ -195,7 +201,7 @@ function PanelStudyBrowserTracking({
|
||||
}
|
||||
|
||||
const imageIds = dataSource.getImageIdsForDisplaySet(displaySet);
|
||||
const imageId = imageIds[Math.floor(imageIds.length / 2)];
|
||||
const imageId = getImageIdForThumbnail(displaySet, imageIds);
|
||||
|
||||
// TODO: Is it okay that imageIds are not returned here for SR displaysets?
|
||||
if (!imageId) {
|
||||
@@ -366,6 +372,19 @@ PanelStudyBrowserTracking.propTypes = {
|
||||
|
||||
export default PanelStudyBrowserTracking;
|
||||
|
||||
function getImageIdForThumbnail(displaySet: any, imageIds: any) {
|
||||
let imageId;
|
||||
if (displaySet.isDynamicVolume) {
|
||||
const timePoints = displaySet.dynamicVolumeInfo.timePoints;
|
||||
const middleIndex = Math.floor(timePoints.length / 2);
|
||||
const middleTimePointImageIds = timePoints[middleIndex];
|
||||
imageId = middleTimePointImageIds[Math.floor(middleTimePointImageIds.length / 2)];
|
||||
} else {
|
||||
imageId = imageIds[Math.floor(imageIds.length / 2)];
|
||||
}
|
||||
return imageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps from the DataSource's format to a naturalized object
|
||||
*
|
||||
@@ -631,4 +650,4 @@ function _findTabAndStudyOfDisplaySet(displaySetInstanceUID, tabs) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,17 +140,18 @@ function TrackedCornerstoneViewport(props) {
|
||||
// Only send the tracked measurements event for the active viewport to avoid
|
||||
// sending it more than once.
|
||||
if (viewportId === activeViewportId) {
|
||||
const { referenceStudyUID: StudyInstanceUID,
|
||||
const {
|
||||
referenceStudyUID: StudyInstanceUID,
|
||||
referenceSeriesUID: SeriesInstanceUID,
|
||||
uid: measurementId } =
|
||||
measurement;
|
||||
uid: measurementId,
|
||||
} = measurement;
|
||||
|
||||
sendTrackedMeasurementsEvent('SET_DIRTY', { SeriesInstanceUID });
|
||||
sendTrackedMeasurementsEvent('TRACK_SERIES', {
|
||||
viewportId,
|
||||
StudyInstanceUID,
|
||||
SeriesInstanceUID,
|
||||
measurementId
|
||||
measurementId,
|
||||
});
|
||||
}
|
||||
}).unsubscribe
|
||||
|
||||
Reference in new issue
Block a user