@cornerstonejs/tools 3.8.3 → 3.8.5

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 (28) hide show
  1. package/dist/esm/enums/WorkerTypes.d.ts +2 -1
  2. package/dist/esm/enums/WorkerTypes.js +1 -0
  3. package/dist/esm/stateManagement/segmentation/getViewportSegmentations.d.ts +2 -1
  4. package/dist/esm/stateManagement/segmentation/getViewportSegmentations.js +7 -3
  5. package/dist/esm/stateManagement/segmentation/helpers/getSegmentationActor.d.ts +0 -1
  6. package/dist/esm/stateManagement/segmentation/helpers/getSegmentationActor.js +0 -5
  7. package/dist/esm/stateManagement/segmentation/helpers/index.d.ts +2 -2
  8. package/dist/esm/stateManagement/segmentation/helpers/index.js +2 -2
  9. package/dist/esm/stateManagement/segmentation/internalAddSegmentationRepresentation.js +0 -2
  10. package/dist/esm/stateManagement/segmentation/segmentationState.d.ts +2 -2
  11. package/dist/esm/stateManagement/segmentation/segmentationState.js +2 -2
  12. package/dist/esm/tools/annotation/CircleROITool.js +7 -4
  13. package/dist/esm/tools/annotation/RegionSegmentPlusTool.js +8 -1
  14. package/dist/esm/tools/displayTools/Labelmap/labelmapDisplay.js +3 -0
  15. package/dist/esm/tools/displayTools/Surface/removeSurfaceFromElement.js +3 -2
  16. package/dist/esm/tools/segmentation/BrushTool.js +1 -1
  17. package/dist/esm/utilities/contours/generateContourSetsFromLabelmap.d.ts +1 -1
  18. package/dist/esm/utilities/contours/generateContourSetsFromLabelmap.js +75 -95
  19. package/dist/esm/utilities/index.d.ts +2 -1
  20. package/dist/esm/utilities/index.js +2 -1
  21. package/dist/esm/utilities/segmentation/computeMetabolicStats.js +9 -0
  22. package/dist/esm/utilities/segmentation/contourAndFindLargestBidirectional.d.ts +1 -1
  23. package/dist/esm/utilities/segmentation/contourAndFindLargestBidirectional.js +2 -2
  24. package/dist/esm/utilities/segmentation/segmentContourAction.d.ts +1 -1
  25. package/dist/esm/utilities/segmentation/segmentContourAction.js +5 -4
  26. package/dist/esm/utilities/segmentation/utilsForWorker.js +3 -0
  27. package/dist/esm/workers/computeWorker.js +6 -2
  28. package/package.json +3 -3
@@ -6,6 +6,7 @@ declare enum ChangeTypes {
6
6
  SURFACE_CLIPPING = "Clipping Surfaces",
7
7
  COMPUTE_STATISTICS = "Computing Statistics",
8
8
  INTERPOLATE_LABELMAP = "Interpolating Labelmap",
9
- COMPUTE_LARGEST_BIDIRECTIONAL = "Computing Largest Bidirectional"
9
+ COMPUTE_LARGEST_BIDIRECTIONAL = "Computing Largest Bidirectional",
10
+ GENERATE_CONTOUR_SETS = "Generating Contour Sets"
10
11
  }
11
12
  export default ChangeTypes;
@@ -8,5 +8,6 @@ var ChangeTypes;
8
8
  ChangeTypes["COMPUTE_STATISTICS"] = "Computing Statistics";
9
9
  ChangeTypes["INTERPOLATE_LABELMAP"] = "Interpolating Labelmap";
10
10
  ChangeTypes["COMPUTE_LARGEST_BIDIRECTIONAL"] = "Computing Largest Bidirectional";
11
+ ChangeTypes["GENERATE_CONTOUR_SETS"] = "Generating Contour Sets";
11
12
  })(ChangeTypes || (ChangeTypes = {}));
12
13
  export default ChangeTypes;
@@ -1,3 +1,4 @@
1
1
  import type { SegmentationRepresentations } from '../../enums';
2
- import type { Segmentation } from '../../types';
2
+ import type { Segmentation, SegmentationRepresentation } from '../../types';
3
3
  export declare function getViewportSegmentations(viewportId: string, type?: SegmentationRepresentations): Segmentation[];
4
+ export declare function getViewportSegmentationRepresentations(viewportId: string): SegmentationRepresentation[];
@@ -1,9 +1,7 @@
1
1
  import { getSegmentation } from './getSegmentation';
2
2
  import { defaultSegmentationStateManager } from './SegmentationStateManager';
