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

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.
@@ -1,7 +1,6 @@
1
- import { data, utilities, derivations, normalizers, log } from 'dcmjs';
1
+ import dcmjs, { data, utilities, derivations, normalizers, log } from 'dcmjs';
2
2
  import { Buffer } from 'buffer';
3
3
  import ndarray from 'ndarray';
4
- import cloneDeep from 'lodash.clonedeep';
5
4
  import { vec3 } from 'gl-matrix';
6
5
 
7
6
  function _iterableToArrayLimit(arr, i) {
@@ -583,7 +582,7 @@ var StructuredReport$1 = derivations.StructuredReport;
583
582
  var Normalizer$4 = normalizers.Normalizer;
584
583
  var TID1500MeasurementReport$1 = TID1500$1.TID1500MeasurementReport,
585
584
  TID1501MeasurementGroup$1 = TID1500$1.TID1501MeasurementGroup;
586
- var DicomMetaDictionary$3 = data.DicomMetaDictionary;
585
+ var DicomMetaDictionary$4 = data.DicomMetaDictionary;
587
586
  var FINDING$2 = {
588
587
  CodingSchemeDesignator: "DCM",
589
588
  CodeValue: "121071"
@@ -754,7 +753,7 @@ var MeasurementReport$1 = /*#__PURE__*/function () {
754
753
  vr: "UI"
755
754
  },
756
755
  ImplementationClassUID: {
757
- Value: [DicomMetaDictionary$3.uid()],
756
+ Value: [DicomMetaDictionary$4.uid()],
758
757
  // TODO: could be git hash or other valid id
759
758
  vr: "UI"
760
759
  },
@@ -1827,7 +1826,7 @@ var _utilities$orientatio$1 = utilities.orientation,
1827
1826
  var datasetToBlob = utilities.datasetToBlob,
1828
1827
  BitArray$2 = utilities.BitArray,
1829
1828
  DicomMessage$1 = utilities.DicomMessage,
1830
- DicomMetaDictionary$2 = utilities.DicomMetaDictionary;
1829
+ DicomMetaDictionary$3 = utilities.DicomMetaDictionary;
1831
1830
  var Normalizer$3 = normalizers.Normalizer;
1832
1831
  var SegmentationDerivation$2 = derivations.Segmentation;
1833
1832
  var Segmentation$5 = {
@@ -1957,16 +1956,16 @@ function _createSegFromImages$1(images, isMultiframe, options) {
1957
1956
  var image = images[0];
1958
1957
  var arrayBuffer = image.data.byteArray.buffer;
1959
1958
  var dicomData = DicomMessage$1.readFile(arrayBuffer);
1960
- var dataset = DicomMetaDictionary$2.naturalizeDataset(dicomData.dict);
1961
- dataset._meta = DicomMetaDictionary$2.namifyDataset(dicomData.meta);
1959
+ var dataset = DicomMetaDictionary$3.naturalizeDataset(dicomData.dict);
1960
+ dataset._meta = DicomMetaDictionary$3.namifyDataset(dicomData.meta);
1962
1961
  datasets.push(dataset);
1963
1962
  } else {
1964
1963
  for (var i = 0; i < images.length; i++) {
1965
1964
  var _image = images[i];
1966
1965
  var _arrayBuffer = _image.data.byteArray.buffer;
1967
1966
  var _dicomData = DicomMessage$1.readFile(_arrayBuffer);
1968
- var _dataset = DicomMetaDictionary$2.naturalizeDataset(_dicomData.dict);
1969
- _dataset._meta = DicomMetaDictionary$2.namifyDataset(_dicomData.meta);
1967
+ var _dataset = DicomMetaDictionary$3.naturalizeDataset(_dicomData.dict);
1968
+ _dataset._meta = DicomMetaDictionary$3.namifyDataset(_dicomData.meta);
1970
1969
  datasets.push(_dataset);
1971
1970
  }
1972
1971
  }
@@ -1986,8 +1985,8 @@ function _createSegFromImages$1(images, isMultiframe, options) {
1986
1985
  */
1987
1986
  function generateToolState$3(imageIds, arrayBuffer, metadataProvider) {
1988
1987
  var dicomData = DicomMessage$1.readFile(arrayBuffer);
1989
- var dataset = DicomMetaDictionary$2.naturalizeDataset(dicomData.dict);
1990
- dataset._meta = DicomMetaDictionary$2.namifyDataset(dicomData.meta);
1988
+ var dataset = DicomMetaDictionary$3.naturalizeDataset(dicomData.dict);
1989
+ dataset._meta = DicomMetaDictionary$3.namifyDataset(dicomData.meta);
1991
1990
  var multiframe = Normalizer$3.normalizeToDataset([dataset]);
1992
1991
  var imagePlaneModule = metadataProvider.get("imagePlaneModule", imageIds[0]);
1993
1992
  if (!imagePlaneModule) {
@@ -2267,7 +2266,7 @@ var _utilities$orientatio = utilities.orientation,
2267
2266
  nearlyEqual = _utilities$orientatio.nearlyEqual;
2268
2267
  var BitArray$1 = data.BitArray,
2269
2268
  DicomMessage = data.DicomMessage,
2270
- DicomMetaDictionary$1 = data.DicomMetaDictionary;
2269
+ DicomMetaDictionary$2 = data.DicomMetaDictionary;
2271
2270
  var Normalizer$2 = normalizers.Normalizer;
2272
2271
  var SegmentationDerivation$1 = derivations.Segmentation;
2273
2272
  var _utilities$compressio = utilities.compression,
@@ -2417,16 +2416,16 @@ function _createSegFromImages(images, isMultiframe, options) {
2417
2416
  var image = images[0];
2418
2417
  var arrayBuffer = image.data.byteArray.buffer;
2419
2418
  var dicomData = DicomMessage.readFile(arrayBuffer);
2420
- var dataset = DicomMetaDictionary$1.naturalizeDataset(dicomData.dict);
2421
- dataset._meta = DicomMetaDictionary$1.namifyDataset(dicomData.meta);
2419
+ var dataset = DicomMetaDictionary$2.naturalizeDataset(dicomData.dict);
2420
+ dataset._meta = DicomMetaDictionary$2.namifyDataset(dicomData.meta);
2422
2421
  datasets.push(dataset);
2423
2422
  } else {
2424
2423
  for (var i = 0; i < images.length; i++) {
2425
2424
  var _image = images[i];
2426
2425
  var _arrayBuffer = _image.data.byteArray.buffer;
2427
2426
  var _dicomData = DicomMessage.readFile(_arrayBuffer);
2428
- var _dataset = DicomMetaDictionary$1.naturalizeDataset(_dicomData.dict);
2429
- _dataset._meta = DicomMetaDictionary$1.namifyDataset(_dicomData.meta);
2427
+ var _dataset = DicomMetaDictionary$2.naturalizeDataset(_dicomData.dict);
2428
+ _dataset._meta = DicomMetaDictionary$2.namifyDataset(_dicomData.meta);
2430
2429
  datasets.push(_dataset);
2431
2430
  }
2432
2431
  }
@@ -2610,8 +2609,8 @@ function _generateToolState() {
2610
2609
  case 0:
2611
2610
  _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;
2612
2611
  dicomData = DicomMessage.readFile(arrayBuffer);
2613
- dataset = DicomMetaDictionary$1.naturalizeDataset(dicomData.dict);
2614
- dataset._meta = DicomMetaDictionary$1.namifyDataset(dicomData.meta);
2612
+ dataset = DicomMetaDictionary$2.naturalizeDataset(dicomData.dict);
2613
+ dataset._meta = DicomMetaDictionary$2.namifyDataset(dicomData.meta);
2615
2614
  multiframe = Normalizer$2.normalizeToDataset([dataset]);
2616
2615
  imagePlaneModule = metadataProvider.get("imagePlaneModule", imageIds[0]);
2617
2616
  generalSeriesModule = metadataProvider.get("generalSeriesModule", imageIds[0]);
@@ -2895,7 +2894,7 @@ function insertOverlappingPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray,
2895
2894
  var tempBuffer = labelmapBufferArray[m].slice(0);
2896
2895
 
2897
2896
  // temp list for checking overlaps
2898
- var tempSegmentsOnFrame = cloneDeep(segmentsOnFrameArray[m]);
2897
+ var tempSegmentsOnFrame = structuredClone(segmentsOnFrameArray[m]);
2899
2898
 
2900
2899
  /** split overlapping SEGs algorithm for each segment:
2901
2900
  * A) copy the labelmapBuffer in the array with index 0
@@ -2954,7 +2953,7 @@ function insertOverlappingPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray,
2954
2953
  M++;
2955
2954
  }
2956
2955
  tempBuffer = labelmapBufferArray[m].slice(0);
2957
- tempSegmentsOnFrame = cloneDeep(segmentsOnFrameArray[m]);
2956
+ tempSegmentsOnFrame = structuredClone(segmentsOnFrameArray[m]);
2958
2957
  _i2 = 0;
2959
2958
  break;
2960
2959
  } else {
@@ -2980,12 +2979,12 @@ function insertOverlappingPixelDataPlanar(segmentsOnFrame, segmentsOnFrameArray,
2980
2979
  if (_ret2 === "continue") continue;
2981
2980
  }
2982
2981
  labelmapBufferArray[m] = tempBuffer.slice(0);
2983
- segmentsOnFrameArray[m] = cloneDeep(tempSegmentsOnFrame);
2982
+ segmentsOnFrameArray[m] = structuredClone(tempSegmentsOnFrame);
2984
2983
 
2985
2984
  // reset temp variables/buffers for new segment
2986
2985
  m = 0;
2987
2986
  tempBuffer = labelmapBufferArray[m].slice(0);
2988
- tempSegmentsOnFrame = cloneDeep(segmentsOnFrameArray[m]);
2987
+ tempSegmentsOnFrame = structuredClone(segmentsOnFrameArray[m]);
2989
2988
  }
2990
2989
  }
2991
2990
  var getSegmentIndex = function getSegmentIndex(multiframe, frame) {
@@ -3587,7 +3586,7 @@ var TID1500 = utilities.TID1500, addAccessors = utilities.addAccessors;
3587
3586
  var StructuredReport = derivations.StructuredReport;
3588
3587
  var Normalizer$1 = normalizers.Normalizer;
3589
3588
  var TID1500MeasurementReport = TID1500.TID1500MeasurementReport, TID1501MeasurementGroup = TID1500.TID1501MeasurementGroup;
3590
- var DicomMetaDictionary = data.DicomMetaDictionary;
3589
+ var DicomMetaDictionary$1 = data.DicomMetaDictionary;
3591
3590
  var FINDING = { CodingSchemeDesignator: "DCM", CodeValue: "121071" };
3592
3591
  var FINDING_SITE = { CodingSchemeDesignator: "SCT", CodeValue: "363698007" };
3593
3592
  var FINDING_SITE_OLD = { CodingSchemeDesignator: "SRT", CodeValue: "G-C0E3" };
@@ -3656,7 +3655,7 @@ var MeasurementReport = /** @class */ (function () {
3656
3655
  vr: "UI"
3657
3656
  },
3658
3657
  ImplementationClassUID: {
3659
- Value: [DicomMetaDictionary.uid()],
3658
+ Value: [DicomMetaDictionary$1.uid()],
3660
3659
  vr: "UI"
3661
3660
  },
3662
3661
  ImplementationVersionName: {
@@ -3691,7 +3690,7 @@ var MeasurementReport = /** @class */ (function () {
3691
3690
  description: undefined,
3692
3691
  sopInstanceUid: ReferencedSOPInstanceUID,
3693
3692
  annotation: {
3694
- annotationUID: DicomMetaDictionary.uid(),
3693
+ annotationUID: DicomMetaDictionary$1.uid(),
3695
3694
  metadata: {
3696
3695
  toolName: toolType,
3697
3696
  referencedImageId: referencedImageId,
@@ -4974,6 +4973,726 @@ var Segmentation$1 = /*#__PURE__*/Object.freeze({
4974
4973
  generateToolState: generateToolState
4975
4974
  });
4976
4975
 
4976
+ /**
4977
+ * Checks if point is within array
4978
+ * @param {*} array
4979
+ * @param {*} pt
4980
+ * @returns
4981
+ */
4982
+ function ptInArray(array, pt) {
4983
+ var index = -1;
4984
+ for (var i = 0; i < array.length; i++) {
4985
+ if (isSamePoint(pt, array[i])) {
4986
+ index = i;
4987
+ }
4988
+ }
4989
+ return index;
4990
+ }
4991
+
4992
+ /**
4993
+ * Checks if point A and point B contain same values
4994
+ * @param {*} ptA
4995
+ * @param {*} ptB
4996
+ * @returns
4997
+ */
4998
+ function isSamePoint(ptA, ptB) {
4999
+ if (ptA[0] == ptB[0] && ptA[1] == ptB[1] && ptA[2] == ptB[2]) {
5000
+ return true;
5001
+ } else {
5002
+ return false;
5003
+ }
5004
+ }
5005
+
5006
+ /**
5007
+ * Goes through linesArray and replaces all references of old index with new index
5008
+ * @param {*} linesArray
5009
+ * @param {*} oldIndex
5010
+ * @param {*} newIndex
5011
+ */
5012
+ function replacePointIndexReferences(linesArray, oldIndex, newIndex) {
5013
+ for (var i = 0; i < linesArray.length; i++) {
5014
+ var line = linesArray[i];
5015
+ if (line.a == oldIndex) {
5016
+ line.a = newIndex;
5017
+ } else if (line.b == oldIndex) {
5018
+ line.b = newIndex;
5019
+ }
5020
+ }
5021
+ }
5022
+
5023
+ /**
5024
+ * Iterate through polyData from vtkjs and merge any points that are the same
5025
+ * then update merged point references within lines array
5026
+ * @param {*} polyData
5027
+ * @param {*} bypass
5028
+ * @returns
5029
+ */
5030
+ function removeDuplicatePoints(polyData, bypass) {
5031
+ var points = polyData.getPoints();
5032
+ var lines = polyData.getLines();
5033
+ var pointsArray = [];
5034
+ for (var i = 0; i < points.getNumberOfPoints(); i++) {
5035
+ var pt = points.getPoint(i).slice();
5036
+ pointsArray.push(pt);
5037
+ }
5038
+ var linesArray = [];
5039
+ for (var _i = 0; _i < lines.getNumberOfCells(); _i++) {
5040
+ var cell = lines.getCell(_i * 3).slice();
5041
+ //console.log(JSON.stringify(cell));
5042
+ var a = cell[0];
5043
+ var b = cell[1];
5044
+ var line = {
5045
+ a: a,
5046
+ b: b
5047
+ };
5048
+ linesArray.push(line);
5049
+ }
5050
+ if (bypass) {
5051
+ return {
5052
+ points: pointsArray,
5053
+ lines: linesArray
5054
+ };
5055
+ }
5056
+
5057
+ // Iterate through points and replace any duplicates
5058
+ var newPoints = [];
5059
+ for (var _i2 = 0; _i2 < pointsArray.length; _i2++) {
5060
+ var _pt = pointsArray[_i2];
5061
+ var index = ptInArray(newPoints, _pt);
5062
+ if (index >= 0) {
5063
+ // Duplicate Point -> replace references in lines
5064
+ replacePointIndexReferences(linesArray, _i2, index);
5065
+ } else {
5066
+ index = newPoints.length;
5067
+ newPoints.push(_pt);
5068
+ replacePointIndexReferences(linesArray, _i2, index);
5069
+ }
5070
+ }
5071
+
5072
+ // Final pass through lines, remove any that refer to exact same point
5073
+ var newLines = [];
5074
+ linesArray.forEach(function (line) {
5075
+ if (line.a != line.b) {
5076
+ newLines.push(line);
5077
+ }
5078
+ });
5079
+ return {
5080
+ points: newPoints,
5081
+ lines: newLines
5082
+ };
5083
+ }
5084
+
5085
+ function findNextLink(line, lines, contourPoints) {
5086
+ var index = -1;
5087
+ lines.forEach(function (cell, i) {
5088
+ if (index >= 0) {
5089
+ return;
5090
+ }
5091
+ if (cell.a == line.b) {
5092
+ index = i;
5093
+ }
5094
+ });
5095
+ if (index >= 0) {
5096
+ var nextLine = lines[index];
5097
+ lines.splice(index, 1);
5098
+ contourPoints.push(nextLine.b);
5099
+ if (contourPoints[0] == nextLine.b) {
5100
+ return {
5101
+ remainingLines: lines,
5102
+ contourPoints: contourPoints,
5103
+ type: "CLOSED_PLANAR"
5104
+ //type: 'CLOSEDPLANAR_XOR',
5105
+ };
5106
+ }
5107
+
5108
+ return findNextLink(nextLine, lines, contourPoints);
5109
+ }
5110
+ return {
5111
+ remainingLines: lines,
5112
+ contourPoints: contourPoints,
5113
+ type: "OPEN_PLANAR"
5114
+ };
5115
+ }
5116
+
5117
+ /**
5118
+ *
5119
+ * @param {*} lines
5120
+ */
5121
+ function findContours(lines) {
5122
+ if (lines.length == 0) {
5123
+ return [];
5124
+ }
5125
+ var contourPoints = [];
5126
+ var firstCell = lines.shift();
5127
+ contourPoints.push(firstCell.a);
5128
+ contourPoints.push(firstCell.b);
5129
+ var result = findNextLink(firstCell, lines, contourPoints);
5130
+ if (result.remainingLines.length == 0) {
5131
+ return [{
5132
+ type: result.type,
5133
+ contourPoints: result.contourPoints
5134
+ }];
5135
+ } else {
5136
+ var extraContours = findContours(result.remainingLines);
5137
+ extraContours.push({
5138
+ type: result.type,
5139
+ contourPoints: result.contourPoints
5140
+ });
5141
+ return extraContours;
5142
+ }
5143
+ }
5144
+ function findContoursFromReducedSet(lines, points) {
5145
+ return findContours(lines);
5146
+ }
5147
+
5148
+ function generateContourSetsFromLabelmap(_ref) {
5149
+ var segmentations = _ref.segmentations,
5150
+ cornerstoneCache = _ref.cornerstoneCache,
5151
+ cornerstoneToolsEnums = _ref.cornerstoneToolsEnums,
5152
+ vtkUtils = _ref.vtkUtils;
5153
+ var LABELMAP = cornerstoneToolsEnums.SegmentationRepresentations.Labelmap;
5154
+ var representationData = segmentations.representationData,
5155
+ segments = segmentations.segments;
5156
+ var segVolumeId = representationData[LABELMAP].volumeId;
5157
+
5158
+ // Get segmentation volume
5159
+ var vol = cornerstoneCache.getVolume(segVolumeId);
5160
+ if (!vol) {
5161
+ console.warn("No volume found for ".concat(segVolumeId));
5162
+ return;
5163
+ }
5164
+ var numSlices = vol.dimensions[2];
5165
+
5166
+ // Get image volume segmentation references
5167
+ var imageVol = cornerstoneCache.getVolume(vol.referencedVolumeId);
5168
+ if (!imageVol) {
5169
+ console.warn("No volume found for ".concat(vol.referencedVolumeId));
5170
+ return;
5171
+ }
5172
+
5173
+ // NOTE: Workaround for marching squares not finding closed contours at
5174
+ // boundary of image volume, clear pixels along x-y border of volume
5175
+ var segData = vol.imageData.getPointData().getScalars().getData();
5176
+ var pixelsPerSlice = vol.dimensions[0] * vol.dimensions[1];
5177
+ for (var z = 0; z < numSlices; z++) {
5178
+ for (var y = 0; y < vol.dimensions[1]; y++) {
5179
+ for (var x = 0; x < vol.dimensions[0]; x++) {
5180
+ var index = x + y * vol.dimensions[0] + z * pixelsPerSlice;
5181
+ if (x === 0 || y === 0 || x === vol.dimensions[0] - 1 || y === vol.dimensions[1] - 1) {
5182
+ segData[index] = 0;
5183
+ }
5184
+ }
5185
+ }
5186
+ }
5187
+
5188
+ // end workaround
5189
+ //
5190
+ //
5191
+ var ContourSets = [];
5192
+
5193
+ // Iterate through all segments in current segmentation set
5194
+ var numSegments = segments.length;
5195
+ for (var segIndex = 0; segIndex < numSegments; segIndex++) {
5196
+ var segment = segments[segIndex];
5197
+
5198
+ // Skip empty segments
5199
+ if (!segment) {
5200
+ continue;
5201
+ }
5202
+ var contourSequence = [];
5203
+ for (var sliceIndex = 0; sliceIndex < numSlices; sliceIndex++) {
5204
+ // Check if the slice is empty before running marching cube
5205
+ if (isSliceEmptyForSegment(sliceIndex, segData, pixelsPerSlice, segIndex)) {
5206
+ continue;
5207
+ }
5208
+ try {
5209
+ var _reducedSet$points;
5210
+ var scalars = vtkUtils.vtkDataArray.newInstance({
5211
+ name: "Scalars",
5212
+ values: Array.from(segData),
5213
+ numberOfComponents: 1
5214
+ });
5215
+
5216
+ // Modify segData for this specific segment directly
5217
+ var segmentIndexFound = false;
5218
+ for (var i = 0; i < segData.length; i++) {
5219
+ var value = segData[i];
5220
+ if (value === segIndex) {
5221
+ segmentIndexFound = true;
5222
+ scalars.setValue(i, 1);
5223
+ } else {
5224
+ scalars.setValue(i, 0);
5225
+ }
5226
+ }
5227
+ if (!segmentIndexFound) {
5228
+ continue;
5229
+ }
5230
+ var mSquares = vtkUtils.vtkImageMarchingSquares.newInstance({
5231
+ slice: sliceIndex
5232
+ });
5233
+
5234
+ // filter out the scalar data so that only it has background and
5235
+ // the current segment index
5236
+ var imageDataCopy = vtkUtils.vtkImageData.newInstance();
5237
+ imageDataCopy.shallowCopy(vol.imageData);
5238
+ imageDataCopy.getPointData().setScalars(scalars);
5239
+
5240
+ // Connect pipeline
5241
+ mSquares.setInputData(imageDataCopy);
5242
+ var cValues = [];
5243
+ cValues[0] = 1;
5244
+ mSquares.setContourValues(cValues);
5245
+ mSquares.setMergePoints(false);
5246
+
5247
+ // Perform marching squares
5248
+ var msOutput = mSquares.getOutputData();
5249
+
5250
+ // Clean up output from marching squares
5251
+ var reducedSet = removeDuplicatePoints(msOutput);
5252
+ if ((_reducedSet$points = reducedSet.points) !== null && _reducedSet$points !== void 0 && _reducedSet$points.length) {
5253
+ var contours = findContoursFromReducedSet(reducedSet.lines, reducedSet.points);
5254
+ contourSequence.push({
5255
+ referencedImageId: imageVol.imageIds[sliceIndex],
5256
+ contours: contours,
5257
+ polyData: reducedSet
5258
+ });
5259
+ }
5260
+ } catch (e) {
5261
+ console.warn(sliceIndex);
5262
+ console.warn(e);
5263
+ }
5264
+ }
5265
+ var metadata = {
5266
+ referencedImageId: imageVol.imageIds[0],
5267
+ // just use 0
5268
+ FrameOfReferenceUID: imageVol.metadata.FrameOfReferenceUID
5269
+ };
5270
+ var ContourSet = {
5271
+ label: segment.label,
5272
+ color: segment.color,
5273
+ metadata: metadata,
5274
+ sliceContours: contourSequence
5275
+ };
5276
+ ContourSets.push(ContourSet);
5277
+ }
5278
+ return ContourSets;
5279
+ }
5280
+ function isSliceEmptyForSegment(sliceIndex, segData, pixelsPerSlice, segIndex) {
5281
+ var startIdx = sliceIndex * pixelsPerSlice;
5282
+ var endIdx = startIdx + pixelsPerSlice;
5283
+ for (var i = startIdx; i < endIdx; i++) {
5284
+ if (segData[i] === segIndex) {
5285
+ return false;
5286
+ }
5287
+ }
5288
+ return true;
5289
+ }
5290
+
5291
+ // comment
5292
+ var RectangleROIStartEndThreshold = /*#__PURE__*/function () {
5293
+ function RectangleROIStartEndThreshold() {
5294
+ _classCallCheck(this, RectangleROIStartEndThreshold);
5295
+ } // empty
5296
+ _createClass(RectangleROIStartEndThreshold, null, [{
5297
+ key: "getContourSequence",
5298
+ value: function getContourSequence(toolData, metadataProvider) {
5299
+ var data = toolData.data;
5300
+ var _data$cachedStats = data.cachedStats,
5301
+ projectionPoints = _data$cachedStats.projectionPoints,
5302
+ projectionPointsImageIds = _data$cachedStats.projectionPointsImageIds;
5303
+ return projectionPoints.map(function (point, index) {
5304
+ var ContourData = getPointData(point);
5305
+ var ContourImageSequence = getContourImageSequence(projectionPointsImageIds[index], metadataProvider);
5306
+ return {
5307
+ NumberOfContourPoints: ContourData.length / 3,
5308
+ ContourImageSequence: ContourImageSequence,
5309
+ ContourGeometricType: "CLOSED_PLANAR",
5310
+ ContourData: ContourData
5311
+ };
5312
+ });
5313
+ }
5314
+ }]);
5315
+ return RectangleROIStartEndThreshold;
5316
+ }();
5317
+ RectangleROIStartEndThreshold.toolName = "RectangleROIStartEndThreshold";
5318
+ function getPointData(points) {
5319
+ // Since this is a closed contour, the order of the points is important.
5320
+ // re-order the points to be in the correct order clockwise
5321
+ // Spread to make sure Float32Arrays are converted to arrays
5322
+ var orderedPoints = [].concat(_toConsumableArray(points[0]), _toConsumableArray(points[1]), _toConsumableArray(points[3]), _toConsumableArray(points[2]));
5323
+ var pointsArray = orderedPoints.flat();
5324
+
5325
+ // reduce the precision of the points to 2 decimal places
5326
+ var pointsArrayWithPrecision = pointsArray.map(function (point) {
5327
+ return point.toFixed(2);
5328
+ });
5329
+ return pointsArrayWithPrecision;
5330
+ }
5331
+ function getContourImageSequence(imageId, metadataProvider) {
5332
+ var sopCommon = metadataProvider.get("sopCommonModule", imageId);
5333
+ return {
5334
+ ReferencedSOPClassUID: sopCommon.sopClassUID,
5335
+ ReferencedSOPInstanceUID: sopCommon.sopInstanceUID
5336
+ };
5337
+ }
5338
+
5339
+ function validateAnnotation(annotation) {
5340
+ if (!(annotation !== null && annotation !== void 0 && annotation.data)) {
5341
+ throw new Error("Tool data is empty");
5342
+ }
5343
+ if (!annotation.metadata || annotation.metadata.referenceImageId) {
5344
+ throw new Error("Tool data is not associated with any imageId");
5345
+ }
5346
+ }
5347
+ var AnnotationToPointData = /*#__PURE__*/function () {
5348
+ function AnnotationToPointData() {
5349
+ _classCallCheck(this, AnnotationToPointData);
5350
+ } // empty
5351
+ _createClass(AnnotationToPointData, null, [{
5352
+ key: "convert",
5353
+ value: function convert(annotation, index, metadataProvider) {
5354
+ validateAnnotation(annotation);
5355
+ var toolName = annotation.metadata.toolName;
5356
+ var toolClass = AnnotationToPointData.TOOL_NAMES[toolName];
5357
+ if (!toolClass) {
5358
+ throw new Error("Unknown tool type: ".concat(toolName, ", cannot convert to RTSSReport"));
5359
+ }
5360
+
5361
+ // Each toolData should become a list of contours, ContourSequence
5362
+ // contains a list of contours with their pointData, their geometry
5363
+ // type and their length.
5364
+ var ContourSequence = toolClass.getContourSequence(annotation, metadataProvider);
5365
+
5366
+ // Todo: random rgb color for now, options should be passed in
5367
+ var color = [Math.floor(Math.random() * 255), Math.floor(Math.random() * 255), Math.floor(Math.random() * 255)];
5368
+ return {
5369
+ ReferencedROINumber: index + 1,
5370
+ ROIDisplayColor: color,
5371
+ ContourSequence: ContourSequence
5372
+ };
5373
+ }
5374
+ }, {
5375
+ key: "register",
5376
+ value: function register(toolClass) {
5377
+ AnnotationToPointData.TOOL_NAMES[toolClass.toolName] = toolClass;
5378
+ }
5379
+ }]);
5380
+ return AnnotationToPointData;
5381
+ }();
5382
+ AnnotationToPointData.TOOL_NAMES = {};
5383
+ AnnotationToPointData.register(RectangleROIStartEndThreshold);
5384
+
5385
+ function getPatientModule(imageId, metadataProvider) {
5386
+ var generalSeriesModule = metadataProvider.get("generalSeriesModule", imageId);
5387
+ var generalStudyModule = metadataProvider.get("generalStudyModule", imageId);
5388
+ var patientStudyModule = metadataProvider.get("patientStudyModule", imageId);
5389
+ var patientModule = metadataProvider.get("patientModule", imageId);
5390
+ var patientDemographicModule = metadataProvider.get("patientDemographicModule", imageId);
5391
+ return {
5392
+ Modality: generalSeriesModule.modality,
5393
+ PatientID: patientModule.patientId,
5394
+ PatientName: patientModule.patientName,
5395
+ PatientBirthDate: "",
5396
+ PatientAge: patientStudyModule.patientAge,
5397
+ PatientSex: patientDemographicModule.patientSex,
5398
+ PatientWeight: patientStudyModule.patientWeight,
5399
+ StudyDate: generalStudyModule.studyDate,
5400
+ StudyTime: generalStudyModule.studyTime,
5401
+ StudyID: "ToDo",
5402
+ AccessionNumber: generalStudyModule.accessionNumber
5403
+ };
5404
+ }
5405
+
5406
+ function getReferencedFrameOfReferenceSequence(metadata, metadataProvider, dataset) {
5407
+ var imageId = metadata.referencedImageId,
5408
+ FrameOfReferenceUID = metadata.FrameOfReferenceUID;
5409
+ var instance = metadataProvider.get("instance", imageId);
5410
+ var SeriesInstanceUID = instance.SeriesInstanceUID;
5411
+ var ReferencedSeriesSequence = dataset.ReferencedSeriesSequence;
5412
+ return [{
5413
+ FrameOfReferenceUID: FrameOfReferenceUID,
5414
+ RTReferencedStudySequence: [{
5415
+ ReferencedSOPClassUID: dataset.SOPClassUID,
5416
+ ReferencedSOPInstanceUID: dataset.SOPInstanceUID,
5417
+ RTReferencedSeriesSequence: [{
5418
+ SeriesInstanceUID: SeriesInstanceUID,
5419
+ ContourImageSequence: _toConsumableArray(ReferencedSeriesSequence[0].ReferencedInstanceSequence)
5420
+ }]
5421
+ }]
5422
+ }];
5423
+ }
5424
+
5425
+ function getReferencedSeriesSequence(metadata, _index, metadataProvider, DicomMetadataStore) {
5426
+ // grab imageId from toolData
5427
+ var imageId = metadata.referencedImageId;
5428
+ var instance = metadataProvider.get("instance", imageId);
5429
+ var SeriesInstanceUID = instance.SeriesInstanceUID,
5430
+ StudyInstanceUID = instance.StudyInstanceUID;
5431
+ var ReferencedSeriesSequence = [];
5432
+ if (SeriesInstanceUID) {
5433
+ var series = DicomMetadataStore.getSeries(StudyInstanceUID, SeriesInstanceUID);
5434
+ var ReferencedSeries = {
5435
+ SeriesInstanceUID: SeriesInstanceUID,
5436
+ ReferencedInstanceSequence: []
5437
+ };
5438
+ series.instances.forEach(function (instance) {
5439
+ var SOPInstanceUID = instance.SOPInstanceUID,
5440
+ SOPClassUID = instance.SOPClassUID;
5441
+ ReferencedSeries.ReferencedInstanceSequence.push({
5442
+ ReferencedSOPClassUID: SOPClassUID,
5443
+ ReferencedSOPInstanceUID: SOPInstanceUID
5444
+ });
5445
+ });
5446
+ ReferencedSeriesSequence.push(ReferencedSeries);
5447
+ }
5448
+ return ReferencedSeriesSequence;
5449
+ }
5450
+
5451
+ function getRTROIObservationsSequence(toolData, index) {
5452
+ return {
5453
+ ObservationNumber: index + 1,
5454
+ ReferencedROINumber: index + 1,
5455
+ RTROIInterpretedType: "Todo: type",
5456
+ ROIInterpreter: "Todo: interpreter"
5457
+ };
5458
+ }
5459
+
5460
+ function getRTSeriesModule(DicomMetaDictionary) {
5461
+ return {
5462
+ SeriesInstanceUID: DicomMetaDictionary.uid(),
5463
+ // generate a new series instance uid
5464
+ SeriesNumber: "99" // Todo:: what should be the series number?
5465
+ };
5466
+ }
5467
+
5468
+ function getStructureSetModule(contour, index) {
5469
+ var FrameOfReferenceUID = contour.metadata.FrameOfReferenceUID;
5470
+ return {
5471
+ ROINumber: index + 1,
5472
+ ROIName: contour.name || "Todo: name ".concat(index + 1),
5473
+ ROIDescription: "Todo: description ".concat(index + 1),
5474
+ ROIGenerationAlgorithm: "Todo: algorithm",
5475
+ ReferencedFrameOfReferenceUID: FrameOfReferenceUID
5476
+ };
5477
+ }
5478
+
5479
+ var DicomMetaDictionary = dcmjs.data.DicomMetaDictionary;
5480
+ /**
5481
+ * Convert handles to RTSS report containing the dcmjs dicom dataset.
5482
+ *
5483
+ * Note: current WIP and using segmentation to contour conversion,
5484
+ * routine that is not fully tested
5485
+ *
5486
+ * @param segmentations - Cornerstone tool segmentations data
5487
+ * @param metadataProvider - Metadata provider
5488
+ * @param DicomMetadataStore - metadata store instance
5489
+ * @param cs - cornerstone instance
5490
+ * @param csTools - cornerstone tool instance
5491
+ * @returns Report object containing the dataset
5492
+ */
5493
+ function generateRTSSFromSegmentations(segmentations, metadataProvider, DicomMetadataStore, cornerstoneCache, cornerstoneToolsEnums, vtkUtils) {
5494
+ // Convert segmentations to ROIContours
5495
+ var roiContours = [];
5496
+ var contourSets = generateContourSetsFromLabelmap({
5497
+ segmentations: segmentations,
5498
+ cornerstoneCache: cornerstoneCache,
5499
+ cornerstoneToolsEnums: cornerstoneToolsEnums,
5500
+ vtkUtils: vtkUtils
5501
+ });
5502
+ contourSets.forEach(function (contourSet, segIndex) {
5503
+ // Check contour set isn't undefined
5504
+ if (contourSet) {
5505
+ var contourSequence_1 = [];
5506
+ contourSet.sliceContours.forEach(function (sliceContour) {
5507
+ /**
5508
+ * addContour - Adds a new ROI with related contours to ROIContourSequence
5509
+ *
5510
+ * @param newContour - cornerstoneTools `ROIContour` object
5511
+ *
5512
+ * newContour = {
5513
+ * name: string,
5514
+ * description: string,
5515
+ * contourSequence: array[contour]
5516
+ * color: array[number],
5517
+ * metadata: {
5518
+ * referencedImageId: string,
5519
+ * FrameOfReferenceUID: string
5520
+ * }
5521
+ * }
5522
+ *
5523
+ * contour = {
5524
+ * ContourImageSequence: array[
5525
+ * { ReferencedSOPClassUID: string, ReferencedSOPInstanceUID: string}
5526
+ * ]
5527
+ * ContourGeometricType: string,
5528
+ * NumberOfContourPoints: number,
5529
+ * ContourData: array[number]
5530
+ * }
5531
+ */
5532
+ // Note: change needed if support non-planar contour representation is needed
5533
+ var sopCommon = metadataProvider.get("sopCommonModule", sliceContour.referencedImageId);
5534
+ var ReferencedSOPClassUID = sopCommon.sopClassUID;
5535
+ var ReferencedSOPInstanceUID = sopCommon.sopInstanceUID;
5536
+ var ContourImageSequence = [
5537
+ { ReferencedSOPClassUID: ReferencedSOPClassUID, ReferencedSOPInstanceUID: ReferencedSOPInstanceUID } // NOTE: replace in dcmjs?
5538
+ ];
5539
+ var sliceContourPolyData = sliceContour.polyData;
5540
+ sliceContour.contours.forEach(function (contour, index) {
5541
+ var ContourGeometricType = contour.type;
5542
+ var NumberOfContourPoints = contour.contourPoints.length;
5543
+ var ContourData = [];
5544
+ contour.contourPoints.forEach(function (point) {
5545
+ var pointData = sliceContourPolyData.points[point];
5546
+ pointData[0] = +pointData[0].toFixed(2);
5547
+ pointData[1] = +pointData[1].toFixed(2);
5548
+ pointData[2] = +pointData[2].toFixed(2);
5549
+ ContourData.push(pointData[0]);
5550
+ ContourData.push(pointData[1]);
5551
+ ContourData.push(pointData[2]);
5552
+ });
5553
+ contourSequence_1.push({
5554
+ ContourImageSequence: ContourImageSequence,
5555
+ ContourGeometricType: ContourGeometricType,
5556
+ NumberOfContourPoints: NumberOfContourPoints,
5557
+ ContourNumber: index + 1,
5558
+ ContourData: ContourData
5559
+ });
5560
+ });
5561
+ });
5562
+ var segLabel = contourSet.label || "Segment ".concat(segIndex + 1);
5563
+ var ROIContour = {
5564
+ name: segLabel,
5565
+ description: segLabel,
5566
+ contourSequence: contourSequence_1,
5567
+ color: contourSet.color,
5568
+ metadata: contourSet.metadata
5569
+ };
5570
+ roiContours.push(ROIContour);
5571
+ }
5572
+ });
5573
+ var rtMetadata = {
5574
+ name: segmentations.label,
5575
+ label: segmentations.label
5576
+ };
5577
+ var dataset = _initializeDataset(rtMetadata, roiContours[0].metadata, metadataProvider);
5578
+ roiContours.forEach(function (contour, index) {
5579
+ var roiContour = {
5580
+ ROIDisplayColor: contour.color || [255, 0, 0],
5581
+ ContourSequence: contour.contourSequence,
5582
+ ReferencedROINumber: index + 1
5583
+ };
5584
+ dataset.StructureSetROISequence.push(getStructureSetModule(contour, index));
5585
+ dataset.ROIContourSequence.push(roiContour);
5586
+ // ReferencedSeriesSequence
5587
+ dataset.ReferencedSeriesSequence = getReferencedSeriesSequence(contour.metadata, index, metadataProvider, DicomMetadataStore);
5588
+ // ReferencedFrameOfReferenceSequence
5589
+ dataset.ReferencedFrameOfReferenceSequence =
5590
+ getReferencedFrameOfReferenceSequence(contour.metadata, metadataProvider, dataset);
5591
+ });
5592
+ var fileMetaInformationVersionArray = new Uint8Array(2);
5593
+ fileMetaInformationVersionArray[1] = 1;
5594
+ var _meta = {
5595
+ FileMetaInformationVersion: {
5596
+ Value: [fileMetaInformationVersionArray.buffer],
5597
+ vr: "OB"
5598
+ },
5599
+ TransferSyntaxUID: {
5600
+ Value: ["1.2.840.10008.1.2.1"],
5601
+ vr: "UI"
5602
+ },
5603
+ ImplementationClassUID: {
5604
+ Value: [DicomMetaDictionary.uid()],
5605
+ vr: "UI"
5606
+ },
5607
+ ImplementationVersionName: {
5608
+ Value: ["dcmjs"],
5609
+ vr: "SH"
5610
+ }
5611
+ };
5612
+ dataset._meta = _meta;
5613
+ return dataset;
5614
+ }
5615
+ /**
5616
+ * Convert handles to RTSSReport report object containing the dcmjs dicom dataset.
5617
+ *
5618
+ * Note: The tool data needs to be formatted in a specific way, and currently
5619
+ * it is limited to the RectangleROIStartEndTool in the Cornerstone.
5620
+ *
5621
+ * @param annotations Array of Cornerstone tool annotation data
5622
+ * @param metadataProvider Metadata provider
5623
+ * @param options report generation options
5624
+ * @returns Report object containing the dataset
5625
+ */
5626
+ function generateRTSSFromAnnotations(annotations, metadataProvider, DicomMetadataStore, options) {
5627
+ var rtMetadata = {
5628
+ name: "RTSS from Annotations",
5629
+ label: "RTSS from Annotations"
5630
+ };
5631
+ var dataset = _initializeDataset(rtMetadata, annotations[0].metadata, metadataProvider);
5632
+ annotations.forEach(function (annotation, index) {
5633
+ var ContourSequence = AnnotationToPointData.convert(annotation, index, metadataProvider, options);
5634
+ dataset.StructureSetROISequence.push(getStructureSetModule(annotation, index));
5635
+ dataset.ROIContourSequence.push(ContourSequence);
5636
+ dataset.RTROIObservationsSequence.push(getRTROIObservationsSequence(annotation, index));
5637
+ // ReferencedSeriesSequence
5638
+ // Todo: handle more than one series
5639
+ dataset.ReferencedSeriesSequence = getReferencedSeriesSequence(annotation.metadata, index, metadataProvider, DicomMetadataStore);
5640
+ // ReferencedFrameOfReferenceSequence
5641
+ dataset.ReferencedFrameOfReferenceSequence =
5642
+ getReferencedFrameOfReferenceSequence(annotation.metadata, metadataProvider, dataset);
5643
+ });
5644
+ var fileMetaInformationVersionArray = new Uint8Array(2);
5645
+ fileMetaInformationVersionArray[1] = 1;
5646
+ var _meta = {
5647
+ FileMetaInformationVersion: {
5648
+ Value: [fileMetaInformationVersionArray.buffer],
5649
+ vr: "OB"
5650
+ },
5651
+ TransferSyntaxUID: {
5652
+ Value: ["1.2.840.10008.1.2.1"],
5653
+ vr: "UI"
5654
+ },
5655
+ ImplementationClassUID: {
5656
+ Value: [DicomMetaDictionary.uid()],
5657
+ vr: "UI"
5658
+ },
5659
+ ImplementationVersionName: {
5660
+ Value: ["dcmjs"],
5661
+ vr: "SH"
5662
+ }
5663
+ };
5664
+ dataset._meta = _meta;
5665
+ return dataset;
5666
+ }
5667
+ // /**
5668
+ // * Generate Cornerstone tool state from dataset
5669
+ // * @param {object} dataset dataset
5670
+ // * @param {object} hooks
5671
+ // * @param {function} hooks.getToolClass Function to map dataset to a tool class
5672
+ // * @returns
5673
+ // */
5674
+ // //static generateToolState(_dataset, _hooks = {}) {
5675
+ // function generateToolState() {
5676
+ // // Todo
5677
+ // console.warn("RTSS.generateToolState not implemented");
5678
+ // }
5679
+ function _initializeDataset(rtMetadata, imgMetadata, metadataProvider) {
5680
+ var rtSOPInstanceUID = DicomMetaDictionary.uid();
5681
+ // get the first annotation data
5682
+ var imageId = imgMetadata.referencedImageId, FrameOfReferenceUID = imgMetadata.FrameOfReferenceUID;
5683
+ var studyInstanceUID = metadataProvider.get("generalSeriesModule", imageId).studyInstanceUID;
5684
+ var patientModule = getPatientModule(imageId, metadataProvider);
5685
+ var rtSeriesModule = getRTSeriesModule(DicomMetaDictionary);
5686
+ return __assign(__assign(__assign({ StructureSetROISequence: [], ROIContourSequence: [], RTROIObservationsSequence: [], ReferencedSeriesSequence: [], ReferencedFrameOfReferenceSequence: [] }, patientModule), rtSeriesModule), { StudyInstanceUID: studyInstanceUID, SOPClassUID: "1.2.840.10008.5.1.4.1.1.481.3", SOPInstanceUID: rtSOPInstanceUID, Manufacturer: "dcmjs", Modality: "RTSTRUCT", FrameOfReferenceUID: FrameOfReferenceUID, PositionReferenceIndicator: "", StructureSetLabel: rtMetadata.label || "", StructureSetName: rtMetadata.name || "", ReferringPhysicianName: "", OperatorsName: "", StructureSetDate: DicomMetaDictionary.date(), StructureSetTime: DicomMetaDictionary.time() });
5687
+ }
5688
+
5689
+ var RTSS = /*#__PURE__*/Object.freeze({
5690
+ __proto__: null,
5691
+ generateContourSetsFromLabelmap: generateContourSetsFromLabelmap,
5692
+ generateRTSSFromAnnotations: generateRTSSFromAnnotations,
5693
+ generateRTSSFromSegmentations: generateRTSSFromSegmentations
5694
+ });
5695
+
4977
5696
  var Cornerstone3DSR = {
4978
5697
  Bidirectional: Bidirectional,
4979
5698
  CobbAngle: CobbAngle,
@@ -4992,6 +5711,9 @@ var Cornerstone3DSR = {
4992
5711
  var Cornerstone3DSEG = {
4993
5712
  Segmentation: Segmentation$1
4994
5713
  };
5714
+ var Cornerstone3DRT = {
5715
+ RTSS: RTSS
5716
+ };
4995
5717
 
4996
5718
  var Colors = data.Colors,
4997
5719
  BitArray = data.BitArray;
@@ -5189,6 +5911,9 @@ var adaptersSEG = {
5189
5911
  Cornerstone3D: Cornerstone3DSEG,
5190
5912
  VTKjs: VTKjsSEG
5191
5913
  };
5914
+ var adaptersRT = {
5915
+ Cornerstone3D: Cornerstone3DRT
5916
+ };
5192
5917
 
5193
- export { index as Enums, adaptersSEG, adaptersSR, index$1 as helpers };
5918
+ export { index as Enums, adaptersRT, adaptersSEG, adaptersSR, index$1 as helpers };
5194
5919
  //# sourceMappingURL=adapters.es.js.map