larvitar 1.5.13 → 2.0.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.
Files changed (103) hide show
  1. package/.vscode/settings.json +4 -0
  2. package/README.md +78 -48
  3. package/bundler/webpack.common.js +27 -0
  4. package/bundler/webpack.dev.js +23 -0
  5. package/bundler/webpack.prod.js +19 -0
  6. package/decs.d.ts +12 -0
  7. package/dist/imaging/MetaDataReadable.d.ts +39 -0
  8. package/dist/imaging/MetaDataTypes.d.ts +3488 -0
  9. package/dist/imaging/imageAnonymization.d.ts +12 -0
  10. package/dist/imaging/imageColormaps.d.ts +47 -0
  11. package/dist/imaging/imageContours.d.ts +18 -0
  12. package/dist/imaging/imageIo.d.ts +42 -0
  13. package/dist/imaging/imageLayers.d.ts +56 -0
  14. package/dist/imaging/imageLoading.d.ts +65 -0
  15. package/dist/imaging/imageParsing.d.ts +46 -0
  16. package/dist/imaging/imagePresets.d.ts +43 -0
  17. package/dist/imaging/imageRendering.d.ts +238 -0
  18. package/dist/imaging/imageReslice.d.ts +14 -0
  19. package/dist/imaging/imageStore.d.ts +121 -0
  20. package/dist/imaging/imageTags.d.ts +22 -0
  21. package/dist/imaging/imageTools.d.ts +20 -0
  22. package/dist/imaging/imageUtils.d.ts +165 -0
  23. package/dist/imaging/loaders/commonLoader.d.ts +103 -0
  24. package/dist/imaging/loaders/dicomLoader.d.ts +29 -0
  25. package/dist/imaging/loaders/fileLoader.d.ts +33 -0
  26. package/dist/imaging/loaders/multiframeLoader.d.ts +37 -0
  27. package/dist/imaging/loaders/nrrdLoader.d.ts +112 -0
  28. package/dist/imaging/loaders/resliceLoader.d.ts +15 -0
  29. package/dist/imaging/monitors/memory.d.ts +41 -0
  30. package/dist/imaging/monitors/performance.d.ts +23 -0
  31. package/dist/imaging/parsers/ecg.d.ts +15 -0
  32. package/dist/imaging/parsers/nrrd.d.ts +3 -0
  33. package/dist/imaging/tools/custom/4dSliceScrollTool.d.ts +12 -0
  34. package/dist/imaging/tools/custom/contourTool.d.ts +409 -0
  35. package/dist/imaging/tools/custom/diameterTool.d.ts +18 -0
  36. package/dist/imaging/tools/custom/editMaskTool.d.ts +22 -0
  37. package/dist/imaging/tools/custom/ellipticalRoiOverlayTool.d.ts +45 -0
  38. package/dist/imaging/tools/custom/polygonSegmentationMixin.d.ts +54 -0
  39. package/dist/imaging/tools/custom/polylineScissorsTool.d.ts +11 -0
  40. package/dist/imaging/tools/custom/rectangleRoiOverlayTool.d.ts +45 -0
  41. package/dist/imaging/tools/custom/seedTool.d.ts +0 -0
  42. package/dist/imaging/tools/custom/setLabelMap3D.d.ts +39 -0
  43. package/dist/imaging/tools/custom/thresholdsBrushTool.d.ts +19 -0
  44. package/dist/imaging/tools/default.d.ts +53 -0
  45. package/dist/imaging/tools/interaction.d.ts +30 -0
  46. package/dist/imaging/tools/io.d.ts +38 -0
  47. package/dist/imaging/tools/main.d.ts +81 -0
  48. package/dist/imaging/tools/segmentation.d.ts +125 -0
  49. package/dist/imaging/tools/state.d.ts +17 -0
  50. package/dist/imaging/tools/strategies/eraseFreehand.d.ts +16 -0
  51. package/dist/imaging/tools/strategies/fillFreehand.d.ts +16 -0
  52. package/dist/imaging/tools/strategies/index.d.ts +2 -0
  53. package/dist/index.d.ts +34 -0
  54. package/dist/larvitar.js +89801 -0
  55. package/dist/larvitar.js.map +1 -0
  56. package/imaging/MetaDataReadable.ts +40 -0
  57. package/imaging/MetaDataTypes.ts +3490 -0
  58. package/imaging/dataDictionary.json +5328 -5328
  59. package/imaging/{imageAnonymization.js → imageAnonymization.ts} +41 -13
  60. package/imaging/{imageColormaps.js → imageColormaps.ts} +48 -30
  61. package/imaging/{imageContours.js → imageContours.ts} +24 -22
  62. package/imaging/{imageIo.js → imageIo.ts} +89 -52
  63. package/imaging/{imageLayers.js → imageLayers.ts} +31 -14
  64. package/imaging/{imageLoading.js → imageLoading.ts} +108 -45
  65. package/imaging/{imageParsing.js → imageParsing.ts} +158 -80
  66. package/imaging/{imagePresets.js → imagePresets.ts} +44 -11
  67. package/imaging/imageRendering.ts +1091 -0
  68. package/imaging/{imageReslice.js → imageReslice.ts} +18 -9
  69. package/imaging/imageStore.ts +487 -0
  70. package/imaging/imageTags.ts +609 -0
  71. package/imaging/imageTools.js +2 -1
  72. package/imaging/{imageUtils.js → imageUtils.ts} +211 -701
  73. package/imaging/loaders/{commonLoader.js → commonLoader.ts} +73 -24
  74. package/imaging/loaders/{dicomLoader.js → dicomLoader.ts} +25 -5
  75. package/imaging/loaders/{fileLoader.js → fileLoader.ts} +5 -5
  76. package/imaging/loaders/{multiframeLoader.js → multiframeLoader.ts} +145 -90
  77. package/imaging/loaders/{nrrdLoader.js → nrrdLoader.ts} +230 -64
  78. package/imaging/loaders/{resliceLoader.js → resliceLoader.ts} +51 -20
  79. package/imaging/monitors/{memory.js → memory.ts} +54 -8
  80. package/imaging/monitors/performance.ts +34 -0
  81. package/imaging/parsers/ecg.ts +51 -0
  82. package/imaging/tools/README.md +27 -0
  83. package/imaging/tools/custom/4dSliceScrollTool.js +47 -46
  84. package/imaging/tools/custom/ellipticalRoiOverlayTool.js +534 -0
  85. package/imaging/tools/custom/polylineScissorsTool.js +1 -1
  86. package/imaging/tools/custom/rectangleRoiOverlayTool.js +564 -0
  87. package/imaging/tools/{setLabelMap3D.js → custom/setLabelMap3D.ts} +19 -25
  88. package/imaging/tools/{default.js → default.ts} +114 -30
  89. package/imaging/tools/{interaction.js → interaction.ts} +42 -23
  90. package/imaging/tools/{io.js → io.ts} +47 -31
  91. package/imaging/tools/{main.js → main.ts} +105 -40
  92. package/imaging/tools/{segmentation.js → segmentation.ts} +95 -68
  93. package/imaging/tools/{state.js → state.ts} +7 -12
  94. package/imaging/tools/types.d.ts +243 -0
  95. package/imaging/types.d.ts +197 -0
  96. package/{index.js → index.ts} +43 -14
  97. package/jsdoc.json +1 -1
  98. package/package.json +32 -14
  99. package/tsconfig.json +102 -0
  100. package/imaging/imageRendering.js +0 -860
  101. package/imaging/imageStore.js +0 -322
  102. package/modules/vuex/larvitar.js +0 -187
  103. /package/imaging/tools/{polygonSegmentationMixin.js → custom/polygonSegmentationMixin.js} +0 -0
@@ -0,0 +1,564 @@
1
+ import cornerstoneTools from "cornerstone-tools";
2
+
3
+ const external = cornerstoneTools.external;
4
+ const BaseAnnotationTool = cornerstoneTools.importInternal(
5
+ "base/BaseAnnotationTool"
6
+ );
7
+
8
+ // State
9
+ const getToolState = cornerstoneTools.getToolState;
10
+ const toolStyle = cornerstoneTools.toolStyle;
11
+ const toolColors = cornerstoneTools.toolColors;
12
+
13
+ // Drawing
14
+ const getNewContext = cornerstoneTools.importInternal("drawing/getNewContext");
15
+ const draw = cornerstoneTools.importInternal("drawing/draw");
16
+ const drawHandles = cornerstoneTools.importInternal("drawing/drawHandles");
17
+ const drawRect = cornerstoneTools.importInternal("drawing/drawRect");
18
+ const drawLinkedTextBox = cornerstoneTools.importInternal(
19
+ "drawing/drawLinkedTextBox"
20
+ );
21
+ const setShadow = cornerstoneTools.importInternal("drawing/setShadow");
22
+
23
+ // Util
24
+ const calculateSUV = cornerstoneTools.importInternal("util/calculateSUV");
25
+ const getROITextBoxCoords = cornerstoneTools.importInternal(
26
+ "util/getROITextBoxCoords"
27
+ );
28
+ const numbersWithCommas = cornerstoneTools.importInternal(
29
+ "util/numbersWithCommas"
30
+ );
31
+ const throttle = cornerstoneTools.importInternal("util/throttle");
32
+ const { rectangleRoiCursor } = cornerstoneTools.importInternal("tools/cursors");
33
+ const getLogger = cornerstoneTools.importInternal("util/getLogger");
34
+ const getPixelSpacing = cornerstoneTools.importInternal("util/getPixelSpacing");
35
+ const getModule = cornerstoneTools.getModule;
36
+
37
+ const logger = getLogger("tools:annotation:RectangleRoiTool");
38
+
39
+ /**
40
+ * @public
41
+ * @class RectangleRoiTool
42
+ * @memberof Tools.Annotation
43
+ * @classdesc Tool for drawing rectangular regions of interest, and measuring
44
+ * the statistics of the enclosed pixels.
45
+ * @extends Tools.Base.BaseAnnotationTool
46
+ */
47
+ export default class RectangleRoiOverlayTool extends BaseAnnotationTool {
48
+ constructor(props = {}) {
49
+ const defaultProps = {
50
+ name: "RectangleRoiOverlay",
51
+ supportedInteractionTypes: ["Mouse", "Touch"],
52
+ configuration: {
53
+ drawHandles: true,
54
+ drawHandlesOnHover: false,
55
+ hideHandlesIfMoving: false,
56
+ renderDashed: false
57
+ // showMinMax: false,
58
+ // showHounsfieldUnits: true,
59
+ },
60
+ svgCursor: rectangleRoiCursor
61
+ };
62
+
63
+ super(props, defaultProps);
64
+
65
+ this.throttledUpdateCachedStats = throttle(this.updateCachedStats, 110);
66
+ }
67
+
68
+ createNewMeasurement(eventData) {
69
+ const goodEventData =
70
+ eventData && eventData.currentPoints && eventData.currentPoints.image;
71
+
72
+ if (!goodEventData) {
73
+ logger.error(
74
+ `required eventData not supplied to tool ${this.name}'s createNewMeasurement`
75
+ );
76
+
77
+ return;
78
+ }
79
+
80
+ return {
81
+ computeMeasurements: this.options.computeMeasurements,
82
+ visible: true,
83
+ active: true,
84
+ color: undefined,
85
+ invalidated: true,
86
+ handles: {
87
+ start: {
88
+ x: eventData.currentPoints.image.x,
89
+ y: eventData.currentPoints.image.y,
90
+ highlight: true,
91
+ active: false
92
+ },
93
+ end: {
94
+ x: eventData.currentPoints.image.x,
95
+ y: eventData.currentPoints.image.y,
96
+ highlight: true,
97
+ active: true
98
+ },
99
+ initialRotation: eventData.viewport.rotation,
100
+ textBox: {
101
+ active: false,
102
+ hasMoved: false,
103
+ movesIndependently: false,
104
+ drawnIndependently: true,
105
+ allowedOutsideImage: true,
106
+ hasBoundingBox: true
107
+ }
108
+ }
109
+ };
110
+ }
111
+
112
+ pointNearTool(element, data, coords, interactionType) {
113
+ const hasStartAndEndHandles =
114
+ data && data.handles && data.handles.start && data.handles.end;
115
+ const validParameters = hasStartAndEndHandles;
116
+
117
+ if (!validParameters) {
118
+ logger.warn(
119
+ `invalid parameters supplied to tool ${this.name}'s pointNearTool`
120
+ );
121
+ }
122
+
123
+ if (!validParameters || data.visible === false) {
124
+ return false;
125
+ }
126
+
127
+ const distance = interactionType === "mouse" ? 15 : 25;
128
+ const startCanvas = external.cornerstone.pixelToCanvas(
129
+ element,
130
+ data.handles.start
131
+ );
132
+ const endCanvas = external.cornerstone.pixelToCanvas(
133
+ element,
134
+ data.handles.end
135
+ );
136
+
137
+ const rect = {
138
+ left: Math.min(startCanvas.x, endCanvas.x),
139
+ top: Math.min(startCanvas.y, endCanvas.y),
140
+ width: Math.abs(startCanvas.x - endCanvas.x),
141
+ height: Math.abs(startCanvas.y - endCanvas.y)
142
+ };
143
+
144
+ const distanceToPoint = external.cornerstoneMath.rect.distanceToPoint(
145
+ rect,
146
+ coords
147
+ );
148
+
149
+ return distanceToPoint < distance;
150
+ }
151
+
152
+ updateCachedStats(image, element, data) {
153
+ if (data.computeMeasurements) {
154
+ const seriesModule =
155
+ external.cornerstone.metaData.get(
156
+ "generalSeriesModule",
157
+ image.imageId
158
+ ) || {};
159
+ const modality = seriesModule.modality;
160
+ const pixelSpacing = getPixelSpacing(image);
161
+
162
+ const stats = _calculateStats(
163
+ image,
164
+ element,
165
+ data.handles,
166
+ modality,
167
+ pixelSpacing
168
+ );
169
+
170
+ data.cachedStats = stats;
171
+ }
172
+
173
+ data.invalidated = false;
174
+ }
175
+
176
+ renderToolData(evt) {
177
+ const toolData = getToolState(evt.currentTarget, this.name);
178
+
179
+ if (!toolData) {
180
+ return;
181
+ }
182
+
183
+ const eventData = evt.detail;
184
+ const { image, element } = eventData;
185
+ const lineWidth = toolStyle.getToolWidth();
186
+ const lineDash = getModule("globalConfiguration").configuration.lineDash;
187
+ const {
188
+ handleRadius,
189
+ drawHandlesOnHover,
190
+ hideHandlesIfMoving,
191
+ renderDashed
192
+ } = this.configuration;
193
+ const context = getNewContext(eventData.canvasContext.canvas);
194
+ const { rowPixelSpacing, colPixelSpacing } = getPixelSpacing(image);
195
+
196
+ // Meta
197
+ const seriesModule =
198
+ external.cornerstone.metaData.get("generalSeriesModule", image.imageId) ||
199
+ {};
200
+
201
+ // Pixel Spacing
202
+ const modality = seriesModule.modality;
203
+ const hasPixelSpacing = rowPixelSpacing && colPixelSpacing;
204
+
205
+ draw(context, context => {
206
+ // If we have tool data for this element - iterate over each set and draw it
207
+ for (let i = 0; i < toolData.data.length; i++) {
208
+ const data = toolData.data[i];
209
+
210
+ if (data.visible === false) {
211
+ continue;
212
+ }
213
+
214
+ // Configure
215
+ const color = toolColors.getColorIfActive(data);
216
+ const handleOptions = {
217
+ color,
218
+ handleRadius,
219
+ drawHandlesIfActive: drawHandlesOnHover,
220
+ hideHandlesIfMoving
221
+ };
222
+
223
+ setShadow(context, this.configuration);
224
+
225
+ const rectOptions = { color };
226
+
227
+ if (renderDashed) {
228
+ rectOptions.lineDash = lineDash;
229
+ }
230
+
231
+ // Draw
232
+ drawRect(
233
+ context,
234
+ element,
235
+ data.handles.start,
236
+ data.handles.end,
237
+ rectOptions,
238
+ "pixel",
239
+ data.handles.initialRotation
240
+ );
241
+
242
+ if (this.configuration.drawHandles) {
243
+ drawHandles(context, eventData, data.handles, handleOptions);
244
+ }
245
+
246
+ if (data.computeMeasurements) {
247
+ // Update textbox stats
248
+ if (data.invalidated === true) {
249
+ if (data.cachedStats) {
250
+ this.throttledUpdateCachedStats(image, element, data);
251
+ } else {
252
+ this.updateCachedStats(image, element, data);
253
+ }
254
+ }
255
+
256
+ // Default to textbox on right side of ROI
257
+ if (!data.handles.textBox.hasMoved) {
258
+ const defaultCoords = getROITextBoxCoords(
259
+ eventData.viewport,
260
+ data.handles
261
+ );
262
+
263
+ Object.assign(data.handles.textBox, defaultCoords);
264
+ }
265
+
266
+ const textBoxAnchorPoints = handles =>
267
+ _findTextBoxAnchorPoints(handles.start, handles.end);
268
+ const textBoxContent = _createTextBoxContent(
269
+ context,
270
+ image.color,
271
+ data.cachedStats,
272
+ modality,
273
+ hasPixelSpacing,
274
+ this.configuration
275
+ );
276
+
277
+ data.unit = _getUnit(
278
+ modality,
279
+ this.configuration.showHounsfieldUnits
280
+ );
281
+
282
+ drawLinkedTextBox(
283
+ context,
284
+ element,
285
+ data.handles.textBox,
286
+ textBoxContent,
287
+ data.handles,
288
+ textBoxAnchorPoints,
289
+ color,
290
+ lineWidth,
291
+ 10,
292
+ true
293
+ );
294
+ }
295
+ }
296
+ });
297
+ }
298
+ }
299
+
300
+ /**
301
+ * TODO: This is the same method (+ GetPixels) for the other ROIs
302
+ * TODO: The pixel filtering is the unique bit
303
+ *
304
+ * @param {*} startHandle
305
+ * @param {*} endHandle
306
+ * @returns {{ left: number, top: number, width: number, height: number}}
307
+ */
308
+ function _getRectangleImageCoordinates(startHandle, endHandle) {
309
+ return {
310
+ left: Math.min(startHandle.x, endHandle.x),
311
+ top: Math.min(startHandle.y, endHandle.y),
312
+ width: Math.abs(startHandle.x - endHandle.x),
313
+ height: Math.abs(startHandle.y - endHandle.y)
314
+ };
315
+ }
316
+
317
+ /**
318
+ *
319
+ *
320
+ * @param {*} image
321
+ * @param {*} element
322
+ * @param {*} handles
323
+ * @param {*} modality
324
+ * @param {*} pixelSpacing
325
+ * @returns {Object} The Stats object
326
+ */
327
+ function _calculateStats(image, element, handles, modality, pixelSpacing) {
328
+ // Retrieve the bounds of the rectangle in image coordinates
329
+ const roiCoordinates = _getRectangleImageCoordinates(
330
+ handles.start,
331
+ handles.end
332
+ );
333
+
334
+ // Retrieve the array of pixels that the rectangle bounds cover
335
+ const pixels = external.cornerstone.getPixels(
336
+ element,
337
+ roiCoordinates.left,
338
+ roiCoordinates.top,
339
+ roiCoordinates.width,
340
+ roiCoordinates.height
341
+ );
342
+
343
+ // Calculate the mean & standard deviation from the pixels and the rectangle details
344
+ const roiMeanStdDev = _calculateRectangleStats(pixels, roiCoordinates);
345
+
346
+ let meanStdDevSUV;
347
+
348
+ if (modality === "PT") {
349
+ meanStdDevSUV = {
350
+ mean: calculateSUV(image, roiMeanStdDev.mean, true) || 0,
351
+ stdDev: calculateSUV(image, roiMeanStdDev.stdDev, true) || 0
352
+ };
353
+ }
354
+
355
+ // Calculate the image area from the rectangle dimensions and pixel spacing
356
+ const area =
357
+ roiCoordinates.width *
358
+ (pixelSpacing.colPixelSpacing || 1) *
359
+ (roiCoordinates.height * (pixelSpacing.rowPixelSpacing || 1));
360
+
361
+ const perimeter =
362
+ roiCoordinates.width * 2 * (pixelSpacing.colPixelSpacing || 1) +
363
+ roiCoordinates.height * 2 * (pixelSpacing.rowPixelSpacing || 1);
364
+
365
+ return {
366
+ area: area || 0,
367
+ perimeter,
368
+ count: roiMeanStdDev.count || 0,
369
+ mean: roiMeanStdDev.mean || 0,
370
+ variance: roiMeanStdDev.variance || 0,
371
+ stdDev: roiMeanStdDev.stdDev || 0,
372
+ min: roiMeanStdDev.min || 0,
373
+ max: roiMeanStdDev.max || 0,
374
+ meanStdDevSUV
375
+ };
376
+ }
377
+
378
+ /**
379
+ *
380
+ *
381
+ * @param {*} sp
382
+ * @param {*} rectangle
383
+ * @returns {{ count, number, mean: number, variance: number, stdDev: number, min: number, max: number }}
384
+ */
385
+ function _calculateRectangleStats(sp, rectangle) {
386
+ let sum = 0;
387
+ let sumSquared = 0;
388
+ let count = 0;
389
+ let index = 0;
390
+ let min = sp ? sp[0] : null;
391
+ let max = sp ? sp[0] : null;
392
+
393
+ for (let y = rectangle.top; y < rectangle.top + rectangle.height; y++) {
394
+ for (let x = rectangle.left; x < rectangle.left + rectangle.width; x++) {
395
+ sum += sp[index];
396
+ sumSquared += sp[index] * sp[index];
397
+ min = Math.min(min, sp[index]);
398
+ max = Math.max(max, sp[index]);
399
+ count++; // TODO: Wouldn't this just be sp.length?
400
+ index++;
401
+ }
402
+ }
403
+
404
+ if (count === 0) {
405
+ return {
406
+ count,
407
+ mean: 0.0,
408
+ variance: 0.0,
409
+ stdDev: 0.0,
410
+ min: 0.0,
411
+ max: 0.0
412
+ };
413
+ }
414
+
415
+ const mean = sum / count;
416
+ const variance = sumSquared / count - mean * mean;
417
+
418
+ return {
419
+ count,
420
+ mean,
421
+ variance,
422
+ stdDev: Math.sqrt(variance),
423
+ min,
424
+ max
425
+ };
426
+ }
427
+
428
+ /**
429
+ *
430
+ *
431
+ * @param {*} startHandle
432
+ * @param {*} endHandle
433
+ * @returns {Array.<{x: number, y: number}>}
434
+ */
435
+ function _findTextBoxAnchorPoints(startHandle, endHandle) {
436
+ const { left, top, width, height } = _getRectangleImageCoordinates(
437
+ startHandle,
438
+ endHandle
439
+ );
440
+
441
+ return [
442
+ {
443
+ // Top middle point of rectangle
444
+ x: left + width / 2,
445
+ y: top
446
+ },
447
+ {
448
+ // Left middle point of rectangle
449
+ x: left,
450
+ y: top + height / 2
451
+ },
452
+ {
453
+ // Bottom middle point of rectangle
454
+ x: left + width / 2,
455
+ y: top + height
456
+ },
457
+ {
458
+ // Right middle point of rectangle
459
+ x: left + width,
460
+ y: top + height / 2
461
+ }
462
+ ];
463
+ }
464
+
465
+ /**
466
+ *
467
+ *
468
+ * @param {*} area
469
+ * @param {*} hasPixelSpacing
470
+ * @returns {string} The formatted label for showing area
471
+ */
472
+ function _formatArea(area, hasPixelSpacing) {
473
+ // This uses Char code 178 for a superscript 2
474
+ const suffix = hasPixelSpacing
475
+ ? ` mm${String.fromCharCode(178)}`
476
+ : ` px${String.fromCharCode(178)}`;
477
+
478
+ return `Area: ${numbersWithCommas(area.toFixed(2))}${suffix}`;
479
+ }
480
+
481
+ function _getUnit(modality, showHounsfieldUnits) {
482
+ return modality === "CT" && showHounsfieldUnits !== false ? "HU" : "";
483
+ }
484
+
485
+ /**
486
+ * TODO: This is identical to EllipticalROI's same fn
487
+ * TODO: We may want to make this a utility for ROIs with these values?
488
+ *
489
+ * @param {*} context
490
+ * @param {*} isColorImage
491
+ * @param {*} { area, mean, stdDev, min, max, meanStdDevSUV }
492
+ * @param {*} modality
493
+ * @param {*} hasPixelSpacing
494
+ * @param {*} [options={}]
495
+ * @returns {string[]}
496
+ */
497
+ function _createTextBoxContent(
498
+ context,
499
+ isColorImage,
500
+ { area = 0, mean = 0, stdDev = 0, min = 0, max = 0, meanStdDevSUV = 0 } = {},
501
+ modality,
502
+ hasPixelSpacing,
503
+ options = {}
504
+ ) {
505
+ const showMinMax = options.showMinMax || false;
506
+ const textLines = [];
507
+
508
+ const otherLines = [];
509
+
510
+ if (!isColorImage) {
511
+ const hasStandardUptakeValues = meanStdDevSUV && meanStdDevSUV.mean !== 0;
512
+ const unit = _getUnit(modality, options.showHounsfieldUnits);
513
+
514
+ let meanString = `Mean: ${numbersWithCommas(mean.toFixed(2))} ${unit}`;
515
+ const stdDevString = `Std Dev: ${numbersWithCommas(
516
+ stdDev.toFixed(2)
517
+ )} ${unit}`;
518
+
519
+ // If this image has SUV values to display, concatenate them to the text line
520
+ if (hasStandardUptakeValues) {
521
+ const SUVtext = " SUV: ";
522
+
523
+ const meanSuvString = `${SUVtext}${numbersWithCommas(
524
+ meanStdDevSUV.mean.toFixed(2)
525
+ )}`;
526
+ const stdDevSuvString = `${SUVtext}${numbersWithCommas(
527
+ meanStdDevSUV.stdDev.toFixed(2)
528
+ )}`;
529
+
530
+ const targetStringLength = Math.floor(
531
+ context.measureText(`${stdDevString} `).width
532
+ );
533
+
534
+ while (context.measureText(meanString).width < targetStringLength) {
535
+ meanString += " ";
536
+ }
537
+
538
+ otherLines.push(`${meanString}${meanSuvString}`);
539
+ otherLines.push(`${stdDevString} ${stdDevSuvString}`);
540
+ } else {
541
+ otherLines.push(`${meanString}`);
542
+ otherLines.push(`${stdDevString}`);
543
+ }
544
+
545
+ if (showMinMax) {
546
+ let minString = `Min: ${min} ${unit}`;
547
+ const maxString = `Max: ${max} ${unit}`;
548
+ const targetStringLength = hasStandardUptakeValues
549
+ ? Math.floor(context.measureText(`${stdDevString} `).width)
550
+ : Math.floor(context.measureText(`${meanString} `).width);
551
+
552
+ while (context.measureText(minString).width < targetStringLength) {
553
+ minString += " ";
554
+ }
555
+
556
+ otherLines.push(`${minString}${maxString}`);
557
+ }
558
+ }
559
+
560
+ textLines.push(_formatArea(area, hasPixelSpacing));
561
+ otherLines.forEach(x => textLines.push(x));
562
+
563
+ return textLines;
564
+ }
@@ -4,21 +4,15 @@
4
4
  * @ronzim