3
3
  export function getViewportSegmentations(viewportId, type) {
4
- const segmentationStateManager = defaultSegmentationStateManager;
5
- const state = segmentationStateManager.getState();
6
- const viewportRepresentations = state.viewportSegRepresentations[viewportId];
4
+ const viewportRepresentations = getViewportSegmentationRepresentations(viewportId);
7
5
  const segmentations = viewportRepresentations.map((representation) => {
8
6
  if (type && representation.type === type) {
9
7
  return getSegmentation(representation.segmentationId);
@@ -13,3 +11,9 @@ export function getViewportSegmentations(viewportId, type) {
13
11
  const filteredSegmentations = segmentations.filter((segmentation) => segmentation !== undefined);
14
12
  return filteredSegmentations;
15
13
  }
14
+ export function getViewportSegmentationRepresentations(viewportId) {
15
+ const segmentationStateManager = defaultSegmentationStateManager;
16
+ const state = segmentationStateManager.getState();
17
+ const viewportRepresentations = state.viewportSegRepresentations[viewportId];
18
+ return viewportRepresentations;
19
+ }
@@ -3,5 +3,4 @@ export declare function getLabelmapActorUID(viewportId: string, segmentationId:
3
3
  export declare function getLabelmapActorEntries(viewportId: string, segmentationId: string): Types.ActorEntry[];
4
4
  export declare function getLabelmapActorEntry(viewportId: string, segmentationId: string): Types.ActorEntry;
5
5
  export declare function getSurfaceActorEntry(viewportId: string, segmentationId: string, segmentIndex?: number | string): Types.ActorEntry;
6
- export declare function getSurfaceActorUID(viewportId: string, segmentationId: string, segmentIndex?: number | string): string | undefined;
7
6
  export declare function getSurfaceRepresentationUID(segmentationId: string, segmentIndex?: number | string): string;
@@ -40,11 +40,6 @@ export function getSurfaceActorEntry(viewportId, segmentationId, segmentIndex) {
40
40
  return getActorEntry(viewportId, segmentationId, (actor) => actor.representationUID ===
41
41
  getSurfaceRepresentationUID(segmentationId, segmentIndex));
42
42
  }
43
- export function getSurfaceActorUID(viewportId, segmentationId, segmentIndex) {
44
- const segIndex = segmentIndex ? segmentIndex.toString() : '';
45
- const actorEntry = getSurfaceActorEntry(viewportId, segmentationId, segIndex);
46
- return actorEntry?.uid;
47
- }
48
43
  export function getSurfaceRepresentationUID(segmentationId, segmentIndex) {
49
44
  return `${segmentationId}-${SegmentationRepresentations.Surface}-${segmentIndex}`;
50
45
  }
@@ -1,3 +1,3 @@
1
1
  import validateSegmentationInput from './validateSegmentationInput';
2
- import { getLabelmapActorEntries, getLabelmapActorEntry, getSurfaceActorEntry, getLabelmapActorUID, getSurfaceActorUID } from './getSegmentationActor';
3
- export { validateSegmentationInput, getLabelmapActorEntries, getLabelmapActorEntry, getSurfaceActorEntry, getLabelmapActorUID, getSurfaceActorUID, };
2
+ import { getLabelmapActorEntries, getLabelmapActorEntry, getSurfaceActorEntry, getLabelmapActorUID } from './getSegmentationActor';
3
+ export { validateSegmentationInput, getLabelmapActorEntries, getLabelmapActorEntry, getSurfaceActorEntry, getLabelmapActorUID, };
@@ -1,3 +1,3 @@
1
1
  import validateSegmentationInput from './validateSegmentationInput';
2
- import { getLabelmapActorEntries, getLabelmapActorEntry, getSurfaceActorEntry, getLabelmapActorUID, getSurfaceActorUID, } from './getSegmentationActor';
3
- export { validateSegmentationInput, getLabelmapActorEntries, getLabelmapActorEntry, getSurfaceActorEntry, getLabelmapActorUID, getSurfaceActorUID, };
2
+ import { getLabelmapActorEntries, getLabelmapActorEntry, getSurfaceActorEntry, getLabelmapActorUID, } from './getSegmentationActor';
3
+ export { validateSegmentationInput, getLabelmapActorEntries, getLabelmapActorEntry, getSurfaceActorEntry, getLabelmapActorUID, };
@@ -3,9 +3,7 @@ import { triggerAnnotationRenderForViewportIds } from '../../utilities/triggerAn
3
3
  import { SegmentationRepresentations } from '../../enums';
4
4
  import { triggerSegmentationModified } from './triggerSegmentationEvents';
5
5
  import { addColorLUT } from './addColorLUT';
6
- import { getNextColorLUTIndex } from './getNextColorLUTIndex';
7
6
  import { defaultSegmentationStateManager } from './SegmentationStateManager';
8
- import { getColorLUT } from './getColorLUT';
9
7
  function internalAddSegmentationRepresentation(viewportId, representationInput) {
10
8
  const { segmentationId, config } = representationInput;
11
9
  const renderingConfig = {
@@ -7,11 +7,11 @@ import { addColorLUT } from './addColorLUT';
7
7
  import { getColorLUT } from './getColorLUT';
8
8
  import { getNextColorLUTIndex } from './getNextColorLUTIndex';
9
9
  import { removeColorLUT } from './removeColorLUT';
10
- import { getViewportSegmentations } from './getViewportSegmentations';
10
+ import { getViewportSegmentations, getViewportSegmentationRepresentations } from './getViewportSegmentations';
11
11
  import { getViewportIdsWithSegmentation } from './getViewportIdsWithSegmentation';
12
12
  import { getCurrentLabelmapImageIdForViewport, getCurrentLabelmapImageIdsForViewport } from './getCurrentLabelmapImageIdForViewport';
13
13
  import { updateLabelmapSegmentationImageReferences } from './updateLabelmapSegmentationImageReferences';
14
14
  import { getStackSegmentationImageIdsForViewport } from './getStackSegmentationImageIdsForViewport';
15
15
  import { getSegmentationRepresentation, getSegmentationRepresentations, getSegmentationRepresentationsBySegmentationId } from './getSegmentationRepresentation';
16
16
  declare function destroy(): void;
17
- export { getColorLUT, getCurrentLabelmapImageIdForViewport, getCurrentLabelmapImageIdsForViewport, getNextColorLUTIndex, getSegmentation, getSegmentations, getStackSegmentationImageIdsForViewport, getViewportIdsWithSegmentation, getSegmentationRepresentation, getSegmentationRepresentations, removeColorLUT, getViewportSegmentations, removeSegmentation, removeLabelmapRepresentation, removeContourRepresentation, removeSurfaceRepresentation, removeSegmentationRepresentation, removeAllSegmentationRepresentations, removeAllSegmentations, addColorLUT, addSegmentations, updateLabelmapSegmentationImageReferences, getSegmentationRepresentationsBySegmentationId, destroy, };
17
+ export { getColorLUT, getCurrentLabelmapImageIdForViewport, getCurrentLabelmapImageIdsForViewport, getNextColorLUTIndex, getSegmentation, getSegmentations, getStackSegmentationImageIdsForViewport, getViewportIdsWithSegmentation, getSegmentationRepresentation, getSegmentationRepresentations, getViewportSegmentationRepresentations, removeColorLUT, getViewportSegmentations, removeSegmentation, removeLabelmapRepresentation, removeContourRepresentation, removeSurfaceRepresentation, removeSegmentationRepresentation, removeAllSegmentationRepresentations, removeAllSegmentations, addColorLUT, addSegmentations, updateLabelmapSegmentationImageReferences, getSegmentationRepresentationsBySegmentationId, destroy, };
@@ -7,7 +7,7 @@ import { addColorLUT } from './addColorLUT';
7
7
  import { getColorLUT } from './getColorLUT';
8
8
  import { getNextColorLUTIndex } from './getNextColorLUTIndex';
9
9
  import { removeColorLUT } from './removeColorLUT';
10
- import { getViewportSegmentations } from './getViewportSegmentations';
10
+ import { getViewportSegmentations, getViewportSegmentationRepresentations, } from './getViewportSegmentations';
11
11
  import { getViewportIdsWithSegmentation } from './getViewportIdsWithSegmentation';
12
12
  import { getCurrentLabelmapImageIdForViewport, getCurrentLabelmapImageIdsForViewport, } from './getCurrentLabelmapImageIdForViewport';
13
13
  import { updateLabelmapSegmentationImageReferences } from './updateLabelmapSegmentationImageReferences';
@@ -17,4 +17,4 @@ import { defaultSegmentationStateManager } from './SegmentationStateManager';
17
17
  function destroy() {
18
18
  defaultSegmentationStateManager.resetState();
19
19
  }
20
- export { getColorLUT, getCurrentLabelmapImageIdForViewport, getCurrentLabelmapImageIdsForViewport, getNextColorLUTIndex, getSegmentation, getSegmentations, getStackSegmentationImageIdsForViewport, getViewportIdsWithSegmentation, getSegmentationRepresentation, getSegmentationRepresentations, removeColorLUT, getViewportSegmentations, removeSegmentation, removeLabelmapRepresentation, removeContourRepresentation, removeSurfaceRepresentation, removeSegmentationRepresentation, removeAllSegmentationRepresentations, removeAllSegmentations, addColorLUT, addSegmentations, updateLabelmapSegmentationImageReferences, getSegmentationRepresentationsBySegmentationId, destroy, };
20
+ export { getColorLUT, getCurrentLabelmapImageIdForViewport, getCurrentLabelmapImageIdsForViewport, getNextColorLUTIndex, getSegmentation, getSegmentations, getStackSegmentationImageIdsForViewport, getViewportIdsWithSegmentation, getSegmentationRepresentation, getSegmentationRepresentations, getViewportSegmentationRepresentations, removeColorLUT, getViewportSegmentations, removeSegmentation, removeLabelmapRepresentation, removeContourRepresentation, removeSurfaceRepresentation, removeSegmentationRepresentation, removeAllSegmentationRepresentations, removeAllSegmentations, addColorLUT, addSegmentations, updateLabelmapSegmentationImageReferences, getSegmentationRepresentationsBySegmentationId, destroy, };
@@ -1,5 +1,5 @@
1
1
  import { AnnotationTool } from '../base';
2
- import { getEnabledElement, VolumeViewport, utilities as csUtils, getEnabledElementByViewportId, } from '@cornerstonejs/core';
2
+ import { getEnabledElement, VolumeViewport, utilities as csUtils, getEnabledElementByViewportId, EPSILON, } from '@cornerstonejs/core';
3
3
  import { getCalibratedAspect, getCalibratedLengthUnitsAndScale, } from '../../utilities/getCalibratedUnits';
4
4
  import throttle from '../../utilities/throttle';
5
5
  import { addAnnotation, getAnnotations, removeAnnotation, } from '../../stateManagement/annotation/annotationState';
@@ -507,11 +507,14 @@ class CircleROITool extends AnnotationTool {
507
507
  (topLeftWorld[1] + bottomRightWorld[1]) / 2,
508
508
  (topLeftWorld[2] + bottomRightWorld[2]) / 2,
509
509
  ];
510
+ const xRadius = Math.abs(topLeftWorld[0] - bottomRightWorld[0]) / 2;
511
+ const yRadius = Math.abs(topLeftWorld[1] - bottomRightWorld[1]) / 2;
512
+ const zRadius = Math.abs(topLeftWorld[2] - bottomRightWorld[2]) / 2;
510
513
  const ellipseObj = {
511
514
  center,
512
- xRadius: Math.abs(topLeftWorld[0] - bottomRightWorld[0]) / 2,
513
- yRadius: Math.abs(topLeftWorld[1] - bottomRightWorld[1]) / 2,
514
- zRadius: Math.abs(topLeftWorld[2] - bottomRightWorld[2]) / 2,
515
+ xRadius: xRadius < EPSILON / 2 ? 0 : xRadius,
516
+ yRadius: yRadius < EPSILON / 2 ? 0 : yRadius,
517
+ zRadius: zRadius < EPSILON / 2 ? 0 : zRadius,
515
518
  };
516
519
  const { worldWidth, worldHeight } = getWorldWidthAndHeightFromTwoPoints(viewPlaneNormal, viewUp, worldPos1, worldPos2);
517
520
  const isEmptyArea = worldWidth === 0 && worldHeight === 0;
@@ -2,6 +2,7 @@ import { cache, utilities as csUtils, getEnabledElement, } from '@cornerstonejs/
2
2
  import { growCut } from '../../utilities/segmentation';
3
3
  import GrowCutBaseTool from '../base/GrowCutBaseTool';
4
4
  import { calculateGrowCutSeeds } from '../../utilities/segmentation/growCut/runOneClickGrowCut';
5
+ import { ToolModes } from '../../enums';
5
6
  class RegionSegmentPlusTool extends GrowCutBaseTool {
6
7
  static { this.toolName = 'RegionSegmentPlus'; }
7
8
  constructor(toolProps = {}, defaultToolProps = {
@@ -21,6 +22,9 @@ class RegionSegmentPlusTool extends GrowCutBaseTool {
21
22
  this.allowedToProceed = false;
22
23
  }
23
24
  mouseMoveCallback(evt) {
25
+ if (this.mode !== ToolModes.Active) {
26
+ return;
27
+ }
24
28
  const eventData = evt.detail;
25
29
  const { currentPoints, element } = eventData;
26
30
  const { world: worldPoint } = currentPoints;
@@ -36,7 +40,10 @@ class RegionSegmentPlusTool extends GrowCutBaseTool {
36
40
  async onMouseStable(evt, worldPoint, element) {
37
41
  await super.preMouseDownCallback(evt);
38
42
  const refVolume = cache.getVolume(this.growCutData.segmentation.referencedVolumeId);
39
- const seeds = calculateGrowCutSeeds(refVolume, worldPoint, {});
43
+ const seeds = calculateGrowCutSeeds(refVolume, worldPoint, {}) || {
44
+ positiveSeedIndices: new Set(),
45
+ negativeSeedIndices: new Set(),
46
+ };
40
47
  const { positiveSeedIndices, negativeSeedIndices } = seeds;
41
48
  let cursor;
42
49
  if (positiveSeedIndices.size / negativeSeedIndices.size > 20 ||
@@ -172,6 +172,9 @@ function _setLabelmapColorAndOpacity(viewportId, labelmapActorEntry, segmentatio
172
172
  : outlineWidth;
173
173
  }
174
174
  labelmapActor.getProperty().setLabelOutlineThickness(outlineWidths);
175
+ labelmapActor.modified();
176
+ labelmapActor.getProperty().modified();
177
+ labelmapActor.getMapper().modified();
175
178
  }
176
179
  else {
177
180
  labelmapActor
@@ -1,10 +1,11 @@
1
1
  import { getEnabledElement } from '@cornerstonejs/core';
2
- import { getSurfaceActorUID } from '../../../stateManagement/segmentation/helpers/getSegmentationActor';
3
2
  function removeSurfaceFromElement(element, segmentationId) {
4
3
  const enabledElement = getEnabledElement(element);
5
4
  const { viewport } = enabledElement;
6
5
  const actorEntries = viewport.getActors();
7
- const filteredSurfaceActors = actorEntries.filter((actor) => actor.uid.startsWith(getSurfaceActorUID(viewport.id, segmentationId, '')));
6
+ const filteredSurfaceActors = actorEntries.filter((actor) => actor.representationUID &&
7
+ typeof actor.representationUID === 'string' &&
8
+ actor.representationUID.startsWith(segmentationId));
8
9
  viewport.removeActors(filteredSurfaceActors.map((actor) => actor.uid));
9
10
  }
10
11
  export default removeSurfaceFromElement;
@@ -200,8 +200,8 @@ class BrushTool extends LabelmapBaseTool {
200
200
  const operationData = this.getOperationData(element);
201
201
  if (!this._previewData.preview && !this._previewData.isDrag) {
202
202
  this.applyActiveStrategy(enabledElement, operationData);
203
- this.doneEditMemo();
204
203
  }
204
+ this.doneEditMemo();
205
205
  this._deactivateDraw(element);
206
206
  resetElementCursor(element);
207
207
  this.updateCursor(evt);
@@ -1,4 +1,4 @@
1
1
  declare function generateContourSetsFromLabelmap({ segmentations }: {
2
2
  segmentations: any;
3
- }): any[];
3
+ }): Promise<any>;
4
4
  export { generateContourSetsFromLabelmap };
@@ -1,111 +1,91 @@
1
- import { cache as cornerstoneCache } from '@cornerstonejs/core';
2
- import vtkImageMarchingSquares from '@kitware/vtk.js/Filters/General/ImageMarchingSquares';
3
- import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
4
- import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
5
- import { getDeduplicatedVTKPolyDataPoints } from './getDeduplicatedVTKPolyDataPoints';
6
- import { findContoursFromReducedSet } from './contourFinder';
1
+ import { cache as cornerstoneCache, getWebWorkerManager, cache, utilities, } from '@cornerstonejs/core';
7
2
  import SegmentationRepresentations from '../../enums/SegmentationRepresentations';
3
+ import { WorkerTypes } from '../../enums';
4
+ import { registerComputeWorker } from '../registerComputeWorker';
5
+ import { triggerWorkerProgress } from '../segmentation/utilsForWorker';
6
+ import getOrCreateSegmentationVolume from '../segmentation/getOrCreateSegmentationVolume';
8
7
  const { Labelmap } = SegmentationRepresentations;
9
- function generateContourSetsFromLabelmap({ segmentations }) {
10
- console.warn('Deprecation Alert: This function will be removed in a future version of Cornerstone Tools. Please use the worker version of this function in computeWorker.');
11
- const { representationData, segments = [0, 1] } = segmentations;
12
- const { volumeId: segVolumeId } = representationData[Labelmap];
8
+ async function generateContourSetsFromLabelmap({ segmentations }) {
9
+ registerComputeWorker();
10
+ triggerWorkerProgress(WorkerTypes.GENERATE_CONTOUR_SETS, 0);
11
+ const { representationData, segments = [0, 1], segmentationId, } = segmentations;
12
+ let { volumeId: segVolumeId } = representationData[Labelmap];
13
+ if (!segVolumeId) {
14
+ const segVolume = getOrCreateSegmentationVolume(segmentationId);
15
+ if (segVolume) {
16
+ segVolumeId = segVolume.volumeId;
17
+ }
18
+ }
13
19
  const vol = cornerstoneCache.getVolume(segVolumeId);
14
20
  if (!vol) {
15
21
  console.warn(`No volume found for ${segVolumeId}`);
16
22
  return;
17
23
  }
18
24
  const voxelManager = vol.voxelManager;
19
- const segData = voxelManager.getCompleteScalarDataArray();
20
- const numSlices = vol.dimensions[2];
21
- const pixelsPerSlice = vol.dimensions[0] * vol.dimensions[1];
22
- for (let z = 0; z < numSlices; z++) {
23
- for (let y = 0; y < vol.dimensions[1]; y++) {
24
- const index = y * vol.dimensions[0] + z * pixelsPerSlice;
25
- segData[index] = 0;
26
- segData[index + vol.dimensions[0] - 1] = 0;
27
- }
28
- }
29
- const ContourSets = [];
30
- const { FrameOfReferenceUID } = vol.metadata;
31
- const numSegments = segments.length;
32
- for (let segIndex = 0; segIndex < numSegments; segIndex++) {
33
- const segment = segments[segIndex];
34
- if (!segment) {
35
- continue;
25
+ const segScalarData = voxelManager.getCompleteScalarDataArray();
26
+ const segmentationInfo = {
27
+ scalarData: segScalarData,
28
+ dimensions: vol.dimensions,
29
+ spacing: vol.imageData.getSpacing(),
30
+ origin: vol.imageData.getOrigin(),
31
+ direction: vol.imageData.getDirection(),
32
+ };
33
+ const indices = Array.isArray(segments)
34
+ ? segments
35
+ .filter((segment) => segment !== null)
36
+ .map((segment) => segment.segmentIndex || segment)
37
+ : Object.values(segments)
38
+ .filter((segment) => segment !== null)
39
+ .map((segment) => segment.segmentIndex || segment);
40
+ const contourSets = await getWebWorkerManager().executeTask('compute', 'generateContourSetsFromLabelmapVolume', {
41
+ segmentation: segmentationInfo,
42
+ indices,
43
+ mode: 'individual',
44
+ });
45
+ const refImages = vol.imageIds.map((imageId) => {
46
+ const refImageId = cache.getImage(imageId)?.referencedImageId;
47
+ return refImageId ? cache.getImage(refImageId) : undefined;
48
+ });
49
+ const refImageDataMetadata = refImages.map((image) => {
50
+ return utilities.getImageDataMetadata(image);
51
+ });
52
+ const processedContourSets = contourSets
53
+ .map((contourSet) => {
54
+ const segment = segments[contourSet.segment.segmentIndex] || {};
55
+ if (!contourSet.sliceContours.length) {
56
+ return null;
36
57
  }
37
- const sliceContours = [];
38
- const scalars = vtkDataArray.newInstance({
39
- name: 'Scalars',
40
- numberOfComponents: 1,
41
- size: pixelsPerSlice * numSlices,
42
- dataType: 'Uint8Array',
43
- });
44
- const { containedSegmentIndices } = segment;
45
- for (let sliceIndex = 0; sliceIndex < numSlices; sliceIndex++) {
46
- if (isSliceEmptyForSegment(sliceIndex, segData, pixelsPerSlice, segIndex)) {
47
- continue;
48
- }
49
- const frameStart = sliceIndex * pixelsPerSlice;
50
- try {
51
- for (let i = 0; i < pixelsPerSlice; i++) {
52
- const value = segData[i + frameStart];
53
- if (value === segIndex || containedSegmentIndices?.has(value)) {
54
- scalars.setValue(i + frameStart, 1);
55
- }
56
- else {
57
- scalars.setValue(i, 0);
58
- }
59
- }
60
- const mSquares = vtkImageMarchingSquares.newInstance({
61
- slice: sliceIndex,
62
- });
63
- const imageDataCopy = vtkImageData.newInstance();
64
- imageDataCopy.shallowCopy(vol.imageData);
65
- imageDataCopy.getPointData().setScalars(scalars);
66
- mSquares.setInputData(imageDataCopy);
67
- const cValues = [1];
68
- mSquares.setContourValues(cValues);
69
- mSquares.setMergePoints(false);
70
- const msOutput = mSquares.getOutputData();
71
- const reducedSet = getDeduplicatedVTKPolyDataPoints(msOutput);
72
- if (reducedSet.points?.length) {
73
- const contours = findContoursFromReducedSet(reducedSet.lines);
74
- sliceContours.push({
75
- contours,
76
- polyData: reducedSet,
77
- FrameNumber: sliceIndex + 1,
78
- sliceIndex,
79
- FrameOfReferenceUID,
80
- });
81
- }
82
- }
83
- catch (e) {
84
- console.warn(sliceIndex);
85
- console.warn(e);
58
+ const p1 = contourSet.sliceContours[0].polyData.points[0];
59
+ let refImageId;
60
+ if (p1) {
61
+ const refImageIndex = refImageDataMetadata.findIndex((imageDataMetadata) => {
62
+ const { scanAxisNormal, origin } = imageDataMetadata;
63
+ const plane = utilities.planar.planeEquation(scanAxisNormal, origin);
64
+ return utilities.planar.isPointOnPlane(p1, plane);
65
+ });
66
+ if (refImageIndex !== -1) {
67
+ refImageId = refImages[refImageIndex].imageId;
86
68
  }
87
69
  }
88
- const metadata = {
89
- FrameOfReferenceUID,
90
- };
91
- const ContourSet = {
70
+ return {
92
71
  label: segment.label,
93
72
  color: segment.color,
94
- metadata,
95
- sliceContours,
73
+ metadata: {
74
+ FrameOfReferenceUID: vol.metadata.FrameOfReferenceUID,
75
+ referencedImageId: refImageId,
76
+ },
77
+ sliceContours: contourSet.sliceContours.map((contourData) => ({
78
+ contours: contourData.contours,
79
+ polyData: contourData.polyData,
80
+ FrameNumber: contourData.sliceIndex + 1,
81
+ sliceIndex: contourData.sliceIndex,
82
+ FrameOfReferenceUID: vol.metadata.FrameOfReferenceUID,
83
+ referencedImageId: refImageId,
84
+ })),
96
85
  };
97
- ContourSets.push(ContourSet);
98
- }
99
- return ContourSets;
100
- }
101
- function isSliceEmptyForSegment(sliceIndex, segData, pixelsPerSlice, segIndex) {
102
- const startIdx = sliceIndex * pixelsPerSlice;
103
- const endIdx = startIdx + pixelsPerSlice;
104
- for (let i = startIdx; i < endIdx; i++) {
105
- if (segData[i] === segIndex) {
106
- return false;
107
- }
108
- }
109
- return true;
86
+ })
87
+ .filter((contourSet) => contourSet !== null);
88
+ triggerWorkerProgress(WorkerTypes.GENERATE_CONTOUR_SETS, 100);
89
+ return processedContourSets;
110
90
  }
111
91
  export { generateContourSetsFromLabelmap };
@@ -39,4 +39,5 @@ import { getPixelValueUnits, getPixelValueUnitsImageId } from './getPixelValueUn
39
39
  import * as geometricSurfaceUtils from './geometricSurfaceUtils';
40
40
  import setAnnotationLabel from './setAnnotationLabel';
41
41
  import { moveAnnotationToViewPlane } from './moveAnnotationToViewPlane';
42
- export { math, planar, viewportFilters, drawing, debounce, dynamicVolume, throttle, orientation, isObject, touch, triggerEvent, calibrateImageSpacing, getCalibratedLengthUnitsAndScale, getCalibratedProbeUnitsAndValue, getCalibratedAspect, getPixelValueUnits, getPixelValueUnitsImageId, segmentation, contours, triggerAnnotationRenderForViewportIds, triggerAnnotationRenderForToolGroupIds, triggerAnnotationRender, getSphereBoundsInfo, getAnnotationNearPoint, getViewportForAnnotation, getAnnotationNearPointOnEnabledElement, viewport, cine, boundingBox, rectangleROITool, planarFreehandROITool, stackPrefetch, stackContextPrefetch, roundNumber, pointToString, polyDataUtils, voi, AnnotationMultiSlice, contourSegmentation, annotationHydration, getClosestImageIdForStackViewport, pointInSurroundingSphereCallback, normalizeViewportPlane, IslandRemoval, geometricSurfaceUtils, setAnnotationLabel, moveAnnotationToViewPlane, };
42
+ import getOrCreateImageVolume from './segmentation/getOrCreateImageVolume';
43
+ export { math, planar, viewportFilters, drawing, debounce, dynamicVolume, throttle, orientation, isObject, touch, triggerEvent, calibrateImageSpacing, getCalibratedLengthUnitsAndScale, getCalibratedProbeUnitsAndValue, getCalibratedAspect, getPixelValueUnits, getPixelValueUnitsImageId, segmentation, contours, triggerAnnotationRenderForViewportIds, triggerAnnotationRenderForToolGroupIds, triggerAnnotationRender, getSphereBoundsInfo, getAnnotationNearPoint, getViewportForAnnotation, getAnnotationNearPointOnEnabledElement, viewport, cine, boundingBox, rectangleROITool, planarFreehandROITool, stackPrefetch, stackContextPrefetch, roundNumber, pointToString, polyDataUtils, voi, AnnotationMultiSlice, contourSegmentation, annotationHydration, getClosestImageIdForStackViewport, pointInSurroundingSphereCallback, normalizeViewportPlane, IslandRemoval, geometricSurfaceUtils, setAnnotationLabel, moveAnnotationToViewPlane, getOrCreateImageVolume, };
@@ -39,4 +39,5 @@ import { getPixelValueUnits, getPixelValueUnitsImageId, } from './getPixelValueU
39
39
  import * as geometricSurfaceUtils from './geometricSurfaceUtils';
40
40
  import setAnnotationLabel from './setAnnotationLabel';
41
41
  import { moveAnnotationToViewPlane } from './moveAnnotationToViewPlane';
42
- export { math, planar, viewportFilters, drawing, debounce, dynamicVolume, throttle, orientation, isObject, touch, triggerEvent, calibrateImageSpacing, getCalibratedLengthUnitsAndScale, getCalibratedProbeUnitsAndValue, getCalibratedAspect, getPixelValueUnits, getPixelValueUnitsImageId, segmentation, contours, triggerAnnotationRenderForViewportIds, triggerAnnotationRenderForToolGroupIds, triggerAnnotationRender, getSphereBoundsInfo, getAnnotationNearPoint, getViewportForAnnotation, getAnnotationNearPointOnEnabledElement, viewport, cine, boundingBox, rectangleROITool, planarFreehandROITool, stackPrefetch, stackContextPrefetch, roundNumber, pointToString, polyDataUtils, voi, AnnotationMultiSlice, contourSegmentation, annotationHydration, getClosestImageIdForStackViewport, pointInSurroundingSphereCallback, normalizeViewportPlane, IslandRemoval, geometricSurfaceUtils, setAnnotationLabel, moveAnnotationToViewPlane, };
42
+ import getOrCreateImageVolume from './segmentation/getOrCreateImageVolume';
43
+ export { math, planar, viewportFilters, drawing, debounce, dynamicVolume, throttle, orientation, isObject, touch, triggerEvent, calibrateImageSpacing, getCalibratedLengthUnitsAndScale, getCalibratedProbeUnitsAndValue, getCalibratedAspect, getPixelValueUnits, getPixelValueUnitsImageId, segmentation, contours, triggerAnnotationRenderForViewportIds, triggerAnnotationRenderForToolGroupIds, triggerAnnotationRender, getSphereBoundsInfo, getAnnotationNearPoint, getViewportForAnnotation, getAnnotationNearPointOnEnabledElement, viewport, cine, boundingBox, rectangleROITool, planarFreehandROITool, stackPrefetch, stackContextPrefetch, roundNumber, pointToString, polyDataUtils, voi, AnnotationMultiSlice, contourSegmentation, annotationHydration, getClosestImageIdForStackViewport, pointInSurroundingSphereCallback, normalizeViewportPlane, IslandRemoval, geometricSurfaceUtils, setAnnotationLabel, moveAnnotationToViewPlane, getOrCreateImageVolume, };
@@ -48,6 +48,15 @@ async function calculateForVolume({ segmentationIds, segmentIndex }) {
48
48
  direction: referenceVolume.direction,
49
49
  scalarData: referenceVolume.voxelManager.getCompleteScalarDataArray(),
50
50
  };
51
+ if (imageInfo.scalarData.length === 0 ||
52
+ segmentationInfo.scalarData.length === 0) {
53
+ return {
54
+ [segmentIndex]: {
55
+ name: 'TMTV',
56
+ value: 0,
57
+ },
58
+ };
59
+ }
51
60
  const stats = await getWebWorkerManager().executeTask('compute', 'computeMetabolicStats', {
52
61
  segmentationInfo,
53
62
  imageInfo,
@@ -1 +1 @@
1
- export default function contourAndFindLargestBidirectional(segmentation: any): any;
1
+ export default function contourAndFindLargestBidirectional(segmentation: any): Promise<any>;
@@ -1,8 +1,8 @@
1
1
  import { generateContourSetsFromLabelmap } from '../contours';
2
2
  import findLargestBidirectional from './findLargestBidirectional';
3
3
  import getOrCreateSegmentationVolume from './getOrCreateSegmentationVolume';
4
- export default function contourAndFindLargestBidirectional(segmentation) {
5
- const contours = generateContourSetsFromLabelmap({
4
+ export default async function contourAndFindLargestBidirectional(segmentation) {
5
+ const contours = await generateContourSetsFromLabelmap({
6
6
  segmentations: segmentation,
7
7
  });
8
8
  if (!contours?.length || !contours[0].sliceContours.length) {
@@ -13,5 +13,5 @@ export type SegmentContourActionConfiguration = {
13
13
  segmentData?: Map<number, Segment>;
14
14
  toolGroupId?: string;
15
15
  };
16
- export default function segmentContourAction(element: HTMLDivElement, configuration: any): any;
16
+ export default function segmentContourAction(element: HTMLDivElement, configuration: any): Promise<any>;
17
17
  export declare function defaultGetSegment(enabledElement: Types.IEnabledElement, configuration: SegmentContourActionConfiguration): Segment;
@@ -5,7 +5,7 @@ import createBidirectionalToolData from './createBidirectionalToolData';
5
5
  import BidirectionalTool from '../../tools/annotation/BidirectionalTool';
6
6
  import { getSegmentations } from '../../stateManagement/segmentation/getSegmentations';
7
7
  import { getActiveSegmentIndex } from '../../stateManagement/segmentation/getActiveSegmentIndex';
8
- export default function segmentContourAction(element, configuration) {
8
+ export default async function segmentContourAction(element, configuration) {
9
9
  console.warn('Deprecation Alert: There is a new getSegmentLargestBidirectional function that handles volume, stack and individual segment cases properly. This function is deprecated and will be removed in a future version.');
10
10
  const { data: configurationData } = configuration;
11
11
  const enabledElement = getEnabledElement(element);
@@ -36,13 +36,14 @@ export default function segmentContourAction(element, configuration) {
36
36
  });
37
37
  }
38
38
  let newBidirectional;
39
- existingLargestBidirectionals.forEach((existingLargestBidirectional) => {
39
+ existingLargestBidirectionals.forEach(async (existingLargestBidirectional) => {
40
40
  const segments = [];
41
- const updateSegment = existingLargestBidirectional.data.segment;
41
+ const updateSegment = existingLargestBidirectional.data
42
+ .segment;
42
43
  const { segmentIndex, segmentationId } = updateSegment;
43
44
  segments[segmentIndex] = updateSegment;
44
45
  annotationState.removeAnnotation(existingLargestBidirectional.annotationUID);
45
- const bidirectionalData = contourAndFindLargestBidirectional({
46
+ const bidirectionalData = await contourAndFindLargestBidirectional({
46
47
  ...segmentationsList.find((segmentation) => segmentation.segmentationId === segmentationId),
47
48
  segments,
48
49
  });
@@ -84,6 +84,9 @@ export const prepareStackDataForWorker = (segImageIds) => {
84
84
  const refImageId = segImage.referencedImageId;
85
85
  if (refImageId) {
86
86
  const refImage = cache.getImage(refImageId);
87
+ if (!refImage) {
88
+ continue;
89
+ }
87
90
  const refPixelData = refImage.getPixelData();
88
91
  const refVoxelManager = refImage.voxelManager;
89
92
  const refSpacing = [
@@ -305,8 +305,12 @@ const computeWorker = {
305
305
  return bidirectionalResults;
306
306
  },
307
307
  generateContourSetsFromLabelmapVolume: (args) => {
308
- const { segmentation, indices, imageData } = args;
309
- const { voxelManager, dimensions, scalarData, origin, direction, spacing } = segmentation;
308
+ const { segmentation, indices } = args;
309
+ const { dimensions, scalarData, origin, direction, spacing } = segmentation;
310
+ let imageData = args.imageData;
311
+ if (!imageData) {
312
+ imageData = computeWorker.createVTKImageData(dimensions, origin, direction, spacing);
313
+ }
310
314
  const numSlices = dimensions[2];
311
315
  const pixelsPerSlice = dimensions[0] * dimensions[1];
312
316
  const segments = computeWorker.createSegmentsFromIndices(indices);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "3.8.3",
3
+ "version": "3.8.5",
4
4
  "description": "Cornerstone3D Tools",
5
5
  "types": "./dist/esm/index.d.ts",
6
6
  "module": "./dist/esm/index.js",
@@ -103,7 +103,7 @@
103
103
  "canvas": "^3.1.0"
104
104
  },
105
105
  "peerDependencies": {
106
- "@cornerstonejs/core": "^3.8.3",
106
+ "@cornerstonejs/core": "^3.8.5",
107
107
  "@kitware/vtk.js": "32.12.1",
108
108
  "@types/d3-array": "^3.0.4",
109
109
  "@types/d3-interpolate": "^3.0.1",
@@ -122,5 +122,5 @@
122
122
  "type": "individual",
123
123
  "url": "https://ohif.org/donate"
124
124
  },
125
- "gitHead": "f4dd844bc47c06493547a4754c955e6854475d3f"
125
+ "gitHead": "782551a1523d3619fa002b9b5bb2991519fb5f40"
126
126
  }