3 * Copyright (C) 2011 Roman Moravcik
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but 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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 # define M_PI 3.14159265358979323846
29 # define LABEL_FONT_HIGH 44
31 # define LABEL_FONT_HIGH 14
35 # define LABEL_FONT_SMALL 26
37 # define LABEL_FONT_SMALL 8
40 #define GPS_MIN_GROUND_SPEED 1 /* 3.6 km/h */
41 #define SENSOR_CALIBRATION_THRESHOLD 0.5
43 #define WIDGET_MARGIN 8
45 void Compass::updateWidget(const int azimuth, double calibration)
51 m_sensorCalibLevel = calibration;
53 if (calibration > 0) {
56 if (m_azimuth != m_compassAzimuth) {
57 if (m_rotateTimer->isActive())
58 m_rotateTimer->stop();
60 m_rotateTimer->start();
66 if (m_rotateTimer->isActive())
67 m_rotateTimer->stop();
73 void Compass::updateWidget(const int azimuth, bool locked, int speed)
82 if (speed >= GPS_MIN_GROUND_SPEED) {
83 if (m_azimuth != m_compassAzimuth) {
84 if (m_rotateTimer->isActive())
85 m_rotateTimer->stop();
87 m_rotateTimer->start();
90 if (m_rotateTimer->isActive())
91 m_rotateTimer->stop();
97 void Compass::paintEvent(QPaintEvent * /* event */)
99 QPainter painter(this);
100 painter.setRenderHint(QPainter::Antialiasing);
102 double widget_width = 0;
103 double widget_height = 0;
107 if (rect().width() < rect().height()) {
108 /* Portrait orientation */
109 widget_width = rect().width() - 2 * WIDGET_MARGIN;
110 widget_height = widget_width;
111 widget_x = rect().x() + WIDGET_MARGIN;
112 widget_y = rect().y() + (rect().height() - widget_height) / 2.0;
114 /* Landscape orientation */
115 widget_height = rect().height() - 2 * WIDGET_MARGIN;
116 widget_width = widget_height;
117 widget_x = rect().x() + (rect().width() - widget_width) / 2.0;
118 widget_y = rect().y() + WIDGET_MARGIN;
121 /* Draw azimuth/warning */
122 paintAzimuth(painter, rect());
125 matrix.translate(widget_x + widget_width / 2.0, widget_y + widget_height / 2.0);
126 matrix.rotate(360 - m_compassAzimuth);
127 painter.setMatrix(matrix);
130 QRectF compassArea(0, 0, widget_width, widget_height);
131 paintCompass(painter, compassArea);
134 void Compass::paintAzimuth(QPainter &painter, const QRectF &area)
136 QFont font = QApplication::font();
137 font.setPointSize(LABEL_FONT_SMALL);
138 painter.setFont(font);
139 painter.setPen(QApplication::palette().color(QPalette::Text));
141 double azimuth_offset = (area.height() - area.width()) / 4.0 -
142 painter.fontMetrics().height() + 2.0 * WIDGET_MARGIN;
143 QRectF azimuthArea(area.x(), area.y() + azimuth_offset, area.width(), painter.fontMetrics().height());
147 QChar degree(0x00B0);
150 .arg(QString::number(m_compassAzimuth))
153 if (m_type == Compass::Gps) {
154 if (m_gpsSpeed < GPS_MIN_GROUND_SPEED)
155 painter.setPen(m_azimuthLabelWarnColor);
156 } else if (m_type == Compass::Sensor) {
157 if (m_sensorCalibLevel < SENSOR_CALIBRATION_THRESHOLD)
158 painter.setPen(m_azimuthLabelWarnColor);
160 painter.drawText(azimuthArea, Qt::AlignCenter, s);
162 if (m_type == Compass::Gps)
163 painter.drawText(azimuthArea, Qt::AlignCenter, tr("GPS not locked"));
164 else if (m_type == Compass::Sensor)
165 painter.drawText(azimuthArea, Qt::AlignCenter, tr("Compass not calibrated"));
169 void Compass::paintCompass(QPainter &painter, const QRectF &area)
171 double compass_radius = area.width() / 2.0;
172 double compass_x = area.x() - compass_radius;
173 double compass_y = area.y() - compass_radius;
176 QString label[8] = {tr("N"), tr("NE"), tr("E"), tr("SE"), tr("S"), tr("SW"), tr("W"), tr("NW")};
177 double label_height = area.height() / 3.6;
178 double label_offset = area.width() / 14.4;
179 for (int i = 0; i < 8; i++) {
180 QFont font = QApplication::font();
184 font.setPointSize(LABEL_FONT_HIGH);
187 font.setPointSize(LABEL_FONT_SMALL);
188 label_y = compass_y + label_offset;
190 QRectF labelArea(compass_x, label_y, area.width(), label_height);
191 painter.setFont(font);
192 painter.drawText(labelArea, Qt::AlignCenter, label[i]);
197 QRectF compassArea(compass_x, compass_y, area.width(), area.height());
198 painter.setPen(QPen(m_scaleColor, 3));
199 painter.drawArc(compassArea, 0, 5760);
201 for (int angle = 0; angle < 360; angle += 2) {
202 double angle_rad = angle * M_PI / 180.0;
204 double x1 = (compass_radius - (area.width() / 18.0)) * qCos(angle_rad);
205 double y1 = (compass_radius - (area.width() / 18.0)) * qSin(angle_rad);
206 double x2 = compass_radius * qCos(angle_rad);
207 double y2 = compass_radius * qSin(angle_rad);
210 painter.setPen(QPen(m_scaleColor, 0));
212 painter.setPen(QPen(m_scaleColor, 3));
214 painter.drawLine(QLineF(x1, y1, x2, y2));
217 /* Compass windrose NE/SE/SW/NW */
218 painter.setPen(m_windroseBckColor);
219 for (int angle = 45; angle < 360; angle += 90) {
220 double angle_rad1 = angle * M_PI / 180.0;
221 double angle_rad2 = (angle - 90) * M_PI / 180.0;
222 double angle_rad3 = (angle + 90) * M_PI / 180.0;
223 double temp1 = compass_radius - (area.width() / 3.6);
224 double temp2 = area.width() / 16.0;
226 double x1 = temp1 * qCos(angle_rad1);
227 double y1 = temp1 * qSin(angle_rad1);
228 double x2 = temp2 * qCos(angle_rad2);
229 double y2 = temp2 * qSin(angle_rad2);
230 double x3 = temp2 * qCos(angle_rad3);
231 double y3 = temp2 * qSin(angle_rad3);
232 QPointF triangle1[3] = { QPointF(x1, y1), QPointF(x2, y2), QPointF(area.x(), area.y()) };
233 painter.setBrush(m_windroseBckColor);
234 painter.drawPolygon(triangle1, 3);
236 QPointF triangle2[3] = { QPointF(x1, y1), QPointF(x3, y3), QPointF(area.x(), area.y()) };
237 painter.setBrush(m_windroseColor);
238 painter.drawPolygon(triangle2, 3);
241 /* Compass windrose N/E/S/W */
242 for (int angle = 0; angle < 360; angle += 90) {
243 double angle_rad1 = angle * M_PI / 180.0;
244 double angle_rad2 = (angle - 45) * M_PI / 180.0;
245 double angle_rad3 = (angle + 45) * M_PI / 180.0;
246 double temp1 = compass_radius - (area.width() / 4.5);
247 double temp2 = area.width() / 16.0;
249 double x1 = temp1 * qCos(angle_rad1);
250 double y1 = temp1 * qSin(angle_rad1);
251 double x2 = temp2 * qCos(angle_rad2);
252 double y2 = temp2 * qSin(angle_rad2);
253 double x3 = temp2 * qCos(angle_rad3);
254 double y3 = temp2 * qSin(angle_rad3);
255 QPointF triangle1[3] = { QPointF(x1, y1), QPointF(x2, y2), QPointF(area.x(), area.y()) };
257 painter.setBrush(m_windroseNorthColor);
259 painter.setBrush(m_windroseBckColor);
261 painter.drawPolygon(triangle1, 3);
263 QPointF triangle2[3] = { QPointF(x1, y1), QPointF(x3, y3), QPointF(area.x(), area.y()) };
264 painter.setBrush(m_windroseColor);
265 painter.drawPolygon(triangle2, 3);
269 double x1 = area.x() + (area.width() / 12.0);
270 double y1 = compass_y - 5;
271 double x2 = area.x() - (area.width() / 12.0);
272 double y2 = compass_y - 5;
273 double x3 = area.x();
274 double y3 = compass_y + (area.height() / 18.0) - 5;
275 QPointF triangle[3] = { QPointF(x1, y1), QPointF(x2, y2), QPointF(x3, y3) };
277 painter.rotate(m_compassAzimuth - 360);
278 painter.setPen(m_windroseNorthColor);
279 painter.setBrush(m_windroseNorthColor);
280 painter.drawPolygon(triangle, 3);
283 void Compass::moveTimerEvent()
287 int delta = qAbs(m_azimuth - m_compassAzimuth);
301 if (m_azimuth > m_compassAzimuth) {
302 if ((m_azimuth - m_compassAzimuth) < 180)
303 m_compassAzimuth += step;
305 m_compassAzimuth -= step;
307 if ((m_compassAzimuth - m_azimuth) < 180)
308 m_compassAzimuth -= step;
310 m_compassAzimuth += step;
313 if (m_compassAzimuth >= 360)
314 m_compassAzimuth = m_compassAzimuth - 360;
315 else if (m_compassAzimuth < 0)
316 m_compassAzimuth = 360 + m_compassAzimuth;
318 if (m_azimuth == m_compassAzimuth)
319 m_rotateTimer->stop();
321 m_rotateTimer->stop();
328 Compass::Compass(CompassType type) : QGLWidget(QGLFormat(QGL::SampleBuffers), 0)
330 Compass::Compass(CompassType type) : QWidget()
334 m_compassAzimuth = 0;
338 m_sensorCalibLevel = 0;
340 m_azimuthLabelWarnColor = QColor(255, 0, 0);
341 m_scaleColor = QColor(153, 153, 153);
342 m_windroseNorthColor = QColor(255, 0, 0);
343 m_windroseColor = QColor(153, 153, 153);
344 m_windroseBckColor = QColor(74, 69, 66);
346 m_rotateTimer = new QTimer();
347 m_rotateTimer->setInterval(70);
348 connect(m_rotateTimer, SIGNAL(timeout()), this, SLOT(moveTimerEvent()));
353 if (m_rotateTimer->isActive())
354 m_rotateTimer->stop();