diff --git a/Core/Code/Rendering/mitkImageVtkMapper2D.cpp b/Core/Code/Rendering/mitkImageVtkMapper2D.cpp index 66753abeea..f365c1bdaf 100644 --- a/Core/Code/Rendering/mitkImageVtkMapper2D.cpp +++ b/Core/Code/Rendering/mitkImageVtkMapper2D.cpp @@ -1,1157 +1,1181 @@ /*========================================================================= 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 + //MITK #include #include #include #include #include #include #include #include #include #include #include #include //MITK Rendering #include "mitkImageVtkMapper2D.h" #include "mitkVtkPropRenderer.h" #include "vtkMitkThickSlicesFilter.h" //VTK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //ITK #include mitk::ImageVtkMapper2D::ImageVtkMapper2D() { m_VtkBased = true; } mitk::ImageVtkMapper2D::~ImageVtkMapper2D() { this->InvokeEvent( itk::DeleteEvent() ); //TODO <- what is this doing exactly? } void mitk::ImageVtkMapper2D::AdjustCamera(mitk::BaseRenderer* renderer) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); //activate parallel projection for 2D renderer->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(true); const mitk::DisplayGeometry* displayGeometry = renderer->GetDisplayGeometry(); double imageHeightInMM = localStorage->m_ReslicedImage->GetDimensions()[1]; //the height of the current slice in mm double displayHeightInMM = displayGeometry->GetSizeInMM()[1]; //the display height in mm (gets smaller when you zoom in) double zoomFactor = imageHeightInMM/displayHeightInMM; //determine how much of the image 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. renderer->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(imageHeightInMM*0.5 ); //zooming with the factor calculated by dividing displayHeight through imegeHeight. The factor is inverse, because the VTK zoom method is working inversely. renderer->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) 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 = renderer->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 camera->SetClippingRange(0.1, 1000000.0); //Reason for huge range: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823) in VTK bugtracker. } } //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 //plane size in crosshair rotation and swivel mode. localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], 0.0); //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], 0.0); //P1: (xMax, yMin, 0) localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], 0.0); //P2: (xMin, yMax, 0) } 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); //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() ) { // vtkCamera* cam = renderer->GetVtkRenderer()->GetActiveCamera(); //set up the camera to view the transformed plane // MITK_INFO << "######################### vor rendern"; // double* range = cam->GetClippingRange(); // cam->Print(std::cout); // MITK_INFO << "range " << range[0] << " " << range[1]; this->GetVtkProp(renderer)->RenderOpaqueGeometry( renderer->GetVtkRenderer() ); // MITK_INFO << "######################### nach rendern"; // MITK_INFO << "range " << range[0] << " " << range[1]; // cam->Print(std::cout); } } 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() ) { // vtkSmartPointer ren = // vtkSmartPointer::New(); // vtkSmartPointer renderWindow = // vtkSmartPointer::New(); // renderWindow->AddRenderer(ren); // vtkSmartPointer renderWindowInteractor = // vtkSmartPointer::New(); // renderWindowInteractor->SetRenderWindow(renderWindow); // ren->AddActor(m_LSH.GetLocalStorage(renderer)->m_Actor); // renderWindow->Render(); // renderWindowInteractor->Start(); this->GetVtkProp(renderer)->RenderTranslucentPolygonalGeometry(renderer->GetVtkRenderer()); } } void mitk::ImageVtkMapper2D::MitkRenderVolumetricGeometry(BaseRenderer* renderer) { if(IsVisible(renderer)==false) return; //TODO is it possible to have a visible BaseRenderer AND an invisible VtkRenderer??? if ( GetVtkProp(renderer)->GetVisibility() ) this->GetVtkProp(renderer)->RenderVolumetricGeometry(renderer->GetVtkRenderer()); } void mitk::ImageVtkMapper2D::GenerateData( mitk::BaseRenderer *renderer ) { // MITK_INFO << "GenerateData"; LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); //TODO WTF CONST CAST?!?!?111 => Error in class design? if ( input == NULL ) { return; } //check if there is a valid worldGeometry TODO: Move to Update()? const Geometry2D *worldGeometry = renderer->GetCurrentWorldGeometry2D(); if( ( worldGeometry == NULL ) || ( !worldGeometry->IsValid() ) || ( !worldGeometry->HasReferenceGeometry() )) { return; } // check if there is something to display. TODO: Move to Update()? 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 ); 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(); //Translate the origin from center based to corner based //by adding (mm per pixel)/2 in the corresponding direction (right/bottom). 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??? // 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 } 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; } // 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(); } //Begin 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 ); 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. // 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. // The reslicing result is used both for 2D and for 3D mapping. // The reslicing result is stored also for the 3D mapping. // Check the result vtkImageData* reslicedImage = 0; 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; } // Store the result in a VTK image if ( localStorage->m_ReslicedImage == NULL ) { localStorage->m_ReslicedImage = vtkImageData::New(); } //TODO image is stored 2x. Do we still need that? //set the current slice for the localStorage localStorage->m_ReslicedImage->DeepCopy( reslicedImage ); //set the current slice as texture for the plane localStorage->m_Texture->SetInput(localStorage->m_ReslicedImage); //set the size textured plane this->GeneratePlane( renderer, sliceBounds ); //turn the light out in the scene in order to render correct grey values. TODO How to turn it on if you need it? - renderer->GetVtkRenderer()->RemoveAllLights(); +// renderer->GetVtkRenderer()->RemoveAllLights(); //remove the VTK interaction - renderer->GetVtkRenderer()->GetRenderWindow()->SetInteractor(NULL); +// renderer->GetVtkRenderer()->GetRenderWindow()->SetInteractor(NULL); //get the transformation matrix of the reslicer in order to render the slice as transversal, coronal or saggital vtkSmartPointer trans = vtkSmartPointer::New(); vtkSmartPointer matrix = localStorage->m_Reslicer->GetResliceAxes(); trans->SetMatrix(matrix); +//trans->SetMatrix(worldGeometry->GetVtkTransform()->GetMatrix()); //apply the properties after the slice was set this->ApplyProperties( renderer, mmPerPixel ); // vtkCamera* cam = renderer->GetVtkRenderer()->GetActiveCamera(); //set up the camera to view the transformed plane // MITK_INFO << "######################### vor"; // MITK_INFO << "######################### vor rendern"; // double* range = cam->GetClippingRange(); // cam->Print(std::cout); // MITK_INFO << "range " << range[0] << " " << range[1]; - this->AdjustCamera( renderer ); +// this->AdjustCamera( renderer ); // renderer->GetVtkRenderer()->SetBackground(1, 1, 1); //transform the plane/contour (the actual actor) to the corresponding view (transversal, coronal or saggital) - localStorage->m_Actor->SetUserTransform(trans); +// localStorage->m_Actor->SetUserTransform(trans); + +//static int counter = 0; +//if(counter < 6) +//{ +// mitk::Surface::Pointer surf = mitk::Surface::New(); +// surf->SetVtkPolyData(localStorage->m_Mapper->GetInput()); +// surf->Update(); + +// mitk::DataNode::Pointer node = mitk::DataNode::New(); +// node->SetData(surf); +// renderer->GetDataStorage()->Add(node); +// counter++; +//} + + if(renderer->GetRenderWindow() == renderer->GetRenderWindowByName("stdmulti.widget2")) + { +// MITK_INFO << "Im Mapper"; +// worldGeometry->GetVtkTransform()->GetMatrix()->Print(std::cout); +// trans->Print(std::cout); + } + //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). - renderer->GetVtkRenderer()->GetActiveCamera()->ApplyTransform(trans); +// renderer->GetVtkRenderer()->GetActiveCamera()->ApplyTransform(trans); // MITK_INFO << "pos Z:" << cam->GetPosition()[2]; // MITK_INFO << "foc Z:" << cam->GetFocalPoint()[2]; // MITK_INFO << "pla Z:" << localStorage->m_Plane->GetCenter()[2]; // renderer->GetVtkRenderer()->ResetCameraClippingRange(); // We have been modified // cam->Print(std::cout); // MITK_INFO << "range " << range[0] << " " << range[1]; 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()) 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(); //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 //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 ); localStorage->m_Mapper->ScalarVisibilityOn(); 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); float binaryOutlineWidth(1.0); if (this->GetDataNode()->GetFloatProperty( "outline width", binaryOutlineWidth, renderer )) { localStorage->m_Actor->GetProperty()->SetLineWidth(binaryOutlineWidth); } } } else { //TODO still true for MITK with VTK rendering? 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() ); // obtain and apply opacity level window mitk::LevelWindow opacLevelWindow; if( this->GetLevelWindow( opacLevelWindow, renderer, "opaclevelwindow" ) ) { finalLookuptable->SetAlphaRange(opacLevelWindow.GetLowerWindowBound()/255.0, opacLevelWindow.GetLowerWindowBound()/255.0); } else { finalLookuptable->SetAlphaRange(0.0, 1.0); } } //use the finalLookuptable for mapping the colors localStorage->m_Texture->SetLookupTable( finalLookuptable ); if(binaryOutline && binary) { localStorage->m_Mapper->SetInput(localStorage->m_OutlinePolyData); localStorage->m_Actor->SetTexture(NULL); } else { //transform the plane to the corresponding view (transversal, coronal or saggital) localStorage->m_Mapper->SetInputConnection(localStorage->m_Plane->GetOutputPort()); //set the texture for the actor localStorage->m_Actor->SetTexture(localStorage->m_Texture); } localStorage->m_Mapper->ScalarVisibilityOff(); } void mitk::ImageVtkMapper2D::Update(mitk::BaseRenderer* renderer) { // MITK_INFO << "Update"; 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->GetDisplayGeometryUpdateTime()) // TODO this does not work || (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->GenerateData( 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( "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]){ 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) 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 != 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); //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); 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); 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); 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() { //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_OutlinePolyData = 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->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); } diff --git a/Core/Code/Rendering/mitkVtkPropRenderer.cpp b/Core/Code/Rendering/mitkVtkPropRenderer.cpp index f9ca525bb7..da24d5804a 100644 --- a/Core/Code/Rendering/mitkVtkPropRenderer.cpp +++ b/Core/Code/Rendering/mitkVtkPropRenderer.cpp @@ -1,883 +1,928 @@ /*========================================================================= - -Program: Medical Imaging & Interaction Toolkit -Language: C++ -Date: $Date: 2007-09-22 11:55:20 +0200 (Sa, 22 Sep 2007) $ -Version: $Revision: 12240 $ - 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) { 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); - #if ( VTK_MAJOR_VERSION >= 5 ) - m_TextRenderer->SetErase(0); - #endif +#if ( VTK_MAJOR_VERSION >= 5 ) + m_TextRenderer->SetErase(0); +#endif } /*! \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? + // 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(); + // 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 + 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)) - { + if((mapper->IsVtkBased() == false) && (lastVtkBased == true)) + { Enable2DOpenGL(); lastVtkBased = false; } //Workarround for bug GL_TEXTURE_2D 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; - //BUG (#1551) changed VTK_MINOR_VERSION FROM 3 to 2 cause RenderTranslucentGeometry was changed in minor version 2 - #if ( ( VTK_MAJOR_VERSION >= 5 ) && ( VTK_MINOR_VERSION>=2) ) - case mitk::VtkPropRenderer::Volumetric: mapper->MitkRenderVolumetricGeometry(this); break; - #endif + case mitk::VtkPropRenderer::Opaque: mapper->MitkRenderOpaqueGeometry(this); break; + case mitk::VtkPropRenderer::Translucent: mapper->MitkRenderTranslucentGeometry(this); break; + case mitk::VtkPropRenderer::Overlay: mapper->MitkRenderOverlay(this); break; + //BUG (#1551) changed VTK_MINOR_VERSION FROM 3 to 2 cause RenderTranslucentGeometry was changed in minor version 2 +#if ( ( VTK_MAJOR_VERSION >= 5 ) && ( VTK_MINOR_VERSION>=2) ) + case mitk::VtkPropRenderer::Volumetric: mapper->MitkRenderVolumetricGeometry(this); break; +#endif } if(mode) glEnable(bit); else glDisable(bit); glLineWidth(lineWidth); } if (lastVtkBased == false) Disable2DOpenGL(); //fix for bug 1177. In 2D rendering the camera is not needed, but nevertheless it is used by //the vtk rendering mechanism to determine what is seen (and therefore has to be rendered) //by using the bounds of the vtkMitkRenderProp if (sthVtkBased == false) this->GetVtkRenderer()->ResetCamera(); // 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() ) Update(); else if (m_MapperID>=2 && 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(); + // 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 - ); + 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); - + mitk::RenderingManager::GetInstance()->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(); + 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 - /* + 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; - } + 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 + 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 ) + 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 ) ); + ( 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) + 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) + 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; } #if ( ( VTK_MAJOR_VERSION >= 5 ) && ( VTK_MINOR_VERSION>=2) ) mitk::VtkPropRenderer::MappersMapType mitk::VtkPropRenderer::GetMappersMap() const { return m_MappersMap; } #endif // 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(); + // 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(); + // vtkMapper::GlobalImmediateModeRenderingOff(); } //MITK_INFO << "GLOBAL 3D DECREASE " << glWorkAroundGlobalCount << "\n"; } - } + } } void mitk::VtkPropRenderer::AdjustCameraToScene(){ -// LocalStorage *localStorage = m_LSH.GetLocalStorage(this); - - //activate parallel projection for 2D - this->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(true); - - const mitk::DisplayGeometry* displayGeometry = this->GetDisplayGeometry(); - - //TODO - double imageHeightInMM = 256.0;//localStorage->m_ReslicedImage->GetDimensions()[1]; //the height of the current slice in mm - double displayHeightInMM = displayGeometry->GetSizeInMM()[1]; //the display height in mm (gets smaller when you zoom in) - double zoomFactor = imageHeightInMM/displayHeightInMM; //determine how much of the image 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(imageHeightInMM*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) - 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) + if(this->GetMapperID() == 1) { - 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 - camera->SetClippingRange(0.1, 1000000.0); //Reason for huge range: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823) in VTK bugtracker. - } + //activate parallel projection for 2D + this->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(true); + + const mitk::DisplayGeometry* displayGeometry = this->GetDisplayGeometry(); + + //TODO + double imageHeightInMM = 256.0;//localStorage->m_ReslicedImage->GetDimensions()[1]; //the height of the current slice in mm + double displayHeightInMM = displayGeometry->GetSizeInMM()[1]; //the display height in mm (gets smaller when you zoom in) + double zoomFactor = imageHeightInMM/displayHeightInMM; //displayGeometry->GetScaleFactorMMPerDisplayUnit() + //determine how much of the image 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(imageHeightInMM*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) + 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-1, distance+1); //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. + } + + this->GetVtkRenderer()->RemoveAllLights(); - this->GetVtkRenderer()->RemoveAllLights(); + //remove the VTK interaction + this->GetVtkRenderer()->GetRenderWindow()->SetInteractor(NULL); - //remove the VTK interaction - this->GetVtkRenderer()->GetRenderWindow()->SetInteractor(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). - //TODO -// this->GetVtkRenderer()->GetActiveCamera()->ApplyTransform(trans); +// this->GetDataNode()->GetVtkTransform(this->GetTimestep()); + +// vtkSmartPointer trans = vtkSmartPointer::New(); +// // trans->SetMatrix(this->GetWorldGeometry()->GetVtkTransform()->GetMatrix()); +// trans->SetMatrix( this->GetWorldGeometry()->GetVtkTransform()->GetLinearInverse()->GetMatrix()); +// vtkSmartPointer trans2 = vtkSmartPointer::New(); +// trans2->SetMatrix( this->GetCurrentWorldGeometry2D()->GetVtkTransform()->GetLinearInverse()->GetMatrix()); +// trans->Concatenate(trans2); + + + if(this->GetRenderWindow() == this->GetRenderWindowByName("stdmulti.widget2")) + { +// MITK_INFO << "1 "; +// this->GetGetMatrixCurrentWorldGeometry2D()->GetReferenceGeometry()->GetVtkTransform()->GetMatrix()->Print(std::cout); +//// this->GetCurrentWorldGeometry2D()->GetVtkTransform()->GetMatrix()->Print(std::cout); +// MITK_INFO << "1 Inverse"; +// this->GetCurrentWorldGeometry2D()->GetReferenceGeometry()->GetVtkTransform()->GetLinearInverse()->GetMatrix()->Print(std::cout); + +// this->GetCurrentWorldGeometry2D()->GetVtkTransform()->GetLinearInverse()->GetMatrix()->Print(std::cout); +// MITK_INFO << "2"; +//// // this->GetDisplayGeometry()->GetVtkTransform()->GetMatrix()->Print(std::cout); +// this->GetWorldGeometry()->GetVtkTransform()->GetMatrix()->Print(std::cout); +////// this->GetSliceNavigationController()->GetCurrentPlaneGeometry()->GetVtkTransform()->GetMatrix()->Print(std::cout); +//// MITK_INFO << "2 Inverse"; +////// this->GetSliceNavigationController()->GetCurrentPlaneGeometry()->GetVtkTransform()->GetLinearInverse()->GetMatrix()->Print(std::cout); +//// // this->GetDisplayGeometry()->GetVtkTransform()->GetLinearInverse()->GetMatrix()->Print(std::cout); +//// this->GetWorldGeometry()->GetVtkTransform()->GetLinearInverse()->GetMatrix()->Print(std::cout); +// MITK_INFO << "3"; +//// // this->GetSliceNavigationController()->GetCurrentGeometry3D()->GetVtkTransform()->GetMatrix()->Print(std::cout); +// this->GetCurrentWorldGeometry2D()->GetVtkTransform()->GetMatrix()->Print(std::cout); +// MITK_INFO << "3 Inverse"; +// // this->GetSliceNavigationController()->GetCurrentGeometry3D()->GetVtkTransform()->GetLinearInverse()->GetMatrix()->Print(std::cout); +//// this->GetCurrentWorldGeometry()->GetVtkTransform()->GetLinearInverse()->GetMatrix()->Print(std::cout); + +// MITK_INFO << "Ende"; + } + // trans->Print(std::cout); + + // const TimeSlicedGeometry *inputTimeGeometry = input->GetTimeSlicedGeometry(); + // const Geometry3D* inputGeometry = inputTimeGeometry->GetGeometry3D( this->GetTimestep() ); + +// this->GetVtkRenderer()->GetActiveCamera()->ApplyTransform(trans); + } }