Commit eeba6801 authored by saubatn's avatar saubatn
Browse files

UPDATED action move frame has been modified in order to easily edit a...

UPDATED action move frame has been modified in order to easily edit a component's frame. Interface's ergonomy has been updated and is really simpler.
NEW Frame can be exported and imported from a .xml file, directly using this action.

git-svn-id: svn+ssh://scm.forge.imag.fr/var/lib/gforge/chroot/scmrepos/svn/camitk/trunk/camitk@2168 ec899d31-69d1-42ba-9299-647d76f65fb3
parent 4c5af94c
......@@ -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,60 @@ 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 +194,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->setTransformRotation(ui.rX->getValue(), ui.rY->getValue(), ui.rZ->getValue());
inputFrame->setTransformTranslation(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 +233,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 +271,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 transfor 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();
}
}
......@@ -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;
};
......
......@@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>652</width>
<height>315</height>
<height>689</height>
</rect>
</property>
<property name="sizePolicy">
......@@ -29,6 +29,71 @@
<bool>true</bool>
</property>
<layout class="QGridLayout">
<item row="3" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<spacer name="horizontalSpacer_4">
<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="saveTransformButton">
<property name="text">
<string>Save Transform</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="loadTransformButton">
<property name="text">
<string>Load Transform</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="parentFrameLayout">
<item>
<widget class="QLabel" name="parentFrameLabel">
<property name="text">
<string>Parent Frame Component</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="parentFrameComboBox"/>
</item>
<item>
<widget class="QPushButton" name="parentFramePushButton">
<property name="text">
<string>Set Parent Frame</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
......@@ -62,35 +127,7 @@
</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>
<layout class="QHBoxLayout" name="horizontalLayout"/>
</item>
</layout>
</widget>
......@@ -124,85 +161,19 @@
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="rotatePushButton">
<property name="text">
<string>Rotate</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<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="setRotationPushButton">
<property name="text">
<string>Set Rotation</string>
</property>
</widget>
</item>
</layout>
<layout class="QHBoxLayout" name="horizontalLayout_2"/>