@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.
Files changed (33) hide show
  1. package/dist/cjs/RenderingEngine/StackViewport.js +4 -4
  2. package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
  3. package/dist/cjs/types/displayArea.d.ts +3 -3
  4. package/dist/cjs/types/index.d.ts +2 -1
  5. package/dist/cjs/utilities/PointsManager.d.ts +33 -0
  6. package/dist/cjs/utilities/PointsManager.js +141 -0
  7. package/dist/cjs/utilities/PointsManager.js.map +1 -0
  8. package/dist/cjs/utilities/index.d.ts +2 -1
  9. package/dist/cjs/utilities/index.js +3 -1
  10. package/dist/cjs/utilities/index.js.map +1 -1
  11. package/dist/esm/RenderingEngine/StackViewport.js +4 -4
  12. package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
  13. package/dist/esm/utilities/PointsManager.js +138 -0
  14. package/dist/esm/utilities/PointsManager.js.map +1 -0
  15. package/dist/esm/utilities/index.js +2 -1
  16. package/dist/esm/utilities/index.js.map +1 -1
  17. package/dist/types/RenderingEngine/StackViewport.d.ts.map +1 -1
  18. package/dist/types/types/displayArea.d.ts +3 -3
  19. package/dist/types/types/displayArea.d.ts.map +1 -1
  20. package/dist/types/types/index.d.ts +2 -1
  21. package/dist/types/types/index.d.ts.map +1 -1
  22. package/dist/types/utilities/PointsManager.d.ts +34 -0
  23. package/dist/types/utilities/PointsManager.d.ts.map +1 -0
  24. package/dist/types/utilities/index.d.ts +2 -1
  25. package/dist/types/utilities/index.d.ts.map +1 -1
  26. package/dist/umd/index.js +1 -1
  27. package/dist/umd/index.js.map +1 -1
  28. package/package.json +2 -2
  29. package/src/RenderingEngine/StackViewport.ts +9 -8
  30. package/src/types/displayArea.ts +3 -3
  31. package/src/types/index.ts +4 -0
  32. package/src/utilities/PointsManager.ts +260 -0
  33. 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.51.4",
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": "2cfe6d0ac8a254b0f6138fac6072d382333c381e"
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
- // if a volume is decached into images then the imageFrame will be undefined
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
 
@@ -1,10 +1,10 @@
1
1
  type DisplayArea = {
2
- imageArea: [number, number]; // areaX, areaY
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: boolean;
7
+ storeAsInitialCamera?: boolean;
8
8
  };
9
9
 
10
10
  export default DisplayArea;
@@ -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
+ }
@@ -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,