5
5
  */
6
6
 
7
- // import getElement from "./getElement";
8
- // import { getToolState } from "../../../stateManagement/toolState.js";
9
- // import state from "./state";
10
- // import getSegmentsOnPixelData from "./getSegmentsOnPixeldata";
11
- // import { triggerLabelmapModifiedEvent } from "../../../util/segmentation";
12
- // import ARRAY_TYPES from "./arrayTypes";
13
- // import { getModule } from "../../index.js";
14
-
15
7
  const ARRAY_TYPES = {
16
8
  UINT_16_ARRAY: 0,
17
9
  FLOAT_32_ARRAY: 1
18
10
  };
19
11
  const { UINT_16_ARRAY, FLOAT_32_ARRAY } = ARRAY_TYPES;
20
12
 
21
- import cornerstoneTools from "cornerstone-tools/dist/cornerstoneTools.js";
13
+ import cornerstoneTools from "cornerstone-tools";
14
+ import type { TypedArray } from "../../types";
15
+ import { EnabledElement } from "cornerstone-core";
22
16
  const { triggerLabelmapModifiedEvent } = cornerstoneTools.importInternal(
23
17
  "util/segmentationUtils"
24
18
  );
@@ -33,12 +27,12 @@ const state = getModule("segmentation").state;
33
27
  */
