@cornerstonejs/adapters 4.15.16 → 4.15.18

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.
@@ -6,7 +6,7 @@ import { toScoord } from '../helpers/toScoordType.js';
6
6
 
7
7
  var _ArrowAnnotate;
8
8
  const {
9
- Point: TID300Point
9
+ ArrowAnnotate: TID300ArrowAnnotate
10
10
  } = utilities.TID300;
11
11
  const {
12
12
  imageToWorldCoords
@@ -89,7 +89,7 @@ class ArrowAnnotate extends BaseAdapter3D {
89
89
  }
90
90
  _ArrowAnnotate = ArrowAnnotate;
91
91
  (() => {
92
- _ArrowAnnotate.init("ArrowAnnotate", TID300Point);
92
+ _ArrowAnnotate.init("ArrowAnnotate", TID300ArrowAnnotate);
93
93
  _ArrowAnnotate.registerLegacy();
94
94
  })();
95
95
 
@@ -52,6 +52,7 @@ declare class Bidirectional extends BaseAdapter3D {
52
52
  };
53
53
  longAxisLength: any;
54
54
  shortAxisLength: any;
55
+ unit: any;
55
56
  trackingIdentifierTextValue: string;
56
57
  finding: any;
57
58
  findingSites: any;
@@ -41,7 +41,9 @@ class Bidirectional extends BaseAdapter3D {
41
41
  state.annotation.data.cachedStats = {
42
42
  [`imageId:${referencedImageId}`]: {
43
43
  length: longAxisNUMGroup.MeasuredValueSequence.NumericValue,
44
- width: shortAxisNUMGroup.MeasuredValueSequence.NumericValue
44
+ width: shortAxisNUMGroup.MeasuredValueSequence.NumericValue,
45
+ unit: longAxisNUMGroup.MeasuredValueSequence.MeasurementUnitsCodeSequence.CodeValue,
46
+ widthUnit: shortAxisNUMGroup.MeasuredValueSequence.MeasurementUnitsCodeSequence.CodeValue
45
47
  }
46
48
  };
47
49
  }
@@ -88,7 +90,8 @@ class Bidirectional extends BaseAdapter3D {
88
90
  const shortAxisEndImage = toScoord(scoordProps, longAxisPoints[1]);
89
91
  const {
90
92
  length,
91
- width
93
+ width,
94
+ unit
92
95
  } = cachedStats[`imageId:${referencedImageId}`] || {};
93
96
  return {
94
97
  longAxis: {
@@ -101,6 +104,7 @@ class Bidirectional extends BaseAdapter3D {
101
104
  },
102
105
  longAxisLength: length,
103
106
  shortAxisLength: width,
107
+ unit,
104
108
  trackingIdentifierTextValue: this.trackingIdentifierTextValue,
105
109
  finding: finding,
106
110
  findingSites: findingSites || [],
@@ -11,8 +11,15 @@ declare class CircleROI extends BaseAdapter3D {
11
11
  };
12
12
  static getTID300RepresentationArguments(tool: any, is3DMeasurement?: boolean): {
13
13
  area: any;
14
+ areaUnit: any;
14
15
  perimeter: number;
16
+ modalityUnit: any;
17
+ radiusUnit: any;
15
18
  radius: any;
19
+ max: any;
20
+ min: any;
21
+ stdDev: any;
22
+ mean: any;
16
23
  points: ({
17
24
  x: any;
18
25
  y: any;
@@ -3,6 +3,7 @@ import MeasurementReport from './MeasurementReport.js';
3
3
  import BaseAdapter3D from './BaseAdapter3D.js';
4
4
  import { toScoord } from '../helpers/toScoordType.js';
5
5
  import '@cornerstonejs/core';
6
+ import { extractAllNUMGroups, restoreAdditionalMetrics } from './metricHandler.js';
6
7
 
7
8
  var _CircleROI;
8
9
  const {
@@ -17,6 +18,9 @@ class CircleROI extends BaseAdapter3D {
17
18
  referencedImageId,
18
19
  ReferencedFrameNumber
19
20
  } = MeasurementReport.getSetupMeasurementData(MeasurementGroup, sopInstanceUIDToImageIdMap, metadata, this.toolType);
21
+ const referencedSOPInstanceUID = state.sopInstanceUid;
22
+ const allNUMGroups = extractAllNUMGroups(MeasurementGroup, referencedSOPInstanceUID);
23
+ const measurementNUMGroups = allNUMGroups[referencedSOPInstanceUID] || {};
20
24
  state.annotation.data = {
21
25
  ...state.annotation.data,
22
26
  handles: {
@@ -30,7 +34,8 @@ class CircleROI extends BaseAdapter3D {
30
34
  [`imageId:${referencedImageId}`]: {
31
35
  area: NUMGroup ? NUMGroup.MeasuredValueSequence.NumericValue : 0,
32
36
  radius: 0,
33
- perimeter: 0
37
+ perimeter: 0,
38
+ ...restoreAdditionalMetrics(measurementNUMGroups)
34
39
  }
35
40
  };
36
41
  }
@@ -59,13 +64,27 @@ class CircleROI extends BaseAdapter3D {
59
64
  const end = toScoord(scoordProps, handles.points[1]);
60
65
  const {
61
66
  area,
62
- radius
67
+ radius,
68
+ max,
69
+ min,
70
+ stdDev,
71
+ mean,
72
+ modalityUnit,
73
+ radiusUnit,
74
+ areaUnit
63
75
  } = cachedStats[`imageId:${referencedImageId}`] || {};
64
76
  const perimeter = 2 * Math.PI * radius;
65
77
  return {
66
78
  area,
79
+ areaUnit,
67
80
  perimeter,
81
+ modalityUnit,
82
+ radiusUnit,
68
83
  radius,
84
+ max,
85
+ min,
86
+ stdDev,
87
+ mean,
69
88
  points: [center, end],
70
89
  trackingIdentifierTextValue: this.trackingIdentifierTextValue,
71
90
  finding,
@@ -11,6 +11,12 @@ declare class EllipticalROI extends BaseAdapter3D {
11
11
  };
12
12
  static getTID300RepresentationArguments(tool: any, is3DMeasurement?: boolean): {
13
13
  area: any;
14
+ areaUnit: any;
15
+ max: any;
16
+ min: any;
17
+ mean: any;
18
+ stdDev: any;
19
+ modalityUnit: any;
14
20
  points: ({
15
21
  x: any;
16
22
  y: any;
@@ -3,6 +3,7 @@ import MeasurementReport from './MeasurementReport.js';
3
3
  import BaseAdapter3D from './BaseAdapter3D.js';
4
4
  import { toScoord } from '../helpers/toScoordType.js';
5
5
  import '@cornerstonejs/core';
6
+ import { extractAllNUMGroups, restoreAdditionalMetrics } from './metricHandler.js';
6
7
 
7
8
  var _EllipticalROI;
8
9
  const {
@@ -17,6 +18,9 @@ class EllipticalROI extends BaseAdapter3D {
17
18
  referencedImageId,
18
19
  ReferencedFrameNumber
19
20
  } = MeasurementReport.getSetupMeasurementData(MeasurementGroup, sopInstanceUIDToImageIdMap, metadata, EllipticalROI.toolType);
21
+ const referencedSOPInstanceUID = state.sopInstanceUid;
22
+ const allNUMGroups = extractAllNUMGroups(MeasurementGroup, referencedSOPInstanceUID);
23
+ const measurementNUMGroups = allNUMGroups[referencedSOPInstanceUID] || {};
20
24
  state.annotation.data = {
21
25
  ...state.annotation.data,
22
26
  handles: {
@@ -27,7 +31,8 @@ class EllipticalROI extends BaseAdapter3D {
27
31
  };
28
32
  state.annotation.data.cachedStats = referencedImageId ? {
29
33
  [`imageId:${referencedImageId}`]: {
30
- area: NUMGroup ? NUMGroup.MeasuredValueSequence.NumericValue : 0
34
+ area: NUMGroup ? NUMGroup.MeasuredValueSequence.NumericValue : 0,
35
+ ...restoreAdditionalMetrics(measurementNUMGroups)
31
36
  }
32
37
  } : {};
33
38
  return state;
@@ -73,11 +78,23 @@ class EllipticalROI extends BaseAdapter3D {
73
78
  points.push(left, right, top, bottom);
74
79
  }
75
80
  const {
76
- area
81
+ area,
82
+ max,
83
+ min,
84
+ mean,
85
+ stdDev,
86
+ modalityUnit,
87
+ areaUnit
77
88
  } = cachedStats[`imageId:${referencedImageId}`] || {};
78
89
  const convertedPoints = points.map(point => toScoord(scoordProps, point));
79
90
  return {
80
91
  area,
92
+ areaUnit,
93
+ max,
94
+ min,
95
+ mean,
96
+ stdDev,
97
+ modalityUnit,
81
98
  points: convertedPoints,
82
99
  trackingIdentifierTextValue: this.trackingIdentifierTextValue,
83
100
  finding,
@@ -7,9 +7,11 @@ const {
7
7
  sr: {
8
8
  valueTypes,
9
9
  coding
10
+ },
11
+ adapters: {
12
+ Cornerstone3D
10
13
  }
11
14
  } = dcmjs;
12
- const CORNERSTONEFREETEXT = "CORNERSTONEFREETEXT";
13
15
  class LabelData {
14
16
  constructor(tid300Item, annotation) {
15
17
  this.tid300Item = tid300Item;
@@ -32,12 +34,16 @@ class LabelData {
32
34
  return contentEntries;
33
35
  }
34
36
  filterCornerstoneFreeText(contentEntries) {
37
+ const {
38
+ codeValues
39
+ } = Cornerstone3D.CodeScheme;
40
+ const freeTextCodes = [codeValues.FREE_TEXT_CODE_VALUE, codeValues.CORNERSTONEFREETEXT];
35
41
  for (let i = 0; i < contentEntries.length; i++) {
36
42
  const group = contentEntries[i];
37
43
  if (!group.ConceptCodeSequence) {
38
44
  continue;
39
45
  }
40
- const csLabel = group.ConceptCodeSequence.find(item => item.CodeValue === CORNERSTONEFREETEXT);
46
+ const csLabel = group.ConceptCodeSequence.findIndex(item => freeTextCodes.includes(item.CodeValue));
41
47
  if (csLabel !== -1) {
42
48
  group.ConceptCodeSequence.splice(csLabel, 1);
43
49
  if (group.ConceptCodeSequence.length === 0) {
@@ -64,9 +70,6 @@ class LabelData {
64
70
  FrameOfReferenceUID: frameOfReferenceUID
65
71
  } = annotation.metadata;
66
72
  const is3DMeasurement = !referencedImageId;
67
- const {
68
- worldPosition
69
- } = textBox;
70
73
  const {
71
74
  x,
72
75
  y,
@@ -74,27 +77,28 @@ class LabelData {
74
77
  } = toScoord({
75
78
  is3DMeasurement,
76
79
  referencedImageId
77
- }, worldPosition);
80
+ }, textBox.worldPosition);
78
81
  const graphicType = valueTypes.GraphicTypes.POINT;
79
82
  const relationshipType = valueTypes.RelationshipTypes.CONTAINS;
80
83
  const name = new coding.CodedConcept(TEXT_ANNOTATION_POSITION);
81
- if (is3DMeasurement) {
82
- const graphicData = [x, y, z];
83
- return new valueTypes.Scoord3DContentItem({
84
- name,
85
- relationshipType,
86
- graphicType,
87
- frameOfReferenceUID,
88
- graphicData
89
- });
90
- }
91
- const graphicData = [x, y];
92
- return new valueTypes.ScoordContentItem({
84
+ const scoord = is3DMeasurement ? new valueTypes.Scoord3DContentItem({
85
+ name,
86
+ relationshipType,
87
+ graphicType,
88
+ graphicData: [x, y, z],
89
+ frameOfReferenceUID
90
+ }) : new valueTypes.ScoordContentItem({
93
91
  name,
94
92
  relationshipType,
95
93
  graphicType,
96
- graphicData
94
+ graphicData: [x, y]
97
95
  });
96
+ scoord.ContentSequence = [{
97
+ RelationshipType: valueTypes.RelationshipTypes.SELECTED_FROM,
98
+ ValueType: valueTypes.ValueTypes.IMAGE,
99
+ ReferencedSOPSequence: this.ReferencedSOPSequence
100
+ }];
101
+ return scoord;
98
102
  }
99
103
  }
100
104
 
@@ -20,7 +20,8 @@ class Length extends BaseAdapter3D {
20
20
  } = MeasurementReport.getSetupMeasurementData(MeasurementGroup, sopInstanceUIDToImageIdMap, metadata, this.toolType);
21
21
  const cachedStats = referencedImageId ? {
22
22
  [`imageId:${referencedImageId}`]: {
23
- length: NUMGroup ? NUMGroup.MeasuredValueSequence.NumericValue : 0
23
+ length: NUMGroup ? NUMGroup.MeasuredValueSequence.NumericValue : 0,
24
+ unit: NUMGroup.MeasuredValueSequence.MeasurementUnitsCodeSequence.CodeValue
24
25
  }
25
26
  } : {};
26
27
  state.annotation.data = {
@@ -26,6 +26,9 @@ type SetupMeasurementData = {
26
26
  };
27
27
  NUMGroup: {
28
28
  MeasuredValueSequence: {
29
+ MeasurementUnitsCodeSequence: {
30
+ CodeValue: string;
31
+ };
29
32
  NumericValue: number;
30
33
  };
31
34
  };
@@ -4,6 +4,7 @@ import { vec3 } from 'gl-matrix';
4
4
  import BaseAdapter3D from './BaseAdapter3D.js';
5
5
  import { toScoords } from '../helpers/toScoordType.js';
6
6
  import '@cornerstonejs/core';
7
+ import { extractAllNUMGroups, restoreAdditionalMetrics } from './metricHandler.js';
7
8
 
8
9
  var _PlanarFreehandROI;
9
10
  const {
@@ -28,6 +29,9 @@ class PlanarFreehandROI extends BaseAdapter3D {
28
29
  if (isOpenContour) {
29
30
  points.push(worldCoords[0], worldCoords[worldCoords.length - 1]);
30
31
  }
32
+ const referencedSOPInstanceUID = state.sopInstanceUid;
33
+ const allNUMGroups = extractAllNUMGroups(MeasurementGroup, referencedSOPInstanceUID);
34
+ const measurementNUMGroups = allNUMGroups[referencedSOPInstanceUID] || {};
31
35
  state.annotation.data = {
32
36
  ...state.annotation.data,
33
37
  contour: {
@@ -43,7 +47,8 @@ class PlanarFreehandROI extends BaseAdapter3D {
43
47
  if (referencedImageId) {
44
48
  state.annotation.data.cachedStats = {
45
49
  [`imageId:${referencedImageId}`]: {
46
- area: NUMGroup ? NUMGroup.MeasuredValueSequence.NumericValue : null
50
+ area: NUMGroup ? NUMGroup.MeasuredValueSequence.NumericValue : null,
51
+ ...restoreAdditionalMetrics(measurementNUMGroups)
47
52
  }
48
53
  };
49
54
  }
@@ -81,13 +86,14 @@ class PlanarFreehandROI extends BaseAdapter3D {
81
86
  perimeter,
82
87
  mean,
83
88
  max,
84
- stdDev
89
+ stdDev,
90
+ length
85
91
  } = data.cachedStats[`imageId:${referencedImageId}`] || {};
86
92
  return {
87
93
  points,
88
94
  area,
89
95
  areaUnit,
90
- perimeter,
96
+ perimeter: perimeter ?? length,
91
97
  modalityUnit,
92
98
  mean,
93
99
  max,
@@ -22,6 +22,11 @@ export declare class RectangleROI extends BaseAdapter3D {
22
22
  })[];
23
23
  area: any;
24
24
  perimeter: any;
25
+ max: any;
26
+ mean: any;
27
+ stdDev: any;
28
+ areaUnit: any;
29
+ modalityUnit: any;
25
30
  trackingIdentifierTextValue: string;
26
31
  finding: any;
27
32
  findingSites: any;
@@ -3,6 +3,7 @@ import { toScoords } from '../helpers/toScoordType.js';
3
3
  import '@cornerstonejs/core';
4
4
  import MeasurementReport from './MeasurementReport.js';
5
5
  import BaseAdapter3D from './BaseAdapter3D.js';
6
+ import { extractAllNUMGroups, restoreAdditionalMetrics } from './metricHandler.js';
6
7
 
7
8
  var _RectangleROI;
8
9
  const {
@@ -23,10 +24,14 @@ class RectangleROI extends BaseAdapter3D {
23
24
  } = MeasurementReport.getSetupMeasurementData(MeasurementGroup, sopInstanceUIDToImageIdMap, metadata, this.toolType);
24
25
  const points = worldCoords.length === 5 ? worldCoords.slice(0, 4) : worldCoords;
25
26
  const areaGroup = MeasurementGroup.ContentSequence.find(g => g.ValueType === "NUM" && g.ConceptNameCodeSequence[0].CodeMeaning === "Area");
27
+ const referencedSOPInstanceUID = state.sopInstanceUid;
28
+ const allNUMGroups = extractAllNUMGroups(MeasurementGroup, referencedSOPInstanceUID);
29
+ const measurementNUMGroups = allNUMGroups[referencedSOPInstanceUID] || {};
26
30
  const cachedStats = referencedImageId ? {
27
31
  [`imageId:${referencedImageId}`]: {
28
32
  area: areaGroup?.MeasuredValueSequence?.[0]?.NumericValue || 0,
29
- areaUnit: areaGroup?.MeasuredValueSequence?.[0]?.MeasurementUnitsCodeSequence?.CodeValue
33
+ areaUnit: areaGroup?.MeasuredValueSequence?.[0]?.MeasurementUnitsCodeSequence?.CodeValue,
34
+ ...restoreAdditionalMetrics(measurementNUMGroups)
30
35
  }
31
36
  } : {};
32
37
  state.annotation.data = {
@@ -58,12 +63,22 @@ class RectangleROI extends BaseAdapter3D {
58
63
  const corners = toScoords(scoordProps, data.handles.points);
59
64
  const {
60
65
  area,
61
- perimeter
66
+ perimeter,
67
+ max,
68
+ mean,
69
+ stdDev,
70
+ areaUnit,
71
+ modalityUnit
62
72
  } = data.cachedStats[`imageId:${referencedImageId}`] || {};
63
73
  return {
64
74
  points: [corners[0], corners[1], corners[3], corners[2], corners[0]],
65
75
  area,
66
76
  perimeter,
77
+ max,
78
+ mean,
79
+ stdDev,
80
+ areaUnit,
81
+ modalityUnit,
67
82
  trackingIdentifierTextValue: this.trackingIdentifierTextValue,
68
83
  finding,
69
84
  findingSites: findingSites || [],
@@ -0,0 +1,13 @@
1
+ export interface AdditionalMetrics {
2
+ mean?: number;
3
+ stdDev?: number;
4
+ max?: number;
5
+ min?: number;
6
+ area?: number;
7
+ radius?: number;
8
+ modalityUnit?: string;
9
+ areaUnit?: string;
10
+ [key: string]: number | string | undefined;
11
+ }
12
+ export declare function extractAllNUMGroups(MeasurementGroup: any, referencedSOPInstanceUID: any): {};
13
+ export declare function restoreAdditionalMetrics(numGroups: any): AdditionalMetrics;
@@ -0,0 +1,74 @@
1
+ function extractAllNUMGroups(MeasurementGroup, referencedSOPInstanceUID) {
2
+ const numGroupsBySOPInstanceUID = {};
3
+ if (MeasurementGroup.ContentSequence) {
4
+ MeasurementGroup.ContentSequence.forEach(item => {
5
+ if (item.ValueType === "NUM" && item.ConceptNameCodeSequence) {
6
+ const codeMeaning = item.ConceptNameCodeSequence.CodeMeaning;
7
+ const numericValue = item.MeasuredValueSequence?.NumericValue;
8
+ const unitCode = item.MeasuredValueSequence?.MeasurementUnitsCodeSequence?.CodeValue;
9
+ if (numericValue !== undefined && referencedSOPInstanceUID) {
10
+ if (!numGroupsBySOPInstanceUID[referencedSOPInstanceUID]) {
11
+ numGroupsBySOPInstanceUID[referencedSOPInstanceUID] = {};
12
+ }
13
+ numGroupsBySOPInstanceUID[referencedSOPInstanceUID][codeMeaning] = {
14
+ value: numericValue,
15
+ unit: unitCode || ""
16
+ };
17
+ }
18
+ }
19
+ });
20
+ }
21
+ return numGroupsBySOPInstanceUID;
22
+ }
23
+ function restoreAdditionalMetrics(numGroups) {
24
+ const additionalMetrics = {};
25
+ let modalityUnit = "";
26
+ const metricMapping = {
27
+ Mean: "mean",
28
+ "Standard Deviation": "stdDev",
29
+ Maximum: "max",
30
+ Minimum: "min",
31
+ Area: "area",
32
+ Radius: "radius",
33
+ Perimeter: "perimeter",
34
+ Length: "length",
35
+ Width: "width"
36
+ };
37
+ const unitCategory = {
38
+ area: "areaUnit",
39
+ radius: "radiusUnit",
40
+ width: "widthUnit"
41
+ };
42
+ for (const [codeMeaning, metricKey] of Object.entries(metricMapping)) {
43
+ const group = numGroups[codeMeaning];
44
+ if (!group) {
45
+ continue;
46
+ }
47
+ const {
48
+ value,
49
+ unit
50
+ } = group;
51
+ if (value == null) {
52
+ continue;
53
+ }
54
+ additionalMetrics[metricKey] = value;
55
+ if (!unit) {
56
+ continue;
57
+ }
58
+ if (!modalityUnit) {
59
+ modalityUnit = unit;
60
+ }
61
+ const category = unitCategory[metricKey];
62
+ if (category) {
63
+ if (!additionalMetrics[category]) {
64
+ additionalMetrics[category] = unit;
65
+ }
66
+ } else {
67
+ additionalMetrics[`${metricKey}Unit`] = unit;
68
+ }
69
+ }
70
+ additionalMetrics.modalityUnit = modalityUnit;
71
+ return additionalMetrics;
72
+ }
73
+
74
+ export { extractAllNUMGroups, restoreAdditionalMetrics };
@@ -1 +1 @@
1
- export declare const version = "4.15.16";
1
+ export declare const version = "4.15.18";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/adapters",
3
- "version": "4.15.16",
3
+ "version": "4.15.18",
4
4
  "description": "Adapters for Cornerstone3D to/from formats including DICOM SR and others",
5
5
  "module": "./dist/esm/index.js",
6
6
  "types": "./dist/esm/index.d.ts",
@@ -84,13 +84,13 @@
84
84
  "dependencies": {
85
85
  "@babel/runtime-corejs2": "7.26.10",
86
86
  "buffer": "6.0.3",
87
- "dcmjs": "0.45.0",
87
+ "dcmjs": "0.48.0",
88
88
  "gl-matrix": "3.4.3",
89
89
  "ndarray": "1.0.19"
90
90
  },
91
91
  "peerDependencies": {
92
- "@cornerstonejs/core": "4.15.16",
93
- "@cornerstonejs/tools": "4.15.16"
92
+ "@cornerstonejs/core": "4.15.18",
93
+ "@cornerstonejs/tools": "4.15.18"
94
94
  },
95
- "gitHead": "734dd7f5fd416c386d08d6ab2d17f44226add8e2"
95
+ "gitHead": "2198d2e21481dd9f7e77148f98693ef0c2e5bdbc"
96
96
  }