larvitar 2.0.4 → 2.0.6

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