Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | 34x 34x | import { cache, imageLoadPoolManager, Enums } from '@cornerstonejs/core'; import zip from 'lodash.zip'; import compact from 'lodash.compact'; import flatten from 'lodash.flatten'; // Map of volumeId and SeriesInstanceId const volumeIdMapsToLoad = new Map<string, string>(); const viewportIdVolumeInputArrayMap = new Map<string, unknown[]>(); /** * This function caches the volumeIds until all the volumes inside the * hanging protocol are initialized. Then it goes through the imageIds * of the volumes, and interleave them, in order for the volumes to be loaded * together from middle to the start and the end. * @param {Object} {viewportData, displaySetMatchDetails} * @returns */ export default function interleaveTopToBottom({ data: { viewportId, volumeInputArray }, displaySetsMatchDetails, viewportMatchDetails: matchDetails, }) { viewportIdVolumeInputArrayMap.set(viewportId, volumeInputArray); // Based on the volumeInputs store the volumeIds and SeriesInstanceIds // to keep track of the volumes being loaded for (const volumeInput of volumeInputArray) { const { volumeId } = volumeInput; const volume = cache.getVolume(volumeId); Iif (!volume) { return; } // if the volumeUID is not in the volumeUIDs array, add it Iif (!volumeIdMapsToLoad.has(volumeId)) { const { metadata } = volume; volumeIdMapsToLoad.set(volumeId, metadata.SeriesInstanceUID); } } const filteredMatchDetails = []; const displaySetsToLoad = new Set(); // Check all viewports that have a displaySet to be loaded. In some cases // (eg: line chart viewports which is not a Cornerstone viewport) the // displaySet is created on the client and there are no instances to be // downloaded. For those viewports the displaySet may have the `skipLoading` // option set to true otherwise it may block the download of all other // instances resulting in blank viewports. Array.from(matchDetails.values()).forEach(curMatchDetails => { const { displaySetsInfo } = curMatchDetails; let numDisplaySetsToLoad = 0; displaySetsInfo.forEach(({ displaySetInstanceUID, displaySetOptions }) => { Iif (!displaySetOptions?.options?.skipLoading) { numDisplaySetsToLoad++; displaySetsToLoad.add(displaySetInstanceUID); } }); Iif (numDisplaySetsToLoad) { filteredMatchDetails.push(curMatchDetails); } }); /** * The following is checking if all the viewports that were matched in the HP has been * successfully created their cornerstone viewport or not. Todo: This can be * improved by not checking it, and as soon as the matched DisplaySets have their * volume loaded, we start the loading, but that comes at the cost of viewports * not being created yet (e.g., in a 10 viewport ptCT fusion, when one ct viewport and one * pt viewport are created we have a guarantee that the volumes are created in the cache * but the rest of the viewports (fusion, mip etc.) are not created yet. So * we can't initiate setting the volumes for those viewports. One solution can be * to add an event when a viewport is created (not enabled element event) and then * listen to it and as the other viewports are created we can set the volumes for them * since volumes are already started loading. */ const uniqueViewportVolumeDisplaySetUIDs = new Set(); viewportIdVolumeInputArrayMap.forEach((volumeInputArray, viewportId) => { volumeInputArray.forEach(volumeInput => { const { volumeId } = volumeInput; uniqueViewportVolumeDisplaySetUIDs.add(volumeId); }); }); const uniqueMatchedDisplaySetUIDs = new Set(); matchDetails.forEach(matchDetail => { const { displaySetsInfo } = matchDetail; displaySetsInfo.forEach(({ displaySetInstanceUID }) => { uniqueMatchedDisplaySetUIDs.add(displaySetInstanceUID); }); }); Iif (uniqueViewportVolumeDisplaySetUIDs.size !== uniqueMatchedDisplaySetUIDs.size) { return; } const volumeIds = Array.from(volumeIdMapsToLoad.keys()).slice(); // get volumes from cache const volumes = volumeIds.map(volumeId => { return cache.getVolume(volumeId); }); // iterate over all volumes, and get their imageIds, and interleave // the imageIds and save them in AllRequests for later use const AllRequests = []; volumes.forEach(volume => { const requests = volume.getImageLoadRequests(); Iif (!requests?.[0]?.imageId) { return; } // reverse the requests AllRequests.push(requests.reverse()); }); // flatten the AllRequests array, which will result in a list of all the // imageIds for all the volumes but interleaved const interleavedRequests = compact(flatten(zip(...AllRequests))); // set the finalRequests to the imageLoadPoolManager const finalRequests = []; interleavedRequests.forEach(request => { const { imageId } = request; AllRequests.forEach(volumeRequests => { const volumeImageIdRequest = volumeRequests.find(req => req.imageId === imageId); Iif (volumeImageIdRequest) { finalRequests.push(volumeImageIdRequest); } }); }); const requestType = Enums.RequestType.Prefetch; const priority = 0; finalRequests.forEach(({ callLoadImage, additionalDetails, imageId, imageIdIndex, options }) => { const callLoadImageBound = callLoadImage.bind(null, imageId, imageIdIndex, options); imageLoadPoolManager.addRequest(callLoadImageBound, requestType, additionalDetails, priority); }); // clear the volumeIdMapsToLoad volumeIdMapsToLoad.clear(); // copy the viewportIdVolumeInputArrayMap const viewportIdVolumeInputArrayMapCopy = new Map(viewportIdVolumeInputArrayMap); // reset the viewportIdVolumeInputArrayMap viewportIdVolumeInputArrayMap.clear(); return viewportIdVolumeInputArrayMapCopy; } |