Skip to content

Commit

Permalink
feat: Brush on mouse move (#20)
Browse files Browse the repository at this point in the history
* Brush on move

* Update API

* circle ci xlarge resource

Co-authored-by: Alireza <ar.sedghi@gmail.com>
  • Loading branch information
JamesAPetts and sedghi authored Mar 28, 2022
1 parent 4e7f77e commit 4a08cce
Show file tree
Hide file tree
Showing 9 changed files with 429 additions and 267 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ jobs:

BUILD_DOCS:
<<: *defaults
resource_class: large
resource_class: xlarge
steps:
- attach_workspace:
at: ~/repo
Expand Down
18 changes: 10 additions & 8 deletions common/reviews/api/tools.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export abstract class AnnotationTool extends BaseTool {
// (undocumented)
abstract isPointNearTool(element: HTMLElement, annotation: Annotation, canvasCoords: Types_2.Point2, proximity: number, interactionType: string): boolean;
// (undocumented)
mouseMoveCallback: (evt: EventTypes_2.MouseMoveEventType, filteredAnnotations: Annotations) => boolean;
mouseMoveCallback: (evt: EventTypes_2.MouseMoveEventType, filteredAnnotations?: Annotations) => boolean;
// (undocumented)
onImageSpacingCalibrated: (evt: Types_2.EventTypes.ImageSpacingCalibratedEvent) => void;
// (undocumented)
Expand Down Expand Up @@ -307,7 +307,9 @@ export class BidirectionalTool extends AnnotationTool {
export class BrushTool extends BaseTool {
constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
// (undocumented)
addNewAnnotation: (evt: EventTypes_2.MouseDownActivateEventType) => void;
mouseMoveCallback: (evt: EventTypes_2.MouseDragEventType) => void;
// (undocumented)
preMouseDownCallback: (evt: EventTypes_2.MouseDownActivateEventType) => boolean;
// (undocumented)
renderAnnotation(enabledElement: Types_2.IEnabledElement, svgDrawingHelper: any): void;
// (undocumented)
Expand Down Expand Up @@ -341,8 +343,6 @@ export class CircleScissorsTool extends BaseTool {
// (undocumented)
_activateDraw: (element: any) => void;
// (undocumented)
addNewAnnotation: (evt: EventTypes_2.MouseDownActivateEventType) => void;
// (undocumented)
_deactivateDraw: (element: any) => void;
// (undocumented)
editData: {
Expand All @@ -368,6 +368,8 @@ export class CircleScissorsTool extends BaseTool {
// (undocumented)
_mouseUpCallback: (evt: EventTypes_2.MouseUpEventType | EventTypes_2.MouseClickEventType) => void;
// (undocumented)
preMouseDownCallback: (evt: EventTypes_2.MouseDownActivateEventType) => boolean;
// (undocumented)
renderAnnotation: (enabledElement: Types_2.IEnabledElement, svgDrawingHelper: any) => void;
// (undocumented)
static toolName: string;
Expand Down Expand Up @@ -2558,8 +2560,6 @@ export class RectangleScissorsTool extends BaseTool {
// (undocumented)
_activateDraw: (element: any) => void;
// (undocumented)
addNewAnnotation: (evt: EventTypes_2.MouseDownActivateEventType) => void;
// (undocumented)
_deactivateDraw: (element: any) => void;
// (undocumented)
editData: {
Expand All @@ -2584,6 +2584,8 @@ export class RectangleScissorsTool extends BaseTool {
// (undocumented)
_mouseUpCallback: (evt: EventTypes_2.MouseUpEventType | EventTypes_2.MouseClickEventType) => void;
// (undocumented)
preMouseDownCallback: (evt: EventTypes_2.MouseDownActivateEventType) => boolean;
// (undocumented)
renderAnnotation: (enabledElement: Types_2.IEnabledElement, svgDrawingHelper: any) => void;
// (undocumented)
_throttledCalculateCachedStats: any;
Expand Down Expand Up @@ -2892,8 +2894,6 @@ export class SphereScissorsTool extends BaseTool {
// (undocumented)
_activateDraw: (element: any) => void;
// (undocumented)
addNewAnnotation: (evt: EventTypes_2.MouseDownActivateEventType) => void;
// (undocumented)
_deactivateDraw: (element: any) => void;
// (undocumented)
editData: {
Expand All @@ -2920,6 +2920,8 @@ export class SphereScissorsTool extends BaseTool {
// (undocumented)
_mouseUpCallback: (evt: EventTypes_2.MouseUpEventType | EventTypes_2.MouseClickEventType) => void;
// (undocumented)
preMouseDownCallback: (evt: EventTypes_2.MouseDownActivateEventType) => true;
// (undocumented)
renderAnnotation: (enabledElement: Types_2.IEnabledElement, svgDrawingHelper: any) => void;
// (undocumented)
static toolName: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ export default function mouseMove(evt: MouseMoveEventType) {
activeAndPassiveTools
)

const toolsWithoutAnnotations = activeAndPassiveTools.filter((tool) => {
const doesNotHaveAnnotations = !toolsWithAnnotations.some(
(toolAndAnnotation) =>
toolAndAnnotation.tool.getToolName() === tool.getToolName()
)

return doesNotHaveAnnotations
})

let annotationsNeedToBeRedrawn = false

for (const { tool, annotations } of toolsWithAnnotations) {
Expand All @@ -47,6 +56,13 @@ export default function mouseMove(evt: MouseMoveEventType) {
}
}

// Run mouse move handlers for non-annotation tools
toolsWithoutAnnotations.forEach((tool) => {
if (typeof tool.mouseMoveCallback === 'function') {
tool.mouseMoveCallback(evt)
}
})

// Annotation activation status changed, redraw the annotations
if (annotationsNeedToBeRedrawn === true) {
triggerAnnotationRender(element)
Expand Down
6 changes: 5 additions & 1 deletion packages/tools/src/tools/base/AnnotationTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,12 @@ abstract class AnnotationTool extends BaseTool {
*/
public mouseMoveCallback = (
evt: EventTypes.MouseMoveEventType,
filteredAnnotations: Annotations
filteredAnnotations?: Annotations
): boolean => {
if (!filteredAnnotations) {
return false
}

const { element, currentPoints } = evt.detail
const canvasCoords = currentPoints.canvas
let annotationsNeedToBeRedrawn = false
Expand Down
163 changes: 143 additions & 20 deletions packages/tools/src/tools/segmentation/BrushTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
export default class BrushTool extends BaseTool {
static toolName = 'Brush'
private _editData: {
toolData: any
brushCursor: any
segmentation: any
segmentationId: string
segmentIndex: number
Expand All @@ -37,6 +37,15 @@ export default class BrushTool extends BaseTool {
viewportIdsToRender: string[]
centerCanvas?: Array<number>
} | null
private _hoverData: {
brushCursor: any
segmentationId: string
segmentIndex: number
segmentationRepresentationUID: string
segmentColor: [number, number, number, number]
viewportIdsToRender: string[]
centerCanvas?: Array<number>
}
private _isDrawing: boolean

constructor(
Expand All @@ -57,7 +66,9 @@ export default class BrushTool extends BaseTool {
super(toolProps, defaultToolProps)
}

addNewAnnotation = (evt: EventTypes.MouseDownActivateEventType): void => {
preMouseDownCallback = (
evt: EventTypes.MouseDownActivateEventType
): boolean => {
const eventData = evt.detail
const { currentPoints, element } = eventData
const worldPos = currentPoints.world
Expand Down Expand Up @@ -100,7 +111,7 @@ export default class BrushTool extends BaseTool {
const segmentation = cache.getVolume(volumeId)

// Todo: Used for drawing the svg only, we might not need it at all
const toolData = {
const brushCursor = {
metadata: {
viewPlaneNormal: <Types.Point3>[...viewPlaneNormal],
viewUp: <Types.Point3>[...viewUp],
Expand All @@ -121,7 +132,7 @@ export default class BrushTool extends BaseTool {
const viewportIdsToRender = [viewport.id]

this._editData = {
toolData,
brushCursor,
segmentation,
centerCanvas: canvasPos,
segmentIndex,
Expand All @@ -139,6 +150,105 @@ export default class BrushTool extends BaseTool {
evt.preventDefault()

triggerAnnotationRenderForViewportUIDs(renderingEngine, viewportIdsToRender)

return true
}

mouseMoveCallback = (evt: EventTypes.MouseDragEventType): void => {
debugger
const brushSize = this.configuration.brushSize
const eventData = evt.detail
const { element } = eventData
const { currentPoints } = eventData
const canvasPos = currentPoints.canvas
const worldPos = currentPoints.world
const enabledElement = getEnabledElement(element)
const { renderingEngine, viewport } = enabledElement
const { canvasToWorld } = viewport

const camera = viewport.getCamera()
const { viewPlaneNormal, viewUp } = camera

const toolGroupId = this.toolGroupId

const activeSegmentationRepresentation =
activeSegmentation.getActiveSegmentationRepresentation(toolGroupId)
if (!activeSegmentationRepresentation) {
throw new Error(
'No active segmentation detected, create one before using the brush tool'
)
}

const { segmentationRepresentationUID, segmentationId, type } =
activeSegmentationRepresentation
const segmentIndex =
segmentIndexController.getActiveSegmentIndex(toolGroupId)

const segmentColor = segmentationColor.getColorForSegmentIndex(
toolGroupId,
segmentationRepresentationUID,
segmentIndex
)

const viewportIdsToRender = [viewport.id]
const brushCursor = {
metadata: {
viewPlaneNormal: <Types.Point3>[...viewPlaneNormal],
viewUp: <Types.Point3>[...viewUp],
FrameOfReferenceUID: viewport.getFrameOfReferenceUID(),
referencedImageId: '',
toolName: BrushTool.toolName,
segmentColor,
},
data: {
invalidated: true,
handles: {
points: [[...worldPos], [...worldPos], [...worldPos], [...worldPos]],
},
cachedStats: {},
},
}

//////
const { data } = brushCursor

const centerCanvas = canvasPos

// Center of circle in canvas Coordinates

const radius = brushSize

const bottomCanvas: Types.Point2 = [
centerCanvas[0],
centerCanvas[1] + radius,
]
const topCanvas: Types.Point2 = [centerCanvas[0], centerCanvas[1] - radius]
const leftCanvas: Types.Point2 = [centerCanvas[0] - radius, centerCanvas[1]]
const rightCanvas: Types.Point2 = [
centerCanvas[0] + radius,
centerCanvas[1],
]

data.handles.points = [
canvasToWorld(bottomCanvas),
canvasToWorld(topCanvas),
canvasToWorld(leftCanvas),
canvasToWorld(rightCanvas),
]

data.invalidated = true

this._hoverData = {
brushCursor,
centerCanvas,
segmentIndex,
segmentationId,
segmentationRepresentationUID,
segmentColor,
viewportIdsToRender,
}

triggerAnnotationRenderForViewportUIDs(renderingEngine, viewportIdsToRender)
}

private _mouseDragCallback = (evt: EventTypes.MouseDragEventType): void => {
Expand All @@ -159,11 +269,11 @@ export default class BrushTool extends BaseTool {
segmentsLocked,
segmentationId,
segmentationRepresentationUID,
toolData,
brushCursor,
viewportIdsToRender,
} = this._editData
const { viewPlaneNormal, viewUp } = toolData.metadata
const { data } = toolData
const { viewPlaneNormal, viewUp } = brushCursor.metadata
const { data } = brushCursor

const centerCanvas = currentCanvasPoints

Expand Down Expand Up @@ -213,15 +323,15 @@ export default class BrushTool extends BaseTool {
const { element } = eventData

const {
toolData,
brushCursor,
segmentation,
segmentIndex,
segmentsLocked,
segmentationId,
segmentationRepresentationUID,
} = this._editData
const { data } = toolData
const { viewPlaneNormal, viewUp } = toolData.metadata
const { data } = brushCursor
const { viewPlaneNormal, viewUp } = brushCursor.metadata

this._deactivateDraw(element)

Expand Down Expand Up @@ -280,24 +390,37 @@ export default class BrushTool extends BaseTool {
enabledElement: Types.IEnabledElement,
svgDrawingHelper: any
): void {
if (!this._editData) {
if (!this._editData && !this._hoverData) {
return
}

const { viewport } = enabledElement
const { viewportIdsToRender } = this._editData

if (!viewportIdsToRender.includes(viewport.id)) {
return
}
let viewportIdsToRender
let brushCursor

if (this._isDrawing) {
viewportIdsToRender = this._editData.viewportIdsToRender

const { toolData } = this._editData
if (!viewportIdsToRender.includes(viewport.id)) {
return
}

brushCursor = this._editData.brushCursor
} else {
viewportIdsToRender = this._hoverData.viewportIdsToRender

if (!viewportIdsToRender.includes(viewport.id)) {
return
}

brushCursor = this._hoverData.brushCursor
}

// Todo: rectangle colro based on segment index
const toolMetadata = toolData.metadata
const annotationUID = toolMetadata.toolDataUID
const toolMetadata = brushCursor.metadata
const annotationUID = toolMetadata.brushCursorUID

const data = toolData.data
const data = brushCursor.data
const { points } = data.handles
const canvasCoordinates = points.map((p) => viewport.worldToCanvas(p))

Expand Down
6 changes: 5 additions & 1 deletion packages/tools/src/tools/segmentation/CircleScissorsTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ export default class CircleScissorsTool extends BaseTool {
* @returns The annotation object.
*
*/
addNewAnnotation = (evt: EventTypes.MouseDownActivateEventType) => {
preMouseDownCallback = (
evt: EventTypes.MouseDownActivateEventType
): boolean => {
const eventDetail = evt.detail
const { currentPoints, element } = eventDetail
const worldPos = currentPoints.world
Expand Down Expand Up @@ -159,6 +161,8 @@ export default class CircleScissorsTool extends BaseTool {
evt.preventDefault()

triggerAnnotationRenderForViewportIds(renderingEngine, viewportIdsToRender)

return true
}

_mouseDragCallback = (evt: EventTypes.MouseDragEventType) => {
Expand Down
Loading

0 comments on commit 4a08cce

Please sign in to comment.