copper3d 3.0.1 → 3.0.2

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 (98) hide show
  1. package/README.md +195 -28
  2. package/dist/Utils/segmentation/CommToolsData.d.ts +24 -9
  3. package/dist/Utils/segmentation/CommToolsData.js +65 -139
  4. package/dist/Utils/segmentation/CommToolsData.js.map +1 -1
  5. package/dist/Utils/segmentation/DragOperator.d.ts +10 -2
  6. package/dist/Utils/segmentation/DragOperator.js +14 -4
  7. package/dist/Utils/segmentation/DragOperator.js.map +1 -1
  8. package/dist/Utils/segmentation/DrawToolCore.d.ts +23 -16
  9. package/dist/Utils/segmentation/DrawToolCore.js +218 -401
  10. package/dist/Utils/segmentation/DrawToolCore.js.map +1 -1
  11. package/dist/Utils/segmentation/NrrdTools.d.ts +152 -10
  12. package/dist/Utils/segmentation/NrrdTools.js +599 -202
  13. package/dist/Utils/segmentation/NrrdTools.js.map +1 -1
  14. package/dist/Utils/segmentation/core/MaskVolume.d.ts +1 -1
  15. package/dist/Utils/segmentation/core/MaskVolume.js +24 -3
  16. package/dist/Utils/segmentation/core/MaskVolume.js.map +1 -1
  17. package/dist/Utils/segmentation/core/UndoManager.d.ts +1 -1
  18. package/dist/Utils/segmentation/core/UndoManager.js +1 -1
  19. package/dist/Utils/segmentation/core/index.d.ts +0 -2
  20. package/dist/Utils/segmentation/core/index.js +0 -1
  21. package/dist/Utils/segmentation/core/index.js.map +1 -1
  22. package/dist/Utils/segmentation/core/types.js +24 -24
  23. package/dist/Utils/segmentation/core/types.js.map +1 -1
  24. package/dist/Utils/segmentation/coreTools/GuiState.d.ts +22 -0
  25. package/dist/Utils/segmentation/coreTools/GuiState.js +48 -0
  26. package/dist/Utils/segmentation/coreTools/GuiState.js.map +1 -0
  27. package/dist/Utils/segmentation/coreTools/NrrdState.d.ts +25 -0
  28. package/dist/Utils/segmentation/coreTools/NrrdState.js +85 -0
  29. package/dist/Utils/segmentation/coreTools/NrrdState.js.map +1 -0
  30. package/dist/Utils/segmentation/coreTools/coreType.d.ts +88 -62
  31. package/dist/Utils/segmentation/coreTools/coreType.js.map +1 -1
  32. package/dist/Utils/segmentation/coreTools/divControlTools.js +1 -1
  33. package/dist/Utils/segmentation/coreTools/divControlTools.js.map +1 -1
  34. package/dist/Utils/segmentation/coreTools/gui.d.ts +12 -12
  35. package/dist/Utils/segmentation/coreTools/gui.js +81 -107
  36. package/dist/Utils/segmentation/coreTools/gui.js.map +1 -1
  37. package/dist/Utils/segmentation/eventRouter/EventRouter.d.ts +2 -1
  38. package/dist/Utils/segmentation/eventRouter/EventRouter.js +15 -10
  39. package/dist/Utils/segmentation/eventRouter/EventRouter.js.map +1 -1
  40. package/dist/Utils/segmentation/eventRouter/types.d.ts +3 -3
  41. package/dist/Utils/segmentation/tools/BaseTool.d.ts +8 -5
  42. package/dist/Utils/segmentation/tools/BaseTool.js +1 -2
  43. package/dist/Utils/segmentation/tools/BaseTool.js.map +1 -1
  44. package/dist/Utils/segmentation/tools/CrosshairTool.js +25 -25
  45. package/dist/Utils/segmentation/tools/CrosshairTool.js.map +1 -1
  46. package/dist/Utils/segmentation/tools/DragSliceTool.d.ts +2 -0
  47. package/dist/Utils/segmentation/tools/DragSliceTool.js +63 -53
  48. package/dist/Utils/segmentation/tools/DragSliceTool.js.map +1 -1
  49. package/dist/Utils/segmentation/tools/DrawingTool.d.ts +93 -0
  50. package/dist/Utils/segmentation/tools/DrawingTool.js +222 -0
  51. package/dist/Utils/segmentation/tools/DrawingTool.js.map +1 -0
  52. package/dist/Utils/segmentation/tools/EraserTool.js +8 -8
  53. package/dist/Utils/segmentation/tools/EraserTool.js.map +1 -1
  54. package/dist/Utils/segmentation/tools/ImageStoreHelper.d.ts +11 -28
  55. package/dist/Utils/segmentation/tools/ImageStoreHelper.js +39 -82
  56. package/dist/Utils/segmentation/tools/ImageStoreHelper.js.map +1 -1
  57. package/dist/Utils/segmentation/tools/PanTool.d.ts +53 -0
  58. package/dist/Utils/segmentation/tools/PanTool.js +90 -0
  59. package/dist/Utils/segmentation/tools/PanTool.js.map +1 -0
  60. package/dist/Utils/segmentation/tools/SphereTool.d.ts +208 -1
  61. package/dist/Utils/segmentation/tools/SphereTool.js +456 -45
  62. package/dist/Utils/segmentation/tools/SphereTool.js.map +1 -1
  63. package/dist/Utils/segmentation/tools/ZoomTool.js +3 -3
  64. package/dist/Utils/segmentation/tools/ZoomTool.js.map +1 -1
  65. package/dist/Utils/segmentation/tools/index.d.ts +6 -2
  66. package/dist/Utils/segmentation/tools/index.js +4 -1
  67. package/dist/Utils/segmentation/tools/index.js.map +1 -1
  68. package/dist/bundle.esm.js +2452 -1492
  69. package/dist/bundle.umd.js +2452 -1492
  70. package/dist/index.d.ts +6 -3
  71. package/dist/index.js +1 -1
  72. package/dist/index.js.map +1 -1
  73. package/dist/types/Utils/segmentation/CommToolsData.d.ts +24 -9
  74. package/dist/types/Utils/segmentation/DragOperator.d.ts +10 -2
  75. package/dist/types/Utils/segmentation/DrawToolCore.d.ts +23 -16
  76. package/dist/types/Utils/segmentation/NrrdTools.d.ts +152 -10
  77. package/dist/types/Utils/segmentation/core/MaskVolume.d.ts +1 -1
  78. package/dist/types/Utils/segmentation/core/UndoManager.d.ts +1 -1
  79. package/dist/types/Utils/segmentation/core/index.d.ts +0 -2
  80. package/dist/types/Utils/segmentation/coreTools/GuiState.d.ts +22 -0
  81. package/dist/types/Utils/segmentation/coreTools/NrrdState.d.ts +25 -0
  82. package/dist/types/Utils/segmentation/coreTools/coreType.d.ts +88 -62
  83. package/dist/types/Utils/segmentation/coreTools/gui.d.ts +12 -12
  84. package/dist/types/Utils/segmentation/eventRouter/EventRouter.d.ts +2 -1
  85. package/dist/types/Utils/segmentation/eventRouter/types.d.ts +3 -3
  86. package/dist/types/Utils/segmentation/tools/BaseTool.d.ts +8 -5
  87. package/dist/types/Utils/segmentation/tools/DragSliceTool.d.ts +2 -0
  88. package/dist/types/Utils/segmentation/tools/DrawingTool.d.ts +93 -0
  89. package/dist/types/Utils/segmentation/tools/ImageStoreHelper.d.ts +11 -28
  90. package/dist/types/Utils/segmentation/tools/PanTool.d.ts +53 -0
  91. package/dist/types/Utils/segmentation/tools/SphereTool.d.ts +208 -1
  92. package/dist/types/Utils/segmentation/tools/index.d.ts +6 -2
  93. package/dist/types/index.d.ts +6 -3
  94. package/package.json +1 -1
  95. package/dist/Utils/segmentation/core/MigrationUtils.d.ts +0 -97
  96. package/dist/Utils/segmentation/core/MigrationUtils.js +0 -163
  97. package/dist/Utils/segmentation/core/MigrationUtils.js.map +0 -1
  98. package/dist/types/Utils/segmentation/core/MigrationUtils.d.ts +0 -97
