--- /dev/null
+/*
+ * GPSData for Maemo.
+ * Copyright (C) 2011 Roman Moravcik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <QtGui>
+
+#include "compass.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#ifdef Q_WS_MAEMO_5
+#define LABEL_FONT_HIGH 44
+#else
+#define LABEL_FONT_HIGH 14
+#endif
+
+#ifdef Q_WS_MAEMO_5
+#define LABEL_FONT_SMALL 26
+#else
+#define LABEL_FONT_SMALL 8
+#endif
+
+#define GPS_MIN_GROUND_SPEED 1 /* 3.6 km/h */
+#define SENSOR_CALIBRATION_THRESHOLD 0.5
+
+#define WIDGET_MARGIN 8
+
+void Compass::updateWidget(const int azimuth, double calibration)
+{
+ m_azimuth = azimuth;
+ if (m_azimuth == 360)
+ m_azimuth = 0;
+
+ m_sensorCalibLevel = calibration;
+
+ if (calibration > 0) {
+ m_locked = true;
+
+ if (m_azimuth != m_compassAzimuth) {
+ if (m_rotateTimer->isActive())
+ m_rotateTimer->stop();
+
+ m_rotateTimer->start();
+ }
+ } else {
+ if (calibration == 0)
+ m_locked = false;
+
+ if (m_rotateTimer->isActive())
+ m_rotateTimer->stop();
+
+ update();
+ }
+}
+
+void Compass::updateWidget(const int azimuth, bool locked, int speed)
+{
+ m_azimuth = azimuth;
+ if (m_azimuth == 360)
+ m_azimuth = 0;
+
+ m_locked = locked;
+ m_gpsSpeed = speed;
+
+ if (speed >= GPS_MIN_GROUND_SPEED) {
+ if (m_azimuth != m_compassAzimuth) {
+ if (m_rotateTimer->isActive())
+ m_rotateTimer->stop();
+
+ m_rotateTimer->start();
+ }
+ } else {
+ if (m_rotateTimer->isActive())
+ m_rotateTimer->stop();
+
+ update();
+ }
+}
+
+void Compass::paintEvent(QPaintEvent * /* event */)
+{
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing);
+
+ double widget_width = 0;
+ double widget_height = 0;
+ double widget_x = 0;
+ double widget_y = 0;
+
+ if (rect().width() < rect().height()) {
+ /* Portrait orientation */
+ widget_width = rect().width() - 2 * WIDGET_MARGIN;
+ widget_height = widget_width;
+ widget_x = rect().x() + WIDGET_MARGIN;
+ widget_y = rect().y() + (rect().height() - widget_height) / 2.0;
+ } else {
+ /* Landscape orientation */
+ widget_height = rect().height() - 2 * WIDGET_MARGIN;
+ widget_width = widget_height;
+ widget_x = rect().x() + (rect().width() - widget_width) / 2.0;
+ widget_y = rect().y() + WIDGET_MARGIN;
+ }
+
+ /* Draw azimuth/warning */
+ paintAzimuth(painter, rect());
+
+ QMatrix matrix;
+ matrix.translate(widget_x + widget_width / 2.0, widget_y + widget_height / 2.0);
+ matrix.rotate(360 - m_compassAzimuth);
+ painter.setMatrix(matrix);
+
+ /* Draw compass */
+ QRectF compassArea(0, 0, widget_width, widget_height);
+ paintCompass(painter, compassArea);
+}
+
+void Compass::paintAzimuth(QPainter &painter, const QRectF &area)
+{
+ QFont font = QApplication::font();
+ font.setPointSize(LABEL_FONT_SMALL);
+ painter.setFont(font);
+ painter.setPen(QApplication::palette().color(QPalette::Text));
+
+ double azimuth_offset = (area.height() - area.width()) / 4.0 -
+ painter.fontMetrics().height() + 2.0 * WIDGET_MARGIN;
+ QRectF azimuthArea(area.x(), area.y() + azimuth_offset, area.width(), painter.fontMetrics().height());
+
+ if (m_locked) {
+ QString s;
+ QChar degree(0x00B0);
+
+ s = QString("%1%2")
+ .arg(QString::number(m_compassAzimuth))
+ .arg(degree);
+
+ if (m_type == Compass::Gps) {
+ if (m_gpsSpeed < GPS_MIN_GROUND_SPEED)
+ painter.setPen(m_azimuthLabelWarnColor);
+ } else if (m_type == Compass::Sensor) {
+ if (m_sensorCalibLevel < SENSOR_CALIBRATION_THRESHOLD)
+ painter.setPen(m_azimuthLabelWarnColor);
+ }
+ painter.drawText(azimuthArea, Qt::AlignCenter, s);
+ } else {
+ if (m_type == Compass::Gps)
+ painter.drawText(azimuthArea, Qt::AlignCenter, tr("GPS not locked"));
+ else if (m_type == Compass::Sensor)
+ painter.drawText(azimuthArea, Qt::AlignCenter, tr("Compass not calibrated"));
+ }
+}
+
+void Compass::paintCompass(QPainter &painter, const QRectF &area)
+{
+ double compass_radius = area.width() / 2.0;
+ double compass_x = area.x() - compass_radius;
+ double compass_y = area.y() - compass_radius;
+
+ /* Labels */
+ QString label[8] = {tr("N"), tr("NE"), tr("E"), tr("SE"), tr("S"), tr("SW"), tr("W"), tr("NW")};
+ double label_height = area.height() / 3.6;
+ double label_offset = area.width() / 14.4;
+ for (int i = 0; i < 8; i++) {
+ QFont font = QApplication::font();
+ double label_y;
+
+ if ((i % 2) == 0) {
+ font.setPointSize(LABEL_FONT_HIGH);
+ label_y = compass_y;
+ } else {
+ font.setPointSize(LABEL_FONT_SMALL);
+ label_y = compass_y + label_offset;
+ }
+ QRectF labelArea(compass_x, label_y, area.width(), label_height);
+ painter.setFont(font);
+ painter.drawText(labelArea, Qt::AlignCenter, label[i]);
+ painter.rotate(45);
+ }
+
+ /* Compass scale */
+ QRectF compassArea(compass_x, compass_y, area.width(), area.height());
+ painter.setPen(QPen(m_scaleColor, 3));
+ painter.drawArc(compassArea, 0, 5760);
+
+ for (int angle = 0; angle < 360; angle += 2) {
+ double angle_rad = angle * M_PI / 180.0;
+
+ double x1 = (compass_radius - (area.width() / 18.0)) * qCos(angle_rad);
+ double y1 = (compass_radius - (area.width() / 18.0)) * qSin(angle_rad);
+ double x2 = compass_radius * qCos(angle_rad);
+ double y2 = compass_radius * qSin(angle_rad);
+
+ if (angle % 30)
+ painter.setPen(QPen(m_scaleColor, 0));
+ else
+ painter.setPen(QPen(m_scaleColor, 3));
+
+ painter.drawLine(QLineF(x1, y1, x2, y2));
+ }
+
+ /* Compass windrose NE/SE/SW/NW */
+ painter.setPen(m_windroseBckColor);
+ for (int angle = 45; angle < 360; angle += 90) {
+ double angle_rad1 = angle * M_PI / 180.0;
+ double angle_rad2 = (angle - 90) * M_PI / 180.0;
+ double angle_rad3 = (angle + 90) * M_PI / 180.0;
+ double temp1 = compass_radius - (area.width() / 3.6);
+ double temp2 = area.width() / 16.0;
+
+ double x1 = temp1 * qCos(angle_rad1);
+ double y1 = temp1 * qSin(angle_rad1);
+ double x2 = temp2 * qCos(angle_rad2);
+ double y2 = temp2 * qSin(angle_rad2);
+ double x3 = temp2 * qCos(angle_rad3);
+ double y3 = temp2 * qSin(angle_rad3);
+ QPointF triangle1[3] = { QPointF(x1, y1), QPointF(x2, y2), QPointF(area.x(), area.y()) };
+ painter.setBrush(m_windroseBckColor);
+ painter.drawPolygon(triangle1, 3);
+
+ QPointF triangle2[3] = { QPointF(x1, y1), QPointF(x3, y3), QPointF(area.x(), area.y()) };
+ painter.setBrush(m_windroseColor);
+ painter.drawPolygon(triangle2, 3);
+ }
+
+ /* Compass windrose N/E/S/W */
+ for (int angle = 0; angle < 360; angle += 90) {
+ double angle_rad1 = angle * M_PI / 180.0;
+ double angle_rad2 = (angle - 45) * M_PI / 180.0;
+ double angle_rad3 = (angle + 45) * M_PI / 180.0;
+ double temp1 = compass_radius - (area.width() / 4.5);
+ double temp2 = area.width() / 16.0;
+
+ double x1 = temp1 * qCos(angle_rad1);
+ double y1 = temp1 * qSin(angle_rad1);
+ double x2 = temp2 * qCos(angle_rad2);
+ double y2 = temp2 * qSin(angle_rad2);
+ double x3 = temp2 * qCos(angle_rad3);
+ double y3 = temp2 * qSin(angle_rad3);
+ QPointF triangle1[3] = { QPointF(x1, y1), QPointF(x2, y2), QPointF(area.x(), area.y()) };
+ if (angle == 270)
+ painter.setBrush(m_windroseNorthColor);
+ else
+ painter.setBrush(m_windroseBckColor);
+
+ painter.drawPolygon(triangle1, 3);
+
+ QPointF triangle2[3] = { QPointF(x1, y1), QPointF(x3, y3), QPointF(area.x(), area.y()) };
+ painter.setBrush(m_windroseColor);
+ painter.drawPolygon(triangle2, 3);
+ }
+
+ /* Red cursor */
+ double x1 = area.x() + (area.width() / 12.0);
+ double y1 = compass_y - 5;
+ double x2 = area.x() - (area.width() / 12.0);
+ double y2 = compass_y - 5;
+ double x3 = area.x();
+ double y3 = compass_y + (area.height() / 18.0) - 5;
+ QPointF triangle[3] = { QPointF(x1, y1), QPointF(x2, y2), QPointF(x3, y3) };
+
+ painter.rotate(m_compassAzimuth - 360);
+ painter.setPen(m_windroseNorthColor);
+ painter.setBrush(m_windroseNorthColor);
+ painter.drawPolygon(triangle, 3);
+}
+
+void Compass::moveTimerEvent()
+{
+ if (m_locked)
+ {
+ int delta = qAbs(m_azimuth - m_compassAzimuth);
+ if (delta > 180)
+ delta = 360 - delta;
+
+ int step = 1;
+ if (delta > 30)
+ step = 4;
+ else if (delta > 20)
+ step = 3;
+ else if (delta > 10)
+ step = 2;
+ else
+ step = 1;
+
+ if (m_azimuth > m_compassAzimuth) {
+ if ((m_azimuth - m_compassAzimuth) < 180)
+ m_compassAzimuth += step;
+ else
+ m_compassAzimuth -= step;
+ } else {
+ if ((m_compassAzimuth - m_azimuth) < 180)
+ m_compassAzimuth -= step;
+ else
+ m_compassAzimuth += step;
+ }
+
+ if (m_compassAzimuth >= 360)
+ m_compassAzimuth = m_compassAzimuth - 360;
+ else if (m_compassAzimuth < 0)
+ m_compassAzimuth = 360 + m_compassAzimuth;
+
+ if (m_azimuth == m_compassAzimuth)
+ m_rotateTimer->stop();
+ } else {
+ m_rotateTimer->stop();
+ }
+
+ update();
+}
+
+#ifdef QT_NO_OPENGL
+Compass::Compass(CompassType type) : QWidget()
+#else
+Compass::Compass(CompassType type) : QGLWidget(QGLFormat(QGL::SampleBuffers), 0)
+#endif
+{
+ m_type = type;
+ m_compassAzimuth = 0;
+ m_azimuth = 0;
+ m_locked = false;
+ m_gpsSpeed = 0;
+ m_sensorCalibLevel = 0;
+
+ m_azimuthLabelWarnColor = QColor(255, 0, 0);
+ m_scaleColor = QColor(153, 153, 153);
+ m_windroseNorthColor = QColor(255, 0, 0);
+ m_windroseColor = QColor(153, 153, 153);
+ m_windroseBckColor = QColor(74, 69, 66);
+
+ m_rotateTimer = new QTimer();
+ m_rotateTimer->setInterval(70);
+ connect(m_rotateTimer, SIGNAL(timeout()), this, SLOT(moveTimerEvent()));
+}
+
+Compass::~Compass()
+{
+ if (m_rotateTimer->isActive())
+ m_rotateTimer->stop();
+}