GCC Code Coverage Report


Directory: plugins/
File: plugins/hppwidgetsplugin/pathplayer.cc
Date: 2024-12-13 15:51:58
Exec Total Coverage
Lines: 0 191 0.0%
Branches: 0 304 0.0%

Line Branch Exec Source
1 //
2 // Copyright (c) CNRS
3 // Authors: Joseph Mirabel
4 //
5
6 #include "hppwidgetsplugin/pathplayer.hh"
7
8 #include <assert.h>
9
10 #include <QProgressDialog>
11 #include <QSlider>
12 #include <sstream>
13 #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
14 #include <QtCore>
15 #else
16 #include <QtConcurrent>
17 #endif
18
19 #include <gepetto/gui/action-search-bar.hh>
20 #include <gepetto/gui/osgwidget.hh>
21 #include <gepetto/gui/windows-manager.hh>
22 #include <hpp/corbaserver/client.hh>
23 #include <hppwidgetsplugin/hppwidgetsplugin.hh>
24
25 #include "gepetto/gui/mainwindow.hh"
26 #include "hppwidgetsplugin/conversions.hh"
27 #include "hppwidgetsplugin/joint-action.hh"
28 #include "hppwidgetsplugin/ui_pathplayerwidget.h"
29
30 namespace hpp {
31 namespace gui {
32 using gepetto::gui::ActionSearchBar;
33 using gepetto::gui::MainWindow;
34
35 PathPlayer::PathPlayer(HppWidgetsPlugin* plugin, QWidget* parent)
36 : QWidget(parent),
37 ui_(new ::Ui::PathPlayerWidget),
38 timerId_(0),
39 velocity_(false),
40 plugin_(plugin) {
41 ui_->setupUi(this);
42 pathIndex()->setMaximum(0);
43 connect(pathSlider(), SIGNAL(sliderMoved(int)), this,
44 SLOT(pathSliderChanged(int)));
45 connect(pathIndex(), SIGNAL(valueChanged(int)), this,
46 SLOT(pathIndexChanged(int)));
47 connect(playPause(), SIGNAL(toggled(bool)), this,
48 SLOT(playPauseToggled(bool)));
49 connect(stop(), SIGNAL(clicked()), this, SLOT(stopClicked()));
50 connect(ui_->refreshButton_path, SIGNAL(clicked()), this, SLOT(update()));
51
52 initSearchActions();
53 }
54
55 PathPlayer::~PathPlayer() { delete ui_; }
56
57 void PathPlayer::initSearchActions() {
58 ActionSearchBar* asb = MainWindow::instance()->actionSearchBar();
59 JointAction* a;
60
61 a = new JointAction(tr("Display &waypoints of selected path"),
62 plugin_->jointTreeWidget(), this);
63 connect(a, SIGNAL(triggered(std::string)),
64 SLOT(displayWaypointsOfPath(std::string)));
65 asb->addAction(a);
66
67 a = new JointAction(tr("Display selected &path"), plugin_->jointTreeWidget(),
68 this);
69 connect(a, SIGNAL(triggered(std::string)), SLOT(displayPath(std::string)));
70 asb->addAction(a);
71
72 {
73 QAction* a = new QAction(tr("Play path"), this);
74 playPause()->connect(a, SIGNAL(triggered()), SLOT(toggle()));
75 asb->addAction(a);
76 }
77 }
78
79 void PathPlayer::displayWaypointsOfPath(const std::string jointName) {
80 gepetto::gui::MainWindow* main = gepetto::gui::MainWindow::instance();
81 if (!pathIndex()->isEnabled()) {
82 main->logError("There is no path. Did you solve a problem ?");
83 return;
84 }
85 int pid = pathIndex()->value();
86 std::stringstream ss;
87 ss << "path" << pid << "_" << jointName;
88 std::string pn = ss.str();
89 const osgVector4 colorN(0.f, 0.f, 1.f, 1.f), colorE(1.f, 0.f, 0.f, 1.f);
90 gepetto::gui::WindowsManagerPtr_t wsm = main->osg();
91 HppWidgetsPlugin::HppClient* hpp = plugin_->client();
92 hpp::floatSeq_var times;
93 hpp::floatSeqSeq_var waypoints =
94 hpp->problem()->getWaypoints((CORBA::ULong)pid, times.out());
95 if (!wsm->getGroup(pn, false)) {
96 wsm->createGroup(pn);
97 wsm->addToGroup(pn, "hpp-gui");
98 }
99 // Temporary object to avoid dynamic allocation.
100 // Arguments are max, length, storage, take ownership.
101 char* tmps[1];
102 hpp::Names_t names(1, 1, tmps, false);
103 gepetto::viewer::Configuration pos;
104 ::osg::Vec3ArrayRefPtr posSeq = new ::osg::Vec3Array;
105 for (unsigned int i = 0; i < waypoints->length(); ++i) {
106 // Make name
107 ss.clear();
108 ss.str(std::string());
109 ss << pn << "/node" << i;
110 std::string xyzName = ss.str();
111 // Get positions
112 names[0] = jointName.c_str();
113 hpp::TransformSeq_var Ts =
114 hpp->robot()->getJointsPosition(waypoints[i], names);
115 fromHPP(Ts[0], pos);
116 posSeq->push_back(pos.position);
117 // Create the nodes
118 if (wsm->nodeExists(xyzName)) wsm->deleteNode(xyzName, false);
119 wsm->addXYZaxis(xyzName, colorN, 0.01f, 0.05f);
120 wsm->applyConfiguration(xyzName, pos);
121 }
122 wsm->addCurve(pn + "/curve", posSeq, colorE);
123 wsm->refresh();
124 }
125
126 void PathPlayer::displayPath(const std::string jointName) {
127 QFutureWatcher<void>* fw = new QFutureWatcher<void>(this);
128 QProgressDialog* pd = new QProgressDialog(
129 "Computing curved path. Please wait...", "Cancel", 0, 100, this);
130 connect(this, SIGNAL(displayPath_status(int)), pd, SLOT(setValue(int)));
131 pd->setCancelButton(0);
132 pd->setRange(0, 100);
133 pd->show();
134 fw->setFuture(
135 QtConcurrent::run(this, &PathPlayer::displayPath_impl, jointName));
136 connect(fw, SIGNAL(finished()), pd, SLOT(deleteLater()));
137 connect(fw, SIGNAL(finished()), fw, SLOT(deleteLater()));
138 }
139
140 void PathPlayer::displayPath_impl(const std::string jointName) {
141 gepetto::gui::MainWindow* main = gepetto::gui::MainWindow::instance();
142 if (!pathIndex()->isEnabled()) {
143 main->logError("There is no path. Did you solve a problem ?");
144 emit displayPath_status(100);
145 return;
146 }
147 CORBA::ULong pid = (CORBA::ULong)pathIndex()->value();
148 std::stringstream ss;
149 ss << "curvedpath_" << pid << "_" << jointName;
150 std::string pn = ss.str();
151 gepetto::viewer::WindowsManager::Color_t colorE(1.f, 0.f, 0.f, 1.f);
152 gepetto::gui::WindowsManagerPtr_t wsm = main->osg();
153 HppWidgetsPlugin::HppClient* hpp = plugin_->client();
154 CORBA::Double length = hpp->problem()->pathLength(pid);
155 double dt = lengthBetweenRefresh();
156 CORBA::ULong nbPos = (CORBA::ULong)(length / dt) + 1;
157 osgVector3 pos;
158 ::osg::Vec3ArrayRefPtr posSeq = new ::osg::Vec3Array;
159 // Temporary object to avoid dynamic allocation.
160 // Arguments are max, length, storage, take ownership.
161 char* tmps[1];
162 hpp::Names_t names(1, 1, tmps, false);
163 float statusStep = 100.f / (float)nbPos;
164 emit displayPath_status(0);
165 for (CORBA::ULong i = 0; i < nbPos; ++i) {
166 double t = std::min(i * dt, length);
167 hpp::floatSeq_var q = hpp->problem()->configAtParam(pid, t);
168 names[0] = jointName.c_str();
169 hpp::TransformSeq_var Ts = hpp->robot()->getJointsPosition(q.in(), names);
170 fromHPP(Ts[0], pos);
171 posSeq->push_back(pos);
172 emit displayPath_status(qFloor((float)i * statusStep));
173 }
174 if (wsm->nodeExists(pn)) wsm->deleteNode(pn, true);
175 wsm->addCurve(pn, posSeq, colorE);
176 wsm->addToGroup(pn.c_str(), "hpp-gui");
177 wsm->refresh();
178 emit displayPath_status(100);
179 }
180
181 void PathPlayer::update() {
182 CORBA::Long nbPath = plugin_->client()->problem()->numberPaths();
183 if (nbPath > 0) {
184 pathIndex()->setEnabled(true);
185 pathSlider()->setEnabled(true);
186 playPause()->setEnabled(true);
187 stop()->setEnabled(true);
188 if (pathIndex()->maximum() == 0) {
189 // If path index value is 0, no signal valueChanged will
190 // be emitted. Force a value changed.
191 if (pathIndex()->value() == 0) pathIndexChanged(0);
192 }
193 pathIndex()->setMaximum(nbPath - 1);
194 pathIndex()->setValue(nbPath - 1);
195 } else {
196 pathIndex()->setEnabled(false);
197 pathSlider()->setEnabled(false);
198 playPause()->setEnabled(false);
199 stop()->setEnabled(false);
200 }
201 }
202
203 void PathPlayer::setRobotVelocity(bool set) { velocity_ = set; }
204
205 void PathPlayer::pathIndexChanged(int i) {
206 assert(i >= 0);
207 pathLength_ = plugin_->client()->problem()->pathLength((short unsigned int)i);
208 timeSpinBox()->setValue(pathLength_);
209 currentParam_ = 0;
210 }
211
212 void PathPlayer::pathSliderChanged(int value) {
213 // The user moved the slider manually.
214 currentParam_ = sliderToLength(value);
215 updateConfiguration();
216 }
217
218 void PathPlayer::playPauseToggled(bool toggled) {
219 if (toggled) {
220 if (timerId_ == 0) timerId_ = startTimer(timeBetweenRefresh());
221 } else {
222 killTimer(timerId_);
223 timerId_ = 0;
224 }
225 }
226
227 void PathPlayer::stopClicked() {
228 // Pause
229 playPause()->setChecked(false);
230 // Reset current position.
231 currentParam_ = 0;
232 pathSlider()->setSliderPosition(0);
233 updateConfiguration();
234 }
235
236 void PathPlayer::pathPulse() {
237 if (playPause()->isChecked()) {
238 // Stil playing
239 currentParam_ += lengthBetweenRefresh();
240 if (currentParam_ > pathLength_) {
241 currentParam_ = pathLength_;
242 playPause()->setChecked(false);
243 }
244 pathSlider()->setSliderPosition(lengthToSlider(currentParam_));
245 updateConfiguration();
246 }
247 }
248
249 void PathPlayer::setCurrentTime(const double& param) {
250 if (!pathIndex()->isEnabled()) return;
251 if (currentParam_ > pathLength_) currentParam_ = pathLength_;
252 if (0 < currentParam_) currentParam_ = 0;
253 currentParam_ = param;
254 pathSlider()->setSliderPosition(lengthToSlider(currentParam_));
255 updateConfiguration();
256 }
257
258 void PathPlayer::timerEvent(QTimerEvent* event) {
259 if (timerId_ == event->timerId()) {
260 pathPulse();
261 }
262 }
263
264 void PathPlayer::updateConfiguration() {
265 gepetto::gui::MainWindow* main = gepetto::gui::MainWindow::instance();
266 hpp::floatSeq_var config, velocity;
267 try {
268 config = plugin_->client()->problem()->configAtParam(
269 (CORBA::ULong)pathIndex()->value(), currentParam_);
270 if (velocity_)
271 velocity = plugin_->client()->problem()->derivativeAtParam(
272 (CORBA::ULong)pathIndex()->value(), 1, currentParam_);
273 } catch (const hpp::Error& e) {
274 main->logError(e.msg.in());
275 return;
276 }
277 plugin_->currentConfig() = config.in();
278 if (velocity_) plugin_->currentVelocity() = velocity.in();
279 main->requestApplyCurrentConfiguration();
280 emit appliedConfigAtParam(getCurrentPath(), currentParam_);
281 }
282
283 inline double PathPlayer::sliderToLength(int v) const {
284 return ((double)v / (double)pathSlider()->maximum()) * pathLength_;
285 }
286
287 int PathPlayer::lengthToSlider(double l) const {
288 return (int)(pathSlider()->maximum() * l / pathLength_);
289 }
290
291 inline double PathPlayer::timeToLength(double time) const {
292 if (timeSpinBox()->value() == 0) return time;
293 return time * pathLength_ / timeSpinBox()->value();
294 }
295
296 inline int PathPlayer::timeBetweenRefresh() const {
297 gepetto::gui::MainWindow* main = gepetto::gui::MainWindow::instance();
298 return main->settings_->refreshRate;
299 }
300
301 double PathPlayer::lengthBetweenRefresh() const {
302 if (timeSpinBox()->value() == 0) return timeBetweenRefresh() / 1000;
303 return pathLength_ * timeBetweenRefresh() / (1000 * timeSpinBox()->value());
304 }
305
306 QDoubleSpinBox* PathPlayer::timeSpinBox() const { return ui_->timeSpinBox; }
307
308 QSpinBox* PathPlayer::pathIndex() const { return ui_->pathIndexSpin; }
309
310 QSlider* PathPlayer::pathSlider() const { return ui_->pathSlider; }
311
312 QPushButton* PathPlayer::playPause() const { return ui_->playPauseButton; }
313
314 QPushButton* PathPlayer::stop() const { return ui_->stopButton; }
315
316 int PathPlayer::getCurrentPath() const {
317 if (!pathIndex()->isEnabled()) return -1;
318 return pathIndex()->value();
319 }
320 } // namespace gui
321 } // namespace hpp
322