Skip to content

Commit

Permalink
Merge pull request #882 from cornerstonejs/fix-bidirectional-sync
Browse files Browse the repository at this point in the history
feat(BidirectionalTool): Update tool data on every modified event of …
  • Loading branch information
dannyrb authored Mar 14, 2019
2 parents 663c3c9 + f620ed0 commit 7c38bec
Show file tree
Hide file tree
Showing 26 changed files with 200 additions and 59 deletions.
20 changes: 10 additions & 10 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: 2
defaults: &defaults
working_directory: ~/repo
docker:
- image: circleci/node:latest
- image: circleci/node:10.0.0

jobs:
##################
Expand All @@ -15,15 +15,15 @@ jobs:
- checkout
- attach_workspace:
at: ~/repo
- restore_cache:
keys:
- v1-dependencies-{{ checksum "package.json" }}
- v1-dependencies-
- run: npm install
- save_cache:
paths:
- node_modules
key: v1-dependencies-{{ checksum "package.json" }}
# - restore_cache:
# keys:
# - v1-dependencies-{{ checksum "package.json" }}
# - v1-dependencies-
# - run: npm install
# - save_cache:
# paths:
# - node_modules
# key: v1-dependencies-{{ checksum "package.json" }}
- persist_to_workspace:
root: ~/repo
paths: .
Expand Down
8 changes: 4 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
name="viewport"
content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"
/>
<link rel="stylesheet" href="examples/reset.css" />
<link rel="stylesheet" href="examples/app.css" />
<link rel="stylesheet" href="examples/icon-classes.css" />
<link rel="stylesheet" href="netlify-example/reset.css" />
<link rel="stylesheet" href="netlify-example/app.css" />
<link rel="stylesheet" href="netlify-example/icon-classes.css" />
<style>
/**
* ~~ MagnifyTool:
Expand Down Expand Up @@ -175,7 +175,7 @@
</script>

<!-- include special code for these examples which provides images -->
<script src="examples/imageLoader.js"></script>
<script src="netlify-example/imageLoader.js"></script>

<script>
cornerstoneTools.init();
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
25 changes: 15 additions & 10 deletions src/tools/annotation/bidirectionalTool/addNewMeasurement.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import external from './../../../externalModules.js';
import EVENTS from './../../../events.js';
import { moveNewHandle } from './../../../manipulators/index.js';
import anyHandlesOutsideImage from './../../../manipulators/anyHandlesOutsideImage.js';
import calculateLongestAndShortestDiameters from './utils/calculateLongestAndShortestDiameters.js';
import {
addToolState,
removeToolState,
Expand All @@ -21,16 +22,6 @@ export default function(evt, interactionType) {
const doneCallback = () => {
measurementData.active = false;
external.cornerstone.updateImage(element);

// Trigger measurement modified event
const eventType = EVENTS.MEASUREMENT_MODIFIED;
const modifiedEventData = {
toolName: this.name,
element,
measurementData,
};

external.cornerstone.triggerEvent(element, eventType, modifiedEventData);
};

// Associate this data with this imageId so we can render it and manipulate it
Expand Down Expand Up @@ -71,6 +62,20 @@ export default function(evt, interactionType) {
perpendicularStart.locked = false;

external.cornerstone.updateImage(element);

const modifiedEventData = {
toolType: this.name,
element,
measurementData,
};

calculateLongestAndShortestDiameters(eventData, measurementData);

external.cornerstone.triggerEvent(
element,
EVENTS.MEASUREMENT_MODIFIED,
modifiedEventData
);
},
},
interactionType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import external from './../../../../externalModules.js';
import { state } from '../../../../store/index.js';
import EVENTS from './../../../../events.js';
import setHandlesPosition from './setHandlesPosition.js';
import calculateLongestAndShortestDiameters from '../utils/calculateLongestAndShortestDiameters.js';

export default function(
mouseEventData,
Expand Down Expand Up @@ -45,6 +46,8 @@ export default function(
measurementData: data,
};

calculateLongestAndShortestDiameters(mouseEventData, data);

external.cornerstone.triggerEvent(
element,
EVENTS.MEASUREMENT_MODIFIED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import external from './../../../../externalModules.js';
import { state } from '../../../../store/index.js';
import EVENTS from './../../../../events.js';
import setHandlesPosition from './setHandlesPosition.js';
import calculateLongestAndShortestDiameters from '../utils/calculateLongestAndShortestDiameters.js';

const touchEndEvents = [
EVENTS.TOUCH_END,
Expand Down Expand Up @@ -47,14 +48,19 @@ export default function(

external.cornerstone.updateImage(element);

const eventType = EVENTS.MEASUREMENT_MODIFIED;
const modifiedEventData = {
toolType,
element,
measurementData: data,
};

external.cornerstone.triggerEvent(element, eventType, modifiedEventData);
calculateLongestAndShortestDiameters(mouseEventData, data);

external.cornerstone.triggerEvent(
element,
EVENTS.MEASUREMENT_MODIFIED,
modifiedEventData
);
};

handle.active = true;
Expand Down
35 changes: 2 additions & 33 deletions src/tools/annotation/bidirectionalTool/renderToolData.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import external from './../../../externalModules.js';
import drawHandles from './../../../drawing/drawHandles.js';
import updatePerpendicularLineHandles from './utils/updatePerpendicularLineHandles.js';
import calculateLongestAndShortestDiameters from './utils/calculateLongestAndShortestDiameters.js';

import toolStyle from './../../../stateManagement/toolStyle.js';
import toolColors from './../../../stateManagement/toolColors.js';
Expand Down Expand Up @@ -63,7 +64,7 @@ export default function(evt) {
color = data.active ? activeColor : toolColors.getToolColor();

// Calculate the data measurements
getMeasurementData(data, rowPixelSpacing, colPixelSpacing);
calculateLongestAndShortestDiameters(eventData, data);

draw(context, context => {
// Configurable shadow
Expand Down Expand Up @@ -127,38 +128,6 @@ export default function(evt) {
}
}

const getMeasurementData = (data, rowPixelSpacing, colPixelSpacing) => {
const { start, end, perpendicularStart, perpendicularEnd } = data.handles;
// Calculate the long axis length
const dx = (start.x - end.x) * (colPixelSpacing || 1);
const dy = (start.y - end.y) * (rowPixelSpacing || 1);
let length = Math.sqrt(dx * dx + dy * dy);

// Calculate the short axis length
const wx =
(perpendicularStart.x - perpendicularEnd.x) * (colPixelSpacing || 1);
const wy =
(perpendicularStart.y - perpendicularEnd.y) * (rowPixelSpacing || 1);
let width = Math.sqrt(wx * wx + wy * wy);

if (!width) {
width = 0;
}

// Length is always longer than width
if (width > length) {
const tempW = width;
const tempL = length;

length = tempW;
width = tempL;
}

// Set measurement values to be use externaly
data.longestDiameter = length.toFixed(1);
data.shortestDiameter = width.toFixed(1);
};

const getTextBoxText = (data, rowPixelSpacing, colPixelSpacing) => {
let suffix = ' mm';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Calculates longest and shortest diameters using measurement handles and pixelSpacing
* @param {Object} eventData
* @param {Object} measurementData
* @returns {void}
*/
export default function calculateLongestAndShortestDiameters(
eventData,
measurementData
) {
const { rowPixelSpacing, columnPixelSpacing } = eventData.image;
const {
start,
end,
perpendicularStart,
perpendicularEnd,
} = measurementData.handles;

// Calculate the long axis length
const dx = (start.x - end.x) * (columnPixelSpacing || 1);
const dy = (start.y - end.y) * (rowPixelSpacing || 1);
let length = Math.sqrt(dx * dx + dy * dy);

// Calculate the short axis length
const wx =
(perpendicularStart.x - perpendicularEnd.x) * (columnPixelSpacing || 1);
const wy =
(perpendicularStart.y - perpendicularEnd.y) * (rowPixelSpacing || 1);
let width = Math.sqrt(wx * wx + wy * wy);

if (!width) {
width = 0;
}

// Length is always longer than width
if (width > length) {
const tempW = width;
const tempL = length;

length = tempW;
width = tempL;
}

// Set measurement text to show lesion table
measurementData.longestDiameter = length.toFixed(1);
measurementData.shortestDiameter = width.toFixed(1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import calculateLongestAndShortestDiameters from './calculateLongestAndShortestDiameters.js';

let measurementData = {};
let eventData = {};

describe('CalculateLongestAndShortestDiameters.js', () => {
beforeEach(() => {
console.error = jest.fn();
console.error.mockClear();
console.warn = jest.fn();
console.warn.mockClear();

measurementData = {
handles: {
start: {
x: 290.6229508196721,
y: 272.7868852459016,
},
end: {
x: 361.96721311475403,
y: 191.99999999999997,
},
perpendicularStart: {
x: 346.49180327868845,
y: 250.22950819672127,
},
perpendicularEnd: {
x: 306.0983606557376,
y: 214.55737704918027,
},
},
};
eventData = {
image: {},
};
});

it('should calculates long/short diameters', () => {
eventData = {
image: {
rowPixelSpacing: 0.876953125,
columnPixelSpacing: 0.876953125,
},
};

calculateLongestAndShortestDiameters(eventData, measurementData);

expect(measurementData.longestDiameter).toEqual('94.5');
expect(measurementData.shortestDiameter).toEqual('47.3');
});

it('should return values with scale of 1', () => {
calculateLongestAndShortestDiameters(eventData, measurementData);

expect(measurementData.shortestDiameter).toMatch(/\d*\.\d$/);
expect(measurementData.longestDiameter).toMatch(/\d*\.\d$/);
});

it('should use a default pixelSpacing of 1 when pixelSpacing is undefined', () => {
calculateLongestAndShortestDiameters(eventData, measurementData);

expect(measurementData.longestDiameter).toEqual('107.8');
expect(measurementData.shortestDiameter).toEqual('53.9');
});

it('should get longest and shortest diameters defined even with undefined handles', () => {
measurementData.handles = {
start: {
x: 0,
y: 0,
},
end: {
x: 4,
y: 4,
},
perpendicularStart: {},
perpendicularEnd: {},
};

calculateLongestAndShortestDiameters(eventData, measurementData);

expect(measurementData.shortestDiameter).toEqual('0.0');
expect(measurementData.longestDiameter).toEqual('5.7');
});

it('should make shortestDiameter always small than longestDiameter', () => {
measurementData.handles = {
start: {
x: 10,
y: 10,
},
end: {
x: 5,
y: 5,
},
perpendicularStart: {
x: 12,
y: 12,
},
perpendicularEnd: {
x: 5,
y: 5,
},
};

calculateLongestAndShortestDiameters(eventData, measurementData);

expect(measurementData.shortestDiameter).toEqual('7.1');
expect(measurementData.longestDiameter).toEqual('9.9');
});
});

0 comments on commit 7c38bec

Please sign in to comment.