PWV-138: Switching selected handle from circle to highlighted line

This commit is contained in:
Bruno Alves de Faria 2017-09-14 17:42:21 -03:00
parent 8c6a72cc0f
commit 45d660636b
6 changed files with 164 additions and 12 deletions

View File

@ -702,6 +702,42 @@ function handleActivator(element, handles, canvasPoint, distanceThreshold=6) {
return handleActivatorChanged;
}
// Draw a line marker over the selected arm
function drawSelectedMarker(eventData, handles, color) {
const lib = OHIF.lesiontracker.bidirectional;
const { canvasContext, element, enabledElement } = eventData;
const handleKey = lib.getSelectedHandleKey(handles);
if (!handleKey) return;
const handle = handles[handleKey];
// Used a big distance (1km) to fill the entire line
const mmStep = -1000000;
// Get the line's start and end points
const fakeImage = {
columnPixelSpacing: eventData.viewport.scale,
rowPixelSpacing: eventData.viewport.scale
};
const pointA = lib.repositionBidirectionalArmHandle(fakeImage, handles, handleKey, mmStep, 0);
const pointB = _.pick(handle, ['x', 'y']);
// Stop here if pointA is not present
if (!pointA) return;
// Get the canvas coordinates for the line var perpendicularStartCanvas = cornerstone.pixelToCanvas(element, data.handles.perpendicularStart);
const canvasPointA = cornerstone.pixelToCanvas(element, pointA);
const canvasPointB = cornerstone.pixelToCanvas(element, pointB);
// Draw the line marker
canvasContext.beginPath();
canvasContext.strokeStyle = color;
canvasContext.lineWidth = cornerstoneTools.toolStyle.getToolWidth();
canvasContext.moveTo(canvasPointA.x, canvasPointA.y);
canvasContext.lineTo(canvasPointB.x, canvasPointB.y);
canvasContext.stroke();
}
// Add a proxy to cornerstoneTools.drawHandles function to change the handles' active state base on
// the hover, moving and selected states
function drawHandles(context, eventData, handles, color, options) {
@ -710,7 +746,7 @@ function drawHandles(context, eventData, handles, color, options) {
const handle = handles[handleKey];
handle.drawnIndependently = handle.moving;
if (handle.selected) {
handle.active = true;
handle.active = handle.hover;
} else {
if (handle.hover) {
handle.active = true;
@ -1080,28 +1116,23 @@ function onImageRendered(e, eventData) {
var handleEndCanvas = cornerstone.pixelToCanvas(element, data.handles.end);
var canvasTextLocation = cornerstone.pixelToCanvas(element, data.handles.textBox);
let lineColor;
if (!data.active && (data.handles.start.selected || data.handles.end.selected)) {
lineColor = activeColor;
}
context.beginPath();
context.strokeStyle = lineColor || color;
context.strokeStyle = color;
context.lineWidth = strokeWidth;
context.moveTo(handleStartCanvas.x, handleStartCanvas.y);
context.lineTo(handleEndCanvas.x, handleEndCanvas.y);
context.stroke();
// Draw perpendicular line
let perpendicularColor;
if (!data.active && (data.handles.perpendicularStart.selected || data.handles.perpendicularEnd.selected)) {
perpendicularColor = activeColor;
}
drawPerpendicularLine(context, eventData, element, data, perpendicularColor || color, strokeWidth);
drawPerpendicularLine(context, eventData, element, data, color, strokeWidth);
// Draw the handles
const handlesColor = lineColor || perpendicularColor || color;
const handlesColor = color;
drawHandles(context, eventData, data.handles, handlesColor, { drawHandlesIfActive: true });
// Draw the selected marker
drawSelectedMarker(eventData, data.handles, '#FF9999');
// Calculate the long axis length
var dx = (data.handles.start.x - data.handles.end.x) * (eventData.image.columnPixelSpacing || 1);
var dy = (data.handles.start.y - data.handles.end.y) * (eventData.image.rowPixelSpacing || 1);

View File

@ -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)
};
}

View File

@ -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;
}

View File

@ -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
};

View File

@ -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;
}

View File

@ -1,6 +1,9 @@
// StudyList-related functions
import './studylist/studylistModification.js';
// Bidirectional tool utility functions
import './bidirectional';
// Library functions
import './TrialCriteriaConstraints.js';
import './MeasurementValidation.js';