@ohif/app 3.13.0-beta.119 → 3.13.0-beta.120

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 (39) hide show
  1. package/dist/{1483.bundle.e208a19dd0ff9a11.js → 1483.bundle.5e93c978bd32d7de.js} +1 -1
  2. package/dist/{2343.bundle.e50c08b2df863e1a.js → 2343.bundle.3445fda02a002697.js} +12 -8
  3. package/dist/{2036.bundle.1b6c0d890aa6bf4e.js → 2493.bundle.f3b6a64d158365da.js} +113 -35
  4. package/dist/{3215.bundle.1fca83719c1b786b.js → 3330.bundle.b1297ef8c94e5440.js} +796 -180
  5. package/dist/{2690.bundle.f5dc28ac498de122.js → 3568.bundle.45dc681ef6890166.js} +2112 -76
  6. package/dist/{6495.bundle.84b83aa091c338cd.js → 6495.bundle.a6764fdb8c0c252f.js} +846 -219
  7. package/dist/{8668.bundle.93c88419e37dc076.js → 8668.bundle.0e47f7231aa07da2.js} +227 -3
  8. package/dist/{9402.bundle.0dd1b538f0708077.js → 9402.bundle.928437e2e48c12dd.js} +2 -2
  9. package/dist/{9560.bundle.bb39f946ea79cf0e.js → 9560.bundle.517f0ef7ee3a20bf.js} +159 -196
  10. package/dist/{app.bundle.bdeb02edea129b2c.js → app.bundle.81a823d1149be346.js} +99 -25
  11. package/dist/{compute.bundle.77e80c1775429bd6.js → compute.bundle.9cc3697d07fbb082.js} +3 -3
  12. package/dist/index.html +1 -1
  13. package/dist/{polySeg.bundle.5e350e0723aa59b6.js → polySeg.bundle.a526954fc2fed311.js} +3 -3
  14. package/dist/sw.js +1 -1
  15. package/package.json +6 -6
  16. /package/dist/{100.bundle.bd6735a86c215595.js → 100.bundle.84a35e9d087b403c.js} +0 -0
  17. /package/dist/{1180.bundle.4c5146471b4d3497.js → 1180.bundle.7f790d9fd6fb031c.js} +0 -0
  18. /package/dist/{1602.bundle.163e3da3a27b860c.js → 1602.bundle.254a392a6b5d2b85.js} +0 -0
  19. /package/dist/{2779.bundle.664d9d0a704f7b94.js → 2779.bundle.c879d6af5dc0c274.js} +0 -0
  20. /package/dist/{3500.bundle.18412afd9ee5d6a7.js → 3500.bundle.d4aaab15c4461cc4.js} +0 -0
  21. /package/dist/{3760.bundle.f69046888fc2b881.js → 3760.bundle.c95abd6ab662bd3b.js} +0 -0
  22. /package/dist/{4556.bundle.128d2abaea69dce3.js → 4556.bundle.c3ac23e680d677b2.js} +0 -0
  23. /package/dist/{4683.bundle.b02523a9d66f4d19.js → 4683.bundle.ed3f14fcb89fbad1.js} +0 -0
  24. /package/dist/{5189.bundle.2a0f740738759e32.js → 5189.bundle.ea191ea99047fd6f.js} +0 -0
  25. /package/dist/{5642.bundle.1622d255af1102d8.js → 5642.bundle.98e17a4413db6ef1.js} +0 -0
  26. /package/dist/{5696.bundle.2f47cb5ab5a7f983.js → 5696.bundle.e77041f7e2b08236.js} +0 -0
  27. /package/dist/{6749.bundle.9f0550714a4d5f8b.js → 6749.bundle.9dcda33e49485da4.js} +0 -0
  28. /package/dist/{7231.bundle.46f843b74a964f89.js → 7231.bundle.1063d727ad99108a.js} +0 -0
  29. /package/dist/{7248.bundle.bffd4e60f806e25d.js → 7248.bundle.ab6f276adad059da.js} +0 -0
  30. /package/dist/{7499.bundle.bb240e8754167cb2.js → 7499.bundle.832916b9b820c33f.js} +0 -0
  31. /package/dist/{781.bundle.f7411dabe0628911.js → 781.bundle.f06b6ab92ef4d695.js} +0 -0
  32. /package/dist/{8423.bundle.071901427fd3cd9e.js → 8423.bundle.ebf8d7d638d9616b.js} +0 -0
  33. /package/dist/{8492.bundle.9c17dcbab24b07c3.js → 8492.bundle.1ceeb18471c1c06b.js} +0 -0
  34. /package/dist/{8832.bundle.e413f00216682f40.js → 8832.bundle.1eb46bfa451c792f.js} +0 -0
  35. /package/dist/{9116.bundle.1cb5c393e3a152cd.js → 9116.bundle.1d0c6c18a4db51cc.js} +0 -0
  36. /package/dist/{9290.bundle.77a274271ce884a3.js → 9290.bundle.82e8dfc0f73c41bb.js} +0 -0
  37. /package/dist/{9383.bundle.9b1d03c71cc52f4f.js → 9383.bundle.ec44c452ccc23e93.js} +0 -0
  38. /package/dist/{9415.bundle.d3532cc872787744.js → 9415.bundle.69d74a2b03d5d6e4.js} +0 -0
  39. /package/dist/{9437.bundle.a18085ed31658c82.js → 9437.bundle.ca5db89624e35827.js} +0 -0
@@ -4986,6 +4986,7 @@ __webpack_require__.d(__webpack_exports__, {
4986
4986
  CircleROIStartEndThresholdTool: () => (/* reexport safe */ _tools_index_js__rspack_import_13.pq),
4987
4987
  CircleROITool: () => (/* reexport safe */ _tools_index_js__rspack_import_13.Vl),
4988
4988
  CircleScissorsTool: () => (/* reexport safe */ _tools_index_js__rspack_import_13.G2),
4989
+ ClickSegmentTool: () => (/* reexport safe */ _tools_index_js__rspack_import_13.Yk),
4989
4990
  CobbAngleTool: () => (/* reexport safe */ _tools_index_js__rspack_import_13.EV),
4990
4991
  CrosshairsTool: () => (/* reexport safe */ _tools_index_js__rspack_import_13.ep),
4991
4992
  DragProbeTool: () => (/* reexport safe */ _tools_index_js__rspack_import_13.j$),
@@ -5059,7 +5060,7 @@ __webpack_require__.d(__webpack_exports__, {
5059
5060
  store: () => (/* reexport module object */ _store_index_js__rspack_import_1),
5060
5061
  synchronizers: () => (/* reexport module object */ _synchronizers_index_js__rspack_import_5),
5061
5062
  utilities: () => (/* reexport module object */ _utilities_index_js__rspack_import_7),
5062
- version: () => (/* reexport safe */ (/* inlined export _version_js__rspack_import_4 */"5.4.12"))
5063
+ version: () => (/* reexport safe */ (/* inlined export _version_js__rspack_import_4 */"5.4.13"))
5063
5064
  });
5064
5065
  /* import */ var _init_js__rspack_import_0 = __webpack_require__(70210);
5065
5066
  /* import */ var _store_index_js__rspack_import_1 = __webpack_require__(37872);
@@ -8065,182 +8066,6 @@ __webpack_require__.d(__webpack_exports__, {
8065
8066
 
8066
8067
 
8067
8068
 
8068
- },
8069
- 88392(__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
8070
- __webpack_require__.d(__webpack_exports__, {
8071
- $n: () => (removeLabelmap),
8072
- AD: () => (registerLabelmap),
8073
- BS: () => (getLabelmapForVolumeId),
8074
- Hs: () => (getLabelmap),
8075
- M4: () => (getLabelmapForImageId),
8076
- kL: () => (getOrCreateLabelmapVolume),
8077
- m: () => (getLabelmaps)
8078
- });
8079
- /* import */ var _cornerstonejs_core__rspack_import_0 = __webpack_require__(88479);
8080
- /* import */ var _normalizeLabelmapSegmentationData_js__rspack_import_1 = __webpack_require__(209);
8081
- /* import */ var _labelmapImageIdMapping_js__rspack_import_2 = __webpack_require__(26372);
8082
-
8083
-
8084
-
8085
- function getLabelmap(segmentation, labelmapId) {
8086
- return (0,_normalizeLabelmapSegmentationData_js__rspack_import_1/* .ensureLabelmapState */.uk)(segmentation)?.labelmaps?.[labelmapId];
8087
- }
8088
- function getLabelmaps(segmentation) {
8089
- const labelmapState = (0,_normalizeLabelmapSegmentationData_js__rspack_import_1/* .ensureLabelmapState */.uk)(segmentation);
8090
- if (!labelmapState) {
8091
- return [];
8092
- }
8093
- return Object.values(labelmapState.labelmaps);
8094
- }
8095
- function registerLabelmap(segmentation, layer) {
8096
- const labelmapState = (0,_normalizeLabelmapSegmentationData_js__rspack_import_1/* .ensureLabelmapState */.uk)(segmentation);
8097
- if (!labelmapState) {
8098
- return;
8099
- }
8100
- labelmapState.labelmaps[layer.labelmapId] = layer;
8101
- }
8102
- function removeLabelmap(segmentation, labelmapId) {
8103
- const labelmapState = (0,_normalizeLabelmapSegmentationData_js__rspack_import_1/* .ensureLabelmapState */.uk)(segmentation);
8104
- if (!labelmapState) {
8105
- return;
8106
- }
8107
- const layer = labelmapState.labelmaps[labelmapId];
8108
- if (layer?.geometryVolumeId && _cornerstonejs_core__rspack_import_0.cache.getVolume(layer.geometryVolumeId)) {
8109
- _cornerstonejs_core__rspack_import_0.cache.removeVolumeLoadObject(layer.geometryVolumeId);
8110
- }
8111
- delete labelmapState.labelmaps[labelmapId];
8112
- }
8113
- function getOrCreateLabelmapVolume(layer) {
8114
- const mergedVolume = getOrCreateMergedStackLabelmapVolume(layer);
8115
- if (mergedVolume) {
8116
- return mergedVolume;
8117
- }
8118
- const existingVolumeId = layer.volumeId ?? layer.geometryVolumeId;
8119
- if (existingVolumeId) {
8120
- const cachedVolume = _cornerstonejs_core__rspack_import_0.cache.getVolume(existingVolumeId);
8121
- if (cachedVolume) {
8122
- return cachedVolume;
8123
- }
8124
- }
8125
- const imageIds = layer.imageIds ?? [];
8126
- if (!imageIds.length) {
8127
- return;
8128
- }
8129
- const volumeId = layer.volumeId ?? layer.geometryVolumeId ?? `${layer.labelmapId}-geometry`;
8130
- if (!layer.volumeId) {
8131
- layer.geometryVolumeId = volumeId;
8132
- }
8133
- const cachedVolume = _cornerstonejs_core__rspack_import_0.cache.getVolume(volumeId);
8134
- if (cachedVolume) {
8135
- return cachedVolume;
8136
- }
8137
- return _cornerstonejs_core__rspack_import_0.volumeLoader.createAndCacheVolumeFromImagesSync(volumeId, imageIds);
8138
- }
8139
- function getOrCreateMergedStackLabelmapVolume(layer) {
8140
- if (layer.volumeId || !hasDuplicateReferencedImageIds(layer)) {
8141
- return;
8142
- }
8143
- const volumeId = layer.geometryVolumeId ?? `${layer.labelmapId}-geometry`;
8144
- const cachedVolume = _cornerstonejs_core__rspack_import_0.cache.getVolume(volumeId);
8145
- if (cachedVolume) {
8146
- return cachedVolume;
8147
- }
8148
- const imageIdsByReferencedImageId = new Map();
8149
- (0,_labelmapImageIdMapping_js__rspack_import_2/* .forEachLabelmapImageReference */.Zd)(layer, (referencedImageId, imageId) => {
8150
- const imageIdsForReference = imageIdsByReferencedImageId.get(referencedImageId) ?? [];
8151
- imageIdsForReference.push(imageId);
8152
- imageIdsByReferencedImageId.set(referencedImageId, imageIdsForReference);
8153
- });
8154
- const mergedReferencedImageIds = Array.from(imageIdsByReferencedImageId.keys());
8155
- if (!mergedReferencedImageIds.length) {
8156
- return;
8157
- }
8158
- let mergedImageIndex = 0;
8159
- const mergedImages = _cornerstonejs_core__rspack_import_0.imageLoader.createAndCacheDerivedImages(mergedReferencedImageIds, {
8160
- getDerivedImageId: () => `${volumeId}-image-${mergedImageIndex++}`,
8161
- targetBuffer: { type: 'Uint8Array' },
8162
- });
8163
- mergedImages.forEach((mergedImage) => {
8164
- const sourceImageIds = imageIdsByReferencedImageId.get(mergedImage.referencedImageId);
8165
- if (!sourceImageIds?.length) {
8166
- return;
8167
- }
8168
- const targetVoxelManager = mergedImage.voxelManager;
8169
- const scalarDataLength = targetVoxelManager.getScalarDataLength();
8170
- sourceImageIds.forEach((sourceImageId) => {
8171
- const sourceImage = _cornerstonejs_core__rspack_import_0.cache.getImage(sourceImageId);
8172
- const sourceVoxelManager = sourceImage?.voxelManager;
8173
- if (!sourceVoxelManager) {
8174
- return;
8175
- }
8176
- const sourceScalarDataLength = sourceVoxelManager.getScalarDataLength();
8177
- const length = Math.min(scalarDataLength, sourceScalarDataLength);
8178
- for (let index = 0; index < length; index++) {
8179
- const value = Number(sourceVoxelManager.getAtIndex(index));
8180
- if (value !== 0) {
8181
- targetVoxelManager.setAtIndex(index, value);
8182
- }
8183
- }
8184
- });
8185
- });
8186
- layer.geometryVolumeId = volumeId;
8187
- return _cornerstonejs_core__rspack_import_0.volumeLoader.createAndCacheVolumeFromImagesSync(volumeId, mergedImages.map((image) => image.imageId));
8188
- }
8189
- function hasDuplicateReferencedImageIds(layer) {
8190
- return (0,_labelmapImageIdMapping_js__rspack_import_2/* .hasMultipleLabelmapImagesPerReferencedImageId */.dm)(layer);
8191
- }
8192
- function getLabelmapIds(segmentation) {
8193
- return getLabelmaps(segmentation).map((layer) => layer.labelmapId);
8194
- }
8195
- function getLabelmapDataById(segmentation, labelmapId) {
8196
- const labelmapState = ensureLabelmapState(segmentation);
8197
- const layer = labelmapState?.labelmaps?.[labelmapId];
8198
- if (!labelmapState || !layer) {
8199
- return;
8200
- }
8201
- return {
8202
- volumeId: layer.volumeId,
8203
- referencedVolumeId: layer.referencedVolumeId,
8204
- imageIds: layer.imageIds,
8205
- referencedImageIds: layer.referencedImageIds,
8206
- sourceRepresentationName: labelmapState.sourceRepresentationName,
8207
- primaryLabelmapId: labelmapId,
8208
- labelmaps: {
8209
- [labelmapId]: layer,
8210
- },
8211
- segmentBindings: Object.fromEntries(Object.entries(labelmapState.segmentBindings).filter(([, binding]) => binding.labelmapId === labelmapId)),
8212
- };
8213
- }
8214
- function getScalarArrayLengthFromLabelmap(layer) {
8215
- if (layer.volumeId) {
8216
- return cache.getVolume(layer.volumeId)?.voxelManager?.getScalarDataLength();
8217
- }
8218
- const firstImageId = layer.imageIds?.[0];
8219
- const firstImage = firstImageId ? cache.getImage(firstImageId) : null;
8220
- if (!firstImage || !layer.imageIds?.length) {
8221
- return 0;
8222
- }
8223
- return firstImage.voxelManager.getScalarDataLength() * layer.imageIds.length;
8224
- }
8225
- function getConstructorNameForLabelmap(layer) {
8226
- if (layer.volumeId) {
8227
- return cache.getVolume(layer.volumeId)?.voxelManager?.getConstructor()
8228
- ?.name;
8229
- }
8230
- const imageId = layer.imageIds?.[0];
8231
- return imageId
8232
- ? cache.getImage(imageId)?.voxelManager?.getConstructor()?.name
8233
- : undefined;
8234
- }
8235
- function getLabelmapForImageId(segmentation, imageId) {
8236
- return getLabelmaps(segmentation).find((layer) => layer.imageIds?.includes(imageId));
8237
- }
8238
- function getLabelmapForVolumeId(segmentation, volumeId) {
8239
- return getLabelmaps(segmentation).find((layer) => layer.volumeId === volumeId || layer.geometryVolumeId === volumeId);
8240
- }
8241
-
8242
-
8243
-
8244
8069
  },
8245
8070
  59371(__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
8246
8071
  __webpack_require__.d(__webpack_exports__, {
@@ -22262,6 +22087,771 @@ function defaultGetTextLines(data, targetId) {
22262
22087
  /* export default */ const __rspack_default_export = (CircleROITool);
22263
22088
 
22264
22089
 
22090
+ },
22091
+ 62843(__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
22092
+ __webpack_require__.d(__webpack_exports__, {
22093
+ A: () => (__rspack_default_export)
22094
+ });
22095
+ /* import */ var _cornerstonejs_core__rspack_import_0 = __webpack_require__(88479);
22096
+ /* import */ var _base_GrowCutBaseTool_js__rspack_import_1 = __webpack_require__(47844);
22097
+ /* import */ var _utilities_segmentation_growCut_runFloodFillSegmentation_js__rspack_import_2 = __webpack_require__(55600);
22098
+ /* import */ var _utilities_segmentation_floodFillSliceLazy_js__rspack_import_3 = __webpack_require__(10621);
22099
+ /* import */ var _utilities_segmentation_growCut_intensityRange_adaptiveRegionIntensityRange_js__rspack_import_4 = __webpack_require__(81537);
22100
+ /* import */ var _utilities_segmentation_growCut_getViewportVoiMappingForVolume_js__rspack_import_5 = __webpack_require__(1967);
22101
+ /* import */ var _stateManagement_segmentation_index_js__rspack_import_6 = __webpack_require__(48735);
22102
+ /* import */ var _stateManagement_segmentation_triggerSegmentationEvents_js__rspack_import_7 = __webpack_require__(49256);
22103
+ /* import */ var _utilities_segmentation_createLabelmapMemo_js__rspack_import_8 = __webpack_require__(1732);
22104
+ /* import */ var _regionSegmentHoverCursors_js__rspack_import_9 = __webpack_require__(58690);
22105
+ /* import */ var _enums_index_js__rspack_import_10 = __webpack_require__(53870);
22106
+
22107
+
22108
+
22109
+
22110
+
22111
+
22112
+
22113
+
22114
+
22115
+
22116
+
22117
+ const { growCutLog } = _cornerstonejs_core__rspack_import_0.utilities.logger;
22118
+ const HOVER_PROBE_THROTTLE_MS = 100;
22119
+ const PROBE_REUSE_DISTANCE_PX = 6;
22120
+ const PROBE_FRESH_MS = 1500;
22121
+ const EXPAND_STEP_FACTOR = 1.15;
22122
+ const SHRINK_STEP_FACTOR = 0.85;
22123
+ const MIN_COMPACTNESS = 0.08;
22124
+ const COMPACTNESS_CHECK_MIN_VOLUME_MM3 = 2000;
22125
+ const COMPUTE_BUDGET_MM3 = 2_000_000;
22126
+ const NOT_LESION_MESSAGE = 'The region here does not form a self-contained, lesion-like shape; nothing was segmented.';
22127
+ const DRY_RUN_YIELD_EVERY = 10_000;
22128
+ const CONSENSUS_MIN_NEIGHBOR_VOTES = 2;
22129
+ const VERDICT_CACHE_TTL_MS = 2500;
22130
+ const MAX_REJECTED_REGIONS = 8;
22131
+ class ClickSegmentTool extends _base_GrowCutBaseTool_js__rspack_import_1/* ["default"] */.A {
22132
+ constructor(toolProps = {}, defaultToolProps = {
22133
+ supportedInteractionTypes: ['Mouse', 'Touch'],
22134
+ configuration: {
22135
+ maxDeltaK: 25,
22136
+ maxDeltaIJ: 512,
22137
+ actions: {
22138
+ cancelInProgress: {
22139
+ method: 'cancelInProgress',
22140
+ bindings: [
22141
+ {
22142
+ key: 'Escape',
22143
+ },
22144
+ ],
22145
+ },
22146
+ },
22147
+ },
22148
+ }) {
22149
+ super(toolProps, defaultToolProps);
22150
+ this.segmentationInProgress = false;
22151
+ this.hoverThrottleTimer = null;
22152
+ this.pendingHoverEvent = null;
22153
+ this.lastHoverElement = null;
22154
+ this.lastProbe = null;
22155
+ this.lastClick = null;
22156
+ this.clickAbortController = null;
22157
+ this.dryRunToken = null;
22158
+ this.confirmedRegion = null;
22159
+ this.rejectedRegions = [];
22160
+ }
22161
+ notifySegmentationError(message) {
22162
+ const event = new CustomEvent(_cornerstonejs_core__rspack_import_0.Enums.Events.ERROR_EVENT, {
22163
+ detail: {
22164
+ type: 'Segmentation',
22165
+ message,
22166
+ },
22167
+ cancelable: true,
22168
+ });
22169
+ _cornerstonejs_core__rspack_import_0.eventTarget.dispatchEvent(event);
22170
+ }
22171
+ cancelInProgress() {
22172
+ return this.cancelActiveOperation();
22173
+ }
22174
+ cancelActiveOperation() {
22175
+ if (!this.clickAbortController ||
22176
+ this.clickAbortController.signal.aborted) {
22177
+ return false;
22178
+ }
22179
+ this.clickAbortController.abort();
22180
+ return true;
22181
+ }
22182
+ clearHoverState() {
22183
+ if (this.hoverThrottleTimer !== null) {
22184
+ window.clearTimeout(this.hoverThrottleTimer);
22185
+ this.hoverThrottleTimer = null;
22186
+ }
22187
+ this.pendingHoverEvent = null;
22188
+ this.lastProbe = null;
22189
+ this.confirmedRegion = null;
22190
+ this.rejectedRegions = [];
22191
+ if (this.dryRunToken) {
22192
+ this.dryRunToken.cancelled = true;
22193
+ this.dryRunToken = null;
22194
+ }
22195
+ if (this.lastHoverElement) {
22196
+ this.lastHoverElement.style.cursor = '';
22197
+ this.lastHoverElement = null;
22198
+ }
22199
+ }
22200
+ pointerOnConfirmedRegion(refVolume, viewport, world) {
22201
+ const region = this.confirmedRegion;
22202
+ if (!region ||
22203
+ region.viewportId !== viewport.id ||
22204
+ Date.now() > region.expiresAt) {
22205
+ return false;
22206
+ }
22207
+ const ijk = _cornerstonejs_core__rspack_import_0.utilities.transformWorldToIndex(refVolume.imageData, world)
22208
+ .map(Math.round);
22209
+ for (let axis = 0; axis < 3; axis++) {
22210
+ if (ijk[axis] < region.bbox.min[axis] ||
22211
+ ijk[axis] > region.bbox.max[axis]) {
22212
+ return false;
22213
+ }
22214
+ }
22215
+ const [width, height] = refVolume.dimensions;
22216
+ const scalar = Number(refVolume.voxelManager.getAtIndex(ijk[2] * width * height + ijk[1] * width + ijk[0]));
22217
+ if (!Number.isFinite(scalar) ||
22218
+ scalar < region.bandMin ||
22219
+ scalar > region.bandMax) {
22220
+ return false;
22221
+ }
22222
+ region.expiresAt = Date.now() + VERDICT_CACHE_TTL_MS;
22223
+ return true;
22224
+ }
22225
+ static bandsAreSimilar(aMin, aMax, bMin, bMax) {
22226
+ const edgeMatches = (a, b) => {
22227
+ if (!Number.isFinite(a) || !Number.isFinite(b)) {
22228
+ return a === b;
22229
+ }
22230
+ const scale = Math.max(Math.abs(a), Math.abs(b), 1e-6);
22231
+ return Math.abs(a - b) <= 0.25 * scale;
22232
+ };
22233
+ return edgeMatches(aMin, bMin) && edgeMatches(aMax, bMax);
22234
+ }
22235
+ matchesRejectedRegion(viewportId, range) {
22236
+ const now = Date.now();
22237
+ this.rejectedRegions = this.rejectedRegions.filter((entry) => entry.expiresAt > now);
22238
+ const seed = range.ijkStart;
22239
+ const match = this.rejectedRegions.find((entry) => {
22240
+ if (entry.viewportId !== viewportId) {
22241
+ return false;
22242
+ }
22243
+ for (let axis = 0; axis < 3; axis++) {
22244
+ if (seed[axis] < entry.bbox.min[axis] ||
22245
+ seed[axis] > entry.bbox.max[axis]) {
22246
+ return false;
22247
+ }
22248
+ }
22249
+ return ClickSegmentTool.bandsAreSimilar(range.min, range.max, entry.bandMin, entry.bandMax);
22250
+ });
22251
+ if (match) {
22252
+ match.expiresAt = now + VERDICT_CACHE_TTL_MS;
22253
+ return true;
22254
+ }
22255
+ return false;
22256
+ }
22257
+ rememberRejectedRegion(viewportId, bbox, bandMin, bandMax) {
22258
+ if (!bbox) {
22259
+ return;
22260
+ }
22261
+ this.rejectedRegions.push({
22262
+ viewportId,
22263
+ bbox: {
22264
+ min: [...bbox.min],
22265
+ max: [...bbox.max],
22266
+ },
22267
+ bandMin,
22268
+ bandMax,
22269
+ expiresAt: Date.now() + VERDICT_CACHE_TTL_MS,
22270
+ });
22271
+ if (this.rejectedRegions.length > MAX_REJECTED_REGIONS) {
22272
+ this.rejectedRegions.splice(0, this.rejectedRegions.length - MAX_REJECTED_REGIONS);
22273
+ }
22274
+ }
22275
+ safeSpacing(volume) {
22276
+ const spacing = volume.spacing ?? [1, 1, 1];
22277
+ return [0, 1, 2].map((axis) => Number.isFinite(spacing[axis]) && spacing[axis] > 0 ? spacing[axis] : 1);
22278
+ }
22279
+ computeVoxelBudget(volume) {
22280
+ const [sx, sy, sz] = this.safeSpacing(volume);
22281
+ return Math.max(1000, Math.ceil(COMPUTE_BUDGET_MM3 / (sx * sy * sz)));
22282
+ }
22283
+ makeRegionShapeGate(volume) {
22284
+ const spacing = this.safeSpacing(volume);
22285
+ const voxelVolumeMm3 = spacing[0] * spacing[1] * spacing[2];
22286
+ const maxDeltaK = this.configuration.maxDeltaK;
22287
+ return ({ voxelCount, bbox }) => {
22288
+ if (typeof maxDeltaK === 'number' && maxDeltaK >= 0) {
22289
+ const kExtent = bbox.max[2] - bbox.min[2] + 1;
22290
+ if (kExtent >= 2 * maxDeltaK + 1) {
22291
+ return false;
22292
+ }
22293
+ }
22294
+ const volumeMm3 = voxelCount * voxelVolumeMm3;
22295
+ if (volumeMm3 < COMPACTNESS_CHECK_MIN_VOLUME_MM3) {
22296
+ return true;
22297
+ }
22298
+ let bboxMm3 = 1;
22299
+ for (let axis = 0; axis < 3; axis++) {
22300
+ bboxMm3 *= (bbox.max[axis] - bbox.min[axis] + 1) * spacing[axis];
22301
+ }
22302
+ return volumeMm3 / bboxMm3 >= MIN_COMPACTNESS;
22303
+ };
22304
+ }
22305
+ onSetToolPassive() {
22306
+ this.clearHoverState();
22307
+ }
22308
+ onSetToolDisabled() {
22309
+ this.clearHoverState();
22310
+ }
22311
+ buildProbeOptions(viewport, element, referencedVolumeId) {
22312
+ return {
22313
+ viewport,
22314
+ element,
22315
+ referencedVolumeId,
22316
+ voiMapping: (0,_utilities_segmentation_growCut_getViewportVoiMappingForVolume_js__rspack_import_5/* .getViewportVoiMappingForVolume */.K)(viewport, referencedVolumeId) ??
22317
+ undefined,
22318
+ };
22319
+ }
22320
+ mouseMoveCallback(evt) {
22321
+ if (this.mode !== _enums_index_js__rspack_import_10.ToolModes.Active) {
22322
+ return;
22323
+ }
22324
+ const { element } = evt.detail;
22325
+ this.lastHoverElement = element;
22326
+ if (this.segmentationInProgress) {
22327
+ element.style.cursor = 'wait';
22328
+ return;
22329
+ }
22330
+ this.queueHoverProbe(evt);
22331
+ }
22332
+ queueHoverProbe(evt) {
22333
+ this.pendingHoverEvent = evt;
22334
+ if (this.hoverThrottleTimer !== null) {
22335
+ return;
22336
+ }
22337
+ this.flushHoverProbe();
22338
+ }
22339
+ flushHoverProbe() {
22340
+ const evt = this.pendingHoverEvent;
22341
+ this.pendingHoverEvent = null;
22342
+ if (!evt) {
22343
+ return;
22344
+ }
22345
+ void this.runHoverProbe(evt);
22346
+ this.hoverThrottleTimer = window.setTimeout(() => {
22347
+ this.hoverThrottleTimer = null;
22348
+ if (this.pendingHoverEvent) {
22349
+ this.flushHoverProbe();
22350
+ }
22351
+ }, HOVER_PROBE_THROTTLE_MS);
22352
+ }
22353
+ getViewportSliceIndex(viewport) {
22354
+ const getSliceIndex = viewport.getSliceIndex;
22355
+ if (typeof getSliceIndex !== 'function') {
22356
+ return null;
22357
+ }
22358
+ try {
22359
+ const sliceIndex = getSliceIndex.call(viewport);
22360
+ return Number.isFinite(sliceIndex) ? sliceIndex : null;
22361
+ }
22362
+ catch {
22363
+ return null;
22364
+ }
22365
+ }
22366
+ async runHoverProbe(evt) {
22367
+ if (this.mode !== _enums_index_js__rspack_import_10.ToolModes.Active || this.segmentationInProgress) {
22368
+ return;
22369
+ }
22370
+ const { element, currentPoints } = evt.detail;
22371
+ const enabledElement = (0,_cornerstonejs_core__rspack_import_0.getEnabledElement)(element);
22372
+ const viewport = enabledElement?.viewport;
22373
+ if (!viewport) {
22374
+ return;
22375
+ }
22376
+ if (this.dryRunToken) {
22377
+ this.dryRunToken.cancelled = true;
22378
+ this.dryRunToken = null;
22379
+ }
22380
+ let state = 'unknown';
22381
+ let dryRunInput = null;
22382
+ try {
22383
+ if (_stateManagement_segmentation_index_js__rspack_import_6.activeSegmentation.getActiveSegmentation(viewport.id)) {
22384
+ const labelmapData = await this.getLabelmapSegmentationData(viewport);
22385
+ if (labelmapData) {
22386
+ const { referencedVolumeId } = labelmapData;
22387
+ if (!this._isOrthogonalView(viewport, referencedVolumeId)) {
22388
+ state = 'blocked';
22389
+ }
22390
+ else {
22391
+ const refVolume = _cornerstonejs_core__rspack_import_0.cache.getVolume(referencedVolumeId);
22392
+ if (refVolume) {
22393
+ if (this.pointerOnConfirmedRegion(refVolume, viewport, currentPoints.world)) {
22394
+ state = 'plus';
22395
+ }
22396
+ else {
22397
+ const options = this.buildProbeOptions(viewport, element, referencedVolumeId);
22398
+ const probe = (0,_utilities_segmentation_growCut_intensityRange_adaptiveRegionIntensityRange_js__rspack_import_4/* .probeAdaptiveRegion */.Ti)(refVolume, currentPoints.world, options);
22399
+ if (!probe.viable || !probe.range) {
22400
+ state = 'blocked';
22401
+ }
22402
+ else if (this.matchesRejectedRegion(viewport.id, probe.range)) {
22403
+ state = 'blocked';
22404
+ }
22405
+ else if (!this.neighborsAgree(probe)) {
22406
+ state = 'blocked';
22407
+ }
22408
+ else {
22409
+ state = 'pending';
22410
+ dryRunInput = { refVolume, range: probe.range };
22411
+ }
22412
+ }
22413
+ }
22414
+ }
22415
+ }
22416
+ }
22417
+ }
22418
+ catch (err) {
22419
+ growCutLog.debug('hover probe: could not evaluate', {
22420
+ message: err instanceof Error ? err.message : String(err),
22421
+ });
22422
+ state = 'unknown';
22423
+ }
22424
+ const verdict = state === 'unknown'
22425
+ ? null
22426
+ : {
22427
+ viewportId: viewport.id,
22428
+ canvas: [...currentPoints.canvas],
22429
+ sliceIndex: this.getViewportSliceIndex(viewport),
22430
+ ok: state !== 'blocked',
22431
+ at: Date.now(),
22432
+ };
22433
+ this.lastProbe = verdict;
22434
+ element.style.cursor =
22435
+ state === 'plus'
22436
+ ? _regionSegmentHoverCursors_js__rspack_import_9/* .PLUS_CURSOR */.ys
22437
+ : state === 'blocked'
22438
+ ? _regionSegmentHoverCursors_js__rspack_import_9/* .BLOCKED_CURSOR */.kC
22439
+ : _regionSegmentHoverCursors_js__rspack_import_9/* .PENDING_CURSOR */.t5;
22440
+ if (state === 'pending' && dryRunInput && verdict) {
22441
+ const token = { cancelled: false };
22442
+ this.dryRunToken = token;
22443
+ void this.runConfinementDryRun(dryRunInput.refVolume, dryRunInput.range, token, verdict, element);
22444
+ }
22445
+ }
22446
+ neighborsAgree(probe) {
22447
+ const joinLevels = probe.clickNeighborJoinLevels;
22448
+ const tolerance = probe.toleranceBytes;
22449
+ if (!joinLevels || typeof tolerance !== 'number') {
22450
+ return true;
22451
+ }
22452
+ let votes = 0;
22453
+ let evaluated = 0;
22454
+ for (const joinLevel of joinLevels) {
22455
+ if (joinLevel === null) {
22456
+ continue;
22457
+ }
22458
+ evaluated++;
22459
+ if (joinLevel >= 0 && joinLevel <= tolerance) {
22460
+ votes++;
22461
+ }
22462
+ }
22463
+ return evaluated < CONSENSUS_MIN_NEIGHBOR_VOTES
22464
+ ? votes === evaluated
22465
+ : votes >= CONSENSUS_MIN_NEIGHBOR_VOTES;
22466
+ }
22467
+ async runConfinementDryRun(refVolume, range, token, verdict, element) {
22468
+ const { dimensions } = refVolume;
22469
+ const [width, height, depth] = dimensions;
22470
+ const pixelsPerSlice = width * height;
22471
+ const voxelManager = refVolume.voxelManager;
22472
+ const { min, max } = range;
22473
+ const shapeGate = this.makeRegionShapeGate(refVolume);
22474
+ try {
22475
+ const { truncated, voxelCount, bbox } = await (0,_utilities_segmentation_floodFillSliceLazy_js__rspack_import_3/* .floodFill3dSliceLazy */.x)((x, y, z) => Number(voxelManager.getAtIndex(z * pixelsPerSlice + y * width + x)), [...range.ijkStart], {
22476
+ width,
22477
+ height,
22478
+ depth,
22479
+ equals: (val) => typeof val === 'number' &&
22480
+ Number.isFinite(val) &&
22481
+ val >= min &&
22482
+ val <= max,
22483
+ yieldEvery: DRY_RUN_YIELD_EVERY,
22484
+ maxDeltaK: this.configuration.maxDeltaK,
22485
+ maxDeltaIJ: this.configuration.maxDeltaIJ,
22486
+ isCancelled: () => token.cancelled,
22487
+ maxVoxels: this.computeVoxelBudget(refVolume),
22488
+ shouldContinue: shapeGate,
22489
+ });
22490
+ if (token.cancelled) {
22491
+ return;
22492
+ }
22493
+ const lesionLike = !truncated && bbox && shapeGate({ voxelCount, bbox });
22494
+ if (lesionLike) {
22495
+ this.confirmedRegion = {
22496
+ viewportId: verdict.viewportId,
22497
+ bbox,
22498
+ bandMin: min,
22499
+ bandMax: max,
22500
+ expiresAt: Date.now() + VERDICT_CACHE_TTL_MS,
22501
+ };
22502
+ if (this.lastProbe === verdict) {
22503
+ verdict.ok = true;
22504
+ element.style.cursor = _regionSegmentHoverCursors_js__rspack_import_9/* .PLUS_CURSOR */.ys;
22505
+ }
22506
+ }
22507
+ else {
22508
+ this.rememberRejectedRegion(verdict.viewportId, bbox, min, max);
22509
+ if (this.lastProbe === verdict) {
22510
+ verdict.ok = false;
22511
+ element.style.cursor = _regionSegmentHoverCursors_js__rspack_import_9/* .BLOCKED_CURSOR */.kC;
22512
+ }
22513
+ }
22514
+ }
22515
+ catch (err) {
22516
+ growCutLog.debug('hover dry-run: could not evaluate', {
22517
+ message: err instanceof Error ? err.message : String(err),
22518
+ });
22519
+ }
22520
+ finally {
22521
+ if (this.dryRunToken === token) {
22522
+ this.dryRunToken = null;
22523
+ }
22524
+ }
22525
+ }
22526
+ probeAppliesToClick(viewport, canvas) {
22527
+ const probe = this.lastProbe;
22528
+ if (!probe || probe.viewportId !== viewport.id) {
22529
+ return false;
22530
+ }
22531
+ if (Date.now() - probe.at > PROBE_FRESH_MS) {
22532
+ return false;
22533
+ }
22534
+ if (probe.sliceIndex !== this.getViewportSliceIndex(viewport)) {
22535
+ return false;
22536
+ }
22537
+ const dx = canvas[0] - probe.canvas[0];
22538
+ const dy = canvas[1] - probe.canvas[1];
22539
+ return Math.sqrt(dx * dx + dy * dy) <= PROBE_REUSE_DISTANCE_PX;
22540
+ }
22541
+ async preMouseDownCallback(evt) {
22542
+ if (this.segmentationInProgress) {
22543
+ return false;
22544
+ }
22545
+ const { currentPoints, element } = evt.detail;
22546
+ const { world: worldPoint, canvas: canvasPoint } = currentPoints;
22547
+ const enabledElement = element ? (0,_cornerstonejs_core__rspack_import_0.getEnabledElement)(element) : undefined;
22548
+ if (enabledElement?.viewport &&
22549
+ this.probeAppliesToClick(enabledElement.viewport, canvasPoint) &&
22550
+ this.lastProbe?.ok === false) {
22551
+ growCutLog.info('click ignored: hover probe reported no proper region', {
22552
+ canvasPoint,
22553
+ });
22554
+ return false;
22555
+ }
22556
+ let setupOk = false;
22557
+ try {
22558
+ setupOk = await super.preMouseDownCallback(evt);
22559
+ }
22560
+ catch (err) {
22561
+ const message = err instanceof Error ? err.message : 'Click segmentation failed.';
22562
+ growCutLog.info('ClickSegment: click setup rejected', { message });
22563
+ this.notifySegmentationError(message);
22564
+ return false;
22565
+ }
22566
+ if (!setupOk || !this.growCutData) {
22567
+ return false;
22568
+ }
22569
+ const clickData = this.growCutData;
22570
+ this.growCutData = null;
22571
+ void this.runClick(clickData, worldPoint, element).catch((err) => {
22572
+ const message = err instanceof Error ? err.message : 'Click segmentation failed.';
22573
+ this.notifySegmentationError(message);
22574
+ growCutLog.error('ClickSegment: segmentation failed', { message });
22575
+ });
22576
+ return true;
22577
+ }
22578
+ async runClick(clickData, worldPoint, element) {
22579
+ const { segmentation, viewportId, renderingEngineId } = clickData;
22580
+ const { referencedVolumeId, labelmapVolumeId, segmentIndex } = segmentation;
22581
+ const renderingEngine = (0,_cornerstonejs_core__rspack_import_0.getRenderingEngine)(renderingEngineId);
22582
+ const viewport = renderingEngine?.getViewport(viewportId);
22583
+ if (!viewport) {
22584
+ throw new Error('ClickSegment: viewport not found for click.');
22585
+ }
22586
+ const refVolume = _cornerstonejs_core__rspack_import_0.cache.getVolume(referencedVolumeId);
22587
+ const labelmapVolume = _cornerstonejs_core__rspack_import_0.cache.getVolume(labelmapVolumeId);
22588
+ if (!refVolume || !labelmapVolume) {
22589
+ throw new Error('ClickSegment: referenced or labelmap volume not in cache.');
22590
+ }
22591
+ const probe = (0,_utilities_segmentation_growCut_intensityRange_adaptiveRegionIntensityRange_js__rspack_import_4/* .probeAdaptiveRegion */.Ti)(refVolume, worldPoint, this.buildProbeOptions(viewport, viewport.element, referencedVolumeId));
22592
+ if (!probe.viable || !probe.range || !probe.expandContext) {
22593
+ growCutLog.info('ClickSegment: click found no meaningful region', {
22594
+ reason: probe.reason,
22595
+ regionAreaMm2: probe.regionAreaMm2,
22596
+ });
22597
+ this.notifySegmentationError('No meaningful region at the clicked location. Move the pointer until the plus cursor appears.');
22598
+ return;
22599
+ }
22600
+ growCutLog.info('ClickSegment: click', {
22601
+ worldPoint,
22602
+ toleranceBytes: probe.toleranceBytes,
22603
+ regionAreaMm2: probe.regionAreaMm2,
22604
+ band: { min: probe.range.min, max: probe.range.max },
22605
+ });
22606
+ const memo = this.beginLabelmapMemo(segmentation, labelmapVolume);
22607
+ let filledPoints;
22608
+ try {
22609
+ filledPoints = await this.fillWithRange(probe.range, {
22610
+ segmentation,
22611
+ viewportId,
22612
+ renderingEngineId,
22613
+ }, viewport, labelmapVolume, element, memo);
22614
+ }
22615
+ finally {
22616
+ this.doneEditMemo();
22617
+ }
22618
+ this.lastClick = {
22619
+ expandContext: probe.expandContext,
22620
+ toleranceBytes: probe.expandContext.chosenToleranceBytes,
22621
+ worldPoint: [...worldPoint],
22622
+ filledPoints,
22623
+ segmentation,
22624
+ viewportId,
22625
+ renderingEngineId,
22626
+ };
22627
+ growCutLog.info('ClickSegment: click complete', {
22628
+ filledVoxels: filledPoints.length,
22629
+ segmentIndex,
22630
+ });
22631
+ }
22632
+ async fillWithRange(range, target, viewport, labelmapVolume, element, memo) {
22633
+ const { segmentation } = target;
22634
+ const { referencedVolumeId, segmentIndex, segmentationId } = segmentation;
22635
+ this.segmentationInProgress = true;
22636
+ if (element) {
22637
+ element.style.cursor = 'wait';
22638
+ }
22639
+ const abortController = new AbortController();
22640
+ this.clickAbortController = abortController;
22641
+ let filledPoints = [];
22642
+ let notLesionLike = false;
22643
+ try {
22644
+ const referencedVolume = _cornerstonejs_core__rspack_import_0.cache.getVolume(referencedVolumeId);
22645
+ if (!referencedVolume) {
22646
+ throw new Error('ClickSegment: referenced volume is no longer cached; cannot fill.');
22647
+ }
22648
+ const result = await (0,_utilities_segmentation_growCut_runFloodFillSegmentation_js__rspack_import_2/* .runFloodFillSegmentation */.ZC)({
22649
+ referencedVolumeId,
22650
+ worldPosition: this.indexToWorld(referencedVolume, range.ijkStart),
22651
+ viewport,
22652
+ labelmapVolume,
22653
+ options: {
22654
+ segmentIndex,
22655
+ getIntensityRange: () => range,
22656
+ element: viewport.element,
22657
+ applyExternalIslandRemoval: true,
22658
+ applyInternalIslandRemoval: true,
22659
+ maxDeltaK: this.configuration.maxDeltaK,
22660
+ maxDeltaIJ: this.configuration.maxDeltaIJ,
22661
+ isCancelled: () => abortController.signal.aborted,
22662
+ maxVoxels: this.computeVoxelBudget(referencedVolume),
22663
+ shouldContinueRegion: this.makeRegionShapeGate(referencedVolume),
22664
+ historyVoxelManager: memo?.voxelManager,
22665
+ onRejected: ({ voxelCount, bbox }) => {
22666
+ notLesionLike = true;
22667
+ growCutLog.info('ClickSegment: fill rejected by shape gate', {
22668
+ voxelCount,
22669
+ bbox,
22670
+ });
22671
+ },
22672
+ onCommitted: (points) => {
22673
+ filledPoints = points;
22674
+ },
22675
+ },
22676
+ });
22677
+ if (!result) {
22678
+ if (abortController.signal.aborted) {
22679
+ throw new Error('ClickSegment: fill cancelled.');
22680
+ }
22681
+ throw new Error(notLesionLike
22682
+ ? NOT_LESION_MESSAGE
22683
+ : 'ClickSegment: fill produced no result (band rejected).');
22684
+ }
22685
+ (0,_stateManagement_segmentation_triggerSegmentationEvents_js__rspack_import_7.triggerSegmentationDataModified)(segmentationId);
22686
+ return filledPoints;
22687
+ }
22688
+ finally {
22689
+ if (this.clickAbortController === abortController) {
22690
+ this.clickAbortController = null;
22691
+ }
22692
+ this.segmentationInProgress = false;
22693
+ if (element) {
22694
+ element.style.cursor = _regionSegmentHoverCursors_js__rspack_import_9/* .PENDING_CURSOR */.t5;
22695
+ }
22696
+ }
22697
+ }
22698
+ indexToWorld(volume, ijk) {
22699
+ return _cornerstonejs_core__rspack_import_0.utilities.transformIndexToWorld(volume.imageData, ijk);
22700
+ }
22701
+ beginLabelmapMemo(segmentation, labelmapVolume) {
22702
+ const memo = _utilities_segmentation_createLabelmapMemo_js__rspack_import_8.createLabelmapMemo(segmentation.segmentationId, labelmapVolume.voxelManager);
22703
+ this.memo = memo;
22704
+ return memo;
22705
+ }
22706
+ curveSizeAt(context, toleranceBytes) {
22707
+ let size = 0;
22708
+ for (const [level, levelSize] of context.growthCurve) {
22709
+ if (level > toleranceBytes) {
22710
+ break;
22711
+ }
22712
+ size = levelSize;
22713
+ }
22714
+ return size;
22715
+ }
22716
+ pickNextTolerance(direction) {
22717
+ const lastClick = this.lastClick;
22718
+ if (!lastClick) {
22719
+ return null;
22720
+ }
22721
+ const { expandContext, toleranceBytes } = lastClick;
22722
+ const currentSize = this.curveSizeAt(expandContext, toleranceBytes);
22723
+ if (direction > 0) {
22724
+ for (const [level, size] of expandContext.growthCurve) {
22725
+ if (level <= toleranceBytes) {
22726
+ continue;
22727
+ }
22728
+ if (size >= Math.max(currentSize + 1, currentSize * EXPAND_STEP_FACTOR)) {
22729
+ return level;
22730
+ }
22731
+ }
22732
+ return null;
22733
+ }
22734
+ for (let index = expandContext.growthCurve.length - 1; index >= 0; index--) {
22735
+ const [level, size] = expandContext.growthCurve[index];
22736
+ if (level >= toleranceBytes) {
22737
+ continue;
22738
+ }
22739
+ if (size <= Math.min(currentSize - 1, currentSize * SHRINK_STEP_FACTOR)) {
22740
+ return level;
22741
+ }
22742
+ }
22743
+ return null;
22744
+ }
22745
+ expand() {
22746
+ this.stepTolerance(1);
22747
+ }
22748
+ shrink() {
22749
+ this.stepTolerance(-1);
22750
+ }
22751
+ refresh() {
22752
+ const lastClick = this.lastClick;
22753
+ if (!lastClick || this.segmentationInProgress) {
22754
+ return;
22755
+ }
22756
+ void this.refillAtTolerance(lastClick.toleranceBytes).catch((err) => {
22757
+ growCutLog.error('ClickSegment: refresh failed', {
22758
+ message: err instanceof Error ? err.message : String(err),
22759
+ });
22760
+ });
22761
+ }
22762
+ stepTolerance(direction) {
22763
+ if (this.segmentationInProgress) {
22764
+ return;
22765
+ }
22766
+ const lastClick = this.lastClick;
22767
+ if (!lastClick) {
22768
+ growCutLog.info('ClickSegment: no click to expand/shrink yet');
22769
+ return;
22770
+ }
22771
+ const next = this.pickNextTolerance(direction);
22772
+ if (next === null) {
22773
+ growCutLog.info('ClickSegment: no further step available', {
22774
+ direction: direction > 0 ? 'expand' : 'shrink',
22775
+ toleranceBytes: lastClick.toleranceBytes,
22776
+ });
22777
+ return;
22778
+ }
22779
+ growCutLog.info('ClickSegment: stepping tolerance', {
22780
+ direction: direction > 0 ? 'expand' : 'shrink',
22781
+ fromToleranceBytes: lastClick.toleranceBytes,
22782
+ toToleranceBytes: next,
22783
+ predictedRegionPx: this.curveSizeAt(lastClick.expandContext, next),
22784
+ });
22785
+ const previousTolerance = lastClick.toleranceBytes;
22786
+ void this.refillAtTolerance(next).catch((err) => {
22787
+ const message = err instanceof Error ? err.message : String(err);
22788
+ if (message === NOT_LESION_MESSAGE && direction > 0) {
22789
+ growCutLog.info('ClickSegment: expand blocked by the lesion shape gate; previous result kept', { previousTolerance });
22790
+ this.notifySegmentationError('Expanding further would leak beyond a lesion-like shape; kept the previous result.');
22791
+ return;
22792
+ }
22793
+ growCutLog.error('ClickSegment: expand/shrink failed', { message });
22794
+ });
22795
+ }
22796
+ async refillAtTolerance(toleranceBytes) {
22797
+ const lastClick = this.lastClick;
22798
+ if (!lastClick) {
22799
+ return;
22800
+ }
22801
+ const { segmentation, viewportId, renderingEngineId } = lastClick;
22802
+ const labelmapVolume = _cornerstonejs_core__rspack_import_0.cache.getVolume(segmentation.labelmapVolumeId);
22803
+ const renderingEngine = (0,_cornerstonejs_core__rspack_import_0.getRenderingEngine)(renderingEngineId);
22804
+ const viewport = renderingEngine?.getViewport(viewportId);
22805
+ if (!labelmapVolume || !viewport) {
22806
+ growCutLog.warn('ClickSegment: labelmap or viewport gone; cannot expand/shrink');
22807
+ return;
22808
+ }
22809
+ const memo = this.beginLabelmapMemo(segmentation, labelmapVolume);
22810
+ try {
22811
+ const { voxelManager } = labelmapVolume;
22812
+ const historyVm = memo.voxelManager;
22813
+ const [width, height] = labelmapVolume.dimensions;
22814
+ const pixelsPerSlice = width * height;
22815
+ const { segmentIndex } = segmentation;
22816
+ const clearedIndices = [];
22817
+ for (const [x, y, z] of lastClick.filledPoints) {
22818
+ const index = z * pixelsPerSlice + y * width + x;
22819
+ if (voxelManager.getAtIndex(index) === segmentIndex) {
22820
+ historyVm.setAtIndex(index, 0);
22821
+ clearedIndices.push(index);
22822
+ }
22823
+ }
22824
+ const range = (0,_utilities_segmentation_growCut_intensityRange_adaptiveRegionIntensityRange_js__rspack_import_4/* .resolveAdaptiveBandAtTolerance */.CN)(lastClick.expandContext, toleranceBytes);
22825
+ try {
22826
+ const filledPoints = await this.fillWithRange(range, {
22827
+ segmentation,
22828
+ viewportId,
22829
+ renderingEngineId,
22830
+ }, viewport, labelmapVolume, this.lastHoverElement ?? undefined, memo);
22831
+ lastClick.toleranceBytes = toleranceBytes;
22832
+ lastClick.filledPoints = filledPoints;
22833
+ growCutLog.info('ClickSegment: refill complete', {
22834
+ toleranceBytes,
22835
+ filledVoxels: filledPoints.length,
22836
+ });
22837
+ }
22838
+ catch (err) {
22839
+ for (const index of clearedIndices) {
22840
+ historyVm.setAtIndex(index, segmentIndex);
22841
+ }
22842
+ (0,_stateManagement_segmentation_triggerSegmentationEvents_js__rspack_import_7.triggerSegmentationDataModified)(segmentation.segmentationId);
22843
+ throw err;
22844
+ }
22845
+ }
22846
+ finally {
22847
+ this.doneEditMemo();
22848
+ }
22849
+ }
22850
+ }
22851
+ ClickSegmentTool.toolName = 'ClickSegment';
22852
+ /* export default */ const __rspack_default_export = (ClickSegmentTool);
22853
+
22854
+
22265
22855
  },
22266
22856
  6902(__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
22267
22857
  __webpack_require__.d(__webpack_exports__, {
@@ -31674,12 +32264,12 @@ __webpack_require__.d(__webpack_exports__, {
31674
32264
  EV: () => (/* reexport safe */ _annotation_CobbAngleTool_js__rspack_import_39.A),
31675
32265
  Eb: () => (/* reexport safe */ _VolumeCroppingControlTool_js__rspack_import_4.A),
31676
32266
  FE: () => (/* reexport safe */ _ScaleOverlayTool_js__rspack_import_18.A),
31677
- Fz: () => (/* reexport safe */ _segmentation_SegmentBidirectionalTool_js__rspack_import_59.A),
31678
- G2: () => (/* reexport safe */ _segmentation_CircleScissorsTool_js__rspack_import_49.A),
31679
- IX: () => (/* reexport safe */ _segmentation_SegmentSelectTool_js__rspack_import_58.A),
32267
+ Fz: () => (/* reexport safe */ _segmentation_SegmentBidirectionalTool_js__rspack_import_60.A),
32268
+ G2: () => (/* reexport safe */ _segmentation_CircleScissorsTool_js__rspack_import_50.A),
32269
+ IX: () => (/* reexport safe */ _segmentation_SegmentSelectTool_js__rspack_import_59.A),
31680
32270
  Ix: () => (/* reexport safe */ _annotation_LivewireContourSegmentationTool_js__rspack_import_36.A),
31681
32271
  J2: () => (/* reexport safe */ _annotation_SplineROITool_js__rspack_import_31.A),
31682
- LK: () => (/* reexport safe */ _segmentation_LabelmapEditWithContour_js__rspack_import_62.A),
32272
+ LK: () => (/* reexport safe */ _segmentation_LabelmapEditWithContour_js__rspack_import_63.A),
31683
32273
  LW: () => (/* reexport safe */ _annotation_LengthTool_js__rspack_import_23.A),
31684
32274
  M$: () => (/* reexport safe */ _AdvancedMagnifyTool_js__rspack_import_13.A),
31685
32275
  Mu: () => (/* reexport safe */ _annotation_BidirectionalTool_js__rspack_import_21.A),
@@ -31693,12 +32283,13 @@ __webpack_require__.d(__webpack_exports__, {
31693
32283
  So: () => (/* reexport safe */ _TrackballRotateTool_js__rspack_import_2.A),
31694
32284
  T8: () => (/* reexport safe */ _annotation_UltrasoundPleuraBLineTool_UltrasoundPleuraBLineTool_js__rspack_import_41.A),
31695
32285
  TG: () => (/* reexport safe */ _WindowLevelRegionTool_js__rspack_import_6.A),
31696
- TR: () => (/* reexport safe */ _segmentation_RectangleROIThresholdTool_js__rspack_import_51.A),
31697
- Tc: () => (/* reexport safe */ _annotation_WholeBodySegmentTool_js__rspack_import_46.A),
31698
- Uj: () => (/* reexport safe */ _segmentation_PaintFillTool_js__rspack_import_55.A),
32286
+ TR: () => (/* reexport safe */ _segmentation_RectangleROIThresholdTool_js__rspack_import_52.A),
32287
+ Tc: () => (/* reexport safe */ _annotation_WholeBodySegmentTool_js__rspack_import_47.A),
32288
+ Uj: () => (/* reexport safe */ _segmentation_PaintFillTool_js__rspack_import_56.A),
31699
32289
  Vl: () => (/* reexport safe */ _annotation_CircleROITool_js__rspack_import_29.A),
31700
32290
  X8: () => (/* reexport safe */ _ReferenceLinesTool_js__rspack_import_14.A),
31701
- Xr: () => (/* reexport safe */ _OrientationMarkerTool_js__rspack_import_56.A),
32291
+ Xr: () => (/* reexport safe */ _OrientationMarkerTool_js__rspack_import_57.A),
32292
+ Yk: () => (/* reexport safe */ _annotation_ClickSegmentTool_js__rspack_import_46.A),
31702
32293
  Ys: () => (/* reexport safe */ _annotation_LivewireContourTool_js__rspack_import_35.A),
31703
32294
  ae: () => (/* reexport safe */ _StackScrollTool_js__rspack_import_7.A),
31704
32295
  ao: () => (/* reexport safe */ _annotation_ArrowAnnotateTool_js__rspack_import_37.A),
@@ -31708,28 +32299,28 @@ __webpack_require__.d(__webpack_exports__, {
31708
32299
  ep: () => (/* reexport safe */ _CrosshairsTool_js__rspack_import_11.A),
31709
32300
  ex: () => (/* reexport safe */ _annotation_PlanarFreehandROITool_js__rspack_import_33.A),
31710
32301
  hz: () => (/* reexport safe */ _annotation_LabelTool_js__rspack_import_22.A),
31711
- il: () => (/* reexport safe */ _segmentation_LabelmapBaseTool_js__rspack_import_47.A),
32302
+ il: () => (/* reexport safe */ _segmentation_LabelmapBaseTool_js__rspack_import_48.A),
31712
32303
  j$: () => (/* reexport safe */ _annotation_DragProbeTool_js__rspack_import_26.A),
31713
- ls: () => (/* reexport safe */ _segmentation_BrushTool_js__rspack_import_54.A),
32304
+ ls: () => (/* reexport safe */ _segmentation_BrushTool_js__rspack_import_55.A),
31714
32305
  m8: () => (/* reexport safe */ _annotation_HeightTool_js__rspack_import_24.A),
31715
- mX: () => (/* reexport safe */ _segmentation_RectangleROIStartEndThresholdTool_js__rspack_import_52.A),
32306
+ mX: () => (/* reexport safe */ _segmentation_RectangleROIStartEndThresholdTool_js__rspack_import_53.A),
31716
32307
  nJ: () => (/* reexport safe */ _annotation_ETDRSGridTool_js__rspack_import_30.A),
31717
32308
  oS: () => (/* reexport safe */ _base_index_js__rspack_import_0.oS),
31718
32309
  oi: () => (/* reexport safe */ _annotation_UltrasoundDirectionalTool_js__rspack_import_40.A),
31719
- pq: () => (/* reexport safe */ _segmentation_CircleROIStartEndThresholdTool_js__rspack_import_53.A),
32310
+ pq: () => (/* reexport safe */ _segmentation_CircleROIStartEndThresholdTool_js__rspack_import_54.A),
31720
32311
  qD: () => (/* reexport safe */ _annotation_EllipticalROITool_js__rspack_import_28.A),
31721
32312
  qT: () => (/* reexport safe */ _annotation_SplineContourSegmentationTool_js__rspack_import_32.A),
31722
32313
  qi: () => (/* reexport safe */ _annotation_PlanarFreehandContourSegmentationTool_js__rspack_import_34.A),
31723
32314
  sR: () => (/* reexport safe */ _annotation_RegionSegmentPlusTool_js__rspack_import_45.A),
31724
- td: () => (/* reexport safe */ _segmentation_RectangleScissorsTool_js__rspack_import_48.A),
31725
- u9: () => (/* reexport safe */ _segmentation_SegmentLabelTool_js__rspack_import_61.A),
32315
+ td: () => (/* reexport safe */ _segmentation_RectangleScissorsTool_js__rspack_import_49.A),
32316
+ u9: () => (/* reexport safe */ _segmentation_SegmentLabelTool_js__rspack_import_62.A),
31726
32317
  uJ: () => (/* reexport safe */ _MIPJumpToClickTool_js__rspack_import_10.A),
31727
- v: () => (/* reexport safe */ _OrientationControllerTool_js__rspack_import_57.A),
32318
+ v: () => (/* reexport safe */ _OrientationControllerTool_js__rspack_import_58.A),
31728
32319
  wR: () => (/* reexport safe */ _annotation_RegionSegmentTool_js__rspack_import_44.A),
31729
32320
  wh: () => (/* reexport safe */ _base_index_js__rspack_import_0.wh),
31730
32321
  xI: () => (/* reexport safe */ _ReferenceCursors_js__rspack_import_17.A),
31731
32322
  yT: () => (/* reexport safe */ _annotation_AngleTool_js__rspack_import_38.A),
31732
- zH: () => (/* reexport safe */ _segmentation_SphereScissorsTool_js__rspack_import_50.A)
32323
+ zH: () => (/* reexport safe */ _segmentation_SphereScissorsTool_js__rspack_import_51.A)
31733
32324
  });
31734
32325
  /* import */ var _base_index_js__rspack_import_0 = __webpack_require__(84962);
31735
32326
  /* import */ var _PanTool_js__rspack_import_1 = __webpack_require__(30507);
@@ -31777,23 +32368,25 @@ __webpack_require__.d(__webpack_exports__, {
31777
32368
  /* import */ var _AnnotationEraserTool_js__rspack_import_43 = __webpack_require__(39447);
31778
32369
  /* import */ var _annotation_RegionSegmentTool_js__rspack_import_44 = __webpack_require__(41589);
31779
32370
  /* import */ var _annotation_RegionSegmentPlusTool_js__rspack_import_45 = __webpack_require__(20053);
31780
- /* import */ var _annotation_WholeBodySegmentTool_js__rspack_import_46 = __webpack_require__(19146);
31781
- /* import */ var _segmentation_LabelmapBaseTool_js__rspack_import_47 = __webpack_require__(28182);
31782
- /* import */ var _segmentation_RectangleScissorsTool_js__rspack_import_48 = __webpack_require__(37661);
31783
- /* import */ var _segmentation_CircleScissorsTool_js__rspack_import_49 = __webpack_require__(69288);
31784
- /* import */ var _segmentation_SphereScissorsTool_js__rspack_import_50 = __webpack_require__(74161);
31785
- /* import */ var _segmentation_RectangleROIThresholdTool_js__rspack_import_51 = __webpack_require__(98283);
31786
- /* import */ var _segmentation_RectangleROIStartEndThresholdTool_js__rspack_import_52 = __webpack_require__(43372);
31787
- /* import */ var _segmentation_CircleROIStartEndThresholdTool_js__rspack_import_53 = __webpack_require__(97125);
31788
- /* import */ var _segmentation_BrushTool_js__rspack_import_54 = __webpack_require__(70947);
31789
- /* import */ var _segmentation_PaintFillTool_js__rspack_import_55 = __webpack_require__(64702);
31790
- /* import */ var _OrientationMarkerTool_js__rspack_import_56 = __webpack_require__(87452);
31791
- /* import */ var _OrientationControllerTool_js__rspack_import_57 = __webpack_require__(8342);
31792
- /* import */ var _segmentation_SegmentSelectTool_js__rspack_import_58 = __webpack_require__(69318);
31793
- /* import */ var _segmentation_SegmentBidirectionalTool_js__rspack_import_59 = __webpack_require__(44391);
31794
- /* import */ var _segmentation_strategies_index_js__rspack_import_60 = __webpack_require__(62831);
31795
- /* import */ var _segmentation_SegmentLabelTool_js__rspack_import_61 = __webpack_require__(97198);
31796
- /* import */ var _segmentation_LabelmapEditWithContour_js__rspack_import_62 = __webpack_require__(54267);
32371
+ /* import */ var _annotation_ClickSegmentTool_js__rspack_import_46 = __webpack_require__(62843);
32372
+ /* import */ var _annotation_WholeBodySegmentTool_js__rspack_import_47 = __webpack_require__(19146);
32373
+ /* import */ var _segmentation_LabelmapBaseTool_js__rspack_import_48 = __webpack_require__(28182);
32374
+ /* import */ var _segmentation_RectangleScissorsTool_js__rspack_import_49 = __webpack_require__(37661);
32375
+ /* import */ var _segmentation_CircleScissorsTool_js__rspack_import_50 = __webpack_require__(69288);
32376
+ /* import */ var _segmentation_SphereScissorsTool_js__rspack_import_51 = __webpack_require__(74161);
32377
+ /* import */ var _segmentation_RectangleROIThresholdTool_js__rspack_import_52 = __webpack_require__(98283);
32378
+ /* import */ var _segmentation_RectangleROIStartEndThresholdTool_js__rspack_import_53 = __webpack_require__(43372);
32379
+ /* import */ var _segmentation_CircleROIStartEndThresholdTool_js__rspack_import_54 = __webpack_require__(97125);
32380
+ /* import */ var _segmentation_BrushTool_js__rspack_import_55 = __webpack_require__(70947);
32381
+ /* import */ var _segmentation_PaintFillTool_js__rspack_import_56 = __webpack_require__(64702);
32382
+ /* import */ var _OrientationMarkerTool_js__rspack_import_57 = __webpack_require__(87452);
32383
+ /* import */ var _OrientationControllerTool_js__rspack_import_58 = __webpack_require__(8342);
32384
+ /* import */ var _segmentation_SegmentSelectTool_js__rspack_import_59 = __webpack_require__(69318);
32385
+ /* import */ var _segmentation_SegmentBidirectionalTool_js__rspack_import_60 = __webpack_require__(44391);
32386
+ /* import */ var _segmentation_strategies_index_js__rspack_import_61 = __webpack_require__(62831);
32387
+ /* import */ var _segmentation_SegmentLabelTool_js__rspack_import_62 = __webpack_require__(97198);
32388
+ /* import */ var _segmentation_LabelmapEditWithContour_js__rspack_import_63 = __webpack_require__(54267);
32389
+
31797
32390
 
31798
32391
 
31799
32392
 
@@ -42485,6 +43078,7 @@ __webpack_require__.r(__webpack_exports__);
42485
43078
  __webpack_require__.d(__webpack_exports__, {
42486
43079
  createLabelmapMemo: () => (createLabelmapMemo),
42487
43080
  createRleMemo: () => (createRleMemo),
43081
+ memoAsStep: () => (memoAsStep),
42488
43082
  restoreMemo: () => (restoreMemo)
42489
43083
  });
42490
43084
  /* import */ var _cornerstonejs_core__rspack_import_0 = __webpack_require__(88479);
@@ -42495,14 +43089,46 @@ const { VoxelManager, RLEVoxelMap } = _cornerstonejs_core__rspack_import_0.utili
42495
43089
  function createLabelmapMemo(segmentationId, segmentationVoxelManager) {
42496
43090
  return createRleMemo(segmentationId, segmentationVoxelManager);
42497
43091
  }
43092
+ function memoAsStep(memo) {
43093
+ return {
43094
+ undo: () => memo.restoreMemo(true),
43095
+ redo: () => memo.restoreMemo(false),
43096
+ };
43097
+ }
42498
43098
  function restoreMemo(isUndo) {
42499
- const { segmentationVoxelManager, undoVoxelManager, redoVoxelManager } = this;
42500
- const useVoxelManager = isUndo === false ? redoVoxelManager : undoVoxelManager;
42501
- useVoxelManager.forEach(({ value, pointIJK }) => {
42502
- segmentationVoxelManager.setAtIJKPoint(pointIJK, value);
42503
- });
42504
- const slices = useVoxelManager.getArrayOfModifiedSlices();
42505
- (0,_stateManagement_segmentation_triggerSegmentationEvents_js__rspack_import_1.triggerSegmentationDataModified)(this.segmentationId, slices);
43099
+ const undo = isUndo !== false;
43100
+ const priorSteps = this.priorSteps ?? [];
43101
+ const postSteps = this.postSteps ?? [];
43102
+ const restoreVoxelChanges = () => {
43103
+ const { segmentationVoxelManager, undoVoxelManager, redoVoxelManager } = this;
43104
+ const useVoxelManager = undo ? undoVoxelManager : redoVoxelManager;
43105
+ if (!useVoxelManager) {
43106
+ return;
43107
+ }
43108
+ useVoxelManager.forEach(({ value, pointIJK }) => {
43109
+ segmentationVoxelManager.setAtIJKPoint(pointIJK, value);
43110
+ });
43111
+ const slices = useVoxelManager.getArrayOfModifiedSlices();
43112
+ (0,_stateManagement_segmentation_triggerSegmentationEvents_js__rspack_import_1.triggerSegmentationDataModified)(this.segmentationId, slices);
43113
+ };
43114
+ if (undo) {
43115
+ for (let i = postSteps.length - 1; i >= 0; i--) {
43116
+ postSteps[i].undo();
43117
+ }
43118
+ restoreVoxelChanges();
43119
+ for (let i = priorSteps.length - 1; i >= 0; i--) {
43120
+ priorSteps[i].undo();
43121
+ }
43122
+ }
43123
+ else {
43124
+ for (const step of priorSteps) {
43125
+ step.redo();
43126
+ }
43127
+ restoreVoxelChanges();
43128
+ for (const step of postSteps) {
43129
+ step.redo();
43130
+ }
43131
+ }
42506
43132
  }
42507
43133
  function createRleMemo(segmentationId, segmentationVoxelManager) {
42508
43134
  const voxelManager = VoxelManager.createRLEHistoryVoxelManager(segmentationVoxelManager);
@@ -42521,8 +43147,9 @@ function commitMemo() {
42521
43147
  if (this.redoVoxelManager) {
42522
43148
  return true;
42523
43149
  }
43150
+ const hasSteps = !!(this.priorSteps?.length || this.postSteps?.length);
42524
43151
  if (!this.voxelManager.modifiedSlices.size) {
42525
- return false;
43152
+ return hasSteps;
42526
43153
  }
42527
43154
  const { segmentationVoxelManager } = this;
42528
43155
  const undoVoxelManager = VoxelManager.createRLEHistoryVoxelManager(segmentationVoxelManager);
@@ -45123,7 +45750,7 @@ __webpack_require__.d(__webpack_exports__, {
45123
45750
 
45124
45751
  },
45125
45752
  80274() {
45126
- const version = '5.4.12';
45753
+ const version = '5.4.13';
45127
45754
 
45128
45755
 
45129
45756
  },