6 #include <QNetworkDiskCache>
7 #include <QDesktopServices>
13 ThreadSaver::ThreadSaver(QImage qi, QString fs){
18 void ThreadSaver::run(){
20 QFile file(fileString);
22 if (!file.open(QIODevice::WriteOnly)) {
23 qDebug() << QString("Cannot open file for writing: %1").arg(file.errorString());
31 TilesMap::TilesMap(QNetworkSession *session, QObject *parent = 0, Log* log=0, int zoom=0, MapType mapType=MapTypeOpenStreetMaps) :
41 height(HEIGHT_DEFAULT),
44 m_mapsDir = QDir(QString(APPLICATION_PATH).append(MAPS_DIR));
45 m_manager = new QNetworkAccessManager(this);
47 // Creating and fullfill emptytile
48 m_emptyTile = QPixmap(tdim, tdim);
49 m_emptyTile.fill(Qt::lightGray);
51 //log->debug(QString("Is Network accessible?:%1").arg(m_manager->networkAccessible()));
52 QNetworkDiskCache *cache = new QNetworkDiskCache;
53 cache->setCacheDirectory(QDesktopServices::storageLocation(QDesktopServices::CacheLocation));
54 m_manager->setCache(cache);
55 connect(m_manager, SIGNAL(finished(QNetworkReply*)),
56 this, SLOT(handleReplies(QNetworkReply*)));
58 //log->debug("exiting from slippyMap constructor!!!!");
62 TilesMap::~TilesMap() {
63 for (int i = 0; i < m_pendingReplies.size(); ++i) {
64 delete m_pendingReplies.at(i);
70 QPointF TilesMap::coordinate2tile(qreal lat, qreal lng, int zoom)
72 qreal zn = static_cast<qreal>(1 << zoom);
73 qreal tx = (lng + 180.0) / 360.0 * zn;
74 qreal ty = (1.0 - log(tan(lat * PI / 180.0) + 1.0 / cos(lat * PI / 180.0)) / PI) / 2.0 * zn;
75 return QPointF(tx, ty);
79 qreal TilesMap::tilex2long(qreal x, int zoom)
81 return (x / pow(2.0, zoom) * 360.0 - 180);
84 qreal TilesMap::tiley2lat(qreal y, int zoom)
86 qreal n = M_PI - 2.0 * M_PI * y / pow(2.0, zoom);
87 return 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n)));
90 void TilesMap::updateTiles(){
91 updateTiles(latitude,longitude);
94 void TilesMap::updateTiles(qreal lat, qreal lng){
96 if (width <= 0 || height <= 0 || (lat==0 && lng==0))
101 QPointF center = coordinate2tile(latitude,longitude,zoom);
103 // getting top-left corner of the centered tile
104 QPoint topLeft = QPoint(width / 2 - (center.x() - floor(center.x())) * tdim,height / 2 - (center.y() - floor(center.y())) * tdim);
106 // getting first tile vertical and horizontal
107 QPoint offsetTile=QPoint((topLeft.x() + tdim - 1) / tdim,(topLeft.y() + tdim - 1) / tdim);
109 QPoint firstTile = QPoint(static_cast<int>(center.x()) - offsetTile.x(),static_cast<int>(center.y()) - offsetTile.y());
111 // offset for top-left tile
112 m_offset = QPoint(topLeft.x() - offsetTile.x() * tdim, topLeft.y() - offsetTile.y() * tdim);
114 QPoint lastTile = QPoint(static_cast<int>(center.x()) + (width - topLeft.x() - 1) / tdim, static_cast<int>(center.y()) + (height - topLeft.y() - 1) / tdim);
117 m_tilesRect = QRect(firstTile.x(), firstTile.y(), lastTile.x() - firstTile.x() + 1, lastTile.y() - firstTile.y() + 1);
121 emit updated(QRect(0, 0, width, height));
124 void TilesMap::getTiles() {
126 QString path = mapUrlProvider();
128 for (int x = 0; x <= m_tilesRect.width(); ++x)
129 for (int y = 0; y <= m_tilesRect.height(); ++y) {
130 QPoint tp = m_tilesRect.topLeft() + QPoint(x, y);
132 if(!m_tileMaps.contains(tp)){
135 if(mapIsOnCache(zoom,grab.x(),grab.y())){
136 // getting maps from tile cache
137 m_log->debug("Map is on cache");
138 QString imgString = QString(fileUrlProvider()).arg(zoom).arg(grab.x()).arg(grab.y());
139 m_log->info(QString("map name:%1").arg(imgString));
143 m_log->debug(QString("going to update tile with tile: x=%1,y=%2").arg(grab.x()).arg(grab.y()));
144 m_tileMaps[grab] = QPixmap::fromImage(img);
146 m_tileMaps[grab]= m_emptyTile;
147 // TODO: remove empty image from disk
150 emit updated(tileRect(grab));
151 }else if(network && (!m_tileRequests.contains(grab) || timeout(m_tileRequests[grab].dateTime))){
152 // request Tiles from Server
153 m_url = QUrl(path.arg(zoom).arg(grab.x()).arg(grab.y()));
154 QNetworkRequest request;
155 m_log->info(QString("making a url request:").append(m_url.toString()));
156 request.setUrl(m_url);
157 request.setRawHeader("User-Agent", "GPSSniffer 1.0");
158 request.setAttribute(QNetworkRequest::User, QVariant(grab));
159 m_pendingReplies << m_manager->get(request);
161 m_tileRequests[grab]=TileRequest(zoom,QDateTime::currentDateTime(),false);
168 int TilesMap::downloadMaps(Track* track_p){
172 // Downloading Window Map
174 m_log->info("starting to downloading maps");
176 downloadWindow(&numTiles,zoom);
178 m_log->info("simple maps aded");
180 // ading tiles needed by track
181 QList<GpsPoint*> gpsPoints = track_p->getGpsPoints();
182 int updateProgress=0;
183 for(int zoom_temp=zoom; zoom_temp < 17; zoom_temp++){
184 for (int i = 0; i < gpsPoints.size(); ++i) {
185 GpsPoint* point = gpsPoints.at(i);
186 downloadTiles(point->getLatitude(), point->getLongitude(),zoom_temp,&numTiles);
187 emit pointsRequested(updateProgress);
191 m_log->info(QString("Num tiles to ad:%1").arg(numTiles));
195 void TilesMap::downloadTiles(qreal lat, qreal lng, int zoom, int* numTiles){
198 if (width <= 0 || height <= 0 || (lat==0 && lng==0))
203 QPointF center = coordinate2tile(latitude,longitude,zoom);
205 // getting top-left corner of the centered tile
206 QPoint topLeft = QPoint(width / 2 - (center.x() - floor(center.x())) * tdim,height / 2 - (center.y() - floor(center.y())) * tdim);
208 // getting first tile vertical and horizontal
209 QPoint offsetTile=QPoint((topLeft.x() + tdim - 1) / tdim,(topLeft.y() + tdim - 1) / tdim);
211 QPoint firstTile = QPoint(static_cast<int>(center.x()) - offsetTile.x(),static_cast<int>(center.y()) - offsetTile.y());
213 // offset for top-left tile
214 m_offset = QPoint(topLeft.x() - offsetTile.x() * tdim, topLeft.y() - offsetTile.y() * tdim);
216 QPoint lastTile = QPoint(static_cast<int>(center.x()) + (width - topLeft.x() - 1) / tdim, static_cast<int>(center.y()) + (height - topLeft.y() - 1) / tdim);
219 m_tilesRect = QRect(firstTile.x(), firstTile.y(), lastTile.x() - firstTile.x() + 1, lastTile.y() - firstTile.y() + 1);
221 downloadWindow(numTiles,zoom);
226 void TilesMap::downloadWindow(int* numTiles,int zoom){
228 QString path = mapUrlProvider();
230 for (int x = 0; x <= m_tilesRect.width(); ++x){
231 for (int y = 0; y <= m_tilesRect.height(); ++y) {
232 QPoint tp = m_tilesRect.topLeft() + QPoint(x, y);
234 if(!mapIsOnCache(zoom,grab.x(),grab.y()) && network && (!m_tileRequests.contains(grab) || timeout(m_tileRequests[grab].dateTime))){
236 // request Tiles from Server
237 m_url = QUrl(path.arg(zoom).arg(grab.x()).arg(grab.y()));
238 QNetworkRequest request;
239 m_log->info(QString("making %1 url request:").arg(*numTiles).append(m_url.toString()));
240 request.setUrl(m_url);
241 request.setRawHeader("User-Agent", "GPSSniffer 1.0");
242 request.setAttribute(QNetworkRequest::User, QVariant(grab));
243 m_pendingReplies << m_manager->get(request);
245 m_tileRequests[grab]= TileRequest(zoom,QDateTime::currentDateTime(),true);
255 void TilesMap::render(QPainter *p, const QRect &rect) {
256 //log->debug("rendering maps...");
257 for (int x = 0; x <= m_tilesRect.width(); ++x)
258 for (int y = 0; y <= m_tilesRect.height(); ++y) {
259 QPoint tp(x + m_tilesRect.left(), y + m_tilesRect.top());
260 QRect box = tileRect(tp);
261 if (rect.intersects(box)) {
262 if (m_tileMaps.contains(tp))
263 p->drawPixmap(box, m_tileMaps.value(tp));
265 p->drawPixmap(box, m_emptyTile);
268 //log->debug("done");
271 void TilesMap::pan(const QPoint &delta) {
272 QPointF dx = QPointF(delta) / qreal(tdim);
273 QPointF center = coordinate2tile(latitude, longitude, zoom) - dx;
274 latitude = tiley2lat(center.y(), zoom);
275 longitude = tilex2long(center.x(), zoom);
279 void TilesMap::updatePosition(GpsPoint point) {
280 latitude = point.getLatitude();
281 longitude = point.getLongitude();
285 void TilesMap::clearAllMaps(){
287 m_pendingReplies.clear();
288 m_tileRequests.clear();
293 void TilesMap::handleReplies(QNetworkReply *reply){
296 QPoint tp = reply->request().attribute(QNetworkRequest::User).toPoint();
297 TileRequest tr = m_tileRequests.value(tp);
300 if(!QDir(mapsDir()).exists()){
301 QDir().mkdir(mapsDir());
303 if (!reply->error()){
304 if (!img.load(reply, 0)){
312 QString fileString = QString(fileUrlProvider()).arg(zoomReply).arg(tp.x()).arg(tp.y());
314 if(!QDir(urlProvider()).exists())
315 QDir().mkdir(urlProvider());
317 if(!QDir(urlProvider().append("%1/").arg(zoomReply)).exists())
318 QDir().mkdir(urlProvider().append("%1").arg(zoomReply));
320 if(!QDir(urlProvider().append("%1/").arg(zoomReply).append("%1/").arg(tp.x())).exists())
321 QDir().mkdir(urlProvider().append("%1/").arg(zoomReply).append("%1/").arg(tp.x()));
324 QFile file(fileString);
326 if (!file.open(QIODevice::WriteOnly)) {
327 qDebug() << QString("Cannot open file for writing: %1").arg(file.errorString());
329 img.save(fileString);
334 m_pendingReplies.removeAll(reply);
335 reply->deleteLater();
337 m_tileRequests.remove(tp);
341 m_tileMaps[tp] = QPixmap::fromImage(img);
343 m_tileMaps[tp] = m_emptyTile;
345 emit updated(tileRect(tp));
348 // purge unused spaces
349 QRect bound = m_tilesRect.adjusted(-2, -2, 2, 2);
350 foreach(QPoint tp, m_tileMaps.keys())
351 if (!bound.contains(tp))
352 m_tileMaps.remove(tp);
354 emit tilesDownloaded(tilesD);
361 QRect TilesMap::tileRect(const QPoint &tp) {
362 QPoint t = tp - m_tilesRect.topLeft();
363 int x = t.x() * tdim + m_offset.x();
364 int y = t.y() * tdim + m_offset.y();
366 return QRect(x, y, tdim, tdim);
369 bool TilesMap::mapIsOnCache(int zoom,int x,int y){
371 QString fileString = QString(fileUrlProvider()).arg(zoom).arg(x).arg(y);
373 QFile file(fileString);
380 bool TilesMap::timeout(QDateTime qdt){
382 QDateTime now = QDateTime::currentDateTime();
383 int duration = qdt.secsTo(now);
384 bool retvalue = (duration>=HTTP_TIMEOUT);
389 QString TilesMap::fileUrlProvider(){
391 QString dir = QString(APPLICATION_PATH).append(MAPS_DIR);
393 case MapTypeGoogleMaps:
394 dir.append("/google/%1/%2/%3.png");
397 dir.append("/icc/%1/%2/%3.png");
399 case MapTypeOpenCycleMaps:
400 dir.append("/ocm/%1/%2/%3.png");
403 case MapTypeOpenStreetMaps:
404 dir.append("/osm/%1/%2/%3.png");
410 QString TilesMap::mapsDir(){
411 QString dir = QString(APPLICATION_PATH).append(MAPS_DIR);
415 QString TilesMap::urlProvider(){
417 QString dir = mapsDir();
419 case MapTypeGoogleMaps:
420 dir.append("/google/");
425 case MapTypeOpenCycleMaps:
429 case MapTypeOpenStreetMaps:
436 QString TilesMap::mapUrlProvider(){
438 //m_log->debug("--- mapUrlProvider ---");
439 QString url("http://");
440 //m_log->debug(QString("mapType:%1").arg(mapType));
442 case MapTypeGoogleMaps:
443 url.append("mt1.google.com/vt/&x=%2&y=%3&z=%1");
446 url.append("norma.icc.cat/tilecache/tilecache.py/1.0.0/topo3857/%1/%2/%3.png?type=google");
448 case MapTypeOpenCycleMaps:
449 url.append("tile.opencyclemap.org/cycle/%1/%2/%3.png");
452 case MapTypeOpenStreetMaps:
453 url.append("tile.openstreetmap.org/%1/%2/%3.png");