@cornerstonejs/core 1.51.4 → 1.52.0
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/cjs/RenderingEngine/StackViewport.js +4 -4
- package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
- package/dist/cjs/types/displayArea.d.ts +3 -3
- package/dist/cjs/types/index.d.ts +2 -1
- package/dist/cjs/utilities/PointsManager.d.ts +33 -0
- package/dist/cjs/utilities/PointsManager.js +141 -0
- package/dist/cjs/utilities/PointsManager.js.map +1 -0
- package/dist/cjs/utilities/index.d.ts +2 -1
- package/dist/cjs/utilities/index.js +3 -1
- package/dist/cjs/utilities/index.js.map +1 -1
- package/dist/esm/RenderingEngine/StackViewport.js +4 -4
- package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
- package/dist/esm/utilities/PointsManager.js +138 -0
- package/dist/esm/utilities/PointsManager.js.map +1 -0
- package/dist/esm/utilities/index.js +2 -1
- package/dist/esm/utilities/index.js.map +1 -1
- package/dist/types/RenderingEngine/StackViewport.d.ts.map +1 -1
- package/dist/types/types/displayArea.d.ts +3 -3
- package/dist/types/types/displayArea.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +2 -1
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/utilities/PointsManager.d.ts +34 -0
- package/dist/types/utilities/PointsManager.d.ts.map +1 -0
- package/dist/types/utilities/index.d.ts +2 -1
- package/dist/types/utilities/index.d.ts.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +2 -2
- package/src/RenderingEngine/StackViewport.ts +9 -8
- package/src/types/displayArea.ts +3 -3
- package/src/types/index.ts +4 -0
- package/src/utilities/PointsManager.ts +260 -0
- package/src/utilities/index.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.52.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"type": "individual",
|
|
48
48
|
"url": "https://ohif.org/donate"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "f09289b1bbae632126eec5ba208dd89da1923a4d"
|
|
51
51
|
}
|
|
@@ -1962,18 +1962,19 @@ class StackViewport extends Viewport implements IStackViewport, IImagesLoader {
|
|
|
1962
1962
|
}
|
|
1963
1963
|
|
|
1964
1964
|
// If Photometric Interpretation is not the same for the next image we are trying to load
|
|
1965
|
-
// invalidate the stack to recreate the VTK imageData
|
|
1965
|
+
// invalidate the stack to recreate the VTK imageData. Get the PMI from
|
|
1966
|
+
// the base csImage if imageFrame isn't defined, which happens when the images
|
|
1967
|
+
// come from the volume
|
|
1966
1968
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1967
1969
|
const csImgFrame = (<any>this.csImage)?.imageFrame;
|
|
1968
1970
|
const imgFrame = image?.imageFrame;
|
|
1971
|
+
const photometricInterpretation =
|
|
1972
|
+
csImgFrame?.photometricInterpretation ||
|
|
1973
|
+
this.csImage?.photometricInterpretation;
|
|
1974
|
+
const newPhotometricInterpretation =
|
|
1975
|
+
imgFrame?.photometricInterpretation || image?.photometricInterpretation;
|
|
1969
1976
|
|
|
1970
|
-
|
|
1971
|
-
if (
|
|
1972
|
-
csImgFrame?.photometricInterpretation !==
|
|
1973
|
-
imgFrame?.photometricInterpretation ||
|
|
1974
|
-
this.csImage?.photometricInterpretation !==
|
|
1975
|
-
image?.photometricInterpretation
|
|
1976
|
-
) {
|
|
1977
|
+
if (photometricInterpretation !== newPhotometricInterpretation) {
|
|
1977
1978
|
this.stackInvalidated = true;
|
|
1978
1979
|
}
|
|
1979
1980
|
|
package/src/types/displayArea.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
type DisplayArea = {
|
|
2
|
-
imageArea
|
|
3
|
-
imageCanvasPoint
|
|
2
|
+
imageArea?: [number, number]; // areaX, areaY
|
|
3
|
+
imageCanvasPoint?: {
|
|
4
4
|
imagePoint: [number, number]; // imageX, imageY
|
|
5
5
|
canvasPoint: [number, number]; // canvasX, canvasY
|
|
6
6
|
};
|
|
7
|
-
storeAsInitialCamera
|
|
7
|
+
storeAsInitialCamera?: boolean;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
export default DisplayArea;
|
package/src/types/index.ts
CHANGED
|
@@ -114,6 +114,9 @@ import type BoundsIJK from './BoundsIJK';
|
|
|
114
114
|
import type { ImageVolumeProps } from './ImageVolumeProps';
|
|
115
115
|
import type { VolumeProps } from './VolumeProps';
|
|
116
116
|
import type BoundsLPS from './BoundsLPS';
|
|
117
|
+
// Sometimes the type is needed rather than the class, so import
|
|
118
|
+
// the type only here.
|
|
119
|
+
import type PointsManager from '../utilities/PointsManager';
|
|
117
120
|
|
|
118
121
|
export type {
|
|
119
122
|
// config
|
|
@@ -133,6 +136,7 @@ export type {
|
|
|
133
136
|
IRenderingEngine,
|
|
134
137
|
ScalingParameters,
|
|
135
138
|
PTScaling,
|
|
139
|
+
PointsManager,
|
|
136
140
|
Scaling,
|
|
137
141
|
IStreamingImageVolume,
|
|
138
142
|
IImage,
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import type { Point2, Point3, PointsXYZ } from '../types';
|
|
2
|
+
|
|
3
|
+
export type PolyDataPointConfiguration = {
|
|
4
|
+
/** The dimensionality of the points */
|
|
5
|
+
dimensions?: number;
|
|
6
|
+
/** The initial size of the backing array, not containing any data initially */
|
|
7
|
+
initialSize?: number;
|
|
8
|
+
/** The incremental size to grow by when required */
|
|
9
|
+
growSize?: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* PointsManager handles Point type data contained in a TypedArray representation
|
|
14
|
+
* where all the point data is consecutive from start to end. That is, the
|
|
15
|
+
* organization is `x0,y0,z0,x1,y1,z1,...,xn,yn,zn`. This optimizes the storage
|
|
16
|
+
* costs for large arrays of data, while still providing access to the point
|
|
17
|
+
* data as though it were a simple array of objects.
|
|
18
|
+
*
|
|
19
|
+
* This representation is efficient for storing large numbers of points and for
|
|
20
|
+
* transferring them amongst systems and is planned to have more methods added
|
|
21
|
+
* for generic manipulation of data.
|
|
22
|
+
*/
|
|
23
|
+
export default class PointsManager<T> {
|
|
24
|
+
/**
|
|
25
|
+
* Allow storage for an index value to indicate where this array is
|
|
26
|
+
* contained in terms of the index location.
|
|
27
|
+
*/
|
|
28
|
+
public kIndex: number;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Sources data for this array. Just used for external access, not updated
|
|
32
|
+
* here.
|
|
33
|
+
*/
|
|
34
|
+
public sources: PointsManager<T>[];
|
|
35
|
+
|
|
36
|
+
data: Float32Array;
|
|
37
|
+
_dimensions = 3;
|
|
38
|
+
_length = 0;
|
|
39
|
+
_byteSize = 4;
|
|
40
|
+
growSize = 128;
|
|
41
|
+
array: ArrayBuffer;
|
|
42
|
+
|
|
43
|
+
constructor(configuration: PolyDataPointConfiguration = {}) {
|
|
44
|
+
const {
|
|
45
|
+
initialSize = 1024,
|
|
46
|
+
dimensions = 3,
|
|
47
|
+
growSize = 128,
|
|
48
|
+
} = configuration;
|
|
49
|
+
const itemLength = initialSize * dimensions;
|
|
50
|
+
this.growSize = growSize;
|
|
51
|
+
// TODO - use resizeable arrays when they become available in all browsers
|
|
52
|
+
this.array = new ArrayBuffer(itemLength * this._byteSize);
|
|
53
|
+
this.data = new Float32Array(this.array);
|
|
54
|
+
this._dimensions = dimensions;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public forEach(func: (value: T, index: number) => void) {
|
|
58
|
+
for (let i = 0; i < this._length; i++) {
|
|
59
|
+
func(this.getPoint(i), i);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public get length() {
|
|
64
|
+
return this._length;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public get dimensions() {
|
|
68
|
+
return this._dimensions;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public get dimensionLength() {
|
|
72
|
+
return this._length * this._dimensions;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Returns a Float32Array view of the given point.
|
|
77
|
+
* Changes to the data in this point will affect the underlying data.
|
|
78
|
+
*
|
|
79
|
+
* @param index - positive index from start, or negative from end
|
|
80
|
+
* @returns Float32Array view onto the point at the given index
|
|
81
|
+
*/
|
|
82
|
+
public getPoint(index: number): T {
|
|
83
|
+
if (index < 0) {
|
|
84
|
+
index += this._length;
|
|
85
|
+
}
|
|
86
|
+
if (index < 0 || index >= this._length) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const offset = this._dimensions * index;
|
|
90
|
+
return this.data.subarray(
|
|
91
|
+
offset,
|
|
92
|
+
offset + this._dimensions
|
|
93
|
+
) as unknown as T;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Returns a `number[]` version of the given point.
|
|
98
|
+
* Changes to the array will NOT affect the underlying data.
|
|
99
|
+
*
|
|
100
|
+
* @param index - positive index from start, or negative from end
|
|
101
|
+
* @returns A new number[] instance of the given point.
|
|
102
|
+
*/
|
|
103
|
+
public getPointArray(index: number): T {
|
|
104
|
+
const array = [];
|
|
105
|
+
if (index < 0) {
|
|
106
|
+
index += this._length;
|
|
107
|
+
}
|
|
108
|
+
if (index < 0 || index >= this._length) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const offset = this._dimensions * index;
|
|
112
|
+
for (let i = 0; i < this._dimensions; i++) {
|
|
113
|
+
array.push(this.data[i + offset]);
|
|
114
|
+
}
|
|
115
|
+
return array as unknown as T;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Updates the array size as needed to allow for at least the given
|
|
120
|
+
* additional number of elements.
|
|
121
|
+
*/
|
|
122
|
+
protected grow(additionalSize = 1, growSize = this.growSize) {
|
|
123
|
+
if (
|
|
124
|
+
this.dimensionLength + additionalSize * this._dimensions <=
|
|
125
|
+
this.data.length
|
|
126
|
+
) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const newSize = this.data.length + growSize;
|
|
130
|
+
const newArray = new ArrayBuffer(
|
|
131
|
+
newSize * this._dimensions * this._byteSize
|
|
132
|
+
);
|
|
133
|
+
const newData = new Float32Array(newArray);
|
|
134
|
+
newData.set(this.data);
|
|
135
|
+
this.data = newData;
|
|
136
|
+
this.array = newArray;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Reverse the points in place.
|
|
141
|
+
*/
|
|
142
|
+
public reverse() {
|
|
143
|
+
const midLength = Math.floor(this._length / 2);
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < midLength; i++) {
|
|
146
|
+
const indexStart = i * this._dimensions;
|
|
147
|
+
const indexEnd = (this._length - 1 - i) * this._dimensions;
|
|
148
|
+
for (let dimension = 0; dimension < this._dimensions; dimension++) {
|
|
149
|
+
const valueStart = this.data[indexStart + dimension];
|
|
150
|
+
this.data[indexStart + dimension] = this.data[indexEnd + dimension];
|
|
151
|
+
this.data[indexEnd + dimension] = valueStart;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Push a new point onto this arrays object
|
|
158
|
+
*/
|
|
159
|
+
public push(point: T) {
|
|
160
|
+
this.grow(1);
|
|
161
|
+
const offset = this.length * this._dimensions;
|
|
162
|
+
for (let i = 0; i < this._dimensions; i++) {
|
|
163
|
+
this.data[i + offset] = point[i];
|
|
164
|
+
}
|
|
165
|
+
this._length++;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Maps the array onto another type.
|
|
170
|
+
*/
|
|
171
|
+
public map<R>(f: (value, index: number) => R): R[] {
|
|
172
|
+
const mapData = [];
|
|
173
|
+
for (let i = 0; i < this._length; i++) {
|
|
174
|
+
mapData.push(f(this.getPoint(i), i));
|
|
175
|
+
}
|
|
176
|
+
return mapData;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* A points object containing Float32Array instances referring to the underlying
|
|
181
|
+
* data, contained in a FloatArray32[] instance.
|
|
182
|
+
* Note - changes to the data store will directly affect the points value
|
|
183
|
+
* returned here, even if stored separately.
|
|
184
|
+
*/
|
|
185
|
+
public get points(): T[] {
|
|
186
|
+
return this.map((p) => p);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The XYZ representation of a points array is an object with three separate
|
|
191
|
+
* arrays, one for each of x,y and z, containing the point data, eg
|
|
192
|
+
* `x: {x0, x1, x2, ...., xn }`
|
|
193
|
+
* Will create just x,y for Point2 arrays.
|
|
194
|
+
*
|
|
195
|
+
* @returns An XYZ array
|
|
196
|
+
*/
|
|
197
|
+
public toXYZ(): PointsXYZ {
|
|
198
|
+
const xyz = { x: [], y: [] } as PointsXYZ;
|
|
199
|
+
if (this._dimensions >= 3) {
|
|
200
|
+
xyz.z = [];
|
|
201
|
+
}
|
|
202
|
+
const { x, y, z } = xyz;
|
|
203
|
+
|
|
204
|
+
this.forEach((p) => {
|
|
205
|
+
x.push(p[0]);
|
|
206
|
+
y.push(p[1]);
|
|
207
|
+
if (z) {
|
|
208
|
+
z.push(p[2]);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
return xyz;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Create an PointsArray3 from the x,y,z individual arrays (see toXYZ)
|
|
216
|
+
* Will create a Point3 array even if z is missing, with 0 as the value.
|
|
217
|
+
*/
|
|
218
|
+
public static fromXYZ({ x, y, z }: PointsXYZ): PointsManager<Point3> {
|
|
219
|
+
const array = PointsManager.create3(x.length);
|
|
220
|
+
let offset = 0;
|
|
221
|
+
for (let i = 0; i < x.length; i++) {
|
|
222
|
+
array.data[offset++] = x[i];
|
|
223
|
+
array.data[offset++] = y[i];
|
|
224
|
+
array.data[offset++] = z ? z[i] : 0;
|
|
225
|
+
}
|
|
226
|
+
array._length = x.length;
|
|
227
|
+
return array;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Select the given number of points from the array, evenly spaced at the
|
|
232
|
+
* given offset (which must be between `(-count,count)`)
|
|
233
|
+
*/
|
|
234
|
+
public subselect(count = 10, offset = 0): PointsManager<T> {
|
|
235
|
+
const selected = new PointsManager<T>({
|
|
236
|
+
initialSize: count,
|
|
237
|
+
dimensions: this._dimensions,
|
|
238
|
+
});
|
|
239
|
+
for (let i = 0; i < count; i++) {
|
|
240
|
+
const index =
|
|
241
|
+
(offset + Math.floor((this.length * i) / count)) % this.length;
|
|
242
|
+
selected.push(this.getPoint(index));
|
|
243
|
+
}
|
|
244
|
+
return selected;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Create a PointsManager<Point3> instance with available capacity of initialSize
|
|
249
|
+
*/
|
|
250
|
+
public static create3(initialSize = 128) {
|
|
251
|
+
return new PointsManager<Point3>({ initialSize, dimensions: 3 });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Create a PointsManager<Point2> instance with available capacity of initialSize
|
|
256
|
+
*/
|
|
257
|
+
public static create2(initialSize = 128) {
|
|
258
|
+
return new PointsManager<Point2>({ initialSize, dimensions: 2 });
|
|
259
|
+
}
|
|
260
|
+
}
|
package/src/utilities/index.ts
CHANGED
|
@@ -46,6 +46,7 @@ import spatialRegistrationMetadataProvider from './spatialRegistrationMetadataPr
|
|
|
46
46
|
import getViewportImageCornersInWorld from './getViewportImageCornersInWorld';
|
|
47
47
|
import hasNaNValues from './hasNaNValues';
|
|
48
48
|
import applyPreset from './applyPreset';
|
|
49
|
+
import PointsManager from './PointsManager';
|
|
49
50
|
import deepMerge from './deepMerge';
|
|
50
51
|
import getScalingParameters from './getScalingParameters';
|
|
51
52
|
import getScalarDataType from './getScalarDataType';
|
|
@@ -130,6 +131,7 @@ export {
|
|
|
130
131
|
hasNaNValues,
|
|
131
132
|
applyPreset,
|
|
132
133
|
deepMerge,
|
|
134
|
+
PointsManager,
|
|
133
135
|
getScalingParameters,
|
|
134
136
|
getScalarDataType,
|
|
135
137
|
colormap,
|