diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake index abc2705524..c6333122ac 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,35 +1,36 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) - set(revision_tag cc0840db) + set(revision_tag 6af89bce) +# ^^^^^^^^ these are just to check correct length of hash part ExternalProject_Add(${proj} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${proj_DEPENDENCIES} ) set(MITK_DATA_DIR ${ep_source_dir}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/Core/Code/Rendering/mitkVtkPropRenderer.cpp b/Core/Code/Rendering/mitkVtkPropRenderer.cpp index 60a42fefbc..b25f64c32e 100644 --- a/Core/Code/Rendering/mitkVtkPropRenderer.cpp +++ b/Core/Code/Rendering/mitkVtkPropRenderer.cpp @@ -1,926 +1,997 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkVtkPropRenderer.h" // MAPPERS #include "mitkMapper.h" #include "mitkImageVtkMapper2D.h" #include "mitkVtkMapper.h" #include "mitkGLMapper.h" #include "mitkGeometry2DDataVtkMapper3D.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" #include "mitkVtkInteractorStyle.h" // VTK #include #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_CameraInitializedForMapperID(0) { 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) { // 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; VtkMapper* vtkmapper = dynamic_cast(mapper); if(vtkmapper) { //sthVtkBased = true; if(!lastVtkBased) { Disable2DOpenGL(); lastVtkBased = true; } } else if(lastVtkBased) { Enable2DOpenGL(); lastVtkBased = false; } mapper->MitkRender(this, type); } if (lastVtkBased == false) Disable2DOpenGL(); // Render text if (type == VtkPropRenderer::Overlay) { if (m_TextCollection.size() > 0) { + m_TextRenderer->SetViewport( this->GetVtkRenderer()->GetViewport() ); 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() ) { Update(); } 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; bool visible = true; node->GetVisibility(visible, this, "visible"); // The information about LOD-enabled mappers is required by RenderingManager if ( mapper->IsLODEnabled( this ) && visible ) { ++m_NumberOfVisibleLODEnabledMappers; } // mapper without a layer property get layer number 1 int layer = 1; node->GetIntProperty("layer", layer, this); int nr = (layer<<16) + mapperNo; 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], + const DisplayGeometry* displayGeometry = this->GetDisplayGeometry(); + + float displayGeometryWidth = displayGeometry->GetSizeInDisplayUnits()[0]; + float displayGeometryHeight = displayGeometry->GetSizeInDisplayUnits()[1]; + float viewportWidth = iViewport[2]; + float viewportHeight = iViewport[3]; + + /* + The following makes OpenGL mappers draw into the same viewport + that is used by VTK when someone calls vtkRenderer::SetViewport(). + + The parameters of glOrtho describe what "input" coordinates + (display coordinates generated by the OpenGL mappers) are transformed + into the region defined by the viewport. The call has to consider + that the scene is fit vertically and centered horizontally. + + Problem: this is a crude first step towards rendering into viewports. + - mitkViewportRenderingTest demonstrates the non-interactive rendering + that is now possible + - interactors that measure mouse movement in pixels will + probably run into problems with display-to-world transformation + + A proper solution should probably modify the DisplayGeometry to + correctly describe the viewport. + */ + // iViewport is (x,y,width,height) + // glOrtho expects (left,right,bottom,top,znear,zfar) + glOrtho( 0 + - 0.5 * (viewportWidth/viewportHeight-1.0)*displayGeometryHeight + + 0.5 * (displayGeometryWidth - displayGeometryHeight) + , + displayGeometryWidth + + 0.5 * (viewportWidth/viewportHeight-1.0)*displayGeometryHeight + - 0.5 * (displayGeometryWidth - displayGeometryHeight) + , + 0, displayGeometryHeight, -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 ); // disable the texturing here so crosshair is painted in the correct colors // vtk will reenable texturing every time it is needed glDisable( GL_TEXTURE_1D ); glDisable( GL_TEXTURE_2D ); glLineWidth(1.0); } /*! \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()) { GLMapper* glmapper=dynamic_cast(mapper.GetPointer()); if(GetDisplayGeometry()->IsValid()) { if(glmapper != NULL) { glmapper->Update(this); m_VtkMapperPresent=false; } else { VtkMapper* vtkmapper=dynamic_cast(mapper.GetPointer()); if(vtkmapper != NULL) { vtkmapper->Update(this); vtkmapper->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; VtkMapper *mapper = dynamic_cast < VtkMapper * > ( 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 * mapper = node->GetMapper( m_MapperID ); if ( mapper == NULL) continue; mitk::VtkMapper * vtkmapper = dynamic_cast< VtkMapper * >(mapper); if(vtkmapper){ //if vtk-based, then ... if ( vtkmapper->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, float opacity) { - if(text.size() > 0) + if(!text.empty()) { + Point2D p; + p[0] = posX; + p[1] = posY; + p = TransformOpenGLPointToViewport(p); + vtkTextActor* textActor = vtkTextActor::New(); - textActor->SetPosition(posX,posY); + textActor->SetPosition(p[0], p[1]); textActor->SetInput(text.c_str()); + textActor->SetTextScaleModeToNone(); textActor->GetTextProperty()->SetColor(color1, color2, color3); //TODO: Read color from node property textActor->GetTextProperty()->SetOpacity( opacity ); int text_id = m_TextCollection.size(); m_TextCollection.insert(TextMapType::value_type(text_id,textActor)); return text_id; } - return -1; + else + { + 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) { VtkMapper* 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 * mapper = node->GetMapper(m_MapperID); if (mapper) { VtkMapper* vtkmapper = dynamic_cast( mapper ); if(vtkmapper) vtkmapper->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"; } } } //### Contains all methods which are neceassry before each VTK Render() call void mitk::VtkPropRenderer::PrepareRender() { if ( this->GetMapperID() != m_CameraInitializedForMapperID ) { Initialize2DvtkCamera(); //Set parallel projection etc. } AdjustCameraToScene(); //Prepare camera for 2D render windows } bool mitk::VtkPropRenderer::Initialize2DvtkCamera() { if ( this->GetMapperID() == Standard3D ) { //activate parallel projection for 2D this->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(false); this->GetRenderWindow()->GetInteractor()->SetInteractorStyle( vtkInteractorStyleTrackballCamera::New() ); m_CameraInitializedForMapperID = Standard3D; } else 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(); this->GetRenderWindow()->GetInteractor()->SetInteractorStyle( mitkVtkInteractorStyle::New() ); m_CameraInitializedForMapperID = Standard2D; } return true; } void mitk::VtkPropRenderer::AdjustCameraToScene(){ if(this->GetMapperID() == Standard2D) { const mitk::DisplayGeometry* displayGeometry = this->GetDisplayGeometry(); 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], 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. 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. } 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); } } } + +mitk::Point2D mitk::VtkPropRenderer::TransformOpenGLPointToViewport( mitk::Point2D point ) +{ + GLint iViewport[4]; + // Get a copy of the viewport + glGetIntegerv( GL_VIEWPORT, iViewport ); + const mitk::DisplayGeometry* displayGeometry = this->GetDisplayGeometry(); + + float displayGeometryWidth = displayGeometry->GetSizeInDisplayUnits()[0]; + float displayGeometryHeight = displayGeometry->GetSizeInDisplayUnits()[1]; + + float viewportWidth = iViewport[2]; + float viewportHeight = iViewport[3]; // seemingly right + + float zoom = viewportHeight / displayGeometryHeight; + + // see glOrtho call above for more explanation + point[0] += + 0.5 * (viewportWidth/viewportHeight-1.0)*displayGeometryHeight + - 0.5 * (displayGeometryWidth - displayGeometryHeight) + ; + + point[0] *= zoom; + point[1] *= zoom; + + return point; +} diff --git a/Core/Code/Rendering/mitkVtkPropRenderer.h b/Core/Code/Rendering/mitkVtkPropRenderer.h index 47d69908c5..b345ddd335 100644 --- a/Core/Code/Rendering/mitkVtkPropRenderer.h +++ b/Core/Code/Rendering/mitkVtkPropRenderer.h @@ -1,239 +1,250 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKVtkPropRenderer_H_HEADER_INCLUDED_C1C29F6D #define MITKVtkPropRenderer_H_HEADER_INCLUDED_C1C29F6D #include #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, float opacity = 1.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(); + /** + \brief Convert display geometry coordinates to VTK coordinates. + + For use within WriteSimpleText: the input is display geometry coordinates + but the text actor needs positions that fit in a specified viewport. + Conversion is done in this method. + */ + mitk::Point2D TransformOpenGLPointToViewport( mitk::Point2D point ); + + 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 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 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). * * 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 becomes smaller. The used VTK method * camera->Zoom( factor ) also works with an inverse scale. */ void AdjustCameraToScene(); // 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; MapperSlotId m_CameraInitializedForMapperID; // 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/Modules/PlanarFigure/Testing/CMakeLists.txt b/Modules/PlanarFigure/Testing/CMakeLists.txt index 153cd81e2e..7ad592ec31 100644 --- a/Modules/PlanarFigure/Testing/CMakeLists.txt +++ b/Modules/PlanarFigure/Testing/CMakeLists.txt @@ -1 +1,148 @@ MITK_CREATE_MODULE_TESTS() + +set(testcaseBasename mitkViewportRenderingTest) + +# set verbose to 1 to get a list of all defined test cases during CMake configuration +set(verbose 0) + +# viewportTest(): +# +# 1. Sets up a scene with a DICOM image, several planar figures, an STL file +# 2. Modifies the viewport of the VTK renderer to only a part of the render window +# 3. Compares the rendering result against an expected version +# +# Parameters determine the size and position of the viewport and the render window +# The expected result is mitkViewportRenderingTest_${testPostfix}.png +# +function(viewportTest + testPostfix # postfix to uniquely identify the test case + rwWidth rwHeight # "rw" = render window + vpLeft vpBottom vpWidth vpHeight # "vp" = viewport + # list of images/files for visualization + ) + set(data ${ARGN}) # use all ADDITIONAL parameters after vpHeight as filenames + + # transform the input parameters in required test parameters + math(EXPR vpRight "${vpLeft} + ${vpWidth}") + math(EXPR vpTop "${vpBottom} + ${vpHeight}") + + #message(STATUS "Testing viewport of ${vpWidth}x${vpHeight} at ${vpLeft},${vpBottom} in render window of size ${rwWidth}x${rwHeight} ('${testPostfix}')") + + # add the actual test + mitkAddCustomModuleTest( + mitkViewportRenderingTest_${testPostfix} + mitkViewportRenderingTest + ${rwWidth} ${rwHeight} + ${vpLeft} ${vpBottom} + ${vpRight} ${vpTop} + ${data} + -V ${MITK_DATA_DIR}/RenderingTestData/viewport/mitkViewportRenderingTest_${testPostfix}.png #corresponding reference screenshot + ) +endfunction() + +function(getFirstCharacter string charVar) + string(SUBSTRING ${string} 0 1 c) + set(${charVar} ${c} PARENT_SCOPE) +endfunction() + + +# The following lines loop over several variations of aspect ratios for +# - render window +# - a viewport within this render window +# - an input image (defines the input world geometry) +# --------------------------------------------------------------------- +# +# Render window +# - Square +# - Landscape +# - Portrait +# +# Viewport +# - Square +# - Landscape +# - Portrait +# +# World / Image +# - Square +# - Landscape +# - Portrait +# +foreach(renderWindowAspect Square Landscape Portrait) + foreach(viewportAspect Square Landscape Portrait) + foreach(worldAspect Square Landscape Portrait) + getFirstCharacter(${renderWindowAspect} renderWindowAspectSymbol) + getFirstCharacter(${viewportAspect} viewportAspectSymbol) + getFirstCharacter(${worldAspect} worldAspectSymbol) + + # construct test case name from various aspect ratios + set(testCaseShortname "r${renderWindowAspectSymbol}v${viewportAspectSymbol}w${worldAspectSymbol}") + + # construct test image name from aspect ratio + set(testImage ${MITK_DATA_DIR}/RenderingTestData/viewport/input_${worldAspect}/SCSFREN.dcm) # nice DICOM name encoding and gray value test image + set(testObjects + ${MITK_DATA_DIR}/RenderingTestData/PlanarFigures/Line1.pf + ${MITK_DATA_DIR}/RenderingTestData/PlanarFigures/Path1.pf + ${MITK_DATA_DIR}/RenderingTestData/PlanarFigures/FourPointAngle1.pf + ${MITK_DATA_DIR}/RenderingTestData/PlanarFigures/Rectangle1.pf + ${MITK_DATA_DIR}/binary.stl + ) + + # render window size + if (renderWindowAspect STREQUAL Landscape) + set(renderWindowWidth 600) + else() + set(renderWindowWidth 500) + endif() + + if (renderWindowAspect STREQUAL Portrait) + set(renderWindowHeight 600) + else() + set(renderWindowHeight 500) + endif() + + # viewport size + if (viewportAspect STREQUAL Landscape) + set(viewportWidth 450) + else() + set(viewportWidth 300) + endif() + + if (viewportAspect STREQUAL Portrait) + set(viewportHeight 450) + else() + set(viewportHeight 300) + endif() + + # world size + if (worldAspect STREQUAL Portrait) + set(worldWidth 300) + set(worldHeight 420) + elseif (worldAspect STREQUAL Landscape) + set(worldWidth 420) + set(worldHeight 300) + else() + set(worldWidth 512) + set(worldHeight 512) + endif() + + # Summary + set(viewportX 30) + set(viewportY 45) + if (verbose) + message(STATUS "(${testCaseShortname}) " + "Render window ${renderWindowAspect} (${renderWindowWidth}x${renderWindowHeight}), " + "Viewport ${viewportAspect} (${viewportWidth}x${viewportHeight}+${viewportX}+${viewportY}), " + "World ${worldAspect} (${worldWidth}x${worldHeight})" + ) + endif() + + viewPortTest(${testCaseShortname} + ${renderWindowWidth} ${renderWindowHeight} + ${viewportX} ${viewportY} + ${viewportWidth} ${viewportHeight} + ${testImage} + ${testObjects}) + + endforeach() + endforeach() +endforeach() diff --git a/Modules/PlanarFigure/Testing/files.cmake b/Modules/PlanarFigure/Testing/files.cmake index a706fdc9b2..3e8d679a26 100644 --- a/Modules/PlanarFigure/Testing/files.cmake +++ b/Modules/PlanarFigure/Testing/files.cmake @@ -1,8 +1,12 @@ set(MODULE_TESTS mitkPlanarCrossTest.cpp mitkPlanarPolygonTest.cpp mitkPlanarSubdivisionPolygonTest.cpp mitkPlanarFigureIOTest.cpp mitkPlanarFigureObjectFactoryTest.cpp mitkPlanarArrowTest.cpp ) + +set(MODULE_CUSTOM_TESTS + mitkViewportRenderingTest.cpp +) diff --git a/Modules/PlanarFigure/Testing/mitkViewportRenderingTest.cpp b/Modules/PlanarFigure/Testing/mitkViewportRenderingTest.cpp new file mode 100644 index 0000000000..0e28ec8c89 --- /dev/null +++ b/Modules/PlanarFigure/Testing/mitkViewportRenderingTest.cpp @@ -0,0 +1,152 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// MITK +#include "mitkTestingMacros.h" +#include "mitkRenderingTestHelper.h" +#include "mitkNodePredicateDataType.h" +#include "mitkLevelWindowProperty.h" +#include "mitkColorProperty.h" +#include "mitkLevelWindowProperty.h" +#include "mitkPlanarFigure.h" +#include "mitkSurface.h" + +// ITK +#include + +// VTK +#include + +// stdlib +#include + +int mitkViewportRenderingTest(int argc, char* argv[]) { + // load all arguments into a datastorage, take last argument as reference rendering + // setup a renderwindow of fixed size X*Y + // render the datastorage + // compare rendering to reference image + MITK_TEST_BEGIN("mitkViewportRenderingTest") + + // enough parameters? + if ( argc < 2 ) + { + MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) + MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) + exit( EXIT_FAILURE ); + } + + double renderWindowWidth = atof(argv[1]); + double renderWindowHeight = atof(argv[2]); + double left = atof(argv[3]); + double bottom = atof(argv[4]); + double right = atof(argv[5]); + double top = atof(argv[6]); + std::string referenceFilename = argv[8+6]; + argv += 6; // DO NOT attempt to read these as files, this just makes no sense + argc -= 6; // DO NOT attempt to read these as files, this just makes no sense + + MITK_INFO << "Testing viewport "<GetSubset( mitk::TNodePredicateDataType::New()); + for (ObjectsSet::const_iterator iterFigures = figures->begin(); + iterFigures != figures->end(); + ++iterFigures) + { + (*iterFigures)->SetProperty("planarfigure.default.line.color", mitk::ColorProperty::New( 1.0, 0.0, 0.0 ) ); // red + (*iterFigures)->SetProperty("planarfigure.drawcontrolpoints", mitk::BoolProperty::New( false ) ); + (*iterFigures)->SetProperty("planarfigure.drawname", mitk::BoolProperty::New( false ) ); + (*iterFigures)->SetProperty("planarfigure.drawquantities", mitk::BoolProperty::New( true ) ); + } + + ObjectsSet::ConstPointer surfaces = renderingHelper.GetDataStorage()->GetSubset( mitk::TNodePredicateDataType::New()); + for (ObjectsSet::const_iterator iterSurfaces = surfaces->begin(); + iterSurfaces != surfaces->end(); + ++iterSurfaces) + { + (*iterSurfaces)->SetProperty("color", mitk::ColorProperty::New( 0.0, 1.0, 0.0 ) ); // green + } + + ObjectsSet::ConstPointer images = renderingHelper.GetDataStorage()->GetSubset( mitk::TNodePredicateDataType::New()); + for (ObjectsSet::const_iterator iterImages = images->begin(); + iterImages != images->end(); + ++iterImages) + { + (*iterImages)->SetProperty("levelwindow", mitk::LevelWindowProperty::New( mitk::LevelWindow(128.0, 256.0) ) ); // green + int imageWidth = dynamic_cast((*iterImages)->GetData())->GetDimension(0); + int imageHeight = dynamic_cast((*iterImages)->GetData())->GetDimension(1); + MITK_INFO << "Image dimension "<InitializeViews( renderingHelper.GetDataStorage()->ComputeBoundingGeometry3D( images ) ); + + double vLeft = left / renderWindowWidth; + double vBottom = bottom / renderWindowHeight; + double vRight = right / renderWindowWidth; + double vTop = top / renderWindowHeight; + + // THIS HERE IS THE ACTUAL TEST PART, all the rest is setup and decoration + renderingHelper.GetVtkRenderer()->SetViewport( vLeft, vBottom, vRight, vTop ); + + renderingHelper.SetAutomaticallyCloseRenderWindow(true); // set to false for testing the test itself + renderingHelper.Render(); + + //use this to generate a reference screenshot or save the file: + bool generateReferenceScreenshot = false; + if(generateReferenceScreenshot) + { + std::string tmpFilename = referenceFilename; + std::string::size_type slashpos = referenceFilename.find_last_of('/'); + tmpFilename = referenceFilename.substr(slashpos+1); + tmpFilename = std::string("/tmp/") + tmpFilename; + renderingHelper.SaveAsPNG( tmpFilename ); + MITK_INFO << "*********************************"; + MITK_INFO << "SAVE TO " << tmpFilename; + MITK_INFO << "*********************************"; + } + + //### Usage of vtkRegressionTestImage: + //vtkRegressionTestImage( vtkRenderWindow ) + //Set a vtkRenderWindow containing the desired scene. + //vtkRegressionTestImage automatically searches in argc and argv[] + //for a path a valid image with -V. If the test failed with the + //first image (foo.png) check if there are images of the form + //foo_N.png (where N=1,2,3...) and compare against them. + int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); + + //retVal meanings: (see VTK/Rendering/vtkTesting.h) + //0 = test failed + //1 = test passed + //2 = test not run + //3 = something with vtkInteraction + MITK_TEST_CONDITION( retVal == 1, "VTK rendering result matches expectation" ); + + MITK_TEST_END(); +}