Raised MapTile scene zValues for normal tiles.
[situare] / src / map / mapengine.cpp
1 /*
2    Situare - A location system for Facebook
3    Copyright (C) 2010  Ixonos Plc. Authors:
4
5        Sami Rämö - sami.ramo@ixonos.com
6        Jussi Laitinen - jussi.laitinen@ixonos.com
7
8    Situare is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License
10    version 2 as published by the Free Software Foundation.
11
12    Situare is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Situare; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
20    USA.
21 */
22
23 #include <QDebug>
24 #include <QString>
25 #include <QStringList>
26 #include <QUrl>
27
28 #include "mapengine.h"
29 #include "maptile.h"
30
31 #include <QtCore>
32 #include <QtGlobal>
33
34 MapEngine::MapEngine(QObject *parent)
35     : QObject(parent)
36     , m_zoomLevel(14)
37 {
38     m_mapScene = new MapScene(this);
39
40     m_mapFetcher = new MapFetcher(new QNetworkAccessManager(this), this);
41     connect(this, SIGNAL(fetchImage(QUrl)), m_mapFetcher, SLOT(fetchMapImage(QUrl)));
42     connect(m_mapFetcher, SIGNAL(mapImageReceived(QUrl,QPixmap)), this,
43             SLOT(mapImageReceived(QUrl, QPixmap)));
44 }
45
46 void MapEngine::init()
47 {
48     emit zoomLevelChanged(m_zoomLevel);
49     setViewLocation(QPointF(25.5000, 65.0000));
50
51 //    // Fetch some map tiles for demo purposes
52 //    for (int x=9351; x<=9354; x++) {
53 //        for (int y=4261; y<=4264; y++) {
54 //            QUrl url = buildURL(m_zoomLevel, QPoint(x, y));
55 //            m_mapFetcher->fetchMapImage(url);
56 //        }
57 //    }
58 }
59
60 void MapEngine::setViewLocation(QPointF latLonCoordinate)
61 {
62     qDebug() << __PRETTY_FUNCTION__;
63     setLocation(convertLatLonToSceneCoordinate(latLonCoordinate));
64 }
65
66 QUrl MapEngine::buildURL(int zoomLevel, QPoint tileNumbers)
67 {
68     QString url = QString("http://tile.openstreetmap.org/mapnik/%1/%2/%3.png")
69                   .arg(zoomLevel).arg(tileNumbers.x()).arg(tileNumbers.y());
70
71     return QUrl(url);
72 }
73
74 void MapEngine::parseURL(const QUrl &url, int &zoom, int &x, int &y)
75 {
76     QString path = url.path();
77     QStringList pathParts = path.split("/", QString::SkipEmptyParts);
78
79     int size = pathParts.size();
80
81     if (size < 3)
82         return;
83
84     zoom = (pathParts.at(size-3)).toInt();
85     x = (pathParts.at(size-2)).toInt();
86     QString yString = pathParts.at(size-1);
87     yString.chop(4);
88     y = yString.toInt();
89 }
90
91 void MapEngine::mapImageReceived(const QUrl &url, const QPixmap &pixmap)
92 {
93     int zoom = -1;
94     int x = -1;
95     int y = -1;
96
97     parseURL(url, zoom, x, y);
98
99     MapTile *mapTile = new MapTile();
100     mapTile->setZoomLevel(zoom);
101     mapTile->setTileNumber(QPoint(x, y));
102     mapTile->setPixmap(pixmap); 
103
104     if (!mapTilesInScene.contains(url.toString())) {
105         mapTilesInScene.insert(url.toString(), mapTile);
106         m_mapScene->addMapTile(mapTile);
107
108         qDebug() << "Tile count: " << mapTilesInScene.size();
109     }
110 }
111
112 QGraphicsScene* MapEngine::scene()
113 {
114     return dynamic_cast<QGraphicsScene *>(m_mapScene);
115 }
116
117 int MapEngine::tileMaxValue(int zoomLevel)
118 {
119     return (1 << zoomLevel) - 1;
120 }
121
122 QRect MapEngine::calculateGrid(QPointF sceneCoordinate)
123 {
124     QPoint tileCoordinate = convertSceneCoordinateToTileNumber(m_zoomLevel, sceneCoordinate);
125
126     int gridWidth = (m_viewSize.width()/TILE_SIZE_X + 1) + (GRID_PADDING*2);
127     int gridHeight = (m_viewSize.height()/TILE_SIZE_Y + 1) + (GRID_PADDING*2);
128
129     int topLeftX = tileCoordinate.x() - (gridWidth/2);
130     int topLeftY = tileCoordinate.y() - (gridHeight/2);
131
132    return QRect(topLeftX, topLeftY, gridWidth, gridHeight);
133 }
134
135 void MapEngine::setLocation(QPointF sceneCoordinate)
136 {
137     m_sceneCoordinate = sceneCoordinate;
138     emit locationChanged(m_sceneCoordinate);
139     calculateTileGrid();
140 }
141
142 void MapEngine::calculateTileGrid()
143 {
144     QRect grid = calculateGrid(m_sceneCoordinate);
145     int topLeftX = grid.topLeft().x();
146     int topLeftY = grid.topLeft().y();
147     int bottomRightX = grid.bottomRight().x();
148     int bottomRightY = grid.bottomRight().y();
149
150     int tileMaxVal = tileMaxValue(m_zoomLevel);
151
152     for (int x = topLeftX; x <= bottomRightX; ++x) {
153         for (int y = topLeftY; y <= bottomRightY; ++y) {
154
155             int tileX = x;
156             int tileY = y;
157
158             if (tileX < 0)
159                 tileX += tileMaxVal;
160             else if (tileX > tileMaxVal)
161                 tileX -= tileMaxVal;
162
163             if (tileY < 0)
164                 tileY += tileMaxVal;
165             else if (tileY > tileMaxVal)
166                 tileY -= tileMaxVal;
167
168             QUrl url = buildURL(m_zoomLevel, QPoint(tileX, tileY));
169
170             if (!mapTilesInScene.contains(url.toString())) {
171                 emit fetchImage(url);
172             }
173         }
174     }
175 }
176
177 void MapEngine::viewResized(const QSize &size)
178 {
179     m_viewSize = size;
180     setLocation(m_sceneCoordinate);
181 }
182
183 void MapEngine::zoomIn()
184 {
185     if (m_zoomLevel >= MAX_MAP_ZOOM_LEVEL)
186         return;
187
188     m_zoomLevel++;
189     emit zoomLevelChanged(m_zoomLevel);
190     /// @todo START FETCHING TILES
191     calculateTileGrid();
192 }
193
194 void MapEngine::zoomOut()
195 {
196     if (m_zoomLevel <= MIN_MAP_ZOOM_LEVEL)
197         return;
198
199     m_zoomLevel--;
200     emit zoomLevelChanged(m_zoomLevel);
201     /// @todo START FETCHING TILES
202     calculateTileGrid();
203 }