@cornerstonejs/adapters 2.0.0-beta.8 → 2.0.1

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 (138) hide show
  1. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +493 -0
  2. package/dist/esm/adapters/Cornerstone/Angle.d.ts +42 -0
  3. package/dist/esm/adapters/Cornerstone/Angle.js +93 -0
  4. package/dist/esm/adapters/Cornerstone/ArrowAnnotate.d.ts +49 -0
  5. package/dist/esm/adapters/Cornerstone/ArrowAnnotate.js +97 -0
  6. package/dist/esm/adapters/Cornerstone/Bidirectional.d.ts +89 -0
  7. package/dist/esm/adapters/Cornerstone/Bidirectional.js +170 -0
  8. package/dist/esm/adapters/Cornerstone/CircleRoi.d.ts +58 -0
  9. package/dist/esm/adapters/Cornerstone/CircleRoi.js +115 -0
  10. package/dist/esm/adapters/Cornerstone/CobbAngle.d.ts +49 -0
  11. package/dist/esm/adapters/Cornerstone/CobbAngle.js +98 -0
  12. package/dist/esm/adapters/Cornerstone/EllipticalRoi.d.ts +57 -0
  13. package/dist/esm/adapters/Cornerstone/EllipticalRoi.js +178 -0
  14. package/dist/esm/adapters/Cornerstone/FreehandRoi.d.ts +42 -0
  15. package/dist/esm/adapters/Cornerstone/FreehandRoi.js +89 -0
  16. package/dist/esm/adapters/Cornerstone/Length.d.ts +39 -0
  17. package/dist/esm/adapters/Cornerstone/Length.js +82 -0
  18. package/dist/esm/adapters/Cornerstone/MeasurementReport.d.ts +29 -0
  19. package/dist/esm/adapters/Cornerstone/MeasurementReport.js +276 -0
  20. package/dist/esm/adapters/Cornerstone/ParametricMap.d.ts +7 -0
  21. package/dist/esm/adapters/Cornerstone/ParametricMap.js +210 -0
  22. package/dist/esm/adapters/Cornerstone/RectangleRoi.d.ts +44 -0
  23. package/dist/esm/adapters/Cornerstone/RectangleRoi.js +97 -0
  24. package/dist/esm/adapters/Cornerstone/Segmentation.d.ts +7 -0
  25. package/dist/esm/adapters/Cornerstone/Segmentation.js +73 -0
  26. package/dist/esm/adapters/Cornerstone/Segmentation_3X.d.ts +13 -0
  27. package/dist/esm/adapters/Cornerstone/Segmentation_3X.js +411 -0
  28. package/dist/esm/adapters/Cornerstone/Segmentation_4X.d.ts +13 -0
  29. package/dist/esm/adapters/Cornerstone/Segmentation_4X.js +1152 -0
  30. package/dist/esm/adapters/Cornerstone/cornerstone4Tag.d.ts +2 -0
  31. package/dist/esm/adapters/Cornerstone/cornerstone4Tag.js +3 -0
  32. package/dist/esm/adapters/Cornerstone/index.d.ts +34 -0
  33. package/dist/esm/adapters/Cornerstone/index.js +33 -0
  34. package/dist/esm/adapters/Cornerstone3D/Angle.js +109 -0
  35. package/dist/esm/adapters/Cornerstone3D/ArrowAnnotate.d.ts +35 -0
  36. package/dist/esm/adapters/Cornerstone3D/ArrowAnnotate.js +123 -0
  37. package/dist/esm/adapters/Cornerstone3D/Bidirectional.js +147 -0
  38. package/dist/{types → esm}/adapters/Cornerstone3D/CircleROI.d.ts +0 -7
  39. package/dist/esm/adapters/Cornerstone3D/CircleROI.js +96 -0
  40. package/dist/esm/adapters/Cornerstone3D/CobbAngle.js +113 -0
  41. package/dist/esm/adapters/Cornerstone3D/CodingScheme.d.ts +9 -0
  42. package/dist/esm/adapters/Cornerstone3D/CodingScheme.js +15 -0
  43. package/dist/esm/adapters/Cornerstone3D/EllipticalROI.js +160 -0
  44. package/dist/esm/adapters/Cornerstone3D/Length.d.ts +41 -0
  45. package/dist/esm/adapters/Cornerstone3D/Length.js +101 -0
  46. package/dist/{types → esm}/adapters/Cornerstone3D/MeasurementReport.d.ts +1 -8
  47. package/dist/esm/adapters/Cornerstone3D/MeasurementReport.js +281 -0
  48. package/dist/esm/adapters/Cornerstone3D/ParametricMap/generateToolState.d.ts +3 -0
  49. package/dist/esm/adapters/Cornerstone3D/ParametricMap/generateToolState.js +11 -0
  50. package/dist/esm/adapters/Cornerstone3D/ParametricMap/index.d.ts +1 -0
  51. package/dist/esm/adapters/Cornerstone3D/ParametricMap/index.js +1 -0
  52. package/dist/{types → esm}/adapters/Cornerstone3D/PlanarFreehandROI.d.ts +0 -2
  53. package/dist/esm/adapters/Cornerstone3D/PlanarFreehandROI.js +126 -0
  54. package/dist/esm/adapters/Cornerstone3D/Probe.d.ts +33 -0
  55. package/dist/esm/adapters/Cornerstone3D/Probe.js +87 -0
  56. package/dist/esm/adapters/Cornerstone3D/RTStruct/RTSS.d.ts +67 -0
  57. package/dist/esm/adapters/Cornerstone3D/RTStruct/RTSS.js +175 -0
  58. package/dist/esm/adapters/Cornerstone3D/RTStruct/index.js +6 -0
  59. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getPatientModule.d.ts +13 -0
  60. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getPatientModule.js +22 -0
  61. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getRTROIObservationsSequence.d.ts +6 -0
  62. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getRTROIObservationsSequence.js +10 -0
  63. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getRTSeriesModule.d.ts +4 -0
  64. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getRTSeriesModule.js +9 -0
  65. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getReferencedFrameOfReferenceSequence.d.ts +11 -0
  66. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getReferencedFrameOfReferenceSequence.js +22 -0
  67. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getReferencedSeriesSequence.d.ts +4 -0
  68. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getReferencedSeriesSequence.js +27 -0
  69. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getStructureSetModule.d.ts +7 -0
  70. package/dist/esm/adapters/Cornerstone3D/RTStruct/utilities/getStructureSetModule.js +12 -0
  71. package/dist/esm/adapters/Cornerstone3D/RectangleROI.js +94 -0
  72. package/dist/{types → esm}/adapters/Cornerstone3D/Segmentation/generateLabelMaps2DFrom3D.d.ts +0 -6
  73. package/dist/esm/adapters/Cornerstone3D/Segmentation/generateLabelMaps2DFrom3D.js +34 -0
  74. package/dist/esm/adapters/Cornerstone3D/Segmentation/generateSegmentation.d.ts +2 -0
  75. package/dist/esm/adapters/Cornerstone3D/Segmentation/generateSegmentation.js +29 -0
  76. package/dist/esm/adapters/Cornerstone3D/Segmentation/generateToolState.d.ts +2 -0
  77. package/dist/esm/adapters/Cornerstone3D/Segmentation/generateToolState.js +9 -0
  78. package/dist/esm/adapters/Cornerstone3D/Segmentation/index.js +3 -0
  79. package/dist/esm/adapters/Cornerstone3D/UltrasoundDirectional.js +93 -0
  80. package/dist/esm/adapters/Cornerstone3D/cornerstone3DTag.d.ts +2 -0
  81. package/dist/esm/adapters/Cornerstone3D/cornerstone3DTag.js +3 -0
  82. package/dist/{types → esm}/adapters/Cornerstone3D/index.d.ts +18 -6
  83. package/dist/esm/adapters/Cornerstone3D/index.js +45 -0
  84. package/dist/esm/adapters/Cornerstone3D/isValidCornerstoneTrackingIdentifier.js +18 -0
  85. package/dist/esm/adapters/VTKjs/Segmentation.d.ts +3 -0
  86. package/dist/esm/adapters/VTKjs/Segmentation.js +186 -0
  87. package/dist/esm/adapters/VTKjs/index.d.ts +5 -0
  88. package/dist/esm/adapters/VTKjs/index.js +7 -0
  89. package/dist/{types → esm}/adapters/enums/Events.d.ts +0 -6
  90. package/dist/esm/adapters/enums/Events.js +7 -0
  91. package/dist/esm/adapters/enums/index.js +1 -0
  92. package/dist/esm/adapters/helpers/checkIfPerpendicular.d.ts +1 -0
  93. package/dist/esm/adapters/helpers/checkIfPerpendicular.js +7 -0
  94. package/dist/esm/adapters/helpers/checkOrientation.d.ts +1 -0
  95. package/dist/esm/adapters/helpers/checkOrientation.js +22 -0
  96. package/dist/esm/adapters/helpers/codeMeaningEquals.d.ts +2 -0
  97. package/dist/esm/adapters/helpers/codeMeaningEquals.js +7 -0
  98. package/dist/esm/adapters/helpers/compareArrays.d.ts +1 -0
  99. package/dist/esm/adapters/helpers/compareArrays.js +16 -0
  100. package/dist/esm/adapters/helpers/downloadDICOMData.d.ts +5 -0
  101. package/dist/esm/adapters/helpers/downloadDICOMData.js +26 -0
  102. package/dist/esm/adapters/helpers/getDatasetsFromImages.d.ts +1 -0
  103. package/dist/esm/adapters/helpers/getDatasetsFromImages.js +33 -0
  104. package/dist/esm/adapters/helpers/graphicTypeEquals.d.ts +2 -0
  105. package/dist/esm/adapters/helpers/graphicTypeEquals.js +7 -0
  106. package/dist/esm/adapters/helpers/index.js +4 -0
  107. package/dist/esm/adapters/helpers/toArray.js +5 -0
  108. package/dist/esm/adapters/index.d.ts +66 -0
  109. package/dist/esm/adapters/index.js +24 -0
  110. package/dist/esm/index.d.ts +2 -0
  111. package/dist/esm/index.js +5 -0
  112. package/dist/umd/adapters.umd.js +5769 -0
  113. package/dist/umd/adapters.umd.js.map +1 -0
  114. package/package.json +47 -11
  115. package/dist/adapters.es.js +0 -5585
  116. package/dist/adapters.es.js.map +0 -1
  117. package/dist/types/adapters/Cornerstone/index.d.ts +0 -16
  118. package/dist/types/adapters/Cornerstone3D/RTStruct/RTSS.d.ts +0 -26
  119. package/dist/types/adapters/Cornerstone3D/Segmentation/generateSegmentation.d.ts +0 -8
  120. package/dist/types/adapters/Cornerstone3D/Segmentation/generateToolState.d.ts +0 -16
  121. package/dist/types/adapters/VTKjs/index.d.ts +0 -4
  122. package/dist/types/adapters/helpers/codeMeaningEquals.d.ts +0 -9
  123. package/dist/types/adapters/helpers/downloadDICOMData.d.ts +0 -10
  124. package/dist/types/adapters/helpers/graphicTypeEquals.d.ts +0 -7
  125. package/dist/types/adapters/index.d.ts +0 -49
  126. package/dist/types/index.d.ts +0 -2
  127. /package/dist/{types → esm}/adapters/Cornerstone3D/Angle.d.ts +0 -0
  128. /package/dist/{types → esm}/adapters/Cornerstone3D/Bidirectional.d.ts +0 -0
  129. /package/dist/{types → esm}/adapters/Cornerstone3D/CobbAngle.d.ts +0 -0
  130. /package/dist/{types → esm}/adapters/Cornerstone3D/EllipticalROI.d.ts +0 -0
  131. /package/dist/{types → esm}/adapters/Cornerstone3D/RTStruct/index.d.ts +0 -0
  132. /package/dist/{types → esm}/adapters/Cornerstone3D/RectangleROI.d.ts +0 -0
  133. /package/dist/{types → esm}/adapters/Cornerstone3D/Segmentation/index.d.ts +0 -0
  134. /package/dist/{types → esm}/adapters/Cornerstone3D/UltrasoundDirectional.d.ts +0 -0
  135. /package/dist/{types → esm}/adapters/Cornerstone3D/isValidCornerstoneTrackingIdentifier.d.ts +0 -0
  136. /package/dist/{types → esm}/adapters/enums/index.d.ts +0 -0
  137. /package/dist/{types → esm}/adapters/helpers/index.d.ts +0 -0
  138. /package/dist/{types → esm}/adapters/helpers/toArray.d.ts +0 -0
