@cornerstonejs/core 1.71.3 → 1.71.5

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 (79) hide show
  1. package/dist/cjs/RenderingEngine/BaseVolumeViewport.d.ts +7 -6
  2. package/dist/cjs/RenderingEngine/BaseVolumeViewport.js +87 -12
  3. package/dist/cjs/RenderingEngine/BaseVolumeViewport.js.map +1 -1
  4. package/dist/cjs/RenderingEngine/RenderingEngine.js +6 -1
  5. package/dist/cjs/RenderingEngine/RenderingEngine.js.map +1 -1
  6. package/dist/cjs/RenderingEngine/StackViewport.d.ts +5 -5
  7. package/dist/cjs/RenderingEngine/StackViewport.js +71 -50
  8. package/dist/cjs/RenderingEngine/StackViewport.js.map +1 -1
  9. package/dist/cjs/RenderingEngine/Viewport.d.ts +2 -1
  10. package/dist/cjs/RenderingEngine/Viewport.js +21 -16
  11. package/dist/cjs/RenderingEngine/Viewport.js.map +1 -1
  12. package/dist/cjs/RenderingEngine/VolumeViewport.d.ts +5 -3
  13. package/dist/cjs/RenderingEngine/VolumeViewport.js +39 -15
  14. package/dist/cjs/RenderingEngine/VolumeViewport.js.map +1 -1
  15. package/dist/cjs/RenderingEngine/VolumeViewport3D.d.ts +1 -0
  16. package/dist/cjs/RenderingEngine/VolumeViewport3D.js +3 -0
  17. package/dist/cjs/RenderingEngine/VolumeViewport3D.js.map +1 -1
  18. package/dist/cjs/types/EventTypes.d.ts +8 -1
  19. package/dist/cjs/types/IViewport.d.ts +5 -1
  20. package/dist/cjs/types/IVolumeViewport.d.ts +2 -1
  21. package/dist/cjs/utilities/index.d.ts +3 -2
  22. package/dist/cjs/utilities/index.js +8 -4
  23. package/dist/cjs/utilities/index.js.map +1 -1
  24. package/dist/cjs/utilities/isEqual.d.ts +3 -0
  25. package/dist/cjs/utilities/isEqual.js +8 -0
  26. package/dist/cjs/utilities/isEqual.js.map +1 -1
  27. package/dist/esm/RenderingEngine/BaseVolumeViewport.js +87 -15
  28. package/dist/esm/RenderingEngine/BaseVolumeViewport.js.map +1 -1
  29. package/dist/esm/RenderingEngine/RenderingEngine.js +6 -1
  30. package/dist/esm/RenderingEngine/RenderingEngine.js.map +1 -1
  31. package/dist/esm/RenderingEngine/StackViewport.js +53 -34
  32. package/dist/esm/RenderingEngine/StackViewport.js.map +1 -1
  33. package/dist/esm/RenderingEngine/Viewport.js +20 -16
  34. package/dist/esm/RenderingEngine/Viewport.js.map +1 -1
  35. package/dist/esm/RenderingEngine/VolumeViewport.js +39 -15
  36. package/dist/esm/RenderingEngine/VolumeViewport.js.map +1 -1
  37. package/dist/esm/RenderingEngine/VolumeViewport3D.js +3 -0
  38. package/dist/esm/RenderingEngine/VolumeViewport3D.js.map +1 -1
  39. package/dist/esm/utilities/index.js +3 -2
  40. package/dist/esm/utilities/index.js.map +1 -1
  41. package/dist/esm/utilities/isEqual.js +5 -0
  42. package/dist/esm/utilities/isEqual.js.map +1 -1
  43. package/dist/types/RenderingEngine/BaseVolumeViewport.d.ts +7 -6
  44. package/dist/types/RenderingEngine/BaseVolumeViewport.d.ts.map +1 -1
  45. package/dist/types/RenderingEngine/RenderingEngine.d.ts.map +1 -1
  46. package/dist/types/RenderingEngine/StackViewport.d.ts +5 -5
  47. package/dist/types/RenderingEngine/StackViewport.d.ts.map +1 -1
  48. package/dist/types/RenderingEngine/Viewport.d.ts +2 -1
  49. package/dist/types/RenderingEngine/Viewport.d.ts.map +1 -1
  50. package/dist/types/RenderingEngine/VolumeViewport.d.ts +5 -3
  51. package/dist/types/RenderingEngine/VolumeViewport.d.ts.map +1 -1
  52. package/dist/types/RenderingEngine/VolumeViewport3D.d.ts +1 -0
  53. package/dist/types/RenderingEngine/VolumeViewport3D.d.ts.map +1 -1
  54. package/dist/types/types/EventTypes.d.ts +8 -1
  55. package/dist/types/types/EventTypes.d.ts.map +1 -1
  56. package/dist/types/types/IViewport.d.ts +5 -1
  57. package/dist/types/types/IViewport.d.ts.map +1 -1
  58. package/dist/types/types/IVolumeViewport.d.ts +2 -1
  59. package/dist/types/types/IVolumeViewport.d.ts.map +1 -1
  60. package/dist/types/types/displayArea.d.ts.map +1 -1
  61. package/dist/types/utilities/index.d.ts +3 -2
  62. package/dist/types/utilities/index.d.ts.map +1 -1
  63. package/dist/types/utilities/isEqual.d.ts +3 -0
  64. package/dist/types/utilities/isEqual.d.ts.map +1 -1
  65. package/dist/umd/index.js +1 -1
  66. package/dist/umd/index.js.map +1 -1
  67. package/package.json +2 -2
  68. package/src/RenderingEngine/BaseVolumeViewport.ts +189 -21
  69. package/src/RenderingEngine/RenderingEngine.ts +12 -1
  70. package/src/RenderingEngine/StackViewport.ts +81 -50
  71. package/src/RenderingEngine/Viewport.ts +37 -24
  72. package/src/RenderingEngine/VolumeViewport.ts +73 -24
  73. package/src/RenderingEngine/VolumeViewport3D.ts +4 -0
  74. package/src/types/EventTypes.ts +19 -0
  75. package/src/types/IViewport.ts +64 -18
  76. package/src/types/IVolumeViewport.ts +6 -1
  77. package/src/types/displayArea.ts +27 -0
  78. package/src/utilities/index.ts +6 -2
  79. package/src/utilities/isEqual.ts +27 -0
