00001
00029 #ifndef VELOCITYWIDGET_H_
00030 #define VELOCITYWIDGET_H_
00031
00032 #include <iostream>
00033 #include <math.h>
00034 #include <ros/ros.h>
00035 #include <boost/bind.hpp>
00036 #include <boost/thread.hpp>
00037 #include <QWidget>
00038 #include <QPainter>
00039 #include <QMouseEvent>
00040
00041 using namespace std;
00042
00043 typedef boost::function<void (double, double)> VelocityCallback;
00044
00045 namespace mr_rqt {
00046
00047 class VelocityWidget : public QWidget {
00048
00049 Q_OBJECT
00050
00051 public:
00052 VelocityWidget(QWidget* parent)
00053 : QWidget(parent),
00054 _linear(0),
00055 _angular(0),
00056 _maxLinear(1),
00057 _maxAngular(1),
00058 _linearPercent(0),
00059 _angularPercent(0),
00060 _minAngular(-1),
00061 _minLinear(-1),
00062 _visibleLinear(0),
00063 _visibleAngular(0),
00064 _mouseEnabled(false),
00065 _feedbackEnabled(true),
00066 _mouseDown(false),
00067 _zeroVelocityCounter(0),
00068 _inputTicks(0),
00069 _updateThread(boost::bind(&VelocityWidget::updateThread, this))
00070 {
00071
00072 connect(this, SIGNAL(redrawSignal()), this, SLOT(redraw()), Qt::QueuedConnection);
00073 }
00074
00075 ~VelocityWidget() {
00076 _updateThread.interrupt();
00077 _updateThread.join();
00078 }
00079
00080 void resetLimits() {
00081 _maxLinear = 0.1;
00082 _maxAngular = 0.1;
00083 }
00084
00085 void setLinear(double linear) {
00086
00087 if (_mouseEnabled && !_feedbackEnabled)
00088 return;
00089
00090 if (linear > _maxLinear)
00091 _maxLinear = (linear);
00092
00093 if (linear < _minLinear)
00094 _minLinear = linear;
00095
00096 _linear = linear;
00097
00098 if (linear >= 0)
00099 _linearPercent = _linear / _maxLinear * 100.0;
00100 else
00101 _linearPercent = -_linear / _minLinear * 100.0;
00102 }
00103
00104 void setAngular(double angular) {
00105
00106 if (_mouseEnabled && !_feedbackEnabled)
00107 return;
00108
00109 if (angular > _maxAngular)
00110 _maxAngular = (angular);
00111
00112 if (angular < _minAngular)
00113 _minAngular = angular;
00114
00115 _angular = angular;
00116
00117 if (angular >= 0)
00118 _angularPercent = _angular / _maxAngular * 100.0;
00119 else
00120 _angularPercent = -_angular / _minAngular * 100.0;
00121 }
00122
00123 void setVelocity(double linear, double angular) {
00124
00125 if (!_feedbackEnabled)
00126 return;
00127
00128 setLinear(linear);
00129 setAngular(angular);
00130
00131
00132 }
00133
00134 void setCallback(VelocityCallback callback) {
00135 _callback = callback;
00136 }
00137
00138 void enableMouseControl() {
00139 _mouseEnabled = true;
00140 }
00141
00142 void disableMouseControl() {
00143 _mouseEnabled = false;
00144 }
00145
00146 public slots:
00147
00148 void redraw() {
00149 update();
00150 }
00151
00152 signals:
00153
00154 void redrawSignal();
00155
00156 private:
00157
00158 volatile double _linear;
00159 volatile double _angular;
00160
00161 volatile double _maxLinear;
00162 volatile double _minLinear;
00163 volatile double _maxAngular;
00164 volatile double _minAngular;
00165
00166 volatile double _linearPercent;
00167 volatile double _angularPercent;
00168
00169 volatile double _visibleLinear;
00170 volatile double _visibleAngular;
00171
00172 bool _mouseEnabled;
00173 bool _feedbackEnabled;
00174 bool _mouseDown;
00175 int _zeroVelocityCounter;
00176 volatile long _inputTicks;
00177
00178 VelocityCallback _callback;
00179
00180 boost::thread _updateThread;
00181
00182 void updateThread() {
00183
00184 while(ros::ok() && !_updateThread.interruption_requested()) {
00185
00186
00187
00188 _visibleLinear += (_linearPercent - _visibleLinear)/ 2.0;
00189 _visibleAngular += (_angularPercent - _visibleAngular) / 2.0;
00190
00191
00192 if (fabs(_visibleLinear) < 0.0001)
00193 _visibleLinear = 0;
00194
00195 if (fabs(_visibleAngular) < 0.0001)
00196 _visibleAngular = 0;
00197
00198 emit redrawSignal();
00199
00200 if (!_mouseDown &&_inputTicks++ > 60)
00201 _feedbackEnabled = true;
00202 else
00203 _feedbackEnabled = false;
00204
00205 boost::this_thread::sleep(boost::posix_time::milliseconds(1000.0 / 60.0));
00206 }
00207 }
00208
00209 void limitVector(double& x, double& y, double maxRadius) {
00210 if (sqrt(x * x + y * y) > maxRadius) {
00211 double angle = atan2(y, x);
00212 x = cos(angle) * maxRadius;
00213 y = sin(angle) * maxRadius;
00214 }
00215 }
00216
00217 void drawBackground(QPainter& p, int width, int height) {
00218 QBrush brush(QColor::fromRgb(255, 255, 255, 255));
00219 p.setBrush(brush);
00220
00221 p.fillRect(0, 0, width, height, brush);
00222 }
00223
00224 void drawBorder(QPainter& p, int width, int height) {
00225 QPen pen(QColor::fromRgb(100, 100, 100, 0));
00226 p.setPen(pen);
00227
00228
00229 p.drawLine(0, 0, width, 0);
00230 p.drawLine(0, height - 1, width, height - 1);
00231
00232
00233 p.drawLine(0, 0, 0, height);
00234 p.drawLine(width - 1, 0, width - 1, height);
00235 }
00236
00237 void drawAxis(QPainter& p, int width, int height) {
00238 QPen pen(QColor::fromRgb(0, 0, 0, 30));
00239 pen.setDashOffset(3);
00240
00241 p.setPen(pen);
00242
00243
00244 p.drawLine(0, height / 2, width, height / 2);
00245
00246
00247 p.drawLine(width / 2, 0, width / 2, height);
00248 }
00249
00250 void drawCircles(QPainter& p, int width, int height) {
00251 QLinearGradient grad(0, 0, width, height);
00252 grad.setColorAt(1.0, QColor::fromRgb(180, 180, 180, 255));
00253 grad.setColorAt(0.0, QColor::fromRgb(220, 220, 220, 255));
00254
00255 QPen pen(QColor::fromRgb(50, 50, 50, 255));
00256 QBrush brush(grad);
00257 brush.setStyle(Qt::LinearGradientPattern);
00258 p.setBrush(brush);
00259 p.setPen(pen);
00260
00261 p.drawEllipse(0, 0, width - 1, height - 1);
00262
00263
00264 grad.setColorAt(0.0, QColor::fromRgb(180, 180, 180, 255));
00265 grad.setColorAt(1.0, QColor::fromRgb(220, 220, 220, 255));
00266 brush = QBrush(grad);
00267
00268 p.setPen(Qt::NoPen);
00269 p.setBrush(brush);
00270
00271 p.drawEllipse(20, 20, width - 1 - 20 * 2, height - 1 - 20 * 2);
00272 }
00273
00274 void drawPointer(QPainter& p, int x, int y, int width, int height, int size) {
00275
00276 int circleWidth = size * width / 100;
00277 int circleHeight = size * height / 100;
00278
00279 int circleX = x * width / 200 + width / 2;
00280 int circleY = y * height / 200 + height / 2;
00281
00282 circleX = circleX - circleWidth / 2;
00283 circleY = circleY - circleHeight / 2;
00284
00285
00286 QLinearGradient gradLine(width / 2, height / 2, circleX + circleWidth / 2, circleY + circleHeight / 2);
00287 gradLine.setColorAt(0.0, QColor(30, 30, 30));
00288 gradLine.setColorAt(0.5, QColor(100, 100, 100));
00289 gradLine.setColorAt(1.0, QColor(0, 0, 0));
00290 p.setPen(QPen(QBrush(gradLine), size / 1.1, Qt::SolidLine, Qt::RoundCap, Qt::BevelJoin));
00291 p.drawLine(width / 2, height / 2, circleX + circleWidth / 2, circleY + circleHeight / 2);
00292
00293
00294 QLinearGradient grad(circleX, circleY, circleX + circleWidth, circleY + circleHeight);
00295 grad.setColorAt(0.0, QColor::fromRgb(220, 0, 0, 255));
00296 grad.setColorAt(1.0, QColor::fromRgb(100, 0, 0, 255));
00297 QBrush brush(grad);
00298
00299 p.setPen(Qt::NoPen);
00300 p.setBrush(brush);
00301
00302 p.drawEllipse(circleX, circleY, circleWidth, circleHeight);
00303
00304
00305 grad.setColorAt(1.0, QColor::fromRgb(220, 0, 0, 255));
00306 grad.setColorAt(0.0, QColor::fromRgb(100, 0, 0, 255));
00307 brush = QBrush(grad);
00308
00309 p.setPen(Qt::NoPen);
00310 p.setBrush(brush);
00311
00312 p.drawEllipse(circleX + 5, circleY + 5, circleWidth - 10, circleHeight - 10);
00313 }
00314
00315 void drawJoystick(int linearPercent, int angularPercent) {
00316 QPainter painter(this);
00317
00318 double w = width();
00319 double h = height();
00320
00321 double linear = -linearPercent;
00322 double angular = -angularPercent;
00323
00324 limitVector(linear, angular, 70);
00325
00326 drawCircles(painter, w, h);
00327 drawPointer(painter, angular, linear, w, h, 30);
00328 }
00329
00330 void paintEvent(QPaintEvent *e)
00331 {
00332 drawJoystick(_visibleLinear, _visibleAngular);
00333 }
00334
00335 void mousePressEvent(QMouseEvent* e) {
00336 _mouseDown = true;
00337 _inputTicks = 0;
00338
00339 if (!_mouseEnabled)
00340 return;
00341
00342 mouseMoveEvent(e);
00343 }
00344
00345 void mouseMoveEvent(QMouseEvent* e) {
00346
00347 _inputTicks = 0;
00348
00349 if (!_mouseEnabled)
00350 return;
00351
00352 _linearPercent = (-e->pos().y() + width() / 2);
00353 _angularPercent = (-e->pos().x() + width() / 2);
00354
00355 if (!_callback.empty())
00356 _callback(_linearPercent, _angularPercent);
00357 }
00358
00359 void mouseReleaseEvent(QMouseEvent* e) {
00360
00361 _mouseDown = false;
00362 _inputTicks = 0;
00363
00364 if (!_mouseEnabled)
00365 return;
00366
00367 _linearPercent = (0);
00368 _angularPercent = (0);
00369
00370 if (!_callback.empty())
00371 _callback(_linearPercent, _angularPercent);
00372 }
00373
00374 void keyPressEvent(QKeyEvent* e) {
00375
00376 }
00377 };
00378
00379 }
00380
00381 #endif