setLongitude(longitude);
}
+qreal GeoCoordinate::distanceTo(const GeoCoordinate &other) const
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ const qreal EARTH_RADIUS = 6371.01; // Earth radius in km
+ const qreal TO_RAD = (M_PI / 180); // Conversion factor to radians
+ const int KM_TO_M = 1000; // Conversion from kilometers to meters
+
+ GeoCoordinate delta = other - *this;
+
+ qreal a = pow(sin(delta.latitude() * TO_RAD / 2), 2)
+ + cos(m_latitude * TO_RAD)
+ * cos(other.latitude() * TO_RAD)
+ * pow(sin(delta.longitude() * TO_RAD / 2), 2);
+ qreal c = 2 * atan2(sqrt(a), sqrt(1 - a));
+
+ return (EARTH_RADIUS * c * KM_TO_M);
+}
+
bool GeoCoordinate::isNull() const
{
qDebug() << __PRETTY_FUNCTION__;
m_validityFlags |= LongitudeSet;
}
+const GeoCoordinate operator-(const GeoCoordinate &coordinate1, const GeoCoordinate &coordinate2)
+{
+ return GeoCoordinate(coordinate1.m_latitude - coordinate2.m_latitude,
+ coordinate1.m_longitude - coordinate2.m_longitude);
+}
+
QDataStream &operator<<(QDataStream &out, const GeoCoordinate &coordinate)
{
out << coordinate.m_latitude << coordinate.m_longitude;
******************************************************************************/
public:
/**
+ * @brief Distance to other coordinate
+ *
+ * This calculation returns the great-circle distance between the two coordinates, with an
+ * assumption that the Earth is spherical. Calculation is done using haversine formula. Altitude
+ * is not used in the calculation.
+ *
+ * @param other Coordinate where the distance is calculated from this coordinate
+ * @returns Distance to other coordinate (in meters)
+ */
+ qreal distanceTo(const GeoCoordinate &other) const;
+
+ /**
* @brief Check if coordinate is (0.0, 0.0)
*
* @returns True if both latitude and longitude are 0.0, otherwise false
* OPERATORS
******************************************************************************/
public:
+ friend const GeoCoordinate operator-(const GeoCoordinate &coordinate1,
+ const GeoCoordinate &coordinate2);
+
/**
* @brief Output operator
*
{
qDebug() << __PRETTY_FUNCTION__;
- if (positionInfo.isAccurate())
- return positionInfo.accuracy();
- else
- return GPS_ACCURACY_UNDEFINED;
+ return positionInfo.accuracy();
}
coordinate.setLatitude(device->fix->latitude);
coordinate.setLongitude(device->fix->longitude);
positionInfo.setCoordinate(coordinate);
- }
+ }
}
wrapper->setLastKnownPosition(positionInfo);
emit wrapper->locationChanged(positionInfo);
#include "gpslocationitem.h"
+const qreal RING_OUTLINE_PEN_WIDTH = 1.0;
+
GPSLocationItem::GPSLocationItem()
- : m_showOnNextUpdate(true)
+ : m_showOnNextUpdate(true),
+ m_radius(3000)
{
qDebug() << __PRETTY_FUNCTION__;
- setPixmap(QPixmap(":/res/images/gps_position.png"));
+ m_pixmap = QPixmap(":/res/images/gps_position.png");
setPos(QPoint(UNDEFINED, UNDEFINED));
setZValue(OWN_LOCATION_ICON_Z_LEVEL);
- setOffset(-pixmap().width() / 2, -pixmap().height() / 2);
- setFlag(QGraphicsItem::ItemIgnoresTransformations);
+ //setOffset(-m_pixmap.width() / 2, -m_pixmap.height() / 2);
+// setFlag(QGraphicsItem::ItemIgnoresTransformations);
+}
+
+QRectF GPSLocationItem::boundingRect() const
+{
+ return QRectF(-m_radius - RING_OUTLINE_PEN_WIDTH / 2, -m_radius - RING_OUTLINE_PEN_WIDTH / 2,
+ 2 * m_radius + RING_OUTLINE_PEN_WIDTH, 2 * m_radius + RING_OUTLINE_PEN_WIDTH);
+}
+
+void GPSLocationItem::calculateAccuracyRingRadius()
+{
+ /// @todo calculate radius based on the current zoom level
+ m_radius;
}
void GPSLocationItem::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
- QGraphicsPixmapItem::paint(painter, option, widget);
+// QGraphicsPixmapItem::paint(painter, option, widget);
QColor color = QColor(Qt::red);
- const int OUTLINE_ALPHA = 96;
- const int FILL_ALPHA = 48;
+ const int RING_OUTLINE_ALPHA = 96;
+ const int RING_FILL_ALPHA = 48;
- color.setAlpha(OUTLINE_ALPHA);
- painter->setPen(color);
+ color.setAlpha(RING_OUTLINE_ALPHA);
+ QPen pen = QPen(color);
+ pen.setWidthF(RING_OUTLINE_PEN_WIDTH);
+ pen.setCosmetic(true);
+ painter->setPen(pen);
- color.setAlpha(FILL_ALPHA);
+ color.setAlpha(RING_FILL_ALPHA);
painter->setBrush(color);
painter->setRenderHint(QPainter::Antialiasing);
QPointF center = QPointF();
- qreal radius = 30;
- painter->drawEllipse(center, radius, radius);
+ painter->drawEllipse(center, m_radius, m_radius);
}
void GPSLocationItem::setEnabled(bool enable)
void GPSLocationItem::updatePosition(SceneCoordinate coordinate, qreal accuracy)
{
- qDebug() << __PRETTY_FUNCTION__;
+ qWarning() << __PRETTY_FUNCTION__ << "accuracy:" << accuracy;
setPos(coordinate.toPointF());
m_accuracy = accuracy;
#ifndef GPSLOCATIONITEM_H
#define GPSLOCATIONITEM_H
-#include <QGraphicsPixmapItem>
+#include <QGraphicsItem>
class SceneCoordinate;
/**
* @brief Class for indicating current position accuired from GPS on the map.
*
- * Also GPS fix accuracy is indicated by using two different color indicator images
- * based on current accuracy
+ * Also the GPS fix accuracy is indicated by the radius of the circle around the position item.
*/
-class GPSLocationItem : public QGraphicsPixmapItem
+class GPSLocationItem : public QGraphicsItem
{
public:
/**
******************************************************************************/
public:
/**
- * @brief Reimplementing the painter from QGraphicsPixmapItem
+ * @brief Implements the bounding rect
+ *
+ * @returns Bounding rect of the item
+ */
+ QRectF boundingRect() const;
+
+ /**
+ * @brief Implements the painter
*/
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
/**
* @brief Enable / disable item
*
+ * Actual enabling is done when next position update is received, so the old value before
+ * hiding the item is not used.
+ *
* @param enable True if item should be enabled, otherwise false
*/
void setEnabled(bool enable);
*/
void updatePosition(SceneCoordinate coordinate, qreal accuracy);
+private:
+ void calculateAccuracyRingRadius();
+
/*******************************************************************************
* DATA MEMBERS
******************************************************************************/
bool m_showOnNextUpdate; ///< should the item be shown when next update arrives
qreal m_accuracy; ///< current accuracy
+ qreal m_radius; ///< accuracy ring radius in scene pixels
+
+ QPixmap m_pixmap; ///< red led pixmap
};
#endif // GPSLOCATIONITEM_H
const double MIN_LONGITUDE = -180.0; ///< Minimum longitude value
const double MAX_LONGITUDE = 180.0; ///< Maximum longitude value
-const qreal EARTH_RADIUS = 6371.01; ///< Earth radius in km
-
const int MAP_GRID_PADDING = 0; ///< Grid padding used in tile grid calculation
const QString OSM_LICENSE = QString::fromUtf8("© OpenStreetMap contributors, CC-BY-SA");
}
}
-qreal MapEngine::greatCircleDistance(GeoCoordinate firstLocation, GeoCoordinate secondLocation)
-{
- qDebug() << __PRETTY_FUNCTION__;
-
- const qreal TO_RAD = (M_PI / 180);
-
- qreal dLat = (secondLocation.latitude() - firstLocation.latitude()) * TO_RAD;
- qreal dLon = (secondLocation.longitude() - firstLocation.longitude()) * TO_RAD;
- qreal a = pow(sin(dLat / 2), 2)
- + cos(firstLocation.latitude() * TO_RAD)
- * cos(secondLocation.latitude() * TO_RAD)
- * pow(sin(dLon / 2), 2);
- qreal c = 2 * atan2(sqrt(a), sqrt(1 - a));
-
- return (EARTH_RADIUS * c);
-}
-
void MapEngine::init()
{
qDebug() << __PRETTY_FUNCTION__;
qDebug() << __PRETTY_FUNCTION__;
const int SHIFT = 200;
- const int KM_TO_M = 1000;
+
qreal scale = (1 << (OSM_MAX_ZOOM_LEVEL - m_zoomLevel));
GeoCoordinate centerCoordinate = centerGeoCoordinate();
SceneCoordinate shiftedSceneCoordinate(m_sceneCoordinate.x() + SHIFT * scale,
m_sceneCoordinate.y());
GeoCoordinate shiftedCoordinate(shiftedSceneCoordinate);
- qreal dist = greatCircleDistance(centerCoordinate, shiftedCoordinate) * KM_TO_M;
+ qreal dist = centerCoordinate.distanceTo(shiftedCoordinate);
return (dist / SHIFT);
}
static SceneCoordinate convertTileNumberToSceneCoordinate(int zoomLevel, QPoint tileNumber);
/**
- * @brief Calculate great-circle distance between two geographic coordinates
- *
- * Calculate great-circle distance between two given geographic locations using
- * haversine formula
- *
- * @param firstLocation Coordinates of the first location
- * @param secondLocation Coordinates of the second location
- * @return qreal Distance in kilometers
- */
- qreal greatCircleDistance(GeoCoordinate firstLocation, GeoCoordinate secondLocation);
-
- /**
* @brief Set initial values for the map
*
* Set initial location and zoom level from the settings, if available, or use the default