@@ -1,8 +1,6 @@
1
1
  import vtkPlane from '@kitware/vtk.js/Common/DataModel/Plane';
2
2
  import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume';
3
3
 
4
- import { vec3 } from 'gl-matrix';
5
-
6
4
  import cache from '../cache';
7
5
  import { MPR_CAMERA_VALUES, RENDERING_DEFAULTS } from '../constants';
8
6
  import { BlendModes, OrientationAxis, Events } from '../enums';
@@ -12,6 +10,9 @@ import type {
12
10
  IVolumeInput,
13
11
  OrientationVectors,
14
12
  Point3,
13
+ EventTypes,
14
+ ViewReference,
15
+ ViewReferenceSpecifier,
15
16
  } from '../types';
16
17
  import type { ViewportInput } from '../types/IViewport';
17
18
  import {
@@ -28,6 +29,7 @@ import setDefaultVolumeVOI from './helpers/setDefaultVolumeVOI';
28
29
  import { setTransferFunctionNodes } from '../utilities/transferFunctionUtils';
29
30
  import { ImageActor } from '../types/IActor';
30
31
  import getImageSliceDataForVolumeViewport from '../utilities/getImageSliceDataForVolumeViewport';
32
+ import getVolumeViewportScrollInfo from '../utilities/getVolumeViewportScrollInfo';
31
33
 
32
34
  /**
33
35
  * An object representing a VolumeViewport. VolumeViewports are used to render
@@ -253,15 +255,19 @@ class VolumeViewport extends BaseVolumeViewport {
253
255
  resetPan = true,
254
256
  resetZoom = true,
255
257
  resetToCenter = true,
256
- resetRotation = false
258
+ resetRotation = false,
259
+ supressEvents = false
257
260
  ): boolean {
261
+ const { orientation } = this.viewportProperties;
262
+ if (orientation) {
263
+ this.applyViewOrientation(orientation, false);
264
+ }
258
265
  super.resetCamera(resetPan, resetZoom, resetToCenter);
259
266
 
260
267
  this.resetVolumeViewportClippingRange();
261
268
 
262
269
  const activeCamera = this.getVtkActiveCamera();
263
270
  const viewPlaneNormal = <Point3>activeCamera.getViewPlaneNormal();
264
- const viewUp = <Point3>activeCamera.getViewUp();
265
271
  const focalPoint = <Point3>activeCamera.getFocalPoint();
266
272
 
267
273
  // always add clipping planes for the volume viewport. If a use case
@@ -310,6 +316,16 @@ class VolumeViewport extends BaseVolumeViewport {
310
316
  });
311
317
  }
312
318
 
319
+ if (!supressEvents) {
320
+ const eventDetail: EventTypes.CameraResetEventDetail = {
321
+ viewportId: this.id,
322
+ camera: this.getCamera(),
323
+ renderingEngineId: this.renderingEngineId,
324
+ element: this.element,
325
+ };
326
+
327
+ triggerEvent(this.element, Events.CAMERA_RESET, eventDetail);
328
+ }
313
329
  return true;
314
330
  }
315
331
 
@@ -350,31 +366,44 @@ class VolumeViewport extends BaseVolumeViewport {
350
366
 
351
367
  /**
352
368
  * Uses the origin and focalPoint to calculate the slice index.
353
- *
354
- * @returns The slice index in the direction of the view
355
- */
356
- public getCurrentImageIdIndex = (volumeId?: string): number => {
357
- const { viewPlaneNormal, focalPoint } = this.getCamera();
358
369
 
359
- const imageData = this.getImageData(volumeId);
360
370
 
361
- if (!imageData) {
362
- return;
363
- }
364
371
 
365
- const { origin, direction, spacing } = imageData;
372
+ * Resets the slab thickness of the actors of the viewport to the default value.
373
+ */
374
+ public resetSlabThickness(): void {
375
+ const actorEntries = this.getActors();
366
376
 
367
- const spacingInNormal = getSpacingInNormalDirection(
368
- { direction, spacing },
369
- viewPlaneNormal
370
- );
371
- const sub = vec3.create();
372
- vec3.sub(sub, focalPoint, origin);
373
- const distance = vec3.dot(sub, viewPlaneNormal);
377
+ actorEntries.forEach((actorEntry) => {
378
+ if (actorIsA(actorEntry, 'vtkVolume')) {
379
+ actorEntry.slabThickness = RENDERING_DEFAULTS.MINIMUM_SLAB_THICKNESS;
380
+ }
381
+ });
374
382
 
375
- // divide by the spacing in the normal direction to get the
376
- // number of steps, and subtract 1 to get the index
377
- return Math.round(Math.abs(distance) / spacingInNormal);
383
+ const currentCamera = this.getCamera();
384
+ this.updateClippingPlanesForActors(currentCamera);
385
+ this.triggerCameraModifiedEventIfNecessary(currentCamera, currentCamera);
386
+ this.viewportProperties.slabThickness = undefined;
387
+ }
388
+
389
+ /**
390
+ * Uses the slice range information to compute the current image id index.
391
+ * Note that this may be offset from the origin location, or opposite in
392
+ * direction to the distance from the origin location, as the index is a
393
+ * complete index from minimum to maximum.
394
+ *
395
+ * @returns The slice index in the direction of the view
396
+ */
397
+ public getCurrentImageIdIndex = (
398
+ volumeId?: string,
399
+ useSlabThickness = true
400
+ ): number => {
401
+ const { currentStepIndex } = getVolumeViewportScrollInfo(
402
+ this,
403
+ volumeId || this.getVolumeId(),
404
+ useSlabThickness
405
+ );
406
+ return currentStepIndex;
378
407
  };
379
408
 
380
409
  /**
@@ -404,6 +433,26 @@ class VolumeViewport extends BaseVolumeViewport {
404
433
  return getClosestImageId(volume, focalPoint, viewPlaneNormal);
405
434
  };
406
435
 
436
+ /**
437
+ * Gets a view target, allowing comparison between view positions as well
438
+ * as restoring views later.
439
+ * Add the referenced image id.
440
+ */
441
+ public getViewReference(
442
+ viewRefSpecifier: ViewReferenceSpecifier = {}
443
+ ): ViewReference {
444
+ const viewRef = super.getViewReference(viewRefSpecifier);
445
+ if (!viewRef?.volumeId) {
446
+ return;
447
+ }
448
+ const volume = cache.getVolume(viewRef.volumeId);
449
+ viewRef.referencedImageId = getClosestImageId(
450
+ volume,
451
+ viewRef.cameraFocalPoint,
452
+ viewRef.viewPlaneNormal
453
+ );
454
+ return viewRef;
455
+ }
407
456
  /**
408
457
  * Reset the viewport properties to the default values
409
458
  *
@@ -64,6 +64,10 @@ class VolumeViewport3D extends BaseVolumeViewport {
64
64
  resetProperties(volumeId?: string): void {
65
65
  return null;
66
66
  }
67
+
68
+ resetSlabThickness(): void {
69
+ return null;
70
+ }
67
71
  }
68
72
 
69
73
  export default VolumeViewport3D;
@@ -31,6 +31,23 @@ type CameraModifiedEventDetail = {
31
31
  rotation?: number;
32
32
  };
33
33
 
34
+ /**
35
+ * CAMERA_RESET Event's data
36
+ */
37
+
38
+ type CameraResetEventDetail = {
39
+ /** Viewport HTML element in the DOM */
40
+ element: HTMLDivElement;
41
+ /** Viewport Unique ID in the renderingEngine */
42
+ viewportId: string;
43
+ /** Unique ID for the renderingEngine */
44
+ renderingEngineId: string;
45
+ /** Camera properties */
46
+ camera: ICamera;
47
+ };
48
+
49
+ type CameraResetEvent = CustomEventType<CameraResetEventDetail>;
50
+
34
51
  /**
35
52
  * VOI_MODIFIED Event's data
36
53
  */
@@ -461,4 +478,6 @@ export type {
461
478
  StackViewportNewStackEventDetail,
462
479
  StackViewportScrollEvent,
463
480
  StackViewportScrollEventDetail,
481
+ CameraResetEvent,
482
+ CameraResetEventDetail,
464
483
  };
@@ -15,7 +15,12 @@ import BoundsLPS from './BoundsLPS';
15
15
  * set of points.
16
16
  */
17
17
  export type ViewReferenceSpecifier = {
18
- /** The slice index within the current viewport camera to get a reference for */
18
+ /**
19
+ * The slice index within the current viewport camera to get a reference for.
20
+ * Note that slice indexes are dependent on the particular view being shown
21
+ * and cannot be shared across different view types such as stacks and
22
+ * volumes, or two viewports showing different orientations or slab thicknesses.
23
+ */
19
24
  sliceIndex?: number | [number, number];
20
25
  /**
21
26
  * Specifies to get a view reference that refers to the generic frame of
@@ -47,12 +52,15 @@ export type ReferenceCompatibleOptions = {
47
52
  withNavigation?: boolean;
48
53
  /**
49
54
  * For a stack viewport, return true if this viewport could show the given
50
- * view if it were converted into a volume viewport, while for a volume,
51
- * could it be shown if the camera/orientation were changed.
52
- * That is, is the specified view showing an image in the stack but with a
53
- * different orientation than acquisition.
55
+ * view if it were converted into a volume viewport. Has no affect on volume
56
+ * viewports.
54
57
  */
55
58
  asVolume?: boolean;
59
+ /**
60
+ * For volume viewports, return true if this viewport could show the given view
61
+ * if the orientation was changed.
62
+ */
63
+ withOrientation?: boolean;
56
64
  /**
57
65
  * Use this imageURI for testing - may or may not be the current one.
58
66
  * Should be a straight contains URI for the set of imageIds in any of
@@ -86,15 +94,39 @@ export type ViewReference = {
86
94
  referencedImageId?: string;
87
95
 
88
96
  /**
89
- * The focal point of the camera in world space
97
+ * The focal point of the camera in world space.
98
+ * The focal point is used for to define the stack positioning, but not the
99
+ * zoom/pan (which is defined by the view presentation
100
+ * object.)
101
+ *
102
+ * Single point objects (probe etc) should use the probe point as the camera
103
+ * focal point as that allows omitting the view plane normal and showing the probe
104
+ * in any orientation.
90
105
  */
91
106
  cameraFocalPoint?: Point3;
92
107
  /**
93
- * The normal for the current view
108
+ * The normal for the current view. This defines the plane used to show the
109
+ * 2d annotation. This should be omitted if the annotation is a point to
110
+ * allows for single-point annotations.
94
111
  */
95
112
  viewPlaneNormal?: Point3;
96
113
  /**
97
- * The slice index or range for this view
114
+ * The view up - this is only used for resetting orientation
115
+ */
116
+ viewUp?: Point3;
117
+ /**
118
+ * The slice index or range for this view.
119
+ * <b>NOTE</b> The slice index is relative to the volume or stack of images.
120
+ * You cannot apply a slice index from one volume to another as they do NOT
121
+ * apply. The referencedImageId should belong to the volume you are trying
122
+ * to apply to, the viewPlane normal should be identical, and then you can
123
+ * apply the sliceIndex.
124
+ *
125
+ * For stack viewports, the referencedImageId should occur at the given slice index.
126
+ *
127
+ * <b>Note 2</b>slice indices don't necessarily indicate anything positionally
128
+ * within the stack of images - subsequent slice indexes can be at opposite
129
+ * ends or can be co-incident but separate types of images.
98
130
  */
99
131
  sliceIndex?: number | [number, number];
100
132
 
@@ -292,11 +324,22 @@ interface IViewport {
292
324
  setPan(pan: Point2, storeAsInitialCamera?: boolean);
293
325
  /** sets the camera */
294
326
  setCamera(cameraInterface: ICamera, storeAsInitialCamera?: boolean): void;
327
+ /** Resets the camera */
328
+ resetCamera(
329
+ resetPan?: boolean,
330
+ resetZoom?: boolean,
331
+ resetToCenter?: boolean,
332
+ storeAsInitialCamera?: boolean
333
+ ): boolean;
295
334
  /** Gets the number of slices in the current camera orientation */
296
335
  getNumberOfSlices(): number;
297
336
  /** Gets the current slice in the current camera orientation */
298
337
  getCurrentImageIdIndex(): number;
299
- /** Gets a referenced image url of some sort - could be a real image id, or could be a URL with parameters */
338
+ /**
339
+ * Gets a referenced image url of some sort - could be a real image id, or
340
+ * could be a URL with parameters. Regardless it refers to the currently displaying
341
+ * image as a string value.
342
+ */
300
343
  getReferenceId(viewRefSpecifier?: ViewReferenceSpecifier): string;
301
344
  /**
302
345
  * Gets a view target specifying WHAT a view is displaying,
@@ -343,20 +386,23 @@ interface IViewport {
343
386
  * @param viewPresSel - select which attributes to display.
344
387
  */
345
388
  getViewPresentation(viewPresSel?: ViewPresentationSelector): ViewPresentation;
389
+
346
390
  /**
347
- * Selects both what a viewport is showing (which image/slice) as well as how it
348
- * is being presented. If only one or the other values is provided, the
349
- * currently applied view for the other attribute is preserved, allowing for
350
- * remember specific sets of attributes.
351
- *
352
- * @param viewRef - the basic positioning in terms of what image id/slice index/orientation to display
353
- * * The viewRef must be applicable to the current stack or volume, otherwise an exception will be thrown
354
- * @param viewPres - the presentation information to apply to the current image (as chosen above)
391
+ * Navigates this viewport to the specified viewRef.
392
+ * Throws an exception if that isn't possible on this viewport.
393
+ * Returns immediately if viewRef isn't defined.
355
394
  */
356
- setView(viewRef?: ViewReference, viewPres?: ViewPresentation);
395
+ setViewReference(viewRef: ViewReference);
396
+
397
+ /**
398
+ * Sets the presentation parameters from the specified viewPres object.
399
+ * Sets display area, zoom, pan, rotation, voi LUT
400
+ */
401
+ setViewPresentation(viewPres: ViewPresentation);
357
402
 
358
403
  /** whether the viewport has custom rendering */
359
404
  customRenderViewportToCanvas: () => unknown;
405
+
360
406
  _getCorners(bounds: Array<number>): Array<number>[];
361
407
  updateRenderingPipeline: () => void;
362
408
  }
@@ -137,8 +137,13 @@ export default interface IVolumeViewport extends IViewport {
137
137
  resetPan?: boolean,
138
138
  resetZoom?: boolean,
139
139
  resetToCenter?: boolean,
140
- resetRotation?: boolean
140
+ resetRotation?: boolean,
141
+ supressEvents?: boolean
141
142
  ): boolean;
143
+ /**
144
+ * Reset the slab thickness for actors of the viewport.
145
+ */
146
+ resetSlabThickness(): void;
142
147
  /**
143
148
  * Sets the blendMode for actors of the viewport.
144
149
  */
@@ -1,14 +1,41 @@
1
1
  import InterpolationType from '../enums/InterpolationType';
2
2
 
3
+ /**
4
+ * The display area type allows specifying or updating the image position and
5
+ * size based on the display area that it is shown in and based on the image
6
+ * size.
7
+ *
8
+ * Two types are currently defined, the default 'FIT', specifies scaling
9
+ * to fit the given image area. For this type, the area that is scaled to
10
+ * fit is the imageArea times the image size. For example, an imageArea of
11
+ * `[0.5,2]` with a 512 square image will try to fit 0.5*512 = 256 pixels width wise,
12
+ * and 2*512 = 1024 height wise.
13
+ *
14
+ * The type 'SCALE' means to use a scale factor, such as 1.0, which means to make
15
+ * every image pixel fit one physical display pixel.
16
+ *
17
+ * Then, the image is positioned such that the image fractional position imagePoint
18
+ * is located at the canvas fractional point canvasPoint. Using fractional
19
+ * points allows being independent of image size.
20
+ *
21
+ * Finally, the store as initial camera allows the zoom and pan values to be
22
+ * set to 1 and [0,0] respectively for the initially displayed position, as well
23
+ * as having the reset camera reset to the specified display area.
24
+ */
3
25
  type DisplayArea = {
4
26
  type?: 'SCALE' | 'FIT';
5
27
  scale?: number;
6
28
  interpolationType?: InterpolationType;
7
29
  imageArea?: [number, number]; // areaX, areaY
8
30
  imageCanvasPoint?: {
31
+ /** Use the fractional imagePoint as the target image point to position */
9
32
  imagePoint: [number, number]; // imageX, imageY
33
+ /** Pan the image such that the target imagePoint is located at the
34
+ * canvas point fraction of the canvas.
35
+ */
10
36
  canvasPoint?: [number, number]; // canvasX, canvasY
11
37
  };
38
+ /** Make this display area the default and reset/navigate will reapply this */
12
39
  storeAsInitialCamera?: boolean;
13
40
  };
14
41
 
@@ -11,7 +11,7 @@ import getRuntimeId from './getRuntimeId';
11
11
  import imageIdToURI from './imageIdToURI';
12
12
  import calibratedPixelSpacingMetadataProvider from './calibratedPixelSpacingMetadataProvider';
13
13
  import clamp from './clamp';
14
- import isEqual from './isEqual';
14
+ import { isEqual, isEqualAbs, isEqualNegative } from './isEqual';
15
15
  import isOpposite from './isOpposite';
16
16
  import createUint8SharedArray from './createUint8SharedArray';
17
17
  import createFloat32SharedArray from './createFloat32SharedArray';
@@ -66,6 +66,7 @@ import { generateVolumePropsFromImageIds } from './generateVolumePropsFromImageI
66
66
  import { convertStackToVolumeViewport } from './convertStackToVolumeViewport';
67
67
  import { convertVolumeToStackViewport } from './convertVolumeToStackViewport';
68
68
  import VoxelManager from './VoxelManager';
69
+ import RLEVoxelMap from './RLEVoxelMap';
69
70
  import roundNumber, { roundToPrecision } from './roundNumber';
70
71
  import convertToGrayscale from './convertToGrayscale';
71
72
  import getViewportImageIds from './getViewportImageIds';
@@ -97,6 +98,8 @@ export {
97
98
  getMinMax,
98
99
  getRuntimeId,
99
100
  isEqual,
101
+ isEqualAbs,
102
+ isEqualNegative,
100
103
  isOpposite,
101
104
  createFloat32SharedArray,
102
105
  createUint8SharedArray,
@@ -151,9 +154,10 @@ export {
151
154
  isValidVolume,
152
155
  genericMetadataProvider,
153
156
  isVideoTransferSyntax,
157
+ generateVolumePropsFromImageIds,
154
158
  getBufferConfiguration,
155
159
  VoxelManager,
156
- generateVolumePropsFromImageIds,
160
+ RLEVoxelMap,
157
161
  convertStackToVolumeViewport,
158
162
  convertVolumeToStackViewport,
159
163
  cacheUtils,
@@ -63,3 +63,30 @@ export default function isEqual<ValueType>(
63
63
 
64
64
  return false;
65
65
  }
66
+
67
+ const negative = (v) =>
68
+ typeof v === 'number' ? -v : v?.map ? v.map(negative) : !v;
69
+
70
+ const abs = (v) =>
71
+ typeof v === 'number' ? Math.abs(v) : v?.map ? v.map(abs) : v;
72
+
73
+ /**
74
+ * Compare negative values of both single numbers and vectors
75
+ */
76
+ const isEqualNegative = <ValueType>(
77
+ v1: ValueType,
78
+ v2: ValueType,
79
+ tolerance = undefined
80
+ ) => isEqual(v1, negative(v2) as unknown as ValueType, tolerance);
81
+
82
+ /**
83
+ * Compare absolute values for single numbers and vectors.
84
+ * Not recommended for large vectors as this creates a copy
85
+ */
86
+ const isEqualAbs = <ValueType>(
87
+ v1: ValueType,
88
+ v2: ValueType,
89
+ tolerance = undefined
90
+ ) => isEqual(abs(v1), abs(v2) as unknown as ValueType, tolerance);
91
+
92
+ export { isEqualNegative, isEqual, isEqualAbs };