@cornerstonejs/core 4.15.18 → 4.15.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/RenderingEngine/Viewport.js +4 -6
- package/dist/esm/utilities/getPlaneCubeIntersectionDimensions.d.ts +7 -0
- package/dist/esm/utilities/getPlaneCubeIntersectionDimensions.js +28 -0
- package/dist/esm/utilities/index.d.ts +2 -0
- package/dist/esm/utilities/index.js +2 -0
- package/dist/esm/utilities/rotateToViewCoordinates.d.ts +3 -0
- package/dist/esm/utilities/rotateToViewCoordinates.js +33 -0
- package/dist/esm/utilities/splitImageIdsBy4DTags.js +80 -0
- package/dist/esm/utilities/toNumber.d.ts +1 -0
- package/dist/esm/utilities/toNumber.js +3 -0
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +2 -2
|
@@ -15,6 +15,7 @@ import { RENDERING_DEFAULTS } from '../constants';
|
|
|
15
15
|
import { InterpolationType } from '../enums';
|
|
16
16
|
import { deepClone } from '../utilities/deepClone';
|
|
17
17
|
import { updatePlaneRestriction } from '../utilities/updatePlaneRestriction';
|
|
18
|
+
import { getCubeSizeInView } from '../utilities/getPlaneCubeIntersectionDimensions';
|
|
18
19
|
import { getConfiguration } from '../init';
|
|
19
20
|
class Viewport {
|
|
20
21
|
static { this.CameraViewPresentation = {
|
|
@@ -526,16 +527,13 @@ class Viewport {
|
|
|
526
527
|
const idx = [middleIJK[0], middleIJK[1], middleIJK[2]];
|
|
527
528
|
imageData.indexToWorld(idx, focalPoint);
|
|
528
529
|
}
|
|
529
|
-
let { widthWorld, heightWorld } =
|
|
530
|
+
let { widthWorld, heightWorld } = imageData
|
|
531
|
+
? getCubeSizeInView(imageData, viewPlaneNormal, viewUp)
|
|
532
|
+
: this._getWorldDistanceViewUpAndViewRight(bounds, viewUp, viewPlaneNormal);
|
|
530
533
|
if (imageData) {
|
|
531
534
|
const spacing = imageData.getSpacing();
|
|
532
535
|
widthWorld = Math.max(spacing[0], widthWorld - spacing[0]);
|
|
533
536
|
heightWorld = Math.max(spacing[1], heightWorld - spacing[1]);
|
|
534
|
-
const extent = imageData.getExtent();
|
|
535
|
-
const widthWorld2 = (extent[1] - extent[0]) * spacing[0];
|
|
536
|
-
const heightWorld2 = (extent[3] - extent[2]) * spacing[1];
|
|
537
|
-
console.warn('extent=', extent, spacing);
|
|
538
|
-
console.log('New method would produce:', this.id, widthWorld2, heightWorld2, widthWorld, heightWorld, widthWorld2 - widthWorld, heightWorld2 - heightWorld);
|
|
539
537
|
}
|
|
540
538
|
const canvasSize = [this.sWidth, this.sHeight];
|
|
541
539
|
const boundsAspectRatio = widthWorld / heightWorld;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Point3 } from '../types';
|
|
2
|
+
import type vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
|
|
3
|
+
export declare function getCubeSizeInView(imageData: vtkImageData, viewPlaneNormal: Point3, viewUp: Point3): {
|
|
4
|
+
widthWorld: number;
|
|
5
|
+
heightWorld: number;
|
|
6
|
+
depthWorld: number;
|
|
7
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { rotateToViewCoordinates } from './rotateToViewCoordinates';
|
|
2
|
+
function findMinCornerIndex(viewCorners, dimension) {
|
|
3
|
+
let minIndex = 0;
|
|
4
|
+
let minValue = viewCorners[0][dimension];
|
|
5
|
+
for (let i = 1; i < viewCorners.length; i++) {
|
|
6
|
+
if (viewCorners[i][dimension] < minValue) {
|
|
7
|
+
minValue = viewCorners[i][dimension];
|
|
8
|
+
minIndex = i;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return minIndex;
|
|
12
|
+
}
|
|
13
|
+
function calculateSize(viewCorners, dimension) {
|
|
14
|
+
const minIndex = findMinCornerIndex(viewCorners, dimension);
|
|
15
|
+
const maxIndex = minIndex ^ 7;
|
|
16
|
+
return viewCorners[maxIndex][dimension] - viewCorners[minIndex][dimension];
|
|
17
|
+
}
|
|
18
|
+
export function getCubeSizeInView(imageData, viewPlaneNormal, viewUp) {
|
|
19
|
+
const viewCorners = rotateToViewCoordinates(imageData, viewPlaneNormal, viewUp);
|
|
20
|
+
const maxWidth = calculateSize(viewCorners, 0);
|
|
21
|
+
const maxHeight = calculateSize(viewCorners, 1);
|
|
22
|
+
const maxDepth = calculateSize(viewCorners, 2);
|
|
23
|
+
return {
|
|
24
|
+
widthWorld: maxWidth,
|
|
25
|
+
heightWorld: maxHeight,
|
|
26
|
+
depthWorld: maxDepth,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -93,6 +93,8 @@ import calculateSpacingBetweenImageIds from './calculateSpacingBetweenImageIds';
|
|
|
93
93
|
export * as logger from './logger';
|
|
94
94
|
import { calculateNeighborhoodStats } from './calculateNeighborhoodStats';
|
|
95
95
|
export * from './getPixelSpacingInformation';
|
|
96
|
+
export * from './getPlaneCubeIntersectionDimensions';
|
|
97
|
+
export * from './rotateToViewCoordinates';
|
|
96
98
|
import { asArray } from './asArray';
|
|
97
99
|
export { updatePlaneRestriction } from './updatePlaneRestriction';
|
|
98
100
|
declare const getViewportModality: (viewport: IViewport, volumeId?: string) => string;
|
|
@@ -94,6 +94,8 @@ import calculateSpacingBetweenImageIds from './calculateSpacingBetweenImageIds';
|
|
|
94
94
|
export * as logger from './logger';
|
|
95
95
|
import { calculateNeighborhoodStats } from './calculateNeighborhoodStats';
|
|
96
96
|
export * from './getPixelSpacingInformation';
|
|
97
|
+
export * from './getPlaneCubeIntersectionDimensions';
|
|
98
|
+
export * from './rotateToViewCoordinates';
|
|
97
99
|
import { asArray } from './asArray';
|
|
98
100
|
export { updatePlaneRestriction } from './updatePlaneRestriction';
|
|
99
101
|
const getViewportModality = (viewport, volumeId) => _getViewportModality(viewport, volumeId, cache.getVolume);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { vec3 } from 'gl-matrix';
|
|
2
|
+
export function rotateToViewCoordinates(imageData, viewPlaneNormal, viewUp) {
|
|
3
|
+
const viewRight = vec3.cross(vec3.create(), viewPlaneNormal, viewUp);
|
|
4
|
+
vec3.normalize(viewRight, viewRight);
|
|
5
|
+
const extent = imageData.getExtent();
|
|
6
|
+
const xMin = extent[0];
|
|
7
|
+
const xMax = extent[1] + 1;
|
|
8
|
+
const yMin = extent[2];
|
|
9
|
+
const yMax = extent[3] + 1;
|
|
10
|
+
const zMin = extent[4];
|
|
11
|
+
const zMax = extent[5] + 1;
|
|
12
|
+
const corners = [
|
|
13
|
+
[xMin, yMin, zMin],
|
|
14
|
+
[xMax, yMin, zMin],
|
|
15
|
+
[xMin, yMax, zMin],
|
|
16
|
+
[xMax, yMax, zMin],
|
|
17
|
+
[xMin, yMin, zMax],
|
|
18
|
+
[xMax, yMin, zMax],
|
|
19
|
+
[xMin, yMax, zMax],
|
|
20
|
+
[xMax, yMax, zMax],
|
|
21
|
+
];
|
|
22
|
+
const viewCorners = corners.map((corner) => {
|
|
23
|
+
const worldPoint = [0, 0, 0];
|
|
24
|
+
imageData.indexToWorld(corner, worldPoint);
|
|
25
|
+
const viewPoint = [
|
|
26
|
+
vec3.dot(worldPoint, viewRight),
|
|
27
|
+
vec3.dot(worldPoint, viewUp),
|
|
28
|
+
vec3.dot(worldPoint, viewPlaneNormal),
|
|
29
|
+
];
|
|
30
|
+
return viewPoint;
|
|
31
|
+
});
|
|
32
|
+
return viewCorners;
|
|
33
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as metaData from '../metaData';
|
|
2
|
+
import { toFiniteNumber } from './toNumber';
|
|
2
3
|
function generateFrameImageId(baseImageId, frameNumber) {
|
|
3
4
|
const framePattern = /\/frames\/\d+/;
|
|
4
5
|
if (!framePattern.test(baseImageId)) {
|
|
@@ -67,6 +68,78 @@ function handleMultiframe4D(imageIds) {
|
|
|
67
68
|
splittingTag: 'TimeSlotVector',
|
|
68
69
|
};
|
|
69
70
|
}
|
|
71
|
+
function handleCardiac4D(imageIds) {
|
|
72
|
+
if (!imageIds || imageIds.length === 0) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const cardiacNumberOfImages = getFiniteValue(imageIds[0], 'CardiacNumberOfImages');
|
|
76
|
+
if (cardiacNumberOfImages === undefined) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const stacks = new Map();
|
|
80
|
+
for (const imageId of imageIds) {
|
|
81
|
+
const stackId = metaData.get('StackID', imageId);
|
|
82
|
+
const inStackPositionNumber = getFiniteValue(imageId, 'InStackPositionNumber');
|
|
83
|
+
const triggerTime = getFiniteValue(imageId, 'TriggerTime');
|
|
84
|
+
if (stackId === undefined ||
|
|
85
|
+
inStackPositionNumber === undefined ||
|
|
86
|
+
triggerTime === undefined) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const stackKey = String(stackId);
|
|
90
|
+
if (!stacks.has(stackKey)) {
|
|
91
|
+
stacks.set(stackKey, new Map());
|
|
92
|
+
}
|
|
93
|
+
const positions = stacks.get(stackKey);
|
|
94
|
+
if (!positions.has(inStackPositionNumber)) {
|
|
95
|
+
positions.set(inStackPositionNumber, []);
|
|
96
|
+
}
|
|
97
|
+
positions.get(inStackPositionNumber).push({ imageId, triggerTime });
|
|
98
|
+
}
|
|
99
|
+
const sortedStackIds = Array.from(stacks.keys()).sort((a, b) => Number(a) - Number(b));
|
|
100
|
+
if (sortedStackIds.length === 0) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const preparedStacks = [];
|
|
104
|
+
let timeCount;
|
|
105
|
+
for (const stackId of sortedStackIds) {
|
|
106
|
+
const positions = stacks.get(stackId);
|
|
107
|
+
const sortedPositions = Array.from(positions.keys()).sort((a, b) => a - b);
|
|
108
|
+
for (const position of sortedPositions) {
|
|
109
|
+
const frames = positions.get(position);
|
|
110
|
+
frames.sort((a, b) => a.triggerTime - b.triggerTime);
|
|
111
|
+
if (timeCount === undefined) {
|
|
112
|
+
timeCount = frames.length;
|
|
113
|
+
}
|
|
114
|
+
else if (frames.length !== timeCount) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
preparedStacks.push({
|
|
119
|
+
stackId,
|
|
120
|
+
positions: sortedPositions,
|
|
121
|
+
framesByPosition: positions,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (!timeCount) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const imageIdGroups = [];
|
|
128
|
+
for (let timeIndex = 0; timeIndex < timeCount; timeIndex++) {
|
|
129
|
+
const group = [];
|
|
130
|
+
for (const stack of preparedStacks) {
|
|
131
|
+
for (const position of stack.positions) {
|
|
132
|
+
const frames = stack.framesByPosition.get(position);
|
|
133
|
+
group.push(frames[timeIndex].imageId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
imageIdGroups.push(group);
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
imageIdGroups,
|
|
140
|
+
splittingTag: 'CardiacTriggerTime',
|
|
141
|
+
};
|
|
142
|
+
}
|
|
70
143
|
const groupBy = (array, key) => {
|
|
71
144
|
return array.reduce((rv, x) => {
|
|
72
145
|
(rv[x[key]] = rv[x[key]] || []).push(x);
|
|
@@ -127,6 +200,9 @@ function getTagValue(imageId, tag) {
|
|
|
127
200
|
return undefined;
|
|
128
201
|
}
|
|
129
202
|
}
|
|
203
|
+
function getFiniteValue(imageId, tag) {
|
|
204
|
+
return toFiniteNumber(getTagValue(imageId, tag));
|
|
205
|
+
}
|
|
130
206
|
function getPhilipsPrivateBValue(imageId) {
|
|
131
207
|
const value = metaData.get('20011003', imageId);
|
|
132
208
|
try {
|
|
@@ -192,6 +268,10 @@ function splitImageIdsBy4DTags(imageIds) {
|
|
|
192
268
|
if (multiframeResult) {
|
|
193
269
|
return multiframeResult;
|
|
194
270
|
}
|
|
271
|
+
const cardiacResult = handleCardiac4D(imageIds);
|
|
272
|
+
if (cardiacResult) {
|
|
273
|
+
return cardiacResult;
|
|
274
|
+
}
|
|
195
275
|
const positionGroups = getIPPGroups(imageIds);
|
|
196
276
|
if (!positionGroups) {
|
|
197
277
|
return { imageIdGroups: [imageIds], splittingTag: null };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function toFiniteNumber(value: number | undefined): number | undefined;
|
package/dist/esm/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "4.15.
|
|
1
|
+
export declare const version = "4.15.20";
|
package/dist/esm/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '4.15.
|
|
1
|
+
export const version = '4.15.20';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/core",
|
|
3
|
-
"version": "4.15.
|
|
3
|
+
"version": "4.15.20",
|
|
4
4
|
"description": "Cornerstone3D Core",
|
|
5
5
|
"module": "./dist/esm/index.js",
|
|
6
6
|
"types": "./dist/esm/index.d.ts",
|
|
@@ -97,5 +97,5 @@
|
|
|
97
97
|
"type": "individual",
|
|
98
98
|
"url": "https://ohif.org/donate"
|
|
99
99
|
},
|
|
100
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "35cc5f2d8ba3cb1c15abd8cf81231bf13ffaefb0"
|
|
101
101
|
}
|