PWV-138: Switching selected handle from circle to highlighted line
This commit is contained in:
parent
8c6a72cc0f
commit
45d660636b
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user