Skip to content

Commit 98f4851

Browse files
committed
fix for measurement is not correctly place orientation
1 parent 5547de5 commit 98f4851

File tree

4 files changed

+80
-22
lines changed

4 files changed

+80
-22
lines changed

extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ const OHIFCornerstoneViewport = React.memo(
264264
const presentations = getViewportPresentations(viewportId, viewportOptions);
265265

266266
let measurement;
267-
if (cacheJumpToMeasurementEvent?.viewportId === viewportId) {
267+
if (cacheJumpToMeasurementEvent?.cornerstoneViewport === viewportId) {
268268
measurement = cacheJumpToMeasurementEvent.measurement;
269269
// Delete the position presentation so that viewport navigates direct
270270
presentations.positionPresentation = null;
@@ -280,7 +280,7 @@ const OHIFCornerstoneViewport = React.memo(
280280
viewportOptions.needsRerendering = false;
281281
}
282282

283-
cornerstoneViewportService.setViewportData(
283+
await cornerstoneViewportService.setViewportData(
284284
viewportId,
285285
viewportData,
286286
viewportOptions,

extensions/cornerstone/src/services/ViewportService/CornerstoneViewportService.ts

+5-12
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
372372
* @param publicDisplaySetOptions - The public display set options.
373373
* @param presentations - The presentations to set.
374374
*/
375-
public setViewportData(
375+
public async setViewportData(
376376
viewportId: string,
377377
viewportData: StackViewportData | VolumeViewportData,
378378
publicViewportOptions: PublicViewportOptions,
@@ -458,21 +458,14 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
458458
this.viewportsById.set(viewportId, viewportInfo);
459459

460460
const viewport = renderingEngine.getViewport(viewportId);
461-
const displaySetPromise = this._setDisplaySets(
462-
viewport,
463-
viewportData,
464-
viewportInfo,
465-
presentations
466-
);
461+
await this._setDisplaySets(viewport, viewportData, viewportInfo, presentations);
467462

468463
// The broadcast event here ensures that listeners have a valid, up to date
469464
// viewport to access. Doing it too early can result in exceptions or
470465
// invalid data.
471-
displaySetPromise.then(() => {
472-
this._broadcastEvent(this.EVENTS.VIEWPORT_DATA_CHANGED, {
473-
viewportData,
474-
viewportId,
475-
});
466+
this._broadcastEvent(this.EVENTS.VIEWPORT_DATA_CHANGED, {
467+
viewportData,
468+
viewportId,
476469
});
477470
}
478471

platform/app/src/components/ViewportGrid.tsx

+16-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useViewportGrid } from '@ohif/ui-next';
66
import EmptyViewport from './EmptyViewport';
77
import classNames from 'classnames';
88
import { useAppConfig } from '@state';
9+
import getClosestOrientationFromIOP from '../utils/getClosestOrientationFromIOP';
910

1011
function ViewerViewportGrid(props: withAppTypes) {
1112
const { servicesManager, viewportComponents = [], dataSource } = props;
@@ -177,22 +178,29 @@ function ViewerViewportGrid(props: withAppTypes) {
177178
const { displaySetInstanceUID: referencedDisplaySetInstanceUID } = measurement;
178179

179180
const updatedViewports = _getUpdatedViewports(viewportId, referencedDisplaySetInstanceUID);
180-
if (!updatedViewports[0]) {
181+
let viewportToUpdate = updatedViewports[0];
182+
if (updatedViewports.length > 1) {
183+
// To get the viewport which orientation is closest to IOP
184+
const closestOrientation = getClosestOrientationFromIOP(
185+
displaySetService,
186+
referencedDisplaySetInstanceUID
187+
);
188+
viewportToUpdate = updatedViewports.find(
189+
viewport => viewport.viewportOptions?.orientation == closestOrientation
190+
);
191+
}
192+
193+
if (!viewportToUpdate) {
181194
console.warn(
182195
'ViewportGrid::Unable to navigate to viewport containing',
183196
referencedDisplaySetInstanceUID
184197
);
185198
return;
186199
}
187200

188-
// Arbitrarily assign the viewport to element 0
189-
// TODO - this should perform a search to find the most suitable viewport.
190-
updatedViewports[0] = { ...updatedViewports[0] };
191-
const [viewport] = updatedViewports;
192-
193201
// Copy the viewport options to prevent modifying the internal data
194-
viewport.viewportOptions = {
195-
...viewport.viewportOptions,
202+
viewportToUpdate.viewportOptions = {
203+
...viewportToUpdate.viewportOptions,
196204
orientation: 'acquisition',
197205
// The preferred way to jump to the measurement view is to set the
198206
// view reference, as this can hold information such as the orientation
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { vec3 } from 'gl-matrix';
2+
import { Enums } from '@cornerstonejs/core';
3+
import OrientationAxis = Enums.OrientationAxis;
4+
5+
/**
6+
* Get the plane (orientation) to which the ImageOrientationPatient is most closely aligned
7+
*
8+
* @param {Array} imageOrientationPatient - ImageOrientationPatient vector for the image
9+
* @returns
10+
*/
11+
export default function getClosestOrientationFromIOP(
12+
displaySetService,
13+
displaySetInstanceUID
14+
): OrientationAxis {
15+
const displaySet = displaySetService.getDisplaySetByUID(displaySetInstanceUID);
16+
const imageOrientationPatient = displaySet.instances[0].ImageOrientationPatient as Array<number>;
17+
if (imageOrientationPatient?.length !== 6) {
18+
throw new Error('ImageOrientationPatient must be an array of length 6.');
19+
}
20+
21+
// Take cross product to get vector coming "out" of image plane
22+
const rowCosineVec = vec3.fromValues(
23+
imageOrientationPatient[0],
24+
imageOrientationPatient[1],
25+
imageOrientationPatient[2]
26+
);
27+
const colCosineVec = vec3.fromValues(
28+
imageOrientationPatient[3],
29+
imageOrientationPatient[4],
30+
imageOrientationPatient[5]
31+
);
32+
const scanAxisNormal = vec3.cross(vec3.create(), rowCosineVec, colCosineVec);
33+
34+
// Define the reference vectors for axial, coronal, and sagittal planes
35+
const unitVectors = {
36+
[OrientationAxis.AXIAL]: vec3.fromValues(0, 0, 1),
37+
[OrientationAxis.CORONAL]: vec3.fromValues(0, 1, 0),
38+
[OrientationAxis.SAGITTAL]: vec3.fromValues(1, 0, 0),
39+
};
40+
41+
// Compute dot products for each reference plane
42+
// Because all vectors are normalized, dot product is bounded between -1 and 1
43+
let maxDot = 0;
44+
let maxOrientation: string = '';
45+
for (const [k, v] of Object.entries(unitVectors)) {
46+
// Absolute value of dot product because we only care about alignment with the axis
47+
// For example, dot product of -1 for a given axis means perfect alignment
48+
// but the image is pointing in the "opposite" direction
49+
const res = Math.abs(vec3.dot(scanAxisNormal, v));
50+
if (res > maxDot) {
51+
maxDot = res;
52+
maxOrientation = k;
53+
}
54+
}
55+
56+
return maxOrientation as OrientationAxis;
57+
}

0 commit comments

Comments
 (0)