From c9d799b98971ad6efc60b893dd252578a7bbaec6 Mon Sep 17 00:00:00 2001 From: James Petts Date: Wed, 13 Feb 2019 12:10:02 +0000 Subject: [PATCH 1/3] perf(BrushTool, onNewImageBrushEventHandler, onImageRenderedBrushEventHandler): Only generate labelm Now labelmaps are only added to the slice as they are created. If you try to erase a labelmap that doesn't exist it now doesn't insert a blank one. This improves performance when stack scrolling through a new set of images, as the memory for the labelmaps is now only allocated when you begin drawing. re #834 --- .../onImageRenderedBrushEventHandler.js | 21 +---- .../onNewImageBrushEventHandler.js | 20 +--- src/tools/base/BaseBrushTool.js | 11 +-- src/tools/brush/BrushTool.js | 93 ++++++++----------- 4 files changed, 48 insertions(+), 97 deletions(-) diff --git a/src/eventListeners/onImageRenderedBrushEventHandler.js b/src/eventListeners/onImageRenderedBrushEventHandler.js index e0bdc0489..e24008855 100644 --- a/src/eventListeners/onImageRenderedBrushEventHandler.js +++ b/src/eventListeners/onImageRenderedBrushEventHandler.js @@ -61,28 +61,15 @@ export default function(evt) { const eventData = evt.detail; const element = eventData.element; const maxSegmentations = BaseBrushTool.getNumberOfColors(); - let toolData = getToolState( + const activeSegIndex = store.modules.brush.state.drawColorId; + + const toolData = getToolState( element, BaseBrushTool.getReferencedToolDataName() ); if (!toolData) { - // Make toolData array as big as max number of segmentations. - for (let i = 0; i < maxSegmentations; i++) { - addToolState(element, BaseBrushTool.getReferencedToolDataName(), {}); - } - - toolData = getToolState(element, BaseBrushTool.getReferencedToolDataName()); - - // TEMP: HACK: Create first pixel data such that the tool has some data and the brush - // Cursor can be rendered. Can be replaced once we have a mechanism for SVG cursors. - const newPixelData = new Uint8ClampedArray( - eventData.image.width * eventData.image.height - ); - - toolData.data[0].pixelData = newPixelData; - - toolData = getToolState(element, BaseBrushTool.getReferencedToolDataName()); + return; } const enabledElement = external.cornerstone.getEnabledElement(element); diff --git a/src/eventListeners/onNewImageBrushEventHandler.js b/src/eventListeners/onNewImageBrushEventHandler.js index 9ba5aa079..5c41fdc7f 100644 --- a/src/eventListeners/onNewImageBrushEventHandler.js +++ b/src/eventListeners/onNewImageBrushEventHandler.js @@ -14,31 +14,17 @@ const { setters } = store.modules.brush; export default function(evt) { const eventData = evt.detail; const element = eventData.element; + const activeSegIndex = store.modules.brush.state.drawColorId; let toolData = getToolState( element, BaseBrushTool.getReferencedToolDataName() ); if (!toolData) { - // Make toolData array as big as max number of segmentations. - const maxSegmentations = BaseBrushTool.getNumberOfColors(); - - for (let i = 0; i < maxSegmentations; i++) { - addToolState(element, BaseBrushTool.getReferencedToolDataName(), {}); - } - - toolData = getToolState(element, BaseBrushTool.getReferencedToolDataName()); - - // TEMP: HACK: Create first pixel data such that the tool has some data and the brush - // Cursor can be rendered. Can be replaced once we have a mechanism for SVG cursors. - const newPixelData = new Uint8ClampedArray( - eventData.image.width * eventData.image.height - ); - - toolData.data[0].pixelData = newPixelData; - + addToolState(element, BaseBrushTool.getReferencedToolDataName(), {}); toolData = getToolState(element, BaseBrushTool.getReferencedToolDataName()); } + const enabledElement = external.cornerstone.getEnabledElement(element); const maxSegmentations = BaseBrushTool.getNumberOfColors(); diff --git a/src/tools/base/BaseBrushTool.js b/src/tools/base/BaseBrushTool.js index 5a283ed1d..55fbad643 100644 --- a/src/tools/base/BaseBrushTool.js +++ b/src/tools/base/BaseBrushTool.js @@ -430,6 +430,7 @@ class BaseBrushTool extends BaseTool { * @returns {null} */ static invalidateBrushOnEnabledElement(enabledElementUID) { + /** WIP **/ const element = store.getters.enabledElementByUID(enabledElementUID); const stackToolState = getToolState(element, 'stack'); @@ -452,15 +453,6 @@ class BaseBrushTool extends BaseTool { const toolState = globalImageIdSpecificToolStateManager.saveToolState(); - // TODO -> Put this elsewhere - /* - const buffer = new ArrayBuffer(dim.xyz); - - const unit8View = new Uint8Array(buffer); - - console.log(unit8View.length); - */ - for (let i = 0; i < imageIds.length; i++) { const imageId = imageIds[i]; @@ -484,6 +476,7 @@ class BaseBrushTool extends BaseTool { * @return {type} description */ static getDataAsVolume(enabledElementUID) { + /** WIP **/ const element = store.getters.enabledElementByUID(enabledElementUID); const stackToolState = getToolState(element, 'stack'); diff --git a/src/tools/brush/BrushTool.js b/src/tools/brush/BrushTool.js index 7457bfbd7..fb57283f8 100644 --- a/src/tools/brush/BrushTool.js +++ b/src/tools/brush/BrushTool.js @@ -32,6 +32,8 @@ export default class BrushTool extends BaseBrushTool { super(initialConfiguration); this.initialConfiguration = initialConfiguration; + + console.log(this); } /** @@ -118,39 +120,17 @@ function _overlappingStrategy(evt, configuration) { const element = eventData.element; const { rows, columns } = eventData.image; const { x, y } = eventData.currentPoints.image; - const toolData = getToolState(element, configuration.referencedToolData); - - let shouldErase = false; - - // Check for key, could be a mouseDown or mouseDrag event. - if (_isCtrlDown(eventData)) { - console.log('ctrlDown'); - shouldErase = true; - } - - const segmentationIndex = state.drawColorId; - - if (!toolData.data[segmentationIndex].pixelData) { - const newPixelData = new Uint8ClampedArray( - eventData.image.width * eventData.image.height - ); - - toolData.data[segmentationIndex].pixelData = newPixelData; - } - - const pixelData = toolData.data[segmentationIndex].pixelData; - - const radius = state.radius; + const toolState = getToolState(element, configuration.referencedToolData); + const toolData = toolState.data; if (x < 0 || x > columns || y < 0 || y > rows) { return; } + const radius = state.radius; const pointerArray = getCircle(radius, rows, columns, x, y); - drawBrushPixels(pointerArray, pixelData, columns, shouldErase); - - toolData.data[segmentationIndex].invalidated = true; + _drawMainColor(eventData, toolData, pointerArray); } function _nonOverlappingStrategy(evt, configuration) { @@ -160,45 +140,20 @@ function _nonOverlappingStrategy(evt, configuration) { const { x, y } = eventData.currentPoints.image; const toolState = getToolState(element, configuration.referencedToolData); const toolData = toolState.data; - - let shouldErase = false; - - // Check for key, could be a mouseDown or mouseDrag event. - if (_isCtrlDown(eventData)) { - console.log('ctrlDown'); - shouldErase = true; - } - - const activeSegmentationIndex = state.drawColorId; - - if (!toolData[activeSegmentationIndex].pixelData) { - const newPixelData = new Uint8ClampedArray( - eventData.image.width * eventData.image.height - ); - - toolData[activeSegmentationIndex].pixelData = newPixelData; - } - - const pixelData = toolData[activeSegmentationIndex].pixelData; - - const radius = state.radius; + const segmentationIndex = state.drawColorId; if (x < 0 || x > columns || y < 0 || y > rows) { return; } + const radius = state.radius; const pointerArray = getCircle(radius, rows, columns, x, y); - // Draw / Erase the active color. - drawBrushPixels(pointerArray, pixelData, columns, shouldErase); - - toolData[activeSegmentationIndex].invalidated = true; - const numberOfColors = BaseBrushTool.getNumberOfColors(); // If there is brush data in this region for other colors, delete it. for (let i = 0; i < numberOfColors; i++) { - if (i === activeSegmentationIndex) { + if (i === segmentationIndex) { continue; } @@ -207,6 +162,36 @@ function _nonOverlappingStrategy(evt, configuration) { toolData[i].invalidated = true; } } + + _drawMainColor(eventData, toolData, pointerArray); +} + +function _drawMainColor(eventData, toolData, pointerArray) { + const shouldErase = _isCtrlDown(eventData); + const columns = eventData.image.columns; + const segmentationIndex = state.drawColorId; + + if (shouldErase && !toolData[segmentationIndex]) { + // Erase command, yet no data yet, just return. + return; + } + + if (!toolData[segmentationIndex]) { + toolData[segmentationIndex] = {}; + } + + if (!toolData[segmentationIndex].pixelData) { + toolData[segmentationIndex].pixelData = new Uint8ClampedArray( + eventData.image.width * eventData.image.height + ); + } + + const pixelData = toolData[segmentationIndex].pixelData; + + // Draw / Erase the active color. + drawBrushPixels(pointerArray, pixelData, columns, shouldErase); + + toolData[segmentationIndex].invalidated = true; } function _isCtrlDown(eventData) { From 556e8429d794de2f0ab95701c3ce6e1f4276599e Mon Sep 17 00:00:00 2001 From: James Petts Date: Wed, 13 Feb 2019 12:16:00 +0000 Subject: [PATCH 2/3] Removed unneeded console log. --- src/tools/brush/BrushTool.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tools/brush/BrushTool.js b/src/tools/brush/BrushTool.js index fb57283f8..0e973d7bf 100644 --- a/src/tools/brush/BrushTool.js +++ b/src/tools/brush/BrushTool.js @@ -32,8 +32,6 @@ export default class BrushTool extends BaseBrushTool { super(initialConfiguration); this.initialConfiguration = initialConfiguration; - - console.log(this); } /** From 1b2d6fdc631a5fb53a62dc918f03ffd87e7a2e56 Mon Sep 17 00:00:00 2001 From: James Petts Date: Wed, 13 Feb 2019 12:25:02 +0000 Subject: [PATCH 3/3] Fixed case where toolState doesn't exist at all. (examples/brush worked, but index.html didn't) --- src/tools/brush/BrushTool.js | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/tools/brush/BrushTool.js b/src/tools/brush/BrushTool.js index 0e973d7bf..2cc8083bc 100644 --- a/src/tools/brush/BrushTool.js +++ b/src/tools/brush/BrushTool.js @@ -1,6 +1,9 @@ import external from './../../externalModules.js'; import BaseBrushTool from './../base/BaseBrushTool.js'; -import { getToolState } from './../../stateManagement/toolState.js'; +import { + getToolState, + addToolState, +} from './../../stateManagement/toolState.js'; import store from './../../store/index.js'; import brushUtils from './../../util/brush/index.js'; import EVENTS from '../../events'; @@ -118,7 +121,19 @@ function _overlappingStrategy(evt, configuration) { const element = eventData.element; const { rows, columns } = eventData.image; const { x, y } = eventData.currentPoints.image; - const toolState = getToolState(element, configuration.referencedToolData); + let toolState = getToolState( + element, + BaseBrushTool.getReferencedToolDataName() + ); + + if (!toolState) { + addToolState(element, BaseBrushTool.getReferencedToolDataName(), {}); + toolState = getToolState( + element, + BaseBrushTool.getReferencedToolDataName() + ); + } + const toolData = toolState.data; if (x < 0 || x > columns || y < 0 || y > rows) { @@ -136,7 +151,20 @@ function _nonOverlappingStrategy(evt, configuration) { const element = eventData.element; const { rows, columns } = eventData.image; const { x, y } = eventData.currentPoints.image; - const toolState = getToolState(element, configuration.referencedToolData); + + let toolState = getToolState( + element, + BaseBrushTool.getReferencedToolDataName() + ); + + if (!toolState) { + addToolState(element, BaseBrushTool.getReferencedToolDataName(), {}); + toolState = getToolState( + element, + BaseBrushTool.getReferencedToolDataName() + ); + } + const toolData = toolState.data; const segmentationIndex = state.drawColorId;