fw4spl
STransformEditor.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2017-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "uiVisuQt/STransformEditor.hpp"
8 
9 #include <fwCom/Signal.hxx>
10 
11 #include <fwData/TransformationMatrix3D.hpp>
12 
13 #include <fwDataTools/TransformationMatrix3D.hpp>
14 
15 #include <fwGuiQt/container/QtContainer.hpp>
16 
17 #include <fwServices/macros.hpp>
18 
19 #include <boost/regex.hpp>
20 
21 #include <glm/gtc/matrix_transform.hpp>
22 #include <glm/gtc/quaternion.hpp>
23 #include <glm/mat4x4.hpp>
24 
25 #include <QHBoxLayout>
26 #include <QLabel>
27 #include <QLineEdit>
28 #include <QSlider>
29 #include <QString>
30 #include <QVBoxLayout>
31 
32 namespace uiVisuQt
33 {
34 
36 
37 //------------------------------------------------------------------------------
38 
40  m_rotation("xyz"),
41  m_translation("xyz")
42 {
43  m_translationRange[0] = -300;
44  m_translationRange[1] = +300;
45  m_rotationRange[0] = -180;
46  m_rotationRange[1] = 180;
47 }
48 
49 //------------------------------------------------------------------------------
50 
52 {
53 
54 }
55 
56 //------------------------------------------------------------------------------
57 
59 {
60  static const ::boost::regex s_REGEX("[xyz][xyz]?[xyz]?");
61 
62  this->initialize();
63 
64  ::fwServices::IService::ConfigType config = this->getConfigTree();
65 
66  const std::string rotation = config.get< std::string >("rotation.<xmlattr>.enabled", "yes");
67 
68  if(rotation == "no")
69  {
70  m_rotation = "";
71  }
72  else if(rotation == "yes")
73  {
74  m_rotation = "xyz";
75  }
76  else if( ::boost::regex_match(rotation, s_REGEX) )
77  {
78  m_rotation = rotation;
79  }
80  else
81  {
82  SLM_ERROR("Attribute 'rotation' should be 'yes', 'no' or a combination of [xyz]");
83  }
84 
85  m_rotationRange[0] = config.get< int >("rotation.<xmlattr>.min", m_rotationRange[0]);
86  m_rotationRange[1] = config.get< int >("rotation.<xmlattr>.max", m_rotationRange[1]);
87 
88  const std::string translation = config.get< std::string >("translation.<xmlattr>.enabled", "yes");
89 
90  if(translation == "no")
91  {
92  m_translation = "";
93  }
94  else if(translation == "yes")
95  {
96  m_translation = "xyz";
97  }
98  else if( ::boost::regex_match(translation, s_REGEX) )
99  {
100  m_translation = translation;
101  }
102  else
103  {
104  SLM_ERROR("Attribute 'translation' should be 'yes', 'no' or a combination of [xyz]");
105  }
106 
107  m_translationRange[0] = config.get< int >("translation.<xmlattr>.min", m_translationRange[0]);
108  m_translationRange[1] = config.get< int >("translation.<xmlattr>.max", m_translationRange[1]);
109 }
110 
111 //------------------------------------------------------------------------------
112 
114 {
115  const char* description[] = {"Translation X", "Translation Y", "Translation Z",
116  "Rotation X", "Rotation Y", "Rotation Z"};
117 
118  this->create();
119  ::fwGuiQt::container::QtContainer::sptr qtContainer =
120  ::fwGuiQt::container::QtContainer::dynamicCast( this->getContainer() );
121 
122  QVBoxLayout* layout = new QVBoxLayout();
123 
124  qtContainer->setLayout( layout );
125 
126  for (unsigned int i = 0; i < MAX_SLIDER_INDEX; i++)
127  {
128  QHBoxLayout* sliderLayout = new QHBoxLayout();
129 
130  m_sliders[i].m_sliderValue = new QLineEdit();
131  m_sliders[i].m_labelMin = new QLabel();
132  m_sliders[i].m_labelMax = new QLabel();
133  m_sliders[i].m_labelDefinition = new QLabel();
134 
135  m_sliders[i].m_slider = new QSlider(Qt::Horizontal);
136  m_sliders[i].m_slider->setTickInterval(1);
137 
138  m_sliders[i].m_labelDefinition->setText(description[i]);
139 
140  sliderLayout->addWidget( m_sliders[i].m_labelDefinition, 0);
141  sliderLayout->addWidget( m_sliders[i].m_labelMin, 0);
142  sliderLayout->addWidget( m_sliders[i].m_slider, 3);
143  sliderLayout->addWidget( m_sliders[i].m_labelMax, 0);
144  sliderLayout->addWidget( m_sliders[i].m_sliderValue, 1);
145 
146  layout->addLayout(sliderLayout, 0);
147  QObject::connect(m_sliders[i].m_slider, SIGNAL(valueChanged(int)), this, SLOT(onSliderChanged(int)));
148  QObject::connect(m_sliders[i].m_sliderValue, SIGNAL(editingFinished()), this, SLOT(onTextChanged()));
149  }
150 
151  for (unsigned int i = POSITION_X; i <= POSITION_Z; i++)
152  {
153  m_sliders[i].m_labelMin->setText(std::to_string(m_translationRange[0]).c_str());
154  m_sliders[i].m_labelMax->setText(std::to_string(m_translationRange[1]).c_str());
155  m_sliders[i].m_slider->setRange(m_translationRange[0], m_translationRange[1]);
156  }
157 
158  const char axes[] = {"xyzxyz"};
159 
160  for (unsigned int i = POSITION_X; i <= POSITION_Z; i++)
161  {
162  const bool visible = m_translation.find(axes[i]) != std::string::npos;
163  m_sliders[i].m_sliderValue->setVisible( visible );
164  m_sliders[i].m_labelMin->setVisible( visible );
165  m_sliders[i].m_labelMax->setVisible( visible );
166  m_sliders[i].m_labelDefinition->setVisible( visible );
167  m_sliders[i].m_slider->setVisible( visible );
168  }
169 
170  for (unsigned int i = ROTATION_X; i <= ROTATION_Z; i++)
171  {
172  m_sliders[i].m_labelMin->setText(std::to_string(m_rotationRange[0]).c_str());
173  m_sliders[i].m_labelMax->setText(std::to_string(m_rotationRange[1]).c_str());
174  m_sliders[i].m_slider->setRange(m_rotationRange[0], m_rotationRange[1]);
175  }
176 
177  for (unsigned int i = ROTATION_X; i <= ROTATION_Z; i++)
178  {
179  const bool visible = m_rotation.find(axes[i]) != std::string::npos;
180  m_sliders[i].m_sliderValue->setVisible( visible );
181  m_sliders[i].m_labelMin->setVisible( visible );
182  m_sliders[i].m_labelMax->setVisible( visible );
183  m_sliders[i].m_labelDefinition->setVisible( visible );
184  m_sliders[i].m_slider->setVisible( visible );
185  }
186 
187  this->updateFromMatrix();
188 }
189 
190 //------------------------------------------------------------------------------
191 
193 {
194  for (unsigned int i = 0; i < MAX_SLIDER_INDEX; i++)
195  {
196  QObject::disconnect(m_sliders[i].m_slider, SIGNAL(valueChanged(int)), this, SLOT(onSliderChanged(int)));
197  QObject::disconnect(m_sliders[i].m_sliderValue, SIGNAL(editingFinished()), this, SLOT(onTextChanged()));
198  }
199 
200  this->destroy();
201 }
202 
203 //------------------------------------------------------------------------------
204 
206 {
207  this->updateFromMatrix();
208 }
209 
210 //------------------------------------------------------------------------------
211 
212 void STransformEditor::onSliderChanged(int value)
213 {
214  ::fwData::TransformationMatrix3D::sptr matrix = this->getInOut< ::fwData::TransformationMatrix3D >("matrix");
215 
216  const double rx = ::glm::radians<double>(m_sliders[ROTATION_X].m_slider->value());
217  const double ry = ::glm::radians<double>(m_sliders[ROTATION_Y].m_slider->value());
218  const double rz = ::glm::radians<double>(m_sliders[ROTATION_Z].m_slider->value());
219 
220  const double tx = m_sliders[POSITION_X].m_slider->value();
221  const double ty = m_sliders[POSITION_Y].m_slider->value();
222  const double tz = m_sliders[POSITION_Z].m_slider->value();
223 
224  ::glm::dquat quat = ::glm::dquat(::glm::dvec3(rx, ry, rz));
225  ::glm::dmat4x4 mat = ::glm::mat4_cast(quat);
226 
227  mat[3] = ::glm::dvec4(tx, ty, tz, 1.);
228 
230 
231  for (unsigned int i = 0; i < MAX_SLIDER_INDEX; i++)
232  {
233  m_sliders[i].m_sliderValue->setText(QString("%1").arg(m_sliders[i].m_slider->value()));
234  }
235 
237  {
238  ::fwCom::Connection::Blocker block(sig->getConnection(m_slotUpdate));
239  sig->asyncEmit();
240  }
241 }
242 
243 //------------------------------------------------------------------------------
244 
245 void STransformEditor::onTextChanged()
246 {
247  for (unsigned int i = 0; i < MAX_SLIDER_INDEX; i++)
248  {
249  QString string = m_sliders[i].m_sliderValue->text();
250  m_sliders[i].m_slider->setValue(string.toInt());
251  }
252 }
253 
254 //------------------------------------------------------------------------------
255 
256 void STransformEditor::updateFromMatrix()
257 {
258  ::fwData::TransformationMatrix3D::sptr matrix = this->getInOut< ::fwData::TransformationMatrix3D >("matrix");
259 
260  SLM_ASSERT("Unable to get matrix", matrix);
261  const ::glm::dmat4x4 mat = ::fwDataTools::TransformationMatrix3D::getMatrixFromTF3D(matrix);
262 
263  const ::glm::dquat quat(mat);
264  const ::glm::dvec3 angles = ::glm::eulerAngles(quat);
265 
266  const ::glm::dvec4 translation = mat[3];
267 
268  // Block
269  for (unsigned int i = 0; i < MAX_SLIDER_INDEX; i++)
270  {
271  m_sliders[i].m_slider->blockSignals(true);
272  m_sliders[i].m_sliderValue->blockSignals(true);
273  }
274 
275  for (::glm::length_t i = POSITION_X, j = 0; i <= POSITION_Z; i++, ++j)
276  {
277  m_sliders[i].m_slider->setValue(static_cast<int>(translation[j]));
278  }
279 
280  for (::glm::length_t i = ROTATION_X, j = 0; i <= ROTATION_Z; i++, ++j)
281  {
282  m_sliders[i].m_slider->setValue(static_cast<int>(::glm::degrees<double>(angles[j])));
283  }
284 
285  for (unsigned int i = 0; i < MAX_SLIDER_INDEX; i++)
286  {
287  m_sliders[i].m_sliderValue->setText(QString("%1").arg(m_sliders[i].m_slider->value()));
288  }
289 
290  for (unsigned int i = 0; i < MAX_SLIDER_INDEX; i++)
291  {
292  m_sliders[i].m_slider->blockSignals(false);
293  m_sliders[i].m_sliderValue->blockSignals(false);
294  }
295 }
296 
297 //------------------------------------------------------------------------------
298 
299 } // namespace uiVisuQt
virtual UIVISUQT_API void starting() override
This method launches the fwGui::IGuiContainerSrv::create method.
virtual UIVISUQT_API void configuring() override
This method is used to configure the service parameters:
Class allowing to block a Connection.
Definition: Connection.hpp:20
UIVISUQT_API STransformEditor() noexcept
Constructor. Do nothing.
static FWDATATOOLS_API void setTF3DFromMatrix(::fwData::TransformationMatrix3D::sptr &_trf, const ::glm::dmat4x4 &_input)
Convert a GLM matrix into a fwData::TransformationMatrix3D.
Defines the service interface managing the editor service for object.
Definition: IEditor.hpp:25
FWGUI_API void destroy()
Stops sub-views and toobar services. Destroys view, sub-views and toolbar containers.
The namespace uiVisuQt supplies user interface editors done with Qt.
virtual UIVISUQT_API void updating() override
Updates Slider value.
virtual UIVISUQT_API void stopping() override
This method launches the fwGui::IGuiContainerSrv::destroy method.
UpdateSlotType::sptr m_slotUpdate
Slot to call update method.
Definition: IService.hpp:690
#define SLM_ERROR(message)
Definition: spyLog.hpp:272
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
This class represents a 3D transformation matrix (4x4).
FWGUI_API void create()
Creates view, sub-views and toolbar containers. Manages sub-views and toobar services.
static FWDATATOOLS_API::glm::dmat4x4 getMatrixFromTF3D(const ::fwData::TransformationMatrix3D::csptr &_trf)
Convert a fwData::TransformationMatrix3D into a GLM matrix.
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_MODIFIED_SIG
Key in m_signals map of signal m_sigModified.
virtual UIVISUQT_API ~STransformEditor() noexcept
Destructor. Do nothing.
This editor regulates the position and rotation defined in a transformation matrix.
FWGUI_API void initialize()
Initialize managers.
FWSERVICES_API ConfigType getConfigTree() const
Return the configuration, in an boost property tree.
Definition: IService.cpp:247