larvitar 2.0.5 → 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 (71) hide show
  1. package/README.md +2 -2
  2. package/dist/larvitar.js +1 -1
  3. package/package.json +6 -2
  4. package/.github/workflows/build-docs.yml +0 -59
  5. package/.github/workflows/codeql-analysis.yml +0 -71
  6. package/.github/workflows/deploy.yml +0 -37
  7. package/.vscode/settings.json +0 -4
  8. package/CODE_OF_CONDUCT.md +0 -76
  9. package/MIGRATION.md +0 -25
  10. package/bundler/webpack.common.js +0 -27
  11. package/bundler/webpack.dev.js +0 -23
  12. package/bundler/webpack.prod.js +0 -19
  13. package/decs.d.ts +0 -12
  14. package/imaging/MetaDataReadable.ts +0 -42
  15. package/imaging/MetaDataTypes.ts +0 -3491
  16. package/imaging/dataDictionary.json +0 -21866
  17. package/imaging/imageAnonymization.ts +0 -135
  18. package/imaging/imageColormaps.ts +0 -217
  19. package/imaging/imageContours.ts +0 -196
  20. package/imaging/imageIo.ts +0 -251
  21. package/imaging/imageLayers.ts +0 -121
  22. package/imaging/imageLoading.ts +0 -299
  23. package/imaging/imageParsing.ts +0 -444
  24. package/imaging/imagePresets.ts +0 -156
  25. package/imaging/imageRendering.ts +0 -1091
  26. package/imaging/imageReslice.ts +0 -87
  27. package/imaging/imageStore.ts +0 -487
  28. package/imaging/imageTags.ts +0 -609
  29. package/imaging/imageTools.js +0 -708
  30. package/imaging/imageUtils.ts +0 -1079
  31. package/imaging/loaders/commonLoader.ts +0 -275
  32. package/imaging/loaders/dicomLoader.ts +0 -66
  33. package/imaging/loaders/fileLoader.ts +0 -71
  34. package/imaging/loaders/multiframeLoader.ts +0 -435
  35. package/imaging/loaders/nrrdLoader.ts +0 -630
  36. package/imaging/loaders/resliceLoader.ts +0 -205
  37. package/imaging/monitors/memory.ts +0 -151
  38. package/imaging/monitors/performance.ts +0 -34
  39. package/imaging/parsers/ecg.ts +0 -54
  40. package/imaging/parsers/nrrd.js +0 -485
  41. package/imaging/tools/README.md +0 -27
  42. package/imaging/tools/custom/4dSliceScrollTool.js +0 -146
  43. package/imaging/tools/custom/BorderMagnifyTool.js +0 -99
  44. package/imaging/tools/custom/contourTool.js +0 -1884
  45. package/imaging/tools/custom/diameterTool.js +0 -141
  46. package/imaging/tools/custom/editMaskTool.js +0 -141
  47. package/imaging/tools/custom/ellipticalRoiOverlayTool.js +0 -534
  48. package/imaging/tools/custom/polygonSegmentationMixin.js +0 -245
  49. package/imaging/tools/custom/polylineScissorsTool.js +0 -59
  50. package/imaging/tools/custom/rectangleRoiOverlayTool.js +0 -564
  51. package/imaging/tools/custom/seedTool.js +0 -342
  52. package/imaging/tools/custom/setLabelMap3D.ts +0 -242
  53. package/imaging/tools/custom/thresholdsBrushTool.js +0 -161
  54. package/imaging/tools/default.ts +0 -594
  55. package/imaging/tools/interaction.ts +0 -266
  56. package/imaging/tools/io.ts +0 -229
  57. package/imaging/tools/main.ts +0 -427
  58. package/imaging/tools/segmentation.ts +0 -532
  59. package/imaging/tools/segmentations.md +0 -38
  60. package/imaging/tools/state.ts +0 -74
  61. package/imaging/tools/strategies/eraseFreehand.js +0 -76
  62. package/imaging/tools/strategies/fillFreehand.js +0 -79
  63. package/imaging/tools/strategies/index.js +0 -2
  64. package/imaging/tools/types.d.ts +0 -243
  65. package/imaging/types.d.ts +0 -200
  66. package/imaging/waveforms/ecg.ts +0 -191
  67. package/index.ts +0 -431
  68. package/jsdoc.json +0 -52
  69. package/rollup.config.js +0 -51
  70. package/template/.gitkeep +0 -0
  71. 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
- }