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 | 1x 8x 8x 8x 8x 8x 8x 32x 8x 32x 96x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 13286x 8x 13286x 121x 13165x 8x 8x 8x | import { utilities as csUtils, StackViewport } from '@cornerstonejs/core'; import type { Types } from '@cornerstonejs/core'; import { getBoundingBoxAroundShapeIJK, getBoundingBoxAroundShapeWorld, } from '../../../utilities/boundingBox'; import { pointInShapeCallback } from '../../../utilities'; import { triggerSegmentationDataModified } from '../../../stateManagement/segmentation/triggerSegmentationEvents'; import { LabelmapToolOperationData } from '../../../types'; import { getStrategyData } from './utils/getStrategyData'; import { isAxisAlignedRectangle } from '../../../utilities/rectangleROITool/isAxisAlignedRectangle'; const { transformWorldToIndex } = csUtils; type OperationData = LabelmapToolOperationData & { points: [Types.Point3, Types.Point3, Types.Point3, Types.Point3]; }; /** * For each point in the bounding box around the rectangle, if the point is inside * the rectangle, set the scalar value to the segmentIndex * @param toolGroupId - string * @param operationData - OperationData * @param inside - boolean */ // Todo: why we have another constraintFn? in addition to the one in the operationData? function fillRectangle( enabledElement: Types.IEnabledElement, operationData: OperationData, inside = true ): void { const { points, segmentsLocked, segmentIndex, segmentationId } = operationData; const { viewport } = enabledElement; const strategyData = getStrategyData({ operationData, viewport: enabledElement.viewport, }); Iif (!strategyData) { console.warn('No data found for fillRectangle'); return; } const { segmentationImageData, segmentationScalarData } = strategyData; let rectangleCornersIJK = points.map((world) => { return transformWorldToIndex(segmentationImageData, world); }); // math round rectangleCornersIJK = rectangleCornersIJK.map((point) => { return point.map((coord) => { return Math.round(coord); }); }); const boundsIJK = getBoundingBoxAroundShapeIJK( rectangleCornersIJK, segmentationImageData.getDimensions() ); const isStackViewport = viewport instanceof StackViewport; // Are we working with 2D rectangle in axis aligned viewport view or not const isAligned = isStackViewport || isAxisAlignedRectangle(rectangleCornersIJK); const direction = segmentationImageData.getDirection(); const spacing = segmentationImageData.getSpacing(); const { viewPlaneNormal } = viewport.getCamera(); // In case that we are working on oblique, our EPS is really the spacing in the // normal direction, since we can't really test each voxel against a 2D rectangle // we need some tolerance in the normal direction. const EPS = csUtils.getSpacingInNormalDirection( { direction, spacing, }, viewPlaneNormal ); const pointsBoundsLPS = getBoundingBoxAroundShapeWorld(points); let [[xMin, xMax], [yMin, yMax], [zMin, zMax]] = pointsBoundsLPS; // Update the bounds with +/- EPS xMin -= EPS; xMax += EPS; yMin -= EPS; yMax += EPS; zMin -= EPS; zMax += EPS; const pointInShapeFn = isAligned ? () => true : (pointLPS) => { const [x, y, z] = pointLPS; const xInside = x >= xMin && x <= xMax; const yInside = y >= yMin && y <= yMax; const zInside = z >= zMin && z <= zMax; return xInside && yInside && zInside; }; const callback = ({ value, index }) => { if (segmentsLocked.includes(value)) { return; } segmentationScalarData[index] = segmentIndex; }; pointInShapeCallback( segmentationImageData, pointInShapeFn, callback, boundsIJK ); triggerSegmentationDataModified(segmentationId); } /** * Fill the inside of a rectangle * @param toolGroupId - The unique identifier of the tool group. * @param operationData - The data that will be used to create the * new rectangle. */ export function fillInsideRectangle( enabledElement: Types.IEnabledElement, operationData: OperationData ): void { fillRectangle(enabledElement, operationData, true); } /** * Fill the area outside of a rectangle for the toolGroupId and segmentationRepresentationUID. * @param toolGroupId - The unique identifier of the tool group. * @param operationData - The data that will be used to create the * new rectangle. */ export function fillOutsideRectangle( enabledElement: Types.IEnabledElement, operationData: OperationData ): void { fillRectangle(enabledElement, operationData, false); } |