From c9d3c08cb66e8d593ac0f9b084da872f028010a0 Mon Sep 17 00:00:00 2001 From: Alireza Date: Fri, 28 Apr 2023 10:14:14 -0400 Subject: [PATCH] feat(cst): Add new command to get nearby annotation tools (#3327) * feat(cst): Add new command to get nearby annotation tools This commit adds a new command `getNearbyAnnotation` to the `commandsModule.ts` file that identifies nearby annotation tools excluding Crosshairs and ReferenceLines. It also removes an unused mapping to `Crosshairs` in `initMeasurementService.js` and changes the command run in `findNearbyToolData.ts` to `getNearbyAnnotation`. * perf(cornerstone): Improve performance by optimizing tools Removes unnecessary imports to improve app's performance. Changes how annotations are detected on the `commandsModule.js` file by fetching the `isAnnotation` property of the tool instance if available. Updates `CrosshairsTool` and `ReferenceLinesTool` to not be annotations anymore. Adjusts the `localhost` URL ports for the `dcm4chee-arc` service interface on `local_dcm4chee.js` to allow for more efficient server communication. * feat(cornerstone): Add CornerstoneServices type and ToolGroupService.getToolGroup to get tool group by ID or active viewport This commit introduces the new CornerstoneServices interface to the code and adds the ToolGroupService.getToolGroup method, which can retrieve a specific tool group by ID or from the active viewport. The older _getToolGroup method has also been removed from commandsModule. When no tool group ID is provided, this method now retrieves the tool group from the currently active viewport with the help of getActiveViewportEnabledElement. Additionally, the required reference to @ohif/core has been removed. --- extensions/cornerstone/src/commandsModule.ts | 80 +++++++++---------- .../cornerstone/src/initCornerstoneTools.js | 3 + .../cornerstone/src/initMeasurementService.js | 14 ---- .../ToolGroupService/ToolGroupService.ts | 49 ++++++++++-- .../src/utils/findNearbyToolData.ts | 2 +- .../MeasurementService/MeasurementService.ts | 3 +- .../viewer/public/config/local_dcm4chee.js | 7 +- 7 files changed, 90 insertions(+), 68 deletions(-) diff --git a/extensions/cornerstone/src/commandsModule.ts b/extensions/cornerstone/src/commandsModule.ts index 4d1948de8d8..c57d3b0a961 100644 --- a/extensions/cornerstone/src/commandsModule.ts +++ b/extensions/cornerstone/src/commandsModule.ts @@ -10,7 +10,6 @@ import { utilities as cstUtils, ReferenceLinesTool, } from '@cornerstonejs/tools'; -import { ServicesManager } from '@ohif/core'; import CornerstoneViewportDownloadForm from './utils/CornerstoneViewportDownloadForm'; import callInputDialog from './utils/callInputDialog'; @@ -18,6 +17,7 @@ import { setColormap } from './utils/colormap/transferFunctionHelpers'; import toggleStackImageSync from './utils/stackSync/toggleStackImageSync'; import { getFirstAnnotationSelected } from './utils/measurementServiceMappings/utils/selection'; import getActiveViewportEnabledElement from './utils/getActiveViewportEnabledElement'; +import { CornerstoneServices } from './types'; function commandsModule({ servicesManager, commandsManager }) { const { @@ -28,51 +28,14 @@ function commandsModule({ servicesManager, commandsManager }) { uiDialogService, cornerstoneViewportService, uiNotificationService, - customizationService, measurementService, - hangingProtocolService, - } = (servicesManager as ServicesManager).services; + } = servicesManager.services as CornerstoneServices; const { measurementServiceSource } = this; function _getActiveViewportEnabledElement() { return getActiveViewportEnabledElement(viewportGridService); } - - function _getToolGroup(toolGroupId) { - let toolGroupIdToUse = toolGroupId; - - if (!toolGroupIdToUse) { - // Use the active viewport's tool group if no tool group id is provided - const enabledElement = _getActiveViewportEnabledElement(); - - if (!enabledElement) { - return; - } - - const { renderingEngineId, viewportId } = enabledElement; - const toolGroup = ToolGroupManager.getToolGroupForViewport( - viewportId, - renderingEngineId - ); - - if (!toolGroup) { - console.warn( - 'No tool group found for viewportId:', - viewportId, - 'and renderingEngineId:', - renderingEngineId - ); - return; - } - - toolGroupIdToUse = toolGroup.id; - } - - const toolGroup = toolGroupService.getToolGroup(toolGroupIdToUse); - return toolGroup; - } - const actions = { /** * Generates the selector props for the context menu, specific to @@ -127,6 +90,36 @@ function commandsModule({ servicesManager, commandsManager }) { cstUtils.getAnnotationNearPoint(element, canvasCoordinates) ); }, + getNearbyAnnotation({ element, canvasCoordinates }) { + const nearbyToolData = actions.getNearbyToolData({ + nearbyToolData: null, + element, + canvasCoordinates, + }); + + const isAnnotation = toolName => { + const enabledElement = getEnabledElement(element); + + if (!enabledElement) { + return; + } + + const { renderingEngineId, viewportId } = enabledElement; + const toolGroup = ToolGroupManager.getToolGroupForViewport( + viewportId, + renderingEngineId + ); + + const toolInstance = toolGroup.getToolInstance(toolName); + + return toolInstance?.constructor?.isAnnotation ?? true; + }; + + return nearbyToolData?.metadata?.toolName && + isAnnotation(nearbyToolData.metadata.toolName) + ? nearbyToolData + : null; + }, // Measurement tool commands: @@ -298,7 +291,7 @@ function commandsModule({ servicesManager, commandsManager }) { setToolActive: ({ toolName, toolGroupId = null }) => { if (toolName === 'Crosshairs') { - const activeViewportToolGroup = _getToolGroup(null); + const activeViewportToolGroup = toolGroupService.getToolGroup(null); if (!activeViewportToolGroup._toolInstances.Crosshairs) { uiNotificationService.show({ @@ -317,7 +310,7 @@ function commandsModule({ servicesManager, commandsManager }) { viewports: [], }; - const toolGroup = _getToolGroup(toolGroupId); + const toolGroup = toolGroupService.getToolGroup(toolGroupId); const toolGroupViewportIds = toolGroup?.getViewportIds?.(); // if toolGroup has been destroyed, or its viewports have been removed @@ -635,6 +628,11 @@ function commandsModule({ servicesManager, commandsManager }) { storeContexts: [], options: {}, }, + getNearbyAnnotation: { + commandFn: actions.getNearbyAnnotation, + storeContexts: [], + options: {}, + }, deleteMeasurement: { commandFn: actions.deleteMeasurement, diff --git a/extensions/cornerstone/src/initCornerstoneTools.js b/extensions/cornerstone/src/initCornerstoneTools.js index 5df8f898309..9549b17f911 100644 --- a/extensions/cornerstone/src/initCornerstoneTools.js +++ b/extensions/cornerstone/src/initCornerstoneTools.js @@ -30,6 +30,9 @@ import { import CalibrationLineTool from './tools/CalibrationLineTool'; export default function initCornerstoneTools(configuration = {}) { + CrosshairsTool.isAnnotation = false; + ReferenceLinesTool.isAnnotation = false; + init(configuration); addTool(PanTool); addTool(WindowLevelTool); diff --git a/extensions/cornerstone/src/initMeasurementService.js b/extensions/cornerstone/src/initMeasurementService.js index c11a53111d9..3a883cc79da 100644 --- a/extensions/cornerstone/src/initMeasurementService.js +++ b/extensions/cornerstone/src/initMeasurementService.js @@ -49,20 +49,6 @@ const initMeasurementService = ( Length.toMeasurement ); - measurementService.addMapping( - csTools3DVer1MeasurementSource, - 'Crosshairs', - Length.matchingCriteria, - () => { - console.warn('Crosshairs mapping not implemented.'); - return {}; - }, - () => { - console.warn('Crosshairs mapping not implemented.'); - return {}; - } - ); - measurementService.addMapping( csTools3DVer1MeasurementSource, 'Bidirectional', diff --git a/extensions/cornerstone/src/services/ToolGroupService/ToolGroupService.ts b/extensions/cornerstone/src/services/ToolGroupService/ToolGroupService.ts index 4f5512ecf05..8772e02bfdc 100644 --- a/extensions/cornerstone/src/services/ToolGroupService/ToolGroupService.ts +++ b/extensions/cornerstone/src/services/ToolGroupService/ToolGroupService.ts @@ -1,6 +1,7 @@ import { ToolGroupManager, Enums, Types } from '@cornerstonejs/tools'; import { Types as OhifTypes, pubSubServiceInterface } from '@ohif/core'; +import getActiveViewportEnabledElement from '../../utils/getActiveViewportEnabledElement'; const EVENTS = { VIEWPORT_ADDED: 'event::cornerstone::toolgroupservice:viewportadded', @@ -39,20 +40,56 @@ export default class ToolGroupService { EVENTS: { [key: string]: string }; constructor(serviceManager) { - const { cornerstoneViewportService } = serviceManager.services; + const { + cornerstoneViewportService, + viewportGridService, + } = serviceManager.services; this.cornerstoneViewportService = cornerstoneViewportService; + this.viewportGridService = viewportGridService; this.listeners = {}; this.EVENTS = EVENTS; Object.assign(this, pubSubServiceInterface); } /** - * Returns the cornerstone ToolGroup for a given toolGroup UID - * @param {string} toolGroupId - The toolGroup uid - * @returns {IToolGroup} - The toolGroup + * Retrieves a tool group from the ToolGroupManager by tool group ID. + * If no tool group ID is provided, it retrieves the tool group of the active viewport. + * @param toolGroupId - Optional ID of the tool group to retrieve. + * @returns The tool group or undefined if it is not found. */ - public getToolGroup(toolGroupId: string): Types.IToolGroup | void { - const toolGroup = ToolGroupManager.getToolGroup(toolGroupId); + public getToolGroup(toolGroupId?: string): Types.IToolGroup | void { + let toolGroupIdToUse = toolGroupId; + + if (!toolGroupIdToUse) { + // Use the active viewport's tool group if no tool group id is provided + const enabledElement = getActiveViewportEnabledElement( + this.viewportGridService + ); + + if (!enabledElement) { + return; + } + + const { renderingEngineId, viewportId } = enabledElement; + const toolGroup = ToolGroupManager.getToolGroupForViewport( + viewportId, + renderingEngineId + ); + + if (!toolGroup) { + console.warn( + 'No tool group found for viewportId:', + viewportId, + 'and renderingEngineId:', + renderingEngineId + ); + return; + } + + toolGroupIdToUse = toolGroup.id; + } + + const toolGroup = ToolGroupManager.getToolGroup(toolGroupIdToUse); return toolGroup; } diff --git a/extensions/cornerstone/src/utils/findNearbyToolData.ts b/extensions/cornerstone/src/utils/findNearbyToolData.ts index ab57a67d25d..95e9347665b 100644 --- a/extensions/cornerstone/src/utils/findNearbyToolData.ts +++ b/extensions/cornerstone/src/utils/findNearbyToolData.ts @@ -11,7 +11,7 @@ export const findNearbyToolData = (commandsManager, evt) => { } const { element, currentPoints } = evt.detail; return commandsManager.runCommand( - 'getNearbyToolData', + 'getNearbyAnnotation', { element, canvasCoordinates: currentPoints?.canvas, diff --git a/platform/core/src/services/MeasurementService/MeasurementService.ts b/platform/core/src/services/MeasurementService/MeasurementService.ts index 3a89d2094ad..b1d3e5af7ee 100644 --- a/platform/core/src/services/MeasurementService/MeasurementService.ts +++ b/platform/core/src/services/MeasurementService/MeasurementService.ts @@ -508,7 +508,6 @@ class MeasurementService extends PubSubService { if (!this._isValidSource(source)) { throw new Error('Invalid source.'); } - if (!annotationType) { throw new Error('No source annotationType provided.'); } @@ -572,7 +571,7 @@ class MeasurementService extends PubSubService { // For now, it is just added in OHIF here and in setMeasurementSelected. this.measurements[internalUID] = newMeasurement; if (isUpdate) { - this._broadcastEvent(this.EVENTS.MEASUREMENT_UPDATED, { + this._broadcastEvent(this.EVENTS.MEASUREMENT_UPDATED, { source, measurement: newMeasurement, notYetUpdatedAtSource: false, diff --git a/platform/viewer/public/config/local_dcm4chee.js b/platform/viewer/public/config/local_dcm4chee.js index 28ae28fd922..fca1f2a71db 100644 --- a/platform/viewer/public/config/local_dcm4chee.js +++ b/platform/viewer/public/config/local_dcm4chee.js @@ -16,14 +16,13 @@ window.config = { sourceName: 'dicomweb', configuration: { name: 'DCM4CHEE', - wadoUriRoot: 'http://localhost/dcm4chee-arc/aets/DCM4CHEE/wado', - qidoRoot: 'http://localhost/dcm4chee-arc/aets/DCM4CHEE/rs', - wadoRoot: 'http://localhost/dcm4chee-arc/aets/DCM4CHEE/rs', + wadoUriRoot: 'http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/wado', + qidoRoot: 'http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs', + wadoRoot: 'http://localhost:8080/dcm4chee-arc/aets/DCM4CHEE/rs', qidoSupportsIncludeField: true, imageRendering: 'wadors', enableStudyLazyLoad: true, thumbnailRendering: 'wadors', - useBulkDataURI: false, requestOptions: { auth: 'admin:admin', },