|
| 1 | +#include <Utils/StudioUtils.h> |
1 | 2 | #include <Visualization/Lightbox.h>
|
2 | 3 | #include <Visualization/StudioSliceInteractorStyle.h>
|
| 4 | +#include <vtkAssemblyPath.h> |
| 5 | +#include <vtkImageActor.h> |
| 6 | +#include <vtkImageMapper3D.h> |
3 | 7 | #include <vtkImageProperty.h>
|
4 | 8 | #include <vtkObjectFactory.h>
|
5 | 9 | #include <vtkRenderer.h>
|
6 | 10 |
|
7 | 11 | namespace shapeworks {
|
8 | 12 |
|
| 13 | +//----------------------------------------------------------------------------- |
9 | 14 | vtkStandardNewMacro(StudioSliceInteractorStyle);
|
10 | 15 |
|
11 | 16 | //-----------------------------------------------------------------------------
|
@@ -44,11 +49,105 @@ void StudioSliceInteractorStyle::OnKeyDown() {
|
44 | 49 |
|
45 | 50 | //-----------------------------------------------------------------------------
|
46 | 51 | void StudioSliceInteractorStyle::WindowLevel() {
|
47 |
| - vtkInteractorStyleImage::WindowLevel(); |
48 |
| - if (CurrentImageProperty) { |
49 |
| - double window = CurrentImageProperty->GetColorWindow(); |
50 |
| - double level = CurrentImageProperty->GetColorLevel(); |
51 |
| - lightbox_->set_shared_window_and_level(window, level); |
| 52 | + if (!CurrentImageProperty) return; |
| 53 | + if (!current_image_slice_) return; |
| 54 | + |
| 55 | + // Extract window width and level from the current image property |
| 56 | + vtkSmartPointer<vtkImageProperty> prop = CurrentImageProperty; |
| 57 | + double windowWidth = prop->GetColorWindow(); |
| 58 | + double windowCenter = prop->GetColorLevel(); |
| 59 | + |
| 60 | + double contrast; |
| 61 | + double brightness; |
| 62 | + |
| 63 | + // get intensity range of the image, using current_image_actor_ which is a vtkImageSlice |
| 64 | + double range[2]; |
| 65 | + vtkImageData* imageData = current_image_slice_->GetMapper()->GetInput(); |
| 66 | + imageData->GetScalarRange(range); |
| 67 | + |
| 68 | + StudioUtils::window_width_level_to_brightness_contrast(windowWidth, windowCenter, range[0], range[1], brightness, contrast); |
| 69 | + |
| 70 | + // Get the interactor |
| 71 | + vtkRenderWindowInteractor* rwi = this->Interactor; |
| 72 | + if (!rwi) return; |
| 73 | + |
| 74 | + // Get the renderer size |
| 75 | + int* rendererSize = this->CurrentRenderer->GetSize(); |
| 76 | + |
| 77 | + // Get the event position |
| 78 | + int eventPos[2]; |
| 79 | + rwi->GetEventPosition(eventPos); |
| 80 | + |
| 81 | + // Get the last event position |
| 82 | + int lastEventPos[2]; |
| 83 | + rwi->GetLastEventPosition(lastEventPos); |
| 84 | + |
| 85 | + // Calculate change in mouse position |
| 86 | + double dx = static_cast<double>(eventPos[0] - lastEventPos[0]) / static_cast<double>(rendererSize[0]) * 100.0; |
| 87 | + double dy = static_cast<double>(eventPos[1] - lastEventPos[1]) / static_cast<double>(rendererSize[1]) * 100.0; |
| 88 | + |
| 89 | + // Adjust brightness and contrast based on mouse movement |
| 90 | + brightness += dx; |
| 91 | + contrast += dy; |
| 92 | + |
| 93 | + // Ensure brightness and contrast stay within valid range |
| 94 | + brightness = std::max<double>(3, std::min<double>(100, brightness)); |
| 95 | + contrast = std::max<double>(3, std::min<double>(97, contrast)); |
| 96 | + |
| 97 | + StudioUtils::brightness_contrast_to_window_width_level(brightness, contrast, range[0], range[1], windowWidth, windowCenter); |
| 98 | + |
| 99 | + lightbox_->set_shared_brightness_and_contrast(brightness, contrast); |
| 100 | + |
| 101 | + // Apply window width and level to the image actor's property |
| 102 | + prop->SetColorWindow(windowWidth); |
| 103 | + prop->SetColorLevel(windowCenter); |
| 104 | + this->Interactor->Render(); |
| 105 | +} |
| 106 | + |
| 107 | +//----------------------------------------------------------------------------- |
| 108 | +void StudioSliceInteractorStyle::StartWindowLevel() { |
| 109 | + // forward events |
| 110 | + vtkInteractorStyleImage::StartWindowLevel(); |
| 111 | + |
| 112 | + if (!this->CurrentRenderer) { |
| 113 | + return; |
| 114 | + } |
| 115 | + |
| 116 | + vtkPropCollection* props = this->CurrentRenderer->GetViewProps(); |
| 117 | + vtkProp* prop = nullptr; |
| 118 | + vtkAssemblyPath* path; |
| 119 | + vtkImageSlice* imageProp = nullptr; |
| 120 | + vtkCollectionSimpleIterator pit; |
| 121 | + |
| 122 | + int i = -1; |
| 123 | + |
| 124 | + for (int k = 0; k < 2; k++) { |
| 125 | + int j = 0; |
| 126 | + for (props->InitTraversal(pit); (prop = props->GetNextProp(pit));) { |
| 127 | + bool foundImageProp = false; |
| 128 | + for (prop->InitPathTraversal(); (path = prop->GetNextPath());) { |
| 129 | + vtkProp* tryProp = path->GetLastNode()->GetViewProp(); |
| 130 | + imageProp = vtkImageSlice::SafeDownCast(tryProp); |
| 131 | + if (imageProp) { |
| 132 | + if (j == i && imageProp->GetPickable()) { |
| 133 | + foundImageProp = true; |
| 134 | + break; |
| 135 | + } |
| 136 | + imageProp = nullptr; |
| 137 | + j++; |
| 138 | + } |
| 139 | + } |
| 140 | + if (foundImageProp) { |
| 141 | + break; |
| 142 | + } |
| 143 | + } |
| 144 | + if (i < 0) { |
| 145 | + i += j; |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + if (imageProp) { |
| 150 | + current_image_slice_ = imageProp; |
52 | 151 | }
|
53 | 152 | }
|
54 | 153 |
|
|
0 commit comments