package/README.md CHANGED
@@ -128,7 +128,7 @@ const container = document.getElementById('viewer') as HTMLDivElement;
128
128
  const nrrdTools = new Copper.NrrdTools(container);
129
129
 
130
130
  // 2. After NRRD images are loaded via Copper scene:
131
- nrrdTools.clear();
131
+ nrrdTools.reset();
132
132
  nrrdTools.setAllSlices(allSlices); // allSlices from Copper scene loader
133
133
 
134
134
  // 3. Hook drawing callbacks
@@ -211,7 +211,7 @@ Must be called **after** Copper has loaded and decoded the NRRD files.
211
211
 
212
212
  ```typescript
213
213
  // Reset state from previous case
214
- nrrdTools.clear();
214
+ nrrdTools.reset();
215
215
 
216
216
  // allSlices is the array of decoded NRRD slice objects returned by Copper's loader
217
217
  nrrdTools.setAllSlices(allSlices);
@@ -336,12 +336,29 @@ nrrdTools.draw({
336
336
  notifyBackendLayerCleared(layerId);
337
337
  },
338
338
 
339
- // Called when the 3D sphere annotation tool places a sphere
339
+ // Called when the 3D sphere annotation tool places a sphere (sphere mode)
340
+ //
341
+ // sphereOrigin: [mouseX, mouseY, sliceIndex] — center on z-axis view
342
+ // sphereRadius: radius in pixels (1-50)
343
+ //
344
+ // Note: Sphere data does NOT write to layer MaskVolume.
345
+ // It is rendered as a visual overlay via the dedicated sphereMaskVolume.
340
346
  getSphereData: (sphereOrigin: number[], sphereRadius: number) => {
341
347
  console.log('Sphere placed at', sphereOrigin, 'radius', sphereRadius);
348
+ sendSphereToBackend({ sphereOrigin, sphereRadius });
342
349
  },
343
350
 
344
- // Called when the calculate-sphere-positions tool fires
351
+ // Called when the calculator sphere positions are updated (calculator mode)
352
+ //
353
+ // Each sphere type maps to a specific channel on layer1:
354
+ // tumour → channel 1
355
+ // ribcage → channel 3
356
+ // skin → channel 4
357
+ // nipple → channel 2
358
+ //
359
+ // Origins are ICommXYZ: { x: [mx, my, slice], y: [...], z: [...] }
360
+ // representing sphere center coordinates on all 3 axis views.
361
+ // null if that sphere type has not been placed yet.
345
362
  getCalculateSpherePositionsData: (
346
363
  tumourOrigin, skinOrigin, ribOrigin, nippleOrigin, axis
347
364
  ) => {
@@ -350,7 +367,116 @@ nrrdTools.draw({
350
367
  });
351
368
  ```
