@cornerstonejs/core 1.61.7 → 1.63.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/core",
3
- "version": "1.61.7",
3
+ "version": "1.63.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": "5a9ace306d9c82f9bbbe7844351b0113ea001da3"
50
+ "gitHead": "952379ee23e86f276b66bc7f58c4b37431a35a53"
51
51
  }
@@ -62,7 +62,6 @@ import type { vtkSlabCamera as vtkSlabCameraType } from './vtkClasses/vtkSlabCam
62
62
  import vtkSlabCamera from './vtkClasses/vtkSlabCamera';
63
63
  import transformWorldToIndex from '../utilities/transformWorldToIndex';
64
64
  import { getTransferFunctionNodes } from '../utilities/transferFunctionUtils';
65
-
66
65
  /**
67
66
  * Abstract base class for volume viewports. VolumeViewports are used to render
68
67
  * 3D volumes from which various orientations can be viewed. Since VolumeViewports
@@ -282,13 +281,16 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
282
281
  cfun.setMappingRange(range[0], range[1]);
283
282
  volumeActor.getProperty().setRGBTransferFunction(0, cfun);
284
283
 
284
+ // This configures the viewport to use the most recently applied colormap.
285
+ // However, this approach is not optimal when dealing with two volumes, as it prevents retrieval of the
286
+ // colormap for Volume A if Volume B's colormap was the last one applied.
285
287
  this.viewportProperties.colormap = colormap;
286
288
 
287
289
  if (!suppressEvents) {
288
290
  const eventDetail = {
289
- viewportId: this.id,
290
- colormap,
291
- volumeId
291
+ viewportId: this.id,
292
+ colormap,
293
+ volumeId,
292
294
  };
293
295
  triggerEvent(this.element, Events.COLORMAP_MODIFIED, eventDetail);
294
296
  }
@@ -789,7 +791,7 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
789
791
  }
790
792
 
791
793
  const {
792
- colormap,
794
+ colormap: latestColormap,
793
795
  VOILUTFunction,
794
796
  interpolationType,
795
797
  invert,
@@ -816,6 +818,15 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
816
818
 
817
819
  const voiRange = voiRanges.length ? voiRanges[0].voiRange : null;
818
820
 
821
+ const volumeColormap = this.getColormap(applicableVolumeActorInfo);
822
+
823
+ let colormap;
824
+ if (volumeId && volumeColormap) {
825
+ colormap = volumeColormap;
826
+ } else {
827
+ colormap = latestColormap;
828
+ }
829
+
819
830
  return {
820
831
  colormap: colormap,
821
832
  voiRange: voiRange,
@@ -827,6 +838,72 @@ abstract class BaseVolumeViewport extends Viewport implements IVolumeViewport {
827
838
  };
828
839
  };
829
840
 
841
+ /**
842
+ * This function extracts the nodes from the RGB Transfer Function, transforming each node's x, r, g, b properties
843
+ * into a unified array "RGB Points." Then, it compares these RGB Points—specifically the r, g, b values—with
844
+ * those in the predefined vtk colormap presets. Upon finding a matching set of r, g, b values, the function identifies and selects the
845
+ * corresponding colormap.
846
+ *
847
+ * Next, the function extracts an array of opacity points, formatted as a sequence of [x,y] pairs, where 'x' represents a value and
848
+ * 'y' represents its opacity. It iterates through this array to construct an opacity object that maps each value to its opacity.
849
+ *
850
+ * The function returns an object that includes the name of the identified colormap and the constructed opacity object.
851
+ * @param applicableVolumeActorInfo - The volume actor information for the volume
852
+ * @returns colormap information for the volume if identified
853
+ */
854
+ private getColormap = (applicableVolumeActorInfo) => {
855
+ const { volumeActor } = applicableVolumeActorInfo;
856
+ const cfun = volumeActor.getProperty().getRGBTransferFunction(0);
857
+ const { nodes } = cfun.getState();
858
+ const RGBPoints = nodes.reduce((acc, node) => {
859
+ acc.push(node.x, node.r, node.g, node.b);
860
+ return acc;
861
+ }, []);
862
+ const colormaps = vtkColorMaps.rgbPresetNames.map((presetName) =>
863
+ vtkColorMaps.getPresetByName(presetName)
864
+ );
865
+ const matchedColormap = colormaps.find((colormap) => {
866
+ const { RGBPoints: presetRGBPoints } = colormap;
867
+ if (presetRGBPoints.length !== RGBPoints.length) {
868
+ return false;
869
+ }
870
+
871
+ for (let i = 0; i < presetRGBPoints.length; i += 4) {
872
+ if (
873
+ !isEqual(
874
+ presetRGBPoints.slice(i + 1, i + 4),
875
+ RGBPoints.slice(i + 1, i + 4)
876
+ )
877
+ ) {
878
+ return false;
879
+ }
880
+ }
881
+
882
+ return true;
883
+ });
884
+
885
+ if (!matchedColormap) {
886
+ return null;
887
+ }
888
+
889
+ const opacityPoints = volumeActor
890
+ .getProperty()
891
+ .getScalarOpacity(0)
892
+ .getDataPointer();
893
+
894
+ const opacity = [];
895
+ for (let i = 0; i < opacityPoints.length; i += 2) {
896
+ opacity.push({ value: opacityPoints[i], opacity: opacityPoints[i + 1] });
897
+ }
898
+
899
+ const colormap = {
900
+ name: matchedColormap.Name,
901
+ opacity: opacity,
902
+ };
903
+
904
+ return colormap;
905
+ };
906
+
830
907
  /**
831
908
  * Creates volume actors for all volumes defined in the `volumeInputArray`.
832
909
  * For each entry, if a `callback` is supplied, it will be called with the new volume actor as input.