Commit bd2fc029 authored by saubatn's avatar saubatn
Browse files

UPDATED InterfaceFrame now proposes also the rotateVTK,...

UPDATED InterfaceFrame now proposes also the rotateVTK, setTransformRotationVTK and setTransformTranslationVTK alternative methods, regarding the rotation order (Z, X, Y) compared to the previous alphabetical one.
UPDATED MoveFrame not a testing action anymore. Now, It allows to edit the selected component frame :
 - modifying its parent's frame
 - modifying the translation values and rotation angles of the frame
 - optionnaly proposing to save / load a frame in / from a .frame file.

git-svn-id: svn+ssh://scm.forge.imag.fr/var/lib/gforge/chroot/scmrepos/svn/camitk/trunk/camitk@2173 ec899d31-69d1-42ba-9299-647d76f65fb3
parent 4de5728c
......@@ -2,7 +2,7 @@
* $CAMITK_LICENCE_BEGIN$
*
* CamiTK - Computer Assisted Medical Intervention ToolKit
* (c) 2001-2016 UJF-Grenoble 1, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
* (c) 2001-2015 UJF-Grenoble 1, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
*
* Visit http://camitk.imag.fr for more information
*
......@@ -49,17 +49,19 @@ using namespace camitk;
#include <vtkPointData.h>
#include <vtkCellData.h>
#include <vtkAlgorithmOutput.h>
#include <vtkMatrix3x3.h>
// --------------- constructor -------------------
MoveFrame::MoveFrame(ActionExtension* extension) : Action(extension) {
setName("Move Frame");
setDescription(tr("This action allow to move a frame from its parent frame (or the world frame if it has no parent) by setting translations and rotation parameters."));
setName("Edit Frame");
setDescription(tr("This action allow to edit a component's frame from its parent frame (or the world frame if it has no parent) by setting translations and rotation parameters."));
setComponent("Component");
// Setting classification family and tags
setFamily("Frame");
addTag(tr("Test"));
addTag(tr("Edit"));
addTag(tr("Move"));
addTag(tr("Visualization"));
......@@ -72,10 +74,21 @@ MoveFrame::MoveFrame(ActionExtension* extension) : Action(extension) {
void MoveFrame::init() {
dialog = new QDialog();
transformation = vtkSmartPointer<vtkTransform>::New();
//-- init user interface
ui.setupUi(dialog);
// sliders initial values
double bounds[6];
InteractiveViewer::get3DViewer()->getBounds(bounds);
double xLength = bounds[1] - bounds[0];
double yLength = bounds[3] - bounds[2];
double zLength = bounds[5] - bounds[4];
ui.tX->init(-xLength*2, + xLength*2, 0.0);
ui.tY->init(-yLength*2, + yLength*2, 0.0);
ui.tZ->init(-zLength*2, + zLength*2, 0.0);
ui.rX->init(-180.0, 180.0, 0.0);
ui.rY->init(-180.0, 180.0, 0.0);
ui.rZ->init(-180.0, 180.0, 0.0);
// initialize slider names
ui.tX->setName("X");
......@@ -86,15 +99,16 @@ void MoveFrame::init() {
ui.rZ->setName(tr("Around Z"));
// connect everything
connect(ui.translatePushButton, SIGNAL(clicked()), SLOT(translate()));
connect(ui.setTranslationPushButton, SIGNAL(clicked()), SLOT(setTranslation()));
connect(ui.rotatePushButton, SIGNAL(clicked()), SLOT(rotate()));
connect(ui.setRotationPushButton, SIGNAL(clicked()), SLOT(setRotation()));
connect(ui.tX, SIGNAL(valueChanged()), SLOT(apply()));
connect(ui.tY, SIGNAL(valueChanged()), SLOT(apply()));
connect(ui.tZ, SIGNAL(valueChanged()), SLOT(apply()));
connect(ui.rX, SIGNAL(valueChanged()), SLOT(apply()));
connect(ui.rY, SIGNAL(valueChanged()), SLOT(apply()));
connect(ui.rZ, SIGNAL(valueChanged()), SLOT(apply()));
connect(ui.resetButton, SIGNAL(clicked()), SLOT(reset()));
connect(ui.setTransformButton, SIGNAL(clicked()), SLOT(apply()));
connect(ui.savePushButton, SIGNAL(clicked()), SLOT(save()));
connect(ui.loadTransformButton, SIGNAL(clicked()), SLOT(load()));
connect(ui.saveTransformButton, SIGNAL(clicked()), SLOT(save()));
connect(ui.parentFramePushButton, SIGNAL(clicked()), SLOT(changeParent()));
}
......@@ -108,27 +122,59 @@ MoveFrame::~MoveFrame() {
QWidget * MoveFrame::getWidget() {
if (!dialog)
init();
// parent component list
ui.parentFrameComboBox->clear();
ui.parentFrameComboBox->addItem("World");
foreach(Component* comp, getTargets()){
if(comp != inputFrame)
ui.parentFrameComboBox->addItem(comp->getName());
}
inputFrame = dynamic_cast<Component *> (getTargets().last());
vtkSmartPointer<vtkTransform> initialTransform = inputFrame->getTransform();
initialPosition.setX(initialTransform->GetPosition()[0]);
initialPosition.setY(initialTransform->GetPosition()[1]);
initialPosition.setZ(initialTransform->GetPosition()[2]);
initialOrientation.setX(initialTransform->GetOrientation()[0]);
initialOrientation.setY(initialTransform->GetOrientation()[1]);
initialOrientation.setZ(initialTransform->GetOrientation()[2]);
// disconnect and reset previous state
reset();
inputFrame = getTargets().last();
// get frame's rotation
ui.rX->setValue(inputFrame->getTransform()->GetOrientation()[0]);
ui.rY->setValue(inputFrame->getTransform()->GetOrientation()[1]);
ui.rZ->setValue(inputFrame->getTransform()->GetOrientation()[2]);
// read translation
// compute translation in the rotated frame
vtkSmartPointer<vtkMatrix3x3> rotationMatrix = vtkSmartPointer<vtkMatrix3x3>::New();
rotationMatrix->Identity();
// isolate the rotation matrix from the transfor one
rotationMatrix->SetElement(0, 0, inputFrame->getTransform()->GetMatrix()->GetElement(0, 0));
rotationMatrix->SetElement(0, 1, inputFrame->getTransform()->GetMatrix()->GetElement(0, 1));
rotationMatrix->SetElement(0, 2, inputFrame->getTransform()->GetMatrix()->GetElement(0, 2));
rotationMatrix->SetElement(1, 0, inputFrame->getTransform()->GetMatrix()->GetElement(1, 0));
rotationMatrix->SetElement(1, 1, inputFrame->getTransform()->GetMatrix()->GetElement(1, 1));
rotationMatrix->SetElement(1, 2, inputFrame->getTransform()->GetMatrix()->GetElement(1, 2));
rotationMatrix->SetElement(2, 0, inputFrame->getTransform()->GetMatrix()->GetElement(2, 0));
rotationMatrix->SetElement(2, 1, inputFrame->getTransform()->GetMatrix()->GetElement(2, 1));
rotationMatrix->SetElement(2, 2, inputFrame->getTransform()->GetMatrix()->GetElement(2, 2));
rotationMatrix->Invert(); // which is a transpose in this case ...
double translation[3] = {0.0, 0.0, 0.0};
rotationMatrix->MultiplyPoint(inputFrame->getTransform()->GetPosition(), translation);
// set frame translation
ui.tX->setValue(translation[0]);
ui.tY->setValue(translation[1]);
ui.tZ->setValue(translation[2]);
apply();
return dialog;
}
//--------------- changeParent -------------
void MoveFrame::changeParent() {
if (inputFrame != NULL) {
QString parentName = ui.parentFrameComboBox->currentText();
if(parentName == "World"){ // no parent frame ...
inputFrame->setParentFrame(NULL);
return;
}
// Find the corresponding component:
const ComponentList existingComponents = Application::getAllComponents();
Component * newParent = NULL;
......@@ -147,130 +193,36 @@ void MoveFrame::changeParent() {
//--------------- reset -------------
void MoveFrame::reset() {
//-- initialize the transformation to Identity
transformation->Identity();
transformation->RotateX(initialOrientation.x());
transformation->RotateY(initialOrientation.y());
transformation->RotateZ(initialOrientation.z());
transformation->Translate(initialPosition.x(), initialPosition.y(), initialPosition.z());
//-- init values
double bounds[6];
InteractiveViewer::get3DViewer()->getBounds(bounds);
double xLength = bounds[1] - bounds[0];
double yLength = bounds[3] - bounds[2];
double zLength = bounds[5] - bounds[4];
ui.tX->init(-xLength, + xLength, initialPosition.x());
ui.tY->init(-yLength, + yLength, initialPosition.y());
ui.tZ->init(-zLength, + zLength, initialPosition.z());
ui.rX->init(-180.0, 180.0, initialOrientation.x());
ui.rY->init(-180.0, 180.0, initialOrientation.y());
ui.rZ->init(-180.0, 180.0, initialOrientation.z());
//-- Fill in the Possible Parent Frame Components ComboBox
ui.parentFrameComboBox->clear();
QStringList possibleParentFrames;
possibleParentFrames << "World Frame";
const ComponentList existingComponents = Application::getAllComponents();
for (int i = 0; i < existingComponents.size(); i++) {
Component * c = existingComponents.at(i);
if( c ) {
SingleImageComponent * csi = dynamic_cast<SingleImageComponent *>( c );
if( csi ) {
//do nothing
//A singleImageComponent cannot be a parent frame, it is always a frame child of another frame.
} else {
possibleParentFrames << c->getName();
}
}
}
ui.parentFrameComboBox->addItems(possibleParentFrames);
if (inputFrame != NULL) {
Component * currentParentComponent = dynamic_cast<Component *> (inputFrame->getParentFrame());
if (currentParentComponent == NULL) {
ui.parentFrameComboBox->setCurrentIndex(0);
} else {
ui.parentFrameComboBox->setCurrentIndex(possibleParentFrames.indexOf(currentParentComponent->getName()));
}
}
// reset all values to 0.0
ui.tX->setValue(0.0);
ui.tY->setValue(0.0);
ui.tZ->setValue(0.0);
ui.rX->setValue(0.0);
ui.rY->setValue(0.0);
ui.rZ->setValue(0.0);
apply(); // to refresh
}
//--------------- apply ------------
Action::ApplyStatus MoveFrame::apply() {
inputFrame = dynamic_cast<Component *> (getTargets().last());
transformation->Identity();
//-- Set the Rotation
transformation->RotateX(double(ui.rX->getValue()));
transformation->RotateY(double(ui.rY->getValue()));
transformation->RotateZ(double(ui.rZ->getValue()));
inputFrame->setTransformRotationVTK(ui.rX->getValue(), ui.rY->getValue(), ui.rZ->getValue());
inputFrame->setTransformTranslationVTK(ui.tX->getValue(), ui.tY->getValue(), ui.tZ->getValue());
//-- Set the Translation
transformation->Translate(double(ui.tX->getValue()), double(ui.tY->getValue()), double(ui.tZ->getValue()));
inputFrame->setTransform(transformation);
// Refresh all the used viewers
// InteractiveViewer::get3DViewer()->refresh();
Application::refresh();
// Refresh only 3D viewer : there is only it displaying the frame.
InteractiveViewer::get3DViewer()->refresh();
return SUCCESS;
}
void MoveFrame::translate() {
QVector3D trans;
trans.setX(double (ui.tX->getValue()));
trans.setY(double (ui.tY->getValue()));
trans.setZ(double (ui.tZ->getValue()));
inputFrame->translate(trans.x(), trans.y(), trans.z());
}
void MoveFrame::setTranslation() {
QVector3D trans;
trans.setX(double (ui.tX->getValue()));
trans.setY(double (ui.tY->getValue()));
trans.setZ(double (ui.tZ->getValue()));
inputFrame->setTransformTranslation(trans.x(), trans.y(), trans.z());
}
void MoveFrame::rotate() {
QVector3D rot;
rot.setX(double (ui.rX->getValue()));
rot.setY(double (ui.rY->getValue()));
rot.setZ(double (ui.rZ->getValue()));
inputFrame->rotate(rot.x(), rot.y(), rot.z());
}
void MoveFrame::setRotation() {
QVector3D rot;
rot.setX(double (ui.rX->getValue()));
rot.setY(double (ui.rY->getValue()));
rot.setZ(double (ui.rZ->getValue()));
inputFrame->setTransformRotation(rot.x(), rot.y(), rot.z());
}
//--------------- save ------------
void MoveFrame::save() {
transformation->Identity();
//-- Set the Rotation
transformation->RotateX(double(ui.rX->getValue()));
transformation->RotateY(double(ui.rY->getValue()));
transformation->RotateZ(double(ui.rZ->getValue()));
//-- Set the Translation
transformation->Translate(double(ui.tX->getValue()), double(ui.tY->getValue()), double(ui.tZ->getValue()));
QString filename = QFileDialog::getSaveFileName(NULL, "Save file");
QString filename = QFileDialog::getSaveFileName(NULL, "Save file", ".frame");
QFile file(filename);
if (file.open(QIODevice::WriteOnly)) {
QTextStream stream(&file);
......@@ -280,7 +232,7 @@ void MoveFrame::save() {
QDomElement transform = doc.createElement("transform");
transform.setAttribute("type", "matrix");
vtkSmartPointer<vtkMatrix4x4> matrix = transformation->GetMatrix();
vtkSmartPointer<vtkMatrix4x4> matrix = inputFrame->getTransform()->GetMatrix();
for (int i = 0; i < 4; i++) {
QDomElement line = doc.createElement("line");
// x
......@@ -318,6 +270,85 @@ void MoveFrame::save() {
doc.save(stream, 0);
file.close();
}
}
}
//--------------- load ------------
void MoveFrame::load(){
// choose the file to open
QString fileName = QFileDialog::getOpenFileName(NULL, tr("Open Frame File"), ".frame", ".frame");
QFile file(fileName);
if(file.open(QIODevice::ReadOnly)){
QDomDocument doc("frame");
if (!doc.setContent(&file)) {
file.close();
return;
}
// we read the file as a vtkTransform, which is better to process then
vtkSmartPointer<vtkTransform> transformation = vtkSmartPointer<vtkTransform>::New();
transformation->Identity();
vtkSmartPointer<vtkMatrix4x4> matrix = transformation->GetMatrix();
// QDomElement docElem = doc.documentElement();
QDomNode transformNode = doc.firstChild();
if(!transformNode.isNull()) {
QDomNodeList lines = doc.elementsByTagName("line");
if(lines.length() != 4){
CAMITK_ERROR("MoveFrame", "load", "Number of XML line elements should be exactly 4.");
return;
}
for (int i = 0; i < 4; i++) {
QDomNode line = lines.at(i);
if(line.childNodes().length() != 4){
CAMITK_ERROR("MoveFrame", "load", "XML line elements should be have exactly 4 children.");
return;
}
for(int j = 0; j < 4; j++){
double value = line.childNodes().at(j).firstChild().nodeValue().toDouble();
matrix->SetElement(i, j, value);
}
}
}
file.close();
// read rotation
double * rotationAngles = transformation->GetOrientation();
ui.rX->setValue(rotationAngles[0]);
ui.rY->setValue(rotationAngles[1]);
ui.rZ->setValue(rotationAngles[2]);
// read translation
// compute translation in the rotated frame
vtkSmartPointer<vtkMatrix3x3> rotationMatrix = vtkSmartPointer<vtkMatrix3x3>::New();
rotationMatrix->Identity();
// isolate the rotation matrix from the transform one
rotationMatrix->SetElement(0, 0, transformation->GetMatrix()->GetElement(0, 0));
rotationMatrix->SetElement(0, 1, transformation->GetMatrix()->GetElement(0, 1));
rotationMatrix->SetElement(0, 2, transformation->GetMatrix()->GetElement(0, 2));
rotationMatrix->SetElement(1, 0, transformation->GetMatrix()->GetElement(1, 0));
rotationMatrix->SetElement(1, 1, transformation->GetMatrix()->GetElement(1, 1));
rotationMatrix->SetElement(1, 2, transformation->GetMatrix()->GetElement(1, 2));
rotationMatrix->SetElement(2, 0, transformation->GetMatrix()->GetElement(2, 0));
rotationMatrix->SetElement(2, 1, transformation->GetMatrix()->GetElement(2, 1));
rotationMatrix->SetElement(2, 2, transformation->GetMatrix()->GetElement(2, 2));
rotationMatrix->Invert(); // which is a transpose in this case ...
double translation[3] = {0.0, 0.0, 0.0};
rotationMatrix->MultiplyPoint(transformation->GetPosition(), translation);
// get it back in the widget
ui.tX->setValue(translation[0]);
ui.tY->setValue(translation[1]);
ui.tZ->setValue(translation[2]);
// refresh the widget
apply();
}
}
......@@ -2,7 +2,7 @@
* $CAMITK_LICENCE_BEGIN$
*
* CamiTK - Computer Assisted Medical Intervention ToolKit
* (c) 2001-2016 UJF-Grenoble 1, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
* (c) 2001-2015 UJF-Grenoble 1, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
*
* Visit http://camitk.imag.fr for more information
*
......@@ -37,7 +37,6 @@
#include "ui_MoveFrame.h"
/** This action allows you to apply a linear transformation
* (translation,rotation around axes) on the top level selected Frame
*/
......@@ -55,14 +54,25 @@ public:
virtual QWidget * getWidget();
public slots:
/// method called when the action is applied
/**
* Update the component's frame with the translation and rotation parameters of the widget.
* This keeps synchronized the frame with the value selected by the user
*/
virtual ApplyStatus apply();
virtual void translate();
virtual void setTranslation();
virtual void rotate();
virtual void setRotation();
/**
* Save the current frame to a file.
*/
virtual void save();
/**
* Load a frame description from a file.
**/
virtual void load();
/**
* Change the current frame's parent.
*/
virtual void changeParent();
private slots:
......@@ -74,22 +84,13 @@ private:
/// initialize the dialog
void init();
/// current transformation
vtkSmartPointer<vtkTransform> transformation;
/// initial transformation
QVector3D initialPosition;
QVector3D initialOrientation;
/// current transform filters (one per selected object)
// QList< vtkSmartPointer<vtkTransformFilter> > filterList;
/// the Qt Gui
Ui::MoveFrame ui;
/// the dialog
QDialog *dialog;
/// the component's frame we work on
camitk::Component * inputFrame;
};
......
......@@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>652</width>
<height>315</height>
<width>686</width>
<height>566</height>
</rect>
</property>
<property name="sizePolicy">
......@@ -28,181 +28,186 @@
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<layout class="QGridLayout">
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="textSliders">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>664</width>
<height>302</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QGroupBox" name="translationBox">
<property name="title">
<string>Translation</string>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="camitk::SliderTextWidget" name="tX" native="true"/>
</item>
<item>
<widget class="camitk::SliderTextWidget" name="tY" native="true"/>
</item>
<item>
<widget class="camitk::SliderTextWidget" name="tZ" native="true"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="translatePushButton">
<property name="text">
<string>Translate</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="setTranslationPushButton">
<property name="text">
<string>SetTranslation</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="rotationBox">
<property name="title">
<string>Rotation</string>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Description:&lt;/span&gt; This action allows you to edit the selected component's frame. &lt;/p&gt;&lt;p&gt;Remember a frame is a 3D space transform represented as a 4x4 matrix in homogeneous coordinates, which stands for the 3D position and orientation of the component relatively to its frame parent component.&lt;/p&gt;&lt;p&gt;Given a frame, we apply first the rotation then the translation. &lt;/p&gt;&lt;p&gt;Using this action you may edit the selected component's frame, ie:&lt;/p&gt;&lt;p&gt;- change its parent frame component.&lt;/p&gt;&lt;p&gt;- change the rotation angles and translation values of the frame.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="camitk::SliderTextWidget" name="rX" native="true"/>
</item>
<item>
<widget class="camitk::SliderTextWidget" name="rY" native="true"/>
</item>
<item>
<widget class="camitk::SliderTextWidget" name="rZ" native="true"/>
</item>
<item>
<spacer name="verticalSpacer_2">