352
369
 
353
- #### 5.3 `enableContrastDragEvents()`Windowing
370
+ #### 5.3 SphereTool3D Sphere Placement & Distance Calculator
371
+
372
+ The SphereTool provides unified sphere placement with 4 sphere types controlled by `gui_states.mode.activeSphereType`. The active type determines which origin and color are used. The old separate "Calculator" mode has been merged into SphereTool.
373
+
374
+ ##### Sphere Types & Channel Mapping
375
+
376
+ Each sphere type maps to a specific channel on layer1. Switch between types using `gui_states.mode.activeSphereType`:
377
+
378
+ | Sphere Type | Channel | Default Color | `activeSphereType` value |
379
+ |-------------|---------|---------------|---------------------|
380
+ | tumour | 1 | `#10b981` (Emerald) | `"tumour"` (default) |
381
+ | nipple | 2 | `#f43f5e` (Rose) | `"nipple"` |
382
+ | ribcage | 3 | `#3b82f6` (Blue) | `"ribcage"` |
383
+ | skin | 4 | `#fbbf24` (Amber) | `"skin"` |
384
+
385
+ These mappings are exported as `SPHERE_CHANNEL_MAP` and `SPHERE_LABELS` from `tools/SphereTool.ts`. (`SPHERE_COLORS` was removed — colors are now derived dynamically from each volume's `colorMap`.)
386
+
387
+ ##### Switching Sphere Type
388
+
389
+ Use the public API — do NOT mutate `gui_states.mode.activeSphereType` directly, as `setActiveSphereType()` also updates brush/fill color as a side-effect:
390
+
391
+ ```typescript
392
+ // Set active sphere type (also updates fillColor / brushColor)
393
+ nrrdTools.setActiveSphereType('nipple'); // channel 2, Rose #f43f5e
394
+ nrrdTools.setActiveSphereType('tumour'); // channel 1, Emerald #10b981
395
+ nrrdTools.setActiveSphereType('skin'); // channel 4, Amber #fbbf24
396
+ nrrdTools.setActiveSphereType('ribcage'); // channel 3, Blue #3b82f6
397
+
398
+ // Read current type
399
+ const type = nrrdTools.getActiveSphereType();
400
+ // → 'tumour' | 'skin' | 'nipple' | 'ribcage'
401
+ ```
402
+
403
+ ##### Interaction Flow
404
+
405
+ ```
406
+ Sphere mode activated (gui_states.mode.sphere = true, keyboard shortcut: 'q'):
407
+ ├─ Shift key DISABLED (no draw mode)
408
+ ├─ Crosshair toggle allowed (S key)
409
+
410
+ ├─ Left-click DOWN → record origin for current activeSphereType type,
411
+ │ show preview, bind sphere wheel
412
+ ├─ Scroll wheel (while holding) → adjust radius [1, 50]
413
+ └─ Left-click UP → write all placed spheres to volume,
414
+ fire getSphere + getCalculateSpherePositions callbacks,
415
+ restore zoom/slice wheel
416
+ ```
417
+
418
+ ##### SphereMaskVolume
419
+
420
+ Sphere 3D data is stored in a dedicated `MaskVolume` (`nrrd_states.sphereMaskVolume`), separate from the layer draw mask volumes. This prevents sphere overlay data from polluting layer1's annotations.
421
+
422
+ - **Created** in `setAllSlices()` (same dimensions as CT volume)
423
+ - **Cleared** in `reset()` (when switching cases)
424
+
425
+ > **Note**: Currently sphere data does NOT write to layer1's MaskVolume. The channel mapping and `sphereMaskVolume` are reserved for future integration.
426
+
427
+ ##### Scenario: Sphere mode with AI backend (distance calculation)
428
+
429
+ ```typescript
430
+ nrrdTools.draw({
431
+ // Called on every sphere placement — receives all 4 sphere origins
432
+ getCalculateSpherePositionsData: (tumour, skin, rib, nipple, axis) => {
433
+ // Each origin is { x: [mx, my, slice], y: [...], z: [...] } or null
434
+ if (tumour && skin && rib && nipple) {
435
+ aiBackend.runSegmentation({ tumour, skin, rib, nipple, axis });
436
+ }
437
+ },
438
+ // Also called — receives the current sphere's origin and radius
439
+ getSphereData: (origin, radius) => {
440
+ console.log('Sphere placed at', origin, 'radius', radius);
441
+ },
442
+ });
443
+ ```
444
+
445
+ ##### Programmatic Sphere Placement (Backend → Frontend)
446
+
447
+ When the backend returns sphere coordinates (e.g., from AI detection), use `setCalculateDistanceSphere()` to place them without user interaction. This method replicates the full mouse-down → mouse-up flow internally:
448
+
449
+ ```typescript
450
+ // Backend returns sphere data for a case
451
+ interface BackendSphereData {
452
+ type: 'tumour' | 'skin' | 'nipple' | 'ribcage';
453
+ x: number; // X in unscaled image space
454
+ y: number; // Y in unscaled image space
455
+ sliceIndex: number; // Target slice index
456
+ }
457
+
458
+ // Place each sphere programmatically
459
+ function applySphereFromBackend(nrrdTools: Copper.NrrdTools, spheres: BackendSphereData[]) {
460
+ for (const s of spheres) {
461
+ nrrdTools.setCalculateDistanceSphere(s.x, s.y, s.sliceIndex, s.type);
462
+ }
463
+ }
464
+
465
+ // Example: place a tumour sphere at (120, 95) on slice 42
466
+ nrrdTools.setCalculateDistanceSphere(120, 95, 42, 'tumour');
467
+ ```
468
+
469
+ Internally, `setCalculateDistanceSphere` performs:
470
+ 1. Sets `sphereRadius = 5` and navigates to the target slice
471
+ 2. Records `sphereOrigin` on all 3 axes (via `crosshairTool.setUpSphereOrigins`)
472
+ 3. Deep-copies the origin into the type-specific field (e.g., `tumourSphereOrigin`)
473
+ 4. Draws the sphere preview on canvas (`drawCalculatorSphere`)
474
+ 5. Writes all placed spheres to `sphereMaskVolume` (`writeAllCalculatorSpheresToVolume`)
475
+ 6. Re-renders the sphere overlay (`refreshSphereCanvas`)
476
+
477
+ > **Note**: Coordinates (`x`, `y`) are in **unscaled** image space. The method automatically applies `sizeFactor` scaling internally.
478
+
479
+ #### 5.4 `enableContrastDragEvents()` — Windowing
354
480
 
355
481
  Enable Ctrl+drag to adjust window/level (brightness/contrast):
356
482
 
@@ -466,14 +592,14 @@ Each layer has its own independent color map. Changing channel 3's color in `lay
466
592
 
467
593
  | Channel | Color | Hex |
468
594
  |---------|-------|-----|
469
- | 1 | Green (Tumour) | `#00ff00` |
470
- | 2 | Red (Edema) | `#ff0000` |
471
- | 3 | Blue (Necrosis) | `#0000ff` |
472
- | 4 | Yellow (Enhancement) | `#ffff00` |
473
- | 5 | Magenta (Vessel) | `#ff00ff` |
474
- | 6 | Cyan (Additional) | `#00ffff` |
475
- | 7 | Orange (Auxiliary) | `#ff8000` |
476
- | 8 | Purple (Extended) | `#8000ff` |
595
+ | 1 | Emerald (Tumour) | `#10b981` |
596
+ | 2 | Rose (Edema) | `#f43f5e` |
597
+ | 3 | Blue (Necrosis) | `#3b82f6` |
598
+ | 4 | Amber (Enhancement) | `#fbbf24` |
599
+ | 5 | Fuchsia (Vessel) | `#d946ef` |
600
+ | 6 | Cyan (Additional) | `#06b6d4` |
601
+ | 7 | Orange (Auxiliary) | `#f97316` |
602
+ | 8 | Violet (Extended) | `#8b5cf6` |
477
603
 
478
604
  #### 7.1 Set a single channel color
479
605
 
@@ -606,6 +732,7 @@ window.addEventListener('keydown', (e) => {
606
732
  | Redo | `y` |
607
733
  | Contrast adjust | `Ctrl` / `Meta` (hold) |
608
734
  | Crosshair | `s` |
735
+ | Sphere mode | `q` |
609
736
  | Mouse wheel | Zoom |
610
737
 
611
738
  #### Reading current settings
@@ -691,7 +818,7 @@ const maxSlices = nrrdTools.getMaxSliceNum();
691
818
  // → [512, 512, 256] (one per axis)
692
819
 
693
820
  // Current viewing state
694
- const { currentIndex, contrastIndex } = nrrdTools.getCurrentSlicesNumAndContrastNum();
821
+ const { currentSliceIndex, contrastIndex } = nrrdTools.getCurrentSlicesNumAndContrastNum();
695
822
  ```
696
823
 
697
824
  #### Accessing internal canvases
@@ -700,13 +827,13 @@ const { currentIndex, contrastIndex } = nrrdTools.getCurrentSlicesNumAndContrast
700
827
  // The topmost interactive canvas (mouse/pen events target here)
701
828
  const drawingCanvas = nrrdTools.getDrawingCanvas();
702
829
 
703
- // The container element passed to the constructor
830
+ // The inner main-area container div (dynamically created by NrrdTools, NOT the original container passed to constructor)
704
831
  const container = nrrdTools.getContainer();
705
832
 
706
- // Raw NrrdStates (all internal state fields)
833
+ // Raw NrrdState (all internal state fields, grouped by semantic sub-objects)
707
834
  const states = nrrdTools.getNrrdToolsSettings();
708
- console.log(states.layers); // ["layer1", "layer2", ...]
709
- console.log(states.dimensions); // [512, 512, 256]
835
+ console.log(states.image.layers); // ["layer1", "layer2", ...]
836
+ console.log(states.image.dimensions); // [512, 512, 256]
710
837
  ```
711
838
 
712
839
  #### Accessing full mask data
@@ -737,7 +864,7 @@ const channelVis = nrrdTools.getChannelVisibility();
737
864
  const hasTumour = nrrdTools.hasLayerData('layer1');
738
865
 
739
866
  // Get current channel color as hex
740
- const hex = nrrdTools.getChannelHexColor('layer1', 1); // → "#00ff00"
867
+ const hex = nrrdTools.getChannelHexColor('layer1', 1); // → "#10b981"
741
868
 
742
869
  // Keyboard settings
743
870
  const keys = nrrdTools.getKeyboardSettings();
@@ -765,7 +892,7 @@ async function initAnnotationTool(container: HTMLDivElement, allSlices: any[]) {
765
892
  });
766
893
 
767
894
  // Load image volume
768
- nrrdTools.clear();
895
+ nrrdTools.reset();
769
896
  nrrdTools.setAllSlices(allSlices);
770
897
 
771
898
  // Register callbacks
@@ -820,7 +947,7 @@ async function loadAndColorCase(nrrdTools: Copper.NrrdTools, caseId: string) {
820
947
  ```typescript
821
948
  async function switchCase(nrrdTools: Copper.NrrdTools, newCaseData: ICaseData) {
822
949
  // Reset annotation volumes
823
- nrrdTools.clear();
950
+ nrrdTools.reset();
824
951
 
825
952
  // Load new image slices (from Copper's scene loader result)
826
953
  nrrdTools.setAllSlices(newCaseData.slices);
@@ -927,12 +1054,32 @@ function buildColorLegend(nrrdTools: Copper.NrrdTools, layerId: string) {
927
1054
  }
928
1055
 
929
1056
  // → [
930
- // { channel: 1, cssColor: 'rgba(0,255,0,1.00)', hexColor: '#00ff00', rgba: { r:0, g:255, b:0, a:255 } },
931
- // { channel: 2, cssColor: 'rgba(255,0,0,1.00)', hexColor: '#ff0000', ... },
1057
+ // { channel: 1, cssColor: 'rgba(16,185,129,1.00)', hexColor: '#10b981', rgba: { r:16, g:185, b:129, a:255 } },
1058
+ // { channel: 2, cssColor: 'rgba(244,63,94,1.00)', hexColor: '#f43f5e', rgba: { r:244, g:63, b:94, a:255 } },
932
1059
  // ...
933
1060
  // ]
934
1061
  ```
935
1062
 
1063
+ #### Scenario H: Clearing annotations
1064
+
1065
+ There are different levels of clearing data depending on the use case:
1066
+
1067
+ ```typescript
1068
+ // 1. Clear ALL data across ALL layers comprehensively (typically used when switching cases)
1069
+ // This clears all volumes, undo histories, UI canvases, index parameters, and sphere data globally.
1070
+ nrrdTools.reset();
1071
+
1072
+ // 2. Clear all annotations on the currently active layer across its entire 3D volume
1073
+ // This clears the active layer's MaskVolume, clears its undo/redo history, and re-renders the canvas.
1074
+ // It also triggers the `onClearLayerVolume` callback so you can notify the backend.
1075
+ nrrdTools.clearActiveLayer();
1076
+
1077
+ // 3. Clear the mask ONLY on the currently viewed 2D slice for the active layer
1078
+ // This removes annotations specifically on the current slice index and orientation.
1079
+ // It records an undo operation to allow rollback.
1080
+ nrrdTools.clearActiveSlice();
1081
+ ```
1082
+
936
1083
  ---
937
1084
 
938
1085
  ### 13. Vue 3 Integration Pattern
@@ -956,7 +1103,7 @@ onMounted(() => {
956
1103
 
957
1104
  // After all NRRD files are loaded by the Copper scene:
958
1105
  function onAllImagesLoaded(allSlices: any[]) {
959
- nrrdTools!.clear();
1106
+ nrrdTools!.reset();
960
1107
  nrrdTools!.setAllSlices(allSlices);
961
1108
 
962
1109
  nrrdTools!.drag({ getSliceNum: (idx) => emit('sliceChanged', idx) });
@@ -1066,8 +1213,9 @@ interface IKeyBoardSettings {
1066
1213
  draw: string;
1067
1214
  undo: string;
1068
1215
  redo: string;
1069
- contrast: string | string[];
1216
+ contrast: string[]; // always an array, e.g. ["Control", "Meta"]
1070
1217
  crosshair: string;
1218
+ sphere: string;
1071
1219
  mouseWheel: 'Scroll:Zoom' | 'Scroll:Slice';
1072
1220
  }
1073
1221
 
@@ -1099,7 +1247,9 @@ type ChannelValue = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
1099
1247
  | | `enableContrastDragEvents(cb)` | Enable Ctrl+drag windowing |
1100
1248
  | | `setDisplaySliceIndexPanel(el)` | Show slice index in a panel |
1101
1249
  | | `setBaseDrawDisplayCanvasesSize(n)` | Set canvas resolution multiplier (1-8) |
1102
- | **Data** | `clear()` | Reset all volumes |
1250
+ | **Data** | `reset()` | Reset all volumes, undo histories, canvases, and sphere data |
1251
+ | | `clearActiveLayer()` | Clear annotations and undo history for the *currently active layer* |
1252
+ | | `clearActiveSlice()` | Clear annotations exclusively on the *currently viewed slice* of the active layer |
1103
1253
  | | `setAllSlices(slices)` | Load NRRD slices, init MaskVolumes |
1104
1254
  | | `setMasksFromNIfTI(map)` | Load saved NIfTI voxel data |
1105
1255
  | **Render** | `start` | Frame callback — pass to render loop |
@@ -1109,6 +1259,8 @@ type ChannelValue = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
1109
1259
  | | `isLayerVisible(id)` | Query layer visibility |
1110
1260
  | | `getLayerVisibility()` | All layer visibility map |
1111
1261
  | | `hasLayerData(id)` | Check if layer has non-zero voxels |
1262
+ | **Sphere** | `setActiveSphereType(type)` | Set active sphere type (`'tumour'`/`'skin'`/`'nipple'`/`'ribcage'`), updates brush color |
1263
+ | | `getActiveSphereType()` | Read current sphere type |
1112
1264
  | **Channel** | `setActiveChannel(ch)` | Switch drawing target channel |
1113
1265
  | | `getActiveChannel()` | Read current channel |
1114
1266
  | | `setChannelVisible(id, ch, bool)` | Toggle channel visibility in a layer |
@@ -1121,6 +1273,22 @@ type ChannelValue = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
1121
1273
  | | `getChannelHexColor(id, ch)` | Read Hex string |
1122
1274
  | | `getChannelCssColor(id, ch)` | Read CSS rgba() string |
1123
1275
  | | `resetChannelColors(id?, ch?)` | Reset to defaults |
1276
+ | **Tool Mode** | `setMode(mode)` | Switch tool mode: `"pencil"` / `"brush"` / `"eraser"` / `"sphere"` / `"calculator"` |
1277
+ | | `getMode()` | Read current tool mode |
1278
+ | | `isCalculatorActive()` | Check if calculator (distance) mode is active |
1279
+ | **Drawing** | `setOpacity(value)` | Set mask overlay opacity [0.1, 1] |
1280
+ | | `getOpacity()` | Read current opacity |
1281
+ | | `setBrushSize(size)` | Set brush/eraser size [5, 50], updates cursor |
1282
+ | | `getBrushSize()` | Read current brush size |
1283
+ | | `setPencilColor(hex)` | Set pencil stroke color (hex string) |
1284
+ | | `getPencilColor()` | Read current pencil color |
1285
+ | **Contrast** | `setWindowHigh(value)` | Set window high (image contrast), call `finishWindowAdjustment()` after drag |
1286
+ | | `setWindowLow(value)` | Set window low (image center) |
1287
+ | | `finishWindowAdjustment()` | Repaint all contrast slices after drag ends |
1288
+ | | `getSliderMeta(key)` | Get slider min/max/step/value for UI config (`"globalAlpha"`, `"brushAndEraserSize"`, etc.) |
1289
+ | **Actions** | `executeAction(action)` | Run named action: `"undo"`, `"redo"`, `"clearActiveSliceMask"`, `"clearActiveLayerMask"`, `"resetZoom"`, `"downloadCurrentMask"` |
1290
+ | **Navigation** | `setSliceOrientation(axis)` | Switch viewing axis `"x"` / `"y"` / `"z"` |
1291
+ | | `setCalculateDistanceSphere(x, y, slice, type)` | Programmatically place a calculator sphere (simulates full click flow: record origin → draw → write to volume) |
1124
1292
  | **History** | `undo()` | Undo last stroke |
1125
1293
  | | `redo()` | Redo last undone stroke |
1126
1294
  | **Keyboard** | `setKeyboardSettings(partial)` | Remap shortcuts |
@@ -1135,11 +1303,10 @@ type ChannelValue = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
1135
1303
  | | `getMaxSliceNum()` | Max slice index per axis |
1136
1304
  | | `getCurrentSlicesNumAndContrastNum()` | Current slice & contrast index |
1137
1305
  | | `getMaskData()` | Raw `IMaskData` object |
1138
- | | `getNrrdToolsSettings()` | Full `INrrdStates` snapshot |
1306
+ | | `getNrrdToolsSettings()` | Full `NrrdState` snapshot (grouped sub-objects: image, view, interaction, sphere, flags) |
1139
1307
  | | `getContainer()` | Host `HTMLElement` |
1140
1308
  | | `getDrawingCanvas()` | Top-layer `HTMLCanvasElement` |
1141
1309
 
1142
- ---
1143
1310
 
1144
1311
  ## Acknowledgements
1145
1312
 
@@ -1,18 +1,22 @@
1
- import { IProtected, IGUIStates, INrrdStates, ICursorPage, IConvertObjType, INewMaskData, IKeyBoardSettings } from "./coreTools/coreType";
1
+ import { IProtected, ICursorPage, IConvertObjType, INewMaskData, IKeyBoardSettings, IAnnotationCallbacks } from "./coreTools/coreType";
2
+ import { NrrdState } from "./coreTools/NrrdState";
3
+ import { GuiState } from "./coreTools/GuiState";
2
4
  import { MaskVolume } from "./core/index";
3
5
  export declare class CommToolsData {
4
6
  baseCanvasesSize: number;
5
7
  private _reusableSliceBuffer;
6
8
  private _reusableBufferWidth;
7
9
  private _reusableBufferHeight;
10
+ /** External annotation callbacks — set via draw() options */
11
+ protected annotationCallbacks: IAnnotationCallbacks;
8
12
  /** Whether the keyboard-config dialog is open (suppresses all shortcuts). */
9
13
  protected _configKeyBoard: boolean;
10
14
  /** Active keyboard shortcut bindings. */
11
15
  protected _keyboardSettings: IKeyBoardSettings;
12
- nrrd_states: INrrdStates;
13
- cursorPage: ICursorPage;
14
- gui_states: IGUIStates;
15
- protectedData: IProtected;
16
+ protected nrrd_states: NrrdState;
17
+ protected cursorPage: ICursorPage;
18
+ protected gui_states: GuiState;
19
+ protected protectedData: IProtected;
16
20
  constructor(container: HTMLElement, mainAreaContainer: HTMLElement, options?: {
17
21
  layers?: string[];
18
22
  });
@@ -56,9 +60,9 @@ export declare class CommToolsData {
56
60
  private generateSystemCanvases;
57
61
  private generateLayerTargets;
58
62
  /**
59
- * Rewrite this {clearPaint} function under DrawToolCore
63
+ * Rewrite this {clearActiveSlice} function under DrawToolCore
60
64
  */
61
- clearPaint(): void;
65
+ clearActiveSlice(): void;
62
66
  /**
63
67
  * Rewrite this {undoLastPainting} function under DrawToolCore
64
68
  */
@@ -68,9 +72,9 @@ export declare class CommToolsData {
68
72
  */
69
73
  redoLastPainting(): void;
70
74
  /**
71
- * Rewrite this {clearStoreImages} function under NrrdTools
75
+ * Rewrite this {clearActiveLayer} function under NrrdTools
72
76
  */
73
- clearStoreImages(): void;
77
+ clearActiveLayer(): void;
74
78
  /**
75
79
  * Rewrite this {resizePaintArea} function under NrrdTools
76
80
  */
@@ -103,6 +107,17 @@ export declare class CommToolsData {
103
107
  * Rewrite this {resetLayerCanvas} function under NrrdTools
104
108
  */
105
109
  resetLayerCanvas(): void;
110
+ /**
111
+ * Enter sphere mode: clear all layer canvases (not MaskVolume),
112
+ * hide all mask data so sphere overlay is the only visible annotation.
113
+ * Rewrite this under NrrdTools.
114
+ */
115
+ enterSphereMode(): void;
116
+ /**
117
+ * Exit sphere mode: clear sphere canvas overlay, reload all layer
118
+ * MaskVolume data back onto canvases. Rewrite this under NrrdTools.
119
+ */
120
+ exitSphereMode(): void;
106
121
  /**
107
122
  * Rewrite this {setSyncsliceNum} function under NrrdTools
108
123
  */