connect(m_mapEngine, SIGNAL(locationItemClicked(QList<QString>)),
m_ui, SIGNAL(locationItemClicked(QList<QString>)));
+
+ connect(m_mapEngine, SIGNAL(newMapResolution(qreal)),
+ m_ui, SIGNAL(newMapResolution(qreal)));
}
void SituareEngine::signalsFromSituareService()
const qreal DEFAULT_LONGITUDE = 0.0000; ///< Default longitude value
const qreal DEFAULT_LATITUDE = 0.0000; ///< Default latitude value
+const qreal EARTH_RADIUS = 6371.01; ///< Earth radius in km
+
const int GRID_PADDING = 1; ///< Grid padding used in tile grid calculation
const QString OSM_LICENSE = QString::fromUtf8("© OpenStreetMap contributors, CC-BY-SA");
return (centerTile != temp);
}
+qreal MapEngine::sceneResolution()
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ const int SHIFT = 200;
+ const int KM_TO_M = 1000;
+ qreal scale = (1 << (MAX_MAP_ZOOM_LEVEL - m_zoomLevel));
+ QPointF centerCoordinate = centerGeoCoordinate();
+ QPoint shiftedSceneCoordinate = QPoint(m_sceneCoordinate.x() + SHIFT*scale
+ , m_sceneCoordinate.y());
+ QPointF shiftedCoordinate = convertSceneCoordinateToLatLon(m_zoomLevel, shiftedSceneCoordinate);
+ qreal dist = greatCircleDistance(centerCoordinate, shiftedCoordinate) * KM_TO_M;
+ return (dist / SHIFT);
+}
+
void MapEngine::mapImageReceived(int zoomLevel, int x, int y, const QPixmap &image)
{
qDebug() << __PRETTY_FUNCTION__;
}
}
+qreal MapEngine::greatCircleDistance(QPointF firstLocation, QPointF secondLocation)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ const qreal TORAD = (M_PI/180);
+
+ qreal dLat = (secondLocation.y() - firstLocation.y())*TORAD;
+ qreal dLon = (secondLocation.x() - firstLocation.x())*TORAD;
+ qreal a = pow(sin(dLat/2),2) + cos(firstLocation.y()*TORAD) * cos(secondLocation.y()*TORAD)
+ * pow(sin(dLon/2),2);
+ qreal c = 2 * atan2(sqrt(a), sqrt(1-a));
+
+ return (EARTH_RADIUS * c);
+}
+
void MapEngine::receiveOwnLocation(User *user)
{
qDebug() << __PRETTY_FUNCTION__;
getTiles(sceneCoordinate);
m_mapScene->removeOutOfViewTiles();
}
+
+ emit newMapResolution(sceneResolution());
}
void MapEngine::setZoomLevel(int newZoomLevel)
emit maxZoomLevelReached();
else if (m_zoomLevel == MIN_VIEW_ZOOM_LEVEL)
emit minZoomLevelReached();
+
+ emit newMapResolution(sceneResolution());
}
void MapEngine::zoomIn()
static QPoint 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(QPointF firstLocation, QPointF secondLocation);
+
+ /**
* @brief MapEngine initializer
*
* Set initial location and zoom level for the engine. locationChanged and
static QString tilePath(int zoomLevel, int x, int y);
public slots:
+
/**
* @brief Slot to catch user own location data
*
bool isCenterTileChanged(QPoint sceneCoordinate);
/**
+ * @brief Calculate scale at the map center of the map in meters/pixel
+ *
+ * @return qreal Scale of the map in meters/pixel
+ */
+ qreal sceneResolution();
+
+ /**
* @brief Calculate maximum value for tile in this zoom level.
*
* @param zoomLevel zoom level
void minZoomLevelReached();
/**
+ * @brief Signal to pass the scale of the map to map scale
+ */
+ void newMapResolution(qreal scale);
+
+ /**
* @brief Request view changing zoom level
*
* @param newZoomLevel New zoom level
m_password(),
m_fullScreenButton(0),
m_webView(0),
+ m_mapScale(0),
m_cookieJar(0)
{
qDebug() << __PRETTY_FUNCTION__;
createMenus();
setWindowTitle(tr("Situare"));
- MapScale *mapScale = new MapScale(this);
- mapScale->move(50, 400);
-
// set stacking order of widgets
m_zoomButtonPanel->stackUnder(m_userPanel);
if(m_fullScreenButton) {
m_fullScreenButton->stackUnder(m_zoomButtonPanel);
m_osmLicense->stackUnder(m_fullScreenButton);
- } else
- m_osmLicense->stackUnder(m_zoomButtonPanel);
+ } else {
+ m_osmLicense->stackUnder(m_zoomButtonPanel);
+ }
m_ownLocationCrosshair->stackUnder(m_osmLicense);
-
- mapScale->stackUnder(m_ownLocationCrosshair);
-
- m_mapView->stackUnder(mapScale);
+ m_mapScale->stackUnder(m_ownLocationCrosshair);
+ m_mapView->stackUnder(m_mapScale);
this->toggleProgressIndicator(true);
buildOsmLicense();
buildManualLocationCrosshair();
buildFullScreenButton();
+ buildMapScale();
connect(m_mapView, SIGNAL(viewScrolled(QPoint)),
this, SIGNAL(mapViewScrolled(QPoint)));
connect(m_mapView, SIGNAL(viewResized(QSize)),
this, SLOT(drawFullScreenButton(QSize)));
+ connect(m_mapView, SIGNAL(viewResized(QSize)),
+ this, SLOT(drawMapScale(QSize)));
+
connect(m_mapView, SIGNAL(viewResizedNewSize(int, int)),
this, SLOT(setViewPortSize(int, int)));
this, SIGNAL(viewZoomFinished()));
}
+void MainWindow::buildMapScale()
+{
+ m_mapScale = new MapScale(this);
+ connect(this, SIGNAL(newMapResolution(qreal)),
+ m_mapScale, SLOT(updateMapResolution(qreal)));
+}
+
void MainWindow::buildOsmLicense()
{
qDebug() << __PRETTY_FUNCTION__;
}
}
+void MainWindow::drawMapScale(const QSize &size)
+{
+ const int LEFT_SCALE_MARGIN = 10;
+ const int BOTTOM_SCALE_MARGIN = 2;
+ qDebug() << __PRETTY_FUNCTION__ << size.width() << "x" << size.height();
+
+ m_mapScale->move(PANEL_PEEK_AMOUNT + LEFT_SCALE_MARGIN,
+ size.height() - m_mapScale->size().height() - BOTTOM_SCALE_MARGIN);
+}
+
void MainWindow::drawOsmLicense(const QSize &size)
{
qDebug() << __PRETTY_FUNCTION__ << size.width() << "x" << size.height();
class FacebookAuthentication;
class FriendListPanel;
+class MapScale;
class MapScene;
class MapView;
class SituareService;
void buildMap();
/**
+ * @brief Build map scale and connect slots
+ */
+ void buildMapScale();
+
+ /**
* @brief Build OSM license and connect slots
*/
void buildOsmLicense();
void drawFullScreenButton(const QSize &size);
/**
+ * @brief Slot for drawing the map distance scale
+ *
+ * @param size Size of the screen
+ */
+ void drawMapScale(const QSize &size);
+
+ /**
* @brief Slot for drawing the Open Street Map license text
*
* @param size Size of the screen
void minZoomLevelReached();
/**
+ * @brief Forwarding signal from MapEngine to MapScale
+ */
+ void newMapResolution(qreal scale);
+
+ /**
* @brief Signal for refreshing user data.
*
*/
QWebView *m_webView; ///< Shows facebook login page
FriendListPanel *m_friendsListPanel; ///< Instance of friends list panel
+ MapScale *m_mapScale; ///< Instance of the map scale
MapView *m_mapView; ///< Instance of the map view
NetworkCookieJar *m_cookieJar; ///< Placeholder for QNetworkCookies
PanelSideBar *m_userPanelSidebar; ///< User panel side bar
#include "mapscale.h"
#include <math.h>
-const int METRIC_STEP = 90; ///< TEST value in pixels
-const qreal KM_TO_MILE = 1.609344; ///< Kilometer to mile conversion value
-const int MAPSCALE_HEIGHT = 14; ///< Height of the the map scale
-const int BASELINE_Y = MAPSCALE_HEIGHT / 2; ///< Y position of the baseline
-const int MAPSCALE_STOP_HEIGHT = 7; ///< Height of each perpendicular stop on the scale
-
-const qreal INPUTVALUE = 450.35; ///< SIMULATED input value: meters/pixel
+const int TARGET_WIDTH = 140; ///< Target width of the scale in pixels
+const qreal M_TO_FT = 3.2808399; ///< Meter to feet conversion value
+const qreal FT_TO_MI = 5280; ///< Feet to mile conversion
+const qreal M_TO_KM = 1000; ///< Meters to kilometers conversion
+const int MAPSCALE_HEIGHT = 31; ///< Height of the the map scale
+const int CENTERLINE_Y = MAPSCALE_HEIGHT / 2; ///< Y position of the centerline
+const int MAPSCALE_STOP_HEIGHT = 7; ///< Height of each perpendicular stop on the scale
+const int SCALE_TEXT_X = 3; ///< X coordinate for the scale texts
MapScale::MapScale(QWidget *parent) :
- QWidget(parent)
+ QWidget(parent),
+ m_centerLineImperial(0),
+ m_centerLineMetric(0),
+ m_imperialText(""),
+ m_metricText("")
{
qDebug() << __PRETTY_FUNCTION__;
-// setAutoFillBackground(true);
+
+// updateMapScale(10.0);
setAttribute(Qt::WA_TransparentForMouseEvents, true);
}
qDebug() << __PRETTY_FUNCTION__;
Q_UNUSED(event);
- qreal gen_scale = METRIC_STEP * INPUTVALUE;
- qreal baseScale;
-
-
- baseScale = roundToBaseScale(gen_scale);
- qreal baseLineLength = baseScale / INPUTVALUE;
- qWarning() << gen_scale << ">" << baseScale << ">" << baseLineLength;
+ resize(ceil(fmax(m_centerLineMetric,m_centerLineImperial)) + 1, MAPSCALE_HEIGHT);
- QLineF BaseLine(0, BASELINE_Y, baseLineLength * KM_TO_MILE, BASELINE_Y);
- QLineF StartKm(1, BASELINE_Y, 1, (BASELINE_Y) - MAPSCALE_STOP_HEIGHT);
- QLineF StartMi(1, BASELINE_Y, 1, (BASELINE_Y) + MAPSCALE_STOP_HEIGHT);
- QLineF StopKm(baseLineLength, BASELINE_Y,
- baseLineLength, (BASELINE_Y) - MAPSCALE_STOP_HEIGHT);
- QLineF StopMi(baseLineLength * KM_TO_MILE, BASELINE_Y,
- baseLineLength * KM_TO_MILE, (BASELINE_Y) + MAPSCALE_STOP_HEIGHT);
+ QLineF centerLine(0, CENTERLINE_Y, fmax(m_centerLineMetric, m_centerLineImperial), CENTERLINE_Y);
+ QLineF startKm(1, CENTERLINE_Y, 1, CENTERLINE_Y - MAPSCALE_STOP_HEIGHT);
+ QLineF stopKm(m_centerLineMetric, CENTERLINE_Y,
+ m_centerLineMetric, CENTERLINE_Y - MAPSCALE_STOP_HEIGHT);
- resize(ceil(baseLineLength * KM_TO_MILE)+1, MAPSCALE_HEIGHT);
+ QLineF startMi(1, CENTERLINE_Y, 1, CENTERLINE_Y + MAPSCALE_STOP_HEIGHT);
+ QLineF stopMi(m_centerLineImperial, CENTERLINE_Y,
+ m_centerLineImperial, CENTERLINE_Y + MAPSCALE_STOP_HEIGHT);
QPainter painter(this);
QPen pen(Qt::black, 2);
+ painter.setFont(QFont("Nokia Sans", 13, QFont::Normal));
painter.setPen(pen);
- painter.drawLine(BaseLine);
- painter.drawLine(StartKm);
- painter.drawLine(StartMi);
- painter.drawLine(StopKm);
- painter.drawLine(StopMi);
+ painter.drawLine(centerLine);
+ painter.drawLine(startKm);
+ painter.drawLine(stopKm);
+ painter.drawText(SCALE_TEXT_X, MAPSCALE_HEIGHT / 2 - 2, m_metricText);
+
+ painter.drawLine(startMi);
+ painter.drawLine(stopMi);
+ painter.drawText(SCALE_TEXT_X, MAPSCALE_HEIGHT, m_imperialText);
}
qreal MapScale::roundToBaseScale(qreal value)
}
if(value < 0.15)
baseLine = 1;
- else if (value < 0.375)
+ else if (value < 0.35)
baseLine = 2;
else if (value < 0.75)
baseLine = 5;
else
baseLine = 10;
baseLine = baseLine * (pow(10,scale-1));
- qWarning() << baseLine;
return baseLine;
}
+
+void MapScale::updateMapResolution(const qreal &resolution)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+
+ //Calculate distance scale in metric units
+ qreal genericMetricScale = TARGET_WIDTH * resolution;
+ qreal baseMetricScale = roundToBaseScale(genericMetricScale);
+ if(resolution != 0)
+ m_centerLineMetric = baseMetricScale / resolution;
+ else
+ m_centerLineMetric = baseMetricScale / 0.000001;
+
+ if(baseMetricScale < M_TO_KM)
+ {
+ m_metricText.setNum(baseMetricScale);
+ m_metricText.append(" m");
+ } else {
+ m_metricText.setNum(baseMetricScale/M_TO_KM);
+ m_metricText.append(" km");
+ }
+
+ //Calculate distance scale in imperial units
+ qreal imperialScaleResolution = resolution * M_TO_FT;
+ qreal genericImperialScale = TARGET_WIDTH * imperialScaleResolution;
+ qreal baseImperialScale;
+
+ if(genericImperialScale < FT_TO_MI) {
+ baseImperialScale = roundToBaseScale(genericImperialScale);
+ if(imperialScaleResolution != 0)
+ m_centerLineImperial = baseImperialScale / imperialScaleResolution;
+ else
+ m_centerLineImperial = baseImperialScale / 0.000001;
+ m_imperialText.setNum(baseImperialScale);
+ m_imperialText.append(" ft");
+ } else {
+ baseImperialScale = roundToBaseScale(genericImperialScale / FT_TO_MI);
+ if(imperialScaleResolution != 0)
+ m_centerLineImperial = (baseImperialScale*FT_TO_MI) / imperialScaleResolution;
+ else
+ m_centerLineImperial = baseImperialScale / 0.000001;
+ m_imperialText.setNum(baseImperialScale);
+ m_imperialText.append(" mi");
+ }
+
+ update();
+}
#include <QWidget>
+class QLineF;
+
+/**
+ * @brief Map distance scale
+ *
+ * @author Kaj Wallin - kaj.wallin (at) ixonos.com
+ */
class MapScale : public QWidget
{
Q_OBJECT
public:
+ /**
+ * @brief Constructor
+ *
+ * @param parent Parent
+ */
MapScale(QWidget *parent = 0);
/*******************************************************************************
/**
* @brief Event handler for paint events
*
- * Paints the button and its icon
+ * Paints the scale
* @param event Paint event
*/
void paintEvent(QPaintEvent *event);
* MEMBER FUNCTIONS AND SLOTS
******************************************************************************/
private:
+ /**
+ * @brief Rounding function for distances
+ *
+ * Rounds the given value to closest 1,2,5 or 10 in the original scale
+ * @param value Value to be rounded
+ * @return qreal Rounded value
+ */
qreal roundToBaseScale(qreal value);
-public slots:
-/*******************************************************************************
- * SIGNALS
- ******************************************************************************/
-signals:
+public slots:
+ /**
+ * @brief Slot to update the scale with latest resolution
+ *
+ * @param resolution Resolution of the map in meters/pixel
+ */
+ void updateMapResolution(const qreal &resolution);
/*******************************************************************************
* DATA MEMBERS
******************************************************************************/
+private:
+ qreal m_centerLineImperial; ///< Length of the imperial scale
+ qreal m_centerLineMetric; ///< Length of the metric scale
+ QString m_imperialText; ///< Text description of the imperial scale
+ QString m_metricText; ///< Text description of the metric scale
};
#endif // MAPSCALE_H
* MEMBER FUNCTIONS AND SLOTS
******************************************************************************/
public:
+ /**
+ * @brief Relative position of the event inside the widget
+ */
const QPoint& eventPosition();
/*******************************************************************************
* @brief Constructor
*
* @param parent Parent
- * @param x Panel x coordinate
- * @param y Panel y coordinate
*/
ZoomButtonPanel(QWidget *parent = 0);