@cornerstonejs/core 2.0.0-beta.19 → 2.0.0-beta.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.
@@ -62,7 +62,7 @@ declare abstract class BaseVolumeViewport extends Viewport implements IVolumeVie
62
62
  getImageIds: (volumeId?: string) => Array<string>;
63
63
  abstract getCurrentImageId(): string;
64
64
  protected getVolumeId(specifier?: ViewReferenceSpecifier): string;
65
- getReferenceId(specifier?: ViewReferenceSpecifier): string;
65
+ getViewReferenceId(specifier?: ViewReferenceSpecifier): string;
66
66
  abstract setBlendMode(blendMode: BlendModes, filterActorUIDs?: Array<string>, immediate?: boolean): void;
67
67
  abstract setSlabThickness(slabThickness: number, filterActorUIDs?: Array<string>): void;
68
68
  abstract resetSlabThickness(): void;
@@ -713,7 +713,7 @@ class BaseVolumeViewport extends Viewport {
713
713
  initializeColorTransferFunction(volumeInputArray) {
714
714
  const selectedVolumeId = volumeInputArray[0].volumeId;
715
715
  const colorTransferFunction = this._getOrCreateColorTransferFunction(selectedVolumeId);
716
- if (!this.initialTransferFunctionNodes) {
716
+ if (!this.initialTransferFunctionNodes && colorTransferFunction) {
717
717
  this.initialTransferFunctionNodes = getTransferFunctionNodes(colorTransferFunction);
718
718
  }
719
719
  }
@@ -788,6 +788,7 @@ class BaseVolumeViewport extends Viewport {
788
788
  imageData: actor.getMapper().getInputData(),
789
789
  metadata: {
790
790
  Modality: volume?.metadata?.Modality,
791
+ FrameOfReferenceUID: volume?.metadata?.FrameOfReferenceUID,
791
792
  },
792
793
  scaling: volume?.scaling,
793
794
  hasPixelSpacing: true,
@@ -853,7 +854,7 @@ class BaseVolumeViewport extends Viewport {
853
854
  return actorEntries.find((actorEntry) => actorEntry.actor.getClassName() === 'vtkVolume' &&
854
855
  actorEntry.uid === specifier.volumeId)?.uid;
855
856
  }
856
- getReferenceId(specifier = {}) {
857
+ getViewReferenceId(specifier = {}) {
857
858
  let { volumeId, sliceIndex: sliceIndex } = specifier;
858
859
  if (!volumeId) {
859
860
  const actorEntries = this.getActors();
@@ -178,10 +178,10 @@ declare class StackViewport extends Viewport implements IStackViewport, IImagesL
178
178
  private _getValidVOILUTFunction;
179
179
  getCurrentImageIdIndex: () => number;
180
180
  getSliceIndex: () => number;
181
- isReferenceViewable(viewRef: ViewReference, options?: ReferenceCompatibleOptions): boolean;
181
+ isReferenceViewable(viewRef: ViewReference, options?: ReferenceCompatibleOptions): boolean | unknown;
182
182
  getViewReference(viewRefSpecifier?: ViewReferenceSpecifier): ViewReference;
183
183
  setViewReference(viewRef: ViewReference): void;
184
- getReferenceId(specifier?: ViewReferenceSpecifier): string;
184
+ getViewReferenceId(specifier?: ViewReferenceSpecifier): string;
185
185
  getTargetImageIdIndex: () => number;
186
186
  getImageIds: () => Array<string>;
187
187
  getCurrentImageId: () => string;
@@ -440,7 +440,10 @@ class StackViewport extends Viewport {
440
440
  direction: vtkImageData.getDirection(),
441
441
  scalarData: vtkImageData.getPointData().getScalars().getData(),
442
442
  imageData: actor.getMapper().getInputData(),
443
- metadata: { Modality: this.modality },
443
+ metadata: {
444
+ Modality: this.modality,
445
+ FrameOfReferenceUID: this.getFrameOfReferenceUID(),
446
+ },
444
447
  scaling: this.scaling,
445
448
  hasPixelSpacing: this.hasPixelSpacing,
446
449
  calibration: { ...this.csImage.calibration, ...this.calibration },
@@ -457,7 +460,10 @@ class StackViewport extends Viewport {
457
460
  spacing,
458
461
  origin: metadata.origin,
459
462
  direction: metadata.direction,
460
- metadata: { Modality: this.modality },
463
+ metadata: {
464
+ Modality: this.modality,
465
+ FrameOfReferenceUID: this.getFrameOfReferenceUID(),
466
+ },
461
467
  scaling: this.scaling,
462
468
  imageData: {
463
469
  getDirection: () => metadata.direction,
@@ -1352,7 +1358,8 @@ class StackViewport extends Viewport {
1352
1358
  addImages(stackInputs) {
1353
1359
  const actors = this.getActors();
1354
1360
  stackInputs.forEach((stackInput) => {
1355
- const image = cache.getImage(stackInput.imageId);
1361
+ const { imageId } = stackInput;
1362
+ const image = cache.getImage(imageId);
1356
1363
  const { origin, dimensions, direction, spacing, numComps } = this.getImageDataMetadata(image);
1357
1364
  const imagedata = this.createVTKImageData({
1358
1365
  origin,
@@ -1364,7 +1371,11 @@ class StackViewport extends Viewport {
1364
1371
  });
1365
1372
  const imageActor = this.createActorMapper(imagedata);
1366
1373
  if (imageActor) {
1367
- actors.push({ uid: stackInput.actorUID, actor: imageActor });
1374
+ actors.push({
1375
+ uid: stackInput.actorUID,
1376
+ actor: imageActor,
1377
+ referencedId: imageId,
1378
+ });
1368
1379
  if (stackInput.callback) {
1369
1380
  stackInput.callback({ imageActor, imageId: stackInput.imageId });
1370
1381
  }
@@ -1624,22 +1635,62 @@ class StackViewport extends Viewport {
1624
1635
  if (!super.isReferenceViewable(viewRef, options)) {
1625
1636
  return false;
1626
1637
  }
1627
- let { imageURI } = options;
1628
1638
  const { referencedImageId, sliceIndex } = viewRef;
1629
1639
  if (viewRef.volumeId && !referencedImageId) {
1630
1640
  return options.asVolume === true;
1631
1641
  }
1632
1642
  let testIndex = this.getCurrentImageIdIndex();
1643
+ const currentImageId = this.imageIds[testIndex];
1633
1644
  if (options.withNavigation && typeof sliceIndex === 'number') {
1634
1645
  testIndex = sliceIndex;
1635
1646
  }
1636
- const imageId = this.imageIds[testIndex];
1637
- if (!imageId) {
1647
+ if (!currentImageId) {
1638
1648
  return false;
1639
1649
  }
1650
+ if (options.asOverlay && referencedImageId) {
1651
+ const matchImagesForOverlay = (targetImageId) => {
1652
+ const referenceImagePlaneModule = metaData.get(MetadataModules.IMAGE_PLANE, referencedImageId);
1653
+ const currentImagePlaneModule = metaData.get(MetadataModules.IMAGE_PLANE, targetImageId);
1654
+ const referenceOrientation = referenceImagePlaneModule.imageOrientationPatient;
1655
+ const currentOrientation = currentImagePlaneModule.imageOrientationPatient;
1656
+ if (referenceOrientation && currentOrientation) {
1657
+ const closeEnough = isEqual(referenceImagePlaneModule.imageOrientationPatient, currentImagePlaneModule.imageOrientationPatient);
1658
+ if (closeEnough) {
1659
+ const referencePosition = referenceImagePlaneModule.imagePositionPatient;
1660
+ const currentPosition = currentImagePlaneModule.imagePositionPatient;
1661
+ if (referencePosition && currentPosition) {
1662
+ const vector = vec3.create();
1663
+ vec3.subtract(vector, currentPosition, referencePosition);
1664
+ const viewPlaneNormal = vec3.create();
1665
+ vec3.cross(viewPlaneNormal, currentOrientation.slice(0, 3), currentOrientation.slice(3, 6));
1666
+ const dotProduct = vec3.dot(vector, viewPlaneNormal);
1667
+ const isOrthogonal = Math.abs(dotProduct) < EPSILON;
1668
+ if (isOrthogonal) {
1669
+ return targetImageId;
1670
+ }
1671
+ }
1672
+ }
1673
+ }
1674
+ else {
1675
+ const referenceRows = referenceImagePlaneModule.rows;
1676
+ const referenceColumns = referenceImagePlaneModule.columns;
1677
+ const currentRows = currentImagePlaneModule.rows;
1678
+ const currentColumns = currentImagePlaneModule.columns;
1679
+ if (referenceRows === currentRows &&
1680
+ referenceColumns === currentColumns) {
1681
+ return targetImageId;
1682
+ }
1683
+ }
1684
+ };
1685
+ const matchedImageId = matchImagesForOverlay(currentImageId);
1686
+ if (matchedImageId) {
1687
+ return matchedImageId;
1688
+ }
1689
+ }
1690
+ let { imageURI } = options;
1640
1691
  if (!imageURI) {
1641
- const colonIndex = imageId.indexOf(':');
1642
- imageURI = imageId.substring(colonIndex + 1);
1692
+ const colonIndex = currentImageId.indexOf(':');
1693
+ imageURI = currentImageId.substring(colonIndex + 1);
1643
1694
  }
1644
1695
  return referencedImageId?.endsWith(imageURI);
1645
1696
  }
@@ -1680,7 +1731,7 @@ class StackViewport extends Viewport {
1680
1731
  }
1681
1732
  }
1682
1733
  }
1683
- getReferenceId(specifier = {}) {
1734
+ getViewReferenceId(specifier = {}) {
1684
1735
  const { sliceIndex: sliceIndex = this.currentImageIdIndex } = specifier;
1685
1736
  if (Array.isArray(sliceIndex)) {
1686
1737
  throw new Error('Use of slice ranges for stacks not supported');
@@ -100,7 +100,7 @@ declare class VideoViewport extends Viewport implements IVideoViewport {
100
100
  protected setColorTransform(): void;
101
101
  setCamera(camera: ICamera): void;
102
102
  getCurrentImageId(): string;
103
- getReferenceId(specifier?: ViewReferenceSpecifier): string;
103
+ getViewReferenceId(specifier?: ViewReferenceSpecifier): string;
104
104
  isReferenceViewable(viewRef: ViewReference, options?: ReferenceCompatibleOptions): boolean;
105
105
  getViewReference(viewRefSpecifier?: ViewReferenceSpecifier): ViewReference;
106
106
  getFrameNumber(): number;
@@ -537,7 +537,7 @@ class VideoViewport extends Viewport {
537
537
  : `/frames/${this.getFrameNumber()}`);
538
538
  return current;
539
539
  }
540
- getReferenceId(specifier = {}) {
540
+ getViewReferenceId(specifier = {}) {
541
541
  const { sliceIndex: sliceIndex } = specifier;
542
542
  if (sliceIndex === undefined) {
543
543
  return `videoId:${this.getCurrentImageId()}`;
@@ -589,7 +589,7 @@ class VideoViewport extends Viewport {
589
589
  }
590
590
  return {
591
591
  ...super.getViewReference(viewRefSpecifier),
592
- referencedImageId: this.getReferenceId(viewRefSpecifier),
592
+ referencedImageId: this.getViewReferenceId(viewRefSpecifier),
593
593
  sliceIndex: sliceIndex,
594
594
  };
595
595
  }
@@ -84,7 +84,7 @@ declare class Viewport implements IViewport {
84
84
  getPan(initialCamera?: ICamera): Point2;
85
85
  getCurrentImageIdIndex(): number;
86
86
  getSliceIndex(): number;
87
- getReferenceId(_specifier?: ViewReferenceSpecifier): string;
87
+ getViewReferenceId(_specifier?: ViewReferenceSpecifier): string;
88
88
  setPan(pan: Point2, storeAsInitialCamera?: boolean): void;
89
89
  getZoom(compareCamera?: ICamera): number;
90
90
  setZoom(value: number, storeAsInitialCamera?: boolean): void;
@@ -101,7 +101,7 @@ declare class Viewport implements IViewport {
101
101
  getClippingPlanesForActor(actorEntry?: ActorEntry): vtkPlane[];
102
102
  private _getWorldDistanceViewUpAndViewRight;
103
103
  getViewReference(viewRefSpecifier?: ViewReferenceSpecifier): ViewReference;
104
- isReferenceViewable(viewRef: ViewReference, options?: ReferenceCompatibleOptions): boolean;
104
+ isReferenceViewable(viewRef: ViewReference, options?: ReferenceCompatibleOptions): boolean | unknown;
105
105
  getViewPresentation(viewPresSel?: ViewPresentationSelector): ViewPresentation;
106
106
  setViewReference(viewRef: ViewReference): void;
107
107
  setViewPresentation(viewPres: ViewPresentation): void;
@@ -505,7 +505,7 @@ class Viewport {
505
505
  getSliceIndex() {
506
506
  throw new Error('Not implemented');
507
507
  }
508
- getReferenceId(_specifier) {
508
+ getViewReferenceId(_specifier) {
509
509
  return null;
510
510
  }
511
511
  setPan(pan, storeAsInitialCamera = false) {
@@ -19,7 +19,9 @@ declare class Cache implements ICache {
19
19
  purgeCache: () => void;
20
20
  purgeVolumeCache: () => void;
21
21
  decacheIfNecessaryUntilBytesAvailable(numBytes: number, volumeImageIds?: Array<string>): number | undefined;
22
+ private _putImageCommon;
22
23
  putImageLoadObject(imageId: string, imageLoadObject: IImageLoadObject): Promise<any>;
24
+ putImageSync(imageId: string, image: IImage): void;
23
25
  getImageLoadObject(imageId: string): IImageLoadObject;
24
26
  isLoaded(imageId: string): boolean;
25
27
  getVolumeContainingImageId(imageId: string): {
@@ -265,6 +265,31 @@ class Cache {
265
265
  }
266
266
  }
267
267
  }
268
+ _putImageCommon(imageId, image, cachedImage) {
269
+ if (!this._imageCache.get(imageId)) {
270
+ console.warn('The image was purged from the cache before it completed loading.');
271
+ return;
272
+ }
273
+ if (image.sizeInBytes === undefined || Number.isNaN(image.sizeInBytes)) {
274
+ throw new Error('_putImageCommon: image.sizeInBytes must not be undefined');
275
+ }
276
+ if (image.sizeInBytes.toFixed === undefined) {
277
+ throw new Error('_putImageCommon: image.sizeInBytes is not a number');
278
+ }
279
+ if (!this.isCacheable(image.sizeInBytes)) {
280
+ throw new Error(Events.CACHE_SIZE_EXCEEDED);
281
+ }
282
+ this.decacheIfNecessaryUntilBytesAvailable(image.sizeInBytes);
283
+ cachedImage.loaded = true;
284
+ cachedImage.image = image;
285
+ cachedImage.sizeInBytes = image.sizeInBytes;
286
+ this.incrementImageCacheSize(cachedImage.sizeInBytes);
287
+ const eventDetails = {
288
+ image: cachedImage,
289
+ };
290
+ triggerEvent(eventTarget, Events.IMAGE_CACHE_IMAGE_ADDED, eventDetails);
291
+ cachedImage.sharedCacheKey = image.sharedCacheKey;
292
+ }
268
293
  putImageLoadObject(imageId, imageLoadObject) {
269
294
  if (imageId === undefined) {
270
295
  throw new Error('putImageLoadObject: imageId must not be undefined');
@@ -290,36 +315,39 @@ class Cache {
290
315
  this._imageCache.set(imageId, cachedImage);
291
316
  return imageLoadObject.promise
292
317
  .then((image) => {
293
- if (!this._imageCache.get(imageId)) {
294
- console.warn('The image was purged from the cache before it completed loading.');
295
- return;
296
- }
297
- if (image.sizeInBytes === undefined ||
298
- Number.isNaN(image.sizeInBytes)) {
299
- throw new Error('putImageLoadObject: image.sizeInBytes must not be undefined');
300
- }
301
- if (image.sizeInBytes.toFixed === undefined) {
302
- throw new Error('putImageLoadObject: image.sizeInBytes is not a number');
303
- }
304
- if (!this.isCacheable(image.sizeInBytes)) {
305
- throw new Error(Events.CACHE_SIZE_EXCEEDED);
306
- }
307
- this.decacheIfNecessaryUntilBytesAvailable(image.sizeInBytes);
308
- cachedImage.loaded = true;
309
- cachedImage.image = image;
310
- cachedImage.sizeInBytes = image.sizeInBytes;
311
- this.incrementImageCacheSize(cachedImage.sizeInBytes);
312
- const eventDetails = {
313
- image: cachedImage,
314
- };
315
- triggerEvent(eventTarget, Events.IMAGE_CACHE_IMAGE_ADDED, eventDetails);
316
- cachedImage.sharedCacheKey = image.sharedCacheKey;
318
+ this._putImageCommon(imageId, image, cachedImage);
317
319
  })
318
320
  .catch((error) => {
319
321
  this._imageCache.delete(imageId);
320
322
  throw error;
321
323
  });
322
324
  }
325
+ putImageSync(imageId, image) {
326
+ if (imageId === undefined) {
327
+ throw new Error('putImageSync: imageId must not be undefined');
328
+ }
329
+ if (this._imageCache.has(imageId)) {
330
+ throw new Error('putImageSync: imageId already in cache');
331
+ }
332
+ const cachedImage = {
333
+ loaded: false,
334
+ imageId,
335
+ sharedCacheKey: undefined,
336
+ imageLoadObject: {
337
+ promise: Promise.resolve(image),
338
+ },
339
+ timeStamp: Date.now(),
340
+ sizeInBytes: 0,
341
+ };
342
+ this._imageCache.set(imageId, cachedImage);
343
+ try {
344
+ this._putImageCommon(imageId, image, cachedImage);
345
+ }
346
+ catch (error) {
347
+ this._imageCache.delete(imageId);
348
+ throw error;
349
+ }
350
+ }
323
351
  getImageLoadObject(imageId) {
324
352
  if (imageId === undefined) {
325
353
  throw new Error('getImageLoadObject: imageId must not be undefined');
@@ -54,7 +54,6 @@ export declare class ImageVolume implements IImageVolume {
54
54
  protected getScalarDataByImageIdIndex(imageIdIndex: number): PixelDataTypedArray;
55
55
  getCornerstoneImage(imageId: string, imageIdIndex: number): IImage;
56
56
  protected imageIdIndexToFrameIndex(imageIdIndex: number): number;
57
- convertToCornerstoneImage(imageId: string, imageIdIndex: number): IImageLoadObject;
58
57
  getCornerstoneImageLoadObject(imageId: string, imageIdIndex: number): IImageLoadObject;
59
58
  getCornerstoneImages(): IImage[];
60
59
  convertToImageSlicesAndCache(): string[];
@@ -120,6 +120,15 @@ export class ImageVolume {
120
120
  }
121
121
  else {
122
122
  this.convertToImageSlicesAndCache();
123
+ const otherVolumes = cache.filterVolumesByReferenceId(this.volumeId);
124
+ if (otherVolumes.length) {
125
+ otherVolumes.forEach((volume) => {
126
+ volume.referencedImageIds = this.imageIds;
127
+ });
128
+ }
129
+ if (completelyRemove) {
130
+ this.removeFromCache();
131
+ }
123
132
  }
124
133
  }
125
134
  removeFromCache() {
@@ -207,7 +216,24 @@ export class ImageVolume {
207
216
  const intercept = modalityLutModule.rescaleIntercept
208
217
  ? modalityLutModule.rescaleIntercept
209
218
  : 0;
210
- return {
219
+ const imageOrientationPatient = [
220
+ this.direction[0],
221
+ this.direction[1],
222
+ this.direction[2],
223
+ this.direction[3],
224
+ this.direction[4],
225
+ this.direction[5],
226
+ ];
227
+ const precision = 6;
228
+ const imagePositionPatient = [
229
+ parseFloat((this.origin[0] +
230
+ imageIdIndex * this.direction[6] * this.spacing[0]).toFixed(precision)),
231
+ parseFloat((this.origin[1] +
232
+ imageIdIndex * this.direction[7] * this.spacing[1]).toFixed(precision)),
233
+ parseFloat((this.origin[2] +
234
+ imageIdIndex * this.direction[8] * this.spacing[2]).toFixed(precision)),
235
+ ];
236
+ const image = {
211
237
  imageId,
212
238
  intercept,
213
239
  windowCenter,
@@ -233,13 +259,43 @@ export class ImageVolume {
233
259
  invert,
234
260
  photometricInterpretation,
235
261
  };
262
+ const pixelData = image.getPixelData();
263
+ const bitsAllocated = pixelData.BYTES_PER_ELEMENT * 8;
264
+ const imagePixelModule = {
265
+ bitsAllocated,
266
+ photometricInterpretation: image.photometricInterpretation,
267
+ windowWidth: image.windowWidth,
268
+ windowCenter: image.windowCenter,
269
+ voiLUTFunction: image.voiLUTFunction,
270
+ };
271
+ const imagePlaneModule = {
272
+ rowCosines: [this.direction[0], this.direction[1], this.direction[2]],
273
+ columnCosines: [this.direction[3], this.direction[4], this.direction[5]],
274
+ pixelSpacing: [this.spacing[0], this.spacing[1]],
275
+ imageOrientationPatient: imageOrientationPatient,
276
+ imagePositionPatient: imagePositionPatient,
277
+ columnPixelSpacing: image.columnPixelSpacing,
278
+ rowPixelSpacing: image.rowPixelSpacing,
279
+ columns: image.columns,
280
+ rows: image.rows,
281
+ };
282
+ const generalSeriesModule = {};
283
+ const metadata = {
284
+ imagePixelModule,
285
+ imagePlaneModule,
286
+ generalSeriesModule,
287
+ };
288
+ ['imagePixelModule', 'imagePlaneModule', 'generalSeriesModule'].forEach((type) => {
289
+ genericMetadataProvider.add(imageId, {
290
+ type,
291
+ metadata: metadata[type],
292
+ });
293
+ });
294
+ return image;
236
295
  }
237
296
  imageIdIndexToFrameIndex(imageIdIndex) {
238
297
  return imageIdIndex % this.numFrames;
239
298
  }
240
- convertToCornerstoneImage(imageId, imageIdIndex) {
241
- return this.getCornerstoneImageLoadObject(imageId, imageIdIndex);
242
- }
243
299
  getCornerstoneImageLoadObject(imageId, imageIdIndex) {
244
300
  const image = this.getCornerstoneImage(imageId, imageIdIndex);
245
301
  const imageLoadObject = {
@@ -276,78 +332,13 @@ export class ImageVolume {
276
332
  const imageId = this.imageIds[imageIdIndex];
277
333
  bytesRemaining = bytesRemaining - bytesPerImage;
278
334
  const image = this.getCornerstoneImage(imageId, imageIdIndex);
279
- const imageLoadObject = {
280
- promise: Promise.resolve(image),
281
- };
282
335
  if (!cache.getImageLoadObject(imageId)) {
283
- cache.putImageLoadObject(imageId, imageLoadObject).catch((err) => {
284
- console.error(err);
285
- });
336
+ cache.putImageSync(imageId, image);
286
337
  }
287
338
  if (bytesRemaining <= bytesPerImage) {
288
339
  break;
289
340
  }
290
- const imageOrientationPatient = [
291
- this.direction[0],
292
- this.direction[1],
293
- this.direction[2],
294
- this.direction[3],
295
- this.direction[4],
296
- this.direction[5],
297
- ];
298
- const precision = 6;
299
- const imagePositionPatient = [
300
- parseFloat((this.origin[0] +
301
- imageIdIndex * this.direction[6] * this.spacing[0]).toFixed(precision)),
302
- parseFloat((this.origin[1] +
303
- imageIdIndex * this.direction[7] * this.spacing[1]).toFixed(precision)),
304
- parseFloat((this.origin[2] +
305
- imageIdIndex * this.direction[8] * this.spacing[2]).toFixed(precision)),
306
- ];
307
- const pixelData = image.getPixelData();
308
- const bitsAllocated = pixelData.BYTES_PER_ELEMENT * 8;
309
- const imagePixelModule = {
310
- bitsAllocated,
311
- photometricInterpretation: image.photometricInterpretation,
312
- windowWidth: image.windowWidth,
313
- windowCenter: image.windowCenter,
314
- voiLUTFunction: image.voiLUTFunction,
315
- };
316
- const imagePlaneModule = {
317
- rowCosines: [this.direction[0], this.direction[1], this.direction[2]],
318
- columnCosines: [
319
- this.direction[3],
320
- this.direction[4],
321
- this.direction[5],
322
- ],
323
- pixelSpacing: [this.spacing[0], this.spacing[1]],
324
- imageOrientationPatient: imageOrientationPatient,
325
- imagePositionPatient: imagePositionPatient,
326
- columnPixelSpacing: image.columnPixelSpacing,
327
- rowPixelSpacing: image.rowPixelSpacing,
328
- columns: image.columns,
329
- rows: image.rows,
330
- };
331
- const generalSeriesModule = {};
332
- const metadata = {
333
- imagePixelModule,
334
- imagePlaneModule,
335
- generalSeriesModule,
336
- };
337
- ['imagePixelModule', 'imagePlaneModule', 'generalSeriesModule'].forEach((type) => {
338
- genericMetadataProvider.add(imageId, {
339
- type,
340
- metadata: metadata[type],
341
- });
342
- });
343
- }
344
- const otherVolumes = cache.filterVolumesByReferenceId(this.volumeId);
345
- if (otherVolumes.length) {
346
- otherVolumes.forEach((volume) => {
347
- volume.referencedImageIds = this.imageIds;
348
- });
349
341
  }
350
- this.removeFromCache();
351
342
  return this.imageIds;
352
343
  }
353
344
  }
@@ -41,7 +41,7 @@ function loadImageFromCacheOrVolume(imageId, options) {
41
41
  if (cachedVolumeInfo?.volume?.loadStatus?.loaded) {
42
42
  const { volume, imageIdIndex } = cachedVolumeInfo;
43
43
  if (volume instanceof ImageVolume) {
44
- imageLoadObject = volume.convertToCornerstoneImage(imageId, imageIdIndex);
44
+ imageLoadObject = volume.getCornerstoneImageLoadObject(imageId, imageIdIndex);
45
45
  }
46
46
  return imageLoadObject;
47
47
  }
@@ -157,6 +157,7 @@ export function createAndCacheLocalImage(options, imageId, preventCache = false)
157
157
  rgba: undefined,
158
158
  columnPixelSpacing: imagePlaneModule.columnPixelSpacing,
159
159
  rowPixelSpacing: imagePlaneModule.rowPixelSpacing,
160
+ FrameOfReferenceUID: imagePlaneModule.FrameOfReferenceUID,
160
161
  invert: false,
161
162
  };
162
163
  if (options.scalarData) {
@@ -133,6 +133,13 @@ export async function createAndCacheDerivedVolume(referencedVolumeId, options) {
133
133
  derivedImageData.setDirection(direction);
134
134
  derivedImageData.setOrigin(origin);
135
135
  derivedImageData.getPointData().setScalars(scalarArray);
136
+ const referencedImageIds = referencedVolume.imageIds ?? [];
137
+ let derivedVolumeImageIds = [];
138
+ if (referencedImageIds.length) {
139
+ derivedVolumeImageIds = referencedImageIds.map((imageId) => {
140
+ return `derived:${imageId}`;
141
+ });
142
+ }
136
143
  const derivedVolume = new ImageVolume({
137
144
  volumeId,
138
145
  metadata: structuredClone(metadata),
@@ -143,13 +150,15 @@ export async function createAndCacheDerivedVolume(referencedVolumeId, options) {
143
150
  imageData: derivedImageData,
144
151
  scalarData: volumeScalarData,
145
152
  sizeInBytes: numBytes,
146
- imageIds: [],
147
153
  referencedVolumeId,
154
+ imageIds: derivedVolumeImageIds,
155
+ referencedImageIds: referencedVolume.imageIds ?? [],
148
156
  });
149
157
  const volumeLoadObject = {
150
158
  promise: Promise.resolve(derivedVolume),
151
159
  };
152
160
  await cache.putVolumeLoadObject(volumeId, volumeLoadObject);
161
+ performCacheOptimizationForVolume(derivedVolume);
153
162
  return derivedVolume;
154
163
  }
155
164
  export function createLocalVolume(options, volumeId, preventCache = false) {
@@ -212,6 +221,7 @@ export function createLocalVolume(options, volumeId, preventCache = false) {
212
221
  promise: Promise.resolve(derivedVolume),
213
222
  };
214
223
  cache.putVolumeLoadObject(volumeId, volumeLoadObject);
224
+ performCacheOptimizationForVolume(derivedVolume);
215
225
  return derivedVolume;
216
226
  }
217
227
  export async function createAndCacheVolumeFromImages(volumeId, imageIds, options = {}) {
@@ -18,6 +18,7 @@ type CPUIImageData = {
18
18
  imageData: CPUImageData;
19
19
  metadata: {
20
20
  Modality: string;
21
+ FrameOfReferenceUID: string;
21
22
  };
22
23
  scalarData: PixelDataTypedArray;
23
24
  scaling: Scaling;
@@ -76,6 +76,7 @@ interface IImage {
76
76
  imageQualityStatus?: ImageQualityStatus;
77
77
  calibration?: IImageCalibration;
78
78
  imageFrame?: any;
79
+ FrameOfReferenceUID?: string;
79
80
  voxelManager?: VoxelManager<number> | VoxelManager<RGB>;
80
81
  bufferView?: {
81
82
  buffer: ArrayBuffer;
@@ -10,6 +10,7 @@ interface IImageData {
10
10
  imageData: vtkImageData;
11
11
  metadata: {
12
12
  Modality: string;
13
+ FrameOfReferenceUID: string;
13
14
  };
14
15
  scaling?: Scaling;
15
16
  hasPixelSpacing?: boolean;
@@ -18,9 +18,10 @@ export type ReferenceCompatibleOptions = {
18
18
  asVolume?: boolean;
19
19
  withOrientation?: boolean;
20
20
  imageURI?: string;
21
+ asOverlay?: boolean;
21
22
  };
22
23
  export type ViewReference = {
23
- FrameOfReferenceUID: string;
24
+ FrameOfReferenceUID?: string;
24
25
  referencedImageId?: string;
25
26
  cameraFocalPoint?: Point3;
26
27
  viewPlaneNormal?: Point3;
@@ -104,9 +105,9 @@ interface IViewport {
104
105
  getNumberOfSlices(): number;
105
106
  getCurrentImageIdIndex(): number;
106
107
  getSliceIndex(): number;
107
- getReferenceId(viewRefSpecifier?: ViewReferenceSpecifier): string;
108
+ getViewReferenceId(viewRefSpecifier?: ViewReferenceSpecifier): string;
108
109
  getViewReference(viewRefSpecifier?: ViewReferenceSpecifier): ViewReference;
109
- isReferenceViewable(viewRef: ViewReference, options?: ReferenceCompatibleOptions): boolean;
110
+ isReferenceViewable(viewRef: ViewReference, options?: ReferenceCompatibleOptions): boolean | unknown;
110
111
  getViewPresentation(viewPresSel?: ViewPresentationSelector): ViewPresentation;
111
112
  setViewReference(viewRef: ViewReference): any;
112
113
  setViewPresentation(viewPres: ViewPresentation): any;