diff --git a/Applications/Tutorial/Step6.cpp b/Applications/Tutorial/Step6.cpp index 7492f1e911..5252be0dac 100644 --- a/Applications/Tutorial/Step6.cpp +++ b/Applications/Tutorial/Step6.cpp @@ -1,249 +1,248 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "Step6.h" #include "QmitkRenderWindow.h" #include "QmitkSliceWidget.h" #include "mitkDataNodeFactory.h" #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkGlobalInteraction.h" #include "mitkPointSet.h" #include "mitkPointSetInteractor.h" #include "mitkImageAccessByItk.h" #include "mitkRenderingManager.h" #include #include #include #include #include #include //##Documentation //## @brief Start region-grower at interactively added points Step6::Step6(int argc, char* argv[], QWidget *parent) : QWidget(parent) { // load data as in the previous steps; a reference to the first loaded // image is kept in the member m_FirstImage and used as input for the // region growing Load(argc, argv); } void Step6::Initialize() { // setup the widgets as in the previous steps, but with an additional // QVBox for a button to start the segmentation this->SetupWidgets(); // Create controlsParent widget with horizontal layout QWidget *controlsParent = new QWidget(this); this->layout()->addWidget(controlsParent); QHBoxLayout* hlayout = new QHBoxLayout(controlsParent); hlayout->setSpacing(2); QLabel *labelThresholdMin = new QLabel("Lower Threshold:", controlsParent); hlayout->addWidget(labelThresholdMin); m_LineEditThresholdMin = new QLineEdit("-1000", controlsParent); hlayout->addWidget(m_LineEditThresholdMin); QLabel *labelThresholdMax = new QLabel("Upper Threshold:", controlsParent); hlayout->addWidget(labelThresholdMax); m_LineEditThresholdMax = new QLineEdit("-400", controlsParent); hlayout->addWidget(m_LineEditThresholdMax); // create button to start the segmentation and connect its clicked() // signal to method StartRegionGrowing QPushButton* startButton = new QPushButton("start region growing", controlsParent); hlayout->addWidget(startButton); connect(startButton, SIGNAL(clicked()), this, SLOT(StartRegionGrowing())); if (m_FirstImage.IsNull()) startButton->setEnabled(false); // as in Step5, create PointSet (now as a member m_Seeds) and // associate a interactor to it m_Seeds = mitk::PointSet::New(); mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); pointSetNode->SetData(m_Seeds); pointSetNode->SetProperty("layer", mitk::IntProperty::New(2)); m_DataStorage->Add(pointSetNode); mitk::GlobalInteraction::GetInstance()->AddInteractor( mitk::PointSetInteractor::New("pointsetinteractor", pointSetNode)); } int Step6::GetThresholdMin() { return m_LineEditThresholdMin->text().toInt(); } int Step6::GetThresholdMax() { return m_LineEditThresholdMax->text().toInt(); } void Step6::StartRegionGrowing() { AccessByItk_1(m_FirstImage, RegionGrowing, this); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void Step6::Load(int argc, char* argv[]) { //************************************************************************* // Part I: Basic initialization //************************************************************************* m_DataStorage = mitk::StandaloneDataStorage::New(); //************************************************************************* // Part II: Create some data by reading files //************************************************************************* int i; for (i = 1; i < argc; ++i) { // For testing if (strcmp(argv[i], "-testing") == 0) continue; // Create a DataNodeFactory to read a data format supported // by the DataNodeFactory (many image formats, surface formats, etc.) mitk::DataNodeFactory::Pointer nodeReader = mitk::DataNodeFactory::New(); const char * filename = argv[i]; try { nodeReader->SetFileName(filename); nodeReader->Update(); //********************************************************************* // Part III: Put the data into the datastorage //********************************************************************* // Since the DataNodeFactory directly creates a node, // use the iterator to add the read node to the tree mitk::DataNode::Pointer node = nodeReader->GetOutput(); - m_ResultNode = node; m_DataStorage->Add(node); mitk::Image::Pointer image = dynamic_cast (node->GetData()); if ((m_FirstImage.IsNull()) && (image.IsNotNull())) m_FirstImage = image; } catch (...) { fprintf(stderr, "Could not open file %s \n\n", filename); exit(2); } } } void Step6::SetupWidgets() { //************************************************************************* // Part I: Create windows and pass the datastorage to it //************************************************************************* // Create toplevel widget with vertical layout QVBoxLayout* vlayout = new QVBoxLayout(this); vlayout->setMargin(0); vlayout->setSpacing(2); // Create viewParent widget with horizontal layout QWidget* viewParent = new QWidget(this); vlayout->addWidget(viewParent); QHBoxLayout* hlayout = new QHBoxLayout(viewParent); hlayout->setMargin(0); hlayout->setSpacing(2); //************************************************************************* // Part Ia: 3D view //************************************************************************* // Create a renderwindow QmitkRenderWindow* renderWindow = new QmitkRenderWindow(viewParent); hlayout->addWidget(renderWindow); // Tell the renderwindow which (part of) the tree to render renderWindow->GetRenderer()->SetDataStorage(m_DataStorage); // Use it as a 3D view renderWindow->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); //************************************************************************* // Part Ib: 2D view for slicing transversally //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget *view2 = new QmitkSliceWidget(viewParent); hlayout->addWidget(view2); // Tell the QmitkSliceWidget which (part of) the tree to render. // By default, it slices the data transversally view2->SetDataStorage(m_DataStorage); mitk::DataStorage::SetOfObjects::ConstPointer rs = m_DataStorage->GetAll(); view2->SetData(rs->Begin(), mitk::SliceNavigationController::Transversal); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the tree! m_DataStorage->Add(view2->GetRenderer()->GetCurrentWorldGeometry2DNode()); //************************************************************************* // Part Ic: 2D view for slicing sagitally //************************************************************************* // Create QmitkSliceWidget, which is based on the class // QmitkRenderWindow, but additionally provides sliders QmitkSliceWidget *view3 = new QmitkSliceWidget(viewParent); hlayout->addWidget(view3); // Tell the QmitkSliceWidget which (part of) the tree to render // and to slice sagitally view3->SetDataStorage(m_DataStorage); view3->SetData(rs->Begin(), mitk::SliceNavigationController::Sagittal); // We want to see the position of the slice in 2D and the // slice itself in 3D: add it to the tree! m_DataStorage->Add(view3->GetRenderer()->GetCurrentWorldGeometry2DNode()); //************************************************************************* // Part II: handle updates: To avoid unnecessary updates, we have to //************************************************************************* // define when to update. The RenderingManager serves this purpose, and // each RenderWindow has to be registered to it. /*mitk::RenderingManager *renderingManager = mitk::RenderingManager::GetInstance(); renderingManager->AddRenderWindow( renderWindow ); renderingManager->AddRenderWindow( view2->GetRenderWindow() ); renderingManager->AddRenderWindow( view3->GetRenderWindow() );*/ } /** \example Step6.cpp */ diff --git a/Applications/Tutorial/Step8.cpp b/Applications/Tutorial/Step8.cpp index 7895e6716d..0d83d38183 100644 --- a/Applications/Tutorial/Step8.cpp +++ b/Applications/Tutorial/Step8.cpp @@ -1,115 +1,93 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "Step8.h" #include "QmitkStdMultiWidget.h" #include "mitkGlobalInteraction.h" #include "mitkRenderingManager.h" -#include #include #include -#include -#include - - //##Documentation //## @brief As Step6, but with QmitkStdMultiWidget as widget Step8::Step8(int argc, char* argv[], QWidget *parent) : Step6(argc, argv, parent) { } void Step8::SetupWidgets() { //************************************************************************* // Part I: Create windows and pass the tree to it //************************************************************************* // Create toplevel widget with vertical layout QVBoxLayout* vlayout = new QVBoxLayout(this); vlayout->setMargin(0); vlayout->setSpacing(2); // Create viewParent widget with horizontal layout QWidget* viewParent = new QWidget(this); vlayout->addWidget(viewParent); QHBoxLayout* hlayout = new QHBoxLayout(viewParent); hlayout->setMargin(0); -// mitk::ImageVtkMapper2D::Pointer mapper = mitk::ImageVtkMapper2D::New(); -// m_ResultNode->SetMapper(mitk::BaseRenderer::Extended2D, mapper); - //************************************************************************* // Part Ia: create and initialize QmitkStdMultiWidget //************************************************************************* QmitkStdMultiWidget* multiWidget = new QmitkStdMultiWidget(viewParent); hlayout->addWidget(multiWidget); // Tell the multiWidget which DataStorage to render multiWidget->SetDataStorage(m_DataStorage); // Initialize views as transversal, sagittal, coronar (from // top-left to bottom) mitk::TimeSlicedGeometry::Pointer geo = m_DataStorage->ComputeBoundingGeometry3D( m_DataStorage->GetAll()); mitk::RenderingManager::GetInstance()->InitializeViews(geo); - // Setup render window interactor -// vtkSmartPointer renderWindowInteractor = vtkSmartPointer::New(); -// vtkSmartPointer style = vtkSmartPointer::New(); - vtkSmartPointer style = vtkSmartPointer::New(); -// renderWindowInteractor->SetInteractorStyle(style); - // Initialize bottom-right view as 3D view -// multiWidget->GetRenderWindow1()->GetRenderer()->SetMapperID( -// mitk::BaseRenderer::Extended2D); -// multiWidget->GetRenderWindow1()->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style); -// renderWindowInteractor->Start(); - - + multiWidget->GetRenderWindow4()->GetRenderer()->SetMapperID( + mitk::BaseRenderer::Standard3D); // Enable standard handler for levelwindow-slider multiWidget->EnableStandardLevelWindow(); // Add the displayed views to the DataStorage to see their positions in 2D and 3D multiWidget->AddDisplayPlaneSubTree(); multiWidget->AddPlanesToDataStorage(); multiWidget->SetWidgetPlanesVisibility(true); //************************************************************************* // Part II: Setup standard interaction with the mouse //************************************************************************* // Moving the cut-planes to click-point multiWidget->EnableNavigationControllerEventListening(); - mitk::SliceNavigationController::Pointer sliceNavi = multiWidget->GetRenderWindow2()->GetSliceNavigationController(); - sliceNavi->SetViewDirection(mitk::SliceNavigationController::Transversal); - sliceNavi->Update(); - // Zooming and panning mitk::GlobalInteraction::GetInstance()->AddListener( multiWidget->GetMoveAndZoomInteractor()); } /** \example Step8.cpp */ diff --git a/Core/Code/Controllers/mitkCameraController.cpp b/Core/Code/Controllers/mitkCameraController.cpp index 7fd4e878c7..3ddd05ac58 100644 --- a/Core/Code/Controllers/mitkCameraController.cpp +++ b/Core/Code/Controllers/mitkCameraController.cpp @@ -1,170 +1,170 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkCameraController.h" #include "mitkVtkPropRenderer.h" #include "mitkRenderingManager.h" #include #include "vtkCommand.h" #include "vtkCamera.h" #include "vtkRenderer.h" mitk::CameraController::CameraController(const char * type) : BaseController(type), m_Renderer(NULL), m_ZoomFactor(1.0) {} mitk::CameraController::~CameraController() {} void mitk::CameraController::Resize(int, int) {} void mitk::CameraController::MousePressEvent(mitk::MouseEvent*) {} void mitk::CameraController::MouseReleaseEvent(mitk::MouseEvent*) {} void mitk::CameraController::MouseMoveEvent(mitk::MouseEvent*) {} void mitk::CameraController::KeyPressEvent(mitk::KeyEvent*) {} void mitk::CameraController::SetViewToAnterior() { this->SetStandardView(ANTERIOR); } void mitk::CameraController::SetViewToPosterior() { this->SetStandardView(POSTERIOR); } void mitk::CameraController::SetViewToSinister() { this->SetStandardView(SINISTER); } void mitk::CameraController::SetViewToDexter() { this->SetStandardView(DEXTER); } void mitk::CameraController::SetViewToCranial() { this->SetStandardView(CRANIAL); } void mitk::CameraController::SetViewToCaudal() { this->SetStandardView(CAUDAL); } void mitk::CameraController::SetStandardView( mitk::CameraController::StandardView view ) { const mitk::VtkPropRenderer* glRenderer = dynamic_cast(m_Renderer); if (glRenderer == NULL) return; vtkRenderer* vtkRenderer = glRenderer->GetVtkRenderer(); assert (vtkRenderer); mitk::BoundingBox::Pointer bb; mitk::DataStorage* ds = m_Renderer->GetDataStorage(); if (ds != NULL) bb = ds->ComputeBoundingBox(); else return; - if(m_Renderer->GetRenderWindow() == m_Renderer->GetRenderWindowByName("stdmulti.widget4")) + if(m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard3D) { - //set up the view for the 3D render window. The views for 2D are set up in the mitkImageVtkMapper2D + //set up the view for the 3D render window. The views for 2D are set up in the mitkVtkPropRenderer mitk::Point3D middle = bb->GetCenter(); vtkRenderer->GetActiveCamera()->SetFocalPoint(middle[0], middle[1], middle[2]); switch(view) { case ANTERIOR: case POSTERIOR: case SINISTER: case DEXTER: vtkRenderer->GetActiveCamera()->SetViewUp(0,0,1); break; case CRANIAL: case CAUDAL: vtkRenderer->GetActiveCamera()->SetViewUp(0,-1,0); break; } switch(view) { case ANTERIOR: vtkRenderer->GetActiveCamera()->SetPosition(middle[0],-100000,middle[2]); break; case POSTERIOR: vtkRenderer->GetActiveCamera()->SetPosition(middle[0],+100000,middle[2]); break; case SINISTER: vtkRenderer->GetActiveCamera()->SetPosition(+100000,middle[1],middle[2]); break; case DEXTER: vtkRenderer->GetActiveCamera()->SetPosition(-100000,middle[1],middle[2]); break; case CRANIAL: vtkRenderer->GetActiveCamera()->SetPosition(middle[0],middle[1],100000); break; case CAUDAL: vtkRenderer->GetActiveCamera()->SetPosition(middle[0],middle[1],-100000); break; } vtkRenderer->ResetCamera(); double *cameraPosition = vtkRenderer->GetActiveCamera()->GetPosition(); switch(view) { case ANTERIOR: case POSTERIOR: vtkRenderer->GetActiveCamera()->SetPosition(cameraPosition[0],cameraPosition[1] / m_ZoomFactor,cameraPosition[2]); break; case SINISTER: case DEXTER: vtkRenderer->GetActiveCamera()->SetPosition(cameraPosition[0] / m_ZoomFactor,cameraPosition[1],cameraPosition[2]); break; case CRANIAL: case CAUDAL: vtkRenderer->GetActiveCamera()->SetPosition(cameraPosition[0],cameraPosition[1],cameraPosition[2] / m_ZoomFactor); break; } vtkRenderer->ResetCameraClippingRange(); } mitk::RenderingManager* rm = m_Renderer->GetRenderingManager(); rm->RequestUpdateAll(); } diff --git a/Core/Code/Controllers/mitkRenderingManager.cpp b/Core/Code/Controllers/mitkRenderingManager.cpp index 277b36f065..c47da30e23 100644 --- a/Core/Code/Controllers/mitkRenderingManager.cpp +++ b/Core/Code/Controllers/mitkRenderingManager.cpp @@ -1,999 +1,1011 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkRenderingManager.h" #include "mitkRenderingManagerFactory.h" #include "mitkBaseRenderer.h" #include "mitkGlobalInteraction.h" #include #include #include "mitkVector.h" #include #include #include #include namespace mitk { RenderingManager::Pointer RenderingManager::s_Instance = 0; RenderingManagerFactory *RenderingManager::s_RenderingManagerFactory = 0; RenderingManager ::RenderingManager() : m_UpdatePending( false ), m_MaxLOD( 1 ), m_LODIncreaseBlocked( false ), m_LODAbortMechanismEnabled( false ), m_ClippingPlaneEnabled( false ), m_TimeNavigationController( NULL ), m_ConstrainedPaddingZooming ( true ), m_DataStorage( NULL ) { m_ShadingEnabled.assign( 3, false ); m_ShadingValues.assign( 4, 0.0 ); m_GlobalInteraction = mitk::GlobalInteraction::GetInstance(); InitializePropertyList(); } RenderingManager ::~RenderingManager() { // Decrease reference counts of all registered vtkRenderWindows for // proper destruction RenderWindowVector::iterator it; for ( it = m_AllRenderWindows.begin(); it != m_AllRenderWindows.end(); ++it ) { (*it)->UnRegister( NULL ); RenderWindowCallbacksList::iterator callbacks_it = this->m_RenderWindowCallbacksList.find(*it); (*it)->RemoveObserver(callbacks_it->second.commands[0u]); (*it)->RemoveObserver(callbacks_it->second.commands[1u]); (*it)->RemoveObserver(callbacks_it->second.commands[2u]); } } void RenderingManager ::SetFactory( RenderingManagerFactory *factory ) { s_RenderingManagerFactory = factory; } const RenderingManagerFactory * RenderingManager ::GetFactory() { return s_RenderingManagerFactory; } bool RenderingManager ::HasFactory() { if ( RenderingManager::s_RenderingManagerFactory ) { return true; } else { return false; } } RenderingManager::Pointer RenderingManager ::New() { const RenderingManagerFactory* factory = GetFactory(); if(factory == NULL) return NULL; return factory->CreateRenderingManager(); } RenderingManager * RenderingManager ::GetInstance() { if ( !RenderingManager::s_Instance ) { if ( s_RenderingManagerFactory ) { s_Instance = s_RenderingManagerFactory->CreateRenderingManager(); } } return s_Instance; } bool RenderingManager ::IsInstantiated() { if ( RenderingManager::s_Instance ) return true; else return false; } void RenderingManager ::AddRenderWindow( vtkRenderWindow *renderWindow ) { if ( renderWindow && (m_RenderWindowList.find( renderWindow ) == m_RenderWindowList.end()) ) { m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_AllRenderWindows.push_back( renderWindow ); if ( m_DataStorage.IsNotNull() ) mitk::BaseRenderer::GetInstance( renderWindow )->SetDataStorage( m_DataStorage.GetPointer() ); // Register vtkRenderWindow instance renderWindow->Register( NULL ); typedef itk::MemberCommand< RenderingManager > MemberCommandType; // Add callbacks for rendering abort mechanism //BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow ); vtkCallbackCommand *startCallbackCommand = vtkCallbackCommand::New(); startCallbackCommand->SetCallback( RenderingManager::RenderingStartCallback ); renderWindow->AddObserver( vtkCommand::StartEvent, startCallbackCommand ); vtkCallbackCommand *progressCallbackCommand = vtkCallbackCommand::New(); progressCallbackCommand->SetCallback( RenderingManager::RenderingProgressCallback ); renderWindow->AddObserver( vtkCommand::AbortCheckEvent, progressCallbackCommand ); vtkCallbackCommand *endCallbackCommand = vtkCallbackCommand::New(); endCallbackCommand->SetCallback( RenderingManager::RenderingEndCallback ); renderWindow->AddObserver( vtkCommand::EndEvent, endCallbackCommand ); RenderWindowCallbacks callbacks; callbacks.commands[0u] = startCallbackCommand; callbacks.commands[1u] = progressCallbackCommand; callbacks.commands[2u] = endCallbackCommand; this->m_RenderWindowCallbacksList[renderWindow] = callbacks; //Delete vtk variables correctly startCallbackCommand->Delete(); progressCallbackCommand->Delete(); endCallbackCommand->Delete(); } } void RenderingManager ::RemoveRenderWindow( vtkRenderWindow *renderWindow ) { if (m_RenderWindowList.erase( renderWindow )) { RenderWindowCallbacksList::iterator callbacks_it = this->m_RenderWindowCallbacksList.find(renderWindow); renderWindow->RemoveObserver(callbacks_it->second.commands[0u]); renderWindow->RemoveObserver(callbacks_it->second.commands[1u]); renderWindow->RemoveObserver(callbacks_it->second.commands[2u]); this->m_RenderWindowCallbacksList.erase(callbacks_it); RenderWindowVector::iterator rw_it = std::find( m_AllRenderWindows.begin(), m_AllRenderWindows.end(), renderWindow ); // Decrease reference count for proper destruction (*rw_it)->UnRegister(NULL); m_AllRenderWindows.erase( rw_it ); } } const RenderingManager::RenderWindowVector& RenderingManager ::GetAllRegisteredRenderWindows() { return m_AllRenderWindows; } void RenderingManager ::RequestUpdate( vtkRenderWindow *renderWindow ) { m_RenderWindowList[renderWindow] = RENDERING_REQUESTED; if ( !m_UpdatePending ) { m_UpdatePending = true; this->GenerateRenderingRequestEvent(); } } void RenderingManager ::ForceImmediateUpdate( vtkRenderWindow *renderWindow ) { // Erase potentially pending requests for this window m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_UpdatePending = false; // Immediately repaint this window (implementation platform specific) // If the size is 0 it crahses int *size = renderWindow->GetSize(); if ( 0 != size[0] && 0 != size[1] ) { + //prepare the camera etc. before rendering + //Note: this is a very important step which should be called before the VTK render! + //If you modify the camera anywhere else or after the render call, the scene cannot be seen. + mitk::VtkPropRenderer *vPR = + dynamic_cast(mitk::BaseRenderer::GetInstance( renderWindow )); + if(vPR) + vPR->PrepareRender(); // Execute rendering renderWindow->Render(); } } void RenderingManager ::RequestUpdateAll( RequestType type ) { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ( (type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)) ) { - dynamic_cast(BaseRenderer::GetInstance(it->first))->AdjustCameraToScene(); - this->RequestUpdate( it->first ); + this->RequestUpdate( it->first ); } } } void RenderingManager ::ForceImmediateUpdateAll( RequestType type ) { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ( (type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)) ) { // Immediately repaint this window (implementation platform specific) // If the size is 0, it crashes int *size = it->first->GetSize(); if ( 0 != size[0] && 0 != size[1] ) { - dynamic_cast(BaseRenderer::GetInstance(it->first))->AdjustCameraToScene(); + //prepare the camera before rendering + //Note: this is a very important step which should be called before the VTK render! + //If you modify the camera anywhere else or after the render call, the scene cannot be seen. + mitk::VtkPropRenderer *vPR = + dynamic_cast(mitk::BaseRenderer::GetInstance( it->first )); + if(vPR) + vPR->PrepareRender(); // Execute rendering it->first->Render(); } it->second = RENDERING_INACTIVE; } } m_UpdatePending = false; } //bool RenderingManager::InitializeViews( const mitk::DataStorage * storage, const DataNode* node = NULL, RequestType type, bool preserveRoughOrientationInWorldSpace ) //{ // mitk::Geometry3D::Pointer geometry; // if ( storage != NULL ) // { // geometry = storage->ComputeVisibleBoundingGeometry3D(node, "visible", NULL, "includeInBoundingBox" ); // // if ( geometry.IsNotNull() ) // { // // let's see if we have data with a limited live-span ... // mitk::TimeBounds timebounds = geometry->GetTimeBounds(); // if ( timebounds[1] < mitk::ScalarTypeNumericTraits::max() ) // { // mitk::ScalarType duration = timebounds[1]-timebounds[0]; // // mitk::TimeSlicedGeometry::Pointer timegeometry = // mitk::TimeSlicedGeometry::New(); // timegeometry->InitializeEvenlyTimed( // geometry, (unsigned int) duration ); // timegeometry->SetTimeBounds( timebounds ); // // timebounds[1] = timebounds[0] + 1.0; // geometry->SetTimeBounds( timebounds ); // // geometry = timegeometry; // } // } // } // // // Use geometry for initialization // return this->InitializeViews( geometry.GetPointer(), type ); //} bool RenderingManager ::InitializeViews( const Geometry3D * dataGeometry, RequestType type, bool preserveRoughOrientationInWorldSpace ) { MITK_DEBUG << "initializing views"; bool boundingBoxInitialized = false; Geometry3D::ConstPointer geometry = dataGeometry; if (dataGeometry && preserveRoughOrientationInWorldSpace) { // clone the input geometry Geometry3D::Pointer modifiedGeometry = dynamic_cast( dataGeometry->Clone().GetPointer() ); assert(modifiedGeometry.IsNotNull()); // construct an affine transform from it AffineGeometryFrame3D::TransformType::Pointer transform = AffineGeometryFrame3D::TransformType::New(); assert( modifiedGeometry->GetIndexToWorldTransform() ); transform->SetMatrix( modifiedGeometry->GetIndexToWorldTransform()->GetMatrix() ); transform->SetOffset( modifiedGeometry->GetIndexToWorldTransform()->GetOffset() ); // get transform matrix AffineGeometryFrame3D::TransformType::MatrixType::InternalMatrixType& oldMatrix = const_cast< AffineGeometryFrame3D::TransformType::MatrixType::InternalMatrixType& > ( transform->GetMatrix().GetVnlMatrix() ); AffineGeometryFrame3D::TransformType::MatrixType::InternalMatrixType newMatrix(oldMatrix); // get offset and bound Vector3D offset = modifiedGeometry->GetIndexToWorldTransform()->GetOffset(); Geometry3D::BoundsArrayType oldBounds = modifiedGeometry->GetBounds(); Geometry3D::BoundsArrayType newBounds = modifiedGeometry->GetBounds(); // get rid of rotation other than pi/2 degree for ( unsigned int i = 0; i < 3; ++i ) { // i-th column of the direction matrix Vector3D currentVector; currentVector[0] = oldMatrix(0,i); currentVector[1] = oldMatrix(1,i); currentVector[2] = oldMatrix(2,i); // matchingRow will store the row that holds the biggest // value in the column unsigned int matchingRow = 0; // maximum value in the column float max = std::numeric_limits::min(); // sign of the maximum value (-1 or 1) int sign = 1; // iterate through the column vector for (unsigned int dim = 0; dim < 3; ++dim) { if ( fabs(currentVector[dim]) > max ) { matchingRow = dim; max = fabs(currentVector[dim]); if(currentVector[dim]<0) sign = -1; else sign = 1; } } // in case we found a negative maximum, // we negate the column and adjust the offset // (in order to run through the dimension in the opposite direction) if(sign == -1) { currentVector *= sign; offset += modifiedGeometry->GetAxisVector(i); } // matchingRow is now used as column index to place currentVector // correctly in the new matrix vnl_vector newMatrixColumn(3); newMatrixColumn[0] = currentVector[0]; newMatrixColumn[1] = currentVector[1]; newMatrixColumn[2] = currentVector[2]; newMatrix.set_column( matchingRow, newMatrixColumn ); // if a column is moved, we also have to adjust the bounding // box accordingly, this is done here newBounds[2*matchingRow ] = oldBounds[2*i ]; newBounds[2*matchingRow+1] = oldBounds[2*i+1]; } // set the newly calculated bounds array modifiedGeometry->SetBounds(newBounds); // set new offset and direction matrix AffineGeometryFrame3D::TransformType::MatrixType newMatrixITK( newMatrix ); transform->SetMatrix( newMatrixITK ); transform->SetOffset( offset ); modifiedGeometry->SetIndexToWorldTransform( transform ); geometry = modifiedGeometry; } int warningLevel = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); if ( (geometry.IsNotNull() ) && (const_cast< mitk::BoundingBox * >( geometry->GetBoundingBox())->GetDiagonalLength2() > mitk::eps) ) { boundingBoxInitialized = true; } if (geometry.IsNotNull() ) {// make sure bounding box has an extent bigger than zero in any direction // clone the input geometry Geometry3D::Pointer modifiedGeometry = dynamic_cast( dataGeometry->Clone().GetPointer() ); assert(modifiedGeometry.IsNotNull()); Geometry3D::BoundsArrayType newBounds = modifiedGeometry->GetBounds(); for( unsigned int dimension = 0; ( 2 * dimension ) < newBounds.Size() ; dimension++ ) { //check for equality but for an epsilon if( Equal( newBounds[ 2 * dimension ], newBounds[ 2 * dimension + 1 ] ) ) { newBounds[ 2 * dimension + 1 ] += 1; } } // set the newly calculated bounds array modifiedGeometry->SetBounds(newBounds); geometry = modifiedGeometry; } RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( it->first ); baseRenderer->GetDisplayGeometry()->SetConstrainZoomingAndPanning(m_ConstrainedPaddingZooming); int id = baseRenderer->GetMapperID(); if ( ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) ) { this->InternalViewInitialization( baseRenderer, geometry, boundingBoxInitialized, id ); } } if ( m_TimeNavigationController != NULL ) { if ( boundingBoxInitialized ) { m_TimeNavigationController->SetInputWorldGeometry( geometry ); } m_TimeNavigationController->Update(); } this->RequestUpdateAll( type ); vtkObject::SetGlobalWarningDisplay( warningLevel ); // Inform listeners that views have been initialized this->InvokeEvent( mitk::RenderingManagerViewsInitializedEvent() ); return boundingBoxInitialized; } bool RenderingManager ::InitializeViews( RequestType type ) { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( it->first ); int id = baseRenderer->GetMapperID(); if ( (type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)) ) { mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); // Update the SNC nc->Update(); } } this->RequestUpdateAll( type ); return true; } //bool RenderingManager::InitializeView( vtkRenderWindow * renderWindow, const DataStorage* ds, const DataNode node = NULL, bool initializeGlobalTimeSNC ) //{ // mitk::Geometry3D::Pointer geometry; // if ( ds != NULL ) // { // geometry = ds->ComputeVisibleBoundingGeometry3D(node, NULL, "includeInBoundingBox" ); // // if ( geometry.IsNotNull() ) // { // // let's see if we have data with a limited live-span ... // mitk::TimeBounds timebounds = geometry->GetTimeBounds(); // if ( timebounds[1] < mitk::ScalarTypeNumericTraits::max() ) // { // mitk::ScalarType duration = timebounds[1]-timebounds[0]; // // mitk::TimeSlicedGeometry::Pointer timegeometry = // mitk::TimeSlicedGeometry::New(); // timegeometry->InitializeEvenlyTimed( // geometry, (unsigned int) duration ); // timegeometry->SetTimeBounds( timebounds ); // // timebounds[1] = timebounds[0] + 1.0; // geometry->SetTimeBounds( timebounds ); // // geometry = timegeometry; // } // } // } // // // Use geometry for initialization // return this->InitializeView( renderWindow, // geometry.GetPointer(), initializeGlobalTimeSNC ); //} bool RenderingManager::InitializeView( vtkRenderWindow * renderWindow, const Geometry3D * geometry, bool initializeGlobalTimeSNC ) { bool boundingBoxInitialized = false; int warningLevel = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); if ( (geometry != NULL ) && (const_cast< mitk::BoundingBox * >( geometry->GetBoundingBox())->GetDiagonalLength2() > mitk::eps) ) { boundingBoxInitialized = true; } mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( renderWindow ); int id = baseRenderer->GetMapperID(); this->InternalViewInitialization( baseRenderer, geometry, boundingBoxInitialized, id ); if ( m_TimeNavigationController != NULL ) { if ( boundingBoxInitialized && initializeGlobalTimeSNC ) { m_TimeNavigationController->SetInputWorldGeometry( geometry ); } m_TimeNavigationController->Update(); } this->RequestUpdate( renderWindow ); vtkObject::SetGlobalWarningDisplay( warningLevel ); return boundingBoxInitialized; } bool RenderingManager::InitializeView( vtkRenderWindow * renderWindow ) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( renderWindow ); mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); // Update the SNC nc->Update(); this->RequestUpdate( renderWindow ); return true; } void RenderingManager::InternalViewInitialization(mitk::BaseRenderer *baseRenderer, const mitk::Geometry3D *geometry, bool boundingBoxInitialized, int mapperID ) { mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); if ( boundingBoxInitialized ) { // Set geometry for NC nc->SetInputWorldGeometry( geometry ); nc->Update(); if ( mapperID == 1 ) { // For 2D SNCs, steppers are set so that the cross is centered // in the image nc->GetSlice()->SetPos( nc->GetSlice()->GetSteps() / 2 ); } // Fit the render window DisplayGeometry baseRenderer->GetDisplayGeometry()->Fit(); baseRenderer->GetCameraController()->SetViewToAnterior(); } else { nc->Update(); } } void RenderingManager::SetTimeNavigationController( SliceNavigationController *nc ) { m_TimeNavigationController = nc; } const SliceNavigationController* RenderingManager::GetTimeNavigationController() const { return m_TimeNavigationController; } SliceNavigationController* RenderingManager::GetTimeNavigationController() { return m_TimeNavigationController; } void RenderingManager::ExecutePendingRequests() { m_UpdatePending = false; // Satisfy all pending update requests RenderWindowList::iterator it; int i = 0; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it, ++i ) { if ( it->second == RENDERING_REQUESTED ) { this->ForceImmediateUpdate( it->first ); } } } void RenderingManager::RenderingStartCallback( vtkObject *caller, unsigned long , void *, void * ) { vtkRenderWindow *renderWindow = dynamic_cast< vtkRenderWindow * >( caller ); mitk::RenderingManager* renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); RenderWindowList &renderWindowList = renman->m_RenderWindowList; if ( renderWindow ) { renderWindowList[renderWindow] = RENDERING_INPROGRESS; } renman->m_UpdatePending = false; } void RenderingManager ::RenderingProgressCallback( vtkObject *caller, unsigned long , void *, void * ) { vtkRenderWindow *renderWindow = dynamic_cast< vtkRenderWindow * >( caller ); mitk::RenderingManager* renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); if ( renman->m_LODAbortMechanismEnabled ) { vtkRenderWindow *renderWindow = dynamic_cast< vtkRenderWindow * >( caller ); if ( renderWindow ) { BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow ); if ( renderer && (renderer->GetNumberOfVisibleLODEnabledMappers() > 0) ) { renman->DoMonitorRendering(); } } } } void RenderingManager ::RenderingEndCallback( vtkObject *caller, unsigned long , void *, void * ) { vtkRenderWindow *renderWindow = dynamic_cast< vtkRenderWindow * >( caller ); mitk::RenderingManager* renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); RenderWindowList &renderWindowList = renman->m_RenderWindowList; RendererIntMap &nextLODMap = renman->m_NextLODMap; if ( renderWindow ) { BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow ); if ( renderer ) { renderWindowList[renderer->GetRenderWindow()] = RENDERING_INACTIVE; // Level-of-Detail handling if ( renderer->GetNumberOfVisibleLODEnabledMappers() > 0 ) { if(nextLODMap[renderer]==0) renman->StartOrResetTimer(); else nextLODMap[renderer] = 0; } } } } bool RenderingManager ::IsRendering() const { RenderWindowList::const_iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { if ( it->second == RENDERING_INPROGRESS ) { return true; } } return false; } void RenderingManager ::AbortRendering() { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { if ( it->second == RENDERING_INPROGRESS ) { it->first->SetAbortRender( true ); m_RenderingAbortedMap[BaseRenderer::GetInstance(it->first)] = true; } } } int RenderingManager ::GetNextLOD( BaseRenderer *renderer ) { if ( renderer != NULL ) { return m_NextLODMap[renderer]; } else { return 0; } } void RenderingManager ::ExecutePendingHighResRenderingRequest() { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { BaseRenderer *renderer = BaseRenderer::GetInstance( it->first ); if(renderer->GetNumberOfVisibleLODEnabledMappers()>0) { if(m_NextLODMap[renderer]==0) { m_NextLODMap[renderer]=1; RequestUpdate( it->first ); } } } } void RenderingManager ::SetMaximumLOD( unsigned int max ) { m_MaxLOD = max; } //enable/disable shading void RenderingManager ::SetShading(bool state, unsigned int lod) { if(lod>m_MaxLOD) { itkWarningMacro(<<"LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return; } m_ShadingEnabled[lod] = state; } bool RenderingManager ::GetShading(unsigned int lod) { if(lod>m_MaxLOD) { itkWarningMacro(<<"LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return false; } return m_ShadingEnabled[lod]; } //enable/disable the clipping plane void RenderingManager ::SetClippingPlaneStatus(bool status) { m_ClippingPlaneEnabled = status; } bool RenderingManager ::GetClippingPlaneStatus() { return m_ClippingPlaneEnabled; } void RenderingManager ::SetShadingValues(float ambient, float diffuse, float specular, float specpower) { m_ShadingValues[0] = ambient; m_ShadingValues[1] = diffuse; m_ShadingValues[2] = specular; m_ShadingValues[3] = specpower; } RenderingManager::FloatVector & RenderingManager ::GetShadingValues() { return m_ShadingValues; } void RenderingManager::SetDepthPeelingEnabled( bool enabled ) { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( it->first ); baseRenderer->SetDepthPeelingEnabled(enabled); } } void RenderingManager::SetMaxNumberOfPeels( int maxNumber ) { RenderWindowList::iterator it; for ( it = m_RenderWindowList.begin(); it != m_RenderWindowList.end(); ++it ) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance( it->first ); baseRenderer->SetMaxNumberOfPeels(maxNumber); } } void RenderingManager::InitializePropertyList() { if (m_PropertyList.IsNull()) { m_PropertyList = PropertyList::New(); } this->SetProperty("coupled-zoom", BoolProperty::New(false)); this->SetProperty("coupled-plane-rotation", BoolProperty::New(false)); this->SetProperty("MIP-slice-rendering", BoolProperty::New(false)); } PropertyList::Pointer RenderingManager::GetPropertyList() const { return m_PropertyList; } BaseProperty* RenderingManager::GetProperty(const char *propertyKey) const { return m_PropertyList->GetProperty(propertyKey); } void RenderingManager::SetProperty(const char *propertyKey, BaseProperty* propertyValue) { m_PropertyList->SetProperty(propertyKey, propertyValue); } void RenderingManager::SetDataStorage( DataStorage* storage ) { if ( storage != NULL ) { m_DataStorage = storage; RenderingManager::RenderWindowVector::iterator iter; for ( iter = m_AllRenderWindows.begin(); iterSetDataStorage( m_DataStorage.GetPointer() ); } } } mitk::DataStorage* RenderingManager::GetDataStorage() { return m_DataStorage; } void RenderingManager::SetGlobalInteraction( mitk::GlobalInteraction* globalInteraction ) { if ( globalInteraction != NULL ) { m_GlobalInteraction = globalInteraction; } } mitk::GlobalInteraction* RenderingManager::GetGlobalInteraction() { return m_GlobalInteraction; } // Create and register generic RenderingManagerFactory. TestingRenderingManagerFactory renderingManagerFactory; } // namespace diff --git a/Core/Code/Rendering/mitkBaseRenderer.h b/Core/Code/Rendering/mitkBaseRenderer.h index 072bd9ff51..0ba30f87dc 100644 --- a/Core/Code/Rendering/mitkBaseRenderer.h +++ b/Core/Code/Rendering/mitkBaseRenderer.h @@ -1,583 +1,585 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 #define BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 #include "mitkDataStorage.h" #include "mitkGeometry2D.h" #include "mitkTimeSlicedGeometry.h" #include "mitkDisplayGeometry.h" #include "mitkGeometry2DData.h" #include "mitkCameraController.h" #include "mitkDisplayPositionEvent.h" #include "mitkWheelEvent.h" //#include "mitkMapper.h" #include "mitkSliceNavigationController.h" #include "mitkCameraController.h" #include "mitkCameraRotationController.h" #include #include #include #include namespace mitk { class NavigationController; class SliceNavigationController; class CameraRotationController; class CameraController; class DataStorage; class Mapper; class BaseLocalStorageHandler; //##Documentation //## @brief Organizes the rendering process //## //## Organizes the rendering process. A Renderer contains a reference to a //## DataStorage and asks the mappers of the data objects to render //## the data into the renderwindow it is associated to. //## //## \#Render() checks if rendering is currently allowed by calling //## RenderWindow::PrepareRendering(). Initialization of a rendering context //## can also be performed in this method. //## //## The actual rendering code has been moved to \#Repaint() //## Both \#Repaint() and \#Update() are declared protected now. //## //## Note: Separation of the Repaint and Update processes (rendering vs //## creating a vtk prop tree) still needs to be worked on. The whole //## rendering process also should be reworked to use VTK based classes for //## both 2D and 3D rendering. //## @ingroup Renderer class MITK_CORE_EXPORT BaseRenderer : public itk::Object { public: typedef std::map BaseRendererMapType; static BaseRendererMapType baseRendererMap; static BaseRenderer* GetInstance(vtkRenderWindow * renWin); static void AddInstance(vtkRenderWindow* renWin, BaseRenderer* baseRenderer); static void RemoveInstance(vtkRenderWindow* renWin); static BaseRenderer* GetByName( const std::string& name ); static vtkRenderWindow* GetRenderWindowByName( const std::string& name ); itkEventMacro( RendererResetEvent, itk::AnyEvent ); /** Standard class typedefs. */ mitkClassMacro(BaseRenderer, itk::Object); BaseRenderer( const char* name = NULL, vtkRenderWindow * renWin = NULL, mitk::RenderingManager* rm= NULL ); //##Documentation //## @brief MapperSlotId defines which kind of mapper (e.g., 2D or 3D) shoud be used. typedef int MapperSlotId; enum StandardMapperSlot{Standard2D=1, Standard3D=2}; virtual void SetDataStorage( DataStorage* storage ); ///< set the datastorage that will be used for rendering //##Documentation //## return the DataStorage that is used for rendering virtual DataStorage::Pointer GetDataStorage() const { return m_DataStorage.GetPointer(); }; //##Documentation //## @brief Access the RenderWindow into which this renderer renders. vtkRenderWindow* GetRenderWindow() const { return m_RenderWindow; } vtkRenderer* GetVtkRenderer() const { return m_VtkRenderer; } //##Documentation //## @brief Default mapper id to use. static const MapperSlotId defaultMapper; //##Documentation //## @brief Do the rendering and flush the result. virtual void Paint(); //##Documentation //## @brief Initialize the RenderWindow. Should only be called from RenderWindow. virtual void Initialize(); //##Documentation //## @brief Called to inform the renderer that the RenderWindow has been resized. virtual void Resize(int w, int h); //##Documentation //## @brief Initialize the renderer with a RenderWindow (@a renderwindow). virtual void InitRenderer(vtkRenderWindow* renderwindow); //##Documentation //## @brief Set the initial size. Called by RenderWindow after it has become //## visible for the first time. virtual void InitSize(int w, int h); //##Documentation //## @brief Draws a point on the widget. //## Should be used during conferences to show the position of the remote mouse virtual void DrawOverlayMouse(Point2D& p2d); //##Documentation //## @brief Set/Get the WorldGeometry (m_WorldGeometry) for 3D and 2D rendering, that describing the //## (maximal) area to be rendered. //## //## Depending of the type of the passed Geometry3D more or less information can be extracted: //## \li if it is a Geometry2D (which is a sub-class of Geometry3D), m_CurrentWorldGeometry2D is //## also set to point to it. m_TimeSlicedWorldGeometry is set to NULL. //## \li if it is a TimeSlicedGeometry, m_TimeSlicedWorldGeometry is also set to point to it. //## If m_TimeSlicedWorldGeometry contains instances of SlicedGeometry3D, m_CurrentWorldGeometry2D is set to //## one of geometries stored in the SlicedGeometry3D according to the value of m_Slice; otherwise //## a PlaneGeometry describing the top of the bounding-box of the Geometry3D is set as the //## m_CurrentWorldGeometry2D. //## \li otherwise a PlaneGeometry describing the top of the bounding-box of the Geometry3D //## is set as the m_CurrentWorldGeometry2D. m_TimeSlicedWorldGeometry is set to NULL. //## @todo add calculation of PlaneGeometry describing the top of the bounding-box of the Geometry3D //## when the passed Geometry3D is not sliced. //## \sa m_WorldGeometry //## \sa m_TimeSlicedWorldGeometry //## \sa m_CurrentWorldGeometry2D virtual void SetWorldGeometry(Geometry3D* geometry); itkGetConstObjectMacro(WorldGeometry, Geometry3D); //##Documentation //## @brief Get the current 3D-worldgeometry (m_CurrentWorldGeometry) used for 3D-rendering itkGetConstObjectMacro(CurrentWorldGeometry, Geometry3D); //##Documentation //## @brief Get the current 2D-worldgeometry (m_CurrentWorldGeometry2D) used for 2D-rendering itkGetConstObjectMacro(CurrentWorldGeometry2D, Geometry2D); //##Documentation //## Calculates the bounds of the DataStorage (if it contains any valid data), //## creates a geometry from these bounds and sets it as world geometry of the renderer. //## //## Call this method to re-initialize the renderer to the current DataStorage //## (e.g. after loading an additional dataset), to ensure that the view is //## aligned correctly. //## \warn This is not implemented yet. virtual bool SetWorldGeometryToDataStorageBounds() { return false; } //##Documentation //## @brief Set/Get the DisplayGeometry (for 2D rendering) //## //## The DisplayGeometry describes which part of the Geometry2D m_CurrentWorldGeometry2D //## is displayed. virtual void SetDisplayGeometry(DisplayGeometry* geometry2d); itkGetConstObjectMacro(DisplayGeometry, DisplayGeometry); itkGetObjectMacro(DisplayGeometry, DisplayGeometry); //##Documentation //## @brief Set/Get m_Slice which defines together with m_TimeStep the 2D geometry //## stored in m_TimeSlicedWorldGeometry used as m_CurrentWorldGeometry2D //## //## \sa m_Slice virtual void SetSlice(unsigned int slice); itkGetConstMacro(Slice, unsigned int); //##Documentation //## @brief Set/Get m_TimeStep which defines together with m_Slice the 2D geometry //## stored in m_TimeSlicedWorldGeometry used as m_CurrentWorldGeometry2D //## //## \sa m_TimeStep virtual void SetTimeStep(unsigned int timeStep); itkGetConstMacro(TimeStep, unsigned int); //##Documentation //## @brief Get the time-step of a BaseData object which //## exists at the time of the currently displayed content //## //## Returns -1 or mitk::BaseData::m_TimeSteps if there //## is no data at the current time. //## \sa GetTimeStep, m_TimeStep int GetTimeStep(const BaseData* data) const; //##Documentation //## @brief Get the time in ms of the currently displayed content //## //## \sa GetTimeStep, m_TimeStep ScalarType GetTime() const; //##Documentation //## @brief SetWorldGeometry is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometrySendEvent virtual void SetGeometry(const itk::EventObject & geometrySliceEvent); //##Documentation //## @brief UpdateWorldGeometry is called to re-read the 2D geometry from the //## slice navigation controller virtual void UpdateGeometry(const itk::EventObject & geometrySliceEvent); //##Documentation //## @brief SetSlice is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometrySliceEvent virtual void SetGeometrySlice(const itk::EventObject & geometrySliceEvent); //##Documentation //## @brief SetTimeStep is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometryTimeEvent virtual void SetGeometryTime(const itk::EventObject & geometryTimeEvent); //##Documentation //## @brief Get a data object containing the DisplayGeometry (for 2D rendering) itkGetObjectMacro(DisplayGeometryData, Geometry2DData); //##Documentation //## @brief Get a data object containing the WorldGeometry (for 2D rendering) itkGetObjectMacro(WorldGeometryData, Geometry2DData); //##Documentation //## @brief Get a DataNode pointing to a data object containing the WorldGeometry (3D and 2D rendering) itkGetObjectMacro(WorldGeometryNode, DataNode); //##Documentation //## @brief Get a DataNode pointing to a data object containing the DisplayGeometry (for 2D rendering) itkGetObjectMacro(DisplayGeometryNode, DataNode); //##Documentation //## @brief Get a DataNode pointing to a data object containing the current 2D-worldgeometry m_CurrentWorldGeometry2D (for 2D rendering) itkGetObjectMacro(CurrentWorldGeometry2DNode, DataNode); //##Documentation //## @brief Sets timestamp of CurrentWorldGeometry2D and DisplayGeometry and forces so reslicing in that renderwindow void SendUpdateSlice(); //##Documentation //## @brief Get timestamp of last call of SetCurrentWorldGeometry2D unsigned long GetCurrentWorldGeometry2DUpdateTime() { return m_CurrentWorldGeometry2DUpdateTime; }; //##Documentation //## @brief Get timestamp of last call of SetDisplayGeometry unsigned long GetDisplayGeometryUpdateTime() { return m_CurrentWorldGeometry2DUpdateTime; }; //##Documentation //## @brief Get timestamp of last change of current TimeStep unsigned long GetTimeStepUpdateTime() { return m_TimeStepUpdateTime; }; //##Documentation //## @brief Perform a picking: find the x,y,z world coordinate of a //## display x,y coordinate. //## @warning Has to be overwritten in subclasses for the 3D-case. //## //## Implemented here only for 2D-rendering by using //## m_DisplayGeometry virtual void PickWorldPoint(const Point2D& diplayPosition, Point3D& worldPosition) const; /** \brief Determines the object (mitk::DataNode) closest to the current * position by means of picking * * \warning Implementation currently empty for 2D rendering; intended to be * implemented for 3D renderers */ virtual DataNode* PickObject( const Point2D& /*displayPosition*/, Point3D& /*worldPosition*/ ) const { return NULL; }; //##Documentation //## @brief Get the MapperSlotId to use. itkGetMacro(MapperID, MapperSlotId); + itkGetConstMacro(MapperID, MapperSlotId); + //##Documentation //## @brief Set the MapperSlotId to use. itkSetMacro(MapperID, MapperSlotId); //##Documentation //## @brief Has the renderer the focus? itkGetMacro(Focused, bool); //##Documentation //## @brief Tell the renderer that it is focused. The caller is responsible for focus management, //## not the renderer itself. itkSetMacro(Focused, bool); //##Documentation //## @brief Sets whether depth peeling is enabled or not void SetDepthPeelingEnabled(bool enabled); //##Documentation //## @brief Sets maximal number of peels void SetMaxNumberOfPeels(int maxNumber); itkGetMacro(Size, int*); void SetSliceNavigationController(SliceNavigationController* SlicenavigationController); void SetCameraController(CameraController* cameraController); itkGetObjectMacro(CameraController, CameraController); itkGetObjectMacro(SliceNavigationController, SliceNavigationController); itkGetObjectMacro(CameraRotationController, CameraRotationController); itkGetMacro(EmptyWorldGeometry, bool); //##Documentation //## @brief Mouse event dispatchers //## @note for internal use only. preliminary. virtual void MousePressEvent(MouseEvent*); //##Documentation //## @brief Mouse event dispatchers //## @note for internal use only. preliminary. virtual void MouseReleaseEvent(MouseEvent*); //##Documentation //## @brief Mouse event dispatchers //## @note for internal use only. preliminary. virtual void MouseMoveEvent(MouseEvent*); //##Documentation //## @brief Wheel event dispatcher //## @note for internal use only. preliminary. virtual void WheelEvent(mitk::WheelEvent* we); //##Documentation //## @brief Key event dispatcher //## @note for internal use only. preliminary. virtual void KeyPressEvent(KeyEvent*); //##Documentation //## @brief get the name of the Renderer //## @note const char * GetName() const { return m_Name.c_str(); } //##Documentation //## @brief get the x_size of the RendererWindow //## @note int GetSizeX() const { return m_Size[0]; } //##Documentation //## @brief get the y_size of the RendererWindow //## @note int GetSizeY() const { return m_Size[1]; } const double* GetBounds() const; void RequestUpdate(); void ForceImmediateUpdate(); /** Returns number of mappers which are visible and have level-of-detail * rendering enabled */ unsigned int GetNumberOfVisibleLODEnabledMappers() const; ///** //* \brief Setter for the RenderingManager that handles this instance of BaseRenderer //*/ //void SetRenderingManager( mitk::RenderingManager* ); /** * \brief Getter for the RenderingManager that handles this instance of BaseRenderer */ virtual mitk::RenderingManager* GetRenderingManager() const; protected: virtual ~BaseRenderer(); //##Documentation //## @brief Call update of all mappers. To be implemented in subclasses. virtual void Update() = 0; vtkRenderWindow* m_RenderWindow; vtkRenderer* m_VtkRenderer; //##Documentation //## @brief MapperSlotId to use. Defines which kind of mapper (e.g., 2D or 3D) shoud be used. MapperSlotId m_MapperID; //##Documentation //## @brief The DataStorage that is used for rendering. DataStorage::Pointer m_DataStorage; //##Documentation //## @brief The RenderingManager that manages this instance RenderingManager::Pointer m_RenderingManager; //##Documentation //## @brief Timestamp of last call of Update(). unsigned long m_LastUpdateTime; //##Documentation //## @brief CameraController for 3D rendering //## @note preliminary. CameraController::Pointer m_CameraController; SliceNavigationController::Pointer m_SliceNavigationController; CameraRotationController::Pointer m_CameraRotationController; //##Documentation //## @brief Size of the RenderWindow. int m_Size[2]; //##Documentation //## @brief Contains whether the renderer that it is focused. The caller of //## SetFocused is responsible for focus management, not the renderer itself. //## is doubled because of mitk::FocusManager in GlobalInteraction!!! (ingmar) bool m_Focused; //##Documentation //## @brief Sets m_CurrentWorldGeometry2D virtual void SetCurrentWorldGeometry2D(Geometry2D* geometry2d); //##Documentation //## @brief Sets m_CurrentWorldGeometry virtual void SetCurrentWorldGeometry(Geometry3D* geometry); private: //##Documentation //## Pointer to the worldgeometry, describing the maximal area to be rendered //## (3D as well as 2D). //## It is const, since we are not allowed to change it (it may be taken //## directly from the geometry of an image-slice and thus it would be //## very strange when suddenly the image-slice changes its geometry). //## \sa SetWorldGeometry Geometry3D::Pointer m_WorldGeometry; //##Documentation //## m_TimeSlicedWorldGeometry is set by SetWorldGeometry if the passed Geometry3D is a //## TimeSlicedGeometry (or a sub-class of it). If it contains instances of SlicedGeometry3D, //## m_Slice and m_TimeStep (set via SetSlice and SetTimeStep, respectively) define //## which 2D geometry stored in m_TimeSlicedWorldGeometry (if available) //## is used as m_CurrentWorldGeometry2D. //## \sa m_CurrentWorldGeometry2D TimeSlicedGeometry::Pointer m_TimeSlicedWorldGeometry; //##Documentation //## Pointer to the current 3D-worldgeometry. Geometry3D::Pointer m_CurrentWorldGeometry; //##Documentation //## Pointer to the current 2D-worldgeometry. The 2D-worldgeometry //## describes the maximal area (2D manifold) to be rendered in case we //## are doing 2D-rendering. More precisely, a subpart of this according //## to m_DisplayGeometry is displayed. //## It is const, since we are not allowed to change it (it may be taken //## directly from the geometry of an image-slice and thus it would be //## very strange when suddenly the image-slice changes its geometry). Geometry2D::Pointer m_CurrentWorldGeometry2D; //##Documentation //## Pointer to the displaygeometry. The displaygeometry describes the //## geometry of the \em visible area in the window controlled by the renderer //## in case we are doing 2D-rendering. //## It is const, since we are not allowed to change it. DisplayGeometry::Pointer m_DisplayGeometry; //##Documentation //## Defines together with m_Slice which 2D geometry stored in m_TimeSlicedWorldGeometry //## is used as m_CurrentWorldGeometry2D: m_TimeSlicedWorldGeometry->GetGeometry2D(m_Slice, m_TimeStep). //## \sa m_TimeSlicedWorldGeometry unsigned int m_Slice; //##Documentation //## Defines together with m_TimeStep which 2D geometry stored in m_TimeSlicedWorldGeometry //## is used as m_CurrentWorldGeometry2D: m_TimeSlicedWorldGeometry->GetGeometry2D(m_Slice, m_TimeStep). //## \sa m_TimeSlicedWorldGeometry unsigned int m_TimeStep; //##Documentation //## @brief timestamp of last call of SetWorldGeometry itk::TimeStamp m_CurrentWorldGeometry2DUpdateTime; //##Documentation //## @brief timestamp of last call of SetDisplayGeometry itk::TimeStamp m_DisplayGeometryUpdateTime; //##Documentation //## @brief timestamp of last change of the current time step itk::TimeStamp m_TimeStepUpdateTime; protected: virtual void PrintSelf(std::ostream& os, itk::Indent indent) const; //##Documentation //## Data object containing the m_WorldGeometry defined above. Geometry2DData::Pointer m_WorldGeometryData; //##Documentation //## Data object containing the m_DisplayGeometry defined above. Geometry2DData::Pointer m_DisplayGeometryData; //##Documentation //## Data object containing the m_CurrentWorldGeometry2D defined above. Geometry2DData::Pointer m_CurrentWorldGeometry2DData; //##Documentation //## DataNode objects containing the m_WorldGeometryData defined above. DataNode::Pointer m_WorldGeometryNode; //##Documentation //## DataNode objects containing the m_DisplayGeometryData defined above. DataNode::Pointer m_DisplayGeometryNode; //##Documentation //## DataNode objects containing the m_CurrentWorldGeometry2DData defined above. DataNode::Pointer m_CurrentWorldGeometry2DNode; //##Documentation //## @brief test only unsigned long m_DisplayGeometryTransformTime; //##Documentation //## @brief test only unsigned long m_CurrentWorldGeometry2DTransformTime; std::string m_Name; double m_Bounds[6]; bool m_EmptyWorldGeometry; bool m_DepthPeelingEnabled; int m_MaxNumberOfPeels; typedef std::set< Mapper * > LODEnabledMappersType; /** Number of mappers which are visible and have level-of-detail * rendering enabled */ unsigned int m_NumberOfVisibleLODEnabledMappers; // Local Storage Handling for mappers protected: std::list m_RegisteredLocalStorageHandlers; public: void RemoveAllLocalStorages(); void RegisterLocalStorageHandler( mitk::BaseLocalStorageHandler *lsh ); void UnregisterLocalStorageHandler( mitk::BaseLocalStorageHandler *lsh ); }; } // namespace mitk #endif /* BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 */ diff --git a/Core/Code/Rendering/mitkGeometry2DDataMapper2D.cpp b/Core/Code/Rendering/mitkGeometry2DDataMapper2D.cpp index 039d8395e6..e6de21c3fc 100644 --- a/Core/Code/Rendering/mitkGeometry2DDataMapper2D.cpp +++ b/Core/Code/Rendering/mitkGeometry2DDataMapper2D.cpp @@ -1,449 +1,452 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkGL.h" #include "mitkGeometry2DDataMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkPlaneGeometry.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkSmartPointerProperty.h" #include "mitkPlaneOrientationProperty.h" #include "mitkGeometry2DDataToSurfaceFilter.h" #include "mitkSurfaceGLMapper2D.h" #include "mitkLine.h" #include "mitkNodePredicateDataType.h" mitk::Geometry2DDataMapper2D::Geometry2DDataMapper2D() : m_SurfaceMapper( NULL ), m_DataStorage(NULL), m_ParentNode(NULL), m_OtherGeometry2Ds(), m_RenderOrientationArrows( false ), m_ArrowOrientationPositive( true ) { } mitk::Geometry2DDataMapper2D::~Geometry2DDataMapper2D() { } const mitk::Geometry2DData* mitk::Geometry2DDataMapper2D::GetInput(void) { return static_cast ( GetData() ); } void mitk::Geometry2DDataMapper2D::GenerateData() { // collect all Geometry2DDatas accessible from the DataStorage m_OtherGeometry2Ds.clear(); if (m_DataStorage.IsNull()) return; mitk::NodePredicateDataType::Pointer p = mitk::NodePredicateDataType::New("Geometry2DData"); mitk::DataStorage::SetOfObjects::ConstPointer all = m_DataStorage->GetDerivations(m_ParentNode, p, false); for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { if(it->Value().IsNull()) continue; BaseData* data = it->Value()->GetData(); if (data == NULL) continue; Geometry2DData* geometry2dData = dynamic_cast(data); if(geometry2dData == NULL) continue; PlaneGeometry* planegeometry = dynamic_cast(geometry2dData->GetGeometry2D()); if (planegeometry != NULL) m_OtherGeometry2Ds.push_back(it->Value()); } } void mitk::Geometry2DDataMapper2D::Paint(BaseRenderer *renderer) { if ( !this->IsVisible(renderer) ) { return; } Geometry2DData::Pointer input = const_cast< Geometry2DData * >(this->GetInput()); // intersecting with ourself? if ( input.IsNull() || (this->GetInput()->GetGeometry2D() == renderer->GetCurrentWorldGeometry2D()) ) { return; // do nothing! } const PlaneGeometry *inputPlaneGeometry = dynamic_cast< const PlaneGeometry * >( input->GetGeometry2D() ); const PlaneGeometry *worldPlaneGeometry = dynamic_cast< const PlaneGeometry* >( renderer->GetCurrentWorldGeometry2D() ); if ( worldPlaneGeometry && inputPlaneGeometry && inputPlaneGeometry->GetReferenceGeometry() ) { DisplayGeometry *displayGeometry = renderer->GetDisplayGeometry(); assert( displayGeometry ); const Geometry3D *referenceGeometry = inputPlaneGeometry->GetReferenceGeometry(); // calculate intersection of the plane data with the border of the // world geometry rectangle Point2D lineFrom, lineTo; typedef Geometry3D::TransformType TransformType; const TransformType *transform = dynamic_cast< const TransformType * >( referenceGeometry->GetIndexToWorldTransform() ); TransformType::Pointer inverseTransform = TransformType::New(); transform->GetInverse( inverseTransform ); Line3D crossLine, otherCrossLine; // Calculate the intersection line of the input plane with the world plane if ( worldPlaneGeometry->IntersectionLine( inputPlaneGeometry, crossLine ) ) { BoundingBox::PointType boundingBoxMin, boundingBoxMax; boundingBoxMin = referenceGeometry->GetBoundingBox()->GetMinimum(); boundingBoxMax = referenceGeometry->GetBoundingBox()->GetMaximum(); if(referenceGeometry->GetImageGeometry()) { for(unsigned int i = 0; i < 3; ++i) { boundingBoxMin[i]-=0.5; boundingBoxMax[i]-=0.5; } } crossLine.Transform( *inverseTransform ); Point3D point1, point2; // Then, clip this line with the (transformed) bounding box of the // reference geometry. if ( crossLine.BoxLineIntersection( boundingBoxMin[0], boundingBoxMin[1], boundingBoxMin[2], boundingBoxMax[0], boundingBoxMax[1], boundingBoxMax[2], crossLine.GetPoint(), crossLine.GetDirection(), point1, point2 ) == 2 ) { // Transform the resulting line start and end points into display // coordinates. worldPlaneGeometry->Map( transform->TransformPoint( point1 ), lineFrom ); worldPlaneGeometry->Map( transform->TransformPoint( point2 ), lineTo ); Line< ScalarType, 2 > line, otherLine; line.SetPoints( lineFrom, lineTo ); displayGeometry->WorldToDisplay( lineFrom, lineFrom ); displayGeometry->WorldToDisplay( lineTo, lineTo ); ScalarType lengthInDisplayUnits = (lineTo - lineFrom).GetNorm(); // lineParams stores the individual segments of the line, which are // separated by a gap each (to mark the intersection with another // displayed line) std::vector< ScalarType > lineParams; lineParams.reserve( m_OtherGeometry2Ds.size() + 2 ); lineParams.push_back( 0.0 ); lineParams.push_back( 1.0 ); Vector2D d, dOrth; // Now iterate through all other lines displayed in this window and // calculate the positions of intersection with the line to be // rendered; these positions will be stored in lineParams to form a // gap afterwards. NodesVectorType::iterator otherPlanesIt = m_OtherGeometry2Ds.begin(); NodesVectorType::iterator otherPlanesEnd = m_OtherGeometry2Ds.end(); while ( otherPlanesIt != otherPlanesEnd ) { PlaneGeometry *otherPlane = static_cast< PlaneGeometry * >( static_cast< Geometry2DData * >( (*otherPlanesIt)->GetData() )->GetGeometry2D() ); // Just as with the original line, calculate the intersaction with // the world geometry... if ( (otherPlane != inputPlaneGeometry) && worldPlaneGeometry->IntersectionLine( otherPlane, otherCrossLine ) ) { // ... and clip the resulting line segment with the reference // geometry bounding box. otherCrossLine.Transform( *inverseTransform ); if ( otherCrossLine.BoxLineIntersection( boundingBoxMin[0], boundingBoxMin[1], boundingBoxMin[2], boundingBoxMax[0], boundingBoxMax[1], boundingBoxMax[2], otherCrossLine.GetPoint(), otherCrossLine.GetDirection(), point1, point2 ) == 2 ) { worldPlaneGeometry->Map( transform->TransformPoint( point1 ), lineFrom ); worldPlaneGeometry->Map( transform->TransformPoint( point2 ), lineTo ); // By means of the dot product, calculate the gap position as // parametric value in the range [0, 1] otherLine.SetPoints( lineFrom, lineTo ); d = otherLine.GetDirection(); dOrth[0] = -d[1]; dOrth[1] = d[0]; ScalarType t, norm; t = ( otherLine.GetPoint1() - line.GetPoint1() ) * dOrth; norm = line.GetDirection() * dOrth; if ( fabs( norm ) > eps ) { t /= norm; if ( (t > 0.0) && (t < 1.0) ) { lineParams.push_back(t); } } } } ++otherPlanesIt; } // Apply color and opacity read from the PropertyList. this->ApplyProperties( renderer ); ScalarType gapSizeInPixel = 10.0; ScalarType gapSizeInParamUnits = 1.0 / lengthInDisplayUnits * gapSizeInPixel; std::sort( lineParams.begin(), lineParams.end() ); Point2D p1, p2; ScalarType p1Param, p2Param; p1Param = lineParams[0]; p1 = line.GetPoint( p1Param ); displayGeometry->WorldToDisplay( p1, p1 ); + //Work arround to show the crosshair always on top of a 2D render window + //The image is usually located at depth = 0 or negative depth values, and thus, + //the crosshair with depth = 1 is always on top. float depthPosition = 1.0f; // Iterate over all line segments and display each, with a gap // inbetween. unsigned int i, preLastLineParam = lineParams.size() - 1; for ( i = 1; i < preLastLineParam; ++i ) { p2Param = lineParams[i] - gapSizeInParamUnits * 0.5; p2 = line.GetPoint( p2Param ); if ( p2Param > p1Param ) { // Convert intersection points (until now mm) to display // coordinates (units). displayGeometry->WorldToDisplay( p2, p2 ); // draw glEnable(GL_DEPTH_TEST); glBegin (GL_LINES); glVertex3f(p1[0],p1[1], depthPosition); glVertex3f(p2[0],p2[1], depthPosition); glEnd (); if ( (i == 1) && (m_RenderOrientationArrows) ) { // Draw orientation arrow for first line segment this->DrawOrientationArrow( p1, p2, inputPlaneGeometry, worldPlaneGeometry, displayGeometry, m_ArrowOrientationPositive ); } } p1Param = p2Param + gapSizeInParamUnits; p1 = line.GetPoint( p1Param ); displayGeometry->WorldToDisplay( p1, p1 ); } // Draw last line segment p2Param = lineParams[i]; p2 = line.GetPoint( p2Param ); displayGeometry->WorldToDisplay( p2, p2 ); glBegin( GL_LINES ); glVertex3f( p1[0], p1[1], depthPosition); glVertex3f( p2[0], p2[1], depthPosition); glEnd(); // Draw orientation arrows if ( m_RenderOrientationArrows ) { this->DrawOrientationArrow( p2, p1, inputPlaneGeometry, worldPlaneGeometry, displayGeometry, m_ArrowOrientationPositive ); if ( preLastLineParam < 2 ) { // If we only have one line segment, draw other arrow, too this->DrawOrientationArrow( p1, p2, inputPlaneGeometry, worldPlaneGeometry, displayGeometry, m_ArrowOrientationPositive ); } } } } } else { Geometry2DDataToSurfaceFilter::Pointer surfaceCreator; SmartPointerProperty::Pointer surfacecreatorprop; surfacecreatorprop = dynamic_cast< SmartPointerProperty * >( GetDataNode()->GetProperty( "surfacegeometry", renderer)); if( (surfacecreatorprop.IsNull()) || (surfacecreatorprop->GetSmartPointer().IsNull()) || ((surfaceCreator = dynamic_cast< Geometry2DDataToSurfaceFilter * >( surfacecreatorprop->GetSmartPointer().GetPointer())).IsNull()) ) { surfaceCreator = Geometry2DDataToSurfaceFilter::New(); surfacecreatorprop = SmartPointerProperty::New(surfaceCreator); surfaceCreator->PlaceByGeometryOn(); GetDataNode()->SetProperty( "surfacegeometry", surfacecreatorprop ); } surfaceCreator->SetInput( input ); // Clip the Geometry2D with the reference geometry bounds (if available) if ( input->GetGeometry2D()->HasReferenceGeometry() ) { surfaceCreator->SetBoundingBox( input->GetGeometry2D()->GetReferenceGeometry()->GetBoundingBox() ); } int res; bool usegeometryparametricbounds = true; if ( GetDataNode()->GetIntProperty("xresolution", res, renderer)) { surfaceCreator->SetXResolution(res); usegeometryparametricbounds=false; } if (GetDataNode()->GetIntProperty("yresolution", res, renderer)) { surfaceCreator->SetYResolution(res); usegeometryparametricbounds=false; } surfaceCreator->SetUseGeometryParametricBounds(usegeometryparametricbounds); // Calculate the surface of the Geometry2D surfaceCreator->Update(); if (m_SurfaceMapper.IsNull()) { m_SurfaceMapper=SurfaceGLMapper2D::New(); } m_SurfaceMapper->SetSurface(surfaceCreator->GetOutput()); m_SurfaceMapper->SetDataNode(GetDataNode()); m_SurfaceMapper->Paint(renderer); } } void mitk::Geometry2DDataMapper2D::DrawOrientationArrow( mitk::Point2D &outerPoint, mitk::Point2D &innerPoint, const mitk::PlaneGeometry *planeGeometry, const mitk::PlaneGeometry *rendererPlaneGeometry, const mitk::DisplayGeometry *displayGeometry, bool positiveOrientation ) { // Draw arrows to indicate plane orientation // Vector along line Vector2D v1 = innerPoint - outerPoint; v1.Normalize(); v1 *= 7.0; // Orthogonal vector Vector2D v2; v2[0] = v1[1]; v2[1] = -v1[0]; // Calculate triangle tip for one side and project it back into world // coordinates to determine whether it is above or below the plane Point2D worldPoint2D; Point3D worldPoint; displayGeometry->DisplayToWorld( outerPoint + v1 + v2, worldPoint2D ); rendererPlaneGeometry->Map( worldPoint2D, worldPoint ); // Initialize remaining triangle coordinates accordingly // (above/below state is XOR'ed with orientation flag) Point2D p1 = outerPoint + v1 * 2.0; Point2D p2 = outerPoint + v1 + ((positiveOrientation ^ planeGeometry->IsAbove( worldPoint )) ? v2 : -v2); // Draw the arrow (triangle) glBegin( GL_TRIANGLES ); glVertex2f( outerPoint[0], outerPoint[1] ); glVertex2f( p1[0], p1[1] ); glVertex2f( p2[0], p2[1] ); glEnd(); } void mitk::Geometry2DDataMapper2D::ApplyProperties( BaseRenderer *renderer ) { Superclass::ApplyProperties(renderer); PlaneOrientationProperty* decorationProperty; this->GetDataNode()->GetProperty( decorationProperty, "decoration", renderer ); if ( decorationProperty != NULL ) { if ( decorationProperty->GetPlaneDecoration() == PlaneOrientationProperty::PLANE_DECORATION_POSITIVE_ORIENTATION ) { m_RenderOrientationArrows = true; m_ArrowOrientationPositive = true; } else if ( decorationProperty->GetPlaneDecoration() == PlaneOrientationProperty::PLANE_DECORATION_NEGATIVE_ORIENTATION ) { m_RenderOrientationArrows = true; m_ArrowOrientationPositive = false; } else { m_RenderOrientationArrows = false; } } } void mitk::Geometry2DDataMapper2D::SetDatastorageAndGeometryBaseNode( mitk::DataStorage::Pointer ds, mitk::DataNode::Pointer parent ) { if (ds.IsNotNull()) { m_DataStorage = ds; } if (parent.IsNotNull()) { m_ParentNode = parent; } } diff --git a/Core/Code/Rendering/mitkImageVtkMapper2D.cpp b/Core/Code/Rendering/mitkImageVtkMapper2D.cpp index d4b863765d..a2e2bcada2 100644 --- a/Core/Code/Rendering/mitkImageVtkMapper2D.cpp +++ b/Core/Code/Rendering/mitkImageVtkMapper2D.cpp @@ -1,1061 +1,1081 @@ /*========================================================================= Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ //MITK #include #include #include #include #include #include #include #include #include #include #include #include //MITK Rendering #include "mitkImageVtkMapper2D.h" #include "vtkMitkThickSlicesFilter.h" #include "vtkMitkApplyLevelWindowToRGBFilter.h" //VTK #include #include #include #include #include #include #include #include #include #include #include #include #include -#include -#include - +#include //ITK #include mitk::ImageVtkMapper2D::ImageVtkMapper2D() { } mitk::ImageVtkMapper2D::~ImageVtkMapper2D() { - // this->InvokeEvent( itk::DeleteEvent() ); //TODO <- what is this doing exactly? + //The 3D RW Mapper (Geometry2DDataVtkMapper3D) is listening to this event, + //in order to delete the images from the 3D RW. + this->InvokeEvent( itk::DeleteEvent() ); } //set the two points defining the textured plane according to the dimension and spacing void mitk::ImageVtkMapper2D::GeneratePlane(mitk::BaseRenderer* renderer, vtkFloatingPointType planeBounds[6]) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); - //Set the origin to (xMin; yMin; 0) of the plane. This is necessary for obtaining the correct + //Set the origin to (xMin; yMin; depth) of the plane. This is necessary for obtaining the correct //plane size in crosshair rotation and swivel mode. - float depthOffset = 0.0; - GetDataNode()->GetFloatProperty( "depthOffset", depthOffset, renderer ); - depthOffset *= -1.0; - localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depthOffset); + float depth = this->CalculateLayerDepth(renderer); + + localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depth); //These two points define the axes of the plane in combination with the origin. //Point 1 is the x-axis and point 2 the y-axis. //Each plane is transformed according to the view (transversal, coronal and saggital) afterwards. - localStorage->m_Plane->SetPoint1(planeBounds[1], planeBounds[2], depthOffset); //P1: (xMax, yMin, 0) - localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depthOffset); //P2: (xMin, yMax, 0) + localStorage->m_Plane->SetPoint1(planeBounds[1], planeBounds[2], depth); //P1: (xMax, yMin, depth) + localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depth); //P2: (xMin, yMax, depth) +} +float mitk::ImageVtkMapper2D::CalculateLayerDepth(mitk::BaseRenderer* renderer) +{ + //get the clipping range to check how deep into z direction we can render images + double maxRange = renderer->GetVtkRenderer()->GetActiveCamera()->GetClippingRange()[1]; + + //Due to a VTK bug, we cannot use the whole clipping range. /100 is empirically determined + float depth = -maxRange*0.01; // divide by 100 + int layer = 0; + GetDataNode()->GetIntProperty( "layer", layer, renderer); + //add the layer property for each image to render images with a higher layer on top of the others + depth += layer*10; //*10: keep some room for each image (e.g. for QBalls in between) + if(depth > 0.0f) { + depth = 0.0f; + MITK_WARN << "Layer value exceeds clipping range. Set to minimum instead."; + } + return depth; } const mitk::Image* mitk::ImageVtkMapper2D::GetInput( void ) { return static_cast< const mitk::Image * >( this->GetData() ); } vtkProp* mitk::ImageVtkMapper2D::GetVtkProp(mitk::BaseRenderer* renderer) -{ - this->Update(renderer); +{ +// this->Update(renderer); //return the actor corresponding to the renderer return m_LSH.GetLocalStorage(renderer)->m_Actor; } void mitk::ImageVtkMapper2D::MitkRenderOverlay(BaseRenderer* renderer) { if ( this->IsVisible(renderer)==false ) return; - if ( this->GetVtkProp(renderer)->GetVisibility() ) { this->GetVtkProp(renderer)->RenderOverlay(renderer->GetVtkRenderer()); } } void mitk::ImageVtkMapper2D::MitkRenderOpaqueGeometry(BaseRenderer* renderer) { if ( this->IsVisible( renderer )==false ) return; - if ( this->GetVtkProp(renderer)->GetVisibility() ) { this->GetVtkProp(renderer)->RenderOpaqueGeometry( renderer->GetVtkRenderer() ); } } void mitk::ImageVtkMapper2D::MitkRenderTranslucentGeometry(BaseRenderer* renderer) { if ( this->IsVisible(renderer)==false ) return; - - //TODO is it possible to have a visible BaseRenderer AND an invisible VtkRenderer??? if ( this->GetVtkProp(renderer)->GetVisibility() ) { this->GetVtkProp(renderer)->RenderTranslucentPolygonalGeometry(renderer->GetVtkRenderer()); } } void mitk::ImageVtkMapper2D::MitkRenderVolumetricGeometry(BaseRenderer* renderer) { if(IsVisible(renderer)==false) return; - if ( GetVtkProp(renderer)->GetVisibility() ) + { this->GetVtkProp(renderer)->RenderVolumetricGeometry(renderer->GetVtkRenderer()); + } } void mitk::ImageVtkMapper2D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); - mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); //TODO WTF CONST CAST?!?!?111 => Error in class design? + mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); if ( input == NULL ) { return; } - //check if there is a valid worldGeometry TODO: Move to Update()? + //check if there is a valid worldGeometry const Geometry2D *worldGeometry = renderer->GetCurrentWorldGeometry2D(); if( ( worldGeometry == NULL ) || ( !worldGeometry->IsValid() ) || ( !worldGeometry->HasReferenceGeometry() )) { return; } - // check if there is something to display. TODO: Move to Update()? + // check if there is something to display if ( !input->IsVolumeSet( this->GetTimestep() ) ) return; input->Update(); vtkImageData* inputData = input->GetVtkImageData( this->GetTimestep() ); if ( inputData == NULL ) { return; } // how big the area is in physical coordinates: widthInMM x heightInMM pixels mitk::ScalarType widthInMM, heightInMM; // where we want to sample Point3D origin; Vector3D right, bottom, normal; // take transform of input image into account const TimeSlicedGeometry *inputTimeGeometry = input->GetTimeSlicedGeometry(); const Geometry3D* inputGeometry = inputTimeGeometry->GetGeometry3D( this->GetTimestep() ); //World spacing ScalarType mmPerPixel[2]; // Bounds information for reslicing (only reuqired if reference geometry // is present) vtkFloatingPointType sliceBounds[6]; bool boundsInitialized = false; for ( int i = 0; i < 6; ++i ) { sliceBounds[i] = 0.0; } //Extent (in pixels) of the image Vector2D extent; // Do we have a simple PlaneGeometry? // This is the "regular" case (e.g. slicing through an image axis-parallel or even oblique) const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( worldGeometry ); if ( planeGeometry != NULL ) { origin = planeGeometry->GetOrigin(); right = planeGeometry->GetAxisVector( 0 ); // right = Extent of Image in mm (worldspace) bottom = planeGeometry->GetAxisVector( 1 ); normal = planeGeometry->GetNormal(); bool inPlaneResampleExtentByGeometry = false; GetDataNode()->GetBoolProperty("in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer); if ( inPlaneResampleExtentByGeometry ) { // Resampling grid corresponds to the current world geometry. This // means that the spacing of the output 2D image depends on the // currently selected world geometry, and *not* on the image itself. extent[0] = worldGeometry->GetExtent( 0 ); extent[1] = worldGeometry->GetExtent( 1 ); } else { // Resampling grid corresponds to the input geometry. This means that // the spacing of the output 2D image is directly derived from the // associated input image, regardless of the currently selected world // geometry. - //TODO use new method instead of deprecated Vector3D rightInIndex, bottomInIndex; - inputGeometry->WorldToIndex( origin, right, rightInIndex ); - inputGeometry->WorldToIndex( origin, bottom, bottomInIndex ); + inputGeometry->WorldToIndex( right, rightInIndex ); + inputGeometry->WorldToIndex( bottom, bottomInIndex ); extent[0] = rightInIndex.GetNorm(); extent[1] = bottomInIndex.GetNorm(); } // Get the extent of the current world geometry and calculate resampling // spacing therefrom. widthInMM = worldGeometry->GetExtentInMM( 0 ); heightInMM = worldGeometry->GetExtentInMM( 1 ); mmPerPixel[0] = widthInMM / extent[0]; mmPerPixel[1] = heightInMM / extent[1]; right.Normalize(); bottom.Normalize(); normal.Normalize(); //transform the origin to corner based coordinates, because VTK is corner based. origin += right * ( mmPerPixel[0] * 0.5 ); origin += bottom * ( mmPerPixel[1] * 0.5 ); // Use inverse transform of the input geometry for reslicing the 3D image localStorage->m_Reslicer->SetResliceTransform( inputGeometry->GetVtkTransform()->GetLinearInverse() ); // Set background level to TRANSLUCENT (see Geometry2DDataVtkMapper3D) - localStorage->m_Reslicer->SetBackgroundLevel( -32768 ); //TODO why -32768 and not 0.0??? + localStorage->m_Reslicer->SetBackgroundLevel( -32768 ); // Calculate the actual bounds of the transformed plane clipped by the // dataset bounding box; this is required for drawing the texture at the // correct position during 3D mapping. boundsInitialized = this->CalculateClippedPlaneBounds( - worldGeometry->GetReferenceGeometry(), planeGeometry, sliceBounds ); //TODO braucht man nicht immer + worldGeometry->GetReferenceGeometry(), planeGeometry, sliceBounds ); } else { // Do we have an AbstractTransformGeometry? // This is the case for AbstractTransformGeometry's (e.g. a thin-plate-spline transform) const mitk::AbstractTransformGeometry* abstractGeometry = dynamic_cast< const AbstractTransformGeometry * >(worldGeometry); if(abstractGeometry != NULL) { extent[0] = abstractGeometry->GetParametricExtent(0); extent[1] = abstractGeometry->GetParametricExtent(1); widthInMM = abstractGeometry->GetParametricExtentInMM(0); heightInMM = abstractGeometry->GetParametricExtentInMM(1); mmPerPixel[0] = widthInMM / extent[0]; mmPerPixel[1] = heightInMM / extent[1]; origin = abstractGeometry->GetPlane()->GetOrigin(); right = abstractGeometry->GetPlane()->GetAxisVector(0); right.Normalize(); bottom = abstractGeometry->GetPlane()->GetAxisVector(1); bottom.Normalize(); normal = abstractGeometry->GetPlane()->GetNormal(); normal.Normalize(); // Use a combination of the InputGeometry *and* the possible non-rigid // AbstractTransformGeometry for reslicing the 3D Image vtkGeneralTransform *composedResliceTransform = vtkGeneralTransform::New(); composedResliceTransform->Identity(); composedResliceTransform->Concatenate( inputGeometry->GetVtkTransform()->GetLinearInverse() ); composedResliceTransform->Concatenate( abstractGeometry->GetVtkAbstractTransform() ); localStorage->m_Reslicer->SetResliceTransform( composedResliceTransform ); composedResliceTransform->UnRegister( NULL ); // decrease RC // Set background level to BLACK instead of translucent, to avoid // boundary artifacts (see Geometry2DDataVtkMapper3D) localStorage->m_Reslicer->SetBackgroundLevel( -1023 ); } else { //no geometry => we can't reslice return; } } // Make sure that the image to display has a certain minimum size. if ( (extent[0] <= 2) && (extent[1] <= 2) ) { return; } //### begin set reslice interpolation // Initialize the interpolation mode for resampling; switch to nearest // neighbor if the input image is too small. if ( (input->GetDimension() >= 3) && (input->GetDimension(2) > 1) ) { VtkResliceInterpolationProperty *resliceInterpolationProperty; this->GetDataNode()->GetProperty( resliceInterpolationProperty, "reslice interpolation" ); int interpolationMode = VTK_RESLICE_NEAREST; if ( resliceInterpolationProperty != NULL ) { interpolationMode = resliceInterpolationProperty->GetInterpolation(); } switch ( interpolationMode ) { case VTK_RESLICE_NEAREST: localStorage->m_Reslicer->SetInterpolationModeToNearestNeighbor(); break; case VTK_RESLICE_LINEAR: localStorage->m_Reslicer->SetInterpolationModeToLinear(); break; case VTK_RESLICE_CUBIC: localStorage->m_Reslicer->SetInterpolationModeToCubic(); break; } } else { localStorage->m_Reslicer->SetInterpolationModeToNearestNeighbor(); } //### end set reslice interpolation //Thickslicing int thickSlicesMode = 0; int thickSlicesNum = 1; // Thick slices parameters if( inputData->GetNumberOfScalarComponents() == 1 ) // for now only single component are allowed { DataNode *dn=renderer->GetCurrentWorldGeometry2DNode(); if(dn) { ResliceMethodProperty *resliceMethodEnumProperty=0; if( dn->GetProperty( resliceMethodEnumProperty, "reslice.thickslices" ) && resliceMethodEnumProperty ) thickSlicesMode = resliceMethodEnumProperty->GetValueAsId(); IntProperty *intProperty=0; if( dn->GetProperty( intProperty, "reslice.thickslices.num" ) && intProperty ) { thickSlicesNum = intProperty->GetValue(); if(thickSlicesNum < 1) thickSlicesNum=1; if(thickSlicesNum > 10) thickSlicesNum=10; } } else { MITK_WARN << "no associated widget plane data tree node found"; } } localStorage->m_UnitSpacingImageFilter->SetInput( inputData ); localStorage->m_Reslicer->SetInput( localStorage->m_UnitSpacingImageFilter->GetOutput() ); //number of pixels per mm in x- and y-direction of the resampled Vector2D pixelsPerMM; pixelsPerMM[0] = 1.0 / mmPerPixel[0]; pixelsPerMM[1] = 1.0 / mmPerPixel[1]; //calulate the originArray and the orientations for the reslice-filter double originArray[3]; itk2vtk( origin, originArray ); localStorage->m_Reslicer->SetResliceAxesOrigin( originArray ); double cosines[9]; // direction of the X-axis of the sampled result vnl2vtk( right.Get_vnl_vector(), cosines ); // direction of the Y-axis of the sampled result vnl2vtk( bottom.Get_vnl_vector(), cosines + 3 );//fill next 3 elements // normal of the plane vnl2vtk( normal.Get_vnl_vector(), cosines + 6 );//fill the last 3 elements localStorage->m_Reslicer->SetResliceAxesDirectionCosines( cosines ); int xMin, xMax, yMin, yMax; if ( boundsInitialized ) { // Calculate output extent (integer values) xMin = static_cast< int >( sliceBounds[0] / mmPerPixel[0] + 0.5 ); xMax = static_cast< int >( sliceBounds[1] / mmPerPixel[0] + 0.5 ); yMin = static_cast< int >( sliceBounds[2] / mmPerPixel[1] + 0.5 ); yMax = static_cast< int >( sliceBounds[3] / mmPerPixel[1] + 0.5 ); } else { // If no reference geometry is available, we also don't know about the // maximum plane size; xMin = yMin = 0; xMax = static_cast< int >( extent[0] - pixelsPerMM[0] + 0.5); yMax = static_cast< int >( extent[1] - pixelsPerMM[1] + 0.5); } // Disallow huge dimensions if ( (xMax-xMin) * (yMax-yMin) > 4096*4096 ) { return; } // Calculate dataset spacing in plane z direction (NOT spacing of current // world geometry) double dataZSpacing = 1.0; Vector3D normInIndex; - inputGeometry->WorldToIndex( origin, normal, normInIndex ); + inputGeometry->WorldToIndex( normal, normInIndex ); if(thickSlicesMode > 0) { dataZSpacing = 1.0 / normInIndex.GetNorm(); localStorage->m_Reslicer->SetOutputDimensionality( 3 ); localStorage->m_Reslicer->SetOutputExtent( xMin, xMax-1, yMin, yMax-1, -thickSlicesNum, 0+thickSlicesNum ); } else { localStorage->m_Reslicer->SetOutputDimensionality( 2 ); localStorage->m_Reslicer->SetOutputExtent( xMin, xMax-1, yMin, yMax-1, 0, 0 ); } localStorage->m_Reslicer->SetOutputOrigin( 0.0, 0.0, 0.0 ); localStorage->m_Reslicer->SetOutputSpacing( mmPerPixel[0], mmPerPixel[1], dataZSpacing ); // xMax and yMax are meant exclusive until now, whereas // SetOutputExtent wants an inclusive bound. Thus, we need // to subtract 1. vtkImageData* reslicedImage = 0; // Do the reslicing. Modified() is called to make sure that the reslicer is // executed even though the input geometry information did not change; this // is necessary when the input /em data, but not the /em geometry changes. if(thickSlicesMode>0) { localStorage->m_TSFilter->SetThickSliceMode( thickSlicesMode-1 ); localStorage->m_TSFilter->SetInput( localStorage->m_Reslicer->GetOutput() ); localStorage->m_TSFilter->Modified(); localStorage->m_TSFilter->Update(); reslicedImage = localStorage->m_TSFilter->GetOutput(); } else { localStorage->m_Reslicer->Modified(); localStorage->m_Reslicer->Update(); reslicedImage = localStorage->m_Reslicer->GetOutput(); } if((reslicedImage == NULL) || (reslicedImage->GetDataDimension() < 1)) { MITK_WARN << "reslicer returned empty image"; return; } - //set the current slice for the localStorage //TODO pass the actor to the 3D mapper + //set the current slice for the localStorage +// localStorage->m_ReslicedImage = reslicedImage; localStorage->m_ReslicedImage->DeepCopy( reslicedImage ); //set the current slice as texture for the plane localStorage->m_Texture->SetInput(localStorage->m_ReslicedImage); //setup the textured plane this->GeneratePlane( renderer, sliceBounds ); //apply the properties after the slice was set this->ApplyProperties( renderer, mmPerPixel ); //get the transformation matrix of the reslicer in order to render the slice as transversal, coronal or saggital vtkSmartPointer trans = vtkSmartPointer::New(); - vtkSmartPointer matrix = vtkSmartPointer::New(); - matrix = localStorage->m_Reslicer->GetResliceAxes(); + vtkSmartPointer matrix = localStorage->m_Reslicer->GetResliceAxes(); //transform the origin to center based coordinates, because MITK is center based. Point3D originCenterBased = origin; originCenterBased -= right * ( mmPerPixel[0] * 0.5 ); originCenterBased -= bottom * ( mmPerPixel[1] * 0.5 ); matrix->SetElement(0, 3, originCenterBased[0]); matrix->SetElement(1, 3, originCenterBased[1]); matrix->SetElement(2, 3, originCenterBased[2]); trans->SetMatrix(matrix); //transform the plane/contour (the actual actor) to the corresponding view (transversal, coronal or saggital) localStorage->m_Actor->SetUserTransform(trans); // We have been modified => save this for next Update() localStorage->m_LastUpdateTime.Modified(); } bool mitk::ImageVtkMapper2D::LineIntersectZero( vtkPoints *points, int p1, int p2, vtkFloatingPointType *bounds ) { vtkFloatingPointType point1[3]; vtkFloatingPointType point2[3]; points->GetPoint( p1, point1 ); points->GetPoint( p2, point2 ); if ( (point1[2] * point2[2] <= 0.0) && (point1[2] != point2[2]) ) { double x, y; x = ( point1[0] * point2[2] - point1[2] * point2[0] ) / ( point2[2] - point1[2] ); y = ( point1[1] * point2[2] - point1[2] * point2[1] ) / ( point2[2] - point1[2] ); if ( x < bounds[0] ) { bounds[0] = x; } if ( x > bounds[1] ) { bounds[1] = x; } if ( y < bounds[2] ) { bounds[2] = y; } if ( y > bounds[3] ) { bounds[3] = y; } bounds[4] = bounds[5] = 0.0; return true; } return false; } bool mitk::ImageVtkMapper2D::CalculateClippedPlaneBounds( const Geometry3D *boundingGeometry, const PlaneGeometry *planeGeometry, vtkFloatingPointType *bounds ) { // Clip the plane with the bounding geometry. To do so, the corner points // of the bounding box are transformed by the inverse transformation // matrix, and the transformed bounding box edges derived therefrom are // clipped with the plane z=0. The resulting min/max values are taken as // bounds for the image reslicer. const mitk::BoundingBox *boundingBox = boundingGeometry->GetBoundingBox(); mitk::BoundingBox::PointType bbMin = boundingBox->GetMinimum(); mitk::BoundingBox::PointType bbMax = boundingBox->GetMaximum(); vtkSmartPointer points = vtkSmartPointer::New(); if(boundingGeometry->GetImageGeometry()) { points->InsertPoint( 0, bbMin[0]-0.5, bbMin[1]-0.5, bbMin[2]-0.5 ); points->InsertPoint( 1, bbMin[0]-0.5, bbMin[1]-0.5, bbMax[2]-0.5 ); points->InsertPoint( 2, bbMin[0]-0.5, bbMax[1]-0.5, bbMax[2]-0.5 ); points->InsertPoint( 3, bbMin[0]-0.5, bbMax[1]-0.5, bbMin[2]-0.5 ); points->InsertPoint( 4, bbMax[0]-0.5, bbMin[1]-0.5, bbMin[2]-0.5 ); points->InsertPoint( 5, bbMax[0]-0.5, bbMin[1]-0.5, bbMax[2]-0.5 ); points->InsertPoint( 6, bbMax[0]-0.5, bbMax[1]-0.5, bbMax[2]-0.5 ); points->InsertPoint( 7, bbMax[0]-0.5, bbMax[1]-0.5, bbMin[2]-0.5 ); } else { points->InsertPoint( 0, bbMin[0], bbMin[1], bbMin[2] ); points->InsertPoint( 1, bbMin[0], bbMin[1], bbMax[2] ); points->InsertPoint( 2, bbMin[0], bbMax[1], bbMax[2] ); points->InsertPoint( 3, bbMin[0], bbMax[1], bbMin[2] ); points->InsertPoint( 4, bbMax[0], bbMin[1], bbMin[2] ); points->InsertPoint( 5, bbMax[0], bbMin[1], bbMax[2] ); points->InsertPoint( 6, bbMax[0], bbMax[1], bbMax[2] ); points->InsertPoint( 7, bbMax[0], bbMax[1], bbMin[2] ); } vtkSmartPointer newPoints = vtkSmartPointer::New(); vtkSmartPointer transform = vtkSmartPointer::New(); transform->Identity(); transform->Concatenate( planeGeometry->GetVtkTransform()->GetLinearInverse() ); transform->Concatenate( boundingGeometry->GetVtkTransform() ); transform->TransformPoints( points, newPoints ); bounds[0] = bounds[2] = 10000000.0; bounds[1] = bounds[3] = -10000000.0; bounds[4] = bounds[5] = 0.0; this->LineIntersectZero( newPoints, 0, 1, bounds ); this->LineIntersectZero( newPoints, 1, 2, bounds ); this->LineIntersectZero( newPoints, 2, 3, bounds ); this->LineIntersectZero( newPoints, 3, 0, bounds ); this->LineIntersectZero( newPoints, 0, 4, bounds ); this->LineIntersectZero( newPoints, 1, 5, bounds ); this->LineIntersectZero( newPoints, 2, 6, bounds ); this->LineIntersectZero( newPoints, 3, 7, bounds ); this->LineIntersectZero( newPoints, 4, 5, bounds ); this->LineIntersectZero( newPoints, 5, 6, bounds ); this->LineIntersectZero( newPoints, 6, 7, bounds ); this->LineIntersectZero( newPoints, 7, 4, bounds ); if ( (bounds[0] > 9999999.0) || (bounds[2] > 9999999.0) || (bounds[1] < -9999999.0) || (bounds[3] < -9999999.0) ) { return false; } else { // The resulting bounds must be adjusted by the plane spacing, since we // we have so far dealt with index coordinates const float *planeSpacing = planeGeometry->GetFloatSpacing(); bounds[0] *= planeSpacing[0]; bounds[1] *= planeSpacing[0]; bounds[2] *= planeSpacing[1]; bounds[3] *= planeSpacing[1]; bounds[4] *= planeSpacing[2]; bounds[5] *= planeSpacing[2]; return true; } } void mitk::ImageVtkMapper2D::ApplyProperties(mitk::BaseRenderer* renderer, mitk::ScalarType mmPerPixel[2]) { //get the current localStorage for the corresponding renderer LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); // check for interpolation properties bool textureInterpolation = false; GetDataNode()->GetBoolProperty( "texture interpolation", textureInterpolation, renderer ); //set the interpolation modus according to the property localStorage->m_Texture->SetInterpolate(textureInterpolation); //do not repeat the texture (the image) localStorage->m_Texture->RepeatOff(); float rgb[3]= { 1.0f, 1.0f, 1.0f }; float opacity = 1.0f; // check for opacity prop and use it for rendering if it exists GetOpacity( opacity, renderer ); //set the opacity according to the properties localStorage->m_Actor->GetProperty()->SetOpacity(opacity); // check for color prop and use it for rendering if it exists // binary image hovering & binary image selection bool hover = false; bool selected = false; GetDataNode()->GetBoolProperty("binaryimage.ishovering", hover, renderer); GetDataNode()->GetBoolProperty("selected", selected, renderer); if(hover && !selected) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty ("binaryimage.hoveringcolor", renderer)); if(colorprop.IsNotNull()) + { memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); + } else + { GetColor( rgb, renderer ); + } } if(selected) { mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty ("binaryimage.selectedcolor", renderer)); - if(colorprop.IsNotNull()) + if(colorprop.IsNotNull()) { memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); + } else + { GetColor( rgb, renderer ); + } } if(!hover && !selected) { GetColor( rgb, renderer ); } //get the binary property bool binary = false; this->GetDataNode()->GetBoolProperty( "binary", binary, renderer ); -// localStorage->m_Texture->SetMapColorScalarsThroughLookupTable(binary); //use color means that we want to use the color from the property list and not a lookuptable bool useColor = true; this->GetDataNode()->GetBoolProperty( "use color", useColor, renderer ); //the finalLookuptable will be used for the rendering and can either be a user-defined table or the default lut - vtkSmartPointer finalLookuptable = vtkSmartPointer::New(); + vtkSmartPointer finalLookuptable = localStorage->m_LookupTable; //BEGIN PROPERTY user-defined lut //currently we do not allow a lookuptable if it is a binary image bool useDefaultLut = true; if((!useColor) && (!binary)) { // If lookup table use is requested... mitk::LookupTableProperty::Pointer LookupTableProp; LookupTableProp = dynamic_cast (this->GetDataNode()->GetProperty("LookupTable")); //...check if there is a lookuptable provided by the user if ( LookupTableProp.IsNull() ) { MITK_WARN << "The use of a lookuptable is requested, but there is no lookuptable supplied by the user! The default lookuptable will be used instead."; } else { // If lookup table use is requested and supplied by the user: // only update the lut, when the properties have changed... if( LookupTableProp->GetLookupTable()->GetMTime() <= this->GetDataNode()->GetPropertyList()->GetMTime() ) { LookupTableProp->GetLookupTable()->ChangeOpacityForAll( opacity ); LookupTableProp->GetLookupTable()->ChangeOpacity(0, 0.0); } //we use the user-defined lookuptable finalLookuptable = LookupTableProp->GetLookupTable()->GetVtkLookupTable(); //we obtained a user-defined lut and dont have to use the default table useDefaultLut = false; } }//END PROPERTY user-defined lut + //use the finalLookuptable for mapping the colors + localStorage->m_Texture->SetLookupTable( finalLookuptable ); + //check if we need the default table if( useDefaultLut ) { - finalLookuptable = localStorage->m_LookupTable; double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK localStorage->m_Actor->GetProperty()->SetColor(rgbConv); } else { //If the user defines a lut, we dont want to use the color and take white instead. localStorage->m_Actor->GetProperty()->SetColor(1.0, 1.0, 1.0); } bool binaryOutline = false; this->GetDataNode()->GetBoolProperty( "outline binary", binaryOutline, renderer ); - if ( binary ) { - finalLookuptable->SetAlphaRange(0.0, 1.0); finalLookuptable->SetRange(0.0, 1.0); //0 is already mapped to transparent. //1 is now mapped to the current color and alpha if ( this->GetInput()->GetPixelType().GetBpe() <= 8 ) { if (binaryOutline) { //generate ontours/outlines TODO: not always necessary - localStorage->m_OutlinePolyData = CreateOutlinePolyData(localStorage->m_ReslicedImage, mmPerPixel); + localStorage->m_OutlinePolyData = CreateOutlinePolyData(renderer ,localStorage->m_ReslicedImage, mmPerPixel); float binaryOutlineWidth(1.0); if (this->GetDataNode()->GetFloatProperty( "outline width", binaryOutlineWidth, renderer )) { localStorage->m_Actor->GetProperty()->SetLineWidth(binaryOutlineWidth); } } } else { MITK_WARN << "Type of all binary images should be (un)signed char. Outline does not work on other pixel types!"; } } //END binary image handling else { + LevelWindow levelWindow; + this->GetLevelWindow( levelWindow, renderer ); + + //set up the lookuptable with the level window range + finalLookuptable->SetRange( levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound() ); mitk::PixelType pixelType = this->GetInput()->GetPixelType(); if( pixelType.GetBitsPerComponent() == pixelType.GetBpe() ) //gray images with just one component { localStorage->m_Texture->MapColorScalarsThroughLookupTableOn(); } else //RGB, RBGA or other images tpyes with more components { // obtain and apply opacity level window if possible localStorage->m_Texture->MapColorScalarsThroughLookupTableOff(); - vtkMitkApplyLevelWindowToRGBFilter* levelWindowToRGBFilterObject = new vtkMitkApplyLevelWindowToRGBFilter(); - levelWindowToRGBFilterObject->SetLookupTable(localStorage->m_Texture->GetLookupTable()); + localStorage->m_LevelWindowToRGBFilterObject->SetLookupTable(localStorage->m_Texture->GetLookupTable()); mitk::LevelWindow opacLevelWindow; if( this->GetLevelWindow( opacLevelWindow, renderer, "opaclevelwindow" ) ) { - levelWindowToRGBFilterObject->SetMinOpacity(opacLevelWindow.GetLowerWindowBound()); - levelWindowToRGBFilterObject->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound()); + localStorage->m_LevelWindowToRGBFilterObject->SetMinOpacity(opacLevelWindow.GetLowerWindowBound()); + localStorage->m_LevelWindowToRGBFilterObject->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound()); } else { - levelWindowToRGBFilterObject->SetMinOpacity(0.0); - levelWindowToRGBFilterObject->SetMaxOpacity(255.0); + localStorage->m_LevelWindowToRGBFilterObject->SetMinOpacity(0.0); + localStorage->m_LevelWindowToRGBFilterObject->SetMaxOpacity(255.0); } - levelWindowToRGBFilterObject->SetInput(localStorage->m_ReslicedImage); - localStorage->m_Texture->SetInputConnection(levelWindowToRGBFilterObject->GetOutputPort()); + localStorage->m_LevelWindowToRGBFilterObject->SetInput(localStorage->m_ReslicedImage); + localStorage->m_Texture->SetInputConnection(localStorage->m_LevelWindowToRGBFilterObject->GetOutputPort()); } - LevelWindow levelWindow; - this->GetLevelWindow( levelWindow, renderer ); - - //set up the lookuptable with the level window range - finalLookuptable->SetRange( levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound() ); } - //use the finalLookuptable for mapping the colors - localStorage->m_Texture->SetLookupTable( finalLookuptable ); if(binaryOutline && binary) { //We need the contour for the binary oultine property as actor localStorage->m_Mapper->SetInput(localStorage->m_OutlinePolyData); - localStorage->m_Actor->SetTexture(NULL); //no texture + localStorage->m_Actor->SetTexture(NULL); //no texture for contours } else { - //transform the plane to the corresponding view (transversal, coronal or saggital) + //set the plane as input for the mapper localStorage->m_Mapper->SetInputConnection(localStorage->m_Plane->GetOutputPort()); //set the texture for the actor localStorage->m_Actor->SetTexture(localStorage->m_Texture); } } void mitk::ImageVtkMapper2D::Update(mitk::BaseRenderer* renderer) { if ( !this->IsVisible( renderer ) ) { return; } mitk::Image* data = const_cast( this->GetInput() ); if ( data == NULL ) { return; } // Calculate time step of the input data for the specified renderer (integer value) this->CalculateTimeStep( renderer ); // Check if time step is valid const TimeSlicedGeometry *dataTimeGeometry = data->GetTimeSlicedGeometry(); if ( ( dataTimeGeometry == NULL ) || ( dataTimeGeometry->GetTimeSteps() == 0 ) || ( !dataTimeGeometry->IsValidTime( this->GetTimestep() ) ) ) { return; } const DataNode *node = this->GetDataNode(); data->UpdateOutputInformation(); LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); //check if something important has changed and we need to rerender if ( (localStorage->m_LastUpdateTime < node->GetMTime()) //was the node modified? || (localStorage->m_LastUpdateTime < data->GetPipelineMTime()) //Was the data modified? || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2DUpdateTime()) //was the geometry modified? - || (localStorage->m_LastUpdateTime < renderer->GetDisplayGeometry()->GetMTime()) //was the display geometry modified? e.g. zooming, panning || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2D()->GetMTime()) || (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) //was a property modified? || (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ) { - this->GenerateDataForRenderer( renderer ); + this->GenerateDataForRenderer( renderer ); } // since we have checked that nothing important has changed, we can set // m_LastUpdateTime to the current time localStorage->m_LastUpdateTime.Modified(); } void mitk::ImageVtkMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { mitk::Image::Pointer image = dynamic_cast(node->GetData()); // Properties common for both images and segmentations node->AddProperty( "use color", mitk::BoolProperty::New( true ), renderer, overwrite ); node->AddProperty( "depthOffset", mitk::FloatProperty::New( 0.0 ), renderer, overwrite ); node->AddProperty( "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "outline width", mitk::FloatProperty::New( 1.0 ), renderer, overwrite ); if(image->IsRotated()) node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_CUBIC) ); else node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ); node->AddProperty( "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ); // set to user configurable default value (see global options) node->AddProperty( "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ); node->AddProperty( "bounding box", mitk::BoolProperty::New( false ) ); bool isBinaryImage(false); if ( ! node->GetBoolProperty("binary", isBinaryImage) ) { // ok, property is not set, use heuristic to determine if this // is a binary image mitk::Image::Pointer centralSliceImage; ScalarType minValue = 0.0; ScalarType maxValue = 0.0; ScalarType min2ndValue = 0.0; ScalarType max2ndValue = 0.0; mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New(); sliceSelector->SetInput(image); sliceSelector->SetSliceNr(image->GetDimension(2)/2); sliceSelector->SetTimeNr(image->GetDimension(3)/2); sliceSelector->SetChannelNr(image->GetDimension(4)/2); sliceSelector->Update(); centralSliceImage = sliceSelector->GetOutput(); if ( centralSliceImage.IsNotNull() && centralSliceImage->IsInitialized() ) { minValue = centralSliceImage->GetScalarValueMin(); maxValue = centralSliceImage->GetScalarValueMax(); min2ndValue = centralSliceImage->GetScalarValue2ndMin(); max2ndValue = centralSliceImage->GetScalarValue2ndMax(); } if ( minValue == maxValue ) { // centralSlice is strange, lets look at all data minValue = image->GetScalarValueMin(); maxValue = image->GetScalarValueMaxNoRecompute(); min2ndValue = image->GetScalarValue2ndMinNoRecompute(); max2ndValue = image->GetScalarValue2ndMaxNoRecompute(); } isBinaryImage = ( maxValue == min2ndValue && minValue == max2ndValue ); } // some more properties specific for a binary... if (isBinaryImage) { node->AddProperty( "opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite ); node->AddProperty( "color", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.selectedcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.selectedannotationcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.hoveringcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binaryimage.hoveringannotationcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( true ), renderer, overwrite ); node->AddProperty("layer", mitk::IntProperty::New(10), renderer, overwrite); } else //...or image type object { node->AddProperty( "opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite ); node->AddProperty( "color", ColorProperty::New(1.0,1.0,1.0), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty("layer", mitk::IntProperty::New(0), renderer, overwrite); } if(image.IsNotNull() && image->IsInitialized()) { if((overwrite) || (node->GetProperty("levelwindow", renderer)==NULL)) { mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetAuto( image, true, true ); levWinProp->SetLevelWindow( levelwindow ); node->SetProperty( "levelwindow", levWinProp, renderer ); } if(((overwrite) || (node->GetProperty("opaclevelwindow", renderer)==NULL)) && (image->GetPixelType().GetItkTypeId() && *(image->GetPixelType().GetItkTypeId()) == typeid(itk::RGBAPixel))) { mitk::LevelWindow opaclevwin; opaclevwin.SetRangeMinMax(0,255); opaclevwin.SetWindowBounds(0,255); mitk::LevelWindowProperty::Pointer prop = mitk::LevelWindowProperty::New(opaclevwin); node->SetProperty( "opaclevelwindow", prop, renderer ); } if((overwrite) || (node->GetProperty("LookupTable", renderer)==NULL)) { // add a default rainbow lookup table for color mapping mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); vtkLookupTable* vtkLut = mitkLut->GetVtkLookupTable(); vtkLut->SetHueRange(0.6667, 0.0); vtkLut->SetTableRange(0.0, 20.0); vtkLut->Build(); mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); mitkLutProp->SetLookupTable(mitkLut); node->SetProperty( "LookupTable", mitkLutProp ); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } -vtkSmartPointer mitk::ImageVtkMapper2D::CreateOutlinePolyData(vtkSmartPointer binarySlice, mitk::ScalarType mmPerPixel[2]){ +vtkSmartPointer mitk::ImageVtkMapper2D::CreateOutlinePolyData(mitk::BaseRenderer* renderer, vtkSmartPointer binarySlice, mitk::ScalarType mmPerPixel[2]){ int* dims = binarySlice->GetDimensions(); //dimensions of the image int line = dims[0]; //how many pixels per line? int x = 0; //pixel index x int y = 0; //pixel index y char* currentPixel; int nn = dims[0]*dims[1]; //max pixel(n,n) + //get the depth for each contour + float depth = CalculateLayerDepth(renderer); + vtkSmartPointer points = vtkSmartPointer::New(); //the points to draw vtkSmartPointer lines = vtkSmartPointer::New(); //the lines to connect the points for (int ii = 0; ii(binarySlice->GetScalarPointer(x, y, 0)); //if the current pixel value is set to something if ((currentPixel) && (*currentPixel != 0)) { //check in which direction a line is necessary if (ii >= line && *(currentPixel-line) == 0) { //x direction - bottom edge of the pixel //add the 2 points - vtkIdType p1 = points->InsertNextPoint(x*mmPerPixel[0], y*mmPerPixel[1], 0); - vtkIdType p2 = points->InsertNextPoint((x+1)*mmPerPixel[0], y*mmPerPixel[1], 0); + vtkIdType p1 = points->InsertNextPoint(x*mmPerPixel[0], y*mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*mmPerPixel[0], y*mmPerPixel[1], depth); //add the line between both points lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } if (ii <= nn-line && *(currentPixel+line) == 0) { //x direction - top edge of the pixel - vtkIdType p1 = points->InsertNextPoint(x*mmPerPixel[0], (y+1)*mmPerPixel[1], 0); - vtkIdType p2 = points->InsertNextPoint((x+1)*mmPerPixel[0], (y+1)*mmPerPixel[1], 0); + vtkIdType p1 = points->InsertNextPoint(x*mmPerPixel[0], (y+1)*mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*mmPerPixel[0], (y+1)*mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } if (ii > 1 && *(currentPixel-1) == 0) { //y direction - left edge of the pixel - vtkIdType p1 = points->InsertNextPoint(x*mmPerPixel[0], y*mmPerPixel[1], 0); - vtkIdType p2 = points->InsertNextPoint(x*mmPerPixel[0], (y+1)*mmPerPixel[1], 0); + vtkIdType p1 = points->InsertNextPoint(x*mmPerPixel[0], y*mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint(x*mmPerPixel[0], (y+1)*mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } if (ii < nn-1 && *(currentPixel+1) == 0) { //y direction - right edge of the pixel - vtkIdType p1 = points->InsertNextPoint((x+1)*mmPerPixel[0], y*mmPerPixel[1], 0); - vtkIdType p2 = points->InsertNextPoint((x+1)*mmPerPixel[0], (y+1)*mmPerPixel[1], 0); + vtkIdType p1 = points->InsertNextPoint((x+1)*mmPerPixel[0], y*mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*mmPerPixel[0], (y+1)*mmPerPixel[1], depth); lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } } //reached end of line x++; if (x >= line) { x = 0; y++; } } // Create a polydata to store everything in vtkSmartPointer polyData = vtkSmartPointer::New(); // Add the points to the dataset polyData->SetPoints(points); // Add the lines to the dataset polyData->SetLines(lines); return polyData; } mitk::ImageVtkMapper2D::LocalStorage::LocalStorage() { //Do as much actions as possible in here to avoid double executions. - //TODO initialize everything with NULL in the list ??? - m_ReslicedImage = vtkSmartPointer::New(); m_Plane = vtkSmartPointer::New(); m_Texture = vtkSmartPointer::New(); m_LookupTable = vtkSmartPointer::New(); m_Mapper = vtkSmartPointer::New(); m_Actor = vtkSmartPointer::New(); m_Reslicer = vtkSmartPointer::New(); m_TSFilter = vtkSmartPointer::New(); - m_UnitSpacingImageFilter = vtkSmartPointer::New(); + m_UnitSpacingImageFilter = vtkSmartPointer::New(); m_OutlinePolyData = vtkSmartPointer::New(); + m_ReslicedImage = vtkSmartPointer::New(); //the following actions are always the same and thus can be performed //in the constructor for each image (i.e. the image-corresponding local storage) m_TSFilter->ReleaseDataFlagOn(); m_Reslicer->ReleaseDataFlagOn(); m_UnitSpacingImageFilter->SetOutputSpacing( 1.0, 1.0, 1.0 ); //built a default lookuptable + m_LookupTable->SetRampToLinear(); m_LookupTable->SetSaturationRange( 0.0, 0.0 ); m_LookupTable->SetHueRange( 0.0, 0.0 ); m_LookupTable->SetValueRange( 0.0, 1.0 ); m_LookupTable->Build(); //map all black values to transparent m_LookupTable->SetTableValue(0, 0.0, 0.0, 0.0, 0.0); //set the mapper for the actor m_Actor->SetMapper(m_Mapper); + + //filter for RGB(A) images + m_LevelWindowToRGBFilterObject = new vtkMitkApplyLevelWindowToRGBFilter(); } diff --git a/Core/Code/Rendering/mitkImageVtkMapper2D.h b/Core/Code/Rendering/mitkImageVtkMapper2D.h index 8628288575..0ba0262799 100644 --- a/Core/Code/Rendering/mitkImageVtkMapper2D.h +++ b/Core/Code/Rendering/mitkImageVtkMapper2D.h @@ -1,238 +1,244 @@ /*========================================================================= Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKIMAGEVTKMAPPER2D_H_HEADER_INCLUDED_C10E906E #define MITKIMAGEVTKMAPPER2D_H_HEADER_INCLUDED_C10E906E //MITK #include //MITK Rendering #include "mitkBaseRenderer.h" #include "mitkVtkMapper2D.h" //VTK #include class vtkActor; class vtkPolyDataMapper; class vtkPlaneSource; class vtkImageData; class vtkLookupTable; class vtkImageReslice; class vtkImageChangeInformation; class vtkPoints; class vtkMitkThickSlicesFilter; class vtkPolyData; +class vtkMitkApplyLevelWindowToRGBFilter; namespace mitk { /** \brief Mapper to resample and display 2D slices of a 3D image. * * The following image gives a brief overview of the mapping and the involved parts. * * \image html imageVtkMapper2Darchitecture.png * * First, the image is resliced by means of vtkImageReslice. The volume image * serves as input to the mapper in addition to spatial placement of the slice and a few other * properties such as thick slices. This code was already present in the old version * (mitkImageMapperGL2D). * * Next, the obtained slice (m_ReslicedImage) is used to create a texture * (m_Texture) and a plane onto which the texture is rendered (m_Plane). For * mapping purposes, a vtkPolyDataMapper (m_Mapper) is utilized. Orthographic * projection is applied to create the effect of a 2D image. The mapper and the * texture are assigned to the actor (m_Actor) which is passed to the VTK rendering * pipeline via the method GetVtkProp(). * * In order to transform the textured plane to the correct position in space, the * same transformation as used for reslicing is applied to both the camera and the - * vtkActor. The camera position is also influenced by the mitkDisplayGeometry - * parameters to facilitate zooming and panning. All important steps are explained - * in more detail below. The resulting 2D image (by reslicing the - * underlying 3D input image appropriately) can either be directly rendered - * in a 2D view or just be calculated to be used later by another + * vtkActor. All important steps are explained in more detail below. The resulting + * 2D image (by reslicing the underlying 3D input image appropriately) can either + * be directly rendered in a 2D view or just be calculated to be used later by another * rendering entity, e.g. in texture mapping in a 3D view. * * Properties that can be set for images and influence the imageMapper2D are: * * - \b "opacity": (FloatProperty) Opacity of the image * - \b "color": (ColorProperty) Color of the image * - \b "use color": (BoolProperty) Use the color of the image or not * - \b "binary": (BoolProperty) is the image a binary image or not * - \b "outline binary": (BoolProperty) show outline of the image or not * - \b "texture interpolation": (BoolProperty) texture interpolation of the image * - \b "reslice interpolation": (VtkResliceInterpolationProperty) reslice interpolation of the image * - \b "in plane resample extent by geometry": (BoolProperty) Do it or not * - \b "bounding box": (BoolProperty) Is the Bounding Box of the image shown or not * - \b "layer": (IntProperty) Layer of the image * - \b "volume annotation color": (ColorProperty) color of the volume annotation, TODO has to be reimplemented * - \b "volume annotation unit": (StringProperty) annotation unit as string (does not implicit convert the unit!) unit is ml or cm3, TODO has to be reimplemented * The default properties are: * - \b "opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite ) * - \b "color", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ) * - \b "use color", mitk::BoolProperty::New( true ), renderer, overwrite ) * - \b "binary", mitk::BoolProperty::New( true ), renderer, overwrite ) * - \b "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ) * - \b "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ) * - \b "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ) * - \b "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ) * - \b "bounding box", mitk::BoolProperty::New( false ) ) * - \b "layer", mitk::IntProperty::New(10), renderer, overwrite) * If the modality-property is set for an image, the mapper uses modality-specific default properties, * e.g. color maps, if they are defined. * \ingroup Mapper */ class MITK_CORE_EXPORT ImageVtkMapper2D : public VtkMapper2D { public: /** Standard class typedefs. */ mitkClassMacro( ImageVtkMapper2D,VtkMapper2D ); /** Method for creation through the object factory. */ itkNewMacro(Self); /** \brief Get the Image to map */ const mitk::Image *GetInput(void); /** \brief Checks whether this mapper needs to update itself and generate * data. */ virtual void Update(mitk::BaseRenderer * renderer); - /** \brief Apply all properties to the vtkActor (e.g. color, opacity, binary image handling, etc.).*/ - virtual void ApplyProperties(mitk::BaseRenderer* renderer, ScalarType mmPerPixel[2]); - //### methods of MITK-VTK rendering pipeline virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); virtual void MitkRenderOverlay(BaseRenderer* renderer); virtual void MitkRenderOpaqueGeometry(BaseRenderer* renderer); virtual void MitkRenderTranslucentGeometry(BaseRenderer* renderer); virtual void MitkRenderVolumetricGeometry(BaseRenderer* renderer); //### end of methods of MITK-VTK rendering pipeline /** \brief Internal class holding the mapper, actor, etc. for each of the 3 2D render windows */ /** * To render transveral, coronal, and sagittal, the mapper is called three times. * For performance reasons, the corresponding data for each view is saved in the * internal helper class LocalStorage. This allows rendering n views with just * 1 mitkMapper using n vtkMapper. * */ class MITK_CORE_EXPORT LocalStorage : public mitk::Mapper::BaseLocalStorage { public: /** \brief Actor of a 2D render window. */ vtkSmartPointer m_Actor; /** \brief Mapper of a 2D render window. */ vtkSmartPointer m_Mapper; /** \brief Current slice of a 2D render window. */ vtkSmartPointer m_ReslicedImage; /** \brief Plane on which the slice is rendered as texture. */ vtkSmartPointer m_Plane; /** \brief The texture which is used to render the current slice. */ vtkSmartPointer m_Texture; /** \brief The lookuptable for colors and level window */ vtkSmartPointer m_LookupTable; /** \brief The actual reslicer (one per renderer) */ vtkSmartPointer m_Reslicer; /** \brief Thickslices post filtering. */ vtkSmartPointer m_TSFilter; /** \brief Using unit spacing for resampling makes life easier TODO improve docu ...*/ vtkSmartPointer m_UnitSpacingImageFilter; /** \brief PolyData object containg all lines/points needed for outlining the contour. This container is used to save a computed contour for the next rendering execution. For instance, if you zoom or pann, there is no need to recompute the contour. */ vtkSmartPointer m_OutlinePolyData; /** \brief Timestamp of last update of stored data. */ itk::TimeStamp m_LastUpdateTime; + /** \brief This filter is used to apply the level window to RBG(A) images. */ + vtkMitkApplyLevelWindowToRGBFilter* m_LevelWindowToRGBFilterObject; + /** \brief Default constructor of the local storage. */ LocalStorage(); /** \brief Default deconstructor of the local storage. */ ~LocalStorage() { } }; /** \brief The LocalStorageHandler holds all (three) LocalStorages for the three 2D render windows. */ mitk::Mapper::LocalStorageHandler m_LSH; /** \brief Set the default properties for general image rendering. */ static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); protected: + /** \brief Apply all properties to the vtkActor (e.g. color, opacity, binary image handling, etc.).*/ + virtual void ApplyProperties(mitk::BaseRenderer* renderer, ScalarType mmPerPixel[2]); + /** \brief Generates a plane according to the size of the resliced image in milimeters. * * \image html texturedPlane.png * * In VTK a vtkPlaneSource is defined through three points. The origin and two * points defining the axes of the plane (see VTK documentation). The origin is - * set to (xMin; yMin; 0), where xMin and yMin are the minimal bounds of the - * resliced image in space. The center of the plane (C) is also the center of - * the view plane (cf. the image above). + * set to (xMin; yMin; Z), where xMin and yMin are the minimal bounds of the + * resliced image in space. Z is relevant for blending and the layer property. + * The center of the plane (C) is also the center of the view plane (cf. the image above). * * \note For the standard MITK view with three 2D render windows showing three * different slices, three such planes are generated. All these planes are generated * in the XY-plane (even if they depict a YZ-slice of the volume). * */ void GeneratePlane(mitk::BaseRenderer* renderer, vtkFloatingPointType planeBounds[6]); /** \brief Generates a vtkPolyData object containing the outline of a given binary slice. \param binarySlice - The binary image slice. (Volumes are not supported.) \param mmPerPixel - Spacing of the binary image slice. Hence it's 2D, only in x/y-direction. \note This code has been taken from the deprecated library iil. */ - vtkSmartPointer CreateOutlinePolyData(vtkSmartPointer binarySlice, ScalarType mmPerPixel[2]); + vtkSmartPointer CreateOutlinePolyData(mitk::BaseRenderer* renderer, vtkSmartPointer binarySlice, ScalarType mmPerPixel[2]); /** Default constructor */ ImageVtkMapper2D(); /** Default deconstructor */ virtual ~ImageVtkMapper2D(); /** \brief Does the actual resampling, without rendering the image yet. * All the data is generated inside this method. The vtkProp (or Actor) * is filled with content (i.e. the resliced image). * * After generation, a 4x4 transformation matrix(t) of the current slice is obtained * from the vtkResliceImage object via GetReslicesAxis(). This matrix is - * applied to each camera (cam->ApplyTransformation(t)) and to each textured - * plane (actor->SetUserTransform(t)) to transform everything + * applied to each textured plane (actor->SetUserTransform(t)) to transform everything * to the actual 3D position (cf. the following image). * * \image html cameraPositioning3D.png * */ virtual void GenerateDataForRenderer(mitk::BaseRenderer *renderer); /** \brief Internal helper method for intersection testing used only in CalculateClippedPlaneBounds() */ bool LineIntersectZero( vtkPoints *points, int p1, int p2, vtkFloatingPointType *bounds ); /** \brief Calculate the bounding box of the resliced image. This is necessary for arbitrarily rotated planes in an image volume. A rotated plane (e.g. in swivel mode) will have a new bounding box, which needs to be calculated. */ bool CalculateClippedPlaneBounds( const Geometry3D *boundingGeometry, const PlaneGeometry *planeGeometry, vtkFloatingPointType *bounds ); + + /** \brief This method uses the vtkCamera clipping range and the layer property + * to calcualte the depth of the object (e.g. image or contour). The depth is used + * to keep the correct order for the final VTK rendering.*/ + float CalculateLayerDepth(mitk::BaseRenderer* renderer); }; } // namespace mitk #endif /* MITKIMAGEVTKMAPPER2D_H_HEADER_INCLUDED_C10E906E */ diff --git a/Core/Code/Rendering/mitkVtkPropRenderer.cpp b/Core/Code/Rendering/mitkVtkPropRenderer.cpp index 76b21f13ea..6463c99264 100644 --- a/Core/Code/Rendering/mitkVtkPropRenderer.cpp +++ b/Core/Code/Rendering/mitkVtkPropRenderer.cpp @@ -1,910 +1,918 @@ /*========================================================================= Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkVtkPropRenderer.h" -#include "picimage.h" - // MAPPERS #include "mitkMapper.h" #include "mitkImageVtkMapper2D.h" #include "mitkVtkMapper2D.h" #include "mitkVtkMapper3D.h" #include "mitkGeometry2DDataVtkMapper3D.h" #include "mitkPointSetGLMapper2D.h" #include "mitkImageSliceSelector.h" #include "mitkRenderingManager.h" #include "mitkGL.h" #include "mitkGeometry3D.h" #include "mitkDisplayGeometry.h" #include "mitkLevelWindow.h" #include "mitkCameraController.h" #include "mitkVtkInteractorCameraController.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" #include "mitkSurface.h" #include "mitkNodePredicateDataType.h" // VTK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include - - mitk::VtkPropRenderer::VtkPropRenderer( const char* name, vtkRenderWindow * renWin, mitk::RenderingManager* rm ) : BaseRenderer(name,renWin, rm), m_VtkMapperPresent(false), - m_NewRenderer(true) + m_NewRenderer(true), + m_2DCameraInitialized(false) { didCount=false; m_WorldPointPicker = vtkWorldPointPicker::New(); m_PointPicker = vtkPointPicker::New(); m_PointPicker->SetTolerance( 0.0025 ); m_CellPicker = vtkCellPicker::New(); m_CellPicker->SetTolerance( 0.0025 ); mitk::Geometry2DDataVtkMapper3D::Pointer geometryMapper = mitk::Geometry2DDataVtkMapper3D::New(); m_CurrentWorldGeometry2DMapper = geometryMapper; m_CurrentWorldGeometry2DNode->SetMapper(2, geometryMapper); m_LightKit = vtkLightKit::New(); m_LightKit->AddLightsToRenderer(m_VtkRenderer); m_PickingMode = WorldPointPicking; m_TextRenderer = vtkRenderer::New(); m_TextRenderer->SetRenderWindow(renWin); m_TextRenderer->SetInteractive(0); m_TextRenderer->SetErase(0); } /*! \brief Destructs the VtkPropRenderer. */ mitk::VtkPropRenderer::~VtkPropRenderer() { // Workaround for GLDisplayList Bug { m_MapperID=0; checkState(); } if (m_LightKit != NULL) m_LightKit->Delete(); if (m_VtkRenderer!=NULL) { m_CameraController = NULL; m_VtkRenderer->Delete(); m_VtkRenderer = NULL; } else m_CameraController = NULL; if (m_WorldPointPicker != NULL) m_WorldPointPicker->Delete(); if (m_PointPicker != NULL) m_PointPicker->Delete(); if (m_CellPicker != NULL) m_CellPicker->Delete(); if (m_TextRenderer != NULL) m_TextRenderer->Delete(); } void mitk::VtkPropRenderer::SetDataStorage( mitk::DataStorage* storage ) { if ( storage == NULL ) return; BaseRenderer::SetDataStorage(storage); static_cast(m_CurrentWorldGeometry2DMapper.GetPointer())->SetDataStorageForTexture( m_DataStorage.GetPointer() ); // Compute the geometry from the current data tree bounds and set it as world geometry this->SetWorldGeometryToDataStorageBounds(); } bool mitk::VtkPropRenderer::SetWorldGeometryToDataStorageBounds() { if ( m_DataStorage.IsNull() ) return false; //initialize world geometry mitk::TimeSlicedGeometry::Pointer geometry = m_DataStorage->ComputeVisibleBoundingGeometry3D( NULL, "includeInBoundingBox" ); if ( geometry.IsNull() ) return false; this->SetWorldGeometry(geometry); //this->GetDisplayGeometry()->SetSizeInDisplayUnits( this->m_TextRenderer->GetRenderWindow()->GetSize()[0], this->m_TextRenderer->GetRenderWindow()->GetSize()[1] ); this->GetDisplayGeometry()->Fit(); this->GetVtkRenderer()->ResetCamera(); this->Modified(); return true; } /*! \brief Called by the vtkMitkRenderProp in order to start MITK rendering process. */ int mitk::VtkPropRenderer::Render(mitk::VtkPropRenderer::RenderType type) { - // MITK_INFO << "hier drin " << type; // Do we have objects to render? if ( this->GetEmptyWorldGeometry()) return 0; if ( m_DataStorage.IsNull()) return 0; // Update mappers and prepare mapper queue if (type == VtkPropRenderer::Opaque) this->PrepareMapperQueue(); //go through the generated list and let the sorted mappers paint bool lastVtkBased = true; bool sthVtkBased = false; for(MappersMapType::iterator it = m_MappersMap.begin(); it != m_MappersMap.end(); it++) { Mapper * mapper = (*it).second; - // MITK_INFO << "name " << mapper->GetNameOfClass(); if((mapper->IsVtkBased() == true) ) { sthVtkBased = true; mitk::VtkMapper3D::Pointer vtkMapper = dynamic_cast(mapper); if(vtkMapper) { vtkMapper->GetVtkProp(this)->SetAllocatedRenderTime(5000,GetVtkRenderer()); //B/ ToDo: rendering time calculation //vtkMapper->GetVtkProp(this)->PokeMatrix(NULL); //B/ ToDo ??: VtkUserTransform } if(lastVtkBased == false) { Disable2DOpenGL(); lastVtkBased = true; } } else if((mapper->IsVtkBased() == false) && (lastVtkBased == true)) { Enable2DOpenGL(); lastVtkBased = false; } - //Workarround for bug GL_TEXTURE_2D + //Workarround for bug GL_TEXTURE_2D (bug #8188) GLboolean mode; GLenum bit = GL_TEXTURE_2D; GLfloat lineWidth; glGetFloatv(GL_LINE_WIDTH, &lineWidth); glGetBooleanv(bit, &mode); - AdjustCameraToScene(); - switch(type) { case mitk::VtkPropRenderer::Opaque: mapper->MitkRenderOpaqueGeometry(this); break; case mitk::VtkPropRenderer::Translucent: mapper->MitkRenderTranslucentGeometry(this); break; case mitk::VtkPropRenderer::Overlay: mapper->MitkRenderOverlay(this); break; case mitk::VtkPropRenderer::Volumetric: mapper->MitkRenderVolumetricGeometry(this); break; } if(mode) glEnable(bit); else glDisable(bit); glLineWidth(lineWidth); + //end Workarround for bug GL_TEXTURE_2D (bug #8188) } if (lastVtkBased == false) Disable2DOpenGL(); // Render text if (type == VtkPropRenderer::Overlay) { if (m_TextCollection.size() > 0) { for (TextMapType::iterator it = m_TextCollection.begin(); it != m_TextCollection.end() ; it++) m_TextRenderer->AddViewProp((*it).second); m_TextRenderer->Render(); } } return 1; } /*! \brief PrepareMapperQueue iterates the datatree PrepareMapperQueue iterates the datatree in order to find mappers which shall be rendered. Also, it sortes the mappers wrt to their layer. */ void mitk::VtkPropRenderer::PrepareMapperQueue() { // variable for counting LOD-enabled mappers m_NumberOfVisibleLODEnabledMappers = 0; // Do we have to update the mappers ? - if ( m_LastUpdateTime < GetMTime() || m_LastUpdateTime < GetDisplayGeometry()->GetMTime() ) + if ( m_LastUpdateTime < GetMTime() || m_LastUpdateTime < GetDisplayGeometry()->GetMTime() ) { Update(); - else if (m_MapperID>=2 && m_MapperID < 6) + } + else if (m_MapperID>=1 && m_MapperID < 6) Update(); // remove all text properties before mappers will add new ones m_TextRenderer->RemoveAllViewProps(); for ( unsigned int i=0; iDelete(); } m_TextCollection.clear(); // clear priority_queue m_MappersMap.clear(); int mapperNo = 0; //DataStorage if( m_DataStorage.IsNull() ) return; DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for (DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it) { DataNode::Pointer node = it->Value(); if ( node.IsNull() ) continue; mitk::Mapper::Pointer mapper = node->GetMapper(m_MapperID); if ( mapper.IsNull() ) continue; // The information about LOD-enabled mappers is required by RenderingManager if ( mapper->IsLODEnabled( this ) && mapper->IsVisible( this ) ) { ++m_NumberOfVisibleLODEnabledMappers; } // mapper without a layer property get layer number 1 int layer = 1; node->GetIntProperty("layer", layer, this); int nr = (layer<<16) + mapperNo; - // MITK_INFO << "Layer Number " << nr << " Mapper type " << mapper->GetNameOfClass(); m_MappersMap.insert( std::pair< int, Mapper * >( nr, mapper ) ); mapperNo++; } } /*! \brief Enable2DOpenGL() and Disable2DOpenGL() are used to switch between 2D rendering (orthographic projection) and 3D rendering (perspective projection) */ void mitk::VtkPropRenderer::Enable2DOpenGL() { GLint iViewport[4]; // Get a copy of the viewport glGetIntegerv( GL_VIEWPORT, iViewport ); // Save a copy of the projection matrix so that we can restore it // when it's time to do 3D rendering again. glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); // Set up the orthographic projection glOrtho( iViewport[0], iViewport[0]+iViewport[2], iViewport[1], iViewport[1]+iViewport[3], -1.0, 1.0 ); glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glLoadIdentity(); // Make sure depth testing and lighting are disabled for 2D rendering until // we are finished rendering in 2D glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT ); glDisable( GL_DEPTH_TEST ); glDisable( GL_LIGHTING ); } /*! \brief Initialize the VtkPropRenderer Enable2DOpenGL() and Disable2DOpenGL() are used to switch between 2D rendering (orthographic projection) and 3D rendering (perspective projection) */ void mitk::VtkPropRenderer::Disable2DOpenGL() { glPopAttrib(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); glPopMatrix(); } void mitk::VtkPropRenderer::Update(mitk::DataNode* datatreenode) { if(datatreenode!=NULL) { mitk::Mapper::Pointer mapper = datatreenode->GetMapper(m_MapperID); if(mapper.IsNotNull()) { Mapper2D* mapper2d=dynamic_cast(mapper.GetPointer()); if(mapper2d != NULL) { if(GetDisplayGeometry()->IsValid()) { VtkMapper2D* vtkmapper2d=dynamic_cast(mapper.GetPointer()); if(vtkmapper2d != NULL) { vtkmapper2d->Update(this); m_VtkMapperPresent=true; } else mapper2d->Update(this); } } else { VtkMapper3D* vtkmapper3d=dynamic_cast(mapper.GetPointer()); if(vtkmapper3d != NULL) { vtkmapper3d->Update(this); vtkmapper3d->UpdateVtkTransform(this); m_VtkMapperPresent=true; } } } } } void mitk::VtkPropRenderer::Update() { if( m_DataStorage.IsNull() ) return; m_VtkMapperPresent = false; mitk::DataStorage::SetOfObjects::ConstPointer all = m_DataStorage->GetAll(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) Update(it->Value()); Modified(); m_LastUpdateTime = GetMTime(); } /*! \brief This method is called from the two Constructors */ void mitk::VtkPropRenderer::InitRenderer(vtkRenderWindow* renderWindow) { BaseRenderer::InitRenderer(renderWindow); if(renderWindow == NULL) { m_InitNeeded = false; m_ResizeNeeded = false; return; } m_InitNeeded = true; m_ResizeNeeded = true; m_LastUpdateTime = 0; } /*! \brief Resize the OpenGL Window */ void mitk::VtkPropRenderer::Resize(int w, int h) { BaseRenderer::Resize(w, h); m_RenderingManager->RequestUpdate(this->GetRenderWindow()); } void mitk::VtkPropRenderer::InitSize(int w, int h) { m_RenderWindow->SetSize(w,h); Superclass::InitSize(w, h); Modified(); Update(); if(m_VtkRenderer!=NULL) { int w=vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); m_VtkRenderer->ResetCamera(); vtkObject::SetGlobalWarningDisplay(w); } } void mitk::VtkPropRenderer::SetMapperID(const MapperSlotId mapperId) { if(m_MapperID != mapperId) Superclass::SetMapperID(mapperId); // Workaround for GL Displaylist Bug checkState(); } /*! \brief Activates the current renderwindow. */ void mitk::VtkPropRenderer::MakeCurrent() { if(m_RenderWindow!=NULL) m_RenderWindow->MakeCurrent(); } void mitk::VtkPropRenderer::PickWorldPoint(const mitk::Point2D& displayPoint, mitk::Point3D& worldPoint) const { if(m_VtkMapperPresent) { //m_WorldPointPicker->SetTolerance (0.0001); switch ( m_PickingMode ) { case (WorldPointPicking) : { m_WorldPointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer); vtk2itk(m_WorldPointPicker->GetPickPosition(), worldPoint); break; } case (PointPicking) : { // create a new vtkRenderer // give it all necessary information (camera position, etc.) // get all surfaces from datastorage, get actors from them // add all those actors to the new renderer // give this new renderer to pointpicker /* vtkRenderer* pickingRenderer = vtkRenderer::New(); pickingRenderer->SetActiveCamera( ); DataStorage* dataStorage = m_DataStorage; TNodePredicateDataType isSurface; DataStorage::SetOfObjects::ConstPointer allSurfaces = dataStorage->GetSubset( isSurface ); MITK_INFO << "in picking: got " << allSurfaces->size() << " surfaces." << std::endl; for (DataStorage::SetOfObjects::const_iterator iter = allSurfaces->begin(); iter != allSurfaces->end(); ++iter) { const DataNode* currentNode = *iter; VtkMapper3D* baseVtkMapper3D = dynamic_cast( currentNode->GetMapper( BaseRenderer::Standard3D ) ); if ( baseVtkMapper3D ) { vtkActor* actor = dynamic_cast( baseVtkMapper3D->GetViewProp() ); if (actor) { MITK_INFO << "a" << std::flush; pickingRenderer->AddActor( actor ); } } } MITK_INFO << ";" << std::endl; */ m_PointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer); vtk2itk(m_PointPicker->GetPickPosition(), worldPoint); break; } } } else { Superclass::PickWorldPoint(displayPoint, worldPoint); } } mitk::DataNode * mitk::VtkPropRenderer::PickObject( const Point2D &displayPosition, Point3D &worldPosition ) const { if ( m_VtkMapperPresent ) { m_CellPicker->InitializePickList(); // Iterate over all DataStorage objects to determine all vtkProps intended // for picking DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for ( DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it ) { DataNode *node = it->Value(); if ( node == NULL ) continue; bool pickable = false; node->GetBoolProperty( "pickable", pickable ); if ( !pickable ) continue; VtkMapper3D *mapper = dynamic_cast< VtkMapper3D * > ( node->GetMapper( m_MapperID ) ); if ( mapper == NULL ) continue; vtkProp *prop = mapper->GetVtkProp( (mitk::BaseRenderer *)this ); if ( prop == NULL ) continue; m_CellPicker->AddPickList( prop ); } // Do the picking and retrieve the picked vtkProp (if any) m_CellPicker->PickFromListOn(); m_CellPicker->Pick( displayPosition[0], displayPosition[1], 0.0, m_VtkRenderer ); m_CellPicker->PickFromListOff(); vtk2itk( m_CellPicker->GetPickPosition(), worldPosition ); vtkProp *prop = m_CellPicker->GetViewProp(); if ( prop == NULL ) { return NULL; } // Iterate over all DataStorage objects to determine if the retrieved // vtkProp is owned by any associated mapper. for ( DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it) { DataNode::Pointer node = it->Value(); if ( node.IsNull() ) continue; mitk::Mapper::Pointer mapper = node->GetMapper( m_MapperID ); if ( mapper.IsNull() ) continue; if ( mapper->HasVtkProp( prop, const_cast< mitk::VtkPropRenderer * >( this ) ) ) { return node; } } return NULL; } else { return Superclass::PickObject( displayPosition, worldPosition ); } }; /*! \brief Writes some 2D text as overlay. Function returns an unique int Text_ID for each call, which can be used via the GetTextLabelProperty(int text_id) function in order to get a vtkTextProperty. This property enables the setup of font, font size, etc. */ int mitk::VtkPropRenderer::WriteSimpleText(std::string text, double posX, double posY, double color1, double color2, double color3) { if(text.size() > 0) { vtkTextActor* textActor = vtkTextActor::New(); textActor->SetPosition(posX,posY); textActor->SetInput(text.c_str()); textActor->GetTextProperty()->SetColor(color1, color2, color3); //TODO: Read color from node property int text_id = m_TextCollection.size(); m_TextCollection.insert(TextMapType::value_type(text_id,textActor)); return text_id; } return -1; } /*! \brief Can be used in order to get a vtkTextProperty for a specific text_id. This property enables the setup of font, font size, etc. */ vtkTextProperty* mitk::VtkPropRenderer::GetTextLabelProperty(int text_id) { return this->m_TextCollection[text_id]->GetTextProperty(); } void mitk::VtkPropRenderer::InitPathTraversal() { if (m_DataStorage.IsNotNull()) { m_PickingObjects = m_DataStorage->GetAll(); m_PickingObjectsIterator = m_PickingObjects->begin(); } } vtkAssemblyPath* mitk::VtkPropRenderer::GetNextPath() { if (m_DataStorage.IsNull() ) { return NULL; } if ( m_PickingObjectsIterator == m_PickingObjects->end() ) { return NULL; } vtkAssemblyPath* returnPath = vtkAssemblyPath::New(); //returnPath->Register(NULL); bool success = false; while (!success) { // loop until AddNode can be called successfully const DataNode* node = *m_PickingObjectsIterator; if (node) { Mapper* mapper = node->GetMapper( BaseRenderer::Standard3D ); if (mapper) { VtkMapper3D* vtkmapper = dynamic_cast( mapper ); if (vtkmapper) { vtkProp* prop = vtkmapper->GetVtkProp(this); if ( prop && prop->GetVisibility() ) { // add to assembly path returnPath->AddNode( prop, prop->GetMatrix() ); success = true; } } } } ++m_PickingObjectsIterator; if ( m_PickingObjectsIterator == m_PickingObjects->end() ) break; } if ( success ) { return returnPath; } else { return NULL; } } void mitk::VtkPropRenderer::ReleaseGraphicsResources(vtkWindow *renWin) { if( m_DataStorage.IsNull() ) return; DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for (DataStorage::SetOfObjects::const_iterator iter = allObjects->begin(); iter != allObjects->end(); ++iter) { DataNode::Pointer node = *iter; if ( node.IsNull() ) continue; Mapper::Pointer mapper = node->GetMapper(m_MapperID); if(mapper.IsNotNull()) mapper->ReleaseGraphicsResources(renWin); } } const vtkWorldPointPicker *mitk::VtkPropRenderer::GetWorldPointPicker() const { return m_WorldPointPicker; } const vtkPointPicker *mitk::VtkPropRenderer::GetPointPicker() const { return m_PointPicker; } const vtkCellPicker *mitk::VtkPropRenderer::GetCellPicker() const { return m_CellPicker; } mitk::VtkPropRenderer::MappersMapType mitk::VtkPropRenderer::GetMappersMap() const { return m_MappersMap; } // Workaround for GL Displaylist bug static int glWorkAroundGlobalCount = 0; bool mitk::VtkPropRenderer::useImmediateModeRendering() { return glWorkAroundGlobalCount>1; } void mitk::VtkPropRenderer::checkState() { if (m_MapperID == Standard3D) { if (!didCount) { didCount = true; glWorkAroundGlobalCount++; if (glWorkAroundGlobalCount == 2) { MITK_INFO << "Multiple 3D Renderwindows active...: turning Immediate Rendering ON for legacy mappers"; // vtkMapper::GlobalImmediateModeRenderingOn(); } //MITK_INFO << "GLOBAL 3D INCREASE " << glWorkAroundGlobalCount << "\n"; } } else { if(didCount) { didCount=false; glWorkAroundGlobalCount--; if(glWorkAroundGlobalCount==1) { MITK_INFO << "Single 3D Renderwindow active...: turning Immediate Rendering OFF for legacy mappers"; // vtkMapper::GlobalImmediateModeRenderingOff(); } //MITK_INFO << "GLOBAL 3D DECREASE " << glWorkAroundGlobalCount << "\n"; } } } -void mitk::VtkPropRenderer::AdjustCameraToScene(){ - if(this->GetMapperID() == 1) +//### Contains all methods which are neceassry before each VTK Render() call +void mitk::VtkPropRenderer::PrepareRender() +{ + // if(!m_2DCameraInitialized) + // { + m_2DCameraInitialized = Initialize2DvtkCamera(); //Set parallel projection etc. TODO: call only once per RW + // } + AdjustCameraToScene(); //Prepare camera for 2D render windows +} + +bool mitk::VtkPropRenderer::Initialize2DvtkCamera(){ + if(this->GetMapperID() == Standard2D) { //activate parallel projection for 2D this->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(true); + //turn the light out in the scene in order to render correct grey values. + //TODO Implement a property for light in the 2D render windows (in another method) + this->GetVtkRenderer()->RemoveAllLights(); + //remove the VTK interaction + this->GetVtkRenderer()->GetRenderWindow()->SetInteractor(NULL); + } + return true; +} +void mitk::VtkPropRenderer::AdjustCameraToScene(){ + if(this->GetMapperID() == Standard2D) + { const mitk::DisplayGeometry* displayGeometry = this->GetDisplayGeometry(); - double objectHeightInMM = this->GetCurrentWorldGeometry2D()->GetExtentInMM(0);//the height of the current object slice in mm + double objectHeightInMM = this->GetCurrentWorldGeometry2D()->GetExtentInMM(1);//the height of the current object slice in mm double displayHeightInMM = displayGeometry->GetSizeInMM()[1]; //the display height in mm (gets smaller when you zoom in) double zoomFactor = objectHeightInMM/displayHeightInMM; //displayGeometry->GetScaleFactorMMPerDisplayUnit() //determine how much of the object can be displayed Vector2D displayGeometryOriginInMM = displayGeometry->GetOriginInMM(); //top left of the render window (Origin) Vector2D displayGeometryCenterInMM = displayGeometryOriginInMM + displayGeometry->GetSizeInMM()*0.5; //center of the render window: (Origin + Size/2) //Scale the rendered object: //The image is scaled by a single factor, because in an orthographic projection sizes //are preserved (so you cannot scale X and Y axis with different parameters). The //parameter sets the size of the total display-volume. If you set this to the image //height, the image plus a border with the size of the image will be rendered. //Therefore, the size is imageHeightInMM / 2. this->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(objectHeightInMM*0.5 ); //zooming with the factor calculated by dividing displayHeight through imegeHeight. The factor is inverse, because the VTK zoom method is working inversely. this->GetVtkRenderer()->GetActiveCamera()->Zoom(zoomFactor); //the center of the view-plane double viewPlaneCenter[3]; viewPlaneCenter[0] = displayGeometryCenterInMM[0]; viewPlaneCenter[1] = displayGeometryCenterInMM[1]; viewPlaneCenter[2] = 0.0; //the view-plane is located in the XY-plane with Z=0.0 //define which direction is "up" for the ciamera (like default for vtk (0.0, 1.0, 0.0) double cameraUp[3]; cameraUp[0] = 0.0; cameraUp[1] = 1.0; cameraUp[2] = 0.0; - //the position of the camera (center[0], center[1], 1000) + //the position of the camera (center[0], center[1], 900000) double cameraPosition[3]; cameraPosition[0] = viewPlaneCenter[0]; cameraPosition[1] = viewPlaneCenter[1]; cameraPosition[2] = 900000.0; //Reason for 900000: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823) in VTK bugtracker. //set the camera corresponding to the textured plane vtkSmartPointer camera = this->GetVtkRenderer()->GetActiveCamera(); if (camera) { camera->SetPosition( cameraPosition ); //set the camera position on the textured plane normal (in our case this is the view plane normal) camera->SetFocalPoint( viewPlaneCenter ); //set the focal point to the center of the textured plane camera->SetViewUp( cameraUp ); //set the view-up for the camera -// double distance = sqrt((cameraPosition[2]-viewPlaneCenter[2])*(cameraPosition[2]-viewPlaneCenter[2])); -// camera->SetClippingRange(distance-50, distance+50); //Reason for huge range: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823) in VTK bugtracker. + // double distance = sqrt((cameraPosition[2]-viewPlaneCenter[2])*(cameraPosition[2]-viewPlaneCenter[2])); + // camera->SetClippingRange(distance-50, distance+50); //Reason for huge range: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823) in VTK bugtracker. camera->SetClippingRange(0.1, 1000000); //Reason for huge range: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823) in VTK bugtracker. } - //turn the light out in the scene in order to render correct grey values. - //TODO Implement a property for light in the 2D render windows - this->GetVtkRenderer()->RemoveAllLights(); - - //remove the VTK interaction - this->GetVtkRenderer()->GetRenderWindow()->SetInteractor(NULL); - const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( this->GetCurrentWorldGeometry2D() ); if ( planeGeometry != NULL ) { //Transform the camera to the current position (transveral, coronal and saggital plane). //This is necessary, because the SetUserTransform() method does not manipulate the vtkCamera. //(Without not all three planes would be visible). vtkSmartPointer trans = vtkSmartPointer::New(); vtkSmartPointer matrix = vtkSmartPointer::New(); Point3D origin; Vector3D right, bottom, normal; origin = planeGeometry->GetOrigin(); right = planeGeometry->GetAxisVector( 0 ); // right = Extent of Image in mm (worldspace) bottom = planeGeometry->GetAxisVector( 1 ); normal = planeGeometry->GetNormal(); right.Normalize(); bottom.Normalize(); normal.Normalize(); matrix->SetElement(0, 0, right[0]); matrix->SetElement(1, 0, right[1]); matrix->SetElement(2, 0, right[2]); matrix->SetElement(0, 1, bottom[0]); matrix->SetElement(1, 1, bottom[1]); matrix->SetElement(2, 1, bottom[2]); matrix->SetElement(0, 2, normal[0]); matrix->SetElement(1, 2, normal[1]); matrix->SetElement(2, 2, normal[2]); matrix->SetElement(0, 3, origin[0]); matrix->SetElement(1, 3, origin[1]); matrix->SetElement(2, 3, origin[2]); matrix->SetElement(3, 0, 0.0); matrix->SetElement(3, 1, 0.0); matrix->SetElement(3, 2, 0.0); matrix->SetElement(3, 3, 1.0); trans->SetMatrix(matrix); //Transform the camera to the current position (transveral, coronal and saggital plane). this->GetVtkRenderer()->GetActiveCamera()->ApplyTransform(trans); } } } diff --git a/Core/Code/Rendering/mitkVtkPropRenderer.h b/Core/Code/Rendering/mitkVtkPropRenderer.h index 828c1a63e5..ed927b2ee3 100644 --- a/Core/Code/Rendering/mitkVtkPropRenderer.h +++ b/Core/Code/Rendering/mitkVtkPropRenderer.h @@ -1,233 +1,241 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2007-09-22 12:01:41 +0200 (Sa, 22 Sep 2007) $ Version: $Revision: 12241 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef MITKVtkPropRenderer_H_HEADER_INCLUDED_C1C29F6D #define MITKVtkPropRenderer_H_HEADER_INCLUDED_C1C29F6D #include "mitkCommon.h" #include "mitkBaseRenderer.h" #include "mitkDataStorage.h" #include "mitkRenderingManager.h" #include #include #include class vtkRenderWindow; class vtkLight; class vtkLightKit; class vtkWorldPointPicker; class vtkPointPicker; class vtkCellPicker; class vtkTextActor; class vtkTextProperty; class vtkAssemblyPath; namespace mitk { class Mapper; /*! \brief VtkPropRenderer VtkPropRenderer organizes the MITK rendering process. The MITK rendering process is completely integrated into the VTK rendering pipeline. The vtkMitkRenderProp is a custom vtkProp derived class, which implements the rendering interface between MITK and VTK. It redirects render() calls to the VtkPropRenderer, which is responsible for rendering of the datatreenodes. VtkPropRenderer replaces the old OpenGLRenderer. \sa rendering \ingroup rendering */ class MITK_CORE_EXPORT VtkPropRenderer : public BaseRenderer { // Workaround for Displaylistbug private: bool didCount; void checkState(); // Workaround END public: mitkClassMacro(VtkPropRenderer,BaseRenderer); mitkNewMacro3Param(VtkPropRenderer, const char*, vtkRenderWindow *, mitk::RenderingManager* ); typedef std::map MappersMapType; // Render - called by vtkMitkRenderProp, returns the number of props rendered enum RenderType{Opaque,Translucent,Overlay,Volumetric}; int Render(RenderType type); + /** \brief This methods contains all method neceassary before a VTK Render() call */ + virtual void PrepareRender(); + // Active current renderwindow virtual void MakeCurrent(); virtual void SetDataStorage( mitk::DataStorage* storage ); ///< set the datastorage that will be used for rendering virtual void InitRenderer(vtkRenderWindow* renderwindow); virtual void Update(mitk::DataNode* datatreenode); virtual void SetMapperID(const MapperSlotId mapperId); // Size virtual void InitSize(int w, int h); virtual void Resize(int w, int h); // Picking enum PickingMode{ WorldPointPicking, PointPicking }; itkSetEnumMacro( PickingMode, PickingMode ); itkGetEnumMacro( PickingMode, PickingMode ); virtual void PickWorldPoint(const Point2D& displayPoint, Point3D& worldPoint) const; virtual mitk::DataNode *PickObject( const Point2D &displayPosition, Point3D &worldPosition ) const; // Simple text rendering method int WriteSimpleText(std::string text, double posX, double posY, double color1 = 0.0, double color2 = 1.0, double color3 = 0.0); vtkTextProperty * GetTextLabelProperty(int text_id); // Initialization / geometry handling /** This method calculates the bounds of the DataStorage (if it contains any * valid data), creates a geometry from these bounds and sets it as world * geometry of the renderer. * * Call this method to re-initialize the renderer to the current DataStorage * (e.g. after loading an additional dataset), to ensure that the view is * aligned correctly. */ virtual bool SetWorldGeometryToDataStorageBounds(); /** * \brief Used by vtkPointPicker/vtkPicker. * This will query a list of all objects in MITK and provide every vtk based mapper to the picker. */ void InitPathTraversal(); /** * \brief Used by vtkPointPicker/vtkPicker. * This will query a list of all objects in MITK and provide every vtk based mapper to the picker. */ vtkAssemblyPath* GetNextPath(); const vtkWorldPointPicker *GetWorldPointPicker() const; const vtkPointPicker *GetPointPicker() const; const vtkCellPicker *GetCellPicker() const; /** * \brief Release vtk-based graphics resources. Called by * vtkMitkRenderProp::ReleaseGraphicsResources. */ virtual void ReleaseGraphicsResources(vtkWindow *renWin); MappersMapType GetMappersMap() const; static bool useImmediateModeRendering(); +protected: + VtkPropRenderer( const char* name = "VtkPropRenderer", vtkRenderWindow * renWin = NULL, mitk::RenderingManager* rm = NULL ); + virtual ~VtkPropRenderer(); + virtual void Update(); + +private: + /** \brief This method sets up the camera on the actor (e.g. an image) of all * 2D vtkRenderWindows. The view is centered; zooming and panning of VTK are called inside. * * \image html ImageMapperdisplayGeometry.png * * Similar to the textured plane of an image * (cf. void mitkImageVtkMapper2D::GeneratePlane(mitk::BaseRenderer* renderer, * vtkFloatingPointType planeBounds[6])), the mitkDisplayGeometry defines a view plane (or * projection plane). This plane is used to set the camera parameters. The view plane * center (VC) is important for camera positioning (cf. the image above). * * The following figure shows the combination of the textured plane and the view plane. * * \image html cameraPositioning.png * * The view plane center (VC) is the center of the textured plane (C) and the focal point - * (FP) at the same time. The FP defines which direction the camera faces. Since + * (FP) at the same time. The FP defines the direction the camera faces. Since * the textured plane is always in the XY-plane and orthographic projection is applied, the * distance between camera and plane is theoretically irrelevant (because in the orthographic * projection the center of projection is at infinity and the size of objects depends only on * a scaling parameter). As a consequence, the direction of projection (DOP) is (0; 0; -1). * The camera up vector is always defined as (0; 1; 0). * * \warning Due to a VTK clipping bug the distance between textured plane and camera is really huge. * Otherwise, VTK would clip off some slices. Same applies for the clipping range size. * * \note The camera position is defined through the mitkDisplayGeometry. * This facilitates zooming and panning, because the display * geometry changes and the textured plane does not. * * \image html scaling.png * * The textured plane is scaled to fill the render window via * camera->SetParallelScale( imageHeightInMM / 2). In the orthographic projection all extends, - * angles and sizes should be preserved. Therefore, the image is scaled by one parameter which defines + * angles and sizes are preserved. Therefore, the image is scaled by one parameter which defines * the size of the rendered image. A higher value will result in smaller images. In order to render - * just the whole image, the scale is set to half of the image height in worldcoordinates (cf. the picture above). + * just the whole image, the scale is set to half of the image height in worldcoordinates + * (cf. the picture above). * * For zooming purposes, a factor is computed as follows: * factor = image height / display height (in worldcoordinates). * When the display geometry gets smaller (zoom in), the factor becomes bigger. When the display - * geometry gets bigger (zoom out), the factor becoomes smaller. The used VTK method + * geometry gets bigger (zoom out), the factor becomes smaller. The used VTK method * camera->Zoom( factor ) also works with an inverse scale. */ void AdjustCameraToScene(); -protected: - VtkPropRenderer( const char* name = "VtkPropRenderer", vtkRenderWindow * renWin = NULL, mitk::RenderingManager* rm = NULL ); - virtual ~VtkPropRenderer(); - virtual void Update(); - -private: // switch between orthogonal opengl projection (2D rendering via mitk::GLMapper2D) and perspective projection (3D rendering) void Enable2DOpenGL(); void Disable2DOpenGL(); // prepare all mitk::mappers for rendering void PrepareMapperQueue(); + /** \brief Set parallel projection, remove the interactor and the lights of VTK. */ + bool Initialize2DvtkCamera(); bool m_InitNeeded; bool m_ResizeNeeded; bool m_VtkMapperPresent; bool m_NewRenderer; + bool m_2DCameraInitialized; // Picking vtkWorldPointPicker * m_WorldPointPicker; vtkPointPicker * m_PointPicker; vtkCellPicker * m_CellPicker; PickingMode m_PickingMode; // Explicit use of SmartPointer to avoid circular #includes itk::SmartPointer< mitk::Mapper > m_CurrentWorldGeometry2DMapper; vtkLightKit* m_LightKit; // sorted list of mappers MappersMapType m_MappersMap; // rendering of text vtkRenderer * m_TextRenderer; typedef std::map TextMapType; TextMapType m_TextCollection; DataStorage::SetOfObjects::ConstPointer m_PickingObjects; DataStorage::SetOfObjects::const_iterator m_PickingObjectsIterator; }; } // namespace mitk #endif /* MITKVtkPropRenderer_H_HEADER_INCLUDED_C1C29F6D */ diff --git a/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.cpp b/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.cpp index d545415721..d9643a8e2e 100644 --- a/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.cpp +++ b/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.cpp @@ -1,265 +1,266 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "vtkMitkApplyLevelWindowToRGBFilter.h" #include #include #include //used for acos etc. #include -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif +//used for PI +#include + +static const double PI = itk::Math::pi; vtkMitkApplyLevelWindowToRGBFilter::vtkMitkApplyLevelWindowToRGBFilter():m_MinOqacity(0.0),m_MaxOpacity(255.0) { } vtkMitkApplyLevelWindowToRGBFilter::~vtkMitkApplyLevelWindowToRGBFilter() { } void vtkMitkApplyLevelWindowToRGBFilter::SetLookupTable(vtkScalarsToColors *lookupTable) { m_LookupTable = lookupTable; } vtkScalarsToColors* vtkMitkApplyLevelWindowToRGBFilter::GetLookupTable() { return m_LookupTable; } //This code was copied from the iil. The template works only for float and double. //Internal method which should never be used anywhere else and should not be in th header. // Convert color pixels from (R,G,B) to (H,S,I). // Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002. template void RGBtoHSI(T* RGB, T* HSI) { T R = RGB[0], G = RGB[1], B = RGB[2], nR = (R<0?0:(R>255?255:R))/255, nG = (G<0?0:(G>255?255:G))/255, nB = (B<0?0:(B>255?255:B))/255, m = nR0) H = (nB<=nG)?theta:360-theta; if (sum>0) S = 1 - 3/sum*m; I = sum/3; HSI[0] = (T)H; HSI[1] = (T)S; HSI[2] = (T)I; } //This code was copied from the iil. The template works only for float and double. //Internal method which should never be used anywhere else and should not be in th header. // Convert color pixels from (H,S,I) to (R,G,B). template void HSItoRGB(T* HSI, T* RGB) { T H = (T)HSI[0], S = (T)HSI[1], I = (T)HSI[2], a = I*(1-S), R = 0, G = 0, B = 0; if (H<120) { B = a; - R = (T)(I*(1+S*std::cos(H*M_PI/180)/std::cos((60-H)*M_PI/180))); + R = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); G = 3*I-(R+B); } else if (H<240) { H-=120; R = a; - G = (T)(I*(1+S*std::cos(H*M_PI/180)/std::cos((60-H)*M_PI/180))); + G = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); B = 3*I-(R+G); } else { H-=240; G = a; - B = (T)(I*(1+S*std::cos(H*M_PI/180)/std::cos((60-H)*M_PI/180))); + B = (T)(I*(1+S*std::cos(H*PI/180)/std::cos((60-H)*PI/180))); R = 3*I-(G+B); } R*=255; G*=255; B*=255; RGB[0] = (T)(R<0?0:(R>255?255:R)); RGB[1] = (T)(G<0?0:(G>255?255:G)); RGB[2] = (T)(B<0?0:(B>255?255:B)); } //Internal method which should never be used anywhere else and should not be in th header. //---------------------------------------------------------------------------- // This templated function executes the filter for any type of data. template void vtkCalculateIntensityFromLookupTable(vtkMitkApplyLevelWindowToRGBFilter *self, vtkImageData *inData, vtkImageData *outData, int outExt[6], T *) { vtkImageIterator inputIt(inData, outExt); vtkImageIterator outputIt(outData, outExt); vtkLookupTable* lookupTable; int maxC; int indexComponents = 3; //RGB case double imgRange[2]; double tableRange[2]; lookupTable = dynamic_cast(self->GetLookupTable()); lookupTable->GetTableRange(tableRange); inData->GetScalarRange(imgRange); //parameters for RGB level window double scale = (tableRange[1] -tableRange[0] > 0 ? 255.0 / (tableRange[1] - tableRange[0]) : 0.0); double bias = tableRange[0] * scale; // find the region to loop over maxC = inData->GetNumberOfScalarComponents(); //parameters for opaque level window double scaleOpac = (self->GetMaxOpacity() -self->GetMinOpacity() > 0 ? 255.0 / (self->GetMaxOpacity() - self->GetMinOpacity()) : 0.0); double biasOpac = self->GetMinOpacity() * scaleOpac; // Loop through ouput pixels while (!outputIt.IsAtEnd()) { T* inputSI = inputIt.BeginSpan(); T* outputSI = outputIt.BeginSpan(); T* outputSIEnd = outputIt.EndSpan(); while (outputSI != outputSIEnd) { double rgb[3], alpha, hsi[3]; // level/window mechanism for intensity in HSI space rgb[0] = static_cast(*inputSI); inputSI++; rgb[1] = static_cast(*inputSI); inputSI++; rgb[2] = static_cast(*inputSI); inputSI++; RGBtoHSI(rgb,hsi); hsi[2] = hsi[2] * 255.0 * scale - bias; hsi[2] = (hsi[2] > 255.0 ? 255 : (hsi[2] < 0.0 ? 0 : hsi[2])); hsi[2] /= 255.0; HSItoRGB(hsi,rgb); *outputSI = static_cast(rgb[0]); outputSI++; *outputSI = static_cast(rgb[1]); outputSI++; *outputSI = static_cast(rgb[2]); outputSI++; //RGBA case if(maxC >= 4) { indexComponents = 4; //now its the RGBA case // level/window mechanism for opacity alpha = static_cast(*inputSI); inputSI++; alpha = alpha * scaleOpac - biasOpac; if(alpha > 255.0) { alpha = 255.0; } else if(alpha < 0.0) { alpha = 0.0; } *outputSI = static_cast(alpha); outputSI++; } for (int i = indexComponents; i < maxC; i++) { *outputSI++ = *inputSI++; } } inputIt.NextSpan(); outputIt.NextSpan(); } } void vtkMitkApplyLevelWindowToRGBFilter::ExecuteInformation() { vtkImageData *input = this->GetInput(); vtkImageData *output = this->GetOutput(); if (!input) { vtkErrorMacro(<< "Input not set."); return; } output->CopyTypeSpecificInformation( input ); int extent[6]; input->GetWholeExtent(extent); output->SetExtent(extent); output->SetWholeExtent(extent); output->SetUpdateExtent(extent); output->AllocateScalars(); switch (input->GetScalarType()) { vtkTemplateMacro( vtkCalculateIntensityFromLookupTable( this, input, output, extent, static_cast(0))); default: vtkErrorMacro(<< "Execute: Unknown ScalarType"); return; } } //Method to run the filter in different threads. void vtkMitkApplyLevelWindowToRGBFilter::ThreadedExecute(vtkImageData *inData, vtkImageData *outData, int extent[6], int id) { switch (inData->GetScalarType()) { vtkTemplateMacro( vtkCalculateIntensityFromLookupTable( this, inData, outData, extent, static_cast(0))); default: vtkErrorMacro(<< "Execute: Unknown ScalarType"); return; } } void vtkMitkApplyLevelWindowToRGBFilter::ExecuteInformation( vtkImageData *vtkNotUsed(inData), vtkImageData *vtkNotUsed(outData)) { } void vtkMitkApplyLevelWindowToRGBFilter::SetMinOpacity(double minOpacity) { m_MinOqacity = minOpacity; } inline double vtkMitkApplyLevelWindowToRGBFilter::GetMinOpacity() const { return m_MinOqacity; } void vtkMitkApplyLevelWindowToRGBFilter::SetMaxOpacity(double maxOpacity) { m_MaxOpacity = maxOpacity; } inline double vtkMitkApplyLevelWindowToRGBFilter::GetMaxOpacity() const { return m_MaxOpacity; } diff --git a/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.h b/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.h index 115f1542dc..36479ab6db 100644 --- a/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.h +++ b/Core/Code/Rendering/vtkMitkApplyLevelWindowToRGBFilter.h @@ -1,82 +1,81 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2009-07-14 19:11:20 +0200 (Tue, 14 Jul 2009) $ Version: $Revision: 18127 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef __vtkMitkApplyLevelWindowToRGBFilter_h #define __vtkMitkApplyLevelWindowToRGBFilter_h class vtkScalarsToColors; #include #include #include /** Documentation * \brief Applies the color and opacity level window to RGB(A) images. * * This filter is used to apply the color level window to RBG images (e.g. * diffusion tensor images). Therefore, the RGB channels are converted to * the HSI color space, where the level window can be applied. Afterwards, * the HSI values transformed back to the RGB space. * * The filter is also able to apply an opacity level window to RGBA images. * * \ingroup Renderer */ class MITK_CORE_EXPORT vtkMitkApplyLevelWindowToRGBFilter : public vtkImageToImageFilter { public: /** \brief Get the lookup table for the RGB level window */ vtkScalarsToColors* GetLookupTable(); /** \brief Set the lookup table for the RGB level window */ void SetLookupTable(vtkScalarsToColors *lookupTable); /** \brief Get/Set the lower window opacity for the alpha level window */ void SetMinOpacity(double minOpacity); inline double GetMinOpacity() const; /** \brief Get/Set the upper window opacity for the alpha level window */ void SetMaxOpacity(double maxOpacity); inline double GetMaxOpacity() const; /** Default constructor. */ vtkMitkApplyLevelWindowToRGBFilter(); -protected: /** Default deconstructor. */ ~vtkMitkApplyLevelWindowToRGBFilter(); - +protected: /** \brief Method for threaded execution of the filter. * \param *inData: The input. * \param *outData: The output of the filter. * \param extent[6]: Specefies the region of the image to be updated inside this thread. * It is a six-component array of the form (xmin, xmax, ymin, ymax, zmin, zmax). * \param id: The thread id. */ void ThreadedExecute(vtkImageData *inData, vtkImageData *outData,int extent[6], int id); /** Standard VTK filter method to apply the filter. See VTK documentation.*/ void ExecuteInformation(); /** Standard VTK filter method to apply the filter. See VTK documentation. Not used at the moment.*/ void ExecuteInformation(vtkImageData *vtkNotUsed(inData), vtkImageData *vtkNotUsed(outData)); private: /** m_LookupTable contains the lookup table for the RGB level window.*/ vtkScalarsToColors* m_LookupTable; /** m_MinOqacity contains the lower bound for the alpha level window.*/ double m_MinOqacity; /** m_MinOqacity contains the upper bound for the alpha level window.*/ double m_MaxOpacity; }; #endif diff --git a/CoreUI/Qmitk/QmitkRenderWindow.cpp b/CoreUI/Qmitk/QmitkRenderWindow.cpp index cbf299e93c..99d12b6c83 100644 --- a/CoreUI/Qmitk/QmitkRenderWindow.cpp +++ b/CoreUI/Qmitk/QmitkRenderWindow.cpp @@ -1,270 +1,278 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkRenderWindow.h" #include #include #include #include #include #include #include "QmitkEventAdapter.h" #include "QmitkRenderWindowMenu.h" QmitkRenderWindow::QmitkRenderWindow(QWidget *parent, QString name, mitk::VtkPropRenderer* /*renderer*/, mitk::RenderingManager* renderingManager ) : QVTKWidget(parent) , m_ResendQtEvents(true) , m_MenuWidget(NULL) , m_MenuWidgetActivated(false) , m_LayoutIndex(0) { Initialize( renderingManager, name.toStdString().c_str() ); // Initialize mitkRenderWindowBase setFocusPolicy(Qt::StrongFocus); setMouseTracking(true); } QmitkRenderWindow::~QmitkRenderWindow() { Destroy(); // Destroy mitkRenderWindowBase } void QmitkRenderWindow::SetResendQtEvents(bool resend) { m_ResendQtEvents = resend; } void QmitkRenderWindow::SetLayoutIndex( unsigned int layoutIndex ) { m_LayoutIndex = layoutIndex; if( m_MenuWidget ) m_MenuWidget->SetLayoutIndex(layoutIndex); } unsigned int QmitkRenderWindow::GetLayoutIndex() { if( m_MenuWidget ) return m_MenuWidget->GetLayoutIndex(); else return NULL; } void QmitkRenderWindow::LayoutDesignListChanged( int layoutDesignIndex ) { if( m_MenuWidget ) m_MenuWidget->UpdateLayoutDesignList( layoutDesignIndex ); } void QmitkRenderWindow::mousePressEvent(QMouseEvent *me) { mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); this->mousePressMitkEvent(&myevent); QVTKWidget::mousePressEvent(me); if (m_ResendQtEvents) me->ignore(); } void QmitkRenderWindow::mouseReleaseEvent(QMouseEvent *me) { mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); this->mouseReleaseMitkEvent(&myevent); QVTKWidget::mouseReleaseEvent(me); if (m_ResendQtEvents) me->ignore(); } void QmitkRenderWindow::mouseMoveEvent(QMouseEvent *me) { this->AdjustRenderWindowMenuVisibility( me->pos() ); mitk::MouseEvent myevent(QmitkEventAdapter::AdaptMouseEvent(m_Renderer, me)); this->mouseMoveMitkEvent(&myevent); QVTKWidget::mouseMoveEvent(me); //if (m_ResendQtEvents) me->ignore(); ////Show/Hide Menu Widget //if( m_MenuWidgetActivated ) //{ // //Show Menu Widget when mouse is inside of the define region of the top right corner // if( m_MenuWidget->GetLayoutIndex() <= QmitkRenderWindowMenu::CORONAL // && me->pos().x() >= 0 // && me->pos().y() <= m_MenuWidget->height() + 20 ) // { // m_MenuWidget->MoveWidgetToCorrectPos(1.0); // m_MenuWidget->show(); // m_MenuWidget->update(); // } // else if( m_MenuWidget->GetLayoutIndex() == QmitkRenderWindowMenu::THREE_D // && me->pos().x() >= this->width() - m_MenuWidget->width() - 20 // && me->pos().y() <= m_MenuWidget->height() + 20 ) // { // m_MenuWidget->MoveWidgetToCorrectPos(1.0); // m_MenuWidget->show(); // m_MenuWidget->update(); // } // //Hide Menu Widget when mouse is outside of the define region of the the right corner // else if( !m_MenuWidget->GetSettingsMenuVisibilty() ) // { // m_MenuWidget->hide(); // } //} } void QmitkRenderWindow::wheelEvent(QWheelEvent *we) { mitk::WheelEvent myevent(QmitkEventAdapter::AdaptWheelEvent(m_Renderer, we)); this->wheelMitkEvent(&myevent); QVTKWidget::wheelEvent(we); if (m_ResendQtEvents) we->ignore(); } void QmitkRenderWindow::keyPressEvent(QKeyEvent *ke) { QPoint cp = mapFromGlobal(QCursor::pos()); mitk::KeyEvent mke(QmitkEventAdapter::AdaptKeyEvent(m_Renderer, ke, cp)); this->keyPressMitkEvent(&mke); ke->accept(); QVTKWidget::keyPressEvent(ke); if (m_ResendQtEvents) ke->ignore(); } void QmitkRenderWindow::enterEvent( QEvent *e ) { MITK_DEBUG << "rw enter Event"; QVTKWidget::enterEvent(e); } void QmitkRenderWindow::DeferredHideMenu( ) { MITK_DEBUG << "QmitkRenderWindow::DeferredHideMenu"; if( m_MenuWidget ) m_MenuWidget->HideMenu(); } void QmitkRenderWindow::leaveEvent( QEvent *e ) { MITK_DEBUG << "QmitkRenderWindow::leaveEvent"; if( m_MenuWidget ) m_MenuWidget->smoothHide(); QVTKWidget::leaveEvent(e); } +void QmitkRenderWindow::paintEvent(QPaintEvent* event) +{ + //Before the paint event is passed to Qt the VTK camera etc. has to be prepared. +// mitk::RenderingManager::GetInstance()->RequestUpdate(GetRenderWindow()); + GetRenderer()->PrepareRender(); + QVTKWidget::paintEvent(event); +} + void QmitkRenderWindow::resizeEvent(QResizeEvent* event) { this->resizeMitkEvent(event->size().width(), event->size().height()); QVTKWidget::resizeEvent(event); - + emit resized(); } void QmitkRenderWindow::moveEvent( QMoveEvent* event ) { QVTKWidget::moveEvent( event ); // after a move the overlays need to be positioned emit moved(); } void QmitkRenderWindow::showEvent( QShowEvent* event ) { QVTKWidget::showEvent( event ); // this singleshot is necessary to have the overlays positioned correctly after initial show // simple call of moved() is no use here!! QTimer::singleShot(0, this ,SIGNAL( moved() ) ); } void QmitkRenderWindow::ActivateMenuWidget( bool state ) { m_MenuWidgetActivated = state; if(!m_MenuWidgetActivated && m_MenuWidget) { //disconnect Signal/Slot Connection disconnect( m_MenuWidget, SIGNAL( SignalChangeLayoutDesign(int) ), this, SLOT(OnChangeLayoutDesign(int)) ); disconnect( m_MenuWidget, SIGNAL( ResetView() ), this, SIGNAL( ResetView()) ); disconnect( m_MenuWidget, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SIGNAL( ChangeCrosshairRotationMode(int)) ); delete m_MenuWidget; m_MenuWidget = 0; } else if(m_MenuWidgetActivated && !m_MenuWidget ) { //create render window MenuBar for split, close Window or set new setting. m_MenuWidget = new QmitkRenderWindowMenu(this,0,m_Renderer); m_MenuWidget->SetLayoutIndex( m_LayoutIndex ); //create Signal/Slot Connection connect( m_MenuWidget, SIGNAL( SignalChangeLayoutDesign(int) ), this, SLOT(OnChangeLayoutDesign(int)) ); connect( m_MenuWidget, SIGNAL( ResetView() ), this, SIGNAL( ResetView()) ); connect( m_MenuWidget, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SIGNAL( ChangeCrosshairRotationMode(int)) ); } } void QmitkRenderWindow::AdjustRenderWindowMenuVisibility( const QPoint& pos ) { if( m_MenuWidget ) { m_MenuWidget->ShowMenu(); m_MenuWidget->MoveWidgetToCorrectPos(1.0f); } } void QmitkRenderWindow::HideRenderWindowMenu( ) { // DEPRECATED METHOD } void QmitkRenderWindow::OnChangeLayoutDesign( int layoutDesignIndex ) { emit SignalLayoutDesignChanged( layoutDesignIndex ); } void QmitkRenderWindow::OnWidgetPlaneModeChanged( int mode ) { if( m_MenuWidget ) m_MenuWidget->NotifyNewWidgetPlanesMode( mode ); } void QmitkRenderWindow::FullScreenMode(bool state) { if( m_MenuWidget ) m_MenuWidget->ChangeFullScreenMode( state ); } diff --git a/CoreUI/Qmitk/QmitkRenderWindow.h b/CoreUI/Qmitk/QmitkRenderWindow.h index eee25435e4..c74b712a2c 100644 --- a/CoreUI/Qmitk/QmitkRenderWindow.h +++ b/CoreUI/Qmitk/QmitkRenderWindow.h @@ -1,152 +1,148 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef QMITKRENDERWINDOW_H_HEADER_INCLUDED_C1C40D66 #define QMITKRENDERWINDOW_H_HEADER_INCLUDED_C1C40D66 #include "mitkCommon.h" #include "mitkRenderWindowBase.h" #include "QVTKWidget.h" #include "QmitkRenderWindowMenu.h" /** * \brief MITK implementation of the QVTKWidget * \ingroup Renderer */ class QMITK_EXPORT QmitkRenderWindow : public QVTKWidget , public mitk::RenderWindowBase { Q_OBJECT public: QmitkRenderWindow(QWidget *parent = 0, QString name = "unnamed renderwindow", mitk::VtkPropRenderer* renderer = NULL, mitk::RenderingManager* renderingManager = NULL); virtual ~QmitkRenderWindow(); /** * \brief Whether Qt events should be passed to parent (default: true) * * With introduction of the QVTKWidget the behaviour regarding Qt events changed. * QVTKWidget "accepts" Qt events like mouse clicks (i.e. set an "accepted" flag). * When this flag is set, Qt fininshed handling of this event -- otherwise it is * reached through to the widget's parent. * * This reaching through to the parent was implicitly required by QmitkMaterialWidget / QmitkMaterialShowCase. * * The default behaviour of QmitkRenderWindow is now to clear the "accepted" flag * of Qt events after they were handled by QVTKWidget. This way parents can also * handle events. * * If you don't want this behaviour, call SetResendQtEvents(true) on your render window. */ virtual void SetResendQtEvents(bool resend); // Set Layout Index to define the Layout Type void SetLayoutIndex( unsigned int layoutIndex ); // Get Layout Index to define the Layout Type unsigned int GetLayoutIndex(); //MenuWidget need to update the Layout Design List when Layout had changed void LayoutDesignListChanged( int layoutDesignIndex ); void HideRenderWindowMenu( ); //Activate or Deactivate MenuWidget. void ActivateMenuWidget( bool state ); bool GetActivateMenuWidgetFlag() { return m_MenuWidgetActivated; } // Get it from the QVTKWidget parent virtual vtkRenderWindow* GetVtkRenderWindow() { return GetRenderWindow();} virtual vtkRenderWindowInteractor* GetVtkRenderWindowInteractor() { return NULL;} void FullScreenMode( bool state ); protected: - // overloaded move handler virtual void moveEvent( QMoveEvent* event ); - // overloaded show handler void showEvent( QShowEvent* event ); - - // overloaded resize handler virtual void resizeEvent(QResizeEvent* event); - + // overloaded paint handler + virtual void paintEvent(QPaintEvent* event); // overloaded mouse press handler virtual void mousePressEvent(QMouseEvent* event); // overloaded mouse move handler virtual void mouseMoveEvent(QMouseEvent* event); // overloaded mouse release handler virtual void mouseReleaseEvent(QMouseEvent* event); // overloaded key press handler virtual void keyPressEvent(QKeyEvent* event); - // overloaded enter handler virtual void enterEvent(QEvent*); // overloaded leave handler virtual void leaveEvent(QEvent*); #ifndef QT_NO_WHEELEVENT // overload wheel mouse event virtual void wheelEvent(QWheelEvent*); #endif void AdjustRenderWindowMenuVisibility( const QPoint& pos ); signals: void ResetView(); // \brief int parameters are enum from QmitkStdMultiWidget void ChangeCrosshairRotationMode(int); void SignalLayoutDesignChanged( int layoutDesignIndex ); void moved(); void resized(); protected slots: void OnChangeLayoutDesign(int layoutDesignIndex); void OnWidgetPlaneModeChanged( int ); void DeferredHideMenu(); private: bool m_ResendQtEvents; QmitkRenderWindowMenu* m_MenuWidget; bool m_MenuWidgetActivated; unsigned int m_LayoutIndex; }; -#endif \ No newline at end of file +#endif diff --git a/CoreUI/Qmitk/QmitkStdMultiWidget.cpp b/CoreUI/Qmitk/QmitkStdMultiWidget.cpp index 27b772b323..10d6487fcf 100644 --- a/CoreUI/Qmitk/QmitkStdMultiWidget.cpp +++ b/CoreUI/Qmitk/QmitkStdMultiWidget.cpp @@ -1,2124 +1,2117 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #define SMW_INFO MITK_INFO("widget.stdmulti") #include "QmitkStdMultiWidget.h" #include #include #include #include #include #include #include #include #include "mitkProperties.h" #include "mitkGeometry2DDataMapper2D.h" #include "mitkGlobalInteraction.h" #include "mitkDisplayInteractor.h" #include "mitkPointSet.h" #include "mitkPositionEvent.h" #include "mitkStateEvent.h" #include "mitkLine.h" #include "mitkInteractionConst.h" #include "mitkDataStorage.h" #include "mitkNodePredicateBase.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateProperty.h" #include "mitkStatusBar.h" #include "mitkImage.h" #include "mitkVtkLayerController.h" -//vtk -#include -#include -#include -#include - QmitkStdMultiWidget::QmitkStdMultiWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), mitkWidget1(NULL), mitkWidget2(NULL), mitkWidget3(NULL), mitkWidget4(NULL), m_PlaneNode1(NULL), m_PlaneNode2(NULL), m_PlaneNode3(NULL), m_Node(NULL), m_PendingCrosshairPositionEvent(false) { /*******************************/ //Create Widget manually /*******************************/ //create Layouts QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //Set Layout to widget this->setLayout(QmitkStdMultiWidgetLayout); // QmitkNavigationToolBar* toolBar = new QmitkNavigationToolBar(); // QmitkStdMultiWidgetLayout->addWidget( toolBar ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //creae Widget Container mitkWidget1Container = new QWidget(m_SubSplit1); mitkWidget2Container = new QWidget(m_SubSplit1); mitkWidget3Container = new QWidget(m_SubSplit2); mitkWidget4Container = new QWidget(m_SubSplit2); mitkWidget1Container->setContentsMargins(0,0,0,0); mitkWidget2Container->setContentsMargins(0,0,0,0); mitkWidget3Container->setContentsMargins(0,0,0,0); mitkWidget4Container->setContentsMargins(0,0,0,0); //create Widget Layout QHBoxLayout *mitkWidgetLayout1 = new QHBoxLayout(mitkWidget1Container); QHBoxLayout *mitkWidgetLayout2 = new QHBoxLayout(mitkWidget2Container); QHBoxLayout *mitkWidgetLayout3 = new QHBoxLayout(mitkWidget3Container); QHBoxLayout *mitkWidgetLayout4 = new QHBoxLayout(mitkWidget4Container); mitkWidgetLayout1->setMargin(0); mitkWidgetLayout2->setMargin(0); mitkWidgetLayout3->setMargin(0); mitkWidgetLayout4->setMargin(0); //set Layout to Widget Container mitkWidget1Container->setLayout(mitkWidgetLayout1); mitkWidget2Container->setLayout(mitkWidgetLayout2); mitkWidget3Container->setLayout(mitkWidgetLayout3); mitkWidget4Container->setLayout(mitkWidgetLayout4); //set SizePolicy mitkWidget1Container->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); mitkWidget2Container->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); mitkWidget3Container->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); mitkWidget4Container->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); //insert Widget Container into the splitters m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit2->addWidget( mitkWidget3Container ); m_SubSplit2->addWidget( mitkWidget4Container ); // mitk::RenderingManager::GetInstance()->SetGlobalInteraction( mitk::GlobalInteraction::GetInstance() ); //Create RenderWindows 1 mitkWidget1 = new QmitkRenderWindow(mitkWidget1Container, "stdmulti.widget1"); mitkWidget1->setMaximumSize(2000,2000); mitkWidget1->SetLayoutIndex( TRANSVERSAL ); mitkWidgetLayout1->addWidget(mitkWidget1); //Create RenderWindows 2 mitkWidget2 = new QmitkRenderWindow(mitkWidget2Container, "stdmulti.widget2"); mitkWidget2->setMaximumSize(2000,2000); mitkWidget2->setEnabled( TRUE ); mitkWidget2->SetLayoutIndex( SAGITTAL ); mitkWidgetLayout2->addWidget(mitkWidget2); //Create RenderWindows 3 mitkWidget3 = new QmitkRenderWindow(mitkWidget3Container, "stdmulti.widget3"); mitkWidget3->setMaximumSize(2000,2000); mitkWidget3->SetLayoutIndex( CORONAL ); mitkWidgetLayout3->addWidget(mitkWidget3); //Create RenderWindows 4 mitkWidget4 = new QmitkRenderWindow(mitkWidget4Container, "stdmulti.widget4"); mitkWidget4->setMaximumSize(2000,2000); mitkWidget4->SetLayoutIndex( THREE_D ); mitkWidgetLayout4->addWidget(mitkWidget4); //create SignalSlot Connection connect( mitkWidget1, SIGNAL( SignalLayoutDesignChanged(int) ), this, SLOT( OnLayoutDesignChanged(int) ) ); connect( mitkWidget1, SIGNAL( ResetView() ), this, SLOT( ResetCrosshair() ) ); connect( mitkWidget1, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SLOT( SetWidgetPlaneMode(int) ) ); connect( this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget1, SLOT(OnWidgetPlaneModeChanged(int)) ); connect( mitkWidget2, SIGNAL( SignalLayoutDesignChanged(int) ), this, SLOT( OnLayoutDesignChanged(int) ) ); connect( mitkWidget2, SIGNAL( ResetView() ), this, SLOT( ResetCrosshair() ) ); connect( mitkWidget2, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SLOT( SetWidgetPlaneMode(int) ) ); connect( this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget2, SLOT(OnWidgetPlaneModeChanged(int)) ); connect( mitkWidget3, SIGNAL( SignalLayoutDesignChanged(int) ), this, SLOT( OnLayoutDesignChanged(int) ) ); connect( mitkWidget3, SIGNAL( ResetView() ), this, SLOT( ResetCrosshair() ) ); connect( mitkWidget3, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SLOT( SetWidgetPlaneMode(int) ) ); connect( this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget3, SLOT(OnWidgetPlaneModeChanged(int)) ); connect( mitkWidget4, SIGNAL( SignalLayoutDesignChanged(int) ), this, SLOT( OnLayoutDesignChanged(int) ) ); connect( mitkWidget4, SIGNAL( ResetView() ), this, SLOT( ResetCrosshair() ) ); connect( mitkWidget4, SIGNAL( ChangeCrosshairRotationMode(int) ), this, SLOT( SetWidgetPlaneMode(int) ) ); connect( this, SIGNAL(WidgetNotifyNewCrossHairMode(int)), mitkWidget4, SLOT(OnWidgetPlaneModeChanged(int)) ); //Create Level Window Widget levelWindowWidget = new QmitkLevelWindowWidget( m_MainSplit ); //this levelWindowWidget->setObjectName(QString::fromUtf8("levelWindowWidget")); QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); sizePolicy.setHeightForWidth(levelWindowWidget->sizePolicy().hasHeightForWidth()); levelWindowWidget->setSizePolicy(sizePolicy); levelWindowWidget->setMaximumSize(QSize(50, 2000)); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //show mainSplitt and add to Layout m_MainSplit->show(); //resize Image. this->resize( QSize(364, 477).expandedTo(minimumSizeHint()) ); //Initialize the widgets. this->InitializeWidget(); //Activate Widget Menu this->ActivateMenuWidget( true ); } void QmitkStdMultiWidget::InitializeWidget() { m_PositionTracker = NULL; // transfer colors in WorldGeometry-Nodes of the associated Renderer QColor qcolor; //float color[3] = {1.0f,1.0f,1.0f}; mitk::DataNode::Pointer planeNode; mitk::IntProperty::Pointer layer; // of widget 1 planeNode = mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetCurrentWorldGeometry2DNode(); planeNode->SetColor(1.0,0.0,0.0); layer = mitk::IntProperty::New(1000); planeNode->SetProperty("layer",layer); // ... of widget 2 planeNode = mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->GetCurrentWorldGeometry2DNode(); planeNode->SetColor(0.0,1.0,0.0); layer = mitk::IntProperty::New(1000); planeNode->SetProperty("layer",layer); // ... of widget 3 planeNode = mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->GetCurrentWorldGeometry2DNode(); planeNode->SetColor(0.0,0.0,1.0); layer = mitk::IntProperty::New(1000); planeNode->SetProperty("layer",layer); // ... of widget 4 planeNode = mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->GetCurrentWorldGeometry2DNode(); planeNode->SetColor(1.0,1.0,0.0); layer = mitk::IntProperty::New(1000); planeNode->SetProperty("layer",layer); mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->SetMapperID(mitk::BaseRenderer::Standard3D); -// mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->SetMapperID(mitk::BaseRenderer::Extended2D); // Set plane mode (slicing/rotation behavior) to slicing (default) m_PlaneMode = PLANE_MODE_SLICING; // Set default view directions for SNCs mitkWidget1->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Transversal ); mitkWidget2->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Sagittal ); mitkWidget3->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Frontal ); mitkWidget4->GetSliceNavigationController()->SetDefaultViewDirection( mitk::SliceNavigationController::Original ); /*************************************************/ //Write Layout Names into the viewers -- hardCoded //Info for later: //int view = this->GetRenderWindow1()->GetSliceNavigationController()->GetDefaultViewDirection(); //QString layoutName; //if( view == mitk::SliceNavigationController::Transversal ) // layoutName = "Transversal"; //else if( view == mitk::SliceNavigationController::Sagittal ) // layoutName = "Sagittal"; //else if( view == mitk::SliceNavigationController::Frontal ) // layoutName = "Coronal"; //else if( view == mitk::SliceNavigationController::Original ) // layoutName = "Original"; //if( view >= 0 && view < 4 ) // //write LayoutName --> Viewer 3D shoudn't write the layoutName. //Render Window 1 == transversal m_CornerAnnotaions[0].cornerText = vtkCornerAnnotation::New(); m_CornerAnnotaions[0].cornerText->SetText(0, "Transversal"); m_CornerAnnotaions[0].cornerText->SetMaximumFontSize(12); m_CornerAnnotaions[0].textProp = vtkTextProperty::New(); m_CornerAnnotaions[0].textProp->SetColor( 1.0, 0.0, 0.0 ); m_CornerAnnotaions[0].cornerText->SetTextProperty( m_CornerAnnotaions[0].textProp ); m_CornerAnnotaions[0].ren = vtkRenderer::New(); m_CornerAnnotaions[0].ren->AddActor(m_CornerAnnotaions[0].cornerText); m_CornerAnnotaions[0].ren->InteractiveOff(); mitk::VtkLayerController::GetInstance(this->GetRenderWindow1()->GetRenderWindow())->InsertForegroundRenderer(m_CornerAnnotaions[0].ren,true); //Render Window 2 == sagittal m_CornerAnnotaions[1].cornerText = vtkCornerAnnotation::New(); m_CornerAnnotaions[1].cornerText->SetText(0, "Sagittal"); m_CornerAnnotaions[1].cornerText->SetMaximumFontSize(12); m_CornerAnnotaions[1].textProp = vtkTextProperty::New(); m_CornerAnnotaions[1].textProp->SetColor( 0.0, 1.0, 0.0 ); m_CornerAnnotaions[1].cornerText->SetTextProperty( m_CornerAnnotaions[1].textProp ); m_CornerAnnotaions[1].ren = vtkRenderer::New(); m_CornerAnnotaions[1].ren->AddActor(m_CornerAnnotaions[1].cornerText); m_CornerAnnotaions[1].ren->InteractiveOff(); mitk::VtkLayerController::GetInstance(this->GetRenderWindow2()->GetRenderWindow())->InsertForegroundRenderer(m_CornerAnnotaions[1].ren,true); //Render Window 3 == coronal m_CornerAnnotaions[2].cornerText = vtkCornerAnnotation::New(); m_CornerAnnotaions[2].cornerText->SetText(0, "Coronal"); m_CornerAnnotaions[2].cornerText->SetMaximumFontSize(12); m_CornerAnnotaions[2].textProp = vtkTextProperty::New(); m_CornerAnnotaions[2].textProp->SetColor( 0.295, 0.295, 1.0 ); m_CornerAnnotaions[2].cornerText->SetTextProperty( m_CornerAnnotaions[2].textProp ); m_CornerAnnotaions[2].ren = vtkRenderer::New(); m_CornerAnnotaions[2].ren->AddActor(m_CornerAnnotaions[2].cornerText); m_CornerAnnotaions[2].ren->InteractiveOff(); mitk::VtkLayerController::GetInstance(this->GetRenderWindow3()->GetRenderWindow())->InsertForegroundRenderer(m_CornerAnnotaions[2].ren,true); /*************************************************/ // create a slice rotator // m_SlicesRotator = mitk::SlicesRotator::New(); // @TODO next line causes sure memory leak // rotator will be created nonetheless (will be switched on and off) m_SlicesRotator = mitk::SlicesRotator::New("slices-rotator"); m_SlicesRotator->AddSliceController( mitkWidget1->GetSliceNavigationController() ); m_SlicesRotator->AddSliceController( mitkWidget2->GetSliceNavigationController() ); m_SlicesRotator->AddSliceController( mitkWidget3->GetSliceNavigationController() ); // create a slice swiveller (using the same state-machine as SlicesRotator) m_SlicesSwiveller = mitk::SlicesSwiveller::New("slices-rotator"); m_SlicesSwiveller->AddSliceController( mitkWidget1->GetSliceNavigationController() ); m_SlicesSwiveller->AddSliceController( mitkWidget2->GetSliceNavigationController() ); m_SlicesSwiveller->AddSliceController( mitkWidget3->GetSliceNavigationController() ); //initialize m_TimeNavigationController: send time via sliceNavigationControllers m_TimeNavigationController = mitk::SliceNavigationController::New("dummy"); m_TimeNavigationController->ConnectGeometryTimeEvent( mitkWidget1->GetSliceNavigationController() , false); m_TimeNavigationController->ConnectGeometryTimeEvent( mitkWidget2->GetSliceNavigationController() , false); m_TimeNavigationController->ConnectGeometryTimeEvent( mitkWidget3->GetSliceNavigationController() , false); m_TimeNavigationController->ConnectGeometryTimeEvent( mitkWidget4->GetSliceNavigationController() , false); mitkWidget1->GetSliceNavigationController() ->ConnectGeometrySendEvent(mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); // Set TimeNavigationController to RenderingManager // (which uses it internally for views initialization!) mitk::RenderingManager::GetInstance()->SetTimeNavigationController( m_TimeNavigationController ); //reverse connection between sliceNavigationControllers and m_TimeNavigationController mitkWidget1->GetSliceNavigationController() ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); mitkWidget2->GetSliceNavigationController() ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); mitkWidget3->GetSliceNavigationController() ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); mitkWidget4->GetSliceNavigationController() ->ConnectGeometryTimeEvent(m_TimeNavigationController.GetPointer(), false); // instantiate display interactor m_MoveAndZoomInteractor = mitk::DisplayVectorInteractor::New( "moveNzoom", new mitk::DisplayInteractor() ); m_LastLeftClickPositionSupplier = mitk::CoordinateSupplier::New("navigation", NULL); mitk::GlobalInteraction::GetInstance()->AddListener( m_LastLeftClickPositionSupplier ); // setup gradient background m_GradientBackground1 = mitk::GradientBackground::New(); m_GradientBackground1->SetRenderWindow( mitkWidget1->GetRenderWindow() ); m_GradientBackground1->Disable(); m_GradientBackground2 = mitk::GradientBackground::New(); m_GradientBackground2->SetRenderWindow( mitkWidget2->GetRenderWindow() ); m_GradientBackground2->Disable(); m_GradientBackground3 = mitk::GradientBackground::New(); m_GradientBackground3->SetRenderWindow( mitkWidget3->GetRenderWindow() ); m_GradientBackground3->Disable(); m_GradientBackground4 = mitk::GradientBackground::New(); m_GradientBackground4->SetRenderWindow( mitkWidget4->GetRenderWindow() ); m_GradientBackground4->SetGradientColors(0.1,0.1,0.1,0.5,0.5,0.5); m_GradientBackground4->Enable(); // setup the department logo rendering m_LogoRendering1 = mitk::ManufacturerLogo::New(); m_LogoRendering1->SetRenderWindow( mitkWidget1->GetRenderWindow() ); m_LogoRendering1->Disable(); m_LogoRendering2 = mitk::ManufacturerLogo::New(); m_LogoRendering2->SetRenderWindow( mitkWidget2->GetRenderWindow() ); m_LogoRendering2->Disable(); m_LogoRendering3 = mitk::ManufacturerLogo::New(); m_LogoRendering3->SetRenderWindow( mitkWidget3->GetRenderWindow() ); m_LogoRendering3->Disable(); m_LogoRendering4 = mitk::ManufacturerLogo::New(); m_LogoRendering4->SetRenderWindow( mitkWidget4->GetRenderWindow() ); m_LogoRendering4->Enable(); m_RectangleRendering1 = mitk::RenderWindowFrame::New(); m_RectangleRendering1->SetRenderWindow( mitkWidget1->GetRenderWindow() ); m_RectangleRendering1->Enable(1.0,0.0,0.0); m_RectangleRendering2 = mitk::RenderWindowFrame::New(); m_RectangleRendering2->SetRenderWindow( mitkWidget2->GetRenderWindow() ); m_RectangleRendering2->Enable(0.0,1.0,0.0); m_RectangleRendering3 = mitk::RenderWindowFrame::New(); m_RectangleRendering3->SetRenderWindow( mitkWidget3->GetRenderWindow() ); m_RectangleRendering3->Enable(0.0,0.0,1.0); m_RectangleRendering4 = mitk::RenderWindowFrame::New(); m_RectangleRendering4->SetRenderWindow( mitkWidget4->GetRenderWindow() ); m_RectangleRendering4->Enable(1.0,1.0,0.0); } QmitkStdMultiWidget::~QmitkStdMultiWidget() { DisablePositionTracking(); DisableNavigationControllerEventListening(); mitk::VtkLayerController::GetInstance(this->GetRenderWindow1()->GetRenderWindow())->RemoveRenderer( m_CornerAnnotaions[0].ren ); mitk::VtkLayerController::GetInstance(this->GetRenderWindow2()->GetRenderWindow())->RemoveRenderer( m_CornerAnnotaions[1].ren ); mitk::VtkLayerController::GetInstance(this->GetRenderWindow3()->GetRenderWindow())->RemoveRenderer( m_CornerAnnotaions[2].ren ); //Delete CornerAnnotation m_CornerAnnotaions[0].cornerText->Delete(); m_CornerAnnotaions[0].textProp->Delete(); m_CornerAnnotaions[0].ren->Delete(); m_CornerAnnotaions[1].cornerText->Delete(); m_CornerAnnotaions[1].textProp->Delete(); m_CornerAnnotaions[1].ren->Delete(); m_CornerAnnotaions[2].cornerText->Delete(); m_CornerAnnotaions[2].textProp->Delete(); m_CornerAnnotaions[2].ren->Delete(); } void QmitkStdMultiWidget::RemovePlanesFromDataStorage() { if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_Node.IsNotNull()) { if(m_DataStorage.IsNotNull()) { m_DataStorage->Remove(m_PlaneNode1); m_DataStorage->Remove(m_PlaneNode2); m_DataStorage->Remove(m_PlaneNode3); m_DataStorage->Remove(m_Node); } } } void QmitkStdMultiWidget::AddPlanesToDataStorage() { if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_Node.IsNotNull()) { if (m_DataStorage.IsNotNull()) { m_DataStorage->Add(m_Node); m_DataStorage->Add(m_PlaneNode1, m_Node); m_DataStorage->Add(m_PlaneNode2, m_Node); m_DataStorage->Add(m_PlaneNode3, m_Node); static_cast(m_PlaneNode1->GetMapper(mitk::BaseRenderer::Standard2D))->SetDatastorageAndGeometryBaseNode(m_DataStorage, m_Node); static_cast(m_PlaneNode2->GetMapper(mitk::BaseRenderer::Standard2D))->SetDatastorageAndGeometryBaseNode(m_DataStorage, m_Node); static_cast(m_PlaneNode3->GetMapper(mitk::BaseRenderer::Standard2D))->SetDatastorageAndGeometryBaseNode(m_DataStorage, m_Node); } } } void QmitkStdMultiWidget::changeLayoutTo2DImagesUp() { SMW_INFO << "changing layout to 2D images up... " << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //Set Layout to widget this->setLayout(QmitkStdMultiWidgetLayout); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //insert Widget Container into splitter top m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit1->addWidget( mitkWidget3Container ); //set SplitterSize for splitter top QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit1->setSizes( splitterSize ); //insert Widget Container into splitter bottom m_SubSplit2->addWidget( mitkWidget4Container ); //set SplitterSize for splitter m_LayoutSplit splitterSize.clear(); splitterSize.push_back(400); splitterSize.push_back(1000); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt m_MainSplit->show(); //show Widget if hidden if ( mitkWidget1->isHidden() ) mitkWidget1->show(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); //Change Layout Name m_Layout = LAYOUT_2D_IMAGES_UP; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_2D_IMAGES_UP ); mitkWidget2->LayoutDesignListChanged( LAYOUT_2D_IMAGES_UP ); mitkWidget3->LayoutDesignListChanged( LAYOUT_2D_IMAGES_UP ); mitkWidget4->LayoutDesignListChanged( LAYOUT_2D_IMAGES_UP ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutTo2DImagesLeft() { SMW_INFO << "changing layout to 2D images left... " << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( Qt::Vertical, m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //insert Widget into the splitters m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit1->addWidget( mitkWidget3Container ); //set splitterSize of SubSplit1 QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit1->setSizes( splitterSize ); m_SubSplit2->addWidget( mitkWidget4Container ); //set splitterSize of Layout Split splitterSize.clear(); splitterSize.push_back(400); splitterSize.push_back(1000); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show Widget if hidden if ( mitkWidget1->isHidden() ) mitkWidget1->show(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); //update Layout Name m_Layout = LAYOUT_2D_IMAGES_LEFT; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_2D_IMAGES_LEFT ); mitkWidget2->LayoutDesignListChanged( LAYOUT_2D_IMAGES_LEFT ); mitkWidget3->LayoutDesignListChanged( LAYOUT_2D_IMAGES_LEFT ); mitkWidget4->LayoutDesignListChanged( LAYOUT_2D_IMAGES_LEFT ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToDefault() { SMW_INFO << "changing layout to default... " << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //insert Widget container into the splitters m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit2->addWidget( mitkWidget3Container ); m_SubSplit2->addWidget( mitkWidget4Container ); //set splitter Size QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit1->setSizes( splitterSize ); m_SubSplit2->setSizes( splitterSize ); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show Widget if hidden if ( mitkWidget1->isHidden() ) mitkWidget1->show(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_DEFAULT; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_DEFAULT ); mitkWidget2->LayoutDesignListChanged( LAYOUT_DEFAULT ); mitkWidget3->LayoutDesignListChanged( LAYOUT_DEFAULT ); mitkWidget4->LayoutDesignListChanged( LAYOUT_DEFAULT ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToBig3D() { SMW_INFO << "changing layout to big 3D ..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //add widget Splitter to main Splitter m_MainSplit->addWidget( mitkWidget4Container ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets mitkWidget1->hide(); mitkWidget2->hide(); mitkWidget3->hide(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_BIG_3D; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_BIG_3D ); mitkWidget2->LayoutDesignListChanged( LAYOUT_BIG_3D ); mitkWidget3->LayoutDesignListChanged( LAYOUT_BIG_3D ); mitkWidget4->LayoutDesignListChanged( LAYOUT_BIG_3D ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToWidget1() { SMW_INFO << "changing layout to big Widget1 ..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //add widget Splitter to main Splitter m_MainSplit->addWidget( mitkWidget1Container ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets if ( mitkWidget1->isHidden() ) mitkWidget1->show(); mitkWidget2->hide(); mitkWidget3->hide(); mitkWidget4->hide(); m_Layout = LAYOUT_WIDGET1; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_WIDGET1 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_WIDGET1 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_WIDGET1 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_WIDGET1 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToWidget2() { SMW_INFO << "changing layout to big Widget2 ..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //add widget Splitter to main Splitter m_MainSplit->addWidget( mitkWidget2Container ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets mitkWidget1->hide(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); mitkWidget3->hide(); mitkWidget4->hide(); m_Layout = LAYOUT_WIDGET2; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_WIDGET2 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_WIDGET2 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_WIDGET2 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_WIDGET2 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToWidget3() { SMW_INFO << "changing layout to big Widget3 ..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //add widget Splitter to main Splitter m_MainSplit->addWidget( mitkWidget3Container ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets mitkWidget1->hide(); mitkWidget2->hide(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); mitkWidget4->hide(); m_Layout = LAYOUT_WIDGET3; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_WIDGET3 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_WIDGET3 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_WIDGET3 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_WIDGET3 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToRowWidget3And4() { SMW_INFO << "changing layout to Widget3 and 4 in a Row..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //add Widgets to splitter m_LayoutSplit->addWidget( mitkWidget3Container ); m_LayoutSplit->addWidget( mitkWidget4Container ); //set Splitter Size QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets mitkWidget1->hide(); mitkWidget2->hide(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_ROW_WIDGET_3_AND_4; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_ROW_WIDGET_3_AND_4 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_ROW_WIDGET_3_AND_4 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_ROW_WIDGET_3_AND_4 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_ROW_WIDGET_3_AND_4 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToColumnWidget3And4() { SMW_INFO << "changing layout to Widget3 and 4 in one Column..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //add Widgets to splitter m_LayoutSplit->addWidget( mitkWidget3Container ); m_LayoutSplit->addWidget( mitkWidget4Container ); //set SplitterSize QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets mitkWidget1->hide(); mitkWidget2->hide(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_COLUMN_WIDGET_3_AND_4; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_COLUMN_WIDGET_3_AND_4 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_COLUMN_WIDGET_3_AND_4 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_COLUMN_WIDGET_3_AND_4 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_COLUMN_WIDGET_3_AND_4 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToRowWidgetSmall3andBig4() { SMW_INFO << "changing layout to Widget3 and 4 in a Row..." << std::endl; this->changeLayoutToRowWidget3And4(); m_Layout = LAYOUT_ROW_WIDGET_SMALL3_AND_BIG4; } void QmitkStdMultiWidget::changeLayoutToSmallUpperWidget2Big3and4() { SMW_INFO << "changing layout to Widget3 and 4 in a Row..." << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( Qt::Vertical, m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //insert Widget into the splitters m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit2->addWidget( mitkWidget3Container ); m_SubSplit2->addWidget( mitkWidget4Container ); //set Splitter Size QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit2->setSizes( splitterSize ); splitterSize.clear(); splitterSize.push_back(500); splitterSize.push_back(1000); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt m_MainSplit->show(); //show Widget if hidden mitkWidget1->hide(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); if ( mitkWidget3->isHidden() ) mitkWidget3->show(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4 ); mitkWidget2->LayoutDesignListChanged( LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4 ); mitkWidget3->LayoutDesignListChanged( LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4 ); mitkWidget4->LayoutDesignListChanged( LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4 ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutTo2x2Dand3DWidget() { SMW_INFO << "changing layout to 2 x 2D and 3D Widget" << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( Qt::Vertical, m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //add Widgets to splitter m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget2Container ); m_SubSplit2->addWidget( mitkWidget4Container ); //set Splitter Size QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit1->setSizes( splitterSize ); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets if ( mitkWidget1->isHidden() ) mitkWidget1->show(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); mitkWidget3->hide(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_2X_2D_AND_3D_WIDGET; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_2X_2D_AND_3D_WIDGET ); mitkWidget2->LayoutDesignListChanged( LAYOUT_2X_2D_AND_3D_WIDGET ); mitkWidget3->LayoutDesignListChanged( LAYOUT_2X_2D_AND_3D_WIDGET ); mitkWidget4->LayoutDesignListChanged( LAYOUT_2X_2D_AND_3D_WIDGET ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutToLeft2Dand3DRight2D() { SMW_INFO << "changing layout to 2D and 3D left, 2D right Widget" << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( Qt::Vertical, m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //add Widgets to splitter m_SubSplit1->addWidget( mitkWidget1Container ); m_SubSplit1->addWidget( mitkWidget4Container ); m_SubSplit2->addWidget( mitkWidget2Container ); //set Splitter Size QList splitterSize; splitterSize.push_back(1000); splitterSize.push_back(1000); m_SubSplit1->setSizes( splitterSize ); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt and add to Layout m_MainSplit->show(); //show/hide Widgets if ( mitkWidget1->isHidden() ) mitkWidget1->show(); if ( mitkWidget2->isHidden() ) mitkWidget2->show(); mitkWidget3->hide(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET ); mitkWidget2->LayoutDesignListChanged( LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET ); mitkWidget3->LayoutDesignListChanged( LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET ); mitkWidget4->LayoutDesignListChanged( LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET ); //update Alle Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::changeLayoutTo2DUpAnd3DDown() { SMW_INFO << "changing layout to 2D up and 3D down" << std::endl; //Hide all Menu Widgets this->HideAllWidgetToolbars(); delete QmitkStdMultiWidgetLayout ; //create Main Layout QmitkStdMultiWidgetLayout = new QHBoxLayout( this ); //Set Layout to widget this->setLayout(QmitkStdMultiWidgetLayout); //create main splitter m_MainSplit = new QSplitter( this ); QmitkStdMultiWidgetLayout->addWidget( m_MainSplit ); //create m_LayoutSplit and add to the mainSplit m_LayoutSplit = new QSplitter( Qt::Vertical, m_MainSplit ); m_MainSplit->addWidget( m_LayoutSplit ); //add LevelWindow Widget to mainSplitter m_MainSplit->addWidget( levelWindowWidget ); //create m_SubSplit1 and m_SubSplit2 m_SubSplit1 = new QSplitter( m_LayoutSplit ); m_SubSplit2 = new QSplitter( m_LayoutSplit ); //insert Widget Container into splitter top m_SubSplit1->addWidget( mitkWidget1Container ); //set SplitterSize for splitter top QList splitterSize; // splitterSize.push_back(1000); // splitterSize.push_back(1000); // splitterSize.push_back(1000); // m_SubSplit1->setSizes( splitterSize ); //insert Widget Container into splitter bottom m_SubSplit2->addWidget( mitkWidget4Container ); //set SplitterSize for splitter m_LayoutSplit splitterSize.clear(); splitterSize.push_back(700); splitterSize.push_back(700); m_LayoutSplit->setSizes( splitterSize ); //show mainSplitt m_MainSplit->show(); //show/hide Widgets if ( mitkWidget1->isHidden() ) mitkWidget1->show(); mitkWidget2->hide(); mitkWidget3->hide(); if ( mitkWidget4->isHidden() ) mitkWidget4->show(); m_Layout = LAYOUT_2D_UP_AND_3D_DOWN; //update Layout Design List mitkWidget1->LayoutDesignListChanged( LAYOUT_2D_UP_AND_3D_DOWN ); mitkWidget2->LayoutDesignListChanged( LAYOUT_2D_UP_AND_3D_DOWN ); mitkWidget3->LayoutDesignListChanged( LAYOUT_2D_UP_AND_3D_DOWN ); mitkWidget4->LayoutDesignListChanged( LAYOUT_2D_UP_AND_3D_DOWN ); //update all Widgets this->UpdateAllWidgets(); } void QmitkStdMultiWidget::SetDataStorage( mitk::DataStorage* ds ) { mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->SetDataStorage(ds); mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->SetDataStorage(ds); mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->SetDataStorage(ds); mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->SetDataStorage(ds); m_DataStorage = ds; } void QmitkStdMultiWidget::Fit() { vtkRenderer * vtkrenderer; mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetDisplayGeometry()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->GetDisplayGeometry()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->GetDisplayGeometry()->Fit(); mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->GetDisplayGeometry()->Fit(); int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkrenderer = mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())->GetVtkRenderer(); if ( vtkrenderer!= NULL ) vtkrenderer->ResetCamera(); vtkObject::SetGlobalWarningDisplay(w); } void QmitkStdMultiWidget::InitPositionTracking() { //PoinSetNode for MouseOrientation m_PositionTrackerNode = mitk::DataNode::New(); m_PositionTrackerNode->SetProperty("name", mitk::StringProperty::New("Mouse Position")); m_PositionTrackerNode->SetData( mitk::PointSet::New() ); m_PositionTrackerNode->SetColor(1.0,0.33,0.0); m_PositionTrackerNode->SetProperty("layer", mitk::IntProperty::New(1001)); m_PositionTrackerNode->SetVisibility(true); m_PositionTrackerNode->SetProperty("inputdevice", mitk::BoolProperty::New(true) ); m_PositionTrackerNode->SetProperty("BaseRendererMapperID", mitk::IntProperty::New(0) );//point position 2D mouse m_PositionTrackerNode->SetProperty("baserenderer", mitk::StringProperty::New("N/A")); } void QmitkStdMultiWidget::AddDisplayPlaneSubTree() { // add the displayed planes of the multiwidget to a node to which the subtree // @a planesSubTree points ... float white[3] = {1.0f,1.0f,1.0f}; mitk::Geometry2DDataMapper2D::Pointer mapper; // ... of widget 1 m_PlaneNode1 = (mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow()))->GetCurrentWorldGeometry2DNode(); m_PlaneNode1->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); m_PlaneNode1->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode1->SetProperty("name", mitk::StringProperty::New("widget1Plane")); m_PlaneNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::Geometry2DDataMapper2D::New(); m_PlaneNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 2 m_PlaneNode2 =( mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow()))->GetCurrentWorldGeometry2DNode(); m_PlaneNode2->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); m_PlaneNode2->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode2->SetProperty("name", mitk::StringProperty::New("widget2Plane")); m_PlaneNode2->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode2->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::Geometry2DDataMapper2D::New(); m_PlaneNode2->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 3 m_PlaneNode3 = (mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow()))->GetCurrentWorldGeometry2DNode(); m_PlaneNode3->SetColor(white, mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); m_PlaneNode3->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode3->SetProperty("name", mitk::StringProperty::New("widget3Plane")); m_PlaneNode3->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode3->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::Geometry2DDataMapper2D::New(); m_PlaneNode3->SetMapper(mitk::BaseRenderer::Standard2D, mapper); m_Node = mitk::DataNode::New(); m_Node->SetProperty("name", mitk::StringProperty::New("Widgets")); m_Node->SetProperty("helper object", mitk::BoolProperty::New(true)); } mitk::SliceNavigationController* QmitkStdMultiWidget::GetTimeNavigationController() { return m_TimeNavigationController.GetPointer(); } void QmitkStdMultiWidget::EnableStandardLevelWindow() { levelWindowWidget->disconnect(this); levelWindowWidget->SetDataStorage(mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow())->GetDataStorage()); levelWindowWidget->show(); } void QmitkStdMultiWidget::DisableStandardLevelWindow() { levelWindowWidget->disconnect(this); levelWindowWidget->hide(); } // CAUTION: Legacy code for enabling Qt-signal-controlled view initialization. // Use RenderingManager::InitializeViews() instead. bool QmitkStdMultiWidget::InitializeStandardViews( const mitk::Geometry3D * geometry ) { return mitk::RenderingManager::GetInstance()->InitializeViews( geometry ); } void QmitkStdMultiWidget::RequestUpdate() { mitk::RenderingManager::GetInstance()->RequestUpdate(mitkWidget1->GetRenderWindow()); mitk::RenderingManager::GetInstance()->RequestUpdate(mitkWidget2->GetRenderWindow()); mitk::RenderingManager::GetInstance()->RequestUpdate(mitkWidget3->GetRenderWindow()); mitk::RenderingManager::GetInstance()->RequestUpdate(mitkWidget4->GetRenderWindow()); } void QmitkStdMultiWidget::ForceImmediateUpdate() { mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(mitkWidget1->GetRenderWindow()); mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(mitkWidget2->GetRenderWindow()); mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(mitkWidget3->GetRenderWindow()); mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(mitkWidget4->GetRenderWindow()); } void QmitkStdMultiWidget::wheelEvent( QWheelEvent * e ) { emit WheelMoved( e ); } void QmitkStdMultiWidget::mousePressEvent(QMouseEvent * e) { if (e->button() == Qt::LeftButton) { mitk::Point3D pointValue = this->GetLastLeftClickPosition(); emit LeftMouseClicked(pointValue); } } void QmitkStdMultiWidget::moveEvent( QMoveEvent* e ) { QWidget::moveEvent( e ); // it is necessary to readjust the position of the overlays as the StdMultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } void QmitkStdMultiWidget::leaveEvent ( QEvent * /*e*/ ) { //set cursor back to initial state m_SlicesRotator->ResetMouseCursor(); } mitk::DisplayVectorInteractor* QmitkStdMultiWidget::GetMoveAndZoomInteractor() { return m_MoveAndZoomInteractor.GetPointer(); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow1() const { return mitkWidget1; } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow2() const { return mitkWidget2; } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow3() const { return mitkWidget3; } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow4() const { return mitkWidget4; } const mitk::Point3D& QmitkStdMultiWidget::GetLastLeftClickPosition() const { return m_LastLeftClickPositionSupplier->GetCurrentPoint(); } const mitk::Point3D QmitkStdMultiWidget::GetCrossPosition() const { const mitk::PlaneGeometry *plane1 = mitkWidget1->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry *plane2 = mitkWidget2->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry *plane3 = mitkWidget3->GetSliceNavigationController()->GetCurrentPlaneGeometry(); mitk::Line3D line; if ( (plane1 != NULL) && (plane2 != NULL) && (plane1->IntersectionLine( plane2, line )) ) { mitk::Point3D point; if ( (plane3 != NULL) && (plane3->IntersectionPoint( line, point )) ) { return point; } } return m_LastLeftClickPositionSupplier->GetCurrentPoint(); } void QmitkStdMultiWidget::EnablePositionTracking() { if (!m_PositionTracker) { m_PositionTracker = mitk::PositionTracker::New("PositionTracker", NULL); } mitk::GlobalInteraction* globalInteraction = mitk::GlobalInteraction::GetInstance(); if (globalInteraction) { if(m_DataStorage.IsNotNull()) m_DataStorage->Add(m_PositionTrackerNode); globalInteraction->AddListener(m_PositionTracker); } } void QmitkStdMultiWidget::DisablePositionTracking() { mitk::GlobalInteraction* globalInteraction = mitk::GlobalInteraction::GetInstance(); if(globalInteraction) { if (m_DataStorage.IsNotNull()) m_DataStorage->Remove(m_PositionTrackerNode); globalInteraction->RemoveListener(m_PositionTracker); } } void QmitkStdMultiWidget::EnsureDisplayContainsPoint( mitk::DisplayGeometry* displayGeometry, const mitk::Point3D& p) { mitk::Point2D pointOnPlane; displayGeometry->Map( p, pointOnPlane ); // point minus origin < width or height ==> outside ? mitk::Vector2D pointOnRenderWindow_MM; pointOnRenderWindow_MM = pointOnPlane.GetVectorFromOrigin() - displayGeometry->GetOriginInMM(); mitk::Vector2D sizeOfDisplay( displayGeometry->GetSizeInMM() ); if ( sizeOfDisplay[0] < pointOnRenderWindow_MM[0] || 0 > pointOnRenderWindow_MM[0] || sizeOfDisplay[1] < pointOnRenderWindow_MM[1] || 0 > pointOnRenderWindow_MM[1] ) { // point is not visible -> move geometry mitk::Vector2D offset( (pointOnRenderWindow_MM - sizeOfDisplay / 2.0) / displayGeometry->GetScaleFactorMMPerDisplayUnit() ); displayGeometry->MoveBy( offset ); } } void QmitkStdMultiWidget::MoveCrossToPosition(const mitk::Point3D& newPosition) { // create a PositionEvent with the given position and // tell the slice navigation controllers to move there mitk::Point2D p2d; mitk::PositionEvent event( mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow()), 0, 0, 0, mitk::Key_unknown, p2d, newPosition ); mitk::StateEvent stateEvent(mitk::EIDLEFTMOUSEBTN, &event); mitk::StateEvent stateEvent2(mitk::EIDLEFTMOUSERELEASE, &event); switch ( m_PlaneMode ) { default: case PLANE_MODE_SLICING: mitkWidget1->GetSliceNavigationController()->HandleEvent( &stateEvent ); mitkWidget2->GetSliceNavigationController()->HandleEvent( &stateEvent ); mitkWidget3->GetSliceNavigationController()->HandleEvent( &stateEvent ); // just in case SNCs will develop something that depends on the mouse // button being released again mitkWidget1->GetSliceNavigationController()->HandleEvent( &stateEvent2 ); mitkWidget2->GetSliceNavigationController()->HandleEvent( &stateEvent2 ); mitkWidget3->GetSliceNavigationController()->HandleEvent( &stateEvent2 ); break; case PLANE_MODE_ROTATION: m_SlicesRotator->HandleEvent( &stateEvent ); // just in case SNCs will develop something that depends on the mouse // button being released again m_SlicesRotator->HandleEvent( &stateEvent2 ); break; case PLANE_MODE_SWIVEL: m_SlicesSwiveller->HandleEvent( &stateEvent ); // just in case SNCs will develop something that depends on the mouse // button being released again m_SlicesSwiveller->HandleEvent( &stateEvent2 ); break; } // determine if cross is now out of display // if so, move the display window EnsureDisplayContainsPoint( mitk::BaseRenderer::GetInstance(mitkWidget1->GetRenderWindow()) ->GetDisplayGeometry(), newPosition ); EnsureDisplayContainsPoint( mitk::BaseRenderer::GetInstance(mitkWidget2->GetRenderWindow()) ->GetDisplayGeometry(), newPosition ); EnsureDisplayContainsPoint( mitk::BaseRenderer::GetInstance(mitkWidget3->GetRenderWindow()) ->GetDisplayGeometry(), newPosition ); // update displays mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkStdMultiWidget::HandleCrosshairPositionEvent() { if(!m_PendingCrosshairPositionEvent) { m_PendingCrosshairPositionEvent=true; QTimer::singleShot(0,this,SLOT( HandleCrosshairPositionEventDelayed() ) ); } } void QmitkStdMultiWidget::HandleCrosshairPositionEventDelayed() { m_PendingCrosshairPositionEvent = false; // find image with highest layer mitk::Point3D crosshairPos = this->GetCrossPosition(); mitk::TNodePredicateDataType::Pointer isImageData = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->m_DataStorage->GetSubset(isImageData).GetPointer(); std::string statusText; mitk::Image::Pointer image3D; int maxlayer = -32768; mitk::BaseRenderer* baseRenderer = this->mitkWidget1->GetSliceNavigationController()->GetRenderer(); // find image with largest layer, that is the image shown on top in the render window for (unsigned int x = 0; x < nodes->size(); x++) { if(nodes->at(x)->GetData()->GetGeometry()->IsInside(crosshairPos)) { int layer = 0; if(!(nodes->at(x)->GetIntProperty("layer", layer))) continue; if(layer > maxlayer) { if( static_cast(nodes->at(x))->IsVisible( baseRenderer ) ) { image3D = dynamic_cast(nodes->at(x)->GetData()); maxlayer = layer; } } } } std::stringstream stream; // get the position and gray value from the image and build up status bar text mitk::Index3D p; if(image3D.IsNotNull()) { image3D->GetGeometry()->WorldToIndex(crosshairPos, p); stream.precision(2); stream<<"Position: <"< mm"; stream<<"; Index: <"< "; stream<<"; Time: " << baseRenderer->GetTime() << " ms; Pixelvalue: "<GetPixelValueByIndex(p, baseRenderer->GetTimeStep())<<" "; } else { stream << "No image information at this position!"; } statusText = stream.str(); mitk::StatusBar::GetInstance()->DisplayGreyValueText(statusText.c_str()); } void QmitkStdMultiWidget::EnableNavigationControllerEventListening() { // Let NavigationControllers listen to GlobalInteraction mitk::GlobalInteraction *gi = mitk::GlobalInteraction::GetInstance(); // Listen for SliceNavigationController mitkWidget1->GetSliceNavigationController()->crosshairPositionEvent.AddListener( mitk::MessageDelegate( this, &QmitkStdMultiWidget::HandleCrosshairPositionEvent ) ); mitkWidget2->GetSliceNavigationController()->crosshairPositionEvent.AddListener( mitk::MessageDelegate( this, &QmitkStdMultiWidget::HandleCrosshairPositionEvent ) ); mitkWidget3->GetSliceNavigationController()->crosshairPositionEvent.AddListener( mitk::MessageDelegate( this, &QmitkStdMultiWidget::HandleCrosshairPositionEvent ) ); switch ( m_PlaneMode ) { default: case PLANE_MODE_SLICING: gi->AddListener( mitkWidget1->GetSliceNavigationController() ); gi->AddListener( mitkWidget2->GetSliceNavigationController() ); gi->AddListener( mitkWidget3->GetSliceNavigationController() ); gi->AddListener( mitkWidget4->GetSliceNavigationController() ); break; case PLANE_MODE_ROTATION: gi->AddListener( m_SlicesRotator ); break; case PLANE_MODE_SWIVEL: gi->AddListener( m_SlicesSwiveller ); break; } gi->AddListener( m_TimeNavigationController ); } void QmitkStdMultiWidget::DisableNavigationControllerEventListening() { // Do not let NavigationControllers listen to GlobalInteraction mitk::GlobalInteraction *gi = mitk::GlobalInteraction::GetInstance(); switch ( m_PlaneMode ) { default: case PLANE_MODE_SLICING: gi->RemoveListener( mitkWidget1->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget2->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget3->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget4->GetSliceNavigationController() ); break; case PLANE_MODE_ROTATION: m_SlicesRotator->ResetMouseCursor(); gi->RemoveListener( m_SlicesRotator ); break; case PLANE_MODE_SWIVEL: m_SlicesSwiveller->ResetMouseCursor(); gi->RemoveListener( m_SlicesSwiveller ); break; } gi->RemoveListener( m_TimeNavigationController ); } int QmitkStdMultiWidget::GetLayout() const { return m_Layout; } void QmitkStdMultiWidget::EnableGradientBackground() { // gradient background is by default only in widget 4, otherwise // interferences between 2D rendering and VTK rendering may occur. //m_GradientBackground1->Enable(); //m_GradientBackground2->Enable(); //m_GradientBackground3->Enable(); m_GradientBackground4->Enable(); } void QmitkStdMultiWidget::DisableGradientBackground() { //m_GradientBackground1->Disable(); //m_GradientBackground2->Disable(); //m_GradientBackground3->Disable(); m_GradientBackground4->Disable(); } void QmitkStdMultiWidget::EnableDepartmentLogo() { m_LogoRendering4->Enable(); } void QmitkStdMultiWidget::DisableDepartmentLogo() { m_LogoRendering4->Disable(); } mitk::SlicesRotator * QmitkStdMultiWidget::GetSlicesRotator() const { return m_SlicesRotator; } mitk::SlicesSwiveller * QmitkStdMultiWidget::GetSlicesSwiveller() const { return m_SlicesSwiveller; } void QmitkStdMultiWidget::SetWidgetPlaneVisibility(const char* widgetName, bool visible, mitk::BaseRenderer *renderer) { if (m_DataStorage.IsNotNull()) { mitk::DataNode* n = m_DataStorage->GetNamedNode(widgetName); if (n != NULL) n->SetVisibility(visible, renderer); } } void QmitkStdMultiWidget::SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer) { SetWidgetPlaneVisibility("widget1Plane", visible, renderer); SetWidgetPlaneVisibility("widget2Plane", visible, renderer); SetWidgetPlaneVisibility("widget3Plane", visible, renderer); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkStdMultiWidget::SetWidgetPlanesLocked(bool locked) { //do your job and lock or unlock slices. GetRenderWindow1()->GetSliceNavigationController()->SetSliceLocked(locked); GetRenderWindow2()->GetSliceNavigationController()->SetSliceLocked(locked); GetRenderWindow3()->GetSliceNavigationController()->SetSliceLocked(locked); } void QmitkStdMultiWidget::SetWidgetPlanesRotationLocked(bool locked) { //do your job and lock or unlock slices. GetRenderWindow1()->GetSliceNavigationController()->SetSliceRotationLocked(locked); GetRenderWindow2()->GetSliceNavigationController()->SetSliceRotationLocked(locked); GetRenderWindow3()->GetSliceNavigationController()->SetSliceRotationLocked(locked); } void QmitkStdMultiWidget::SetWidgetPlanesRotationLinked( bool link ) { m_SlicesRotator->SetLinkPlanes( link ); m_SlicesSwiveller->SetLinkPlanes( link ); emit WidgetPlanesRotationLinked( link ); } void QmitkStdMultiWidget::SetWidgetPlaneMode( int userMode ) { MITK_DEBUG << "Changing crosshair mode to " << userMode; emit WidgetNotifyNewCrossHairMode( userMode ); int mode = m_PlaneMode; bool link = false; // Convert user interface mode to actual mode { switch(userMode) { case 0: mode = PLANE_MODE_SLICING; link = false; break; case 1: mode = PLANE_MODE_ROTATION; link = false; break; case 2: mode = PLANE_MODE_ROTATION; link = true; break; case 3: mode = PLANE_MODE_SWIVEL; link = false; break; } } // Slice rotation linked m_SlicesRotator->SetLinkPlanes( link ); m_SlicesSwiveller->SetLinkPlanes( link ); // Do nothing if mode didn't change if ( m_PlaneMode == mode ) { return; } mitk::GlobalInteraction *gi = mitk::GlobalInteraction::GetInstance(); // Remove listeners of previous mode switch ( m_PlaneMode ) { default: case PLANE_MODE_SLICING: // Notify MainTemplate GUI that this mode has been deselected emit WidgetPlaneModeSlicing( false ); gi->RemoveListener( mitkWidget1->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget2->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget3->GetSliceNavigationController() ); gi->RemoveListener( mitkWidget4->GetSliceNavigationController() ); break; case PLANE_MODE_ROTATION: // Notify MainTemplate GUI that this mode has been deselected emit WidgetPlaneModeRotation( false ); m_SlicesRotator->ResetMouseCursor(); gi->RemoveListener( m_SlicesRotator ); break; case PLANE_MODE_SWIVEL: // Notify MainTemplate GUI that this mode has been deselected emit WidgetPlaneModeSwivel( false ); m_SlicesSwiveller->ResetMouseCursor(); gi->RemoveListener( m_SlicesSwiveller ); break; } // Set new mode and add corresponding listener to GlobalInteraction m_PlaneMode = mode; switch ( m_PlaneMode ) { default: case PLANE_MODE_SLICING: // Notify MainTemplate GUI that this mode has been selected emit WidgetPlaneModeSlicing( true ); // Add listeners gi->AddListener( mitkWidget1->GetSliceNavigationController() ); gi->AddListener( mitkWidget2->GetSliceNavigationController() ); gi->AddListener( mitkWidget3->GetSliceNavigationController() ); gi->AddListener( mitkWidget4->GetSliceNavigationController() ); mitk::RenderingManager::GetInstance()->InitializeViews(); break; case PLANE_MODE_ROTATION: // Notify MainTemplate GUI that this mode has been selected emit WidgetPlaneModeRotation( true ); // Add listener gi->AddListener( m_SlicesRotator ); break; case PLANE_MODE_SWIVEL: // Notify MainTemplate GUI that this mode has been selected emit WidgetPlaneModeSwivel( true ); // Add listener gi->AddListener( m_SlicesSwiveller ); break; } // Notify MainTemplate GUI that mode has changed emit WidgetPlaneModeChange(m_PlaneMode); } void QmitkStdMultiWidget::SetGradientBackgroundColors( const mitk::Color & upper, const mitk::Color & lower ) { m_GradientBackground1->SetGradientColors(upper[0], upper[1], upper[2], lower[0], lower[1], lower[2]); m_GradientBackground2->SetGradientColors(upper[0], upper[1], upper[2], lower[0], lower[1], lower[2]); m_GradientBackground3->SetGradientColors(upper[0], upper[1], upper[2], lower[0], lower[1], lower[2]); m_GradientBackground4->SetGradientColors(upper[0], upper[1], upper[2], lower[0], lower[1], lower[2]); } void QmitkStdMultiWidget::SetDepartmentLogoPath( const char * path ) { m_LogoRendering1->SetLogoSource(path); m_LogoRendering2->SetLogoSource(path); m_LogoRendering3->SetLogoSource(path); m_LogoRendering4->SetLogoSource(path); } void QmitkStdMultiWidget::SetWidgetPlaneModeToSlicing( bool activate ) { if ( activate ) { this->SetWidgetPlaneMode( PLANE_MODE_SLICING ); } } void QmitkStdMultiWidget::SetWidgetPlaneModeToRotation( bool activate ) { if ( activate ) { this->SetWidgetPlaneMode( PLANE_MODE_ROTATION ); } } void QmitkStdMultiWidget::SetWidgetPlaneModeToSwivel( bool activate ) { if ( activate ) { this->SetWidgetPlaneMode( PLANE_MODE_SWIVEL ); } } void QmitkStdMultiWidget::OnLayoutDesignChanged( int layoutDesignIndex ) { switch( layoutDesignIndex ) { case LAYOUT_DEFAULT: { this->changeLayoutToDefault(); break; } case LAYOUT_2D_IMAGES_UP: { this->changeLayoutTo2DImagesUp(); break; } case LAYOUT_2D_IMAGES_LEFT: { this->changeLayoutTo2DImagesLeft(); break; } case LAYOUT_BIG_3D: { this->changeLayoutToBig3D(); break; } case LAYOUT_WIDGET1: { this->changeLayoutToWidget1(); break; } case LAYOUT_WIDGET2: { this->changeLayoutToWidget2(); break; } case LAYOUT_WIDGET3: { this->changeLayoutToWidget3(); break; } case LAYOUT_2X_2D_AND_3D_WIDGET: { this->changeLayoutTo2x2Dand3DWidget(); break; } case LAYOUT_ROW_WIDGET_3_AND_4: { this->changeLayoutToRowWidget3And4(); break; } case LAYOUT_COLUMN_WIDGET_3_AND_4: { this->changeLayoutToColumnWidget3And4(); break; } case LAYOUT_ROW_WIDGET_SMALL3_AND_BIG4: { this->changeLayoutToRowWidgetSmall3andBig4(); break; } case LAYOUT_SMALL_UPPER_WIDGET2_BIG3_AND4: { this->changeLayoutToSmallUpperWidget2Big3and4(); break; } case LAYOUT_2D_AND_3D_LEFT_2D_RIGHT_WIDGET: { this->changeLayoutToLeft2Dand3DRight2D(); break; } }; } void QmitkStdMultiWidget::UpdateAllWidgets() { mitkWidget1->resize( mitkWidget1Container->frameSize().width()-1, mitkWidget1Container->frameSize().height() ); mitkWidget1->resize( mitkWidget1Container->frameSize().width(), mitkWidget1Container->frameSize().height() ); mitkWidget2->resize( mitkWidget2Container->frameSize().width()-1, mitkWidget2Container->frameSize().height() ); mitkWidget2->resize( mitkWidget2Container->frameSize().width(), mitkWidget2Container->frameSize().height() ); mitkWidget3->resize( mitkWidget3Container->frameSize().width()-1, mitkWidget3Container->frameSize().height() ); mitkWidget3->resize( mitkWidget3Container->frameSize().width(), mitkWidget3Container->frameSize().height() ); mitkWidget4->resize( mitkWidget4Container->frameSize().width()-1, mitkWidget4Container->frameSize().height() ); mitkWidget4->resize( mitkWidget4Container->frameSize().width(), mitkWidget4Container->frameSize().height() ); } void QmitkStdMultiWidget::HideAllWidgetToolbars() { mitkWidget1->HideRenderWindowMenu(); mitkWidget2->HideRenderWindowMenu(); mitkWidget3->HideRenderWindowMenu(); mitkWidget4->HideRenderWindowMenu(); } void QmitkStdMultiWidget::ActivateMenuWidget( bool state ) { mitkWidget1->ActivateMenuWidget( state ); mitkWidget2->ActivateMenuWidget( state ); mitkWidget3->ActivateMenuWidget( state ); mitkWidget4->ActivateMenuWidget( state ); } void QmitkStdMultiWidget::ResetCrosshair() { if (m_DataStorage.IsNotNull()) { mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox" , mitk::BoolProperty::New(false))); mitk::NodePredicateNot::Pointer pred2 = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox" , mitk::BoolProperty::New(true))); mitk::DataStorage::SetOfObjects::ConstPointer rs = m_DataStorage->GetSubset(pred); mitk::DataStorage::SetOfObjects::ConstPointer rs2 = m_DataStorage->GetSubset(pred2); // calculate bounding geometry of these nodes mitk::TimeSlicedGeometry::Pointer bounds = m_DataStorage->ComputeBoundingGeometry3D(rs, "visible"); mitk::RenderingManager::GetInstance()->InitializeViews(bounds); //mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeVisibleBoundingGeometry3D() ); // reset interactor to normal slicing this->SetWidgetPlaneMode(PLANE_MODE_SLICING); } } void QmitkStdMultiWidget::EnableColoredRectangles() { m_RectangleRendering1->Enable(1.0, 0.0, 0.0); m_RectangleRendering2->Enable(0.0, 1.0, 0.0); m_RectangleRendering3->Enable(0.0, 0.0, 1.0); m_RectangleRendering4->Enable(1.0, 1.0, 0.0); } void QmitkStdMultiWidget::DisableColoredRectangles() { m_RectangleRendering1->Disable(); m_RectangleRendering2->Disable(); m_RectangleRendering3->Disable(); m_RectangleRendering4->Disable(); } diff --git a/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingView.cpp b/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingView.cpp index 42d184d35d..54aaa8e522 100644 --- a/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingView.cpp +++ b/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingView.cpp @@ -1,1126 +1,1054 @@ /*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision: 10185 $ + Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkBasicImageProcessingView.h" // QT includes (GUI) #include #include #include #include #include #include #include // Berry includes (selection service) #include #include // MITK includes (GUI) #include "QmitkStdMultiWidget.h" #include "QmitkDataNodeSelectionProvider.h" #include "mitkDataNodeObject.h" // MITK includes (general) #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateDimension.h" #include "mitkNodePredicateAnd.h" #include "mitkImageTimeSelector.h" #include "mitkVectorImageMapper2D.h" #include "mitkProperties.h" // Includes for image casting between ITK and MITK #include "mitkImageCast.h" #include "mitkITKImageImport.h" // ITK includes (general) #include // Morphological Operations #include #include #include #include #include // Smoothing #include #include #include // Threshold #include // Inversion #include // Derivatives #include #include #include // Resampling #include #include // Image Arithmetics #include #include #include #include // Boolean operations #include #include #include -//vtk -#include -#include -#include -#include -#include - // Convenient Definitions typedef itk::Image ImageType; typedef itk::Image FloatImageType; typedef itk::Image, 3> VectorImageType; typedef itk::BinaryBallStructuringElement BallType; typedef itk::GrayscaleDilateImageFilter DilationFilterType; typedef itk::GrayscaleErodeImageFilter ErosionFilterType; typedef itk::GrayscaleMorphologicalOpeningImageFilter OpeningFilterType; typedef itk::GrayscaleMorphologicalClosingImageFilter ClosingFilterType; typedef itk::MedianImageFilter< ImageType, ImageType > MedianFilterType; typedef itk::DiscreteGaussianImageFilter< ImageType, ImageType> GaussianFilterType; typedef itk::TotalVariationDenoisingImageFilter TotalVariationFilterType; typedef itk::TotalVariationDenoisingImageFilter VectorTotalVariationFilterType; typedef itk::BinaryThresholdImageFilter< ImageType, ImageType > ThresholdFilterType; typedef itk::InvertIntensityImageFilter< ImageType, ImageType > InversionFilterType; typedef itk::GradientMagnitudeRecursiveGaussianImageFilter< ImageType, ImageType > GradientFilterType; typedef itk::LaplacianImageFilter< FloatImageType, FloatImageType > LaplacianFilterType; typedef itk::SobelEdgeDetectionImageFilter< FloatImageType, FloatImageType > SobelFilterType; typedef itk::ResampleImageFilter< ImageType, ImageType > ResampleImageFilterType; typedef itk::AddImageFilter< ImageType, ImageType, ImageType > AddFilterType; typedef itk::SubtractImageFilter< ImageType, ImageType, ImageType > SubtractFilterType; typedef itk::MultiplyImageFilter< ImageType, ImageType, ImageType > MultiplyFilterType; typedef itk::DivideImageFilter< ImageType, ImageType, FloatImageType > DivideFilterType; typedef itk::OrImageFilter< ImageType, ImageType > OrImageFilterType; typedef itk::AndImageFilter< ImageType, ImageType > AndImageFilterType; typedef itk::XorImageFilter< ImageType, ImageType > XorImageFilterType; QmitkBasicImageProcessing::QmitkBasicImageProcessing() - : QmitkFunctionality(), +: QmitkFunctionality(), m_Controls(NULL), m_SelectedImageNode(NULL), m_TimeStepperAdapter(NULL), m_SelectionListener(NULL) { } QmitkBasicImageProcessing::~QmitkBasicImageProcessing() { //berry::ISelectionService* s = GetSite()->GetWorkbenchWindow()->GetSelectionService(); //if(s) // s->RemoveSelectionListener(m_SelectionListener); } void QmitkBasicImageProcessing::CreateQtPartControl(QWidget *parent) { if (m_Controls == NULL) { m_Controls = new Ui::QmitkBasicImageProcessingViewControls; m_Controls->setupUi(parent); this->CreateConnections(); //setup predictaes for combobox mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); mitk::NodePredicateDataType::Pointer imagePredicate = mitk::NodePredicateDataType::New("Image"); m_Controls->m_ImageSelector2->SetDataStorage(this->GetDefaultDataStorage()); m_Controls->m_ImageSelector2->SetPredicate(mitk::NodePredicateAnd::New(dimensionPredicate, imagePredicate)); } m_Controls->gbTwoImageOps->hide(); m_SelectedImageNode = mitk::DataStorageSelection::New(this->GetDefaultDataStorage(), false); } void QmitkBasicImageProcessing::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->cbWhat1), SIGNAL( activated(int) ), this, SLOT( SelectAction(int) ) ); connect( (QObject*)(m_Controls->btnDoIt), SIGNAL(clicked()),(QObject*) this, SLOT(StartButtonClicked())); connect( (QObject*)(m_Controls->cbWhat2), SIGNAL( activated(int) ), this, SLOT( SelectAction2(int) ) ); connect( (QObject*)(m_Controls->btnDoIt2), SIGNAL(clicked()),(QObject*) this, SLOT(StartButton2Clicked())); connect( (QObject*)(m_Controls->rBOneImOp), SIGNAL( clicked() ), this, SLOT( ChangeGUI() ) ); connect( (QObject*)(m_Controls->rBTwoImOp), SIGNAL( clicked() ), this, SLOT( ChangeGUI() ) ); - - - connect( (QObject*)(m_Controls->m_testButton), SIGNAL( clicked() ), this, SLOT( TestButtonClicked() ) ); - connect( (QObject*)(m_Controls->viewX), SIGNAL( clicked() ), this, SLOT( ViewXClicked() ) ); - connect( (QObject*)(m_Controls->viewY), SIGNAL( clicked() ), this, SLOT( ViewYClicked() ) ); - connect( (QObject*)(m_Controls->viewZ), SIGNAL( clicked() ), this, SLOT( ViewZClicked() ) ); } m_TimeStepperAdapter = new QmitkStepperAdapter((QObject*) m_Controls->sliceNavigatorTime, - GetActiveStdMultiWidget()->GetTimeNavigationController()->GetTime(), "sliceNavigatorTimeFromBIP"); + GetActiveStdMultiWidget()->GetTimeNavigationController()->GetTime(), "sliceNavigatorTimeFromBIP"); } void QmitkBasicImageProcessing::Activated() { QmitkFunctionality::Activated(); this->m_Controls->cbWhat1->clear(); this->m_Controls->cbWhat1->insertItem( NOACTIONSELECTED, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Please select operation", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( CATEGORY_DENOISING, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "--- Denoising ---", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( GAUSSIAN, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Gaussian", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( MEDIAN, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Median", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( TOTALVARIATION, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Total Variation", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( CATEGORY_MORPHOLOGICAL, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "--- Morphological ---", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( DILATION, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Dilation", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( EROSION, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Erosion", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( OPENING, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Opening", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( CLOSING, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Closing", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( CATEGORY_EDGE_DETECTION, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "--- Edge Detection ---", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( GRADIENT, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Gradient", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( LAPLACIAN, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Laplacian (2nd Derivative)", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( SOBEL, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Sobel Operator", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( CATEGORY_MISC, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "--- Misc ---", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( THRESHOLD, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Threshold", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( INVERSION, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Image Inversion", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat1->insertItem( DOWNSAMPLING, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Downsampling", 0, QApplication::UnicodeUTF8) )); this->m_Controls->cbWhat2->clear(); this->m_Controls->cbWhat2->insertItem( TWOIMAGESNOACTIONSELECTED, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Please select on operation", 0, QApplication::UnicodeUTF8) ) ); this->m_Controls->cbWhat2->insertItem( CATEGORY_ARITHMETIC, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "--- Arithmetric operations ---", 0, QApplication::UnicodeUTF8) ) ); this->m_Controls->cbWhat2->insertItem( ADD, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Add to Image 1:", 0, QApplication::UnicodeUTF8) ) ); this->m_Controls->cbWhat2->insertItem( SUBTRACT, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Subtract from Image 1:", 0, QApplication::UnicodeUTF8) ) ); this->m_Controls->cbWhat2->insertItem( MULTIPLY, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Multiply with Image 1:", 0, QApplication::UnicodeUTF8) ) ); this->m_Controls->cbWhat2->insertItem( DIVIDE, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "Divide Image 1 by:", 0, QApplication::UnicodeUTF8) ) ); this->m_Controls->cbWhat2->insertItem( CATEGORY_BOOLEAN, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "--- Boolean operations ---", 0, QApplication::UnicodeUTF8) ) ); this->m_Controls->cbWhat2->insertItem( AND, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "AND", 0, QApplication::UnicodeUTF8) ) ); this->m_Controls->cbWhat2->insertItem( OR, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "OR", 0, QApplication::UnicodeUTF8) ) ); this->m_Controls->cbWhat2->insertItem( XOR, QString( QApplication::translate("QmitkBasicImageProcessingViewControls", "XOR", 0, QApplication::UnicodeUTF8) ) ); } //datamanager selection changed void QmitkBasicImageProcessing::OnSelectionChanged(std::vector nodes) { //any nodes there? if (!nodes.empty()) { - // reset GUI - this->ResetOneImageOpPanel(); - m_Controls->sliceNavigatorTime->setEnabled(false); - m_Controls->leImage1->setText("Select an Image in Data Manager"); - m_Controls->tlWhat1->setEnabled(false); - m_Controls->cbWhat1->setEnabled(false); - m_Controls->tlWhat2->setEnabled(false); - m_Controls->cbWhat2->setEnabled(false); - - m_SelectedImageNode->RemoveAllNodes(); - //get the selected Node - mitk::DataNode* _DataNode = nodes.front(); - *m_SelectedImageNode = _DataNode; - //try to cast to image - mitk::Image::Pointer tempImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); + // reset GUI + this->ResetOneImageOpPanel(); + m_Controls->sliceNavigatorTime->setEnabled(false); + m_Controls->leImage1->setText("Select an Image in Data Manager"); + m_Controls->tlWhat1->setEnabled(false); + m_Controls->cbWhat1->setEnabled(false); + m_Controls->tlWhat2->setEnabled(false); + m_Controls->cbWhat2->setEnabled(false); + + m_SelectedImageNode->RemoveAllNodes(); + //get the selected Node + mitk::DataNode* _DataNode = nodes.front(); + *m_SelectedImageNode = _DataNode; + //try to cast to image + mitk::Image::Pointer tempImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); //no image if( tempImage.IsNull() || (tempImage->IsInitialized() == false) ) { m_Controls->leImage1->setText("Not an image."); return; } //2D image if( tempImage->GetDimension() < 3) { m_Controls->leImage1->setText("2D images are not supported."); return; } //image m_Controls->leImage1->setText(QString(m_SelectedImageNode->GetNode()->GetName().c_str())); // button coding if ( tempImage->GetDimension() > 3 ) { m_Controls->sliceNavigatorTime->setEnabled(true); m_Controls->tlTime->setEnabled(true); } m_Controls->tlWhat1->setEnabled(true); m_Controls->cbWhat1->setEnabled(true); m_Controls->tlWhat2->setEnabled(true); m_Controls->cbWhat2->setEnabled(true); } } void QmitkBasicImageProcessing::ChangeGUI() { if(m_Controls->rBOneImOp->isChecked()) { m_Controls->gbTwoImageOps->hide(); m_Controls->gbOneImageOps->show(); } else if(m_Controls->rBTwoImOp->isChecked()) { m_Controls->gbOneImageOps->hide(); m_Controls->gbTwoImageOps->show(); } } void QmitkBasicImageProcessing::ResetOneImageOpPanel() { m_Controls->tlParam1->setText("Param1"); m_Controls->tlParam2->setText("Param2"); m_Controls->cbWhat1->setCurrentIndex(0); m_Controls->tlTime->setEnabled(false); this->ResetParameterPanel(); m_Controls->btnDoIt->setEnabled(false); m_Controls->cbHideOrig->setEnabled(false); } void QmitkBasicImageProcessing::ResetParameterPanel() { m_Controls->tlParam->setEnabled(false); m_Controls->tlParam1->setEnabled(false); m_Controls->tlParam2->setEnabled(false); m_Controls->sbParam1->setEnabled(false); m_Controls->sbParam2->setEnabled(false); m_Controls->sbParam1->setValue(0); m_Controls->sbParam2->setValue(0); } void QmitkBasicImageProcessing::ResetTwoImageOpPanel() { m_Controls->cbWhat2->setCurrentIndex(0); m_Controls->tlImage2->setEnabled(false); m_Controls->m_ImageSelector2->setEnabled(false); m_Controls->btnDoIt2->setEnabled(false); } void QmitkBasicImageProcessing::SelectAction(int action) { if ( ! m_SelectedImageNode->GetNode() ) return; // Prepare GUI this->ResetParameterPanel(); m_Controls->btnDoIt->setEnabled(false); m_Controls->cbHideOrig->setEnabled(false); QString text1 = "No Parameters"; QString text2 = "No Parameters"; // check which operation the user has selected and set parameters and GUI accordingly switch (action) { case 2: { m_SelectedAction = GAUSSIAN; m_Controls->tlParam1->setEnabled(true); m_Controls->sbParam1->setEnabled(true); text1 = "&Variance:"; m_Controls->sbParam1->setMinimum( 0 ); m_Controls->sbParam1->setMaximum( 200 ); m_Controls->sbParam1->setValue( 2 ); break; } case 3: { m_SelectedAction = MEDIAN; m_Controls->tlParam1->setEnabled(true); m_Controls->sbParam1->setEnabled(true); text1 = "&Radius:"; m_Controls->sbParam1->setMinimum( 0 ); m_Controls->sbParam1->setMaximum( 200 ); m_Controls->sbParam1->setValue( 3 ); break; } case 4: { m_SelectedAction = TOTALVARIATION; m_Controls->tlParam1->setEnabled(true); m_Controls->sbParam1->setEnabled(true); m_Controls->tlParam2->setEnabled(true); m_Controls->sbParam2->setEnabled(true); text1 = "Number Iterations:"; text2 = "Regularization\n(Lambda/1000):"; m_Controls->sbParam1->setMinimum( 1 ); m_Controls->sbParam1->setMaximum( 1000 ); m_Controls->sbParam1->setValue( 40 ); m_Controls->sbParam2->setMinimum( 0 ); m_Controls->sbParam2->setMaximum( 100000 ); m_Controls->sbParam2->setValue( 1 ); break; } case 6: { m_SelectedAction = DILATION; m_Controls->tlParam1->setEnabled(true); m_Controls->sbParam1->setEnabled(true); text1 = "&Radius:"; m_Controls->sbParam1->setMinimum( 0 ); m_Controls->sbParam1->setMaximum( 200 ); m_Controls->sbParam1->setValue( 3 ); break; } case 7: { m_SelectedAction = EROSION; m_Controls->tlParam1->setEnabled(true); m_Controls->sbParam1->setEnabled(true); text1 = "&Radius:"; m_Controls->sbParam1->setMinimum( 0 ); m_Controls->sbParam1->setMaximum( 200 ); m_Controls->sbParam1->setValue( 3 ); break; } case 8: { m_SelectedAction = OPENING; m_Controls->tlParam1->setEnabled(true); m_Controls->sbParam1->setEnabled(true); text1 = "&Radius:"; m_Controls->sbParam1->setMinimum( 0 ); m_Controls->sbParam1->setMaximum( 200 ); m_Controls->sbParam1->setValue( 3 ); break; } case 9: { m_SelectedAction = CLOSING; m_Controls->tlParam1->setEnabled(true); m_Controls->sbParam1->setEnabled(true); text1 = "&Radius:"; m_Controls->sbParam1->setMinimum( 0 ); m_Controls->sbParam1->setMaximum( 200 ); m_Controls->sbParam1->setValue( 3 ); break; } case 11: { m_SelectedAction = GRADIENT; m_Controls->tlParam1->setEnabled(true); m_Controls->sbParam1->setEnabled(true); text1 = "Sigma of Gaussian Kernel:\n(in Image Spacing Units)"; m_Controls->sbParam1->setMinimum( 0 ); m_Controls->sbParam1->setMaximum( 200 ); m_Controls->sbParam1->setValue( 2 ); break; } case 12: { m_SelectedAction = LAPLACIAN; break; } case 13: { m_SelectedAction = SOBEL; break; } case 15: { m_SelectedAction = THRESHOLD; m_Controls->tlParam1->setEnabled(true); m_Controls->sbParam1->setEnabled(true); m_Controls->tlParam2->setEnabled(true); m_Controls->sbParam2->setEnabled(true); text1 = "Lower threshold:"; text2 = "Upper threshold:"; m_Controls->sbParam1->setMinimum( -100000 ); m_Controls->sbParam1->setMaximum( 100000 ); m_Controls->sbParam1->setValue( 0 ); m_Controls->sbParam2->setMinimum( -100000 ); m_Controls->sbParam2->setMaximum( 100000 ); m_Controls->sbParam2->setValue( 300 ); break; } case 16: { m_SelectedAction = INVERSION; break; } case 17: { m_SelectedAction = DOWNSAMPLING; m_Controls->tlParam1->setEnabled(true); m_Controls->sbParam1->setEnabled(true); text1 = "Downsampling by Factor:"; m_Controls->sbParam1->setMinimum( 1 ); m_Controls->sbParam1->setMaximum( 100 ); m_Controls->sbParam1->setValue( 2 ); break; } default: return; } m_Controls->tlParam->setEnabled(true); m_Controls->tlParam1->setText(text1); m_Controls->tlParam2->setText(text2); m_Controls->btnDoIt->setEnabled(true); m_Controls->cbHideOrig->setEnabled(true); } void QmitkBasicImageProcessing::StartButtonClicked() { if(!m_SelectedImageNode->GetNode()) return; this->BusyCursorOn(); mitk::Image::Pointer newImage; try { newImage = dynamic_cast(m_SelectedImageNode->GetNode()->GetData()); } catch ( std::exception &e ) { - QString exceptionString = "An error occured during image loading:\n"; - exceptionString.append( e.what() ); + QString exceptionString = "An error occured during image loading:\n"; + exceptionString.append( e.what() ); QMessageBox::warning( NULL, "Basic Image Processing", exceptionString , QMessageBox::Ok, QMessageBox::NoButton ); this->BusyCursorOff(); return; } // check if input image is valid, casting does not throw exception when casting from 'NULL-Object' if ( (! newImage) || (newImage->IsInitialized() == false) ) { this->BusyCursorOff(); - + QMessageBox::warning( NULL, "Basic Image Processing", "Input image is broken or not initialized. Returning.", QMessageBox::Ok, QMessageBox::NoButton ); return; } // check if operation is done on 4D a image time step if(newImage->GetDimension() > 3) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(newImage); timeSelector->SetTimeNr( ((QmitkSliderNavigatorWidget*)m_Controls->sliceNavigatorTime)->GetPos() ); timeSelector->Update(); newImage = timeSelector->GetOutput(); } // check if image or vector image ImageType::Pointer itkImage = ImageType::New(); VectorImageType::Pointer itkVecImage = VectorImageType::New(); int isVectorImage = newImage->GetPixelType().GetNumberOfComponents(); if(isVectorImage > 1) { CastToItkImage( newImage, itkVecImage ); } else { CastToItkImage( newImage, itkImage ); } std::stringstream nameAddition(""); int param1 = m_Controls->sbParam1->value(); int param2 = m_Controls->sbParam2->value(); try{ - switch (m_SelectedAction) + switch (m_SelectedAction) + { + + case GAUSSIAN: { + GaussianFilterType::Pointer gaussianFilter = GaussianFilterType::New(); + gaussianFilter->SetInput( itkImage ); + gaussianFilter->SetVariance( param1 ); + gaussianFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(gaussianFilter->GetOutput()); + nameAddition << "_Gaussian_var_" << param1; + std::cout << "Gaussian filtering successful." << std::endl; + break; + } - case GAUSSIAN: - { - GaussianFilterType::Pointer gaussianFilter = GaussianFilterType::New(); - gaussianFilter->SetInput( itkImage ); - gaussianFilter->SetVariance( param1 ); - gaussianFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(gaussianFilter->GetOutput()); - nameAddition << "_Gaussian_var_" << param1; - std::cout << "Gaussian filtering successful." << std::endl; - break; - } + case MEDIAN: + { + MedianFilterType::Pointer medianFilter = MedianFilterType::New(); + MedianFilterType::InputSizeType size; + size.Fill(param1); + medianFilter->SetRadius( size ); + medianFilter->SetInput(itkImage); + medianFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(medianFilter->GetOutput()); + nameAddition << "_Median_radius_" << param1; + std::cout << "Median Filtering successful." << std::endl; + break; + } - case MEDIAN: + case TOTALVARIATION: + { + if(isVectorImage > 1) { - MedianFilterType::Pointer medianFilter = MedianFilterType::New(); - MedianFilterType::InputSizeType size; - size.Fill(param1); - medianFilter->SetRadius( size ); - medianFilter->SetInput(itkImage); - medianFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(medianFilter->GetOutput()); - nameAddition << "_Median_radius_" << param1; - std::cout << "Median Filtering successful." << std::endl; - break; + VectorTotalVariationFilterType::Pointer TVFilter + = VectorTotalVariationFilterType::New(); + TVFilter->SetInput( itkVecImage.GetPointer() ); + TVFilter->SetNumberIterations(param1); + TVFilter->SetLambda(double(param2)/1000.); + TVFilter->UpdateLargestPossibleRegion(); + + newImage = mitk::ImportItkImage(TVFilter->GetOutput()); } - - case TOTALVARIATION: + else { - if(isVectorImage > 1) - { - VectorTotalVariationFilterType::Pointer TVFilter - = VectorTotalVariationFilterType::New(); - TVFilter->SetInput( itkVecImage.GetPointer() ); - TVFilter->SetNumberIterations(param1); - TVFilter->SetLambda(double(param2)/1000.); - TVFilter->UpdateLargestPossibleRegion(); - - newImage = mitk::ImportItkImage(TVFilter->GetOutput()); - } - else - { - FloatImageType::Pointer fImage = FloatImageType::New(); - CastToItkImage( newImage, fImage ); - TotalVariationFilterType::Pointer TVFilter - = TotalVariationFilterType::New(); - TVFilter->SetInput( fImage.GetPointer() ); - TVFilter->SetNumberIterations(param1); - TVFilter->SetLambda(double(param2)/1000.); - TVFilter->UpdateLargestPossibleRegion(); - - newImage = mitk::ImportItkImage(TVFilter->GetOutput()); - } - - nameAddition << "_TV_Iter_" << param1 << "_L_" << param2; - std::cout << "Total Variation Filtering successful." << std::endl; - break; + FloatImageType::Pointer fImage = FloatImageType::New(); + CastToItkImage( newImage, fImage ); + TotalVariationFilterType::Pointer TVFilter + = TotalVariationFilterType::New(); + TVFilter->SetInput( fImage.GetPointer() ); + TVFilter->SetNumberIterations(param1); + TVFilter->SetLambda(double(param2)/1000.); + TVFilter->UpdateLargestPossibleRegion(); + + newImage = mitk::ImportItkImage(TVFilter->GetOutput()); } - case DILATION: - { - BallType binaryBall; - binaryBall.SetRadius( param1 ); - binaryBall.CreateStructuringElement(); - - DilationFilterType::Pointer dilationFilter = DilationFilterType::New(); - dilationFilter->SetInput( itkImage ); - dilationFilter->SetKernel( binaryBall ); - dilationFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(dilationFilter->GetOutput()); - nameAddition << "_Dilated_by_" << param1; - std::cout << "Dilation successful." << std::endl; - break; - } + nameAddition << "_TV_Iter_" << param1 << "_L_" << param2; + std::cout << "Total Variation Filtering successful." << std::endl; + break; + } - case EROSION: - { - BallType binaryBall; - binaryBall.SetRadius( param1 ); - binaryBall.CreateStructuringElement(); - - ErosionFilterType::Pointer erosionFilter = ErosionFilterType::New(); - erosionFilter->SetInput( itkImage ); - erosionFilter->SetKernel( binaryBall ); - erosionFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(erosionFilter->GetOutput()); - nameAddition << "_Eroded_by_" << param1; - std::cout << "Erosion successful." << std::endl; - break; - } + case DILATION: + { + BallType binaryBall; + binaryBall.SetRadius( param1 ); + binaryBall.CreateStructuringElement(); + + DilationFilterType::Pointer dilationFilter = DilationFilterType::New(); + dilationFilter->SetInput( itkImage ); + dilationFilter->SetKernel( binaryBall ); + dilationFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(dilationFilter->GetOutput()); + nameAddition << "_Dilated_by_" << param1; + std::cout << "Dilation successful." << std::endl; + break; + } - case OPENING: - { - BallType binaryBall; - binaryBall.SetRadius( param1 ); - binaryBall.CreateStructuringElement(); - - OpeningFilterType::Pointer openFilter = OpeningFilterType::New(); - openFilter->SetInput( itkImage ); - openFilter->SetKernel( binaryBall ); - openFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(openFilter->GetOutput()); - nameAddition << "_Opened_by_" << param1; - std::cout << "Opening successful." << std::endl; - break; - } + case EROSION: + { + BallType binaryBall; + binaryBall.SetRadius( param1 ); + binaryBall.CreateStructuringElement(); + + ErosionFilterType::Pointer erosionFilter = ErosionFilterType::New(); + erosionFilter->SetInput( itkImage ); + erosionFilter->SetKernel( binaryBall ); + erosionFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(erosionFilter->GetOutput()); + nameAddition << "_Eroded_by_" << param1; + std::cout << "Erosion successful." << std::endl; + break; + } - case CLOSING: - { - BallType binaryBall; - binaryBall.SetRadius( param1 ); - binaryBall.CreateStructuringElement(); - - ClosingFilterType::Pointer closeFilter = ClosingFilterType::New(); - closeFilter->SetInput( itkImage ); - closeFilter->SetKernel( binaryBall ); - closeFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(closeFilter->GetOutput()); - nameAddition << "_Closed_by_" << param1; - std::cout << "Closing successful." << std::endl; - break; - } + case OPENING: + { + BallType binaryBall; + binaryBall.SetRadius( param1 ); + binaryBall.CreateStructuringElement(); + + OpeningFilterType::Pointer openFilter = OpeningFilterType::New(); + openFilter->SetInput( itkImage ); + openFilter->SetKernel( binaryBall ); + openFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(openFilter->GetOutput()); + nameAddition << "_Opened_by_" << param1; + std::cout << "Opening successful." << std::endl; + break; + } - case GRADIENT: - { - GradientFilterType::Pointer gradientFilter = GradientFilterType::New(); - gradientFilter->SetInput( itkImage ); - gradientFilter->SetSigma( param1 ); - gradientFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(gradientFilter->GetOutput()); - nameAddition << "_Gradient_sigma_" << param1; - std::cout << "Gradient calculation successful." << std::endl; - break; - } + case CLOSING: + { + BallType binaryBall; + binaryBall.SetRadius( param1 ); + binaryBall.CreateStructuringElement(); + + ClosingFilterType::Pointer closeFilter = ClosingFilterType::New(); + closeFilter->SetInput( itkImage ); + closeFilter->SetKernel( binaryBall ); + closeFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(closeFilter->GetOutput()); + nameAddition << "_Closed_by_" << param1; + std::cout << "Closing successful." << std::endl; + break; + } - case LAPLACIAN: - { - FloatImageType::Pointer fImage = FloatImageType::New(); - CastToItkImage( newImage, fImage ); - LaplacianFilterType::Pointer laplacianFilter = LaplacianFilterType::New(); - laplacianFilter->SetInput( fImage ); - laplacianFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(laplacianFilter->GetOutput()); - nameAddition << "_Second_Derivative"; - std::cout << "Laplacian filtering successful." << std::endl; - break; - } + case GRADIENT: + { + GradientFilterType::Pointer gradientFilter = GradientFilterType::New(); + gradientFilter->SetInput( itkImage ); + gradientFilter->SetSigma( param1 ); + gradientFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(gradientFilter->GetOutput()); + nameAddition << "_Gradient_sigma_" << param1; + std::cout << "Gradient calculation successful." << std::endl; + break; + } - case SOBEL: - { - FloatImageType::Pointer fImage = FloatImageType::New(); - CastToItkImage( newImage, fImage ); - SobelFilterType::Pointer sobelFilter = SobelFilterType::New(); - sobelFilter->SetInput( fImage ); - sobelFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(sobelFilter->GetOutput()); - nameAddition << "_Sobel"; - std::cout << "Edge Detection successful." << std::endl; - break; - } + case LAPLACIAN: + { + FloatImageType::Pointer fImage = FloatImageType::New(); + CastToItkImage( newImage, fImage ); + LaplacianFilterType::Pointer laplacianFilter = LaplacianFilterType::New(); + laplacianFilter->SetInput( fImage ); + laplacianFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(laplacianFilter->GetOutput()); + nameAddition << "_Second_Derivative"; + std::cout << "Laplacian filtering successful." << std::endl; + break; + } - case THRESHOLD: - { - ThresholdFilterType::Pointer thFilter = ThresholdFilterType::New(); - thFilter->SetLowerThreshold(param1 < param2 ? param1 : param2); - thFilter->SetUpperThreshold(param2 > param1 ? param2 : param1); - thFilter->SetInsideValue(1); - thFilter->SetOutsideValue(0); - thFilter->SetInput(itkImage); - thFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(thFilter->GetOutput()); - nameAddition << "_Threshold"; - std::cout << "Thresholding successful." << std::endl; - break; - } + case SOBEL: + { + FloatImageType::Pointer fImage = FloatImageType::New(); + CastToItkImage( newImage, fImage ); + SobelFilterType::Pointer sobelFilter = SobelFilterType::New(); + sobelFilter->SetInput( fImage ); + sobelFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(sobelFilter->GetOutput()); + nameAddition << "_Sobel"; + std::cout << "Edge Detection successful." << std::endl; + break; + } - case INVERSION: - { - InversionFilterType::Pointer invFilter = InversionFilterType::New(); - mitk::ScalarType min = newImage->GetScalarValueMin(); - mitk::ScalarType max = newImage->GetScalarValueMax(); - invFilter->SetMaximum( max + min ); - invFilter->SetInput(itkImage); - invFilter->UpdateLargestPossibleRegion(); - newImage = mitk::ImportItkImage(invFilter->GetOutput()); - nameAddition << "_Inverted"; - std::cout << "Image inversion successful." << std::endl; - break; - } + case THRESHOLD: + { + ThresholdFilterType::Pointer thFilter = ThresholdFilterType::New(); + thFilter->SetLowerThreshold(param1 < param2 ? param1 : param2); + thFilter->SetUpperThreshold(param2 > param1 ? param2 : param1); + thFilter->SetInsideValue(1); + thFilter->SetOutsideValue(0); + thFilter->SetInput(itkImage); + thFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(thFilter->GetOutput()); + nameAddition << "_Threshold"; + std::cout << "Thresholding successful." << std::endl; + break; + } + + case INVERSION: + { + InversionFilterType::Pointer invFilter = InversionFilterType::New(); + mitk::ScalarType min = newImage->GetScalarValueMin(); + mitk::ScalarType max = newImage->GetScalarValueMax(); + invFilter->SetMaximum( max + min ); + invFilter->SetInput(itkImage); + invFilter->UpdateLargestPossibleRegion(); + newImage = mitk::ImportItkImage(invFilter->GetOutput()); + nameAddition << "_Inverted"; + std::cout << "Image inversion successful." << std::endl; + break; + } + + case DOWNSAMPLING: + { + ResampleImageFilterType::Pointer downsampler = ResampleImageFilterType::New(); + downsampler->SetInput( itkImage ); + + typedef itk::NearestNeighborInterpolateImageFunction< ImageType, double > InterpolatorType; + InterpolatorType::Pointer interpolator = InterpolatorType::New(); + downsampler->SetInterpolator( interpolator ); + + downsampler->SetDefaultPixelValue( 0 ); + + ResampleImageFilterType::SpacingType spacing = itkImage->GetSpacing(); + spacing *= (double) param1; + downsampler->SetOutputSpacing( spacing ); - case DOWNSAMPLING: + downsampler->SetOutputOrigin( itkImage->GetOrigin() ); + downsampler->SetOutputDirection( itkImage->GetDirection() ); + + ResampleImageFilterType::SizeType size = itkImage->GetLargestPossibleRegion().GetSize(); + for ( int i = 0; i < 3; ++i ) { - ResampleImageFilterType::Pointer downsampler = ResampleImageFilterType::New(); - downsampler->SetInput( itkImage ); - - typedef itk::NearestNeighborInterpolateImageFunction< ImageType, double > InterpolatorType; - InterpolatorType::Pointer interpolator = InterpolatorType::New(); - downsampler->SetInterpolator( interpolator ); - - downsampler->SetDefaultPixelValue( 0 ); - - ResampleImageFilterType::SpacingType spacing = itkImage->GetSpacing(); - spacing *= (double) param1; - downsampler->SetOutputSpacing( spacing ); - - downsampler->SetOutputOrigin( itkImage->GetOrigin() ); - downsampler->SetOutputDirection( itkImage->GetDirection() ); - - ResampleImageFilterType::SizeType size = itkImage->GetLargestPossibleRegion().GetSize(); - for ( int i = 0; i < 3; ++i ) - { - size[i] /= param1; - } - downsampler->SetSize( size ); - downsampler->UpdateLargestPossibleRegion(); - - newImage = mitk::ImportItkImage(downsampler->GetOutput()); - nameAddition << "_Downsampled_by_" << param1; - std::cout << "Downsampling successful." << std::endl; - break; + size[i] /= param1; } + downsampler->SetSize( size ); + downsampler->UpdateLargestPossibleRegion(); - default: - this->BusyCursorOff(); - return; + newImage = mitk::ImportItkImage(downsampler->GetOutput()); + nameAddition << "_Downsampled_by_" << param1; + std::cout << "Downsampling successful." << std::endl; + break; } + + default: + this->BusyCursorOff(); + return; + } } catch (...) { this->BusyCursorOff(); QMessageBox::warning(NULL, "Warning", "Problem when applying filter operation. Check your input..."); return; } newImage->DisconnectPipeline(); // adjust level/window to new image mitk::LevelWindow levelwindow; levelwindow.SetAuto( newImage ); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); levWinProp->SetLevelWindow( levelwindow ); // compose new image name std::string name = m_SelectedImageNode->GetNode()->GetName(); if (name.find(".pic.gz") == name.size() -7 ) { name = name.substr(0,name.size() -7); } name.append( nameAddition.str() ); // create final result MITK data storage node mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty( "levelwindow", levWinProp ); result->SetProperty( "name", mitk::StringProperty::New( name.c_str() ) ); result->SetData( newImage ); // for vector images, a different mapper is needed if(isVectorImage > 1) { mitk::VectorImageMapper2D::Pointer mapper = - mitk::VectorImageMapper2D::New(); + mitk::VectorImageMapper2D::New(); result->SetMapper(1,mapper); } // reset GUI to ease further processing this->ResetOneImageOpPanel(); // add new image to data storage and set as active to ease further processing GetDefaultDataStorage()->Add( result, m_SelectedImageNode->GetNode() ); if ( m_Controls->cbHideOrig->isChecked() == true ) m_SelectedImageNode->GetNode()->SetProperty( "visible", mitk::BoolProperty::New(false) ); // TODO!! m_Controls->m_ImageSelector1->SetSelectedNode(result); // show the results mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->BusyCursorOff(); } void QmitkBasicImageProcessing::SelectAction2(int operation) { // check which operation the user has selected and set parameters and GUI accordingly switch (operation) { case 2: m_SelectedOperation = ADD; break; case 3: m_SelectedOperation = SUBTRACT; break; case 4: m_SelectedOperation = MULTIPLY; break; case 5: m_SelectedOperation = DIVIDE; break; case 7: m_SelectedOperation = AND; break; case 8: m_SelectedOperation = OR; break; case 9: m_SelectedOperation = XOR; break; default: this->ResetTwoImageOpPanel(); return; } m_Controls->tlImage2->setEnabled(true); m_Controls->m_ImageSelector2->setEnabled(true); m_Controls->btnDoIt2->setEnabled(true); } - -void QmitkBasicImageProcessing::TestButtonClicked() -{ - vtkSmartPointer vtkCam = vtkSmartPointer::New(); - - vtkCam->SetFocalPoint(-10.0, -10.0, 1); - vtkCam->SetPosition(-10.0, -10.0, 0); - vtkCam->SetViewUp(0.0, 1.0, 0.0); - vtkCam->SetParallelProjection(1); - GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetVtkRenderer()->SetActiveCamera(vtkCam); - GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetVtkRenderer()->ResetCamera(); - - for(int i = 0; i <= 25; i++) - { - vtkCam->SetDistance(900+i*3); - vtkCam->Modified(); - GetActiveStdMultiWidget()->ForceImmediateUpdate(); -// sleep(1); - } - QMessageBox::critical(0, "Opening Perspective Failed", QString("The perspective could not be opened.\nSee the log for details.")); -} - -void QmitkBasicImageProcessing::ViewZClicked() -{ - - vtkSmartPointer vtkCam = vtkSmartPointer::New(); - - vtkCam->SetFocalPoint(0.0, 0.0, 1.0); - vtkCam->SetPosition(0.0, 0.0, 0.0); - vtkCam->SetViewUp(0.0, -1.0, 0.0); - vtkCam->SetParallelProjection(1); - GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetVtkRenderer()->SetActiveCamera(vtkCam); - GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetVtkRenderer()->ResetCamera(); - GetActiveStdMultiWidget()->ForceImmediateUpdate(); -} - -void QmitkBasicImageProcessing::ViewXClicked() -{ - - vtkSmartPointer vtkCam = vtkSmartPointer::New(); - - vtkCam->SetFocalPoint(-1.0, 0.0, 0.0); - vtkCam->SetPosition(0.0, 0.0, 0.0); - vtkCam->SetViewUp(0.0, 0.0, 1.0); - vtkCam->SetParallelProjection(1); - GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetVtkRenderer()->SetActiveCamera(vtkCam); - GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetVtkRenderer()->ResetCamera(); - GetActiveStdMultiWidget()->ForceImmediateUpdate(); -} - -void QmitkBasicImageProcessing::ViewYClicked() -{ - - vtkSmartPointer vtkCam = vtkSmartPointer::New(); - - vtkCam->SetFocalPoint(0.0, 1.0, 0.0); - vtkCam->SetPosition(0.0, 0.0, 0.0); - vtkCam->SetViewUp(-1.0, 0.0, 0.0); - vtkCam->SetParallelProjection(1); - GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetVtkRenderer()->SetActiveCamera(vtkCam); - GetActiveStdMultiWidget()->GetRenderWindow1()->GetRenderer()->GetVtkRenderer()->ResetCamera(); - GetActiveStdMultiWidget()->ForceImmediateUpdate(); -} - - void QmitkBasicImageProcessing::StartButton2Clicked() { mitk::Image::Pointer newImage1 = dynamic_cast - (m_SelectedImageNode->GetNode()->GetData()); + (m_SelectedImageNode->GetNode()->GetData()); mitk::Image::Pointer newImage2 = dynamic_cast - (m_Controls->m_ImageSelector2->GetSelectedNode()->GetData()); + (m_Controls->m_ImageSelector2->GetSelectedNode()->GetData()); // check if images are valid if( (!newImage1) || (!newImage2) || (newImage1->IsInitialized() == false) || (newImage2->IsInitialized() == false) ) { itkGenericExceptionMacro(<< "At least one of the input images are broken or not initialized. Returning"); return; } this->BusyCursorOn(); this->ResetTwoImageOpPanel(); // check if 4D image and use filter on correct time step int time = ((QmitkSliderNavigatorWidget*)m_Controls->sliceNavigatorTime)->GetPos(); if(time>=0) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(newImage1); timeSelector->SetTimeNr( time ); timeSelector->UpdateLargestPossibleRegion(); newImage1 = timeSelector->GetOutput(); newImage1->DisconnectPipeline(); timeSelector->SetInput(newImage2); timeSelector->SetTimeNr( time ); timeSelector->UpdateLargestPossibleRegion(); newImage2 = timeSelector->GetOutput(); newImage2->DisconnectPipeline(); } // reset GUI for better usability this->ResetTwoImageOpPanel(); ImageType::Pointer itkImage1 = ImageType::New(); ImageType::Pointer itkImage2 = ImageType::New(); CastToItkImage( newImage1, itkImage1 ); CastToItkImage( newImage2, itkImage2 ); // Remove temp image newImage2 = NULL; std::string nameAddition = ""; try { - switch (m_SelectedOperation) + switch (m_SelectedOperation) + { + case ADD: { - case ADD: - { - AddFilterType::Pointer addFilter = AddFilterType::New(); - addFilter->SetInput1( itkImage1 ); - addFilter->SetInput2( itkImage2 ); - addFilter->UpdateLargestPossibleRegion(); - newImage1 = mitk::ImportItkImage(addFilter->GetOutput()); - nameAddition = "_Added"; - } - break; - - case SUBTRACT: - { - SubtractFilterType::Pointer subFilter = SubtractFilterType::New(); - subFilter->SetInput1( itkImage1 ); - subFilter->SetInput2( itkImage2 ); - subFilter->UpdateLargestPossibleRegion(); - newImage1 = mitk::ImportItkImage(subFilter->GetOutput()); - nameAddition = "_Subtracted"; - } - break; + AddFilterType::Pointer addFilter = AddFilterType::New(); + addFilter->SetInput1( itkImage1 ); + addFilter->SetInput2( itkImage2 ); + addFilter->UpdateLargestPossibleRegion(); + newImage1 = mitk::ImportItkImage(addFilter->GetOutput()); + nameAddition = "_Added"; + } + break; - case MULTIPLY: - { - MultiplyFilterType::Pointer multFilter = MultiplyFilterType::New(); - multFilter->SetInput1( itkImage1 ); - multFilter->SetInput2( itkImage2 ); - multFilter->UpdateLargestPossibleRegion(); - newImage1 = mitk::ImportItkImage(multFilter->GetOutput()); - nameAddition = "_Multiplied"; - } - break; + case SUBTRACT: + { + SubtractFilterType::Pointer subFilter = SubtractFilterType::New(); + subFilter->SetInput1( itkImage1 ); + subFilter->SetInput2( itkImage2 ); + subFilter->UpdateLargestPossibleRegion(); + newImage1 = mitk::ImportItkImage(subFilter->GetOutput()); + nameAddition = "_Subtracted"; + } + break; - case DIVIDE: - { - DivideFilterType::Pointer divFilter = DivideFilterType::New(); - divFilter->SetInput1( itkImage1 ); - divFilter->SetInput2( itkImage2 ); - divFilter->UpdateLargestPossibleRegion(); - newImage1 = mitk::ImportItkImage(divFilter->GetOutput()); - nameAddition = "_Divided"; - } - break; + case MULTIPLY: + { + MultiplyFilterType::Pointer multFilter = MultiplyFilterType::New(); + multFilter->SetInput1( itkImage1 ); + multFilter->SetInput2( itkImage2 ); + multFilter->UpdateLargestPossibleRegion(); + newImage1 = mitk::ImportItkImage(multFilter->GetOutput()); + nameAddition = "_Multiplied"; + } + break; - case AND: - { - AndImageFilterType::Pointer andFilter = AndImageFilterType::New(); - andFilter->SetInput1( itkImage1 ); - andFilter->SetInput2( itkImage2 ); - andFilter->UpdateLargestPossibleRegion(); - newImage1 = mitk::ImportItkImage(andFilter->GetOutput()); - nameAddition = "_AND"; - break; - } + case DIVIDE: + { + DivideFilterType::Pointer divFilter = DivideFilterType::New(); + divFilter->SetInput1( itkImage1 ); + divFilter->SetInput2( itkImage2 ); + divFilter->UpdateLargestPossibleRegion(); + newImage1 = mitk::ImportItkImage(divFilter->GetOutput()); + nameAddition = "_Divided"; + } + break; - case OR: - { - OrImageFilterType::Pointer orFilter = OrImageFilterType::New(); - orFilter->SetInput1( itkImage1 ); - orFilter->SetInput2( itkImage2 ); - orFilter->UpdateLargestPossibleRegion(); - newImage1 = mitk::ImportItkImage(orFilter->GetOutput()); - nameAddition = "_OR"; - break; - } + case AND: + { + AndImageFilterType::Pointer andFilter = AndImageFilterType::New(); + andFilter->SetInput1( itkImage1 ); + andFilter->SetInput2( itkImage2 ); + andFilter->UpdateLargestPossibleRegion(); + newImage1 = mitk::ImportItkImage(andFilter->GetOutput()); + nameAddition = "_AND"; + break; + } - case XOR: - { - XorImageFilterType::Pointer xorFilter = XorImageFilterType::New(); - xorFilter->SetInput1( itkImage1 ); - xorFilter->SetInput2( itkImage2 ); - xorFilter->UpdateLargestPossibleRegion(); - newImage1 = mitk::ImportItkImage(xorFilter->GetOutput()); - nameAddition = "_XOR"; - break; - } + case OR: + { + OrImageFilterType::Pointer orFilter = OrImageFilterType::New(); + orFilter->SetInput1( itkImage1 ); + orFilter->SetInput2( itkImage2 ); + orFilter->UpdateLargestPossibleRegion(); + newImage1 = mitk::ImportItkImage(orFilter->GetOutput()); + nameAddition = "_OR"; + break; + } - default: - std::cout << "Something went wrong..." << std::endl; - this->BusyCursorOff(); - return; + case XOR: + { + XorImageFilterType::Pointer xorFilter = XorImageFilterType::New(); + xorFilter->SetInput1( itkImage1 ); + xorFilter->SetInput2( itkImage2 ); + xorFilter->UpdateLargestPossibleRegion(); + newImage1 = mitk::ImportItkImage(xorFilter->GetOutput()); + nameAddition = "_XOR"; + break; } + + default: + std::cout << "Something went wrong..." << std::endl; + this->BusyCursorOff(); + return; + } } catch (...) { this->BusyCursorOff(); QMessageBox::warning(NULL, "Warning", "Problem when applying arithmetic operation to two images. Check dimensions of input images."); return; } // disconnect pipeline; images will not be reused newImage1->DisconnectPipeline(); itkImage1 = NULL; itkImage2 = NULL; // adjust level/window to new image and compose new image name mitk::LevelWindow levelwindow; levelwindow.SetAuto( newImage1 ); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); levWinProp->SetLevelWindow( levelwindow ); std::string name = m_SelectedImageNode->GetNode()->GetName(); if (name.find(".pic.gz") == name.size() -7 ) { name = name.substr(0,name.size() -7); } // create final result MITK data storage node mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty( "levelwindow", levWinProp ); result->SetProperty( "name", mitk::StringProperty::New( (name + nameAddition ).c_str() )); result->SetData( newImage1 ); GetDefaultDataStorage()->Add( result, m_SelectedImageNode->GetNode() ); // show only the newly created image m_SelectedImageNode->GetNode()->SetProperty( "visible", mitk::BoolProperty::New(false) ); m_Controls->m_ImageSelector2->GetSelectedNode()->SetProperty( "visible", mitk::BoolProperty::New(false) ); // show the newly created image mitk::RenderingManager::GetInstance()->RequestUpdateAll(); this->BusyCursorOff(); } diff --git a/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingView.h b/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingView.h index 89117582a4..410743505e 100644 --- a/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingView.h +++ b/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingView.h @@ -1,192 +1,185 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 10185 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #if !defined(QmitkBasicImageProcessingView_H__INCLUDED) #define QmitkBasicImageProcessingView_H__INCLUDED #include "QmitkFunctionality.h" #include #include "ui_QmitkBasicImageProcessingViewControls.h" #include "QmitkStepperAdapter.h" #include #include /*! \brief This module allows to use some basic image processing filters for preprocessing, image enhancement and testing purposes Several basic ITK image processing filters, like denoising, morphological and edge detection are encapsulated in this module and can be selected via a list and an intuitive parameter input. The selected filter will be applied on the image, and a new image showing the output is displayed as result. Also, some image arithmetic operations are available. Images can be 3D or 4D. In the 4D case, the filters work on the 3D image selected via the time slider. The result is also a 3D image. \sa QmitkFunctionality, QObject \class QmitkBasicImageProcessing \author Tobias Schwarz \version 1.0 (3M3) \date 2009-05-10 \ingroup Bundles */ class BASICIMAGEPROCESSING_EXPORT QmitkBasicImageProcessing : public QmitkFunctionality { Q_OBJECT public: /*! \brief default constructor */ QmitkBasicImageProcessing(); QmitkBasicImageProcessing(const QmitkBasicImageProcessing& other) { Q_UNUSED(other) throw std::runtime_error("Copy constructor not implemented"); } /*! \brief default destructor */ virtual ~QmitkBasicImageProcessing(); /*! \brief method for creating the widget containing the application controls, like sliders, buttons etc. */ virtual void CreateQtPartControl(QWidget *parent); /*! \brief method for creating the connections of main and control widget */ virtual void CreateConnections(); virtual void Activated(); /*! \brief Invoked when the DataManager selection changed */ virtual void OnSelectionChanged(std::vector nodes); protected slots: /* * When an action is selected in the "one image ops" list box */ void SelectAction(int action); /* * When an action is selected in the "two image ops" list box */ void SelectAction2(int operation); /* * The "Execute" button in the "one image ops" box was triggered */ void StartButtonClicked(); /* * The "Execute" button in the "two image ops" box was triggered */ void StartButton2Clicked(); /* * Switch between the one and the two image operations GUI */ void ChangeGUI(); - void ViewXClicked(); - void ViewYClicked(); - void ViewZClicked(); - - void TestButtonClicked(); - - private: /* * After a one image operation, reset the "one image ops" panel */ void ResetOneImageOpPanel(); /* * Helper method to reset the parameter set panel */ void ResetParameterPanel(); /* * After a two image operation, reset the "two image ops" panel */ void ResetTwoImageOpPanel(); /*! * controls containing sliders for scrolling through the slices */ Ui::QmitkBasicImageProcessingViewControls *m_Controls; //mitk::DataNode* m_SelectedImageNode; mitk::DataStorageSelection::Pointer m_SelectedImageNode; QmitkStepperAdapter* m_TimeStepperAdapter; berry::ISelectionListener::Pointer m_SelectionListener; enum ActionType { NOACTIONSELECTED, CATEGORY_DENOISING, GAUSSIAN, MEDIAN, TOTALVARIATION, CATEGORY_MORPHOLOGICAL, DILATION, EROSION, OPENING, CLOSING, CATEGORY_EDGE_DETECTION, GRADIENT, LAPLACIAN, SOBEL, CATEGORY_MISC, THRESHOLD, INVERSION, DOWNSAMPLING, } m_SelectedAction; enum OperationType{ TWOIMAGESNOACTIONSELECTED, CATEGORY_ARITHMETIC, ADD, SUBTRACT, MULTIPLY, DIVIDE, CATEGORY_BOOLEAN, AND, OR, XOR } m_SelectedOperation; }; #endif // !defined(QmitkBasicImageProcessing_H__INCLUDED) diff --git a/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui b/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui index c38288c99a..ae1765e459 100644 --- a/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui +++ b/Modules/Bundles/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui @@ -1,372 +1,344 @@ QmitkBasicImageProcessingViewControls 0 0 - 311 + 272 980 Form true 0 6 0 6 Filters (One Image) true Arithmetic (Two Images) Select an Image in Data Manager true false Output image will be 3D Choose time step if 4D (Slider for both images) false false Output image will be 3D true 0 6 0 0 false Select an operation: false cbWhat1 false false ... and parameters: false false Parameter 1: false sbParam1 false false Parameter 2: false sbParam2 false false &Execute false Hide Original Image true true true false false 0 6 0 0 false Select second image: false m_ImageSelector2 false false E&xecute false Select an operation: false cbWhat2 false - + Qt::Vertical 254 403 - - - - Set InteractionStyle - - - - - - - View X - - - - - - - View Y - - - - - - - View Z - - - QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkSliderNavigatorWidget QWidget
QmitkSliderNavigatorWidget.h
diff --git a/Modules/IGT/IGTFilters/mitkCameraVisualization.cpp b/Modules/IGT/IGTFilters/mitkCameraVisualization.cpp index 371a7fbdb2..85727a7a3b 100644 --- a/Modules/IGT/IGTFilters/mitkCameraVisualization.cpp +++ b/Modules/IGT/IGTFilters/mitkCameraVisualization.cpp @@ -1,148 +1,146 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkCameraVisualization.h" #include "vtkCamera.h" #include "mitkPropertyList.h" #include "mitkProperties.h" mitk::CameraVisualization::CameraVisualization(): NavigationDataToNavigationDataFilter(), m_Renderer(NULL), m_FocalLength(10.0), m_ViewAngle(30.0) { // initialize members m_DirectionOfProjectionInToolCoordinates[0] = 0; m_DirectionOfProjectionInToolCoordinates[1] = 0; m_DirectionOfProjectionInToolCoordinates[2] = -1; m_ViewUpInToolCoordinates[0] = 1; m_ViewUpInToolCoordinates[1] = 0; m_ViewUpInToolCoordinates[2] = 0; - m_DirectionOfProjection.Fill(0); } mitk::CameraVisualization::~CameraVisualization() { } void mitk::CameraVisualization::GenerateData() { // check if renderer was set if (m_Renderer.IsNull()) itkExceptionMacro(<< "Renderer was not properly set"); /* update outputs with tracking data from tools */ unsigned int numberOfInputs = this->GetNumberOfInputs(); for (unsigned int i = 0; i < numberOfInputs ; ++i) { mitk::NavigationData* output = this->GetOutput(i); assert(output); const mitk::NavigationData* input = this->GetInput(i); assert(input); if (input->IsDataValid() == false) { continue; } output->Graft(input); // First, copy all information from input to output } const NavigationData* navigationData = this->GetInput(); // get position from NavigationData to move the camera to this position - m_CameraPosition = navigationData->GetPosition(); + Point3D cameraPosition = navigationData->GetPosition(); //calculate the transform from the quaternions static itk::QuaternionRigidTransform::Pointer quatTransform = itk::QuaternionRigidTransform::New(); mitk::NavigationData::OrientationType orientation = navigationData->GetOrientation(); // convert mitk::Scalartype quaternion to double quaternion because of itk bug vnl_quaternion doubleQuaternion(orientation.x(), orientation.y(), orientation.z(), orientation.r()); quatTransform->SetIdentity(); quatTransform->SetRotation(doubleQuaternion); quatTransform->Modified(); /* because of an itk bug, the transform can not be calculated with float datatype. To use it in the mitk geometry classes, it has to be transfered to mitk::ScalarType which is float */ static AffineTransform3D::MatrixType m; mitk::TransferMatrix(quatTransform->GetMatrix(), m); - m_DirectionOfProjection = m*m_DirectionOfProjectionInToolCoordinates; - m_DirectionOfProjection.Normalize(); - Point3D focalPoint = m_CameraPosition + m_FocalLength*m_DirectionOfProjection; + Vector3D directionOfProjection = m*m_DirectionOfProjectionInToolCoordinates; + directionOfProjection.Normalize(); + Point3D focalPoint = cameraPosition + m_FocalLength*directionOfProjection; // compute current view up vector Vector3D viewUp = m*m_ViewUpInToolCoordinates; - m_Renderer->GetVtkRenderer()->GetActiveCamera()->SetPosition(m_CameraPosition[0],m_CameraPosition[1],m_CameraPosition[2]); + m_Renderer->GetVtkRenderer()->GetActiveCamera()->SetPosition(cameraPosition[0],cameraPosition[1],cameraPosition[2]); m_Renderer->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(focalPoint[0],focalPoint[1],focalPoint[2]); m_Renderer->GetVtkRenderer()->GetActiveCamera()->SetViewUp(viewUp[0],viewUp[1],viewUp[2]); m_Renderer->GetVtkRenderer()->ResetCameraClippingRange(); m_Renderer->RequestUpdate(); - MITK_INFO << "mitkCameraVisualization.cpp"; } void mitk::CameraVisualization::SetRenderer(mitk::BaseRenderer* renderer) { m_Renderer = renderer; // if (m_Renderer) // { // m_Renderer->GetVtkRenderer()->GetActiveCamera()->Zoom(0.4); // } } const mitk::BaseRenderer* mitk::CameraVisualization::GetRenderer() { return m_Renderer; } void mitk::CameraVisualization::SetParameters( const mitk::PropertyList* p ) { if (p == NULL) return; mitk::Vector3D doP; if (p->GetPropertyValue("CameraVisualization_DirectionOfProjectionInToolCoordinates", doP) == true) // search for DirectionOfProjectionInToolCoordinates parameter this->SetDirectionOfProjectionInToolCoordinates(doP); // apply if found; mitk::Vector3D vUp; if (p->GetPropertyValue("CameraVisualization_ViewUpInToolCoordinates", vUp) == true) // search for ViewUpInToolCoordinates parameter this->SetViewUpInToolCoordinates(vUp); // apply if found; float fL; if (p->GetPropertyValue("CameraVisualization_FocalLength", fL) == true) // search for FocalLength parameter this->SetFocalLength(fL); // apply if found; float vA; if (p->GetPropertyValue("CameraVisualization_ViewAngle", vA) == true) // search for ViewAngle parameter this->SetFocalLength(vA); // apply if found; } mitk::PropertyList::ConstPointer mitk::CameraVisualization::GetParameters() const { mitk::PropertyList::Pointer p = mitk::PropertyList::New(); p->SetProperty("CameraVisualization_DirectionOfProjectionInToolCoordinates", mitk::Vector3DProperty::New(this->GetDirectionOfProjectionInToolCoordinates())); // store DirectionOfProjectionInToolCoordinates parameter p->SetProperty("CameraVisualization_ViewUpInToolCoordinates", mitk::Vector3DProperty::New(this->GetViewUpInToolCoordinates())); // store ViewUpInToolCoordinates parameter p->SetProperty("CameraVisualization_FocalLength", mitk::Vector3DProperty::New(this->GetFocalLength())); // store FocalLength parameter p->SetProperty("CameraVisualization_ViewAngle", mitk::Vector3DProperty::New(this->GetViewAngle())); // store ViewAngle parameter return mitk::PropertyList::ConstPointer(p); } diff --git a/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.cpp b/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.cpp index 216ee052c0..9faddb5017 100644 --- a/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.cpp +++ b/Modules/MitkExt/Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.cpp @@ -1,7343 +1,7342 @@ /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkMitkOpenGLGPUVolumeRayCastMapper.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkMitkOpenGLGPUVolumeRayCastMapper.h" // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) #include "vtkObjectFactory.h" #include "vtkVolume.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkCamera.h" #include "vtkMatrix4x4.h" #include "vtkImageData.h" #include "vtkTimerLog.h" #include "vtkVolumeProperty.h" #include "vtkColorTransferFunction.h" #include "vtkPiecewiseFunction.h" #include "vtkOpenGLExtensionManager.h" #include "vtkgl.h" #ifndef VTK_IMPLEMENT_MESA_CXX # include "vtkOpenGL.h" #endif #include #include #include #include #include #include "vtkClipDataSet.h" #include "vtkCellArray.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkGeometryFilter.h" #include "vtkMath.h" #include "vtkPlane.h" #include "vtkPlaneCollection.h" #include "vtkPlanes.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkPoints.h" #include "vtkUnsignedCharArray.h" #include "vtkUnsignedShortArray.h" #include "vtkUnsignedIntArray.h" #include "vtkUnstructuredGrid.h" #include "vtkVoxel.h" #include "vtkClipConvexPolyData.h" #include "vtkClipPolyData.h" #include "vtkDensifyPolyData.h" #include "vtkImageResample.h" #include #include // qsort() #include "vtkDataSetTriangleFilter.h" #include "vtkAbstractArray.h" // required if compiled against VTK 5.0 #include "vtkTessellatedBoxSource.h" #include "vtkCleanPolyData.h" #include "vtkCommand.h" // for VolumeMapperRender{Start|End|Progress}Event #include "vtkPerlinNoise.h" #include #include "vtkStdString.h" //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- class vtkUnsupportedRequiredExtensionsStringStream { public: vtkstd::ostringstream Stream; vtkUnsupportedRequiredExtensionsStringStream() { } private: // undefined copy constructor. vtkUnsupportedRequiredExtensionsStringStream(const vtkUnsupportedRequiredExtensionsStringStream &other); // undefined assignment operator. vtkUnsupportedRequiredExtensionsStringStream &operator=(const vtkUnsupportedRequiredExtensionsStringStream &other); }; class vtkMapDataArrayTextureId { public: vtkstd::map Map; vtkMapDataArrayTextureId() { } private: // undefined copy constructor. vtkMapDataArrayTextureId(const vtkMapDataArrayTextureId &other); // undefined assignment operator. vtkMapDataArrayTextureId &operator=(const vtkMapDataArrayTextureId &other); }; class vtkMapMaskTextureId { public: vtkstd::map Map; vtkMapMaskTextureId() { } private: // undefined copy constructor. vtkMapMaskTextureId(const vtkMapMaskTextureId &other); // undefined assignment operator. vtkMapMaskTextureId &operator=(const vtkMapMaskTextureId &other); }; //----------------------------------------------------------------------------- extern const char *vtkMitkGPUVolumeRayCastMapper_CompositeFS; extern const char *vtkMitkGPUVolumeRayCastMapper_CompositeCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_CompositeNoCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_HeaderFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPFourDependentFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPFourDependentCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPFourDependentNoCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MIPNoCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_ParallelProjectionFS; extern const char *vtkMitkGPUVolumeRayCastMapper_PerspectiveProjectionFS; extern const char *vtkMitkGPUVolumeRayCastMapper_ScaleBiasFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPFourDependentFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPFourDependentCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPFourDependentNoCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_MinIPNoCroppingFS; extern const char *vtkMitkGPUVolumeRayCastMapper_CompositeMaskFS; extern const char *vtkMitkGPUVolumeRayCastMapper_NoShadeFS; extern const char *vtkMitkGPUVolumeRayCastMapper_ShadeFS; extern const char *vtkMitkGPUVolumeRayCastMapper_OneComponentFS; extern const char *vtkMitkGPUVolumeRayCastMapper_FourComponentsFS; enum { vtkMitkOpenGLGPUVolumeRayCastMapperProjectionNotInitialized=-1, // not init vtkMitkOpenGLGPUVolumeRayCastMapperProjectionPerspective=0, // false vtkMitkOpenGLGPUVolumeRayCastMapperProjectionParallel=1 // true }; enum { vtkMitkOpenGLGPUVolumeRayCastMapperMethodNotInitialized, vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP, vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIPFourDependent, vtkMitkOpenGLGPUVolumeRayCastMapperMethodComposite, vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIP, vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIPFourDependent, vtkMitkOpenGLGPUVolumeRayCastMapperMethodCompositeMask }; // component implementation enum { vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotInitialized=-1, // not init vtkMitkOpenGLGPUVolumeRayCastMapperComponentOne=0, // false vtkMitkOpenGLGPUVolumeRayCastMapperComponentFour=1, // true vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotUsed=2 // when not composite }; // Shade implementation enum { vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotInitialized=-1, // not init vtkMitkOpenGLGPUVolumeRayCastMapperShadeNo=0, // false vtkMitkOpenGLGPUVolumeRayCastMapperShadeYes=1, // true vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotUsed=2 // when not composite }; // Cropping implementation enum { vtkMitkOpenGLGPUVolumeRayCastMapperCroppingNotInitialized, vtkMitkOpenGLGPUVolumeRayCastMapperCompositeCropping, vtkMitkOpenGLGPUVolumeRayCastMapperCompositeNoCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMIPCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMIPNoCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMIPFourDependentCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMIPFourDependentNoCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMinIPCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMinIPNoCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMinIPFourDependentCropping, vtkMitkOpenGLGPUVolumeRayCastMapperMinIPFourDependentNoCropping }; enum { vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectDepthMap=0, // 2d texture vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront // 2d texture }; const int vtkMitkOpenGLGPUVolumeRayCastMapperNumberOfTextureObjects=vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+2; const int vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize=1024; //power of two #ifndef VTK_IMPLEMENT_MESA_CXX vtkCxxRevisionMacro(vtkMitkOpenGLGPUVolumeRayCastMapper, "$Revision: 1.9 $"); vtkStandardNewMacro(vtkMitkOpenGLGPUVolumeRayCastMapper); #endif //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- class vtkOpacityTable { public: vtkOpacityTable() { this->TextureId=0; this->LastBlendMode=vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND; this->LastSampleDistance=1.0; this->Table=0; this->Loaded=false; this->LastLinearInterpolation=false; } ~vtkOpacityTable() { if(this->TextureId!=0) { glDeleteTextures(1,&this->TextureId); this->TextureId=0; } if(this->Table!=0) { delete[] this->Table; this->Table=0; } } bool IsLoaded() { return this->Loaded; } void Bind() { assert("pre: uptodate" && this->Loaded); glBindTexture(GL_TEXTURE_1D,this->TextureId); } // \pre the active texture is set to TEXTURE2 void Update(vtkPiecewiseFunction *scalarOpacity, int blendMode, double sampleDistance, double range[2], double unitDistance, bool linearInterpolation) { assert("pre: scalarOpacity_exists" && scalarOpacity!=0); bool needUpdate=false; if(this->TextureId==0) { glGenTextures(1,&this->TextureId); needUpdate=true; } glBindTexture(GL_TEXTURE_1D,this->TextureId); if(needUpdate) { glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); } if(scalarOpacity->GetMTime() > this->BuildTime || (this->LastBlendMode!=blendMode) || (blendMode==vtkVolumeMapper::COMPOSITE_BLEND && this->LastSampleDistance!=sampleDistance) || needUpdate || !this->Loaded) { this->Loaded=false; if(this->Table==0) { this->Table= new float[vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize]; } scalarOpacity->GetTable(range[0],range[1], vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize, this->Table); this->LastBlendMode=blendMode; // Correct the opacity array for the spacing between the planes if we // are using a composite blending operation if(blendMode==vtkVolumeMapper::COMPOSITE_BLEND) { float *ptr=this->Table; double factor=sampleDistance/unitDistance; int i=0; while(i0.0001f) { *ptr=static_cast(1.0-pow(1.0-static_cast(*ptr), factor)); } ++ptr; ++i; } this->LastSampleDistance=sampleDistance; } glTexImage1D(GL_TEXTURE_1D,0,GL_ALPHA16, vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize,0, GL_ALPHA,GL_FLOAT,this->Table); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("1d opacity texture is too large"); this->Loaded=true; this->BuildTime.Modified(); } needUpdate=needUpdate || this->LastLinearInterpolation!=linearInterpolation; if(needUpdate) { this->LastLinearInterpolation=linearInterpolation; GLint value; if(linearInterpolation) { value=GL_LINEAR; } else { value=GL_NEAREST; } glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,value); glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,value); } } protected: GLuint TextureId; int LastBlendMode; double LastSampleDistance; vtkTimeStamp BuildTime; float *Table; bool Loaded; bool LastLinearInterpolation; }; //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- class vtkOpacityTables { public: vtkstd::vector Vector; vtkOpacityTables(size_t numberOfLevels) : Vector(numberOfLevels) { } private: // undefined copy constructor. vtkOpacityTables(const vtkOpacityTables &other); // undefined assignment operator. vtkOpacityTables &operator=(const vtkOpacityTables &other); }; //----------------------------------------------------------------------------- class vtkRGBTable { public: vtkRGBTable() { this->TextureId=0; this->Table=0; this->Loaded=false; this->LastLinearInterpolation=false; } ~vtkRGBTable() { if(this->TextureId!=0) { glDeleteTextures(1,&this->TextureId); this->TextureId=0; } if(this->Table!=0) { delete[] this->Table; this->Table=0; } } bool IsLoaded() { return this->Loaded; } void Bind() { assert("pre: uptodate" && this->Loaded); glBindTexture(GL_TEXTURE_1D,this->TextureId); } // \pre the active texture is set properly. (default color, // mask1, mask2,..) void Update(vtkColorTransferFunction *scalarRGB, double range[2], bool linearInterpolation) { assert("pre: scalarRGB_exists" && scalarRGB!=0); bool needUpdate=false; if(this->TextureId==0) { glGenTextures(1,&this->TextureId); needUpdate=true; } glBindTexture(GL_TEXTURE_1D,this->TextureId); if(needUpdate) { glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); } if(scalarRGB->GetMTime() > this->BuildTime || needUpdate || !this->Loaded) { this->Loaded=false; if(this->Table==0) { this->Table= new float[vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize*3]; } scalarRGB->GetTable(range[0],range[1], vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize, this->Table); glTexImage1D(GL_TEXTURE_1D,0,GL_RGB16, vtkMitkOpenGLGPUVolumeRayCastMapperOpacityTableSize,0, GL_RGB,GL_FLOAT,this->Table); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("1d RGB texture is too large"); this->Loaded=true; this->BuildTime.Modified(); } needUpdate=needUpdate || this->LastLinearInterpolation!=linearInterpolation; if(needUpdate) { this->LastLinearInterpolation=linearInterpolation; GLint value; if(linearInterpolation) { value=GL_LINEAR; } else { value=GL_NEAREST; } glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,value); glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,value); } } protected: GLuint TextureId; vtkTimeStamp BuildTime; float *Table; bool Loaded; bool LastLinearInterpolation; }; //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- class vtkKWScalarField { public: vtkKWScalarField() { this->TextureId=0; this->Loaded=false; this->Supports_GL_ARB_texture_float=false; this->LoadedTableRange[0]=0.0; this->LoadedTableRange[1]=1.0; this->LoadedExtent[0]=VTK_INT_MAX; this->LoadedExtent[1]=VTK_INT_MIN; this->LoadedExtent[2]=VTK_INT_MAX; this->LoadedExtent[3]=VTK_INT_MIN; this->LoadedExtent[4]=VTK_INT_MAX; this->LoadedExtent[5]=VTK_INT_MIN; } ~vtkKWScalarField() { if(this->TextureId!=0) { glDeleteTextures(1,&this->TextureId); this->TextureId=0; } } vtkTimeStamp GetBuildTime() { return this->BuildTime; } void Bind() { assert("pre: uptodate" && this->Loaded); glBindTexture(vtkgl::TEXTURE_3D,this->TextureId); } void Update(vtkImageData *input, int cellFlag, int textureExtent[6], int scalarMode, int arrayAccessMode, int arrayId, const char *arrayName, bool linearInterpolation, double tableRange[2], int maxMemoryInBytes) { bool needUpdate=false; bool modified=false; if(this->TextureId==0) { glGenTextures(1,&this->TextureId); needUpdate=true; } glBindTexture(vtkgl::TEXTURE_3D,this->TextureId); int obsolete=needUpdate || !this->Loaded || input->GetMTime()>this->BuildTime; if(!obsolete) { obsolete=cellFlag!=this->LoadedCellFlag; int i=0; while(!obsolete && i<6) { obsolete=obsolete || this->LoadedExtent[i]>textureExtent[i]; ++i; obsolete=obsolete || this->LoadedExtent[i]LoadedTableRange[0]!=tableRange[0] || this->LoadedTableRange[1]!=tableRange[1]; } if(obsolete) { this->Loaded=false; int dim[3]; input->GetDimensions(dim); GLint internalFormat=0; GLenum format=0; GLenum type=0; // shift then scale: y:=(x+shift)*scale double shift=0.0; double scale=1.0; int needTypeConversion=0; vtkDataArray *sliceArray=0; vtkDataArray *scalars= vtkAbstractMapper::GetScalars(input,scalarMode,arrayAccessMode, arrayId,arrayName, this->LoadedCellFlag); // DONT USE GetScalarType() or GetNumberOfScalarComponents() on // ImageData as it deals only with point data... int scalarType=scalars->GetDataType(); if(scalars->GetNumberOfComponents()==4) { // this is RGBA, unsigned char only internalFormat=GL_RGBA16; format=GL_RGBA; type=GL_UNSIGNED_BYTE; } else { // input->GetNumberOfScalarComponents()==1 switch(scalarType) { case VTK_FLOAT: if(this->Supports_GL_ARB_texture_float) { internalFormat=vtkgl::INTENSITY16F_ARB; } else { internalFormat=GL_INTENSITY16; } format=GL_RED; type=GL_FLOAT; shift=-tableRange[0]; scale=1/(tableRange[1]-tableRange[0]); break; case VTK_UNSIGNED_CHAR: internalFormat=GL_INTENSITY8; format=GL_RED; type=GL_UNSIGNED_BYTE; shift=-tableRange[0]/VTK_UNSIGNED_CHAR_MAX; scale= VTK_UNSIGNED_CHAR_MAX/(tableRange[1]-tableRange[0]); break; case VTK_SIGNED_CHAR: internalFormat=GL_INTENSITY8; format=GL_RED; type=GL_BYTE; shift=-(2*tableRange[0]+1)/VTK_UNSIGNED_CHAR_MAX; scale=VTK_SIGNED_CHAR_MAX/(tableRange[1]-tableRange[0]); break; case VTK_CHAR: // not supported assert("check: impossible case" && 0); break; case VTK_BIT: // not supported assert("check: impossible case" && 0); break; case VTK_ID_TYPE: // not supported assert("check: impossible case" && 0); break; case VTK_INT: internalFormat=GL_INTENSITY16; format=GL_RED; type=GL_INT; shift=-(2*tableRange[0]+1)/VTK_UNSIGNED_INT_MAX; scale=VTK_INT_MAX/(tableRange[1]-tableRange[0]); break; case VTK_DOUBLE: case VTK___INT64: case VTK_LONG: case VTK_LONG_LONG: case VTK_UNSIGNED___INT64: case VTK_UNSIGNED_LONG: case VTK_UNSIGNED_LONG_LONG: needTypeConversion=1; // to float if(this->Supports_GL_ARB_texture_float) { internalFormat=vtkgl::INTENSITY16F_ARB; } else { internalFormat=GL_INTENSITY16; } format=GL_RED; type=GL_FLOAT; shift=-tableRange[0]; scale=1/(tableRange[1]-tableRange[0]); sliceArray=vtkFloatArray::New(); break; case VTK_SHORT: internalFormat=GL_INTENSITY16; format=GL_RED; type=GL_SHORT; shift=-(2*tableRange[0]+1)/VTK_UNSIGNED_SHORT_MAX; scale=VTK_SHORT_MAX/(tableRange[1]-tableRange[0]); break; case VTK_STRING: // not supported assert("check: impossible case" && 0); break; case VTK_UNSIGNED_SHORT: internalFormat=GL_INTENSITY16; format=GL_RED; type=GL_UNSIGNED_SHORT; shift=-tableRange[0]/VTK_UNSIGNED_SHORT_MAX; scale= VTK_UNSIGNED_SHORT_MAX/(tableRange[1]-tableRange[0]); break; case VTK_UNSIGNED_INT: internalFormat=GL_INTENSITY16; format=GL_RED; type=GL_UNSIGNED_INT; shift=-tableRange[0]/VTK_UNSIGNED_INT_MAX; scale=VTK_UNSIGNED_INT_MAX/(tableRange[1]-tableRange[0]); break; default: assert("check: impossible case" && 0); break; } } // Enough memory? int textureSize[3]; int i=0; while(i<3) { textureSize[i]=textureExtent[2*i+1]-textureExtent[2*i]+1; ++i; } GLint width; glGetIntegerv(vtkgl::MAX_3D_TEXTURE_SIZE,&width); this->Loaded=textureSize[0]<=width && textureSize[1]<=width && textureSize[2]<=width; if(this->Loaded) { // so far, so good. the texture size is theorically small enough // for OpenGL vtkgl::TexImage3D(vtkgl::PROXY_TEXTURE_3D,0,internalFormat, textureSize[0],textureSize[1],textureSize[2],0, format,type,0); glGetTexLevelParameteriv(vtkgl::PROXY_TEXTURE_3D,0,GL_TEXTURE_WIDTH, &width); this->Loaded=width!=0; if(this->Loaded) { // so far, so good but some cards always succeed with a proxy texture // let's try to actually allocate.. vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,internalFormat,textureSize[0], textureSize[1],textureSize[2],0,format,type,0); GLenum errorCode=glGetError(); this->Loaded=errorCode!=GL_OUT_OF_MEMORY; if(this->Loaded) { // so far, so good, actual allocation succeeded. if(errorCode!=GL_NO_ERROR) { cout<<"after try to load the texture"; cout<<" ERROR (x"<(errorCode)); cout<Loaded=textureSize[0]*textureSize[1]* textureSize[2]*vtkAbstractArray::GetDataTypeSize(scalarType)* scalars->GetNumberOfComponents()<=maxMemoryInBytes; if(this->Loaded) { // OK, we consider the allocation above succeeded... // If it actually didn't the only to fix it for the user // is to decrease the value of this->MaxMemoryInBytes. // enough memory! We can load the scalars! double bias=shift*scale; // we don't clamp to edge because for the computation of the // gradient on the border we need some external value. glTexParameterf(vtkgl::TEXTURE_3D,vtkgl::TEXTURE_WRAP_R,vtkgl::CLAMP_TO_EDGE); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_WRAP_S,vtkgl::CLAMP_TO_EDGE); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_WRAP_T,vtkgl::CLAMP_TO_EDGE); GLfloat borderColor[4]={0.0,0.0,0.0,0.0}; glTexParameterfv(vtkgl::TEXTURE_3D,GL_TEXTURE_BORDER_COLOR, borderColor); if(needTypeConversion) { // Convert and send to the GPU, z-slice by z-slice. // Allocate memory on the GPU (NULL data pointer with the right // dimensions) // Here we are assuming that GL_ARB_texture_non_power_of_two is // available glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // memory allocation is already done. // Send the slices: // allocate CPU memory for a slice. sliceArray->SetNumberOfComponents(1); // FB TODO CHECK THAT sliceArray->SetNumberOfTuples(textureSize[0]*textureSize[1]); void *slicePtr=sliceArray->GetVoidPointer(0); int k=0; int kInc=(dim[0]-cellFlag)*(dim[1]-cellFlag); int kOffset=(textureExtent[4]*(dim[1]-cellFlag) +textureExtent[2])*(dim[0]-cellFlag) +textureExtent[0]; while(kSetTuple1(jDestOffset+i, (scalars->GetTuple1(kOffset+jOffset +i) +shift)*scale); ++i; } ++j; jOffset+=dim[0]-cellFlag; jDestOffset+=textureSize[0]; } // Here we are assuming that GL_ARB_texture_non_power_of_two is // available vtkgl::TexSubImage3D(vtkgl::TEXTURE_3D, 0, 0,0,k, textureSize[0],textureSize[1], 1, // depth is 1, not 0! format,type, slicePtr); ++k; kOffset+=kInc; } sliceArray->Delete(); } else { // One chunk of data to the GPU. // It works for the whole volume or for a subvolume. // Here we are assuming that GL_ARB_texture_non_power_of_two is // available // make sure any previous OpenGL call is executed and will not // be disturbed by our PixelTransfer value glFinish(); glPixelTransferf(GL_RED_SCALE,static_cast(scale)); glPixelTransferf(GL_RED_BIAS,static_cast(bias)); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); if(!(textureExtent[1]-textureExtent[0]+cellFlag==dim[0])) { glPixelStorei(GL_UNPACK_ROW_LENGTH,dim[0]-cellFlag); } if(!(textureExtent[3]-textureExtent[2]+cellFlag==dim[1])) { glPixelStorei(vtkgl::UNPACK_IMAGE_HEIGHT_EXT, dim[1]-cellFlag); } void *dataPtr=scalars->GetVoidPointer( ((textureExtent[4]*(dim[1]-cellFlag)+textureExtent[2]) *(dim[0]-cellFlag)+textureExtent[0]) *scalars->GetNumberOfComponents()); if(1) // !this->SupportsPixelBufferObjects) { vtkgl::TexImage3D(vtkgl::TEXTURE_3D, 0, internalFormat, textureSize[0],textureSize[1],textureSize[2], 0,format,type,dataPtr); } else { GLuint pbo=0; vtkgl::GenBuffers(1,&pbo); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("genbuffer"); vtkgl::BindBuffer(vtkgl::PIXEL_UNPACK_BUFFER,pbo); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("binbuffer"); vtkgl::GLsizeiptr texSize= textureSize[0]*textureSize[1]*textureSize[2]* vtkAbstractArray::GetDataTypeSize(scalarType)* scalars->GetNumberOfComponents(); vtkgl::BufferData(vtkgl::PIXEL_UNPACK_BUFFER,texSize,dataPtr, vtkgl::STREAM_DRAW); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("bufferdata"); vtkgl::TexImage3D(vtkgl::TEXTURE_3D, 0, internalFormat, textureSize[0],textureSize[1],textureSize[2], 0,format,type,0); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("teximage3d"); vtkgl::BindBuffer(vtkgl::PIXEL_UNPACK_BUFFER,0); vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("bindbuffer to 0"); vtkgl::DeleteBuffers(1,&pbo); } vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError("3d texture is too large2"); // make sure TexImage3D is executed with our PixelTransfer mode glFinish(); // Restore the default values. glPixelStorei(GL_UNPACK_ROW_LENGTH,0); glPixelStorei(vtkgl::UNPACK_IMAGE_HEIGHT_EXT,0); glPixelTransferf(GL_RED_SCALE,1.0); glPixelTransferf(GL_RED_BIAS,0.0); } this->LoadedCellFlag=cellFlag; i=0; while(i<6) { this->LoadedExtent[i]=textureExtent[i]; ++i; } double spacing[3]; double origin[3]; input->GetSpacing(spacing); input->GetOrigin(origin); int swapBounds[3]; swapBounds[0]=(spacing[0]<0); swapBounds[1]=(spacing[1]<0); swapBounds[2]=(spacing[2]<0); if(!this->LoadedCellFlag) // loaded extents represent points { // slabsPoints[i]=(slabsDataSet[i] - origin[i/2]) / spacing[i/2]; // in general, x=o+i*spacing. // if spacing is positive min extent match the min of the // bounding box // and the max extent match the max of the bounding box // if spacing is negative min extent match the max of the // bounding box // and the max extent match the min of the bounding box // if spacing is negative, we may have to rethink the equation // between real point and texture coordinate... this->LoadedBounds[0]=origin[0]+ static_cast(this->LoadedExtent[0+swapBounds[0]])*spacing[0]; this->LoadedBounds[2]=origin[1]+ static_cast(this->LoadedExtent[2+swapBounds[1]])*spacing[1]; this->LoadedBounds[4]=origin[2]+ static_cast(this->LoadedExtent[4+swapBounds[2]])*spacing[2]; this->LoadedBounds[1]=origin[0]+ static_cast(this->LoadedExtent[1-swapBounds[0]])*spacing[0]; this->LoadedBounds[3]=origin[1]+ static_cast(this->LoadedExtent[3-swapBounds[1]])*spacing[1]; this->LoadedBounds[5]=origin[2]+ static_cast(this->LoadedExtent[5-swapBounds[2]])*spacing[2]; } else // loaded extents represent cells { int wholeTextureExtent[6]; input->GetExtent(wholeTextureExtent); i=1; while(i<6) { wholeTextureExtent[i]--; i+=2; } i=0; while(i<3) { if(this->LoadedExtent[2*i]==wholeTextureExtent[2*i]) { this->LoadedBounds[2*i+swapBounds[i]]=origin[i]; } else { this->LoadedBounds[2*i+swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i])+0.5)*spacing[i]; } if(this->LoadedExtent[2*i+1]==wholeTextureExtent[2*i+1]) { this->LoadedBounds[2*i+1-swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i+1])+1.0)*spacing[i]; } else { this->LoadedBounds[2*i+1-swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i+1])+0.5)*spacing[i]; } ++i; } } this->LoadedTableRange[0]=tableRange[0]; this->LoadedTableRange[1]=tableRange[1]; modified=true; } // if enough memory else { } } //load fail with out of memory else { } } // proxy ok else { // proxy failed } } else { // out of therical limitationa } } // if obsolete if(this->Loaded && (needUpdate || modified || linearInterpolation!=this->LinearInterpolation)) { this->LinearInterpolation=linearInterpolation; if(this->LinearInterpolation) { glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MAG_FILTER, GL_NEAREST ); } modified=true; } if(modified) { this->BuildTime.Modified(); } } double *GetLoadedBounds() { assert("pre: loaded" && this->Loaded); return this->LoadedBounds; } vtkIdType *GetLoadedExtent() { assert("pre: loaded" && this->Loaded); return this->LoadedExtent; } int GetLoadedCellFlag() { assert("pre: loaded" && this->Loaded); return this->LoadedCellFlag; } bool IsLoaded() { return this->Loaded; } bool GetSupports_GL_ARB_texture_float() { return this->Supports_GL_ARB_texture_float; } void SetSupports_GL_ARB_texture_float(bool value) { this->Supports_GL_ARB_texture_float=value; } protected: GLuint TextureId; vtkTimeStamp BuildTime; double LoadedBounds[6]; vtkIdType LoadedExtent[6]; int LoadedCellFlag; bool Loaded; bool LinearInterpolation; bool Supports_GL_ARB_texture_float; double LoadedTableRange[2]; }; //----------------------------------------------------------------------------- class vtkKWMask { public: vtkKWMask() { this->TextureId=0; this->Loaded=false; this->LoadedExtent[0]=VTK_INT_MAX; this->LoadedExtent[1]=VTK_INT_MIN; this->LoadedExtent[2]=VTK_INT_MAX; this->LoadedExtent[3]=VTK_INT_MIN; this->LoadedExtent[4]=VTK_INT_MAX; this->LoadedExtent[5]=VTK_INT_MIN; } ~vtkKWMask() { if(this->TextureId!=0) { glDeleteTextures(1,&this->TextureId); this->TextureId=0; } } vtkTimeStamp GetBuildTime() { return this->BuildTime; } // \pre vtkgl::ActiveTexture(vtkgl::TEXTURE7) has to be called first. void Bind() { assert("pre: uptodate" && this->Loaded); glBindTexture(vtkgl::TEXTURE_3D,this->TextureId); } // \pre vtkgl::ActiveTexture(vtkgl::TEXTURE7) has to be called first. void Update(vtkImageData *input, int cellFlag, int textureExtent[6], int scalarMode, int arrayAccessMode, int arrayId, const char *arrayName, int maxMemoryInBytes) { bool needUpdate=false; bool modified=false; if(this->TextureId==0) { glGenTextures(1,&this->TextureId); needUpdate=true; } glBindTexture(vtkgl::TEXTURE_3D,this->TextureId); int obsolete=needUpdate || !this->Loaded || input->GetMTime()>this->BuildTime; if(!obsolete) { obsolete=cellFlag!=this->LoadedCellFlag; int i=0; while(!obsolete && i<6) { obsolete=obsolete || this->LoadedExtent[i]>textureExtent[i]; ++i; obsolete=obsolete || this->LoadedExtent[i]Loaded=false; int dim[3]; input->GetDimensions(dim); vtkDataArray *scalars= vtkAbstractMapper::GetScalars(input,scalarMode,arrayAccessMode, arrayId,arrayName, this->LoadedCellFlag); // DONT USE GetScalarType() or GetNumberOfScalarComponents() on // ImageData as it deals only with point data... int scalarType=scalars->GetDataType(); if(scalarType!=VTK_UNSIGNED_CHAR) { cout <<"mask should be VTK_UNSIGNED_CHAR." << endl; } if(scalars->GetNumberOfComponents()!=1) { cout <<"mask should be a one-component scalar field." << endl; } GLint internalFormat=GL_ALPHA8; GLenum format=GL_ALPHA; GLenum type=GL_UNSIGNED_BYTE; // Enough memory? int textureSize[3]; int i=0; while(i<3) { textureSize[i]=textureExtent[2*i+1]-textureExtent[2*i]+1; ++i; } GLint width; glGetIntegerv(vtkgl::MAX_3D_TEXTURE_SIZE,&width); this->Loaded=textureSize[0]<=width && textureSize[1]<=width && textureSize[2]<=width; if(this->Loaded) { // so far, so good. the texture size is theorically small enough // for OpenGL vtkgl::TexImage3D(vtkgl::PROXY_TEXTURE_3D,0,internalFormat, textureSize[0],textureSize[1],textureSize[2],0, format,type,0); glGetTexLevelParameteriv(vtkgl::PROXY_TEXTURE_3D,0,GL_TEXTURE_WIDTH, &width); this->Loaded=width!=0; if(this->Loaded) { // so far, so good but some cards always succeed with a proxy texture // let's try to actually allocate.. vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,internalFormat,textureSize[0], textureSize[1],textureSize[2],0,format,type,0); GLenum errorCode=glGetError(); this->Loaded=errorCode!=GL_OUT_OF_MEMORY; if(this->Loaded) { // so far, so good, actual allocation succeeded. if(errorCode!=GL_NO_ERROR) { cout<<"after try to load the texture"; cout<<" ERROR (x"<(errorCode)); cout<Loaded=textureSize[0]*textureSize[1]* textureSize[2]*vtkAbstractArray::GetDataTypeSize(scalarType)* scalars->GetNumberOfComponents()<=maxMemoryInBytes; if(this->Loaded) { // OK, we consider the allocation above succeeded... // If it actually didn't the only to fix it for the user // is to decrease the value of this->MaxMemoryInBytes. // enough memory! We can load the scalars! // we don't clamp to edge because for the computation of the // gradient on the border we need some external value. glTexParameterf(vtkgl::TEXTURE_3D,vtkgl::TEXTURE_WRAP_R,vtkgl::CLAMP_TO_EDGE); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_WRAP_S,vtkgl::CLAMP_TO_EDGE); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_WRAP_T,vtkgl::CLAMP_TO_EDGE); GLfloat borderColor[4]={0.0,0.0,0.0,0.0}; glTexParameterfv(vtkgl::TEXTURE_3D,GL_TEXTURE_BORDER_COLOR, borderColor); glPixelTransferf(GL_ALPHA_SCALE,1.0); glPixelTransferf(GL_ALPHA_BIAS,0.0); glPixelStorei(GL_UNPACK_ALIGNMENT,1); if(!(textureExtent[1]-textureExtent[0]+cellFlag==dim[0])) { glPixelStorei(GL_UNPACK_ROW_LENGTH,dim[0]-cellFlag); } if(!(textureExtent[3]-textureExtent[2]+cellFlag==dim[1])) { glPixelStorei(vtkgl::UNPACK_IMAGE_HEIGHT_EXT, dim[1]-cellFlag); } void *dataPtr=scalars->GetVoidPointer( ((textureExtent[4]*(dim[1]-cellFlag)+textureExtent[2]) *(dim[0]-cellFlag)+textureExtent[0]) *scalars->GetNumberOfComponents()); vtkgl::TexImage3D(vtkgl::TEXTURE_3D, 0, internalFormat, textureSize[0],textureSize[1],textureSize[2], 0,format,type,dataPtr); // Restore the default values. glPixelStorei(GL_UNPACK_ROW_LENGTH,0); glPixelStorei(vtkgl::UNPACK_IMAGE_HEIGHT_EXT,0); glPixelTransferf(GL_ALPHA_SCALE,1.0); glPixelTransferf(GL_ALPHA_BIAS,0.0); this->LoadedCellFlag=cellFlag; i=0; while(i<6) { this->LoadedExtent[i]=textureExtent[i]; ++i; } double spacing[3]; double origin[3]; input->GetSpacing(spacing); input->GetOrigin(origin); int swapBounds[3]; swapBounds[0]=(spacing[0]<0); swapBounds[1]=(spacing[1]<0); swapBounds[2]=(spacing[2]<0); if(!this->LoadedCellFlag) // loaded extents represent points { // slabsPoints[i]=(slabsDataSet[i] - origin[i/2]) / spacing[i/2]; // in general, x=o+i*spacing. // if spacing is positive min extent match the min of the // bounding box // and the max extent match the max of the bounding box // if spacing is negative min extent match the max of the // bounding box // and the max extent match the min of the bounding box // if spacing is negative, we may have to rethink the equation // between real point and texture coordinate... this->LoadedBounds[0]=origin[0]+ static_cast(this->LoadedExtent[0+swapBounds[0]])*spacing[0]; this->LoadedBounds[2]=origin[1]+ static_cast(this->LoadedExtent[2+swapBounds[1]])*spacing[1]; this->LoadedBounds[4]=origin[2]+ static_cast(this->LoadedExtent[4+swapBounds[2]])*spacing[2]; this->LoadedBounds[1]=origin[0]+ static_cast(this->LoadedExtent[1-swapBounds[0]])*spacing[0]; this->LoadedBounds[3]=origin[1]+ static_cast(this->LoadedExtent[3-swapBounds[1]])*spacing[1]; this->LoadedBounds[5]=origin[2]+ static_cast(this->LoadedExtent[5-swapBounds[2]])*spacing[2]; } else // loaded extents represent cells { int wholeTextureExtent[6]; input->GetExtent(wholeTextureExtent); i=1; while(i<6) { wholeTextureExtent[i]--; i+=2; } i=0; while(i<3) { if(this->LoadedExtent[2*i]==wholeTextureExtent[2*i]) { this->LoadedBounds[2*i+swapBounds[i]]=origin[i]; } else { this->LoadedBounds[2*i+swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i])+0.5)*spacing[i]; } if(this->LoadedExtent[2*i+1]==wholeTextureExtent[2*i+1]) { this->LoadedBounds[2*i+1-swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i+1])+1.0)*spacing[i]; } else { this->LoadedBounds[2*i+1-swapBounds[i]]=origin[i]+ (static_cast(this->LoadedExtent[2*i+1])+0.5)*spacing[i]; } ++i; } } modified=true; } // if enough memory else { } } //load fail with out of memory else { } } // proxy ok else { // proxy failed } } else { // out of therical limitationa } } // if obsolete if(this->Loaded && (needUpdate || modified)) { glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameterf(vtkgl::TEXTURE_3D,GL_TEXTURE_MAG_FILTER, GL_NEAREST ); modified=true; } if(modified) { this->BuildTime.Modified(); } } double *GetLoadedBounds() { assert("pre: loaded" && this->Loaded); return this->LoadedBounds; } vtkIdType *GetLoadedExtent() { assert("pre: loaded" && this->Loaded); return this->LoadedExtent; } int GetLoadedCellFlag() { assert("pre: loaded" && this->Loaded); return this->LoadedCellFlag; } bool IsLoaded() { return this->Loaded; } protected: GLuint TextureId; vtkTimeStamp BuildTime; double LoadedBounds[6]; vtkIdType LoadedExtent[6]; int LoadedCellFlag; bool Loaded; }; //----------------------------------------------------------------------------- // Display the status of the current framebuffer on the standard output. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::CheckFrameBufferStatus() { GLenum status; status = vtkgl::CheckFramebufferStatusEXT(vtkgl::FRAMEBUFFER_EXT); switch(status) { case 0: cout << "call to vtkgl::CheckFramebufferStatusEXT generates an error." << endl; break; case vtkgl::FRAMEBUFFER_COMPLETE_EXT: break; case vtkgl::FRAMEBUFFER_UNSUPPORTED_EXT: cout << "framebuffer is unsupported" << endl; break; case vtkgl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: cout << "framebuffer has an attachment error"<DisplayFrameBufferAttachments(); // this->DisplayReadAndDrawBuffers(); } //----------------------------------------------------------------------------- vtkStdString vtkMitkOpenGLGPUVolumeRayCastMapper::BufferToString(int buffer) { vtkStdString result; vtksys_ios::ostringstream ost; GLint size; GLint b=static_cast(buffer); switch(b) { case GL_NONE: ost << "GL_NONE"; break; case GL_FRONT_LEFT: ost << "GL_FRONT_LEFT"; break; case GL_FRONT_RIGHT: ost << "GL_FRONT_RIGHT"; break; case GL_BACK_LEFT: ost << "GL_BACK_LEFT"; break; case GL_BACK_RIGHT: ost << "GL_BACK_RIGHT"; break; case GL_FRONT: ost << "GL_FRONT"; break; case GL_BACK: ost << "GL_BACK"; break; case GL_LEFT: ost << "GL_LEFT"; break; case GL_RIGHT: ost << "GL_RIGHT"; break; case GL_FRONT_AND_BACK: ost << "GL_FRONT_AND_BACK"; break; default: glGetIntegerv(GL_AUX_BUFFERS,&size); if(buffer>=GL_AUX0 && buffer<(GL_AUX0+size)) { ost << "GL_AUX" << (buffer-GL_AUX0); } else { glGetIntegerv(vtkgl::MAX_COLOR_ATTACHMENTS_EXT,&size); if(static_cast(buffer)>=vtkgl::COLOR_ATTACHMENT0_EXT && static_cast(buffer)< (vtkgl::COLOR_ATTACHMENT0_EXT+static_cast(size))) { ost << "GL_COLOR_ATTACHMENT" << (static_cast(buffer)-vtkgl::COLOR_ATTACHMENT0_EXT) << "_EXT"; } else { ost << "unknown color buffer type=0x"<(value); vtkStdString s; GLenum i=0; while(iBufferToString(static_cast(value)); cout << "draw buffer " << i << "=" << s << endl; ++i; } glGetIntegerv(GL_READ_BUFFER,&value); s=this->BufferToString(static_cast(value)); cout << "read buffer=" << s << endl; } // ---------------------------------------------------------------------------- // Description: // Display all the attachments of the current framebuffer object. // ---------------------------------------------------------------------------- // // ---------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::DisplayFrameBufferAttachments() { GLint framebufferBinding; glGetIntegerv(vtkgl::FRAMEBUFFER_BINDING_EXT,&framebufferBinding); this->PrintError("after getting FRAMEBUFFER_BINDING_EXT"); if(framebufferBinding==0) { cout<<"Current framebuffer is bind to the system one"<(value); this->PrintError("after getting MAX_COLOR_ATTACHMENTS_EXT"); GLenum i=0; while(iDisplayFrameBufferAttachment(vtkgl::COLOR_ATTACHMENT0_EXT+i); ++i; } cout<<"depth attachement :"<DisplayFrameBufferAttachment(vtkgl::DEPTH_ATTACHMENT_EXT); cout<<"stencil attachement :"<DisplayFrameBufferAttachment(vtkgl::STENCIL_ATTACHMENT_EXT); } } // ---------------------------------------------------------------------------- // Description: // Display a given attachment for the current framebuffer object. //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::DisplayFrameBufferAttachment( unsigned int uattachment) { GLenum attachment=static_cast(uattachment); GLint params; vtkgl::GetFramebufferAttachmentParameterivEXT( vtkgl::FRAMEBUFFER_EXT,attachment, vtkgl::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT,¶ms); this->PrintError("after getting FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT"); switch(params) { case GL_NONE: cout<<" this attachment is empty"<PrintError("after getting FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT"); cout<<" this attachment is a texture with name: "<PrintError( "after getting FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT"); cout<<" its mipmap level is: "<PrintError( "after getting FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT"); if(params==0) { cout<<" this is not a cube map texture."<PrintError( "after getting FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT"); if(params==0) { cout<<" this is not 3D texture."<PrintError("after getting FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT"); cout<<" this attachment is a renderbuffer with name: "<(params)); this->PrintError( "after getting binding the current RENDERBUFFER_EXT to params"); vtkgl::GetRenderbufferParameterivEXT(vtkgl::RENDERBUFFER_EXT, vtkgl::RENDERBUFFER_WIDTH_EXT, ¶ms); this->PrintError("after getting RENDERBUFFER_WIDTH_EXT"); cout<<" renderbuffer width="<PrintError("after getting RENDERBUFFER_HEIGHT_EXT"); cout<<" renderbuffer height="<PrintError("after getting RENDERBUFFER_INTERNAL_FORMAT_EXT"); cout<<" renderbuffer internal format=0x"<< hex<PrintError("after getting RENDERBUFFER_RED_SIZE_EXT"); cout<<" renderbuffer actual resolution for the red component="<PrintError("after getting RENDERBUFFER_GREEN_SIZE_EXT"); cout<<" renderbuffer actual resolution for the green component="<PrintError("after getting RENDERBUFFER_BLUE_SIZE_EXT"); cout<<" renderbuffer actual resolution for the blue component="<PrintError("after getting RENDERBUFFER_ALPHA_SIZE_EXT"); cout<<" renderbuffer actual resolution for the alpha component="<PrintError("after getting RENDERBUFFER_DEPTH_SIZE_EXT"); cout<<" renderbuffer actual resolution for the depth component="<PrintError("after getting RENDERBUFFER_STENCIL_SIZE_EXT"); cout<<" renderbuffer actual resolution for the stencil component=" <(errorCode)) { case GL_NO_ERROR: result="No error"; break; case GL_INVALID_ENUM: result="Invalid enum"; break; case GL_INVALID_VALUE: result="Invalid value"; break; case GL_INVALID_OPERATION: result="Invalid operation"; break; case GL_STACK_OVERFLOW: result="stack overflow"; break; case GL_STACK_UNDERFLOW: result="stack underflow"; break; case GL_OUT_OF_MEMORY: result="out of memory"; break; case vtkgl::TABLE_TOO_LARGE: // GL_ARB_imaging result="Table too large"; break; case vtkgl::INVALID_FRAMEBUFFER_OPERATION_EXT: // GL_EXT_framebuffer_object, 310 result="invalid framebuffer operation ext"; break; case vtkgl::TEXTURE_TOO_LARGE_EXT: // GL_EXT_texture result="Texture too large"; break; default: result="unknown error"; } assert("post: result_exists" && result!=0); return result; } //----------------------------------------------------------------------------- // Display headerMessage on the standard output and the last OpenGL error // message if any. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::PrintError(const char *headerMessage) { GLenum errorCode=glGetError(); if(errorCode!=GL_NO_ERROR) { if ( headerMessage ) { cout<(errorCode)); cout<UnsupportedRequiredExtensions=0; this->OpenGLObjectsCreated=0; this->LoadExtensionsSucceeded=0; this->NumberOfFrameBuffers=0; this->m_BindMax = false; // up to 2 frame buffer 2D textures (left/right) // 1 dataset 3D texture // 1 colormap 1D texture // 1 opacitymap 1d texture // 1 grabbed depth buffer 2d texture int i=0; while(iTextureObjects[i]=0; ++i; } this->DepthRenderBufferObject=0; this->FrameBufferObject=0; for ( int j = 0; j < 8; j++ ) { for (i = 0; i < 3; i++ ) { this->BoundingBox[j][i] = 0.0; } } this->LastSize[0]=0; this->LastSize[1]=0; this->ReductionFactor = 1.0; this->Supports_GL_ARB_texture_float=0; this->SupportsPixelBufferObjects=0; i=0; while(i<3) { this->TempMatrix[i]=vtkMatrix4x4::New(); ++i; } this->ErrorLine=0; this->ErrorColumn=0; this->ErrorString=0; this->LastParallelProjection= vtkMitkOpenGLGPUVolumeRayCastMapperProjectionNotInitialized; this->LastRayCastMethod= vtkMitkOpenGLGPUVolumeRayCastMapperMethodNotInitialized; this->LastCroppingMode= vtkMitkOpenGLGPUVolumeRayCastMapperCroppingNotInitialized; this->LastComponent= vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotInitialized; this->LastShade=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotInitialized; this->ClippedBoundingBox = NULL; this->SmallInput = NULL; this->MaxValueFrameBuffer=0; this->MaxValueFrameBuffer2=0; this->ReducedSize[0]=0; this->ReducedSize[1]=0; this->NumberOfCroppingRegions=0; this->PolyDataBoundingBox=0; this->Planes=0; this->NearPlane=0; this->Clip=0; this->Densify=0; this->InvVolumeMatrix=vtkMatrix4x4::New(); this->ScaleBiasProgramShader=0; this->UFrameBufferTexture=-1; this->UScale=-1; this->UBias=-1; this->SavedFrameBuffer=0; this->BoxSource=0; this->NoiseTexture=0; this->NoiseTextureSize=0; this->NoiseTextureId=0; this->IgnoreSampleDistancePerPixel=true; this->ScalarsTextures=new vtkMapDataArrayTextureId; this->MaskTextures=new vtkMapMaskTextureId; this->RGBTable=0; this->Mask1RGBTable=0; this->Mask2RGBTable=0; this->OpacityTables=0; this->CurrentScalar=0; this->CurrentMask=0; this->ActualSampleDistance=1.0; this->LastProgressEventTime=0.0; // date in seconds this->PreserveOrientation=true; } //----------------------------------------------------------------------------- // Destruct a vtkMitkOpenGLGPUVolumeRayCastMapper - clean up any memory used //----------------------------------------------------------------------------- vtkMitkOpenGLGPUVolumeRayCastMapper::~vtkMitkOpenGLGPUVolumeRayCastMapper() { if(this->UnsupportedRequiredExtensions!=0) { delete this->UnsupportedRequiredExtensions; this->UnsupportedRequiredExtensions=0; } int i=0; while(i<3) { this->TempMatrix[i]->Delete(); this->TempMatrix[i]=0; ++i; } if(this->ErrorString!=0) { delete[] this->ErrorString; this->ErrorString=0; } if ( this->SmallInput ) { this->SmallInput->UnRegister(this); } if(this->PolyDataBoundingBox!=0) { this->PolyDataBoundingBox->UnRegister(this); this->PolyDataBoundingBox=0; } if(this->Planes!=0) { this->Planes->UnRegister(this); this->Planes=0; } if(this->NearPlane!=0) { this->NearPlane->UnRegister(this); this->NearPlane=0; } if(this->Clip!=0) { this->Clip->UnRegister(this); this->Clip=0; } if(this->Densify!=0) { this->Densify->UnRegister(this); this->Densify=0; } if(this->BoxSource!=0) { this->BoxSource->UnRegister(this); this->BoxSource=0; } this->InvVolumeMatrix->UnRegister(this); this->InvVolumeMatrix=0; if(this->NoiseTexture!=0) { delete[] this->NoiseTexture; this->NoiseTexture=0; this->NoiseTextureSize=0; } if(this->ScalarsTextures!=0) { delete this->ScalarsTextures; this->ScalarsTextures=0; } if(this->MaskTextures!=0) { delete this->MaskTextures; this->MaskTextures=0; } } //----------------------------------------------------------------------------- // Based on hardware and properties, we may or may not be able to // render using 3D texture mapping. This indicates if 3D texture // mapping is supported by the hardware, and if the other extensions // necessary to support the specific properties are available. // //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::IsRenderSupported( vtkRenderWindow *window, vtkVolumeProperty *vtkNotUsed(property)) { window->MakeCurrent(); if(!this->LoadExtensionsSucceeded) { this->LoadExtensions(window); } if(!this->LoadExtensionsSucceeded) { vtkDebugMacro( "The following OpenGL extensions are required but not supported: " << (this->UnsupportedRequiredExtensions->Stream.str()).c_str()); return 0; } return 1; } //----------------------------------------------------------------------------- // Return if the required OpenGL extension `extensionName' is supported. // If not, its name is added to the string of unsupported but required // extensions. // \pre extensions_exist: extensions!=0 // \pre extensionName_exists: extensionName!=0 //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::TestRequiredExtension( vtkOpenGLExtensionManager *extensions, const char *extensionName) { assert("pre: extensions_exist" && extensions!=0); assert("pre: extensionName_exists" && extensionName!=0); int result=extensions->ExtensionSupported(extensionName); if(!result) { if(this->LoadExtensionsSucceeded) { this->UnsupportedRequiredExtensions->Stream<LoadExtensionsSucceeded=0; } else { this->UnsupportedRequiredExtensions->Stream<<", "<LoadExtensionsSucceeded will be set to 0 or 1 // - this->UnsupportedRequiredExtensions will have a message indicating // any failure codes //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::LoadExtensions( vtkRenderWindow *window) { // We may already have a string stream for the unsupported extensions // from the last time this method was called. If so, delete it. if(this->UnsupportedRequiredExtensions!=0) { delete this->UnsupportedRequiredExtensions; } // Create a string stream to hold the unsupported extensions so we can // report something meaningful back this->UnsupportedRequiredExtensions = new vtkUnsupportedRequiredExtensionsStringStream; // It does not work on Apple OS X Snow Leopard with nVidia. // There is a bug in the OpenGL driver with an error in the // Cg compiler about an infinite loop. #ifdef __APPLE__ this->LoadExtensionsSucceeded=0; return; #endif // Assume success this->LoadExtensionsSucceeded=1; const char *gl_vendor=reinterpret_cast(glGetString(GL_VENDOR)); /* if(strstr(gl_vendor,"ATI")!=0) { this->LoadExtensionsSucceeded=0; return; }*/ const char *gl_version=reinterpret_cast(glGetString(GL_VERSION)); if(strstr(gl_version,"Mesa")!=0) { // - GL_VENDOR cannot be used because it can be "Brian Paul" or // "Mesa project" // - GL_RENDERER cannot be used because it can be "Software Rasterizer" or // "Mesa X11" // - GL_VERSION is more robust. It has things like "2.0 Mesa 7.0.4" or // "2.1 Mesa 7.2" or "2.1 Mesa 7.3-devel" // Mesa does not work with multiple draw buffers: // "framebuffer has bad draw buffer" // "render clipped 1 ERROR (x506) invalid framebuffer operation ext" this->LoadExtensionsSucceeded=0; return; } // Create an extension manager vtkOpenGLExtensionManager *extensions=vtkOpenGLExtensionManager::New(); extensions->SetRenderWindow(window); // GL_ARB_draw_buffers requires OpenGL 1.3, so we must have OpenGL 1.3 // We don't need to check for some extensions that become part of OpenGL // core after 1.3. Among them: // - texture_3d is in core OpenGL since 1.2 // - texture_edge_clamp is in core OpenGL since 1.2 // (GL_SGIS_texture_edge_clamp or GL_EXT_texture_edge_clamp (nVidia) ) // - multitexture is in core OpenGL since 1.3 int supports_GL_1_3=extensions->ExtensionSupported("GL_VERSION_1_3"); int supports_GL_2_0=0; // No 1.3 support - give up if(!supports_GL_1_3) { this->LoadExtensionsSucceeded=0; this->UnsupportedRequiredExtensions->Stream<< " OpenGL 1.3 is required but not supported"; extensions->Delete(); return; } // Check for 2.0 support supports_GL_2_0=extensions->ExtensionSupported("GL_VERSION_2_0"); // Some extensions that are supported in 2.0, but if we don't // have 2.0 we'll need to check further int supports_shading_language_100 = 1; int supports_shader_objects = 1; int supports_fragment_shader = 1; int supports_texture_non_power_of_two = 1; int supports_draw_buffers = 1; if(!supports_GL_2_0) { supports_shading_language_100= extensions->ExtensionSupported("GL_ARB_shading_language_100"); supports_shader_objects= extensions->ExtensionSupported("GL_ARB_shader_objects"); supports_fragment_shader= extensions->ExtensionSupported("GL_ARB_fragment_shader"); supports_texture_non_power_of_two= extensions->ExtensionSupported("GL_ARB_texture_non_power_of_two"); supports_draw_buffers= extensions->ExtensionSupported("GL_ARB_draw_buffers"); } // We have to check for framebuffer objects int supports_GL_EXT_framebuffer_object= extensions->ExtensionSupported("GL_EXT_framebuffer_object" ); // Find out if we have OpenGL 1.4 support int supports_GL_1_4=extensions->ExtensionSupported("GL_VERSION_1_4"); // Find out if we have the depth texture ARB extension int supports_GL_ARB_depth_texture= extensions->ExtensionSupported("GL_ARB_depth_texture"); // Depth textures are support if we either have OpenGL 1.4 // or if the depth texture ARB extension is supported int supports_depth_texture = supports_GL_1_4 || supports_GL_ARB_depth_texture; // Now start adding messages to the UnsupportedRequiredExtensions string // Log message if shading language 100 is not supported if(!supports_shading_language_100) { this->UnsupportedRequiredExtensions->Stream<< " shading_language_100 (or OpenGL 2.0) is required but not supported"; this->LoadExtensionsSucceeded=0; } else { // We can query the GLSL version, we need >=1.20 const char *glsl_version= reinterpret_cast(glGetString(vtkgl::SHADING_LANGUAGE_VERSION)); int glslMajor, glslMinor; vtksys_ios::istringstream ist(glsl_version); ist >> glslMajor; char c; ist.get(c); // '.' ist >> glslMinor; //sscanf(version, "%d.%d", &glslMajor, &glslMinor); if(glslMajor<1 || (glslMajor==1 && glslMinor<20)) { this->LoadExtensionsSucceeded=0; } } // Log message if shader objects are not supported if(!supports_shader_objects) { this->UnsupportedRequiredExtensions->Stream<< " shader_objects (or OpenGL 2.0) is required but not supported"; this->LoadExtensionsSucceeded=0; } // Log message if fragment shaders are not supported if(!supports_fragment_shader) { this->UnsupportedRequiredExtensions->Stream<< " fragment_shader (or OpenGL 2.0) is required but not supported"; this->LoadExtensionsSucceeded=0; } // Log message if non power of two textures are not supported if(!supports_texture_non_power_of_two) { this->UnsupportedRequiredExtensions->Stream<< " texture_non_power_of_two (or OpenGL 2.0) is required but not " << "supported"; this->LoadExtensionsSucceeded=0; } // Log message if draw buffers are not supported if(!supports_draw_buffers) { this->UnsupportedRequiredExtensions->Stream<< " draw_buffers (or OpenGL 2.0) is required but not supported"; this->LoadExtensionsSucceeded=0; } // Log message if depth textures are not supported if(!supports_depth_texture) { this->UnsupportedRequiredExtensions->Stream<< " depth_texture (or OpenGL 1.4) is required but not supported"; this->LoadExtensionsSucceeded=0; } // Log message if framebuffer objects are not supported if(!supports_GL_EXT_framebuffer_object) { this->UnsupportedRequiredExtensions->Stream<< " framebuffer_object is required but not supported"; this->LoadExtensionsSucceeded=0; } // Have we succeeded so far? If not, just return. if(!this->LoadExtensionsSucceeded) { extensions->Delete(); return; } // Now start loading the extensions // First load all 1.2 and 1.3 extensions (we know we // support at least up to 1.3) extensions->LoadExtension("GL_VERSION_1_2"); extensions->LoadExtension("GL_VERSION_1_3"); // Load the 2.0 extensions if supported if(supports_GL_2_0) { extensions->LoadExtension("GL_VERSION_2_0"); } // Otherwise, we'll need to specifically load the // shader objects, fragment shader, and draw buffers // extensions else { extensions->LoadCorePromotedExtension("GL_ARB_shader_objects"); extensions->LoadCorePromotedExtension("GL_ARB_fragment_shader"); extensions->LoadCorePromotedExtension("GL_ARB_draw_buffers"); } // Load the framebuffer object extension extensions->LoadExtension("GL_EXT_framebuffer_object"); // Optional extension (does not fail if not present) // Load it if supported which will allow us to store // textures as floats this->Supports_GL_ARB_texture_float= extensions->ExtensionSupported("GL_ARB_texture_float" ); if(this->Supports_GL_ARB_texture_float) { extensions->LoadExtension( "GL_ARB_texture_float" ); } // Optional extension (does not fail if not present) // Used to minimize memory footprint when loading large 3D textures // of scalars. // VBO or 1.5 is required by PBO or 2.1 int supports_GL_1_5=extensions->ExtensionSupported("GL_VERSION_1_5"); int supports_vertex_buffer_object=supports_GL_1_5 || extensions->ExtensionSupported("GL_ARB_vertex_buffer_object"); int supports_GL_2_1=extensions->ExtensionSupported("GL_VERSION_2_1"); this->SupportsPixelBufferObjects=supports_vertex_buffer_object && (supports_GL_2_1 || extensions->ExtensionSupported("GL_ARB_pixel_buffer_object")); if(this->SupportsPixelBufferObjects) { if(supports_GL_1_5) { extensions->LoadExtension("GL_VERSION_1_5"); } else { extensions->LoadCorePromotedExtension("GL_ARB_vertex_buffer_object"); } if(supports_GL_2_1) { extensions->LoadExtension("GL_VERSION_2_1"); } else { extensions->LoadCorePromotedExtension("GL_ARB_pixel_buffer_object"); } } // Ultimate test. Some old cards support OpenGL 2.0 but not while // statements in a fragment shader (example: nVidia GeForce FX 5200) // It does not fail when compiling each shader source but at linking // stage because the parser underneath only check for syntax during // compilation and the actual native code generation happens during // the linking stage. this->CreateGLSLObjects(); this->NumberOfCroppingRegions=1; this->BuildProgram(1,vtkMitkOpenGLGPUVolumeRayCastMapperMethodComposite, vtkMitkOpenGLGPUVolumeRayCastMapperShadeNo, vtkMitkOpenGLGPUVolumeRayCastMapperComponentOne); GLint params; vtkgl::GetProgramiv(static_cast(this->ProgramShader), vtkgl::LINK_STATUS,¶ms); if(params==GL_FALSE) { this->LoadExtensionsSucceeded=0; this->UnsupportedRequiredExtensions->Stream<< " this card does not support while statements in fragment shaders."; } // FB debug this->CheckLinkage(this->ProgramShader); // Release GLSL Objects. GLuint programShader=static_cast(this->ProgramShader); vtkgl::DeleteProgram(programShader); this->LastParallelProjection= vtkMitkOpenGLGPUVolumeRayCastMapperProjectionNotInitialized; this->LastRayCastMethod= vtkMitkOpenGLGPUVolumeRayCastMapperMethodNotInitialized; this->LastCroppingMode= vtkMitkOpenGLGPUVolumeRayCastMapperCroppingNotInitialized; this->LastComponent= vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotInitialized; this->LastShade=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotInitialized; extensions->Delete(); } //----------------------------------------------------------------------------- // Create GLSL OpenGL objects such fragment program Ids. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::CreateGLSLObjects() { GLuint programShader; GLuint fragmentMainShader; programShader=vtkgl::CreateProgram(); fragmentMainShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); vtkgl::AttachShader(programShader,fragmentMainShader); vtkgl::DeleteShader(fragmentMainShader); // reference counting vtkgl::ShaderSource( fragmentMainShader,1, const_cast(&vtkMitkGPUVolumeRayCastMapper_HeaderFS),0); vtkgl::CompileShader(fragmentMainShader); this->CheckCompilation(static_cast(fragmentMainShader)); GLuint fragmentProjectionShader; GLuint fragmentTraceShader; GLuint fragmentCroppingShader; GLuint fragmentComponentShader; GLuint fragmentShadeShader; fragmentProjectionShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); vtkgl::AttachShader(programShader,fragmentProjectionShader); vtkgl::DeleteShader(fragmentProjectionShader); // reference counting fragmentTraceShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); vtkgl::AttachShader(programShader,fragmentTraceShader); vtkgl::DeleteShader(fragmentTraceShader); // reference counting fragmentCroppingShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); vtkgl::AttachShader(programShader,fragmentCroppingShader); vtkgl::DeleteShader(fragmentCroppingShader); // reference counting fragmentComponentShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); // don't delete it, it is optionally attached. fragmentShadeShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); // Save GL objects by static casting to standard C types. GL* types // are not allowed in VTK header files. this->ProgramShader=static_cast(programShader); this->FragmentMainShader=static_cast(fragmentMainShader); this->FragmentProjectionShader= static_cast(fragmentProjectionShader); this->FragmentTraceShader=static_cast(fragmentTraceShader); this->FragmentCroppingShader= static_cast(fragmentCroppingShader); this->FragmentComponentShader= static_cast(fragmentComponentShader); this->FragmentShadeShader= static_cast(fragmentShadeShader); } void vtkMitkOpenGLGPUVolumeRayCastMapper::BindFramebuffer() { vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront], 0); GLenum err = glGetError(); if(m_BindMax) { vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D,this->MaxValueFrameBuffer,0); } } //----------------------------------------------------------------------------- // Create OpenGL objects such as textures, buffers and fragment program Ids. // It only registers Ids, there is no actual initialization of textures or // fragment program. // // Pre-conditions: // This method assumes that this->LoadedExtensionsSucceeded is 1. // // Post-conditions: // When this method completes successfully, this->OpenGLObjectsCreated // will be 1. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::CreateOpenGLObjects() { // Do nothing if the OpenGL objects have already been created if ( this->OpenGLObjectsCreated ) { return; } // We need only two color buffers (ping-pong) this->NumberOfFrameBuffers=2; // TODO: clean this up! // 2*Frame buffers(2d textures)+colorMap (1d texture) +dataset (3d texture) // + opacitymap (1d texture) + grabbed depthMap (2d texture) // Frame buffers(2d textures)+colorMap (1d texture) +dataset (3d texture) // + opacity (1d texture)+grabbed depth buffer (2d texture) GLuint frameBufferObject; GLuint depthRenderBufferObject; GLuint textureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperNumberOfTextureObjects]; // Create the various objects we will need - one frame buffer // which will contain a render buffer for depth and a texture // for color. vtkgl::GenFramebuffersEXT(1, &frameBufferObject); // color vtkgl::GenRenderbuffersEXT(1, &depthRenderBufferObject); // depth glGenTextures(vtkMitkOpenGLGPUVolumeRayCastMapperNumberOfTextureObjects,textureObjects); // Color buffers GLint value; glGetIntegerv(vtkgl::FRAMEBUFFER_BINDING_EXT,&value); GLuint savedFrameBuffer=static_cast(value); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT,frameBufferObject); // Depth buffer vtkgl::BindRenderbufferEXT(vtkgl::RENDERBUFFER_EXT, depthRenderBufferObject); vtkgl::FramebufferRenderbufferEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::DEPTH_ATTACHMENT_EXT, vtkgl::RENDERBUFFER_EXT, depthRenderBufferObject); // Restore default frame buffer. vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT,savedFrameBuffer); this->CreateGLSLObjects(); // Save GL objects by static casting to standard C types. GL* types // are not allowed in VTK header files. this->FrameBufferObject=static_cast(frameBufferObject); this->DepthRenderBufferObject=static_cast(depthRenderBufferObject); int i=0; while(iTextureObjects[i]=static_cast(textureObjects[i]); ++i; } this->OpenGLObjectsCreated=1; } //----------------------------------------------------------------------------- // Check the compilation status of some fragment shader source. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::CheckCompilation( unsigned int fragmentShader) { GLuint fs=static_cast(fragmentShader); GLint params; vtkgl::GetShaderiv(fs,vtkgl::COMPILE_STATUS,¶ms); if(params==GL_TRUE) { vtkDebugMacro(<<"shader source compiled successfully"); } else { vtkErrorMacro(<<"shader source compile error"); // include null terminator vtkgl::GetShaderiv(fs,vtkgl::INFO_LOG_LENGTH,¶ms); if(params>0) { char *buffer=new char[params]; vtkgl::GetShaderInfoLog(fs,params,0,buffer); vtkErrorMacro(<<"log: "<(programShader); // info about the list of active uniform variables vtkgl::GetProgramiv(prog,vtkgl::ACTIVE_UNIFORMS,¶ms); cout<<"There are "<(params); vtkgl::GetProgramiv(prog,vtkgl::OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, ¶ms); GLint buffSize=params; char *name=new char[buffSize+1]; GLint size; GLenum type; while(i(programShader); vtkgl::GetProgramiv(prog,vtkgl::LINK_STATUS,¶ms); int status = 0; if(params==GL_TRUE) { status = 1; vtkDebugMacro(<<"program linked successfully"); } else { vtkErrorMacro(<<"program link error"); vtkgl::GetProgramiv(prog,vtkgl::INFO_LOG_LENGTH,¶ms); if(params>0) { char *buffer=new char[params]; vtkgl::GetProgramInfoLog(prog,params,0,buffer); vtkErrorMacro(<<"log: "<OpenGLObjectsCreated==0 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::ReleaseGraphicsResources( vtkWindow *window) { if(this->OpenGLObjectsCreated) { window->MakeCurrent(); this->LastSize[0]=0; this->LastSize[1]=0; GLuint frameBufferObject=static_cast(this->FrameBufferObject); vtkgl::DeleteFramebuffersEXT(1,&frameBufferObject); GLuint depthRenderBufferObject= static_cast(this->DepthRenderBufferObject); vtkgl::DeleteRenderbuffersEXT(1,&depthRenderBufferObject); GLuint textureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperNumberOfTextureObjects]; int i=0; while(i<(vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+this->NumberOfFrameBuffers)) { textureObjects[i]=static_cast(this->TextureObjects[i]); ++i; } glDeleteTextures(vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+this->NumberOfFrameBuffers,textureObjects); if(this->MaxValueFrameBuffer!=0) { GLuint maxValueFrameBuffer= static_cast(this->MaxValueFrameBuffer); glDeleteTextures(1,&maxValueFrameBuffer); this->MaxValueFrameBuffer=0; } if(this->MaxValueFrameBuffer2!=0) { GLuint maxValueFrameBuffer2= static_cast(this->MaxValueFrameBuffer2); glDeleteTextures(1,&maxValueFrameBuffer2); this->MaxValueFrameBuffer2=0; } GLuint programShader=static_cast(this->ProgramShader); vtkgl::DeleteProgram(programShader); this->ProgramShader=0; GLuint fragmentComponentShader= static_cast(this->FragmentComponentShader); vtkgl::DeleteShader(fragmentComponentShader); GLuint fragmentShadeShader= static_cast(this->FragmentShadeShader); vtkgl::DeleteShader(fragmentShadeShader); GLuint scaleBiasProgramShader= static_cast(this->ScaleBiasProgramShader); if(scaleBiasProgramShader!=0) { vtkgl::DeleteProgram(scaleBiasProgramShader); this->ScaleBiasProgramShader=0; } this->LastParallelProjection= vtkMitkOpenGLGPUVolumeRayCastMapperProjectionNotInitialized; this->LastRayCastMethod= vtkMitkOpenGLGPUVolumeRayCastMapperMethodNotInitialized; this->LastCroppingMode= vtkMitkOpenGLGPUVolumeRayCastMapperCroppingNotInitialized; this->LastComponent= vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotInitialized; this->LastShade=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotInitialized; this->OpenGLObjectsCreated=0; } if(this->NoiseTextureId!=0) { window->MakeCurrent(); GLuint noiseTextureObjects=static_cast(this->NoiseTextureId); glDeleteTextures(1,&noiseTextureObjects); this->NoiseTextureId=0; } if(this->ScalarsTextures!=0) { if(!this->ScalarsTextures->Map.empty()) { vtkstd::map::iterator it=this->ScalarsTextures->Map.begin(); while(it!=this->ScalarsTextures->Map.end()) { vtkKWScalarField *texture=(*it).second; delete texture; ++it; } this->ScalarsTextures->Map.clear(); } } if(this->MaskTextures!=0) { if(!this->MaskTextures->Map.empty()) { vtkstd::map::iterator it=this->MaskTextures->Map.begin(); while(it!=this->MaskTextures->Map.end()) { vtkKWMask *texture=(*it).second; delete texture; ++it; } this->MaskTextures->Map.clear(); } } if(this->RGBTable!=0) { delete this->RGBTable; this->RGBTable=0; } if(this->Mask1RGBTable!=0) { delete this->Mask1RGBTable; this->Mask1RGBTable=0; } if(this->Mask2RGBTable!=0) { delete this->Mask2RGBTable; this->Mask2RGBTable=0; } if(this->OpacityTables!=0) { delete this->OpacityTables; this->OpacityTables=0; } } //----------------------------------------------------------------------------- // Allocate memory on the GPU for the framebuffers according to the size of // the window or reallocate if the size has changed. Return true if // allocation succeeded. // \pre ren_exists: ren!=0 // \pre opengl_objects_created: this->OpenGLObjectsCreated // \post right_size: LastSize[]=window size. //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::AllocateFrameBuffers(vtkRenderer *ren) { assert("pre: ren_exists" && ren!=0); assert("pre: opengl_objects_created" && this->OpenGLObjectsCreated); int result=1; int size[2]; ren->GetTiledSize(&size[0],&size[1]); int sizeChanged=this->LastSize[0]!=size[0] || this->LastSize[1]!=size[1]; GLenum errorCode=glGetError(); // Need allocation? if(sizeChanged) { int i=0; GLenum errorCode=glGetError(); while(i NumberOfFrameBuffers && errorCode==GL_NO_ERROR) { glBindTexture(GL_TEXTURE_2D,static_cast(this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+i])); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Here we are assuming that GL_ARB_texture_non_power_of_two is available if(this->Supports_GL_ARB_texture_float) { glTexImage2D(GL_TEXTURE_2D,0,vtkgl::RGBA16F_ARB,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } else { glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA16,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } errorCode=glGetError(); ++i; } if(errorCode==GL_NO_ERROR) { // grabbed depth buffer glBindTexture(GL_TEXTURE_2D,static_cast(this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectDepthMap])); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri(GL_TEXTURE_2D, vtkgl::DEPTH_TEXTURE_MODE, GL_LUMINANCE); glTexImage2D(GL_TEXTURE_2D, 0, vtkgl::DEPTH_COMPONENT32, size[0],size[1], 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL ); // Set up the depth render buffer GLint savedFrameBuffer; glGetIntegerv(vtkgl::FRAMEBUFFER_BINDING_EXT,&savedFrameBuffer); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(this->FrameBufferObject)); this->BindFramebuffer(); vtkgl::BindRenderbufferEXT( vtkgl::RENDERBUFFER_EXT, static_cast(this->DepthRenderBufferObject)); vtkgl::RenderbufferStorageEXT(vtkgl::RENDERBUFFER_EXT, vtkgl::DEPTH_COMPONENT24,size[0],size[1]); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(savedFrameBuffer)); errorCode=glGetError(); if(errorCode==GL_NO_ERROR) { this->LastSize[0]=size[0]; this->LastSize[1]=size[1]; } } result=errorCode==GL_NO_ERROR; } int needNewMaxValueBuffer=this->MaxValueFrameBuffer==0 && (this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND); if(needNewMaxValueBuffer) { // blend mode changed and need max value buffer. // create and bind second color buffer (we use only the red component // to store the max scalar). We cant use a one component color buffer // because all color buffer have to have the same format. // max scalar frame buffer GLuint maxValueFrameBuffer; glGenTextures(1,&maxValueFrameBuffer); this->MaxValueFrameBuffer= static_cast(maxValueFrameBuffer); // Color buffers this->m_BindMax = true; // max scalar frame buffer2 GLuint maxValueFrameBuffer2; glGenTextures(1,&maxValueFrameBuffer2); glBindTexture(GL_TEXTURE_2D,maxValueFrameBuffer2); this->MaxValueFrameBuffer2= static_cast(maxValueFrameBuffer2); } else { if(this->MaxValueFrameBuffer!=0 && (this->BlendMode!=vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND && this->BlendMode!=vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND)) { // blend mode changed and does not need max value buffer anymore. GLint savedFrameBuffer; glGetIntegerv(vtkgl::FRAMEBUFFER_BINDING_EXT,&savedFrameBuffer); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(this->FrameBufferObject)); vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D,0,0); // not scalar buffer vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(savedFrameBuffer)); GLuint maxValueFrameBuffer= static_cast(this->MaxValueFrameBuffer); glDeleteTextures(1,&maxValueFrameBuffer); this->MaxValueFrameBuffer=0; m_BindMax = false; GLuint maxValueFrameBuffer2= static_cast(this->MaxValueFrameBuffer2); glDeleteTextures(1,&maxValueFrameBuffer2); this->MaxValueFrameBuffer2=0; } } if((this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) && (sizeChanged || needNewMaxValueBuffer)) { // max scalar frame buffer GLuint maxValueFrameBuffer=static_cast(this->MaxValueFrameBuffer); glBindTexture(GL_TEXTURE_2D,maxValueFrameBuffer); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Here we are assuming that GL_ARB_texture_non_power_of_two is available if(this->Supports_GL_ARB_texture_float) { glTexImage2D(GL_TEXTURE_2D,0,vtkgl::RGBA16F_ARB,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } else { glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA16,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } // max scalar frame buffer 2 GLuint maxValueFrameBuffer2=static_cast(this->MaxValueFrameBuffer2); glBindTexture(GL_TEXTURE_2D,maxValueFrameBuffer2); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vtkgl::CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Here we are assuming that GL_ARB_texture_non_power_of_two is available if(this->Supports_GL_ARB_texture_float) { glTexImage2D(GL_TEXTURE_2D,0,vtkgl::RGBA16F_ARB,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } else { glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA16,size[0],size[1], 0, GL_RGBA, GL_FLOAT, NULL ); } } PrintError("AllocateFrameBuffers"); return result; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::GetTextureFormat( vtkImageData *input, unsigned int *internalFormat, unsigned int *format, unsigned int *type, int *componentSize) { *internalFormat=0; *format=0; *type=0; *componentSize=0; vtkDataArray *scalars=this->GetScalars(input,this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, this->CellFlag); int scalarType=scalars->GetDataType(); int components=scalars->GetNumberOfComponents(); *componentSize=vtkAbstractArray::GetDataTypeSize(scalarType)*components; if(components==4) { // this is RGBA, unsigned char only *internalFormat=GL_RGBA16; *format=GL_RGBA; *type=GL_UNSIGNED_BYTE; } else { // components==1 switch(scalarType) { case VTK_FLOAT: if(this->Supports_GL_ARB_texture_float) { *internalFormat=vtkgl::INTENSITY16F_ARB; } else { *internalFormat=GL_INTENSITY16; } *format=GL_RED; *type=GL_FLOAT; break; case VTK_UNSIGNED_CHAR: *internalFormat=GL_INTENSITY8; *format=GL_RED; *type=GL_UNSIGNED_BYTE; break; case VTK_SIGNED_CHAR: *internalFormat=GL_INTENSITY8; *format=GL_RED; *type=GL_BYTE; break; case VTK_CHAR: // not supported assert("check: impossible case" && 0); break; case VTK_BIT: // not supported assert("check: impossible case" && 0); break; case VTK_ID_TYPE: // not supported assert("check: impossible case" && 0); break; case VTK_INT: *internalFormat=GL_INTENSITY16; *format=GL_RED; *type=GL_INT; break; case VTK_DOUBLE: case VTK___INT64: case VTK_LONG: case VTK_LONG_LONG: case VTK_UNSIGNED___INT64: case VTK_UNSIGNED_LONG: case VTK_UNSIGNED_LONG_LONG: if(this->Supports_GL_ARB_texture_float) { *internalFormat=vtkgl::INTENSITY16F_ARB; } else { *internalFormat=GL_INTENSITY16; } *format=GL_RED; *type=GL_FLOAT; break; case VTK_SHORT: *internalFormat=GL_INTENSITY16; *format=GL_RED; *type=GL_SHORT; break; case VTK_STRING: // not supported assert("check: impossible case" && 0); break; case VTK_UNSIGNED_SHORT: *internalFormat=GL_INTENSITY16; *format=GL_RED; *type=GL_UNSIGNED_SHORT; break; case VTK_UNSIGNED_INT: *internalFormat=GL_INTENSITY16; *format=GL_RED; *type=GL_UNSIGNED_INT; break; default: assert("check: impossible case" && 0); break; } } } //----------------------------------------------------------------------------- // Assuming the textureSize[3] is less of equal to the maximum size of an // OpenGL 3D texture, try to see if the texture can fit on the card. //----------------------------------------------------------------------------- bool vtkMitkOpenGLGPUVolumeRayCastMapper::TestLoadingScalar( unsigned int internalFormat, unsigned int format, unsigned int type, int textureSize[3], int componentSize) { // componentSize=vtkAbstractArray::GetDataTypeSize(scalarType)*input->GetNumberOfScalarComponents() bool result; vtkgl::TexImage3D(vtkgl::PROXY_TEXTURE_3D,0, static_cast(internalFormat), textureSize[0],textureSize[1],textureSize[2],0, format, type,0); GLint width; glGetTexLevelParameteriv(vtkgl::PROXY_TEXTURE_3D,0,GL_TEXTURE_WIDTH, &width); result=width!=0; if(result) { // so far, so good but some cards always succeed with a proxy texture // let's try to actually allocate.. vtkgl::TexImage3D(vtkgl::TEXTURE_3D,0,static_cast(internalFormat), textureSize[0], textureSize[1],textureSize[2],0, format, type,0); GLenum errorCode=glGetError(); result=errorCode!=GL_OUT_OF_MEMORY; if(result) { if(errorCode!=GL_NO_ERROR) { cout<<"after try to load the texture"; cout<<" ERROR (x"<(errorCode)); cout<(this->MaxMemoryInBytes)*this->MaxMemoryFraction; } } return result; } //----------------------------------------------------------------------------- // Load the scalar field (one or four component scalar field), cell or point // based for a given subextent of the whole extent (can be the whole extent) // as a 3D texture on the GPU. // Extents are expressed in point if the cell flag is false or in cells of // the cell flag is true. // It returns true if it succeeded, false if there is not enough memory on // the GPU. // If succeeded, it updates the LoadedExtent, LoadedBounds, LoadedCellFlag // and LoadedTime. It also succeed if the scalar field is already loaded // (ie since last load, input has not changed and cell flag has not changed // and requested texture extents are enclosed in the loaded extent). // \pre input_exists: input!=0 // \pre valid_point_extent: (this->CellFlag || // (textureExtent[0]CellFlag || // (textureExtent[0]<=textureExtent[1] && // textureExtent[2]<=textureExtent[3] && // textureExtent[4]<=textureExtent[5]))) //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::LoadScalarField(vtkImageData *input, vtkImageData *maskInput, int textureExtent[6], vtkVolume *volume) { assert("pre: input_exists" && input!=0); assert("pre: valid_point_extent" && (this->CellFlag || (textureExtent[0]CellFlag || (textureExtent[0]<=textureExtent[1] && textureExtent[2]<=textureExtent[3] && textureExtent[4]<=textureExtent[5]))); int result=1; // succeeded // make sure we rebind our texture object to texture0 even if we don't have // to load the data themselves because the binding might be changed by // another mapper between two rendering calls. vtkgl::ActiveTexture(vtkgl::TEXTURE0); // Find the texture. vtkstd::map::iterator it= this->ScalarsTextures->Map.find(input); vtkKWScalarField *texture; if(it==this->ScalarsTextures->Map.end()) { texture=new vtkKWScalarField; this->ScalarsTextures->Map[input]=texture; texture->SetSupports_GL_ARB_texture_float(this->Supports_GL_ARB_texture_float==1); } else { texture=(*it).second; } texture->Update(input,this->CellFlag,textureExtent,this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, volume->GetProperty()->GetInterpolationType() ==VTK_LINEAR_INTERPOLATION, this->TableRange, static_cast(static_cast(this->MaxMemoryInBytes)*this->MaxMemoryFraction)); result=texture->IsLoaded(); this->CurrentScalar=texture; // Mask if(maskInput!=0) { vtkgl::ActiveTexture(vtkgl::TEXTURE7); // Find the texture. vtkstd::map::iterator it2= this->MaskTextures->Map.find(maskInput); vtkKWMask *mask; if(it2==this->MaskTextures->Map.end()) { mask=new vtkKWMask; this->MaskTextures->Map[maskInput]=mask; } else { mask=(*it2).second; } mask->Update(maskInput,this->CellFlag,textureExtent,this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, static_cast(static_cast(this->MaxMemoryInBytes)*this->MaxMemoryFraction)); result=result && mask->IsLoaded(); this->CurrentMask=mask; vtkgl::ActiveTexture(vtkgl::TEXTURE0); } return result; } //----------------------------------------------------------------------------- // Allocate memory and load color table on the GPU or // reload it if the transfer function changed. // \pre vol_exists: vol!=0 // \pre valid_numberOfScalarComponents: numberOfScalarComponents==1 || numberOfScalarComponents==4 //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::UpdateColorTransferFunction( vtkVolume *vol, int numberOfScalarComponents) { assert("pre: vol_exists" && vol!=0); assert("pre: valid_numberOfScalarComponents" && (numberOfScalarComponents==1 || numberOfScalarComponents==4)); // Build the colormap in a 1D texture. // 1D RGB-texture=mapping from scalar values to color values // build the table if(numberOfScalarComponents==1) { vtkVolumeProperty *volumeProperty=vol->GetProperty(); vtkColorTransferFunction *colorTransferFunction=volumeProperty->GetRGBTransferFunction(0); vtkgl::ActiveTexture(vtkgl::TEXTURE1); this->RGBTable->Update( colorTransferFunction,this->TableRange, volumeProperty->GetInterpolationType()==VTK_LINEAR_INTERPOLATION); // Restore default vtkgl::ActiveTexture( vtkgl::TEXTURE0); } if(this->MaskInput!=0) { vtkVolumeProperty *volumeProperty=vol->GetProperty(); vtkColorTransferFunction *c=volumeProperty->GetRGBTransferFunction(1); vtkgl::ActiveTexture(vtkgl::TEXTURE8); this->Mask1RGBTable->Update(c,this->TableRange,false); c=volumeProperty->GetRGBTransferFunction(2); vtkgl::ActiveTexture(vtkgl::TEXTURE9); this->Mask2RGBTable->Update(c,this->TableRange,false); // Restore default vtkgl::ActiveTexture( vtkgl::TEXTURE0); } return 1; } //----------------------------------------------------------------------------- // Allocate memory and load opacity table on the GPU or // reload it if the transfert function changed. // \pre vol_exists: vol!=0 // \pre valid_numberOfScalarComponents: numberOfScalarComponents==1 || numberOfScalarComponents==4 //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::UpdateOpacityTransferFunction( vtkVolume *vol, int numberOfScalarComponents, unsigned int level) { assert("pre: vol_exists" && vol!=0); assert("pre: valid_numberOfScalarComponents" && (numberOfScalarComponents==1 || numberOfScalarComponents==4)); (void)numberOfScalarComponents; // remove warning in release mode. vtkVolumeProperty *volumeProperty=vol->GetProperty(); vtkPiecewiseFunction *scalarOpacity=volumeProperty->GetScalarOpacity(); vtkgl::ActiveTexture( vtkgl::TEXTURE2); //stay here this->OpacityTables->Vector[level].Update( scalarOpacity,this->BlendMode, this->ActualSampleDistance, this->TableRange, volumeProperty->GetScalarOpacityUnitDistance(0), volumeProperty->GetInterpolationType()==VTK_LINEAR_INTERPOLATION); // Restore default active texture vtkgl::ActiveTexture( vtkgl::TEXTURE0); return 1; } //----------------------------------------------------------------------------- // Prepare rendering in the offscreen framebuffer. // \pre ren_exists: ren!=0 // \pre vol_exists: vol!=0 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::SetupRender(vtkRenderer *ren, vtkVolume *vol) { assert("pre: ren_exists" && ren!=0); assert("pre: vol_exists" && vol!=0); double aspect[2]; int lowerLeft[2]; int usize, vsize; ren->GetTiledSizeAndOrigin(&usize,&vsize,lowerLeft,lowerLeft+1); usize = static_cast(usize*this->ReductionFactor); vsize = static_cast(vsize*this->ReductionFactor); this->ReducedSize[0]=usize; this->ReducedSize[1]=vsize; // the FBO has the size of the renderer (not the renderwindow), // we always starts at 0,0. glViewport(0,0, usize, vsize); glEnable( GL_SCISSOR_TEST ); // scissor on the FBO, on the reduced part. glScissor(0,0, usize, vsize); glClearColor(0.0, 0.0, 0.0, 0.0); // maxvalue is 1 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); ren->ComputeAspect(); ren->GetAspect(aspect); double aspect2[2]; ren->vtkViewport::ComputeAspect(); ren->vtkViewport::GetAspect(aspect2); double aspectModification = aspect[0]*aspect2[1]/(aspect[1]*aspect2[0]); vtkCamera *cam = ren->GetActiveCamera(); glMatrixMode( GL_PROJECTION); if(usize && vsize) { this->TempMatrix[0]->DeepCopy(cam->GetProjectionTransformMatrix( aspectModification*usize/vsize, -1,1)); this->TempMatrix[0]->Transpose(); glLoadMatrixd(this->TempMatrix[0]->Element[0]); } else { glLoadIdentity(); } // push the model view matrix onto the stack, make sure we // adjust the mode first glMatrixMode(GL_MODELVIEW); glPushMatrix(); this->TempMatrix[0]->DeepCopy(vol->GetMatrix()); this->TempMatrix[0]->Transpose(); // insert camera view transformation glMultMatrixd(this->TempMatrix[0]->Element[0]); glShadeModel(GL_SMOOTH); glDisable( GL_LIGHTING); glEnable (GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); // very important, otherwise the first image looks dark. this->PrintError("SetupRender"); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::DebugDisplayBox(vtkPolyData *box) { vtkPoints *points=box->GetPoints(); vtkCellArray *polys=box->GetPolys(); cout<<"npts="<GetNumberOfPoints()<GetNumberOfPoints()) { double coords[3]; points->GetPoint(pointId,coords); cout<<"pointId="<GetMatrix( this->InvVolumeMatrix ); this->InvVolumeMatrix->Invert(); if(this->BoxSource==0) { this->BoxSource=vtkTessellatedBoxSource::New(); } this->BoxSource->SetBounds(worldBounds); this->BoxSource->SetLevel(0); this->BoxSource->QuadsOn(); if(this->Planes==0) { this->Planes=vtkPlaneCollection::New(); } this->Planes->RemoveAllItems(); vtkCamera *cam = ren->GetActiveCamera(); double camWorldRange[2]; double camWorldPos[4]; double camFocalWorldPoint[4]; double camWorldDirection[3]; double range[2]; double camPos[4]; double focalPoint[4]; double direction[3]; cam->GetPosition(camWorldPos); camWorldPos[3] = 1.0; this->InvVolumeMatrix->MultiplyPoint( camWorldPos, camPos ); if ( camPos[3] ) { camPos[0] /= camPos[3]; camPos[1] /= camPos[3]; camPos[2] /= camPos[3]; } cam->GetFocalPoint(camFocalWorldPoint); camFocalWorldPoint[3]=1.0; this->InvVolumeMatrix->MultiplyPoint( camFocalWorldPoint,focalPoint ); if ( focalPoint[3] ) { focalPoint[0] /= focalPoint[3]; focalPoint[1] /= focalPoint[3]; focalPoint[2] /= focalPoint[3]; } // Compute the normalized view direction direction[0] = focalPoint[0] - camPos[0]; direction[1] = focalPoint[1] - camPos[1]; direction[2] = focalPoint[2] - camPos[2]; vtkMath::Normalize(direction); // The range (near/far) must also be transformed // into the local coordinate system. camWorldDirection[0] = camFocalWorldPoint[0] - camWorldPos[0]; camWorldDirection[1] = camFocalWorldPoint[1] - camWorldPos[1]; camWorldDirection[2] = camFocalWorldPoint[2] - camWorldPos[2]; vtkMath::Normalize(camWorldDirection); double camNearWorldPoint[4]; double camFarWorldPoint[4]; double camNearPoint[4]; double camFarPoint[4]; cam->GetClippingRange(camWorldRange); - MITK_INFO << "vtkMiktOpenGLGPUVolumeRayCastMapper.cpp"; camNearWorldPoint[0] = camWorldPos[0] + camWorldRange[0]*camWorldDirection[0]; camNearWorldPoint[1] = camWorldPos[1] + camWorldRange[0]*camWorldDirection[1]; camNearWorldPoint[2] = camWorldPos[2] + camWorldRange[0]*camWorldDirection[2]; camNearWorldPoint[3] = 1.; camFarWorldPoint[0] = camWorldPos[0] + camWorldRange[1]*camWorldDirection[0]; camFarWorldPoint[1] = camWorldPos[1] + camWorldRange[1]*camWorldDirection[1]; camFarWorldPoint[2] = camWorldPos[2] + camWorldRange[1]*camWorldDirection[2]; camFarWorldPoint[3] = 1.; this->InvVolumeMatrix->MultiplyPoint( camNearWorldPoint, camNearPoint ); if (camNearPoint[3]) { camNearPoint[0] /= camNearPoint[3]; camNearPoint[1] /= camNearPoint[3]; camNearPoint[2] /= camNearPoint[3]; } this->InvVolumeMatrix->MultiplyPoint( camFarWorldPoint, camFarPoint ); if (camFarPoint[3]) { camFarPoint[0] /= camFarPoint[3]; camFarPoint[1] /= camFarPoint[3]; camFarPoint[2] /= camFarPoint[3]; } range[0] = sqrt(vtkMath::Distance2BetweenPoints(camNearPoint, camPos)); range[1] = sqrt(vtkMath::Distance2BetweenPoints(camFarPoint, camPos)); //double nearPoint[3], farPoint[3]; double dist = range[1] - range[0]; range[0] += dist / (2<<16); range[1] -= dist / (2<<16); if(this->NearPlane==0) { this->NearPlane= vtkPlane::New(); } //this->NearPlane->SetOrigin( nearPoint ); this->NearPlane->SetOrigin( camNearPoint ); this->NearPlane->SetNormal( direction ); this->Planes->AddItem(this->NearPlane); if ( this->ClippingPlanes ) { this->ClippingPlanes->InitTraversal(); vtkPlane *plane; while ( (plane = this->ClippingPlanes->GetNextItem()) ) { // Planes are in world coordinates, we need to // convert them in local coordinates double planeOrigin[4], planeNormal[4], planeP1[4]; plane->GetOrigin(planeOrigin); planeOrigin[3] = 1.; plane->GetNormal(planeNormal); planeP1[0] = planeOrigin[0] + planeNormal[0]; planeP1[1] = planeOrigin[1] + planeNormal[1]; planeP1[2] = planeOrigin[2] + planeNormal[2]; planeP1[3] = 1.; this->InvVolumeMatrix->MultiplyPoint(planeOrigin, planeOrigin); this->InvVolumeMatrix->MultiplyPoint(planeP1, planeP1); if( planeOrigin[3]) { planeOrigin[0] /= planeOrigin[3]; planeOrigin[1] /= planeOrigin[3]; planeOrigin[2] /= planeOrigin[3]; } if( planeP1[3]) { planeP1[0] /= planeP1[3]; planeP1[1] /= planeP1[3]; planeP1[2] /= planeP1[3]; } planeNormal[0] = planeP1[0] - planeOrigin[0]; planeNormal[1] = planeP1[1] - planeOrigin[1]; planeNormal[2] = planeP1[2] - planeOrigin[2]; vtkMath::Normalize(planeNormal); vtkPlane* localPlane = vtkPlane::New(); localPlane->SetOrigin(planeOrigin); localPlane->SetNormal(planeNormal); this->Planes->AddItem(localPlane); localPlane->Delete(); } } if(this->Clip==0) { this->Clip=vtkClipConvexPolyData::New(); this->Clip->SetInputConnection(this->BoxSource->GetOutputPort()); this->Clip->SetPlanes( this->Planes ); } this->Clip->Update(); if(this->Densify==0) { this->Densify=vtkDensifyPolyData::New(); this->Densify->SetInputConnection(this->Clip->GetOutputPort()); this->Densify->SetNumberOfSubdivisions(2); } this->Densify->Update(); this->ClippedBoundingBox = this->Densify->GetOutput(); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::RenderClippedBoundingBox( int tcoordFlag, size_t currentBlock, size_t numberOfBlocks, vtkRenderWindow *renWin ) { assert("pre: valid_currentBlock" && currentBlockClippedBoundingBox->GetPoints(); vtkCellArray *polys = this->ClippedBoundingBox->GetPolys(); vtkIdType npts; vtkIdType *pts; vtkIdType i, j; double center[3] = {0,0,0}; double min[3] = {VTK_DOUBLE_MAX, VTK_DOUBLE_MAX, VTK_DOUBLE_MAX}; double max[3] = {VTK_DOUBLE_MIN, VTK_DOUBLE_MIN, VTK_DOUBLE_MIN}; // First compute center point npts = points->GetNumberOfPoints(); for ( i = 0; i < npts; i++ ) { double pt[3]; points->GetPoint( i, pt ); for ( j = 0; j < 3; j++ ) { min[j] = (pt[j]max[j])?(pt[j]):(max[j]); } } center[0] = 0.5*(min[0]+max[0]); center[1] = 0.5*(min[1]+max[1]); center[2] = 0.5*(min[2]+max[2]); double *loadedBounds=0; vtkIdType *loadedExtent=0; if ( tcoordFlag ) { loadedBounds=this->CurrentScalar->GetLoadedBounds(); loadedExtent=this->CurrentScalar->GetLoadedExtent(); } double *spacing=this->GetInput()->GetSpacing(); double spacingSign[3]; i=0; while(i<3) { if(spacing[i]<0) { spacingSign[i]=-1.0; } else { spacingSign[i]=1.0; } ++i; } // make it double for the ratio of the progress. int polyId=0; double polyCount=static_cast(polys->GetNumberOfCells()); polys->InitTraversal(); int abort=0; while ( !abort && polys->GetNextCell(npts, pts) ) { vtkIdType start, end, inc; // Need to have at least a triangle if ( npts > 2 ) { // Check the cross product of the first two // vectors dotted with the vector from the // center to the second point. Is it positive or // negative? double p1[3], p2[3], p3[3]; double v1[3], v2[3], v3[3], v4[3]; points->GetPoint(pts[0], p1 ); points->GetPoint(pts[1], p2 ); points->GetPoint(pts[2], p3 ); v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2]; v2[0] = p2[0] - p3[0]; v2[1] = p2[1] - p3[1]; v2[2] = p2[2] - p3[2]; vtkMath::Cross( v1, v2, v3 ); vtkMath::Normalize(v3); v4[0] = p2[0] - center[0]; v4[1] = p2[1] - center[1]; v4[2] = p2[2] - center[2]; vtkMath::Normalize(v4); double dot = vtkMath::Dot( v3, v4 ); if (( dot < 0) && this->PreserveOrientation) { start = 0; end = npts; inc = 1; } else { start = npts-1; end = -1; inc = -1; } glBegin( GL_TRIANGLE_FAN ); // GL_POLYGON -> GL_TRIANGLE_FAN double vert[3]; double tcoord[3]; for ( i = start; i != end; i += inc ) { points->GetPoint(pts[i], vert); if ( tcoordFlag ) { for ( j = 0; j < 3; j++ ) { // loaded bounds take both cell data and point date cases into // account if(this->CellFlag) // texcoords between 0 and 1. More complex // depends on the loaded texture { tcoord[j] = spacingSign[j]*(vert[j] - loadedBounds[j*2]) / (loadedBounds[j*2+1] - loadedBounds[j*2]); } else // texcoords between 1/2N and 1-1/2N. { double tmp; // between 0 and 1 tmp = spacingSign[j]*(vert[j] - loadedBounds[j*2]) / (loadedBounds[j*2+1] - loadedBounds[j*2]); double delta=static_cast( loadedExtent[j*2+1]-loadedExtent[j*2]+1); tcoord[j]=(tmp*(delta-1)+0.5)/delta; } } vtkgl::MultiTexCoord3dv(vtkgl::TEXTURE0, tcoord); } glVertex3dv(vert); } glEnd(); } if(tcoordFlag) { // otherwise, we are rendering back face to initialize the zbuffer. if (!this->GeneratingCanonicalView && this->ReportProgress) { glFinish(); // Only invoke an event at most one every second. double currentTime=vtkTimerLog::GetUniversalTime(); if(currentTime - this->LastProgressEventTime > 1.0) { double progress=(static_cast(currentBlock)+polyId/polyCount)/ static_cast(numberOfBlocks); this->InvokeEvent(vtkCommand::VolumeMapperRenderProgressEvent, &progress); renWin->MakeCurrent(); this->LastProgressEventTime = currentTime; } } abort=renWin->CheckAbortStatus(); } ++polyId; } return abort; } void vtkMitkOpenGLGPUVolumeRayCastMapper::CopyFBOToTexture() { // in OpenGL copy texture to texture does not exist but // framebuffer to texture exists (and our FB is an FBO). // we have to copy and not just to switch color textures because the // colorbuffer has to accumulate color or values step after step. // Switching would not work because two different steps can draw different // polygons that don't overlap vtkgl::ActiveTexture(vtkgl::TEXTURE4); glBindTexture( GL_TEXTURE_2D, this->TextureObjects[ vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+1]); glReadBuffer(vtkgl::COLOR_ATTACHMENT0_EXT); glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,this->ReducedSize[0], this->ReducedSize[1]); if(this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) { vtkgl::ActiveTexture(vtkgl::TEXTURE5); glBindTexture(GL_TEXTURE_2D,this->MaxValueFrameBuffer2); glReadBuffer(vtkgl::COLOR_ATTACHMENT0_EXT+1); glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,this->ReducedSize[0], this->ReducedSize[1]); } vtkgl::ActiveTexture(vtkgl::TEXTURE0); } //----------------------------------------------------------------------------- // Restore OpenGL state after rendering of the dataset. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::CleanupRender() { glPopMatrix(); glDisable(GL_CULL_FACE); } //----------------------------------------------------------------------------- // Build the fragment shader program that scale and bias a texture // for window/level purpose. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::BuildScaleBiasProgram() { if(this->ScaleBiasProgramShader==0) { GLuint programShader; GLuint fragmentShader; programShader=vtkgl::CreateProgram(); fragmentShader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER); vtkgl::AttachShader(programShader,fragmentShader); vtkgl::DeleteShader(fragmentShader); // reference counting vtkgl::ShaderSource( fragmentShader,1, const_cast(&vtkMitkGPUVolumeRayCastMapper_ScaleBiasFS),0); vtkgl::CompileShader(fragmentShader); this->CheckCompilation(static_cast(fragmentShader)); vtkgl::LinkProgram(programShader); this->CheckLinkage(static_cast(programShader)); this->ScaleBiasProgramShader=static_cast(programShader); this->UFrameBufferTexture= static_cast(vtkgl::GetUniformLocation(programShader, "frameBufferTexture")); this->UScale=static_cast(vtkgl::GetUniformLocation(programShader, "scale")); this->UBias=static_cast(vtkgl::GetUniformLocation(programShader, "bias")); } } //----------------------------------------------------------------------------- // Render the offscreen buffer to the screen. // \pre ren_exists: ren!=0 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::RenderTextureToScreen(vtkRenderer *ren) { assert("pre: ren_exists" && ren!=0); if ( this->GeneratingCanonicalView ) { // We just need to copy of the data, not render it glBindTexture(GL_TEXTURE_2D, this->TextureObjects[ vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); glPixelStorei( GL_PACK_ALIGNMENT, 1 ); unsigned char *outPtr = static_cast(this->CanonicalViewImageData->GetScalarPointer()); glGetTexImage( GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, outPtr ); return; } int lowerLeft[2]; int usize, vsize; ren->GetTiledSizeAndOrigin(&usize,&vsize,lowerLeft,lowerLeft+1); glViewport(lowerLeft[0],lowerLeft[1], usize, vsize); glEnable( GL_SCISSOR_TEST ); glScissor(lowerLeft[0],lowerLeft[1], usize, vsize); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0.0, usize, 0.0, vsize, -1.0, 1.0 ); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glBindTexture(GL_TEXTURE_2D, this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glEnable(GL_BLEND); glBlendFunc( GL_ONE,GL_ONE_MINUS_SRC_ALPHA); // As we use replace mode, we don't need to set the color value. glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE); glDisable(GL_DEPTH_TEST); double xOffset = 1.0 / usize; double yOffset = 1.0 / vsize; glDepthMask(GL_FALSE); double scale=1.0/this->FinalColorWindow; double bias=0.5-this->FinalColorLevel/this->FinalColorWindow; if(scale!=1.0 || bias!=0.0) { this->BuildScaleBiasProgram(); vtkgl::UseProgram(this->ScaleBiasProgramShader); if(this->UFrameBufferTexture!=-1) { vtkgl::Uniform1i(this->UFrameBufferTexture,0); } else { vtkErrorMacro(<<"uFrameBufferTexture is not a uniform variable."); } if(this->UScale!=-1) { vtkgl::Uniform1f(this->UScale,static_cast(scale)); } else { vtkErrorMacro(<<"uScale is not a uniform variable."); } if(this->UBias!=-1) { vtkgl::Uniform1f(this->UBias,static_cast(bias)); } else { vtkErrorMacro(<<"uBias is not a uniform variable."); } } else { glEnable(GL_TEXTURE_2D); // fixed pipeline } glBegin(GL_QUADS); glTexCoord2f(static_cast(xOffset),static_cast(yOffset)); glVertex2f(0.0,0.0); glTexCoord2f(static_cast(this->ReductionFactor-xOffset), static_cast(yOffset)); glVertex2f(static_cast(usize),0.0); glTexCoord2f(static_cast(this->ReductionFactor-xOffset), static_cast(this->ReductionFactor-yOffset)); glVertex2f(static_cast(usize),static_cast(vsize)); glTexCoord2f(static_cast(xOffset), static_cast(this->ReductionFactor-yOffset)); glVertex2f(0.0,static_cast(vsize)); glEnd(); // Restore the default mode. Used in overlay. glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); if(scale!=1.0 || bias!=0.0) { vtkgl::UseProgram(0); } else { glDisable(GL_TEXTURE_2D); } glDepthMask(GL_TRUE); glDisable(GL_BLEND); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } //----------------------------------------------------------------------------- // Update the reduction factor of the render viewport (this->ReductionFactor) // according to the time spent in seconds to render the previous frame // (this->TimeToDraw) and a time in seconds allocated to render the next // frame (allocatedTime). // \pre valid_current_reduction_range: this->ReductionFactor>0.0 && this->ReductionFactor<=1.0 // \pre positive_TimeToDraw: this->TimeToDraw>=0.0 // \pre positive_time: allocatedTime>0.0 // \post valid_new_reduction_range: this->ReductionFactor>0.0 && this->ReductionFactor<=1.0 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::ComputeReductionFactor( double allocatedTime) { assert("pre: valid_current_reduction_range" && this->ReductionFactor>0.0 && this->ReductionFactor<=1.0); assert("pre: positive_TimeToDraw" && this->TimeToDraw>=0.0); assert("pre: positive_time" && allocatedTime>0.0); if ( this->GeneratingCanonicalView ) { this->ReductionFactor = 1.0; return; } if ( !this->AutoAdjustSampleDistances ) { this->ReductionFactor = 1.0 / this->ImageSampleDistance; return; } if ( this->TimeToDraw ) { double oldFactor = this->ReductionFactor; double timeToDraw; if (allocatedTime < 1.0) { timeToDraw = this->SmallTimeToDraw; if ( timeToDraw == 0.0 ) { timeToDraw = this->BigTimeToDraw/3.0; } } else { timeToDraw = this->BigTimeToDraw; } if ( timeToDraw == 0.0 ) { timeToDraw = 10.0; } double fullTime = timeToDraw / this->ReductionFactor; double newFactor = allocatedTime / fullTime; if ( oldFactor == 1.0 || newFactor / oldFactor > 1.3 || newFactor / oldFactor < .95 ) { this->ReductionFactor = (newFactor+oldFactor)/2.0; this->ReductionFactor = (this->ReductionFactor > 5.0)?(1.00):(this->ReductionFactor); this->ReductionFactor = (this->ReductionFactor > 1.0)?(0.99):(this->ReductionFactor); this->ReductionFactor = (this->ReductionFactor < 0.1)?(0.10):(this->ReductionFactor); if ( 1.0/this->ReductionFactor > this->MaximumImageSampleDistance ) { this->ReductionFactor = 1.0 / this->MaximumImageSampleDistance; } if ( 1.0/this->ReductionFactor < this->MinimumImageSampleDistance ) { this->ReductionFactor = 1.0 / this->MinimumImageSampleDistance; } } } else { this->ReductionFactor = 1.0; } assert("post: valid_new_reduction_range" && this->ReductionFactor>0.0 && this->ReductionFactor<=1.0); } //----------------------------------------------------------------------------- // Rendering initialization including making the context current, loading // necessary extensions, allocating frame buffers, updating transfer function, // computing clipping regions, and building the fragment shader. // // Pre-conditions: // - ren != NULL // - vol != NULL // - ren->GetRenderWindow() != NULL // - 1 <= numberOfScalarComponents <= 4 // - numberOfLevels >= 1 //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::PreRender(vtkRenderer *ren, vtkVolume *vol, double datasetBounds[6], double scalarRange[2], int numberOfScalarComponents, unsigned int numberOfLevels) { // make sure our window is the current OpenGL context. ren->GetRenderWindow()->MakeCurrent(); // If we haven't already succeeded in loading the extensions, // try to load them if(!this->LoadExtensionsSucceeded) { this->LoadExtensions(ren->GetRenderWindow()); } // If we can't load the necessary extensions, provide // feedback on why it failed. if(!this->LoadExtensionsSucceeded) { vtkErrorMacro( "Rendering failed because the following OpenGL extensions " "are required but not supported: " << (this->UnsupportedRequiredExtensions->Stream.str()).c_str()); return; } // Create the OpenGL object that we need this->CreateOpenGLObjects(); // Compute the reduction factor that may be necessary to get // the interactive rendering rate that we want this->ComputeReductionFactor(vol->GetAllocatedRenderTime()); // Allocate the frame buffers if(!this->AllocateFrameBuffers(ren)) { vtkErrorMacro("Not enough GPU memory to create a framebuffer."); return; } // Save the scalar range - this is what we will use for the range // of the transfer functions this->TableRange[0]=scalarRange[0]; this->TableRange[1]=scalarRange[1]; if(this->RGBTable==0) { this->RGBTable=new vtkRGBTable; } if(this->MaskInput!=0) { if(this->Mask1RGBTable==0) { this->Mask1RGBTable=new vtkRGBTable; } if(this->Mask2RGBTable==0) { this->Mask2RGBTable=new vtkRGBTable; } } // Update the color transfer function this->UpdateColorTransferFunction(vol,numberOfScalarComponents); // Update the noise texture that will be used to jitter rays to // reduce alliasing artifacts this->UpdateNoiseTexture(); // We are going to change the blending mode and blending function - // so lets push here so we can pop later glPushAttrib(GL_COLOR_BUFFER_BIT); // If this is the canonical view - we don't want to intermix so we'll just // start by clearing the z buffer. if ( this->GeneratingCanonicalView ) { glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } // See if the volume transform is orientation-preserving vtkMatrix4x4 *m=vol->GetMatrix(); double det=vtkMath::Determinant3x3( m->GetElement(0,0),m->GetElement(0,1),m->GetElement(0,2), m->GetElement(1,0),m->GetElement(1,1),m->GetElement(1,2), m->GetElement(2,0),m->GetElement(2,1),m->GetElement(2,2)); this->PreserveOrientation=det>0; // If we have clipping planes, render the back faces of the clipped // bounding box of the whole dataset to set the zbuffer. if(this->ClippingPlanes && this->ClippingPlanes->GetNumberOfItems()!=0) { // push the model view matrix onto the stack, make sure we // adjust the mode first glMatrixMode(GL_MODELVIEW); glPushMatrix(); this->TempMatrix[0]->DeepCopy(vol->GetMatrix()); this->TempMatrix[0]->Transpose(); glMultMatrixd(this->TempMatrix[0]->Element[0]); this->ClipBoundingBox(ren,datasetBounds,vol); glEnable (GL_CULL_FACE); glCullFace (GL_FRONT); glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE); this->RenderClippedBoundingBox(0,0,1,ren->GetRenderWindow()); glDisable (GL_CULL_FACE); glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); //glMatrixMode(GL_MODELVIEW); glPopMatrix(); } // Check if everything is OK this->CheckFrameBufferStatus(); // Intermixed geometry: Grab the depth buffer into a texture int size[2]; int lowerLeft[2]; ren->GetTiledSizeAndOrigin(size,size+1,lowerLeft,lowerLeft+1); vtkgl::ActiveTexture( vtkgl::TEXTURE3 ); glBindTexture(GL_TEXTURE_2D, static_cast( this->TextureObjects[ vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectDepthMap])); glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,lowerLeft[0],lowerLeft[1],size[0], size[1]); vtkgl::ActiveTexture( vtkgl::TEXTURE0 ); int parallelProjection=ren->GetActiveCamera()->GetParallelProjection(); // initialize variables to prevent compiler warnings. int rayCastMethod=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP; int shadeMethod=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNotUsed; int componentMethod=vtkMitkOpenGLGPUVolumeRayCastMapperComponentNotUsed; switch(this->BlendMode) { case vtkVolumeMapper::COMPOSITE_BLEND: switch(numberOfScalarComponents) { case 1: componentMethod=vtkMitkOpenGLGPUVolumeRayCastMapperComponentOne; break; case 4: componentMethod=vtkMitkOpenGLGPUVolumeRayCastMapperComponentFour; break; default: assert("check: impossible case" && false); break; } if(this->MaskInput!=0) { rayCastMethod= vtkMitkOpenGLGPUVolumeRayCastMapperMethodCompositeMask; } else { //cout<<"program is composite+shade"<GetProperty()->GetShade() ) { shadeMethod=vtkMitkOpenGLGPUVolumeRayCastMapperShadeYes; assert("check: only_1_component_todo" && numberOfScalarComponents==1); } else { shadeMethod=vtkMitkOpenGLGPUVolumeRayCastMapperShadeNo; //cout<<"program is composite"<ComputeNumberOfCroppingRegions(); // TODO AMR vs single block if(this->AMRMode) { NumberOfCroppingRegions=2; // >1, means use do compositing between blocks } this->BuildProgram(parallelProjection,rayCastMethod,shadeMethod, componentMethod); this->CheckLinkage(this->ProgramShader); vtkgl::UseProgram(this->ProgramShader); // for active texture 0, dataset if(numberOfScalarComponents==1) { // colortable vtkgl::ActiveTexture(vtkgl::TEXTURE1); this->RGBTable->Bind(); if(this->MaskInput!=0) { vtkgl::ActiveTexture(vtkgl::TEXTURE8); this->Mask1RGBTable->Bind(); vtkgl::ActiveTexture(vtkgl::TEXTURE9); this->Mask2RGBTable->Bind(); } } GLint uDataSetTexture; uDataSetTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"dataSetTexture"); if(uDataSetTexture!=-1) { vtkgl::Uniform1i(uDataSetTexture,0); } else { vtkErrorMacro(<<"dataSetTexture is not a uniform variable."); } if ( this->MaskInput) { // Make the mask texture available on texture unit 7 GLint uMaskTexture; uMaskTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"maskTexture"); if(uMaskTexture!=-1) { vtkgl::Uniform1i(uMaskTexture,7); } else { vtkErrorMacro(<<"maskTexture is not a uniform variable."); } } if(numberOfScalarComponents==1) { GLint uColorTexture; uColorTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"colorTexture"); if(uColorTexture!=-1) { vtkgl::Uniform1i(uColorTexture,1); } else { vtkErrorMacro(<<"colorTexture is not a uniform variable."); } if(this->MaskInput!=0) { GLint uMask1ColorTexture; uMask1ColorTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"mask1ColorTexture"); if(uMask1ColorTexture!=-1) { vtkgl::Uniform1i(uMask1ColorTexture,8); } else { vtkErrorMacro(<<"mask1ColorTexture is not a uniform variable."); } GLint uMask2ColorTexture; uMask2ColorTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"mask2ColorTexture"); if(uMask2ColorTexture!=-1) { vtkgl::Uniform1i(uMask2ColorTexture,9); } else { vtkErrorMacro(<<"mask2ColorTexture is not a uniform variable."); } GLint uMaskBlendFactor; uMaskBlendFactor=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"maskBlendFactor"); if(uMaskBlendFactor!=-1) { vtkgl::Uniform1f(uMaskBlendFactor,this->MaskBlendFactor); } else { vtkErrorMacro(<<"maskBlendFactor is not a uniform variable."); } } } GLint uOpacityTexture; uOpacityTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"opacityTexture"); if(uOpacityTexture!=-1) { vtkgl::Uniform1i(uOpacityTexture,2); } else { vtkErrorMacro(<<"opacityTexture is not a uniform variable."); } // depthtexture vtkgl::ActiveTexture( vtkgl::TEXTURE3 ); glBindTexture(GL_TEXTURE_2D,static_cast(this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectDepthMap])); GLint uDepthTexture; uDepthTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"depthTexture"); if(uDepthTexture!=-1) { vtkgl::Uniform1i(uDepthTexture,3); } else { vtkErrorMacro(<<"depthTexture is not a uniform variable."); } // noise texture vtkgl::ActiveTexture( vtkgl::TEXTURE6 ); glBindTexture(GL_TEXTURE_2D,static_cast(this->NoiseTextureId)); GLint uNoiseTexture; uNoiseTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"noiseTexture"); if(uNoiseTexture!=-1) { vtkgl::Uniform1i(uNoiseTexture,6); } else { vtkErrorMacro(<<"noiseTexture is not a uniform variable."); } this->CheckFrameBufferStatus(); if(this->NumberOfCroppingRegions>1) { // framebuffer texture if(rayCastMethod!=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP && rayCastMethod!=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIP) { vtkgl::ActiveTexture( vtkgl::TEXTURE4 ); glBindTexture(GL_TEXTURE_2D,static_cast(this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront])); GLint uFrameBufferTexture; uFrameBufferTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"frameBufferTexture"); this->PrintError("framebuffertexture 1"); if(uFrameBufferTexture!=-1) { vtkgl::Uniform1i(uFrameBufferTexture,4); } else { vtkErrorMacro(<<"frameBufferTexture is not a uniform variable."); } this->PrintError("framebuffertexture 2"); } this->CheckFrameBufferStatus(); // max scalar value framebuffer texture if(this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) { vtkgl::ActiveTexture( vtkgl::TEXTURE5 ); glBindTexture(GL_TEXTURE_2D,static_cast(this->MaxValueFrameBuffer2)); GLint uScalarBufferTexture; uScalarBufferTexture=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"scalarBufferTexture"); this->PrintError("scalarbuffertexture 1"); if(uScalarBufferTexture!=-1) { vtkgl::Uniform1i(uScalarBufferTexture,5); } else { vtkErrorMacro(<<"scalarBufferTexture is not a uniform variable."); } this->PrintError("scalarbuffertexture 2"); } } this->CheckFrameBufferStatus(); GLint uWindowLowerLeftCorner; uWindowLowerLeftCorner=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"windowLowerLeftCorner"); if(uWindowLowerLeftCorner!=-1) { vtkgl::Uniform2f(uWindowLowerLeftCorner,static_cast(lowerLeft[0]), static_cast(lowerLeft[1])); } else { vtkErrorMacro(<<"windowLowerLeftCorner is not a uniform variable."); } GLint uInvOriginalWindowSize; uInvOriginalWindowSize=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"invOriginalWindowSize"); if(uInvOriginalWindowSize!=-1) { vtkgl::Uniform2f(uInvOriginalWindowSize, static_cast(1.0/size[0]), static_cast(1.0/size[1])); } else { // yes it is not error. It is only actually used when there is some // complex cropping (this->NumberOfCroppingRegions>1). Some GLSL compilers // may remove the uniform variable for optimization when it is not used. vtkDebugMacro( <<"invOriginalWindowSize is not an active uniform variable."); } size[0] = static_cast(size[0]*this->ReductionFactor); size[1] = static_cast(size[1]*this->ReductionFactor); GLint uInvWindowSize; uInvWindowSize=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"invWindowSize"); if(uInvWindowSize!=-1) { vtkgl::Uniform2f(uInvWindowSize,static_cast(1.0/size[0]), static_cast(1.0/size[1])); } else { vtkErrorMacro(<<"invWindowSize is not a uniform variable."); } this->PrintError("after uniforms for textures"); this->CheckFrameBufferStatus(); GLint savedFrameBuffer; glGetIntegerv(vtkgl::FRAMEBUFFER_BINDING_EXT,&savedFrameBuffer); this->SavedFrameBuffer=static_cast(savedFrameBuffer); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(this->FrameBufferObject)); this->BindFramebuffer(); GLenum buffer[4]; buffer[0] = vtkgl::COLOR_ATTACHMENT0_EXT; if(this->NumberOfCroppingRegions>1 && this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND) { // max scalar frame buffer buffer[1] = vtkgl::COLOR_ATTACHMENT1_EXT; } else { buffer[1] = GL_NONE; } vtkgl::DrawBuffers(2,buffer); this->CheckFrameBufferStatus(); // Use by the composite+shade program double shininess=vol->GetProperty()->GetSpecularPower(); if(shininess>128.0) { shininess=128.0; // upper limit for the OpenGL shininess. } glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,static_cast(shininess)); glDisable(GL_COLOR_MATERIAL); // other mapper may have enable that. GLfloat values[4]; values[3]=1.0; values[0]=0.0; values[1]=values[0]; values[2]=values[0]; glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,values); values[0]=static_cast(vol->GetProperty()->GetAmbient()); values[1]=values[0]; values[2]=values[0]; glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,values); values[0]=static_cast(vol->GetProperty()->GetDiffuse()); values[1]=values[0]; values[2]=values[0]; glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,values); values[0]=static_cast(vol->GetProperty()->GetSpecular()); values[1]=values[0]; values[2]=values[0]; glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,values); // cout << "pingpong=" << this->PingPongFlag << endl; // To initialize the second color buffer vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront], 0); vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D, this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+1], 0); buffer[0] = vtkgl::COLOR_ATTACHMENT0_EXT; buffer[1] = vtkgl::COLOR_ATTACHMENT1_EXT; vtkgl::DrawBuffers(2,buffer); // cout << "check before setup" << endl; this->CheckFrameBufferStatus(); this->SetupRender(ren,vol); // restore in case of composite with no cropping or streaming. buffer[0] = vtkgl::COLOR_ATTACHMENT0_EXT; buffer[1] = GL_NONE; vtkgl::DrawBuffers(2,buffer); vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D,0,0); // cout << "check after color init" << endl; this->CheckFrameBufferStatus(); if(this->NumberOfCroppingRegions>1 && (this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MAXIMUM_INTENSITY_BLEND)) { // cout << "this->MaxValueFrameBuffer="<< this->MaxValueFrameBuffer <MaxValueFrameBuffer2="<< this->MaxValueFrameBuffer2 <MaxValueFrameBuffer,0); vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D, this->MaxValueFrameBuffer2,0); buffer[0] = vtkgl::COLOR_ATTACHMENT0_EXT; buffer[1] = vtkgl::COLOR_ATTACHMENT1_EXT; vtkgl::DrawBuffers(2,buffer); if(this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) { glClearColor(1.0, 0.0, 0.0, 0.0); } else { glClearColor(0.0, 0.0, 0.0, 0.0); // for MAXIMUM_INTENSITY_BLEND } // cout << "check before clear on max" << endl; this->CheckFrameBufferStatus(); glClear(GL_COLOR_BUFFER_BIT); } if(this->NumberOfCroppingRegions>1) { // color buffer target in the color attachement 0 vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront], 0); // color buffer input is on texture unit 4. vtkgl::ActiveTexture(vtkgl::TEXTURE4); glBindTexture(GL_TEXTURE_2D,this->TextureObjects[vtkMitkOpenGLGPUVolumeRayCastMapperTextureObjectFrameBufferLeftFront+1]); if(this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) { // max buffer target in the color attachment 1 vtkgl::FramebufferTexture2DEXT(vtkgl::FRAMEBUFFER_EXT, vtkgl::COLOR_ATTACHMENT0_EXT+1, GL_TEXTURE_2D, this->MaxValueFrameBuffer,0); // max buffer input is on texture unit 5. vtkgl::ActiveTexture(vtkgl::TEXTURE5); glBindTexture(GL_TEXTURE_2D,this->MaxValueFrameBuffer2); } vtkgl::ActiveTexture(vtkgl::TEXTURE0); } this->CheckFrameBufferStatus(); if(this->OpacityTables!=0 && this->OpacityTables->Vector.size()!=numberOfLevels) { delete this->OpacityTables; this->OpacityTables=0; } if(this->OpacityTables==0) { this->OpacityTables=new vtkOpacityTables(numberOfLevels); } // debug code // DO NOT REMOVE the following commented line // this->ValidateProgram(); glCullFace (GL_BACK); // otherwise, we are rendering back face to initialize the zbuffer. if(!this->GeneratingCanonicalView && this->ReportProgress) { // initialize the time to avoid a progress event at the beginning. this->LastProgressEventTime=vtkTimerLog::GetUniversalTime(); } this->PrintError("PreRender end"); } //----------------------------------------------------------------------------- // Compute how each axis of a cell is projected on the viewport in pixel. // This requires to have information about the camera and about the volume. // It set the value of IgnoreSampleDistancePerPixel to true in case of // degenerated case (axes aligned with the view). //----------------------------------------------------------------------------- double vtkMitkOpenGLGPUVolumeRayCastMapper::ComputeMinimalSampleDistancePerPixel( vtkRenderer *renderer, vtkVolume *volume) { // For each of the 3 directions of a cell, compute the step in z // (world coordinate, not eye/camera coordinate) // to go to the next pixel in x. // Same for the next pixel in y. // Keep the minimum of both zstep // Then keep the minimum for the 3 directions. // in case of either the numerator or the denominator of each ratio is 0. this->IgnoreSampleDistancePerPixel=true; double result=0.0; vtkMatrix4x4 *worldToDataset=volume->GetMatrix(); vtkCamera *camera=renderer->GetActiveCamera(); vtkMatrix4x4 *eyeToWorld=camera->GetViewTransformMatrix(); vtkMatrix4x4 *eyeToDataset=vtkMatrix4x4::New(); vtkMatrix4x4::Multiply4x4(eyeToWorld,worldToDataset,eyeToDataset); int usize; int vsize; renderer->GetTiledSize(&usize,&vsize); vtkMatrix4x4 *viewportToEye=camera->GetProjectionTransformMatrix( usize/static_cast(vsize),0.0,1.0); double volBounds[6]; this->GetInput()->GetBounds(volBounds); int dims[3]; this->GetInput()->GetDimensions(dims); double v0[4]; v0[0]=volBounds[0]; v0[1]=volBounds[2]; v0[2]=volBounds[4]; v0[3]=1.0; double w0[4]; eyeToDataset->MultiplyPoint(v0,w0); double z0; if(w0[3]!=0.0) { z0=w0[2]/w0[3]; } else { z0=0.0; vtkGenericWarningMacro( "eyeToWorld transformation has some projective component." ); } double p0[4]; viewportToEye->MultiplyPoint(w0,p0); p0[0]/=p0[3]; p0[1]/=p0[3]; p0[2]/=p0[3]; bool inFrustum=p0[0]>=-1.0 && p0[0]<=1.0 && p0[1]>=-1.0 && p0[1]<=1.0 && p0[2]>=-1.0 && p0[2]<=1.0; if(inFrustum) { int dim=0; while(dim<3) { double v1[4]; int coord=0; while(coord<3) { if(coord==dim) { v1[coord]=volBounds[2*coord+1]; } else { v1[coord]=volBounds[2*coord]; // same as v0[coord]; } ++coord; } v1[3]=1.0; double w1[4]; eyeToDataset->MultiplyPoint(v1,w1); double z1; if(w1[3]!=0.0) { z1=w1[2]/w1[3]; } else { z1=0.0; vtkGenericWarningMacro( "eyeToWorld transformation has some projective component." ); } double p1[4]; viewportToEye->MultiplyPoint(w1,p1); p1[0]/=p1[3]; p1[1]/=p1[3]; p1[2]/=p1[3]; inFrustum=p1[0]>=-1.0 && p1[0]<=1.0 && p1[1]>=-1.0 && p1[1]<=1.0 && p1[2]>=-1.0 && p1[2]<=1.0; if(inFrustum) { double dx=fabs(p1[0]-p0[0]); double dy=fabs(p1[1]-p0[1]); double dz=fabs(z1-z0); dz=dz/(dims[dim]-1); dx=dx/(dims[dim]-1)*usize; dy=dy/(dims[dim]-1)*vsize; if(dz!=0.0) { if(dx!=0.0) { double d=dz/dx; if(!this->IgnoreSampleDistancePerPixel) { if(result>d) { result=d; } } else { this->IgnoreSampleDistancePerPixel=false; result=d; } } if(dy!=0.0) { double d=dz/dy; if(!this->IgnoreSampleDistancePerPixel) { if(result>d) { result=d; } } else { this->IgnoreSampleDistancePerPixel=false; result=d; } } } } ++dim; } } eyeToDataset->Delete(); if(this->IgnoreSampleDistancePerPixel) { // cout<<"ignore SampleDistancePerPixel"<ValidateProgram(); this->PrintError("before render"); if(!this->Cropping) { this->RenderWholeVolume(ren,vol); } else { this->ClipCroppingRegionPlanes(); this->RenderRegions(ren,vol); } this->PrintError("after render"); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::PostRender( vtkRenderer *ren, int numberOfScalarComponents) { this->PrintError("PostRender1"); if(this->NumberOfCroppingRegions>1) { if(this->BlendMode==vtkVolumeMapper::MAXIMUM_INTENSITY_BLEND || this->BlendMode==vtkMitkGPUVolumeRayCastMapper::MINIMUM_INTENSITY_BLEND) { vtkgl::ActiveTexture( vtkgl::TEXTURE5 ); glBindTexture(GL_TEXTURE_2D,0); } if(this->LastRayCastMethod!=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP && this->LastRayCastMethod!=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIP) { vtkgl::ActiveTexture( vtkgl::TEXTURE4 ); glBindTexture(GL_TEXTURE_2D,0); } } // noisetexture vtkgl::ActiveTexture(vtkgl::TEXTURE6); glBindTexture(GL_TEXTURE_2D,0); // depthtexture vtkgl::ActiveTexture(vtkgl::TEXTURE3); glBindTexture(GL_TEXTURE_2D,0); // opacity vtkgl::ActiveTexture(vtkgl::TEXTURE2); glBindTexture(GL_TEXTURE_1D,0); if(numberOfScalarComponents==1) { vtkgl::ActiveTexture(vtkgl::TEXTURE1); glBindTexture(GL_TEXTURE_1D,0); } // mask, if any if(this->MaskInput!=0) { vtkgl::ActiveTexture(vtkgl::TEXTURE7); glBindTexture(vtkgl::TEXTURE_3D_EXT,0); } // back to active texture 0. vtkgl::ActiveTexture(vtkgl::TEXTURE0); glBindTexture(vtkgl::TEXTURE_3D_EXT,0); vtkgl::UseProgram(0); this->PrintError("after UseProgram(0)"); this->CleanupRender(); this->PrintError("after CleanupRender"); vtkgl::BindFramebufferEXT(vtkgl::FRAMEBUFFER_EXT, static_cast(this->SavedFrameBuffer)); this->SavedFrameBuffer=0; // Undo the viewport change we made to reduce resolution int size[2]; int lowerLeft[2]; ren->GetTiledSizeAndOrigin(size,size+1,lowerLeft,lowerLeft+1); glViewport(lowerLeft[0],lowerLeft[1], size[0], size[1]); glEnable( GL_SCISSOR_TEST ); glScissor(lowerLeft[0],lowerLeft[1], size[0], size[1]); // Render the texture to the screen - this copies the offscreen buffer // onto the screen as a texture mapped polygon this->RenderTextureToScreen(ren); this->PrintError("after RenderTextureToScreen"); glEnable(GL_DEPTH_TEST); glPopAttrib(); // restore the blending mode and function glFinish(); this->PrintError("PostRender2"); } //----------------------------------------------------------------------------- // The main render method called from the superclass //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer *ren, vtkVolume *vol) { // We've already checked that we have input vtkImageData *input = this->GetTransformedInput(); // Get the bounds of this data double bounds[6]; this->GetBounds(bounds); // Get the scalar range. First we have to get the scalars. double range[2]; vtkDataArray *scalars=this->GetScalars(input,this->ScalarMode, this->ArrayAccessMode, this->ArrayId,this->ArrayName, this->CellFlag); // How many components are there? int numberOfScalarComponents=scalars->GetNumberOfComponents(); // If it is just one, then get the range from the scalars if(numberOfScalarComponents==1) { // Warning: here, we ignore the blank cells. scalars->GetRange(range); } // If it is 3, then use the 4th component's range since that is // the component that will be passed through the scalar opacity // transfer function to look up opacity else { // Note that we've already checked data type and we know this is // unsigned char scalars->GetRange(range,3); } // The rendering work has been broken into 3 stages to support AMR // volume rendering in blocks. Here we are simply rendering the // whole volume as one block. Note that if the volume is too big // to fix into texture memory, it will be streamed through in the // RenderBlock method. this->PreRender(ren,vol,bounds,range,numberOfScalarComponents,1); if(!this->OpacityTables) this->PreRender(ren,vol,bounds,range,numberOfScalarComponents,1); if(this->LoadExtensionsSucceeded) { this->RenderBlock(ren,vol,0); this->PostRender(ren,numberOfScalarComponents); } // Let's just make sure no OpenGL errors occurred during this render this->PrintError("End GPU Render"); // If this isn't a canonical view render, then update the progress to // 1 because we are done. if (!this->GeneratingCanonicalView ) { double progress=1.0; this->InvokeEvent(vtkCommand::VolumeMapperRenderProgressEvent,&progress); ren->GetRenderWindow()->MakeCurrent(); } } //----------------------------------------------------------------------------- // Render a the whole volume. // \pre this->ProgramShader!=0 and is linked. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::RenderWholeVolume(vtkRenderer *ren, vtkVolume *vol) { double volBounds[6]; this->GetTransformedInput()->GetBounds(volBounds); this->RenderSubVolume(ren,volBounds,vol); } //----------------------------------------------------------------------------- // Sort regions from front to back. //----------------------------------------------------------------------------- class vtkRegionDistance2 { public: size_t Id; // 0<=Id<27 // square distance between camera center to region center: >=0 double Distance2; }; //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- extern "C" int vtkRegionComparisonFunction(const void *x, const void *y) { double dx=static_cast(x)->Distance2; double dy=static_cast(y)->Distance2; int result; if(dxdy) { result=1; } else { result=0; } } return result; } //----------------------------------------------------------------------------- // Render a subvolume. // \pre this->ProgramShader!=0 and is linked. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::RenderRegions(vtkRenderer *ren, vtkVolume *vol) { double bounds[27][6]; double distance2[27]; double camPos[4]; ren->GetActiveCamera()->GetPosition(camPos); double volBounds[6]; this->GetInput()->GetBounds(volBounds); // Pass camera through inverse volume matrix // so that we are in the same coordinate system vol->GetMatrix( this->InvVolumeMatrix ); camPos[3] = 1.0; this->InvVolumeMatrix->Invert(); this->InvVolumeMatrix->MultiplyPoint( camPos, camPos ); if ( camPos[3] ) { camPos[0] /= camPos[3]; camPos[1] /= camPos[3]; camPos[2] /= camPos[3]; } // These are the region limits for x (first four), y (next four) and // z (last four). The first region limit is the lower bound for // that axis, the next two are the region planes along that axis, and // the final one in the upper bound for that axis. double limit[12]; size_t i; for ( i = 0; i < 3; i++ ) { limit[i*4 ] = volBounds[i*2]; limit[i*4+1] = this->ClippedCroppingRegionPlanes[i*2]; limit[i*4+2] = this->ClippedCroppingRegionPlanes[i*2+1]; limit[i*4+3] = volBounds[i*2+1]; } // For each of the 27 possible regions, find out if it is enabled, // and if so, compute the bounds and the distance from the camera // to the center of the region. size_t numRegions = 0; size_t region; for ( region = 0; region < 27; region++ ) { int regionFlag = 1<CroppingRegionFlags & regionFlag ) { // what is the coordinate in the 3x3x3 grid size_t loc[3]; loc[0] = region%3; loc[1] = (region/3)%3; loc[2] = (region/9)%3; // make sure the cropping region is not empty NEW // otherwise, we skip the region. if((limit[loc[0]]!=limit[loc[0]+1]) && (limit[loc[1]+4]!=limit[loc[1]+5]) && (limit[loc[2]+8]!=limit[loc[2]+9])) { // compute the bounds and center double center[3]; for ( i = 0; i < 3; i++ ) { bounds[numRegions][i*2 ] = limit[4*i+loc[i]]; bounds[numRegions][i*2+1] = limit[4*i+loc[i]+1]; center[i]=(bounds[numRegions][i*2]+bounds[numRegions][i*2+1])*0.5; } // compute the distance squared to the center distance2[numRegions] = (camPos[0]-center[0])*(camPos[0]-center[0]) + (camPos[1]-center[1])*(camPos[1]-center[1]) + (camPos[2]-center[2])*(camPos[2]-center[2]); // we've added one region numRegions++; } } } vtkRegionDistance2 regions[27]; i=0; while(iNumberOfCroppingRegions>=0); } //----------------------------------------------------------------------------- // slabsDataSet are position of the slabs in dataset coordinates. // slabsPoints are position of the slabs in points coordinates. // For instance, slabsDataSet[0] is the position of the plane bounding the slab // on the left of x axis of the dataset. slabsPoints[0]=0.3 means that // this plane lies between point 0 and point 1 along the x-axis. // There is no clamping/clipping according to the dataset bounds so, // slabsPoints can be negative or excess the number of points along the // corresponding axis. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::SlabsFromDatasetToIndex( double slabsDataSet[6], double slabsPoints[6]) { double *spacing=this->GetInput()->GetSpacing(); double origin[3]; // take spacing sign into account double *bds = this->GetInput()->GetBounds(); origin[0] = bds[0]; origin[1] = bds[2]; origin[2] = bds[4]; int i=0; while(i<6) { slabsPoints[i]=(slabsDataSet[i] - origin[i/2]) / spacing[i/2]; ++i; } } //----------------------------------------------------------------------------- // slabsDataSet are position of the slabs in dataset coordinates. // slabsPoints are position of the slabs in points coordinates. // For instance, slabsDataSet[0] is the position of the plane bounding the slab // on the left of x axis of the dataset. slabsPoints[0]=0.3 means that // this plane lies between point 0 and point 1 along the x-axis. // There is no clamping/clipping according to the dataset bounds so, // slabsPoints can be negative or excess the number of points along the // corresponding axis. //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::SlabsFromIndexToDataset( double slabsPoints[6], double slabsDataSet[6]) { double *spacing=this->GetInput()->GetSpacing(); double origin[3]; // take spacing sign into account double *bds = this->GetInput()->GetBounds(); origin[0] = bds[0]; origin[1] = bds[2]; origin[2] = bds[4]; int i=0; while(i<6) { slabsDataSet[i]=slabsPoints[i]*spacing[i/2]+origin[i/2]; ++i; } } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- class vtkStreamBlock { public: double Bounds[6]; double Extent[6]; }; //----------------------------------------------------------------------------- // Render a subvolume. bounds are in world coordinates. // \pre this->ProgramShader!=0 and is linked. //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::RenderSubVolume(vtkRenderer *ren, double bounds[6], vtkVolume *volume) { // Time to load scalar field size_t i; int wholeTextureExtent[6]; this->GetTransformedInput()->GetExtent(wholeTextureExtent); if(this->CellFlag) { i=1; while(i<6) { wholeTextureExtent[i]--; i+=2; } } // 1. Found out the extent of the subvolume double realExtent[6]; int subvolumeTextureExtent[6]; this->SlabsFromDatasetToIndex(bounds,realExtent); if(this->CellFlag) // 3D texture are celldata { // texture extents are expressed in cells in this case i=0; while(i<6) { subvolumeTextureExtent[i]=vtkMath::Floor(realExtent[i]-0.5); ++i; subvolumeTextureExtent[i]=vtkMath::Floor(realExtent[i]-0.5)+1; ++i; } } else { // texture extents are expressed in points in this case i=0; while(i<6) { subvolumeTextureExtent[i]=vtkMath::Floor(realExtent[i]); ++i; subvolumeTextureExtent[i]=vtkMath::Floor(realExtent[i])+1; // used to not have +1 ++i; } } i=0; while(i<6) { assert("check: wholeTextureExtent" && wholeTextureExtent[i]==0); if(subvolumeTextureExtent[i]wholeTextureExtent[i]) { subvolumeTextureExtent[i]=wholeTextureExtent[i]; } ++i; } assert("check: subvolume_inside_wholevolume" && subvolumeTextureExtent[0]>=wholeTextureExtent[0] && subvolumeTextureExtent[1]<=wholeTextureExtent[1] && subvolumeTextureExtent[2]>=wholeTextureExtent[2] && subvolumeTextureExtent[3]<=wholeTextureExtent[3] && subvolumeTextureExtent[4]>=wholeTextureExtent[4] && subvolumeTextureExtent[5]<=wholeTextureExtent[5]); // 2. Is this subvolume already on the GPU? // ie are the extent of the subvolume inside the loaded extent? // Find the texture (and mask). vtkstd::map::iterator it= this->ScalarsTextures->Map.find(this->GetTransformedInput()); vtkKWScalarField *texture; if(it==this->ScalarsTextures->Map.end()) { texture=0; } else { texture=(*it).second; } vtkKWMask *mask=0; if(this->MaskInput!=0) { vtkstd::map::iterator it2= this->MaskTextures->Map.find(this->MaskInput); if(it2==this->MaskTextures->Map.end()) { mask=0; } else { mask=(*it2).second; } } int loaded = texture!=0 && texture->IsLoaded() && this->GetTransformedInput()->GetMTime()<=texture->GetBuildTime() && (this->GetMaskInput() ? this->GetMaskInput()->GetMTime() <= texture->GetBuildTime() : true) && texture->GetLoadedCellFlag()==this->CellFlag; vtkIdType *loadedExtent; if(loaded) { loadedExtent=texture->GetLoadedExtent(); i=0; while(loaded && i<6) { loaded=loaded && loadedExtent[i]<=subvolumeTextureExtent[i]; ++i; loaded=loaded && loadedExtent[i]>=subvolumeTextureExtent[i]; ++i; } } if(loaded) { this->CurrentScalar=texture; vtkgl::ActiveTexture(vtkgl::TEXTURE0); this->CurrentScalar->Bind(); vtkgl::ActiveTexture(vtkgl::TEXTURE7); this->CurrentMask=mask; if(this->CurrentMask!=0) { this->CurrentMask->Bind(); } } if(!loaded) { // 3. Not loaded: try to load the whole dataset if(!this->LoadScalarField(this->GetTransformedInput(),this->MaskInput,wholeTextureExtent,volume)) { // 4. loading the whole dataset failed: try to load the subvolume if(!this->LoadScalarField(this->GetTransformedInput(),this->MaskInput, subvolumeTextureExtent, volume)) { // 5. loading the subvolume failed: stream the subvolume // 5.1 do zslabs first, if too large then cut with x or y with the // largest dimension. order of zlabs depends on sign of spacing[2] int streamTextureExtent[6]; i=0; while(i<6) { streamTextureExtent[i]=subvolumeTextureExtent[i]; ++i; } unsigned int internalFormat; unsigned int format; unsigned int type; int componentSize; this->GetTextureFormat(this->GetInput(),&internalFormat,&format,&type, &componentSize); // Enough memory? int originalTextureSize[3]; int textureSize[3]; i=0; while(i<3) { textureSize[i]=subvolumeTextureExtent[2*i+1]-subvolumeTextureExtent[2*i]+1; originalTextureSize[i]=textureSize[i]; ++i; } // Make sure loading did not fail because of theorical limits GLint width; glGetIntegerv(vtkgl::MAX_3D_TEXTURE_SIZE,&width); int clippedXY=0; int clippedZ=0; if(textureSize[0]>width) { textureSize[0]=width; clippedXY=1; } if(textureSize[1]>width) { textureSize[1]=width; clippedXY=1; } if(textureSize[2]>width) { textureSize[2]=width; clippedZ=1; } int minSize; if(this->CellFlag) { minSize=1; } else { minSize=2; } if(clippedXY) { // We cannot expect to first divide as z-slabs because it is already // clipped in another dimension. From now, just divide in the largest // dimension. bool foundSize=false; while(!foundSize && textureSize[0]>=minSize && textureSize[1]>=minSize) { foundSize=this->TestLoadingScalar(internalFormat,format,type, textureSize,componentSize); if(!foundSize) { int maxDim=0; if(textureSize[1]>textureSize[0]) { maxDim=1; } if(textureSize[2]>textureSize[maxDim]) { maxDim=2; } textureSize[maxDim]>>=1; // /=2 } } } else { // we are in cropping mode, it will be slow anyway. the case we want // to optimize is stream the all scalar field. With that in mine, // it is better to first try to send z-slabs. If even a minimal // z-slab is too big, we have to divide by x or y dimensions. In // this case, it will be slow and we can choose to keep blocks as // square as possible by dividing by the largest dimension at each // iteration. if(!clippedZ) { // we start by subdividing only if we did not already clipped // the z dimension according to the theorical limits. textureSize[2]>>=1; // /=2 } bool foundSize=false; while(!foundSize && textureSize[2]>=minSize) { foundSize=this->TestLoadingScalar(internalFormat,format,type, textureSize,componentSize); if(!foundSize) { textureSize[2]>>=1; // /=2 } } if(!foundSize) { textureSize[2]=minSize; if(textureSize[0]>textureSize[1]) { textureSize[0]>>=1; // /=2 } else { textureSize[1]>>=1; // /=2 } while(!foundSize && textureSize[0]>=minSize && textureSize[1]>=minSize) { foundSize=this->TestLoadingScalar(internalFormat,format,type, textureSize,componentSize); if(!foundSize) { if(textureSize[0]>textureSize[1]) { textureSize[0]>>=1; // /=2 } else { textureSize[1]>>=1; // /=2 } } } } if(!foundSize) { vtkErrorMacro( <<"No memory left on the GPU even for a minimal block."); return 1; // abort } } // except for the last bound. // front to back ordering // Pass camera through inverse volume matrix // so that we are in the same coordinate system double camPos[4]; vtkCamera *cam = ren->GetActiveCamera(); cam->GetPosition(camPos); volume->GetMatrix( this->InvVolumeMatrix ); camPos[3] = 1.0; this->InvVolumeMatrix->Invert(); this->InvVolumeMatrix->MultiplyPoint( camPos, camPos ); if ( camPos[3] ) { camPos[0] /= camPos[3]; camPos[1] /= camPos[3]; camPos[2] /= camPos[3]; } // 5.2 iterate of each stream of the subvolume and render it: // point scalar: on the first block, the first point is not shared // blockExtent is always expressed in point, not in texture // extent. size_t remainder[3]; i=0; while(i<3) { remainder[i]=static_cast( (originalTextureSize[i]-textureSize[i])%(textureSize[i]-1)); if(remainder[i]>0) { remainder[i]=1; } ++i; } size_t counts[3]; counts[0]=static_cast((originalTextureSize[0]-textureSize[0]) /(textureSize[0]-1)); counts[0]+=remainder[0]+1; counts[1]=static_cast((originalTextureSize[1]-textureSize[1]) /(textureSize[1]-1)); counts[1]+=remainder[1]+1; counts[2]=static_cast((originalTextureSize[2]-textureSize[2]) /(textureSize[2]-1)); counts[2]+=remainder[2]+1; size_t count=counts[0]*counts[1]*counts[2]; double blockExtent[6]; vtkStreamBlock *blocks=new vtkStreamBlock[count]; vtkRegionDistance2 *sortedBlocks=new vtkRegionDistance2[count]; // iterate over z,y,x size_t blockId=0; size_t zIndex=0; blockExtent[4]=realExtent[4]; blockExtent[5]=vtkMath::Floor(blockExtent[4])+textureSize[2]; if(!this->CellFlag) { blockExtent[5]--; } if(blockExtent[5]>realExtent[5]) { blockExtent[5]=realExtent[5]; } while(zIndexCellFlag) { blockExtent[3]--; } if(blockExtent[3]>realExtent[3]) { blockExtent[3]=realExtent[3]; } size_t yIndex=0; while(yIndexCellFlag) { blockExtent[1]--; } if(blockExtent[1]>realExtent[1]) { blockExtent[1]=realExtent[1]; } size_t xIndex=0; while(xIndexSlabsFromIndexToDataset(blockExtent,blockBounds); // compute the bounds and center double center[3]; i=0; while(i<3) { center[i]=(blockBounds[i*2]+blockBounds[i*2+1])*0.5; ++i; } // compute the distance squared to the center double distance2=(camPos[0]-center[0])*(camPos[0]-center[0])+ (camPos[1]-center[1])*(camPos[1]-center[1]) + (camPos[2]-center[2])*(camPos[2]-center[2]); i=0; while(i<6) { blocks[blockId].Bounds[i]=blockBounds[i]; blocks[blockId].Extent[i]=blockExtent[i]; ++i; } sortedBlocks[blockId].Id=blockId; sortedBlocks[blockId].Distance2=distance2; ++blockId; blockExtent[0]=blockExtent[1]; blockExtent[1]=blockExtent[0]+textureSize[0]; if(!this->CellFlag) { blockExtent[1]--; } if(blockExtent[1]>realExtent[1]) { blockExtent[1]=realExtent[1]; } ++xIndex; } // while x blockExtent[2]=blockExtent[3]; blockExtent[3]=blockExtent[2]+textureSize[1]; if(!this->CellFlag) { blockExtent[3]--; } if(blockExtent[3]>realExtent[3]) { blockExtent[3]=realExtent[3]; } ++yIndex; } // while y blockExtent[4]=blockExtent[5]; blockExtent[5]=blockExtent[4]+textureSize[2]; if(!this->CellFlag) { blockExtent[5]--; } if(blockExtent[5]>realExtent[5]) { blockExtent[5]=realExtent[5]; } ++zIndex; } // while z assert("check: valid_number_of_blocks" && blockId==count); qsort(sortedBlocks,static_cast(count), sizeof(vtkRegionDistance2), vtkRegionComparisonFunction); // loop over all blocks we need to render i=0; int abort=0; while(!abort && i < count) // 1) //count) { size_t k=sortedBlocks[i].Id; int blockTextureExtent[6]; int j; if(this->CellFlag) // 3D texture are celldata { // texture extents are expressed in cells in this case j=0; while(j<6) { blockTextureExtent[j]=vtkMath::Floor(blocks[k].Extent[j]); ++j; } } else { // texture extents are expressed in points in this case j=0; while(j<6) { blockTextureExtent[j]=vtkMath::Floor(blocks[k].Extent[j]); ++j; blockTextureExtent[j]=vtkMath::Floor(blocks[k].Extent[j]); if(blockTextureExtent[j]LoadScalarField(this->GetInput(),this->MaskInput, blockTextureExtent, volume)) { cout<<"Loading the streamed block FAILED!!!!!"<CurrentScalar->GetLoadedExtent(); float lowBounds[3]; float highBounds[3]; if(!this->CurrentScalar->GetLoadedCellFlag()) // points { j=0; while(j<3) { double delta= static_cast(loadedExtent[j*2+1]-loadedExtent[j*2]); lowBounds[j]=static_cast((blocks[k].Extent[j*2]-static_cast(loadedExtent[j*2]))/delta); highBounds[j]=static_cast((blocks[k].Extent[j*2+1]-static_cast(loadedExtent[j*2]))/delta); ++j; } } else // cells { j=0; while(j<3) { double delta= static_cast(loadedExtent[j*2+1]-loadedExtent[j*2]); lowBounds[j]=static_cast((blocks[k].Extent[j*2]-0.5-static_cast(loadedExtent[j*2]))/delta); highBounds[j]=static_cast((blocks[k].Extent[j*2+1]-0.5-static_cast(loadedExtent[j*2]))/delta); ++j; } } // bounds have to be normalized. There are used in the shader // as bounds to a value used to sample a texture. assert("check: positive_low_bounds0" && lowBounds[0]>=0.0); assert("check: positive_low_bounds1" && lowBounds[1]>=0.0); assert("check: positive_low_bounds2" && lowBounds[2]>=0.0); assert("check: increasing_bounds0" && lowBounds[0]<=highBounds[0]); assert("check: increasing_bounds1" && lowBounds[1]<=highBounds[1]); assert("check: increasing_bounds2" && lowBounds[2]<=highBounds[2]); assert("check: high_bounds0_less_than1" && highBounds[0]<=1.0); assert("check: high_bounds1_less_than1" && highBounds[1]<=1.0); assert("check: high_bounds2_less_than1" && highBounds[2]<=1.0); GLint lb; lb=vtkgl::GetUniformLocation(static_cast(this->ProgramShader), "lowBounds"); this->PrintError("get uniform low bounds"); if(lb!=-1) { vtkgl::Uniform3f(lb, lowBounds[0],lowBounds[1],lowBounds[2]); this->PrintError("set uniform low bounds"); } else { vtkErrorMacro(<<" lowBounds is not a uniform variable."); } GLint hb; hb=vtkgl::GetUniformLocation(static_cast(this->ProgramShader), "highBounds"); this->PrintError("get uniform high bounds"); if(hb!=-1) { vtkgl::Uniform3f(hb, highBounds[0],highBounds[1],highBounds[2]); this->PrintError("set uniform high bounds"); } else { vtkErrorMacro(<<" highBounds is not a uniform variable."); } this->PrintError("uniform low/high bounds block"); // other sub-volume rendering code this->LoadProjectionParameters(ren,volume); this->ClipBoundingBox(ren,blocks[k].Bounds,volume); abort=this->RenderClippedBoundingBox(1,i,count,ren->GetRenderWindow()); if (!abort) { this->CopyFBOToTexture(); } this->PrintError("render clipped block 1"); ++i; } delete[] blocks; delete[] sortedBlocks; return abort; } } } loadedExtent=this->CurrentScalar->GetLoadedExtent(); // low bounds and high bounds are in texture coordinates. float lowBounds[3]; float highBounds[3]; if(!this->CurrentScalar->GetLoadedCellFlag()) // points { i=0; while(i<3) { double delta= static_cast(loadedExtent[i*2+1]-loadedExtent[i*2]+1); lowBounds[i]=static_cast((realExtent[i*2]+0.5-static_cast(loadedExtent[i*2]))/delta); highBounds[i]=static_cast((realExtent[i*2+1]+0.5-static_cast(loadedExtent[i*2]))/delta); ++i; } } else // cells { i=0; while(i<3) { double delta= static_cast(loadedExtent[i*2+1]-loadedExtent[i*2]+1); // this->LoadedExtent[i*2]==0, texcoord starts at 0, if realExtent==0 // otherwise, texcoord start at 1/2N // this->LoadedExtent[i*2]==wholeTextureExtent[i*2+1], texcoord stops at 1, if realExtent==wholeTextureExtent[i*2+1]+1 // otherwise it stop at 1-1/2N // N is the number of texels in the loadedtexture not the number of // texels in the whole texture. lowBounds[i]=static_cast((realExtent[i*2]-static_cast(loadedExtent[i*2]))/delta); highBounds[i]=static_cast((realExtent[i*2+1]-static_cast(loadedExtent[i*2]))/delta); ++i; } } assert("check: positive_low_bounds0" && lowBounds[0]>=0.0); assert("check: positive_low_bounds1" && lowBounds[1]>=0.0); assert("check: positive_low_bounds2" && lowBounds[2]>=0.0); assert("check: increasing_bounds0" && lowBounds[0]<=highBounds[0]); assert("check: increasing_bounds1" && lowBounds[1]<=highBounds[1]); assert("check: increasing_bounds2" && lowBounds[2]<=highBounds[2]); assert("check: high_bounds0_less_than1" && highBounds[0]<=1.0); assert("check: high_bounds1_less_than1" && highBounds[1]<=1.0); assert("check: high_bounds2_less_than1" && highBounds[2]<=1.0); GLint lb; lb=vtkgl::GetUniformLocation(static_cast(this->ProgramShader), "lowBounds"); this->PrintError("get uniform low bounds"); if(lb!=-1) { vtkgl::Uniform3f(lb, lowBounds[0],lowBounds[1],lowBounds[2]); this->PrintError("set uniform low bounds"); } else { vtkErrorMacro(<<" lowBounds is not a uniform variable."); } GLint hb; hb=vtkgl::GetUniformLocation(static_cast(this->ProgramShader), "highBounds"); this->PrintError("get uniform high bounds"); if(hb!=-1) { vtkgl::Uniform3f(hb, highBounds[0],highBounds[1],highBounds[2]); this->PrintError("set uniform high bounds"); } else { vtkErrorMacro(<<" highBounds is not a uniform variable."); } this->PrintError("uniform low/high bounds"); // other sub-volume rendering code this->LoadProjectionParameters(ren,volume); this->ClipBoundingBox(ren,bounds,volume); int abort=this->RenderClippedBoundingBox(1,0,1,ren->GetRenderWindow()); if (!abort) { this->CopyFBOToTexture(); } this->PrintError("render clipped 1"); return abort; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::LoadProjectionParameters( vtkRenderer *ren, vtkVolume *vol) { vtkMatrix4x4 *worldToDataset=vol->GetMatrix(); vtkMatrix4x4 *datasetToWorld=this->TempMatrix[0]; vtkMatrix4x4::Invert(worldToDataset,datasetToWorld); double *bounds=this->CurrentScalar->GetLoadedBounds(); double dx=bounds[1]-bounds[0]; double dy=bounds[3]-bounds[2]; double dz=bounds[5]-bounds[4]; // worldToTexture matrix is needed // Compute change-of-coordinate matrix from world space to texture space. vtkMatrix4x4 *worldToTexture=this->TempMatrix[2]; vtkMatrix4x4 *datasetToTexture=this->TempMatrix[1]; // Set the matrix datasetToTexture->Zero(); datasetToTexture->SetElement(0,0,dx); datasetToTexture->SetElement(1,1,dy); datasetToTexture->SetElement(2,2,dz); datasetToTexture->SetElement(3,3,1.0); datasetToTexture->SetElement(0,3,bounds[0]); datasetToTexture->SetElement(1,3,bounds[2]); datasetToTexture->SetElement(2,3,bounds[4]); // worldToTexture=worldToDataSet*dataSetToTexture vtkMatrix4x4::Multiply4x4(worldToDataset,datasetToTexture,worldToTexture); // NEW int parallelProjection=ren->GetActiveCamera()->GetParallelProjection(); // cout << "actualSampleDistance=" << this->ActualSampleDistance << endl; if(parallelProjection) { // Unit vector of the direction of projection in world space. double dirWorld[4]; double dir[4]; ren->GetActiveCamera()->GetDirectionOfProjection(dirWorld); dirWorld[3]=0.0; // direction in dataset space. datasetToWorld->MultiplyPoint(dirWorld,dir); // incremental vector: // direction in texture space times sample distance in world space. dir[0]=dir[0]*this->ActualSampleDistance/dx; dir[1]=dir[1]*this->ActualSampleDistance/dy; dir[2]=dir[2]*this->ActualSampleDistance/dz; GLint rayDir; rayDir=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"parallelRayDirection"); if(rayDir!=-1) { vtkgl::Uniform3f(rayDir,static_cast(dir[0]), static_cast(dir[1]), static_cast(dir[2])); } else { vtkErrorMacro(<<"parallelRayDirection is not a uniform variable."); } //cout<<"rayDir="<GetActiveCamera()->GetPosition(cameraPosWorld); cameraPosWorld[3]=1.0; // we use homogeneous coordinates. datasetToWorld->MultiplyPoint(cameraPosWorld,cameraPosDataset); // From homogeneous to cartesian coordinates. if(cameraPosDataset[3]!=1.0) { double ratio=1/cameraPosDataset[3]; cameraPosDataset[0]*=ratio; cameraPosDataset[1]*=ratio; cameraPosDataset[2]*=ratio; } cameraPosTexture[0] = (cameraPosDataset[0]-bounds[0])/dx; cameraPosTexture[1] = (cameraPosDataset[1]-bounds[2])/dy; cameraPosTexture[2] = (cameraPosDataset[2]-bounds[4])/dz; // Only make sense for the vectorial part of the homogeneous matrix. // coefMatrix=transposeWorldToTexture*worldToTexture // we re-cycle the datasetToWorld pointer with a different name vtkMatrix4x4 *transposeWorldToTexture=this->TempMatrix[1]; // transposeWorldToTexture={^t}worldToTexture vtkMatrix4x4::Transpose(worldToTexture,transposeWorldToTexture); vtkMatrix4x4 *coefMatrix=this->TempMatrix[1]; vtkMatrix4x4::Multiply4x4(transposeWorldToTexture,worldToTexture, coefMatrix); GLint uCameraPosition; uCameraPosition=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"cameraPosition"); if(uCameraPosition!=-1) { vtkgl::Uniform3f(uCameraPosition, static_cast(cameraPosTexture[0]), static_cast(cameraPosTexture[1]), static_cast(cameraPosTexture[2])); } else { vtkErrorMacro(<<"cameraPosition is not a uniform variable."); } GLint uSampleDistance; uSampleDistance=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"sampleDistance"); if(uSampleDistance!=-1) { vtkgl::Uniform1f(uSampleDistance,this->ActualSampleDistance); } else { vtkErrorMacro(<<"sampleDistance is not a uniform variable."); } GLint uMatrix1; uMatrix1=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"matrix1"); if(uMatrix1!=-1) { vtkgl::Uniform3f(uMatrix1, static_cast(coefMatrix->GetElement(0,0)), static_cast(coefMatrix->GetElement(1,1)), static_cast(coefMatrix->GetElement(2,2))); } else { vtkErrorMacro(<<"matrix1 is not a uniform variable."); } GLint uMatrix2; uMatrix2=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"matrix2"); if(uMatrix2!=-1) { vtkgl::Uniform3f(uMatrix2, static_cast(2*coefMatrix->GetElement(0,1)), static_cast(2*coefMatrix->GetElement(1,2)), static_cast(2*coefMatrix->GetElement(0,2))); } else { vtkErrorMacro(<<"matrix2 is not a uniform variable."); } } this->PrintError("after uniforms for projection"); // Change-of-coordinate matrix from Eye space to texture space. vtkMatrix4x4 *eyeToTexture=this->TempMatrix[1]; vtkMatrix4x4 *eyeToWorld=ren->GetActiveCamera()->GetViewTransformMatrix(); vtkMatrix4x4::Multiply4x4(eyeToWorld,worldToTexture,eyeToTexture); GLfloat matrix[16];// used sometimes as 3x3, sometimes as 4x4. double *raw=eyeToTexture->Element[0]; int index; int column; int row; int shadeMethod=this->LastShade; if(shadeMethod==vtkMitkOpenGLGPUVolumeRayCastMapperShadeYes) { index=0; column=0; while(column<3) { row=0; while(row<3) { // cout << "index=" << index << " row*4+column=" << row*4+column << endl; matrix[index]=static_cast(raw[row*4+column]); ++index; ++row; } ++column; } GLint uEyeToTexture3; uEyeToTexture3=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"eyeToTexture3"); this->PrintError("after getUniform eyeToTexture3"); if(uEyeToTexture3!=-1) { vtkgl::UniformMatrix3fv(uEyeToTexture3,1,GL_FALSE,matrix); } else { vtkErrorMacro(<<"eyeToTexture3 is not a uniform variable."); } this->PrintError("after Uniform eyeToTexture3"); index=0; column=0; while(column<4) { row=0; while(row<4) { // cout << "index=" << index << " row*4+column=" << row*4+column << endl; matrix[index]=static_cast(raw[row*4+column]); ++index; ++row; } ++column; } GLint uEyeToTexture4; uEyeToTexture4=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"eyeToTexture4"); if(uEyeToTexture4!=-1) { vtkgl::UniformMatrix4fv(uEyeToTexture4,1,GL_FALSE,matrix); } else { vtkErrorMacro(<<"eyeToTexture4 is not a uniform variable."); } } eyeToTexture->Invert(); index=0; column=0; while(column<4) { row=0; while(row<4) { // cout << "index=" << index << " row*4+column=" << row*4+column << endl; matrix[index]=static_cast(raw[row*4+column]); ++index; ++row; } ++column; } this->PrintError("before GetUniformLocation TextureToEye"); GLint uTextureToEye; uTextureToEye=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"textureToEye"); this->PrintError("after GetUniformLocation TextureToEye"); if(uTextureToEye!=-1) { vtkgl::UniformMatrix4fv(uTextureToEye,1,GL_FALSE,matrix); } else { vtkErrorMacro(<<"textureToEye is not a uniform variable."); } this->PrintError("after UniformMatrxix TextureToEye"); if(shadeMethod==vtkMitkOpenGLGPUVolumeRayCastMapperShadeYes) { eyeToTexture->Transpose(); index=0; column=0; while(column<3) { row=0; while(row<3) { // cout << "index=" << index << " row*4+column=" << row*4+column << endl; matrix[index]=static_cast(raw[row*4+column]); ++index; ++row; } ++column; } GLint uTranposeTextureToEye; uTranposeTextureToEye=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"transposeTextureToEye"); if(uTranposeTextureToEye!=-1) { vtkgl::UniformMatrix3fv(uTranposeTextureToEye,1,GL_FALSE,matrix); } else { vtkErrorMacro(<<"transposeTextureToEye is not a uniform variable."); } float cellScale[3]; // 1/(2*Step) float cellStep[3]; // Step vtkIdType *loadedExtent=this->CurrentScalar->GetLoadedExtent(); cellScale[0]=static_cast(static_cast( loadedExtent[1]-loadedExtent[0])*0.5); cellScale[1]=static_cast(static_cast( loadedExtent[3]-loadedExtent[2])*0.5); cellScale[2]=static_cast(static_cast( loadedExtent[5]-loadedExtent[4])*0.5); cellStep[0]=static_cast(1.0/static_cast( loadedExtent[1]-loadedExtent[0])); cellStep[1]=static_cast(1.0/static_cast( loadedExtent[3]-loadedExtent[2])); cellStep[2]=static_cast(1.0/static_cast( loadedExtent[5]-loadedExtent[4])); GLint uCellScale; uCellScale=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"cellScale"); if(uCellScale!=-1) { vtkgl::Uniform3f(uCellScale,cellScale[0],cellScale[1],cellScale[2]); } else { vtkErrorMacro(<<"error: cellScale is not a uniform variable."); } GLint uCellStep; uCellStep=vtkgl::GetUniformLocation( static_cast(this->ProgramShader),"cellStep"); if(uCellStep!=-1) { vtkgl::Uniform3f(uCellStep,cellStep[0],cellStep[1],cellStep[2]); } else { vtkErrorMacro(<<"error: cellStep is not a uniform variable."); } } } //----------------------------------------------------------------------------- // Concatenate the header string, projection type code and method to the // final fragment code in this->FragmentCode. // \pre valid_raycastMethod: raycastMethod>= // vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP && // raycastMethod<=vtkMitkOpenGLGPUVolumeRayCastMapperMethodMinIPFourDependent //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::BuildProgram(int parallelProjection, int raycastMethod, int shadeMethod, int componentMethod) { assert("pre: valid_raycastMethod" && raycastMethod>= vtkMitkOpenGLGPUVolumeRayCastMapperMethodMIP && raycastMethod<=vtkMitkOpenGLGPUVolumeRayCastMapperMethodCompositeMask); GLuint fs; // cout<<"projection="<ProgramShader, vtkgl::INFO_LOG_LENGTH,¶ms); if(params>0) { char *buffer=new char[params]; vtkgl::GetProgramInfoLog(this->ProgramShader,params,0,buffer); cout<<"validation log: "<GetEnabledString(glIsEnabled(GL_LIGHTING))<GetEnabledString(glIsEnabled(GL_LIGHTING))<(value); cout<<"active texture is "<<(activeTexture-vtkgl::TEXTURE0)<(value); cout<<"light\t| status\t| ambient\t| diffuse\t| specular\t| position\t| spot direction\t| spot exponent\t| spot cutoff\t| k0\t| k1\t| k2"<=0 // \post valid_result: result>=x //----------------------------------------------------------------------------- int vtkMitkOpenGLGPUVolumeRayCastMapper::PowerOfTwoGreaterOrEqual(int x) { assert("pre: positive_x" && x>=0); int result=1; while(result=x); return result; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::UpdateNoiseTexture() { if(this->NoiseTextureId==0) { GLuint noiseTextureObject; glGenTextures(1,&noiseTextureObject); this->NoiseTextureId=static_cast(noiseTextureObject); vtkgl::ActiveTexture(vtkgl::TEXTURE6); glBindTexture(GL_TEXTURE_2D,noiseTextureObject); GLsizei size=128; // 1024; // Power of two value GLint maxSize; const float factor=0.1f; // const float factor=1.0f; const float amplitude=0.5f*factor; // something positive. // amplitude=0.5. noise between -0.5 +0.5. add some +0.5 shift. glGetIntegerv(GL_MAX_TEXTURE_SIZE,&maxSize); if(size>maxSize) { size=maxSize; } if(this->NoiseTexture!=0 && this->NoiseTextureSize!=size) { delete[] this->NoiseTexture; this->NoiseTexture=0; } if(this->NoiseTexture==0) { this->NoiseTexture=new float[size*size]; this->NoiseTextureSize=size; vtkPerlinNoise *noiseGenerator=vtkPerlinNoise::New(); noiseGenerator->SetFrequency(size,1.0,1.0); noiseGenerator->SetPhase(0.0,0.0,0.0); noiseGenerator->SetAmplitude(amplitude); int j=0; while(jNoiseTexture[j*size+i]=0.0; //amplitude+static_cast(noiseGenerator->EvaluateFunction(i,j,0.0)); ++i; } ++j; } noiseGenerator->Delete(); } glTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE,size,size,0,GL_RED,GL_FLOAT, this->NoiseTexture); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); GLfloat borderColor[4]={0.0,0.0,0.0,0.0}; glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR,borderColor); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); vtkgl::ActiveTexture(vtkgl::TEXTURE0); } } // ---------------------------------------------------------------------------- // Description: // Return how much the dataset has to be reduced in each dimension to // fit on the GPU. If the value is 1.0, there is no need to reduce the // dataset. // \pre the calling thread has a current OpenGL context. // \pre mapper_supported: IsRenderSupported(renderer->GetRenderWindow(),0) // The computation is based on hardware limits (3D texture indexable size) // and MaxMemoryInBytes. // \post valid_i_ratio: ratio[0]>0 && ratio[0]<=1.0 // \post valid_j_ratio: ratio[1]>0 && ratio[1]<=1.0 // \post valid_k_ratio: ratio[2]>0 && ratio[2]<=1.0 void vtkMitkOpenGLGPUVolumeRayCastMapper::GetReductionRatio(double ratio[3]) { // Compute texture size int i; int wholeTextureExtent[6]; this->GetInput()->GetExtent(wholeTextureExtent); if(this->CellFlag) // if we deal with cell data { i=1; while(i<6) { wholeTextureExtent[i]--; i+=2; } } // Indexable hardware limits GLint maxSize; glGetIntegerv(vtkgl::MAX_3D_TEXTURE_SIZE,&maxSize); vtkIdType rTextureSize[3]; double dMaxSize=static_cast(maxSize); i=0; while(i<3) { double textureSize=wholeTextureExtent[2*i+1]-wholeTextureExtent[2*i]+1; if(textureSize>maxSize) { ratio[i]=dMaxSize/textureSize; } else { ratio[i]=1.0; // no reduction } rTextureSize[i]=static_cast(floor(textureSize*ratio[i])); ++i; } // Data memory limits. vtkDataArray *scalars=this->GetScalars(this->GetInput(),this->ScalarMode, this->ArrayAccessMode, this->ArrayId, this->ArrayName, this->CellFlag); int scalarType=scalars->GetDataType(); vtkIdType size=rTextureSize[0]*rTextureSize[1]*rTextureSize[2] *vtkAbstractArray::GetDataTypeSize(scalarType) *scalars->GetNumberOfComponents(); if(size>static_cast(this->MaxMemoryInBytes) *static_cast(this->MaxMemoryFraction)) { double r=static_cast(this->MaxMemoryInBytes) *static_cast(this->MaxMemoryFraction)/static_cast(size); double r3=pow(r,1.0/3.0); // try the keep reduction ratio uniform to avoid artifacts. bool reduced[3]; i=0; int count=0; while(i<3) { vtkIdType newSize=static_cast( floor(static_cast(rTextureSize[i])*r3)); reduced[i]=newSize>=1; if(reduced[i]) { ++count; } ++i; } if(count<3) // some axis cannot be reduced { double r2=sqrt(r); count=0; i=0; while(i<3) { if(reduced[i]) { vtkIdType newSize=static_cast( floor(static_cast(rTextureSize[i])*r2)); reduced[i]=newSize>=1; if(reduced[i]) { ++count; } } ++i; } if(count<2) // we can only reduce one axis { i=0; while(i<3) { if(reduced[i]) { ratio[i]*=r; } ++i; } } else // we can reduce two axes { i=0; while(i<3) { if(reduced[i]) { ratio[i]*=r2; } ++i; } } } else // we can reduce all three axes { i=0; while(i<3) { ratio[i]*=r3; ++i; } } } assert("post: valid_i_ratio" && ratio[0]>0 && ratio[0]<=1.0); assert("post: valid_j_ratio" && ratio[1]>0 && ratio[1]<=1.0); assert("post: valid_k_ratio" && ratio[2]>0 && ratio[2]<=1.0); } //----------------------------------------------------------------------------- // Standard print method //----------------------------------------------------------------------------- void vtkMitkOpenGLGPUVolumeRayCastMapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } -#endif +#endif \ No newline at end of file