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

Volume3d #3

Draft
wants to merge 60 commits into
base: gradient_legacy
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
76bfcaf
feat: query string app config
Ouwen Sep 13, 2022
1bad378
feat: support for mobile view
Ouwen Oct 19, 2022
b7d2ef6
feat: viewport actionbar no-wrap
Ouwen Sep 26, 2022
dd9ded4
feat: added voiLUTFunction to MetadataProvider
Ouwen Sep 26, 2022
a50a32d
feat: increased vtk 25.11.1, more reusable cornerstone-extension and …
Ouwen Nov 21, 2022
e97647d
feat: added initial display area
Ouwen Nov 4, 2022
56ec247
feat: enable loading a study after viewer is initialized
Ouwen Nov 20, 2022
0acbedc
add support for updating the WebApiDataSource configuraiton
Zaid-Safadi Nov 23, 2022
9725c34
feat: added CacheAPI support
Ouwen Dec 12, 2022
e5ae833
[RDV-64] static standalone deployment
Dec 16, 2022
3d06737
[RDV-64] update README
Dec 16, 2022
33186ae
Launch OHIF by series instance UID via URL param
HemantPatel30 Dec 21, 2022
c2faae0
RDV-104 Remove loading indicator and change OHIF ICON with RapidAI
HemantPatel30 Dec 21, 2022
4e58ae7
Viewer support to launch by study and series through external interfa…
HemantPatel30 Dec 21, 2022
bc6869e
Remove Extra classname used for scrollbar - accomodate overlay design
HemantPatel30 Dec 28, 2022
43965da
Handling Series Instance UID with Hanging Protocol for Axial Display+…
HemantPatel30 Jan 18, 2023
383519f
RDV-113 Fix : Hide overlay followed by scroll image also hide orienta…
HemantPatel30 Jan 24, 2023
861c451
RDV-111 Create Server side hanging protocol and load respective image…
HemantPatel30 Jan 24, 2023
c18c82d
static assets v0.0.1 built from unknown revision
aaronadrid-isv Jan 25, 2023
080e5aa
move dist assets to viewer-static
aaronadrid-isv Jan 26, 2023
1ddf9e1
add viewer-static project
aaronadrid-isv Jan 26, 2023
359c4c9
configuration updates, build scripts, readme
aaronadrid-isv Jan 26, 2023
9b3a645
delete static assets
aaronadrid-isv Jan 26, 2023
fb85f53
re-adding static assets
aaronadrid-isv Jan 26, 2023
d4544fb
rename packages
aaronadrid-isv Jan 26, 2023
513f289
update whitelist
aaronadrid-isv Jan 26, 2023
02c836a
Merge pull request #4 from ischemaview/task/RDV-110_ohif_viewer_stati…
aaronadrid-isv Jan 27, 2023
45228e1
add new version of static viewer from rma branch
aaronadrid-isv Jan 27, 2023
7baae98
@ischemaview/[email protected]
aaronadrid-isv Jan 27, 2023
4a5aa5b
Merge pull request #5 from ischemaview/task/RDV-110_ohif_viewer_stati…
aaronadrid-isv Jan 27, 2023
95a8270
feat: implement withCredentials flag on xhr calls
aaronadrid-isv Feb 1, 2023
3d18ce0
Merge pull request #6 from ischemaview/feature/RDV-91_xhr_withCredent…
aaronadrid-isv Feb 1, 2023
d1de42e
Raising Viewer ready event once app is init
HemantPatel30 Feb 1, 2023
3a43856
fix the touch problem
HemantPatel30 Feb 2, 2023
26b963c
Merge pull request #7 from ischemaview/US_Externalinterface_Viewer
HemantPatel30 Feb 2, 2023
05e7048
feat: add xhr withCredentials support to DicomWebDataSource
aaronadrid-isv Feb 2, 2023
18cda52
fix: revert withCredentials default to false
aaronadrid-isv Feb 2, 2023
4018da6
Merge pull request #9 from ischemaview/feature/RDV-91_xhr_withCredent…
aaronadrid-isv Feb 2, 2023
02a6f1a
feat: addwithCredentials support to searchForSeries calls
aaronadrid-isv Feb 2, 2023
ab895a9
Merge pull request #10 from ischemaview/feature/RDV-91_xhr_withCreden…
aaronadrid-isv Feb 2, 2023
231b514
RDV-147 Bug Fix - Study load is not working as - onNewStudyLoad subsc…
HemantPatel30 Feb 6, 2023
7d5f96b
RDV-118- State management - use of State management service in Viewer
HemantPatel30 Feb 10, 2023
bf852d9
feat: viewport actionbar no-wrap
Ouwen Sep 26, 2022
30c8472
feat: increased vtk 26.4.0, more reusable cornerstone-extension and m…
Ouwen Nov 21, 2022
8128b25
feat: query string app config
Ouwen Sep 13, 2022
575edee
feat: added initial display area
Ouwen Nov 4, 2022
903f46a
feat: added CacheAPI support
Ouwen Dec 12, 2022
eb071b8
feat: enable loading a study after viewer is initialized
Ouwen Nov 20, 2022
3844b21
feat: add support for updating the WebApiDataSource configuraiton
Zaid-Safadi Nov 23, 2022
8d50f1e
feat: support for mobile view
Ouwen Oct 19, 2022
983c563
Merge pull request #11 from ischemaview/US_Statemanagement_Viewer_Opt…
HemantPatel30 Feb 19, 2023
cba401e
rapidai: whitelabeling
Ouwen Nov 6, 2022
4df5715
feat: added max volume
Ouwen Feb 15, 2023
12d242f
feat: added config
Ouwen Feb 22, 2023
a4a0405
feat: changed popup message
Ouwen Feb 22, 2023
3dcf4ce
Merge branch 'US_SlabVP_merged' into US_sqaush
HemantPatel30 Feb 23, 2023
203d2e1
Fix build issue
HemantPatel30 Feb 23, 2023
d5060e4
lint: linted OHIFCornerstoneViewport
Ouwen Mar 2, 2023
f67f642
feat: added touch to viewport grid
Ouwen Mar 2, 2023
7383a98
volume3D rendering and trackball tool
Mar 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
473 changes: 245 additions & 228 deletions extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import ViewportImageSliceLoadingIndicator from './ViewportImageSliceLoadingIndic

