Commit dc51a028 authored by Emmanuel Promayon's avatar Emmanuel Promayon

FIXED code cleaning and arbitrary slice management simplification

parent 8a0cc144
......@@ -29,9 +29,6 @@
#include <Property.h>
#include <SetAnglesAction.h>
// Qt stuff
#include <QSpinBox>
using namespace camitk;
// -------------------- constructor --------------------
......@@ -53,7 +50,8 @@ AnglesSetterWidget::AnglesSetterWidget(SetAnglesAction* a, QWidget* parent): QWi
}
// -------------------- destructor --------------------
AnglesSetterWidget::~AnglesSetterWidget() {}
AnglesSetterWidget::~AnglesSetterWidget() {
}
// -------------------- updateGUI --------------------
void AnglesSetterWidget::updateGUI() {
......
......@@ -92,6 +92,8 @@ QWidget* SetAnglesAction::getWidget() {
actionWidget = new AnglesSetterWidget(this);
// first call : force visibility of the arbitrary viewer
MedicalImageViewer::getInstance()->setVisibleViewer(MedicalImageViewer::VIEWER_ARBITRARY);
// connect the arbitrary viewer so that a change to its slider can update the "Slice Index" attribute
connect(InteractiveViewer::getArbitraryViewer(), SIGNAL(selectionChanged()), this, SLOT(viewerSliderChanged()));
}
// reset current pointer so that nothing will happen in the event(..) method
......@@ -116,9 +118,6 @@ QWidget* SetAnglesAction::getWidget() {
// update widget
dynamic_cast<AnglesSetterWidget*>(actionWidget)->updateGUI();
// connect the arbitrary viewer so that a change to its slider can update the "Slice Index" attribute
connect(InteractiveViewer::getArbitraryViewer(), SIGNAL(selectionChanged()), this, SLOT(viewerSliderChanged()));
return actionWidget;
}
......@@ -154,8 +153,6 @@ bool SetAnglesAction::event(QEvent* e) {
return false;
// do something depending of the property that has changed
CAMITK_INFO(QString("[") + changeEvent->propertyName() + QString("] changed to [%2]").arg(property(changeEvent->propertyName()).toInt()))
if (changeEvent->propertyName() == "Slice Index") {
currentImageComp->setSlice(property(changeEvent->propertyName()).toInt());
}
......
......@@ -690,8 +690,6 @@ public:
delegate0(mySlice, updatePickPlane)
delegate0(mySlice, updateReslice)
delegate1(mySlice, setSlice, int)
delegate3(mySlice, setSlice, double, double, double)
......@@ -702,7 +700,7 @@ public:
delegate1(mySlice, setImageWorldTransform, vtkSmartPointer<vtkTransform>)
delegate1(mySlice, setReslicerTransform, vtkSmartPointer<vtkTransform>)
delegate1(mySlice, setArbitraryTransform, vtkSmartPointer<vtkTransform>)
/// see Component.cpp
......
......@@ -85,13 +85,10 @@ public:
/** Return the vtkActor used to pick pixels in the slices. */
virtual vtkSmartPointer<vtkActor> getPixelActor() = 0;
/** For an arbitrary slice: update the image depending on the current value of the reslice transform */
virtual void updateReslice() = 0;
/** Set the pointer to the image transformation.
* this should be done once, at initialization, using the frame transformation (getTransform)
*/
virtual void setReslicerTransform(vtkSmartPointer<vtkTransform>) = 0;
virtual void setArbitraryTransform(vtkSmartPointer<vtkTransform>) = 0;
/** This method is called when the associated plane has been picked in the InteractiveViewer,
* the given coordinates is position where the plane was picked.
......
......@@ -38,9 +38,6 @@
#include <vtkImageMapToColors.h>
#include <vtkImageChangeInformation.h>
using namespace std;
namespace camitk {
// -------------------- constructor --------------------
Slice::Slice(vtkSmartPointer<vtkImageData> volume, SliceOrientation orientation, vtkSmartPointer<vtkWindowLevelLookupTable> lookupTable) {
......@@ -74,8 +71,6 @@ void Slice::init() {
pixelActor = nullptr;
pixelActorPointSet = nullptr;
image2DReslicer = nullptr;
imageTransform = nullptr;
resliceTransform = nullptr;
}
// -------------------- getImageData --------------------
......@@ -112,9 +107,8 @@ void Slice::setOriginalVolume(vtkSmartPointer<vtkImageData> volume) {
// -------------------- setImageWorldTransform --------------------
void Slice::setImageWorldTransform(vtkSmartPointer<vtkTransform> transform) {
// store the transform to world as the 3D actor transformation for correct viewing
imageTransform = transform;
image3DActor->SetUserTransform(imageTransform);
// store the transform to world as the 3D actor transformation for correct viewing in the 3D
image3DActor->SetUserTransform(transform);
}
// -------------------- pixelPicked --------------------
......@@ -145,7 +139,10 @@ int Slice::getNumberOfSlices() const {
int nbSlices;
switch (sliceOrientation) {
case ARBITRARY: // for arbitrary, as it is initialized the same ways as an axial slice, just z extent
case ARBITRARY:
// for arbitrary, use the longest orthogonal dimension
nbSlices = std::max(originalSize[0], std::max(originalSize[1], originalSize[2])) + std::max(originalSpacing[0],std::max(originalSpacing[1], originalSpacing[2]));
break;
case AXIAL:
case AXIAL_NEURO:
nbSlices = extent[5] - extent[4] + 1;
......@@ -191,7 +188,6 @@ void Slice::setSlice(int s) {
switch (sliceOrientation) {
case ARBITRARY:
updateReslice();
break;
case AXIAL:
case AXIAL_NEURO:
......@@ -259,12 +255,11 @@ void Slice::setPixelRealPosition(double x, double y, double z) {
}
// -------------------- setReslicerTransform --------------------
void Slice::setReslicerTransform(vtkSmartPointer<vtkTransform> transform) {
// store the transformation pointer
// (when the transformation is changed, you need to call updateReslice() in order
// to take the new transformation into account and update the arbitrary slice image
resliceTransform = transform;
updateReslice();
void Slice::setArbitraryTransform(vtkSmartPointer<vtkTransform> transform) {
if (sliceOrientation == ARBITRARY) {
image2DReslicer->SetResliceAxes(transform->GetMatrix());
image2DReslicer->Update();
}
}
// -------------------- get2DImageActor --------------------
......@@ -318,10 +313,6 @@ void Slice::initActors() {
image2DActor->GetMapper()->SetInputConnection(imgToMapFilter->GetOutputPort());
}
// use identity by default for the arbitrary slice
resliceTransform = vtkSmartPointer<vtkTransform>::New();
resliceTransform->Identity();
// Picked plane
initPickPlaneActor();
updatePickPlane();
......@@ -609,41 +600,6 @@ void Slice::updatePixelActor(double x, double y, double z) {
pixelActorPointSet->Modified();
}
// -------------------- updateReslice --------------------
void Slice::updateReslice() {
if (sliceOrientation == ARBITRARY) {
/*
// Original volume dimensions in number of voxels (x, y and z)
int originalDimensions[3];
originalVolume->GetDimensions(originalDimensions);
// Transformations required to compute the arbitrary slice inside the volume
vtkSmartPointer<vtkTransform> transformationInsideVolume = vtkTransform::New();
transformationInsideVolume->Identity();
// go to the image center
double imageCenter[3];
for (int i = 0; i < 3; i++) {
imageCenter[i] = / * originalSpacing[i]* * /originalDimensions[i] / 2.0;
}
transformationInsideVolume->Translate(imageCenter[0], imageCenter[1], imageCenter[2]);
// apply the current rotation from the frame
double xyz[4];
resliceTransform->GetOrientation(xyz);
transformationInsideVolume->RotateWXYZ(xyz[0], xyz[1], xyz[2], xyz[3]);
// go back to the image origin
transformationInsideVolume->Translate(-imageCenter[0], -imageCenter[1], -imageCenter[2]);
// translate to the current slice
transformationInsideVolume->Translate(0.0, 0.0, currentSliceIndex);
resliceTransform->DeepCopy(transformationInsideVolume);
*/
image2DReslicer->SetResliceAxes(resliceTransform->GetMatrix());
image2DReslicer->Update();
}
updatePickPlane();
}
......
......@@ -162,6 +162,8 @@ public:
void setOriginalVolume(vtkSmartPointer<vtkImageData> img) override;
/// set the transformation for 3D image representation
/// This is the transformation relative to the world. This is required to have
/// the 3D actor properly positioned in world space
void setImageWorldTransform(vtkSmartPointer<vtkTransform>) override;
/** Return the vtkImageActor (vtkProp) representing a slice to be displayed in the 2D viewers. */
......@@ -207,13 +209,13 @@ public:
/// move the pixel selection green indicator (pixelActor) to the given real position
void setPixelRealPosition(double, double, double) override;
/** For an arbitrary slice: update the image depending on the current value of the reslice transform */
virtual void updateReslice() override;
/** Set the pointer to the image transformation.
* this should be done once, at initialization, using the frame transformation (getTransform)
*/
virtual void setReslicerTransform(vtkSmartPointer<vtkTransform>) override;
/// Set the pointer to the arbitrary slice transformation.
/// this should be done once, at initialization.
/// For SingleImageComponent, it should be the same as the frame of the arbitrary slices (getTransform).
/// This is the transformation relative to the 3D image (it is not parallel to one
/// of the main axe, but has a specific rotation and translation relative to the vtkImage).
/// This is only required for arbitrary orientation.
virtual void setArbitraryTransform(vtkSmartPointer<vtkTransform>) override;
/// get the current image data
vtkSmartPointer<vtkImageData> getImageData() const override;
......@@ -305,17 +307,7 @@ protected:
/// @name Management of the arbitrary slice
/// @{
/// Transformation relative to the world. This is required to place
/// the 3D actor properly in space
vtkSmartPointer<vtkTransform> imageTransform;
/// Transformation relative to the 3D image (it is not parallel to one
/// of the main axe, but has a specific rotation). This should be initialized
/// using the single image component transformation to the parent.
/// This is only required for arbitrary orientation.
vtkSmartPointer<vtkTransform> resliceTransform;
/// The image reslicer computes the arbitrary slice pixels
vtkSmartPointer<vtkImageReslice> image2DReslicer;
......
......@@ -51,8 +51,7 @@ SingleImageComponent::SingleImageComponent(Component* parentComponent, Slice::Sl
this->lut = lut;
// set my parent image as my parent frame
auto* myParentFrame = (Frame*) dynamic_cast<Frame*>(parentComponent->getFrame());
this->setParentFrame(myParentFrame);
this->setParentFrame(parentComponent->getFrame());
// build the slice 3D
initRepresentation();
......@@ -85,7 +84,10 @@ void SingleImageComponent::setViewSliceIn3D(bool toggle) {
// -------------------- initRepresentation --------------------
void SingleImageComponent::initRepresentation() {
// initialize Slice
mySlice = new Slice(dynamic_cast<ImageComponent*>(getParentComponent())->getImageData(), sliceOrientation, lut);
// initialize 3D image actor to the proper position/orientation in the world reference frame
mySlice->setImageWorldTransform(getTransformFromWorld());
switch (sliceOrientation) {
......@@ -101,9 +103,10 @@ void SingleImageComponent::initRepresentation() {
break;
case Slice::ARBITRARY:
setVisibility(InteractiveViewer::getArbitraryViewer(), true);
mySlice->setReslicerTransform(getTransform());
// initial frame is center
setSlice(getNumberOfSlices()/2);
// initial arbitrary slice is centered in the volume along the original z axis
myFrame->translate(0.0, 0.0, dynamic_cast<ImageComponent*>(getParentComponent())->getImageData()->GetDimensions()[2]/2.0*dynamic_cast<ImageComponent*>(getParentComponent())->getImageData()->GetSpacing()[2]);
// initialize the arbitrary transform using the transform to parent vtkTransform
mySlice->setArbitraryTransform(getTransform());
break;
}
}
......@@ -122,7 +125,6 @@ void SingleImageComponent::setTransform(vtkSmartPointer<vtkTransform> transform)
// unless this is a arbitrary slice
if (sliceOrientation == Slice::ARBITRARY) {
myFrame->setTransform(transform);
mySlice->updateReslice();
}
}
......@@ -132,7 +134,6 @@ void SingleImageComponent::resetTransform() {
// unless this is a arbitrary slice
if (sliceOrientation == Slice::ARBITRARY) {
myFrame->resetTransform();
mySlice->updateReslice();
}
}
......@@ -142,7 +143,6 @@ void SingleImageComponent::rotate(double aroundX, double aroundY, double aroundZ
// unless this is a arbitrary slice
if (sliceOrientation == Slice::ARBITRARY) {
myFrame->rotate(aroundX, aroundY, aroundZ);
mySlice->updateReslice();
}
}
......@@ -152,7 +152,6 @@ void SingleImageComponent::rotateVTK(double aroundX, double aroundY, double arou
// unless this is a arbitrary slice
if (sliceOrientation == Slice::ARBITRARY) {
myFrame->rotateVTK(aroundX, aroundY, aroundZ);
mySlice->updateReslice();
}
}
......@@ -179,9 +178,7 @@ void SingleImageComponent::setTransformRotation(double aroundX, double aroundY,
double currentSliceCenter[4];
vtkSmartPointer<vtkTransform> centerTransformation = getTransform();
centerTransformation->MultiplyPoint(initialSliceCenter, currentSliceCenter);
// CAMITK_INFO_ALT(QString("initial center=(%1,%2,%3)").arg(initialSliceCenter[0]).arg(initialSliceCenter[1]).arg(initialSliceCenter[2]))
// CAMITK_INFO_ALT(QString("current center=(%1,%2,%3)").arg(currentSliceCenter[0]).arg(currentSliceCenter[1]).arg(currentSliceCenter[2]))
centerTransformation->Identity();
centerTransformation->Translate(currentSliceCenter[0], currentSliceCenter[1], currentSliceCenter[2]);
centerTransformation->RotateX(aroundX);
......@@ -189,7 +186,6 @@ void SingleImageComponent::setTransformRotation(double aroundX, double aroundY,
centerTransformation->RotateZ(aroundZ);
centerTransformation->Translate(-initialSliceCenter[0], -initialSliceCenter[1], 0.0);
centerTransformation->Update();
mySlice->updateReslice();
}
}
......@@ -199,7 +195,6 @@ void SingleImageComponent::setTransformRotationVTK(double aroundX, double around
// unless this is a arbitrary slice
if (sliceOrientation == Slice::ARBITRARY) {
myFrame->setTransformRotationVTK(aroundX, aroundY, aroundZ);
mySlice->updateReslice();
}
}
......@@ -209,7 +204,6 @@ void SingleImageComponent::setTransformTranslation(double x, double y, double z)
// unless this is a arbitrary slice
if (sliceOrientation == Slice::ARBITRARY) {
myFrame->setTransformTranslation(x, y, z);
mySlice->updateReslice();
}
}
......@@ -219,7 +213,6 @@ void SingleImageComponent::setTransformTranslationVTK(double x, double y, double
// unless this is a arbitrary slice
if (sliceOrientation == Slice::ARBITRARY) {
myFrame->setTransformTranslationVTK(x, y, z);
mySlice->updateReslice();
}
}
......@@ -229,15 +222,13 @@ void SingleImageComponent::translate(double x, double y, double z) {
// unless this is a arbitrary slice
if (sliceOrientation == Slice::ARBITRARY) {
myFrame->translate(x, y, z);
mySlice->updateReslice();
}
}
// -------------------- setSlice --------------------
void SingleImageComponent::setSlice(int s) {
if (sliceOrientation == Slice::ARBITRARY) {
myFrame->setTransformTranslation(0, 0, s*dynamic_cast<ImageComponent*>(getParentComponent())->getImageData()->GetSpacing()[2]);
mySlice->setSlice(s);
if (sliceOrientation == Slice::ARBITRARY) {
myFrame->setTransformTranslation(0.0, 0.0, s);
}
else {
Component::setSlice(s);
......@@ -248,4 +239,14 @@ void SingleImageComponent::setSlice(double x, double y, double z) {
Component::setSlice(x,y,z);
}
// -------------------- getSlice --------------------
int SingleImageComponent::getSlice() const {
if (sliceOrientation == Slice::ARBITRARY) {
return myFrame->getTransform()->GetPosition()[2];
}
else {
return Component::getSlice();
}
}
}
......@@ -48,9 +48,11 @@ namespace camitk {
*
* @brief
* This Component manages a set of images, destined to be seen in a single orientation only
* (axial OR sagittal OR coronal).
* It does implement Slice representation, not Geometry.
*
* (axial OR sagittal OR coronal) and manages the specific case of arbitrary orientation.
*
* Arbitrary slice frame is used to position and orientate the slice inside the parent image volume.
*
* It does have a Slice representation (InterfaceBitMap), not a Geometry.
*
*/
class CAMITK_API SingleImageComponent : public camitk::Component {
......@@ -98,11 +100,16 @@ public:
/// @}
/// rewritten so that the arbitrary slice is directly updating its frame
// (nothing special to do when this is not an arbitrary slice
/// (nothing special to do when this is not an arbitrary slice
virtual void setSlice(int) override;
/// rewritten because the setSlice(int) method is overriden (compiler needs this)
virtual void setSlice(double, double, double) override;
/// Rewritten for arbitrary slice.
/// Arbitrary return the current position in the volume
/// while nothing special has to be done for other orientation
virtual int getSlice() const override;
protected:
/** The concrete building of the Service (Slice in this case, for a 2D representation). */
......
Markdown is supported
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