JoystickControlWidget.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 *
19 * @package ArmarX::RobotAPI
20 * @author Raphael Grimm <raphael dot grimm at kit dot edu>
21 * @date 2014
22 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
23 * GNU General Public License
24 */
25
27
28//qt
29#include <QBrush>
30#include <QColor>
31#include <QPen>
32#include <QSizePolicy>
33#include <QVBoxLayout>
34
35//std
36#include <cmath>
37#include <iostream>
38#include <memory>
39
40namespace armarx
41{
42
44 QWidget* parent) :
45 QGraphicsView{scene, parent}
46 {
47 }
48
50
51 void
53 {
54 emit positionChanged(mapToScene(event->pos()));
55 emit pressed();
56 }
57
58 void
60 {
61 emit positionChanged(mapToScene(event->pos()));
62 }
63
64 void
66 {
67 emit positionChanged({0, 0});
68 emit released();
69 }
70
71 JoystickControlWidget::JoystickControlWidget(bool useQuadrant3and4, QWidget* parent) :
72 QWidget{parent}, onlyQuadrant2and1{!useQuadrant3and4}, nibble{}, steps{0}
73 {
74 //build scene + use explicit pens (on some platforms the default ones dont have the desired default values)
75 std::unique_ptr<QGraphicsScene> scene{new QGraphicsScene{}};
76 QPen pen{Qt::black, 0};
77 //bounding circle
78 scene->addEllipse(-1, -1, 2, 2, pen);
79 //inner circle
80 scene->addEllipse(-0.13, -0.13, 0.26, 0.26, pen);
81 //cross
82 scene->addLine(0, -1, 0, 1, pen);
83 scene->addLine(-1, 0, 1, 0, pen);
84 //nibble
85 QPen penRed{Qt::darkRed};
86 penRed.setCosmetic(true);
87 nibble = scene->addEllipse(-0.1, -0.1, 0.2, 0.2, penRed, QBrush{Qt::darkRed});
88
89 //build view
90 std::unique_ptr<JoystickControlWidgetQGraphicsView> viewPtr{
91 new JoystickControlWidgetQGraphicsView{scene.release()}};
92 view = viewPtr.get();
93
94 view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
95 view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
96 view->setSceneRect(-1, -1, 2, (onlyQuadrant2and1 ? 1 : 2));
97
98 //connect
99 connect(viewPtr.get(), SIGNAL(positionChanged(QPointF)), this, SLOT(setNibble(QPointF)));
100 connect(viewPtr.get(), SIGNAL(released()), this, SLOT(mouseReleased()));
101 connect(viewPtr.get(), SIGNAL(pressed()), this, SIGNAL(pressed()));
102
103 //set gui
104 std::unique_ptr<QVBoxLayout> layout{new QVBoxLayout{}};
105 layout->setSpacing(0);
106 layout->setContentsMargins(0, 0, 0, 0);
107 layout->addWidget(viewPtr.release());
108 setLayout(layout.release());
109 }
110
111 QPointF
113 {
114 return nibble->pos();
115 }
116
117 double
119 {
120 //if the nibble is in the middle return the angle 0.
121 //otherwise use polar coordinates (up is 0, down pi, Quadrant I & IV are positive)
122 auto pos = getPosition();
123 auto length = std::hypot(pos.x(), pos.y());
124 auto normalized = pos / length;
125
126 if (length == 0)
127 {
128 return 0;
129 }
130 else
131 {
132 if (normalized.x() < 0)
133 {
134 return -std::acos(-normalized.y());
135 }
136 else
137 {
138 return std::acos(-normalized.y());
139 }
140 }
141 }
142
143 void
144 JoystickControlWidget::mouseReleased()
145 {
146 setNibble({0, 0});
147 emit released();
148 }
149
150 void
152 {
153 if (onlyQuadrant2and1 && (pos.y() > 0))
154 {
155 //project position to quadrant II & I
156 pos.setY(0);
157 }
158
159 auto length = std::hypot(pos.x(), pos.y());
160 auto normalized = pos / length;
161
162 if (length != 0)
163 {
164
165 if (steps == 0)
166 {
167 //dont snap
168 pos = (length > 1) ? normalized : pos;
169 }
170 else
171 {
172 //snapp to step
173 double stepSize = 1.0 / steps;
174 //length/(1.0/steps) => length*steps
175 // +0.3*stepSize => if the border of the step is more forgiving
176 double newLength =
177 static_cast<unsigned int>(length * steps + 0.3 * stepSize) * stepSize;
178 pos = std::fmin(1, newLength) * normalized;
179 }
180 }
181
182
183 //set position
184 nibble->setPos(pos);
185
186 //flip y (from downwards to upwards)
187 pos.setY(-pos.y());
188
189 //emit signals
190 emit positionChanged(pos);
191
193
194 emit changed(pos, getRotation());
195 }
196
197 void
199 {
200 int width;
201 int height;
202
203 //calculate size
204 if (onlyQuadrant2and1)
205 {
206 height = std::min(contentsRect().width() / 2, contentsRect().height());
207 width = height * 2;
208 }
209 else
210 {
211 width = std::min(contentsRect().width(), contentsRect().height());
212 height = width;
213 }
214
215 //if minsz=maxsz you block resizing
216 view->setMinimumSize(0.9 * width, 0.9 * height);
217 view->setMaximumSize(width, height);
218 auto viewScaleFactor = 0.49 * width;
219 view->setTransform(QTransform::fromScale(viewScaleFactor, viewScaleFactor));
220 }
221
222 void
224 {
225 steps = (stepCount < 0) ? 0 : stepCount;
226 }
227
228 int
230 {
231 return steps;
232 }
233} // namespace armarx
Provides the coordinates of mouse events through signals.
void mouseMoveEvent(QMouseEvent *event) override
Passes the mapped mouse coordinates of the event through the signal positionChanged.
void mousePressEvent(QMouseEvent *event) override
Passes the mapped mouse coordinates of the event through the signal positionChanged.
void pressed()
Emitted when the mouse was pressed.
JoystickControlWidgetQGraphicsView(QGraphicsScene *scene, QWidget *parent=nullptr)
void mouseReleaseEvent(QMouseEvent *) override
Passes (0;0) through the signal positionChanged.
void positionChanged(QPointF)
Sends the mouse position on press or move in the scene coordinates.
void released()
Emitted when the mouse was released.
double getRotation() const
f the control in polar coordinates (-pi,pi].
void changed(QPointF, double)
Passes the position and angle of the control in polar coordinates (-pi,pi].
void setSteps(int stepCount)
Sets the steps of the control.
QPointF getPosition() const
Returns the position of the nibble.
int getSteps()
Returns the steps of the control.
void setNibble(QPointF pos)
Sets the nibble to pos.
void pressed()
Emitted when the nibble was pressed.
void rotationChanged(double)
Passes the angle of the control in polar coordinates (-pi,pi].
void resizeEvent(QResizeEvent *event) override
JoystickControlWidget(bool useQuadrant3and4=true, QWidget *parent=0)
void positionChanged(QPointF)
Passes the position of the control.
void released()
Emitted when the nibble was released.
This file offers overloads of toIce() and fromIce() functions for STL container types.