dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
tlmaps.cpp
Go to the documentation of this file.
1 
13 /*
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, see <http://www.gnu.org/licenses/>
26 */
27 #include "tlmaps.h"
30 #include "QDebug"
31 #include "QPainter"
32 
33 //#define DEBUG_Q_TILES
34 
35 using namespace projections;
36 
37 namespace core {
38  TLMaps* TLMaps::m_pInstance=nullptr;
39 
40  TLMaps* TLMaps::Instance()
41  {
42  if(!m_pInstance)
43  m_pInstance=new TLMaps;
44  return m_pInstance;
45  }
46  TLMaps::TLMaps():
47  RetryLoadTile(2),useMemoryCache(true),lastZoom(0),quadCoordRight(0),quadCoordBottom(0)
48  {
49  accessmode=AccessMode::ServerAndCache;
50  Language=LanguageType::autoDetect;
51  LanguageStr=LanguageType().toShortString(Language);
53 
54  }
55 
56 
58  {
59  TileDBcacheQueue.wait();
60  }
61 
73  QByteArray TLMaps::GetImageFromFile(const MapType::Types &type,const core::Point &pos,const int &zoom, double hScale, double vScale, QString userImageFileName, internals::PureProjection *projection)
74  {
75 
76 
77 #ifdef DEBUG_TIMINGS
78  QTime time;
79  time.restart();
80 #endif
81 #ifdef DEBUG_GMAPS
82  qDebug()<<"Entered GetImageFrom";
83 #endif //DEBUG_GMAPS
84  QByteArray ret;
85 
86  if(useMemoryCache)
87  {
88 #ifdef DEBUG_GMAPS
89  qDebug()<<"Try Tile from memory:Size="<<TilesInMemory.MemoryCacheSize();
90 #endif //DEBUG_GMAPS
91  ret=GetTileFromMemoryCache(RawTile(type,pos,zoom));
92  if(!ret.isEmpty())
93  {
94  errorvars.lock();
96  errorvars.unlock();
97  }
98 
99  }
100  if(ret.isEmpty())
101  {
102 #ifdef DEBUG_GMAPS
103  qDebug()<<"Tile not in memory";
104 #endif //DEBUG_GMAPS
105 
106  //Attempt to read tile from cache
107  if(accessmode != (AccessMode::ServerOnly) && type != MapType::UserImage) //Don't use cache if the user supplies a file. This is because
108  {
109 #ifdef DEBUG_GMAPS
110  qDebug()<<"Try tile from DataBase";
111 #endif //DEBUG_GMAPS
112  ret=Cache::Instance()->ImageCache.GetImageFromCache(type,pos,zoom);
113  if(!ret.isEmpty())
114  {
115  errorvars.lock();
116  ++diag.tilesFromDB;
117  errorvars.unlock();
118 #ifdef DEBUG_GMAPS
119  qDebug()<<"Tile found in Database";
120 #endif //DEBUG_GMAPS
121  if(useMemoryCache)
122  {
123 #ifdef DEBUG_GMAPS
124  qDebug()<<"Add Tile to memory";
125 #endif //DEBUG_GMAPS
126  AddTileToMemoryCache(RawTile(type,pos,zoom),ret);
127  }
128  return ret;
129  }
130  }
131 
132  //Attempt to read file from original source
133  if(accessmode!=AccessMode::CacheOnly)
134  {
135  //If it's a local user file...
136  if (type == MapType::UserImage)
137  {
138  //Load the image
139  static QImage imMap(userImageFileName);
140 
141  //Get image width and height, in [m]
142  static double widthPx=imMap.width();
143  static double heightPx=imMap.height();
144  static double width=widthPx*hScale;
145  static double height=heightPx*vScale;
146  static double cornerLLA[3];
147  static bool once=true;
148 
149  //TODO: Only do this once, not every time
150  if(once){
151  once=false;
152 
153  double homeLLA[3]={0,0,0};
154  double cornerNED[3]={-height, width, 0};
155  Utils::CoordinateConversions().NED2LLA_HomeLLA(homeLLA, cornerNED, cornerLLA);
156  }
157 
158  //Get the tile width
159  int tileSize= projection->TileSize().Width();
160 
161  //Only update is the zoom level has changed
162  if(lastZoom != zoom){
163  lastZoom=zoom;
164 
165  //Generate image scaled for this zoom level
166  imScaled=imMap.scaledToWidth(width / projection->GetGroundResolution(zoom, 0));
167 
168  //Find the quadtile that contains the opposite corner of the image
169  double top=90, bottom=-90, left=-180, right=180;
170  double lat=cornerLLA[0];
171  double lon=cornerLLA[1];
172  quadCoordRight=0;
173  quadCoordBottom=0;
174  for (int i=0; i<zoom; i++)
175  {
176  quadCoordRight <<=1;
177  quadCoordBottom<<=1;
178  if ((left+right)/2<lon )
179  {
180  quadCoordRight|=1;
181  left=(right+left)/2;
182  }
183  else
184  {
185  right=(right+left)/2;
186  }
187 
188  if ((top+bottom)/2<lat)
189  {
190  bottom=(top+bottom)/2;
191  }
192  else
193  {
194  quadCoordBottom |= 1;
195  top=(top+bottom)/2;
196  }
197  }
198 
199  // Determine the smallest quadtile that contains all the image, as determined by the location of the opposite corner.
200  leastCommonZoom=zoom-1;
202 
203  {
204  leastCommonZoom--;
205  }
206 
207 
208  while((((1<<leastCommonZoom) & quadCoordBottom) == ((1<<leastCommonZoom) & quadCoordRight)) && !((1<<leastCommonZoom) & quadCoordRight) && leastCommonZoom >0 )
209  {
210  leastCommonZoom--;
211  }
212 
213  qDebug() << "LCZ: " << leastCommonZoom;
214 
215  }
216 
217  // Only write output files for the smallest quadtile the contains the image, as determined by the opposite corner
218  if((pos.X() >> (leastCommonZoom+1)) == (quadCoordRight >> (leastCommonZoom+1)) && (pos.Y() >> (leastCommonZoom+1)) == (quadCoordBottom >> (leastCommonZoom+1)))
219  {
220 
221  QImage retImage=imScaled.copy((pos.X() & ((1<<(leastCommonZoom+1))-1)) * tileSize, (pos.Y() & ((1<<(leastCommonZoom+1))-1)) * tileSize, tileSize, tileSize);
222 
223 #ifdef DEBUG_Q_TILES
224  //For a silly reason of making sure that everything is properly drawn, display the quadtile element on each tile
225  retImage=retImage.convertToFormat(QImage::Format_ARGB32);
226  QPainter painter(&retImage);
227  painter.setFont(QFont("Chicago", 7)); // The font size
228  painter.setPen(QColor(233, 10, 150));
229  painter.drawText(20, 40, QString::number(pos.X() , 2));
230  painter.drawText(20, 80, QString::number(pos.Y() , 2));
231  painter.drawText(20, 120, QString::number(quadCoordRight , 2));
232  painter.drawText(20, 160, QString::number(quadCoordBottom , 2));
233 #endif
234 
235  QBuffer buffer(&ret);
236  buffer.open(QIODevice::WriteOnly);
237  retImage.save(&buffer, "PNG"); // writes image into ba in PNG format
238  }
239  else{ //Nothing here, fill it in with black tiles.
240  QImage retImage(tileSize,tileSize, QImage::Format_ARGB32);
241  retImage.fill(Qt::black);
242 
243 #ifdef DEBUG_Q_TILES
244  //For a silly reason of making sure that everything is properly drawn, display the quadtile element on each tile
245  QPainter painter(&retImage);
246  painter.setFont(QFont("Chicago", 16)); // The font size
247  painter.setPen(QColor(10, 233, 150));
248  painter.drawText(20, 40, QString::number(pos.X() , 2));
249  painter.drawText(20, 80, QString::number(pos.Y() , 2));
250  painter.drawText(20, 120, QString::number(quadCoordRight , 2));
251  painter.drawText(20, 160, QString::number(quadCoordBottom , 2));
252 #endif
253  QBuffer buffer(&ret);
254  buffer.open(QIODevice::WriteOnly);
255  retImage.save(&buffer, "PNG"); // writes image into ba in PNG format
256 
257  }
258  }
259 
260  errorvars.unlock();
261 
262  //Save tile to cache
263  if (useMemoryCache)
264  {
265 #ifdef DEBUG_GMAPS
266  qDebug()<<"Add Tile to memory cache";
267 #endif //DEBUG_GMAPS
268  AddTileToMemoryCache(RawTile(type,pos,zoom),ret);
269  }
270 
271  //Save tile to database
272  if(accessmode!=AccessMode::ServerOnly)
273  {
274 #ifdef DEBUG_GMAPS
275  qDebug()<<"Add tile to DataBase";
276 #endif //DEBUG_GMAPS
277  CacheItemQueue * item=new CacheItemQueue(type,pos,ret,zoom);
279  }
280 
281 
282  }
283  }
284 #ifdef DEBUG_GMAPS
285  qDebug()<<"Entered GetImageFrom";
286 #endif //DEBUG_GMAPS
287  return ret;
288  }
289 
290  void TLMaps::setLanguage(const LanguageType::Types &language)
291  {
292  QMutexLocker locker(&settingsProtect);
293  Language = language;
294  LanguageStr=LanguageType().toShortString(Language);
295  }
296 
297 
305  QByteArray TLMaps::GetImageFromServer(const MapType::Types &type,const Point &pos,const int &zoom)
306  {
307  QMutexLocker locker(&settingsProtect);
308 #ifdef DEBUG_TIMINGS
309  QTime time;
310  time.restart();
311 #endif
312 #ifdef DEBUG_GMAPS
313  qDebug()<<"Entered GetImageFrom";
314 #endif //DEBUG_GMAPS
315  QByteArray ret;
316 
317  if(useMemoryCache)
318  {
319 #ifdef DEBUG_GMAPS
320  qDebug()<<"Try Tile from memory:Size="<<TilesInMemory.MemoryCacheSize();
321 #endif //DEBUG_GMAPS
322  ret=GetTileFromMemoryCache(RawTile(type,pos,zoom));
323  if(!ret.isEmpty())
324  {
325  errorvars.lock();
326  ++diag.tilesFromMem;
327  errorvars.unlock();
328  }
329 
330  }
331  if(ret.isEmpty())
332  {
333 #ifdef DEBUG_GMAPS
334  qDebug()<<"Tile not in memory";
335 #endif //DEBUG_GMAPS
336 
337  //Attempt to read tile from cache
338  if(accessmode != (AccessMode::ServerOnly) && type != MapType::UserImage) //Don't use cache if the user supplies a file. This is because
339  {
340 #ifdef DEBUG_GMAPS
341  qDebug()<<"Try tile from DataBase";
342 #endif //DEBUG_GMAPS
343  ret=Cache::Instance()->ImageCache.GetImageFromCache(type,pos,zoom);
344  if(!ret.isEmpty())
345  {
346  errorvars.lock();
347  ++diag.tilesFromDB;
348  errorvars.unlock();
349 #ifdef DEBUG_GMAPS
350  qDebug()<<"Tile found in Database";
351 #endif //DEBUG_GMAPS
352  if(useMemoryCache)
353  {
354 #ifdef DEBUG_GMAPS
355  qDebug()<<"Add Tile to memory";
356 #endif //DEBUG_GMAPS
357  AddTileToMemoryCache(RawTile(type,pos,zoom),ret);
358  }
359  return ret;
360  }
361  }
362 
363  //Attempt to read file from original source
364  if(accessmode!=AccessMode::CacheOnly)
365  {
366  { //Otherwise, we're getting the tiles from the internet
367  QEventLoop q;
368  QNetworkReply *reply;
369  QNetworkRequest qheader;
370  QNetworkAccessManager network;
371  QTimer tT;
372  tT.setSingleShot(true);
373  connect(&network, SIGNAL(finished(QNetworkReply*)),
374  &q, SLOT(quit()));
375  connect(&tT, SIGNAL(timeout()), &q, SLOT(quit()));
376  network.setProxy(Proxy);
377  #ifdef DEBUG_GMAPS
378  qDebug()<<"Try Tile from the Internet";
379  #endif //DEBUG_GMAPS
380  #ifdef DEBUG_TIMINGS
381  qDebug()<<"opmaps before make image url"<<time.elapsed();
382  #endif
383  QString url=MakeImageUrl(type,pos,zoom,LanguageStr);
384  #ifdef DEBUG_TIMINGS
385  qDebug()<<"opmaps after make image url"<<time.elapsed();
386  #endif //url "http://vec02.maps.yandex.ru/tiles?l=map&v=2.10.2&x=7&y=5&z=3" string
387  //"http://map3.pergo.com.tr/tile/02/000/000/007/000/000/002.png"
388  qheader.setUrl(QUrl(url));
389  qheader.setRawHeader("User-Agent",UserAgent);
390  qheader.setRawHeader("Accept","*/*");
391  switch(type)
392  {
393  case MapType::GoogleMap:
394  case MapType::GoogleSatellite:
395  case MapType::GoogleLabels:
396  case MapType::GoogleTerrain:
397  case MapType::GoogleHybrid:
398  {
399  qheader.setRawHeader("Referrer", "http://maps.google.com/");
400  }
401  break;
402 
403  case MapType::GoogleMapChina:
404  case MapType::GoogleSatelliteChina:
405  case MapType::GoogleLabelsChina:
406  case MapType::GoogleTerrainChina:
407  case MapType::GoogleHybridChina:
408  {
409  qheader.setRawHeader("Referrer", "http://ditu.google.cn/");
410  }
411  break;
412 
413  case MapType::BingHybrid:
414  case MapType::BingMap:
415  case MapType::BingSatellite:
416  {
417  qheader.setRawHeader("Referrer", "http://www.bing.com/maps/");
418  }
419  break;
420 
421  case MapType::YahooHybrid:
422  case MapType::YahooLabels:
423  case MapType::YahooMap:
424  case MapType::YahooSatellite:
425  {
426  qheader.setRawHeader("Referrer", "http://maps.yahoo.com/");
427  }
428  break;
429 
430  case MapType::ArcGIS_MapsLT_Map_Labels:
431  case MapType::ArcGIS_MapsLT_Map:
432  case MapType::ArcGIS_MapsLT_OrtoFoto:
433  case MapType::ArcGIS_MapsLT_Map_Hybrid:
434  {
435  qheader.setRawHeader("Referrer", "http://www.maps.lt/map_beta/");
436  }
437  break;
438 
439  case MapType::OpenStreetMapSurfer:
440  case MapType::OpenStreetMapSurferTerrain:
441  {
442  qheader.setRawHeader("Referrer", "http://www.mapsurfer.net/");
443  }
444  break;
445 
446  case MapType::OpenStreetMap:
447  case MapType::OpenStreetOsm:
448  {
449  qheader.setRawHeader("Referrer", "http://www.openstreetmap.org/");
450  }
451  break;
452 
453  case MapType::YandexMapRu:
454  {
455  qheader.setRawHeader("Referrer", "http://maps.yandex.ru/");
456  }
457  break;
458  default:
459  break;
460  }
461 #ifdef DEBUG_GMAPS
462  qDebug() << "qheader: " << qheader.url();
463 #endif //DEBUG_GMAPS
464  reply=network.get(qheader);
465  tT.start(Timeout);
466  q.exec();
467 
468  if(!tT.isActive()){
469  errorvars.lock();
470  ++diag.timeouts;
471  errorvars.unlock();
472  return ret;
473  }
474  tT.stop();
475  if( (reply->error()!=QNetworkReply::NoError))
476  {
477  errorvars.lock();
479  errorvars.unlock();
480  reply->deleteLater();
481  return ret;
482  }
483  ret=reply->readAll();
484  reply->deleteLater();//TODO can't this be global??
485  if(ret.isEmpty())
486  {
487  #ifdef DEBUG_GMAPS
488  qDebug()<<"Invalid Tile";
489  #endif //DEBUG_GMAPS
490  errorvars.lock();
491  ++diag.emptytiles;
492  errorvars.unlock();
493  return ret;
494  }
495  #ifdef DEBUG_GMAPS
496  qDebug()<<"Received Tile from the Internet";
497  #endif //DEBUG_GMAPS
498  errorvars.lock();
499  ++diag.tilesFromNet;
500  }
501 
502  errorvars.unlock();
503 
504  //Save tile to cache
505  if (useMemoryCache)
506  {
507 #ifdef DEBUG_GMAPS
508  qDebug()<<"Add Tile to memory cache";
509 #endif //DEBUG_GMAPS
510  AddTileToMemoryCache(RawTile(type,pos,zoom),ret);
511  }
512 
513  //Save tile to database
514  if(accessmode!=AccessMode::ServerOnly)
515  {
516 #ifdef DEBUG_GMAPS
517  qDebug()<<"Add tile to DataBase";
518 #endif //DEBUG_GMAPS
519  CacheItemQueue * item=new CacheItemQueue(type,pos,ret,zoom);
521  }
522 
523 
524  }
525  }
526 #ifdef DEBUG_GMAPS
527  qDebug()<<"Entered GetImageFrom";
528 #endif //DEBUG_GMAPS
529  return ret;
530  }
531 
532  bool TLMaps::ExportToGMDB(const QString &file)
533  {
534  return Cache::Instance()->ImageCache.ExportMapDataToDB(Cache::Instance()->ImageCache.GtileCache()+QDir::separator()+"Data.qmdb",file);
535  }
536  bool TLMaps::ImportFromGMDB(const QString &file)
537  {
538  return Cache::Instance()->ImageCache.ExportMapDataToDB(file,Cache::Instance()->ImageCache.GtileCache()+QDir::separator()+"Data.qmdb");
539  }
540 
542  {
543  diagnostics i;
544  errorvars.lock();
545  i=diag;
546  errorvars.unlock();
547  return i;
548  }
549 }
550 
bool ExportToGMDB(const QString &file)
Definition: tlmaps.cpp:532
LanguageType::Types Language
Definition: tlmaps.h:79
qint64 X() const
Definition: point.h:51
static Cache * Instance()
Definition: cache.cpp:34
QByteArray GetImageFromCache(MapType::Types type, core::Point pos, int zoom)
QByteArray UserAgent
Gets or sets the value of the User-agent HTTP header.
Definition: urlfactory.h:55
virtual Size TileSize() const =0
AccessMode::Types accessmode
Definition: tlmaps.h:80
QByteArray GetImageFromFile(const MapType::Types &type, const core::Point &pos, const int &zoom, double hScale, double vScale, QString userImageFileName, internals::PureProjection *projection)
OPMaps::GetImageFromFile.
Definition: tlmaps.cpp:73
int quadCoordRight
Definition: tlmaps.h:92
bool useMemoryCache
Definition: tlmaps.h:78
int leastCommonZoom
Definition: tlmaps.h:95
void AddTileToMemoryCache(const RawTile &tile, const QByteArray &pic)
Definition: memorycache.cpp:46
end buffer
quint8 lastZoom
Definition: tlmaps.h:91
QMutex errorvars
Definition: tlmaps.h:89
for i
Definition: OPPlots.m:140
QString LanguageStr
Definition: urlfactory.h:86
int tilesFromMem
Definition: diagnostics.h:37
int quadCoordBottom
Definition: tlmaps.h:93
Parse log file
TileCacheQueue TileDBcacheQueue
Definition: tlmaps.h:82
QByteArray GetImageFromServer(const MapType::Types &type, const core::Point &pos, const int &zoom)
timeout for map connections
Definition: tlmaps.cpp:305
KiberTileCache TilesInMemory
Definition: memorycache.h:43
int emptytiles
Definition: diagnostics.h:34
bool ImportFromGMDB(const QString &file)
Definition: tlmaps.cpp:536
diagnostics GetDiagnostics()
Definition: tlmaps.cpp:541
QImage imScaled
Definition: tlmaps.h:94
diagnostics diag
Definition: tlmaps.h:88
int NED2LLA_HomeLLA(double homeLLA[3], double NED[3], double LLA[3])
QString MakeImageUrl(const MapType::Types &type, const core::Point &pos, const int &zoom, const QString &language)
UrlFactory::MakeImageUrl Make the requesting URL for the desired quadtile.
Definition: urlfactory.cpp:191
int networkerrors
Definition: diagnostics.h:33
QNetworkProxy Proxy
Definition: urlfactory.h:56
int tilesFromNet
Definition: diagnostics.h:38
PureImageCache ImageCache
Definition: cache.h:41
virtual double GetGroundResolution(const int &zoom, const double &latitude)
PureProjection::GetGroundResolution Returns the conversion from pixels to meters. ...
void setLanguage(const LanguageType::Types &language)
Definition: tlmaps.cpp:290
static bool ExportMapDataToDB(QString sourceFile, QString destFile)
void EnqueueCacheTask(CacheItemQueue *task)
int tilesFromDB
Definition: diagnostics.h:39
qint64 Y() const
Definition: point.h:52
QMutex settingsProtect
Definition: tlmaps.h:90
QByteArray GetTileFromMemoryCache(const RawTile &tile)
Definition: memorycache.cpp:37