Skip to content

Commit

Permalink
feat: Add CINE tool via playClip (#99)
Browse files Browse the repository at this point in the history
* feat: Add CINE tool via playClip

* apply review comments

* apply review comments

* fix api build

* update default value for loop
  • Loading branch information
sedghi authored May 12, 2022
1 parent cf7e308 commit 916d783
Show file tree
Hide file tree
Showing 10 changed files with 577 additions and 6 deletions.
74 changes: 72 additions & 2 deletions common/reviews/api/tools.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ function addSegmentations(segmentationInputArray: SegmentationPublicInput[]): vo
// @public (undocumented)
export function addTool(ToolClass: any): void;

// @public (undocumented)
function addToolState(element: HTMLDivElement, data: CINETypes.ToolData): void;

// @public (undocumented)
interface AngleAnnotation extends Annotation {
// (undocumented)
Expand Down Expand Up @@ -552,6 +555,23 @@ export function cancelActiveManipulations(element: HTMLDivElement): string | und
// @public (undocumented)
function checkAndDefineIsLockedProperty(annotation: Annotation): void;

declare namespace cine {
export {
playClip,
stopClip,
Events_2 as Events,
getToolState,
addToolState
}
}

declare namespace CINETypes {
export {
PlayClipOptions,
ToolData
}
}

// @public (undocumented)
export class CircleScissorsTool extends BaseTool {
constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
Expand Down Expand Up @@ -1375,6 +1395,14 @@ enum Events {
SEGMENTATION_REPRESENTATION_REMOVED = "CORNERSTONE_TOOLS_SEGMENTATION_REPRESENTATION_REMOVED"
}

// @public (undocumented)
enum Events_2 {
// (undocumented)
CLIP_STARTED = "CORNERSTONE_CINE_TOOL_STARTED",
// (undocumented)
CLIP_STOPPED = "CORNERSTONE_CINE_TOOL_STOPPED"
}

declare namespace EventTypes {
export {
CameraModifiedEventDetail,
Expand Down Expand Up @@ -1642,6 +1670,9 @@ function getToolGroupSpecificConfig_2(toolGroupId: string): SegmentationRepresen
// @public (undocumented)
function getToolGroupsWithSegmentation(segmentationId: string): string[];

// @public (undocumented)
function getToolState(element: HTMLDivElement): CINETypes.ToolData | undefined;

// @public (undocumented)
function getViewportIdsWithToolToRender(element: HTMLDivElement, toolName: string, requireSameOrientation?: boolean): string[];

Expand Down Expand Up @@ -2794,6 +2825,18 @@ export class PlanarFreehandROITool extends AnnotationTool {
// @public
type Plane = [number, number, number, number];

// @public (undocumented)
function playClip(element: HTMLDivElement, playClipOptions: CINETypes.PlayClipOptions): void;

// @public (undocumented)
type PlayClipOptions = {
framesPerSecond?: number;
frameTimeVector?: number[];
reverse?: boolean;
loop?: boolean;
frameTimeVectorSpeedMultiplier?: number;
};

// @public
type Point2 = [number, number];

Expand Down Expand Up @@ -3622,6 +3665,9 @@ declare namespace state_2 {
}
}

// @public (undocumented)
function stopClip(element: HTMLDivElement): void;

// @public (undocumented)
type StyleConfig = {
annotations?: {
Expand Down Expand Up @@ -3736,6 +3782,28 @@ function throttle(func: Function, wait?: number, options?: {
trailing?: boolean;
}): Function;

// @public (undocumented)
interface ToolData {
// (undocumented)
framesPerSecond: number;
// (undocumented)
frameTimeVector: number[] | undefined;
// (undocumented)
ignoreFrameTimeVector: boolean;
// (undocumented)
intervalId: number | undefined;
// (undocumented)
lastFrameTimeStamp: number | undefined;
// (undocumented)
loop: boolean;
// (undocumented)
reverse: boolean;
// (undocumented)
speed: number;
// (undocumented)
usingFrameTimeVector: boolean;
}

declare namespace ToolGroupManager {
export {
createToolGroup,
Expand Down Expand Up @@ -3897,7 +3965,8 @@ declare namespace Types {
LabelmapTypes,
SVGCursorDescriptor,
SVGPoint_2 as SVGPoint,
ScrollOptions_2 as ScrollOptions
ScrollOptions_2 as ScrollOptions,
CINETypes
}
}
export { Types }
Expand Down Expand Up @@ -3925,7 +3994,8 @@ declare namespace utilities {
pointInSurroundingSphereCallback,
getAnnotationNearPoint,
getAnnotationNearPointOnEnabledElement,
jumpToSlice
jumpToSlice,
cine
}
}
export { utilities }
Expand Down
179 changes: 179 additions & 0 deletions packages/tools/examples/CINETool/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import {
RenderingEngine,
Types,
Enums,
utilities as csUtils,
} from '@cornerstonejs/core';
import {
initDemo,
createImageIdsAndCacheMetaData,
setTitleAndDescription,
addButtonToToolbar,
addSliderToToolbar,
} from '../../../../utils/demo/helpers';
import * as cornerstoneTools from '@cornerstonejs/tools';

// This is for debugging purposes
console.warn(
'Click on index.ts to open source code for this example --------->'
);

const {
WindowLevelTool,
PanTool,
ZoomTool,
ToolGroupManager,
Enums: csToolsEnums,
utilities: csToolsUtilities,
} = cornerstoneTools;

const { ViewportType } = Enums;
const { MouseBindings } = csToolsEnums;

// ======== Set up page ======== //
setTitleAndDescription('CINE Tool', 'Show the usage of the CINE Tool.');

const content = document.getElementById('content');
const element = document.createElement('div');

// Disable right click context menu so we can have right click tools
element.oncontextmenu = (e) => e.preventDefault();

element.id = 'cornerstone-element';
element.style.width = '500px';
element.style.height = '500px';

content.appendChild(element);

const instructions = document.createElement('p');
instructions.innerText = `
- Click on Play Clip to start the CINE tool
- Click on Stop Clip to stop the CINE tool
- Drag the frame slider to change the frames per second rate
`;

content.append(instructions);
// ============================= //

const toolGroupId = 'STACK_TOOL_GROUP_ID';
let framesPerSecond = 24;

addButtonToToolbar({
title: 'Play Clip',
onClick: () => {
csToolsUtilities.cine.playClip(element, { framesPerSecond });
},
});

addButtonToToolbar({
title: 'Stop Clip',
onClick: () => {
csToolsUtilities.cine.stopClip(element);
},
});

addSliderToToolbar({
title: `Frame per second`,
range: [1, 100],
defaultValue: framesPerSecond,
onSelectedValueChange: (value) => {
csToolsUtilities.cine.stopClip(element);
framesPerSecond = Number(value);
csToolsUtilities.cine.playClip(element, { framesPerSecond });
},
updateLabelOnChange: (value, label) => {
label.innerText = `Frames per second: ${value}`;
},
});
/**
* Runs the demo
*/
async function run() {
// Init Cornerstone and related libraries
await initDemo();

// Add tools to Cornerstone3D
cornerstoneTools.addTool(WindowLevelTool);
cornerstoneTools.addTool(PanTool);
cornerstoneTools.addTool(ZoomTool);

// Define a tool group, which defines how mouse events map to tool commands for
// Any viewport using the group
const toolGroup = ToolGroupManager.createToolGroup(toolGroupId);

// Add the tools to the tool group
toolGroup.addTool(WindowLevelTool.toolName);
toolGroup.addTool(PanTool.toolName);
toolGroup.addTool(ZoomTool.toolName);

// Set the initial state of the tools, here we set one tool active on left click.
// This means left click will draw that tool.
toolGroup.setToolActive(WindowLevelTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Primary, // Left Click
},
],
});

toolGroup.setToolActive(PanTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Auxiliary,
},
],
});

toolGroup.setToolActive(ZoomTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Secondary,
},
],
});