function CornerstoneOverlays(props) {
const { viewportIndex, element, scrollbarHeight, servicesManager } = props;
const {
disableViewportImageScrollbar,
disableViewportOverlay,
disableViewportImageSliceLoadingIndicator,
disableViewportOrientationMarkers,
} = props;
const { cornerstoneViewportService } = servicesManager.services;
const [imageSliceData, setImageSliceData] = useState({
imageIndex: 0,
Expand Down Expand Up @@ -47,33 +53,41 @@ function CornerstoneOverlays(props) {

return (
<div className="noselect">
<ViewportImageScrollbar
viewportIndex={viewportIndex}
viewportData={viewportData}
element={element}
imageSliceData={imageSliceData}
setImageSliceData={setImageSliceData}
scrollbarHeight={scrollbarHeight}
servicesManager={servicesManager}
/>
<ViewportOverlay
imageSliceData={imageSliceData}
viewportData={viewportData}
viewportIndex={viewportIndex}
servicesManager={servicesManager}
element={element}
/>
<ViewportImageSliceLoadingIndicator
viewportData={viewportData}
element={element}
/>
<ViewportOrientationMarkers
imageSliceData={imageSliceData}
element={element}
viewportData={viewportData}
servicesManager={servicesManager}
viewportIndex={viewportIndex}
/>
{!disableViewportImageScrollbar && (
<ViewportImageScrollbar
viewportIndex={viewportIndex}
viewportData={viewportData}
element={element}
imageSliceData={imageSliceData}
setImageSliceData={setImageSliceData}
scrollbarHeight={scrollbarHeight}
servicesManager={servicesManager}
/>
)}
{!disableViewportOverlay && (
<ViewportOverlay
imageSliceData={imageSliceData}
viewportData={viewportData}
viewportIndex={viewportIndex}
servicesManager={servicesManager}
element={element}
/>
)}
{!disableViewportImageSliceLoadingIndicator && (
<ViewportImageSliceLoadingIndicator
viewportData={viewportData}
element={element}
/>
)}
{!disableViewportOrientationMarkers && (
<ViewportOrientationMarkers
imageSliceData={imageSliceData}
element={element}
viewportData={viewportData}
servicesManager={servicesManager}
viewportIndex={viewportIndex}
/>
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ function _getInstanceNumberFromVolume(
viewportIndex,
cornerstoneViewportService
) {
const volumes = viewportData.volumes;
const volumes = viewportData.data.map(d => d.volume);

// Todo: support fusion of acquisition plane which has instanceNumber
if (!volumes || volumes.length > 1) {
Expand Down
10 changes: 6 additions & 4 deletions extensions/cornerstone/src/commandsModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,9 @@ const commandsModule = ({ servicesManager }) => {

if (viewport instanceof StackViewport) {
viewport.resetProperties();
viewport.resetCamera();
} else {
// Todo: add reset properties for volume viewport
viewport.resetCamera();
}

viewport.resetCamera();
viewport.render();
},
scaleViewport: ({ direction }) => {
Expand Down Expand Up @@ -449,6 +446,11 @@ const commandsModule = ({ servicesManager }) => {
};

const definitions = {
getActiveViewportEnabledElement: {
commandFn: actions.getActiveViewportEnabledElement,
storeContexts: [],
options: {},
},
setWindowLevel: {
commandFn: actions.setWindowLevel,
storeContexts: [],
Expand Down
20 changes: 14 additions & 6 deletions extensions/cornerstone/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ import SegmentationService from './services/SegmentationService';
import CornerstoneCacheService from './services/CornerstoneCacheService';

import { toolNames } from './initCornerstoneTools';
import { getEnabledElement, reset as enabledElementReset } from './state';
import {
getEnabledElement,
setEnabledElement,
reset as enabledElementReset,
} from './state';
import CornerstoneViewportService from './services/ViewportService/CornerstoneViewportService';

import dicomLoaderService from './utils/dicomLoaderService';
import { registerColormap } from './utils/colormap/transferFunctionHelpers';

Expand All @@ -33,13 +38,14 @@ const Component = React.lazy(() => {
);
});

const OHIFCornerstoneViewport = props => {
const OHIFCornerstoneViewport = React.forwardRef((props, ref) => {
return (
<React.Suspense fallback={<div>Loading...</div>}>
<Component {...props} />
<Component ref={ref} {...props} />
</React.Suspense>
);
};
});
OHIFCornerstoneViewport.displayName = 'OHIFCornerstoneViewport';

/**
*
Expand Down Expand Up @@ -90,21 +96,22 @@ const cornerstoneExtension: Types.Extensions.Extension = {
},
getHangingProtocolModule,
getViewportModule({ servicesManager, commandsManager }) {
const ExtendedOHIFCornerstoneViewport = props => {
const ExtendedOHIFCornerstoneViewport = React.forwardRef((props, ref) => {
// const onNewImageHandler = jumpData => {
// commandsManager.runCommand('jumpToImage', jumpData);
// };
const { ToolbarService } = servicesManager.services;

return (
<OHIFCornerstoneViewport
ref={ref}
{...props}
ToolbarService={ToolbarService}
servicesManager={servicesManager}
commandsManager={commandsManager}
/>
);
};
});

return [
{
Expand All @@ -129,6 +136,7 @@ const cornerstoneExtension: Types.Extensions.Extension = {
return { cornerstone, cornerstoneTools };
},
getEnabledElement,
setEnabledElement,
dicomLoaderService,
registerColormap,
},
Expand Down
7 changes: 4 additions & 3 deletions extensions/cornerstone/src/init.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ export default async function init({
uiNotificationService.show({
title: 'Cross Origin Isolation',
message:
'Cross Origin Isolation is not enabled, volume rendering will not work (e.g., MPR)',
type: 'warning',
'Cross Origin Isolation is not enabled, volume rendering will be less performant',
type: 'info',
duration: 1000,
});
}

Expand Down Expand Up @@ -374,7 +375,7 @@ export default async function init({

// check if reference lines are active
const referenceLinesEnabled =
toolGroup._toolInstances['ReferenceLines'].mode ===
toolGroup._toolInstances?.['ReferenceLines']?.mode ===
Enums.ToolModes.Enabled;

if (!referenceLinesEnabled) {
Expand Down
3 changes: 3 additions & 0 deletions extensions/cornerstone/src/initCornerstoneTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
addTool,
annotation,
ReferenceLinesTool,
TrackballRotateTool,
} from '@cornerstonejs/tools';

export default function initCornerstoneTools(configuration = {}) {
Expand All @@ -48,6 +49,7 @@ export default function initCornerstoneTools(configuration = {}) {
addTool(CrosshairsTool);
addTool(SegmentationDisplayTool);
addTool(ReferenceLinesTool);
addTool(TrackballRotateTool);

// Modify annotation tools to use dashed lines on SR
const annotationStyle = {
Expand Down Expand Up @@ -86,6 +88,7 @@ const toolNames = {
Crosshairs: CrosshairsTool.toolName,
SegmentationDisplay: SegmentationDisplayTool.toolName,
ReferenceLines: ReferenceLinesTool.toolName,
TrackballRotateTool: TrackballRotateTool.toolName,
};

export { toolNames };
2 changes: 2 additions & 0 deletions extensions/cornerstone/src/initWADOImageLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default function initWADOImageLoader(
// Until the default is set to true (which is the case for cornerstone3D),
// we should set this flag to false.
convertFloatPixelDataToInt: false,
use16BitDataType: true,
},
beforeSend: function(xhr) {
const headers = userAuthenticationService.getAuthorizationHeader();
Expand All @@ -78,6 +79,7 @@ export default function initWADOImageLoader(
errorInterceptor: error => {
errorHandler.getHTTPErrorHandler(error);
},
withCredentials: true,
});

initWebWorkers(appConfig);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ServicesManager } from '@ohif/core';
import { cache as cs3DCache, Enums, volumeLoader } from '@cornerstonejs/core';
import { utils } from '@ohif/core';
import sortImageIdsAndGetSpacing from './sortImageIdsAndGetSpacing';
import makeVolumeMetadata from './makeVolumeMetadata';
import { vec3 } from 'gl-matrix';

import getCornerstoneViewportType from '../../utils/getCornerstoneViewportType';
import {
Expand Down Expand Up @@ -66,7 +70,8 @@ class CornerstoneCacheService {
);
}

if (cs3DViewportType === Enums.ViewportType.ORTHOGRAPHIC) {
if (cs3DViewportType === Enums.ViewportType.ORTHOGRAPHIC
|| cs3DViewportType === Enums.ViewportType.VOLUME_3D) {
viewportData = await this._getVolumeViewportData(dataSource, displaySets);
}

Expand Down Expand Up @@ -187,8 +192,34 @@ class CornerstoneCacheService {
dataSource
);

const MAX_VOLUME_SIZE = 400;
const volumeMetadata = makeVolumeMetadata(volumeImageIds);
const { ImageOrientationPatient: chi } = volumeMetadata;
const rowCosineVec = vec3.fromValues(chi[0], chi[1], chi[2]);
const colCosineVec = vec3.fromValues(chi[3], chi[4], chi[5]);
const scanAxisNormal = vec3.create();
vec3.cross(scanAxisNormal, rowCosineVec, colCosineVec);
const { sortedImageIds } = sortImageIdsAndGetSpacing(
volumeImageIds,
scanAxisNormal
);

const distributedCopy = (items, n) => {
const elements = [items[0]];
const totalItems = items.length - 2;
const interval = totalItems / (n - 2);
for (let i = 1; i < n - 1; i++) {
elements.push(items[Math.floor(i * interval)]);
}
elements.push(items[items.length - 1]);
return elements;
};

volume = await volumeLoader.createAndCacheVolume(volumeId, {
imageIds: volumeImageIds,
imageIds:
volumeImageIds.length > MAX_VOLUME_SIZE
? distributedCopy(sortedImageIds, MAX_VOLUME_SIZE)
: volumeImageIds,
});

this.volumeImageIds.set(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { metaData } from '@cornerstonejs/core';
import type { Types } from '@cornerstonejs/core';

/**
* It creates a metadata object for a volume given the imageIds that compose it.
* It uses the first imageId to get the metadata.
*
* @param imageIds - array of imageIds
* @returns The volume metadata
*/
export default function makeVolumeMetadata(
imageIds: Array<string>
): Types.Metadata {
const imageId0 = imageIds[0];

const {
pixelRepresentation,
bitsAllocated,
bitsStored,
highBit,
photometricInterpretation,
samplesPerPixel,
} = metaData.get('imagePixelModule', imageId0);

// Add list of VOIs stored on the DICOM.
const voiLut = [];

const voiLutModule = metaData.get('voiLutModule', imageId0);

// voiLutModule is not always present
let voiLUTFunction;
if (voiLutModule) {
const { windowWidth, windowCenter } = voiLutModule;
voiLUTFunction = voiLutModule?.voiLUTFunction;

if (Array.isArray(windowWidth)) {
for (let i = 0; i < windowWidth.length; i++) {
voiLut.push({
windowWidth: windowWidth[i],
windowCenter: windowCenter[i],
});
}
} else {
voiLut.push({
windowWidth: windowWidth,
windowCenter: windowCenter,
});
}
} else {
voiLut.push({
windowWidth: undefined,
windowCenter: undefined,
});
}

const { modality, seriesInstanceUID } = metaData.get(
'generalSeriesModule',
imageId0
);

const {
imageOrientationPatient,
pixelSpacing,
frameOfReferenceUID,
columns,
rows,
} = metaData.get('imagePlaneModule', imageId0);

// Map to dcmjs-style keywords. This is becoming the standard and makes it
// Easier to swap out cornerstoneWADOImageLoader at a later date.
return {
BitsAllocated: bitsAllocated,
BitsStored: bitsStored,
SamplesPerPixel: samplesPerPixel,
HighBit: highBit,
PhotometricInterpretation: photometricInterpretation,
PixelRepresentation: pixelRepresentation,
Modality: modality,
ImageOrientationPatient: imageOrientationPatient,
PixelSpacing: pixelSpacing,
FrameOfReferenceUID: frameOfReferenceUID,
Columns: columns,
Rows: rows,
// This is a reshaped object and not a dicom tag:
voiLut,
VOILUTFunction: voiLUTFunction,
SeriesInstanceUID: seriesInstanceUID,
};
}
Loading