@cornerstonejs/core 2.3.3 → 2.4.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.
@@ -1,6 +1,5 @@
1
1
  import { loadAndCacheImage } from '../../loaders/imageLoader';
2
2
  import * as metaData from '../../metaData';
3
- import getMinMax from '../../utilities/getMinMax';
4
3
  import * as windowLevel from '../../utilities/windowLevel';
5
4
  import { RequestType } from '../../enums';
6
5
  import cache from '../../cache/cache';
@@ -95,8 +94,11 @@ async function getVOIFromMiddleSliceMinMax(imageVolume) {
95
94
  if (!imageVolume.referencedImageIds?.length) {
96
95
  image = await loadAndCacheImage(imageId, { ...options, ignoreCache: true });
97
96
  }
98
- const imageScalarData = image.getPixelData();
99
- const { min, max } = getMinMax(imageScalarData);
97
+ let { min, max } = image.voxelManager.getMinMax();
98
+ if (min.length > 1) {
99
+ min = Math.min(...min);
100
+ max = Math.max(...max);
101
+ }
100
102
  return {
101
103
  lower: min,
102
104
  upper: max,
@@ -0,0 +1,5 @@
1
+ declare enum VoxelManagerEnum {
2
+ RLE = "RLE",
3
+ Volume = "Volume"
4
+ }
5
+ export default VoxelManagerEnum;
@@ -0,0 +1,6 @@
1
+ var VoxelManagerEnum;
2
+ (function (VoxelManagerEnum) {
3
+ VoxelManagerEnum["RLE"] = "RLE";
4
+ VoxelManagerEnum["Volume"] = "Volume";
5
+ })(VoxelManagerEnum || (VoxelManagerEnum = {}));
6
+ export default VoxelManagerEnum;
@@ -13,5 +13,6 @@ import ViewportStatus from './ViewportStatus';
13
13
  import ImageQualityStatus from './ImageQualityStatus';
14
14
  import * as VideoEnums from './VideoEnums';
15
15
  import MetadataModules from './MetadataModules';
16
+ import VoxelManagerEnum from './VoxelManagerEnum';
16
17
  import { GenerateImageType } from './GenerateImageType';
17
- export { Events, BlendModes, CalibrationTypes, InterpolationType, RequestType, ViewportType, OrientationAxis, GeometryType, ContourType, VOILUTFunctionType, DynamicOperatorType, ViewportStatus, VideoEnums, MetadataModules, ImageQualityStatus, GenerateImageType, };
18
+ export { Events, BlendModes, CalibrationTypes, InterpolationType, RequestType, ViewportType, OrientationAxis, GeometryType, ContourType, VOILUTFunctionType, DynamicOperatorType, ViewportStatus, VideoEnums, MetadataModules, ImageQualityStatus, VoxelManagerEnum, GenerateImageType, };
@@ -13,5 +13,6 @@ import ViewportStatus from './ViewportStatus';
13
13
  import ImageQualityStatus from './ImageQualityStatus';
14
14
  import * as VideoEnums from './VideoEnums';
15
15
  import MetadataModules from './MetadataModules';
16
+ import VoxelManagerEnum from './VoxelManagerEnum';
16
17
  import { GenerateImageType } from './GenerateImageType';
17
- export { Events, BlendModes, CalibrationTypes, InterpolationType, RequestType, ViewportType, OrientationAxis, GeometryType, ContourType, VOILUTFunctionType, DynamicOperatorType, ViewportStatus, VideoEnums, MetadataModules, ImageQualityStatus, GenerateImageType, };
18
+ export { Events, BlendModes, CalibrationTypes, InterpolationType, RequestType, ViewportType, OrientationAxis, GeometryType, ContourType, VOILUTFunctionType, DynamicOperatorType, ViewportStatus, VideoEnums, MetadataModules, ImageQualityStatus, VoxelManagerEnum, GenerateImageType, };
@@ -1,4 +1,5 @@
1
1
  import type { IImage, ImageLoaderFn, Point2, Point3, Mat3, PixelDataTypedArrayString, PixelDataTypedArray } from '../types';
2
+ import VoxelManagerEnum from '../enums/VoxelManagerEnum';
2
3
  export interface ImageLoaderOptions {
3
4
  priority: number;
4
5
  requestType: string;
@@ -11,6 +12,7 @@ interface LocalImageOptions {
11
12
  targetBuffer?: {
12
13
  type: PixelDataTypedArrayString;
13
14
  };
15
+ voxelRepresentation?: VoxelManagerEnum;
14
16
  dimensions?: Point2;
15
17
  spacing?: Point2;
16
18
  origin?: Point3;
@@ -31,6 +33,7 @@ export declare function createAndCacheDerivedImages(referencedImageIds: string[]
31
33
  targetBuffer?: {
32
34
  type: PixelDataTypedArrayString;
33
35
  };
36
+ voxelRepresentation?: VoxelManagerEnum;
34
37
  }): IImage[];
35
38
  export declare function createAndCacheLocalImage(imageId: string, options: LocalImageOptions): IImage;
36
39
  export declare function cancelLoadImage(imageId: string): void;
@@ -8,6 +8,7 @@ import uuidv4 from '../utilities/uuidv4';
8
8
  import VoxelManager from '../utilities/VoxelManager';
9
9
  import imageLoadPoolManager from '../requestPool/imageLoadPoolManager';
10
10
  import * as metaData from '../metaData';
11
+ import VoxelManagerEnum from '../enums/VoxelManagerEnum';
11
12
  const imageLoaders = {};
12
13
  let unknownImageLoader;
13
14
  function loadImageFromImageLoader(imageId, options) {
@@ -85,7 +86,7 @@ export function createAndCacheDerivedImage(referencedImageId, options = {}) {
85
86
  if (options.imageId === undefined) {
86
87
  options.imageId = `derived:${uuidv4()}`;
87
88
  }
88
- const { imageId, skipCreateBuffer, onCacheAdd } = options;
89
+ const { imageId, skipCreateBuffer, onCacheAdd, voxelRepresentation } = options;
89
90
  const imagePlaneModule = metaData.get('imagePlaneModule', referencedImageId);
90
91
  const length = imagePlaneModule.rows * imagePlaneModule.columns;
91
92
  const { TypedArrayConstructor } = getBufferConfiguration(options.targetBuffer?.type, length);
@@ -126,6 +127,7 @@ export function createAndCacheDerivedImage(referencedImageId, options = {}) {
126
127
  targetBuffer: {
127
128
  type: imageScalarData.constructor.name,
128
129
  },
130
+ voxelRepresentation,
129
131
  dimensions: [imagePlaneModule.columns, imagePlaneModule.rows],
130
132
  spacing: [
131
133
  imagePlaneModule.columnPixelSpacing,
@@ -161,7 +163,7 @@ export function createAndCacheDerivedImages(referencedImageIds, options = {}) {
161
163
  return images;
162
164
  }
163
165
  export function createAndCacheLocalImage(imageId, options) {
164
- const { scalarData, origin, direction, targetBuffer, skipCreateBuffer, onCacheAdd, frameOfReferenceUID, } = options;
166
+ const { scalarData, origin, direction, targetBuffer, skipCreateBuffer, onCacheAdd, frameOfReferenceUID, voxelRepresentation, } = options;
165
167
  const dimensions = options.dimensions;
166
168
  const spacing = options.spacing;
167
169
  if (!dimensions || !spacing) {
@@ -196,7 +198,7 @@ export function createAndCacheLocalImage(imageId, options) {
196
198
  scalarDataToUse = scalarData;
197
199
  }
198
200
  else if (!skipCreateBuffer) {
199
- const { numBytes, TypedArrayConstructor } = getBufferConfiguration(targetBuffer?.type, length);
201
+ const { TypedArrayConstructor } = getBufferConfiguration(targetBuffer?.type, length);
200
202
  const imageScalarData = new TypedArrayConstructor(length);
201
203
  scalarDataToUse = imageScalarData;
202
204
  }
@@ -245,12 +247,14 @@ export function createAndCacheLocalImage(imageId, options) {
245
247
  metadata: metadata[type] || {},
246
248
  });
247
249
  });
248
- const voxelManager = VoxelManager.createImageVoxelManager({
249
- height,
250
- width,
251
- numberOfComponents,
252
- scalarData: scalarDataToUse,
253
- });
250
+ const voxelManager = (voxelRepresentation === VoxelManagerEnum.RLE &&
251
+ VoxelManager.createRLEImageVoxelManager({ dimensions })) ||
252
+ VoxelManager.createImageVoxelManager({
253
+ height,
254
+ width,
255
+ numberOfComponents,
256
+ scalarData: scalarDataToUse,
257
+ });
254
258
  let minPixelValue = scalarDataToUse[0];
255
259
  let maxPixelValue = scalarDataToUse[0];
256
260
  for (let i = 1; i < scalarDataToUse.length; i++) {
@@ -1,4 +1,5 @@
1
1
  import '@kitware/vtk.js/Rendering/Profiles/Volume';
2
+ import type VoxelManagerEnum from '../enums/VoxelManagerEnum';
2
3
  import type { Point3, Metadata, Mat3, IImageVolume, VolumeLoaderFn, PixelDataTypedArray, PixelDataTypedArrayString, IStreamingImageVolume } from '../types';
3
4
  interface VolumeLoaderOptions {
4
5
  imageIds: string[];
@@ -9,6 +10,7 @@ interface DerivedVolumeOptions {
9
10
  targetBuffer?: {
10
11
  type: PixelDataTypedArrayString;
11
12
  };
13
+ voxelRepresentation?: VoxelManagerEnum;
12
14
  }
13
15
  export interface LocalVolumeOptions {
14
16
  metadata: Metadata;
@@ -65,6 +65,7 @@ export function createAndCacheDerivedVolume(referencedVolumeId, options) {
65
65
  throw new Error(`Cannot created derived volume: Referenced volume with id ${referencedVolumeId} does not exist.`);
66
66
  }
67
67
  let { volumeId } = options;
68
+ const { voxelRepresentation } = options;
68
69
  if (volumeId === undefined) {
69
70
  volumeId = uuidv4();
70
71
  }
@@ -74,6 +75,7 @@ export function createAndCacheDerivedVolume(referencedVolumeId, options) {
74
75
  : referencedVolume.imageIds ?? [];
75
76
  const derivedImages = createAndCacheDerivedImages(referencedImageIds, {
76
77
  targetBuffer: options.targetBuffer,
78
+ voxelRepresentation,
77
79
  });
78
80
  const dataType = derivedImages[0].dataType;
79
81
  const derivedVolumeImageIds = derivedImages.map((image) => image.imageId);
@@ -222,7 +224,10 @@ export function getUnknownVolumeLoaderSchema() {
222
224
  export function createAndCacheDerivedLabelmapVolume(referencedVolumeId, options = {}) {
223
225
  return createAndCacheDerivedVolume(referencedVolumeId, {
224
226
  ...options,
225
- targetBuffer: { type: 'Uint8Array' },
227
+ targetBuffer: {
228
+ type: 'Uint8Array',
229
+ ...options?.targetBuffer,
230
+ },
226
231
  });
227
232
  }
228
233
  export function createLocalLabelmapVolume(options, volumeId, preventCache = false) {
@@ -1,2 +1,2 @@
1
1
  export type PixelDataTypedArray = Float32Array | Int16Array | Uint16Array | Uint8Array | Int8Array | Uint8ClampedArray;
2
- export type PixelDataTypedArrayString = 'Float32Array' | 'Int16Array' | 'Uint16Array' | 'Uint8Array' | 'Int8Array' | 'Uint8ClampedArray';
2
+ export type PixelDataTypedArrayString = 'Float32Array' | 'Int16Array' | 'Uint16Array' | 'Uint8Array' | 'Int8Array' | 'Uint8ClampedArray' | 'none';
@@ -20,6 +20,7 @@ export default class PointsManager<T> {
20
20
  getPointArray(index: number): T;
21
21
  protected grow(additionalSize?: number, growSize?: number): void;
22
22
  reverse(): void;
23
+ getTypedArray(): Float32Array;
23
24
  push(point: T): void;
24
25
  map<R>(f: (value: any, index: number) => R): R[];
25
26
  get points(): T[];
@@ -73,6 +73,9 @@ export default class PointsManager {
73
73
  }
74
74
  }
75
75
  }
76
+ getTypedArray() {
77
+ return this.data;
78
+ }
76
79
  push(point) {
77
80
  this.grow(1);
78
81
  const offset = this.length * this._dimensions;
@@ -1,21 +1,57 @@
1
- import type { PixelDataTypedArray, RLERun } from '../types';
1
+ import type Point3 from '../types/Point3';
2
+ import type BoundsIJK from '../types/BoundsIJK';
3
+ import type { PixelDataTypedArray } from '../types';
4
+ export type RLERun<T> = {
5
+ value: T;
6
+ start: number;
7
+ end: number;
8
+ };
9
+ export type PlaneNormalizer = {
10
+ toIJK: (ijkPrime: Point3) => Point3;
11
+ fromIJK: (ijk: Point3) => Point3;
12
+ boundsIJKPrime: BoundsIJK;
13
+ };
2
14
  export default class RLEVoxelMap<T> {
15
+ normalizer: PlaneNormalizer;
3
16
  protected rows: Map<number, RLERun<T>[]>;
4
- protected height: number;
5
- protected width: number;
6
- protected depth: number;
17
+ height: number;
18
+ width: number;
19
+ depth: number;
7
20
  protected jMultiple: number;
8
21
  protected kMultiple: number;
9
- protected numberOfComponents: number;
22
+ protected numComps: number;
10
23
  defaultValue: T;
11
24
  pixelDataConstructor: Uint8ArrayConstructor;
25
+ static copyMap<T>(destination: RLEVoxelMap<T>, source: RLEVoxelMap<T>): void;
12
26
  constructor(width: number, height: number, depth?: number);
27
+ static getScalarData: (ArrayType?: Uint8ClampedArrayConstructor) => Uint8ClampedArray;
28
+ updateScalarData: (scalarData: PixelDataTypedArray) => void;
13
29
  get: (index: number) => T;
14
- protected getRLE(i: number, j: number, k?: number): RLERun<T> | undefined;
30
+ toIJK(index: number): Point3;
31
+ toIndex([i, j, k]: Point3): number;
32
+ protected getRLE(i: number, j: number, k?: number): RLERun<T>;
33
+ has(index: number): boolean;
34
+ delete(index: number): void;
15
35
  protected findIndex(row: RLERun<T>[], i: number): number;
36
+ forEach(callback: any, options?: {
37
+ rowModified?: boolean;
38
+ }): void;
39
+ forEachRow(callback: any): void;
16
40
  getRun: (j: number, k: number) => RLERun<T>[];
17
41
  set: (index: number, value: T) => void;
18
42
  clear(): void;
19
43
  keys(): number[];
20
44
  getPixelData(k?: number, pixelData?: PixelDataTypedArray): PixelDataTypedArray;
45
+ floodFill(i: number, j: number, k: number, value: T, options?: {
46
+ planar?: boolean;
47
+ diagonals?: boolean;
48
+ singlePlane?: boolean;
49
+ }): number;
50
+ private flood;
51
+ fillFrom(getter: (i: number, j: number, k: number) => T, boundsIJK: BoundsIJK): void;
52
+ findAdjacents(item: [RLERun<T>, number, number, Point3[]?], { diagonals, planar, singlePlane }: {
53
+ diagonals?: boolean;
54
+ planar?: boolean;
55
+ singlePlane?: boolean;
56
+ }): any[];
21
57
  }
@@ -1,4 +1,29 @@
1
+ const ADJACENT_ALL = [
2
+ [0, -1, 0],
3
+ [0, 1, 0],
4
+ [0, 0, -1],
5
+ [0, 0, 1],
6
+ ];
7
+ const ADJACENT_SINGLE_PLANE = [
8
+ [0, -1, 0],
9
+ [0, 1, 0],
10
+ ];
11
+ const ADJACENT_IN = [
12
+ [0, -1, 0],
13
+ [0, 1, 0],
14
+ [0, 0, -1],
15
+ ];
16
+ const ADJACENT_OUT = [
17
+ [0, -1, 0],
18
+ [0, 1, 0],
19
+ [0, 0, 1],
20
+ ];
1
21
  export default class RLEVoxelMap {
22
+ static copyMap(destination, source) {
23
+ for (const [index, row] of source.rows) {
24
+ destination.rows.set(index, structuredClone(row));
25
+ }
26
+ }
2
27
  constructor(width, height, depth = 1) {
3
28
  this.rows = new Map();
4
29
  this.height = 1;
@@ -6,14 +31,23 @@ export default class RLEVoxelMap {
6
31
  this.depth = 1;
7
32
  this.jMultiple = 1;
8
33
  this.kMultiple = 1;
9
- this.numberOfComponents = 1;
10
- this.defaultValue = 0;
34
+ this.numComps = 1;
11
35
  this.pixelDataConstructor = Uint8Array;
36
+ this.updateScalarData = function (scalarData) {
37
+ scalarData.fill(0);
38
+ const callback = (index, rle, row) => {
39
+ const { start, end, value } = rle;
40
+ for (let i = start; i < end; i++) {
41
+ scalarData[index + i] = value;
42
+ }
43
+ };
44
+ this.forEach(callback);
45
+ };
12
46
  this.get = (index) => {
13
47
  const i = index % this.jMultiple;
14
48
  const j = (index - i) / this.jMultiple;
15
49
  const rle = this.getRLE(i, j);
16
- return rle?.value || this.defaultValue;
50
+ return rle?.value ?? this.defaultValue;
17
51
  };
18
52
  this.getRun = (j, k) => {
19
53
  const runIndex = j + k * this.height;
@@ -21,7 +55,7 @@ export default class RLEVoxelMap {
21
55
  };
22
56
  this.set = (index, value) => {
23
57
  if (value === undefined) {
24
- throw new Error(`Can't set undefined at ${index % this.width}`);
58
+ return;
25
59
  }
26
60
  const i = index % this.width;
27
61
  const j = (index - i) / this.width;
@@ -50,7 +84,7 @@ export default class RLEVoxelMap {
50
84
  const insertIndex = isAfter ? rleIndex + 1 : rleIndex;
51
85
  const rlePrev = isAfter ? rle1 : rle0;
52
86
  let rleNext = isAfter ? row[rleIndex + 1] : rle1;
53
- if (rlePrev?.value === value && rlePrev.end === i) {
87
+ if (rlePrev?.value === value && rlePrev?.end === i) {
54
88
  rlePrev.end++;
55
89
  if (rleNext?.value === value && rleNext.start === i + 1) {
56
90
  rlePrev.end = rleNext.end;
@@ -82,7 +116,7 @@ export default class RLEVoxelMap {
82
116
  if (rleNext?.start === i && rleNext.end === i + 1) {
83
117
  rleNext.value = value;
84
118
  const nextnext = row[rleIndex + 1];
85
- if (nextnext?.start == i + 1 && nextnext?.value === value) {
119
+ if (nextnext?.start == i + 1 && nextnext.value === value) {
86
120
  row.splice(rleIndex + 1, 1);
87
121
  rleNext.end = nextnext.end;
88
122
  }
@@ -111,6 +145,20 @@ export default class RLEVoxelMap {
111
145
  this.jMultiple = width;
112
146
  this.kMultiple = this.jMultiple * height;
113
147
  }
148
+ static { this.getScalarData = function (ArrayType = Uint8ClampedArray) {
149
+ const scalarData = new ArrayType(this.frameSize);
150
+ this.map.updateScalarData(scalarData);
151
+ return scalarData;
152
+ }; }
153
+ toIJK(index) {
154
+ const i = index % this.jMultiple;
155
+ const j = ((index - i) / this.jMultiple) % this.height;
156
+ const k = Math.floor(index / this.kMultiple);
157
+ return [i, j, k];
158
+ }
159
+ toIndex([i, j, k]) {
160
+ return i + k * this.kMultiple + j * this.jMultiple;
161
+ }
114
162
  getRLE(i, j, k = 0) {
115
163
  const row = this.rows.get(j + k * this.height);
116
164
  if (!row) {
@@ -120,6 +168,46 @@ export default class RLEVoxelMap {
120
168
  const rle = row[index];
121
169
  return i >= rle?.start ? rle : undefined;
122
170
  }
171
+ has(index) {
172
+ const i = index % this.jMultiple;
173
+ const j = (index - i) / this.jMultiple;
174
+ const rle = this.getRLE(i, j);
175
+ return rle?.value !== undefined;
176
+ }
177
+ delete(index) {
178
+ const i = index % this.width;
179
+ const j = (index - i) / this.width;
180
+ const row = this.rows.get(j);
181
+ if (!row) {
182
+ return;
183
+ }
184
+ const rleIndex = this.findIndex(row, i);
185
+ const rle = row[rleIndex];
186
+ if (!rle || rle.start > i) {
187
+ return;
188
+ }
189
+ if (rle.end === i + 1) {
190
+ rle.end--;
191
+ if (rle.start >= rle.end) {
192
+ row.splice(rleIndex, 1);
193
+ if (!row.length) {
194
+ this.rows.delete(j);
195
+ }
196
+ }
197
+ return;
198
+ }
199
+ if (rle.start === i) {
200
+ rle.start++;
201
+ return;
202
+ }
203
+ const newRle = {
204
+ value: rle.value,
205
+ start: i + 1,
206
+ end: rle.end,
207
+ };
208
+ rle.end = i;
209
+ row.splice(rleIndex + 1, 0, newRle);
210
+ }
123
211
  findIndex(row, i) {
124
212
  for (let index = 0; index < row.length; index++) {
125
213
  const { end: iEnd } = row[index];
@@ -129,6 +217,20 @@ export default class RLEVoxelMap {
129
217
  }
130
218
  return row.length;
131
219
  }
220
+ forEach(callback, options) {
221
+ const rowModified = options?.rowModified;
222
+ for (const [baseIndex, row] of this.rows) {
223
+ const rowToUse = rowModified ? [...row] : row;
224
+ for (const rle of rowToUse) {
225
+ callback(baseIndex * this.width, rle, row);
226
+ }
227
+ }
228
+ }
229
+ forEachRow(callback) {
230
+ for (const [baseIndex, row] of this.rows) {
231
+ callback(baseIndex * this.width, row);
232
+ }
233
+ }
132
234
  clear() {
133
235
  this.rows.clear();
134
236
  }
@@ -137,18 +239,18 @@ export default class RLEVoxelMap {
137
239
  }
138
240
  getPixelData(k = 0, pixelData) {
139
241
  if (!pixelData) {
140
- pixelData = new this.pixelDataConstructor(this.width * this.height * this.numberOfComponents);
242
+ pixelData = new this.pixelDataConstructor(this.width * this.height * this.numComps);
141
243
  }
142
244
  else {
143
245
  pixelData.fill(0);
144
246
  }
145
- const { width, height, numberOfComponents } = this;
247
+ const { width, height, numComps } = this;
146
248
  for (let j = 0; j < height; j++) {
147
249
  const row = this.getRun(j, k);
148
250
  if (!row) {
149
251
  continue;
150
252
  }
151
- if (numberOfComponents === 1) {
253
+ if (numComps === 1) {
152
254
  for (const rle of row) {
153
255
  const rowOffset = j * width;
154
256
  const { start, end, value } = rle;
@@ -159,10 +261,10 @@ export default class RLEVoxelMap {
159
261
  }
160
262
  else {
161
263
  for (const rle of row) {
162
- const rowOffset = j * width * numberOfComponents;
264
+ const rowOffset = j * width * numComps;
163
265
  const { start, end, value } = rle;
164
- for (let i = start; i < end; i += numberOfComponents) {
165
- for (let comp = 0; comp < numberOfComponents; comp++) {
266
+ for (let i = start; i < end; i += numComps) {
267
+ for (let comp = 0; comp < numComps; comp++) {
166
268
  pixelData[rowOffset + i + comp] = value[comp];
167
269
  }
168
270
  }
@@ -171,4 +273,103 @@ export default class RLEVoxelMap {
171
273
  }
172
274
  return pixelData;
173
275
  }
276
+ floodFill(i, j, k, value, options) {
277
+ const rle = this.getRLE(i, j, k);
278
+ if (!rle) {
279
+ throw new Error(`Initial point ${i},${j},${k} isn't in the RLE`);
280
+ }
281
+ const stack = [[rle, j, k]];
282
+ const replaceValue = rle.value;
283
+ if (replaceValue === value) {
284
+ throw new Error(`source (${replaceValue}) and destination (${value}) are identical`);
285
+ }
286
+ return this.flood(stack, replaceValue, value, options);
287
+ }
288
+ flood(stack, sourceValue, value, options) {
289
+ let sum = 0;
290
+ const { planar = true, diagonals = true, singlePlane = false, } = options || {};
291
+ const childOptions = { planar, diagonals, singlePlane };
292
+ while (stack.length) {
293
+ const top = stack.pop();
294
+ const [current] = top;
295
+ if (current.value !== sourceValue) {
296
+ continue;
297
+ }
298
+ current.value = value;
299
+ sum += current.end - current.start;
300
+ const adjacents = this.findAdjacents(top, childOptions).filter((adjacent) => adjacent && adjacent[0].value === sourceValue);
301
+ stack.push(...adjacents);
302
+ }
303
+ return sum;
304
+ }
305
+ fillFrom(getter, boundsIJK) {
306
+ for (let k = boundsIJK[2][0]; k <= boundsIJK[2][1]; k++) {
307
+ for (let j = boundsIJK[1][0]; j <= boundsIJK[1][1]; j++) {
308
+ let rle;
309
+ let row;
310
+ for (let i = boundsIJK[0][0]; i <= boundsIJK[0][1]; i++) {
311
+ const value = getter(i, j, k);
312
+ if (value === undefined) {
313
+ rle = undefined;
314
+ continue;
315
+ }
316
+ if (!row) {
317
+ row = [];
318
+ this.rows.set(j + k * this.height, row);
319
+ }
320
+ if (rle && rle.value !== value) {
321
+ rle = undefined;
322
+ }
323
+ if (!rle) {
324
+ rle = { start: i, end: i, value };
325
+ row.push(rle);
326
+ }
327
+ rle.end++;
328
+ }
329
+ }
330
+ }
331
+ }
332
+ findAdjacents(item, { diagonals = true, planar = true, singlePlane = false }) {
333
+ const [rle, j, k, adjacentsDelta] = item;
334
+ const { start, end } = rle;
335
+ const leftRle = start > 0 && this.getRLE(start - 1, j, k);
336
+ const rightRle = end < this.width && this.getRLE(end, j, k);
337
+ const range = diagonals
338
+ ? [start > 0 ? start - 1 : start, end < this.width ? end + 1 : end]
339
+ : [start, end];
340
+ const adjacents = [];
341
+ if (leftRle) {
342
+ adjacents.push([leftRle, j, k]);
343
+ }
344
+ if (rightRle) {
345
+ adjacents.push([rightRle, j, k]);
346
+ }
347
+ for (const delta of adjacentsDelta ||
348
+ (singlePlane ? ADJACENT_SINGLE_PLANE : ADJACENT_ALL)) {
349
+ const [, delta1, delta2] = delta;
350
+ const testJ = delta1 + j;
351
+ const testK = delta2 + k;
352
+ if (testJ < 0 || testJ >= this.height) {
353
+ continue;
354
+ }
355
+ if (testK < 0 || testK >= this.depth) {
356
+ continue;
357
+ }
358
+ const row = this.getRun(testJ, testK);
359
+ if (!row) {
360
+ continue;
361
+ }
362
+ for (const testRle of row) {
363
+ const newAdjacentDelta = adjacentsDelta ||
364
+ (singlePlane && ADJACENT_SINGLE_PLANE) ||
365
+ (planar && delta2 > 0 && ADJACENT_OUT) ||
366
+ (planar && delta2 < 0 && ADJACENT_IN) ||
367
+ ADJACENT_ALL;
368
+ if (!(testRle.end <= range[0] || testRle.start >= range[1])) {
369
+ adjacents.push([testRle, testJ, testK, newAdjacentDelta]);
370
+ }
371
+ }
372
+ }
373
+ return adjacents;
374
+ }
174
375
  }
@@ -1,4 +1,4 @@
1
- import type { BoundsIJK, Point3, PixelDataTypedArray, IImage, RGB, CPUImageData, IVoxelManager, IRLEVoxelMap } from '../types';
1
+ import type { BoundsIJK, Point3, PixelDataTypedArray, IImage, RGB, CPUImageData, IVoxelManager, IRLEVoxelMap, Point2 } from '../types';
2
2
  import type vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
3
3
  export default class VoxelManager<T> {
4
4
  modifiedSlices: Set<number>;
@@ -7,30 +7,45 @@ export default class VoxelManager<T> {
7
7
  sourceVoxelManager: IVoxelManager<T>;
8
8
  isInObject: (pointLPS: any, pointIJK: any) => boolean;
9
9
  readonly dimensions: Point3;
10
- numberOfComponents: number;
10
+ readonly numberOfComponents: any;
11
11
  getCompleteScalarDataArray?: () => ArrayLike<number>;
12
12
  setCompleteScalarDataArray?: (scalarData: ArrayLike<number>) => void;
13
13
  getRange: () => [number, number];
14
14
  private scalarData;
15
15
  private _sliceDataCache;
16
+ readonly _id: string;
16
17
  points: Set<number>;
17
18
  width: number;
18
19
  frameSize: number;
19
- _get: (index: number) => T;
20
- _set: (index: number, v: T) => boolean;
21
- _getConstructor?: () => new (length: number) => PixelDataTypedArray;
20
+ readonly _get: (index: number) => T;
21
+ readonly _set: (index: number, v: T) => boolean;
22
+ readonly _getConstructor?: () => new (length: number) => PixelDataTypedArray;
22
23
  _getScalarDataLength?: () => number;
23
- _getScalarData?: () => PixelDataTypedArray;
24
+ _getScalarData?: () => ArrayLike<number>;
25
+ _updateScalarData?: (scalarData: ArrayLike<number>) => PixelDataTypedArray;
24
26
  _getSliceData: (args: {
25
27
  sliceIndex: number;
26
28
  slicePlane: number;
27
29
  }) => PixelDataTypedArray;
28
- constructor(dimensions: any, _get: (index: number) => T, _set?: (index: number, v: T) => boolean);
30
+ constructor(dimensions: any, options: {
31
+ _get: (index: number) => T;
32
+ _set?: (index: number, v: T) => boolean;
33
+ _getScalarData?: () => ArrayLike<number>;
34
+ _id?: string;
35
+ _updateScalarData?: (scalarData: ArrayLike<number>) => PixelDataTypedArray;
36
+ numberOfComponents?: number;
37
+ scalarData?: ArrayLike<number>;
38
+ _getConstructor?: () => new (length: number) => PixelDataTypedArray;
39
+ });
29
40
  getAtIJK: (i: any, j: any, k: any) => T;
30
41
  setAtIJK: (i: number, j: number, k: number, v: any) => boolean;
31
42
  getAtIJKPoint: ([i, j, k]: [any, any, any]) => T;
32
43
  setAtIJKPoint: ([i, j, k]: Point3, v: any) => void;
33
44
  getAtIndex: (index: any) => T;
45
+ getMinMax(): {
46
+ min: any;
47
+ max: any;
48
+ };
34
49
  setAtIndex: (index: any, v: any) => boolean;
35
50
  toIJK(index: number): Point3;
36
51
  getMiddleSliceData: () => PixelDataTypedArray;
@@ -47,8 +62,9 @@ export default class VoxelManager<T> {
47
62
  isInObject?: (pointLPS: any, pointIJK: any) => boolean;
48
63
  returnPoints?: boolean;
49
64
  imageData?: vtkImageData | CPUImageData;
50
- }) => any[];
51
- getScalarData(): PixelDataTypedArray;
65
+ }) => void | any[];
66
+ rleForEach(callback: any, options?: any): void;
67
+ getScalarData(storeScalarData?: boolean): PixelDataTypedArray;
52
68
  setScalarData(newScalarData: PixelDataTypedArray): void;
53
69
  getScalarDataLength(): number;
54
70
  get sizeInBytes(): number;
@@ -96,13 +112,17 @@ export default class VoxelManager<T> {
96
112
  static createHistoryVoxelManager<T>({ sourceVoxelManager, }: {
97
113
  sourceVoxelManager: VoxelManager<T>;
98
114
  }): VoxelManager<T>;
115
+ static createRLEHistoryVoxelManager<T>(sourceVoxelManager: VoxelManager<T>): VoxelManager<T>;
99
116
  static createLazyVoxelManager<T>({ dimensions, planeFactory, }: {
100
117
  dimensions: Point3;
101
118
  planeFactory: (width: number, height: number) => T;
102
119
  }): VoxelManager<T>;
103
- static createRLEVoxelManager<T>({ dimensions, }: {
120
+ static createRLEVolumeVoxelManager<T>({ dimensions, }: {
104
121
  dimensions: Point3;
105
122
  }): VoxelManager<T>;
123
+ static createRLEImageVoxelManager<T>({ dimensions, }: {
124
+ dimensions: Point2;
125
+ }): VoxelManager<T>;
106
126
  static addInstanceToImage(image: IImage): void;
107
127
  static: any;
108
128
  }