WIP reorganization

This commit is contained in:
Erik Ziegler committed 2018-12-12 09:10:39 +01:00
1 parent 6706dfe634
commit 054e37dfb7
266 files changed
+98 -620

No files matched your search

@@ -0,0 +1,16 @@
export default function(handles, image={}) {
// Calculate the long axis length
const dx = (handles.start.x - handles.end.x) * (image.columnPixelSpacing || 1);
const dy = (handles.start.y - handles.end.y) * (image.rowPixelSpacing || 1);
const length = Math.sqrt(dx * dx + dy * dy) || 0;
// Calculate the short axis length
const wx = (handles.perpendicularStart.x - handles.perpendicularEnd.x) * (image.columnPixelSpacing || 1);
const wy = (handles.perpendicularStart.y - handles.perpendicularEnd.y) * (image.rowPixelSpacing || 1);
const width = Math.sqrt(wx * wx + wy * wy) || 0;
return {
longestDiameter: length.toFixed(1),
shortestDiameter: width.toFixed(1)
};
}
@@ -0,0 +1,14 @@
// Get the key for the handle which is selected
export default function(handles) {
let selectedHandleKey;
Object.keys(handles).every(handleKey => {
const handle = handles[handleKey];
if (handle.selected) {
selectedHandleKey = handleKey;
return false;
}
return true;
});
return selectedHandleKey;
}
@@ -0,0 +1,23 @@
import { OHIF } from 'meteor/ohif:core';
import getSelectedHandleKey from './getSelectedHandleKey';
import repositionBidirectionalArmHandle from './repositionBidirectionalArmHandle';
import getLongestAndShortestDiameters from './getLongestAndShortestDiameters';
OHIF.lesiontracker.bidirectional = {
toolType: 'bidirectional',
inverseKeyMap: {
start: 'end',
end: 'start',
perpendicularStart: 'perpendicularEnd',
perpendicularEnd: 'perpendicularStart'
},
perpendicularKeyMap: {
start: 'perpendicularStart',
end: 'perpendicularEnd',
perpendicularStart: 'start',
perpendicularEnd: 'end'
},
getSelectedHandleKey,
repositionBidirectionalArmHandle,
getLongestAndShortestDiameters
};
@@ -0,0 +1,65 @@
import { _ } from 'meteor/underscore';
import { OHIF } from 'meteor/ohif:core';
// Return the newPosition for the handle based on the mmStep and handles
export default function(image, handles, handleKey, mmStep, mmLimit=1) {
if (handleKey === 'textBox') return;
const lib = OHIF.lesiontracker.bidirectional;
// Defines how much the arm will increase/decrease
const columnPixelSpacing = (image && image.columnPixelSpacing) || 1;
const rowPixelSpacing = (image && image.rowPixelSpacing) || 1;
const stepX = mmStep * (1 / columnPixelSpacing);
const stepY = mmStep * (1 / rowPixelSpacing);
// Get the line angle and its handles
const keyA = handleKey;
const keyB = lib.inverseKeyMap[handleKey];
const handleA = handles[keyA];
const handleB = handles[keyB];
const angle = Math.atan2(handleA.y - handleB.y, handleA.x - handleB.x);
// Calculate the new position of the handle
const newPosition = {
x: handleA.x + Math.cos(angle) * stepX,
y: handleA.y + Math.sin(angle) * stepY
};
if (mmStep < 0) {
// Get the perpendicular handles
const keyC = lib.perpendicularKeyMap[keyA];
const keyD = lib.perpendicularKeyMap[keyB];
const handleC = handles[keyC];
const handleD = handles[keyD];
// Create the line segment for the arm being resized
const lineAB = {
start: _.pick(handleA, ['x', 'y']),
end: _.pick(handleB, ['x', 'y'])
};
// Create the line segment for the perpendicular arm
const lineCD = {
start: _.pick(handleC, ['x', 'y']),
end: _.pick(handleD, ['x', 'y'])
};
// Get the intersection point between the arms
const intersection = cornerstoneMath.lineSegment.intersectLine(lineAB, lineCD);
// Keep the minimum distance of 0.1 mm to the intersection point
const dx = (intersection.x - newPosition.x) * columnPixelSpacing;
const dy = (intersection.y - newPosition.y) * rowPixelSpacing;
const distance = Math.sqrt((dx * dx) + (dy * dy));
const newAngle = Math.atan2(newPosition.y - intersection.y, newPosition.x - intersection.x);
if (angle.toFixed(8) !== newAngle.toFixed(8) || distance < Math.abs(mmLimit)) {
Object.assign(newPosition, {
x: intersection.x - Math.cos(angle) * mmLimit * Math.sign(stepX),
y: intersection.y - Math.sin(angle) * mmLimit * Math.sign(stepY)
});
}
}
return newPosition;
}
@@ -0,0 +1,50 @@
import { OHIF } from 'meteor/ohif:core';
const removeToolDataWithMeasurementId = (imageId, toolType, measurementId) => {
OHIF.log.info('removeToolDataWithMeasurementId');
const toolState = cornerstoneTools.globalImageIdSpecificToolStateManager.saveToolState();
// Find any related toolData
if (!toolState[imageId] || !toolState[imageId][toolType]) {
return;
}
const toolData = toolState[imageId][toolType].data;
if (!toolData.length) {
return;
}
// Search toolData for entries linked to the specified Measurement
const toRemove = [];
toolData.forEach(function(measurement, index) {
if (measurement.id === measurementId ||
measurement._id === measurementId) {
toRemove.push(index);
return false;
}
});
OHIF.log.info('Removing Indices: ');
OHIF.log.info(toRemove);
// If any toolData entries need to be removed, splice them from
// the toolData array
toRemove.forEach(function(index) {
toolData.splice(index, 1);
});
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState(toolState);
};
OHIF.lesiontracker.clearMeasurementTimepointData = (measurementId, timepointId) => {
const data = Measurements.findOne(measurementId);
// Clear the Measurement data for this timepoint
const imageId = data.timepoints[timepointId].imageId;
const toolType = data.toolType;
removeToolDataWithMeasurementId(imageId, toolType, measurementId);
// Update any viewports that are currently displaying this imageId
const enabledElements = cornerstone.getEnabledElementsByImageId(imageId);
enabledElements.forEach(enabledElement => cornerstone.updateImage(enabledElement.element));
};
@@ -0,0 +1,52 @@
import { _ } from 'meteor/underscore';
import { OHIF } from 'meteor/ohif:core';
OHIF.lesiontracker.configureTargetToolsHandles = () => {
const toggleLabel = (measurementData, eventData, doneCallback) => {
delete measurementData.isCreating;
if (OHIF.lesiontracker.removeMeasurementIfInvalid(measurementData, eventData)) {
return;
}
const getHandlePosition = key => _.pick(measurementData.handles[key], ['x', 'y']);
const start = getHandlePosition('start');
const end = getHandlePosition('end');
const getDirection = axis => start[axis] < end[axis] ? 1 : -1;
const position = OHIF.cornerstone.pixelToPage(eventData.element, end);
OHIF.measurements.toggleLabelButton({
measurement: measurementData,
element: eventData.element,
measurementApi: OHIF.viewer.measurementApi,
position: position,
direction: {
x: getDirection('x'),
y: getDirection('y')
}
});
};
const callbackConfig = {
// TODO: Check the position for these, the Add Label button position seems very awkward
getMeasurementLocationCallback: toggleLabel,
changeMeasurementLocationCallback: toggleLabel,
};
// TODO: Reconcile this with the configuration in toolManager it would be better to have this
// all in one place.
const appendConfig = toolType => {
const tool = cornerstoneTools[toolType];
const toolConfig = tool.getConfiguration();
const config = Object.assign({}, toolConfig, callbackConfig);
tool.setConfiguration(config);
};
// Append the callback configuration to bidirectional tool
appendConfig('bidirectional');
// Append the callback configuration to CR and UN tools
appendConfig('targetCR');
appendConfig('targetUN');
};
@@ -0,0 +1,12 @@
// StudyList-related functions
import './studylist/studylistModification.js';
// Bidirectional tool utility functions
import './bidirectional';
// Library functions
import './pixelSpacingAutorunCheck.js';
import './removeMeasurementIfInvalid.js';
import './toggleLesionTrackerTools.js';
import './clearMeasurementTimepointData.js';
import './configureTargetToolsHandles.js';
@@ -0,0 +1,40 @@
import { Session } from 'meteor/session';
import { OHIF } from 'meteor/ohif:core';
OHIF.lesiontracker.pixelSpacingAutorunCheck = () => {
OHIF.log.info('lesionTool button change autorun');
// Get oncology tools
const $oncologyTools = $('button#lesion, button#nonTarget');
// TODO: Set activeViewport for empty viewport element
const activeViewportIndex = window.store.getState().viewports.activeViewport;
if (activeViewportIndex === undefined) {
return;
}
const element = $('.imageViewerViewport').get(activeViewportIndex);
if (!element) {
return;
}
let enabledElement;
try {
enabledElement = cornerstone.getEnabledElement(element);
} catch(error) {
return;
}
// Check value of rowPixelSpacing & columnPixelSpacing to define as unavailable
if (!enabledElement ||
!enabledElement.image ||
!enabledElement.image.rowPixelSpacing ||
!enabledElement.image.columnPixelSpacing) {
// Disable Lesion Buttons
$oncologyTools.prop('disabled', true);
} else {
// Enable Lesion Buttons
$oncologyTools.prop('disabled', false);
}
};
@@ -0,0 +1,16 @@
import { OHIF } from 'meteor/ohif:core';
import { _ } from 'meteor/underscore';
OHIF.lesiontracker.removeMeasurementIfInvalid = (measurementData, eventData) => {
const handles = measurementData.handles;
const start = _.pick(handles.start, ['x', 'y']);
const end = _.pick(handles.end, ['x', 'y']);
const element = eventData.element;
const toolType = measurementData.toolType;
if (_.isEqual(start, end)) {
cornerstoneTools.removeToolState(element, toolType, measurementData);
return true;
}
return false;
};
@@ -0,0 +1,31 @@
import { Meteor } from 'meteor/meteor';
import { Router } from 'meteor/clinical:router';
import { OHIF } from 'meteor/ohif:core';
Meteor.startup(function() {
if (!OHIF.studylist) return;
OHIF.studylist.callbacks.dblClickOnStudy = dblClickOnStudy;
OHIF.studylist.callbacks.middleClickOnStudy = dblClickOnStudy;
OHIF.studylist.timepointApi = new OHIF.measurements.TimepointApi();
});
/**
* Lesion Tracker method including Timepoints / other studies
*/
const dblClickOnStudy = data => {
// Find the relevant timepoint given the clicked-on study
const timepointApi = OHIF.studylist.timepointApi;
if (!timepointApi) {
OHIF.log.warn('No timepoint api on dbl-clicked study?');
return;
}
const timepoint = timepointApi.study(data.studyInstanceUid)[0];
if (timepoint) {
Router.go('viewerTimepoint', { timepointId: timepoint.timepointId });
} else {
Router.go('viewerStudies', { studyInstanceUids: data.studyInstanceUid });
}
};
@@ -0,0 +1,83 @@
import { OHIF } from 'meteor/ohif:core';
import { Viewerbase } from 'meteor/ohif:viewerbase';
/**
* Show / hide lesion tracker tools
*/
let previousStates;
let previousActiveTool;
let toolsShown = true;
OHIF.lesiontracker.toggleLesionTrackerTools = () => {
const toolManager = Viewerbase.toolManager;
if (toolsShown === true) {
// Save the current settings for later
previousStates = toolManager.getToolDefaultStates();
previousActiveTool = toolManager.getActiveTool();
// Hide the tools (set them all to disabled)
const toolDefaultStates = {
activate: ['deleteLesionKeyboardTool'],
deactivate: [],
enable: [],
disable: ['bidirectional', 'nonTarget', 'length', 'targetCR', 'targetUN']
};
toolManager.setToolDefaultStates(toolDefaultStates);
// Using setActiveTool with no arguments activates the
// default tool on all available viewports
toolManager.setActiveTool();
toolsShown = false;
} else {
// Show the tools (reload previous states)
toolManager.setToolDefaultStates(previousStates);
// Using setActiveTool with no elements specified activates
// the specified tool on all available viewports
toolManager.setActiveTool(previousActiveTool);
toolsShown = true;
}
};
OHIF.lesiontracker.toggleLesionTrackerToolsButtons = (isEnabled) => {
const toolManager = Viewerbase.toolManager;
const toolStates = previousStates || toolManager.getToolDefaultStates();
if (isEnabled) {
toolStates.disabledToolButtons = [];
OHIF.lesiontracker.toggleLesionTrackerToolsHotKeys(true);
} else {
toolStates.disabledToolButtons = ['bidirectional', 'nonTarget', 'targetCR', 'targetUN',
'toggleHUD', 'toggleTrial', 'toolbarSectionEntry', 'toggleMeasurements'];
OHIF.lesiontracker.toggleLesionTrackerToolsHotKeys(false);
}
// Reload the updated previous or default states
toolManager.setToolDefaultStates(toolStates);
// Reset the active tool if disabled
if (!isEnabled) {
toolManager.setActiveTool();
}
};
OHIF.lesiontracker.toggleLesionTrackerToolsHotKeys = (isEnabled) => {
// The hotkey can also be an array (e.g. ["NUMPAD0", "0"])
OHIF.viewer.defaultHotkeys = OHIF.viewer.defaultHotkeys || {};
if (isEnabled) {
OHIF.viewer.defaultHotkeys.toggleLesionTrackerTools = 'O';
OHIF.viewer.defaultHotkeys.bidirectional = 'T'; // Target
OHIF.viewer.defaultHotkeys.nonTarget = 'N'; // Non-target
} else {
OHIF.viewer.defaultHotkeys.toggleLesionTrackerTools = null;
OHIF.viewer.defaultHotkeys.bidirectional = null; // Target
OHIF.viewer.defaultHotkeys.nonTarget = null; // Non-target
}
};