@@ -0,0 +1,1152 @@
1
+ import { asyncToGenerator as _asyncToGenerator, regeneratorRuntime as _regeneratorRuntime, toConsumableArray as _toConsumableArray, createForOfIteratorHelper as _createForOfIteratorHelper, slicedToArray as _slicedToArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
2
+ import { utilities, data, normalizers, derivations, log } from 'dcmjs';
3
+ import ndarray from 'ndarray';
4
+ import getDatasetsFromImages from '../helpers/getDatasetsFromImages.js';
5
+ import checkOrientation from '../helpers/checkOrientation.js';
6
+ import compareArrays from '../helpers/compareArrays.js';
7
+ import Events from '../enums/Events.js';
8
+
9
+ var _utilities$orientatio = utilities.orientation,
10
+ rotateDirectionCosinesInPlane = _utilities$orientatio.rotateDirectionCosinesInPlane,
11
+ flipIOP = _utilities$orientatio.flipImageOrientationPatient,
12
+ flipMatrix2D = _utilities$orientatio.flipMatrix2D,
13
+ rotateMatrix902D = _utilities$orientatio.rotateMatrix902D;
14
+ var BitArray = data.BitArray,
15
+ DicomMessage = data.DicomMessage,
16
+ DicomMetaDictionary = data.DicomMetaDictionary;
17
+ var Normalizer = normalizers.Normalizer;
18
+ var SegmentationDerivation = derivations.Segmentation;
19
+ var _utilities$compressio = utilities.compression,
20
+ encode = _utilities$compressio.encode,
21
+ decode = _utilities$compressio.decode;
22
+
23
+ /**
24
+ *
25
+ * @typedef {Object} BrushData
26
+ * @property {Object} toolState - The cornerstoneTools global toolState.
27
+ * @property {Object[]} segments - The cornerstoneTools segment metadata that corresponds to the
28
+ * seriesInstanceUid.
29
+ */
30
+ var generateSegmentationDefaultOptions = {
31
+ includeSliceSpacing: true,
32
+ rleEncode: false
33
+ };
34
+
35
+ /**
36
+ * generateSegmentation - Generates cornerstoneTools brush data, given a stack of
37
+ * imageIds, images and the cornerstoneTools brushData.
38
+ *
39
+ * @param {object[]} images An array of cornerstone images that contain the source
40
+ * data under `image.data.byteArray.buffer`.
41
+ * @param {Object|Object[]} inputLabelmaps3D The cornerstone `Labelmap3D` object, or an array of objects.
42
+ * @param {Object} userOptions Options to pass to the segmentation derivation and `fillSegmentation`.
43
+ * @returns {Blob}
44
+ */
45
+ function generateSegmentation(images, inputLabelmaps3D) {
46
+ var userOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
47
+ var isMultiframe = images[0].imageId.includes("?frame");
48
+ var segmentation = _createSegFromImages(images, isMultiframe, userOptions);
49
+ return fillSegmentation(segmentation, inputLabelmaps3D, userOptions);
50
+ }
51
+
52
+ /**
53
+ * Fills a given segmentation object with data from the input labelmaps3D
54
+ *
55
+ * @param segmentation - The segmentation object to be filled.
56
+ * @param inputLabelmaps3D - An array of 3D labelmaps, or a single 3D labelmap.
57
+ * @param userOptions - Optional configuration settings. Will override the default options.
58
+ *
59
+ * @returns {object} The filled segmentation object.
60
+ */
61
+ function fillSegmentation(segmentation, inputLabelmaps3D) {
62
+ var userOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
63
+ var options = Object.assign({}, generateSegmentationDefaultOptions, userOptions);
64
+
65
+ // Use another variable so we don't redefine labelmaps3D.
66
+ var labelmaps3D = Array.isArray(inputLabelmaps3D) ? inputLabelmaps3D : [inputLabelmaps3D];
67
+ var numberOfFrames = 0;
68
+ var referencedFramesPerLabelmap = [];
69
+ var _loop = function _loop() {
70
+ var labelmap3D = labelmaps3D[labelmapIndex];
71
+ var labelmaps2D = labelmap3D.labelmaps2D,
72
+ metadata = labelmap3D.metadata;
73
+ var referencedFramesPerSegment = [];
74
+ for (var i = 1; i < metadata.length; i++) {
75
+ if (metadata[i]) {
76
+ referencedFramesPerSegment[i] = [];
77
+ }
78
+ }
79
+ var _loop2 = function _loop2(_i) {
80
+ var labelmap2D = labelmaps2D[_i];
81
+ if (labelmaps2D[_i]) {
82
+ var segmentsOnLabelmap = labelmap2D.segmentsOnLabelmap;
83
+ segmentsOnLabelmap.forEach(function (segmentIndex) {
84
+ if (segmentIndex !== 0) {
85
+ referencedFramesPerSegment[segmentIndex].push(_i);
86
+ numberOfFrames++;
87
+ }
88
+ });
89
+ }
90
+ };
91
+ for (var _i = 0; _i < labelmaps2D.length; _i++) {
92
+ _loop2(_i);
93
+ }
94
+ referencedFramesPerLabelmap[labelmapIndex] = referencedFramesPerSegment;
95
+ };
96
+ for (var labelmapIndex = 0; labelmapIndex < labelmaps3D.length; labelmapIndex++) {
97
+ _loop();
98
+ }
99
+ segmentation.setNumberOfFrames(numberOfFrames);
100
+ for (var _labelmapIndex = 0; _labelmapIndex < labelmaps3D.length; _labelmapIndex++) {
101
+ var referencedFramesPerSegment = referencedFramesPerLabelmap[_labelmapIndex];
102
+ var labelmap3D = labelmaps3D[_labelmapIndex];
103
+ var metadata = labelmap3D.metadata;
104
+ for (var segmentIndex = 1; segmentIndex < referencedFramesPerSegment.length; segmentIndex++) {
105
+ var referencedFrameIndicies = referencedFramesPerSegment[segmentIndex];
106
+ if (referencedFrameIndicies) {
107
+ // Frame numbers start from 1.
108
+ var referencedFrameNumbers = referencedFrameIndicies.map(function (element) {
109
+ return element + 1;
110
+ });
111
+ var segmentMetadata = metadata[segmentIndex];
112
+ var labelmaps = _getLabelmapsFromReferencedFrameIndicies(labelmap3D, referencedFrameIndicies);
113
+ segmentation.addSegmentFromLabelmap(segmentMetadata, labelmaps, segmentIndex, referencedFrameNumbers);
114
+ }
115
+ }
116
+ }
117
+ if (options.rleEncode) {
118
+ var rleEncodedFrames = encode(segmentation.dataset.PixelData, numberOfFrames, segmentation.dataset.Rows, segmentation.dataset.Columns);
119
+
120
+ // Must use fractional now to RLE encode, as the DICOM standard only allows BitStored && BitsAllocated
121
+ // to be 1 for BINARY. This is not ideal and there should be a better format for compression in this manner
122
+ // added to the standard.
123
+ segmentation.assignToDataset({
124
+ BitsAllocated: "8",
125
+ BitsStored: "8",
126
+ HighBit: "7",
127
+ SegmentationType: "FRACTIONAL",
128
+ SegmentationFractionalType: "PROBABILITY",
129
+ MaximumFractionalValue: "255"
130
+ });
131
+ segmentation.dataset._meta.TransferSyntaxUID = {
132
+ Value: ["1.2.840.10008.1.2.5"],
133
+ vr: "UI"
134
+ };
135
+ segmentation.dataset.SpecificCharacterSet = "ISO_IR 192";
136
+ segmentation.dataset._vrMap.PixelData = "OB";
137
+ segmentation.dataset.PixelData = rleEncodedFrames;
138
+ } else {
139
+ // If no rleEncoding, at least bitpack the data.
140
+ segmentation.bitPackPixelData();
141
+ }
142
+ return segmentation;
143
+ }
144
+ function _getLabelmapsFromReferencedFrameIndicies(labelmap3D, referencedFrameIndicies) {
145
+ var labelmaps2D = labelmap3D.labelmaps2D;
146
+ var labelmaps = [];
147
+ for (var i = 0; i < referencedFrameIndicies.length; i++) {
148
+ var frame = referencedFrameIndicies[i];
149
+ labelmaps.push(labelmaps2D[frame].pixelData);
150
+ }
151
+ return labelmaps;
152
+ }
153
+
154
+ /**
155
+ * _createSegFromImages - description
156
+ *
157
+ * @param {Object[]} images An array of the cornerstone image objects.
158
+ * @param {Boolean} isMultiframe Whether the images are multiframe.
159
+ * @returns {Object} The Seg derived dataSet.
160
+ */
161
+ function _createSegFromImages(images, isMultiframe, options) {
162
+ var multiframe = getDatasetsFromImages(images, isMultiframe);
163
+ return new SegmentationDerivation([multiframe], options);
164
+ }
165
+
166
+ /**
167
+ * generateToolState - Given a set of cornerstoneTools imageIds and a Segmentation buffer,
168
+ * derive cornerstoneTools toolState and brush metadata.
169
+ *
170
+ * @param {string[]} imageIds - An array of the imageIds.
171
+ * @param {ArrayBuffer} arrayBuffer - The SEG arrayBuffer.
172
+ * @param {*} metadataProvider.
173
+ * @param {obj} options - Options object.
174
+ *
175
+ * @return {[]ArrayBuffer}a list of array buffer for each labelMap
176
+ * @return {Object} an object from which the segment metadata can be derived
177
+ * @return {[][][]} 2D list containing the track of segments per frame
178
+ * @return {[][][]} 3D list containing the track of segments per frame for each labelMap
179
+ * (available only for the overlapping case).
180
+ */
181
+ function generateToolState(_x, _x2, _x3, _x4) {
182
+ return _generateToolState.apply(this, arguments);
183
+ } // function insertPixelDataPerpendicular(
184
+ // segmentsOnFrame,
185
+ // labelmapBuffer,
186
+ // pixelData,
187
+ // multiframe,
188
+ // imageIds,
189
+ // validOrientations,
190
+ // metadataProvider
191
+ // ) {
192
+ // const {
193
+ // SharedFunctionalGroupsSequence,
194
+ // PerFrameFunctionalGroupsSequence,
195
+ // Rows,
196
+ // Columns
197
+ // } = multiframe;
198
+ // const firstImagePlaneModule = metadataProvider.get(
199
+ // "imagePlaneModule",
200
+ // imageIds[0]
201
+ // );
202
+ // const lastImagePlaneModule = metadataProvider.get(
203
+ // "imagePlaneModule",
204
+ // imageIds[imageIds.length - 1]
205
+ // );
206
+ // console.log(firstImagePlaneModule);
207
+ // console.log(lastImagePlaneModule);
208
+ // const corners = [
209
+ // ...getCorners(firstImagePlaneModule),
210
+ // ...getCorners(lastImagePlaneModule)
211
+ // ];
212
+ // console.log(`corners:`);
213
+ // console.log(corners);
214
+ // const indexToWorld = mat4.create();
215
+ // const ippFirstFrame = firstImagePlaneModule.imagePositionPatient;
216
+ // const rowCosines = Array.isArray(firstImagePlaneModule.rowCosines)
217
+ // ? [...firstImagePlaneModule.rowCosines]
218
+ // : [
219
+ // firstImagePlaneModule.rowCosines.x,
220
+ // firstImagePlaneModule.rowCosines.y,
221
+ // firstImagePlaneModule.rowCosines.z
222
+ // ];
223
+ // const columnCosines = Array.isArray(firstImagePlaneModule.columnCosines)
224
+ // ? [...firstImagePlaneModule.columnCosines]
225
+ // : [
226
+ // firstImagePlaneModule.columnCosines.x,
227
+ // firstImagePlaneModule.columnCosines.y,
228
+ // firstImagePlaneModule.columnCosines.z
229
+ // ];
230
+ // const { pixelSpacing } = firstImagePlaneModule;
231
+ // mat4.set(
232
+ // indexToWorld,
233
+ // // Column 1
234
+ // 0,
235
+ // 0,
236
+ // 0,
237
+ // ippFirstFrame[0],
238
+ // // Column 2
239
+ // 0,
240
+ // 0,
241
+ // 0,
242
+ // ippFirstFrame[1],
243
+ // // Column 3
244
+ // 0,
245
+ // 0,
246
+ // 0,
247
+ // ippFirstFrame[2],
248
+ // // Column 4
249
+ // 0,
250
+ // 0,
251
+ // 0,
252
+ // 1
253
+ // );
254
+ // // TODO -> Get origin and (x,y,z) increments to build a translation matrix:
255
+ // // TODO -> Equation C.7.6.2.1-1
256
+ // // | cx*di rx* Xx 0 | |x|
257
+ // // | cy*di ry Xy 0 | |y|
258
+ // // | cz*di rz Xz 0 | |z|
259
+ // // | tx ty tz 1 | |1|
260
+ // // const [
261
+ // // 0, 0 , 0 , 0,
262
+ // // 0, 0 , 0 , 0,
263
+ // // 0, 0 , 0 , 0,
264
+ // // ipp[0], ipp[1] , ipp[2] , 1,
265
+ // // ]
266
+ // // Each frame:
267
+ // // Find which corner the first voxel lines up with (one of 8 corners.)
268
+ // // Find how i,j,k orient with respect to source volume.
269
+ // // Go through each frame, find location in source to start, and whether to increment +/ix,+/-y,+/-z
270
+ // // through each voxel.
271
+ // // [1,0,0,0,1,0]
272
+ // // const [
273
+ // // ]
274
+ // // Invert transformation matrix to get worldToIndex
275
+ // // Apply world to index on each point to fill up the matrix.
276
+ // // const sharedImageOrientationPatient = SharedFunctionalGroupsSequence.PlaneOrientationSequence
277
+ // // ? SharedFunctionalGroupsSequence.PlaneOrientationSequence
278
+ // // .ImageOrientationPatient
279
+ // // : undefined;
280
+ // // const sliceLength = Columns * Rows;
281
+ // }
282
+ // function getCorners(imagePlaneModule) {
283
+ // // console.log(imagePlaneModule);
284
+ // const {
285
+ // rows,
286
+ // columns,
287
+ // rowCosines,
288
+ // columnCosines,
289
+ // imagePositionPatient: ipp,
290
+ // rowPixelSpacing,
291
+ // columnPixelSpacing
292
+ // } = imagePlaneModule;
293
+ // const rowLength = columns * columnPixelSpacing;
294
+ // const columnLength = rows * rowPixelSpacing;
295
+ // const entireRowVector = [
296
+ // rowLength * columnCosines[0],
297
+ // rowLength * columnCosines[1],
298
+ // rowLength * columnCosines[2]
299
+ // ];
300
+ // const entireColumnVector = [
301
+ // columnLength * rowCosines[0],
302
+ // columnLength * rowCosines[1],
303
+ // columnLength * rowCosines[2]
304
+ // ];
305
+ // const topLeft = [ipp[0], ipp[1], ipp[2]];
306
+ // const topRight = [
307
+ // topLeft[0] + entireRowVector[0],
308
+ // topLeft[1] + entireRowVector[1],
309
+ // topLeft[2] + entireRowVector[2]
310
+ // ];
311
+ // const bottomLeft = [
312
+ // topLeft[0] + entireColumnVector[0],
313
+ // topLeft[1] + entireColumnVector[1],
314
+ // topLeft[2] + entireColumnVector[2]
315
+ // ];
316
+ // const bottomRight = [
317
+ // bottomLeft[0] + entireRowVector[0],
318
+ // bottomLeft[1] + entireRowVector[1],
319
+ // bottomLeft[2] + entireRowVector[2]
320
+ // ];
321
+ // return [topLeft, topRight, bottomLeft, bottomRight];
322
+ // }
323
+ /**
324
+ * Find the reference frame of the segmentation frame in the source data.
325
+ *
326
+ * @param {Object} multiframe dicom metadata
327
+ * @param {Int} frameSegment frame dicom index
328
+ * @param {String[]} imageIds A list of imageIds.
329
+ * @param {Object} sopUIDImageIdIndexMap A map of SOPInstanceUID to imageId
330
+ * @param {Float} tolerance The tolerance parameter
331
+ *
332
+ * @returns {String} Returns the imageId
333
+ */
334
+ function _generateToolState() {
335
+ _generateToolState = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(imageIds, arrayBuffer, metadataProvider, options) {
336
+ var _options$skipOverlapp, skipOverlapping, _options$tolerance, tolerance, _options$TypedArrayCo, TypedArrayConstructor, _options$maxBytesPerC, maxBytesPerChunk, eventTarget, triggerEvent, dicomData, dataset, multiframe, imagePlaneModule, generalSeriesModule, SeriesInstanceUID, ImageOrientationPatient, validOrientations, sliceLength, segMetadata, TransferSyntaxUID, pixelData, pixelDataChunks, rleEncodedFrames, orientation, sopUIDImageIdIndexMap, overlapping, insertFunction, segmentsOnFrameArray, segmentsOnFrame, arrayBufferLength, labelmapBufferArray, imageIdMaps, segmentsPixelIndices, overlappingSegments, centroidXYZ;
337
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
338
+ while (1) switch (_context.prev = _context.next) {
339
+ case 0:
340
+ _options$skipOverlapp = options.skipOverlapping, skipOverlapping = _options$skipOverlapp === void 0 ? false : _options$skipOverlapp, _options$tolerance = options.tolerance, tolerance = _options$tolerance === void 0 ? 1e-3 : _options$tolerance, _options$TypedArrayCo = options.TypedArrayConstructor, TypedArrayConstructor = _options$TypedArrayCo === void 0 ? Uint8Array : _options$TypedArrayCo, _options$maxBytesPerC = options.maxBytesPerChunk, maxBytesPerChunk = _options$maxBytesPerC === void 0 ? 199000000 : _options$maxBytesPerC, eventTarget = options.eventTarget, triggerEvent = options.triggerEvent;
341
+ dicomData = DicomMessage.readFile(arrayBuffer);
342
+ dataset = DicomMetaDictionary.naturalizeDataset(dicomData.dict);
343
+ dataset._meta = DicomMetaDictionary.namifyDataset(dicomData.meta);
344
+ multiframe = Normalizer.normalizeToDataset([dataset]);
345
+ imagePlaneModule = metadataProvider.get("imagePlaneModule", imageIds[0]);
346
+ generalSeriesModule = metadataProvider.get("generalSeriesModule", imageIds[0]);
347
+ SeriesInstanceUID = generalSeriesModule.seriesInstanceUID;
348
+ if (!imagePlaneModule) {
349
+ console.warn("Insufficient metadata, imagePlaneModule missing.");
350
+ }
351
+ ImageOrientationPatient = Array.isArray(imagePlaneModule.rowCosines) ? [].concat(_toConsumableArray(imagePlaneModule.rowCosines), _toConsumableArray(imagePlaneModule.columnCosines)) : [imagePlaneModule.rowCosines.x, imagePlaneModule.rowCosines.y, imagePlaneModule.rowCosines.z, imagePlaneModule.columnCosines.x, imagePlaneModule.columnCosines.y, imagePlaneModule.columnCosines.z]; // Get IOP from ref series, compute supported orientations:
352
+ validOrientations = getValidOrientations(ImageOrientationPatient);
353
+ sliceLength = multiframe.Columns * multiframe.Rows;
354
+ segMetadata = getSegmentMetadata(multiframe, SeriesInstanceUID);
355
+ TransferSyntaxUID = multiframe._meta.TransferSyntaxUID.Value[0];
356
+ if (!(TransferSyntaxUID === "1.2.840.10008.1.2.5")) {
357
+ _context.next = 23;
358
+ break;
359
+ }
360
+ rleEncodedFrames = Array.isArray(multiframe.PixelData) ? multiframe.PixelData : [multiframe.PixelData];
361
+ pixelData = decode(rleEncodedFrames, multiframe.Rows, multiframe.Columns);
362
+ if (!(multiframe.BitsStored === 1)) {
363
+ _context.next = 20;
364
+ break;
365
+ }
366
+ console.warn("No implementation for rle + bitbacking.");
367
+ return _context.abrupt("return");
368
+ case 20:
369
+ // Todo: need to test this with rle data
370
+ pixelDataChunks = [pixelData];
371
+ _context.next = 26;
372
+ break;
373
+ case 23:
374
+ pixelDataChunks = unpackPixelData(multiframe, {
375
+ maxBytesPerChunk: maxBytesPerChunk
376
+ });
377
+ if (pixelDataChunks) {
378
+ _context.next = 26;
379
+ break;
380
+ }
381
+ throw new Error("Fractional segmentations are not yet supported");
382
+ case 26:
383
+ orientation = checkOrientation(multiframe, validOrientations, [imagePlaneModule.rows, imagePlaneModule.columns, imageIds.length], tolerance); // Pre-compute the sop UID to imageId index map so that in the for loop
384
+ // we don't have to call metadataProvider.get() for each imageId over
385
+ // and over again.
386
+ sopUIDImageIdIndexMap = imageIds.reduce(function (acc, imageId) {
387
+ var _metadataProvider$get = metadataProvider.get("generalImageModule", imageId),
388
+ sopInstanceUID = _metadataProvider$get.sopInstanceUID;
389
+ acc[sopInstanceUID] = imageId;
390
+ return acc;
391
+ }, {});
392
+ overlapping = false;
393
+ if (!skipOverlapping) {
394
+ overlapping = checkSEGsOverlapping(pixelDataChunks, multiframe, imageIds, validOrientations, metadataProvider, tolerance, TypedArrayConstructor, sopUIDImageIdIndexMap);
395
+ }
396
+ _context.t0 = orientation;
397
+ _context.next = _context.t0 === "Planar" ? 33 : _context.t0 === "Perpendicular" ? 35 : _context.t0 === "Oblique" ? 36 : 37;
398
+ break;
399
+ case 33:
400
+ if (overlapping) {
401
+ insertFunction = insertOverlappingPixelDataPlanar;
402
+ } else {
403
+ insertFunction = insertPixelDataPlanar;
404
+ }
405
+ return _context.abrupt("break", 37);
406
+ case 35:
407
+ throw new Error("Segmentations orthogonal to the acquisition plane of the source data are not yet supported.");
408
+ case 36:
409
+ throw new Error("Segmentations oblique to the acquisition plane of the source data are not yet supported.");
410
+ case 37:
411
+ /* if SEGs are overlapping:
412
+ 1) the labelmapBuffer will contain M volumes which have non-overlapping segments;
413
+ 2) segmentsOnFrame will have M * numberOfFrames values to track in which labelMap are the segments;
414
+ 3) insertFunction will return the number of LabelMaps
415
+ 4) generateToolState return is an array*/
416
+ segmentsOnFrameArray = [];
417
+ segmentsOnFrameArray[0] = [];
418
+ segmentsOnFrame = [];
419
+ arrayBufferLength = sliceLength * imageIds.length * TypedArrayConstructor.BYTES_PER_ELEMENT;
420
+ labelmapBufferArray = [];
421
+ labelmapBufferArray[0] = new ArrayBuffer(arrayBufferLength);
422
+
423
+ // Pre-compute the indices and metadata so that we don't have to call
424
+ // a function for each imageId in the for loop.
425
+ imageIdMaps = imageIds.reduce(function (acc, curr, index) {
426
+ acc.indices[curr] = index;
427
+ acc.metadata[curr] = metadataProvider.get("instance", curr);
428
+ return acc;
429
+ }, {
430
+ indices: {},
431
+ metadata: {}
432
+ }); // This is the centroid calculation for each segment Index, the data structure
433
+ // is a Map with key = segmentIndex and value = {imageIdIndex: centroid, ...}
434
+ // later on we will use this data structure to calculate the centroid of the
435
+ // segment in the labelmapBuffer
436
+ segmentsPixelIndices = new Map();
437
+ _context.next = 47;
438
+ return insertFunction(segmentsOnFrame, segmentsOnFrameArray, labelmapBufferArray, pixelDataChunks, multiframe, imageIds, validOrientations, metadataProvider, tolerance, TypedArrayConstructor, segmentsPixelIndices, sopUIDImageIdIndexMap, imageIdMaps, eventTarget, triggerEvent);
439
+ case 47:
440
+ overlappingSegments = _context.sent;
441
+ // calculate the centroid of each segment
442
+ centroidXYZ = new Map();
443
+ segmentsPixelIndices.forEach(function (imageIdIndexBufferIndex, segmentIndex) {
444
+ var centroids = calculateCentroid(imageIdIndexBufferIndex, multiframe, metadataProvider, imageIds);
445
+ centroidXYZ.set(segmentIndex, centroids);
446
+ });
447
+ return _context.abrupt("return", {
448
+ labelmapBufferArray: labelmapBufferArray,
449
+ segMetadata: segMetadata,
450
+ segmentsOnFrame: segmentsOnFrame,
451
+ segmentsOnFrameArray: segmentsOnFrameArray,
452
+ centroids: centroidXYZ,
453
+ overlappingSegments: overlappingSegments
454
+ });
455
+ case 51:
456
+ case "end":
457
+ return _context.stop();
458
+ }
459
+ }, _callee);
460
+ }));
461
+ return _generateToolState.apply(this, arguments);
462
+ }
463
+ function findReferenceSourceImageId(multiframe, frameSegment, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap) {
464
+ var imageId = undefined;
465
+ if (!multiframe) {
466
+ return imageId;
467
+ }
468
+ var FrameOfReferenceUID = multiframe.FrameOfReferenceUID,
469
+ PerFrameFunctionalGroupsSequence = multiframe.PerFrameFunctionalGroupsSequence,
470
+ SourceImageSequence = multiframe.SourceImageSequence,
471
+ ReferencedSeriesSequence = multiframe.ReferencedSeriesSequence;
472
+ if (!PerFrameFunctionalGroupsSequence || PerFrameFunctionalGroupsSequence.length === 0) {
473
+ return imageId;
474
+ }
475
+ var PerFrameFunctionalGroup = PerFrameFunctionalGroupsSequence[frameSegment];
476
+ if (!PerFrameFunctionalGroup) {
477
+ return imageId;
478
+ }
479
+ var frameSourceImageSequence = undefined;
480
+ if (PerFrameFunctionalGroup.DerivationImageSequence) {
481
+ var DerivationImageSequence = PerFrameFunctionalGroup.DerivationImageSequence;
482
+ if (Array.isArray(DerivationImageSequence)) {
483
+ if (DerivationImageSequence.length !== 0) {
484
+ DerivationImageSequence = DerivationImageSequence[0];
485
+ } else {
486
+ DerivationImageSequence = undefined;
487
+ }
488
+ }
489
+ if (DerivationImageSequence) {
490
+ frameSourceImageSequence = DerivationImageSequence.SourceImageSequence;
491
+ if (Array.isArray(frameSourceImageSequence)) {
492
+ if (frameSourceImageSequence.length !== 0) {
493
+ frameSourceImageSequence = frameSourceImageSequence[0];
494
+ } else {
495
+ frameSourceImageSequence = undefined;
496
+ }
497
+ }
498
+ }
499
+ } else if (SourceImageSequence && SourceImageSequence.length !== 0) {
500
+ console.warn("DerivationImageSequence not present, using SourceImageSequence assuming SEG has the same geometry as the source image.");
501
+ frameSourceImageSequence = SourceImageSequence[frameSegment];
502
+ }
503
+ if (frameSourceImageSequence) {
504
+ imageId = getImageIdOfSourceImageBySourceImageSequence(frameSourceImageSequence, sopUIDImageIdIndexMap);
505
+ }
506
+ if (imageId === undefined && ReferencedSeriesSequence) {
507
+ var referencedSeriesSequence = Array.isArray(ReferencedSeriesSequence) ? ReferencedSeriesSequence[0] : ReferencedSeriesSequence;
508
+ var ReferencedSeriesInstanceUID = referencedSeriesSequence.SeriesInstanceUID;
509
+ imageId = getImageIdOfSourceImagebyGeometry(ReferencedSeriesInstanceUID, FrameOfReferenceUID, PerFrameFunctionalGroup, imageIds, metadataProvider, tolerance);
510
+ }
511
+ return imageId;
512
+ }
513
+
514
+ /**
515
+ * Checks if there is any overlapping segmentations.
516
+ * @returns {boolean} Returns a flag if segmentations overlapping
517
+ */
518
+
519
+ function checkSEGsOverlapping(pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance, TypedArrayConstructor, sopUIDImageIdIndexMap) {
520
+ var SharedFunctionalGroupsSequence = multiframe.SharedFunctionalGroupsSequence,
521
+ PerFrameFunctionalGroupsSequence = multiframe.PerFrameFunctionalGroupsSequence,
522
+ SegmentSequence = multiframe.SegmentSequence,
523
+ Rows = multiframe.Rows,
524
+ Columns = multiframe.Columns;
525
+ var numberOfSegs = SegmentSequence.length;
526
+ if (numberOfSegs < 2) {
527
+ return false;
528
+ }
529
+ var sharedImageOrientationPatient = SharedFunctionalGroupsSequence.PlaneOrientationSequence ? SharedFunctionalGroupsSequence.PlaneOrientationSequence.ImageOrientationPatient : undefined;
530
+ var sliceLength = Columns * Rows;
531
+ var groupsLen = PerFrameFunctionalGroupsSequence.length;
532
+
533
+ /** sort groupsLen to have all the segments for each frame in an array
534
+ * frame 2 : 1, 2
535
+ * frame 4 : 1, 3
536
+ * frame 5 : 4
537
+ */
538
+
539
+ var frameSegmentsMapping = new Map();
540
+ var _loop3 = function _loop3() {
541
+ var segmentIndex = getSegmentIndex(multiframe, frameSegment);
542
+ if (segmentIndex === undefined) {
543
+ console.warn("Could not retrieve the segment index for frame segment " + frameSegment + ", skipping this frame.");
544
+ return 0; // continue
545
+ }
546
+ var imageId = findReferenceSourceImageId(multiframe, frameSegment, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
547
+ if (!imageId) {
548
+ console.warn("Image not present in stack, can't import frame : " + frameSegment + ".");
549
+ return 0; // continue
550
+ }
551
+ var imageIdIndex = imageIds.findIndex(function (element) {
552
+ return element === imageId;
553
+ });
554
+ if (frameSegmentsMapping.has(imageIdIndex)) {
555
+ var segmentArray = frameSegmentsMapping.get(imageIdIndex);
556
+ if (!segmentArray.includes(frameSegment)) {
557
+ segmentArray.push(frameSegment);
558
+ frameSegmentsMapping.set(imageIdIndex, segmentArray);
559
+ }
560
+ } else {
561
+ frameSegmentsMapping.set(imageIdIndex, [frameSegment]);
562
+ }
563
+ },
564
+ _ret;
565
+ for (var frameSegment = 0; frameSegment < groupsLen; ++frameSegment) {
566
+ _ret = _loop3();
567
+ if (_ret === 0) continue;
568
+ }
569
+ var _iterator = _createForOfIteratorHelper(frameSegmentsMapping.entries()),
570
+ _step;
571
+ try {
572
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
573
+ var _step$value = _slicedToArray(_step.value, 2),
574
+ role = _step$value[1];
575
+ var temp2DArray = new TypedArrayConstructor(sliceLength).fill(0);
576
+ for (var i = 0; i < role.length; ++i) {
577
+ var _frameSegment = role[i];
578
+ var PerFrameFunctionalGroups = PerFrameFunctionalGroupsSequence[_frameSegment];
579
+ var ImageOrientationPatientI = sharedImageOrientationPatient || PerFrameFunctionalGroups.PlaneOrientationSequence.ImageOrientationPatient;
580
+ var view = readFromUnpackedChunks(pixelData, _frameSegment * sliceLength, sliceLength);
581
+ var pixelDataI2D = ndarray(view, [Rows, Columns]);
582
+ var alignedPixelDataI = alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
583
+ if (!alignedPixelDataI) {
584
+ console.warn("Individual SEG frames are out of plane with respect to the first SEG frame, this is not yet supported, skipping this frame.");
585
+ continue;
586
+ }
587
+ var data = alignedPixelDataI.data;
588
+ for (var j = 0, len = data.length; j < len; ++j) {
589
+ if (data[j] !== 0) {
590
+ temp2DArray[j]++;
591
+ if (temp2DArray[j] > 1) {
592
+ return true;
593
+ }
594
+ }
595
+ }
596
+ }
597
+ }
598
+ } catch (err) {
599
+ _iterator.e(err);
600
+ } finally {
601
+ _iterator.f();
602
+ }
603
+ return false;
604
+ }
605
+ function insertOverlappingPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray, labelmapBufferArray, pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance, TypedArrayConstructor, segmentsPixelIndices, sopUIDImageIdIndexMap) {
606
+ var SharedFunctionalGroupsSequence = multiframe.SharedFunctionalGroupsSequence,
607
+ PerFrameFunctionalGroupsSequence = multiframe.PerFrameFunctionalGroupsSequence,
608
+ Rows = multiframe.Rows,
609
+ Columns = multiframe.Columns;
610
+ var sharedImageOrientationPatient = SharedFunctionalGroupsSequence.PlaneOrientationSequence ? SharedFunctionalGroupsSequence.PlaneOrientationSequence.ImageOrientationPatient : undefined;
611
+ var sliceLength = Columns * Rows;
612
+ var arrayBufferLength = sliceLength * imageIds.length * TypedArrayConstructor.BYTES_PER_ELEMENT;
613
+ // indicate the number of labelMaps
614
+ var M = 1;
615
+
616
+ // indicate the current labelMap array index;
617
+ var m = 0;
618
+
619
+ // temp array for checking overlaps
620
+ var tempBuffer = labelmapBufferArray[m].slice(0);
621
+
622
+ // temp list for checking overlaps
623
+ var tempSegmentsOnFrame = structuredClone(segmentsOnFrameArray[m]);
624
+
625
+ /** split overlapping SEGs algorithm for each segment:
626
+ * A) copy the labelmapBuffer in the array with index 0
627
+ * B) add the segment pixel per pixel on the copied buffer from (A)
628
+ * C) if no overlap, copy the results back on the orignal array from (A)
629
+ * D) if overlap, repeat increasing the index m up to M (if out of memory, add new buffer in the array and M++);
630
+ */
631
+
632
+ var numberOfSegs = multiframe.SegmentSequence.length;
633
+ for (var segmentIndexToProcess = 1; segmentIndexToProcess <= numberOfSegs; ++segmentIndexToProcess) {
634
+ var _loop4 = function _loop4(_i2) {
635
+ var PerFrameFunctionalGroups = PerFrameFunctionalGroupsSequence[_i2];
636
+ var segmentIndex = getSegmentIndex(multiframe, _i2);
637
+ if (segmentIndex === undefined) {
638
+ throw new Error("Could not retrieve the segment index. Aborting segmentation loading.");
639
+ }
640
+ if (segmentIndex !== segmentIndexToProcess) {
641
+ i = _i2;
642
+ return 0; // continue
643
+ }
644
+ var ImageOrientationPatientI = sharedImageOrientationPatient || PerFrameFunctionalGroups.PlaneOrientationSequence.ImageOrientationPatient;
645
+
646
+ // Since we moved to the chunks approach, we need to read the data
647
+ // and handle scenarios where the portion of data is in one chunk
648
+ // and the other portion is in another chunk
649
+ var view = readFromUnpackedChunks(pixelData, _i2 * sliceLength, sliceLength);
650
+ var pixelDataI2D = ndarray(view, [Rows, Columns]);
651
+ var alignedPixelDataI = alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
652
+ if (!alignedPixelDataI) {
653
+ throw new Error("Individual SEG frames are out of plane with respect to the first SEG frame. " + "This is not yet supported. Aborting segmentation loading.");
654
+ }
655
+ var imageId = findReferenceSourceImageId(multiframe, _i2, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
656
+ if (!imageId) {
657
+ console.warn("Image not present in stack, can't import frame : " + _i2 + ".");
658
+ i = _i2;
659
+ return 0; // continue
660
+ }
661
+ var sourceImageMetadata = metadataProvider.get("instance", imageId);
662
+ if (Rows !== sourceImageMetadata.Rows || Columns !== sourceImageMetadata.Columns) {
663
+ throw new Error("Individual SEG frames have different geometry dimensions (Rows and Columns) " + "respect to the source image reference frame. This is not yet supported. " + "Aborting segmentation loading. ");
664
+ }
665
+ var imageIdIndex = imageIds.findIndex(function (element) {
666
+ return element === imageId;
667
+ });
668
+ var byteOffset = sliceLength * imageIdIndex * TypedArrayConstructor.BYTES_PER_ELEMENT;
669
+ var labelmap2DView = new TypedArrayConstructor(tempBuffer, byteOffset, sliceLength);
670
+ var data = alignedPixelDataI.data;
671
+ var segmentOnFrame = false;
672
+ for (var j = 0, len = alignedPixelDataI.data.length; j < len; ++j) {
673
+ if (data[j]) {
674
+ if (labelmap2DView[j] !== 0) {
675
+ m++;
676
+ if (m >= M) {
677
+ labelmapBufferArray[m] = new ArrayBuffer(arrayBufferLength);
678
+ segmentsOnFrameArray[m] = [];
679
+ M++;
680
+ }
681
+ tempBuffer = labelmapBufferArray[m].slice(0);
682
+ tempSegmentsOnFrame = structuredClone(segmentsOnFrameArray[m]);
683
+ _i2 = 0;
684
+ break;
685
+ } else {
686
+ labelmap2DView[j] = segmentIndex;
687
+ segmentOnFrame = true;
688
+ }
689
+ }
690
+ }
691
+ if (segmentOnFrame) {
692
+ if (!tempSegmentsOnFrame[imageIdIndex]) {
693
+ tempSegmentsOnFrame[imageIdIndex] = [];
694
+ }
695
+ tempSegmentsOnFrame[imageIdIndex].push(segmentIndex);
696
+ if (!segmentsOnFrame[imageIdIndex]) {
697
+ segmentsOnFrame[imageIdIndex] = [];
698
+ }
699
+ segmentsOnFrame[imageIdIndex].push(segmentIndex);
700
+ }
701
+ i = _i2;
702
+ },
703
+ _ret2;
704
+ for (var i = 0, groupsLen = PerFrameFunctionalGroupsSequence.length; i < groupsLen; ++i) {
705
+ _ret2 = _loop4(i);
706
+ if (_ret2 === 0) continue;
707
+ }
708
+ labelmapBufferArray[m] = tempBuffer.slice(0);
709
+ segmentsOnFrameArray[m] = structuredClone(tempSegmentsOnFrame);
710
+
711
+ // reset temp variables/buffers for new segment
712
+ m = 0;
713
+ tempBuffer = labelmapBufferArray[m].slice(0);
714
+ tempSegmentsOnFrame = structuredClone(segmentsOnFrameArray[m]);
715
+ }
716
+ }
717
+ var getSegmentIndex = function getSegmentIndex(multiframe, frame) {
718
+ var PerFrameFunctionalGroupsSequence = multiframe.PerFrameFunctionalGroupsSequence,
719
+ SharedFunctionalGroupsSequence = multiframe.SharedFunctionalGroupsSequence;
720
+ var PerFrameFunctionalGroups = PerFrameFunctionalGroupsSequence[frame];
721
+ return PerFrameFunctionalGroups && PerFrameFunctionalGroups.SegmentIdentificationSequence ? PerFrameFunctionalGroups.SegmentIdentificationSequence.ReferencedSegmentNumber : SharedFunctionalGroupsSequence.SegmentIdentificationSequence ? SharedFunctionalGroupsSequence.SegmentIdentificationSequence.ReferencedSegmentNumber : undefined;
722
+ };
723
+ function insertPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray, labelmapBufferArray, pixelData, multiframe, imageIds, validOrientations, metadataProvider, tolerance, TypedArrayConstructor, segmentsPixelIndices, sopUIDImageIdIndexMap, imageIdMaps, eventTarget, triggerEvent) {
724
+ var SharedFunctionalGroupsSequence = multiframe.SharedFunctionalGroupsSequence,
725
+ PerFrameFunctionalGroupsSequence = multiframe.PerFrameFunctionalGroupsSequence,
726
+ Rows = multiframe.Rows,
727
+ Columns = multiframe.Columns;
728
+ var sharedImageOrientationPatient = SharedFunctionalGroupsSequence.PlaneOrientationSequence ? SharedFunctionalGroupsSequence.PlaneOrientationSequence.ImageOrientationPatient : undefined;
729
+ var sliceLength = Columns * Rows;
730
+ var i = 0;
731
+ var groupsLen = PerFrameFunctionalGroupsSequence.length;
732
+ var chunkSize = Math.ceil(groupsLen / 10); // 10% of total length
733
+
734
+ var shouldTriggerEvent = triggerEvent && eventTarget;
735
+ var overlapping = false;
736
+ // Below, we chunk the processing of the frames to avoid blocking the main thread
737
+ // if the segmentation is large. We also use a promise to allow the caller to
738
+ // wait for the processing to finish.
739
+ return new Promise(function (resolve) {
740
+ function processInChunks() {
741
+ // process one chunk
742
+ for (var end = Math.min(i + chunkSize, groupsLen); i < end; ++i) {
743
+ var PerFrameFunctionalGroups = PerFrameFunctionalGroupsSequence[i];
744
+ var ImageOrientationPatientI = sharedImageOrientationPatient || PerFrameFunctionalGroups.PlaneOrientationSequence.ImageOrientationPatient;
745
+ var view = readFromUnpackedChunks(pixelData, i * sliceLength, sliceLength);
746
+ var pixelDataI2D = ndarray(view, [Rows, Columns]);
747
+ var alignedPixelDataI = alignPixelDataWithSourceData(pixelDataI2D, ImageOrientationPatientI, validOrientations, tolerance);
748
+ if (!alignedPixelDataI) {
749
+ throw new Error("Individual SEG frames are out of plane with respect to the first SEG frame. " + "This is not yet supported. Aborting segmentation loading.");
750
+ }
751
+ var segmentIndex = getSegmentIndex(multiframe, i);
752
+ if (segmentIndex === undefined) {
753
+ throw new Error("Could not retrieve the segment index. Aborting segmentation loading.");
754
+ }
755
+ if (!segmentsPixelIndices.has(segmentIndex)) {
756
+ segmentsPixelIndices.set(segmentIndex, {});
757
+ }
758
+ var imageId = findReferenceSourceImageId(multiframe, i, imageIds, metadataProvider, tolerance, sopUIDImageIdIndexMap);
759
+ if (!imageId) {
760
+ console.warn("Image not present in stack, can't import frame : " + i + ".");
761
+ continue;
762
+ }
763
+ var sourceImageMetadata = imageIdMaps.metadata[imageId];
764
+ if (Rows !== sourceImageMetadata.Rows || Columns !== sourceImageMetadata.Columns) {
765
+ throw new Error("Individual SEG frames have different geometry dimensions (Rows and Columns) " + "respect to the source image reference frame. This is not yet supported. " + "Aborting segmentation loading. ");
766
+ }
767
+ var imageIdIndex = imageIdMaps.indices[imageId];
768
+ var byteOffset = sliceLength * imageIdIndex * TypedArrayConstructor.BYTES_PER_ELEMENT;
769
+ var labelmap2DView = new TypedArrayConstructor(labelmapBufferArray[0], byteOffset, sliceLength);
770
+ var data = alignedPixelDataI.data;
771
+ var indexCache = [];
772
+ for (var j = 0, len = alignedPixelDataI.data.length; j < len; ++j) {
773
+ if (data[j]) {
774
+ for (var x = j; x < len; ++x) {
775
+ if (data[x]) {
776
+ if (!overlapping && labelmap2DView[x] !== 0) {
777
+ overlapping = true;
778
+ }
779
+ labelmap2DView[x] = segmentIndex;
780
+ indexCache.push(x);
781
+ }
782
+ }
783
+ if (!segmentsOnFrame[imageIdIndex]) {
784
+ segmentsOnFrame[imageIdIndex] = [];
785
+ }
786
+ segmentsOnFrame[imageIdIndex].push(segmentIndex);
787
+ break;
788
+ }
789
+ }
790
+ var segmentIndexObject = segmentsPixelIndices.get(segmentIndex);
791
+ segmentIndexObject[imageIdIndex] = indexCache;
792
+ segmentsPixelIndices.set(segmentIndex, segmentIndexObject);
793
+ }
794
+
795
+ // trigger an event after each chunk
796
+ if (shouldTriggerEvent) {
797
+ var percentComplete = Math.round(i / groupsLen * 100);
798
+ triggerEvent(eventTarget, Events.SEGMENTATION_LOAD_PROGRESS, {
799
+ percentComplete: percentComplete
800
+ });
801
+ }
802
+
803
+ // schedule next chunk
804
+ if (i < groupsLen) {
805
+ setTimeout(processInChunks, 0);
806
+ } else {
807
+ // resolve the Promise when all chunks have been processed
808
+ resolve(overlapping);
809
+ }
810
+ }
811
+ processInChunks();
812
+ });
813
+ }
814
+
815
+ /**
816
+ * unpackPixelData - Unpacks bit packed pixelData if the Segmentation is BINARY.
817
+ *
818
+ * @param {Object} multiframe The multiframe dataset.
819
+ * @param {Object} options Options for the unpacking.
820
+ * @return {Uint8Array} The unpacked pixelData.
821
+ */
822
+ function unpackPixelData(multiframe, options) {
823
+ var segType = multiframe.SegmentationType;
824
+ var data;
825
+ if (Array.isArray(multiframe.PixelData)) {
826
+ data = multiframe.PixelData[0];
827
+ } else {
828
+ data = multiframe.PixelData;
829
+ }
830
+ if (data === undefined) {
831
+ log.error("This segmentation pixelData is undefined.");
832
+ }
833
+ if (segType === "BINARY") {
834
+ // For extreme big data, we can't unpack the data at once and we need to
835
+ // chunk it and unpack each chunk separately.
836
+ // MAX 2GB is the limit right now to allocate a buffer
837
+ return getUnpackedChunks(data, options.maxBytesPerChunk);
838
+ }
839
+ var pixelData = new Uint8Array(data);
840
+ var max = multiframe.MaximumFractionalValue;
841
+ var onlyMaxAndZero = pixelData.find(function (element) {
842
+ return element !== 0 && element !== max;
843
+ }) === undefined;
844
+ if (!onlyMaxAndZero) {
845
+ // This is a fractional segmentation, which is not currently supported.
846
+ return;
847
+ }
848
+ log.warn("This segmentation object is actually binary... processing as such.");
849
+ return pixelData;
850
+ }
851
+ function getUnpackedChunks(data, maxBytesPerChunk) {
852
+ var bitArray = new Uint8Array(data);
853
+ var chunks = [];
854
+ var maxBitsPerChunk = maxBytesPerChunk * 8;
855
+ var numberOfChunks = Math.ceil(bitArray.length * 8 / maxBitsPerChunk);
856
+ for (var i = 0; i < numberOfChunks; i++) {
857
+ var startBit = i * maxBitsPerChunk;
858
+ var endBit = Math.min(startBit + maxBitsPerChunk, bitArray.length * 8);
859
+ var startByte = Math.floor(startBit / 8);
860
+ var endByte = Math.ceil(endBit / 8);
861
+ var chunk = bitArray.slice(startByte, endByte);
862
+ var unpackedChunk = BitArray.unpack(chunk);
863
+ chunks.push(unpackedChunk);
864
+ }
865
+ return chunks;
866
+ }
867
+
868
+ /**
869
+ * getImageIdOfSourceImageBySourceImageSequence - Returns the Cornerstone imageId of the source image.
870
+ *
871
+ * @param {Object} SourceImageSequence Sequence describing the source image.
872
+ * @param {String[]} imageIds A list of imageIds.
873
+ * @param {Object} sopUIDImageIdIndexMap A map of SOPInstanceUIDs to imageIds.
874
+ * @return {String} The corresponding imageId.
875
+ */
876
+ function getImageIdOfSourceImageBySourceImageSequence(SourceImageSequence, sopUIDImageIdIndexMap) {
877
+ var ReferencedSOPInstanceUID = SourceImageSequence.ReferencedSOPInstanceUID,
878
+ ReferencedFrameNumber = SourceImageSequence.ReferencedFrameNumber;
879
+ return ReferencedFrameNumber ? getImageIdOfReferencedFrame(ReferencedSOPInstanceUID, ReferencedFrameNumber, sopUIDImageIdIndexMap) : sopUIDImageIdIndexMap[ReferencedSOPInstanceUID];
880
+ }
881
+
882
+ /**
883
+ * getImageIdOfSourceImagebyGeometry - Returns the Cornerstone imageId of the source image.
884
+ *
885
+ * @param {String} ReferencedSeriesInstanceUID Referenced series of the source image.
886
+ * @param {String} FrameOfReferenceUID Frame of reference.
887
+ * @param {Object} PerFrameFunctionalGroup Sequence describing segmentation reference attributes per frame.
888
+ * @param {String[]} imageIds A list of imageIds.
889
+ * @param {Object} sopUIDImageIdIndexMap A map of SOPInstanceUIDs to imageIds.
890
+ * @param {Float} tolerance The tolerance parameter
891
+ *
892
+ * @return {String} The corresponding imageId.
893
+ */
894
+ function getImageIdOfSourceImagebyGeometry(ReferencedSeriesInstanceUID, FrameOfReferenceUID, PerFrameFunctionalGroup, imageIds, metadataProvider, tolerance) {
895
+ if (ReferencedSeriesInstanceUID === undefined || PerFrameFunctionalGroup.PlanePositionSequence === undefined || PerFrameFunctionalGroup.PlanePositionSequence[0] === undefined || PerFrameFunctionalGroup.PlanePositionSequence[0].ImagePositionPatient === undefined) {
896
+ return undefined;
897
+ }
898
+ for (var imageIdsIndexc = 0; imageIdsIndexc < imageIds.length; ++imageIdsIndexc) {
899
+ var sourceImageMetadata = metadataProvider.get("instance", imageIds[imageIdsIndexc]);
900
+ if (sourceImageMetadata === undefined || sourceImageMetadata.ImagePositionPatient === undefined || sourceImageMetadata.FrameOfReferenceUID !== FrameOfReferenceUID || sourceImageMetadata.SeriesInstanceUID !== ReferencedSeriesInstanceUID) {
901
+ continue;
902
+ }
903
+ if (compareArrays(PerFrameFunctionalGroup.PlanePositionSequence[0].ImagePositionPatient, sourceImageMetadata.ImagePositionPatient, tolerance)) {
904
+ return imageIds[imageIdsIndexc];
905
+ }
906
+ }
907
+ }
908
+
909
+ /**
910
+ * getImageIdOfReferencedFrame - Returns the imageId corresponding to the
911
+ * specified sopInstanceUid and frameNumber for multi-frame images.
912
+ *
913
+ * @param {String} sopInstanceUid The sopInstanceUid of the desired image.
914
+ * @param {Number} frameNumber The frame number.
915
+ * @param {String} imageIds The list of imageIds.
916
+ * @param {Object} sopUIDImageIdIndexMap A map of SOPInstanceUIDs to imageIds.
917
+ * @return {String} The imageId that corresponds to the sopInstanceUid.
918
+ */
919
+ function getImageIdOfReferencedFrame(sopInstanceUid, frameNumber, sopUIDImageIdIndexMap) {
920
+ var imageId = sopUIDImageIdIndexMap[sopInstanceUid];
921
+ if (!imageId) {
922
+ return;
923
+ }
924
+ var imageIdFrameNumber = Number(imageId.split("frame=")[1]);
925
+ return imageIdFrameNumber === frameNumber - 1 ? imageId : undefined;
926
+ }
927
+
928
+ /**
929
+ * getValidOrientations - returns an array of valid orientations.
930
+ *
931
+ * @param {Number[6]} iop The row (0..2) an column (3..5) direction cosines.
932
+ * @return {Number[8][6]} An array of valid orientations.
933
+ */
934
+ function getValidOrientations(iop) {
935
+ var orientations = [];
936
+
937
+ // [0, 1, 2]: 0, 0hf, 0vf
938
+ // [3, 4, 5]: 90, 90hf, 90vf
939
+ // [6, 7]: 180, 270
940
+
941
+ orientations[0] = iop;
942
+ orientations[1] = flipIOP.h(iop);
943
+ orientations[2] = flipIOP.v(iop);
944
+ var iop90 = rotateDirectionCosinesInPlane(iop, Math.PI / 2);
945
+ orientations[3] = iop90;
946
+ orientations[4] = flipIOP.h(iop90);
947
+ orientations[5] = flipIOP.v(iop90);
948
+ orientations[6] = rotateDirectionCosinesInPlane(iop, Math.PI);
949
+ orientations[7] = rotateDirectionCosinesInPlane(iop, 1.5 * Math.PI);
950
+ return orientations;
951
+ }
952
+
953
+ /**
954
+ * alignPixelDataWithSourceData -
955
+ *
956
+ * @param {Ndarray} pixelData2D - The data to align.
957
+ * @param {Number[6]} iop - The orientation of the image slice.
958
+ * @param {Number[8][6]} orientations - An array of valid imageOrientationPatient values.
959
+ * @param {Number} tolerance.
960
+ * @return {Ndarray} The aligned pixelData.
961
+ */
962
+ function alignPixelDataWithSourceData(pixelData2D, iop, orientations, tolerance) {
963
+ if (compareArrays(iop, orientations[0], tolerance)) {
964
+ return pixelData2D;
965
+ } else if (compareArrays(iop, orientations[1], tolerance)) {
966
+ // Flipped vertically.
967
+
968
+ // Undo Flip
969
+ return flipMatrix2D.v(pixelData2D);
970
+ } else if (compareArrays(iop, orientations[2], tolerance)) {
971
+ // Flipped horizontally.
972
+
973
+ // Unfo flip
974
+ return flipMatrix2D.h(pixelData2D);
975
+ } else if (compareArrays(iop, orientations[3], tolerance)) {
976
+ //Rotated 90 degrees
977
+
978
+ // Rotate back
979
+ return rotateMatrix902D(pixelData2D);
980
+ } else if (compareArrays(iop, orientations[4], tolerance)) {
981
+ //Rotated 90 degrees and fliped horizontally.
982
+
983
+ // Undo flip and rotate back.
984
+ return rotateMatrix902D(flipMatrix2D.h(pixelData2D));
985
+ } else if (compareArrays(iop, orientations[5], tolerance)) {
986
+ // Rotated 90 degrees and fliped vertically
987
+
988
+ // Unfo flip and rotate back.
989
+ return rotateMatrix902D(flipMatrix2D.v(pixelData2D));
990
+ } else if (compareArrays(iop, orientations[6], tolerance)) {
991
+ // Rotated 180 degrees. // TODO -> Do this more effeciently, there is a 1:1 mapping like 90 degree rotation.
992
+
993
+ return rotateMatrix902D(rotateMatrix902D(pixelData2D));
994
+ } else if (compareArrays(iop, orientations[7], tolerance)) {
995
+ // Rotated 270 degrees
996
+
997
+ // Rotate back.
998
+ return rotateMatrix902D(rotateMatrix902D(rotateMatrix902D(pixelData2D)));
999
+ }
1000
+ }
1001
+ function getSegmentMetadata(multiframe, seriesInstanceUid) {
1002
+ var segmentSequence = multiframe.SegmentSequence;
1003
+ var data = [];
1004
+ if (Array.isArray(segmentSequence)) {
1005
+ data = [undefined].concat(_toConsumableArray(segmentSequence));
1006
+ } else {
1007
+ // Only one segment, will be stored as an object.
1008
+ data = [undefined, segmentSequence];
1009
+ }
1010
+ return {
1011
+ seriesInstanceUid: seriesInstanceUid,
1012
+ data: data
1013
+ };
1014
+ }
1015
+
1016
+ /**
1017
+ * Reads a range of bytes from an array of ArrayBuffer chunks and
1018
+ * aggregate them into a new Uint8Array.
1019
+ *
1020
+ * @param {ArrayBuffer[]} chunks - An array of ArrayBuffer chunks.
1021
+ * @param {number} offset - The offset of the first byte to read.
1022
+ * @param {number} length - The number of bytes to read.
1023
+ * @returns {Uint8Array} A new Uint8Array containing the requested bytes.
1024
+ */
1025
+ function readFromUnpackedChunks(chunks, offset, length) {
1026
+ var mapping = getUnpackedOffsetAndLength(chunks, offset, length);
1027
+
1028
+ // If all the data is in one chunk, we can just slice that chunk
1029
+ if (mapping.start.chunkIndex === mapping.end.chunkIndex) {
1030
+ return new Uint8Array(chunks[mapping.start.chunkIndex].buffer, mapping.start.offset, length);
1031
+ } else {
1032
+ // If the data spans multiple chunks, we need to create a new Uint8Array and copy the data from each chunk
1033
+ var result = new Uint8Array(length);
1034
+ var resultOffset = 0;
1035
+ for (var i = mapping.start.chunkIndex; i <= mapping.end.chunkIndex; i++) {
1036
+ var start = i === mapping.start.chunkIndex ? mapping.start.offset : 0;
1037
+ var end = i === mapping.end.chunkIndex ? mapping.end.offset : chunks[i].length;
1038
+ result.set(new Uint8Array(chunks[i].buffer, start, end - start), resultOffset);
1039
+ resultOffset += end - start;
1040
+ }
1041
+ return result;
1042
+ }
1043
+ }
1044
+ function getUnpackedOffsetAndLength(chunks, offset, length) {
1045
+ var totalBytes = chunks.reduce(function (total, chunk) {
1046
+ return total + chunk.length;
1047
+ }, 0);
1048
+ if (offset < 0 || offset + length > totalBytes) {
1049
+ throw new Error("Offset and length out of bounds");
1050
+ }
1051
+ var startChunkIndex = 0;
1052
+ var startOffsetInChunk = offset;
1053
+ while (startOffsetInChunk >= chunks[startChunkIndex].length) {
1054
+ startOffsetInChunk -= chunks[startChunkIndex].length;
1055
+ startChunkIndex++;
1056
+ }
1057
+ var endChunkIndex = startChunkIndex;
1058
+ var endOffsetInChunk = startOffsetInChunk + length;
1059
+ while (endOffsetInChunk > chunks[endChunkIndex].length) {
1060
+ endOffsetInChunk -= chunks[endChunkIndex].length;
1061
+ endChunkIndex++;
1062
+ }
1063
+ return {
1064
+ start: {
1065
+ chunkIndex: startChunkIndex,
1066
+ offset: startOffsetInChunk
1067
+ },
1068
+ end: {
1069
+ chunkIndex: endChunkIndex,
1070
+ offset: endOffsetInChunk
1071
+ }
1072
+ };
1073
+ }
1074
+ function calculateCentroid(imageIdIndexBufferIndex, multiframe, metadataProvider, imageIds) {
1075
+ var xAcc = 0;
1076
+ var yAcc = 0;
1077
+ var zAcc = 0;
1078
+ var worldXAcc = 0;
1079
+ var worldYAcc = 0;
1080
+ var worldZAcc = 0;
1081
+ var count = 0;
1082
+ for (var _i3 = 0, _Object$entries = Object.entries(imageIdIndexBufferIndex); _i3 < _Object$entries.length; _i3++) {
1083
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i3], 2),
1084
+ imageIdIndex = _Object$entries$_i[0],
1085
+ bufferIndices = _Object$entries$_i[1];
1086
+ var z = Number(imageIdIndex);
1087
+ if (!bufferIndices || bufferIndices.length === 0) {
1088
+ continue;
1089
+ }
1090
+
1091
+ // Get metadata for this slice
1092
+ var imageId = imageIds[z];
1093
+ var imagePlaneModule = metadataProvider.get("imagePlaneModule", imageId);
1094
+ if (!imagePlaneModule) {
1095
+ console.debug("Missing imagePlaneModule metadata for centroid calculation");
1096
+ continue;
1097
+ }
1098
+ var imagePositionPatient = imagePlaneModule.imagePositionPatient,
1099
+ rowCosines = imagePlaneModule.rowCosines,
1100
+ columnCosines = imagePlaneModule.columnCosines,
1101
+ rowPixelSpacing = imagePlaneModule.rowPixelSpacing,
1102
+ columnPixelSpacing = imagePlaneModule.columnPixelSpacing;
1103
+ var _iterator2 = _createForOfIteratorHelper(bufferIndices),
1104
+ _step2;
1105
+ try {
1106
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1107
+ var bufferIndex = _step2.value;
1108
+ var y = Math.floor(bufferIndex / multiframe.Rows);
1109
+ var x = bufferIndex % multiframe.Rows;
1110
+
1111
+ // Image coordinates
1112
+ xAcc += x;
1113
+ yAcc += y;
1114
+ zAcc += z;
1115
+
1116
+ // Calculate world coordinates
1117
+ // P(world) = P(image) * IOP * spacing + IPP
1118
+ var worldX = imagePositionPatient[0] + x * rowCosines[0] * columnPixelSpacing + y * columnCosines[0] * rowPixelSpacing;
1119
+ var worldY = imagePositionPatient[1] + x * rowCosines[1] * columnPixelSpacing + y * columnCosines[1] * rowPixelSpacing;
1120
+ var worldZ = imagePositionPatient[2] + x * rowCosines[2] * columnPixelSpacing + y * columnCosines[2] * rowPixelSpacing;
1121
+ worldXAcc += worldX;
1122
+ worldYAcc += worldY;
1123
+ worldZAcc += worldZ;
1124
+ count++;
1125
+ }
1126
+ } catch (err) {
1127
+ _iterator2.e(err);
1128
+ } finally {
1129
+ _iterator2.f();
1130
+ }
1131
+ }
1132
+ return {
1133
+ image: {
1134
+ x: Math.floor(xAcc / count),
1135
+ y: Math.floor(yAcc / count),
1136
+ z: Math.floor(zAcc / count)
1137
+ },
1138
+ world: {
1139
+ x: worldXAcc / count,
1140
+ y: worldYAcc / count,
1141
+ z: worldZAcc / count
1142
+ },
1143
+ count: count
1144
+ };
1145
+ }
1146
+ var Segmentation = {
1147
+ generateSegmentation: generateSegmentation,
1148
+ generateToolState: generateToolState,
1149
+ fillSegmentation: fillSegmentation
1150
+ };
1151
+
1152
+ export { Segmentation as default, fillSegmentation, generateSegmentation, generateToolState };