EulerWidget.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2016, Bielefeld University, CITEC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * Author: Robert Haschke <rhaschke@techfak.uni-bielefeld.de>
30  */
31 
32 #include "EulerWidget.h"
33 #include "ui_euler.h"
34 
35 #include <angles/angles.h>
36 #include <QStandardItemModel>
37 #include <iostream>
38 
39 // ensure different axes for consecutive operations
40 static void disableAxis(QComboBox *w, unsigned int axis) {
41  const QStandardItemModel* model = qobject_cast<const QStandardItemModel*>(w->model());
42  for (unsigned int i=0; i < 3; ++i) {
43  QStandardItem* item = model->item(i);
44  if (i == axis) {
45  item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
46  if (w->currentIndex() == static_cast<int>(axis)) w->setCurrentIndex((axis+1) % 3);
47  } else {
48  item->setFlags(item->flags() | Qt::ItemIsEnabled);
49  }
50  }
51 }
52 
53 EulerWidget::EulerWidget(QWidget *parent) :
54  QWidget(parent), ui_(new Ui::EulerWidget)
55 {
56  qRegisterMetaType<Eigen::Quaterniond>("Eigen::Quaterniond");
57 
58  ui_->setupUi(this);
59  ui_->a1->setCurrentIndex(0);
60  ui_->a2->setCurrentIndex(1); disableAxis(ui_->a2, 0);
61  ui_->a3->setCurrentIndex(2); disableAxis(ui_->a3, 1);
62 
63  q_ = Eigen::Quaterniond::Identity();
64  updateAngles();
65 
66  // react to axis changes
67  connect(ui_->a1, SIGNAL(currentIndexChanged(int)),
68  this, SLOT(axisChanged(int)));
69  connect(ui_->a2, SIGNAL(currentIndexChanged(int)),
70  this, SLOT(axisChanged(int)));
71  connect(ui_->a3, SIGNAL(currentIndexChanged(int)),
72  this, SLOT(axisChanged(int)));
73 
74  // react to angle changes
75  connect(ui_->e1, SIGNAL(valueChanged(double)),
76  this, SLOT(angleChanged(double)));
77  connect(ui_->e2, SIGNAL(valueChanged(double)),
78  this, SLOT(angleChanged(double)));
79  connect(ui_->e3, SIGNAL(valueChanged(double)),
80  this, SLOT(angleChanged(double)));
81 }
82 
83 void EulerWidget::getGuiAxes(uint a[]) const {
84  a[0] = ui_->a1->currentIndex();
85  a[1] = ui_->a2->currentIndex();
86  a[2] = ui_->a3->currentIndex();
87 }
88 
89 void EulerWidget::getGuiAngles(double e[3]) const {
90  e[0] = angles::from_degrees(ui_->e1->value());
91  e[1] = angles::from_degrees(ui_->e2->value());
92  e[2] = angles::from_degrees(ui_->e3->value());
93 }
94 
95 
96 void EulerWidget::axisChanged(int axis) {
97  bool bFirstCall = !this->signalsBlocked();
98  this->blockSignals(true);
99 
100  // ensure different axes for consecutive operations
101  QComboBox* origin = dynamic_cast<QComboBox*>(sender());
102  if (origin == ui_->a1) disableAxis(ui_->a2, axis);
103  if (origin == ui_->a2) disableAxis(ui_->a3, axis);
104 
105  if (bFirstCall) {
106  updateAngles();
107  this->blockSignals(false);
108 
109  emit axesChanged(ui_->a1->currentIndex(),
110  ui_->a2->currentIndex(),
111  ui_->a3->currentIndex());
112  }
113 }
114 
115 void EulerWidget::angleChanged(double angle) {
116  double e[3]; getGuiAngles(e);
117  setEulerAngles(e[0], e[1], e[2], false);
118 }
119 
120 void EulerWidget::setEulerAngles(double e1, double e2, double e3, bool normalize) {
121  uint a[3]; getGuiAxes(a);
122  Eigen::Quaterniond q =
123  Eigen::AngleAxisd(e1, Eigen::Vector3d::Unit(a[0])) *
124  Eigen::AngleAxisd(e2, Eigen::Vector3d::Unit(a[1])) *
125  Eigen::AngleAxisd(e3, Eigen::Vector3d::Unit(a[2]));
126  if (normalize)
127  setValue(q);
128  else {
129  // do not trigger angleChanged() again
130  ui_->e1->blockSignals(true);
131  ui_->e2->blockSignals(true);
132  ui_->e3->blockSignals(true);
133 
134  ui_->e1->setValue(angles::to_degrees(e1));
135  ui_->e2->setValue(angles::to_degrees(e2));
136  ui_->e3->setValue(angles::to_degrees(e3));
137 
138  ui_->e1->blockSignals(false);
139  ui_->e2->blockSignals(false);
140  ui_->e3->blockSignals(false);
141 
142  if (q_.isApprox(q)) return;
143  q_ = q;
144  emit valueChanged(q);
145  }
146 }
147 
148 void EulerWidget::setEulerAxes(uint a1, uint a2, uint a3)
149 {
150  if (a1 > 2 || a2 > 2 || a3 > 2) return;
151  if (static_cast<int>(a1) == ui_->a1->currentIndex() &&
152  static_cast<int>(a2) == ui_->a2->currentIndex() &&
153  static_cast<int>(a3) == ui_->a3->currentIndex()) return;
154 
155  this->blockSignals(true);
156  ui_->a3->setCurrentIndex(a3);
157  ui_->a2->setCurrentIndex(a2);
158  ui_->a1->setCurrentIndex(a1);
159  this->blockSignals(false);
160  updateAngles();
161 
162  emit axesChanged(a1, a2, a3);
163 }
164 
165 
166 void EulerWidget::setValue(const Eigen::Quaterniond &q) {
167  if (q_.isApprox(q)) return;
168  q_ = q;
169  updateAngles();
170  emit valueChanged(q);
171 }
172 
173 const Eigen::Quaterniond& EulerWidget::value() const {
174  return q_;
175 }
176 
177 
179  // ensure different axes for consecutive operations
180  uint a[3]; getGuiAxes(a);
181  Eigen::Vector3d e = q_.matrix().eulerAngles(a[0], a[1], a[2]);
182  setEulerAngles(e[0], e[1], e[2], false);
183 }
void getGuiAngles(double e[]) const
retrieve angles from GUI
Definition: EulerWidget.cpp:89
void axisChanged(int axis)
Definition: EulerWidget.cpp:96
void setEulerAxes(uint a1, uint a2, uint a3)
const Eigen::Quaterniond & value() const
void angleChanged(double angle)
Definition: EulerWidget.h:37
Ui::EulerWidget * ui_
Definition: EulerWidget.h:76
void axesChanged(uint a1, uint a2, uint a3)
euler axis selection changed
static double from_degrees(double degrees)
void setEulerAngles(double e1, double e2, double e3, bool normalize)
static double to_degrees(double radians)
void valueChanged(const Eigen::Quaterniond &q)
quaternion value has changed
Eigen::Quaterniond q_
Definition: EulerWidget.h:75
void setValue(const Eigen::Quaterniond &q)
static void disableAxis(QComboBox *w, unsigned int axis)
Definition: EulerWidget.cpp:40
void getGuiAxes(uint a[3]) const
retrieve indices of axes selected in GUI
Definition: EulerWidget.cpp:83
EulerWidget(QWidget *parent=0)
Definition: EulerWidget.cpp:53
void updateAngles()


agni_tf_tools
Author(s): Robert Haschke
autogenerated on Fri Jun 7 2019 22:04:59