diff --git a/crystalfly/VTK Error Out.txt b/crystalfly/VTK Error Out.txt new file mode 100644 index 0000000..19a514d --- /dev/null +++ b/crystalfly/VTK Error Out.txt @@ -0,0 +1,8 @@ +ERROR: In vtkDemandDrivenPipeline.cxx, line 677 +vtkCompositeDataPipeline (00000233450F5040): Input port 0 of algorithm vtkOpenGLGPUVolumeRayCastMapper (0000023343594B20) has 0 connections but is not optional. + + +ERROR: In vtkDemandDrivenPipeline.cxx, line 677 +vtkCompositeDataPipeline (00000233450F5040): Input port 0 of algorithm vtkOpenGLGPUVolumeRayCastMapper (0000023343594B20) has 0 connections but is not optional. + + diff --git a/crystalfly/main.py b/crystalfly/main.py index de66de9..593d5e2 100644 --- a/crystalfly/main.py +++ b/crystalfly/main.py @@ -2,6 +2,7 @@ import ctypes import sys from PySide6.QtWidgets import QApplication +from vtkmodules.vtkCommonCore import vtkFileOutputWindow, vtkOutputWindow from crystalfly.ui.main_window import MainWindow @@ -16,4 +17,9 @@ def main(): if __name__ == '__main__': + # pipe vtk output errors to file + errOut = vtkFileOutputWindow() + errOut.SetFileName("VTK Error Out.txt") + vtkStdErrOut = vtkOutputWindow() + vtkStdErrOut.SetInstance(errOut) main() diff --git a/crystalfly/ui/__pycache__/main_window.cpython-311.pyc b/crystalfly/ui/__pycache__/main_window.cpython-311.pyc index e507c55..d427a53 100644 Binary files a/crystalfly/ui/__pycache__/main_window.cpython-311.pyc and b/crystalfly/ui/__pycache__/main_window.cpython-311.pyc differ diff --git a/crystalfly/ui/__pycache__/volume_viewer.cpython-311.pyc b/crystalfly/ui/__pycache__/volume_viewer.cpython-311.pyc index 0154e07..32f042b 100644 Binary files a/crystalfly/ui/__pycache__/volume_viewer.cpython-311.pyc and b/crystalfly/ui/__pycache__/volume_viewer.cpython-311.pyc differ diff --git a/crystalfly/ui/__pycache__/vtk_viewer.cpython-311.pyc b/crystalfly/ui/__pycache__/vtk_viewer.cpython-311.pyc index cf38fd9..b124128 100644 Binary files a/crystalfly/ui/__pycache__/vtk_viewer.cpython-311.pyc and b/crystalfly/ui/__pycache__/vtk_viewer.cpython-311.pyc differ diff --git a/crystalfly/ui/main_window.py b/crystalfly/ui/main_window.py index bd375e6..eba9256 100644 --- a/crystalfly/ui/main_window.py +++ b/crystalfly/ui/main_window.py @@ -1,8 +1,8 @@ from pathlib import Path -from PySide6.QtCore import Slot +from PySide6.QtCore import Slot, Qt from PySide6.QtUiTools import loadUiType -from PySide6.QtWidgets import QMainWindow +from PySide6.QtWidgets import QMainWindow, QSlider from vtkmodules.vtkRenderingOpenGL2 import vtkGenericOpenGLRenderWindow from crystalfly.ui.import_file import ImportFile @@ -39,15 +39,44 @@ class MainWindow(QMainWindow, MainWindowType): self.coronal.doubleClicked.connect(self.cell_max) self.sagittal.doubleClicked.connect(self.cell_max) self.transverse.doubleClicked.connect(self.cell_max) - # self.gridLayout.addWidget() + + self.volume.clicked.connect(self.cell_active) + self.coronal.clicked.connect(self.cell_active) + self.sagittal.clicked.connect(self.cell_active) + self.transverse.clicked.connect(self.cell_active) + + self.coronal.range_changed.connect(self.set_slide_range) + self.sagittal.range_changed.connect(self.set_slide_range) + self.transverse.range_changed.connect(self.set_slide_range) + self.volume_grid_layout.addWidget(self.volume) - self.coronal_grid_layout.addWidget(self.coronal) - self.gridLayout_3.addWidget(self.sagittal) - self.gridLayout_4.addWidget(self.transverse) + self.coronal_grid_layout.addWidget(self.coronal, 0, 0, 8, 8) + self.gridLayout_3.addWidget(self.sagittal, 0, 0, 8, 8) + self.gridLayout_4.addWidget(self.transverse, 0, 0, 8, 8) + + self.coronal_slider = QSlider(Qt.Orientation.Vertical) + self.sagittal_slider = QSlider(Qt.Orientation.Vertical) + self.transverse_slider = QSlider(Qt.Orientation.Vertical) + + self.coronal_slider.valueChanged.connect(self.coronal.image_viewer.SetSlice) + self.sagittal_slider.valueChanged.connect(self.sagittal.image_viewer.SetSlice) + self.transverse_slider.valueChanged.connect(self.transverse.image_viewer.SetSlice) + + self.coronal_grid_layout.addWidget(self.coronal_slider, 0, 8, 8, 1) + self.gridLayout_3.addWidget(self.sagittal_slider, 0, 8, 8, 1) + self.gridLayout_4.addWidget(self.transverse_slider, 0, 8, 8, 1) + + @Slot(int, int) + def set_slide_range(self, quadrant, value): + if quadrant == 1: + self.coronal_slider.setRange(0, value) + elif quadrant == 3: + self.sagittal_slider.setRange(0, value) + elif quadrant == 4: + self.transverse_slider.setRange(0, value) @Slot(int) def cell_max(self, quadrant: int): - print(quadrant) if self.is_pane_maximum: self.widget_3d.show() self.widget_coronal.show() @@ -59,7 +88,6 @@ class MainWindow(QMainWindow, MainWindowType): self.widget_coronal.hide() self.widget_sagittal.hide() self.widget_transverse.hide() - print(quadrant) if quadrant == 1: self.widget_coronal.show() elif quadrant == 2: @@ -70,9 +98,36 @@ class MainWindow(QMainWindow, MainWindowType): self.widget_transverse.show() self.is_pane_maximum = True - @Slot() - def cell_click(self): - print("clicked") + @Slot(int) + def cell_active(self, quadrant: int): + self.widget_3d.setStyleSheet(".QWidget {" + "border: none;" + "}") + self.widget_coronal.setStyleSheet(".QWidget {" + "border: none;" + "}") + self.widget_sagittal.setStyleSheet(".QWidget {" + "border: none;" + "}") + self.widget_transverse.setStyleSheet(".QWidget {" + "border: none;" + "}") + if quadrant == 1: + self.widget_coronal.setStyleSheet(".QWidget {" + "border: 1px solid tomato;" + "}") + elif quadrant == 2: + self.widget_3d.setStyleSheet(".QWidget {" + "border: 1px solid tomato;" + "}") + elif quadrant == 3: + self.widget_sagittal.setStyleSheet(".QWidget {" + "border: 1px solid tomato;" + "}") + elif quadrant == 4: + self.widget_transverse.setStyleSheet(".QWidget {" + "border: 1px solid tomato;" + "}") @Slot() def handle_file_open(self): diff --git a/crystalfly/ui/main_window.ui b/crystalfly/ui/main_window.ui index 04d9314..189436b 100644 --- a/crystalfly/ui/main_window.ui +++ b/crystalfly/ui/main_window.ui @@ -35,7 +35,7 @@ - + 0 diff --git a/crystalfly/ui/volume_viewer.py b/crystalfly/ui/volume_viewer.py index d8aebb8..18a8a84 100644 --- a/crystalfly/ui/volume_viewer.py +++ b/crystalfly/ui/volume_viewer.py @@ -15,6 +15,7 @@ from crystalfly.model.image_reader import image_reader_model class VolumeViewer(QVTKRenderWindowInteractor): doubleClicked = Signal(int) + clicked = Signal(int) def __init__(self, quadrant: int): super().__init__() @@ -73,9 +74,13 @@ class VolumeViewer(QVTKRenderWindowInteractor): self.volume_mapper.SetInputData(image) self.iren.SetRenderWindow(self.render_window) self.render_window.Render() + self.renderer.ResetCamera() + self.renderer.GetActiveCamera().Zoom(1.3) self.volume.Update() # self.volume_mapper.Render() def mouseDoubleClickEvent(self, evt: QMouseEvent): - print(evt, self.quadrant) self.doubleClicked.emit(self.quadrant) + + # def mousePressEvent(self, ev: QMouseEvent): + # self.clicked.emit(self.quadrant) diff --git a/crystalfly/ui/vtk_viewer.py b/crystalfly/ui/vtk_viewer.py index b2e1a17..9732e1e 100644 --- a/crystalfly/ui/vtk_viewer.py +++ b/crystalfly/ui/vtk_viewer.py @@ -3,15 +3,16 @@ import vtkmodules.vtkRenderingContextOpenGL2 from PySide6.QtCore import Signal from PySide6.QtGui import QCloseEvent, QMouseEvent from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor -from vtkmodules.vtkInteractionImage import vtkResliceImageViewer, vtkImageViewer2 +from vtkmodules.vtkInteractionImage import vtkImageViewer2 from vtkmodules.vtkInteractionStyle import vtkInteractorStyleImage -from vtkmodules.vtkInteractionWidgets import vtkResliceCursorLineRepresentation, vtkImagePlaneWidget from crystalfly.model.image_reader import image_reader_model class VTKImageViewer(QVTKRenderWindowInteractor): doubleClicked = Signal(int) + clicked = Signal(int) + range_changed = Signal(int, int) def __init__(self, quadrant: int): super().__init__() @@ -46,6 +47,8 @@ class VTKImageViewer(QVTKRenderWindowInteractor): self.image_viewer.SetRenderWindow(self.render_window) self.image_viewer.SetInputData(image) self.image_viewer.Render() + max_slice = self.image_viewer.GetSliceMax() + self.range_changed.emit(self.quadrant, max_slice) print("setImage") def mouse_wheel_forward_event(self, a, b): @@ -66,3 +69,6 @@ class VTKImageViewer(QVTKRenderWindowInteractor): def mouseDoubleClickEvent(self, evt: QMouseEvent): self.doubleClicked.emit(self.quadrant) + + # def mousePressEvent(self, ev: QMouseEvent): + # self.clicked.emit(self.quadrant)