// Get Cornerstone imageIds and fetch metadata into RAM
const imageIds = await createImageIdsAndCacheMetaData({
StudyInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7009.2403.334240657131972136850343327463',
SeriesInstanceUID:
'1.3.6.1.4.1.14519.5.2.1.7009.2403.226151125820845824875394858561',
wadoRsRoot: 'https://d1qmxk7r72ysft.cloudfront.net/dicomweb',
type: 'STACK',
});

// Instantiate a rendering engine
const renderingEngineId = 'myRenderingEngine';
const renderingEngine = new RenderingEngine(renderingEngineId);

// Create a stack viewport
const viewportId = 'CT_STACK';
const viewportInput = {
viewportId,
type: ViewportType.STACK,
element,
defaultOptions: {
background: <Types.Point3>[0.2, 0, 0.2],
},
};

renderingEngine.enableElement(viewportInput);

// Set the tool group on the viewport
toolGroup.addViewport(viewportId, renderingEngineId);

// Get the stack viewport that was created
const viewport = <Types.IStackViewport>(
renderingEngine.getViewport(viewportId)
);

// Set the stack on the viewport
viewport.setStack(imageIds).then(() => {
csUtils.prefetchStack(imageIds);
});

// Render the image
viewport.render();
}

run();
21 changes: 21 additions & 0 deletions packages/tools/src/types/CINETypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
type PlayClipOptions = {
framesPerSecond?: number;
frameTimeVector?: number[];
reverse?: boolean;
loop?: boolean;
frameTimeVectorSpeedMultiplier?: number;
};

interface ToolData {
intervalId: number | undefined;
framesPerSecond: number;
lastFrameTimeStamp: number | undefined;
frameTimeVector: number[] | undefined;
ignoreFrameTimeVector: boolean;
usingFrameTimeVector: boolean;
speed: number;
reverse: boolean;
loop: boolean;
}

export type { PlayClipOptions, ToolData };
3 changes: 3 additions & 0 deletions packages/tools/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type { ToolProps, PublicToolProps } from './ToolProps';
import type { SVGCursorDescriptor, SVGPoint } from './CursorTypes';
import type JumpToSliceOptions from './JumpToSliceOptions';
import type ScrollOptions from './ScrollOptions';
import type * as CINETypes from './CINETypes';
import type {
Color,
ColorLUT,
Expand Down Expand Up @@ -81,4 +82,6 @@ export type {
SVGPoint,
// Scroll
ScrollOptions,
// CINE
CINETypes,
};
9 changes: 9 additions & 0 deletions packages/tools/src/utilities/cine/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* CINE Tool Events
*/
enum Events {
CLIP_STOPPED = 'CORNERSTONE_CINE_TOOL_STOPPED',
CLIP_STARTED = 'CORNERSTONE_CINE_TOOL_STARTED',
}

export default Events;
5 changes: 5 additions & 0 deletions packages/tools/src/utilities/cine/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { playClip, stopClip } from './playClip';
import Events from './events';
import { getToolState, addToolState } from './state';

export { playClip, stopClip, Events, getToolState, addToolState };
Loading

0 comments on commit 916d783

Please sign in to comment.