@ohif/app 3.8.0-beta.86 → 3.8.0-beta.88

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 (41) hide show
  1. package/dist/117.bundle.a5e6959bf225da5cf4ed.js +6552 -0
  2. package/dist/164.bundle.96c0518b435ea19ef8c4.js +11816 -0
  3. package/dist/{433.bundle.c92d3f716a797127c1be.js → 203.bundle.846a90d1ede185c941b0.js} +4765 -6951
  4. package/dist/{206.bundle.1203a96e327b365264e5.js → 206.bundle.98ed38d4cc3cd491592d.js} +4 -4
  5. package/dist/{183.bundle.c88c4355c4829ed94a88.js → 236.bundle.fb6c65ae3a5aa0c58727.js} +17541 -23678
  6. package/dist/{321.bundle.5bd98d3324768715f634.js → 321.bundle.df33483c22991d82b0d3.js} +45 -43
  7. package/dist/{342.bundle.8c74ac4c7871bd4a6f60.js → 342.bundle.36ee082163b01284eeba.js} +1 -1
  8. package/dist/{41.bundle.45737afb9f85e7e69ff3.js → 41.bundle.b087dd5f5575fef9f4d7.js} +2 -2
  9. package/dist/{217.bundle.bbc6090836dcca555dfc.js → 416.bundle.837e0b84baddd2193d67.js} +61564 -70419
  10. package/dist/{448.bundle.fde8b8e0fd744f39389d.js → 448.bundle.e2db79f9db64f2211caf.js} +2 -2
  11. package/dist/473.bundle.f6804e7ac014a561eff8.js +7256 -0
  12. package/dist/483.bundle.9263b25c34b349aae80e.js +2287 -0
  13. package/dist/{487.bundle.8d0477af42cf9f8c0937.js → 487.bundle.6c4b3c9abadeab2ec397.js} +7 -7
  14. package/dist/{544.bundle.80c013bb477a263bcf10.js → 544.bundle.1b6998bb61d6f8f88da9.js} +2 -2
  15. package/dist/{574.bundle.9919f94ea252d4a45aaf.js → 574.bundle.d6f15a036af7ecaf82f9.js} +4 -4
  16. package/dist/{633.bundle.3961c49efec0b913b9cc.js → 633.bundle.409655439a8a864c3a0a.js} +4 -4
  17. package/dist/{669.bundle.5652fa450c1d63575a5a.js → 669.bundle.b28fafccfe244c340713.js} +9 -9
  18. package/dist/{335.bundle.fab6af469f98e7a59bfa.js → 7.bundle.d9bef0f76f54df3ed3d0.js} +185 -228
  19. package/dist/{722.bundle.a91ce7b563b901b25db0.js → 722.bundle.05e8759e64d484f4554d.js} +2 -2
  20. package/dist/{724.bundle.634bee9667a518d1202f.js → 724.bundle.236e5bb2a2c4e0e436b9.js} +234 -7
  21. package/dist/{726.bundle.0b3d9277d22fe7e15b89.js → 726.bundle.c8de818cf1a3ff0cf7d2.js} +2 -2
  22. package/dist/{164.bundle.288b10692cc72b81a98d.js → 783.bundle.2266dca43e7b065e00e2.js} +1 -1
  23. package/dist/{835.bundle.15aff0b7433bb0dd6d6d.js → 835.bundle.4c0eaa2c1a427ee41817.js} +2 -2
  24. package/dist/{862.bundle.217ce894d955626c78c5.js → 862.bundle.4be5d148c2b1adf4dbf3.js} +2 -2
  25. package/dist/{889.bundle.e2700d7456565ce71dad.js → 889.bundle.3e25455cd8ed5cff6736.js} +1 -1
  26. package/dist/{94.bundle.b35c818d871de99336d8.js → 94.bundle.84aeabf47a50226a3757.js} +4 -4
  27. package/dist/{app.bundle.ce0e385dbbb6c1c1769f.js → app.bundle.4d1d6a9e1f5ddf2ecc89.js} +44487 -42404
  28. package/dist/cornerstoneDICOMImageLoader.min.js +1 -1
  29. package/dist/cornerstoneDICOMImageLoader.min.js.map +1 -1
  30. package/dist/index.html +1 -1
  31. package/dist/{polySeg.bundle.c2653f8ce77f44ae095b.js → polySeg.bundle.43bf3490e07982491e2b.js} +3 -3
  32. package/dist/suv-peak-worker.bundle.1f9b9e6887eebc07c50a.js +404 -0
  33. package/dist/sw.js +1 -1
  34. package/package.json +18 -18
  35. /package/dist/{188.bundle.d9b13c4a2910858bca9b.js → 188.bundle.a3f7d32b447d383dc882.js} +0 -0
  36. /package/dist/{325.bundle.ac07a6ca0a4e66bed604.js → 325.bundle.88b9768fe4c3f8b4c479.js} +0 -0
  37. /package/dist/{594.bundle.e8e1b20c5c46cf16ffa3.js → 594.bundle.dd4e77925f097e4715a5.js} +0 -0
  38. /package/dist/{699.bundle.7228b225e0c2b8100077.js → 699.bundle.fa08705eb3ffb41fc6d4.js} +0 -0
  39. /package/dist/{905.bundle.ec6275a2096f7f096618.js → 905.bundle.fddef85afd237a0e41e8.js} +0 -0
  40. /package/dist/{907.bundle.d2823642d3a32b5209a2.js → 907.bundle.245684385d33246c88a7.js} +0 -0
  41. /package/dist/{961.bundle.34a9b1fbf372d18b9b36.js → 961.bundle.493b3434a6d12cd53707.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
- (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[335],{
2
+ (globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[7],{
3
3
 
4
- /***/ 27335:
4
+ /***/ 89007:
5
5
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
6
6
 
7
7
  // ESM COMPAT FLAG
@@ -970,11 +970,76 @@ PanelPetSUV.propTypes = {
970
970
  }).isRequired
971
971
  }).isRequired
972
972
  };
973
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 28 modules
974
+ var esm = __webpack_require__(92136);
975
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/index.js
976
+ var dist_esm = __webpack_require__(39371);
977
+ ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/utils/handleROIThresholding.ts
978
+
979
+ const handleROIThresholding = async ({
980
+ segmentationId,
981
+ commandsManager,
982
+ segmentationService,
983
+ config = {}
984
+ }) => {
985
+ const segmentation = segmentationService.getSegmentation(segmentationId);
986
+
987
+ // re-calculating the cached stats for the active segmentation
988
+ const updatedPerSegmentCachedStats = {};
989
+ segmentation.segments = await Promise.all(segmentation.segments.map(async segment => {
990
+ if (!segment || !segment.segmentIndex) {
991
+ return segment;
992
+ }
993
+ const labelmap = esm.cache.getVolume(segmentationId);
994
+ const segmentIndex = segment.segmentIndex;
995
+ const lesionStats = commandsManager.run('getLesionStats', {
996
+ labelmap,
997
+ segmentIndex
998
+ });
999
+ const suvPeak = await commandsManager.run('calculateSuvPeak', {
1000
+ labelmap,
1001
+ segmentIndex
1002
+ });
1003
+ const lesionGlyoclysisStats = lesionStats.volume * lesionStats.meanValue;
1004
+
1005
+ // update segDetails with the suv peak for the active segmentation
1006
+ const cachedStats = {
1007
+ lesionStats,
1008
+ suvPeak,
1009
+ lesionGlyoclysisStats
1010
+ };
1011
+ segment.cachedStats = cachedStats;
1012
+ segment.displayText = [`SUV Peak: ${suvPeak.suvPeak.toFixed(2)}`, `Volume: ${lesionStats.volume.toFixed(2)} mm3`];
1013
+ updatedPerSegmentCachedStats[segmentIndex] = cachedStats;
1014
+ return segment;
1015
+ }));
1016
+ const notYetUpdatedAtSource = true;
1017
+ const segmentations = segmentationService.getSegmentations();
1018
+ const tmtv = commandsManager.run('calculateTMTV', {
1019
+ segmentations
1020
+ });
1021
+ segmentation.cachedStats = Object.assign(segmentation.cachedStats, updatedPerSegmentCachedStats, {
1022
+ tmtv: {
1023
+ value: tmtv.toFixed(3),
1024
+ config: {
1025
+ ...config
1026
+ }
1027
+ }
1028
+ });
1029
+ segmentationService.addOrUpdateSegmentation({
1030
+ ...segmentation
1031
+ }, false,
1032
+ // don't suppress events
1033
+ notYetUpdatedAtSource);
1034
+ };
973
1035
  ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/Panels/PanelROIThresholdSegmentation/PanelROIThresholdExport.tsx
974
1036
 
975
1037
 
976
1038
 
977
1039
 
1040
+
1041
+
1042
+
978
1043
  function PanelRoiThresholdSegmentation({
979
1044
  servicesManager,
980
1045
  commandsManager
@@ -987,6 +1052,7 @@ function PanelRoiThresholdSegmentation({
987
1052
  t
988
1053
  } = (0,es/* useTranslation */.Bd)('PanelSUVExport');
989
1054
  const [segmentations, setSegmentations] = (0,react.useState)(() => segmentationService.getSegmentations());
1055
+ const [activeSegmentation, setActiveSegmentation] = (0,react.useState)(null);
990
1056
 
991
1057
  /**
992
1058
  * Update UI based on segmentation changes (added, removed, updated)
@@ -1003,6 +1069,8 @@ function PanelRoiThresholdSegmentation({
1003
1069
  } = segmentationService.subscribe(evt, () => {
1004
1070
  const segmentations = segmentationService.getSegmentations();
1005
1071
  setSegmentations(segmentations);
1072
+ const activeSegmentation = segmentations.filter(seg => seg.isActive);
1073
+ setActiveSegmentation(activeSegmentation[0]);
1006
1074
  });
1007
1075
  subscriptions.push(unsubscribe);
1008
1076
  });
@@ -1012,26 +1080,50 @@ function PanelRoiThresholdSegmentation({
1012
1080
  });
1013
1081
  };
1014
1082
  }, []);
1015
- const tmtvValue = segmentations?.[0]?.cachedStats?.tmtv?.value || null;
1016
- const config = segmentations?.[0]?.cachedStats?.tmtv?.config || {};
1017
- segmentations.forEach(segmentation => {
1018
- const {
1019
- cachedStats
1020
- } = segmentation;
1021
- if (!cachedStats) {
1022
- return;
1023
- }
1024
-
1025
- // segment 1
1026
- const suvPeak = cachedStats?.['1']?.suvPeak?.suvPeak;
1027
- if (Number.isNaN(suvPeak)) {
1028
- uiNotificationService.show({
1029
- title: 'SUV Peak',
1030
- message: 'Segmented volume does not allow SUV Peak calculation',
1031
- type: 'warning'
1083
+ (0,react.useEffect)(() => {
1084
+ const callback = async evt => {
1085
+ const {
1086
+ detail
1087
+ } = evt;
1088
+ const {
1089
+ segmentationId
1090
+ } = detail;
1091
+ if (!segmentationId) {
1092
+ return;
1093
+ }
1094
+ await handleROIThresholding({
1095
+ segmentationId,
1096
+ commandsManager,
1097
+ segmentationService
1032
1098
  });
1033
- }
1034
- });
1099
+ const segmentation = segmentationService.getSegmentation(segmentationId);
1100
+ const {
1101
+ cachedStats
1102
+ } = segmentation;
1103
+ if (!cachedStats) {
1104
+ return;
1105
+ }
1106
+
1107
+ // segment 1
1108
+ const suvPeak = cachedStats?.['1']?.suvPeak?.suvPeak;
1109
+ if (Number.isNaN(suvPeak)) {
1110
+ uiNotificationService.show({
1111
+ title: 'SUV Peak',
1112
+ message: 'Segmented volume does not allow SUV Peak calculation',
1113
+ type: 'warning'
1114
+ });
1115
+ }
1116
+ };
1117
+ esm.eventTarget.addEventListenerDebounced(dist_esm.Enums.Events.SEGMENTATION_DATA_MODIFIED, callback, 300);
1118
+ return () => {
1119
+ esm.eventTarget.removeEventListenerDebounced(dist_esm.Enums.Events.SEGMENTATION_DATA_MODIFIED, callback);
1120
+ };
1121
+ }, []);
1122
+ if (!activeSegmentation) {
1123
+ return null;
1124
+ }
1125
+ const tmtvValue = activeSegmentation.cachedStats?.tmtv?.value || null;
1126
+ const config = activeSegmentation.cachedStats?.tmtv?.config || {};
1035
1127
  const actions = [{
1036
1128
  label: 'Export CSV',
1037
1129
  onClick: () => {
@@ -1043,7 +1135,7 @@ function PanelRoiThresholdSegmentation({
1043
1135
  },
1044
1136
  disabled: tmtvValue === null
1045
1137
  }, {
1046
- label: 'Create RT Report',
1138
+ label: 'Export RT Report',
1047
1139
  onClick: () => {
1048
1140
  commandsManager.runCommand('createTMTVRTReport');
1049
1141
  },
@@ -1054,7 +1146,7 @@ function PanelRoiThresholdSegmentation({
1054
1146
  }, /*#__PURE__*/react.createElement("div", {
1055
1147
  className: "invisible-scrollbar overflow-y-auto overflow-x-hidden"
1056
1148
  }, tmtvValue !== null ? /*#__PURE__*/react.createElement("div", {
1057
- className: "bg-secondary-dark mt-1 flex items-baseline justify-between px-2 py-1"
1149
+ className: "bg-secondary-dark flex items-baseline justify-between px-2 py-1"
1058
1150
  }, /*#__PURE__*/react.createElement("span", {
1059
1151
  className: "text-base font-bold uppercase tracking-widest text-white"
1060
1152
  }, 'TMTV:'), /*#__PURE__*/react.createElement("div", {
@@ -1157,12 +1249,8 @@ function getPanelModule({
1157
1249
  }];
1158
1250
  }
1159
1251
  /* harmony default export */ const src_getPanelModule = (getPanelModule);
1160
- // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/index.js + 18 modules
1161
- var esm = __webpack_require__(24542);
1162
1252
  ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/utils/measurementServiceMappings/constants/supportedTools.js
1163
1253
  /* harmony default export */ const supportedTools = (['RectangleROIStartEndThreshold']);
1164
- // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 328 modules
1165
- var dist_esm = __webpack_require__(73868);
1166
1254
  ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/utils/measurementServiceMappings/utils/getSOPInstanceAttributes.js
1167
1255
 
1168
1256
  function getSOPInstanceAttributes(imageId) {
@@ -1171,7 +1259,7 @@ function getSOPInstanceAttributes(imageId) {
1171
1259
  }
1172
1260
  }
1173
1261
  function _getUIDFromImageID(imageId) {
1174
- const instance = dist_esm.metaData.get('instance', imageId);
1262
+ const instance = esm.metaData.get('instance', imageId);
1175
1263
  return {
1176
1264
  SOPInstanceUID: instance.SOPInstanceUID,
1177
1265
  SeriesInstanceUID: instance.SeriesInstanceUID,
@@ -1274,7 +1362,7 @@ function init({
1274
1362
  displaySetService,
1275
1363
  cornerstoneViewportService
1276
1364
  } = servicesManager.services;
1277
- (0,esm.addTool)(esm.RectangleROIStartEndThresholdTool);
1365
+ (0,dist_esm.addTool)(dist_esm.RectangleROIStartEndThresholdTool);
1278
1366
  const {
1279
1367
  RectangleROIStartEndThreshold
1280
1368
  } = measurementServiceMappings_measurementServiceMappingsFactory(measurementService, displaySetService, cornerstoneViewportService);
@@ -1298,7 +1386,7 @@ function getRoiStats(referencedVolume, annotations) {
1298
1386
  baseValue
1299
1387
  } = _getStrategyFn('max');
1300
1388
  let value = baseValue;
1301
- const boundsIJK = esm.utilities.rectangleROITool.getBoundsIJKFromRectangleAnnotations(annotations, referencedVolume);
1389
+ const boundsIJK = dist_esm.utilities.rectangleROITool.getBoundsIJKFromRectangleAnnotations(annotations, referencedVolume);
1302
1390
  const [[iMin, iMax], [jMin, jMax], [kMin, kMax]] = boundsIJK;
1303
1391
  for (let i = iMin; i <= iMax; i++) {
1304
1392
  for (let j = jMin; j <= jMax; j++) {
@@ -1322,7 +1410,7 @@ function getThresholdValues(annotationUIDs, referencedVolumes, config) {
1322
1410
  const {
1323
1411
  weight
1324
1412
  } = config;
1325
- const annotations = annotationUIDs.map(annotationUID => esm.annotation.state.getAnnotation(annotationUID));
1413
+ const annotations = annotationUIDs.map(annotationUID => dist_esm.annotation.state.getAnnotation(annotationUID));
1326
1414
  const ptValue = getRoiStats(referencedVolumes[0], annotations);
1327
1415
  return {
1328
1416
  ctLower: -Infinity,
@@ -1345,110 +1433,6 @@ function _getStrategyFn(statistic) {
1345
1433
  };
1346
1434
  }
1347
1435
  /* harmony default export */ const getThresholdValue = (getThresholdValues);
1348
- ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/utils/calculateSUVPeak.ts
1349
-
1350
-
1351
- /**
1352
- * This method calculates the SUV peak on a segmented ROI from a reference PET
1353
- * volume. If a rectangle annotation is provided, the peak is calculated within that
1354
- * rectangle. Otherwise, the calculation is performed on the entire volume which
1355
- * will be slower but same result.
1356
- * @param viewport Viewport to use for the calculation
1357
- * @param labelmap Labelmap from which the mask is taken
1358
- * @param referenceVolume PET volume to use for SUV calculation
1359
- * @param toolData [Optional] list of toolData to use for SUV calculation
1360
- * @param segmentIndex The index of the segment to use for masking
1361
- * @returns
1362
- */
1363
- function calculateSuvPeak(labelmap, referenceVolume, annotations, segmentIndex = 1) {
1364
- if (referenceVolume.metadata.Modality !== 'PT') {
1365
- return;
1366
- }
1367
- const labelmapData = labelmap.getScalarData();
1368
- const referenceVolumeData = referenceVolume.getScalarData();
1369
- if (labelmapData.length !== referenceVolumeData.length) {
1370
- throw new Error('labelmap and referenceVolume must have the same number of pixels');
1371
- }
1372
- const {
1373
- dimensions,
1374
- imageData: labelmapImageData
1375
- } = labelmap;
1376
- const {
1377
- imageData: referenceVolumeImageData
1378
- } = referenceVolume;
1379
- let boundsIJK;
1380
- // Todo: using the first annotation for now
1381
- if (annotations?.length && annotations[0].data?.cachedStats) {
1382
- const {
1383
- projectionPoints
1384
- } = annotations[0].data.cachedStats;
1385
- const pointsToUse = [].concat(...projectionPoints); // cannot use flat() because of typescript compiler right now
1386
-
1387
- const rectangleCornersIJK = pointsToUse.map(world => {
1388
- const ijk = gl_matrix_esm/* vec3.fromValues */.eR.fromValues(0, 0, 0);
1389
- referenceVolumeImageData.worldToIndex(world, ijk);
1390
- return ijk;
1391
- });
1392
- boundsIJK = esm.utilities.boundingBox.getBoundingBoxAroundShape(rectangleCornersIJK, dimensions);
1393
- }
1394
- let max = 0;
1395
- let maxIJK = [0, 0, 0];
1396
- let maxLPS = [0, 0, 0];
1397
- const callback = ({
1398
- pointIJK,
1399
- pointLPS
1400
- }) => {
1401
- const offset = referenceVolumeImageData.computeOffsetIndex(pointIJK);
1402
- const value = labelmapData[offset];
1403
- if (value !== segmentIndex) {
1404
- return;
1405
- }
1406
- const referenceValue = referenceVolumeData[offset];
1407
- if (referenceValue > max) {
1408
- max = referenceValue;
1409
- maxIJK = pointIJK;
1410
- maxLPS = pointLPS;
1411
- }
1412
- };
1413
- esm.utilities.pointInShapeCallback(labelmapImageData, () => true, callback, boundsIJK);
1414
- const direction = labelmapImageData.getDirection().slice(0, 3);
1415
-
1416
- /**
1417
- * 2. Find the bottom and top of the great circle for the second sphere (1cc sphere)
1418
- * V = (4/3)πr3
1419
- */
1420
- const radius = Math.pow(1 / (4 / 3 * Math.PI), 1 / 3) * 10;
1421
- const diameter = radius * 2;
1422
- const secondaryCircleWorld = gl_matrix_esm/* vec3.create */.eR.create();
1423
- const bottomWorld = gl_matrix_esm/* vec3.create */.eR.create();
1424
- const topWorld = gl_matrix_esm/* vec3.create */.eR.create();
1425
- referenceVolumeImageData.indexToWorld(maxIJK, secondaryCircleWorld);
1426
- gl_matrix_esm/* vec3.scaleAndAdd */.eR.scaleAndAdd(bottomWorld, secondaryCircleWorld, direction, -diameter / 2);
1427
- gl_matrix_esm/* vec3.scaleAndAdd */.eR.scaleAndAdd(topWorld, secondaryCircleWorld, direction, diameter / 2);
1428
- const suvPeakCirclePoints = [bottomWorld, topWorld];
1429
-
1430
- /**
1431
- * 3. Find the Mean and Max of the 1cc sphere centered on the suv Max of the previous
1432
- * sphere
1433
- */
1434
- let count = 0;
1435
- let acc = 0;
1436
- const suvPeakMeanCallback = ({
1437
- value
1438
- }) => {
1439
- acc += value;
1440
- count += 1;
1441
- };
1442
- esm.utilities.pointInSurroundingSphereCallback(referenceVolumeImageData, suvPeakCirclePoints, suvPeakMeanCallback);
1443
- const mean = acc / count;
1444
- return {
1445
- max,
1446
- maxIJK,
1447
- maxLPS,
1448
- mean
1449
- };
1450
- }
1451
- /* harmony default export */ const calculateSUVPeak = (calculateSuvPeak);
1452
1436
  ;// CONCATENATED MODULE: ../../../extensions/tmtv/src/utils/calculateTMTV.ts
1453
1437
 
1454
1438
 
@@ -1464,7 +1448,7 @@ function calculateSuvPeak(labelmap, referenceVolume, annotations, segmentIndex =
1464
1448
  */
1465
1449
  function calculateTMTV(labelmaps, segmentIndex = 1) {
1466
1450
  const volumeId = 'mergedLabelmap';
1467
- const mergedLabelmap = esm.utilities.segmentation.createMergedLabelmapForIndex(labelmaps, segmentIndex, volumeId);
1451
+ const mergedLabelmap = dist_esm.utilities.segmentation.createMergedLabelmapForIndex(labelmaps, segmentIndex, volumeId);
1468
1452
  const {
1469
1453
  imageData,
1470
1454
  spacing
@@ -1558,7 +1542,22 @@ function dicomRTAnnotationExport(annotations) {
1558
1542
 
1559
1543
  const commandsModule_metadataProvider = core_src.classes.MetadataProvider;
1560
1544
  const RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS = ['RectangleROIStartEndThreshold', 'RectangleROIThreshold'];
1561
- const LABELMAP = esm.Enums.SegmentationRepresentations.Labelmap;
1545
+ const LABELMAP = dist_esm.Enums.SegmentationRepresentations.Labelmap;
1546
+ const workerManager = (0,esm.getWebWorkerManager)();
1547
+ const options = {
1548
+ maxWorkerInstances: 1,
1549
+ autoTerminateOnIdle: {
1550
+ enabled: true,
1551
+ idleTimeThreshold: 3000
1552
+ }
1553
+ };
1554
+
1555
+ // Register the task
1556
+ const workerFn = () => {
1557
+ return new Worker(new URL(/* worker import */ __webpack_require__.p + __webpack_require__.u(584), __webpack_require__.b), {
1558
+ name: 'suv-peak-worker' // name used by the browser to name the worker
1559
+ });
1560
+ };
1562
1561
  const commandsModule = ({
1563
1562
  servicesManager,
1564
1563
  commandsManager,
@@ -1584,7 +1583,7 @@ const commandsModule = ({
1584
1583
  const {
1585
1584
  element
1586
1585
  } = getEnabledElement(activeViewportId) || {};
1587
- const enabledElement = dist_esm.getEnabledElement(element);
1586
+ const enabledElement = esm.getEnabledElement(element);
1588
1587
  return enabledElement;
1589
1588
  }
1590
1589
  function _getMatchedViewportsToolGroupIds() {
@@ -1607,7 +1606,7 @@ const commandsModule = ({
1607
1606
  }
1608
1607
  function _getAnnotationsSelectedByToolNames(toolNames) {
1609
1608
  return toolNames.reduce((allAnnotationUIDs, toolName) => {
1610
- const annotationUIDs = esm.annotation.selection.getAnnotationsSelectedByToolName(toolName);
1609
+ const annotationUIDs = dist_esm.annotation.selection.getAnnotationsSelectedByToolName(toolName);
1611
1610
  return allAnnotationUIDs.concat(annotationUIDs);
1612
1611
  }, []);
1613
1612
  }
@@ -1711,7 +1710,7 @@ const commandsModule = ({
1711
1710
  config,
1712
1711
  segmentIndex
1713
1712
  }) => {
1714
- const segmentation = esm.segmentation.state.getSegmentation(segmentationId);
1713
+ const segmentation = dist_esm.segmentation.state.getSegmentation(segmentationId);
1715
1714
  const {
1716
1715
  representationData
1717
1716
  } = segmentation;
@@ -1728,7 +1727,7 @@ const commandsModule = ({
1728
1727
  } = representationData[LABELMAP];
1729
1728
  const {
1730
1729
  referencedVolumeId
1731
- } = dist_esm.cache.getVolume(segVolumeId);
1730
+ } = esm.cache.getVolume(segVolumeId);
1732
1731
  const annotationUIDs = _getAnnotationsSelectedByToolNames(RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS);
1733
1732
  if (annotationUIDs.length === 0) {
1734
1733
  uiNotificationService.show({
@@ -1738,9 +1737,9 @@ const commandsModule = ({
1738
1737
  });
1739
1738
  return;
1740
1739
  }
1741
- const labelmapVolume = dist_esm.cache.getVolume(segmentationId);
1742
- let referencedVolume = dist_esm.cache.getVolume(referencedVolumeId);
1743
- const ctReferencedVolume = dist_esm.cache.getVolume(ctVolumeId);
1740
+ const labelmapVolume = esm.cache.getVolume(segmentationId);
1741
+ let referencedVolume = esm.cache.getVolume(referencedVolumeId);
1742
+ const ctReferencedVolume = esm.cache.getVolume(ctVolumeId);
1744
1743
 
1745
1744
  // check if viewport is
1746
1745
 
@@ -1750,7 +1749,7 @@ const commandsModule = ({
1750
1749
  if (!labelmapVolume) {
1751
1750
  throw new Error('No Reference labelmap found');
1752
1751
  }
1753
- const annotation = esm.annotation.state.getAnnotation(annotationUIDs[0]);
1752
+ const annotation = dist_esm.annotation.state.getAnnotation(annotationUIDs[0]);
1754
1753
  const {
1755
1754
  metadata: {
1756
1755
  enabledElement: {
@@ -1770,8 +1769,8 @@ const commandsModule = ({
1770
1769
  // 3. We throw an error
1771
1770
  const displaySetInstanceUIDs = viewportGridService.getDisplaySetsUIDsForViewport(viewport.id);
1772
1771
  displaySetInstanceUIDs.forEach(displaySetInstanceUID => {
1773
- const volume = dist_esm.cache.getVolumes().find(volume => volume.volumeId.includes(displaySetInstanceUID));
1774
- if (dist_esm.utilities.isEqual(volume.dimensions, labelmapVolume.dimensions) && dist_esm.utilities.isEqual(volume.spacing, labelmapVolume.spacing)) {
1772
+ const volume = esm.cache.getVolumes().find(volume => volume.volumeId.includes(displaySetInstanceUID));
1773
+ if (esm.utilities.isEqual(volume.dimensions, labelmapVolume.dimensions) && esm.utilities.isEqual(volume.spacing, labelmapVolume.spacing)) {
1775
1774
  referencedVolume = volume;
1776
1775
  }
1777
1776
  });
@@ -1782,7 +1781,7 @@ const commandsModule = ({
1782
1781
  ctLower,
1783
1782
  ctUpper
1784
1783
  } = getThresholdValue(annotationUIDs, [referencedVolume, ctReferencedVolume], config);
1785
- return esm.utilities.segmentation.rectangleROIThresholdVolumeByRange(annotationUIDs, labelmapVolume, [{
1784
+ return dist_esm.utilities.segmentation.rectangleROIThresholdVolumeByRange(annotationUIDs, labelmapVolume, [{
1786
1785
  volume: referencedVolume,
1787
1786
  lower: ptLower,
1788
1787
  upper: ptUpper
@@ -1795,17 +1794,40 @@ const commandsModule = ({
1795
1794
  segmentIndex
1796
1795
  });
1797
1796
  },
1798
- calculateSuvPeak: ({
1797
+ calculateSuvPeak: async ({
1799
1798
  labelmap,
1800
1799
  segmentIndex
1801
1800
  }) => {
1801
+ // if we put it in the top, it will appear in other modes
1802
+ workerManager.registerWorker('suv-peak-worker', workerFn, options);
1802
1803
  const {
1803
1804
  referencedVolumeId
1804
1805
  } = labelmap;
1805
- const referencedVolume = dist_esm.cache.getVolume(referencedVolumeId);
1806
+ const referencedVolume = esm.cache.getVolume(referencedVolumeId);
1806
1807
  const annotationUIDs = _getAnnotationsSelectedByToolNames(RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS);
1807
- const annotations = annotationUIDs.map(annotationUID => esm.annotation.state.getAnnotation(annotationUID));
1808
- const suvPeak = calculateSUVPeak(labelmap, referencedVolume, annotations, segmentIndex);
1808
+ const annotations = annotationUIDs.map(annotationUID => dist_esm.annotation.state.getAnnotation(annotationUID));
1809
+ const labelmapProps = {
1810
+ dimensions: labelmap.dimensions,
1811
+ origin: labelmap.origin,
1812
+ direction: labelmap.direction,
1813
+ spacing: labelmap.spacing,
1814
+ scalarData: labelmap.scalarData,
1815
+ metadata: labelmap.metadata
1816
+ };
1817
+ const referenceVolumeProps = {
1818
+ dimensions: referencedVolume.dimensions,
1819
+ origin: referencedVolume.origin,
1820
+ direction: referencedVolume.direction,
1821
+ spacing: referencedVolume.spacing,
1822
+ scalarData: referencedVolume.scalarData,
1823
+ metadata: referencedVolume.metadata
1824
+ };
1825
+ const suvPeak = await workerManager.executeTask('suv-peak-worker', 'calculateSuvPeak', {
1826
+ labelmapProps,
1827
+ referenceVolumeProps,
1828
+ annotations,
1829
+ segmentIndex
1830
+ });
1809
1831
  return {
1810
1832
  suvPeak: suvPeak.mean,
1811
1833
  suvMax: suvPeak.max,
@@ -1821,7 +1843,7 @@ const commandsModule = ({
1821
1843
  scalarData,
1822
1844
  spacing
1823
1845
  } = labelmap;
1824
- const referencedScalarData = dist_esm.cache.getVolume(labelmap.referencedVolumeId).getScalarData();
1846
+ const referencedScalarData = esm.cache.getVolume(labelmap.referencedVolumeId).getScalarData();
1825
1847
  let segmentationMax = -Infinity;
1826
1848
  let segmentationMin = Infinity;
1827
1849
  let segmentationValues = [];
@@ -1909,7 +1931,7 @@ const commandsModule = ({
1909
1931
  // merge labelmap will through an error if labels maps are not the same size
1910
1932
  // or same direction or ....
1911
1933
  try {
1912
- mergedLabelmap = esm.utilities.segmentation.createMergedLabelmapForIndex(labelmapVolumes);
1934
+ mergedLabelmap = dist_esm.utilities.segmentation.createMergedLabelmapForIndex(labelmapVolumes);
1913
1935
  } catch (e) {
1914
1936
  console.error('commandsModule::getTotalLesionGlycolysis', e);
1915
1937
  return;
@@ -1923,7 +1945,7 @@ const commandsModule = ({
1923
1945
  if (!referencedVolumeId) {
1924
1946
  console.error('commandsModule::getTotalLesionGlycolysis:No referencedVolumeId found');
1925
1947
  }
1926
- const ptVolume = dist_esm.cache.getVolume(referencedVolumeId);
1948
+ const ptVolume = esm.cache.getVolume(referencedVolumeId);
1927
1949
  const mergedLabelData = mergedLabelmap.getScalarData();
1928
1950
  if (mergedLabelData.length !== ptVolume.getScalarData().length) {
1929
1951
  console.error('commandsModule::getTotalLesionGlycolysis:Labelmap and ptVolume are not the same size');
@@ -1954,7 +1976,7 @@ const commandsModule = ({
1954
1976
  } = viewport.getCamera();
1955
1977
  const selectedAnnotationUIDs = _getAnnotationsSelectedByToolNames(RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS);
1956
1978
  const annotationUID = selectedAnnotationUIDs[0];
1957
- const annotation = esm.annotation.state.getAnnotation(annotationUID);
1979
+ const annotation = dist_esm.annotation.state.getAnnotation(annotationUID);
1958
1980
  const {
1959
1981
  handles
1960
1982
  } = annotation.data;
@@ -1990,7 +2012,7 @@ const commandsModule = ({
1990
2012
  } = _getActiveViewportsEnabledElement();
1991
2013
  const selectedAnnotationUIDs = _getAnnotationsSelectedByToolNames(RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS);
1992
2014
  const annotationUID = selectedAnnotationUIDs[0];
1993
- const annotation = esm.annotation.state.getAnnotation(annotationUID);
2015
+ const annotation = dist_esm.annotation.state.getAnnotation(annotationUID);
1994
2016
 
1995
2017
  // get the current slice Index
1996
2018
  const sliceIndex = viewport.getCurrentImageIdIndex();
@@ -2003,7 +2025,7 @@ const commandsModule = ({
2003
2025
  },
2004
2026
  createTMTVRTReport: () => {
2005
2027
  // get all Rectangle ROI annotation
2006
- const stateManager = esm.annotation.state.getAnnotationManager();
2028
+ const stateManager = dist_esm.annotation.state.getAnnotationManager();
2007
2029
  const annotations = [];
2008
2030
  Object.keys(stateManager.annotations).forEach(frameOfReferenceUID => {
2009
2031
  const forAnnotations = stateManager.annotations[frameOfReferenceUID];
@@ -2177,7 +2199,7 @@ const commandsModule = ({
2177
2199
 
2178
2200
  const ROI_STAT = 'roi_stat';
2179
2201
  const RANGE = 'range';
2180
- const options = [{
2202
+ const ROIThresholdConfiguration_options = [{
2181
2203
  value: ROI_STAT,
2182
2204
  label: 'Max',
2183
2205
  placeHolder: 'Max'
@@ -2204,8 +2226,8 @@ function ROIThresholdConfiguration({
2204
2226
  label: t('Strategy'),
2205
2227
  closeMenuOnSelect: true,
2206
2228
  className: "border-primary-main mr-2 bg-black text-white ",
2207
- options: options,
2208
- placeholder: options.find(option => option.value === config.strategy).placeHolder,
2229
+ options: ROIThresholdConfiguration_options,
2230
+ placeholder: ROIThresholdConfiguration_options.find(option => option.value === config.strategy).placeHolder,
2209
2231
  value: config.strategy,
2210
2232
  onChange: ({
2211
2233
  value
@@ -2402,63 +2424,15 @@ function RectangleROIOptions({
2402
2424
  });
2403
2425
  const handleROIThresholding = (0,react.useCallback)(() => {
2404
2426
  const segmentationId = selectedSegmentationId;
2405
- const segmentation = segmentationService.getSegmentation(segmentationId);
2406
- const activeSegmentIndex = esm.segmentation.segmentIndex.getActiveSegmentIndex(segmentationId);
2427
+ const activeSegmentIndex = dist_esm.segmentation.segmentIndex.getActiveSegmentIndex(segmentationId);
2407
2428
 
2408
2429
  // run the threshold based on the active segment index
2409
2430
  // Todo: later find a way to associate each rectangle with a segment (e.g., maybe with color?)
2410
- const labelmap = runCommand('thresholdSegmentationByRectangleROITool', {
2431
+ runCommand('thresholdSegmentationByRectangleROITool', {
2411
2432
  segmentationId,
2412
2433
  config,
2413
2434
  segmentIndex: activeSegmentIndex
2414
2435
  });
2415
-
2416
- // re-calculating the cached stats for the active segmentation
2417
- const updatedPerSegmentCachedStats = {};
2418
- segmentation.segments = segmentation.segments.map(segment => {
2419
- if (!segment || !segment.segmentIndex) {
2420
- return segment;
2421
- }
2422
- const segmentIndex = segment.segmentIndex;
2423
- const lesionStats = runCommand('getLesionStats', {
2424
- labelmap,
2425
- segmentIndex
2426
- });
2427
- const suvPeak = runCommand('calculateSuvPeak', {
2428
- labelmap,
2429
- segmentIndex
2430
- });
2431
- const lesionGlyoclysisStats = lesionStats.volume * lesionStats.meanValue;
2432
-
2433
- // update segDetails with the suv peak for the active segmentation
2434
- const cachedStats = {
2435
- lesionStats,
2436
- suvPeak,
2437
- lesionGlyoclysisStats
2438
- };
2439
- segment.cachedStats = cachedStats;
2440
- segment.displayText = [`SUV Peak: ${suvPeak.suvPeak.toFixed(2)}`, `Volume: ${lesionStats.volume.toFixed(2)} mm3`];
2441
- updatedPerSegmentCachedStats[segmentIndex] = cachedStats;
2442
- return segment;
2443
- });
2444
- const notYetUpdatedAtSource = true;
2445
- const segmentations = segmentationService.getSegmentations();
2446
- const tmtv = runCommand('calculateTMTV', {
2447
- segmentations
2448
- });
2449
- segmentation.cachedStats = Object.assign(segmentation.cachedStats, updatedPerSegmentCachedStats, {
2450
- tmtv: {
2451
- value: tmtv.toFixed(3),
2452
- config: {
2453
- ...config
2454
- }
2455
- }
2456
- });
2457
- segmentationService.addOrUpdateSegmentation({
2458
- ...segmentation
2459
- }, false,
2460
- // don't suppress events
2461
- notYetUpdatedAtSource);
2462
2436
  }, [selectedSegmentationId, config]);
2463
2437
  (0,react.useEffect)(() => {
2464
2438
  const segmentations = segmentationService.getSegmentations();
@@ -2496,23 +2470,6 @@ function RectangleROIOptions({
2496
2470
  });
2497
2471
  };
2498
2472
  }, []);
2499
- (0,react.useEffect)(() => {
2500
- const {
2501
- unsubscribe
2502
- } = segmentationService.subscribe(segmentationService.EVENTS.SEGMENTATION_REMOVED, () => {
2503
- const segmentations = segmentationService.getSegmentations();
2504
- if (segmentations.length > 0) {
2505
- setSelectedSegmentationId(segmentations[0].id);
2506
- handleROIThresholding();
2507
- } else {
2508
- setSelectedSegmentationId(null);
2509
- handleROIThresholding();
2510
- }
2511
- });
2512
- return () => {
2513
- unsubscribe();
2514
- };
2515
- }, []);
2516
2473
  return /*#__PURE__*/react.createElement("div", {
2517
2474
  className: "invisible-scrollbar mb-2 flex flex-col overflow-y-auto overflow-x-hidden"
2518
2475
  }, /*#__PURE__*/react.createElement(PanelROIThresholdSegmentation_ROIThresholdConfiguration, {
@@ -22,8 +22,8 @@ __webpack_require__.d(enums_namespaceObject, {
22
22
  s: () => (enums_Events)
23
23
  });
24
24
 
25
- // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 328 modules
26
- var esm = __webpack_require__(73868);
25
+ // EXTERNAL MODULE: ../../../node_modules/@cornerstonejs/core/dist/esm/index.js + 28 modules
26
+ var esm = __webpack_require__(92136);
27
27
  // EXTERNAL MODULE: ../../../node_modules/gl-matrix/esm/index.js + 1 modules
28
28
  var gl_matrix_esm = __webpack_require__(44753);
29
29
  ;// CONCATENATED MODULE: ../../../node_modules/@cornerstonejs/streaming-image-volume-loader/dist/esm/helpers/getVolumeInfo.js