@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.
- package/dist/117.bundle.a5e6959bf225da5cf4ed.js +6552 -0
- package/dist/164.bundle.96c0518b435ea19ef8c4.js +11816 -0
- package/dist/{433.bundle.c92d3f716a797127c1be.js → 203.bundle.846a90d1ede185c941b0.js} +4765 -6951
- package/dist/{206.bundle.1203a96e327b365264e5.js → 206.bundle.98ed38d4cc3cd491592d.js} +4 -4
- package/dist/{183.bundle.c88c4355c4829ed94a88.js → 236.bundle.fb6c65ae3a5aa0c58727.js} +17541 -23678
- package/dist/{321.bundle.5bd98d3324768715f634.js → 321.bundle.df33483c22991d82b0d3.js} +45 -43
- package/dist/{342.bundle.8c74ac4c7871bd4a6f60.js → 342.bundle.36ee082163b01284eeba.js} +1 -1
- package/dist/{41.bundle.45737afb9f85e7e69ff3.js → 41.bundle.b087dd5f5575fef9f4d7.js} +2 -2
- package/dist/{217.bundle.bbc6090836dcca555dfc.js → 416.bundle.837e0b84baddd2193d67.js} +61564 -70419
- package/dist/{448.bundle.fde8b8e0fd744f39389d.js → 448.bundle.e2db79f9db64f2211caf.js} +2 -2
- package/dist/473.bundle.f6804e7ac014a561eff8.js +7256 -0
- package/dist/483.bundle.9263b25c34b349aae80e.js +2287 -0
- package/dist/{487.bundle.8d0477af42cf9f8c0937.js → 487.bundle.6c4b3c9abadeab2ec397.js} +7 -7
- package/dist/{544.bundle.80c013bb477a263bcf10.js → 544.bundle.1b6998bb61d6f8f88da9.js} +2 -2
- package/dist/{574.bundle.9919f94ea252d4a45aaf.js → 574.bundle.d6f15a036af7ecaf82f9.js} +4 -4
- package/dist/{633.bundle.3961c49efec0b913b9cc.js → 633.bundle.409655439a8a864c3a0a.js} +4 -4
- package/dist/{669.bundle.5652fa450c1d63575a5a.js → 669.bundle.b28fafccfe244c340713.js} +9 -9
- package/dist/{335.bundle.fab6af469f98e7a59bfa.js → 7.bundle.d9bef0f76f54df3ed3d0.js} +185 -228
- package/dist/{722.bundle.a91ce7b563b901b25db0.js → 722.bundle.05e8759e64d484f4554d.js} +2 -2
- package/dist/{724.bundle.634bee9667a518d1202f.js → 724.bundle.236e5bb2a2c4e0e436b9.js} +234 -7
- package/dist/{726.bundle.0b3d9277d22fe7e15b89.js → 726.bundle.c8de818cf1a3ff0cf7d2.js} +2 -2
- package/dist/{164.bundle.288b10692cc72b81a98d.js → 783.bundle.2266dca43e7b065e00e2.js} +1 -1
- package/dist/{835.bundle.15aff0b7433bb0dd6d6d.js → 835.bundle.4c0eaa2c1a427ee41817.js} +2 -2
- package/dist/{862.bundle.217ce894d955626c78c5.js → 862.bundle.4be5d148c2b1adf4dbf3.js} +2 -2
- package/dist/{889.bundle.e2700d7456565ce71dad.js → 889.bundle.3e25455cd8ed5cff6736.js} +1 -1
- package/dist/{94.bundle.b35c818d871de99336d8.js → 94.bundle.84aeabf47a50226a3757.js} +4 -4
- package/dist/{app.bundle.ce0e385dbbb6c1c1769f.js → app.bundle.4d1d6a9e1f5ddf2ecc89.js} +44487 -42404
- package/dist/cornerstoneDICOMImageLoader.min.js +1 -1
- package/dist/cornerstoneDICOMImageLoader.min.js.map +1 -1
- package/dist/index.html +1 -1
- package/dist/{polySeg.bundle.c2653f8ce77f44ae095b.js → polySeg.bundle.43bf3490e07982491e2b.js} +3 -3
- package/dist/suv-peak-worker.bundle.1f9b9e6887eebc07c50a.js +404 -0
- package/dist/sw.js +1 -1
- package/package.json +18 -18
- /package/dist/{188.bundle.d9b13c4a2910858bca9b.js → 188.bundle.a3f7d32b447d383dc882.js} +0 -0
- /package/dist/{325.bundle.ac07a6ca0a4e66bed604.js → 325.bundle.88b9768fe4c3f8b4c479.js} +0 -0
- /package/dist/{594.bundle.e8e1b20c5c46cf16ffa3.js → 594.bundle.dd4e77925f097e4715a5.js} +0 -0
- /package/dist/{699.bundle.7228b225e0c2b8100077.js → 699.bundle.fa08705eb3ffb41fc6d4.js} +0 -0
- /package/dist/{905.bundle.ec6275a2096f7f096618.js → 905.bundle.fddef85afd237a0e41e8.js} +0 -0
- /package/dist/{907.bundle.d2823642d3a32b5209a2.js → 907.bundle.245684385d33246c88a7.js} +0 -0
- /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([[
|
|
2
|
+
(globalThis["webpackChunk"] = globalThis["webpackChunk"] || []).push([[7],{
|
|
3
3
|
|
|
4
|
-
/***/
|
|
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
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
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: '
|
|
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
|
|
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 =
|
|
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,
|
|
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 =
|
|
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 =>
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
} =
|
|
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 =
|
|
1742
|
-
let referencedVolume =
|
|
1743
|
-
const ctReferencedVolume =
|
|
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 =
|
|
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 =
|
|
1774
|
-
if (
|
|
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
|
|
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 =
|
|
1806
|
+
const referencedVolume = esm.cache.getVolume(referencedVolumeId);
|
|
1806
1807
|
const annotationUIDs = _getAnnotationsSelectedByToolNames(RECTANGLE_ROI_THRESHOLD_MANUAL_TOOL_IDS);
|
|
1807
|
-
const annotations = annotationUIDs.map(annotationUID =>
|
|
1808
|
-
const
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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:
|
|
2208
|
-
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
|
|
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
|
-
|
|
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 +
|
|
26
|
-
var esm = __webpack_require__(
|
|
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
|