34
28
 
35
29
  // from getSegmentsOnPixelData.js
36
- function getSegmentsOnPixelData(pixelData) {
30
+ function getSegmentsOnPixelData(pixelData: TypedArray) {
37
31
  return [...new Set(pixelData)];
38
32
  }
39
33
 
40
34
  // from getElement.js
41
- function getElement(elementOrEnabledElementUID) {
35
+ function getElement(elementOrEnabledElementUID: EnabledElement | string) {
42
36
  if (elementOrEnabledElementUID instanceof HTMLElement) {
43
37
  return elementOrEnabledElementUID;
44
38
  }
@@ -61,11 +55,11 @@ function getElement(elementOrEnabledElementUID) {
61
55
  * @returns {null}
62
56
  */
63
57
  async function setLabelmap3DForElement(
64
- elementOrEnabledElementUID,
65
- buffer,
66
- labelmapIndex,
67
- metadata = [],
68
- segmentsOnLabelmapArray,
58
+ elementOrEnabledElementUID: EnabledElement | string,
59
+ buffer: ArrayBuffer,
60
+ labelmapIndex: number,
61
+ metadata: Object[] = [],
62
+ segmentsOnLabelmapArray: number[][],
69
63
  colorLUTIndex = 0
70
64
  ) {
71
65
  const element = getElement(elementOrEnabledElementUID);
@@ -110,13 +104,13 @@ async function setLabelmap3DForElement(
110
104
  * @returns {null}
111
105
  */
112
106
  function setLabelmap3DByFirstImageId(
113
- firstImageId,
114
- buffer,
115
- labelmapIndex,
116
- metadata = [],
117
- numberOfFrames,
118
- segmentsOnLabelmapArray,
119
- colorLUTIndex = 0
107
+ firstImageId: string,
108
+ buffer: ArrayBuffer,
109
+ labelmapIndex: number,
110
+ metadata: Object[] = [],
111
+ numberOfFrames: number,
112
+ segmentsOnLabelmapArray: number[][],
113
+ colorLUTIndex: number = 0
120
114
  ) {
121
115
  const { configuration } = getModule("segmentation");
122
116
 
@@ -148,8 +142,8 @@ function setLabelmap3DByFirstImageId(
148
142
  /* non-blocking implementation by @ronzim */
149
143
 
150
144
  return new Promise(resolve => {
151
- function setSingleSlice(i, numberOfFrames) {
152
- var pixelData = void 0;
145
+ function setSingleSlice(i: number, numberOfFrames: number) {
146
+ var pixelData: TypedArray | undefined = void 0;
153
147
 
154
148
  switch (configuration.arrayType) {
155
149
  case UINT_16_ARRAY: