Commit 98d19f2f authored by saubatn's avatar saubatn
Browse files

FIXED : Bug : Flipping slice actions menu was not correctly initialize.

FIXED : Bug : Flipping slice disappeared the pixel actor surrounding the picked pixel.
FIXED : Slice Class is a bit more "clean".

git-svn-id: svn+ssh://scm.forge.imag.fr/var/lib/gforge/chroot/scmrepos/svn/camitk/trunk/camitk@225 ec899d31-69d1-42ba-9299-647d76f65fb3
parent 7bb911ec
......@@ -26,6 +26,8 @@
// -- Core stuff
#include "Slice.h"
#include "Log.h"
#include <InteractiveViewer.h>
#include <RendererWidget.h>
// -- vtk stuff
#include <vtkImageData.h>
......@@ -71,8 +73,6 @@ void Slice::init()
originalDimensions[1] = 0;
originalDimensions[2] = 0;
originalVolume = NULL;
imgToMapFilter = NULL;
......@@ -89,8 +89,6 @@ void Slice::init()
pickPlaneMapper = NULL;
pickPlaneActor = NULL;
pixelActor = NULL; // Will be set in getPixelActor
imgToMapFilter = vtkSmartPointer<vtkImageMapToColors>::New();
image3DActor = vtkSmartPointer<vtkImageActor>::New();
image2DReslicer = vtkSmartPointer<vtkImageReslice>::New();
......@@ -105,8 +103,6 @@ void Slice::init()
pickPlane = vtkSmartPointer<vtkPlaneSource>::New();
pickPlaneMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
pickPlaneActor = vtkSmartPointer<vtkActor>::New();
}
void Slice::setOriginalVolume( vtkSmartPointer<vtkImageData> volume )
......@@ -126,10 +122,8 @@ void Slice::setOriginalVolume( vtkSmartPointer<vtkImageData> volume )
if (originalSpacing[1] == 0.0) originalSpacing[1] = -1.0;
if (originalSpacing[2] == 0.0) originalSpacing[2] = -1.0;
// Sets the end of the pipeline
initActors();
}
......@@ -244,7 +238,6 @@ void Slice::initActors()
image3DActor->SetInput(imgToMapFilter->GetOutput());
image3DActor->InterpolateOn();
/* 2D Actor: pluged to the output of the reslicer */
// Put the origin to 0, 0, 0 so that the reslicer could cut at the right place
// it also helps to display 2D actor at the right place in 2D viewers.
......@@ -263,7 +256,6 @@ void Slice::initActors()
setInitialSlicerTransformation();
computeReslicedDimensions();
// Pick plane
updatePickPlane();
......@@ -419,8 +411,6 @@ int Slice::getNumberOfSlices() const
/* Set the current arbitrary angle.*/
void Slice::setRotationX(double angle)
{
// Check if s is inside the volume bounds
if ( angle < 0 || angle > 360) {
angle = 0.0;
......@@ -430,8 +420,6 @@ void Slice::setRotationX(double angle)
applyRotation();
}
/* Set the current arbitrary angle.*/
void Slice::setRotationY(double angle)
{
......@@ -600,120 +588,138 @@ int Slice::getNumberOfColors() const
// move the pixel selection green indicator (pixelActor) to the given real position
void Slice::setPixelRealPosition(double x, double y, double z)
{
// Truncate the pixel coordinates
int intPixelX = x;
int intPixelY = y;
int intPixelZ = z;
// Truncate the pixel coordinates
int intPixelX = x;
int intPixelY = y;
int intPixelZ = z;
// Compute pixel REAL coordiantes. Add an offset to the Z coordinate to make the actor visible in TOP lEFT origin.
// TODO : Handle actor's visibility in BOTTOM RIGHT origin.
double matchPixelX = (double)intPixelX * resliceSpacing[0];
double matchPixelY = (double)intPixelY * resliceSpacing[1];
double matchPixelZ = (double)intPixelZ * resliceSpacing[2] + 0.01;
// Compute pixel REAL coordinates. Add an offset to the Z coordinate to make the actor visible in TOP lEFT origin.
// TODO : Handle actor's visibility in BOTTOM RIGHT origin.
double matchPixelX = (double)intPixelX * resliceSpacing[0];
double matchPixelY = (double)intPixelY * resliceSpacing[1];
double matchPixelZ = (double)intPixelZ * resliceSpacing[2];
//-- Update position
position[0] = matchPixelX;
position[1] = matchPixelY;
position[2] = matchPixelZ;
// Update pixel actor
// TODO : Handle correctly the vtk pipeline in order to create only one vtkActor
// with moving points defining him.
getPixelActor();
//return;
updatePixelActorPosition(matchPixelX, matchPixelY, matchPixelZ);
}
/* Return the vtkActor used to pick pixels in the slices. */
vtkSmartPointer<vtkActor> Slice::getPixelActor()
void Slice::initPixelActor()
{
double xMin, xMax , yMin, yMax, xBorderMin, xBorderMax, yBorderMin, yBorderMax;
double pickPlaneBounds[6];
//--- Update pick plane
image2DReslicer->GetOutput()->ComputeBounds();
image2DReslicer->GetOutput()->Update();
image2DReslicer->GetOutput()->GetBounds(pickPlaneBounds);
computeReslicedDimensions();
// Compute the size of the pixel
// Get the bounding box coordinates within the slice
double pickPlaneBounds[6];
image2DReslicer->GetOutput()->ComputeBounds();
image2DReslicer->GetOutput()->Update();
image2DReslicer->GetOutput()->GetBounds(pickPlaneBounds);
double xMin = pickPlaneBounds[0];
double xMax = pickPlaneBounds[1];
double yMin = pickPlaneBounds[2];
double yMax = pickPlaneBounds[3];
computeReslicedDimensions();
// Instanciate the actor
pixelActor = vtkSmartPointer<vtkActor>::New();
// Draw the bounding box around the center of the slice
updatePixelActorPosition(xMin + (xMax - xMin)/2, yMin + (yMax - yMin)/2, 0.01);
}
void Slice::updatePixelActorPosition(double x, double y, double z)
{
// The coordinates of the bounding box around the picked pixel
double xMin, xMax , yMin, yMax;
//--- Update pick plane
double pickPlaneBounds[6];
image2DReslicer->GetOutput()->ComputeBounds();
image2DReslicer->GetOutput()->Update();
image2DReslicer->GetOutput()->GetBounds(pickPlaneBounds);
xMin = pickPlaneBounds[0];
xMax = pickPlaneBounds[1];
yMin = pickPlaneBounds[2];
yMax = pickPlaneBounds[3];
computeReslicedDimensions();
if (!pixelActor)
{
pixelActor = vtkSmartPointer<vtkActor>::New();
hLine = vtkSmartPointer<vtkLine>::New();
vLine = vtkSmartPointer<vtkLine>::New();
position[0] = xMin + (xMax - xMin)/2;
position[1] = yMin + (yMax - yMin)/2;
position[2] = 0.01;
}
// Compute the image borders depending on the picked position (Here it is (x, y) )
xBorderMin = - position[0];
xBorderMax = - position[0] + xMin - xMax;
// Compute the bounding box according to the picked pixel
double xBorderMin, xBorderMax, yBorderMin, yBorderMax;
xBorderMin = - x;
xBorderMax = - x + xMin - xMax;
switch (sliceOrientation)
{
case AXIAL_ORIENTATION:
yBorderMin = - position[1];
yBorderMax = - position[1] + yMin - yMax;
yBorderMin = - y;
yBorderMax = - y + yMin - yMax;
break;
default:
yBorderMin = - position[1];
yBorderMax = - position[1] - yMin + yMax;
yBorderMin = - y;
yBorderMax = - y - yMin + yMax;
break;
}
double z = 0.01;
pixelPoints = vtkSmartPointer<vtkPoints>::New();
pixelPoints->SetNumberOfPoints(16);
pixelPoints->InsertPoint(0, xMin, yBorderMin, z );
pixelPoints->InsertPoint(1, xMax, yBorderMin, z );
pixelPoints->InsertPoint(2, xMax, yMin, z );
pixelPoints->InsertPoint(3, xBorderMax, yMin, z );
pixelPoints->InsertPoint(4, xBorderMax, yMax, z );
pixelPoints->InsertPoint(5, xMax, yMax, z );
pixelPoints->InsertPoint(6, xMax, yBorderMax, z );
pixelPoints->InsertPoint(7, xMin, yBorderMax, z );
pixelPoints->InsertPoint(8, xMin, yMax, z );
pixelPoints->InsertPoint(9, xBorderMin, yMax, z );
pixelPoints->InsertPoint(10, xBorderMin, yMin, z );
pixelPoints->InsertPoint(11, xMin, yMin, z );
pixelPoints->InsertPoint(12, xBorderMin, 0, z );
pixelPoints->InsertPoint(13, xBorderMax, 0, z );
pixelPoints->InsertPoint(14, 0, yBorderMin, z );
pixelPoints->InsertPoint(15, 0, yBorderMax, z );
hLine->GetPointIds()->SetId(0, 12);
hLine->GetPointIds()->SetId(1, 13);
vLine->GetPointIds()->SetId(0, 14);
vLine->GetPointIds()->SetId(1, 15);
aPixelGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
// Check the orientation of the slice to deduce the depth to draw the pixel actor with its bounding box
RendererWidget::CameraOrientation orientation;
switch(sliceOrientation)
{
case AXIAL_ORIENTATION:
orientation = InteractiveViewer::getAxialViewer()->getRendererWidget()->getCameraOrientation();
break;
case CORONAL_ORIENTATION:
orientation = InteractiveViewer::getCoronalViewer()->getRendererWidget()->getCameraOrientation();
break;
case SAGITTAL_ORIENTATION:
orientation = InteractiveViewer::getSagittalViewer()->getRendererWidget()->getCameraOrientation();
break;
default:
break;
}
switch(orientation)
{
case RendererWidget::LEFT_UP:
case RendererWidget::RIGHT_DOWN: // camera position has a negative depth
z = -0.01;
break;
case RendererWidget::RIGHT_UP:
z = +0.01;
break;
default:
break;
}
// Create the cloup points used to describe the bounding box around
vtkSmartPointer<vtkPoints> pixelPoints = vtkSmartPointer<vtkPoints>::New();
pixelPoints->SetNumberOfPoints(4);
// Those points describes the (red / blue / green) cross around the picked pixel.
pixelPoints->InsertPoint(0, xBorderMin, 0, z );
pixelPoints->InsertPoint(1, xBorderMax, 0, z );
pixelPoints->InsertPoint(2, 0, yBorderMin, z );
pixelPoints->InsertPoint(3, 0, yBorderMax, z );
// Create the lines crossing the picked pixel
vtkSmartPointer<vtkLine> hLine = vtkSmartPointer<vtkLine>::New();
hLine->GetPointIds()->SetId(0, 0);
hLine->GetPointIds()->SetId(1, 1);
vtkSmartPointer<vtkLine> vLine = vtkSmartPointer<vtkLine>::New();
vLine->GetPointIds()->SetId(0, 2);
vLine->GetPointIds()->SetId(1, 3);
// Create the unstructured grid according to these 2 lines and cloup points
vtkSmartPointer<vtkUnstructuredGrid> aPixelGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
aPixelGrid->Allocate(2, 2);
aPixelGrid->InsertNextCell( hLine->GetCellType(), hLine->GetPointIds());
aPixelGrid->InsertNextCell( vLine->GetCellType(), vLine->GetPointIds());
aPixelGrid->SetPoints(pixelPoints);
aPixelMapper = vtkSmartPointer<vtkDataSetMapper>::New();
// Create the corresponding mapper
vtkSmartPointer<vtkDataSetMapper> aPixelMapper = vtkSmartPointer<vtkDataSetMapper>::New();
aPixelMapper->SetInput(aPixelGrid);
pixelActor->SetMapper(aPixelMapper);
pixelActor->SetMapper(aPixelMapper);
pixelActor->GetProperty()->SetAmbient(1.0);
pixelActor->GetProperty()->SetDiffuse(1.0);
// Update pixel actor properties
switch (sliceOrientation)
{
default:
......@@ -731,11 +737,27 @@ vtkSmartPointer<vtkActor> Slice::getPixelActor()
break;
}
pixelActor->GetProperty()->SetLineWidth( 1.0 );
pixelActor->SetPosition( position[0], position[1], position[2] );
pixelActor->SetPosition( x, y, z );
//-- pixelActor can not be picked
pixelActor->PickableOff();
}
return pixelActor;
/* Create the pixel grid (bounding box) around the pixel picked.
* Returns the actors that has been calculated */
vtkSmartPointer<vtkActor> Slice::getPixelActor()
{
if (!pixelActor)
initPixelActor();
else
{
// Refresh the drawing of the pixel actor from its current position
// Needed if slice plane are flipped.
double crtPos[3];
pixelActor->GetPosition(crtPos);
updatePixelActorPosition(crtPos[0], crtPos[1], crtPos[2]);
}
return pixelActor;
}
// TODO : put those methods into a dedicated interface
......
......@@ -301,66 +301,67 @@ private:
/** Transformation between the reslice volume and the original volume. */
vtkSmartPointer<vtkTransform> transformReslice2Volume;
/**@} */
/** Keep track of the slice number */
int currentSliceIndex;
/// Common lookup table
vtkSmartPointer<vtkWindowLevelLookupTable> lut;
/// To be able to extract a slice
vtkSmartPointer<vtkImageMapToColors> imgToMapFilter;
/**@} */
/// 3D actor
vtkSmartPointer<vtkImageActor> image3DActor;
/**@{ */
/**@name For 2D actor */
/// Reslicer: cut the volume at the right plane and displays it facing the 2D camera
vtkSmartPointer<vtkImageReslice> image2DReslicer;
/// To put the origin of the reslicer at (0, 0, 0)
/// (mandatory to visualize 2D actor (axial, coronal or sagittal) properly in a 2D window)
vtkSmartPointer<vtkImageChangeInformation> image2DChangeInfo;
/// 2D actor itself
vtkSmartPointer<vtkImageActor> image2DActor;
/**@} */
/** Keep track of the slice number */
int currentSliceIndex;
/// Common lookup table
vtkSmartPointer<vtkWindowLevelLookupTable> lut;
/**@} */
/**@name Uses for picking */
/**@{ */
/// To be able to extract a slice
vtkSmartPointer<vtkImageMapToColors> imgToMapFilter;
/** A plane used for picking. This plane has the same size and position as the displayed slice. However, it is a
* real vtkActor that can be easily picked (using 'p' ot 'Ctrl+left click'). */
vtkSmartPointer<vtkPlaneSource> pickPlane;
/// 3D actor
vtkSmartPointer<vtkImageActor> image3DActor;
/** Mapper of the the pickPlane. */
vtkSmartPointer<vtkPolyDataMapper> pickPlaneMapper;
/**@{ */
/**@name For 2D actor */
/// Reslicer: cut the volume at the right plane and displays it facing the 2D camera
vtkSmartPointer<vtkImageReslice> image2DReslicer;
/// To put the origin of the reslicer at (0, 0, 0)
/// (mandatory to visualize 2D actor (axial, coronal or sagittal) properly in a 2D window)
vtkSmartPointer<vtkImageChangeInformation> image2DChangeInfo;
/// 2D actor itself
vtkSmartPointer<vtkImageActor> image2DActor;
/**@} */
/** Actor representing the pickPlane. */
vtkSmartPointer<vtkActor> pickPlaneActor;
/**@} */
/**@} */
/**@name Uses for picking */
/**@{ */
/** A plane used for picking. This plane has the same size and position as the displayed slice. However, it is a
* real vtkActor that can be easily picked (using 'p' ot 'Ctrl+left click'). */
vtkSmartPointer<vtkPlaneSource> pickPlane;
/**@} */
/** Mapper of the the pickPlane. */
vtkSmartPointer<vtkPolyDataMapper> pickPlaneMapper;
/** Actor representing a pixel, displayed over the image. */
vtkSmartPointer<vtkActor> pixelActor;
vtkSmartPointer<vtkPixel> aPixel;
vtkSmartPointer<vtkPolygon> aCross;
vtkSmartPointer<vtkUnstructuredGrid> aPixelGrid;
vtkSmartPointer<vtkPoints> pixelPoints;
vtkSmartPointer<vtkDataSetMapper> aPixelMapper;
vtkSmartPointer<vtkLine> vLine;
vtkSmartPointer<vtkLine> hLine;
double position[3];
/** Actor representing the pickPlane. */
vtkSmartPointer<vtkActor> pickPlaneActor;
/**@} */
/**
* Init the pixel actor for pixel picking
*/
void initPixelActor();
/** Update the pixel actor position according to the specified pixel picked by the user
* i.e. Compute and draw the bounding box around the selected pixel.
* @param x:
* The absciss value of the selected pixel
* @param y:
* The ordinate value of the selected pixel
* @param z:
* The depth value of the selected pixel. In the plane, it's always +/- 0.01 in order to the pixel actor to be
* visible over the slice.
**/
void updatePixelActorPosition(double x, double y, double z);
/** Actor representing a pixel, displayed over the image. */
vtkSmartPointer<vtkActor> pixelActor;
};
......
......@@ -233,7 +233,7 @@ void InteractiveViewer::initSettings() {
RendererWidget::CameraOrientation cameraOrientation;
cameraOrientation = (RendererWidget::CameraOrientation) settings.value("cameraOrientation", rendererWidget->getCameraOrientation()).toInt();
rendererWidget->setCameraOrientation(cameraOrientation);
// highlight mode
highlightMode = (HighlightMode) settings.value("highlightMode", SELECTION).toInt();
......@@ -738,20 +738,20 @@ void InteractiveViewer::initActions() {
cameraOrientationRightDownAction->setChecked(rendererWidget->getCameraOrientation() == RendererWidget::RIGHT_DOWN);
cameraOrientationRightDownAction->setStatusTip(tr("Set the camera such as x points to the right, y points downward, z points backward"));
cameraOrientationRightDownAction->setWhatsThis(tr("Set the camera such as x points to the right, y points downward, z points backward"));
cameraOrientationLeftUpAction = new QAction(tr("x-left y-up z-back"), cameraOrientationGrp);
cameraOrientationRightDownAction->setChecked(rendererWidget->getCameraOrientation() == RendererWidget::LEFT_UP);
cameraOrientationLeftUpAction->setCheckable(true);
cameraOrientationLeftUpAction->setCheckable(true);
cameraOrientationLeftUpAction->setChecked(rendererWidget->getCameraOrientation() == RendererWidget::LEFT_UP);
cameraOrientationLeftUpAction->setStatusTip(tr("Set the camera such as x points to the left, y points upward, z points backward"));
cameraOrientationLeftUpAction->setWhatsThis(tr("Set the camera such as x points to the left, y points upward, z points backward"));
cameraOrientationRightUpAction = new QAction(tr("x-right y-up z-front"), cameraOrientationGrp);
cameraOrientationRightUpAction->setCheckable(true);
cameraOrientationRightDownAction->setChecked(rendererWidget->getCameraOrientation() == RendererWidget::RIGHT_UP);
cameraOrientationRightUpAction->setChecked(rendererWidget->getCameraOrientation() == RendererWidget::RIGHT_UP);
cameraOrientationRightUpAction->setStatusTip(tr("Set the camera such as x points to the right, y points upward, z points to the front"));
cameraOrientationRightUpAction->setWhatsThis(tr("Set the camera such as x points to the right, y points upward, z points to the front"));
//-- others
//-- others
backgroundColorAction = new QAction(tr("Background &Color"), this);
backgroundColorAction->setStatusTip(tr("Change background color"));
backgroundColorAction->setWhatsThis(tr("Change the color background of the InteractiveViewer"));
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment