@cornerstonejs/tools 1.12.1 → 1.13.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/cjs/store/ToolGroupManager/ToolGroup.d.ts +3 -3
- package/dist/cjs/store/ToolGroupManager/ToolGroup.js.map +1 -1
- package/dist/cjs/tools/annotation/AngleTool.d.ts +0 -1
- package/dist/cjs/tools/annotation/AngleTool.js +11 -10
- package/dist/cjs/tools/annotation/AngleTool.js.map +1 -1
- package/dist/cjs/tools/annotation/BidirectionalTool.d.ts +0 -1
- package/dist/cjs/tools/annotation/BidirectionalTool.js +14 -13
- package/dist/cjs/tools/annotation/BidirectionalTool.js.map +1 -1
- package/dist/cjs/tools/annotation/CircleROITool.d.ts +0 -1
- package/dist/cjs/tools/annotation/CircleROITool.js +39 -51
- package/dist/cjs/tools/annotation/CircleROITool.js.map +1 -1
- package/dist/cjs/tools/annotation/CobbAngleTool.d.ts +0 -1
- package/dist/cjs/tools/annotation/CobbAngleTool.js +11 -10
- package/dist/cjs/tools/annotation/CobbAngleTool.js.map +1 -1
- package/dist/cjs/tools/annotation/DragProbeTool.js +13 -1
- package/dist/cjs/tools/annotation/DragProbeTool.js.map +1 -1
- package/dist/cjs/tools/annotation/EllipticalROITool.d.ts +0 -1
- package/dist/cjs/tools/annotation/EllipticalROITool.js +33 -45
- package/dist/cjs/tools/annotation/EllipticalROITool.js.map +1 -1
- package/dist/cjs/tools/annotation/LengthTool.d.ts +0 -1
- package/dist/cjs/tools/annotation/LengthTool.js +11 -10
- package/dist/cjs/tools/annotation/LengthTool.js.map +1 -1
- package/dist/cjs/tools/annotation/PlanarFreehandROITool.d.ts +0 -1
- package/dist/cjs/tools/annotation/PlanarFreehandROITool.js +34 -42
- package/dist/cjs/tools/annotation/PlanarFreehandROITool.js.map +1 -1
- package/dist/cjs/tools/annotation/ProbeTool.d.ts +0 -1
- package/dist/cjs/tools/annotation/ProbeTool.js +13 -12
- package/dist/cjs/tools/annotation/ProbeTool.js.map +1 -1
- package/dist/cjs/tools/annotation/RectangleROITool.d.ts +0 -1
- package/dist/cjs/tools/annotation/RectangleROITool.js +31 -47
- package/dist/cjs/tools/annotation/RectangleROITool.js.map +1 -1
- package/dist/cjs/tools/base/AnnotationTool.d.ts +2 -1
- package/dist/cjs/tools/base/AnnotationTool.js +10 -2
- package/dist/cjs/tools/base/AnnotationTool.js.map +1 -1
- package/dist/cjs/types/CalculatorTypes.d.ts +6 -0
- package/dist/cjs/types/CalculatorTypes.js +3 -0
- package/dist/cjs/types/CalculatorTypes.js.map +1 -0
- package/dist/cjs/types/IToolGroup.d.ts +3 -2
- package/dist/cjs/types/ToolProps.d.ts +5 -1
- package/dist/cjs/types/index.d.ts +3 -2
- package/dist/cjs/utilities/math/basic/BasicStatsCalculator.d.ts +14 -0
- package/dist/cjs/utilities/math/basic/BasicStatsCalculator.js +44 -0
- package/dist/cjs/utilities/math/basic/BasicStatsCalculator.js.map +1 -0
- package/dist/cjs/utilities/math/basic/Calculator.d.ts +8 -0
- package/dist/cjs/utilities/math/basic/Calculator.js +6 -0
- package/dist/cjs/utilities/math/basic/Calculator.js.map +1 -0
- package/dist/cjs/utilities/math/basic/index.d.ts +3 -0
- package/dist/cjs/utilities/math/basic/index.js +11 -0
- package/dist/cjs/utilities/math/basic/index.js.map +1 -0
- package/dist/cjs/utilities/math/index.d.ts +2 -1
- package/dist/cjs/utilities/math/index.js +3 -1
- package/dist/cjs/utilities/math/index.js.map +1 -1
- package/dist/cjs/utilities/math/vec2/liangBarksyClip.d.ts +1 -1
- package/dist/cjs/utilities/pointInShapeCallback.d.ts +7 -1
- package/dist/cjs/utilities/pointInShapeCallback.js +6 -1
- package/dist/cjs/utilities/pointInShapeCallback.js.map +1 -1
- package/dist/esm/store/ToolGroupManager/ToolGroup.d.ts +3 -3
- package/dist/esm/store/ToolGroupManager/ToolGroup.js.map +1 -1
- package/dist/esm/tools/annotation/AngleTool.d.ts +0 -1
- package/dist/esm/tools/annotation/AngleTool.js +11 -10
- package/dist/esm/tools/annotation/AngleTool.js.map +1 -1
- package/dist/esm/tools/annotation/BidirectionalTool.d.ts +0 -1
- package/dist/esm/tools/annotation/BidirectionalTool.js +14 -13
- package/dist/esm/tools/annotation/BidirectionalTool.js.map +1 -1
- package/dist/esm/tools/annotation/CircleROITool.d.ts +0 -1
- package/dist/esm/tools/annotation/CircleROITool.js +38 -51
- package/dist/esm/tools/annotation/CircleROITool.js.map +1 -1
- package/dist/esm/tools/annotation/CobbAngleTool.d.ts +0 -1
- package/dist/esm/tools/annotation/CobbAngleTool.js +11 -10
- package/dist/esm/tools/annotation/CobbAngleTool.js.map +1 -1
- package/dist/esm/tools/annotation/DragProbeTool.js +13 -1
- package/dist/esm/tools/annotation/DragProbeTool.js.map +1 -1
- package/dist/esm/tools/annotation/EllipticalROITool.d.ts +0 -1
- package/dist/esm/tools/annotation/EllipticalROITool.js +32 -45
- package/dist/esm/tools/annotation/EllipticalROITool.js.map +1 -1
- package/dist/esm/tools/annotation/LengthTool.d.ts +0 -1
- package/dist/esm/tools/annotation/LengthTool.js +11 -10
- package/dist/esm/tools/annotation/LengthTool.js.map +1 -1
- package/dist/esm/tools/annotation/PlanarFreehandROITool.d.ts +0 -1
- package/dist/esm/tools/annotation/PlanarFreehandROITool.js +33 -42
- package/dist/esm/tools/annotation/PlanarFreehandROITool.js.map +1 -1
- package/dist/esm/tools/annotation/ProbeTool.d.ts +0 -1
- package/dist/esm/tools/annotation/ProbeTool.js +13 -12
- package/dist/esm/tools/annotation/ProbeTool.js.map +1 -1
- package/dist/esm/tools/annotation/RectangleROITool.d.ts +0 -1
- package/dist/esm/tools/annotation/RectangleROITool.js +30 -47
- package/dist/esm/tools/annotation/RectangleROITool.js.map +1 -1
- package/dist/esm/tools/base/AnnotationTool.d.ts +2 -1
- package/dist/esm/tools/base/AnnotationTool.js +9 -2
- package/dist/esm/tools/base/AnnotationTool.js.map +1 -1
- package/dist/esm/types/CalculatorTypes.d.ts +6 -0
- package/dist/esm/types/CalculatorTypes.js +2 -0
- package/dist/esm/types/CalculatorTypes.js.map +1 -0
- package/dist/esm/types/IToolGroup.d.ts +3 -2
- package/dist/esm/types/ToolProps.d.ts +5 -1
- package/dist/esm/types/index.d.ts +3 -2
- package/dist/esm/utilities/math/basic/BasicStatsCalculator.d.ts +14 -0
- package/dist/esm/utilities/math/basic/BasicStatsCalculator.js +36 -0
- package/dist/esm/utilities/math/basic/BasicStatsCalculator.js.map +1 -0
- package/dist/esm/utilities/math/basic/Calculator.d.ts +8 -0
- package/dist/esm/utilities/math/basic/Calculator.js +4 -0
- package/dist/esm/utilities/math/basic/Calculator.js.map +1 -0
- package/dist/esm/utilities/math/basic/index.d.ts +3 -0
- package/dist/esm/utilities/math/basic/index.js +4 -0
- package/dist/esm/utilities/math/basic/index.js.map +1 -0
- package/dist/esm/utilities/math/index.d.ts +2 -1
- package/dist/esm/utilities/math/index.js +2 -1
- package/dist/esm/utilities/math/index.js.map +1 -1
- package/dist/esm/utilities/math/vec2/liangBarksyClip.d.ts +1 -1
- package/dist/esm/utilities/pointInShapeCallback.d.ts +7 -1
- package/dist/esm/utilities/pointInShapeCallback.js +6 -1
- package/dist/esm/utilities/pointInShapeCallback.js.map +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +3 -3
- package/src/store/ToolGroupManager/ToolGroup.ts +4 -3
- package/src/tools/annotation/AngleTool.ts +15 -15
- package/src/tools/annotation/BidirectionalTool.ts +21 -22
- package/src/tools/annotation/CircleROITool.ts +64 -87
- package/src/tools/annotation/CobbAngleTool.ts +15 -15
- package/src/tools/annotation/DragProbeTool.ts +19 -1
- package/src/tools/annotation/EllipticalROITool.ts +47 -70
- package/src/tools/annotation/LengthTool.ts +16 -16
- package/src/tools/annotation/PlanarFreehandROITool.ts +36 -49
- package/src/tools/annotation/ProbeTool.ts +20 -18
- package/src/tools/annotation/RectangleROITool.ts +51 -74
- package/src/tools/base/AnnotationTool.ts +16 -1
- package/src/types/CalculatorTypes.ts +7 -0
- package/src/types/IToolGroup.ts +6 -3
- package/src/types/ToolProps.ts +7 -1
- package/src/types/index.ts +9 -1
- package/src/utilities/math/basic/BasicStatsCalculator.ts +60 -0
- package/src/utilities/math/basic/Calculator.ts +8 -0
- package/src/utilities/math/basic/index.ts +4 -0
- package/src/utilities/math/index.ts +10 -1
- package/src/utilities/pointInShapeCallback.ts +15 -3
|
@@ -113,6 +113,7 @@ class LengthTool extends AnnotationTool {
|
|
|
113
113
|
supportedInteractionTypes: ['Mouse', 'Touch'],
|
|
114
114
|
configuration: {
|
|
115
115
|
preventHandleOutsideImage: false,
|
|
116
|
+
getTextLines: defaultGetTextLines,
|
|
116
117
|
},
|
|
117
118
|
}
|
|
118
119
|
) {
|
|
@@ -731,7 +732,7 @@ class LengthTool extends AnnotationTool {
|
|
|
731
732
|
return renderStatus;
|
|
732
733
|
}
|
|
733
734
|
|
|
734
|
-
const textLines = this.
|
|
735
|
+
const textLines = this.configuration.getTextLines(data, targetId);
|
|
735
736
|
|
|
736
737
|
// Need to update to sync with annotation while unlinked/not moved
|
|
737
738
|
if (!data.handles.textBox.hasMoved) {
|
|
@@ -770,21 +771,6 @@ class LengthTool extends AnnotationTool {
|
|
|
770
771
|
return renderStatus;
|
|
771
772
|
};
|
|
772
773
|
|
|
773
|
-
// text line for the current active length annotation
|
|
774
|
-
_getTextLines(data, targetId) {
|
|
775
|
-
const cachedVolumeStats = data.cachedStats[targetId];
|
|
776
|
-
const { length, unit } = cachedVolumeStats;
|
|
777
|
-
|
|
778
|
-
// Can be null on load
|
|
779
|
-
if (length === undefined || length === null || isNaN(length)) {
|
|
780
|
-
return;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
const textLines = [`${roundNumber(length)} ${unit}`];
|
|
784
|
-
|
|
785
|
-
return textLines;
|
|
786
|
-
}
|
|
787
|
-
|
|
788
774
|
_calculateLength(pos1, pos2) {
|
|
789
775
|
const dx = pos1[0] - pos2[0];
|
|
790
776
|
const dy = pos1[1] - pos2[1];
|
|
@@ -862,5 +848,19 @@ class LengthTool extends AnnotationTool {
|
|
|
862
848
|
}
|
|
863
849
|
}
|
|
864
850
|
|
|
851
|
+
function defaultGetTextLines(data, targetId): string[] {
|
|
852
|
+
const cachedVolumeStats = data.cachedStats[targetId];
|
|
853
|
+
const { length, unit } = cachedVolumeStats;
|
|
854
|
+
|
|
855
|
+
// Can be null on load
|
|
856
|
+
if (length === undefined || length === null || isNaN(length)) {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const textLines = [`${roundNumber(length)} ${unit}`];
|
|
861
|
+
|
|
862
|
+
return textLines;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
865
|
LengthTool.toolName = 'Length';
|
|
866
866
|
export default LengthTool;
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
ModalityUnitOptions,
|
|
60
60
|
getModalityUnit,
|
|
61
61
|
} from '../../utilities/getModalityUnit';
|
|
62
|
+
import { BasicStatsCalculator } from '../../utilities/math/basic';
|
|
62
63
|
|
|
63
64
|
const { pointCanProjectOnLine } = polyline;
|
|
64
65
|
const { EPSILON } = CONSTANTS;
|
|
@@ -124,6 +125,7 @@ const PARALLEL_THRESHOLD = 1 - EPSILON;
|
|
|
124
125
|
*
|
|
125
126
|
* Read more in the Docs section of the website.
|
|
126
127
|
*/
|
|
128
|
+
|
|
127
129
|
class PlanarFreehandROITool extends AnnotationTool {
|
|
128
130
|
static toolName;
|
|
129
131
|
|
|
@@ -215,6 +217,8 @@ class PlanarFreehandROITool extends AnnotationTool {
|
|
|
215
217
|
knotsRatioPercentageOnEdit: 40,
|
|
216
218
|
},
|
|
217
219
|
calculateStats: false,
|
|
220
|
+
getTextLines: defaultGetTextLines,
|
|
221
|
+
statsCalculator: BasicStatsCalculator,
|
|
218
222
|
},
|
|
219
223
|
}
|
|
220
224
|
) {
|
|
@@ -805,25 +809,10 @@ class PlanarFreehandROITool extends AnnotationTool {
|
|
|
805
809
|
const worldPosEnd = imageData.indexToWorld([iMax, jMax, kMax]);
|
|
806
810
|
const canvasPosEnd = viewport.worldToCanvas(worldPosEnd);
|
|
807
811
|
|
|
808
|
-
let count = 0;
|
|
809
|
-
let sum = 0;
|
|
810
|
-
let sumSquares = 0;
|
|
811
|
-
let max = -Infinity;
|
|
812
|
-
|
|
813
|
-
const statCalculator = ({ value: newValue }) => {
|
|
814
|
-
if (newValue > max) {
|
|
815
|
-
max = newValue;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
sum += newValue;
|
|
819
|
-
sumSquares += newValue ** 2;
|
|
820
|
-
count += 1;
|
|
821
|
-
};
|
|
822
|
-
|
|
823
812
|
let curRow = 0;
|
|
824
813
|
let intersections = [];
|
|
825
814
|
let intersectionCounter = 0;
|
|
826
|
-
pointInShapeCallback(
|
|
815
|
+
const pointsInShape = pointInShapeCallback(
|
|
827
816
|
imageData,
|
|
828
817
|
(pointLPS, pointIJK) => {
|
|
829
818
|
let result = true;
|
|
@@ -857,28 +846,26 @@ class PlanarFreehandROITool extends AnnotationTool {
|
|
|
857
846
|
}
|
|
858
847
|
return result;
|
|
859
848
|
},
|
|
860
|
-
|
|
849
|
+
this.configuration.statsCalculator.statsCallback,
|
|
861
850
|
boundsIJK
|
|
862
851
|
);
|
|
863
852
|
|
|
864
|
-
const mean = sum / count;
|
|
865
|
-
|
|
866
|
-
// https://www.strchr.com/standard_deviation_in_one_pass?allcomments=1
|
|
867
|
-
let stdDev = sumSquares / count - mean ** 2;
|
|
868
|
-
stdDev = Math.sqrt(stdDev);
|
|
869
|
-
|
|
870
853
|
const modalityUnit = getModalityUnit(
|
|
871
854
|
metadata.Modality,
|
|
872
855
|
annotation.metadata.referencedImageId,
|
|
873
856
|
modalityUnitOptions
|
|
874
857
|
);
|
|
875
858
|
|
|
859
|
+
const stats = this.configuration.statsCalculator.getStatistics();
|
|
860
|
+
|
|
876
861
|
cachedStats[targetId] = {
|
|
877
862
|
Modality: metadata.Modality,
|
|
878
863
|
area,
|
|
879
|
-
mean,
|
|
880
|
-
max,
|
|
881
|
-
stdDev,
|
|
864
|
+
mean: stats[1]?.value,
|
|
865
|
+
max: stats[0]?.value,
|
|
866
|
+
stdDev: stats[3]?.value,
|
|
867
|
+
statsArray: stats,
|
|
868
|
+
pointsInShape: pointsInShape,
|
|
882
869
|
areaUnit: getCalibratedAreaUnits(null, image),
|
|
883
870
|
modalityUnit,
|
|
884
871
|
};
|
|
@@ -895,7 +882,7 @@ class PlanarFreehandROITool extends AnnotationTool {
|
|
|
895
882
|
const data = annotation.data;
|
|
896
883
|
const targetId = this.getTargetId(viewport);
|
|
897
884
|
|
|
898
|
-
const textLines = this.
|
|
885
|
+
const textLines = this.configuration.getTextLines(data, targetId);
|
|
899
886
|
if (!textLines || textLines.length === 0) {
|
|
900
887
|
return;
|
|
901
888
|
}
|
|
@@ -941,35 +928,35 @@ class PlanarFreehandROITool extends AnnotationTool {
|
|
|
941
928
|
bottomRight: viewport.canvasToWorld([left + width, top + height]),
|
|
942
929
|
};
|
|
943
930
|
};
|
|
931
|
+
}
|
|
944
932
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
933
|
+
function defaultGetTextLines(data, targetId): string[] {
|
|
934
|
+
const cachedVolumeStats = data.cachedStats[targetId];
|
|
935
|
+
const { area, mean, stdDev, max, isEmptyArea, areaUnit, modalityUnit } =
|
|
936
|
+
cachedVolumeStats;
|
|
949
937
|
|
|
950
|
-
|
|
938
|
+
const textLines: string[] = [];
|
|
951
939
|
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
940
|
+
if (area) {
|
|
941
|
+
const areaLine = isEmptyArea
|
|
942
|
+
? `Area: Oblique not supported`
|
|
943
|
+
: `Area: ${roundNumber(area)} ${areaUnit}`;
|
|
944
|
+
textLines.push(areaLine);
|
|
945
|
+
}
|
|
958
946
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
947
|
+
if (mean) {
|
|
948
|
+
textLines.push(`Mean: ${roundNumber(mean)} ${modalityUnit}`);
|
|
949
|
+
}
|
|
962
950
|
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
951
|
+
if (max) {
|
|
952
|
+
textLines.push(`Max: ${roundNumber(max)} ${modalityUnit}`);
|
|
953
|
+
}
|
|
966
954
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
955
|
+
if (stdDev) {
|
|
956
|
+
textLines.push(`Std Dev: ${roundNumber(stdDev)} ${modalityUnit}`);
|
|
957
|
+
}
|
|
970
958
|
|
|
971
|
-
|
|
972
|
-
};
|
|
959
|
+
return textLines;
|
|
973
960
|
}
|
|
974
961
|
|
|
975
962
|
PlanarFreehandROITool.toolName = 'PlanarFreehandROI';
|
|
@@ -94,6 +94,7 @@ const { transformWorldToIndex } = csUtils;
|
|
|
94
94
|
* Read more in the Docs section of the website.
|
|
95
95
|
*
|
|
96
96
|
*/
|
|
97
|
+
|
|
97
98
|
class ProbeTool extends AnnotationTool {
|
|
98
99
|
static toolName;
|
|
99
100
|
|
|
@@ -118,6 +119,7 @@ class ProbeTool extends AnnotationTool {
|
|
|
118
119
|
configuration: {
|
|
119
120
|
shadow: true,
|
|
120
121
|
preventHandleOutsideImage: false,
|
|
122
|
+
getTextLines: defaultGetTextLines,
|
|
121
123
|
},
|
|
122
124
|
}
|
|
123
125
|
) {
|
|
@@ -525,7 +527,7 @@ class ProbeTool extends AnnotationTool {
|
|
|
525
527
|
|
|
526
528
|
renderStatus = true;
|
|
527
529
|
|
|
528
|
-
const textLines = this.
|
|
530
|
+
const textLines = this.configuration.getTextLines(data, targetId);
|
|
529
531
|
if (textLines) {
|
|
530
532
|
const textCanvasCoordinates = [
|
|
531
533
|
canvasCoordinates[0] + 6,
|
|
@@ -547,23 +549,6 @@ class ProbeTool extends AnnotationTool {
|
|
|
547
549
|
return renderStatus;
|
|
548
550
|
};
|
|
549
551
|
|
|
550
|
-
_getTextLines(data, targetId: string): string[] | undefined {
|
|
551
|
-
const cachedVolumeStats = data.cachedStats[targetId];
|
|
552
|
-
const { index, value, modalityUnit } = cachedVolumeStats;
|
|
553
|
-
|
|
554
|
-
if (value === undefined) {
|
|
555
|
-
return;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
const textLines = [];
|
|
559
|
-
|
|
560
|
-
textLines.push(`(${index[0]}, ${index[1]}, ${index[2]})`);
|
|
561
|
-
|
|
562
|
-
textLines.push(`${value.toFixed(2)} ${modalityUnit}`);
|
|
563
|
-
|
|
564
|
-
return textLines;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
552
|
_calculateCachedStats(
|
|
568
553
|
annotation,
|
|
569
554
|
renderingEngine,
|
|
@@ -662,5 +647,22 @@ class ProbeTool extends AnnotationTool {
|
|
|
662
647
|
}
|
|
663
648
|
}
|
|
664
649
|
|
|
650
|
+
function defaultGetTextLines(data, targetId): string[] {
|
|
651
|
+
const cachedVolumeStats = data.cachedStats[targetId];
|
|
652
|
+
const { index, value, modalityUnit } = cachedVolumeStats;
|
|
653
|
+
|
|
654
|
+
if (value === undefined) {
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
const textLines = [];
|
|
659
|
+
|
|
660
|
+
textLines.push(`(${index[0]}, ${index[1]}, ${index[2]})`);
|
|
661
|
+
|
|
662
|
+
textLines.push(`${value.toFixed(2)} ${modalityUnit}`);
|
|
663
|
+
|
|
664
|
+
return textLines;
|
|
665
|
+
}
|
|
666
|
+
|
|
665
667
|
ProbeTool.toolName = 'Probe';
|
|
666
668
|
export default ProbeTool;
|
|
@@ -56,6 +56,8 @@ import {
|
|
|
56
56
|
import { StyleSpecifier } from '../../types/AnnotationStyle';
|
|
57
57
|
import { getModalityUnit } from '../../utilities/getModalityUnit';
|
|
58
58
|
import { isViewportPreScaled } from '../../utilities/viewport/isViewportPreScaled';
|
|
59
|
+
import { pointInShapeCallback } from '../../utilities/';
|
|
60
|
+
import { BasicStatsCalculator } from '../../utilities/math/basic';
|
|
59
61
|
|
|
60
62
|
const { transformWorldToIndex } = csUtils;
|
|
61
63
|
|
|
@@ -97,6 +99,7 @@ const { transformWorldToIndex } = csUtils;
|
|
|
97
99
|
*
|
|
98
100
|
* Read more in the Docs section of the website.
|
|
99
101
|
*/
|
|
102
|
+
|
|
100
103
|
class RectangleROITool extends AnnotationTool {
|
|
101
104
|
static toolName;
|
|
102
105
|
|
|
@@ -119,6 +122,8 @@ class RectangleROITool extends AnnotationTool {
|
|
|
119
122
|
configuration: {
|
|
120
123
|
shadow: true,
|
|
121
124
|
preventHandleOutsideImage: false,
|
|
125
|
+
getTextLines: defaultGetTextLines,
|
|
126
|
+
statsCalculator: BasicStatsCalculator,
|
|
122
127
|
},
|
|
123
128
|
}
|
|
124
129
|
) {
|
|
@@ -786,7 +791,7 @@ class RectangleROITool extends AnnotationTool {
|
|
|
786
791
|
|
|
787
792
|
renderStatus = true;
|
|
788
793
|
|
|
789
|
-
const textLines = this.
|
|
794
|
+
const textLines = this.configuration.getTextLines(data, targetId);
|
|
790
795
|
if (!textLines || textLines.length === 0) {
|
|
791
796
|
continue;
|
|
792
797
|
}
|
|
@@ -845,33 +850,6 @@ class RectangleROITool extends AnnotationTool {
|
|
|
845
850
|
};
|
|
846
851
|
};
|
|
847
852
|
|
|
848
|
-
/**
|
|
849
|
-
* _getTextLines - Returns the Area, mean and std deviation of the area of the
|
|
850
|
-
* target volume enclosed by the rectangle.
|
|
851
|
-
*
|
|
852
|
-
* @param data - The annotation tool-specific data.
|
|
853
|
-
* @param targetId - The volumeId of the volume to display the stats for.
|
|
854
|
-
* @param isPreScaled - Whether the viewport is pre-scaled or not.
|
|
855
|
-
*/
|
|
856
|
-
_getTextLines = (data, targetId: string): string[] | undefined => {
|
|
857
|
-
const cachedVolumeStats = data.cachedStats[targetId];
|
|
858
|
-
const { area, mean, max, stdDev, areaUnit, modalityUnit } =
|
|
859
|
-
cachedVolumeStats;
|
|
860
|
-
|
|
861
|
-
if (mean === undefined) {
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
const textLines: string[] = [];
|
|
866
|
-
|
|
867
|
-
textLines.push(`Area: ${roundNumber(area)} ${areaUnit}`);
|
|
868
|
-
textLines.push(`Mean: ${roundNumber(mean)} ${modalityUnit}`);
|
|
869
|
-
textLines.push(`Max: ${roundNumber(max)} ${modalityUnit}`);
|
|
870
|
-
textLines.push(`Std Dev: ${roundNumber(stdDev)} ${modalityUnit}`);
|
|
871
|
-
|
|
872
|
-
return textLines;
|
|
873
|
-
};
|
|
874
|
-
|
|
875
853
|
/**
|
|
876
854
|
* _calculateCachedStats - For each volume in the frame of reference that a
|
|
877
855
|
* tool instance in particular viewport defines as its target volume, find the
|
|
@@ -945,6 +923,12 @@ class RectangleROITool extends AnnotationTool {
|
|
|
945
923
|
const kMin = Math.min(worldPos1Index[2], worldPos2Index[2]);
|
|
946
924
|
const kMax = Math.max(worldPos1Index[2], worldPos2Index[2]);
|
|
947
925
|
|
|
926
|
+
const boundsIJK = [
|
|
927
|
+
[iMin, iMax],
|
|
928
|
+
[jMin, jMax],
|
|
929
|
+
[kMin, kMax],
|
|
930
|
+
] as [Types.Point2, Types.Point2, Types.Point2];
|
|
931
|
+
|
|
948
932
|
const { worldWidth, worldHeight } = getWorldWidthAndHeightFromCorners(
|
|
949
933
|
viewPlaneNormal,
|
|
950
934
|
viewUp,
|
|
@@ -955,61 +939,29 @@ class RectangleROITool extends AnnotationTool {
|
|
|
955
939
|
|
|
956
940
|
const area = Math.abs(worldWidth * worldHeight) / (scale * scale);
|
|
957
941
|
|
|
958
|
-
let count = 0;
|
|
959
|
-
let mean = 0;
|
|
960
|
-
let stdDev = 0;
|
|
961
|
-
let max = -Infinity;
|
|
962
|
-
|
|
963
|
-
const yMultiple = dimensions[0];
|
|
964
|
-
const zMultiple = dimensions[0] * dimensions[1];
|
|
965
|
-
|
|
966
|
-
//Todo: this can be replaced by pointInShapeCallback....
|
|
967
|
-
// This is a triple loop, but one of these 3 values will be constant
|
|
968
|
-
// In the planar view.
|
|
969
|
-
for (let k = kMin; k <= kMax; k++) {
|
|
970
|
-
for (let j = jMin; j <= jMax; j++) {
|
|
971
|
-
for (let i = iMin; i <= iMax; i++) {
|
|
972
|
-
const value = scalarData[k * zMultiple + j * yMultiple + i];
|
|
973
|
-
|
|
974
|
-
if (value > max) {
|
|
975
|
-
max = value;
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
count++;
|
|
979
|
-
mean += value;
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
mean /= count;
|
|
985
|
-
|
|
986
|
-
for (let k = kMin; k <= kMax; k++) {
|
|
987
|
-
for (let j = jMin; j <= jMax; j++) {
|
|
988
|
-
for (let i = iMin; i <= iMax; i++) {
|
|
989
|
-
const value = scalarData[k * zMultiple + j * yMultiple + i];
|
|
990
|
-
|
|
991
|
-
const valueMinusMean = value - mean;
|
|
992
|
-
|
|
993
|
-
stdDev += valueMinusMean * valueMinusMean;
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
stdDev /= count;
|
|
999
|
-
stdDev = Math.sqrt(stdDev);
|
|
1000
|
-
|
|
1001
942
|
const modalityUnit = getModalityUnit(
|
|
1002
943
|
metadata.Modality,
|
|
1003
944
|
annotation.metadata.referencedImageId,
|
|
1004
945
|
modalityUnitOptions
|
|
1005
946
|
);
|
|
1006
947
|
|
|
948
|
+
const pointsInShape = pointInShapeCallback(
|
|
949
|
+
imageData,
|
|
950
|
+
() => true,
|
|
951
|
+
this.configuration.statsCalculator.statsCallback,
|
|
952
|
+
boundsIJK
|
|
953
|
+
);
|
|
954
|
+
|
|
955
|
+
const stats = this.configuration.statsCalculator.getStatistics();
|
|
956
|
+
|
|
1007
957
|
cachedStats[targetId] = {
|
|
1008
958
|
Modality: metadata.Modality,
|
|
1009
959
|
area,
|
|
1010
|
-
mean,
|
|
1011
|
-
stdDev,
|
|
1012
|
-
max,
|
|
960
|
+
mean: stats[1]?.value,
|
|
961
|
+
stdDev: stats[2]?.value,
|
|
962
|
+
max: stats[0]?.value,
|
|
963
|
+
statsArray: stats,
|
|
964
|
+
pointsInShape: pointsInShape,
|
|
1013
965
|
areaUnit: getCalibratedAreaUnits(null, image),
|
|
1014
966
|
modalityUnit,
|
|
1015
967
|
};
|
|
@@ -1044,5 +996,30 @@ class RectangleROITool extends AnnotationTool {
|
|
|
1044
996
|
};
|
|
1045
997
|
}
|
|
1046
998
|
|
|
999
|
+
/**
|
|
1000
|
+
* _getTextLines - Returns the Area, mean and std deviation of the area of the
|
|
1001
|
+
* target volume enclosed by the rectangle.
|
|
1002
|
+
*
|
|
1003
|
+
* @param data - The annotation tool-specific data.
|
|
1004
|
+
* @param targetId - The volumeId of the volume to display the stats for.
|
|
1005
|
+
*/
|
|
1006
|
+
function defaultGetTextLines(data, targetId: string): string[] {
|
|
1007
|
+
const cachedVolumeStats = data.cachedStats[targetId];
|
|
1008
|
+
const { area, mean, max, stdDev, areaUnit, modalityUnit } = cachedVolumeStats;
|
|
1009
|
+
|
|
1010
|
+
if (mean === undefined) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
const textLines: string[] = [];
|
|
1015
|
+
|
|
1016
|
+
textLines.push(`Area: ${roundNumber(area)} ${areaUnit}`);
|
|
1017
|
+
textLines.push(`Mean: ${roundNumber(mean)} ${modalityUnit}`);
|
|
1018
|
+
textLines.push(`Max: ${roundNumber(max)} ${modalityUnit}`);
|
|
1019
|
+
textLines.push(`Std Dev: ${roundNumber(stdDev)} ${modalityUnit}`);
|
|
1020
|
+
|
|
1021
|
+
return textLines;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1047
1024
|
RectangleROITool.toolName = 'RectangleROI';
|
|
1048
1025
|
export default RectangleROITool;
|
|
@@ -18,10 +18,12 @@ import {
|
|
|
18
18
|
EventTypes,
|
|
19
19
|
ToolHandle,
|
|
20
20
|
InteractionTypes,
|
|
21
|
+
ToolProps,
|
|
22
|
+
PublicToolProps,
|
|
21
23
|
} from '../../types';
|
|
22
24
|
import { StyleSpecifier } from '../../types/AnnotationStyle';
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
/**-q
|
|
25
27
|
* Abstract class for tools which create and display annotations on the
|
|
26
28
|
* cornerstone3D canvas. In addition, it provides a base class for segmentation
|
|
27
29
|
* tools that require drawing an annotation before running the segmentation strategy
|
|
@@ -37,6 +39,19 @@ abstract class AnnotationTool extends AnnotationDisplayTool {
|
|
|
37
39
|
// Abstract Methods - Must be implemented.
|
|
38
40
|
// ===================================================================
|
|
39
41
|
|
|
42
|
+
constructor(toolProps: PublicToolProps, defaultToolProps: ToolProps) {
|
|
43
|
+
super(toolProps, defaultToolProps);
|
|
44
|
+
|
|
45
|
+
if (toolProps.configuration?.getTextLines) {
|
|
46
|
+
this.configuration.getTextLines = toolProps.configuration.getTextLines;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (toolProps.configuration?.statsCalculator) {
|
|
50
|
+
this.configuration.statsCalculator =
|
|
51
|
+
toolProps.configuration.statsCalculator;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
40
55
|
/**
|
|
41
56
|
* @abstract addNewAnnotation Creates a new annotation based on the clicked mouse position
|
|
42
57
|
*
|
package/src/types/IToolGroup.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import { SetToolBindingsType, ToolOptionsType } from './ISetToolModeOptions';
|
|
3
3
|
import { MouseBindings } from '../enums';
|
|
4
|
+
import { ToolConfiguration } from '../types';
|
|
4
5
|
/**
|
|
5
6
|
* ToolGroup interface
|
|
6
7
|
*/
|
|
@@ -19,8 +20,10 @@ export default interface IToolGroup {
|
|
|
19
20
|
getViewportsInfo: () => Array<Types.IViewportId>;
|
|
20
21
|
/** Get the toolInstance of the toolName */
|
|
21
22
|
getToolInstance: { (toolName: string): any };
|
|
22
|
-
/** Add a tool to toolGroup with its configuration */
|
|
23
|
-
addTool: {
|
|
23
|
+
/** Add a tool to toolGroup with its configuration and custom calculator if wanted */
|
|
24
|
+
addTool: {
|
|
25
|
+
(toolName: string, toolConfiguration?: ToolConfiguration): void;
|
|
26
|
+
};
|
|
24
27
|
/** Add tool instance, if you want to create more than one instance from the same tool e.g., brush/eraser tool */
|
|
25
28
|
addToolInstance: {
|
|
26
29
|
(ttoolName: string, parentClassName: string, configuration?: any): void;
|
|
@@ -62,7 +65,7 @@ export default interface IToolGroup {
|
|
|
62
65
|
setToolConfiguration: {
|
|
63
66
|
(
|
|
64
67
|
toolName: string,
|
|
65
|
-
configuration:
|
|
68
|
+
configuration: ToolConfiguration,
|
|
66
69
|
overwrite?: boolean
|
|
67
70
|
): void;
|
|
68
71
|
};
|
package/src/types/ToolProps.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { Calculator } from '../utilities/math/basic';
|
|
2
|
+
|
|
1
3
|
type SharedToolProp = {
|
|
2
4
|
/** supported interactions for the tool */
|
|
3
5
|
supportedInteractionTypes?: Array<string>;
|
|
4
6
|
/** tool specific tool configuration */
|
|
5
|
-
configuration?:
|
|
7
|
+
configuration?: ToolConfiguration;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type ToolConfiguration = Record<string, any> & {
|
|
11
|
+
statsCalculator?: Calculator;
|
|
6
12
|
};
|
|
7
13
|
|
|
8
14
|
export type ToolProps = SharedToolProp;
|
package/src/types/index.ts
CHANGED
|
@@ -21,7 +21,11 @@ import type * as AnnotationStyle from './AnnotationStyle';
|
|
|
21
21
|
import type ToolHandle from './ToolHandle';
|
|
22
22
|
import type { AnnotationHandle, TextBoxHandle } from './ToolHandle';
|
|
23
23
|
import type InteractionTypes from './InteractionTypes';
|
|
24
|
-
import type {
|
|
24
|
+
import type {
|
|
25
|
+
ToolProps,
|
|
26
|
+
PublicToolProps,
|
|
27
|
+
ToolConfiguration,
|
|
28
|
+
} from './ToolProps';
|
|
25
29
|
import type { SVGCursorDescriptor, SVGPoint } from './CursorTypes';
|
|
26
30
|
import type JumpToSliceOptions from './JumpToSliceOptions';
|
|
27
31
|
import type ScrollOptions from './ScrollOptions';
|
|
@@ -52,6 +56,7 @@ import IToolClassReference from './IToolClassReference';
|
|
|
52
56
|
import { ContourSegmentationData } from './ContourTypes';
|
|
53
57
|
import IAnnotationManager from './IAnnotationManager';
|
|
54
58
|
import AnnotationGroupSelector from './AnnotationGroupSelector';
|
|
59
|
+
import { Statistics } from './CalculatorTypes';
|
|
55
60
|
|
|
56
61
|
export type {
|
|
57
62
|
// AnnotationState
|
|
@@ -68,6 +73,7 @@ export type {
|
|
|
68
73
|
PlanarBoundingBox,
|
|
69
74
|
ToolProps,
|
|
70
75
|
PublicToolProps,
|
|
76
|
+
ToolConfiguration,
|
|
71
77
|
// Event data
|
|
72
78
|
EventTypes,
|
|
73
79
|
IPoints,
|
|
@@ -114,4 +120,6 @@ export type {
|
|
|
114
120
|
FloodFillOptions,
|
|
115
121
|
// Contour
|
|
116
122
|
ContourSegmentationData,
|
|
123
|
+
//Statistics
|
|
124
|
+
Statistics,
|
|
117
125
|
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Statistics } from '../../../types';
|
|
2
|
+
import Calculator from './Calculator';
|
|
3
|
+
|
|
4
|
+
export default class BasicStatsCalculator extends Calculator {
|
|
5
|
+
private static max = -Infinity;
|
|
6
|
+
private static currentMax = 0;
|
|
7
|
+
private static sum = 0;
|
|
8
|
+
private static sumSquares = 0;
|
|
9
|
+
private static squaredDiffSum = 0;
|
|
10
|
+
private static count = 0;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* This callback is used when we verify if the point is in the annotion drawn so we can get every point
|
|
14
|
+
* in the shape to calculate the statistics
|
|
15
|
+
* @param value of the point in the shape of the annotation
|
|
16
|
+
*/
|
|
17
|
+
static statsCallback = ({ value: newValue }): void => {
|
|
18
|
+
if (newValue > this.max) {
|
|
19
|
+
this.max = newValue;
|
|
20
|
+
this.currentMax = newValue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.count += 1;
|
|
24
|
+
|
|
25
|
+
this.sum += newValue;
|
|
26
|
+
this.sumSquares += newValue ** 2;
|
|
27
|
+
this.squaredDiffSum += Math.pow(newValue - this.sum / this.count, 2);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Basic function that calculates statictics for a given array of points.
|
|
32
|
+
* @param points
|
|
33
|
+
* @returns An object that contains :
|
|
34
|
+
* max : The maximum value of the array
|
|
35
|
+
* mean : mean of the array
|
|
36
|
+
* stdDev : standard deviation of the array
|
|
37
|
+
* stdDevWithSumSquare : standard deviation of the array using sum²
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
static getStatistics = (): Statistics[] => {
|
|
41
|
+
const mean = this.sum / this.count;
|
|
42
|
+
const stdDev = Math.sqrt(this.squaredDiffSum / this.count);
|
|
43
|
+
const stdDevWithSumSquare = Math.sqrt(
|
|
44
|
+
this.sumSquares / this.count - mean ** 2
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
this.max = -Infinity;
|
|
48
|
+
this.sum = 0;
|
|
49
|
+
this.sumSquares = 0;
|
|
50
|
+
this.squaredDiffSum = 0;
|
|
51
|
+
this.count = 0;
|
|
52
|
+
|
|
53
|
+
return [
|
|
54
|
+
{ name: 'max', value: this.currentMax, unit: null },
|
|
55
|
+
{ name: 'mean', value: mean, unit: null },
|
|
56
|
+
{ name: 'stdDev', value: stdDev, unit: null },
|
|
57
|
+
{ name: 'stdDevWithSumSquare', value: stdDevWithSumSquare, unit: null },
|
|
58
|
+
];
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -4,5 +4,14 @@ import * as lineSegment from './line';
|
|
|
4
4
|
import * as rectangle from './rectangle';
|
|
5
5
|
import * as polyline from './polyline';
|
|
6
6
|
import * as point from './point';
|
|
7
|
+
import * as BasicStatsCalculator from './basic';
|
|
7
8
|
|
|
8
|
-
export {
|
|
9
|
+
export {
|
|
10
|
+
vec2,
|
|
11
|
+
ellipse,
|
|
12
|
+
lineSegment,
|
|
13
|
+
rectangle,
|
|
14
|
+
polyline,
|
|
15
|
+
point,
|
|
16
|
+
BasicStatsCalculator,
|
|
17
|
+
};
|