@cornerstonejs/adapters 2.0.0-beta.2 → 2.0.0-beta.21

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