@cornerstonejs/tools 2.5.3 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/enums/StrategyCallbacks.d.ts +1 -0
- package/dist/esm/enums/StrategyCallbacks.js +1 -0
- package/dist/esm/tools/annotation/DragProbeTool.js +2 -1
- package/dist/esm/tools/annotation/LivewireContourTool.js +1 -1
- package/dist/esm/tools/annotation/PlanarFreehandROITool.d.ts +3 -3
- package/dist/esm/tools/annotation/ProbeTool.d.ts +13 -3
- package/dist/esm/tools/annotation/ProbeTool.js +10 -9
- package/dist/esm/tools/annotation/SplineROITool.d.ts +2 -2
- package/dist/esm/tools/base/AnnotationDisplayTool.d.ts +2 -1
- package/dist/esm/tools/base/AnnotationDisplayTool.js +40 -1
- package/dist/esm/tools/base/BaseTool.d.ts +10 -0
- package/dist/esm/tools/base/BaseTool.js +20 -8
- package/dist/esm/tools/base/ContourBaseTool.d.ts +1 -1
- package/dist/esm/tools/base/ContourBaseTool.js +9 -39
- package/dist/esm/tools/base/ContourSegmentationBaseTool.d.ts +2 -1
- package/dist/esm/tools/base/ContourSegmentationBaseTool.js +0 -1
- package/dist/esm/tools/displayTools/Labelmap/addLabelmapToElement.js +1 -1
- package/dist/esm/tools/segmentation/BrushTool.d.ts +3 -108
- package/dist/esm/tools/segmentation/BrushTool.js +4 -194
- package/dist/esm/tools/segmentation/LabelmapBaseTool.d.ts +155 -0
- package/dist/esm/tools/segmentation/LabelmapBaseTool.js +218 -0
- package/dist/esm/tools/segmentation/strategies/BrushStrategy.d.ts +2 -0
- package/dist/esm/tools/segmentation/strategies/BrushStrategy.js +8 -0
- package/dist/esm/tools/segmentation/strategies/compositions/determineSegmentIndex.js +14 -1
- package/dist/esm/types/AnnotationTypes.d.ts +2 -1
- package/package.json +3 -3
|
@@ -9,6 +9,7 @@ declare enum StrategyCallbacks {
|
|
|
9
9
|
CreateIsInThreshold = "createIsInThreshold",
|
|
10
10
|
Initialize = "initialize",
|
|
11
11
|
INTERNAL_setValue = "setValue",
|
|
12
|
+
AddPreview = "addPreview",
|
|
12
13
|
ComputeInnerCircleRadius = "computeInnerCircleRadius",
|
|
13
14
|
GetStatistics = "getStatistics"
|
|
14
15
|
}
|
|
@@ -10,6 +10,7 @@ var StrategyCallbacks;
|
|
|
10
10
|
StrategyCallbacks["CreateIsInThreshold"] = "createIsInThreshold";
|
|
11
11
|
StrategyCallbacks["Initialize"] = "initialize";
|
|
12
12
|
StrategyCallbacks["INTERNAL_setValue"] = "setValue";
|
|
13
|
+
StrategyCallbacks["AddPreview"] = "addPreview";
|
|
13
14
|
StrategyCallbacks["ComputeInnerCircleRadius"] = "computeInnerCircleRadius";
|
|
14
15
|
StrategyCallbacks["GetStatistics"] = "getStatistics";
|
|
15
16
|
})(StrategyCallbacks || (StrategyCallbacks = {}));
|
|
@@ -2,6 +2,7 @@ import { getEnabledElement } from '@cornerstonejs/core';
|
|
|
2
2
|
import { drawHandles as drawHandlesSvg, drawTextBox as drawTextBoxSvg, } from '../../drawingSvg';
|
|
3
3
|
import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters';
|
|
4
4
|
import { hideElementCursor } from '../../cursors/elementCursor';
|
|
5
|
+
import { ChangeTypes, Events } from '../../enums';
|
|
5
6
|
import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
|
|
6
7
|
import ProbeTool from './ProbeTool';
|
|
7
8
|
class DragProbeTool extends ProbeTool {
|
|
@@ -84,7 +85,7 @@ class DragProbeTool extends ProbeTool {
|
|
|
84
85
|
styleSpecifier,
|
|
85
86
|
});
|
|
86
87
|
if (!data.cachedStats[targetId] ||
|
|
87
|
-
data.cachedStats[targetId].value
|
|
88
|
+
data.cachedStats[targetId].value === null) {
|
|
88
89
|
data.cachedStats[targetId] = {
|
|
89
90
|
Modality: null,
|
|
90
91
|
index: null,
|
|
@@ -605,7 +605,7 @@ class LivewireContourTool extends ContourSegmentationBaseTool {
|
|
|
605
605
|
}
|
|
606
606
|
super.renderAnnotationInstance(renderContext);
|
|
607
607
|
if (!data.cachedStats[targetId] ||
|
|
608
|
-
data.cachedStats[targetId]
|
|
608
|
+
data.cachedStats[targetId]?.areaUnit === null) {
|
|
609
609
|
data.cachedStats[targetId] = {
|
|
610
610
|
Modality: null,
|
|
611
611
|
area: null,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
|
-
import type { EventTypes, ToolHandle,
|
|
3
|
-
import type { PlanarFreehandROIAnnotation } from '../../types/ToolSpecificAnnotationTypes';
|
|
2
|
+
import type { EventTypes, ToolHandle, Annotations, PublicToolProps, ToolProps, AnnotationRenderContext } from '../../types';
|
|
3
|
+
import type { ContourAnnotation, PlanarFreehandROIAnnotation } from '../../types/ToolSpecificAnnotationTypes';
|
|
4
4
|
import ContourSegmentationBaseTool from '../base/ContourSegmentationBaseTool';
|
|
5
5
|
declare class PlanarFreehandROITool extends ContourSegmentationBaseTool {
|
|
6
6
|
static toolName: any;
|
|
@@ -30,7 +30,7 @@ declare class PlanarFreehandROITool extends ContourSegmentationBaseTool {
|
|
|
30
30
|
filterInteractableAnnotationsForElement(element: HTMLDivElement, annotations: Annotations): Annotations | undefined;
|
|
31
31
|
private filterAnnotationsWithinSlice;
|
|
32
32
|
protected isContourSegmentationTool(): boolean;
|
|
33
|
-
protected createAnnotation(evt: EventTypes.InteractionEventType):
|
|
33
|
+
protected createAnnotation(evt: EventTypes.InteractionEventType): ContourAnnotation;
|
|
34
34
|
protected getAnnotationStyle(context: any): any;
|
|
35
35
|
protected renderAnnotationInstance(renderContext: AnnotationRenderContext): boolean;
|
|
36
36
|
_calculateStatsIfActive(annotation: PlanarFreehandROIAnnotation, targetId: string, viewport: any, renderingEngine: any, enabledElement: any): void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import { AnnotationTool } from '../base';
|
|
3
|
-
import
|
|
3
|
+
import { ChangeTypes } from '../../enums';
|
|
4
|
+
import type { EventTypes, ToolHandle, PublicToolProps, SVGDrawingHelper, Annotation } from '../../types';
|
|
4
5
|
import type { ProbeAnnotation } from '../../types/ToolSpecificAnnotationTypes';
|
|
5
6
|
declare class ProbeTool extends AnnotationTool {
|
|
6
7
|
static toolName: any;
|
|
@@ -15,7 +16,15 @@ declare class ProbeTool extends AnnotationTool {
|
|
|
15
16
|
};
|
|
16
17
|
isDrawing: boolean;
|
|
17
18
|
isHandleOutsideImage: boolean;
|
|
18
|
-
|
|
19
|
+
static probeDefaults: {
|
|
20
|
+
supportedInteractionTypes: string[];
|
|
21
|
+
configuration: {
|
|
22
|
+
shadow: boolean;
|
|
23
|
+
preventHandleOutsideImage: boolean;
|
|
24
|
+
getTextLines: typeof defaultGetTextLines;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
constructor(toolProps?: PublicToolProps, defaultToolProps?: any);
|
|
19
28
|
isPointNearTool(): boolean;
|
|
20
29
|
toolSelectedCallback(): void;
|
|
21
30
|
static hydrate: (viewportId: string, points: Types.Point3[], options?: {
|
|
@@ -30,6 +39,7 @@ declare class ProbeTool extends AnnotationTool {
|
|
|
30
39
|
_activateModify: (element: any) => void;
|
|
31
40
|
_deactivateModify: (element: any) => void;
|
|
32
41
|
renderAnnotation: (enabledElement: Types.IEnabledElement, svgDrawingHelper: SVGDrawingHelper) => boolean;
|
|
33
|
-
_calculateCachedStats(annotation: any, renderingEngine: any, enabledElement: any): any;
|
|
42
|
+
_calculateCachedStats(annotation: any, renderingEngine: any, enabledElement: any, changeType?: ChangeTypes): any;
|
|
34
43
|
}
|
|
44
|
+
declare function defaultGetTextLines(data: any, targetId: any): string[];
|
|
35
45
|
export default ProbeTool;
|
|
@@ -6,7 +6,7 @@ import { triggerAnnotationCompleted, triggerAnnotationModified, } from '../../st
|
|
|
6
6
|
import { getCalibratedProbeUnitsAndValue } from '../../utilities/getCalibratedUnits';
|
|
7
7
|
import { drawHandles as drawHandlesSvg, drawTextBox as drawTextBoxSvg, } from '../../drawingSvg';
|
|
8
8
|
import { state } from '../../store/state';
|
|
9
|
-
import { Events } from '../../enums';
|
|
9
|
+
import { ChangeTypes, Events } from '../../enums';
|
|
10
10
|
import { getViewportIdsWithToolToRender } from '../../utilities/viewportFilters';
|
|
11
11
|
import { resetElementCursor, hideElementCursor, } from '../../cursors/elementCursor';
|
|
12
12
|
import triggerAnnotationRenderForViewportIds from '../../utilities/triggerAnnotationRenderForViewportIds';
|
|
@@ -14,15 +14,16 @@ import { getPixelValueUnits } from '../../utilities/getPixelValueUnits';
|
|
|
14
14
|
import { isViewportPreScaled } from '../../utilities/viewport/isViewportPreScaled';
|
|
15
15
|
const { transformWorldToIndex } = csUtils;
|
|
16
16
|
class ProbeTool extends AnnotationTool {
|
|
17
|
-
|
|
17
|
+
static { this.probeDefaults = {
|
|
18
18
|
supportedInteractionTypes: ['Mouse', 'Touch'],
|
|
19
19
|
configuration: {
|
|
20
20
|
shadow: true,
|
|
21
21
|
preventHandleOutsideImage: false,
|
|
22
22
|
getTextLines: defaultGetTextLines,
|
|
23
23
|
},
|
|
24
|
-
}
|
|
25
|
-
|
|
24
|
+
}; }
|
|
25
|
+
constructor(toolProps = {}, defaultToolProps) {
|
|
26
|
+
super(toolProps, AnnotationTool.mergeDefaultProps(ProbeTool.probeDefaults, defaultToolProps));
|
|
26
27
|
this.addNewAnnotation = (evt) => {
|
|
27
28
|
const eventDetail = evt.detail;
|
|
28
29
|
const { currentPoints, element } = eventDetail;
|
|
@@ -164,13 +165,13 @@ class ProbeTool extends AnnotationTool {
|
|
|
164
165
|
data.cachedStats = {};
|
|
165
166
|
}
|
|
166
167
|
if (!data.cachedStats[targetId] ||
|
|
167
|
-
data.cachedStats[targetId].value
|
|
168
|
+
data.cachedStats[targetId].value === null) {
|
|
168
169
|
data.cachedStats[targetId] = {
|
|
169
170
|
Modality: null,
|
|
170
171
|
index: null,
|
|
171
172
|
value: null,
|
|
172
173
|
};
|
|
173
|
-
this._calculateCachedStats(annotation, renderingEngine, enabledElement);
|
|
174
|
+
this._calculateCachedStats(annotation, renderingEngine, enabledElement, ChangeTypes.StatsUpdated);
|
|
174
175
|
}
|
|
175
176
|
else if (annotation.invalidated) {
|
|
176
177
|
this._calculateCachedStats(annotation, renderingEngine, enabledElement);
|
|
@@ -280,7 +281,7 @@ class ProbeTool extends AnnotationTool {
|
|
|
280
281
|
triggerAnnotationRenderForViewportIds(viewportIdsToRender);
|
|
281
282
|
evt.preventDefault();
|
|
282
283
|
}
|
|
283
|
-
_calculateCachedStats(annotation, renderingEngine, enabledElement) {
|
|
284
|
+
_calculateCachedStats(annotation, renderingEngine, enabledElement, changeType = ChangeTypes.StatsUpdated) {
|
|
284
285
|
const data = annotation.data;
|
|
285
286
|
const { renderingEngineId, viewport } = enabledElement;
|
|
286
287
|
const { element } = viewport;
|
|
@@ -340,7 +341,7 @@ class ProbeTool extends AnnotationTool {
|
|
|
340
341
|
};
|
|
341
342
|
}
|
|
342
343
|
annotation.invalidated = false;
|
|
343
|
-
triggerAnnotationModified(annotation, element);
|
|
344
|
+
triggerAnnotationModified(annotation, element, changeType);
|
|
344
345
|
}
|
|
345
346
|
return cachedStats;
|
|
346
347
|
}
|
|
@@ -348,7 +349,7 @@ class ProbeTool extends AnnotationTool {
|
|
|
348
349
|
function defaultGetTextLines(data, targetId) {
|
|
349
350
|
const cachedVolumeStats = data.cachedStats[targetId];
|
|
350
351
|
const { index, value, modalityUnit } = cachedVolumeStats;
|
|
351
|
-
if (value === undefined) {
|
|
352
|
+
if (value === undefined || !index) {
|
|
352
353
|
return;
|
|
353
354
|
}
|
|
354
355
|
const textLines = [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import { ChangeTypes } from '../../enums';
|
|
3
3
|
import type { Annotation, EventTypes, ToolHandle, PublicToolProps, ToolProps, AnnotationRenderContext } from '../../types';
|
|
4
|
-
import type { SplineROIAnnotation } from '../../types/ToolSpecificAnnotationTypes';
|
|
4
|
+
import type { ContourAnnotation, SplineROIAnnotation } from '../../types/ToolSpecificAnnotationTypes';
|
|
5
5
|
import ContourSegmentationBaseTool from '../base/ContourSegmentationBaseTool';
|
|
6
6
|
declare enum SplineTypesEnum {
|
|
7
7
|
Cardinal = "CARDINAL",
|
|
@@ -56,7 +56,7 @@ declare class SplineROITool extends ContourSegmentationBaseTool {
|
|
|
56
56
|
protected isContourSegmentationTool(): boolean;
|
|
57
57
|
protected renderAnnotationInstance(renderContext: AnnotationRenderContext): boolean;
|
|
58
58
|
protected createInterpolatedSplineControl(annotation: any): void;
|
|
59
|
-
protected createAnnotation(evt: EventTypes.InteractionEventType):
|
|
59
|
+
protected createAnnotation(evt: EventTypes.InteractionEventType): ContourAnnotation;
|
|
60
60
|
private _renderStats;
|
|
61
61
|
addControlPointCallback: (evt: EventTypes.InteractionEventType, annotation: SplineROIAnnotation) => void;
|
|
62
62
|
private _deleteControlPointByIndex;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import BaseTool from './BaseTool';
|
|
3
|
-
import type { Annotation, Annotations, SVGDrawingHelper } from '../../types';
|
|
3
|
+
import type { Annotation, Annotations, EventTypes, SVGDrawingHelper } from '../../types';
|
|
4
4
|
import type { StyleSpecifier } from '../../types/AnnotationStyle';
|
|
5
5
|
declare abstract class AnnotationDisplayTool extends BaseTool {
|
|
6
6
|
static toolName: any;
|
|
7
7
|
abstract renderAnnotation(enabledElement: Types.IEnabledElement, svgDrawingHelper: SVGDrawingHelper): any;
|
|
8
8
|
filterInteractableAnnotationsForElement(element: HTMLDivElement, annotations: Annotations): Annotations | undefined;
|
|
9
9
|
onImageSpacingCalibrated: (evt: Types.EventTypes.ImageSpacingCalibratedEvent) => void;
|
|
10
|
+
protected createAnnotation(evt: EventTypes.InteractionEventType): Annotation;
|
|
10
11
|
protected getReferencedImageId(viewport: Types.IViewport, worldPos: Types.Point3, viewPlaneNormal: Types.Point3, viewUp?: Types.Point3): string;
|
|
11
12
|
getStyle(property: string, specifications: StyleSpecifier, annotation?: Annotation): unknown;
|
|
12
13
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { utilities, getEnabledElement,
|
|
1
|
+
import { utilities, getEnabledElement, cache, BaseVolumeViewport, } from '@cornerstonejs/core';
|
|
2
2
|
import BaseTool from './BaseTool';
|
|
3
3
|
import { getAnnotationManager } from '../../stateManagement/annotation/annotationState';
|
|
4
4
|
import triggerAnnotationRender from '../../utilities/triggerAnnotationRender';
|
|
@@ -41,6 +41,45 @@ class AnnotationDisplayTool extends BaseTool {
|
|
|
41
41
|
const { viewport } = enabledElement;
|
|
42
42
|
return filterAnnotationsForDisplay(viewport, annotations);
|
|
43
43
|
}
|
|
44
|
+
createAnnotation(evt) {
|
|
45
|
+
const eventDetail = evt.detail;
|
|
46
|
+
const { currentPoints, element } = eventDetail;
|
|
47
|
+
const { world: worldPos } = currentPoints;
|
|
48
|
+
const enabledElement = getEnabledElement(element);
|
|
49
|
+
const { viewport } = enabledElement;
|
|
50
|
+
const camera = viewport.getCamera();
|
|
51
|
+
const { viewPlaneNormal, viewUp, position: cameraPosition } = camera;
|
|
52
|
+
const referencedImageId = this.getReferencedImageId(viewport, worldPos, viewPlaneNormal, viewUp);
|
|
53
|
+
const viewReference = viewport.getViewReference({ points: [worldPos] });
|
|
54
|
+
return {
|
|
55
|
+
highlighted: true,
|
|
56
|
+
invalidated: true,
|
|
57
|
+
metadata: {
|
|
58
|
+
toolName: this.getToolName(),
|
|
59
|
+
...viewReference,
|
|
60
|
+
referencedImageId,
|
|
61
|
+
viewUp,
|
|
62
|
+
cameraPosition,
|
|
63
|
+
},
|
|
64
|
+
data: {
|
|
65
|
+
cachedStats: {},
|
|
66
|
+
handles: {
|
|
67
|
+
points: [],
|
|
68
|
+
activeHandleIndex: null,
|
|
69
|
+
textBox: {
|
|
70
|
+
hasMoved: false,
|
|
71
|
+
worldPosition: [0, 0, 0],
|
|
72
|
+
worldBoundingBox: {
|
|
73
|
+
topLeft: [0, 0, 0],
|
|
74
|
+
topRight: [0, 0, 0],
|
|
75
|
+
bottomLeft: [0, 0, 0],
|
|
76
|
+
bottomRight: [0, 0, 0],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
44
83
|
getReferencedImageId(viewport, worldPos, viewPlaneNormal, viewUp) {
|
|
45
84
|
const targetId = this.getTargetId(viewport);
|
|
46
85
|
let referencedImageId = targetId.split(/^[a-zA-Z]+:/)[1];
|
|
@@ -10,7 +10,17 @@ declare abstract class BaseTool {
|
|
|
10
10
|
toolGroupId: string;
|
|
11
11
|
mode: ToolModes;
|
|
12
12
|
protected memo: utilities.HistoryMemo.Memo;
|
|
13
|
+
static defaults: {
|
|
14
|
+
configuration: {
|
|
15
|
+
strategies: {};
|
|
16
|
+
defaultStrategy: any;
|
|
17
|
+
activeStrategy: any;
|
|
18
|
+
strategyOptions: {};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
13
21
|
constructor(toolProps: PublicToolProps, defaultToolProps: ToolProps);
|
|
22
|
+
static mergeDefaultProps(defaultProps?: {}, additionalProps?: any): any;
|
|
23
|
+
get toolName(): string;
|
|
14
24
|
getToolName(): string;
|
|
15
25
|
applyActiveStrategy(enabledElement: Types.IEnabledElement, operationData: unknown): any;
|
|
16
26
|
applyActiveStrategyCallback(enabledElement: Types.IEnabledElement, operationData: unknown, callbackType: StrategyCallbacks | string, ...extraArgs: any[]): any;
|
|
@@ -1,21 +1,33 @@
|
|
|
1
|
-
import { utilities
|
|
1
|
+
import { utilities } from '@cornerstonejs/core';
|
|
2
2
|
import ToolModes from '../../enums/ToolModes';
|
|
3
3
|
const { DefaultHistoryMemo } = utilities.HistoryMemo;
|
|
4
4
|
class BaseTool {
|
|
5
|
+
static { this.defaults = {
|
|
6
|
+
configuration: {
|
|
7
|
+
strategies: {},
|
|
8
|
+
defaultStrategy: undefined,
|
|
9
|
+
activeStrategy: undefined,
|
|
10
|
+
strategyOptions: {},
|
|
11
|
+
},
|
|
12
|
+
}; }
|
|
5
13
|
constructor(toolProps, defaultToolProps) {
|
|
6
|
-
const
|
|
14
|
+
const mergedDefaults = BaseTool.mergeDefaultProps(BaseTool.defaults, defaultToolProps);
|
|
15
|
+
const initialProps = utilities.deepMerge(mergedDefaults, toolProps);
|
|
7
16
|
const { configuration = {}, supportedInteractionTypes, toolGroupId, } = initialProps;
|
|
8
|
-
if (!configuration.strategies) {
|
|
9
|
-
configuration.strategies = {};
|
|
10
|
-
configuration.defaultStrategy = undefined;
|
|
11
|
-
configuration.activeStrategy = undefined;
|
|
12
|
-
configuration.strategyOptions = {};
|
|
13
|
-
}
|
|
14
17
|
this.toolGroupId = toolGroupId;
|
|
15
18
|
this.supportedInteractionTypes = supportedInteractionTypes || [];
|
|
16
19
|
this.configuration = Object.assign({}, configuration);
|
|
17
20
|
this.mode = ToolModes.Disabled;
|
|
18
21
|
}
|
|
22
|
+
static mergeDefaultProps(defaultProps = {}, additionalProps) {
|
|
23
|
+
if (!additionalProps) {
|
|
24
|
+
return defaultProps;
|
|
25
|
+
}
|
|
26
|
+
return utilities.deepMerge(defaultProps, additionalProps);
|
|
27
|
+
}
|
|
28
|
+
get toolName() {
|
|
29
|
+
return this.getToolName();
|
|
30
|
+
}
|
|
19
31
|
getToolName() {
|
|
20
32
|
return this.constructor.toolName;
|
|
21
33
|
}
|
|
@@ -5,7 +5,7 @@ import type { ContourWindingDirection } from '../../types/ContourAnnotation';
|
|
|
5
5
|
declare abstract class ContourBaseTool extends AnnotationTool {
|
|
6
6
|
constructor(toolProps: PublicToolProps, defaultToolProps: ToolProps);
|
|
7
7
|
renderAnnotation(enabledElement: Types.IEnabledElement, svgDrawingHelper: SVGDrawingHelper): boolean;
|
|
8
|
-
protected createAnnotation(evt: EventTypes.InteractionEventType):
|
|
8
|
+
protected createAnnotation(evt: EventTypes.InteractionEventType): ContourAnnotation;
|
|
9
9
|
protected addAnnotation(annotation: Annotation, element: HTMLDivElement): string;
|
|
10
10
|
protected cancelAnnotation(annotation: Annotation): void;
|
|
11
11
|
protected moveAnnotation(annotation: Annotation, worldPosDelta: Types.Point3): void;
|
|
@@ -53,48 +53,18 @@ class ContourBaseTool extends AnnotationTool {
|
|
|
53
53
|
return renderStatus;
|
|
54
54
|
}
|
|
55
55
|
createAnnotation(evt) {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const camera = viewport.getCamera();
|
|
62
|
-
const { viewPlaneNormal, viewUp, position: cameraPosition } = camera;
|
|
63
|
-
const referencedImageId = this.getReferencedImageId(viewport, worldPos, viewPlaneNormal, viewUp);
|
|
64
|
-
const viewReference = viewport.getViewReference({ points: [worldPos] });
|
|
65
|
-
return {
|
|
66
|
-
highlighted: true,
|
|
67
|
-
invalidated: true,
|
|
68
|
-
metadata: {
|
|
69
|
-
toolName: this.getToolName(),
|
|
70
|
-
...viewReference,
|
|
71
|
-
referencedImageId,
|
|
72
|
-
viewUp,
|
|
73
|
-
cameraPosition,
|
|
74
|
-
},
|
|
75
|
-
data: {
|
|
76
|
-
handles: {
|
|
77
|
-
points: [],
|
|
78
|
-
activeHandleIndex: null,
|
|
79
|
-
textBox: {
|
|
80
|
-
hasMoved: false,
|
|
81
|
-
worldPosition: [0, 0, 0],
|
|
82
|
-
worldBoundingBox: {
|
|
83
|
-
topLeft: [0, 0, 0],
|
|
84
|
-
topRight: [0, 0, 0],
|
|
85
|
-
bottomLeft: [0, 0, 0],
|
|
86
|
-
bottomRight: [0, 0, 0],
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
contour: {
|
|
91
|
-
polyline: [],
|
|
92
|
-
closed: false,
|
|
93
|
-
},
|
|
56
|
+
const annotation = super.createAnnotation(evt);
|
|
57
|
+
Object.assign(annotation.data, {
|
|
58
|
+
contour: {
|
|
59
|
+
polyline: [],
|
|
60
|
+
closed: false,
|
|
94
61
|
},
|
|
62
|
+
});
|
|
63
|
+
Object.assign(annotation, {
|
|
95
64
|
interpolationUID: '',
|
|
96
65
|
autoGenerated: false,
|
|
97
|
-
};
|
|
66
|
+
});
|
|
67
|
+
return annotation;
|
|
98
68
|
}
|
|
99
69
|
addAnnotation(annotation, element) {
|
|
100
70
|
return addAnnotation(annotation, element);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Annotation, EventTypes, PublicToolProps, ToolProps, AnnotationRenderContext } from '../../types';
|
|
2
|
+
import type { ContourAnnotation } from '../../types/ToolSpecificAnnotationTypes';
|
|
2
3
|
import type { StyleSpecifier } from '../../types/AnnotationStyle';
|
|
3
4
|
import ContourBaseTool from './ContourBaseTool';
|
|
4
5
|
declare abstract class ContourSegmentationBaseTool extends ContourBaseTool {
|
|
5
6
|
constructor(toolProps: PublicToolProps, defaultToolProps: ToolProps);
|
|
6
7
|
protected isContourSegmentationTool(): boolean;
|
|
7
|
-
protected createAnnotation(evt: EventTypes.InteractionEventType):
|
|
8
|
+
protected createAnnotation(evt: EventTypes.InteractionEventType): ContourAnnotation;
|
|
8
9
|
protected addAnnotation(annotation: Annotation, element: HTMLDivElement): string;
|
|
9
10
|
protected cancelAnnotation(annotation: Annotation): void;
|
|
10
11
|
protected getAnnotationStyle(context: {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getEnabledElement, utilities } from '@cornerstonejs/core';
|
|
2
|
-
import { getSegmentation } from '../../stateManagement/segmentation/getSegmentation';
|
|
3
2
|
import { SegmentationRepresentations } from '../../enums';
|
|
4
3
|
import ContourBaseTool from './ContourBaseTool';
|
|
5
4
|
import { triggerSegmentationDataModified } from '../../stateManagement/segmentation/triggerSegmentationEvents';
|
|
@@ -35,7 +35,7 @@ async function addLabelmapToElement(element, labelMapData, segmentationId) {
|
|
|
35
35
|
representationUID: `${segmentationId}-${SegmentationRepresentations.Labelmap}`,
|
|
36
36
|
},
|
|
37
37
|
];
|
|
38
|
-
|
|
38
|
+
addImageSlicesToViewports(renderingEngine, stackInputs, [viewportId]);
|
|
39
39
|
}
|
|
40
40
|
triggerSegmentationDataModified(segmentationId);
|
|
41
41
|
}
|
|
@@ -1,127 +1,22 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import type { PublicToolProps, ToolProps, EventTypes, SVGDrawingHelper } from '../../types';
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
export type PreviewData = {
|
|
6
|
-
preview: unknown;
|
|
7
|
-
timer?: number;
|
|
8
|
-
timerStart: number;
|
|
9
|
-
startPoint: Types.Point2;
|
|
10
|
-
element: HTMLDivElement;
|
|
11
|
-
isDrag: boolean;
|
|
12
|
-
};
|
|
13
|
-
declare class BrushTool extends BaseTool {
|
|
3
|
+
import LabelmapBaseTool from './LabelmapBaseTool';
|
|
4
|
+
declare class BrushTool extends LabelmapBaseTool {
|
|
14
5
|
static toolName: any;
|
|
15
|
-
|
|
16
|
-
private _hoverData?;
|
|
17
|
-
private _previewData?;
|
|
6
|
+
prg: any;
|
|
18
7
|
constructor(toolProps?: PublicToolProps, defaultToolProps?: ToolProps);
|
|
19
8
|
onSetToolPassive: (evt: any) => void;
|
|
20
9
|
onSetToolEnabled: () => void;
|
|
21
10
|
onSetToolDisabled: (evt: any) => void;
|
|
22
11
|
private disableCursor;
|
|
23
|
-
createEditData(element: any): {
|
|
24
|
-
volumeId: string;
|
|
25
|
-
referencedVolumeId: any;
|
|
26
|
-
segmentsLocked: number[] | [];
|
|
27
|
-
imageId?: undefined;
|
|
28
|
-
override?: undefined;
|
|
29
|
-
} | {
|
|
30
|
-
imageId: string;
|
|
31
|
-
segmentsLocked: number[] | [];
|
|
32
|
-
override: {
|
|
33
|
-
voxelManager: Types.IVoxelManager<number> | Types.IVoxelManager<Types.RGB>;
|
|
34
|
-
imageData: vtkImageData;
|
|
35
|
-
};
|
|
36
|
-
volumeId?: undefined;
|
|
37
|
-
referencedVolumeId?: undefined;
|
|
38
|
-
} | {
|
|
39
|
-
imageId: string;
|
|
40
|
-
segmentsLocked: number[] | [];
|
|
41
|
-
volumeId?: undefined;
|
|
42
|
-
referencedVolumeId?: undefined;
|
|
43
|
-
override?: undefined;
|
|
44
|
-
};
|
|
45
12
|
preMouseDownCallback: (evt: EventTypes.MouseDownActivateEventType) => boolean;
|
|
46
13
|
mouseMoveCallback: (evt: EventTypes.InteractionEventType) => void;
|
|
47
14
|
previewCallback: () => void;
|
|
48
|
-
private createHoverData;
|
|
49
|
-
private getActiveSegmentationData;
|
|
50
15
|
protected updateCursor(evt: EventTypes.InteractionEventType): void;
|
|
51
16
|
private _dragCallback;
|
|
52
|
-
protected getOperationData(element?: any): {
|
|
53
|
-
points: any;
|
|
54
|
-
segmentIndex: number;
|
|
55
|
-
previewColors: any;
|
|
56
|
-
viewPlaneNormal: any;
|
|
57
|
-
toolGroupId: string;
|
|
58
|
-
segmentationId: string;
|
|
59
|
-
viewUp: any;
|
|
60
|
-
strategySpecificConfiguration: any;
|
|
61
|
-
preview: unknown;
|
|
62
|
-
override: {
|
|
63
|
-
voxelManager: Types.IVoxelManager<number>;
|
|
64
|
-
imageData: vtkImageData;
|
|
65
|
-
};
|
|
66
|
-
segmentsLocked: number[];
|
|
67
|
-
imageId?: string;
|
|
68
|
-
imageIds?: string[];
|
|
69
|
-
volumeId?: string;
|
|
70
|
-
referencedVolumeId?: string;
|
|
71
|
-
} | {
|
|
72
|
-
points: any;
|
|
73
|
-
segmentIndex: number;
|
|
74
|
-
previewColors: any;
|
|
75
|
-
viewPlaneNormal: any;
|
|
76
|
-
toolGroupId: string;
|
|
77
|
-
segmentationId: string;
|
|
78
|
-
viewUp: any;
|
|
79
|
-
strategySpecificConfiguration: any;
|
|
80
|
-
preview: unknown;
|
|
81
|
-
volumeId: string;
|
|
82
|
-
referencedVolumeId: any;
|
|
83
|
-
segmentsLocked: number[] | [];
|
|
84
|
-
imageId?: undefined;
|
|
85
|
-
override?: undefined;
|
|
86
|
-
} | {
|
|
87
|
-
points: any;
|
|
88
|
-
segmentIndex: number;
|
|
89
|
-
previewColors: any;
|
|
90
|
-
viewPlaneNormal: any;
|
|
91
|
-
toolGroupId: string;
|
|
92
|
-
segmentationId: string;
|
|
93
|
-
viewUp: any;
|
|
94
|
-
strategySpecificConfiguration: any;
|
|
95
|
-
preview: unknown;
|
|
96
|
-
imageId: string;
|
|
97
|
-
segmentsLocked: number[] | [];
|
|
98
|
-
override: {
|
|
99
|
-
voxelManager: Types.IVoxelManager<number> | Types.IVoxelManager<Types.RGB>;
|
|
100
|
-
imageData: vtkImageData;
|
|
101
|
-
};
|
|
102
|
-
volumeId?: undefined;
|
|
103
|
-
referencedVolumeId?: undefined;
|
|
104
|
-
} | {
|
|
105
|
-
points: any;
|
|
106
|
-
segmentIndex: number;
|
|
107
|
-
previewColors: any;
|
|
108
|
-
viewPlaneNormal: any;
|
|
109
|
-
toolGroupId: string;
|
|
110
|
-
segmentationId: string;
|
|
111
|
-
viewUp: any;
|
|
112
|
-
strategySpecificConfiguration: any;
|
|
113
|
-
preview: unknown;
|
|
114
|
-
imageId: string;
|
|
115
|
-
segmentsLocked: number[] | [];
|
|
116
|
-
volumeId?: undefined;
|
|
117
|
-
referencedVolumeId?: undefined;
|
|
118
|
-
override?: undefined;
|
|
119
|
-
};
|
|
120
17
|
private _calculateCursor;
|
|
121
18
|
private _endCallback;
|
|
122
19
|
getStatistics(element: any, segmentIndices?: any): any;
|
|
123
|
-
rejectPreview(element?: HTMLDivElement): void;
|
|
124
|
-
acceptPreview(element?: HTMLDivElement): void;
|
|
125
20
|
private _activateDraw;
|
|
126
21
|
private _deactivateDraw;
|
|
127
22
|
invalidateBrushCursor(): void;
|
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getEnabledElement } from '@cornerstonejs/core';
|
|
2
2
|
import { vec3, vec2 } from 'gl-matrix';
|
|
3
|
-
import { BaseTool } from '../base';
|
|
4
3
|
import { fillInsideSphere, thresholdInsideSphere, thresholdInsideSphereIsland, } from './strategies/fillSphere';
|
|
5
4
|
import { eraseInsideSphere } from './strategies/eraseSphere';
|
|
6
5
|
import { thresholdInsideCircle, fillInsideCircle, } from './strategies/fillCircle';
|
|
7
6
|
import { eraseInsideCircle } from './strategies/eraseCircle';
|
|
8
|
-
import { Events, ToolModes,
|
|
7
|
+
import { Events, ToolModes, StrategyCallbacks } from '../../enums';
|
|
9
8
|
import { drawCircle as drawCircleSvg } from '../../drawingSvg';
|
|
10
9
|
import { resetElementCursor, hideElementCursor, } from '../../cursors/elementCursor';
|
|
11
10
|
import triggerAnnotationRenderForViewportUIDs from '../../utilities/triggerAnnotationRenderForViewportIds';
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
import { getActiveSegmentIndex } from '../../stateManagement/segmentation/getActiveSegmentIndex';
|
|
15
|
-
import { getSegmentIndexColor } from '../../stateManagement/segmentation/config/segmentationColor';
|
|
16
|
-
import { getActiveSegmentation } from '../../stateManagement/segmentation/getActiveSegmentation';
|
|
17
|
-
class BrushTool extends BaseTool {
|
|
11
|
+
import LabelmapBaseTool from './LabelmapBaseTool';
|
|
12
|
+
class BrushTool extends LabelmapBaseTool {
|
|
18
13
|
constructor(toolProps = {}, defaultToolProps = {
|
|
19
14
|
supportedInteractionTypes: ['Mouse', 'Touch'],
|
|
20
15
|
configuration: {
|
|
@@ -57,14 +52,6 @@ class BrushTool extends BaseTool {
|
|
|
57
52
|
},
|
|
58
53
|
}) {
|
|
59
54
|
super(toolProps, defaultToolProps);
|
|
60
|
-
this._previewData = {
|
|
61
|
-
preview: null,
|
|
62
|
-
element: null,
|
|
63
|
-
timerStart: 0,
|
|
64
|
-
timer: null,
|
|
65
|
-
startPoint: [NaN, NaN],
|
|
66
|
-
isDrag: false,
|
|
67
|
-
};
|
|
68
55
|
this.onSetToolPassive = (evt) => {
|
|
69
56
|
this.disableCursor();
|
|
70
57
|
};
|
|
@@ -183,144 +170,6 @@ class BrushTool extends BaseTool {
|
|
|
183
170
|
this._hoverData = undefined;
|
|
184
171
|
this.rejectPreview();
|
|
185
172
|
}
|
|
186
|
-
createEditData(element) {
|
|
187
|
-
const enabledElement = getEnabledElement(element);
|
|
188
|
-
const { viewport } = enabledElement;
|
|
189
|
-
const activeSegmentation = getActiveSegmentation(viewport.id);
|
|
190
|
-
if (!activeSegmentation) {
|
|
191
|
-
const event = new CustomEvent(Enums.Events.ERROR_EVENT, {
|
|
192
|
-
detail: {
|
|
193
|
-
type: 'Segmentation',
|
|
194
|
-
message: 'No active segmentation detected, create a segmentation representation before using the brush tool',
|
|
195
|
-
},
|
|
196
|
-
cancelable: true,
|
|
197
|
-
});
|
|
198
|
-
eventTarget.dispatchEvent(event);
|
|
199
|
-
return null;
|
|
200
|
-
}
|
|
201
|
-
const { segmentationId } = activeSegmentation;
|
|
202
|
-
const segmentsLocked = getLockedSegmentIndices(segmentationId);
|
|
203
|
-
const { representationData } = getSegmentation(segmentationId);
|
|
204
|
-
if (viewport instanceof BaseVolumeViewport) {
|
|
205
|
-
const { volumeId } = representationData[SegmentationRepresentations.Labelmap];
|
|
206
|
-
const actors = viewport.getActors();
|
|
207
|
-
const isStackViewport = viewport instanceof StackViewport;
|
|
208
|
-
if (isStackViewport) {
|
|
209
|
-
const event = new CustomEvent(Enums.Events.ERROR_EVENT, {
|
|
210
|
-
detail: {
|
|
211
|
-
type: 'Segmentation',
|
|
212
|
-
message: 'Cannot perform brush operation on the selected viewport',
|
|
213
|
-
},
|
|
214
|
-
cancelable: true,
|
|
215
|
-
});
|
|
216
|
-
eventTarget.dispatchEvent(event);
|
|
217
|
-
return null;
|
|
218
|
-
}
|
|
219
|
-
const volumes = actors.map((actorEntry) => cache.getVolume(actorEntry.referencedId));
|
|
220
|
-
const segmentationVolume = cache.getVolume(volumeId);
|
|
221
|
-
const referencedVolumeIdToThreshold = volumes.find((volume) => csUtils.isEqual(volume.dimensions, segmentationVolume.dimensions))?.volumeId || volumes[0]?.volumeId;
|
|
222
|
-
return {
|
|
223
|
-
volumeId,
|
|
224
|
-
referencedVolumeId: this.configuration.thresholdVolumeId ?? referencedVolumeIdToThreshold,
|
|
225
|
-
segmentsLocked,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
const segmentationImageId = getCurrentLabelmapImageIdForViewport(viewport.id, segmentationId);
|
|
230
|
-
if (!segmentationImageId) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
if (this.configuration.activeStrategy.includes('SPHERE')) {
|
|
234
|
-
const referencedImageIds = viewport.getImageIds();
|
|
235
|
-
const isValidVolumeForSphere = csUtils.isValidVolume(referencedImageIds);
|
|
236
|
-
if (!isValidVolumeForSphere) {
|
|
237
|
-
throw new Error('Volume is not reconstructable for sphere manipulation');
|
|
238
|
-
}
|
|
239
|
-
const volumeId = `${segmentationId}_${viewport.id}`;
|
|
240
|
-
const volume = cache.getVolume(volumeId);
|
|
241
|
-
if (volume) {
|
|
242
|
-
return {
|
|
243
|
-
imageId: segmentationImageId,
|
|
244
|
-
segmentsLocked,
|
|
245
|
-
override: {
|
|
246
|
-
voxelManager: volume.voxelManager,
|
|
247
|
-
imageData: volume.imageData,
|
|
248
|
-
},
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
const labelmapImageIds = getStackSegmentationImageIdsForViewport(viewport.id, segmentationId);
|
|
253
|
-
if (!labelmapImageIds || labelmapImageIds.length === 1) {
|
|
254
|
-
return {
|
|
255
|
-
imageId: segmentationImageId,
|
|
256
|
-
segmentsLocked,
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
const volume = volumeLoader.createAndCacheVolumeFromImagesSync(volumeId, labelmapImageIds);
|
|
260
|
-
return {
|
|
261
|
-
imageId: segmentationImageId,
|
|
262
|
-
segmentsLocked,
|
|
263
|
-
override: {
|
|
264
|
-
voxelManager: volume.voxelManager,
|
|
265
|
-
imageData: volume.imageData,
|
|
266
|
-
},
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
return {
|
|
272
|
-
imageId: segmentationImageId,
|
|
273
|
-
segmentsLocked,
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
createHoverData(element, centerCanvas) {
|
|
279
|
-
const enabledElement = getEnabledElement(element);
|
|
280
|
-
const { viewport } = enabledElement;
|
|
281
|
-
const camera = viewport.getCamera();
|
|
282
|
-
const { viewPlaneNormal, viewUp } = camera;
|
|
283
|
-
const viewportIdsToRender = [viewport.id];
|
|
284
|
-
const { segmentIndex, segmentationId, segmentColor } = this.getActiveSegmentationData(viewport) || {};
|
|
285
|
-
const brushCursor = {
|
|
286
|
-
metadata: {
|
|
287
|
-
viewPlaneNormal: [...viewPlaneNormal],
|
|
288
|
-
viewUp: [...viewUp],
|
|
289
|
-
FrameOfReferenceUID: viewport.getFrameOfReferenceUID(),
|
|
290
|
-
referencedImageId: '',
|
|
291
|
-
toolName: this.getToolName(),
|
|
292
|
-
segmentColor,
|
|
293
|
-
},
|
|
294
|
-
data: {},
|
|
295
|
-
};
|
|
296
|
-
return {
|
|
297
|
-
brushCursor,
|
|
298
|
-
centerCanvas,
|
|
299
|
-
segmentIndex,
|
|
300
|
-
viewport,
|
|
301
|
-
segmentationId,
|
|
302
|
-
segmentColor,
|
|
303
|
-
viewportIdsToRender,
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
getActiveSegmentationData(viewport) {
|
|
307
|
-
const viewportId = viewport.id;
|
|
308
|
-
const activeRepresentation = getActiveSegmentation(viewportId);
|
|
309
|
-
if (!activeRepresentation) {
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
const { segmentationId } = activeRepresentation;
|
|
313
|
-
const segmentIndex = getActiveSegmentIndex(segmentationId);
|
|
314
|
-
if (!segmentIndex) {
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
const segmentColor = getSegmentIndexColor(viewportId, segmentationId, segmentIndex);
|
|
318
|
-
return {
|
|
319
|
-
segmentIndex,
|
|
320
|
-
segmentationId,
|
|
321
|
-
segmentColor,
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
173
|
updateCursor(evt) {
|
|
325
174
|
const eventData = evt.detail;
|
|
326
175
|
const { element } = eventData;
|
|
@@ -333,27 +182,6 @@ class BrushTool extends BaseTool {
|
|
|
333
182
|
}
|
|
334
183
|
triggerAnnotationRenderForViewportUIDs(this._hoverData.viewportIdsToRender);
|
|
335
184
|
}
|
|
336
|
-
getOperationData(element) {
|
|
337
|
-
const editData = this._editData || this.createEditData(element);
|
|
338
|
-
const { segmentIndex, segmentationId, brushCursor } = this._hoverData || this.createHoverData(element);
|
|
339
|
-
const { data, metadata = {} } = brushCursor || {};
|
|
340
|
-
const { viewPlaneNormal, viewUp } = metadata;
|
|
341
|
-
const operationData = {
|
|
342
|
-
...editData,
|
|
343
|
-
points: data?.handles?.points,
|
|
344
|
-
segmentIndex,
|
|
345
|
-
previewColors: this.configuration.preview.enabled
|
|
346
|
-
? this.configuration.preview.previewColors
|
|
347
|
-
: null,
|
|
348
|
-
viewPlaneNormal,
|
|
349
|
-
toolGroupId: this.toolGroupId,
|
|
350
|
-
segmentationId,
|
|
351
|
-
viewUp,
|
|
352
|
-
strategySpecificConfiguration: this.configuration.strategySpecificConfiguration,
|
|
353
|
-
preview: this._previewData?.preview,
|
|
354
|
-
};
|
|
355
|
-
return operationData;
|
|
356
|
-
}
|
|
357
185
|
_calculateCursor(element, centerCanvas) {
|
|
358
186
|
const enabledElement = getEnabledElement(element);
|
|
359
187
|
const { viewport } = enabledElement;
|
|
@@ -410,24 +238,6 @@ class BrushTool extends BaseTool {
|
|
|
410
238
|
const stats = this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.GetStatistics, segmentIndices);
|
|
411
239
|
return stats;
|
|
412
240
|
}
|
|
413
|
-
rejectPreview(element = this._previewData.element) {
|
|
414
|
-
if (!element || !this._previewData.preview) {
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
const enabledElement = getEnabledElement(element);
|
|
418
|
-
this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.RejectPreview);
|
|
419
|
-
this._previewData.preview = null;
|
|
420
|
-
this._previewData.isDrag = false;
|
|
421
|
-
}
|
|
422
|
-
acceptPreview(element = this._previewData.element) {
|
|
423
|
-
if (!element) {
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
const enabledElement = getEnabledElement(element);
|
|
427
|
-
this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.AcceptPreview);
|
|
428
|
-
this._previewData.isDrag = false;
|
|
429
|
-
this._previewData.preview = null;
|
|
430
|
-
}
|
|
431
241
|
invalidateBrushCursor() {
|
|
432
242
|
if (this._hoverData === undefined) {
|
|
433
243
|
return;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type { Types } from '@cornerstonejs/core';
|
|
2
|
+
import { BaseTool } from '../base';
|
|
3
|
+
import type vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData';
|
|
4
|
+
export type PreviewData = {
|
|
5
|
+
preview: unknown;
|
|
6
|
+
timer?: number;
|
|
7
|
+
timerStart: number;
|
|
8
|
+
startPoint: Types.Point2;
|
|
9
|
+
element: HTMLDivElement;
|
|
10
|
+
isDrag: boolean;
|
|
11
|
+
};
|
|
12
|
+
export default class LabelmapBaseTool extends BaseTool {
|
|
13
|
+
protected _editData: {
|
|
14
|
+
override: {
|
|
15
|
+
voxelManager: Types.IVoxelManager<number>;
|
|
16
|
+
imageData: vtkImageData;
|
|
17
|
+
};
|
|
18
|
+
segmentsLocked: number[];
|
|
19
|
+
imageId?: string;
|
|
20
|
+
imageIds?: string[];
|
|
21
|
+
volumeId?: string;
|
|
22
|
+
referencedVolumeId?: string;
|
|
23
|
+
} | null;
|
|
24
|
+
protected _hoverData?: {
|
|
25
|
+
brushCursor: any;
|
|
26
|
+
segmentationId: string;
|
|
27
|
+
segmentIndex: number;
|
|
28
|
+
segmentColor: [number, number, number, number];
|
|
29
|
+
viewportIdsToRender: string[];
|
|
30
|
+
centerCanvas?: Array<number>;
|
|
31
|
+
viewport: Types.IViewport;
|
|
32
|
+
};
|
|
33
|
+
protected _previewData?: PreviewData;
|
|
34
|
+
constructor(toolProps: any, defaultToolProps: any);
|
|
35
|
+
createMemo(segmentId: string, segmentationVoxelManager: any, preview: any): void;
|
|
36
|
+
createEditData(element: any): {
|
|
37
|
+
volumeId: string;
|
|
38
|
+
referencedVolumeId: any;
|
|
39
|
+
segmentsLocked: number[] | [];
|
|
40
|
+
imageId?: undefined;
|
|
41
|
+
override?: undefined;
|
|
42
|
+
} | {
|
|
43
|
+
imageId: string;
|
|
44
|
+
segmentsLocked: number[] | [];
|
|
45
|
+
override: {
|
|
46
|
+
voxelManager: Types.IVoxelManager<number> | Types.IVoxelManager<Types.RGB>;
|
|
47
|
+
imageData: vtkImageData;
|
|
48
|
+
};
|
|
49
|
+
volumeId?: undefined;
|
|
50
|
+
referencedVolumeId?: undefined;
|
|
51
|
+
} | {
|
|
52
|
+
imageId: string;
|
|
53
|
+
segmentsLocked: number[] | [];
|
|
54
|
+
volumeId?: undefined;
|
|
55
|
+
referencedVolumeId?: undefined;
|
|
56
|
+
override?: undefined;
|
|
57
|
+
};
|
|
58
|
+
protected createHoverData(element: any, centerCanvas?: any): {
|
|
59
|
+
brushCursor: {
|
|
60
|
+
metadata: {
|
|
61
|
+
viewPlaneNormal: Types.Point3;
|
|
62
|
+
viewUp: Types.Point3;
|
|
63
|
+
FrameOfReferenceUID: string;
|
|
64
|
+
referencedImageId: string;
|
|
65
|
+
toolName: string;
|
|
66
|
+
segmentColor: Types.Color;
|
|
67
|
+
};
|
|
68
|
+
data: {};
|
|
69
|
+
};
|
|
70
|
+
centerCanvas: any;
|
|
71
|
+
segmentIndex: number;
|
|
72
|
+
viewport: Types.IStackViewport | import("@cornerstonejs/core").VolumeViewport;
|
|
73
|
+
segmentationId: string;
|
|
74
|
+
segmentColor: Types.Color;
|
|
75
|
+
viewportIdsToRender: string[];
|
|
76
|
+
};
|
|
77
|
+
protected getActiveSegmentationData(viewport: any): {
|
|
78
|
+
segmentIndex: number;
|
|
79
|
+
segmentationId: string;
|
|
80
|
+
segmentColor: Types.Color;
|
|
81
|
+
};
|
|
82
|
+
protected getOperationData(element?: any): {
|
|
83
|
+
points: any;
|
|
84
|
+
segmentIndex: number;
|
|
85
|
+
previewColors: any;
|
|
86
|
+
viewPlaneNormal: any;
|
|
87
|
+
toolGroupId: string;
|
|
88
|
+
segmentationId: string;
|
|
89
|
+
viewUp: any;
|
|
90
|
+
strategySpecificConfiguration: any;
|
|
91
|
+
preview: unknown;
|
|
92
|
+
override: {
|
|
93
|
+
voxelManager: Types.IVoxelManager<number>;
|
|
94
|
+
imageData: vtkImageData;
|
|
95
|
+
};
|
|
96
|
+
segmentsLocked: number[];
|
|
97
|
+
imageId?: string;
|
|
98
|
+
imageIds?: string[];
|
|
99
|
+
volumeId?: string;
|
|
100
|
+
referencedVolumeId?: string;
|
|
101
|
+
} | {
|
|
102
|
+
points: any;
|
|
103
|
+
segmentIndex: number;
|
|
104
|
+
previewColors: any;
|
|
105
|
+
viewPlaneNormal: any;
|
|
106
|
+
toolGroupId: string;
|
|
107
|
+
segmentationId: string;
|
|
108
|
+
viewUp: any;
|
|
109
|
+
strategySpecificConfiguration: any;
|
|
110
|
+
preview: unknown;
|
|
111
|
+
volumeId: string;
|
|
112
|
+
referencedVolumeId: any;
|
|
113
|
+
segmentsLocked: number[] | [];
|
|
114
|
+
imageId?: undefined;
|
|
115
|
+
override?: undefined;
|
|
116
|
+
} | {
|
|
117
|
+
points: any;
|
|
118
|
+
segmentIndex: number;
|
|
119
|
+
previewColors: any;
|
|
120
|
+
viewPlaneNormal: any;
|
|
121
|
+
toolGroupId: string;
|
|
122
|
+
segmentationId: string;
|
|
123
|
+
viewUp: any;
|
|
124
|
+
strategySpecificConfiguration: any;
|
|
125
|
+
preview: unknown;
|
|
126
|
+
imageId: string;
|
|
127
|
+
segmentsLocked: number[] | [];
|
|
128
|
+
override: {
|
|
129
|
+
voxelManager: Types.IVoxelManager<number> | Types.IVoxelManager<Types.RGB>;
|
|
130
|
+
imageData: vtkImageData;
|
|
131
|
+
};
|
|
132
|
+
volumeId?: undefined;
|
|
133
|
+
referencedVolumeId?: undefined;
|
|
134
|
+
} | {
|
|
135
|
+
points: any;
|
|
136
|
+
segmentIndex: number;
|
|
137
|
+
previewColors: any;
|
|
138
|
+
viewPlaneNormal: any;
|
|
139
|
+
toolGroupId: string;
|
|
140
|
+
segmentationId: string;
|
|
141
|
+
viewUp: any;
|
|
142
|
+
strategySpecificConfiguration: any;
|
|
143
|
+
preview: unknown;
|
|
144
|
+
imageId: string;
|
|
145
|
+
segmentsLocked: number[] | [];
|
|
146
|
+
volumeId?: undefined;
|
|
147
|
+
referencedVolumeId?: undefined;
|
|
148
|
+
override?: undefined;
|
|
149
|
+
};
|
|
150
|
+
addPreview(element?: HTMLDivElement, options?: {
|
|
151
|
+
acceptReject: boolean;
|
|
152
|
+
}): unknown;
|
|
153
|
+
rejectPreview(element?: HTMLDivElement): void;
|
|
154
|
+
acceptPreview(element?: HTMLDivElement): void;
|
|
155
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { getEnabledElement, cache, utilities as csUtils, Enums, eventTarget, BaseVolumeViewport, volumeLoader, } from '@cornerstonejs/core';
|
|
2
|
+
import { BaseTool } from '../base';
|
|
3
|
+
import SegmentationRepresentations from '../../enums/SegmentationRepresentations';
|
|
4
|
+
import { getActiveSegmentation } from '../../stateManagement/segmentation/getActiveSegmentation';
|
|
5
|
+
import { getLockedSegmentIndices } from '../../stateManagement/segmentation/segmentLocking';
|
|
6
|
+
import { getSegmentation } from '../../stateManagement/segmentation/getSegmentation';
|
|
7
|
+
import { getClosestImageIdForStackViewport } from '../../utilities/annotationHydration';
|
|
8
|
+
import { getCurrentLabelmapImageIdForViewport } from '../../stateManagement/segmentation/getCurrentLabelmapImageIdForViewport';
|
|
9
|
+
import { getStackSegmentationImageIdsForViewport } from '../../stateManagement/segmentation/getStackSegmentationImageIdsForViewport';
|
|
10
|
+
import { getSegmentIndexColor } from '../../stateManagement/segmentation/config/segmentationColor';
|
|
11
|
+
import { getActiveSegmentIndex } from '../../stateManagement/segmentation/getActiveSegmentIndex';
|
|
12
|
+
import { StrategyCallbacks } from '../../enums';
|
|
13
|
+
export default class LabelmapBaseTool extends BaseTool {
|
|
14
|
+
constructor(toolProps, defaultToolProps) {
|
|
15
|
+
super(toolProps, defaultToolProps);
|
|
16
|
+
this._previewData = {
|
|
17
|
+
preview: null,
|
|
18
|
+
element: null,
|
|
19
|
+
timerStart: 0,
|
|
20
|
+
timer: null,
|
|
21
|
+
startPoint: [NaN, NaN],
|
|
22
|
+
isDrag: false,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
createMemo(segmentId, segmentationVoxelManager, preview) {
|
|
26
|
+
console.warn('LabelmapBaseTool.createMemo not implemented yet');
|
|
27
|
+
}
|
|
28
|
+
createEditData(element) {
|
|
29
|
+
const enabledElement = getEnabledElement(element);
|
|
30
|
+
const { viewport } = enabledElement;
|
|
31
|
+
const activeSegmentation = getActiveSegmentation(viewport.id);
|
|
32
|
+
if (!activeSegmentation) {
|
|
33
|
+
const event = new CustomEvent(Enums.Events.ERROR_EVENT, {
|
|
34
|
+
detail: {
|
|
35
|
+
type: 'Segmentation',
|
|
36
|
+
message: 'No active segmentation detected, create a segmentation representation before using the brush tool',
|
|
37
|
+
},
|
|
38
|
+
cancelable: true,
|
|
39
|
+
});
|
|
40
|
+
eventTarget.dispatchEvent(event);
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const { segmentationId } = activeSegmentation;
|
|
44
|
+
const segmentsLocked = getLockedSegmentIndices(segmentationId);
|
|
45
|
+
const { representationData } = getSegmentation(segmentationId);
|
|
46
|
+
if (viewport instanceof BaseVolumeViewport) {
|
|
47
|
+
const { volumeId } = representationData[SegmentationRepresentations.Labelmap];
|
|
48
|
+
const actors = viewport.getActors();
|
|
49
|
+
const isStackViewport = viewport instanceof getClosestImageIdForStackViewport;
|
|
50
|
+
if (isStackViewport) {
|
|
51
|
+
const event = new CustomEvent(Enums.Events.ERROR_EVENT, {
|
|
52
|
+
detail: {
|
|
53
|
+
type: 'Segmentation',
|
|
54
|
+
message: 'Cannot perform brush operation on the selected viewport',
|
|
55
|
+
},
|
|
56
|
+
cancelable: true,
|
|
57
|
+
});
|
|
58
|
+
eventTarget.dispatchEvent(event);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const volumes = actors.map((actorEntry) => cache.getVolume(actorEntry.referencedId));
|
|
62
|
+
const segmentationVolume = cache.getVolume(volumeId);
|
|
63
|
+
const referencedVolumeIdToThreshold = volumes.find((volume) => csUtils.isEqual(volume.dimensions, segmentationVolume.dimensions))?.volumeId || volumes[0]?.volumeId;
|
|
64
|
+
return {
|
|
65
|
+
volumeId,
|
|
66
|
+
referencedVolumeId: this.configuration.thresholdVolumeId ?? referencedVolumeIdToThreshold,
|
|
67
|
+
segmentsLocked,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const segmentationImageId = getCurrentLabelmapImageIdForViewport(viewport.id, segmentationId);
|
|
72
|
+
if (!segmentationImageId) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (this.configuration.activeStrategy.includes('SPHERE')) {
|
|
76
|
+
const referencedImageIds = viewport.getImageIds();
|
|
77
|
+
const isValidVolumeForSphere = csUtils.isValidVolume(referencedImageIds);
|
|
78
|
+
if (!isValidVolumeForSphere) {
|
|
79
|
+
throw new Error('Volume is not reconstructable for sphere manipulation');
|
|
80
|
+
}
|
|
81
|
+
const volumeId = `${segmentationId}_${viewport.id}`;
|
|
82
|
+
const volume = cache.getVolume(volumeId);
|
|
83
|
+
if (volume) {
|
|
84
|
+
return {
|
|
85
|
+
imageId: segmentationImageId,
|
|
86
|
+
segmentsLocked,
|
|
87
|
+
override: {
|
|
88
|
+
voxelManager: volume.voxelManager,
|
|
89
|
+
imageData: volume.imageData,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const labelmapImageIds = getStackSegmentationImageIdsForViewport(viewport.id, segmentationId);
|
|
95
|
+
if (!labelmapImageIds || labelmapImageIds.length === 1) {
|
|
96
|
+
return {
|
|
97
|
+
imageId: segmentationImageId,
|
|
98
|
+
segmentsLocked,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const volume = volumeLoader.createAndCacheVolumeFromImagesSync(volumeId, labelmapImageIds);
|
|
102
|
+
return {
|
|
103
|
+
imageId: segmentationImageId,
|
|
104
|
+
segmentsLocked,
|
|
105
|
+
override: {
|
|
106
|
+
voxelManager: volume.voxelManager,
|
|
107
|
+
imageData: volume.imageData,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
return {
|
|
114
|
+
imageId: segmentationImageId,
|
|
115
|
+
segmentsLocked,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
createHoverData(element, centerCanvas) {
|
|
121
|
+
const enabledElement = getEnabledElement(element);
|
|
122
|
+
const { viewport } = enabledElement;
|
|
123
|
+
const camera = viewport.getCamera();
|
|
124
|
+
const { viewPlaneNormal, viewUp } = camera;
|
|
125
|
+
const viewportIdsToRender = [viewport.id];
|
|
126
|
+
const { segmentIndex, segmentationId, segmentColor } = this.getActiveSegmentationData(viewport) || {};
|
|
127
|
+
const brushCursor = {
|
|
128
|
+
metadata: {
|
|
129
|
+
viewPlaneNormal: [...viewPlaneNormal],
|
|
130
|
+
viewUp: [...viewUp],
|
|
131
|
+
FrameOfReferenceUID: viewport.getFrameOfReferenceUID(),
|
|
132
|
+
referencedImageId: '',
|
|
133
|
+
toolName: this.getToolName(),
|
|
134
|
+
segmentColor,
|
|
135
|
+
},
|
|
136
|
+
data: {},
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
brushCursor,
|
|
140
|
+
centerCanvas,
|
|
141
|
+
segmentIndex,
|
|
142
|
+
viewport,
|
|
143
|
+
segmentationId,
|
|
144
|
+
segmentColor,
|
|
145
|
+
viewportIdsToRender,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
getActiveSegmentationData(viewport) {
|
|
149
|
+
const viewportId = viewport.id;
|
|
150
|
+
const activeRepresentation = getActiveSegmentation(viewportId);
|
|
151
|
+
if (!activeRepresentation) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const { segmentationId } = activeRepresentation;
|
|
155
|
+
const segmentIndex = getActiveSegmentIndex(segmentationId);
|
|
156
|
+
if (!segmentIndex) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const segmentColor = getSegmentIndexColor(viewportId, segmentationId, segmentIndex);
|
|
160
|
+
return {
|
|
161
|
+
segmentIndex,
|
|
162
|
+
segmentationId,
|
|
163
|
+
segmentColor,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
getOperationData(element) {
|
|
167
|
+
const editData = this._editData || this.createEditData(element);
|
|
168
|
+
const { segmentIndex, segmentationId, brushCursor } = this._hoverData || this.createHoverData(element);
|
|
169
|
+
const { data, metadata = {} } = brushCursor || {};
|
|
170
|
+
const { viewPlaneNormal, viewUp } = metadata;
|
|
171
|
+
const operationData = {
|
|
172
|
+
...editData,
|
|
173
|
+
points: data?.handles?.points,
|
|
174
|
+
segmentIndex,
|
|
175
|
+
previewColors: this.configuration.preview?.enabled || this._previewData.preview
|
|
176
|
+
? this.configuration.preview.previewColors
|
|
177
|
+
: null,
|
|
178
|
+
viewPlaneNormal,
|
|
179
|
+
toolGroupId: this.toolGroupId,
|
|
180
|
+
segmentationId,
|
|
181
|
+
viewUp,
|
|
182
|
+
strategySpecificConfiguration: this.configuration.strategySpecificConfiguration,
|
|
183
|
+
preview: this._previewData?.preview,
|
|
184
|
+
};
|
|
185
|
+
return operationData;
|
|
186
|
+
}
|
|
187
|
+
addPreview(element = this._previewData.element, options) {
|
|
188
|
+
const acceptReject = options?.acceptReject;
|
|
189
|
+
if (acceptReject === true) {
|
|
190
|
+
this.acceptPreview(element);
|
|
191
|
+
}
|
|
192
|
+
else if (acceptReject === false) {
|
|
193
|
+
this.rejectPreview(element);
|
|
194
|
+
}
|
|
195
|
+
const enabledElement = getEnabledElement(element);
|
|
196
|
+
this._previewData.preview = this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.AddPreview);
|
|
197
|
+
this._previewData.isDrag = true;
|
|
198
|
+
return this._previewData.preview;
|
|
199
|
+
}
|
|
200
|
+
rejectPreview(element = this._previewData.element) {
|
|
201
|
+
if (!element || !this._previewData.preview) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const enabledElement = getEnabledElement(element);
|
|
205
|
+
this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.RejectPreview);
|
|
206
|
+
this._previewData.preview = null;
|
|
207
|
+
this._previewData.isDrag = false;
|
|
208
|
+
}
|
|
209
|
+
acceptPreview(element = this._previewData.element) {
|
|
210
|
+
if (!element) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const enabledElement = getEnabledElement(element);
|
|
214
|
+
this.applyActiveStrategyCallback(enabledElement, this.getOperationData(element), StrategyCallbacks.AcceptPreview);
|
|
215
|
+
this._previewData.isDrag = false;
|
|
216
|
+
this._previewData.preview = null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -76,6 +76,7 @@ export default class BrushStrategy {
|
|
|
76
76
|
setValue: (brushStrategy: any, func: any) => void;
|
|
77
77
|
preview: (brushStrategy: any, func: any) => void;
|
|
78
78
|
computeInnerCircleRadius: (brushStrategy: any, func: any) => void;
|
|
79
|
+
addPreview: (brushStrategy: any, func: any) => void;
|
|
79
80
|
getStatistics: (brushStrategy: any, func: any) => void;
|
|
80
81
|
compositions: any;
|
|
81
82
|
};
|
|
@@ -92,6 +93,7 @@ export default class BrushStrategy {
|
|
|
92
93
|
onInteractionStart: (enabledElement: Types.IEnabledElement, operationData: LabelmapToolOperationDataAny) => void;
|
|
93
94
|
onInteractionEnd: (enabledElement: Types.IEnabledElement, operationData: LabelmapToolOperationDataAny) => void;
|
|
94
95
|
rejectPreview: (enabledElement: Types.IEnabledElement, operationData: LabelmapToolOperationDataAny) => void;
|
|
96
|
+
addPreview: (enabledElement: any, operationData: LabelmapToolOperationDataAny) => any;
|
|
95
97
|
acceptPreview: (enabledElement: Types.IEnabledElement, operationData: LabelmapToolOperationDataAny) => void;
|
|
96
98
|
preview: (enabledElement: Types.IEnabledElement, operationData: LabelmapToolOperationDataAny) => unknown;
|
|
97
99
|
setValue: (operationData: InitializedOperationData, data: any) => void;
|
|
@@ -17,6 +17,7 @@ export default class BrushStrategy {
|
|
|
17
17
|
[StrategyCallbacks.INTERNAL_setValue]: addSingletonMethod(StrategyCallbacks.INTERNAL_setValue),
|
|
18
18
|
[StrategyCallbacks.Preview]: addSingletonMethod(StrategyCallbacks.Preview, false),
|
|
19
19
|
[StrategyCallbacks.ComputeInnerCircleRadius]: addListMethod(StrategyCallbacks.ComputeInnerCircleRadius),
|
|
20
|
+
[StrategyCallbacks.AddPreview]: addListMethod(StrategyCallbacks.AddPreview),
|
|
20
21
|
[StrategyCallbacks.GetStatistics]: addSingletonMethod(StrategyCallbacks.GetStatistics),
|
|
21
22
|
compositions: null,
|
|
22
23
|
}; }
|
|
@@ -58,6 +59,13 @@ export default class BrushStrategy {
|
|
|
58
59
|
}
|
|
59
60
|
this._onInteractionStart.forEach((func) => func.call(this, initializedData));
|
|
60
61
|
};
|
|
62
|
+
this.addPreview = (enabledElement, operationData) => {
|
|
63
|
+
const initializedData = this.initialize(enabledElement, operationData, StrategyCallbacks.AddPreview);
|
|
64
|
+
if (!initializedData) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
return initializedData.preview || initializedData;
|
|
68
|
+
};
|
|
61
69
|
this.configurationName = name;
|
|
62
70
|
this.compositions = initializers;
|
|
63
71
|
initializers.forEach((initializer) => {
|
|
@@ -11,13 +11,25 @@ export default {
|
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
[StrategyCallbacks.OnInteractionStart]: (operationData) => {
|
|
14
|
-
const { segmentIndex, previewSegmentIndex, segmentationVoxelManager, centerIJK, strategySpecificConfiguration,
|
|
14
|
+
const { segmentIndex, previewSegmentIndex, segmentationVoxelManager, centerIJK, strategySpecificConfiguration, viewPlaneNormal, segmentationImageData, preview, } = operationData;
|
|
15
15
|
if (!strategySpecificConfiguration?.useCenterSegmentIndex) {
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
delete strategySpecificConfiguration.centerSegmentIndex;
|
|
19
19
|
let hasSegmentIndex = false;
|
|
20
20
|
let hasPreviewIndex = false;
|
|
21
|
+
const nestedBounds = [
|
|
22
|
+
...segmentationVoxelManager.getBoundsIJK(),
|
|
23
|
+
];
|
|
24
|
+
if (Math.abs(viewPlaneNormal[0]) > 0.8) {
|
|
25
|
+
nestedBounds[0] = [centerIJK[0], centerIJK[0]];
|
|
26
|
+
}
|
|
27
|
+
else if (Math.abs(viewPlaneNormal[1]) > 0.8) {
|
|
28
|
+
nestedBounds[1] = [centerIJK[1], centerIJK[1]];
|
|
29
|
+
}
|
|
30
|
+
else if (Math.abs(viewPlaneNormal[2]) > 0.8) {
|
|
31
|
+
nestedBounds[2] = [centerIJK[2], centerIJK[2]];
|
|
32
|
+
}
|
|
21
33
|
const callback = ({ value }) => {
|
|
22
34
|
hasSegmentIndex ||= value === segmentIndex;
|
|
23
35
|
hasPreviewIndex ||= value === previewSegmentIndex;
|
|
@@ -25,6 +37,7 @@ export default {
|
|
|
25
37
|
segmentationVoxelManager.forEach(callback, {
|
|
26
38
|
imageData: segmentationImageData,
|
|
27
39
|
isInObject: operationData.isInObject,
|
|
40
|
+
boundsIJK: nestedBounds,
|
|
28
41
|
});
|
|
29
42
|
if (!hasSegmentIndex && !hasPreviewIndex) {
|
|
30
43
|
return;
|
|
@@ -2,6 +2,7 @@ import type { Types } from '@cornerstonejs/core';
|
|
|
2
2
|
type Annotation = {
|
|
3
3
|
annotationUID?: string;
|
|
4
4
|
parentAnnotationUID?: string;
|
|
5
|
+
interpolationUID?: string;
|
|
5
6
|
childAnnotationUIDs?: string[];
|
|
6
7
|
highlighted?: boolean;
|
|
7
8
|
isLocked?: boolean;
|
|
@@ -31,7 +32,7 @@ type Annotation = {
|
|
|
31
32
|
[key: string]: unknown;
|
|
32
33
|
};
|
|
33
34
|
[key: string]: unknown;
|
|
34
|
-
cachedStats?: unknown
|
|
35
|
+
cachedStats?: Record<string, unknown>;
|
|
35
36
|
};
|
|
36
37
|
};
|
|
37
38
|
type Annotations = Array<Annotation>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cornerstonejs/tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Cornerstone3D Tools",
|
|
5
5
|
"types": "./dist/esm/index.d.ts",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"canvas": "^2.11.2"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
|
-
"@cornerstonejs/core": "^2.
|
|
107
|
+
"@cornerstonejs/core": "^2.6.0",
|
|
108
108
|
"@kitware/vtk.js": "32.1.1",
|
|
109
109
|
"@types/d3-array": "^3.0.4",
|
|
110
110
|
"@types/d3-interpolate": "^3.0.1",
|
|
@@ -123,5 +123,5 @@
|
|
|
123
123
|
"type": "individual",
|
|
124
124
|
"url": "https://ohif.org/donate"
|
|
125
125
|
},
|
|
126
|
-
"gitHead": "
|
|
126
|
+
"gitHead": "d5c8036b08e8927a3fbbc1af6a0557687fc0645c"
|
|
127
127
|
}
|