Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(orientation marker) New Orientation Marker tool #794

Merged
merged 12 commits into from
Sep 26, 2023
98 changes: 98 additions & 0 deletions common/reviews/api/tools.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

```ts

import { Corners } from '@kitware/vtk.js/Interaction/Widgets/OrientationMarkerWidget/Constants';
import type { GetGPUTier } from 'detect-gpu';
import type { mat4 } from 'gl-matrix';
import type { TierResult } from 'detect-gpu';
import type vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
import vtkAnnotatedCubeActor from '@kitware/vtk.js/Rendering/Core/AnnotatedCubeActor';
import type { vtkColorTransferFunction } from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
import type { vtkImageData } from '@kitware/vtk.js/Common/DataModel/ImageData';
import vtkImageSlice from '@kitware/vtk.js/Rendering/Core/ImageSlice';
Expand Down Expand Up @@ -3611,6 +3613,102 @@ declare namespace orientation_2 {
}
}

// @public (undocumented)
export class OrientationMarkerTool extends BaseTool {
constructor(toolProps?: {}, defaultToolProps?: {
configuration: {
orientationWidget: {
enabled: boolean;
viewportCorner: Corners;
viewportSize: number;
minPixelSize: number;
maxPixelSize: number;
};
overlayMarkerType: number;
overlayConfiguration: {
[x: number]: {
faceProperties: {
xPlus: {
text: string;
faceColor: string;
faceRotation: number;
};
xMinus: {
text: string;
faceColor: string;
faceRotation: number;
};
yPlus: {
text: string;
faceColor: string;
fontColor: string;
faceRotation: number;
};
yMinus: {
text: string;
faceColor: string;
fontColor: string;
};
zPlus: {
text: string;
};
zMinus: {
text: string;
};
};
defaultStyle: {
fontStyle: string;
fontFamily: string;
fontColor: string;
fontSizeScale: (res: any) => number;
faceColor: string;
edgeThickness: number;
edgeColor: string;
resolution: number;
};
polyDataURL?: undefined;
} | {
faceProperties?: undefined;
defaultStyle?: undefined;
polyDataURL?: undefined;
} | {
polyDataURL: string;
faceProperties?: undefined;
defaultStyle?: undefined;
};
};
};
});
// (undocumented)
addAxisActorInViewport(viewport: any): Promise<void>;
// (undocumented)
static AXIS: number;
// (undocumented)
configuration_invalidated: boolean;
// (undocumented)
createAnnotatedCubeActor(): Promise<vtkAnnotatedCubeActor>;
// (undocumented)
static CUBE: number;
// (undocumented)
onSetToolActive: () => void;
// (undocumented)
onSetToolEnabled: () => void;
// (undocumented)
orientationMarkers: any;
// (undocumented)
static OVERLAY_MARKER_TYPES: {
ANNOTATED_CUBE: number;
AXES: number;
CUSTOM: number;
};
// (undocumented)
polyDataURL: any;
// (undocumented)
static toolName: any;
// (undocumented)
static VTPFILE: number;
}

// @public
type OrientationVectors = {
viewPlaneNormal: Point3;
Expand Down
217 changes: 217 additions & 0 deletions packages/tools/examples/orientationMarker/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import {
RenderingEngine,
Enums,
volumeLoader,
setVolumesForViewports,
} from '@cornerstonejs/core';
import {
initDemo,
createImageIdsAndCacheMetaData,
setCtTransferFunctionForVolumeActor,
setTitleAndDescription,
} from '../../../../utils/demo/helpers';
import * as cornerstoneTools from '@cornerstonejs/tools';
import addDropDownToToolbar from '../../../../utils/demo/helpers/addDropdownToToolbar';

async function getImageStacks() {
// Get Cornerstone imageIds for the source data and fetch metadata into RAM
const wadoRsRoot = 'https://d33do7qe4w26qo.cloudfront.net/dicomweb';
const studyInstanceUID =
'1.3.6.1.4.1.25403.345050719074.3824.20170125095258.1';
const seriesInstanceUIDs = [
'1.3.6.1.4.1.25403.345050719074.3824.20170125095258.7',
];
const axialImageIds = await createImageIdsAndCacheMetaData({
StudyInstanceUID: studyInstanceUID,
SeriesInstanceUID: seriesInstanceUIDs[0],
wadoRsRoot,
});

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

const {
ToolGroupManager,
Enums: csToolsEnums,
OrientationMarkerTool,
ZoomTool,
PanTool,
VolumeRotateMouseWheelTool,
TrackballRotateTool,
} = cornerstoneTools;

addDropDownToToolbar({
options: {
values: Object.keys(OrientationMarkerTool.OVERLAY_MARKER_TYPES),
defaultValue: OrientationMarkerTool.OVERLAY_MARKER_TYPES.AXES,
},
onSelectedValueChange: (value) => {
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId);
toolGroup.setToolConfiguration(OrientationMarkerTool.toolName, {
overlayMarkerType: OrientationMarkerTool.OVERLAY_MARKER_TYPES[value],
});

toolGroup.setToolEnabled(OrientationMarkerTool.toolName);
},
});

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

// Define a unique id for the volume
const volumeName = 'CT_VOLUME_ID'; // Id of the volume less loader prefix
const volumeLoaderScheme = 'cornerstoneStreamingImageVolume'; // Loader id which defines which volume loader to use
const volumeId = `${volumeLoaderScheme}:${volumeName}`; // VolumeId with loader id + volume id
const toolGroupId = 'MY_TOOLGROUP_ID';

// ======== Set up page ======== //
setTitleAndDescription(
'OverlayGrid',
'Here we demonstrate overlay grid tool working. The reference lines for all the images in axial series is displayed in the sagittal and coronal series.'
);

const size = '500px';
const content = document.getElementById('content');
const viewportGrid = document.createElement('div');

viewportGrid.style.display = 'flex';
viewportGrid.style.display = 'flex';
viewportGrid.style.flexDirection = 'row';

const elements = [];
const numberOfElements = 3;
for (let i = 0; i < numberOfElements; i++) {
const element = document.createElement('div');
element.style.width = size;
element.style.height = size;
// Disable right click context menu so we can have right click tools
element.oncontextmenu = (e) => e.preventDefault();
viewportGrid.appendChild(element);
elements.push(element);
}

content.appendChild(viewportGrid);

const instructions = document.createElement('p');
instructions.innerText = `
`;

content.append(instructions);

const viewportIds = ['CT_AXIAL', 'CT_SAGITTAL', 'CT_CORONAL'].slice(
0,
numberOfElements
);

const renderingEngineId = 'myRenderingEngine';

/**
* Runs the demo
*/
async function run() {
// Define tool groups to add the segmentation display tool to
const toolGroup = ToolGroupManager.createToolGroup(toolGroupId);

// Init Cornerstone and related libraries
await initDemo();

// Add tools to Cornerstone3D
cornerstoneTools.addTool(OrientationMarkerTool);
cornerstoneTools.addTool(PanTool);
cornerstoneTools.addTool(ZoomTool);
cornerstoneTools.addTool(TrackballRotateTool);
cornerstoneTools.addTool(VolumeRotateMouseWheelTool);

toolGroup.addTool(OrientationMarkerTool.toolName);
toolGroup.addTool(ZoomTool.toolName);
toolGroup.addTool(PanTool.toolName);
toolGroup.addTool(VolumeRotateMouseWheelTool.toolName);
toolGroup.addTool(TrackballRotateTool.toolName);

toolGroup.setToolActive(TrackballRotateTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Primary, // Left Click
},
],
});

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

// Create the viewports
const viewportInputArray = [
{
viewportId: viewportIds[0],
type: ViewportType.ORTHOGRAPHIC,
element: elements[0],
defaultOptions: {
orientation: Enums.OrientationAxis.AXIAL,
},
},
{
viewportId: viewportIds[1],
type: ViewportType.ORTHOGRAPHIC,
element: elements[1],
defaultOptions: {
orientation: Enums.OrientationAxis.SAGITTAL,
},
},
{
viewportId: viewportIds[2],
type: ViewportType.ORTHOGRAPHIC,
element: elements[2],
defaultOptions: {
orientation: Enums.OrientationAxis.CORONAL,
},
},
];

renderingEngine.setViewports(viewportInputArray);

const usedViewportIds = viewportInputArray.map(({ viewportId }) => {
toolGroup.addViewport(viewportId, renderingEngineId);
return viewportId;
});

const imageIds = await getImageStacks();

// Define a volume in memory
const volume = await volumeLoader.createAndCacheVolume(volumeId, {
imageIds,
});
volume.load();

await setVolumesForViewports(
renderingEngine,
[
{
volumeId,
callback: setCtTransferFunctionForVolumeActor,
blendMode: Enums.BlendModes.MAXIMUM_INTENSITY_BLEND,
// Todo: just for test
slabThickness: 100,
},
],
usedViewportIds
);

toolGroup.setToolActive(OrientationMarkerTool.toolName);
toolGroup.setToolActive(VolumeRotateMouseWheelTool.toolName);
toolGroup.setToolActive(ZoomTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Secondary, // Left Click
},
],
});

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

run();
2 changes: 2 additions & 0 deletions packages/tools/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
ReferenceLines,
PaintFillTool,
ScaleOverlayTool,
OrientationMarkerTool,
OverlayGridTool,
} from './tools';

Expand Down Expand Up @@ -112,6 +113,7 @@ export {
RectangleROIThresholdTool,
RectangleROIStartEndThresholdTool,
BrushTool,
OrientationMarkerTool,
// Synchronizers
synchronizers,
Synchronizer,
Expand Down
Loading