EulerWidget.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2016, Bielefeld University, CITEC
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  * Author: Robert Haschke <rhaschke@techfak.uni-bielefeld.de>
00030  */
00031 
00032 #include "EulerWidget.h"
00033 #include "ui_euler.h"
00034 
00035 #include <angles/angles.h>
00036 #include <QStandardItemModel>
00037 #include <iostream>
00038 
00039 // ensure different axes for consecutive operations
00040 static void disableAxis(QComboBox *w, unsigned int axis) {
00041   const QStandardItemModel* model = qobject_cast<const QStandardItemModel*>(w->model());
00042   for (unsigned int i=0; i < 3; ++i) {
00043     QStandardItem* item = model->item(i);
00044     if (i == axis) {
00045       item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
00046       if (w->currentIndex() == static_cast<int>(axis)) w->setCurrentIndex((axis+1) % 3);
00047     } else {
00048       item->setFlags(item->flags() | Qt::ItemIsEnabled);
00049     }
00050   }
00051 }
00052 
00053 EulerWidget::EulerWidget(QWidget *parent) :
00054   QWidget(parent), ui_(new Ui::EulerWidget)
00055 {
00056   qRegisterMetaType<Eigen::Quaterniond>("Eigen::Quaterniond");
00057 
00058   ui_->setupUi(this);
00059   ui_->a1->setCurrentIndex(0);
00060   ui_->a2->setCurrentIndex(1); disableAxis(ui_->a2, 0);
00061   ui_->a3->setCurrentIndex(2); disableAxis(ui_->a3, 1);
00062 
00063   q_ = Eigen::Quaterniond::Identity();
00064   updateAngles();
00065 
00066   // react to axis changes
00067   connect(ui_->a1, SIGNAL(currentIndexChanged(int)),
00068           this, SLOT(axisChanged(int)));
00069   connect(ui_->a2, SIGNAL(currentIndexChanged(int)),
00070           this, SLOT(axisChanged(int)));
00071   connect(ui_->a3, SIGNAL(currentIndexChanged(int)),
00072           this, SLOT(axisChanged(int)));
00073 
00074   // react to angle changes
00075   connect(ui_->e1, SIGNAL(valueChanged(double)),
00076           this, SLOT(angleChanged(double)));
00077   connect(ui_->e2, SIGNAL(valueChanged(double)),
00078           this, SLOT(angleChanged(double)));
00079   connect(ui_->e3, SIGNAL(valueChanged(double)),
00080           this, SLOT(angleChanged(double)));
00081 }
00082 
00083 void EulerWidget::getGuiAxes(uint a[]) const {
00084   a[0] = ui_->a1->currentIndex();
00085   a[1] = ui_->a2->currentIndex();
00086   a[2] = ui_->a3->currentIndex();
00087 }
00088 
00089 void EulerWidget::getGuiAngles(double e[3]) const {
00090   e[0] = angles::from_degrees(ui_->e1->value());
00091   e[1] = angles::from_degrees(ui_->e2->value());
00092   e[2] = angles::from_degrees(ui_->e3->value());
00093 }
00094 
00095 
00096 void EulerWidget::axisChanged(int axis) {
00097   bool bFirstCall = !this->signalsBlocked();
00098   this->blockSignals(true);
00099 
00100   // ensure different axes for consecutive operations
00101   QComboBox* origin = dynamic_cast<QComboBox*>(sender());
00102   if (origin == ui_->a1) disableAxis(ui_->a2, axis);
00103   if (origin == ui_->a2) disableAxis(ui_->a3, axis);
00104 
00105   if (bFirstCall) {
00106     updateAngles();
00107     this->blockSignals(false);
00108 
00109     emit axesChanged(ui_->a1->currentIndex(),
00110                      ui_->a2->currentIndex(),
00111                      ui_->a3->currentIndex());
00112   }
00113 }
00114 
00115 void EulerWidget::angleChanged(double angle) {
00116   double e[3]; getGuiAngles(e);
00117   setEulerAngles(e[0], e[1], e[2], false);
00118 }
00119 
00120 void EulerWidget::setEulerAngles(double e1, double e2, double e3, bool normalize) {
00121   uint a[3]; getGuiAxes(a);
00122   Eigen::Quaterniond q =
00123       Eigen::AngleAxisd(e1, Eigen::Vector3d::Unit(a[0])) *
00124       Eigen::AngleAxisd(e2, Eigen::Vector3d::Unit(a[1])) *
00125       Eigen::AngleAxisd(e3, Eigen::Vector3d::Unit(a[2]));
00126   if (normalize)
00127     setValue(q);
00128   else {
00129     // do not trigger angleChanged() again
00130     ui_->e1->blockSignals(true);
00131     ui_->e2->blockSignals(true);
00132     ui_->e3->blockSignals(true);
00133 
00134     ui_->e1->setValue(angles::to_degrees(e1));
00135     ui_->e2->setValue(angles::to_degrees(e2));
00136     ui_->e3->setValue(angles::to_degrees(e3));
00137 
00138     ui_->e1->blockSignals(false);
00139     ui_->e2->blockSignals(false);
00140     ui_->e3->blockSignals(false);
00141 
00142     if (q_.isApprox(q)) return;
00143     q_ = q;
00144     emit valueChanged(q);
00145   }
00146 }
00147 
00148 void EulerWidget::setEulerAxes(uint a1, uint a2, uint a3)
00149 {
00150   if (a1 > 2 || a2 > 2 || a3 > 2) return;
00151   if (static_cast<int>(a1) == ui_->a1->currentIndex() &&
00152       static_cast<int>(a2) == ui_->a2->currentIndex() &&
00153       static_cast<int>(a3) == ui_->a3->currentIndex()) return;
00154 
00155   this->blockSignals(true);
00156   ui_->a3->setCurrentIndex(a3);
00157   ui_->a2->setCurrentIndex(a2);
00158   ui_->a1->setCurrentIndex(a1);
00159   this->blockSignals(false);
00160   updateAngles();
00161 
00162   emit axesChanged(a1, a2, a3);
00163 }
00164 
00165 
00166 void EulerWidget::setValue(const Eigen::Quaterniond &q) {
00167   if (q_.isApprox(q)) return;
00168   q_ = q;
00169   updateAngles();
00170   emit valueChanged(q);
00171 }
00172 
00173 const Eigen::Quaterniond& EulerWidget::value() const {
00174   return q_;
00175 }
00176 
00177 
00178 void EulerWidget::updateAngles() {
00179   // ensure different axes for consecutive operations
00180   uint a[3]; getGuiAxes(a);
00181   Eigen::Vector3d e = q_.matrix().eulerAngles(a[0], a[1], a[2]);
00182   setEulerAngles(e[0], e[1], e[2], false);
00183 }


agni_tf_tools
Author(s): Robert Haschke
autogenerated on Sat Jun 8 2019 21:01:20